Loading migrations/versions/f21d6efeef88_.py 0 → 100644 +30 −0 Original line number Original line Diff line number Diff line """empty message Revision ID: f21d6efeef88 Revises: 6347503cdaef Create Date: 2019-03-19 08:51:00.650612 """ from alembic import op import sqlalchemy as sa # revision identifiers, used by Alembic. revision = 'f21d6efeef88' down_revision = '6347503cdaef' branch_labels = None depends_on = None def upgrade(): # ### commands auto generated by Alembic - please adjust! ### op.add_column('project', sa.Column('submit_configurable', sa.Boolean(), nullable=True)) op.add_column('project', sa.Column('submit_instructions', sa.Text(), nullable=True)) # ### end Alembic commands ### def downgrade(): # ### commands auto generated by Alembic - please adjust! ### op.drop_column('project', 'submit_instructions') op.drop_column('project', 'submit_configurable') # ### end Alembic commands ### portal/database/models.py +2 −0 Original line number Original line Diff line number Diff line Loading @@ -453,6 +453,8 @@ class Project(db.Model, EntityBase, NamedMixin): id = db.Column(db.String(length=36), default=lambda: str( id = db.Column(db.String(length=36), default=lambda: str( uuid.uuid4()), primary_key=True) uuid.uuid4()), primary_key=True) assignment_url = db.Column(db.Text) assignment_url = db.Column(db.Text) submit_instructions = db.Column(db.Text, nullable=True) submit_configurable = db.Column(db.Boolean, default=True) config = db.relationship("ProjectConfig", back_populates="project", uselist=False, config = db.relationship("ProjectConfig", back_populates="project", uselist=False, cascade="all, delete-orphan", passive_deletes=True) cascade="all, delete-orphan", passive_deletes=True) Loading portal/facade/submissions_facade.py +3 −1 Original line number Original line Diff line number Diff line Loading @@ -20,7 +20,9 @@ class SubmissionsFacade(GeneralCRUDFacade): f'params: {data}, UA: {self._request.user_agent} ' f'params: {data}, UA: {self._request.user_agent} ' f'({request_helpers.get_ip()})') f'({request_helpers.get_ip()})') user = user or self.client user = user or self.client return super(SubmissionsFacade, self).create(user=user, project=project, **data) allow_override = self.permissions(course=project.course).check.create_submission_other() return super(SubmissionsFacade, self).create(user=user, project=project, allow_override=allow_override, **data) def get_source_files(self, submission: Submission): def get_source_files(self, submission: Submission): service = self.services.storage(submission=submission) service = self.services.storage(submission=submission) Loading portal/rest/schemas.py +4 −2 Original line number Original line Diff line number Diff line Loading @@ -13,7 +13,7 @@ class NestedCollection: ENTITIES = { ENTITIES = { 'Role': ('id', 'codename', 'course.id', 'course.codename'), 'Role': ('id', 'codename', 'course.id', 'course.codename'), 'Group': ('id', 'codename', 'course.id', 'course.codename'), 'Group': ('id', 'codename', 'course.id', 'course.codename'), 'Project': ('id', 'codename', 'course.id', 'state'), 'Project': ('id', 'codename', 'course.id', 'state', 'submit_configurable'), 'Course': ('id', 'codename'), 'Course': ('id', 'codename'), 'User': ('id', 'username', 'uco', 'codename', 'name'), 'User': ('id', 'username', 'uco', 'codename', 'name'), 'Worker': ('id', 'codename', 'name'), 'Worker': ('id', 'codename', 'name'), Loading Loading @@ -171,6 +171,8 @@ class ProjectSchema(BaseSchema, NamedSchema, Schema): """Project Schema """Project Schema """ """ assignment_url = fields.Str(required=False, allow_none=True) assignment_url = fields.Str(required=False, allow_none=True) submit_instructions = fields.Str(required=False, allow_none=True) submit_configurable = fields.Str(required=False, allow_none=True) config = NESTED('ProjectConfig', config = NESTED('ProjectConfig', exclude=('id', '_submissions_allowed_from', exclude=('id', '_submissions_allowed_from', '_submissions_allowed_to', '_archive_from')) '_submissions_allowed_to', '_archive_from')) Loading Loading @@ -412,7 +414,7 @@ class Schemas: 'submission_state': (*ALWAYS_ALLOWED, 'state', 'parameters', 'scheduled_for'), 'submission_state': (*ALWAYS_ALLOWED, 'state', 'parameters', 'scheduled_for'), 'roles': ENT_W_COURSE, 'roles': ENT_W_COURSE, 'groups': ENT_W_COURSE, 'groups': ENT_W_COURSE, 'projects': (*ENT_W_COURSE, 'state'), 'projects': (*ENT_W_COURSE, 'state', 'submit_configurable'), 'course_reduced': (*CODENAME_W_DESC,), 'course_reduced': (*CODENAME_W_DESC,), 'courses': (*CODENAME_W_DESC,), 'courses': (*CODENAME_W_DESC,), 'config_reduced': (*ALWAYS_ALLOWED, 'project', 'submissions_allowed_from', 'config_reduced': (*ALWAYS_ALLOWED, 'project', 'submissions_allowed_from', Loading portal/service/permissions.py +17 −3 Original line number Original line Diff line number Diff line Loading @@ -68,7 +68,7 @@ class PermissionServiceCheck: def read_submissions_all(self) -> bool: def read_submissions_all(self) -> bool: result = self.permissions(['read_submissions_all']) result = self.permissions(['read_submissions_all']) log.debug(f"[TRY] Read Submissions Group for {self.service.submission} " log.debug(f"[TRY] Read sub all for {self.service.submission} " f"by {self.service.auth.client.log_name}: {result}") f"by {self.service.auth.client.log_name}: {result}") return result return result Loading @@ -76,7 +76,7 @@ class PermissionServiceCheck: submission = submission or self.service.submission submission = submission or self.service.submission result = self.read_submissions_all() or self.service.submission_access_group(submission, [ result = self.read_submissions_all() or self.service.submission_access_group(submission, [ 'read_submissions_groups']) 'read_submissions_groups']) log.debug(f"[TRY] Read Submissions Group for {submission.log_name} " log.debug(f"[TRY] Read sub group for {submission.log_name} " f"by {self.service.client_name}: {result}") f"by {self.service.client_name}: {result}") return result return result Loading @@ -84,7 +84,7 @@ class PermissionServiceCheck: submission = submission or self.service.submission submission = submission or self.service.submission result = self.read_submissions_all() or self.permissions( result = self.read_submissions_all() or self.permissions( ['read_submissions_own']) and submission.user == self.service.client_owner ['read_submissions_own']) and submission.user == self.service.client_owner log.debug(f"[TRY] Read Submission Own for {submission.log_name} " log.debug(f"[TRY] Read Sub Own for {submission.log_name} " f"by {self.service.client_name}: {result}") f"by {self.service.client_name}: {result}") return result return result Loading @@ -96,6 +96,17 @@ class PermissionServiceCheck: ] ] return self.any_check(*checks) return self.any_check(*checks) def create_submission(self, user): if user != self.service.client: self.permissions(['create_submissions_other']) from portal.service.services_collection import ServicesCollection user_service = ServicesCollection().permissions(course=self.service.course, client=user) return user_service.check.permissions(['create_submissions']) def create_submission_other(self): return self.permissions(['create_submissions_other']) class PermissionServiceRequire: class PermissionServiceRequire: def __init__(self, service: 'PermissionsService'): def __init__(self, service: 'PermissionsService'): Loading Loading @@ -184,6 +195,9 @@ class PermissionServiceRequire: user_service = ServicesCollection().permissions(course=self.service.course, client=user) user_service = ServicesCollection().permissions(course=self.service.course, client=user) user_service.require.permissions(['create_submissions']) user_service.require.permissions(['create_submissions']) def create_submission_other(self): return self.permissions(['create_submissions_other']) def course_access_token(self): def course_access_token(self): self.permissions(['handle_notes_access_token']) self.permissions(['handle_notes_access_token']) Loading Loading
migrations/versions/f21d6efeef88_.py 0 → 100644 +30 −0 Original line number Original line Diff line number Diff line """empty message Revision ID: f21d6efeef88 Revises: 6347503cdaef Create Date: 2019-03-19 08:51:00.650612 """ from alembic import op import sqlalchemy as sa # revision identifiers, used by Alembic. revision = 'f21d6efeef88' down_revision = '6347503cdaef' branch_labels = None depends_on = None def upgrade(): # ### commands auto generated by Alembic - please adjust! ### op.add_column('project', sa.Column('submit_configurable', sa.Boolean(), nullable=True)) op.add_column('project', sa.Column('submit_instructions', sa.Text(), nullable=True)) # ### end Alembic commands ### def downgrade(): # ### commands auto generated by Alembic - please adjust! ### op.drop_column('project', 'submit_instructions') op.drop_column('project', 'submit_configurable') # ### end Alembic commands ###
portal/database/models.py +2 −0 Original line number Original line Diff line number Diff line Loading @@ -453,6 +453,8 @@ class Project(db.Model, EntityBase, NamedMixin): id = db.Column(db.String(length=36), default=lambda: str( id = db.Column(db.String(length=36), default=lambda: str( uuid.uuid4()), primary_key=True) uuid.uuid4()), primary_key=True) assignment_url = db.Column(db.Text) assignment_url = db.Column(db.Text) submit_instructions = db.Column(db.Text, nullable=True) submit_configurable = db.Column(db.Boolean, default=True) config = db.relationship("ProjectConfig", back_populates="project", uselist=False, config = db.relationship("ProjectConfig", back_populates="project", uselist=False, cascade="all, delete-orphan", passive_deletes=True) cascade="all, delete-orphan", passive_deletes=True) Loading
portal/facade/submissions_facade.py +3 −1 Original line number Original line Diff line number Diff line Loading @@ -20,7 +20,9 @@ class SubmissionsFacade(GeneralCRUDFacade): f'params: {data}, UA: {self._request.user_agent} ' f'params: {data}, UA: {self._request.user_agent} ' f'({request_helpers.get_ip()})') f'({request_helpers.get_ip()})') user = user or self.client user = user or self.client return super(SubmissionsFacade, self).create(user=user, project=project, **data) allow_override = self.permissions(course=project.course).check.create_submission_other() return super(SubmissionsFacade, self).create(user=user, project=project, allow_override=allow_override, **data) def get_source_files(self, submission: Submission): def get_source_files(self, submission: Submission): service = self.services.storage(submission=submission) service = self.services.storage(submission=submission) Loading
portal/rest/schemas.py +4 −2 Original line number Original line Diff line number Diff line Loading @@ -13,7 +13,7 @@ class NestedCollection: ENTITIES = { ENTITIES = { 'Role': ('id', 'codename', 'course.id', 'course.codename'), 'Role': ('id', 'codename', 'course.id', 'course.codename'), 'Group': ('id', 'codename', 'course.id', 'course.codename'), 'Group': ('id', 'codename', 'course.id', 'course.codename'), 'Project': ('id', 'codename', 'course.id', 'state'), 'Project': ('id', 'codename', 'course.id', 'state', 'submit_configurable'), 'Course': ('id', 'codename'), 'Course': ('id', 'codename'), 'User': ('id', 'username', 'uco', 'codename', 'name'), 'User': ('id', 'username', 'uco', 'codename', 'name'), 'Worker': ('id', 'codename', 'name'), 'Worker': ('id', 'codename', 'name'), Loading Loading @@ -171,6 +171,8 @@ class ProjectSchema(BaseSchema, NamedSchema, Schema): """Project Schema """Project Schema """ """ assignment_url = fields.Str(required=False, allow_none=True) assignment_url = fields.Str(required=False, allow_none=True) submit_instructions = fields.Str(required=False, allow_none=True) submit_configurable = fields.Str(required=False, allow_none=True) config = NESTED('ProjectConfig', config = NESTED('ProjectConfig', exclude=('id', '_submissions_allowed_from', exclude=('id', '_submissions_allowed_from', '_submissions_allowed_to', '_archive_from')) '_submissions_allowed_to', '_archive_from')) Loading Loading @@ -412,7 +414,7 @@ class Schemas: 'submission_state': (*ALWAYS_ALLOWED, 'state', 'parameters', 'scheduled_for'), 'submission_state': (*ALWAYS_ALLOWED, 'state', 'parameters', 'scheduled_for'), 'roles': ENT_W_COURSE, 'roles': ENT_W_COURSE, 'groups': ENT_W_COURSE, 'groups': ENT_W_COURSE, 'projects': (*ENT_W_COURSE, 'state'), 'projects': (*ENT_W_COURSE, 'state', 'submit_configurable'), 'course_reduced': (*CODENAME_W_DESC,), 'course_reduced': (*CODENAME_W_DESC,), 'courses': (*CODENAME_W_DESC,), 'courses': (*CODENAME_W_DESC,), 'config_reduced': (*ALWAYS_ALLOWED, 'project', 'submissions_allowed_from', 'config_reduced': (*ALWAYS_ALLOWED, 'project', 'submissions_allowed_from', Loading
portal/service/permissions.py +17 −3 Original line number Original line Diff line number Diff line Loading @@ -68,7 +68,7 @@ class PermissionServiceCheck: def read_submissions_all(self) -> bool: def read_submissions_all(self) -> bool: result = self.permissions(['read_submissions_all']) result = self.permissions(['read_submissions_all']) log.debug(f"[TRY] Read Submissions Group for {self.service.submission} " log.debug(f"[TRY] Read sub all for {self.service.submission} " f"by {self.service.auth.client.log_name}: {result}") f"by {self.service.auth.client.log_name}: {result}") return result return result Loading @@ -76,7 +76,7 @@ class PermissionServiceCheck: submission = submission or self.service.submission submission = submission or self.service.submission result = self.read_submissions_all() or self.service.submission_access_group(submission, [ result = self.read_submissions_all() or self.service.submission_access_group(submission, [ 'read_submissions_groups']) 'read_submissions_groups']) log.debug(f"[TRY] Read Submissions Group for {submission.log_name} " log.debug(f"[TRY] Read sub group for {submission.log_name} " f"by {self.service.client_name}: {result}") f"by {self.service.client_name}: {result}") return result return result Loading @@ -84,7 +84,7 @@ class PermissionServiceCheck: submission = submission or self.service.submission submission = submission or self.service.submission result = self.read_submissions_all() or self.permissions( result = self.read_submissions_all() or self.permissions( ['read_submissions_own']) and submission.user == self.service.client_owner ['read_submissions_own']) and submission.user == self.service.client_owner log.debug(f"[TRY] Read Submission Own for {submission.log_name} " log.debug(f"[TRY] Read Sub Own for {submission.log_name} " f"by {self.service.client_name}: {result}") f"by {self.service.client_name}: {result}") return result return result Loading @@ -96,6 +96,17 @@ class PermissionServiceCheck: ] ] return self.any_check(*checks) return self.any_check(*checks) def create_submission(self, user): if user != self.service.client: self.permissions(['create_submissions_other']) from portal.service.services_collection import ServicesCollection user_service = ServicesCollection().permissions(course=self.service.course, client=user) return user_service.check.permissions(['create_submissions']) def create_submission_other(self): return self.permissions(['create_submissions_other']) class PermissionServiceRequire: class PermissionServiceRequire: def __init__(self, service: 'PermissionsService'): def __init__(self, service: 'PermissionsService'): Loading Loading @@ -184,6 +195,9 @@ class PermissionServiceRequire: user_service = ServicesCollection().permissions(course=self.service.course, client=user) user_service = ServicesCollection().permissions(course=self.service.course, client=user) user_service.require.permissions(['create_submissions']) user_service.require.permissions(['create_submissions']) def create_submission_other(self): return self.permissions(['create_submissions_other']) def course_access_token(self): def course_access_token(self): self.permissions(['handle_notes_access_token']) self.permissions(['handle_notes_access_token']) Loading