1
0
Fork 0
mirror of https://codeberg.org/Mo8it/AdvLabDB.git synced 2024-09-19 18:31:16 +00:00
AdvLabDB/advlabdb/modelViews.py

511 lines
17 KiB
Python
Raw Normal View History

2021-06-02 21:43:41 +00:00
from flask import flash, request, url_for
from flask_admin.contrib.sqla.filters import BaseSQLAFilter
2021-06-02 21:43:41 +00:00
from flask_admin.menu import MenuLink
2021-07-01 14:38:37 +00:00
from flask_admin.model.template import EndpointLinkRowAction
2021-06-09 00:51:26 +00:00
from flask_security import current_user, hash_password
2021-06-14 10:50:09 +00:00
from sqlalchemy import func
from wtforms import Form, BooleanField, SelectField, TextField, RadioField, FloatField
from wtforms.validators import DataRequired, Email, Optional
from flask_admin.contrib.sqla.fields import QuerySelectMultipleField, QuerySelectField
from flask_admin.helpers import get_form_data
2021-07-01 11:12:43 +00:00
from wtforms.fields.html5 import DateField
2021-06-02 21:43:41 +00:00
from advlabdb import admin, app, db, user_datastore
2021-06-01 23:56:49 +00:00
from advlabdb.configUtils import getConfig
2021-06-02 21:43:41 +00:00
from advlabdb.customClasses import SecureModelView
from advlabdb.models import (
Appointment,
Assistant,
Experiment,
ExperimentMark,
Group,
GroupExperiment,
Part,
SemesterExperiment,
2021-06-02 21:43:41 +00:00
PartStudent,
Role,
Semester,
Student,
User,
)
from advlabdb.utils import (
partFromLabelInUserActiveSemester,
randomPassword,
setUserActiveSemester,
2021-06-02 21:43:41 +00:00
userActiveSemester,
)
2021-06-30 20:04:33 +00:00
class UserView(SecureModelView):
column_list = ["email", "active", "roles", "assistant"]
column_searchable_list = ["email"]
column_filters = ["active"]
2021-04-27 21:28:47 +00:00
form_columns = ["email", "active", "roles"]
2021-07-01 11:12:43 +00:00
column_editable_list = ["active"]
2021-04-27 21:28:47 +00:00
form_args = {
"email": {"validators": [Email()]},
"active": {"default": True},
2021-06-02 21:43:41 +00:00
"roles": {"validators": [DataRequired(message="A role is required!")]},
2021-04-27 21:28:47 +00:00
}
2021-06-09 00:22:37 +00:00
deleteSelfException = "Tried to delete yourself as user!"
deactivateSelfException = "Tried to deactiavte yourself as user!"
def create_model(self, form):
password = randomPassword()
passwordHash = hash_password(password)
email = form.email.data.lower()
roles = [role.name for role in form.roles.data]
if "admin" in roles:
flash("You have registered a new admin!", "danger")
try:
model = user_datastore.create_user(email=email, password=passwordHash, roles=roles)
self.on_model_change(form, model, True)
self.session.commit()
except Exception as ex:
flash(ex, "error")
self.session.rollback()
else:
flash(
f"{email} registered with roles: {', '.join([role.name for role in form.roles.data])}.",
category="success",
)
flash(f"Random password: {password}", category="warning")
return model
2021-06-09 00:22:37 +00:00
def on_model_delete(self, model):
if model == current_user:
raise Exception(self.deleteSelfException)
def on_model_change(self, form, model, is_created):
if model == current_user and not form.active.data:
raise Exception(self.deactivateSelfException)
def handle_view_exception(self, exc):
if exc.args[0] in (self.deleteSelfException, self.deactivateSelfException):
pass
else:
return super().handle_view_exception(exc)
2021-06-30 20:04:33 +00:00
class RoleView(SecureModelView):
2021-06-09 00:22:37 +00:00
can_create = False
can_edit = False
can_delete = False
column_display_actions = False
column_list = ["name", "description"]
2021-04-24 11:38:03 +00:00
2021-06-30 20:04:33 +00:00
class SemesterView(SecureModelView):
can_edit = False
2021-04-24 11:38:03 +00:00
column_list = ["label", "parts"]
form_columns = ["semester_label", "year", "transfer_parts", "transfer_semester_experiments", "transfer_assistants"]
2021-04-24 11:38:03 +00:00
semesterLabels = ["WS", "SS"]
2021-07-01 14:38:37 +00:00
transferDesciption = "Will be trasfered from your current semester."
2021-04-24 11:38:03 +00:00
form_extra_fields = {
"semester_label": RadioField(
"Semester", choices=list(zip(semesterLabels, semesterLabels)), validators=[DataRequired()]
),
"year": TextField("Year", validators=[DataRequired()]),
"transfer_parts": BooleanField(
2021-07-01 14:38:37 +00:00
"Transfer parts",
description=transferDesciption,
default=True,
),
"transfer_semester_experiments": BooleanField(
2021-07-01 14:38:37 +00:00
"Transfer Semester Experiemnts", description=transferDesciption, default=True
),
"transfer_assistants": BooleanField(
"Transfer Assistants",
description=transferDesciption + " This option has no effect if Semester Experiments are not transfered.",
default=True,
),
2021-04-24 11:38:03 +00:00
}
def create_model(self, form):
try:
model = Semester(label=form.semester_label.data + form.year.data)
self.session.add(model)
self.on_model_change(form, model, True)
self.session.commit()
except Exception as ex:
flash(ex, "error")
self.session.rollback()
else:
self.after_model_change(form, model, True)
return model
2021-04-24 11:38:03 +00:00
def after_model_change(self, form, model, is_created):
admin.add_link(
MenuLink(
name=model.label,
url=url_for("set_semester") + "?semester_id=" + str(model.id),
category="Active semester",
)
)
oldSemester = userActiveSemester()
setUserActiveSemester(model.id)
if form.transfer_parts.data:
model.transferParts(oldSemester)
2021-04-24 11:38:03 +00:00
if form.transfer_semester_experiments.data:
try:
for semesterExperiment in oldSemester.semester_experiments:
newSemesterExperiment = SemesterExperiment(
experiment=semesterExperiment.experiment, semester=userActiveSemester()
)
if form.transfer_assistants.data:
newSemesterExperiment.assistants = semesterExperiment.assistants
self.session.add(newSemesterExperiment)
self.session.commit()
except Exception as ex:
flash(ex, "error")
self.session.rollback()
2021-04-24 11:38:03 +00:00
2021-06-30 20:04:33 +00:00
class PartView(SecureModelView):
2021-04-24 11:38:03 +00:00
can_view_details = True
column_details_list = ["label", "semester", "part_students", "groups"]
2021-04-24 11:38:03 +00:00
form_columns = ["label", "semester"]
2021-06-10 01:14:30 +00:00
def get_query(self):
return super().get_query().filter(Part.id.in_([part.id for part in userActiveSemester().parts]))
def get_count_query(self):
return (
self.session.query(func.count("*"))
.select_from(self.model)
.filter(Part.id.in_([part.id for part in userActiveSemester().parts]))
)
2021-06-30 20:04:33 +00:00
class StudentView(SecureModelView):
can_view_details = True
column_list = ["student_number", "first_name", "last_name", "uni_email", "contact_email", "part_students"]
2021-04-26 22:26:11 +00:00
column_details_list = column_list + ["bachelor_thesis", "bachelor_thesis_work_group", "note"]
column_sortable_list = ["student_number", "first_name", "last_name"]
column_searchable_list = column_sortable_list + ["uni_email", "contact_email"]
form_excluded_columns = ["part_students"]
2021-04-26 22:26:11 +00:00
2021-04-27 21:28:47 +00:00
form_args = {
"uni_email": {"validators": [Email()]},
"contact_email": {"validators": [Email()]},
2021-04-27 21:28:47 +00:00
}
2021-07-01 14:38:37 +00:00
column_extra_row_actions = [
EndpointLinkRowAction(
"glyphicon glyphicon-time",
id_arg="flt1_0",
title="Experiments history",
endpoint="experimentmark.index_view",
)
]
2021-06-10 01:14:30 +00:00
def partQueryFactory():
return Part.query.filter(Part.id.in_([part.id for part in userActiveSemester().parts]))
2021-06-10 01:14:30 +00:00
2021-07-01 11:12:43 +00:00
def groupQueryFactory():
return Group.query.filter(Group.part_id.in_([part.id for part in userActiveSemester().parts]))
2021-06-30 20:04:33 +00:00
class PartStudentView(SecureModelView):
class CreateForm(Form):
def studentQueryFactory():
return Student.query
2021-04-26 22:26:11 +00:00
student = QuerySelectField(
"Student", query_factory=studentQueryFactory, validators=[DataRequired()], allow_blank=True, blank_text="-"
)
part = QuerySelectField(
"Part", query_factory=partQueryFactory, validators=[DataRequired()], allow_blank=True, blank_text="-"
)
group = QuerySelectField("Group", query_factory=groupQueryFactory, allow_blank=True, blank_text="-")
2021-04-26 22:26:11 +00:00
class EditForm(CreateForm):
student = None
part = None
final_part_mark = FloatField("Final Part Mark", validators=[Optional()])
form = EditForm
column_filters = ["part", "student", "group"]
partGroupPartMismatchException = "Part and groups part don't match!"
def create_form(self, obj=None):
form = self.CreateForm
return form(get_form_data(), obj=obj)
2021-04-27 21:28:47 +00:00
def on_model_change(self, form, model, is_created):
if model.group and model.part != model.group.part:
raise Exception(self.partGroupPartMismatchException)
2021-04-27 21:28:47 +00:00
def handle_view_exception(self, exc):
if exc.args[0] in (self.partGroupPartMismatchException):
pass
2021-04-27 21:28:47 +00:00
else:
return super().handle_view_exception(exc)
2021-04-27 21:28:47 +00:00
2021-06-10 01:14:30 +00:00
def get_query(self):
return super().get_query().filter(PartStudent.part_id.in_([part.id for part in userActiveSemester().parts]))
def get_count_query(self):
return (
self.session.query(func.count("*"))
.select_from(self.model)
.filter(PartStudent.part_id.in_([part.id for part in userActiveSemester().parts]))
)
2021-06-30 20:04:33 +00:00
class GroupView(SecureModelView):
class CreateForm(Form):
def partStudentsQueryFactory():
return PartStudent.query.filter(PartStudent.part_id.in_([part.id for part in userActiveSemester().parts]))
part = QuerySelectField(
2021-07-01 11:12:43 +00:00
"Part", query_factory=partQueryFactory, validators=[DataRequired()], allow_blank=True, blank_text="-"
)
2021-07-01 11:12:43 +00:00
part_students = QuerySelectMultipleField("Part Students", query_factory=partStudentsQueryFactory)
class EditForm(CreateForm):
part = None
form = EditForm
column_list = ["number", "part", "part_students"]
2021-07-01 11:12:43 +00:00
column_filters = ["number", "part"]
partStudentPartPartMismatchException = "Part and StudentParts part don't match!"
def create_model(self, form):
try:
orderedPartGroups = Group.query.filter(Group.part == form.part.data).order_by(Group.number)
lastTakenGroupNumber = orderedPartGroups[-1].number if orderedPartGroups.count() > 0 else 0
model = Group(
number=lastTakenGroupNumber + 1,
part_students=form.part_students.data,
part=form.part.data,
)
self.session.add(model)
self.on_model_change(form, model, True)
self.session.commit()
except Exception as ex:
flash(ex, "error")
self.session.rollback()
else:
self.after_model_change(form, model, True)
return model
def on_model_change(self, form, model, is_created):
for partStudent in model.part_students:
if model.part != partStudent.part:
raise Exception(self.partStudentPartPartMismatchException)
def handle_view_exception(self, exc):
if exc.args[0] in (self.partStudentPartPartMismatchException):
pass
else:
return super().handle_view_exception(exc)
def create_form(self, obj=None):
form = self.CreateForm
return form(get_form_data(), obj=obj)
2021-06-07 15:15:10 +00:00
2021-06-10 01:14:30 +00:00
def get_query(self):
return super().get_query().filter(Group.part_id.in_([part.id for part in userActiveSemester().parts]))
def get_count_query(self):
return (
self.session.query(func.count("*"))
.select_from(self.model)
.filter(Group.part_id.in_([part.id for part in userActiveSemester().parts]))
)
2021-06-07 15:15:10 +00:00
2021-06-30 20:04:33 +00:00
class ExperimentView(SecureModelView):
2021-06-21 16:07:18 +00:00
can_view_details = True
column_filters = ["deprecated"]
2021-06-21 16:26:38 +00:00
column_list = ["number", "name", "deprecated"]
class SemesterExperimentView(SecureModelView):
column_list = ["experiment", "semester", "assistants"]
2021-06-21 16:26:38 +00:00
def get_query(self):
return super().get_query().filter(SemesterExperiment.semester == userActiveSemester())
2021-06-21 16:26:38 +00:00
def get_count_query(self):
return (
self.session.query(func.count("*"))
.select_from(self.model)
.filter(SemesterExperiment.semester == userActiveSemester())
2021-06-21 16:26:38 +00:00
)
2021-06-21 16:07:18 +00:00
2021-06-30 20:04:33 +00:00
class AssistantView(SecureModelView):
2021-06-24 17:24:14 +00:00
can_view_details = True
column_list = ["first_name", "last_name", "email", "user", "semester_experiments"]
2021-07-01 11:12:43 +00:00
column_details_list = column_list + [
"phone_number",
"mobile_phone_number",
"room",
"building",
"appointments",
"experiment_marks",
]
2021-06-24 17:24:14 +00:00
column_filters = ["user.active"]
form_excluded_columns = ["experiment_marks"]
2021-06-30 20:04:33 +00:00
class GroupExperimentView(SecureModelView):
2021-07-01 11:12:43 +00:00
class CreateForm(Form):
def semesterExperimentQueryFactory():
return SemesterExperiment.query.filter(SemesterExperiment.semester == userActiveSemester())
2021-07-01 11:12:43 +00:00
def assistantQueryFactory():
return Assistant.query.filter(
Assistant.user_id.in_([user.id for user in User.query.filter(User.active == True)])
)
group = QuerySelectField(
"Group", query_factory=groupQueryFactory, validators=[DataRequired()], allow_blank=True, blank_text="-"
)
semester_experiment = QuerySelectField(
"Semester Experiment",
query_factory=semesterExperimentQueryFactory,
2021-07-01 11:12:43 +00:00
validators=[DataRequired()],
allow_blank=True,
blank_text="-",
)
assistantBlankText = "Auto assign if experiment has only one assistant"
2021-07-01 14:38:37 +00:00
appointment1 = DateField("Appointment-1")
appointment1_special = BooleanField("Appointment-1 special", default=False)
2021-07-01 11:12:43 +00:00
appointment1_assistant = QuerySelectField(
2021-07-01 14:38:37 +00:00
"Appointment-1 Assistant",
2021-07-01 11:12:43 +00:00
query_factory=assistantQueryFactory,
allow_blank=True,
blank_text=assistantBlankText,
)
2021-07-01 14:38:37 +00:00
appointment2 = DateField("Appointment-2")
appointment2_special = BooleanField("Appointment-2 special", default=False)
2021-07-01 11:12:43 +00:00
appointment2_assistant = QuerySelectField(
2021-07-01 14:38:37 +00:00
"Appointment-2 Assistant",
2021-07-01 11:12:43 +00:00
query_factory=assistantQueryFactory,
allow_blank=True,
blank_text=assistantBlankText,
)
form = CreateForm
2021-07-01 14:38:37 +00:00
can_edit = False
column_list = ["group", "semester_experiment", "appointments", "experiment_marks"]
column_filters = ["group", "semester_experiment.experiment", "appointments"]
2021-06-24 17:39:26 +00:00
def get_query(self):
return (
super()
.get_query()
.filter(
GroupExperiment.group_id.in_(
[
g.id
for g in Group.query.filter(Group.part_id.in_([part.id for part in userActiveSemester().parts]))
]
)
)
)
def get_count_query(self):
return (
self.session.query(func.count("*"))
.select_from(self.model)
.filter(
GroupExperiment.group_id.in_(
[
g.id
for g in Group.query.filter(Group.part_id.in_([part.id for part in userActiveSemester().parts]))
]
)
)
)
2021-07-01 11:12:43 +00:00
class AppointmentView(SecureModelView):
column_list = ["date", "special", "group_experiment", "assistant"]
2021-07-01 14:38:37 +00:00
class ExperimentMarkView(SecureModelView):
class StudentIdFilter(BaseSQLAFilter):
def apply(self, query, value, alias=None):
return query.filter(self.column == value)
def operation(self):
return "equals"
def validate(self, value):
if Student.query.get(value):
return True
else:
return False
column_filters = [
StudentIdFilter(PartStudent.id, "Student / ID"),
"part_student.student",
"group_experiment.semester_experiment.semester",
"group_experiment.semester_experiment.experiment",
]
2021-06-30 20:04:33 +00:00
admin.add_view(StudentView(Student, db.session))
admin.add_view(PartStudentView(PartStudent, db.session))
admin.add_view(GroupView(Group, db.session))
admin.add_view(GroupExperimentView(GroupExperiment, db.session))
2021-07-01 14:38:37 +00:00
admin.add_view(AppointmentView(Appointment, db.session))
admin.add_view(ExperimentMarkView(ExperimentMark, db.session))
2021-06-30 20:04:33 +00:00
admin.add_view(ExperimentView(Experiment, db.session))
admin.add_view(SemesterExperimentView(SemesterExperiment, db.session))
2021-06-30 20:04:33 +00:00
admin.add_view(AssistantView(Assistant, db.session))
admin.add_view(PartView(Part, db.session))
admin.add_view(SemesterView(Semester, db.session))
admin.add_view(UserView(User, db.session))
admin.add_view(RoleView(Role, db.session))
with app.app_context():
semesters = Semester.query.order_by(Semester.id)
for semester in semesters:
2021-06-02 21:43:41 +00:00
admin.add_link(
MenuLink(
name=semester.label,
url=url_for("set_semester") + "?semester_id=" + str(semester.id),
category="Active semester",
)
)
2021-06-28 16:43:13 +00:00
admin.add_link(MenuLink(name="Logout", url=url_for("security.logout")))