Updated HTML docs

This commit is contained in:
Griatch 2021-05-29 13:55:45 +02:00
parent 1bbc93507a
commit 8c5212d5ff
409 changed files with 17441 additions and 15857 deletions

View file

@ -76,7 +76,7 @@ command:</p>
<span class="normal">2</span>
<span class="normal">3</span></pre></div></td><td class="code"><div class="highlight"><pre><span></span> <span class="k">if</span> <span class="ow">not</span> <span class="n">obj</span><span class="o">.</span><span class="n">access</span><span class="p">(</span><span class="n">accessing_obj</span><span class="p">,</span> <span class="s1">&#39;delete&#39;</span><span class="p">):</span>
<span class="n">accessing_obj</span><span class="o">.</span><span class="n">msg</span><span class="p">(</span><span class="s2">&quot;Sorry, you may not delete that.&quot;</span><span class="p">)</span>
<span class="k">return</span>
<span class="k">return</span>
</pre></div>
</td></tr></table></div>
</section>
@ -89,9 +89,9 @@ definitions to the objects <code class="docutils literal notranslate"><span c
<span class="normal">2</span>
<span class="normal">3</span>
<span class="normal">4</span></pre></div></td><td class="code"><div class="highlight"><pre><span></span> <span class="n">delete</span><span class="p">:</span><span class="nb">id</span><span class="p">(</span><span class="mi">34</span><span class="p">)</span> <span class="c1"># only allow obj #34 to delete</span>
<span class="n">edit</span><span class="p">:</span><span class="nb">all</span><span class="p">()</span> <span class="c1"># let everyone edit </span>
<span class="n">edit</span><span class="p">:</span><span class="nb">all</span><span class="p">()</span> <span class="c1"># let everyone edit</span>
<span class="c1"># only those who are not &quot;very_weak&quot; or are Admins may pick this up</span>
<span class="n">get</span><span class="p">:</span> <span class="ow">not</span> <span class="n">attr</span><span class="p">(</span><span class="n">very_weak</span><span class="p">)</span> <span class="ow">or</span> <span class="n">perm</span><span class="p">(</span><span class="n">Admin</span><span class="p">)</span>
<span class="n">get</span><span class="p">:</span> <span class="ow">not</span> <span class="n">attr</span><span class="p">(</span><span class="n">very_weak</span><span class="p">)</span> <span class="ow">or</span> <span class="n">perm</span><span class="p">(</span><span class="n">Admin</span><span class="p">)</span>
</pre></div>
</td></tr></table></div>
<p>Formally, a lockstring has the following syntax:</p>
@ -106,7 +106,7 @@ returns either <code class="docutils literal notranslate"><span class="pre">True
total result is <code class="docutils literal notranslate"><span class="pre">True</span></code>, the lock is passed.</p>
<p>You can create several lock types one after the other by separating them with a semicolon (<code class="docutils literal notranslate"><span class="pre">;</span></code>) in
the lockstring. The string below yields the same result as the previous example:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">delete</span><span class="p">:</span><span class="nb">id</span><span class="p">(</span><span class="mi">34</span><span class="p">);</span><span class="n">edit</span><span class="p">:</span><span class="nb">all</span><span class="p">();</span><span class="n">get</span><span class="p">:</span> <span class="ow">not</span> <span class="n">attr</span><span class="p">(</span><span class="n">very_weak</span><span class="p">)</span> <span class="ow">or</span> <span class="n">perm</span><span class="p">(</span><span class="n">Admin</span><span class="p">)</span>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">delete</span><span class="p">:</span><span class="nb">id</span><span class="p">(</span><span class="mi">34</span><span class="p">);</span><span class="n">edit</span><span class="p">:</span><span class="nb">all</span><span class="p">();</span><span class="n">get</span><span class="p">:</span> <span class="ow">not</span> <span class="n">attr</span><span class="p">(</span><span class="n">very_weak</span><span class="p">)</span> <span class="ow">or</span> <span class="n">perm</span><span class="p">(</span><span class="n">Admin</span><span class="p">)</span>
</pre></div>
</div>
<section id="valid-access-types">
@ -205,7 +205,7 @@ trying to read the board):</p>
<span class="normal">2</span>
<span class="normal">3</span></pre></div></td><td class="code"><div class="highlight"><pre><span></span> <span class="k">if</span> <span class="ow">not</span> <span class="n">obj</span><span class="o">.</span><span class="n">access</span><span class="p">(</span><span class="n">accessing_obj</span><span class="p">,</span> <span class="s1">&#39;read&#39;</span><span class="p">):</span>
<span class="n">accessing_obj</span><span class="o">.</span><span class="n">msg</span><span class="p">(</span><span class="s2">&quot;Sorry, you may not read that.&quot;</span><span class="p">)</span>
<span class="k">return</span>
<span class="k">return</span>
</pre></div>
</td></tr></table></div>
</section>
@ -230,12 +230,12 @@ arguments explicitly given in the lock definition will appear as extra arguments
<span class="normal">7</span>
<span class="normal">8</span></pre></div></td><td class="code"><div class="highlight"><pre><span></span> <span class="c1"># A simple example lock function. Called with e.g. `id(34)`. This is</span>
<span class="c1"># defined in, say mygame/server/conf/lockfuncs.py</span>
<span class="k">def</span> <span class="nf">id</span><span class="p">(</span><span class="n">accessing_obj</span><span class="p">,</span> <span class="n">accessed_obj</span><span class="p">,</span> <span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">):</span>
<span class="k">if</span> <span class="n">args</span><span class="p">:</span>
<span class="n">wanted_id</span> <span class="o">=</span> <span class="n">args</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span>
<span class="k">return</span> <span class="n">accessing_obj</span><span class="o">.</span><span class="n">id</span> <span class="o">==</span> <span class="n">wanted_id</span>
<span class="k">return</span> <span class="kc">False</span>
<span class="k">return</span> <span class="kc">False</span>
</pre></div>
</td></tr></table></div>
<p>The above could for example be used in a lock function like this:</p>
@ -313,126 +313,6 @@ child object to change the default. Also creation commands like <code class="doc
objects you create - for example it sets the <code class="docutils literal notranslate"><span class="pre">control</span></code> lock_type so as to allow you, its creator, to
control and delete the object.</p>
</section>
</section>
<section id="permissions">
<h1>Permissions<a class="headerlink" href="#permissions" title="Permalink to this headline"></a></h1>
<blockquote>
<div><p>This section covers the underlying code use of permissions. If you just want to learn how to
practically assign permissions in-game, refer to the <a class="reference internal" href="../Concepts/Building-Permissions.html"><span class="doc">Building Permissions</span></a>
page, which details how you use the <code class="docutils literal notranslate"><span class="pre">perm</span></code> command.</p>
</div></blockquote>
<p>A <em>permission</em> is simply a list of text strings stored in the handler <code class="docutils literal notranslate"><span class="pre">permissions</span></code> on <code class="docutils literal notranslate"><span class="pre">Objects</span></code>
and <code class="docutils literal notranslate"><span class="pre">Accounts</span></code>. Permissions can be used as a convenient way to structure access levels and
hierarchies. It is set by the <code class="docutils literal notranslate"><span class="pre">perm</span></code> command. Permissions are especially handled by the <code class="docutils literal notranslate"><span class="pre">perm()</span></code> and
<code class="docutils literal notranslate"><span class="pre">pperm()</span></code> lock functions listed above.</p>
<p>Lets say we have a <code class="docutils literal notranslate"><span class="pre">red_key</span></code> object. We also have red chests that we want to unlock with this key.</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">perm</span> <span class="n">red_key</span> <span class="o">=</span> <span class="n">unlocks_red_chests</span>
</pre></div>
</div>
<p>This gives the <code class="docutils literal notranslate"><span class="pre">red_key</span></code> object the permission “unlocks_red_chests”. Next we lock our red chests:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">lock</span> <span class="n">red</span> <span class="n">chest</span> <span class="o">=</span> <span class="n">unlock</span><span class="p">:</span><span class="n">perm</span><span class="p">(</span><span class="n">unlocks_red_chests</span><span class="p">)</span>
</pre></div>
</div>
<p>What this lock will expect is to the fed the actual key object. The <code class="docutils literal notranslate"><span class="pre">perm()</span></code> lock function will
check the permissions set on the key and only return true if the permission is the one given.</p>
<p>Finally we need to actually check this lock somehow. Lets say the chest has an command <code class="docutils literal notranslate"><span class="pre">open</span> <span class="pre">&lt;key&gt;</span></code>
sitting on itself. Somewhere in its code the command needs to figure out which key you are using and
test if this key has the correct permission:</p>
<div class="highlight-python notranslate"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal">1</span>
<span class="normal">2</span>
<span class="normal">3</span>
<span class="normal">4</span>
<span class="normal">5</span>
<span class="normal">6</span>
<span class="normal">7</span></pre></div></td><td class="code"><div class="highlight"><pre><span></span> <span class="c1"># self.obj is the chest </span>
<span class="c1"># and used_key is the key we used as argument to</span>
<span class="c1"># the command. The self.caller is the one trying</span>
<span class="c1"># to unlock the chest</span>
<span class="k">if</span> <span class="ow">not</span> <span class="bp">self</span><span class="o">.</span><span class="n">obj</span><span class="o">.</span><span class="n">access</span><span class="p">(</span><span class="n">used_key</span><span class="p">,</span> <span class="s2">&quot;unlock&quot;</span><span class="p">):</span>
<span class="bp">self</span><span class="o">.</span><span class="n">caller</span><span class="o">.</span><span class="n">msg</span><span class="p">(</span><span class="s2">&quot;The key does not fit!&quot;</span><span class="p">)</span>
<span class="k">return</span>
</pre></div>
</td></tr></table></div>
<p>All new accounts are given a default set of permissions defined by
<code class="docutils literal notranslate"><span class="pre">settings.PERMISSION_ACCOUNT_DEFAULT</span></code>.</p>
<p>Selected permission strings can be organized in a <em>permission hierarchy</em> by editing the tuple
<code class="docutils literal notranslate"><span class="pre">settings.PERMISSION_HIERARCHY</span></code>. Evennias default permission hierarchy is as follows:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span> <span class="n">Developer</span> <span class="c1"># like superuser but affected by locks</span>
<span class="n">Admin</span> <span class="c1"># can administrate accounts</span>
<span class="n">Builder</span> <span class="c1"># can edit the world</span>
<span class="n">Helper</span> <span class="c1"># can edit help files</span>
<span class="n">Player</span> <span class="c1"># can chat and send tells (default level)</span>
</pre></div>
</div>
<p>(Also the plural form works, so you could use <code class="docutils literal notranslate"><span class="pre">Developers</span></code> etc too).</p>
<blockquote>
<div><p>There is also a <code class="docutils literal notranslate"><span class="pre">Guest</span></code> level below <code class="docutils literal notranslate"><span class="pre">Player</span></code> that is only active if <code class="docutils literal notranslate"><span class="pre">settings.GUEST_ENABLED</span></code> is
set. This is never part of <code class="docutils literal notranslate"><span class="pre">settings.PERMISSION_HIERARCHY</span></code>.</p>
</div></blockquote>
<p>The main use of this is that if you use the lock function <code class="docutils literal notranslate"><span class="pre">perm()</span></code> mentioned above, a lock check for
a particular permission in the hierarchy will <em>also</em> grant access to those with <em>higher</em> hierarchy
access. So if you have the permission “Admin” you will also pass a lock defined as <code class="docutils literal notranslate"><span class="pre">perm(Builder)</span></code>
or any of those levels below “Admin”.</p>
<p>When doing an access check from an <a class="reference internal" href="Objects.html"><span class="doc">Object</span></a> or Character, the <code class="docutils literal notranslate"><span class="pre">perm()</span></code> lock function will
always first use the permissions of any Account connected to that Object before checking for
permissions on the Object. In the case of hierarchical permissions (Admins, Builders etc), the
Account permission will always be used (this stops an Account from escalating their permission by
puppeting a high-level Character). If the permission looked for is not in the hierarchy, an exact
match is required, first on the Account and if not found there (or if no Account is connected), then
on the Object itself.</p>
<p>Here is how you use <code class="docutils literal notranslate"><span class="pre">perm</span></code> to give an account more permissions:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span> <span class="n">perm</span><span class="o">/</span><span class="n">account</span> <span class="n">Tommy</span> <span class="o">=</span> <span class="n">Builders</span>
<span class="n">perm</span><span class="o">/</span><span class="n">account</span><span class="o">/</span><span class="k">del</span> <span class="n">Tommy</span> <span class="o">=</span> <span class="n">Builders</span> <span class="c1"># remove it again</span>
</pre></div>
</div>
<p>Note the use of the <code class="docutils literal notranslate"><span class="pre">/account</span></code> switch. It means you assign the permission to the
<a class="reference internal" href="Accounts.html"><span class="doc">Accounts</span></a> Tommy instead of any <a class="reference internal" href="Objects.html"><span class="doc">Character</span></a> that also happens to be named
“Tommy”.</p>
<p>Putting permissions on the <em>Account</em> guarantees that they are kept, <em>regardless</em> of which Character
they are currently puppeting. This is especially important to remember when assigning permissions
from the <em>hierarchy tree</em> - as mentioned above, an Accounts permissions will overrule that of its
character. So to be sure to avoid confusion you should generally put hierarchy permissions on the
Account, not on their Characters (but see also <a class="reference external" href="Components/Locks.html#Quelling">quelling</a>).</p>
<p>Below is an example of an object without any connected account</p>
<div class="highlight-python notranslate"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal">1</span>
<span class="normal">2</span>
<span class="normal">3</span>
<span class="normal">4</span></pre></div></td><td class="code"><div class="highlight"><pre><span></span> <span class="n">obj1</span><span class="o">.</span><span class="n">permissions</span> <span class="o">=</span> <span class="p">[</span><span class="s2">&quot;Builders&quot;</span><span class="p">,</span> <span class="s2">&quot;cool_guy&quot;</span><span class="p">]</span>
<span class="n">obj2</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;enter:perm_above(Accounts) and perm(cool_guy)&quot;</span><span class="p">)</span>
<span class="n">obj2</span><span class="o">.</span><span class="n">access</span><span class="p">(</span><span class="n">obj1</span><span class="p">,</span> <span class="s2">&quot;enter&quot;</span><span class="p">)</span> <span class="c1"># this returns True!</span>
</pre></div>
</td></tr></table></div>
<p>And one example of a puppet with a connected account:</p>
<div class="highlight-python notranslate"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal">1</span>
<span class="normal">2</span>
<span class="normal">3</span>
<span class="normal">4</span>
<span class="normal">5</span></pre></div></td><td class="code"><div class="highlight"><pre><span></span> <span class="n">account</span><span class="o">.</span><span class="n">permissions</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="s2">&quot;Accounts&quot;</span><span class="p">)</span>
<span class="n">puppet</span><span class="o">.</span><span class="n">permissions</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="s2">&quot;Builders&quot;</span><span class="p">,</span> <span class="s2">&quot;cool_guy&quot;</span><span class="p">)</span>
<span class="n">obj2</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;enter:perm_above(Accounts) and perm(cool_guy)&quot;</span><span class="p">)</span>
<span class="n">obj2</span><span class="o">.</span><span class="n">access</span><span class="p">(</span><span class="n">puppet</span><span class="p">,</span> <span class="s2">&quot;enter&quot;</span><span class="p">)</span> <span class="c1"># this returns False!</span>
</pre></div>
</td></tr></table></div>
<section id="superusers">
<h2>Superusers<a class="headerlink" href="#superusers" title="Permalink to this headline"></a></h2>
<p>There is normally only one <em>superuser</em> account and that is the one first created when starting
Evennia (User #1). This is sometimes known as the “Owner” or “God” user. A superuser has more than
full access - it completely <em>bypasses</em> all locks so no checks are even run. This allows for the
superuser to always have access to everything in an emergency. But it also hides any eventual errors
you might have made in your lock definitions. So when trying out game systems you should either use
quelling (see below) or make a second Developer-level character so your locks get tested correctly.</p>
</section>
<section id="quelling">
<h2>Quelling<a class="headerlink" href="#quelling" title="Permalink to this headline"></a></h2>
<p>The <code class="docutils literal notranslate"><span class="pre">quell</span></code> command can be used to enforce the <code class="docutils literal notranslate"><span class="pre">perm()</span></code> lockfunc to ignore permissions on the
Account and instead use the permissions on the Character only. This can be used e.g. by staff to
test out things with a lower permission level. Return to the normal operation with <code class="docutils literal notranslate"><span class="pre">unquell</span></code>. Note
that quelling will use the smallest of any hierarchical permission on the Account or Character, so
one cannot escalate ones Account permission by quelling to a high-permission Character. Also the
superuser can quell their powers this way, making them affectable by locks.</p>
</section>
<section id="more-lock-definition-examples">
<h2>More Lock definition examples<a class="headerlink" href="#more-lock-definition-examples" title="Permalink to this headline"></a></h2>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">examine</span><span class="p">:</span> <span class="n">attr</span><span class="p">(</span><span class="n">eyesight</span><span class="p">,</span> <span class="n">excellent</span><span class="p">)</span> <span class="ow">or</span> <span class="n">perm</span><span class="p">(</span><span class="n">Builders</span><span class="p">)</span>
@ -441,7 +321,7 @@ superuser can quell their powers this way, making them affectable by locks.</p>
<p>You are only allowed to do <em>examine</em> on this object if you have excellent eyesight (that is, has
an Attribute <code class="docutils literal notranslate"><span class="pre">eyesight</span></code> with the value <code class="docutils literal notranslate"><span class="pre">excellent</span></code> defined on yourself) or if you have the
“Builders” permission string assigned to you.</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="nb">open</span><span class="p">:</span> <span class="n">holds</span><span class="p">(</span><span class="s1">&#39;the green key&#39;</span><span class="p">)</span> <span class="ow">or</span> <span class="n">perm</span><span class="p">(</span><span class="n">Builder</span><span class="p">)</span>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="nb">open</span><span class="p">:</span> <span class="n">holds</span><span class="p">(</span><span class="s1">&#39;the green key&#39;</span><span class="p">)</span> <span class="ow">or</span> <span class="n">perm</span><span class="p">(</span><span class="n">Builder</span><span class="p">)</span>
</pre></div>
</div>
<p>This could be called by the <code class="docutils literal notranslate"><span class="pre">open</span></code> command on a “door” object. The check is passed if you are a
@ -534,20 +414,20 @@ strength above 50 however and youll pick it up no problem. Done! A very heavy
<span class="normal">12</span>
<span class="normal">13</span>
<span class="normal">14</span>
<span class="normal">15</span></pre></div></td><td class="code"><div class="highlight"><pre><span></span>
<span class="normal">15</span></pre></div></td><td class="code"><div class="highlight"><pre><span></span>
<span class="kn">from</span> <span class="nn">evennia</span> <span class="kn">import</span> <span class="n">create_object</span>
<span class="c1"># create, then set the lock</span>
<span class="n">box</span> <span class="o">=</span> <span class="n">create_object</span><span class="p">(</span><span class="kc">None</span><span class="p">,</span> <span class="n">key</span><span class="o">=</span><span class="s2">&quot;box&quot;</span><span class="p">)</span>
<span class="n">box</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;get:attr_gt(strength, 50)&quot;</span><span class="p">)</span>
<span class="c1"># or we can assign locks in one go right away</span>
<span class="n">box</span> <span class="o">=</span> <span class="n">create_object</span><span class="p">(</span><span class="kc">None</span><span class="p">,</span> <span class="n">key</span><span class="o">=</span><span class="s2">&quot;box&quot;</span><span class="p">,</span> <span class="n">locks</span><span class="o">=</span><span class="s2">&quot;get:attr_gt(strength, 50)&quot;</span><span class="p">)</span>
<span class="c1"># set the attributes</span>
<span class="n">box</span><span class="o">.</span><span class="n">db</span><span class="o">.</span><span class="n">desc</span> <span class="o">=</span> <span class="s2">&quot;This is a very big and heavy box.&quot;</span>
<span class="n">box</span><span class="o">.</span><span class="n">db</span><span class="o">.</span><span class="n">get_err_msg</span> <span class="o">=</span> <span class="s2">&quot;You are not strong enough to lift this box.&quot;</span>
<span class="c1"># one heavy box, ready to withstand all but the strongest...</span>
</pre></div>
</td></tr></table></div>
@ -601,11 +481,6 @@ interface. Its stand-alone from the permissions described above.</p>
</li>
<li><a class="reference internal" href="#checking-simple-strings">Checking simple strings</a></li>
<li><a class="reference internal" href="#default-locks">Default locks</a></li>
</ul>
</li>
<li><a class="reference internal" href="#permissions">Permissions</a><ul>
<li><a class="reference internal" href="#superusers">Superusers</a></li>
<li><a class="reference internal" href="#quelling">Quelling</a></li>
<li><a class="reference internal" href="#more-lock-definition-examples">More Lock definition examples</a></li>
<li><a class="reference internal" href="#a-complete-example-of-setting-locks-on-an-object">A complete example of setting locks on an object</a></li>
<li><a class="reference internal" href="#on-django-s-permission-system">On Djangos permission system</a></li>

View file

@ -0,0 +1,240 @@
<!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>Permissions &#8212; Evennia 1.0-dev 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" />
</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="nav-item nav-item-0"><a href="../index.html">Evennia 1.0-dev</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">Permissions</a></li>
</ul>
<div class="develop">develop branch</div>
</div>
<div class="document">
<div class="documentwrapper">
<div class="bodywrapper">
<div class="body" role="main">
<section id="permissions">
<h1>Permissions<a class="headerlink" href="#permissions" title="Permalink to this headline"></a></h1>
<p>A <em>permission</em> is simply a text string stored in the handler <code class="docutils literal notranslate"><span class="pre">permissions</span></code> on <code class="docutils literal notranslate"><span class="pre">Objects</span></code>
and <code class="docutils literal notranslate"><span class="pre">Accounts</span></code>. Think of it as a specialized sort of <a class="reference internal" href="Tags.html"><span class="doc">Tag</span></a> - one specifically dedicated
to access checking. They are thus often tightly coupled to <a class="reference internal" href="Locks.html"><span class="doc">Locks</span></a>.</p>
<p>Permissions are used as a convenient way to structure access levels and
hierarchies. It is set by the <code class="docutils literal notranslate"><span class="pre">perm</span></code> command. Permissions are especially
handled by the <code class="docutils literal notranslate"><span class="pre">perm()</span></code> and <code class="docutils literal notranslate"><span class="pre">pperm()</span></code> <a class="reference internal" href="Locks.html"><span class="doc">lock functions</span></a>.</p>
<p>Lets say we have a <code class="docutils literal notranslate"><span class="pre">red_key</span></code> object. We also have red chests that we want to unlock with this key.</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">perm</span> <span class="n">red_key</span> <span class="o">=</span> <span class="n">unlocks_red_chests</span>
</pre></div>
</div>
<p>This gives the <code class="docutils literal notranslate"><span class="pre">red_key</span></code> object the permission “unlocks_red_chests”. Next we
lock our red chests:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">lock</span> <span class="n">red</span> <span class="n">chest</span> <span class="o">=</span> <span class="n">unlock</span><span class="p">:</span><span class="n">perm</span><span class="p">(</span><span class="n">unlocks_red_chests</span><span class="p">)</span>
</pre></div>
</div>
<p>When trying to unlock the red chest with this key, the chest Typeclass could
then take the key and do an access check:</p>
<div class="highlight-python notranslate"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal"> 1</span>
<span class="normal"> 2</span>
<span class="normal"> 3</span>
<span class="normal"> 4</span>
<span class="normal"> 5</span>
<span class="normal"> 6</span>
<span class="normal"> 7</span>
<span class="normal"> 8</span>
<span class="normal"> 9</span>
<span class="normal">10</span>
<span class="normal">11</span></pre></div></td><td class="code"><div class="highlight"><pre><span></span><span class="c1"># in some typeclass file where chest is defined</span>
<span class="k">class</span> <span class="nc">TreasureChest</span><span class="p">(</span><span class="n">Object</span><span class="p">):</span>
<span class="c1"># ...</span>
<span class="k">def</span> <span class="nf">open_chest</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">who</span><span class="p">,</span> <span class="n">tried_key</span><span class="p">):</span>
<span class="k">if</span> <span class="ow">not</span> <span class="n">chest</span><span class="o">.</span><span class="n">access</span><span class="p">(</span><span class="n">who</span><span class="p">,</span> <span class="n">tried_key</span><span class="p">,</span> <span class="s2">&quot;unlock&quot;</span><span class="p">):</span>
<span class="n">who</span><span class="o">.</span><span class="n">msg</span><span class="p">(</span><span class="s2">&quot;The key does not fit!&quot;</span><span class="p">)</span>
<span class="k">return</span>
</pre></div>
</td></tr></table></div>
<p>All new accounts are given a default set of permissions defined by
<code class="docutils literal notranslate"><span class="pre">settings.PERMISSION_ACCOUNT_DEFAULT</span></code>.</p>
<p>Selected permission strings can be organized in a <em>permission hierarchy</em> by editing the tuple
<code class="docutils literal notranslate"><span class="pre">settings.PERMISSION_HIERARCHY</span></code>. Evennias default permission hierarchy is as follows:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span> <span class="n">Developer</span> <span class="c1"># like superuser but affected by locks</span>
<span class="n">Admin</span> <span class="c1"># can administrate accounts</span>
<span class="n">Builder</span> <span class="c1"># can edit the world</span>
<span class="n">Helper</span> <span class="c1"># can edit help files</span>
<span class="n">Player</span> <span class="c1"># can chat and send tells (default level)</span>
</pre></div>
</div>
<p>(Also the plural form works, so you could use <code class="docutils literal notranslate"><span class="pre">Developers</span></code> etc too).</p>
<blockquote>
<div><p>There is also a <code class="docutils literal notranslate"><span class="pre">Guest</span></code> level below <code class="docutils literal notranslate"><span class="pre">Player</span></code> that is only active if <code class="docutils literal notranslate"><span class="pre">settings.GUEST_ENABLED</span></code> is
set. This is never part of <code class="docutils literal notranslate"><span class="pre">settings.PERMISSION_HIERARCHY</span></code>.</p>
</div></blockquote>
<p>The main use of this is that if you use the lock function <code class="docutils literal notranslate"><span class="pre">perm()</span></code> mentioned above, a lock check for
a particular permission in the hierarchy will <em>also</em> grant access to those with <em>higher</em> hierarchy
access. So if you have the permission “Admin” you will also pass a lock defined as <code class="docutils literal notranslate"><span class="pre">perm(Builder)</span></code>
or any of those levels below “Admin”.</p>
<p>When doing an access check from an <a class="reference internal" href="Objects.html"><span class="doc">Object</span></a> or Character, the <code class="docutils literal notranslate"><span class="pre">perm()</span></code> lock function will
always first use the permissions of any Account connected to that Object before checking for
permissions on the Object. In the case of hierarchical permissions (Admins, Builders etc), the
Account permission will always be used (this stops an Account from escalating their permission by
puppeting a high-level Character). If the permission looked for is not in the hierarchy, an exact
match is required, first on the Account and if not found there (or if no Account is connected), then
on the Object itself.</p>
<p>Here is how you use <code class="docutils literal notranslate"><span class="pre">perm</span></code> to give an account more permissions:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span> <span class="n">perm</span><span class="o">/</span><span class="n">account</span> <span class="n">Tommy</span> <span class="o">=</span> <span class="n">Builders</span>
<span class="n">perm</span><span class="o">/</span><span class="n">account</span><span class="o">/</span><span class="k">del</span> <span class="n">Tommy</span> <span class="o">=</span> <span class="n">Builders</span> <span class="c1"># remove it again</span>
</pre></div>
</div>
<p>Note the use of the <code class="docutils literal notranslate"><span class="pre">/account</span></code> switch. It means you assign the permission to the
<a class="reference internal" href="Accounts.html"><span class="doc">Accounts</span></a> Tommy instead of any <a class="reference internal" href="Objects.html"><span class="doc">Character</span></a> that also happens to be named
“Tommy”.</p>
<p>Putting permissions on the <em>Account</em> guarantees that they are kept, <em>regardless</em> of which Character
they are currently puppeting. This is especially important to remember when assigning permissions
from the <em>hierarchy tree</em> - as mentioned above, an Accounts permissions will overrule that of its
character. So to be sure to avoid confusion you should generally put hierarchy permissions on the
Account, not on their Characters (but see also <a class="reference external" href="Components/Locks.html#Quelling">quelling</a>).</p>
<p>Below is an example of an object without any connected account</p>
<div class="highlight-python notranslate"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal">1</span>
<span class="normal">2</span>
<span class="normal">3</span>
<span class="normal">4</span></pre></div></td><td class="code"><div class="highlight"><pre><span></span> <span class="n">obj1</span><span class="o">.</span><span class="n">permissions</span> <span class="o">=</span> <span class="p">[</span><span class="s2">&quot;Builders&quot;</span><span class="p">,</span> <span class="s2">&quot;cool_guy&quot;</span><span class="p">]</span>
<span class="n">obj2</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;enter:perm_above(Accounts) and perm(cool_guy)&quot;</span><span class="p">)</span>
<span class="n">obj2</span><span class="o">.</span><span class="n">access</span><span class="p">(</span><span class="n">obj1</span><span class="p">,</span> <span class="s2">&quot;enter&quot;</span><span class="p">)</span> <span class="c1"># this returns True!</span>
</pre></div>
</td></tr></table></div>
<p>And one example of a puppet with a connected account:</p>
<div class="highlight-python notranslate"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal">1</span>
<span class="normal">2</span>
<span class="normal">3</span>
<span class="normal">4</span>
<span class="normal">5</span></pre></div></td><td class="code"><div class="highlight"><pre><span></span> <span class="n">account</span><span class="o">.</span><span class="n">permissions</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="s2">&quot;Accounts&quot;</span><span class="p">)</span>
<span class="n">puppet</span><span class="o">.</span><span class="n">permissions</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="s2">&quot;Builders&quot;</span><span class="p">,</span> <span class="s2">&quot;cool_guy&quot;</span><span class="p">)</span>
<span class="n">obj2</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;enter:perm_above(Accounts) and perm(cool_guy)&quot;</span><span class="p">)</span>
<span class="n">obj2</span><span class="o">.</span><span class="n">access</span><span class="p">(</span><span class="n">puppet</span><span class="p">,</span> <span class="s2">&quot;enter&quot;</span><span class="p">)</span> <span class="c1"># this returns False!</span>
</pre></div>
</td></tr></table></div>
<section id="superusers">
<h2>Superusers<a class="headerlink" href="#superusers" title="Permalink to this headline"></a></h2>
<p>There is normally only one <em>superuser</em> account and that is the one first created when starting
Evennia (User #1). This is sometimes known as the “Owner” or “God” user. A superuser has more than
full access - it completely <em>bypasses</em> all locks so no checks are even run. This allows for the
superuser to always have access to everything in an emergency. But it also hides any eventual errors
you might have made in your lock definitions. So when trying out game systems you should either use
quelling (see below) or make a second Developer-level character so your locks get tested correctly.</p>
</section>
<section id="quelling">
<h2>Quelling<a class="headerlink" href="#quelling" title="Permalink to this headline"></a></h2>
<p>The <code class="docutils literal notranslate"><span class="pre">quell</span></code> command can be used to enforce the <code class="docutils literal notranslate"><span class="pre">perm()</span></code> lockfunc to ignore permissions on the
Account and instead use the permissions on the Character only. This can be used e.g. by staff to
test out things with a lower permission level. Return to the normal operation with <code class="docutils literal notranslate"><span class="pre">unquell</span></code>. Note
that quelling will use the smallest of any hierarchical permission on the Account or Character, so
one cannot escalate ones Account permission by quelling to a high-permission Character. Also the
superuser can quell their powers this way, making them affectable by locks.</p>
</section>
</section>
<div class="clearer"></div>
</div>
</div>
</div>
<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>
<p><h3><a href="../index.html">Table of Contents</a></h3>
<ul>
<li><a class="reference internal" href="#">Permissions</a><ul>
<li><a class="reference internal" href="#superusers">Superusers</a></li>
<li><a class="reference internal" href="#quelling">Quelling</a></li>
</ul>
</li>
</ul>
<div role="note" aria-label="source link">
<!--h3>This Page</h3-->
<ul class="this-page-menu">
<li><a href="../_sources/Components/Permissions.md.txt"
rel="nofollow">Show Page Source</a></li>
</ul>
</div><h3>Links</h3>
<ul>
<li><a href="https://www.evennia.com">Home page</a> </li>
<li><a href="https://github.com/evennia/evennia">Evennia Github</a> </li>
<li><a href="http://games.evennia.com">Game Index</a> </li>
<li><a href="http://webchat.freenode.net/?channels=evennia&uio=MT1mYWxzZSY5PXRydWUmMTE9MTk1JjEyPXRydWUbb">IRC</a> -
<a href="https://discord.gg/NecFePw">Discord</a> -
<a href="https://groups.google.com/forum/#%21forum/evennia">Forums</a>
</li>
<li><a href="http://evennia.blogspot.com/">Evennia Dev blog</a> </li>
</ul>
<h3>Versions</h3>
<ul>
<li><a href="Permissions.html">1.0-dev (develop branch)</a></li>
<li><a href="../../0.9.5/index.html">0.9.5 (v0.9.5 branch)</a></li>
</ul>
</div>
</div>
<div class="clearer"></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="nav-item nav-item-0"><a href="../index.html">Evennia 1.0-dev</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">Permissions</a></li>
</ul>
<div class="develop">develop branch</div>
</div>
<div class="footer" role="contentinfo">
&#169; Copyright 2020, The Evennia developer community.
Created using <a href="https://www.sphinx-doc.org/">Sphinx</a> 3.2.1.
</div>
</body>
</html>

View file

@ -0,0 +1,231 @@
<!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>Evennia REST API &#8212; Evennia 1.0-dev 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" />
</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="nav-item nav-item-0"><a href="../index.html">Evennia 1.0-dev</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">Evennia REST API</a></li>
</ul>
<div class="develop">develop branch</div>
</div>
<div class="document">
<div class="documentwrapper">
<div class="bodywrapper">
<div class="body" role="main">
<section id="evennia-rest-api">
<h1>Evennia REST API<a class="headerlink" href="#evennia-rest-api" title="Permalink to this headline"></a></h1>
<p>Evennia makes its database accessible via a REST API found on
<a class="reference external" href="http://localhost:4001/api">http://localhost:4001/api</a> if running locally with
default setup. The API allows you to retrieve, edit and create resources from
outside the game, for example with your own custom client or game editor.</p>
<p>While you can view and learn about the api in the web browser, it is really
meant to be accessed in code, by other programs.</p>
<p>The API is using <a class="reference external" href="https://www.django-rest-framework.org/">Django Rest Framework</a>. This automates the process
of setting up <em>views</em> (Python code) to process the result of web requests.
The process of retrieving data is similar to that explained on the
<a class="reference internal" href="Webserver.html"><span class="doc">Webserver</span></a> page, except the views will here return <a class="reference external" href="https://en.wikipedia.org/wiki/JSON">JSON</a>
data for the resource you want. You can also <em>send</em> such JSON data
in order to update the database from the outside.</p>
<section id="usage">
<h2>Usage<a class="headerlink" href="#usage" title="Permalink to this headline"></a></h2>
<p>To activate the API, add this to your settings file.</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">REST_API_ENABLED</span> <span class="o">=</span> <span class="kc">True</span>
</pre></div>
</div>
<p>The main controlling setting is <code class="docutils literal notranslate"><span class="pre">REST_FRAMEWORK</span></code>, which is a dict. The keys
<code class="docutils literal notranslate"><span class="pre">DEFAULT_LIST_PERMISSION</span></code> and <code class="docutils literal notranslate"><span class="pre">DEFAULT_CREATE_PERMISSIONS</span></code> control who may
view and create new objects via the api respectively. By default, users with
<a class="reference internal" href="Permissions.html"><span class="doc">Builder-level permission</span></a> or higher may access both actions.</p>
<p>While the api is meant to be expanded upon, Evennia supplies several operations
out of the box. If you click the <code class="docutils literal notranslate"><span class="pre">Autodoc</span></code> button in the upper right of the <code class="docutils literal notranslate"><span class="pre">/api</span></code>
website youll get a fancy graphical presentation of the available endpoints.</p>
<p>Here is an example of calling the api in Python using the standard <code class="docutils literal notranslate"><span class="pre">requests</span></code> library.</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">&gt;&gt;&gt; </span><span class="kn">import</span> <span class="nn">requests</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">response</span> <span class="o">=</span> <span class="n">requests</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&quot;https://www.mygame.com/api&quot;</span><span class="p">,</span> <span class="n">auth</span><span class="o">=</span><span class="p">(</span><span class="s2">&quot;MyUsername&quot;</span><span class="p">,</span> <span class="s2">&quot;password123&quot;</span><span class="p">))</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">response</span><span class="o">.</span><span class="n">json</span><span class="p">()</span>
<span class="go">{&#39;accounts&#39;: &#39;http://www.mygame.com/api/accounts/&#39;,</span>
<span class="go"> &#39;objects&#39;: &#39;http://www.mygame.com/api/objects/&#39;,</span>
<span class="go">&#39;characters&#39;: &#39;http://www.mygame.comg/api/characters/&#39;,</span>
<span class="go">&#39;exits&#39;: &#39;http://www.mygame.com/api/exits/&#39;,</span>
<span class="go">&#39;rooms&#39;: &#39;http://www.mygame.com/api/rooms/&#39;,</span>
<span class="go">&#39;scripts&#39;: &#39;http://www.mygame.com/api/scripts/&#39;</span>
<span class="go">&#39;helpentries&#39;: &#39;http://www.mygame.com/api/helpentries/&#39; }</span>
</pre></div>
</div>
<p>To list a specific type of object:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">&gt;&gt;&gt; </span><span class="n">response</span> <span class="o">=</span> <span class="n">requests</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&quot;https://www.mygame.com/api/objects&quot;</span><span class="p">,</span>
<span class="go"> auth=(&quot;Myusername&quot;, &quot;password123&quot;))</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">response</span><span class="o">.</span><span class="n">json</span><span class="p">()</span>
<span class="go">{</span>
<span class="go">&quot;count&quot;: 125,</span>
<span class="go">&quot;next&quot;: &quot;https://www.mygame.com/api/objects/?limit=25&amp;offset=25&quot;,</span>
<span class="go">&quot;previous&quot;: null,</span>
<span class="go">&quot;results&quot; : [{&quot;db_key&quot;: &quot;A rusty longsword&quot;, &quot;id&quot;: 57, &quot;db_location&quot;: 213, ...}]}</span>
</pre></div>
</div>
<p>In the above example, it now displays the objects inside the “results” array,
while it has a “count” value for the number of total objects, and “next” and
“previous” links for the next and previous page, if any. This is called
<a class="reference external" href="https://www.django-rest-framework.org/api-guide/pagination/">pagination</a>, and the link displays “limit” and “offset” as query
parameters that can be added to the url to control the output.</p>
<p>Other query parameters can be defined as <a class="reference external" href="https://www.django-rest-framework.org/api-guide/filtering/#filtering">filters</a> which allow you to
further narrow the results. For example, to only get accounts with developer
permissions:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">&gt;&gt;&gt; </span><span class="n">response</span> <span class="o">=</span> <span class="n">requests</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&quot;https://www.mygame.com/api/accounts/?permission=developer&quot;</span><span class="p">,</span>
<span class="go"> auth=(&quot;MyUserName&quot;, &quot;password123&quot;))</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">response</span><span class="o">.</span><span class="n">json</span><span class="p">()</span>
<span class="go">{</span>
<span class="go">&quot;count&quot;: 1,</span>
<span class="go">&quot;results&quot;: [{&quot;username&quot;: &quot;bob&quot;,...}]</span>
<span class="go">}</span>
</pre></div>
</div>
<p>Now suppose that you want to use the API to create an <a class="reference internal" href="Objects.html"><span class="doc">Object</span></a>:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">&gt;&gt;&gt; </span><span class="n">data</span> <span class="o">=</span> <span class="p">{</span><span class="s2">&quot;db_key&quot;</span><span class="p">:</span> <span class="s2">&quot;A shiny sword&quot;</span><span class="p">}</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">response</span> <span class="o">=</span> <span class="n">requests</span><span class="o">.</span><span class="n">post</span><span class="p">(</span><span class="s2">&quot;https://www.mygame.com/api/objects&quot;</span><span class="p">,</span>
<span class="go"> data=data, auth=(&quot;Anotherusername&quot;, &quot;mypassword&quot;))</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">response</span><span class="o">.</span><span class="n">json</span><span class="p">()</span>
<span class="go">{&quot;db_key&quot;: &quot;A shiny sword&quot;, &quot;id&quot;: 214, &quot;db_location&quot;: None, ...}</span>
</pre></div>
</div>
<p>Here we made a HTTP POST request to the <code class="docutils literal notranslate"><span class="pre">/api/objects</span></code> endpoint with the <code class="docutils literal notranslate"><span class="pre">db_key</span></code>
we wanted. We got back info for the newly created object. You can now make
another request with PUT (replace everything) or PATCH (replace only what you
provide). By providing the id to the endpoint (<code class="docutils literal notranslate"><span class="pre">/api/objects/214</span></code>),
we make sure to update the right sword:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">&gt;&gt;&gt; </span><span class="n">data</span> <span class="o">=</span> <span class="p">{</span><span class="s2">&quot;db_key&quot;</span><span class="p">:</span> <span class="s2">&quot;An even SHINIER sword&quot;</span><span class="p">,</span> <span class="s2">&quot;db_location&quot;</span><span class="p">:</span> <span class="mi">50</span><span class="p">}</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">response</span> <span class="o">=</span> <span class="n">requests</span><span class="o">.</span><span class="n">put</span><span class="p">(</span><span class="s2">&quot;https://www.mygame.com/api/objects/214&quot;</span><span class="p">,</span>
<span class="go"> data=data, auth=(&quot;Anotherusername&quot;, &quot;mypassword&quot;))</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">response</span><span class="o">.</span><span class="n">json</span><span class="p">()</span>
<span class="go">{&quot;db_key&quot;: &quot;An even SHINIER sword&quot;, &quot;id&quot;: 214, &quot;db_location&quot;: 50, ...}</span>
</pre></div>
</div>
<p>In most cases, you wont be making API requests to the backend with Python,
but with Javascript from some frontend application.
There are many Javascript libraries which are meant to make this process
easier for requests from the frontend, such as <a class="reference external" href="https://github.com/axios/axios">AXIOS</a>, or using
the native <a class="reference external" href="https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API">Fetch</a>.</p>
</section>
<section id="customizing-the-api">
<h2>Customizing the API<a class="headerlink" href="#customizing-the-api" title="Permalink to this headline"></a></h2>
<p>Overall, reading up on <a class="reference external" href="https://www.django-rest-framework.org/api-guide/viewsets">Django Rest Framework ViewSets</a> and
other parts of their documentation is required for expanding and
customizing the API.</p>
<p>Check out the <a class="reference internal" href="Website.html"><span class="doc">Website</span></a> page for help on how to override code, templates
and static files.</p>
<ul class="simple">
<li><p>API templates (for the web-display) is located in <code class="docutils literal notranslate"><span class="pre">evennia/web/api/templates/rest_framework/</span></code> (it must
be named such to allow override of the original REST framework templates).</p></li>
<li><p>Static files is in <code class="docutils literal notranslate"><span class="pre">evennia/web/api/static/rest_framework/</span></code></p></li>
<li><p>The api code is located in <code class="docutils literal notranslate"><span class="pre">evennia/web/api/</span></code> - the <code class="docutils literal notranslate"><span class="pre">url.py</span></code> file here is responsible for
collecting all view-classes.</p></li>
</ul>
<p>Contrary to other web components, there is no pre-made urls.py set up for
<code class="docutils literal notranslate"><span class="pre">mygame/web/api/</span></code>. This is because the registration of models with the api is
strongly integrated with the REST api functionality. Easiest is probably to
copy over <code class="docutils literal notranslate"><span class="pre">evennia/web/api/urls.py</span></code> and modify it in place.</p>
</section>
</section>
<div class="clearer"></div>
</div>
</div>
</div>
<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>
<p><h3><a href="../index.html">Table of Contents</a></h3>
<ul>
<li><a class="reference internal" href="#">Evennia REST API</a><ul>
<li><a class="reference internal" href="#usage">Usage</a></li>
<li><a class="reference internal" href="#customizing-the-api">Customizing the API</a></li>
</ul>
</li>
</ul>
<div role="note" aria-label="source link">
<!--h3>This Page</h3-->
<ul class="this-page-menu">
<li><a href="../_sources/Components/Web-API.md.txt"
rel="nofollow">Show Page Source</a></li>
</ul>
</div><h3>Links</h3>
<ul>
<li><a href="https://www.evennia.com">Home page</a> </li>
<li><a href="https://github.com/evennia/evennia">Evennia Github</a> </li>
<li><a href="http://games.evennia.com">Game Index</a> </li>
<li><a href="http://webchat.freenode.net/?channels=evennia&uio=MT1mYWxzZSY5PXRydWUmMTE9MTk1JjEyPXRydWUbb">IRC</a> -
<a href="https://discord.gg/NecFePw">Discord</a> -
<a href="https://groups.google.com/forum/#%21forum/evennia">Forums</a>
</li>
<li><a href="http://evennia.blogspot.com/">Evennia Dev blog</a> </li>
</ul>
<h3>Versions</h3>
<ul>
<li><a href="Web-API.html">1.0-dev (develop branch)</a></li>
<li><a href="../../0.9.5/index.html">0.9.5 (v0.9.5 branch)</a></li>
</ul>
</div>
</div>
<div class="clearer"></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="nav-item nav-item-0"><a href="../index.html">Evennia 1.0-dev</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">Evennia REST API</a></li>
</ul>
<div class="develop">develop branch</div>
</div>
<div class="footer" role="contentinfo">
&#169; Copyright 2020, The Evennia developer community.
Created using <a href="https://www.sphinx-doc.org/">Sphinx</a> 3.2.1.
</div>
</body>
</html>

View file

@ -0,0 +1,284 @@
<!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>The Web Admin &#8212; Evennia 1.0-dev 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" />
</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="nav-item nav-item-0"><a href="../index.html">Evennia 1.0-dev</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">The Web Admin</a></li>
</ul>
<div class="develop">develop branch</div>
</div>
<div class="document">
<div class="documentwrapper">
<div class="bodywrapper">
<div class="body" role="main">
<section id="the-web-admin">
<h1>The Web Admin<a class="headerlink" href="#the-web-admin" title="Permalink to this headline"></a></h1>
<p>The Evennia <em>Web admin</em> is a customized <a class="reference external" href="https://docs.djangoproject.com/en/3.2/ref/contrib/admin/">Django admin site</a>
used for manipulating the game database using a graphical interface. You
have to be logged into the site to use it. It then appears as an <code class="docutils literal notranslate"><span class="pre">Admin</span></code> link
the top of your website. You can also go to <a class="reference external" href="http://localhost:4001/admin">http://localhost:4001/admin</a> when
running locally.</p>
<p>Almost all actions done in the admin can also be done in-game by use of Admin-
or Builder-commands.</p>
<section id="usage">
<h2>Usage<a class="headerlink" href="#usage" title="Permalink to this headline"></a></h2>
<p>The admin is pretty self-explanatory - you can see lists of each object type,
create new instances of each type and also add new Attributes/tags them. The
admin frontpage will give a summary of all relevant entities and how they are
used.</p>
<p>There are a few use cases that requires some additional explanation though.</p>
<section id="adding-objects-to-attributes">
<h3>Adding objects to Attributes<a class="headerlink" href="#adding-objects-to-attributes" title="Permalink to this headline"></a></h3>
<p>The <code class="docutils literal notranslate"><span class="pre">value</span></code> field of an Attribute is pickled into a special form. This is usually not
something you need to worry about (the admin will pickle/unpickle) the value
for you), <em>except</em> if you want to store a database-object in an attribute. Such
objects are actually stored as a <code class="docutils literal notranslate"><span class="pre">tuple</span></code> with object-unique data.</p>
<ol>
<li><p>Find the object you want to add to the Attribute. At the bottom of the first section
youll find the field <em>Serialized string</em>. This string shows a Python tuple like</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="p">(</span><span class="s1">&#39;__packed_dbobj__&#39;</span><span class="p">,</span> <span class="p">(</span><span class="s1">&#39;objects&#39;</span><span class="p">,</span> <span class="s1">&#39;objectdb&#39;</span><span class="p">),</span> <span class="s1">&#39;2021:05:15-08:59:30:624660&#39;</span><span class="p">,</span> <span class="mi">358</span><span class="p">)</span>
</pre></div>
</div>
<p>Mark and copy this tuple-string to your clipboard exactly as it stands (parentheses and all).</p>
</li>
<li><p>Go to the entity that should have the new Attribute and create the Attribute. In its <code class="docutils literal notranslate"><span class="pre">value</span></code>
field, paste the tuple-string you copied before. Save!</p></li>
<li><p>If you want to store multiple objects in, say, a list, you can do so by literally
typing a python list <code class="docutils literal notranslate"><span class="pre">[tuple,</span> <span class="pre">tuple,</span> <span class="pre">tuple,</span> <span class="pre">...]</span></code> where you paste in the serialized
tuple-strings with commas. At some point its probably easier to do this in code though …</p></li>
</ol>
</section>
<section id="linking-accounts-and-characters">
<h3>Linking Accounts and Characters<a class="headerlink" href="#linking-accounts-and-characters" title="Permalink to this headline"></a></h3>
<p>In <code class="docutils literal notranslate"><span class="pre">MULTISESSION_MODE</span></code> 0 or 1, each connection can have one Account and one
Character, usually with the same name. Normally this is done by the user
creating a new account and logging in - a matching Character will then be
created for them. You can however also do so manually in the admin:</p>
<ol class="simple">
<li><p>First create the complete Account in the admin.</p></li>
<li><p>Next, create the Object (usually of <code class="docutils literal notranslate"><span class="pre">Character</span></code> typeclass) and name it the same
as the Account. It also needs a command-set. The default CharacterCmdset is a good bet.</p></li>
<li><p>In the <code class="docutils literal notranslate"><span class="pre">Puppeting</span> <span class="pre">Account</span></code> field, select the Account.</p></li>
<li><p>Make sure to save everything.</p></li>
<li><p>Click the <code class="docutils literal notranslate"><span class="pre">Link</span> <span class="pre">to</span> <span class="pre">Account</span></code> button (this will only work if you saved first). This will
add the needed locks and Attributes to the Account to allow them to immediately
connect to the Character when they next log in. This will (where possible):</p>
<ul class="simple">
<li><p>Set <code class="docutils literal notranslate"><span class="pre">account.db._last_puppet</span></code> to the Character.</p></li>
<li><p>Add Character to <code class="docutils literal notranslate"><span class="pre">account.db._playabel_characters</span></code> list.</p></li>
<li><p>Add/extend the <code class="docutils literal notranslate"><span class="pre">puppet:</span></code> lock on the Character to include <code class="docutils literal notranslate"><span class="pre">puppet:pid(&lt;Character.id&gt;)</span></code></p></li>
</ul>
</li>
</ol>
</section>
<section id="building-with-the-admin">
<h3>Building with the Admin<a class="headerlink" href="#building-with-the-admin" title="Permalink to this headline"></a></h3>
<p>Its possible (if probably not very practical at scale) to build and describe
rooms in the Admin.</p>
<ol class="simple">
<li><p>Create an <code class="docutils literal notranslate"><span class="pre">Object</span></code> of a Room-typeclass with a suitable room-name.</p></li>
<li><p>Set an Attribute desc on the room - the value of this Attribute is the
rooms description.</p></li>
<li><p>Add <code class="docutils literal notranslate"><span class="pre">Tags</span></code> of <code class="docutils literal notranslate"><span class="pre">type</span></code> alias to add room-aliases (no type for regular tags)</p></li>
</ol>
<p>Exits:</p>
<ol class="simple">
<li><p>Exits are <code class="docutils literal notranslate"><span class="pre">Objects</span></code> of an <code class="docutils literal notranslate"><span class="pre">Exit</span></code> typeclass, so create one.</p></li>
<li><p>The exit has <code class="docutils literal notranslate"><span class="pre">Location</span></code> of the room you just created.</p></li>
<li><p>Set <code class="docutils literal notranslate"><span class="pre">Destination</span></code> set to where the exit leads to.</p></li>
<li><p>Set a desc Attribute, this is shown if someone looks at the exit.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">Tags</span></code> of <code class="docutils literal notranslate"><span class="pre">type</span></code> alias are alternative names users can use to go through
this exit.</p></li>
</ol>
</section>
</section>
<section id="grant-others-access-to-the-admin">
<h2>Grant others access to the admin<a class="headerlink" href="#grant-others-access-to-the-admin" title="Permalink to this headline"></a></h2>
<p>The access to the admin is controlled by the <code class="docutils literal notranslate"><span class="pre">Staff</span> <span class="pre">status</span></code> flag on the
Account. Without this flag set, even superusers will not even see the admin
link on the web page. The staff-status has no in-game equivalence.</p>
<p>Only Superusers can change the <code class="docutils literal notranslate"><span class="pre">Superuser</span> <span class="pre">status</span></code> flag, and grant new
permissions to accounts. The superuser is the only permission level that is
also relevant in-game. <code class="docutils literal notranslate"><span class="pre">User</span> <span class="pre">Permissions</span></code> and <code class="docutils literal notranslate"><span class="pre">Groups</span></code> found on the <code class="docutils literal notranslate"><span class="pre">Account</span></code>
admin page <em>only</em> affects the admin - they have no connection to the in-game
<a class="reference internal" href="Permissions.html"><span class="doc">Permissions</span></a> (Player, Builder, Admin etc).</p>
<p>For a staffer with <code class="docutils literal notranslate"><span class="pre">Staff</span> <span class="pre">status</span></code> to be able to actually do anything, the
superuser must grant at least some permissions for them on their Account. This
can also be good in order to limit mistakes. It can be a good idea to not allow
the <code class="docutils literal notranslate"><span class="pre">Can</span> <span class="pre">delete</span> <span class="pre">Account</span></code> permission, for example.</p>
<div class="admonition important">
<p class="admonition-title">Important</p>
<p>If you grant staff-status and permissions to an Account and they still cannot
access the admins content, try reloading the server.</p>
</div>
<div class="admonition warning">
<p class="admonition-title">Warning</p>
<p>If a staff member has access to the in-game <code class="docutils literal notranslate"><span class="pre">py</span></code> command, they can just as
well have their admin <code class="docutils literal notranslate"><span class="pre">Superuser</span> <span class="pre">status</span></code> set too. The reason is that <code class="docutils literal notranslate"><span class="pre">py</span></code>
grants them all the power they need to set the <code class="docutils literal notranslate"><span class="pre">is_superuser</span></code> flag on their
account manually. There is a reason access to the <code class="docutils literal notranslate"><span class="pre">py</span></code> command must be
considered carefully …</p>
</div>
</section>
<section id="customizing-the-web-admin">
<h2>Customizing the web admin<a class="headerlink" href="#customizing-the-web-admin" title="Permalink to this headline"></a></h2>
<p>Customizing the admin is a big topic and something beyond the scope of this
documentation. See the <a class="reference external" href="https://docs.djangoproject.com/en/3.2/ref/contrib/admin/">official Django docs</a> for
the details. This is just a brief summary.</p>
<p>See the <a class="reference internal" href="Website.html"><span class="doc">Website</span></a> page for an overview of the components going into
generating a web page. The Django admin uses the same principle except that
Django provides a lot of tools to automate the admin-generation for us.</p>
<p>Admin templates are found in <code class="docutils literal notranslate"><span class="pre">evennia/web/templates/admin/</span></code> but youll find
this is relatively empty. This is because most of the templates are just
inherited directly from their original location in the Django package
(<code class="docutils literal notranslate"><span class="pre">django/contrib/admin/templates/</span></code>). So if you wanted to override one youd have
to copy it from <em>there</em> into your <code class="docutils literal notranslate"><span class="pre">mygame/templates/admin/</span></code> folder. Same is true
for CSS files.</p>
<p>The admin sites backend code (the views) is found in <code class="docutils literal notranslate"><span class="pre">evennia/web/admin/</span></code>. It
is organized into <code class="docutils literal notranslate"><span class="pre">admin</span></code>-classes, like <code class="docutils literal notranslate"><span class="pre">ObjectAdmin</span></code>, <code class="docutils literal notranslate"><span class="pre">AccountAdmin</span></code> etc.
These automatically use the underlying database models to generate useful views
for us without us havint go code the forms etc ourselves.</p>
<p>The top level <code class="docutils literal notranslate"><span class="pre">AdminSite</span></code> (the admin configuration referenced in django docs)
is found in <code class="docutils literal notranslate"><span class="pre">evennia/web/utils/adminsite.py</span></code>.</p>
<section id="change-the-title-of-the-admin">
<h3>Change the title of the admin<a class="headerlink" href="#change-the-title-of-the-admin" title="Permalink to this headline"></a></h3>
<p>By default the admins title is <code class="docutils literal notranslate"><span class="pre">Evennia</span> <span class="pre">web</span> <span class="pre">admin</span></code>. To change this, add the
following to your <code class="docutils literal notranslate"><span class="pre">mygame/web/urls.py</span></code>:</p>
<div class="highlight-python notranslate"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal"> 1</span>
<span class="normal"> 2</span>
<span class="normal"> 3</span>
<span class="normal"> 4</span>
<span class="normal"> 5</span>
<span class="normal"> 6</span>
<span class="normal"> 7</span>
<span class="normal"> 8</span>
<span class="normal"> 9</span>
<span class="normal">10</span></pre></div></td><td class="code"><div class="highlight"><pre><span></span><span class="c1"># in mygame/web/urls.py</span>
<span class="c1"># ...</span>
<span class="kn">from</span> <span class="nn">django.conf.admin</span> <span class="kn">import</span> <span class="n">site</span>
<span class="c1">#...</span>
<span class="n">site</span><span class="o">.</span><span class="n">site_header</span> <span class="o">=</span> <span class="s2">&quot;My great game admin&quot;</span>
</pre></div>
</td></tr></table></div>
<p>Reload the server and the admins title header will have changed.</p>
</section>
</section>
</section>
<div class="clearer"></div>
</div>
</div>
</div>
<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>
<p><h3><a href="../index.html">Table of Contents</a></h3>
<ul>
<li><a class="reference internal" href="#">The Web Admin</a><ul>
<li><a class="reference internal" href="#usage">Usage</a><ul>
<li><a class="reference internal" href="#adding-objects-to-attributes">Adding objects to Attributes</a></li>
<li><a class="reference internal" href="#linking-accounts-and-characters">Linking Accounts and Characters</a></li>
<li><a class="reference internal" href="#building-with-the-admin">Building with the Admin</a></li>
</ul>
</li>
<li><a class="reference internal" href="#grant-others-access-to-the-admin">Grant others access to the admin</a></li>
<li><a class="reference internal" href="#customizing-the-web-admin">Customizing the web admin</a><ul>
<li><a class="reference internal" href="#change-the-title-of-the-admin">Change the title of the admin</a></li>
</ul>
</li>
</ul>
</li>
</ul>
<div role="note" aria-label="source link">
<!--h3>This Page</h3-->
<ul class="this-page-menu">
<li><a href="../_sources/Components/Web-Admin.md.txt"
rel="nofollow">Show Page Source</a></li>
</ul>
</div><h3>Links</h3>
<ul>
<li><a href="https://www.evennia.com">Home page</a> </li>
<li><a href="https://github.com/evennia/evennia">Evennia Github</a> </li>
<li><a href="http://games.evennia.com">Game Index</a> </li>
<li><a href="http://webchat.freenode.net/?channels=evennia&uio=MT1mYWxzZSY5PXRydWUmMTE9MTk1JjEyPXRydWUbb">IRC</a> -
<a href="https://discord.gg/NecFePw">Discord</a> -
<a href="https://groups.google.com/forum/#%21forum/evennia">Forums</a>
</li>
<li><a href="http://evennia.blogspot.com/">Evennia Dev blog</a> </li>
</ul>
<h3>Versions</h3>
<ul>
<li><a href="Web-Admin.html">1.0-dev (develop branch)</a></li>
<li><a href="../../0.9.5/index.html">0.9.5 (v0.9.5 branch)</a></li>
</ul>
</div>
</div>
<div class="clearer"></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="nav-item nav-item-0"><a href="../index.html">Evennia 1.0-dev</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">The Web Admin</a></li>
</ul>
<div class="develop">develop branch</div>
</div>
<div class="footer" role="contentinfo">
&#169; Copyright 2020, The Evennia developer community.
Created using <a href="https://www.sphinx-doc.org/">Sphinx</a> 3.2.1.
</div>
</body>
</html>

View file

@ -6,7 +6,7 @@
<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>Webclient &#8212; Evennia 1.0-dev documentation</title>
<title>Web Client &#8212; Evennia 1.0-dev 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>
@ -28,7 +28,7 @@
<a href="../py-modindex.html" title="Python Module Index"
>modules</a> |</li>
<li class="nav-item nav-item-0"><a href="../index.html">Evennia 1.0-dev</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">Webclient</a></li>
<li class="nav-item nav-item-this"><a href="">Web Client</a></li>
</ul>
<div class="develop">develop branch</div>
</div>
@ -38,11 +38,8 @@
<div class="bodywrapper">
<div class="body" role="main">
<section id="webclient">
<h1>Webclient<a class="headerlink" href="#webclient" title="Permalink to this headline"></a></h1>
</section>
<section id="web-client">
<h1><strong>Web client</strong><a class="headerlink" href="#web-client" title="Permalink to this headline"></a></h1>
<section id="web-client">
<h1>Web Client<a class="headerlink" href="#web-client" title="Permalink to this headline"></a></h1>
<p>Evennia comes with a MUD client accessible from a normal web browser. During development you can try
it at <code class="docutils literal notranslate"><span class="pre">http://localhost:4001/webclient</span></code>. The client consists of several parts, all under
<code class="docutils literal notranslate"><span class="pre">evennia/web/webclient/</span></code>:</p>
@ -317,8 +314,7 @@ window.plugin_handler.add(&quot;myplugin&quot;, myplugin);
<script>$('#searchbox').show(0);</script>
<p><h3><a href="../index.html">Table of Contents</a></h3>
<ul>
<li><a class="reference internal" href="#">Webclient</a></li>
<li><a class="reference internal" href="#web-client"><strong>Web client</strong></a><ul>
<li><a class="reference internal" href="#">Web Client</a><ul>
<li><a class="reference internal" href="#customizing-the-web-client">Customizing the web client</a></li>
</ul>
</li>
@ -369,7 +365,7 @@ window.plugin_handler.add(&quot;myplugin&quot;, myplugin);
<a href="../py-modindex.html" title="Python Module Index"
>modules</a> |</li>
<li class="nav-item nav-item-0"><a href="../index.html">Evennia 1.0-dev</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">Webclient</a></li>
<li class="nav-item nav-item-this"><a href="">Web Client</a></li>
</ul>
<div class="develop">develop branch</div>
</div>

View file

@ -40,7 +40,75 @@
<section id="webserver">
<h1>Webserver<a class="headerlink" href="#webserver" title="Permalink to this headline"></a></h1>
<p>TODO: There is no central docs for this component yet.</p>
<p>When Evennia starts it also spins up its own Twisted-based web server. The
webserver is responsible for serving the html pages of the games website. It
can also serve static resources like images and music.</p>
<p>The webclient runs as part of the <a class="reference internal" href="Portal-And-Server.html"><span class="doc">Server</span></a> process of
Evennia. This means that it can directly access cached objects modified
in-game, and there is no risk of working with objects that are temporarily
out-of-sync in the database.</p>
<p>The webserver runs on Twisted and is meant to be used in a production
environment. It leverages the Django web framework and provides:</p>
<ul class="simple">
<li><p>A <a class="reference internal" href="Website.html"><span class="doc">Game Website</span></a> - this is what you see when you go to
<code class="docutils literal notranslate"><span class="pre">localhost:4001</span></code>. The look of the website is meant to be customized to your
game. Users logged into the website will be auto-logged into the game if they
do so with the webclient since they share the same login credentials (there
is no way to safely do auto-login with telnet clients).</p></li>
<li><p>The <a class="reference internal" href="Web-Admin.html"><span class="doc">Web Admin</span></a> is based on the Django web admin and allows you to
edit the game database in a graphical interface.</p></li>
<li><p>The <a class="reference internal" href="Webclient.html"><span class="doc">Webclient</span></a> page is served by the webserver, but the actual
game communication (sending/receiving data) is done by the javascript client
on the page opening a websocket connection directly to Evennias Portal.</p></li>
<li><p>The <a class="reference internal" href="Web-API.html"><span class="doc">Evennia REST-API</span></a> allows for accessing the database from outside the game
(only if `REST_API_ENABLED=True).</p></li>
</ul>
<section id="basic-webserver-data-flow">
<h2>Basic Webserver data flow<a class="headerlink" href="#basic-webserver-data-flow" title="Permalink to this headline"></a></h2>
<ol class="simple">
<li><p>A user enters an url in their browser (or clicks a button). This leads to
the browser sending a <em>HTTP request</em> to the server containing an url-path
(like for <code class="docutils literal notranslate"><span class="pre">https://localhost:4001/</span></code>, the part of the url we need to consider
<code class="docutils literal notranslate"><span class="pre">/</span></code>). Other possibilities would be <code class="docutils literal notranslate"><span class="pre">/admin/</span></code>, <code class="docutils literal notranslate"><span class="pre">/login/</span></code>, <code class="docutils literal notranslate"><span class="pre">/channels/</span></code> etc.</p></li>
<li><p>evennia (through Django) will make use of the regular expressions registered
in the <code class="docutils literal notranslate"><span class="pre">urls.py</span></code> file. This acts as a rerouter to <em>views</em>, which are
regular Python functions or callable classes able to process the incoming
request (think of these as similar to the right Evennia Command being
selected to handle your input - views are like Commands in this sense). In
the case of <code class="docutils literal notranslate"><span class="pre">/</span></code> we reroute to a view handling the main index-page of the
website.</p></li>
<li><p>The view code will prepare all the data needed by the web page. For the default
index page, this means gather the game statistics so you can see how many
are currently connected to the game etc.</p></li>
<li><p>The view will next fetch a <em>template</em>. A template is a HTML-document with special
placeholder tags (written as <code class="docutils literal notranslate"><span class="pre">{{...}}</span></code> or <code class="docutils literal notranslate"><span class="pre">{%</span> <span class="pre">...</span> <span class="pre">%}</span></code> usually). These
placeholders allow the view to inject dynamic content into the HTML and make
the page customized to the current situation. For the index page, it means
injecting the current player-count in the right places of the html page. This
is called rendering the template. The result is a complete HTML page.</p></li>
<li><p>(The view can also pull in a <em>form</em> to customize user-input in a similar way.)</p></li>
<li><p>The finished HTML page is packed into a <em>HTTP response</em> and returned to the
web browser, which can now display the page!</p></li>
</ol>
<section id="a-note-on-the-webclient">
<h3>A note on the webclient<a class="headerlink" href="#a-note-on-the-webclient" title="Permalink to this headline"></a></h3>
<p>The web browser can also execute code directly without talking to the Server.
This code must be written/loaded into the web page and is written using the
Javascript programming language (there is no way around this, it is what web
browsers understand). Executing Javascript is something the web browser does,
it operates independently from Evennia. Small snippets of javascript can be
used on a page to have buttons react, make small animations etc that doesnt
require the server.</p>
<p>In the case of the <a class="reference internal" href="Webclient.html"><span class="doc">Webclient</span></a>, Evennia will load the Webclient page
as above, but the page then initiates Javascript code (a lot of it) responsible
for actually displaying the client GUI, allows you to resize windows etc.</p>
<p>After it starts, the webclient calls home and spins up a
<a class="reference external" href="https://en.wikipedia.org/wiki/WebSocket">websocket</a> link to the Evennia Portal - this
is how all data is then exchanged. So after the initial loading of the
webclient page, the above sequence doesnt happen again until close the tab and
come back or you reload it manually in your browser.</p>
</section>
</section>
</section>
@ -63,6 +131,17 @@
</div>
</div>
<script>$('#searchbox').show(0);</script>
<p><h3><a href="../index.html">Table of Contents</a></h3>
<ul>
<li><a class="reference internal" href="#">Webserver</a><ul>
<li><a class="reference internal" href="#basic-webserver-data-flow">Basic Webserver data flow</a><ul>
<li><a class="reference internal" href="#a-note-on-the-webclient">A note on the webclient</a></li>
</ul>
</li>
</ul>
</li>
</ul>
<div role="note" aria-label="source link">
<!--h3>This Page</h3-->
<ul class="this-page-menu">

View file

@ -0,0 +1,542 @@
<!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>Game website &#8212; Evennia 1.0-dev 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" />
</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="nav-item nav-item-0"><a href="../index.html">Evennia 1.0-dev</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">Game website</a></li>
</ul>
<div class="develop">develop branch</div>
</div>
<div class="document">
<div class="documentwrapper">
<div class="bodywrapper">
<div class="body" role="main">
<section id="game-website">
<h1>Game website<a class="headerlink" href="#game-website" title="Permalink to this headline"></a></h1>
<p>When Evennia starts it will also start a <a class="reference internal" href="Webserver.html"><span class="doc">Webserver</span></a> as part of the
<a class="reference internal" href="Portal-And-Server.html"><span class="doc">Server</span></a> process. This uses <a class="reference external" href="https://docs.djangoproject.com">Django</a>
to present a simple but functional default game website. With the default setup,
open your browser to <a class="reference external" href="http://localhost:4001">localhost:4001</a> or <a class="reference external" href="http://127.0.0.1:4001">127.0.0.1:4001</a>
to see it.</p>
<p>The website allows existing players to log in using an account-name and
password they previously used to register with the game. If a user logs in with
the <a class="reference internal" href="Webclient.html"><span class="doc">Webclient</span></a> they will also log into the website and vice-versa.
So if you are logged into the website, opening the webclient will automatically
log you into the game as that account.</p>
<p>The default website shows a “Welcome!” page with a few links to useful
resources. It also shows some statistics about how many players are currently
connected.</p>
<p>In the top menu you can find</p>
<ul class="simple">
<li><p><em>Home</em> - Get back to front page.</p></li>
<li><p><em>Documentation</em> - A link to the latest stable Evennia documentation.</p></li>
<li><p><em>Characters</em> - This is a demo of connecting in-game characters to the website.
It will display a list of all entities of the
_typeclasses.characters.Character` typeclass and allow you to view their
description with an optional image. The list is only available to logged-in
users.</p></li>
<li><p><em>Channels</em> - This is a demo of connecting in-game chats to the website. It will
show a list of all channels available to you and allow you to view the latest
discussions. Most channels require logging in, but the <code class="docutils literal notranslate"><span class="pre">Public</span></code> channel can
also be viewed by non-loggedin users.</p></li>
<li><p><em>Help</em> - This ties the in-game <a class="reference internal" href="Help-System.html"><span class="doc">Help system</span></a> to the website. All
database-based help entries that are publicly available or accessible to your
account can be read. This is a good way to present a body of help for people
to read outside of the game.</p></li>
<li><p><em>Play Online</em> - This opens the <a class="reference internal" href="Webclient.html"><span class="doc">Webclient</span></a> in the browser.</p></li>
<li><p><em>Admin</em> The [Web admin](Web admin) will only show if you are logged in.</p></li>
<li><p><em>Log in/out</em> - Allows you to authenticate using the same credentials you use
in the game.</p></li>
<li><p><em>Register</em> - Allows you to register a new account. This is the same as
creating a new account upon first logging into the game).</p></li>
</ul>
<section id="modifying-the-default-website">
<h2>Modifying the default Website<a class="headerlink" href="#modifying-the-default-website" title="Permalink to this headline"></a></h2>
<p>You can modify and override all aspects of the web site from your game dir.
Youll mostly be doing so in your settings file
(<code class="docutils literal notranslate"><span class="pre">mygame/server/conf/settings.py</span></code> and in the gamedirs <code class="docutils literal notranslate"><span class="pre">web/folder</span></code>
(<code class="docutils literal notranslate"><span class="pre">mygame/web/</span></code> if your game folder is <code class="docutils literal notranslate"><span class="pre">mygame/</span></code>).</p>
<blockquote>
<div><p>When testing your modifications, its a good idea to add <code class="docutils literal notranslate"><span class="pre">DEBUG</span> <span class="pre">=</span> <span class="pre">True</span></code> to
your settings file. This will give you nice informative tracebacks directly
in your browser instead of generic 404 or 500 error pages. Just remember that
DEBUG mode leaks memory (for retaining debug info) and is <em>not</em> safe to use
for a production game!</p>
</div></blockquote>
<p>As explained on the <a class="reference internal" href="Webserver.html"><span class="doc">Webserver</span></a> page, the process for getting a web
page is</p>
<ol class="simple">
<li><p>Web browser sends HTTP request to server with an URL</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">urls.py</span></code> uses regex to match that URL to a <em>view</em> (a Python function or callable class).</p></li>
<li><p>The correct Python view is loaded and executes.</p></li>
<li><p>The view pulls in a <em>template</em>, a HTML document with placeholder markers in it,
and fills those in as needed (it may also use a <em>form</em> to customize user-input in the same way).
A HTML page may also in turn point to static resources (usually CSS, sometimes images etc).</p></li>
<li><p>The rendered HTML page is returned to the browser as a HTTP response. If
the HTML page requires static resources are requested, the browser will
fetch those separately before displaying it to the user.</p></li>
</ol>
<p>If you look at the <a class="reference external" href="https://github.com/evennia/evennia/blob/develop/evennia/web">evennia/web/</a> directory youll find the following
structure (leaving out stuff not relevant to the website):</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span> <span class="n">evennia</span><span class="o">/</span><span class="n">web</span><span class="o">/</span>
<span class="o">...</span>
<span class="n">static</span><span class="o">/</span>
<span class="n">website</span><span class="o">/</span>
<span class="n">css</span><span class="o">/</span>
<span class="p">(</span><span class="n">css</span> <span class="n">style</span> <span class="n">files</span><span class="p">)</span>
<span class="n">images</span><span class="o">/</span>
<span class="p">(</span><span class="n">images</span> <span class="n">to</span> <span class="n">show</span><span class="p">)</span>
<span class="n">templates</span><span class="o">/</span>
<span class="n">website</span><span class="o">/</span>
<span class="p">(</span><span class="n">html</span> <span class="n">files</span><span class="p">)</span>
<span class="n">website</span><span class="o">/</span>
<span class="n">urls</span><span class="o">.</span><span class="n">py</span>
<span class="n">views</span><span class="o">/</span>
<span class="p">(</span><span class="n">python</span> <span class="n">files</span> <span class="n">related</span> <span class="n">to</span> <span class="n">website</span><span class="p">)</span>
<span class="n">urls</span><span class="o">.</span><span class="n">py</span>
</pre></div>
</div>
<p>The top-level <code class="docutils literal notranslate"><span class="pre">web/urls.py</span></code> file includes the <code class="docutils literal notranslate"><span class="pre">web/website/urls.py</span></code> file -
that way all the website-related url-handling is kept in the same place.</p>
<p>This is the layout of the <code class="docutils literal notranslate"><span class="pre">mygame/web/</span></code> folder relevant for the website:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span> <span class="n">mygame</span><span class="o">/</span><span class="n">web</span><span class="o">/</span>
<span class="o">...</span>
<span class="n">static</span><span class="o">/</span>
<span class="n">website</span><span class="o">/</span>
<span class="n">css</span><span class="o">/</span>
<span class="n">images</span><span class="o">/</span>
<span class="n">templates</span><span class="o">/</span>
<span class="n">website</span><span class="o">/</span>
<span class="n">website</span><span class="o">/</span>
<span class="n">urls</span><span class="o">.</span><span class="n">py</span>
<span class="n">views</span><span class="o">/</span>
<span class="n">urls</span><span class="o">.</span><span class="n">py</span>
</pre></div>
</div>
<div class="versionchanged">
<p><span class="versionmodified changed">Changed in version 1.0: </span>Game folders created with older versions of Evennia will lack most of this
convenient <cite>mygame/web/</cite> layout. If you use a game dir from an older version,
you should copy over the missing <cite>evennia/game_template/web/</cite> folders from
there, as well as the main urls.py file.</p>
</div>
<p>As you can see, the <code class="docutils literal notranslate"><span class="pre">mygame/web/</span></code> folder is a copy of the <code class="docutils literal notranslate"><span class="pre">evennia/web/</span></code> folder
structure except the <code class="docutils literal notranslate"><span class="pre">mygame</span></code> folders are mostly empty.</p>
<p>For static- and template-files, Evennia will <em>first</em>
look in <code class="docutils literal notranslate"><span class="pre">mygame/static</span></code> and <code class="docutils literal notranslate"><span class="pre">mygame/templates</span></code> before going to the default
locations in <code class="docutils literal notranslate"><span class="pre">evennia/web/</span></code>. So override these resources, you just need to put
a file with the same name in the right spot under <code class="docutils literal notranslate"><span class="pre">mygame/web/</span></code> (and then
reload the server). Easiest is often to copy the original over and modify it.</p>
<p>Overridden views (Python modules) also need an additional tweak to the
<code class="docutils literal notranslate"><span class="pre">website/urls.py</span></code> file - you must make sure to repoint the url to the new
version rather than it using the original.</p>
</section>
<section id="examples-of-commom-web-changes">
<h2>Examples of commom web changes<a class="headerlink" href="#examples-of-commom-web-changes" title="Permalink to this headline"></a></h2>
<div class="admonition important">
<p class="admonition-title">Important</p>
<p>Django is a very mature web-design framework. There are endless
internet-tutorials, courses and books available to explain how to use Django.
So these examples only serve as a first primer to get you started.</p>
</div>
<section id="change-title-and-blurb">
<h3>Change Title and blurb<a class="headerlink" href="#change-title-and-blurb" title="Permalink to this headline"></a></h3>
<p>The websites title and blurb are simply changed by tweaking
<code class="docutils literal notranslate"><span class="pre">settings.SERVERNAME</span></code> and <code class="docutils literal notranslate"><span class="pre">settings.GAME_SLOGAN</span></code>. Your settings file is in
<code class="docutils literal notranslate"><span class="pre">mygame/server/conf/settings.py</span></code>, just set/add</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">SERVERNAME</span> <span class="o">=</span> <span class="s2">&quot;My Awesome Game&quot;</span>
<span class="n">GAME_SLOGAN</span> <span class="o">=</span> <span class="s2">&quot;The best game in the world&quot;</span>
</pre></div>
</div>
</section>
<section id="change-the-logo">
<h3>Change the Logo<a class="headerlink" href="#change-the-logo" title="Permalink to this headline"></a></h3>
<p>The Evennia googly-eyed snake logo is probably not what you want for your game.
The template looks for a file <code class="docutils literal notranslate"><span class="pre">web/static/website/images/evennia_logo.png</span></code>. Just
plop your own PNG logo (64x64 pixels large) in there and name it the same.</p>
</section>
<section id="change-front-page-html">
<h3>Change front page HTML<a class="headerlink" href="#change-front-page-html" title="Permalink to this headline"></a></h3>
<p>The front page of the website is usually referred to as the index in HTML
parlance.</p>
<p>The frontpage template is found in <code class="docutils literal notranslate"><span class="pre">evennia/web/templates/website/index.html</span></code>.
Just copy this to the equivalent place in <code class="docutils literal notranslate"><span class="pre">mygame/web/</span></code>. Modify it there and
reload the server to see your changes.</p>
<p>Django templates has a few special features that separate them from normal HTML
documents - they contain a special templating language marked with <code class="docutils literal notranslate"><span class="pre">{%</span> <span class="pre">...</span> <span class="pre">%}</span></code> and
<code class="docutils literal notranslate"><span class="pre">{{</span> <span class="pre">...</span> <span class="pre">}}</span></code>.</p>
<p>Some important things to know:</p>
<ul class="simple">
<li><p><code class="docutils literal notranslate"><span class="pre">{%</span> <span class="pre">extends</span> <span class="pre">&quot;base.html&quot;</span> <span class="pre">%}</span></code> - This is equivalent to a Python
<code class="docutils literal notranslate"><span class="pre">from</span> <span class="pre">othermodule</span> <span class="pre">import</span> <span class="pre">*</span></code> statement, but for templates. It allows a given template
to use everything from the imported (extended) template, but also to override anything
it wants to change. This makes it easy to keep all pages looking the same and avoids
a lot of boiler plate.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">{%</span> <span class="pre">block</span> <span class="pre">blockname</span> <span class="pre">%}...{%</span> <span class="pre">endblock</span> <span class="pre">%}</span></code> - Blocks are inheritable, named pieces of code
that are modified in one place and then used elsewhere. This works a bit in reverse to
normal inheritance, because its commonly in such a way that <code class="docutils literal notranslate"><span class="pre">base.html</span></code> defines an empty
block, lets say <code class="docutils literal notranslate"><span class="pre">contents</span></code>: <code class="docutils literal notranslate"><span class="pre">{%</span> <span class="pre">block</span> <span class="pre">contents</span> <span class="pre">%}{%</span> <span class="pre">endblock</span> <span class="pre">%}</span></code> but makes sure to put
that <em>in the right place</em>, say in the main body, next to the sidebar etc. Then each page
does <code class="docutils literal notranslate"><span class="pre">{%</span> <span class="pre">extends</span> <span class="pre">&quot;base.html</span> <span class="pre">%&quot;}</span></code> and makes their own <code class="docutils literal notranslate"><span class="pre">{%</span> <span class="pre">block</span> <span class="pre">contents}</span> <span class="pre">&lt;actual</span> <span class="pre">content&gt;</span> <span class="pre">{%</span> <span class="pre">endblock</span> <span class="pre">%}</span></code>.
Their <code class="docutils literal notranslate"><span class="pre">contents</span></code> block will now override the empty one in <code class="docutils literal notranslate"><span class="pre">base.html</span></code> and appear in the right
place in the document, without the extending template having to specifying everything else
around it!</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">{{</span> <span class="pre">...</span> <span class="pre">}}</span></code> are slots usually embedded inside HTML tags or content. They reference a
<em>context</em> (basically a dict) that the Python <em>view</em> makes available to it.
Keys on the context are accessed with dot-notation, so if you provide a
context <code class="docutils literal notranslate"><span class="pre">{&quot;stats&quot;:</span> <span class="pre">{&quot;hp&quot;:</span> <span class="pre">10,</span> <span class="pre">&quot;mp&quot;:</span> <span class="pre">5}}</span></code> to your template, you could access
that as <code class="docutils literal notranslate"><span class="pre">{{</span> <span class="pre">stats.hp</span> <span class="pre">}}</span></code> to display <code class="docutils literal notranslate"><span class="pre">10</span></code> at that location to display <code class="docutils literal notranslate"><span class="pre">10</span></code> at
that location.</p></li>
</ul>
<p>This allows for template inheritance (making it easier to make all
pages look the same without rewriting the same thing over and over)</p>
<p>Theres a lot more information to be found in the <a class="reference external" href="https://docs.djangoproject.com/en/3.2/ref/templates/language/">Django template language documentation</a>.</p>
</section>
<section id="change-webpage-colors-and-styling">
<h3>Change webpage colors and styling<a class="headerlink" href="#change-webpage-colors-and-styling" title="Permalink to this headline"></a></h3>
<p>You can tweak the <a class="reference external" href="https://en.wikipedia.org/wiki/Cascading_Style_Sheets">CSS</a> of the entire
website. If you investigate the <code class="docutils literal notranslate"><span class="pre">evennia/web/templates/website/base.html</span></code> file youll see that we
use the <a class="reference external" href="https://getbootstrap.com/docs/4.6/getting-started/introduction/">Bootstrap
4</a> toolkit.</p>
<p>Much structural HTML functionality is actually coming from bootstrap, so you
will often be able to just add bootstrap CSS classes to elements in the HTML
file to get various effects like text-centering or similar.</p>
<p>The websites custom CSS is found in
<code class="docutils literal notranslate"><span class="pre">evennia/web/static/website/css/website.css</span></code> but we also look for a (currently
empty) <code class="docutils literal notranslate"><span class="pre">custom.css</span></code> in the same location. You can override either, but it may
be easier to revert your changes if you only add things to <code class="docutils literal notranslate"><span class="pre">custom.css</span></code>.</p>
<p>Copy the CSS file you want to modify to the corresponding location in <code class="docutils literal notranslate"><span class="pre">mygame/web</span></code>.
Modify it and reload the server to see your changes.</p>
<p>You can also apply static files without reloading, but running this in the
terminal:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">evennia</span> <span class="n">collectstatic</span> <span class="o">--</span><span class="n">no</span><span class="o">-</span><span class="nb">input</span>
</pre></div>
</div>
<p>(this is run automatically when reloading the server).</p>
<blockquote>
<div><p>Note that before you see new CSS files applied you may need to refresh your
browser without cache (Ctrl-F5 in Firefox, for example).</p>
</div></blockquote>
<p>As an example, add/copy <code class="docutils literal notranslate"><span class="pre">custom.css</span></code> to <code class="docutils literal notranslate"><span class="pre">mygame/web/static/website/css/</span></code> and
add the following:</p>
<div class="highlight-css notranslate"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal">1</span>
<span class="normal">2</span>
<span class="normal">3</span>
<span class="normal">4</span>
<span class="normal">5</span>
<span class="normal">6</span>
<span class="normal">7</span></pre></div></td><td class="code"><div class="highlight"><pre><span></span><span class="p">.</span><span class="nc">navbar</span> <span class="p">{</span>
<span class="k">background-color</span><span class="p">:</span> <span class="mh">#7a3d54</span><span class="p">;</span>
<span class="p">}</span>
<span class="p">.</span><span class="nc">footer</span> <span class="p">{</span>
<span class="k">background-color</span><span class="p">:</span> <span class="mh">#7a3d54</span><span class="p">;</span>
<span class="p">}</span>
</pre></div>
</td></tr></table></div>
<p>Reload and your website now has a red theme!</p>
<blockquote>
<div><p>Hint: Learn to use your web browsers <a class="reference external" href="https://torquemag.io/2020/06/browser-developer-tools-tutorial/">Developer tools</a>.
These allow you to tweak CSS live to find a look you like and copy it into
the .css file only when you want to make the changes permanent.</p>
</div></blockquote>
</section>
<section id="change-front-page-functionality">
<h3>Change front page functionality<a class="headerlink" href="#change-front-page-functionality" title="Permalink to this headline"></a></h3>
<p>The logic is all in the view. To find where the index-page view is found, we
look in <code class="docutils literal notranslate"><span class="pre">evennia/web/website/urls.py</span></code>. Here we find the following line:</p>
<div class="highlight-python notranslate"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal">1</span>
<span class="normal">2</span>
<span class="normal">3</span>
<span class="normal">4</span>
<span class="normal">5</span>
<span class="normal">6</span></pre></div></td><td class="code"><div class="highlight"><pre><span></span><span class="c1"># in evennia/web/website/urls.py</span>
<span class="o">...</span>
<span class="c1"># website front page</span>
<span class="n">path</span><span class="p">(</span><span class="s2">&quot;&quot;</span><span class="p">,</span> <span class="n">index</span><span class="o">.</span><span class="n">EvenniaIndexView</span><span class="o">.</span><span class="n">as_view</span><span class="p">(),</span> <span class="n">name</span><span class="o">=</span><span class="s2">&quot;index&quot;</span><span class="p">),</span>
<span class="o">...</span>
</pre></div>
</td></tr></table></div>
<p>The first <code class="docutils literal notranslate"><span class="pre">&quot;&quot;</span></code> is the empty url - root - what you get if you just enter <code class="docutils literal notranslate"><span class="pre">localhost:4001/</span></code>
with no extra path. As expected, this leads to the index page. By looking at the imports
we find the view is in in <code class="docutils literal notranslate"><span class="pre">evennia/web/website/views/index.py</span></code>.</p>
<p>Copy this file to the corresponding location in <code class="docutils literal notranslate"><span class="pre">mygame/web</span></code>. Then tweak your <code class="docutils literal notranslate"><span class="pre">mygame/web/website/urls.py</span></code>
file to point to the new file:</p>
<div class="highlight-python notranslate"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal"> 1</span>
<span class="normal"> 2</span>
<span class="normal"> 3</span>
<span class="normal"> 4</span>
<span class="normal"> 5</span>
<span class="normal"> 6</span>
<span class="normal"> 7</span>
<span class="normal"> 8</span>
<span class="normal"> 9</span>
<span class="normal">10</span>
<span class="normal">11</span></pre></div></td><td class="code"><div class="highlight"><pre><span></span><span class="c1"># in mygame/web/website/urls.py</span>
<span class="c1"># ...</span>
<span class="kn">from</span> <span class="nn">web.website.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="s2">&quot;&quot;</span><span class="p">,</span> <span class="n">index</span><span class="o">.</span><span class="n">EvenniaIndexView</span><span class="o">.</span><span class="n">as_view</span><span class="p">(),</span> <span class="n">name</span><span class="o">=</span><span class="s2">&quot;index&quot;</span><span class="p">)</span>
<span class="p">]</span>
<span class="c1"># ...</span>
</pre></div>
</td></tr></table></div>
<p>So we just import <code class="docutils literal notranslate"><span class="pre">index</span></code> from the new location and point to it. After a reload
the front page will now redirect to use your copy rather than the original.</p>
<p>The frontpage view is a class <code class="docutils literal notranslate"><span class="pre">EvenniaIndexView</span></code>. This is a <a class="reference external" href="https://docs.djangoproject.com/en/3.2/topics/class-based-views/">Django class-based view</a>.
Its a little less visible what happens in a class-based view than in a function (since
the class implements a lot of functionality as methods), but its powerful and
much easier to extend/modify.</p>
<p>The class property <code class="docutils literal notranslate"><span class="pre">template_name</span></code> sets the location of the template used under
the <code class="docutils literal notranslate"><span class="pre">templates/</span></code> folder. So <code class="docutils literal notranslate"><span class="pre">website/index.html</span></code> points to
<code class="docutils literal notranslate"><span class="pre">web/templates/website/index.html</span></code> (as we already explored above.</p>
<p>The <code class="docutils literal notranslate"><span class="pre">get_context_data</span></code> is a convenient method for providing the context for the
template. In the index-pages case we want the game stats (number of recent
players etc). These are then made available to use in <code class="docutils literal notranslate"><span class="pre">{{</span> <span class="pre">...</span> <span class="pre">}}</span></code> slots in the
template as described in the previous section.</p>
</section>
<section id="change-other-website-pages">
<h3>Change other website pages<a class="headerlink" href="#change-other-website-pages" title="Permalink to this headline"></a></h3>
<p>The other sub pages are handled in the same way - copy the template or static
resource to the right place, or copy the view and repoint your <code class="docutils literal notranslate"><span class="pre">website/urls.py</span></code> to
your copy. Just remember to reload.</p>
</section>
</section>
<section id="adding-a-new-web-page">
<h2>Adding a new web page<a class="headerlink" href="#adding-a-new-web-page" title="Permalink to this headline"></a></h2>
<section id="using-flat-pages">
<h3>Using Flat Pages<a class="headerlink" href="#using-flat-pages" title="Permalink to this headline"></a></h3>
<p>The absolutely simplest way to add a new web page is to use the <code class="docutils literal notranslate"><span class="pre">Flat</span> <span class="pre">Pages</span></code>
app available in the <a class="reference internal" href="Web-Admin.html"><span class="doc">Web Admin</span></a>. The page will appear with the same
styling as the rest of the site.</p>
<p>For the <code class="docutils literal notranslate"><span class="pre">Flat</span> <span class="pre">pages</span></code> module to work you must first set up a <em>Site</em> (or
domain) to use. You only need to this once.</p>
<ul class="simple">
<li><p>Go to the Web admin and select <code class="docutils literal notranslate"><span class="pre">Sites</span></code>. If your
game is at <code class="docutils literal notranslate"><span class="pre">mygreatgame.com</span></code>, thats the domain you need to add. For local
experimentation, add the domain <code class="docutils literal notranslate"><span class="pre">localhost:4001</span></code>. Note the <code class="docutils literal notranslate"><span class="pre">id</span></code> of the domain
(look at the url when you click on the new domain, if its for example
<code class="docutils literal notranslate"><span class="pre">http://localhost:4001/admin/sites/site/2/change/</span></code>, then the id is <code class="docutils literal notranslate"><span class="pre">2</span></code>).</p></li>
<li><p>Now add the line <code class="docutils literal notranslate"><span class="pre">SITE_ID</span> <span class="pre">=</span> <span class="pre">&lt;id&gt;</span></code> to your settings file.</p></li>
</ul>
<p>Next you create new pages easily.</p>
<ul class="simple">
<li><p>Go the <code class="docutils literal notranslate"><span class="pre">Flat</span> <span class="pre">Pages</span></code> web admin and choose to add a new flat page.</p></li>
<li><p>Set the url. If you want the page to appear as e.g. <code class="docutils literal notranslate"><span class="pre">localhost:4001/test/</span></code>, then
add <code class="docutils literal notranslate"><span class="pre">/test/</span></code> here. You need to add both leading and trailing slashes.</p></li>
<li><p>Set <code class="docutils literal notranslate"><span class="pre">Title</span></code> to the name of the page.</p></li>
<li><p>The <code class="docutils literal notranslate"><span class="pre">Content</span></code> is the HTML content of the body of the page. Go wild!</p></li>
<li><p>Finally pick the <code class="docutils literal notranslate"><span class="pre">Site</span></code> you made before, and save.</p></li>
<li><p>(in the advanced section you can make it so that you have to login to see the page etc).</p></li>
</ul>
<p>You can now go to <code class="docutils literal notranslate"><span class="pre">localhost:4001/test/</span></code> and see your new page!</p>
</section>
<section id="add-custom-new-page">
<h3>Add Custom new page<a class="headerlink" href="#add-custom-new-page" title="Permalink to this headline"></a></h3>
<p>The <code class="docutils literal notranslate"><span class="pre">Flat</span> <span class="pre">Pages</span></code> page doesnt allow for (much) dynamic content and customization. For
this you need to add the needed components yourself.</p>
<p>Lets see how to make a <code class="docutils literal notranslate"><span class="pre">/test/</span></code> page from scratch.</p>
<ul>
<li><p>Add a new <code class="docutils literal notranslate"><span class="pre">test.html</span></code> file under <code class="docutils literal notranslate"><span class="pre">mygame/web/templates/website/</span></code>. Easiest is to base
this off an existing file. Make sure to <code class="docutils literal notranslate"><span class="pre">{%</span> <span class="pre">extend</span> <span class="pre">base.html</span> <span class="pre">%}</span></code> if you want to
get the same styling as the rest of your site.</p></li>
<li><p>Add a new view <code class="docutils literal notranslate"><span class="pre">testview.py</span></code> under <code class="docutils literal notranslate"><span class="pre">mygame/web/website/views/</span></code> (dont name it <code class="docutils literal notranslate"><span class="pre">test.py</span></code> or
Django/Evennia will think it contains unit tests). Add a view there to process
your page. This is a minimal view to start from (read much more <a class="reference external" href="https://docs.djangoproject.com/en/3.2/topics/class-based-views/">in the Django docs</a>):</p>
<div class="highlight-python notranslate"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal">1</span>
<span class="normal">2</span>
<span class="normal">3</span>
<span class="normal">4</span>
<span class="normal">5</span>
<span class="normal">6</span>
<span class="normal">7</span></pre></div></td><td class="code"><div class="highlight"><pre><span></span><span class="c1"># mygame/web/website/views/testview.py</span>
<span class="kn">from</span> <span class="nn">django.views.generic</span> <span class="kn">import</span> <span class="n">TemplateView</span>
<span class="k">class</span> <span class="nc">MyTestView</span><span class="p">(</span><span class="n">TemplateView</span><span class="p">):</span>
<span class="n">template_name</span> <span class="o">=</span> <span class="s2">&quot;website/test.html&quot;</span>
</pre></div>
</td></tr></table></div>
</li>
<li><p>Finally, point to your view from the <code class="docutils literal notranslate"><span class="pre">mygame/web/website/urls.py</span></code>:</p>
<div class="highlight-python notranslate"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal"> 1</span>
<span class="normal"> 2</span>
<span class="normal"> 3</span>
<span class="normal"> 4</span>
<span class="normal"> 5</span>
<span class="normal"> 6</span>
<span class="normal"> 7</span>
<span class="normal"> 8</span>
<span class="normal"> 9</span>
<span class="normal">10</span></pre></div></td><td class="code"><div class="highlight"><pre><span></span><span class="c1"># in mygame/web/website/urls.py</span>
<span class="c1"># ...</span>
<span class="kn">from</span> <span class="nn">web.website.views</span> <span class="kn">import</span> <span class="n">testview</span>
<span class="n">urlpatterns</span> <span class="o">=</span> <span class="p">[</span>
<span class="c1"># ...</span>
<span class="c1"># we can skip the initial / here</span>
<span class="n">path</span><span class="p">(</span><span class="s2">&quot;test/&quot;</span><span class="p">,</span> <span class="n">testview</span><span class="o">.</span><span class="n">MyTestView</span><span class="o">.</span><span class="n">as_view</span><span class="p">())</span>
<span class="p">]</span>
</pre></div>
</td></tr></table></div>
</li>
<li><p>Reload the server and your new page is available. You can now continue to add
all sorts of advanced dynamic content through your view and template!</p></li>
</ul>
</section>
</section>
<section id="user-forms">
<h2>User forms<a class="headerlink" href="#user-forms" title="Permalink to this headline"></a></h2>
<p>All the pages created so far deal with <em>presenting</em> information to the user.
Its also possible for the user to <em>input</em> data on the page through <em>forms</em>. An
example would be a page of fields and sliders you fill in to create a
character, with a big Submit button at the bottom.</p>
<p>Firstly, this must be represented in HTML. The <code class="docutils literal notranslate"><span class="pre">&lt;form&gt;</span> <span class="pre">...</span> <span class="pre">&lt;/form&gt;</span></code> is a
standard HTML element you need to add to your template. It also has some other
requirements, such as <code class="docutils literal notranslate"><span class="pre">&lt;input&gt;</span></code> and often Javascript components as well (but
usually Django will help with this). If you are unfamiliar with how HTML forms
work, <a class="reference external" href="https://docs.djangoproject.com/en/3.2/topics/forms/#html-forms">read about them here</a>.</p>
<p>The basic gist of it is that when you click to submit the form, a POST HTML
request will be sent to the server containing the data the user entered. Its
now up to the server to make sure the data makes sense (validation) and then
process the input somehow (like creating a new character).</p>
<p>On the backend side, we need to specify the logic for validating and processing
the form data. This is done by the <code class="docutils literal notranslate"><span class="pre">Form</span></code> <a class="reference external" href="https://docs.djangoproject.com/en/3.2/topics/forms/#forms-in-django">Django class</a>.
This specifies <em>fields</em> on itself that define how to validate that piece of data.</p>
<p>The form is then linked into the view-class by adding <code class="docutils literal notranslate"><span class="pre">form_class</span> <span class="pre">=</span> <span class="pre">MyFormClass</span></code> to
the view (next to <code class="docutils literal notranslate"><span class="pre">template_name</span></code>).</p>
<p>There are several example forms in <code class="docutils literal notranslate"><span class="pre">evennia/web/website/forms.py</span></code>. Its also a good
idea to read <a class="reference external" href="https://docs.djangoproject.com/en/3.2/topics/forms/#building-a-form-in-django">Building a form in Django</a>
on the Django website - it covers all you need.</p>
</section>
</section>
<div class="clearer"></div>
</div>
</div>
</div>
<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>
<p><h3><a href="../index.html">Table of Contents</a></h3>
<ul>
<li><a class="reference internal" href="#">Game website</a><ul>
<li><a class="reference internal" href="#modifying-the-default-website">Modifying the default Website</a></li>
<li><a class="reference internal" href="#examples-of-commom-web-changes">Examples of commom web changes</a><ul>
<li><a class="reference internal" href="#change-title-and-blurb">Change Title and blurb</a></li>
<li><a class="reference internal" href="#change-the-logo">Change the Logo</a></li>
<li><a class="reference internal" href="#change-front-page-html">Change front page HTML</a></li>
<li><a class="reference internal" href="#change-webpage-colors-and-styling">Change webpage colors and styling</a></li>
<li><a class="reference internal" href="#change-front-page-functionality">Change front page functionality</a></li>
<li><a class="reference internal" href="#change-other-website-pages">Change other website pages</a></li>
</ul>
</li>
<li><a class="reference internal" href="#adding-a-new-web-page">Adding a new web page</a><ul>
<li><a class="reference internal" href="#using-flat-pages">Using Flat Pages</a></li>
<li><a class="reference internal" href="#add-custom-new-page">Add Custom new page</a></li>
</ul>
</li>
<li><a class="reference internal" href="#user-forms">User forms</a></li>
</ul>
</li>
</ul>
<div role="note" aria-label="source link">
<!--h3>This Page</h3-->
<ul class="this-page-menu">
<li><a href="../_sources/Components/Website.md.txt"
rel="nofollow">Show Page Source</a></li>
</ul>
</div><h3>Links</h3>
<ul>
<li><a href="https://www.evennia.com">Home page</a> </li>
<li><a href="https://github.com/evennia/evennia">Evennia Github</a> </li>
<li><a href="http://games.evennia.com">Game Index</a> </li>
<li><a href="http://webchat.freenode.net/?channels=evennia&uio=MT1mYWxzZSY5PXRydWUmMTE9MTk1JjEyPXRydWUbb">IRC</a> -
<a href="https://discord.gg/NecFePw">Discord</a> -
<a href="https://groups.google.com/forum/#%21forum/evennia">Forums</a>
</li>
<li><a href="http://evennia.blogspot.com/">Evennia Dev blog</a> </li>
</ul>
<h3>Versions</h3>
<ul>
<li><a href="Website.html">1.0-dev (develop branch)</a></li>
<li><a href="../../0.9.5/index.html">0.9.5 (v0.9.5 branch)</a></li>
</ul>
</div>
</div>
<div class="clearer"></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="nav-item nav-item-0"><a href="../index.html">Evennia 1.0-dev</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">Game website</a></li>
</ul>
<div class="develop">develop branch</div>
</div>
<div class="footer" role="contentinfo">
&#169; Copyright 2020, The Evennia developer community.
Created using <a href="https://www.sphinx-doc.org/">Sphinx</a> 3.2.1.
</div>
</body>
</html>