mirror of
https://github.com/evennia/evennia.git
synced 2026-03-16 21:06:30 +01:00
Add locks to filehelp entities. Test view/read locks
This commit is contained in:
parent
905cc78069
commit
0fb29073b2
3 changed files with 99 additions and 59 deletions
|
|
@ -259,46 +259,46 @@ class CmdHelp(COMMAND_DEFAULT_CLASS):
|
|||
|
||||
return help_index
|
||||
|
||||
def check_show_help(self, cmd, caller):
|
||||
def check_show_help(self, cmd_or_topic, caller):
|
||||
"""
|
||||
Helper method. If this return True, the given cmd
|
||||
auto-help will be viewable in the help listing.
|
||||
Override this to easily select what is shown to
|
||||
the account. Note that only commands available
|
||||
in the caller's merged cmdset are available.
|
||||
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 (Command): Command class from the merged cmdset
|
||||
caller (Character, Account or Session): The current caller
|
||||
executing the help command.
|
||||
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.
|
||||
|
||||
"""
|
||||
# return only those with auto_help set and passing the cmd: lock
|
||||
return cmd.auto_help and cmd.access(caller)
|
||||
if inherits_from(cmd_or_topic, "evennia.commands.command.Command"):
|
||||
return cmd_or_topic.auto_help and cmd_or_topic.access(caller)
|
||||
else:
|
||||
return cmd_or_topic.access(caller, 'read', default=True)
|
||||
|
||||
def should_list_cmd(self, cmd, caller):
|
||||
def should_list_topic(self, cmd_or_topic, caller):
|
||||
"""
|
||||
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 'check_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.
|
||||
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 'check_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:
|
||||
cmd: the command to be tested.
|
||||
caller: the caller of the help system.
|
||||
cmd_or_topic (Command, HelpEntry or FileHelpEntry): The topic/command to test.
|
||||
caller: the caller checking for access.
|
||||
|
||||
Return:
|
||||
True: the command should appear in the table.
|
||||
False: the command shouldn't appear in the table.
|
||||
Returns:
|
||||
bool: If command should be listed or not.
|
||||
|
||||
"""
|
||||
return True
|
||||
return cmd_or_topic.access(caller, 'view', default=True)
|
||||
|
||||
def parse(self):
|
||||
"""
|
||||
|
|
@ -336,39 +336,49 @@ class CmdHelp(COMMAND_DEFAULT_CLASS):
|
|||
cmdset.make_unique(caller)
|
||||
|
||||
# retrieve all available commands and database / file-help topics
|
||||
all_cmds = [cmd for cmd in cmdset if self.check_show_help(cmd, caller)]
|
||||
all_cmd_topics = [cmd for cmd in cmdset if self.check_show_help(cmd, caller) if cmd]
|
||||
|
||||
# we group the file-help topics with the db ones, giving the db ones priority
|
||||
file_help_topics = FILE_HELP_ENTRIES.all(return_dict=True)
|
||||
db_topics = {
|
||||
topic.key.lower().strip(): topic for topic in HelpEntry.objects.all()
|
||||
if topic.access(caller, "view", default=True)
|
||||
# get all file-based help entries, checking perms
|
||||
file_help_topics = {
|
||||
topic.key.lower().strip(): topic
|
||||
for topic in FILE_HELP_ENTRIES.all()
|
||||
if topic.access(caller)
|
||||
}
|
||||
all_db_topics = list({**file_help_topics, **db_topics}.values())
|
||||
# get db-based help entries, checking perms
|
||||
db_topics = {
|
||||
topic.key.lower().strip(): topic
|
||||
for topic in HelpEntry.objects.all()
|
||||
if topic.access(caller)
|
||||
}
|
||||
# merge so db topics override file topics with same key
|
||||
all_file_db_topics = list({**file_help_topics, **db_topics}.values())
|
||||
|
||||
# get all categories
|
||||
all_categories = list(set(
|
||||
[HelpCategory(cmd.help_category) for cmd in all_cmds]
|
||||
+ [HelpCategory(topic.help_category) for topic in all_db_topics]
|
||||
[HelpCategory(cmd.help_category) for cmd in all_cmd_topics]
|
||||
+ [HelpCategory(topic.help_category) for topic in all_file_db_topics]
|
||||
))
|
||||
|
||||
if not query:
|
||||
# list all available help entries, grouped by category. We want to
|
||||
# build dictionaries {category: [topic, topic, ...], ...}
|
||||
cmd_help_dict = defaultdict(list)
|
||||
db_help_dict = defaultdict(list)
|
||||
file_db_help_dict = defaultdict(list)
|
||||
|
||||
# Filter commands that should be reached by the help
|
||||
# Filter commands/topics that should be reached by the help
|
||||
# system, but not be displayed in the table, or be displayed differently.
|
||||
for cmd in all_cmds:
|
||||
if self.should_list_cmd(cmd, caller):
|
||||
key = (cmd.auto_help_display_key
|
||||
if hasattr(cmd, "auto_help_display_key") else cmd.key)
|
||||
for cmd in all_cmd_topics:
|
||||
if self.should_list_topic(cmd, caller):
|
||||
key = (
|
||||
cmd.auto_help_display_key
|
||||
if hasattr(cmd, "auto_help_display_key") else cmd.key
|
||||
)
|
||||
cmd_help_dict[cmd.help_category].append(key)
|
||||
for topic in all_file_db_topics:
|
||||
if self.should_list_topic(topic, caller):
|
||||
file_db_help_dict[topic.help_category].append(topic.key)
|
||||
|
||||
for db_topic in all_db_topics:
|
||||
db_help_dict[db_topic.help_category].append(db_topic.key)
|
||||
|
||||
output = self.format_help_index(cmd_help_dict, db_help_dict)
|
||||
output = self.format_help_index(cmd_help_dict, file_db_help_dict)
|
||||
self.msg_help(output)
|
||||
|
||||
return
|
||||
|
|
@ -376,8 +386,8 @@ class CmdHelp(COMMAND_DEFAULT_CLASS):
|
|||
# We have a query - try to find a specific topic/category using the
|
||||
# Lunr search engine
|
||||
|
||||
# all available options
|
||||
entries = [cmd for cmd in all_cmds if cmd] + all_db_topics + all_categories
|
||||
# all available help options - will be searched in order
|
||||
entries = all_cmd_topics + all_file_db_topics + all_categories
|
||||
|
||||
# lunr search fields/boosts
|
||||
search_fields = [
|
||||
|
|
@ -443,14 +453,14 @@ class CmdHelp(COMMAND_DEFAULT_CLASS):
|
|||
{
|
||||
match.key: [
|
||||
cmd.key
|
||||
for cmd in all_cmds
|
||||
for cmd in all_cmd_topics
|
||||
if match.key.lower() == cmd.help_category
|
||||
]
|
||||
},
|
||||
{
|
||||
match.key: [
|
||||
topic.key
|
||||
for topic in all_db_topics
|
||||
for topic in all_file_db_topics
|
||||
if match.key.lower() == topic.help_category
|
||||
]
|
||||
},
|
||||
|
|
|
|||
|
|
@ -13,12 +13,13 @@ Each help-entry dict is on the form
|
|||
::
|
||||
|
||||
{'key': <str>,
|
||||
'text': <str>,
|
||||
'category': <str>, # optional, otherwise settings.DEFAULT_HELP_CATEGORY
|
||||
'aliases': <list>, # optional
|
||||
'text': <str>}
|
||||
'locks': <str>} # optional, use access-type 'view'. Default is view:all()
|
||||
|
||||
where the `category` is optional and the `text`` should be formatted on the
|
||||
same form as other help entry-texts and contain ``# subtopics`` as normal.
|
||||
The `text`` should be formatted on the same form as other help entry-texts and
|
||||
can contain ``# subtopics`` as normal.
|
||||
|
||||
New help-entry modules are added to the system by providing the python-path to
|
||||
the module to `settings.FILE_HELP_ENTRY_MODULES`. Note that if same-key entries are
|
||||
|
|
@ -33,6 +34,7 @@ An example of the contents of a module:
|
|||
"key": "The Gods", # case-insensitive, also partial-matching ('gods') works
|
||||
"aliases": ['pantheon', 'religion'],
|
||||
"category": "Lore",
|
||||
"locks": "view:all()", # this is optional unless restricting access
|
||||
"text": '''
|
||||
The gods formed the world ...
|
||||
|
||||
|
|
@ -68,6 +70,8 @@ from django.conf import settings
|
|||
from evennia.utils.utils import (
|
||||
variable_from_module, make_iter, all_from_module)
|
||||
from evennia.utils import logger
|
||||
from evennia.utils.utils import lazy_property
|
||||
from evennia.locks.lockhandler import LockHandler
|
||||
|
||||
_DEFAULT_HELP_CATEGORY = settings.DEFAULT_HELP_CATEGORY
|
||||
|
||||
|
|
@ -84,6 +88,7 @@ class FileHelpEntry:
|
|||
aliases: list
|
||||
help_category: str
|
||||
entrytext: str
|
||||
lock_storage: str
|
||||
|
||||
@property
|
||||
def search_index_entry(self):
|
||||
|
|
@ -96,6 +101,7 @@ class FileHelpEntry:
|
|||
"aliases": " ".join(self.aliases),
|
||||
"category": self.help_category,
|
||||
"tags": "",
|
||||
"locks": "",
|
||||
"text": self.entrytext,
|
||||
}
|
||||
|
||||
|
|
@ -105,6 +111,22 @@ class FileHelpEntry:
|
|||
def __repr__(self):
|
||||
return f"<FileHelpEntry {self.key}>"
|
||||
|
||||
@lazy_property
|
||||
def locks(self):
|
||||
return LockHandler(self)
|
||||
|
||||
def access(self, accessing_obj, access_type="view", default=True):
|
||||
"""
|
||||
Determines if another object has permission to access this help entry.
|
||||
|
||||
Args:
|
||||
accessing_obj (Object or Account): Entity trying to access this one.
|
||||
access_type (str): type of access sought.
|
||||
default (bool): What to return if no lock of `access_type` was found.
|
||||
|
||||
"""
|
||||
return self.locks.check(accessing_obj, access_type=access_type, default=default)
|
||||
|
||||
|
||||
class FileHelpStorageHandler:
|
||||
"""
|
||||
|
|
@ -154,14 +176,15 @@ class FileHelpStorageHandler:
|
|||
key = dct.get('key').lower().strip()
|
||||
category = dct.get('category', _DEFAULT_HELP_CATEGORY).strip()
|
||||
aliases = list(dct.get('aliases', []))
|
||||
entrytext = dct.get('text')
|
||||
entrytext = dct.get('text', '')
|
||||
locks = dct.get('locks', '')
|
||||
|
||||
if not key and entrytext:
|
||||
logger.error(f"Cannot load file-help-entry (missing key or text): {dct}")
|
||||
continue
|
||||
|
||||
unique_help_entries[key] = FileHelpEntry(
|
||||
key=key, help_category=category, aliases=aliases,
|
||||
key=key, help_category=category, aliases=aliases, lock_storage=locks,
|
||||
entrytext=entrytext)
|
||||
|
||||
self.help_entries_dict = unique_help_entries
|
||||
|
|
|
|||
|
|
@ -114,12 +114,19 @@ class HelpEntry(SharedMemoryModel):
|
|||
def __repr__(self):
|
||||
return f"<HelpEntry {self.key}>"
|
||||
|
||||
def access(self, accessing_obj, access_type="read", default=False):
|
||||
def access(self, accessing_obj, access_type="read", default=True):
|
||||
"""
|
||||
Determines if another object has permission to access.
|
||||
accessing_obj - object trying to access this one
|
||||
access_type - type of access sought
|
||||
default - what to return if no lock of access_type was found
|
||||
Determines if another object has permission to access this help entry.
|
||||
|
||||
Accesses used by default:
|
||||
'read' - read the help entry itself.
|
||||
'view' - see help entry in help index.
|
||||
|
||||
Args:
|
||||
accessing_obj (Object or Account): Entity trying to access this one.
|
||||
access_type (str): type of access sought.
|
||||
default (bool): What to return if no lock of `access_type` was found.
|
||||
|
||||
"""
|
||||
return self.locks.check(accessing_obj, access_type=access_type, default=default)
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue