Skip to content

Commit 380abbb

Browse files
committed
[Fixes #11995] Implement POST and PATCH methods for the User API
1 parent dafb255 commit 380abbb

File tree

2 files changed

+38
-27
lines changed

2 files changed

+38
-27
lines changed

geonode/base/api/permissions.py

+24-2
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,30 @@
4040
logger = logging.getLogger(__name__)
4141

4242

43+
class IsSelfOrAdminOrReadOnlyUsers(permissions.BasePermission):
44+
"""Grant permission only if the current instance is the request user.
45+
Used to allow users to edit their own account).
46+
"""
47+
48+
def has_permission(self, request, view):
49+
"""Always return True here.
50+
The fine-grained permissions are handled in has_object_permission().
51+
"""
52+
return True
53+
54+
def has_object_permission(self, request, view, obj):
55+
user = request.user
56+
if request.method in permissions.SAFE_METHODS:
57+
return True
58+
if user and (user.is_superuser or user.is_staff):
59+
return True
60+
if user and isinstance(obj, get_user_model()) and obj.pk == user.pk:
61+
if request.method == "DELETE":
62+
return False
63+
return True
64+
return False
65+
66+
4367
class IsSelf(permissions.BasePermission):
4468
"""Grant permission only if the current instance is the request user.
4569
Used to allow users to edit their own account, nothing to others (even
@@ -50,8 +74,6 @@ def has_permission(self, request, view):
5074
"""Always return False here.
5175
The fine-grained permissions are handled in has_object_permission().
5276
"""
53-
if view.basename == "users": # CUTOM CASE FOR users
54-
return True
5577
return False
5678

5779
def has_object_permission(self, request, view, obj):

geonode/people/views.py

+14-25
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@
4949
from geonode.base.models import ResourceBase
5050
from geonode.base.api.filters import DynamicSearchFilter
5151
from geonode.groups.models import GroupProfile, GroupMember
52-
from geonode.base.api.permissions import IsSelfOrAdminOrReadOnly
52+
from geonode.base.api.permissions import IsSelfOrAdminOrReadOnlyUsers
5353
from geonode.base.api.serializers import UserSerializer, GroupProfileSerializer, ResourceBaseSerializer
5454
from geonode.base.api.pagination import GeoNodeApiPagination
5555

@@ -165,6 +165,14 @@ def forgot_username(request):
165165
return render(request, "people/forgot_username_form.html", context={"message": message, "form": username_form})
166166

167167

168+
def password_validation(password_payload):
169+
try:
170+
validate_password(password_payload)
171+
except ValidationErrorForm as err:
172+
raise ValidationError(detail=",".join(err.messages))
173+
return make_password(password_payload)
174+
175+
168176
class UserViewSet(DynamicModelViewSet):
169177
"""
170178
API endpoint that allows users to be viewed or edited.
@@ -173,7 +181,7 @@ class UserViewSet(DynamicModelViewSet):
173181
authentication_classes = [SessionAuthentication, BasicAuthentication, OAuth2Authentication]
174182
permission_classes = [
175183
IsAuthenticated,
176-
IsSelfOrAdminOrReadOnly,
184+
IsSelfOrAdminOrReadOnlyUsers,
177185
]
178186
filter_backends = [DynamicFilterBackend, DynamicSortingFilter, DynamicSearchFilter]
179187
serializer_class = UserSerializer
@@ -192,18 +200,6 @@ def get_queryset(self):
192200
queryset = self.get_serializer_class().setup_eager_loading(queryset)
193201
return queryset.order_by("username")
194202

195-
def perform_destroy(self, instance):
196-
# not implemented added to make tests pass
197-
if any(
198-
(
199-
not self.request.user.is_superuser,
200-
not self.request.user.is_staff,
201-
self.request.user.pk == int(self.kwargs["pk"]),
202-
)
203-
):
204-
raise PermissionDenied()
205-
instance.delete()
206-
207203
def perform_create(self, serializer):
208204
user = self.request.user
209205
if not (user.is_superuser or user.is_staff):
@@ -214,26 +210,19 @@ def perform_create(self, serializer):
214210

215211
if ACCOUNT_EMAIL_REQUIRED and email_payload == "":
216212
raise ValidationError(detail="email missing from payload")
217-
try:
218-
validate_password(password_payload, user=None, password_validators=None)
219-
self.request.data["password"] = make_password(password_payload)
220-
except ValidationErrorForm as err:
221-
raise ValidationError(detail=",".join(err.messages))
213+
self.request.data["password"] = password_validation(password_payload)
222214
instance = serializer.save()
223215
return instance
224216

225217
def update(self, request, *args, **kwargs):
226218
kwargs["partial"] = True
227-
if not self.request.user.is_superuser:
219+
user = self.request.user
220+
if not (user.is_superuser or user.is_staff):
228221
request.data.pop("is_superuser", None)
229222
request.data.pop("is_staff", None)
230223
password_payload = self.request.data.get("password", "")
231224
if password_payload:
232-
try:
233-
validate_password(password_payload, user=None, password_validators=None)
234-
request.data["password"] = make_password(password_payload)
235-
except ValidationErrorForm as err:
236-
raise ValidationError(detail=",".join(err.messages))
225+
request.data["password"] = password_validation(password_payload)
237226
return super().update(request, *args, **kwargs)
238227

239228
@extend_schema(

0 commit comments

Comments
 (0)