-
-

Help System Tutorial

-

Before doing this tutorial you will probably want to read the intro in [Basic Web tutorial](Web- Tutorial). Reading the three first parts of the Django tutorial might help as well.

-

This tutorial will show you how to access the help system through your website. Both help commands -and regular help entries will be visible, depending on the logged-in user or an anonymous character.

+
+

Web Help System Tutorial

+

Before doing this tutorial you will probably want to read the intro in the Changing the Web page tutorial. Reading the three first parts of the Django tutorial might help as well.

+

This tutorial will show you how to access the help system through your website. Both help commands and regular help entries will be visible, depending on the logged-in user or an anonymous character.

This tutorial will show you how to:

  • Create a new page to add to your website.

  • @@ -142,23 +141,16 @@ and regular help entries will be visible, depending on the logged-in user or an

Creating our app

-

The first step is to create our new Django app. An app in Django can contain pages and -mechanisms: your website may contain different apps. Actually, the website provided out-of-the-box -by Evennia has already three apps: a “webclient” app, to handle the entire webclient, a “website” -app to contain your basic pages, and a third app provided by Django to create a simple admin -interface. So we’ll create another app in parallel, giving it a clear name to represent our help -system.

-

From your game directory, use the following command:

-
evennia startapp help_system
+

The first step is to create our new Django app. An app in Django can contain pages and mechanisms: your website may contain different apps. Actually, the website provided out-of-the-box by Evennia has already three apps: a “webclient” app, to handle the entire webclient, a “website” app to contain your basic pages, and a third app provided by Django to create a simple admin interface. So we’ll create another app in parallel, giving it a clear name to represent our help system.

+

From your game directory, use the following commands:

+
cd web 
+evennia startapp help_system
 
-

Note: calling the app “help” would have been more explicit, but this name is already used by -Django.

+

Note: calling the app “help” would have been more explicit, but this name is already used by Django.

-

This will create a directory named help_system at the root of your game directory. It’s a good -idea to keep things organized and move this directory in the “web” directory of your game. Your -game directory should look like:

+

This will create a directory named help_system under mygame/web/. We put it there to keep all web-related things together, but you can organize however you like. Here’s how the structure looks:

mygame/
     ...
     web/
@@ -166,42 +158,32 @@ game directory should look like:

...
-

The “web/help_system” directory contains files created by Django. We’ll use some of them, but if -you want to learn more about them all, you should read the Django -tutorial.

-

There is a last thing to be done: your folder has been added, but Django doesn’t know about it, it -doesn’t know it’s a new app. We need to tell it, and we do so by editing a simple setting. Open -your “server/conf/settings.py” file and add, or edit, these lines:

+

The “web/help_system” directory contains files created by Django. We’ll use some of them, but if you want to learn more about them all, you should read the Django tutorial.

+

There is a last thing to be done: your folder has been added, but Django doesn’t know about it, it doesn’t know it’s a new app. We need to tell it, and we do so by editing a simple setting. Open your “server/conf/settings.py” file and add, or edit, these lines:

# Web configuration
 INSTALLED_APPS += (
         "web.help_system",
 )
 
-

You can start Evennia if you want, and go to your website, probably at -http://localhost:4001 . You won’t see anything different though: we added -the app but it’s fairly empty.

+

You can start Evennia if you want, and go to your website, probably at http://localhost:4001 . You won’t see anything different though: we added the app but it’s fairly empty.

Our new page

-

At this point, our new app contains mostly empty files that you can explore. In order to create -a page for our help system, we need to add:

+

At this point, our new app contains mostly empty files that you can explore. In order to create a page for our help system, we need to add:

  • A view, dealing with the logic of our page.

  • A template to display our new page.

  • A new URL pointing to our page.

-

We could get away by creating just a view and a new URL, but that’s not a recommended way to work -with your website. Building on templates is so much more convenient.

+

We could get away by creating just a view and a new URL, but that’s not a recommended way to work with your website. Building on templates is so much more convenient.

Create a view

A view in Django is a simple Python function placed in the “views.py” file in your app. It will -handle the behavior that is triggered when a user asks for this information by entering a URL (the -connection between views and URLs will be discussed later).

-

So let’s create our view. You can open the “web/help_system/views.py” file and paste the following -lines:

+handle the behavior that is triggered when a user asks for this information by entering a URL (the connection between views and URLs will be discussed later).

+

So let’s create our view. You can open the “web/help_system/views.py” file and paste the following lines:

from django.shortcuts import render
 
 def index(request):
@@ -209,16 +191,11 @@ lines:

return render(request, "help_system/index.html")
-

Our view handles all code logic. This time, there’s not much: when this function is called, it will -render the template we will now create. But that’s where we will do most of our work afterward.

+

Our view handles all code logic. This time, there’s not much: when this function is called, it will render the template we will now create. But that’s where we will do most of our work afterward.

Create a template

-

The render function called into our view asks the template help_system/index.html. The -templates of our apps are stored in the app directory, “templates” sub-directory. Django may have -created the “templates” folder already. If not, create it yourself. In it, create another folder -“help_system”, and inside of this folder, create a file named “index.html”. Wow, that’s some -hierarchy. Your directory structure (starting from web) should look like this:

+

The render function called into our view asks the template help_system/index.html. The templates of our apps are stored in the app directory, “templates” sub-directory. Django may have created the “templates” folder already. If not, create it yourself. In it, create another folder “help_system”, and inside of this folder, create a file named “index.html”. Wow, that’s some hierarchy. Your directory structure (starting from web) should look like this:

web/
     help_system/
         ...
@@ -237,24 +214,17 @@ hierarchy.  Your directory structure (starting from 
-
  • It loads the “base.html” template. This describes the basic structure of all your pages, with -a menu at the top and a footer, and perhaps other information like images and things to be present -on each page. You can create templates that do not inherit from “base.html”, but you should have a -good reason for doing so.

  • -
  • The “base.html” template defines all the structure of the page. What is left is to override -some sections of our pages. These sections are called blocks. On line 2, we override the block -named “blocktitle”, which contains the title of our page.

  • -
  • Same thing here, we override the block named “content”, which contains the main content of our -web page. This block is bigger, so we define it on several lines.

  • +
  • It loads the “base.html” template. This describes the basic structure of all your pages, with a menu at the top and a footer, and perhaps other information like images and things to be present on each page. You can create templates that do not inherit from “base.html”, but you should have a good reason for doing so.

  • +
  • The “base.html” template defines all the structure of the page. What is left is to override some sections of our pages. These sections are called blocks. On line 2, we override the block named “blocktitle”, which contains the title of our page.

  • +
  • Same thing here, we override the block named “content”, which contains the main content of our web page. This block is bigger, so we define it on several lines.

  • This is perfectly normal HTML code to display a level-2 heading.

  • And finally we close the block named “content”.

  • Create a new URL

    -

    Last step to add our page: we need to add a URL leading to it… otherwise users won’t be able to -access it. The URLs of our apps are stored in the app’s directory “urls.py” file.

    -

    Open the web/help_system/urls.py file (you might have to create it) and make it look like this.

    +

    Last step to add our page: we need to add a URL leading to it… otherwise users won’t be able to access it. The URLs of our apps are stored in the app’s directory “urls.py” file.

    +

    Open the web/help_system/urls.py file (you might have to create it) and make it look like this:

    # URL patterns for the help_system app
     
     from django.urls import path
    @@ -265,12 +235,8 @@ access it.  The URLs of our apps are stored in the app’s directory “]
     
    -

    The urlpatterns variable is what Django/Evennia looks for to figure out how to -direct a user entering an URL in their browser to the view-code you have -written.

    -

    Last we need to tie this into the main namespace for your game. Edit the file -mygame/web/urls.py. In it you will find the urlpatterns list again. -Add a new path to the end of the list.

    +

    The urlpatterns variable is what Django/Evennia looks for to figure out how to direct a user entering an URL in their browser to the view-code you have written.

    +

    Last we need to tie this into the main namespace for your game. Edit the file mygame/web/urls.py. In it you will find the urlpatterns list again. Add a new path to the end of the list.

    # mygame/web/urls.py
     # [...]
     
    @@ -292,21 +258,14 @@ Add a new path
     

    When a user will ask for a specific URL on your site, Django will:

      -
    1. Read the list of custom patterns defined in “web/urls.py”. There’s one pattern here, which -describes to Django that all URLs beginning by ‘help/’ should be sent to the ‘help_system’ app. The -‘help/’ part is removed.

    2. -
    3. Then Django will check the “web.help_system/urls.py” file. It contains only one URL, which is -empty (^$).

    4. +
    5. Read the list of custom patterns defined in “web/urls.py”. There’s one pattern here, which describes to Django that all URLs beginning by ‘help/’ should be sent to the ‘help_system’ app. The ‘help/’ part is removed.

    6. +
    7. Then Django will check the “web.help_system/urls.py” file. It contains only one URL, which is empty (^$).

    In other words, if the URL is ‘/help/’, then Django will execute our defined view.

    Let’s see it work

    -

    You can now reload or start Evennia. Open a tab in your browser and go to -http://localhost:4001/help/ . If everything goes well, you should -see your new page… which isn’t empty since Evennia uses our “base.html” template. In the -content of our page, there’s only a heading that reads “help index”. Notice that the title of our -page is “mygame - Help index” (“mygame” is replaced by the name of your game).

    +

    You can now reload or start Evennia. Open a tab in your browser and go to http://localhost:4001/help/ . If everything goes well, you should see your new page… which isn’t empty since Evennia uses our “base.html” template. In the content of our page, there’s only a heading that reads “help index”. Notice that the title of our page is “mygame - Help index” (“mygame” is replaced by the name of your game).

    From now on, it will be easier to move forward and add features.

    @@ -325,30 +284,17 @@ page is “mygame - Help index” (“mygame” is replaced by the name of your

    Should we create two URLs?

    -

    The answer is… maybe. It depends on what you want to do. We have our help index accessible -through the “/help/” URL. We could have the detail of a help entry accessible through “/help/desc” -(to see the detail of the “desc” command). The problem is that our commands or help topics may -contain special characters that aren’t to be present in URLs. There are different ways around this -problem. I have decided to use a GET variable here, which would create URLs like this:

    +

    The answer is… maybe. It depends on what you want to do. We have our help index accessible through the “/help/” URL. We could have the detail of a help entry accessible through “/help/desc” (to see the detail of the “desc” command). The problem is that our commands or help topics may contain special characters that aren’t to be present in URLs. There are different ways around this problem. I have decided to use a GET variable here, which would create URLs like this:

    /help?name=desc
     
    -

    If you use this system, you don’t have to add a new URL: GET and POST variables are accessible -through our requests and we’ll see how soon enough.

    +

    If you use this system, you don’t have to add a new URL: GET and POST variables are accessible through our requests and we’ll see how soon enough.

    Handling logged-in users

    -

    One of our requirements is to have a help system tailored to our accounts. If an account with admin -access logs in, the page should display a lot of commands that aren’t accessible to common users. -And perhaps even some additional help topics.

    -

    Fortunately, it’s fairly easy to get the logged in account in our view (remember that we’ll do most -of our coding there). The request object, passed to our function, contains a user attribute. -This attribute will always be there: we cannot test whether it’s None or not, for instance. But -when the request comes from a user that isn’t logged in, the user attribute will contain an -anonymous Django user. We then can use the is_anonymous method to see whether the user is logged- -in or not. Last gift by Evennia, if the user is logged in, request.user contains a reference to -an account object, which will help us a lot in coupling the game and online system.

    +

    One of our requirements is to have a help system tailored to our accounts. If an account with admin access logs in, the page should display a lot of commands that aren’t accessible to common users. And perhaps even some additional help topics.

    +

    Fortunately, it’s fairly easy to get the logged in account in our view (remember that we’ll do most of our coding there). The request object, passed to our function, contains a user attribute. This attribute will always be there: we cannot test whether it’s None or not, for instance. But when the request comes from a user that isn’t logged in, the user attribute will contain an anonymous Django user. We then can use the is_anonymous method to see whether the user is logged-in or not. Last gift by Evennia, if the user is logged in, request.user contains a reference to an account object, which will help us a lot in coupling the game and online system.

    So we might end up with something like:

    def index(request):
         """The 'index' view."""
    @@ -358,8 +304,7 @@ an account object, which will help us a lot in coupling the game and online syst
     
    -

    Note: this code works when your MULTISESSION_MODE is set to 0 or 1. When it’s above, you would -have something like:

    +

    Note: this code works when your MULTISESSION_MODE is set to 0 or 1. When it’s above, you would have something like:

    def index(request):
         """The 'index' view."""
    @@ -369,14 +314,12 @@ have something like:

    In this second case, it will select the first character of the account.

    -

    But what if the user’s not logged in? Again, we have different solutions. One of the most simple -is to create a character that will behave as our default character for the help system. You can -create it through your game: connect to it and enter:

    +

    But what if the user’s not logged in? Again, we have different solutions. One of the most simple is to create a character that will behave as our default character for the help system. You can create it through your game: connect to it and enter:

    @charcreate anonymous
     

    The system should answer:

    -
    Created new character anonymous. Use @ic anonymous to enter the game as this character.
    +
        Created new character anonymous. Use @ic anonymous to enter the game as this character.
     

    So in our view, we could have something like this:

    @@ -391,15 +334,12 @@ create it through your game: connect to it and enter:

    character = Character.objects.get(db_key="anonymous")
    -

    This time, we have a valid character no matter what: remember to adapt this code if you’re running -in multisession mode above 1.

    +

    This time, we have a valid character no matter what: remember to adapt this code if you’re running in multisession mode above 1.

    The full system

    -

    What we’re going to do is to browse through all commands and help entries, and list all the commands -that can be seen by this character (either our ‘anonymous’ character, or our logged-in character).

    -

    The code is longer, but it presents the entire concept in our view. Edit the -“web/help_system/views.py” file and paste into it:

    +

    What we’re going to do is to browse through all commands and help entries, and list all the commands that can be seen by this character (either our ‘anonymous’ character, or our logged-in character).

    +

    The code is longer, but it presents the entire concept in our view. Edit the “web/help_system/views.py” file and paste into it:

    from django.http import Http404
     from django.shortcuts import render
     from evennia.help.models import HelpEntry
    @@ -493,26 +433,17 @@ that can be seen by this character (either our ‘anonymous’ character, or our
     
  • The index function is our view:

    • It begins by getting the character as we saw in the previous section.

    • -
    • It gets the help topics (commands and help entries) accessible to this character. It’s another -function that handles that part.

    • -
    • If there’s a GET variable “name” in our URL (like “/help?name=drop”), it will retrieve it. If -it’s not a valid topic’s name, it returns a 404. Otherwise, it renders the template called -“detail.html”, to display the detail of our topic.

    • +
    • It gets the help topics (commands and help entries) accessible to this character. It’s another function that handles that part.

    • +
    • If there’s a GET variable “name” in our URL (like “/help?name=drop”), it will retrieve it. If it’s not a valid topic’s name, it returns a 404. Otherwise, it renders the template called “detail.html”, to display the detail of our topic.

    • If there’s no GET variable “name”, render “index.html”, to display the list of topics.

  • -
  • The _get_topics is a private function. Its sole mission is to retrieve the commands a character -can execute, and the help entries this same character can see. This code is more Evennia-specific -than Django-specific, it will not be detailed in this tutorial. Just notice that all help topics -are stored in a dictionary. This is to simplify our job when displaying them in our templates.

  • +
  • The _get_topics is a private function. Its sole mission is to retrieve the commands a character can execute, and the help entries this same character can see. This code is more Evennia-specific than Django-specific, it will not be detailed in this tutorial. Just notice that all help topics are stored in a dictionary. This is to simplify our job when displaying them in our templates.