From eb19163c1f8c3a3cc2cb8907eab5c4ba20eddf6c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cyrill=20K=C3=BCttel?= Date: Tue, 5 Mar 2024 09:29:18 +0100 Subject: [PATCH 1/7] add code for meta and content --- src/onegov/org/management.py | 60 ++++++++++++++++++++++--- tests/onegov/org/test_views_settings.py | 28 ++++++++++++ 2 files changed, 81 insertions(+), 7 deletions(-) diff --git a/src/onegov/org/management.py b/src/onegov/org/management.py index 72d802b06d..03e4a1a15f 100644 --- a/src/onegov/org/management.py +++ b/src/onegov/org/management.py @@ -5,17 +5,20 @@ import transaction from aiohttp import ClientTimeout from sqlalchemy.orm import object_session +from sqlalchemy.ext.declarative import declared_attr from urlextract import URLExtract +from inspect import getmembers, isfunction from onegov.async_http.fetch import async_aiohttp_get_all +from onegov.core.orm.mixins import ContentMixin from onegov.core.utils import normalize_for_url from onegov.org.models import SiteCollection from onegov.people import AgencyCollection -from typing import Literal, NamedTuple, TYPE_CHECKING +from typing import Literal, NamedTuple, TYPE_CHECKING, Any, Callable if TYPE_CHECKING: - from collections.abc import Iterable, Iterator, Sequence + from collections.abc import Iterable, Sequence from onegov.form import Form from onegov.org.request import OrgRequest from onegov.page import Page @@ -57,7 +60,7 @@ def __init__( def migrate_url( self, item: object, - fields: 'Iterable[str]', + fields_with_urls: 'Iterable[str]', test: bool = False, group_by: str | None = None, count_obj: dict[str, dict[str, int]] | None = None @@ -73,6 +76,7 @@ def migrate_url( group_by = group_by or item.__class__.__name__ def repl(matchobj: re.Match[str]) -> str: + # replaces it with a new URI. if self.use_domain: return f'{matchobj.group(1)}{new_uri}' return new_uri @@ -83,7 +87,43 @@ def repl(matchobj: re.Match[str]) -> str: else: pattern = re.compile(re.escape(old_uri)) - for field in fields: + def content_mixin_declared_attrs( + members: list[tuple['str', 'Any']] + ) -> 'Iterable[tuple[str, Callable]]': + # don't be overly specific, we might add additional fields in + # the future + def predicate(member: tuple[str, Callable]) -> bool: + name, attr = member + return ( + isinstance(attr, declared_attr) + and name in ContentMixin.__dict__ + ) + + return filter(predicate, members) + + # Migrate `meta` and `content`: + if isinstance(item, ContentMixin): + for name, attribute in content_mixin_declared_attrs( + getmembers(item, isfunction) + ): + meta_or_content = getattr(item, name, None) + if meta_or_content is None: + continue + # breakpoitn + for key, v in meta_or_content: ## key might be 'lead' 'text' + new_val = pattern.sub(repl, v) + if v != new_val: + occurrences = len(pattern.findall(v)) + count += occurrences + id_count = count_by_id.setdefault(group_by, defaultdict(int)) + id_count[meta_or_content] += occurrences + + try: + item.name[key] = new_val + except AttributeError: + pass + + for field in fields_with_urls: value = getattr(item, field, None) if not value: continue @@ -92,8 +132,8 @@ def repl(matchobj: re.Match[str]) -> str: count += 1 id_count = count_by_id.setdefault( group_by, - defaultdict(int) ) + defaultdict(int) id_count[field] += 1 if not test: @@ -112,10 +152,16 @@ def migrate_site_collection( grouped: dict[str, dict[str, int]] = {} total = 0 + simple_count = 0 for name, entries in self.site_collection.get().items(): - for item in entries: + for _ in entries: + simple_count += 1 + breakpoint() + + for name, entries in self.site_collection.get().items(): + for entry in entries: count, grouped_count = self.migrate_url( - item, self.fields_with_urls, + entry, self.fields_with_urls, test=test, count_obj=grouped ) diff --git a/tests/onegov/org/test_views_settings.py b/tests/onegov/org/test_views_settings.py index 1443536c80..8cf90906a0 100644 --- a/tests/onegov/org/test_views_settings.py +++ b/tests/onegov/org/test_views_settings.py @@ -1,6 +1,7 @@ from onegov.api.models import ApiKey from onegov.org.theme.org_theme import HELVETICA from xml.etree.ElementTree import tostring +from onegov.org.models import SiteCollection def test_settings(client): @@ -143,3 +144,30 @@ def test_switch_languages(client): assert 'Tedesco' in page assert 'Allemand' not in page assert 'Deutsch' not in page + + +def test_migrate_links(client): + session = client.app.session() + + sitecollection = SiteCollection(session) + objects = sitecollection.get() + + # pages = client.app.session().query(Topic).defer(Topic.) + # topics = session.query(Topic) + # + # topics = topics.options(defer(Topic.meta)) + # topics = topics.options(defer(Topic.content)) + # topics = topics.options(defer(Topic.order)) + + client.login_admin() + page = client.get('/migrate-links') + assert ( + 'Migriert Links von der angegebenen Domain zur aktuellen Domain ' + '"localhost"' in page + ) + + # migrate from 'localhost' to 127.0.0.1 + # (pointless but enough for test) + page.form['old_domain'] = '127.0.0.1' + page.form.submit() + page.showbrowser() From 8f9a16aa7621a7d7262563cacbd849b9e87832a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cyrill=20K=C3=BCttel?= Date: Tue, 12 Mar 2024 10:35:01 +0100 Subject: [PATCH 2/7] wip --- src/onegov/org/management.py | 62 +++++++++++++++++------------------- 1 file changed, 30 insertions(+), 32 deletions(-) diff --git a/src/onegov/org/management.py b/src/onegov/org/management.py index 03e4a1a15f..6f0f034f3d 100644 --- a/src/onegov/org/management.py +++ b/src/onegov/org/management.py @@ -4,6 +4,7 @@ import transaction from aiohttp import ClientTimeout +from sqlalchemy.ext.mutable import MutableDict from sqlalchemy.orm import object_session from sqlalchemy.ext.declarative import declared_attr from urlextract import URLExtract @@ -87,41 +88,39 @@ def repl(matchobj: re.Match[str]) -> str: else: pattern = re.compile(re.escape(old_uri)) - def content_mixin_declared_attrs( - members: list[tuple['str', 'Any']] - ) -> 'Iterable[tuple[str, Callable]]': - # don't be overly specific, we might add additional fields in - # the future - def predicate(member: tuple[str, Callable]) -> bool: - name, attr = member - return ( - isinstance(attr, declared_attr) - and name in ContentMixin.__dict__ - ) - - return filter(predicate, members) + def predicate(attr) -> bool: + return isinstance(attr, MutableDict) # Migrate `meta` and `content`: if isinstance(item, ContentMixin): - for name, attribute in content_mixin_declared_attrs( - getmembers(item, isfunction) - ): - meta_or_content = getattr(item, name, None) - if meta_or_content is None: + kv = getmembers(item, predicate) + + if len(kv) > 2: + breakpoint() + + kv: list[tuple[str, MutableDict]] + for el in kv: + if not el: continue - # breakpoitn - for key, v in meta_or_content: ## key might be 'lead' 'text' - new_val = pattern.sub(repl, v) - if v != new_val: - occurrences = len(pattern.findall(v)) - count += occurrences - id_count = count_by_id.setdefault(group_by, defaultdict(int)) - id_count[meta_or_content] += occurrences - - try: - item.name[key] = new_val - except AttributeError: - pass + + if len(el) != 2: + breakpoint() + + if el[0] == 'content' or el[0] == 'meta' and el[1]: + meta_or_content = el[1] + + for key, v in meta_or_content: + new_val = pattern.sub(repl, v) + if v != new_val: + occurrences = len(pattern.findall(v)) + count += occurrences + id_count = count_by_id.setdefault(group_by, defaultdict(int)) + id_count[meta_or_content] += occurrences + + try: + item.name[key] = new_val + except AttributeError: + pass for field in fields_with_urls: value = getattr(item, field, None) @@ -156,7 +155,6 @@ def migrate_site_collection( for name, entries in self.site_collection.get().items(): for _ in entries: simple_count += 1 - breakpoint() for name, entries in self.site_collection.get().items(): for entry in entries: From d89df85f19fb8feda2f48302048c5a87dc999ecb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cyrill=20K=C3=BCttel?= Date: Tue, 12 Mar 2024 14:31:32 +0100 Subject: [PATCH 3/7] Wip [skip ci] --- src/onegov/org/management.py | 44 +++++++++++++++++++++++++++--------- 1 file changed, 33 insertions(+), 11 deletions(-) diff --git a/src/onegov/org/management.py b/src/onegov/org/management.py index 6f0f034f3d..f9e16c172e 100644 --- a/src/onegov/org/management.py +++ b/src/onegov/org/management.py @@ -17,7 +17,7 @@ from onegov.people import AgencyCollection -from typing import Literal, NamedTuple, TYPE_CHECKING, Any, Callable +from typing import Literal, NamedTuple, TYPE_CHECKING, Iterator if TYPE_CHECKING: from collections.abc import Iterable, Sequence from onegov.form import Form @@ -77,7 +77,7 @@ def migrate_url( group_by = group_by or item.__class__.__name__ def repl(matchobj: re.Match[str]) -> str: - # replaces it with a new URI. + # replaces it with a new URI. if self.use_domain: return f'{matchobj.group(1)}{new_uri}' return new_uri @@ -89,33 +89,55 @@ def repl(matchobj: re.Match[str]) -> str: pattern = re.compile(re.escape(old_uri)) def predicate(attr) -> bool: + nonlocal item return isinstance(attr, MutableDict) + # todo: can it be an iterable which contains MUtableDict? + + # todo: refactor away from getmembers() + # this fails in some rare edge cases # Migrate `meta` and `content`: if isinstance(item, ContentMixin): - kv = getmembers(item, predicate) - - if len(kv) > 2: - breakpoint() + try: + kv = getmembers(item, predicate) + except NotImplementedError: + print('notimplementeed') + cal = "calendar_date_range" + # go with pdb into predicate and check for + try: + kv = getmembers(item, predicate) + breakpoint() + except Exception: + breakpoint() + # if len(kv) > 2: + # breakpoint() kv: list[tuple[str, MutableDict]] for el in kv: if not el: continue + attribute_name = el[0] + if attribute_name not in ContentMixin.__dict__: + continue + if attribute_name == 'calendar_date_range': + breakpoint() if len(el) != 2: breakpoint() if el[0] == 'content' or el[0] == 'meta' and el[1]: - meta_or_content = el[1] - - for key, v in meta_or_content: + content = el[1] + for key, v in content.items(): # key might be 'lead' + # 'text', 'people' etc. + if not isinstance(v, str) or not v: + continue new_val = pattern.sub(repl, v) if v != new_val: + breakpoint() + # get number of replacements so the count is + # correct occurrences = len(pattern.findall(v)) count += occurrences - id_count = count_by_id.setdefault(group_by, defaultdict(int)) - id_count[meta_or_content] += occurrences try: item.name[key] = new_val From d154ec99e3b24eb6cdfd36c70396d6d57089766d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cyrill=20K=C3=BCttel?= Date: Tue, 8 Oct 2024 04:12:50 +0200 Subject: [PATCH 4/7] Add simpler way of migrating these links --- src/onegov/org/cli.py | 2 +- src/onegov/org/management.py | 128 +++++++++++++++---------------- src/onegov/org/views/settings.py | 2 +- 3 files changed, 63 insertions(+), 69 deletions(-) diff --git a/src/onegov/org/cli.py b/src/onegov/org/cli.py index c52c674239..d6b4d22de3 100644 --- a/src/onegov/org/cli.py +++ b/src/onegov/org/cli.py @@ -847,7 +847,7 @@ def execute(request: 'OrgRequest', app: 'OrgApp') -> None: else: new_uri = request.domain migration = LinkMigration(request, old_uri=old_uri, new_uri=new_uri) - total, grouped_count = migration.migrate_site_collection( + total, grouped_count = migration.migrate( test=dry_run ) diff --git a/src/onegov/org/management.py b/src/onegov/org/management.py index f9e16c172e..8582dd7fb8 100644 --- a/src/onegov/org/management.py +++ b/src/onegov/org/management.py @@ -1,17 +1,12 @@ import re import time from collections import defaultdict - import transaction from aiohttp import ClientTimeout -from sqlalchemy.ext.mutable import MutableDict from sqlalchemy.orm import object_session -from sqlalchemy.ext.declarative import declared_attr from urlextract import URLExtract -from inspect import getmembers, isfunction - +from sqlalchemy import text, bindparam from onegov.async_http.fetch import async_aiohttp_get_all -from onegov.core.orm.mixins import ContentMixin from onegov.core.utils import normalize_for_url from onegov.org.models import SiteCollection from onegov.people import AgencyCollection @@ -77,7 +72,6 @@ def migrate_url( group_by = group_by or item.__class__.__name__ def repl(matchobj: re.Match[str]) -> str: - # replaces it with a new URI. if self.use_domain: return f'{matchobj.group(1)}{new_uri}' return new_uri @@ -88,62 +82,6 @@ def repl(matchobj: re.Match[str]) -> str: else: pattern = re.compile(re.escape(old_uri)) - def predicate(attr) -> bool: - nonlocal item - return isinstance(attr, MutableDict) - # todo: can it be an iterable which contains MUtableDict? - - # todo: refactor away from getmembers() - # this fails in some rare edge cases - - # Migrate `meta` and `content`: - if isinstance(item, ContentMixin): - try: - kv = getmembers(item, predicate) - except NotImplementedError: - print('notimplementeed') - cal = "calendar_date_range" - # go with pdb into predicate and check for - try: - kv = getmembers(item, predicate) - breakpoint() - except Exception: - breakpoint() - - # if len(kv) > 2: - # breakpoint() - kv: list[tuple[str, MutableDict]] - for el in kv: - if not el: - continue - attribute_name = el[0] - if attribute_name not in ContentMixin.__dict__: - continue - if attribute_name == 'calendar_date_range': - breakpoint() - - if len(el) != 2: - breakpoint() - - if el[0] == 'content' or el[0] == 'meta' and el[1]: - content = el[1] - for key, v in content.items(): # key might be 'lead' - # 'text', 'people' etc. - if not isinstance(v, str) or not v: - continue - new_val = pattern.sub(repl, v) - if v != new_val: - breakpoint() - # get number of replacements so the count is - # correct - occurrences = len(pattern.findall(v)) - count += occurrences - - try: - item.name[key] = new_val - except AttributeError: - pass - for field in fields_with_urls: value = getattr(item, field, None) if not value: @@ -165,19 +103,24 @@ def predicate(attr) -> bool: ) return count, count_by_id - def migrate_site_collection( + def migrate( self, test: bool = False ) -> tuple[int, dict[str, dict[str, int]]]: + total, grouped = self.migrate_site_collection(test=test) + if not test: + self.migrate_content_mixin() + + return total, grouped + + def migrate_site_collection(self, test): grouped: dict[str, dict[str, int]] = {} total = 0 - simple_count = 0 for name, entries in self.site_collection.get().items(): for _ in entries: simple_count += 1 - for name, entries in self.site_collection.get().items(): for entry in entries: count, grouped_count = self.migrate_url( @@ -189,6 +132,57 @@ def migrate_site_collection( total += count return total, grouped + def migrate_content_mixin(self): + """ Updates the JSON and text columns defined in models using the + ContentMixin to replace old URIs with new ones across multiple tables. + + Generates SQL of the following form: + + update pages set content = replace(content::text, 'old', 'new')::jsonb; + update forms set meta = replace(meta::text, 'old', 'new')::jsonb; + + """ + + def replace_json(col: str) -> str: + return f"{col} = replace({col}::text, :old_uri, :new_uri)::jsonb" + + def replace_text(col: str) -> str: + return f"{col} = replace({col}, :old_uri, :new_uri)" + + updates = [ + ('pages', ['meta', 'content']), + ('forms', ['meta', 'content']), + ('events', ['meta', 'content']), + ('resources', ['meta', 'content']), + ('people', ['meta', 'content', 'picture_url']), + ('organisations', ['meta', 'logo_url']), + ('directories', ['content']), + ('tickets', ['snapshot']), + ('external_links', ['url']), + ] + + for table, columns in updates: + sql_parts = [] + for col in columns: + if col in {'meta', 'content', 'snapshot'}: + sql_parts.append(replace_json(col)) + else: + sql_parts.append(replace_text(col)) + + sql = text( + f"UPDATE {table} SET {', '.join(sql_parts)}" # nosec:B608 + ) + + self.request.session.execute( + sql, + { + 'old_uri': bindparam('old_uri', self.old_uri), + 'new_uri': bindparam('new_uri', self.new_uri) + } + ) + + self.request.session.commit() + class PageNameChange(ModelsWithLinksMixin): @@ -242,7 +236,7 @@ def run() -> int: count = 0 for before, after in zip(urls_before, urls_after): migration = LinkMigration(self.request, before, after) - total, grouped = migration.migrate_site_collection(test=test) + total, grouped = migration.migrate(test=test) count += total return count diff --git a/src/onegov/org/views/settings.py b/src/onegov/org/views/settings.py index 0cf5c1f5ab..66d4f329de 100644 --- a/src/onegov/org/views/settings.py +++ b/src/onegov/org/views/settings.py @@ -357,7 +357,7 @@ def handle_migrate_links( old_uri=form.old_domain.data, new_uri=request.domain ) - total, grouped = migration.migrate_site_collection(test_only) + total, grouped = migration.migrate(test_only) if not test_only: request.success( From 9e8ad7957445cf9afeef6ec62353c9a216333e3a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cyrill=20K=C3=BCttel?= Date: Thu, 10 Oct 2024 14:37:30 +0200 Subject: [PATCH 5/7] Almost there, just need to writ this test --- .pre-commit-config.yaml | 6 +-- .../locale/de_CH/LC_MESSAGES/onegov.org.po | 4 +- .../locale/fr_CH/LC_MESSAGES/onegov.org.po | 4 +- src/onegov/org/management.py | 19 +++++--- src/onegov/org/views/settings.py | 3 +- tests/onegov/org/test_views_settings.py | 47 ++++++++++++++----- 6 files changed, 58 insertions(+), 25 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 216283dc92..a7aba30039 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,6 +1,6 @@ repos: - repo: https://github.com/pre-commit/pre-commit-hooks - rev: v4.6.0 + rev: v5.0.0 hooks: - id: trailing-whitespace - id: mixed-line-ending @@ -15,7 +15,7 @@ repos: exclude: .pre-commit-config.yaml - id: pt_structure - repo: https://github.com/astral-sh/ruff-pre-commit - rev: v0.6.8 + rev: v0.6.9 hooks: - id: ruff args: [ "--fix" ] @@ -33,7 +33,7 @@ repos: - id: sass-lint files: '^src/.*\.scss' - repo: https://github.com/pre-commit/mirrors-eslint - rev: v9.11.1 + rev: v9.12.0 hooks: - id: eslint files: '^src/.*\.jsx?$' diff --git a/src/onegov/org/locale/de_CH/LC_MESSAGES/onegov.org.po b/src/onegov/org/locale/de_CH/LC_MESSAGES/onegov.org.po index 68c1866463..296f4ef66c 100644 --- a/src/onegov/org/locale/de_CH/LC_MESSAGES/onegov.org.po +++ b/src/onegov/org/locale/de_CH/LC_MESSAGES/onegov.org.po @@ -5858,9 +5858,9 @@ msgstr "Total ${number} Links gefunden" #, python-format msgid "" -"Migrates links from the given domain to the current domain \"${domain}\"." +"Migrates links from the given domain to the current domain \"${domain}\". The form must be used *after* the DNS changeover to \"${domain}\"." msgstr "" -"Migriert Links von der angegebenen Domain zur aktuellen Domain \"${domain}\"." +"Migriert Links von der angegebenen Domain zur aktuellen Domain \"${domain}\". Das Formular muss *nach* der DNS-Umstellung auf \"${domain}\" verwendet werden." msgid "OneGov API" msgstr "OneGov API" diff --git a/src/onegov/org/locale/fr_CH/LC_MESSAGES/onegov.org.po b/src/onegov/org/locale/fr_CH/LC_MESSAGES/onegov.org.po index e527402abf..130dedebfd 100644 --- a/src/onegov/org/locale/fr_CH/LC_MESSAGES/onegov.org.po +++ b/src/onegov/org/locale/fr_CH/LC_MESSAGES/onegov.org.po @@ -5877,9 +5877,9 @@ msgstr "Total de ${number} liens trouvés" #, python-format msgid "" -"Migrates links from the given domain to the current domain \"${domain}\"." +"Migrates links from the given domain to the current domain \"${domain}\". The form must be used *after* the DNS changeover to \"${domain}\"." msgstr "" -"Fait migrer les liens du domaine donné vers le domaine actuel \"${domain}\"." +"Fait migrer les liens du domaine donné vers le domaine actuel \"${domain}\". Le formulaire doit être utilisé *après* le passage du DNS à \"${domain}\"." msgid "OneGov API" msgstr "API OneGov" diff --git a/src/onegov/org/management.py b/src/onegov/org/management.py index 1a8f3d6815..a15367f647 100644 --- a/src/onegov/org/management.py +++ b/src/onegov/org/management.py @@ -5,7 +5,7 @@ from aiohttp import ClientTimeout from sqlalchemy.orm import object_session from urlextract import URLExtract -from sqlalchemy import text, bindparam +from sqlalchemy import text, bindparam, String from onegov.async_http.fetch import async_aiohttp_get_all from onegov.core.utils import normalize_for_url from onegov.org.models import SiteCollection @@ -135,8 +135,12 @@ def migrate_site_collection( return total, grouped def migrate_content_mixin(self) -> None: - """ Updates the JSON and text columns defined in models using the - ContentMixin to replace old URIs with new ones across multiple tables. + """ A catch-all function to migrate content not covered by + migrate_site_collection. + + This function was added to handle links that were not processed by the + migrate_site_collection function. + Generates SQL of the following form: @@ -173,17 +177,20 @@ def replace_text(col: str) -> str: sql = text( f"UPDATE {table} SET {', '.join(sql_parts)}" # nosec:B608 + ).bindparams( + bindparam('old_uri', type_=String), + bindparam('new_uri', type_=String) ) self.request.session.execute( sql, { - 'old_uri': bindparam('old_uri', self.old_uri), - 'new_uri': bindparam('new_uri', self.new_uri) + 'old_uri': self.old_uri, + 'new_uri': self.new_uri } ) - self.request.session.commit() + transaction.commit() class PageNameChange(ModelsWithLinksMixin): diff --git a/src/onegov/org/views/settings.py b/src/onegov/org/views/settings.py index 2b27d432c2..7785c57085 100644 --- a/src/onegov/org/views/settings.py +++ b/src/onegov/org/views/settings.py @@ -376,7 +376,8 @@ def handle_migrate_links( 'button_text': button_text, 'callout': _( 'Migrates links from the given domain to the current domain ' - '"${domain}".', + '"${domain}". The form must be used *after* the DNS changeover ' + 'to "${domain}".', mapping={'domain': domain} ), } diff --git a/tests/onegov/org/test_views_settings.py b/tests/onegov/org/test_views_settings.py index d69b7b17d6..181652deab 100644 --- a/tests/onegov/org/test_views_settings.py +++ b/tests/onegov/org/test_views_settings.py @@ -1,4 +1,6 @@ from onegov.api.models import ApiKey +import pytest +from onegov.page import Page from onegov.org.theme.org_theme import HELVETICA from xml.etree.ElementTree import tostring from onegov.org.models import SiteCollection @@ -146,28 +148,51 @@ def test_switch_languages(client): assert 'Deutsch' not in page +@pytest.mark.skip('wip') def test_migrate_links(client): session = client.app.session() sitecollection = SiteCollection(session) objects = sitecollection.get() - # pages = client.app.session().query(Topic).defer(Topic.) - # topics = session.query(Topic) - # - # topics = topics.options(defer(Topic.meta)) - # topics = topics.options(defer(Topic.content)) - # topics = topics.options(defer(Topic.order)) + foo = [page.content for page in objects['topics']] + # set one of the pages content and set + # content.text to something that contains an url. + + # Set up test data + old_domain = 'localhost' + new_domain = '127.0.0.1' + + # Create test objects with content containing the old domain + page = Page( + name='page', + title='Page', + content={'text': f'A link to http://{old_domain}/page'}, + ) + # form = Form(meta={'url': f'http://{old_domain}/form'}) + # event = Event(content={'description': f'Visit us at {old_domain}'}) + # resource = Resource(meta={'link': f'https://{old_domain}/resource'}) + # person = Person(picture_url=f'http://{old_domain}/person.jpg') + # org = Organisation(logo_url=f'http://{old_domain}/logo.png') + # directory = Directory(content={'entries': [f'http://{old_domain}/entry1', + # f'http://{old_domain}/entry2']}) + # ticket = Ticket(snapshot={'url': f'http://{old_domain}/ticket'}) + + # external_link = ExternalLink(url=f'http://{old_domain}/external') + + # todo: this is hard to test, need to bypass form validation + # Die Domain muss einen Punkt enthalten + session.add_all([page]) + session.flush() client.login_admin() page = client.get('/migrate-links') + assert ( 'Migriert Links von der angegebenen Domain zur aktuellen Domain ' '"localhost"' in page ) - - # migrate from 'localhost' to 127.0.0.1 - # (pointless but enough for test) - page.form['old_domain'] = '127.0.0.1' - page.form.submit() + page.form['old_domain'] = old_domain + page.form['test'] = False + page = page.form.submit().maybe_follow() page.showbrowser() From 0dd671c925050484236307fee4925b561fe0d76c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cyrill=20K=C3=BCttel?= Date: Tue, 15 Oct 2024 14:24:02 +0200 Subject: [PATCH 6/7] fix mypy errors --- src/onegov/core/cli/commands.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/onegov/core/cli/commands.py b/src/onegov/core/cli/commands.py index e5b39d363e..22dd18a565 100644 --- a/src/onegov/core/cli/commands.py +++ b/src/onegov/core/cli/commands.py @@ -190,7 +190,7 @@ def __init__(self, queue_processors: list[SmsQueueProcessor]): ) def on_moved(self, event: 'FileSystemEvent') -> None: - dest_path = os.path.abspath(event.dest_path) + dest_path = os.path.abspath(str(event.dest_path)) assert isinstance(dest_path, str) for qp in self.queue_processors: # only one queue processor should match @@ -208,7 +208,7 @@ def on_moved(self, event: 'FileSystemEvent') -> None: # moved. But we should also trigger when new files are created just # in case this ever changes. def on_created(self, event: 'FileSystemEvent') -> None: - src_path = os.path.abspath(event.src_path) + src_path = os.path.abspath(str(event.src_path)) assert isinstance(src_path, str) for qp in self.queue_processors: # only one queue processor should match From 1617cb31c0cc72301bbd6bd9250bfdc922b381c2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cyrill=20K=C3=BCttel?= Date: Tue, 15 Oct 2024 14:25:00 +0200 Subject: [PATCH 7/7] Remove unused type ignore statements --- src/onegov/core/cache.py | 2 +- src/onegov/org/models/ticket.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/onegov/core/cache.py b/src/onegov/core/cache.py index 7989fd83f9..5d27010901 100644 --- a/src/onegov/core/cache.py +++ b/src/onegov/core/cache.py @@ -82,7 +82,7 @@ def instance_lru_cache( def decorator(wrapped: '_F') -> '_F': def wrapper(self: Any) -> Any: return lru_cache(maxsize=maxsize)( - update_wrapper(partial(wrapped, self), wrapped) # type:ignore + update_wrapper(partial(wrapped, self), wrapped) ) # NOTE: we are doing some oddball stuff here that the type diff --git a/src/onegov/org/models/ticket.py b/src/onegov/org/models/ticket.py index a6e8c63cf4..7871c7adea 100644 --- a/src/onegov/org/models/ticket.py +++ b/src/onegov/org/models/ticket.py @@ -345,7 +345,7 @@ def get_links( # type:ignore[override] url_obj = URL(request.link(self.submission)) edit_url = url_obj.query_param('edit', '').as_string() - (links if not links else extra).append( # type:ignore + (links if not links else extra).append( Link( text=_('Edit submission'), url=request.return_here(edit_url),