A lot of misc cleanup.
Docstring updates.
Removed code that is not required.
This commit is contained in:
davewiththenicehat 2021-06-05 21:00:19 -04:00
parent 5caaf149f4
commit 4d9308b1d0

View file

@ -11,8 +11,6 @@ from django.views.generic import ListView, DetailView
from django.http import HttpResponseBadRequest from django.http import HttpResponseBadRequest
from evennia.help.models import HelpEntry from evennia.help.models import HelpEntry
from evennia.help.filehelp import FILE_HELP_ENTRIES 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 from evennia.utils.ansi import strip_ansi
DEFAULT_HELP_CATEGORY = settings.DEFAULT_HELP_CATEGORY DEFAULT_HELP_CATEGORY = settings.DEFAULT_HELP_CATEGORY
@ -26,93 +24,69 @@ def get_help_category(help_entry, slugify_cat=True):
slugify_cat (bool): If true the return string is slugified. Default is True. slugify_cat (bool): If true the return string is slugified. Default is True.
Notes: Notes:
If the entry does not have attribute 'web_help_entries'. One is created with If an entry does not have a `help_category` attribute, DEFAULT_HELP_CATEGORY from the
a slugified copy of the attribute help_category. settings file is used.
This attribute is used for sorting the entries for the help index (ListView) page. 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: Returns:
help_category (str): The category for the help entry. 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'): if not hasattr(help_entry, 'web_help_category'):
setattr(help_entry, 'web_help_category', slugify(help_entry.help_category)) setattr(help_entry, 'web_help_category', slugify(help_category))
return slugify(help_entry.help_category) if slugify_cat else help_entry.help_category return slugify(help_category) if slugify_cat else help_category
def get_help_topic(help_entry): def get_help_topic(help_entry):
topic = getattr(help_entry, 'key', False) """Get the topic of the help entry.
if not topic:
getattr(help_entry, 'db_key', False)
# log_info(f'get_help_topic returning: {topic}')
return topic
Args:
help_entry (HelpEntry, FileHelpEntry or Command): Help entry instance.
def can_read_topic(cmd_or_topic, caller): Returns:
topic (str): The topic of the help entry. Default is 'unknown_topic'.
""" """
Helper method. If this return True, the given help topic return getattr(help_entry, 'key', 'unknown_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. def can_read_topic(cmd_or_topic, account):
"""Check if an account or puppet has read access to a help entry.
Args: Args:
cmd_or_topic (Command, HelpEntry or FileHelpEntry): The topic/command to test. 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: Returns:
bool: If command can be viewed or not. bool: If command can be viewed or not.
Notes: Notes:
This uses the 'read' lock. If no 'read' lock is defined, the topic is assumed readable This uses the 'read' lock. If no 'read' lock is defined, the topic is assumed readable
by all. 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.
""" """
if inherits_from(cmd_or_topic, "evennia.commands.command.Command"): 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) return cmd_or_topic.auto_help and cmd_or_topic.access(account, 'read', default=True)
else: else:
return cmd_or_topic.access(caller, 'read', default=True) return cmd_or_topic.access(account, 'read', default=True)
def can_list_topic(cmd_or_topic, caller): def collect_topics(account):
""" """Collect help topics from all sources (cmd/db/file).
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.
Args: Args:
cmd_or_topic (Command, HelpEntry or FileHelpEntry): The topic/command to test. account (Character or Account): Account or Character to collect help topics from.
caller: the caller checking for access.
Returns: Returns:
bool: If command should be listed or not. cmd_help_topics (dict): contains Command instances.
Notes: db_help_topics (dict): contains HelpEntry instances.
By default, the 'view' lock will be checked, and if no such lock is defined, the 'read' file_help_topics (dict): contains FileHelpEntry instances
lock will be used. If neither lock is defined, the help entry is assumed to be
accessible to all.
""" """
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: # collect commands of account and all puppets
return cmd_or_topic.access(caller, 'view', default=True) # skip a command if an entry is recorded with the same topics, category and help entry
else:
# no explicit 'view' lock - use the 'read' lock
return cmd_or_topic.access(caller, '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 = [] cmd_help_topics = []
if not str(account) == 'AnonymousUser': if not str(account) == 'AnonymousUser':
# create list of account and account's puppets # create list of account and account's puppets
@ -129,6 +103,9 @@ def collect_topics(account, mode='list'):
# skip the command if the puppet does not have access # skip the command if the puppet does not have access
if not cmd.access(puppet, 'cmd'): if not cmd.access(puppet, 'cmd'):
continue 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 # skip the command if it's help entry already exists in the topic list
entry_exists = False entry_exists = False
for verify_cmd in cmd_help_topics: for verify_cmd in cmd_help_topics:
@ -141,47 +118,32 @@ def collect_topics(account, mode='list'):
continue continue
# add this command to the list # add this command to the list
cmd_help_topics.append(cmd) cmd_help_topics.append(cmd)
# get all file-based help entries, checking perms
# Verify account has read access to filehelp entries and gather them into a dictionary
file_help_topics = { file_help_topics = {
topic.key.lower().strip(): topic topic.key.lower().strip(): topic
for topic in FILE_HELP_ENTRIES.all() for topic in FILE_HELP_ENTRIES.all()
if can_read_topic(topic, account)
} }
# get db-based help entries, checking perms
# Verify account has read access to database entries and gather them into a dictionary
db_help_topics = { db_help_topics = {
topic.key.lower().strip(): topic topic.key.lower().strip(): topic
for topic in HelpEntry.objects.all() for topic in HelpEntry.objects.all()
if can_read_topic(topic, account)
} }
if mode == 'list':
# check the view lock for all help entries/commands and determine key # Collect commands into a dictionary, read access verified at puppet level
cmd_help_topics = { cmd_help_topics = {
cmd.auto_help_display_key cmd.auto_help_display_key
if hasattr(cmd, "auto_help_display_key") else cmd.key: cmd if hasattr(cmd, "auto_help_display_key") else cmd.key: cmd
for cmd in cmd_help_topics if can_list_topic(cmd, account)} for cmd in cmd_help_topics
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)}
return cmd_help_topics, db_help_topics, file_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. 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. and other documentation that the current user is allowed to see.
Returns: 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 account = self.request.user
# collect all help entries # 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 # merge the entries
file_db_help_topics = {**file_help_topics, **db_help_topics} file_db_help_topics = {**file_help_topics, **db_help_topics}
all_topics = {**file_db_help_topics, **cmd_help_topics} all_topics = {**file_db_help_topics, **cmd_help_topics}
all_entries = list(all_topics.values()) all_entries = list(all_topics.values())
# sort the entries # sort the entries
all_entries = sorted(all_entries, key=get_help_topic) # sort alphabetically all_entries = sorted(all_entries, key=get_help_topic) # sort alphabetically
all_entries.sort(key=get_help_category) # group by categories all_entries.sort(key=get_help_category) # group by categories
log_info('get_queryset success')
return all_entries return all_entries
@ -242,12 +206,12 @@ class HelpDetailView(HelpMixin, DetailView):
""" """
# -- Django constructs -- # -- Django constructs --
# the html template to use when contructing the detail page for a help topic
template_name = "website/help_detail.html" template_name = "website/help_detail.html"
@property @property
def page_title(self): def page_title(self):
# Makes sure the page has a sensible title. # Makes sure the page has a sensible title.
# return "%s Detail" % self.typeclass._meta.verbose_name.title()
obj = self.get_object() obj = self.get_object()
topic = get_help_topic(obj) topic = get_help_topic(obj)
return f'{topic} detail' return f'{topic} detail'
@ -261,14 +225,15 @@ class HelpDetailView(HelpMixin, DetailView):
context (dict): Django context object context (dict): Django context object
""" """
log_info('get_context_data')
context = super().get_context_data(**kwargs) context = super().get_context_data(**kwargs)
# Get the object in question # get a full query set
obj = self.get_object()
# Get queryset and filter out non-related categories
full_set = self.get_queryset() 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) obj_category = get_help_category(obj)
category_set = [] category_set = []
for entry in full_set: for entry in full_set:
@ -277,9 +242,7 @@ class HelpDetailView(HelpMixin, DetailView):
category_set.append(entry) category_set.append(entry)
context["topic_list"] = category_set context["topic_list"] = category_set
# log_info(f'category_set: {category_set}') # Find the index position of the given obj in the category set
# Find the index position of the given obj in the queryset
objs = list(category_set) objs = list(category_set)
for i, x in enumerate(objs): for i, x in enumerate(objs):
if obj is x: if obj is x:
@ -298,7 +261,7 @@ class HelpDetailView(HelpMixin, DetailView):
except: except:
context["topic_previous"] = None context["topic_previous"] = None
# Format the help entry using HTML instead of newlines # Get the help entry text
text = 'Failed to find entry.' text = 'Failed to find entry.'
if inherits_from(obj, "evennia.commands.command.Command"): if inherits_from(obj, "evennia.commands.command.Command"):
text = obj.__doc__ text = obj.__doc__
@ -308,7 +271,7 @@ class HelpDetailView(HelpMixin, DetailView):
text = obj.entrytext text = obj.entrytext
text = strip_ansi(text) # remove ansii markups text = strip_ansi(text) # remove ansii markups
context["entry_text"] = text.strip() context["entry_text"] = text.strip()
log_info('get_context_data success')
return context return context
def get_object(self, queryset=None): 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 Override of Django hook that retrieves an object by category and topic
instead of pk and slug. instead of pk and slug.
Args:
queryset (list): A list of help entry objects.
Returns: 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 # Get the queryset for the help entries the user can access
if not queryset: if not queryset:
queryset = self.get_queryset() queryset = self.get_queryset()
@ -334,19 +299,18 @@ class HelpDetailView(HelpMixin, DetailView):
for entry in queryset: for entry in queryset:
# continue to next entry if the topics do not match # continue to next entry if the topics do not match
entry_topic = get_help_topic(entry) entry_topic = get_help_topic(entry)
if not entry_topic.lower() == topic.replace('-', ' '): if not slugify(entry_topic) == topic:
continue continue
# if the category also matches, object requested is found # if the category also matches, object requested is found
entry_category = get_help_category(entry) entry_category = get_help_category(entry)
if entry_category.lower() == category.replace('-', ' '): if slugify(entry_category) == category:
obj = entry obj = entry
break break
# Check if this object was requested in a valid manner # Check if this object was requested in a valid manner
if not obj: if not obj:
return HttpResponseBadRequest( 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 return obj