Trying to relocate admin (not working yet)
This commit is contained in:
parent
273cc31146
commit
8e02be23e4
15 changed files with 67 additions and 49 deletions
0
evennia/web/admin/__init__.py
Normal file
0
evennia/web/admin/__init__.py
Normal file
365
evennia/web/admin/accounts.py
Normal file
365
evennia/web/admin/accounts.py
Normal file
|
|
@ -0,0 +1,365 @@
|
|||
#
|
||||
# This sets up how models are displayed
|
||||
# in the web admin interface.
|
||||
#
|
||||
from django import forms
|
||||
from django.conf import settings
|
||||
from django.contrib import admin, messages
|
||||
from django.contrib.admin.options import IS_POPUP_VAR
|
||||
from django.contrib.auth.admin import UserAdmin as BaseUserAdmin
|
||||
from django.contrib.auth.forms import UserChangeForm, UserCreationForm
|
||||
from django.contrib.admin.utils import unquote
|
||||
from django.template.response import TemplateResponse
|
||||
from django.http import Http404, HttpResponseRedirect
|
||||
from django.core.exceptions import PermissionDenied
|
||||
from django.views.decorators.debug import sensitive_post_parameters
|
||||
from django.utils.decorators import method_decorator
|
||||
from django.utils.html import escape
|
||||
from django.urls import path, reverse
|
||||
from django.contrib.auth import update_session_auth_hash
|
||||
|
||||
from evennia.accounts.models import AccountDB
|
||||
from evennia.typeclasses.admin import AttributeInline, TagInline
|
||||
from evennia.utils import create
|
||||
|
||||
sensitive_post_parameters_m = method_decorator(sensitive_post_parameters())
|
||||
|
||||
|
||||
# handle the custom User editor
|
||||
class AccountDBChangeForm(UserChangeForm):
|
||||
"""
|
||||
Modify the accountdb class.
|
||||
|
||||
"""
|
||||
|
||||
class Meta(object):
|
||||
model = AccountDB
|
||||
fields = "__all__"
|
||||
|
||||
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="30 characters or fewer. Letters, spaces, digits and " "@/./+/-/_ only.",
|
||||
)
|
||||
|
||||
def clean_username(self):
|
||||
"""
|
||||
Clean the username and check its existence.
|
||||
|
||||
"""
|
||||
username = self.cleaned_data["username"]
|
||||
if username.upper() == self.instance.username.upper():
|
||||
return username
|
||||
elif AccountDB.objects.filter(username__iexact=username):
|
||||
raise forms.ValidationError("An account with that name " "already exists.")
|
||||
return self.cleaned_data["username"]
|
||||
|
||||
|
||||
class AccountDBCreationForm(UserCreationForm):
|
||||
"""
|
||||
Create a new AccountDB instance.
|
||||
"""
|
||||
|
||||
class Meta(object):
|
||||
model = AccountDB
|
||||
fields = "__all__"
|
||||
|
||||
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="30 characters or fewer. Letters, spaces, digits and " "@/./+/-/_ only.",
|
||||
)
|
||||
|
||||
def clean_username(self):
|
||||
"""
|
||||
Cleanup username.
|
||||
"""
|
||||
username = self.cleaned_data["username"]
|
||||
if AccountDB.objects.filter(username__iexact=username):
|
||||
raise forms.ValidationError("An account with that name already " "exists.")
|
||||
return username
|
||||
|
||||
|
||||
class AccountForm(forms.ModelForm):
|
||||
"""
|
||||
Defines how to display Accounts
|
||||
|
||||
"""
|
||||
|
||||
class Meta(object):
|
||||
model = AccountDB
|
||||
fields = "__all__"
|
||||
app_label = "accounts"
|
||||
|
||||
db_key = forms.RegexField(
|
||||
label="Username",
|
||||
initial="AccountDummy",
|
||||
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 connected Account's key "
|
||||
"name. 30 characters or fewer. Letters, spaces, digits and "
|
||||
"@/./+/-/_ only.",
|
||||
)
|
||||
|
||||
db_typeclass_path = forms.CharField(
|
||||
label="Typeclass",
|
||||
initial=settings.BASE_ACCOUNT_TYPECLASS,
|
||||
widget=forms.TextInput(attrs={"size": "78"}),
|
||||
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_ACCOUNT_TYPECLASS.",
|
||||
)
|
||||
|
||||
db_permissions = forms.CharField(
|
||||
label="Permissions",
|
||||
initial=settings.PERMISSION_ACCOUNT_DEFAULT,
|
||||
required=False,
|
||||
widget=forms.TextInput(attrs={"size": "78"}),
|
||||
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 an Account have permission "
|
||||
"'Admin', 'Builder' etc. An Account permission can be "
|
||||
"overloaded by the permissions of a controlled Character. "
|
||||
"Normal accounts use 'Accounts' by default.",
|
||||
)
|
||||
|
||||
db_lock_storage = forms.CharField(
|
||||
label="Locks",
|
||||
widget=forms.Textarea(attrs={"cols": "100", "rows": "2"}),
|
||||
required=False,
|
||||
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_ACCOUNT,
|
||||
widget=forms.TextInput(attrs={"size": "78"}),
|
||||
required=False,
|
||||
help_text="python path to account cmdset class (set in "
|
||||
"settings.CMDSET_ACCOUNT by default)",
|
||||
)
|
||||
|
||||
|
||||
class AccountInline(admin.StackedInline):
|
||||
"""
|
||||
Inline creation of Account
|
||||
|
||||
"""
|
||||
|
||||
model = AccountDB
|
||||
template = "admin/accounts/stacked.html"
|
||||
form = AccountForm
|
||||
fieldsets = (
|
||||
(
|
||||
"In-game Permissions and Locks",
|
||||
{
|
||||
"fields": ("db_lock_storage",),
|
||||
# {'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 Account data",
|
||||
{
|
||||
"fields": ("db_typeclass_path", "db_cmdset_storage"),
|
||||
"description": "<i>These fields define in-game-specific properties "
|
||||
"for the Account object in-game.</i>",
|
||||
},
|
||||
),
|
||||
)
|
||||
|
||||
extra = 1
|
||||
max_num = 1
|
||||
|
||||
|
||||
class AccountTagInline(TagInline):
|
||||
"""
|
||||
Inline Account Tags.
|
||||
|
||||
"""
|
||||
|
||||
model = AccountDB.db_tags.through
|
||||
related_field = "accountdb"
|
||||
|
||||
|
||||
class AccountAttributeInline(AttributeInline):
|
||||
"""
|
||||
Inline Account Attributes.
|
||||
|
||||
"""
|
||||
|
||||
model = AccountDB.db_attributes.through
|
||||
related_field = "accountdb"
|
||||
|
||||
|
||||
@admin.register(AccountDB)
|
||||
class AccountDBAdmin(BaseUserAdmin):
|
||||
"""
|
||||
This is the main creation screen for Users/accounts
|
||||
|
||||
"""
|
||||
list_display = ("username", "email", "is_staff", "is_superuser")
|
||||
form = AccountDBChangeForm
|
||||
add_form = AccountDBCreationForm
|
||||
inlines = [AccountTagInline, AccountAttributeInline]
|
||||
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>",
|
||||
},
|
||||
),
|
||||
(
|
||||
"Game Options",
|
||||
{
|
||||
"fields": ("db_typeclass_path", "db_cmdset_storage", "db_lock_storage"),
|
||||
"description": "<i>These are attributes that are more relevant " "to gameplay.</i>",
|
||||
},
|
||||
),
|
||||
)
|
||||
# ('Game Options', {'fields': (
|
||||
# 'db_typeclass_path', 'db_cmdset_storage',
|
||||
# 'db_permissions', 'db_lock_storage'),
|
||||
# 'description': '<i>These are attributes that are '
|
||||
# 'more relevant to gameplay.</i>'}))
|
||||
|
||||
add_fieldsets = (
|
||||
(
|
||||
None,
|
||||
{
|
||||
"fields": ("username", "password1", "password2", "email"),
|
||||
"description": "<i>These account details are shared by the admin "
|
||||
"system and the game.</i>",
|
||||
},
|
||||
),
|
||||
)
|
||||
|
||||
@sensitive_post_parameters_m
|
||||
def user_change_password(self, request, id, form_url=""):
|
||||
user = self.get_object(request, unquote(id))
|
||||
if not self.has_change_permission(request, user):
|
||||
raise PermissionDenied
|
||||
if user is None:
|
||||
raise Http404("%(name)s object with primary key %(key)r does not exist.") % {
|
||||
"name": self.model._meta.verbose_name,
|
||||
"key": escape(id),
|
||||
}
|
||||
if request.method == "POST":
|
||||
form = self.change_password_form(user, request.POST)
|
||||
if form.is_valid():
|
||||
form.save()
|
||||
change_message = self.construct_change_message(request, form, None)
|
||||
self.log_change(request, user, change_message)
|
||||
msg = "Password changed successfully."
|
||||
messages.success(request, msg)
|
||||
update_session_auth_hash(request, form.user)
|
||||
return HttpResponseRedirect(
|
||||
reverse(
|
||||
"%s:%s_%s_change"
|
||||
% (
|
||||
self.admin_site.name,
|
||||
user._meta.app_label,
|
||||
# the model_name is something we need to hardcode
|
||||
# since our accountdb is a proxy:
|
||||
"accountdb",
|
||||
),
|
||||
args=(user.pk,),
|
||||
)
|
||||
)
|
||||
else:
|
||||
form = self.change_password_form(user)
|
||||
|
||||
fieldsets = [(None, {"fields": list(form.base_fields)})]
|
||||
adminForm = admin.helpers.AdminForm(form, fieldsets, {})
|
||||
|
||||
context = {
|
||||
"title": "Change password: %s" % escape(user.get_username()),
|
||||
"adminForm": adminForm,
|
||||
"form_url": form_url,
|
||||
"form": form,
|
||||
"is_popup": (IS_POPUP_VAR in request.POST or IS_POPUP_VAR in request.GET),
|
||||
"add": True,
|
||||
"change": False,
|
||||
"has_delete_permission": False,
|
||||
"has_change_permission": True,
|
||||
"has_absolute_url": False,
|
||||
"opts": self.model._meta,
|
||||
"original": user,
|
||||
"save_as": False,
|
||||
"show_save": True,
|
||||
**self.admin_site.each_context(request),
|
||||
}
|
||||
|
||||
request.current_app = self.admin_site.name
|
||||
|
||||
return TemplateResponse(
|
||||
request,
|
||||
self.change_user_password_template or "admin/auth/user/change_password.html",
|
||||
context,
|
||||
)
|
||||
|
||||
def save_model(self, request, obj, form, change):
|
||||
"""
|
||||
Custom save actions.
|
||||
|
||||
Args:
|
||||
request (Request): Incoming request.
|
||||
obj (Object): Object to save.
|
||||
form (Form): Related form instance.
|
||||
change (bool): False if this is a new save and not an update.
|
||||
|
||||
"""
|
||||
obj.save()
|
||||
if not change:
|
||||
# calling hooks for new account
|
||||
obj.set_class_from_typeclass(typeclass_path=settings.BASE_ACCOUNT_TYPECLASS)
|
||||
obj.basetype_setup()
|
||||
obj.at_account_creation()
|
||||
|
||||
def response_add(self, request, obj, post_url_continue=None):
|
||||
from django.http import HttpResponseRedirect
|
||||
from django.urls import reverse
|
||||
|
||||
return HttpResponseRedirect(reverse("admin:accounts_accountdb_change", args=[obj.id]))
|
||||
|
||||
|
||||
# admin.site.register(AccountDB, AccountDBAdmin)
|
||||
123
evennia/web/admin/comms.py
Normal file
123
evennia/web/admin/comms.py
Normal file
|
|
@ -0,0 +1,123 @@
|
|||
"""
|
||||
This defines how Comm models are displayed in the web admin interface.
|
||||
|
||||
"""
|
||||
|
||||
from django.contrib import admin
|
||||
from evennia.comms.models import ChannelDB
|
||||
from evennia.typeclasses.admin import AttributeInline, TagInline
|
||||
from django.conf import settings
|
||||
|
||||
|
||||
class ChannelAttributeInline(AttributeInline):
|
||||
"""
|
||||
Inline display of Channel Attribute - experimental
|
||||
|
||||
"""
|
||||
|
||||
model = ChannelDB.db_attributes.through
|
||||
related_field = "channeldb"
|
||||
|
||||
|
||||
class ChannelTagInline(TagInline):
|
||||
"""
|
||||
Inline display of Channel Tags - experimental
|
||||
|
||||
"""
|
||||
|
||||
model = ChannelDB.db_tags.through
|
||||
related_field = "channeldb"
|
||||
|
||||
|
||||
class MsgAdmin(admin.ModelAdmin):
|
||||
"""
|
||||
Defines display for Msg objects
|
||||
|
||||
"""
|
||||
|
||||
list_display = (
|
||||
"id",
|
||||
"db_date_created",
|
||||
"db_sender",
|
||||
"db_receivers",
|
||||
"db_channels",
|
||||
"db_message",
|
||||
"db_lock_storage",
|
||||
)
|
||||
list_display_links = ("id",)
|
||||
ordering = ["db_date_created", "db_sender", "db_receivers", "db_channels"]
|
||||
# readonly_fields = ['db_message', 'db_sender', 'db_receivers', 'db_channels']
|
||||
search_fields = ["id", "^db_date_created", "^db_message"]
|
||||
save_as = True
|
||||
save_on_top = True
|
||||
list_select_related = True
|
||||
|
||||
|
||||
# admin.site.register(Msg, MsgAdmin)
|
||||
|
||||
|
||||
class ChannelAdmin(admin.ModelAdmin):
|
||||
"""
|
||||
Defines display for Channel objects
|
||||
|
||||
"""
|
||||
|
||||
inlines = [ChannelTagInline, ChannelAttributeInline]
|
||||
list_display = ("id", "db_key", "db_lock_storage", "subscriptions")
|
||||
list_display_links = ("id", "db_key")
|
||||
ordering = ["db_key"]
|
||||
search_fields = ["id", "db_key", "db_tags__db_key"]
|
||||
save_as = True
|
||||
save_on_top = True
|
||||
list_select_related = True
|
||||
raw_id_fields = ("db_object_subscriptions", "db_account_subscriptions")
|
||||
fieldsets = (
|
||||
(
|
||||
None,
|
||||
{
|
||||
"fields": (
|
||||
("db_key",),
|
||||
"db_lock_storage",
|
||||
"db_account_subscriptions",
|
||||
"db_object_subscriptions",
|
||||
)
|
||||
},
|
||||
),
|
||||
)
|
||||
|
||||
def subscriptions(self, obj):
|
||||
"""
|
||||
Helper method to get subs from a channel.
|
||||
|
||||
Args:
|
||||
obj (Channel): The channel to get subs from.
|
||||
|
||||
"""
|
||||
return ", ".join([str(sub) for sub in obj.subscriptions.all()])
|
||||
|
||||
def save_model(self, request, obj, form, change):
|
||||
"""
|
||||
Model-save hook.
|
||||
|
||||
Args:
|
||||
request (Request): Incoming request.
|
||||
obj (Object): Database object.
|
||||
form (Form): Form instance.
|
||||
change (bool): If this is a change or a new object.
|
||||
|
||||
"""
|
||||
obj.save()
|
||||
if not change:
|
||||
# adding a new object
|
||||
# have to call init with typeclass passed to it
|
||||
obj.set_class_from_typeclass(typeclass_path=settings.BASE_CHANNEL_TYPECLASS)
|
||||
obj.at_init()
|
||||
|
||||
def response_add(self, request, obj, post_url_continue=None):
|
||||
from django.http import HttpResponseRedirect
|
||||
from django.urls import reverse
|
||||
|
||||
return HttpResponseRedirect(reverse("admin:comms_channeldb_change", args=[obj.id]))
|
||||
|
||||
|
||||
admin.site.register(ChannelDB, ChannelAdmin)
|
||||
|
|
@ -13,12 +13,14 @@ from django.contrib.admin.views.decorators import staff_member_required
|
|||
def evennia_admin(request):
|
||||
"""
|
||||
Helpful Evennia-specific admin page.
|
||||
|
||||
"""
|
||||
return render(request, "evennia_admin.html", {"accountdb": AccountDB})
|
||||
return render(request, "admin/frontpage.html", {"accountdb": AccountDB})
|
||||
|
||||
|
||||
def admin_wrapper(request):
|
||||
"""
|
||||
Wrapper that allows us to properly use the base Django admin site, if needed.
|
||||
|
||||
"""
|
||||
return staff_member_required(site.index)(request)
|
||||
56
evennia/web/admin/help.py
Normal file
56
evennia/web/admin/help.py
Normal file
|
|
@ -0,0 +1,56 @@
|
|||
"""
|
||||
This defines how to edit help entries in Admin.
|
||||
"""
|
||||
from django import forms
|
||||
from django.contrib import admin
|
||||
from evennia.help.models import HelpEntry
|
||||
from evennia.typeclasses.admin import TagInline
|
||||
|
||||
|
||||
class HelpTagInline(TagInline):
|
||||
model = HelpEntry.db_tags.through
|
||||
related_field = "helpentry"
|
||||
|
||||
|
||||
class HelpEntryForm(forms.ModelForm):
|
||||
"Defines how to display the help entry"
|
||||
|
||||
class Meta(object):
|
||||
model = HelpEntry
|
||||
fields = "__all__"
|
||||
|
||||
db_help_category = forms.CharField(
|
||||
label="Help category", initial="General", help_text="organizes help entries in lists"
|
||||
)
|
||||
db_lock_storage = forms.CharField(
|
||||
label="Locks",
|
||||
initial="view:all()",
|
||||
required=False,
|
||||
widget=forms.TextInput(attrs={"size": "40"}),
|
||||
)
|
||||
|
||||
|
||||
class HelpEntryAdmin(admin.ModelAdmin):
|
||||
"Sets up the admin manaager for help entries"
|
||||
inlines = [HelpTagInline]
|
||||
list_display = ("id", "db_key", "db_help_category", "db_lock_storage")
|
||||
list_display_links = ("id", "db_key")
|
||||
search_fields = ["^db_key", "db_entrytext"]
|
||||
ordering = ["db_help_category", "db_key"]
|
||||
save_as = True
|
||||
save_on_top = True
|
||||
list_select_related = True
|
||||
|
||||
form = HelpEntryForm
|
||||
fieldsets = (
|
||||
(
|
||||
None,
|
||||
{
|
||||
"fields": (("db_key", "db_help_category"), "db_entrytext", "db_lock_storage"),
|
||||
"description": "Sets a Help entry. Set lock to <i>view:all()</I> unless you want to restrict it.",
|
||||
},
|
||||
),
|
||||
)
|
||||
|
||||
|
||||
admin.site.register(HelpEntry, HelpEntryAdmin)
|
||||
197
evennia/web/admin/objects.py
Normal file
197
evennia/web/admin/objects.py
Normal file
|
|
@ -0,0 +1,197 @@
|
|||
#
|
||||
# This sets up how models are displayed
|
||||
# in the web admin interface.
|
||||
#
|
||||
from django import forms
|
||||
from django.conf import settings
|
||||
from django.contrib import admin
|
||||
from evennia.typeclasses.admin import AttributeInline, TagInline
|
||||
from evennia.objects.models import ObjectDB
|
||||
from django.contrib.admin.utils import flatten_fieldsets
|
||||
from django.utils.translation import gettext as _
|
||||
|
||||
|
||||
class ObjectAttributeInline(AttributeInline):
|
||||
"""
|
||||
Defines inline descriptions of Attributes (experimental)
|
||||
|
||||
"""
|
||||
|
||||
model = ObjectDB.db_attributes.through
|
||||
related_field = "objectdb"
|
||||
|
||||
|
||||
class ObjectTagInline(TagInline):
|
||||
"""
|
||||
Defines inline descriptions of Tags (experimental)
|
||||
|
||||
"""
|
||||
|
||||
model = ObjectDB.db_tags.through
|
||||
related_field = "objectdb"
|
||||
|
||||
|
||||
class ObjectCreateForm(forms.ModelForm):
|
||||
"""
|
||||
This form details the look of the fields.
|
||||
|
||||
"""
|
||||
|
||||
class Meta(object):
|
||||
model = ObjectDB
|
||||
fields = "__all__"
|
||||
|
||||
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=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. If you are "
|
||||
"creating a Character you should use the typeclass defined by "
|
||||
"settings.BASE_CHARACTER_TYPECLASS or one derived from that.",
|
||||
)
|
||||
db_cmdset_storage = forms.CharField(
|
||||
label="CmdSet",
|
||||
initial="",
|
||||
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.",
|
||||
)
|
||||
raw_id_fields = ("db_destination", "db_location", "db_home")
|
||||
|
||||
|
||||
class ObjectEditForm(ObjectCreateForm):
|
||||
"""
|
||||
Form used for editing. Extends the create one with more fields
|
||||
|
||||
"""
|
||||
|
||||
class Meta(object):
|
||||
fields = "__all__"
|
||||
|
||||
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):
|
||||
"""
|
||||
Describes the admin page for Objects.
|
||||
|
||||
"""
|
||||
|
||||
inlines = [ObjectTagInline, ObjectAttributeInline]
|
||||
list_display = ("id", "db_key", "db_account", "db_typeclass_path")
|
||||
list_display_links = ("id", "db_key")
|
||||
ordering = ["db_account", "db_typeclass_path", "id"]
|
||||
search_fields = ["=id", "^db_key", "db_typeclass_path", "^db_account__db_key"]
|
||||
raw_id_fields = ("db_destination", "db_location", "db_home")
|
||||
|
||||
save_as = True
|
||||
save_on_top = True
|
||||
list_select_related = True
|
||||
list_filter = ("db_typeclass_path",)
|
||||
|
||||
# editing fields setup
|
||||
|
||||
form = ObjectEditForm
|
||||
fieldsets = (
|
||||
(
|
||||
None,
|
||||
{
|
||||
"fields": (
|
||||
("db_key", "db_typeclass_path"),
|
||||
("db_lock_storage",),
|
||||
("db_location", "db_home"),
|
||||
"db_destination",
|
||||
"db_cmdset_storage",
|
||||
)
|
||||
},
|
||||
),
|
||||
)
|
||||
|
||||
add_form = ObjectCreateForm
|
||||
add_fieldsets = (
|
||||
(
|
||||
None,
|
||||
{
|
||||
"fields": (
|
||||
("db_key", "db_typeclass_path"),
|
||||
("db_location", "db_home"),
|
||||
"db_destination",
|
||||
"db_cmdset_storage",
|
||||
)
|
||||
},
|
||||
),
|
||||
)
|
||||
|
||||
def get_fieldsets(self, request, obj=None):
|
||||
"""
|
||||
Return fieldsets.
|
||||
|
||||
Args:
|
||||
request (Request): Incoming request.
|
||||
obj (ObjectDB, optional): Database object.
|
||||
"""
|
||||
if not obj:
|
||||
return self.add_fieldsets
|
||||
return super().get_fieldsets(request, obj)
|
||||
|
||||
def get_form(self, request, obj=None, **kwargs):
|
||||
"""
|
||||
Use special form during creation.
|
||||
|
||||
Args:
|
||||
request (Request): Incoming request.
|
||||
obj (Object, optional): Database object.
|
||||
|
||||
"""
|
||||
defaults = {}
|
||||
if obj is None:
|
||||
defaults.update(
|
||||
{"form": self.add_form, "fields": flatten_fieldsets(self.add_fieldsets)}
|
||||
)
|
||||
defaults.update(kwargs)
|
||||
return super().get_form(request, obj, **defaults)
|
||||
|
||||
def save_model(self, request, obj, form, change):
|
||||
"""
|
||||
Model-save hook.
|
||||
|
||||
Args:
|
||||
request (Request): Incoming request.
|
||||
obj (Object): Database object.
|
||||
form (Form): Form instance.
|
||||
change (bool): If this is a change or a new object.
|
||||
|
||||
"""
|
||||
obj.save()
|
||||
if not change:
|
||||
# adding a new object
|
||||
# have to call init with typeclass passed to it
|
||||
obj.set_class_from_typeclass(typeclass_path=obj.db_typeclass_path)
|
||||
obj.basetype_setup()
|
||||
obj.basetype_posthook_setup()
|
||||
obj.at_object_creation()
|
||||
obj.at_init()
|
||||
|
||||
def response_add(self, request, obj, post_url_continue=None):
|
||||
from django.http import HttpResponseRedirect
|
||||
from django.urls import reverse
|
||||
|
||||
return HttpResponseRedirect(reverse("admin:objects_objectdb_change", args=[obj.id]))
|
||||
|
||||
|
||||
admin.site.register(ObjectDB, ObjectDBAdmin)
|
||||
91
evennia/web/admin/scripts.py
Normal file
91
evennia/web/admin/scripts.py
Normal file
|
|
@ -0,0 +1,91 @@
|
|||
#
|
||||
# This sets up how models are displayed
|
||||
# in the web admin interface.
|
||||
#
|
||||
from django.conf import settings
|
||||
|
||||
from evennia.typeclasses.admin import AttributeInline, TagInline
|
||||
|
||||
from evennia.scripts.models import ScriptDB
|
||||
from django.contrib import admin
|
||||
|
||||
|
||||
class ScriptTagInline(TagInline):
|
||||
"""
|
||||
Inline script tags.
|
||||
|
||||
"""
|
||||
|
||||
model = ScriptDB.db_tags.through
|
||||
related_field = "scriptdb"
|
||||
|
||||
|
||||
class ScriptAttributeInline(AttributeInline):
|
||||
"""
|
||||
Inline attribute tags.
|
||||
|
||||
"""
|
||||
|
||||
model = ScriptDB.db_attributes.through
|
||||
related_field = "scriptdb"
|
||||
|
||||
|
||||
class ScriptDBAdmin(admin.ModelAdmin):
|
||||
"""
|
||||
Displaying the main Script page.
|
||||
|
||||
"""
|
||||
|
||||
list_display = (
|
||||
"id",
|
||||
"db_key",
|
||||
"db_typeclass_path",
|
||||
"db_obj",
|
||||
"db_interval",
|
||||
"db_repeats",
|
||||
"db_persistent",
|
||||
)
|
||||
list_display_links = ("id", "db_key")
|
||||
ordering = ["db_obj", "db_typeclass_path"]
|
||||
search_fields = ["^db_key", "db_typeclass_path"]
|
||||
save_as = True
|
||||
save_on_top = True
|
||||
list_select_related = True
|
||||
raw_id_fields = ("db_obj",)
|
||||
|
||||
fieldsets = (
|
||||
(
|
||||
None,
|
||||
{
|
||||
"fields": (
|
||||
("db_key", "db_typeclass_path"),
|
||||
"db_interval",
|
||||
"db_repeats",
|
||||
"db_start_delay",
|
||||
"db_persistent",
|
||||
"db_obj",
|
||||
)
|
||||
},
|
||||
),
|
||||
)
|
||||
inlines = [ScriptTagInline, ScriptAttributeInline]
|
||||
|
||||
def save_model(self, request, obj, form, change):
|
||||
"""
|
||||
Model-save hook.
|
||||
|
||||
Args:
|
||||
request (Request): Incoming request.
|
||||
obj (Object): Database object.
|
||||
form (Form): Form instance.
|
||||
change (bool): If this is a change or a new object.
|
||||
|
||||
"""
|
||||
obj.save()
|
||||
if not change:
|
||||
# adding a new object
|
||||
# have to call init with typeclass passed to it
|
||||
obj.set_class_from_typeclass(typeclass_path=obj.db_typeclass_path)
|
||||
|
||||
|
||||
admin.site.register(ScriptDB, ScriptDBAdmin)
|
||||
344
evennia/web/admin/typeclasses.py
Normal file
344
evennia/web/admin/typeclasses.py
Normal file
|
|
@ -0,0 +1,344 @@
|
|||
import traceback
|
||||
from datetime import datetime
|
||||
from django.contrib import admin
|
||||
from evennia.typeclasses.models import Tag
|
||||
from django import forms
|
||||
from evennia.utils.picklefield import PickledFormField
|
||||
from evennia.utils.dbserialize import from_pickle, _SaverSet
|
||||
|
||||
|
||||
class TagAdmin(admin.ModelAdmin):
|
||||
"""
|
||||
A django Admin wrapper for Tags.
|
||||
"""
|
||||
|
||||
search_fields = ("db_key", "db_category", "db_tagtype")
|
||||
list_display = ("db_key", "db_category", "db_tagtype", "db_data")
|
||||
fields = ("db_key", "db_category", "db_tagtype", "db_data")
|
||||
list_filter = ("db_tagtype",)
|
||||
|
||||
|
||||
class TagForm(forms.ModelForm):
|
||||
"""
|
||||
This form overrides the base behavior of the ModelForm that would be used for a
|
||||
Tag-through-model. Since the through-models only have access to the foreignkeys of the Tag and
|
||||
the Object that they're attached to, we need to spoof the behavior of it being a form that would
|
||||
correspond to its tag, or the creation of a tag. Instead of being saved, we'll call to the
|
||||
Object's handler, which will handle the creation, change, or deletion of a tag for us, as well
|
||||
as updating the handler's cache so that all changes are instantly updated in-game.
|
||||
"""
|
||||
|
||||
tag_key = forms.CharField(
|
||||
label="Tag Name", required=True, help_text="This is the main key identifier"
|
||||
)
|
||||
tag_category = forms.CharField(
|
||||
label="Category",
|
||||
help_text="Used for grouping tags. Unset (default) gives a category of None",
|
||||
required=False,
|
||||
)
|
||||
tag_type = forms.CharField(
|
||||
label="Type",
|
||||
help_text='Internal use. Either unset, "alias" or "permission"',
|
||||
required=False,
|
||||
)
|
||||
tag_data = forms.CharField(
|
||||
label="Data",
|
||||
help_text="Usually unused. Intended for eventual info about the tag itself",
|
||||
required=False,
|
||||
)
|
||||
|
||||
class Meta:
|
||||
fields = ("tag_key", "tag_category", "tag_data", "tag_type")
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
"""
|
||||
If we have a tag, then we'll prepopulate our instance with the fields we'd expect it
|
||||
to have based on the tag. tag_key, tag_category, tag_type, and tag_data all refer to
|
||||
the corresponding tag fields. The initial data of the form fields will similarly be
|
||||
populated.
|
||||
"""
|
||||
super().__init__(*args, **kwargs)
|
||||
tagkey = None
|
||||
tagcategory = None
|
||||
tagtype = None
|
||||
tagdata = None
|
||||
if hasattr(self.instance, "tag"):
|
||||
tagkey = self.instance.tag.db_key
|
||||
tagcategory = self.instance.tag.db_category
|
||||
tagtype = self.instance.tag.db_tagtype
|
||||
tagdata = self.instance.tag.db_data
|
||||
self.fields["tag_key"].initial = tagkey
|
||||
self.fields["tag_category"].initial = tagcategory
|
||||
self.fields["tag_type"].initial = tagtype
|
||||
self.fields["tag_data"].initial = tagdata
|
||||
self.instance.tag_key = tagkey
|
||||
self.instance.tag_category = tagcategory
|
||||
self.instance.tag_type = tagtype
|
||||
self.instance.tag_data = tagdata
|
||||
|
||||
def save(self, commit=True):
|
||||
"""
|
||||
One thing we want to do here is the or None checks, because forms are saved with an empty
|
||||
string rather than null from forms, usually, and the Handlers may handle empty strings
|
||||
differently than None objects. So for consistency with how things are handled in game,
|
||||
we'll try to make sure that empty form fields will be None, rather than ''.
|
||||
"""
|
||||
# we are spoofing a tag for the Handler that will be called
|
||||
# instance = super().save(commit=False)
|
||||
instance = self.instance
|
||||
instance.tag_key = self.cleaned_data["tag_key"]
|
||||
instance.tag_category = self.cleaned_data["tag_category"] or None
|
||||
instance.tag_type = self.cleaned_data["tag_type"] or None
|
||||
instance.tag_data = self.cleaned_data["tag_data"] or None
|
||||
return instance
|
||||
|
||||
|
||||
class TagFormSet(forms.BaseInlineFormSet):
|
||||
"""
|
||||
The Formset handles all the inline forms that are grouped together on the change page of the
|
||||
corresponding object. All the tags will appear here, and we'll save them by overriding the
|
||||
formset's save method. The forms will similarly spoof their save methods to return an instance
|
||||
which hasn't been saved to the database, but have the relevant fields filled out based on the
|
||||
contents of the cleaned form. We'll then use that to call to the handler of the corresponding
|
||||
Object, where the handler is an AliasHandler, PermissionsHandler, or TagHandler, based on the
|
||||
type of tag.
|
||||
"""
|
||||
|
||||
def save(self, commit=True):
|
||||
def get_handler(finished_object):
|
||||
related = getattr(finished_object, self.related_field)
|
||||
try:
|
||||
tagtype = finished_object.tag_type
|
||||
except AttributeError:
|
||||
tagtype = finished_object.tag.db_tagtype
|
||||
if tagtype == "alias":
|
||||
handler_name = "aliases"
|
||||
elif tagtype == "permission":
|
||||
handler_name = "permissions"
|
||||
else:
|
||||
handler_name = "tags"
|
||||
return getattr(related, handler_name)
|
||||
|
||||
instances = super().save(commit=False)
|
||||
# self.deleted_objects is a list created when super of save is called, we'll remove those
|
||||
for obj in self.deleted_objects:
|
||||
handler = get_handler(obj)
|
||||
handler.remove(obj.tag_key, category=obj.tag_category)
|
||||
for instance in instances:
|
||||
handler = get_handler(instance)
|
||||
handler.add(instance.tag_key, category=instance.tag_category, data=instance.tag_data)
|
||||
|
||||
|
||||
class TagInline(admin.TabularInline):
|
||||
"""
|
||||
A handler for inline Tags. This class should be subclassed in the admin of your models,
|
||||
and the 'model' and 'related_field' class attributes must be set. model should be the
|
||||
through model (ObjectDB_db_tag', for example), while related field should be the name
|
||||
of the field on that through model which points to the model being used: 'objectdb',
|
||||
'msg', 'accountdb', etc.
|
||||
"""
|
||||
|
||||
# Set this to the through model of your desired M2M when subclassing.
|
||||
model = None
|
||||
form = TagForm
|
||||
formset = TagFormSet
|
||||
related_field = None # Must be 'objectdb', 'accountdb', 'msg', etc. Set when subclassing
|
||||
# raw_id_fields = ('tag',)
|
||||
# readonly_fields = ('tag',)
|
||||
extra = 0
|
||||
|
||||
def get_formset(self, request, obj=None, **kwargs):
|
||||
"""
|
||||
get_formset has to return a class, but we need to make the class that we return
|
||||
know about the related_field that we'll use. Returning the class itself rather than
|
||||
a proxy isn't threadsafe, since it'd be the base class and would change if multiple
|
||||
people used the admin at the same time
|
||||
"""
|
||||
formset = super().get_formset(request, obj, **kwargs)
|
||||
|
||||
class ProxyFormset(formset):
|
||||
pass
|
||||
|
||||
ProxyFormset.related_field = self.related_field
|
||||
return ProxyFormset
|
||||
|
||||
|
||||
class AttributeForm(forms.ModelForm):
|
||||
"""
|
||||
This form overrides the base behavior of the ModelForm that would be used for a Attribute-through-model.
|
||||
Since the through-models only have access to the foreignkeys of the Attribute and the Object that they're
|
||||
attached to, we need to spoof the behavior of it being a form that would correspond to its Attribute,
|
||||
or the creation of an Attribute. Instead of being saved, we'll call to the Object's handler, which will handle
|
||||
the creation, change, or deletion of an Attribute for us, as well as updating the handler's cache so that all
|
||||
changes are instantly updated in-game.
|
||||
"""
|
||||
|
||||
attr_key = forms.CharField(
|
||||
label="Attribute Name", required=False, initial="Enter Attribute Name Here"
|
||||
)
|
||||
attr_category = forms.CharField(
|
||||
label="Category", help_text="type of attribute, for sorting", required=False, max_length=128
|
||||
)
|
||||
attr_value = PickledFormField(label="Value", help_text="Value to pickle/save", required=False)
|
||||
attr_type = forms.CharField(
|
||||
label="Type",
|
||||
help_text='Internal use. Either unset (normal Attribute) or "nick"',
|
||||
required=False,
|
||||
max_length=16,
|
||||
)
|
||||
attr_lockstring = forms.CharField(
|
||||
label="Locks",
|
||||
required=False,
|
||||
help_text="Lock string on the form locktype:lockdef;lockfunc:lockdef;...",
|
||||
widget=forms.Textarea(attrs={"rows": 1, "cols": 8}),
|
||||
)
|
||||
|
||||
class Meta:
|
||||
fields = ("attr_key", "attr_value", "attr_category", "attr_lockstring", "attr_type")
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
"""
|
||||
If we have an Attribute, then we'll prepopulate our instance with the fields we'd expect it
|
||||
to have based on the Attribute. attr_key, attr_category, attr_value, attr_type,
|
||||
and attr_lockstring all refer to the corresponding Attribute fields. The initial data of the form fields will
|
||||
similarly be populated.
|
||||
|
||||
"""
|
||||
super().__init__(*args, **kwargs)
|
||||
attr_key = None
|
||||
attr_category = None
|
||||
attr_value = None
|
||||
attr_type = None
|
||||
attr_lockstring = None
|
||||
if hasattr(self.instance, "attribute"):
|
||||
attr_key = self.instance.attribute.db_key
|
||||
attr_category = self.instance.attribute.db_category
|
||||
attr_value = self.instance.attribute.db_value
|
||||
attr_type = self.instance.attribute.db_attrtype
|
||||
attr_lockstring = self.instance.attribute.db_lock_storage
|
||||
self.fields["attr_key"].initial = attr_key
|
||||
self.fields["attr_category"].initial = attr_category
|
||||
self.fields["attr_type"].initial = attr_type
|
||||
self.fields["attr_value"].initial = attr_value
|
||||
self.fields["attr_lockstring"].initial = attr_lockstring
|
||||
self.instance.attr_key = attr_key
|
||||
self.instance.attr_category = attr_category
|
||||
self.instance.attr_value = attr_value
|
||||
|
||||
# prevent from being transformed to str
|
||||
if isinstance(attr_value, (set, _SaverSet)):
|
||||
self.fields["attr_value"].disabled = True
|
||||
|
||||
self.instance.deserialized_value = from_pickle(attr_value)
|
||||
self.instance.attr_type = attr_type
|
||||
self.instance.attr_lockstring = attr_lockstring
|
||||
|
||||
def save(self, commit=True):
|
||||
"""
|
||||
One thing we want to do here is the or None checks, because forms are saved with an empty
|
||||
string rather than null from forms, usually, and the Handlers may handle empty strings
|
||||
differently than None objects. So for consistency with how things are handled in game,
|
||||
we'll try to make sure that empty form fields will be None, rather than ''.
|
||||
"""
|
||||
# we are spoofing an Attribute for the Handler that will be called
|
||||
instance = self.instance
|
||||
instance.attr_key = self.cleaned_data["attr_key"] or "no_name_entered_for_attribute"
|
||||
instance.attr_category = self.cleaned_data["attr_category"] or None
|
||||
instance.attr_value = self.cleaned_data["attr_value"]
|
||||
# convert the serialized string value into an object, if necessary, for AttributeHandler
|
||||
instance.attr_value = from_pickle(instance.attr_value)
|
||||
instance.attr_type = self.cleaned_data["attr_type"] or None
|
||||
instance.attr_lockstring = self.cleaned_data["attr_lockstring"]
|
||||
return instance
|
||||
|
||||
def clean_attr_value(self):
|
||||
"""
|
||||
Prevent certain data-types from being cleaned due to literal_eval
|
||||
failing on them. Otherwise they will be turned into str.
|
||||
|
||||
"""
|
||||
data = self.cleaned_data["attr_value"]
|
||||
initial = self.instance.attr_value
|
||||
if isinstance(initial, (set, _SaverSet, datetime)):
|
||||
return initial
|
||||
return data
|
||||
|
||||
|
||||
class AttributeFormSet(forms.BaseInlineFormSet):
|
||||
"""
|
||||
Attribute version of TagFormSet, as above.
|
||||
"""
|
||||
|
||||
def save(self, commit=True):
|
||||
def get_handler(finished_object):
|
||||
related = getattr(finished_object, self.related_field)
|
||||
try:
|
||||
attrtype = finished_object.attr_type
|
||||
except AttributeError:
|
||||
attrtype = finished_object.attribute.db_attrtype
|
||||
if attrtype == "nick":
|
||||
handler_name = "nicks"
|
||||
else:
|
||||
handler_name = "attributes"
|
||||
return getattr(related, handler_name)
|
||||
|
||||
instances = super().save(commit=False)
|
||||
for obj in self.deleted_objects:
|
||||
# self.deleted_objects is a list created when super of save is called, we'll remove those
|
||||
handler = get_handler(obj)
|
||||
handler.remove(obj.attr_key, category=obj.attr_category)
|
||||
|
||||
for instance in instances:
|
||||
handler = get_handler(instance)
|
||||
|
||||
value = instance.attr_value
|
||||
|
||||
try:
|
||||
handler.add(
|
||||
instance.attr_key,
|
||||
value,
|
||||
category=instance.attr_category,
|
||||
strattr=False,
|
||||
lockstring=instance.attr_lockstring,
|
||||
)
|
||||
except (TypeError, ValueError):
|
||||
# catch errors in nick templates and continue
|
||||
traceback.print_exc()
|
||||
continue
|
||||
|
||||
|
||||
class AttributeInline(admin.TabularInline):
|
||||
"""
|
||||
A handler for inline Attributes. This class should be subclassed in the admin of your models,
|
||||
and the 'model' and 'related_field' class attributes must be set. model should be the
|
||||
through model (ObjectDB_db_tag', for example), while related field should be the name
|
||||
of the field on that through model which points to the model being used: 'objectdb',
|
||||
'msg', 'accountdb', etc.
|
||||
"""
|
||||
|
||||
# Set this to the through model of your desired M2M when subclassing.
|
||||
model = None
|
||||
form = AttributeForm
|
||||
formset = AttributeFormSet
|
||||
related_field = None # Must be 'objectdb', 'accountdb', 'msg', etc. Set when subclassing
|
||||
# raw_id_fields = ('attribute',)
|
||||
# readonly_fields = ('attribute',)
|
||||
extra = 0
|
||||
|
||||
def get_formset(self, request, obj=None, **kwargs):
|
||||
"""
|
||||
get_formset has to return a class, but we need to make the class that we return
|
||||
know about the related_field that we'll use. Returning the class itself rather than
|
||||
a proxy isn't threadsafe, since it'd be the base class and would change if multiple
|
||||
people used the admin at the same time
|
||||
"""
|
||||
formset = super().get_formset(request, obj, **kwargs)
|
||||
|
||||
class ProxyFormset(formset):
|
||||
pass
|
||||
|
||||
ProxyFormset.related_field = self.related_field
|
||||
return ProxyFormset
|
||||
|
||||
|
||||
admin.site.register(Tag, TagAdmin)
|
||||
30
evennia/web/admin/urls.py
Normal file
30
evennia/web/admin/urls.py
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
"""
|
||||
Rerouting admin frontpage to evennia version.
|
||||
|
||||
These patterns are all under the admin/* namespace.
|
||||
|
||||
"""
|
||||
from django.conf import settings
|
||||
from django.contrib import admin
|
||||
from django.conf.urls import url, include
|
||||
from . import frontpage
|
||||
|
||||
|
||||
urlpatterns = [
|
||||
# Django original admin page. Make this URL is always available, whether
|
||||
# we've chosen to use Evennia's custom admin or not.
|
||||
url(r"/django/", frontpage.admin_wrapper, name="django_admin"),
|
||||
# Admin docs
|
||||
url(r"/doc/", include("django.contrib.admindocs.urls")),
|
||||
]
|
||||
|
||||
if settings.EVENNIA_ADMIN:
|
||||
urlpatterns += [
|
||||
# Our override for the admin.
|
||||
url("^/$", frontpage.evennia_admin, name="evennia_admin"),
|
||||
# Makes sure that other admin pages get loaded.
|
||||
url(r"^/", admin.site.urls),
|
||||
]
|
||||
else:
|
||||
# Just include the normal Django admin.
|
||||
urlpatterns += [url(r"^/", admin.site.urls)]
|
||||
|
|
@ -16,7 +16,6 @@
|
|||
|
||||
<h3>Game entities</h3>
|
||||
|
||||
|
||||
<p class="card-text">
|
||||
<h4><a href="{% url "admin:accounts_accountdb_changelist" %}">Accounts</a></h4>
|
||||
Accounts can have several characters under them. A user's login and
|
||||
|
|
@ -30,6 +30,8 @@ urlpatterns = [
|
|||
path("", include("evennia.web.website.urls")),
|
||||
# webclient
|
||||
path("webclient/", include("evennia.web.webclient.urls")),
|
||||
# admin
|
||||
path("admin", include("evennia.web.admin.urls")),
|
||||
# favicon
|
||||
path("favicon.ico", RedirectView.as_view(url="/media/images/favicon.ico", permanent=False)),
|
||||
]
|
||||
|
|
|
|||
|
|
@ -1,15 +1,26 @@
|
|||
#
|
||||
# This file defines global variables that will always be
|
||||
# available in a view context without having to repeatedly
|
||||
# include it. For this to work, this file is included in
|
||||
# the settings file, in the TEMPLATE_CONTEXT_PROCESSORS
|
||||
# tuple.
|
||||
#
|
||||
"""
|
||||
This file defines global variables that will always be available in a view
|
||||
context without having to repeatedly include it.
|
||||
|
||||
For this to work, this file is included in the settings file, in the
|
||||
TEMPLATE_CONTEXT_PROCESSORS tuple.
|
||||
|
||||
"""
|
||||
|
||||
|
||||
import os
|
||||
from django.conf import settings
|
||||
from evennia.utils.utils import get_evennia_version
|
||||
|
||||
# Setup lists of the most relevant apps so
|
||||
# the adminsite becomes more readable.
|
||||
|
||||
ACCOUNT_RELATED = ["Accounts"]
|
||||
GAME_ENTITIES = ["Objects", "Scripts", "Comms", "Help"]
|
||||
GAME_SETUP = ["Permissions", "Config"]
|
||||
CONNECTIONS = ["Irc"]
|
||||
WEBSITE = ["Flatpages", "News", "Sites"]
|
||||
|
||||
# Determine the site name and server version
|
||||
def set_game_name_and_slogan():
|
||||
"""
|
||||
|
|
@ -18,6 +29,7 @@ def set_game_name_and_slogan():
|
|||
|
||||
Notes:
|
||||
This function is used for unit testing the values of the globals.
|
||||
|
||||
"""
|
||||
global GAME_NAME, GAME_SLOGAN, SERVER_VERSION
|
||||
try:
|
||||
|
|
@ -31,18 +43,6 @@ def set_game_name_and_slogan():
|
|||
GAME_SLOGAN = SERVER_VERSION
|
||||
|
||||
|
||||
set_game_name_and_slogan()
|
||||
|
||||
# Setup lists of the most relevant apps so
|
||||
# the adminsite becomes more readable.
|
||||
|
||||
ACCOUNT_RELATED = ["Accounts"]
|
||||
GAME_ENTITIES = ["Objects", "Scripts", "Comms", "Help"]
|
||||
GAME_SETUP = ["Permissions", "Config"]
|
||||
CONNECTIONS = ["Irc"]
|
||||
WEBSITE = ["Flatpages", "News", "Sites"]
|
||||
|
||||
|
||||
def set_webclient_settings():
|
||||
"""
|
||||
As with set_game_name_and_slogan above, this sets global variables pertaining
|
||||
|
|
@ -50,6 +50,7 @@ def set_webclient_settings():
|
|||
|
||||
Notes:
|
||||
Used for unit testing.
|
||||
|
||||
"""
|
||||
global WEBCLIENT_ENABLED, WEBSOCKET_CLIENT_ENABLED, WEBSOCKET_PORT, WEBSOCKET_URL
|
||||
WEBCLIENT_ENABLED = settings.WEBCLIENT_ENABLED
|
||||
|
|
@ -64,13 +65,15 @@ def set_webclient_settings():
|
|||
WEBSOCKET_URL = settings.WEBSOCKET_CLIENT_URL
|
||||
|
||||
|
||||
set_game_name_and_slogan()
|
||||
set_webclient_settings()
|
||||
|
||||
# The main context processor function
|
||||
def general_context(request):
|
||||
"""
|
||||
Returns common Evennia-related context stuff, which
|
||||
is automatically added to context of all views.
|
||||
Returns common Evennia-related context stuff, which is automatically added
|
||||
to context of all views.
|
||||
|
||||
"""
|
||||
account = None
|
||||
if request.user.is_authenticated:
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ from django.contrib import admin
|
|||
from django.conf.urls import url, include
|
||||
from django import views as django_views
|
||||
from .views import (index, errors, accounts, help as helpviews, channels,
|
||||
characters, admin as adminviews)
|
||||
characters)
|
||||
|
||||
urlpatterns = [
|
||||
# website front page
|
||||
|
|
@ -52,26 +52,8 @@ urlpatterns = [
|
|||
url(r"^characters/delete/(?P<slug>[\w\d\-]+)/(?P<pk>[0-9]+)/$",
|
||||
characters.CharacterDeleteView.as_view(),
|
||||
name="character-delete"),
|
||||
|
||||
# Django original admin page. Make this URL is always available, whether
|
||||
# we've chosen to use Evennia's custom admin or not.
|
||||
|
||||
url(r"django_admin/", adminviews.admin_wrapper, name="django_admin"),
|
||||
|
||||
# Admin docs
|
||||
url(r"^admin/doc/", include("django.contrib.admindocs.urls")),
|
||||
]
|
||||
|
||||
if settings.EVENNIA_ADMIN:
|
||||
urlpatterns += [
|
||||
# Our override for the admin.
|
||||
url("^admin/$", adminviews.evennia_admin, name="evennia_admin"),
|
||||
# Makes sure that other admin pages get loaded.
|
||||
url(r"^admin/", admin.site.urls),
|
||||
]
|
||||
else:
|
||||
# Just include the normal Django admin.
|
||||
urlpatterns += [url(r"^admin/", admin.site.urls)]
|
||||
|
||||
# This sets up the server if the user want to run the Django
|
||||
# test server (this should normally not be needed).
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ def _gamestats():
|
|||
fpage_account_limit = 4
|
||||
|
||||
# A QuerySet of the most recently connected accounts.
|
||||
recent_users = AccountDB.objects.get_recently_connected_accounts()[:fpage_account_limit]
|
||||
recent_users = AccountDB.objects.get_recently_connected_accounts()
|
||||
nplyrs_conn_recent = len(recent_users) or "none"
|
||||
nplyrs = AccountDB.objects.num_total_accounts() or "none"
|
||||
nplyrs_reg_recent = len(AccountDB.objects.get_recently_created_accounts()) or "none"
|
||||
|
|
@ -44,7 +44,7 @@ def _gamestats():
|
|||
|
||||
pagevars = {
|
||||
"page_title": "Front Page",
|
||||
"accounts_connected_recent": recent_users,
|
||||
"accounts_connected_recent": recent_users[:fpage_account_limit],
|
||||
"num_accounts_connected": nsess or "no one",
|
||||
"num_accounts_registered": nplyrs or "no",
|
||||
"num_accounts_connected_recent": nplyrs_conn_recent or "no",
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue