Coverage for src/history/views.py: 0%

125 statements  

« prev     ^ index     » next       coverage.py v7.7.0, created at 2025-04-09 14:54 +0000

1import traceback 

2 

3from django.conf import settings 

4from django.urls import reverse_lazy 

5from django.utils import timezone 

6from django.views.generic import TemplateView 

7from django.views.generic.base import ContextMixin 

8from django.views.generic.edit import DeleteView 

9from matching import matching 

10from ptf import views as ptf_views 

11from ptf.exceptions import ServerUnderMaintenance 

12from requests.exceptions import Timeout 

13 

14from history.models import ( 

15 HistoryEvent, 

16 get_history_error_warning_counts, 

17 get_history_events, 

18 insert_history_event, 

19) 

20 

21 

22def manage_exceptions(operation, pid, colid, status, exception, target=""): 

23 if type(exception).__name__ == "ServerUnderMaintenance": 

24 message = " - ".join([str(exception), "Please try again later"]) 

25 else: 

26 message = " - ".join([str(exception), traceback.format_exc()]) 

27 

28 print("exception for " + colid + " " + pid) 

29 message = "<br>".join(message.split("\n")) 

30 

31 insert_history_event( 

32 { 

33 "type": operation, 

34 "pid": pid, 

35 "col": colid, 

36 "status": status, 

37 "data": { 

38 "ids_count": 0, 

39 "message": message, 

40 "target": target, 

41 }, 

42 } 

43 ) 

44 

45 

46def matching_decorator(func, is_article): 

47 def inner(*args, **kwargs): 

48 seq = None 

49 if is_article: 

50 article = args[0] 

51 else: 

52 article = args[0].resource.cast() 

53 seq = args[0].sequence 

54 pid = article.pid 

55 colid = article.get_top_collection().pid 

56 

57 what = args[1] 

58 list_ = what.split("-") 

59 id_type = what if len(list_) == 0 else list_[0] 

60 

61 try: 

62 id_value = func(*args, **kwargs) 

63 if id_value: 

64 id_dict = {"type": id_type, "id": id_value} 

65 if seq: 

66 id_dict["seq"] = seq 

67 ids = [id_dict] 

68 

69 insert_history_event( 

70 { 

71 "type": "matching", 

72 "pid": pid, 

73 "col": colid, 

74 "status": "OK", 

75 "data": {"message": "", "ids_count": 1, "ids": ids}, 

76 } 

77 ) 

78 else: 

79 insert_history_event( 

80 { 

81 "type": "matching", 

82 "pid": pid, 

83 "col": colid, 

84 "status": "OK", 

85 "data": {"message": "", "ids_count": 0, "ids": []}, 

86 } 

87 ) 

88 

89 except Timeout as exception: 

90 """ 

91 Exception caused by the requests module: store it as a warning 

92 """ 

93 manage_exceptions("matching", pid, colid, "WARNING", exception) 

94 raise exception 

95 

96 except ServerUnderMaintenance as exception: 

97 manage_exceptions("deploy", pid, colid, "ERROR", exception) 

98 raise exception 

99 

100 except Exception as exception: 

101 manage_exceptions("matching", pid, colid, "ERROR", exception) 

102 raise exception 

103 

104 return id_value 

105 

106 return inner 

107 

108 

109# decorate matching.match_bibitem and match_article 

110matching.match_bibitem = matching_decorator(matching.match_bibitem, False) 

111matching.match_article = matching_decorator(matching.match_article, True) 

112 

113 

114def execute_and_record_func( 

115 type, pid, colid, func, message="", record_error_only=False, *func_args, **func_kwargs 

116): 

117 status = 200 

118 func_result = None 

119 try: 

120 func_result = func(*func_args, **func_kwargs) 

121 

122 if not record_error_only: 

123 insert_history_event( 

124 { 

125 "type": type, 

126 "pid": pid, 

127 "col": colid, 

128 "status": "OK", 

129 "data": {"message": message}, 

130 } 

131 ) 

132 except Timeout as exception: 

133 """ 

134 Exception caused by the requests module: store it as a warning 

135 """ 

136 manage_exceptions(type, pid, colid, "WARNING", exception, target=message) 

137 raise exception 

138 except Exception as exception: 

139 manage_exceptions(type, pid, colid, "ERROR", exception, target=message) 

140 raise exception 

141 return func_result, status, message 

142 

143 

144def edit_decorator(func): 

145 def inner(cls_inst, action, *args, **kwargs): 

146 resource_obj = cls_inst.resource.cast() 

147 pid = resource_obj.pid 

148 colid = resource_obj.get_top_collection().pid 

149 

150 message = "" 

151 if hasattr(cls_inst, "obj"): 

152 # Edit 1 item (ExtId or BibItemId) 

153 obj = cls_inst.obj 

154 if hasattr(cls_inst, "parent"): 

155 parent = cls_inst.parent 

156 if parent: 

157 message += "[" + str(parent.sequence) + "] " 

158 list_ = obj.id_type.split("-") 

159 id_type = obj.id_type if len(list_) == 0 else list_[0] 

160 message += id_type + ":" + obj.id_value + " " + action 

161 else: 

162 message += "All " + action 

163 

164 args = (cls_inst, action) + args 

165 

166 execute_and_record_func("edit", pid, colid, func, message, False, *args, **kwargs) 

167 

168 return inner 

169 

170 

171ptf_views.UpdateExtIdView.update_obj = edit_decorator(ptf_views.UpdateExtIdView.update_obj) 

172ptf_views.UpdateMatchingView.update_obj = edit_decorator(ptf_views.UpdateMatchingView.update_obj) 

173 

174 

175class HistoryContextMixin(ContextMixin): 

176 def get_context_data(self, **kwargs): 

177 context = super().get_context_data(**kwargs) 

178 error_count, warning_count = get_history_error_warning_counts() 

179 context["warning_count"] = warning_count 

180 context["error_count"] = error_count 

181 

182 # if isinstance(last_clockss_event, datetime): 

183 # now = timezone.now() 

184 # td = now - last_clockss_event['created_on'] 

185 # context['last_clockss_event'] = td.days 

186 return context 

187 

188 

189class HistoryView(TemplateView, HistoryContextMixin): 

190 template_name = "history.html" 

191 

192 def get_context_data(self, **kwargs): 

193 context = super().get_context_data(**kwargs) 

194 

195 context["collections"] = settings.MERSENNE_COLLECTIONS 

196 

197 all_filters = ["type", "col", "status", "month"] 

198 filters = {} 

199 

200 for filter in all_filters: 

201 value = self.request.GET.get(filter, None) 

202 if value: 

203 filters[filter] = value 

204 

205 params = [ 

206 f"{key}={value}" 

207 for key, value in self.request.GET.items() 

208 if key not in [filter, "page", "search"] 

209 ] 

210 # Insert empty string to make sure '&' is added before the first param 

211 params.insert(0, "") 

212 params_str = "&".join(params) 

213 context[filter + "_link"] = "?search=" + params_str 

214 

215 # MongoDB can create groups, SQL does not 

216 # We use the Django template 'regroup' builtin function to regroup the events in the template 

217 grouped_events = get_history_events(filters) 

218 context["grouped_events"] = grouped_events 

219 context["now"] = timezone.now() 

220 

221 # events = get_history_events(filters) 

222 # context['events'] = events 

223 

224 return context 

225 

226 

227class HistoryClearView(DeleteView): 

228 model = HistoryEvent 

229 template_name_suffix = "_confirm_clear" 

230 success_url = reverse_lazy("history") 

231 

232 def get_object(self): 

233 return self.get_queryset().get_stale_events() 

234 

235 

236class HistoryEventDeleteView(DeleteView): 

237 model = HistoryEvent 

238 success_url = reverse_lazy("history")