From c54e906ca93447ffb254a2644a12e524bc2438bd Mon Sep 17 00:00:00 2001
From: Peter Stanko <peter.stanko0@gmail.com>
Date: Mon, 20 Aug 2018 12:54:39 +0200
Subject: [PATCH] Submission tree support

---
 portal/async_celery/tasks.py  |  5 +++
 portal/rest/submissions.py    | 68 ++++++++++++++++++++++++++++++++++-
 portal/service/submissions.py |  6 ++++
 3 files changed, 78 insertions(+), 1 deletion(-)

diff --git a/portal/async_celery/tasks.py b/portal/async_celery/tasks.py
index ab5ee02..9fe50d7 100644
--- a/portal/async_celery/tasks.py
+++ b/portal/async_celery/tasks.py
@@ -5,6 +5,8 @@ from celery.utils.log import get_task_logger
 from portal import storage
 from portal.async_celery import celery_app
 from portal.async_celery.storage import submission_store_ended
+from portal.database import SubmissionState
+from portal.service import general
 from portal.service.general import find_submission
 
 log = get_task_logger(__name__)
@@ -29,6 +31,9 @@ def upload_results_to_storage(new_submission_id: str, path: str):
         f"[ASYNC] Uploading result for the submission {new_submission.id} with {file_params}")
     entity = storage.results.create(entity_id=new_submission.id, **file_params)
     Path(path).unlink()
+    new_submission.state = SubmissionState.FINISHED
+    general.write_entity(new_submission)
+
 
 
 @celery_app.task(name='clone-submission-files')
diff --git a/portal/rest/submissions.py b/portal/rest/submissions.py
index 73a1a0b..7c876d4 100644
--- a/portal/rest/submissions.py
+++ b/portal/rest/submissions.py
@@ -1,5 +1,6 @@
 import logging
 
+import flask
 from flask_jwt_extended import jwt_required
 from flask_restplus import Namespace, Resource
 
@@ -10,7 +11,8 @@ from portal.service import auth, general, permissions
 from portal.service.permissions import check_client, require_client
 from portal.service.reviews import create_review, create_review_items
 from portal.service.submissions import copy_submission, delete_submission, \
-    update_submission_state, cancel_submission, send_file_or_zip, upload_results_to_storage
+    update_submission_state, cancel_submission, send_file_or_zip, upload_results_to_storage, \
+    send_files_tree
 
 submissions_namespace = Namespace('submissions')
 
@@ -119,6 +121,28 @@ class SubmissionFiles(Resource):
         raise NotImplementedError()
 
 
+@submissions_namespace.route('/<string:sid>/files/sources/tree')
+@submissions_namespace.doc({'sid': 'Submission id'})
+@submissions_namespace.response(404, 'Submissions not found')
+class SubmissionSourcesTree(Resource):
+    @jwt_required
+    def get(self, sid: str):
+        client = auth.find_client()
+        submission = general.find_submission(sid)
+        course = submission.project.course
+        # authorization
+        checks = [
+            check_client(client, course, ['read_submissions_all']),
+            submission_access_group(client, submission, course, [
+                'read_submissions_groups']),
+            (check_client(client, course, [
+                'read_submissions_own']) and submission.user == client)
+            ]
+        permissions.require_any_check(client, checks=checks)
+        storage_submission = storage.submissions.get(submission.id)
+        return send_files_tree(storage_submission)
+
+
 @submissions_namespace.route('/<string:sid>/files/sources')
 @submissions_namespace.param('sid', 'Submission id')
 @submissions_namespace.response(404, 'Submissions not found')
@@ -141,8 +165,29 @@ class SubmissionSourceFiles(Resource):
         return send_file_or_zip(storage_submission)
 
 
+@submissions_namespace.route('/<string:sid>/files/test_files/tree')
+@submissions_namespace.doc({'sid': 'Submission id'})
+@submissions_namespace.response(404, 'Submissions not found')
+class SubmissionTestFilesTree(Resource):
+    @jwt_required
+    def get(self, sid: str):
+        client = auth.find_client()
+        submission = general.find_submission(sid)
+        course = submission.project.course
+        # authorization
+        checks = [
+            check_client(client, course, ['read_submissions_all']),
+            submission_access_group(client, submission, course, [
+                'read_submissions_groups'])
+            ]
+        permissions.require_any_check(client, checks=checks)
+        storage_entity = storage.test_files.get(submission.project.id)
+        return send_files_tree(storage_entity)
+
+
 @submissions_namespace.route('/<string:sid>/files/test_files')
 @submissions_namespace.doc({'sid': 'Submission id'})
+@submissions_namespace.response(404, 'Submissions not found')
 class SubmissionTestFiles(Resource):
     @jwt_required
     def get(self, sid: str):
@@ -160,6 +205,27 @@ class SubmissionTestFiles(Resource):
         return send_file_or_zip(storage_entity)
 
 
+@submissions_namespace.route('/<string:sid>/files/results/tree')
+@submissions_namespace.param('sid', 'Submission id')
+@submissions_namespace.response(404, 'Submissions not found')
+class SubmissionResultFilesTree(Resource):
+    @jwt_required
+    def get(self, sid: str):
+        client = auth.find_client()
+        submission = general.find_submission(sid)
+        course = submission.project.course
+        # authorization
+        checks = [
+            check_client(client, course, ['read_submissions_all']),
+            submission_access_group(client, submission, course, [
+                'read_submissions_groups'])
+            ]
+        permissions.require_any_check(client, checks=checks)
+        storage_entity = storage.results.get(submission.id)
+        tree = send_files_tree(storage_entity)
+        return flask.jsonify(tree), 200
+
+
 @submissions_namespace.route('/<string:sid>/files/results')
 @submissions_namespace.param('sid', 'Submission id')
 @submissions_namespace.response(404, 'Submissions not found')
diff --git a/portal/service/submissions.py b/portal/service/submissions.py
index 3cf52ce..8c987e8 100644
--- a/portal/service/submissions.py
+++ b/portal/service/submissions.py
@@ -168,6 +168,12 @@ def send_file_or_zip(storage_entity):
     return send_selected_file(storage_entity, path_query)
 
 
+def send_files_tree(storage_entity):
+    tree = storage_entity.tree()
+    log.debug(f"[TREE] Tree for the storage entity {storage_entity.entity_id}: {tree} ")
+    return tree
+
+
 def upload_file_is_allowed(file):
     extension = Path(file.filename).suffix
     log.debug(f"[ZIP] Extension for {file.filename}: {extension}")
-- 
GitLab