Skip to content

Commit

Permalink
Feature: add support for regions (add, edit, filter)
Browse files Browse the repository at this point in the history
  • Loading branch information
TrueBrain committed Mar 4, 2023
1 parent 5cefae1 commit 629db4e
Show file tree
Hide file tree
Showing 12 changed files with 248 additions and 24 deletions.
17 changes: 17 additions & 0 deletions webclient/helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
_api_url = None
_frontend_url = None
_tus_url = None # None means equal to _api_url
_regions = None


def content_type(key, singular, plural):
Expand All @@ -31,6 +32,21 @@ def content_type(key, singular, plural):
)


def get_regions():
# Delayed import to avoid circular imports
from .api import api_get

global _regions
if not _regions:
_regions = {}

regions = api_get(("config", "regions"))
for region in regions:
_regions[region["code"]] = region

return _regions


@click_helper.extend
@click.option(
"--api-url",
Expand Down Expand Up @@ -69,6 +85,7 @@ def template(*args, **kwargs):
kwargs["globals"] = {
"copyright_year": datetime.datetime.utcnow().year,
"content_types": _content_types,
"regions": get_regions(),
}

response = flask.make_response(flask.render_template(*args, **kwargs))
Expand Down
6 changes: 6 additions & 0 deletions webclient/pages/package_info.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,12 @@ def manager_package_edit(session, content_type, unique_id):
record_change(changes, package, "name", form.get("name").strip())
record_change(changes, package, "url", form.get("url").strip())

regions = form.get("regions").strip().splitlines()
regions = set(t.strip() for t in regions)
regions.discard("")
regions = sorted(regions)
record_change(changes, package, "regions", regions)

desc = "\n".join(t.rstrip() for t in form.get("description").strip().splitlines())
record_change(changes, package, "description", desc)

Expand Down
58 changes: 40 additions & 18 deletions webclient/pages/version_info.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
api_put,
)
from ..helpers import (
get_regions,
redirect,
template,
tus_host,
Expand Down Expand Up @@ -83,7 +84,7 @@ def record_change_compatibility(changes, data, form):
record_change(changes, data, "compatibility", compatability, True)


def record_change_dependencies(changes, data, form, messages):
def record_change_dependencies(changes, data, form, errors):
valid_data = True
dependencies = set()
for dependency in form.get("dependencies").splitlines():
Expand All @@ -96,7 +97,7 @@ def record_change_dependencies(changes, data, form, messages):
dependencies.add((match.group(1), match.group(2), match.group(3)))
else:
valid_data = False
messages.append("Invalid dependency: {}".format(dependency))
errors.append("Invalid dependency: {}".format(dependency))

dependencies = sorted(dependencies)
dependencies = [{"content-type": d[0], "unique-id": d[1], "md5sum-partial": d[2]} for d in dependencies]
Expand All @@ -105,7 +106,26 @@ def record_change_dependencies(changes, data, form, messages):
return valid_data


def record_change_descripton(changes, data, desc):
def record_change_regions(changes, data, regions, errors):
valid_data = True

regions = regions.strip().splitlines()
regions = set(r.strip() for r in regions)
regions.discard("")
regions = sorted(regions)

known_regions = get_regions()
for region in regions:
if region not in known_regions:
valid_data = False
errors.append("Invalid region: {}".format(region))

record_change(changes, data, "regions", regions, True)

return valid_data


def record_change_description(changes, data, desc):
desc = "\n".join(t.rstrip() for t in desc.strip().splitlines())
record_change(changes, data, "description", desc, True)

Expand Down Expand Up @@ -171,7 +191,7 @@ def manager_version_edit(session, content_type, unique_id, upload_date):
csrf_context = ("manager_version_edit", content_type, unique_id, upload_date)
version = api_get(("package", content_type, unique_id, upload_date), session=session)
package = api_get(("package", content_type, unique_id), session=session)
messages = []
errors = []

if flask.request.method == "POST":
form = flask.request.form
Expand All @@ -183,19 +203,21 @@ def manager_version_edit(session, content_type, unique_id, upload_date):
record_change(changes, version, "url", form.get("url").strip(), True)
record_change(changes, version, "version", form.get("version").strip())
record_change_compatibility(changes, version, form)
if not record_change_dependencies(changes, version, form, messages):
if not record_change_dependencies(changes, version, form, errors):
valid_data = False
record_change_descripton(changes, version, form.get("description"))
if not record_change_regions(changes, version, form.get("regions"), errors):
valid_data = False
record_change_description(changes, version, form.get("description"))

version.update(changes)
if not valid_csrf:
messages.append("CSRF token expired. Please reconfirm your changes.")
errors.append("CSRF token expired. Please reconfirm your changes.")
elif valid_data and changes:
_, error = api_put(
("package", content_type, unique_id, upload_date), json=changes, session=session, return_errors=True
)
if error:
messages.append(error)
errors.append(error)
else:
return redirect(
"manager_version_info",
Expand All @@ -220,7 +242,7 @@ def manager_version_edit(session, content_type, unique_id, upload_date):
version=version,
compatibility=compatibility,
deps_editable=deps_editable,
messages=messages,
errors=errors,
csrf_token=csrf_token,
)

Expand All @@ -238,7 +260,7 @@ def manager_new_package_upload(session, token):
csrf_context = ("manager_new_package_upload", token)
version = api_get(("new-package", token), session=session)
accept_tos = False
messages = []
errors = []

if flask.request.method == "POST":
form = flask.request.form
Expand All @@ -253,13 +275,15 @@ def manager_new_package_upload(session, token):
if form.get("license", "empty") != "empty":
record_change(changes, version, "license", form.get("license").strip())
record_change_compatibility(changes, version, form)
if not record_change_dependencies(changes, version, form, messages):
if not record_change_dependencies(changes, version, form, errors):
valid_data = False
if not record_change_regions(changes, version, form.get("regions"), errors):
valid_data = False
record_change_descripton(changes, version, form.get("description"))
record_change_description(changes, version, form.get("description"))

version.update(changes)
if not valid_csrf:
messages.append("CSRF token expired. Please reconfirm your changes.")
errors.append("CSRF token expired. Please reconfirm your changes.")

revalidate = False
if valid_csrf:
Expand All @@ -277,10 +301,8 @@ def manager_new_package_upload(session, token):
revalidate = True
_, error = api_put(("new-package", token), json=changes, session=session, return_errors=True)
if error:
messages.append(error)
errors.append(error)
revalidate = False # keep pending form data
else:
messages.append("Data updated")

if revalidate:
# rerun validation
Expand All @@ -294,7 +316,7 @@ def manager_new_package_upload(session, token):
("new-package", token, "publish"), json=changes, session=session, return_errors=True
)
if error:
messages.append(error)
errors.append(error)
else:
content_type = published.get("content-type")
unique_id = published.get("unique-id")
Expand Down Expand Up @@ -323,7 +345,7 @@ def manager_new_package_upload(session, token):
licenses=licenses,
accept_tos=accept_tos,
deps_editable=deps_editable,
messages=messages,
errors=errors,
tus_url=tus_url(),
upload_token=token,
csrf_token=csrf_token,
Expand Down
46 changes: 41 additions & 5 deletions webclient/static/filter.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,35 @@ function filterList() {
let match = true;
let filters = document.getElementsByClassName("filter-select");
for (let filter of filters) {
let value = row.dataset[filter.name];
/* Filter that is not set is always a match. */
if (filter.value == "") continue;

if (filter.value == "(none)") {
/* If the filter is set to "(none)", then the entry should not have
* this key at all. */
for (let key in row.dataset) {
if (key == filter.name || key.startsWith(filter.name + "--")) {
match = false;
break;
}
}
continue;
}

/* Find all the dataset entries that match this filter. Some can
* end with --<number>, to have unique entries in the dataset.
* But that postfix should be ignored for matching. */
let matches = 0;
for (let key in row.dataset) {
if (key == filter.name || key.startsWith(filter.name + "--")) {
if (row.dataset[key] == filter.value) {
matches++;
}
}
}

if (filter.value != "" && value != filter.value) {
if (matches == 0) {
/* If there are no matches, this entry is not a match. */
match = false;
break;
}
Expand Down Expand Up @@ -55,14 +81,24 @@ document.addEventListener("DOMContentLoaded", function(event) {
let list = document.getElementById("bananas-table");
for (var i = 0; i < list.rows.length; i++) {
let row = list.rows[i];
for (let key in row.dataset) {
let value = row.dataset[key];
for (let rawkey in row.dataset) {
let value = row.dataset[rawkey];

/* If a key ends with --<index>-<number>, remove this postfix. We do this,
* as some entries, like regions, are in fact a list. "dataset"
* doesn't support this, so we postfix it to make the key unique. */
let key = rawkey.replace(/--\d+-\d+$/, "");

if (classifications.has(key)) {
classifications.get(key).add(value);
} else {
classifications.set(key, new Set([value]));
}

/* For multi-selects, add a "None" option. */
if (key != rawkey) {
classifications.get(key).add("(none)")
}
}
}

Expand All @@ -87,7 +123,7 @@ document.addEventListener("DOMContentLoaded", function(event) {

let option = document.createElement("option");
option.value = "";
option.text = "All";
option.text = "(All)";
select.appendChild(option);

for (let value of Array.from(classification[1]).sort()) {
Expand Down
17 changes: 16 additions & 1 deletion webclient/templates/manager_new_package.html
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,18 @@ <h3>Step 3: Complete the description</h3>
</ul>
{% endif %}
</td></tr>
<tr><th>Regions<br/><small>Only available with NewGRFs, Heightmaps, and Scenarios</small></th><td>
<textarea name="regions" cols="20" rows="10" placeholder="
{%- for r in package["regions"] -%}
{{ r }}
{% endfor -%}
">
{%- for r in version["regions"] -%}
{{ r }}
{% endfor -%}
</textarea>
<p id="input-desc">Enter one region per row{% if package %}, leave empty to use the regions from the package{% endif %}</p>
</td></tr>
<tr><th>Description</th><td>
{% if package %}Leave empty to use the description from the package.<br/>{% endif %}
<textarea name="description" cols="50" rows="20" placeholder="{{ package["description"] }}">
Expand All @@ -129,12 +141,15 @@ <h3>Step 3: Complete the description</h3>

<h3>Step 4: Validate and publish</h3>

{% if version["errors"] %}
{% if version["errors"] or errors %}
Errors:
<ul>
{% for msg in version["errors"] %}
<li>{{ msg }}</li>
{% endfor %}
{% for msg in errors %}
<li>{{ msg }}</li>
{% endfor %}
</ul>
{% endif %}

Expand Down
8 changes: 8 additions & 0 deletions webclient/templates/manager_package_edit.html
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,14 @@ <h1>{% block title %}{{ package["name"] }}{% endblock %}</h1>
<li>{{ a["display-name"] }}</li>
{% endfor %}
</ul></td></tr>
<tr><th>Regions<br/><small>Only available with NewGRFs, Heightmaps, and Scenarios</small></th><td>
<textarea name="regions" cols="20" rows="10">
{%- for r in package["regions"] -%}
{{ r }}
{% endfor -%}
</textarea>
<p id="input-desc">Enter one region per row{% if package %}, leave empty to use the regions from the package{% endif %}</p>
</td></tr>
<tr><th>Description</th><td>
<textarea name="description" cols="50" rows="20">
{{- package["description"] -}}
Expand Down
23 changes: 23 additions & 0 deletions webclient/templates/manager_package_info.html
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,29 @@ <h1>{% block title %}{{ package["name"] }}{% endblock %}</h1>
</table>
</td></tr>
{% endif %}
{% if package["regions"] %}
<tr><th>Regions</th><td>
<ul class="author-list">
{% for region in package["regions"] %}
<li>
{% macro render_region(count, region) -%}
{% if count != 0 %}
--
{% endif %}

{{ globals.regions[region].name }}

{% if globals.regions[region].parent %}
{{ render_region(count + 1, globals.regions[region].parent) }}
{% endif %}
{%- endmacro %}

{{ render_region(0, region) }}
</li>
{% endfor %}
</ul>
</td></tr>
{% endif %}
<tr><th>Name</th><td>{{ package["name"] }}</td></tr>
<tr><th>Project site</th><td>
{% if package["url"] %}
Expand Down
12 changes: 12 additions & 0 deletions webclient/templates/manager_version_edit.html
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,18 @@ <h1><a href="/manager/{{ package["content-type"] }}/{{ package["unique-id"] }}">
</ul>
{% endif %}
</td></tr>
<tr><th>Regions<br/><small>Only available with NewGRFs, Heightmaps, and Scenarios</small></th><td>
<textarea name="regions" cols="20" rows="10" placeholder="
{%- for r in package["regions"] -%}
{{ r }}
{% endfor -%}
">
{%- for r in version["regions"] -%}
{{ r }}
{% endfor -%}
</textarea>
<p id="input-desc">Enter one region per row{% if package %}, leave empty to use the regions from the package{% endif %}</p>
</td></tr>
<tr><th>Description</th><td>
Leave empty to use the description from the package.<br/>
<textarea name="description" cols="50" rows="20" placeholder="{{ package["description"] }}">
Expand Down

0 comments on commit 629db4e

Please sign in to comment.