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.
Completed
Push — master ( 0c3d5f...5b7906 )
by Lambda
6s
created

src.registration.admin.RegistrationAdmin   B

Complexity

Total Complexity 53

Size/Duplication

Total Lines 289
Duplicated Lines 0 %
Metric Value
dl 0
loc 289
rs 7.4757
wmc 53

16 Methods

Rating   Name   Duplication   Size   Complexity  
A RegistrationAdmin.accept_users() 0 4 2
B RegistrationAdmin.get_actions() 0 21 6
A RegistrationAdmin.has_delete_permission() 0 3 1
A RegistrationAdmin.get_object() 0 19 3
A RegistrationAdmin.has_add_permission() 0 3 1
A RegistrationAdmin.has_activate_permission() 0 5 2
A RegistrationAdmin.display_activation_key() 0 20 2
A RegistrationAdmin.has_reject_permission() 0 5 2
F RegistrationAdmin.change_view() 0 54 15
A RegistrationAdmin.reject_users() 0 4 2
A RegistrationAdmin.resend_acceptance_email() 0 14 4
A RegistrationAdmin.force_activate_users() 0 5 2
B RegistrationAdmin.get_inline_instances() 0 36 5
A RegistrationAdmin.__init__() 0 7 2
A RegistrationAdmin.has_accept_permission() 0 5 2
A RegistrationAdmin.display_supplement_summary() 0 12 2

How to fix   Complexity   

Complex Class

Complex classes like src.registration.admin.RegistrationAdmin 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
            fields = self.model._meta.get_all_field_names()
144
            if 'id' in fields:
145
                fields.remove('id')
146
            if 'registration_profile_id' in fields:
147
                fields.remove('registration_profile_id')
148
        if excludes is not None:
149
            for exclude in excludes:
150
                fields.remove(exclude)
151
        return fields
152
153
    def has_change_permission(self, request, obj=None):
154
        # Without change permission, supplemental information won't be shown
155
        # while get_queryset required change permission
156
        # Ref: https://github.com/django/django/blob/1.7
157
        #      /django/contrib/admin/options.py#L1852
158
        return True
159
160
161
class RegistrationAdmin(admin.ModelAdmin):
162
    """Admin class of RegistrationProfile
163
164
    Admin users can accept/reject registration and activate user in Django
165
    Admin page.
166
167
    If ``REGISTRATION_SUPPLEMENT_CLASS`` is specified, admin users can see the
168
    summary of the supplemental information in list view and detail of it in
169
    change view.
170
171
    ``RegistrationProfile`` is not assumed to handle by hand thus
172
    adding/changing/deleting is not accepted even in Admin page.
173
    ``RegistrationProfile`` only can be accepted/rejected or activated.
174
    To prevent these disallowed functions, the special AdminForm called
175
    ``RegistrationAdminForm`` is used.
176
    Its ``save`` method is overridden and it actually does not save the
177
    instance.
178
    It just call ``accept``, ``reject`` or ``activate`` method of current
179
    registration backend. So you don't want to override the ``save`` method of
180
    the form.
181
182
    """
183
    list_display = ('user', 'get_status_display',
184
                    'activation_key_expired', 'display_supplement_summary')
185
    raw_id_fields = ['user']
186
    search_fields = ('user__username', 'user__first_name', 'user__last_name')
187
    list_filter = ('_status', )
188
189
    form = RegistrationAdminForm
190
    backend = get_backend()
191
192
    readonly_fields = ('user', '_status')
193
194
    actions = (
195
        'accept_users',
196
        'reject_users',
197
        'force_activate_users',
198
        'resend_acceptance_email'
199
    )
200
201
    def __init__(self, model, admin_site):
202
        super(RegistrationAdmin, self).__init__(model, admin_site)
203
        if not hasattr(super(RegistrationAdmin, self), 'get_inline_instances'):
204
            # Django 1.3 doesn't have ``get_inline_instances`` method but
205
            # ``inline_instances`` was generated in ``__init__`` thus
206
            # update the attribute
207
            self.inline_instances = self.get_inline_instances(None)
208
209
    def has_add_permission(self, request):
210
        """registration profile should not be created by hand"""
211
        return False
212
213
    def has_delete_permission(self, request, obj=None):
214
        """registration profile should not be created by hand"""
215
        return False
216
217
    def has_accept_permission(self, request, obj):
218
        """whether the user has accept permission"""
219
        if not settings.REGISTRATION_USE_OBJECT_PERMISSION:
220
            obj = None
221
        return request.user.has_perm('registration.accept_registration', obj)
222
223
    def has_reject_permission(self, request, obj):
224
        """whether the user has reject permission"""
225
        if not settings.REGISTRATION_USE_OBJECT_PERMISSION:
226
            obj = None
227
        return request.user.has_perm('registration.reject_registration', obj)
228
229
    def has_activate_permission(self, request, obj):
230
        """whether the user has activate permission"""
231
        if not settings.REGISTRATION_USE_OBJECT_PERMISSION:
232
            obj = None
233
        return request.user.has_perm('registration.activate_user', obj)
234
235
    def get_actions(self, request):
236
        """get actions displaied in admin site
237
238
        RegistrationProfile should not be deleted in admin site thus
239
        'delete_selected' is disabled in default.
240
241
        Each actions has permissions thus delete the action if the accessed
242
        user doesn't have appropriate permission.
243
244
        """
245
        actions = super(RegistrationAdmin, self).get_actions(request)
246
        if 'delete_selected' in actions:
247
            del actions['delete_selected']
248
        if not request.user.has_perm('registration.accept_registration'):
249
            del actions['accept_users']
250
        if not request.user.has_perm('registration.reject_registration'):
251
            del actions['reject_users']
252
        if not request.user.has_perm('registration.accept_registration') or \
253
           not request.user.has_perm('registration.activate_user'):
254
            del actions['force_activate_users']
255
        return actions
256
257
    def accept_users(self, request, queryset):
258
        """Accept the selected users, if they are not already accepted"""
259
        for profile in queryset:
260
            self.backend.accept(profile, request=request, force=True)
261
    accept_users.short_description = _(
262
        "(Re)Accept registrations of selected users"
263
    )
264
265
    def reject_users(self, request, queryset):
266
        """Reject the selected users, if they are not already accepted"""
267
        for profile in queryset:
268
            self.backend.reject(profile, request=request)
269
    reject_users.short_description = _(
270
        "Reject registrations of selected users"
271
    )
272
273
    def force_activate_users(self, request, queryset):
274
        """Activates the selected users, if they are not already activated"""
275
        for profile in queryset:
276
            self.backend.accept(profile, request=request, send_email=False)
277
            self.backend.activate(profile.activation_key, request=request)
278
    force_activate_users.short_description = _(
279
        "Activate selected users forcibly"
280
    )
281
282
    def resend_acceptance_email(self, request, queryset):
283
        """Re-sends acceptance emails for the selected users
284
285
        Note that this will *only* send acceptance emails for users
286
        who are eligible to activate; emails will not be sent to users
287
        whose activation keys have expired or who have already
288
        activated or rejected.
289
290
        """
291
        site = get_site(request)
292
        for profile in queryset:
293
            if not profile.activation_key_expired():
294
                if profile.status != 'rejected':
295
                    profile.send_acceptance_email(site=site)
296
    resend_acceptance_email.short_description = _(
297
        "Re-send acceptance emails to selected users"
298
    )
299
300
    def display_supplement_summary(self, obj):
301
        """Display supplement summary
302
303
        Display ``__unicode__`` method result of
304
        ``REGISTRATION_SUPPLEMENT_CLASS``
305
        ``Not available`` when ``REGISTRATION_SUPPLEMENT_CLASS`` is not
306
        specified
307
308
        """
309
        if obj.supplement:
310
            return force_text(obj.supplement)
311
        return _('Not available')
312
    display_supplement_summary.short_description = _(
313
        'A summary of supplemental information'
314
    )
315
316
    def display_activation_key(self, obj):
317
        """Display activation key with link
318
319
        Note that displaying activation key is not recommended in security
320
        reason.
321
        If you really want to use this method, create your own subclass and
322
        re-register to admin.site
323
324
        Even this is a little bit risky, it is really useful for developping
325
        (without checking email, you can activate any user you want) thus
326
        I created but turned off in default :-p
327
328
        """
329
        if obj.status == 'accepted':
330
            activation_url = reverse('registration_activate',
331
                                     kwargs={
332
                                         'activation_key': obj.activation_key})
333
            return mark_safe('<a href="%s">%s</a>' % (
334
                activation_url, obj.activation_key))
335
        return _('Not available')
336
    display_activation_key.short_description = _('Activation key')
337
    display_activation_key.allow_tags = True
338
339
    def get_inline_instances(self, request, obj=None):
340
        """
341
        return inline instances with registration supplement inline instance
342
        """
343
        inline_instances = []
344
        supplement_class = self.backend.get_supplement_class()
345
        if supplement_class:
346
            kwargs = {
347
                'extra': 1,
348
                'max_num': 1,
349
                'can_delete': False,
350
                'model': supplement_class,
351
            }
352
            inline_base = get_supplement_admin_inline_base_class()
353
            inline_form = type(
354
                str("RegistrationSupplementInlineAdmin"),
355
                (inline_base,), kwargs
356
            )
357
            inline_instances = [inline_form(self.model, self.admin_site)]
358
        supercls = super(RegistrationAdmin, self)
359
        if hasattr(supercls, 'get_inline_instances'):
360
            if django.VERSION >= (1, 5):
361
                inline_instances.extend(supercls.get_inline_instances(
362
                    request, obj
363
                ))
364
            else:
365
                # Django 1.4 cannot handle obj
366
                inline_instances.extend(supercls.get_inline_instances(
367
                    request,
368
                ))
369
        else:
370
            # Django 1.3
371
            for inline_class in self.inlines:
372
                inline_instance = inline_class(self.model, self.admin_site)
373
                inline_instances.append(inline_instance)
374
        return inline_instances
375
376
    def get_object(self, request, object_id, from_field=None):
377
        """add ``request`` instance to model instance and return
378
379
        To get ``request`` instance in form, ``request`` instance is stored
380
        in the model instance.
381
382
        """
383
        if django.VERSION < (1, 8, 0):
384
            obj = super(RegistrationAdmin, self).get_object(request, object_id)
385
        else:
386
            # Note:
387
            #   from_field was introduced from django 1.8
388
            obj = super(RegistrationAdmin, self).get_object(request,
389
                                                            object_id,
390
                                                            from_field)
391
        if obj:
392
            attr_name = settings._REGISTRATION_ADMIN_REQ_ATTR_NAME_IN_MODEL_INS
393
            setattr(obj, attr_name, request)
394
        return obj
395
396
    @csrf_protect_m
397
    @transaction_atomic
398
    def change_view(self, request, object_id, form_url='', extra_context=None):
399
        """called for change view
400
401
        Check permissions of the admin user for ``POST`` request depends on
402
        what action is requested and raise PermissionDenied if the action is
403
        not accepted for the admin user.
404
405
        """
406
        obj = self.get_object(request, unquote(object_id))
407
408
        # Permissin check
409
        if request.method == 'POST':
410
            #
411
            # Note:
412
            #   actions will be treated in form.save() method.
413
            #   in general, activate action will remove the profile because
414
            #   the profile is no longer required after the activation
415
            #   but if I remove the profile in form.save() method, django admin
416
            #   will raise IndexError thus I passed `no_profile_delete = True`
417
            #   to activate with backend in form.save() method.
418
            #
419
            action_name = request.POST.get('action_name')
420
            if (action_name == 'accept' and
421
                    not self.has_accept_permission(request, obj)):
422
                raise PermissionDenied
423
            elif (action_name == 'reject' and
424
                    not self.has_reject_permission(request, obj)):
425
                raise PermissionDenied
426
            elif (action_name == 'activate' and
427
                    not self.has_activate_permission(request, obj)):
428
                raise PermissionDenied
429
            elif action_name == 'force_activate' and (
430
                    not self.has_accept_permission(request, obj) or
431
                    not self.has_activate_permission(request, obj)):
432
                raise PermissionDenied
433
434
        if django.VERSION < (1, 4,):
435
            response = super(RegistrationAdmin, self).change_view(
436
                request, object_id, extra_context
437
            )
438
        else:
439
            response = super(RegistrationAdmin, self).change_view(
440
                request, object_id, form_url, extra_context
441
            )
442
443
        if (request.method == 'POST' and
444
                action_name in ('activate', 'force_activate')):
445
            # if the requested data is valid then response will be an instance
446
            # of ``HttpResponseRedirect`` otherwise ``TemplateResponse``
447
            if isinstance(response, HttpResponseRedirect):
448
                obj.delete()
449
        return response
450
admin.site.register(RegistrationProfile, RegistrationAdmin)
451