Passed
Push — master ( 117bca...82de29 )
by Alexander
02:11
created

tcms.testcases.admin.BugSystemAdmin.save_model()   A

Complexity

Conditions 4

Size

Total Lines 31
Code Lines 26

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 26
dl 0
loc 31
rs 9.256
c 0
b 0
f 0
cc 4
nop 5
1
# pylint: disable=no-self-use
2
3
from django import forms
4
from django.conf import settings
5
from django.contrib import admin, messages
6
from django.forms.widgets import Select
7
from django.http import HttpResponseRedirect
8
from django.urls import reverse
9
from django.utils.module_loading import import_string
10
from django.utils.translation import gettext_lazy as _
11
12
from tcms.core.admin import ObjectPermissionsAdminMixin
13
from tcms.core.history import ReadOnlyHistoryAdmin
14
from tcms.testcases.models import BugSystem, Category, TestCase, TestCaseStatus
15
16
17
class TestCaseStatusAdmin(admin.ModelAdmin):
18
    list_display = ("id", "name", "is_confirmed")
19
    ordering = ["-is_confirmed", "id"]
20
    fieldsets = [
21
        (
22
            "",
23
            {
24
                "fields": ("name", "description", "is_confirmed"),
25
                "description": "<h1>%s</h1>"
26
                % _(
27
                    """For more information about customizing test case statuses see
28
        <a href="https://kiwitcms.readthedocs.io/en/latest/admin.html#test-case-statuses">
29
        the documentation</a>!"""
30
                ),
31
            },
32
        ),
33
    ]
34
35
    @admin.options.csrf_protect_m
36
    def delete_view(self, request, object_id, extra_context=None):
37
        obj = self.model.objects.get(pk=object_id)
38
39
        if (
40
            not self.model.objects.filter(is_confirmed=obj.is_confirmed)
41
            .exclude(pk=object_id)
42
            .exists()
43
        ):
44
            messages.add_message(
45
                request,
46
                messages.ERROR,
47
                _("1 confirmed & 1 uncomfirmed status required!"),
48
            )
49
50
            return HttpResponseRedirect(
51
                reverse("admin:testcases_testcasestatus_changelist")
52
            )
53
54
        return super().delete_view(request, object_id, extra_context)
55
56
57
class TestCaseAdmin(ObjectPermissionsAdminMixin, ReadOnlyHistoryAdmin):
58
    def add_view(self, request, form_url="", extra_context=None):
59
        return HttpResponseRedirect(reverse("testcases-new"))
60
61
    def change_view(self, request, object_id, form_url="", extra_context=None):
62
        return HttpResponseRedirect(reverse("testcases-get", args=[object_id]))
63
64
65
class CategoryAdmin(admin.ModelAdmin):
66
    search_fields = ("name",)
67
    list_display = ("id", "name", "product", "description")
68
    list_filter = ("product",)
69
70
71
class IssueTrackerTypeSelectWidget(Select):
72
    """
73
    A select widget which displays the names of all classes
74
    derived from IssueTrackerType. Skip IssueTrackerType
75
    because it is doesn't provide implementations for most of its methods.
76
    """
77
78
    _choices = None
79
80
    @property
81
    def choices(self):
82
        if self._choices is None:
83
            self._choices = self._types_as_choices()
84
        return self._choices
85
86
    @choices.setter
87
    def choices(self, _):
88
        # ChoiceField.__init__ sets ``self.choices = choices``
89
        # which would override ours.
90
        pass
91
92
    @staticmethod
93
    def _types_as_choices():
94
        return (("", ""),) + tuple(
95
            zip(settings.EXTERNAL_BUG_TRACKERS, settings.EXTERNAL_BUG_TRACKERS)
96
        )
97
98
99
class IssueTrackerTypeField(forms.ChoiceField):
100
    """Special choice field which uses the widget above"""
101
102
    widget = IssueTrackerTypeSelectWidget
103
104
    def valid_value(self, value):
105
        return True
106
107
108
class BugSystemAdminForm(forms.ModelForm):
109
    # make password show asterisks
110
    api_password = forms.CharField(
111
        widget=forms.PasswordInput(render_value=True), required=False
112
    )
113
114
    # select only tracker types for which we have available integrations
115
    tracker_type = IssueTrackerTypeField(  # pylint:disable=form-field-help-text-used
116
        help_text="This determines how Kiwi TCMS integrates with the IT system",
117
    )
118
119
    hc_bug_url = forms.CharField(  # pylint: disable=form-field-label-used, form-field-help-text-used
120
        required=False,
121
        max_length=1024,
122
        label=_("Bug URL"),
123
        help_text=_(
124
            "Kiwi TCMS will try fetching details for the given bug URL using the "
125
            "integration defined above! Click the `Save and continue` button and "
126
            "watch out for messages at the top of the screen. <strong>WARNING:</strong> "
127
            "in case of failures some issue trackers will fall back to fetching details "
128
            "via the OpenGraph protocol. In that case the result will include field named "
129
            "`from_open_graph`."
130
        ),
131
        widget=admin.widgets.AdminTextInputWidget,
132
    )
133
134
    class Meta:
135
        model = BugSystem
136
        fields = "__all__"
137
138
139
class BugSystemAdmin(admin.ModelAdmin):
140
    search_fields = ("name",)
141
    list_display = ("id", "name", "base_url")
142
    fieldsets = [
143
        (
144
            "",
145
            {
146
                "fields": ("name",),
147
            },
148
        ),
149
        (
150
            _("External Issue Tracker Integration"),
151
            {
152
                "fields": (
153
                    "tracker_type",
154
                    "base_url",
155
                    "api_url",
156
                    "api_username",
157
                    "api_password",
158
                ),
159
                "description": _(
160
                    """<h1>Warning: read the
161
<a href="http://kiwitcms.readthedocs.io/en/latest/admin.html#configure-external-bug-trackers">
162
Configure external bug trackers</a> section before editting the values below!</h1>"""
163
                ),
164
            },
165
        ),
166
        (
167
            _("Configuration health check"),
168
            {
169
                "fields": ("hc_bug_url",),
170
            },
171
        ),
172
    ]
173
    form = BugSystemAdminForm
174
175
    def save_model(self, request, obj, form, change):
176
        super().save_model(request, obj, form, change)
177
        # try health check
178
        bug_url = form.cleaned_data["hc_bug_url"]
179
        if bug_url:
180
            try:
181
                tracker = import_string(obj.tracker_type)(obj, request)
182
                if not tracker:
183
                    raise RuntimeError(_("Failed creating Issue Tracker"))
184
185
                details = tracker.details(bug_url)
186
                messages.add_message(
187
                    request,
188
                    messages.SUCCESS,
189
                    _("Issue Tracker configuration check passed"),
190
                )
191
                messages.add_message(
192
                    request,
193
                    messages.SUCCESS,
194
                    details,
195
                )
196
            except Exception as err:  # pylint: disable=broad-except
197
                messages.add_message(
198
                    request,
199
                    messages.ERROR,
200
                    _("Issue Tracker configuration check failed"),
201
                )
202
                messages.add_message(
203
                    request,
204
                    messages.ERROR,
205
                    err,
206
                )
207
208
209
admin.site.register(BugSystem, BugSystemAdmin)
210
admin.site.register(Category, CategoryAdmin)
211
admin.site.register(TestCase, TestCaseAdmin)
212
admin.site.register(TestCaseStatus, TestCaseStatusAdmin)
213