11import csv
22import io
33import logging
4+ from datetime import time as tm
45from html import escape
56
67from cacheops import invalidate_obj
2526from ....utils .date import get_date_range_this_year
2627from ...auth .decorators import attendance_taker_required , deny_restricted , eighth_admin_required
2728from ...dashboard .views import gen_sponsor_schedule
29+ from ...schedule .models import Day
2830from ...schedule .views import decode_date
2931from ..forms .admin .activities import ActivitySelectionForm
3032from ..forms .admin .blocks import BlockSelectionForm
3133from ..models import EighthActivity , EighthBlock , EighthScheduledActivity , EighthSignup , EighthSponsor , EighthWaitlist
3234from ..tasks import email_scheduled_activity_students_task
3335from ..utils import get_start_date
36+ from .signup import shift_time
3437
3538logger = logging .getLogger (__name__ )
3639
@@ -304,13 +307,20 @@ def take_attendance_view(request, scheduled_activity_id):
304307 status = 403 ,
305308 )
306309
310+ if "att_code_mode" in request .POST :
311+ selected_mode = int (request .POST ["att_code_mode" ])
312+ if scheduled_activity .code_mode != selected_mode :
313+ scheduled_activity .set_code_mode (selected_mode )
314+ redirect_url = reverse (url_name , args = [scheduled_activity .id ])
315+ return redirect (redirect_url )
316+
307317 if not scheduled_activity .block .locked and request .user .is_eighth_admin :
308318 messages .success (request , "Note: Taking attendance on an unlocked block." )
309319
310- present_user_ids = list (request .POST .keys ()) # list of member.ids checked off
320+ present_user_ids = list (request .POST .keys ()) # list of member.ids checked off
311321
312322 if request .FILES .get ("attendance" ):
313- #csv attendance
323+ # csv attendance
314324 try :
315325 csv_file = request .FILES ["attendance" ].read ().decode ("utf-8" )
316326 data = csv .DictReader (io .StringIO (csv_file ))
@@ -335,6 +345,9 @@ def take_attendance_view(request, scheduled_activity_id):
335345 except (csv .Error , ValueError , KeyError , IndexError ):
336346 messages .error (request , "Could not interpret file. Did you upload a Google Meet attendance report without modification?" )
337347
348+ if "att_code_mode" in present_user_ids :
349+ present_user_ids .remove ("att_code_mode" )
350+
338351 csrf = "csrfmiddlewaretoken"
339352 if csrf in present_user_ids :
340353 present_user_ids .remove (csrf )
@@ -417,7 +430,7 @@ def take_attendance_view(request, scheduled_activity_id):
417430 "show_checkboxes" : (scheduled_activity .block .locked or request .user .is_eighth_admin ),
418431 "show_icons" : (scheduled_activity .block .locked and scheduled_activity .block .attendance_locked () and not request .user .is_eighth_admin ),
419432 "bbcu_script" : settings .BBCU_SCRIPT ,
420- "attendance_code " : scheduled_activity .get_attendance_code ( ),
433+ "is_sponsor " : scheduled_activity .user_is_sponsor ( request . user ),
421434 }
422435
423436 if request .user .is_eighth_admin :
@@ -757,3 +770,75 @@ def email_students_view(request, scheduled_activity_id):
757770 context = {"scheduled_activity" : scheduled_activity }
758771
759772 return render (request , "eighth/email_students.html" , context )
773+
774+
775+ @login_required
776+ @deny_restricted
777+ def student_attendance_view (request ):
778+ blocks = EighthBlock .objects .get_blocks_today ()
779+ attc = None
780+ attf = None
781+ attimef = None
782+ atteachf = None
783+ if request .method == "POST" :
784+ now = timezone .localtime ()
785+ dayblks = Day .objects .select_related ("day_type" ).get (date = now ).day_type .blocks .all ()
786+ for blk in blocks :
787+ blklet = blk .block_letter
788+ code = request .POST .get (blklet )
789+ if code is None :
790+ continue
791+ act = request .user .eighthscheduledactivity_set .get (block = blk )
792+ 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 :
802+ attimef = blk
803+ break
804+ start_time = shift_time (tm (hour = dayblk .start .hour , minute = dayblk .start .minute ), - 20 )
805+ end_time = shift_time (tm (hour = dayblk .end .hour , minute = dayblk .end .minute ), 20 )
806+ if not start_time <= now .time () <= end_time :
807+ attimef = blk
808+ break
809+ elif act .get_code_mode_display () == "Closed" :
810+ atteachf = blk
811+ break
812+ code = code .upper ()
813+ if code == act .attendance_code :
814+ present = EighthSignup .objects .filter (scheduled_activity = act , user__in = [request .user .id ])
815+ present .update (was_absent = False )
816+ attc = blk
817+ for s in present :
818+ invalidate_obj (s )
819+ act .attendance_taken = True
820+ act .save ()
821+ invalidate_obj (act )
822+ break
823+ else :
824+ attf = blk
825+ break
826+ if blocks :
827+ sch_acts = []
828+ for b in blocks :
829+ try :
830+ act = request .user .eighthscheduledactivity_set .get (block = b )
831+ if act .activity .name != "z - Hybrid Sticky" :
832+ 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+
834+ except EighthScheduledActivity .DoesNotExist :
835+ sch_acts .append ([b , None ])
836+ response = render (
837+ request ,
838+ "eighth/student_submit_attendance.html" ,
839+ context = {"sch_acts" : sch_acts , "attc" : attc , "attf" : attf , "attimef" : attimef , "atteachf" : atteachf },
840+ )
841+ else :
842+ messages .error (request , "There are no eighth period blocks scheduled today." )
843+ response = redirect ("index" )
844+ return response
0 commit comments