This document shows you how to get the project and run various local dev tasks.
Before diving into the setup, a quick note about how the application is designed:
Although it uses a database, the site is actually 100% static. There's no runtime way to alter the database content, and every page is cached in production.
This means that when you make a change to the data, you simply wipe the database out and redo the "reset" process (see below) to regenerate your data.
PostgreSQL specifically is required due to the usage of JSON data types.
Docker can be used to simplify the setup of the infrastructure required to run the application locally.
Install GNU make and git.
Clone the source code locally:
cd src
git clone http://git.modding-openmw.com/Modding-OpenMW.com/momw.git
cd
into the source directory:
cd momw
Start the application:
sudo make compose-up
Once you see Starting development server at http://0.0.0.0:8000/
in the terminal output, you can open up that URL in your browser to see the local copy of the application running. It will say "docker" in the site title.
There's a hardcoded wait in the service command; this is to ensure that the database container is ready before the application tries to run. If the wait isn't long enough, simply edit that line.
If any data changes are made, that volume will need to be deleted (note the psql
container needs to be deleted first):
sudo make docker-reset
Then simply re-run sudo make compose-up
.
These steps should work for any unix-based system (Linux, macOS).
To make sure that the following instructions work, please install the following dependencies on your machine:
To get the source, clone the git repository via:
$ git clone http://git.modding-openmw.com/Modding-OpenMW.com/momw.git
This will clone the complete source to your local machine. Navigate to the project folder and install all needed dependencies via pip3:
$ pip3 install --user --upgrade -r requirements.txt
If desired, the --user
flag may be omitted but this is not advised.
Create a psql database, role, and user called momwdb
with login
and createdb
privileges.
Next, a database user (and related unix account) are created:
$ sudo useradd momwdb
$ sudo -u postgres psql -c 'create user momwdb with encrypted password \'postgresqlpassword\';'
Create the required databases:
$ sudo -u postgres createdb momwdb
$ sudo -u postgres createdb test_momwdb
Add privileges to the app's database user:
$ sudo -u postgres psql -c 'alter user momwdb createdb;'
$ sudo -u postgres psql -c 'alter user momwdb login;'
And finally, set the owner on the databases that were created:
$ sudo -u postgres psql -c 'alter database momwdb owner to momwdb;'
$ sudo -u postgres psql -c 'alter database test_momwdb owner to momwdb;'
If you want to not require a password to do things like psql
as the app's database user, add the following to your sudoers config:
<your username> ALL=(momwdb) NOPASSWD: /bin/psql,/bin/createdb,/bin/dropdb
Adjust the paths to the binaries as needed.
With that, you should now me able to run the app and related tasks:
make reset
make server
If you just want to run a local version of the site, you should now be set.
Tests depend on a working install of both the chrome and gecko webdrivers for selenium, as well as a working local manual install of the application. Docker-based setups are not yet supported. Their installation and setup is (for now) outside the scope of this document, but all that's necessary is to have chromedriver
and geckodriver
binaries for your OS in your $PATH
.
To run tests:
make test
After a short time, a chrome or chromium instance will pop up with a note about it being controlled by software. After a bit more time it will close and then firefox will open and do the same. This is normal and part of the test suite.
Source is automatically formatted as part of the make test
target, using python black. Please ensure it's installed for your system.
Linting also happens as part of the test target, be sure the following rules are set at minimum:
[flake8]
ignore = E501, E402, W503
max-line-length = 160
Any commit to any branch on the primary Modding-OpenMW.com/momw
repository will kick off
a buildbot build.
Check out a new branch based on beta
and name it to what you intend to do:
$ git checkout -b my-cool-feature origin/beta
Use one branch per fix/feature
Make your changes
make test
.Commit your changes
Make a pull request
beta
branch.Tests are expected for any submitted changes. If it's specific to a particular page, or adds a new page, related selenium tests should be written.
Mods exist in .py
files in this directory. They are divided by category, each file is named after their respective category.
As for how to decide what a mod's category is: use your best judgement. If you think a new category is needed, you can add those via the mod_categories.py file.
Here's a sample of what mod data might look like, fully annotated with comments:
{
# Optional; a list of strings which are mod names. Any strings that aren't mod names are ignored.
"alt_to": ["Mod Name 1", "Mod Name 2"],
# Required; this can be a raw string, or you can use the nexus_user() helper as seen below.
"author": nexus_user("1234567", "Some User Name"),
# Required; the category is always defined in each file. Refer to existing data to see how it should be.
"category": some_category,
# Required; A string, one of: "fully working", "partially working", "not working", or "unknown".
"compat": "fully working",
# Required; a string, formatted: YYYY-MM-DD HH:MM:SS -OFFSET
"date_added": "2090-04-11 21:00:00 -0500",
# Optional; also a string, formatted: YYYY-MM-DD HH:MM:SS -OFFSET
"date_updated": "2090-08-21 21:00:00 -0500",
# Required; a potentially very long string. Use python triple quotes("""Hello""") for long/multi-line descriptions.
"description": "A very good description of this mod.",
# Optional; A string for the URL at which the mod can be directly downloaded.
"dl_url": "https://modding-openmw.com/files/cool-mod.zip",
# Optional; HTML-formatted string to be viewed as "extra cfg".
# See this as an example: https://git.modding-openmw.com/Modding-OpenMW.com/momw/src/commit/409ab1c5925575d03d9c6840f8cd9d7bb83d14d9/momw/momw/data_seeds/by_category/replacers.py#L50-L52
# Note that when you use "extra_cfg" you should also use "extra_cfg_raw" (see below).
"extra_cfg": "HTML-formatted extra cfg",
# Optional; raw text string used by the CFG Generator for a mod's extra_cfg.
# See this as an example: https://git.modding-openmw.com/Modding-OpenMW.com/momw/src/commit/409ab1c5925575d03d9c6840f8cd9d7bb83d14d9/momw/momw/data_seeds/by_category/replacers.py#L53-L57
"extra_cfg_raw": "Text only extra cfg",
# Optional; if a mod has multiple folder paths you can represent them like this.
"folder_paths": {"01": "00 Core", "02": "01 Extra Stuff"},
# Optional; Set this to True (no quotes) if the mod requires a BSA. Otherwise this can be omitted.
"has_bsa": False,
# Optional; Set this to True (no quotes) if the mod requires a plugin. Otherwise this can be omitted.
"has_plugin": False,
# Required; either True or False (no quotes) if the mod is or isn't active, respectively.
"is_active": True,
# Required; a string that is the name of the mod.
"name": "A Very Awesome Mod",
# Optional; Set this to True (no quotes) if the mod's plugin needs to be cleaned with tes3cmd.
# Otherwise, this can be omitted.
"needs_cleaning": False,
# Optional; similar to category, tags are defined in each file.
# You may need to define a tag if it isn't already.
"tags": [tag_high_res],
# Required; similar to "author" above, you may provide a raw string for the URL or use the nexus_mod() helper.
"url": nexus_mod("98765"),
# Optional; a potentially large string (like description) for the mod's usage notes.
"usage_notes": "Here is how to use this mod ...",
},
You can verify your formatting with the black
command (either run make test-black
or invoke black
by hand). If your formatting is wrong, black
will automatically fix it, unless there's a major syntax problem.
As noted above, mods exist in .py
files in this directory. They are divided by category, each file is named after their respective category.
Open the file that corresponds to the category for the mod you wish to edit, find the mod in the file, and edit as needed. See above for a fully annotated sample of mod data.
If you are making a change that will alter the URL of a mod (e.g. a name change that affects the slug), please see below for a note on preserving old links.
Non-mod pages (such as the main index of the website) are defined in various ways.
First, there's the view function. If the page is to be totally static HTML, then you can use the static_view()
view function.
If the page needs to be dynamic in some way, then you would define a new view function in the dynamicpages.py
file.
In either case, you will also need a .html
file in the templates
directory.
Then you have the URL route, defined in urls.py
.
This is how URLs are matched to view functions, see the file for examples of this in action in various ways.
Editing a non-mod page isn't much different from adding one. The same patterns apply, except you'd be working with existing content.
If you are making a change that will alter the URL of a page, please see below for a note on preserving old links.
While developing this website, care is taken to not cause any link rot.
This codebase contains a legacy_url_redirect()
view function for ensuring that old URLs stick around while pointing to updated content as needed. Please see here and throughout that file for several examples of how to use it.
The main thing to remember is: if you're changing a URL, make sure the old one still works after the change. Either via the helper view mentioned above or some other means as needed.