예제 #1
0
 def test_save_from_scratch_without_creation_event(self, mock_database):
     """An exception is raised when there is no creation event."""
     mock_database.store_events = mock_store_events
     user = User(12345, '*****@*****.**')
     e2 = UpdateMetadata(creator=user, metadata=[['title', 'foo']])
     with self.assertRaises(NoSuchSubmission):
         save(e2)
예제 #2
0
    def setUp(self):
        """An arXiv user is submitting a new paper."""
        self.submitter = events.domain.User(1234, email='*****@*****.**',
                                            forename='Jane', surname='User')

        # Create and finalize a new submission.
        cc0 = 'http://creativecommons.org/publicdomain/zero/1.0/'
        with self.app.app_context():
            classic.create_all()
            self.submission, _ = events.save(
                events.CreateSubmission(creator=self.submitter),
                events.VerifyContactInformation(creator=self.submitter),
                events.AssertAuthorship(
                    creator=self.submitter,
                    submitter_is_author=True
                ),
                events.SelectLicense(
                    creator=self.submitter,
                    license_uri=cc0,
                    license_name='CC0 1.0'
                ),
                events.AcceptPolicy(creator=self.submitter),
                events.SetPrimaryClassification(
                    creator=self.submitter,
                    category='cs.DL'
                ),
                events.AttachSourceContent(
                    creator=self.submitter,
                    location="https://submit.arxiv.org/upload/123",
                    checksum="a9s9k342900skks03330029k",
                    format='tex',
                    mime_type="application/zip",
                    identifier=123,
                    size=593992
                ),
                events.UpdateMetadata(
                    creator=self.submitter,
                    metadata=[
                        ('title', 'Foo title'),
                        ('abstract', "One morning, as Gregor Samsa was..."),
                        ('comments', '5 pages, 2 turtle doves'),
                        ('report_num', 'asdf1234'),
                        ('doi', '10.01234/56789'),
                        ('journal_ref', 'Foo Rev 1, 2 (1903)')
                    ]
                ),
                events.UpdateAuthors(
                    creator=self.submitter,
                    authors=[events.Author(
                        order=0,
                        forename='Bob',
                        surname='Paulson',
                        email='*****@*****.**',
                        affiliation='Fight Club'
                    )]
                ),
                events.FinalizeSubmission(creator=self.submitter)
            )
예제 #3
0
 def test_create_and_update_authors(self, mock_database):
     """Save multiple events for a nonexistant submission."""
     mock_database.store_events = mock_store_events
     user = User(12345, '*****@*****.**')
     e = CreateSubmission(creator=user)
     e2 = UpdateAuthors(creator=user, authors=[
         Author(0, forename='Joe', surname="Bloggs", email="*****@*****.**")
     ])
     submission, events = save(e, e2)
     self.assertIsInstance(submission.metadata.authors[0], Author)
예제 #4
0
    def test_save_events_on_existing_submission(self, mock_db):
        """Save multiple sets of events in separate calls to :func:`.save`."""
        cache = defaultdict(list)

        def mock_store_events_with_cache(*events, submission):
            if submission.submission_id is None:
                submission.submission_id = 1
            for event in events:
                event.committed = True
                event.submission_id = submission.submission_id
                cache[event.submission_id].append(event)
            return submission

        def mock_get_events(submission_id):
            return cache[submission_id]

        mock_db.store_events = mock_store_events_with_cache
        mock_db.get_events = mock_get_events

        # Here is the first set of events.
        user = User(12345, '*****@*****.**')
        e = CreateSubmission(creator=user)
        e2 = UpdateMetadata(creator=user, metadata=[['title', 'foo']])
        submission, _ = save(e, e2)
        submission_id = submission.submission_id

        # Now we apply a second set of events.
        e3 = UpdateMetadata(creator=user, metadata=[['abstract', 'bar']])
        submission2, _ = save(e3, submission_id=submission_id)

        # The submission state reflects all three events.
        self.assertEqual(submission2.metadata.abstract, 'bar',
                         "State of the submission should reflect both sets"
                         " of events.")
        self.assertEqual(submission2.metadata.title, 'foo',
                         "State of the submission should reflect both sets"
                         " of events.")
        self.assertEqual(submission2.created, e.created,
                         "The creation date of the submission should be the"
                         " original creation date.")
        self.assertEqual(submission2.submission_id, submission_id,
                         "The submission ID should remain the same.")
예제 #5
0
    def test_save_events_from_scratch(self, mock_database):
        """Save multiple events for a nonexistant submission."""
        mock_database.store_events = mock_store_events
        user = User(12345, '*****@*****.**')
        e = CreateSubmission(creator=user)
        e2 = UpdateMetadata(creator=user, metadata=[['title', 'foo']])
        submission, events = save(e, e2)

        self.assertEqual(submission.metadata.title, 'foo')
        self.assertIsInstance(submission.submission_id, int)
        self.assertEqual(submission.created, e.created)
예제 #6
0
 def test_save_creation_event(self, mock_database):
     """A :class:`.CreationEvent` is passed."""
     mock_database.store_events = mock_store_events
     user = User(12345, '*****@*****.**')
     event = CreateSubmission(creator=user)
     submission, events = save(event)
     self.assertIsInstance(submission, Submission,
                           "A submission instance should be returned")
     self.assertIsInstance(events[0], Event,
                           "Should return a list of events")
     self.assertEqual(events[0], event,
                      "The first event should be the event that was passed")
     self.assertIsNotNone(submission.submission_id,
                          "Submission ID should be set.")
예제 #7
0
def create_submission(data: dict, headers: dict, user_data: dict,
                      client_data: dict, token: str) -> Response:
    """
    Create a new submission.

    Implements the hook for :meth:`sword.SWORDCollection.add_submission`.

    Parameters
    ----------
    data : dict
        Deserialized compact JSON-LD document.
    headers : dict
        Request headers from the client.

    Returns
    -------
    dict
        Response data.
    int
        HTTP status code.
    dict
        Headers to add to the response.
    """
    logger.debug('Received request to create submission')
    user, client, proxy = _get_agents(headers, user_data, client_data)
    logger.debug(f'User: {user}; client: {client}, proxy: {proxy}')
    agents = dict(creator=user, client=client, proxy=proxy)
    create = ev.CreateSubmission(creator=user, client=client, proxy=proxy)
    events = handlers.handle_submission(data, agents)
    try:
        submission, events = ev.save(create, *events)
    except (ev.InvalidEvent, ev.InvalidStack) as e:
        raise BadRequest(str(e)) from e
    except ev.SaveError as e:
        logger.error('Problem interacting with database: (%s) %s',
                     str(type(e)), str(e))
        raise InternalServerError('Problem interacting with database') from e

    response_headers = {
        'Location': url_for('submission.get_submission',
                            submission_id=submission.submission_id)
    }
    return submission.to_dict(), status.HTTP_201_CREATED, response_headers
예제 #8
0
def update_submission(data: dict, headers: dict, user_data: dict,
                      client_data: dict, token: str, submission_id: str) \
        -> Response:
    """Update the submission."""
    user, client, proxy = _get_agents(headers, user_data, client_data)
    agents = dict(creator=user, client=client, proxy=proxy)
    events = handlers.handle_submission(data, agents)
    try:
        submission, events = ev.save(*events, submission_id=submission_id)
    except ev.NoSuchSubmission as e:
        raise NotFound(f"No submission found with id {submission_id}")
    except (ev.InvalidEvent, ev.InvalidStack) as e:
        raise BadRequest(str(e)) from e
    except ev.SaveError as e:
        raise InternalServerError('Problem interacting with database') from e

    response_headers = {
        'Location': url_for('submission.get_submission', creator=user,
                            submission_id=submission.submission_id)
    }
    return submission.to_dict(), status.HTTP_200_OK, response_headers
def process_submission(s):
    """Process a submission from a tsvfile row."""
    # TODO: Make sure forename surname separation are better
    try:
        forename, surname = s['submitter_name'].rsplit(maxsplit=1)
    except ValueError:
        forename = ''
        surname = s['submitter_name']
    submitter = events.domain.User(s['submitter_id'],
                                   email=s['submitter_email'],
                                   forename=forename,
                                   surname=surname)

    metadata = [('title', s['title']), ('abstract', s['abstract']),
                ('comments', s['comments']), ('report_num', s['report_num']),
                ('doi', s['doi']), ('journal_ref', s['journal_ref'])]

    submission, stack = events.save(events.CreateSubmission(creator=submitter))

    if s.get('is_author') == '1':
        submission, stack = events.save(events.AssertAuthorship(
            creator=submitter, submitter_is_author=True),
                                        submission_id=submission.submission_id)
    else:
        submission, stack = events.save(events.AssertAuthorship(
            creator=submitter, submitter_is_author=False),
                                        submission_id=submission.submission_id)

    if s.get('agree_policy') == '1':
        submission, stack = events.save(events.AcceptPolicy(creator=submitter),
                                        submission_id=submission.submission_id)

    if s.get('userinfo') == '1':
        submission, stack = events.save(
            events.VerifyContactInformation(creator=submitter),
            submission_id=submission.submission_id)

    submission, stack = events.save(
        events.UpdateAuthors(authors_display=s['authors'], creator=submitter),
        events.UpdateMetadata(creator=submitter, metadata=metadata),
        events.SetPrimaryClassification(creator=submitter,
                                        category=s['category']),
        submission_id=submission.submission_id)

    # Parse the license
    license_uri = s.get('license')
    if license_uri:
        submission, stack = events.save(events.SelectLicense(
            creator=submitter, license_uri=license_uri),
                                        submission_id=submission.submission_id)

    if s.get('package'):
        submission, stack = events.save(events.AttachSourceContent(
            location='https://example.arxiv.org/' + s['package'],
            format=s['source_format'],
            checksum='0',
            identifier=1,
            creator=submitter),
                                        submission_id=submission.submission_id)

    if s.get('status') not in INVALID_STATUSES:
        submission, stack = events.save(
            events.FinalizeSubmission(creator=submitter),
            submission_id=submission.submission_id)

    return submission.submission_id
예제 #10
0
    def test_classic_workflow(self, submitter=None, metadata=None, authors=None):
        """Submitter proceeds through workflow in a linear fashion."""

        # Instantiate objects that have not yet been instantiated or use defaults.
        if submitter is None:
            submitter = self.submitter

        if metadata is None:
            metadata = [
                ('title', 'Foo title'),
                ('abstract', "One morning, as Gregor Samsa was waking up..."),
                ('comments', '5 pages, 2 turtle doves'),
                ('report_num', 'asdf1234'),
                ('doi', '10.01234/56789'),
                ('journal_ref', 'Foo Rev 1, 2 (1903)')
            ]


        # TODO: Process data in dictionary form to events.Author objects.
        if authors is None:
            authors = [events.Author(order=0,
                                     forename='Bob',
                                     surname='Paulson',
                                     email='*****@*****.**',
                                     affiliation='Fight Club'
                        )]

        with in_memory_db() as session:
            # Submitter clicks on 'Start new submission' in the user dashboard.
            submission, stack = events.save(
                events.CreateSubmission(creator=submitter)
            )
            self.assertIsNotNone(submission.submission_id,
                                 "A submission ID is assigned")
            self.assertEqual(len(stack), 1, "A single command is executed.")

            db_submission = session.query(classic.models.Submission)\
                .get(submission.submission_id)
            self.assertEqual(db_submission.submission_id,
                             submission.submission_id,
                             "A row is added to the submission table")
            self.assertEqual(db_submission.submitter_id,
                             submitter.native_id,
                             "Submitter ID set on submission")
            self.assertEqual(db_submission.submitter_email,
                             submitter.email,
                             "Submitter email set on submission")
            self.assertEqual(db_submission.submitter_name, submitter.name,
                             "Submitter name set on submission")
            self.assertEqual(db_submission.created, submission.created,
                             "Creation datetime set correctly")

            # TODO: What else to check here?

            # /start: Submitter completes the start submission page.
            license_uri = 'http://creativecommons.org/publicdomain/zero/1.0/'
            submission, stack = events.save(
                events.VerifyContactInformation(creator=submitter),
                events.AssertAuthorship(
                    creator=submitter,
                    submitter_is_author=True
                ),
                events.SelectLicense(
                    creator=submitter,
                    license_uri=license_uri,
                    license_name='CC0 1.0'
                ),
                events.AcceptPolicy(creator=submitter),
                events.SetPrimaryClassification(
                    creator=submitter,
                    category='cs.DL'
                ),
                submission_id=submission.submission_id
            )
            self.assertEqual(len(stack), 6,
                             "Six commands have been executed in total.")

            db_submission = session.query(classic.models.Submission)\
                .get(submission.submission_id)
            self.assertEqual(db_submission.userinfo, 1,
                             "Contact verification set correctly in database.")
            self.assertEqual(db_submission.is_author, 1,
                             "Authorship status set correctly in database.")
            self.assertEqual(db_submission.license, license_uri,
                             "License set correctly in database.")
            self.assertEqual(db_submission.agree_policy, 1,
                             "Policy acceptance set correctly in database.")
            self.assertEqual(len(db_submission.categories), 1,
                             "A single category is associated in the database")
            self.assertEqual(db_submission.categories[0].is_primary, 1,
                             "Primary category is set correct in the database")
            self.assertEqual(db_submission.categories[0].category, 'cs.DL',
                             "Primary category is set correct in the database")

            # /addfiles: Submitter has uploaded files to the file management
            # service, and verified that they compile. Now they associate the
            # content package with the submission.
            submission, stack = events.save(
                events.AttachSourceContent(
                    creator=submitter,
                    location="https://submit.arxiv.org/upload/123",
                    checksum="a9s9k342900skks03330029k",
                    format='tex',
                    mime_type="application/zip",
                    identifier=123,
                    size=593992
                ),
                submission_id=submission.submission_id
            )

            self.assertEqual(len(stack), 7,
                             "Seven commands have been executed in total.")
            db_submission = session.query(classic.models.Submission)\
                .get(submission.submission_id)
            self.assertEqual(db_submission.must_process, 0,
                             "Processing status is set correctly in database")
            self.assertEqual(db_submission.source_size, 593992,
                             "Source package size set correctly in database")
            self.assertEqual(db_submission.source_format, 'tex',
                             "Source format set correctly in database")

            # /metadata: Submitter adds metadata to their submission, including
            # authors. In this package, we model authors in more detail than
            # in the classic system, but we should preserve the canonical
            # format in the db for legacy components' sake.
            submission, stack = events.save(
                events.UpdateMetadata(
                    creator=submitter,
                    metadata=metadata
                ),
                events.UpdateAuthors(
                    creator=submitter,
                    authors=authors
                ),
                submission_id=submission.submission_id
            )
            db_submission = session.query(classic.models.Submission)\
                .get(submission.submission_id)
            self.assertEqual(db_submission.title, dict(metadata)['title'],
                             "Title updated as expected in database")
            self.assertEqual(db_submission.abstract,
                             dict(metadata)['abstract'],
                             "Abstract updated as expected in database")
            self.assertEqual(db_submission.comments,
                             dict(metadata)['comments'],
                             "Comments updated as expected in database")
            self.assertEqual(db_submission.report_num,
                             dict(metadata)['report_num'],
                             "Report number updated as expected in database")
            self.assertEqual(db_submission.doi, dict(metadata)['doi'],
                             "DOI updated as expected in database")
            self.assertEqual(db_submission.journal_ref,
                             dict(metadata)['journal_ref'],
                             "Journal ref updated as expected in database")

            author_str = ';'.join([f"{author.forename} {author.surname} ({author.affiliation})"
                                      for author in authors])
            self.assertEqual(db_submission.authors,
                             author_str,
                             "Authors updated in canonical format in database")

            self.assertEqual(len(stack), 9,
                             "Nine commands have been executed in total.")

            # /preview: Submitter adds a secondary classification.
            submission, stack = events.save(
                events.AddSecondaryClassification(
                    creator=submitter,
                    category='cs.IR'
                ),
                submission_id=submission.submission_id
            )
            db_submission = session.query(classic.models.Submission)\
                .get(submission.submission_id)

            self.assertEqual(len(db_submission.categories), 2,
                             "A secondary category is added in the database")
            secondaries = [
                db_cat for db_cat in db_submission.categories
                if db_cat.is_primary == 0
            ]
            self.assertEqual(len(secondaries), 1,
                             "A secondary category is added in the database")
            self.assertEqual(secondaries[0].category, 'cs.IR',
                             "A secondary category is added in the database")
            self.assertEqual(len(stack), 10,
                             "Ten commands have been executed in total.")

            # /preview: Submitter finalizes submission.
            finalize = events.FinalizeSubmission(creator=submitter)
            submission, stack = events.save(
                finalize, submission_id=submission.submission_id
            )
            db_submission = session.query(classic.models.Submission)\
                .get(submission.submission_id)

            self.assertEqual(db_submission.status, db_submission.SUBMITTED,
                             "Submission status set correctly in database")
            self.assertEqual(db_submission.submit_time, finalize.created,
                             "Submit time is set.")
            self.assertEqual(len(stack), 11,
                             "Eleven commands have been executed in total.")