Skip to content

Commit ed17d53

Browse files
authored
Merge pull request #1703 from UlrichB22/link_converter
Fix moin-nonexistent class in itemlinks starting with '+'
2 parents 704e08c + 62f70be commit ed17d53

File tree

5 files changed

+51
-7
lines changed

5 files changed

+51
-7
lines changed

src/moin/app.py

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@
3030
from moin.utils import monkeypatch # noqa
3131
from moin.utils.clock import Clock
3232
from moin import auth, user, config
33-
from moin.constants.misc import ANON
33+
from moin.constants.misc import ANON, VALID_ITEMLINK_VIEWS
3434
from moin.i18n import i18n_init
3535
from moin.themes import setup_jinja_env, themed_error
3636
from moin.storage.middleware import protecting, indexing, routing
@@ -156,6 +156,8 @@ class ItemNameConverter(PathConverter):
156156
from moin.apps.serve import serve
157157

158158
app.register_blueprint(serve, url_prefix="/+serve")
159+
160+
app.view_endpoints = get_endpoints(app)
159161
clock.stop("create_app register")
160162
clock.start("create_app flask-cache")
161163
# 'SimpleCache' caching uses a dict and is not thread safe according to the docs.
@@ -191,6 +193,16 @@ class ItemNameConverter(PathConverter):
191193
return app
192194

193195

196+
def get_endpoints(app):
197+
"""Get dict with views and related endpoints allowed as itemlink"""
198+
view_endpoints = {}
199+
for rule in app.url_map.iter_rules():
200+
view = rule.rule.split("/")[1]
201+
if view in VALID_ITEMLINK_VIEWS and rule.rule == f"/{view}/<itemname:item_name>":
202+
view_endpoints[view] = rule.endpoint
203+
return view_endpoints
204+
205+
194206
def destroy_app(app):
195207
deinit_backends(app)
196208

src/moin/constants/misc.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
# Copyright: 2011 MoinMoin:ThomasWaldmann
2+
# Copyright: 2024 MoinMoin:UlrichB
23
# License: GNU GPL v2 (or any later version), see LICENSE.txt for details.
34

45
"""
@@ -69,3 +70,6 @@
6970
NO_LOCK = 0 # false, someone else holds lock for current item
7071
LOCKED = 1 # true, current user has obtained or renewed lock
7172
LOCK = "lock"
73+
74+
# Valid views allowed for itemlinks
75+
VALID_ITEMLINK_VIEWS = ["+meta", "+history", "+download", "+highlight"]

src/moin/converters/link.py

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
# Copyright: 2008 MoinMoin:BastianBlank
2+
# Copyright: 2024 MoinMoin:UlrichB
23
# License: GNU GPL v2 (or any later version), see LICENSE.txt for details.
34

45
"""
@@ -8,8 +9,10 @@
89
special wiki links.
910
"""
1011

12+
from flask import current_app as app
1113
from flask import g as flaskg
1214

15+
from moin.constants.misc import VALID_ITEMLINK_VIEWS
1316
from moin.utils.interwiki import is_known_wiki, url_for_item
1417
from moin.utils.iri import Iri
1518
from moin.utils.mime import type_moin_document
@@ -182,18 +185,28 @@ def handle_wiki_links(self, elem, input, to_tag=ConverterBase._tag_xlink_href):
182185
elem.set(to_tag, link)
183186

184187
def handle_wikilocal_links(self, elem, input, page, to_tag=ConverterBase._tag_xlink_href):
188+
view_name = ""
185189
if input.path:
186-
# this can be a relative path, make it absolute:
187-
path = input.path
190+
item_name = str(input.path)
191+
# Remove view from item_name before searching
192+
if item_name.startswith("+"):
193+
view_name = item_name.split("/")[0]
194+
if view_name in VALID_ITEMLINK_VIEWS:
195+
item_name = item_name.split(f"{view_name}/")[1]
188196
if page:
189-
path = self.absolute_path(path, page.path)
190-
item_name = str(path)
197+
# this can be a relative path, make it absolute:
198+
item_name = str(self.absolute_path(Iri(path=item_name).path, page.path))
191199
if not flaskg.storage.has_item(item_name):
192200
# XXX these index accesses slow down the link converter quite a bit
193201
elem.set(moin_page.class_, "moin-nonexistent")
194202
else:
195203
item_name = str(page.path[1:]) if page else ""
196204
endpoint, rev, query = self._get_do_rev(input.query)
205+
206+
if view_name in app.view_endpoints.keys():
207+
# Other views will be shown with class moin-nonexistent as non-existent links
208+
endpoint = app.view_endpoints[view_name]
209+
197210
url = url_for_item(item_name, rev=rev, endpoint=endpoint)
198211
if not page:
199212
url = url[1:]

src/moin/templates/utils.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -153,7 +153,7 @@
153153
<li class="list-group-item">Item Links:&nbsp;
154154
{%- if meta['itemlinks'] -%}
155155
{%- for item in meta['itemlinks']|sort -%}
156-
<a href="{{ url_for('frontend.show_item', item_name=item) }}" {% if not theme_supp.item_exists(item) %}class="moin-nonexistent"{% endif %}>{{ item }}</a>
156+
<a href="{{ url_for('frontend.show_item', item_name=item) }}" {% if not theme_supp.itemlink_exists(item) %}class="moin-nonexistent"{% endif %}>{{ item }}</a>
157157
{%- if not loop.last %}, {% endif -%}
158158
{%- endfor -%}
159159
{%- else -%}

src/moin/themes/__init__.py

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
# Copyright: 2003-2010 MoinMoin:ThomasWaldmann
22
# Copyright: 2008 MoinMoin:RadomirDopieralski
33
# Copyright: 2010 MoinMoin:DiogenesAugusto
4-
# Copyright: 2023 MoinMoin project
4+
# Copyright: 2023-2024 MoinMoin project
55
# License: GNU GPL v2 (or any later version), see LICENSE.txt for details.
66

77
"""
@@ -26,6 +26,7 @@
2626
from moin import wikiutil, user
2727
from moin.constants.keys import USERID, ADDRESS, HOSTNAME, REVID, ITEMID, NAME_EXACT, ASSIGNED_TO, NAME, NAMESPACE
2828
from moin.constants.contenttypes import CONTENTTYPES_MAP, CONTENTTYPE_MARKUP, CONTENTTYPE_TEXT, CONTENTTYPE_MOIN_19
29+
from moin.constants.misc import VALID_ITEMLINK_VIEWS
2930
from moin.constants.namespaces import NAMESPACE_DEFAULT, NAMESPACE_USERS, NAMESPACE_ALL
3031
from moin.constants.rights import SUPERUSER
3132
from moin.search import SearchForm
@@ -591,6 +592,20 @@ def item_exists(self, itemname):
591592
"""
592593
return self.storage.has_item(itemname)
593594

595+
def itemlink_exists(self, itemlink):
596+
"""
597+
Check whether the item pointed to by the given itemlink exists or not
598+
599+
:rtype: boolean
600+
:returns: whether item pointed to by the link exists or not
601+
"""
602+
item_name = itemlink
603+
if itemlink.startswith("+"):
604+
view_name = itemlink.split("/")[0]
605+
if view_name in VALID_ITEMLINK_VIEWS:
606+
item_name = itemlink.split(f"{view_name}/")[1]
607+
return self.storage.has_item(item_name)
608+
594609
def variables_css(self):
595610
"""
596611
Check whether this theme has a variables.css file

0 commit comments

Comments
 (0)