diff --git a/advlabdb/adminModelViews.py b/advlabdb/adminModelViews.py index e8c23c9..0233f1a 100644 --- a/advlabdb/adminModelViews.py +++ b/advlabdb/adminModelViews.py @@ -1,6 +1,6 @@ from pathlib import Path -from flask import flash, redirect, request, url_for +from flask import flash, redirect, request, url_for, has_request_context from flask_admin import expose from flask_admin.contrib.sqla.fields import QuerySelectField, QuerySelectMultipleField from flask_admin.contrib.sqla.filters import FilterEqual @@ -134,10 +134,10 @@ class UserView(SecureAdminModelView): "last_name", "email", ] - column_filters = [ + column_filters = ( "active", "active_semester", - ] + ) column_editable_list = [ "active", ] @@ -292,14 +292,18 @@ class SemesterView(SecureAdminModelView): ) def addMenuLink(space, newSemester): - space.add_link( - MenuLink( - name=newSemester.repr(), - url=url_for("set_semester") + "?semester_id=" + str(newSemester.id), - category="Active semester", - ) + categoryText = "Active semester" + link = MenuLink( + name=newSemester.repr(), + url=url_for("set_semester") + "?semester_id=" + str(newSemester.id), + category=categoryText, ) + category = self._menu_categories.get(categoryText) + + link.parent = category + category._children.insert(0, link) + def after_model_change(self, form, model, is_created): setUserActiveSemester(model.id) @@ -398,7 +402,28 @@ def groupQueryFactory(): return Group.query.filter(Group.semester == userActiveSemester()) +def partFilterOptions(): + if has_request_context(): + parts = Part.query.filter(Part.semester == userActiveSemester()) + return ((part.id, f"{part.program.repr()}{part.number}") for part in parts) + else: + return + + class PartStudentView(SecureAdminModelView): + @expose("/") + def index_view(self): + # To update filter options + self._refresh_filters_cache() + return super().index_view() + + class PartFilter(FilterEqual): + def get_options(self, view): + return partFilterOptions() + + def apply(self, query, value, alias=None): + return query.filter(self.column.part_id == int(value)) + class CreateForm(Form): def studentQueryFactory(): return Student.query @@ -438,11 +463,14 @@ class PartStudentView(SecureAdminModelView): "experiment_marks", ] - column_filters = [ - "part", - "student", - "group", - ] + column_filters = ( + PartFilter(PartStudent, "Part"), + "student.student_number", + "student.first_name", + "student.last_name", + "group.number", + "experiment_marks", + ) def queryFilter(self): return PartStudent.part.has(Part.semester == userActiveSemester()) @@ -460,6 +488,20 @@ def partStudentQueryFactory(): class GroupView(SecureAdminModelView): + @expose("/") + def index_view(self): + # To update filter options + self._refresh_filters_cache() + return super().index_view() + + class ProgramFilter(FilterEqual): + def get_options(self, view): + programs = Program.query + return ((program.id, program.repr()) for program in programs) + + def apply(self, query, value, alias=None): + return query.filter(self.column.program_id == int(value)) + def formFactory(is_created, group): if is_created: @@ -488,15 +530,14 @@ class GroupView(SecureAdminModelView): column_list = [ "number", - "semester", "program", "part_students", "group_experiments", ] - column_filters = [ + column_filters = ( + ProgramFilter(Group, "Program"), "number", - "program", - ] + ) def queryFilter(self): return Group.semester == userActiveSemester() @@ -516,9 +557,7 @@ class GroupView(SecureAdminModelView): class ExperimentView(SecureAdminModelView): can_view_details = True - column_filters = [ - "active", - ] + column_filters = ("active",) column_list = [ "number", "program", @@ -611,9 +650,7 @@ class SemesterExperimentView(SecureAdminModelView): "final_weighting", "group_experiments", ] - column_filters = [ - "experiment", - ] + column_filters = ("experiment",) def queryFilter(self): return SemesterExperiment.semester == userActiveSemester() @@ -657,9 +694,7 @@ class AssistantView(SecureAdminModelView): "user.last_name", "user.email", ] - column_filters = [ - "user.active", - ] + column_filters = ("user.active",) form_excluded_columns = [ "experiment_marks", "appointments", @@ -688,6 +723,17 @@ class AssistantView(SecureAdminModelView): assistantBlankText = "Auto assign if experiment has only one assistant" +def experimentFilterOptions(): + activeExperiments = Experiment.query.filter(Experiment.active == True) + return ( + ( + f"{activeExperiment.number},{activeExperiment.program.id}", + f"{activeExperiment.number} {activeExperiment.program.repr()}", + ) + for activeExperiment in activeExperiments + ) + + class GroupExperimentView(SecureAdminModelView): @expose("/") def index_view(self): @@ -697,14 +743,7 @@ class GroupExperimentView(SecureAdminModelView): class ExperimentFilter(FilterEqual): def get_options(self, view): - activeExperiments = Experiment.query.filter(Experiment.active == True).all() - return ( - ( - f"{activeExperiment.number},{activeExperiment.program.id}", - f"{activeExperiment.number} {activeExperiment.program.repr()}", - ) - for activeExperiment in activeExperiments - ) + return experimentFilterOptions() def apply(self, query, value, alias=None): values = value.split(",") @@ -770,11 +809,12 @@ class GroupExperimentView(SecureAdminModelView): "appointments", "experiment_marks", ] - column_filters = [ - "group", + column_filters = ( ExperimentFilter(GroupExperiment, "Experiment"), + "group.number", "appointments", - ] + "experiment_marks", + ) def queryFilter(self): return GroupExperiment.group.has(Group.semester == userActiveSemester()) @@ -808,7 +848,47 @@ def groupExperimentQueryFactory(): ) +def assistantFilterOptions(): + assistants = Assistant.query.filter(Assistant.user.has(User.active == True)) + return ((assistant.id, assistant.repr()) for assistant in assistants) + + class AppointmentView(SecureAdminModelView): + @expose("/") + def index_view(self): + # To update filter options + self._refresh_filters_cache() + return super().index_view() + + class ExperimentFilter(FilterEqual): + def get_options(self, view): + return experimentFilterOptions() + + def apply(self, query, value, alias=None): + values = value.split(",") + experimentNumber = int(values[0]) + programId = int(values[1]) + + return query.filter( + self.column.group_experiment.has( + GroupExperiment.semester_experiment.has( + SemesterExperiment.experiment.has(Experiment.program_id == programId) + ) + ), + self.column.group_experiment.has( + GroupExperiment.semester_experiment.has( + SemesterExperiment.experiment.has(Experiment.number == experimentNumber) + ) + ), + ) + + class AssistantFilter(FilterEqual): + def get_options(self, view): + return assistantFilterOptions() + + def apply(self, query, value, alias=None): + return query.filter(self.column.assistant_id == int(value)) + class CreateForm(Form): group_experiment = QuerySelectField( "Group Experiment", @@ -828,13 +908,13 @@ class AppointmentView(SecureAdminModelView): form = CreateForm - column_filters = [ + column_filters = ( + ExperimentFilter(Appointment, "Experiment"), + AssistantFilter(Appointment, "Assistant"), + "group_experiment.group", "date", "special", - "group_experiment.group", - "group_experiment.semester_experiment.experiment", - "assistant.user", - ] + ) column_editable_list = [ "date", "special", @@ -886,21 +966,72 @@ class ExperimentMarkView(SecureAdminModelView): else: return False + def apply(self, query, value, alias=None): + return query.filter(self.column.part_student.has(PartStudent.student_id == int(value))) + class AssistantFilter(FilterEqual): def get_options(self, view): - assistants = Assistant.query.filter(Assistant.user.has(User.active == True)).all() - return ((assistant.id, assistant.repr()) for assistant in assistants) + return assistantFilterOptions() def apply(self, query, value, alias=None): - return query.filter(self.column == int(value)) + return query.filter(self.column.assistant_id == int(value)) class AdminFilter(FilterEqual): def get_options(self, view): - admins = Admin.query.filter(Admin.user.has(User.active == True)).all() + admins = Admin.query.filter(Admin.user.has(User.active == True)) return ((admin.id, admin.repr()) for admin in admins) def apply(self, query, value, alias=None): - return query.filter(self.column == int(value)) + return query.filter(self.column.admin_id == int(value)) + + class ExperimentFilter(FilterEqual): + def get_options(self, view): + return experimentFilterOptions() + + def apply(self, query, value, alias=None): + values = value.split(",") + experimentNumber = int(values[0]) + programId = int(values[1]) + + return query.filter( + self.column.group_experiment.has( + GroupExperiment.semester_experiment.has( + SemesterExperiment.experiment.has(Experiment.program_id == programId) + ) + ), + self.column.group_experiment.has( + GroupExperiment.semester_experiment.has( + SemesterExperiment.experiment.has(Experiment.number == experimentNumber) + ) + ), + ) + + class ProgramFilter(FilterEqual): + def get_options(self, view): + programs = Program.query + return ((program.id, program.repr()) for program in programs) + + def apply(self, query, value, alias=None): + return query.filter(self.column.part_student.has(PartStudent.part.has(Part.program_id == int(value)))) + + class PartFilter(FilterEqual): + def get_options(self, view): + return partFilterOptions() + + def apply(self, query, value, alias=None): + return query.filter(self.column.part_student.has(PartStudent.part_id == int(value))) + + class SemesterFilter(FilterEqual): + def get_options(self, view): + semesters = Semester.query.order_by(Semester.id.desc()) + return ((semester.id, semester.repr()) for semester in semesters) + + def apply(self, query, value, alias=None): + return query.filter( + self.column.group_experiment.has( + GroupExperiment.semester_experiment.has(SemesterExperiment.semester_id == int(value)) + ) + ) class CreateForm(Form): part_student = QuerySelectField( @@ -940,20 +1071,19 @@ class ExperimentMarkView(SecureAdminModelView): "admin": "The last admin who edited the mark", } - column_filters = [ - StudentFilter(PartStudent.id, "Student / ID"), - AssistantFilter(ExperimentMark.assistant_id, "Assistant"), - AdminFilter(ExperimentMark.admin_id, "Admin"), - "part_student.part.program", - "part_student.part", - "part_student.student", + column_filters = ( + StudentFilter(ExperimentMark, "Student / ID"), + SemesterFilter(ExperimentMark, "Semester"), + AssistantFilter(ExperimentMark, "Assistant"), + AdminFilter(ExperimentMark, "Admin"), + ExperimentFilter(ExperimentMark, "Experiment"), + ProgramFilter(ExperimentMark, "Program"), + PartFilter(ExperimentMark, "Part"), "group_experiment.group", - "group_experiment.semester_experiment.semester", - "group_experiment.semester_experiment.experiment", "oral_mark", "protocol_mark", "final_experiment_mark", - ] + ) column_default_sort = [("oral_mark", False), ("protocol_mark", False)] """ diff --git a/advlabdb/utils.py b/advlabdb/utils.py index 4918485..5db692c 100644 --- a/advlabdb/utils.py +++ b/advlabdb/utils.py @@ -56,7 +56,7 @@ def setUserActiveSemester(semesterId): def initActiveSemesterMenuLinks(space): with app.app_context(): - semesters = Semester.query.order_by(Semester.id) + semesters = Semester.query.order_by(Semester.id.desc()) for semester in semesters: space.add_link( MenuLink( diff --git a/testDB.py b/testDB.py index c1e63b9..e45bce4 100644 --- a/testDB.py +++ b/testDB.py @@ -95,13 +95,13 @@ with app.app_context(): db.session.add(gx1) db.session.add(gx2) - user_datastore.create_role(name="admin") - user_datastore.create_role(name="assistant") + adminRole = user_datastore.create_role(name="admin") + assistantRole = user_datastore.create_role(name="assistant") admin_user = user_datastore.create_user( email="admin@advlabdb.de", password=hash_password("admin"), - roles=["admin"], + roles=[adminRole], first_name="Peter", last_name="Blümler", ) @@ -113,7 +113,7 @@ with app.app_context(): us1 = user_datastore.create_user( email="test@protonmail.com", password=hash_password("h1"), - roles=["assistant"], + roles=[assistantRole], first_name="As1", last_name="l", phone_number="012333212", @@ -122,7 +122,7 @@ with app.app_context(): us2 = user_datastore.create_user( email="test2@protonmail.com", password=hash_password("h2"), - roles=["assistant"], + roles=[assistantRole], first_name="As2", last_name="l", )