From a914171cb3adfb39d91cb2fec5f60b1edc12045c Mon Sep 17 00:00:00 2001 From: Tanner Collin Date: Sun, 30 Jan 2022 00:04:44 +0000 Subject: [PATCH] Add student count to course's classes, prevent empty add student --- apiserver/apiserver/api/views.py | 6 +- apiserver/export_class_report.py | 22 ++++++ apiserver/output.csv | 104 +++++++++++++++++++++++++++++ webclient/src/Courses.js | 17 ++++- webclient/src/InstructorClasses.js | 6 +- 5 files changed, 149 insertions(+), 6 deletions(-) create mode 100644 apiserver/export_class_report.py create mode 100644 apiserver/output.csv diff --git a/apiserver/apiserver/api/views.py b/apiserver/apiserver/api/views.py index ff98f31..44680c8 100644 --- a/apiserver/apiserver/api/views.py +++ b/apiserver/apiserver/api/views.py @@ -339,7 +339,7 @@ class TrainingViewSet(Base, Retrieve, Create, Update): if data.get('member_id', None): if not (is_admin_director(user) or session.instructor == user): - raise exceptions.ValidationError('Not allowed to register others') + raise exceptions.ValidationError(dict(non_field_errors='Not allowed to register others')) member = get_object_or_404(models.Member, id=data['member_id']) user = member.user @@ -354,9 +354,9 @@ class TrainingViewSet(Base, Retrieve, Create, Update): else: training = models.Training.objects.filter(user=user, session=session) if training.exists(): - raise exceptions.ValidationError('Already registered') + raise exceptions.ValidationError(dict(non_field_errors='Already registered')) if user == session.instructor: - raise exceptions.ValidationError('You are teaching this session') + raise exceptions.ValidationError(dict(non_field_errors='You are teaching this session')) if status == 'Waiting for payment' and session.cost == 0: status = 'Confirmed' serializer.save(user=user, attendance_status=status) diff --git a/apiserver/export_class_report.py b/apiserver/export_class_report.py new file mode 100644 index 0000000..834c7a6 --- /dev/null +++ b/apiserver/export_class_report.py @@ -0,0 +1,22 @@ +import django, sys, os +os.environ['DJANGO_SETTINGS_MODULE'] = 'apiserver.settings' +django.setup() + +import csv +from apiserver.api import models + +sessions = models.Session.objects.filter(datetime__gte='2021-01-01') + +with open('output.csv', 'w', newline='') as csvfile: + fields = ['date', 'name', 'num_students'] + writer = csv.DictWriter(csvfile, fieldnames=fields) + + writer.writeheader() + + for s in sessions: + writer.writerow(dict( + date=s.datetime.date(), + name=s.course.name, + num_students=s.students.filter(attendance_status='Attended').count(), + )) + diff --git a/apiserver/output.csv b/apiserver/output.csv new file mode 100644 index 0000000..8ea4349 --- /dev/null +++ b/apiserver/output.csv @@ -0,0 +1,104 @@ +date,name,num_students +2021-07-25,New Members: Orientation and Basic Safety,5 +2021-07-17,Monthly Cleanup and Group Lunch,0 +2021-08-07,Woodworking Tools 1: Intro to Saws,5 +2021-08-08,Woodworking Tools 1: Intro to Saws,1 +2021-08-07,"Woodworking Tools 2: Jointer, Thickness Planer, Drum Sander",6 +2021-08-08,"Woodworking Tools 2: Jointer, Thickness Planer, Drum Sander",1 +2021-08-07,Introduction to the Wood Lathe,4 +2021-08-08,Introduction to the Wood Lathe,0 +2021-08-07,New Members: Orientation and Basic Safety,3 +2021-08-22,New Members: Orientation and Basic Safety,6 +2021-08-21,Woodworking Tools 1: Intro to Saws,3 +2021-08-21,Monthly Cleanup and Group Lunch,0 +2021-09-11,Annual General Meeting,0 +2021-09-11,Monthly Members Meeting,0 +2021-09-25,Metal: Metal Cutting & Manual Lathe,5 +2021-08-21,Introduction to the Wood Lathe,5 +2021-09-02,New Members: Orientation and Basic Safety,3 +2021-09-12,Basic CNC Wood Router,6 +2021-09-04,"Woodworking Tools 2: Jointer, Thickness Planer, Drum Sander",2 +2021-09-12,Woodworking Tools 1: Intro to Saws,4 +2021-09-12,Introduction to the Wood Lathe,2 +2021-09-11,New Members: Orientation and Basic Safety,1 +2021-10-21,Monthly Members Meeting,0 +2021-09-18,Monthly Cleanup and Group Lunch,0 +2021-09-23,New Members: Orientation and Basic Safety,5 +2021-10-03,New Members: Orientation and Basic Safety,1 +2021-09-18,Basic CNC Wood Router,6 +2021-10-02,Woodworking Tools 1: Intro to Saws,3 +2021-10-09,Basic CNC Wood Router,5 +2021-10-23,Laser: Cutting and Engraving,5 +2021-11-06,Laser: Cutting and Engraving,3 +2021-10-23,Laser: Cutting and Engraving,6 +2021-10-16,Laser II: Trotec Course (For Rabbit-Certified members),0 +2021-10-16,Laser II: Trotec Course (For Rabbit-Certified members),3 +2021-10-23,Laser II: Trotec Course (For Rabbit-Certified members),1 +2021-10-23,Laser II: Trotec Course (For Rabbit-Certified members),0 +2021-10-30,Laser II: Trotec Course (For Rabbit-Certified members),8 +2021-10-30,Laser II: Trotec Course (For Rabbit-Certified members),0 +2021-10-22,New Members: Orientation and Basic Safety,1 +2021-10-17,Woodworking Tools 1: Intro to Saws,5 +2021-10-17,"Woodworking Tools 2: Jointer, Thickness Planer, Drum Sander",8 +2021-10-17,Introduction to the Wood Lathe,3 +2021-10-16,Monthly Cleanup and Group Lunch,0 +2021-11-21,Woodworking Tools 1: Intro to Saws,4 +2021-11-06,CAD/CAM for The Complete Beginner: Fusion 360,4 +2021-11-07,New Members: Orientation and Basic Safety,6 +2021-11-07,Laser II: Trotec Course (For Rabbit-Certified members),0 +2021-11-05,Electronics Night,0 +2021-11-13,Basic CNC Wood Router,4 +2021-11-28,Basic CNC Wood Router,4 +2021-12-03,Electronics Night,0 +2021-11-25,New Members: Orientation and Basic Safety,7 +2021-12-11,New Members: Orientation and Basic Safety,5 +2021-11-19,Monthly Members Meeting,0 +2021-11-20,Monthly Cleanup and Group Lunch,0 +2022-01-15,CAD/CAM for The Complete Beginner: Fusion 360,0 +2021-12-18,Monthly Cleanup and Group Lunch,0 +2022-01-16,Woodworking Tools 1: Intro to Saws,6 +2022-03-13,Woodworking Tools 1: Intro to Saws,0 +2022-05-15,Woodworking Tools 1: Intro to Saws,0 +2021-11-27,CRT Retro Computing Club,0 +2021-12-23,New Members: Orientation and Basic Safety,1 +2021-12-11,Roots2STEM tour,5 +2021-12-18,Basic CNC Wood Router,4 +2021-12-11,Woodworking Tools 1: Intro to Saws,3 +2021-12-11,"Woodworking Tools 2: Jointer, Thickness Planer, Drum Sander",5 +2021-12-12,Introduction to the Wood Lathe,1 +2021-12-19,CRT Retro Computing Club,0 +2022-01-23,3D Printing: Introduction to 3D Printing,7 +2022-01-09,New Members: Orientation and Basic Safety,5 +2022-01-22,New Members: Orientation and Basic Safety,4 +2022-01-29,Basic CNC Wood Router,0 +2022-01-07,Electronics Night,0 +2022-02-04,Electronics Night,0 +2022-02-13,Woodworking Tools 1: Intro to Saws,0 +2022-02-03,New Members: Orientation and Basic Safety,0 +2022-02-27,Basic CNC Wood Router,0 +2022-03-05,Tormach: CAM and Tormach Intro,0 +2022-02-05,CAD: Introduction to 3D CAD (Fusion),0 +2022-01-30,Laser: Cutting and Engraving,0 +2022-01-22,CAD/CAM for The Complete Beginner Part II (Classroom Booking Edition),0 +2022-02-12,Metal: Metal Cutting & Manual Lathe,0 +2022-01-21,Monthly Members Meeting,0 +2022-02-12,New Members: Orientation and Basic Safety,0 +2022-02-24,New Members: Orientation and Basic Safety,0 +2022-03-26,Basic CNC Wood Router,0 +2022-01-29,"Woodworking Tools 2: Jointer, Thickness Planer, Drum Sander",0 +2022-02-06,Laser: Cutting and Engraving,0 +2022-01-28,New Members: Orientation and Basic Safety,2 +2022-01-23,New Members: Orientation and Basic Safety,2 +2022-01-25,New Members: Orientation and Basic Safety,1 +2022-01-29,New Members: Orientation and Basic Safety,0 +2022-02-17,Monthly Members Meeting,0 +2022-02-19,Monthly Cleanup and Group Lunch,0 +2022-01-30,Intro to Blade Sharpening,0 +2022-01-29,Welding 101 - MIG Welding and Safety,0 +2021-12-30,Woodworking Tools 1: Intro to Saws,0 +2022-01-27,Woodworking Tools 1: Intro to Saws,2 +2022-02-03,Woodworking Tools 1: Intro to Saws,0 +2022-02-05,"Woodworking Tools 2: Jointer, Thickness Planer, Drum Sander",0 +2022-02-12,Roots 2 STEM classes,0 +2022-02-12,Laser II: Trotec Course (For Rabbit-Certified members),0 +2022-02-19,Laser II: Trotec Course (For Rabbit-Certified members),0 diff --git a/webclient/src/Courses.js b/webclient/src/Courses.js index 17ee0f8..fd226c2 100644 --- a/webclient/src/Courses.js +++ b/webclient/src/Courses.js @@ -137,6 +137,8 @@ export function CourseDetail(props) { }); }, []); + const now = new Date().toISOString(); + return ( {!error ? @@ -170,21 +172,32 @@ export function CourseDetail(props) { Time Instructor Cost + Students {course.sessions.length ? course.sessions.sort((a, b) => a.datetime < b.datetime ? 1 : -1).slice(0,10).map(x => - + - {moment.utc(x.datetime).tz('America/Edmonton').format('ll')} +  {moment.utc(x.datetime).tz('America/Edmonton').format('ll')} {x.is_cancelled ? 'Cancelled' : moment.utc(x.datetime).tz('America/Edmonton').format('LT')} {getInstructor(x)} {x.cost === '0.00' ? 'Free' : '$'+x.cost} + + {!!x.max_students ? + x.max_students <= x.student_count ? + 'Full' + : + x.student_count + ' / ' + x.max_students + : + x.student_count + } + ) : diff --git a/webclient/src/InstructorClasses.js b/webclient/src/InstructorClasses.js index b6f46b3..b7cee2c 100644 --- a/webclient/src/InstructorClasses.js +++ b/webclient/src/InstructorClasses.js @@ -209,7 +209,11 @@ export function InstructorClassAttendance(props) { /> - + Submit