33import logging
44from datetime import time as tm
55from html import escape
6+ from io import BytesIO
67
8+ import qrcode
79from cacheops import invalidate_obj
810from django import http
911from django .conf import settings
1012from django .contrib import messages
1113from django .contrib .auth import get_user_model
1214from django .contrib .auth .decorators import login_required
1315from django .db .models import Q
14- from django .http import Http404
16+ from django .http import Http404 , HttpResponse
1517from django .shortcuts import get_object_or_404 , redirect , render
1618from django .urls import reverse
1719from django .utils import timezone
@@ -430,7 +432,6 @@ def take_attendance_view(request, scheduled_activity_id):
430432 "show_checkboxes" : (scheduled_activity .block .locked or request .user .is_eighth_admin ),
431433 "show_icons" : (scheduled_activity .block .locked and scheduled_activity .block .attendance_locked () and not request .user .is_eighth_admin ),
432434 "bbcu_script" : settings .BBCU_SCRIPT ,
433- "is_sponsor" : scheduled_activity .user_is_sponsor (request .user ),
434435 }
435436
436437 if request .user .is_eighth_admin :
@@ -774,31 +775,21 @@ def email_students_view(request, scheduled_activity_id):
774775
775776@login_required
776777@deny_restricted
777- def student_attendance_view (request ):
778+ def student_attendance_view (request , attc = None , attf = None , attimef = None , atteachf = None ):
778779 blocks = EighthBlock .objects .get_blocks_today ()
779- attc = None
780- attf = None
781- attimef = None
782- atteachf = None
783780 if request .method == "POST" :
784781 now = timezone .localtime ()
785- dayblks = Day .objects .select_related ("day_type" ).get (date = now ).day_type .blocks . all ()
782+ dayblks = Day .objects .select_related ("day_type" ).get (date = now ).day_type .blocks
786783 for blk in blocks :
787784 blklet = blk .block_letter
788785 code = request .POST .get (blklet )
789786 if code is None :
790787 continue
791788 act = request .user .eighthscheduledactivity_set .get (block = blk )
792789 if act .get_code_mode_display () == "Auto" :
793- dayblk = None
794- for bk in dayblks :
795- name = bk .name
796- if name is None :
797- continue
798- if blklet in name and "8" in name :
799- dayblk = bk
800- break
801- if dayblk is None :
790+ try :
791+ dayblk = dayblks .get (name = "8" + blklet )
792+ except Exception :
802793 attimef = blk
803794 break
804795 start_time = shift_time (tm (hour = dayblk .start .hour , minute = dayblk .start .minute ), - 20 )
@@ -823,22 +814,85 @@ def student_attendance_view(request):
823814 else :
824815 attf = blk
825816 break
817+ return student_frontend (request , attc , attf , attimef , atteachf )
818+
819+
820+ @login_required
821+ @deny_restricted
822+ def student_frontend (request , attc = None , attf = None , attimef = None , atteachf = None ):
823+ blocks = EighthBlock .objects .get_blocks_today ()
826824 if blocks :
827825 sch_acts = []
826+ att_marked = []
828827 for b in blocks :
829828 try :
830829 act = request .user .eighthscheduledactivity_set .get (block = b )
831830 if act .activity .name != "z - Hybrid Sticky" :
832831 sch_acts .append ([b , act , ", " .join ([r .name for r in act .get_true_rooms ()]), ", " .join ([s .name for s in act .get_true_sponsors ()])])
833-
832+ signup = EighthSignup .objects .get (user = request .user , scheduled_activity = act )
833+ if not signup .was_absent :
834+ att_marked .append (b )
834835 except EighthScheduledActivity .DoesNotExist :
835836 sch_acts .append ([b , None ])
836837 response = render (
837838 request ,
838839 "eighth/student_submit_attendance.html" ,
839- context = {"sch_acts" : sch_acts , "attc" : attc , "attf" : attf , "attimef" : attimef , "atteachf" : atteachf },
840+ context = {"sch_acts" : sch_acts , "att_marked" : att_marked , " attc" : attc , "attf" : attf , "attimef" : attimef , "atteachf" : atteachf },
840841 )
841842 else :
842843 messages .error (request , "There are no eighth period blocks scheduled today." )
843844 response = redirect ("index" )
844845 return response
846+
847+
848+ @login_required
849+ @deny_restricted
850+ def qr_attendance_view (request , act_id , code ):
851+ act = get_object_or_404 (EighthScheduledActivity , id = act_id )
852+ error = False
853+ block = act .block
854+ attc = None
855+ attf = None
856+ attimef = None
857+ atteachf = None
858+ if act .get_code_mode_display () == "Auto" :
859+ now = timezone .localtime ()
860+ dayblks = Day .objects .select_related ("day_type" ).get (date = now ).day_type .blocks
861+ try :
862+ dayblk = dayblks .get (name = "8" + block .block_letter )
863+ start_time = shift_time (tm (hour = dayblk .start .hour , minute = dayblk .start .minute ), - 20 )
864+ end_time = shift_time (tm (hour = dayblk .end .hour , minute = dayblk .end .minute ), 20 )
865+ if not start_time <= now .time () <= end_time :
866+ attimef = block
867+ except Exception :
868+ attimef = block
869+ elif act .get_code_mode_display () == "Closed" :
870+ atteachf = block
871+ if not error :
872+ code = code .upper ()
873+ if code == act .attendance_code :
874+ present = EighthSignup .objects .filter (scheduled_activity = act , user__in = [request .user .id ])
875+ present .update (was_absent = False )
876+ for s in present :
877+ invalidate_obj (s )
878+ act .attendance_taken = True
879+ act .save ()
880+ invalidate_obj (act )
881+ attc = block
882+ else :
883+ attf = block
884+ return student_frontend (request , attc , attf , attimef , atteachf )
885+
886+
887+ def qr_image (request , act_id , code ):
888+ url = request .build_absolute_uri (reverse ("qr_attendance" , args = [act_id , code ]))
889+ qr = qrcode .QRCode (
890+ version = 1 ,
891+ box_size = 14 ,
892+ border = 2 ,
893+ )
894+ qr .add_data (url )
895+ img = qr .make_image (fill = "black" , back_color = "white" )
896+ buffer = BytesIO ()
897+ img .save (buffer , format = "PNG" )
898+ return HttpResponse (buffer .getvalue (), content_type = "image/png" )
0 commit comments