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