from flask import flash from flask_admin import expose from flask_admin.contrib.sqla.fields import QuerySelectField, QuerySelectMultipleField from flask_security import admin_change_password, current_user from sqlalchemy import and_ from wtforms import BooleanField, Form, RadioField, SelectField, StringField from wtforms.fields import DateField from wtforms.validators import NumberRange from advlabdb import assistantSpace, db from advlabdb.customClasses import SecureAssistantBaseView, SecureAssistantModelView from advlabdb.exceptions import DataBaseException, ModelViewException from advlabdb.models import ( Appointment, Assistant, Experiment, ExperimentMark, Group, GroupExperiment, Part, PartStudent, Program, Role, Semester, SemesterExperiment, Student, User, ) from advlabdb.utils import ( flashRandomPassword, initActiveSemesterMenuLinks, randomPassword, userActiveSemester, ) class AssistantAppointmentView(SecureAssistantModelView): can_edit = True column_list = [ "date", "special", "group_experiment.semester_experiment.experiment", "group_experiment.group", "group_experiment.group.part_students", ] column_labels = { "group_experiment.semester_experiment.experiment": "Experiment", "group_experiment.group": "Group", "group_experiment.group.part_students": "Students", } column_editable_list = [ "date", ] form_columns = column_editable_list def queryFilter(self): return and_( Appointment.group_experiment.has( GroupExperiment.semester_experiment.has(SemesterExperiment.semester == userActiveSemester()) ), Appointment.assistant == current_user.assistant, ) class AssistantExperimentMarkView(SecureAssistantModelView): can_edit = True column_list = [ "oral_mark", "protocol_mark", "final_experiment_mark", "group_experiment.semester_experiment.experiment", "part_student.student.first_name", "part_student.student.last_name", "part_student.group", "part_student.student.uni_email", "part_student.student.contact_email", "part_student.part", "assistant", "edited_by_admin", ] column_labels = { "group_experiment.semester_experiment.experiment": "Experiment", "part_student.student.first_name": "First Name", "part_student.student.last_name": "Last Name", "part_student.group": "Group", "part_student.student.uni_email": "Uni Email", "part_student.student.contact_email": "Contact Email", "part_student.part": "Part", } column_descriptions = { "oral_mark": "Between 0 and 15", "protocol_mark": "Between 0 and 15", "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 assistant who assigned the mark", "edited_by_admin": "If the mark was edited by an admin", } column_editable_list = [ "oral_mark", "protocol_mark", ] form_columns = column_editable_list form_args = { "oral_mark": {"validators": [NumberRange(0, 15)]}, "protocol_mark": {"validators": [NumberRange(0, 15)]}, } column_default_sort = [("oral_mark", False), ("protocol_mark", False)] def queryFilter(self): return ExperimentMark.group_experiment.has( GroupExperiment.semester_experiment.has( and_( SemesterExperiment.semester == userActiveSemester(), SemesterExperiment.assistants.any(Assistant.user == current_user), ) ) ) def update_model(self, form, model): if (form.oral_mark and form.oral_mark.data != model.oral_mark) or ( form.protocol_mark and form.protocol_mark.data != model.protocol_mark ): model.assistant = current_user.assistant ret = super().update_model(form, model) model.part_student.checkThenSetFinalPartMark() return ret else: # Nothing changed return True class AssistantUserView(SecureAssistantModelView): class EditForm(Form): phone_number = StringField("Phone Number") mobile_phone_number = StringField("Mobile Phone Number") building = StringField("Building") room = StringField("Room") generate_new_password = BooleanField("Generate new random password", default=False) form = EditForm can_edit = 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 queryFilter(self): return 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/assistant.html") assistantSpace.add_view( AssistantAppointmentView(Appointment, db.session, endpoint="assistant_appointment", url="appointment") ) assistantSpace.add_view( AssistantExperimentMarkView(ExperimentMark, db.session, endpoint="assistant_experimentmark", url="experimentmark") ) 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)