Issues (87)

tcms/bugs/views.py (1 issue)

Severity
1
# Copyright (c) 2019-2021 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.http import HttpResponseRedirect
8
from django.urls import reverse
9
from django.utils.decorators import method_decorator
10
from django.utils.translation import gettext_lazy as _
11
from django.views.generic import DetailView
12
from django.views.generic.base import TemplateView, View
13
from django.views.generic.edit import CreateView, UpdateView
14
from guardian.decorators import permission_required as object_permission_required
15
16
from tcms.bugs.forms import BugCommentForm, NewBugForm
17
from tcms.bugs.models import Bug
18
from tcms.core.helpers.comments import add_comment
19
from tcms.management.models import Component
20
21
22
@method_decorator(
23
    object_permission_required(
24
        "bugs.view_bug", (Bug, "pk", "pk"), accept_global_perms=True
25
    ),
26
    name="dispatch",
27
)
28
class Get(DetailView):
29
    model = Bug
30
    template_name = "bugs/get.html"
31
    http_method_names = ["get"]
32
33
    def get_context_data(self, **kwargs):
34
        context = super().get_context_data(**kwargs)
35
        context["comment_form"] = BugCommentForm()
36
        context["comment_form"].populate(self.object.pk)
37
        context["executions"] = self.object.executions.all()
38
        context["OBJECT_MENU_ITEMS"] = [
39
            (
40
                "...",
41
                [
42
                    (_("Edit"), reverse("bugs-edit", args=[self.object.pk])),
43
                    ("-", "-"),
44
                    (
45
                        _("Object permissions"),
46
                        reverse("admin:bugs_bug_permissions", args=[self.object.pk]),
47
                    ),
48
                    ("-", "-"),
49
                    (
50
                        _("Delete"),
51
                        reverse("admin:bugs_bug_delete", args=[self.object.pk]),
52
                    ),
53
                ],
54
            )
55
        ]
56
57
        return context
58
59
60
@method_decorator(permission_required("bugs.add_bug"), name="dispatch")
61
class New(CreateView):
62
    model = Bug
63
    form_class = NewBugForm
64
    template_name = "bugs/mutable.html"
65
66
    def get_context_data(self, **kwargs):
67
        context = super().get_context_data(**kwargs)
68
        context["page_title"] = _("New Bug")
69
        context["form_post_url"] = reverse("bugs-new")
70
        return context
71
72
    def get_form_kwargs(self):
73
        kwargs = super().get_form_kwargs()
74
        kwargs["initial"].update(  # pylint: disable=objects-update-used
75
            {
76
                "reporter": self.request.user,
77
            }
78
        )
79
        return kwargs
80
81
    def get_form(self, form_class=None):
82
        form = super().get_form(form_class)
83
        # clear fields which are set dynamically via JavaScript
84
        form.populate(self.request.POST.get("product", -1))
85
        return form
86
87
    def form_valid(self, form):
88
        response = super().form_valid(form)
89
90
        if not self.object.assignee:
91
            self.object.assignee = New.find_assignee(self.request.POST)
92
            self.object.save()
93
        add_comment([self.object], form.cleaned_data["text"], self.request.user)
94
95
        return response
96
97
    @staticmethod
98
    def assignee_from_components(components):
99
        """
100
        Return the first owner which is assigned to any of the
101
        components. This is as best as we can to automatically figure
102
        out who should be assigned to this bug.
103
        """
104
        for component in components:
105
            if component.initial_owner:
106
                return component.initial_owner
107
108
        return None
109
110
    @staticmethod
111
    def find_assignee(data):
112
        """
113
        Try to automatically find an assignee for Bug by first scanning
114
        TestCase components (if present) and then components for the
115
        product.
116
        """
117
        assignee = None
118
        if "_execution" in data:
119
            assignee = New.assignee_from_components(
120
                data["_execution"].case.component.all()
121
            )
122
            del data["_execution"]
123
124
        if not assignee:
125
            assignee = New.assignee_from_components(
126
                Component.objects.filter(product=data["product"])
127
            )
128
129
        return assignee
130
131
    @staticmethod
132
    def create_bug(data):
133
        """
134
        Helper method used within Issue Tracker integration.
135
136
        :param data: Untrusted input, usually via HTTP request
137
        :type data: dict
138
        :return: bug
139
        :rtype: Model
140
        """
141
        bug = None
142
143
        if "assignee" not in data or not data["assignee"]:
144
            data["assignee"] = New.find_assignee(data)
145
146
        text = data["text"]
147
        del data["text"]
148
149
        bug = Bug.objects.create(**data)
150
        add_comment([bug], text, bug.reporter)
151
152
        return bug
153
154
155
@method_decorator(
156
    object_permission_required(
157
        "bugs.change_bug", (Bug, "pk", "pk"), accept_global_perms=True
158
    ),
159
    name="dispatch",
160
)
161
class Edit(UpdateView):
162
    model = Bug
163
    form_class = NewBugForm
164
    template_name = "bugs/mutable.html"
165
    _values_before_update = {}
166
167
    def _record_changes(self, new_data):
168
        result = ""
169
        for field in self.model._meta.fields:
170
            field = field.name
171
            if (
172
                field in new_data
173
                and self._values_before_update[field] != new_data[field]
174
            ):
175
                _before_update = self._values_before_update[field]
176
                _after_update = new_data[field]
177
                result += f"{field.title()}: {_before_update} -> {_after_update}\n"
178
        if result:
179
            add_comment([self.object], result, self.request.user)
180
181
    def get_initial(self):
182
        return {
183
            "assignee": self.object.assignee,
184
        }
185
186
    def get_context_data(self, **kwargs):
187
        context = super().get_context_data(**kwargs)
188
        context["page_title"] = _("Edit bug")
189
        context["form_post_url"] = reverse(
190
            "bugs-edit",
191
            args=[
192
                self.object.pk,
193
            ],
194
        )
195
        return context
196
197
    def get_object(self, queryset=None):
198
        obj = super().get_object(queryset)
199
        for field in self.model._meta.fields:
200
            self._values_before_update[field.name] = getattr(obj, field.name)
201
        return obj
202
203
    def form_valid(self, form):
204
        self._record_changes(form.cleaned_data)
205
        return super().form_valid(form)
206
207
208
@method_decorator(permission_required("django_comments.add_comment"), name="dispatch")
209
class AddComment(View):
210
    http_methods = ["post"]
211
212
    def post(self, request):
213
        form = BugCommentForm(request.POST)
214
        request_action = request.POST.get("action")
215
216
        if form.is_valid():
217
            bug = form.cleaned_data["bug"]
218
            if form.cleaned_data["text"]:
219
                add_comment([bug], form.cleaned_data["text"], request.user)
220
221
            if request_action == "close":
222
                bug.status = False
223
                add_comment([bug], _("*bug closed*"), request.user)
224
225
            if request_action == "reopen":
226
                bug.status = True
227
                add_comment([bug], _("*bug reopened*"), request.user)
228
            bug.save()
229
230
        return HttpResponseRedirect(reverse("bugs-get", args=[bug.pk]))
0 ignored issues
show
The variable bug does not seem to be defined in case form.is_valid() on line 216 is False. Are you sure this can never be the case?
Loading history...
231
232
233
@method_decorator(permission_required("bugs.view_bug"), name="dispatch")
234
class Search(TemplateView):
235
    template_name = "bugs/search.html"
236
237
    def get_context_data(self, **kwargs):
238
        form = NewBugForm(self.request.GET)
239
        form.populate(self.request.GET.get("product", -1))
240
241
        return {"form": form}
242