Add support for user preferences
authorJeremy Stanley <fungi@yuggoth.org>
Tue, 22 Jan 2019 01:44:57 +0000 (01:44 +0000)
committerJeremy Stanley <fungi@yuggoth.org>
Tue, 22 Jan 2019 02:25:54 +0000 (02:25 +0000)
Make it possible for users to list, view and set values of any
account facets white-listed in configuration. Also add
administrator-only preferences as a convenience option. To have a
means of exercising this, make the active state prompt dynamic so
that each user can set it as a preferences. Include sample
configuration, regression tests and documentation.

doc/source/configuration.rst
doc/source/data_model.rst
etc/mudpy.yaml
mudpy/command.py
mudpy/misc.py
mudpy/tests/fixtures/test_daemon.yaml
mudpy/tests/selftest.py
share/command.yaml

index bca9161..d0f8093 100644 (file)
@@ -2,7 +2,7 @@
  configuration
 ===============
 
-.. Copyright (c) 2004-2018 mudpy authors. Permission to use, copy,
+.. Copyright (c) 2004-2019 mudpy authors. Permission to use, copy,
    modify, and distribute this software is granted under terms
    provided in the LICENSE file distributed with this software.
 
@@ -422,3 +422,36 @@ written.
 Example::
 
   .mudpy.timing.status: 6000
+
+.mudpy.user
+-----------
+
+.mudpy.user.pref_admin
+~~~~~~~~~~~~~~~~~~~~~~
+
+list, optional
+
+This can be used to list facets an administrative user is allowed to
+set or override on their own ``account`` element, in addition to any
+in the `.mudpy.user.pref_allow`_ list. Note that this is merely a
+convenience, as an administrator is already able to call the ``set``
+command to set values for facets of any element.
+
+Example::
+
+  .mudpy.user.pref_admin:
+      - loglevel
+
+.mudpy.user.pref_allow
+~~~~~~~~~~~~~~~~~~~~~~
+
+list, optional
+
+This can be used to list facets any user is allowed to set or
+override on their own ``account`` element with the ``preference``
+command.
+
+Example::
+
+  .mudpy.user.pref_allow:
+      - prompt
index af7a4b0..807c788 100644 (file)
@@ -2,7 +2,7 @@
  data model
 ============
 
-.. Copyright (c) 2004-2018 mudpy authors. Permission to use, copy,
+.. Copyright (c) 2004-2019 mudpy authors. Permission to use, copy,
    modify, and distribute this software is granted under terms
    provided in the LICENSE file distributed with this software.
 
@@ -127,6 +127,11 @@ kept by default.
 
 Timing-specific settings and scheduling for the main loop.
 
+.mudpy.user
+~~~~~~~~~~~
+
+User-focused settings such as access controls.
+
 storage
 -------
 
index 3cc39d9..8eccba3 100644 (file)
@@ -1,5 +1,5 @@
 ---
-_copy: Copyright (c) 2004-2017 mudpy authors. Permission to use, copy,
+_copy: Copyright (c) 2004-2019 mudpy authors. Permission to use, copy,
     modify, and distribute this software is granted under terms
     provided in the LICENSE file distributed with this software.
 
@@ -89,3 +89,8 @@ _lock: true
 .mudpy.timing.increment: 0.1
 .mudpy.timing.save: 600
 .mudpy.timing.status: 6000
+
+.mudpy.user.pref_admin:
+    - loglevel
+.mudpy.user.pref_allow:
+    - prompt
index 2eaf383..ebd9036 100644 (file)
@@ -235,6 +235,40 @@ def move(actor, parameters):
         actor.send("You cannot go that way.")
 
 
+def preferences(actor, parameters):
+    """List, view and change actor preferences."""
+    message = ""
+    arguments = parameters.split()
+    allowed_prefs = set()
+    user_config = actor.universe.contents.get("mudpy.user")
+    if user_config:
+        allowed_prefs.update(user_config.get("pref_allow", []))
+        if actor.owner.account.get("administrator"):
+            allowed_prefs.update(user_config.get("pref_admin", []))
+    if not arguments:
+        message += "These are your current preferences:"
+        for pref in allowed_prefs:
+            message += ("$(eol)   $(red)%s $(grn)%s$(nrm)"
+                        % (pref, actor.owner.account.get(pref)))
+    elif arguments[0] not in allowed_prefs:
+        message += (
+            'Preference "%s" does not exist. Try the `preferences` command by '
+            "itself for a list of valid preferences." % arguments[0])
+    elif len(arguments) == 1:
+        message += "%s" % actor.owner.account.get(arguments[0])
+    else:
+        pref = arguments[0]
+        value = " ".join(arguments[1:])
+        try:
+            actor.owner.account.set(pref, value)
+            message += 'Preference "%s" set to "%s".' % (pref, value)
+        except ValueError:
+            message = (
+                'Preference "%s" cannot be set to type "%s".' % (
+                    pref, type(value)))
+    actor.send(message)
+
+
 def quit(actor):
     """Leave the world and go back to the main menu."""
     if actor.owner:
index 930d4d7..2bf4db3 100644 (file)
@@ -1,6 +1,6 @@
 """Miscellaneous functions for the mudpy engine."""
 
-# Copyright (c) 2004-2018 mudpy authors. Permission to use, copy,
+# Copyright (c) 2004-2019 mudpy authors. Permission to use, copy,
 # modify, and distribute this software is granted under terms
 # provided in the LICENSE file distributed with this software.
 
@@ -722,7 +722,7 @@ class User:
                 if not just_prompt:
                     output += "$(eol)"
                 if add_prompt:
-                    output += "> "
+                    output += self.account.get("prompt", ">") + " "
                     mode = self.avatar.get("mode")
                     if mode:
                         output += "(" + mode + ") "
index a2bf565..8edfc59 100644 (file)
@@ -1,5 +1,5 @@
 ---
-_copy: Copyright (c) 2004-2017 mudpy authors. Permission to use, copy,
+_copy: Copyright (c) 2004-2019 mudpy authors. Permission to use, copy,
     modify, and distribute this software is granted under terms
     provided in the LICENSE file distributed with this software.
 
@@ -90,3 +90,8 @@ _lock: true
 .mudpy.timing.increment: 0.1
 .mudpy.timing.save: 5
 .mudpy.timing.status: 25
+
+.mudpy.user.pref_admin:
+    - loglevel
+.mudpy.user.pref_allow:
+    - prompt
index 40ea0f3..43e93ae 100644 (file)
@@ -1,4 +1,4 @@
-# Copyright (c) 2004-2018 mudpy authors. Permission to use, copy,
+# Copyright (c) 2004-2019 mudpy authors. Permission to use, copy,
 # modify, and distribute this software is granted under terms
 # provided in the LICENSE file distributed with this software.
 
@@ -158,6 +158,17 @@ test_admin_setup = (
     (2, "Whom would you like to awaken?", ""),
 )
 
+test_preferences = (
+    (0, "> ", "preferences"),
+    (0, r"prompt \x1b\[32m.*> ", "preferences prompt #"),
+    (0, r"# ", "preferences prompt"),
+    (0, r"#.*# ", "preferences prompt >"),
+    (2, "> ", "preferences loglevel 0"),
+    (2, "> ", "preferences"),
+    (2, r"loglevel \x1b\[32m0\x1b\[0m.*> ", "preferences loglevel zero"),
+    (2, r'''cannot be set to type "<class 'str'>"\..*> ''', ""),
+)
+
 test_crlf_eol = (
     # Send a CR+LF at the end of the line instead of the default CR+NUL,
     # to make sure they're treated the same
@@ -303,6 +314,7 @@ dialogue = (
     (test_actor_disappears, "actor spontaneous disappearance"),
     (test_account1_teardown, "second account teardown"),
     (test_admin_setup, "admin account setup"),
+    (test_preferences, "set and show preferences"),
     (test_crlf_eol, "send crlf from the client as eol"),
     (test_telnet_iac, "escape stray telnet iac bytes"),
     (test_telnet_unknown, "strip unknown telnet command"),
index 08bf518..6d009b2 100644 (file)
@@ -54,6 +54,16 @@ command.move.description: Move in a specific direction.
 command.move.help: You move in a direction by entering:$(eol)$(eol)   move
     north
 
+command.preferences.action: mudpy.command.preferences(actor, parameters)
+command.preferences.description: View or change your preferences.
+command.preferences.help: If invoked with no parameters, all your current
+    preferences and their values are listed. If one parameter is supplied, the
+    value of the preference with that name is displayed. If more than one
+    parameter is supplied, the first must be the name of a preference and the
+    remainder is the value to which you wish to change it.
+    Examples:$(eol)$(eol)   preferences$(eol)   preferences
+    prompt$(eol)   preferences prompt $
+
 command.quit.action: mudpy.command.quit(actor)
 command.quit.description: Leave the World.
 command.quit.help: This will deactivate your avatar and return you to the main