diff --git a/src/commands/default/building.py b/src/commands/default/building.py index d447681df9..f260895dc3 100644 --- a/src/commands/default/building.py +++ b/src/commands/default/building.py @@ -9,6 +9,9 @@ from src.objects.models import ObjectDB, ObjAttribute from src.utils import create, utils, debug from src.commands.default.muxcommand import MuxCommand +# used by @find +CHAR_TYPECLASS = settings.BASE_CHARACTER_TYPECLASS + class ObjManipCommand(MuxCommand): """ This is a parent class for some of the defining objmanip commands @@ -1562,35 +1565,92 @@ class CmdFind(MuxCommand): find objects Usage: - @find + @find[/switches] [= dbrefmin[ dbrefmax]] + + Switches: + room - only look for rooms (location=None) + exit - only look for exits (destination!=None) + char - only look for characters (BASE_CHARACTER_TYPECLASS) + + Searches the database for an object of a particular name or dbref. + Use *playername to search for a player. The switches allows for + limiting matches to certain game entities. Dbrefmin and dbrefmax + limits matches to within the given dbrefs, or above/below if only one is given. + """ - Searches for an object of a particular name. - """ - key = "@find" - aliases = "@locate, find, locate" + aliases = "find, @search, search, @locate, locate" locks = "cmd:perm(find) or perm(Builders)" help_category = "Building" def func(self): "Search functionality" caller = self.caller - arglist = self.arglist + switches = self.switches - if not arglist: - caller.msg("Usage: @find ")# [,low [,high]]") + if not self.args: + caller.msg("Usage: @find [= low [high]]") return - searchstring = arglist[0] - if len(arglist) > 1: - low = arglist[1] - if len(arglist) > 2: - high = arglist[2] - #TODO: Implement efficient db search with limits - result = caller.search(searchstring, global_search=True) - if not result: - return - string = "%s(#%s) - %s" % (result.name, result.id, result) - caller.msg(string) + + searchstring = self.lhs + low, high = 1, ObjectDB.objects.all().order_by("-id")[0].id + if self.rhs: + if "-" in self.rhs: + # also support low-high syntax + limlist = [part.strip() for part in self.rhs.split("-", 1)] + else: + # otherwise split by space + limlist = self.rhs.split(None, 1) + if limlist and limlist[0].isdigit(): + low = max(low, int(limlist[0])) + if len(limlist) > 1 and limlist[1].isdigit(): + high = min(high, int(limlist[1])) + low = min(low, high) + high = max(low, high) + + if searchstring.startswith("*") or utils.dbref(searchstring): + # A player/dbref search. + # run a normal player- or dbref search. This should be unique. + + string = "{wMatch{n(#%i-#%i):" % (low, high) + + result = caller.search(searchstring, global_search=True) + if not result: + return + if not low <= int(result.id) <= high: + string += "\n {RNo match found for '%s' within the given dbref limits.{n" % searchstring + else: + string += "\n{g %s(%s) - %s{n" % (result.key, result.dbref, result.typeclass) + else: + # Not a player/dbref search but a wider search; build a queryset. + + results = ObjectDB.objects.filter(db_key__istartswith=searchstring, id__gte=low, id__lte=high) + if "room" in switches: + results = results.filter(db_location__isnull=True) + if "exit" in switches: + results = results.filter(db_destination__isnull=False) + if "char" in switches: + results = results.filter(db_typeclass_path=CHAR_TYPECLASS) + nresults = results.count() + restrictions = "" + if self.switches: + restrictions = ", %s" % (",".join(self.switches)) + if nresults: + # convert result to typeclasses. Database is not hit until this point! + results = [result.typeclass(result) for result in results] + if nresults > 1: + string = "{w%i Matches{n(#%i-#%i%s):" % (nresults, low, high, restrictions) + for res in results: + string += "\n {g%s(%s) - %s{n" % (res.key, res.dbref, res.typeclass) + else: + string = "{wOne Match{n(#%i-#%i%s):" % (low, high, restrictions) + string += "\n {g%s(%s) - %s{n" % (results[0].key, results[0].dbref, results[0].typeclass) + else: + string = "{wMatch{n(#%i-#%i%s):" % (low, high, restrictions) + string += "\n {RNo matches found for '%s'{n" % searchstring + + # send result + caller.msg(string.strip()) class CmdTeleport(MuxCommand): diff --git a/src/commands/default/cmdset_default.py b/src/commands/default/cmdset_default.py index 255a38e659..9d0b24e46c 100644 --- a/src/commands/default/cmdset_default.py +++ b/src/commands/default/cmdset_default.py @@ -83,6 +83,7 @@ class DefaultCmdSet(CmdSet): # Comm commands self.add(comms.CmdAddCom()) self.add(comms.CmdDelCom()) + self.add(comms.CmdAllCom()) self.add(comms.CmdChannels()) self.add(comms.CmdCdestroy()) self.add(comms.CmdChannelCreate()) diff --git a/src/commands/default/comms.py b/src/commands/default/comms.py index f9670415f7..920dfd3ca6 100644 --- a/src/commands/default/comms.py +++ b/src/commands/default/comms.py @@ -70,7 +70,7 @@ class CmdAddCom(MuxCommand): # check permissions if not channel.access(player, 'listen'): - caller.msg("You are not allowed to listen to this channel.") + caller.msg("%s: You are not allowed to listen to this channel." % channel.key) return string = "" @@ -78,18 +78,20 @@ class CmdAddCom(MuxCommand): # we want to connect as well. if not channel.connect_to(player): # if this would have returned True, the player is connected - caller.msg("You are not allowed to join this channel.") + caller.msg("%s: You are not allowed to join this channel." % channel.key) return else: string += "You now listen to the channel %s. " % channel.key + else: + string += "You are already connected to channel %s." % channel.key if alias: # create a nick and add it to the caller. caller.nicks.add(alias, channel.key, nick_type="channel") - string += "You can now refer to the channel %s with the alias '%s'." + string += " You can now refer to the channel %s with the alias '%s'." caller.msg(string % (channel.key, alias)) else: - string += "No alias added." + string += " No alias added." caller.msg(string) @@ -125,7 +127,7 @@ class CmdDelCom(MuxCommand): if channel: # we have given a channel name - unsubscribe if not channel.has_connection(player): - caller.msg("You are listening to that channel.") + caller.msg("You are not listening to that channel.") return chkey = channel.key.lower() # find all nicks linked to this channel and delete them @@ -145,97 +147,66 @@ class CmdDelCom(MuxCommand): caller.nicks.delete(ostring, nick_type="channel") caller.msg("Your alias '%s' for channel %s was cleared." % (ostring, channel.key)) -# def cmd_allcom(command): -# """ -# allcom - operate on all channels +class CmdAllCom(MuxCommand): + """ + allcom - operate on all channels -# Usage: -# allcom [on | off | who | clear] + Usage: + allcom [on | off | who | destroy] -# Allows the user to universally turn off or on all channels they are on, -# as well as perform a 'who' for all channels they are on. Clear deletes -# all channels. + Allows the user to universally turn off or on all channels they are on, + as well as perform a 'who' for all channels they are on. Destroy deletes + all channels that you control. -# Without argument, works like comlist. -# """ + Without argument, works like comlist. + """ -# caller = self.caller -# arg = self.args -# if not arg: -# cmd_comlist(command) -# caller.msg("(allcom arguments: 'on', 'off', 'who' and 'clear'.)") -# return -# arg = arg.strip() -# if arg == 'clear': -# cmd_clearcom(command) -# return + key = "allcom" + locks = "cmd: not perm(channel_banned)" + help_category = "Comms" -# #get names and alias of all subscribed channels -# chandict = comsys.plr_get_cdict(self.session) -# aliaslist = chandict.keys() -# aliaslist.sort() -# if arg == "on": -# for alias in aliaslist: -# comsys.plr_chan_on(self.session, alias) -# elif arg == "off": -# for alias in aliaslist: -# comsys.plr_chan_off(self.session, alias) -# elif arg == "who": -# s = "" -# if not aliaslist: -# s += " (No channels) " -# for alias in aliaslist: -# s += "-- %s (alias: %s)\n" % (chandict[alias][0],alias) -# sess_list = comsys.get_cwho_list(chandict[alias][0]) -# objlist = [sess.get_pobject() for sess in sess_list] -# plist = [p.get_name(show_dbref=caller.sees_dbrefs()) -# for p in filter(lambda o: o.is_player(), objlist)] -# olist = [o.get_name(show_dbref=caller.sees_dbrefs()) -# for o in filter(lambda o: not o.is_player(), objlist)] -# plist.sort() -# olist.sort() -# if plist: -# s += " Players:\n " -# for pname in plist: -# s += "%s, " % pname -# s = s[:-2] + "\n" -# if olist: -# s += " Objects:\n " -# for oname in olist: -# s += "%s, " % oname -# s = s[:-2] + "\n" -# s = s[:-1] -# caller.msg(s) -# GLOBAL_CMD_TABLE.add_self("allcom", cmd_allcom, help_category="Comms") - -## def cmd_clearcom(self): -## """ -## clearcom - removes all channels + def func(self): + "Runs the function" -## Usage: -## clearcom + caller = self.caller + args = self.args + if not args: + caller.execute_cmd("@channels") + caller.msg("(Usage: allcom on | off | who | destroy)") + return -## Effectively runs delcom on all channels the user is on. It will remove -## their aliases, remove them from the channel, and clear any titles they -## have set. -## """ -## caller = self.caller -## #get aall subscribed channel memberships -## memberships = caller.channel_membership_set.all() - -## if not memberships: -## s = "No channels to delete. " -## else: -## s = "Deleting all channels in your subscriptions ...\n" -## for membership in memberships: -## chan_name = membership.channel.get_name() -## s += "You have left %s.\n" % chan_name -## comsys.plr_del_channel(caller, membership.user_alias) -## comsys.send_cmessage(chan_name, "%s has left the channel." % caller.get_name(show_dbref=False)) -## s = s[:-1] -## caller.msg(s) -## GLOBAL_CMD_TABLE.add_self("clearcom", cmd_clearcom) - + if args == "on": + # get names of all channels available to listen to and activate them all + channels = [chan for chan in Channel.objects.get_all_channels() if chan.access(caller, 'listen')] + for channel in channels: + caller.execute_cmd("addcom %s" % channel.key) + elif args == "off": + #get names all subscribed channels and disconnect from them all + channels = [conn.channel for conn in PlayerChannelConnection.objects.get_all_player_connections(caller.player)] + for channel in channels: + caller.execute_cmd("delcom %s" % channel.key) + elif args == "destroy": + # destroy all channels you control + channels = [chan for chan in Channel.objects.get_all_channels() if chan.access(caller, 'control')] + for channel in channels: + caller.execute_cmd("@cdestroy %s" % channel.key) + elif args == "who": + # run a who, listing the subscribers on visible channels. + string = "\n{CChannel subscriptions{n" + channels = [chan for chan in Channel.objects.get_all_channels() if chan.access(caller, 'listen')] + if not channels: + string += "No channels." + for channel in channels: + string += "\n{w%s:{n\n" % channel.key + conns = PlayerChannelConnection.objects.get_all_connections(channel) + if conns: + string += " " + ", ".join([conn.player.key for conn in conns]) + else: + string += " " + caller.msg(string.strip()) + else: + # wrong input + caller.msg("Usage: allcom on | off | who | clear") class CmdChannels(MuxCommand): """ @@ -246,7 +217,7 @@ class CmdChannels(MuxCommand): @clist comlist - Lists all available channels available to you, wether you listen to them or not. + Lists all channels available to you, wether you listen to them or not. Use 'comlist" to only view your current channel subscriptions. """ key = "@channels" @@ -262,7 +233,7 @@ class CmdChannels(MuxCommand): # all channels we have available to listen to channels = [chan for chan in Channel.objects.get_all_channels() if chan.access(caller, 'listen')] if not channels: - caller.msg("No channels available") + caller.msg("No channels available.") return # all channel we are already subscribed to subs = [conn.channel for conn in PlayerChannelConnection.objects.get_all_player_connections(caller.player)] @@ -333,7 +304,7 @@ class CmdCdestroy(MuxCommand): if not channel: caller.msg("Could not find channel %s." % self.args) return - if not channel.access(caller, 'admin'): + if not channel.access(caller, 'control'): caller.msg("You are not allowed to do that.") return @@ -606,7 +577,7 @@ class CmdChannelCreate(MuxCommand): caller.msg("A channel with that name already exists.") return # Create and set the channel up - lockstring = "send:all();listen:all();admin:id(%s)" % caller.id + lockstring = "send:all();listen:all();control: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) @@ -683,7 +654,7 @@ class CmdCdesc(MuxCommand): caller.msg("Channel '%s' not found." % self.lhs) return #check permissions - if not caller.access(caller, 'admin'): + if not caller.access(caller, 'control'): caller.msg("You cant admin this channel.") return # set the description diff --git a/src/commands/default/general.py b/src/commands/default/general.py index 483660a992..348de2378c 100644 --- a/src/commands/default/general.py +++ b/src/commands/default/general.py @@ -432,57 +432,6 @@ class CmdSay(MuxCommand): caller.location.msg_contents(emit_string, exclude=caller) -## def cmd_fsay(command): -## """ -## @fsay - make an object say something - -## Usage: -## @fsay = - -## Make an object talk to its current location. -## """ -## caller = command.caller -## args = command.command_argument - -## if not args or not "=" in args: -## caller.msg("Usage: @fsay = ") -## return -## target, speech = [arg.strip() for arg in args.split("=",1)] - -## # find object -## if target in ['here']: -## results = [caller.location] -## elif target in ['me','my']: -## results = [caller] -## else: -## results = Object.objects.global_object_name_search(target) -## if not results: -## caller.msg("No matches found for '%s'." % target) -## return -## if len(results) > 1: -## string = "There are multiple matches. Please use #dbref to be more specific." -## for result in results: -## string += "\n %s" % results.name -## caller.msg(string) -## return -## target = results[0] - -## # permission check -## if not caller.controls_other(target): -## caller.msg("Cannot pose %s (you don's control it)" % target.name) -## return - -## # Feedback for the object doing the talking. -## caller.msg("%s says, '%s%s'" % (target.name, -## speech, -## ANSITable.ansi['normal'])) - -## # Build the string to emit to neighbors. -## emit_string = "%s says, '%s'" % (target.name, -## speech) -## target.location.msg_contents(emit_string, -## exclude=caller) -## GLOBAL_CMD_TABLE.add_command("@fsay", cmd_fsay) class CmdPose(MuxCommand): """ @@ -525,64 +474,6 @@ class CmdPose(MuxCommand): msg = "%s%s" % (self.caller.name, self.args) self.caller.location.msg_contents(msg) -## def cmd_fpose(command): -## """ -## @fpose - force an object to pose - -## Usage: -## @fpose[/switches] = - -## Switches: -## nospace : put no text between the object's name -## and the start of the pose. - -## Describe an action being taken as performed by obj. -## The pose text will automatically begin with the name -## of the object. -## """ -## caller = command.caller -## args = command.command_argument - -## if not args or not "=" in args: -## caller.msg("Usage: @fpose = ") -## return -## target, pose_string = [arg.strip() for arg in args.split("=",1)] -## # find object -## if target in ['here']: -## results = [caller.location] -## elif target in ['me','my']: -## results = [caller] -## else: -## results = Object.objects.global_object_name_search(target) -## if not results: -## caller.msg("No matches found for '%s'." % target) -## return -## if len(results) > 1: -## string = "There are multiple matches. Please use #dbref to be more specific." -## for result in results: -## string += "\n %s" % results.name -## caller.msg(string) -## return -## target = results[0] - -## # permission check -## if not caller.controls_other(target): -## caller.msg("Cannot pose %s (you don's control it)" % target.name) -## return - -## if "nospace" in command.command_switches: -## # Output without a space between the player name and the emote. -## sent_msg = "%s%s" % (target.name, -## pose_string) -## else: -## # No switches, default. -## sent_msg = "%s %s" % (target.name, -## pose_string) - -## caller.location.msg_contents(sent_msg) -## GLOBAL_CMD_TABLE.add_command("@fpose", cmd_fpose) - - class CmdEncoding(MuxCommand): """ encoding - set a custom text encoding @@ -666,23 +557,3 @@ class CmdAccess(MuxCommand): if hasattr(caller, 'player'): string += "\nPlayer %s: %s" % (caller.player.key, ", ".join(caller.player.permissions)) caller.msg(string) - -## def cmd_apropos(command): -## """ -## apropos - show rough help matches - -## Usage: -## apropos -## or -## suggest - -## This presents a list of topics very loosely matching your -## search text. Use this command when you are searching for -## help on a certain concept but don't know any exact -## command names. You can also use the normal help command -## with the /apropos switch to get the same functionality. -## """ -## arg = command.command_argument -## command.caller.execute_cmd("help/apropos %s" % arg) -## GLOBAL_CMD_TABLE.add_command("apropos", cmd_apropos) -## GLOBAL_CMD_TABLE.add_command("suggest", cmd_apropos) diff --git a/src/commands/default/help.py b/src/commands/default/help.py index eccc931510..ea8b5cb191 100644 --- a/src/commands/default/help.py +++ b/src/commands/default/help.py @@ -13,24 +13,25 @@ from src.utils import create from src.commands.default.muxcommand import MuxCommand LIST_ARGS = ["list", "all"] - +SEP = "{C" + "-"*78 + "{n" + def format_help_entry(title, help_text, aliases=None, suggested=None): """ This visually formats the help entry. """ - string = "-"*78 + "\n" + string = SEP + "\n" if title: - string += "Help topic for {w%s{n" % (title.capitalize()) + string += "{CHelp topic for {w%s{n" % (title.capitalize()) if aliases: - string += " (aliases: %s)" % (", ".join(aliases)) + string += " {C(aliases: {w%s{n{C){n" % (", ".join(aliases)) if help_text: string += "\n%s" % dedent(help_text.rstrip()) if suggested: - string += "\nSuggested:\n" - string += fill(", ".join(suggested)) + string += "\n\n{CSuggested:{n " + string += "{w%s{n" % fill(", ".join(suggested)) string.strip() - string += "\n" + "-"*78 + string += "\n" + SEP return string def format_help_list(hdict_cmds, hdict_db): @@ -39,16 +40,15 @@ def format_help_list(hdict_cmds, hdict_db): """ string = "" if hdict_cmds and hdict_cmds.values(): - string += "\n\r" + "-"*70 + "\n\r {gCommand help entries{n\n" + "-"*70 + string += "\n" + SEP + "\n {CCommand help entries{n\n" + SEP for category in sorted(hdict_cmds.keys()): - string += "\n {w%s{n:\n" % \ - (str(category).capitalize()) - string += fill(", ".join(sorted(hdict_cmds[category]))) + string += "\n {w%s{n:\n" % (str(category).capitalize()) + string += "{G" + fill(", ".join(sorted(hdict_cmds[category]))) + "{n" if hdict_db and hdict_db.values(): - string += "\n\r\n\r" + "-"*70 + "\n\r {gOther help entries{n\n" + '-'*70 + string += "\n\n" + SEP + "\n\r {COther help entries{n\n" + SEP for category in sorted(hdict_db.keys()): string += "\n\r {w%s{n:\n" % (str(category).capitalize()) - string += fill(", ".join(sorted([str(topic) for topic in hdict_db[category]]))) + string += "{G" + fill(", ".join(sorted([str(topic) for topic in hdict_db[category]]))) + "{n" return string class CmdHelp(Command): @@ -72,7 +72,7 @@ class CmdHelp(Command): def parse(self): """ - inp is a string containing the command or topic match. + input is a string containing the command or topic to match. """ self.original_args = self.args.strip() self.args = self.args.strip().lower() diff --git a/src/commands/default/system.py b/src/commands/default/system.py index a4c2416248..bd90279ff8 100644 --- a/src/commands/default/system.py +++ b/src/commands/default/system.py @@ -295,8 +295,8 @@ class CmdObjects(MuxCommand): srow = "{w%s{n" % srow string += srow - string += "\n\n{wLast %s Objects created:{n" % nlim - objs = ObjectDB.objects.all()[max(0, nobjs-nlim):] + string += "\n\n{wLast %s Objects created:{n" % min(nobjs, nlim) + objs = ObjectDB.objects.all().order_by("db_date_created")[max(0, nobjs-nlim):] table = [["Created"], ["dbref"], ["name"], ["typeclass"]] for i, obj in enumerate(objs): diff --git a/src/commands/default/unimplemented/__init__.py b/src/commands/default/unimplemented/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/src/commands/default/unimplemented/search.py b/src/commands/default/unimplemented/search.py deleted file mode 100644 index c163b35e33..0000000000 --- a/src/commands/default/unimplemented/search.py +++ /dev/null @@ -1,235 +0,0 @@ -""" -Implementation of the @search command that resembles MUX2. -""" -from django.db.models import Q -#from src.objects.models import Object -from src.utils import OBJECT as Object -from src import defines_global -from src.cmdtable import GLOBAL_CMD_TABLE - -def _parse_restriction_split(source_object, restriction_split, search_low_dbnum, - search_high_dbnum): - """ - Parses a split restriction string and sets some needed variables. - - Returns a tuple in the form of: (low dbnum, high dbnum) - """ - restriction_size = len(restriction_split) - if restriction_size >= 2: - try: - search_low_dbnum = int(restriction_split[1].strip()) - except ValueError: - source_object.msg("Invalid value for low dbref limit.") - return False - if restriction_size >= 3: - try: - search_high_dbnum = int(restriction_split[2].strip()) - except ValueError: - source_object.msg("Invalid value for high dbref limit.") - return False - - return search_low_dbnum, search_high_dbnum - -def display_results(source_object, search_query): - """ - Display the results to the searcher. - """ - # Lists to hold results by type. There may be a better way to do this - thing_list = [] - room_list = [] - exit_list = [] - player_list = [] - # this bits gotta get totally redone - for obj in search_query: - thing_list.append(obj) - - # Render each section for different object types - if thing_list: - source_object.msg("\n\rTHINGS:") - for thing in thing_list: - source_object.msg(thing.name) - - if exit_list: - source_object.msg("\n\rEXITS:") - for exit in exit_list: - source_object.msg(exit.name) - - if room_list: - source_object.msg("\n\rROOMS:") - for room in room_list: - source_object.msg(room.name) - - if player_list: - source_object.msg("\n\rPLAYER:") - for player in player_list: - source_object.msg(player.name) - - # Show the total counts by type - source_object.msg("\n\rFound: Rooms...%d Exits...%d Things...%d Players...%d" % ( - len(room_list), - len(exit_list), - len(thing_list), - len(player_list))) - -def build_query(source_object, search_query, search_player, search_type, - search_restriction, search_low_dbnum, search_high_dbnum): - """ - Builds and returns a QuerySet object, or None if an error occurs. - """ - # Look up an Object matching the player search query - if search_player: - # Replace the string variable with an Object reference - search_player = source_object.search_for_object(search_player) - # Use standard_objsearch to handle duplicate/nonexistant results - if not search_player: - return None - - # Searching by player, chain filter - search_query = search_query.filter(owner=search_player) - - # Check to ensure valid search types - if search_type == "type": - if search_restriction == "room": - search_query = search_query.filter(type=defines_global.OTYPE_ROOM) - elif search_restriction == "thing": - search_query = search_query.filter(type=defines_global.OTYPE_THING) - elif search_restriction == "exit": - search_query = search_query.filter(type=defines_global.OTYPE_EXIT) - elif search_restriction == "player": - search_query = search_query.filter(type=defines_global.OTYPE_PLAYER) - else: - source_object.msg("Invalid class. See 'help SEARCH CLASSES'.") - return None - elif search_type == "parent": - search_query = search_query.filter(script_parent__iexact=search_restriction) - elif search_type == "object" or search_type == "thing": - search_query = search_query.filter(name__icontains=search_restriction, - type=defines_global.OTYPE_THING) - elif search_type == "rooms": - search_query = search_query.filter(name__icontains=search_restriction, - type=defines_global.OTYPE_ROOM) - elif search_type == "exits": - search_query = search_query.filter(name__icontains=search_restriction, - type=defines_global.OTYPE_EXIT) - elif search_type == "players": - search_query = search_query.filter(name__icontains=search_restriction, - type=defines_global.OTYPE_PLAYER) - elif search_type == "zone": - zone_obj = source_object.search_for_object(search_restriction) - # Use search_for_object to handle duplicate/nonexistant results. - if not zone_obj: - return None - search_query = search_query.filter(zone=zone_obj) - elif search_type == "power": - # TODO: Need this once we have powers implemented. - source_object.msg("To be implemented...") - return None - elif search_type == "flags": - flag_list = search_restriction.split() - #source_object.msg("restriction: %s" % flag_list) - for flag in flag_list: - search_query = search_query.filter(Q(flags__icontains=flag) | Q(nosave_flags__icontains=flag)) - - if search_low_dbnum: - search_query = search_query.filter(id__gte=search_low_dbnum) - - if search_high_dbnum: - search_query = search_query.filter(id__lte=search_high_dbnum) - - return search_query - -def cmd_search(command): - """ - search - - Usage: - search - - Searches for owned objects as per MUX2. - """ - source_object = command.source_object - - search_player = None - search_type = None - search_restriction = None - search_low_dbnum = None - search_high_dbnum = None - - if not command.command_argument: - search_player = "#" + str(source_object.id) - else: - first_check_split = command.command_argument.split(' ', 1) - if '=' in first_check_split[0]: - # @search class=restriction... - eq_split = command.command_argument.split('=', 1) - search_type = eq_split[0] - restriction_split = eq_split[1].split(',') - search_restriction = restriction_split[0].strip() - #source_object.msg("@search class=restriction") - #source_object.msg("eq_split: %s" % eq_split) - #source_object.msg("restriction_split: %s" % restriction_split) - - try: - search_low_dbnum, search_high_dbnum = _parse_restriction_split(source_object, - restriction_split, - search_low_dbnum, - search_high_dbnum) - except TypeError: - return - - else: - # @search player - if len(first_check_split) == 1: - #source_object.msg("@search player") - #source_object.msg(first_check_split) - search_player = first_check_split[0] - else: - #source_object.msg("@search player class=restriction") - #source_object.msg(first_check_split) - search_player = first_check_split[0] - eq_split = first_check_split[1].split('=', 1) - search_type = eq_split[0] - #source_object.msg("eq_split: %s" % eq_split) - restriction_split = eq_split[1].split(',') - search_restriction = restriction_split[0] - #source_object.msg("restriction_split: %s" % restriction_split) - - try: - search_low_dbnum, search_high_dbnum = _parse_restriction_split(source_object, - restriction_split, - search_low_dbnum, - search_high_dbnum) - except TypeError: - return - - search_query = Object.objects.all() - - #source_object.msg("search_player: %s" % search_player) - #source_object.msg("search_type: %s" % search_type) - #source_object.msg("search_restriction: %s" % search_restriction) - #source_object.msg("search_lowdb: %s" % search_low_dbnum) - #source_object.msg("search_highdb: %s" % search_high_dbnum) - - # Clean up these variables for comparisons. - try: - search_type = search_type.strip().lower() - except AttributeError: - pass - try: - search_restriction = search_restriction.strip().lower() - except AttributeError: - pass - - # Build the search query. - search_query = build_query(source_object, search_query, search_player, search_type, - search_restriction, search_low_dbnum, - search_high_dbnum) - - # Something bad happened in query construction, die here. - if search_query is None: - return - - display_results(source_object, search_query) -GLOBAL_CMD_TABLE.add_command("@search", cmd_search, - priv_tuple=("objects.info",), - help_category="Building") diff --git a/src/comms/imc2.py b/src/comms/imc2.py index a1717f3796..e94934ff41 100644 --- a/src/comms/imc2.py +++ b/src/comms/imc2.py @@ -41,11 +41,11 @@ IMC2_CHANLIST = IMC2ChanList() def msg_info(message): """ Send info to default info channel - """ - message = '[%s][IMC2]: %s' % (INFOCHANNEL[0].key, message) + """ try: INFOCHANNEL[0].msg(message) - except AttributeError: + message = '[%s][IMC2]: %s' % (INFOCHANNEL[0].key, message) + except Exception: logger.log_infomsg("MUDinfo (imc2): %s" % message) # diff --git a/src/comms/migrations/0004_changing_lock_comm_admin2control.py b/src/comms/migrations/0004_changing_lock_comm_admin2control.py new file mode 100644 index 0000000000..bbe2f6d915 --- /dev/null +++ b/src/comms/migrations/0004_changing_lock_comm_admin2control.py @@ -0,0 +1,129 @@ +# encoding: utf-8 +import datetime +from south.db import db +from south.v2 import DataMigration +from django.db import models + +class Migration(DataMigration): + + # fixes a changed syntax in the locks. + + def forwards(self, orm): + "Write your forwards methods here." + for channel in orm.Channel.objects.all(): + lockstring = channel.db_lock_storage + lockstring = lockstring.replace("admin:", "control:") + channel.db_lock_storage = lockstring + channel.save() + + def backwards(self, orm): + "Write your backwards methods here." + for channel in orm.Channel.objects.all(): + lockstring = channel.db_lock_storage + lockstring = lockstring.replace("control:", "admin:") + channel.db_lock_storage = lockstring + channel.save() + + models = { + 'auth.group': { + 'Meta': {'object_name': 'Group'}, + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}), + 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}) + }, + 'auth.permission': { + 'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'}, + 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}) + }, + 'auth.user': { + 'Meta': {'object_name': 'User'}, + 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}), + 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), + 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), + 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}), + 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}), + 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'}) + }, + 'comms.channel': { + 'Meta': {'object_name': 'Channel'}, + 'db_aliases': ('django.db.models.fields.CharField', [], {'max_length': '255'}), + 'db_desc': ('django.db.models.fields.CharField', [], {'max_length': '80', 'null': 'True', 'blank': 'True'}), + 'db_keep_log': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'db_key': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}), + 'db_lock_storage': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}) + }, + 'comms.externalchannelconnection': { + 'Meta': {'object_name': 'ExternalChannelConnection'}, + 'db_channel': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['comms.Channel']"}), + 'db_external_config': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'db_external_key': ('django.db.models.fields.CharField', [], {'max_length': '128'}), + 'db_external_send_code': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'db_is_enabled': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}) + }, + 'comms.msg': { + 'Meta': {'object_name': 'Msg'}, + 'db_channels': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}), + 'db_date_sent': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}), + 'db_hide_from_channels': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}), + 'db_hide_from_receivers': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}), + 'db_hide_from_sender': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'db_lock_storage': ('django.db.models.fields.TextField', [], {'null': 'True'}), + 'db_message': ('django.db.models.fields.TextField', [], {}), + 'db_receivers': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}), + 'db_sender': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'sender_set'", 'null': 'True', 'to': "orm['players.PlayerDB']"}), + 'db_sender_external': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}) + }, + 'comms.playerchannelconnection': { + 'Meta': {'object_name': 'PlayerChannelConnection'}, + 'db_channel': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['comms.Channel']"}), + 'db_player': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['players.PlayerDB']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}) + }, + 'contenttypes.contenttype': { + 'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"}, + 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}) + }, + 'objects.objectdb': { + 'Meta': {'object_name': 'ObjectDB'}, + 'db_cmdset_storage': ('django.db.models.fields.TextField', [], {'null': 'True'}), + 'db_date_created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}), + 'db_destination': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'destinations_set'", 'null': 'True', 'to': "orm['objects.ObjectDB']"}), + 'db_home': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'homes_set'", 'null': 'True', 'to': "orm['objects.ObjectDB']"}), + 'db_key': ('django.db.models.fields.CharField', [], {'max_length': '255'}), + 'db_location': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'locations_set'", 'null': 'True', 'to': "orm['objects.ObjectDB']"}), + 'db_lock_storage': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'db_permissions': ('django.db.models.fields.CharField', [], {'max_length': '512', 'blank': 'True'}), + 'db_player': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['players.PlayerDB']", 'null': 'True', 'blank': 'True'}), + 'db_typeclass_path': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}) + }, + 'players.playerdb': { + 'Meta': {'object_name': 'PlayerDB'}, + 'db_date_created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}), + 'db_key': ('django.db.models.fields.CharField', [], {'max_length': '255'}), + 'db_lock_storage': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'db_obj': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['objects.ObjectDB']", 'null': 'True'}), + 'db_permissions': ('django.db.models.fields.CharField', [], {'max_length': '512', 'blank': 'True'}), + 'db_typeclass_path': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'unique': 'True'}) + } + } + + complete_apps = ['comms'] diff --git a/src/help/manager.py b/src/help/manager.py index 5a9dc32c54..7a3466731f 100644 --- a/src/help/manager.py +++ b/src/help/manager.py @@ -2,7 +2,7 @@ Custom manager for HelpEntry objects. """ from django.db import models -from src.utils import logger +from src.utils import logger, utils class HelpEntryManager(models.Manager): """ @@ -12,8 +12,8 @@ class HelpEntryManager(models.Manager): """ Searches for matching topics based on player's input. """ - if topicstr.isdigit(): - return self.filter(id=topicstr) + if utils.dbref(topicstr): + return self.filter(id=utils.dbref(topicstr)) topics = self.filter(db_key__iexact=topicstr) if not topics and not exact: topics = self.filter(db_key__istartswith=topicstr) diff --git a/src/locks/lockhandler.py b/src/locks/lockhandler.py index 5820dac5a3..ef483439fb 100644 --- a/src/locks/lockhandler.py +++ b/src/locks/lockhandler.py @@ -103,6 +103,14 @@ import re, inspect from django.conf import settings from src.utils import logger, utils +# +# Exception class +# + +class LockException(Exception): + pass + + # # Cached lock functions # @@ -181,7 +189,8 @@ class LockHandler(object): return locks nlocks = storage_lockstring.count(';') + 1 duplicates = 0 - elist = [] + elist = [] # errors + wlist = [] # warnings for raw_lockstring in storage_lockstring.split(';'): lock_funcs = [] access_type, rhs = (part.strip() for part in raw_lockstring.split(':', 1)) @@ -211,11 +220,13 @@ class LockHandler(object): continue if access_type in locks: duplicates += 1 - elist.append("Lock: access type '%s' changed from '%s' to '%s' " % \ - (access_type, locks[access_type][2], raw_lockstring)) + wlist.append("Lock: access type '%s' changed from '%s' to '%s' " % \ + (access_type, locks[access_type][2], raw_lockstring)) locks[access_type] = (evalstring, tuple(lock_funcs), raw_lockstring) + if wlist: + self._log_error("\n".join(wlist)) if elist: - self._log_error("\n".join(elist)) + raise LockException("\n".join(elist)) self.no_errors = False return locks @@ -304,12 +315,14 @@ class LockHandler(object): self._cache_locks(self.obj.lock_storage) self.reset_flag = False - if (not no_superuser_bypass and (hasattr(accessing_obj, 'player') - and hasattr(accessing_obj.player, 'is_superuser') and accessing_obj.player.is_superuser) - or (hasattr(accessing_obj, 'get_player') and (accessing_obj.get_player()==None or accessing_obj.get_player().is_superuser))): + if (not no_superuser_bypass + and ((hasattr(accessing_obj, 'is_superuser') and accessing_obj.is_superuser) + or (hasattr(accessing_obj, 'player') and hasattr(accessing_obj.player, 'is_superuser') and accessing_obj.player.is_superuser) + or (hasattr(accessing_obj, 'get_player') and (accessing_obj.get_player()==None or accessing_obj.get_player().is_superuser)))): # we grant access to superusers and also to protocol instances that not yet has any player assigned to them (the # latter is a safety feature since superuser cannot be authenticated at some point during the connection). return True + if access_type in self.locks: # we have a lock, test it. evalstring, func_tup, raw_string = self.locks[access_type] diff --git a/src/settings_default.py b/src/settings_default.py index 6ef479653c..ac66f1606d 100644 --- a/src/settings_default.py +++ b/src/settings_default.py @@ -249,15 +249,14 @@ LOCK_FUNC_MODULES = ("src.locks.lockfuncs",) # where aliases may be a tuple too, and locks is # a valid lockstring definition. # Default user channel for communication -CHANNEL_PUBLIC = ("Public", 'ooc', 'Public discussion', - "admin:perm(Wizards);listen:all();send:all()") +CHANNEL_PUBLIC = ("Public", ('ooc',), 'Public discussion', + "control:perm(Wizards);listen:all();send:all()") # General info about the server CHANNEL_MUDINFO = ("MUDinfo", '', 'Informative messages', - "admin:perm(Immortals);listen:perm(Immortals);send:false()") + "control:perm(Immortals);listen:perm(Immortals);send:false()") # Channel showing when new people connecting -CHANNEL_CONNECTINFO = ("MUDconnections", ('connections, mud_conns'), - 'Connection log', - "admin:perm(Immortals);listen:perm(Wizards);send:false()") +CHANNEL_CONNECTINFO = ("MUDconnections", '', 'Connection log', + "control:perm(Immortals);listen:perm(Wizards);send:false()") ################################################### # External Channel connections diff --git a/src/typeclasses/managers.py b/src/typeclasses/managers.py index 4639e8751a..d2ea973ac0 100644 --- a/src/typeclasses/managers.py +++ b/src/typeclasses/managers.py @@ -95,8 +95,7 @@ class TypedObjectManager(idmapper.manager.SharedMemoryManager): if isinstance(dbref, basestring): dbref = dbref.lstrip('#') try: - dbref = int(dbref) - if dbref < 1: + if int(dbref) < 1: return None except Exception: return None diff --git a/src/utils/debug.py b/src/utils/debug.py index 37337a4a37..c33d51b21b 100644 --- a/src/utils/debug.py +++ b/src/utils/debug.py @@ -49,6 +49,7 @@ def debug_script(script_path, obj=None, auto_delete=True): try: scriptobj.delete() except: pass return string + string += "\nRunning syntax check ..." try: string += "\nTesting syntax of at_script_creation(self) ... " diff --git a/src/utils/utils.py b/src/utils/utils.py index 54cb83422a..15df4fc95c 100644 --- a/src/utils/utils.py +++ b/src/utils/utils.py @@ -210,7 +210,7 @@ def dbref(dbref): (database reference number) are either a string '#N' or an integer N. Output is the integer part. """ - if type(dbref) == str: + if isinstance(dbref, basestring): dbref = dbref.lstrip('#') try: dbref = int(dbref)