mirror of
https://codeberg.org/Mo8it/AdvLabDB.git
synced 2024-12-20 23:41:20 +00:00
Improved Students, PartStudents and Groups view
This commit is contained in:
parent
5aa408df89
commit
d9eaafeb6d
1 changed files with 110 additions and 106 deletions
|
@ -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]))
|
||||
|
|
Loading…
Reference in a new issue