From df6fe086af1f27fd8cb3fa7032468c758161eba6 Mon Sep 17 00:00:00 2001 From: Aaron Nagler Date: Tue, 13 Feb 2024 00:10:58 -0500 Subject: [PATCH 1/4] added redundant test case to deleted user --- happiness-backend/api/routes/user.py | 2 +- happiness-backend/tests/test_auth.py | 22 ++++++++++++++++++++++ 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/happiness-backend/api/routes/user.py b/happiness-backend/api/routes/user.py index 9f53a80..7bf1680 100644 --- a/happiness-backend/api/routes/user.py +++ b/happiness-backend/api/routes/user.py @@ -98,7 +98,7 @@ def delete_user(): current_user = token_current_user() db.session.delete(current_user) db.session.commit() - + print("gooofy") return '', 204 diff --git a/happiness-backend/tests/test_auth.py b/happiness-backend/tests/test_auth.py index ccd4744..df2f63c 100644 --- a/happiness-backend/tests/test_auth.py +++ b/happiness-backend/tests/test_auth.py @@ -232,6 +232,28 @@ def test_delete_user(client): and get_user_by_id(1) is None) + user_create_response2 = client.post('/api/user/', json={ + 'email': 'test@example.com', + 'username': 'test2', + 'password': 'test2', + }) + user_credentials2 = base64.b64encode(b"test2:test2").decode('utf-8') + assert user_create_response2.status_code == 201 + + login_response2 = client.post( + '/api/token/', headers={"Authorization": f"Basic {user_credentials2}"}) + assert login_response2.status_code == 201 + bearer_token2 = json.loads(login_response2.get_data()).get("session_token") + assert bearer_token2 is not None + + delete_res2 = client.delete( + '/api/user/', headers={"Authorization": f"Bearer {bearer_token}"}) + assert delete_res2.status_code == 204 + assert (get_user_by_email("text2@example.com") is None and get_user_by_username("test2") is None + and get_user_by_id(1) is None) + + + def test_add_user_setting(client): """ Tests adding two settings to a single user in an instance of the backend. From 8ce6d3b86f39d586f2ada63d18fc431d0aa3b3b2 Mon Sep 17 00:00:00 2001 From: Aaron Nagler Date: Tue, 13 Feb 2024 16:24:55 -0500 Subject: [PATCH 2/4] hopefully fixed delete account bug --- happiness-backend/api/routes/user.py | 8 +- happiness-backend/tests/test_auth.py | 132 +++++++++++++++++++++++---- 2 files changed, 120 insertions(+), 20 deletions(-) diff --git a/happiness-backend/api/routes/user.py b/happiness-backend/api/routes/user.py index bba6dd9..47acc5a 100644 --- a/happiness-backend/api/routes/user.py +++ b/happiness-backend/api/routes/user.py @@ -12,7 +12,7 @@ from api.authentication.auth import token_current_user from api.util.jwt_methods import verify_token from api.dao import users_dao, happiness_dao -from api.models.models import User, Setting +from api.models.models import User, Setting, Happiness from api.models.schema import UserSchema, CreateUserSchema, SettingsSchema, SettingInfoSchema, \ UserInfoSchema, PasswordResetReqSchema, SimpleUserSchema, EmptySchema, PasswordResetSchema, \ FileUploadSchema, NumberSchema, AmountSchema, CountSchema @@ -96,9 +96,13 @@ def delete_user(): Deletes the user that is currently logged in, including all user data. """ current_user = token_current_user() + + happiness_records = db.session.query(Happiness).filter_by(user_id=current_user.id).all() + for happiness_record in happiness_records: + db.session.delete(happiness_record) + db.session.delete(current_user) db.session.commit() - print("gooofy") return '', 204 diff --git a/happiness-backend/tests/test_auth.py b/happiness-backend/tests/test_auth.py index b486330..58ae3f7 100644 --- a/happiness-backend/tests/test_auth.py +++ b/happiness-backend/tests/test_auth.py @@ -4,12 +4,16 @@ import pytest from flask import json +from sqlalchemy.sql.functions import current_user from api import create_app from api.app import db +from api.dao.groups_dao import get_group_by_id from api.dao.users_dao import * +from api.models.models import Happiness from config import TestConfig -from tests.test_groups import auth_header +from tests.test_groups import auth_header, invite_in_group_json_model, group_in_user_modal, invite_in_user_modal, \ + user_in_group_json_model @pytest.fixture @@ -253,26 +257,118 @@ def test_delete_user(client): and get_user_by_id(1) is None) - user_create_response2 = client.post('/api/user/', json={ - 'email': 'test@example.com', - 'username': 'test2', - 'password': 'test2', - }) - user_credentials2 = base64.b64encode(b"test2:test2").decode('utf-8') - assert user_create_response2.status_code == 201 +def test_delete_user_2(init_client): + client, tokens = init_client + init_test_data(client, tokens) + assert (get_user_by_email("test1@example.app") is not None and get_user_by_username("user1") is not None and + get_user_by_id(1) is not None) - login_response2 = client.post( - '/api/token/', headers={"Authorization": f"Basic {user_credentials2}"}) - assert login_response2.status_code == 201 - bearer_token2 = json.loads(login_response2.get_data()).get("session_token") - assert bearer_token2 is not None + # having user make happiness entry - delete_res2 = client.delete( - '/api/user/', headers={"Authorization": f"Bearer {bearer_token}"}) - assert delete_res2.status_code == 204 - assert (get_user_by_email("text2@example.com") is None and get_user_by_username("test2") is None - and get_user_by_id(1) is None) + happiness_create_response0 = client.post('/api/happiness/', json={ + 'value': 2, + 'comment': 'not great day', + 'timestamp': '2024-01-11' + }, headers={"Authorization": f"Bearer {tokens[0]}"}) + assert happiness_create_response0.status_code == 201 + + # creating a big group + + client.post('/api/group/', json={'name': 'test'}, headers=auth_header(tokens[0])) + + invite_users = client.put('/api/group/1', json={ + 'invite_users': ['user2', 'user3'] + }, headers=auth_header(tokens[0])) + assert invite_users.status_code == 200 + assert len(invite_users.json['invited_users']) == len(get_group_by_id(1).invited_users) == 2 + assert invite_in_group_json_model('user2', invite_users.json, get_group_by_id(1)) + assert invite_in_group_json_model('user3', invite_users.json, get_group_by_id(1)) + assert not group_in_user_modal(1, get_user_by_id(2)) + assert invite_in_user_modal(1, get_user_by_id(2)) + + unauthorized_edit = client.put('/api/group/1', json={'name': 'sus'}, + headers=auth_header(tokens[1])) + assert unauthorized_edit.status_code == 403 + + bad_accept_invite = client.post('/api/group/accept_invite/5', headers=auth_header(tokens[1])) + assert bad_accept_invite.status_code == 404 + + accept_invite = client.post('/api/group/accept_invite/1', headers=auth_header(tokens[1])) + assert accept_invite.status_code == 204 + get_group = client.get('/api/group/1', headers=auth_header(tokens[1])) + assert user_in_group_json_model('user2', get_group.json, get_group_by_id(1)) + assert group_in_user_modal(1, get_user_by_id(2)) + + # deleting random member of group + + assert (get_user_by_email("test3@example.app") is not None and get_user_by_username("user3") is not None + and get_user_by_id(3) is not None) + + delete_res = client.delete( + '/api/user/', headers={"Authorization": f"Bearer {tokens[2]}"}) + assert delete_res.status_code == 204 + assert (get_user_by_email("test3@example.app") is None and get_user_by_username("user3") is None + and get_user_by_id(3) is None) + + # deleting creator of group + + delete_res = client.delete( + '/api/user/', headers={"Authorization": f"Bearer {tokens[0]}"}) + assert delete_res.status_code == 204 + assert (get_user_by_email("test1@example.app") is None and get_user_by_username("user1") is None + and get_user_by_id(1) is None) + + # dealing with a different user, who makes entries and has their own group + + assert (get_user_by_email("test2@example.app") is not None and get_user_by_username("user2") is not None and + get_user_by_id(2) is not None) + + count_group11 = client.get('/api/user/count/', query_string={ + }, headers=auth_header(tokens[1])) + assert count_group11.status_code == 200 + assert count_group11.json.get("groups") == 1 + + group_create = client.post('/api/group/', json={'name': 'test2'}, headers=auth_header(tokens[1])) + assert group_create.status_code == 201 + + count_group11 = client.get('/api/user/count/', query_string={ + }, headers=auth_header(tokens[1])) + assert count_group11.status_code == 200 + assert count_group11.json.get("groups") == 2 + assert count_group11.json.get("entries") == 0 + + #count numb of happiness entries of user 2 in the database (before making happiness entry) + + happiness_records = db.session.query(Happiness).filter_by(user_id=2).all() + assert len(happiness_records) == 0 + + happiness_create_response0 = client.post('/api/happiness/', json={ + 'value': 3, + 'comment': 'not great day', + 'timestamp': '2024-01-11' + }, headers={"Authorization": f"Bearer {tokens[1]}"}) + assert happiness_create_response0.status_code == 201 + + count_group12 = client.get('/api/user/count/', query_string={ + }, headers=auth_header(tokens[1])) + assert count_group12.status_code == 200 + assert count_group12.json.get("entries") == 1 + + # count numb of happiness entries of user 2 in the database (after making happiness entry) + + happiness_records2 = db.session.query(Happiness).filter_by(user_id=2).all() + assert len(happiness_records2) == 1 + + delete_res = client.delete( + '/api/user/', headers={"Authorization": f"Bearer {tokens[1]}"}) + assert delete_res.status_code == 204 + assert (get_user_by_email("test2@example.app") is None and get_user_by_username("user2") is None + and get_user_by_id(2) is None) + + # count numb of happiness entries of user 2 in the database (after deleting account) + happiness_records3 = db.session.query(Happiness).filter_by(user_id=2).all() + assert len(happiness_records3) == 0 def test_add_user_setting(client): From cd6becf491b961f445ed1dc4569afa04d830c423 Mon Sep 17 00:00:00 2001 From: Aaron Nagler Date: Tue, 13 Feb 2024 20:33:28 -0500 Subject: [PATCH 3/4] fixed delete user a lil more (private journals) --- happiness-backend/api/routes/user.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/happiness-backend/api/routes/user.py b/happiness-backend/api/routes/user.py index 47acc5a..65f81a2 100644 --- a/happiness-backend/api/routes/user.py +++ b/happiness-backend/api/routes/user.py @@ -12,7 +12,7 @@ from api.authentication.auth import token_current_user from api.util.jwt_methods import verify_token from api.dao import users_dao, happiness_dao -from api.models.models import User, Setting, Happiness +from api.models.models import User, Setting, Happiness, Journal from api.models.schema import UserSchema, CreateUserSchema, SettingsSchema, SettingInfoSchema, \ UserInfoSchema, PasswordResetReqSchema, SimpleUserSchema, EmptySchema, PasswordResetSchema, \ FileUploadSchema, NumberSchema, AmountSchema, CountSchema @@ -101,6 +101,10 @@ def delete_user(): for happiness_record in happiness_records: db.session.delete(happiness_record) + journal_records = db.session.query(Journal).filter_by(user_id=current_user.id).all() + for journal_record in journal_records: + db.session.delete(journal_record) + db.session.delete(current_user) db.session.commit() return '', 204 From 3e07f957454d6db8c3e5805a81a74ef41710e7f4 Mon Sep 17 00:00:00 2001 From: Aaron Nagler Date: Tue, 13 Feb 2024 21:31:58 -0500 Subject: [PATCH 4/4] make delete_user check for password --- happiness-backend/api/models/schema.py | 4 ++++ happiness-backend/api/routes/user.py | 10 ++++++++-- happiness-backend/tests/test_auth.py | 17 ++++++++++++----- 3 files changed, 24 insertions(+), 7 deletions(-) diff --git a/happiness-backend/api/models/schema.py b/happiness-backend/api/models/schema.py index 324b265..cf6aa88 100644 --- a/happiness-backend/api/models/schema.py +++ b/happiness-backend/api/models/schema.py @@ -246,3 +246,7 @@ class CountSchema(ma.Schema): class AmountSchema(ma.Schema): user_id = ma.Int() + + +class UserDeleteSchema(ma.Schema): + password = ma.Str(required=True) diff --git a/happiness-backend/api/routes/user.py b/happiness-backend/api/routes/user.py index 65f81a2..79b904d 100644 --- a/happiness-backend/api/routes/user.py +++ b/happiness-backend/api/routes/user.py @@ -7,6 +7,7 @@ from apifairy import authenticate, response, body, other_responses, arguments from flask import Blueprint from flask import current_app +from pip._internal import req from api.app import db from api.authentication.auth import token_current_user @@ -15,7 +16,7 @@ from api.models.models import User, Setting, Happiness, Journal from api.models.schema import UserSchema, CreateUserSchema, SettingsSchema, SettingInfoSchema, \ UserInfoSchema, PasswordResetReqSchema, SimpleUserSchema, EmptySchema, PasswordResetSchema, \ - FileUploadSchema, NumberSchema, AmountSchema, CountSchema + FileUploadSchema, NumberSchema, AmountSchema, CountSchema, UserDeleteSchema from api.routes.token import token_auth from api.util import email_methods from api.util.errors import failure_response @@ -89,12 +90,17 @@ def get_user_by_username(username): @user.delete('/') +@body(UserDeleteSchema) @authenticate(token_auth) -def delete_user(): +def delete_user(req): """ Delete User Deletes the user that is currently logged in, including all user data. + Requires that the user inputs their password before deleting their account. """ + if not token_current_user().verify_password(req.get("password")): + return failure_response("Incorrect Password", 401) + current_user = token_current_user() happiness_records = db.session.query(Happiness).filter_by(user_id=current_user.id).all() diff --git a/happiness-backend/tests/test_auth.py b/happiness-backend/tests/test_auth.py index 58ae3f7..5ccaaa6 100644 --- a/happiness-backend/tests/test_auth.py +++ b/happiness-backend/tests/test_auth.py @@ -250,8 +250,9 @@ def test_delete_user(client): bearer_token = json.loads(login_response.get_data()).get("session_token") assert bearer_token is not None - delete_res = client.delete( - '/api/user/', headers={"Authorization": f"Bearer {bearer_token}"}) + delete_res = client.delete('/api/user/', json={ + 'password': 'test', + }, headers={"Authorization": f"Bearer {bearer_token}"}) assert delete_res.status_code == 204 assert (get_user_by_email("text@example.com") is None and get_user_by_username("test") is None and get_user_by_id(1) is None) @@ -305,7 +306,9 @@ def test_delete_user_2(init_client): and get_user_by_id(3) is not None) delete_res = client.delete( - '/api/user/', headers={"Authorization": f"Bearer {tokens[2]}"}) + '/api/user/', json={ + 'password': 'test', + }, headers={"Authorization": f"Bearer {tokens[2]}"}) assert delete_res.status_code == 204 assert (get_user_by_email("test3@example.app") is None and get_user_by_username("user3") is None and get_user_by_id(3) is None) @@ -313,7 +316,9 @@ def test_delete_user_2(init_client): # deleting creator of group delete_res = client.delete( - '/api/user/', headers={"Authorization": f"Bearer {tokens[0]}"}) + '/api/user/', json={ + 'password': 'test', + }, headers={"Authorization": f"Bearer {tokens[0]}"}) assert delete_res.status_code == 204 assert (get_user_by_email("test1@example.app") is None and get_user_by_username("user1") is None and get_user_by_id(1) is None) @@ -360,7 +365,9 @@ def test_delete_user_2(init_client): assert len(happiness_records2) == 1 delete_res = client.delete( - '/api/user/', headers={"Authorization": f"Bearer {tokens[1]}"}) + '/api/user/', json={ + 'password': 'test', + }, headers={"Authorization": f"Bearer {tokens[1]}"}) assert delete_res.status_code == 204 assert (get_user_by_email("test2@example.app") is None and get_user_by_username("user2") is None and get_user_by_id(2) is None)