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

392 lines
14 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-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
2021-04-26 22:26:11 +00:00
from wtforms import BooleanField, SelectField, TextField
2021-04-27 21:28:47 +00:00
from wtforms.validators import DataRequired, Email
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,
PartExperiment,
PartStudent,
Role,
Semester,
Student,
User,
)
from advlabdb.utils import (
partFromLabelInUserActiveSemester,
randomPassword,
setActiveSemester,
userActiveSemester,
)
class UserModelView(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"]
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.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)
class RoleModelView(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
class SemesterModelView(SecureModelView):
can_edit = False
2021-04-24 11:38:03 +00:00
column_list = ["label", "parts"]
form_columns = ["semester_label", "year", "create_parts"]
2021-04-24 11:38:03 +00:00
semesterLabels = ["WS", "SS"]
2021-04-24 11:38:03 +00:00
form_extra_fields = {
"semester_label": SelectField(
"Semester", choices=list(zip(semesterLabels, semesterLabels)), validators=[DataRequired()]
),
"year": TextField("Year", validators=[DataRequired()]),
"create_parts": BooleanField("Create parts:" + ", ".join(getConfig("partLabels")) + ".", 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.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):
2021-04-27 21:28:47 +00:00
if form.create_parts.data:
2021-06-02 00:13:52 +00:00
model.createParts()
2021-04-24 11:38:03 +00:00
if is_created:
2021-06-02 21:43:41 +00:00
admin.add_link(
MenuLink(
name=model.label,
url=url_for("set_semester") + "?semester_id=" + str(model.id),
category="Active semester",
)
)
setActiveSemester(model.id)
2021-04-24 11:38:03 +00:00
class PartModelView(SecureModelView):
can_view_details = True
column_details_list = ["label", "semester", "part_experiments", "part_students", "groups"]
form_columns = ["label", "semester"]
partLabels = getConfig("partLabels")
form_choices = {"label": list(zip(partLabels, partLabels))}
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]))
)
class StudentModelView(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_searchable_list = ["student_number", "uni_email", "contact_email", "first_name", "last_name"]
2021-04-26 22:26:11 +00:00
form_columns = column_details_list + ["new_part_student_part", "new_part_student_group_number"]
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
}
partChoices = ["-"] + getConfig("partLabels")
2021-04-26 22:26:11 +00:00
form_extra_fields = {
2021-06-02 21:43:41 +00:00
"new_part_student_part": SelectField(
"Part", choices=list(zip(partChoices, partChoices)), default=partChoices[0]
),
"new_part_student_group_number": TextField("Group number"),
2021-04-26 22:26:11 +00:00
}
def validate_form(self, form):
if request.method == "POST":
partLabel = form.new_part_student_part.data
groupNumber = form.new_part_student_group_number.data
2021-06-10 01:14:30 +00:00
2021-06-02 21:43:41 +00:00
if (partLabel != self.partChoices[0] and groupNumber == "") or (
partLabel == self.partChoices[0] and groupNumber != ""
):
2021-04-26 22:26:11 +00:00
flash("You have to assign both part and group if you want to add a part student!", "danger")
return False
2021-06-10 01:14:30 +00:00
if partLabel != self.partChoices[0] and not partFromLabelInUserActiveSemester(partLabel):
2021-04-26 22:26:11 +00:00
flash(f"Part {partLabel} is not created in {str(userActiveSemester())} yet!", "danger")
return False
2021-06-10 01:14:30 +00:00
2021-04-26 22:26:11 +00:00
if groupNumber != "":
message = "The group number has to be an integer > 0 !"
2021-06-10 01:14:30 +00:00
2021-04-26 22:26:11 +00:00
try:
groupNumber = int(groupNumber)
2021-06-10 01:14:30 +00:00
except Exception:
2021-04-26 22:26:11 +00:00
flash(message, "danger")
return False
2021-06-10 01:14:30 +00:00
2021-04-26 22:26:11 +00:00
if groupNumber < 1:
flash(message, "danger")
return False
2021-06-10 01:14:30 +00:00
2021-04-26 22:26:11 +00:00
return super().validate_form(form)
def after_model_change(self, form, model, is_created):
partLabel = form.new_part_student_part.data
2021-04-26 22:26:11 +00:00
if partLabel != self.partChoices[0]:
groupNumber = int(form.new_part_student_group_number.data)
part = partFromLabelInUserActiveSemester(partLabel)
2021-04-26 22:26:11 +00:00
group = Group.query.filter(Group.number == groupNumber, Group.part == part).first()
if group is None:
try:
group = Group(number=groupNumber, part=part)
self.session.add(group)
self.session.commit()
except Exception as ex:
flash(ex, "error")
2021-04-26 22:26:11 +00:00
self.session.rollback()
return
else:
flash(f"Added the new group with number {str(groupNumber)} in part {str(part)}.", "success")
try:
partStudent = PartStudent(student=model, part=part, group=group)
self.session.add(partStudent)
self.session.commit()
except Exception as ex:
flash(ex, "error")
self.session.rollback()
else:
flash("Added part student.", "success")
2021-04-27 21:28:47 +00:00
class PartFilter(BaseSQLAFilter):
def apply(self, query, value, alias=None):
return query.filter(self.column == partFromLabelInUserActiveSemester(value).id)
def operation(self):
return "equals"
def validate(self, value):
if partFromLabelInUserActiveSemester(value):
return True
else:
flash(f"Part {value} not found in your active semester {userActiveSemester()}!", "danger")
return False
class PartStudentModelView(SecureModelView):
partLabels = getConfig("partLabels")
column_filters = [PartFilter(PartStudent.part_id, "Part", options=list(zip(partLabels, partLabels)))]
2021-04-27 21:28:47 +00:00
form_excluded_columns = ["experiment_marks"]
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-07 15:15:10 +00:00
class GroupModelView(SecureModelView):
partLabels = getConfig("partLabels")
column_filters = [PartFilter(Group.part_id, "Part", options=list(zip(partLabels, partLabels)))]
2021-06-07 15:15:10 +00:00
def validate_form(self, form):
if request.method == "POST":
if Group.query.filter(Group.number == form.number.data, Group.part == form.part.data).first():
lastTakenGroupNumber = (
Group.query.filter(Group.part == form.part.data).order_by(Group.number)[-1].number
)
flash(
f"Group number taken in this part! Last group number taken in this part is {lastTakenGroupNumber}.",
"warning",
)
return False
return super().validate_form(form)
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-21 16:07:18 +00:00
class ExperimentModelView(SecureModelView):
can_view_details = True
column_filters = ["deprecated"]
2021-06-21 16:26:38 +00:00
column_list = ["number", "name", "deprecated"]
class PartExperimentModelView(SecureModelView):
column_list = ["experiment", "part", "assistants"]
partLabels = getConfig("partLabels")
column_filters = [PartFilter(PartExperiment.part_id, "Part", options=list(zip(partLabels, partLabels)))]
def get_query(self):
return super().get_query().filter(PartExperiment.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(PartExperiment.part_id.in_([part.id for part in userActiveSemester().parts]))
)
2021-06-21 16:07:18 +00:00
2021-06-24 17:24:14 +00:00
class AssistantModelView(SecureModelView):
can_view_details = True
column_list = ["first_name", "last_name", "email", "user", "part_experiments"]
column_details_list = column_list + ["phone_number", "mobile_phone_number", "room", "building", "experiment_marks"]
column_filters = ["user.active"]
form_excluded_columns = ["experiment_marks"]
2021-06-24 17:39:26 +00:00
class GroupExperimentModelView(SecureModelView):
column_list = ["group", "part_experiment", "appointments", "experiment_marks"]
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]))
]
)
)
)
admin.add_view(StudentModelView(Student, db.session))
admin.add_view(PartStudentModelView(PartStudent, db.session))
2021-06-07 15:15:10 +00:00
admin.add_view(GroupModelView(Group, db.session))
2021-06-24 17:39:26 +00:00
admin.add_view(GroupExperimentModelView(GroupExperiment, db.session))
2021-06-21 16:07:18 +00:00
admin.add_view(ExperimentModelView(Experiment, db.session))
2021-06-21 16:26:38 +00:00
admin.add_view(PartExperimentModelView(PartExperiment, db.session))
2021-06-24 17:24:14 +00:00
admin.add_view(AssistantModelView(Assistant, db.session))
admin.add_view(SecureModelView(Appointment, db.session))
2021-04-24 11:38:03 +00:00
admin.add_view(PartModelView(Part, db.session))
admin.add_view(SemesterModelView(Semester, db.session))
admin.add_view(SecureModelView(ExperimentMark, db.session))
admin.add_view(UserModelView(User, db.session))
admin.add_view(RoleModelView(Role, db.session))
with app.app_context():
2021-05-17 20:15:50 +00:00
semesters = Semester.query.all()[::-1]
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",
)
)