Exemple #1
0
    def delete(cls, id, account, dry_run=False):
        # as long as authentication (in the layer above) has been successful, and the account exists, then
        # we are good to proceed
        if account is None:
            raise Api401Error()

        applicationService = DOAJ.applicationService()
        authService = DOAJ.authorisationService()

        if dry_run:
            application, _ = applicationService.application(id)
            if application is not None:
                try:
                    authService.can_edit_application(account, application)
                except AuthoriseException as e:
                    if e.reason == e.WRONG_STATUS:
                        raise Api403Error()
                    raise Api404Error()
            else:
                raise Api404Error()
        else:
            try:
                applicationService.delete_application(id, account)
            except AuthoriseException as e:
                if e.reason == e.WRONG_STATUS:
                    raise Api403Error()
                raise Api404Error()
            except NoSuchObjectException as e:
                raise Api404Error()
Exemple #2
0
    def test_02_get_application(self, name, application, application_id, account, lock_application, raises=None):
        if lock_application:
            lock.lock(constants.LOCK_APPLICATION, application.id, "someoneelse", blocking=True)

        svc = DOAJ.applicationService()

        if application is not None:
            application.save(blocking=True)

        if raises is not None:
            with self.assertRaises(raises):
                if account is None:
                    retrieved, _ = svc.application(application_id)
                else:
                    retrieved, jlock = svc.application(application_id, lock_application=True, lock_account=account)
        else:
            if account is None:
                retrieved, _ = svc.application(application_id)
                if retrieved is not None:
                    assert retrieved.data == application.data
                else:
                    assert retrieved is None
            else:
                retrieved, jlock = svc.application(application_id, lock_application=True, lock_account=account)
                if retrieved is not None:
                    assert retrieved.data == application.data
                else:
                    assert retrieved is None

                time.sleep(2)

                assert lock.has_lock(constants.LOCK_APPLICATION, application_id, account.id)
Exemple #3
0
    def delete(cls, id, account, dry_run=False):
        # as long as authentication (in the layer above) has been successful, and the account exists, then
        # we are good to proceed
        if account is None:
            raise Api401Error()

        applicationService = DOAJ.applicationService()
        authService = DOAJ.authorisationService()

        if dry_run:
            application, _ = applicationService.application(id)
            if application is not None:
                try:
                    authService.can_edit_application(account, application)
                except AuthoriseException as e:
                    if e.reason == e.WRONG_STATUS:
                        raise Api403Error()
                    raise Api404Error()
            else:
                raise Api404Error()
        else:
            try:
                applicationService.delete_application(id, account)
            except AuthoriseException as e:
                if e.reason == e.WRONG_STATUS:
                    raise Api403Error()
                raise Api404Error()
            except NoSuchObjectException as e:
                raise Api404Error()
Exemple #4
0
def update_request_readonly(application_id):
    # DOAJ BLL for this request
    applicationService = DOAJ.applicationService()
    authService = DOAJ.authorisationService()

    application, _ = applicationService.application(application_id)
    try:
        authService.can_view_application(current_user._get_current_object(),
                                         application)
    except AuthoriseException as e:
        abort(404)

    fc = formcontext.ApplicationFormFactory.get_form_context(
        role="update_request_readonly", source=application)
    return fc.render_template(no_sidebar=True)
Exemple #5
0
    def update(cls, id, data, account):
        # as long as authentication (in the layer above) has been successful, and the account exists, then
        # we are good to proceed
        if account is None:
            raise Api401Error()

        # next thing to do is a structural validation of the replacement data, by instantiating the object
        try:
            ia = IncomingApplication(data)
        except dataobj.DataStructureException as e:
            raise Api400Error(e.message)

        # now see if there's something for us to update
        ap = models.Suggestion.pull(id)
        if ap is None:
            raise Api404Error()

        # if that works, convert it to a Suggestion object
        new_ap = ia.to_application_model()

        # now augment the suggestion object with all the additional information it requires
        #
        # suggester name and email from the user account
        new_ap.set_suggester(account.name, account.email)

        # they are not allowed to set "subject"
        new_ap.bibjson().remove_subjects()

        # DOAJ BLL for this request
        applicationService = DOAJ.applicationService()
        authService = DOAJ.authorisationService()

        # if a current_journal is specified on the incoming data
        if new_ap.current_journal is not None:
            # once an application has a current_journal specified, you can't change it
            if new_ap.current_journal != ap.current_journal:
                raise Api400Error(
                    "current_journal cannot be changed once set.  current_journal is {x}; this request tried to change it to {y}"
                    .format(x=ap.current_journal, y=new_ap.current_journal))

            # load the update_request application either directly or by crosswalking the journal object
            vanilla_ap = None
            jlock = None
            alock = None
            try:
                vanilla_ap, jlock, alock = applicationService.update_request_for_journal(
                    new_ap.current_journal, account=account)
            except AuthoriseException as e:
                if e.reason == AuthoriseException.WRONG_STATUS:
                    raise Api403Error(
                        "The application is no longer in a state in which it can be edited via the API"
                    )
                else:
                    raise Api404Error()
            except lock.Locked as e:
                raise Api409Error(
                    "The application is locked for editing by another user - most likely your application is being reviewed by an editor"
                )

            # if we didn't find an application or journal, 404 the user
            if vanilla_ap is None:
                if jlock is not None: jlock.delete()
                if alock is not None: alock.delete()
                raise Api404Error()

            # convert the incoming application into the web form
            form = MultiDict(xwalk.SuggestionFormXWalk.obj2form(new_ap))

            fc = formcontext.ApplicationFormFactory.get_form_context(
                role="publisher", form_data=form, source=vanilla_ap)
            if fc.validate():
                try:
                    fc.finalise(email_alert=False)
                    return fc.target
                except formcontext.FormContextException as e:
                    raise Api400Error(e.message)
                finally:
                    if jlock is not None: jlock.delete()
                    if alock is not None: alock.delete()
            else:
                if jlock is not None: jlock.delete()
                if alock is not None: alock.delete()
                raise Api400Error(cls._validation_message(fc))
        else:
            try:
                authService.can_edit_application(account, ap)
            except AuthoriseException as e:
                if e.reason == e.WRONG_STATUS:
                    raise Api403Error(
                        "The application is no longer in a state in which it can be edited via the API"
                    )
                else:
                    raise Api404Error()

            # convert the incoming application into the web form
            form = MultiDict(xwalk.SuggestionFormXWalk.obj2form(new_ap))

            fc = formcontext.ApplicationFormFactory.get_form_context(
                form_data=form, source=ap)
            if fc.validate():
                try:
                    fc.finalise(email_alert=False)
                    return fc.target
                except formcontext.FormContextException as e:
                    raise Api400Error(e.message)
            else:
                raise Api400Error(cls._validation_message(fc))
Exemple #6
0
def update_request(journal_id):
    # DOAJ BLL for this request
    journalService = DOAJ.journalService()
    applicationService = DOAJ.applicationService()

    # if this is a delete request, deal with it first and separately from the below logic
    if request.method == "DELETE":
        journal, _ = journalService.journal(journal_id)
        application_id = journal.current_application
        if application_id is not None:
            applicationService.delete_application(
                application_id, current_user._get_current_object())
        else:
            abort(404)
        return ""

    # load the application either directly or by crosswalking the journal object
    application = None
    jlock = None
    alock = None
    try:
        application, jlock, alock = applicationService.update_request_for_journal(
            journal_id, account=current_user._get_current_object())
    except AuthoriseException as e:
        if e.reason == AuthoriseException.WRONG_STATUS:
            journal, _ = journalService.journal(journal_id)
            return render_template(
                "publisher/application_already_submitted.html",
                journal=journal)
        else:
            abort(404)
    except lock.Locked as e:
        journal, _ = journalService.journal(journal_id)
        return render_template("publisher/locked.html",
                               journal=journal,
                               lock=e.lock)

    # if we didn't find an application or journal, 404 the user
    if application is None:
        if jlock is not None: jlock.delete()
        if alock is not None: alock.delete()
        abort(404)

    # if we have a live application and cancel was hit, then cancel the operation and redirect
    # first determine if this is a cancel request on the form
    cancelled = request.values.get("cancel")
    if cancelled is not None:
        if jlock is not None: jlock.delete()
        if alock is not None: alock.delete()
        return redirect(url_for("publisher.updates_in_progress"))

    # if we are requesting the page with a GET, we just want to show the form
    if request.method == "GET":
        fc = formcontext.ApplicationFormFactory.get_form_context(
            role="publisher", source=application)
        return fc.render_template(edit_suggestion_page=True)

    # if we are requesting the page with a POST, we need to accept the data and handle it
    elif request.method == "POST":
        fc = formcontext.ApplicationFormFactory.get_form_context(
            role="publisher", form_data=request.form, source=application)
        if fc.validate():
            try:
                fc.finalise()
                Messages.flash(Messages.APPLICATION_UPDATE_SUBMITTED_FLASH)
                for a in fc.alert:
                    Messages.flash_with_url(a, "success")
                return redirect(url_for("publisher.updates_in_progress"))
            except formcontext.FormContextException as e:
                Messages.flash(e.message)
                return redirect(
                    url_for("publisher.update_request",
                            journal_id=journal_id,
                            _anchor='cannot_edit'))
            finally:
                if jlock is not None: jlock.delete()
                if alock is not None: alock.delete()
        else:
            return fc.render_template(edit_suggestion_page=True)
    def test_01_accept_application(self, name, application_type, account_type, manual_update, provenance, raises, result_provenance, result_manual_update):

        ###############################################
        ## set up

        # create the application
        application = None
        if application_type == "save_fail":
            application = Suggestion(**ApplicationFixtureFactory.make_application_source())
            application.save = mock_save
            Journal.save = mock_save
        elif application_type == "with_current_journal":
            application = Suggestion(**ApplicationFixtureFactory.make_application_source())
            application.remove_notes()
            application.add_note("unique 1", "2002-01-01T00:00:00Z")
            application.add_note("duplicate", "2001-01-01T00:00:00Z")
            cj = application.current_journal
            journal = Journal(**JournalFixtureFactory.make_journal_source())
            journal.set_id(cj)
            journal.remove_notes()
            journal.add_note("unique 2", "2003-01-01T00:00:00Z")
            journal.add_note("duplicate", "2001-01-01T00:00:00Z")
            journal.save(blocking=True)
        elif application_type == "no_current_journal":
            application = Suggestion(**ApplicationFixtureFactory.make_application_source())
            application.remove_current_journal()


        acc = None
        if account_type == "not_allowed":
            acc = Account(**AccountFixtureFactory.make_publisher_source())
        elif account_type == "allowed":
            acc = Account(**AccountFixtureFactory.make_managing_editor_source())

        mu = None
        if manual_update in ["true", "false"]:
            mu = manual_update == "true"

        prov = None
        if provenance in ["true", "false"]:
            prov = provenance == "true"

        save = bool(randint(0,1))

        ###########################################################
        # Execution

        svc = DOAJ.applicationService()
        if raises != "":
            with self.assertRaises(EXCEPTIONS[raises]):
                svc.accept_application(application, acc, mu, prov)
        else:
            journal = svc.accept_application(application, acc, mu, prov, save_journal=save, save_application=save)

            # we need to sleep, so the index catches up
            time.sleep(1)

            # check a few common things
            assert application.application_status == constants.APPLICATION_STATUS_ACCEPTED
            assert application.current_journal is None
            assert journal.current_application is None
            assert application.related_journal == journal.id

            related = journal.related_applications
            if application_type == "with_current_journal":
                assert len(related) == 3
            elif application_type == "no_current_journal":
                assert len(related) == 1
            assert related[0].get("application_id") == application.id
            assert related[0].get("date_accepted") is not None

            if result_manual_update == "yes":
                assert journal.last_manual_update is not None
                assert journal.last_manual_update != "1970-01-01T00:00:00Z"
                assert application.last_manual_update is not None
                assert application.last_manual_update != "1970-01-01T00:00:00Z"
            elif result_manual_update == "no":
                assert journal.last_manual_update is None
                assert application.last_manual_update is None

            if application_type == "with_current_journal":
                assert len(journal.notes) == 3
                notevals = [note.get("note") for note in journal.notes]
                assert "duplicate" in notevals
                assert "unique 1" in notevals
                assert "unique 2" in notevals

            app_prov = Provenance.get_latest_by_resource_id(application.id)
            if result_provenance == "yes":
                assert app_prov is not None
            elif result_provenance == "no":
                assert app_prov is None

            if save:
                pass
    def test_01_reject_application(self, name, application, application_status, account, prov, current_journal, note, save, raises=None):

        #######################################
        ## set up

        if save == "fail":
            Suggestion.save = mock_save_fail

        ap = None
        journal = None
        if application == "exists":
            ap = Suggestion(**ApplicationFixtureFactory.make_application_source())
            ap.set_application_status(application_status)
            ap.set_id(ap.makeid())
            ap.remove_notes()
            if current_journal == "yes":
                journal = Journal(**JournalFixtureFactory.make_journal_source(in_doaj=True))
                journal.set_id(journal.makeid())
                journal.set_current_application(ap.id)
                journal.save(blocking=True)
                ap.set_current_journal(journal.id)
            else:
                ap.remove_current_journal()

        acc = None
        if account == "publisher":
            acc = Account(**AccountFixtureFactory.make_publisher_source())
        elif account == "admin":
            acc = Account(**AccountFixtureFactory.make_managing_editor_source())

        provenance = None
        if prov != "none":
            provenance = prov == "true"

        thenote = None
        if note == "yes":
            thenote = "abcdefg"

        ########################################
        ## execute

        svc = DOAJ.applicationService()
        if raises is not None and raises != "":
            with self.assertRaises(EXCEPTIONS[raises]):
                svc.reject_application(ap, acc, provenance, note=thenote)
        else:
            svc.reject_application(ap, acc, provenance, note=thenote)
            time.sleep(1)

            #######################################
            ## Check

            ap2 = Suggestion.pull(ap.id)
            assert ap2 is not None
            assert ap2.application_status == constants.APPLICATION_STATUS_REJECTED
            assert ap2.current_journal is None

            # check the updated and manually updated date are essentially the same (they can theoretically differ
            # by a small amount just based on when they are set)
            updated_spread = abs((ap2.last_updated_timestamp - ap2.last_manual_update_timestamp).total_seconds())
            assert updated_spread <= 1.0

            if current_journal == "yes" and journal is not None:
                j2 = Journal.pull(journal.id)
                assert j2 is not None
                assert j2.current_application is None
                assert ap2.related_journal == j2.id

            if prov == "true":
                pr = Provenance.get_latest_by_resource_id(ap.id)
                assert pr is not None

            if note == "yes":
                assert len(ap2.notes) == 1
                assert ap2.notes[0].get("note") == "abcdefg"
            elif note == "no":
                assert len(ap2.notes) == 0
Exemple #9
0
    def test_01_delete_application(self, name, application_type, account_type,
                                   current_journal, related_journal, raises):

        ###############################################
        ## set up

        # create the test application (if needed), and the associated current_journal and related_journal in suitable states
        application = None
        cj = None
        rj = None
        if application_type == "found" or application_type == "locked":
            application = Suggestion(
                **ApplicationFixtureFactory.make_application_source())

            if current_journal == "none":
                application.remove_current_journal()
            elif current_journal == "not_found":
                application.set_current_journal("123456789987654321")
            elif current_journal == "found":
                cj = Journal(**JournalFixtureFactory.make_journal_source())
                cj.set_id(cj.makeid())
                cj.save(blocking=True)
                application.set_current_journal(cj.id)
            elif current_journal == "locked":
                cj = Journal(**JournalFixtureFactory.make_journal_source())
                cj.set_id(cj.makeid())
                cj.save(blocking=True)
                application.set_current_journal(cj.id)
                lock.lock(constants.LOCK_JOURNAL, cj.id, "otheruser")

            if related_journal == "none":
                application.remove_related_journal()
            elif related_journal == "not_found":
                application.set_related_journal("123456789987654321")
            elif related_journal == "found":
                rj = Journal(**JournalFixtureFactory.make_journal_source())
                rj.set_id(rj.makeid())
                rj.save(blocking=True)
                application.set_related_journal(rj.id)
            elif related_journal == "locked":
                rj = Journal(**JournalFixtureFactory.make_journal_source())
                rj.set_id(rj.makeid())
                rj.save(blocking=True)
                application.set_related_journal(rj.id)
                lock.lock(constants.LOCK_JOURNAL, rj.id, "otheruser")

        acc = None
        if account_type != "none":
            acc = Account(**AccountFixtureFactory.make_publisher_source())
            if account_type == "not_permitted":
                acc.remove_role("publisher")
            if application_type == "locked":
                thelock = lock.lock(constants.LOCK_APPLICATION, application.id,
                                    "otheruser")
                # we can't explicitly block on the lock, but we can halt until we confirm it is saved
                thelock.blockall([(thelock.id, thelock.last_updated)])

        application_id = None
        if application is not None:
            if acc is not None:
                application.set_owner(acc.id)
            application.save(blocking=True)
            application_id = application.id
        elif application_type == "not_found":
            application_id = "sdjfasofwefkwflkajdfasjd"

        ###########################################################
        # Execution

        svc = DOAJ.applicationService()
        if raises != "":
            with self.assertRaises(EXCEPTIONS[raises]):
                svc.delete_application(application_id, acc)
            time.sleep(1)
            check_locks(application, cj, rj, acc)
        else:
            svc.delete_application(application_id, acc)

            # we need to sleep, so the index catches up
            time.sleep(1)

            # check that no locks remain set for this user
            check_locks(application, cj, rj, acc)

            # check that the application actually is gone
            if application is not None:
                assert Suggestion.pull(application.id) is None

            # check that the current journal no longer has a reference to the application
            if cj is not None:
                cj = Journal.pull(cj.id)
                assert cj.current_application is None

            # check that the related journal has a record that the application was deleted
            if rj is not None:
                rj = Journal.pull(rj.id)
                record = rj.related_application_record(application.id)
                assert "status" in record
                assert record["status"] == "deleted"
Exemple #10
0
    def test_01_reject_application(self,
                                   name,
                                   application,
                                   application_status,
                                   account,
                                   prov,
                                   current_journal,
                                   note,
                                   save,
                                   raises=None):

        #######################################
        ## set up

        if save == "fail":
            Suggestion.save = mock_save_fail

        ap = None
        journal = None
        if application == "exists":
            ap = Suggestion(
                **ApplicationFixtureFactory.make_application_source())
            ap.set_application_status(application_status)
            ap.set_id(ap.makeid())
            ap.remove_notes()
            if current_journal == "yes":
                journal = Journal(**JournalFixtureFactory.make_journal_source(
                    in_doaj=True))
                journal.set_id(journal.makeid())
                journal.set_current_application(ap.id)
                journal.save(blocking=True)
                ap.set_current_journal(journal.id)
            else:
                ap.remove_current_journal()

        acc = None
        if account == "publisher":
            acc = Account(**AccountFixtureFactory.make_publisher_source())
        elif account == "admin":
            acc = Account(
                **AccountFixtureFactory.make_managing_editor_source())

        provenance = None
        if prov != "none":
            provenance = prov == "true"

        thenote = None
        if note == "yes":
            thenote = "abcdefg"

        ########################################
        ## execute

        svc = DOAJ.applicationService()
        if raises is not None and raises != "":
            with self.assertRaises(EXCEPTIONS[raises]):
                svc.reject_application(ap, acc, provenance, note=thenote)
        else:
            svc.reject_application(ap, acc, provenance, note=thenote)
            time.sleep(1)

            #######################################
            ## Check

            ap2 = Suggestion.pull(ap.id)
            assert ap2 is not None
            assert ap2.application_status == constants.APPLICATION_STATUS_REJECTED
            assert ap2.current_journal is None

            # check the updated and manually updated date are essentially the same (they can theoretically differ
            # by a small amount just based on when they are set)
            updated_spread = abs(
                (ap2.last_updated_timestamp -
                 ap2.last_manual_update_timestamp).total_seconds())
            assert updated_spread <= 1.0

            if current_journal == "yes" and journal is not None:
                j2 = Journal.pull(journal.id)
                assert j2 is not None
                assert j2.current_application is None
                assert ap2.related_journal == j2.id

            if prov == "true":
                pr = Provenance.get_latest_by_resource_id(ap.id)
                assert pr is not None

            if note == "yes":
                assert len(ap2.notes) == 1
                assert ap2.notes[0].get("note") == "abcdefg"
            elif note == "no":
                assert len(ap2.notes) == 0
    def test_01_update_request(self, name, journal_id, journal_lock, account,
                               account_role, account_is_owner,
                               current_applications, application_lock,
                               application_status, completed_applications,
                               raises, return_app, return_jlock, return_alock,
                               db_jlock, db_alock, db_app):

        ###############################################
        ## set up

        # create the journal
        journal = None
        jid = None
        if journal_id == "valid":
            journal = Journal(**JournalFixtureFactory.make_journal_source(
                in_doaj=True))
            journal.remove_related_applications()
            journal.remove_current_application()
            jid = journal.id
        elif journal_id == "not_in_doaj":
            journal = Journal(**JournalFixtureFactory.make_journal_source(
                in_doaj=False))
            journal.remove_related_applications()
            journal.remove_current_application()
            jid = journal.id
        elif journal_id == "missing":
            jid = uuid.uuid4().hex

        acc = None
        if account == "yes":
            acc = Account(**AccountFixtureFactory.make_publisher_source())
            if account_role == "none":
                acc.remove_role("publisher")
            elif account_role == "admin":
                acc.remove_role("publisher")
                acc.add_role("admin")
            acc.set_id(acc.makeid())
            if account_is_owner == "yes":
                acc.set_id(journal.owner)

        if journal_lock == "yes":
            lock.lock("journal", jid, "someoneelse", blocking=True)

        latest_app = None
        current_app_count = int(current_applications)
        for i in range(current_app_count):
            app = Suggestion(
                **ApplicationFixtureFactory.make_application_source())
            app.set_id(app.makeid())
            app.set_created("198" + str(i) + "-01-01T00:00:00Z")
            app.set_current_journal(jid)
            app.save()
            latest_app = app
            if journal is not None:
                journal.set_current_application(app.id)

        comp_app_count = int(completed_applications)
        for i in range(comp_app_count):
            app = Suggestion(
                **ApplicationFixtureFactory.make_application_source())
            app.set_id(app.makeid())
            app.set_created("197" + str(i) + "-01-01T00:00:00Z")
            app.set_related_journal(jid)
            app.save()
            if journal is not None:
                journal.add_related_application(app.id,
                                                date_accepted=app.created_date)

        if current_app_count == 0 and comp_app_count == 0:
            # save at least one record to initialise the index mapping, otherwise tests fail
            app = Suggestion(
                **ApplicationFixtureFactory.make_application_source())
            app.set_id(app.makeid())
            app.save()

        if application_lock == "yes":
            lock.lock("suggestion",
                      latest_app.id,
                      "someoneelse",
                      blocking=True)

        if application_status != "n/a":
            latest_app.set_application_status(application_status)
            latest_app.save(blocking=True)

        # finally save the journal record, ensuring we get a blocking save, so everything
        # above here should be synchronised with the repo
        if journal is not None:
            journal.save(blocking=True)

        ###########################################################
        # Execution

        svc = DOAJ.applicationService()
        if raises != "":
            with self.assertRaises(EXCEPTIONS[raises]):
                svc.update_request_for_journal(jid, acc)
        else:
            application, jlock, alock = svc.update_request_for_journal(
                jid, acc)

            # we need to sleep, so the index catches up
            time.sleep(1)

            if return_app == "none":
                assert application is None
            elif return_app == "yes":
                assert application is not None

            if return_jlock == "none":
                assert jlock is None
            elif return_jlock == "yes":
                assert jlock is not None

            if return_alock == "none":
                assert alock is None
            elif return_alock == "yes":
                assert alock is not None

            if db_jlock == "no" and acc is not None:
                assert not lock.has_lock("journal", jid, acc.id)
            elif db_jlock == "yes" and acc is not None:
                l = lock.has_lock("journal", jid, acc.id)
                assert lock.has_lock("journal", jid, acc.id)

            if db_alock == "no" and application.id is not None and acc is not None:
                assert not lock.has_lock("suggestion", application.id, acc.id)
            elif db_alock == "yes" and application.id is not None and acc is not None:
                assert lock.has_lock("suggestion", application.id, acc.id)

            if db_app == "no" and application.id is not None:
                indb = Suggestion.q2obj(q="id.exact:" + application.id)
                assert indb is None
            elif db_app == "yes" and application.id is not None:
                indb = Suggestion.q2obj(q="id.exact:" + application.id)
                assert indb is not None

            if current_app_count == 0 and comp_app_count == 0 and application is not None:
                assert application.article_metadata is None
                assert application.articles_last_year is None
            elif application is not None:
                assert application.article_metadata is not None
                assert application.articles_last_year is not None
    def test_01_delete_application(self, name, application_type, account_type, current_journal, related_journal, raises):

        ###############################################
        ## set up

        # create the test application (if needed), and the associated current_journal and related_journal in suitable states
        application = None
        cj = None
        rj = None
        if application_type == "found" or application_type == "locked":
            application = Suggestion(**ApplicationFixtureFactory.make_application_source())

            if current_journal == "none":
                application.remove_current_journal()
            elif current_journal == "not_found":
                application.set_current_journal("123456789987654321")
            elif current_journal == "found":
                cj = Journal(**JournalFixtureFactory.make_journal_source())
                cj.set_id(cj.makeid())
                cj.save(blocking=True)
                application.set_current_journal(cj.id)
            elif current_journal == "locked":
                cj = Journal(**JournalFixtureFactory.make_journal_source())
                cj.set_id(cj.makeid())
                cj.save(blocking=True)
                application.set_current_journal(cj.id)
                lock.lock(constants.LOCK_JOURNAL, cj.id, "otheruser")

            if related_journal == "none":
                application.remove_related_journal()
            elif related_journal == "not_found":
                application.set_related_journal("123456789987654321")
            elif related_journal == "found":
                rj = Journal(**JournalFixtureFactory.make_journal_source())
                rj.set_id(rj.makeid())
                rj.save(blocking=True)
                application.set_related_journal(rj.id)
            elif related_journal == "locked":
                rj = Journal(**JournalFixtureFactory.make_journal_source())
                rj.set_id(rj.makeid())
                rj.save(blocking=True)
                application.set_related_journal(rj.id)
                lock.lock(constants.LOCK_JOURNAL, rj.id, "otheruser")


        acc = None
        if account_type != "none":
            acc = Account(**AccountFixtureFactory.make_publisher_source())
            if account_type == "not_permitted":
                acc.remove_role("publisher")
            if application_type == "locked":
                thelock = lock.lock(constants.LOCK_APPLICATION, application.id, "otheruser")
                # we can't explicitly block on the lock, but we can halt until we confirm it is saved
                thelock.blockall([(thelock.id, thelock.last_updated)])

        application_id = None
        if application is not None:
            if acc is not None:
                application.set_owner(acc.id)
            application.save(blocking=True)
            application_id = application.id
        elif application_type == "not_found":
            application_id = u"sdjfasofwefkwflkajdfasjd"

        ###########################################################
        # Execution

        svc = DOAJ.applicationService()
        if raises != "":
            with self.assertRaises(EXCEPTIONS[raises]):
                svc.delete_application(application_id, acc)
            time.sleep(1)
            check_locks(application, cj, rj, acc)
        else:
            svc.delete_application(application_id, acc)

            # we need to sleep, so the index catches up
            time.sleep(1)

            # check that no locks remain set for this user
            check_locks(application, cj, rj, acc)

            # check that the application actually is gone
            if application is not None:
                assert Suggestion.pull(application.id) is None

            # check that the current journal no longer has a reference to the application
            if cj is not None:
                cj = Journal.pull(cj.id)
                assert cj.current_application is None

            # check that the related journal has a record that the application was deleted
            if rj is not None:
                rj = Journal.pull(rj.id)
                record = rj.related_application_record(application.id)
                assert "status" in record
                assert record["status"] == "deleted"
Exemple #13
0
    def create(cls, data, account, dry_run=False):
        # as long as authentication (in the layer above) has been successful, and the account exists, then
        # we are good to proceed
        if account is None:
            raise Api401Error()

        # first thing to do is a structural validation, but instantiating the data object
        try:
            ia = IncomingApplication(data)
        except dataobj.DataStructureException as e:
            raise Api400Error(e.message)

        # if that works, convert it to a Suggestion object
        ap = ia.to_application_model()

        # now augment the suggestion object with all the additional information it requires
        #
        # suggester name and email from the user account
        ap.set_suggester(account.name, account.email)

        # they are not allowed to set "subject"
        ap.bibjson().remove_subjects()

        # if this is an update request on an existing journal
        if ap.current_journal is not None:
            # DOAJ BLL for this request
            applicationService = DOAJ.applicationService()

            # load the update_request application either directly or by crosswalking the journal object
            vanilla_ap = None
            jlock = None
            alock = None
            try:
                vanilla_ap, jlock, alock = applicationService.update_request_for_journal(ap.current_journal, account=account)
            except AuthoriseException as e:
                if e.reason == AuthoriseException.WRONG_STATUS:
                    raise Api403Error("The application is no longer in a state in which it can be edited via the API")
                else:
                    raise Api404Error()
            except lock.Locked as e:
                raise Api409Error("The application you are requesting an update for is locked for editing by another user")

            # if we didn't find an application or journal, 404 the user
            if vanilla_ap is None:
                if jlock is not None: jlock.delete()
                if alock is not None: alock.delete()
                raise Api404Error()

            # convert the incoming application into the web form
            form = MultiDict(xwalk.SuggestionFormXWalk.obj2form(ap))

            fc = formcontext.ApplicationFormFactory.get_form_context(role="publisher", form_data=form, source=vanilla_ap)
            if fc.validate():
                try:
                    save_target = not dry_run
                    fc.finalise(save_target=save_target, email_alert=False)
                    return fc.target
                except formcontext.FormContextException as e:
                    raise Api400Error(e.message)
                finally:
                    if jlock is not None: jlock.delete()
                    if alock is not None: alock.delete()
            else:
                if jlock is not None: jlock.delete()
                if alock is not None: alock.delete()
                raise Api400Error(cls._validation_message(fc))

        # otherwise, this is a brand-new application
        else:
            # convert the incoming application into the web form
            form = MultiDict(xwalk.SuggestionFormXWalk.obj2form(ap))

            # create a template that will hold all the values we want to persist across the form submission
            template = models.Suggestion()
            template.set_owner(account.id)

            fc = formcontext.ApplicationFormFactory.get_form_context(form_data=form, source=template)
            if fc.validate():
                try:
                    save_target = not dry_run
                    fc.finalise(save_target=save_target, email_alert=False)
                    return fc.target
                except formcontext.FormContextException as e:
                    raise Api400Error(e.message)
            else:
                raise Api400Error(cls._validation_message(fc))
Exemple #14
0
    def update(cls, id, data, account):
        # as long as authentication (in the layer above) has been successful, and the account exists, then
        # we are good to proceed
        if account is None:
            raise Api401Error()

        # next thing to do is a structural validation of the replacement data, by instantiating the object
        try:
            ia = IncomingApplication(data)
        except dataobj.DataStructureException as e:
            raise Api400Error(e.message)

        # now see if there's something for us to update
        ap = models.Suggestion.pull(id)
        if ap is None:
            raise Api404Error()

        # if that works, convert it to a Suggestion object
        new_ap = ia.to_application_model()

        # now augment the suggestion object with all the additional information it requires
        #
        # suggester name and email from the user account
        new_ap.set_suggester(account.name, account.email)

        # they are not allowed to set "subject"
        new_ap.bibjson().remove_subjects()

        # DOAJ BLL for this request
        applicationService = DOAJ.applicationService()
        authService = DOAJ.authorisationService()

        # if a current_journal is specified on the incoming data
        if new_ap.current_journal is not None:
            # once an application has a current_journal specified, you can't change it
            if new_ap.current_journal != ap.current_journal:
                raise Api400Error("current_journal cannot be changed once set.  current_journal is {x}; this request tried to change it to {y}".format(x=ap.current_journal, y=new_ap.current_journal))

            # load the update_request application either directly or by crosswalking the journal object
            vanilla_ap = None
            jlock = None
            alock = None
            try:
                vanilla_ap, jlock, alock = applicationService.update_request_for_journal(new_ap.current_journal, account=account)
            except AuthoriseException as e:
                if e.reason == AuthoriseException.WRONG_STATUS:
                    raise Api403Error("The application is no longer in a state in which it can be edited via the API")
                else:
                    raise Api404Error()
            except lock.Locked as e:
                raise Api409Error("The application is locked for editing by another user - most likely your application is being reviewed by an editor")

            # if we didn't find an application or journal, 404 the user
            if vanilla_ap is None:
                if jlock is not None: jlock.delete()
                if alock is not None: alock.delete()
                raise Api404Error()

            # convert the incoming application into the web form
            form = MultiDict(xwalk.SuggestionFormXWalk.obj2form(new_ap))

            fc = formcontext.ApplicationFormFactory.get_form_context(role="publisher", form_data=form, source=vanilla_ap)
            if fc.validate():
                try:
                    fc.finalise(email_alert=False)
                    return fc.target
                except formcontext.FormContextException as e:
                    raise Api400Error(e.message)
                finally:
                    if jlock is not None: jlock.delete()
                    if alock is not None: alock.delete()
            else:
                if jlock is not None: jlock.delete()
                if alock is not None: alock.delete()
                raise Api400Error(cls._validation_message(fc))
        else:
            try:
                authService.can_edit_application(account, ap)
            except AuthoriseException as e:
                if e.reason == e.WRONG_STATUS:
                    raise Api403Error("The application is no longer in a state in which it can be edited via the API")
                else:
                    raise Api404Error()

            # convert the incoming application into the web form
            form = MultiDict(xwalk.SuggestionFormXWalk.obj2form(new_ap))

            fc = formcontext.ApplicationFormFactory.get_form_context(form_data=form, source=ap)
            if fc.validate():
                try:
                    fc.finalise(email_alert=False)
                    return fc.target
                except formcontext.FormContextException as e:
                    raise Api400Error(e.message)
            else:
                raise Api400Error(cls._validation_message(fc))
    def test_02_application_2_journal(self, name, application_type,
                                      manual_update_arg, app_key_properties,
                                      current_journal, raises):
        # set up for the test
        #########################################

        cj = None
        has_seal = bool(randint(0, 1))
        application = None
        if application_type == "present":
            application = Suggestion(
                **ApplicationFixtureFactory.make_application_source())
            application.set_id(application.makeid())
            application.remove_contacts()
            application.remove_editor_group()
            application.remove_editor()
            application.remove_owner()
            application.remove_current_journal()
            application.remove_notes()

            if app_key_properties == "yes":
                application.add_contact("Application",
                                        "*****@*****.**")
                application.set_editor_group("appeditorgroup")
                application.set_editor("appeditor")
                application.set_owner("appowner")

            application.set_seal(has_seal)
            application.add_note("Application Note")

            if current_journal == "present":
                journal = Journal(
                    **JournalFixtureFactory.make_journal_source())
                journal.remove_contacts()
                journal.add_contact("Journal", "*****@*****.**")
                journal.set_editor_group("journaleditorgroup")
                journal.set_editor("journaleditor")
                journal.set_owner("journalowner")
                journal.remove_current_application()
                journal.remove_notes()
                journal.add_note("Journal Note")
                journal.save(blocking=True)
                application.set_current_journal(journal.id)
                cj = journal
            elif current_journal == "missing":
                application.set_current_journal("123456789987654321")

        manual_update = None
        if manual_update_arg == "true":
            manual_update = True
        elif manual_update_arg == "false":
            manual_update = False

        # execute the test
        ########################################

        svc = DOAJ.applicationService()
        if raises is not None and raises != "":
            with self.assertRaises(EXCEPTIONS[raises]):
                svc.application_2_journal(application, manual_update)
        else:
            journal = svc.application_2_journal(application, manual_update)

            # check the result
            ######################################

            assert journal is not None
            assert isinstance(journal, Journal)
            assert journal.is_in_doaj() is True

            jbj = journal.bibjson().data
            del jbj["active"]
            assert jbj == application.bibjson().data

            if current_journal == "present":
                assert len(journal.related_applications) == 3
            else:
                assert len(journal.related_applications) == 1
            related = journal.related_application_record(application.id)
            assert related is not None

            if manual_update_arg == "true":
                assert journal.last_manual_update is not None and journal.last_manual_update != "1970-01-01T00:00:00Z"

            if app_key_properties == "yes":
                contacts = journal.contacts()
                assert len(contacts) == 1
                assert contacts[0].get("name") == "Application"
                assert contacts[0].get("email") == "*****@*****.**"
                assert journal.editor_group == "appeditorgroup"
                assert journal.editor == "appeditor"
                assert journal.owner == "appowner"
                assert journal.has_seal() == has_seal

                if current_journal == "present":
                    assert len(journal.notes) == 2
                else:
                    assert len(journal.notes) == 1

            elif app_key_properties == "no":
                if current_journal == "present":
                    contacts = journal.contacts()
                    assert len(contacts) == 1
                    assert contacts[0].get("name") == "Journal"
                    assert contacts[0].get("email") == "*****@*****.**"
                    assert journal.editor_group == "journaleditorgroup"
                    assert journal.editor == "journaleditor"
                    assert journal.owner == "journalowner"
                    assert journal.has_seal() == has_seal
                    assert len(journal.notes) == 2

                elif current_journal == "none" or current_journal == "missing":
                    contacts = journal.contacts()
                    assert len(contacts) == 0
                    assert journal.editor_group is None
                    assert journal.editor is None
                    assert journal.owner is None
                    assert journal.has_seal() == has_seal
                    assert len(journal.notes) == 1

            if current_journal == "present":
                assert cj.id == journal.id
                assert cj.created_date == journal.created_date
    def test_02_application_2_journal(self, name, application_type, manual_update_arg, app_key_properties, current_journal, raises):
        # set up for the test
        #########################################

        cj = None
        has_seal = bool(randint(0, 1))
        application = None
        if application_type == "present":
            application = Suggestion(**ApplicationFixtureFactory.make_application_source())
            application.set_id(application.makeid())
            application.remove_contacts()
            application.remove_editor_group()
            application.remove_editor()
            application.remove_owner()
            application.remove_current_journal()
            application.remove_notes()

            if app_key_properties == "yes":
                application.add_contact("Application", "*****@*****.**")
                application.set_editor_group("appeditorgroup")
                application.set_editor("appeditor")
                application.set_owner("appowner")

            application.set_seal(has_seal)
            application.add_note("Application Note")

            if current_journal == "present":
                journal = Journal(**JournalFixtureFactory.make_journal_source())
                journal.remove_contacts()
                journal.add_contact("Journal", "*****@*****.**")
                journal.set_editor_group("journaleditorgroup")
                journal.set_editor("journaleditor")
                journal.set_owner("journalowner")
                journal.remove_current_application()
                journal.remove_notes()
                journal.add_note("Journal Note")
                journal.save(blocking=True)
                application.set_current_journal(journal.id)
                cj = journal
            elif current_journal == "missing":
                application.set_current_journal("123456789987654321")

        manual_update = None
        if manual_update_arg == "true":
            manual_update = True
        elif manual_update_arg == "false":
            manual_update = False

        # execute the test
        ########################################

        svc = DOAJ.applicationService()
        if raises is not None and raises != "":
            with self.assertRaises(EXCEPTIONS[raises]):
                svc.application_2_journal(application, manual_update)
        else:
            journal = svc.application_2_journal(application, manual_update)

            # check the result
            ######################################

            assert journal is not None
            assert isinstance(journal, Journal)
            assert journal.is_in_doaj() is True

            jbj = journal.bibjson().data
            del jbj["active"]
            assert jbj == application.bibjson().data

            if current_journal == "present":
                assert len(journal.related_applications) == 3
            else:
                assert len(journal.related_applications) == 1
            related = journal.related_application_record(application.id)
            assert related is not None

            if manual_update_arg == "true":
                assert journal.last_manual_update is not None and journal.last_manual_update != "1970-01-01T00:00:00Z"

            if app_key_properties == "yes":
                contacts = journal.contacts()
                assert len(contacts) == 1
                assert contacts[0].get("name") == "Application"
                assert contacts[0].get("email") == "*****@*****.**"
                assert journal.editor_group == "appeditorgroup"
                assert journal.editor == "appeditor"
                assert journal.owner == "appowner"
                assert journal.has_seal() == has_seal

                if current_journal == "present":
                    assert len(journal.notes) == 2
                else:
                    assert len(journal.notes) == 1

            elif app_key_properties == "no":
                if current_journal == "present":
                    contacts = journal.contacts()
                    assert len(contacts) == 1
                    assert contacts[0].get("name") == "Journal"
                    assert contacts[0].get("email") == "*****@*****.**"
                    assert journal.editor_group == "journaleditorgroup"
                    assert journal.editor == "journaleditor"
                    assert journal.owner == "journalowner"
                    assert journal.has_seal() == has_seal
                    assert len(journal.notes) == 2

                elif current_journal == "none" or current_journal == "missing":
                    contacts = journal.contacts()
                    assert len(contacts) == 0
                    assert journal.editor_group is None
                    assert journal.editor is None
                    assert journal.owner is None
                    assert journal.has_seal() == has_seal
                    assert len(journal.notes) == 1

            if current_journal == "present":
                assert cj.id == journal.id
                assert cj.created_date == journal.created_date
Exemple #17
0
    def create(cls, data, account, dry_run=False):
        # as long as authentication (in the layer above) has been successful, and the account exists, then
        # we are good to proceed
        if account is None:
            raise Api401Error()

        # first thing to do is a structural validation, but instantiating the data object
        try:
            ia = IncomingApplication(data)
        except dataobj.DataStructureException as e:
            raise Api400Error(e.message)

        # if that works, convert it to a Suggestion object
        ap = ia.to_application_model()

        # now augment the suggestion object with all the additional information it requires
        #
        # suggester name and email from the user account
        ap.set_suggester(account.name, account.email)

        # they are not allowed to set "subject"
        ap.bibjson().remove_subjects()

        # if this is an update request on an existing journal
        if ap.current_journal is not None:
            # DOAJ BLL for this request
            applicationService = DOAJ.applicationService()

            # load the update_request application either directly or by crosswalking the journal object
            vanilla_ap = None
            jlock = None
            alock = None
            try:
                vanilla_ap, jlock, alock = applicationService.update_request_for_journal(
                    ap.current_journal, account=account)
            except AuthoriseException as e:
                if e.reason == AuthoriseException.WRONG_STATUS:
                    raise Api403Error(
                        "The application is no longer in a state in which it can be edited via the API"
                    )
                else:
                    raise Api404Error()
            except lock.Locked as e:
                raise Api409Error(
                    "The application you are requesting an update for is locked for editing by another user"
                )

            # if we didn't find an application or journal, 404 the user
            if vanilla_ap is None:
                if jlock is not None: jlock.delete()
                if alock is not None: alock.delete()
                raise Api404Error()

            # convert the incoming application into the web form
            form = MultiDict(xwalk.SuggestionFormXWalk.obj2form(ap))

            fc = formcontext.ApplicationFormFactory.get_form_context(
                role="publisher", form_data=form, source=vanilla_ap)
            if fc.validate():
                try:
                    save_target = not dry_run
                    fc.finalise(save_target=save_target, email_alert=False)
                    return fc.target
                except formcontext.FormContextException as e:
                    raise Api400Error(e.message)
                finally:
                    if jlock is not None: jlock.delete()
                    if alock is not None: alock.delete()
            else:
                if jlock is not None: jlock.delete()
                if alock is not None: alock.delete()
                raise Api400Error(cls._validation_message(fc))

        # otherwise, this is a brand-new application
        else:
            # convert the incoming application into the web form
            form = MultiDict(xwalk.SuggestionFormXWalk.obj2form(ap))

            # create a template that will hold all the values we want to persist across the form submission
            template = models.Suggestion()
            template.set_owner(account.id)

            fc = formcontext.ApplicationFormFactory.get_form_context(
                form_data=form, source=template)
            if fc.validate():
                try:
                    save_target = not dry_run
                    fc.finalise(save_target=save_target, email_alert=False)
                    return fc.target
                except formcontext.FormContextException as e:
                    raise Api400Error(e.message)
            else:
                raise Api400Error(cls._validation_message(fc))
Exemple #18
0
    def test_01_update_request(self, name, journal_id, journal_lock,
                               account, account_role, account_is_owner,
                               current_applications, application_lock, application_status,
                               completed_applications, raises,
                               return_app, return_jlock, return_alock,
                               db_jlock, db_alock, db_app):

        ###############################################
        ## set up

        # create the journal
        journal = None
        jid = None
        if journal_id == "valid":
            journal = Journal(**JournalFixtureFactory.make_journal_source(in_doaj=True))
            journal.remove_related_applications()
            journal.remove_current_application()
            jid = journal.id
        elif journal_id == "not_in_doaj":
            journal = Journal(**JournalFixtureFactory.make_journal_source(in_doaj=False))
            journal.remove_related_applications()
            journal.remove_current_application()
            jid = journal.id
        elif journal_id == "missing":
            jid = uuid.uuid4().hex

        acc = None
        if account == "yes":
            acc = Account(**AccountFixtureFactory.make_publisher_source())
            if account_role == "none":
                acc.remove_role("publisher")
            elif account_role == "admin":
                acc.remove_role("publisher")
                acc.add_role("admin")
            acc.set_id(acc.makeid())
            if account_is_owner == "yes":
                acc.set_id(journal.owner)

        if journal_lock == "yes":
            lock.lock("journal", jid, "someoneelse", blocking=True)

        latest_app = None
        current_app_count = int(current_applications)
        for i in range(current_app_count):
            app = Suggestion(**ApplicationFixtureFactory.make_application_source())
            app.set_id(app.makeid())
            app.set_created("198" + str(i) + "-01-01T00:00:00Z")
            app.set_current_journal(jid)
            app.save()
            latest_app = app
            if journal is not None:
                journal.set_current_application(app.id)

        comp_app_count = int(completed_applications)
        for i in range(comp_app_count):
            app = Suggestion(**ApplicationFixtureFactory.make_application_source())
            app.set_id(app.makeid())
            app.set_created("197" + str(i) + "-01-01T00:00:00Z")
            app.set_related_journal(jid)
            app.save()
            if journal is not None:
                journal.add_related_application(app.id, date_accepted=app.created_date)

        if current_app_count == 0 and comp_app_count == 0:
            # save at least one record to initialise the index mapping, otherwise tests fail
            app = Suggestion(**ApplicationFixtureFactory.make_application_source())
            app.set_id(app.makeid())
            app.save()

        if application_lock == "yes":
            lock.lock("suggestion", latest_app.id, "someoneelse", blocking=True)

        if application_status != "n/a":
            latest_app.set_application_status(application_status)
            latest_app.save(blocking=True)

        # finally save the journal record, ensuring we get a blocking save, so everything
        # above here should be synchronised with the repo
        if journal is not None:
            journal.save(blocking=True)

        ###########################################################
        # Execution

        svc = DOAJ.applicationService()
        if raises != "":
            with self.assertRaises(EXCEPTIONS[raises]):
                svc.update_request_for_journal(jid, acc)
        else:
            application, jlock, alock = svc.update_request_for_journal(jid, acc)

            # we need to sleep, so the index catches up
            time.sleep(1)

            if return_app == "none":
                assert application is None
            elif return_app == "yes":
                assert application is not None

            if return_jlock == "none":
                assert jlock is None
            elif return_jlock == "yes":
                assert jlock is not None

            if return_alock == "none":
                assert alock is None
            elif return_alock == "yes":
                assert alock is not None

            if db_jlock == "no" and acc is not None:
                assert not lock.has_lock("journal", jid, acc.id)
            elif db_jlock == "yes" and acc is not None:
                assert lock.has_lock("journal", jid, acc.id)

            if db_alock == "no" and application.id is not None and acc is not None:
                assert not lock.has_lock("suggestion", application.id, acc.id)
            elif db_alock == "yes" and application.id is not None and acc is not None:
                assert lock.has_lock("suggestion", application.id, acc.id)

            if db_app == "no" and application.id is not None:
                indb = Suggestion.q2obj(q="id.exact:" + application.id)
                assert indb is None
            elif db_app == "yes" and application.id is not None:
                indb = Suggestion.q2obj(q="id.exact:" + application.id)
                assert indb is not None

            if current_app_count == 0 and comp_app_count == 0 and application is not None:
                assert application.article_metadata is None
                assert application.articles_last_year is None
            elif application is not None:
                assert application.article_metadata is not None
                assert application.articles_last_year is not None