Update API docs, add support for code highlighting, add markdown table support

This commit is contained in:
rubenwardy 2021-02-02 17:09:19 +00:00
parent 033f40c263
commit 2f66db5989
13 changed files with 163 additions and 79 deletions

@ -1,5 +1,5 @@
# ContentDB # ContentDB
# Copyright (C) 2018-1 rubenwardy # Copyright (C) 2018-21 rubenwardy
# #
# This program is free software: you can redistribute it and/or modify # This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published by # it under the terms of the GNU Affero General Public License as published by
@ -21,7 +21,7 @@ import flask_menu as menu
from flask_mail import Mail from flask_mail import Mail
from flask_github import GitHub from flask_github import GitHub
from flask_wtf.csrf import CSRFProtect from flask_wtf.csrf import CSRFProtect
from flask_flatpages import FlatPages from flask_flatpages import FlatPages, pygments_style_defs
from flask_babel import Babel from flask_babel import Babel
from flask_login import logout_user, current_user, LoginManager from flask_login import logout_user, current_user, LoginManager
import os, redis import os, redis
@ -29,6 +29,14 @@ import os, redis
app = Flask(__name__, static_folder="public/static") app = Flask(__name__, static_folder="public/static")
app.config["FLATPAGES_ROOT"] = "flatpages" app.config["FLATPAGES_ROOT"] = "flatpages"
app.config["FLATPAGES_EXTENSION"] = ".md" app.config["FLATPAGES_EXTENSION"] = ".md"
app.config["FLATPAGES_MARKDOWN_EXTENSIONS"] = ["fenced_code", "tables", "codehilite"]
app.config["FLATPAGES_EXTENSION_CONFIG"] = {
"fenced_code": {},
"tables": {},
"codehilite": {
"linenums": "True"
}
}
app.config.from_pyfile(os.environ["FLASK_CONFIG"]) app.config.from_pyfile(os.environ["FLASK_CONFIG"])
r = redis.Redis.from_url(app.config["REDIS_URL"]) r = redis.Redis.from_url(app.config["REDIS_URL"])
@ -41,8 +49,8 @@ pages = FlatPages(app)
babel = Babel(app) babel = Babel(app)
gravatar = Gravatar(app, gravatar = Gravatar(app,
size=58, size=58,
rating='g', rating="g",
default='mp', default="mp",
force_default=False, force_default=False,
force_lower=False, force_lower=False,
use_ssl=True, use_ssl=True,
@ -66,7 +74,7 @@ init_app(app)
# @babel.localeselector # @babel.localeselector
# def get_locale(): # def get_locale():
# return request.accept_languages.best_match(app.config['LANGUAGES'].keys()) # return request.accept_languages.best_match(app.config["LANGUAGES"].keys())
from . import models, template_filters from . import models, template_filters
@ -80,13 +88,13 @@ create_blueprints(app)
@app.route("/uploads/<path:path>") @app.route("/uploads/<path:path>")
def send_upload(path): def send_upload(path):
return send_from_directory(app.config['UPLOAD_DIR'], path) return send_from_directory(app.config["UPLOAD_DIR"], path)
@menu.register_menu(app, ".help", "Help", order=19, endpoint_arguments_constructor=lambda: { 'path': 'help' }) @menu.register_menu(app, ".help", "Help", order=19, endpoint_arguments_constructor=lambda: { "path": "help" })
@app.route('/<path:path>/') @app.route("/<path:path>/")
def flatpage(path): def flatpage(path):
page = pages.get_or_404(path) page = pages.get_or_404(path)
template = page.meta.get('template', 'flatpage.html') template = page.meta.get("template", "flatpage.html")
return render_template(template, page=page) return render_template(template, page=page)
@app.before_request @app.before_request
@ -95,7 +103,7 @@ def check_for_ban():
if current_user.rank == models.UserRank.BANNED: if current_user.rank == models.UserRank.BANNED:
flash("You have been banned.", "danger") flash("You have been banned.", "danger")
logout_user() logout_user()
return redirect(url_for('users.login')) return redirect(url_for("users.login"))
elif current_user.rank == models.UserRank.NOT_JOINED: elif current_user.rank == models.UserRank.NOT_JOINED:
current_user.rank = models.UserRank.MEMBER current_user.rank = models.UserRank.MEMBER
models.db.session.commit() models.db.session.commit()

@ -102,7 +102,7 @@ def populate_test_data(session):
mod1.desc = """ mod1.desc = """
Majority of awards are back ported from Calinou's old fork in Carbone, under same license. Majority of awards are back ported from Calinou's old fork in Carbone, under same license.
``` ```lua
awards.register_achievement("award_mesefind",{ awards.register_achievement("award_mesefind",{
title = "First Mese Find", title = "First Mese Find",
description = "Found some Mese!", description = "Found some Mese!",

@ -12,7 +12,6 @@ title: Help
## Help for Package Authors ## Help for Package Authors
* [Package Inclusion Policy and Guidance](/policy_and_guidance/) * [Package Inclusion Policy and Guidance](/policy_and_guidance/)
* [Package Tags](package_tags)
* [Git Update Detection](update_config) * [Git Update Detection](update_config)
* [Creating Releases using Webhooks](release_webhooks) * [Creating Releases using Webhooks](release_webhooks)
* [Package Configuration and Releases Guide](package_config) * [Package Configuration and Releases Guide](package_config)

@ -5,11 +5,11 @@ title: API
Not all endpoints require authentication. Not all endpoints require authentication.
Authentication is done using Bearer tokens: Authentication is done using Bearer tokens:
Authorization: Bearer YOURTOKEN ```bash
curl -H "Authorization: Bearer YOURTOKEN" https://content.minetest.net/api/whoami/
```
You can use the `/api/whoami` to check authentication. Tokens can be attained by visiting [Settings > API Tokens](/user/tokens/).
Tokens can be attained by visiting [Profile > "API Tokens"](/user/tokens/).
## Endpoints ## Endpoints
@ -43,8 +43,8 @@ Tokens can be attained by visiting [Profile > "API Tokens"](/user/tokens/).
### Releases ### Releases
* GET `/api/packages/<username>/<name>/releases/` * GET `/api/packages/<username>/<name>/releases/` (List)
* POST `/api/packages/<username>/<name>/releases/new/` * POST `/api/packages/<username>/<name>/releases/new/` (Create)
* Requires authentication. * Requires authentication.
* Body is multipart form if zip upload, JSON otherwise. * Body is multipart form if zip upload, JSON otherwise.
* `title`: human-readable name of the release. * `title`: human-readable name of the release.
@ -55,6 +55,19 @@ Tokens can be attained by visiting [Profile > "API Tokens"](/user/tokens/).
* `file`: multipart file to upload, like `<input type=file>`. * `file`: multipart file to upload, like `<input type=file>`.
* You can set min and max Minetest Versions [using the content's .conf file](/help/package_config/). * You can set min and max Minetest Versions [using the content's .conf file](/help/package_config/).
Examples:
```bash
# Create release from Git
curl -X POST https://content.minetest.net/api/packages/username/name/releases/new/ \
-H "Authorization: Bearer YOURTOKEN" -H "Content-Type: application/json" \
-d "{\"method\": \"git\", \"title\": \"My Release\", \"ref\": \"master\" }"
# Create release from zip upload
curl https://content.minetest.net/api/packages/username/name/releases/new/ \
-H "Authorization: Bearer YOURTOKEN" \
-F title="My Release" -F file=@path/to/file.zip
```
### Topics ### Topics

@ -1,33 +0,0 @@
title: Package Tags
## Overview
Tags should be added to packages to enable easy identification of different types of mods, games and texture packs.
They are only beneficial when applied correctly, so please use the following guidelines.
## Tag Usage
* **Building** - For mods that focus on adding new materials or nodes to build with.
* **Education** - For mods or games created for educational purposes.
* **Environment** - For mods that add environmental effects, including ambient sound and weather effects.
* **Inventory** - For mods that add new inventory systems or new inventory pages.
* **Machines and Electronics** - For mods that include placeable machinery or electronic components which interact to complete tasks.
* **Maintenance** - For mods that assist with world or player maintenance. This includes large-scale map manipulation, area protection and other administrative tools.
* **Mapgen** - For mods that add new biomes, new mapgen decorations, or any other mapgen elements.
* **Mobs and NPCs** - For mods that add mobs or NPCs, or provide tools that assist with mob and NPC creation or manipulation.
* **Plants and Farming** - For mods that add new plants or other farmable resources.
* **Player effects/Food** - For mods that change player effects, for example speed, jump height or gravity, and food.
* **Tools** - For mods that add new tools or new features for existing tools.
* **Transport** - For mods that add transportation methods. This includes teleportation, vehicles and ridable mobs.
* **Survival** - For mods written specifically for survival games. For example, these mods might focus on game-balance or increase the difficulty level. This tag should also be used for games with a heavy survival focus.
* **Creative** - For mods written specifically (and often exclusively) for use in creative mode. For example, these mods may add a large amount of decorative content, or content without crafting recipes. This tag should also be used for games with a heavy creative focus.
* **Multiplayer-focused** - For games that can be played with other players.
* **Singleplayer-focused** - For games that can be played alone.
* **PvP** - For games designed to be played competitively against other players.
* **PvE** - For games designed for one or multiple players which focus on combat against mobs or NPCs.
* **Puzzle** - For mods and games with a focus on puzzle solving instead of combat.
* **16px** - For 16px texture packs.
* **32px** - For 32px texture packs.
* **64px** - For 64px texture packs.
* **128px+** - For 128px or higher texture packs.

@ -11,8 +11,10 @@ plus the sum of the score given by reviews.
A review score is 100 if positive, -100 if negative. A review score is 100 if positive, -100 if negative.
reviews_sum = sum(100 * (positive ? 1 : -1)) ```c
score = avg_downloads + reviews_sum reviews_sum = sum(100 * (positive ? 1 : -1));
score = avg_downloads + reviews_sum;
```
## Pseudo rolling average of downloads ## Pseudo rolling average of downloads

@ -3,7 +3,7 @@ title: Git Update Detection
## Introduction ## Introduction
When you push a change to your Git repository, ContentDB can create a new release automatically or When you push a change to your Git repository, ContentDB can create a new release automatically or
send you a reminder. ContentDB will check your Git repository every day, but you can use send you a reminder. ContentDB will check your Git repository one per day, but you can use
webhooks or the API for faster updates. webhooks or the API for faster updates.
Git Update Detection is clever enough to not create a release again if you've already created Git Update Detection is clever enough to not create a release again if you've already created

@ -11,25 +11,18 @@ Default whitelist of allowed HTML tags. Any other HTML tags will be escaped or
stripped from the text. This applies to the html output that Markdown produces. stripped from the text. This applies to the html output that Markdown produces.
""" """
ALLOWED_TAGS = [ ALLOWED_TAGS = [
'ul', "h1", "h2", "h3", "h4", "h5", "h6", "hr",
'ol', "ul", "ol", "li",
'li', "p",
'p', "br",
'pre', "pre",
'code', "code",
'blockquote', "blockquote",
'h1', "strong",
'h2', "em",
'h3', "a",
'h4', "img",
'h5', "table", "thead", "tbody", "tr", "th", "td"
'h6',
'hr',
'br',
'strong',
'em',
'a',
'img'
] ]
""" """
@ -38,8 +31,8 @@ tags and the src, title and alt attributes for <img> tags. Any other attribute
will be stripped from its tag. will be stripped from its tag.
""" """
ALLOWED_ATTRIBUTES = { ALLOWED_ATTRIBUTES = {
'a': ['href', 'title'], "a": ["href", "title"],
'img': ['src', 'title', 'alt'] "img": ["src", "title", "alt"]
} }
""" """
@ -47,10 +40,10 @@ If you allow tags that have attributes containing a URI value
(like the href attribute of an anchor tag,) you may want to adapt (like the href attribute of an anchor tag,) you may want to adapt
the accepted protocols. The default list only allows http, https and mailto. the accepted protocols. The default list only allows http, https and mailto.
""" """
ALLOWED_PROTOCOLS = ['http', 'https', 'mailto'] ALLOWED_PROTOCOLS = ["http", "https", "mailto"]
md = Markdown(extensions=["fenced_code"], output_format="html5") md = None
def render_markdown(source): def render_markdown(source):
return bleach.clean(md.convert(source), return bleach.clean(md.convert(source),
@ -58,6 +51,10 @@ def render_markdown(source):
styles=[], protocols=ALLOWED_PROTOCOLS) styles=[], protocols=ALLOWED_PROTOCOLS)
def init_app(app): def init_app(app):
global md
md = Markdown(extensions=app.config["FLATPAGES_MARKDOWN_EXTENSIONS"], output_format="html5")
@app.template_filter() @app.template_filter()
def markdown(source): def markdown(source):
return Markup(render_markdown(source)) return Markup(render_markdown(source))

@ -67,7 +67,7 @@ p, .content li {
pre code { pre code {
display: block; display: block;
border: 1px solid rgba(255, 255, 255, 0.1); border: 1px solid rgba(255, 255, 255, 0.1);
background: rgba(255, 255, 255, 0.03); background: rgba(51, 51, 51, 0.25);
padding: 0.75rem 1.25rem; padding: 0.75rem 1.25rem;
border-radius: 0.25rem; border-radius: 0.25rem;
} }
@ -157,3 +157,5 @@ pre code {
text-align: left; text-align: left;
} }
} }
@import "dracula.scss";

94
app/scss/dracula.scss Normal file

@ -0,0 +1,94 @@
/* Dracula Theme v1.2.5
*
* https://github.com/zenorocha/dracula-theme
*
* Copyright 2016, All rights reserved
*
* Code licensed under the MIT license
* http://zenorocha.mit-license.org
*
* @author Rob G <wowmotty@gmail.com>
* @author Chris Bracco <chris@cbracco.me>
* @author Zeno Rocha <hi@zenorocha.com>
*/
.highlight, .codehilite {
color: #f8f8f2;
.hll { background-color: #f1fa8c }
.c { color: #6272a4 } /* Comment */
.err { color: #f8f8f2 } /* Error */
.g { color: #f8f8f2 } /* Generic */
.k { color: #ff79c6 } /* Keyword */
.l { color: #f8f8f2 } /* Literal */
.n { color: #f8f8f2 } /* Name */
.o { color: #ff79c6 } /* Operator */
.x { color: #f8f8f2 } /* Other */
.p { color: #f8f8f2 } /* Punctuation */
.ch { color: #6272a4 } /* Comment.Hashbang */
.cm { color: #6272a4 } /* Comment.Multiline */
.cp { color: #ff79c6 } /* Comment.Preproc */
.cpf { color: #6272a4 } /* Comment.PreprocFile */
.c1 { color: #6272a4 } /* Comment.Single */
.cs { color: #6272a4 } /* Comment.Special */
.gd { color: #8b080b } /* Generic.Deleted */
.ge { color: #f8f8f2; text-decoration: underline } /* Generic.Emph */
.gr { color: #f8f8f2 } /* Generic.Error */
.gh { color: #f8f8f2; font-weight: bold } /* Generic.Heading */
.gi { color: #f8f8f2; font-weight: bold } /* Generic.Inserted */
.go { color: #44475a } /* Generic.Output */
.gp { color: #f8f8f2 } /* Generic.Prompt */
.gs { color: #f8f8f2 } /* Generic.Strong */
.gu { color: #f8f8f2; font-weight: bold } /* Generic.Subheading */
.gt { color: #f8f8f2 } /* Generic.Traceback */
.kc { color: #ff79c6 } /* Keyword.Constant */
.kd { color: #8be9fd; font-style: italic } /* Keyword.Declaration */
.kn { color: #ff79c6 } /* Keyword.Namespace */
.kp { color: #ff79c6 } /* Keyword.Pseudo */
.kr { color: #ff79c6 } /* Keyword.Reserved */
.kt { color: #8be9fd } /* Keyword.Type */
.ld { color: #f8f8f2 } /* Literal.Date */
.m { color: #bd93f9 } /* Literal.Number */
.s { color: #f1fa8c } /* Literal.String */
.na { color: #50fa7b } /* Name.Attribute */
.nb { color: #8be9fd; font-style: italic } /* Name.Builtin */
.nc { color: #50fa7b } /* Name.Class */
.no { color: #f8f8f2 } /* Name.Constant */
.nd { color: #f8f8f2 } /* Name.Decorator */
.ni { color: #f8f8f2 } /* Name.Entity */
.ne { color: #f8f8f2 } /* Name.Exception */
.nf { color: #50fa7b } /* Name.Function */
.nl { color: #8be9fd; font-style: italic } /* Name.Label */
.nn { color: #f8f8f2 } /* Name.Namespace */
.nx { color: #f8f8f2 } /* Name.Other */
.py { color: #f8f8f2 } /* Name.Property */
.nt { color: #ff79c6 } /* Name.Tag */
.nv { color: #8be9fd; font-style: italic } /* Name.Variable */
.ow { color: #ff79c6 } /* Operator.Word */
.w { color: #f8f8f2 } /* Text.Whitespace */
.mb { color: #bd93f9 } /* Literal.Number.Bin */
.mf { color: #bd93f9 } /* Literal.Number.Float */
.mh { color: #bd93f9 } /* Literal.Number.Hex */
.mi { color: #bd93f9 } /* Literal.Number.Integer */
.mo { color: #bd93f9 } /* Literal.Number.Oct */
.sa { color: #f1fa8c } /* Literal.String.Affix */
.sb { color: #f1fa8c } /* Literal.String.Backtick */
.sc { color: #f1fa8c } /* Literal.String.Char */
.dl { color: #f1fa8c } /* Literal.String.Delimiter */
.sd { color: #f1fa8c } /* Literal.String.Doc */
.s2 { color: #f1fa8c } /* Literal.String.Double */
.se { color: #f1fa8c } /* Literal.String.Escape */
.sh { color: #f1fa8c } /* Literal.String.Heredoc */
.si { color: #f1fa8c } /* Literal.String.Interpol */
.sx { color: #f1fa8c } /* Literal.String.Other */
.sr { color: #f1fa8c } /* Literal.String.Regex */
.s1 { color: #f1fa8c } /* Literal.String.Single */
.ss { color: #f1fa8c } /* Literal.String.Symbol */
.bp { color: #f8f8f2; font-style: italic } /* Name.Builtin.Pseudo */
.fm { color: #50fa7b } /* Name.Function.Magic */
.vc { color: #8be9fd; font-style: italic } /* Name.Variable.Class */
.vg { color: #8be9fd; font-style: italic } /* Name.Variable.Global */
.vi { color: #8be9fd; font-style: italic } /* Name.Variable.Instance */
.vm { color: #8be9fd; font-style: italic } /* Name.Variable.Magic */
.il { color: #bd93f9 } /* Literal.Number.Integer.Long */
}

@ -7,7 +7,7 @@
<meta name="viewport" content="width=device-width, initial-scale=1"> <meta name="viewport" content="width=device-width, initial-scale=1">
<title>{% block title %}title{% endblock %} - {{ config.USER_APP_NAME }}</title> <title>{% block title %}title{% endblock %} - {{ config.USER_APP_NAME }}</title>
<link rel="stylesheet" type="text/css" href="/static/bootstrap.css"> <link rel="stylesheet" type="text/css" href="/static/bootstrap.css">
<link rel="stylesheet" type="text/css" href="/static/custom.css?v=19"> <link rel="stylesheet" type="text/css" href="/static/custom.css?v=20">
<link rel="search" type="application/opensearchdescription+xml" href="/static/opensearch.xml" title="ContentDB" /> <link rel="search" type="application/opensearchdescription+xml" href="/static/opensearch.xml" title="ContentDB" />
<link rel="shortcut icon" href="/favicon-16.png" sizes="16x16"> <link rel="shortcut icon" href="/favicon-16.png" sizes="16x16">
<link rel="icon" href="/favicon-128.png" sizes="128x128"> <link rel="icon" href="/favicon-128.png" sizes="128x128">

@ -51,6 +51,7 @@ psycopg2==2.8.5
py==1.9.0 py==1.9.0
pycparser==2.20 pycparser==2.20
pyparsing==2.4.7 pyparsing==2.4.7
pygments==2.7.4
pyScss==1.3.7 pyScss==1.3.7
pytest==5.4.3 pytest==5.4.3
pytest-cov==2.10.0 pytest-cov==2.10.0

@ -15,6 +15,7 @@ markdown ~= 3.1
bleach ~= 3.1 bleach ~= 3.1
passlib ~= 1.7 passlib ~= 1.7
pygments ~= 2.7
beautifulsoup4 ~= 4.6 beautifulsoup4 ~= 4.6
celery ~= 4.4 celery ~= 4.4