mirror of
https://github.com/evennia/evennia.git
synced 2026-03-26 17:56:32 +01:00
Made all unit tests pass
This commit is contained in:
parent
a74029e3a9
commit
ba61ed3d7e
10 changed files with 148 additions and 110 deletions
|
|
@ -258,12 +258,12 @@ def prototype_from_object(obj):
|
|||
aliases = obj.aliases.get(return_list=True)
|
||||
if aliases:
|
||||
prot['aliases'] = aliases
|
||||
tags = [(tag.db_key, tag.db_category, tag.db_data)
|
||||
for tag in obj.tags.all(return_objs=True)]
|
||||
tags = sorted([(tag.db_key, tag.db_category, tag.db_data)
|
||||
for tag in obj.tags.all(return_objs=True)])
|
||||
if tags:
|
||||
prot['tags'] = tags
|
||||
attrs = [(attr.key, attr.value, attr.category, ';'.join(attr.locks.all()))
|
||||
for attr in obj.attributes.all()]
|
||||
attrs = sorted([(attr.key, attr.value, attr.category, ';'.join(attr.locks.all()))
|
||||
for attr in obj.attributes.all()])
|
||||
if attrs:
|
||||
prot['attrs'] = attrs
|
||||
|
||||
|
|
|
|||
|
|
@ -122,9 +122,9 @@ class TestUtils(EvenniaTest):
|
|||
|
||||
self.assertEqual(obj_prototype,
|
||||
{'aliases': ['foo'],
|
||||
'attrs': [('oldtest', 'to_keep', None, ''),
|
||||
('test', 'testval', None, ''),
|
||||
('desc', 'changed desc', None, '')],
|
||||
'attrs': [('desc', 'changed desc', None, ''),
|
||||
('oldtest', 'to_keep', None, ''),
|
||||
('test', 'testval', None, '')],
|
||||
'key': 'Obj',
|
||||
'home': '#1',
|
||||
'location': '#1',
|
||||
|
|
@ -213,9 +213,9 @@ class TestUtils(EvenniaTest):
|
|||
self.assertEqual(count, 1)
|
||||
|
||||
new_prot = spawner.prototype_from_object(self.obj1)
|
||||
self.assertEqual({'attrs': [('oldtest', 'to_keep', None, ''),
|
||||
('fooattr', 'fooattrval', None, ''),
|
||||
self.assertEqual({'attrs': [('fooattr', 'fooattrval', None, ''),
|
||||
('new', 'new_val', None, ''),
|
||||
('oldtest', 'to_keep', None, ''),
|
||||
('test', 'testval_changed', None, '')],
|
||||
'home': Something,
|
||||
'key': 'Obj',
|
||||
|
|
|
|||
|
|
@ -1401,7 +1401,7 @@ def create_superuser():
|
|||
"""
|
||||
print(
|
||||
"\nCreate a superuser below. The superuser is Account #1, the 'owner' "
|
||||
"account of the server.\n")
|
||||
"account of the server. Email is optional and can be empty.\n")
|
||||
django.core.management.call_command("createsuperuser", interactive=True)
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -114,20 +114,20 @@ class TestTelnet(TwistedTestCase):
|
|||
self.assertEqual(self.proto.protocol_flags['SCREENWIDTH'], {0: DEFAULT_WIDTH})
|
||||
self.assertEqual(self.proto.protocol_flags['SCREENHEIGHT'], {0: DEFAULT_HEIGHT})
|
||||
self.proto.dataReceived(IAC + WILL + NAWS)
|
||||
self.proto.dataReceived([IAC, SB, NAWS, '', 'x', '', 'd', IAC, SE])
|
||||
self.assertEqual(self.proto.protocol_flags['SCREENWIDTH'][0], 120)
|
||||
self.assertEqual(self.proto.protocol_flags['SCREENHEIGHT'][0], 100)
|
||||
self.proto.dataReceived(b"".join([IAC, SB, NAWS, b'', b'x', b'', b'd', IAC, SE]))
|
||||
self.assertEqual(self.proto.protocol_flags['SCREENWIDTH'][0], 78)
|
||||
self.assertEqual(self.proto.protocol_flags['SCREENHEIGHT'][0], 45)
|
||||
self.assertEqual(self.proto.handshakes, 6)
|
||||
# test ttype
|
||||
self.assertTrue(self.proto.protocol_flags["FORCEDENDLINE"])
|
||||
self.assertFalse(self.proto.protocol_flags["TTYPE"])
|
||||
self.assertTrue(self.proto.protocol_flags["ANSI"])
|
||||
self.proto.dataReceived(IAC + WILL + TTYPE)
|
||||
self.proto.dataReceived([IAC, SB, TTYPE, IS, "MUDLET", IAC, SE])
|
||||
self.proto.dataReceived(b"".join([IAC, SB, TTYPE, IS, b"MUDLET", IAC, SE]))
|
||||
self.assertTrue(self.proto.protocol_flags["XTERM256"])
|
||||
self.assertEqual(self.proto.protocol_flags["CLIENTNAME"], "MUDLET")
|
||||
self.proto.dataReceived([IAC, SB, TTYPE, IS, "XTERM", IAC, SE])
|
||||
self.proto.dataReceived([IAC, SB, TTYPE, IS, "MTTS 137", IAC, SE])
|
||||
self.proto.dataReceived(b"".join([IAC, SB, TTYPE, IS, b"XTERM", IAC, SE]))
|
||||
self.proto.dataReceived(b"".join([IAC, SB, TTYPE, IS, b"MTTS 137", IAC, SE]))
|
||||
self.assertEqual(self.proto.handshakes, 5)
|
||||
# test mccp
|
||||
self.proto.dataReceived(IAC + DONT + MCCP)
|
||||
|
|
@ -138,7 +138,7 @@ class TestTelnet(TwistedTestCase):
|
|||
self.assertEqual(self.proto.handshakes, 3)
|
||||
# test oob
|
||||
self.proto.dataReceived(IAC + DO + MSDP)
|
||||
self.proto.dataReceived([IAC, SB, MSDP, MSDP_VAR, "LIST", MSDP_VAL, "COMMANDS", IAC, SE])
|
||||
self.proto.dataReceived(b"".join([IAC, SB, MSDP, MSDP_VAR, b"LIST", MSDP_VAL, b"COMMANDS", IAC, SE]))
|
||||
self.assertTrue(self.proto.protocol_flags['OOB'])
|
||||
self.assertEqual(self.proto.handshakes, 2)
|
||||
# test mxp
|
||||
|
|
|
|||
|
|
@ -817,7 +817,7 @@ class TypedObject(SharedMemoryModel):
|
|||
kwargs={'pk': self.pk, 'slug': slugify(self.name)})
|
||||
except:
|
||||
return '#'
|
||||
|
||||
|
||||
def web_get_puppet_url(self):
|
||||
"""
|
||||
Returns the URI path for a View that allows users to puppet a specific
|
||||
|
|
|
|||
|
|
@ -10,6 +10,25 @@ from evennia.utils.test_resources import EvenniaTest
|
|||
# ------------------------------------------------------------
|
||||
|
||||
|
||||
class TestAttributes(EvenniaTest):
|
||||
def test_attrhandler(self):
|
||||
key = 'testattr'
|
||||
value = 'test attr value '
|
||||
self.obj1.attributes.add(key, value)
|
||||
self.assertEqual(self.obj1.attributes.get(key), value)
|
||||
self.obj1.db.testattr = value
|
||||
self.assertEqual(self.obj1.db.testattr, value)
|
||||
|
||||
def test_weird_text_save(self):
|
||||
"test 'weird' text type (different in py2 vs py3)"
|
||||
from django.utils.safestring import SafeText
|
||||
key = 'test attr 2'
|
||||
value = SafeText('test attr value 2')
|
||||
self.obj1.attributes.add(key, value)
|
||||
self.assertEqual(self.obj1.attributes.get(key), value)
|
||||
|
||||
|
||||
|
||||
class TestTypedObjectManager(EvenniaTest):
|
||||
def _manager(self, methodname, *args, **kwargs):
|
||||
return list(getattr(self.obj1.__class__.objects, methodname)(*args, **kwargs))
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@ except ImportError:
|
|||
from pickle import dumps, loads
|
||||
from django.core.exceptions import ObjectDoesNotExist
|
||||
from django.contrib.contenttypes.models import ContentType
|
||||
from django.utils.safestring import SafeString, SafeBytes
|
||||
from evennia.utils.utils import to_str, uses_database, is_iter
|
||||
from evennia.utils import logger
|
||||
|
||||
|
|
@ -521,7 +522,7 @@ def to_pickle(data):
|
|||
def process_item(item):
|
||||
"""Recursive processor and identification of data"""
|
||||
dtype = type(item)
|
||||
if dtype in (str, int, float, bool):
|
||||
if dtype in (str, int, float, bool, bytes, SafeString, SafeBytes):
|
||||
return item
|
||||
elif dtype == tuple:
|
||||
return tuple(process_item(val) for val in item)
|
||||
|
|
@ -573,7 +574,7 @@ def from_pickle(data, db_obj=None):
|
|||
def process_item(item):
|
||||
"""Recursive processor and identification of data"""
|
||||
dtype = type(item)
|
||||
if dtype in (str, int, float, bool):
|
||||
if dtype in (str, int, float, bool, bytes, SafeString, SafeBytes):
|
||||
return item
|
||||
elif _IS_PACKED_DBOBJ(item):
|
||||
# this must be checked before tuple
|
||||
|
|
@ -602,7 +603,7 @@ def from_pickle(data, db_obj=None):
|
|||
def process_tree(item, parent):
|
||||
"""Recursive processor, building a parent-tree from iterable data"""
|
||||
dtype = type(item)
|
||||
if dtype in (str, int, float, bool):
|
||||
if dtype in (str, int, float, bool, bytes, SafeString, SafeBytes):
|
||||
return item
|
||||
elif _IS_PACKED_DBOBJ(item):
|
||||
# this must be checked before tuple
|
||||
|
|
|
|||
|
|
@ -10,13 +10,10 @@ class TestEvForm(TestCase):
|
|||
def test_form(self):
|
||||
self.maxDiff = None
|
||||
form1 = evform._test()
|
||||
print("len(form1): {}".format(len(form1)))
|
||||
form2 = evform._test()
|
||||
print("len(form2): {}".format(len(form2)))
|
||||
|
||||
self.assertEqual(form1, form2)
|
||||
|
||||
# self.assertEqual(form, "")
|
||||
# self.assertEqual(form1, "")
|
||||
# '.------------------------------------------------.\n'
|
||||
# '| |\n'
|
||||
# '| Name: \x1b[0m\x1b[1m\x1b[32mTom\x1b[1m\x1b[32m \x1b'
|
||||
|
|
|
|||
|
|
@ -10,24 +10,24 @@ class EvenniaForm(forms.Form):
|
|||
This is a stock Django form, but modified so that all values provided
|
||||
through it are escaped (sanitized). Validation is performed by the fields
|
||||
you define in the form.
|
||||
|
||||
|
||||
This has little to do with Evennia itself and is more general web security-
|
||||
related.
|
||||
|
||||
|
||||
https://www.owasp.org/index.php/Input_Validation_Cheat_Sheet#Goals_of_Input_Validation
|
||||
|
||||
|
||||
"""
|
||||
def clean(self):
|
||||
"""
|
||||
Django hook. Performed on form submission.
|
||||
|
||||
|
||||
Returns:
|
||||
cleaned (dict): Dictionary of key:value pairs submitted on the form.
|
||||
|
||||
|
||||
"""
|
||||
# Call parent function
|
||||
cleaned = super(EvenniaForm, self).clean()
|
||||
|
||||
|
||||
# Escape all values provided by user
|
||||
cleaned = {k:escape(v) for k,v in cleaned.items()}
|
||||
return cleaned
|
||||
|
|
@ -35,123 +35,125 @@ class EvenniaForm(forms.Form):
|
|||
class AccountForm(UserCreationForm):
|
||||
"""
|
||||
This is a generic Django form tailored to the Account model.
|
||||
|
||||
|
||||
In this incarnation it does not allow getting/setting of attributes, only
|
||||
core User model fields (username, email, password).
|
||||
|
||||
|
||||
"""
|
||||
class Meta:
|
||||
"""
|
||||
This is a Django construct that provides additional configuration to
|
||||
the form.
|
||||
|
||||
|
||||
"""
|
||||
# The model/typeclass this form creates
|
||||
model = class_from_module(settings.BASE_ACCOUNT_TYPECLASS)
|
||||
|
||||
|
||||
# The fields to display on the form, in the given order
|
||||
fields = ("username", "email")
|
||||
|
||||
|
||||
# Any overrides of field classes
|
||||
field_classes = {'username': UsernameField}
|
||||
|
||||
|
||||
# Username is collected as part of the core UserCreationForm, so we just need
|
||||
# to add a field to (optionally) capture email.
|
||||
email = forms.EmailField(help_text="A valid email address. Optional; used for password resets.", required=False)
|
||||
|
||||
|
||||
class ObjectForm(EvenniaForm, ModelForm):
|
||||
"""
|
||||
This is a Django form for generic Evennia Objects that allows modification
|
||||
of attributes when called from a descendent of ObjectUpdate or ObjectCreate
|
||||
views.
|
||||
|
||||
|
||||
It defines no fields by default; you have to do that by extending this class
|
||||
and defining what fields you want to be recorded. See the CharacterForm for
|
||||
a simple example of how to do this.
|
||||
|
||||
|
||||
"""
|
||||
class Meta:
|
||||
"""
|
||||
This is a Django construct that provides additional configuration to
|
||||
the form.
|
||||
|
||||
|
||||
"""
|
||||
# The model/typeclass this form creates
|
||||
model = class_from_module(settings.BASE_OBJECT_TYPECLASS)
|
||||
|
||||
|
||||
# The fields to display on the form, in the given order
|
||||
fields = ("db_key",)
|
||||
|
||||
|
||||
# This lets us rename ugly db-specific keys to something more human
|
||||
labels = {
|
||||
'db_key': 'Name',
|
||||
}
|
||||
|
||||
|
||||
class CharacterForm(ObjectForm):
|
||||
"""
|
||||
This is a Django form for Evennia Character objects.
|
||||
|
||||
|
||||
Since Evennia characters only have one attribute by default, this form only
|
||||
defines a field for that single attribute. The names of fields you define should
|
||||
correspond to their names as stored in the dbhandler; you can display
|
||||
defines a field for that single attribute. The names of fields you define should
|
||||
correspond to their names as stored in the dbhandler; you can display
|
||||
'prettier' versions of the fieldname on the form using the 'label' kwarg.
|
||||
|
||||
|
||||
The basic field types are CharFields and IntegerFields, which let you enter
|
||||
text and numbers respectively. IntegerFields have some neat validation tricks
|
||||
they can do, like mandating values fall within a certain range.
|
||||
|
||||
text and numbers respectively. IntegerFields have some neat validation tricks
|
||||
they can do, like mandating values fall within a certain range.
|
||||
|
||||
For example, a complete "age" field (which stores its value to
|
||||
`character.db.age` might look like:
|
||||
|
||||
|
||||
age = forms.IntegerField(
|
||||
label="Your Age",
|
||||
min_value=18, max_value=9000,
|
||||
min_value=18, max_value=9000,
|
||||
help_text="Years since your birth.")
|
||||
|
||||
Default input fields are generic single-line text boxes. You can control what
|
||||
sort of input field users will see by specifying a "widget." An example of
|
||||
|
||||
Default input fields are generic single-line text boxes. You can control what
|
||||
sort of input field users will see by specifying a "widget." An example of
|
||||
this is used for the 'desc' field to show a Textarea box instead of a Textbox.
|
||||
|
||||
|
||||
For help in building out your form, please see:
|
||||
https://docs.djangoproject.com/en/1.11/topics/forms/#building-a-form-in-django
|
||||
|
||||
|
||||
For more information on fields and their capabilities, see:
|
||||
https://docs.djangoproject.com/en/1.11/ref/forms/fields/
|
||||
|
||||
|
||||
For more on widgets, see:
|
||||
https://docs.djangoproject.com/en/1.11/ref/forms/widgets/
|
||||
|
||||
|
||||
"""
|
||||
class Meta:
|
||||
"""
|
||||
This is a Django construct that provides additional configuration to
|
||||
the form.
|
||||
|
||||
|
||||
"""
|
||||
# Get the correct object model
|
||||
model = class_from_module(settings.BASE_CHARACTER_TYPECLASS)
|
||||
|
||||
|
||||
# Allow entry of the 'key' field
|
||||
fields = ("db_key",)
|
||||
|
||||
|
||||
# Rename 'key' to something more intelligible
|
||||
labels = {
|
||||
'db_key': 'Name',
|
||||
}
|
||||
|
||||
|
||||
# Fields pertaining to configurable attributes on the Character object.
|
||||
desc = forms.CharField(label='Description', max_length=2048, required=False,
|
||||
desc = forms.CharField(
|
||||
label='Description', max_length=2048, required=False,
|
||||
widget=forms.Textarea(attrs={'rows': 3}),
|
||||
help_text="A brief description of your character.")
|
||||
|
||||
|
||||
|
||||
class CharacterUpdateForm(CharacterForm):
|
||||
"""
|
||||
This is a Django form for updating Evennia Character objects.
|
||||
|
||||
|
||||
By default it is the same as the CharacterForm, but if there are circumstances
|
||||
in which you don't want to let players edit all the same attributes they had
|
||||
access to during creation, you can redefine this form with those fields you do
|
||||
wish to allow.
|
||||
|
||||
|
||||
"""
|
||||
pass
|
||||
pass
|
||||
|
|
|
|||
|
|
@ -1,24 +1,22 @@
|
|||
"""
|
||||
This file contains the generic, assorted views that don't fall under one of the other applications.
|
||||
Views are django's way of processing e.g. html templates on the fly.
|
||||
|
||||
"""
|
||||
This file contains the generic, assorted views that don't fall under one of
|
||||
the other applications. Views are django's way of processing e.g. html
|
||||
templates on the fly.
|
||||
|
||||
"""
|
||||
from collections import OrderedDict
|
||||
|
||||
from django.contrib.admin.sites import site
|
||||
from django.conf import settings
|
||||
from django.contrib import messages
|
||||
from django.contrib.auth import authenticate
|
||||
from django.contrib.auth.mixins import LoginRequiredMixin
|
||||
from django.contrib.admin.views.decorators import staff_member_required
|
||||
from django.core.exceptions import PermissionDenied
|
||||
from django.db.models.functions import Lower
|
||||
from django.http import HttpResponseBadRequest, HttpResponseRedirect, Http404
|
||||
from django.http import HttpResponseBadRequest, HttpResponseRedirect
|
||||
from django.shortcuts import render
|
||||
from django.urls import reverse, reverse_lazy
|
||||
from django.views.generic import View, TemplateView, ListView, DetailView, FormView
|
||||
from django.urls import reverse_lazy
|
||||
from django.views.generic import TemplateView, ListView, DetailView
|
||||
from django.views.generic.base import RedirectView
|
||||
from django.views.generic.edit import CreateView, UpdateView, DeleteView
|
||||
|
||||
|
|
@ -26,15 +24,15 @@ from evennia import SESSION_HANDLER
|
|||
from evennia.help.models import HelpEntry
|
||||
from evennia.objects.models import ObjectDB
|
||||
from evennia.accounts.models import AccountDB
|
||||
from evennia.utils import class_from_module, logger
|
||||
from evennia.utils import class_from_module
|
||||
from evennia.utils.logger import tail_log_file
|
||||
from evennia.web.website.forms import *
|
||||
from evennia.web.website import forms as website_forms
|
||||
|
||||
from django.contrib.auth import login
|
||||
from django.utils.text import slugify
|
||||
|
||||
_BASE_CHAR_TYPECLASS = settings.BASE_CHARACTER_TYPECLASS
|
||||
|
||||
|
||||
def _gamestats():
|
||||
# Some misc. configurable stuff.
|
||||
# TODO: Move this to either SQL or settings.py based configuration.
|
||||
|
|
@ -49,8 +47,10 @@ def _gamestats():
|
|||
# nsess = len(AccountDB.objects.get_connected_accounts()) or "no one"
|
||||
|
||||
nobjs = ObjectDB.objects.all().count()
|
||||
nrooms = ObjectDB.objects.filter(db_location__isnull=True).exclude(db_typeclass_path=_BASE_CHAR_TYPECLASS).count()
|
||||
nexits = ObjectDB.objects.filter(db_location__isnull=False, db_destination__isnull=False).count()
|
||||
nrooms = ObjectDB.objects.filter(
|
||||
db_location__isnull=True).exclude(db_typeclass_path=_BASE_CHAR_TYPECLASS).count()
|
||||
nexits = ObjectDB.objects.filter(
|
||||
db_location__isnull=False, db_destination__isnull=False).count()
|
||||
nchars = ObjectDB.objects.filter(db_typeclass_path=_BASE_CHAR_TYPECLASS).count()
|
||||
nothers = nobjs - nrooms - nchars - nexits
|
||||
|
||||
|
|
@ -99,6 +99,7 @@ def admin_wrapper(request):
|
|||
"""
|
||||
return staff_member_required(site.index)(request)
|
||||
|
||||
|
||||
#
|
||||
# Class-based views
|
||||
#
|
||||
|
|
@ -237,6 +238,7 @@ class EvenniaDeleteView(DeleteView, TypeclassMixin):
|
|||
# Makes sure the page has a sensible title.
|
||||
return 'Delete %s' % self.typeclass._meta.verbose_name.title()
|
||||
|
||||
|
||||
#
|
||||
# Object views
|
||||
#
|
||||
|
|
@ -336,8 +338,9 @@ class ObjectDetailView(EvenniaDetailView):
|
|||
|
||||
# Check if this object was requested in a valid manner
|
||||
if slugify(obj.name) != self.kwargs.get(self.slug_url_kwarg):
|
||||
raise HttpResponseBadRequest(u"No %(verbose_name)s found matching the query" %
|
||||
{'verbose_name': queryset.model._meta.verbose_name})
|
||||
raise HttpResponseBadRequest(
|
||||
u"No %(verbose_name)s found matching the query" %
|
||||
{'verbose_name': queryset.model._meta.verbose_name})
|
||||
|
||||
# Check if the requestor account has permissions to access object
|
||||
account = self.request.user
|
||||
|
|
@ -430,7 +433,8 @@ class ObjectUpdateView(LoginRequiredMixin, ObjectDetailView, EvenniaUpdateView):
|
|||
object detail page so the user can see their changes reflected.
|
||||
|
||||
"""
|
||||
if self.success_url: return self.success_url
|
||||
if self.success_url:
|
||||
return self.success_url
|
||||
return self.object.web_get_detail_url()
|
||||
|
||||
def get_initial(self):
|
||||
|
|
@ -448,10 +452,10 @@ class ObjectUpdateView(LoginRequiredMixin, ObjectDetailView, EvenniaUpdateView):
|
|||
obj = self.get_object()
|
||||
|
||||
# Get attributes
|
||||
data = {k:getattr(obj.db, k, '') for k in self.form_class.base_fields}
|
||||
data = {k: getattr(obj.db, k, '') for k in self.form_class.base_fields}
|
||||
|
||||
# Get model fields
|
||||
data.update({k:getattr(obj, k, '') for k in self.form_class.Meta.fields})
|
||||
data.update({k: getattr(obj, k, '') for k in self.form_class.Meta.fields})
|
||||
|
||||
return data
|
||||
|
||||
|
|
@ -471,17 +475,18 @@ class ObjectUpdateView(LoginRequiredMixin, ObjectDetailView, EvenniaUpdateView):
|
|||
|
||||
"""
|
||||
# Get the attributes after they've been cleaned and validated
|
||||
data = {k:v for k,v in form.cleaned_data.items() if k not in self.form_class.Meta.fields}
|
||||
data = {k: v for k, v in form.cleaned_data.items() if k not in self.form_class.Meta.fields}
|
||||
|
||||
# Update the object attributes
|
||||
for key, value in data.items():
|
||||
setattr(self.object.db, key, value)
|
||||
self.object.attributes.add(key, value)
|
||||
messages.success(self.request, "Successfully updated '%s' for %s." % (key, self.object))
|
||||
|
||||
# Do not return super().form_valid; we don't want to update the model
|
||||
# instance, just its attributes.
|
||||
return HttpResponseRedirect(self.get_success_url())
|
||||
|
||||
|
||||
#
|
||||
# Account views
|
||||
#
|
||||
|
|
@ -496,7 +501,7 @@ class AccountMixin(TypeclassMixin):
|
|||
"""
|
||||
# -- Django constructs --
|
||||
model = class_from_module(settings.BASE_ACCOUNT_TYPECLASS)
|
||||
form_class = AccountForm
|
||||
form_class = website_forms.AccountForm
|
||||
|
||||
|
||||
class AccountCreateView(AccountMixin, EvenniaCreateView):
|
||||
|
|
@ -537,11 +542,13 @@ class AccountCreateView(AccountMixin, EvenniaCreateView):
|
|||
return self.form_invalid(form)
|
||||
|
||||
# Inform user of success
|
||||
messages.success(self.request, "Your account '%s' was successfully created! You may log in using it now." % account.name)
|
||||
messages.success(self.request, "Your account '%s' was successfully created! "
|
||||
"You may log in using it now." % account.name)
|
||||
|
||||
# Redirect the user to the login page
|
||||
return HttpResponseRedirect(self.success_url)
|
||||
|
||||
|
||||
#
|
||||
# Character views
|
||||
#
|
||||
|
|
@ -556,7 +563,7 @@ class CharacterMixin(TypeclassMixin):
|
|||
"""
|
||||
# -- Django constructs --
|
||||
model = class_from_module(settings.BASE_CHARACTER_TYPECLASS)
|
||||
form_class = CharacterForm
|
||||
form_class = website_forms.CharacterForm
|
||||
success_url = reverse_lazy('character-manage')
|
||||
|
||||
def get_queryset(self):
|
||||
|
|
@ -608,7 +615,8 @@ class CharacterListView(LoginRequiredMixin, CharacterMixin, ListView):
|
|||
|
||||
# Return a queryset consisting of characters the user is allowed to
|
||||
# see.
|
||||
ids = [obj.id for obj in self.typeclass.objects.all() if obj.access(account, self.access_type)]
|
||||
ids = [obj.id for obj in self.typeclass.objects.all()
|
||||
if obj.access(account, self.access_type)]
|
||||
|
||||
return self.typeclass.objects.filter(id__in=ids).order_by(Lower('db_key'))
|
||||
|
||||
|
|
@ -637,7 +645,7 @@ class CharacterPuppetView(LoginRequiredMixin, CharacterMixin, RedirectView, Obje
|
|||
char = self.get_object()
|
||||
|
||||
# Get the page the user came from
|
||||
next = self.request.GET.get('next', self.success_url)
|
||||
next_page = self.request.GET.get('next', self.success_url)
|
||||
|
||||
if char:
|
||||
# If the account owns the char, store the ID of the char in the
|
||||
|
|
@ -650,7 +658,7 @@ class CharacterPuppetView(LoginRequiredMixin, CharacterMixin, RedirectView, Obje
|
|||
self.request.session['puppet'] = None
|
||||
messages.error(self.request, "You cannot become '%s'." % char)
|
||||
|
||||
return next
|
||||
return next_page
|
||||
|
||||
|
||||
class CharacterManageView(LoginRequiredMixin, CharacterMixin, ListView):
|
||||
|
|
@ -674,7 +682,7 @@ class CharacterUpdateView(CharacterMixin, ObjectUpdateView):
|
|||
|
||||
"""
|
||||
# -- Django constructs --
|
||||
form_class = CharacterUpdateForm
|
||||
form_class = website_forms.CharacterUpdateForm
|
||||
template_name = 'website/character_form.html'
|
||||
|
||||
|
||||
|
|
@ -705,7 +713,8 @@ class CharacterDetailView(CharacterMixin, ObjectDetailView):
|
|||
|
||||
# Return a queryset consisting of characters the user is allowed to
|
||||
# see.
|
||||
ids = [obj.id for obj in self.typeclass.objects.all() if obj.access(account, self.access_type)]
|
||||
ids = [obj.id for obj in self.typeclass.objects.all()
|
||||
if obj.access(account, self.access_type)]
|
||||
|
||||
return self.typeclass.objects.filter(id__in=ids).order_by(Lower('db_key'))
|
||||
|
||||
|
|
@ -746,7 +755,6 @@ class CharacterCreateView(CharacterMixin, ObjectCreateView):
|
|||
self.attributes = {k: form.cleaned_data[k] for k in form.cleaned_data.keys()}
|
||||
charname = self.attributes.pop('db_key')
|
||||
description = self.attributes.pop('desc')
|
||||
|
||||
# Create a character
|
||||
character, errors = self.typeclass.create(charname, account, description=description)
|
||||
|
||||
|
|
@ -756,7 +764,7 @@ class CharacterCreateView(CharacterMixin, ObjectCreateView):
|
|||
|
||||
if character:
|
||||
# Assign attributes from form
|
||||
for key,value in self.attributes.items():
|
||||
for key, value in self.attributes.items():
|
||||
setattr(character.db, key, value)
|
||||
|
||||
# Return the user to the character management page, unless overridden
|
||||
|
|
@ -768,6 +776,7 @@ class CharacterCreateView(CharacterMixin, ObjectCreateView):
|
|||
messages.error(self.request, "Your character could not be created.")
|
||||
return self.form_invalid(form)
|
||||
|
||||
|
||||
#
|
||||
# Channel views
|
||||
#
|
||||
|
|
@ -881,12 +890,14 @@ class ChannelDetailView(ChannelMixin, ObjectDetailView):
|
|||
context = super(ChannelDetailView, self).get_context_data(**kwargs)
|
||||
|
||||
# Get the filename this Channel is recording to
|
||||
filename = self.object.attributes.get("log_file", default="channel_%s.log" % self.object.key)
|
||||
filename = self.object.attributes.get(
|
||||
"log_file", default="channel_%s.log" % self.object.key)
|
||||
|
||||
# Split log entries so we can filter by time
|
||||
bucket = []
|
||||
for log in (x.strip() for x in tail_log_file(filename, 0, self.max_num_lines)):
|
||||
if not log: continue
|
||||
if not log:
|
||||
continue
|
||||
time, msg = log.split(' [-] ')
|
||||
time_key = time.split(':')[0]
|
||||
|
||||
|
|
@ -904,7 +915,6 @@ class ChannelDetailView(ChannelMixin, ObjectDetailView):
|
|||
|
||||
return context
|
||||
|
||||
|
||||
def get_object(self, queryset=None):
|
||||
"""
|
||||
Override of Django hook that retrieves an object by slugified channel
|
||||
|
|
@ -924,8 +934,9 @@ class ChannelDetailView(ChannelMixin, ObjectDetailView):
|
|||
|
||||
# Check if this object was requested in a valid manner
|
||||
if not obj:
|
||||
raise HttpResponseBadRequest(u"No %(verbose_name)s found matching the query" %
|
||||
{'verbose_name': queryset.model._meta.verbose_name})
|
||||
raise HttpResponseBadRequest(
|
||||
u"No %(verbose_name)s found matching the query" %
|
||||
{'verbose_name': queryset.model._meta.verbose_name})
|
||||
|
||||
return obj
|
||||
|
||||
|
|
@ -976,6 +987,7 @@ class HelpMixin(TypeclassMixin):
|
|||
|
||||
return filtered
|
||||
|
||||
|
||||
class HelpListView(HelpMixin, ListView):
|
||||
"""
|
||||
Returns a list of help entries that can be viewed by a user, authenticated
|
||||
|
|
@ -989,6 +1001,7 @@ class HelpListView(HelpMixin, ListView):
|
|||
# -- Evennia constructs --
|
||||
page_title = "Help Index"
|
||||
|
||||
|
||||
class HelpDetailView(HelpMixin, EvenniaDetailView):
|
||||
"""
|
||||
Returns the detail page for a given help entry.
|
||||
|
|
@ -1012,7 +1025,8 @@ class HelpDetailView(HelpMixin, EvenniaDetailView):
|
|||
obj = self.get_object()
|
||||
|
||||
# Get queryset and filter out non-related categories
|
||||
queryset = self.get_queryset().filter(db_help_category=obj.db_help_category).order_by(Lower('db_key'))
|
||||
queryset = self.get_queryset().filter(
|
||||
db_help_category=obj.db_help_category).order_by(Lower('db_key'))
|
||||
context['topic_list'] = queryset
|
||||
|
||||
# Find the index position of the given obj in the queryset
|
||||
|
|
@ -1025,12 +1039,14 @@ class HelpDetailView(HelpMixin, EvenniaDetailView):
|
|||
try:
|
||||
assert i+1 <= len(objs) and objs[i+1] is not obj
|
||||
context['topic_next'] = objs[i+1]
|
||||
except: context['topic_next'] = None
|
||||
except:
|
||||
context['topic_next'] = None
|
||||
|
||||
try:
|
||||
assert i-1 >= 0 and objs[i-1] is not obj
|
||||
context['topic_previous'] = objs[i-1]
|
||||
except: context['topic_previous'] = None
|
||||
except:
|
||||
context['topic_previous'] = None
|
||||
|
||||
# Format the help entry using HTML instead of newlines
|
||||
text = obj.db_entrytext
|
||||
|
|
@ -1057,11 +1073,14 @@ class HelpDetailView(HelpMixin, EvenniaDetailView):
|
|||
# Find the object in the queryset
|
||||
category = slugify(self.kwargs.get('category', ''))
|
||||
topic = slugify(self.kwargs.get('topic', ''))
|
||||
obj = next((x for x in queryset if slugify(x.db_help_category)==category and slugify(x.db_key)==topic), None)
|
||||
obj = next((x for x in queryset
|
||||
if slugify(x.db_help_category) == category and
|
||||
slugify(x.db_key) == topic), None)
|
||||
|
||||
# Check if this object was requested in a valid manner
|
||||
if not obj:
|
||||
raise HttpResponseBadRequest(u"No %(verbose_name)s found matching the query" %
|
||||
{'verbose_name': queryset.model._meta.verbose_name})
|
||||
raise HttpResponseBadRequest(
|
||||
u"No %(verbose_name)s found matching the query" %
|
||||
{'verbose_name': queryset.model._meta.verbose_name})
|
||||
|
||||
return obj
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue