learning-credentials 0.3.0rc2__py3-none-any.whl → 0.3.0rc4__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.
@@ -45,7 +45,7 @@ class CredentialEligibilitySerializer(serializers.Serializer):
45
45
  name = serializers.CharField()
46
46
  is_eligible = serializers.BooleanField()
47
47
  existing_credential = serializers.UUIDField(required=False, allow_null=True)
48
- existing_credential_url = serializers.URLField(required=False, allow_null=True)
48
+ existing_credential_url = serializers.URLField(required=False, allow_blank=True, allow_null=True)
49
49
 
50
50
  current_grades = serializers.DictField(required=False)
51
51
  required_grades = serializers.DictField(required=False)
@@ -2,9 +2,15 @@
2
2
 
3
3
  from django.urls import path
4
4
 
5
- from .views import CredentialEligibilityView, CredentialListView
5
+ from .views import CredentialConfigurationCheckView, CredentialEligibilityView, CredentialListView
6
6
 
7
7
  urlpatterns = [
8
+ # Credential configuration check endpoint
9
+ path(
10
+ 'configured/<str:learning_context_key>/',
11
+ CredentialConfigurationCheckView.as_view(),
12
+ name='credential-configuration-check',
13
+ ),
8
14
  # Credential eligibility endpoints
9
15
  path('eligibility/<str:learning_context_key>/', CredentialEligibilityView.as_view(), name='credential-eligibility'),
10
16
  path(
@@ -28,6 +28,66 @@ if TYPE_CHECKING:
28
28
  logger = logging.getLogger(__name__)
29
29
 
30
30
 
31
+ class CredentialConfigurationCheckView(APIView):
32
+ """API view to check if any credentials are configured for a specific learning context."""
33
+
34
+ permission_classes = (IsAuthenticated, IsAdminOrSelf, CanAccessLearningContext)
35
+
36
+ @apidocs.schema(
37
+ parameters=[
38
+ apidocs.string_parameter(
39
+ "learning_context_key",
40
+ ParameterLocation.PATH,
41
+ description=(
42
+ "Learning context identifier. Can be a course key (course-v1:OpenedX+DemoX+DemoCourse) "
43
+ "or learning path key (path-v1:OpenedX+DemoX+DemoPath+Demo)"
44
+ ),
45
+ ),
46
+ ],
47
+ responses={
48
+ 200: "Boolean indicating if credentials are configured.",
49
+ 400: "Invalid context key format.",
50
+ 404: "Learning context not found or user does not have access.",
51
+ },
52
+ )
53
+ def get(self, _request: "Request", learning_context_key: str) -> Response:
54
+ """
55
+ Check if any credentials are configured for the given learning context.
56
+
57
+ **Example Request**
58
+
59
+ GET /api/learning_credentials/v1/configured/course-v1:OpenedX+DemoX+DemoCourse/
60
+
61
+ **Response Values**
62
+
63
+ If the request is successful, an HTTP 200 "OK" response is returned.
64
+
65
+ **Example Response**
66
+
67
+ ```json
68
+ {
69
+ "has_credentials": true,
70
+ "credential_count": 2
71
+ }
72
+ ```
73
+
74
+ **Response Fields**
75
+ - `has_credentials`: Boolean indicating if any credentials are configured
76
+ - `credential_count`: Number of credential configurations available
77
+
78
+ **Note**
79
+ This endpoint does not perform learning context existence validation, so it will not return 404 for staff users.
80
+ """
81
+ credential_count = CredentialConfiguration.objects.filter(learning_context_key=learning_context_key).count()
82
+
83
+ response_data = {
84
+ 'has_credentials': credential_count > 0,
85
+ 'credential_count': credential_count,
86
+ }
87
+
88
+ return Response(response_data, status=status.HTTP_200_OK)
89
+
90
+
31
91
  class CredentialEligibilityView(APIView):
32
92
  """
33
93
  API view for credential eligibility and generation.
@@ -37,6 +97,10 @@ class CredentialEligibilityView(APIView):
37
97
  Supported Learning Contexts:
38
98
  - Course keys: `course-v1:org+course+run`
39
99
  - Learning path keys: `path-v1:org+path+run+group`
100
+
101
+ **Staff Features**:
102
+ - Staff users can view eligibility for any user by providing `username` parameter
103
+ - Non-staff users can only view their own eligibility
40
104
  """
41
105
 
42
106
  permission_classes = (IsAuthenticated, IsAdminOrSelf, CanAccessLearningContext)
@@ -93,6 +157,9 @@ class CredentialEligibilityView(APIView):
93
157
  - Step-by-step progress for learning paths
94
158
  - Eligibility status for each credential type
95
159
 
160
+ **Query Parameters:**
161
+ - `username` (staff only): View eligibility for a specific user
162
+
96
163
  **Example Request**
97
164
 
98
165
  GET /api/learning_credentials/v1/eligibility/course-v1:OpenedX+DemoX+DemoCourse/
@@ -150,11 +217,14 @@ class CredentialEligibilityView(APIView):
150
217
  }
151
218
  ```
152
219
  """
220
+ username = request.query_params.get('username')
221
+ user = get_object_or_404(User, username=username) if username else request.user
222
+
153
223
  configurations = CredentialConfiguration.objects.filter(
154
224
  learning_context_key=learning_context_key
155
225
  ).select_related('credential_type')
156
226
 
157
- eligibility_data = [self._get_eligibility_data(request.user, config) for config in configurations]
227
+ eligibility_data = [self._get_eligibility_data(user, config) for config in configurations]
158
228
 
159
229
  response_data = {
160
230
  'context_key': learning_context_key,
@@ -210,6 +280,9 @@ class CredentialEligibilityView(APIView):
210
280
  **Notification:**
211
281
  Users will receive an email notification when credential generation completes.
212
282
 
283
+ **Query Parameters:**
284
+ - `username` (staff only): Trigger credential generation for a specific user
285
+
213
286
  **Example Request**
214
287
 
215
288
  POST /api/learning_credentials/v1/eligibility/course-v1:OpenedX+DemoX+DemoCourse/1/
@@ -228,6 +301,9 @@ class CredentialEligibilityView(APIView):
228
301
  }
229
302
  ```
230
303
  """
304
+ username = request.query_params.get('username')
305
+ user = get_object_or_404(User, username=username) if username else request.user
306
+
231
307
  config = get_object_or_404(
232
308
  CredentialConfiguration.objects.select_related('credential_type'),
233
309
  learning_context_key=learning_context_key,
@@ -236,7 +312,7 @@ class CredentialEligibilityView(APIView):
236
312
 
237
313
  existing_credential = (
238
314
  Credential.objects.filter(
239
- user_id=request.user.id,
315
+ user_id=user.id,
240
316
  learning_context_key=learning_context_key,
241
317
  credential_type=config.credential_type.name,
242
318
  )
@@ -247,10 +323,10 @@ class CredentialEligibilityView(APIView):
247
323
  if existing_credential:
248
324
  return Response({"detail": "User already has a credential of this type."}, status=status.HTTP_409_CONFLICT)
249
325
 
250
- if not config.get_eligible_user_ids(user_id=request.user.id):
326
+ if not config.get_eligible_user_ids(user_id=user.id):
251
327
  return Response({"detail": "User is not eligible for this credential."}, status=status.HTTP_400_BAD_REQUEST)
252
328
 
253
- generate_credential_for_user_task.delay(config.id, request.user.id)
329
+ generate_credential_for_user_task.delay(config.id, user.id)
254
330
  return Response({"detail": "Credential generation started."}, status=status.HTTP_201_CREATED)
255
331
 
256
332
 
@@ -307,8 +383,6 @@ class CredentialListView(APIView):
307
383
 
308
384
  **Query Parameters:**
309
385
  - `username` (staff only): View credentials for a specific user
310
-
311
- **Path Parameters:**
312
386
  - `learning_context_key` (optional): Filter credentials by learning context
313
387
 
314
388
  **Response includes:**
@@ -26,9 +26,9 @@ class LearningCredentialsConfig(AppConfig):
26
26
  'common': {'relative_path': 'settings.common'},
27
27
  'production': {'relative_path': 'settings.production'},
28
28
  },
29
- 'cms.djangoapp': {
30
- 'common': {'relative_path': 'settings.common'},
31
- 'production': {'relative_path': 'settings.production'},
32
- },
29
+ # 'cms.djangoapp': {
30
+ # 'common': {'relative_path': 'settings.common'},
31
+ # 'production': {'relative_path': 'settings.production'},
32
+ # },
33
33
  },
34
34
  }
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: learning-credentials
3
- Version: 0.3.0rc2
3
+ Version: 0.3.0rc4
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
@@ -1,6 +1,6 @@
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=F3W0q1BCWOm2MxqLr7GsDGkwqvNq3Icxc9OqgomdD7k,1128
3
+ learning_credentials/apps.py,sha256=COijTeVYYFZgQP_-gHJNy2ITqhFT0dfimC0PtYwnynM,1136
4
4
  learning_credentials/compat.py,sha256=g32MLgTnSZLGa6H3Qsq1WIPJXWPlFaNVuyZfbZXsKR8,4832
5
5
  learning_credentials/core_api.py,sha256=ZVNPm7SQk54roZ8rmZ0Bc6T6NLvumKWJZjJepAxM6L8,3232
6
6
  learning_credentials/exceptions.py,sha256=UaqBVXFMWR2Iob7_LMb3j4NNVmWQFAgLi_MNMRUvGsI,290
@@ -14,9 +14,9 @@ learning_credentials/api/__init__.py,sha256=q8sLFfwo5RwQu8FY6BJUL_Jrt3TUojbZK-Zl
14
14
  learning_credentials/api/urls.py,sha256=JfGSbzvC5d7s9dRq4C0d-AzTDuOVnen3wvFYSJQoEdQ,255
15
15
  learning_credentials/api/v1/__init__.py,sha256=A7ZqENtM4QM1A7j_cAfnzw4zn0kuyfXSWtylFIE0_f8,43
16
16
  learning_credentials/api/v1/permissions.py,sha256=DZMa2A6Q1ltPdWCksr7I8Ltv_qV46B9yvMM0UXXWo8E,2379
17
- learning_credentials/api/v1/serializers.py,sha256=c4gNva-OzBUfmKHFOgsb1Ti1GiHSnsyIeT3gYBt7fMk,2685
18
- learning_credentials/api/v1/urls.py,sha256=n8CTXgKyXyCkgNr210Jl5c5HQ2bZ1iEYMNLSnaB39Hc,585
19
- learning_credentials/api/v1/views.py,sha256=LrlHRzURWi_zEii_zq55CH05tpC2ZqPhZLyebx1Jy8M,13606
17
+ learning_credentials/api/v1/serializers.py,sha256=etBfIlTnb3vC8GcwTOQUUVRnTP3d_f_7Ca-azCm2O_0,2703
18
+ learning_credentials/api/v1/urls.py,sha256=sS7KK-GUgKsGYmhbCqx86O3SWofNvg1KnxeBAJpzwtk,831
19
+ learning_credentials/api/v1/views.py,sha256=OBORrqOVm1OhqGoqXp1yYt-6FqnXs8LdqAmDSs3g_dM,16319
20
20
  learning_credentials/conf/locale/config.yaml,sha256=jPen2DmckNDKK30axCKEd2Q2ha9oOG3IBxrJ63Pvznk,2280
21
21
  learning_credentials/migrations/0001_initial.py,sha256=61EvThCv-0UAnhCE5feyQVfjRodbp-6cDaAr4CY5PMA,8435
22
22
  learning_credentials/migrations/0002_migrate_to_learning_credentials.py,sha256=vUhcnQKDdwOsppkXsjz2zZwOGMwIJ-fkQRsaj-K7l1o,1779
@@ -37,9 +37,9 @@ learning_credentials/templates/learning_credentials/edx_ace/certificate_generate
37
37
  learning_credentials/templates/learning_credentials/edx_ace/certificate_generated/email/from_name.txt,sha256=-n8tjPSwfwAfeOSZ1WhcCTrpOah4VswzMZ5mh63Pxow,20
38
38
  learning_credentials/templates/learning_credentials/edx_ace/certificate_generated/email/head.html,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
39
39
  learning_credentials/templates/learning_credentials/edx_ace/certificate_generated/email/subject.txt,sha256=S7Hc5T_sZSsSBXm5_H5HBNNv16Ohl0oZn0nVqqeWL0g,132
40
- learning_credentials-0.3.0rc2.dist-info/licenses/LICENSE.txt,sha256=GDpsPnW_1NKhPvZpZL9imz25P2nIpbwJPEhrlq4vPAU,34523
41
- learning_credentials-0.3.0rc2.dist-info/METADATA,sha256=HgEuWC93fRcs84MGP4vJ6qMOiueVHhtAcPBGi-Mw3WA,6864
42
- learning_credentials-0.3.0rc2.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
43
- learning_credentials-0.3.0rc2.dist-info/entry_points.txt,sha256=kaYKfkH1k_yFaGqe-MXjBxA5RsjkqOLxz7XLrF5BUC0,258
44
- learning_credentials-0.3.0rc2.dist-info/top_level.txt,sha256=Ce-4_leZe_nny7CpmkeRiemcDV6jIHpIvLjlcQBuf18,21
45
- learning_credentials-0.3.0rc2.dist-info/RECORD,,
40
+ learning_credentials-0.3.0rc4.dist-info/licenses/LICENSE.txt,sha256=GDpsPnW_1NKhPvZpZL9imz25P2nIpbwJPEhrlq4vPAU,34523
41
+ learning_credentials-0.3.0rc4.dist-info/METADATA,sha256=Twx2Sgek5BKOv8UZYWsIQd0Z5Ph-1sONWyjIfY61_2I,6864
42
+ learning_credentials-0.3.0rc4.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
43
+ learning_credentials-0.3.0rc4.dist-info/entry_points.txt,sha256=6aT7brHXkmLp829ZgV8t9R__wXLsLOsYKmZWOvPlGyc,166
44
+ learning_credentials-0.3.0rc4.dist-info/top_level.txt,sha256=Ce-4_leZe_nny7CpmkeRiemcDV6jIHpIvLjlcQBuf18,21
45
+ learning_credentials-0.3.0rc4.dist-info/RECORD,,
@@ -1,6 +1,3 @@
1
- [cms.djangoapp]
2
- learning_credentials = learning_credentials.apps:LearningCredentialsConfig
3
-
4
1
  [lms.djangoapp]
5
2
  learning_credentials = learning_credentials.apps:LearningCredentialsConfig
6
3