GitHub Access Token became invalid

It seems like the GitHub access token used for retrieving details about this repository from GitHub became invalid. This might prevent certain types of inspections from being run (in particular, everything related to pull requests).
Please ask an admin of your repository to re-new the access token on this website.

RegistrationAdmin.change_view()   F
last analyzed

Complexity

Conditions 15

Size

Total Lines 54

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 0 Features 0
Metric Value
cc 15
c 2
b 0
f 0
dl 0
loc 54
rs 3.5669

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

Complexity

Complex classes like RegistrationAdmin.change_view() 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
from __future__ import unicode_literals
3
"""
4
Admins of django-inspectional-registration
5
6
This is a modification of django-registration_ ``admin.py``
7
The original code is written by James Bennett
8
9
.. _django-registration: https://bitbucket.org/ubernostrum/django-registration
10
11
12
Original License::
13
14
    Copyright (c) 2007-2011, James Bennett
15
    All rights reserved.
16
17
    Redistribution and use in source and binary forms, with or without
18
    modification, are permitted provided that the following conditions are
19
    met:
20
21
        * Redistributions of source code must retain the above copyright
22
        notice, this list of conditions and the following disclaimer.
23
        * Redistributions in binary form must reproduce the above
24
        copyright notice, this list of conditions and the following
25
        disclaimer in the documentation and/or other materials provided
26
        with the distribution.
27
        * Neither the name of the author nor the names of other
28
        contributors may be used to endorse or promote products derived
29
        from this software without specific prior written permission.
30
31
    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
32
    "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
33
    LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
34
    A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
35
    OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
36
    SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
37
    LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
38
    DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
39
    THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
40
    (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
41
    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
42
"""
43
__author__ = 'Alisue <[email protected]>'
44
__all__ = (
45
    'RegistrationSupplementAdminInlineBase',
46
    'RegistrationAdmin'
47
)
48
import django
49
from django.db import transaction
50
from django.http import HttpResponseRedirect
51
from django.contrib import admin
52
from django.core.exceptions import PermissionDenied
53
from django.core.urlresolvers import reverse
54
from django.core.exceptions import ImproperlyConfigured
55
from django.views.decorators.csrf import csrf_protect
56
from django.utils.safestring import mark_safe
57
from django.utils.decorators import method_decorator
58
from django.utils.translation import ugettext_lazy as _
59
from django.utils.encoding import force_text
60
61
from registration.conf import settings
62
from registration.backends import get_backend
63
from registration.models import RegistrationProfile
64
from registration.utils import get_site
65
from registration.admin.forms import RegistrationAdminForm
66
from registration.compat import import_module
67
from registration.compat import transaction_atomic
68
from registration.compat import unquote
69
70
71
csrf_protect_m = method_decorator(csrf_protect)
72
73
74 View Code Duplication
def get_supplement_admin_inline_base_class(path=None):
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
75
    """
76
    Return a class of a admin inline class for registration supplement,
77
    given the dotted Python import path (as a string) to the admin inline
78
    class.
79
80
    If the addition cannot be located (e.g., because no such module
81
    exists, or because the module does not contain a class of the
82
    appropriate name), ``django.core.exceptions.ImproperlyConfigured``
83
    is raised.
84
85
    """
86
    path = path or settings.REGISTRATION_SUPPLEMENT_ADMIN_INLINE_BASE_CLASS
87
    i = path.rfind('.')
88
    module, attr = path[:i], path[i+1:]
89
    try:
90
        mod = import_module(module)
91
    except ImportError as e:
92
        raise ImproperlyConfigured((
93
            'Error loading admin inline class for registration supplement '
94
            '%s: "%s"'
95
        ) % (module, e))
96
    try:
97
        cls = getattr(mod, attr)
98
    except AttributeError:
99
        raise ImproperlyConfigured((
100
            'Module "%s" does not define a admin inline class for '
101
            'registration supplement named "%s"'
102
        ) % (module, attr))
103
    if cls and not issubclass(cls, RegistrationSupplementAdminInlineBase):
104
        raise ImproperlyConfigured((
105
            'Admin inline class for registration supplement class "%s" '
106
            'must be a subclass of ``registration.admin.'
107
            'RegistrationSupplementAdminInlineBase``'
108
        ) % path)
109
    return cls
110
111
112
class RegistrationSupplementAdminInlineBase(admin.StackedInline):
113
    """Registration supplement admin inline base class
114
115
    This inline class is used to generate admin inline class of current
116
    registration supplement. Used inline class is defined as
117
    ``settings.REGISTRATION_SUPPLEMENT_ADMIN_INLINE_BASE_CLASS`` thus if you
118
    want to modify the inline class of supplement, create a subclass of this
119
    class and set to ``REGISTRATION_SUPPLEMENT_ADMIN_INLINE_BASE_CLASS``
120
121
    """
122
    fields = ()
123
124
    def get_readonly_fields(self, request, obj=None):
125
        """get readonly fields of supplement
126
127
        Readonly fields will be generated by supplement's
128
        ``get_admin_fields`` and ``get_admin_excludes`` method thus if you want
129
        to change the fields displayed in django admin site. You want to change
130
        the method or attributes ``admin_fields`` or ``admin_excludes`` which
131
        is loaded by those method in default.
132
133
        See more detail in
134
        ``registration.supplements.DefaultRegistrationSupplement``
135
        documentation.
136
137
        """
138
        if obj is None:
139
            return ()
140
        fields = self.model.get_admin_fields()
141
        excludes = self.model.get_admin_excludes()
142
        if fields is None:
143
            try:
144
                #<django 1.10 _meta API
145
                fields = self.model._meta.get_all_field_names()
146
            except AttributeError:
147
                #django 1.10+ _meta API
148
                fields = [f.name for f in self.model._meta.get_fields()]
149
            
150
            if 'id' in fields:
151
                fields.remove('id')
152
            if 'registration_profile_id' in fields:
153
                fields.remove('registration_profile_id')
154
        if excludes is not None:
155
            for exclude in excludes:
156
                fields.remove(exclude)
157
        return fields
158
159
    def has_change_permission(self, request, obj=None):
160
        # Without change permission, supplemental information won't be shown
161
        # while get_queryset required change permission
162
        # Ref: https://github.com/django/django/blob/1.7
163
        #      /django/contrib/admin/options.py#L1852
164
        return True
165
166
167
class RegistrationAdmin(admin.ModelAdmin):
168
    """Admin class of RegistrationProfile
169
170
    Admin users can accept/reject registration and activate user in Django
171
    Admin page.
172
173
    If ``REGISTRATION_SUPPLEMENT_CLASS`` is specified, admin users can see the
174
    summary of the supplemental information in list view and detail of it in
175
    change view.
176
177
    ``RegistrationProfile`` is not assumed to handle by hand thus
178
    adding/changing/deleting is not accepted even in Admin page.
179
    ``RegistrationProfile`` only can be accepted/rejected or activated.
180
    To prevent these disallowed functions, the special AdminForm called
181
    ``RegistrationAdminForm`` is used.
182
    Its ``save`` method is overridden and it actually does not save the
183
    instance.
184
    It just call ``accept``, ``reject`` or ``activate`` method of current
185
    registration backend. So you don't want to override the ``save`` method of
186
    the form.
187
188
    """
189
    list_display = ('user', 'get_status_display',
190
                    'activation_key_expired', 'display_supplement_summary')
191
    raw_id_fields = ['user']
192
    search_fields = ('user__username', 'user__first_name', 'user__last_name')
193
    list_filter = ('_status', )
194
195
    form = RegistrationAdminForm
196
    backend = get_backend()
197
198
    readonly_fields = ('user', '_status')
199
200
    actions = (
201
        'accept_users',
202
        'reject_users',
203
        'force_activate_users',
204
        'resend_acceptance_email'
205
    )
206
207
    def __init__(self, model, admin_site):
208
        super(RegistrationAdmin, self).__init__(model, admin_site)
209
        if not hasattr(super(RegistrationAdmin, self), 'get_inline_instances'):
210
            # Django 1.3 doesn't have ``get_inline_instances`` method but
211
            # ``inline_instances`` was generated in ``__init__`` thus
212
            # update the attribute
213
            self.inline_instances = self.get_inline_instances(None)
214
215
    def has_add_permission(self, request):
216
        """registration profile should not be created by hand"""
217
        return False
218
219
    def has_delete_permission(self, request, obj=None):
220
        """registration profile should not be created by hand"""
221
        return False
222
223
    def has_accept_permission(self, request, obj):
224
        """whether the user has accept permission"""
225
        if not settings.REGISTRATION_USE_OBJECT_PERMISSION:
226
            obj = None
227
        return request.user.has_perm('registration.accept_registration', obj)
228
229
    def has_reject_permission(self, request, obj):
230
        """whether the user has reject permission"""
231
        if not settings.REGISTRATION_USE_OBJECT_PERMISSION:
232
            obj = None
233
        return request.user.has_perm('registration.reject_registration', obj)
234
235
    def has_activate_permission(self, request, obj):
236
        """whether the user has activate permission"""
237
        if not settings.REGISTRATION_USE_OBJECT_PERMISSION:
238
            obj = None
239
        return request.user.has_perm('registration.activate_user', obj)
240
241
    def get_actions(self, request):
242
        """get actions displaied in admin site
243
244
        RegistrationProfile should not be deleted in admin site thus
245
        'delete_selected' is disabled in default.
246
247
        Each actions has permissions thus delete the action if the accessed
248
        user doesn't have appropriate permission.
249
250
        """
251
        actions = super(RegistrationAdmin, self).get_actions(request)
252
        if 'delete_selected' in actions:
253
            del actions['delete_selected']
254
        if not request.user.has_perm('registration.accept_registration'):
255
            del actions['accept_users']
256
        if not request.user.has_perm('registration.reject_registration'):
257
            del actions['reject_users']
258
        if not request.user.has_perm('registration.accept_registration') or \
259
           not request.user.has_perm('registration.activate_user'):
260
            del actions['force_activate_users']
261
        return actions
262
263
    def accept_users(self, request, queryset):
264
        """Accept the selected users, if they are not already accepted"""
265
        for profile in queryset:
266
            self.backend.accept(profile, request=request, force=True)
267
    accept_users.short_description = _(
268
        "(Re)Accept registrations of selected users"
269
    )
270
271
    def reject_users(self, request, queryset):
272
        """Reject the selected users, if they are not already accepted"""
273
        for profile in queryset:
274
            self.backend.reject(profile, request=request)
275
    reject_users.short_description = _(
276
        "Reject registrations of selected users"
277
    )
278
279
    def force_activate_users(self, request, queryset):
280
        """Activates the selected users, if they are not already activated"""
281
        for profile in queryset:
282
            self.backend.accept(profile, request=request, send_email=False)
283
            self.backend.activate(profile.activation_key, request=request)
284
    force_activate_users.short_description = _(
285
        "Activate selected users forcibly"
286
    )
287
288
    def resend_acceptance_email(self, request, queryset):
289
        """Re-sends acceptance emails for the selected users
290
291
        Note that this will *only* send acceptance emails for users
292
        who are eligible to activate; emails will not be sent to users
293
        whose activation keys have expired or who have already
294
        activated or rejected.
295
296
        """
297
        site = get_site(request)
298
        for profile in queryset:
299
            if not profile.activation_key_expired():
300
                if profile.status != 'rejected':
301
                    profile.send_acceptance_email(site=site)
302
    resend_acceptance_email.short_description = _(
303
        "Re-send acceptance emails to selected users"
304
    )
305
306
    def display_supplement_summary(self, obj):
307
        """Display supplement summary
308
309
        Display ``__unicode__`` method result of
310
        ``REGISTRATION_SUPPLEMENT_CLASS``
311
        ``Not available`` when ``REGISTRATION_SUPPLEMENT_CLASS`` is not
312
        specified
313
314
        """
315
        if obj.supplement:
316
            return force_text(obj.supplement)
317
        return _('Not available')
318
    display_supplement_summary.short_description = _(
319
        'A summary of supplemental information'
320
    )
321
322
    def display_activation_key(self, obj):
323
        """Display activation key with link
324
325
        Note that displaying activation key is not recommended in security
326
        reason.
327
        If you really want to use this method, create your own subclass and
328
        re-register to admin.site
329
330
        Even this is a little bit risky, it is really useful for developping
331
        (without checking email, you can activate any user you want) thus
332
        I created but turned off in default :-p
333
334
        """
335
        if obj.status == 'accepted':
336
            activation_url = reverse('registration_activate',
337
                                     kwargs={
338
                                         'activation_key': obj.activation_key})
339
            return mark_safe('<a href="%s">%s</a>' % (
340
                activation_url, obj.activation_key))
341
        return _('Not available')
342
    display_activation_key.short_description = _('Activation key')
343
    display_activation_key.allow_tags = True
344
345
    def get_inline_instances(self, request, obj=None):
346
        """
347
        return inline instances with registration supplement inline instance
348
        """
349
        inline_instances = []
350
        supplement_class = self.backend.get_supplement_class()
351
        if supplement_class:
352
            kwargs = {
353
                'extra': 1,
354
                'max_num': 1,
355
                'can_delete': False,
356
                'model': supplement_class,
357
            }
358
            inline_base = get_supplement_admin_inline_base_class()
359
            inline_form = type(
360
                str("RegistrationSupplementInlineAdmin"),
361
                (inline_base,), kwargs
362
            )
363
            inline_instances = [inline_form(self.model, self.admin_site)]
364
        supercls = super(RegistrationAdmin, self)
365
        if hasattr(supercls, 'get_inline_instances'):
366
            if django.VERSION >= (1, 5):
367
                inline_instances.extend(supercls.get_inline_instances(
368
                    request, obj
369
                ))
370
            else:
371
                # Django 1.4 cannot handle obj
372
                inline_instances.extend(supercls.get_inline_instances(
373
                    request,
374
                ))
375
        else:
376
            # Django 1.3
377
            for inline_class in self.inlines:
378
                inline_instance = inline_class(self.model, self.admin_site)
379
                inline_instances.append(inline_instance)
380
        return inline_instances
381
382
    def get_object(self, request, object_id, from_field=None):
383
        """add ``request`` instance to model instance and return
384
385
        To get ``request`` instance in form, ``request`` instance is stored
386
        in the model instance.
387
388
        """
389
        if django.VERSION < (1, 8, 0):
390
            obj = super(RegistrationAdmin, self).get_object(request, object_id)
391
        else:
392
            # Note:
393
            #   from_field was introduced from django 1.8
394
            obj = super(RegistrationAdmin, self).get_object(request,
395
                                                            object_id,
396
                                                            from_field)
397
        if obj:
398
            attr_name = settings._REGISTRATION_ADMIN_REQ_ATTR_NAME_IN_MODEL_INS
399
            setattr(obj, attr_name, request)
400
        return obj
401
402
    @csrf_protect_m
403
    @transaction_atomic
404
    def change_view(self, request, object_id, form_url='', extra_context=None):
405
        """called for change view
406
407
        Check permissions of the admin user for ``POST`` request depends on
408
        what action is requested and raise PermissionDenied if the action is
409
        not accepted for the admin user.
410
411
        """
412
        obj = self.get_object(request, unquote(object_id))
413
414
        # Permissin check
415
        if request.method == 'POST':
416
            #
417
            # Note:
418
            #   actions will be treated in form.save() method.
419
            #   in general, activate action will remove the profile because
420
            #   the profile is no longer required after the activation
421
            #   but if I remove the profile in form.save() method, django admin
422
            #   will raise IndexError thus I passed `no_profile_delete = True`
423
            #   to activate with backend in form.save() method.
424
            #
425
            action_name = request.POST.get('action_name')
426
            if (action_name == 'accept' and
427
                    not self.has_accept_permission(request, obj)):
428
                raise PermissionDenied
429
            elif (action_name == 'reject' and
430
                    not self.has_reject_permission(request, obj)):
431
                raise PermissionDenied
432
            elif (action_name == 'activate' and
433
                    not self.has_activate_permission(request, obj)):
434
                raise PermissionDenied
435
            elif action_name == 'force_activate' and (
436
                    not self.has_accept_permission(request, obj) or
437
                    not self.has_activate_permission(request, obj)):
438
                raise PermissionDenied
439
440
        if django.VERSION < (1, 4,):
441
            response = super(RegistrationAdmin, self).change_view(
442
                request, object_id, extra_context
443
            )
444
        else:
445
            response = super(RegistrationAdmin, self).change_view(
446
                request, object_id, form_url, extra_context
447
            )
448
449
        if (request.method == 'POST' and
450
                action_name in ('activate', 'force_activate')):
451
            # if the requested data is valid then response will be an instance
452
            # of ``HttpResponseRedirect`` otherwise ``TemplateResponse``
453
            if isinstance(response, HttpResponseRedirect):
454
                obj.delete()
455
        return response
456
admin.site.register(RegistrationProfile, RegistrationAdmin)
457