from flask import flash from flask_admin import expose from flask_security import admin_change_password, current_user from wtforms import Form from wtforms.fields import BooleanField, IntegerField, StringField from . import assistantSpace, db from .advlabdb_independent_funs import ( deep_getattr, flashRandomPassword, missing_formatter, str_formatter, str_without_semester_formatter, ) from .customClasses import SecureAssistantBaseView, SecureAssistantModelView from .exceptions import DataBaseException, ModelViewException from .model_dependent_funs import ( generate_new_password_field, initActiveSemesterMenuLinks, mark_field, user_info_fields, ) from .model_independent_funs import randomPassword from .models import ( MAX_MARK, MIN_MARK, Appointment, Assistant, ExperimentMark, GroupExperiment, SemesterExperiment, User, ) class AssistantAppointmentView(SecureAssistantModelView): can_edit = True column_list = [ "date", "special", "group_experiment.semester_experiment.experiment", "group_experiment.group.number", "group_experiment.group.part_students", ] column_labels = { "group_experiment.semester_experiment.experiment": "Experiment", "group_experiment.group.number": "Group number", "group_experiment.group.part_students": "Students", } column_editable_list = [ "date", ] form_columns = column_editable_list column_descriptions = { "special": "A special appointment should take place in the semester break", } def part_students_formatter(view, context, model, name): part_students = deep_getattr(model, name) if part_students is not None: return ", ".join([str(part_student.student) for part_student in part_students]) return attr column_formatters = { "group_experiment.semester_experiment.experiment": str_formatter, "group_experiment.group.part_students": part_students_formatter, } def query_modifier(self, query): return ( query.join(GroupExperiment) .join(SemesterExperiment) .where( SemesterExperiment.semester == current_user.active_semester, Appointment.assistant == current_user.assistant, ) ) class AssistantExperimentMarkView(SecureAssistantModelView): class EditForm(Form): oral_mark = mark_field("Oral") protocol_mark = mark_field("Protocol") can_edit = True column_display_actions = True column_list = [ "oral_mark", "protocol_mark", "final_experiment_mark", "group_experiment.semester_experiment.experiment.number", "part_student.student", "part_student.group.number", "part_student.student.uni_email", "part_student.student.contact_email", "part_student.part", "assistant", "admin", ] column_labels = { "group_experiment.semester_experiment.experiment.number": "Experiment number", "part_student.student": "Student", "part_student.group.number": "Group number", "part_student.student.uni_email": "Uni Email", "part_student.student.contact_email": "Contact Email", "part_student.part": "Part", } column_descriptions = { "oral_mark": f"Between {MIN_MARK} and {MAX_MARK}", "protocol_mark": f"Between {MIN_MARK} and {MAX_MARK}", "final_experiment_mark": "Calculated automatically with oral and protocol marks and weightings", "part_student.student.contact_email": "The preferred contact email address if entered by the student", "assistant": "The last assistant who edited the mark", "admin": "The last admin who edited the mark", } column_searchable_list = [ "part_student.student.first_name", "part_student.student.last_name", "part_student.student.uni_email", "part_student.student.contact_email", ] column_formatters = { "oral_mark": missing_formatter, "protocol_mark": missing_formatter, "part_student.part": str_without_semester_formatter, } column_default_sort = [("oral_mark", False), ("protocol_mark", False)] def query_modifier(self, query): return ( query.join(GroupExperiment) .join(SemesterExperiment) .where(SemesterExperiment.semester == current_user.active_semester) .join(SemesterExperiment.assistants) .where(Assistant.user == current_user) ) def update_model(self, form, model): if (form.oral_mark is not None and form.oral_mark.data != model.oral_mark) or ( form.protocol_mark is not None and form.protocol_mark.data != model.protocol_mark ): model.assistant = current_user.assistant updateSuccessful = super().update_model(form, model) model.part_student.checkThenSetFinalPartMark() return updateSuccessful else: # Nothing changed return True class AssistantUserView(SecureAssistantModelView): class EditForm(Form): phone_number, mobile_phone_number, building, room = user_info_fields() generate_new_password = generate_new_password_field() can_edit = True can_view_details = True column_display_actions = True column_sortable_list = [] column_list = [ "email", "phone_number", "mobile_phone_number", "building", "room", "assistant.semester_experiments", ] column_labels = { "assistant.semester_experiments": "Semester Experiments", } def query_modifier(self, query): return query.where(User.id == current_user.id) def on_model_change(self, form, model, is_created): if form.generate_new_password.data: password = randomPassword() flashRandomPassword(password) admin_change_password(model, password, notify=False) # Password is automatically hashed with this function class AssistantDocsView(SecureAssistantBaseView): @expose("/") def index(self): return self.render("docs/docs.html", role="assistant") assistantSpace.add_view( AssistantAppointmentView(Appointment, db.session, endpoint="assistant_appointment", url="appointment") ) assistantSpace.add_view( AssistantExperimentMarkView(ExperimentMark, db.session, endpoint="assistant_experimentmark", url="experiment_mark") ) assistantSpace.add_view(AssistantUserView(User, db.session, endpoint="assistant_user", url="user")) assistantSpace.add_view(AssistantDocsView(name="Docs", endpoint="assistant_docs", url="docs")) initActiveSemesterMenuLinks(assistantSpace)