OBS: You'll need to resync/rebuild your database!

- This implements an updated, clearer and more robust access system. The policy is now to lock that which is not explicitly left open.
- Permission strings -> Lock strings. Separating permissions and locks makes more sense security-wise
- No more permissiongroup table; permissions instead use a simple tuple PERMISSIONS_HIERARCHY to define an access hierarchy
- Cleaner lock-definition syntax, all based on function calls.
- New objects/players/channels get a default security policy during creation (set through typeclass)

As part of rebuilding and testing the new lock/permission system I got into testing and debugging several other systems, fixing some
outstanding issues:
- @reload now fully updates the database asynchronously. No need to reboot server when changing cmdsets
- Dozens of new test suites added for about 30 commands so far
- Help for channels made more clever and informative.
This commit is contained in:
Griatch 2011-03-15 16:08:32 +00:00
parent c2030c2c0c
commit 08b3de9e5e
49 changed files with 1714 additions and 1877 deletions

View file

@ -8,8 +8,6 @@ from django.conf import settings
from django.contrib.auth.models import User
from src.players.models import PlayerDB
from src.server.sessionhandler import SESSIONS
from src.permissions.permissions import has_perm, has_perm_string
from src.permissions.models import PermissionGroup
from src.utils import utils
from src.commands.default.muxcommand import MuxCommand
@ -29,7 +27,7 @@ class CmdBoot(MuxCommand):
"""
key = "@boot"
permissions = "cmd:boot"
locks = "cmd:perm(boot) or perm(Wizard)"
help_category = "Admin"
def func(self):
@ -60,7 +58,7 @@ class CmdBoot(MuxCommand):
if not pobj:
return
if pobj.character.has_player:
if not has_perm(caller, pobj, 'can_boot'):
if not pobj.access(caller, 'boot'):
string = "You don't have the permission to boot %s."
pobj.msg(string)
return
@ -107,7 +105,7 @@ class CmdDelPlayer(MuxCommand):
"""
key = "@delplayer"
permissions = "cmd:delplayer"
locks = "cmd:perm(delplayer) or perm(Immortals)"
help_category = "Admin"
def func(self):
@ -149,7 +147,7 @@ class CmdDelPlayer(MuxCommand):
except Exception:
player = None
if not has_perm_string(caller, 'manage_players'):
if player and not player.access(caller, 'delete'):
string = "You don't have the permissions to delete this player."
caller.msg(string)
return
@ -166,20 +164,19 @@ class CmdDelPlayer(MuxCommand):
caller.msg(string)
return
elif len(players) > 1:
string = "There where multiple matches:"
elif utils.is_iter(players):
string = "There were multiple matches:"
for player in players:
string += "\n %s %s" % (player.id, player.key)
return
else:
# one single match
player = players[0]
player = players
user = player.user
character = player.character
if not has_perm(caller, player, 'manage_players'):
if not player.access(caller, 'delete'):
string = "You don't have the permissions to delete that player."
caller.msg(string)
return
@ -209,7 +206,7 @@ class CmdEmit(MuxCommand):
@pemit [<obj>, <obj>, ... =] <message>
Switches:
room : limit emits to rooms only
room : limit emits to rooms only (default)
players : limit emits to players only
contents : send to the contents of matched objects too
@ -221,7 +218,7 @@ class CmdEmit(MuxCommand):
"""
key = "@emit"
aliases = ["@pemit", "@remit"]
permissions = "cmd:emit"
locks = "cmd:perm(emit) or perm(Builders)"
help_category = "Admin"
def func(self):
@ -266,7 +263,7 @@ class CmdEmit(MuxCommand):
if players_only and not obj.has_player:
caller.msg("%s has no active player. Ignored." % objname)
continue
if has_perm(caller, obj, 'send_to'):
if obj.access(caller, 'tell'):
obj.msg(message)
if send_to_contents:
for content in obj.contents:
@ -290,7 +287,7 @@ class CmdNewPassword(MuxCommand):
"""
key = "@userpassword"
permissions = "cmd:newpassword"
locks = "cmd:perm(newpassword) or perm(Wizards)"
help_category = "Admin"
def func(self):
@ -303,14 +300,13 @@ class CmdNewPassword(MuxCommand):
return
# the player search also matches 'me' etc.
character = caller.search("*%s" % self.lhs, global_search=True)
if not character:
player = caller.search("*%s" % self.lhs, global_search=True)
if not player:
return
player = character.player
player.user.set_password(self.rhs)
player.user.save()
caller.msg("%s - new password set to '%s'." % (player.name, self.rhs))
if character != caller:
if player.character != caller:
player.msg("%s has changed your password to '%s'." % (caller.name, self.rhs))
@ -333,7 +329,7 @@ class CmdPerm(MuxCommand):
"""
key = "@perm"
aliases = "@setperm"
permissions = "cmd:perm"
locks = "cmd:perm(perm) or perm(Immortals)"
help_category = "Admin"
def func(self):
@ -434,7 +430,7 @@ class CmdPuppet(MuxCommand):
"""
key = "@puppet"
permissions = "cmd:puppet"
locks = "cmd:perm(puppet) or perm(Builders)"
help_category = "Admin"
def func(self):
@ -453,6 +449,8 @@ class CmdPuppet(MuxCommand):
if not utils.inherits_from(new_character, settings.BASE_CHARACTER_TYPECLASS):
caller.msg("%s is not a Character." % self.args)
return
if new_character.player:
caller.msg("This character is already under the control of a player.")
if player.swap_character(new_character):
new_character.msg("You now control %s." % new_character.name)
else:
@ -468,7 +466,7 @@ class CmdWall(MuxCommand):
Announces a message to all connected players.
"""
key = "@wall"
permissions = "cmd:wall"
locks = "cmd:perm(wall) or perm(Wizards)"
help_category = "Admin"
def func(self):

View file

@ -193,7 +193,7 @@ class CmdBatchCommands(MuxCommand):
"""
key = "@batchcommands"
aliases = ["@batchcommand", "@batchcmd"]
permissions = "cmd:batchcommands"
locks = "cmd:perm(batchcommands)"
help_category = "Building"
def func(self):
@ -277,7 +277,7 @@ class CmdBatchCode(MuxCommand):
"""
key = "@batchcode"
aliases = ["@batchcodes"]
permissions = "cmd:batchcodes"
locks = "cmd:perm(batchcommands)"
help_category = "Building"
def func(self):
@ -359,6 +359,7 @@ class CmdStateAbort(MuxCommand):
"""
key = "@abort"
help_category = "BatchProcess"
locks = "cmd:perm(batchcommands)"
def func(self):
"Exit back to default."
@ -374,6 +375,7 @@ class CmdStateLL(MuxCommand):
"""
key = "ll"
help_category = "BatchProcess"
locks = "cmd:perm(batchcommands)"
def func(self):
show_curr(self.caller, showall=True)
@ -386,6 +388,7 @@ class CmdStatePP(MuxCommand):
"""
key = "pp"
help_category = "BatchProcess"
locks = "cmd:perm(batchcommands)"
def func(self):
"""
@ -407,6 +410,7 @@ class CmdStateRR(MuxCommand):
"""
key = "rr"
help_category = "BatchProcess"
locks = "cmd:perm(batchcommands)"
def func(self):
caller = self.caller
@ -426,6 +430,7 @@ class CmdStateRRR(MuxCommand):
"""
key = "rrr"
help_category = "BatchProcess"
locks = "cmd:perm(batchcommands)"
def func(self):
caller = self.caller
@ -445,6 +450,7 @@ class CmdStateNN(MuxCommand):
"""
key = "nn"
help_category = "BatchProcess"
locks = "cmd:perm(batchcommands)"
def func(self):
caller = self.caller
@ -465,6 +471,7 @@ class CmdStateNL(MuxCommand):
"""
key = "nl"
help_category = "BatchProcess"
locks = "cmd:perm(batchcommands)"
def func(self):
caller = self.caller
@ -485,6 +492,7 @@ class CmdStateBB(MuxCommand):
"""
key = "bb"
help_category = "BatchProcess"
locks = "cmd:perm(batchcommands)"
def func(self):
caller = self.caller
@ -505,6 +513,7 @@ class CmdStateBL(MuxCommand):
"""
key = "bl"
help_category = "BatchProcess"
locks = "cmd:perm(batchcommands)"
def func(self):
caller = self.caller
@ -526,6 +535,7 @@ class CmdStateSS(MuxCommand):
"""
key = "ss"
help_category = "BatchProcess"
locks = "cmd:perm(batchcommands)"
def func(self):
caller = self.caller
@ -553,6 +563,7 @@ class CmdStateSL(MuxCommand):
"""
key = "sl"
help_category = "BatchProcess"
locks = "cmd:perm(batchcommands)"
def func(self):
caller = self.caller
@ -579,6 +590,7 @@ class CmdStateCC(MuxCommand):
"""
key = "cc"
help_category = "BatchProcess"
locks = "cmd:perm(batchcommands)"
def func(self):
caller = self.caller
@ -608,6 +620,7 @@ class CmdStateJJ(MuxCommand):
"""
key = "j"
help_category = "BatchProcess"
locks = "cmd:perm(batchcommands)"
def func(self):
caller = self.caller
@ -630,6 +643,7 @@ class CmdStateJL(MuxCommand):
"""
key = "jl"
help_category = "BatchProcess"
locks = "cmd:perm(batchcommands)"
def func(self):
caller = self.caller
@ -652,6 +666,7 @@ class CmdStateQQ(MuxCommand):
"""
key = "qq"
help_category = "BatchProcess"
locks = "cmd:perm(batchcommands)"
def func(self):
purge_processor(self.caller)
@ -662,6 +677,7 @@ class CmdStateHH(MuxCommand):
key = "hh"
help_category = "BatchProcess"
locks = "cmd:perm(batchcommands)"
def func(self):
string = """

View file

@ -5,7 +5,6 @@ Building and world design commands
"""
from django.conf import settings
from src.permissions.permissions import has_perm, has_perm_string
from src.objects.models import ObjectDB, ObjAttribute
from src.utils import create, utils, debug
from src.commands.default.muxcommand import MuxCommand
@ -121,7 +120,7 @@ class CmdSetObjAlias(MuxCommand):
key = "@alias"
aliases = "@setobjalias"
permissions = "cmd:setobjalias"
locks = "cmd:perm(setobjalias) or perm(Builders)"
help_category = "Building"
def func(self):
@ -143,7 +142,7 @@ class CmdSetObjAlias(MuxCommand):
else:
caller.msg("No aliases exist for '%s'." % obj.key)
return
if not has_perm(caller, obj, 'modify_attributes'):
if not obj.access(caller, 'edit'):
caller.msg("You don't have permission to do that.")
return
if not aliases or not aliases[0]:
@ -164,7 +163,7 @@ class CmdSetObjAlias(MuxCommand):
aliases = list(set(old_aliases))
# save back to object.
obj.aliases = aliases
caller.msg("Aliases for '%s' are now set to %s." % (obj.key, obj.aliases))
caller.msg("Aliases for '%s' are now set to %s." % (obj.key, ", ".join(obj.aliases)))
class CmdCopy(ObjManipCommand):
"""
@ -183,7 +182,7 @@ class CmdCopy(ObjManipCommand):
"""
key = "@copy"
permissions = "cmd:copy"
locks = "cmd:perm(copy) or perm(Builders)"
help_category = "Building"
def func(self):
@ -252,7 +251,7 @@ class CmdCpAttr(MuxCommand):
Copy the attribute one object to one or more attributes on another object.
"""
key = "@cpattr"
permissions = "cmd:cpattr"
locks = "cmd:perm(cpattr) or perm(Builders)"
help_category = "Building"
def func(self):
@ -334,7 +333,7 @@ class CmdCreate(ObjManipCommand):
"""
key = "@create"
permissions = "cmd:create"
locks = "cmd:perm(create) or perm(Builders)"
help_category = "Building"
def func(self):
@ -366,8 +365,10 @@ class CmdCreate(ObjManipCommand):
# create object (if not a valid typeclass, the default
# object typeclass will automatically be used)
lockstring = "owner:id(%s);examine:perm(Builders);delete:id(%s) or perm(Wizards);get:all()" % (caller.id, caller.id)
obj = create.create_object(typeclass, name, caller,
home=caller, aliases=aliases)
home=caller, aliases=aliases, locks=lockstring)
if not obj:
string = "Error when creating object."
continue
@ -412,7 +413,7 @@ class CmdDebug(MuxCommand):
"""
key = "@debug"
permissions = "cmd:debug"
locks = "cmd:perm(debug) or perm(Builders)"
help_category = "Building"
def func(self):
@ -462,7 +463,7 @@ class CmdDesc(MuxCommand):
"""
key = "@desc"
aliases = "@describe"
permissions = "cmd:desc"
locks = "cmd:perm(desc) or perm(Builders)"
help_category = "Building"
def func(self):
@ -504,7 +505,7 @@ class CmdDestroy(MuxCommand):
key = "@destroy"
aliases = "@delete"
permissions = "cmd:destroy"
locks = "cmd:perm(destroy) or perm(Builders)"
help_category = "Building"
def func(self):
@ -525,7 +526,7 @@ class CmdDestroy(MuxCommand):
if obj.player and not 'override' in self.switches:
string = "Object %s is a player object. Use /override to delete anyway." % objname
continue
if not has_perm(caller, obj, 'create'):
if not obj.access(caller, 'delete'):
string = "You don't have permission to delete %s." % objname
continue
# do the deletion
@ -558,7 +559,7 @@ class CmdDig(ObjManipCommand):
like to the name of the room and the exits in question; an example would be 'north;no;n'.
"""
key = "@dig"
permissions = "cmd:dig"
locks = "cmd:perm(dig) or perm(Builders)"
help_category = "Building"
def func(self):
@ -681,7 +682,7 @@ class CmdLink(MuxCommand):
"""
key = "@link"
permissions = "cmd:link"
locks = "cmd:perm(link) or perm(Builders)"
help_category = "Building"
def func(self):
@ -759,7 +760,7 @@ class CmdListCmdSets(MuxCommand):
"""
key = "@cmdsets"
aliases = "@listcmsets"
permissions = "cmd:listcmdsets"
locks = "cmd:perm(listcmdsets) or perm(Builders)"
help_category = "Building"
def func(self):
@ -789,7 +790,7 @@ class CmdMvAttr(ObjManipCommand):
and target are the same, in which case this is like a copy operation)
"""
key = "@mvattr"
permissions = "cmd:mvattr"
locks = "cmd:perm(mvattr) or perm(Builders)"
help_category = "Building"
def func(self):
@ -861,7 +862,7 @@ class CmdName(ObjManipCommand):
key = "@name"
aliases = ["@rename"]
permissions = "cmd:rename"
locks = "cmd:perm(rename) or perm(Builders)"
help_category = "Building"
def func(self):
@ -912,7 +913,7 @@ class CmdOpen(ObjManipCommand):
"""
key = "@open"
permissions = "cmd:open"
locks = "cmd:perm(open) or perm(Builders)"
help_category = "Building"
# a custom member method to chug out exits and do checks
@ -1053,7 +1054,7 @@ class CmdSetAttribute(ObjManipCommand):
"""
key = "@set"
permissions = "cmd:set"
locks = "cmd:perm(set) or perm(Builders)"
help_category = "Building"
def func(self):
@ -1128,7 +1129,7 @@ class CmdTypeclass(MuxCommand):
key = "@typeclass"
aliases = "@type, @parent"
permissions = "cmd:typeclass"
locks = "cmd:perm(typeclass) or perm(Builders)"
help_category = "Building"
def func(self):
@ -1166,7 +1167,7 @@ class CmdTypeclass(MuxCommand):
typeclass = "%s.%s" % (settings.BASE_TYPECLASS_PATH,
typeclass)
if not has_perm(caller, obj, 'change_typeclass'):
if not obj.access(caller, 'edit'):
caller.msg("You are not allowed to do that.")
return
@ -1208,7 +1209,7 @@ class CmdWipe(ObjManipCommand):
matching the given attribute-wildcard search string.
"""
key = "@wipe"
permissions = "cmd:wipe"
locks = "cmd:perm(wipe) or perm(Builders)"
help_category = "Building"
def func(self):
@ -1229,6 +1230,9 @@ class CmdWipe(ObjManipCommand):
obj = caller.search(objname)
if not obj:
return
if not obj.access(caller, 'edit'):
caller.msg("You are not allowed to do that.")
return
if not attrs:
# wipe everything
for attr in obj.get_all_attributes():
@ -1241,7 +1245,90 @@ class CmdWipe(ObjManipCommand):
string = string % (",".join(attrs), obj.name)
caller.msg(string)
class CmdLock(ObjManipCommand):
"""
lock - assign a lock definition to an object
Usage:
@lock <object>[ = <lockstring>]
or
@lock[/switch] object/<access_type>
Switch:
del - delete given access type
view - view lock associated with given access type (default)
If no lockstring is given, shows all locks on
object.
Lockstring is on the form
'access_type:[NOT] func1(args)[ AND|OR][ NOT] func2(args) ...]
Where func1, func2 ... valid lockfuncs with or without arguments.
Separator expressions need not be capitalized.
For example:
'get: id(25) or perm(Wizards)'
The 'get' access_type is checked by the get command and will
an object locked with this string will only be possible to
pick up by Wizards or by object with id 25.
You can add several access_types after oneanother by separating
them by ';', i.e:
'get:id(25);delete:perm(Builders)'
"""
key = "@lock"
aliases = ["@locks", "lock", "locks"]
locks = "cmd: perm(@locks) or perm(Builders)"
help_category = "Building"
def func(self):
"Sets up the command"
caller = self.caller
if not self.args:
string = "@lock <object>[ = <lockstring>] or @lock[/switch] object/<access_type>"
caller.msg(string)
return
if '/' in self.lhs:
# call on the form @lock obj/access_type
objname, access_type = [p.strip() for p in self.lhs.split('/', 1)]
obj = caller.search(objname)
if not obj:
return
lockdef = obj.locks.get(access_type)
if lockdef:
string = lockdef[2]
if 'del' in self.switches:
if obj.access(caller, 'edit'):
caller.msg("You are not allowed to do that.")
return
obj.locks.delete(access_type)
string = "deleted lock %s" % string
else:
string = "%s has no lock of access type '%s'." % (obj, access_type)
caller.msg(string)
return
if self.rhs:
# we have a = separator, so we are assigning a new lock
objname, lockdef = self.lhs, self.rhs
obj = caller.search(objname)
if not obj:
return
if obj.access(caller, 'edit'):
caller.msg("You are not allowed to do that.")
return
ok = obj.locks.add(lockdef, caller)
if ok:
caller.msg("Added lock '%s' to %s." % (lockdef, obj))
return
# if we get here, we are just viewing all locks
obj = caller.search(self.lhs)
if not obj:
return
caller.msg(obj.locks)
class CmdExamine(ObjManipCommand):
"""
examine - detailed info on objects
@ -1255,7 +1342,7 @@ class CmdExamine(ObjManipCommand):
"""
key = "@examine"
aliases = ["@ex","ex", "exam"]
permissions = "cmd:examine"
locks = "cmd:perm(examine) or perm(Builders)"
help_category = "Building"
def crop_line(self, text, heading="", line_width=79):
@ -1324,7 +1411,10 @@ class CmdExamine(ObjManipCommand):
string += "\n{wLocation{n: %s" % obj.location
perms = obj.permissions
if perms:
string += "\n{wObj Perms/Locks{n: %s" % (", ".join(perms))
string += "\n{wPermissions{n: %s" % (", ".join(perms))
locks = str(obj.locks)
if locks:
string += "\n{wLocks{n: %s" % ("; ".join([lock for lock in locks.split(';')]))
if not (len(obj.cmdset.all()) == 1 and obj.cmdset.current.key == "Empty"):
string += "\n{wCurrent Cmdset (before permission checks){n:\n\r %s" % obj.cmdset
if obj.scripts.all():
@ -1360,7 +1450,7 @@ class CmdExamine(ObjManipCommand):
if not self.args:
# If no arguments are provided, examine the invoker's location.
obj = caller.location
if not has_perm(caller, obj, 'obj_info'):
if not obj.access(caller, 'examine'):
#If we don't have special info access, just look at the object instead.
caller.exec_cmd('look %s' % obj.name)
return
@ -1379,7 +1469,7 @@ class CmdExamine(ObjManipCommand):
obj = caller.search(obj_name)
if not obj:
continue
if not has_perm(caller, obj, 'obj_info'):
if not obj.access(caller, 'examine'):
#If we don't have special info access, just look at the object instead.
caller.exec_cmd('look %s' % obj_name)
continue
@ -1407,7 +1497,7 @@ class CmdFind(MuxCommand):
key = "@find"
aliases = "@locate, find, locate"
permissions = "cmd:find"
locks = "cmd:perm(find) or perm(Builders)"
help_category = "Building"
def func(self):
@ -1447,7 +1537,7 @@ class CmdTeleport(MuxCommand):
"""
key = "@tel"
aliases = "@teleport"
permissions = "cmd:teleport"
locks = "cmd:perm(teleport) or perm(Builders)"
help_category = "Building"
def func(self):
@ -1501,7 +1591,7 @@ class CmdUnLink(CmdLink):
# this is just a child of CmdLink
key = "@unlink"
permissions = "cmd:unlink"
locks = "cmd:perm(unlink) or perm(Builders)"
help_key = "Building"
def func(self):

View file

@ -27,7 +27,7 @@ class DefaultCmdSet(CmdSet):
self.add(general.CmdDrop())
self.add(general.CmdWho())
self.add(general.CmdSay())
self.add(general.CmdGroup())
self.add(general.CmdAccess())
self.add(general.CmdEncoding())
# The help system
@ -37,16 +37,15 @@ class DefaultCmdSet(CmdSet):
# System commands
self.add(system.CmdReload())
self.add(system.CmdPy())
self.add(system.CmdListScripts())
self.add(system.CmdListObjects())
self.add(system.CmdScripts())
self.add(system.CmdObjects())
self.add(system.CmdService())
self.add(system.CmdShutdown())
self.add(system.CmdVersion())
self.add(system.CmdTime())
self.add(system.CmdList())
self.add(system.CmdServerLoad())
self.add(system.CmdPs())
self.add(system.CmdStats())
# Admin commands
self.add(admin.CmdBoot())
self.add(admin.CmdDelPlayer())
@ -77,6 +76,7 @@ class DefaultCmdSet(CmdSet):
self.add(building.CmdDestroy())
self.add(building.CmdExamine())
self.add(building.CmdTypeclass())
self.add(building.CmdLock())
# Comm commands
self.add(comms.CmdAddCom())
@ -93,5 +93,5 @@ class DefaultCmdSet(CmdSet):
# Testing/Utility commands
self.add(utils.CmdTest())
self.add(utils.CmdTestPerms())
#self.add(utils.CmdTestPerms())
self.add(utils.TestCom())

View file

@ -5,7 +5,6 @@ Comsys command module.
from src.comms.models import Channel, Msg, ChannelConnection
from src.comms.channelhandler import CHANNELHANDLER
from src.utils import create, utils
from src.permissions.permissions import has_perm
from src.commands.default.muxcommand import MuxCommand
def find_channel(caller, channelname, silent=False):
@ -41,6 +40,7 @@ class CmdAddCom(MuxCommand):
key = "addcom"
aliases = ["aliaschan","chanalias"]
help_category = "Comms"
locks = "cmd:not perm(channel_banned)"
def func(self):
"Implement the command"
@ -67,7 +67,7 @@ class CmdAddCom(MuxCommand):
return
# check permissions
if not has_perm(player, channel, 'chan_listen'):
if not channel.access(player, 'listen'):
caller.msg("You are not allowed to listen to this channel.")
return
@ -83,7 +83,7 @@ class CmdAddCom(MuxCommand):
if alias:
# create a nick and add it to the caller.
caller.nickhandler(alias, channel.key, nick_type="channel")
caller.nicks.add(alias, channel.key, nick_type="channel")
string += "You can now refer to the channel %s with the alias '%s'."
caller.msg(string % (channel.key, alias))
else:
@ -106,6 +106,7 @@ class CmdDelCom(MuxCommand):
key = "delcom"
aliases = ["delaliaschan, delchanalias"]
help_category = "Comms"
locks = "cmd:not perm(channel_banned)"
def func(self):
"Implementing the command. "
@ -126,20 +127,20 @@ class CmdDelCom(MuxCommand):
return
chkey = channel.key.lower()
# find all nicks linked to this channel and delete them
for nick in [nick for nick in caller.nicks
if nick.db_type == "channel" and nick.db_real.lower() == chkey]:
for nick in [nick for nick in caller.nicks.get(nick_type="channel")
if nick.db_real.lower() == chkey]:
nick.delete()
channel.disconnect_from(player)
caller.msg("You stop listening to channel '%s'. Eventual aliases were removed." % channel.key)
return
else:
# we are removing a channel nick
channame = caller.nickhandler(ostring, nick_type="channel")
channame = caller.nicks.get(ostring, nick_type="channel")
channel = find_channel(caller, channame, silent=True)
if not channel:
caller.msg("No channel with alias '%s' was found." % ostring)
else:
caller.nickhandler(ostring, nick_type="channel", delete=True)
caller.nicks.delete(ostring, nick_type="channel")
caller.msg("Your alias '%s' for channel %s was cleared." % (ostring, channel.key))
# def cmd_allcom(command):
@ -249,6 +250,7 @@ class CmdChannels(MuxCommand):
key = "@channels"
aliases = ["@clist", "channels", "comlist", "chanlist", "channellist", "all channels"]
help_category = "Comms"
locks = "cmd:all()"
def func(self):
"Implement function"
@ -256,7 +258,7 @@ class CmdChannels(MuxCommand):
caller = self.caller
# all channels we have available to listen to
channels = [chan for chan in Channel.objects.get_all_channels() if has_perm(caller, chan, 'can_listen')]
channels = [chan for chan in Channel.objects.get_all_channels() if chan.access(caller, 'listen')]
if not channels:
caller.msg("No channels available")
return
@ -265,7 +267,7 @@ class CmdChannels(MuxCommand):
if self.cmdstring != "comlist":
string = "\nAll available channels:"
string = "\nChannels available:"
cols = [[" "], ["Channel"], ["Aliases"], ["Perms"], ["Description"]]
for chan in channels:
if chan in subs:
@ -274,7 +276,7 @@ class CmdChannels(MuxCommand):
cols[0].append(" ")
cols[1].append(chan.key)
cols[2].append(",".join(chan.aliases))
cols[3].append(",".join(chan.permissions))
cols[3].append(str(chan.locks))
cols[4].append(chan.desc)
# put into table
for ir, row in enumerate(utils.format_table(cols)):
@ -284,18 +286,18 @@ class CmdChannels(MuxCommand):
string += "\n" + "".join(row)
self.caller.msg(string)
string = "\nYour channel subscriptions:"
string = "\nChannel subscriptions:"
if not subs:
string += "(None)"
else:
nicks = [nick for nick in caller.nicks if nick.db_type == 'channel']
print nicks
cols = [["Channel"], ["Aliases"], ["Description"]]
nicks = [nick for nick in caller.nicks.get(nick_type="channel")]
cols = [[" "], ["Channel"], ["Aliases"], ["Description"]]
for chan in subs:
cols[0].append(chan.key)
cols[1].append(",".join([nick.db_nick for nick in nicks
cols[0].append(" ")
cols[1].append(chan.key)
cols[2].append(",".join([nick.db_nick for nick in nicks
if nick.db_real.lower() == chan.key.lower()] + chan.aliases))
cols[2].append(chan.desc)
cols[3].append(chan.desc)
# put into table
for ir, row in enumerate(utils.format_table(cols)):
if ir == 0:
@ -316,6 +318,7 @@ class CmdCdestroy(MuxCommand):
key = "@cdestroy"
help_category = "Comms"
locks = "cmd:all()"
def func(self):
"Destroy objects cleanly."
@ -328,7 +331,7 @@ class CmdCdestroy(MuxCommand):
if not channel:
caller.msg("Could not find channel %s." % self.args)
return
if not has_perm(caller, channel, 'chan_admin', default_deny=True):
if not channel.access(caller, 'admin'):
caller.msg("You are not allowed to do that.")
return
@ -572,7 +575,7 @@ class CmdChannelCreate(MuxCommand):
key = "@ccreate"
aliases = "channelcreate"
permissions = "cmd:ccreate"
locks = "cmd:not perm(channel_banned)"
help_category = "Comms"
def func(self):
@ -601,9 +604,8 @@ class CmdChannelCreate(MuxCommand):
caller.msg("A channel with that name already exists.")
return
# Create and set the channel up
permissions = "chan_send:%s,chan_listen:%s,chan_admin:has_id(%s)" % \
("Players","Players",caller.id)
new_chan = create.create_channel(channame, aliases, description, permissions)
lockstring = "send:all();listen:all();admin:id(%s)" % caller.id
new_chan = create.create_channel(channame, aliases, description, locks=lockstring)
new_chan.connect_to(caller)
caller.msg("Created channel %s and connected to it." % new_chan.key)
@ -663,7 +665,7 @@ class CmdCdesc(MuxCommand):
"""
key = "@cdesc"
permissions = "cmd:cdesc"
locks = "cmd:not perm(channel_banned)"
help_category = "Comms"
def func(self):
@ -679,7 +681,7 @@ class CmdCdesc(MuxCommand):
caller.msg("Channel '%s' not found." % self.lhs)
return
#check permissions
if not has_perm(caller, channel, 'channel_admin'):
if not caller.access(caller, 'admin'):
caller.msg("You cant admin this channel.")
return
# set the description
@ -694,19 +696,19 @@ class CmdPage(MuxCommand):
Usage:
page[/switches] [<player>,<player>,... = <message>]
tell ''
page/list <number>
page <number>
Switch:
list - show your last <number> of tells/pages.
last - shows who you last messaged
list - show your last <number> of tells/pages (default)
Send a message to target user (if online). If no
argument is given, you will instead see who was the last
person you paged to.
argument is given, you will get a list of your latest messages.
"""
key = "page"
aliases = ['tell']
permissions = "cmd:tell"
locks = "cmd:not perm(page_banned)"
help_category = "Comms"
def func(self):
@ -722,17 +724,29 @@ class CmdPage(MuxCommand):
if msg.receivers]
# get last messages we've got
pages_we_got = list(Msg.objects.get_messages_by_receiver(player))
if 'list' in self.switches:
if 'last' in self.switches:
if pages_we_sent:
string = "You last paged {c%s{n." % (", ".join([obj.name
for obj in pages_we_sent[-1].receivers]))
caller.msg(string)
return
else:
string = "You haven't paged anyone yet."
caller.msg(string)
return
if not self.args or not self.rhs:
pages = pages_we_sent + pages_we_got
pages.sort(lambda x, y: cmp(x.date_sent, y.date_sent))
number = 10
number = 5
if self.args:
try:
number = int(self.args)
except ValueError:
pass
caller.msg("Usage: tell [<player> = msg]")
return
if len(pages) > number:
lastpages = pages[-number:]
@ -744,19 +758,14 @@ class CmdPage(MuxCommand):
"{n,{c ".join([obj.name for obj in page.receivers]),
page.message)
for page in lastpages])
caller.msg("Your latest pages:\n %s" % lastpages )
return
if not self.args or not self.rhs:
if pages_we_sent:
string = "You last paged {c%s{n." % (", ".join([obj.name
for obj in pages_we_sent[-1].receivers]))
caller.msg(string)
return
if lastpages:
string = "Your latest pages:\n %s" % lastpages
else:
string = "You haven't paged anyone yet."
caller.msg(string)
return
caller.msg(string)
return
# We are sending. Build a list of targets
@ -786,7 +795,7 @@ class CmdPage(MuxCommand):
if not recobjs:
caller.msg("No players matching your target were found.")
return
header = "{wPlayer{n {c%s{n {wpages:{n" % caller.key
message = self.rhs
@ -800,12 +809,17 @@ class CmdPage(MuxCommand):
# tell the players they got a message.
received = []
rstrings = []
for pobj in recobjs:
pobj.msg("%s %s" % (header, message))
if not pobj.access(caller, 'msg'):
rstrings.append("You are not allowed to page %s." % pobj)
continue
pobj.msg("%s %s" % (header, message))
if hasattr(pobj, 'has_player') and not pobj.has_player:
received.append("{C%s{n" % pobj.name)
caller.msg("%s is offline. They will see your message if they list their pages later." % received[-1])
rstrings.append("%s is offline. They will see your message if they list their pages later." % received[-1])
else:
received.append("{c%s{n" % pobj.name)
received = ", ".join(received)
caller.msg("You paged %s with: '%s'." % (received, message))
if rstrings:
caller.msg(rstrings = "\n".join(rstrings))
caller.msg("You paged %s with: '%s'." % (", ".join(received), message))

View file

@ -5,8 +5,6 @@ now.
import time
from django.conf import settings
from src.server.sessionhandler import SESSIONS
from src.permissions.models import PermissionGroup
from src.permissions.permissions import has_perm, has_perm_string
from src.objects.models import HANDLE_SEARCH_ERRORS
from src.utils import utils
from src.objects.models import Nick
@ -23,7 +21,7 @@ class CmdHome(MuxCommand):
"""
key = "home"
permissions = "cmd:home"
locks = "cmd:perm(home) or perm(Builders)"
def func(self):
"Implement the command"
@ -48,6 +46,7 @@ class CmdLook(MuxCommand):
"""
key = "look"
aliases = ["l"]
locks = "cmd:all()"
def func(self):
"""
@ -84,6 +83,7 @@ class CmdPassword(MuxCommand):
Changes your password. Make sure to pick a safe one.
"""
key = "@password"
locks = "cmd:all()"
def func(self):
"hook function."
@ -138,7 +138,8 @@ class CmdNick(MuxCommand):
"""
key = "nick"
aliases = ["nickname", "nicks", "@nick", "alias"]
locks = "cmd:all()"
def func(self):
"Create the nickname"
@ -185,7 +186,7 @@ class CmdNick(MuxCommand):
if oldnick:
# clear the alias
string += "\nNick '%s' (= '%s') was cleared." % (nick, oldnick[0].db_real)
caller.nickhandler(nick, nick_type=switch, delete=True)
caller.nicks.delete(nick, nick_type=switch)
else:
string += "\nNo nick '%s' found, so it could not be removed." % nick
else:
@ -194,7 +195,7 @@ class CmdNick(MuxCommand):
string += "\nNick %s changed from '%s' to '%s'." % (nick, oldnick[0].db_real, real)
else:
string += "\nNick set: '%s' = '%s'." % (nick, real)
caller.nickhandler(nick, real, nick_type=switch)
caller.nicks.add(nick, real, nick_type=switch)
caller.msg(string)
class CmdInventory(MuxCommand):
@ -209,6 +210,7 @@ class CmdInventory(MuxCommand):
"""
key = "inventory"
aliases = ["inv", "i"]
locks = "cmd:all()"
def func(self):
"hook function"
@ -237,7 +239,8 @@ class CmdGet(MuxCommand):
"""
key = "get"
aliases = "grab"
locks = "cmd:all()"
def func(self):
"implements the command."
@ -256,7 +259,7 @@ class CmdGet(MuxCommand):
# don't allow picking up player objects, nor exits.
caller.msg("You can't get that.")
return
if not has_perm(caller, obj, 'get'):
if not obj.access(caller, 'get'):
if obj.db.get_err_msg:
caller.msg(obj.db.get_err_msg)
else:
@ -285,6 +288,7 @@ class CmdDrop(MuxCommand):
"""
key = "drop"
locks = "cmd:all()"
def func(self):
"Implement command"
@ -322,14 +326,15 @@ class CmdQuit(MuxCommand):
Gracefully disconnect from the game.
"""
key = "@quit"
locks = "cmd:all()"
def func(self):
"hook function"
sessions = self.caller.sessions
for session in sessions:
session.msg("Quitting. Hope to see you soon again.")
session.at_disconnect()
session.session_disconnect()
class CmdWho(MuxCommand):
"""
who
@ -357,7 +362,7 @@ class CmdWho(MuxCommand):
if self.cmdstring == "doing":
show_session_data = False
else:
show_session_data = has_perm_string(caller, "Immortals,Wizards")
show_session_data = caller.check_permstring("Immortals") or caller.check_permstring("Wizards")
if show_session_data:
table = [["Player Name"], ["On for"], ["Idle"], ["Room"], ["Cmds"], ["Host"]]
@ -411,6 +416,7 @@ class CmdSay(MuxCommand):
key = "say"
aliases = ['"']
locks = "cmd:all()"
def func(self):
"Run the say command"
@ -505,6 +511,7 @@ class CmdPose(MuxCommand):
"""
key = "pose"
aliases = [":", "emote"]
locks = "cmd:all()"
def parse(self):
"""
@ -608,6 +615,7 @@ class CmdEncoding(MuxCommand):
key = "@encoding"
aliases = "@encode"
locks = "cmd:all()"
def func(self):
"""
@ -640,39 +648,31 @@ class CmdEncoding(MuxCommand):
string = "Your custom text encoding was changed from '%s' to '%s'." % (old_encoding, encoding)
caller.msg(string)
class CmdGroup(MuxCommand):
class CmdAccess(MuxCommand):
"""
group - show your groups
access - show access groups
Usage:
group
access
This command shows you which user permission groups
you are a member of, if any.
This command shows you the permission hierarchy and
which permission groups you are a member of.
"""
key = "access"
aliases = "groups"
aliases = ["groups", "hierarchy"]
locks = "cmd:all()"
def func(self):
"Load the permission groups"
caller = self.caller
string = ""
if caller.player and caller.player.is_superuser:
string += "\n This is a SUPERUSER account! Group membership does not matter."
else:
# get permissions and determine if they are groups
perms = list(set(caller.permissions + caller.player.permissions))
for group in [group for group in PermissionGroup.objects.all()
if group.key in perms]:
string += "\n {w%s{n\n%s" % (group.key, ", ".join(group.group_permissions))
if string:
string = "\nGroup memberships for you (Player %s + Character %s): %s" % (caller.player.name,
caller.name, string)
else:
string = "\nYou are not not a member of any groups."
hierarchy_full = settings.PERMISSION_HIERARCHY
string = "\n{wPermission Hierarchy{n (climbing):\n %s" % ", ".join(hierarchy_full)
hierarchy = [p.lower() for p in hierarchy_full]
string += "\n{wYour access{n:"
string += "\nCharacter %s: %s" % (caller.key, ", ".join(caller.permissions))
if hasattr(caller, 'player'):
string += "\nPlayer %s: %s" % (caller.player.key, ", ".join(caller.player.permissions))
caller.msg(string)
## def cmd_apropos(command):

View file

@ -9,7 +9,6 @@ creation of other help topics such as RP help or game-world aides.
from src.utils.utils import fill, dedent
from src.commands.command import Command
from src.help.models import HelpEntry
from src.permissions.permissions import has_perm
from src.utils import create
from src.commands.default.muxcommand import MuxCommand
@ -65,6 +64,8 @@ class CmdHelp(Command):
topics related to the game.
"""
key = "help"
locks = "cmd:all()"
# this is a special cmdhandler flag that makes the cmdhandler also pack
# the current cmdset with the call to self.func().
return_cmdset = True
@ -73,6 +74,7 @@ class CmdHelp(Command):
"""
inp is a string containing the command or topic match.
"""
self.original_args = self.args.strip()
self.args = self.args.strip().lower()
def func(self):
@ -94,7 +96,7 @@ class CmdHelp(Command):
if query in LIST_ARGS:
# we want to list all available help entries
hdict_cmd = {}
for cmd in (cmd for cmd in cmdset if has_perm(caller, cmd, 'cmd')
for cmd in (cmd for cmd in cmdset if cmd.access(caller)
if not cmd.key.startswith('__')
and not (hasattr(cmd, 'is_exit') and cmd.is_exit)):
if hdict_cmd.has_key(cmd.help_category):
@ -103,7 +105,7 @@ class CmdHelp(Command):
hdict_cmd[cmd.help_category] = [cmd.key]
hdict_db = {}
for topic in (topic for topic in HelpEntry.objects.get_all_topics()
if has_perm(caller, topic, 'view')):
if topic.access(caller, 'view', default=True)):
if hdict_db.has_key(topic.help_category):
hdict_db[topic.help_category].append(topic.key)
else:
@ -116,7 +118,7 @@ class CmdHelp(Command):
# Cmd auto-help dynamic entries
cmdmatches = [cmd for cmd in cmdset
if query in cmd and has_perm(caller, cmd, 'cmd')]
if query in cmd and cmd.access(caller)]
if len(cmdmatches) > 1:
# multiple matches. Try to limit it down to exact match
exactmatches = [cmd for cmd in cmdmatches if cmd == query]
@ -127,12 +129,12 @@ class CmdHelp(Command):
dbmatches = \
[topic for topic in
HelpEntry.objects.find_topicmatch(query, exact=False)
if has_perm(caller, topic, 'view')]
if topic.access(caller, 'view', default=True)]
if len(dbmatches) > 1:
exactmatches = \
[topic for topic in
HelpEntry.objects.find_topicmatch(query, exact=True)
if has_perm(caller, topic, 'view')]
if topic.access(caller, 'view', default=True)]
if exactmatches:
dbmatches = exactmatches
@ -140,11 +142,11 @@ class CmdHelp(Command):
if (not cmdmatches) and (not dbmatches):
# no normal match. Check if this is a category match instead
categ_cmdmatches = [cmd.key for cmd in cmdset
if query == cmd.help_category and has_perm(caller, cmd, 'cmd')]
if query == cmd.help_category and cmd.access(caller)]
categ_dbmatches = \
[topic.key for topic in
HelpEntry.objects.find_topics_with_category(query)
if has_perm(caller, topic, 'view')]
if topic.access(caller, 'view', default=True)]
cmddict = None
dbdict = None
if categ_cmdmatches:
@ -154,7 +156,7 @@ class CmdHelp(Command):
if cmddict or dbdict:
help_entry = format_help_list(cmddict, dbdict)
else:
help_entry = "No help entry found for '%s'" % query
help_entry = "No help entry found for '%s'" % self.original_args
elif len(cmdmatches) == 1:
# we matched against a command name or alias. Show its help entry.
@ -184,7 +186,7 @@ class CmdSetHelp(MuxCommand):
@help - edit the help database
Usage:
@help[/switches] <topic>[,category[,permission,permission,...]] = <text>
@help[/switches] <topic>[,category[,locks]] = <text>
Switches:
add - add or replace a new topic with text.
@ -203,7 +205,7 @@ class CmdSetHelp(MuxCommand):
"""
key = "@help"
aliases = "@sethelp"
permissions = "cmd:sethelp"
locks = "cmd:perm(PlayerHelpers)"
help_category = "Building"
def func(self):
@ -214,36 +216,33 @@ class CmdSetHelp(MuxCommand):
lhslist = self.lhslist
rhs = self.rhs
if not self.rhs:
caller.msg("Usage: @sethelp/[add|del|append|merge] <topic>[,category[,permission,..] = <text>]")
if not self.args:
caller.msg("Usage: @sethelp/[add|del|append|merge] <topic>[,category[,locks,..] = <text>]")
return
topicstr = ""
category = ""
permissions = ""
lockstring = ""
try:
topicstr = lhslist[0]
category = lhslist[1]
permissions = ",".join(lhslist[2:])
lockstring = ",".join(lhslist[2:])
except Exception:
pass
if not topicstr:
caller.msg("You have to define a topic!")
return
string = ""
print topicstr, category, permissions
#print topicstr, category, lockstring
if switches and switches[0] in ('append', 'app','merge'):
# add text to the end of a help topic
# find the topic to append to
old_entry = None
try:
old_entry = HelpEntry.objects.get(key=topicstr)
except Exception:
pass
old_entry = HelpEntry.objects.filter(db_key__iexact=topicstr)
if not old_entry:
string = "Could not find topic '%s'. You must give an exact name." % topicstr
else:
old_entry = old_entry[0]
entrytext = old_entry.entrytext
if switches[0] == 'merge':
old_entry.entrytext = "%s %s" % (entrytext, self.rhs)
@ -255,15 +254,11 @@ class CmdSetHelp(MuxCommand):
elif switches and switches[0] in ('delete','del'):
#delete a help entry
old_entry = None
try:
old_entry = HelpEntry.objects.get(key=topicstr)
except Exception:
pass
old_entry = HelpEntry.objects.filter(db_key__iexact=topicstr)
if not old_entry:
string = "Could not find topic. You must give an exact name."
string = "Could not find topic '%s'." % topicstr
else:
old_entry.delete()
old_entry[0].delete()
string = "Deleted the help entry '%s'." % topicstr
else:
@ -279,7 +274,8 @@ class CmdSetHelp(MuxCommand):
old_entry.key = topicstr
old_entry.entrytext = self.rhs
old_entry.help_category = category
old_entry.permissions = permissions
old_entry.locks.clear()
old_entry.locks.add(lockstring)
old_entry.save()
string = "Overwrote the old topic '%s' with a new one." % topicstr
else:
@ -287,7 +283,8 @@ class CmdSetHelp(MuxCommand):
else:
# no old entry. Create a new one.
new_entry = create.create_help_entry(topicstr,
rhs, category, permissions)
rhs, category, lockstring)
if new_entry:
string = "Topic '%s' was successfully created." % topicstr
else:

View file

@ -20,7 +20,6 @@ the line is just added to the editor buffer).
from src.comms.models import Channel
from src.utils import create
from src.permissions.permissions import has_perm
# The command keys the engine is calling
# (the actual names all start with __)
@ -41,6 +40,7 @@ class SystemNoInput(MuxCommand):
This is called when there is no input given
"""
key = CMD_NOINPUT
locks = "cmd:all()"
def func(self):
"Do nothing."
@ -56,7 +56,8 @@ class SystemNoMatch(MuxCommand):
No command was found matching the given input.
"""
key = CMD_NOMATCH
locks = "cmd:all()"
def func(self):
"""
This is given the failed raw string as input.
@ -79,6 +80,7 @@ class SystemMultimatch(MuxCommand):
and cmd is an an instantiated Command object matching the candidate.
"""
key = CMD_MULTIMATCH
locks = "cmd:all()"
def format_multimatches(self, caller, matches):
"""
@ -131,6 +133,7 @@ class SystemNoPerm(MuxCommand):
correct permissions to use a particular command.
"""
key = CMD_NOPERM
locks = "cmd:all()"
def func(self):
"""
@ -154,7 +157,7 @@ class SystemSendToChannel(MuxCommand):
"""
key = CMD_CHANNEL
permissions = "cmd:use_channels"
locks = "cmd:all()"
def parse(self):
channelname, msg = self.args.split(':', 1)
@ -178,7 +181,7 @@ class SystemSendToChannel(MuxCommand):
string = "You are not connected to channel '%s'."
caller.msg(string % channelkey)
return
if not has_perm(caller, channel, 'chan_send'):
if not channel.access(caller, 'send'):
string = "You are not permitted to send to channel '%s'."
caller.msg(string % channelkey)
return
@ -199,6 +202,7 @@ class SystemUseExit(MuxCommand):
as a command. It receives the raw string as input.
"""
key = CMD_EXIT
locks = "cmd:all()"
def func(self):
"""
@ -214,7 +218,7 @@ class SystemUseExit(MuxCommand):
destination = exi.attr('_destination')
if not destination:
return
if has_perm(caller, exit, 'traverse'):
if exit.access(caller, 'traverse'):
caller.move_to(destination)
else:
caller.msg("You cannot enter")

View file

@ -9,9 +9,11 @@ import os, datetime
import django, twisted
from django.contrib.auth.models import User
from django.conf import settings
from src.server.sessionhandler import SESSIONS
from src.scripts.models import ScriptDB
from src.objects.models import ObjectDB
from src.players.models import PlayerDB
from src.config.models import ConfigValue
from src.utils import reloads, create, logger, utils, gametime
from src.commands.default.muxcommand import MuxCommand
@ -28,7 +30,7 @@ class CmdReload(MuxCommand):
re-validates all scripts.
"""
key = "@reload"
permissions = "cmd:reload"
locks = "cmd:perm(reload) or perm(Immortals)"
help_category = "System"
def func(self):
@ -84,7 +86,7 @@ class CmdPy(MuxCommand):
"""
key = "@py"
aliases = ["!"]
permissions = "cmd:py"
locks = "cmd:perm(py) or perm(Immortals)"
help_category = "System"
def func(self):
@ -130,7 +132,7 @@ class CmdPy(MuxCommand):
obj.delete()
script.delete()
class CmdListScripts(MuxCommand):
class CmdScripts(MuxCommand):
"""
Operate on scripts.
@ -149,7 +151,7 @@ class CmdListScripts(MuxCommand):
"""
key = "@scripts"
aliases = "@listscripts"
permissions = "cmd:listscripts"
locks = "cmd:perm(listscripts) or perm(Wizards)"
help_category = "System"
def format_script_list(self, scripts):
@ -255,7 +257,7 @@ class CmdListScripts(MuxCommand):
class CmdListObjects(MuxCommand):
class CmdObjects(MuxCommand):
"""
Give a summary of object types in database
@ -267,8 +269,8 @@ class CmdListObjects(MuxCommand):
given, <nr> defaults to 10.
"""
key = "@objects"
aliases = ["@listobjects", "@listobjs"]
permissions = "cmd:listobjects"
aliases = ["@listobjects", "@listobjs", '@stats', '@db']
locks = "cmd:perm(listobjects) or perm(Builders)"
help_category = "System"
def func(self):
@ -280,9 +282,24 @@ class CmdListObjects(MuxCommand):
nlim = int(self.args)
else:
nlim = 10
string = "\n{wDatabase totals:{n"
nplayers = PlayerDB.objects.count()
nobjs = ObjectDB.objects.count()
base_typeclass = settings.BASE_CHARACTER_TYPECLASS
nchars = ObjectDB.objects.filter(db_typeclass_path=base_typeclass).count()
nrooms = ObjectDB.objects.filter(db_location=None).exclude(db_typeclass_path=base_typeclass).count()
nexits = sum([1 for obj in ObjectDB.objects.filter(db_location=None) if obj.get_attribute('_destination')])
string += "\n{wPlayers:{n %i" % nplayers
string += "\n{wObjects:{n %i" % nobjs
string += "\n{w Characters (base type):{n %i" % nchars
string += "\n{w Rooms (location==None):{n %i" % nrooms
string += "\n{w Exits (.db._destination!=None):{n %i" % nexits
string += "\n{w Other:{n %i\n" % (nobjs - nchars - nrooms - nexits)
dbtotals = ObjectDB.objects.object_totals()
#print dbtotals
string = "\n{wDatase Object totals:{n"
table = [["Count"], ["Typeclass"]]
for path, count in dbtotals.items():
table[0].append(count)
@ -332,7 +349,7 @@ class CmdService(MuxCommand):
"""
key = "@service"
permissions = "cmd:service"
locks = "cmd:perm(service) or perm(Immortals)"
help_category = "System"
def func(self):
@ -351,7 +368,7 @@ class CmdService(MuxCommand):
sessions = caller.sessions
if not sessions:
return
service_collection = sessions[0].server.service_collection
service_collection = SESSIONS.server.services
if switch == "list":
# Just display the list of installed services and their
@ -417,7 +434,7 @@ class CmdShutdown(MuxCommand):
Shut the game server down gracefully.
"""
key = "@shutdown"
permissions = "cmd:shutdown"
locks = "cmd:perm(shutdown) or perm(Immortals)"
help_category = "System"
def func(self):
@ -468,159 +485,124 @@ class CmdTime(MuxCommand):
"""
key = "@time"
aliases = "@uptime"
permissions = "cmd:time"
locks = "cmd:perm(time) or perm(Players)"
help_category = "System"
def func(self):
"Show times."
string1 = "\nCurrent server uptime: \t"
string1 += "{w%s{n" % (utils.time_format(gametime.uptime(format=False), 2))
string2 = "\nTotal server running time: \t"
string2 += "{w%s{n" % (utils.time_format(gametime.runtime(format=False), 2))
string3 = "\nTotal in-game time (realtime x %g):\t" % (gametime.TIMEFACTOR)
string3 += "{w%s{n" % (utils.time_format(gametime.gametime(format=False), 2))
string4 = "\nServer time stamp: \t"
string4 += "{w%s{n" % (str(datetime.datetime.now()))
string5 = ""
if not utils.host_os_is('nt'):
# os.getloadavg() is not available on Windows.
table = [["Current server uptime:",
"Total server running time:",
"Total in-game time (realtime x %g):" % (gametime.TIMEFACTOR),
"Server time stamp:"
],
[utils.time_format(gametime.uptime(format=False), 2),
utils.time_format(gametime.runtime(format=False), 2),
utils.time_format(gametime.gametime(format=False), 2),
datetime.datetime.now()
]]
if utils.host_os_is('posix'):
loadavg = os.getloadavg()
string5 += "\nServer load (per minute): \t"
string5 += "{w%g%%{n" % (100 * loadavg[0])
string = "%s%s%s%s%s" % (string1, string2, string3, string4, string5)
table[0].append("Server load (per minute):")
table[1].append("{w%g%%{n" % (100 * loadavg[0]))
stable = []
for col in table:
stable.append([str(val).strip() for val in col])
ftable = utils.format_table(stable, 5)
string = ""
for row in ftable:
string += "\n " + "{w%s{n" % row[0] + "".join(row[1:])
self.caller.msg(string)
class CmdList(MuxCommand):
class CmdServerLoad(MuxCommand):
"""
@list - list info
server load statistics
Usage:
@list <option>
@serverload
Options:
process - list processes
objects - list objects
scripts - list scripts
perms - list permission keys and groups
Shows game related information depending
on which argument is given.
Show server load statistics in a table.
"""
key = "@list"
permissions = "cmd:list"
key = "@serverload"
locks = "cmd:perm(list) or perm(Immortals)"
help_category = "System"
def func(self):
"Show list."
caller = self.caller
if not self.args:
caller.msg("Usage: @list process|objects|scripts|perms")
return
string = ""
if self.arglist[0] in ["proc","process"]:
# display active processes
# display active processes
if utils.host_os_is('nt'):
string = "Feature not available on Windows."
else:
import resource
loadavg = os.getloadavg()
psize = resource.getpagesize()
rusage = resource.getrusage(resource.RUSAGE_SELF)
table = [["Server load (1 min):",
"Process ID:",
"Bytes per page:",
"Time used:",
"Integral memory:",
"Max res memory:",
"Page faults:",
"Disk I/O:",
"Network I/O",
"Context switching:"
],
["%g%%" % (100 * loadavg[0]),
"%10d" % os.getpid(),
"%10d " % psize,
"%10d" % rusage[0],
"%10d shared" % rusage[3],
"%10d pages" % rusage[2],
"%10d hard" % rusage[7],
"%10d reads" % rusage[9],
"%10d in" % rusage[12],
"%10d vol" % rusage[14]
],
["", "", "",
"(user: %g)" % rusage[1],
"%10d private" % rusage[4],
"%10d bytes" % (rusage[2] * psize),
"%10d soft" % rusage[6],
"%10d writes" % rusage[10],
"%10d out" % rusage[11],
"%10d forced" % rusage[15]
],
["", "", "", "",
"%10d stack" % rusage[5],
"",
"%10d swapouts" % rusage[8],
"", "",
"%10d sigs" % rusage[13]
]
]
stable = []
for col in table:
stable.append([str(val).strip() for val in col])
ftable = utils.format_table(stable, 5)
string = ""
for row in ftable:
string += "\n " + "{w%s{n" % row[0] + "".join(row[1:])
# string = "\n Server load (1 min) : %.2f " % loadavg[0]
# string += "\n Process ID: %10d" % os.getpid()
# string += "\n Bytes per page: %10d" % psize
# string += "\n Time used: %10d, user: %g" % (rusage[0], rusage[1])
# string += "\n Integral mem: %10d shared, %10d, private, %10d stack " % \
# (rusage[3], rusage[4], rusage[5])
# string += "\n Max res mem: %10d pages %10d bytes" % \
# (rusage[2],rusage[2] * psize)
# string += "\n Page faults: %10d hard %10d soft %10d swapouts " % \
# (rusage[7], rusage[6], rusage[8])
# string += "\n Disk I/O: %10d reads %10d writes " % \
# (rusage[9], rusage[10])
# string += "\n Network I/O: %10d in %10d out " % \
# (rusage[12], rusage[11])
# string += "\n Context swi: %10d vol %10d forced %10d sigs " % \
# (rusage[14], rusage[15], rusage[13])
elif self.arglist[0] in ["obj", "objects"]:
caller.execute_cmd("@objects")
elif self.arglist[0] in ["scr", "scripts"]:
caller.execute_cmd("@scripts")
elif self.arglist[0] in ["perm", "perms","permissions"]:
caller.execute_cmd("@perm/list")
if not utils.host_os_is('posix'):
string = "Process listings are only available under Linux/Unix."
else:
string = "'%s' is not a valid option." % self.arglist[0]
# send info
import resource
loadavg = os.getloadavg()
psize = resource.getpagesize()
rusage = resource.getrusage(resource.RUSAGE_SELF)
table = [["Server load (1 min):",
"Process ID:",
"Bytes per page:",
"Time used:",
"Integral memory:",
"Max res memory:",
"Page faults:",
"Disk I/O:",
"Network I/O",
"Context switching:"
],
["%g%%" % (100 * loadavg[0]),
"%10d" % os.getpid(),
"%10d " % psize,
"%10d" % rusage[0],
"%10d shared" % rusage[3],
"%10d pages" % rusage[2],
"%10d hard" % rusage[7],
"%10d reads" % rusage[9],
"%10d in" % rusage[12],
"%10d vol" % rusage[14]
],
["", "", "",
"(user: %g)" % rusage[1],
"%10d private" % rusage[4],
"%10d bytes" % (rusage[2] * psize),
"%10d soft" % rusage[6],
"%10d writes" % rusage[10],
"%10d out" % rusage[11],
"%10d forced" % rusage[15]
],
["", "", "", "",
"%10d stack" % rusage[5],
"",
"%10d swapouts" % rusage[8],
"", "",
"%10d sigs" % rusage[13]
]
]
stable = []
for col in table:
stable.append([str(val).strip() for val in col])
ftable = utils.format_table(stable, 5)
string = ""
for row in ftable:
string += "\n " + "{w%s{n" % row[0] + "".join(row[1:])
caller.msg(string)
#TODO - expand @ps as we add irc/imc2 support.
class CmdPs(MuxCommand):
"""
@ps - list processes
list processes
Usage
@ps
Shows the process/event table.
"""
key = "@ps"
permissions = "cmd:ps"
locks = "cmd:perm(ps) or perm(Builders)"
help_category = "System"
def func(self):
@ -651,36 +633,4 @@ class CmdPs(MuxCommand):
string += "\n{wTotal{n: %d scripts." % len(all_scripts)
self.caller.msg(string)
class CmdStats(MuxCommand):
"""
@stats - show object stats
Usage:
@stats
Shows stats about the database.
"""
key = "@stats"
aliases = "@db"
permissions = "cmd:stats"
help_category = "System"
def func(self):
"Show all stats"
# get counts for all typeclasses
stats_dict = ObjectDB.objects.object_totals()
# get all objects
stats_allobj = ObjectDB.objects.all().count()
# get all rooms
stats_room = ObjectDB.objects.filter(db_location=None).count()
# get all players
stats_users = User.objects.all().count()
string = "\n{wNumber of users:{n %i" % stats_users
string += "\n{wTotal number of objects:{n %i" % stats_allobj
string += "\n{wNumber of rooms (location==None):{n %i" % stats_room
string += "\n (Use @objects for detailed info)"
self.caller.msg(string)

View file

@ -19,8 +19,9 @@ try:
except ImportError:
from django.test import TestCase
from django.conf import settings
from src.utils import create
from src.utils import create, ansi
from src.server import session, sessionhandler
from src.locks.lockhandler import LockHandler
from src.config.models import ConfigValue
#------------------------------------------------------------
@ -29,6 +30,7 @@ from src.config.models import ConfigValue
# print all feedback from test commands (can become very verbose!)
VERBOSE = False
NOMANGLE = False
class FakeSession(session.Session):
"""
@ -55,8 +57,13 @@ class FakeSession(session.Session):
else:
rstring = return_list
self.player.character.ndb.return_string = None
if not message.startswith(rstring):
retval = "Returned message ('%s') != desired message ('%s')" % (message, rstring)
message_noansi = ansi.parse_ansi(message, strip_ansi=True).strip()
rstring = rstring.strip()
if not message_noansi.startswith(rstring):
sep1 = "\n" + "="*30 + "Wanted message" + "="*34 + "\n"
sep2 = "\n" + "="*30 + "Returned message" + "="*32 + "\n"
sep3 = "\n" + "="*78
retval = sep1 + rstring + sep2 + message_noansi + sep3
raise AssertionError(retval)
if VERBOSE:
print message
@ -77,17 +84,28 @@ class CommandTest(TestCase):
self.room2 = create.create_object(settings.BASE_ROOM_TYPECLASS, key="room2")
# create a faux player/character for testing.
self.char1 = create.create_player("TestingPlayer", "testplayer@test.com", "testpassword", location=self.room1)
self.char1 = create.create_player("TestChar", "testplayer@test.com", "testpassword", location=self.room1)
self.char1.player.user.is_superuser = True
self.char1.lock_storage = ""
self.char1.locks = LockHandler(self.char1)
self.char1.ndb.return_string = None
sess = FakeSession()
sess.connectionMade()
sess.session_login(self.char1.player)
# create second player and some objects
self.char2 = create.create_object(settings.BASE_CHARACTER_TYPECLASS, key="char2", location=self.room1)
# create second player
self.char2 = create.create_player("TestChar2", "testplayer2@test.com", "testpassword2", location=self.room1)
self.char2.player.user.is_superuser = False
self.char2.lock_storage = ""
self.char2.locks = LockHandler(self.char2)
self.char2.ndb.return_string = None
sess2 = FakeSession()
sess2.connectionMade()
sess2.session_login(self.char2.player)
# A non-player-controlled character
self.char3 = create.create_object(settings.BASE_CHARACTER_TYPECLASS, key="TestChar3", location=self.room1)
# create some objects
self.obj1 = create.create_object(settings.BASE_OBJECT_TYPECLASS, key="obj1", location=self.room1)
self.obj2 = create.create_object(settings.BASE_OBJECT_TYPECLASS, key="obj2", location=self.room1)
self.obj2 = create.create_object(settings.BASE_OBJECT_TYPECLASS, key="obj2", location=self.room1)
self.exit1 = create.create_object(settings.BASE_EXIT_TYPECLASS, key="exit1", location=self.room1)
self.exit2 = create.create_object(settings.BASE_EXIT_TYPECLASS, key="exit2", location=self.room2)
@ -110,7 +128,7 @@ class CommandTest(TestCase):
This also mangles the input in various ways to test if the command
will be fooled.
"""
if not VERBOSE:
if not VERBOSE and not NOMANGLE:
# only mangle if not VERBOSE, to make fewer return lines
test1 = re.sub(r'\s', '', raw_string) # remove all whitespace inside it
test2 = "%s/åäö öäö;-:$£@*~^' 'test" % raw_string # inserting weird characters in call
@ -129,52 +147,129 @@ class CommandTest(TestCase):
# Default set Command testing
#------------------------------------------------------------
# general.py tests
class TestLook(CommandTest):
def test_call(self):
self.execute_cmd("look here")
class TestHome(CommandTest):
def test_call(self):
self.char1.location = self.room1
self.char1.home = self.room2
self.execute_cmd("home")
self.assertEqual(self.char1.location, self.room2)
class TestLook(CommandTest):
def test_call(self):
self.execute_cmd("look here")
class TestPassword(CommandTest):
def test_call(self):
self.execute_cmd("@password testpassword = newpassword")
class TestInventory(CommandTest):
def test_call(self):
self.execute_cmd("inv")
class TestQuit(CommandTest):
def test_call(self):
self.execute_cmd("@quit")
class TestPose(CommandTest):
def test_call(self):
self.execute_cmd("pose is testing","TestChar is testing")
class TestNick(CommandTest):
def test_call(self):
self.char1.player.user.is_superuser = False
self.execute_cmd("nickname testalias = testaliasedstring1")
self.execute_cmd("nickname/player testalias = testaliasedstring2")
self.execute_cmd("nickname/object testalias = testaliasedstring3")
self.assertEquals(u"testaliasedstring1", self.char1.nickhandler("testalias"))
self.assertEquals(u"testaliasedstring2", self.char1.nickhandler("testalias",nick_type="player"))
self.assertEquals(u"testaliasedstring3", self.char1.nickhandler("testalias",nick_type="object"))
self.assertEquals(u"testaliasedstring1", self.char1.nicks.get("testalias"))
self.assertEquals(u"testaliasedstring2", self.char1.nicks.get("testalias",nick_type="player"))
self.assertEquals(u"testaliasedstring3", self.char1.nicks.get("testalias",nick_type="object"))
class TestGet(CommandTest):
def test_call(self):
self.obj1.location = self.room1
self.execute_cmd("get obj1", "You pick up obj1.")
class TestDrop(CommandTest):
def test_call(self):
self.obj1.location = self.char1
self.execute_cmd("drop obj1", "You drop obj1.")
class TestWho(CommandTest):
def test_call(self):
self.execute_cmd("who")
class TestSay(CommandTest):
def test_call(self):
self.execute_cmd("say Hello", 'You say, "Hello')
class TestAccess(CommandTest):
def test_call(self):
self.execute_cmd("access")
class TestEncoding(CommandTest):
def test_call(self):
self.execute_cmd("@encoding", "Supported encodings")
# help.py command tests
class TestHelpSystem(CommandTest):
def test_call(self):
global NOMANGLE
NOMANGLE = True
sep = "-"*70 + "\n"
self.execute_cmd("@help/add TestTopic,TestCategory = Test1", )
self.execute_cmd("help TestTopic",sep + "Help topic for Testtopic\nTest1")
self.execute_cmd("@help/merge TestTopic = Test2", "Added the new text right after")
self.execute_cmd("help TestTopic", sep + "Help topic for Testtopic\nTest1 Test2")
self.execute_cmd("@help/append TestTopic = Test3", "Added the new text as a")
self.execute_cmd("help TestTopic",sep + "Help topic for Testtopic\nTest1 Test2\n\nTest3")
self.execute_cmd("@help/delete TestTopic","Deleted the help entry")
self.execute_cmd("help TestTopic","No help entry found for 'TestTopic'")
NOMANGLE = False
# system.py command tests
class TestPy(CommandTest):
def test_call(self):
self.execute_cmd("@py 1+2", [">>> 1+2", "<<< 3"])
class TestListScripts(CommandTest):
class TestScripts(CommandTest):
def test_call(self):
self.execute_cmd("@scripts")
class TestListObjects(CommandTest):
self.execute_cmd("@scripts", "id")
class TestObjects(CommandTest):
def test_call(self):
self.execute_cmd("@objects")
class TestListService(CommandTest):
def test_call(self):
self.execute_cmd("@service")
self.execute_cmd("@objects", "Database totals")
# Cannot be tested since we don't have an active server running at this point.
# class TestListService(CommandTest):
# def test_call(self):
# self.execute_cmd("@service/list", "---")
class TestVersion(CommandTest):
def test_call(self):
self.execute_cmd("@version")
self.execute_cmd("@version", '---')
class TestTime(CommandTest):
def test_call(self):
self.execute_cmd("@time")
class TestList(CommandTest):
self.execute_cmd("@time", "Current server uptime")
class TestServerLoad(CommandTest):
def test_call(self):
self.execute_cmd("@list")
self.execute_cmd("@serverload", "Server load")
class TestPs(CommandTest):
def test_call(self):
self.execute_cmd("@ps","\n{wNon-timed scripts")
class TestStats(CommandTest):
self.execute_cmd("@ps","Non-timed scripts")
# admin.py command tests
class TestBoot(CommandTest):
def test_call(self):
self.execute_cmd("@boot TestChar2","You booted TestChar2.")
class TestDelPlayer(CommandTest):
def test_call(self):
self.execute_cmd("@delplayer TestChar2","Booting and informing player ...")
class TestEmit(CommandTest):
def test_call(self):
self.execute_cmd("@stats")
self.execute_cmd("@emit Test message", "Emitted to room1.")
class TestUserPassword(CommandTest):
def test_call(self):
self.execute_cmd("@userpassword TestChar2 = newpass", "TestChar2 - new password set to 'newpass'.")
class TestPerm(CommandTest):
def test_call(self):
self.execute_cmd("@perm TestChar2 = Builders", "Permission 'Builders' given to")
# cannot test this at the moment, screws up the test suite
#class TestPuppet(CommandTest):
# def test_call(self):
# self.execute_cmd("@puppet TestChar3", "You now control TestChar3.")
# self.execute_cmd("@puppet TestChar", "You now control TestChar.")
class TestWall(CommandTest):
def test_call(self):
self.execute_cmd("@wall = This is a test message", "TestChar shouts")
# building.py command tests
#TODO

View file

@ -25,6 +25,7 @@ class CmdConnect(MuxCommand):
"""
key = "connect"
aliases = ["conn", "con", "co"]
locks = "cmd:all()" # not really needed
def func(self):
"""
@ -116,6 +117,7 @@ class CmdCreate(MuxCommand):
"""
key = "create"
aliases = ["cre", "cr"]
locks = "cmd:all()"
def parse(self):
"""
@ -193,6 +195,9 @@ class CmdCreate(MuxCommand):
location=default_home,
typeclass=typeclass,
home=default_home)
# character safety features
new_character.locks.delete("get")
new_character.locks.add("get:perm(Wizards)")
# set a default description
new_character.db.desc = "This is a Player."
@ -227,6 +232,7 @@ class CmdQuit(MuxCommand):
"""
key = "quit"
aliases = ["q", "qu"]
locks = "cmd:all()"
def func(self):
"Simply close the connection."
@ -241,6 +247,7 @@ class CmdUnconnectedLook(MuxCommand):
"""
key = "look"
aliases = "l"
locks = "cmd:all()"
def func(self):
"Show the connect screen."
@ -259,6 +266,7 @@ class CmdUnconnectedHelp(MuxCommand):
"""
key = "help"
aliases = ["h", "?"]
locks = "cmd:all()"
def func(self):
"Shows help"

View file

@ -6,7 +6,6 @@ This defines some test commands for use while testing the MUD and its components
from django.conf import settings
from django.db import IntegrityError
from src.comms.models import Msg
from src.permissions import permissions
from src.utils import create, debug, utils
from src.commands.default.muxcommand import MuxCommand
@ -29,7 +28,7 @@ class CmdTest(MuxCommand):
key = "@test"
aliases = ["@te", "@test all"]
help_category = "Utils"
permissions = "cmd:Immortals" #Wizards
locks = "cmd:perm(Wizards)"
# the muxcommand class itself handles the display
# so we just defer to it by not adding any function.
@ -62,131 +61,6 @@ class CmdTest(MuxCommand):
#self.caller.msg("Imported %s" % cmdsetname)
#self.caller.msg(cmdsethandler.CACHED_CMDSETS)
class CmdTestPerms(MuxCommand):
"""
Test command - test permissions
Usage:
@testperm [[lockstring] [=permstring]]
With no arguments, runs a sequence of tests for the
permission system using the calling player's permissions.
If <lockstring> is given, match caller's permissions
against these locks. If also <permstring> is given,
match this against the given locks instead.
"""
key = "@testperm"
permissions = "cmd:Immortals Wizards"
help_category = "Utils"
def func(self):
"""
Run tests
"""
caller = self.caller
if caller.user.is_superuser:
caller.msg("You are a superuser. Permission tests are pointless.")
return
# create a test object
obj = create.create_object(None, "accessed_object") # this will use default typeclass
obj_id = obj.id
caller.msg("obj_attr: %s" % obj.attr("testattr"))
# perms = ["has_permission", "has permission", "skey:has_permission",
# "has_id(%s)" % obj_id, "has_attr(testattr)",
# "has_attr(testattr, testattr_value)"]
# test setting permissions
uprofile = caller.user.get_profile()
# do testing
caller.msg("----------------")
permissions.set_perm(obj, "has_permission")
permissions.add_perm(obj, "skey:has_permission")
caller.msg(" keys:[%s] locks:[%s]" % (uprofile.permissions, obj.permissions))
caller.msg("normal permtest: %s" % permissions.has_perm(uprofile, obj))
caller.msg("skey permtest: %s" % permissions.has_perm(uprofile, obj, 'skey'))
permissions.set_perm(uprofile, "has_permission")
caller.msg(" keys:[%s] locks:[%s]" % (uprofile.permissions, obj.permissions))
caller.msg("normal permtest: %s" % permissions.has_perm(uprofile, obj))
caller.msg("skey permtest: %s" % permissions.has_perm(uprofile, obj, 'skey'))
# function tests
permissions.set_perm(obj, "has_id(%s)" % (uprofile.id))
caller.msg(" keys:[%s] locks:[%s]" % (uprofile.permissions, obj.permissions))
caller.msg("functest: %s" % permissions.has_perm(uprofile, obj))
uprofile.attr("testattr", "testattr_value")
permissions.set_perm(obj, "has_attr(testattr, testattr_value)")
caller.msg(" keys:[%s] locks:[%s]" % (uprofile.permissions, obj.permissions))
caller.msg("functest: %s" % permissions.has_perm(uprofile, obj))
# cleanup of test permissions
permissions.del_perm(uprofile, "has_permission")
caller.msg(" cleanup: keys:[%s] locks:[%s]" % (uprofile.permissions, obj.permissions))
obj.delete()
uprofile.attr("testattr", delete=True)
# # Add/remove states (removed; not valid.)
# EXAMPLE_STATE="game.gamesrc.commands.examples.example.EXAMPLESTATE"
# class CmdTestState(MuxCommand):
# """
# Test command - add a state.
# Usage:
# @teststate[/switch] [<python path to state instance>]
# Switches:
# add - add a state
# clear - remove all added states.
# list - view current state stack
# reload - reload current state stack
# If no python path is given, an example state will be added.
# You will know it worked if you can use the commands '@testcommand'
# and 'smile'.
# """
# key = "@teststate"
# alias = "@testingstate"
# permissions = "cmd:Immortals Wizards"
# def func(self):
# """
# inp is the dict returned from MuxCommand's parser.
# """
# caller = self.caller
# switches = self.switches
# if not switches or switches[0] not in ["add", "clear", "list", "reload"]:
# string = "Usage: @teststate[/add|clear|list|reload] [<python path>]"
# caller.msg(string)
# elif "clear" in switches:
# caller.cmdset.clear()
# caller.msg("All cmdset cleared.")
# return
# elif "list" in switches:
# string = "%s" % caller.cmdset
# caller.msg(string)
# elif "reload" in switches:
# caller.cmdset.load()
# caller.msg("Cmdset reloaded.")
# else: #add
# arg = inp["raw"]
# if not arg:
# arg = EXAMPLE_STATE
# caller.cmdset.add(arg)
# string = "Added state '%s'." % caller.cmdset.state.key
# caller.msg(string)
class TestCom(MuxCommand):
"""
Test the command system
@ -195,7 +69,7 @@ class TestCom(MuxCommand):
@testcom/create/list [channel]
"""
key = "@testcom"
permissions = "cmd:Immortals Wizards"
locks = "cmd:perm(Wizards)"
help_category = "Utils"
def func(self):
"Run the test program"