Coverage for portality / tasks / journal_in_out_doaj.py: 82%

112 statements  

« prev     ^ index     » next       coverage.py v7.13.5, created at 2026-05-04 09:41 +0100

1from flask_login import current_user 

2from portality import models, lock 

3from portality.bll import DOAJ 

4from portality.core import app 

5from portality.lib import dates 

6 

7from portality.tasks.redis_huey import events_queue as queue 

8from portality.decorators import write_required 

9 

10from portality.background import BackgroundTask, BackgroundApi, BackgroundSummary 

11 

12import json 

13 

14from portality.ui.messages import Messages 

15 

16 

17def change_by_query(query, in_doaj_new_val, dry_run=True): 

18 ids = [] 

19 sane = {} 

20 sane["query"] = query["query"] 

21 job = None 

22 for j in models.Journal.iterate(sane, wrap=False): 

23 ids.append(j.get("id")) 

24 if not dry_run: 

25 job = change_in_doaj(ids, in_doaj_new_val, selection_query=sane) 

26 

27 affected = len(ids) 

28 job_id = None 

29 if job is not None: 

30 job_id = job.id 

31 return BackgroundSummary(job_id, affected={"journals" : affected}) 

32 

33 # return len(ids) 

34 

35def change_in_doaj(journal_ids, in_doaj_new_val, **kwargs): 

36 job = SetInDOAJBackgroundTask.prepare(current_user.id, journal_ids=journal_ids, in_doaj=in_doaj_new_val, **kwargs) 

37 SetInDOAJBackgroundTask.submit(job) 

38 return job 

39 

40def find_matching_issns_in_doaj(journal_ids): 

41 if not isinstance(journal_ids, list): 

42 journal_ids = [journal_ids] 

43 with_matches = [] 

44 for journal_id in journal_ids: 

45 j = models.Journal.pull(journal_id) 

46 other_with_the_same_issns = models.Journal.find_by_issn(j.bibjson().issns()) 

47 if len([j for j in other_with_the_same_issns if j.is_in_doaj()]) > 0: 

48 with_matches.append(journal_id) 

49 return with_matches 

50 

51class SetInDOAJBackgroundTask(BackgroundTask): 

52 # ~~SetInDOAJBackgroundTask:Process->BackgroundTask:Process~~ 

53 __action__ = "set_in_doaj" 

54 

55 def run(self): 

56 """ 

57 Execute the task as specified by the background_jon 

58 :return: 

59 """ 

60 job = self.background_job 

61 params = job.params 

62 

63 journal_ids = self.get_param(params, "journal_ids") 

64 in_doaj = self.get_param(params, "in_doaj") 

65 

66 if journal_ids is None or len(journal_ids) == 0 or in_doaj is None: 

67 raise RuntimeError("SetInDOAJBackgroundTask.run run without sufficient parameters") 

68 

69 # preliminary check to see whether we can change the status of all requested journals 

70 if in_doaj: 

71 matching_issns = find_matching_issns_in_doaj(journal_ids) 

72 if matching_issns: 

73 job.add_audit_message( 

74 Messages.CANNOT_CHANGE_THE_STATUS__OTHER_JOURNAL_IN_DOAJ_EXISTS) 

75 job.outcome_fail() 

76 return job 

77 

78 for journal_id in journal_ids: 

79 job.add_audit_message("Setting in_doaj to {x} for journal {y}".format(x=str(in_doaj), y=journal_id)) 

80 # ~~->Journal:Model~~ 

81 j = models.Journal.pull(journal_id) 

82 

83 # ~~->Account:Model~~ 

84 account = models.Account.pull(job.user) 

85 if j is None: 

86 raise RuntimeError("Journal with id {} does not exist".format(journal_id)) 

87 

88 current_in_doaj = j.is_in_doaj() 

89 if in_doaj and not current_in_doaj: 

90 j.last_reinstated = dates.now_str() 

91 j.add_note(Messages.JOURNAL_REINSTATED_NOTE.format(username=job.user, date=dates.now_str()), author_id=job.user) 

92 

93 if not in_doaj: 

94 if current_in_doaj: 

95 j.last_withdrawn = dates.now_str() 

96 j.add_note(Messages.JOURNAL_WITHDRAWN_NOTE.format(username=job.user, date=dates.now_str()), author_id=job.user) 

97 

98 # Rejecting associated update request 

99 # ~~->Application:Service~~ 

100 svc = DOAJ.applicationService() 

101 ur = svc.reject_update_request_of_journal(j.id, account) 

102 if ur: 

103 job.add_audit_message(Messages.AUTOMATICALLY_REJECTED_UPDATE_REQUEST_WITH_ID.format(urid=ur)) 

104 else: 

105 job.add_audit_message(Messages.NO_UPDATE_REQUESTS) 

106 

107 

108 j.bibjson().active = in_doaj 

109 j.set_in_doaj(in_doaj) 

110 j.save() 

111 j.propagate_in_doaj_status_to_articles() # will save each article, could take a while 

112 job.add_audit_message("Journal {x} set in_doaj to {y}, and all associated articles".format(x=journal_id, y=str(in_doaj))) 

113 

114 def cleanup(self): 

115 """ 

116 Cleanup after a successful OR failed run of the task 

117 :return: 

118 """ 

119 # remove the lock on the journal 

120 job = self.background_job 

121 params = job.params 

122 journal_ids = self.get_param(params, "journal_ids") 

123 username = job.user 

124 

125 lock.batch_unlock("journal", journal_ids, username) 

126 

127 @classmethod 

128 def prepare(cls, username, **kwargs): 

129 """ 

130 Take an arbitrary set of keyword arguments and return an instance of a BackgroundJob, 

131 or fail with a suitable exception 

132 

133 :param kwargs: arbitrary keyword arguments pertaining to this task type 

134 :return: a BackgroundJob instance representing this task 

135 """ 

136 

137 # first prepare a job record 

138 job = models.BackgroundJob() 

139 job.user = username 

140 job.action = cls.__action__ 

141 

142 journal_ids = kwargs.get("journal_ids") 

143 

144 params = {} 

145 cls.set_param(params, "journal_ids", journal_ids) 

146 cls.set_param(params, "in_doaj", kwargs.get("in_doaj")) 

147 

148 if journal_ids is None or len(journal_ids) == 0 or kwargs.get("in_doaj") is None: 

149 raise RuntimeError("SetInDOAJBackgroundTask.prepare run without sufficient parameters") 

150 

151 job.params = params 

152 job.queue_id = huey_helper.queue_id 

153 

154 if "selection_query" in kwargs: 

155 refs = {} 

156 cls.set_reference(refs, "selection_query", json.dumps(kwargs.get('selection_query'))) 

157 job.reference = refs 

158 

159 # now ensure that we have the locks for this journal 

160 # will raise an exception if this fails 

161 lock.batch_lock("journal", journal_ids, username, timeout=app.config.get("BACKGROUND_TASK_LOCK_TIMEOUT", 3600)) 

162 

163 return job 

164 

165 @classmethod 

166 def submit(cls, background_job): 

167 """ 

168 Submit the specified BackgroundJob to the background queue 

169 

170 :param background_job: the BackgroundJob instance 

171 :return: 

172 """ 

173 background_job.save() 

174 set_in_doaj.schedule(args=(background_job.id,), delay=app.config.get('HUEY_ASYNC_DELAY', 10)) 

175 

176 

177huey_helper = SetInDOAJBackgroundTask.create_huey_helper(queue) 

178 

179 

180@huey_helper.register_execute(is_load_config=False) 

181def set_in_doaj(job_id): 

182 job = models.BackgroundJob.pull(job_id) 

183 task = SetInDOAJBackgroundTask(job) 

184 BackgroundApi.execute(task)