learning-credentials 0.3.0rc3__py3-none-any.whl → 0.3.0rc10__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- learning_credentials/api/v1/permissions.py +42 -24
- learning_credentials/api/v1/urls.py +4 -8
- learning_credentials/api/v1/views.py +28 -302
- learning_credentials/apps.py +7 -10
- learning_credentials/compat.py +1 -7
- learning_credentials/generators.py +0 -1
- learning_credentials/models.py +10 -44
- learning_credentials/processors.py +40 -148
- learning_credentials/settings/common.py +5 -2
- learning_credentials/settings/production.py +5 -2
- {learning_credentials-0.3.0rc3.dist-info → learning_credentials-0.3.0rc10.dist-info}/METADATA +19 -3
- {learning_credentials-0.3.0rc3.dist-info → learning_credentials-0.3.0rc10.dist-info}/RECORD +16 -22
- {learning_credentials-0.3.0rc3.dist-info → learning_credentials-0.3.0rc10.dist-info}/entry_points.txt +0 -3
- learning_credentials/api/v1/serializers.py +0 -74
- learning_credentials/core_api.py +0 -77
- learning_credentials/public/css/credentials_xblock.css +0 -7
- learning_credentials/public/html/credentials_xblock.html +0 -48
- learning_credentials/public/js/credentials_xblock.js +0 -23
- learning_credentials/xblocks.py +0 -85
- {learning_credentials-0.3.0rc3.dist-info → learning_credentials-0.3.0rc10.dist-info}/WHEEL +0 -0
- {learning_credentials-0.3.0rc3.dist-info → learning_credentials-0.3.0rc10.dist-info}/licenses/LICENSE.txt +0 -0
- {learning_credentials-0.3.0rc3.dist-info → learning_credentials-0.3.0rc10.dist-info}/top_level.txt +0 -0
|
@@ -1,48 +0,0 @@
|
|
|
1
|
-
<div class="credentials-block">
|
|
2
|
-
{% if is_author_mode %}
|
|
3
|
-
<p>The Studio view of this XBlock is not supported yet. Please preview the XBlock in the LMS.</p>
|
|
4
|
-
{% else %}
|
|
5
|
-
<h3>Check Your Certificate Eligibility Status</h3>
|
|
6
|
-
<ul class="credentials-list">
|
|
7
|
-
{% if credentials %}
|
|
8
|
-
{% for credential_type, credential in credentials.items %}
|
|
9
|
-
<li class="credential">
|
|
10
|
-
<strong>Type:</strong> {{ credential_type }}
|
|
11
|
-
{% if credential.download_url %}
|
|
12
|
-
<p class="credential-status">Congratulations on finishing strong!</p>
|
|
13
|
-
<strong>Download Link:</strong> <a href="{{ credential.download_url }}">Download Certificate</a>
|
|
14
|
-
{% elif credential.status == credential.Status.ERROR %}
|
|
15
|
-
<p class="credential-status">Something went wrong. Please contact us via the Help page for assistance.</p>
|
|
16
|
-
{% endif %}
|
|
17
|
-
<button class="btn-brand generate-credential" data-credential-type="{{ credential_type }}" disabled>
|
|
18
|
-
Certificate Claimed
|
|
19
|
-
</button>
|
|
20
|
-
<div id="message-area-{{ credential_type }}"></div>
|
|
21
|
-
</li>
|
|
22
|
-
{% endfor %}
|
|
23
|
-
{% endif %}
|
|
24
|
-
|
|
25
|
-
{% if eligible_types %}
|
|
26
|
-
{% for credential_type, is_eligible in eligible_types.items %}
|
|
27
|
-
{% if not credentials or credential_type not in credentials %}
|
|
28
|
-
<li class="credential">
|
|
29
|
-
<strong>Type:</strong> {{ credential_type }}
|
|
30
|
-
{% if is_eligible %}
|
|
31
|
-
<p class="credential-status">Congratulations! You have earned this certificate. Please claim it below.</p>
|
|
32
|
-
<button class="btn-brand generate-credential" data-credential-type="{{ credential_type }}">
|
|
33
|
-
Claim Certificate
|
|
34
|
-
</button>
|
|
35
|
-
{% else %}
|
|
36
|
-
<p class="certificate-status">You are not yet eligible for this certificate.</p>
|
|
37
|
-
<button class="btn-brand generate-certificate" data-certificate-type="{{ credential_type }}" disabled>
|
|
38
|
-
Claim Certificate
|
|
39
|
-
</button>
|
|
40
|
-
{% endif %}
|
|
41
|
-
<div id="message-area-{{ credential_type }}"></div>
|
|
42
|
-
</li>
|
|
43
|
-
{% endif %}
|
|
44
|
-
{% endfor %}
|
|
45
|
-
{% endif %}
|
|
46
|
-
</ul>
|
|
47
|
-
{% endif %}
|
|
48
|
-
</div>
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
function CredentialsXBlock(runtime, element) {
|
|
2
|
-
function generateCredential(event) {
|
|
3
|
-
const button = event.target;
|
|
4
|
-
const credentialType = $(button).data('credential-type');
|
|
5
|
-
const handlerUrl = runtime.handlerUrl(element, 'generate_credential');
|
|
6
|
-
|
|
7
|
-
$.post(handlerUrl, JSON.stringify({ credential_type: credentialType }))
|
|
8
|
-
.done(function(data) {
|
|
9
|
-
const messageArea = $(element).find('#message-area-' + credentialType);
|
|
10
|
-
if (data.status === 'success') {
|
|
11
|
-
messageArea.html('<p style="color:green;">Certificate generation initiated successfully.</p>');
|
|
12
|
-
} else {
|
|
13
|
-
messageArea.html('<p style="color:red;">' + data.message + '</p>');
|
|
14
|
-
}
|
|
15
|
-
})
|
|
16
|
-
.fail(function() {
|
|
17
|
-
const messageArea = $(element).find('#message-area-' + credentialType);
|
|
18
|
-
messageArea.html('<p style="color:red;">An error occurred while processing your request.</p>');
|
|
19
|
-
});
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
$(element).find('.generate-credential').on('click', generateCredential);
|
|
23
|
-
}
|
learning_credentials/xblocks.py
DELETED
|
@@ -1,85 +0,0 @@
|
|
|
1
|
-
"""XBlocks for Learning Credentials."""
|
|
2
|
-
|
|
3
|
-
import logging
|
|
4
|
-
|
|
5
|
-
from xblock.core import XBlock
|
|
6
|
-
from xblock.fields import Scope, String
|
|
7
|
-
from xblock.fragment import Fragment
|
|
8
|
-
from xblock.utils.resources import ResourceLoader
|
|
9
|
-
from xblock.utils.studio_editable import StudioEditableXBlockMixin
|
|
10
|
-
|
|
11
|
-
from .core_api import generate_credential_for_user, get_eligible_users_by_credential_type, get_user_credentials_by_type
|
|
12
|
-
|
|
13
|
-
loader = ResourceLoader(__name__)
|
|
14
|
-
logger = logging.getLogger(__name__)
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
class CredentialsXBlock(StudioEditableXBlockMixin, XBlock):
|
|
18
|
-
"""XBlock that displays the credential eligibility status and allows eligible users to generate credentials."""
|
|
19
|
-
|
|
20
|
-
display_name = String(
|
|
21
|
-
help='The display name for this component.',
|
|
22
|
-
scope=Scope.content,
|
|
23
|
-
display_name="Display name",
|
|
24
|
-
default='Credentials',
|
|
25
|
-
)
|
|
26
|
-
|
|
27
|
-
def student_view(self, context) -> Fragment: # noqa: ANN001, ARG002
|
|
28
|
-
"""Main view for the student. Displays the credential eligibility or ineligibility status."""
|
|
29
|
-
fragment = Fragment()
|
|
30
|
-
eligible_types = False
|
|
31
|
-
credentials = []
|
|
32
|
-
|
|
33
|
-
if not (is_author_mode := getattr(self.runtime, 'is_author_mode', False)):
|
|
34
|
-
credentials = self.get_credentials()
|
|
35
|
-
eligible_types = self.get_eligible_credential_types()
|
|
36
|
-
|
|
37
|
-
# Filter out the eligible types that already have a credential generated
|
|
38
|
-
for cred_type in credentials:
|
|
39
|
-
if cred_type in eligible_types:
|
|
40
|
-
del eligible_types[cred_type]
|
|
41
|
-
|
|
42
|
-
fragment.add_content(
|
|
43
|
-
loader.render_django_template(
|
|
44
|
-
'public/html/credentials_xblock.html',
|
|
45
|
-
{
|
|
46
|
-
'credentials': credentials,
|
|
47
|
-
'eligible_types': eligible_types,
|
|
48
|
-
'is_author_mode': is_author_mode,
|
|
49
|
-
},
|
|
50
|
-
)
|
|
51
|
-
)
|
|
52
|
-
|
|
53
|
-
fragment.add_css_url(self.runtime.local_resource_url(self, "public/css/credentials_xblock.css"))
|
|
54
|
-
fragment.add_javascript_url(self.runtime.local_resource_url(self, "public/js/credentials_xblock.js"))
|
|
55
|
-
fragment.initialize_js('CredentialsXBlock')
|
|
56
|
-
return fragment
|
|
57
|
-
|
|
58
|
-
def get_eligible_credential_types(self) -> dict[str, bool]:
|
|
59
|
-
"""Retrieve the eligibility status for each credential type."""
|
|
60
|
-
eligible_users = get_eligible_users_by_credential_type(self.runtime.course_id, user_id=self.scope_ids.user_id)
|
|
61
|
-
|
|
62
|
-
return {credential_type: bool(users) for credential_type, users in eligible_users.items()}
|
|
63
|
-
|
|
64
|
-
def get_credentials(self) -> dict[str, dict[str, str]]:
|
|
65
|
-
"""Retrieve the credentials for the current user in the current course."""
|
|
66
|
-
return get_user_credentials_by_type(self.runtime.course_id, self.scope_ids.user_id)
|
|
67
|
-
|
|
68
|
-
@XBlock.json_handler
|
|
69
|
-
def generate_credential(self, data: dict, suffix: str = '') -> dict[str, str]: # noqa: ARG002
|
|
70
|
-
"""Handler for generating a credential for a specific type."""
|
|
71
|
-
credential_type = data.get('credential_type')
|
|
72
|
-
if not credential_type:
|
|
73
|
-
return {'status': 'error', 'message': 'No credential type specified.'}
|
|
74
|
-
|
|
75
|
-
course_id = self.runtime.course_id
|
|
76
|
-
user_id = self.scope_ids.user_id
|
|
77
|
-
logger.info(
|
|
78
|
-
'Generating a credential for user %s in course %s with type %s.', user_id, course_id, credential_type
|
|
79
|
-
)
|
|
80
|
-
|
|
81
|
-
try:
|
|
82
|
-
generate_credential_for_user(course_id, credential_type, user_id)
|
|
83
|
-
except ValueError as e:
|
|
84
|
-
return {'status': 'error', 'message': str(e)}
|
|
85
|
-
return {'status': 'success'}
|
|
File without changes
|
|
File without changes
|
{learning_credentials-0.3.0rc3.dist-info → learning_credentials-0.3.0rc10.dist-info}/top_level.txt
RENAMED
|
File without changes
|