Verified Commit 6fc4b042 authored by Peter Stanko's avatar Peter Stanko
Browse files

Ability to disable parameters for submission

parent c485f895
Pipeline #30103 passed with stage
in 3 minutes and 29 seconds
"""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 ###
......@@ -453,6 +453,8 @@ class Project(db.Model, EntityBase, NamedMixin):
id = db.Column(db.String(length=36), default=lambda: str(
uuid.uuid4()), primary_key=True)
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,
cascade="all, delete-orphan", passive_deletes=True)
......
......@@ -20,7 +20,9 @@ class SubmissionsFacade(GeneralCRUDFacade):
f'params: {data}, UA: {self._request.user_agent} '
f'({request_helpers.get_ip()})')
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):
service = self.services.storage(submission=submission)
......
......@@ -13,7 +13,7 @@ class NestedCollection:
ENTITIES = {
'Role': ('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'),
'User': ('id', 'username', 'uco', 'codename', 'name'),
'Worker': ('id', 'codename', 'name'),
......@@ -171,6 +171,8 @@ class ProjectSchema(BaseSchema, NamedSchema, Schema):
"""Project Schema
"""
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',
exclude=('id', '_submissions_allowed_from',
'_submissions_allowed_to', '_archive_from'))
......@@ -412,7 +414,7 @@ class Schemas:
'submission_state': (*ALWAYS_ALLOWED, 'state', 'parameters', 'scheduled_for'),
'roles': ENT_W_COURSE,
'groups': ENT_W_COURSE,
'projects': (*ENT_W_COURSE, 'state'),
'projects': (*ENT_W_COURSE, 'state', 'submit_configurable'),
'course_reduced': (*CODENAME_W_DESC,),
'courses': (*CODENAME_W_DESC,),
'config_reduced': (*ALWAYS_ALLOWED, 'project', 'submissions_allowed_from',
......
......@@ -68,7 +68,7 @@ class PermissionServiceCheck:
def read_submissions_all(self) -> bool:
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}")
return result
......@@ -76,7 +76,7 @@ class PermissionServiceCheck:
submission = submission or self.service.submission
result = self.read_submissions_all() or self.service.submission_access_group(submission, [
'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}")
return result
......@@ -84,7 +84,7 @@ class PermissionServiceCheck:
submission = submission or self.service.submission
result = self.read_submissions_all() or self.permissions(
['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}")
return result
......@@ -96,6 +96,17 @@ class PermissionServiceCheck:
]
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:
def __init__(self, service: 'PermissionsService'):
......@@ -184,6 +195,9 @@ class PermissionServiceRequire:
user_service = ServicesCollection().permissions(course=self.service.course, client=user)
user_service.require.permissions(['create_submissions'])
def create_submission_other(self):
return self.permissions(['create_submissions_other'])
def course_access_token(self):
self.permissions(['handle_notes_access_token'])
......
......@@ -4,6 +4,7 @@ Submissions service
import datetime
import json
import logging
from copy import deepcopy
from pathlib import Path
from celery.result import AsyncResult
......@@ -62,12 +63,26 @@ class SubmissionsService(GeneralService):
def storage_results(self):
return self.storage.results.get(self.submission.id)
def create(self, user: User = None, project: Project = None, submission_params: dict = None):
def _configure_sub_params(self, user: User, project: Project, params: dict):
if not project.submit_configurable:
return params
updated_params = deepcopy(params)
gitlab_base = self._config.get("GITLAB_BASE_DOMAIN")
course_code = project.course.codename
updated_params['file_params'] = dict(
from_dir=project.codename,
source={'type': 'git', 'url': f'git@{gitlab_base}:{user.username}/{course_code}.git'}
)
return updated_params
def create(self, user: User = None, project: Project = None, submission_params: dict = None,
allow_override=False):
"""Creates a new submission in the database and downloads its files.
Zip and git sources are processed differently.
Args:
allow_override: Whether override is possible
user(User): the submission's author
project(Project): the project the submission falls under
submission_params(dict): custom parameters specified by
......@@ -81,6 +96,10 @@ class SubmissionsService(GeneralService):
log.info(f"[SUBMIT] Create new submission for user {user.log_name} "
f"for project {project.log_name} "
f"with params: {submission_params}")
if not allow_override:
submission_params = self._configure_sub_params(
user=user, project=project, params=submission_params
)
new_submission = Submission(
user=user, project=project, parameters=submission_params)
self.write_entity(new_submission)
......
......@@ -281,7 +281,7 @@ def test_create_submission_as_with_default_params(client, ent_mocker, rest_servi
assert submission.course == course
assert submission.user == user
assert submission.parameters['file_params']['from_dir'] == project.codename
gitlab_url = f'git@gitlab.local/{user.username}/{course.codename}'
gitlab_url = f'git@gitlab.fi.muni.cz:{user.username}/{course.codename}.git'
assert submission.parameters['file_params']['source']['url'] == gitlab_url
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment