diff --git a/game/gamesrc/commands/basecommand.py b/game/gamesrc/commands/basecommand.py index 6d7dd7572b..5bf7392aa7 100644 --- a/game/gamesrc/commands/basecommand.py +++ b/game/gamesrc/commands/basecommand.py @@ -10,7 +10,6 @@ See src/commands/default/muxcommand.py for an example. from src.commands.command import Command as BaseCommand from src.commands.default.muxcommand import MuxCommand as BaseMuxCommand -from src.permissions import permissions from src.utils import utils class MuxCommand(BaseMuxCommand): @@ -41,7 +40,7 @@ class MuxCommand(BaseMuxCommand): cmdhandler): self.key - the name of this command ('look') self.aliases - the aliases of this cmd ('l') - self.permissions - permission string for this command + self.locks - lock definition for this command, usually cmd: self.help_category - overall category of command self.caller - the object calling this command @@ -105,7 +104,7 @@ class Command(BaseCommand): used by Evennia to create the automatic help entry for the command, so make sure to document consistently here. """ - def has_perm(self, srcobj): + def access(self, srcobj): """ This is called by the cmdhandler to determine if srcobj is allowed to execute this command. This @@ -114,7 +113,7 @@ class Command(BaseCommand): By default, We use checks of the 'cmd' type of lock to determine if the command should be run. """ - return permissions.has_perm(srcobj, self, 'cmd') + return super(Command, self).access(srcobj) def at_pre_cmd(self): """ diff --git a/game/gamesrc/objects/baseobjects.py b/game/gamesrc/objects/baseobjects.py index 778796e4ec..12b4d94757 100644 --- a/game/gamesrc/objects/baseobjects.py +++ b/game/gamesrc/objects/baseobjects.py @@ -91,7 +91,7 @@ class Object(BaseObject): """ pass - + class Character(BaseCharacter): """ This is the default object created for a new user connecting - the @@ -103,7 +103,6 @@ class Character(BaseCharacter): def at_object_creation(self): # This adds the default cmdset to the player every time they log # in. Don't change this unless you really know what you are doing. - #self.scripts.add(scripts.AddDefaultCmdSet) super(Character, self).at_object_creation() # expand with whatever customizations you want below... @@ -147,6 +146,7 @@ class Exit(BaseExit): clean up a bit after themselves though, easiest accomplished by letting by_object_delete() call the object's parent. """ + def at_object_delete(self): """ The game needs to do some cache cleanups when deleting an exit, @@ -158,7 +158,6 @@ class Exit(BaseExit): # custom modifications below. # ... - class Player(BasePlayer): """ This class describes the actual OOC player (i.e. the user connecting diff --git a/src/commands/cmdhandler.py b/src/commands/cmdhandler.py index fab1add4fc..3e1d00c2bb 100644 --- a/src/commands/cmdhandler.py +++ b/src/commands/cmdhandler.py @@ -338,7 +338,7 @@ def cmdhandler(caller, raw_string, unloggedin=False, testing=False): cmd_candidate, cmd = matches[0] # Check so we have permission to use this command. - if not cmd.has_perm(caller): + if not cmd.access(caller): cmd = cmdset.get(CMD_NOPERM) if cmd: sysarg = raw_string diff --git a/src/commands/cmdset.py b/src/commands/cmdset.py index 44f269b634..ccb8f3f107 100644 --- a/src/commands/cmdset.py +++ b/src/commands/cmdset.py @@ -28,9 +28,11 @@ class CmdSetMeta(type): # by default we key the cmdset the same as the # name of its class. mcs.key = mcs.__name__ + mcs.path = "%s.%s" % (mcs.__module__, mcs.__name__) if not type(mcs.key_mergetypes) == dict: mcs.key_mergetypes = {} + super(CmdSetMeta, mcs).__init__(*args, **kwargs) diff --git a/src/commands/cmdsethandler.py b/src/commands/cmdsethandler.py index 2f19b350d3..d4a9ebb58d 100644 --- a/src/commands/cmdsethandler.py +++ b/src/commands/cmdsethandler.py @@ -99,7 +99,6 @@ def import_cmdset(python_path, cmdsetobj, emit_to_obj=None, no_logging=False): module = __import__(modulepath, fromlist=[True]) cmdsetclass = module.__dict__[classname] CACHED_CMDSETS[wanted_cache_key] = cmdsetclass - #print "cmdset %s found." % wanted_cache_key #instantiate the cmdset (and catch its errors) if callable(cmdsetclass): cmdsetclass = cmdsetclass(cmdsetobj) @@ -362,3 +361,21 @@ class CmdSetHandler(object): self.cmdset_stack = [self.cmdset_stack[0]] self.mergetype_stack = [self.cmdset_stack[0].mergetype] self.update() + + def reset(self): + """ + Force reload of all cmdsets in handler. This should be called + after CACHED_CMDSETS have been cleared (normally by @reload). + """ + new_cmdset_stack = [] + new_mergetype_stack = [] + for cmdset in self.cmdset_stack: + if cmdset.key == "Empty": + new_cmdset_stack.append(cmdset) + new_mergetype_stack.append("Union") + else: + new_cmdset_stack.append(self.import_cmdset(cmdset.path)) + new_mergetype_stack.append(cmdset.mergetype) + self.cmdset_stack = new_cmdset_stack + self.mergetype_stack = new_mergetype_stack + self.update() diff --git a/src/commands/command.py b/src/commands/command.py index 77f90d60ca..a8dc21a94c 100644 --- a/src/commands/command.py +++ b/src/commands/command.py @@ -5,7 +5,7 @@ All commands in Evennia inherit from the 'Command' class in this module. """ -from src.permissions import permissions +from src.locks.lockhandler import LockHandler from src.utils.utils import is_iter class CommandMeta(type): @@ -17,18 +17,26 @@ class CommandMeta(type): """ Simply make sure all data are stored as lowercase and do checking on all properties that should be in list form. + Sets up locks to be more forgiving. """ mcs.key = mcs.key.lower() if mcs.aliases and not is_iter(mcs.aliases): mcs.aliases = mcs.aliases.split(',') mcs.aliases = [str(alias).strip().lower() for alias in mcs.aliases] - if mcs.permissions and not is_iter(mcs.permissions) : - mcs.permissions = mcs.permissions.split(',') - mcs.permissions = [str(perm).strip().lower() for perm in mcs.permissions] + + # pre-process locks as defined in class definition + temp = [] + if hasattr(mcs, 'permissions'): + mcs.locks = mcs.permissions + for lockstring in mcs.locks.split(';'): + if lockstring and not ':' in lockstring: + lockstring = "cmd:%s" % lockstring + temp.append(lockstring) + mcs.lock_storage = ";".join(temp) + mcs.help_category = mcs.help_category.lower() super(CommandMeta, mcs).__init__(*args, **kwargs) - # The Command class is the basic unit of an Evennia command; when # defining new commands, the admin subclass this class and # define their own parser method to handle the input. The @@ -69,15 +77,17 @@ class Command(object): key = "command" # alternative ways to call the command (e.g. 'l', 'glance', 'examine') aliases = [] - # a list of permission strings or comma-separated string limiting - # access to this command. - permissions = [] + # a list of lock definitions on the form cmd:[NOT] func(args) [ AND|OR][ NOT] func2(args) + locks = "" # used by the help system to group commands in lists. help_category = "general" # There is also the property 'obj'. This gets set by the system # on the fly to tie this particular command to a certain in-game entity. # self.obj should NOT be defined here since it will not be overwritten # if it already exists. + + def __init__(self): + self.lockhandler = LockHandler(self) def __str__(self): "Print the command" @@ -115,15 +125,15 @@ class Command(object): """ return (cmdname == self.key) or (cmdname in self.aliases) - def has_perm(self, srcobj): + def access(self, srcobj, access_type="cmd", default=False): """ This hook is called by the cmdhandler to determine if srcobj is allowed to execute this command. It should return a boolean value and is not normally something that need to be changed since it's using the Evennia permission system directly. """ - return permissions.has_perm(srcobj, self, 'cmd') - + return self.lockhandler.check(srcobj, access_type, default=default) + # Common Command hooks def at_pre_cmd(self): diff --git a/src/commands/default/admin.py b/src/commands/default/admin.py index 2340317102..e66d9c9611 100644 --- a/src/commands/default/admin.py +++ b/src/commands/default/admin.py @@ -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 [, , ... =] 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): diff --git a/src/commands/default/batchprocess.py b/src/commands/default/batchprocess.py index 8a75b3132e..442087075f 100644 --- a/src/commands/default/batchprocess.py +++ b/src/commands/default/batchprocess.py @@ -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 = """ diff --git a/src/commands/default/building.py b/src/commands/default/building.py index 7cafeefceb..f56797e02f 100644 --- a/src/commands/default/building.py +++ b/src/commands/default/building.py @@ -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 [ = ] + or + @lock[/switch] object/ + + 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 [ = ] or @lock[/switch] object/" + 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): diff --git a/src/commands/default/cmdset_default.py b/src/commands/default/cmdset_default.py index b53f29ae9f..dc204653ec 100644 --- a/src/commands/default/cmdset_default.py +++ b/src/commands/default/cmdset_default.py @@ -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()) diff --git a/src/commands/default/comms.py b/src/commands/default/comms.py index fade6af511..6f74754dd3 100644 --- a/src/commands/default/comms.py +++ b/src/commands/default/comms.py @@ -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] [,,... = ] tell '' - page/list + page Switch: - list - show your last of tells/pages. + last - shows who you last messaged + list - show your last 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 [ = 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)) diff --git a/src/commands/default/general.py b/src/commands/default/general.py index 51ed421cbb..3308840ed3 100644 --- a/src/commands/default/general.py +++ b/src/commands/default/general.py @@ -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): diff --git a/src/commands/default/help.py b/src/commands/default/help.py index 3ea366c885..57117a6b14 100644 --- a/src/commands/default/help.py +++ b/src/commands/default/help.py @@ -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] [,category[,permission,permission,...]] = + @help[/switches] [,category[,locks]] = 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] [,category[,permission,..] = ]") + if not self.args: + caller.msg("Usage: @sethelp/[add|del|append|merge] [,category[,locks,..] = ]") 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: diff --git a/src/commands/default/syscommands.py b/src/commands/default/syscommands.py index b472c91092..98026038a3 100644 --- a/src/commands/default/syscommands.py +++ b/src/commands/default/syscommands.py @@ -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") diff --git a/src/commands/default/system.py b/src/commands/default/system.py index e20d705823..c739f206dc 100644 --- a/src/commands/default/system.py +++ b/src/commands/default/system.py @@ -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, 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