mirror of
https://github.com/evennia/evennia.git
synced 2026-03-16 21:06:30 +01:00
Add account-object link button to admin
This commit is contained in:
parent
14968e4b42
commit
a7f1e24c9c
4 changed files with 167 additions and 46 deletions
|
|
@ -6,7 +6,7 @@ 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.admin.widgets import ForeignKeyRawIdWidget
|
||||
from django.contrib.admin.widgets import ForeignKeyRawIdWidget, FilteredSelectMultiple
|
||||
from django.contrib.auth.admin import UserAdmin as BaseUserAdmin
|
||||
from django.utils.translation import gettext as _
|
||||
from django.contrib.auth.forms import UserChangeForm, UserCreationForm
|
||||
|
|
@ -236,6 +236,39 @@ class AccountAttributeInline(AttributeInline):
|
|||
model = AccountDB.db_attributes.through
|
||||
related_field = "accountdb"
|
||||
|
||||
class ObjectPuppetInline(admin.StackedInline):
|
||||
"""
|
||||
Inline creation of puppet-Object in Account.
|
||||
|
||||
"""
|
||||
from .objects import ObjectCreateForm
|
||||
|
||||
model = ObjectDB
|
||||
view_on_site = False
|
||||
show_change_link = True
|
||||
# template = "admin/accounts/stacked.html"
|
||||
form = ObjectCreateForm
|
||||
fieldsets = (
|
||||
(
|
||||
None,
|
||||
{
|
||||
"fields": (
|
||||
("db_key", "db_typeclass_path"),
|
||||
("db_location", "db_home", "db_destination"),
|
||||
"db_cmdset_storage",
|
||||
"db_lock_storage",
|
||||
),
|
||||
"description": "Object currently puppeted by the account (note that this "
|
||||
"will go away if account logs out or unpuppets)",
|
||||
},
|
||||
),
|
||||
)
|
||||
|
||||
extra = 0
|
||||
readonly_fields = ("db_key", "db_typeclass_path", "db_destination",
|
||||
"db_location", "db_home", "db_account",
|
||||
"db_cmdset_storage", "db_lock_storage")
|
||||
|
||||
|
||||
@admin.register(AccountDB)
|
||||
class AccountAdmin(BaseUserAdmin):
|
||||
|
|
@ -246,8 +279,8 @@ class AccountAdmin(BaseUserAdmin):
|
|||
list_display = ("username", "email", "is_staff", "is_superuser")
|
||||
form = AccountChangeForm
|
||||
add_form = AccountCreationForm
|
||||
inlines = [AccountTagInline, AccountAttributeInline]
|
||||
readonly_fields = ["db_date_created", "serialized_string"]
|
||||
inlines = [AccountTagInline, AccountAttributeInline, ObjectPuppetInline]
|
||||
readonly_fields = ["db_date_created", "serialized_string", "link_button"]
|
||||
view_on_site = False
|
||||
fieldsets = (
|
||||
(
|
||||
|
|
|
|||
|
|
@ -73,6 +73,8 @@ class MsgAdmin(admin.ModelAdmin):
|
|||
save_as = True
|
||||
save_on_top = True
|
||||
list_select_related = True
|
||||
view_on_site = False
|
||||
|
||||
raw_id_fields = (
|
||||
"db_date_created", "db_sender_accounts",
|
||||
"db_sender_objects", "db_sender_scripts",
|
||||
|
|
|
|||
|
|
@ -2,11 +2,16 @@
|
|||
# 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 django import forms
|
||||
from django.urls import reverse
|
||||
from django.http import HttpResponseRedirect
|
||||
from django.conf import settings
|
||||
from django.conf.urls import url
|
||||
from django.contrib import admin, messages
|
||||
from django.contrib.admin.utils import flatten_fieldsets
|
||||
from django.contrib.admin.widgets import ForeignKeyRawIdWidget
|
||||
from django.utils.html import format_html
|
||||
from django.utils.translation import gettext as _
|
||||
|
||||
from evennia.objects.models import ObjectDB
|
||||
|
|
@ -68,26 +73,66 @@ class ObjectCreateForm(forms.ModelForm):
|
|||
"This string should be on the form "
|
||||
"<i>type:lockfunction(args);type2:lockfunction2(args);...",
|
||||
)
|
||||
|
||||
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.",
|
||||
)
|
||||
|
||||
db_account = forms.ModelChoiceField(
|
||||
AccountDB.objects.all(),
|
||||
label="Controlling Account",
|
||||
db_location = forms.ModelChoiceField(
|
||||
ObjectDB.objects.all(),
|
||||
label="Location",
|
||||
required=False,
|
||||
widget=ForeignKeyRawIdWidget(
|
||||
ObjectDB._meta.get_field('db_account').remote_field, admin.site),
|
||||
help_text="Only needed for characters in MULTISESSION_MODE=1 or 2."
|
||||
ObjectDB._meta.get_field('db_location').remote_field, admin.site),
|
||||
help_text="The (current) in-game location.<BR>"
|
||||
"Usually a Room but can be<BR>"
|
||||
"empty for un-puppeted Characters."
|
||||
)
|
||||
db_home = forms.ModelChoiceField(
|
||||
ObjectDB.objects.all(),
|
||||
label="Home",
|
||||
required=False,
|
||||
widget=ForeignKeyRawIdWidget(
|
||||
ObjectDB._meta.get_field('db_location').remote_field, admin.site),
|
||||
help_text="Fallback in-game location.<BR>"
|
||||
"All objects should usually have<BR>"
|
||||
"a home location."
|
||||
)
|
||||
db_destination = forms.ModelChoiceField(
|
||||
ObjectDB.objects.all(),
|
||||
label="Destination",
|
||||
required=False,
|
||||
widget=ForeignKeyRawIdWidget(
|
||||
ObjectDB._meta.get_field('db_destination').remote_field, admin.site),
|
||||
help_text="Only used by Exits."
|
||||
)
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
"""
|
||||
Tweak some fields dynamically.
|
||||
|
||||
"""
|
||||
super().__init__(*args, **kwargs)
|
||||
|
||||
# set default home
|
||||
home_id = str(settings.DEFAULT_HOME)
|
||||
home_id = home_id[1:] if home_id.startswith("#") else home_id
|
||||
default_home = ObjectDB.objects.filter(id=home_id)
|
||||
if default_home:
|
||||
default_home = default_home[0]
|
||||
self.fields["db_home"].initial = default_home
|
||||
self.fields["db_location"].initial = default_home
|
||||
|
||||
# better help text for cmdset_storage
|
||||
char_cmdset = settings.CMDSET_CHARACTER
|
||||
account_cmdset = settings.CMDSET_ACCOUNT
|
||||
self.fields["db_cmdset_storage"].help_text = (
|
||||
"Path to Command-set path. Most non-character objects don't need a cmdset"
|
||||
" and can leave this field blank. Some common cmdset-paths<BR> are "
|
||||
f"<strong>{char_cmdset}</strong> and <strong>{account_cmdset}</strong>"
|
||||
)
|
||||
|
||||
raw_id_fields = ("db_destination", "db_location", "db_home")
|
||||
|
||||
|
||||
class ObjectEditForm(ObjectCreateForm):
|
||||
|
|
@ -100,33 +145,16 @@ class ObjectEditForm(ObjectCreateForm):
|
|||
model = ObjectDB
|
||||
fields = "__all__"
|
||||
|
||||
|
||||
class ObjectInline(admin.StackedInline):
|
||||
"""
|
||||
Inline creation of Object.
|
||||
|
||||
"""
|
||||
model = ObjectDB
|
||||
# template = "admin/accounts/stacked.html"
|
||||
form = ObjectCreateForm
|
||||
fieldsets = (
|
||||
(
|
||||
None,
|
||||
{
|
||||
"fields": (
|
||||
("db_key", "db_typeclass_path"),
|
||||
("db_location", "db_home", "db_destination", "db_account"),
|
||||
"db_cmdset_storage",
|
||||
"db_lock_storage",
|
||||
)
|
||||
},
|
||||
),
|
||||
db_account = forms.ModelChoiceField(
|
||||
AccountDB.objects.all(),
|
||||
label="Puppeting Account",
|
||||
required=False,
|
||||
widget=ForeignKeyRawIdWidget(
|
||||
ObjectDB._meta.get_field('db_account').remote_field, admin.site),
|
||||
help_text="An Account puppeting this Object (if any).<BR>Note that when a user logs "
|
||||
"off/unpuppets, this<BR>field will be empty again. This is normal."
|
||||
)
|
||||
|
||||
extra = 1
|
||||
max_num = 1
|
||||
raw_id_fields = ("db_destination", "db_location", "db_home", "db_account")
|
||||
|
||||
|
||||
@admin.register(ObjectDB)
|
||||
class ObjectAdmin(admin.ModelAdmin):
|
||||
|
|
@ -141,7 +169,7 @@ class ObjectAdmin(admin.ModelAdmin):
|
|||
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", "db_account")
|
||||
readonly_fields = ("serialized_string", )
|
||||
readonly_fields = ("serialized_string", "link_button")
|
||||
|
||||
save_as = True
|
||||
save_on_top = True
|
||||
|
|
@ -158,7 +186,8 @@ class ObjectAdmin(admin.ModelAdmin):
|
|||
{
|
||||
"fields": (
|
||||
("db_key", "db_typeclass_path"),
|
||||
("db_location", "db_home", "db_destination", "db_account"),
|
||||
("db_location", "db_home", "db_destination"),
|
||||
("db_account", "link_button"),
|
||||
"db_cmdset_storage",
|
||||
"db_lock_storage",
|
||||
"serialized_string"
|
||||
|
|
@ -174,7 +203,7 @@ class ObjectAdmin(admin.ModelAdmin):
|
|||
{
|
||||
"fields": (
|
||||
("db_key", "db_typeclass_path"),
|
||||
("db_location", "db_home", "db_destination", "db_account"),
|
||||
("db_location", "db_home", "db_destination"),
|
||||
"db_cmdset_storage",
|
||||
)
|
||||
},
|
||||
|
|
@ -227,6 +256,63 @@ class ObjectAdmin(admin.ModelAdmin):
|
|||
defaults.update(kwargs)
|
||||
return super().get_form(request, obj, **defaults)
|
||||
|
||||
def get_urls(self):
|
||||
urls = super().get_urls()
|
||||
custom_urls = [
|
||||
url(
|
||||
r"^account-object-link/(?P<object_id>.+)/$",
|
||||
self.admin_site.admin_view(self.link_object_to_account),
|
||||
name="object-account-link"
|
||||
)
|
||||
]
|
||||
return custom_urls + urls
|
||||
|
||||
def link_button(self, obj):
|
||||
return format_html(
|
||||
'<a class="button" href="{}">Link to Account</a> ',
|
||||
reverse("admin:object-account-link", args=[obj.pk])
|
||||
)
|
||||
link_button.short_description = "Create puppet links for MULTISESSION_MODE 0/1"
|
||||
link_button.allow_tags = True
|
||||
|
||||
def link_object_to_account(self, request, object_id):
|
||||
"""
|
||||
Link object and account when pressing the button.
|
||||
|
||||
This will:
|
||||
|
||||
- Set account.db._last_puppet to this object
|
||||
- Add object to account.db._playable_characters
|
||||
- Change object locks to allow puppeting by account
|
||||
|
||||
"""
|
||||
obj = self.get_object(request, object_id)
|
||||
account = obj.db_account
|
||||
|
||||
if account:
|
||||
account.db._last_puppet = obj
|
||||
if not account.db._playable_characters:
|
||||
account.db._playable_characters = []
|
||||
if obj not in account.db._playable_characters:
|
||||
account.db._playable_characters.append(obj)
|
||||
if not obj.access(account, "puppet"):
|
||||
lock = obj.locks.get("puppet")
|
||||
lock += f" or pid({account.id})"
|
||||
obj.locks.add(lock)
|
||||
self.message_user(request,
|
||||
"Did the following (where possible): "
|
||||
f"Set Account.db._last_puppet = {obj}, "
|
||||
f"Added {obj} to Account.db._playable_characters list, "
|
||||
f"Added 'puppet:pid({account.id})' lock to {obj}.")
|
||||
else:
|
||||
self.message_user(request, "Account must be connected to set up puppet links "
|
||||
"(set Puppeting Account and save this page first).", level=messages.ERROR)
|
||||
|
||||
# stay on the same page
|
||||
return HttpResponseRedirect(reverse("admin:objects_objectdb_change", args=[obj.pk]))
|
||||
|
||||
|
||||
|
||||
def save_model(self, request, obj, form, change):
|
||||
"""
|
||||
Model-save hook.
|
||||
|
|
|
|||
|
|
@ -67,9 +67,9 @@
|
|||
|
||||
<p class="card-text">
|
||||
<h4><a href="{% url "admin:server_serverconfig_changelist" %}">ServerConfig</a></h4>
|
||||
ServerConfigs store variables set by the running server. While possibly
|
||||
interesting for debugging, you should usually not modify these
|
||||
manually unless you <i>really</i> know what you are doing. For
|
||||
ServerConfigs store variables set by the running server. While
|
||||
possibly interesting for debugging, you should usually not modify
|
||||
these manually unless you <i>really</i> know what you are doing. For
|
||||
example, the <i>BASE_*_TYPECLASS</i> fields are stored in order to
|
||||
auto-update when their setting changes; they must <i>not</i> be
|
||||
changed manually here.
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue