diff --git a/advlabdb/__init__.py b/advlabdb/__init__.py index a06b21c..c8a52a3 100644 --- a/advlabdb/__init__.py +++ b/advlabdb/__init__.py @@ -18,6 +18,8 @@ app.config["SECRET_KEY"] = "dev" app.config["SECURITY_PASSWORD_SALT"] = "devSalt" # os.environ.get("SECURITY_PASSWORD_SALT", "") app.config["SQLALCHEMY_DATABASE_URI"] = "sqlite:///../advLab.db" +app.config["SQLALCHEMY_TRACK_MODIFICATIONS"] = False + db = SQLAlchemy(app) fsqla.FsModels.set_db_info(db) diff --git a/advlabdb/customClasses.py b/advlabdb/customClasses.py index d2e8801..7713e1d 100644 --- a/advlabdb/customClasses.py +++ b/advlabdb/customClasses.py @@ -3,7 +3,7 @@ from flask_admin.contrib.sqla import ModelView from flask_security import current_user from flask import redirect, request, url_for, flash -from advlabdb.exceptions import ModelViewValidatorException +from advlabdb.exceptions import ModelViewException, DataBaseException def adminViewIsAccessible(): @@ -53,7 +53,7 @@ class SecureModelView(ModelView): return super().get_count_query() def handle_view_exception(self, exc): - if type(exc) == ModelViewValidatorException: + if type(exc) in (ModelViewException, DataBaseException): flash(str(exc), "error") return True diff --git a/advlabdb/exceptions.py b/advlabdb/exceptions.py index da95330..28d6a3d 100644 --- a/advlabdb/exceptions.py +++ b/advlabdb/exceptions.py @@ -1,2 +1,6 @@ -class ModelViewValidatorException(Exception): +class ModelViewException(Exception): + pass + + +class DataBaseException(Exception): pass diff --git a/advlabdb/modelViews.py b/advlabdb/modelViews.py index 2839c52..857e02a 100644 --- a/advlabdb/modelViews.py +++ b/advlabdb/modelViews.py @@ -34,7 +34,7 @@ from advlabdb.utils import ( setUserActiveSemester, userActiveSemester, ) -from advlabdb.exceptions import ModelViewValidatorException +from advlabdb.exceptions import ModelViewException class UserView(SecureModelView): @@ -79,11 +79,11 @@ class UserView(SecureModelView): def on_model_delete(self, model): if model == current_user: - raise ModelViewValidatorException("Tried to delete yourself as user!") + raise ModelViewException("Tried to delete yourself as user!") def on_model_change(self, form, model, is_created): if model == current_user and not form.active.data: - raise ModelViewValidatorException("Tried to deactiavte yourself as user!") + raise ModelViewException("Tried to deactiavte yourself as user!") class RoleView(SecureModelView): @@ -262,7 +262,7 @@ class PartStudentView(SecureModelView): def on_model_change(self, form, model, is_created): if model.group and model.part != model.group.part: - raise ModelViewValidatorException("Student's part and group's part do not match!") + raise ModelViewException("Student's part and group's part do not match!") def update_model(self, form, model): if form.final_part_mark.data == -1: @@ -312,10 +312,10 @@ class GroupView(SecureModelView): 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 ModelViewValidatorException("Group's part and student's part do not match!") + def update_model(self, form, model): + Group.checkPartStudents(form.part_students.data) + + return super().update_model(form, model) def create_form(self, obj=None): form = self.CreateForm diff --git a/advlabdb/models.py b/advlabdb/models.py index 0ac3f39..3891da3 100644 --- a/advlabdb/models.py +++ b/advlabdb/models.py @@ -13,6 +13,7 @@ from flask_security.models.fsqla_v2 import FsRoleMixin, FsUserMixin # Importing the database instance from advlabdb import db from advlabdb.configUtils import getConfig +from advlabdb.exceptions import DataBaseException class Student(db.Model): @@ -68,14 +69,27 @@ class Group(db.Model): number = db.Column(db.Integer, db.CheckConstraint("number > 0"), nullable=False) semester_id = db.Column(db.Integer, db.ForeignKey("semester.id"), nullable=False) - program_id = db.Column(db.Integer, db.ForeignKey("program.id", nullable=False)) + program_id = db.Column(db.Integer, db.ForeignKey("program.id"), nullable=False) part_students = db.relationship("PartStudent", backref="group", lazy=True) group_experiments = db.relationship("GroupExperiment", backref="group", lazy=True) __table_args__ = (db.UniqueConstraint(number, semester_id, program_id),) + def checkPartStudents(partStudents): + if partStudents: + program = partStudents[0].part.program + semester = partStudents[0].part.semester + for partStudent in partStudents[1:]: + if partStudent.part.program != program: + raise DataBaseException(f"Part Students {partStudents} are not in the same program!") + + if partStudent.part.semester != semester: + raise DataBaseException(f"Part Students {partStudents} are not in the same semester!") + def customInit(semester, program, partStudents): + checkPartStudents(partStudents) + orderedGroups = Group.query.filter(Group.semester == semester, Group.program == program).order_by(Group.number) lastTakenGroupNumber = orderedGroups[-1].number if orderedPartGroups.count() > 0 else 0 @@ -295,7 +309,7 @@ class Part(db.Model): class Semester(db.Model): id = db.Column(db.Integer, primary_key=True) label = db.Column(db.String(10), nullable=False) - year = db.Column(db.Integer, db.CheckConstraint("year > 0"), db.CheckConstraint("year < 100"), nullalbe=False) + year = db.Column(db.Integer, db.CheckConstraint("year > 0"), db.CheckConstraint("year < 100"), nullable=False) parts = db.relationship("Part", backref="semester", lazy=True) semester_experiments = db.relationship("SemesterExperiment", backref="semester", lazy=True) @@ -364,6 +378,7 @@ class Role(db.Model, FsRoleMixin): class Program(db.Model): + id = db.Column(db.Integer, primary_key=True) label = db.Column(db.String(25), nullable=False) parts = db.relationship("Part", backref="program", lazy=True) diff --git a/testDB.py b/testDB.py index 39d3e9c..00ddf11 100644 --- a/testDB.py +++ b/testDB.py @@ -9,26 +9,34 @@ with app.app_context(): db.drop_all() db.create_all() - sem1 = Semester(label="WS2021") - sem2 = Semester(label="SS21") + program1 = Program(label="BS") + program2 = Program(label="MS") + program3 = Program(label="BE") + + db.session.add(program1) + db.session.add(program2) + db.session.add(program3) + + sem1 = Semester(label="WS", year=21) + sem2 = Semester(label="SS", year=21) db.session.add(sem1) db.session.add(sem2) partKwargs = [ - {"label": "BS", "number": 1}, - {"label": "BS", "number": 2}, - {"label": "BE", "number": 1}, - {"label": "MS", "number": 1}, - {"label": "MS", "number": 2}, + {"program": program1, "number": 1}, + {"program": program1, "number": 2}, + {"program": program2, "number": 1}, + {"program": program2, "number": 2}, + {"program": program3, "number": 1}, ] for kwargs in partKwargs: db.session.add(Part(semester=sem1, **kwargs)) sem2.transferPartsFrom(sem1) - parta1 = sem2.parts[0] - partb2 = sem2.parts[1] + part1 = sem2.parts[0] + part2 = sem2.parts[2] student1 = Student(student_number=123, first_name="Mo", last_name="Bit", uni_email="m@test.com") student2 = Student(student_number=1232, first_name="Mo2", last_name="Bit", uni_email="m2@test.com") @@ -38,22 +46,23 @@ with app.app_context(): db.session.add(student2) db.session.add(student3) - g1 = Group(number=1, part=parta1) - g2 = Group(number=2, part=partb2) + g1 = Group(number=1, program=program1) + g2 = Group(number=1, program=program2) db.session.add(g1) db.session.add(g2) - ps1 = PartStudent(student=student1, part=parta1, group=g1) - ps2 = PartStudent(student=student2, part=parta1, group=g1) - ps3 = PartStudent(student=student3, part=partb2, group=g2) + ps1 = PartStudent(student=student1, part=part1, group=g1) + ps2 = PartStudent(student=student2, part=part1, group=g1) + ps3 = PartStudent(student=student3, part=part2, group=g2) db.session.add(ps1) db.session.add(ps2) db.session.add(ps3) ex1 = Experiment( - label="B1", + number=1, + program=program1, title="exp", room="123", building="phy", @@ -65,7 +74,8 @@ with app.app_context(): ) ex2 = Experiment( - label="B2", + number=1, + program=program2, title="exp2", room="123", building="phy",