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

Improved Students, PartStudents and Groups view

This commit is contained in:
Mo 2021-06-30 21:58:57 +02:00
parent 5aa408df89
commit d9eaafeb6d

View file

@ -3,8 +3,10 @@ from flask_admin.contrib.sqla.filters import BaseSQLAFilter
from flask_admin.menu import MenuLink
from flask_security import current_user, hash_password
from sqlalchemy import func
from wtforms import BooleanField, SelectField, TextField, RadioField
from wtforms.validators import DataRequired, Email
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
from advlabdb import admin, app, db, user_datastore
from advlabdb.configUtils import getConfig
@ -59,6 +61,8 @@ class UserModelView(SecureModelView):
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")
@ -120,7 +124,9 @@ class SemesterModelView(SecureModelView):
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")
@ -183,108 +189,65 @@ class PartModelView(SecureModelView):
class StudentModelView(SecureModelView):
can_view_details = True
column_list = ["student_number", "first_name", "last_name", "uni_email", "contact_email", "part_students"]
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"]
form_columns = column_details_list + ["new_part_student_part", "new_part_student_group_number"]
column_sortable_list = ["student_number", "first_name", "last_name"]
column_searchable_list = column_sortable_list + ["uni_email", "contact_email"]
form_excluded_columns = ["part_students"]
form_args = {
"uni_email": {"validators": [Email()]},
"contact_email": {"validators": [Email()]},
}
partChoices = ["-"] + getConfig("partLabels")
form_extra_fields = {
"new_part_student_part": SelectField(
"Part", choices=list(zip(partChoices, partChoices)), default=partChoices[0]
),
"new_part_student_group_number": TextField("Group number"),
}
def validate_form(self, form):
if request.method == "POST":
partLabel = form.new_part_student_part.data
groupNumber = form.new_part_student_group_number.data
if (partLabel != self.partChoices[0] and groupNumber == "") or (
partLabel == self.partChoices[0] and groupNumber != ""
):
flash("You have to assign both part and group if you want to add a part student!", "danger")
return False
if partLabel != self.partChoices[0] and not partFromLabelInUserActiveSemester(partLabel):
flash(f"Part {partLabel} is not created in {str(userActiveSemester())} yet!", "danger")
return False
if groupNumber != "":
message = "The group number has to be an integer > 0 !"
try:
groupNumber = int(groupNumber)
except Exception:
flash(message, "danger")
return False
if groupNumber < 1:
flash(message, "danger")
return False
return super().validate_form(form)
def after_model_change(self, form, model, is_created):
partLabel = form.new_part_student_part.data
if partLabel != self.partChoices[0]:
groupNumber = int(form.new_part_student_group_number.data)
part = partFromLabelInUserActiveSemester(partLabel)
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")
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")
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
def partQueryFactory():
return Part.query.filter(Part.id.in_([part.id for part in userActiveSemester().parts]))
class PartStudentModelView(SecureModelView):
partLabels = getConfig("partLabels")
column_filters = [PartFilter(PartStudent.part_id, "Part", options=list(zip(partLabels, partLabels)))]
class CreateForm(Form):
def studentQueryFactory():
return Student.query
form_excluded_columns = ["experiment_marks"]
def groupQueryFactory():
return Group.query.filter(Group.part_id.in_([part.id for part in userActiveSemester().parts]))
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="-")
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)
def on_model_change(self, form, model, is_created):
if model.group and model.part != model.group.part:
raise Exception(self.partGroupPartMismatchException)
def handle_view_exception(self, exc):
if exc.args[0] in (self.partGroupPartMismatchException):
pass
else:
return super().handle_view_exception(exc)
def get_query(self):
return super().get_query().filter(PartStudent.part_id.in_([part.id for part in userActiveSemester().parts]))
@ -298,21 +261,62 @@ class PartStudentModelView(SecureModelView):
class GroupModelView(SecureModelView):
partLabels = getConfig("partLabels")
column_filters = [PartFilter(Group.part_id, "Part", options=list(zip(partLabels, partLabels)))]
class CreateForm(Form):
def partStudentsQueryFactory():
return PartStudent.query.filter(PartStudent.part_id.in_([part.id for part in userActiveSemester().parts]))
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)
part = QuerySelectField(
label="Part", query_factory=partQueryFactory, validators=[DataRequired()], allow_blank=True, blank_text="-"
)
part_students = QuerySelectMultipleField(label="Part Students", query_factory=partStudentsQueryFactory)
class EditForm(CreateForm):
part = None
form = EditForm
column_list = ["number", "part", "part_students"]
column_filters = ["part"]
column_searchable_list = ["number"]
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)
def get_query(self):
return super().get_query().filter(Group.part_id.in_([part.id for part in userActiveSemester().parts]))
@ -335,7 +339,7 @@ class PartExperimentModelView(SecureModelView):
column_list = ["experiment", "part", "assistants"]
partLabels = getConfig("partLabels")
column_filters = [PartFilter(PartExperiment.part_id, "Part", options=list(zip(partLabels, partLabels)))]
column_filters = ["part"]
def get_query(self):
return super().get_query().filter(PartExperiment.part_id.in_([part.id for part in userActiveSemester().parts]))