From bad3ffb4c597a814b4b5dad3abb403217bdd83d8 Mon Sep 17 00:00:00 2001 From: Johnny Date: Thu, 4 Oct 2018 00:08:23 +0000 Subject: [PATCH 01/48] Updates Bootstrap to v4 stable. --- evennia/web/website/templates/website/base.html | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/evennia/web/website/templates/website/base.html b/evennia/web/website/templates/website/base.html index a2172b308f..556aad0306 100644 --- a/evennia/web/website/templates/website/base.html +++ b/evennia/web/website/templates/website/base.html @@ -12,7 +12,7 @@ - + @@ -56,7 +56,7 @@ - - + + From a0e3afd9a43716fd8ee32ba2ab8ac12aac7b1b50 Mon Sep 17 00:00:00 2001 From: Johnny Date: Thu, 4 Oct 2018 00:32:38 +0000 Subject: [PATCH 02/48] Adds template tag to override body. --- evennia/web/website/templates/website/base.html | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/evennia/web/website/templates/website/base.html b/evennia/web/website/templates/website/base.html index 556aad0306..2004425849 100644 --- a/evennia/web/website/templates/website/base.html +++ b/evennia/web/website/templates/website/base.html @@ -29,6 +29,8 @@ {{game_name}} - {% if flatpage %}{{flatpage.title}}{% else %}{% block titleblock %}{{page_title}}{% endblock %}{% endif %} + {% block body %} + {% include "website/_menu.html" %}
@@ -53,6 +55,8 @@
{% endblock %} + + {% endblock %} From 63c8ae5bd5b7a2b9f012267640516272f84f34eb Mon Sep 17 00:00:00 2001 From: Johnny Date: Thu, 4 Oct 2018 00:33:32 +0000 Subject: [PATCH 03/48] Fixes failure to display error messages and display form as standalone. --- .../templates/website/registration/login.html | 73 ++++++++++--------- 1 file changed, 39 insertions(+), 34 deletions(-) diff --git a/evennia/web/website/templates/website/registration/login.html b/evennia/web/website/templates/website/registration/login.html index 8b2213a251..2aa32d5cff 100644 --- a/evennia/web/website/templates/website/registration/login.html +++ b/evennia/web/website/templates/website/registration/login.html @@ -4,44 +4,49 @@ Login {% endblock %} -{% block content %} +{% block body %} {% load addclass %} - -
-
-
-
-

Login

-
- {% if user.is_authenticated %} -

You are already logged in!

- {% else %} - {% if form.has_errors %} -

Your username and password didn't match. Please try again.

- {% endif %} - -
- {% csrf_token %} - -
- - {{ form.username | addclass:"form-control" }} -
- -
- - {{ form.password | addclass:"form-control" }} -
- -
- - -
-
+
+
+
+
+
+

Login

+
+ {% if user.is_authenticated %} + + {% else %} + {% if form.errors %} + + {% endif %} + {% endif %} + + {% if not user.is_authenticated %} +
+ {% csrf_token %} + +
+ + {{ form.username | addclass:"form-control" }} +
+ +
+ + {{ form.password | addclass:"form-control" }} +
+ +
+
+ + +
+
+ + {% endif %} +
-{% endif %} {% endblock %} From db5b68e94309e1e946f5550110829b2986ec7380 Mon Sep 17 00:00:00 2001 From: Johnny Date: Thu, 4 Oct 2018 17:19:52 +0000 Subject: [PATCH 04/48] Adds link to password reset form. --- .../web/website/templates/website/registration/login.html | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/evennia/web/website/templates/website/registration/login.html b/evennia/web/website/templates/website/registration/login.html index 2aa32d5cff..87f5d7b9f7 100644 --- a/evennia/web/website/templates/website/registration/login.html +++ b/evennia/web/website/templates/website/registration/login.html @@ -35,6 +35,12 @@ Login {{ form.password | addclass:"form-control" }}
+ +
+
+ +
Sign Up
+

From 32c8d0fce206bd0b4846226edaaef354905f4627 Mon Sep 17 00:00:00 2001 From: Johnny Date: Thu, 4 Oct 2018 18:17:32 +0000 Subject: [PATCH 05/48] Updates style of password reset forms to use Bootstrap instead of Django Admin. --- .../registration/password_reset_complete.html | 31 +++++++++++ .../registration/password_reset_confirm.html | 55 +++++++++++++++++++ .../registration/password_reset_done.html | 34 ++++++++++++ .../registration/password_reset_email.html | 15 +++++ .../registration/password_reset_form.html | 48 ++++++++++++++++ 5 files changed, 183 insertions(+) create mode 100644 evennia/web/website/templates/website/registration/password_reset_complete.html create mode 100644 evennia/web/website/templates/website/registration/password_reset_confirm.html create mode 100644 evennia/web/website/templates/website/registration/password_reset_done.html create mode 100644 evennia/web/website/templates/website/registration/password_reset_email.html create mode 100644 evennia/web/website/templates/website/registration/password_reset_form.html diff --git a/evennia/web/website/templates/website/registration/password_reset_complete.html b/evennia/web/website/templates/website/registration/password_reset_complete.html new file mode 100644 index 0000000000..697b4bc4ad --- /dev/null +++ b/evennia/web/website/templates/website/registration/password_reset_complete.html @@ -0,0 +1,31 @@ +{% extends "base.html" %} + +{% block titleblock %} +Forgot Password - Reset Successful +{% endblock %} + +{% block body %} + +{% load addclass %} +
+
+
+
+
+

Password Reset

+
+ {% if user.is_authenticated %} + + {% else %} + +

Your password has been successfully reset!

+ +

You may now log in using it here.

+ + {% endif %} +
+
+
+
+
+{% endblock %} diff --git a/evennia/web/website/templates/website/registration/password_reset_confirm.html b/evennia/web/website/templates/website/registration/password_reset_confirm.html new file mode 100644 index 0000000000..a7bdc683be --- /dev/null +++ b/evennia/web/website/templates/website/registration/password_reset_confirm.html @@ -0,0 +1,55 @@ +{% extends "base.html" %} + +{% block titleblock %} +Forgot Password - Reset +{% endblock %} + +{% block body %} + +{% load addclass %} +
+
+
+
+
+

Reset Password

+
+ {% if not validlink %} + + {% else %} + + {% if form.errors %} + {% for field in form %} + {% for error in field.errors %} + + {% endfor %} + {% endfor %} + {% endif %} + +
+ {% csrf_token %} + +
+ + {{ form.new_password1 | addclass:"form-control" }} +
+ +
+ + {{ form.new_password2 | addclass:"form-control" }} +
+ +
+
+ + +
+
+ + {% endif %} +
+
+
+
+
+{% endblock %} diff --git a/evennia/web/website/templates/website/registration/password_reset_done.html b/evennia/web/website/templates/website/registration/password_reset_done.html new file mode 100644 index 0000000000..d248c56d0f --- /dev/null +++ b/evennia/web/website/templates/website/registration/password_reset_done.html @@ -0,0 +1,34 @@ +{% extends "base.html" %} + +{% block titleblock %} +Forgot Password - Reset Link Sent +{% endblock %} + +{% block body %} + +{% load addclass %} +
+
+
+
+
+

Reset Sent

+
+ {% if user.is_authenticated %} + + {% else %} + +

Instructions for resetting your password will be emailed to the + address you provided, if that address matches the one we have on file + for your account. You should receive them shortly.

+ +

Please allow up to to a few hours for the email to transmit, and be + sure to check your spam folder if it doesn't show up in a timely manner.

+ + {% endif %} +
+
+
+
+
+{% endblock %} diff --git a/evennia/web/website/templates/website/registration/password_reset_email.html b/evennia/web/website/templates/website/registration/password_reset_email.html new file mode 100644 index 0000000000..28e5a0daa2 --- /dev/null +++ b/evennia/web/website/templates/website/registration/password_reset_email.html @@ -0,0 +1,15 @@ +{% autoescape off %} +To initiate the password reset process for your {{ user.get_username }} {{ site_name }} account, +click the link below: + +{{ protocol }}://{{ domain }}{% url 'password_reset_confirm' uidb64=uid token=token %} + +If clicking the link above doesn't work, please copy and paste the URL in a new browser +window instead. + +If you did not request a password reset, please disregard this notice. Whoever requested it +cannot follow through on resetting your password without access to this message. + +Sincerely, +{{ site_name }} Management. +{% endautoescape %} \ No newline at end of file diff --git a/evennia/web/website/templates/website/registration/password_reset_form.html b/evennia/web/website/templates/website/registration/password_reset_form.html new file mode 100644 index 0000000000..f13c532a58 --- /dev/null +++ b/evennia/web/website/templates/website/registration/password_reset_form.html @@ -0,0 +1,48 @@ +{% extends "base.html" %} + +{% block titleblock %} +Forgot Password +{% endblock %} + +{% block body %} + +{% load addclass %} +
+
+
+
+
+

Forgot Password

+
+ {% if user.is_authenticated %} + + {% else %} + {% if form.errors %} + + {% endif %} + {% endif %} + + {% if not user.is_authenticated %} +
+ {% csrf_token %} + +
+ + {{ form.email | addclass:"form-control" }} + The email address you provided at registration. If you left it blank, your password cannot be reset through this form. +
+ +
+
+ + +
+
+ + {% endif %} +
+
+
+
+
+{% endblock %} From aae242a41129f3e95efbd4ae34b1b5c3016ea9a4 Mon Sep 17 00:00:00 2001 From: Johnny Date: Thu, 4 Oct 2018 20:04:37 +0000 Subject: [PATCH 06/48] Enables django.contrib.messages via INSTALLED_APPS and adds a context processor for it. --- evennia/settings_default.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/evennia/settings_default.py b/evennia/settings_default.py index 9efbb6314b..4922b08996 100644 --- a/evennia/settings_default.py +++ b/evennia/settings_default.py @@ -751,6 +751,7 @@ TEMPLATES = [{ 'django.contrib.auth.context_processors.auth', 'django.template.context_processors.media', 'django.template.context_processors.debug', + 'django.contrib.messages.context_processors.messages', 'sekizai.context_processors.sekizai', 'evennia.web.utils.general_context.general_context'], # While true, show "pretty" error messages for template syntax errors. @@ -785,6 +786,7 @@ INSTALLED_APPS = ( 'django.contrib.flatpages', 'django.contrib.sites', 'django.contrib.staticfiles', + 'django.contrib.messages', 'sekizai', 'evennia.utils.idmapper', 'evennia.server', From 927a1044627a8eadeeed0c6f68d83a4184e72664 Mon Sep 17 00:00:00 2001 From: Johnny Date: Thu, 4 Oct 2018 20:05:32 +0000 Subject: [PATCH 07/48] Adds hook to retrieve messsages and an include for the actual blocks. --- evennia/web/website/templates/website/base.html | 2 ++ evennia/web/website/templates/website/messages.html | 9 +++++++++ 2 files changed, 11 insertions(+) create mode 100644 evennia/web/website/templates/website/messages.html diff --git a/evennia/web/website/templates/website/base.html b/evennia/web/website/templates/website/base.html index 2004425849..e690d61d2b 100644 --- a/evennia/web/website/templates/website/base.html +++ b/evennia/web/website/templates/website/base.html @@ -42,6 +42,8 @@
{% endif %} diff --git a/evennia/web/website/templates/website/messages.html b/evennia/web/website/templates/website/messages.html new file mode 100644 index 0000000000..7b237180eb --- /dev/null +++ b/evennia/web/website/templates/website/messages.html @@ -0,0 +1,9 @@ +{% if messages %} + +{% for message in messages %} +
+ {{ message }} +
+{% endfor %} + +{% endif %} \ No newline at end of file From 9b924fc07e481325e481a4d20e1ab449fb4daf1c Mon Sep 17 00:00:00 2001 From: Johnny Date: Thu, 4 Oct 2018 20:05:55 +0000 Subject: [PATCH 08/48] Adds include block for messages. --- evennia/web/website/templates/website/registration/login.html | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/evennia/web/website/templates/website/registration/login.html b/evennia/web/website/templates/website/registration/login.html index 87f5d7b9f7..27339c9480 100644 --- a/evennia/web/website/templates/website/registration/login.html +++ b/evennia/web/website/templates/website/registration/login.html @@ -14,6 +14,7 @@ Login

Login


+ {% include 'website/messages.html' %} {% if user.is_authenticated %} {% else %} @@ -39,7 +40,7 @@ Login

From 79d122a1dda42a4b1455becb653e977d6fab8ce1 Mon Sep 17 00:00:00 2001 From: Johnny Date: Thu, 4 Oct 2018 20:21:02 +0000 Subject: [PATCH 09/48] Adds account registration form. --- evennia/web/website/forms.py | 13 +++++ .../web/website/templates/website/_menu.html | 2 +- .../templates/website/registration/login.html | 2 +- .../website/registration/register.html | 56 +++++++++++++++++++ evennia/web/website/urls.py | 3 +- evennia/web/website/views.py | 42 ++++++++++++++ 6 files changed, 115 insertions(+), 3 deletions(-) create mode 100644 evennia/web/website/forms.py create mode 100644 evennia/web/website/templates/website/registration/register.html diff --git a/evennia/web/website/forms.py b/evennia/web/website/forms.py new file mode 100644 index 0000000000..cc7677926c --- /dev/null +++ b/evennia/web/website/forms.py @@ -0,0 +1,13 @@ +from django import forms +from django.conf import settings +from django.contrib.auth.forms import UserCreationForm, UsernameField +from evennia.utils import class_from_module + +class AccountCreationForm(UserCreationForm): + + class Meta: + model = class_from_module(settings.BASE_ACCOUNT_TYPECLASS) + fields = ("username", "email") + field_classes = {'username': UsernameField} + + email = forms.EmailField(help_text="A valid email address. Optional; used for password resets.", required=False) \ No newline at end of file diff --git a/evennia/web/website/templates/website/_menu.html b/evennia/web/website/templates/website/_menu.html index 8430d0f805..6a81d04866 100644 --- a/evennia/web/website/templates/website/_menu.html +++ b/evennia/web/website/templates/website/_menu.html @@ -51,7 +51,7 @@ folder and edit it to add/remove links to the menu. Log In
  • - Register + Register
  • {% endif %} {% endblock %} diff --git a/evennia/web/website/templates/website/registration/login.html b/evennia/web/website/templates/website/registration/login.html index 27339c9480..cf798e8f76 100644 --- a/evennia/web/website/templates/website/registration/login.html +++ b/evennia/web/website/templates/website/registration/login.html @@ -40,7 +40,7 @@ Login

    diff --git a/evennia/web/website/templates/website/registration/register.html b/evennia/web/website/templates/website/registration/register.html new file mode 100644 index 0000000000..5475d922be --- /dev/null +++ b/evennia/web/website/templates/website/registration/register.html @@ -0,0 +1,56 @@ +{% extends "base.html" %} + +{% block titleblock %} +Register +{% endblock %} + +{% block body %} + +{% load addclass %} +
    +
    +
    +
    +
    +

    Register

    +
    + {% if user.is_authenticated %} + + {% else %} + {% if form.errors %} + {% for field in form %} + {% for error in field.errors %} + + {% endfor %} + {% endfor %} + {% endif %} + {% endif %} + + {% if not user.is_authenticated %} +
    + {% csrf_token %} + + {% for field in form %} +
    + {{ field.label_tag }} + {{ field | addclass:"form-control" }} + {% if field.help_text %} + {{ field.help_text|safe }} + {% endif %} +
    + {% endfor %} + +
    +
    + + +
    +
    + + {% endif %} +
    +
    +
    +
    +
    +{% endblock %} diff --git a/evennia/web/website/urls.py b/evennia/web/website/urls.py index f906b6b142..1cc7fe75d8 100644 --- a/evennia/web/website/urls.py +++ b/evennia/web/website/urls.py @@ -13,7 +13,8 @@ urlpatterns = [ url(r'^tbi/', website_views.to_be_implemented, name='to_be_implemented'), # User Authentication (makes login/logout url names available) - url(r'^authenticate/', include('django.contrib.auth.urls')), + url(r'^auth/', include('django.contrib.auth.urls')), + url(r'^auth/register', website_views.AccountCreationView.as_view(), name="register"), # Django original admin page. Make this URL is always available, whether # we've chosen to use Evennia's custom admin or not. diff --git a/evennia/web/website/views.py b/evennia/web/website/views.py index fe93b06426..e4342ebc6d 100644 --- a/evennia/web/website/views.py +++ b/evennia/web/website/views.py @@ -7,14 +7,19 @@ templates on the fly. """ 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.admin.views.decorators import staff_member_required +from django.http import HttpResponseRedirect from django.shortcuts import render +from django.urls import reverse, reverse_lazy +from django.views.generic import View, DetailView, ListView, FormView from evennia import SESSION_HANDLER from evennia.objects.models import ObjectDB from evennia.accounts.models import AccountDB from evennia.utils import logger +from evennia.web.website.forms import AccountCreationForm from django.contrib.auth import login @@ -134,3 +139,40 @@ def admin_wrapper(request): Wrapper that allows us to properly use the base Django admin site, if needed. """ return staff_member_required(site.index)(request) + +class AccountCreationView(FormView): + form_class = AccountCreationForm + template_name = 'website/registration/register.html' + success_url = reverse_lazy('login') + + def form_valid(self, form): + # Check to make sure basics validated + valid = super(AccountCreationView, self).form_valid(form) + if not valid: return self.form_invalid(form) + + username = form.cleaned_data['username'] + password = form.cleaned_data['password1'] + email = form.cleaned_data.get('email', '') + + # Create a fake session object to intercept calls to the terminal + from mock import Mock + session = self.request + session.address = self.request.META.get('REMOTE_ADDR', '') + session.msg = Mock() + + # Create account + from evennia.commands.default.unloggedin import _create_account + permissions = settings.PERMISSION_ACCOUNT_DEFAULT + account = _create_account(session, username, password, permissions) + + # If unsuccessful, get messages passed to session.msg + if not account: + [messages.error(self.request, call) for call in session.msg.call_args_list] + return self.form_invalid(form) + + # Append email address if given + account.email = email + account.save() + + messages.success(self.request, "Your account '%s' was successfully created! You may log in using it now." % account.name) + return HttpResponseRedirect(self.success_url) \ No newline at end of file From a465b6c39f1b17c064e2f7df6cc43aacf087fea0 Mon Sep 17 00:00:00 2001 From: Johnny Date: Thu, 4 Oct 2018 22:54:35 +0000 Subject: [PATCH 10/48] Adds authenticated dropdown with links to password change form, create/manage characters, and character quickselect. --- evennia/accounts/accounts.py | 4 ++++ .../web/website/templates/website/_menu.html | 17 +++++++++++++++-- 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/evennia/accounts/accounts.py b/evennia/accounts/accounts.py index 2c33e5c1f8..f4711299cf 100644 --- a/evennia/accounts/accounts.py +++ b/evennia/accounts/accounts.py @@ -189,6 +189,10 @@ class DefaultAccount(with_metaclass(TypeclassBase, AccountDB)): @lazy_property def sessions(self): return AccountSessionHandler(self) + + @lazy_property + def characters(self): + return self.db._playable_characters # session-related methods diff --git a/evennia/web/website/templates/website/_menu.html b/evennia/web/website/templates/website/_menu.html index 6a81d04866..ea01404967 100644 --- a/evennia/web/website/templates/website/_menu.html +++ b/evennia/web/website/templates/website/_menu.html @@ -40,8 +40,21 @@ folder and edit it to add/remove links to the menu. {% endblock %} {% block navbar_user %} {% if user.is_authenticated %} -
  • Log Out From 0531afceef9c70885d581ee6416c89e20ac897da Mon Sep 17 00:00:00 2001 From: Johnny Date: Thu, 4 Oct 2018 22:54:48 +0000 Subject: [PATCH 11/48] Stylizes password_change form. --- .../registration/password_change_form.html | 51 +++++++++++++++++++ 1 file changed, 51 insertions(+) create mode 100644 evennia/web/website/templates/website/registration/password_change_form.html diff --git a/evennia/web/website/templates/website/registration/password_change_form.html b/evennia/web/website/templates/website/registration/password_change_form.html new file mode 100644 index 0000000000..bae8c90962 --- /dev/null +++ b/evennia/web/website/templates/website/registration/password_change_form.html @@ -0,0 +1,51 @@ +{% extends "base.html" %} + +{% block titleblock %} +Password Change +{% endblock %} + +{% block content %} + +{% load addclass %} +
    +
    +
    +
    +
    +

    Password Change

    +
    + + {% if form.errors %} + {% for field in form %} + {% for error in field.errors %} + + {% endfor %} + {% endfor %} + {% endif %} + +
    + {% csrf_token %} + + {% for field in form %} +
    + {{ field.label_tag }} + {{ field | addclass:"form-control" }} + {% if field.help_text %} + {{ field.help_text|safe }} + {% endif %} +
    + {% endfor %} + +
    +
    + + +
    +
    + +
    +
    +
    +
    +
    +{% endblock %} From 40f5f283ad862224e6b49a9e21d7205c527c8f2c Mon Sep 17 00:00:00 2001 From: Johnny Date: Fri, 5 Oct 2018 18:59:55 +0000 Subject: [PATCH 12/48] Implements web-based character creation. --- evennia/web/website/forms.py | 131 +++++++++++++++++- .../web/website/templates/website/_menu.html | 2 +- .../templates/website/chargen_form.html | 51 +++++++ evennia/web/website/urls.py | 3 + evennia/web/website/views.py | 61 +++++++- 5 files changed, 244 insertions(+), 4 deletions(-) create mode 100644 evennia/web/website/templates/website/chargen_form.html diff --git a/evennia/web/website/forms.py b/evennia/web/website/forms.py index cc7677926c..ca93dd2c3b 100644 --- a/evennia/web/website/forms.py +++ b/evennia/web/website/forms.py @@ -2,6 +2,7 @@ from django import forms from django.conf import settings from django.contrib.auth.forms import UserCreationForm, UsernameField from evennia.utils import class_from_module +from random import choice, randint class AccountCreationForm(UserCreationForm): @@ -10,4 +11,132 @@ class AccountCreationForm(UserCreationForm): fields = ("username", "email") field_classes = {'username': UsernameField} - email = forms.EmailField(help_text="A valid email address. Optional; used for password resets.", required=False) \ No newline at end of file + email = forms.EmailField(help_text="A valid email address. Optional; used for password resets.", required=False) + +class CharacterCreationForm(forms.Form): + name = forms.CharField(help_text="The name of your intended character.") + age = forms.IntegerField(min_value=3, max_value=99, help_text="How old your character should be once spawned.") + description = forms.CharField(widget=forms.Textarea(attrs={'rows': 3}), max_length=2048, min_length=160, required=False) + + @classmethod + def assign_attributes(cls, attribute_list, points, min_points, max_points): + """ + Randomly distributes a number of points across the given attributes, + while also ensuring each attribute gets at least a certain amount + and at most a certain amount. + + Args: + attribute_list (iterable): List or tuple of attribute names to assign + points to. + points (int): Starting number of points + min_points (int): Least amount of points each attribute should have + max_points (int): Most amount of points each attribute should have + + Returns: + spread (dict): Dict of attributes and a point assignment. + + """ + num_buckets = len(attribute_list) + point_spread = (x for x in self.random_distribution(points, num_buckets, min_points, max_points)) + + # For each field, get the point calculation for the next attribute value generated + return {attribute: next(point_spread) for k in attribute_list} + + @classmethod + def random_distribution(cls, points, num_buckets, min_points, max_points): + """ + Distributes a set number of points randomly across a number of 'buckets' + while also attempting to ensure each bucket's value finishes within a + certain range. + + If your math doesn't add up (you try to distribute 5 points across 100 + buckets and insist each bucket has at least 20 points), the algorithm + will return the best spread it could achieve but will not raise an error + (so in this case, 5 random buckets would get 1 point each and that's all). + + Args: + points (int): The number of points to distribute. + num_buckets (int): The number of 'buckets' (or stats, skills, etc) + you wish to distribute points to. + min_points (int): The least amount of points each bucket should have. + max_points (int): The most points each bucket should have. + + Returns: + buckets (list): List of random point assignments. + + """ + buckets = [0 for x in range(num_buckets)] + indices = [i for (i, value) in enumerate(buckets)] + + # Do this while we have eligible buckets, points to assign and we haven't + # maxed out all the buckets. + while indices and points and sum(buckets) <= (max_points * num_buckets): + # Pick a random bucket index + index = choice(indices) + + # Add to bucket + buckets[index] = buckets[index] + 1 + points = points - 1 + + # Get the indices of eligible buckets + indices = [i for (i, value) in enumerate(buckets) if (value < min_points) or (value < max_points)] + + return buckets + +class ExtendedCharacterCreationForm(forms.Form): + + GENDERS = ( + ('male', 'Male'), + ('female', 'Female'), + ('androgynous', 'Androgynous'), + ('special', 'Special') + ) + + RACES = ( + ('human', 'Human'), + ('elf', 'Elf'), + ('orc', 'Orc'), + ) + + CLASSES = ( + ('civilian', 'Civilian'), + ('warrior', 'Warrior'), + ('thief', 'Thief'), + ('cleric', 'Cleric') + ) + + PERKS = ( + ('strong', 'Extra strength'), + ('nimble', 'Quick on their toes'), + ('diplomatic', 'Fast talker') + ) + + name = forms.CharField(help_text="The name of your intended character.") + age = forms.IntegerField(min_value=3, max_value=99, help_text="How old your character should be once spawned.") + gender = forms.ChoiceField(choices=GENDERS, help_text="Which end of the multidimensional spectrum does your character most closely align with, in terms of gender?") + race = forms.ChoiceField(choices=RACES, help_text="What race does your character belong to?") + job = forms.ChoiceField(choices=CLASSES, help_text="What profession or role does your character fulfill or is otherwise destined to?") + + perks = forms.MultipleChoiceField(choices=PERKS, help_text="What extraordinary abilities does your character possess?") + description = forms.CharField(widget=forms.Textarea(attrs={'rows': 3}), max_length=2048, min_length=160, required=False) + + strength = forms.IntegerField(min_value=1, max_value=10) + perception = forms.IntegerField(min_value=1, max_value=10) + intelligence = forms.IntegerField(min_value=1, max_value=10) + dexterity = forms.IntegerField(min_value=1, max_value=10) + charisma = forms.IntegerField(min_value=1, max_value=10) + vitality = forms.IntegerField(min_value=1, max_value=10) + magic = forms.IntegerField(min_value=1, max_value=10) + + def __init__(self, *args, **kwargs): + # Do all the normal initizliation stuff that would otherwise be happening + super(ExtendedCharacterCreationForm, self).__init__(*args, **kwargs) + + # Given a pool of points, let's randomly distribute them across attributes. + # First get a list of attributes + attributes = ('strength', 'perception', 'intelligence', 'dexterity', 'charisma', 'vitality', 'magic') + # Distribute a random number of points across them + attrs = self.assign_attributes(attributes, 50, 1, 10) + # Initialize the form with the results of the point distribution + for field in attrs.keys(): + self.initial[field] = attrs[field] \ No newline at end of file diff --git a/evennia/web/website/templates/website/_menu.html b/evennia/web/website/templates/website/_menu.html index ea01404967..432b6e4827 100644 --- a/evennia/web/website/templates/website/_menu.html +++ b/evennia/web/website/templates/website/_menu.html @@ -43,7 +43,7 @@ folder and edit it to add/remove links to the menu.
  • diff --git a/evennia/web/website/templates/website/pagination.html b/evennia/web/website/templates/website/pagination.html new file mode 100644 index 0000000000..e2cb6bed73 --- /dev/null +++ b/evennia/web/website/templates/website/pagination.html @@ -0,0 +1,34 @@ +{% if page_obj %} + +{% endif %} \ No newline at end of file From 0ed56ad78fa3bb4daa6b9569453163169e8e7aad Mon Sep 17 00:00:00 2001 From: Johnny Date: Fri, 5 Oct 2018 21:06:42 +0000 Subject: [PATCH 20/48] Adds template for character management list view. --- .../website/character_manage_list.html | 38 +++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 evennia/web/website/templates/website/character_manage_list.html diff --git a/evennia/web/website/templates/website/character_manage_list.html b/evennia/web/website/templates/website/character_manage_list.html new file mode 100644 index 0000000000..f4e112fd7a --- /dev/null +++ b/evennia/web/website/templates/website/character_manage_list.html @@ -0,0 +1,38 @@ +{% extends "base.html" %} + +{% block titleblock %} +Manage Characters +{% endblock %} + +{% block content %} + +{% load addclass %} +
    +
    +
    +
    +
    +

    Manage Characters

    +
    + + {% for object in object_list %} +
    + +
    +

    {{ object.db_date_created }} +
    Delete +
    Edit

    +
    {{ object }} {% if object.subtitle %}{{ object.subtitle }}{% endif %}
    +

    {{ object.db.desc }}

    +
    +
    + {% endfor %} + +
    +
    +
    +
    +
    +{% endblock %} + + From 0886b8ef286f7460250a83bf74f6f5594e18756d Mon Sep 17 00:00:00 2001 From: Johnny Date: Fri, 5 Oct 2018 21:07:07 +0000 Subject: [PATCH 21/48] Removes character update form. --- evennia/web/website/forms.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/evennia/web/website/forms.py b/evennia/web/website/forms.py index 937c6be6e8..8759d681e8 100644 --- a/evennia/web/website/forms.py +++ b/evennia/web/website/forms.py @@ -82,10 +82,6 @@ class CharacterForm(forms.Form): indices = [i for (i, value) in enumerate(buckets) if (value < min_points) or (value < max_points)] return buckets - -class CharacterUpdateForm(CharacterForm): - class Meta: - fields = ('description',) class ExtendedCharacterForm(CharacterForm): From c5f2ac171cf75b908c1dadd207c7a2c656ba48e4 Mon Sep 17 00:00:00 2001 From: Johnny Date: Fri, 5 Oct 2018 21:07:44 +0000 Subject: [PATCH 22/48] Adds character management/deletion views and some other changes. --- evennia/web/website/views.py | 30 +++++++++++++++++++++++++----- 1 file changed, 25 insertions(+), 5 deletions(-) diff --git a/evennia/web/website/views.py b/evennia/web/website/views.py index d25c3493ec..0ae996027c 100644 --- a/evennia/web/website/views.py +++ b/evennia/web/website/views.py @@ -8,13 +8,19 @@ templates on the fly. from django.contrib.admin.sites import site from django.conf import settings 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.db.models.functions import Lower from django.shortcuts import render +from django.urls import reverse_lazy +from django.views.generic import View, TemplateView, ListView, DetailView, FormView +from django.views.generic.edit import DeleteView from evennia import SESSION_HANDLER from evennia.objects.models import ObjectDB from evennia.accounts.models import AccountDB from evennia.utils import logger +from evennia.web.website.forms import AccountForm, CharacterForm from django.contrib.auth import login from django.utils.text import slugify @@ -185,23 +191,37 @@ class AccountCreationView(FormView): class CharacterManageView(LoginRequiredMixin, ListView): model = ObjectDB + paginate_by = 10 + template_name = 'website/character_manage_list.html' def get_queryset(self): # Get IDs of characters owned by account ids = [getattr(x, 'id') for x in self.request.user.db._playable_characters] # Return a queryset consisting of those characters - return self.model.filter(id__in=ids) + return self.model.objects.filter(id__in=ids).order_by(Lower('db_key')) class CharacterUpdateView(LoginRequiredMixin, FormView): - form_class = CharacterUpdateForm + form_class = CharacterForm template_name = 'website/generic_form.html' - success_url = '/'#reverse_lazy('character-manage') + success_url = reverse_lazy('manage-characters') + fields = ('description',) + +class CharacterDeleteView(LoginRequiredMixin, ObjectDetailView, DeleteView): + model = ObjectDB + + def get_queryset(self): + # Restrict characters available for deletion to those owned by + # the authenticated account + ids = [getattr(x, 'id') for x in self.request.user.db._playable_characters] + + # Return a queryset consisting of those characters + return self.model.objects.filter(id__in=ids).order_by(Lower('db_key')) class CharacterCreateView(LoginRequiredMixin, FormView): form_class = CharacterForm - template_name = 'website/chargen_form.html' - success_url = '/'#reverse_lazy('character-manage') + template_name = 'website/character_create_form.html' + success_url = reverse_lazy('manage-characters') def form_valid(self, form): # Get account ref From 6c56d591147540b17694c4ad40c14107ed27dbc8 Mon Sep 17 00:00:00 2001 From: Johnny Date: Fri, 5 Oct 2018 21:08:00 +0000 Subject: [PATCH 23/48] Adds links to charman views. --- evennia/web/website/templates/website/_menu.html | 2 +- evennia/web/website/urls.py | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/evennia/web/website/templates/website/_menu.html b/evennia/web/website/templates/website/_menu.html index 9874b7ef4a..90eabba4eb 100644 --- a/evennia/web/website/templates/website/_menu.html +++ b/evennia/web/website/templates/website/_menu.html @@ -44,7 +44,7 @@ folder and edit it to add/remove links to the menu.