From eb4f45d08c45e464ae9d91a4265207e7c33b588a Mon Sep 17 00:00:00 2001 From: jan Date: Mon, 13 May 2024 10:11:58 +0200 Subject: [PATCH 01/18] let admins change the applicant name in internal signup --- src/spz/templates/signupinternal.html | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/spz/templates/signupinternal.html b/src/spz/templates/signupinternal.html index d25bea0..1b51b84 100644 --- a/src/spz/templates/signupinternal.html +++ b/src/spz/templates/signupinternal.html @@ -12,11 +12,15 @@ {{ csrf_field() }} {{ render_raw_input(form.state, type='hidden') }} {{ render_raw_input(form.course, type='hidden') }} -

Persönliche Angaben

- {{ render_input(form.first_name, placeholder='Mika', icon='user', readonly=True) }} - {{ render_input(form.last_name, placeholder='Müller', icon='users', readonly=True) }} + {% if current_user.is_admin_or_superuser %} + {{ render_input(form.first_name, placeholder='Mika', icon='user') }} + {{ render_input(form.last_name, placeholder='Müller', icon='users') }} + {% else %} + {{ render_input(form.first_name, placeholder='Mika', icon='user', readonly=True) }} + {{ render_input(form.last_name, placeholder='Müller', icon='users', readonly=True) }} + {% endif %}
{{ render_input(form.phone, placeholder='0 1521 1234 678', icon='mobile') }} From 52a7b01e0e17cae2f09c2faeb632d31f5a69077c Mon Sep 17 00:00:00 2001 From: urvdp Date: Mon, 13 May 2024 11:54:09 +0200 Subject: [PATCH 02/18] update spanish export templates for SS24 --- src/spz/templates/export/spanisch.xlsx | Bin 63818 -> 63895 bytes src/spz/templates/export/spanisch_hueber.xlsx | Bin 68477 -> 67629 bytes 2 files changed, 0 insertions(+), 0 deletions(-) diff --git a/src/spz/templates/export/spanisch.xlsx b/src/spz/templates/export/spanisch.xlsx index 5d8db78d53440424e5fa88645921d9b4459cc2e3..a1b2a37535cb0eff08753180096b86e814992b34 100644 GIT binary patch delta 18820 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 CR1eYs delta 18705 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 F#Q@-8)=>Ze diff --git a/src/spz/templates/export/spanisch_hueber.xlsx b/src/spz/templates/export/spanisch_hueber.xlsx index 01026901f984094645599741457c6b3a20f8845c..4d2fedde912631e91a03351f62d560f5f9adbe77 100644 GIT binary patch delta 35229 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 a)8@|*yV-$umwW}Yg*X^R*$(^z83O=@e~4!Q From 10b8b1760a46de7a5efcad779562c8e68721ad03 Mon Sep 17 00:00:00 2001 From: Jan Fenker Date: Mon, 13 May 2024 13:13:34 +0200 Subject: [PATCH 03/18] Views for teacher (#21) * solve merge conflicts manually * create language page for adding teachers * fix merge conflicts in views * resolve rebase conflict in views * begin to implement pages to add and administrate teachers * finish add form for teachers, add multiple course select field to cached * add basic db.model for teacher * add edit_teacher view, finish add_teacher function, implement list to show all teachers of one language, finish db.Model Teacher * implement logic to add/remove courses to teachers, delete Teacher attribute languages (implicit known through link between courses and languages -> be efficient), course is only addable to a teacher, if it is not assigned already * put administration view functions in admin_views (own package), code view for teachers to manage their courses (def teacher in views) * add attendance base view and view to put the grade * add grade edit views and intern representation for the grade * changes to insert grades (at the moment not fully working) * export for participation certificates (#16) * add check boxes to courses.html, implement participation certificate generator * return applicant mail if checkbox in course.html is marked * write logic for participation_cert pdf generation and implement zip-writer * nicer checkbox design * minor final changes * add teacher administration view * Merge new User database model (#18) * update excel templates * export for participation certificates (#16) * add check boxes to courses.html, implement participation certificate generator * return applicant mail if checkbox in course.html is marked * write logic for participation_cert pdf generation and implement zip-writer * nicer checkbox design * minor final changes * minor changes in spanish templates * bugfix on spanisch_hueber * give all users the possibility to generate participation certificates * Fix non-discounted price being shown in outstanding payments * Use roles to store user permissions * Add helper to check if user has superuser role * Rename LANGUAGE_ADMIN role to COURSE_ADMIN * Update can_edit_course check with new role system * Create log entries for courses, not for languages * Replace usages of user.languages * Add additional teacher attributes to user model --------- Co-authored-by: Tobias Dierich * implementation of new database model for teacher administration views * finish integration of database model, adapt edit_teacher with add/remove course * prefill edit grade field and show corresponding field in template * show statistics for teacher administration, code attendance table * adjust design and spacing of attendance table * attempt using Flask WTForms for the input handling of the grade (edit_grade.html). Unfortunately the FieldList with FormField causes problems e g Field Validation seems not to work, flashed messages not displayed,... * implement edit_grade form to adjust ects points for each student and set the grade in percentages, later it is shown as grade with comma * add hide_grade template * finish implementation of the templates for setting the grade, ects and if the grade should be hidden * fix logic error in edit_grade * adapt model to new database role * send pw reset mails to teachers, display teachers in course template, begin to limit views for teachers * show courses that are not assigned to a teacher in teacher overview * fix course assigning to teachers, make error messages work as intended * show only avalable courses in add_teacher form * restrict access for teachers to only necessary pages * integrate edit grade flow into language table of courses as own column * fix grade routing for admins, add page for teachers without any course to make new course assignments possible * fix teacher routing, remove complete row in database when removing course role, fix check availability function to assign new courses to a teacher * minor view enhancements --------- Co-authored-by: Tobias Dierich --- src/spz/__init__.py | 16 +- src/spz/administration/__init__.py | 77 +++++ src/spz/administration/admin_views.py | 327 ++++++++++++++++++ src/spz/forms/__init__.py | 205 ++++++++++- src/spz/forms/cached.py | 41 ++- src/spz/models.py | 57 ++- src/spz/templates/baselayout.html | 173 ++++----- .../internal/administration/add_teacher.html | 32 ++ .../internal/administration/attendances.html | 78 +++++ .../administration/edit_attendances.html | 14 + .../internal/administration/edit_grade.html | 89 +++++ .../administration/edit_grade_view.html | 77 +++++ .../internal/administration/edit_teacher.html | 70 ++++ .../internal/administration/grade.html | 66 ++++ .../administration/teacher_overview_base.html | 41 +++ .../administration/teacher_overview_lang.html | 99 ++++++ .../internal/administration/teacher_void.html | 39 +++ src/spz/templates/internal/course.html | 22 +- src/spz/templates/internal/export.html | 29 +- src/spz/templates/internal/internal.html | 5 +- src/spz/templates/internal/language.html | 4 + src/spz/templates/internal/teacher.html | 53 +++ src/spz/views.py | 65 +++- 23 files changed, 1566 insertions(+), 113 deletions(-) create mode 100644 src/spz/administration/__init__.py create mode 100644 src/spz/administration/admin_views.py create mode 100644 src/spz/templates/internal/administration/add_teacher.html create mode 100644 src/spz/templates/internal/administration/attendances.html create mode 100644 src/spz/templates/internal/administration/edit_attendances.html create mode 100644 src/spz/templates/internal/administration/edit_grade.html create mode 100644 src/spz/templates/internal/administration/edit_grade_view.html create mode 100644 src/spz/templates/internal/administration/edit_teacher.html create mode 100644 src/spz/templates/internal/administration/grade.html create mode 100644 src/spz/templates/internal/administration/teacher_overview_base.html create mode 100644 src/spz/templates/internal/administration/teacher_overview_lang.html create mode 100644 src/spz/templates/internal/administration/teacher_void.html create mode 100644 src/spz/templates/internal/teacher.html diff --git a/src/spz/__init__.py b/src/spz/__init__.py index cecedb3..295cc06 100644 --- a/src/spz/__init__.py +++ b/src/spz/__init__.py @@ -84,6 +84,7 @@ def rlrc_comment(): # add Jinja helpers app.jinja_env.globals['include_raw'] = lambda filename: Markup(app.jinja_loader.get_source(app.jinja_env, filename)[0]) app.jinja_env.globals['rlrc_comment'] = rlrc_comment +app.jinja_env.globals.update(zip=zip) # Assets handling; keep the spz.assets module in sync with the static directory assets_env = Environment(app) @@ -129,9 +130,9 @@ def rlrc_comment(): # Rich Text Editor setup ckeditor = CKEditor(app) - # Register all views here from spz import views, errorhandlers, pdf # NOQA +from spz.administration import admin_views routes = [ ('/', views.index, ['GET', 'POST']), @@ -191,6 +192,19 @@ def rlrc_comment(): ('/internal/login', views.login, ['GET', 'POST']), ('/internal/logout', views.logout, ['GET', 'POST']), ('/internal/auth/reset_password/', views.reset_password, ['GET', 'POST']), + + ('/internal/administration/teacher', admin_views.administration_teacher, ['GET', 'POST']), + ('/internal/administration/teacher/', admin_views.administration_teacher_lang, ['GET', 'POST']), + ('/internal/administration/teacher//add', admin_views.add_teacher, ['GET', 'POST']), + ('/internal/administration/teacher/edit/', admin_views.edit_teacher, ['GET', 'POST']), + ('/internal/administration/teacher/void', admin_views.teacher_void, ['GET']), + ('/internal/teacher', admin_views.teacher, ['GET', 'POST']), + ('/internal/grades/', admin_views.grade, ['GET', 'POST']), + ('/internal/grades//edit', admin_views.edit_grade, ['GET', 'POST']), + ('/internal//grades//edit_view', admin_views.edit_grade_view, ['GET', 'POST']), + ('/internal/teacher//attendance/', admin_views.attendances, ['GET', 'POST']), + ('/internal/teacher//attendance//edit/', admin_views.edit_attendances, ['GET', 'POST']) + ] for rule, view_func, methods in routes: diff --git a/src/spz/administration/__init__.py b/src/spz/administration/__init__.py new file mode 100644 index 0000000..82cb1d5 --- /dev/null +++ b/src/spz/administration/__init__.py @@ -0,0 +1,77 @@ +# -*- coding: utf-8 -*- +"""static functions related to administration tasks + +This module contains methods for: + - teacher management + - course management +""" + +from flask import flash +from spz import models, db +from spz.mail import generate_status_mail + +from flask_babel import gettext as _ + + +def get_course_ids(): + course_ids_tuple = db.session.query(models.Role.course_id).filter( + models.Role.course_id.isnot(None)) \ + .filter(models.Role.role == models.Role.COURSE_TEACHER) \ + .distinct().all() + # transform query tuples into right integer format + """flash('Vergebene Kurse sind:') + for course_id in course_ids_tuple: + course = models.Course.query.get(course_id[0]) + flash(f'{course.full_name}: {course_id[0]}')""" + return [course_id[0] for course_id in course_ids_tuple] + + +class TeacherManagement: + @staticmethod + def remove_course(teacher, course, user_id): + role_to_remove = models.Role.query. \ + join(models.User.roles). \ + filter(models.Role.user_id == user_id). \ + filter(models.Role.course_id == course.id). \ + first() + if role_to_remove: + # remove complete table row from role table + db.session.delete(role_to_remove) + else: + raise ValueError(_('Folgender Kurs "{}" war kein Kurs des/der Lehrbeauftragten.' + ' Wurde der richtige Kurs ausgewählt?'.format(course.full_name))) + + return course + + @staticmethod + def add_course(teacher, course): + own_courses_id = [course.id for course in teacher.teacher_courses] + if course.id in own_courses_id: + raise ValueError( + _('Der/die Lehrbeauftragte hat diesen Kurs schon zugewiesen. Doppelzuweisung nicht möglich!')) + TeacherManagement.check_availability(course) + teacher.roles.append(models.Role(course=course, role=models.Role.COURSE_TEACHER)) + + @staticmethod + def check_availability(course): + teachers = db.session.query(models.User) \ + .join(models.Role, models.User.roles) \ + .filter(models.Role.role == models.Role.COURSE_TEACHER).all() + course_ids = get_course_ids() + if course.id in course_ids: + for teacher in teachers: + if teacher.is_course_teacher(course): + #flash(f'{course.full_name} ({course.id}) is already assigned to {teacher.full_name}') + raise ValueError('{0} ist schon vergeben an {1}.'.format(course.full_name, teacher.full_name)) + + @staticmethod + def unassigned_courses(language_id): + # courses with assigned teachers only + unassigned_courses = db.session.query(models.Course) \ + .outerjoin(models.Role, + (models.Role.course_id == models.Course.id) & (models.Role.role == models.Role.COURSE_TEACHER)) \ + .join(models.Language) \ + .filter(models.Language.id == language_id) \ + .filter(models.Role.id == None) + + return unassigned_courses diff --git a/src/spz/administration/admin_views.py b/src/spz/administration/admin_views.py new file mode 100644 index 0000000..183ff4d --- /dev/null +++ b/src/spz/administration/admin_views.py @@ -0,0 +1,327 @@ +# -*- coding: utf-8 -*- + +"""The application's administration views. + + Manages the mapping between routes and their activities for the administrators. +""" +import socket +from flask import request, redirect, render_template, url_for, flash +from flask_login import current_user, login_required, login_user, logout_user +from flask_mail import Message + +from spz import app +from spz import models, db, log +from spz.administration import TeacherManagement +from spz.decorators import templated +from spz.auth.password_reset import send_password_reset_to_user +import spz.forms as forms + +from flask_babel import gettext as _ + + +@templated('internal/administration/teacher_overview_base.html') +def administration_teacher(): + if current_user.is_teacher: + return redirect(url_for('teacher')) + # Aliasing might be necessary if Role or User is joined through different paths + # An outer join retrieves records that have matching values in one of the tables, and also those records from the + # primary table that have no matches in the joined table. + languages_info = db.session.query( + models.Language.id, + models.Language.name, + db.func.count(models.Course.id).label('course_count'), + db.func.count(db.distinct(models.Role.user_id)).label('teacher_count') + ).outerjoin( + models.Course, models.Language.id == models.Course.language_id # Ensure all languages are included + ).outerjoin( + models.Role, (models.Role.course_id == models.Course.id) & (models.Role.role == models.Role.COURSE_TEACHER) + ).group_by( + models.Language.id, models.Language.name + ).all() + + languages_data = [{ + 'id': l_id, + 'name': name, + 'course_count': course_count if course_count else 0, + 'teacher_count': teacher_count if teacher_count else 0, + 'teacher_rate_per_course': teacher_count / course_count if course_count else 0, + } for l_id, name, course_count, teacher_count in languages_info] + + return dict(language=languages_data) + + +@templated('internal/administration/teacher_overview_lang.html') +def administration_teacher_lang(id): + lang = models.Language.query.get_or_404(id) + + teacher = models.User.query \ + .join(models.Role, models.User.roles) \ + .join(models.Course, models.Role.course_id == models.Course.id) \ + .filter(models.Course.language_id == id) \ + .filter(models.Role.role == 'COURSE_TEACHER') \ + .distinct().all() + + # courses with assigned teachers + unassigned_courses = TeacherManagement.unassigned_courses(id) + + return dict(language=lang, teacher=teacher, unassigned_courses=unassigned_courses) + + +@templated('internal/administration/add_teacher.html') +def add_teacher(id): + lang = models.Language.query.get_or_404(id) + form = forms.AddTeacherForm(id) + + if form.validate_on_submit(): + teacher = form.get_teacher() + + # check, if course is already assigned to a teacher + courses = form.get_courses() + try: + for course in courses: + # if course is not available, error is thrown + TeacherManagement.check_availability(course) + except Exception as e: + flash(_('Der Kurs ist schon vergeben. Es kann nur eine*n Lehrbeauftragte*n je Kurs geben: %(error)s', + error=e), 'negative') + return dict(language=lang, form=form) + + if teacher is None: + roles = [] + teacher_courses = form.get_courses() + for course in teacher_courses: + roles.append(models.Role(course=course, role=models.Role.COURSE_TEACHER)) + teacher = models.User(email=form.get_mail(), + tag=form.get_tag(), + active=True, + roles=roles + ) + teacher.first_name = form.get_first_name() + teacher.last_name = form.get_last_name() + try: + db.session.add(teacher) + db.session.commit() + except Exception as e: + db.session.rollback() + flash(_('Es gab einen Fehler beim Hinzufügen des Lehrbeauftragten: %(error)s', error=e), 'negative') + return dict(form=form) + + # send password reset mail, if writing to database was successfully + try: + send_password_reset_to_user(teacher) + except (AssertionError, socket.error, ConnectionError) as e: + flash(_('Eine Mail zum Passwort Reset konnte nicht verschickt werden: %(error)s', error=e), 'negative') + + return redirect(url_for('administration_teacher_lang', id=lang.id)) + + # update course choices depending on the visited language page + form.update_courses(id) + return dict(language=lang, form=form) + + +@templated('internal/administration/edit_teacher.html') +def edit_teacher(id): + teacher = models.User.query.get_or_404(id) + form = forms.EditTeacherForm(teacher) + + if form.validate_on_submit(): + + try: + + changes = False + + if teacher.first_name != form.first_name.data: + teacher.first_name = form.first_name.data + changes = True + + if teacher.last_name != form.last_name.data: + teacher.last_name = form.last_name.data + changes = True + + if teacher.email != form.mail.data: + teacher.email = form.mail.data + changes = True + + if teacher.tag != form.tag.data: + teacher.tag = form.tag.data + changes = True + + if changes: + db.session.commit() + flash(_('Der/die Lehrbeauftragte wurde aktualisiert (pers. Daten)'), 'success') + else: + flash(_('Es gab keine Änderung der persönlichen Daten.'), 'info') + + add_to_course = form.get_add_to_course() + remove_from_course = form.get_remove_from_course() + + reset_password = form.get_send_mail() + + if remove_from_course: + try: + success = TeacherManagement.remove_course(teacher, remove_from_course, teacher.id) + flash( + _('Der/die Lehrbeauftragte wurde vom Kurs "(%(name)s)" entfernt', + name=remove_from_course.full_name), + 'success') + db.session.commit() + except Exception as e: + db.session.rollback() + flash(_('Der/die Lehrbeauftragte konnte nicht aus dem Kurs entfernt werden: %(error)s', error=e), + 'negative') + + if add_to_course: + try: + TeacherManagement.add_course(teacher, add_to_course) + flash( + _('Der/die Lehrbeauftragte wurde zum Kurs {} hinzugefügt.'.format(add_to_course.full_name)), + 'success' + ) + db.session.commit() + except Exception as e: + db.session.rollback() + flash( + _('Der/die Lehrbeauftragte konnte nicht für den Kurs eingetragen werden: %(error)s', + error=e), + 'negative') + + if reset_password: + try: + send_password_reset_to_user(teacher) + flash( + _('Eine Mail zum Passwort Zurücksetzen wurde an {} geschickt.'.format(teacher.full_name)), + 'success') + except (AssertionError, socket.error, ConnectionError) as e: + flash(_('Eine Mail zum Passwort Reset konnte nicht verschickt werden: %(error)s', error=e), + 'negative') + + return redirect(url_for('edit_teacher', id=teacher.id)) + + except Exception as e: + db.session.rollback() + flash(_('Der Bewerber konnte nicht aktualisiert werden: %(error)s', error=e), 'negative') + return dict(form=form) + + form.populate(teacher) + return dict(teacher=teacher, form=form) + + +@templated('internal/teacher.html') +def teacher(): + + return dict(user=current_user) + + +@templated('internal/administration/grade.html') +def grade(course_id): + course = models.Course.query.get_or_404(course_id) + + exam_date = app.config['EXAM_DATE'] + + return dict(course=course, exam_date=exam_date) + + +@templated('internal/administration/edit_grade.html') +def edit_grade(course_id): + course = models.Course.query.get_or_404(course_id) + if not current_user.is_admin_or_superuser and not current_user.is_course_teacher(course): + return redirect(url_for('internal')) + # !!! course.course_list returns only active applicants (not on waiting list) + # populate grade fields with applicant parameters + grade_list = forms.create_grade_form(course.course_list) + form = grade_list(request.form) + + exam_date = app.config['EXAM_DATE'] + + if request.method == 'POST' and form.validate(): + try: + changes = False + for applicant in course.course_list: + grade_field = getattr(form, f'grade_{applicant.id}', None) + if grade_field and grade_field.data != applicant.grade: + applicant.grade = grade_field.data + changes = True + + ects_field_name = f'ects_{applicant.id}' + if ects_field_name in request.form: + submitted_ects = int(request.form[ects_field_name]) + if submitted_ects != applicant.ects_points: + applicant.ects_points = submitted_ects + changes = True + + if changes: + db.session.commit() + flash('Noten wurden erfolgreich gespeichert!', 'success') + else: + flash('Es gab keine Änderungen zu speichern.', 'info') + except Exception as e: + db.session.rollback() + flash(_('Es gab einen Fehler beim Speichern der Noten: %(error)s', error=e), 'negative') + + return redirect(url_for('edit_grade_view', course_id=course_id)) + + return dict(course=course, form=form, exam_date=exam_date) + + +@templated('internal/administration/edit_grade_view.html') +def edit_grade_view(course_id): + course = models.Course.query.get_or_404(course_id) + exam_date = app.config['EXAM_DATE'] + + if request.method == 'POST': + try: + changes = False + for applicant in course.course_list: + view_field_name = f'view_{applicant.id}' + submitted_view = request.form.get(view_field_name) + if submitted_view is not None: + hide_view = (int(submitted_view) == 0) + if hide_view != applicant.hide_grade: + applicant.hide_grade = hide_view + changes = True + if changes: + db.session.commit() + flash('Als bestanden eingetragene Noten wurden erfolgreich gespeichert!', 'success') + else: + flash('Es gab keine Änderungen zu speichern.', 'info') + except Exception as e: + db.session.rollback() + flash(_('Es ist ein Fehler beim Abspeichern der Bestanden-Attribute aufgetreten: %(error)s', error=e), + 'negative') + + + return redirect(url_for('grade', id=id, course_id=course_id)) + + return dict(course=course, exam_date=exam_date) + + +@templated('internal/administration/attendances.html') +def attendances(id, course_id): + teacher_db = models.User.query.get_or_404(id) + course = models.Course.query.get_or_404(course_id) + + weeks = app.config['WEEKS'] + # weeks = [i for i in range(week_num)] + return dict(teacher=teacher_db, course=course, weeks=int(weeks)) + + +@templated('internal/administration/edit_attendances.html') +def edit_attendances(id, course_id, class_id): + teacher_db = models.User.query.get_or_404(id) + course = models.Course.query.get_or_404(course_id) + + return dict(teacher=teacher_db, course=course, class_id=class_id) + + +@templated('internal/administration/teacher_void.html') +def teacher_void(): + if current_user.is_teacher: + return redirect(url_for('teacher')) + + all_users = models.User.query.all() + + # Filter users who do not have COURSE_TEACHER or SUPERUSER roles + users_without_roles = [user for user in all_users if + not any(role.role in ['COURSE_TEACHER', 'SUPERUSER'] for role in user.roles)] + + return dict(users=users_without_roles) diff --git a/src/spz/forms/__init__.py b/src/spz/forms/__init__.py index 50de669..cdb2bab 100644 --- a/src/spz/forms/__init__.py +++ b/src/spz/forms/__init__.py @@ -9,11 +9,11 @@ from datetime import datetime from sqlalchemy import func, and_, or_, not_ -from flask_wtf import FlaskForm +from flask_wtf import FlaskForm, Form from flask_login import current_user from markupsafe import Markup from wtforms import widgets, StringField, SelectField, SelectMultipleField, IntegerField, Label -from wtforms import TextAreaField, BooleanField, DecimalField, MultipleFileField +from wtforms import TextAreaField, BooleanField, DecimalField, MultipleFileField, FieldList, FormField, HiddenField from flask_ckeditor import CKEditorField from spz import app, models, token @@ -36,7 +36,15 @@ 'UniqueForm', 'TagForm', 'SignoffForm', - 'ExportCourseForm' + 'ExportCourseForm', + 'CourseForm', + 'AddTeacherForm', + 'EditTeacherForm', + 'CourseForm', + 'VacanciesForm', + 'DeleteCourseForm', + 'TriStateField', + 'TriStateLabel' ] @@ -855,8 +863,199 @@ def __init__(self, languages=[], *args, **kwargs): (f.id, f.descriptive_name) for f in models.ExportFormat.list_formatters(languages=languages) ] + def update_course_list(self, user): + # fetch courses depending on user + if user.is_admin_or_superuser: + new_choices = cached.all_courses_to_choicelist() + if self.courses.choices != new_choices: + self.courses.choices = new_choices + else: + courses = getattr(user, 'teacher_courses', []) + new_choices = [(course.id, course.full_name) for course in courses] + if self.courses.choices != new_choices: + self.courses.choices = new_choices + + +class AddTeacherForm(FlaskForm): + """Represents the form to add teachers to database. + + """ + first_name = StringField( + 'Vorname', + [validators.Length(1, 60, 'Länge muss zwischen 1 und 60 Zeichen sein')] + ) + last_name = StringField( + 'Nachname', + [validators.Length(1, 60, 'Länge muss zwischen 1 and 60 Zeichen sein')] + ) + + mail = StringField( + 'E-Mail', + [ + validators.Length(max=120, message='Länge muss zwischen 1 und 120 Zeichen sein'), + validators.EmailPlusValidator() + ] + ) + + confirm_mail = StringField( + 'E-Mail bestätigen', + [validators.EqualTo('mail', message='E-Mailadressen müssen übereinstimmen.')] + ) + + tag = StringField( + 'Mitarbeiterkürzel', + [ + validators.Length(max=10, message='Länge darf maximal 10 Zeichen sein') + ] + ) + + courses = SelectMultipleField( + 'Kurse', + [validators.DataRequired('Mindestens ein Kurs muss ausgewählt werden')], + coerce=int + ) + + def __init__(self, language_id, *args, **kwargs): + super(AddTeacherForm, self).__init__(*args, **kwargs) + self.courses.choices = cached.language_to_choicelist(language_id, True) + + def update_courses(self, language_id): + self.courses.choices = cached.language_to_choicelist(language_id, True) + + def get_first_name(self): + return self.first_name.data + + def get_last_name(self): + return self.last_name.data + + def get_mail(self): + return self.mail.data + + def get_tag(self): + return self.tag.data + + def get_courses(self): + return [models.Course.query.get(id) for id in self.courses.data] + + def get_teacher(self): + existing = models.User.query.filter( + func.lower(models.User.email) == func.lower(self.get_mail()) + ).first() + if existing: + return existing + else: + return None + + +class EditTeacherForm(FlaskForm): + """Represents the form for editing a teacher and his/her courses and languages. + + """ + first_name = StringField( + 'Vorname', + [validators.Length(1, 60, 'Länge muss zwischen 1 und 60 Zeichen sein')] + ) + last_name = StringField( + 'Nachname', + [validators.Length(1, 60, 'Länge muss zwischen 1 and 60 sein')] + ) + mail = StringField( + 'E-Mail', + [ + validators.Length(max=120, message='Länge muss zwischen 1 und 120 Zeichen sein'), + validators.EmailPlusValidator() + ] + ) + tag = StringField( + 'Mitarbeiterkürzel', + [ + validators.Optional(), + validators.Length(max=30, message='Länge darf maximal 30 Zeichen sein') + ] + ) + + add_to_course = SelectField( + 'Kurs hinzufügen', + [validators.Optional()], + coerce=int, + choices=[] + ) + remove_from_course = SelectField( + 'Kurs löschen', + [validators.Optional()], + coerce=int, + choices=[] + ) + + send_mail = BooleanField( + 'Passwort zurücksetzen und Mail verschicken' + ) + + def __init__(self, teacher, *args, **kwargs): + super(EditTeacherForm, self).__init__(*args, **kwargs) + self.teacher = teacher + + self.add_to_course.choices = cached.all_courses_to_choicelist() + self.remove_from_course.choices = cached.all_courses_to_choicelist() + + def populate(self, teacher): + self.teacher = teacher + self.first_name.data = self.teacher.first_name + self.last_name.data = self.teacher.last_name + self.mail.data = self.teacher.email + self.tag.data = self.teacher.tag + + def get_teacher(self): + return self.teacher + + def get_courses(self): + sorted_courses = sorted(self.teacher.teacher_courses, key=lambda x: x.full_name) + return sorted_courses + + def get_languages(self): + language_ids = [] + languages = [] + if self.teacher is not None: + for course in self.teacher.teacher_courses: + if course.language_id not in language_ids: + language_ids.append(course.language_id) + db_lang = models.Language.query.get_or_404(course.language_id) + languages.append(db_lang) + + return languages if languages else None + + def get_add_to_course(self): + return models.Course.query.get(self.add_to_course.data) if self.add_to_course.data else None + + def get_remove_from_course(self): + return models.Course.query.get(self.remove_from_course.data) if self.remove_from_course.data else None + + def get_send_mail(self): + return self.send_mail.data + class CourseForm(FlaskForm): """ A form to select different participants in that specific course """ identifier = StringField() + + +def create_grade_form(applicants): + """ + Dynamically creates a GradeForm class with fields for each applicant. + """ + + class GradeForm(FlaskForm): + pass + + for applicant in applicants: + field_name = f'grade_{applicant.id}' + setattr(GradeForm, field_name, + IntegerField("Note", validators=[validators.NumberRange(min=0, max=100)], + default=applicant.grade)) + + return GradeForm + + +class AttendanceForm(FlaskForm): + attendance = HiddenField("attendance_id") diff --git a/src/spz/forms/cached.py b/src/spz/forms/cached.py index cc8c628..bfa7dce 100644 --- a/src/spz/forms/cached.py +++ b/src/spz/forms/cached.py @@ -40,6 +40,7 @@ def origins_to_choicelist(): in models.Origin.query.order_by(models.Origin.id.asc()) ] + @cache.cached(key_prefix='internal_origins') def internal_origins_to_choicelist(): return [ @@ -48,6 +49,7 @@ def internal_origins_to_choicelist(): in models.Origin.query.filter(models.Origin.is_internal == True).order_by(models.Origin.id.asc()) ] + @cache.cached(key_prefix='external_origins') def external_origins_to_choicelist(): return [ @@ -56,15 +58,39 @@ def external_origins_to_choicelist(): in models.Origin.query.filter(models.Origin.is_internal == False).order_by(models.Origin.id.asc()) ] + @cache.cached(key_prefix='languages') def languages_to_choicelist(): return [ - (x.id, '{0}'.format(x.name)) + (x.id, '{0}'.format(x.full_name)) for x in models.Language.query.order_by(models.Language.name.asc()) ] +@cache.cached(key_prefix='language') +def language_to_choicelist(lang_id, has_teacher=False): # shows only courses from selected language + if not has_teacher: + return [ + (x.id, '{0}'.format(x.full_name)) + for x + in models.Course.query.filter(models.Course.language_id == lang_id).order_by(models.Course.id.asc()) + ] + else: + unassigned_courses = [ + (course.id, '{0}'.format(course.full_name)) + for course + in db.session.query(models.Course) + .outerjoin(models.Role, + (models.Role.course_id == models.Course.id) & (models.Role.role == models.Role.COURSE_TEACHER)) + .filter(models.Course.language_id == lang_id) + .filter(models.Role.id == None) + .order_by(models.Course.id.asc()) + ] + + return unassigned_courses + + @cache.cached(key_prefix='gers') def gers_to_choicelist(): return [ @@ -116,3 +142,16 @@ def all_courses_to_choicelist(): (course.id, '{0}'.format(course.full_name)) for course in courses ] + + +""" +@cache.cached(key_prefix='all_languages') +def all_languages_to_choicelist(): + languages = models.Language.query \ + .order_by(models.Language.name) + + return [ + (language.id, '{0}'.format(language.name)) + for language in languages + ] +""" diff --git a/src/spz/models.py b/src/spz/models.py index 0141521..9df018a 100644 --- a/src/spz/models.py +++ b/src/spz/models.py @@ -209,6 +209,12 @@ class Applicant(db.Model): discounted = db.Column(db.Boolean) is_student = db.Column(db.Boolean) + # internal representation of the grade is in % + grade = db.Column(db.Integer, nullable=True) # TODO store grade encrypted + ects_points = db.Column(db.Integer, nullable=True, default=0) + # if a student only wants 'bestanden' instead of the grade value, is set to true + hide_grade = db.Column(db.Boolean, nullable=False, default=False) + # See {add,remove}_course_attendance member functions below attendances = db.relationship("Attendance", backref="applicant", cascade='all, delete-orphan', lazy="joined") @@ -243,6 +249,29 @@ def __lt__(self, other): def full_name(self): return '{} {}'.format(self.first_name, self.last_name) + @property + def full_grade(self): + if self.grade is None: + return "-" + conversion_table = [ + (98, 1), + (95, 1.3), + (90, 1.7), + (85, 2), + (79, 2.3), + (73, 2.7), + (68, 3), + (62, 3.3), + (56, 3.7), + (50, 4) + ] + + for percentage, grade in conversion_table: + if self.grade >= percentage: + return grade + + return "nicht bestanden" + def add_course_attendance(self, *args, **kwargs): attendance = Attendance(*args, **kwargs) self.attendances.append(attendance) @@ -254,7 +283,6 @@ def remove_course_attendance(self, course): self.attendances.remove(attendance) return len(remove) > 0 - def best_rating(self): """Results best rating, prioritize sticky entries.""" results_priority = [ @@ -276,6 +304,7 @@ def best_rating(self): return 0 """ Discount (factor) for the next course beeing entered """ + def current_discount(self): attends = len([attendance for attendance in self.attendances if not attendance.waiting]) if self.is_student and attends == 0: @@ -390,8 +419,9 @@ class Course(db.Model): )) def __init__( - self, language, level, alternative, limit, price, level_english=None, ger=None, rating_highest=100, rating_lowest=0, collision=[], - ects_points=2): + self, language, level, alternative, limit, price, level_english=None, ger=None, rating_highest=100, + rating_lowest=0, collision=[], + ects_points=2): self.language = language self.level = level self.alternative = alternative @@ -422,6 +452,7 @@ def has_rating_restrictions(self): :param is_unpaid: Whether the course fee is still (partially) unpaid :param is_free: Whether the course is fully discounted """ + def filter_attendances(self, waiting=None, is_unpaid=None, is_free=None): result = [] for att in self.attendances: @@ -496,6 +527,7 @@ def name_english(self): return '{0} {1}'.format(self.language.name_english, self.level_english) """ active attendants without debt """ + @property def course_list(self): list = [attendance.applicant for attendance in self.filter_attendances(waiting=False)] @@ -560,6 +592,7 @@ def __init__(self, name, reply_to, signup_begin, signup_rnd_window_end, signup_m self.signup_end = signup_end self.signup_auto_end = signup_auto_end self.name_english = name_english + def __repr__(self): return '' % self.name @@ -859,20 +892,21 @@ class User(db.Model): __tablename__ = 'user' id = db.Column(db.Integer, primary_key=True) - first_name = db.Column(db.String(120), nullable=True) - last_name = db.Column(db.String(120), nullable=True) + first_name = db.Column(db.String(120), nullable=True, default=None) + last_name = db.Column(db.String(120), nullable=True, default=None) tag = db.Column(db.String(30), unique=False, nullable=True) email = db.Column(db.String(120), unique=True) active = db.Column(db.Boolean, default=True) pwsalted = db.Column(db.LargeBinary(32), nullable=True) - roles = db.relationship('Role') + roles = db.relationship('Role', backref='user') - def __init__(self, email, active, roles): + def __init__(self, email, active, roles, tag=None): """Create new user without password.""" self.email = email self.active = active self.pwsalted = None self.roles = roles + self.tag = tag def reset_password(self): """Reset password to random one and return it.""" @@ -910,7 +944,8 @@ def is_superuser(self): @property def admin_courses(self): - return (role.course for role in [r for r in self.roles if r.role == Role.COURSE_ADMIN]) + admin_courses = (role.course for role in [r for r in self.roles if r.role == Role.COURSE_ADMIN]) + return sorted(admin_courses, key=lambda x: x.full_name) @property def teacher_courses(self): @@ -983,6 +1018,10 @@ def get_by_login(email, pw): User.pwsalted == salted )).first() + @property + def full_name(self): + return '{} {}'.format(self.first_name, self.last_name) + @total_ordering class LogEntry(db.Model): @@ -1073,6 +1112,7 @@ def list_formatters(languages=[]): ExportFormat.language_id.in_(language_ids) )).all() + class OAuthToken(db.Model): """Token used to store data while oidc flow with kit server @@ -1094,4 +1134,3 @@ def __init__(self, state, code_verifier): self.code_verifier = code_verifier self.request_has_been_made = False self.is_student = False - diff --git a/src/spz/templates/baselayout.html b/src/spz/templates/baselayout.html index a2a8676..2135437 100644 --- a/src/spz/templates/baselayout.html +++ b/src/spz/templates/baselayout.html @@ -1,83 +1,94 @@ - - - - KIT Sprachenzentrum - + + + + KIT Sprachenzentrum + - {% assets "all_css" %} - - {% endassets %} + {% assets "all_css" %} + + {% endassets %} - + - {% block head %} - {% endblock head %} - - - -
-