From f8a5567475f14aac1119bbeebb69d5b85a55bb86 Mon Sep 17 00:00:00 2001 From: UlrichB22 <97119703+UlrichB22@users.noreply.github.com> Date: Tue, 29 Oct 2024 21:16:13 +0100 Subject: [PATCH] Add RandomQuote macro --- docs/user/moinwiki.rst | 3 + src/moin/help/help-en/FortuneCookies.data | 8 +++ src/moin/help/help-en/FortuneCookies.meta | 28 +++++++++ src/moin/help/help-en/MoinWikiMacros.data | 24 ++++++++ src/moin/help/help-en/MoinWikiMacros.meta | 10 ++-- src/moin/macros/RandomQuote.py | 70 +++++++++++++++++++++++ src/moin/macros/_base.py | 15 +++++ 7 files changed, 153 insertions(+), 5 deletions(-) create mode 100644 src/moin/help/help-en/FortuneCookies.data create mode 100644 src/moin/help/help-en/FortuneCookies.meta create mode 100644 src/moin/macros/RandomQuote.py diff --git a/docs/user/moinwiki.rst b/docs/user/moinwiki.rst index 51bfaf5cd..5b9575c39 100644 --- a/docs/user/moinwiki.rst +++ b/docs/user/moinwiki.rst @@ -818,6 +818,9 @@ extra features. The following is a table of MoinMoin's macros. +-------------------------------------------+------------------------------------------------------------+ | ``<>`` | Inserts names of 3 random items | +-------------------------------------------+------------------------------------------------------------+ +| ``<>`` | Select a random quote from the given item, | +| | or from FortuneCookies if omitted. | ++-------------------------------------------+------------------------------------------------------------+ | ``<>`` | Displays all icons in /static/img/icons directory | +-------------------------------------------+------------------------------------------------------------+ | ``<>`` | Displays available smileys and the corresponding markup | diff --git a/src/moin/help/help-en/FortuneCookies.data b/src/moin/help/help-en/FortuneCookies.data new file mode 100644 index 000000000..dafc6728a --- /dev/null +++ b/src/moin/help/help-en/FortuneCookies.data @@ -0,0 +1,8 @@ += Fortune Cookies = + +This item is used to show the result of the RandomQuote macro. + + * I like '''MoinMoin''' Wiki + * Try out MoinMoin version 2.0, see install docs at [[https://moin-20.readthedocs.io/en/latest/admin/install.html|moin-20.readthedocs.io]] + * The '''RandomQuote''' macro uses the item '''FortuneCookies''' by default + * This is a random quote generated by the '''RandomQuote''' macro diff --git a/src/moin/help/help-en/FortuneCookies.meta b/src/moin/help/help-en/FortuneCookies.meta new file mode 100644 index 000000000..dd5298317 --- /dev/null +++ b/src/moin/help/help-en/FortuneCookies.meta @@ -0,0 +1,28 @@ +{ + "action": "SAVE", + "address": "127.0.0.1", + "comment": "", + "contenttype": "text/x.moin.wiki;charset=utf-8", + "dataid": "1ae8372681474a6bafc162078dc6679d", + "externallinks": [ + "https://moin-20.readthedocs.io/en/latest/admin/install.html" + ], + "itemid": "237f55f536a14767b5b0f4942a8bb1d8", + "itemlinks": [], + "itemtransclusions": [], + "itemtype": "default", + "language": "en", + "mtime": 1730226097, + "name": [ + "FortuneCookies" + ], + "name_old": [], + "namespace": "help-en", + "rev_number": 1, + "revid": "2ee6b5b42d304ebcab3e7874df973aa7", + "sha1": "8ceccfe52b6914aeb48eef5acef9163ac074ec6c", + "size": 407, + "summary": "", + "tags": [], + "wikiname": "MyMoinMoin" +} diff --git a/src/moin/help/help-en/MoinWikiMacros.data b/src/moin/help/help-en/MoinWikiMacros.data index 2b3e56bbe..e8b4c79a7 100644 --- a/src/moin/help/help-en/MoinWikiMacros.data +++ b/src/moin/help/help-en/MoinWikiMacros.data @@ -516,6 +516,30 @@ Five random items: <> +=== RandomQuote === + +This macro randomly selects a quote from a list in the specified item (default: FortuneCookies in the current namespace). + +'''Markup:''' + +{{{ +A random Quote: + +Quote 1.: <> + +Quote 2.: <> + +}}} + +'''Result:''' + +Two random quotes: + + Quote 1.: <> + + Quote 2.: <> + + === ShowUserGroup === This macro displays the contents of the metadata defined in the "usergroup" attribute. diff --git a/src/moin/help/help-en/MoinWikiMacros.meta b/src/moin/help/help-en/MoinWikiMacros.meta index 77ff4af81..23f8cb66b 100644 --- a/src/moin/help/help-en/MoinWikiMacros.meta +++ b/src/moin/help/help-en/MoinWikiMacros.meta @@ -3,7 +3,7 @@ "address": "127.0.0.1", "comment": "", "contenttype": "text/x.moin.wiki;charset=utf-8", - "dataid": "e5c04311b38c46029e237c0c12f3aa40", + "dataid": "3783c3fdda3b43b1a4ec0f3300c22bdb", "externallinks": [ "https://fontawesome.com/search?o=r&m=free", "https://moinmo.in/HelpOnMacros/Include" @@ -19,16 +19,16 @@ ], "itemtype": "default", "language": "en", - "mtime": 1723402687, + "mtime": 1730231040, "name": [ "MoinWikiMacros" ], "name_old": [], "namespace": "help-en", "rev_number": 1, - "revid": "dfc263543dd84e4b9fbe6b64dd983b58", - "sha1": "0064f57340dac2f337760e88e5bd57fc9ef550b1", - "size": 14479, + "revid": "931016b31ee144e7879f2ab37ebc3caa", + "sha1": "d9c425e1ccc9d1a9d862b50ea46848558d6028cf", + "size": 14886, "summary": "", "tags": [ "macros", diff --git a/src/moin/macros/RandomQuote.py b/src/moin/macros/RandomQuote.py new file mode 100644 index 000000000..5f0f3917b --- /dev/null +++ b/src/moin/macros/RandomQuote.py @@ -0,0 +1,70 @@ +# Copyright: 2002-2004 Juergen Hermann +# Copyright: 2002 MoinMoin:ThomasWaldmann +# Copyright: 2024 MoinMoin:UlrichB +# License: GNU GPL v2 (or any later version), see LICENSE.txt for details. + +""" +MoinMoin - RandomQuote Macro selects a random quote from FortuneCookies or a given moinwiki item. + + Usage: + <> + <> + + Comments: + It will look for list delimiters on the moinwiki item in question. + It will ignore anything that is not in an "*" list. +""" + +import random + +from moin.constants.keys import NAME_EXACT +from moin.items import Item +from moin.i18n import _ +from moin.constants.itemtypes import ITEMTYPE_NONEXISTENT +from moin.converters._util import decode_data +from moin.converters import default_registry as reg +from moin.macros._base import MacroInlineBase, fail_message, valid_item_name +from moin.utils.mime import Type, type_moin_document + +from moin.utils.interwiki import get_fqname, split_fqname + +random.seed() + + +class Macro(MacroInlineBase): + """Return a random quote from FortuneCookies or a given wiki item""" + + def macro(self, content, arguments, page_url, alternative): + item_name = arguments[0] if arguments else "FortuneCookies" + if item_name[0] in ['"', "'"] and item_name[-1] in ['"', "'"]: # remove quotes + item_name = item_name[1:-1] + if not valid_item_name(item_name): + err_msg = _("Invalid value given for item name: {0}").format(item_name) + return fail_message(err_msg, alternative) + + # use same namespace as current item + namespace = split_fqname(str(page_url.path)).namespace + if not item_name.startswith(f"{namespace}/"): + item_name = get_fqname(item_name, NAME_EXACT, namespace) + + # get the item with the list of quotes + item = Item.create(item_name) + if item.itemtype == ITEMTYPE_NONEXISTENT: + err_msg = _("Item does not exist or read access blocked by ACLs: {0}").format(item_name) + return fail_message(err_msg, alternative) + data = decode_data(item.content.data, item.contenttype) + + # select lines looking like a list item + quotes = data.splitlines() + quotes = [quote.strip() for quote in quotes] + quotes = [quote[2:] for quote in quotes if quote.startswith("* ")] + if not quotes: + err_msg = _("No quotes found in {0}").format(item_name) + return fail_message(err_msg, alternative) + + result = random.choice(quotes) + # quote may use some sort of markup, convert it to dom + input_conv = reg.get(Type(item.contenttype), type_moin_document, includes="expandall") + if not input_conv: + raise TypeError(f"We cannot handle the conversion from {item.contenttype} to the DOM tree") + return input_conv(result) diff --git a/src/moin/macros/_base.py b/src/moin/macros/_base.py index ace3a9887..a425a789b 100644 --- a/src/moin/macros/_base.py +++ b/src/moin/macros/_base.py @@ -72,6 +72,21 @@ def get_item_names(name="", startswith="", kind="files", skiptag="", tag=""): return item_names +def valid_item_name(name): + """return False if item_name not valid""" + if not isinstance(name, str): + return False + if name != name.strip(): + return False + if name[0] in ["+", ".", "/"]: # allow only absolute path + return False + if name.startswith("/") or name.endswith("/"): + return False + if "//" in name: # empty ancestor name is invalid + return False + return True + + def extract_h1(item_name): """ Return the first heading found in the item's content