diff --git a/ChangeLog.rst b/ChangeLog.rst index 0c75c0cd3..bacd716ae 100644 --- a/ChangeLog.rst +++ b/ChangeLog.rst @@ -35,6 +35,7 @@ Deployment notes ✨ New features --------------- +* Wiki: Update metadata and content of related pages after a edit 🏗 Changes ---------- diff --git a/inyoka/wiki/management/commands/regenerate_metadata.py b/inyoka/wiki/management/commands/regenerate_metadata.py deleted file mode 100755 index f0593068c..000000000 --- a/inyoka/wiki/management/commands/regenerate_metadata.py +++ /dev/null @@ -1,38 +0,0 @@ -#!/usr/bin/env python -""" - inyoka.wiki.management.commands.regenerate_metadata - ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - - Allows to regenerate the MetaData for wiki pages with a specific tested tag. - - :copyright: (c) 2007-2024 by the Inyoka Team, see AUTHORS for more details. - :license: BSD, see LICENSE for more details. -""" - -from django.core.management.base import BaseCommand - -from inyoka.wiki.models import MetaData, Page - - -class Command(BaseCommand): - help = "Allows to regenerate the MetaData for wiki pages with a specific tested tag." - - def add_arguments(self, parser): - parser.add_argument('--tested-tag', - action='store', - dest='tested_tag', - help='Metadata for all wiki pages that have this tested tag will be regenerated.') - - def handle(self, *args, **options): - to_clean = [] - for d in MetaData.objects.filter(key="getestet", value=options['tested_tag']): - p = d.page - print(p) - p.update_meta() - to_clean.append(p.name) - - Page.objects.clean_cache(to_clean) - - # drop overview pages from the cache - Page.objects.get_by_name('Wiki/ungetestet').rev.text.remove_value_from_cache() - Page.objects.get_by_name('Wiki/nur_getestet_bionic').rev.text.remove_value_from_cache() diff --git a/inyoka/wiki/models.py b/inyoka/wiki/models.py index 01695ce30..ac9589924 100644 --- a/inyoka/wiki/models.py +++ b/inyoka/wiki/models.py @@ -988,6 +988,31 @@ def update_meta(self): continue MetaData(page=self, key=key, value=value[:MAX_METADATA]).save() + def update_related_pages(self, update_meta: bool=True) -> None: + """ + Removes the content of page from the cache and its related pages. + + It also updates the metadata of all pages. This is f.e. relevant for page + templates that emit tags. + + Intended to be run in a celery task. + """ + + related_pages = Page.objects.select_related('last_rev__text') \ + .filter(metadata__key__in=('X-Link', 'X-Attach'), + metadata__value=self.name) + + for p in related_pages: + cache.delete(f'wiki/page/{p.name.lower()}') + p.last_rev.text.remove_value_from_cache() + if update_meta: + p.update_meta() + + cache.delete(f'wiki/page/{self.name.lower()}') + self.last_rev.text.remove_value_from_cache() + if update_meta: + self.update_meta() + def save(self, update_meta=True, *args, **kwargs): """ This not only saves the page but also a revision that is @@ -1275,7 +1300,7 @@ class Revision(models.Model): `rendered_text`. user - The user that created this revision. If an anoymous user created + The user that created this revision. If an anonymous user created the revision this will be `None`. change_date diff --git a/inyoka/wiki/tasks.py b/inyoka/wiki/tasks.py index 54f9e6a54..0448ceccb 100644 --- a/inyoka/wiki/tasks.py +++ b/inyoka/wiki/tasks.py @@ -63,20 +63,10 @@ def update_page_by_slug(): @shared_task -def update_related_pages(page, update_meta=True): - from inyoka.wiki.models import MetaData, Page - page = Page.objects.get(id=page) - related_pages = set() - values = ('value', 'page__last_rev__text_id') - linked = MetaData.objects.values_list(*values) \ - .filter(key__in=('X-Link', 'X-Attach'), value=page.name) - for value, text_id in linked.all(): - cache.delete(f'wiki/page/{value.lower()}') - related_pages.add(text_id) - cache.delete(f'wiki/page/{page.name.lower()}') - - if update_meta: - page.update_meta() +def update_related_pages(page_id: int, update_meta: bool=True) -> None: + from inyoka.wiki.models import Page + page = Page.objects.get(id=page_id) + page.update_related_pages(update_meta=update_meta) @shared_task diff --git a/tests/apps/wiki/test_models.py b/tests/apps/wiki/test_models.py index 45e2a8ef0..b9b4d9795 100644 --- a/tests/apps/wiki/test_models.py +++ b/tests/apps/wiki/test_models.py @@ -12,6 +12,64 @@ BASE_PATH = path.dirname(__file__) +class TestPage(TestCase): + + def test_update_related_pages__content_updated(self): + """ + Test, that content of a embedder page will be updated. + """ + template = Page.objects.create('Wiki/Templates/template', 'Foo') + page = Page.objects.create('test1', '[:test1:] content [[Vorlage(template, "Hello World")]]') + + self.assertEqual(page.last_rev.text.value_rendered, + '
test1 content Foo
') + + # included `template` was changed + # `page` should have a different content, but it's yet not updated + template.edit('Bar', note='changed content') + self.assertEqual(page.last_rev.text.value_rendered, + 'test1 content Foo
') + + template.update_related_pages() + + self.assertEqual(page.last_rev.text.value_rendered, + 'test1 content Bar
') + + def test_update_related_pages__metadata_updated(self): + """ + Test, that metadata will be updated. + """ + template = Page.objects.create('Wiki/Templates/template', '#tag: untested') + page = Page.objects.create('test1', '[:test1:] content [[Vorlage(template, "Hello World")]]') + + self.assertEqual(len(page.metadata), 3) + self.assertEqual(page.metadata['X-Link'], ['test1']) + self.assertEqual(page.metadata['X-Attach'], ['Wiki/Templates/template']) + self.assertEqual(page.metadata['tag'], ['untested']) + + # included `template` was changed + # `page` should have a different metadata, but it's yet not updated + template.edit('# tag: foo', note='changed tag') + page = Page.objects.get(id=page.id) # defer of page.meta caches the metadata once we accessed it + self.assertEqual(len(page.metadata), 3) + self.assertEqual(page.metadata['tag'], ['untested']) + + template.update_related_pages() + page = Page.objects.get(id=page.id) # defer of page.meta caches the metadata once we accessed it + self.assertEqual(len(page.metadata), 3) + self.assertEqual(page.metadata['tag'], ['foo']) + + def test_update_related_pages__queries_used(self): + """ + Test, how many database queries are needed. + """ + template = Page.objects.create('Wiki/Templates/template', 'Foo') + Page.objects.create('test1', '[:test1:] content [[Vorlage(template, "Hello World")]]') + + with self.assertNumQueries(7): + template.update_related_pages() + + class TestPageManager(TestCase): def test_get_by_name_case_sensitive(self): """