Coverage for sites/ptf_tools/history/views.py: 26%
126 statements
« prev ^ index » next coverage.py v7.3.2, created at 2024-11-04 17:46 +0000
« prev ^ index » next coverage.py v7.3.2, created at 2024-11-04 17:46 +0000
1import traceback
3from requests.exceptions import Timeout
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
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
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()])
27 print("exception for " + colid + " " + pid)
28 message = "<br>".join(message.split("\n"))
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 )
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
56 what = args[1]
57 list_ = what.split("-")
58 id_type = what if len(list_) == 0 else list_[0]
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]
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 )
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
95 except ServerUnderMaintenance as exception:
96 manage_exceptions("deploy", pid, colid, "ERROR", exception)
97 raise exception
99 except Exception as exception:
100 manage_exceptions("matching", pid, colid, "ERROR", exception)
101 raise exception
103 return id_value
105 return inner
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)
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)
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
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
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
163 args = (cls_inst, action) + args
165 execute_and_record_func("edit", pid, colid, func, message, False, *args, **kwargs)
167 return inner
170ptf_views.UpdateExtIdView.update_obj = edit_decorator(ptf_views.UpdateExtIdView.update_obj)
171ptf_views.UpdateMatchingView.update_obj = edit_decorator(ptf_views.UpdateMatchingView.update_obj)
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
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
188class HistoryView(TemplateView, HistoryContextMixin):
189 template_name = "history.html"
191 def get_context_data(self, **kwargs):
192 context = super().get_context_data(**kwargs)
194 context["collections"] = settings.MERSENNE_COLLECTIONS
196 all_filters = ["type", "col", "status", "month"]
197 filters = {}
199 for filter in all_filters:
200 value = self.request.GET.get(filter, None)
201 if value:
202 filters[filter] = value
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
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()
220 # events = get_history_events(filters)
221 # context['events'] = events
223 return context
226class HistoryClearView(DeleteView):
227 model = HistoryEvent
228 template_name_suffix = "_confirm_clear"
229 success_url = reverse_lazy("history")
231 def get_object(self):
232 return self.get_queryset().get_stale_events()
235class HistoryEventDeleteView(DeleteView):
236 model = HistoryEvent
237 success_url = reverse_lazy("history")