tcms.kiwi_auth.admin   B
last analyzed

Complexity

Total Complexity 43

Size/Duplication

Total Lines 226
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
wmc 43
eloc 146
dl 0
loc 226
rs 8.96
c 0
b 0
f 0

16 Methods

Rating   Name   Duplication   Size   Complexity  
A KiwiGroupAdmin.get_fields() 0 10 2
A KiwiUserAdmin.has_change_permission() 0 2 1
A KiwiUserAdmin.user_change_password() 0 5 1
A KiwiUserAdmin.has_delete_permission() 0 7 2
A KiwiUserAdmin.response_delete() 0 9 2
A MyUserChangeForm.clean_email() 0 8 3
A KiwiUserAdmin.render_change_form() 0 17 5
A KiwiGroupAdmin.get_readonly_fields() 0 7 3
A KiwiGroupAdmin.has_delete_permission() 0 4 3
A KiwiUserAdmin.delete_view() 0 14 2
A KiwiUserAdmin.has_view_permission() 0 5 2
A GroupAdminForm.__init__() 0 5 2
A KiwiUserAdmin.delete_model() 0 2 1
B KiwiUserAdmin.get_fieldsets() 0 20 8
A GroupAdminForm.save() 0 8 1
A KiwiUserAdmin.get_readonly_fields() 0 18 4

1 Function

Rating   Name   Duplication   Size   Complexity  
A _modifying_myself() 0 2 1

How to fix   Complexity   

Complexity

Complex classes like tcms.kiwi_auth.admin often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

1
# -*- coding: utf-8 -*-
2
3
from django import forms
4
from django.contrib import admin
5
from django.contrib.admin.widgets import FilteredSelectMultiple
6
from django.contrib.auth import get_user_model
7
from django.contrib.auth.admin import GroupAdmin, UserAdmin, sensitive_post_parameters_m
8
from django.contrib.auth.forms import UserChangeForm
9
from django.contrib.auth.models import Group, Permission
10
from django.http import HttpResponseForbidden, HttpResponseRedirect
11
from django.urls import reverse
12
from django.utils.text import capfirst
13
from django.utils.translation import gettext_lazy as _
14
15
from tcms.utils.user import delete_user
16
17
User = get_user_model()  # pylint: disable=invalid-name
18
19
20
class MyUserChangeForm(UserChangeForm):
21
    """
22
    Enforces unique user emails.
23
    """
24
25
    email = forms.EmailField(required=True)
26
27
    def clean_email(self):
28
        query_set = User.objects.filter(email=self.cleaned_data["email"])
29
        if self.instance:
30
            query_set = query_set.exclude(pk=self.instance.pk)
31
        if query_set.count():
32
            raise forms.ValidationError(_("This email address is already in use"))
33
34
        return self.cleaned_data["email"]
35
36
37
def _modifying_myself(request, object_id):
38
    return request.user.pk == int(object_id)
39
40
41
class GroupAdminForm(forms.ModelForm):
42
    class Meta:
43
        model = Group
44
        fields = ["name", "permissions"]
45
46
    users = forms.ModelMultipleChoiceField(
47
        queryset=User.objects.all(),
48
        required=False,
49
        widget=FilteredSelectMultiple("users", False),
50
    )
51
52
    def __init__(self, *args, **kwargs):
53
        super().__init__(*args, **kwargs)
54
        self.fields["users"].label = capfirst(_("users"))
55
        if self.instance.pk:
56
            self.fields["users"].initial = self.instance.user_set.all()
57
58
    def save(self, commit=True):
59
        instance = super().save(commit=commit)
60
        instance.save()
61
62
        self.instance.user_set.set(self.cleaned_data["users"])
63
        self.save_m2m()
64
65
        return instance
66
67
68
class KiwiUserAdmin(UserAdmin):
69
    list_display = UserAdmin.list_display + (
70
        "is_active",
71
        "is_superuser",
72
        "date_joined",
73
        "last_login",
74
    )
75
    ordering = ["-pk"]  # same as -date_joined
76
77
    # override standard form and make the email address unique
78
    # even when adding users via admin panel
79
    form = MyUserChangeForm
80
81
    def has_change_permission(self, request, obj=None):
82
        return request.user.is_superuser or obj is not None
83
84
    def has_view_permission(self, request, obj=None):
85
        if _modifying_myself(request, getattr(obj, "pk", 0)):
86
            return True
87
88
        return super().has_view_permission(request, obj)
89
90
    # pylint: disable=too-many-arguments
91
    def render_change_form(
92
        self, request, context, add=False, change=False, form_url="", obj=None
93
    ):
94
        if not self.has_view_permission(request, obj):
95
            return HttpResponseForbidden()
96
97
        if obj and not (
98
            _modifying_myself(request, obj.pk) or request.user.is_superuser
99
        ):
100
            context.update(
101
                {
102
                    "show_save": False,
103
                    "show_save_and_continue": False,
104
                }
105
            )
106
        return super().render_change_form(
107
            request, context, add=add, change=change, form_url=form_url, obj=obj
108
        )
109
110
    def get_readonly_fields(self, request, obj=None):
111
        if request.user.is_superuser:
112
            return super().get_readonly_fields(request, obj)
113
114
        readonly_fields = [
115
            "username",
116
            "is_staff",
117
            "is_active",
118
            "is_superuser",
119
            "last_login",
120
            "date_joined",
121
            "groups",
122
            "user_permissions",
123
        ]
124
        if obj and not _modifying_myself(request, obj.pk):
125
            readonly_fields.extend(["first_name", "last_name", "email"])
126
127
        return readonly_fields
128
129
    def get_fieldsets(self, request, obj=None):
130
        # super-user adding new account
131
        if not obj and request.user.is_superuser:
132
            return super().get_fieldsets(request, obj)
133
134
        first_fieldset_fields = ("username",)
135
        if obj and _modifying_myself(request, obj.pk):
136
            first_fieldset_fields = first_fieldset_fields + ("password",)
137
138
        remaining_fieldsets = (
139
            (_("Personal info"), {"fields": ("first_name", "last_name", "email")}),
140
            (_("Permissions"), {"fields": ("is_active", "groups")}),
141
        )
142
143
        if request.user.is_superuser:
144
            field_sets = super().get_fieldsets(request, obj)
145
            if field_sets[0][0] is None and "password" in field_sets[0][1]["fields"]:
146
                remaining_fieldsets = field_sets[1:]
147
148
        return ((None, {"fields": first_fieldset_fields}),) + remaining_fieldsets
149
150
    @sensitive_post_parameters_m
151
    def user_change_password(
152
        self, request, id, form_url=""
153
    ):  # pylint: disable=redefined-builtin
154
        return HttpResponseRedirect(reverse("admin:password_change"))
155
156
    @admin.options.csrf_protect_m
157
    def delete_view(self, request, object_id, extra_context=None):
158
        if not _modifying_myself(request, object_id):
159
            return super().delete_view(request, object_id, extra_context)
160
161
        # allow deletion of the user own account
162
        permission = Permission.objects.get(
163
            content_type__app_label="auth", codename="delete_user"
164
        )
165
        try:
166
            request.user.user_permissions.add(permission)
167
            return super().delete_view(request, object_id, extra_context)
168
        finally:
169
            request.user.user_permissions.remove(permission)
170
171
    def response_delete(self, request, obj_display, obj_id):
172
        result = super().response_delete(request, obj_display, obj_id)
173
174
        if not _modifying_myself(request, obj_id):
175
            return result
176
177
        # user doesn't exist anymore so go to the index page
178
        # instead of returning to the user admin page
179
        return HttpResponseRedirect(reverse("core-views-index"))
180
181
    def has_delete_permission(self, request, obj=None):
182
        # allow to delete yourself without having 'delete' permission
183
        # explicitly assigned
184
        if _modifying_myself(request, getattr(obj, "pk", 0)):
185
            return True
186
187
        return super().has_delete_permission(request, obj)
188
189
    def delete_model(self, request, obj):
190
        delete_user(obj)
191
192
193
class KiwiGroupAdmin(GroupAdmin):
194
    form = GroupAdminForm
195
196
    def has_delete_permission(self, request, obj=None):
197
        if obj and obj.name in ["Tester", "Administrator"]:
198
            return False
199
        return super().has_delete_permission(request, obj)
200
201
    def get_fields(self, request, obj=None):
202
        fields = super().get_fields(request, obj=obj)
203
        name_index = fields.index("name")
204
205
        # make sure Name is always the first field
206
        if name_index > 0:
207
            del fields[name_index]
208
            fields.insert(0, "name")
209
210
        return fields
211
212
    def get_readonly_fields(self, request, obj=None):
213
        readonly_fields = super().get_readonly_fields(request, obj)
214
215
        if obj and obj.name in ["Tester", "Administrator"]:
216
            readonly_fields = readonly_fields + ("name",)
217
218
        return readonly_fields
219
220
221
# user admin extended functionality
222
admin.site.unregister(User)
223
admin.site.register(User, KiwiUserAdmin)
224
admin.site.unregister(Group)
225
admin.site.register(Group, KiwiGroupAdmin)
226