Coverage for CIResults/bugs_views.py: 100%
117 statements
« prev ^ index » next coverage.py v7.6.9, created at 2024-12-19 09:20 +0000
« prev ^ index » next coverage.py v7.6.9, created at 2024-12-19 09:20 +0000
1from django.contrib import messages
2from django.contrib.auth.mixins import LoginRequiredMixin, PermissionRequiredMixin
3from django.contrib.auth.decorators import permission_required
4from django.db import transaction
5from django.shortcuts import render, get_object_or_404
6from django.http import JsonResponse
7from django.db.models import Prefetch
8from django.utils import timezone
9from django.views.decorators.http import require_http_methods, require_POST
10from django.views.generic import ListView
11from django.views.generic.edit import CreateView, UpdateView
12from django.urls import reverse
14from collections import defaultdict
16from .models import BugTracker, Bug
17from .models import BugComment, ReplicationScript
19from .sandbox.io import Client
20from .serializers import ReplicationScriptSerializer
21from .filtering import QueryCreator
23from datetime import timedelta
24import json
27@require_POST
28@permission_required('CIResults.change_replicationscript')
29def replication_script_check(request, **kwargs):
30 script = request.POST.get("script")
31 src_tracker_name = request.POST["source_tracker"]
32 dest_tracker_name = request.POST["destination_tracker"]
34 src_tracker = BugTracker.objects.get(name=src_tracker_name)
35 dest_tracker = BugTracker.objects.get(name=dest_tracker_name)
37 try:
38 client = Client.get_or_create_instance(script)
39 except ValueError as e:
40 return JsonResponse({'status': 'false', 'message': str(e)}, status=500)
41 except (OSError, IOError):
42 msg = "Script failed, likely due to illegal syscall made by script."
43 return JsonResponse({'status': 'false', 'message': msg}, status=500)
45 try:
46 p = Prefetch('children', queryset=Bug.objects.filter(tracker=dest_tracker), to_attr="children_bugs")
47 bug_list = Bug.objects.filter(tracker=src_tracker).prefetch_related(p)
48 bugs = src_tracker.tracker.tracker_check_replication(bug_list, dest_tracker, script, client, dryrun=True)
50 except Client.UserFunctionCallError as e:
51 return JsonResponse({'status': 'false', 'message': e.reason}, status=500)
52 except ValueError as e:
53 return JsonResponse({'status': 'false', 'message': str(e)}, status=500)
54 finally:
55 client.shutdown()
56 return JsonResponse({'bugs': bugs}, safe=False)
59class ReplicationScriptListView(ListView):
60 model = ReplicationScript
61 context_object_name = 'script_list'
63 def get_queryset(self):
64 return ReplicationScript.objects.all()
67class ReplicationScriptCreateView(LoginRequiredMixin, PermissionRequiredMixin, CreateView):
68 model = ReplicationScript
69 fields = ['name', 'enabled', 'source_tracker', 'destination_tracker', 'script']
70 template_name = 'CIResults/replication_script.html'
72 permission_required = 'CIResults.add_replicationscript'
73 permission_denied_message = "You don't have the necessary permissions to create a replication script"
75 def get_success_url(self):
76 messages.success(self.request, "The script {} has been created".format(self.object))
77 return reverse("CIResults-replication-script-list")
79 def form_valid(self, form):
80 form.instance.created_by = self.request.user
81 return super().form_valid(form)
84class ReplicationScriptEditView(LoginRequiredMixin, PermissionRequiredMixin, UpdateView):
85 model = ReplicationScript
86 fields = ['name', 'enabled', 'source_tracker', 'destination_tracker', 'script']
87 template_name = 'CIResults/replication_script.html'
89 permission_required = 'CIResults.change_replicationscript'
90 permission_denied_message = "You don't have the necessary permissions to edit a replication script"
92 def get_success_url(self):
93 messages.success(self.request, "The script {} has been edited".format(self.object))
94 return reverse("CIResults-replication-script-list")
96 def get_context_data(self, **kwargs):
97 context = super().get_context_data(**kwargs)
98 context['script_history'] = ReplicationScript.objects.get(pk=self.object.pk).script_history
99 return context
101 def form_valid(self, form):
102 original = ReplicationScript.objects.get(pk=self.object.pk)
103 orig_hist = json.loads(form.instance.script_history)
104 orig_hist.append(ReplicationScriptSerializer(original).data)
105 form.instance.script_history = json.dumps(orig_hist)
106 return super().form_valid(form)
109def open_bugs(request, **kwargs):
110 # Parse the user request
111 user_query = QueryCreator(request, Bug).request_to_query()
113 # If the user request is empty, just select everything
114 selected_bugs = Bug.objects.all() if user_query.is_empty else user_query.objects
115 selected_bugs = selected_bugs.defer('description')
116 selected_bugs = selected_bugs.prefetch_related('tracker', 'assignee__person', "creator__person",
117 "issue_set", "children", "parent")
119 referenced_bugs = set([b.id for b in selected_bugs if len(b.issue_set.all()) > 0])
120 all_followed_and_open_bugs = set([b for b in selected_bugs if b.is_open and (b.id in referenced_bugs or
121 b.component in b.tracker.components_followed_list or not b.tracker.tracker.has_components)]) # noqa
122 all_followed_and_open_bugs = set(b if b.parent is None else b.parent for b in all_followed_and_open_bugs)
124 all_comments = BugComment.objects.filter(bug__in=selected_bugs).only('bug', 'account', 'created_on')
125 all_comments = all_comments.prefetch_related('bug__tracker', "account__person")
127 # HACK: Preload all the comments and assign them to their respective bugs
128 comments = defaultdict(list)
129 for comment in all_comments:
130 comments[(comment.bug_id, comment.bug.tracker_id)].append(comment)
131 for bug in all_followed_and_open_bugs:
132 bug.comments_cached = comments[(bug.id, bug.tracker_id)]
134 # Now, classify the urgency
135 overdue = list()
136 close = list()
137 other = list()
138 for bug in sorted(all_followed_and_open_bugs, key=lambda b: b.effective_priority, reverse=True):
139 time_left = bug.SLA_remaining_time
140 if time_left < timedelta(seconds=0):
141 overdue.append(bug)
142 elif time_left < timedelta(days=7):
143 close.append(bug) # pragma: no cover (TODO: requires to control the current time)
144 else:
145 other.insert(-1, bug)
147 context = {
148 "trackers": BugTracker.objects.all(),
149 "all_open_bugs": all_followed_and_open_bugs,
150 "bugs_overdue": overdue,
151 "bugs_close_to_deadline": close,
152 "bugs_other": other,
154 'filters_model': Bug,
155 'query': user_query,
156 }
157 return render(request, 'CIResults/open_bugs.html', context)
160@transaction.atomic
161@require_http_methods(["POST"])
162def bug_flag_for_update(request, pk):
163 bug = get_object_or_404(Bug.objects.select_for_update(), pk=pk)
165 if not bug.is_being_updated:
166 bug.flagged_as_update_pending_on = timezone.now()
167 bug.save()
168 status = 200
169 else:
170 status = 409
172 return JsonResponse(data={}, status=status)