Introduce flask_arrest, fix dotenv loading (Apache), and new template macro "nl.jinja2"
This commit is contained in:
parent
910e01b691
commit
acf918f656
10 changed files with 80 additions and 118 deletions
4
.gitignore
vendored
4
.gitignore
vendored
|
|
@ -7,8 +7,8 @@ site-*.conf
|
||||||
run_8180.py
|
run_8180.py
|
||||||
.env
|
.env
|
||||||
alembic.ini
|
alembic.ini
|
||||||
venv/
|
venv
|
||||||
venv-*/
|
venv-*
|
||||||
.venv
|
.venv
|
||||||
env
|
env
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,7 @@ suitable as a community or team knowledge base.
|
||||||
## Requirements
|
## Requirements
|
||||||
|
|
||||||
+ **Python** 3.6+.
|
+ **Python** 3.6+.
|
||||||
+ **Flask** web framework (and Flask-Login / Flask-WTF extensions).
|
+ **Flask** web framework (and Flask-Login / Flask-WTF / Flask-Arrest extensions).
|
||||||
+ **Peewee** ORM.
|
+ **Peewee** ORM.
|
||||||
+ **Markdown** for page rendering.
|
+ **Markdown** for page rendering.
|
||||||
+ **Python-I18n**.
|
+ **Python-I18n**.
|
||||||
|
|
|
||||||
22
app.py
22
app.py
|
|
@ -17,6 +17,7 @@ from flask import (
|
||||||
render_template, send_from_directory)
|
render_template, send_from_directory)
|
||||||
from flask_login import LoginManager, login_user, logout_user, current_user, login_required
|
from flask_login import LoginManager, login_user, logout_user, current_user, login_required
|
||||||
from flask_wtf import CSRFProtect
|
from flask_wtf import CSRFProtect
|
||||||
|
#from flask_arrest import RestBlueprint, serialize_response
|
||||||
from werkzeug.security import generate_password_hash, check_password_hash
|
from werkzeug.security import generate_password_hash, check_password_hash
|
||||||
from werkzeug.routing import BaseConverter
|
from werkzeug.routing import BaseConverter
|
||||||
from peewee import *
|
from peewee import *
|
||||||
|
|
@ -46,9 +47,9 @@ PING_RE = r'(?<!\w)@(' + USERNAME_RE + r')'
|
||||||
|
|
||||||
#### GENERAL CONFIG ####
|
#### GENERAL CONFIG ####
|
||||||
|
|
||||||
dotenv.load_dotenv()
|
dotenv.load_dotenv(os.path.join(APP_BASE_DIR, '.env'))
|
||||||
|
|
||||||
CONFIG_FILE = os.getenv('SALVI_CONF', APP_BASE_DIR + '/site.conf')
|
CONFIG_FILE = os.getenv('SALVI_CONF', os.path.join(APP_BASE_DIR, 'site.conf'))
|
||||||
|
|
||||||
# security check: one may specify only configuration files INSIDE
|
# security check: one may specify only configuration files INSIDE
|
||||||
# the code directory.
|
# the code directory.
|
||||||
|
|
@ -96,7 +97,6 @@ def render_paginated_template(template_name, query_name, **kwargs):
|
||||||
template_name,
|
template_name,
|
||||||
page_n = page,
|
page_n = page,
|
||||||
total_count = query.count(),
|
total_count = query.count(),
|
||||||
min=min,
|
|
||||||
**kwargs
|
**kwargs
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -143,12 +143,6 @@ class BaseModel(Model):
|
||||||
class Meta:
|
class Meta:
|
||||||
database = database
|
database = database
|
||||||
|
|
||||||
# Used for PagePolicy
|
|
||||||
def _passphrase_hash(pp):
|
|
||||||
pp_bin = pp.encode('utf-8')
|
|
||||||
h = str(len(pp_bin)) + ':' + hashlib.sha256(pp_bin).hexdigest()
|
|
||||||
return h
|
|
||||||
|
|
||||||
class User(BaseModel):
|
class User(BaseModel):
|
||||||
username = CharField(32, unique=True)
|
username = CharField(32, unique=True)
|
||||||
email = CharField(256, null=True)
|
email = CharField(256, null=True)
|
||||||
|
|
@ -325,6 +319,12 @@ class Page(BaseModel):
|
||||||
pass
|
pass
|
||||||
return ", ".join(kw)
|
return ", ".join(kw)
|
||||||
|
|
||||||
|
#def ldjson(self):
|
||||||
|
# return {
|
||||||
|
# "@context": "https://www.w3.org/ns/activitystreams",
|
||||||
|
#
|
||||||
|
# }
|
||||||
|
|
||||||
|
|
||||||
class PageText(BaseModel):
|
class PageText(BaseModel):
|
||||||
content = BlobField()
|
content = BlobField()
|
||||||
|
|
@ -657,13 +657,13 @@ def _before_request():
|
||||||
|
|
||||||
@app.context_processor
|
@app.context_processor
|
||||||
def _inject_variables():
|
def _inject_variables():
|
||||||
|
|
||||||
return {
|
return {
|
||||||
'T': partial(get_string, _get_lang()),
|
'T': partial(get_string, _get_lang()),
|
||||||
'app_name': os.getenv("APP_NAME") or _getconf('site', 'title'),
|
'app_name': os.getenv("APP_NAME") or _getconf('site', 'title'),
|
||||||
'strong': lambda x:Markup('<strong>{0}</strong>').format(x),
|
'strong': lambda x:Markup('<strong>{0}</strong>').format(x),
|
||||||
'app_version': __version__,
|
'app_version': __version__,
|
||||||
'material_icons_url': _getconf('site', 'material_icons_url')
|
'material_icons_url': _getconf('site', 'material_icons_url'),
|
||||||
|
'min': min
|
||||||
}
|
}
|
||||||
|
|
||||||
@login_manager.user_loader
|
@login_manager.user_loader
|
||||||
|
|
|
||||||
|
|
@ -4,3 +4,5 @@ markdown
|
||||||
flask-login
|
flask-login
|
||||||
flask-wtf
|
flask-wtf
|
||||||
python-i18n
|
python-i18n
|
||||||
|
flask-arrest
|
||||||
|
python-dotenv
|
||||||
|
|
|
||||||
|
|
@ -13,8 +13,11 @@
|
||||||
<link rel="stylesheet" href="https://fonts.googleapis.com/icon?family=Material+Icons">
|
<link rel="stylesheet" href="https://fonts.googleapis.com/icon?family=Material+Icons">
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% block json_info %}{% endblock %}
|
{% block json_info %}{% endblock %}
|
||||||
|
{% block ldjson %}{% endblock %}
|
||||||
</head>
|
</head>
|
||||||
<body {% if request.cookies.get('dark') == '1' %}class="dark"{% endif %}>
|
<body {% if request.cookies.get('dark') == '1' -%}
|
||||||
|
class="dark"
|
||||||
|
{%- endif %}>
|
||||||
<div id="__top"></div>
|
<div id="__top"></div>
|
||||||
<header class="header">
|
<header class="header">
|
||||||
<span class="header-app-name"><a href="/">{{ app_name }}</a></span>
|
<span class="header-app-name"><a href="/">{{ app_name }}</a></span>
|
||||||
|
|
|
||||||
|
|
@ -15,33 +15,9 @@
|
||||||
<h2>{{ T('latest-notes') }}</h2>
|
<h2>{{ T('latest-notes') }}</h2>
|
||||||
|
|
||||||
<br style="clear:both">
|
<br style="clear:both">
|
||||||
<ul class="nl-list">
|
|
||||||
{% for n in new_notes %}
|
{% from "macros/nl.jinja2" import nl_list with context %}
|
||||||
<li>
|
{{ nl_list(new_notes) }}
|
||||||
<a href="{{ n.get_url() }}" class="nl-title">{{ n.title }}</a>
|
|
||||||
<p class="nl-desc">{{ n.short_desc() }}</p>
|
|
||||||
{% if n.tags %}
|
|
||||||
<p class="nl-tags">
|
|
||||||
<span class="material-icons">tag</span>
|
|
||||||
{{ T('tags') }}:
|
|
||||||
{% for tag in n.tags %}
|
|
||||||
{% set tn = tag.name %}
|
|
||||||
<a href="/tags/{{ tn }}/" class="nl-tag">#{{ tn }}</a>
|
|
||||||
{% endfor %}
|
|
||||||
</p>
|
|
||||||
{% endif %}
|
|
||||||
{% if n.calendar %}
|
|
||||||
<p class="nl-calendar">
|
|
||||||
<span class="material-icons">calendar_today</span>
|
|
||||||
<a href="/calendar/{{ n.calendar.year }}/{{ n.calendar.month }}">
|
|
||||||
<time datetime="{{ n.calendar.isoformat() }}">{{ n.calendar.strftime('%B %-d, %Y') }}</time>
|
|
||||||
</a>
|
|
||||||
</p>
|
|
||||||
{% endif %}
|
|
||||||
</li>
|
|
||||||
{% endfor %}
|
|
||||||
<li class="nl-next"><a href="/p/most_recent/">{{ T('show-all') }}</a></li>
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
</article>
|
</article>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -4,39 +4,7 @@
|
||||||
<article>
|
<article>
|
||||||
<h1 id="firstHeading">Notes by date</h1>
|
<h1 id="firstHeading">Notes by date</h1>
|
||||||
|
|
||||||
<p class="nl-pagination">Showing results <strong>{{ page_n * 20 - 19 }}</strong> to <strong>{{ min(page_n * 20, total_count) }}</strong> of <strong>{{ total_count }}</strong> total.</p>
|
{% from "macros/nl.jinja2" import nl_list with context %}
|
||||||
|
{{ nl_list(notes, page_n=page_n, total_count=total_count) }}
|
||||||
<ul class="nl-list">
|
|
||||||
{% if page_n > 1 %}
|
|
||||||
<li class="nl-prev"><a href="/p/most_recent/{{ page_n - 1 }}">« Previous page</a></li>
|
|
||||||
{% endif %}
|
|
||||||
{% for n in notes %}
|
|
||||||
<li>
|
|
||||||
<a href="{{ n.get_url() }}" class="nl-title">{{ n.title }}</a>
|
|
||||||
<p class="nl-desc">{{ n.short_desc() }}</p>
|
|
||||||
{% if n.tags %}
|
|
||||||
<p class="nl-tags">
|
|
||||||
<span class="material-icons">tag</span>
|
|
||||||
{{ T('tags') }}:
|
|
||||||
{% for tag in n.tags %}
|
|
||||||
{% set tn = tag.name %}
|
|
||||||
<a href="/tags/{{ tn }}/" class="nl-tag">#{{ tn }}</a>
|
|
||||||
{% endfor %}
|
|
||||||
</p>
|
|
||||||
{% endif %}
|
|
||||||
{% if n.calendar %}
|
|
||||||
<p class="nl-calendar">
|
|
||||||
<span class="material-icons">calendar_today</span>
|
|
||||||
<a href="/calendar/{{ n.calendar.year }}/{{ n.calendar.month }}">
|
|
||||||
<time datetime="{{ n.calendar.isoformat() }}">{{ n.calendar.strftime('%B %-d, %Y') }}</time>
|
|
||||||
</a>
|
|
||||||
</p>
|
|
||||||
{% endif %}
|
|
||||||
</li>
|
|
||||||
{% endfor %}
|
|
||||||
{% if page_n <= total_count // 20 %}
|
|
||||||
<li class="nl-next"><a href="/p/most_recent/{{ page_n + 1 }}/">Next page »</a></li>
|
|
||||||
{% endif %}
|
|
||||||
</ul>
|
|
||||||
</article>
|
</article>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
|
||||||
|
|
@ -8,42 +8,8 @@
|
||||||
<div class="preview-subtitle">{{ T('notes-tagged') }}</div>
|
<div class="preview-subtitle">{{ T('notes-tagged') }}</div>
|
||||||
|
|
||||||
{% if total_count > 0 %}
|
{% if total_count > 0 %}
|
||||||
<p class="nl-pagination">Showing results <strong>{{ page_n * 20 - 19 }}</strong> to <strong>{{ min(page_n * 20, total_count) }}</strong> of <strong>{{ total_count }}</strong> total.</p>
|
{% from "macros/nl.jinja2" import nl_list with context %}
|
||||||
|
{{ nl_list(l, page_n=page_n, total_count=total_count, hl_tags=(tagname,)) }}
|
||||||
<ul class="nl-list">
|
|
||||||
{% if page_n > 1 %}
|
|
||||||
<li class="nl-prev"><a href="/tags/{{ tagname }}/{{ page_n - 1 }}/">« Previous page</a></li>
|
|
||||||
{% endif %}
|
|
||||||
{% for n in tagged_notes %}
|
|
||||||
<li>
|
|
||||||
<a href="{{ n.get_url() }}" class="nl-title">{{ n.title }}</a>
|
|
||||||
<p class="nl-desc">{{ n.short_desc() }}</p>
|
|
||||||
<p class="nl-tags">
|
|
||||||
<span class="material-icons">tag</span>
|
|
||||||
{{ T('tags') }}:
|
|
||||||
{% for tag in n.tags %}
|
|
||||||
{% set tn = tag.name %}
|
|
||||||
{% if tn == tagname %}
|
|
||||||
<strong class="nl-tag-hl">#{{ tn }}</strong>
|
|
||||||
{% else %}
|
|
||||||
<a href="/tags/{{ tn }}/" class="nl-tag">#{{ tn }}</a>
|
|
||||||
{% endif %}
|
|
||||||
{% endfor %}
|
|
||||||
{% if n.calendar %}
|
|
||||||
<p class="nl-calendar">
|
|
||||||
<span class="material-icons">calendar_today</span>
|
|
||||||
<a href="/calendar/{{ n.calendar.year }}/{{ n.calendar.month }}">
|
|
||||||
<time datetime="{{ n.calendar.isoformat() }}">{{ n.calendar.strftime('%B %-d, %Y') }}</time>
|
|
||||||
</a>
|
|
||||||
</p>
|
|
||||||
{% endif %}
|
|
||||||
</p>
|
|
||||||
</li>
|
|
||||||
{% endfor %}
|
|
||||||
{% if page_n < total_count // 20 %}
|
|
||||||
<li class="nl-next"><a href="/tags/{{ tagname }}/{{ page_n + 1 }}/">Next page »</a></li>
|
|
||||||
{% endif %}
|
|
||||||
</ul>
|
|
||||||
{% else %}
|
{% else %}
|
||||||
<p class="nl-placeholder">{{ T('notes-tagged-empty') }}</p>
|
<p class="nl-placeholder">{{ T('notes-tagged-empty') }}</p>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
|
||||||
50
templates/macros/nl.jinja2
Normal file
50
templates/macros/nl.jinja2
Normal file
|
|
@ -0,0 +1,50 @@
|
||||||
|
|
||||||
|
|
||||||
|
{% macro nl_list(l, page_n=None, total_count=None, hl_tags=(), other_url='p/most_recent') %}
|
||||||
|
{% if page_n and total_count %}
|
||||||
|
<p class="nl-pagination">
|
||||||
|
Showing results <strong>{{ page_n * 20 - 19 }}</strong> to <strong>{{ min(page_n * 20, total_count) }}</strong>
|
||||||
|
of <strong>{{ total_count }}</strong> total.</p>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
<ul class="nl-list">
|
||||||
|
{% if page_n and page_n > 1 %}
|
||||||
|
<li class="nl-prev"><a href="/{{ other_url }}/?page={{ page_n - 1 }}">« Previous page</a></li>
|
||||||
|
{% endif %}
|
||||||
|
{% for n in l %}
|
||||||
|
<li>
|
||||||
|
<a href="{{ n.get_url() }}" class="nl-title">{{ n.title }}</a>
|
||||||
|
<p class="nl-desc">{{ n.short_desc() }}</p>
|
||||||
|
{% if n.tags %}
|
||||||
|
<p class="nl-tags">
|
||||||
|
<span class="material-icons">tag</span>
|
||||||
|
{{ T('tags') }}:
|
||||||
|
{% for tag in n.tags %}
|
||||||
|
{% set tn = tag.name %}
|
||||||
|
{% if tn in hl_tags %}
|
||||||
|
<strong class="nl-tag-hl">#{{ tn }}</strong>
|
||||||
|
{% else %}
|
||||||
|
<a href="/tags/{{ tn }}/" class="nl-tag">#{{ tn }}</a>
|
||||||
|
{% endif %}
|
||||||
|
{% endfor %}
|
||||||
|
</p>
|
||||||
|
{% endif %}
|
||||||
|
{% if n.calendar %}
|
||||||
|
<p class="nl-calendar">
|
||||||
|
<span class="material-icons">calendar_today</span>
|
||||||
|
<a href="/calendar/{{ n.calendar.year }}/{{ n.calendar.month }}">
|
||||||
|
<time datetime="{{ n.calendar.isoformat() }}">{{ n.calendar.strftime('%B %-d, %Y') }}</time>
|
||||||
|
</a>
|
||||||
|
</p>
|
||||||
|
{% endif %}
|
||||||
|
</li>
|
||||||
|
{% endfor %}
|
||||||
|
|
||||||
|
{% if page_n is none %}
|
||||||
|
<li class="nl-next"><a href="/{{ other_url }}/">{{ T('show-all') }}</a></li>
|
||||||
|
{% elif page_n <= total_count // 20 %}
|
||||||
|
<li class="nl-next"><a href="/{{ other_url }}/?page={{ page_n + 1 }}">Next page »</a></li>
|
||||||
|
{% endif %}
|
||||||
|
</ul>
|
||||||
|
{% endmacro %}
|
||||||
|
|
||||||
|
|
@ -21,11 +21,8 @@
|
||||||
{% if results %}
|
{% if results %}
|
||||||
<h2>Search results for <em>{{ q }}</em></h2>
|
<h2>Search results for <em>{{ q }}</em></h2>
|
||||||
|
|
||||||
<ul class="nl-list">
|
{% from "macros/nl.jinja2" import nl_list with context %}
|
||||||
{% for n in results %}
|
{{ nl_list(l, other_url=None) }}
|
||||||
<li>{% include "includes/nl_item.jinja2" %}</li>
|
|
||||||
{% endfor %}
|
|
||||||
</ul>
|
|
||||||
{% elif q %}
|
{% elif q %}
|
||||||
<h2>{{ T('search-no-results') }} <em>{{ q }}</em></h2>
|
<h2>{{ T('search-no-results') }} <em>{{ q }}</em></h2>
|
||||||
{% else %}
|
{% else %}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue