Source code for tcms.testcases.admin

# pylint: disable=no-self-use

import traceback

from django import forms
from django.conf import settings
from django.contrib import admin, messages
from django.forms.widgets import Select
from django.http import HttpResponseRedirect
from django.urls import reverse
from django.utils.module_loading import import_string
from django.utils.translation import gettext_lazy as _

from tcms.core.admin import ObjectPermissionsAdminMixin
from tcms.core.history import ReadOnlyHistoryAdmin
from tcms.core.widgets import SimpleMDE
from tcms.testcases.models import (
    BugSystem,
    Category,
    Template,
    TestCase,
    TestCaseStatus,
)


[docs] class TestCaseStatusAdmin(admin.ModelAdmin): _for_more_info = _( """For more information about customizing test case statuses see <a href="https://kiwitcms.readthedocs.io/en/latest/admin.html#test-case-statuses"> the documentation</a>!""" ) list_display = ("id", "name", "is_confirmed") ordering = ["-is_confirmed", "id"] fieldsets = [ ( "", { "fields": ("name", "description", "is_confirmed"), "description": f"<h1>{_for_more_info}</h1>", }, ), ]
[docs] @admin.options.csrf_protect_m def delete_view(self, request, object_id, extra_context=None): obj = self.model.objects.get(pk=object_id) if ( not self.model.objects.filter(is_confirmed=obj.is_confirmed) .exclude(pk=object_id) .exists() ): messages.add_message( request, messages.ERROR, _("1 confirmed & 1 uncomfirmed status required!"), ) return HttpResponseRedirect( reverse("admin:testcases_testcasestatus_changelist") ) return super().delete_view(request, object_id, extra_context)
[docs] class TestCaseAdmin(ObjectPermissionsAdminMixin, ReadOnlyHistoryAdmin):
[docs] def add_view(self, request, form_url="", extra_context=None): return HttpResponseRedirect(reverse("testcases-new"))
[docs] def change_view(self, request, object_id, form_url="", extra_context=None): return HttpResponseRedirect(reverse("testcases-get", args=[object_id]))
[docs] class CategoryAdmin(admin.ModelAdmin): search_fields = ("name",) list_display = ("id", "name", "product", "description") list_filter = ("product",)
[docs] class IssueTrackerTypeSelectWidget(Select): """ A select widget which displays the names of all classes derived from IssueTrackerType. Skip IssueTrackerType because it is doesn't provide implementations for most of its methods. """ _choices = None @property def choices(self): if self._choices is None: self._choices = self._types_as_choices() return self._choices @choices.setter def choices(self, _): # ChoiceField.__init__ sets ``self.choices = choices`` # which would override ours. pass @staticmethod def _types_as_choices(): return (("", ""),) + tuple( zip(settings.EXTERNAL_BUG_TRACKERS, settings.EXTERNAL_BUG_TRACKERS) )
[docs] class IssueTrackerTypeField(forms.ChoiceField): """Special choice field which uses the widget above""" widget = IssueTrackerTypeSelectWidget
[docs] def valid_value(self, value): return True
[docs] class BugSystemAdminForm(forms.ModelForm): # make password show asterisks api_password = forms.CharField( widget=forms.PasswordInput(render_value=True), required=False ) # select only tracker types for which we have available integrations tracker_type = IssueTrackerTypeField( # pylint:disable=form-field-help-text-used help_text="This determines how Kiwi TCMS integrates with the IT system", ) hc_bug_url = forms.CharField( # pylint: disable=form-field-label-used required=False, max_length=1024, label=_("Bug URL"), widget=admin.widgets.AdminTextInputWidget, )
[docs] class Meta: model = BugSystem fields = "__all__"
[docs] class BugSystemAdmin(admin.ModelAdmin): search_fields = ("name",) list_display = ("id", "name", "base_url") fieldsets = [ ( "", { "fields": ("name",), }, ), ( _("External Issue Tracker Integration"), { "fields": ( "tracker_type", "base_url", "api_url", "api_username", "api_password", ), "description": _( """<h1>Warning: read the <a href="http://kiwitcms.readthedocs.io/en/latest/admin.html#configure-external-bug-trackers"> Configure external bug trackers</a> section before editting the values below!</h1>""" ), }, ), ( _("Configuration health check"), { "fields": ("hc_bug_url",), "description": _( "Kiwi TCMS will try fetching details for the given bug URL using the " "integration defined above! Click the `Save and continue` button and " "watch out for messages at the top of the screen. <strong>WARNING:</strong> " "in case of failures some issue trackers will fall back to fetching details " "via the OpenGraph protocol. In that case the result will include field named " "`from_open_graph`." ), }, ), ] form = BugSystemAdminForm
[docs] def save_model(self, request, obj, form, change): super().save_model(request, obj, form, change) # try health check bug_url = form.cleaned_data["hc_bug_url"] if bug_url: try: tracker = import_string(obj.tracker_type)(obj, request) if not tracker: raise RuntimeError(_("Failed creating Issue Tracker")) details = tracker.details(bug_url) if details.get("from_open_graph", False): messages.add_message( request, messages.WARNING, _( "Details extracted via OpenGraph. " "Issue Tracker may still be configured incorrectly!" ), ) else: messages.add_message( request, messages.SUCCESS, _( "Details extracted via API. Issue Tracker configuration looks good!" ), ) messages.add_message( request, messages.INFO, details, ) except Exception: # pylint: disable=broad-except messages.add_message( request, messages.ERROR, _("Issue Tracker configuration check failed"), ) # show the actual exception with traceback b/c it can help debug failures messages.add_message( request, messages.ERROR, traceback.format_exc(), )
[docs] class TemplateAdminForm(forms.ModelForm): text = forms.CharField( widget=SimpleMDE(), required=True, )
[docs] class Meta: model = Template fields = "__all__"
[docs] class Media: js = [ "js/bundle.js", ]
[docs] class TemplateAdmin(admin.ModelAdmin): form = TemplateAdminForm
admin.site.register(BugSystem, BugSystemAdmin) admin.site.register(Category, CategoryAdmin) admin.site.register(TestCase, TestCaseAdmin) admin.site.register(TestCaseStatus, TestCaseStatusAdmin) admin.site.register(Template, TemplateAdmin)