From 686217375bebe9a354c6743dbab7bedb183a08e6 Mon Sep 17 00:00:00 2001 From: Johnny Date: Sun, 28 Oct 2018 22:12:29 +0000 Subject: [PATCH 1/2] Adds generic CharacterListView and unit test. --- .../web/website/templates/website/_menu.html | 1 + .../templates/website/character_list.html | 27 ++++++++++ evennia/web/website/tests.py | 4 ++ evennia/web/website/urls.py | 1 + evennia/web/website/views.py | 54 +++++++++++++++++++ 5 files changed, 87 insertions(+) create mode 100644 evennia/web/website/templates/website/character_list.html diff --git a/evennia/web/website/templates/website/_menu.html b/evennia/web/website/templates/website/_menu.html index 32c17db361..7bdfe82cc5 100644 --- a/evennia/web/website/templates/website/_menu.html +++ b/evennia/web/website/templates/website/_menu.html @@ -29,6 +29,7 @@ folder and edit it to add/remove links to the menu. About
  • Documentation
  • +
  • Characters
  • {% if user.is_staff %}
  • Admin
  • {% endif %} diff --git a/evennia/web/website/templates/website/character_list.html b/evennia/web/website/templates/website/character_list.html new file mode 100644 index 0000000000..4e7601d49a --- /dev/null +++ b/evennia/web/website/templates/website/character_list.html @@ -0,0 +1,27 @@ +{% extends "base.html" %} + +{% block titleblock %} +{{ view.page_title }} +{% endblock %} + +{% block content %} + +{% load addclass %} +
    +
    +
    +
    +

    {{ view.page_title }}

    +
    + +
      + {% for object in object_list %} +
    • {{ object }}
    • + {% endfor %} +
    + +
    +
    +
    +
    +{% endblock %} diff --git a/evennia/web/website/tests.py b/evennia/web/website/tests.py index 69b570b1b7..1fc775f051 100644 --- a/evennia/web/website/tests.py +++ b/evennia/web/website/tests.py @@ -158,6 +158,10 @@ class CharacterPuppetView(EvenniaWebTest): response = self.client.get(reverse(self.url_name, kwargs=kwargs), follow=True) self.assertTrue(response.status_code >= 400, "Invalid access should return a 4xx code-- either obj not found or permission denied! (Returned %s)" % response.status_code) +class CharacterListView(EvenniaWebTest): + url_name = 'characters' + unauthenticated_response = 302 + class CharacterManageView(EvenniaWebTest): url_name = 'character-manage' unauthenticated_response = 302 diff --git a/evennia/web/website/urls.py b/evennia/web/website/urls.py index f254cbaaae..fbf1c01d9c 100644 --- a/evennia/web/website/urls.py +++ b/evennia/web/website/urls.py @@ -21,6 +21,7 @@ urlpatterns = [ url(r'^help/(?P[\w\d\-]+)/(?P[\w\d\-]+)/$', website_views.HelpDetailView.as_view(), name="help-entry-detail"), # Character management + url(r'^characters/$', website_views.CharacterListView.as_view(), name="characters"), url(r'^characters/create/$', website_views.CharacterCreateView.as_view(), name="character-create"), url(r'^characters/manage/$', website_views.CharacterManageView.as_view(), name="character-manage"), url(r'^characters/detail/(?P[\w\d\-]+)/(?P[0-9]+)/$', website_views.CharacterDetailView.as_view(), name="character-detail"), diff --git a/evennia/web/website/views.py b/evennia/web/website/views.py index e1b80c415f..4f66fa5f20 100644 --- a/evennia/web/website/views.py +++ b/evennia/web/website/views.py @@ -576,6 +576,42 @@ class CharacterMixin(TypeclassMixin): return self.typeclass.objects.filter(id__in=ids).order_by(Lower('db_key')) +class CharacterListView(LoginRequiredMixin, CharacterMixin, ListView): + """ + This view provides a mechanism by which a logged-in player can view a list + of all other characters. + + This view requires authentication by default as a nominal effort to prevent + human stalkers and automated bots/scrapers from harvesting data on your users. + + """ + # -- Django constructs -- + template_name = 'website/character_list.html' + paginate_by = 100 + + # -- Evennia constructs -- + page_title = 'Character List' + access_type = 'view' + + def get_queryset(self): + """ + This method will override the Django get_queryset method to return a + list of all characters (filtered/sorted) instead of just those limited + to the account. + + Returns: + queryset (QuerySet): Django queryset for use in the given view. + + """ + account = self.request.user + + # Return a queryset consisting of characters the user is allowed to + # see. + ids = [obj.id for obj in self.model.objects.all() if obj.access(account, self.access_type)] + + return self.model.objects.filter(id__in=ids).order_by(Lower('db_key')) + + class CharacterPuppetView(LoginRequiredMixin, CharacterMixin, RedirectView, ObjectDetailView): """ This view provides a mechanism by which a logged-in player can "puppet" one @@ -653,6 +689,24 @@ class CharacterDetailView(CharacterMixin, ObjectDetailView): # -- Evennia constructs -- # What attributes to display for this object attributes = ['name', 'desc'] + access_type = 'view' + + def get_queryset(self): + """ + This method will override the Django get_queryset method to return a + list of all characters the user may access. + + Returns: + queryset (QuerySet): Django queryset for use in the given view. + + """ + account = self.request.user + + # Return a queryset consisting of characters the user is allowed to + # see. + ids = [obj.id for obj in self.model.objects.all() if obj.access(account, self.access_type)] + + return self.model.objects.filter(id__in=ids).order_by(Lower('db_key')) class CharacterDeleteView(CharacterMixin, ObjectDeleteView): From 274cd7661a2cc333a667336ee03fb8334ae06733 Mon Sep 17 00:00:00 2001 From: Johnny Date: Tue, 30 Oct 2018 01:38:54 +0000 Subject: [PATCH 2/2] Changes all reference from view.modelto view.typeclass. --- evennia/web/website/views.py | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/evennia/web/website/views.py b/evennia/web/website/views.py index 6a4274876f..4382793256 100644 --- a/evennia/web/website/views.py +++ b/evennia/web/website/views.py @@ -608,9 +608,9 @@ class CharacterListView(LoginRequiredMixin, CharacterMixin, ListView): # Return a queryset consisting of characters the user is allowed to # see. - ids = [obj.id for obj in self.model.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.model.objects.filter(id__in=ids).order_by(Lower('db_key')) + return self.typeclass.objects.filter(id__in=ids).order_by(Lower('db_key')) class CharacterPuppetView(LoginRequiredMixin, CharacterMixin, RedirectView, ObjectDetailView): @@ -705,9 +705,9 @@ class CharacterDetailView(CharacterMixin, ObjectDetailView): # Return a queryset consisting of characters the user is allowed to # see. - ids = [obj.id for obj in self.model.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.model.objects.filter(id__in=ids).order_by(Lower('db_key')) + return self.typeclass.objects.filter(id__in=ids).order_by(Lower('db_key')) class CharacterDeleteView(CharacterMixin, ObjectDeleteView): @@ -772,7 +772,7 @@ class CharacterCreateView(CharacterMixin, ObjectCreateView): # Channel views # -class ChannelMixin(object): +class ChannelMixin(TypeclassMixin): """ This is a "mixin", a modifier of sorts. @@ -802,13 +802,13 @@ class ChannelMixin(object): account = self.request.user # Get list of all Channels - channels = self.model.objects.all().iterator() + channels = self.typeclass.objects.all().iterator() # Now figure out which ones the current user is allowed to see bucket = [channel.id for channel in channels if channel.access(account, 'listen')] # Re-query and set a sorted list - filtered = self.model.objects.filter( + filtered = self.typeclass.objects.filter( id__in=bucket ).order_by( Lower('db_key') @@ -934,7 +934,7 @@ class ChannelDetailView(ChannelMixin, ObjectDetailView): # Help views # -class HelpMixin(object): +class HelpMixin(TypeclassMixin): """ This is a "mixin", a modifier of sorts. @@ -960,13 +960,13 @@ class HelpMixin(object): account = self.request.user # Get list of all HelpEntries - entries = self.model.objects.all().iterator() + entries = self.typeclass.objects.all().iterator() # Now figure out which ones the current user is allowed to see bucket = [entry.id for entry in entries if entry.access(account, 'view')] # Re-query and set a sorted list - filtered = self.model.objects.filter( + filtered = self.typeclass.objects.filter( id__in=bucket ).order_by( Lower('db_key')