1 | # Copyright (c) 2019 Alexander Todorov <[email protected]> |
||
2 | |||
3 | # Licensed under the GPL 2.0: https://www.gnu.org/licenses/old-licenses/gpl-2.0.html |
||
4 | |||
5 | |||
6 | from django.contrib.auth.decorators import permission_required |
||
7 | from django.urls import reverse |
||
8 | from django.http import HttpResponseRedirect |
||
9 | from django.test import modify_settings |
||
10 | from django.utils.decorators import method_decorator |
||
11 | from django.views.generic import DetailView |
||
12 | from django.views.generic.edit import CreateView |
||
13 | from django.views.generic.edit import UpdateView |
||
14 | from django.views.generic.base import View |
||
15 | from django.views.generic.base import TemplateView |
||
16 | from django.utils.translation import ugettext_lazy as _ |
||
17 | |||
18 | from tcms.bugs.models import Bug |
||
19 | from tcms.management.models import Component |
||
20 | from tcms.bugs.forms import NewBugForm, BugCommentForm |
||
21 | from tcms.core.helpers.comments import add_comment |
||
22 | from tcms.core.response import ModifySettingsTemplateResponse |
||
23 | |||
24 | |||
25 | class Get(DetailView): # pylint: disable=missing-permission-required |
||
26 | model = Bug |
||
27 | template_name = 'bugs/get.html' |
||
28 | http_method_names = ['get'] |
||
29 | response_class = ModifySettingsTemplateResponse |
||
30 | |||
31 | def render_to_response(self, context, **response_kwargs): |
||
32 | self.response_class.modify_settings = modify_settings( |
||
33 | MENU_ITEMS={'append': [ |
||
34 | ('...', [ |
||
35 | ( |
||
36 | _('Edit'), |
||
37 | reverse('bugs-edit', args=[self.object.pk]) |
||
38 | ), |
||
39 | ]) |
||
40 | ]} |
||
41 | ) |
||
42 | return super().render_to_response(context, **response_kwargs) |
||
43 | |||
44 | def get_context_data(self, **kwargs): |
||
45 | context = super().get_context_data(**kwargs) |
||
46 | context['comment_form'] = BugCommentForm() |
||
47 | context['comment_form'].populate(self.object.pk) |
||
48 | context['executions'] = self.object.executions.all() |
||
49 | |||
50 | return context |
||
51 | |||
52 | |||
53 | @method_decorator(permission_required('bugs.add_bug'), name='dispatch') |
||
54 | class New(CreateView): |
||
55 | model = Bug |
||
56 | form_class = NewBugForm |
||
57 | template_name = 'bugs/mutable.html' |
||
58 | |||
59 | def get_context_data(self, **kwargs): |
||
60 | context = super().get_context_data(**kwargs) |
||
61 | context['page_title'] = _('New bug') |
||
62 | context['form_post_url'] = reverse('bugs-new') |
||
63 | return context |
||
64 | |||
65 | def get_form_kwargs(self): |
||
66 | kwargs = super().get_form_kwargs() |
||
67 | kwargs['initial'].update({ |
||
68 | 'reporter': self.request.user, |
||
69 | }) |
||
70 | return kwargs |
||
71 | |||
72 | def get_form(self): |
||
73 | form = super().get_form() |
||
74 | # clear fields which are set dynamically via JavaScript |
||
75 | form.populate(self.request.POST.get('product', -1)) |
||
76 | return form |
||
77 | |||
78 | def form_valid(self, form): |
||
79 | response = super().form_valid(form) |
||
80 | |||
81 | if not self.object.assignee: |
||
82 | self.object.assignee = New.find_assignee(self.request.POST) |
||
83 | self.object.save() |
||
84 | add_comment([self.object], form.cleaned_data['text'], self.request.user) |
||
85 | |||
86 | return response |
||
87 | |||
88 | @staticmethod |
||
89 | def assignee_from_components(components): |
||
90 | """ |
||
91 | Return the first owner which is assigned to any of the |
||
92 | components. This is as best as we can to automatically figure |
||
93 | out who should be assigned to this bug. |
||
94 | """ |
||
95 | for component in components: |
||
96 | if component.initial_owner: |
||
97 | return component.initial_owner |
||
98 | |||
99 | return None |
||
100 | |||
101 | @staticmethod |
||
102 | def find_assignee(data): |
||
103 | """ |
||
104 | Try to automatically find an assignee for Bug by first scanning |
||
105 | TestCase components (if present) and then components for the |
||
106 | product. |
||
107 | """ |
||
108 | assignee = None |
||
109 | if '_execution' in data: |
||
110 | assignee = New.assignee_from_components(data['_execution'].case.component.all()) |
||
111 | del data['_execution'] |
||
112 | |||
113 | if not assignee: |
||
114 | assignee = New.assignee_from_components( |
||
115 | Component.objects.filter(product=data['product'])) |
||
116 | |||
117 | return assignee |
||
118 | |||
119 | @staticmethod |
||
120 | def create_bug(data): |
||
121 | """ |
||
122 | Helper method used within Issue Tracker integration. |
||
123 | |||
124 | :param data: Untrusted input, usually via HTTP request |
||
125 | :type data: dict |
||
126 | :return: bug |
||
127 | :rtype: Model |
||
128 | """ |
||
129 | bug = None |
||
130 | |||
131 | if 'assignee' not in data or not data['assignee']: |
||
132 | data['assignee'] = New.find_assignee(data) |
||
133 | |||
134 | text = data['text'] |
||
135 | del data['text'] |
||
136 | |||
137 | bug = Bug.objects.create(**data) |
||
138 | add_comment([bug], text, bug.reporter) |
||
139 | |||
140 | return bug |
||
141 | |||
142 | |||
143 | @method_decorator(permission_required('bugs.change_bug'), name='dispatch') |
||
144 | class Edit(UpdateView): |
||
145 | model = Bug |
||
146 | # todo: try using NewBugForm instead of duplicating the field names here |
||
147 | # must figure out how to collect info about changes and hide comments |
||
148 | fields = ['summary', 'assignee', 'reporter', 'product', 'version', 'build'] |
||
149 | template_name = 'bugs/mutable.html' |
||
150 | _values_before_update = {} |
||
151 | |||
152 | def _record_changes(self, new_data): |
||
153 | result = "" |
||
154 | for field in self.fields: |
||
155 | if self._values_before_update[field] != new_data[field]: |
||
156 | result += "%s: %s -> %s\n" % (field.title(), |
||
157 | self._values_before_update[field], |
||
158 | new_data[field]) |
||
159 | if result: |
||
160 | add_comment([self.object], result, self.request.user) |
||
161 | |||
162 | def get_context_data(self, **kwargs): |
||
163 | context = super().get_context_data(**kwargs) |
||
164 | context['page_title'] = _('Edit bug') |
||
165 | context['form_post_url'] = reverse('bugs-edit', args=[self.object.pk, ]) |
||
166 | return context |
||
167 | |||
168 | def get_object(self, queryset=None): |
||
169 | object = super().get_object(queryset) |
||
170 | for field in self.fields: |
||
171 | self._values_before_update[field] = getattr(object, field) |
||
172 | return object |
||
173 | |||
174 | def form_valid(self, form): |
||
175 | self._record_changes(form.cleaned_data) |
||
176 | return super().form_valid(form) |
||
177 | |||
178 | |||
179 | @method_decorator(permission_required('django_comments.add_comment'), name='dispatch') |
||
180 | class AddComment(View): |
||
181 | http_methods = ['post'] |
||
182 | |||
183 | def post(self, request, *args, **kwargs): |
||
184 | form = BugCommentForm(request.POST) |
||
185 | |||
186 | if form.is_valid(): |
||
187 | bug = form.cleaned_data['bug'] |
||
188 | if form.cleaned_data['text']: |
||
189 | add_comment([bug], form.cleaned_data['text'], request.user) |
||
190 | |||
191 | if request.POST.get('action') == 'close': |
||
192 | bug.status = False |
||
193 | bug.save() |
||
194 | add_comment([bug], _('*bug closed*'), request.user) |
||
195 | |||
196 | return HttpResponseRedirect(reverse('bugs-get', args=[bug.pk])) |
||
0 ignored issues
–
show
introduced
by
Loading history...
|
|||
197 | |||
198 | |||
199 | class Search(TemplateView): # pylint: disable=missing-permission-required |
||
200 | template_name = 'bugs/search.html' |
||
201 | |||
202 | def get_context_data(self, **kwargs): |
||
203 | form = NewBugForm(self.request.GET) |
||
204 | form.populate(self.request.GET.get('product', -1)) |
||
205 | |||
206 | return {'form': form} |
||
207 |