From a0bed8f2b58e3877feb5f74f4499592e5b9261c0 Mon Sep 17 00:00:00 2001 From: Johnny Date: Fri, 5 Oct 2018 22:02:20 +0000 Subject: [PATCH 1/6] Adds get_absolute_url() and get_admin_url() methods to DefaultObject, DefaultCharacter, Account and DefaultRoom objects. --- evennia/accounts/accounts.py | 21 +++++++++++++++++ evennia/accounts/tests.py | 13 +++++++++++ evennia/objects/objects.py | 44 ++++++++++++++++++++++++++++++++++++ evennia/objects/tests.py | 11 +++++++++ 4 files changed, 89 insertions(+) create mode 100644 evennia/objects/tests.py diff --git a/evennia/accounts/accounts.py b/evennia/accounts/accounts.py index 2c33e5c1f8..f90575edd2 100644 --- a/evennia/accounts/accounts.py +++ b/evennia/accounts/accounts.py @@ -14,7 +14,9 @@ instead for most things). import time from django.conf import settings from django.contrib.auth import password_validation +from django.contrib.contenttypes.models import ContentType from django.core.exceptions import ValidationError +from django.urls import reverse_lazy from django.utils import timezone from evennia.typeclasses.models import TypeclassBase from evennia.accounts.manager import AccountManager @@ -189,6 +191,25 @@ class DefaultAccount(with_metaclass(TypeclassBase, AccountDB)): @lazy_property def sessions(self): return AccountSessionHandler(self) + + def get_absolute_url(self): + """ + Returns the canonical URL for an Account. + + To callers, this method should appear to return a string that can be + used to refer to the object over HTTP. + + https://docs.djangoproject.com/en/2.1/ref/models/instances/#get-absolute-url + """ + try: return reverse_lazy('account-detail', kwargs={'pk': self.pk, 'slug': slugify(self.name)}) + except: return '#' + + def get_admin_url(self): + """ + Returns a link to this object's entry within the Django Admin panel. + """ + content_type = ContentType.objects.get_for_model(self.__class__) + return reverse_lazy("admin:%s_%s_change" % (content_type.app_label, content_type.model), args=(self.id,)) # session-related methods diff --git a/evennia/accounts/tests.py b/evennia/accounts/tests.py index 2855dd0ca2..4d941782ad 100644 --- a/evennia/accounts/tests.py +++ b/evennia/accounts/tests.py @@ -59,6 +59,19 @@ class TestDefaultAccount(TestCase): self.s1 = Session() self.s1.puppet = None self.s1.sessid = 0 + + def test_absolute_url(self): + "Get URL for account detail page on website" + self.account = create.create_account("TestAccount%s" % randint(100000, 999999), + email="test@test.com", password="testpassword", typeclass=DefaultAccount) + self.assertTrue(self.account.get_absolute_url()) + + def test_admin_url(self): + "Get object's URL for access via Admin pane" + self.account = create.create_account("TestAccount%s" % randint(100000, 999999), + email="test@test.com", password="testpassword", typeclass=DefaultAccount) + self.assertTrue(self.account.get_admin_url()) + self.assertTrue(self.account.get_admin_url() != '#') def test_password_validation(self): "Check password validators deny bad passwords" diff --git a/evennia/objects/objects.py b/evennia/objects/objects.py index 27d8147999..167cd60612 100644 --- a/evennia/objects/objects.py +++ b/evennia/objects/objects.py @@ -12,6 +12,9 @@ from future.utils import with_metaclass from collections import defaultdict from django.conf import settings +from django.contrib.contenttypes.models import ContentType +from django.urls import reverse +from django.utils.text import slugify from evennia.typeclasses.models import TypeclassBase from evennia.typeclasses.attributes import NickHandler @@ -324,6 +327,25 @@ class DefaultObject(with_metaclass(TypeclassBase, ObjectDB)): # look at 'an egg'. self.aliases.add(singular, category="plural_key") return singular, plural + + def get_absolute_url(self): + """ + Returns the canonical URL for an object. + + To callers, this method should appear to return a string that can be + used to refer to the object over HTTP. + + https://docs.djangoproject.com/en/2.1/ref/models/instances/#get-absolute-url + """ + try: return reverse('object-detail', kwargs={'pk': self.pk, 'slug': slugify(self.name)}) + except: return '#' + + def get_admin_url(self): + """ + Returns a link to this object's entry within the Django Admin panel. + """ + content_type = ContentType.objects.get_for_model(self.__class__) + return reverse("admin:%s_%s_change" % (content_type.app_label, content_type.model), args=(self.id,)) def search(self, searchdata, global_search=False, @@ -1821,6 +1843,17 @@ class DefaultCharacter(DefaultObject): a character avatar controlled by an account. """ + def get_absolute_url(self): + """ + Returns the canonical URL for a Character. + + To callers, this method should appear to return a string that can be + used to refer to the object over HTTP. + + https://docs.djangoproject.com/en/2.1/ref/models/instances/#get-absolute-url + """ + try: return reverse('character-detail', kwargs={'pk': self.pk, 'slug': slugify(self.name)}) + except: return super(DefaultCharacter, self).get_absolute_url() def basetype_setup(self): """ @@ -1938,6 +1971,17 @@ class DefaultRoom(DefaultObject): This is the base room object. It's just like any Object except its location is always `None`. """ + def get_absolute_url(self): + """ + Returns the canonical URL for a Room. + + To callers, this method should appear to return a string that can be + used to refer to the object over HTTP. + + https://docs.djangoproject.com/en/2.1/ref/models/instances/#get-absolute-url + """ + try: return reverse('location-detail', kwargs={'pk': self.pk, 'slug': slugify(self.name)}) + except: return super(DefaultRoom, self).get_absolute_url() def basetype_setup(self): """ diff --git a/evennia/objects/tests.py b/evennia/objects/tests.py new file mode 100644 index 0000000000..f317f2c39c --- /dev/null +++ b/evennia/objects/tests.py @@ -0,0 +1,11 @@ +from evennia.utils.test_resources import EvenniaTest + +class DefaultObjectTest(EvenniaTest): + + def test_urls(self): + "Make sure objects are returning URLs" + self.assertTrue(self.char1.get_absolute_url()) + self.assertTrue('admin' in self.char1.get_admin_url()) + + self.assertTrue(self.room1.get_absolute_url()) + self.assertTrue('admin' in self.room1.get_admin_url()) \ No newline at end of file From fc55f0f2a14d56cbfae673d119f08f78d107d35f Mon Sep 17 00:00:00 2001 From: Johnny Date: Fri, 5 Oct 2018 22:30:12 +0000 Subject: [PATCH 2/6] Adds dynamic get_*_url() fields to DefaultObject and children and static get_*_url() fields to DefaultAccount. --- evennia/accounts/accounts.py | 16 +++++++++++ evennia/objects/objects.py | 56 +++++++++++++++++++----------------- 2 files changed, 46 insertions(+), 26 deletions(-) diff --git a/evennia/accounts/accounts.py b/evennia/accounts/accounts.py index f90575edd2..bd1fb4f573 100644 --- a/evennia/accounts/accounts.py +++ b/evennia/accounts/accounts.py @@ -204,6 +204,22 @@ class DefaultAccount(with_metaclass(TypeclassBase, AccountDB)): try: return reverse_lazy('account-detail', kwargs={'pk': self.pk, 'slug': slugify(self.name)}) except: return '#' + def get_delete_url(self): + """ + Returns the canonical URL to the page that allows deleting an object. + + """ + try: return reverse('account-delete', kwargs={'pk': self.pk, 'slug': slugify(self.name)}) + except: return '#' + + def get_update_url(self): + """ + Returns the canonical URL to the page that allows updating an object. + + """ + try: return reverse('account-update', kwargs={'pk': self.pk, 'slug': slugify(self.name)}) + except: return '#' + def get_admin_url(self): """ Returns a link to this object's entry within the Django Admin panel. diff --git a/evennia/objects/objects.py b/evennia/objects/objects.py index 167cd60612..71ccb28f77 100644 --- a/evennia/objects/objects.py +++ b/evennia/objects/objects.py @@ -7,6 +7,7 @@ entities. """ import time import inflect +import re from builtins import object from future.utils import with_metaclass from collections import defaultdict @@ -328,21 +329,48 @@ class DefaultObject(with_metaclass(TypeclassBase, ObjectDB)): self.aliases.add(singular, category="plural_key") return singular, plural + def get_url_prefix(self): + """ + Derives the object name from the class name. + + i.e. 'DefaultAccount' = 'default-account', 'Character' = 'character' + """ + klass = self.__class__.__name__ + terms = [x.lower() for x in re.split('([A-Z][a-z]+)', klass) if x] + return slugify(' '.join(terms)) + def get_absolute_url(self): """ - Returns the canonical URL for an object. + Returns the canonical URL to view an object. To callers, this method should appear to return a string that can be used to refer to the object over HTTP. https://docs.djangoproject.com/en/2.1/ref/models/instances/#get-absolute-url """ - try: return reverse('object-detail', kwargs={'pk': self.pk, 'slug': slugify(self.name)}) + try: return reverse('%s-detail' % self.get_url_prefix(), kwargs={'pk': self.pk, 'slug': slugify(self.name)}) + except: return '#' + + def get_delete_url(self): + """ + Returns the canonical URL to the page that allows deleting an object. + + """ + try: return reverse('%s-delete' % self.get_url_prefix(), kwargs={'pk': self.pk, 'slug': slugify(self.name)}) + except: return '#' + + def get_update_url(self): + """ + Returns the canonical URL to the page that allows updating an object. + + """ + try: return reverse('%s-update' % self.get_url_prefix(), kwargs={'pk': self.pk, 'slug': slugify(self.name)}) except: return '#' def get_admin_url(self): """ Returns a link to this object's entry within the Django Admin panel. + """ content_type = ContentType.objects.get_for_model(self.__class__) return reverse("admin:%s_%s_change" % (content_type.app_label, content_type.model), args=(self.id,)) @@ -1843,18 +1871,6 @@ class DefaultCharacter(DefaultObject): a character avatar controlled by an account. """ - def get_absolute_url(self): - """ - Returns the canonical URL for a Character. - - To callers, this method should appear to return a string that can be - used to refer to the object over HTTP. - - https://docs.djangoproject.com/en/2.1/ref/models/instances/#get-absolute-url - """ - try: return reverse('character-detail', kwargs={'pk': self.pk, 'slug': slugify(self.name)}) - except: return super(DefaultCharacter, self).get_absolute_url() - def basetype_setup(self): """ Setup character-specific security. @@ -1971,18 +1987,6 @@ class DefaultRoom(DefaultObject): This is the base room object. It's just like any Object except its location is always `None`. """ - def get_absolute_url(self): - """ - Returns the canonical URL for a Room. - - To callers, this method should appear to return a string that can be - used to refer to the object over HTTP. - - https://docs.djangoproject.com/en/2.1/ref/models/instances/#get-absolute-url - """ - try: return reverse('location-detail', kwargs={'pk': self.pk, 'slug': slugify(self.name)}) - except: return super(DefaultRoom, self).get_absolute_url() - def basetype_setup(self): """ Simple room setup setting locks to make sure the room From 7830f34dc360e9d90a3f2a6c1698ed92d867a413 Mon Sep 17 00:00:00 2001 From: Johnny Date: Fri, 5 Oct 2018 22:34:34 +0000 Subject: [PATCH 3/6] Makes lazy reversals not lazy; prevents errors from manifesting out of scope. --- evennia/accounts/accounts.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/evennia/accounts/accounts.py b/evennia/accounts/accounts.py index bd1fb4f573..6631911dc8 100644 --- a/evennia/accounts/accounts.py +++ b/evennia/accounts/accounts.py @@ -16,7 +16,7 @@ from django.conf import settings from django.contrib.auth import password_validation from django.contrib.contenttypes.models import ContentType from django.core.exceptions import ValidationError -from django.urls import reverse_lazy +from django.urls import reverse from django.utils import timezone from evennia.typeclasses.models import TypeclassBase from evennia.accounts.manager import AccountManager @@ -201,7 +201,7 @@ class DefaultAccount(with_metaclass(TypeclassBase, AccountDB)): https://docs.djangoproject.com/en/2.1/ref/models/instances/#get-absolute-url """ - try: return reverse_lazy('account-detail', kwargs={'pk': self.pk, 'slug': slugify(self.name)}) + try: return reverse('account-detail', kwargs={'pk': self.pk, 'slug': slugify(self.name)}) except: return '#' def get_delete_url(self): @@ -225,7 +225,7 @@ class DefaultAccount(with_metaclass(TypeclassBase, AccountDB)): Returns a link to this object's entry within the Django Admin panel. """ content_type = ContentType.objects.get_for_model(self.__class__) - return reverse_lazy("admin:%s_%s_change" % (content_type.app_label, content_type.model), args=(self.id,)) + return reverse("admin:%s_%s_change" % (content_type.app_label, content_type.model), args=(self.id,)) # session-related methods From b37e3a8b25bee8052c5611e3312028fef4d57bdd Mon Sep 17 00:00:00 2001 From: Johnny Date: Wed, 17 Oct 2018 22:52:06 +0000 Subject: [PATCH 4/6] Renames all URL methods to web_*, moves to TypedObject model. --- evennia/accounts/accounts.py | 37 --------- evennia/accounts/tests.py | 6 +- evennia/objects/objects.py | 46 ----------- evennia/typeclasses/models.py | 145 ++++++++++++++++++++++++++++++++++ 4 files changed, 148 insertions(+), 86 deletions(-) diff --git a/evennia/accounts/accounts.py b/evennia/accounts/accounts.py index 6631911dc8..2c33e5c1f8 100644 --- a/evennia/accounts/accounts.py +++ b/evennia/accounts/accounts.py @@ -14,9 +14,7 @@ instead for most things). import time from django.conf import settings from django.contrib.auth import password_validation -from django.contrib.contenttypes.models import ContentType from django.core.exceptions import ValidationError -from django.urls import reverse from django.utils import timezone from evennia.typeclasses.models import TypeclassBase from evennia.accounts.manager import AccountManager @@ -191,41 +189,6 @@ class DefaultAccount(with_metaclass(TypeclassBase, AccountDB)): @lazy_property def sessions(self): return AccountSessionHandler(self) - - def get_absolute_url(self): - """ - Returns the canonical URL for an Account. - - To callers, this method should appear to return a string that can be - used to refer to the object over HTTP. - - https://docs.djangoproject.com/en/2.1/ref/models/instances/#get-absolute-url - """ - try: return reverse('account-detail', kwargs={'pk': self.pk, 'slug': slugify(self.name)}) - except: return '#' - - def get_delete_url(self): - """ - Returns the canonical URL to the page that allows deleting an object. - - """ - try: return reverse('account-delete', kwargs={'pk': self.pk, 'slug': slugify(self.name)}) - except: return '#' - - def get_update_url(self): - """ - Returns the canonical URL to the page that allows updating an object. - - """ - try: return reverse('account-update', kwargs={'pk': self.pk, 'slug': slugify(self.name)}) - except: return '#' - - def get_admin_url(self): - """ - Returns a link to this object's entry within the Django Admin panel. - """ - content_type = ContentType.objects.get_for_model(self.__class__) - return reverse("admin:%s_%s_change" % (content_type.app_label, content_type.model), args=(self.id,)) # session-related methods diff --git a/evennia/accounts/tests.py b/evennia/accounts/tests.py index 4d941782ad..fbf976d644 100644 --- a/evennia/accounts/tests.py +++ b/evennia/accounts/tests.py @@ -64,14 +64,14 @@ class TestDefaultAccount(TestCase): "Get URL for account detail page on website" self.account = create.create_account("TestAccount%s" % randint(100000, 999999), email="test@test.com", password="testpassword", typeclass=DefaultAccount) - self.assertTrue(self.account.get_absolute_url()) + self.assertTrue(self.account.web_detail_url()) def test_admin_url(self): "Get object's URL for access via Admin pane" self.account = create.create_account("TestAccount%s" % randint(100000, 999999), email="test@test.com", password="testpassword", typeclass=DefaultAccount) - self.assertTrue(self.account.get_admin_url()) - self.assertTrue(self.account.get_admin_url() != '#') + self.assertTrue(self.account.web_admin_url()) + self.assertTrue(self.account.web_admin_url() != '#') def test_password_validation(self): "Check password validators deny bad passwords" diff --git a/evennia/objects/objects.py b/evennia/objects/objects.py index 71ccb28f77..027e8ff47f 100644 --- a/evennia/objects/objects.py +++ b/evennia/objects/objects.py @@ -329,52 +329,6 @@ class DefaultObject(with_metaclass(TypeclassBase, ObjectDB)): self.aliases.add(singular, category="plural_key") return singular, plural - def get_url_prefix(self): - """ - Derives the object name from the class name. - - i.e. 'DefaultAccount' = 'default-account', 'Character' = 'character' - """ - klass = self.__class__.__name__ - terms = [x.lower() for x in re.split('([A-Z][a-z]+)', klass) if x] - return slugify(' '.join(terms)) - - def get_absolute_url(self): - """ - Returns the canonical URL to view an object. - - To callers, this method should appear to return a string that can be - used to refer to the object over HTTP. - - https://docs.djangoproject.com/en/2.1/ref/models/instances/#get-absolute-url - """ - try: return reverse('%s-detail' % self.get_url_prefix(), kwargs={'pk': self.pk, 'slug': slugify(self.name)}) - except: return '#' - - def get_delete_url(self): - """ - Returns the canonical URL to the page that allows deleting an object. - - """ - try: return reverse('%s-delete' % self.get_url_prefix(), kwargs={'pk': self.pk, 'slug': slugify(self.name)}) - except: return '#' - - def get_update_url(self): - """ - Returns the canonical URL to the page that allows updating an object. - - """ - try: return reverse('%s-update' % self.get_url_prefix(), kwargs={'pk': self.pk, 'slug': slugify(self.name)}) - except: return '#' - - def get_admin_url(self): - """ - Returns a link to this object's entry within the Django Admin panel. - - """ - content_type = ContentType.objects.get_for_model(self.__class__) - return reverse("admin:%s_%s_change" % (content_type.app_label, content_type.model), args=(self.id,)) - def search(self, searchdata, global_search=False, use_nicks=True, diff --git a/evennia/typeclasses/models.py b/evennia/typeclasses/models.py index c156aa2ac6..098606b53c 100644 --- a/evennia/typeclasses/models.py +++ b/evennia/typeclasses/models.py @@ -31,9 +31,12 @@ from django.db.models import signals from django.db.models.base import ModelBase from django.db import models +from django.contrib.contenttypes.models import ContentType from django.core.exceptions import ObjectDoesNotExist from django.conf import settings +from django.urls import reverse from django.utils.encoding import smart_str +from django.utils.text import slugify from evennia.typeclasses.attributes import Attribute, AttributeHandler, NAttributeHandler from evennia.typeclasses.tags import Tag, TagHandler, AliasHandler, PermissionHandler @@ -733,3 +736,145 @@ class TypedObject(SharedMemoryModel): """ pass + + # + # Web/Django methods + # + + def web_admin_url(self): + """ + Returns the URI path for the Django Admin page for this object. + + ex. Account#1 = '/admin/accounts/accountdb/1/change/' + + Returns: + path (str): URI path to Django Admin page for object. + + """ + content_type = ContentType.objects.get_for_model(self.__class__) + return reverse("admin:%s_%s_change" % (content_type.app_label, content_type.model), args=(self.id,)) + + @classmethod + def web_create_url(cls): + """ + Returns the URI path for a View that allows users to create new + instances of this object. + + ex. Chargen = '/characters/create/' + + For this to work, the developer must have defined a named view somewhere + in urls.py that follows the format 'modelname-action', so in this case + a named view of 'character-create' would be referenced by this method. + + ex. + url(r'characters/create/', ChargenView.as_view(), name='character-create') + + If no View has been created and defined in urls.py, returns an + HTML anchor. + + This method is naive and simply returns a path. Securing access to + the actual view and limiting who can create new objects is the + developer's responsibility. + + Returns: + path (str): URI path to object creation page, if defined. + + """ + try: return reverse('%s-create' % cls._meta.verbose_name.lower()) + except: return '#' + + def web_detail_url(self): + """ + Returns the URI path for a View that allows users to view details for + this object. + + ex. Oscar (Character) = '/characters/oscar/1/' + + For this to work, the developer must have defined a named view somewhere + in urls.py that follows the format 'modelname-action', so in this case + a named view of 'character-detail' would be referenced by this method. + + ex. + url(r'characters/(?P[\w\d\-]+)/(?P[0-9]+)/$', CharDetailView.as_view(), name='character-detail') + + If no View has been created and defined in urls.py, returns an + HTML anchor. + + This method is naive and simply returns a path. Securing access to + the actual view and limiting who can view this object is the developer's + responsibility. + + Returns: + path (str): URI path to object detail page, if defined. + + """ + try: return reverse('%s-detail' % self._meta.verbose_name.lower(), kwargs={'pk': self.pk, 'slug': slugify(self.name)}) + except: return '#' + + def web_update_url(self): + """ + Returns the URI path for a View that allows users to update this + object. + + ex. Oscar (Character) = '/characters/oscar/1/change/' + + For this to work, the developer must have defined a named view somewhere + in urls.py that follows the format 'modelname-action', so in this case + a named view of 'character-update' would be referenced by this method. + + ex. + url(r'characters/(?P[\w\d\-]+)/(?P[0-9]+)/change/$', CharUpdateView.as_view(), name='character-update') + + If no View has been created and defined in urls.py, returns an + HTML anchor. + + This method is naive and simply returns a path. Securing access to + the actual view and limiting who can modify objects is the developer's + responsibility. + + Returns: + path (str): URI path to object update page, if defined. + + """ + try: return reverse('%s-update' % self._meta.verbose_name.lower(), kwargs={'pk': self.pk, 'slug': slugify(self.name)}) + except: return '#' + + def web_delete_url(self): + """ + Returns the URI path for a View that allows users to delete this object. + + ex. Oscar (Character) = '/characters/oscar/1/delete/' + + For this to work, the developer must have defined a named view somewhere + in urls.py that follows the format 'modelname-action', so in this case + a named view of 'character-detail' would be referenced by this method. + + ex. + url(r'characters/(?P[\w\d\-]+)/(?P[0-9]+)/delete/$', CharDeleteView.as_view(), name='character-delete') + + If no View has been created and defined in urls.py, returns an + HTML anchor. + + This method is naive and simply returns a path. Securing access to + the actual view and limiting who can delete this object is the developer's + responsibility. + + Returns: + path (str): URI path to object deletion page, if defined. + + """ + try: return reverse('%s-delete' % self._meta.verbose_name.lower(), kwargs={'pk': self.pk, 'slug': slugify(self.name)}) + except: return '#' + + def get_absolute_url(self): + """ + Django construct; used by Django Sites framework and within the Admin + panel for reverse linking to the object detail page. + + https://docs.djangoproject.com/en/2.1/ref/models/instances/#get-absolute-url + + Returns: + path (str): URI path to object detail page, if defined. + + """ + return self.web_detail_url() \ No newline at end of file From a5b759cff0555f55953473f06b245b6dcf5ef747 Mon Sep 17 00:00:00 2001 From: Johnny Date: Mon, 22 Oct 2018 20:33:56 +0000 Subject: [PATCH 5/6] Renames methods to web_get_* and fixes tests. --- evennia/accounts/tests.py | 6 +++--- evennia/objects/tests.py | 4 ++-- evennia/typeclasses/models.py | 24 +++++++----------------- 3 files changed, 12 insertions(+), 22 deletions(-) diff --git a/evennia/accounts/tests.py b/evennia/accounts/tests.py index fbf976d644..be07a30cbd 100644 --- a/evennia/accounts/tests.py +++ b/evennia/accounts/tests.py @@ -64,14 +64,14 @@ class TestDefaultAccount(TestCase): "Get URL for account detail page on website" self.account = create.create_account("TestAccount%s" % randint(100000, 999999), email="test@test.com", password="testpassword", typeclass=DefaultAccount) - self.assertTrue(self.account.web_detail_url()) + self.assertTrue(self.account.web_get_detail_url()) def test_admin_url(self): "Get object's URL for access via Admin pane" self.account = create.create_account("TestAccount%s" % randint(100000, 999999), email="test@test.com", password="testpassword", typeclass=DefaultAccount) - self.assertTrue(self.account.web_admin_url()) - self.assertTrue(self.account.web_admin_url() != '#') + self.assertTrue(self.account.web_get_admin_url()) + self.assertTrue(self.account.web_get_admin_url() != '#') def test_password_validation(self): "Check password validators deny bad passwords" diff --git a/evennia/objects/tests.py b/evennia/objects/tests.py index f317f2c39c..824007f287 100644 --- a/evennia/objects/tests.py +++ b/evennia/objects/tests.py @@ -5,7 +5,7 @@ class DefaultObjectTest(EvenniaTest): def test_urls(self): "Make sure objects are returning URLs" self.assertTrue(self.char1.get_absolute_url()) - self.assertTrue('admin' in self.char1.get_admin_url()) + self.assertTrue('admin' in self.char1.web_get_admin_url()) self.assertTrue(self.room1.get_absolute_url()) - self.assertTrue('admin' in self.room1.get_admin_url()) \ No newline at end of file + self.assertTrue('admin' in self.room1.web_get_admin_url()) \ No newline at end of file diff --git a/evennia/typeclasses/models.py b/evennia/typeclasses/models.py index 098606b53c..d549efb8ff 100644 --- a/evennia/typeclasses/models.py +++ b/evennia/typeclasses/models.py @@ -741,7 +741,7 @@ class TypedObject(SharedMemoryModel): # Web/Django methods # - def web_admin_url(self): + def web_get_admin_url(self): """ Returns the URI path for the Django Admin page for this object. @@ -755,7 +755,7 @@ class TypedObject(SharedMemoryModel): return reverse("admin:%s_%s_change" % (content_type.app_label, content_type.model), args=(self.id,)) @classmethod - def web_create_url(cls): + def web_get_create_url(cls): """ Returns the URI path for a View that allows users to create new instances of this object. @@ -783,7 +783,7 @@ class TypedObject(SharedMemoryModel): try: return reverse('%s-create' % cls._meta.verbose_name.lower()) except: return '#' - def web_detail_url(self): + def web_get_detail_url(self): """ Returns the URI path for a View that allows users to view details for this object. @@ -811,7 +811,7 @@ class TypedObject(SharedMemoryModel): try: return reverse('%s-detail' % self._meta.verbose_name.lower(), kwargs={'pk': self.pk, 'slug': slugify(self.name)}) except: return '#' - def web_update_url(self): + def web_get_update_url(self): """ Returns the URI path for a View that allows users to update this object. @@ -839,7 +839,7 @@ class TypedObject(SharedMemoryModel): try: return reverse('%s-update' % self._meta.verbose_name.lower(), kwargs={'pk': self.pk, 'slug': slugify(self.name)}) except: return '#' - def web_delete_url(self): + def web_get_delete_url(self): """ Returns the URI path for a View that allows users to delete this object. @@ -866,15 +866,5 @@ class TypedObject(SharedMemoryModel): try: return reverse('%s-delete' % self._meta.verbose_name.lower(), kwargs={'pk': self.pk, 'slug': slugify(self.name)}) except: return '#' - def get_absolute_url(self): - """ - Django construct; used by Django Sites framework and within the Admin - panel for reverse linking to the object detail page. - - https://docs.djangoproject.com/en/2.1/ref/models/instances/#get-absolute-url - - Returns: - path (str): URI path to object detail page, if defined. - - """ - return self.web_detail_url() \ No newline at end of file + # Used by Django Sites/Admin + get_absolute_url = web_get_detail_url \ No newline at end of file From 30547cb5bfbcb76165cc3a59f09f7afbb3be286f Mon Sep 17 00:00:00 2001 From: Griatch Date: Mon, 22 Oct 2018 23:32:12 +0200 Subject: [PATCH 6/6] Made some pep8 fixes --- evennia/accounts/tests.py | 14 ++- evennia/objects/objects.py | 10 +- evennia/objects/tests.py | 7 +- evennia/typeclasses/models.py | 185 ++++++++++++++++++---------------- 4 files changed, 113 insertions(+), 103 deletions(-) diff --git a/evennia/accounts/tests.py b/evennia/accounts/tests.py index d60db0fce5..084e8a6a66 100644 --- a/evennia/accounts/tests.py +++ b/evennia/accounts/tests.py @@ -5,12 +5,9 @@ from unittest import TestCase from django.test import override_settings from evennia.accounts.accounts import AccountSessionHandler from evennia.accounts.accounts import DefaultAccount -from evennia.server.session import Session from evennia.utils import create from evennia.utils.test_resources import EvenniaTest -from django.conf import settings - class TestAccountSessionHandler(TestCase): "Check AccountSessionHandler class" @@ -73,7 +70,7 @@ class TestDefaultAccount(TestCase): self.account = create.create_account("TestAccount%s" % randint(100000, 999999), email="test@test.com", password="testpassword", typeclass=DefaultAccount) self.assertTrue(self.account.web_get_detail_url()) - + def test_admin_url(self): "Get object's URL for access via Admin pane" self.account = create.create_account("TestAccount%s" % randint(100000, 999999), @@ -211,17 +208,18 @@ class TestDefaultAccount(TestCase): class TestAccountPuppetDeletion(EvenniaTest): - + @override_settings(MULTISESSION_MODE=2) def test_puppet_deletion(self): # Check for existing chars self.assertFalse(self.account.db._playable_characters, 'Account should not have any chars by default.') - + # Add char1 to account's playable characters self.account.db._playable_characters.append(self.char1) self.assertTrue(self.account.db._playable_characters, 'Char was not added to account.') - + # See what happens when we delete char1. self.char1.delete() # Playable char list should be empty. - self.assertFalse(self.account.db._playable_characters, 'Playable character list is not empty! %s' % self.account.db._playable_characters) \ No newline at end of file + self.assertFalse(self.account.db._playable_characters, + 'Playable character list is not empty! %s' % self.account.db._playable_characters) diff --git a/evennia/objects/objects.py b/evennia/objects/objects.py index 7e1a13722e..919da40a7c 100644 --- a/evennia/objects/objects.py +++ b/evennia/objects/objects.py @@ -7,15 +7,11 @@ entities. """ import time import inflect -import re from builtins import object from future.utils import with_metaclass from collections import defaultdict from django.conf import settings -from django.contrib.contenttypes.models import ContentType -from django.urls import reverse -from django.utils.text import slugify from evennia.typeclasses.models import TypeclassBase from evennia.typeclasses.attributes import NickHandler @@ -218,7 +214,7 @@ class DefaultObject(with_metaclass(TypeclassBase, ObjectDB)): @property def is_connected(self): # we get an error for objects subscribed to channels without this - if self.account: # seems sane to pass on the account + if self.account: # seems sane to pass on the account return self.account.is_connected else: return False @@ -328,7 +324,7 @@ class DefaultObject(with_metaclass(TypeclassBase, ObjectDB)): # look at 'an egg'. self.aliases.add(singular, category="plural_key") return singular, plural - + def search(self, searchdata, global_search=False, use_nicks=True, @@ -922,7 +918,7 @@ class DefaultObject(with_metaclass(TypeclassBase, ObjectDB)): self.account.db._playable_characters = [x for x in self.account.db._playable_characters if x != self] for session in self.sessions.all(): self.account.unpuppet_object(session) - + self.account = None for script in _ScriptDB.objects.get_all_scripts_on_obj(self): diff --git a/evennia/objects/tests.py b/evennia/objects/tests.py index 824007f287..2c014cbe77 100644 --- a/evennia/objects/tests.py +++ b/evennia/objects/tests.py @@ -1,11 +1,12 @@ from evennia.utils.test_resources import EvenniaTest + class DefaultObjectTest(EvenniaTest): - + def test_urls(self): "Make sure objects are returning URLs" self.assertTrue(self.char1.get_absolute_url()) self.assertTrue('admin' in self.char1.web_get_admin_url()) - + self.assertTrue(self.room1.get_absolute_url()) - self.assertTrue('admin' in self.room1.web_get_admin_url()) \ No newline at end of file + self.assertTrue('admin' in self.room1.web_get_admin_url()) diff --git a/evennia/typeclasses/models.py b/evennia/typeclasses/models.py index d549efb8ff..61dddc0c80 100644 --- a/evennia/typeclasses/models.py +++ b/evennia/typeclasses/models.py @@ -740,131 +740,146 @@ class TypedObject(SharedMemoryModel): # # Web/Django methods # - + def web_get_admin_url(self): """ Returns the URI path for the Django Admin page for this object. - + ex. Account#1 = '/admin/accounts/accountdb/1/change/' - + Returns: path (str): URI path to Django Admin page for object. - + """ content_type = ContentType.objects.get_for_model(self.__class__) - return reverse("admin:%s_%s_change" % (content_type.app_label, content_type.model), args=(self.id,)) - + return reverse("admin:%s_%s_change" % (content_type.app_label, + content_type.model), args=(self.id,)) + @classmethod def web_get_create_url(cls): """ Returns the URI path for a View that allows users to create new instances of this object. - + ex. Chargen = '/characters/create/' - + For this to work, the developer must have defined a named view somewhere in urls.py that follows the format 'modelname-action', so in this case a named view of 'character-create' would be referenced by this method. - + ex. url(r'characters/create/', ChargenView.as_view(), name='character-create') - + If no View has been created and defined in urls.py, returns an HTML anchor. - + This method is naive and simply returns a path. Securing access to - the actual view and limiting who can create new objects is the + the actual view and limiting who can create new objects is the developer's responsibility. - + Returns: path (str): URI path to object creation page, if defined. - + """ - try: return reverse('%s-create' % cls._meta.verbose_name.lower()) - except: return '#' - + try: + return reverse('%s-create' % cls._meta.verbose_name.lower()) + except: + return '#' + def web_get_detail_url(self): """ - Returns the URI path for a View that allows users to view details for + Returns the URI path for a View that allows users to view details for this object. - + ex. Oscar (Character) = '/characters/oscar/1/' - - For this to work, the developer must have defined a named view somewhere - in urls.py that follows the format 'modelname-action', so in this case - a named view of 'character-detail' would be referenced by this method. - - ex. - url(r'characters/(?P[\w\d\-]+)/(?P[0-9]+)/$', CharDetailView.as_view(), name='character-detail') - - If no View has been created and defined in urls.py, returns an - HTML anchor. - - This method is naive and simply returns a path. Securing access to - the actual view and limiting who can view this object is the developer's - responsibility. - - Returns: - path (str): URI path to object detail page, if defined. - - """ - try: return reverse('%s-detail' % self._meta.verbose_name.lower(), kwargs={'pk': self.pk, 'slug': slugify(self.name)}) - except: return '#' - - def web_get_update_url(self): - """ - Returns the URI path for a View that allows users to update this - object. - - ex. Oscar (Character) = '/characters/oscar/1/change/' - - For this to work, the developer must have defined a named view somewhere - in urls.py that follows the format 'modelname-action', so in this case - a named view of 'character-update' would be referenced by this method. - - ex. - url(r'characters/(?P[\w\d\-]+)/(?P[0-9]+)/change/$', CharUpdateView.as_view(), name='character-update') - - If no View has been created and defined in urls.py, returns an - HTML anchor. - - This method is naive and simply returns a path. Securing access to - the actual view and limiting who can modify objects is the developer's - responsibility. - - Returns: - path (str): URI path to object update page, if defined. - - """ - try: return reverse('%s-update' % self._meta.verbose_name.lower(), kwargs={'pk': self.pk, 'slug': slugify(self.name)}) - except: return '#' - - def web_get_delete_url(self): - """ - Returns the URI path for a View that allows users to delete this object. - - ex. Oscar (Character) = '/characters/oscar/1/delete/' - + For this to work, the developer must have defined a named view somewhere in urls.py that follows the format 'modelname-action', so in this case a named view of 'character-detail' would be referenced by this method. ex. - url(r'characters/(?P[\w\d\-]+)/(?P[0-9]+)/delete/$', CharDeleteView.as_view(), name='character-delete') - + url(r'characters/(?P[\w\d\-]+)/(?P[0-9]+)/$', + CharDetailView.as_view(), name='character-detail') + If no View has been created and defined in urls.py, returns an HTML anchor. - + This method is naive and simply returns a path. Securing access to - the actual view and limiting who can delete this object is the developer's + the actual view and limiting who can view this object is the developer's responsibility. - + + Returns: + path (str): URI path to object detail page, if defined. + + """ + try: + return reverse('%s-detail' % self._meta.verbose_name.lower(), + kwargs={'pk': self.pk, 'slug': slugify(self.name)}) + except: + return '#' + + def web_get_update_url(self): + """ + Returns the URI path for a View that allows users to update this + object. + + ex. Oscar (Character) = '/characters/oscar/1/change/' + + For this to work, the developer must have defined a named view somewhere + in urls.py that follows the format 'modelname-action', so in this case + a named view of 'character-update' would be referenced by this method. + + ex. + url(r'characters/(?P[\w\d\-]+)/(?P[0-9]+)/change/$', + CharUpdateView.as_view(), name='character-update') + + If no View has been created and defined in urls.py, returns an + HTML anchor. + + This method is naive and simply returns a path. Securing access to + the actual view and limiting who can modify objects is the developer's + responsibility. + + Returns: + path (str): URI path to object update page, if defined. + + """ + try: + return reverse('%s-update' % self._meta.verbose_name.lower(), + kwargs={'pk': self.pk, 'slug': slugify(self.name)}) + except: + return '#' + + def web_get_delete_url(self): + """ + Returns the URI path for a View that allows users to delete this object. + + ex. Oscar (Character) = '/characters/oscar/1/delete/' + + For this to work, the developer must have defined a named view somewhere + in urls.py that follows the format 'modelname-action', so in this case + a named view of 'character-detail' would be referenced by this method. + + ex. + url(r'characters/(?P[\w\d\-]+)/(?P[0-9]+)/delete/$', + CharDeleteView.as_view(), name='character-delete') + + If no View has been created and defined in urls.py, returns an + HTML anchor. + + This method is naive and simply returns a path. Securing access to + the actual view and limiting who can delete this object is the developer's + responsibility. + Returns: path (str): URI path to object deletion page, if defined. - + """ - try: return reverse('%s-delete' % self._meta.verbose_name.lower(), kwargs={'pk': self.pk, 'slug': slugify(self.name)}) - except: return '#' - + try: + return reverse('%s-delete' % self._meta.verbose_name.lower(), + kwargs={'pk': self.pk, 'slug': slugify(self.name)}) + except: + return '#' + # Used by Django Sites/Admin - get_absolute_url = web_get_detail_url \ No newline at end of file + get_absolute_url = web_get_detail_url