feat: implement eligibility REST API endpoint#136
Conversation
There was a problem hiding this comment.
Pull request overview
This pull request adds new REST API endpoints for credential eligibility checking and generation, marking version 0.5.1rc1. The changes refactor the internal processor functions to return detailed eligibility information (as dictionaries) rather than simple lists of eligible user IDs, enabling more informative API responses. The PR introduces three new endpoints: one for checking eligibility with detailed progress information, one for triggering credential generation, and one for listing user credentials.
Changes:
- Refactored processor functions to return
dict[int, dict[str, Any]]with detailed eligibility and progress information instead oflist[int] - Added credential eligibility check endpoint (GET) with detailed progress data including current grades, completion percentages, and existing credential information
- Added credential generation endpoint (POST) for eligible users to request credential generation
- Added credential list endpoint (GET) with optional filtering by learning context
Reviewed changes
Copilot reviewed 12 out of 13 changed files in this pull request and generated 7 comments.
Show a summary per file
| File | Description |
|---|---|
| uv.lock | Updated version lock to 0.5.1rc1 |
| pyproject.toml | Bumped version to 0.5.1rc1 |
| CHANGELOG.rst | Added changelog entry for 0.5.1 release |
| learning_credentials/processors.py | Refactored all processor functions to return detailed dict results instead of user ID lists; added user_id parameter for single-user queries |
| learning_credentials/models.py | Added _call_retrieval_func and get_user_eligibility_details methods; updated get_eligible_user_ids to extract eligible IDs from detailed results |
| learning_credentials/api/v1/views.py | Added CredentialEligibilityView for GET/POST eligibility operations and CredentialListView for listing credentials; updated CredentialConfigurationCheckView permissions |
| learning_credentials/api/v1/serializers.py | Added CredentialModelSerializer, CredentialEligibilitySerializer, CredentialEligibilityResponseSerializer, and CredentialListResponseSerializer |
| learning_credentials/api/v1/permissions.py | Added IsAdminOrSelf permission class for username-based access control |
| learning_credentials/api/v1/urls.py | Added URL patterns for eligibility check, credential generation, and credential list endpoints |
| tests/test_views.py | Added comprehensive test suites for CredentialEligibilityView and CredentialListView |
| tests/test_processors.py | Updated tests to match new processor return type and added tests for detailed result structure |
| tests/test_models.py | Added tests for get_user_eligibility_details method |
| tests/conftest.py | Updated mock retrieval function to return dict format with user_id parameter support |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
8388035 to
6d8a532
Compare
|
Note for future reference: credential list view has been removed in 8d770c1 because we do not need it at the moment. |
3392da0 to
d8a6d98
Compare
d8a6d98 to
e693087
Compare
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 12 out of 13 changed files in this pull request and generated 8 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| 0.5.1 - 2026-03-17 | ||
| ****************** |
| path( | ||
| 'eligibility/<str:learning_context_key>/<int:credential_type_id>/', | ||
| CredentialEligibilityView.as_view(), | ||
| name='credential-generation', | ||
| ), |
| username = request.query_params.get('username') | ||
| user = get_object_or_404(User, username=username) if username else request.user | ||
|
|
| if TYPE_CHECKING: | ||
| from rest_framework.request import Request | ||
|
|
||
| logger = logging.getLogger(__name__) | ||
|
|
|
|
||
| configurations = CredentialConfiguration.objects.filter( | ||
| learning_context_key=learning_context_key | ||
| ).select_related('credential_type') |
| existing_credential = next((cred for cred in credentials if cred.configuration_id == config.id), None) | ||
|
|
| total_score += score * category_weights[category] | ||
|
|
||
| user_grades_with_total = {**user_grades, 'total': total_score} | ||
| is_eligible = _are_grades_passing_criteria(user_grades, required_grades, category_weights) |
| func = getattr(module, func_name) | ||
|
|
||
| custom_options = _deep_merge(self.credential_type.custom_options, self.custom_options) | ||
| return func(self.learning_context_key, custom_options) | ||
| return func(self.learning_context_key, custom_options, user_id=user_id) | ||
|
|
Merge checklist:
Check off if complete or not applicable: