async def test_change_password(self): user_id, password = await self._create_test_user( "user", "*****@*****.**") _, session_id, _ = await self.user_service.login_user( "user", password=password, session_name="session1") token = token_for_user(user_id, session_id, self.secret_key) headers = {"Authorization": f"Bearer {token}"} # check that we cannot change anything without providing the correct password resp = await self.client.post( f"/api/v1/profile/change_password", headers=headers, json={ "old_password": "******", "new_password": "******" }, ) self.assertEqual(400, resp.status) resp = await self.client.post( f"/api/v1/profile/change_password", headers=headers, json={ "old_password": password, "new_password": "******" }, ) self.assertEqual(204, resp.status) # check that we can login with the new password await self._login("user", "password2")
async def setUpAsync(self) -> None: await super().setUpAsync() self.test_user_id, password = await self._create_test_user( "user1", "*****@*****.**") _, session_id, _ = await self.user_service.login_user( "user1", password=password, session_name="session1") self.jwt_token = token_for_user(self.test_user_id, session_id, self.secret_key)
async def test_change_email(self): username = "******" old_email = "*****@*****.**" new_email = "*****@*****.**" user_id, password = await self._create_test_user(username, old_email) _, session_id, _ = await self.user_service.login_user( username=username, password=password, session_name="session1") token = token_for_user(user_id, session_id, self.secret_key) headers = {"Authorization": f"Bearer {token}"} resp = await self.client.post( f"/api/v1/profile/change_email", headers=headers, json={ "email": new_email, "password": password }, ) self.assertEqual(204, resp.status) resp = await self.client.post( f"/api/v1/profile/change_email", headers=headers, json={ "email": new_email, "password": "******" }, ) self.assertEqual(400, resp.status) resp = await self.client.get(f"/api/v1/profile", headers=headers) self.assertEqual(200, resp.status) profile = await resp.json() # we still have the old email self.assertEqual(old_email, profile["email"]) # confirm the email change # fetch the registration token from the database async with self.db_pool.acquire() as conn: token = await conn.fetchval( "select token from pending_email_change where user_id = $1", user_id) resp = await self.client.post(f"/api/v1/auth/confirm_email_change", json={"token": "foobar lol"}) self.assertEqual(400, resp.status) resp = await self.client.post(f"/api/v1/auth/confirm_email_change", json={"token": str(token)}) self.assertEqual(204, resp.status) # now we have the new email resp = await self.client.get(f"/api/v1/profile", headers=headers) self.assertEqual(200, resp.status) profile = await resp.json() # we still have the old email self.assertEqual(new_email, profile["email"])
async def test_websocket_notifications(self): user_id, password = await self._create_test_user( username="******", email="*****@*****.**") _, session_id, _ = await self.user_service.login_user( "user", password=password, session_name="session1") token = token_for_user(user_id, session_id=session_id, secret_key=self.secret_key) ws = await self.client.ws_connect("/api/v1/ws") self.assertIsNotNone(ws) await ws.send_json({ "type": "subscribe", "token": token, "data": { "subscription_type": "group", "element_id": user_id }, }) await self.expect_ws_message( ws, { "type": "subscribe_success", "data": { "element_id": user_id, "subscription_type": "group", }, }, ) group_id = await self.group_service.create_group( user_id=user_id, name="group1", description="asdf", currency_symbol="€", terms="terms...", ) # make sure we receive a notification on the group scope await self.expect_ws_message( ws, { "type": "notification", "data": { "element_id": user_id, "group_id": group_id, "subscription_type": "group", }, }, ) await ws.send_json({ "type": "subscribe", "token": token, "data": { "subscription_type": "account", "element_id": group_id }, }) await self.expect_ws_message( ws, { "type": "subscribe_success", "data": { "element_id": group_id, "subscription_type": "account", }, }, ) account_id = await self.account_service.create_account( user_id=user_id, group_id=group_id, type="personal", name="group1", description="asdf", ) await self.expect_ws_message( ws, { "type": "notification", "data": { "element_id": group_id, "account_id": account_id, "subscription_type": "account", }, }, ) # subscribe to transaction changes await ws.send_json({ "type": "subscribe", "token": token, "data": { "subscription_type": "transaction", "element_id": group_id }, }) await self.expect_ws_message( ws, { "type": "subscribe_success", "data": { "element_id": group_id, "subscription_type": "transaction", }, }, ) transaction_id = await self.transaction_service.create_transaction( user_id=user_id, group_id=group_id, type="transfer", value=1.2, currency_symbol="€", currency_conversion_rate=1.0, billed_at=date.today(), description="asdf", ) await self.expect_ws_message( ws, { "type": "notification", "data": { "element_id": group_id, "transaction_id": transaction_id, "subscription_type": "transaction", "deleted": False, "revision_committed": None, "revision_version": 0, }, }, ) # subscribe to group invite changes await ws.send_json({ "type": "subscribe", "token": token, "data": { "subscription_type": "group_invite", "element_id": group_id }, }) await self.expect_ws_message( ws, { "type": "subscribe_success", "data": { "element_id": group_id, "subscription_type": "group_invite", }, }, ) invite_id = await self.group_service.create_invite( user_id=user_id, group_id=group_id, description="foobar invite", single_use=False, valid_until=datetime.now() + timedelta(hours=4), join_as_editor=True, ) await self.expect_ws_message( ws, { "type": "notification", "data": { "element_id": group_id, "invite_id": invite_id, "subscription_type": "group_invite", }, }, ) await ws.send_json({ "type": "unsubscribe", "token": token, "data": { "subscription_type": "transaction", "element_id": group_id }, }) await self.expect_ws_message( ws, { "type": "unsubscribe_success", "data": { "element_id": group_id, "subscription_type": "transaction", }, }, ) await ws.send_json({ "type": "unsubscribe", "token": token, "data": { "subscription_type": "account", "element_id": group_id }, }) await self.expect_ws_message( ws, { "type": "unsubscribe_success", "data": { "element_id": group_id, "subscription_type": "account", }, }, ) await ws.send_json({ "type": "unsubscribe", "token": token, "data": { "subscription_type": "group", "element_id": user_id }, }) await self.expect_ws_message( ws, { "type": "unsubscribe_success", "data": { "element_id": user_id, "subscription_type": "group", }, }, )
async def test_delete_group(self): user2_id, user2_password = await self._create_test_user( "user2", "*****@*****.**") _, session_id, _ = await self.user_service.login_user( "user2", password=user2_password, session_name="foobar") user2_token = token_for_user(user2_id, session_id, self.secret_key) group_id = await self.group_service.create_group( user_id=self.test_user_id, name="foobar", description="foobar", currency_symbol="€", terms="foo", ) async with self.db_pool.acquire() as conn: await conn.execute( "insert into group_membership (user_id, group_id, is_owner, can_write) " "values ($1, $2, true, true)", user2_id, group_id, ) account1_id = await self.account_service.create_account( user_id=self.test_user_id, group_id=group_id, type="personal", name="account1", description="", ) account2_id = await self.account_service.create_account( user_id=self.test_user_id, group_id=group_id, type="personal", name="account2", description="", ) transaction_id = await self.transaction_service.create_transaction( user_id=self.test_user_id, group_id=group_id, type="purchase", description="asdf", billed_at=datetime.now(tz=timezone.utc), currency_symbol="€", currency_conversion_rate=1.0, value=20.0, debitor_shares={account1_id: 1.0}, creditor_shares={account2_id: 1.0}, ) resp = await self._delete(f"/api/v1/groups/{group_id}") self.assertEqual(403, resp.status) resp = await self._post(f"/api/v1/groups/{group_id}/leave") self.assertEqual(204, resp.status) await self._fetch_group(group_id, expected_status=404) resp = await self.client.delete( f"/api/v1/groups/{group_id}", headers={"Authorization": f"Bearer {user2_token}"}, ) self.assertEqual(204, resp.status) async with self.db_pool.acquire() as conn: gid = await conn.fetchval("select id from grp where grp.id = $1", group_id) self.assertIsNone(gid)
async def test_invites(self): group_id = await self.group_service.create_group( user_id=self.test_user_id, name="group1", description="description", currency_symbol="€", terms="terms", ) resp = await self._post( f"/api/v1/groups/{group_id}/invites", json={ "description": "description", "single_use": False, "join_as_editor": False, "valid_until": (datetime.now() + timedelta(hours=1)).isoformat(), }, ) self.assertEqual(204, resp.status) resp = await self._get(f"/api/v1/groups/{group_id}/invites") self.assertEqual(200, resp.status) invites = await resp.json() self.assertEqual(1, len(invites)) # we hardcode assume the invite id is 0 to check if the id counting works as expected resp = await self._delete( f"/api/v1/groups/{group_id}/invites/{invites[0]['id']}") self.assertEqual(204, resp.status) resp = await self._get(f"/api/v1/groups/{group_id}/invites") self.assertEqual(200, resp.status) invites = await resp.json() self.assertEqual(0, len(invites)) # now check that we can actually preview the group as a different user resp = await self._post( f"/api/v1/groups/{group_id}/invites", json={ "description": "description", "single_use": True, "join_as_editor": True, "valid_until": (datetime.now() + timedelta(hours=1)).isoformat(), }, ) self.assertEqual(204, resp.status) resp = await self._get(f"/api/v1/groups/{group_id}/invites") self.assertEqual(200, resp.status) invites = await resp.json() self.assertEqual(1, len(invites)) invite_token = invites[0]["token"] self.assertIsNotNone(invite_token) user2_id, password = await self._create_test_user( "user", "*****@*****.**") _, session_id, _ = await self.user_service.login_user( "user", password=password, session_name="session1") jwt_token = token_for_user(user2_id, session_id=session_id, secret_key=self.secret_key) resp = await self.client.post( f"/api/v1/groups/preview", json={"invite_token": invite_token}, headers={"Authorization": f"Bearer {jwt_token}"}, ) self.assertEqual(200, resp.status) prev_group_data = await resp.json() self.assertEqual("group1", prev_group_data["name"]) self.assertEqual(group_id, prev_group_data["id"]) resp = await self.client.post( f"/api/v1/groups/join", json={"invite_token": invite_token}, headers={"Authorization": f"Bearer {jwt_token}"}, ) self.assertEqual(204, resp.status) resp = await self.client.get( f"/api/v1/groups", headers={"Authorization": f"Bearer {jwt_token}"}, ) self.assertEqual(200, resp.status) groups = await resp.json() self.assertEqual(1, len(groups)) resp = await self._get(f"/api/v1/groups/{group_id}/invites") self.assertEqual(200, resp.status) invites = await resp.json() self.assertEqual(0, len(invites)) resp = await self._get(f"/api/v1/groups/{group_id}/logs") self.assertEqual(200, resp.status) logs = await resp.json() self.assertEqual(6, len(logs)) self.assertEqual( { "group-created", "member-joined", "invite-created", "invite-deleted" }, set([log["type"] for log in logs]), )