mirror of
https://github.com/lemeow125/StudE-Backend.git
synced 2024-11-17 06:19:24 +08:00
Added endpoint for querying avatars of users in a study group and for individual study group details
This commit is contained in:
parent
0ecfb2223a
commit
c8fca412b8
7 changed files with 199 additions and 16 deletions
|
@ -0,0 +1,21 @@
|
||||||
|
# Generated by Django 4.2.3 on 2023-09-30 15:35
|
||||||
|
|
||||||
|
from django.db import migrations
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('accounts', '0002_initial'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterModelOptions(
|
||||||
|
name='customuser',
|
||||||
|
options={},
|
||||||
|
),
|
||||||
|
migrations.AlterUniqueTogether(
|
||||||
|
name='customuser',
|
||||||
|
unique_together={('first_name', 'last_name')},
|
||||||
|
),
|
||||||
|
]
|
106
stude/schema.yml
106
stude/schema.yml
|
@ -135,7 +135,7 @@ paths:
|
||||||
name: id
|
name: id
|
||||||
schema:
|
schema:
|
||||||
type: integer
|
type: integer
|
||||||
description: A unique integer value identifying this user.
|
description: A unique integer value identifying this custom user.
|
||||||
required: true
|
required: true
|
||||||
tags:
|
tags:
|
||||||
- api
|
- api
|
||||||
|
@ -155,7 +155,7 @@ paths:
|
||||||
name: id
|
name: id
|
||||||
schema:
|
schema:
|
||||||
type: integer
|
type: integer
|
||||||
description: A unique integer value identifying this user.
|
description: A unique integer value identifying this custom user.
|
||||||
required: true
|
required: true
|
||||||
tags:
|
tags:
|
||||||
- api
|
- api
|
||||||
|
@ -187,7 +187,7 @@ paths:
|
||||||
name: id
|
name: id
|
||||||
schema:
|
schema:
|
||||||
type: integer
|
type: integer
|
||||||
description: A unique integer value identifying this user.
|
description: A unique integer value identifying this custom user.
|
||||||
required: true
|
required: true
|
||||||
tags:
|
tags:
|
||||||
- api
|
- api
|
||||||
|
@ -218,7 +218,7 @@ paths:
|
||||||
name: id
|
name: id
|
||||||
schema:
|
schema:
|
||||||
type: integer
|
type: integer
|
||||||
description: A unique integer value identifying this user.
|
description: A unique integer value identifying this custom user.
|
||||||
required: true
|
required: true
|
||||||
tags:
|
tags:
|
||||||
- api
|
- api
|
||||||
|
@ -763,6 +763,26 @@ paths:
|
||||||
items:
|
items:
|
||||||
$ref: '#/components/schemas/StudyGroup'
|
$ref: '#/components/schemas/StudyGroup'
|
||||||
description: ''
|
description: ''
|
||||||
|
/api/v1/study_groups/{name}/:
|
||||||
|
get:
|
||||||
|
operationId: api_v1_study_groups_retrieve
|
||||||
|
parameters:
|
||||||
|
- in: path
|
||||||
|
name: name
|
||||||
|
schema:
|
||||||
|
type: string
|
||||||
|
required: true
|
||||||
|
tags:
|
||||||
|
- api
|
||||||
|
security:
|
||||||
|
- jwtAuth: []
|
||||||
|
responses:
|
||||||
|
'200':
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/StudyGroupDetail'
|
||||||
|
description: ''
|
||||||
/api/v1/study_groups/create/:
|
/api/v1/study_groups/create/:
|
||||||
post:
|
post:
|
||||||
operationId: api_v1_study_groups_create_create
|
operationId: api_v1_study_groups_create_create
|
||||||
|
@ -851,7 +871,7 @@ paths:
|
||||||
schema:
|
schema:
|
||||||
type: array
|
type: array
|
||||||
items:
|
items:
|
||||||
$ref: '#/components/schemas/StudyGroup'
|
$ref: '#/components/schemas/StudyGroupDistance'
|
||||||
description: ''
|
description: ''
|
||||||
/api/v1/subjects/:
|
/api/v1/subjects/:
|
||||||
get:
|
get:
|
||||||
|
@ -1068,21 +1088,18 @@ components:
|
||||||
readOnly: true
|
readOnly: true
|
||||||
user:
|
user:
|
||||||
type: string
|
type: string
|
||||||
|
description: Required. 150 characters or fewer. Letters, digits and @/./+/-/_
|
||||||
|
only.
|
||||||
study_group:
|
study_group:
|
||||||
type: string
|
type: string
|
||||||
message_content:
|
message_content:
|
||||||
type: string
|
type: string
|
||||||
maxLength: 1024
|
|
||||||
timestamp:
|
timestamp:
|
||||||
type: string
|
type: string
|
||||||
format: date-time
|
format: date-time
|
||||||
readOnly: true
|
|
||||||
required:
|
required:
|
||||||
- id
|
- id
|
||||||
- message_content
|
- message_content
|
||||||
- study_group
|
|
||||||
- timestamp
|
|
||||||
- user
|
|
||||||
PasswordResetConfirm:
|
PasswordResetConfirm:
|
||||||
type: object
|
type: object
|
||||||
properties:
|
properties:
|
||||||
|
@ -1348,6 +1365,75 @@ components:
|
||||||
- name
|
- name
|
||||||
- subject
|
- subject
|
||||||
- timestamp
|
- timestamp
|
||||||
|
StudyGroupDetail:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
id:
|
||||||
|
type: integer
|
||||||
|
readOnly: true
|
||||||
|
name:
|
||||||
|
type: string
|
||||||
|
students:
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
type: string
|
||||||
|
subject:
|
||||||
|
type: string
|
||||||
|
location:
|
||||||
|
type: string
|
||||||
|
landmark:
|
||||||
|
type: string
|
||||||
|
nullable: true
|
||||||
|
timestamp:
|
||||||
|
type: string
|
||||||
|
format: date
|
||||||
|
readOnly: true
|
||||||
|
required:
|
||||||
|
- id
|
||||||
|
- location
|
||||||
|
- name
|
||||||
|
- students
|
||||||
|
- subject
|
||||||
|
- timestamp
|
||||||
|
StudyGroupDistance:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
id:
|
||||||
|
type: integer
|
||||||
|
readOnly: true
|
||||||
|
name:
|
||||||
|
type: string
|
||||||
|
students:
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
type: string
|
||||||
|
subject:
|
||||||
|
type: string
|
||||||
|
location:
|
||||||
|
type: string
|
||||||
|
landmark:
|
||||||
|
type: string
|
||||||
|
nullable: true
|
||||||
|
radius:
|
||||||
|
type: number
|
||||||
|
format: double
|
||||||
|
distance:
|
||||||
|
type: string
|
||||||
|
readOnly: true
|
||||||
|
default: 0
|
||||||
|
timestamp:
|
||||||
|
type: string
|
||||||
|
format: date
|
||||||
|
readOnly: true
|
||||||
|
required:
|
||||||
|
- distance
|
||||||
|
- id
|
||||||
|
- location
|
||||||
|
- name
|
||||||
|
- radius
|
||||||
|
- students
|
||||||
|
- subject
|
||||||
|
- timestamp
|
||||||
SubjectInstance:
|
SubjectInstance:
|
||||||
type: object
|
type: object
|
||||||
properties:
|
properties:
|
||||||
|
|
|
@ -4,6 +4,16 @@ from accounts.models import CustomUser
|
||||||
from subjects.models import Subject
|
from subjects.models import Subject
|
||||||
from drf_extra_fields.geo_fields import PointField
|
from drf_extra_fields.geo_fields import PointField
|
||||||
from landmarks.models import Landmark
|
from landmarks.models import Landmark
|
||||||
|
from drf_extra_fields.fields import Base64ImageField
|
||||||
|
from djoser.serializers import UserSerializer as BaseUserSerializer
|
||||||
|
|
||||||
|
|
||||||
|
class CustomUserAvatarSerializer(BaseUserSerializer):
|
||||||
|
avatar = Base64ImageField()
|
||||||
|
|
||||||
|
class Meta(BaseUserSerializer.Meta):
|
||||||
|
model = CustomUser
|
||||||
|
fields = ['avatar', 'username']
|
||||||
|
|
||||||
|
|
||||||
class CustomUserKeyRelatedField(serializers.PrimaryKeyRelatedField):
|
class CustomUserKeyRelatedField(serializers.PrimaryKeyRelatedField):
|
||||||
|
@ -13,6 +23,21 @@ class CustomUserKeyRelatedField(serializers.PrimaryKeyRelatedField):
|
||||||
return str(value)
|
return str(value)
|
||||||
|
|
||||||
|
|
||||||
|
class StudyGroupDetailSerializer(serializers.ModelSerializer):
|
||||||
|
name = serializers.CharField()
|
||||||
|
students = serializers.StringRelatedField(many=True)
|
||||||
|
subject = serializers.SlugRelatedField(
|
||||||
|
many=False, slug_field='name', queryset=Subject.objects.all(), required=True, allow_null=False)
|
||||||
|
location = PointField()
|
||||||
|
landmark = serializers.SlugRelatedField(
|
||||||
|
queryset=Landmark.objects.all(), many=False, slug_field='name', required=False, allow_null=True)
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
model = StudyGroup
|
||||||
|
fields = '__all__'
|
||||||
|
read_only_fields = ['landmark', 'radius', 'students', 'distance']
|
||||||
|
|
||||||
|
|
||||||
class StudyGroupSerializer(serializers.ModelSerializer):
|
class StudyGroupSerializer(serializers.ModelSerializer):
|
||||||
name = serializers.CharField()
|
name = serializers.CharField()
|
||||||
students = serializers.StringRelatedField(many=True)
|
students = serializers.StringRelatedField(many=True)
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
from django.urls import include, path
|
from django.urls import include, path
|
||||||
from .views import StudyGroupListView, StudyGroupListNearView, StudyGroupCreateView
|
from .views import StudyGroupListView, StudyGroupListNearView, StudyGroupCreateView, StudyGroupDetailView, StudyGroupAvatarsView
|
||||||
from rest_framework import routers
|
from rest_framework import routers
|
||||||
|
|
||||||
router = routers.DefaultRouter()
|
router = routers.DefaultRouter()
|
||||||
|
@ -7,7 +7,10 @@ router.register(r'create', StudyGroupCreateView,
|
||||||
basename='Create Study Group')
|
basename='Create Study Group')
|
||||||
|
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
|
|
||||||
path('', StudyGroupListView.as_view()),
|
path('', StudyGroupListView.as_view()),
|
||||||
path('near/', StudyGroupListNearView.as_view()),
|
|
||||||
path('', include(router.urls)),
|
path('', include(router.urls)),
|
||||||
|
path('near/', StudyGroupListNearView.as_view()),
|
||||||
|
path('member_avatars/', StudyGroupAvatarsView.as_view()),
|
||||||
|
path('<str:name>/', StudyGroupDetailView.as_view()),
|
||||||
]
|
]
|
||||||
|
|
|
@ -2,7 +2,7 @@ from django.shortcuts import render
|
||||||
from rest_framework import generics, mixins
|
from rest_framework import generics, mixins
|
||||||
from rest_framework.exceptions import PermissionDenied
|
from rest_framework.exceptions import PermissionDenied
|
||||||
from rest_framework.permissions import IsAuthenticated
|
from rest_framework.permissions import IsAuthenticated
|
||||||
from .serializers import StudyGroupSerializer, StudyGroupCreateSerializer, StudyGroupDistanceSerializer
|
from .serializers import StudyGroupSerializer, StudyGroupCreateSerializer, StudyGroupDistanceSerializer, StudyGroupDetailSerializer, CustomUserAvatarSerializer
|
||||||
from .models import StudyGroup
|
from .models import StudyGroup
|
||||||
from subjects.models import Subject, SubjectInstance
|
from subjects.models import Subject, SubjectInstance
|
||||||
from student_status.models import StudentStatus
|
from student_status.models import StudentStatus
|
||||||
|
@ -12,10 +12,48 @@ from django.contrib.gis.db.models.functions import Distance
|
||||||
from rest_framework import status
|
from rest_framework import status
|
||||||
from rest_framework.response import Response
|
from rest_framework.response import Response
|
||||||
from rest_framework import permissions
|
from rest_framework import permissions
|
||||||
|
from accounts.models import CustomUser
|
||||||
|
|
||||||
# Create your views here.
|
# Create your views here.
|
||||||
|
|
||||||
|
|
||||||
|
class StudyGroupAvatarsView(generics.ListAPIView):
|
||||||
|
permission_classes = [IsAuthenticated]
|
||||||
|
serializer_class = CustomUserAvatarSerializer
|
||||||
|
queryset = CustomUser.objects.all()
|
||||||
|
|
||||||
|
def get_queryset(self):
|
||||||
|
# Get user
|
||||||
|
user = self.request.user
|
||||||
|
|
||||||
|
# Get status of user
|
||||||
|
user_status = StudentStatus.objects.filter(user=user).first()
|
||||||
|
|
||||||
|
# Return error if not in study group
|
||||||
|
if (not user_status.study_group):
|
||||||
|
raise exceptions.ValidationError("You are not in a study group")
|
||||||
|
|
||||||
|
# Get study group of user
|
||||||
|
user_study_group = user_status.study_group
|
||||||
|
|
||||||
|
# Get students in that study group
|
||||||
|
study_group_student_ids = user_study_group.students.values_list(
|
||||||
|
'user', flat=True)
|
||||||
|
|
||||||
|
# Then get user instances of those students
|
||||||
|
study_group_users = CustomUser.objects.filter(
|
||||||
|
id__in=study_group_student_ids)
|
||||||
|
|
||||||
|
# Return to be parsed by serializer
|
||||||
|
return study_group_users
|
||||||
|
|
||||||
|
|
||||||
|
class StudyGroupMembersAvatarView(generics.ListAPIView):
|
||||||
|
permission_classes = [IsAuthenticated]
|
||||||
|
serializer_class = StudyGroupCreateSerializer
|
||||||
|
queryset = CustomUser.objects.all()
|
||||||
|
|
||||||
|
|
||||||
class StudyGroupCreateView(viewsets.ModelViewSet):
|
class StudyGroupCreateView(viewsets.ModelViewSet):
|
||||||
http_method_names = ['patch', 'post', 'delete']
|
http_method_names = ['patch', 'post', 'delete']
|
||||||
permission_classes = [IsAuthenticated]
|
permission_classes = [IsAuthenticated]
|
||||||
|
@ -23,6 +61,13 @@ class StudyGroupCreateView(viewsets.ModelViewSet):
|
||||||
queryset = StudyGroup.objects.all()
|
queryset = StudyGroup.objects.all()
|
||||||
|
|
||||||
|
|
||||||
|
class StudyGroupDetailView(generics.RetrieveAPIView):
|
||||||
|
permission_classes = [IsAuthenticated]
|
||||||
|
serializer_class = StudyGroupDetailSerializer
|
||||||
|
queryset = StudyGroup.objects.all()
|
||||||
|
lookup_field = 'name'
|
||||||
|
|
||||||
|
|
||||||
class StudyGroupListView(generics.ListAPIView):
|
class StudyGroupListView(generics.ListAPIView):
|
||||||
permission_classes = [IsAuthenticated]
|
permission_classes = [IsAuthenticated]
|
||||||
serializer_class = StudyGroupSerializer
|
serializer_class = StudyGroupSerializer
|
||||||
|
|
|
@ -6,10 +6,13 @@ from study_groups.models import StudyGroup
|
||||||
|
|
||||||
class MessageSerializer(serializers.ModelSerializer):
|
class MessageSerializer(serializers.ModelSerializer):
|
||||||
user = serializers.SlugRelatedField(
|
user = serializers.SlugRelatedField(
|
||||||
queryset=CustomUser.objects.all(), slug_field='full_name', required=True)
|
queryset=CustomUser.objects.all(), slug_field='username', required=False)
|
||||||
study_group = serializers.SlugRelatedField(
|
study_group = serializers.SlugRelatedField(
|
||||||
queryset=StudyGroup.objects.all(), slug_field='name', required=True)
|
queryset=StudyGroup.objects.all(), slug_field='name', required=False)
|
||||||
|
message_content = serializers.CharField()
|
||||||
|
timestamp = serializers.DateTimeField(format="%I:%M %p", required=False)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Message
|
model = Message
|
||||||
fields = '__all__'
|
fields = '__all__'
|
||||||
|
read_only_fields = ['user', 'study_group', 'timestamp']
|
||||||
|
|
|
@ -48,5 +48,5 @@ class MessageViewSet(viewsets.ModelViewSet):
|
||||||
|
|
||||||
# Now fetch the Messages matching the study group id
|
# Now fetch the Messages matching the study group id
|
||||||
messages = Message.objects.filter(
|
messages = Message.objects.filter(
|
||||||
study_group=user_study_group).order_by('-timestamp')
|
study_group=user_study_group).order_by('timestamp')
|
||||||
return messages
|
return messages
|
||||||
|
|
Loading…
Reference in a new issue