From e6067c873cfa8d1e8b5f236a7519bf9eb5065c36 Mon Sep 17 00:00:00 2001 From: Griatch Date: Thu, 20 Jun 2013 18:06:10 +0200 Subject: [PATCH 01/17] Fixing old docstring on @quell command, suggesting superuser cannot be quelled. --- src/commands/default/player.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/commands/default/player.py b/src/commands/default/player.py index 346c9d1a94..cec03d2cb2 100644 --- a/src/commands/default/player.py +++ b/src/commands/default/player.py @@ -606,9 +606,6 @@ class CmdQuell(MuxPlayerCommand): Hierarchical permission quelling only work downwards, thus a Player cannot use a higher-permission Character to escalate their permission level. Use the unquell command to revert back to normal operation. - - Note that the superuser character cannot be quelled. Use a separate - admin account for testing. """ key = "@quell" From e30f3f7e5942b1eb39eaba80b41c7c0d29f976e8 Mon Sep 17 00:00:00 2001 From: Griatch Date: Thu, 20 Jun 2013 18:10:51 +0200 Subject: [PATCH 02/17] Minor fix to a comment. --- src/settings_default.py | 1 - 1 file changed, 1 deletion(-) diff --git a/src/settings_default.py b/src/settings_default.py index 1bded0b669..068709af83 100644 --- a/src/settings_default.py +++ b/src/settings_default.py @@ -126,7 +126,6 @@ GAME_CACHE_TYPE = "local" # memory. So every now and then Evennia checks the size of this cache and resets # it if it's too big. This variable sets the maximum size (in MB). ATTRIBUTE_CACHE_MAXSIZE = 100 -# OOB (Out-of-band ###################################################################### # Evennia Database config From c3f86ab45ba5737af6a58113fa5718c8fb6f7a07 Mon Sep 17 00:00:00 2001 From: Kelketek Date: Sat, 29 Jun 2013 14:14:00 -0500 Subject: [PATCH 03/17] Fixed issue where searching for 'me' did not return typeclassed object. --- src/objects/models.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/objects/models.py b/src/objects/models.py index a063b256ec..b0e2773269 100644 --- a/src/objects/models.py +++ b/src/objects/models.py @@ -606,7 +606,7 @@ class ObjectDB(TypedObject): if searchdata == _HERE: return self.location if searchdata in (_ME, _SELF): - return self + return self.typeclass if use_nicks: nick = None From 240dee1d5b90784ff466ecece6be926a8b056ad8 Mon Sep 17 00:00:00 2001 From: Kelketek Date: Sat, 29 Jun 2013 15:10:14 -0500 Subject: [PATCH 04/17] Fixed issue with attribute search not properly handling attribute prefixes. --- src/objects/manager.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/objects/manager.py b/src/objects/manager.py index 41866a3d6b..729511aced 100644 --- a/src/objects/manager.py +++ b/src/objects/manager.py @@ -174,7 +174,8 @@ class ObjectManager(TypedObjectManager): if isinstance(property_value, basestring): property_value = to_unicode(property_value) if isinstance(property_name, basestring): - property_name = "db_%s" % property_name.lstrip('db_') + if not property_name.startswith('db_'): + property_name = "db_%s" % property_name querykwargs = {property_name:property_value} cand_restriction = candidates and Q(pk__in=[_GA(obj, "id") for obj in make_iter(candidates) if obj]) or Q() type_restriction = typeclasses and Q(db_typeclass_path__in=make_iter(typeclasses)) or Q() From c4db3e53706950344854a931364497aef7af50b1 Mon Sep 17 00:00:00 2001 From: Kelketek Date: Sat, 29 Jun 2013 18:52:15 -0500 Subject: [PATCH 05/17] Made normal channels not message offline users by default. --- src/comms/channelhandler.py | 2 +- src/comms/managers.py | 31 ++++++++++++++++++++++++------- src/comms/models.py | 7 ++++--- 3 files changed, 29 insertions(+), 11 deletions(-) diff --git a/src/comms/channelhandler.py b/src/comms/channelhandler.py index 8173aeb5fc..876f1494df 100644 --- a/src/comms/channelhandler.py +++ b/src/comms/channelhandler.py @@ -90,7 +90,7 @@ class ChannelCommand(command.Command): msgobj.senders = sender msgobj.channels = channel # send new message object to channel - channel.msg(msgobj, senders=sender) + channel.msg(msgobj, senders=sender, online=True) class ChannelHandler(object): """ diff --git a/src/comms/managers.py b/src/comms/managers.py index 9439f501da..d40c1c293a 100644 --- a/src/comms/managers.py +++ b/src/comms/managers.py @@ -198,7 +198,7 @@ class MsgManager(models.Manager): NOTE: This can potentially be slow, so make sure to supply one of the other arguments to limit the search. dbref - (int) the exact database id of the message. This will override - all other search crieteria since it's unique and + all other search criteria since it's unique and always gives a list with only one match. """ # unique msg id @@ -299,19 +299,36 @@ class ChannelManager(models.Manager): CHANNELHANDLER.update() return None - def get_all_connections(self, channel): + def get_all_connections(self, channel, online=False): """ Return the connections of all players listening - to this channel + to this channel. If Online is true, it only returns + connected players. """ - # import here to avoid circular imports - #from src.comms.models import PlayerChannelConnection + PlayerChannelConnection = ContentType.objects.get(app_label="comms", model="playerchannelconnection").model_class() ExternalChannelConnection = ContentType.objects.get(app_label="comms", model="externalchannelconnection").model_class() - return itertools.chain(PlayerChannelConnection.objects.get_all_connections(channel), - ExternalChannelConnection.objects.get_all_connections(channel)) + # Importing here to avoid circular imports. + from src.server.sessionhandler import SESSIONS + players = [] + if online: + session_list = SESSIONS.get_sessions() + for session in session_list: + if not session.logged_in: + continue + try: + players.append(PlayerChannelConnection.objects.get(db_player=session.get_player(), + db_channel=channel)) + except PlayerChannelConnection.DoesNotExist: + pass + else: + players.extend(PlayerChannelConnection.objects.get_all_connections(channel)) + + external_connections = ExternalChannelConnection.objects.get_all_connections(channel) + + return itertools.chain(players, external_connections) def channel_search(self, ostring): """ diff --git a/src/comms/models.py b/src/comms/models.py index 3c62c34815..a0110f5ff7 100644 --- a/src/comms/models.py +++ b/src/comms/models.py @@ -555,7 +555,7 @@ class Channel(SharedMemoryModel): # do the check return PlayerChannelConnection.objects.has_player_connection(player, self) - def msg(self, msgobj, header=None, senders=None, persistent=True): + def msg(self, msgobj, header=None, senders=None, persistent=True, online=False): """ Send the given message to all players connected to channel. Note that no permission-checking is done here; it is assumed to have been @@ -568,7 +568,8 @@ class Channel(SharedMemoryModel): persistent=False. persistent (bool) - ignored if msgobj is a Msg or TempMsg. If True, a Msg will be created, using header and senders keywords. If False, other keywords will be ignored. - + online (bool) - If this is set true, only messages people who are online. Otherwise, messages all players + connected. This can make things faster, but may not trigger listeners on players that are offline. """ if isinstance(msgobj, basestring): @@ -590,7 +591,7 @@ class Channel(SharedMemoryModel): msg = msgobj.message # get all players connected to this channel and send to them - for conn in Channel.objects.get_all_connections(self): + for conn in Channel.objects.get_all_connections(self, online=online): try: conn.player.msg(msg, senders) except AttributeError: From 1e6384e40cba240808e04782180ac46cc83f27e6 Mon Sep 17 00:00:00 2001 From: Griatch Date: Sun, 30 Jun 2013 14:13:01 +0200 Subject: [PATCH 06/17] Fixed some documentation typos/rewrites as suggested in Issue 393. --- src/objects/objects.py | 38 ++++++++++++++++++-------------------- 1 file changed, 18 insertions(+), 20 deletions(-) diff --git a/src/objects/objects.py b/src/objects/objects.py index f67491882b..ed67fc026c 100644 --- a/src/objects/objects.py +++ b/src/objects/objects.py @@ -37,14 +37,14 @@ class Object(TypeClass): # __init__ is only defined here in order to present docstring to API. def __init__(self, dbobj): """ - This is the root typeclass object representing all entities - that has and actual presence in-game. Objects generally has a - location, can be manipulated and looked at. Most game entities - you define should inherit from Object at some distance. - Important subclasses of Object are that Evennia defines by - default for you are Characters, Exits and Rooms. + This is the root typeclass object, representing all entities + that have an actual presence in-game. Objects generally have a + location. They can also be manipulated and looked at. Most + game entities you define should inherit from Object at some distance. + Evennia defines some important subclasses of Object by default, namely + Characters, Exits and Rooms (see the bottom of this module). - Note that all Objects and its subclasses *must* always be + Note that all new Objects and their subclasses *must* always be created using the ev.create_object() function. This is so the typeclass system can be correctly initiated behind the scenes. @@ -54,7 +54,7 @@ class Object(TypeClass): * Available properties (only available on *initiated* typeclass objects) key (string) - name of object - name (string)- same as key + name (string) - same as key aliases (list of strings) - aliases to the object. Will be saved to database as AliasDB entries but returned as strings. dbref (int, read-only) - unique #id-number. Also "id" can be used. dbobj (Object, read-only) - link to database model. dbobj.typeclass points back to this class @@ -755,7 +755,7 @@ class Object(TypeClass): return message # -# Base Player object +# Base Character object # class Character(Object): @@ -836,14 +836,13 @@ class Character(Object): class Room(Object): """ - This is the base room object. It's basically - like any Object except its location is None. + This is the base room object. It's just like any Object except its + location is None. """ def basetype_setup(self): """ Simple setup, shown as an example (since default is None anyway) - """ super(Room, self).basetype_setup() @@ -852,19 +851,18 @@ class Room(Object): self.location = None # -# Exits +# Base Exit object # class Exit(Object): """ - This is the base exit object - it connects a location to - another. This is done by the exit assigning a "command" on itself - with the same name as the exit object (to do this we need to - remember to re-create the command when the object is cached since it must be + This is the base exit object - it connects a location to another. + This is done by the exit assigning a "command" on itself with the + same name as the exit object (to do this we need to remember to + re-create the command when the object is cached since it must be created dynamically depending on what the exit is called). This - command (which has a high priority) will thus allow us to traverse exits - simply by giving the exit-object's name on its own. - + command (which has a high priority) will thus allow us to traverse + exits simply by giving the exit-object's name on its own. """ # Helper classes and methods to implement the Exit. These need not From 92339362ec54a868f9709a820e2d5336382fd20e Mon Sep 17 00:00:00 2001 From: Griatch Date: Mon, 1 Jul 2013 14:30:17 +0200 Subject: [PATCH 07/17] Changed/fixed some issues with the command priorities that caused a lower-prio dynamically-created command to not properly be accounted for. Also changed the prio order for which of the cmdsets are used for checking the "duplicates" flag - it is now the new set being merged onto the new one (i.e. the priorotized) cmdset that must have this flag set in order for the result to have duplicates. --- src/commands/cmdset.py | 28 ++++----- src/commands/command.py | 116 ++++++++++++++++++++---------------- src/comms/channelhandler.py | 11 ++-- src/objects/objects.py | 13 ++-- 4 files changed, 90 insertions(+), 78 deletions(-) diff --git a/src/commands/cmdset.py b/src/commands/cmdset.py index c54383ef1b..ebab1aad09 100644 --- a/src/commands/cmdset.py +++ b/src/commands/cmdset.py @@ -152,21 +152,21 @@ class CmdSet(object): # Priority-sensitive merge operations for cmdsets - def _union(self, cmdset_a, cmdset_b, duplicates=False): + def _union(self, cmdset_a, cmdset_b): "C = A U B. CmdSet A is assumed to have higher priority" cmdset_c = cmdset_a._duplicate() # we make copies, not refs by use of [:] cmdset_c.commands = cmdset_a.commands[:] - if duplicates and cmdset_a.priority == cmdset_b.priority: + if cmdset_a.duplicates and cmdset_a.priority == cmdset_b.priority: cmdset_c.commands.extend(cmdset_b.commands) else: cmdset_c.commands.extend([cmd for cmd in cmdset_b if not cmd in cmdset_a]) return cmdset_c - def _intersect(self, cmdset_a, cmdset_b, duplicates=False): + def _intersect(self, cmdset_a, cmdset_b): "C = A (intersect) B. A is assumed higher priority" cmdset_c = cmdset_a._duplicate() - if duplicates and cmdset_a.priority == cmdset_b.priority: + if cmdset_a.duplicates and cmdset_a.priority == cmdset_b.priority: for cmd in [cmd for cmd in cmdset_a if cmd in cmdset_b]: cmdset_c.add(cmd) cmdset_c.add(cmdset_b.get(cmd)) @@ -174,13 +174,13 @@ class CmdSet(object): cmdset_c.commands = [cmd for cmd in cmdset_a if cmd in cmdset_b] return cmdset_c - def _replace(self, cmdset_a, cmdset_b, cmdset_c): + def _replace(self, cmdset_a, cmdset_b): "C = A + B where the result is A." cmdset_c = cmdset_a._duplicate() cmdset_c.commands = cmdset_a.commands[:] return cmdset_c - def _remove(self, cmdset_a, cmdset_b, cmdset_c): + def _remove(self, cmdset_a, cmdset_b): "C = A + B, where B is filtered by A" cmdset_c = cmdset_a._duplicate() cmdset_c.commands = [cmd for cmd in cmdset_b if not cmd in cmdset_a] @@ -267,13 +267,13 @@ class CmdSet(object): mergetype = self.key_mergetypes.get(cmdset_b.key, self.mergetype) if mergetype == "Intersect": - cmdset_c = self._intersect(self, cmdset_b, cmdset_b.duplicates) + cmdset_c = self._intersect(self, cmdset_b) elif mergetype == "Replace": - cmdset_c = self._replace(self, cmdset_b, cmdset_b.duplicates) + cmdset_c = self._replace(self, cmdset_b) elif mergetype == "Remove": - cmdset_c = self._remove(self, cmdset_b, cmdset_b.duplicates) + cmdset_c = self._remove(self, cmdset_b) else: # Union - cmdset_c = self._union(self, cmdset_b, cmdset_b.duplicates) + cmdset_c = self._union(self, cmdset_b) cmdset_c.no_channels = self.no_channels cmdset_c.no_exits = self.no_exits cmdset_c.no_objs = self.no_objs @@ -286,13 +286,13 @@ class CmdSet(object): mergetype = cmdset_b.key_mergetypes.get(self.key, cmdset_b.mergetype) if mergetype == "Intersect": - cmdset_c = self._intersect(cmdset_b, self, self.duplicates) + cmdset_c = self._intersect(cmdset_b, self) elif mergetype == "Replace": - cmdset_c = self._replace(cmdset_b, self, self.duplicates) + cmdset_c = self._replace(cmdset_b, self) elif mergetype == "Remove": - cmdset_c = self._remove(self, cmdset_b, self.duplicates) + cmdset_c = self._remove(self, cmdset_b) else: # Union - cmdset_c = self._union(cmdset_b, self, self.duplicates) + cmdset_c = self._union(cmdset_b, self) cmdset_c.no_channels = cmdset_b.no_channels cmdset_c.no_exits = cmdset_b.no_exits cmdset_c.no_objs = cmdset_b.no_objs diff --git a/src/commands/command.py b/src/commands/command.py index 13988352dd..e6badfe15c 100644 --- a/src/commands/command.py +++ b/src/commands/command.py @@ -9,58 +9,70 @@ import re from src.locks.lockhandler import LockHandler from src.utils.utils import is_iter, fill +def _init_command(mcs, **kwargs): + """ + Helper command. + Makes 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. This is used both by the metaclass + and (optionally) at instantiation time. + + If kwargs are given, these are set as instance-specific properties on the command. + """ + for i in range(len(kwargs)): + # used for dynamic creation of commands + key, value = kwargs.popitem() + setattr(mcs, key, value) + + mcs.key = mcs.key.lower() + if mcs.aliases and not is_iter(mcs.aliases): + try: + mcs.aliases = [str(alias).strip().lower() for alias in mcs.aliases.split(',')] + except Exception: + mcs.aliases = [] + mcs.aliases = list(set(alias for alias in mcs.aliases if alias != mcs.key)) + + # optimization - a set is much faster to match against than a list + mcs._matchset = set([mcs.key] + mcs.aliases) + # optimization for looping over keys+aliases + mcs._keyaliases = tuple(mcs._matchset) + + # by default we don't save the command between runs + if not hasattr(mcs, "save_for_next"): + mcs.save_for_next = False + + # pre-process locks as defined in class definition + temp = [] + if hasattr(mcs, 'permissions'): + mcs.locks = mcs.permissions + if not hasattr(mcs, 'locks'): + # default if one forgets to define completely + mcs.locks = "cmd:all()" + for lockstring in mcs.locks.split(';'): + if lockstring and not ':' in lockstring: + lockstring = "cmd:%s" % lockstring + temp.append(lockstring) + mcs.lock_storage = ";".join(temp) + + if hasattr(mcs, 'arg_regex') and isinstance(mcs.arg_regex, basestring): + mcs.arg_regex = re.compile(r"%s" % mcs.arg_regex, re.I) + else: + mcs.arg_regex = None + if not hasattr(mcs, "auto_help"): + mcs.auto_help = True + if not hasattr(mcs, 'is_exit'): + mcs.is_exit = False + if not hasattr(mcs, "help_category"): + mcs.help_category = "general" + mcs.help_category = mcs.help_category.lower() + + class CommandMeta(type): """ - This metaclass makes some minor on-the-fly convenience fixes to the command - class in case the admin forgets to put things in lowercase etc. + The metaclass cleans up all properties on the class """ def __init__(mcs, *args, **kwargs): - """ - 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): - try: - mcs.aliases = [str(alias).strip().lower() for alias in mcs.aliases.split(',')] - except Exception: - mcs.aliases = [] - mcs.aliases = list(set(alias for alias in mcs.aliases if alias != mcs.key)) - - # optimization - a set is much faster to match against than a list - mcs._matchset = set([mcs.key] + mcs.aliases) - # optimization for looping over keys+aliases - mcs._keyaliases = tuple(mcs._matchset) - - # by default we don't save the command between runs - if not hasattr(mcs, "save_for_next"): - mcs.save_for_next = False - - # pre-process locks as defined in class definition - temp = [] - if hasattr(mcs, 'permissions'): - mcs.locks = mcs.permissions - if not hasattr(mcs, 'locks'): - # default if one forgets to define completely - mcs.locks = "cmd:all()" - for lockstring in mcs.locks.split(';'): - if lockstring and not ':' in lockstring: - lockstring = "cmd:%s" % lockstring - temp.append(lockstring) - mcs.lock_storage = ";".join(temp) - - if hasattr(mcs, 'arg_regex') and isinstance(mcs.arg_regex, basestring): - mcs.arg_regex = re.compile(r"%s" % mcs.arg_regex, re.I) - else: - mcs.arg_regex = None - if not hasattr(mcs, "auto_help"): - mcs.auto_help = True - if not hasattr(mcs, 'is_exit'): - mcs.is_exit = False - if not hasattr(mcs, "help_category"): - mcs.help_category = "general" - mcs.help_category = mcs.help_category.lower() + _init_command(mcs, **kwargs) super(CommandMeta, mcs).__init__(*args, **kwargs) # The Command class is the basic unit of an Evennia command; when @@ -125,8 +137,12 @@ class Command(object): # sessid - which session-id (if any) is responsible for triggering this command # - def __init__(self): - "the lockhandler works the same as for objects." + def __init__(self, **kwargs): + """the lockhandler works the same as for objects. + optional kwargs will be set as properties on the Command at runtime, + overloading evential same-named class properties.""" + if kwargs: + _init_command(self, **kwargs) self.lockhandler = LockHandler(self) def __str__(self): diff --git a/src/comms/channelhandler.py b/src/comms/channelhandler.py index 876f1494df..e020e88e95 100644 --- a/src/comms/channelhandler.py +++ b/src/comms/channelhandler.py @@ -136,14 +136,11 @@ class ChannelHandler(object): and run self.update on the handler. """ # map the channel to a searchable command - cmd = ChannelCommand() - cmd.key = channel.key.strip().lower() - cmd.obj = channel + cmd = ChannelCommand(key=channel.key.strip().lower(), + aliases=channel.aliases if channel.aliases else [], + locks="cmd:all();%s" % channel.locks, + obj=channel) cmd.__doc__= self._format_help(channel) - if channel.aliases: - cmd.aliases = channel.aliases - cmd.lock_storage = "cmd:all();%s" % channel.locks - cmd.lockhandler.reset() self.cached_channel_cmds.append(cmd) self.cached_cmdsets = {} diff --git a/src/objects/objects.py b/src/objects/objects.py index ed67fc026c..1df919d032 100644 --- a/src/objects/objects.py +++ b/src/objects/objects.py @@ -907,13 +907,12 @@ class Exit(Object): self.obj.at_failed_traverse(self.caller) # create an exit command. - cmd = ExitCommand() - cmd.key = exidbobj.db_key.strip().lower() - cmd.obj = exidbobj - cmd.aliases = exidbobj.aliases - cmd.locks = str(exidbobj.locks) - cmd.destination = exidbobj.db_destination - cmd.auto_help = False + cmd = ExitCommand(key=exidbobj.db_key.strip().lower(), + aliases=exidbobj.aliases, + locks=str(exidbobj.locks), + auto_help=False, + destination=exidbobj.db_destination, + obj=exidbobj) # create a cmdset exit_cmdset = cmdset.CmdSet(None) exit_cmdset.key = '_exitset' From 0164574c00dd6f6db3a84e0181a7b4c3df848957 Mon Sep 17 00:00:00 2001 From: Griatch Date: Mon, 1 Jul 2013 15:03:12 +0200 Subject: [PATCH 08/17] Added sessid keyword to at_pre_puppet and at_post_unpuppet hooks, where the sessid is otherwise not yet available, as per Issue 383. --- src/objects/objects.py | 12 +++++++----- src/players/models.py | 4 ++-- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/src/objects/objects.py b/src/objects/objects.py index 1df919d032..6a748cdbb3 100644 --- a/src/objects/objects.py +++ b/src/objects/objects.py @@ -465,12 +465,13 @@ class Object(TypeClass): """ pass - def at_pre_puppet(self, player): + def at_pre_puppet(self, player, sessid=None): """ Called just before a Player connects to this object to puppet it. player - connecting player object + sessid - session id controlling the connection """ pass @@ -488,13 +489,14 @@ class Object(TypeClass): """ pass - def at_post_unpuppet(self, player): + def at_post_unpuppet(self, player, sessid=None): """ Called just after the Player successfully disconnected from this object, severing all connections. player - the player object that just disconnected from this object. + sessid - session id controlling the connection """ pass @@ -793,7 +795,7 @@ class Character(Object): "Default is to look around after a move." self.execute_cmd('look') - def at_pre_puppet(self, player): + def at_pre_puppet(self, player, sessid=None): """ This recovers the character again after having been "stoved away" at the unpuppet """ @@ -809,7 +811,7 @@ class Character(Object): self.location.msg_contents("%s has entered the game." % self.name, exclude=[self]) self.location.at_object_receive(self, self.location) else: - player.msg("{r%s has no location and no home is set.{n" % self) + player.msg("{r%s has no location and no home is set.{n" % self, sessid=sessid) def at_post_puppet(self): """ @@ -820,7 +822,7 @@ class Character(Object): if self.location: self.location.msg_contents("%s has entered the game." % self.name, exclude=[self]) - def at_post_unpuppet(self, player): + def at_post_unpuppet(self, player, sessid=None): """ We stove away the character when the player goes ooc/logs off, otherwise the character object will remain in the room also after the player logged off ("headless", so to say). diff --git a/src/players/models.py b/src/players/models.py index 278ab00a14..aaab60f7e1 100644 --- a/src/players/models.py +++ b/src/players/models.py @@ -421,7 +421,7 @@ class PlayerDB(TypedObject): # with a lingering player/sessid reference from an unclean server kill or similar if normal_mode: - _GA(obj.typeclass, "at_pre_puppet")(self.typeclass) + _GA(obj.typeclass, "at_pre_puppet")(self.typeclass, sessid=sessid) # do the connection obj.sessid = sessid obj.player = self @@ -453,7 +453,7 @@ class PlayerDB(TypedObject): del obj.dbobj.player session.puppet = None session.puid = None - _GA(obj.typeclass, "at_post_unpuppet")(self) + _GA(obj.typeclass, "at_post_unpuppet")(self.typeclass, sessid=sessid) return True def unpuppet_all(self): From b9f40fe8ee304817bf539732f2a7fe966c02787a Mon Sep 17 00:00:00 2001 From: Daniel Benoy Date: Mon, 1 Jul 2013 21:46:20 -0400 Subject: [PATCH 09/17] Fixed a regression which caused exits to be locked out from use. --- src/objects/objects.py | 1 - 1 file changed, 1 deletion(-) diff --git a/src/objects/objects.py b/src/objects/objects.py index 6a748cdbb3..73156c632e 100644 --- a/src/objects/objects.py +++ b/src/objects/objects.py @@ -911,7 +911,6 @@ class Exit(Object): # create an exit command. cmd = ExitCommand(key=exidbobj.db_key.strip().lower(), aliases=exidbobj.aliases, - locks=str(exidbobj.locks), auto_help=False, destination=exidbobj.db_destination, obj=exidbobj) From 5800b960ff25891374e6f2b6444d3ae859bdd0ef Mon Sep 17 00:00:00 2001 From: Griatch Date: Tue, 2 Jul 2013 09:34:35 +0200 Subject: [PATCH 10/17] Added safety feature to lock handling. --- src/commands/command.py | 2 ++ src/objects/objects.py | 1 - 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/commands/command.py b/src/commands/command.py index e6badfe15c..395aa024ea 100644 --- a/src/commands/command.py +++ b/src/commands/command.py @@ -48,6 +48,8 @@ def _init_command(mcs, **kwargs): if not hasattr(mcs, 'locks'): # default if one forgets to define completely mcs.locks = "cmd:all()" + elif not "cmd:" in mcs.locks: + mcs.locks = "cmd:all();" + mcs.locks for lockstring in mcs.locks.split(';'): if lockstring and not ':' in lockstring: lockstring = "cmd:%s" % lockstring diff --git a/src/objects/objects.py b/src/objects/objects.py index 6a748cdbb3..73156c632e 100644 --- a/src/objects/objects.py +++ b/src/objects/objects.py @@ -911,7 +911,6 @@ class Exit(Object): # create an exit command. cmd = ExitCommand(key=exidbobj.db_key.strip().lower(), aliases=exidbobj.aliases, - locks=str(exidbobj.locks), auto_help=False, destination=exidbobj.db_destination, obj=exidbobj) From 3cf01ce711cb92bc52ee424b4564bdcaf2504054 Mon Sep 17 00:00:00 2001 From: Griatch Date: Tue, 2 Jul 2013 11:51:04 +0200 Subject: [PATCH 11/17] Reverted previous merge, instead solving the issue by the metaclass making sure to add cmd:all() to the exit command only if the object itself does not specify it. --- src/commands/command.py | 2 +- src/objects/migrations/0005_add_object_default_locks.py | 6 +++--- src/objects/objects.py | 1 + 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/commands/command.py b/src/commands/command.py index 395aa024ea..0c65a90873 100644 --- a/src/commands/command.py +++ b/src/commands/command.py @@ -48,7 +48,7 @@ def _init_command(mcs, **kwargs): if not hasattr(mcs, 'locks'): # default if one forgets to define completely mcs.locks = "cmd:all()" - elif not "cmd:" in mcs.locks: + if not "cmd:" in mcs.locks: mcs.locks = "cmd:all();" + mcs.locks for lockstring in mcs.locks.split(';'): if lockstring and not ':' in lockstring: diff --git a/src/objects/migrations/0005_add_object_default_locks.py b/src/objects/migrations/0005_add_object_default_locks.py index 8dccaf25b5..0ae1bd3dd4 100644 --- a/src/objects/migrations/0005_add_object_default_locks.py +++ b/src/objects/migrations/0005_add_object_default_locks.py @@ -10,7 +10,7 @@ class Migration(DataMigration): "Write your forwards methods here." # we need to add a default lock string to all objects, then a separate set to Characters. - + lockstring1 = 'control:id(1);get:all();edit:perm(Wizards);examine:perm(Builders);call:true();puppet:id(#4) or perm(Immortals) or pperm(Immortals);delete:id(1) or perm(Wizards)' lockstring2 = 'control:id(#3) or perm(Immortals);get:perm(Wizards);edit:perm(Wizards);examine:perm(Builders);call:false();puppet:id(%i) or pid(%i) or perm(Immortals) or pperm(Immortals);delete:perm(Wizards)' @@ -21,10 +21,10 @@ class Migration(DataMigration): for obj in orm.ObjectDB.objects.filter(db_player__isnull=False): obj.db_lock_storage = lockstring2 % (obj.id, obj.db_player.id) obj.save() - + except utils.DatabaseError: # running from scatch. In this case we just ignore this. - pass + pass def backwards(self, orm): "Write your backwards methods here." diff --git a/src/objects/objects.py b/src/objects/objects.py index 73156c632e..6a748cdbb3 100644 --- a/src/objects/objects.py +++ b/src/objects/objects.py @@ -911,6 +911,7 @@ class Exit(Object): # create an exit command. cmd = ExitCommand(key=exidbobj.db_key.strip().lower(), aliases=exidbobj.aliases, + locks=str(exidbobj.locks), auto_help=False, destination=exidbobj.db_destination, obj=exidbobj) From 47a324f720bf42bb0b6d90ef4b0e64091f6f8bc7 Mon Sep 17 00:00:00 2001 From: Griatch Date: Tue, 2 Jul 2013 13:38:38 +0200 Subject: [PATCH 12/17] Made cmdhandler merge same-prio cmdsets in groups. Before this fix one could face the following situation: Two exits "allcom" and "test". Both have exit cmdsets with prio 9. If "test" merges first, it contains no "allcom" command to overload the "allcom" in the Player cmdset (prio -5). But the merged set now has a priority of 9 thanks to merging the "test" set. So when merging the "allcom" exit-command, it merges with a same-prio set. And since exit-cmdsets have the duplicate-flag set, there will be two allcom commands in the final set. The problem does not show up if "allcom" happened to be merged first, making this effect non-consistent and buggy. Merging the same-prio exit-sets first, then merging onto the lower-prio sets resolves this issue. --- src/commands/cmdhandler.py | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/src/commands/cmdhandler.py b/src/commands/cmdhandler.py index 9be05a915e..bbb93b7b5d 100644 --- a/src/commands/cmdhandler.py +++ b/src/commands/cmdhandler.py @@ -139,14 +139,25 @@ def get_and_merge_cmdsets(caller): cmdsets = yield [caller_cmdset] + [player_cmdset] + [channel_cmdset] + local_objects_cmdsets # weed out all non-found sets - cmdsets = yield [cmdset for cmdset in cmdsets if cmdset] + cmdsets = yield [cmdset for cmdset in cmdsets if cmdset and cmdset.key!="Empty"] # report cmdset errors to user (these should already have been logged) yield [caller.msg(cmdset.message) for cmdset in cmdsets if cmdset.key == "_CMDSET_ERROR"] - # sort cmdsets after reverse priority (highest prio are merged in last) - yield cmdsets.sort(key=lambda x: x.priority) - #cmdsets = yield sorted(cmdsets, key=lambda x: x.priority) if cmdsets: + # we group and merge all same-prio cmdsets separately (this avoids order-dependent + # clashes in certain cases, such as when duplicates=True) + tempmergers = {} + for cmdset in cmdsets: + prio = cmdset.priority + if prio in tempmergers: + # merge same-prio cmdset together separately + tempmergers[prio] = yield cmdset + tempmergers[prio] + else: + tempmergers[prio] = cmdset + + # sort cmdsets after reverse priority (highest prio are merged in last) + cmdsets = yield sorted(tempmergers.values(), key=lambda x: x.priority) + # Merge all command sets into one, beginning with the lowest-prio one cmdset = cmdsets.pop(0) for merging_cmdset in cmdsets: From 92a8e39de5282a1e27efa3cfce9e03f23465fe18 Mon Sep 17 00:00:00 2001 From: Griatch Date: Tue, 2 Jul 2013 15:50:42 +0200 Subject: [PATCH 13/17] Changed how the cmdset's errmessage is propagated. Adding failing cmdsets added ErrorCmdsets to the cmdhandler. This was for callback reasons, but it clutters up things for no good reason. --- contrib/tutorial_world/objects.py | 1 + src/commands/cmdhandler.py | 2 +- src/commands/cmdset.py | 3 ++- src/commands/cmdsethandler.py | 8 ++++---- 4 files changed, 8 insertions(+), 6 deletions(-) diff --git a/contrib/tutorial_world/objects.py b/contrib/tutorial_world/objects.py index 08a9f1ab3e..2d033372a3 100644 --- a/contrib/tutorial_world/objects.py +++ b/contrib/tutorial_world/objects.py @@ -561,6 +561,7 @@ class CrumblingWall(TutorialObject, Exit): self.aliases = ["secret passage", "passage", "crack", "opening", "secret door"] # this is assigned first when pushing button, so assign this at creation time! + self.db.destination = 2 # locks on the object directly transfer to the exit "command" self.locks.add("cmd:not locattr(is_dark)") diff --git a/src/commands/cmdhandler.py b/src/commands/cmdhandler.py index bbb93b7b5d..44e6860a3d 100644 --- a/src/commands/cmdhandler.py +++ b/src/commands/cmdhandler.py @@ -141,7 +141,7 @@ def get_and_merge_cmdsets(caller): # weed out all non-found sets cmdsets = yield [cmdset for cmdset in cmdsets if cmdset and cmdset.key!="Empty"] # report cmdset errors to user (these should already have been logged) - yield [caller.msg(cmdset.message) for cmdset in cmdsets if cmdset.key == "_CMDSET_ERROR"] + yield [caller.msg(cmdset.errmessage) for cmdset in cmdsets if cmdset.key == "_CMDSET_ERROR"] if cmdsets: # we group and merge all same-prio cmdsets separately (this avoids order-dependent diff --git a/src/commands/cmdset.py b/src/commands/cmdset.py index ebab1aad09..1346e2f091 100644 --- a/src/commands/cmdset.py +++ b/src/commands/cmdset.py @@ -128,9 +128,10 @@ class CmdSet(object): no_objs = False no_channels = False permanent = False + errmessage = "" # pre-store properties to duplicate straight off to_duplicate = ("key", "cmdsetobj", "no_exits", "no_objs", "no_channels", "permanent", - "mergetype", "priority", "duplicates") + "mergetype", "priority", "duplicates", "errmessage") def __init__(self, cmdsetobj=None, key=None): """ diff --git a/src/commands/cmdsethandler.py b/src/commands/cmdsethandler.py index 4c19164f31..59a3d658b1 100644 --- a/src/commands/cmdsethandler.py +++ b/src/commands/cmdsethandler.py @@ -76,7 +76,7 @@ _CACHED_CMDSETS = {} class _ErrorCmdSet(CmdSet): "This is a special cmdset used to report errors" key = "_CMDSET_ERROR" - message = "Error when loading cmdset." + errmessage = "Error when loading cmdset." def import_cmdset(python_path, cmdsetobj, emit_to_obj=None, no_logging=False): """ @@ -130,7 +130,7 @@ def import_cmdset(python_path, cmdsetobj, emit_to_obj=None, no_logging=False): if emit_to_obj and not ServerConfig.objects.conf("server_starting_mode"): object.__getattribute__(emit_to_obj, "msg")(errstring) err_cmdset = _ErrorCmdSet() - err_cmdset.message = errstring + err_cmdset.errmessage = errstring return err_cmdset # classes @@ -283,7 +283,7 @@ class CmdSetHandler(object): elif isinstance(cmdset, basestring): # this is (maybe) a python path. Try to import from cache. cmdset = self._import_cmdset(cmdset) - if cmdset: + if cmdset and cmdset.key != '_CMDSET_ERROR': if permanent and cmdset.key != '_CMDSET_ERROR': # store the path permanently cmdset.permanent = True @@ -315,7 +315,7 @@ class CmdSetHandler(object): elif isinstance(cmdset, basestring): # this is (maybe) a python path. Try to import from cache. cmdset = self._import_cmdset(cmdset) - if cmdset: + if cmdset and cmdset.key != '_CMDSET_ERROR': if self.cmdset_stack: self.cmdset_stack[0] = cmdset self.mergetype_stack[0] = cmdset.mergetype From 2487d4b6221e5300e4a2184016772b038d919631 Mon Sep 17 00:00:00 2001 From: Griatch Date: Tue, 2 Jul 2013 16:09:20 +0200 Subject: [PATCH 14/17] Fixed script-searching using the obj= keyword. Also made the search more efficient using Q-objects. Resolves Issue 385. --- src/scripts/manager.py | 24 +++++++----------------- 1 file changed, 7 insertions(+), 17 deletions(-) diff --git a/src/scripts/manager.py b/src/scripts/manager.py index 66c739aa16..68c0fffdbf 100644 --- a/src/scripts/manager.py +++ b/src/scripts/manager.py @@ -2,6 +2,7 @@ The custom manager for Scripts. """ +from django.db.models import Q from src.typeclasses.managers import TypedObjectManager from src.typeclasses.managers import returns_typeclass_list from src.utils.utils import make_iter @@ -194,25 +195,14 @@ class ScriptManager(TypedObjectManager): if dbref or dbref == 0: # this is a dbref, try to find the script directly dbref_match = self.dbref_search(dbref) - if dbref_match: - ok = True - if obj and obj != dbref_match.obj: - ok = False - if only_timed and dbref_match.interval: - ok = False - if ok: - return [dbref_match] - if obj: - # convenience check to make sure obj is really a dbobj - obj = hasattr(obj, "dbobj") and obj.dbobj or obj + if dbref_match and not ((obj and obj != dbref_match.obj) + or (only_timed and dbref_match.interval)): + return [dbref_match] # not a dbref; normal search - scripts = self.filter(db_key__iexact=ostring) - - if obj: - scripts = scripts.exclude(db_obj=None).filter(db_obj__db_key__iexact=ostring) - if only_timed: - scripts = scripts.exclude(interval=0) + obj_restriction = obj and Q(db_obj=obj.dbobj) or Q() + timed_restriction = only_timed and Q(interval__gt=0) or Q() + scripts = self.filter(timed_restriction & obj_restriction & Q(db_key__iexact=ostring)) return scripts def copy_script(self, original_script, new_key=None, new_obj=None, new_locks=None): From 261e4635052a54abf2f0ad116141ccc1ecbc81f3 Mon Sep 17 00:00:00 2001 From: Griatch Date: Tue, 2 Jul 2013 16:24:47 +0200 Subject: [PATCH 15/17] cleaned up script copy method in script manager. --- src/scripts/manager.py | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/src/scripts/manager.py b/src/scripts/manager.py index 68c0fffdbf..6941f27b88 100644 --- a/src/scripts/manager.py +++ b/src/scripts/manager.py @@ -209,14 +209,10 @@ class ScriptManager(TypedObjectManager): """ Make an identical copy of the original_script """ - typeclass = original_script.typeclass_path - if not new_key: - new_key = original_script.key - if not new_obj: - new_obj = original_script.obj - if not new_locks: - new_locks = original_script.db_lock_storage + new_key = new_key if new_key!=None else original_script.key + new_obj = new_obj if new_obj!=None else original_script.obj + new_locks = new_locks if new_locks!=None else original_script.db_lock_storage from src.utils import create new_script = create.create_script(typeclass, key=new_key, obj=new_obj, locks=new_locks, autostart=True) From c94472492a2b5fadbc37bc5b9141f6873a369b49 Mon Sep 17 00:00:00 2001 From: Griatch Date: Wed, 10 Jul 2013 19:13:41 +0200 Subject: [PATCH 16/17] Implemented PlayerDB as replacement for User, as per Django1.5. All migrations work, but there are still lots of changes to be done in the code to remove references to the User model. --- src/players/manager.py | 4 +- ...o__add_field_playerdb_db_cmdset_storage.py | 4 +- .../migrations/0020_add_playerdbtmp.py | 162 ++++++++++++++++++ .../0021_copy_user_profile_to_tmp.py | 118 +++++++++++++ .../migrations/0022_delete_old_profile.py | 107 ++++++++++++ .../0023_rename_tmp_player_to_playerdb.py | 101 +++++++++++ src/players/models.py | 74 ++++---- src/server/initial_setup.py | 17 +- src/settings_default.py | 5 +- src/web/news/models.py | 10 +- 10 files changed, 553 insertions(+), 49 deletions(-) create mode 100644 src/players/migrations/0020_add_playerdbtmp.py create mode 100644 src/players/migrations/0021_copy_user_profile_to_tmp.py create mode 100644 src/players/migrations/0022_delete_old_profile.py create mode 100644 src/players/migrations/0023_rename_tmp_player_to_playerdb.py diff --git a/src/players/manager.py b/src/players/manager.py index 9916928f51..b95c96284b 100644 --- a/src/players/manager.py +++ b/src/players/manager.py @@ -4,7 +4,7 @@ The managers for the custom Player object and permissions. import datetime from functools import update_wrapper -from django.contrib.auth.models import User +from django.contrib.auth.models import UserManager from src.typeclasses.managers import returns_typeclass_list, returns_typeclass, TypedObjectManager from src.utils import logger __all__ = ("PlayerManager",) @@ -60,7 +60,7 @@ def returns_player(method): return None return update_wrapper(func, method) -class PlayerManager(TypedObjectManager): +class PlayerManager(TypedObjectManager, UserManager): """ This PlayerManager implements methods for searching and manipulating Players directly from the database. diff --git a/src/players/migrations/0003_auto__add_field_playerdb_db_cmdset_storage.py b/src/players/migrations/0003_auto__add_field_playerdb_db_cmdset_storage.py index c089e1f8ec..3169188d57 100644 --- a/src/players/migrations/0003_auto__add_field_playerdb_db_cmdset_storage.py +++ b/src/players/migrations/0003_auto__add_field_playerdb_db_cmdset_storage.py @@ -7,13 +7,13 @@ from django.db import models class Migration(SchemaMigration): def forwards(self, orm): - + # Adding field 'PlayerDB.db_cmdset_storage' db.add_column('players_playerdb', 'db_cmdset_storage', self.gf('django.db.models.fields.TextField')(null=True), keep_default=False) def backwards(self, orm): - + # Deleting field 'PlayerDB.db_cmdset_storage' db.delete_column('players_playerdb', 'db_cmdset_storage') diff --git a/src/players/migrations/0020_add_playerdbtmp.py b/src/players/migrations/0020_add_playerdbtmp.py new file mode 100644 index 0000000000..8a51877312 --- /dev/null +++ b/src/players/migrations/0020_add_playerdbtmp.py @@ -0,0 +1,162 @@ +# -*- coding: utf-8 -*- +import datetime +from south.db import db +from south.v2 import SchemaMigration +from django.db import models, connection + + +class Migration(SchemaMigration): + + def forwards(self, orm): + # Adding model 'PlayerDBtmp' + if "auth_user" in connection.introspection.table_names(): + # auth_user exists ffrom before. Use that as a base. + db.rename_table('auth_user', 'players_playerdbtmp') + else: + # from-scratch creation; no auth_user table available. Create vanilla User table + db.create_table(u'players_playerdbtmp', ( + (u'id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), + ('password', self.gf('django.db.models.fields.CharField')(max_length=128)), + ('last_login', self.gf('django.db.models.fields.DateTimeField')(default=datetime.datetime.now)), + ('is_superuser', self.gf('django.db.models.fields.BooleanField')(default=False)), + ('username', self.gf('django.db.models.fields.CharField')(unique=True, max_length=30)), + ('first_name', self.gf('django.db.models.fields.CharField')(max_length=30, blank=True)), + ('last_name', self.gf('django.db.models.fields.CharField')(max_length=30, blank=True)), + ('email', self.gf('django.db.models.fields.EmailField')(max_length=75, blank=True)), + ('is_staff', self.gf('django.db.models.fields.BooleanField')(default=False)), + ('is_active', self.gf('django.db.models.fields.BooleanField')(default=True)), + ('date_joined', self.gf('django.db.models.fields.DateTimeField')(default=datetime.datetime.now)), + )) + db.send_create_signal(u'players', ['PlayerDBtmp']) + + # Adding M2M table for field groups on 'PlayerDBtmp' + db.create_table(u'players_playerdbtmp_groups', ( + ('id', models.AutoField(verbose_name='ID', primary_key=True, auto_created=True)), + ('playerdbtmp', models.ForeignKey(orm[u'players.playerdbtmp'], null=False)), + ('group', models.ForeignKey(orm[u'auth.group'], null=False)) + )) + db.create_unique(u'players_playerdbtmp_groups', ['playerdbtmp_id', 'group_id']) + + # Adding M2M table for field user_permissions on 'PlayerDBtmp' + db.create_table(u'players_playerdbtmp_user_permissions', ( + ('id', models.AutoField(verbose_name='ID', primary_key=True, auto_created=True)), + ('playerdbtmp', models.ForeignKey(orm[u'players.playerdbtmp'], null=False)), + ('permission', models.ForeignKey(orm[u'auth.permission'], null=False)) + )) + db.create_unique(u'players_playerdbtmp_user_permissions', ['playerdbtmp_id', 'permission_id']) + + # Adding field 'PlayerDB.db_is_connected' + db.add_column(u'players_playerdb', 'db_is_connected', + self.gf('django.db.models.fields.BooleanField')(default=False), + keep_default=False) + + # Adding field 'PlayerDB.db_cmdset_storage' + db.add_column(u'players_playerdb', 'db_cmdset_storage', + self.gf('django.db.models.fields.CharField')(max_length=255, null=True), + keep_default=False) + + # add Evennia-specific columns + db.add_column('players_playerdbtmp', 'db_key', self.gf('django.db.models.fields.CharField')(max_length=255, db_index=True, null=True)) + db.add_column('players_playerdbtmp', 'db_typeclass_path', self.gf('django.db.models.fields.CharField')(max_length=255, null=True)) + db.add_column('players_playerdbtmp', 'db_date_created', self.gf('django.db.models.fields.DateTimeField')(null=True, auto_now_add=True, blank=True)) + db.add_column('players_playerdbtmp', 'db_permissions', self.gf('django.db.models.fields.CharField')(max_length=255, blank=True, null=True)) + db.add_column('players_playerdbtmp', 'db_lock_storage', self.gf('django.db.models.fields.TextField')(blank=True, null=True)) + db.add_column('players_playerdbtmp', 'db_is_connected', self.gf('django.db.models.fields.BooleanField')(default=False)) + db.add_column('players_playerdbtmp', 'db_cmdset_storage', self.gf('django.db.models.fields.CharField')(max_length=255, null=True)) + + def backwards(self, orm): + raise RuntimeError("Cannot revert migration") + + + models = { + u'auth.group': { + 'Meta': {'object_name': 'Group'}, + u'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': u"orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}) + }, + u'auth.permission': { + 'Meta': {'ordering': "(u'content_type__app_label', u'content_type__model', u'codename')", 'unique_together': "((u'content_type', u'codename'),)", 'object_name': 'Permission'}, + 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['contenttypes.ContentType']"}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}) + }, + u'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': u"orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}), + u'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': u"orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}), + 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'}) + }, + u'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'}), + u'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'}) + }, + u'players.playerattribute': { + 'Meta': {'object_name': 'PlayerAttribute'}, + '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_index': 'True'}), + 'db_lock_storage': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'db_obj': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['players.PlayerDB']"}), + 'db_value': ('src.utils.picklefield.PickledObjectField', [], {'null': 'True'}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}) + }, + u'players.playerdb': { + 'Meta': {'object_name': 'PlayerDB'}, + 'db_cmdset_storage': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True'}), + 'db_date_created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}), + 'db_is_connected': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'db_key': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}), + 'db_lock_storage': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'db_permissions': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}), + 'db_typeclass_path': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True'}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['auth.User']", 'unique': 'True'}) + }, + u'players.playerdbtmp': { + 'Meta': {'ordering': "['-db_date_created', 'id', 'db_typeclass_path', 'db_key']", 'object_name': 'PlayerDBtmp'}, + 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + '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_index': 'True'}), + 'db_is_connected': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'db_cmdset_storage': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True'}), + 'db_lock_storage': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'db_permissions': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}), + 'db_typeclass_path': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True'}), + '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': u"orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}), + u'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': u"orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}), + 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'}) + }, + u'players.playernick': { + 'Meta': {'unique_together': "(('db_nick', 'db_type', 'db_obj'),)", 'object_name': 'PlayerNick'}, + 'db_nick': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}), + 'db_obj': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['players.PlayerDB']"}), + 'db_real': ('django.db.models.fields.TextField', [], {}), + 'db_type': ('django.db.models.fields.CharField', [], {'default': "'inputline'", 'max_length': '16', 'null': 'True', 'blank': 'True'}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}) + } + } + + complete_apps = ['players'] diff --git a/src/players/migrations/0021_copy_user_profile_to_tmp.py b/src/players/migrations/0021_copy_user_profile_to_tmp.py new file mode 100644 index 0000000000..030e6d21e8 --- /dev/null +++ b/src/players/migrations/0021_copy_user_profile_to_tmp.py @@ -0,0 +1,118 @@ +# -*- coding: utf-8 -*- +import datetime +from south.db import db +from south.v2 import DataMigration +from django.db import models + +class Migration(DataMigration): + + def forwards(self, orm): + "Write your forwards methods here." + # Note: Remember to use orm['appname.ModelName'] rather than "from appname.models..." + if not db.dry_run: + for profile in orm['players.PlayerDB'].objects.all(): + plyr = orm['players.PlayerDBtmp'].objects.get(id=profile.user_id) + plyr.db_cmdset_storage = profile.db_cmdset_storage + plyr.db_date_created = profile.db_date_created + plyr.db_is_connected = profile.db_is_connected + plyr.db_key = profile.db_key + plyr.db_lock_storage = profile.db_lock_storage + plyr.db_typeclass_path = profile.db_typeclass_path + plyr.db_permissions = profile.db_permissions + plyr.save() + + def backwards(self, orm): + "Write your backwards methods here." + raise RuntimeError("Cannot revert this migration.") + + models = { + u'auth.group': { + 'Meta': {'object_name': 'Group'}, + u'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': u"orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}) + }, + u'auth.permission': { + 'Meta': {'ordering': "(u'content_type__app_label', u'content_type__model', u'codename')", 'unique_together': "((u'content_type', u'codename'),)", 'object_name': 'Permission'}, + 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['contenttypes.ContentType']"}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}) + }, + u'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': u"orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}), + u'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': u"orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}), + 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'}) + }, + u'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'}), + u'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'}) + }, + u'players.playerattribute': { + 'Meta': {'object_name': 'PlayerAttribute'}, + '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_index': 'True'}), + 'db_lock_storage': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'db_obj': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['players.PlayerDB']"}), + 'db_value': ('src.utils.picklefield.PickledObjectField', [], {'null': 'True'}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}) + }, + u'players.playerdb': { + 'Meta': {'object_name': 'PlayerDB'}, + 'db_cmdset_storage': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True'}), + 'db_date_created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}), + 'db_is_connected': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'db_key': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}), + 'db_lock_storage': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'db_permissions': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}), + 'db_typeclass_path': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True'}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['auth.User']", 'unique': 'True'}) + }, + u'players.playerdbtmp': { + 'Meta': {'ordering': "['-db_date_created', 'id', 'db_typeclass_path', 'db_key']", 'object_name': 'PlayerDBtmp'}, + 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + '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_index': 'True'}), + 'db_lock_storage': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'db_permissions': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}), + 'db_typeclass_path': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True'}), + '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': u"orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}), + u'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': u"orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}), + 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'}) + }, + u'players.playernick': { + 'Meta': {'unique_together': "(('db_nick', 'db_type', 'db_obj'),)", 'object_name': 'PlayerNick'}, + 'db_nick': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}), + 'db_obj': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['players.PlayerDB']"}), + 'db_real': ('django.db.models.fields.TextField', [], {}), + 'db_type': ('django.db.models.fields.CharField', [], {'default': "'inputline'", 'max_length': '16', 'null': 'True', 'blank': 'True'}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}) + } + } + + complete_apps = ['players'] + symmetrical = True diff --git a/src/players/migrations/0022_delete_old_profile.py b/src/players/migrations/0022_delete_old_profile.py new file mode 100644 index 0000000000..dd1f7c2dd8 --- /dev/null +++ b/src/players/migrations/0022_delete_old_profile.py @@ -0,0 +1,107 @@ +# -*- coding: utf-8 -*- +import datetime +from south.db import db +from south.v2 import SchemaMigration +from django.db import models + + +class Migration(SchemaMigration): + + def forwards(self, orm): + db.delete_table('players_playerdb') + + def backwards(self, orm): + raise RuntimeError("Cannot revert this migration") + + models = { + u'auth.group': { + 'Meta': {'object_name': 'Group'}, + u'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': u"orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}) + }, + u'auth.permission': { + 'Meta': {'ordering': "(u'content_type__app_label', u'content_type__model', u'codename')", 'unique_together': "((u'content_type', u'codename'),)", 'object_name': 'Permission'}, + 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['contenttypes.ContentType']"}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}) + }, + u'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': u"orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}), + u'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': u"orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}), + 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'}) + }, + u'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'}), + u'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'}) + }, + u'players.playerattribute': { + 'Meta': {'object_name': 'PlayerAttribute'}, + '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_index': 'True'}), + 'db_lock_storage': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'db_obj': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['players.PlayerDB']"}), + 'db_value': ('src.utils.picklefield.PickledObjectField', [], {'null': 'True'}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}) + }, + u'players.playerdb': { + 'Meta': {'object_name': 'PlayerDB'}, + 'db_cmdset_storage': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True'}), + 'db_date_created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}), + 'db_is_connected': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'db_key': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}), + 'db_lock_storage': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'db_permissions': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}), + 'db_typeclass_path': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True'}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['auth.User']", 'unique': 'True'}) + }, + u'players.playerdbtmp': { + 'Meta': {'ordering': "['-db_date_created', 'id', 'db_typeclass_path', 'db_key']", 'object_name': 'PlayerDBtmp'}, + 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + '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_index': 'True'}), + 'db_is_connected': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'db_cmdset_storage': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True'}), + 'db_lock_storage': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'db_permissions': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}), + 'db_typeclass_path': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True'}), + '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': u"orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}), + u'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': u"orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}), + 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'}) + }, + u'players.playernick': { + 'Meta': {'unique_together': "(('db_nick', 'db_type', 'db_obj'),)", 'object_name': 'PlayerNick'}, + 'db_nick': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}), + 'db_obj': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['players.PlayerDB']"}), + 'db_real': ('django.db.models.fields.TextField', [], {}), + 'db_type': ('django.db.models.fields.CharField', [], {'default': "'inputline'", 'max_length': '16', 'null': 'True', 'blank': 'True'}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}) + } + } + + complete_apps = ['players'] diff --git a/src/players/migrations/0023_rename_tmp_player_to_playerdb.py b/src/players/migrations/0023_rename_tmp_player_to_playerdb.py new file mode 100644 index 0000000000..1a942b8be1 --- /dev/null +++ b/src/players/migrations/0023_rename_tmp_player_to_playerdb.py @@ -0,0 +1,101 @@ +# -*- coding: utf-8 -*- +import datetime +from south.db import db +from south.v2 import SchemaMigration +from django.db import models + + +class Migration(SchemaMigration): + + def forwards(self, orm): + db.rename_table('players_PlayerDBtmp', 'players_PlayerDB') + db.send_create_signal('players', ['PlayerDB']) + + def backwards(self, orm): + raise RuntimeError("Cannot revert this migration.") + + models = { + u'auth.group': { + 'Meta': {'object_name': 'Group'}, + u'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': u"orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}) + }, + u'auth.permission': { + 'Meta': {'ordering': "(u'content_type__app_label', u'content_type__model', u'codename')", 'unique_together': "((u'content_type', u'codename'),)", 'object_name': 'Permission'}, + 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['contenttypes.ContentType']"}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}) + }, + u'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'}), + u'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'}) + }, + u'players.playerattribute': { + 'Meta': {'object_name': 'PlayerAttribute'}, + '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_index': 'True'}), + 'db_lock_storage': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'db_obj': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['players.PlayerDB']"}), + 'db_value': ('src.utils.picklefield.PickledObjectField', [], {'null': 'True'}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}) + }, +# u'players.playerdbtmp': { +# 'Meta': {'ordering': "['-db_date_created', 'id', 'db_typeclass_path', 'db_key']", 'object_name': 'PlayerDBtmp'}, +# 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), +# '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_index': 'True'}), +# 'db_is_connected': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), +# 'db_cmdset_storage': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True'}), +# 'db_lock_storage': ('django.db.models.fields.TextField', [], {'blank': 'True'}), +# 'db_permissions': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}), +# 'db_typeclass_path': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True'}), +# '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': u"orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}), +# u'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': u"orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}), +# 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'}) +# }, + u'players.playerdb': { + 'Meta': {'ordering': "['-db_date_created', 'id', 'db_typeclass_path', 'db_key']", 'object_name': 'PlayerDB'}, + 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + '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_index': 'True'}), + 'db_lock_storage': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'db_permissions': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}), + 'db_typeclass_path': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True'}), + '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': u"orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}), + u'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': u"orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}), + 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'}) + }, + u'players.playernick': { + 'Meta': {'unique_together': "(('db_nick', 'db_type', 'db_obj'),)", 'object_name': 'PlayerNick'}, + 'db_nick': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}), + 'db_obj': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['players.PlayerDB']"}), + 'db_real': ('django.db.models.fields.TextField', [], {}), + 'db_type': ('django.db.models.fields.CharField', [], {'default': "'inputline'", 'max_length': '16', 'null': 'True', 'blank': 'True'}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}) + } + } + + complete_apps = ['players'] diff --git a/src/players/models.py b/src/players/models.py index aaab60f7e1..d3b46654ee 100644 --- a/src/players/models.py +++ b/src/players/models.py @@ -25,7 +25,7 @@ account info and OOC account configuration variables etc. from django.conf import settings from django.db import models -from django.contrib.auth.models import User +from django.contrib.auth.models import AbstractUser, User from django.utils.encoding import smart_str from src.server.caches import get_field_cache, set_field_cache, del_field_cache @@ -110,7 +110,8 @@ class PlayerNickHandler(TypeNickHandler): # #------------------------------------------------------------ -class PlayerDB(TypedObject): + +class PlayerDB(TypedObject, AbstractUser): """ This is a special model using Django's 'profile' functionality and extends the default Django User model. It is defined as such @@ -145,8 +146,8 @@ class PlayerDB(TypedObject): # this is the one-to-one link between the customized Player object and # this profile model. It is required by django. - user = models.ForeignKey(User, unique=True, db_index=True, - help_text="The User object holds django-specific authentication for each Player. A unique User should be created and tied to each Player, the two should never be switched or changed around. The User will be deleted automatically when the Player is.") + #user = models.ForeignKey(User, unique=True, db_index=True, + # help_text="The User object holds django-specific authentication for each Player. A unique User should be created and tied to each Player, the two should never be switched or changed around. The User will be deleted automatically when the Player is.") # store a connected flag here too, not just in sessionhandler. # This makes it easier to track from various out-of-process locations db_is_connected = models.BooleanField(default=False, verbose_name="is_connected", help_text="If player is connected to game or not") @@ -254,17 +255,19 @@ class PlayerDB(TypedObject): #@property def __name_get(self): "Getter. Allows for value = self.name" - name = get_prop_cache(self, "_name") - if not name: - name = _GA(self,"user").username - set_prop_cache(self, "_name", name) - return name + return self.username + #name = get_prop_cache(self, "_name") + #if not name: + # name = _GA(self,"user").username + # set_prop_cache(self, "_name", name) + #return name #@name.setter def __name_set(self, value): "Setter. Allows for player.name = newname" - _GA(self, "user").username = value - _GA(self, "user").save() - set_prop_cache(self, "_name", value) + self.username = value + #_GA(self, "user").username = value + #_GA(self, "user").save() + #set_prop_cache(self, "_name", value) #@name.deleter def __name_del(self): "Deleter. Allows for del self.name" @@ -275,11 +278,12 @@ class PlayerDB(TypedObject): #@property def __uid_get(self): "Getter. Retrieves the user id" - uid = get_prop_cache(self, "_uid") - if not uid: - uid = _GA(self, "user").id - set_prop_cache(self, "_uid", uid) - return uid + return self.id + #uid = get_prop_cache(self, "_uid") + #if not uid: + # uid = _GA(self, "user").id + # set_prop_cache(self, "_uid", uid) + #return uid def __uid_set(self, value): raise Exception("User id cannot be set!") def __uid_del(self): @@ -287,14 +291,15 @@ class PlayerDB(TypedObject): uid = property(__uid_get, __uid_set, __uid_del) #@property - def __is_superuser_get(self): - "Superusers have all permissions." - is_suser = get_prop_cache(self, "_is_superuser") - if is_suser == None: - is_suser = _GA(self, "user").is_superuser - set_prop_cache(self, "_is_superuser", is_suser) - return is_suser - is_superuser = property(__is_superuser_get) + #def __is_superuser_get(self): + # "Superusers have all permissions." + # return self.db_is_superuser + # #is_suser = get_prop_cache(self, "_is_superuser") + # #if is_suser == None: + # # is_suser = _GA(self, "user").is_superuser + # # set_prop_cache(self, "_is_superuser", is_suser) + # #return is_suser + #is_superuser = property(__is_superuser_get) # # PlayerDB class access methods @@ -516,16 +521,12 @@ class PlayerDB(TypedObject): self.unpuppet_object(session.sessid) session.sessionhandler.disconnect(session, reason=_("Player being deleted.")) - try: - if _GA(self, "user"): - _GA(_GA(self, "user"), "delete")() - except AssertionError: - pass - try: - super(PlayerDB, self).delete(*args, **kwargs) - except AssertionError: - # this means deleting the user already cleared out the Player object. - pass + #try: + # if _GA(self, "user"): + # _GA(_GA(self, "user"), "delete")() + #except AssertionError: + # pass + super(PlayerDB, self).delete(*args, **kwargs) def execute_cmd(self, raw_string, sessid=None): """ @@ -573,3 +574,6 @@ class PlayerDB(TypedObject): except: pass return matches + +class PlayerDBtmp(AbstractUser): + pass diff --git a/src/server/initial_setup.py b/src/server/initial_setup.py index dc0326fe78..f93da77d5b 100644 --- a/src/server/initial_setup.py +++ b/src/server/initial_setup.py @@ -7,13 +7,15 @@ Everything starts at handle_setup() """ import django -from django.contrib.auth.models import User from django.core import management from django.conf import settings +from django.core.management import call_command +from django.contrib.auth import get_user_model from src.server.models import ServerConfig from src.help.models import HelpEntry from src.utils import create + from django.utils.translation import ugettext as _ def create_config_values(): @@ -25,9 +27,18 @@ def create_config_values(): def get_god_user(): """ - Returns the initially created 'god' User object. + Creates the god user. """ - return User.objects.get(id=1) + PlayerDB = get_user_model() + try: + god_user = PlayerDB.objects.get(id=1) + except PlayerDB.DoesNotExist: + txt = "\n\nNo superuser exists yet. The superuser is the 'owner' account on the" + txt += "\nEvennia server; a good safety fallback. Create a new superuser using the command" + txt += "\n\n python manage.py createsuperuser" + txt += "\n\nFollow the prompts, then restart the server." + raise Exception(txt) + return god_user def create_objects(): """ diff --git a/src/settings_default.py b/src/settings_default.py index 068709af83..90d0509482 100644 --- a/src/settings_default.py +++ b/src/settings_default.py @@ -484,11 +484,12 @@ INSTALLED_APPS = ( 'src.comms', 'src.help', 'src.scripts', - 'src.web.news', + #'src.web.news', 'src.web.website',) # The user profile extends the User object with more functionality; # This should usually not be changed. -AUTH_PROFILE_MODULE = "players.PlayerDB" +AUTH_USER_MODEL = "players.PlayerDB" +#AUTH_PROFILE_MODULE = "players.PlayerDB" # Use a custom test runner that just tests Evennia-specific apps. TEST_RUNNER = 'src.utils.test_utils.EvenniaTestSuiteRunner' diff --git a/src/web/news/models.py b/src/web/news/models.py index 02819644f6..9ea8f54953 100755 --- a/src/web/news/models.py +++ b/src/web/news/models.py @@ -1,7 +1,7 @@ # # This module implements a simple news entry system -# for the evennia website. One needs to use the -# admin interface to add/edit/delete entries. +# for the evennia website. One needs to use the +# admin interface to add/edit/delete entries. # from django.db import models @@ -13,8 +13,8 @@ class NewsTopic(models.Model): """ name = models.CharField(max_length=75, unique=True) description = models.TextField(blank=True) - icon = models.ImageField(upload_to='newstopic_icons', - default='newstopic_icons/default.png', + icon = models.ImageField(upload_to='newstopic_icons', + default='newstopic_icons/default.png', blank=True, help_text="Image for the news topic.") def __str__(self): @@ -35,7 +35,7 @@ class NewsEntry(models.Model): body = models.TextField() topic = models.ForeignKey(NewsTopic, related_name='newstopic') date_posted = models.DateTimeField(auto_now_add=True) - + def __str__(self): return self.title From 46d1c48a389b33d7243891271867347b671aef55 Mon Sep 17 00:00:00 2001 From: Griatch Date: Thu, 11 Jul 2013 18:03:07 +0200 Subject: [PATCH 17/17] Working implementation of User->PlayerDB conversion. Superuser must be created separately. The player-create method was corrected, along with the most obvious places where the user-setup was used. One can log in and look around but it's not heavily debugged yet. --- src/commands/default/unloggedin.py | 5 +- src/objects/manager.py | 28 +------ src/players/admin.py | 1 + src/players/manager.py | 71 +++------------- src/server/initial_setup.py | 28 ++++--- src/server/serversession.py | 11 ++- src/utils/create.py | 129 ++++++++++------------------- src/utils/search.py | 4 +- 8 files changed, 81 insertions(+), 196 deletions(-) diff --git a/src/commands/default/unloggedin.py b/src/commands/default/unloggedin.py index d9c5145f7c..f4f734ca5c 100644 --- a/src/commands/default/unloggedin.py +++ b/src/commands/default/unloggedin.py @@ -4,7 +4,6 @@ Commands that are available from the connect screen. import re import traceback from django.conf import settings -from django.contrib.auth.models import User from src.players.models import PlayerDB from src.objects.models import ObjectDB from src.server.models import ServerConfig @@ -68,7 +67,7 @@ class CmdUnconnectedConnect(MuxCommand): player = PlayerDB.objects.get_player_from_name(playername) pswd = None if player: - pswd = player.user.check_password(password) + pswd = player.check_password(password) if not (player and pswd): # No playername or password match @@ -142,7 +141,7 @@ class CmdUnconnectedCreate(MuxCommand): return # strip excessive spaces in playername playername = re.sub(r"\s+", " ", playername).strip() - if PlayerDB.objects.filter(user__username__iexact=playername) or User.objects.filter(username__iexact=playername): + if PlayerDB.objects.filter(username__iexact=playername): # player already exists (we also ignore capitalization here) session.msg("Sorry, there is already a player with the name '%s'." % playername) return diff --git a/src/objects/manager.py b/src/objects/manager.py index 0e8d0bbc57..d45e4b4d7e 100644 --- a/src/objects/manager.py +++ b/src/objects/manager.py @@ -34,7 +34,6 @@ class ObjectManager(TypedObjectManager): get_dbref_range object_totals typeclass_search - get_object_with_user get_object_with_player get_objs_with_key_and_typeclass get_objs_with_attr @@ -52,29 +51,8 @@ class ObjectManager(TypedObjectManager): # ObjectManager Get methods # - # user/player related + # player related - @returns_typeclass - def get_object_with_user(self, user): - """ - Matches objects with obj.player.user matching the argument. - A player<->user is a one-to-relationship, so this always - returns just one result or None. - - user - may be a user object or user id. - """ - dbref = self.dbref(user) - if dbref: - try: - return self.get(db_player__user__id=dbref) - except self.model.DoesNotExist: - pass - try: - return self.get(db_player__user=user) - except self.model.DoesNotExist: - return None - - # This returns typeclass since get_object_with_user and get_dbref does. @returns_typeclass def get_object_with_player(self, ostring, exact=True, candidates=None): """ @@ -92,9 +70,9 @@ class ObjectManager(TypedObjectManager): # not a dbref. Search by name. cand_restriction = candidates and Q(pk__in=[_GA(obj, "id") for obj in make_iter(candidates) if obj]) or Q() if exact: - return self.filter(cand_restriction & Q(db_player__user__username__iexact=ostring)) + return self.filter(cand_restriction & Q(db_player__username__iexact=ostring)) else: # fuzzy matching - ply_cands = self.filter(cand_restriction & Q(playerdb__user__username__istartswith=ostring)).values_list("db_key", flat=True) + ply_cands = self.filter(cand_restriction & Q(playerdb__username__istartswith=ostring)).values_list("db_key", flat=True) if candidates: index_matches = string_partial_matching(ply_cands, ostring, ret_index=True) return [obj for ind, obj in enumerate(make_iter(candidates)) if ind in index_matches] diff --git a/src/players/admin.py b/src/players/admin.py index 64e8e3d36b..b61b36f60a 100644 --- a/src/players/admin.py +++ b/src/players/admin.py @@ -141,6 +141,7 @@ class UserAdmin(BaseUserAdmin): {'fields': ('username', 'password1', 'password2', 'email'), 'description':"These account details are shared by the admin system and the game."},),) + # TODO! Remove User reference! def save_formset(self, request, form, formset, change): "Run all hooks on the player object" super(UserAdmin, self).save_formset(request, form, formset, change) diff --git a/src/players/manager.py b/src/players/manager.py index b95c96284b..4bfc9605b0 100644 --- a/src/players/manager.py +++ b/src/players/manager.py @@ -3,8 +3,8 @@ The managers for the custom Player object and permissions. """ import datetime -from functools import update_wrapper from django.contrib.auth.models import UserManager +from functools import update_wrapper from src.typeclasses.managers import returns_typeclass_list, returns_typeclass, TypedObjectManager from src.utils import logger __all__ = ("PlayerManager",) @@ -13,53 +13,6 @@ __all__ = ("PlayerManager",) # Player Manager # -def returns_player_list(method): - """ - decorator that makes sure that a method - returns a Player object instead of a User - one (if you really want the User object, not - the player, use the player's 'user' property) - """ - def func(self, *args, **kwargs): - "This *always* returns a list." - match = method(self, *args, **kwargs) - if not match: - return [] - try: - match = list(match) - except TypeError: - match = [match] - players = [] - for user in match: - try: - players.append(user.get_profile()) - except Exception: - # there is something wrong with get_profile. But - # there is a 1-1 relation between Users-Players, so we - # try to go the other way instead. - from src.players.models import PlayerDB - match = PlayerDB.objects.filter(user__id=user.id) - if match: - players.append(match[0]) - else: - logger.log_trace("No connection User<->Player, maybe database was partially reset?") - return players - return update_wrapper(func, method) - -def returns_player(method): - """ - Decorator: Always returns a single result or None. - """ - def func(self, *args, **kwargs): - "decorator" - rfunc = returns_player_list(method) - match = rfunc(self, *args, **kwargs) - if match: - return match[0] - else: - return None - return update_wrapper(func, method) - class PlayerManager(TypedObjectManager, UserManager): """ This PlayerManager implements methods for searching @@ -87,7 +40,7 @@ class PlayerManager(TypedObjectManager, UserManager): """ def num_total_players(self): """ - Returns the total number of registered users/players. + Returns the total number of registered players. """ return self.count() @@ -99,7 +52,6 @@ class PlayerManager(TypedObjectManager, UserManager): return self.filter(db_is_connected=True) @returns_typeclass_list - @returns_player_list def get_recently_created_players(self, days=7): """ Returns a QuerySet containing the player User accounts that have been @@ -108,13 +60,12 @@ class PlayerManager(TypedObjectManager, UserManager): end_date = datetime.datetime.now() tdelta = datetime.timedelta(days) start_date = end_date - tdelta - return User.objects.filter(date_joined__range=(start_date, end_date)) + return self.filter(date_joined__range=(start_date, end_date)) @returns_typeclass_list - @returns_player_list def get_recently_connected_players(self, days=7): """ - Returns a QuerySet containing the player User accounts that have been + Returns a QuerySet containing the player accounts that have been connected within the last days. days - number of days backwards to check @@ -122,33 +73,31 @@ class PlayerManager(TypedObjectManager, UserManager): end_date = datetime.datetime.now() tdelta = datetime.timedelta(days) start_date = end_date - tdelta - return User.objects.filter(last_login__range=( + return self.filter(last_login__range=( start_date, end_date)).order_by('-last_login') @returns_typeclass - @returns_player def get_player_from_email(self, uemail): """ Returns a player object when given an email address. """ - return User.objects.filter(email__iexact=uemail) + return self.filter(email__iexact=uemail) @returns_typeclass - @returns_player def get_player_from_uid(self, uid): """ Returns a player object based on User id. """ try: - return User.objects.get(id=uid) - except User.model.DoesNotExist: + return self.get(id=uid) + except self.model.DoesNotExist: return None @returns_typeclass def get_player_from_name(self, uname): "Get player object based on name" try: - return self.get(user__username__iexact=uname) + return self.get(username__iexact=uname) except self.model.DoesNotExist: return None @@ -165,7 +114,7 @@ class PlayerManager(TypedObjectManager, UserManager): matches = self.filter(id=dbref) if matches: return matches - return self.filter(user__username__iexact=ostring) + return self.filter(username__iexact=ostring) def swap_character(self, player, new_character, delete_old_character=False): """ diff --git a/src/server/initial_setup.py b/src/server/initial_setup.py index f93da77d5b..feaca4ec33 100644 --- a/src/server/initial_setup.py +++ b/src/server/initial_setup.py @@ -25,20 +25,20 @@ def create_config_values(): ServerConfig.objects.conf("site_name", settings.SERVERNAME) ServerConfig.objects.conf("idle_timeout", settings.IDLE_TIMEOUT) -def get_god_user(): +def get_god_player(): """ Creates the god user. """ PlayerDB = get_user_model() try: - god_user = PlayerDB.objects.get(id=1) + god_player = PlayerDB.objects.get(id=1) except PlayerDB.DoesNotExist: txt = "\n\nNo superuser exists yet. The superuser is the 'owner' account on the" - txt += "\nEvennia server; a good safety fallback. Create a new superuser using the command" + txt += "\nEvennia server. Create a new superuser using the command" txt += "\n\n python manage.py createsuperuser" txt += "\n\nFollow the prompts, then restart the server." raise Exception(txt) - return god_user + return god_player def create_objects(): """ @@ -49,22 +49,26 @@ def create_objects(): # Set the initial User's account object's username on the #1 object. # This object is pure django and only holds name, email and password. - god_user = get_god_user() + god_player = get_god_player() # Create a Player 'user profile' object to hold eventual # mud-specific settings for the bog standard User object. This is # accessed by user.get_profile() and can also store attributes. # It also holds mud permissions, but for a superuser these # have no effect anyhow. - character_typeclass = settings.BASE_CHARACTER_TYPECLASS + player_typeclass = settings.BASE_PLAYER_TYPECLASS - # Create the Player object as well as the in-game god-character - # for user #1. We can't set location and home yet since nothing + # run all creation hooks on god_player (we must do so manually since the manage.py command does not) + god_player.typeclass_path = player_typeclass + god_player.basetype_setup() + god_player.at_player_creation() + god_player.locks.add("examine:perm(Immortals);edit:false();delete:false();boot:false();msg:all()") + + # Create the in-game god-character for player #1. We can't set location and home yet since nothing # exists. Also, all properties (name, email, password, is_superuser) # is inherited from the user so we don't specify it again here. - - god_player = create.create_player(god_user.username, None, None, user=god_user) - god_character = create.create_object(character_typeclass, key=god_user.username) + character_typeclass = settings.BASE_CHARACTER_TYPECLASS + god_character = create.create_object(character_typeclass, key=god_player.username) god_character.id = 1 god_character.db.desc = _('This is User #1.') @@ -132,7 +136,7 @@ def create_channels(): return # connect the god user to all these channels by default. - goduser = get_god_user() + goduser = get_god_player() from src.comms.models import PlayerChannelConnection PlayerChannelConnection.objects.create_connection(goduser, pchan) PlayerChannelConnection.objects.create_connection(goduser, ichan) diff --git a/src/server/serversession.py b/src/server/serversession.py index 49493311f8..24ba73cae1 100644 --- a/src/server/serversession.py +++ b/src/server/serversession.py @@ -77,17 +77,16 @@ class ServerSession(Session): player - the player associated with the session """ self.player = player - self.user = player.user - self.uid = self.user.id - self.uname = self.user.username + self.uid = self.player.id + self.uname = self.player.username self.logged_in = True self.conn_time = time.time() self.puid = None self.puppet = None # Update account's last login time. - self.user.last_login = datetime.now() - self.user.save() + self.player.last_login = datetime.now() + self.player.save() def at_disconnect(self): """ @@ -97,7 +96,7 @@ class ServerSession(Session): sessid = self.sessid player = self.player _GA(player.dbobj, "unpuppet_object")(sessid) - uaccount = _GA(player.dbobj, "user") + uaccount = player.dbobj uaccount.last_login = datetime.now() uaccount.save() # calling player hook diff --git a/src/utils/create.py b/src/utils/create.py index 0eae842304..32e07dfa7c 100644 --- a/src/utils/create.py +++ b/src/utils/create.py @@ -22,7 +22,6 @@ Models covered: Players """ from django.conf import settings -from django.contrib.auth.models import User from django.db import IntegrityError from src.utils.idmapper.models import SharedMemoryModel from src.utils import utils, logger @@ -387,49 +386,32 @@ channel = create_channel # Player creation methods # -def create_player(name, email, password, - user=None, +def create_player(key, email, password, typeclass=None, is_superuser=False, locks=None, permissions=None, - player_dbobj=None, report_to=None): + report_to=None): """ - This creates a new player, handling the creation of the User - object and its associated Player object. + This creates a new player. - If player_dbobj is given, this player object is used instead of - creating a new one. This is called by the admin interface since it - needs to create the player object in order to relate it automatically - to the user. + key - the player's name. This should be unique. + email - email on valid addr@addr.domain form. + password - password in cleartext + is_superuser - wether or not this player is to be a superuser + locks - lockstring + permission - list of permissions + report_to - an object with a msg() method to report errors to. If + not given, errors will be logged. - If create_character is - True, a game player object with the same name as the User/Player will - also be created. Its typeclass and base properties can also be given. - - Returns the new game character, or the Player obj if no - character is created. For more info about the typeclass argument, - see create_objects() above. - - Note: if user is supplied, it will NOT be modified (args name, email, - passw and is_superuser will be ignored). Change those properties - directly on the User instead. - - If no permissions are given (None), the default permission group - as defined in settings.PERMISSION_PLAYER_DEFAULT will be - assigned. If permissions are given, no automatic assignment will - occur. + Will return the Player-typeclass or None/raise Exception if the + Typeclass given failed to load. Concerning is_superuser: - A superuser should have access to everything - in the game and on the server/web interface. The very first user - created in the database is always a superuser (that's using - django's own creation, not this one). Usually only the server admin should need to be superuser, all other access levels can be handled with more fine-grained - permissions or groups. - Since superuser overrules all permissions, we don't - set any in this case. + permissions or groups. A superuser bypasses all lock checking + operations and is thus not suitable for play-testing the game. """ global _PlayerDB, _Player @@ -440,48 +422,28 @@ def create_player(name, email, password, if not email: email = "dummy@dummy.com" - if user: - new_user = user - email = user.email - - if user: - conflict_check = User.objects.filter(username__iexact=user.username) - conflict_check = len(conflict_check) > 1 - else: - conflict_check = User.objects.filter(username__iexact=name) - - if conflict_check: - raise ValueError("A user with this name already exists.") - - if not user: - if is_superuser: - new_user = User.objects.create_superuser(name, email, password) - else: - new_user = User.objects.create_user(name, email, password) + if _PlayerDB.objects.filter(username__iexact=key): + raise ValueError("A Player with this name already exists.") try: + + # create the correct Player object + if is_superuser: + new_db_player = _PlayerDB.objects.create_superuser(key, email, password) + else: + new_db_player = _PlayerDB.objects.create_user(key, email, password) + if not typeclass: typeclass = settings.BASE_PLAYER_TYPECLASS elif isinstance(typeclass, _PlayerDB): - # this is already an objectdb instance, extract its typeclass + # this is an PlayerDB instance, extract its typeclass path typeclass = typeclass.typeclass.path elif isinstance(typeclass, _Player) or utils.inherits_from(typeclass, _Player): - # this is already an object typeclass, extract its path + # this is Player object typeclass, extract its path typeclass = typeclass.path - if player_dbobj: - try: - _GA(player_dbobj, "dbobj") - new_db_player = player_dbobj.dbobj - except AttributeError: - new_db_player = player_dbobj - # use the typeclass from this object - typeclass = new_db_player.typeclass_path - else: - new_user = User.objects.get(username=new_user.username) - new_db_player = _PlayerDB(db_key=name, user=new_user) - new_db_player.save() - # assign the typeclass - typeclass = utils.to_unicode(typeclass) - new_db_player.typeclass_path = typeclass + + # assign the typeclass + typeclass = utils.to_unicode(typeclass) + new_db_player.typeclass_path = typeclass # this will either load the typeclass or the default one new_player = new_db_player.typeclass @@ -500,34 +462,27 @@ def create_player(name, email, password, # call hook method (may override default permissions) new_player.at_player_creation() - print # custom given arguments potentially overrides the hook if permissions: new_player.permissions = permissions elif not new_player.permissions: new_player.permissions = settings.PERMISSION_PLAYER_DEFAULT - if locks: new_player.locks.add(locks) - return new_player + except Exception: - # a failure in creating the character - if not user: - # in there was a failure we clean up everything we can - logger.log_trace() - try: - new_user.delete() - except Exception: - pass - try: - new_player.delete() - except Exception: - pass - try: - del new_player - except Exception: - pass + # a failure in creating the player; we try to clean + # up as much as we can + logger.log_trace() + try: + new_player.delete() + except Exception: + pass + try: + del new_player + except Exception: + pass raise # alias diff --git a/src/utils/search.py b/src/utils/search.py index a7abbc2354..032c6241d1 100644 --- a/src/utils/search.py +++ b/src/utils/search.py @@ -16,11 +16,11 @@ the database model and call its 'objects' property. Also remember that all commands in this file return lists (also if there is only one match) unless noted otherwise. -Example: To reach the search method 'get_object_with_user' +Example: To reach the search method 'get_object_with_player' in src/objects/managers.py: > from src.objects.models import ObjectDB -> match = Object.objects.get_object_with_user(...) +> match = Object.objects.get_object_with_player(...) """