diff --git a/.github/ISSUE_TEMPLATE/feature.md b/.github/ISSUE_TEMPLATE/feature.md new file mode 100644 index 00000000..13e62510 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature.md @@ -0,0 +1,60 @@ +--- +name: Mulearn Backend +about: MuLearn Community Issues Template +title: "[Muelearn] Button for likes" +labels: MuLearn Community +assignees: '' + +--- + +## Description +[Provide a brief description of the feature, including why it is needed and what it will accomplish. You can skip any of Goals, Expected Outcome, Implementation Details, Mockups / Wireframes if they are irrelevant. Please note that this section of the ticket is suggestive & you can structure it as per your prerogative.] + +## Goals +- [ ] [Goal 1] +- [ ] [Goal 2] +- [ ] [Goal 3] +- [ ] [Goal 4] +- [ ] [Goal 5] + +## Expected Outcome +[Describe in detail what the final product or result should look like and how it should behave.] + +## Acceptance Criteria +- [ ] [Criteria 1] +- [ ] [Criteria 2] +- [ ] [Criteria 3] +- [ ] [Criteria 4] +- [ ] [Criteria 5] + +## Implementation Details +[List any technical details about the proposed implementation, including any specific technologies that will be used.] + +## Mockups / Wireframes +[Include links to any visual aids, mockups, wireframes, or diagrams that help illustrate what the final product should look like. This is not always necessary, but can be very helpful in many cases.] + +--- +[Please note that the below section of the ticket ****has to be in the format as mentioned as it is key to enabling proper listing of the project.**** Please only choose the options mentioned under the headings wherever applicable.] + +### Product Name +[Product Name: For eg: Beckn, Sunbird Obsrv etc] + + +### Project Name +[Project Name: Descriptive of the ticket] + + +### Tech Skills Needed: +[Required technical skills for the project] + +### Mentor(s) +[@Mentor1] [@Mentor2] [@Mentor3] + +### Complexity +Pick one of [High]/[Medium]/[Low] + +### Category +Pick one or more of [CI/CD], [Integrations], [Performance Improvement], [Security], [UI/UX/Design], [Bug], [Feature], [Documentation], [Deployment], [Test], [PoC] + +### Sub Category +Pick one or more of [API], [Database], [Analytics], [Refactoring], [Data Science], [Machine Learning], [Accessibility], [Internationalization], [Localization], [Frontend], [Backend], [Mobile], [SEO], [Configuration], [Deprecation], [Breaking Change], [Maintenance], [Support], [Question], [Technical Debt], [Beginner friendly], [Research], [Reproducible], [Needs Reproduction]. diff --git a/.github/ISSUE_TEMPLATE/feature_form.yml b/.github/ISSUE_TEMPLATE/feature_form.yml new file mode 100644 index 00000000..93f8a74c --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_form.yml @@ -0,0 +1,222 @@ +name: Mulearn Ticket Form +description: Create a new Ticket for MuLearn Community +title: "[MuLearn Community]: " +labels: ["MuLearn Community"] +body: + - type: textarea + id: ticket-description + validations: + required: true + attributes: + label: Ticket Contents + value: | + ## Description + [Provide a brief description of the feature, including why it is needed and what it will accomplish.] + + - type: textarea + id: ticket-goals + validations: + required: true + attributes: + label: Goals + description: List the goals of the feature. + value: | + ## Goals + - [ ] [Goal 1] + - [ ] [Goal 2] + - [ ] [Goal 3] + - [ ] [Goal 4] + - [ ] [Goal 5] + + - type: textarea + id: ticket-expected-outcome + attributes: + label: Expected Outcome + description: Describe in detail what the final product or result should look like and how it should behave. + + - type: textarea + id: ticket-acceptance-criteria + attributes: + label: Acceptance Criteria + description: List the acceptance criteria for this feature. + + - type: textarea + id: ticket-implementation-details + validations: + required: true + attributes: + label: Implementation Details + description: List any technical details about the proposed implementation, including any specific technologies that will be used. + + - type: textarea + id: ticket-mockups + attributes: + label: Mockups/Wireframes + description: Include links to any visual aids, mockups, wireframes, or diagrams that help illustrate what the final product should look like. This is not always necessary, but can be very helpful in many cases. + + - type: input + id: ticket-product + attributes: + label: Product Name + placeholder: Enter Product Name + validations: + required: true + + - type: input + id: ticket-governance-domain + attributes: + label: Domain + placeholder: Enter Area of Governance + + - type: dropdown + id: ticket-technical-skills-required + attributes: + label: Tech Skills Needed + description: Select the technologies needed for this ticket (use Ctrl or Command to select multiple) + multiple: true + options: + - .NET + - Agile + - Angular + - Artificial Intelligence + - ASP.NET + - AWS + - Babel + - Bootstrap + - C# + - Chart.js + - CI/CD + - Computer Vision + - CORS + - cURL + - Cypress + - D3.js + - Database + - Debugging + - Design + - DevOps + - Django + - Docker + - Electron + - ESLint + - Express.js + - Feature + - Flask + - Go + - GraphQL + - HTML + - Ionic + - Jest + - Java + - JavaScript + - Jenkins + - JWT + - Kubernetes + - Laravel + - Machine Learning + - Maintenance + - Material-UI + - Microservices + - MongoDB + - Mobile + - Mockups + - Mocha + - Natural Language Processing + - NestJS + - Node.js + - NUnit + - OAuth + - Performance Improvement + - Prettier + - Python + - Question + - React + - React Native + - Redux + - RESTful APIs + - Ruby + - Ruby on Rails + - Rust + - Scala + - Security + - Selenium + - SEO + - Serverless + - Solidity + - Spring Boot + - SQL + - Swagger + - Tailwind CSS + - Test + - Testing Library + - Three.js + - TypeScript + - UI/UX/Design + - Virtual Reality + - Vue.js + - WebSockets + - Webpack + - Other + validations: + required: true + + - type: textarea + id: ticket-mentors + attributes: + label: Mentor(s) + description: Please tag relevant mentors for the ticket + validations: + required: true + + - type: dropdown + id: ticket-complexity + attributes: + label: Complexity + description: Choose a complexity describing the complexity of your ticket + multiple: false + options: + - Low + - Medium + - High + validations: + required: true + + - type: dropdown + id: ticket-category + attributes: + label: Category + description: Choose the categories that best describe your ticket + multiple: true + options: + - API + - Analytics + - Accessibility + - Backend + - Breaking Change + - Beginner Friendly + - Configuration + - CI/CD + - Database + - Data Science + - Deprecation + - Documentation + - Delpoyment + - Frontend + - Internationalization + - Localization + - Machine Learning + - Maintenance + - Mobile + - Performance Improvement + - Question + - Refactoring + - Research + - Needs Reproduction + - SEO + - Security + - Testing + - Other + validations: + required: true + + diff --git a/api/dashboard/coupon/coupon_view.py b/api/dashboard/coupon/coupon_view.py index f75ac9ac..7b3367d0 100644 --- a/api/dashboard/coupon/coupon_view.py +++ b/api/dashboard/coupon/coupon_view.py @@ -1,18 +1,21 @@ from rest_framework.views import APIView from utils.response import CustomResponse +from utils.types import CouponResponseKey, DiscountTypes from db.user import UserCouponLink from rest_framework.response import Response - - - class CouponApi(APIView): def post(self, request): - if coupon_code := request.data.get('data'): + if coupon_code := request.data.get("data"): if UserCouponLink.objects.filter(coupon=coupon_code).exists(): - - return CustomResponse(general_message="Coupon is valid").get_success_response() + data = { + CouponResponseKey.DISCOUNT_TYPE.value: DiscountTypes.PERCENTAGE.value, + CouponResponseKey.DISCOUNT_VALUE.value: 100, + CouponResponseKey.TICKET.value: ["bb3a795e-060d-4f6d-9bc7-107632589c35"], + } + return CustomResponse( + general_message="Coupon is valid", response=data + ).get_success_response() return CustomResponse(general_message="Coupon is invalid").get_failure_response() return CustomResponse(general_message="Coupon code is required").get_failure_response() - diff --git a/api/integrations/wadhwani/wadhwani_views.py b/api/integrations/wadhwani/wadhwani_views.py index 538fd97b..71812466 100644 --- a/api/integrations/wadhwani/wadhwani_views.py +++ b/api/integrations/wadhwani/wadhwani_views.py @@ -22,10 +22,11 @@ def post(self, request): class WadhwaniUserLogin(APIView): def post(self, request): - url = settings.WADHWANI_BASE_URL + "api/v1/iamservice/oauth/login" + url = settings.WADHWANI_BASE_URL + "/api/v1/iamservice/oauth/login" + token = request.data.get('Client-Auth-Token', None) + course_root_id = request.data.get("course_root_id", None) user_id = JWTUtils.fetch_user_id(request) user = User.objects.get(id=user_id) - token = request.headers.get('Client-Auth-Token') data = { "name": user.full_name, "candidateId": user.id, @@ -34,36 +35,39 @@ def post(self, request): "mobile": f"+91-{user.mobile}", "countryCode": "IN", "userLanguageCode": "en", - "token": token + "token": token, + "courseRootId": course_root_id } response = requests.post(url, data=data) return CustomResponse(response=response.json()).get_success_response() class WadhwaniCourseDetails(APIView): - def get(self, request): - url = settings.WADHWANI_BASE_URL + "api/v1/courseservice/oauth/client/courses" - token = request.headers.get('Client-Auth-Token') + def post(self, request): + url = settings.WADHWANI_BASE_URL + "/api/v1/courseservice/oauth/client/courses" + token = request.data.get('Client-Auth-Token', None) headers = {'Authorization': token} response = requests.get(url, headers=headers) return CustomResponse(response=response.json()).get_success_response() class WadhwaniCourseEnrollStatus(APIView): - def get(self, request): - url = settings.WADHWANI_BASE_URL + "api/v1/courseservice/oauth/client/courses" - token = request.headers.get('Client-Auth-Token') + def post(self, request): + url = settings.WADHWANI_BASE_URL + "/api/v1/courseservice/oauth/client/courses" + token = request.data.get('Client-Auth-Token', None) headers = {'Authorization': token} user_id = JWTUtils.fetch_user_id(request) user = User.objects.get(id=user_id) + if response.json()["status"] == "ERROR": + return CustomResponse(general_message="User doesn't have any enrolled courses").get_failure_response() response = requests.get(url, params={"username": user.email}, headers=headers) return CustomResponse(response=response.json()).get_success_response() class WadhwaniCourseQuizData(APIView): - def get(self, request): - url = settings.WADHWANI_BASE_URL + f"api/v1/courseservice/oauth/course/{course_id}/reports/quiz/student/{user.email}" - token = request.headers.get('Client-Auth-Token') + def post(self, request): + token = request.data.get('Client-Auth-Token', None) + course_id = request.data.get('course_id', None) headers = {'Authorization': token} - course_id = request.query_params.get('course_id') user_id = JWTUtils.fetch_user_id(request) user = User.objects.get(id=user_id) + url = settings.WADHWANI_BASE_URL + f"/api/v1/courseservice/oauth/course/{course_id}/reports/quiz/student/{user.email}" response = requests.get(url, headers=headers) return CustomResponse(response=response.json()).get_success_response() \ No newline at end of file diff --git a/mulearnbackend/settings.py b/mulearnbackend/settings.py index 63983e49..7575b8cb 100644 --- a/mulearnbackend/settings.py +++ b/mulearnbackend/settings.py @@ -232,9 +232,9 @@ FROM_MAIL = decouple_config("FROM_MAIL") FR_DOMAIN_NAME = decouple_config("FR_DOMAIN_NAME") -# WADHWANI_CLIENT_AUTH_URL = decouple_config("WADHWANI_CLIENT_AUTH_URL") -# WADHWANI_CLIENT_SECRET = decouple_config("WADHWANI_CLIENT_SECRET") -# WADHWANI_BASE_URL = decouple_config("WADHWANI_BASE_URL") +WADHWANI_CLIENT_AUTH_URL = decouple_config("WADHWANI_CLIENT_AUTH_URL") +WADHWANI_CLIENT_SECRET = decouple_config("WADHWANI_CLIENT_SECRET") +WADHWANI_BASE_URL = decouple_config("WADHWANI_BASE_URL") DEFAULT_FILE_STORAGE = "django.core.files.storage.FileSystemStorage" diff --git a/utils/types.py b/utils/types.py index 9113abb5..47f351cf 100644 --- a/utils/types.py +++ b/utils/types.py @@ -126,6 +126,14 @@ class Lc(Enum): KARMA = 20 TASK_HASHTAG = '#lcmeetreport' +class CouponResponseKey(Enum): + DISCOUNT_TYPE = 'discount_type' + DISCOUNT_VALUE = 'discount_value' + TICKET = 'ticket' + +class DiscountTypes(Enum): + PERCENTAGE = 'percentage' + AMOUNT = 'amount' DEFAULT_HACKATHON_FORM_FIELDS = { 'name': 'system',