mirror of
https://github.com/evennia/evennia.git
synced 2026-03-16 21:06:30 +01:00
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.conf import settings
|
||||
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
|
||||
|
||||
# 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 = 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,
|
||||
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 NickInline(admin.TabularInline):
|
||||
model = ObjectNick
|
||||
fields = ('db_nick', 'db_real', 'db_type')
|
||||
extra = 0
|
||||
|
||||
class AliasInline(admin.TabularInline):
|
||||
model = Alias
|
||||
fields = ("db_key",)
|
||||
extra = 0
|
||||
|
||||
class ObjectCreateForm(forms.ModelForm):
|
||||
"This form details the look of the fields"
|
||||
class Meta:
|
||||
model = ObjectDB
|
||||
fields = ('db_key',)
|
||||
db_typeclass_path = forms.CharField(label="Typeclass",initial=settings.BASE_OBJECT_TYPECLASS,
|
||||
db_key = forms.CharField(label="Name/Key",
|
||||
widget=forms.TextInput(attrs={'size':'78'}),
|
||||
help_text="Main identifier, like 'apple', 'strong guy', 'Elizabeth' etc. If creating a Character, check so the name is unique among characters!",)
|
||||
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.")
|
||||
db_permissions = forms.CharField(label="Permissions", initial=settings.PERMISSION_PLAYER_DEFAULT, required=False,
|
||||
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'}),
|
||||
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):
|
||||
|
|
@ -77,7 +80,7 @@ class ObjectDBAdmin(admin.ModelAdmin):
|
|||
)
|
||||
|
||||
#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.
|
||||
|
|
|
|||
|
|
@ -12,19 +12,19 @@ from django.contrib.admin import widgets
|
|||
from django.contrib.auth.forms import UserChangeForm, UserCreationForm
|
||||
from django.contrib.auth.models import User
|
||||
from src.players.models import PlayerDB, PlayerAttribute
|
||||
|
||||
from src.utils import logger, create
|
||||
|
||||
# remove User itself from admin site
|
||||
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'}),
|
||||
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):
|
||||
username = forms.RegexField(label="Username",
|
||||
|
|
@ -32,166 +32,117 @@ class CustomUserCreationForm(UserCreationForm):
|
|||
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.")
|
||||
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):
|
||||
"This will pop up from the Player admin."
|
||||
# class PlayerAttributeInline(admin.TabularInline):
|
||||
# "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')
|
||||
form = CustomUserChangeForm
|
||||
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 PlayerForm(forms.ModelForm):
|
||||
"Defines how to display Players"
|
||||
|
||||
class Meta:
|
||||
# important! This allows us to not excplicitly add all fields.
|
||||
model = PlayerDB
|
||||
|
||||
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'}),
|
||||
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.")
|
||||
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.")
|
||||
|
||||
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.")
|
||||
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",
|
||||
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.")
|
||||
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",
|
||||
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.")
|
||||
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",
|
||||
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"
|
||||
|
||||
class Meta:
|
||||
# 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_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
|
||||
help_text="python path to player cmdset class (settings.CMDSET_OOC by default)")
|
||||
|
||||
class PlayerInline(admin.StackedInline):
|
||||
"Inline creation of Player"
|
||||
model = PlayerDB
|
||||
template = "admin/players/stacked.html"
|
||||
form = PlayerForm
|
||||
fieldsets = (
|
||||
(None,
|
||||
{'fields' : (('db_key', 'db_typeclass_path'), 'user', ('db_permissions','db_lock_storage'), 'db_cmdset_storage', 'db_obj'),
|
||||
'classes' : ('wide', 'extrapretty')}),)
|
||||
# deactivated, they cause empty players to be created in admin.
|
||||
inlines = [PlayerAttributeInline]
|
||||
("In-game Permissions and Locks",
|
||||
{'fields': ('db_permissions', 'db_lock_storage'),
|
||||
'description':"<i>These are permissions/locks for in-game use. They are unrelated to website access rights.</i>"}),
|
||||
("In-game Player data",
|
||||
{'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>"}))
|
||||
|
||||
add_form = PlayerCreateForm
|
||||
|
||||
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_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 <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.',
|
||||
'classes' : ('wide', 'extrapretty')}),)
|
||||
(None,
|
||||
{'fields': ('username', 'password1', 'password2', 'email'),
|
||||
'description':"<i>These account details are shared by the admin system and the game.</i>"},),)
|
||||
|
||||
def get_fieldsets(self, request, obj=None):
|
||||
if not obj:
|
||||
return self.add_fieldsets
|
||||
return super(PlayerDBAdmin, self).get_fieldsets(request, obj)
|
||||
|
||||
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:
|
||||
# adding a new object
|
||||
new_obj = obj.typeclass
|
||||
new_obj.basetype_setup()
|
||||
new_obj.at_player_creation()
|
||||
if new_obj.obj:
|
||||
char = new_obj.db_obj
|
||||
char.db_player = obj
|
||||
char.save()
|
||||
new_obj.at_init()
|
||||
else:
|
||||
if obj.db_obj:
|
||||
char = obj.db_obj
|
||||
char.db_player = obj
|
||||
char.save()
|
||||
|
||||
obj.at_init()
|
||||
|
||||
def delete_model(self, request, obj):
|
||||
# called when deleting a player object. Makes sure to also delete user.
|
||||
user = obj.user
|
||||
user.delete()
|
||||
|
||||
admin.site.register(PlayerDB, PlayerDBAdmin)
|
||||
def save_formset(self, request, form, formset, change):
|
||||
"Run all hooks on the player object"
|
||||
super(UserAdmin, self).save_formset(request, form, formset, change)
|
||||
playerdb = form.instance.get_profile()
|
||||
if not change:
|
||||
create.create_player("", "", "",
|
||||
typeclass=playerdb.db_typeclass_path,
|
||||
create_character=False,
|
||||
player_dbobj=playerdb)
|
||||
if playerdb.db_obj:
|
||||
playerdb.db_obj.db_player = playerdb
|
||||
playerdb.db_obj.save()
|
||||
|
||||
#assert False, (form.instance, form.instance.get_profile())
|
||||
|
||||
admin.site.register(User, UserAdmin)
|
||||
|
|
|
|||
|
|
@ -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.")
|
||||
# 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.')
|
||||
db_obj = models.ForeignKey("objects.ObjectDB", null=True, blank=True, verbose_name="character", help_text='In-game object.')
|
||||
|
||||
# database storage of persistant cmdsets.
|
||||
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
|
||||
objects = manager.PlayerManager()
|
||||
|
|
|
|||
|
|
@ -351,12 +351,18 @@ def create_player(name, email, password,
|
|||
is_superuser=False,
|
||||
locks=None, permissions=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
|
||||
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
|
||||
True, a game player object with the same name as the User/Player will
|
||||
|
|
@ -414,9 +420,12 @@ def create_player(name, email, password,
|
|||
# this is already an object typeclass, extract its path
|
||||
typeclass = typeclass.path
|
||||
|
||||
# create new database object
|
||||
new_db_player = PlayerDB(db_key=name, user=new_user)
|
||||
new_db_player.save()
|
||||
if player_dbobj:
|
||||
new_db_player = player_dbobj
|
||||
else:
|
||||
# create new database object
|
||||
new_db_player = PlayerDB(db_key=name, user=new_user)
|
||||
new_db_player.save()
|
||||
|
||||
# assign the typeclass
|
||||
typeclass = utils.to_unicode(typeclass)
|
||||
|
|
|
|||
|
|
@ -20,10 +20,9 @@
|
|||
|
||||
{% if app.name == 'Auth' %}
|
||||
<h2>Admin</h2>
|
||||
<p><i>Note: Users hold django-specific authentication and should
|
||||
not be created stand-alone. Groups
|
||||
define permissions only relevant to admin-site access.
|
||||
To create a new In-game user, create a new <b>Player</b></i>.</p>
|
||||
<p><i>Players are the out-of-character representation of a
|
||||
game account. A Player can potentially control any number of
|
||||
in-game character Objects (depending on game).</i></p>
|
||||
{% endif %}
|
||||
|
||||
<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>
|
||||
{% for model in app.models %}
|
||||
<tr>
|
||||
{% if model.perms.change %}
|
||||
<th scope="row"><a href="{{ model.admin_url }}">{{ model.name }}</a></th>
|
||||
{% else %}
|
||||
<th scope="row">{{ model.name }}</th>
|
||||
{% if model.name == "Users" %}
|
||||
{% if model.perms.change %}
|
||||
<th scope="row"><a href="{{ model.admin_url }}">Player</a></th>
|
||||
{% else %}
|
||||
<th scope="row">Player</th>
|
||||
{% endif %}
|
||||
|
||||
{% if model.perms.add %}
|
||||
|
|
@ -49,6 +49,7 @@
|
|||
<td> </td>
|
||||
{% endif %}
|
||||
</tr>
|
||||
{% endif %}
|
||||
|
||||
{% endfor %}
|
||||
</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