Update upstream source from tag 'upstream/2.0.0'
Update to upstream version '2.0.0'
with Debian dir 5e492424f38ca2f3963c4ed7805deff6c71f6090
Thomas Goirand
4 years ago
20 | 20 | .idea/ |
21 | 21 | .eggs/ |
22 | 22 | .cache/ |
23 | .mypy_cache/ | |
24 | .pytest_cache/ | |
23 | 25 | |
24 | 26 | # WebDAV remote filesystem |
25 | 27 | .DAV |
0 | 0 | language: python |
1 | sudo: false | |
1 | dist: xenial | |
2 | 2 | |
3 | 3 | cache: pip |
4 | 4 | |
5 | python: | |
6 | - 2.7 | |
7 | - 3.4 | |
8 | - 3.5 | |
9 | - 3.6 | |
10 | ||
11 | env: | |
12 | - DJANGO_VERSION=1.8 DATABASE_URL=postgres://postgres@/django_guardian | |
13 | - DJANGO_VERSION=1.10 DATABASE_URL=postgres://postgres@/django_guardian | |
14 | - DJANGO_VERSION=1.11 DATABASE_URL=postgres://postgres@/django_guardian | |
15 | - DJANGO_VERSION=master DATABASE_URL=postgres://postgres@/django_guardian | |
16 | ||
17 | - DJANGO_VERSION=1.8 DATABASE_URL=mysql://root:@localhost/django_guardian | |
18 | - DJANGO_VERSION=1.10 DATABASE_URL=mysql://root:@localhost/django_guardian | |
19 | - DJANGO_VERSION=1.11 DATABASE_URL=mysql://root:@localhost/django_guardian | |
20 | - DJANGO_VERSION=master DATABASE_URL=mysql://root:@localhost/django_guardian | |
21 | ||
22 | - DJANGO_VERSION=1.8 DATABASE_URL=sqlite:// | |
23 | - DJANGO_VERSION=1.10 DATABASE_URL=sqlite:// | |
24 | - DJANGO_VERSION=1.11 DATABASE_URL=sqlite:// | |
25 | - DJANGO_VERSION=master DATABASE_URL=sqlite:// | |
26 | ||
27 | before_install: | |
28 | - pip install -q -U pytest | |
29 | ||
30 | 5 | install: |
31 | - travis_retry pip install -q mock==1.0.1 pytest pytest-django pytest-cov django-environ setuptools_scm | |
32 | # Install django master or version | |
33 | - bash -c "if [[ "$DJANGO_VERSION" == 'master' ]]; then pip install 'https://github.com/django/django/archive/master.tar.gz'; else pip install Django==$DJANGO_VERSION; fi; " | |
34 | # Install database drivers | |
35 | - bash -c "if [[ $DATABASE_URL = postgres* ]]; then pip install psycopg2==2.7.1; fi; " | |
36 | - bash -c "if [[ $DATABASE_URL = mysql* ]]; then pip install mysqlclient==1.3.10; fi; " | |
6 | - ./contrib/travis/install.sh | |
37 | 7 | |
38 | 8 | script: |
39 | - python ./setup.py --version | |
40 | - py.test --cov=guardian | |
41 | - bash -c "if [[ $DJANGO_VERSION = 1.10 || $DJANGO_VERSION = 1.11 || $DJANGO_VERSION = "master" ]]; then pip install .; cd example_project; python manage.py test; fi; " | |
9 | - ./contrib/travis/test.sh | |
42 | 10 | |
43 | 11 | notifications: |
44 | 12 | irc: "irc.freenode.net#django-guardian" |
45 | 13 | |
14 | templates: | |
15 | django21: &django21 DJANGO_VERSION=2.1.* | |
16 | django22: &django22 DJANGO_VERSION=2.2.* | |
17 | djangomaster: &djangomaster DJANGO_VERSION=master | |
18 | ||
19 | postgres: &postgres DATABASE_URL=postgres://postgres@/django_guardian | |
20 | mysql: &mysql DATABASE_URL=mysql://root:@localhost/django_guardian | |
21 | sqlite: &sqlite DATABASE_URL=sqlite:// | |
22 | ||
23 | pgdb: &pgdb | |
24 | addons: {postgresql: "10"} | |
25 | mariadb: &mariadb | |
26 | addons: {mariadb: "10.3"} | |
27 | ||
46 | 28 | |
47 | 29 | matrix: |
48 | 30 | fast_finish: true |
49 | exclude: | |
50 | - python: 2.7 | |
51 | env: DJANGO_VERSION=master DATABASE_URL=postgres://postgres@/django_guardian | |
52 | - python: 2.7 | |
53 | env: DJANGO_VERSION=master DATABASE_URL=mysql://root:@localhost/django_guardian | |
54 | - python: 2.7 | |
55 | env: DJANGO_VERSION=master DATABASE_URL=sqlite:// | |
56 | - python: 3.4 | |
57 | env: DJANGO_VERSION=master DATABASE_URL=postgres://postgres@/django_guardian | |
58 | - python: 3.4 | |
59 | env: DJANGO_VERSION=master DATABASE_URL=mysql://root:@localhost/django_guardian | |
60 | - python: 3.4 | |
61 | env: DJANGO_VERSION=master DATABASE_URL=sqlite:// | |
31 | include: | |
32 | - { python: 3.5, env: [*django21, *postgres], <<: *pgdb} | |
33 | - { python: 3.5, env: [*django21, *mysql], <<: *mariadb} | |
34 | - { python: 3.5, env: [*django21, *sqlite]} | |
35 | - { python: 3.5, env: [*django22, *postgres], <<: *pgdb} | |
36 | - { python: 3.5, env: [*django22, *mysql], <<: *mariadb} | |
37 | - { python: 3.5, env: [*django22, *sqlite]} | |
38 | ||
39 | - { python: 3.6, env: [*django21, *postgres], <<: *pgdb} | |
40 | - { python: 3.6, env: [*django21, *mysql], <<: *mariadb} | |
41 | - { python: 3.6, env: [*django21, *sqlite]} | |
42 | - { python: 3.6, env: [*django22, *postgres], <<: *pgdb} | |
43 | - { python: 3.6, env: [*django22, *mysql], <<: *mariadb} | |
44 | - { python: 3.6, env: [*django22, *sqlite]} | |
45 | - { python: 3.6, env: [*djangomaster, *postgres], <<: *pgdb} | |
46 | - { python: 3.6, env: [*djangomaster, *mysql], <<: *mariadb} | |
47 | - { python: 3.6, env: [*djangomaster, *sqlite]} | |
48 | ||
49 | - { python: 3.7, env: [*django21, *postgres], <<: *pgdb} | |
50 | - { python: 3.7, env: [*django21, *mysql], <<: *mariadb} | |
51 | - { python: 3.7, env: [*django21, *sqlite]} | |
52 | - { python: 3.7, env: [*django22, *postgres], <<: *pgdb} | |
53 | - { python: 3.7, env: [*django22, *mysql], <<: *mariadb} | |
54 | - { python: 3.7, env: [*django22, *sqlite]} | |
55 | - { python: 3.7, env: [*djangomaster, *postgres], <<: *pgdb} | |
56 | - { python: 3.7, env: [*djangomaster, *mysql], <<: *mariadb} | |
57 | - { python: 3.7, env: [*djangomaster, *sqlite]} | |
62 | 58 | allow_failures: |
63 | - env: DJANGO_VERSION=master DATABASE_URL=postgres://postgres@/django_guardian | |
64 | - env: DJANGO_VERSION=master DATABASE_URL=mysql://root:@localhost/django_guardian | |
65 | - env: DJANGO_VERSION=master DATABASE_URL=sqlite:// | |
59 | - env: [*djangomaster, *postgres] | |
60 | - env: [*djangomaster, *mysql] | |
61 | - env: [*djangomaster, *sqlite] |
55 | 55 | - Frank Wickström <frank@bambuser.com> |
56 | 56 | - George Karakostas <gckarakostas@gmail.com> |
57 | 57 | - Adam Dobrawy <guardian@jawnosc.tk> |
58 | - Jeff Hackshaw <intrepidevio@gmail.com> |
0 | Release 2.0.0 (June 11, 2019) | |
1 | ========================== | |
2 | ||
3 | * Drop support for Python 2.7 & 3.4 and Django 1.11 & 2.0 | |
4 | ||
5 | Release 1.5.1 (May 2, 2019) | |
6 | ========================== | |
7 | ||
8 | * Restore compatibility with Python 2.7 | |
9 | ||
10 | .. important:: | |
11 | The 1.5.x release line will be the last one that has support for Python 2.7. | |
12 | ||
13 | Release 1.5.0 (Jan 31, 2019) | |
14 | ========================== | |
15 | ||
16 | * Updates for compatibility with latest Python and Django versions. | |
17 | ||
0 | 18 | Release 1.4.9 (Jul 01, 2017) |
1 | 19 | ============================ |
2 | 20 | |
44 | 62 | * Moved queryset support in remove_perms to its own function |
45 | 63 | * Consolidated {User,Group}ObjectPermissionManager, move logic of bulk_*_perm |
46 | 64 | to managers |
47 | * `assign_perm` and `remove_perm` shortcuts accept `Permission` | |
65 | * `assign_perm` and `remove_perm` shortcuts accept `Permission` | |
48 | 66 | instance as `perm` and `QuerySet` as `obj` too. |
49 | 67 | * Consolidated bulk_assign_perm to assign_perm and bulk_remove_perm to remove_perm |
50 | 68 | * Upgraded Grappelli templates breadcrumbs block to new Django 1.9 and |
0 | Metadata-Version: 1.1 | |
1 | Name: django-guardian | |
2 | Version: 1.4.9 | |
3 | Summary: Implementation of per object permissions for Django. | |
4 | Home-page: http://github.com/django-guardian/django-guardian | |
5 | Author: Lukasz Balcerzak | |
6 | Author-email: lukaszbalcerzak@gmail.com | |
7 | License: BSD | |
8 | Download-URL: https://github.com/django-guardian/django-guardian/tags | |
9 | Description: =============== | |
10 | django-guardian | |
11 | =============== | |
12 | ||
13 | .. image:: https://travis-ci.org/django-guardian/django-guardian.svg?branch=devel | |
14 | :target: https://travis-ci.org/django-guardian/django-guardian | |
15 | ||
16 | ``django-guardian`` is an implementation of per object permissions [1]_ on top | |
17 | of Django's authorization backend | |
18 | ||
19 | Documentation | |
20 | ------------- | |
21 | ||
22 | Online documentation is available at https://django-guardian.readthedocs.io/. | |
23 | ||
24 | Requirements | |
25 | ------------ | |
26 | ||
27 | * Python 2.7 or 3.4+ | |
28 | * A supported version of Django (currently 1.8+) | |
29 | ||
30 | Travis CI tests on Django version 1.8, 1.10, and 1.11. | |
31 | ||
32 | Installation | |
33 | ------------ | |
34 | ||
35 | To install ``django-guardian`` simply run:: | |
36 | ||
37 | pip install django-guardian | |
38 | ||
39 | Configuration | |
40 | ------------- | |
41 | ||
42 | We need to hook ``django-guardian`` into our project. | |
43 | ||
44 | 1. Put ``guardian`` into your ``INSTALLED_APPS`` at settings module: | |
45 | ||
46 | .. code:: python | |
47 | ||
48 | INSTALLED_APPS = ( | |
49 | ... | |
50 | 'guardian', | |
51 | ) | |
52 | ||
53 | 2. Add extra authorization backend to your ``settings.py``: | |
54 | ||
55 | .. code:: python | |
56 | ||
57 | AUTHENTICATION_BACKENDS = ( | |
58 | 'django.contrib.auth.backends.ModelBackend', # default | |
59 | 'guardian.backends.ObjectPermissionBackend', | |
60 | ) | |
61 | ||
62 | 3. Create ``guardian`` database tables by running:: | |
63 | ||
64 | python manage.py migrate | |
65 | ||
66 | Usage | |
67 | ----- | |
68 | ||
69 | After installation and project hooks we can finally use object permissions | |
70 | with Django_. | |
71 | ||
72 | Lets start really quickly: | |
73 | ||
74 | .. code:: python | |
75 | ||
76 | >>> from django.contrib.auth.models import User, Group | |
77 | >>> jack = User.objects.create_user('jack', 'jack@example.com', 'topsecretagentjack') | |
78 | >>> admins = Group.objects.create(name='admins') | |
79 | >>> jack.has_perm('change_group', admins) | |
80 | False | |
81 | >>> from guardian.models import UserObjectPermission | |
82 | >>> UserObjectPermission.objects.assign_perm('change_group', jack, obj=admins) | |
83 | <UserObjectPermission: admins | jack | change_group> | |
84 | >>> jack.has_perm('change_group', admins) | |
85 | True | |
86 | ||
87 | Of course our agent jack here would not be able to *change_group* globally: | |
88 | ||
89 | .. code:: python | |
90 | ||
91 | >>> jack.has_perm('change_group') | |
92 | False | |
93 | ||
94 | Admin integration | |
95 | ----------------- | |
96 | ||
97 | Replace ``admin.ModelAdmin`` with ``GuardedModelAdmin`` for those models | |
98 | which should have object permissions support within admin panel. | |
99 | ||
100 | For example: | |
101 | ||
102 | .. code:: python | |
103 | ||
104 | from django.contrib import admin | |
105 | from myapp.models import Author | |
106 | from guardian.admin import GuardedModelAdmin | |
107 | ||
108 | # Old way: | |
109 | #class AuthorAdmin(admin.ModelAdmin): | |
110 | # pass | |
111 | ||
112 | # With object permissions support | |
113 | class AuthorAdmin(GuardedModelAdmin): | |
114 | pass | |
115 | ||
116 | admin.site.register(Author, AuthorAdmin) | |
117 | ||
118 | ||
119 | .. [1] Great paper about this feature is available at `djangoadvent articles <https://github.com/djangoadvent/djangoadvent-articles/blob/master/1.2/06_object-permissions.rst>`_. | |
120 | ||
121 | .. _Django: http://www.djangoproject.com/ | |
122 | ||
123 | ||
124 | Platform: UNKNOWN | |
125 | Classifier: Development Status :: 5 - Production/Stable | |
126 | Classifier: Environment :: Web Environment | |
127 | Classifier: Framework :: Django | |
128 | Classifier: Framework :: Django :: 1.8 | |
129 | Classifier: Framework :: Django :: 1.9 | |
130 | Classifier: Framework :: Django :: 1.10 | |
131 | Classifier: Framework :: Django :: 1.11 | |
132 | Classifier: Intended Audience :: Developers | |
133 | Classifier: License :: OSI Approved :: BSD License | |
134 | Classifier: Operating System :: OS Independent | |
135 | Classifier: Programming Language :: Python | |
136 | Classifier: Topic :: Security | |
137 | Classifier: Programming Language :: Python :: 2.7 | |
138 | Classifier: Programming Language :: Python :: 3.4 | |
139 | Classifier: Programming Language :: Python :: 3.5 | |
140 | Classifier: Programming Language :: Python :: 3.6 |
15 | 15 | Requirements |
16 | 16 | ------------ |
17 | 17 | |
18 | * Python 2.7 or 3.4+ | |
19 | * A supported version of Django (currently 1.8+) | |
18 | * Python 3.5+ | |
19 | * A supported version of Django (currently 2.1+) | |
20 | 20 | |
21 | Travis CI tests on Django version 1.8, 1.10, and 1.11. | |
21 | Travis CI tests on Django version 2.1, 2.2, and master. | |
22 | 22 | |
23 | 23 | Installation |
24 | 24 | ------------ |
40 | 40 | ... |
41 | 41 | 'guardian', |
42 | 42 | ) |
43 | ||
43 | ||
44 | 44 | 2. Add extra authorization backend to your ``settings.py``: |
45 | 45 | |
46 | 46 | .. code:: python |
110 | 110 | .. [1] Great paper about this feature is available at `djangoadvent articles <https://github.com/djangoadvent/djangoadvent-articles/blob/master/1.2/06_object-permissions.rst>`_. |
111 | 111 | |
112 | 112 | .. _Django: http://www.djangoproject.com/ |
113 |
42 | 42 | return ''.join(random.choice(chars) for i in range(length)) |
43 | 43 | |
44 | 44 | |
45 | def get_model_name(model): | |
46 | """ | |
47 | Returns the name of the model | |
48 | """ | |
49 | # model._meta.module_name is deprecated in django version 1.7 and removed in django version 1.8. | |
50 | # It is replaced by model._meta.model_name | |
51 | return model._meta.model_name | |
52 | ||
53 | ||
54 | class Call(object): | |
45 | class Call: | |
55 | 46 | |
56 | 47 | def __init__(self, args, kwargs, start=None, finish=None): |
57 | 48 | self.args = args |
63 | 54 | return self.finish - self.start |
64 | 55 | |
65 | 56 | |
66 | class Timed(object): | |
57 | class Timed: | |
67 | 58 | |
68 | 59 | def __init__(self, action=None): |
69 | 60 | self.action = action |
89 | 80 | return wrapper |
90 | 81 | |
91 | 82 | |
92 | class Benchmark(object): | |
83 | class Benchmark: | |
93 | 84 | |
94 | 85 | def __init__(self, name, users_count, objects_count, |
95 | 86 | objects_with_perms_count, model, subquery): |
99 | 90 | self.objects_with_perms_count = objects_with_perms_count |
100 | 91 | self.subquery = subquery |
101 | 92 | self.Model = model |
102 | self.perm = 'add_%s' % get_model_name(model) | |
93 | self.perm = 'add_%s' % model._meta.model_name | |
103 | 94 | |
104 | 95 | def info(self, msg): |
105 | 96 | print(colorize(msg + '\n', fg='green')) |
106 | 97 | |
107 | 98 | def prepare_db(self): |
108 | 99 | from django.core.management import call_command |
109 | call_command('syncdb', interactive=False) | |
100 | call_command('makemigrations', interactive=False) | |
101 | call_command('migrate', interactive=False) | |
110 | 102 | |
111 | 103 | for model in [User, Group, self.Model]: |
112 | 104 | model.objects.all().delete() |
0 | #!/bin/bash | |
1 | ||
2 | set -ev | |
3 | ||
4 | pip install -U pip | |
5 | ||
6 | # Array of packages | |
7 | PACKAGES=('mock==1.0.1' 'pytest' 'pytest-django' 'pytest-cov' 'django-environ' 'setuptools_scm') | |
8 | # Install django master or version | |
9 | if [[ "$DJANGO_VERSION" == 'master' ]]; then | |
10 | PACKAGES+=('https://github.com/django/django/archive/master.tar.gz'); | |
11 | else | |
12 | PACKAGES+=("Django==$DJANGO_VERSION"); | |
13 | fi; | |
14 | ||
15 | # Install database drivers | |
16 | if [[ $DATABASE_URL = postgres* ]]; then | |
17 | PACKAGES+=('psycopg2==2.7.5'); | |
18 | fi; | |
19 | ||
20 | if [[ $DATABASE_URL = mysql* ]]; then | |
21 | PACKAGES+=('mysqlclient==1.3.13'); | |
22 | fi; | |
23 | echo "Install " ${PACKAGES[*]}; | |
24 | pip install --upgrade --upgrade-strategy=only-if-needed ${PACKAGES[*]}; | |
25 | pip check |
0 | #!/bin/bash | |
1 | ||
2 | python ./setup.py --version | |
3 | py.test --cov=guardian | |
4 | ||
5 | # Test example_project on supported django versions | |
6 | if [ "${DJANGO_VERSION:0:3}" = "2.1" ] || \ | |
7 | [ "${DJANGO_VERSION:0:3}" = "2.2" ] || \ | |
8 | [ "$DJANGO_VERSION" = "master" ]; then | |
9 | pip install .; | |
10 | cd example_project; | |
11 | python -Wa manage.py test; | |
12 | fi; |
0 | Metadata-Version: 1.1 | |
1 | Name: django-guardian | |
2 | Version: 1.4.9 | |
3 | Summary: Implementation of per object permissions for Django. | |
4 | Home-page: http://github.com/django-guardian/django-guardian | |
5 | Author: Lukasz Balcerzak | |
6 | Author-email: lukaszbalcerzak@gmail.com | |
7 | License: BSD | |
8 | Download-URL: https://github.com/django-guardian/django-guardian/tags | |
9 | Description: =============== | |
10 | django-guardian | |
11 | =============== | |
12 | ||
13 | .. image:: https://travis-ci.org/django-guardian/django-guardian.svg?branch=devel | |
14 | :target: https://travis-ci.org/django-guardian/django-guardian | |
15 | ||
16 | ``django-guardian`` is an implementation of per object permissions [1]_ on top | |
17 | of Django's authorization backend | |
18 | ||
19 | Documentation | |
20 | ------------- | |
21 | ||
22 | Online documentation is available at https://django-guardian.readthedocs.io/. | |
23 | ||
24 | Requirements | |
25 | ------------ | |
26 | ||
27 | * Python 2.7 or 3.4+ | |
28 | * A supported version of Django (currently 1.8+) | |
29 | ||
30 | Travis CI tests on Django version 1.8, 1.10, and 1.11. | |
31 | ||
32 | Installation | |
33 | ------------ | |
34 | ||
35 | To install ``django-guardian`` simply run:: | |
36 | ||
37 | pip install django-guardian | |
38 | ||
39 | Configuration | |
40 | ------------- | |
41 | ||
42 | We need to hook ``django-guardian`` into our project. | |
43 | ||
44 | 1. Put ``guardian`` into your ``INSTALLED_APPS`` at settings module: | |
45 | ||
46 | .. code:: python | |
47 | ||
48 | INSTALLED_APPS = ( | |
49 | ... | |
50 | 'guardian', | |
51 | ) | |
52 | ||
53 | 2. Add extra authorization backend to your ``settings.py``: | |
54 | ||
55 | .. code:: python | |
56 | ||
57 | AUTHENTICATION_BACKENDS = ( | |
58 | 'django.contrib.auth.backends.ModelBackend', # default | |
59 | 'guardian.backends.ObjectPermissionBackend', | |
60 | ) | |
61 | ||
62 | 3. Create ``guardian`` database tables by running:: | |
63 | ||
64 | python manage.py migrate | |
65 | ||
66 | Usage | |
67 | ----- | |
68 | ||
69 | After installation and project hooks we can finally use object permissions | |
70 | with Django_. | |
71 | ||
72 | Lets start really quickly: | |
73 | ||
74 | .. code:: python | |
75 | ||
76 | >>> from django.contrib.auth.models import User, Group | |
77 | >>> jack = User.objects.create_user('jack', 'jack@example.com', 'topsecretagentjack') | |
78 | >>> admins = Group.objects.create(name='admins') | |
79 | >>> jack.has_perm('change_group', admins) | |
80 | False | |
81 | >>> from guardian.models import UserObjectPermission | |
82 | >>> UserObjectPermission.objects.assign_perm('change_group', jack, obj=admins) | |
83 | <UserObjectPermission: admins | jack | change_group> | |
84 | >>> jack.has_perm('change_group', admins) | |
85 | True | |
86 | ||
87 | Of course our agent jack here would not be able to *change_group* globally: | |
88 | ||
89 | .. code:: python | |
90 | ||
91 | >>> jack.has_perm('change_group') | |
92 | False | |
93 | ||
94 | Admin integration | |
95 | ----------------- | |
96 | ||
97 | Replace ``admin.ModelAdmin`` with ``GuardedModelAdmin`` for those models | |
98 | which should have object permissions support within admin panel. | |
99 | ||
100 | For example: | |
101 | ||
102 | .. code:: python | |
103 | ||
104 | from django.contrib import admin | |
105 | from myapp.models import Author | |
106 | from guardian.admin import GuardedModelAdmin | |
107 | ||
108 | # Old way: | |
109 | #class AuthorAdmin(admin.ModelAdmin): | |
110 | # pass | |
111 | ||
112 | # With object permissions support | |
113 | class AuthorAdmin(GuardedModelAdmin): | |
114 | pass | |
115 | ||
116 | admin.site.register(Author, AuthorAdmin) | |
117 | ||
118 | ||
119 | .. [1] Great paper about this feature is available at `djangoadvent articles <https://github.com/djangoadvent/djangoadvent-articles/blob/master/1.2/06_object-permissions.rst>`_. | |
120 | ||
121 | .. _Django: http://www.djangoproject.com/ | |
122 | ||
123 | ||
124 | Platform: UNKNOWN | |
125 | Classifier: Development Status :: 5 - Production/Stable | |
126 | Classifier: Environment :: Web Environment | |
127 | Classifier: Framework :: Django | |
128 | Classifier: Framework :: Django :: 1.8 | |
129 | Classifier: Framework :: Django :: 1.9 | |
130 | Classifier: Framework :: Django :: 1.10 | |
131 | Classifier: Framework :: Django :: 1.11 | |
132 | Classifier: Intended Audience :: Developers | |
133 | Classifier: License :: OSI Approved :: BSD License | |
134 | Classifier: Operating System :: OS Independent | |
135 | Classifier: Programming Language :: Python | |
136 | Classifier: Topic :: Security | |
137 | Classifier: Programming Language :: Python :: 2.7 | |
138 | Classifier: Programming Language :: Python :: 3.4 | |
139 | Classifier: Programming Language :: Python :: 3.5 | |
140 | Classifier: Programming Language :: Python :: 3.6 |
0 | .gitignore | |
1 | .isort.cfg | |
2 | .travis.yml | |
3 | AUTHORS | |
4 | CHANGES | |
5 | LICENSE | |
6 | MANIFEST.in | |
7 | README.rst | |
8 | extras.py | |
9 | manage.py | |
10 | pytest.ini | |
11 | requirements.txt | |
12 | run_test_and_report.sh | |
13 | setup.cfg | |
14 | setup.py | |
15 | tox.ini | |
16 | utils.py | |
17 | benchmarks/__init__.py | |
18 | benchmarks/models.py | |
19 | benchmarks/run_benchmarks.py | |
20 | benchmarks/settings.py | |
21 | django_guardian.egg-info/PKG-INFO | |
22 | django_guardian.egg-info/SOURCES.txt | |
23 | django_guardian.egg-info/dependency_links.txt | |
24 | django_guardian.egg-info/not-zip-safe | |
25 | django_guardian.egg-info/requires.txt | |
26 | django_guardian.egg-info/top_level.txt | |
27 | docs/Makefile | |
28 | docs/conf.py | |
29 | docs/configuration.rst | |
30 | docs/exts.py | |
31 | docs/index.rst | |
32 | docs/installation.rst | |
33 | docs/license.rst | |
34 | docs/make.bat | |
35 | docs/overview.rst | |
36 | docs/watch-docs.sh | |
37 | docs/api/guardian.admin.rst | |
38 | docs/api/guardian.backends.rst | |
39 | docs/api/guardian.core.rst | |
40 | docs/api/guardian.decorators.rst | |
41 | docs/api/guardian.forms.rst | |
42 | docs/api/guardian.management.commands.rst | |
43 | docs/api/guardian.managers.rst | |
44 | docs/api/guardian.mixins.rst | |
45 | docs/api/guardian.models.rst | |
46 | docs/api/guardian.shortcuts.rst | |
47 | docs/api/guardian.templatetags.guardian_tags.rst | |
48 | docs/api/guardian.utils.rst | |
49 | docs/api/index.rst | |
50 | docs/develop/changes.rst | |
51 | docs/develop/index.rst | |
52 | docs/develop/overview.rst | |
53 | docs/develop/supported-versions.rst | |
54 | docs/develop/testing.rst | |
55 | docs/userguide/admin-integration.rst | |
56 | docs/userguide/assign.rst | |
57 | docs/userguide/caveats.rst | |
58 | docs/userguide/check.rst | |
59 | docs/userguide/custom-user-model.rst | |
60 | docs/userguide/example_project.rst | |
61 | docs/userguide/index.rst | |
62 | docs/userguide/performance.rst | |
63 | docs/userguide/remove.rst | |
64 | example_project/__init__.py | |
65 | example_project/manage.py | |
66 | example_project/requirements.txt | |
67 | example_project/settings.py | |
68 | example_project/urls.py | |
69 | example_project/articles/__init__.py | |
70 | example_project/articles/admin.py | |
71 | example_project/articles/apps.py | |
72 | example_project/articles/models.py | |
73 | example_project/articles/tests.py | |
74 | example_project/articles/urls.py | |
75 | example_project/articles/views.py | |
76 | example_project/articles/migrations/0001_initial.py | |
77 | example_project/articles/migrations/0002_auto_20160622_1050.py | |
78 | example_project/articles/migrations/__init__.py | |
79 | example_project/articles/templates/articles/article_confirm_delete.html | |
80 | example_project/articles/templates/articles/article_detail.html | |
81 | example_project/articles/templates/articles/article_form.html | |
82 | example_project/articles/templates/articles/article_list.html | |
83 | example_project/core/__init__.py | |
84 | example_project/core/admin.py | |
85 | example_project/core/context_processors.py | |
86 | example_project/core/models.py | |
87 | example_project/core/migrations/0001_initial.py | |
88 | example_project/core/migrations/__init__.py | |
89 | example_project/posts/__init__.py | |
90 | example_project/posts/admin.py | |
91 | example_project/posts/models.py | |
92 | example_project/posts/urls.py | |
93 | example_project/posts/views.py | |
94 | example_project/posts/migrations/0001_initial.py | |
95 | example_project/posts/migrations/__init__.py | |
96 | example_project/posts/templates/posts/post_detail.html | |
97 | example_project/posts/templates/posts/post_list.html | |
98 | example_project/static/css/bootstrap.min.css | |
99 | example_project/static/img/glyphicons-halflings-white.png | |
100 | example_project/static/img/glyphicons-halflings.png | |
101 | example_project/static/js/bootstrap.min.js | |
102 | example_project/templates/403.html | |
103 | example_project/templates/404.html | |
104 | example_project/templates/500.html | |
105 | example_project/templates/base.html | |
106 | example_project/templates/home.html | |
107 | guardian/__init__.py | |
108 | guardian/admin.py | |
109 | guardian/apps.py | |
110 | guardian/backends.py | |
111 | guardian/checks.py | |
112 | guardian/compat.py | |
113 | guardian/core.py | |
114 | guardian/ctypes.py | |
115 | guardian/decorators.py | |
116 | guardian/exceptions.py | |
117 | guardian/forms.py | |
118 | guardian/managers.py | |
119 | guardian/mixins.py | |
120 | guardian/models.py | |
121 | guardian/shortcuts.py | |
122 | guardian/utils.py | |
123 | guardian/conf/__init__.py | |
124 | guardian/conf/settings.py | |
125 | guardian/locale/es/LC_MESSAGES/django.mo | |
126 | guardian/locale/es/LC_MESSAGES/django.po | |
127 | guardian/locale/fr/LC_MESSAGES/django.mo | |
128 | guardian/locale/fr/LC_MESSAGES/django.po | |
129 | guardian/locale/pl/LC_MESSAGES/django.mo | |
130 | guardian/locale/pl/LC_MESSAGES/django.po | |
131 | guardian/locale/pt_BR/LC_MESSAGES/django.mo | |
132 | guardian/locale/pt_BR/LC_MESSAGES/django.po | |
133 | guardian/locale/ru/LC_MESSAGES/django.mo | |
134 | guardian/locale/ru/LC_MESSAGES/django.po | |
135 | guardian/management/__init__.py | |
136 | guardian/management/commands/__init__.py | |
137 | guardian/management/commands/clean_orphan_obj_perms.py | |
138 | guardian/migrations/0001_initial.py | |
139 | guardian/migrations/__init__.py | |
140 | guardian/static/guardian/img/icon-no.svg | |
141 | guardian/static/guardian/img/icon-yes.svg | |
142 | guardian/templates/admin/guardian/contrib/grappelli/field.html | |
143 | guardian/templates/admin/guardian/contrib/grappelli/obj_perms_manage.html | |
144 | guardian/templates/admin/guardian/contrib/grappelli/obj_perms_manage_group.html | |
145 | guardian/templates/admin/guardian/contrib/grappelli/obj_perms_manage_user.html | |
146 | guardian/templates/admin/guardian/model/change_form.html | |
147 | guardian/templates/admin/guardian/model/field.html | |
148 | guardian/templates/admin/guardian/model/obj_perms_manage.html | |
149 | guardian/templates/admin/guardian/model/obj_perms_manage_group.html | |
150 | guardian/templates/admin/guardian/model/obj_perms_manage_user.html | |
151 | guardian/templates/admin/guardian/model/obj_perms_no.html | |
152 | guardian/templates/admin/guardian/model/obj_perms_yes.html | |
153 | guardian/templatetags/__init__.py | |
154 | guardian/templatetags/guardian_tags.py | |
155 | guardian/testapp/__init__.py | |
156 | guardian/testapp/models.py | |
157 | guardian/testapp/testsettings.py | |
158 | guardian/testapp/migrations/0001_initial.py | |
159 | guardian/testapp/migrations/0002_logentrywithgroup.py | |
160 | guardian/testapp/migrations/__init__.py | |
161 | guardian/testapp/tests/__init__.py | |
162 | guardian/testapp/tests/conf.py | |
163 | guardian/testapp/tests/test_admin.py | |
164 | guardian/testapp/tests/test_checks.py | |
165 | guardian/testapp/tests/test_conf.py | |
166 | guardian/testapp/tests/test_core.py | |
167 | guardian/testapp/tests/test_custompkmodel.py | |
168 | guardian/testapp/tests/test_decorators.py | |
169 | guardian/testapp/tests/test_direct_rel.py | |
170 | guardian/testapp/tests/test_forms.py | |
171 | guardian/testapp/tests/test_management.py | |
172 | guardian/testapp/tests/test_managers.py | |
173 | guardian/testapp/tests/test_mixins.py | |
174 | guardian/testapp/tests/test_orphans.py | |
175 | guardian/testapp/tests/test_other.py | |
176 | guardian/testapp/tests/test_shortcuts.py | |
177 | guardian/testapp/tests/test_tags.py | |
178 | guardian/testapp/tests/test_utils.py | |
179 | guardian/testapp/tests/urls.py | |
180 | guardian/testapp/tests/templates/404.html | |
181 | guardian/testapp/tests/templates/500.html | |
182 | guardian/testapp/tests/templates/blank.html | |
183 | guardian/testapp/tests/templates/dummy403.html | |
184 | guardian/testapp/tests/templates/dummy404.html | |
185 | guardian/testapp/tests/templates/list.html⏎ |
13 | 13 | .. autoclass:: guardian.admin.GuardedModelAdmin |
14 | 14 | :members: |
15 | 15 | |
16 | GuardedModelAdminMixin | |
17 | ---------------------- | |
18 | ||
19 | .. autoclass:: guardian.admin.GuardedModelAdminMixin | |
20 | :members: | |
21 |
0 | # -*- coding: utf-8 -*- | |
1 | # | |
2 | 0 | # django-guardian documentation build configuration file, created by |
3 | 1 | # sphinx-quickstart on Thu Feb 18 23:18:28 2010. |
4 | 2 | # |
20 | 20 | |
21 | 21 | .. note:: |
22 | 22 | Once project is configured to work with ``django-guardian``, calling |
23 | ``syncdb`` management command would create ``User`` instance for | |
23 | ``migrate`` management command would create ``User`` instance for | |
24 | 24 | anonymous user support (with name of ``AnonymousUser``). |
25 | 25 | |
26 | 26 | .. note:: |
32 | 32 | |
33 | 33 | .. code-block:: python |
34 | 34 | |
35 | from guardian.compat import get_user_model | |
35 | from django.contrib.auth import get_user_model | |
36 | 36 | User = get_user_model() |
37 | 37 | anon = User.get_anonymous() |
38 | anon.is_anonymous() # returns False | |
38 | anon.is_anonymous # returns False | |
39 | 39 | |
40 | 40 | We can change id to whatever we like. Project should be now ready to use object |
41 | 41 | permissions. |
42 | ||
42 | ||
43 | 43 | |
44 | 44 | Optional settings |
45 | 45 | ================= |
113 | 113 | |
114 | 114 | Defaults to ``"AnonymousUser"``. |
115 | 115 | |
116 | .. seealso:: https://docs.djangoproject.com/en/1.5/topics/auth/customizing/#substituting-a-custom-user-model | |
116 | .. seealso:: https://docs.djangoproject.com/en/2.1/topics/auth/customizing/#substituting-a-custom-user-model | |
117 | 117 | |
118 | 118 | |
119 | 119 | .. setting:: GUARDIAN_GET_INIT_ANONYMOUS_USER |
126 | 126 | Guardian supports object level permissions for anonymous users, however when |
127 | 127 | in our project we use custom User model, default function might fail. This can |
128 | 128 | lead to issues as ``guardian`` tries to create anonymous user after each |
129 | ``syncdb`` call. Object that is going to be created is retrieved using function | |
129 | ``migrate`` call. Object that is going to be created is retrieved using function | |
130 | 130 | pointed by this setting. Once retrieved, ``save`` method would be called on |
131 | 131 | that instance. |
132 | 132 | |
151 | 151 | polymorphic models and the regular model ``ContentType`` for non-polymorphic |
152 | 152 | classes. |
153 | 153 | |
154 | Defaults to ``"guardian.ctypes.get_default_content_type"``.⏎ | |
154 | Defaults to ``"guardian.ctypes.get_default_content_type"``. |
85 | 85 | * Commit changes of codebase, e.g. ``git commit -m "Release 1.4.8" -a``. |
86 | 86 | * Tag a new release, e.g. ``git tag "v1.4.8"``. |
87 | 87 | * Push new tag to repo - ``git push origin --tags``. |
88 | * Push a new release to PyPI - ``python setup.py sdist bdist_wheel upload``. | |
88 | * Push a new release to PyPI - ``python3 setup.py sdist bdist_wheel upload``. |
2 | 2 | Supported versions |
3 | 3 | ================== |
4 | 4 | |
5 | ``django-guardian`` supports Python 2.7+/3.3+ and Django 1.7+. | |
5 | ``django-guardian`` supports Python 3.5+ and Django 2.1+. | |
6 | 6 | |
7 | 7 | Rules |
8 | 8 | ----- |
9 | 9 | |
10 | * We would support Python 2.7. We also support Python 3.3+. | |
11 | * Support for Python 3.3 may get dropped in the future. | |
12 | * We support Django 1.7+. This is due to many simplifications in code we could | |
10 | * We support Python 3.5+. | |
11 | * We support Django 2.1+. This is due to many simplifications in code we could | |
13 | 12 | do. |
2 | 2 | Installation |
3 | 3 | ============ |
4 | 4 | |
5 | This application requires Django_ 1.7 or higher and it is the only prerequisite | |
5 | This application requires Django_ 1.11 or higher and it is the only prerequisite | |
6 | 6 | before ``django-guardian`` may be used. |
7 | 7 | |
8 | 8 | In order to install ``django-guardian`` simply use ``pip``:: |
30 | 30 | |
31 | 31 | class Meta: |
32 | 32 | permissions = ( |
33 | ('view_post', 'Can view post'), | |
33 | ('hide_post', 'Can hide post'), | |
34 | 34 | ) |
35 | 35 | get_latest_by = 'created_at' |
36 | 36 | |
37 | def __unicode__(self): | |
37 | def __str__(self): | |
38 | 38 | return self.title |
39 | 39 | |
40 | 40 | def get_absolute_url(self): |
89 | 89 | .. note:: |
90 | 90 | Example above is shipped with ``django-guardian`` package with the example |
91 | 91 | project. |
92 |
18 | 18 | reported_by = models.ForeignKey(User, on_delete=models.CASCADE) |
19 | 19 | created_at = models.DateTimeField(auto_now_add=True) |
20 | 20 | |
21 | ... and we want to be able to set custom permission *view_task*. We let Django | |
21 | ... and we want to be able to set custom permission *assign_task*. We let Django | |
22 | 22 | know to do so by adding ``permissions`` tuple to ``Meta`` class and our final |
23 | 23 | model could look like: |
24 | 24 | |
32 | 32 | |
33 | 33 | class Meta: |
34 | 34 | permissions = ( |
35 | ('view_task', 'View task'), | |
35 | ('assign_task', 'Assign task'), | |
36 | 36 | ) |
37 | 37 | |
38 | After we call ``syncdb`` (with a ``--all`` switch if you are using south) | |
39 | management command our *view_task* permission would be added to default set of | |
40 | permissions. | |
38 | After we call management commands ``makemigrations`` and ``migrate`` | |
39 | our *assign_task* permission would be added to default set of permissions. | |
41 | 40 | |
42 | 41 | .. note:: |
43 | 42 | By default, Django adds 3 permissions for each registered model: |
45 | 44 | - *add_modelname* |
46 | 45 | - *change_modelname* |
47 | 46 | - *delete_modelname* |
47 | - *view_modelname* (since Django 2.1) | |
48 | 48 | |
49 | 49 | (where *modelname* is a simplified name of our model's class). See |
50 | 50 | https://docs.djangoproject.com/en/dev/topics/auth/default/#default-permissions for |
51 | 51 | more detail. |
52 | ||
53 | .. note:: | |
54 | When upgrading to Django 2.1 custom created *view_modelname* permissions | |
55 | clash with the newly built-in ones. The simplest way to fix this is to | |
56 | add ``default_permissions = ('add', 'change', 'delete')`` to ``Meta``. | |
52 | 57 | |
53 | 58 | There is nothing new here since creation of permissions is |
54 | 59 | `handled by django <http://docs.djangoproject.com/en/1.2/topics/auth/#id1>`_. |
65 | 70 | For user |
66 | 71 | ~~~~~~~~ |
67 | 72 | |
68 | Continuing our example we now can allow Joe user to view some task: | |
73 | Continuing our example we now can allow Joe user to assign some task: | |
69 | 74 | |
70 | 75 | .. code-block:: python |
71 | 76 | |
73 | 78 | >>> boss = User.objects.create(username='Big Boss') |
74 | 79 | >>> joe = User.objects.create(username='joe') |
75 | 80 | >>> task = Task.objects.create(summary='Some job', content='', reported_by=boss) |
76 | >>> joe.has_perm('view_task', task) | |
81 | >>> joe.has_perm('assign_task', task) | |
77 | 82 | False |
78 | 83 | |
79 | 84 | Well, not so fast Joe, let us create an object permission finally: |
81 | 86 | .. code-block:: python |
82 | 87 | |
83 | 88 | >>> from guardian.shortcuts import assign_perm |
84 | >>> assign_perm('view_task', joe, task) | |
85 | >>> joe.has_perm('view_task', task) | |
89 | >>> assign_perm('assign_task', joe, task) | |
90 | >>> joe.has_perm('assign_task', task) | |
86 | 91 | True |
87 | 92 | |
88 | 93 |
79 | 79 | |
80 | 80 | .. code-block:: python |
81 | 81 | |
82 | from django.shortcuts import render_to_response | |
82 | from django.shortcuts import render | |
83 | 83 | from django.template import RequestContext |
84 | 84 | from projects.models import Project |
85 | 85 | from guardian.shortcuts import get_objects_for_user |
86 | 86 | |
87 | 87 | def user_dashboard(request, template_name='projects/dashboard.html'): |
88 | 88 | projects = get_objects_for_user(request.user, 'projects.view_project') |
89 | return render_to_response(template_name, {'projects': projects}, | |
89 | return render(request, template_name, {'projects': projects}, | |
90 | 90 | RequestContext(request)) |
91 | 91 | |
92 | 92 | It is also possible to provide list of permissions rather than single string, |
4 | 4 | |
5 | 5 | .. versionadded:: 1.1 |
6 | 6 | |
7 | Django 1.5 comes with the ability to customize default ``auth.User`` model | |
7 | Django comes with the ability to customize default ``auth.User`` model | |
8 | 8 | - either by subclassing ``AbstractUser`` or defining very own class. This can be |
9 | 9 | very powerful, it must be done with caution, though. Basically, if we subclass |
10 | 10 | ``AbstractUser`` or define many-to-many relation with ``auth.Group`` (and give |
25 | 25 | auth.Group relation django-guardian will BREAK**. |
26 | 26 | |
27 | 27 | |
28 | .. seealso:: Read more about customizing User model introduced in Django 1.5 | |
29 | here: https://docs.djangoproject.com/en/1.5/topics/auth/customizing/#substituting-a-custom-user-model. | |
28 | .. seealso:: Read more about customizing User model | |
29 | here: https://docs.djangoproject.com/en/2.1/topics/auth/customizing/#substituting-a-custom-user-model. | |
30 | 30 | |
31 | 31 | |
32 | 32 | .. _custom-user-model-anonymous: |
104 | 104 | is discouraged (it's not consistent and might be a quick road to hell from the |
105 | 105 | maintainence point of view, especially). |
106 | 106 | |
107 | To temporarily disable the detection of this direct relation model, add | |
108 | ``enabled = False`` to the object permission model classes. This is useful to | |
109 | allow the ORM to create the tables for you and for you to migrate data from the | |
110 | generic model tables before using the direct models. | |
111 | ||
107 | 112 | .. note:: |
108 | 113 | By defining direct relation models we can also tweak that object permission |
109 | 114 | model, i.e. by adding some fields. |
0 | # -*- coding: utf-8 -*- | |
1 | 0 | # Generated by Django 1.9.4 on 2016-06-22 05:23 |
2 | from __future__ import unicode_literals | |
3 | ||
4 | 1 | from django.conf import settings |
5 | 2 | from django.db import migrations, models |
6 | 3 | import django.db.models.deletion |
27 | 24 | ], |
28 | 25 | options={ |
29 | 26 | 'get_latest_by': 'created_at', |
30 | 'permissions': (('view_articlew', 'Can view article'),), | |
27 | 'default_permissions': ('add', 'change', 'delete'), | |
28 | 'permissions': (('view_article', 'Can view article'),), | |
31 | 29 | }, |
32 | 30 | ), |
33 | 31 | migrations.CreateModel( |
0 | # -*- coding: utf-8 -*- | |
1 | # Generated by Django 1.9.4 on 2016-06-22 10:50 | |
2 | from __future__ import unicode_literals | |
3 | ||
4 | from django.db import migrations | |
5 | ||
6 | ||
7 | class Migration(migrations.Migration): | |
8 | ||
9 | dependencies = [ | |
10 | ('articles', '0001_initial'), | |
11 | ] | |
12 | ||
13 | operations = [ | |
14 | migrations.AlterModelOptions( | |
15 | name='article', | |
16 | options={'get_latest_by': 'created_at', 'permissions': (('view_article', 'Can view article'),)}, | |
17 | ), | |
18 | ] |
0 | from __future__ import unicode_literals | |
1 | ||
2 | 0 | from django.db import models |
3 | from guardian.compat import reverse | |
1 | from django.urls import reverse | |
4 | 2 | |
5 | 3 | |
6 | 4 | from guardian.models import GroupObjectPermissionBase, UserObjectPermissionBase |
13 | 11 | created_at = models.DateTimeField(auto_now_add=True, db_index=True) |
14 | 12 | |
15 | 13 | class Meta: |
14 | default_permissions = ('add', 'change', 'delete') | |
16 | 15 | permissions = ( |
17 | 16 | ('view_article', 'Can view article'), |
18 | 17 | ) |
19 | 18 | get_latest_by = 'created_at' |
20 | 19 | |
21 | def __unicode__(self): | |
20 | def __str__(self): | |
22 | 21 | return self.title |
23 | 22 | |
24 | 23 | def get_absolute_url(self): |
0 | from django.contrib.auth import get_user_model | |
0 | 1 | from django.test import TestCase |
1 | 2 | from django.test.client import RequestFactory |
2 | from guardian.compat import get_user_model | |
3 | 3 | from guardian.shortcuts import assign_perm |
4 | 4 | from articles.models import Article |
5 | 5 | from articles.views import (ArticleCreateView, ArticleDeleteView, ArticleDetailView, |
0 | # -*- coding: utf-8 -*- | |
1 | from __future__ import unicode_literals | |
2 | ||
3 | 0 | from django.conf.urls import url |
4 | 1 | from . import views |
5 | 2 |
0 | from django.urls import reverse_lazy | |
0 | 1 | from django.views.generic import (CreateView, DeleteView, DetailView, ListView, |
1 | 2 | UpdateView) |
2 | from guardian.compat import reverse_lazy | |
3 | 3 | from guardian.mixins import PermissionRequiredMixin, PermissionListMixin |
4 | 4 | from guardian.shortcuts import assign_perm |
5 | 5 | from articles.models import Article |
22 | 22 | fields = ['title', 'slug', 'content'] |
23 | 23 | |
24 | 24 | def form_valid(self, *args, **kwargs): |
25 | resp = super(ArticleCreateView, self).form_valid(*args, **kwargs) | |
25 | resp = super().form_valid(*args, **kwargs) | |
26 | 26 | assign_perm('view_article', self.request.user, self.object) |
27 | 27 | assign_perm('change_article', self.request.user, self.object) |
28 | 28 | assign_perm('delete_article', self.request.user, self.object) |
0 | # -*- coding: utf-8 -*- | |
1 | from __future__ import unicode_literals | |
2 | 0 | import django |
3 | 1 | from django.db import migrations, models |
4 | 2 | import django.utils.timezone |
5 | 3 | import django.core.validators |
6 | 4 | import django.contrib.auth.models |
7 | ||
8 | if django.VERSION >= (1, 8): | |
9 | django_version_depend = {'managers': [ | |
10 | ('objects', django.contrib.auth.models.UserManager()), | |
11 | ]} | |
12 | else: | |
13 | django_version_depend = {} | |
14 | 5 | |
15 | 6 | |
16 | 7 | class Migration(migrations.Migration): |
56 | 47 | 'verbose_name': 'user', |
57 | 48 | 'verbose_name_plural': 'users', |
58 | 49 | }, |
59 | **django_version_depend | |
50 | managers=[ | |
51 | ('objects', django.contrib.auth.models.UserManager()), | |
52 | ], | |
60 | 53 | ), |
61 | 54 | ] |
0 | import datetime | |
1 | ||
0 | 2 | from django.contrib.auth.models import AbstractUser |
1 | 3 | from django.db import models |
2 | import datetime | |
3 | 4 | |
4 | 5 | |
5 | 6 | class CustomUser(AbstractUser): |
0 | 0 | #!/usr/bin/env python |
1 | import django | |
2 | 1 | import os |
3 | 2 | import sys |
4 | ||
5 | if django.VERSION < (1, 5): | |
6 | sys.stderr.write("ERROR: guardian's example project must be run with " | |
7 | "Django 1.8 or later!\n") | |
8 | sys.exit(1) | |
9 | 3 | |
10 | 4 | |
11 | 5 | if __name__ == "__main__": |
0 | # -*- coding: utf-8 -*- | |
1 | from __future__ import unicode_literals | |
2 | ||
3 | 0 | from django.db import migrations, models |
4 | 1 | |
5 | 2 | |
22 | 19 | ], |
23 | 20 | options={ |
24 | 21 | 'get_latest_by': 'created_at', |
22 | 'default_permissions': ('add', 'change', 'delete'), | |
25 | 23 | 'permissions': (('view_post', 'Can view post'),), |
26 | 24 | }, |
27 | 25 | ), |
0 | 0 | from django.db import models |
1 | from django.urls import reverse | |
1 | 2 | |
2 | 3 | |
3 | 4 | class Post(models.Model): |
7 | 8 | created_at = models.DateTimeField(auto_now_add=True, db_index=True) |
8 | 9 | |
9 | 10 | class Meta: |
11 | default_permissions = ('add', 'change', 'delete') | |
10 | 12 | permissions = ( |
11 | 13 | ('view_post', 'Can view post'), |
12 | 14 | ) |
13 | 15 | get_latest_by = 'created_at' |
14 | 16 | |
15 | def __unicode__(self): | |
17 | def __str__(self): | |
16 | 18 | return self.title |
17 | 19 | |
18 | @models.permalink | |
19 | 20 | def get_absolute_url(self): |
20 | return ('posts_post_detail', (), {'slug': self.slug}) | |
21 | return reverse('posts_post_detail', args=(), kwargs={'slug': self.slug}) |
0 | from django.contrib.auth import get_user_model | |
0 | 1 | from django.contrib.auth.models import Group |
1 | from django.shortcuts import render_to_response, get_object_or_404 | |
2 | from django.shortcuts import render, get_object_or_404 | |
2 | 3 | from django.views.generic import ListView |
3 | 4 | from django.template import RequestContext |
4 | 5 | from guardian.decorators import permission_required_or_403 |
5 | from guardian.compat import get_user_model | |
6 | 6 | |
7 | 7 | from .models import Post |
8 | 8 | |
23 | 23 | 'users': User.objects.all(), |
24 | 24 | 'groups': Group.objects.all(), |
25 | 25 | } |
26 | return render_to_response( | |
27 | 'posts/post_detail.html', data, | |
26 | return render( | |
27 | request, 'posts/post_detail.html', data, | |
28 | 28 | RequestContext(request)) |
0 | Django==1.9.4 | |
1 | django-environ==0.4.0 | |
2 | django-rosetta==0.7.8 | |
3 | microsofttranslator==0.7 | |
4 | polib==1.0.7 | |
5 | six==1.10.0 | |
0 | Django==2.1.* | |
1 | django-environ==0.4.5 | |
2 | django-rosetta==0.9.3 | |
3 | microsofttranslator==0.8 | |
4 | polib==1.1.0 |
0 | 0 | import os |
1 | 1 | import sys |
2 | from django.conf import global_settings | |
3 | 2 | import environ |
4 | 3 | |
5 | 4 | env = environ.Env() |
8 | 7 | |
9 | 8 | |
10 | 9 | DEBUG = True |
11 | TEMPLATE_DEBUG = DEBUG | |
12 | 10 | SECRET_KEY = 'CHANGE_THIS_TO_SOMETHING_UNIQUE_AND_SECURE' |
13 | 11 | |
14 | 12 | PROJECT_ROOT = abspath(os.path.dirname(__file__)) |
44 | 42 | except ImportError: |
45 | 43 | pass |
46 | 44 | |
47 | MIDDLEWARE_CLASSES = ( | |
45 | MIDDLEWARE = ( | |
48 | 46 | 'django.middleware.common.CommonMiddleware', |
49 | 47 | 'django.contrib.sessions.middleware.SessionMiddleware', |
50 | 48 | 'django.middleware.csrf.CsrfViewMiddleware', |
58 | 56 | GUARDIAN_RAISE_403 = True |
59 | 57 | |
60 | 58 | ROOT_URLCONF = 'urls' |
61 | ||
62 | TEMPLATE_CONTEXT_PROCESSORS = ( | |
63 | 'core.context_processors.version', | |
64 | "django.contrib.auth.context_processors.auth", | |
65 | "django.template.context_processors.debug", | |
66 | "django.template.context_processors.i18n", | |
67 | "django.template.context_processors.media", | |
68 | "django.template.context_processors.static", | |
69 | "django.template.context_processors.request", | |
70 | "django.template.context_processors.tz", | |
71 | "django.contrib.messages.context_processors.messages" | |
72 | ) | |
73 | TEMPLATE_LOADERS = ( | |
74 | 'django.template.loaders.filesystem.Loader', | |
75 | 'django.template.loaders.app_directories.Loader', | |
76 | ) | |
77 | ||
78 | TEMPLATE_DIRS = ( | |
79 | os.path.join(os.path.dirname(__file__), 'templates'), | |
80 | ) | |
81 | 59 | |
82 | 60 | SITE_ID = 1 |
83 | 61 | |
106 | 84 | TEMPLATES = [ |
107 | 85 | { |
108 | 86 | 'BACKEND': 'django.template.backends.django.DjangoTemplates', |
109 | 'DIRS': TEMPLATE_DIRS, | |
87 | 'DIRS': ( | |
88 | os.path.join(os.path.dirname(__file__), 'templates'), | |
89 | ), | |
110 | 90 | 'OPTIONS': { |
111 | 'debug': TEMPLATE_DEBUG, | |
112 | 'loaders': TEMPLATE_LOADERS, | |
113 | 'context_processors': TEMPLATE_CONTEXT_PROCESSORS, | |
91 | 'debug': DEBUG, | |
92 | 'loaders': ( | |
93 | 'django.template.loaders.filesystem.Loader', | |
94 | 'django.template.loaders.app_directories.Loader', | |
95 | ), | |
96 | 'context_processors': ( | |
97 | 'core.context_processors.version', | |
98 | 'django.contrib.auth.context_processors.auth', | |
99 | 'django.template.context_processors.debug', | |
100 | 'django.template.context_processors.i18n', | |
101 | 'django.template.context_processors.media', | |
102 | 'django.template.context_processors.static', | |
103 | 'django.template.context_processors.request', | |
104 | 'django.template.context_processors.tz', | |
105 | 'django.contrib.messages.context_processors.messages' | |
106 | ), | |
114 | 107 | }, |
115 | 108 | }, |
116 | 109 | ] |
0 | 0 | from guardian.compat import include, url, handler404, handler500 |
1 | 1 | from django.conf import settings |
2 | 2 | from django.contrib import admin |
3 | from django.contrib.auth.views import logout | |
3 | from django.contrib.auth.views import LogoutView | |
4 | 4 | |
5 | 5 | __all__ = ['handler404', 'handler500'] |
6 | 6 | |
9 | 9 | |
10 | 10 | urlpatterns = [ |
11 | 11 | url(r'^admin/', admin.site.urls), |
12 | url(r'^logout/$', logout, {'next_page': '/'}, name='logout'), | |
12 | url(r'^logout/$', LogoutView.as_view(next_page='/'), name='logout'), | |
13 | 13 | url(r'^article/', include('articles.urls', namespace='articles')), |
14 | 14 | url(r'^', include('posts.urls')), |
15 | 15 | ] |
0 | 0 | """ |
1 | 1 | Implementation of per object permissions for Django. |
2 | 2 | """ |
3 | from __future__ import unicode_literals | |
4 | 3 | from . import checks |
5 | 4 | |
6 | 5 | default_app_config = 'guardian.apps.GuardianConfig' |
7 | 6 | |
8 | 7 | # PEP 396: The __version__ attribute's value SHOULD be a string. |
9 | __version__ = '1.4.9' | |
8 | __version__ = '2.0.0' | |
10 | 9 | |
11 | 10 | # Compatibility to eg. django-rest-framework |
12 | 11 | VERSION = tuple(int(x) for x in __version__.split('.')[:3]) |
17 | 16 | |
18 | 17 | |
19 | 18 | def monkey_patch_user(): |
20 | from .compat import get_user_model | |
19 | from django.contrib.auth import get_user_model | |
21 | 20 | from .utils import get_anonymous_user |
22 | 21 | from .models import UserObjectPermission |
23 | 22 | User = get_user_model() |
0 | from __future__ import unicode_literals | |
1 | ||
2 | 0 | from collections import OrderedDict |
3 | 1 | |
4 | 2 | from django import forms |
5 | 3 | from django.conf import settings |
6 | 4 | from django.contrib import admin, messages |
7 | 5 | from django.contrib.admin.widgets import FilteredSelectMultiple |
8 | from django.shortcuts import get_object_or_404, redirect, render_to_response, render | |
9 | from django.template import RequestContext | |
6 | from django.contrib.auth import get_user_model | |
7 | from django.shortcuts import get_object_or_404, redirect, render | |
8 | from django.urls import reverse | |
10 | 9 | from django.utils.translation import ugettext_lazy as _ |
11 | 10 | from django.utils.translation import ugettext |
12 | from guardian.compat import get_model_name, get_user_model, url, reverse | |
11 | from guardian.compat import url | |
13 | 12 | from guardian.forms import GroupObjectPermissionsForm, UserObjectPermissionsForm |
14 | 13 | from guardian.models import Group |
15 | 14 | from guardian.shortcuts import (get_group_perms, get_groups_with_perms, get_perms_for_model, get_user_perms, |
16 | 15 | get_users_with_perms) |
17 | 16 | |
18 | import django | |
19 | ||
20 | 17 | |
21 | 18 | class AdminUserObjectPermissionsForm(UserObjectPermissionsForm): |
22 | 19 | """ |
40 | 37 | return FilteredSelectMultiple(_("Permissions"), False) |
41 | 38 | |
42 | 39 | |
43 | class GuardedModelAdminMixin(object): | |
40 | class GuardedModelAdminMixin: | |
44 | 41 | """ |
45 | 42 | Serves as a helper for custom subclassing ``admin.ModelAdmin``. |
46 | 43 | """ |
59 | 56 | include_object_permissions_urls = True |
60 | 57 | |
61 | 58 | def get_queryset(self, request): |
62 | # Prefer the Django >= 1.6 interface but maintain | |
63 | # backward compatibility | |
64 | method = getattr( | |
65 | super(GuardedModelAdminMixin, self), 'get_queryset', | |
66 | getattr(super(GuardedModelAdminMixin, self), 'queryset', None)) | |
67 | qs = method(request) | |
59 | qs = super().get_queryset(request) | |
68 | 60 | |
69 | 61 | if request.user.is_superuser: |
70 | 62 | return qs |
93 | 85 | ``/admin/flatpages/1/``) |
94 | 86 | |
95 | 87 | """ |
96 | urls = super(GuardedModelAdminMixin, self).get_urls() | |
88 | urls = super().get_urls() | |
97 | 89 | if self.include_object_permissions_urls: |
98 | info = self.model._meta.app_label, get_model_name(self.model) | |
90 | info = self.model._meta.app_label, self.model._meta.model_name | |
99 | 91 | myurls = [ |
100 | 92 | url(r'^(?P<object_pk>.+)/permissions/$', |
101 | 93 | view=self.admin_site.admin_view( |
116 | 108 | def get_obj_perms_base_context(self, request, obj): |
117 | 109 | """ |
118 | 110 | Returns context dictionary with common admin and object permissions |
119 | related content. It uses AdminSite.each_context (available in Django >= 1.8, | |
111 | related content. It uses AdminSite.each_context, | |
120 | 112 | making sure all required template vars are in the context. |
121 | 113 | """ |
122 | if django.VERSION >= (1, 8): | |
123 | context = self.admin_site.each_context(request) | |
124 | else: | |
125 | context = {} | |
126 | context.update( { | |
114 | context = self.admin_site.each_context(request) | |
115 | context.update({ | |
127 | 116 | 'adminform': {'model_admin': self}, |
128 | 117 | 'media': self.media, |
129 | 118 | 'object': obj, |
130 | 119 | 'app_label': self.model._meta.app_label, |
131 | 120 | 'opts': self.model._meta, |
132 | 'original': hasattr(obj, '__unicode__') and obj.__unicode__() or str(obj), | |
121 | 'original': str(obj), | |
133 | 122 | 'has_change_permission': self.has_change_permission(request, obj), |
134 | 123 | 'model_perms': get_perms_for_model(obj), |
135 | 124 | 'title': _("Object permissions"), |
148 | 137 | post_url = reverse('admin:index', current_app=self.admin_site.name) |
149 | 138 | return redirect(post_url) |
150 | 139 | |
151 | try: | |
152 | # django >= 1.7 | |
153 | from django.contrib.admin.utils import unquote | |
154 | except ImportError: | |
155 | # django < 1.7 | |
156 | from django.contrib.admin.util import unquote | |
140 | from django.contrib.admin.utils import unquote | |
157 | 141 | obj = get_object_or_404(self.get_queryset( |
158 | 142 | request), pk=unquote(object_pk)) |
159 | 143 | users_perms = OrderedDict( |
178 | 162 | info = ( |
179 | 163 | self.admin_site.name, |
180 | 164 | self.model._meta.app_label, |
181 | get_model_name(self.model) | |
165 | self.model._meta.model_name, | |
182 | 166 | ) |
183 | 167 | if user_form.is_valid(): |
184 | 168 | user_id = user_form.cleaned_data['user'].pk |
193 | 177 | info = ( |
194 | 178 | self.admin_site.name, |
195 | 179 | self.model._meta.app_label, |
196 | get_model_name(self.model) | |
180 | self.model._meta.model_name, | |
197 | 181 | ) |
198 | 182 | if group_form.is_valid(): |
199 | 183 | group_id = group_form.cleaned_data['group'].id |
215 | 199 | # https://github.com/django/django/commit/cf1f36bb6eb34fafe6c224003ad585a647f6117b |
216 | 200 | request.current_app = self.admin_site.name |
217 | 201 | |
218 | if django.VERSION >= (1, 10): | |
219 | return render(request, self.get_obj_perms_manage_template(), context) | |
220 | ||
221 | return render_to_response(self.get_obj_perms_manage_template(), context, RequestContext(request)) | |
202 | return render(request, self.get_obj_perms_manage_template(), context) | |
222 | 203 | |
223 | 204 | def get_obj_perms_manage_template(self): |
224 | 205 | """ |
254 | 235 | info = ( |
255 | 236 | self.admin_site.name, |
256 | 237 | self.model._meta.app_label, |
257 | get_model_name(self.model) | |
238 | self.model._meta.model_name, | |
258 | 239 | ) |
259 | 240 | url = reverse( |
260 | 241 | '%s:%s_%s_permissions_manage_user' % info, |
269 | 250 | |
270 | 251 | request.current_app = self.admin_site.name |
271 | 252 | |
272 | if django.VERSION >= (1, 10): | |
273 | return render(request, self.get_obj_perms_manage_user_template(), context) | |
274 | ||
275 | return render_to_response(self.get_obj_perms_manage_user_template(), context, RequestContext(request)) | |
253 | return render(request, self.get_obj_perms_manage_user_template(), context) | |
276 | 254 | |
277 | 255 | def get_obj_perms_manage_user_template(self): |
278 | 256 | """ |
330 | 308 | info = ( |
331 | 309 | self.admin_site.name, |
332 | 310 | self.model._meta.app_label, |
333 | get_model_name(self.model) | |
311 | self.model._meta.model_name, | |
334 | 312 | ) |
335 | 313 | url = reverse( |
336 | 314 | '%s:%s_%s_permissions_manage_group' % info, |
345 | 323 | |
346 | 324 | request.current_app = self.admin_site.name |
347 | 325 | |
348 | if django.VERSION >= (1, 10): | |
349 | return render(request, self.get_obj_perms_manage_group_template(), context) | |
350 | ||
351 | return render_to_response(self.get_obj_perms_manage_group_template(), context, RequestContext(request)) | |
326 | return render(request, self.get_obj_perms_manage_group_template(), context) | |
352 | 327 | |
353 | 328 | def get_obj_perms_manage_group_template(self): |
354 | 329 | """ |
0 | from __future__ import unicode_literals | |
0 | from django.contrib.auth import get_user_model | |
1 | 1 | from django.db import models |
2 | from guardian.compat import get_user_model, is_authenticated | |
3 | 2 | from guardian.conf import settings |
4 | 3 | from guardian.core import ObjectPermissionChecker |
5 | 4 | from guardian.ctypes import get_content_type |
26 | 25 | """ |
27 | 26 | # This is how we support anonymous users - simply try to retrieve User |
28 | 27 | # instance and perform checks for that predefined user |
29 | if not is_authenticated(user_obj): | |
28 | if not user_obj.is_authenticated: | |
30 | 29 | # If anonymous user permission is disabled then they are always |
31 | 30 | # unauthorized |
32 | 31 | if settings.ANONYMOUS_USER_NAME is None: |
47 | 46 | return obj_support and user_support, user_obj |
48 | 47 | |
49 | 48 | |
50 | class ObjectPermissionBackend(object): | |
49 | class ObjectPermissionBackend: | |
51 | 50 | supports_object_permissions = True |
52 | 51 | supports_anonymous_user = True |
53 | 52 | supports_inactive_user = True |
54 | 53 | |
55 | def authenticate(self, username, password): | |
54 | def authenticate(self, request, username, password): | |
56 | 55 | return None |
57 | 56 | |
58 | 57 | def has_perm(self, user_obj, perm, obj=None): |
81 | 80 | return False |
82 | 81 | |
83 | 82 | if '.' in perm: |
84 | app_label, perm = perm.split('.') | |
83 | app_label, _ = perm.split('.', 1) | |
85 | 84 | if app_label != obj._meta.app_label: |
86 | 85 | # Check the content_type app_label when permission |
87 | 86 | # and obj app labels don't match. |
0 | from __future__ import unicode_literals | |
1 | ||
2 | 0 | from django.conf import settings |
3 | 1 | from django.conf.urls import handler404, handler500, include, url |
2 | from django.contrib.auth import get_user_model | |
4 | 3 | from django.contrib.auth.models import AnonymousUser, Group, Permission |
5 | from importlib import import_module | |
6 | ||
7 | import django | |
8 | import six | |
9 | import sys | |
10 | 4 | |
11 | 5 | __all__ = [ |
12 | 'User', | |
13 | 6 | 'Group', |
14 | 7 | 'Permission', |
15 | 8 | 'AnonymousUser', |
16 | 9 | 'get_user_model', |
17 | 'import_string', | |
18 | 10 | 'user_model_label', |
19 | 11 | 'url', |
20 | 'patterns', | |
21 | 12 | 'include', |
22 | 13 | 'handler404', |
23 | 14 | 'handler500', |
24 | 15 | ] |
25 | 16 | |
26 | # Django 1.5 compatibility utilities, providing support for custom User models. | |
27 | 17 | # Since get_user_model() causes a circular import if called when app models are |
28 | 18 | # being loaded, the user_model_label should be used when possible, with calls |
29 | 19 | # to get_user_model deferred to execution time |
30 | 20 | |
31 | 21 | user_model_label = getattr(settings, 'AUTH_USER_MODEL', 'auth.User') |
32 | ||
33 | try: | |
34 | from django.contrib.auth import get_user_model | |
35 | except ImportError: | |
36 | from django.contrib.auth.models import User | |
37 | get_user_model = lambda: User | |
38 | 22 | |
39 | 23 | |
40 | 24 | def get_user_model_path(): |
64 | 48 | ``myapp.CustomUser`` is used it would return ``change_customuser``. |
65 | 49 | """ |
66 | 50 | return get_user_permission_full_codename(perm).split('.')[1] |
67 | ||
68 | ||
69 | def import_string(dotted_path): | |
70 | """ | |
71 | Import a dotted module path and return the attribute/class designated by the | |
72 | last name in the path. Raise ImportError if the import failed. | |
73 | ||
74 | Backported from Django 1.7 | |
75 | """ | |
76 | try: | |
77 | module_path, class_name = dotted_path.rsplit('.', 1) | |
78 | except ValueError: | |
79 | msg = "%s doesn't look like a module path" % dotted_path | |
80 | six.reraise(ImportError, ImportError(msg), sys.exc_info()[2]) | |
81 | ||
82 | module = import_module(module_path) | |
83 | ||
84 | try: | |
85 | return getattr(module, class_name) | |
86 | except AttributeError: | |
87 | msg = 'Module "%s" does not define a "%s" attribute/class' % ( | |
88 | dotted_path, class_name) | |
89 | six.reraise(ImportError, ImportError(msg), sys.exc_info()[2]) | |
90 | ||
91 | ||
92 | # Python 3 | |
93 | try: | |
94 | unicode = unicode # pyflakes:ignore | |
95 | basestring = basestring # pyflakes:ignore | |
96 | str = str # pyflakes:ignore | |
97 | except NameError: | |
98 | basestring = unicode = str = str | |
99 | ||
100 | ||
101 | # Django 1.7 compatibility | |
102 | # create_permission API changed: skip the create_models (second | |
103 | # positional argument) if we have django 1.7+ and 2+ positional | |
104 | # arguments with the second one being a list/tuple | |
105 | def create_permissions(*args, **kwargs): | |
106 | from django.contrib.auth.management import create_permissions as original_create_permissions | |
107 | ||
108 | if len(args) > 1 and isinstance(args[1], (list, tuple)): | |
109 | args = args[:1] + args[2:] | |
110 | return original_create_permissions(*args, **kwargs) | |
111 | ||
112 | __all__ = ['User', 'Group', 'Permission', 'AnonymousUser'] | |
113 | ||
114 | ||
115 | def get_model_name(model): | |
116 | """ | |
117 | Returns the name of the model | |
118 | """ | |
119 | # model._meta.module_name is deprecated in django version 1.7 and removed | |
120 | # in django version 1.8. It is replaced by model._meta.model_name | |
121 | return model._meta.model_name | |
122 | ||
123 | ||
124 | def template_debug_setter(value): | |
125 | if hasattr(settings, 'TEMPLATE_DEBUG'): | |
126 | settings.TEMPLATE_DEBUG = value | |
127 | settings.TEMPLATES[0]['OPTIONS']['DEBUG'] = value | |
128 | ||
129 | ||
130 | def template_debug_getter(): | |
131 | if hasattr(settings, 'TEMPLATE_DEBUG'): | |
132 | return settings.TEMPLATE_DEBUG | |
133 | return settings.TEMPLATES[0]['OPTIONS'].get('DEBUG', False) | |
134 | ||
135 | ||
136 | # Django 1.9 compatibility | |
137 | def remote_field(field): | |
138 | """ | |
139 | https://docs.djangoproject.com/en/1.9/releases/1.9/#field-rel-changes | |
140 | """ | |
141 | if django.VERSION < (1, 9): | |
142 | return field.rel | |
143 | return field.remote_field | |
144 | ||
145 | ||
146 | def remote_model(field): | |
147 | if django.VERSION < (1, 9): | |
148 | return remote_field(field).to | |
149 | return remote_field(field).model | |
150 | ||
151 | ||
152 | # Django 1.10 compatibility | |
153 | def is_authenticated(user): | |
154 | if django.VERSION < (1, 10): | |
155 | return user.is_authenticated() | |
156 | return user.is_authenticated | |
157 | ||
158 | ||
159 | def is_anonymous(user): | |
160 | if django.VERSION < (1, 10): | |
161 | return user.is_anonymous() | |
162 | return user.is_anonymous | |
163 | ||
164 | try: | |
165 | from django.urls import reverse, reverse_lazy | |
166 | except ImportError: | |
167 | from django.core.urlresolvers import reverse, reverse_lazy |
0 | from __future__ import unicode_literals |
0 | from __future__ import unicode_literals | |
1 | 0 | import warnings |
2 | 1 | from django.conf import settings |
3 | 2 | from django.core.exceptions import ImproperlyConfigured |
0 | from __future__ import unicode_literals | |
0 | from itertools import chain | |
1 | ||
2 | from django.contrib.auth import get_user_model | |
1 | 3 | from django.contrib.auth.models import Permission |
2 | 4 | from django.db.models.query import QuerySet |
3 | 5 | from django.utils.encoding import force_text |
4 | from guardian.compat import get_user_model | |
5 | 6 | from guardian.ctypes import get_content_type |
6 | 7 | from guardian.utils import get_group_obj_perms_model, get_identity, get_user_obj_perms_model |
7 | from itertools import chain | |
8 | 8 | |
9 | 9 | |
10 | 10 | def _get_pks_model_and_ctype(objects): |
28 | 28 | return pks, model, ctype |
29 | 29 | |
30 | 30 | |
31 | class ObjectPermissionChecker(object): | |
31 | class ObjectPermissionChecker: | |
32 | 32 | """ |
33 | 33 | Generic object permissions checker class being the heart of |
34 | 34 | ``django-guardian``. |
70 | 70 | return False |
71 | 71 | elif self.user and self.user.is_superuser: |
72 | 72 | return True |
73 | perm = perm.split('.')[-1] | |
73 | if '.' in perm: | |
74 | _, perm = perm.split('.', 1) | |
74 | 75 | return perm in self.get_perms(obj) |
75 | 76 | |
76 | 77 | def get_group_filters(self, obj): |
156 | 157 | group_perms = self.get_group_perms(obj) |
157 | 158 | perms = list(set(chain(user_perms, group_perms))) |
158 | 159 | else: |
159 | group_filters = self.get_group_filters(obj) | |
160 | perms = list(set(chain(*Permission.objects | |
161 | .filter(content_type=ctype) | |
162 | .filter(**group_filters) | |
163 | .values_list("codename")))) | |
160 | perms = list(set(self.get_group_perms(obj))) | |
164 | 161 | self._obj_perms_cache[key] = perms |
165 | 162 | return self._obj_perms_cache[key] |
166 | 163 |
0 | from __future__ import unicode_literals | |
1 | ||
2 | 0 | from django.contrib.contenttypes.models import ContentType |
1 | from django.utils.module_loading import import_string | |
3 | 2 | |
4 | 3 | from guardian.conf import settings as guardian_settings |
5 | from guardian.compat import import_string | |
6 | 4 | |
7 | 5 | |
8 | 6 | def get_content_type(obj): |
0 | from __future__ import unicode_literals | |
1 | 0 | from django.apps import apps |
2 | 1 | from django.conf import settings |
3 | 2 | from django.contrib.auth import REDIRECT_FIELD_NAME |
6 | 5 | from django.db.models.query import QuerySet |
7 | 6 | from django.shortcuts import get_object_or_404 |
8 | 7 | from django.utils.functional import wraps |
9 | from guardian.compat import basestring | |
10 | 8 | from guardian.exceptions import GuardianError |
11 | 9 | from guardian.utils import get_40x_or_None |
12 | 10 | |
81 | 79 | |
82 | 80 | # Check if perm is given as string in order not to decorate |
83 | 81 | # view function itself which makes debugging harder |
84 | if not isinstance(perm, basestring): | |
82 | if not isinstance(perm, str): | |
85 | 83 | raise GuardianError("First argument must be in format: " |
86 | 84 | "'app_label.codename or a callable which return similar string'") |
87 | 85 | |
93 | 91 | if lookup_variables: |
94 | 92 | model, lookups = lookup_variables[0], lookup_variables[1:] |
95 | 93 | # Parse model |
96 | if isinstance(model, basestring): | |
94 | if isinstance(model, str): | |
97 | 95 | splitted = model.split('.') |
98 | 96 | if len(splitted) != 2: |
99 | 97 | raise GuardianError("If model should be looked up from " |
1 | 1 | Exceptions used by django-guardian. All internal and guardian-specific errors |
2 | 2 | should extend GuardianError class. |
3 | 3 | """ |
4 | from __future__ import unicode_literals | |
5 | 4 | |
6 | 5 | |
7 | 6 | class GuardianError(Exception): |
22 | 21 | |
23 | 22 | class MixedContentTypeError(GuardianError): |
24 | 23 | pass |
24 | ||
25 | ||
26 | class MultipleIdentityAndObjectError(GuardianError): | |
27 | pass |
0 | from __future__ import unicode_literals | |
1 | 0 | from django import forms |
2 | 1 | from django.utils.translation import ugettext as _ |
3 | 2 | from guardian.shortcuts import assign_perm, get_group_perms, get_perms_for_model, get_user_perms, remove_perm |
17 | 16 | permissions" |
18 | 17 | """ |
19 | 18 | self.obj = obj |
20 | super(BaseObjectPermissionsForm, self).__init__(*args, **kwargs) | |
19 | super().__init__(*args, **kwargs) | |
21 | 20 | field_name = self.get_obj_perms_field_name() |
22 | 21 | self.fields[field_name] = self.get_obj_perms_field() |
23 | 22 | |
118 | 117 | |
119 | 118 | def __init__(self, user, *args, **kwargs): |
120 | 119 | self.user = user |
121 | super(UserObjectPermissionsForm, self).__init__(*args, **kwargs) | |
120 | super().__init__(*args, **kwargs) | |
122 | 121 | |
123 | 122 | def get_obj_perms_field_initial(self): |
124 | 123 | perms = get_user_perms(self.user, self.obj) |
131 | 130 | |
132 | 131 | Should be called *after* form is validated. |
133 | 132 | """ |
134 | perms = self.cleaned_data[self.get_obj_perms_field_name()] | |
135 | model_perms = [c[0] for c in self.get_obj_perms_field_choices()] | |
133 | perms = set(self.cleaned_data[self.get_obj_perms_field_name()]) | |
134 | model_perms = set([c[0] for c in self.get_obj_perms_field_choices()]) | |
135 | init_perms = set(self.get_obj_perms_field_initial()) | |
136 | 136 | |
137 | to_remove = set(model_perms) - set(perms) | |
137 | to_remove = (model_perms - perms) & init_perms | |
138 | 138 | for perm in to_remove: |
139 | 139 | remove_perm(perm, self.user, self.obj) |
140 | 140 | |
141 | for perm in perms: | |
141 | for perm in perms - init_perms: | |
142 | 142 | assign_perm(perm, self.user, self.obj) |
143 | 143 | |
144 | 144 | |
165 | 165 | |
166 | 166 | def __init__(self, group, *args, **kwargs): |
167 | 167 | self.group = group |
168 | super(GroupObjectPermissionsForm, self).__init__(*args, **kwargs) | |
168 | super().__init__(*args, **kwargs) | |
169 | 169 | |
170 | 170 | def get_obj_perms_field_initial(self): |
171 | 171 | perms = get_group_perms(self.group, self.obj) |
178 | 178 | |
179 | 179 | Should be called *after* form is validated. |
180 | 180 | """ |
181 | perms = self.cleaned_data[self.get_obj_perms_field_name()] | |
182 | model_perms = [c[0] for c in self.get_obj_perms_field_choices()] | |
181 | perms = set(self.cleaned_data[self.get_obj_perms_field_name()]) | |
182 | model_perms = set([c[0] for c in self.get_obj_perms_field_choices()]) | |
183 | init_perms = set(self.get_obj_perms_field_initial()) | |
183 | 184 | |
184 | to_remove = set(model_perms) - set(perms) | |
185 | to_remove = (model_perms - perms) & init_perms | |
185 | 186 | for perm in to_remove: |
186 | 187 | remove_perm(perm, self.group, self.obj) |
187 | 188 | |
188 | for perm in perms: | |
189 | for perm in perms - init_perms: | |
189 | 190 | assign_perm(perm, self.group, self.obj) |
Binary diff not shown
0 | # Dutch translation of django-guardian | |
1 | # This file is distributed under the same license as the PACKAGE package. | |
2 | # Translator: Melvyn Sopacua <melvyn@pluggable.nl>, 2017. | |
3 | # | |
4 | msgid "" | |
5 | msgstr "" | |
6 | "Project-Id-Version: 1.4.9\n" | |
7 | "Report-Msgid-Bugs-To: \n" | |
8 | "POT-Creation-Date: 2017-10-16 07:58+0200\n" | |
9 | "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" | |
10 | "Last-Translator: Melvyn Sopacua <melvyn@pluggable.nl>\n" | |
11 | "Language: nl\n" | |
12 | "MIME-Version: 1.0\n" | |
13 | "Content-Type: text/plain; charset=UTF-8\n" | |
14 | "Content-Transfer-Encoding: 8bit\n" | |
15 | "Plural-Forms: nplurals=2; plural=(n != 1);\n" | |
16 | ||
17 | #: admin.py:30 admin.py:41 forms.py:52 | |
18 | msgid "Permissions" | |
19 | msgstr "Permissies" | |
20 | ||
21 | #: admin.py:136 | |
22 | #: templates/admin/guardian/contrib/grappelli/obj_perms_manage.html:24 | |
23 | #: templates/admin/guardian/contrib/grappelli/obj_perms_manage_group.html:24 | |
24 | #: templates/admin/guardian/contrib/grappelli/obj_perms_manage_group.html:29 | |
25 | #: templates/admin/guardian/contrib/grappelli/obj_perms_manage_group.html:40 | |
26 | #: templates/admin/guardian/contrib/grappelli/obj_perms_manage_user.html:24 | |
27 | #: templates/admin/guardian/contrib/grappelli/obj_perms_manage_user.html:29 | |
28 | #: templates/admin/guardian/contrib/grappelli/obj_perms_manage_user.html:40 | |
29 | #: templates/admin/guardian/model/change_form.html:6 | |
30 | #: templates/admin/guardian/model/obj_perms_manage.html:16 | |
31 | #: templates/admin/guardian/model/obj_perms_manage_group.html:14 | |
32 | #: templates/admin/guardian/model/obj_perms_manage_group.html:25 | |
33 | #: templates/admin/guardian/model/obj_perms_manage_user.html:14 | |
34 | #: templates/admin/guardian/model/obj_perms_manage_user.html:25 | |
35 | msgid "Object permissions" | |
36 | msgstr "Object permissies" | |
37 | ||
38 | #: admin.py:253 admin.py:329 | |
39 | msgid "Permissions saved." | |
40 | msgstr "Permissies zijn opgeslagen." | |
41 | ||
42 | #: admin.py:457 | |
43 | msgid "User identification" | |
44 | msgstr "Gebruikersindentificatie" | |
45 | ||
46 | #: admin.py:460 | |
47 | msgid "This user does not exist" | |
48 | msgstr "Deze gebruiker bestaat niet" | |
49 | ||
50 | #: admin.py:462 | |
51 | msgid "Enter a value compatible with User.USERNAME_FIELD" | |
52 | msgstr "Voer een waarde in die compatible is met User.USERNAME_FIELD" | |
53 | ||
54 | #: admin.py:485 | |
55 | msgid "This group does not exist" | |
56 | msgstr "Deze groep bestaat niet" | |
57 | ||
58 | #: models.py:46 | |
59 | msgid "object ID" | |
60 | msgstr "object ID" | |
61 | ||
62 | #: templates/admin/guardian/contrib/grappelli/obj_perms_manage.html:9 | |
63 | #: templates/admin/guardian/contrib/grappelli/obj_perms_manage_group.html:11 | |
64 | #: templates/admin/guardian/contrib/grappelli/obj_perms_manage_user.html:11 | |
65 | #: templates/admin/guardian/model/obj_perms_manage.html:12 | |
66 | #: templates/admin/guardian/model/obj_perms_manage_group.html:10 | |
67 | #: templates/admin/guardian/model/obj_perms_manage_user.html:10 | |
68 | msgid "Home" | |
69 | msgstr "Home" | |
70 | ||
71 | #: templates/admin/guardian/contrib/grappelli/obj_perms_manage.html:33 | |
72 | #: templates/admin/guardian/contrib/grappelli/obj_perms_manage.html:94 | |
73 | msgid "Please correct the error below." | |
74 | msgid_plural "Please correct the errors below." | |
75 | msgstr[0] "Corrigeer de fout hieronder." | |
76 | msgstr[1] "Corrigeer de fouten hieronder." | |
77 | ||
78 | #: templates/admin/guardian/contrib/grappelli/obj_perms_manage.html:37 | |
79 | #: templates/admin/guardian/model/obj_perms_manage.html:31 | |
80 | msgid "Users" | |
81 | msgstr "Gebruikers" | |
82 | ||
83 | #: templates/admin/guardian/contrib/grappelli/obj_perms_manage.html:40 | |
84 | #: templates/admin/guardian/model/obj_perms_manage.html:37 | |
85 | msgid "User permissions" | |
86 | msgstr "Gebruiker's permissies" | |
87 | ||
88 | #: templates/admin/guardian/contrib/grappelli/obj_perms_manage.html:45 | |
89 | #: templates/admin/guardian/contrib/grappelli/obj_perms_manage_user.html:49 | |
90 | #: templates/admin/guardian/model/obj_perms_manage.html:40 | |
91 | #: templates/admin/guardian/model/obj_perms_manage_user.html:30 | |
92 | msgid "User" | |
93 | msgstr "Gebruiker" | |
94 | ||
95 | #: templates/admin/guardian/contrib/grappelli/obj_perms_manage.html:49 | |
96 | #: templates/admin/guardian/contrib/grappelli/obj_perms_manage.html:110 | |
97 | #: templates/admin/guardian/model/obj_perms_manage.html:44 | |
98 | #: templates/admin/guardian/model/obj_perms_manage.html:98 | |
99 | msgid "Action" | |
100 | msgstr "Actie" | |
101 | ||
102 | #: templates/admin/guardian/contrib/grappelli/obj_perms_manage.html:66 | |
103 | #: templates/admin/guardian/contrib/grappelli/obj_perms_manage.html:127 | |
104 | #: templates/admin/guardian/model/obj_perms_manage.html:61 | |
105 | #: templates/admin/guardian/model/obj_perms_manage.html:115 | |
106 | msgid "Edit" | |
107 | msgstr "Veranderen" | |
108 | ||
109 | #: templates/admin/guardian/contrib/grappelli/obj_perms_manage.html:82 | |
110 | #: templates/admin/guardian/contrib/grappelli/obj_perms_manage_user.html:31 | |
111 | #: templates/admin/guardian/model/obj_perms_manage.html:72 | |
112 | #: templates/admin/guardian/model/obj_perms_manage_user.html:15 | |
113 | msgid "Manage user" | |
114 | msgstr "Beheer de gebruiker" | |
115 | ||
116 | #: templates/admin/guardian/contrib/grappelli/obj_perms_manage.html:98 | |
117 | #: templates/admin/guardian/model/obj_perms_manage.html:85 | |
118 | msgid "Groups" | |
119 | msgstr "Groepen" | |
120 | ||
121 | #: templates/admin/guardian/contrib/grappelli/obj_perms_manage.html:101 | |
122 | #: templates/admin/guardian/model/obj_perms_manage.html:91 | |
123 | msgid "Group permissions" | |
124 | msgstr "Groep permissies" | |
125 | ||
126 | #: templates/admin/guardian/contrib/grappelli/obj_perms_manage.html:106 | |
127 | #: templates/admin/guardian/contrib/grappelli/obj_perms_manage_group.html:49 | |
128 | #: templates/admin/guardian/model/obj_perms_manage.html:94 | |
129 | #: templates/admin/guardian/model/obj_perms_manage_group.html:30 | |
130 | msgid "Group" | |
131 | msgstr "Groep" | |
132 | ||
133 | #: templates/admin/guardian/contrib/grappelli/obj_perms_manage.html:144 | |
134 | #: templates/admin/guardian/contrib/grappelli/obj_perms_manage_group.html:31 | |
135 | #: templates/admin/guardian/model/obj_perms_manage.html:126 | |
136 | #: templates/admin/guardian/model/obj_perms_manage_group.html:15 | |
137 | msgid "Manage group" | |
138 | msgstr "Beheer de groep" | |
139 | ||
140 | #: templates/admin/guardian/contrib/grappelli/obj_perms_manage_group.html:43 | |
141 | #: templates/admin/guardian/contrib/grappelli/obj_perms_manage_user.html:43 | |
142 | #: templates/admin/guardian/model/obj_perms_manage_group.html:27 | |
143 | #: templates/admin/guardian/model/obj_perms_manage_user.html:27 | |
144 | msgid "Object" | |
145 | msgstr "Object" | |
146 | ||
147 | #: templates/admin/guardian/contrib/grappelli/obj_perms_manage_group.html:60 | |
148 | #: templates/admin/guardian/contrib/grappelli/obj_perms_manage_user.html:60 | |
149 | #: templates/admin/guardian/model/obj_perms_manage_group.html:37 | |
150 | #: templates/admin/guardian/model/obj_perms_manage_user.html:37 | |
151 | msgid "Save" | |
152 | msgstr "Opslaan" | |
153 | ||
154 | #: templates/admin/guardian/model/obj_perms_manage.html:27 | |
155 | #: templates/admin/guardian/model/obj_perms_manage.html:81 | |
156 | msgid "Please correct the errors below." | |
157 | msgstr "Corrigeer de fout hieronder." |
Binary diff not shown
0 | # SOME DESCRIPTIVE TITLE. | |
1 | # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER | |
2 | # This file is distributed under the same license as the PACKAGE package. | |
3 | # FIRST AUTHOR <EMAIL@ADDRESS>, YEAR. | |
4 | # | |
5 | #, fuzzy | |
6 | msgid "" | |
7 | msgstr "" | |
8 | "Project-Id-Version: PACKAGE VERSION\n" | |
9 | "Report-Msgid-Bugs-To: \n" | |
10 | "POT-Creation-Date: 2018-07-27 10:10+0800\n" | |
11 | "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" | |
12 | "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" | |
13 | "Language-Team: LANGUAGE <LL@li.org>\n" | |
14 | "Language: \n" | |
15 | "MIME-Version: 1.0\n" | |
16 | "Content-Type: text/plain; charset=UTF-8\n" | |
17 | "Content-Transfer-Encoding: 8bit\n" | |
18 | "Plural-Forms: nplurals=1; plural=0;\n" | |
19 | ||
20 | #: guardian/admin.py:30 guardian/admin.py:41 guardian/forms.py:52 | |
21 | msgid "Permissions" | |
22 | msgstr "权限" | |
23 | ||
24 | #: guardian/admin.py:136 | |
25 | #: guardian/templates/admin/guardian/contrib/grappelli/obj_perms_manage.html:24 | |
26 | #: guardian/templates/admin/guardian/contrib/grappelli/obj_perms_manage_group.html:24 | |
27 | #: guardian/templates/admin/guardian/contrib/grappelli/obj_perms_manage_group.html:29 | |
28 | #: guardian/templates/admin/guardian/contrib/grappelli/obj_perms_manage_group.html:40 | |
29 | #: guardian/templates/admin/guardian/contrib/grappelli/obj_perms_manage_user.html:24 | |
30 | #: guardian/templates/admin/guardian/contrib/grappelli/obj_perms_manage_user.html:29 | |
31 | #: guardian/templates/admin/guardian/contrib/grappelli/obj_perms_manage_user.html:40 | |
32 | #: guardian/templates/admin/guardian/model/change_form.html:6 | |
33 | #: guardian/templates/admin/guardian/model/obj_perms_manage.html:16 | |
34 | #: guardian/templates/admin/guardian/model/obj_perms_manage_group.html:14 | |
35 | #: guardian/templates/admin/guardian/model/obj_perms_manage_group.html:25 | |
36 | #: guardian/templates/admin/guardian/model/obj_perms_manage_user.html:14 | |
37 | #: guardian/templates/admin/guardian/model/obj_perms_manage_user.html:25 | |
38 | msgid "Object permissions" | |
39 | msgstr "对象权限" | |
40 | ||
41 | #: guardian/admin.py:253 guardian/admin.py:329 | |
42 | msgid "Permissions saved." | |
43 | msgstr "权限已保存" | |
44 | ||
45 | #: guardian/admin.py:457 | |
46 | msgid "User identification" | |
47 | msgstr "用户 ID" | |
48 | ||
49 | #: guardian/admin.py:460 | |
50 | msgid "This user does not exist" | |
51 | msgstr "用户不存在" | |
52 | ||
53 | #: guardian/admin.py:462 | |
54 | msgid "Enter a value compatible with User.USERNAME_FIELD" | |
55 | msgstr "输入对应 User.USERNAME_FIELD 的值" | |
56 | ||
57 | #: guardian/admin.py:485 | |
58 | msgid "This group does not exist" | |
59 | msgstr "组不存在" | |
60 | ||
61 | #: guardian/models.py:46 | |
62 | msgid "object ID" | |
63 | msgstr "对象 ID" | |
64 | ||
65 | #: guardian/templates/admin/guardian/contrib/grappelli/obj_perms_manage.html:9 | |
66 | #: guardian/templates/admin/guardian/contrib/grappelli/obj_perms_manage_group.html:11 | |
67 | #: guardian/templates/admin/guardian/contrib/grappelli/obj_perms_manage_user.html:11 | |
68 | #: guardian/templates/admin/guardian/model/obj_perms_manage.html:12 | |
69 | #: guardian/templates/admin/guardian/model/obj_perms_manage_group.html:10 | |
70 | #: guardian/templates/admin/guardian/model/obj_perms_manage_user.html:10 | |
71 | msgid "Home" | |
72 | msgstr "首页" | |
73 | ||
74 | #: guardian/templates/admin/guardian/contrib/grappelli/obj_perms_manage.html:33 | |
75 | #: guardian/templates/admin/guardian/contrib/grappelli/obj_perms_manage.html:94 | |
76 | msgid "Please correct the error below." | |
77 | msgid_plural "Please correct the errors below." | |
78 | msgstr[0] "请修复下列错误" | |
79 | msgstr[1] "请修复下列错误" | |
80 | ||
81 | #: guardian/templates/admin/guardian/contrib/grappelli/obj_perms_manage.html:37 | |
82 | #: guardian/templates/admin/guardian/model/obj_perms_manage.html:31 | |
83 | msgid "Users" | |
84 | msgstr "用户" | |
85 | ||
86 | #: guardian/templates/admin/guardian/contrib/grappelli/obj_perms_manage.html:40 | |
87 | #: guardian/templates/admin/guardian/model/obj_perms_manage.html:37 | |
88 | msgid "User permissions" | |
89 | msgstr "用户权限" | |
90 | ||
91 | #: guardian/templates/admin/guardian/contrib/grappelli/obj_perms_manage.html:45 | |
92 | #: guardian/templates/admin/guardian/contrib/grappelli/obj_perms_manage_user.html:49 | |
93 | #: guardian/templates/admin/guardian/model/obj_perms_manage.html:40 | |
94 | #: guardian/templates/admin/guardian/model/obj_perms_manage_user.html:30 | |
95 | msgid "User" | |
96 | msgstr "用户" | |
97 | ||
98 | #: guardian/templates/admin/guardian/contrib/grappelli/obj_perms_manage.html:49 | |
99 | #: guardian/templates/admin/guardian/contrib/grappelli/obj_perms_manage.html:110 | |
100 | #: guardian/templates/admin/guardian/model/obj_perms_manage.html:44 | |
101 | #: guardian/templates/admin/guardian/model/obj_perms_manage.html:98 | |
102 | msgid "Action" | |
103 | msgstr "行为" | |
104 | ||
105 | #: guardian/templates/admin/guardian/contrib/grappelli/obj_perms_manage.html:66 | |
106 | #: guardian/templates/admin/guardian/contrib/grappelli/obj_perms_manage.html:127 | |
107 | #: guardian/templates/admin/guardian/model/obj_perms_manage.html:61 | |
108 | #: guardian/templates/admin/guardian/model/obj_perms_manage.html:115 | |
109 | msgid "Edit" | |
110 | msgstr "编辑" | |
111 | ||
112 | #: guardian/templates/admin/guardian/contrib/grappelli/obj_perms_manage.html:82 | |
113 | #: guardian/templates/admin/guardian/contrib/grappelli/obj_perms_manage_user.html:31 | |
114 | #: guardian/templates/admin/guardian/model/obj_perms_manage.html:72 | |
115 | #: guardian/templates/admin/guardian/model/obj_perms_manage_user.html:15 | |
116 | msgid "Manage user" | |
117 | msgstr "管理用户" | |
118 | ||
119 | #: guardian/templates/admin/guardian/contrib/grappelli/obj_perms_manage.html:98 | |
120 | #: guardian/templates/admin/guardian/model/obj_perms_manage.html:85 | |
121 | msgid "Groups" | |
122 | msgstr "组" | |
123 | ||
124 | #: guardian/templates/admin/guardian/contrib/grappelli/obj_perms_manage.html:101 | |
125 | #: guardian/templates/admin/guardian/model/obj_perms_manage.html:91 | |
126 | msgid "Group permissions" | |
127 | msgstr "组权限" | |
128 | ||
129 | #: guardian/templates/admin/guardian/contrib/grappelli/obj_perms_manage.html:106 | |
130 | #: guardian/templates/admin/guardian/contrib/grappelli/obj_perms_manage_group.html:49 | |
131 | #: guardian/templates/admin/guardian/model/obj_perms_manage.html:94 | |
132 | #: guardian/templates/admin/guardian/model/obj_perms_manage_group.html:30 | |
133 | msgid "Group" | |
134 | msgstr "组" | |
135 | ||
136 | #: guardian/templates/admin/guardian/contrib/grappelli/obj_perms_manage.html:144 | |
137 | #: guardian/templates/admin/guardian/contrib/grappelli/obj_perms_manage_group.html:31 | |
138 | #: guardian/templates/admin/guardian/model/obj_perms_manage.html:126 | |
139 | #: guardian/templates/admin/guardian/model/obj_perms_manage_group.html:15 | |
140 | msgid "Manage group" | |
141 | msgstr "管理组" | |
142 | ||
143 | #: guardian/templates/admin/guardian/contrib/grappelli/obj_perms_manage_group.html:43 | |
144 | #: guardian/templates/admin/guardian/contrib/grappelli/obj_perms_manage_user.html:43 | |
145 | #: guardian/templates/admin/guardian/model/obj_perms_manage_group.html:27 | |
146 | #: guardian/templates/admin/guardian/model/obj_perms_manage_user.html:27 | |
147 | msgid "Object" | |
148 | msgstr "对象" | |
149 | ||
150 | #: guardian/templates/admin/guardian/contrib/grappelli/obj_perms_manage_group.html:60 | |
151 | #: guardian/templates/admin/guardian/contrib/grappelli/obj_perms_manage_user.html:60 | |
152 | #: guardian/templates/admin/guardian/model/obj_perms_manage_group.html:37 | |
153 | #: guardian/templates/admin/guardian/model/obj_perms_manage_user.html:37 | |
154 | msgid "Save" | |
155 | msgstr "保存" | |
156 | ||
157 | #: guardian/templates/admin/guardian/model/obj_perms_manage.html:27 | |
158 | #: guardian/templates/admin/guardian/model/obj_perms_manage.html:81 | |
159 | msgid "Please correct the errors below." | |
160 | msgstr "请修复下列错误" |
0 | from __future__ import unicode_literals | |
1 | ||
2 | 0 | import django |
1 | from django.contrib.auth import get_user_model | |
3 | 2 | from django.db.models import signals |
3 | from django.utils.module_loading import import_string | |
4 | 4 | |
5 | 5 | from guardian.conf import settings as guardian_settings |
6 | from guardian.compat import get_user_model | |
7 | from guardian.compat import import_string | |
8 | 6 | |
9 | 7 | |
10 | 8 | def get_init_anonymous_user(User): |
38 | 36 | |
39 | 37 | # Only create an anonymous user if support is enabled. |
40 | 38 | if guardian_settings.ANONYMOUS_USER_NAME is not None: |
41 | # Django 1.7+ uses post_migrate signal | |
42 | 39 | from django.apps import apps |
43 | 40 | guardian_app = apps.get_app_config('guardian') |
44 | 41 | signals.post_migrate.connect(create_anonymous_user, sender=guardian_app, |
0 | from __future__ import unicode_literals |
0 | from __future__ import unicode_literals | |
1 | 0 | from django.core.management.base import BaseCommand |
2 | 1 | |
3 | 2 | from guardian.utils import clean_orphan_obj_perms |
0 | from __future__ import unicode_literals | |
1 | 0 | from django.db import models |
2 | 1 | from django.db.models import Q |
3 | 2 | from guardian.core import ObjectPermissionChecker |
77 | 76 | |
78 | 77 | return assigned_perms |
79 | 78 | |
79 | def assign_perm_to_many(self, perm, users_or_groups, obj): | |
80 | """ | |
81 | Bulk assigns given ``perm`` for the object ``obj`` to a set of users or a set of groups. | |
82 | """ | |
83 | ctype = get_content_type(obj) | |
84 | if not isinstance(perm, Permission): | |
85 | permission = Permission.objects.get(content_type=ctype, | |
86 | codename=perm) | |
87 | else: | |
88 | permission = perm | |
89 | ||
90 | kwargs = {'permission': permission} | |
91 | if self.is_generic(): | |
92 | kwargs['content_type'] = ctype | |
93 | kwargs['object_pk'] = obj.pk | |
94 | else: | |
95 | kwargs['content_object'] = obj | |
96 | ||
97 | to_add = [] | |
98 | field = self.user_or_group_field | |
99 | for user in users_or_groups: | |
100 | kwargs[field] = user | |
101 | to_add.append( | |
102 | self.model(**kwargs) | |
103 | ) | |
104 | ||
105 | return self.model.objects.bulk_create(to_add) | |
106 | ||
80 | 107 | def assign(self, perm, user_or_group, obj): |
81 | 108 | """ Depreciated function name left in for compatibility""" |
82 | 109 | warnings.warn("UserObjectPermissionManager method 'assign' is being renamed to 'assign_perm'. Update your code accordingly as old name will be depreciated in 2.0 version.", DeprecationWarning) |
126 | 153 | permission__content_type=ctype) |
127 | 154 | |
128 | 155 | if self.is_generic(): |
129 | filters &= Q(object_pk__in = [str(pk) for pk in queryset.values_list('pk', flat=True)]) | |
156 | filters &= Q(object_pk__in=[str(pk) for pk in queryset.values_list('pk', flat=True)]) | |
130 | 157 | else: |
131 | 158 | filters &= Q(content_object__in=queryset) |
132 | 159 |
0 | # -*- coding: utf-8 -*- | |
1 | from __future__ import unicode_literals | |
2 | ||
3 | 0 | from django.db import models, migrations |
4 | 1 | from django.conf import settings |
5 | 2 |
0 | from __future__ import unicode_literals | |
1 | from collections import Iterable | |
0 | from collections.abc import Iterable | |
1 | ||
2 | 2 | from django.conf import settings |
3 | 3 | from django.contrib.auth.decorators import login_required, REDIRECT_FIELD_NAME |
4 | 4 | from django.core.exceptions import ImproperlyConfigured, PermissionDenied |
5 | from guardian.compat import basestring | |
6 | 5 | from guardian.models import UserObjectPermission |
7 | 6 | from guardian.utils import get_40x_or_None, get_anonymous_user |
8 | 7 | from guardian.shortcuts import get_objects_for_user |
9 | 8 | |
10 | 9 | |
11 | class LoginRequiredMixin(object): | |
10 | class LoginRequiredMixin: | |
12 | 11 | """ |
13 | 12 | A login required mixin for use with class based views. This Class is a |
14 | 13 | light wrapper around the `login_required` decorator and hence function |
43 | 42 | def dispatch(self, request, *args, **kwargs): |
44 | 43 | return login_required(redirect_field_name=self.redirect_field_name, |
45 | 44 | login_url=self.login_url)( |
46 | super(LoginRequiredMixin, self).dispatch | |
45 | super().dispatch | |
47 | 46 | )(request, *args, **kwargs) |
48 | 47 | |
49 | 48 | |
50 | class PermissionRequiredMixin(object): | |
49 | class PermissionRequiredMixin: | |
51 | 50 | """ |
52 | 51 | A view mixin that verifies if the current logged in user has the specified |
53 | 52 | permission by wrapping the ``request.user.has_perm(..)`` method. |
143 | 142 | |
144 | 143 | :param request: Original request. |
145 | 144 | """ |
146 | if isinstance(self.permission_required, basestring): | |
145 | if isinstance(self.permission_required, str): | |
147 | 146 | perms = [self.permission_required] |
148 | 147 | elif isinstance(self.permission_required, Iterable): |
149 | 148 | perms = [p for p in self.permission_required] |
203 | 202 | response = self.check_permissions(request) |
204 | 203 | if response: |
205 | 204 | return response |
206 | return super(PermissionRequiredMixin, self).dispatch(request, *args, | |
207 | **kwargs) | |
208 | ||
209 | ||
210 | class GuardianUserMixin(object): | |
205 | return super().dispatch(request, *args, **kwargs) | |
206 | ||
207 | ||
208 | class GuardianUserMixin: | |
211 | 209 | |
212 | 210 | @staticmethod |
213 | 211 | def get_anonymous(): |
220 | 218 | return UserObjectPermission.objects.remove_perm(perm, self, obj) |
221 | 219 | |
222 | 220 | |
223 | class PermissionListMixin(object): | |
221 | class PermissionListMixin: | |
224 | 222 | """ |
225 | 223 | A view mixin that filter object in queryset for the current logged by required permission. |
226 | 224 | |
262 | 260 | |
263 | 261 | :param request: Original request. |
264 | 262 | """ |
265 | if isinstance(self.permission_required, basestring): | |
263 | if isinstance(self.permission_required, str): | |
266 | 264 | perms = [self.permission_required] |
267 | 265 | elif isinstance(self.permission_required, Iterable): |
268 | 266 | perms = [p for p in self.permission_required] |
285 | 283 | **self.get_objects_for_user_extra_kwargs) |
286 | 284 | |
287 | 285 | def get_queryset(self, *args, **kwargs): |
288 | qs = super(PermissionListMixin, self).get_queryset(*args, **kwargs) | |
286 | qs = super().get_queryset(*args, **kwargs) | |
289 | 287 | return get_objects_for_user(**self.get_get_objects_for_user_kwargs(qs)) |
0 | from __future__ import unicode_literals | |
1 | 0 | from django.contrib.auth.models import Group, Permission |
1 | from django.contrib.contenttypes.fields import GenericForeignKey | |
2 | 2 | from django.contrib.contenttypes.models import ContentType |
3 | 3 | from django.core.exceptions import ValidationError |
4 | 4 | from django.db import models |
5 | 5 | from django.utils.translation import ugettext_lazy as _ |
6 | from guardian.compat import unicode, user_model_label | |
6 | from guardian.compat import user_model_label | |
7 | 7 | from guardian.ctypes import get_content_type |
8 | 8 | from guardian.managers import GroupObjectPermissionManager, UserObjectPermissionManager |
9 | ||
10 | try: | |
11 | from django.contrib.contenttypes.fields import GenericForeignKey | |
12 | except ImportError: | |
13 | from django.contrib.contenttypes.generic import GenericForeignKey | |
14 | 9 | |
15 | 10 | |
16 | 11 | class BaseObjectPermission(models.Model): |
23 | 18 | class Meta: |
24 | 19 | abstract = True |
25 | 20 | |
26 | def __unicode__(self): | |
21 | def __str__(self): | |
27 | 22 | return '%s | %s | %s' % ( |
28 | unicode(self.content_object), | |
29 | unicode(getattr(self, 'user', False) or self.group), | |
30 | unicode(self.permission.codename)) | |
23 | str(self.content_object), | |
24 | str(getattr(self, 'user', False) or self.group), | |
25 | str(self.permission.codename)) | |
31 | 26 | |
32 | 27 | def save(self, *args, **kwargs): |
33 | 28 | content_type = get_content_type(self.content_object) |
35 | 30 | raise ValidationError("Cannot persist permission not designed for " |
36 | 31 | "this class (permission's type is %r and object's type is %r)" |
37 | 32 | % (self.permission.content_type, content_type)) |
38 | return super(BaseObjectPermission, self).save(*args, **kwargs) | |
33 | return super().save(*args, **kwargs) | |
39 | 34 | |
40 | 35 | |
41 | 36 | class BaseGenericObjectPermission(models.Model): |
0 | 0 | """ |
1 | 1 | Convenient shortcuts to manage or check object permissions. |
2 | 2 | """ |
3 | from __future__ import unicode_literals | |
4 | ||
5 | 3 | import warnings |
6 | 4 | from collections import defaultdict |
7 | 5 | from itertools import groupby |
8 | 6 | |
9 | 7 | from django.apps import apps |
8 | from django.contrib.auth import get_user_model | |
10 | 9 | from django.contrib.auth.models import Group, Permission |
11 | 10 | from django.contrib.contenttypes.models import ContentType |
12 | 11 | from django.db.models import Count, Q, QuerySet |
13 | 12 | from django.shortcuts import _get_queryset |
14 | 13 | |
15 | from guardian.compat import basestring, get_user_model, is_anonymous | |
16 | 14 | from guardian.core import ObjectPermissionChecker |
17 | 15 | from guardian.ctypes import get_content_type |
18 | from guardian.exceptions import MixedContentTypeError, WrongAppError | |
16 | from guardian.exceptions import MixedContentTypeError, WrongAppError, MultipleIdentityAndObjectError | |
19 | 17 | from guardian.models import GroupObjectPermission |
20 | 18 | from guardian.utils import get_anonymous_user, get_group_obj_perms_model, get_identity, get_user_obj_perms_model |
21 | 19 | |
29 | 27 | If ``obj`` is not given, must be in format ``app_label.codename`` or |
30 | 28 | ``Permission`` instance. |
31 | 29 | |
32 | :param user_or_group: instance of ``User``, ``AnonymousUser`` or ``Group``; | |
30 | :param user_or_group: instance of ``User``, ``AnonymousUser``, ``Group``, | |
31 | list of ``User`` or ``Group``, or queryset of ``User`` or ``Group``; | |
33 | 32 | passing any other object would raise |
34 | 33 | ``guardian.exceptions.NotUserNorGroup`` exception |
35 | 34 | |
68 | 67 | <Permission: sites | site | Can change site> |
69 | 68 | |
70 | 69 | """ |
71 | ||
72 | 70 | user, group = get_identity(user_or_group) |
73 | 71 | # If obj is None we try to operate on global permissions |
74 | 72 | if obj is None: |
92 | 90 | perm = perm.split('.')[-1] |
93 | 91 | |
94 | 92 | if isinstance(obj, QuerySet): |
93 | if isinstance(user_or_group, (QuerySet, list)): | |
94 | raise MultipleIdentityAndObjectError("Only bulk operations on either users/groups OR objects supported") | |
95 | 95 | if user: |
96 | 96 | model = get_user_obj_perms_model(obj.model) |
97 | 97 | return model.objects.bulk_assign_perm(perm, user, obj) |
98 | 98 | if group: |
99 | 99 | model = get_group_obj_perms_model(obj.model) |
100 | 100 | return model.objects.bulk_assign_perm(perm, group, obj) |
101 | ||
102 | if isinstance(user_or_group, (QuerySet, list)): | |
103 | if user: | |
104 | model = get_user_obj_perms_model(obj) | |
105 | return model.objects.assign_perm_to_many(perm, user, obj) | |
106 | if group: | |
107 | model = get_group_obj_perms_model(obj) | |
108 | return model.objects.assign_perm_to_many(perm, group, obj) | |
101 | 109 | |
102 | 110 | if user: |
103 | 111 | model = get_user_obj_perms_model(obj) |
201 | 209 | Returns queryset of all Permission objects for the given class. It is |
202 | 210 | possible to pass Model as class or instance. |
203 | 211 | """ |
204 | if isinstance(cls, basestring): | |
212 | if isinstance(cls, str): | |
205 | 213 | app_label, model_name = cls.split('.') |
206 | 214 | model = apps.get_model(app_label, model_name) |
207 | 215 | else: |
211 | 219 | |
212 | 220 | |
213 | 221 | def get_users_with_perms(obj, attach_perms=False, with_superusers=False, |
214 | with_group_users=True): | |
222 | with_group_users=True, only_with_perms_in=None): | |
215 | 223 | """ |
216 | 224 | Returns queryset of all ``User`` objects with *any* object permissions for |
217 | 225 | the given ``obj``. |
228 | 236 | :param with_group_users: Default: ``True``. If set to ``False`` result would |
229 | 237 | **not** contain those users who have only group permissions for given |
230 | 238 | ``obj``. |
239 | ||
240 | :param only_with_perms_in: Default: ``None``. If set to an iterable of | |
241 | permission strings then only users with those permissions would be | |
242 | returned. | |
231 | 243 | |
232 | 244 | Example:: |
233 | 245 | |
237 | 249 | >>> |
238 | 250 | >>> page = FlatPage.objects.create(title='Some page', path='/some/page/') |
239 | 251 | >>> joe = User.objects.create_user('joe', 'joe@example.com', 'joesecret') |
252 | >>> dan = User.objects.create_user('dan', 'dan@example.com', 'dansecret') | |
240 | 253 | >>> assign_perm('change_flatpage', joe, page) |
254 | >>> assign_perm('delete_flatpage', dan, page) | |
241 | 255 | >>> |
242 | 256 | >>> get_users_with_perms(page) |
243 | [<User: joe>] | |
257 | [<User: joe>, <User: dan>] | |
244 | 258 | >>> |
245 | 259 | >>> get_users_with_perms(page, attach_perms=True) |
246 | {<User: joe>: [u'change_flatpage']} | |
260 | {<User: joe>: [u'change_flatpage'], <User: dan>: [u'delete_flatpage']} | |
261 | >>> get_users_with_perms(page, only_with_perms_in=['change_flatpage']) | |
262 | [<User: joe>] | |
247 | 263 | |
248 | 264 | """ |
249 | 265 | ctype = get_content_type(obj) |
260 | 276 | else: |
261 | 277 | user_filters = {'%s__content_object' % related_name: obj} |
262 | 278 | qset = Q(**user_filters) |
279 | if only_with_perms_in is not None: | |
280 | permission_ids = Permission.objects.filter(content_type=ctype, codename__in=only_with_perms_in).values_list('id', flat=True) | |
281 | qset &= Q(**{ | |
282 | '%s__permission_id__in' % related_name: permission_ids, | |
283 | }) | |
263 | 284 | if with_group_users: |
264 | 285 | group_model = get_group_obj_perms_model(obj) |
265 | 286 | group_rel_name = group_model.group.field.related_query_name() |
272 | 293 | group_filters = { |
273 | 294 | 'groups__%s__content_object' % group_rel_name: obj, |
274 | 295 | } |
296 | if only_with_perms_in is not None: | |
297 | group_filters.update({ | |
298 | 'groups__%s__permission_id__in' % group_rel_name: permission_ids, | |
299 | }) | |
275 | 300 | qset = qset | Q(**group_filters) |
276 | 301 | if with_superusers: |
277 | 302 | qset = qset | Q(is_superuser=True) |
281 | 306 | users = {} |
282 | 307 | for user in get_users_with_perms(obj, |
283 | 308 | with_group_users=with_group_users, |
309 | only_with_perms_in=only_with_perms_in, | |
284 | 310 | with_superusers=with_superusers): |
285 | 311 | # TODO: Support the case of set with_group_users but not with_superusers. |
286 | 312 | if with_group_users or with_superusers: |
337 | 363 | groups_with_perms = get_groups_with_perms(obj) |
338 | 364 | qs = group_model.objects.filter(group__in=groups_with_perms).prefetch_related('group', 'permission') |
339 | 365 | if group_model is GroupObjectPermission: |
340 | qs = qs.filter(object_pk=obj.pk) | |
366 | qs = qs.filter(object_pk=obj.pk, content_type=ctype) | |
341 | 367 | else: |
342 | 368 | qs = qs.filter(content_object_id=obj.pk) |
343 | 369 | |
447 | 473 | - If accept_global_perms is ``True``: Empty list. |
448 | 474 | - If accept_global_perms is ``False``: Empty list. |
449 | 475 | """ |
450 | if isinstance(perms, basestring): | |
476 | if isinstance(perms, str): | |
451 | 477 | perms = [perms] |
452 | 478 | ctype = None |
453 | 479 | app_label = None |
499 | 525 | # Check if the user is anonymous. The |
500 | 526 | # django.contrib.auth.models.AnonymousUser object doesn't work for queries |
501 | 527 | # and it's nice to be able to pass in request.user blindly. |
502 | if is_anonymous(user): | |
528 | if user.is_anonymous: | |
503 | 529 | user = get_anonymous_user() |
504 | 530 | |
505 | 531 | global_perms = set() |
650 | 676 | [<Task some task>] |
651 | 677 | |
652 | 678 | """ |
653 | if isinstance(perms, basestring): | |
679 | if isinstance(perms, str): | |
654 | 680 | perms = [perms] |
655 | 681 | ctype = None |
656 | 682 | app_label = None |
38 | 38 | <div class="l-2c-fluid l-d-4"> |
39 | 39 | <div class="c-1"><label for="user-permissions" class="required">{% trans "User permissions" %}</label></div> |
40 | 40 | <div class="c-2"> |
41 | <table id="user-permissions" class="object-perms"> | |
41 | <table id="user-permissions" class="grp-table object-perms"> | |
42 | 42 | <thead> |
43 | 43 | <tr> |
44 | 44 | <th>{% trans "User" %}</th> |
99 | 99 | <div class="l-2c-fluid l-d-4"> |
100 | 100 | <div class="c-1"><label for="group-permissions" class="required">{% trans "Group permissions" %}</label></div> |
101 | 101 | <div class="c-2"> |
102 | <table id="group-permissions" class="object-perms"> | |
102 | <table id="group-permissions" class="grp-table object-perms"> | |
103 | 103 | <thead> |
104 | 104 | <tr> |
105 | 105 | <th>{% trans "Group" %}</th> |
147 | 147 | </fieldset> |
148 | 148 | </div> |
149 | 149 | </form> |
150 | {% endblock %}⏎ | |
150 | {% endblock %} |
9 | 9 | {% block breadcrumbs %}{% if not is_popup %} |
10 | 10 | <div class="breadcrumbs"> |
11 | 11 | <a href="../../../../">{% trans "Home" %}</a> › |
12 | <a href="../../../">{{ app_label|capfirst|escape }}</a> › | |
13 | {% if has_change_permission %}<a href="../../">{{ opts.verbose_name_plural|capfirst }}</a>{% else %}{{ opts.verbose_name_plural|capfirst }}{% endif %} › | |
12 | <a href="../../../">{{ opts.app_config.verbose_name|capfirst|escape }}</a> › | |
13 | {% if has_change_permission %}<a href="../../">{{ opts.verbose_name_plural|capfirst }}</a>{% else %}{{ opts.verbose_name_plural|capfirst }}{% endif %} › | |
14 | 14 | {% if has_change_permission %}<a href="../">{{ original|truncatewords:"18" }}</a>{% else %}{{ original|truncatewords:"18" }}{% endif %} › |
15 | 15 | {% trans "Object permissions" %} |
16 | 16 | </div> |
94 | 94 | {% for perm in model_perms %} |
95 | 95 | <th>{{ perm.name }}</th> |
96 | 96 | {% endfor %} |
97 | <th>{% trans "Action" %}</th> | |
97 | <th>{% trans "Action" %}</th> | |
98 | 98 | </tr> |
99 | 99 | </thead> |
100 | 100 | <tbody> |
112 | 112 | {% endfor %} |
113 | 113 | <td> |
114 | 114 | <a href="group-manage/{{ group.id|safe }}/">{% trans "Edit" %}</a> |
115 | </td> | |
115 | </td> | |
116 | 116 | </tr> |
117 | 117 | {% endfor %} |
118 | 118 | </tbody> |
7 | 7 | {% block breadcrumbs %}{% if not is_popup %} |
8 | 8 | <div class="breadcrumbs"> |
9 | 9 | <a href="../../../../../../">{% trans "Home" %}</a> › |
10 | <a href="../../../../../">{{ app_label|capfirst|escape }}</a> › | |
11 | {% if has_change_permission %}<a href="../../../../">{{ opts.verbose_name_plural|capfirst }}</a>{% else %}{{ opts.verbose_name_plural|capfirst }}{% endif %} › | |
10 | <a href="../../../../../">{{ opts.app_config.verbose_name|capfirst|escape }}</a> › | |
11 | {% if has_change_permission %}<a href="../../../../">{{ opts.verbose_name_plural|capfirst }}</a>{% else %}{{ opts.verbose_name_plural|capfirst }}{% endif %} › | |
12 | 12 | {% if has_change_permission %}<a href="../../../">{{ original|truncatewords:"18" }}</a>{% else %}{{ original|truncatewords:"18" }}{% endif %} › |
13 | 13 | {% if has_change_permission %}<a href="../../">{% trans "Object permissions" %}</a>{% else %}{% trans "Object permissions" %}{% endif %} › |
14 | 14 | {% trans "Manage group" %}: {{ group_obj|truncatewords:"18" }} |
7 | 7 | {% block breadcrumbs %}{% if not is_popup %} |
8 | 8 | <div class="breadcrumbs"> |
9 | 9 | <a href="../../../../../../">{% trans "Home" %}</a> › |
10 | <a href="../../../../../">{{ app_label|capfirst|escape }}</a> › | |
11 | {% if has_change_permission %}<a href="../../../../">{{ opts.verbose_name_plural|capfirst }}</a>{% else %}{{ opts.verbose_name_plural|capfirst }}{% endif %} › | |
10 | <a href="../../../../../">{{ opts.app_config.verbose_name|capfirst|escape }}</a> › | |
11 | {% if has_change_permission %}<a href="../../../../">{{ opts.verbose_name_plural|capfirst }}</a>{% else %}{{ opts.verbose_name_plural|capfirst }}{% endif %} › | |
12 | 12 | {% if has_change_permission %}<a href="../../../">{{ original|truncatewords:"18" }}</a>{% else %}{{ original|truncatewords:"18" }}{% endif %} › |
13 | 13 | {% if has_change_permission %}<a href="../../">{% trans "Object permissions" %}</a>{% else %}{% trans "Object permissions" %}{% endif %} › |
14 | 14 | {% trans "Manage user" %}: {{ user_obj|truncatewords:"18" }} |
0 | from __future__ import unicode_literals |
4 | 4 | {% load guardian_tags %} |
5 | 5 | |
6 | 6 | """ |
7 | from __future__ import unicode_literals | |
8 | ||
9 | 7 | from django import template |
8 | from django.contrib.auth import get_user_model | |
10 | 9 | from django.contrib.auth.models import AnonymousUser, Group |
11 | 10 | |
12 | from guardian.compat import get_user_model | |
13 | 11 | from guardian.core import ObjectPermissionChecker |
14 | 12 | from guardian.exceptions import NotUserNorGroup |
15 | 13 | |
41 | 39 | obj = self.obj.resolve(context) |
42 | 40 | if not obj: |
43 | 41 | return '' |
44 | ||
42 | ||
45 | 43 | check = self.checker.resolve(context) if self.checker else ObjectPermissionChecker(for_whom) |
46 | 44 | perms = check.get_perms(obj) |
47 | 45 |
0 | from __future__ import unicode_literals |
0 | # -*- coding: utf-8 -*- | |
1 | 0 | # Generated by Django 1.9.9 on 2016-09-18 17:52 |
2 | from __future__ import unicode_literals | |
3 | ||
4 | 1 | import datetime |
5 | 2 | from django.conf import settings |
6 | 3 | import django.contrib.auth.models |
0 | # -*- coding: utf-8 -*- | |
1 | 0 | # Generated by Django 1.9.9 on 2016-09-18 17:52 |
2 | from __future__ import unicode_literals | |
3 | ||
4 | 1 | from django.db import migrations, models |
5 | 2 | import django.db.models.deletion |
6 | 3 |
0 | # Generated by Django 2.2.2 on 2019-06-11 04:40 | |
1 | ||
2 | import django.contrib.auth.validators | |
3 | from django.db import migrations, models | |
4 | ||
5 | ||
6 | class Migration(migrations.Migration): | |
7 | ||
8 | dependencies = [ | |
9 | ('testapp', '0002_logentrywithgroup'), | |
10 | ] | |
11 | ||
12 | operations = [ | |
13 | migrations.AlterField( | |
14 | model_name='customuser', | |
15 | name='last_name', | |
16 | field=models.CharField(blank=True, max_length=150, verbose_name='last name'), | |
17 | ), | |
18 | migrations.AlterField( | |
19 | model_name='customuser', | |
20 | name='username', | |
21 | field=models.CharField(error_messages={'unique': 'A user with that username already exists.'}, help_text='Required. 150 characters or fewer. Letters, digits and @/./+/-/_ only.', max_length=150, unique=True, validators=[django.contrib.auth.validators.UnicodeUsernameValidator()], verbose_name='username'), | |
22 | ), | |
23 | ] |
0 | from __future__ import unicode_literals | |
1 | 0 | from datetime import datetime |
2 | 1 | |
3 | 2 | from django.db import models |
4 | 3 | from django.contrib.admin.models import LogEntry |
5 | 4 | from django.contrib.auth.models import AbstractUser, AbstractBaseUser |
6 | from django.utils.encoding import python_2_unicode_compatible | |
7 | 5 | |
8 | 6 | from guardian.mixins import GuardianUserMixin |
9 | 7 | from guardian.models import UserObjectPermissionBase |
10 | 8 | from guardian.models import GroupObjectPermissionBase |
11 | 9 | |
12 | 10 | |
13 | @python_2_unicode_compatible | |
14 | 11 | class Post(models.Model): |
15 | 12 | title = models.CharField('title', max_length=64) |
16 | 13 | |
18 | 15 | return self.title |
19 | 16 | |
20 | 17 | |
21 | class DynamicAccessor(object): | |
18 | class DynamicAccessor: | |
22 | 19 | |
23 | 20 | def __init__(self): |
24 | 21 | pass |
53 | 50 | content_object = models.ForeignKey('Mixed', on_delete=models.CASCADE) |
54 | 51 | |
55 | 52 | |
56 | @python_2_unicode_compatible | |
57 | 53 | class Mixed(models.Model): |
58 | 54 | """ |
59 | 55 | Model for tests obj perms checks with generic user object permissions model |
69 | 65 | content_object = models.ForeignKey('ReverseMixed', on_delete=models.CASCADE) |
70 | 66 | |
71 | 67 | |
72 | @python_2_unicode_compatible | |
73 | 68 | class ReverseMixed(models.Model): |
74 | 69 | """ |
75 | 70 | Model for tests obj perms checks with generic group object permissions model |
0 | from __future__ import unicode_literals |
0 | from __future__ import unicode_literals | |
1 | import os | |
2 | 0 | import unittest |
3 | from guardian.utils import abspath | |
4 | 1 | from guardian.conf import settings as guardian_settings |
5 | 2 | from django.conf import settings |
6 | 3 | from django.conf import UserSettingsHolder |
7 | 4 | from django.utils.functional import wraps |
8 | ||
9 | ||
10 | THIS = abspath(os.path.dirname(__file__)) | |
11 | TEST_TEMPLATES_DIR = abspath(THIS, 'templates') | |
12 | ||
13 | ||
14 | TEST_SETTINGS = dict( | |
15 | TEMPLATE_DIRS=[TEST_TEMPLATES_DIR], | |
16 | ) | |
17 | 5 | |
18 | 6 | |
19 | 7 | def skipUnlessTestApp(obj): |
22 | 10 | 'app %r must be installed to run this test' % app)(obj) |
23 | 11 | |
24 | 12 | |
25 | class TestDataMixin(object): | |
13 | class TestDataMixin: | |
26 | 14 | |
27 | 15 | def setUp(self): |
28 | super(TestDataMixin, self).setUp() | |
16 | super().setUp() | |
29 | 17 | from django.contrib.auth.models import Group |
30 | try: | |
31 | from django.contrib.auth import get_user_model | |
32 | User = get_user_model() | |
33 | except ImportError: | |
34 | from django.contrib.auth.models import User | |
18 | from django.contrib.auth import get_user_model | |
19 | User = get_user_model() | |
35 | 20 | Group.objects.create(pk=1, name='admins') |
36 | 21 | jack_group = Group.objects.create(pk=2, name='jackGroup') |
37 | 22 | User.objects.get_or_create(username=guardian_settings.ANONYMOUS_USER_NAME) |
40 | 25 | jack.groups.add(jack_group) |
41 | 26 | |
42 | 27 | |
43 | class override_settings(object): | |
28 | class override_settings: | |
44 | 29 | """ |
45 | 30 | Acts as either a decorator, or a context manager. If it's a decorator it |
46 | 31 | takes a function and returns a wrapped function. If it's a contextmanager |
0 | from __future__ import unicode_literals | |
1 | 0 | import copy |
2 | 1 | |
3 | 2 | from django import forms |
4 | 3 | from django.conf import settings |
5 | 4 | from django.contrib import admin |
5 | from django.contrib.auth import get_user_model | |
6 | 6 | from django.contrib.contenttypes.models import ContentType |
7 | 7 | from django.http import HttpRequest |
8 | 8 | from django.test import TestCase |
9 | 9 | from django.test.client import Client |
10 | from django.urls import reverse | |
10 | 11 | |
11 | 12 | from guardian.admin import GuardedModelAdmin |
12 | from guardian.compat import get_user_model, get_model_name | |
13 | from guardian.compat import reverse | |
14 | from guardian.compat import str | |
15 | 13 | from guardian.shortcuts import get_perms |
16 | 14 | from guardian.shortcuts import get_perms_for_model |
17 | from guardian.testapp.tests.conf import TEST_SETTINGS | |
18 | from guardian.testapp.tests.conf import override_settings | |
19 | 15 | from guardian.models import Group |
20 | 16 | from guardian.testapp.tests.conf import skipUnlessTestApp |
21 | 17 | from guardian.testapp.models import LogEntryWithGroup as LogEntry |
33 | 29 | admin.site.register(ContentType, ContentTypeGuardedAdmin) |
34 | 30 | |
35 | 31 | |
36 | @override_settings(**TEST_SETTINGS) | |
37 | 32 | class AdminTests(TestCase): |
38 | 33 | |
39 | 34 | def setUp(self): |
44 | 39 | self.client = Client() |
45 | 40 | self.obj = ContentType.objects.create( |
46 | 41 | model='bar', app_label='fake-for-guardian-tests') |
47 | self.obj_info = self.obj._meta.app_label, get_model_name(self.obj) | |
42 | self.obj_info = self.obj._meta.app_label, self.obj._meta.model_name | |
48 | 43 | |
49 | 44 | def tearDown(self): |
50 | 45 | self.client.logout() |
0 | from __future__ import unicode_literals | |
1 | 0 | from django.core.exceptions import ImproperlyConfigured |
2 | 1 | from django.test import TestCase |
3 | 2 | import mock |
0 | from __future__ import unicode_literals | |
1 | 0 | from itertools import chain |
2 | 1 | |
3 | 2 | from django.conf import settings |
4 | 3 | from guardian.conf import settings as guardian_settings |
5 | # Try the new app settings (Django 1.7) and fall back to the old system | |
6 | try: | |
7 | from django.apps import apps as django_apps | |
8 | auth_app = django_apps.get_app_config("auth") | |
9 | except ImportError: | |
10 | from django.contrib.auth import models as auth_app | |
4 | from django.apps import apps as django_apps | |
5 | from django.contrib.auth import get_user_model | |
6 | from django.contrib.auth.management import create_permissions | |
11 | 7 | from django.contrib.auth.models import Group, Permission, AnonymousUser |
12 | 8 | from django.contrib.contenttypes.models import ContentType |
13 | 9 | from django.test import TestCase |
14 | 10 | |
15 | 11 | from guardian.core import ObjectPermissionChecker |
16 | from guardian.compat import get_user_model, create_permissions | |
17 | 12 | from guardian.exceptions import NotUserNorGroup |
18 | 13 | from guardian.models import UserObjectPermission, GroupObjectPermission |
19 | 14 | from guardian.shortcuts import assign_perm |
21 | 16 | |
22 | 17 | from guardian.testapp.models import Project |
23 | 18 | |
19 | auth_app = django_apps.get_app_config('auth') | |
24 | 20 | User = get_user_model() |
25 | 21 | |
26 | 22 | |
56 | 52 | class ObjectPermissionCheckerTest(ObjectPermissionTestCase): |
57 | 53 | |
58 | 54 | def setUp(self): |
59 | super(ObjectPermissionCheckerTest, self).setUp() | |
55 | super().setUp() | |
60 | 56 | # Required if MySQL backend is used :/ |
61 | create_permissions(auth_app, [], 1) | |
57 | create_permissions(auth_app, 1) | |
62 | 58 | |
63 | 59 | def test_cache_for_queries_count(self): |
64 | 60 | settings.DEBUG = True |
0 | from __future__ import unicode_literals | |
0 | from django.contrib.auth import get_user_model | |
1 | 1 | from django.contrib.contenttypes.models import ContentType |
2 | 2 | from django.test import TestCase |
3 | 3 | |
4 | from guardian.compat import get_user_model | |
5 | 4 | from guardian.shortcuts import assign_perm, remove_perm |
6 | 5 | |
7 | 6 |
0 | from __future__ import unicode_literals | |
1 | from django.conf import settings, global_settings | |
0 | from django.conf import global_settings | |
1 | from django.contrib.auth import get_user_model | |
2 | 2 | from django.contrib.auth.models import Group, AnonymousUser |
3 | 3 | from django.core.exceptions import ObjectDoesNotExist, PermissionDenied |
4 | 4 | from django.db.models.base import ModelBase |
11 | 11 | from django.template import TemplateDoesNotExist |
12 | 12 | from django.test import TestCase |
13 | 13 | |
14 | from guardian.compat import get_user_model | |
15 | 14 | from guardian.compat import get_user_model_path |
16 | 15 | from guardian.compat import get_user_permission_full_codename |
17 | 16 | import mock |
19 | 18 | from guardian.exceptions import GuardianError |
20 | 19 | from guardian.exceptions import WrongAppError |
21 | 20 | from guardian.shortcuts import assign_perm |
22 | from guardian.testapp.tests.conf import TEST_SETTINGS | |
23 | 21 | from guardian.testapp.tests.conf import TestDataMixin |
24 | 22 | from guardian.testapp.tests.conf import override_settings |
25 | 23 | from guardian.testapp.tests.conf import skipUnlessTestApp |
26 | from django import get_version as django_get_version | |
27 | 24 | |
28 | 25 | User = get_user_model() |
29 | 26 | user_model_path = get_user_model_path() |
30 | 27 | |
31 | 28 | |
32 | @override_settings(**TEST_SETTINGS) | |
33 | 29 | @skipUnlessTestApp |
34 | 30 | class PermissionRequiredTest(TestDataMixin, TestCase): |
35 | 31 | |
36 | 32 | def setUp(self): |
37 | super(PermissionRequiredTest, self).setUp() | |
33 | super().setUp() | |
38 | 34 | self.anon = AnonymousUser() |
39 | 35 | self.user = User.objects.get_or_create(username='jack')[0] |
40 | 36 | self.group = Group.objects.get_or_create(name='jackGroup')[0] |
393 | 389 | def test_redirection_class(self): |
394 | 390 | view_url = '/permission_required/' |
395 | 391 | |
396 | if django_get_version() < "1.5": | |
397 | # skip this test for django versions < 1.5 | |
398 | return | |
399 | ||
400 | 392 | response = self.client.get(view_url) |
401 | 393 | # this should be '/account/login' |
402 | 394 | self.assertRedirects( |
0 | from __future__ import unicode_literals | |
1 | ||
0 | from django.contrib.auth import get_user_model | |
2 | 1 | from django.contrib.auth.models import Group, Permission |
3 | 2 | from django.test import TestCase |
4 | 3 | |
5 | from guardian.compat import get_user_model | |
6 | 4 | from guardian.shortcuts import assign_perm |
7 | 5 | from guardian.shortcuts import get_groups_with_perms |
8 | 6 | from guardian.shortcuts import get_objects_for_group |
0 | from __future__ import unicode_literals | |
1 | ||
0 | from django.contrib.auth import get_user_model | |
2 | 1 | from django.contrib.contenttypes.models import ContentType |
3 | 2 | from django.test import TestCase |
4 | from guardian.compat import get_user_model | |
5 | 3 | from guardian.forms import BaseObjectPermissionsForm |
6 | 4 | |
7 | 5 | |
19 | 17 | |
20 | 18 | def __init__(formself, user, *args, **kwargs): |
21 | 19 | self.user = user |
22 | super(MyUserObjectPermissionsForm, formself).__init__(*args, | |
23 | **kwargs) | |
20 | super().__init__(*args, **kwargs) | |
24 | 21 | |
25 | 22 | form = MyUserObjectPermissionsForm(self.user, self.obj, {}) |
26 | 23 | self.assertRaises(NotImplementedError, form.save_obj_perms) |
0 | from __future__ import absolute_import | |
1 | from __future__ import unicode_literals | |
0 | from django.contrib.auth import get_user_model | |
2 | 1 | from django.test import TestCase, override_settings |
3 | 2 | |
4 | from guardian.compat import get_user_model | |
5 | 3 | import mock |
6 | 4 | from guardian.management import create_anonymous_user |
7 | 5 | from guardian.utils import get_anonymous_user |
0 | from __future__ import unicode_literals | |
0 | import warnings | |
1 | ||
2 | import mock | |
1 | 3 | from django.test import TestCase |
2 | import mock | |
3 | import warnings | |
4 | 4 | from guardian.managers import UserObjectPermissionManager |
5 | 5 | from guardian.managers import GroupObjectPermissionManager |
6 | 6 |
0 | from __future__ import unicode_literals | |
1 | ||
0 | from django.contrib.auth import get_user_model | |
2 | 1 | from django.contrib.auth.models import AnonymousUser |
3 | 2 | from django.core.exceptions import ImproperlyConfigured |
4 | 3 | from django.core.exceptions import PermissionDenied |
9 | 8 | from django.views.generic import ListView |
10 | 9 | |
11 | 10 | from guardian.shortcuts import assign_perm |
12 | from guardian.compat import get_user_model | |
13 | 11 | import mock |
14 | 12 | from guardian.mixins import LoginRequiredMixin |
15 | 13 | from guardian.mixins import PermissionRequiredMixin |
0 | from __future__ import unicode_literals | |
1 | ||
2 | 0 | from django.apps import apps as django_apps |
3 | 1 | auth_app = django_apps.get_app_config("auth") |
4 | 2 | |
3 | from django.contrib.auth import get_user_model | |
4 | from django.contrib.auth.management import create_permissions | |
5 | 5 | from django.contrib.contenttypes.models import ContentType |
6 | 6 | from django.core.management import call_command |
7 | 7 | from django.test import TestCase |
8 | 8 | |
9 | from guardian.compat import get_user_model, create_permissions, get_model_name | |
10 | 9 | from guardian.utils import clean_orphan_obj_perms |
11 | 10 | from guardian.shortcuts import assign_perm |
12 | 11 | from guardian.models import Group |
14 | 13 | |
15 | 14 | |
16 | 15 | User = get_user_model() |
17 | user_module_name = get_model_name(User) | |
16 | user_module_name = User._meta.model_name | |
18 | 17 | |
19 | 18 | |
20 | 19 | @skipUnlessTestApp |
29 | 28 | self.target_obj2 = ContentType.objects.create( |
30 | 29 | model='bar', app_label='fake-for-guardian-tests') |
31 | 30 | # Required if MySQL backend is used :/ |
32 | create_permissions(auth_app, [], 1) | |
31 | create_permissions(auth_app, 1) | |
33 | 32 | |
34 | 33 | self.user = User.objects.create(username='user') |
35 | 34 | self.group = Group.objects.create(name='group') |
0 | from __future__ import unicode_literals | |
1 | ||
2 | 0 | import mock |
3 | 1 | import unittest |
4 | 2 | |
3 | from django.contrib.auth import get_user_model | |
4 | from django.contrib.auth.models import AbstractUser | |
5 | 5 | from django.contrib.auth.models import AnonymousUser |
6 | 6 | from django.contrib.auth.models import Group |
7 | 7 | from django.contrib.auth.models import Permission |
11 | 11 | |
12 | 12 | import guardian |
13 | 13 | from guardian.backends import ObjectPermissionBackend |
14 | from guardian.compat import get_user_model | |
15 | 14 | from guardian.compat import get_user_model_path |
16 | 15 | from guardian.compat import get_user_permission_codename |
17 | from guardian.compat import basestring | |
18 | from guardian.compat import unicode | |
19 | 16 | from guardian.exceptions import GuardianError |
20 | 17 | from guardian.exceptions import NotUserNorGroup |
21 | 18 | from guardian.exceptions import ObjectNotPersisted |
30 | 27 | class UserPermissionTests(TestDataMixin, TestCase): |
31 | 28 | |
32 | 29 | def setUp(self): |
33 | super(UserPermissionTests, self).setUp() | |
30 | super().setUp() | |
34 | 31 | self.user = User.objects.get(username='jack') |
35 | 32 | self.ctype = ContentType.objects.create( |
36 | 33 | model='bar', app_label='fake-for-guardian-tests') |
105 | 102 | self.assertRaises(ValidationError, UserObjectPermission.objects.create, |
106 | 103 | **create_info) |
107 | 104 | |
108 | def test_unicode(self): | |
109 | codename = get_user_permission_codename('change') | |
110 | obj_perm = UserObjectPermission.objects.assign_perm(codename, | |
111 | self.user, self.user) | |
112 | self.assertTrue(isinstance(obj_perm.__unicode__(), unicode)) | |
113 | ||
114 | 105 | def test_errors(self): |
115 | 106 | not_saved_user = User(username='not_saved_user') |
116 | 107 | codename = get_user_permission_codename('change') |
125 | 116 | class GroupPermissionTests(TestDataMixin, TestCase): |
126 | 117 | |
127 | 118 | def setUp(self): |
128 | super(GroupPermissionTests, self).setUp() | |
119 | super().setUp() | |
129 | 120 | self.user = User.objects.get(username='jack') |
130 | 121 | self.group, created = Group.objects.get_or_create(name='jackGroup') |
131 | 122 | self.user.groups.add(self.group) |
200 | 191 | ) |
201 | 192 | self.assertRaises(ValidationError, GroupObjectPermission.objects.create, |
202 | 193 | **create_info) |
203 | ||
204 | def test_unicode(self): | |
205 | obj_perm = GroupObjectPermission.objects.assign_perm("change_group", | |
206 | self.group, self.group) | |
207 | self.assertTrue(isinstance(obj_perm.__unicode__(), unicode)) | |
208 | 194 | |
209 | 195 | def test_errors(self): |
210 | 196 | not_saved_group = Group(name='not_saved_group') |
267 | 253 | |
268 | 254 | def test_version(self): |
269 | 255 | for x in guardian.VERSION: |
270 | self.assertTrue(isinstance(x, (int, basestring))) | |
256 | self.assertTrue(isinstance(x, (int, str))) | |
271 | 257 | |
272 | 258 | def test_get_version(self): |
273 | self.assertTrue(isinstance(guardian.get_version(), basestring)) | |
259 | self.assertTrue(isinstance(guardian.get_version(), str)) | |
274 | 260 | |
275 | 261 | |
276 | 262 | class TestExceptions(TestCase): |
288 | 274 | @unittest.skip("test is broken") |
289 | 275 | class TestMonkeyPatch(TestCase): |
290 | 276 | |
291 | @mock.patch('guardian.compat.get_user_model') | |
277 | @mock.patch('django.contrib.auth.get_user_model') | |
292 | 278 | def test_monkey_patch(self, mocked_get_user_model): |
293 | # Import AbstractUser here as it is only available since Django 1.5 | |
294 | from django.contrib.auth.models import AbstractUser | |
295 | 279 | |
296 | 280 | class CustomUserTestClass(AbstractUser): |
297 | 281 | pass |
0 | from __future__ import unicode_literals | |
1 | ||
0 | import warnings | |
1 | ||
2 | import django | |
3 | from django.contrib.auth import get_user_model | |
2 | 4 | from django.contrib.auth.models import AnonymousUser |
3 | 5 | from django.contrib.contenttypes.models import ContentType |
4 | 6 | from django.db.models.query import QuerySet |
6 | 8 | |
7 | 9 | from guardian.shortcuts import get_perms_for_model |
8 | 10 | from guardian.core import ObjectPermissionChecker |
9 | from guardian.compat import get_user_model | |
10 | from guardian.compat import get_user_permission_full_codename, get_model_name | |
11 | from guardian.compat import get_user_permission_full_codename | |
11 | 12 | from guardian.shortcuts import assign |
12 | 13 | from guardian.shortcuts import assign_perm |
13 | 14 | from guardian.shortcuts import remove_perm |
21 | 22 | from guardian.exceptions import MixedContentTypeError |
22 | 23 | from guardian.exceptions import NotUserNorGroup |
23 | 24 | from guardian.exceptions import WrongAppError |
25 | from guardian.exceptions import MultipleIdentityAndObjectError | |
24 | 26 | from guardian.testapp.models import NonIntPKModel |
25 | 27 | from guardian.testapp.tests.test_core import ObjectPermissionTestCase |
26 | 28 | from guardian.models import Group, Permission |
27 | 29 | |
28 | import warnings | |
29 | ||
30 | 30 | |
31 | 31 | User = get_user_model() |
32 | 32 | user_app_label = User._meta.app_label |
33 | user_module_name = get_model_name(User) | |
33 | user_module_name = User._meta.model_name | |
34 | 34 | |
35 | 35 | |
36 | 36 | class ShortcutsTests(ObjectPermissionTestCase): |
37 | 37 | |
38 | 38 | def test_get_perms_for_model(self): |
39 | self.assertEqual(get_perms_for_model(self.user).count(), 3) | |
39 | expected_perms_amount = 3 if django.VERSION < (2, 1) else 4 | |
40 | self.assertEqual(get_perms_for_model(self.user).count(), expected_perms_amount) | |
40 | 41 | self.assertTrue(list(get_perms_for_model(self.user)) == |
41 | 42 | list(get_perms_for_model(User))) |
42 | self.assertEqual(get_perms_for_model(Permission).count(), 3) | |
43 | self.assertEqual(get_perms_for_model(Permission).count(), expected_perms_amount) | |
43 | 44 | |
44 | 45 | model_str = 'contenttypes.ContentType' |
45 | 46 | self.assertEqual( |
124 | 125 | self.assertTrue(isinstance(warns[0].message, DeprecationWarning)) |
125 | 126 | |
126 | 127 | |
128 | class MultipleIdentitiesOperationsTest(ObjectPermissionTestCase): | |
129 | """ | |
130 | Tests assignment of permission to multiple users or groups | |
131 | """ | |
132 | def setUp(self): | |
133 | super().setUp() | |
134 | self.users_list = jim, bob = [ | |
135 | User.objects.create_user(username='jim'), | |
136 | User.objects.create_user(username='bob') | |
137 | ] | |
138 | self.groups_list = jim_group, bob_group = [ | |
139 | Group.objects.create(name='jimgroup'), | |
140 | Group.objects.create(name='bobgroup') | |
141 | ] | |
142 | jim_group.user_set.add(jim) | |
143 | bob_group.user_set.add(bob) | |
144 | self.users_qs = User.objects.exclude(username='AnonymousUser') | |
145 | self.groups_qs = Group.objects.all() | |
146 | ||
147 | def test_assign_to_many_users_queryset(self): | |
148 | assign_perm("add_contenttype", self.users_qs, self.ctype) | |
149 | assign_perm(self.get_permission("delete_contenttype"), self.users_qs, self.ctype) | |
150 | for user in self.users_list: | |
151 | self.assertTrue(user.has_perm("add_contenttype", self.ctype)) | |
152 | self.assertTrue(user.has_perm("delete_contenttype", self.ctype)) | |
153 | ||
154 | def test_assign_to_many_users_list(self): | |
155 | assign_perm("add_contenttype", self.users_list, self.ctype) | |
156 | assign_perm(self.get_permission("delete_contenttype"), self.users_list, self.ctype) | |
157 | for user in self.users_list: | |
158 | self.assertTrue(user.has_perm("add_contenttype", self.ctype)) | |
159 | self.assertTrue(user.has_perm("delete_contenttype", self.ctype)) | |
160 | ||
161 | def test_assign_to_many_groups_queryset(self): | |
162 | assign_perm("add_contenttype", self.groups_qs, self.ctype) | |
163 | assign_perm(self.get_permission("delete_contenttype"), self.groups_qs, self.ctype) | |
164 | for user in self.users_list: | |
165 | self.assertTrue(user.has_perm("add_contenttype", self.ctype)) | |
166 | self.assertTrue(user.has_perm("delete_contenttype", self.ctype)) | |
167 | ||
168 | def test_assign_to_many_groups_list(self): | |
169 | assign_perm("add_contenttype", self.groups_list, self.ctype) | |
170 | assign_perm(self.get_permission("delete_contenttype"), self.groups_list, self.ctype) | |
171 | for user in self.users_list: | |
172 | self.assertTrue(user.has_perm("add_contenttype", self.ctype)) | |
173 | self.assertTrue(user.has_perm("delete_contenttype", self.ctype)) | |
174 | ||
175 | def test_assign_to_multiple_identity_and_obj(self): | |
176 | with self.assertRaises(MultipleIdentityAndObjectError): | |
177 | assign_perm("add_contenttype", self.users_list, self.ctype_qset) | |
178 | with self.assertRaises(MultipleIdentityAndObjectError): | |
179 | assign_perm("add_contenttype", self.users_qs, self.ctype_qset) | |
180 | ||
181 | ||
127 | 182 | class RemovePermTest(ObjectPermissionTestCase): |
128 | 183 | """ |
129 | 184 | Tests object permissions removal. |
164 | 219 | assign_perm("change_contenttype", self.user, self.ctype_qset) |
165 | 220 | remove_perm("change_contenttype", self.user, self.ctype_qset.none()) |
166 | 221 | |
167 | self.assertEquals(list(self.ctype_qset.none()), []) | |
222 | self.assertEqual(list(self.ctype_qset.none()), []) | |
168 | 223 | for obj in self.ctype_qset: |
169 | 224 | self.assertTrue(self.user.has_perm("change_contenttype", obj)) |
170 | 225 | |
254 | 309 | set(result_vals), |
255 | 310 | set([user.username for user in (self.user1, self.user2)]), |
256 | 311 | ) |
312 | ||
313 | def test_only_with_perms_in(self): | |
314 | assign_perm("change_contenttype", self.user1, self.obj1) | |
315 | assign_perm("delete_contenttype", self.user2, self.obj1) | |
316 | assign_perm("delete_contenttype", self.user3, self.obj2) | |
317 | ||
318 | result = get_users_with_perms(self.obj1, only_with_perms_in=('change_contenttype',)) | |
319 | result_vals = result.values_list('username', flat=True) | |
320 | ||
321 | self.assertEqual( | |
322 | set(result_vals), | |
323 | set((self.user1.username,)), | |
324 | ) | |
325 | ||
326 | def test_only_with_perms_in_and_with_group_users(self): | |
327 | self.user1.groups.add(self.group1) | |
328 | self.user2.groups.add(self.group2) | |
329 | self.user3.groups.add(self.group3) | |
330 | ||
331 | # assign perms to groups | |
332 | assign_perm("change_contenttype", self.group1, self.obj1) | |
333 | assign_perm("delete_contenttype", self.group2, self.obj1) | |
334 | assign_perm("add_contenttype", self.group3, self.obj2) | |
335 | ||
336 | result = get_users_with_perms(self.obj1, only_with_perms_in=('change_contenttype', 'delete_contenttype'), with_group_users=True) | |
337 | result_vals = result.values_list('username', flat=True) | |
338 | ||
339 | self.assertEqual( | |
340 | set(result_vals), | |
341 | set((self.user1.username, self.user2.username)), | |
342 | ) | |
343 | ||
344 | def test_only_with_perms_in_and_not_with_group_users(self): | |
345 | self.user1.groups.add(self.group1) | |
346 | self.user2.groups.add(self.group2) | |
347 | self.user3.groups.add(self.group3) | |
348 | ||
349 | # assign perms to groups | |
350 | assign_perm("change_contenttype", self.group1, self.obj1) | |
351 | assign_perm("delete_contenttype", self.group2, self.obj1) | |
352 | assign_perm("delete_contenttype", self.group3, self.obj2) | |
353 | ||
354 | # assign perms to user | |
355 | assign_perm("change_contenttype", self.user2, self.obj1) | |
356 | ||
357 | result = get_users_with_perms(self.obj1, only_with_perms_in=('change_contenttype', 'delete_contenttype'), with_group_users=False) | |
358 | result_vals = result.values_list('username', flat=True) | |
359 | ||
360 | self.assertEqual( | |
361 | set(result_vals), | |
362 | set((self.user2.username,)), | |
363 | ) | |
364 | ||
365 | def test_only_with_perms_in_attached(self): | |
366 | assign_perm("change_contenttype", self.user1, self.obj1) | |
367 | assign_perm("change_contenttype", self.user2, self.obj1) | |
368 | assign_perm("delete_contenttype", self.user2, self.obj1) | |
369 | assign_perm("delete_contenttype", self.user3, self.obj2) | |
370 | ||
371 | result = get_users_with_perms(self.obj1, only_with_perms_in=('delete_contenttype',), | |
372 | attach_perms=True) | |
373 | ||
374 | expected = {self.user2: ('change_contenttype', 'delete_contenttype')} | |
375 | self.assertEqual(result.keys(), expected.keys()) | |
376 | for key, perms in result.items(): | |
377 | self.assertEqual(set(perms), set(expected[key])) | |
257 | 378 | |
258 | 379 | def test_users_groups_perms(self): |
259 | 380 | self.user1.groups.add(self.group1) |
384 | 505 | self.assertEqual(set(get_group_perms(self.group1, self.obj1)), set(['delete_contenttype'])) |
385 | 506 | self.assertEqual(set(get_group_perms(self.group2, self.obj1)), set([])) |
386 | 507 | self.assertEqual(set(get_group_perms(admin, self.obj1)), set([])) |
387 | self.assertEqual(set(get_perms(admin, self.obj1)), set(['add_contenttype', 'change_contenttype', 'delete_contenttype'])) | |
508 | expected_permissions = ['add_contenttype', 'change_contenttype', 'delete_contenttype'] | |
509 | if django.VERSION >= (2, 1): | |
510 | expected_permissions.append('view_contenttype') | |
511 | self.assertEqual(set(get_perms(admin, self.obj1)), set(expected_permissions)) | |
388 | 512 | self.assertEqual(set(get_perms(self.user1, self.obj1)), set(['change_contenttype', 'delete_contenttype'])) |
389 | 513 | self.assertEqual(set(get_perms(self.user2, self.obj1)), set(['delete_contenttype'])) |
390 | 514 | self.assertEqual(set(get_perms(self.group1, self.obj1)), set(['delete_contenttype'])) |
402 | 526 | admin: ["add_contenttype", "change_contenttype", "delete_contenttype"], |
403 | 527 | self.user2: ["delete_contenttype"] |
404 | 528 | } |
529 | if django.VERSION >= (2, 1): | |
530 | expected[admin].append("view_contenttype") | |
405 | 531 | result = get_users_with_perms(self.obj1, attach_perms=True, |
406 | 532 | with_superusers=False, with_group_users=True) |
407 | 533 | self.assertEqual(result.keys(), expected.keys()) |
480 | 606 | remove_perm("change_contenttype", self.group1, self.obj1) |
481 | 607 | result = get_groups_with_perms(self.obj1, attach_perms=True) |
482 | 608 | self.assertEqual(len(result), 0) |
609 | ||
610 | def test_filter_by_contenttype(self): | |
611 | # Make sure that both objects have same pk. | |
612 | obj = ContentType.objects.create(pk=1042, model='baz', app_label='guardian-tests') | |
613 | group = Group.objects.create(pk=1042, name='group') | |
614 | ||
615 | assign_perm("change_group", self.group1, group) | |
616 | assign_perm("change_contenttype", self.group1, obj) | |
617 | ||
618 | result = get_groups_with_perms(obj, attach_perms=True) | |
619 | # No group permissions should be included, even though objects have same pk. | |
620 | self.assertEqual(result[self.group1], ["change_contenttype"]) | |
483 | 621 | |
484 | 622 | def test_mixed(self): |
485 | 623 | assign_perm("change_contenttype", self.group1, self.obj1) |
1062 | 1200 | |
1063 | 1201 | objects = get_objects_for_group( |
1064 | 1202 | self.group1, ['contenttypes.change_contenttype']) |
1065 | self.assertEquals(set(objects), | |
1203 | self.assertEqual(set(objects), | |
1066 | 1204 | set(ContentType.objects.all())) |
1067 | 1205 | |
1068 | 1206 | def test_has_global_permission_and_object_based_permission(self): |
1071 | 1209 | |
1072 | 1210 | objects = get_objects_for_group(self.group1, [ |
1073 | 1211 | 'contenttypes.change_contenttype', 'contenttypes.delete_contenttype'], any_perm=False) |
1074 | self.assertEquals(set(objects), | |
1212 | self.assertEqual(set(objects), | |
1075 | 1213 | set([self.obj1])) |
1076 | 1214 | |
1077 | 1215 | def test_has_global_permission_and_object_based_permission_any_perm(self): |
1080 | 1218 | |
1081 | 1219 | objects = get_objects_for_group(self.group1, [ |
1082 | 1220 | 'contenttypes.change_contenttype', 'contenttypes.delete_contenttype'], any_perm=True) |
1083 | self.assertEquals(set(objects), | |
1221 | self.assertEqual(set(objects), | |
1084 | 1222 | set(ContentType.objects.all())) |
1085 | 1223 | |
1086 | 1224 | def test_has_global_permission_and_object_based_permission_3perms(self): |
1089 | 1227 | assign_perm('contenttypes.add_contenttype', self.group1, self.obj2) |
1090 | 1228 | |
1091 | 1229 | objects = get_objects_for_group(self.group1, [ |
1092 | 'contenttypes.change_contenttype', 'contenttypes.delete_contenttype', 'contenttypes.add_contenttype'], any_perm=False) | |
1093 | self.assertEquals(set(objects), | |
1230 | 'contenttypes.change_contenttype', 'contenttypes.delete_contenttype', 'contenttypes.add_contenttype'], any_perm=False) | |
1231 | self.assertEqual(set(objects), | |
1094 | 1232 | set()) |
1095 | 1233 | |
1096 | 1234 | def test_exception_different_ctypes(self): |
0 | from __future__ import unicode_literals | |
1 | ||
0 | from django.conf import settings | |
1 | from django.contrib.auth import get_user_model | |
2 | 2 | from django.contrib.auth.models import Group, AnonymousUser |
3 | 3 | from django.contrib.contenttypes.models import ContentType |
4 | 4 | from django.template import Template, Context, TemplateSyntaxError |
5 | 5 | from django.test import TestCase |
6 | 6 | |
7 | from guardian.compat import get_user_model, template_debug_getter, template_debug_setter | |
8 | 7 | from guardian.core import ObjectPermissionChecker |
9 | 8 | from guardian.exceptions import NotUserNorGroup |
10 | 9 | from guardian.models import UserObjectPermission, GroupObjectPermission |
81 | 80 | )) |
82 | 81 | context = {'some_obj': ContentType(), 'contenttype': self.ctype} |
83 | 82 | # This test would raise TemplateSyntaxError instead of NotUserNorGroup |
84 | # if TEMPLATE_DEBUG is set to True during tests | |
85 | tmp = template_debug_getter() | |
86 | template_debug_setter(False) | |
83 | # if the template option 'debug' is set to True during tests. | |
84 | template_options = settings.TEMPLATES[0]['OPTIONS'] | |
85 | tmp = template_options.get('debug', False) | |
86 | template_options['debug'] = False | |
87 | 87 | self.assertRaises(NotUserNorGroup, render, template, context) |
88 | template_debug_setter(tmp) | |
88 | template_options['debug'] = tmp | |
89 | 89 | |
90 | 90 | def test_superuser(self): |
91 | 91 | user = User.objects.create(username='superuser', is_superuser=True) |
131 | 131 | output = render(template, context) |
132 | 132 | |
133 | 133 | self.assertEqual(output, 'delete_contenttype') |
134 | ||
134 | ||
135 | 135 | def test_checker(self): |
136 | 136 | GroupObjectPermission.objects.assign_perm("delete_contenttype", self.group, |
137 | 137 | self.ctype) |
138 | 138 | |
139 | 139 | checker = ObjectPermissionChecker(self.user) |
140 | 140 | checker.prefetch_perms(Group.objects.all()) |
141 | ||
141 | ||
142 | 142 | template = ''.join(( |
143 | 143 | '{% load guardian_tags %}', |
144 | 144 | '{% get_obj_perms group for contenttype as "obj_perms" checker %}', |
0 | from __future__ import unicode_literals | |
1 | 0 | from django.test import TestCase |
1 | from django.contrib.auth import get_user_model | |
2 | 2 | from django.contrib.contenttypes.models import ContentType |
3 | 3 | from django.contrib.auth.models import Group, AnonymousUser |
4 | 4 | from django.db import models |
5 | 5 | |
6 | from guardian.compat import get_user_model | |
7 | 6 | from guardian.testapp.tests.conf import skipUnlessTestApp |
8 | 7 | from guardian.testapp.tests.test_core import ObjectPermissionTestCase |
9 | 8 | from guardian.testapp.models import Project |
51 | 50 | self.assertRaises(NotUserNorGroup, get_identity, 1) |
52 | 51 | self.assertRaises(NotUserNorGroup, get_identity, "User") |
53 | 52 | self.assertRaises(NotUserNorGroup, get_identity, User) |
53 | ||
54 | def test_multiple_user_qs(self): | |
55 | user, group = get_identity(User.objects.all()) | |
56 | self.assertIsInstance(user, models.QuerySet) | |
57 | self.assertIsNone(group) | |
58 | ||
59 | def test_multiple_user_list(self): | |
60 | user, group = get_identity([self.user]) | |
61 | self.assertIsInstance(user, list) | |
62 | self.assertIsNone(group) | |
63 | ||
64 | def test_multiple_group_qs(self): | |
65 | user, group = get_identity(Group.objects.all()) | |
66 | self.assertIsInstance(group, models.QuerySet) | |
67 | self.assertIsNone(user) | |
68 | ||
69 | def test_multiple_group_list(self): | |
70 | user, group = get_identity([self.group]) | |
71 | self.assertIsInstance(group, list) | |
72 | self.assertIsNone(user) | |
54 | 73 | |
55 | 74 | |
56 | 75 | @skipUnlessTestApp |
0 | from __future__ import unicode_literals | |
1 | 0 | # handler404 and handler500 are needed for admin tests |
2 | from guardian.compat import include, url, handler404, handler500 # pyflakes:ignore | |
1 | from guardian.compat import url, handler404, handler500 # pyflakes:ignore | |
3 | 2 | from guardian.mixins import PermissionRequiredMixin |
4 | 3 | from django.contrib import admin |
5 | from django.contrib.auth.views import login | |
4 | from django.contrib.auth.views import LoginView | |
6 | 5 | from django.views.generic import View |
7 | 6 | |
8 | 7 | admin.autodiscover() |
13 | 12 | |
14 | 13 | urlpatterns = [ |
15 | 14 | url(r'^admin/', admin.site.urls), |
16 | url(r'^accounts/login/', login, {'template_name': 'blank.html'}), | |
15 | url(r'^accounts/login/', LoginView.as_view(template_name='blank.html')), | |
17 | 16 | url(r'^permission_required/', TestClassRedirectView.as_view()), |
18 | 17 | ] |
1 | 1 | import random |
2 | 2 | import string |
3 | 3 | import environ |
4 | import django | |
5 | 4 | |
6 | 5 | env = environ.Env() |
7 | 6 | |
28 | 27 | 'guardian.backends.ObjectPermissionBackend', |
29 | 28 | ) |
30 | 29 | |
31 | # this fixes warnings in django 1.10 | |
32 | 30 | MIDDLEWARE = ( |
33 | 31 | 'django.middleware.common.CommonMiddleware', |
34 | 32 | 'django.contrib.sessions.middleware.SessionMiddleware', |
35 | 33 | 'django.contrib.auth.middleware.AuthenticationMiddleware', |
36 | 34 | 'django.contrib.messages.middleware.MessageMiddleware', |
37 | 35 | ) |
38 | ||
39 | if django.VERSION < (1, 10): | |
40 | MIDDLEWARE_CLASSES = MIDDLEWARE | |
41 | 36 | |
42 | 37 | TEST_RUNNER = 'django.test.runner.DiscoverRunner' |
43 | 38 | |
71 | 66 | }, |
72 | 67 | }, |
73 | 68 | ] |
74 | ||
75 | if django.VERSION < (1, 8): | |
76 | TEMPLATE_DIRS = TEMPLATES[0]['DIRS'] |
4 | 4 | internal functionality. They are **not** guaranteed to be stable - which means |
5 | 5 | they actual input parameters/output type may change in future releases. |
6 | 6 | """ |
7 | from __future__ import unicode_literals | |
7 | import logging | |
8 | import os | |
9 | from itertools import chain | |
10 | ||
8 | 11 | from django.conf import settings |
9 | from django.contrib.auth import REDIRECT_FIELD_NAME | |
12 | from django.contrib.auth import REDIRECT_FIELD_NAME, get_user_model | |
10 | 13 | from django.contrib.auth.models import AnonymousUser, Group |
11 | 14 | from django.core.exceptions import ObjectDoesNotExist, PermissionDenied |
12 | from django.db.models import Model | |
15 | from django.db.models import Model, QuerySet | |
13 | 16 | from django.http import HttpResponseForbidden, HttpResponseNotFound |
14 | from django.shortcuts import render_to_response | |
15 | from django.template import RequestContext | |
16 | from guardian.compat import get_user_model, remote_model | |
17 | from django.shortcuts import render | |
17 | 18 | from guardian.conf import settings as guardian_settings |
18 | 19 | from guardian.ctypes import get_content_type |
19 | 20 | from guardian.exceptions import NotUserNorGroup |
20 | from itertools import chain | |
21 | ||
22 | import django | |
23 | import logging | |
24 | import os | |
25 | 21 | |
26 | 22 | logger = logging.getLogger(__name__) |
27 | 23 | abspath = lambda *p: os.path.abspath(os.path.join(*p)) |
71 | 67 | if isinstance(identity, AnonymousUser): |
72 | 68 | identity = get_anonymous_user() |
73 | 69 | |
70 | # get identity from queryset model type | |
71 | if isinstance(identity, QuerySet): | |
72 | identity_model_type = identity.model | |
73 | if identity_model_type == get_user_model(): | |
74 | return identity, None | |
75 | elif identity_model_type == Group: | |
76 | return None, identity | |
77 | ||
78 | # get identity from first element in list | |
79 | if isinstance(identity, list) and isinstance(identity[0], get_user_model()): | |
80 | return identity, None | |
81 | if isinstance(identity, list) and isinstance(identity[0], Group): | |
82 | return None, identity | |
83 | ||
74 | 84 | if isinstance(identity, get_user_model()): |
75 | 85 | return identity, None |
76 | elif isinstance(identity, Group): | |
86 | if isinstance(identity, Group): | |
77 | 87 | return None, identity |
78 | 88 | |
79 | 89 | raise NotUserNorGroup("User/AnonymousUser or Group instance is required " |
101 | 111 | if not has_permissions: |
102 | 112 | if return_403: |
103 | 113 | if guardian_settings.RENDER_403: |
104 | response = render_to_response( | |
105 | guardian_settings.TEMPLATE_403, {}, | |
106 | RequestContext(request)) | |
114 | response = render(request, guardian_settings.TEMPLATE_403) | |
107 | 115 | response.status_code = 403 |
108 | 116 | return response |
109 | 117 | elif guardian_settings.RAISE_403: |
111 | 119 | return HttpResponseForbidden() |
112 | 120 | if return_404: |
113 | 121 | if guardian_settings.RENDER_404: |
114 | response = render_to_response( | |
115 | guardian_settings.TEMPLATE_404, {}, | |
116 | RequestContext(request)) | |
122 | response = render(request, guardian_settings.TEMPLATE_404) | |
117 | 123 | response.status_code = 404 |
118 | 124 | return response |
119 | 125 | elif guardian_settings.RAISE_404: |
157 | 163 | obj = obj.__class__ |
158 | 164 | ctype = get_content_type(obj) |
159 | 165 | |
160 | if django.VERSION >= (1, 8): | |
161 | fields = (f for f in obj._meta.get_fields() | |
162 | if (f.one_to_many or f.one_to_one) and f.auto_created) | |
163 | else: | |
164 | fields = obj._meta.get_all_related_objects() | |
166 | fields = (f for f in obj._meta.get_fields() | |
167 | if (f.one_to_many or f.one_to_one) and f.auto_created) | |
165 | 168 | |
166 | 169 | for attr in fields: |
167 | if django.VERSION < (1, 8): | |
168 | model = getattr(attr, 'model', None) | |
169 | else: | |
170 | model = getattr(attr, 'related_model', None) | |
170 | model = getattr(attr, 'related_model', None) | |
171 | 171 | if (model and issubclass(model, base_cls) and |
172 | model is not generic_cls): | |
172 | model is not generic_cls and getattr(model, 'enabled', True)): | |
173 | 173 | # if model is generic one it would be returned anyway |
174 | 174 | if not model.objects.is_generic(): |
175 | 175 | # make sure that content_object's content_type is same as |
176 | 176 | # the one of given obj |
177 | 177 | fk = model._meta.get_field('content_object') |
178 | if ctype == get_content_type(remote_model(fk)): | |
178 | if ctype == get_content_type(fk.remote_field.model): | |
179 | 179 | return model |
180 | 180 | return generic_cls |
181 | 181 |
0 | 0 | [pytest] |
1 | 1 | DJANGO_SETTINGS_MODULE=guardian.testapp.testsettings |
2 | ||
3 | filterwarnings = | |
4 | once::DeprecationWarning | |
5 | once::PendingDeprecationWarning |
0 | 0 | [bumpversion] |
1 | current_version = 1.4.9 | |
1 | current_version = 2.0.0 | |
2 | 2 | |
3 | 3 | [build_sphinx] |
4 | 4 | source-dir = docs/ |
9 | 9 | upload-dir = docs/build/html |
10 | 10 | |
11 | 11 | [bdist_rpm] |
12 | requires = Django >= 1.8 | |
13 | ||
14 | [wheel] | |
15 | universal = 1 | |
12 | requires = Django >= 2.1 | |
16 | 13 | |
17 | 14 | [aliases] |
18 | 15 | test = pytest |
24 | 21 | [bumpversion:file:guardian/__init__.py] |
25 | 22 | search = __version__ = '{current_version}' |
26 | 23 | replace = __version__ = '{new_version}' |
27 | ||
28 | [egg_info] | |
29 | tag_build = | |
30 | tag_date = 0 | |
31 | tag_svn_revision = 0 | |
32 |
2 | 2 | from extras import RunFlakesCommand |
3 | 3 | |
4 | 4 | |
5 | version = '1.4.9' | |
5 | version = '2.0.0' | |
6 | 6 | |
7 | 7 | readme_file = os.path.join(os.path.dirname(__file__), 'README.rst') |
8 | 8 | with open(readme_file, 'r') as f: |
11 | 11 | setup( |
12 | 12 | name='django-guardian', |
13 | 13 | version=version, |
14 | python_requires='>=3.5', | |
14 | 15 | setup_requires=['pytest-runner', ], |
15 | 16 | url='http://github.com/django-guardian/django-guardian', |
16 | 17 | author='Lukasz Balcerzak', |
27 | 28 | ], |
28 | 29 | include_package_data=True, |
29 | 30 | license='BSD', |
30 | install_requires=[ | |
31 | 'six', | |
32 | ], | |
31 | install_requires=[], | |
33 | 32 | tests_require=['mock', 'django-environ', 'pytest', 'pytest-django'], |
34 | 33 | classifiers=['Development Status :: 5 - Production/Stable', |
35 | 34 | 'Environment :: Web Environment', |
36 | 35 | 'Framework :: Django', |
37 | 'Framework :: Django :: 1.8', | |
38 | 'Framework :: Django :: 1.9', | |
39 | 'Framework :: Django :: 1.10', | |
40 | 'Framework :: Django :: 1.11', | |
36 | 'Framework :: Django :: 2.1', | |
37 | 'Framework :: Django :: 2.2', | |
41 | 38 | 'Intended Audience :: Developers', |
42 | 39 | 'License :: OSI Approved :: BSD License', |
43 | 40 | 'Operating System :: OS Independent', |
44 | 41 | 'Programming Language :: Python', |
45 | 42 | 'Topic :: Security', |
46 | 'Programming Language :: Python :: 2.7', | |
47 | 'Programming Language :: Python :: 3.4', | |
48 | 43 | 'Programming Language :: Python :: 3.5', |
49 | 44 | 'Programming Language :: Python :: 3.6', |
45 | 'Programming Language :: Python :: 3.7', | |
46 | 'Programming Language :: Python :: 3 :: Only', | |
50 | 47 | ], |
51 | 48 | test_suite='tests.main', |
52 | 49 | cmdclass={'flakes': RunFlakesCommand}, |
0 | 0 | [tox] |
1 | 1 | downloadcache = {toxworkdir}/cache/ |
2 | envlist = | |
3 | {core,docs}-py27-django18, | |
4 | {core}-py34-django18, | |
5 | {core,docs}-py35-django18, | |
6 | {core,example,docs}-py27-django110, | |
7 | {core,example,docs}-py27-django111, | |
8 | {core}-py34-django110, | |
9 | {core}-py34-django111, | |
10 | {core,example,docs}-py35-django110 | |
11 | {core,example,docs}-py35-django111 | |
12 | {core,example,docs}-py36-django110 | |
13 | {core,example,docs}-py36-django111 | |
2 | envlist = # sort by django version, next by python version | |
3 | {core,example,docs}-py{35,36,py37}-django21, | |
4 | {core,example,docs}-py{35,36,py37}-django22, | |
14 | 5 | |
15 | 6 | [testenv] |
16 | 7 | passenv = DATABASE_URL |
17 | 8 | basepython = |
18 | py27: python2.7 | |
19 | py34: python3.4 | |
20 | 9 | py35: python3.5 |
21 | 10 | py36: python3.6 |
11 | py37: python3.7 | |
22 | 12 | changedir = |
23 | 13 | example: example_project |
24 | 14 | docs: docs |
25 | 15 | commands = |
16 | django21: python {toxinidir}/manage.py makemigrations --check --dry-run | |
17 | django22: python {toxinidir}/manage.py makemigrations --check --dry-run | |
26 | 18 | core: py.test --cov=guardian |
27 | 19 | docs: sphinx-build -b html -d {envtmpdir}/doctrees . {envtmpdir}/html |
28 | 20 | example: python manage.py test |
38 | 30 | docs: sphinx |
39 | 31 | docs: sphinx_rtd_theme |
40 | 32 | docs: setuptools_scm |
41 | django18: django==1.8.17 | |
42 | django110: django>=1.10<1.11 | |
43 | django111: django>=1.11<1.12 | |
33 | django21: django>=2.1,<2.2 | |
34 | django22: django>=2.2,<2.3 |