Skip to content

Commit

Permalink
✅ Finished a first version of user/me PATCH
Browse files Browse the repository at this point in the history
- Added a few tests
- Made them all pass
- `test_permission_is_removed_when_changing_email` will be fixed when
  #65 will me fixed and merged
  • Loading branch information
Lugrim committed Oct 14, 2023
1 parent 646e7c0 commit d494e19
Show file tree
Hide file tree
Showing 2 changed files with 134 additions and 32 deletions.
126 changes: 104 additions & 22 deletions insalan/user/tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
from rest_framework import serializers
from insalan.user.models import User
from django.utils.translation import gettext_lazy as _
import json
import re


Expand Down Expand Up @@ -578,7 +579,6 @@ def test_password_reset_is_token_checked(self):
self.client.post("/v1/user/password-reset/ask/", data, format="json")

match = re.search(
# "https?://[^ ]*/password-reset/ask[^ ]*",
".*https?://[^ ]*/\?user=(?P<username>[^ &]*)&token=(?P<token>[^ /]*)",
mail.outbox[0].body,
)
Expand All @@ -602,10 +602,12 @@ def test_password_reset_is_token_checked(self):
self.assertEqual(request.status_code, 400)

def test_cant_edit_user_if_not_connected(self):
"""
Test that we can't edit any field if we are not connected
"""
request = self.client.patch(
"/v1/user/me/",
data={
"username": "randomplayer",
"current_password": "IUseAVerySecurePassword",
"new_password": "AsDf!621$",
"password_validation": "AsDf!621$",
Expand All @@ -616,8 +618,6 @@ def test_cant_edit_user_if_not_connected(self):
request = self.client.patch(
"/v1/user/me/",
data={
"username": "randomplayer",
"current_password": "IUseAVerySecurePassword",
"email": "[email protected]",
},
)
Expand All @@ -626,8 +626,6 @@ def test_cant_edit_user_if_not_connected(self):
request = self.client.patch(
"/v1/user/me/",
data={
"username": "randomplayer",
"current_password": "IUseAVerySecurePassword",
"last_name": "LesMaths",
},
)
Expand All @@ -636,22 +634,22 @@ def test_cant_edit_user_if_not_connected(self):
request = self.client.patch(
"/v1/user/me/",
data={
"username": "randomplayer",
"current_password": "IUseAVerySecurePassword",
"first_name": "Kevin",
},
)
self.assertEqual(request.status_code, 403)

def test_cant_edit_other_user(self):
"""
Test we can't edit any field of another user
"""
c = APIClient()

c.login(username="anotherplayer", password="ThisIsPassword")

request = c.patch(
"/v1/user/me/",
data={
"username": "randomplayer",
"current_password": "IUseAVerySecurePassword",
"new_password": "AsDf!621$",
"password_validation": "AsDf!621$",
Expand All @@ -662,8 +660,6 @@ def test_cant_edit_other_user(self):
request = c.patch(
"/v1/user/me/",
data={
"username": "randomplayer",
"current_password": "IUseAVerySecurePassword",
"email": "[email protected]",
},
)
Expand All @@ -672,8 +668,6 @@ def test_cant_edit_other_user(self):
request = c.patch(
"/v1/user/me/",
data={
"username": "randomplayer",
"current_password": "IUseAVerySecurePassword",
"last_name": "LesMaths",
},
)
Expand All @@ -682,37 +676,37 @@ def test_cant_edit_other_user(self):
request = c.patch(
"/v1/user/me/",
data={
"username": "randomplayer",
"current_password": "IUseAVerySecurePassword",
"first_name": "Kevin",
},
)
self.assertEqual(request.status_code, 403)

def test_can_edit_self_single_field(self):
"""
Test that we can edit our own fields individually
"""
c = APIClient()

c.login(username="randomplayer", password="IUseAVerySecurePassword")

request = c.patch(
"/v1/user/me/",
data={
"username": "randomplayer",
"current_password": "IUseAVerySecurePassword",
"new_password": "AsDf!621$",
"password_validation": "AsDf!621$",
},
)
self.assertEqual(request.status_code, 200)
self.assertTrue(
User.objects.get(username="randomplayer").check_password("AsDf!621!")
User.objects.get(username="randomplayer").check_password("AsDf!621$")
)

c.login(username="randomplayer", password="AsDf!621$")

request = c.patch(
"/v1/user/me/",
data={
"username": "randomplayer",
"current_password": "IUseAVerySecurePassword",
"email": "[email protected]",
},
)
Expand All @@ -724,8 +718,6 @@ def test_can_edit_self_single_field(self):
request = c.patch(
"/v1/user/me/",
data={
"username": "randomplayer",
"current_password": "IUseAVerySecurePassword",
"last_name": "Les Maths",
},
)
Expand All @@ -737,10 +729,100 @@ def test_can_edit_self_single_field(self):
request = c.patch(
"/v1/user/me/",
data={
"username": "randomplayer",
"first_name": "Kevin",
},
)
self.assertEqual(request.status_code, 200)
self.assertEqual(User.objects.get(username="randomplayer").first_name, "Kevin")

def test_can_edit_several_fields_at_once(self):
"""
Test that we can edit our own fields individually
"""
c = APIClient()

c.login(username="randomplayer", password="IUseAVerySecurePassword")

request = c.patch(
"/v1/user/me/",
data={
"current_password": "IUseAVerySecurePassword",
"new_password": "AsDf!621$",
"password_validation": "AsDf!621$",
},
)
self.assertEqual(request.status_code, 200)
self.assertTrue(
User.objects.get(username="randomplayer").check_password("AsDf!621$")
)

c.login(username="randomplayer", password="AsDf!621$")

request = c.patch(
"/v1/user/me/",
data={
"email": "[email protected]",
"first_name": "Kevin",
"last_name": "Les Maths",
},
)
self.assertEqual(request.status_code, 200)
self.assertEqual(
User.objects.get(username="randomplayer").email, "[email protected]"
)
self.assertEqual(
User.objects.get(username="randomplayer").last_name, "Les Maths"
)
self.assertEqual(User.objects.get(username="randomplayer").first_name, "Kevin")

def test_is_user_logged_out_on_password_change(self):
"""
Test that when we change our password, we are logged out
"""
c = APIClient()

c.login(username="randomplayer", password="IUseAVerySecurePassword")

request = c.patch(
"/v1/user/me/",
data={
"current_password": "IUseAVerySecurePassword",
"new_password": "AsDf!621$",
"password_validation": "AsDf!621$",
},
)
self.assertEqual(request.status_code, 200)
self.assertTrue(
User.objects.get(username="randomplayer").check_password("AsDf!621$")
)

self.assertEqual(c.cookies["sessionid"].value, "")
self.assertEqual(
json.loads(request.content),
{
"logout": [
_(
"Votre mot de passe a bien été changé. Merci de vous re-connecter"
)
]
},
)

def test_permission_is_removed_when_changing_email(self):
"""
Test that the email is no-longer considered as confirmed when we change it
"""
c = APIClient()

c.login(username="randomplayer", password="IUseAVerySecurePassword")

request = c.patch(
"/v1/user/me/",
data={
"email": "[email protected]",
},
)

self.assertFalse(
User.objects.get(username="randomplayer").has_perm("user.email_active")
)
40 changes: 30 additions & 10 deletions insalan/user/views.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
"""User module API Endpoints"""

import sys

from datetime import datetime

from django.contrib.auth import login, logout
Expand All @@ -25,7 +27,7 @@
UserSerializer,
)

from .models import EmailConfirmationTokenGenerator, User, UserMailer
from .models import EmailConfirmationTokenGenerator, User, UserMailer, UserManager


@require_GET
Expand Down Expand Up @@ -70,33 +72,51 @@ def patch(self, request):
"""
user: User = request.user
data = request.data
resp = Response()

if user is None:
raise PermissionDenied()
if "current_password" not in data:
raise BadRequest()
if not user.check_password(data["current_password"]):
raise PermissionDenied()

if "new_password" in data and "password_validation" in data:
# We need the old password to change...
if "current_password" not in data:
raise BadRequest()
# ...and we need it to be correct
if not user.check_password(data["current_password"]):
raise PermissionDenied()

# We need password and its confirmation
if data["new_password"] != data["password_validation"]:
raise BadRequest()

# We need a strong-enough password
validation_errors = validate_password(data["new_password"], user=user)
if validation_errors is not None:
raise BadRequest(validation_errors)

# Everything good, we set the new password
user.set_password(data["new_password"])

# And we log-out
logout(request)
resp.data = {
"logout": [
_(
"Votre mot de passe a bien été changé. Merci de vous re-connecter"
)
]
}

if "email" in data:
user.set_email(data["email"])
user.email = UserManager.normalize_email(data["email"])

if "first_name" in data:
user.set_first_name(data["first_name"])
user.first_name = data["first_name"]

if "last_name" in data:
user.set_last_name(data["last_name"])
user.last_name = data["last_name"]

user.save()
return Response()
return resp


# TODO: change permission
Expand Down

0 comments on commit d494e19

Please sign in to comment.