Loading portal/database/models.py +4 −5 Original line number Diff line number Diff line """ Models module where all of the models are specified """ import copy import logging import uuid from pathlib import Path Loading Loading @@ -819,8 +819,8 @@ class Submission(db.Model, EntityBase): uuid.uuid4()), primary_key=True) scheduled_for = db.Column(db.TIMESTAMP(timezone=True)) parameters = db.Column(JSONEncodedDict(), nullable=True) note = db.Column(JSONEncodedDict(), nullable=True) state = db.Column(db.Enum(SubmissionState, name='SubmissionState'), nullable=False) note = db.Column(JSONEncodedDict()) source_hash = db.Column(db.String(64)) user_id = db.Column(db.String(36), db.ForeignKey('user.id', ondelete='cascade'), nullable=False, index=True) Loading Loading @@ -869,12 +869,11 @@ class Submission(db.Model, EntityBase): if self.state not in allow: return False self.state = new_state self.make_change(dict(state=new_state, message=message)) self.make_change(dict(state=new_state.name, message=message)) return True def make_change(self, change): if self.note is None: self.note = {} self.note = copy.deepcopy(self.note or {}) if 'changes' not in self.note: self.note['changes'] = [] self.note['changes'].append(change) Loading portal/database/types.py +17 −3 Original line number Diff line number Diff line Loading @@ -3,11 +3,19 @@ from enum import Enum import sqlalchemy import yaml from sqlalchemy import TypeDecorator from sqlalchemy import TypeDecorator, String from sqlalchemy.sql import operators class JSONEncodedDict(TypeDecorator): "Represents an immutable structure as a json-encoded string." """Represents an immutable structure as a json-encoded string.""" def process_literal_param(self, value, dialect): return self.process_bind_param(value, dialect) @property def python_type(self): return dict impl = sqlalchemy.Text Loading @@ -21,9 +29,15 @@ class JSONEncodedDict(TypeDecorator): value = json.loads(value) return value def coerce_compared_value(self, op, value): if op in (operators.like_op, operators.notlike_op): return String() else: return self class YAMLEncodedDict(TypeDecorator): "Represents an immutable structure as a yaml-encoded string." """Represents an immutable structure as a yaml-encoded string.""" impl = sqlalchemy.Text Loading portal/service/general.py +1 −0 Original line number Diff line number Diff line Loading @@ -112,6 +112,7 @@ class GeneralService: log.trace(f"[WRITE] Entity {entity.__class__.__name__}: {entity}") self.db_session.add(entity) self.db_session.commit() return entity def delete_entity(self, entity): """Deletes an entity from the database. Loading portal/service/submissions.py +1 −0 Original line number Diff line number Diff line Loading @@ -217,6 +217,7 @@ class SubmissionsService(GeneralService): def set_state(self, state: Union[str, SubmissionState], message: str = None): if isinstance(state, str): state = SubmissionState[state] if self.submission.change_state(state, message=message): self.write_entity(self.submission) log.info(f"[UPDATE] Submission state {self.submission.log_name} " Loading tests/service/conftest.py +26 −0 Original line number Diff line number Diff line import pytest @pytest.fixture def admin_user(app, portal_services): return portal_services.find.user('admin') @pytest.fixture def student_user(app, portal_services): return portal_services.find.user('student1') @pytest.fixture def teacher_user(app, portal_services): return portal_services.find.user('teacher1') @pytest.fixture def course(app, portal_services): return portal_services.find.course('testcourse1') @pytest.fixture def project(app, portal_services, course): return portal_services.find.project(course, 'hw01') Loading
portal/database/models.py +4 −5 Original line number Diff line number Diff line """ Models module where all of the models are specified """ import copy import logging import uuid from pathlib import Path Loading Loading @@ -819,8 +819,8 @@ class Submission(db.Model, EntityBase): uuid.uuid4()), primary_key=True) scheduled_for = db.Column(db.TIMESTAMP(timezone=True)) parameters = db.Column(JSONEncodedDict(), nullable=True) note = db.Column(JSONEncodedDict(), nullable=True) state = db.Column(db.Enum(SubmissionState, name='SubmissionState'), nullable=False) note = db.Column(JSONEncodedDict()) source_hash = db.Column(db.String(64)) user_id = db.Column(db.String(36), db.ForeignKey('user.id', ondelete='cascade'), nullable=False, index=True) Loading Loading @@ -869,12 +869,11 @@ class Submission(db.Model, EntityBase): if self.state not in allow: return False self.state = new_state self.make_change(dict(state=new_state, message=message)) self.make_change(dict(state=new_state.name, message=message)) return True def make_change(self, change): if self.note is None: self.note = {} self.note = copy.deepcopy(self.note or {}) if 'changes' not in self.note: self.note['changes'] = [] self.note['changes'].append(change) Loading
portal/database/types.py +17 −3 Original line number Diff line number Diff line Loading @@ -3,11 +3,19 @@ from enum import Enum import sqlalchemy import yaml from sqlalchemy import TypeDecorator from sqlalchemy import TypeDecorator, String from sqlalchemy.sql import operators class JSONEncodedDict(TypeDecorator): "Represents an immutable structure as a json-encoded string." """Represents an immutable structure as a json-encoded string.""" def process_literal_param(self, value, dialect): return self.process_bind_param(value, dialect) @property def python_type(self): return dict impl = sqlalchemy.Text Loading @@ -21,9 +29,15 @@ class JSONEncodedDict(TypeDecorator): value = json.loads(value) return value def coerce_compared_value(self, op, value): if op in (operators.like_op, operators.notlike_op): return String() else: return self class YAMLEncodedDict(TypeDecorator): "Represents an immutable structure as a yaml-encoded string." """Represents an immutable structure as a yaml-encoded string.""" impl = sqlalchemy.Text Loading
portal/service/general.py +1 −0 Original line number Diff line number Diff line Loading @@ -112,6 +112,7 @@ class GeneralService: log.trace(f"[WRITE] Entity {entity.__class__.__name__}: {entity}") self.db_session.add(entity) self.db_session.commit() return entity def delete_entity(self, entity): """Deletes an entity from the database. Loading
portal/service/submissions.py +1 −0 Original line number Diff line number Diff line Loading @@ -217,6 +217,7 @@ class SubmissionsService(GeneralService): def set_state(self, state: Union[str, SubmissionState], message: str = None): if isinstance(state, str): state = SubmissionState[state] if self.submission.change_state(state, message=message): self.write_entity(self.submission) log.info(f"[UPDATE] Submission state {self.submission.log_name} " Loading
tests/service/conftest.py +26 −0 Original line number Diff line number Diff line import pytest @pytest.fixture def admin_user(app, portal_services): return portal_services.find.user('admin') @pytest.fixture def student_user(app, portal_services): return portal_services.find.user('student1') @pytest.fixture def teacher_user(app, portal_services): return portal_services.find.user('teacher1') @pytest.fixture def course(app, portal_services): return portal_services.find.course('testcourse1') @pytest.fixture def project(app, portal_services, course): return portal_services.find.project(course, 'hw01')