Add API route for training
This commit is contained in:
parent
801d35aa88
commit
57407be11e
|
@ -82,4 +82,4 @@ class Training(models.Model):
|
||||||
member_id = models.IntegerField(blank=True, null=True)
|
member_id = models.IntegerField(blank=True, null=True)
|
||||||
attendance_status = models.TextField(blank=True, null=True)
|
attendance_status = models.TextField(blank=True, null=True)
|
||||||
sign_up_date = models.DateField(default=date.today, blank=True, null=True)
|
sign_up_date = models.DateField(default=date.today, blank=True, null=True)
|
||||||
paid_date = models.DateField(default=date.today, blank=True, null=True)
|
paid_date = models.DateField(blank=True, null=True)
|
||||||
|
|
|
@ -226,19 +226,32 @@ class TransactionSerializer(serializers.ModelSerializer):
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class TrainingSerializer(serializers.ModelSerializer):
|
||||||
|
attendance_status = serializers.ChoiceField(['waiting for payment', 'withdrawn', 'rescheduled', 'no-show', 'attended', 'confirmed'])
|
||||||
|
session = serializers.PrimaryKeyRelatedField(queryset=models.Session.objects.all())
|
||||||
|
class Meta:
|
||||||
|
model = models.Training
|
||||||
|
fields = '__all__'
|
||||||
|
read_only_fields = ['user', 'sign_up_date', 'paid_date', 'member_id']
|
||||||
|
|
||||||
|
class StudentTrainingSerializer(TrainingSerializer):
|
||||||
|
attendance_status = serializers.ChoiceField(['waiting for payment', 'withdrawn'])
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class SessionSerializer(serializers.ModelSerializer):
|
class SessionSerializer(serializers.ModelSerializer):
|
||||||
student_count = serializers.SerializerMethodField()
|
student_count = serializers.SerializerMethodField()
|
||||||
course_name = serializers.SerializerMethodField()
|
course_name = serializers.SerializerMethodField()
|
||||||
instructor_name = serializers.SerializerMethodField()
|
instructor_name = serializers.SerializerMethodField()
|
||||||
datetime = serializers.DateTimeField()
|
datetime = serializers.DateTimeField()
|
||||||
instructor = serializers.PrimaryKeyRelatedField(queryset=models.User.objects.all())
|
|
||||||
course = serializers.PrimaryKeyRelatedField(queryset=models.Course.objects.all())
|
course = serializers.PrimaryKeyRelatedField(queryset=models.Course.objects.all())
|
||||||
|
students = TrainingSerializer(many=True, read_only=True)
|
||||||
class Meta:
|
class Meta:
|
||||||
model = models.Session
|
model = models.Session
|
||||||
fields = '__all__'
|
fields = '__all__'
|
||||||
read_only_fields = ['old_instructor']
|
read_only_fields = ['old_instructor', 'instructor']
|
||||||
def get_student_count(self, obj):
|
def get_student_count(self, obj):
|
||||||
return len(obj.students.all())
|
return len([x for x in obj.students.all() if x.attendance_status != 'withdrawn'])
|
||||||
def get_course_name(self, obj):
|
def get_course_name(self, obj):
|
||||||
return obj.course.name
|
return obj.course.name
|
||||||
def get_instructor_name(self, obj):
|
def get_instructor_name(self, obj):
|
||||||
|
@ -249,9 +262,7 @@ class SessionSerializer(serializers.ModelSerializer):
|
||||||
return obj.old_instructor or name
|
return obj.old_instructor or name
|
||||||
|
|
||||||
class SessionListSerializer(SessionSerializer):
|
class SessionListSerializer(SessionSerializer):
|
||||||
class Meta:
|
students = None
|
||||||
model = models.Session
|
|
||||||
fields = '__all__'
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
from django.contrib.auth.models import User, Group
|
from django.contrib.auth.models import User, Group
|
||||||
|
from django.shortcuts import get_object_or_404
|
||||||
from django.db.models import Max
|
from django.db.models import Max
|
||||||
from rest_framework import viewsets, views, mixins, generics, exceptions
|
from rest_framework import viewsets, views, mixins, generics, exceptions
|
||||||
from rest_framework.permissions import BasePermission, IsAuthenticated, SAFE_METHODS
|
from rest_framework.permissions import BasePermission, IsAuthenticated, SAFE_METHODS
|
||||||
|
@ -15,11 +16,21 @@ class AllowMetadata(BasePermission):
|
||||||
return request.method in ['OPTIONS', 'HEAD']
|
return request.method in ['OPTIONS', 'HEAD']
|
||||||
|
|
||||||
def is_admin_director(user):
|
def is_admin_director(user):
|
||||||
return user.is_staff or user.member.is_director or user.member.is_staff
|
return bool(user.is_staff or user.member.is_director or user.member.is_staff)
|
||||||
|
|
||||||
class IsOwnerOrAdmin(BasePermission):
|
class IsObjOwnerOrAdmin(BasePermission):
|
||||||
def has_object_permission(self, request, view, obj):
|
def has_object_permission(self, request, view, obj):
|
||||||
return request.user and (obj.user == request.user or is_admin_director(request.user))
|
return bool(request.user and (obj.user == request.user or is_admin_director(request.user)))
|
||||||
|
|
||||||
|
class IsSessionInstructorOrAdmin(BasePermission):
|
||||||
|
def has_object_permission(self, request, view, obj):
|
||||||
|
return bool(request.user and (obj.session.instructor == request.user or is_admin_director(request.user)))
|
||||||
|
|
||||||
|
class ReadOnly(BasePermission):
|
||||||
|
def has_permission(self, request, view):
|
||||||
|
return bool(request.method in SAFE_METHODS)
|
||||||
|
def has_object_permission(self, request, view, obj):
|
||||||
|
return bool(request.method in SAFE_METHODS)
|
||||||
|
|
||||||
class IsAdminOrReadOnly(BasePermission):
|
class IsAdminOrReadOnly(BasePermission):
|
||||||
def has_permission(self, request, view):
|
def has_permission(self, request, view):
|
||||||
|
@ -58,7 +69,7 @@ def gen_search_strings():
|
||||||
search_strings[string] = m.id
|
search_strings[string] = m.id
|
||||||
|
|
||||||
NUM_SEARCH_RESULTS = 10
|
NUM_SEARCH_RESULTS = 10
|
||||||
class SearchViewSet(viewsets.GenericViewSet, mixins.RetrieveModelMixin):
|
class SearchViewSet(Base, Retrieve):
|
||||||
permission_classes = [AllowMetadata | IsAuthenticated]
|
permission_classes = [AllowMetadata | IsAuthenticated]
|
||||||
|
|
||||||
def get_serializer_class(self):
|
def get_serializer_class(self):
|
||||||
|
@ -113,7 +124,7 @@ class SearchViewSet(viewsets.GenericViewSet, mixins.RetrieveModelMixin):
|
||||||
|
|
||||||
|
|
||||||
class MemberViewSet(Base, Retrieve, Update):
|
class MemberViewSet(Base, Retrieve, Update):
|
||||||
permission_classes = [AllowMetadata | IsAuthenticated, IsOwnerOrAdmin]
|
permission_classes = [AllowMetadata | IsAuthenticated, IsObjOwnerOrAdmin]
|
||||||
queryset = models.Member.objects.all()
|
queryset = models.Member.objects.all()
|
||||||
|
|
||||||
def get_serializer_class(self):
|
def get_serializer_class(self):
|
||||||
|
@ -124,7 +135,7 @@ class MemberViewSet(Base, Retrieve, Update):
|
||||||
|
|
||||||
|
|
||||||
class CardViewSet(Base, Create, Retrieve, Update, Destroy):
|
class CardViewSet(Base, Create, Retrieve, Update, Destroy):
|
||||||
permission_classes = [AllowMetadata | IsAuthenticated, IsOwnerOrAdmin, IsAdminOrReadOnly]
|
permission_classes = [AllowMetadata | IsAuthenticated, IsObjOwnerOrAdmin, IsAdminOrReadOnly]
|
||||||
queryset = models.Card.objects.all()
|
queryset = models.Card.objects.all()
|
||||||
serializer_class = serializers.CardSerializer
|
serializer_class = serializers.CardSerializer
|
||||||
|
|
||||||
|
@ -142,7 +153,6 @@ class CourseViewSet(Base, List, Retrieve, Create, Update):
|
||||||
|
|
||||||
class SessionViewSet(Base, List, Retrieve, Create, Update):
|
class SessionViewSet(Base, List, Retrieve, Create, Update):
|
||||||
permission_classes = [AllowMetadata | IsAuthenticated, IsAdminOrReadOnly | IsInstructorOrReadOnly]
|
permission_classes = [AllowMetadata | IsAuthenticated, IsAdminOrReadOnly | IsInstructorOrReadOnly]
|
||||||
serializer_class = serializers.SessionSerializer
|
|
||||||
|
|
||||||
def get_queryset(self):
|
def get_queryset(self):
|
||||||
if self.action == 'list':
|
if self.action == 'list':
|
||||||
|
@ -150,6 +160,37 @@ class SessionViewSet(Base, List, Retrieve, Create, Update):
|
||||||
else:
|
else:
|
||||||
return models.Session.objects.all()
|
return models.Session.objects.all()
|
||||||
|
|
||||||
|
def get_serializer_class(self):
|
||||||
|
if self.action == 'list':
|
||||||
|
return serializers.SessionListSerializer
|
||||||
|
else:
|
||||||
|
return serializers.SessionSerializer
|
||||||
|
|
||||||
|
def perform_create(self, serializer):
|
||||||
|
serializer.save(instructor=self.request.user)
|
||||||
|
|
||||||
|
class TrainingViewSet(Base, Retrieve, Create, Update):
|
||||||
|
permission_classes = [AllowMetadata | IsAuthenticated, IsObjOwnerOrAdmin | IsSessionInstructorOrAdmin | ReadOnly]
|
||||||
|
serializer_class = serializers.TrainingSerializer
|
||||||
|
queryset = models.Training.objects.all()
|
||||||
|
|
||||||
|
def get_serializer_class(self):
|
||||||
|
user = self.request.user
|
||||||
|
if is_admin_director(user) or user.member.is_instructor:
|
||||||
|
return serializers.TrainingSerializer
|
||||||
|
else:
|
||||||
|
return serializers.StudentTrainingSerializer
|
||||||
|
|
||||||
|
def perform_create(self, serializer):
|
||||||
|
session_id = self.request.data['session']
|
||||||
|
session = get_object_or_404(models.Session, id=session_id)
|
||||||
|
training = models.Training.objects.filter(user=self.request.user, session=session)
|
||||||
|
if training.exists():
|
||||||
|
raise exceptions.ValidationError('You have already registered')
|
||||||
|
if self.request.user == session.instructor:
|
||||||
|
raise exceptions.ValidationError('You are teaching this session')
|
||||||
|
serializer.save(user=self.request.user)
|
||||||
|
|
||||||
|
|
||||||
class UserView(views.APIView):
|
class UserView(views.APIView):
|
||||||
permission_classes = [AllowMetadata | IsAuthenticated]
|
permission_classes = [AllowMetadata | IsAuthenticated]
|
||||||
|
|
|
@ -7,11 +7,12 @@ from .api import views
|
||||||
|
|
||||||
router = routers.DefaultRouter()
|
router = routers.DefaultRouter()
|
||||||
#router.register(r'users', views.UserViewSet)
|
#router.register(r'users', views.UserViewSet)
|
||||||
|
router.register(r'cards', views.CardViewSet, basename='card')
|
||||||
|
router.register(r'search', views.SearchViewSet, basename='search')
|
||||||
router.register(r'members', views.MemberViewSet, basename='members')
|
router.register(r'members', views.MemberViewSet, basename='members')
|
||||||
router.register(r'courses', views.CourseViewSet, basename='course')
|
router.register(r'courses', views.CourseViewSet, basename='course')
|
||||||
router.register(r'sessions', views.SessionViewSet, basename='session')
|
router.register(r'sessions', views.SessionViewSet, basename='session')
|
||||||
router.register(r'search', views.SearchViewSet, basename='search')
|
router.register(r'training', views.TrainingViewSet, basename='training')
|
||||||
router.register(r'cards', views.CardViewSet, basename='card')
|
|
||||||
#router.register(r'me', views.FullMemberView, basename='fullmember')
|
#router.register(r'me', views.FullMemberView, basename='fullmember')
|
||||||
#router.register(r'registration', views.RegistrationViewSet, basename='register')
|
#router.register(r'registration', views.RegistrationViewSet, basename='register')
|
||||||
|
|
||||||
|
|
|
@ -116,7 +116,7 @@ export function InstructorClassDetail(props) {
|
||||||
};
|
};
|
||||||
|
|
||||||
export function InstructorClassList(props) {
|
export function InstructorClassList(props) {
|
||||||
const { course, setCourse, token, user } = props;
|
const { course, setCourse, token } = props;
|
||||||
const [open, setOpen] = useState(false);
|
const [open, setOpen] = useState(false);
|
||||||
const [input, setInput] = useState({});
|
const [input, setInput] = useState({});
|
||||||
const [error, setError] = useState(false);
|
const [error, setError] = useState(false);
|
||||||
|
@ -126,7 +126,7 @@ export function InstructorClassList(props) {
|
||||||
const handleSubmit = (e) => {
|
const handleSubmit = (e) => {
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
setSuccess(false);
|
setSuccess(false);
|
||||||
const data = { ...input, instructor: user.id, course: course.id };
|
const data = { ...input, course: course.id };
|
||||||
requester('/sessions/', 'POST', token, data)
|
requester('/sessions/', 'POST', token, data)
|
||||||
.then(res => {
|
.then(res => {
|
||||||
setSuccess(res.id);
|
setSuccess(res.id);
|
||||||
|
|
|
@ -2,7 +2,7 @@ import React, { useState, useEffect } from 'react';
|
||||||
import { Table } from 'semantic-ui-react';
|
import { Table } from 'semantic-ui-react';
|
||||||
|
|
||||||
export const isAdmin = (user) => user.is_staff || user.member.is_director || user.member.is_staff;
|
export const isAdmin = (user) => user.is_staff || user.member.is_director || user.member.is_staff;
|
||||||
export const isInstructor = (user) => isAdmin(user) || user.member.is_staff;
|
export const isInstructor = (user) => isAdmin(user) || user.member.is_instructor;
|
||||||
|
|
||||||
export const siteUrl = window.location.protocol + '//' + window.location.hostname;
|
export const siteUrl = window.location.protocol + '//' + window.location.hostname;
|
||||||
export const apiUrl = window.location.protocol + '//api.' + window.location.hostname;
|
export const apiUrl = window.location.protocol + '//api.' + window.location.hostname;
|
||||||
|
|
Loading…
Reference in New Issue
Block a user