evennia/docs/latest/Howtos/Web-Character-Generation.html
Evennia docbuilder action d17f22fc2c Updated HTML docs.
2024-03-17 13:48:03 +00:00

703 lines
No EOL
72 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" /><meta name="generator" content="Docutils 0.17.1: http://docutils.sourceforge.net/" />
<title>Web Character Generation &#8212; Evennia latest documentation</title>
<link rel="stylesheet" href="../_static/nature.css" type="text/css" />
<link rel="stylesheet" href="../_static/pygments.css" type="text/css" />
<script id="documentation_options" data-url_root="../" src="../_static/documentation_options.js"></script>
<script src="../_static/jquery.js"></script>
<script src="../_static/underscore.js"></script>
<script src="../_static/doctools.js"></script>
<script src="../_static/language_data.js"></script>
<link rel="shortcut icon" href="../_static/favicon.ico"/>
<link rel="index" title="Index" href="../genindex.html" />
<link rel="search" title="Search" href="../search.html" />
<link rel="next" title="Web Character View Tutorial" href="Web-Character-View-Tutorial.html" />
<link rel="prev" title="Add a wiki on your website" href="Web-Add-a-wiki.html" />
</head><body>
<div class="related" role="navigation" aria-label="related navigation">
<h3>Navigation</h3>
<ul>
<li class="right" style="margin-right: 10px">
<a href="../genindex.html" title="General Index"
accesskey="I">index</a></li>
<li class="right" >
<a href="../py-modindex.html" title="Python Module Index"
>modules</a> |</li>
<li class="right" >
<a href="Web-Character-View-Tutorial.html" title="Web Character View Tutorial"
accesskey="N">next</a> |</li>
<li class="right" >
<a href="Web-Add-a-wiki.html" title="Add a wiki on your website"
accesskey="P">previous</a> |</li>
<li class="nav-item nav-item-0"><a href="../index.html">Evennia latest</a> &#187;</li>
<li class="nav-item nav-item-1"><a href="Howtos-Overview.html" accesskey="U">Tutorials and How-Tos</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">Web Character Generation</a></li>
</ul>
</div>
<div class="document">
<div class="documentwrapper">
<div class="sphinxsidebar" role="navigation" aria-label="main navigation">
<div class="sphinxsidebarwrapper">
<p class="logo"><a href="../index.html">
<img class="logo" src="../_static/evennia_logo.png" alt="Logo"/>
</a></p>
<div id="searchbox" style="display: none" role="search">
<h3 id="searchlabel">Quick search</h3>
<div class="searchformwrapper">
<form class="search" action="../search.html" method="get">
<input type="text" name="q" aria-labelledby="searchlabel" />
<input type="submit" value="Go" />
</form>
</div>
</div>
<script>$('#searchbox').show(0);</script>
<h3><a href="../index.html">Table of Contents</a></h3>
<ul>
<li><a class="reference internal" href="#">Web Character Generation</a><ul>
<li><a class="reference internal" href="#introduction">Introduction</a></li>
<li><a class="reference internal" href="#pictures">Pictures</a></li>
<li><a class="reference internal" href="#installing-an-app">Installing an App</a><ul>
<li><a class="reference internal" href="#installing-checkpoint">Installing - Checkpoint:</a></li>
</ul>
</li>
<li><a class="reference internal" href="#create-models">Create Models</a><ul>
<li><a class="reference internal" href="#model-checkpoint">Model - Checkpoint:</a></li>
</ul>
</li>
<li><a class="reference internal" href="#create-views">Create Views</a><ul>
<li><a class="reference internal" href="#index-view"><em>Index</em> view</a></li>
<li><a class="reference internal" href="#detail-view"><em>Detail</em> view</a></li>
</ul>
</li>
<li><a class="reference internal" href="#creating-view"><em>Creating</em> view</a><ul>
<li><a class="reference internal" href="#create-views-checkpoint">Create Views - Checkpoint:</a></li>
</ul>
</li>
<li><a class="reference internal" href="#create-urls">Create URLs</a><ul>
<li><a class="reference internal" href="#urls-checkpoint">URLs - Checkpoint:</a></li>
</ul>
</li>
<li><a class="reference internal" href="#html-templates">HTML Templates</a><ul>
<li><a class="reference internal" href="#index-html">index.html</a></li>
<li><a class="reference internal" href="#detail-html">detail.html</a></li>
<li><a class="reference internal" href="#create-html">create.html</a></li>
<li><a class="reference internal" href="#templates-checkpoint">Templates - Checkpoint:</a></li>
</ul>
</li>
<li><a class="reference internal" href="#activating-your-new-character-generation">Activating your new character generation</a></li>
<li><a class="reference internal" href="#adding-a-no-capcha-recapcha-on-your-character-generation">Adding a no CAPCHA reCAPCHA on your character generation</a><ul>
<li><a class="reference internal" href="#step-1-obtain-a-sitekey-and-secret-from-google">Step 1: Obtain a SiteKey and secret from Google</a></li>
<li><a class="reference internal" href="#step-2-installing-and-configuring-the-dedicated-django-app">Step 2: installing and configuring the dedicated Django app</a></li>
<li><a class="reference internal" href="#step-3-adding-the-capcha-to-our-form">Step 3: Adding the CAPCHA to our form</a></li>
</ul>
</li>
</ul>
</li>
</ul>
<h4>Previous topic</h4>
<p class="topless"><a href="Web-Add-a-wiki.html"
title="previous chapter">Add a wiki on your website</a></p>
<h4>Next topic</h4>
<p class="topless"><a href="Web-Character-View-Tutorial.html"
title="next chapter">Web Character View Tutorial</a></p>
<div role="note" aria-label="source link">
<!--h3>This Page</h3-->
<ul class="this-page-menu">
<li><a href="../_sources/Howtos/Web-Character-Generation.md.txt"
rel="nofollow">Show Page Source</a></li>
</ul>
</div><h3>Links</h3>
<ul>
<li><a href="https://www.evennia.com/docs/latest/index.html">Documentation Top</a> </li>
<li><a href="https://www.evennia.com">Evennia Home</a> </li>
<li><a href="https://github.com/evennia/evennia">Github</a> </li>
<li><a href="http://games.evennia.com">Game Index</a> </li>
<li>
<a href="https://discord.gg/AJJpcRUhtF">Discord</a> -
<a href="https://github.com/evennia/evennia/discussions">Discussions</a> -
<a href="https://evennia.blogspot.com/">Blog</a>
</li>
</ul>
<h3>Doc Versions</h3>
<ul>
<li><a href="Web-Character-Generation.html">latest (main branch)</a></li>
<li><a href="../4.x/index.html">v4.0.0 branch (outdated)</a></li>
<li><a href="../3.x/index.html">v3.0.0 branch (outdated)</a></li>
<li><a href="../2.x/index.html">v2.0.0 branch (outdated)</a></li>
<li><a href="../1.x/index.html">v1.0.0 branch (outdated)</a></li>
<li><a href="../0.x/index.html">v0.9.5 branch (outdated)</a></li>
</ul>
</div>
</div>
<div class="bodywrapper">
<div class="body" role="main">
<section class="tex2jax_ignore mathjax_ignore" id="web-character-generation">
<h1>Web Character Generation<a class="headerlink" href="#web-character-generation" title="Permalink to this headline"></a></h1>
<section id="introduction">
<h2>Introduction<a class="headerlink" href="#introduction" title="Permalink to this headline"></a></h2>
<p>This tutorial will create a simple web-based interface for generating a new in-game Character. Accounts will need to have first logged into the website (with their <code class="docutils literal notranslate"><span class="pre">AccountDB</span></code> account). Once finishing character generation the Character will be created immediately and the Accounts can then log into the game and play immediately (the Character will not require staff approval or anything like that). This guide does not go over how to create an AccountDB on the website with the right permissions to transfer to their web-created characters.</p>
<p>It is probably most useful to set <code class="docutils literal notranslate"><span class="pre">AUTO_CREATE_CHARACTER_WITH_ACCOUNT</span> <span class="pre">=</span> <span class="pre">False</span></code> so that all player characters can be created through this.</p>
<p>You should have some familiarity with how Django sets up its Model Template View framework. You need to understand what is happening in the basic <a class="reference internal" href="Web-Character-View-Tutorial.html"><span class="doc std std-doc">Web Character View tutorial</span></a>. If you dont understand the listed tutorial or have a grasp of Django basics, please look at the <a class="reference external" href="https://docs.djangoproject.com/en/4.1/intro/">Django tutorial</a> to get a taste of what Django does, before throwing Evennia into the mix (Evennia shares its API and attributes with the website interface). This guide will outline the format of the models, views, urls, and html templates needed.</p>
</section>
<section id="pictures">
<h2>Pictures<a class="headerlink" href="#pictures" title="Permalink to this headline"></a></h2>
<p>Here are some screenshots of the simple app we will be making.</p>
<p>Index page, with no character application yet done:</p>
<hr class="docutils" />
<p><img alt="Index page, with no character application yet done." src="https://lh3.googleusercontent.com/-57KuSWHXQ_M/VWcULN152tI/AAAAAAAAEZg/kINTmVlHf6M/w425-h189-no/webchargen_index2.gif" /></p>
<hr class="docutils" />
<p>Having clicked the “create” link you get to create your character (here we will only have name and background, you can add whatever is needed to fit your game):</p>
<hr class="docutils" />
<p><img alt="Character creation." src="https://lh3.googleusercontent.com/-ORiOEM2R_yQ/VWcUKgy84rI/AAAAAAAAEZY/B3CBh3FHii4/w607-h60-no/webchargen_creation.gif" /></p>
<hr class="docutils" />
<p>Back to the index page. Having entered our character application (we called our character “TestApp”) you see it listed:</p>
<hr class="docutils" />
<p><img alt="Having entered an application." src="https://lh6.googleusercontent.com/-HlxvkvAimj4/VWcUKjFxEiI/AAAAAAAAEZo/gLppebr05JI/w321-h194-no/webchargen_index1.gif" /></p>
<hr class="docutils" />
<p>We can also view an already written character application by clicking on it - this brings us to the <em>detail</em> page:</p>
<hr class="docutils" />
<p><img alt="Detail view of character application." src="https://lh6.googleusercontent.com/-2m1UhSE7s_k/VWcUKfLRfII/AAAAAAAAEZc/UFmBOqVya4k/w267-h175-no/webchargen_detail.gif" /></p>
</section>
<hr class="docutils" />
<section id="installing-an-app">
<h2>Installing an App<a class="headerlink" href="#installing-an-app" title="Permalink to this headline"></a></h2>
<p>Assuming your game is named “mygame”, navigate to your <code class="docutils literal notranslate"><span class="pre">mygame/</span></code> directory, and type:</p>
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>cd web
evennia startapp chargen
</pre></div>
</div>
<p>This will initialize a new Django app we choose to call “chargen” in <code class="docutils literal notranslate"><span class="pre">mygame/web/</span></code>. We put it under <code class="docutils literal notranslate"><span class="pre">web/</span></code> to keep all web stuff together, but you can organize however you like. It is directory containing some basic starting things Django needs.</p>
<p>Next, navigate to <code class="docutils literal notranslate"><span class="pre">mygame/server/conf/settings.py</span></code> and add or edit the following line to make Evennia (and Django) aware of our new app:</p>
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>INSTALLED_APPS += (&#39;web.chargen&#39;,)
</pre></div>
</div>
<p>After this, we will get into defining our <em>models</em> (the description of the database storage),
<em>views</em> (the server-side website content generators), <em>urls</em> (how the web browser finds the pages) and <em>templates</em> (how the web page should be structured).</p>
<section id="installing-checkpoint">
<h3>Installing - Checkpoint:<a class="headerlink" href="#installing-checkpoint" title="Permalink to this headline"></a></h3>
<ul class="simple">
<li><p>you should have a folder named <code class="docutils literal notranslate"><span class="pre">chargen</span></code> or whatever you chose in your mygame/web/ directory</p></li>
<li><p>you should have your application name added to your INSTALLED_APPS in <a class="reference external" href="http://settings.py">settings.py</a></p></li>
</ul>
</section>
</section>
<section id="create-models">
<h2>Create Models<a class="headerlink" href="#create-models" title="Permalink to this headline"></a></h2>
<p>Models are created in <code class="docutils literal notranslate"><span class="pre">mygame/web/chargen/models.py</span></code>.</p>
<p>A <a class="reference internal" href="../Concepts/Models.html"><span class="doc std std-doc">Django database model</span></a> is a Python class that describes the database storage of the
data you want to manage. Any data you choose to store is stored in the same database as the game and you have access to all the games objects here.</p>
<p>We need to define what a character application actually is. This will differ from game to game so for this tutorial we will define a simple character sheet with the following database fields:</p>
<ul class="simple">
<li><p><code class="docutils literal notranslate"><span class="pre">app_id</span></code> (AutoField): Primary key for this character application sheet.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">char_name</span></code> (CharField): The new characters name.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">date_applied</span></code> (DateTimeField): Date that this application was received.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">background</span></code> (TextField): Character story background.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">account_id</span></code> (IntegerField): Which account ID does this application belong to? This is an
AccountID from the AccountDB object.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">submitted</span></code> (BooleanField): <code class="docutils literal notranslate"><span class="pre">True</span></code>/<code class="docutils literal notranslate"><span class="pre">False</span></code> depending on if the application has been submitted yet.</p></li>
</ul>
<blockquote>
<div><p>Note: In a full-fledged game, youd likely want them to be able to select races, skills, attributes and so on.</p>
</div></blockquote>
<p>Our <code class="docutils literal notranslate"><span class="pre">models.py</span></code> file should look something like this:</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="c1"># in mygame/web/chargen/models.py</span>
<span class="kn">from</span> <span class="nn">django.db</span> <span class="kn">import</span> <span class="n">models</span>
<span class="k">class</span> <span class="nc">CharApp</span><span class="p">(</span><span class="n">models</span><span class="o">.</span><span class="n">Model</span><span class="p">):</span>
<span class="n">app_id</span> <span class="o">=</span> <span class="n">models</span><span class="o">.</span><span class="n">AutoField</span><span class="p">(</span><span class="n">primary_key</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
<span class="n">char_name</span> <span class="o">=</span> <span class="n">models</span><span class="o">.</span><span class="n">CharField</span><span class="p">(</span><span class="n">max_length</span><span class="o">=</span><span class="mi">80</span><span class="p">,</span> <span class="n">verbose_name</span><span class="o">=</span><span class="s1">&#39;Character Name&#39;</span><span class="p">)</span>
<span class="n">date_applied</span> <span class="o">=</span> <span class="n">models</span><span class="o">.</span><span class="n">DateTimeField</span><span class="p">(</span><span class="n">verbose_name</span><span class="o">=</span><span class="s1">&#39;Date Applied&#39;</span><span class="p">)</span>
<span class="n">background</span> <span class="o">=</span> <span class="n">models</span><span class="o">.</span><span class="n">TextField</span><span class="p">(</span><span class="n">verbose_name</span><span class="o">=</span><span class="s1">&#39;Background&#39;</span><span class="p">)</span>
<span class="n">account_id</span> <span class="o">=</span> <span class="n">models</span><span class="o">.</span><span class="n">IntegerField</span><span class="p">(</span><span class="n">default</span><span class="o">=</span><span class="mi">1</span><span class="p">,</span> <span class="n">verbose_name</span><span class="o">=</span><span class="s1">&#39;Account ID&#39;</span><span class="p">)</span>
<span class="n">submitted</span> <span class="o">=</span> <span class="n">models</span><span class="o">.</span><span class="n">BooleanField</span><span class="p">(</span><span class="n">default</span><span class="o">=</span><span class="kc">False</span><span class="p">)</span>
</pre></div>
</div>
<p>You should consider how you are going to link your application to your account. For this tutorial, we are using the account_id attribute on our character application model in order to keep track of which characters are owned by which accounts. Since the account id is a primary key in Evennia, it is a good candidate, as you will never have two of the same IDs in Evennia. You can feel free to use anything else, but for the purposes of this guide, we are going to use account ID to join the character applications with the proper account.</p>
<section id="model-checkpoint">
<h3>Model - Checkpoint:<a class="headerlink" href="#model-checkpoint" title="Permalink to this headline"></a></h3>
<ul class="simple">
<li><p>you should have filled out <code class="docutils literal notranslate"><span class="pre">mygame/web/chargen/models.py</span></code> with the model class shown above (eventually adding fields matching what you need for your game).</p></li>
</ul>
</section>
</section>
<section id="create-views">
<h2>Create Views<a class="headerlink" href="#create-views" title="Permalink to this headline"></a></h2>
<p><em>Views</em> are server-side constructs that make dynamic data available to a web page. We are going to add them to <code class="docutils literal notranslate"><span class="pre">mygame/web/chargen.views.py</span></code>. Each view in our example represents the backbone of a
specific web page. We will use three views and three pages here:</p>
<ul class="simple">
<li><p>The index (managing <code class="docutils literal notranslate"><span class="pre">index.html</span></code>). This is what you see when you navigate to
<code class="docutils literal notranslate"><span class="pre">http://yoursite.com/chargen</span></code>.</p></li>
<li><p>The detail display sheet (manages <code class="docutils literal notranslate"><span class="pre">detail.html</span></code>). A page that passively displays the stats of a given Character.</p></li>
<li><p>Character creation sheet (manages <code class="docutils literal notranslate"><span class="pre">create.html</span></code>). This is the main form with fields to fill in.</p></li>
</ul>
<section id="index-view">
<h3><em>Index</em> view<a class="headerlink" href="#index-view" title="Permalink to this headline"></a></h3>
<p>Lets get started with the index first.</p>
<p>Well want characters to be able to see their created characters so lets</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="c1"># file mygame/web/chargen.views.py</span>
<span class="kn">from</span> <span class="nn">.models</span> <span class="kn">import</span> <span class="n">CharApp</span>
<span class="k">def</span> <span class="nf">index</span><span class="p">(</span><span class="n">request</span><span class="p">):</span>
<span class="n">current_user</span> <span class="o">=</span> <span class="n">request</span><span class="o">.</span><span class="n">user</span> <span class="c1"># current user logged in</span>
<span class="n">p_id</span> <span class="o">=</span> <span class="n">current_user</span><span class="o">.</span><span class="n">id</span> <span class="c1"># the account id</span>
<span class="c1"># submitted Characters by this account</span>
<span class="n">sub_apps</span> <span class="o">=</span> <span class="n">CharApp</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">filter</span><span class="p">(</span><span class="n">account_id</span><span class="o">=</span><span class="n">p_id</span><span class="p">,</span> <span class="n">submitted</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
<span class="n">context</span> <span class="o">=</span> <span class="p">{</span><span class="s1">&#39;sub_apps&#39;</span><span class="p">:</span> <span class="n">sub_apps</span><span class="p">}</span>
<span class="c1"># make the variables in &#39;context&#39; available to the web page template</span>
<span class="k">return</span> <span class="n">render</span><span class="p">(</span><span class="n">request</span><span class="p">,</span> <span class="s1">&#39;chargen/index.html&#39;</span><span class="p">,</span> <span class="n">context</span><span class="p">)</span>
</pre></div>
</div>
</section>
<section id="detail-view">
<h3><em>Detail</em> view<a class="headerlink" href="#detail-view" title="Permalink to this headline"></a></h3>
<p>Our detail page will have pertinent character application information our users can see. Since this is a basic demonstration, our detail page will only show two fields:</p>
<ul class="simple">
<li><p>Character name</p></li>
<li><p>Character background</p></li>
</ul>
<p>We will use the account ID again just to double-check that whoever tries to check our character page is actually the account who owns the application.</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="c1"># file mygame/web/chargen.views.py</span>
<span class="k">def</span> <span class="nf">detail</span><span class="p">(</span><span class="n">request</span><span class="p">,</span> <span class="n">app_id</span><span class="p">):</span>
<span class="n">app</span> <span class="o">=</span> <span class="n">CharApp</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">app_id</span><span class="o">=</span><span class="n">app_id</span><span class="p">)</span>
<span class="n">name</span> <span class="o">=</span> <span class="n">app</span><span class="o">.</span><span class="n">char_name</span>
<span class="n">background</span> <span class="o">=</span> <span class="n">app</span><span class="o">.</span><span class="n">background</span>
<span class="n">submitted</span> <span class="o">=</span> <span class="n">app</span><span class="o">.</span><span class="n">submitted</span>
<span class="n">p_id</span> <span class="o">=</span> <span class="n">request</span><span class="o">.</span><span class="n">user</span><span class="o">.</span><span class="n">id</span>
<span class="n">context</span> <span class="o">=</span> <span class="p">{</span><span class="s1">&#39;name&#39;</span><span class="p">:</span> <span class="n">name</span><span class="p">,</span> <span class="s1">&#39;background&#39;</span><span class="p">:</span> <span class="n">background</span><span class="p">,</span>
<span class="s1">&#39;p_id&#39;</span><span class="p">:</span> <span class="n">p_id</span><span class="p">,</span> <span class="s1">&#39;submitted&#39;</span><span class="p">:</span> <span class="n">submitted</span><span class="p">}</span>
<span class="k">return</span> <span class="n">render</span><span class="p">(</span><span class="n">request</span><span class="p">,</span> <span class="s1">&#39;chargen/detail.html&#39;</span><span class="p">,</span> <span class="n">context</span><span class="p">)</span>
</pre></div>
</div>
</section>
</section>
<section id="creating-view">
<h2><em>Creating</em> view<a class="headerlink" href="#creating-view" title="Permalink to this headline"></a></h2>
<p>Predictably, our <em>create</em> function will be the most complicated of the views, as it needs to accept information from the user, validate the information, and send the information to the server. Once the form content is validated will actually create a playable Character.</p>
<p>The form itself we will define first. In our simple example we are just looking for the Characters name and background. This form we create in <code class="docutils literal notranslate"><span class="pre">mygame/web/chargen/forms.py</span></code>:</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="c1"># file mygame/web/chargen/forms.py</span>
<span class="kn">from</span> <span class="nn">django</span> <span class="kn">import</span> <span class="n">forms</span>
<span class="k">class</span> <span class="nc">AppForm</span><span class="p">(</span><span class="n">forms</span><span class="o">.</span><span class="n">Form</span><span class="p">):</span>
<span class="n">name</span> <span class="o">=</span> <span class="n">forms</span><span class="o">.</span><span class="n">CharField</span><span class="p">(</span><span class="n">label</span><span class="o">=</span><span class="s1">&#39;Character Name&#39;</span><span class="p">,</span> <span class="n">max_length</span><span class="o">=</span><span class="mi">80</span><span class="p">)</span>
<span class="n">background</span> <span class="o">=</span> <span class="n">forms</span><span class="o">.</span><span class="n">CharField</span><span class="p">(</span><span class="n">label</span><span class="o">=</span><span class="s1">&#39;Background&#39;</span><span class="p">)</span>
</pre></div>
</div>
<p>Now we make use of this form in our view.</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="c1"># file mygame/web/chargen/views.py</span>
<span class="kn">from</span> <span class="nn">web.chargen.models</span> <span class="kn">import</span> <span class="n">CharApp</span>
<span class="kn">from</span> <span class="nn">web.chargen.forms</span> <span class="kn">import</span> <span class="n">AppForm</span>
<span class="kn">from</span> <span class="nn">django.http</span> <span class="kn">import</span> <span class="n">HttpResponseRedirect</span>
<span class="kn">from</span> <span class="nn">datetime</span> <span class="kn">import</span> <span class="n">datetime</span>
<span class="kn">from</span> <span class="nn">evennia.objects.models</span> <span class="kn">import</span> <span class="n">ObjectDB</span>
<span class="kn">from</span> <span class="nn">django.conf</span> <span class="kn">import</span> <span class="n">settings</span>
<span class="kn">from</span> <span class="nn">evennia.utils</span> <span class="kn">import</span> <span class="n">create</span>
<span class="k">def</span> <span class="nf">creating</span><span class="p">(</span><span class="n">request</span><span class="p">):</span>
<span class="n">user</span> <span class="o">=</span> <span class="n">request</span><span class="o">.</span><span class="n">user</span>
<span class="k">if</span> <span class="n">request</span><span class="o">.</span><span class="n">method</span> <span class="o">==</span> <span class="s1">&#39;POST&#39;</span><span class="p">:</span>
<span class="n">form</span> <span class="o">=</span> <span class="n">AppForm</span><span class="p">(</span><span class="n">request</span><span class="o">.</span><span class="n">POST</span><span class="p">)</span>
<span class="k">if</span> <span class="n">form</span><span class="o">.</span><span class="n">is_valid</span><span class="p">():</span>
<span class="n">name</span> <span class="o">=</span> <span class="n">form</span><span class="o">.</span><span class="n">cleaned_data</span><span class="p">[</span><span class="s1">&#39;name&#39;</span><span class="p">]</span>
<span class="n">background</span> <span class="o">=</span> <span class="n">form</span><span class="o">.</span><span class="n">cleaned_data</span><span class="p">[</span><span class="s1">&#39;background&#39;</span><span class="p">]</span>
<span class="n">applied_date</span> <span class="o">=</span> <span class="n">datetime</span><span class="o">.</span><span class="n">now</span><span class="p">()</span>
<span class="n">submitted</span> <span class="o">=</span> <span class="kc">True</span>
<span class="k">if</span> <span class="s1">&#39;save&#39;</span> <span class="ow">in</span> <span class="n">request</span><span class="o">.</span><span class="n">POST</span><span class="p">:</span>
<span class="n">submitted</span> <span class="o">=</span> <span class="kc">False</span>
<span class="n">app</span> <span class="o">=</span> <span class="n">CharApp</span><span class="p">(</span><span class="n">char_name</span><span class="o">=</span><span class="n">name</span><span class="p">,</span> <span class="n">background</span><span class="o">=</span><span class="n">background</span><span class="p">,</span>
<span class="n">date_applied</span><span class="o">=</span><span class="n">applied_date</span><span class="p">,</span> <span class="n">account_id</span><span class="o">=</span><span class="n">user</span><span class="o">.</span><span class="n">id</span><span class="p">,</span>
<span class="n">submitted</span><span class="o">=</span><span class="n">submitted</span><span class="p">)</span>
<span class="n">app</span><span class="o">.</span><span class="n">save</span><span class="p">()</span>
<span class="k">if</span> <span class="n">submitted</span><span class="p">:</span>
<span class="c1"># Create the actual character object</span>
<span class="n">typeclass</span> <span class="o">=</span> <span class="n">settings</span><span class="o">.</span><span class="n">BASE_CHARACTER_TYPECLASS</span>
<span class="n">home</span> <span class="o">=</span> <span class="n">ObjectDB</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">get_id</span><span class="p">(</span><span class="n">settings</span><span class="o">.</span><span class="n">GUEST_HOME</span><span class="p">)</span>
<span class="c1"># turn the permissionhandler to a string</span>
<span class="n">perms</span> <span class="o">=</span> <span class="nb">str</span><span class="p">(</span><span class="n">user</span><span class="o">.</span><span class="n">permissions</span><span class="p">)</span>
<span class="c1"># create the character</span>
<span class="n">char</span> <span class="o">=</span> <span class="n">create</span><span class="o">.</span><span class="n">create_object</span><span class="p">(</span><span class="n">typeclass</span><span class="o">=</span><span class="n">typeclass</span><span class="p">,</span> <span class="n">key</span><span class="o">=</span><span class="n">name</span><span class="p">,</span>
<span class="n">home</span><span class="o">=</span><span class="n">home</span><span class="p">,</span> <span class="n">permissions</span><span class="o">=</span><span class="n">perms</span><span class="p">)</span>
<span class="n">user</span><span class="o">.</span><span class="n">add_character</span><span class="p">(</span><span class="n">char</span><span class="p">)</span>
<span class="c1"># add the right locks for the character so the account can</span>
<span class="c1"># puppet it</span>
<span class="n">char</span><span class="o">.</span><span class="n">locks</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="s2">&quot; or &quot;</span><span class="o">.</span><span class="n">join</span><span class="p">([</span>
<span class="sa">f</span><span class="s2">&quot;puppet:id(</span><span class="si">{</span><span class="n">char</span><span class="o">.</span><span class="n">id</span><span class="si">}</span><span class="s2">)&quot;</span><span class="p">,</span>
<span class="sa">f</span><span class="s2">&quot;pid(</span><span class="si">{</span><span class="n">user</span><span class="o">.</span><span class="n">id</span><span class="si">}</span><span class="s2">)&quot;</span><span class="p">,</span>
<span class="s2">&quot;perm(Developers)&quot;</span><span class="p">,</span>
<span class="s2">&quot;pperm(Developers)&quot;</span><span class="p">,</span>
<span class="p">]))</span>
<span class="n">char</span><span class="o">.</span><span class="n">db</span><span class="o">.</span><span class="n">background</span> <span class="o">=</span> <span class="n">background</span> <span class="c1"># set the character background</span>
<span class="k">return</span> <span class="n">HttpResponseRedirect</span><span class="p">(</span><span class="s1">&#39;/chargen&#39;</span><span class="p">)</span>
<span class="k">else</span><span class="p">:</span>
<span class="n">form</span> <span class="o">=</span> <span class="n">AppForm</span><span class="p">()</span>
<span class="k">return</span> <span class="n">render</span><span class="p">(</span><span class="n">request</span><span class="p">,</span> <span class="s1">&#39;chargen/create.html&#39;</span><span class="p">,</span> <span class="p">{</span><span class="s1">&#39;form&#39;</span><span class="p">:</span> <span class="n">form</span><span class="p">})</span>
</pre></div>
</div>
<blockquote>
<div><p>Note also that we basically create the character using the Evennia API, and we grab the proper permissions from the <code class="docutils literal notranslate"><span class="pre">AccountDB</span></code> object and copy them to the character object. We take the user permissions attribute and turn that list of strings into a string object in order for the create_object function to properly process the permissions.</p>
</div></blockquote>
<p>Most importantly, the following attributes must be set on the created character object:</p>
<ul class="simple">
<li><p>Evennia <a class="reference internal" href="../Components/Permissions.html"><span class="doc std std-doc">permissions</span></a> (copied from the <code class="docutils literal notranslate"><span class="pre">AccountDB</span></code>).</p></li>
<li><p>The right <code class="docutils literal notranslate"><span class="pre">puppet</span></code> <a class="reference internal" href="../Components/Locks.html"><span class="doc std std-doc">locks</span></a> so the Account can actually play as this Character later.</p></li>
<li><p>The relevant Character <a class="reference internal" href="../Components/Typeclasses.html"><span class="doc std std-doc">typeclass</span></a></p></li>
<li><p>Character name (key)</p></li>
<li><p>The Characters home room location (<code class="docutils literal notranslate"><span class="pre">#2</span></code> by default)</p></li>
</ul>
<p>Other attributes are strictly speaking optional, such as the <code class="docutils literal notranslate"><span class="pre">background</span></code> attribute on our character. It may be a good idea to decompose this function and create a separate _create_character function in order to set up your character object the account owns. But with the Evennia API, setting custom attributes is as easy as doing it in the meat of your Evennia game directory.</p>
<p>After all of this, our <code class="docutils literal notranslate"><span class="pre">views.py</span></code> file should look like something like this:</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="c1"># file mygame/web/chargen/views.py</span>
<span class="kn">from</span> <span class="nn">django.shortcuts</span> <span class="kn">import</span> <span class="n">render</span>
<span class="kn">from</span> <span class="nn">web.chargen.models</span> <span class="kn">import</span> <span class="n">CharApp</span>
<span class="kn">from</span> <span class="nn">web.chargen.forms</span> <span class="kn">import</span> <span class="n">AppForm</span>
<span class="kn">from</span> <span class="nn">django.http</span> <span class="kn">import</span> <span class="n">HttpResponseRedirect</span>
<span class="kn">from</span> <span class="nn">datetime</span> <span class="kn">import</span> <span class="n">datetime</span>
<span class="kn">from</span> <span class="nn">evennia.objects.models</span> <span class="kn">import</span> <span class="n">ObjectDB</span>
<span class="kn">from</span> <span class="nn">django.conf</span> <span class="kn">import</span> <span class="n">settings</span>
<span class="kn">from</span> <span class="nn">evennia.utils</span> <span class="kn">import</span> <span class="n">create</span>
<span class="k">def</span> <span class="nf">index</span><span class="p">(</span><span class="n">request</span><span class="p">):</span>
<span class="n">current_user</span> <span class="o">=</span> <span class="n">request</span><span class="o">.</span><span class="n">user</span> <span class="c1"># current user logged in</span>
<span class="n">p_id</span> <span class="o">=</span> <span class="n">current_user</span><span class="o">.</span><span class="n">id</span> <span class="c1"># the account id</span>
<span class="c1"># submitted apps under this account</span>
<span class="n">sub_apps</span> <span class="o">=</span> <span class="n">CharApp</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">filter</span><span class="p">(</span><span class="n">account_id</span><span class="o">=</span><span class="n">p_id</span><span class="p">,</span> <span class="n">submitted</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
<span class="n">context</span> <span class="o">=</span> <span class="p">{</span><span class="s1">&#39;sub_apps&#39;</span><span class="p">:</span> <span class="n">sub_apps</span><span class="p">}</span>
<span class="k">return</span> <span class="n">render</span><span class="p">(</span><span class="n">request</span><span class="p">,</span> <span class="s1">&#39;chargen/index.html&#39;</span><span class="p">,</span> <span class="n">context</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">detail</span><span class="p">(</span><span class="n">request</span><span class="p">,</span> <span class="n">app_id</span><span class="p">):</span>
<span class="n">app</span> <span class="o">=</span> <span class="n">CharApp</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">app_id</span><span class="o">=</span><span class="n">app_id</span><span class="p">)</span>
<span class="n">name</span> <span class="o">=</span> <span class="n">app</span><span class="o">.</span><span class="n">char_name</span>
<span class="n">background</span> <span class="o">=</span> <span class="n">app</span><span class="o">.</span><span class="n">background</span>
<span class="n">submitted</span> <span class="o">=</span> <span class="n">app</span><span class="o">.</span><span class="n">submitted</span>
<span class="n">p_id</span> <span class="o">=</span> <span class="n">request</span><span class="o">.</span><span class="n">user</span><span class="o">.</span><span class="n">id</span>
<span class="n">context</span> <span class="o">=</span> <span class="p">{</span><span class="s1">&#39;name&#39;</span><span class="p">:</span> <span class="n">name</span><span class="p">,</span> <span class="s1">&#39;background&#39;</span><span class="p">:</span> <span class="n">background</span><span class="p">,</span>
<span class="s1">&#39;p_id&#39;</span><span class="p">:</span> <span class="n">p_id</span><span class="p">,</span> <span class="s1">&#39;submitted&#39;</span><span class="p">:</span> <span class="n">submitted</span><span class="p">}</span>
<span class="k">return</span> <span class="n">render</span><span class="p">(</span><span class="n">request</span><span class="p">,</span> <span class="s1">&#39;chargen/detail.html&#39;</span><span class="p">,</span> <span class="n">context</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">creating</span><span class="p">(</span><span class="n">request</span><span class="p">):</span>
<span class="n">user</span> <span class="o">=</span> <span class="n">request</span><span class="o">.</span><span class="n">user</span>
<span class="k">if</span> <span class="n">request</span><span class="o">.</span><span class="n">method</span> <span class="o">==</span> <span class="s1">&#39;POST&#39;</span><span class="p">:</span>
<span class="n">form</span> <span class="o">=</span> <span class="n">AppForm</span><span class="p">(</span><span class="n">request</span><span class="o">.</span><span class="n">POST</span><span class="p">)</span>
<span class="k">if</span> <span class="n">form</span><span class="o">.</span><span class="n">is_valid</span><span class="p">():</span>
<span class="n">name</span> <span class="o">=</span> <span class="n">form</span><span class="o">.</span><span class="n">cleaned_data</span><span class="p">[</span><span class="s1">&#39;name&#39;</span><span class="p">]</span>
<span class="n">background</span> <span class="o">=</span> <span class="n">form</span><span class="o">.</span><span class="n">cleaned_data</span><span class="p">[</span><span class="s1">&#39;background&#39;</span><span class="p">]</span>
<span class="n">applied_date</span> <span class="o">=</span> <span class="n">datetime</span><span class="o">.</span><span class="n">now</span><span class="p">()</span>
<span class="n">submitted</span> <span class="o">=</span> <span class="kc">True</span>
<span class="k">if</span> <span class="s1">&#39;save&#39;</span> <span class="ow">in</span> <span class="n">request</span><span class="o">.</span><span class="n">POST</span><span class="p">:</span>
<span class="n">submitted</span> <span class="o">=</span> <span class="kc">False</span>
<span class="n">app</span> <span class="o">=</span> <span class="n">CharApp</span><span class="p">(</span><span class="n">char_name</span><span class="o">=</span><span class="n">name</span><span class="p">,</span> <span class="n">background</span><span class="o">=</span><span class="n">background</span><span class="p">,</span>
<span class="n">date_applied</span><span class="o">=</span><span class="n">applied_date</span><span class="p">,</span> <span class="n">account_id</span><span class="o">=</span><span class="n">user</span><span class="o">.</span><span class="n">id</span><span class="p">,</span>
<span class="n">submitted</span><span class="o">=</span><span class="n">submitted</span><span class="p">)</span>
<span class="n">app</span><span class="o">.</span><span class="n">save</span><span class="p">()</span>
<span class="k">if</span> <span class="n">submitted</span><span class="p">:</span>
<span class="c1"># Create the actual character object</span>
<span class="n">typeclass</span> <span class="o">=</span> <span class="n">settings</span><span class="o">.</span><span class="n">BASE_CHARACTER_TYPECLASS</span>
<span class="n">home</span> <span class="o">=</span> <span class="n">ObjectDB</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">get_id</span><span class="p">(</span><span class="n">settings</span><span class="o">.</span><span class="n">GUEST_HOME</span><span class="p">)</span>
<span class="c1"># turn the permissionhandler to a string</span>
<span class="n">perms</span> <span class="o">=</span> <span class="nb">str</span><span class="p">(</span><span class="n">user</span><span class="o">.</span><span class="n">permissions</span><span class="p">)</span>
<span class="c1"># create the character</span>
<span class="n">char</span> <span class="o">=</span> <span class="n">create</span><span class="o">.</span><span class="n">create_object</span><span class="p">(</span><span class="n">typeclass</span><span class="o">=</span><span class="n">typeclass</span><span class="p">,</span> <span class="n">key</span><span class="o">=</span><span class="n">name</span><span class="p">,</span>
<span class="n">home</span><span class="o">=</span><span class="n">home</span><span class="p">,</span> <span class="n">permissions</span><span class="o">=</span><span class="n">perms</span><span class="p">)</span>
<span class="n">user</span><span class="o">.</span><span class="n">add_character</span><span class="p">(</span><span class="n">char</span><span class="p">)</span>
<span class="c1"># add the right locks for the character so the account can</span>
<span class="c1"># puppet it</span>
<span class="n">char</span><span class="o">.</span><span class="n">locks</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="s2">&quot; or &quot;</span><span class="o">.</span><span class="n">join</span><span class="p">([</span>
<span class="sa">f</span><span class="s2">&quot;puppet:id(</span><span class="si">{</span><span class="n">char</span><span class="o">.</span><span class="n">id</span><span class="si">}</span><span class="s2">)&quot;</span><span class="p">,</span>
<span class="sa">f</span><span class="s2">&quot;pid(</span><span class="si">{</span><span class="n">user</span><span class="o">.</span><span class="n">id</span><span class="si">}</span><span class="s2">)&quot;</span><span class="p">,</span>
<span class="s2">&quot;perm(Developers)&quot;</span><span class="p">,</span>
<span class="s2">&quot;pperm(Developers)&quot;</span><span class="p">,</span>
<span class="p">]))</span>
<span class="n">char</span><span class="o">.</span><span class="n">db</span><span class="o">.</span><span class="n">background</span> <span class="o">=</span> <span class="n">background</span> <span class="c1"># set the character background</span>
<span class="k">return</span> <span class="n">HttpResponseRedirect</span><span class="p">(</span><span class="s1">&#39;/chargen&#39;</span><span class="p">)</span>
<span class="k">else</span><span class="p">:</span>
<span class="n">form</span> <span class="o">=</span> <span class="n">AppForm</span><span class="p">()</span>
<span class="k">return</span> <span class="n">render</span><span class="p">(</span><span class="n">request</span><span class="p">,</span> <span class="s1">&#39;chargen/create.html&#39;</span><span class="p">,</span> <span class="p">{</span><span class="s1">&#39;form&#39;</span><span class="p">:</span> <span class="n">form</span><span class="p">})</span>
</pre></div>
</div>
<section id="create-views-checkpoint">
<h3>Create Views - Checkpoint:<a class="headerlink" href="#create-views-checkpoint" title="Permalink to this headline"></a></h3>
<ul class="simple">
<li><p>youve defined a <code class="docutils literal notranslate"><span class="pre">views.py</span></code> that has an index, detail, and creating functions.</p></li>
<li><p>youve defined a <a class="reference external" href="http://forms.py">forms.py</a> with the <code class="docutils literal notranslate"><span class="pre">AppForm</span></code> class needed by the <code class="docutils literal notranslate"><span class="pre">creating</span></code> function of <code class="docutils literal notranslate"><span class="pre">views.py</span></code>.</p></li>
<li><p>your <code class="docutils literal notranslate"><span class="pre">mygame/web/chargen</span></code> directory should now have a <code class="docutils literal notranslate"><span class="pre">views.py</span></code> and <code class="docutils literal notranslate"><span class="pre">forms.py</span></code> file</p></li>
</ul>
</section>
</section>
<section id="create-urls">
<h2>Create URLs<a class="headerlink" href="#create-urls" title="Permalink to this headline"></a></h2>
<p>URL patterns helps redirect requests from the web browser to the right views. These patterns are created in <code class="docutils literal notranslate"><span class="pre">mygame/web/chargen/urls.py</span></code>.</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="c1"># file mygame/web/chargen/urls.py</span>
<span class="kn">from</span> <span class="nn">django.urls</span> <span class="kn">import</span> <span class="n">path</span>
<span class="kn">from</span> <span class="nn">web.chargen</span> <span class="kn">import</span> <span class="n">views</span>
<span class="n">urlpatterns</span> <span class="o">=</span> <span class="p">[</span>
<span class="c1"># url: /chargen/</span>
<span class="n">path</span><span class="p">(</span><span class="s2">&quot;&quot;</span><span class="p">,</span> <span class="n">views</span><span class="o">.</span><span class="n">index</span><span class="p">,</span> <span class="n">name</span><span class="o">=</span><span class="s1">&#39;chargen-index&#39;</span><span class="p">),</span>
<span class="c1"># url: /chargen/5/</span>
<span class="n">path</span><span class="p">(</span><span class="s2">&quot;&lt;int:app_id&gt;/&quot;</span><span class="p">,</span> <span class="n">views</span><span class="o">.</span><span class="n">detail</span><span class="p">,</span> <span class="n">name</span><span class="o">=</span><span class="s2">&quot;chargen-detail&quot;</span><span class="p">),</span>
<span class="c1"># url: /chargen/create</span>
<span class="n">path</span><span class="p">(</span><span class="s2">&quot;create/&quot;</span><span class="p">,</span> <span class="n">views</span><span class="o">.</span><span class="n">creating</span><span class="p">,</span> <span class="n">name</span><span class="o">=</span><span class="s1">&#39;chargen-creating&#39;</span><span class="p">),</span>
<span class="p">]</span>
</pre></div>
</div>
<p>You could change the format as you desire. To make it more secure, you could remove app_id from the “detail” url, and instead just fetch the accounts applications using a unifying field like account_id to find all the character application objects to display.</p>
<p>To add this to our website, we must also update the main <code class="docutils literal notranslate"><span class="pre">mygame/website/urls.py</span></code> file; this will help tying our new chargen app in with the rest of the website. <code class="docutils literal notranslate"><span class="pre">urlpatterns</span></code> variable, and change it to include:</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="c1"># in file mygame/website/urls.py</span>
<span class="kn">from</span> <span class="nn">django.urls</span> <span class="kn">import</span> <span class="n">path</span><span class="p">,</span> <span class="n">include</span>
<span class="n">urlpatterns</span> <span class="o">=</span> <span class="p">[</span>
<span class="c1"># make all chargen endpoints available under /chargen url</span>
<span class="n">path</span><span class="p">(</span><span class="s2">&quot;chargen/&quot;</span><span class="p">,</span> <span class="n">include</span><span class="p">(</span><span class="s2">&quot;web.chargen.urls&quot;</span><span class="p">)</span>
<span class="p">]</span>
</pre></div>
</div>
<section id="urls-checkpoint">
<h3>URLs - Checkpoint:<a class="headerlink" href="#urls-checkpoint" title="Permalink to this headline"></a></h3>
<ul class="simple">
<li><p>Youve created a <a class="reference external" href="http://urls.py">urls.py</a> file in the <code class="docutils literal notranslate"><span class="pre">mygame/web/chargen</span></code> directory</p></li>
<li><p>You have edited the main <code class="docutils literal notranslate"><span class="pre">mygame/web/urls.py</span></code> file to include urls to the <code class="docutils literal notranslate"><span class="pre">chargen</span></code> directory.</p></li>
</ul>
</section>
</section>
<section id="html-templates">
<h2>HTML Templates<a class="headerlink" href="#html-templates" title="Permalink to this headline"></a></h2>
<p>So we have our url patterns, views, and models defined. Now we must define our HTML templates that the actual user will see and interact with. For this tutorial we us the basic <em>prosimii</em> template that comes with Evennia.</p>
<p>Take note that we use <code class="docutils literal notranslate"><span class="pre">user.is_authenticated</span></code> to make sure that the user cannot create a character without logging in.</p>
<p>These files will all go into the <code class="docutils literal notranslate"><span class="pre">/mygame/web/chargen/templates/chargen/</span></code> directory.</p>
<section id="index-html">
<h3>index.html<a class="headerlink" href="#index-html" title="Permalink to this headline"></a></h3>
<p>This HTML template should hold a list of all the applications the account currently has active. For this demonstration, we will only list the applications that the account has submitted. You could easily adjust this to include saved applications, or other types of applications if you have different kinds.</p>
<p>Please refer back to <code class="docutils literal notranslate"><span class="pre">views.py</span></code> to see where we define the variables these templates make use of.</p>
<div class="highlight-html notranslate"><div class="highlight"><pre><span></span><span class="cm">&lt;!-- file mygame/web/chargen/templates/chargen/index.html--&gt;</span>
{% extends &quot;base.html&quot; %}
{% block content %}
{% if user.is_authenticated %}
<span class="p">&lt;</span><span class="nt">h1</span><span class="p">&gt;</span>Character Generation<span class="p">&lt;/</span><span class="nt">h1</span><span class="p">&gt;</span>
{% if sub_apps %}
<span class="p">&lt;</span><span class="nt">ul</span><span class="p">&gt;</span>
{% for sub_app in sub_apps %}
<span class="p">&lt;</span><span class="nt">li</span><span class="p">&gt;&lt;</span><span class="nt">a</span> <span class="na">href</span><span class="o">=</span><span class="s">&quot;/chargen/{{ sub_app.app_id }}/&quot;</span><span class="p">&gt;</span>{{ sub_app.char_name }}<span class="p">&lt;/</span><span class="nt">a</span><span class="p">&gt;&lt;/</span><span class="nt">li</span><span class="p">&gt;</span>
{% endfor %}
<span class="p">&lt;/</span><span class="nt">ul</span><span class="p">&gt;</span>
{% else %}
<span class="p">&lt;</span><span class="nt">p</span><span class="p">&gt;</span>You haven&#39;t submitted any character applications.<span class="p">&lt;/</span><span class="nt">p</span><span class="p">&gt;</span>
{% endif %}
{% else %}
<span class="p">&lt;</span><span class="nt">p</span><span class="p">&gt;</span>Please <span class="p">&lt;</span><span class="nt">a</span> <span class="na">href</span><span class="o">=</span><span class="s">&quot;{% url &#39;login&#39;%}&quot;</span><span class="p">&gt;</span>login<span class="p">&lt;/</span><span class="nt">a</span><span class="p">&gt;</span>first.<span class="p">&lt;</span><span class="nt">a</span><span class="p">/&gt;&lt;/</span><span class="nt">p</span><span class="p">&gt;</span>
{% endif %}
{% endblock %}
</pre></div>
</div>
</section>
<section id="detail-html">
<h3>detail.html<a class="headerlink" href="#detail-html" title="Permalink to this headline"></a></h3>
<p>This page should show a detailed character sheet of their application. This will only show their name and character background. You will likely want to extend this to show many more fields for your game. In a full-fledged character generation, you may want to extend the boolean attribute of submitted to allow accounts to save character applications and submit them later.</p>
<div class="highlight-html notranslate"><div class="highlight"><pre><span></span><span class="cm">&lt;!-- file mygame/web/chargen/templates/chargen/detail.html--&gt;</span>
{% extends &quot;base.html&quot; %}
{% block content %}
<span class="p">&lt;</span><span class="nt">h1</span><span class="p">&gt;</span>Character Information<span class="p">&lt;/</span><span class="nt">h1</span><span class="p">&gt;</span>
{% if user.is_authenticated %}
{% if user.id == p_id %}
<span class="p">&lt;</span><span class="nt">h2</span><span class="p">&gt;</span>{{name}}<span class="p">&lt;/</span><span class="nt">h2</span><span class="p">&gt;</span>
<span class="p">&lt;</span><span class="nt">h2</span><span class="p">&gt;</span>Background<span class="p">&lt;/</span><span class="nt">h2</span><span class="p">&gt;</span>
<span class="p">&lt;</span><span class="nt">p</span><span class="p">&gt;</span>{{background}}<span class="p">&lt;/</span><span class="nt">p</span><span class="p">&gt;</span>
<span class="p">&lt;</span><span class="nt">p</span><span class="p">&gt;</span>Submitted: {{submitted}}<span class="p">&lt;/</span><span class="nt">p</span><span class="p">&gt;</span>
{% else %}
<span class="p">&lt;</span><span class="nt">p</span><span class="p">&gt;</span>You didn&#39;t submit this character.<span class="p">&lt;/</span><span class="nt">p</span><span class="p">&gt;</span>
{% endif %}
{% else %}
<span class="p">&lt;</span><span class="nt">p</span><span class="p">&gt;</span>You aren&#39;t logged in.<span class="p">&lt;/</span><span class="nt">p</span><span class="p">&gt;</span>
{% endif %}
{% endblock %}
</pre></div>
</div>
</section>
<section id="create-html">
<h3>create.html<a class="headerlink" href="#create-html" title="Permalink to this headline"></a></h3>
<p>Our create HTML template will use the Django form we defined back in <a class="reference external" href="http://views.py/forms.py">views.py/forms.py</a> to drive the majority of the application process. There will be a form input for every field we defined in <a class="reference external" href="http://forms.py">forms.py</a>, which is handy. We have used POST as our method because we are sending information to the server that will update the database. As an alternative, GET would be much less secure. You can read up on documentation elsewhere on the web for GET vs. POST.</p>
<div class="highlight-html notranslate"><div class="highlight"><pre><span></span><span class="cm">&lt;!-- file mygame/web/chargen/templates/chargen/create.html--&gt;</span>
{% extends &quot;base.html&quot; %}
{% block content %}
<span class="p">&lt;</span><span class="nt">h1</span><span class="p">&gt;</span>Character Creation<span class="p">&lt;/</span><span class="nt">h1</span><span class="p">&gt;</span>
{% if user.is_authenticated %}
<span class="p">&lt;</span><span class="nt">form</span> <span class="na">action</span><span class="o">=</span><span class="s">&quot;/chargen/create/&quot;</span> <span class="na">method</span><span class="o">=</span><span class="s">&quot;post&quot;</span><span class="p">&gt;</span>
{% csrf_token %}
{{ form }}
<span class="p">&lt;</span><span class="nt">input</span> <span class="na">type</span><span class="o">=</span><span class="s">&quot;submit&quot;</span> <span class="na">name</span><span class="o">=</span><span class="s">&quot;submit&quot;</span> <span class="na">value</span><span class="o">=</span><span class="s">&quot;Submit&quot;</span><span class="p">/&gt;</span>
<span class="p">&lt;/</span><span class="nt">form</span><span class="p">&gt;</span>
{% else %}
<span class="p">&lt;</span><span class="nt">p</span><span class="p">&gt;</span>You aren&#39;t logged in.<span class="p">&lt;/</span><span class="nt">p</span><span class="p">&gt;</span>
{% endif %}
{% endblock %}
</pre></div>
</div>
</section>
<section id="templates-checkpoint">
<h3>Templates - Checkpoint:<a class="headerlink" href="#templates-checkpoint" title="Permalink to this headline"></a></h3>
<ul class="simple">
<li><p>Create a <code class="docutils literal notranslate"><span class="pre">index.html</span></code>, <code class="docutils literal notranslate"><span class="pre">detail.html</span></code> and <code class="docutils literal notranslate"><span class="pre">create.html</span></code> template in your <code class="docutils literal notranslate"><span class="pre">mygame/web/chargen/templates/chargen</span></code> directory</p></li>
</ul>
</section>
</section>
<section id="activating-your-new-character-generation">
<h2>Activating your new character generation<a class="headerlink" href="#activating-your-new-character-generation" title="Permalink to this headline"></a></h2>
<p>After finishing this tutorial you should have edited or created the following files:</p>
<div class="highlight-bash notranslate"><div class="highlight"><pre><span></span>mygame/web/website/urls.py
mygame/web/chargen/models.py
mygame/web/chargen/views.py
mygame/web/chargen/urls.py
mygame/web/chargen/templates/chargen/index.html
mygame/web/chargen/templates/chargen/create.html
mygame/web/chargen/templates/chargen/detail.html
</pre></div>
</div>
<p>Once you have all these files stand in your <code class="docutils literal notranslate"><span class="pre">mygame/</span></code>folder and run:</p>
<div class="highlight-bash notranslate"><div class="highlight"><pre><span></span>evennia<span class="w"> </span>makemigrations
evennia<span class="w"> </span>migrate
</pre></div>
</div>
<p>This will create and update the models. If you see any errors at this stage, read the traceback carefully, it should be relatively easy to figure out where the error is.</p>
<p>Login to the website (you need to have previously registered an Player account with the game to do this). Next you navigate to <code class="docutils literal notranslate"><span class="pre">http://yourwebsite.com/chargen</span></code> (if you are running locally this will be something like <code class="docutils literal notranslate"><span class="pre">http://localhost:4001/chargen</span></code> and you will see your new app in action.</p>
<p>This should hopefully give you a good starting point in figuring out how youd like to approach your own web generation. The main difficulties are in setting the appropriate settings on your newly created character object. Thankfully, the Evennia API makes this easy.</p>
</section>
<section id="adding-a-no-capcha-recapcha-on-your-character-generation">
<h2>Adding a no CAPCHA reCAPCHA on your character generation<a class="headerlink" href="#adding-a-no-capcha-recapcha-on-your-character-generation" title="Permalink to this headline"></a></h2>
<p>As sad as it is, if your server is open to the web, bots might come to visit and take advantage of your open form to create hundreds, thousands, millions of characters if you give them the opportunity. This section shows you how to use the <a class="reference external" href="https://www.google.com/recaptcha/intro/invisible.html">No CAPCHA
reCAPCHA</a> designed by Google. Not only is it easy to use, it is user-friendly… for humans. A simple checkbox to check, except if Google has some suspicion, in which case you will have a more difficult test with an image and the usual text inside. Its worth pointing out that, as long as Google doesnt suspect you of being a robot, this is quite useful, not only for common users, but to screen-reader users, to which reading inside of an image is pretty difficult, if not impossible. And to top it all, it will be so easy to add in your website.</p>
<section id="step-1-obtain-a-sitekey-and-secret-from-google">
<h3>Step 1: Obtain a SiteKey and secret from Google<a class="headerlink" href="#step-1-obtain-a-sitekey-and-secret-from-google" title="Permalink to this headline"></a></h3>
<p>The first thing is to ask Google for a way to safely authenticate your website to their service. To do it, we need to create a site key and a secret. Go to <a class="reference external" href="https://www.google.com/recaptcha/admin">https://www.google.com/recaptcha/admin</a> to create such a site key. Its quite easy when you have a Google account.</p>
<p>When you have created your site key, save it safely. Also copy your secret key as well. You should find both information on the web page. Both would contain a lot of letters and figures.</p>
</section>
<section id="step-2-installing-and-configuring-the-dedicated-django-app">
<h3>Step 2: installing and configuring the dedicated Django app<a class="headerlink" href="#step-2-installing-and-configuring-the-dedicated-django-app" title="Permalink to this headline"></a></h3>
<p>Since Evennia runs on Django, the easiest way to add our CAPCHA and perform the proper check is to install the dedicated Django app. Quite easy:</p>
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>pip install django-nocaptcha-recaptcha
</pre></div>
</div>
<p>And add it to the installed apps in your settings. In your <code class="docutils literal notranslate"><span class="pre">mygame/server/conf/settings.py</span></code>, you might have something like this:</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="c1"># ...</span>
<span class="n">INSTALLED_APPS</span> <span class="o">+=</span> <span class="p">(</span>
<span class="s1">&#39;web.chargen&#39;</span><span class="p">,</span>
<span class="s1">&#39;nocaptcha_recaptcha&#39;</span><span class="p">,</span>
<span class="p">)</span>
</pre></div>
</div>
<p>Dont close the setting file just yet. We have to add in the site key and secret key. You can add them below:</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="c1"># NoReCAPCHA site key</span>
<span class="n">NORECAPTCHA_SITE_KEY</span> <span class="o">=</span> <span class="s2">&quot;PASTE YOUR SITE KEY HERE&quot;</span>
<span class="c1"># NoReCAPCHA secret key</span>
<span class="n">NORECAPTCHA_SECRET_KEY</span> <span class="o">=</span> <span class="s2">&quot;PUT YOUR SECRET KEY HERE&quot;</span>
</pre></div>
</div>
</section>
<section id="step-3-adding-the-capcha-to-our-form">
<h3>Step 3: Adding the CAPCHA to our form<a class="headerlink" href="#step-3-adding-the-capcha-to-our-form" title="Permalink to this headline"></a></h3>
<p>Finally we have to add the CAPCHA to our form. It will be pretty easy too. First, open your <code class="docutils literal notranslate"><span class="pre">web/chargen/forms.py</span></code> file. Were going to add a new field, but hopefully, all the hard work has been done for us. Update at your convenience, You might end up with something like this:</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">django</span> <span class="kn">import</span> <span class="n">forms</span>
<span class="kn">from</span> <span class="nn">nocaptcha_recaptcha.fields</span> <span class="kn">import</span> <span class="n">NoReCaptchaField</span>
<span class="k">class</span> <span class="nc">AppForm</span><span class="p">(</span><span class="n">forms</span><span class="o">.</span><span class="n">Form</span><span class="p">):</span>
<span class="n">name</span> <span class="o">=</span> <span class="n">forms</span><span class="o">.</span><span class="n">CharField</span><span class="p">(</span><span class="n">label</span><span class="o">=</span><span class="s1">&#39;Character Name&#39;</span><span class="p">,</span> <span class="n">max_length</span><span class="o">=</span><span class="mi">80</span><span class="p">)</span>
<span class="n">background</span> <span class="o">=</span> <span class="n">forms</span><span class="o">.</span><span class="n">CharField</span><span class="p">(</span><span class="n">label</span><span class="o">=</span><span class="s1">&#39;Background&#39;</span><span class="p">)</span>
<span class="n">captcha</span> <span class="o">=</span> <span class="n">NoReCaptchaField</span><span class="p">()</span>
</pre></div>
</div>
<p>As you see, we added a line of import (line 2) and a field in our form.</p>
<p>And lastly, we need to update our HTML file to add in the Google library. You can open
<code class="docutils literal notranslate"><span class="pre">web/chargen/templates/chargen/create.html</span></code>. Theres only one line to add:</p>
<div class="highlight-html notranslate"><div class="highlight"><pre><span></span><span class="p">&lt;</span><span class="nt">script</span> <span class="na">src</span><span class="o">=</span><span class="s">&quot;https://www.google.com/recaptcha/api.js&quot;</span> <span class="na">async</span> <span class="na">defer</span><span class="p">&gt;&lt;/</span><span class="nt">script</span><span class="p">&gt;</span>
</pre></div>
</div>
<p>And you should put it at the bottom of the page. Just before the closing body would be good, but for the time being, the base page doesnt provide a footer block, so well put it in the content block. Note that its not the best place, but it will work. In the end, your
<code class="docutils literal notranslate"><span class="pre">web/chargen/templates/chargen/create.html</span></code> file should look like this:</p>
<div class="highlight-html notranslate"><div class="highlight"><pre><span></span>{% extends &quot;base.html&quot; %}
{% block content %}
<span class="p">&lt;</span><span class="nt">h1</span><span class="p">&gt;</span>Character Creation<span class="p">&lt;/</span><span class="nt">h1</span><span class="p">&gt;</span>
{% if user.is_authenticated %}
<span class="p">&lt;</span><span class="nt">form</span> <span class="na">action</span><span class="o">=</span><span class="s">&quot;/chargen/create/&quot;</span> <span class="na">method</span><span class="o">=</span><span class="s">&quot;post&quot;</span><span class="p">&gt;</span>
{% csrf_token %}
{{ form }}
<span class="p">&lt;</span><span class="nt">input</span> <span class="na">type</span><span class="o">=</span><span class="s">&quot;submit&quot;</span> <span class="na">name</span><span class="o">=</span><span class="s">&quot;submit&quot;</span> <span class="na">value</span><span class="o">=</span><span class="s">&quot;Submit&quot;</span><span class="p">/&gt;</span>
<span class="p">&lt;/</span><span class="nt">form</span><span class="p">&gt;</span>
{% else %}
<span class="p">&lt;</span><span class="nt">p</span><span class="p">&gt;</span>You aren&#39;t logged in.<span class="p">&lt;/</span><span class="nt">p</span><span class="p">&gt;</span>
{% endif %}
<span class="p">&lt;</span><span class="nt">script</span> <span class="na">src</span><span class="o">=</span><span class="s">&quot;https://www.google.com/recaptcha/api.js&quot;</span> <span class="na">async</span> <span class="na">defer</span><span class="p">&gt;&lt;/</span><span class="nt">script</span><span class="p">&gt;</span>
{% endblock %}
</pre></div>
</div>
<p>Reload and open <a class="reference external" href="http://localhost:4001/chargen/create/">http://localhost:4001/chargen/create</a> and you should see your beautiful CAPCHA just before the “submit” button. Try not to check the checkbox to see what happens. And do the same while checking the checkbox!</p>
</section>
</section>
</section>
</div>
</div>
</div>
</div>
<div class="related" role="navigation" aria-label="related navigation">
<h3>Navigation</h3>
<ul>
<li class="right" style="margin-right: 10px">
<a href="../genindex.html" title="General Index"
>index</a></li>
<li class="right" >
<a href="../py-modindex.html" title="Python Module Index"
>modules</a> |</li>
<li class="right" >
<a href="Web-Character-View-Tutorial.html" title="Web Character View Tutorial"
>next</a> |</li>
<li class="right" >
<a href="Web-Add-a-wiki.html" title="Add a wiki on your website"
>previous</a> |</li>
<li class="nav-item nav-item-0"><a href="../index.html">Evennia latest</a> &#187;</li>
<li class="nav-item nav-item-1"><a href="Howtos-Overview.html" >Tutorials and How-Tos</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">Web Character Generation</a></li>
</ul>
</div>
<div class="footer" role="contentinfo">
&#169; Copyright 2024, The Evennia developer community.
Created using <a href="https://www.sphinx-doc.org/">Sphinx</a> 3.2.1.
</div>
</body>
</html>