Coverage for portality / tasks / admin_reports.py: 26%

85 statements  

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

1from portality import models 

2from portality.background import BackgroundTask, BackgroundApi 

3from portality.bll.doaj import DOAJ 

4from portality.core import app 

5from portality.tasks.helpers import background_helper 

6from portality.tasks.redis_huey import events_queue as queue 

7from portality import constants 

8from portality.util import url_for 

9 

10import json 

11 

12 

13class AdminReportsBackgroundTask(BackgroundTask): 

14 

15 __action__ = "admin_reports" 

16 

17 MODELS = { 

18 "journal": models.Journal, 

19 "application": models.Application 

20 } 

21 

22 def __init__(self, background_job): 

23 super(AdminReportsBackgroundTask, self).__init__(background_job) 

24 self.filename = None 

25 

26 def run(self): 

27 """ 

28 Execute the task as specified by the background_job  

29 :return: 

30 """ 

31 job = self.background_job 

32 

33 params = job.params 

34 model_type = self.get_param(params, "model", "journal") 

35 query_raw = self.get_param(params, "query", None) 

36 ui_query_raw = self.get_param(params, "ui_query", None) 

37 name = self.get_param(params, "name", None) 

38 notes = self.get_param(params, "notes", False) 

39 

40 model = self.MODELS.get(model_type, models.Journal) 

41 query = json.loads(query_raw) if query_raw is not None else None 

42 

43 def serialise_notes(obj): 

44 """ 

45 Serialise the notes for a journal or application object 

46 :param obj: a models.Journal or models.Application 

47 :return: a list of notes in the order they were added 

48 """ 

49 out = "" 

50 if hasattr(obj, "ordered_notes"): 

51 notes = obj.ordered_notes 

52 for n in notes: 

53 d = n.get("date", "unknown date") 

54 a = n.get("author_id", "unknown author") 

55 note = n.get("note", "") 

56 out += f"[{d}] {a}: {note}\n\n" 

57 return ("Notes", out.strip()) 

58 

59 custom_columns = [] 

60 if notes: 

61 job.add_audit_message("Export requested with notes") 

62 custom_columns.append(serialise_notes) 

63 

64 # generate the admin csv in the temp store 

65 export_svc = DOAJ.exportService() 

66 filepath, filename = export_svc.csv(model, query, 

67 admin_fieldset=True, 

68 obscure_accounts=False, 

69 add_sensitive_account_info=True, 

70 exclude_no_issn=False, 

71 custom_columns=custom_columns, 

72 ) 

73 self.filename = filename 

74 

75 # publish it to the main store and record its existence 

76 export = export_svc.publish(filepath, filename, requester=job.user, request_date=job.created_date, name=name, query=ui_query_raw, model=model_type) 

77 job.add_audit_message("Export generated with id {id}".format(id=export.id)) 

78 

79 # send a notification to the requesting user 

80 notify_svc = DOAJ.notificationsService() 

81 

82 # note we're using the doaj url_for wrapper, not the flask url_for directly, due to the request context hack required 

83 url = url_for("admin.get_report", report_id=export.id) 

84 

85 source_id = "bg:job:" + self.__action__ + ":export_available" 

86 

87 notification = models.Notification() 

88 notification.who = job.user 

89 notification.created_by = source_id 

90 notification.classification = constants.NOTIFICATION_CLASSIFICATION_FINISHED 

91 notification.long = notify_svc.long_notification(source_id).format(name=name) 

92 notification.short = notify_svc.short_notification(source_id).format(name=name) 

93 notification.action = url 

94 notify_svc.notify(notification) 

95 

96 def cleanup(self): 

97 """ 

98 Cleanup after a successful OR failed run of the task 

99 :return: 

100 """ 

101 if self.filename is not None: 

102 export_svc = DOAJ.exportService() 

103 export_svc.delete_tmp_csv(self.filename) 

104 self.filename = None 

105 

106 @classmethod 

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

108 """ 

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

110 or fail with a suitable exception 

111 

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

113 :return: a BackgroundJob instance representing this task 

114 """ 

115 # prepare a job record 

116 model = kwargs.get("model", "journal") 

117 query = kwargs.get("true_query", None) 

118 ui_query = kwargs.get("ui_query", None) 

119 name = kwargs.get("name", None) 

120 notes = kwargs.get("notes", False) 

121 

122 params = {} 

123 cls.set_param(params, "model", model) 

124 cls.set_param(params, "query", json.dumps(query)) 

125 cls.set_param(params, "ui_query", json.dumps(ui_query)) 

126 cls.set_param(params, "name", name) 

127 cls.set_param(params, "notes", notes) 

128 

129 # first prepare a job record 

130 job = background_helper.create_job(username=username, 

131 action=cls.__action__, 

132 params=params, 

133 queue_id=huey_helper.queue_id, ) 

134 

135 return job 

136 

137 @classmethod 

138 def submit(cls, background_job): 

139 """ 

140 Submit the specified BackgroundJob to the background queue 

141 

142 :param background_job: the BackgroundJob instance 

143 :return: 

144 """ 

145 background_job.save() 

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

147 

148 

149huey_helper = AdminReportsBackgroundTask.create_huey_helper(queue) 

150 

151 

152@huey_helper.register_execute(is_load_config=False) 

153def admin_reports(job_id): 

154 job = models.BackgroundJob.pull(job_id) 

155 task = AdminReportsBackgroundTask(job) 

156 BackgroundApi.execute(task)