Improve collection editing and rendering

This commit is contained in:
rucki
2026-08-30 13:05:57 +02:00
parent 5aeb12899b
commit d5917d411a
5 changed files with 172 additions and 14 deletions
+92 -4
View File
@@ -2,8 +2,8 @@ from django.contrib.auth import get_user_model
from django.test import TestCase
from django.urls import reverse
from .models import Collection, CollectionSection, Item, Tag, Team, TeamMembership, UserPreference
from .templatetags.markdown_extras import markdown
from .models import ApiKey, Collection, CollectionSection, Item, Tag, Team, TeamMembership, UserPreference
from .templatetags.markdown_extras import markdown, markdown_title
from .views import parse_due_command, parse_quick_content
@@ -98,15 +98,25 @@ class MarkdownHeadingTests(TestCase):
def test_heading_with_space_remains_a_heading(self):
self.assertIn('<h1>Project</h1>', str(markdown('# Project')))
self.assertIn('<h2>Section</h2>', str(markdown('## Section')))
def test_hash_in_fenced_code_is_unchanged(self):
rendered = str(markdown('```python\n# comment\n```'))
self.assertIn('# comment', rendered)
self.assertNotIn('\\# comment', rendered)
self.assertNotIn('<h1>', rendered)
def test_hash_in_inline_code_is_not_a_heading(self):
rendered = str(markdown('```# Das ist Kommentar im Code```'))
self.assertIn('<code># Das ist Kommentar im Code</code>', rendered)
self.assertNotIn('<h1>', rendered)
def test_underline_is_allowed(self):
self.assertIn('<u>underlined</u>', str(markdown('<u>underlined</u>')))
def test_markdown_title_strips_heading_marker(self):
self.assertEqual(markdown_title('## Ziel von my2dos\n\nText'), 'Ziel von my2dos')
class FormattingToolbarTests(TestCase):
def test_toolbar_and_shortcuts_are_available(self):
@@ -179,6 +189,21 @@ class TeamItemEditTests(TestCase):
response = self.client.get(reverse('item_editor', args=[item.id]))
self.assertContains(response, '<option value="team" selected>', html=False)
def test_team_item_can_be_made_public_even_with_team_tag(self):
item = Item.objects.create(
owner=self.user, team=self.team, content='Original #docs', visibility=Item.Visibility.TEAM,
)
item.sync_metadata()
response = self.client.post(reverse('item_editor', args=[item.id]), {
'content': 'Updated #docs', 'comment': '', 'visibility': Item.Visibility.PUBLIC, 'url': '',
})
self.assertRedirects(response, item.get_absolute_url())
item.refresh_from_db()
self.assertEqual(item.visibility, Item.Visibility.PUBLIC)
self.assertIsNone(item.team)
class CollectionTests(TestCase):
def setUp(self):
@@ -274,8 +299,10 @@ class CollectionTests(TestCase):
response = self.client.get(collection.get_absolute_url())
html = response.content.decode()
self.assertContains(response, 'Tag-Sammlung')
self.assertLess(html.index('First #guide'), html.index('Second #guide'))
self.assertNotContains(response, 'Ignored #guide')
self.assertLess(html.index('First'), html.index('Second'))
self.assertNotContains(response, 'First #guide')
self.assertNotContains(response, 'Second #guide')
self.assertNotContains(response, 'Ignored')
self.assertContains(response, reverse('collection_edit', args=[collection.id]))
self.assertNotContains(response, reverse('collection_manage', args=[collection.id]))
@@ -294,6 +321,26 @@ class CollectionTests(TestCase):
self.assertNotContains(response, 'Add existing note')
self.assertNotContains(response, 'section_id')
def test_collection_reading_view_hides_note_tags(self):
collection = Collection.objects.create(owner=self.user, title='Reading view')
note = Item.objects.create(owner=self.user, kind=Item.Kind.NOTE, content='## Section #tutorial\nText #my2dos and `#code`')
CollectionSection.objects.create(collection=collection, item=note, position=0)
response = self.client.get(collection.get_absolute_url())
self.assertContains(response, '<h2>Section</h2>', html=True)
self.assertContains(response, '<code>#code</code>', html=True)
self.assertNotContains(response, '#tutorial')
self.assertNotContains(response, '#my2dos')
def test_collection_manage_links_note_editor_back_to_collection(self):
collection = Collection.objects.create(owner=self.user, title='Reading view')
note = Item.objects.create(owner=self.user, kind=Item.Kind.NOTE, content='## Section')
CollectionSection.objects.create(collection=collection, item=note, position=0)
manage_url = reverse('collection_manage', args=[collection.id])
response = self.client.get(manage_url)
self.assertContains(response, f'{reverse("item_editor", args=[note.id])}?next={manage_url}')
self.assertContains(response, '>Section</')
self.assertNotContains(response, '>## Section</')
def test_public_collection_is_visible_without_login(self):
collection = Collection.objects.create(owner=self.user, title='Public', visibility=Item.Visibility.PUBLIC)
self.client.logout()
@@ -325,6 +372,47 @@ class CollectionTests(TestCase):
self.assertEqual(note.visibility, Item.Visibility.PUBLIC)
class ApiItemFilterTests(TestCase):
def setUp(self):
self.user = get_user_model().objects.create_user(username='api-filter', password='secret')
self.help_tag = Tag.objects.create(name='help')
self.api_key = ApiKey.objects.create(owner=self.user, name='Help CLI')
self.api_key.tags.add(self.help_tag)
def create_item(self, content):
item = Item.objects.create(owner=self.user, content=content)
item.sync_metadata()
return item
def test_api_key_scope_and_request_tags_are_combined(self):
matching = self.create_item('Keyboard shortcuts #help #tasten')
self.create_item('Git help #help #git')
self.create_item('Private keyboard note #tasten')
response = self.client.get(
reverse('api_items'), {'tag': 'tasten', 'tag_mode': 'all'},
HTTP_X_API_KEY=self.api_key.token,
)
self.assertEqual(response.status_code, 200)
ids = [item['id'] for item in response.json()['items']]
self.assertEqual(ids, [matching.id])
def test_api_items_supports_limit_and_search(self):
self.create_item('First #help #shell')
second = self.create_item('Second #help #shell keyboard')
response = self.client.get(
reverse('api_items'), {'tag': 'shell', 'q': 'keyboard', 'limit': '1'},
HTTP_X_API_KEY=self.api_key.token,
)
self.assertEqual(response.status_code, 200)
items = response.json()['items']
self.assertEqual(len(items), 1)
self.assertEqual(items[0]['id'], second.id)
class CopyButtonTests(TestCase):
def test_item_has_copy_button_with_original_text(self):
user = get_user_model().objects.create_user(username='tester', password='secret')