diff --git a/dormitory/admin.py b/dormitory/admin.py index cefb013b..cf582089 100644 --- a/dormitory/admin.py +++ b/dormitory/admin.py @@ -5,6 +5,10 @@ admin.site.register(Dormitory) +@admin.register(Agreement) +class DormitoryAgreementAdmin(admin.ModelAdmin): + list_display = ['user', 'sign_time'] + @admin.register(DormitoryAssignment) class DormitoryAssignmentAdmin(admin.ModelAdmin): list_display = ['dormitory', 'user', 'bed_id', 'time'] diff --git a/dormitory/migrations/0003_agreement.py b/dormitory/migrations/0003_agreement.py new file mode 100644 index 00000000..1b2794ee --- /dev/null +++ b/dormitory/migrations/0003_agreement.py @@ -0,0 +1,28 @@ +# Generated by Django 4.2.3 on 2024-01-02 13:11 + +from django.conf import settings +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ('dormitory', '0002_initial'), + ] + + operations = [ + migrations.CreateModel( + name='Agreement', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('sign_time', models.DateTimeField(auto_now_add=True, verbose_name='签订时间')), + ('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL, verbose_name='用户')), + ], + options={ + 'verbose_name': '住宿协议', + 'verbose_name_plural': '住宿协议', + }, + ), + ] diff --git a/dormitory/models.py b/dormitory/models.py index 218d5978..fbbc85f6 100644 --- a/dormitory/models.py +++ b/dormitory/models.py @@ -7,8 +7,19 @@ __all__ = [ 'Dormitory', 'DormitoryAssignment', + 'Agreement' ] +class Agreement(models.Model): + + class Meta: + verbose_name = '住宿协议' + verbose_name_plural = verbose_name + + user = models.ForeignKey(User, on_delete=models.CASCADE, verbose_name='用户') + sign_time = models.DateTimeField('签订时间', auto_now_add=True) + + class Dormitory(models.Model): class Meta: verbose_name = '宿舍' diff --git a/dormitory/serializers.py b/dormitory/serializers.py index 9e3af25b..8509a5fe 100644 --- a/dormitory/serializers.py +++ b/dormitory/serializers.py @@ -1,6 +1,6 @@ from rest_framework import serializers -from dormitory.models import Dormitory, DormitoryAssignment +from dormitory.models import Dormitory, DormitoryAssignment, Agreement class DormitorySerializer(serializers.ModelSerializer): @@ -13,3 +13,19 @@ class DormitoryAssignmentSerializer(serializers.ModelSerializer): class Meta: model = DormitoryAssignment fields = '__all__' + + +class AgreementSerializerFixme(serializers.ModelSerializer): + class Meta: + model = Agreement + fields = ['id'] + + +class AgreementSerializer(serializers.ModelSerializer): + + user = serializers.StringRelatedField() + + class Meta: + model = Agreement + fields = ['user', 'sign_time'] + read_only_fields = ['user', 'sign_time'] diff --git a/dormitory/urls.py b/dormitory/urls.py index ac25ca02..f7f193a4 100644 --- a/dormitory/urls.py +++ b/dormitory/urls.py @@ -1,15 +1,20 @@ from django.urls import include, path from rest_framework.routers import DefaultRouter -from dormitory.views import (DormitoryAssignmentViewSet, - DormitoryAssignResultView, DormitoryRoutineQAView, - DormitoryViewSet) +from dormitory.views import ( + DormitoryAssignmentViewSet, DormitoryAssignResultView, + DormitoryRoutineQAView, DormitoryViewSet, + AgreementView, DormitoryAgreementViewSetFixme, DormitoryAgreementViewSet) router = DefaultRouter() router.register('dormitory', DormitoryViewSet, basename='dormitory') router.register('dormitoryassignment', DormitoryAssignmentViewSet, basename='dormitoryassignment') +router.register('agreement-query-fixme', DormitoryAgreementViewSetFixme, + basename='agreement-query-fixme') +router.register('agreement-query', DormitoryAgreementViewSet, + basename='agreement-query') urlpatterns = [ @@ -18,4 +23,6 @@ name='dormitory-routine-QA'), path('assign-result/', DormitoryAssignResultView.as_view(), name='dormitory-assign-result'), + path('agreement/', AgreementView.as_view(), + name='agreement'), ] diff --git a/dormitory/views.py b/dormitory/views.py index 35d86c97..14044e8c 100644 --- a/dormitory/views.py +++ b/dormitory/views.py @@ -2,11 +2,14 @@ from rest_framework import viewsets # TODO: Leaky dependency +from utils.marker import fix_me +from generic.models import User from app.models import NaturalPerson from app.view.base import ProfileTemplateView -from dormitory.models import Dormitory, DormitoryAssignment -from dormitory.serializers import (DormitoryAssignmentSerializer, - DormitorySerializer) +from dormitory.models import Dormitory, DormitoryAssignment, Agreement +from dormitory.serializers import ( + DormitoryAssignmentSerializer, DormitorySerializer, + AgreementSerializerFixme, AgreementSerializer) from questionnaire.models import AnswerSheet, AnswerText, Survey @@ -20,6 +23,23 @@ class DormitoryAssignmentViewSet(viewsets.ReadOnlyModelViewSet): serializer_class = DormitoryAssignmentSerializer +class DormitoryAgreementViewSetFixme(viewsets.ReadOnlyModelViewSet): + serializer_class = AgreementSerializerFixme + def get_queryset(self): + # Only active students need to sign the agreement + require_agreement = User.objects.filter(active=True, + utype=User.Type.STUDENT).contains(self.request.user) + if require_agreement: + return Agreement.objects.filter(user=self.request.user) + # A hack to return something, so that the frontend won't redirect + official_user = User.objects.get(username='zz00000') + Agreement.objects.get_or_create(user=official_user) + return Agreement.objects.filter(user=official_user) + +class DormitoryAgreementViewSet(viewsets.ReadOnlyModelViewSet): + queryset = Agreement.objects.all() + serializer_class = AgreementSerializer + class DormitoryRoutineQAView(ProfileTemplateView): template_name = 'dormitory/routine_QA.html' @@ -85,3 +105,17 @@ def show_dorm_assign(self): ) except DormitoryAssignment.DoesNotExist: self.extra_context.update(dorm_assign=False) + +class AgreementView(ProfileTemplateView): + template_name = 'dormitory/agreement.html' + page_name = '住宿协议' + need_prepare = False + + def get(self): + return self.render() + + @fix_me + def post(self): + Agreement.objects.get_or_create(user=self.request.user) + from django.shortcuts import redirect + return redirect("/welcome") diff --git a/static/assets/js/dorm_forcement.js b/static/assets/js/dorm_forcement.js new file mode 100644 index 00000000..5dc2bd44 --- /dev/null +++ b/static/assets/js/dorm_forcement.js @@ -0,0 +1,32 @@ +const dorm_path = '/dormitory/agreement'; +const query_path = '/dormitory/agreement-query-fixme'; + +function currentIsDormPage() { + var current_url = window.location.pathname; + return current_url.includes(dorm_path); +} + +function getAgreementState() { + return fetch(query_path) + .then(response => response.json()) + .then(data => { + // Bad design: + // If user do not have to sign, + // or user has signed, return is not empty. + return data.length > 0; + }) + .catch(error => { + console.error('Error fetching agreement state:', error); + return true; // Pretend user has signed on network error. + }); +} + +$(function() { + if (!currentIsDormPage()) { + getAgreementState().then(signed => { + if (!signed) { + window.location.href = dorm_path; + } + }); + } +}); diff --git a/templates/base.html b/templates/base.html index 127ea74e..fdfb0689 100644 --- a/templates/base.html +++ b/templates/base.html @@ -380,6 +380,8 @@