Coverage for sites/ptf_tools/history/views.py: 26%

126 statements  

« prev     ^ index     » next       coverage.py v7.4.4, created at 2024-05-19 19:20 +0000

1import traceback 

2 

3from requests.exceptions import Timeout 

4 

5from django.conf import settings 

6from django.urls import reverse_lazy 

7from django.utils import timezone 

8from django.views.generic import TemplateView 

9from django.views.generic.base import ContextMixin 

10from django.views.generic.edit import DeleteView 

11 

12from history.models import HistoryEvent 

13from history.models import get_history_error_warning_counts 

14from history.models import get_history_events 

15from history.models import insert_history_event 

16from matching import matching 

17from ptf import views as ptf_views 

18from ptf.exceptions import ServerUnderMaintenance 

19 

20 

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

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

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

24 else: 

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

26 

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

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

29 

30 insert_history_event( 

31 { 

32 "type": operation, 

33 "pid": pid, 

34 "col": colid, 

35 "status": status, 

36 "data": { 

37 "ids_count": 0, 

38 "message": message, 

39 "target": target, 

40 }, 

41 } 

42 ) 

43 

44 

45def matching_decorator(func, is_article): 

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

47 seq = None 

48 if is_article: 

49 article = args[0] 

50 else: 

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

52 seq = args[0].sequence 

53 pid = article.pid 

54 colid = article.get_top_collection().pid 

55 

56 what = args[1] 

57 list_ = what.split("-") 

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

59 

60 try: 

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

62 if id_value: 

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

64 if seq: 

65 id_dict["seq"] = seq 

66 ids = [id_dict] 

67 

68 insert_history_event( 

69 { 

70 "type": "matching", 

71 "pid": pid, 

72 "col": colid, 

73 "status": "OK", 

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

75 } 

76 ) 

77 else: 

78 insert_history_event( 

79 { 

80 "type": "matching", 

81 "pid": pid, 

82 "col": colid, 

83 "status": "OK", 

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

85 } 

86 ) 

87 

88 except Timeout as exception: 

89 """ 

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

91 """ 

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

93 raise exception 

94 

95 except ServerUnderMaintenance as exception: 

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

97 raise exception 

98 

99 except Exception as exception: 

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

101 raise exception 

102 

103 return id_value 

104 

105 return inner 

106 

107 

108# decorate matching.match_bibitem and match_article 

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

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

111 

112 

113def execute_and_record_func( 

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

115): 

116 status = 200 

117 func_result = None 

118 try: 

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

120 

121 if not record_error_only: 

122 insert_history_event( 

123 { 

124 "type": type, 

125 "pid": pid, 

126 "col": colid, 

127 "status": "OK", 

128 "data": {"message": message}, 

129 } 

130 ) 

131 except Timeout as exception: 

132 """ 

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

134 """ 

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

136 raise exception 

137 except Exception as exception: 

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

139 raise exception 

140 return func_result, status, message 

141 

142 

143def edit_decorator(func): 

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

145 resource_obj = cls_inst.resource.cast() 

146 pid = resource_obj.pid 

147 colid = resource_obj.get_top_collection().pid 

148 

149 message = "" 

150 if hasattr(cls_inst, "obj"): 

151 # Edit 1 item (ExtId or BibItemId) 

152 obj = cls_inst.obj 

153 if hasattr(cls_inst, "parent"): 

154 parent = cls_inst.parent 

155 if parent: 

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

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

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

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

160 else: 

161 message += "All " + action 

162 

163 args = (cls_inst, action) + args 

164 

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

166 

167 return inner 

168 

169 

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

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

172 

173 

174class HistoryContextMixin(ContextMixin): 

175 def get_context_data(self, **kwargs): 

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

177 error_count, warning_count = get_history_error_warning_counts() 

178 context["warning_count"] = warning_count 

179 context["error_count"] = error_count 

180 

181 # if isinstance(last_clockss_event, datetime): 

182 # now = timezone.now() 

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

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

185 return context 

186 

187 

188class HistoryView(TemplateView, HistoryContextMixin): 

189 template_name = "history.html" 

190 

191 def get_context_data(self, **kwargs): 

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

193 

194 context["collections"] = settings.MERSENNE_COLLECTIONS 

195 

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

197 filters = {} 

198 

199 for filter in all_filters: 

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

201 if value: 

202 filters[filter] = value 

203 

204 params = [ 

205 f"{key}={value}" 

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

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

208 ] 

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

210 params.insert(0, "") 

211 params_str = "&".join(params) 

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

213 

214 # MongoDB can create groups, SQL does not 

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

216 grouped_events = get_history_events(filters) 

217 context["grouped_events"] = grouped_events 

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

219 

220 # events = get_history_events(filters) 

221 # context['events'] = events 

222 

223 return context 

224 

225 

226class HistoryClearView(DeleteView): 

227 model = HistoryEvent 

228 template_name_suffix = "_confirm_clear" 

229 success_url = reverse_lazy("history") 

230 

231 def get_object(self): 

232 return self.get_queryset().get_stale_events() 

233 

234 

235class HistoryEventDeleteView(DeleteView): 

236 model = HistoryEvent 

237 success_url = reverse_lazy("history")