Hide keyboard shortcuts

Hot-keys on this page

r m x p   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

119

120

121

122

123

124

125

126

127

128

129

130

131

132

133

134

135

136

137

138

139

""" 

django-model-permissions - simple object permissions for django. 

 

Copyright (C) 2018 Mathias Stelzer 

 

This program is free software: you can redistribute it and/or modify 

it under the terms of the GNU General Public License as published by 

the Free Software Foundation, either version 3 of the License, or 

(at your option) any later version. 

 

This program is distributed in the hope that it will be useful, 

but WITHOUT ANY WARRANTY; without even the implied warranty of 

MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 

GNU General Public License for more details. 

 

You should have received a copy of the GNU General Public License 

along with this program. If not, see <http://www.gnu.org/licenses/>. 

""" 

from django.contrib.auth.context_processors import PermLookupDict, PermWrapper 

from django.core.exceptions import PermissionDenied 

from django.views.generic import ( 

DetailView as DjangoDetailView, 

UpdateView as DjangoUpdateView, 

DeleteView as DjangoDeleteView, 

) 

 

 

class ObjPermLookupDict(PermLookupDict): 

"""Object permissions lookup dictionary.""" 

 

def __init__(self, user, app_label, obj=None): 

"""Initialize object permission lookup dictionary.""" 

super(ObjPermLookupDict, self).__init__(user, app_label) 

self.object = obj 

 

def __getitem__(self, perm_name): 

"""Check whether the user has the given permission for the object.""" 

return self.user.has_perm('{}.{}'.format(self.app_label, perm_name), self.object) 

 

 

class ObjPermWrapper(PermWrapper): 

"""Object permissions wrapper to traverse a list of permissions.""" 

 

def __init__(self, user, obj=None): 

"""Initialize object permissions wrapper.""" 

super(ObjPermWrapper, self).__init__(user) 

self.object = obj 

 

def __getitem__(self, app_label): 

"""Get a lookup dictionary for the object.""" 

return ObjPermLookupDict(self.user, app_label, self.object) 

 

 

class PermissionContextMixin(object): 

""" 

View mixin to insert permissions in the template context. 

 

If the `get_context_data` method is called and the context contains 

an `'object'` element, this will insert a `'object_perms'` permission 

wrapper. 

 

The `get_context_object_name` method will be used too, if it exists. 

""" 

 

def get_context_data(self, **kwargs): 

"""Add object permissions to template context.""" 

kwargs = super().get_context_data(**kwargs) 

if getattr(self, 'object', None): 

permission_wrapper = ObjPermWrapper(self.request.user, self.object) 

kwargs['object_perms'] = permission_wrapper 

if hasattr(self, 'get_context_object_name'): 

context_object_name = self.get_context_object_name(self.object) 

if context_object_name: 

kwargs[context_object_name + '_perms'] = permission_wrapper 

return kwargs 

 

 

class RequirePermissionMixin(object): 

"""View mixin to require object permissions for access.""" 

 

required_permission = None 

 

# noinspection PyMethodMayBeStatic 

def get_required_permission_object(self, obj): 

"""Overwrite to check the required_permission against another model object.""" 

return obj 

 

def check_required_permission(self, permission_object): 

""" 

Check the `required_permission` on the given object. 

 

:raises: :class:`django.core.exceptions.PermissionDenied` if the 

current user does not have the `required_permission`. 

""" 

if not self.has_perm(self.required_permission, permission_object): 

raise PermissionDenied() 

 

def get_object(self, queryset=None): 

""" 

Get the object and check the `required_permission` on it. 

 

:raises: :class:`django.core.exceptions.PermissionDenied` if the 

current user does not have the `required_permission`. 

""" 

obj = super().get_object(queryset=queryset) 

 

if self.required_permission is not None: 

perm_obj = self.get_required_permission_object(obj) 

self.check_required_permission(perm_obj) 

 

return obj 

 

def has_perm(self, perm, obj=None): 

"""Check the given permission on the given object.""" 

return self.request.user.has_perm(perm, obj=obj) 

 

 

class PermissionMixin(RequirePermissionMixin, PermissionContextMixin): 

"""View mixin to enable permissions.""" 

 

pass 

 

 

class DetailView(PermissionMixin, DjangoDetailView): 

"""DetailView with permissions.""" 

 

pass 

 

 

class UpdateView(PermissionMixin, DjangoUpdateView): 

"""UpdateView with permissions.""" 

 

pass 

 

 

class DeleteView(PermissionMixin, DjangoDeleteView): 

"""DeleteView with permissions.""" 

 

pass