learning-credentials 0.2.3__py3-none-any.whl → 0.3.0__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/__init__.py +1 -0
- learning_credentials/api/urls.py +9 -0
- learning_credentials/api/v1/__init__.py +1 -0
- learning_credentials/api/v1/permissions.py +81 -0
- learning_credentials/api/v1/urls.py +13 -0
- learning_credentials/api/v1/views.py +83 -0
- learning_credentials/apps.py +10 -3
- learning_credentials/compat.py +4 -1
- learning_credentials/generators.py +2 -1
- learning_credentials/models.py +1 -1
- learning_credentials/settings/common.py +5 -2
- learning_credentials/settings/production.py +5 -2
- learning_credentials/urls.py +5 -5
- {learning_credentials-0.2.3.dist-info → learning_credentials-0.3.0.dist-info}/METADATA +19 -2
- {learning_credentials-0.2.3.dist-info → learning_credentials-0.3.0.dist-info}/RECORD +19 -14
- learning_credentials/views.py +0 -1
- {learning_credentials-0.2.3.dist-info → learning_credentials-0.3.0.dist-info}/WHEEL +0 -0
- {learning_credentials-0.2.3.dist-info → learning_credentials-0.3.0.dist-info}/entry_points.txt +0 -0
- {learning_credentials-0.2.3.dist-info → learning_credentials-0.3.0.dist-info}/licenses/LICENSE.txt +0 -0
- {learning_credentials-0.2.3.dist-info → learning_credentials-0.3.0.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""Learning Credentials API package."""
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""Learning Credentials API v1 package."""
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
"""Django REST framework permissions."""
|
|
2
|
+
|
|
3
|
+
from typing import TYPE_CHECKING
|
|
4
|
+
|
|
5
|
+
from django.db.models import Q
|
|
6
|
+
from learning_paths.models import LearningPath
|
|
7
|
+
from opaque_keys import InvalidKeyError
|
|
8
|
+
from opaque_keys.edx.keys import LearningContextKey
|
|
9
|
+
from rest_framework.exceptions import NotFound, ParseError
|
|
10
|
+
from rest_framework.permissions import BasePermission
|
|
11
|
+
|
|
12
|
+
from learning_credentials.compat import get_course_enrollments
|
|
13
|
+
|
|
14
|
+
if TYPE_CHECKING:
|
|
15
|
+
from django.contrib.auth.models import User
|
|
16
|
+
from learning_paths.keys import LearningPathKey
|
|
17
|
+
from opaque_keys.edx.keys import CourseKey
|
|
18
|
+
from rest_framework.request import Request
|
|
19
|
+
from rest_framework.views import APIView
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class CanAccessLearningContext(BasePermission):
|
|
23
|
+
"""Permission to allow access to learning context if the user is enrolled."""
|
|
24
|
+
|
|
25
|
+
def has_permission(self, request: "Request", view: "APIView") -> bool:
|
|
26
|
+
"""Check if the user can access the learning context."""
|
|
27
|
+
try:
|
|
28
|
+
key = view.kwargs.get("learning_context_key") or request.query_params.get("learning_context_key")
|
|
29
|
+
learning_context_key = LearningContextKey.from_string(key)
|
|
30
|
+
except InvalidKeyError as e:
|
|
31
|
+
msg = "Invalid learning context key."
|
|
32
|
+
raise ParseError(msg) from e
|
|
33
|
+
|
|
34
|
+
if request.user.is_staff:
|
|
35
|
+
return True
|
|
36
|
+
|
|
37
|
+
if learning_context_key.is_course:
|
|
38
|
+
if self._can_access_course(learning_context_key, request.user):
|
|
39
|
+
return True
|
|
40
|
+
|
|
41
|
+
msg = "Course not found or user does not have access."
|
|
42
|
+
raise NotFound(msg)
|
|
43
|
+
|
|
44
|
+
# For learning paths, check enrollment or if it's not invite-only.
|
|
45
|
+
if self._can_access_learning_path(learning_context_key, request.user):
|
|
46
|
+
return True
|
|
47
|
+
|
|
48
|
+
msg = "Learning path not found or user does not have access."
|
|
49
|
+
raise NotFound(msg)
|
|
50
|
+
|
|
51
|
+
def _can_access_course(self, course_key: "CourseKey", user: "User") -> bool:
|
|
52
|
+
"""Check if user can access a course."""
|
|
53
|
+
# Check if user is enrolled in the course.
|
|
54
|
+
if get_course_enrollments(course_key, user.id): # ty: ignore[unresolved-attribute]
|
|
55
|
+
return True
|
|
56
|
+
|
|
57
|
+
# Check if the course is a part of a learning path the user can access.
|
|
58
|
+
return self._can_access_course_via_learning_path(course_key, user)
|
|
59
|
+
|
|
60
|
+
def _get_accessible_learning_paths_filter(self, user: "User") -> Q:
|
|
61
|
+
"""Get Q filter for learning paths that the user can access."""
|
|
62
|
+
return Q(invite_only=False) | Q(learningpathenrollment__user=user, learningpathenrollment__is_active=True)
|
|
63
|
+
|
|
64
|
+
def _can_access_course_via_learning_path(self, course_key: "CourseKey", user: "User") -> bool:
|
|
65
|
+
"""Check if user can access a course through learning path membership."""
|
|
66
|
+
accessible_paths = (
|
|
67
|
+
LearningPath.objects.filter(steps__course_key=course_key)
|
|
68
|
+
.filter(self._get_accessible_learning_paths_filter(user))
|
|
69
|
+
.distinct()
|
|
70
|
+
)
|
|
71
|
+
|
|
72
|
+
return accessible_paths.exists()
|
|
73
|
+
|
|
74
|
+
def _can_access_learning_path(self, learning_path_key: "LearningPathKey", user: "User") -> bool:
|
|
75
|
+
"""Check if user can access a learning path."""
|
|
76
|
+
# Single query to check if learning path exists and user can access it
|
|
77
|
+
accessible_path = LearningPath.objects.filter(key=learning_path_key).filter(
|
|
78
|
+
self._get_accessible_learning_paths_filter(user)
|
|
79
|
+
)
|
|
80
|
+
|
|
81
|
+
return accessible_path.exists()
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
"""API v1 URLs."""
|
|
2
|
+
|
|
3
|
+
from django.urls import path
|
|
4
|
+
|
|
5
|
+
from .views import CredentialConfigurationCheckView
|
|
6
|
+
|
|
7
|
+
urlpatterns = [
|
|
8
|
+
path(
|
|
9
|
+
'configured/<str:learning_context_key>/',
|
|
10
|
+
CredentialConfigurationCheckView.as_view(),
|
|
11
|
+
name='credential_configuration_check',
|
|
12
|
+
),
|
|
13
|
+
]
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
"""API views for Learning Credentials."""
|
|
2
|
+
|
|
3
|
+
from typing import TYPE_CHECKING
|
|
4
|
+
|
|
5
|
+
import edx_api_doc_tools as apidocs
|
|
6
|
+
from edx_api_doc_tools import ParameterLocation
|
|
7
|
+
from rest_framework import status
|
|
8
|
+
from rest_framework.permissions import IsAuthenticated
|
|
9
|
+
from rest_framework.response import Response
|
|
10
|
+
from rest_framework.views import APIView
|
|
11
|
+
|
|
12
|
+
from learning_credentials.models import CredentialConfiguration
|
|
13
|
+
|
|
14
|
+
from .permissions import CanAccessLearningContext
|
|
15
|
+
|
|
16
|
+
if TYPE_CHECKING:
|
|
17
|
+
from rest_framework.request import Request
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class CredentialConfigurationCheckView(APIView):
|
|
21
|
+
"""API view to check if any credentials are configured for a specific learning context."""
|
|
22
|
+
|
|
23
|
+
permission_classes = (IsAuthenticated, CanAccessLearningContext)
|
|
24
|
+
|
|
25
|
+
@apidocs.schema(
|
|
26
|
+
parameters=[
|
|
27
|
+
apidocs.string_parameter(
|
|
28
|
+
"learning_context_key",
|
|
29
|
+
ParameterLocation.PATH,
|
|
30
|
+
description=(
|
|
31
|
+
"Learning context identifier. Can be a course key (course-v1:OpenedX+DemoX+DemoCourse) "
|
|
32
|
+
"or learning path key (path-v1:OpenedX+DemoX+DemoPath+Demo)"
|
|
33
|
+
),
|
|
34
|
+
),
|
|
35
|
+
],
|
|
36
|
+
responses={
|
|
37
|
+
200: "Boolean indicating if credentials are configured.",
|
|
38
|
+
400: "Invalid context key format.",
|
|
39
|
+
403: "User is not authenticated or does not have permission to access the learning context.",
|
|
40
|
+
404: "Learning context not found or user does not have access.",
|
|
41
|
+
},
|
|
42
|
+
)
|
|
43
|
+
def get(self, _request: "Request", learning_context_key: str) -> Response:
|
|
44
|
+
"""
|
|
45
|
+
Check if any credentials are configured for the given learning context.
|
|
46
|
+
|
|
47
|
+
**Example Request**
|
|
48
|
+
|
|
49
|
+
``GET /api/learning_credentials/v1/configured/course-v1:OpenedX+DemoX+DemoCourse/``
|
|
50
|
+
|
|
51
|
+
**Response Values**
|
|
52
|
+
|
|
53
|
+
- **200 OK**: Request successful, returns credential configuration status.
|
|
54
|
+
- **400 Bad Request**: Invalid learning context key format.
|
|
55
|
+
- **403 Forbidden**: User is not authenticated or does not have permission to access the learning context.
|
|
56
|
+
- **404 Not Found**: Learning context not found or user does not have access.
|
|
57
|
+
|
|
58
|
+
**Example Response**
|
|
59
|
+
|
|
60
|
+
.. code-block:: json
|
|
61
|
+
|
|
62
|
+
{
|
|
63
|
+
"has_credentials": true,
|
|
64
|
+
"credential_count": 2
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
**Response Fields**
|
|
68
|
+
|
|
69
|
+
- ``has_credentials``: Boolean indicating if any credentials are configured
|
|
70
|
+
- ``credential_count``: Number of credential configurations available
|
|
71
|
+
|
|
72
|
+
**Note**
|
|
73
|
+
|
|
74
|
+
This endpoint does not perform learning context existence validation, so it will not return 404 for staff users.
|
|
75
|
+
"""
|
|
76
|
+
credential_count = CredentialConfiguration.objects.filter(learning_context_key=learning_context_key).count()
|
|
77
|
+
|
|
78
|
+
response_data = {
|
|
79
|
+
'has_credentials': credential_count > 0,
|
|
80
|
+
'credential_count': credential_count,
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
return Response(response_data, status=status.HTTP_200_OK)
|
learning_credentials/apps.py
CHANGED
|
@@ -5,6 +5,7 @@ from __future__ import annotations
|
|
|
5
5
|
from typing import ClassVar
|
|
6
6
|
|
|
7
7
|
from django.apps import AppConfig
|
|
8
|
+
from edx_django_utils.plugins.constants import PluginSettings, PluginURLs
|
|
8
9
|
|
|
9
10
|
|
|
10
11
|
class LearningCredentialsConfig(AppConfig):
|
|
@@ -15,10 +16,16 @@ class LearningCredentialsConfig(AppConfig):
|
|
|
15
16
|
|
|
16
17
|
# https://edx.readthedocs.io/projects/edx-django-utils/en/latest/plugins/how_tos/how_to_create_a_plugin_app.html
|
|
17
18
|
plugin_app: ClassVar[dict[str, dict[str, dict]]] = {
|
|
18
|
-
|
|
19
|
+
PluginURLs.CONFIG: {
|
|
19
20
|
'lms.djangoapp': {
|
|
20
|
-
|
|
21
|
-
|
|
21
|
+
PluginURLs.NAMESPACE: name,
|
|
22
|
+
PluginURLs.APP_NAME: name,
|
|
23
|
+
}
|
|
24
|
+
},
|
|
25
|
+
PluginSettings.CONFIG: {
|
|
26
|
+
'lms.djangoapp': {
|
|
27
|
+
'common': {PluginSettings.RELATIVE_PATH: 'settings.common'},
|
|
28
|
+
'production': {PluginSettings.RELATIVE_PATH: 'settings.production'},
|
|
22
29
|
},
|
|
23
30
|
},
|
|
24
31
|
}
|
learning_credentials/compat.py
CHANGED
|
@@ -73,12 +73,15 @@ def get_learning_context_name(learning_context_key: LearningContextKey) -> str:
|
|
|
73
73
|
return _get_learning_path_name(learning_context_key)
|
|
74
74
|
|
|
75
75
|
|
|
76
|
-
def get_course_enrollments(course_id: CourseKey) -> list[User]:
|
|
76
|
+
def get_course_enrollments(course_id: CourseKey, user_id: int | None = None) -> list[User]:
|
|
77
77
|
"""Get the course enrollments from Open edX."""
|
|
78
78
|
# noinspection PyUnresolvedReferences,PyPackageRequirements
|
|
79
79
|
from common.djangoapps.student.models import CourseEnrollment
|
|
80
80
|
|
|
81
81
|
enrollments = CourseEnrollment.objects.filter(course_id=course_id, is_active=True).select_related('user')
|
|
82
|
+
if user_id:
|
|
83
|
+
enrollments = enrollments.filter(user__id=user_id)
|
|
84
|
+
|
|
82
85
|
return [enrollment.user for enrollment in enrollments]
|
|
83
86
|
|
|
84
87
|
|
|
@@ -89,7 +89,7 @@ def _write_text_on_template(template: any, font: str, username: str, context_nam
|
|
|
89
89
|
pdf_canvas = canvas.Canvas(io.BytesIO(), pagesize=(template_width, template_height))
|
|
90
90
|
|
|
91
91
|
# Write the learner name.
|
|
92
|
-
pdf_canvas.setFont(font, 32)
|
|
92
|
+
pdf_canvas.setFont(font, options.get('name_size', 32))
|
|
93
93
|
name_color = options.get('name_color', '#000')
|
|
94
94
|
pdf_canvas.setFillColorRGB(*hex_to_rgb(name_color))
|
|
95
95
|
|
|
@@ -184,6 +184,7 @@ def generate_pdf_credential(
|
|
|
184
184
|
- font: The name of the font to use.
|
|
185
185
|
- name_y: The Y coordinate of the name on the credential (vertical position on the template).
|
|
186
186
|
- name_color: The color of the name on the credential (hexadecimal color code).
|
|
187
|
+
- name_size: The font size of the name on the credential. The default value is 32.
|
|
187
188
|
- context_name: Specify the custom course or Learning Path name.
|
|
188
189
|
- context_name_y: The Y coordinate of the context name on the credential (vertical position on the template).
|
|
189
190
|
- context_name_color: The color of the context name on the credential (hexadecimal color code).
|
learning_credentials/models.py
CHANGED
|
@@ -112,7 +112,7 @@ class CredentialConfiguration(TimeStampedModel):
|
|
|
112
112
|
task_path = f"{task.__wrapped__.__module__}.{task.__wrapped__.__name__}"
|
|
113
113
|
|
|
114
114
|
if self._state.adding:
|
|
115
|
-
schedule,
|
|
115
|
+
schedule, _created = IntervalSchedule.objects.get_or_create(every=10, period=IntervalSchedule.DAYS)
|
|
116
116
|
self.periodic_task = PeriodicTask.objects.create(
|
|
117
117
|
enabled=False,
|
|
118
118
|
interval=schedule,
|
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
"""App-specific settings for all environments."""
|
|
2
2
|
|
|
3
|
-
from
|
|
3
|
+
from typing import TYPE_CHECKING
|
|
4
4
|
|
|
5
|
+
if TYPE_CHECKING:
|
|
6
|
+
from django.conf import Settings
|
|
5
7
|
|
|
6
|
-
|
|
8
|
+
|
|
9
|
+
def plugin_settings(settings: 'Settings'):
|
|
7
10
|
"""Add `django_celery_beat` to `INSTALLED_APPS`."""
|
|
8
11
|
if 'django_celery_beat' not in settings.INSTALLED_APPS:
|
|
9
12
|
settings.INSTALLED_APPS += ('django_celery_beat',)
|
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
"""App-specific settings for production environments."""
|
|
2
2
|
|
|
3
|
-
from
|
|
3
|
+
from typing import TYPE_CHECKING
|
|
4
4
|
|
|
5
|
+
if TYPE_CHECKING:
|
|
6
|
+
from django.conf import Settings
|
|
5
7
|
|
|
6
|
-
|
|
8
|
+
|
|
9
|
+
def plugin_settings(settings: 'Settings'):
|
|
7
10
|
"""
|
|
8
11
|
Use the database scheduler for Celery Beat.
|
|
9
12
|
|
learning_credentials/urls.py
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
"""URLs for learning_credentials."""
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
# from django.views.generic import TemplateView # noqa: ERA001, RUF100
|
|
3
|
+
from django.urls import include, path
|
|
5
4
|
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
5
|
+
from .api import urls as api_urls
|
|
6
|
+
|
|
7
|
+
urlpatterns = [
|
|
8
|
+
path('api/learning_credentials/', include(api_urls)),
|
|
9
9
|
]
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: learning-credentials
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.3.0
|
|
4
4
|
Summary: A pluggable service for preparing Open edX credentials.
|
|
5
5
|
Author-email: OpenCraft <help@opencraft.com>
|
|
6
6
|
License-Expression: AGPL-3.0-or-later
|
|
@@ -21,6 +21,8 @@ Description-Content-Type: text/x-rst
|
|
|
21
21
|
License-File: LICENSE.txt
|
|
22
22
|
Requires-Dist: django
|
|
23
23
|
Requires-Dist: django-model-utils
|
|
24
|
+
Requires-Dist: edx-api-doc-tools
|
|
25
|
+
Requires-Dist: edx-django-utils
|
|
24
26
|
Requires-Dist: edx-opaque-keys
|
|
25
27
|
Requires-Dist: celery
|
|
26
28
|
Requires-Dist: django-celery-beat
|
|
@@ -122,7 +124,7 @@ file in this repo.
|
|
|
122
124
|
Reporting Security Issues
|
|
123
125
|
*************************
|
|
124
126
|
|
|
125
|
-
Please do not report security issues in public. Please email
|
|
127
|
+
Please do not report security issues in public. Please email help@opencraft.com.
|
|
126
128
|
|
|
127
129
|
.. |pypi-badge| image:: https://img.shields.io/pypi/v/learning-credentials.svg
|
|
128
130
|
:target: https://pypi.python.org/pypi/learning-credentials/
|
|
@@ -174,6 +176,21 @@ Unreleased
|
|
|
174
176
|
|
|
175
177
|
*
|
|
176
178
|
|
|
179
|
+
0.3.0 - 2025-09-17
|
|
180
|
+
******************
|
|
181
|
+
|
|
182
|
+
Added
|
|
183
|
+
=====
|
|
184
|
+
|
|
185
|
+
* REST API endpoint to check if credentials are configured for a learning context.
|
|
186
|
+
|
|
187
|
+
0.2.4 - 2025-09-07
|
|
188
|
+
|
|
189
|
+
Added
|
|
190
|
+
=====
|
|
191
|
+
|
|
192
|
+
* Option to customize the learner's name size on the PDF certificate.
|
|
193
|
+
|
|
177
194
|
0.2.3 - 2025-08-18
|
|
178
195
|
|
|
179
196
|
Modified
|
|
@@ -1,14 +1,19 @@
|
|
|
1
1
|
learning_credentials/__init__.py,sha256=8Q0-3Hdnfmcj41EKu1GSfzEfwWcYNDlItyEEke2r9bs,62
|
|
2
2
|
learning_credentials/admin.py,sha256=ynK3tVJwLsIeV7Jk66t1FAVyVsU1G-KRIAdRkycVTmA,10439
|
|
3
|
-
learning_credentials/apps.py,sha256=
|
|
4
|
-
learning_credentials/compat.py,sha256=
|
|
3
|
+
learning_credentials/apps.py,sha256=trdQxe-JRhUdUaOQoQWiGL1sn6I1sfDiTvdCwy8yGuw,1037
|
|
4
|
+
learning_credentials/compat.py,sha256=OvgzxnhGG5A7Ij65mBv3kyaYojKKQ381RbUGsWXtyOg,4651
|
|
5
5
|
learning_credentials/exceptions.py,sha256=UaqBVXFMWR2Iob7_LMb3j4NNVmWQFAgLi_MNMRUvGsI,290
|
|
6
|
-
learning_credentials/generators.py,sha256=
|
|
7
|
-
learning_credentials/models.py,sha256=
|
|
6
|
+
learning_credentials/generators.py,sha256=KCB166rOx-bwnm6kOc-Vz2HomGdJrQXqglv2MPVBF_Q,9075
|
|
7
|
+
learning_credentials/models.py,sha256=J_SCNiu42yhdi12eDMLsxNCTkJK7_vqneQjyGYG5KJ4,16048
|
|
8
8
|
learning_credentials/processors.py,sha256=LkdjmkLBnXc9qeMcksB1T8AQ5ZhYaECyQO__KfHB_aU,15212
|
|
9
9
|
learning_credentials/tasks.py,sha256=byoFEUvN_ayVaU5K5SlEiA7vu9BRPaSSmKnB9g5toec,1927
|
|
10
|
-
learning_credentials/urls.py,sha256=
|
|
11
|
-
learning_credentials/
|
|
10
|
+
learning_credentials/urls.py,sha256=gO_c930rzMylP-riQ9SGHXH9JIMF7ajySDT2Tc-E8x4,188
|
|
11
|
+
learning_credentials/api/__init__.py,sha256=q8sLFfwo5RwQu8FY6BJUL_Jrt3TUojbZK-Zlw9v08EM,40
|
|
12
|
+
learning_credentials/api/urls.py,sha256=wW27hrrJ7D_h8PbFDbSxzeaneNla0R-56gjKy9zISG8,216
|
|
13
|
+
learning_credentials/api/v1/__init__.py,sha256=A7ZqENtM4QM1A7j_cAfnzw4zn0kuyfXSWtylFIE0_f8,43
|
|
14
|
+
learning_credentials/api/v1/permissions.py,sha256=TqM50TpR3JGUgZgIgKZF0-R_g1_P2V9bqKzYXgk-VvY,3436
|
|
15
|
+
learning_credentials/api/v1/urls.py,sha256=6YqLS4aVfA1cuLOgVe4lFUFa38wVehYKleXBF8ImMm0,287
|
|
16
|
+
learning_credentials/api/v1/views.py,sha256=rkdj1AfRBDzrpRC5uGMAxTUf4P1zs-MSF9lpNMIgYLw,3005
|
|
12
17
|
learning_credentials/conf/locale/config.yaml,sha256=jPen2DmckNDKK30axCKEd2Q2ha9oOG3IBxrJ63Pvznk,2280
|
|
13
18
|
learning_credentials/migrations/0001_initial.py,sha256=61EvThCv-0UAnhCE5feyQVfjRodbp-6cDaAr4CY5PMA,8435
|
|
14
19
|
learning_credentials/migrations/0002_migrate_to_learning_credentials.py,sha256=vUhcnQKDdwOsppkXsjz2zZwOGMwIJ-fkQRsaj-K7l1o,1779
|
|
@@ -18,17 +23,17 @@ learning_credentials/migrations/0005_rename_processors_and_generators.py,sha256=
|
|
|
18
23
|
learning_credentials/migrations/0006_cleanup_openedx_certificates_tables.py,sha256=aJs_gOP4TmW9J-Dmr21m94jBfLQxzjAu6-ua7x4uYLE,727
|
|
19
24
|
learning_credentials/migrations/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
20
25
|
learning_credentials/settings/__init__.py,sha256=tofc5eg3Q2lV13Ff_jjg1ggGgWpKYoeESkP1qxl3H_A,29
|
|
21
|
-
learning_credentials/settings/common.py,sha256=
|
|
22
|
-
learning_credentials/settings/production.py,sha256=
|
|
26
|
+
learning_credentials/settings/common.py,sha256=Cck-nyFt11G1NLiz-bHfKJp8MV6sDZGqTwdbC8_1WE0,360
|
|
27
|
+
learning_credentials/settings/production.py,sha256=6P0P7JxbpWNsk4Lk8lfyxHirOWMgU4UWOb3EYKLjiVQ,542
|
|
23
28
|
learning_credentials/templates/learning_credentials/base.html,sha256=wtjBYqfHmOnyEY5tN3VGOmzYLsOD24MXdEUhTZ7OmwI,662
|
|
24
29
|
learning_credentials/templates/learning_credentials/edx_ace/certificate_generated/email/body.html,sha256=t-i1Ra9AC4pX-rPRifDJIvBBZuxCxdrFqg1NKTjHBOk,813
|
|
25
30
|
learning_credentials/templates/learning_credentials/edx_ace/certificate_generated/email/body.txt,sha256=IF_x8aF_-dORlQB-RCh0IkJDl2ktD489E8qGgLe9M3Y,677
|
|
26
31
|
learning_credentials/templates/learning_credentials/edx_ace/certificate_generated/email/from_name.txt,sha256=-n8tjPSwfwAfeOSZ1WhcCTrpOah4VswzMZ5mh63Pxow,20
|
|
27
32
|
learning_credentials/templates/learning_credentials/edx_ace/certificate_generated/email/head.html,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
28
33
|
learning_credentials/templates/learning_credentials/edx_ace/certificate_generated/email/subject.txt,sha256=S7Hc5T_sZSsSBXm5_H5HBNNv16Ohl0oZn0nVqqeWL0g,132
|
|
29
|
-
learning_credentials-0.
|
|
30
|
-
learning_credentials-0.
|
|
31
|
-
learning_credentials-0.
|
|
32
|
-
learning_credentials-0.
|
|
33
|
-
learning_credentials-0.
|
|
34
|
-
learning_credentials-0.
|
|
34
|
+
learning_credentials-0.3.0.dist-info/licenses/LICENSE.txt,sha256=GDpsPnW_1NKhPvZpZL9imz25P2nIpbwJPEhrlq4vPAU,34523
|
|
35
|
+
learning_credentials-0.3.0.dist-info/METADATA,sha256=8sXA-uNGK_6_5rckxyCuvv3vAKXALKcljj1QphW1mQk,7131
|
|
36
|
+
learning_credentials-0.3.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
37
|
+
learning_credentials-0.3.0.dist-info/entry_points.txt,sha256=hHqqLUEdzAN24v5OGBX9Fr-wh3ATDPjQjByKz03eC2Y,91
|
|
38
|
+
learning_credentials-0.3.0.dist-info/top_level.txt,sha256=Ce-4_leZe_nny7CpmkeRiemcDV6jIHpIvLjlcQBuf18,21
|
|
39
|
+
learning_credentials-0.3.0.dist-info/RECORD,,
|
learning_credentials/views.py
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
"""TODO."""
|
|
File without changes
|
{learning_credentials-0.2.3.dist-info → learning_credentials-0.3.0.dist-info}/entry_points.txt
RENAMED
|
File without changes
|
{learning_credentials-0.2.3.dist-info → learning_credentials-0.3.0.dist-info}/licenses/LICENSE.txt
RENAMED
|
File without changes
|
|
File without changes
|