From 1291509d0333cf2a0e441e4501a00cc82238e470 Mon Sep 17 00:00:00 2001 From: Griatch Date: Tue, 4 Oct 2011 21:14:41 +0200 Subject: [PATCH] Added inlines and fixed admin interface to not allow editing User once a Player is created. --- src/objects/admin.py | 49 +++++++++++++---------- src/players/admin.py | 93 ++++++++++++++++++++++++++++--------------- src/players/models.py | 2 +- 3 files changed, 91 insertions(+), 53 deletions(-) diff --git a/src/objects/admin.py b/src/objects/admin.py index 6cb6fee30e..aad61004ab 100644 --- a/src/objects/admin.py +++ b/src/objects/admin.py @@ -9,31 +9,37 @@ from django.contrib import admin from src.objects.models import ObjAttribute, ObjectDB from src.utils.utils import mod_import -class ObjectAttributeAdmin(admin.ModelAdmin): - list_display = ('id', 'db_key', 'db_obj') - list_display_links = ('id', 'db_key') - ordering = ('db_obj','db_key', 'id') - search_fields = ('^db_key', 'db_obj') - save_as = True - save_on_top = True - list_select_related = True -admin.site.register(ObjAttribute, ObjectAttributeAdmin) +# class ObjectAttributeAdmin(admin.ModelAdmin): +# list_display = ('id', 'db_key', 'db_obj') +# list_display_links = ('id', 'db_key') +# ordering = ('db_obj','db_key', 'id') +# search_fields = ('^db_key', 'db_obj') +# save_as = True +# save_on_top = True +# list_select_related = True +# admin.site.register(ObjAttribute, ObjectAttributeAdmin) class ObjAttributeInline(admin.TabularInline): model = ObjAttribute fields = ('db_key', 'db_value') - extra = 1 + extra = 0 class ObjectEditForm(forms.ModelForm): "This form details the look of the fields" class Meta: model = ObjectDB - db_typeclass_path = forms.CharField(label="Typeclass",initial=settings.BASE_OBJECT_TYPECLASS, - help_text="this defines what 'type' of entity this is. This variable holds a Python path to a module with a valid Evennia Typeclass.") - db_permissions = forms.CharField(label="Permissions", required=False, - help_text="a comma-separated list of text strings checked by certain locks. They are mainly of use for Character objects. Character permissions overload permissions defined on a controlling Player. Most objects normally don't have any permissions defined.") - db_lock_storage = forms.CharField(label="Locks", required=False, widget=forms.Textarea(attrs={'cols':'100', 'rows':'1'}), - help_text="locks limit access to an entity. A lock is defined as a 'lock string' on the form 'type:lockfunctions', defining what functionality is locked and how to determine access. Take a look at other Objects to see valid strings. An empty lock means no access is given to anything for anyone. ") + db_typeclass_path = forms.CharField(label="Typeclass", + initial=settings.BASE_OBJECT_TYPECLASS, + widget=forms.TextInput(attrs={'size':'78'}), + help_text="this defines what 'type' of entity this is. This variable holds a Python path to a module with a valid Evennia Typeclass.") + db_permissions = forms.CharField(label="Permissions", + required=False, + widget=forms.TextInput(attrs={'size':'78'}), + help_text="a comma-separated list of text strings checked by certain locks. They are mainly of use for Character objects. Character permissions overload permissions defined on a controlling Player. Most objects normally don't have any permissions defined.") + db_lock_storage = forms.CharField(label="Locks", + required=False, + widget=forms.Textarea(attrs={'cols':'100', 'rows':'2'}), + help_text="locks limit access to an entity. A lock is defined as a 'lock string' on the form 'type:lockfunctions', defining what functionality is locked and how to determine access. Take a look at other Objects to see valid strings. An empty lock means no access is given to anything for anyone. ") class ObjectCreateForm(forms.ModelForm): "This form details the look of the fields" @@ -41,9 +47,11 @@ class ObjectCreateForm(forms.ModelForm): model = ObjectDB fields = ('db_key',) db_typeclass_path = forms.CharField(label="Typeclass",initial=settings.BASE_OBJECT_TYPECLASS, - help_text="this defines what 'type' of entity this is. This variable holds a Python path to a module with a valid Evennia Typeclass.") - db_permissions = forms.CharField(label="Permissions", initial=settings.PERMISSION_PLAYER_DEFAULT,required=False, - help_text="a comma-separated list of text strings checked by certain locks. They are mainly of use for Character objects. Character permissions overload permissions defined on a controlling Player. Most objects normally don't have any permissions defined.") + widget=forms.TextInput(attrs={'size':'78'}), + help_text="this defines what 'type' of entity this is. This variable holds a Python path to a module with a valid Evennia Typeclass.") + db_permissions = forms.CharField(label="Permissions", initial=settings.PERMISSION_PLAYER_DEFAULT, required=False, + widget=forms.TextInput(attrs={'size':'78'}), + help_text="a comma-separated list of text strings checked by certain locks. They are mainly of use for Character objects. Character permissions overload permissions defined on a controlling Player. Most objects normally don't have any permissions defined.") class ObjectDBAdmin(admin.ModelAdmin): @@ -56,6 +64,7 @@ class ObjectDBAdmin(admin.ModelAdmin): save_as = True save_on_top = True list_select_related = True + list_filter = ('db_permissions', 'db_location', 'db_typeclass_path') # editing fields setup @@ -68,7 +77,7 @@ class ObjectDBAdmin(admin.ModelAdmin): ) #deactivated temporarily, they cause empty objects to be created in admin - #inlines = [ObjAttributeInline] + inlines = [ObjAttributeInline] # Custom modification to give two different forms wether adding or not. diff --git a/src/players/admin.py b/src/players/admin.py index df2322b798..29903ac84c 100644 --- a/src/players/admin.py +++ b/src/players/admin.py @@ -19,20 +19,26 @@ admin.site.unregister(User) # handle the custom User editor class CustomUserChangeForm(UserChangeForm): - username = forms.RegexField(label="Username", max_length=30, regex=r'^[\w. @+-]+$',widget=forms.TextInput(attrs={'size':'30'}), - help_text = "This should be the same as the connected Player's key name. 30 characters or fewer. Letters, spaces, digits and @/./+/-/_ only.", - error_messages = {'invalid': "This value may contain only letters, spaces, numbers and @/./+/-/_ characters."}) + username = forms.RegexField(label="Username", + max_length=30, + regex=r'^[\w. @+-]+$', + widget=forms.TextInput(attrs={'size':'30'}), + error_messages = {'invalid': "This value may contain only letters, spaces, numbers and @/./+/-/_ characters."}, + help_text = "This should be the same as the connected Player's key name. 30 characters or fewer. Letters, spaces, digits and @/./+/-/_ only.") + class CustomUserCreationForm(UserCreationForm): - username = forms.RegexField(label="Username", max_length=30, regex=r'^[\w. @+-]+$',widget=forms.TextInput(attrs={'size':'30'}), - help_text = "This should be the same as the connected Player's key name. 30 characters or fewer. Letters, spaces, digits and @/./+/-/_ only.", - error_messages = {'invalid': "This value may contain only letters, spaces, numbers and @/./+/-/_ characters."}) + username = forms.RegexField(label="Username", + max_length=30, + regex=r'^[\w. @+-]+$', + widget=forms.TextInput(attrs={'size':'30'}), + error_messages = {'invalid': "This value may contain only letters, spaces, numbers and @/./+/-/_ characters."}, + help_text = "This should be the same as the connected Player's key name. 30 characters or fewer. Letters, spaces, digits and @/./+/-/_ only.") class UserAdmin(BaseUserAdmin): "This will pop up from the Player admin." list_display = ('username', 'email', 'is_staff', 'is_superuser') - form = CustomUserChangeForm add_form = CustomUserCreationForm add_fieldsets = ( @@ -41,19 +47,20 @@ class UserAdmin(BaseUserAdmin): 'description':"The User object holds all authentication information and bits for using the admin site. A superuser account represents a 'God user' in-game. This User account should have the same username as its corresponding Player object has; the two are always uniquely connected to each other."},),) admin.site.register(User, UserAdmin) - # The Player editor class PlayerAttributeForm(forms.ModelForm): "Defines how to display the atttributes" class Meta: model = PlayerAttribute - db_key = forms.CharField(label="Key", widget=forms.TextInput(attrs={'size':'15'})) - db_value = forms.CharField(label="Value", widget=forms.Textarea(attrs={'rows':'2'})) + db_key = forms.CharField(label="Key", + widget=forms.TextInput(attrs={'size':'15'})) + db_value = forms.CharField(label="Value", + widget=forms.Textarea(attrs={'rows':'2'})) class PlayerAttributeInline(admin.TabularInline): "Inline creation of player attributes" model = PlayerAttribute - extra = 1 + extra = 0 form = PlayerAttributeForm fieldsets = ( (None, {'fields' : (('db_key', 'db_value'))}),) @@ -65,18 +72,34 @@ class PlayerEditForm(forms.ModelForm): # important! This allows us to not excplicitly add all fields. model = PlayerDB - db_key = forms.RegexField(label="Username", max_length=30, regex=r'^[\w. @+-]+$', widget=forms.TextInput(attrs={'size':'30'}), - help_text = "this should be the same as the User's name. 30 characters or fewer. Letters, spaces, digits and @/./+/-/_ only.") - db_typeclass_path = forms.CharField(label="Typeclass",initial=settings.BASE_PLAYER_TYPECLASS, widget=forms.TextInput(attrs={'size':'78'}), - help_text="this defines what 'type' of entity this is. This variable holds a Python path to a module with a valid Evennia Typeclass.") - db_permissions = forms.CharField(label="Permissions", initial=settings.PERMISSION_PLAYER_DEFAULT,required=False, - help_text="a comma-separated list of text strings checked by certain locks. They are often used for hierarchies, such as letting a Player have permission 'Wizards', 'Builders' etc. A Player permission can be overloaded by the permissions of a controlled Character. Normal players use 'Players' by default.") - db_lock_storage = forms.CharField(label="Locks", widget=forms.Textarea(attrs={'cols':'100', 'rows':'1'}), + db_key = forms.RegexField(label="Username", + max_length=30, regex=r'^[\w. @+-]+$', + widget=forms.TextInput(attrs={'size':'30'}), + error_messages = {'invalid': "This value may contain only letters, spaces, numbers and @/./+/-/_ characters."}, + help_text = "this should be the same as the User's name. 30 characters or fewer. Letters, spaces, digits and @/./+/-/_ only.") + db_typeclass_path = forms.CharField(label="Typeclass", + initial=settings.BASE_PLAYER_TYPECLASS, + widget=forms.TextInput(attrs={'size':'78'}), + help_text="this defines what 'type' of entity this is. This variable holds a Python path to a module with a valid Evennia Typeclass.") + db_permissions = forms.CharField(label="Permissions", + initial=settings.PERMISSION_PLAYER_DEFAULT, + required=False, + widget=forms.TextInput(attrs={'size':'78'}), + help_text="a comma-separated list of text strings checked by certain locks. They are often used for hierarchies, such as letting a Player have permission 'Wizards', 'Builders' etc. A Player permission can be overloaded by the permissions of a controlled Character. Normal players use 'Players' by default.") + db_lock_storage = forms.CharField(label="Locks", + widget=forms.Textarea(attrs={'cols':'100', 'rows':'2'}), required=False, - help_text="locks limit access to an entity. A lock is defined as a 'lock string' on the form 'type:lockfunctions', defining what functionality is locked and how to determine access. This is set to a default upon creation.") - db_cmdset_storage = forms.CharField(label="cmdset", initial=settings.CMDSET_OOC, widget=forms.TextInput(attrs={'size':'78'}), + help_text="locks limit access to an entity. A lock is defined as a 'lock string' on the form 'type:lockfunctions', defining what functionality is locked and how to determine access. This is set to a default upon creation.") + db_cmdset_storage = forms.CharField(label="cmdset", + initial=settings.CMDSET_OOC, + widget=forms.TextInput(attrs={'size':'78'}), required=False, help_text="python path to cmdset class.") + user = forms.ModelChoiceField(queryset=User.objects.all(), + widget=forms.Select(attrs={'disabled':'true'})) + + + class PlayerCreateForm(forms.ModelForm): "This form details the look of the fields" @@ -86,11 +109,17 @@ class PlayerCreateForm(forms.ModelForm): db_key = forms.RegexField(label="Username", max_length=30, regex=r'^[\w. @+-]+$', widget=forms.TextInput(attrs={'size':'30'}), help_text = "this should be the same as the User's name. 30 characters or fewer. Letters, spaces, digits and @/./+/-/_ only.") - db_typeclass_path = forms.CharField(label="Typeclass",initial=settings.BASE_PLAYER_TYPECLASS, widget=forms.TextInput(attrs={'size':'78'}), - help_text="this defines what 'type' of entity this is. This variable holds a Python path to a module with a valid Evennia Typeclass.") - db_permissions = forms.CharField(label="Permissions", initial=settings.PERMISSION_PLAYER_DEFAULT,required=False, - help_text="a comma-separated list of text strings checked by certain locks. They are often used for hierarchies, such as letting a Player have permission 'Wizards', 'Builders' etc. A Player permission can be overloaded by the permissions of a controlled Character. Normal players use 'Players' by default.") - db_cmdset_storage = forms.CharField(label="cmdset", initial=settings.CMDSET_OOC, widget=forms.TextInput(attrs={'size':'78'}), + db_typeclass_path = forms.CharField(label="Typeclass", + initial=settings.BASE_PLAYER_TYPECLASS, + widget=forms.TextInput(attrs={'size':'78'}), + help_text="this defines what 'type' of entity this is. This variable holds a Python path to a module with a valid Evennia Typeclass.") + db_permissions = forms.CharField(label="Permissions", + initial=settings.PERMISSION_PLAYER_DEFAULT, + required=False, + help_text="a comma-separated list of text strings checked by certain locks. They are often used for hierarchies, such as letting a Player have permission 'Wizards', 'Builders' etc. A Player permission can be overloaded by the permissions of a controlled Character. Normal players use 'Players' by default.") + db_cmdset_storage = forms.CharField(label="cmdset", + initial=settings.CMDSET_OOC, + widget=forms.TextInput(attrs={'size':'78'}), required=False, help_text="python path to cmdset class.") @@ -104,24 +133,24 @@ class PlayerDBAdmin(admin.ModelAdmin): save_as = True save_on_top = True list_select_related = True + list_filter = ('db_permissions',) + # editing/adding player form = PlayerEditForm fieldsets = ( (None, {'fields' : (('db_key', 'db_typeclass_path'), 'user', ('db_permissions','db_lock_storage'), 'db_cmdset_storage', 'db_obj'), - 'description': 'To create a new Player, a User object must also be created and/or assigned. When deleting a Player, its connected User will also be deleted. A Character object is optional, but required for IC interactions in the game.', - 'classes' : ('wide', 'extrapretty')}),) - + 'classes' : ('wide', 'extrapretty')}),) # deactivated, they cause empty players to be created in admin. - #inlines = [PlayerAttributeInline] - + inlines = [PlayerAttributeInline] + add_form = PlayerCreateForm add_fieldsets = ( (None, {'fields' : (('db_key', 'db_typeclass_path'), 'user', 'db_permissions', 'db_cmdset_storage', 'db_obj'), - 'description': 'To create a new Player, a User object must also be created and/or assigned. When deleting a Player, its connected User will also be deleted. A Character object is optional, but required for IC interactions in the game.', - 'classes' : ('wide', 'extrapretty')}),) + 'description': 'To create a new Player, a User object must also be created to match. Never connect a Player to a User already assigned to another Player. When deleting a Player, its connected User will also be deleted.', + 'classes' : ('wide', 'extrapretty')}),) def get_fieldsets(self, request, obj=None): if not obj: diff --git a/src/players/models.py b/src/players/models.py index 7bcf1966e2..088a8242fa 100644 --- a/src/players/models.py +++ b/src/players/models.py @@ -148,7 +148,7 @@ 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, - help_text="The User object holds django-related authentication. Each Player must have a unique User account linked to them at all times.") + 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.") # the in-game object connected to this player (if any). # Use the property 'obj' to access. db_obj = models.ForeignKey("objects.ObjectDB", null=True, verbose_name="character", help_text='In-game object.')