evennia/docs/2.x/Howtos/Web-Help-System-Tutorial.html

550 lines
52 KiB
HTML
Raw Normal View History

2023-06-10 08:55:41 +02:00
<!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/" />
2023-10-19 20:22:27 +00:00
<title>Web Help System Tutorial &#8212; Evennia 2.x documentation</title>
2023-06-10 08:55:41 +02:00
<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="Extending the REST API" href="Web-Extending-the-REST-API.html" />
<link rel="prev" title="Web Character View Tutorial" href="Web-Character-View-Tutorial.html" />
</head><body>
2023-10-19 20:22:27 +00:00
2023-06-10 08:55:41 +02:00
<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-Extending-the-REST-API.html" title="Extending the REST API"
accesskey="N">next</a> |</li>
<li class="right" >
<a href="Web-Character-View-Tutorial.html" title="Web Character View Tutorial"
accesskey="P">previous</a> |</li>
2023-10-19 20:22:27 +00:00
<li class="nav-item nav-item-0"><a href="../index.html">Evennia 2.x</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 Help System Tutorial</a></li>
2023-06-10 08:55:41 +02:00
</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>
2023-10-19 20:22:27 +00:00
<li><a class="reference internal" href="#">Web Help System Tutorial</a><ul>
2023-06-10 08:55:41 +02:00
<li><a class="reference internal" href="#creating-our-app">Creating our app</a></li>
<li><a class="reference internal" href="#our-new-page">Our new page</a><ul>
<li><a class="reference internal" href="#create-a-view">Create a view</a></li>
<li><a class="reference internal" href="#create-a-template">Create a template</a></li>
<li><a class="reference internal" href="#create-a-new-url">Create a new URL</a></li>
<li><a class="reference internal" href="#lets-see-it-work">Lets see it work</a></li>
<li><a class="reference internal" href="#a-brief-reminder">A brief reminder</a></li>
</ul>
</li>
<li><a class="reference internal" href="#handling-logged-in-users">Handling logged-in users</a></li>
<li><a class="reference internal" href="#the-full-system">The full system</a><ul>
<li><a class="reference internal" href="#the-index-template">The index template</a></li>
<li><a class="reference internal" href="#the-detail-template">The detail template</a></li>
<li><a class="reference internal" href="#put-it-all-together">Put it all together</a></li>
</ul>
</li>
<li><a class="reference internal" href="#to-improve-this-feature">To improve this feature</a></li>
</ul>
</li>
</ul>
<h4>Previous topic</h4>
<p class="topless"><a href="Web-Character-View-Tutorial.html"
title="previous chapter">Web Character View Tutorial</a></p>
<h4>Next topic</h4>
<p class="topless"><a href="Web-Extending-the-REST-API.html"
title="next chapter">Extending the REST API</a></p>
<div role="note" aria-label="source link">
<!--h3>This Page</h3-->
<ul class="this-page-menu">
<li><a href="../_sources/Howtos/Web-Help-System-Tutorial.md.txt"
rel="nofollow">Show Page Source</a></li>
</ul>
</div><h3>Links</h3>
<ul>
2023-10-19 20:22:27 +00:00
<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>
2023-06-10 08:55:41 +02:00
<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>
2023-10-19 20:22:27 +00:00
<h3>Doc Versions</h3>
2023-10-19 19:49:53 +00:00
<ul>
2023-10-19 20:22:27 +00:00
<li><a href="Web-Help-System-Tutorial.html">2.x (main branch)</a></li>
2023-10-19 19:49:53 +00:00
<ul>
2023-10-19 20:22:27 +00:00
<li><a href="../1.3.0/index.html">1.3.0 (v1.3.0 branch)</a></li>
<li><a href="../0.9.5/index.html">0.9.5 (v0.9.5 branch)</a></li>
2023-10-19 19:49:53 +00:00
</ul>
2023-06-10 08:55:41 +02:00
</div>
</div>
<div class="bodywrapper">
<div class="body" role="main">
2023-10-19 20:22:27 +00:00
<section class="tex2jax_ignore mathjax_ignore" id="web-help-system-tutorial">
<h1>Web Help System Tutorial<a class="headerlink" href="#web-help-system-tutorial" title="Permalink to this headline"></a></h1>
<p><strong>Before doing this tutorial you will probably want to read the intro in the <a class="reference internal" href="Web-Changing-Webpage.html"><span class="doc std std-doc">Changing the Web page tutorial</span></a>.</strong> Reading the three first parts of the <a class="reference external" href="https://docs.djangoproject.com/en/4.0/intro/tutorial01/">Django tutorial</a> might help as well.</p>
<p>This tutorial will show you how to access the help system through your website. Both help commands and regular help entries will be visible, depending on the logged-in user or an anonymous character.</p>
2023-06-10 08:55:41 +02:00
<p>This tutorial will show you how to:</p>
<ul class="simple">
<li><p>Create a new page to add to your website.</p></li>
<li><p>Take advantage of a basic view and basic templates.</p></li>
<li><p>Access the help system on your website.</p></li>
<li><p>Identify whether the viewer of this page is logged-in and, if so, to what account.</p></li>
</ul>
<section id="creating-our-app">
<h2>Creating our app<a class="headerlink" href="#creating-our-app" title="Permalink to this headline"></a></h2>
2023-10-19 20:22:27 +00:00
<p>The first step is to create our new Django <em>app</em>. An app in Django can contain pages and mechanisms: your website may contain different apps. Actually, the website provided out-of-the-box by Evennia has already three apps: a “webclient” app, to handle the entire webclient, a “website” app to contain your basic pages, and a third app provided by Django to create a simple admin interface. So well create another app in parallel, giving it a clear name to represent our help system.</p>
<p>From your game directory, use the following commands:</p>
2023-11-23 19:40:52 +00:00
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>cd web
2023-10-19 20:22:27 +00:00
evennia startapp help_system
2023-06-10 08:55:41 +02:00
</pre></div>
</div>
2023-11-23 19:40:52 +00:00
<p>This creates a new folder <code class="docutils literal notranslate"><span class="pre">help_system</span></code> in your <code class="docutils literal notranslate"><span class="pre">mygame/</span></code> folder. To keep things
tidy, lets move it to the <code class="docutils literal notranslate"><span class="pre">web/</span></code> folder:</p>
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>mv help_system web (linux)
move help_system web (windows)
</pre></div>
</div>
2023-06-10 08:55:41 +02:00
<blockquote>
2023-10-19 20:22:27 +00:00
<div><p>Note: calling the app “help” would have been more explicit, but this name is already used by Django.</p>
2023-06-10 08:55:41 +02:00
</div></blockquote>
2023-11-23 19:40:52 +00:00
<p>We put the new app under <code class="docutils literal notranslate"><span class="pre">web/</span></code>t o keep all web-related things together, but you can organize however you like. Heres how the structure looks:</p>
2023-06-10 08:55:41 +02:00
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>mygame/
...
web/
help_system/
...
</pre></div>
</div>
2023-10-19 20:22:27 +00:00
<p>The “web/help_system” directory contains files created by Django. Well use some of them, but if you want to learn more about them all, you should read <a class="reference external" href="https://docs.djangoproject.com/en/4.1/intro/tutorial01/">the Django tutorial</a>.</p>
<p>There is a last thing to be done: your folder has been added, but Django doesnt know about it, it doesnt know its a new app. We need to tell it, and we do so by editing a simple setting. Open your “server/conf/settings.py” file and add, or edit, these lines:</p>
2023-06-10 08:55:41 +02:00
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="c1"># Web configuration</span>
<span class="n">INSTALLED_APPS</span> <span class="o">+=</span> <span class="p">(</span>
<span class="s2">&quot;web.help_system&quot;</span><span class="p">,</span>
<span class="p">)</span>
</pre></div>
</div>
2023-10-19 20:22:27 +00:00
<p>You can start Evennia if you want, and go to your website, probably at <a class="reference external" href="http://localhost:4001">http://localhost:4001</a> . You wont see anything different though: we added the app but its fairly empty.</p>
2023-06-10 08:55:41 +02:00
</section>
<section id="our-new-page">
<h2>Our new page<a class="headerlink" href="#our-new-page" title="Permalink to this headline"></a></h2>
2023-10-19 20:22:27 +00:00
<p>At this point, our new <em>app</em> contains mostly empty files that you can explore. In order to create a page for our help system, we need to add:</p>
2023-06-10 08:55:41 +02:00
<ul class="simple">
<li><p>A <em>view</em>, dealing with the logic of our page.</p></li>
<li><p>A <em>template</em> to display our new page.</p></li>
<li><p>A new <em>URL</em> pointing to our page.</p></li>
</ul>
<blockquote>
2023-10-19 20:22:27 +00:00
<div><p>We could get away by creating just a view and a new URL, but thats not a recommended way to work with your website. Building on templates is so much more convenient.</p>
2023-06-10 08:55:41 +02:00
</div></blockquote>
<section id="create-a-view">
<h3>Create a view<a class="headerlink" href="#create-a-view" title="Permalink to this headline"></a></h3>
<p>A <em>view</em> in Django is a simple Python function placed in the “<a class="reference external" href="http://views.py">views.py</a>” file in your app. It will
2023-10-19 20:22:27 +00:00
handle the behavior that is triggered when a user asks for this information by entering a <em>URL</em> (the connection between <em>views</em> and <em>URLs</em> will be discussed later).</p>
<p>So lets create our view. You can open the “web/help_system/views.py” file and paste the following lines:</p>
2023-06-10 08:55:41 +02:00
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">django.shortcuts</span> <span class="kn">import</span> <span class="n">render</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="w"> </span><span class="sd">&quot;&quot;&quot;The &#39;index&#39; view.&quot;&quot;&quot;</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="s2">&quot;help_system/index.html&quot;</span><span class="p">)</span>
</pre></div>
</div>
2023-10-19 20:22:27 +00:00
<p>Our view handles all code logic. This time, theres not much: when this function is called, it will render the template we will now create. But thats where we will do most of our work afterward.</p>
2023-06-10 08:55:41 +02:00
</section>
<section id="create-a-template">
<h3>Create a template<a class="headerlink" href="#create-a-template" title="Permalink to this headline"></a></h3>
2023-10-19 20:22:27 +00:00
<p>The <code class="docutils literal notranslate"><span class="pre">render</span></code> function called into our <em>view</em> asks the <em>template</em> <code class="docutils literal notranslate"><span class="pre">help_system/index.html</span></code>. The <em>templates</em> of our apps are stored in the app directory, “templates” sub-directory. Django may have created the “templates” folder already. If not, create it yourself. In it, create another folder “help_system”, and inside of this folder, create a file named “index.html”. Wow, thats some hierarchy. Your directory structure (starting from <code class="docutils literal notranslate"><span class="pre">web</span></code>) should look like this:</p>
2023-06-10 08:55:41 +02:00
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>web/
help_system/
...
templates/
help_system/
index.html
</pre></div>
</div>
<p>Open the “index.html” file and paste in the following lines:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="p">{</span><span class="o">%</span> <span class="n">extends</span> <span class="s2">&quot;base.html&quot;</span> <span class="o">%</span><span class="p">}</span>
<span class="p">{</span><span class="o">%</span> <span class="n">block</span> <span class="n">titleblock</span> <span class="o">%</span><span class="p">}</span><span class="n">Help</span> <span class="n">index</span><span class="p">{</span><span class="o">%</span> <span class="n">endblock</span> <span class="o">%</span><span class="p">}</span>
<span class="p">{</span><span class="o">%</span> <span class="n">block</span> <span class="n">content</span> <span class="o">%</span><span class="p">}</span>
<span class="o">&lt;</span><span class="n">h2</span><span class="o">&gt;</span><span class="n">Help</span> <span class="n">index</span><span class="o">&lt;/</span><span class="n">h2</span><span class="o">&gt;</span>
<span class="p">{</span><span class="o">%</span> <span class="n">endblock</span> <span class="o">%</span><span class="p">}</span>
</pre></div>
</div>
<p>Heres a little explanation line by line of what this template does:</p>
<ol class="simple">
2023-10-19 20:22:27 +00:00
<li><p>It loads the “base.html” <em>template</em>. This describes the basic structure of all your pages, with a menu at the top and a footer, and perhaps other information like images and things to be present on each page. You can create templates that do not inherit from “base.html”, but you should have a good reason for doing so.</p></li>
<li><p>The “base.html” <em>template</em> defines all the structure of the page. What is left is to override some sections of our pages. These sections are called <em>blocks</em>. On line 2, we override the block named “blocktitle”, which contains the title of our page.</p></li>
<li><p>Same thing here, we override the <em>block</em> named “content”, which contains the main content of our web page. This block is bigger, so we define it on several lines.</p></li>
2023-06-10 08:55:41 +02:00
<li><p>This is perfectly normal HTML code to display a level-2 heading.</p></li>
<li><p>And finally we close the <em>block</em> named “content”.</p></li>
</ol>
</section>
<section id="create-a-new-url">
<h3>Create a new URL<a class="headerlink" href="#create-a-new-url" title="Permalink to this headline"></a></h3>
2023-10-19 20:22:27 +00:00
<p>Last step to add our page: we need to add a <em>URL</em> leading to it… otherwise users wont be able to access it. The URLs of our apps are stored in the apps directory “<a class="reference external" href="http://urls.py">urls.py</a>” file.</p>
<p>Open the <code class="docutils literal notranslate"><span class="pre">web/help_system/urls.py</span></code> file (you might have to create it) and make it look like this:</p>
2023-06-10 08:55:41 +02:00
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="c1"># URL patterns for the help_system app</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">.views</span> <span class="kn">import</span> <span class="n">index</span>
<span class="n">urlpatterns</span> <span class="o">=</span> <span class="p">[</span>
<span class="n">path</span><span class="p">(</span><span class="s1">&#39;&#39;</span><span class="p">,</span> <span class="n">index</span><span class="p">)</span>
<span class="p">]</span>
</pre></div>
</div>
2023-10-19 20:22:27 +00:00
<p>The <code class="docutils literal notranslate"><span class="pre">urlpatterns</span></code> variable is what Django/Evennia looks for to figure out how to direct a user entering an URL in their browser to the view-code you have written.</p>
<p>Last we need to tie this into the main namespace for your game. Edit the file <code class="docutils literal notranslate"><span class="pre">mygame/web/urls.py</span></code>. In it you will find the <code class="docutils literal notranslate"><span class="pre">urlpatterns</span></code> list again. Add a new <code class="docutils literal notranslate"><span class="pre">path</span></code> to the end of the list.</p>
2023-06-10 08:55:41 +02:00
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="c1"># mygame/web/urls.py</span>
<span class="c1"># [...]</span>
<span class="c1"># add patterns</span>
<span class="n">urlpatterns</span> <span class="o">=</span> <span class="p">[</span>
<span class="c1"># website</span>
<span class="n">path</span><span class="p">(</span><span class="s2">&quot;&quot;</span><span class="p">,</span> <span class="n">include</span><span class="p">(</span><span class="s2">&quot;web.website.urls&quot;</span><span class="p">)),</span>
<span class="c1"># webclient</span>
<span class="n">path</span><span class="p">(</span><span class="s2">&quot;webclient/&quot;</span><span class="p">,</span> <span class="n">include</span><span class="p">(</span><span class="s2">&quot;web.webclient.urls&quot;</span><span class="p">)),</span>
<span class="c1"># web admin</span>
<span class="n">path</span><span class="p">(</span><span class="s2">&quot;admin/&quot;</span><span class="p">,</span> <span class="n">include</span><span class="p">(</span><span class="s2">&quot;web.admin.urls&quot;</span><span class="p">)),</span>
<span class="c1"># my help system</span>
<span class="n">path</span><span class="p">(</span><span class="s1">&#39;help/&#39;</span><span class="p">,</span> <span class="n">include</span><span class="p">(</span><span class="s1">&#39;web.help_system.urls&#39;</span><span class="p">))</span> <span class="c1"># &lt;--- NEW</span>
<span class="p">]</span>
<span class="c1"># [...]</span>
</pre></div>
</div>
<p>When a user will ask for a specific <em>URL</em> on your site, Django will:</p>
<ol class="simple">
2023-10-19 20:22:27 +00:00
<li><p>Read the list of custom patterns defined in “web/urls.py”. Theres one pattern here, which describes to Django that all URLs beginning by help/ should be sent to the help_system app. The help/ part is removed.</p></li>
<li><p>Then Django will check the “web.help_system/urls.py” file. It contains only one URL, which is empty (<code class="docutils literal notranslate"><span class="pre">^$</span></code>).</p></li>
2023-06-10 08:55:41 +02:00
</ol>
<p>In other words, if the URL is /help/, then Django will execute our defined view.</p>
</section>
<section id="lets-see-it-work">
<h3>Lets see it work<a class="headerlink" href="#lets-see-it-work" title="Permalink to this headline"></a></h3>
2023-10-19 20:22:27 +00:00
<p>You can now reload or start Evennia. Open a tab in your browser and go to <a class="reference external" href="http://localhost:4001/help/">http://localhost:4001/help/</a> . If everything goes well, you should see your new page… which isnt empty since Evennia uses our “base.html” <em>template</em>. In the content of our page, theres only a heading that reads “help index”. Notice that the title of our page is “mygame - Help index” (“mygame” is replaced by the name of your game).</p>
2023-06-10 08:55:41 +02:00
<p>From now on, it will be easier to move forward and add features.</p>
</section>
<section id="a-brief-reminder">
<h3>A brief reminder<a class="headerlink" href="#a-brief-reminder" title="Permalink to this headline"></a></h3>
<p>Well be trying the following things:</p>
<ul class="simple">
<li><p>Have the help of commands and help entries accessed online.</p></li>
<li><p>Have various commands and help entries depending on whether the user is logged in or not.</p></li>
</ul>
<p>In terms of pages, well have:</p>
<ul class="simple">
<li><p>One to display the list of help topics.</p></li>
<li><p>One to display the content of a help topic.</p></li>
</ul>
<p>The first one would link to the second.</p>
<blockquote>
<div><p>Should we create two URLs?</p>
</div></blockquote>
2023-10-19 20:22:27 +00:00
<p>The answer is… maybe. It depends on what you want to do. We have our help index accessible through the “/help/” URL. We could have the detail of a help entry accessible through “/help/desc” (to see the detail of the “desc” command). The problem is that our commands or help topics may contain special characters that arent to be present in URLs. There are different ways around this problem. I have decided to use a <em>GET variable</em> here, which would create URLs like this:</p>
2023-06-10 08:55:41 +02:00
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>/help?name=desc
</pre></div>
</div>
2023-10-19 20:22:27 +00:00
<p>If you use this system, you dont have to add a new URL: GET and POST variables are accessible through our requests and well see how soon enough.</p>
2023-06-10 08:55:41 +02:00
</section>
</section>
<section id="handling-logged-in-users">
<h2>Handling logged-in users<a class="headerlink" href="#handling-logged-in-users" title="Permalink to this headline"></a></h2>
2023-10-19 20:22:27 +00:00
<p>One of our requirements is to have a help system tailored to our accounts. If an account with admin access logs in, the page should display a lot of commands that arent accessible to common users. And perhaps even some additional help topics.</p>
<p>Fortunately, its fairly easy to get the logged in account in our view (remember that well do most of our coding there). The <em>request</em> object, passed to our function, contains a <code class="docutils literal notranslate"><span class="pre">user</span></code> attribute. This attribute will always be there: we cannot test whether its <code class="docutils literal notranslate"><span class="pre">None</span></code> or not, for instance. But when the request comes from a user that isnt logged in, the <code class="docutils literal notranslate"><span class="pre">user</span></code> attribute will contain an anonymous Django user. We then can use the <code class="docutils literal notranslate"><span class="pre">is_anonymous</span></code> method to see whether the user is logged-in or not. Last gift by Evennia, if the user is logged in, <code class="docutils literal notranslate"><span class="pre">request.user</span></code> contains a reference to an account object, which will help us a lot in coupling the game and online system.</p>
2023-06-10 08:55:41 +02:00
<p>So we might end up with something like:</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></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="w"> </span><span class="sd">&quot;&quot;&quot;The &#39;index&#39; view.&quot;&quot;&quot;</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="ow">not</span> <span class="n">user</span><span class="o">.</span><span class="n">is_anonymous</span><span class="p">()</span> <span class="ow">and</span> <span class="n">user</span><span class="o">.</span><span class="n">character</span><span class="p">:</span>
<span class="n">character</span> <span class="o">=</span> <span class="n">user</span><span class="o">.</span><span class="n">character</span>
</pre></div>
</div>
<blockquote>
2023-10-19 20:22:27 +00:00
<div><p>Note: this code works when your MULTISESSION_MODE is set to 0 or 1. When its above, you would have something like:</p>
2023-06-10 08:55:41 +02:00
</div></blockquote>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></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="w"> </span><span class="sd">&quot;&quot;&quot;The &#39;index&#39; view.&quot;&quot;&quot;</span>
<span class="n">user</span> <span class="o">=</span> <span class="n">request</span><span class="o">.</span><span class="n">user</span>
2023-10-31 19:28:12 +00:00
<span class="k">if</span> <span class="ow">not</span> <span class="n">user</span><span class="o">.</span><span class="n">is_anonymous</span><span class="p">()</span> <span class="ow">and</span> <span class="n">user</span><span class="o">.</span><span class="n">characters</span><span class="p">:</span>
<span class="n">character</span> <span class="o">=</span> <span class="n">user</span><span class="o">.</span><span class="n">characters</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span>
2023-06-10 08:55:41 +02:00
</pre></div>
</div>
<p>In this second case, it will select the first character of the account.</p>
2023-10-19 20:22:27 +00:00
<p>But what if the users not logged in? Again, we have different solutions. One of the most simple is to create a character that will behave as our default character for the help system. You can create it through your game: connect to it and enter:</p>
2023-06-10 08:55:41 +02:00
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>@charcreate anonymous
</pre></div>
</div>
<p>The system should answer:</p>
2023-10-19 20:22:27 +00:00
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span> Created new character anonymous. Use @ic anonymous to enter the game as this character.
2023-06-10 08:55:41 +02:00
</pre></div>
</div>
<p>So in our view, we could have something like this:</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">typeclasses.characters</span> <span class="kn">import</span> <span class="n">Character</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="w"> </span><span class="sd">&quot;&quot;&quot;The &#39;index&#39; view.&quot;&quot;&quot;</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="ow">not</span> <span class="n">user</span><span class="o">.</span><span class="n">is_anonymous</span><span class="p">()</span> <span class="ow">and</span> <span class="n">user</span><span class="o">.</span><span class="n">character</span><span class="p">:</span>
<span class="n">character</span> <span class="o">=</span> <span class="n">user</span><span class="o">.</span><span class="n">character</span>
<span class="k">else</span><span class="p">:</span>
<span class="n">character</span> <span class="o">=</span> <span class="n">Character</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">db_key</span><span class="o">=</span><span class="s2">&quot;anonymous&quot;</span><span class="p">)</span>
</pre></div>
</div>
2023-10-19 20:22:27 +00:00
<p>This time, we have a valid character no matter what: remember to adapt this code if youre running in multisession mode above 1.</p>
2023-06-10 08:55:41 +02:00
</section>
<section id="the-full-system">
<h2>The full system<a class="headerlink" href="#the-full-system" title="Permalink to this headline"></a></h2>
2023-10-19 20:22:27 +00:00
<p>What were going to do is to browse through all commands and help entries, and list all the commands that can be seen by this character (either our anonymous character, or our logged-in character).</p>
<p>The code is longer, but it presents the entire concept in our view. Edit the “web/help_system/views.py” file and paste into it:</p>
2023-06-10 08:55:41 +02:00
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">django.http</span> <span class="kn">import</span> <span class="n">Http404</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">evennia.help.models</span> <span class="kn">import</span> <span class="n">HelpEntry</span>
<span class="kn">from</span> <span class="nn">typeclasses.characters</span> <span class="kn">import</span> <span class="n">Character</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="w"> </span><span class="sd">&quot;&quot;&quot;The &#39;index&#39; view.&quot;&quot;&quot;</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="ow">not</span> <span class="n">user</span><span class="o">.</span><span class="n">is_anonymous</span><span class="p">()</span> <span class="ow">and</span> <span class="n">user</span><span class="o">.</span><span class="n">character</span><span class="p">:</span>
<span class="n">character</span> <span class="o">=</span> <span class="n">user</span><span class="o">.</span><span class="n">character</span>
<span class="k">else</span><span class="p">:</span>
<span class="n">character</span> <span class="o">=</span> <span class="n">Character</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">db_key</span><span class="o">=</span><span class="s2">&quot;anonymous&quot;</span><span class="p">)</span>
<span class="c1"># Get the categories and topics accessible to this character</span>
<span class="n">categories</span><span class="p">,</span> <span class="n">topics</span> <span class="o">=</span> <span class="n">_get_topics</span><span class="p">(</span><span class="n">character</span><span class="p">)</span>
<span class="c1"># If we have the &#39;name&#39; in our GET variable</span>
<span class="n">topic</span> <span class="o">=</span> <span class="n">request</span><span class="o">.</span><span class="n">GET</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&quot;name&quot;</span><span class="p">)</span>
<span class="k">if</span> <span class="n">topic</span><span class="p">:</span>
<span class="k">if</span> <span class="n">topic</span> <span class="ow">not</span> <span class="ow">in</span> <span class="n">topics</span><span class="p">:</span>
<span class="k">raise</span> <span class="n">Http404</span><span class="p">(</span><span class="s2">&quot;This help topic doesn&#39;t exist.&quot;</span><span class="p">)</span>
<span class="n">topic</span> <span class="o">=</span> <span class="n">topics</span><span class="p">[</span><span class="n">topic</span><span class="p">]</span>
<span class="n">context</span> <span class="o">=</span> <span class="p">{</span>
<span class="s2">&quot;character&quot;</span><span class="p">:</span> <span class="n">character</span><span class="p">,</span>
<span class="s2">&quot;topic&quot;</span><span class="p">:</span> <span class="n">topic</span><span class="p">,</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="s2">&quot;help_system/detail.html&quot;</span><span class="p">,</span> <span class="n">context</span><span class="p">)</span>
<span class="k">else</span><span class="p">:</span>
<span class="n">context</span> <span class="o">=</span> <span class="p">{</span>
<span class="s2">&quot;character&quot;</span><span class="p">:</span> <span class="n">character</span><span class="p">,</span>
<span class="s2">&quot;categories&quot;</span><span class="p">:</span> <span class="n">categories</span><span class="p">,</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="s2">&quot;help_system/index.html&quot;</span><span class="p">,</span> <span class="n">context</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">_get_topics</span><span class="p">(</span><span class="n">character</span><span class="p">):</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;Return the categories and topics for this character.&quot;&quot;&quot;</span>
<span class="n">cmdset</span> <span class="o">=</span> <span class="n">character</span><span class="o">.</span><span class="n">cmdset</span><span class="o">.</span><span class="n">all</span><span class="p">()[</span><span class="mi">0</span><span class="p">]</span>
<span class="n">commands</span> <span class="o">=</span> <span class="n">cmdset</span><span class="o">.</span><span class="n">commands</span>
<span class="n">entries</span> <span class="o">=</span> <span class="p">[</span><span class="n">entry</span> <span class="k">for</span> <span class="n">entry</span> <span class="ow">in</span> <span class="n">HelpEntry</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">all</span><span class="p">()]</span>
<span class="n">categories</span> <span class="o">=</span> <span class="p">{}</span>
<span class="n">topics</span> <span class="o">=</span> <span class="p">{}</span>
<span class="c1"># Browse commands</span>
<span class="k">for</span> <span class="n">command</span> <span class="ow">in</span> <span class="n">commands</span><span class="p">:</span>
<span class="k">if</span> <span class="ow">not</span> <span class="n">command</span><span class="o">.</span><span class="n">auto_help</span> <span class="ow">or</span> <span class="ow">not</span> <span class="n">command</span><span class="o">.</span><span class="n">access</span><span class="p">(</span><span class="n">character</span><span class="p">):</span>
<span class="k">continue</span>
<span class="c1"># Create the template for a command</span>
<span class="n">template</span> <span class="o">=</span> <span class="p">{</span>
<span class="s2">&quot;name&quot;</span><span class="p">:</span> <span class="n">command</span><span class="o">.</span><span class="n">key</span><span class="p">,</span>
<span class="s2">&quot;category&quot;</span><span class="p">:</span> <span class="n">command</span><span class="o">.</span><span class="n">help_category</span><span class="p">,</span>
<span class="s2">&quot;content&quot;</span><span class="p">:</span> <span class="n">command</span><span class="o">.</span><span class="n">get_help</span><span class="p">(</span><span class="n">character</span><span class="p">,</span> <span class="n">cmdset</span><span class="p">),</span>
<span class="p">}</span>
<span class="n">category</span> <span class="o">=</span> <span class="n">command</span><span class="o">.</span><span class="n">help_category</span>
<span class="k">if</span> <span class="n">category</span> <span class="ow">not</span> <span class="ow">in</span> <span class="n">categories</span><span class="p">:</span>
<span class="n">categories</span><span class="p">[</span><span class="n">category</span><span class="p">]</span> <span class="o">=</span> <span class="p">[]</span>
<span class="n">categories</span><span class="p">[</span><span class="n">category</span><span class="p">]</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">template</span><span class="p">)</span>
<span class="n">topics</span><span class="p">[</span><span class="n">command</span><span class="o">.</span><span class="n">key</span><span class="p">]</span> <span class="o">=</span> <span class="n">template</span>
<span class="c1"># Browse through the help entries</span>
<span class="k">for</span> <span class="n">entry</span> <span class="ow">in</span> <span class="n">entries</span><span class="p">:</span>
<span class="k">if</span> <span class="ow">not</span> <span class="n">entry</span><span class="o">.</span><span class="n">access</span><span class="p">(</span><span class="n">character</span><span class="p">,</span> <span class="s1">&#39;view&#39;</span><span class="p">,</span> <span class="n">default</span><span class="o">=</span><span class="kc">True</span><span class="p">):</span>
<span class="k">continue</span>
<span class="c1"># Create the template for an entry</span>
<span class="n">template</span> <span class="o">=</span> <span class="p">{</span>
<span class="s2">&quot;name&quot;</span><span class="p">:</span> <span class="n">entry</span><span class="o">.</span><span class="n">key</span><span class="p">,</span>
<span class="s2">&quot;category&quot;</span><span class="p">:</span> <span class="n">entry</span><span class="o">.</span><span class="n">help_category</span><span class="p">,</span>
<span class="s2">&quot;content&quot;</span><span class="p">:</span> <span class="n">entry</span><span class="o">.</span><span class="n">entrytext</span><span class="p">,</span>
<span class="p">}</span>
<span class="n">category</span> <span class="o">=</span> <span class="n">entry</span><span class="o">.</span><span class="n">help_category</span>
<span class="k">if</span> <span class="n">category</span> <span class="ow">not</span> <span class="ow">in</span> <span class="n">categories</span><span class="p">:</span>
<span class="n">categories</span><span class="p">[</span><span class="n">category</span><span class="p">]</span> <span class="o">=</span> <span class="p">[]</span>
<span class="n">categories</span><span class="p">[</span><span class="n">category</span><span class="p">]</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">template</span><span class="p">)</span>
<span class="n">topics</span><span class="p">[</span><span class="n">entry</span><span class="o">.</span><span class="n">key</span><span class="p">]</span> <span class="o">=</span> <span class="n">template</span>
<span class="c1"># Sort categories</span>
<span class="k">for</span> <span class="n">entries</span> <span class="ow">in</span> <span class="n">categories</span><span class="o">.</span><span class="n">values</span><span class="p">():</span>
<span class="n">entries</span><span class="o">.</span><span class="n">sort</span><span class="p">(</span><span class="n">key</span><span class="o">=</span><span class="k">lambda</span> <span class="n">c</span><span class="p">:</span> <span class="n">c</span><span class="p">[</span><span class="s2">&quot;name&quot;</span><span class="p">])</span>
<span class="n">categories</span> <span class="o">=</span> <span class="nb">list</span><span class="p">(</span><span class="nb">sorted</span><span class="p">(</span><span class="n">categories</span><span class="o">.</span><span class="n">items</span><span class="p">()))</span>
<span class="k">return</span> <span class="n">categories</span><span class="p">,</span> <span class="n">topics</span>
</pre></div>
</div>
<p>Thats a bit more complicated here, but all in all, it can be divided in small chunks:</p>
<ul class="simple">
<li><p>The <code class="docutils literal notranslate"><span class="pre">index</span></code> function is our view:</p>
<ul>
<li><p>It begins by getting the character as we saw in the previous section.</p></li>
2023-10-19 20:22:27 +00:00
<li><p>It gets the help topics (commands and help entries) accessible to this character. Its another function that handles that part.</p></li>
<li><p>If theres a <em>GET variable</em> “name” in our URL (like “/help?name=drop”), it will retrieve it. If its not a valid topics name, it returns a <em>404</em>. Otherwise, it renders the template called “detail.html”, to display the detail of our topic.</p></li>
2023-06-10 08:55:41 +02:00
<li><p>If theres no <em>GET variable</em> “name”, render “index.html”, to display the list of topics.</p></li>
</ul>
</li>
2023-10-19 20:22:27 +00:00
<li><p>The <code class="docutils literal notranslate"><span class="pre">_get_topics</span></code> is a private function. Its sole mission is to retrieve the commands a character can execute, and the help entries this same character can see. This code is more Evennia-specific than Django-specific, it will not be detailed in this tutorial. Just notice that all help topics are stored in a dictionary. This is to simplify our job when displaying them in our templates.</p></li>
2023-06-10 08:55:41 +02:00
</ul>
2023-10-19 20:22:27 +00:00
<p>Notice that, in both cases when we asked to render a <em>template</em>, we passed to <code class="docutils literal notranslate"><span class="pre">render</span></code> a third argument which is the dictionary of variables used in our templates. We can pass variables this way, and we will use them in our templates.</p>
2023-06-10 08:55:41 +02:00
<section id="the-index-template">
<h3>The index template<a class="headerlink" href="#the-index-template" title="Permalink to this headline"></a></h3>
2023-10-19 20:22:27 +00:00
<p>Lets look at our full “index” <em>template</em>. You can open the “web/help_system/templates/help_sstem/index.html” file and paste the following into it:</p>
2023-06-10 08:55:41 +02:00
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="p">{</span><span class="o">%</span> <span class="n">extends</span> <span class="s2">&quot;base.html&quot;</span> <span class="o">%</span><span class="p">}</span>
<span class="p">{</span><span class="o">%</span> <span class="n">block</span> <span class="n">titleblock</span> <span class="o">%</span><span class="p">}</span><span class="n">Help</span> <span class="n">index</span><span class="p">{</span><span class="o">%</span> <span class="n">endblock</span> <span class="o">%</span><span class="p">}</span>
<span class="p">{</span><span class="o">%</span> <span class="n">block</span> <span class="n">content</span> <span class="o">%</span><span class="p">}</span>
<span class="o">&lt;</span><span class="n">h2</span><span class="o">&gt;</span><span class="n">Help</span> <span class="n">index</span><span class="o">&lt;/</span><span class="n">h2</span><span class="o">&gt;</span>
<span class="p">{</span><span class="o">%</span> <span class="k">if</span> <span class="n">categories</span> <span class="o">%</span><span class="p">}</span>
<span class="p">{</span><span class="o">%</span> <span class="k">for</span> <span class="n">category</span><span class="p">,</span> <span class="n">topics</span> <span class="ow">in</span> <span class="n">categories</span> <span class="o">%</span><span class="p">}</span>
<span class="o">&lt;</span><span class="n">h2</span><span class="o">&gt;</span><span class="p">{{</span> <span class="n">category</span><span class="o">|</span><span class="n">capfirst</span> <span class="p">}}</span><span class="o">&lt;/</span><span class="n">h2</span><span class="o">&gt;</span>
<span class="o">&lt;</span><span class="n">table</span><span class="o">&gt;</span>
<span class="o">&lt;</span><span class="n">tr</span><span class="o">&gt;</span>
<span class="p">{</span><span class="o">%</span> <span class="k">for</span> <span class="n">topic</span> <span class="ow">in</span> <span class="n">topics</span> <span class="o">%</span><span class="p">}</span>
<span class="p">{</span><span class="o">%</span> <span class="k">if</span> <span class="n">forloop</span><span class="o">.</span><span class="n">counter</span><span class="o">|</span><span class="n">divisibleby</span><span class="p">:</span><span class="s2">&quot;5&quot;</span> <span class="o">%</span><span class="p">}</span>
<span class="o">&lt;/</span><span class="n">tr</span><span class="o">&gt;</span>
<span class="o">&lt;</span><span class="n">tr</span><span class="o">&gt;</span>
<span class="p">{</span><span class="o">%</span> <span class="n">endif</span> <span class="o">%</span><span class="p">}</span>
<span class="o">&lt;</span><span class="n">td</span><span class="o">&gt;&lt;</span><span class="n">a</span> <span class="n">href</span><span class="o">=</span><span class="s2">&quot;{</span><span class="si">% u</span><span class="s2">rl &#39;help_system:index&#39; %}?name={{ topic.name|urlencode }}&quot;</span><span class="o">&gt;</span>
<span class="p">{{</span> <span class="n">topic</span><span class="o">.</span><span class="n">name</span> <span class="p">}}</span><span class="o">&lt;/</span><span class="n">td</span><span class="o">&gt;</span>
<span class="p">{</span><span class="o">%</span> <span class="n">endfor</span> <span class="o">%</span><span class="p">}</span>
<span class="o">&lt;/</span><span class="n">tr</span><span class="o">&gt;</span>
<span class="o">&lt;/</span><span class="n">table</span><span class="o">&gt;</span>
<span class="p">{</span><span class="o">%</span> <span class="n">endfor</span> <span class="o">%</span><span class="p">}</span>
<span class="p">{</span><span class="o">%</span> <span class="n">endif</span> <span class="o">%</span><span class="p">}</span>
<span class="p">{</span><span class="o">%</span> <span class="n">endblock</span> <span class="o">%</span><span class="p">}</span>
</pre></div>
</div>
<p>This template is definitely more detailed. What it does is:</p>
<ol class="simple">
<li><p>Browse through all categories.</p></li>
<li><p>For all categories, display a level-2 heading with the name of the category.</p></li>
2023-10-19 20:22:27 +00:00
<li><p>All topics in a category (remember, they can be either commands or help entries) are displayed in a table. The trickier part may be that, when the loop is above 5, it will create a new line. The table will have 5 columns at the most per row.</p></li>
<li><p>For every cell in the table, we create a link redirecting to the detail page (see below). The URL would look something like “help?name=say”. We use <code class="docutils literal notranslate"><span class="pre">urlencode</span></code> to ensure special characters are properly escaped.</p></li>
2023-06-10 08:55:41 +02:00
</ol>
</section>
<section id="the-detail-template">
<h3>The detail template<a class="headerlink" href="#the-detail-template" title="Permalink to this headline"></a></h3>
2023-10-19 20:22:27 +00:00
<p>Its now time to show the detail of a topic (command or help entry). You can create the file “web/help_system/templates/help_system/detail.html”. You can paste into it the following code:</p>
2023-06-10 08:55:41 +02:00
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="p">{</span><span class="o">%</span> <span class="n">extends</span> <span class="s2">&quot;base.html&quot;</span> <span class="o">%</span><span class="p">}</span>
<span class="p">{</span><span class="o">%</span> <span class="n">block</span> <span class="n">titleblock</span> <span class="o">%</span><span class="p">}</span><span class="n">Help</span> <span class="k">for</span> <span class="p">{{</span> <span class="n">topic</span><span class="o">.</span><span class="n">name</span> <span class="p">}}{</span><span class="o">%</span> <span class="n">endblock</span> <span class="o">%</span><span class="p">}</span>
<span class="p">{</span><span class="o">%</span> <span class="n">block</span> <span class="n">content</span> <span class="o">%</span><span class="p">}</span>
<span class="o">&lt;</span><span class="n">h2</span><span class="o">&gt;</span><span class="p">{{</span> <span class="n">topic</span><span class="o">.</span><span class="n">name</span><span class="o">|</span><span class="n">capfirst</span> <span class="p">}}</span> <span class="n">help</span> <span class="n">topic</span><span class="o">&lt;/</span><span class="n">h2</span><span class="o">&gt;</span>
<span class="o">&lt;</span><span class="n">p</span><span class="o">&gt;</span><span class="n">Category</span><span class="p">:</span> <span class="p">{{</span> <span class="n">topic</span><span class="o">.</span><span class="n">category</span><span class="o">|</span><span class="n">capfirst</span> <span class="p">}}</span><span class="o">&lt;/</span><span class="n">p</span><span class="o">&gt;</span>
<span class="p">{{</span> <span class="n">topic</span><span class="o">.</span><span class="n">content</span><span class="o">|</span><span class="n">linebreaks</span> <span class="p">}}</span>
<span class="p">{</span><span class="o">%</span> <span class="n">endblock</span> <span class="o">%</span><span class="p">}</span>
</pre></div>
</div>
2023-10-19 20:22:27 +00:00
<p>This template is much easier to read. Some <em>filters</em> might be unknown to you, but they are just used to format here.</p>
2023-06-10 08:55:41 +02:00
</section>
<section id="put-it-all-together">
<h3>Put it all together<a class="headerlink" href="#put-it-all-together" title="Permalink to this headline"></a></h3>
2023-10-19 20:22:27 +00:00
<p>Remember to reload or start Evennia, and then go to <a class="reference external" href="http://localhost:4001/help/">http://localhost:4001/help</a>. You should see the list of commands and topics accessible by all characters. Try to login (click the “login” link in the menu of your website) and go to the same page again. You should now see a more detailed list of commands and help entries. Click on one to see its detail.</p>
2023-06-10 08:55:41 +02:00
</section>
</section>
<section id="to-improve-this-feature">
<h2>To improve this feature<a class="headerlink" href="#to-improve-this-feature" title="Permalink to this headline"></a></h2>
2023-10-19 20:22:27 +00:00
<p>As always, a tutorial is here to help you feel comfortable adding new features and code by yourself. Here are some ideas of things to improve this little feature:</p>
2023-06-10 08:55:41 +02:00
<ul class="simple">
<li><p>Links at the bottom of the detail template to go back to the index might be useful.</p></li>
2023-10-19 20:22:27 +00:00
<li><p>A link in the main menu to link to this page would be great… for the time being you have to enter the URL, users wont guess its there.</p></li>
2023-06-10 08:55:41 +02:00
<li><p>Colors arent handled at this point, which isnt exactly surprising. You could add it though.</p></li>
2023-10-19 20:22:27 +00:00
<li><p>Linking help entries between one another wont be simple, but it would be great. For instance, if you see a help entry about how to use several commands, it would be great if these commands were themselves links to display their details.</p></li>
2023-06-10 08:55:41 +02:00
</ul>
</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-Extending-the-REST-API.html" title="Extending the REST API"
>next</a> |</li>
<li class="right" >
<a href="Web-Character-View-Tutorial.html" title="Web Character View Tutorial"
>previous</a> |</li>
2023-10-19 20:22:27 +00:00
<li class="nav-item nav-item-0"><a href="../index.html">Evennia 2.x</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 Help System Tutorial</a></li>
2023-06-10 08:55:41 +02:00
</ul>
</div>
2023-10-19 20:22:27 +00:00
2023-06-10 08:55:41 +02:00
<div class="footer" role="contentinfo">
2023-10-19 20:22:27 +00:00
&#169; Copyright 2023, The Evennia developer community.
2023-06-10 08:55:41 +02:00
Created using <a href="https://www.sphinx-doc.org/">Sphinx</a> 3.2.1.
</div>
</body>
</html>