Remove mastodon posts on delete and OTP
This commit is contained in:
@@ -273,7 +273,50 @@ def test_admin_can_remove_user_with_owned_data():
|
||||
|
||||
removed = client.delete(f'/api/admin/users/{user_id}', headers=headers)
|
||||
assert removed.status_code == 200
|
||||
assert client.get('/api/auth/me', params={'token': user_headers['Authorization'].removeprefix('Bearer ')}).status_code == 401
|
||||
assert client.get('/api/auth/me', params={'token': user_token}).status_code == 401
|
||||
|
||||
|
||||
def test_deleting_link_removes_all_mastodon_posts_first():
|
||||
owner_headers = login_headers('alice')
|
||||
created = client.post('/api/links', headers=owner_headers, json={
|
||||
'title': 'Remote cleanup',
|
||||
'url': 'https://example.com/remote-cleanup',
|
||||
})
|
||||
assert created.status_code == 201
|
||||
link_id = created.json()['id']
|
||||
with get_connection() as conn:
|
||||
conn.execute(
|
||||
'UPDATE links SET mastodon_posted = 1, mastodon_post_id = ?, mastodon_post_ids = ? WHERE id = ?',
|
||||
('post-2', json.dumps(['post-1', 'post-2']), link_id),
|
||||
)
|
||||
conn.commit()
|
||||
|
||||
with patch('backend.app.api.links.plugin_manager.delete_mastodon_posts', return_value={'status': 'deleted', 'count': 2}) as delete_posts:
|
||||
deleted = client.delete(f'/api/links/{link_id}', headers=owner_headers)
|
||||
assert deleted.status_code == 200
|
||||
delete_posts.assert_called_once()
|
||||
assert delete_posts.call_args.args[0]['mastodon_post_ids'] == ['post-1', 'post-2']
|
||||
assert client.delete(f'/api/links/{link_id}', headers=owner_headers).status_code == 404
|
||||
|
||||
|
||||
def test_link_is_kept_when_mastodon_cleanup_fails():
|
||||
owner_headers = login_headers('alice')
|
||||
created = client.post('/api/links', headers=owner_headers, json={
|
||||
'title': 'Failed remote cleanup',
|
||||
'url': 'https://example.com/failed-remote-cleanup',
|
||||
})
|
||||
link_id = created.json()['id']
|
||||
with get_connection() as conn:
|
||||
conn.execute(
|
||||
'UPDATE links SET mastodon_posted = 1, mastodon_post_id = ?, mastodon_post_ids = ? WHERE id = ?',
|
||||
('post-failed', json.dumps(['post-failed']), link_id),
|
||||
)
|
||||
conn.commit()
|
||||
with patch('backend.app.api.links.plugin_manager.delete_mastodon_posts', return_value={'status': 'failed', 'reason': 'remote refused'}):
|
||||
deleted = client.delete(f'/api/links/{link_id}', headers=owner_headers)
|
||||
assert deleted.status_code == 502
|
||||
assert 'remote refused' in deleted.json()['detail']
|
||||
assert client.get('/api/links').json()
|
||||
|
||||
|
||||
def test_admin_can_toggle_privileges_without_removing_last_admin():
|
||||
|
||||
@@ -10,7 +10,7 @@ def test_database_migrations_are_versioned_and_idempotent():
|
||||
connection = sqlite3.connect(':memory:')
|
||||
|
||||
apply_migrations(connection)
|
||||
assert get_schema_version(connection) == 9
|
||||
assert get_schema_version(connection) == 11
|
||||
tables = {
|
||||
row[0]
|
||||
for row in connection.execute(
|
||||
@@ -27,6 +27,6 @@ def test_database_migrations_are_versioned_and_idempotent():
|
||||
assert set(DEFAULT_TAGS) <= seeded_tags
|
||||
|
||||
apply_migrations(connection)
|
||||
assert get_schema_version(connection) == 9
|
||||
assert get_schema_version(connection) == 11
|
||||
|
||||
connection.close()
|
||||
@@ -4,6 +4,7 @@
|
||||
from fastapi.testclient import TestClient
|
||||
|
||||
from backend.app.main import app
|
||||
from backend.app.services.otp_service import current_code
|
||||
|
||||
|
||||
client = TestClient(app)
|
||||
@@ -75,3 +76,30 @@ def test_user_config_api_and_profile_page():
|
||||
|
||||
updated_profile = client.get('/api/user/me', headers=headers).json()
|
||||
assert updated_profile['avatar_url'] == avatar_url
|
||||
|
||||
|
||||
def test_user_can_enable_and_use_otp():
|
||||
login = client.post('/api/auth/login', json={'username': 'alice', 'password': 'secret123'}).json()
|
||||
headers = {'Authorization': f"Bearer {login['access_token']}"}
|
||||
setup = client.post('/api/user/otp/setup', headers=headers)
|
||||
assert setup.status_code == 200
|
||||
secret = setup.json()['secret']
|
||||
assert setup.json()['otpauth_url'].startswith('otpauth://totp/')
|
||||
|
||||
enabled = client.post('/api/user/otp', headers=headers, json={
|
||||
'action': 'enable', 'code': current_code(secret),
|
||||
})
|
||||
assert enabled.status_code == 200
|
||||
assert enabled.json()['enabled'] is True
|
||||
assert client.post('/api/auth/login', json={'username': 'alice', 'password': 'secret123'}).status_code == 401
|
||||
|
||||
otp_login = client.post('/api/auth/login', json={
|
||||
'username': 'alice', 'password': 'secret123', 'otp': current_code(secret),
|
||||
})
|
||||
assert otp_login.status_code == 200
|
||||
|
||||
disabled = client.post('/api/user/otp', headers=headers, json={
|
||||
'action': 'disable', 'code': current_code(secret),
|
||||
})
|
||||
assert disabled.status_code == 200
|
||||
assert disabled.json()['enabled'] is False
|
||||
|
||||
Reference in New Issue
Block a user