Coverage for portality/api/current/bulk/articles.py: 61%

51 statements  

« prev     ^ index     » next       coverage.py v6.4.2, created at 2022-07-20 16:12 +0100

1# ~~APIBulkArticles:Feature->APIBulk:Feature~~ 

2from portality.api.common import Api, Api404Error, Api400Error, Api403Error, Api401Error 

3from portality.api.current.crud import ArticlesCrudApi 

4 

5from portality.bll import DOAJ 

6from portality.bll import exceptions 

7 

8from copy import deepcopy 

9 

10from portality.bll.exceptions import DuplicateArticleException 

11 

12 

13class ArticlesBulkApi(Api): 

14 

15 #~~->Swagger:Feature~~ 

16 # ~~->API:Documentation~~ 

17 SWAG_TAG = 'Bulk API' 

18 

19 @classmethod 

20 def create_swag(cls): 

21 template = deepcopy(cls.SWAG_TEMPLATE) 

22 template['parameters'].append( 

23 { 

24 "description": "<div class=\"search-query-docs\">A list/array of article JSON objects that you would like to create or update. The contents should be a list, and each object in the list should comply with the schema displayed in the <a href=\"/api/docs#CRUD_Articles_get_api_articles_article_id\"> GET (Retrieve) an article route</a>. Partial updates are not allowed, you have to supply the full JSON.</div>", 

25 "required": True, 

26 "schema": {"type" : "string"}, 

27 "name": "article_json", 

28 "in": "body" 

29 } 

30 ) 

31 template['parameters'].append(cls.SWAG_API_KEY_REQ_PARAM) 

32 template['responses']['201'] = cls.R201_BULK 

33 template['responses']['400'] = cls.R400 

34 template['responses']['401'] = cls.R401 

35 template['responses']['403'] = cls.R403 

36 return cls._build_swag_response(template) 

37 

38 @classmethod 

39 def create(cls, articles, account): 

40 # We run through the articles once, validating in dry-run mode 

41 # and deduplicating as we go. Then we .save() everything once 

42 # we know all incoming articles are valid. 

43 

44 # as long as authentication (in the layer above) has been successful, and the account exists, then 

45 # we are good to proceed 

46 if account is None: 

47 raise Api401Error() 

48 

49 # convert the data into a suitable article models 

50 articles = [ArticlesCrudApi.prep_article(data, account) for data in articles] 

51 

52 # ~~->Article:Service~~ 

53 articleService = DOAJ.articleService() 

54 try: 

55 # ~~->BatchCreateArticles:Feature~~ 

56 result = articleService.batch_create_articles(articles, account, add_journal_info=True) 

57 return [a.id for a in articles] 

58 except DuplicateArticleException as e: 

59 raise Api403Error(str(e)) 

60 except exceptions.IngestException as e: 

61 raise Api400Error(str(e)) 

62 

63 

64 @classmethod 

65 def delete_swag(cls): 

66 template = deepcopy(cls.SWAG_TEMPLATE) 

67 template['parameters'].append( 

68 { 

69 "description": "<div class=\"search-query-docs\">A list/array of DOAJ article IDs. E.g. [\"4cf8b72139a749c88d043129f00e1b07\", \"232b53726fb74cc4a8eb4717e5a43193\"].</div>", 

70 "required": True, 

71 "schema": {"type" : "string"}, 

72 "name": "article_ids", 

73 "in": "body" 

74 } 

75 ) 

76 template['parameters'].append(cls.SWAG_API_KEY_REQ_PARAM) 

77 template['responses']['204'] = cls.R204 

78 template['responses']['400'] = cls.R400 

79 template['responses']['401'] = cls.R401 

80 return cls._build_swag_response(template) 

81 

82 @classmethod 

83 def delete(cls, article_ids, account): 

84 # we run through delete twice, once as a dry-run and the second time 

85 # as the real deal 

86 # ~~->APICrudArticles:Feature~~ 

87 for id in article_ids: 

88 try: 

89 ArticlesCrudApi.delete(id, account, dry_run=True) 

90 except Api404Error as e: 

91 raise Api400Error("Id {x} does not exist or does not belong to this user account".format(x=id)) 

92 except Api403Error as e: 

93 raise Api400Error("Id {x} is not in a state which allows it to be deleted".format(x=id)) 

94 

95 for id in article_ids: 

96 ArticlesCrudApi.delete(id, account)