Passed
Push — master ( 62d7d9...8230b1 )
by Alexander
03:29
created

tcms.bugs.views.New.find_assignee()   A

Complexity

Conditions 3

Size

Total Lines 17
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 10
dl 0
loc 17
rs 9.9
c 0
b 0
f 0
cc 3
nop 1
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
The variable bug does not seem to be defined in case form.is_valid() on line 186 is False. Are you sure this can never be the case?
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