From 93c673540f0c2b9ff78a5a9985b40ff3e342f044 Mon Sep 17 00:00:00 2001 From: davewiththenicehat <54369722+davewiththenicehat@users.noreply.github.com> Date: Sat, 5 Jun 2021 21:00:19 -0400 Subject: [PATCH] cleanup A lot of misc cleanup. Docstring updates. Removed code that is not required. --- evennia/web/website/views/help.py | 278 +++++++++++++----------------- 1 file changed, 121 insertions(+), 157 deletions(-) diff --git a/evennia/web/website/views/help.py b/evennia/web/website/views/help.py index 3b8c1faa31..c6a5b6c9fc 100644 --- a/evennia/web/website/views/help.py +++ b/evennia/web/website/views/help.py @@ -11,8 +11,6 @@ from django.views.generic import ListView, DetailView from django.http import HttpResponseBadRequest from evennia.help.models import HelpEntry from evennia.help.filehelp import FILE_HELP_ENTRIES -from .mixins import TypeclassMixin -from evennia.utils.logger import log_info from evennia.utils.ansi import strip_ansi DEFAULT_HELP_CATEGORY = settings.DEFAULT_HELP_CATEGORY @@ -26,162 +24,126 @@ def get_help_category(help_entry, slugify_cat=True): slugify_cat (bool): If true the return string is slugified. Default is True. Notes: - If the entry does not have attribute 'web_help_entries'. One is created with - a slugified copy of the attribute help_category. - This attribute is used for sorting the entries for the help index (ListView) page. + If an entry does not have a `help_category` attribute, DEFAULT_HELP_CATEGORY from the + settings file is used. + If the entry does not have attribute 'web_help_entries'. One is created with a slugified + copy of the attribute help_category. This attribute is used for sorting the entries for the + help index (ListView) page. Returns: help_category (str): The category for the help entry. """ + help_category = help_entry.help_category if help_entry.help_category else DEFAULT_HELP_CATEGORY if not hasattr(help_entry, 'web_help_category'): - setattr(help_entry, 'web_help_category', slugify(help_entry.help_category)) - return slugify(help_entry.help_category) if slugify_cat else help_entry.help_category + setattr(help_entry, 'web_help_category', slugify(help_category)) + return slugify(help_category) if slugify_cat else help_category def get_help_topic(help_entry): - topic = getattr(help_entry, 'key', False) - if not topic: - getattr(help_entry, 'db_key', False) - # log_info(f'get_help_topic returning: {topic}') - return topic + """Get the topic of the help entry. + Args: + help_entry (HelpEntry, FileHelpEntry or Command): Help entry instance. -def can_read_topic(cmd_or_topic, caller): - """ - Helper method. If this return True, the given help topic - be viewable in the help listing. Note that even if this returns False, - the entry will still be visible in the help index unless `should_list_topic` - is also returning False. - Args: - cmd_or_topic (Command, HelpEntry or FileHelpEntry): The topic/command to test. - caller: the caller checking for access. - Returns: - bool: If command can be viewed or not. - Notes: - This uses the 'read' lock. If no 'read' lock is defined, the topic is assumed readable - by all. - """ - if inherits_from(cmd_or_topic, "evennia.commands.command.Command"): - return cmd_or_topic.auto_help and cmd_or_topic.access(caller, 'read', default=True) - else: - return cmd_or_topic.access(caller, 'read', default=True) - - -def can_list_topic(cmd_or_topic, caller): + Returns: + topic (str): The topic of the help entry. Default is 'unknown_topic'. """ - Should the specified command appear in the help table? - This method only checks whether a specified command should appear in the table of - topics/commands. The command can be used by the caller (see the 'should_show_help' method) - and the command will still be available, for instance, if a character type 'help name of the - command'. However, if you return False, the specified command will not appear in the table. - This is sometimes useful to "hide" commands in the table, but still access them through the - help system. + return getattr(help_entry, 'key', 'unknown_topic') + + +def can_read_topic(cmd_or_topic, account): + """Check if an account or puppet has read access to a help entry. + Args: cmd_or_topic (Command, HelpEntry or FileHelpEntry): The topic/command to test. - caller: the caller checking for access. + account: the account or puppet checking for access. + Returns: - bool: If command should be listed or not. + bool: If command can be viewed or not. + Notes: - By default, the 'view' lock will be checked, and if no such lock is defined, the 'read' - lock will be used. If neither lock is defined, the help entry is assumed to be - accessible to all. + This uses the 'read' lock. If no 'read' lock is defined, the topic is assumed readable + by all. + Even if this returns False, the entry will still be visible in the help index unless + `can_list_topic` is also returning False. """ - has_view = ( - "view:" in cmd_or_topic.locks - if inherits_from(cmd_or_topic, "evennia.commands.command.Command") - else cmd_or_topic.locks.get("view") - ) - - if has_view: - return cmd_or_topic.access(caller, 'view', default=True) + if inherits_from(cmd_or_topic, "evennia.commands.command.Command"): + return cmd_or_topic.auto_help and cmd_or_topic.access(account, 'read', default=True) else: - # no explicit 'view' lock - use the 'read' lock - return cmd_or_topic.access(caller, 'read', default=True) + return cmd_or_topic.access(account, 'read', default=True) -def collect_topics(account, mode='list'): - """ - Collect help topics from all sources (cmd/db/file). - Args: - account (Object or Account): The user of the Command. - mode (str): One of 'list' or 'query', where the first means we are collecting to view - the help index and the second because of wanting to search for a specific help - entry/cmd to read. This determines which access should be checked. - Returns: - tuple: A tuple of three dicts containing the different types of help entries - in the order cmd-help, db-help, file-help: - `({key: cmd,...}, {key: dbentry,...}, {key: fileentry,...}` - """ - # start with cmd-help - cmd_help_topics = [] - if not str(account) == 'AnonymousUser': - # create list of account and account's puppets - puppets = account.db._playable_characters + [account] - # add the account's and puppets' commands to cmd_help_topics list - for puppet in puppets: - for cmdset in puppet.cmdset.get(): - # removing doublets in cmdset, caused by cmdhandler - # having to allow doublet commands to manage exits etc. - cmdset.make_unique(puppet) - # retrieve all available commands and database / file-help topics. - # also check the 'cmd:' lock here - for cmd in cmdset: - # skip the command if the puppet does not have access - if not cmd.access(puppet, 'cmd'): - continue - # skip the command if it's help entry already exists in the topic list - entry_exists = False - for verify_cmd in cmd_help_topics: - if verify_cmd.key and cmd.key and \ - verify_cmd.help_category == cmd.help_category and \ - verify_cmd.__doc__ == cmd.__doc__: - entry_exists = True - break - if entry_exists: - continue - # add this command to the list - cmd_help_topics.append(cmd) - # get all file-based help entries, checking perms - file_help_topics = { - topic.key.lower().strip(): topic - for topic in FILE_HELP_ENTRIES.all() - } - # get db-based help entries, checking perms - db_help_topics = { - topic.key.lower().strip(): topic - for topic in HelpEntry.objects.all() - } - if mode == 'list': - # check the view lock for all help entries/commands and determine key - cmd_help_topics = { - cmd.auto_help_display_key - if hasattr(cmd, "auto_help_display_key") else cmd.key: cmd - for cmd in cmd_help_topics if can_list_topic(cmd, account)} - db_help_topics = { - key: entry for key, entry in db_help_topics.items() - if can_list_topic(entry, account) - } - file_help_topics = { - key: entry for key, entry in file_help_topics.items() - if can_list_topic(entry, account)} - else: - # query - cmd_help_topics = { - cmd.auto_help_display_key - if hasattr(cmd, "auto_help_display_key") else cmd.key: cmd - for cmd in cmd_help_topics if can_read_topic(cmd, account)} - db_help_topics = { - key: entry for key, entry in db_help_topics.items() - if can_read_topic(entry, account) - } - file_help_topics = { - key: entry for key, entry in file_help_topics.items() - if can_read_topic(entry, account)} +def collect_topics(account): + """Collect help topics from all sources (cmd/db/file). - return cmd_help_topics, db_help_topics, file_help_topics + Args: + account (Character or Account): Account or Character to collect help topics from. + + Returns: + cmd_help_topics (dict): contains Command instances. + db_help_topics (dict): contains HelpEntry instances. + file_help_topics (dict): contains FileHelpEntry instances + """ + + # collect commands of account and all puppets + # skip a command if an entry is recorded with the same topics, category and help entry + cmd_help_topics = [] + if not str(account) == 'AnonymousUser': + # create list of account and account's puppets + puppets = account.db._playable_characters + [account] + # add the account's and puppets' commands to cmd_help_topics list + for puppet in puppets: + for cmdset in puppet.cmdset.get(): + # removing doublets in cmdset, caused by cmdhandler + # having to allow doublet commands to manage exits etc. + cmdset.make_unique(puppet) + # retrieve all available commands and database / file-help topics. + # also check the 'cmd:' lock here + for cmd in cmdset: + # skip the command if the puppet does not have access + if not cmd.access(puppet, 'cmd'): + continue + # skip the command if the puppet does not have read access + if not can_read_topic(cmd, puppet): + continue + # skip the command if it's help entry already exists in the topic list + entry_exists = False + for verify_cmd in cmd_help_topics: + if verify_cmd.key and cmd.key and \ + verify_cmd.help_category == cmd.help_category and \ + verify_cmd.__doc__ == cmd.__doc__: + entry_exists = True + break + if entry_exists: + continue + # add this command to the list + cmd_help_topics.append(cmd) + + # Verify account has read access to filehelp entries and gather them into a dictionary + file_help_topics = { + topic.key.lower().strip(): topic + for topic in FILE_HELP_ENTRIES.all() + if can_read_topic(topic, account) + } + + # Verify account has read access to database entries and gather them into a dictionary + db_help_topics = { + topic.key.lower().strip(): topic + for topic in HelpEntry.objects.all() + if can_read_topic(topic, account) + } + + # Collect commands into a dictionary, read access verified at puppet level + cmd_help_topics = { + cmd.auto_help_display_key + if hasattr(cmd, "auto_help_display_key") else cmd.key: cmd + for cmd in cmd_help_topics + } + + return cmd_help_topics, db_help_topics, file_help_topics -class HelpMixin(TypeclassMixin): +class HelpMixin(): """ This is a "mixin", a modifier of sorts. @@ -202,21 +164,23 @@ class HelpMixin(TypeclassMixin): and other documentation that the current user is allowed to see. Returns: - queryset (QuerySet): List of Help entries available to the user. + queryset (list): List of Help entries available to the user. """ - log_info('get_queryset') account = self.request.user + # collect all help entries - cmd_help_topics, db_help_topics, file_help_topics = collect_topics(account, mode='query') + cmd_help_topics, db_help_topics, file_help_topics = collect_topics(account) + # merge the entries file_db_help_topics = {**file_help_topics, **db_help_topics} all_topics = {**file_db_help_topics, **cmd_help_topics} all_entries = list(all_topics.values()) + # sort the entries all_entries = sorted(all_entries, key=get_help_topic) # sort alphabetically all_entries.sort(key=get_help_category) # group by categories - log_info('get_queryset success') + return all_entries @@ -242,12 +206,12 @@ class HelpDetailView(HelpMixin, DetailView): """ # -- Django constructs -- + # the html template to use when contructing the detail page for a help topic template_name = "website/help_detail.html" @property def page_title(self): # Makes sure the page has a sensible title. - # return "%s Detail" % self.typeclass._meta.verbose_name.title() obj = self.get_object() topic = get_help_topic(obj) return f'{topic} detail' @@ -261,14 +225,15 @@ class HelpDetailView(HelpMixin, DetailView): context (dict): Django context object """ - log_info('get_context_data') context = super().get_context_data(**kwargs) - # Get the object in question - obj = self.get_object() - - # Get queryset and filter out non-related categories + # get a full query set full_set = self.get_queryset() + + # Get the object in question + obj = self.get_object(full_set) + + # filter non related caegories from the query set obj_category = get_help_category(obj) category_set = [] for entry in full_set: @@ -277,9 +242,7 @@ class HelpDetailView(HelpMixin, DetailView): category_set.append(entry) context["topic_list"] = category_set - # log_info(f'category_set: {category_set}') - - # Find the index position of the given obj in the queryset + # Find the index position of the given obj in the category set objs = list(category_set) for i, x in enumerate(objs): if obj is x: @@ -298,7 +261,7 @@ class HelpDetailView(HelpMixin, DetailView): except: context["topic_previous"] = None - # Format the help entry using HTML instead of newlines + # Get the help entry text text = 'Failed to find entry.' if inherits_from(obj, "evennia.commands.command.Command"): text = obj.__doc__ @@ -308,7 +271,7 @@ class HelpDetailView(HelpMixin, DetailView): text = obj.entrytext text = strip_ansi(text) # remove ansii markups context["entry_text"] = text.strip() - log_info('get_context_data success') + return context def get_object(self, queryset=None): @@ -316,11 +279,13 @@ class HelpDetailView(HelpMixin, DetailView): Override of Django hook that retrieves an object by category and topic instead of pk and slug. + Args: + queryset (list): A list of help entry objects. + Returns: - entry (HelpEntry): HelpEntry requested in the URL. + entry (HelpEntry, FileHelpEntry or Command): HelpEntry requested in the URL. """ - log_info('get_object start') # Get the queryset for the help entries the user can access if not queryset: queryset = self.get_queryset() @@ -334,19 +299,18 @@ class HelpDetailView(HelpMixin, DetailView): for entry in queryset: # continue to next entry if the topics do not match entry_topic = get_help_topic(entry) - if not entry_topic.lower() == topic.replace('-', ' '): + if not slugify(entry_topic) == topic: continue # if the category also matches, object requested is found entry_category = get_help_category(entry) - if entry_category.lower() == category.replace('-', ' '): + if slugify(entry_category) == category: obj = entry break # Check if this object was requested in a valid manner if not obj: return HttpResponseBadRequest( - f"No ({category}/{topic})s found matching the query" + f"No ({category}/{topic})s found matching the query." ) - log_info(f'get_obj returning {obj}') return obj