""" Admin commands """ 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.utils import utils from src.commands.default.muxcommand import MuxCommand PERMISSION_HIERARCHY = [p.lower() for p in settings.PERMISSION_HIERARCHY] class CmdBoot(MuxCommand): """ @boot Usage @boot[/switches] [: reason] Switches: quiet - Silently boot without informing player port - boot by port number instead of name or dbref Boot a player object from the server. If a reason is supplied it will be echoed to the user unless /quiet is set. """ key = "@boot" locks = "cmd:perm(boot) or perm(Wizards)" help_category = "Admin" def func(self): "Implementing the function" caller = self.caller args = self.args if not args: caller.msg("Usage: @boot[/switches] [:reason]") return if ':' in args: args, reason = [a.strip() for a in args.split(':', 1)] else: args, reason = args, "" boot_list = [] if 'port' in self.switches: # Boot a particular port. sessions = SESSIONS.get_session_list(True) for sess in sessions: # Find the session with the matching port number. if sess.getClientAddress()[1] == int(args): boot_list.append(sess) break else: # Boot by player object pobj = caller.search("*%s" % args, global_search=True) if not pobj: return if pobj.character.has_player: if not pobj.access(caller, 'boot'): string = "You don't have the permission to boot %s." pobj.msg(string) return # we have a bootable object with a connected user matches = SESSIONS.sessions_from_player(pobj) for match in matches: boot_list.append(match) else: caller.msg("That object has no connected player.") return if not boot_list: caller.msg("No matches found.") return # Carry out the booting of the sessions in the boot list. feedback = None if not 'quiet' in self.switches: feedback = "You have been disconnected by %s.\n" % caller.name if reason: feedback += "\nReason given: %s" % reason for session in boot_list: name = session.name session.msg(feedback) session.disconnect() caller.msg("You booted %s." % name) class CmdDelPlayer(MuxCommand): """ delplayer - delete player from server Usage: @delplayer[/switch] [: reason] Switch: delobj - also delete the player's currently assigned in-game object. Completely deletes a user from the server database, making their nick and e-mail again available. """ key = "@delplayer" locks = "cmd:perm(delplayer) or perm(Immortals)" help_category = "Admin" def func(self): "Implements the command." caller = self.caller args = self.args if not args: caller.msg("Usage: @delplayer[/delobj] [: reason]") return reason = "" if ':' in args: args, reason = [arg.strip() for arg in args.split(':', 1)] # We use player_search since we want to be sure to find also players # that lack characters. players = caller.search("*%s" % args) if not players: try: players = PlayerDB.objects.filter(id=args) except ValueError: pass if not players: # try to find a user instead of a Player try: user = User.objects.get(id=args) except Exception: try: user = User.objects.get(username__iexact=args) except Exception: string = "No Player nor User found matching '%s'." % args caller.msg(string) return try: player = user.get_profile() except Exception: player = None if player and not player.access(caller, 'delete'): string = "You don't have the permissions to delete this player." caller.msg(string) return string = "" name = user.username user.delete() if player: name = player.name player.delete() string = "Player %s was deleted." % name else: string += "The User %s was deleted. It had no Player associated with it." % name caller.msg(string) return 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 user = player.user character = player.character if not player.access(caller, 'delete'): string = "You don't have the permissions to delete that player." caller.msg(string) return uname = user.username # boot the player then delete if character and character.has_player: caller.msg("Booting and informing player ...") string = "\nYour account '%s' is being *permanently* deleted.\n" % uname if reason: string += " Reason given:\n '%s'" % reason character.msg(string) caller.execute_cmd("@boot %s" % uname) player.delete() user.delete() caller.msg("Player %s was successfully deleted." % uname) class CmdEmit(MuxCommand): """ @emit Usage: @emit[/switches] [, , ... =] @remit [, , ... =] @pemit [, , ... =] Switches: room : limit emits to rooms only (default) players : limit emits to players only contents : send to the contents of matched objects too Emits a message to the selected objects or to your immediate surroundings. If the object is a room, send to its contents. @remit and @pemit are just limited forms of @emit, for sending to rooms and to players respectively. """ key = "@emit" aliases = ["@pemit", "@remit"] locks = "cmd:perm(emit) or perm(Builders)" help_category = "Admin" def func(self): "Implement the command" caller = self.caller args = self.args if not args: string = "Usage: " string += "\n@emit[/switches] [, , ... =] " string += "\n@remit [, , ... =] " string += "\n@pemit [, , ... =] " caller.msg(string) return rooms_only = 'rooms' in self.switches players_only = 'players' in self.switches send_to_contents = 'contents' in self.switches # we check which command was used to force the switches if self.cmdstring == '@remit': rooms_only = True elif self.cmdstring == '@pemit': players_only = True if not self.rhs: message = self.args objnames = [caller.location.key] else: message = self.rhs objnames = self.lhslist # send to all objects for objname in objnames: obj = caller.search(objname, global_search=True) if not obj: return if rooms_only and not obj.location == None: caller.msg("%s is not a room. Ignored." % objname) continue if players_only and not obj.has_player: caller.msg("%s has no active player. Ignored." % objname) continue if obj.access(caller, 'tell'): obj.msg(message) if send_to_contents: for content in obj.contents: content.msg(message) caller.msg("Emitted to %s and its contents." % objname) else: caller.msg("Emitted to %s." % objname) else: caller.msg("You are not allowed to send to %s." % objname) class CmdNewPassword(MuxCommand): """ @setpassword Usage: @userpassword = Set a player's password. """ key = "@userpassword" locks = "cmd:perm(newpassword) or perm(Wizards)" help_category = "Admin" def func(self): "Implement the function." caller = self.caller if not self.rhs: caller.msg("Usage: @userpassword = ") return # the player search also matches 'me' etc. player = caller.search("*%s" % self.lhs, global_search=True) if not player: return player.user.set_password(self.rhs) player.user.save() caller.msg("%s - new password set to '%s'." % (player.name, self.rhs)) if player.character != caller: player.msg("%s has changed your password to '%s'." % (caller.name, self.rhs)) class CmdPerm(MuxCommand): """ @perm - set permissions Usage: @perm[/switch] [= [,,...]] Switches: del : delete the given permission from . This command sets/clears individual permission strings on an object. If no permission is given, list all permissions on """ key = "@perm" aliases = "@setperm" locks = "cmd:perm(perm) or perm(Immortals)" help_category = "Admin" def func(self): "Implement function" caller = self.caller switches = self.switches lhs, rhs = self.lhs, self.rhs if not self.args: string = "Usage: @perm[/switch] object [ = permission, permission, ...]\n" caller.msg(string) return # locate the object obj = caller.search(lhs, global_search=True) if not obj: return if not rhs: if not obj.access(caller, 'examine'): caller.msg("You are not allowed to examine this object.") return string = "Permissions on {w%s{n: " % obj.key if not obj.permissions: string += "" else: string += ", ".join(obj.permissions) if hasattr(obj, 'player') and hasattr(obj.player, 'is_superuser') and obj.player.is_superuser: string += "\n(... but this object is currently controlled by a SUPERUSER! " string += "All access checks are passed automatically.)" caller.msg(string) return # we supplied an argument on the form obj = perm if not obj.access(caller, 'control'): caller.msg("You are not allowed to edit this object's permissions.") return cstring = "" tstring = "" if 'del' in switches: # delete the given permission(s) from object. for perm in self.rhslist: try: index = obj.permissions.index(perm) except ValueError: cstring += "\nPermission '%s' was not defined on %s." % (perm, obj.name) continue permissions = obj.permissions del permissions[index] obj.permissions = permissions cstring += "\nPermission '%s' was removed from %s." % (perm, obj.name) tstring += "\n%s revokes the permission '%s' from you." % (caller.name, perm) else: # add a new permission permissions = obj.permissions caller.permissions for perm in self.rhslist: perm = perm.lower() # don't allow to set a permission higher in the hierarchy than the one the # caller has (to prevent self-escalation) if perm in PERMISSION_HIERARCHY and not obj.locks.check_lockstring(caller, "dummy:perm(%s)" % perm): caller.msg("You cannot assign a permission higher than the one you have yourself.") return if perm in permissions: cstring += "\nPermission '%s' is already defined on %s." % (rhs, obj.name) else: permissions.append(perm) obj.permissions = permissions cstring += "\nPermission '%s' given to %s." % (rhs, obj.name) tstring += "\n%s gives you the permission '%s'." % (caller.name, rhs) caller.msg(cstring.strip()) if tstring: obj.msg(tstring.strip()) class CmdPuppet(MuxCommand): """ Switch control to an object Usage: @puppet This will attempt to "become" a different character. Note that this command does not check so that the target object has the appropriate cmdset. You cannot puppet a character that is already "taken". """ key = "@puppet" locks = "cmd:perm(puppet) or perm(Builders)" help_category = "Admin" def func(self): """ Simple puppet method (does not check permissions) """ caller = self.caller if not self.args: caller.msg("Usage: @puppet ") return player = caller.player new_character = caller.search(self.args) if not new_character: return 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: caller.msg("You cannot control %s." % new_character.name) class CmdWall(MuxCommand): """ @wall Usage: @wall Announces a message to all connected players. """ key = "@wall" locks = "cmd:perm(wall) or perm(Wizards)" help_category = "Admin" def func(self): "Implements command" if not self.args: self.caller.msg("Usage: @wall ") return message = "%s shouts \"%s\"" % (self.caller.name, self.args) SESSIONS.announce_all(message)