Example #1
0
def search_articles(search_query):
    # get the values for the 2 other bits of search info: the page number and the page size
    page = request.values.get("page", 1)
    psize = request.values.get("pageSize", 10)
    sort = request.values.get("sort")

    # check the page is an integer
    try:
        page = int(page)
    except:
        raise Api400Error("Page number was not an integer")

    # check the page size is an integer
    try:
        psize = int(psize)
    except:
        raise Api400Error("Page size was not an integer")

    results = None
    try:
        results = DiscoveryApi.search('article', None, search_query, page, psize, sort)
    except DiscoveryException as e:
        raise Api400Error(str(e))

    return jsonify_models(results)
Example #2
0
    def retrieve(cls, jid, account):
        # is the journal id valid
        try:
            j = models.Journal.pull(jid)
        except Exception as e:
            raise Api400Error(str(e))
        if j is None:
            raise Api404Error()

        # at this point we're happy to return the journal if it's
        # meant to be seen by the public
        if j.is_in_doaj():
            return OutgoingJournal.from_model(j)

        # 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()

        # this journal's metadata is not currently published in DOAJ, so
        # we need to check ownership
        # is the current account the owner of the journal
        # if not we raise a 404 because that id does not exist for that user account.
        if account.is_anonymous or j.owner != account.id:
            raise Api404Error()

        return OutgoingJournal.from_model(j)
Example #3
0
def bulk_article_delete():
    # get the data from the request
    try:
        data = json.loads(request.data.decode("utf-8"))
    except:
        raise Api400Error("Supplied data was not valid JSON")

    ArticlesBulkApi.delete(data, current_user._get_current_object())

    return no_content()
Example #4
0
def bulk_application_delete():
    # get the data from the request
    try:
        data = json.loads(request.data)
    except:
        raise Api400Error("Supplied data was not valid JSON")

    ApplicationsBulkApi.delete(data, current_user)

    return no_content()
Example #5
0
def update_article(article_id):
    # get the data from the request
    try:
        data = json.loads(request.data.decode("utf-8"))
    except:
        raise Api400Error("Supplied data was not valid JSON")

    # delegate to the API implementation
    ArticlesCrudApi.update(article_id, data, current_user)

    # respond with a suitable No Content successful response
    return no_content()
Example #6
0
def create_article():
    # get the data from the request
    try:
        data = json.loads(request.data.decode("utf-8"))
    except:
        raise Api400Error("Supplied data was not valid JSON")

    # delegate to the API implementation
    a = ArticlesCrudApi.create(data, current_user._get_current_object())

    # respond with a suitable Created response
    return created(a, url_for("api_v1.retrieve_article", article_id=a.id))
Example #7
0
def update_application(application_id):
    # get the data from the request
    try:
        data = json.loads(request.data)
    except:
        raise Api400Error("Supplied data was not valid JSON")

    # delegate to the API implementation
    ApplicationsCrudApi.update(application_id, data,
                               current_user._get_current_object())

    # respond with a suitable No Content successful response
    return no_content()
Example #8
0
    def create(cls, 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()

        # convert the data into a suitable article model (raises Api400Error if doesn't conform to struct)
        am = cls.prep_article(data)

        articleService = DOAJ.articleService()
        try:
            result = articleService.create_article(am, account, add_journal_info=True)
        except ArticleMergeConflict as e:
            raise Api400Error(str(e))
        except ArticleNotAcceptable as e:
            raise Api400Error("; ".join(e.errors))
        except exceptions.DuplicateArticleException as e:
            raise Api403Error(str(e))

        # Check we are allowed to create an article for this journal
        if result.get("fail", 0) == 1:
            raise Api403Error("It is not possible to create an article for this journal. Have you included in the upload an ISSN which is not associated with any journal in your account? ISSNs must match exactly the ISSNs against the journal record.")

        return am
Example #9
0
    def create(cls, 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()

        # convert the data into a suitable article model
        am = cls.prep_article(data)

        articleService = DOAJ.articleService()
        try:
            result = articleService.create_article(am,
                                                   account,
                                                   add_journal_info=True)
        except ArticleMergeConflict as e:
            raise Api400Error(e.message)
        except ArticleNotAcceptable as e:
            raise Api400Error("; ".join(e.errors))

        # Check we are allowed to create an article for this journal
        if result.get("fail", 0) == 1:
            raise Api403Error()

        return am
Example #10
0
def bulk_article_create():
    # get the data from the request
    try:
        data = json.loads(request.data.decode("utf-8"))
    except:
        raise Api400Error("Supplied data was not valid JSON")

    # delegate to the API implementation
    ids = ArticlesBulkApi.create(data, current_user._get_current_object())

    # get all the locations for the ids
    inl = []
    for id in ids:
        inl.append((id, url_for("api_v1.retrieve_article", article_id=id)))

    # respond with a suitable Created response
    return bulk_created(inl)
Example #11
0
    def __handle_journal_info(cls, am):
        # handle journal info - first save fields users ARE allowed to update into temporary vars
        number = am.bibjson().number
        volume = am.bibjson().volume
        start_page = am.bibjson().start_page
        end_page = am.bibjson().end_page
        am.bibjson().remove_journal_metadata()  # then destroy all journal metadata

        try:
            am.add_journal_metadata()  # overwrite journal part of metadata and in_doaj setting
        except models.NoJournalException as e:
            raise Api400Error("No journal found to attach article to. Each article in DOAJ must belong to a journal and the (E)ISSNs provided in the bibjson.identifiers section of this article record do not match any DOAJ journal.")

        # restore the user's data
        am.bibjson().number = number
        am.bibjson().volume = volume
        am.bibjson().start_page = start_page
        am.bibjson().end_page = end_page
        return am
Example #12
0
    def prep_article(cls, data):
        # first thing to do is a structural validation, by instantiating the data object
        try:
            ia = IncomingArticleDO(data)
        except dataobj.DataStructureException as e:
            raise Api400Error(str(e))

        # if that works, convert it to an Article object
        am = ia.to_article_model()

        # the user may have supplied metadata in the model for id and created_date
        # and we want to can that data.  If this is a truly new article its fine for
        # us to assign a new id here, and if it's a duplicate, it will get attached
        # to its duplicate id anyway.
        am.set_id()
        am.set_created()

        # not allowed to set subjects
        am.bibjson().remove_subjects()

        # get the journal information set straight
        am = cls.__handle_journal_info(am)

        return am
Example #13
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()

        # now see if there's something for us to delete
        ar = models.Article.pull(id)
        if ar is None:
            raise Api404Error()

        # Check we're allowed to edit this article
        articleService = DOAJ.articleService()
        if not articleService.is_legitimate_owner(ar, account.id):
            raise Api404Error()  # not found for this account

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

        # if that works, convert it to an Article object bringing over everything outside the
        # incoming article from the original article
        new_ar = ia.to_article_model(ar)

        # we need to ensure that any properties of the existing article that aren't allowed to change
        # are copied over
        new_ar.set_id(id)
        new_ar.set_created(ar.created_date)
        new_ar.bibjson().set_subjects(ar.bibjson().subjects())
        new_ar = cls.__handle_journal_info(new_ar)

        # finally save the new article, and return to the caller
        new_ar.save()
        return new_ar
Example #14
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))
Example #15
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))