From 1441ec2ad54e460c739ec68f5068c4e3cc195198 Mon Sep 17 00:00:00 2001
From: Jorran de Wit <jorrandewit@outlook.com>
Date: Thu, 31 Aug 2017 20:56:14 +0200
Subject: [PATCH] iThenticate ready for action

---
 requirements.txt          |  2 +-
 submissions/exceptions.py |  4 ++
 submissions/forms.py      | 43 +++++-------------
 submissions/plagiarism.py | 95 +++++++++++++++++++++++++++++++++++++++
 4 files changed, 111 insertions(+), 33 deletions(-)
 create mode 100644 submissions/plagiarism.py

diff --git a/requirements.txt b/requirements.txt
index 1998b0de2..a10c22acc 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -43,7 +43,7 @@ Whoosh==2.7.4  # Directly related to Haystack.
 
 
 # Python Utils
-ithenticate-api-python==0.4.2
+ithenticate-api-python==0.6
 mailchimp3==2.0.15
 python-dateutil==2.6.0  # Doesn't Django have this functionality built-in?  -- JdW
 Pillow==3.4.2  # Latest version is v4.2.1; need to know about usage before upgrade. -- JdW
diff --git a/submissions/exceptions.py b/submissions/exceptions.py
index 474d3b343..d52fa4fa0 100644
--- a/submissions/exceptions.py
+++ b/submissions/exceptions.py
@@ -16,3 +16,7 @@ class InvalidReportVettingValue(BaseCustomException):
 
 class ArxivPDFNotFound(Exception):
     pass
+
+
+class InvalidDocumentError(Exception):
+    pass
diff --git a/submissions/forms.py b/submissions/forms.py
index 33d4ebb5d..a76a6ccb5 100644
--- a/submissions/forms.py
+++ b/submissions/forms.py
@@ -722,35 +722,14 @@ class iThenticateReportForm(forms.ModelForm):
         return None
 
     def upload_document(self):
-        client = self.client
-
-        # Get first folder available
-        # TODO: Fix this ugly piece of crap
-        if settings.ITHENTICATE_DEFAULT_FOLDER_ID:
-            folder_id = settings.ITHENTICATE_DEFAULT_FOLDER_ID
-        else:
-            folders = client.folders.all()
-            if folders['status'] == 200:
-                folder_id = folders['data'][0]['id']
-            else:
-                self.add_error(None, "Uploading failed. iThenticate didn't return valid data [2]")
-                self.add_error(None, client.messages[0])
-
-        # Finally, upload the file
-        author = self.submission.authors.first()
-        response = client.documents.add(
-            self.document,
-            folder_id,
-            author.user.first_name,
-            author.user.last_name,
-            self.submission.title,
-        )
-
-        if response['status'] == 200:
-            self.submission.add_general_event(('The document has been submitted '
-                                               'for a plagiarism check.'))
-            return response
-
-        self.add_error(None, "Updating failed. iThenticate didn't return valid data [3]")
-        self.add_error(None, client.messages[0])
-        return None
+        from .plagiarism import iThenticate
+        plagiarism = iThenticate()
+        response = plagiarism.upload_submission(self.document, self.submission)
+
+        # Give feedback to the user
+        if not response:
+            self.add_error(None, "Updating failed. iThenticate didn't return valid data [3]")
+            for msg in plagiarism.get_messages():
+                self.add_error(None, msg)
+            return None
+        return response
diff --git a/submissions/plagiarism.py b/submissions/plagiarism.py
new file mode 100644
index 000000000..28d445457
--- /dev/null
+++ b/submissions/plagiarism.py
@@ -0,0 +1,95 @@
+from django.conf import settings
+
+from .exceptions import InvalidDocumentError
+
+import iThenticate as iThenticateAPI
+
+
+class iThenticate:
+    def __init__(self):
+        self.client = self.get_client()
+
+    def get_client(self):
+        client = iThenticateAPI.API.Client(settings.ITHENTICATE_USERNAME,
+                                           settings.ITHENTICATE_PASSWORD)
+        if client.login():
+            return client
+        self.add_error(None, "Failed to login to iThenticate.")
+        return None
+
+    def determine_folder_group(self, group_re):
+        groups = self.client.groups.all()
+        if groups['status'] != 200:
+            raise InvalidDocumentError("Uploading failed. iThenticate didn't return"
+                                       " valid data [4]: %s" % self.client.messages[0])
+
+        for group in groups['data']:
+            # Found the group
+            if group['name'] == group_re:
+                return group['id']
+
+        # Create a new group
+        response = self.client.groups.add(group_re)
+
+        if response['status'] != 200:
+            raise InvalidDocumentError("Failed creating a new Folder Group [5].")
+
+        return response['data'][0]['id']
+
+    def determine_folder_id(self, submission):
+        """
+        Return the folder id to which the system should upload a new document to.
+
+        Generates a new folder and id if needed.
+        """
+        group_re = '{journal}_submissions'.format(journal=submission.submitted_to_journal)
+        folder_re = '{year}_{month}'.format(
+            year=submission.submission_date.year,
+            month=submission.submission_date.month
+        )
+        all_folders = self.client.folders.all()
+        if all_folders['status'] != 200:
+            raise InvalidDocumentError("Uploading failed. iThenticate didn't return"
+                                       " valid data [2]: %s" % self.client.messages[0])
+
+        # Iterate folders as the api doesn't allow for a search
+        for folder in all_folders['data']:
+            # Found right folder!
+            if folder['name'] == folder_re and folder['group']['name']:
+                return folder['id']
+
+        group_id = self.determine_folder_group(group_re)
+
+        # Create new folder
+        data = self.client.folders.add(group_id, folder_re)
+        if data['status'] != 200:
+            raise InvalidDocumentError("Failed to create a new folder [3].")
+
+        return data['data'][0]['id']
+
+    def upload_submission(self, document, submission):
+        """
+        Upload a document related to a submission
+
+        :document: The document to upload
+        :submission: submission which should be uploaded
+        """
+        folder_id = self.determine_folder_id(submission)
+
+        # Finally, upload the file
+        author = submission.authors.first()
+        response = self.client.documents.add(
+            document,
+            folder_id,
+            author.user.first_name,
+            author.user.last_name,
+            submission.title,
+        )
+
+        if response['status'] == 200:
+            submission.add_general_event('The document has been submitted for a plagiarism check.')
+            return response
+        return None
+
+    def get_messages(self):
+        return self.client.messages
-- 
GitLab