Exemplo n.º 1
0
    def to_application_model(self, existing=None):
        nd = deepcopy(self.data)

        # we need to re-write the archiving policy section
        ap = nd.get("bibjson", {}).get("archiving_policy")
        if ap is not None:
            nap = {}
            if "url" in ap:
                nap["url"] = ap["url"]
            if "policy" in ap:
                known = []
                for pol in ap["policy"]:
                    if "domain" in pol:
                        if pol.get("domain").lower() == "other":
                            nap["other"] = pol.get("name")
                        elif pol.get("domain").lower() == "a national library":
                            nap["nat_lib"] = pol.get("name")
                    else:
                        known.append(pol.get("name"))
                if len(known) > 0:
                    nap["known"] = known
            nd["bibjson"]["archiving_policy"] = nap

        if existing is None:
            return models.Suggestion(**nd)
        else:
            nnd = dataobj.merge_outside_construct(self._struct, nd, existing.data)
            return models.Suggestion(**nnd)
Exemplo n.º 2
0
    def test_31_application_latest_by_current_journal(self):
        j = models.Journal()
        j.set_id(j.makeid())

        app1 = models.Suggestion(
            **ApplicationFixtureFactory.make_application_source())
        app1.set_id(app1.makeid())
        app1.set_current_journal(j.id)
        app1.set_created("1970-01-01T00:00:00Z")
        app1.save()

        app2 = models.Suggestion(
            **ApplicationFixtureFactory.make_application_source())
        app2.set_id(app2.makeid())
        app2.set_current_journal(j.id)
        app2.set_created("1971-01-01T00:00:00Z")
        app2.save(blocking=True)

        # check that we find the right application when we search
        app3 = models.Suggestion.find_latest_by_current_journal(j.id)
        assert app3 is not None
        assert app3.id == app2.id

        # make sure we get a None response when there's no application
        app0 = models.Suggestion.find_latest_by_current_journal("whatever")
        assert app0 is None
Exemplo n.º 3
0
    def test_02_classification_required(self):
        # Check we can mark an application 'completed' with a subject classification present
        in_progress_application = models.Suggestion(
            **ApplicationFixtureFactory.make_application_source())
        in_progress_application.set_application_status(
            constants.APPLICATION_STATUS_IN_PROGRESS)

        fc = formcontext.ApplicationFormFactory.get_form_context(
            role='associate_editor', source=in_progress_application)

        # Make changes to the application status via the form, check it validates
        fc.form.application_status.data = constants.APPLICATION_STATUS_COMPLETED

        assert fc.validate()

        # Without a subject classification, we should not be able to set the status to 'completed'
        no_class_application = models.Suggestion(
            **ApplicationFixtureFactory.make_application_source())
        del no_class_application.data['bibjson']['subject']
        fc = formcontext.ApplicationFormFactory.get_form_context(
            role='associate_editor', source=no_class_application)
        # Make changes to the application status via the form
        assert fc.source.bibjson().subjects() == []
        fc.form.application_status.data = constants.APPLICATION_STATUS_COMPLETED

        assert not fc.validate()

        # However, we should be able to set it to a different status rather than 'completed'
        fc.form.application_status.data = constants.APPLICATION_STATUS_PENDING

        assert fc.validate()
Exemplo n.º 4
0
    def test_03_classification_required(self):
        # Check we can accept an application with a subject classification present
        ready_application = models.Suggestion(**ApplicationFixtureFactory.make_application_source())
        ready_application.set_application_status(constants.APPLICATION_STATUS_READY)

        fc = formcontext.ApplicationFormFactory.get_form_context(role='admin', source=ready_application)

        # Make changes to the application status via the form, check it validates
        fc.form.application_status.data = constants.APPLICATION_STATUS_ACCEPTED

        assert fc.validate()

        # Without a subject classification, we should not be able to set the status to 'accepted'
        no_class_application = models.Suggestion(**ApplicationFixtureFactory.make_application_source())
        del no_class_application.data['bibjson']['subject']
        fc = formcontext.ApplicationFormFactory.get_form_context(role='admin', source=no_class_application)
        # Make changes to the application status via the form
        assert fc.source.bibjson().subjects() == []
        fc.form.application_status.data = constants.APPLICATION_STATUS_ACCEPTED

        assert not fc.validate()

        # However, we should be able to set it to a different status rather than 'accepted'
        fc.form.application_status.data = constants.APPLICATION_STATUS_IN_PROGRESS

        assert fc.validate()
Exemplo n.º 5
0
    def test_01_publisher_csv_reapplication_success(self):
        """Give the publisher's csv reapplication a full workout"""

        # we start by constructing it from source
        fc = formcontext.ApplicationFormFactory.get_form_context(
            role="csv", source=models.Suggestion(**REAPPLICATION_SOURCE))
        assert isinstance(fc, formcontext.PublisherCsvReApplication)
        assert fc.form is not None
        assert fc.source is not None
        assert fc.form_data is None
        assert fc.template is None  # because no template is set

        # now construct it from form data (with a known source)
        fc = formcontext.ApplicationFormFactory.get_form_context(
            role="csv",
            form_data=MultiDict(REAPPLICATION_FORM),
            source=models.Suggestion(**REAPPLICATION_SOURCE))

        assert isinstance(fc, formcontext.PublisherCsvReApplication)
        assert fc.form is not None
        assert fc.source is not None
        assert fc.form_data is not None

        # test each of the workflow components individually ...

        # pre-validate and ensure that the disbaled fields get re-set
        fc.pre_validate()
        assert fc.form.pissn.data == "1234-5678"
        assert fc.form.eissn.data == "9876-5432"
        assert fc.form.contact_name.data == "Contact Name"
        assert fc.form.contact_email.data == "*****@*****.**"
        assert fc.form.confirm_contact_email.data == "*****@*****.**"

        # run the validation itself
        assert fc.validate(), fc.form.errors

        # run the crosswalk (no need to look in detail, xwalks are tested elsewhere)
        fc.form2target()
        assert fc.target is not None

        # patch the target with data from the source
        fc.patch_target()
        assert fc.target.created_date == "2000-01-01T00:00:00Z"
        assert fc.target.id == "abcdefghijk"
        assert len(fc.target.notes()) == 2
        assert fc.target.owner == "Owner"
        assert fc.target.editor_group == "editorgroup"
        assert fc.target.editor == "associate"
        assert fc.target.application_status == "reapplication"  # because it hasn't been finalised yet
        assert fc.target.suggester, 'Suggester not set'
        assert fc.target.suggester['name'] == fc.form.contact_name.data
        assert fc.target.suggester['email'] == fc.form.contact_email.data

        # now do finalise (which will also re-run all of the steps above)
        fc.finalise()
        assert fc.target.application_status == "submitted"
Exemplo n.º 6
0
    def test_02_conditional_disabled(self):
        s = models.Suggestion(**deepcopy(REAPPLICATION_SOURCE))

        # source only, all fields disabled
        fc = formcontext.ApplicationFormFactory.get_form_context(
            role="publisher", source=s)
        assert "pissn" in fc.renderer.disabled_fields
        assert "eissn" in fc.renderer.disabled_fields
        assert "contact_name" in fc.renderer.disabled_fields
        assert "contact_email" in fc.renderer.disabled_fields
        assert "confirm_contact_email" in fc.renderer.disabled_fields
        # should validate
        assert fc.validate()

        # source only, no contact details, so those fields not disabled
        del s.data["admin"]["contact"]
        fc = formcontext.ApplicationFormFactory.get_form_context(
            role="publisher", source=s)
        assert "pissn" in fc.renderer.disabled_fields
        assert "eissn" in fc.renderer.disabled_fields
        assert "contact_name" not in fc.renderer.disabled_fields
        assert "contact_email" not in fc.renderer.disabled_fields
        assert "confirm_contact_email" not in fc.renderer.disabled_fields
        # should fail to validate
        assert not fc.validate()

        # source + form data, everything complete from source, so all fields disabled
        s = models.Suggestion(**deepcopy(REAPPLICATION_SOURCE))
        fd = MultiDict(deepcopy(REAPPLICATION_FORM))
        fc = formcontext.ApplicationFormFactory.get_form_context(
            role="publisher", source=s, form_data=fd)
        assert "pissn" in fc.renderer.disabled_fields
        assert "eissn" in fc.renderer.disabled_fields
        assert "contact_name" in fc.renderer.disabled_fields
        assert "contact_email" in fc.renderer.disabled_fields
        assert "confirm_contact_email" in fc.renderer.disabled_fields
        # should validate
        assert fc.validate()

        # source + form data, both source and form missing some values, but disabled fields only draw from source
        del s.data["admin"]["contact"]
        rf = deepcopy(REAPPLICATION_FORM)
        rf["contact_name"] = "Contact Name"
        fc = formcontext.ApplicationFormFactory.get_form_context(
            role="publisher", source=s, form_data=fd)
        assert "pissn" in fc.renderer.disabled_fields
        assert "eissn" in fc.renderer.disabled_fields
        assert "contact_name" not in fc.renderer.disabled_fields
        assert "contact_email" not in fc.renderer.disabled_fields
        assert "confirm_contact_email" not in fc.renderer.disabled_fields
        # should fail to validate
        assert not fc.validate()
Exemplo n.º 7
0
    def test_03_workflow_editor_notifications(self):
        ctx = self._make_and_push_test_context()

        emails = {}

        # When we make the application unchanged for a short period of time, we don't tell the editors
        [APPLICATION_SOURCE_1, APPLICATION_SOURCE_2, APPLICATION_SOURCE_3
         ] = ApplicationFixtureFactory.make_many_application_sources(count=3)
        comfortably_idle = app.config['ASSOC_ED_IDLE_DAYS'] + 1
        APPLICATION_SOURCE_1['last_manual_update'] = datetime.utcnow(
        ) - timedelta(days=comfortably_idle)
        application1 = models.Suggestion(**APPLICATION_SOURCE_1)
        application1.save()

        # This exceeds the idle limit, editors should be notified.
        APPLICATION_SOURCE_2['admin'][
            'application_status'] = constants.APPLICATION_STATUS_IN_PROGRESS
        extremely_idle = app.config['ED_IDLE_WEEKS'] + 1
        APPLICATION_SOURCE_2['last_manual_update'] = datetime.utcnow(
        ) - timedelta(weeks=extremely_idle)
        application2 = models.Suggestion(**APPLICATION_SOURCE_2)
        application2.save()

        # This one is assigned to the group but not an associate - editors are reminded.
        extremely_idle = app.config['ED_IDLE_WEEKS'] + 1
        APPLICATION_SOURCE_2['admin'][
            'application_status'] = constants.APPLICATION_STATUS_UPDATE_REQUEST
        APPLICATION_SOURCE_3['last_manual_update'] = datetime.utcnow(
        ) - timedelta(days=extremely_idle)
        APPLICATION_SOURCE_3['admin']['editor'] = None
        application3 = models.Suggestion(**APPLICATION_SOURCE_3)
        application3.save()

        models.Suggestion.blockall([
            (application1.id, application1.last_updated),
            (application2.id, application2.last_updated),
            (application3.id, application3.last_updated)
        ])

        async_workflow_notifications.editor_notifications(emails)

        assert len(emails) > 0
        assert EDITOR_SOURCE['email'] in list(emails.keys())

        email_text_catted = " ".join(emails[EDITOR_SOURCE['email']][1])
        assert '1 application(s) currently assigned to your Editor Group, "editorgroup", which have no Associate Editor' in email_text_catted
        assert "1 application(s) which have been assigned to an Associate Editor but have been idle" in email_text_catted

        ctx.pop()
Exemplo n.º 8
0
    def test_28_make_provenance(self):
        acc = models.Account()
        acc.set_id("test")
        acc.add_role("associate_editor")
        acc.add_role("editor")

        obj1 = models.Suggestion()
        obj1.set_id("obj1")

        models.Provenance.make(acc, "act1", obj1)

        time.sleep(2)

        prov = models.Provenance.get_latest_by_resource_id("obj1")
        assert prov.type == "suggestion"
        assert prov.user == "test"
        assert prov.roles == ["associate_editor", "editor"]
        assert len(prov.editor_group) == 0
        assert prov.subtype is None
        assert prov.action == "act1"
        assert prov.resource_id == "obj1"

        eg1 = models.EditorGroup()
        eg1.set_id("associate")
        eg1.add_associate(acc.id)
        eg1.save()

        eg2 = models.EditorGroup()
        eg2.set_id("editor")
        eg2.set_editor(acc.id)
        eg2.save()

        time.sleep(2)

        obj2 = models.Suggestion()
        obj2.set_id("obj2")

        models.Provenance.make(acc, "act2", obj2, "sub")

        time.sleep(2)

        prov = models.Provenance.get_latest_by_resource_id("obj2")
        assert prov.type == "suggestion"
        assert prov.user == "test"
        assert prov.roles == ["associate_editor", "editor"]
        assert prov.editor_group == ["editor", "associate"]
        assert prov.subtype == "sub"
        assert prov.action == "act2"
        assert prov.resource_id == "obj2"
Exemplo n.º 9
0
    def test_01_maned_review_success(self):
        """Give the editor's reapplication form a full workout"""

        # we start by constructing it from source
        fc = formcontext.ApplicationFormFactory.get_form_context(
            role="admin", source=models.Suggestion(**APPLICATION_SOURCE))
        assert isinstance(fc, formcontext.ManEdApplicationReview)
        assert fc.form is not None
        assert fc.source is not None
        assert fc.form_data is None
        assert fc.template is not None

        # no need to check form rendering - there are no disabled fields

        # now construct it from form data (with a known source)
        fc = formcontext.ApplicationFormFactory.get_form_context(
            role="admin",
            form_data=MultiDict(APPLICATION_FORM),
            source=models.Suggestion(**APPLICATION_SOURCE))

        assert isinstance(fc, formcontext.ManEdApplicationReview)
        assert fc.form is not None
        assert fc.source is not None
        assert fc.form_data is not None

        # test each of the workflow components individually ...

        # pre-validate and ensure that the disabled fields get re-set
        fc.pre_validate()
        # no disabled fields, so just test the function runs

        # run the validation itself
        fc.form.subject.choices = mock_lcc_choices  # set the choices allowed for the subject manually (part of the test)
        assert fc.validate(), fc.form.errors

        # run the crosswalk (no need to look in detail, xwalks are tested elsewhere)
        fc.form2target()
        assert fc.target is not None

        # patch the target with data from the source
        fc.patch_target()
        assert fc.target.created_date == "2000-01-01T00:00:00Z"
        assert fc.target.id == "abcdefghijk"
        # everything else is overridden by the form, so no need to check it has patched

        # now do finalise (which will also re-run all of the steps above)
        fc.finalise()
        assert True  # gives us a place to drop a break point later if we need it
Exemplo n.º 10
0
    def test_02_application(self):
        forminfo = suggestion_form.SuggestionFormXWalk.obj2form(
            models.Suggestion(**APPLICATION_SOURCE))
        #diff_dicts(APPLICATION_FORMINFO, forminfo)
        assert forminfo == APPLICATION_FORMINFO

        form = forms.ManEdApplicationReviewForm(
            formdata=MultiDict(APPLICATION_FORM))
        obj = suggestion_form.SuggestionFormXWalk.form2obj(form)

        onotes = obj["admin"]["notes"]
        del obj["admin"]["notes"]

        cnotes = APPLICATION_SOURCE["admin"]["notes"]
        csource = deepcopy(APPLICATION_SOURCE)
        del csource["admin"]["notes"]

        otext = [n.get("note") for n in onotes]
        ctext = [n.get("note") for n in cnotes]
        assert otext == ctext

        # get rid of the id and created_date in the ready-made fixture application for comparison
        # the model object is not going to have an id or created_date since it's not been saved yet
        del csource['id']
        del csource['created_date']
        del csource["admin"]["current_journal"]
        del csource["admin"]["related_journal"]
        #diff_dicts(csource, obj, 'csource', 'modelobj')
        #diff_dicts(csource["bibjson"], obj["bibjson"])
        assert obj == csource
Exemplo n.º 11
0
    def test_06_make_journal(self):
        s = models.Suggestion(**ApplicationFixtureFactory.make_application_source())
        j = s.make_journal()

        assert j.id != s.id
        assert "suggestion" not in j.data
        assert j.data.get("bibjson", {}).get("active")
Exemplo n.º 12
0
    def test_01_maned_review_success(self):
        """Give the editor's application form a full workout"""
        acc = models.Account()
        acc.set_id("richard")
        acc.add_role("admin")
        ctx = self._make_and_push_test_context(acc=acc)

        # we start by constructing it from source
        fc = formcontext.ApplicationFormFactory.get_form_context(role="admin", source=models.Suggestion(**APPLICATION_SOURCE))
        assert isinstance(fc, formcontext.ManEdApplicationReview)
        assert fc.form is not None
        assert fc.source is not None
        assert fc.form_data is None
        assert fc.template is not None

        # no need to check form rendering - there are no disabled fields

        # now construct it from form data (with a known source)
        fc = formcontext.ApplicationFormFactory.get_form_context(
            role="admin",
            form_data=MultiDict(APPLICATION_FORM) ,
            source=models.Suggestion(**APPLICATION_SOURCE))

        assert isinstance(fc, formcontext.ManEdApplicationReview)
        assert fc.form is not None
        assert fc.source is not None
        assert fc.form_data is not None

        # test each of the workflow components individually ...

        # pre-validate and ensure that the disabled fields get re-set
        fc.pre_validate()
        # no disabled fields, so just test the function runs

        # run the validation itself
        fc.form.subject.choices = mock_lcc_choices # set the choices allowed for the subject manually (part of the test)
        assert fc.validate(), fc.form.errors

        # run the crosswalk (no need to look in detail, xwalks are tested elsewhere)
        fc.form2target()
        assert fc.target is not None

        # patch the target with data from the source
        fc.patch_target()
        assert fc.target.created_date == "2000-01-01T00:00:00Z"
        assert fc.target.id == "abcdefghijk"
        assert fc.target.current_journal == "123456789987654321"
        assert fc.target.related_journal == "987654321123456789"
        # everything else is overridden by the form, so no need to check it has patched

        # now do finalise (which will also re-run all of the steps above)
        fc.finalise()

        time.sleep(2)

        # now check that a provenance record was recorded
        prov = models.Provenance.get_latest_by_resource_id(fc.target.id)
        assert prov is not None

        ctx.pop()
Exemplo n.º 13
0
    def test_05_maned_review_accept(self):
        """Give the editor's application form a full workout"""
        acc = models.Account()
        acc.set_id("richard")
        acc.add_role("admin")
        ctx = self._make_and_push_test_context(acc=acc)

        # construct a context from a form submission
        source = deepcopy(APPLICATION_FORM)
        source["application_status"] = constants.APPLICATION_STATUS_ACCEPTED
        fd = MultiDict(source)
        fc = formcontext.ApplicationFormFactory.get_form_context(
            role="admin",
            form_data=fd,
            source=models.Suggestion(**APPLICATION_SOURCE))

        fc.finalise()
        time.sleep(2)

        # now check that a provenance record was recorded
        count = 0
        for prov in models.Provenance.iterall():
            if prov.action == "edit":
                count += 1
            if prov.action == "status:accepted":
                count += 10
        assert count == 11

        ctx.pop()
Exemplo n.º 14
0
def list_by_title(input, out):
    # first read in and prep the search data
    terms = _prep_search_terms(input)

    conn = esprit.raw.make_connection(None, app.config["ELASTIC_SEARCH_HOST"],
                                      None, app.config["ELASTIC_SEARCH_DB"])

    application_rows = []
    for a in esprit.tasks.scroll(conn,
                                 models.Suggestion.__type__,
                                 q=APPS_NOT_ACCEPTED,
                                 page_size=1000,
                                 keepalive='5m'):
        application = models.Suggestion(_source=a)
        title = application.bibjson().title
        alt = application.bibjson().alternative_title
        titles = []
        if title is not None and title != "":
            titles.append(_normalise_title(title))
        if alt is not None and alt != "":
            titles.append(_normalise_title(alt))
        for variants in terms:
            for v in variants:
                if v in titles or len([t for t in titles if v in t]) > 0:
                    row = [variants[-1]] + _extract_report_row(application)
                    application_rows.append(row)
                    break

    journal_rows = []
    for j in esprit.tasks.scroll(conn,
                                 models.Journal.__type__,
                                 q=ALL_JOURNALS,
                                 page_size=1000,
                                 keepalive='5m'):
        journal = models.Journal(_source=j)
        title = journal.bibjson().title
        alt = journal.bibjson().alternative_title
        titles = []
        if title is not None and title != "":
            titles.append(_normalise_title(title))
        if alt is not None and alt != "":
            titles.append(_normalise_title(alt))
        for variants in terms:
            for v in variants:
                if v in titles or len([t for t in titles if v in t]) > 0:
                    row = [variants[-1]] + _extract_journal_row(journal)
                    application_rows.append(row)
                    break

    with open(out, "w", encoding="utf-8") as o:
        writer = csv.writer(o)
        writer.writerow([
            "Supplied Title", "Type", "ISSN(s)", "Date Created",
            "Last Updated", "Date Applied", "Status", "Most Recent Note",
            "Title Matched", "Alternative Title Matched", "Link"
        ])
        for row in application_rows:
            writer.writerow(row)
        for row in journal_rows:
            writer.writerow(row)
Exemplo n.º 15
0
    def setUp(self):
        super(TestTaskSuggestionBulkEdit, self).setUp()

        acc = models.Account()
        acc.set_id("0987654321")
        acc.set_email("*****@*****.**")
        acc.save()

        egs = EditorGroupFixtureFactory.make_editor_group_source(
            "1234567890", "0987654321")
        egm = models.EditorGroup(**egs)
        egm.save(blocking=True)

        self.suggestions = []
        for app_src in ApplicationFixtureFactory.make_many_application_sources(
                count=TEST_SUGGESTION_COUNT):
            self.suggestions.append(models.Suggestion(**app_src))
            self.suggestions[-1].set_editor_group("1234567890")
            self.suggestions[-1].set_editor("0987654321")
            self.suggestions[-1].save()

        self.default_eg = EditorGroupFixtureFactory.setup_editor_group_with_editors(
        )

        self.forbidden_accounts = [
            AccountFixtureFactory.make_editor_source()['id'],
            AccountFixtureFactory.make_assed1_source()['id'],
            AccountFixtureFactory.make_assed2_source()['id'],
            AccountFixtureFactory.make_assed3_source()['id']
        ]

        self._make_and_push_test_context(acc=models.Account(
            **AccountFixtureFactory.make_managing_editor_source()))
Exemplo n.º 16
0
    def test_04_suggestion_model_rw(self):
        """Read and write properties into the suggestion model"""
        s = models.Suggestion()
        s.set_current_journal("9876543")
        s.set_related_journal("123456789")
        s.set_bulk_upload_id("abcdef")
        s.set_application_status(constants.APPLICATION_STATUS_REJECTED)
        s.suggested_on = "2001-01-01T00:00:00Z"
        s.set_articles_last_year(12, "http://aly.com")
        s.article_metadata = True
        s.set_suggester("test", "*****@*****.**")

        assert s.data.get("admin", {}).get("current_journal") == "9876543"
        assert s.current_journal == "9876543"
        assert s.related_journal == "123456789"
        assert s.bulk_upload_id == "abcdef"
        assert s.application_status == constants.APPLICATION_STATUS_REJECTED
        assert s.suggested_on == "2001-01-01T00:00:00Z"
        assert s.articles_last_year.get("count") == 12
        assert s.articles_last_year.get("url") == "http://aly.com"
        assert s.article_metadata is True
        assert s.suggester.get("name") == "test"
        assert s.suggester.get("email") == "*****@*****.**"

        # check over ordered note reading
        s.add_note("another note", "2010-01-01T00:00:00Z")
        s.add_note("an old note", "2001-01-01T00:00:00Z")
        ons = s.ordered_notes
        assert len(ons) == 2
        assert ons[1]["note"] == "an old note"
        assert ons[0]["note"] == "another note"

        s.prep()
        assert 'index' in s, s
        assert 'application_type' in s['index'], s['index']
        assert s['index'][
            'application_type'] == constants.APPLICATION_TYPE_UPDATE_REQUEST

        s.remove_current_journal()
        assert s.current_journal is None
        s.prep()
        assert 'index' in s, s
        assert 'application_type' in s['index'], s['index']
        assert s['index'][
            'application_type'] == constants.APPLICATION_TYPE_FINISHED

        s.set_application_status(constants.APPLICATION_STATUS_PENDING)
        s.prep()
        assert s['index'][
            'application_type'] == constants.APPLICATION_TYPE_NEW_APPLICATION

        s.save()

        s.remove_current_journal()
        s.remove_related_journal()

        assert s.current_journal is None
        assert s.related_journal is None
Exemplo n.º 17
0
    def test_02_workflow_managing_editor_notifications(self):
        ctx = self._make_and_push_test_context()

        emails = {}

        # When we make the application unchanged for a short period of time, we don't tell the managing editors
        [APPLICATION_SOURCE_1, APPLICATION_SOURCE_2, APPLICATION_SOURCE_3
         ] = ApplicationFixtureFactory.make_many_application_sources(count=3)
        comfortably_idle = app.config['ASSOC_ED_IDLE_DAYS'] + 1
        APPLICATION_SOURCE_1['last_manual_update'] = datetime.utcnow(
        ) - timedelta(days=comfortably_idle)
        application1 = models.Suggestion(**APPLICATION_SOURCE_1)
        application1.save()

        # This exceeds the idle limit, managing editors should be notified.
        APPLICATION_SOURCE_2['admin'][
            'application_status'] = constants.APPLICATION_STATUS_IN_PROGRESS
        extremely_idle = app.config['MAN_ED_IDLE_WEEKS'] + 1
        APPLICATION_SOURCE_2['last_manual_update'] = datetime.utcnow(
        ) - timedelta(weeks=extremely_idle)
        application2 = models.Suggestion(**APPLICATION_SOURCE_2)
        application2.save()

        # This one is ready - managing editors are told as it's now their responsibility.
        APPLICATION_SOURCE_3['last_manual_update'] = datetime.utcnow()
        APPLICATION_SOURCE_3['admin'][
            'application_status'] = constants.APPLICATION_STATUS_READY
        application3 = models.Suggestion(**APPLICATION_SOURCE_3)
        application3.save()

        models.Suggestion.blockall([
            (application1.id, application1.last_updated),
            (application2.id, application2.last_updated),
            (application3.id, application3.last_updated)
        ])

        async_workflow_notifications.managing_editor_notifications(emails)
        assert len(emails) > 0
        assert app.config['MANAGING_EDITOR_EMAIL'] in list(emails.keys())

        email_text_catted = " ".join(
            emails[app.config['MANAGING_EDITOR_EMAIL']][1])
        assert '1 application(s) are assigned to an Associate Editor' in email_text_catted
        assert "There are 1 records in status 'Ready'" in email_text_catted
        ctx.pop()
Exemplo n.º 18
0
def anonymise_suggestion(record):
    try:
        sug = models.Suggestion(**record)
    except DataStructureException:
        return record

    sug = _anonymise_admin(sug)
    sug.set_suggester(anon_name(), anon_email(sug.suggester['email']))
    return sug.data
Exemplo n.º 19
0
    def test_03_suggestion_model_rw(self):
        """Read and write properties into the suggestion model"""
        s = models.Suggestion()
        s.set_current_journal("9876543")
        s.set_bulk_upload_id("abcdef")

        assert s.data.get("admin", {}).get("current_journal") == "9876543"
        assert s.current_journal == "9876543"
        assert s.bulk_upload_id == "abcdef"
Exemplo n.º 20
0
    def test_04_workflow_associate_editor_notifications(self):
        ctx = self._make_and_push_test_context()

        APPLICATION_SOURCE['last_manual_update'] = datetime.utcnow()
        application = models.Suggestion(**APPLICATION_SOURCE)
        application.save(blocking=True)

        # This application is assigned to associate editor 1, but it is not yet stale enough to require a reminder
        emails = {}
        async_workflow_notifications.associate_editor_notifications(emails)
        assert_false(emails)

        # When we make the application unchanged for a period of time, we expect a message to be generated
        [APPLICATION_SOURCE_2, APPLICATION_SOURCE_3
         ] = ApplicationFixtureFactory.make_many_application_sources(count=2)
        comfortably_idle = app.config['ASSOC_ED_IDLE_DAYS'] + 1
        APPLICATION_SOURCE_2['last_manual_update'] = datetime.utcnow(
        ) - timedelta(days=comfortably_idle)
        application2 = models.Suggestion(**APPLICATION_SOURCE_2)
        application2.save()

        extremely_idle = app.config['ASSOC_ED_IDLE_WEEKS'] + 1
        APPLICATION_SOURCE_3['last_manual_update'] = datetime.utcnow(
        ) - timedelta(weeks=extremely_idle)
        application3 = models.Suggestion(**APPLICATION_SOURCE_3)
        application3.save()

        models.Suggestion.blockall([
            (application.id, application.last_updated),
            (application2.id, application2.last_updated),
            (application3.id, application3.last_updated)
        ])

        async_workflow_notifications.associate_editor_notifications(emails)
        assert len(emails) > 0
        assert ASSED1_SOURCE['email'] in list(emails.keys())

        email_text = emails[ASSED1_SOURCE['email']][1].pop()
        assert 'You have 2 application(s) assigned to you' in email_text
        assert 'including 1 which have been unchanged' in email_text

        ctx.pop()
Exemplo n.º 21
0
    def setUp(self):
        super(TestTick, self).setUp()
        self.j_correct = models.Journal(created_date="2014-06-28T11:26:42Z")
        self.j_correct.set_in_doaj(True)
        self.j_correct.save()

        self.j_not_in_doaj_excplicit = models.Journal(
            created_date="2014-06-28T11:26:42Z")
        self.j_not_in_doaj_excplicit.set_in_doaj(False)
        self.j_not_in_doaj_excplicit.save()

        self.j_not_in_doaj_implicit = models.Journal(
            created_date="2014-06-28T11:26:42Z")
        self.j_not_in_doaj_implicit.save()

        self.j_too_old = models.Journal(created_date="2012-06-28T11:26:42Z")
        self.j_too_old.set_in_doaj(True)
        self.j_too_old.save()

        self.j_too_old_not_in = models.Journal(
            created_date="2012-06-28T11:26:42Z")
        self.j_too_old_not_in.set_in_doaj(False)
        self.j_too_old_not_in.save()

        self.sugg = models.Suggestion(created_date="2014-06-28T11:26:42Z")
        self.sugg.save()

        # update request tests
        self.j_old_cd_old_reapp = models.Journal(
            created_date="2012-06-28T11:26:42Z")
        self.j_old_cd_old_reapp.add_related_application(
            "123456789", date_accepted="2012-07-28T11:26:42Z")
        self.j_old_cd_old_reapp.set_in_doaj(True)
        self.j_old_cd_old_reapp.save()

        self.j_old_cd_new_reapp = models.Journal(
            created_date="2012-06-28T11:26:42Z")
        self.j_old_cd_new_reapp.add_related_application(
            "123456789", date_accepted="2015-01-01T11:26:42Z")
        self.j_old_cd_new_reapp.set_in_doaj(True)
        self.j_old_cd_new_reapp.save()

        self.j_old_cd_new_reapp_out = models.Journal(
            created_date="2012-06-28T11:26:42Z")
        self.j_old_cd_new_reapp_out.add_related_application(
            "123456789", date_accepted="2015-01-01T11:26:42Z")
        self.j_old_cd_new_reapp_out.set_in_doaj(False)
        self.j_old_cd_new_reapp_out.save()

        # Refresh the type to force changes in the index, then wait for it to be done
        models.Journal.refresh()
        models.Suggestion.refresh()
        time.sleep(2)
Exemplo n.º 22
0
    def test_06_formcontext_factory(self):
        fc = formcontext.ApplicationFormFactory.get_form_context()
        assert isinstance(fc, formcontext.PublicApplication)
        assert fc.form is not None
        assert fc.form_data is None
        assert fc.source is None

        fc = formcontext.ApplicationFormFactory.get_form_context(
            role="admin", source=models.Suggestion(**APPLICATION_SOURCE))
        assert isinstance(fc, formcontext.ManEdApplicationReview)
        assert fc.form is not None
        assert fc.form_data is None
        assert fc.source is not None

        fc = formcontext.ApplicationFormFactory.get_form_context(
            role="editor",
            source=models.Suggestion(**APPLICATION_SOURCE),
            form_data=MultiDict(APPLICATION_FORM))
        assert isinstance(fc, formcontext.EditorApplicationReview)
        assert fc.form is not None
        assert fc.form_data is not None
        assert fc.source is not None

        fc = formcontext.ApplicationFormFactory.get_form_context(
            "associate_editor",
            source=models.Suggestion(**APPLICATION_SOURCE),
            form_data=MultiDict(APPLICATION_FORM))
        assert isinstance(fc, formcontext.AssEdApplicationReview)
        assert fc.form is not None
        assert fc.form_data is not None
        assert fc.source is not None

        fc = formcontext.ApplicationFormFactory.get_form_context(
            "publisher",
            source=models.Suggestion(**APPLICATION_SOURCE),
            form_data=MultiDict(APPLICATION_FORM))
        assert isinstance(fc, formcontext.PublisherUpdateRequest)
        assert fc.form is not None
        assert fc.form_data is not None
        assert fc.source is not None
Exemplo n.º 23
0
    def test_02_update_request(self):
        acc = models.Account()
        acc.set_id("richard")
        acc.add_role("admin")
        ctx = self._make_and_push_test_context(acc=acc)

        # There needs to be an existing journal in the index for this test to work
        jsource = JournalFixtureFactory.make_journal_source()
        del jsource["admin"]["related_applications"]
        extant_j = models.Journal(**jsource)
        assert extant_j.last_update_request is None
        extant_j_created_date = extant_j.created_date
        extant_j.save()
        time.sleep(1)

        # We've added one journal, so there'll be one snapshot already
        assert models.Journal.count() == 1
        h = self.list_today_journal_history_files()
        assert len(h) == 1

        # set up an application which is an update on an existing journal
        s = models.Suggestion(**APPLICATION_SOURCE)
        s.set_current_journal("abcdefghijk_journal")
        s.set_application_status(constants.APPLICATION_STATUS_UPDATE_REQUEST)

        # set up the form which "accepts" this update request
        fd = deepcopy(APPLICATION_FORM)
        fd["application_status"] = constants.APPLICATION_STATUS_ACCEPTED
        fd = MultiDict(fd)

        # create and finalise the form context
        fc = formcontext.ApplicationFormFactory.get_form_context(role="admin",
                                                                 form_data=fd,
                                                                 source=s)

        # with app.test_request_context():
        fc.finalise()

        # let the index catch up
        time.sleep(1)

        j = models.Journal.pull("abcdefghijk_journal")
        assert j is not None
        assert j.created_date == extant_j_created_date
        assert j.last_update_request is not None
        assert models.Journal.count() == 1

        h = self.list_today_journal_history_files()
        assert h is not None
        assert len(h) == 2

        ctx.pop()
Exemplo n.º 24
0
    def test_08_sync_owners(self):
        # suggestion with no current_journal
        s = models.Suggestion(
            **ApplicationFixtureFactory.make_application_source())
        s.save()

        models.Suggestion.refresh()
        s = models.Suggestion.pull(s.id)
        assert s is not None

        # journal with no current_application
        j = models.Journal(**JournalFixtureFactory.make_journal_source())
        j.save()

        models.Journal.refresh()
        j = models.Journal.pull(j.id)
        assert j is not None

        # suggestion with erroneous current_journal
        s.set_current_journal("asdklfjsadjhflasdfoasf")
        s.save()

        models.Suggestion.refresh()
        s = models.Suggestion.pull(s.id)
        assert s is not None

        # journal with erroneous current_application
        j.set_current_application("kjwfuiwqhu220952gw")
        j.save()

        models.Journal.refresh()
        j = models.Journal.pull(j.id)
        assert j is not None

        # suggestion with journal
        s.set_owner("my_new_owner")
        s.set_current_journal(j.id)
        s.save()

        models.Journal.refresh()
        j = models.Journal.pull(j.id)
        assert j.owner == "my_new_owner"

        # journal with suggestion
        j.set_owner("another_new_owner")
        j.set_current_application(s.id)
        j.save()

        models.Suggestion.refresh()
        s = models.Suggestion.pull(s.id)
        assert s.owner == "another_new_owner"
Exemplo n.º 25
0
    def test_32_application_all_by_related_journal(self):
        j = models.Journal()
        j.set_id(j.makeid())

        app1 = models.Suggestion(
            **ApplicationFixtureFactory.make_application_source())
        app1.set_id(app1.makeid())
        app1.set_related_journal(j.id)
        app1.set_created("1970-01-01T00:00:00Z")
        app1.save()

        app2 = models.Suggestion(
            **ApplicationFixtureFactory.make_application_source())
        app2.set_id(app2.makeid())
        app2.set_related_journal(j.id)
        app2.set_created("1971-01-01T00:00:00Z")
        app2.save(blocking=True)

        # check that we find all the applications when we search, and that they're in the right order
        all = models.Suggestion.find_all_by_related_journal(j.id)
        assert len(all) == 2
        assert all[0].id == app1.id
        assert all[1].id == app2.id
Exemplo n.º 26
0
    def test_03_api_401(self):
        # make a user account for the authorisation test
        a1 = models.Account.make_account(username="******",
                                         name="a1_name",
                                         email="*****@*****.**",
                                         roles=["user", "api"],
                                         associated_journal_ids=[])
        a1_key = a1.api_key
        a1.save()  # a1 has api access

        # populate the index with an application owned by this owner
        a = models.Suggestion()
        a.set_owner("a1_user")
        bj = a.bibjson()
        bj.title = "Test Suggestion Title"
        bj.add_identifier(bj.P_ISSN, "0000-0000")
        bj.publisher = "Test Publisher"
        bj.add_url("http://homepage.com", "homepage")
        a.save()

        time.sleep(1)

        with self.app_test.test_client() as t_client:
            # a successful authenticated query, giving the right result
            response = t_client.get(
                '/api/v1/search/applications/issn%3A0000-0000?api_key=' +
                a1_key)
            assert response.status_code == 200
            # check we got a result by looking for something that must be in the results
            assert "Test Suggestion Title" in response.data

            # and a successful but empty search for an application that doesn't belong to them
            a.set_owner('not_a1_user')
            a.save()
            time.sleep(1)
            response = t_client.get(
                '/api/v1/search/applications/issn%3A0000-0000?api_key=' +
                a1_key)
            assert response.status_code == 200
            assert "Test Suggestion Title" not in response.data

            # and we expect a json 401 error if we fail to authenticate
            spurious_key = 'blahblahblah'
            response = t_client.get(
                '/api/v1/search/applications/issn%3A0000-0000?api_key=' +
                spurious_key)
            assert response.status_code == 401
            assert response.mimetype == 'application/json'
            assert "An API Key is required to access this." in response.data
Exemplo n.º 27
0
    def test_06_retrieve_application_success(self):
        # set up all the bits we need
        data = ApplicationFixtureFactory.make_update_request_source()
        ap = models.Suggestion(**data)
        ap.save()
        time.sleep(2)

        account = models.Account()
        account.set_id(ap.owner)
        account.set_name("Tester")
        account.set_email("*****@*****.**")

        # call retrieve on the object
        a = ApplicationsCrudApi.retrieve(ap.id, account)

        # check that we got back the object we expected
        assert isinstance(a, OutgoingApplication)
        assert a.id == ap.id
    def test_05_editor_revert_to_in_progress(self):
        """ Check that editors are permitted to revert applications from 'completed' to 'in progress' """

        acc = models.Account()
        acc.set_id("contextuser")
        acc.add_role("editor")
        ctx = self._make_and_push_test_context(acc=acc)

        # There should be an associate editor to receive an email when the status is changed
        associate_account = models.Account(
            **AccountFixtureFactory.make_assed1_source())
        associate_account.save(blocking=True)

        # Check that an editor can change from 'completed' to 'in progress' after a failed review
        completed_source = APPLICATION_SOURCE.copy()
        completed_source['admin'][
            'application_status'] = constants.APPLICATION_STATUS_COMPLETED

        in_progress_form = APPLICATION_FORM.copy()
        in_progress_form[
            'application_status'] = constants.APPLICATION_STATUS_IN_PROGRESS

        # Construct the formcontext from form data (with a known source)
        fc = formcontext.ApplicationFormFactory.get_form_context(
            role="editor",
            form_data=MultiDict(in_progress_form),
            source=models.Suggestion(**completed_source))

        assert isinstance(fc, formcontext.EditorApplicationReview)
        assert fc.form is not None
        assert fc.source is not None
        assert fc.form_data is not None

        # Finalise the formcontext. This should raise an exception because the application has already been accepted.
        fc.finalise()

        time.sleep(1.5)

        # now check that a provenance record was recorded
        prov = models.Provenance.get_latest_by_resource_id(fc.target.id)
        assert prov is not None

        ctx.pop()
Exemplo n.º 29
0
    def test_03_associate_review_complete(self):
        """Give the editor's application form a full workout"""
        acc = models.Account()
        acc.set_id("contextuser")
        acc.add_role("associate_editor")
        ctx = self._make_and_push_test_context(acc=acc)

        editor = models.Account()
        editor.set_id("editor")
        editor.set_email("*****@*****.**")
        editor.save()

        eg = models.EditorGroup()
        eg.set_name(APPLICATION_SOURCE["admin"]["editor_group"])
        eg.set_editor("editor")
        eg.add_associate("contextuser")
        eg.save()

        time.sleep(2)

        # construct a context from a form submission
        source = deepcopy(APPLICATION_FORM)
        source["application_status"] = constants.APPLICATION_STATUS_COMPLETED
        fd = MultiDict(source)
        fc = formcontext.ApplicationFormFactory.get_form_context(
            role="associate_editor",
            form_data=fd,
            source=models.Suggestion(**APPLICATION_SOURCE))

        fc.finalise()
        time.sleep(2)

        # now check that a provenance record was recorded
        count = 0
        for prov in models.Provenance.iterall():
            if prov.action == "edit":
                count += 1
            if prov.action == "status:completed":
                count += 10
        assert count == 11

        ctx.pop()
Exemplo n.º 30
0
    def test_05_outgoing_application_do(self):
        # make a blank one
        oa = OutgoingApplication()

        # make one from an incoming application model fixture
        data = ApplicationFixtureFactory.make_update_request_source()
        ap = models.Suggestion(**data)
        oa = OutgoingApplication.from_model(ap)

        # check that it does not contain information that it shouldn't
        assert oa.data.get("index") is None
        assert oa.data.get("history") is None
        assert oa.data.get("admin", {}).get("notes") is None
        assert oa.data.get("admin", {}).get("editor_group") is None
        assert oa.data.get("admin", {}).get("editor") is None
        assert oa.data.get("admin", {}).get("seal") is None
        assert oa.data.get("admin", {}).get("related_journal") is None

        # check that it does contain admin information that it should
        assert oa.data.get("admin", {}).get("current_journal") is not None