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 fa5d152b51
commit 93c673540f

View file

@ -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