Skip to content

Commit

Permalink
Merge pull request #1703 from UlrichB22/link_converter
Browse files Browse the repository at this point in the history
Fix moin-nonexistent class in itemlinks starting with '+'
  • Loading branch information
RogerHaase authored Jul 2, 2024
2 parents 704e08c + 62f70be commit ed17d53
Show file tree
Hide file tree
Showing 5 changed files with 51 additions and 7 deletions.
14 changes: 13 additions & 1 deletion src/moin/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
from moin.utils import monkeypatch # noqa
from moin.utils.clock import Clock
from moin import auth, user, config
from moin.constants.misc import ANON
from moin.constants.misc import ANON, VALID_ITEMLINK_VIEWS
from moin.i18n import i18n_init
from moin.themes import setup_jinja_env, themed_error
from moin.storage.middleware import protecting, indexing, routing
Expand Down Expand Up @@ -156,6 +156,8 @@ class ItemNameConverter(PathConverter):
from moin.apps.serve import serve

app.register_blueprint(serve, url_prefix="/+serve")

app.view_endpoints = get_endpoints(app)
clock.stop("create_app register")
clock.start("create_app flask-cache")
# 'SimpleCache' caching uses a dict and is not thread safe according to the docs.
Expand Down Expand Up @@ -191,6 +193,16 @@ class ItemNameConverter(PathConverter):
return app


def get_endpoints(app):
"""Get dict with views and related endpoints allowed as itemlink"""
view_endpoints = {}
for rule in app.url_map.iter_rules():
view = rule.rule.split("/")[1]
if view in VALID_ITEMLINK_VIEWS and rule.rule == f"/{view}/<itemname:item_name>":
view_endpoints[view] = rule.endpoint
return view_endpoints


def destroy_app(app):
deinit_backends(app)

Expand Down
4 changes: 4 additions & 0 deletions src/moin/constants/misc.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
# Copyright: 2011 MoinMoin:ThomasWaldmann
# Copyright: 2024 MoinMoin:UlrichB
# License: GNU GPL v2 (or any later version), see LICENSE.txt for details.

"""
Expand Down Expand Up @@ -69,3 +70,6 @@
NO_LOCK = 0 # false, someone else holds lock for current item
LOCKED = 1 # true, current user has obtained or renewed lock
LOCK = "lock"

# Valid views allowed for itemlinks
VALID_ITEMLINK_VIEWS = ["+meta", "+history", "+download", "+highlight"]
21 changes: 17 additions & 4 deletions src/moin/converters/link.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
# Copyright: 2008 MoinMoin:BastianBlank
# Copyright: 2024 MoinMoin:UlrichB
# License: GNU GPL v2 (or any later version), see LICENSE.txt for details.

"""
Expand All @@ -8,8 +9,10 @@
special wiki links.
"""

from flask import current_app as app
from flask import g as flaskg

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

def handle_wikilocal_links(self, elem, input, page, to_tag=ConverterBase._tag_xlink_href):
view_name = ""
if input.path:
# this can be a relative path, make it absolute:
path = input.path
item_name = str(input.path)
# Remove view from item_name before searching
if item_name.startswith("+"):
view_name = item_name.split("/")[0]
if view_name in VALID_ITEMLINK_VIEWS:
item_name = item_name.split(f"{view_name}/")[1]
if page:
path = self.absolute_path(path, page.path)
item_name = str(path)
# this can be a relative path, make it absolute:
item_name = str(self.absolute_path(Iri(path=item_name).path, page.path))
if not flaskg.storage.has_item(item_name):
# XXX these index accesses slow down the link converter quite a bit
elem.set(moin_page.class_, "moin-nonexistent")
else:
item_name = str(page.path[1:]) if page else ""
endpoint, rev, query = self._get_do_rev(input.query)

if view_name in app.view_endpoints.keys():
# Other views will be shown with class moin-nonexistent as non-existent links
endpoint = app.view_endpoints[view_name]

url = url_for_item(item_name, rev=rev, endpoint=endpoint)
if not page:
url = url[1:]
Expand Down
2 changes: 1 addition & 1 deletion src/moin/templates/utils.html
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,7 @@
<li class="list-group-item">Item Links:&nbsp;
{%- if meta['itemlinks'] -%}
{%- for item in meta['itemlinks']|sort -%}
<a href="{{ url_for('frontend.show_item', item_name=item) }}" {% if not theme_supp.item_exists(item) %}class="moin-nonexistent"{% endif %}>{{ item }}</a>
<a href="{{ url_for('frontend.show_item', item_name=item) }}" {% if not theme_supp.itemlink_exists(item) %}class="moin-nonexistent"{% endif %}>{{ item }}</a>
{%- if not loop.last %}, {% endif -%}
{%- endfor -%}
{%- else -%}
Expand Down
17 changes: 16 additions & 1 deletion src/moin/themes/__init__.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# Copyright: 2003-2010 MoinMoin:ThomasWaldmann
# Copyright: 2008 MoinMoin:RadomirDopieralski
# Copyright: 2010 MoinMoin:DiogenesAugusto
# Copyright: 2023 MoinMoin project
# Copyright: 2023-2024 MoinMoin project
# License: GNU GPL v2 (or any later version), see LICENSE.txt for details.

"""
Expand All @@ -26,6 +26,7 @@
from moin import wikiutil, user
from moin.constants.keys import USERID, ADDRESS, HOSTNAME, REVID, ITEMID, NAME_EXACT, ASSIGNED_TO, NAME, NAMESPACE
from moin.constants.contenttypes import CONTENTTYPES_MAP, CONTENTTYPE_MARKUP, CONTENTTYPE_TEXT, CONTENTTYPE_MOIN_19
from moin.constants.misc import VALID_ITEMLINK_VIEWS
from moin.constants.namespaces import NAMESPACE_DEFAULT, NAMESPACE_USERS, NAMESPACE_ALL
from moin.constants.rights import SUPERUSER
from moin.search import SearchForm
Expand Down Expand Up @@ -591,6 +592,20 @@ def item_exists(self, itemname):
"""
return self.storage.has_item(itemname)

def itemlink_exists(self, itemlink):
"""
Check whether the item pointed to by the given itemlink exists or not
:rtype: boolean
:returns: whether item pointed to by the link exists or not
"""
item_name = itemlink
if itemlink.startswith("+"):
view_name = itemlink.split("/")[0]
if view_name in VALID_ITEMLINK_VIEWS:
item_name = itemlink.split(f"{view_name}/")[1]
return self.storage.has_item(item_name)

def variables_css(self):
"""
Check whether this theme has a variables.css file
Expand Down

0 comments on commit ed17d53

Please sign in to comment.