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
« prev ^ index » next coverage.py v7.7.0, created at 2025-04-09 14:54 +0000
1import traceback
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
14from history.models import (
15 HistoryEvent,
16 get_history_error_warning_counts,
17 get_history_events,
18 insert_history_event,
19)
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()])
28 print("exception for " + colid + " " + pid)
29 message = "<br>".join(message.split("\n"))
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 )
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
57 what = args[1]
58 list_ = what.split("-")
59 id_type = what if len(list_) == 0 else list_[0]
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]
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 )
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
96 except ServerUnderMaintenance as exception:
97 manage_exceptions("deploy", pid, colid, "ERROR", exception)
98 raise exception
100 except Exception as exception:
101 manage_exceptions("matching", pid, colid, "ERROR", exception)
102 raise exception
104 return id_value
106 return inner
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)
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)
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
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
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
164 args = (cls_inst, action) + args
166 execute_and_record_func("edit", pid, colid, func, message, False, *args, **kwargs)
168 return inner
171ptf_views.UpdateExtIdView.update_obj = edit_decorator(ptf_views.UpdateExtIdView.update_obj)
172ptf_views.UpdateMatchingView.update_obj = edit_decorator(ptf_views.UpdateMatchingView.update_obj)
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
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
189class HistoryView(TemplateView, HistoryContextMixin):
190 template_name = "history.html"
192 def get_context_data(self, **kwargs):
193 context = super().get_context_data(**kwargs)
195 context["collections"] = settings.MERSENNE_COLLECTIONS
197 all_filters = ["type", "col", "status", "month"]
198 filters = {}
200 for filter in all_filters:
201 value = self.request.GET.get(filter, None)
202 if value:
203 filters[filter] = value
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
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()
221 # events = get_history_events(filters)
222 # context['events'] = events
224 return context
227class HistoryClearView(DeleteView):
228 model = HistoryEvent
229 template_name_suffix = "_confirm_clear"
230 success_url = reverse_lazy("history")
232 def get_object(self):
233 return self.get_queryset().get_stale_events()
236class HistoryEventDeleteView(DeleteView):
237 model = HistoryEvent
238 success_url = reverse_lazy("history")