Skip to content

Commit babdcc7

Browse files
authored
Merge pull request #2394 from gtech-mulearn/dev-server
Prod Server
2 parents 08442a8 + b4c1d8c commit babdcc7

26 files changed

+1647
-529
lines changed

.gitignore

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,5 +27,4 @@ env/
2727
venv/
2828
.vscode
2929
.idea
30-
3130
dump.rdb

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
# µLearn Backend Project
1+
# µLearn Backend Project
22

3-
## Project Setup
3+
## Project Setup
44

55
### Clone the Project
66
Clone the repository to your local machine using the following command:
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
from rest_framework import serializers
2+
from db.achievement import Achievement, UserAchievementsLog
3+
# from db.user import User
4+
5+
class AchievementSerializer(serializers.ModelSerializer):
6+
7+
class Meta:
8+
model = Achievement
9+
fields = '__all__'
10+
11+
class AchievementBasicSerializer(serializers.ModelSerializer):
12+
achievement_name = serializers.CharField(source='name')
13+
14+
class Meta:
15+
model = Achievement
16+
fields = ['id', 'achievement_name', 'description', 'icon', 'level_id', 'tags', 'template_id']
17+
18+
class UserAchievementsSerializer(serializers.ModelSerializer):
19+
achievement = AchievementBasicSerializer(source='achievement_id', read_only=True)
20+
21+
class Meta:
22+
model = UserAchievementsLog
23+
fields = ['id', 'user_id', 'achievement', 'is_issued', 'vc_url']
Lines changed: 209 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,209 @@
1+
from rest_framework.generics import get_object_or_404
2+
from rest_framework.views import APIView
3+
from . import achievement_serializer
4+
from db.achievement import Achievement, UserAchievementsLog
5+
from utils.response import CustomResponse
6+
from utils.permission import JWTUtils
7+
from db.user import User
8+
from db.task import Level
9+
import uuid
10+
from django.utils.timezone import now
11+
from django.core.exceptions import ObjectDoesNotExist, ValidationError
12+
class AchievementListAPIView(APIView):
13+
def get(self, request):
14+
user_id = JWTUtils.fetch_user_id(request)
15+
16+
if not user_id:
17+
return CustomResponse(general_message="Invalid or missing token").get_failure_response()
18+
19+
user = User.objects.filter(id=user_id).first()
20+
21+
if not user:
22+
return CustomResponse(general_message="User Not Exists").get_failure_response()
23+
24+
achievements = Achievement.objects.all()
25+
achievements_serializer = achievement_serializer.AchievementSerializer(achievements, many=True)
26+
27+
return CustomResponse(response=achievements_serializer.data).get_success_response()
28+
29+
class AchievementCreateAPIView(APIView):
30+
def post(self, request):
31+
user_id = JWTUtils.fetch_user_id(request)
32+
33+
if not user_id:
34+
return CustomResponse(general_message="Invalid or missing token").get_failure_response()
35+
36+
user = User.objects.filter(id=user_id).first()
37+
if not user:
38+
return CustomResponse(general_message="User Not Exists").get_failure_response()
39+
40+
data = request.data
41+
required_fields = ["name", "description", "icon", "tags", "type", "has_vc"]
42+
43+
missing_fields = [field for field in required_fields if field not in data]
44+
if missing_fields:
45+
return CustomResponse(
46+
general_message=f"Missing required fields: {', '.join(missing_fields)}"
47+
).get_failure_response()
48+
49+
if Achievement.objects.filter(name=data["name"]).exists():
50+
return CustomResponse(general_message="Name already exists").get_failure_response()
51+
52+
level = None
53+
if "level_id" in data and data["level_id"]:
54+
try:
55+
level = Level.objects.get(id=data["level_id"])
56+
except Level.DoesNotExist:
57+
return CustomResponse(general_message="Invalid level_id").get_failure_response()
58+
59+
achievement = Achievement.objects.create(
60+
id=str(uuid.uuid4()),
61+
name=data["name"],
62+
description=data["description"],
63+
icon=data["icon"],
64+
tags=data["tags"],
65+
type=data["type"],
66+
level_id=level,
67+
has_vc=data["has_vc"],
68+
template_id=data.get("template_id"),
69+
created_by=user,
70+
updated_by=user,
71+
created_at=now(),
72+
updated_at=now(),
73+
)
74+
75+
return CustomResponse(
76+
general_message=f"Achievement '{achievement.name}' created successfully!").get_success_response()
77+
78+
79+
class AchievementUpdateAPIView(APIView):
80+
def put(self, request, achievement_id=None):
81+
user_id = JWTUtils.fetch_user_id(request)
82+
83+
if not user_id:
84+
return CustomResponse(general_message="Invalid or missing token").get_failure_response()
85+
86+
user = User.objects.filter(id=user_id).first()
87+
if not user:
88+
return CustomResponse(general_message="User Not Exists").get_failure_response()
89+
90+
if not achievement_id:
91+
return CustomResponse(general_message="Achievement ID is required").get_failure_response()
92+
93+
try:
94+
achievement = Achievement.objects.get(id=achievement_id)
95+
except Achievement.DoesNotExist:
96+
return CustomResponse(general_message="Achievement not found").get_failure_response()
97+
98+
data = request.data.copy()
99+
data["updated_by"] = user_id
100+
101+
if "level_id" in data:
102+
if data["level_id"]:
103+
try:
104+
level = Level.objects.get(id=data["level_id"])
105+
data["level_id"] = level.id
106+
except Level.DoesNotExist:
107+
return CustomResponse(general_message="Invalid level_id").get_failure_response()
108+
else:
109+
data["level_id"] = None
110+
111+
serializer = achievement_serializer.AchievementSerializer(achievement, data=data, partial=True)
112+
113+
if serializer.is_valid():
114+
serializer.save()
115+
return CustomResponse(general_message="Achievement updated successfully").get_success_response()
116+
117+
return CustomResponse(general_message="Invalid Data", response=serializer.errors).get_failure_response()
118+
119+
120+
class AchievementDeleteAPIView(APIView):
121+
def delete(self, request, achievement_id):
122+
user_id = JWTUtils.fetch_user_id(request)
123+
124+
if not user_id:
125+
return CustomResponse(general_message="Invalid or missing token").get_failure_response()
126+
127+
user = User.objects.filter(id=user_id).first()
128+
if not user:
129+
return CustomResponse(general_message="User Not Exists").get_failure_response()
130+
131+
try:
132+
achievement = Achievement.objects.get(id=achievement_id)
133+
except Achievement.DoesNotExist:
134+
return CustomResponse(general_message="Achievement not found").get_failure_response()
135+
136+
achievement.delete()
137+
return CustomResponse(general_message="Achievement deleted successfully").get_success_response()
138+
139+
class UserAchievementsListAPIView(APIView):
140+
def get(self, request, muid):
141+
try:
142+
user = get_object_or_404(User, muid=muid)
143+
144+
user_achievements = (
145+
UserAchievementsLog.objects
146+
.filter(user_id=user.id)
147+
.select_related('achievement_id')
148+
.only('id', 'user_id', 'achievement_id', 'is_issued', 'vc_url', 'achievement_id__name', 'achievement_id__description')
149+
)
150+
151+
152+
if not user_achievements.exists():
153+
return CustomResponse(general_message="No achievements found for this user").get_failure_response()
154+
155+
156+
serializer = achievement_serializer.UserAchievementsSerializer(user_achievements, many=True)
157+
return CustomResponse(response=serializer.data).get_success_response()
158+
159+
except ValidationError:
160+
return CustomResponse(general_message="Invalid format for muid").get_failure_response()
161+
162+
except Exception as e:
163+
return CustomResponse(general_message=f"An unexpected error occurred: {str(e)}").get_failure_response()
164+
165+
166+
class UserAchievementsIssueAPIView(APIView):
167+
def post(self, request):
168+
user_id = JWTUtils.fetch_user_id(request)
169+
if not user_id:
170+
return CustomResponse(general_message="Invalid or missing token").get_failure_response()
171+
172+
achievement_id = request.data.get("achievement_id")
173+
vc_url = request.data.get("vc_url")
174+
175+
if not achievement_id:
176+
return CustomResponse(general_message="Achievement ID is required").get_failure_response()
177+
178+
if not vc_url:
179+
return CustomResponse(general_message="VC URL is required").get_failure_response()
180+
181+
if not User.objects.filter(id=user_id).exists():
182+
return CustomResponse(general_message="User Not Exists").get_failure_response()
183+
184+
try:
185+
user_achievement = UserAchievementsLog.objects.get(user_id=user_id, achievement_id=achievement_id)
186+
except UserAchievementsLog.DoesNotExist:
187+
return CustomResponse(general_message="Achievement record not found").get_failure_response()
188+
189+
if user_achievement.is_issued:
190+
return CustomResponse(general_message="This achievement has already been issued").get_failure_response()
191+
192+
UserAchievementsLog.objects.filter(user_id=user_id, achievement_id=achievement_id).update(is_issued=True, vc_url=vc_url)
193+
194+
return CustomResponse(general_message="Achievement issued successfully").get_success_response()
195+
196+
197+
198+
199+
200+
201+
202+
203+
204+
205+
206+
207+
208+
209+

api/dashboard/achievement/urls.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
from django.urls import path
2+
from . import achievement_views
3+
4+
urlpatterns = [
5+
path('list/', achievement_views.AchievementListAPIView.as_view(), name='achievement-list'),
6+
path('create/', achievement_views.AchievementCreateAPIView.as_view(), name='achievements-create'),
7+
path('update/<str:achievement_id>/', achievement_views.AchievementUpdateAPIView.as_view(), name='achievements-update'),
8+
path('delete/<str:achievement_id>/', achievement_views.AchievementDeleteAPIView.as_view(), name='achievements-delete'),
9+
path('list/user/<str:muid>/', achievement_views.UserAchievementsListAPIView.as_view(), name='achievements-user'),
10+
path('issue-vc/', achievement_views.UserAchievementsIssueAPIView.as_view(), name='achievements-issue'),
11+
]

api/dashboard/ig/dash_ig_serializer.py

Lines changed: 7 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,17 @@
1-
21
from rest_framework import serializers
32

43
from db.task import InterestGroup
54

65

76
class InterestGroupSerializer(serializers.ModelSerializer):
87

9-
updated_by = serializers.CharField(source='updated_by.full_name')
10-
created_by = serializers.CharField(source='created_by.full_name')
8+
updated_by = serializers.CharField(source="updated_by.full_name")
9+
created_by = serializers.CharField(source="created_by.full_name")
1110
members = serializers.SerializerMethodField()
12-
category = serializers.ChoiceField(choices=["hardware", "coder", "creative", "manager", "others"])
11+
category = serializers.ChoiceField(
12+
choices=["maker", "coder", "creative", "manager", "others"]
13+
)
14+
1315
class Meta:
1416
model = InterestGroup
1517
fields = [
@@ -33,11 +35,4 @@ class InterestGroupCreateUpdateSerializer(serializers.ModelSerializer):
3335

3436
class Meta:
3537
model = InterestGroup
36-
fields = [
37-
"name",
38-
"code",
39-
"category",
40-
"icon",
41-
"created_by",
42-
"updated_by"
43-
]
38+
fields = ["name", "code", "category", "icon", "created_by", "updated_by"]

0 commit comments

Comments
 (0)