Fixed User/Player creation in Admin, much more intuitive now. Remains issues with creating attributes since these need to be pickled to/from the database in order to be properly handled.
This commit is contained in:
parent
ce0e3c4857
commit
a60cd9bf1f
9 changed files with 420 additions and 185 deletions
|
|
@ -6,52 +6,55 @@
|
||||||
from django import forms
|
from django import forms
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.contrib import admin
|
from django.contrib import admin
|
||||||
from src.objects.models import ObjAttribute, ObjectDB
|
from src.objects.models import ObjAttribute, ObjectDB, ObjectNick, Alias
|
||||||
from src.utils.utils import mod_import
|
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 ObjAttributeInline(admin.TabularInline):
|
class ObjAttributeInline(admin.TabularInline):
|
||||||
model = ObjAttribute
|
model = ObjAttribute
|
||||||
fields = ('db_key', 'db_value')
|
fields = ('db_key', 'db_value')
|
||||||
extra = 0
|
extra = 0
|
||||||
|
|
||||||
class ObjectEditForm(forms.ModelForm):
|
class NickInline(admin.TabularInline):
|
||||||
"This form details the look of the fields"
|
model = ObjectNick
|
||||||
class Meta:
|
fields = ('db_nick', 'db_real', 'db_type')
|
||||||
model = ObjectDB
|
extra = 0
|
||||||
db_typeclass_path = forms.CharField(label="Typeclass",
|
|
||||||
initial=settings.BASE_OBJECT_TYPECLASS,
|
class AliasInline(admin.TabularInline):
|
||||||
widget=forms.TextInput(attrs={'size':'78'}),
|
model = Alias
|
||||||
help_text="this defines what 'type' of entity this is. This variable holds a Python path to a module with a valid Evennia Typeclass.")
|
fields = ("db_key",)
|
||||||
db_permissions = forms.CharField(label="Permissions",
|
extra = 0
|
||||||
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):
|
class ObjectCreateForm(forms.ModelForm):
|
||||||
"This form details the look of the fields"
|
"This form details the look of the fields"
|
||||||
class Meta:
|
class Meta:
|
||||||
model = ObjectDB
|
model = ObjectDB
|
||||||
fields = ('db_key',)
|
db_key = forms.CharField(label="Name/Key",
|
||||||
db_typeclass_path = forms.CharField(label="Typeclass",initial=settings.BASE_OBJECT_TYPECLASS,
|
|
||||||
widget=forms.TextInput(attrs={'size':'78'}),
|
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.")
|
help_text="Main identifier, like 'apple', 'strong guy', 'Elizabeth' etc. If creating a Character, check so the name is unique among characters!",)
|
||||||
db_permissions = forms.CharField(label="Permissions", initial=settings.PERMISSION_PLAYER_DEFAULT, required=False,
|
db_typeclass_path = forms.CharField(label="Typeclass",initial="Change to (for example) %s or %s." % (settings.BASE_OBJECT_TYPECLASS, settings.BASE_CHARACTER_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. If you are creating a Character you should use the typeclass defined by settings.BASE_CHARACTER_TYPECLASS or one derived from that.")
|
||||||
|
db_permissions = forms.CharField(label="Permissions",
|
||||||
|
initial=settings.PERMISSION_PLAYER_DEFAULT,
|
||||||
|
required=False,
|
||||||
widget=forms.TextInput(attrs={'size':'78'}),
|
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.")
|
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_cmdset_storage = forms.CharField(label="CmdSet",
|
||||||
|
initial=settings.CMDSET_DEFAULT,
|
||||||
|
required=False,
|
||||||
|
widget=forms.TextInput(attrs={'size':'78'}),
|
||||||
|
help_text="Most non-character objects don't need a cmdset and can leave this field blank.")
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class ObjectEditForm(ObjectCreateForm):
|
||||||
|
"Form used for editing. Extends the create one with more fields"
|
||||||
|
|
||||||
|
db_lock_storage = forms.CharField(label="Locks",
|
||||||
|
required=False,
|
||||||
|
widget=forms.Textarea(attrs={'cols':'100', 'rows':'2'}),
|
||||||
|
help_text="In-game lock definition string. If not given, defaults will be used. This string should be on the form <i>type:lockfunction(args);type2:lockfunction2(args);...")
|
||||||
|
|
||||||
|
|
||||||
class ObjectDBAdmin(admin.ModelAdmin):
|
class ObjectDBAdmin(admin.ModelAdmin):
|
||||||
|
|
@ -77,7 +80,7 @@ class ObjectDBAdmin(admin.ModelAdmin):
|
||||||
)
|
)
|
||||||
|
|
||||||
#deactivated temporarily, they cause empty objects to be created in admin
|
#deactivated temporarily, they cause empty objects to be created in admin
|
||||||
inlines = [ObjAttributeInline]
|
inlines = [AliasInline, ObjAttributeInline]
|
||||||
|
|
||||||
|
|
||||||
# Custom modification to give two different forms wether adding or not.
|
# Custom modification to give two different forms wether adding or not.
|
||||||
|
|
|
||||||
|
|
@ -12,19 +12,19 @@ from django.contrib.admin import widgets
|
||||||
from django.contrib.auth.forms import UserChangeForm, UserCreationForm
|
from django.contrib.auth.forms import UserChangeForm, UserCreationForm
|
||||||
from django.contrib.auth.models import User
|
from django.contrib.auth.models import User
|
||||||
from src.players.models import PlayerDB, PlayerAttribute
|
from src.players.models import PlayerDB, PlayerAttribute
|
||||||
|
from src.utils import logger, create
|
||||||
|
|
||||||
# remove User itself from admin site
|
# remove User itself from admin site
|
||||||
admin.site.unregister(User)
|
admin.site.unregister(User)
|
||||||
|
|
||||||
# handle the custom User editor
|
# handle the custom User editor
|
||||||
|
|
||||||
class CustomUserChangeForm(UserChangeForm):
|
class CustomUserChangeForm(UserChangeForm):
|
||||||
username = forms.RegexField(label="Username",
|
username = forms.RegexField(label="Username",
|
||||||
max_length=30,
|
max_length=30,
|
||||||
regex=r'^[\w. @+-]+$',
|
regex=r'^[\w. @+-]+$',
|
||||||
widget=forms.TextInput(attrs={'size':'30'}),
|
widget=forms.TextInput(attrs={'size':'30'}),
|
||||||
error_messages = {'invalid': "This value may contain only letters, spaces, numbers and @/./+/-/_ characters."},
|
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.")
|
help_text = "30 characters or fewer. Letters, spaces, digits and @/./+/-/_ only.")
|
||||||
|
|
||||||
class CustomUserCreationForm(UserCreationForm):
|
class CustomUserCreationForm(UserCreationForm):
|
||||||
username = forms.RegexField(label="Username",
|
username = forms.RegexField(label="Username",
|
||||||
|
|
@ -32,166 +32,117 @@ class CustomUserCreationForm(UserCreationForm):
|
||||||
regex=r'^[\w. @+-]+$',
|
regex=r'^[\w. @+-]+$',
|
||||||
widget=forms.TextInput(attrs={'size':'30'}),
|
widget=forms.TextInput(attrs={'size':'30'}),
|
||||||
error_messages = {'invalid': "This value may contain only letters, spaces, numbers and @/./+/-/_ characters."},
|
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.")
|
help_text = "30 characters or fewer. Letters, spaces, digits and @/./+/-/_ only.")
|
||||||
|
|
||||||
|
# # 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'}))
|
||||||
|
|
||||||
class UserAdmin(BaseUserAdmin):
|
# class PlayerAttributeInline(admin.TabularInline):
|
||||||
"This will pop up from the Player admin."
|
# "Inline creation of player attributes"
|
||||||
|
# model = PlayerAttribute
|
||||||
|
# extra = 0
|
||||||
|
# form = PlayerAttributeForm
|
||||||
|
# fieldsets = (
|
||||||
|
# (None, {'fields' : (('db_key', 'db_value'))}),)
|
||||||
|
|
||||||
list_display = ('username', 'email', 'is_staff', 'is_superuser')
|
class PlayerForm(forms.ModelForm):
|
||||||
form = CustomUserChangeForm
|
"Defines how to display Players"
|
||||||
add_form = CustomUserCreationForm
|
|
||||||
add_fieldsets = (
|
|
||||||
(None,
|
|
||||||
{'fields': ('username', 'email', 'password1', 'password2', ('is_staff', 'is_superuser')),
|
|
||||||
'description':"The <i>User</i> object holds all authentication information and bits for using the admin site. A <i>superuser</i> account represents a 'God user' in-game. This User account should have the same username as its corresponding <i>Player</i> 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'}))
|
|
||||||
|
|
||||||
class PlayerAttributeInline(admin.TabularInline):
|
|
||||||
"Inline creation of player attributes"
|
|
||||||
model = PlayerAttribute
|
|
||||||
extra = 0
|
|
||||||
form = PlayerAttributeForm
|
|
||||||
fieldsets = (
|
|
||||||
(None, {'fields' : (('db_key', 'db_value'))}),)
|
|
||||||
|
|
||||||
class PlayerEditForm(forms.ModelForm):
|
|
||||||
"This form details the look of the fields"
|
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
# important! This allows us to not excplicitly add all fields.
|
|
||||||
model = PlayerDB
|
model = PlayerDB
|
||||||
|
|
||||||
db_key = forms.RegexField(label="Username",
|
db_key = forms.RegexField(label="Username",
|
||||||
max_length=30, regex=r'^[\w. @+-]+$',
|
initial="PlayerDummy",
|
||||||
|
max_length=30,
|
||||||
|
regex=r'^[\w. @+-]+$',
|
||||||
|
required=False,
|
||||||
widget=forms.TextInput(attrs={'size':'30'}),
|
widget=forms.TextInput(attrs={'size':'30'}),
|
||||||
error_messages = {'invalid': "This value may contain only letters, spaces, numbers and @/./+/-/_ characters."},
|
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.")
|
help_text = "This should be the same as the connected Player's key name. 30 characters or fewer. Letters, spaces, digits and @/./+/-/_ only.")
|
||||||
|
|
||||||
db_typeclass_path = forms.CharField(label="Typeclass",
|
db_typeclass_path = forms.CharField(label="Typeclass",
|
||||||
initial=settings.BASE_PLAYER_TYPECLASS,
|
initial=settings.BASE_PLAYER_TYPECLASS,
|
||||||
widget=forms.TextInput(attrs={'size':'78'}),
|
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.")
|
help_text="Required. Defines what 'type' of entity this is. This variable holds a Python path to a module with a valid Evennia Typeclass. Defaults to settings.BASE_PLAYER_TYPECLASS.")
|
||||||
db_permissions = forms.CharField(label="Permissions",
|
db_permissions = forms.CharField(label="Permissions",
|
||||||
initial=settings.PERMISSION_PLAYER_DEFAULT,
|
initial=settings.PERMISSION_PLAYER_DEFAULT,
|
||||||
required=False,
|
required=False,
|
||||||
widget=forms.TextInput(attrs={'size':'78'}),
|
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.")
|
help_text="In-game permissions. 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",
|
db_lock_storage = forms.CharField(label="Locks",
|
||||||
widget=forms.Textarea(attrs={'cols':'100', 'rows':'2'}),
|
widget=forms.Textarea(attrs={'cols':'100', 'rows':'2'}),
|
||||||
required=False,
|
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.")
|
help_text="In-game lock definition string. If not given, defaults will be used. This string should be on the form <i>type:lockfunction(args);type2:lockfunction2(args);...")
|
||||||
db_cmdset_storage = forms.CharField(label="cmdset",
|
db_cmdset_storage = forms.CharField(label="cmdset",
|
||||||
initial=settings.CMDSET_OOC,
|
initial=settings.CMDSET_OOC,
|
||||||
widget=forms.TextInput(attrs={'size':'78'}),
|
widget=forms.TextInput(attrs={'size':'78'}),
|
||||||
required=False,
|
required=False,
|
||||||
help_text="python path to cmdset class.")
|
help_text="python path to player cmdset class (settings.CMDSET_OOC by default)")
|
||||||
user = forms.ModelChoiceField(queryset=User.objects.all(),
|
|
||||||
widget=forms.Select(attrs={'disabled':'true'}))
|
|
||||||
|
|
||||||
|
class PlayerInline(admin.StackedInline):
|
||||||
|
"Inline creation of Player"
|
||||||
class PlayerCreateForm(forms.ModelForm):
|
|
||||||
"This form details the look of the fields"
|
|
||||||
|
|
||||||
class Meta:
|
|
||||||
# important! This allows us to not excplicitly add all fields.
|
|
||||||
model = PlayerDB
|
model = PlayerDB
|
||||||
|
template = "admin/players/stacked.html"
|
||||||
db_key = forms.RegexField(label="Username", max_length=30, regex=r'^[\w. @+-]+$', widget=forms.TextInput(attrs={'size':'30'}),
|
form = PlayerForm
|
||||||
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'}),
|
|
||||||
required=False,
|
|
||||||
help_text="python path to cmdset class.")
|
|
||||||
|
|
||||||
class PlayerDBAdmin(admin.ModelAdmin):
|
|
||||||
"Setting up and tying the player administration together"
|
|
||||||
|
|
||||||
list_display = ('id', 'db_key', 'user', 'db_obj', 'db_permissions', 'db_typeclass_path')
|
|
||||||
list_display_links = ('id', 'db_key')
|
|
||||||
ordering = ['db_key', 'db_typeclass_path']
|
|
||||||
search_fields = ['^db_key', 'db_typeclass_path']
|
|
||||||
save_as = True
|
|
||||||
save_on_top = True
|
|
||||||
list_select_related = True
|
|
||||||
list_filter = ('db_permissions',)
|
|
||||||
|
|
||||||
|
|
||||||
# editing/adding player
|
|
||||||
form = PlayerEditForm
|
|
||||||
fieldsets = (
|
fieldsets = (
|
||||||
(None,
|
("In-game Permissions and Locks",
|
||||||
{'fields' : (('db_key', 'db_typeclass_path'), 'user', ('db_permissions','db_lock_storage'), 'db_cmdset_storage', 'db_obj'),
|
{'fields': ('db_permissions', 'db_lock_storage'),
|
||||||
'classes' : ('wide', 'extrapretty')}),)
|
'description':"<i>These are permissions/locks for in-game use. They are unrelated to website access rights.</i>"}),
|
||||||
# deactivated, they cause empty players to be created in admin.
|
("In-game Player data",
|
||||||
inlines = [PlayerAttributeInline]
|
{'fields':('db_typeclass_path', 'db_cmdset_storage'),
|
||||||
|
'description':"<i>These fields define in-game-specific properties for the Player object in-game.</i>"}),
|
||||||
|
("Evennia In-game Character",
|
||||||
|
{'fields':('db_obj',),
|
||||||
|
'description': "<i>To actually play the game, a Player must control a Character. This could be added in-game instead of from here if some sort of character creation system is in play. If not, you should normally create a new Character here rather than assigning an existing one. Observe that the admin does not check for puppet-access rights when assigning Characters! If not creating a new Character, make sure the one you assign is not puppeted by someone else!</i>"}))
|
||||||
|
|
||||||
|
|
||||||
|
extra = 1
|
||||||
|
max_num = 1
|
||||||
|
|
||||||
|
class UserAdmin(BaseUserAdmin):
|
||||||
|
"This is the main creation screen for Users/players"
|
||||||
|
|
||||||
|
list_display = ('username','email', 'is_staff', 'is_superuser')
|
||||||
|
form = CustomUserChangeForm
|
||||||
|
add_form = CustomUserCreationForm
|
||||||
|
inlines = [PlayerInline]
|
||||||
|
add_form_template = "admin/players/add_form.html"
|
||||||
|
change_form_template = "admin/players/change_form.html"
|
||||||
|
change_list_template = "admin/players/change_list.html"
|
||||||
|
fieldsets = (
|
||||||
|
(None, {'fields': ('username', 'password', 'email')}),
|
||||||
|
('Website profile', {'fields': ('first_name', 'last_name'),
|
||||||
|
'description':"<i>These are not used in the default system.</i>"}),
|
||||||
|
('Website dates', {'fields': ('last_login', 'date_joined'),
|
||||||
|
'description':'<i>Relevant only to the website.</i>'}),
|
||||||
|
('Website Permissions', {'fields': ('is_active', 'is_staff', 'is_superuser', 'user_permissions','groups'),
|
||||||
|
'description': "<i>These are permissions/permission groups for accessing the admin site. They are unrelated to in-game access rights.</i>"}),)
|
||||||
|
|
||||||
|
|
||||||
add_form = PlayerCreateForm
|
|
||||||
add_fieldsets = (
|
add_fieldsets = (
|
||||||
(None,
|
(None,
|
||||||
{'fields' : (('db_key', 'db_typeclass_path'), 'user', 'db_permissions', 'db_cmdset_storage', 'db_obj'),
|
{'fields': ('username', 'password1', 'password2', 'email'),
|
||||||
'description': 'To create a new Player, a User object <i>must</i> 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.',
|
'description':"<i>These account details are shared by the admin system and the game.</i>"},),)
|
||||||
'classes' : ('wide', 'extrapretty')}),)
|
|
||||||
|
|
||||||
def get_fieldsets(self, request, obj=None):
|
def save_formset(self, request, form, formset, change):
|
||||||
if not obj:
|
"Run all hooks on the player object"
|
||||||
return self.add_fieldsets
|
super(UserAdmin, self).save_formset(request, form, formset, change)
|
||||||
return super(PlayerDBAdmin, self).get_fieldsets(request, obj)
|
playerdb = form.instance.get_profile()
|
||||||
|
|
||||||
def get_form(self, request, obj=None, **kwargs):
|
|
||||||
"""
|
|
||||||
Use special form during creation
|
|
||||||
"""
|
|
||||||
defaults = {}
|
|
||||||
if obj is None:
|
|
||||||
defaults.update({
|
|
||||||
'form': self.add_form,
|
|
||||||
'fields': admin.util.flatten_fieldsets(self.add_fieldsets),
|
|
||||||
})
|
|
||||||
defaults.update(kwargs)
|
|
||||||
return super(PlayerDBAdmin, self).get_form(request, obj, **defaults)
|
|
||||||
|
|
||||||
def save_model(self, request, obj, form, change):
|
|
||||||
if not change:
|
if not change:
|
||||||
# adding a new object
|
create.create_player("", "", "",
|
||||||
new_obj = obj.typeclass
|
typeclass=playerdb.db_typeclass_path,
|
||||||
new_obj.basetype_setup()
|
create_character=False,
|
||||||
new_obj.at_player_creation()
|
player_dbobj=playerdb)
|
||||||
if new_obj.obj:
|
if playerdb.db_obj:
|
||||||
char = new_obj.db_obj
|
playerdb.db_obj.db_player = playerdb
|
||||||
char.db_player = obj
|
playerdb.db_obj.save()
|
||||||
char.save()
|
|
||||||
new_obj.at_init()
|
|
||||||
else:
|
|
||||||
if obj.db_obj:
|
|
||||||
char = obj.db_obj
|
|
||||||
char.db_player = obj
|
|
||||||
char.save()
|
|
||||||
|
|
||||||
obj.at_init()
|
#assert False, (form.instance, form.instance.get_profile())
|
||||||
|
|
||||||
def delete_model(self, request, obj):
|
admin.site.register(User, UserAdmin)
|
||||||
# called when deleting a player object. Makes sure to also delete user.
|
|
||||||
user = obj.user
|
|
||||||
user.delete()
|
|
||||||
|
|
||||||
admin.site.register(PlayerDB, PlayerDBAdmin)
|
|
||||||
|
|
|
||||||
|
|
@ -151,11 +151,11 @@ class PlayerDB(TypedObject):
|
||||||
help_text="The <I>User</I> 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.")
|
help_text="The <I>User</I> 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).
|
# the in-game object connected to this player (if any).
|
||||||
# Use the property 'obj' to access.
|
# Use the property 'obj' to access.
|
||||||
db_obj = models.ForeignKey("objects.ObjectDB", null=True, verbose_name="character", help_text='In-game object.')
|
db_obj = models.ForeignKey("objects.ObjectDB", null=True, blank=True, verbose_name="character", help_text='In-game object.')
|
||||||
|
|
||||||
# database storage of persistant cmdsets.
|
# database storage of persistant cmdsets.
|
||||||
db_cmdset_storage = models.CharField('cmdset', max_length=255, null=True,
|
db_cmdset_storage = models.CharField('cmdset', max_length=255, null=True,
|
||||||
help_text="optional python path to a cmdset class.")
|
help_text="optional python path to a cmdset class. If creating a Character, this will default to settings.CMDSET_DEFAULT.")
|
||||||
|
|
||||||
# Database manager
|
# Database manager
|
||||||
objects = manager.PlayerManager()
|
objects = manager.PlayerManager()
|
||||||
|
|
|
||||||
|
|
@ -351,13 +351,19 @@ def create_player(name, email, password,
|
||||||
is_superuser=False,
|
is_superuser=False,
|
||||||
locks=None, permissions=None,
|
locks=None, permissions=None,
|
||||||
create_character=True, character_typeclass=None,
|
create_character=True, character_typeclass=None,
|
||||||
character_location=None, character_home=None):
|
character_location=None, character_home=None,
|
||||||
|
player_dbobj=None):
|
||||||
|
|
||||||
|
|
||||||
"""
|
"""
|
||||||
This creates a new player, handling the creation of the User
|
This creates a new player, handling the creation of the User
|
||||||
object and its associated Player object.
|
object and its associated Player object.
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
If create_character is
|
If create_character is
|
||||||
True, a game player object with the same name as the User/Player will
|
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.
|
also be created. Its typeclass and base properties can also be given.
|
||||||
|
|
@ -414,6 +420,9 @@ def create_player(name, email, password,
|
||||||
# this is already an object typeclass, extract its path
|
# this is already an object typeclass, extract its path
|
||||||
typeclass = typeclass.path
|
typeclass = typeclass.path
|
||||||
|
|
||||||
|
if player_dbobj:
|
||||||
|
new_db_player = player_dbobj
|
||||||
|
else:
|
||||||
# create new database object
|
# create new database object
|
||||||
new_db_player = PlayerDB(db_key=name, user=new_user)
|
new_db_player = PlayerDB(db_key=name, user=new_user)
|
||||||
new_db_player.save()
|
new_db_player.save()
|
||||||
|
|
|
||||||
|
|
@ -20,10 +20,9 @@
|
||||||
|
|
||||||
{% if app.name == 'Auth' %}
|
{% if app.name == 'Auth' %}
|
||||||
<h2>Admin</h2>
|
<h2>Admin</h2>
|
||||||
<p><i>Note: Users hold django-specific authentication and should
|
<p><i>Players are the out-of-character representation of a
|
||||||
not be created stand-alone. Groups
|
game account. A Player can potentially control any number of
|
||||||
define permissions only relevant to admin-site access.
|
in-game character Objects (depending on game).</i></p>
|
||||||
To create a new In-game user, create a new <b>Player</b></i>.</p>
|
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
<div class="module">
|
<div class="module">
|
||||||
|
|
@ -31,10 +30,11 @@
|
||||||
<caption><a href="{{ app.app_url }}" class="section">{% blocktrans with app.name as name %}{{ name }}{% endblocktrans %}</a></caption>
|
<caption><a href="{{ app.app_url }}" class="section">{% blocktrans with app.name as name %}{{ name }}{% endblocktrans %}</a></caption>
|
||||||
{% for model in app.models %}
|
{% for model in app.models %}
|
||||||
<tr>
|
<tr>
|
||||||
|
{% if model.name == "Users" %}
|
||||||
{% if model.perms.change %}
|
{% if model.perms.change %}
|
||||||
<th scope="row"><a href="{{ model.admin_url }}">{{ model.name }}</a></th>
|
<th scope="row"><a href="{{ model.admin_url }}">Player</a></th>
|
||||||
{% else %}
|
{% else %}
|
||||||
<th scope="row">{{ model.name }}</th>
|
<th scope="row">Player</th>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
{% if model.perms.add %}
|
{% if model.perms.add %}
|
||||||
|
|
@ -49,6 +49,7 @@
|
||||||
<td> </td>
|
<td> </td>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</tr>
|
</tr>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</table>
|
</table>
|
||||||
|
|
|
||||||
14
src/web/templates/admin/players/add_form.html
Normal file
14
src/web/templates/admin/players/add_form.html
Normal file
|
|
@ -0,0 +1,14 @@
|
||||||
|
{% extends "admin/players/change_form.html" %}
|
||||||
|
{% load i18n %}
|
||||||
|
|
||||||
|
{% block form_top %}
|
||||||
|
{% if not is_popup %}
|
||||||
|
<p>{% trans "First, enter a username and password. Then you'll be able to edit more Player options." %}</p>
|
||||||
|
{% else %}
|
||||||
|
<p>{% trans "Enter a username and password." %}</p>
|
||||||
|
{% endif %}
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block after_field_sets %}
|
||||||
|
<script type="text/javascript">document.getElementById("id_username").focus();</script>
|
||||||
|
{% endblock %}
|
||||||
71
src/web/templates/admin/players/change_form.html
Normal file
71
src/web/templates/admin/players/change_form.html
Normal file
|
|
@ -0,0 +1,71 @@
|
||||||
|
{% extends "admin/base_site.html" %}
|
||||||
|
{% load i18n admin_modify adminmedia %}
|
||||||
|
{% load url from future %}
|
||||||
|
|
||||||
|
{% block extrahead %}{{ block.super }}
|
||||||
|
{% url 'admin:jsi18n' as jsi18nurl %}
|
||||||
|
<script type="text/javascript" src="{{ jsi18nurl|default:"../../../jsi18n/" }}"></script>
|
||||||
|
{{ media }}
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block extrastyle %}{{ block.super }}<link rel="stylesheet" type="text/css" href="{% admin_media_prefix %}css/forms.css" />{% endblock %}
|
||||||
|
|
||||||
|
{% block coltype %}{% if ordered_objects %}colMS{% else %}colM{% endif %}{% endblock %}
|
||||||
|
|
||||||
|
{% block bodyclass %}{{ opts.app_label }}-{{ opts.object_name.lower }}
|
||||||
|
change-form{% endblock %}
|
||||||
|
|
||||||
|
{% block breadcrumbs %}{% if not is_popup %}
|
||||||
|
<div class="breadcrumbs">
|
||||||
|
<a href="../../../">{% trans "Home" %}</a> ›
|
||||||
|
<a href="../../">{{ app_label|capfirst|escape }}</a> ›
|
||||||
|
{% if has_change_permission %}<a href="../">{{ opts.verbose_name_plural|capfirst }}</a>{% else %}{{ opts.verbose_name_plural|capfirst }}{% endif %} ›
|
||||||
|
{% if add %}{% trans "Add" %} {{ opts.verbose_name }}{% else %}{{ original|truncatewords:"18" }}{% endif %}
|
||||||
|
</div>
|
||||||
|
{% endif %}{% endblock %}
|
||||||
|
{% block content %}<div id="content-main">
|
||||||
|
{% block object-tools %}
|
||||||
|
{% if change %}{% if not is_popup %}
|
||||||
|
<ul class="object-tools">
|
||||||
|
{% block object-tools-items %}
|
||||||
|
<li><a href="history/" class="historylink">{% trans "History" %}</a></li>
|
||||||
|
{% if has_absolute_url %}<li><a href="../../../r/{{ content_type_id }}/{{ object_id }}/" class="viewsitelink">{% trans "View on site" %}</a></li>{% endif%}
|
||||||
|
{% endblock %}
|
||||||
|
</ul>
|
||||||
|
{% endif %}{% endif %}
|
||||||
|
{% endblock %}
|
||||||
|
<form {% if has_file_field %}enctype="multipart/form-data" {% endif %}action="{{ form_url }}" method="post" id="{{ opts.module_name }}_form">{% csrf_token %}{% block form_top %}{% endblock %}
|
||||||
|
<div>
|
||||||
|
{% if is_popup %}<input type="hidden" name="_popup" value="1" />{% endif %}
|
||||||
|
{% if save_on_top %}{% submit_row %}{% endif %}
|
||||||
|
{% if errors %}
|
||||||
|
<p class="errornote">
|
||||||
|
{% blocktrans count errors|length as counter %}Please correct the error below.{% plural %}Please correct the errors below.{% endblocktrans %}
|
||||||
|
</p>
|
||||||
|
{{ adminform.form.non_field_errors }}
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% for fieldset in adminform %}
|
||||||
|
{% include "admin/includes/fieldset.html" %}
|
||||||
|
{% endfor %}
|
||||||
|
|
||||||
|
{% block after_field_sets %}{% endblock %}
|
||||||
|
|
||||||
|
{% for inline_admin_formset in inline_admin_formsets %}
|
||||||
|
{% include inline_admin_formset.opts.template %}
|
||||||
|
{% endfor %}
|
||||||
|
|
||||||
|
{% block after_related_objects %}{% endblock %}
|
||||||
|
|
||||||
|
{% submit_row %}
|
||||||
|
|
||||||
|
{% if adminform and add %}
|
||||||
|
<script type="text/javascript">document.getElementById("{{ adminform.first_field.id_for_label }}").focus();</script>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{# JavaScript for prepopulated fields #}
|
||||||
|
{% prepopulated_fields_js %}
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</form></div>
|
||||||
|
{% endblock %}
|
||||||
104
src/web/templates/admin/players/change_list.html
Normal file
104
src/web/templates/admin/players/change_list.html
Normal file
|
|
@ -0,0 +1,104 @@
|
||||||
|
{% extends "admin/base_site.html" %}
|
||||||
|
{% load adminmedia admin_list i18n %}
|
||||||
|
{% load url from future %}
|
||||||
|
{% block extrastyle %}
|
||||||
|
{{ block.super }}
|
||||||
|
<link rel="stylesheet" type="text/css" href="{% admin_media_prefix %}css/changelists.css" />
|
||||||
|
{% if cl.formset %}
|
||||||
|
<link rel="stylesheet" type="text/css" href="{% admin_media_prefix %}css/forms.css" />
|
||||||
|
{% endif %}
|
||||||
|
{% if cl.formset or action_form %}
|
||||||
|
{% url 'admin:jsi18n' as jsi18nurl %}
|
||||||
|
<script type="text/javascript" src="{{ jsi18nurl|default:'../../jsi18n/' }}"></script>
|
||||||
|
{% endif %}
|
||||||
|
{{ media.css }}
|
||||||
|
{% if not actions_on_top and not actions_on_bottom %}
|
||||||
|
<style>
|
||||||
|
#changelist table thead th:first-child {width: inherit}
|
||||||
|
</style>
|
||||||
|
{% endif %}
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block extrahead %}
|
||||||
|
{{ block.super }}
|
||||||
|
{{ media.js }}
|
||||||
|
{% if action_form %}{% if actions_on_top or actions_on_bottom %}
|
||||||
|
<script type="text/javascript">
|
||||||
|
(function($) {
|
||||||
|
$(document).ready(function($) {
|
||||||
|
$("tr input.action-select").actions();
|
||||||
|
});
|
||||||
|
})(django.jQuery);
|
||||||
|
</script>
|
||||||
|
{% endif %}{% endif %}
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block bodyclass %}change-list{% endblock %}
|
||||||
|
|
||||||
|
{% if not is_popup %}
|
||||||
|
{% block breadcrumbs %}
|
||||||
|
<div class="breadcrumbs">
|
||||||
|
<a href="../../">
|
||||||
|
{% trans "Home" %}
|
||||||
|
</a>
|
||||||
|
›
|
||||||
|
<a href="../">
|
||||||
|
{{ app_label|capfirst }}
|
||||||
|
</a>
|
||||||
|
›
|
||||||
|
{{ cl.opts.verbose_name_plural|capfirst }}
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% block coltype %}flex{% endblock %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<div id="content-main">
|
||||||
|
{% block object-tools %}
|
||||||
|
{% if has_add_permission %}
|
||||||
|
<ul class="object-tools">
|
||||||
|
{% block object-tools-items %}
|
||||||
|
<li>
|
||||||
|
<a href="add/{% if is_popup %}?_popup=1{% endif %}" class="addlink">
|
||||||
|
{% blocktrans with cl.opts.verbose_name as name %}Add {{ name }}{% endblocktrans %}
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
{% endblock %}
|
||||||
|
</ul>
|
||||||
|
{% endif %}
|
||||||
|
{% endblock %}
|
||||||
|
{% if cl.formset.errors %}
|
||||||
|
<p class="errornote">
|
||||||
|
{% blocktrans count cl.formset.errors|length as counter %}Please correct the error below.{% plural %}Please correct the errors below.{% endblocktrans %}
|
||||||
|
</p>
|
||||||
|
{{ cl.formset.non_form_errors }}
|
||||||
|
{% endif %}
|
||||||
|
<div class="module{% if cl.has_filters %} filtered{% endif %}" id="changelist">
|
||||||
|
{% block search %}{% search_form cl %}{% endblock %}
|
||||||
|
{% block date_hierarchy %}{% date_hierarchy cl %}{% endblock %}
|
||||||
|
|
||||||
|
{% block filters %}
|
||||||
|
{% if cl.has_filters %}
|
||||||
|
<div id="changelist-filter">
|
||||||
|
<h2>{% trans 'Filter' %}</h2>
|
||||||
|
{% for spec in cl.filter_specs %}{% admin_list_filter cl spec %}{% endfor %}
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
<form id="changelist-form" action="" method="post"{% if cl.formset.is_multipart %} enctype="multipart/form-data"{% endif %}>{% csrf_token %}
|
||||||
|
{% if cl.formset %}
|
||||||
|
<div>{{ cl.formset.management_form }}</div>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% block result_list %}
|
||||||
|
{% if action_form and actions_on_top and cl.full_result_count %}{% admin_actions %}{% endif %}
|
||||||
|
{% result_list cl %}
|
||||||
|
{% if action_form and actions_on_bottom and cl.full_result_count %}{% admin_actions %}{% endif %}
|
||||||
|
{% endblock %}
|
||||||
|
{% block pagination %}{% pagination cl %}{% endblock %}
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
||||||
82
src/web/templates/admin/players/stacked.html
Normal file
82
src/web/templates/admin/players/stacked.html
Normal file
|
|
@ -0,0 +1,82 @@
|
||||||
|
{% load i18n adminmedia %}
|
||||||
|
<div class="inline-group" id="{{ inline_admin_formset.formset.prefix }}-group">
|
||||||
|
<!--h2>{{ inline_admin_formset.opts.verbose_name_plural|title }}</h2-->
|
||||||
|
{{ inline_admin_formset.formset.management_form }}
|
||||||
|
{{ inline_admin_formset.formset.non_form_errors }}
|
||||||
|
|
||||||
|
{% for inline_admin_form in inline_admin_formset %}<div class="inline-related{% if forloop.last %} empty-form last-related{% endif %}" id="{{ inline_admin_formset.formset.prefix }}-{% if not forloop.last %}{{ forloop.counter0 }}{% else %}empty{% endif %}">
|
||||||
|
<!--h3><b>{{ inline_admin_formset.opts.verbose_name|title }}:</b> <span class="inline_label">{% if inline_admin_form.original %}{{ inline_admin_form.original }}{% else %}#{{ forloop.counter }}{% endif %}</span>
|
||||||
|
{% if inline_admin_form.show_url %}<a href="../../../r/{{ inline_admin_form.original_content_type_id }}/{{ inline_admin_form.original.id }}/">{% trans "View on site" %}</a>{% endif %}
|
||||||
|
{% if inline_admin_formset.formset.can_delete and inline_admin_form.original %}<span class="delete">{{ inline_admin_form.deletion_field.field }} {{ inline_admin_form.deletion_field.label_tag }}</span>{% endif %}
|
||||||
|
</h3-->
|
||||||
|
{% if inline_admin_form.form.non_field_errors %}{{ inline_admin_form.form.non_field_errors }}{% endif %}
|
||||||
|
{% for fieldset in inline_admin_form %}
|
||||||
|
{% include "admin/includes/fieldset.html" %}
|
||||||
|
{% endfor %}
|
||||||
|
{% if inline_admin_form.has_auto_field %}{{ inline_admin_form.pk_field.field }}{% endif %}
|
||||||
|
{{ inline_admin_form.fk_field.field }}
|
||||||
|
</div>{% endfor %}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script type="text/javascript">
|
||||||
|
(function($) {
|
||||||
|
$(document).ready(function() {
|
||||||
|
var rows = "#{{ inline_admin_formset.formset.prefix }}-group .inline-related";
|
||||||
|
var updateInlineLabel = function(row) {
|
||||||
|
$(rows).find(".inline_label").each(function(i) {
|
||||||
|
var count = i + 1;
|
||||||
|
$(this).html($(this).html().replace(/(#\d+)/g, "#" + count));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
var reinitDateTimeShortCuts = function() {
|
||||||
|
// Reinitialize the calendar and clock widgets by force, yuck.
|
||||||
|
if (typeof DateTimeShortcuts != "undefined") {
|
||||||
|
$(".datetimeshortcuts").remove();
|
||||||
|
DateTimeShortcuts.init();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var updateSelectFilter = function() {
|
||||||
|
// If any SelectFilter widgets were added, instantiate a new instance.
|
||||||
|
if (typeof SelectFilter != "undefined"){
|
||||||
|
$(".selectfilter").each(function(index, value){
|
||||||
|
var namearr = value.name.split('-');
|
||||||
|
SelectFilter.init(value.id, namearr[namearr.length-1], false, "{% admin_media_prefix %}");
|
||||||
|
});
|
||||||
|
$(".selectfilterstacked").each(function(index, value){
|
||||||
|
var namearr = value.name.split('-');
|
||||||
|
SelectFilter.init(value.id, namearr[namearr.length-1], true, "{% admin_media_prefix %}");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var initPrepopulatedFields = function(row) {
|
||||||
|
row.find('.prepopulated_field').each(function() {
|
||||||
|
var field = $(this);
|
||||||
|
var input = field.find('input, select, textarea');
|
||||||
|
var dependency_list = input.data('dependency_list') || [];
|
||||||
|
var dependencies = [];
|
||||||
|
$.each(dependency_list, function(i, field_name) {
|
||||||
|
dependencies.push('#' + row.find(field_name).find('input, select, textarea').attr('id'));
|
||||||
|
});
|
||||||
|
if (dependencies.length) {
|
||||||
|
input.prepopulate(dependencies, input.attr('maxlength'));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
$(rows).formset({
|
||||||
|
prefix: "{{ inline_admin_formset.formset.prefix }}",
|
||||||
|
addText: "{% blocktrans with inline_admin_formset.opts.verbose_name|title as verbose_name %}Add another {{ verbose_name }}{% endblocktrans %}",
|
||||||
|
formCssClass: "dynamic-{{ inline_admin_formset.formset.prefix }}",
|
||||||
|
deleteCssClass: "inline-deletelink",
|
||||||
|
deleteText: "{% trans "Remove" %}",
|
||||||
|
emptyCssClass: "empty-form",
|
||||||
|
removed: updateInlineLabel,
|
||||||
|
added: (function(row) {
|
||||||
|
initPrepopulatedFields(row);
|
||||||
|
reinitDateTimeShortCuts();
|
||||||
|
updateSelectFilter();
|
||||||
|
updateInlineLabel(row);
|
||||||
|
})
|
||||||
|
});
|
||||||
|
});
|
||||||
|
})(django.jQuery);
|
||||||
|
</script>
|
||||||
Loading…
Add table
Add a link
Reference in a new issue