Tag functionality added
This commit is contained in:
@@ -111,6 +111,42 @@ def test_submit_link_stores_cleaned_url_and_public_feed():
|
||||
assert 'alice' in users_response.json()
|
||||
|
||||
|
||||
def test_links_support_tags_and_tag_filtering():
|
||||
headers = login_headers()
|
||||
response = client.post('/api/links', headers=headers, json={
|
||||
'title': 'Tagged page',
|
||||
'url': 'https://example.com/tagged',
|
||||
'tags': ['#CasePreserved', '#web', 'casepreserved'],
|
||||
})
|
||||
assert response.status_code == 201
|
||||
link_id = response.json()['id']
|
||||
assert response.json()['tags'] == ['#CasePreserved', '#web']
|
||||
|
||||
tags = client.get('/api/tags').json()
|
||||
assert any(tag.casefold() == '#casepreserved' for tag in tags) and '#web' in tags
|
||||
assert {
|
||||
'#Internet', '#Cybersecurity', '#Fediverse', '#Food', '#Photography', '#Music', '#AI'
|
||||
} <= set(tags)
|
||||
tagged_feed = client.get('/api/public/feed').json()
|
||||
tagged_item = next(item for item in tagged_feed if item['id'] == link_id)
|
||||
assert {tag.casefold() for tag in tagged_item['tags']} == {'#casepreserved', '#web'}
|
||||
|
||||
too_many = client.post('/api/links', headers=headers, json={
|
||||
'title': 'Too many tags',
|
||||
'url': 'https://example.com/too-many',
|
||||
'tags': [f'tag-{index}' for index in range(11)],
|
||||
})
|
||||
assert too_many.status_code == 422
|
||||
|
||||
edited = client.put(f'/api/links/{link_id}', headers=headers, json={
|
||||
'title': 'Tagged page',
|
||||
'url': 'https://example.com/tagged',
|
||||
'tags': ['edited'],
|
||||
})
|
||||
assert edited.status_code == 200
|
||||
assert edited.json()['tags'] == ['#edited']
|
||||
|
||||
|
||||
def test_only_link_owner_can_edit_link():
|
||||
owner_headers = login_headers('alice')
|
||||
response = client.post('/api/links', headers=owner_headers, json={
|
||||
@@ -180,6 +216,7 @@ def test_public_and_admin_pages_render_html():
|
||||
assert 'id="auth-login-button" href="/login"' in root_page.text
|
||||
assert 'id="auth-profile-link" class="hidden"' in root_page.text
|
||||
assert 'id="auth-admin-link" class="hidden"' in root_page.text
|
||||
assert '<select id="tag-filter">' in root_page.text
|
||||
assert 'logout.js?v=3' in root_page.text
|
||||
assert client.get('/alice').status_code == 200
|
||||
assert client.get('/alice/').status_code == 200
|
||||
@@ -203,8 +240,13 @@ def test_public_and_admin_pages_render_html():
|
||||
assert 'id="auth-home-link" href="/">Home</a>' in admin_page
|
||||
assert '<a id="auth-username" class="user-name" href="/">' in admin_page
|
||||
assert 'admin.js?v=3' in admin_page
|
||||
feed_script = client.get('/static/feed.js?v=5').text
|
||||
feed_script = client.get('/static/feed.js?v=7').text
|
||||
assert 'if (item.is_owner)' in feed_script
|
||||
assert 'tag.toLowerCase() === pref.tag.toLowerCase()' in feed_script
|
||||
assert 'return `${date.getFullYear()} ${months[date.getMonth()]} ${date.getDate()} - ${hours}:${minutes}`' in feed_script
|
||||
assert 'edit-tag-options' in feed_script
|
||||
assert 'new_tags' in feed_script
|
||||
assert 'A link can have at most 10 tags.' in feed_script
|
||||
|
||||
|
||||
def test_link_submission_posts_to_enabled_mastodon_plugin():
|
||||
@@ -240,13 +282,14 @@ def test_link_submission_posts_to_enabled_mastodon_plugin():
|
||||
'title': 'A useful page',
|
||||
'url': 'https://example.com/useful',
|
||||
'comment': 'Worth sharing',
|
||||
'tags': ['#python', '#web'],
|
||||
})
|
||||
|
||||
assert response.status_code == 201
|
||||
assert received['path'] == '/api/v1/statuses'
|
||||
assert received['authorization'] == 'Bearer test-token'
|
||||
assert received['body'] == {
|
||||
'status': 'A useful page\nWorth sharing\nFrom my #LinkLog: "https://example.com/useful',
|
||||
'status': 'A useful page\nWorth sharing\nFrom my #LinkLog: "https://example.com/useful #python #web',
|
||||
}
|
||||
finally:
|
||||
server.shutdown()
|
||||
|
||||
@@ -1,22 +1,27 @@
|
||||
import sqlite3
|
||||
|
||||
from backend.app.database import apply_migrations, get_schema_version
|
||||
from backend.app.database import DEFAULT_TAGS, apply_migrations, get_schema_version, seed_default_tags
|
||||
|
||||
|
||||
def test_database_migrations_are_versioned_and_idempotent():
|
||||
connection = sqlite3.connect(':memory:')
|
||||
|
||||
apply_migrations(connection)
|
||||
assert get_schema_version(connection) == 1
|
||||
assert get_schema_version(connection) == 3
|
||||
tables = {
|
||||
row[0]
|
||||
for row in connection.execute(
|
||||
"SELECT name FROM sqlite_master WHERE type = 'table'"
|
||||
)
|
||||
}
|
||||
assert {'users', 'tokens', 'links', 'plugins', 'user_plugin_config'} <= tables
|
||||
assert {
|
||||
'users', 'tokens', 'links', 'plugins', 'user_plugin_config', 'tags', 'link_tags'
|
||||
} <= tables
|
||||
seed_default_tags(connection)
|
||||
seeded_tags = {row[0] for row in connection.execute('SELECT name FROM tags')}
|
||||
assert set(DEFAULT_TAGS) <= seeded_tags
|
||||
|
||||
apply_migrations(connection)
|
||||
assert get_schema_version(connection) == 1
|
||||
assert get_schema_version(connection) == 3
|
||||
|
||||
connection.close()
|
||||
Reference in New Issue
Block a user