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(...) """