Skip to content

Commit

Permalink
PB-1109 Add PUT endpoint to update user
Browse files Browse the repository at this point in the history
  • Loading branch information
asteiner-swisstopo committed Nov 5, 2024
1 parent 424f4c4 commit 1a9fc66
Show file tree
Hide file tree
Showing 2 changed files with 139 additions and 0 deletions.
34 changes: 34 additions & 0 deletions app/access/api.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,15 @@
from http import HTTPStatus

from cognito.utils.user import create_cognito_user
from cognito.utils.user import update_cognito_user
from ninja import Router
from ninja.errors import HttpError
from provider.models import Provider

from django.db import transaction
from django.http import Http404
from django.http import HttpRequest
from django.http import HttpResponse
from django.shortcuts import get_object_or_404

from .models import User
Expand Down Expand Up @@ -75,3 +80,32 @@ def create(request: HttpRequest, user_in: UserSchema) -> UserSchema:
if not created:
raise HttpError(500, "Internal Server Error")
return user_to_response(user_out)


@router.put("users/{username}")
def update_user(request: HttpRequest, username: str, user_in: UserSchema) -> HttpResponse:
"""Update the given user with the given user data.
Return HTTP status code
- 200 (OK) if the user has been updated successfully
- 404 (Not Found) if there is no user with the given username
- 500 (Internal Server Error) if there is an inconsistency with Cognito
- 500 (Internal Server Error) if there no provider with the given ID
- 503 (Service Unavailable) if Cognito cannot be reached
"""
with transaction.atomic():
user_object = User.objects.select_for_update().filter(username=username).first()
if not user_object:
raise Http404()

if not Provider.objects.filter(id=user_in.provider_id).exists():
raise HttpError(HTTPStatus.INTERNAL_SERVER_ERROR, "Provider does not exist")

for attr, value in user_in.dict(exclude_unset=True).items():
setattr(user_object, attr, value)
user_object.save()

updated = update_cognito_user(user_object)
if not updated:
raise HttpError(HTTPStatus.INTERNAL_SERVER_ERROR, "Internal Server Error")
return HttpResponse(status=HTTPStatus.OK)
105 changes: 105 additions & 0 deletions app/access/tests/test_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -249,3 +249,108 @@ def test_post_users_returns_503_if_cognito_down(self, create_cognito_user):
assert response.data == {'code': 503, 'description': 'Service Unavailable'}
assert User.objects.count() == 1
assert create_cognito_user.called

@patch('access.api.update_cognito_user')
def test_update_user_updates_existing_user_as_expected(self, update_cognito_user):
update_cognito_user.return_value = True

payload = {
"username": "dude",
"first_name": "Jeff",
"last_name": "Bridges",
"email": "[email protected]",
"provider_id": Provider.objects.last().id,
}

response = self.client.put("users/dude", json=payload)

assert response.status_code == 200
assert response.content == b''
user = User.objects.filter(username="dude").first()
for key, value in payload.items():
assert getattr(user, key) == value
assert update_cognito_user.called

def test_update_user_returns_404_and_leaves_user_as_is_if_user_nonexistent(self):

user_before = User.objects.filter(username="dude").first()
payload = {
"username": "dude",
"first_name": "Jeff",
"last_name": "Bridges",
"email": "[email protected]",
"provider_id": Provider.objects.last().id,
}

nonexistent_username = "maude"
response = self.client.put(f"users/{nonexistent_username}", json=payload)

assert response.status_code == 404
assert response.data == {"code": 404, "description": "Resource not found"}
user_after = User.objects.filter(username="dude").first()
assert user_after == user_before

def test_update_user_returns_500_and_leaves_user_as_is_if_provider_nonexistent(self):

user_before = User.objects.filter(username="dude").first()
nonexistent_id = Provider.objects.last().id + 1234
payload = {
"username": "dude",
"first_name": "Jeff",
"last_name": "Bridges",
"email": "[email protected]",
"provider_id": nonexistent_id,
}

response = self.client.put("users/dude", json=payload)

assert response.status_code == 500
assert response.data == {"code": 500, "description": "Provider does not exist"}
user_after = User.objects.filter(username="dude").first()
assert user_after == user_before

@patch('access.api.update_cognito_user')
def test_update_user_returns_500_and_leaves_user_as_is_if_cognito_inconsistent(
self, update_cognito_user
):
update_cognito_user.return_value = False

user_before = User.objects.filter(username="dude").first()
payload = {
"username": "dude",
"first_name": "Jeff",
"last_name": "Bridges",
"email": "[email protected]",
"provider_id": Provider.objects.last().id,
}

response = self.client.put("users/dude", json=payload)

assert response.status_code == 500
assert response.data == {"code": 500, "description": "Internal Server Error"}
user_after = User.objects.filter(username="dude").first()
assert user_after == user_before
assert update_cognito_user.called

@patch('access.api.update_cognito_user')
def test_update_user_returns_503_and_leaves_user_as_is_if_cognito_down(
self, update_cognito_user
):
update_cognito_user.side_effect = EndpointConnectionError(endpoint_url='http://localhost')

user_before = User.objects.filter(username="dude").first()
payload = {
"username": "dude",
"first_name": "Jeff",
"last_name": "Bridges",
"email": "[email protected]",
"provider_id": Provider.objects.last().id,
}

response = self.client.put("users/dude", json=payload)

assert response.status_code == 503
assert response.data == {"code": 503, "description": "Service Unavailable"}
user_after = User.objects.filter(username="dude").first()
assert user_after == user_before
assert update_cognito_user.called

0 comments on commit 1a9fc66

Please sign in to comment.