Made all unit tests pass
This commit is contained in:
parent
844b04adbb
commit
aa48593a40
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
|
||||
|
|
|
|||
|
|
@ -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'
|
||||
|
|
|
|||
|
|
@ -140,10 +140,12 @@ class CharacterForm(ObjectForm):
|
|||
}
|
||||
|
||||
# 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.
|
||||
|
|
|
|||
|
|
@ -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,7 +338,8 @@ 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" %
|
||||
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
|
||||
|
|
@ -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):
|
||||
|
|
@ -475,13 +479,14 @@ class ObjectUpdateView(LoginRequiredMixin, ObjectDetailView, EvenniaUpdateView):
|
|||
|
||||
# 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)
|
||||
|
||||
|
|
@ -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,7 +934,8 @@ 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" %
|
||||
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" %
|
||||
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