i18n
* Added class for internationalization to the project * Added English and German language files * Moved all strings to the language files * Translated to German * Added context processor to inject language file into every template
This commit is contained in:
parent
ad8f68cdd8
commit
1e3ce054a9
50
i18n/de-DE.json
Normal file
50
i18n/de-DE.json
Normal file
@ -0,0 +1,50 @@
|
||||
{
|
||||
"html_language": "de",
|
||||
"browser_language": "de-DE",
|
||||
"ok": "ok",
|
||||
"cancel": "abbrechen",
|
||||
"dashboard": "dashboard",
|
||||
"username": "benutzername",
|
||||
"password": "passwort",
|
||||
"login": "login",
|
||||
"logout": "abmelden",
|
||||
"comments": "kommentare",
|
||||
"unpublished": "unveröffentlicht",
|
||||
"published": "veröffentlicht",
|
||||
"spam": "spam",
|
||||
"edit": "editieren",
|
||||
"manage": "verwalten",
|
||||
"export": "export",
|
||||
"delete": "löschen",
|
||||
"new": "neu",
|
||||
"project": "projekt",
|
||||
"new_project": "neues projekt",
|
||||
"statistics": "statistiken",
|
||||
"address": "adresse",
|
||||
"status": "status",
|
||||
"manage_mail": "Mail Addressen verwalten",
|
||||
"manage_comments": "Kommentare verwalten",
|
||||
"manage_comments_delete_comment": "Diesen Kommentar löschen",
|
||||
"manage_comments_delete_and_block": "Diesen Kommentar löschen und EMail Adresse blocken.",
|
||||
"manage_comments_allow_comment": "Diesen Kommentar erlauben, aber Email Adresse nicht freischalten.",
|
||||
"manage_comments_allow_and_approve": "Diesen Kommentar erlauben und Email Adresse freischalten.",
|
||||
"manage_spam": "Spam verwalten",
|
||||
"select_article": "Artikel auswählen",
|
||||
"hooray_no_spam": "Hurra, kein Spam!",
|
||||
"spam_score": "Spamerkennung",
|
||||
"tooltip_spam_score": "Je höher der Spam Wert ist, desto höher die Chance, dass es sich um Spam handelt.",
|
||||
"stats_label_regular_comments": "reguläre Kommentare",
|
||||
"stats_label_unpublished_comments": "unveröffentlichte Kommentare",
|
||||
"stats_last_7_days": "Aktivität der letzten 7 Tage",
|
||||
"stats_total_percentage": "Verhältnis von Kommentaren zu Spam",
|
||||
"select_project_to_manage": "Projekte:",
|
||||
"tooltip_create_new_project": "Neues Projekt erzeugen",
|
||||
"tooltip_delete_project": "Projekt und dazugehörige Daten löschen",
|
||||
"tooltip_edit_project": "Einstellungen und Daten des Projekts ändern",
|
||||
"tooltip_export_all_comments": "Alle Kommentare nach Hugo exportieren.<br>Wird normalerweise nicht benötigt.",
|
||||
"tooltip_manage_this_project": "Dieses Projekt verwalten",
|
||||
"placeholder_search_mail": "Mail Adressen durchsuchen",
|
||||
"tooltip_email_blocked": "Email ist momentan gesperrt. Zum entsperren klicken.",
|
||||
"tooltip_email_allowed": "Email darf momentan ohne Bestätigung posten. Zum Sperren klicken.",
|
||||
"tooltip_delete_email": "Eintrag löschen. Email unterliegt wieder den normalen Regeln."
|
||||
}
|
49
i18n/en-US.json
Normal file
49
i18n/en-US.json
Normal file
@ -0,0 +1,49 @@
|
||||
{
|
||||
"html_language": "en",
|
||||
"browser_language": "en-US",
|
||||
"ok": "ok",
|
||||
"cancel": "cancel",
|
||||
"dashboard": "dashboard",
|
||||
"username": "username",
|
||||
"password": "password",
|
||||
"login": "login",
|
||||
"logout": "logout",
|
||||
"comments": "comments",
|
||||
"unpublished": "unpublished",
|
||||
"published": "published",
|
||||
"spam": "spam",
|
||||
"edit": "edit",
|
||||
"manage": "manage",
|
||||
"export": "export",
|
||||
"delete": "delete",
|
||||
"new": "new",
|
||||
"project": "project",
|
||||
"new_project": "new project",
|
||||
"statistics": "statistics",
|
||||
"address": "address",
|
||||
"status": "status",
|
||||
"manage_mail": "manage mail addresses",
|
||||
"stats_label_regular_comments": "regular comments",
|
||||
"stats_label_unpublished_comments": "unpublished comments",
|
||||
"stats_last_7_days": "Activity last 7 days",
|
||||
"stats_total_percentage": "Total comment - spam ratio",
|
||||
"manage_comments": "manage comments",
|
||||
"manage_comments_delete_comment": "Delete this comment",
|
||||
"manage_comments_delete_and_block": "Delete this comment and block mail address",
|
||||
"manage_comments_allow_comment": "Approve this comment, don't approve mail",
|
||||
"manage_comments_allow_and_approve": "Approve this comment and approve mail",
|
||||
"select_article": "Select article",
|
||||
"select_project_to_manage": "Projects",
|
||||
"hooray_no_spam": "Hooray, no Spam!",
|
||||
"spam_score": "score",
|
||||
"tooltip_spam_score": "The higher the spam score is, the more likely it is spam",
|
||||
"tooltip_create_new_project": "Create a new project",
|
||||
"tooltip_delete_project": "Delete the project and all of its content",
|
||||
"tooltip_edit_project": "Edit the name of the project and it's properties",
|
||||
"tooltip_export_all_comments": "Export all comments to Hugo.<br>This is normally not needed.",
|
||||
"tooltip_manage_this_project": "Manage this project",
|
||||
"placeholder_search_mail": "Search mail",
|
||||
"tooltip_email_blocked": "Email is currently blocked. Click to unblock.",
|
||||
"tooltip_email_allowed": "Email is currently excempt from spam detection. Click to block.",
|
||||
"tooltip_delete_email": "Delete entry, Email has to follow the regular rules."
|
||||
}
|
@ -13,7 +13,8 @@ from labertasche import (
|
||||
blueprints,
|
||||
helper,
|
||||
mail,
|
||||
settings
|
||||
settings,
|
||||
language
|
||||
)
|
||||
|
||||
_all_ = [
|
||||
@ -22,5 +23,6 @@ _all_ = [
|
||||
blueprints,
|
||||
helper,
|
||||
mail,
|
||||
settings
|
||||
settings,
|
||||
language
|
||||
]
|
||||
|
47
labertasche/language/__init__.py
Normal file
47
labertasche/language/__init__.py
Normal file
@ -0,0 +1,47 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
# /**********************************************************************************
|
||||
# * _author : Domeniko Gentner
|
||||
# * _mail : code@tuxstash.de
|
||||
# * _repo : https://git.tuxstash.de/gothseidank/labertasche
|
||||
# * _license : This project is under MIT License
|
||||
# *********************************************************************************/
|
||||
from flask import Request
|
||||
from pathlib import Path
|
||||
from json import load
|
||||
|
||||
|
||||
class Language:
|
||||
|
||||
def __init__(self, request: Request):
|
||||
# Define data
|
||||
self.i18n = dict()
|
||||
self.languages = list()
|
||||
|
||||
# Directory where translations live
|
||||
i18n_dir = Path('./i18n').absolute()
|
||||
|
||||
# Looks for translations
|
||||
for filename in i18n_dir.glob("*.json"):
|
||||
if filename.is_file():
|
||||
self.languages.append(filename.stem)
|
||||
|
||||
# Check the browser language in the headers
|
||||
self.browser_language = request.accept_languages.best_match(self.languages, default="en-US")
|
||||
|
||||
# Try to Load language accepted by browser
|
||||
try:
|
||||
file = i18n_dir / self.browser_language
|
||||
with file.with_suffix(".json").absolute().open('r', encoding='utf-8') as fp:
|
||||
foreign = load(fp)
|
||||
except FileNotFoundError:
|
||||
pass
|
||||
|
||||
# Always load english
|
||||
file = i18n_dir / "en-US"
|
||||
with file.with_suffix(".json").absolute().open('r', encoding='utf-8') as fp:
|
||||
self.i18n = load(fp)
|
||||
|
||||
# Merge dicts, so missing keys are replaced with English
|
||||
self.i18n.update(**foreign)
|
||||
|
20
server.py
20
server.py
@ -9,11 +9,12 @@
|
||||
# noinspection PyProtectedMember
|
||||
from sqlalchemy.engine import Engine
|
||||
from logging import getLogger, ERROR as LOGGING_ERROR
|
||||
from flask import Flask, redirect, url_for
|
||||
from flask import Flask, redirect, url_for, request
|
||||
from flask_cors import CORS
|
||||
from sqlalchemy import event, inspect
|
||||
from labertasche.settings import Settings, Secret
|
||||
from labertasche.database import labertasche_db
|
||||
from labertasche.language import Language
|
||||
from labertasche.blueprints import bp_comments, bp_login, bp_dashboard, bp_jsconnector, bp_dbupgrades
|
||||
from labertasche.helper import User
|
||||
from flask_login import LoginManager
|
||||
@ -36,15 +37,13 @@ laberflask.config.update(dict(
|
||||
SECRET_KEY=secret.key,
|
||||
TEMPLATES_AUTO_RELOAD=settings.debug,
|
||||
SQLALCHEMY_DATABASE_URI=settings.database_uri,
|
||||
SQLALCHEMY_TRACK_MODIFICATIONS=False
|
||||
SQLALCHEMY_TRACK_MODIFICATIONS=False,
|
||||
JSON_AS_ASCII=False
|
||||
))
|
||||
|
||||
# Mark secret for deletion
|
||||
del secret
|
||||
|
||||
# CORS
|
||||
cors = CORS(laberflask)
|
||||
|
||||
# Import blueprints
|
||||
laberflask.register_blueprint(bp_comments)
|
||||
laberflask.register_blueprint(bp_dashboard)
|
||||
@ -70,6 +69,10 @@ with laberflask.app_context():
|
||||
labertasche_db.create_all()
|
||||
|
||||
|
||||
# CORS
|
||||
cors = CORS(laberflask)
|
||||
|
||||
|
||||
# There is only one user
|
||||
@loginmgr.user_loader
|
||||
def user_loader(user_id):
|
||||
@ -92,3 +95,10 @@ def set_sqlite_pragma(dbapi_connection, connection_record):
|
||||
cursor = dbapi_connection.cursor()
|
||||
cursor.execute("PRAGMA journal_mode=WAL;")
|
||||
cursor.close()
|
||||
|
||||
|
||||
# Inject i18n dictionaries into all templates
|
||||
@laberflask.context_processor
|
||||
def inject_language():
|
||||
lang = Language(request)
|
||||
return {"i18n": lang.i18n}
|
||||
|
@ -1,5 +1,5 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<html lang="{{ i18n['html_language'] }}">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=5.0, user-scalable=yes">
|
||||
@ -8,33 +8,47 @@
|
||||
<link rel="stylesheet" href="/static/css/materialdesignicons.min.css" media="screen">
|
||||
<link rel="stylesheet" href="/static/css/Chart.min.css" media="screen">
|
||||
|
||||
<title>labertasche Dashboard</title>
|
||||
<title>Labertasche {{ i18n['dashboard'] | capitalize }}</title>
|
||||
</head>
|
||||
<body class="is-family-sans-serif">
|
||||
<body class="is-family-sans-serif" data-language="{{ i18n['browser_language'] }}">
|
||||
<nav class="navbar" role="navigation" aria-label="main navigation">
|
||||
<a class="navbar-item is-size-4" href="/">
|
||||
<span class="icon"><span class="mdi mdi-24px mdi-chart-bar"></span></span>
|
||||
Labertasche Dashboard
|
||||
<span class="icon"><span class="mdi mdi-24px mdi-home-group"></span></span>
|
||||
<span class="is-capitalized"> Labertasche {{ i18n['dashboard'] }}</span>
|
||||
</a>
|
||||
<div class="navbar-start"></div>
|
||||
<div class="navbar-start">
|
||||
</div>
|
||||
<div class="navbar-end">
|
||||
{% if project is defined %}
|
||||
<a class="navbar-item" href="/dashboard/{{ project }}/manage-spam/">
|
||||
<span class="icon"><i class="mdi mdi-24px mdi-space-invaders"></i></span>
|
||||
MANAGE SPAM
|
||||
<div class="navbar-item has-dropdown is-hoverable">
|
||||
<a class="navbar-link is-uppercase">
|
||||
<span class="icon"><i class="mdi mdi-24px mdi-comment-edit-outline"></i></span>
|
||||
<span class="is-uppercase"> {{ project }}</span>
|
||||
</a>
|
||||
<div class="navbar-dropdown">
|
||||
<a class="navbar-item" href="/dashboard/{{ project }}/">
|
||||
<span class="icon"><i class="mdi mdi-24px mdi-chart-box-outline"></i></span>
|
||||
<span class="is-uppercase"> {{ i18n['statistics'] }}</span>
|
||||
</a>
|
||||
<a class="navbar-item" href="/dashboard/{{ project }}/manage-comments/">
|
||||
<span class="icon"><i class="mdi mdi-24px mdi-comment"></i></span>
|
||||
MANAGE COMMENTS
|
||||
<span class="icon"><i class="mdi mdi-24px mdi-comment-check-outline"></i></span>
|
||||
<span class="is-uppercase"> {{ i18n['comments'] }}</span>
|
||||
</a>
|
||||
<a class="navbar-item" href="/dashboard/{{ project }}/manage-mail">
|
||||
<span class="icon"><i class="mdi mdi-24px mdi-email"></i></span>
|
||||
MANAGE EMAIL ADDRESSES
|
||||
<a class="navbar-item" href="/dashboard/{{ project }}/manage-spam/">
|
||||
<span class="icon"><i class="mdi mdi-24px mdi-comment-alert-outline"></i></span>
|
||||
<span class="is-uppercase"> {{ i18n['spam'] }}</span>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
<a class="navbar-item" href="/dashboard/{{ project }}/manage-mail">
|
||||
<span class="icon"><i class="mdi mdi-24px mdi-email-outline"></i></span>
|
||||
<span class="is-uppercase"> {{ i18n['manage_mail'] }}</span>
|
||||
</a>
|
||||
<!--suppress HtmlUnknownTarget -->
|
||||
<a class="navbar-item" href="/logout/">
|
||||
<span class="icon"><i class="mdi mdi-24px mdi-account-cancel"></i></span>
|
||||
LOGOUT
|
||||
<span class="is-uppercase"> {{ i18n['logout'] }}</span>
|
||||
</a>
|
||||
</div>
|
||||
</nav>
|
||||
@ -55,6 +69,11 @@
|
||||
if (urlParams.get("error") === "404"){
|
||||
show_modal('modal-project-not-found');
|
||||
}
|
||||
|
||||
tippy('[data-tippy-content]', {
|
||||
allowHTML: true,
|
||||
delay: 500
|
||||
});
|
||||
{% block javascript %}
|
||||
{% endblock %}
|
||||
});
|
||||
|
@ -1,5 +1,5 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<html lang="{{ i18n.browser_language }}">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=5.0, user-scalable=yes">
|
||||
@ -7,29 +7,28 @@
|
||||
<link rel="stylesheet" href="/static/css/labertasche.css" media="screen">
|
||||
<link rel="stylesheet" href="/static/css/materialdesignicons.min.css" media="screen">
|
||||
<link rel="stylesheet" href="/static/css/Chart.min.css" media="screen">
|
||||
|
||||
<title>labertasche Dashboard</title>
|
||||
<title>Labertasche {{ i18n['dashboard'] | capitalize }}</title>
|
||||
</head>
|
||||
<body>
|
||||
<section class="hero bg-yayellow is-fullheight">
|
||||
<div class="hero-head">
|
||||
<a target="_blank" href="https://github.com/domeniko-gentner/labertasche" rel="noopener nofollow noreferrer"
|
||||
class="button is-info is-inverted is-medium">
|
||||
class="button is-info is-inverted is-medium ml-1 mt-1 my-shadow-subtle">
|
||||
<span class="icon mr-2">
|
||||
<i class="mdi mdi-36px mdi-github"></i>
|
||||
</span>
|
||||
<span>Download</span>
|
||||
<span>Github</span>
|
||||
</a>
|
||||
</div>
|
||||
<div class="hero-body has-text-black">
|
||||
<div class="container has-text-centered">
|
||||
<p class="title">Labertasche Login</p>
|
||||
<p class="title">Labertasche {{ i18n['login'] | capitalize }}</p>
|
||||
<!--suppress HtmlUnknownTarget -->
|
||||
<form method="POST" action="/login">
|
||||
<div class="field">
|
||||
<div class="control is-expanded has-icons-left">
|
||||
<label for="username" class="help has-text-left has-text-black">
|
||||
<input class="input" name="username" type="text" placeholder="username">
|
||||
<input class="input" name="username" type="text" placeholder="{{ i18n['username'] | capitalize }}">
|
||||
</label>
|
||||
<span class="icon is-small is-left">
|
||||
<span class="mdi mdi-24px mdi-shield-account"></span>
|
||||
@ -39,7 +38,7 @@
|
||||
<div class="field">
|
||||
<div class="control is-expanded has-icons-left">
|
||||
<label for="password">
|
||||
<input class="input" name="password" type="password" placeholder="password">
|
||||
<input class="input" name="password" type="password" placeholder="{{ i18n['password'] | capitalize }}">
|
||||
</label>
|
||||
<span class="icon is-small is-left">
|
||||
<span class="mdi mdi-24px mdi-shield-key"></span>
|
||||
@ -52,6 +51,5 @@
|
||||
</div>
|
||||
<div class="hero-foot"></div>
|
||||
</section>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
@ -1,14 +1,18 @@
|
||||
{% extends "base.html" %}
|
||||
{% block main %}
|
||||
<div style="min-height: 100vh;" class="container bg-deepmatte p-6 brdr-yayellow">
|
||||
<h1 class="title has-text-white has-text-centered">{{ title }}</h1>
|
||||
{% if action == "spam" %}
|
||||
<h1 class="title has-text-white has-text-centered">{{ i18n['manage_spam'] }}</h1>
|
||||
{% else %}
|
||||
<h1 class="title has-text-white has-text-centered">{{ i18n['manage_comments'] }}</h1>
|
||||
{% endif %}
|
||||
<div class="field">
|
||||
<form method="GET" action="/dashboard/{{ project }}/manage-{{action}}/">
|
||||
<div class="control">
|
||||
<div class="select">
|
||||
<label for="location">
|
||||
<select name="location" onchange="this.form.submit();">
|
||||
<option value="-1">Select the article</option>
|
||||
<option value="-1">{{ i18n['select_article'] }}</option>
|
||||
{% for each in locations %}
|
||||
{% if selected is defined %}
|
||||
{% if selected | string() == each.id_location | string() %}
|
||||
@ -27,6 +31,13 @@
|
||||
</form>
|
||||
</div>
|
||||
<div>
|
||||
{% if locations | length == 0 %}
|
||||
{% if action == "spam" %}
|
||||
<div class="block">
|
||||
<p class="has-text-centered mt-5 is-size-2">{{ i18n['hooray_no_spam'] }}</p>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% if spam_comments is defined %}
|
||||
{% for comment in spam_comments %}
|
||||
<article>
|
||||
@ -38,32 +49,40 @@
|
||||
</figure>
|
||||
<div class="media-content">
|
||||
<div class="content mr-5 mt-2">
|
||||
<a title="comment ID" id="comment_{{comment.comments_id}}" href="#comment_{{comment.comments_id}}">#{{comment.comments_id}}</a>
|
||||
Posted by <span class="fg-yellow">{{comment.email}}</span>
|
||||
on <small class="fg-yellow">{{comment.created_on}}</small>
|
||||
spam score: <span title="The higher this is, the less likely it is spam" class="fg-yellow">{{ comment.spam_score }}</span>
|
||||
<a data-tippy-content="comment ID"
|
||||
id="comment_{{comment.comments_id}}"
|
||||
href="#comment_{{comment.comments_id}}">
|
||||
#{{comment.comments_id}}
|
||||
</a>
|
||||
<span class="fg-yellow">{{comment.email}}</span>
|
||||
<span class="fg-yellow">{{comment.created_on}}</span>
|
||||
{{ i18n['spam_score'] }}:
|
||||
<span data-tippy-content="{{ i18n['tooltip_spam_score'] }}"
|
||||
class="fg-yellow">
|
||||
{{ comment.spam_score | round(5) }}</span>
|
||||
{{ i18n['published'] }}: <span class="fg-yellow">{{ comment.is_published }}</span>
|
||||
<br><br>
|
||||
<span class="mt-5">
|
||||
{{comment.content}}
|
||||
</span>
|
||||
</div>
|
||||
<nav class="level is-mobile">
|
||||
<a title="Delete this comment"
|
||||
<a data-tippy-content="{{ i18n['manage_comments_delete_comment'] }}"
|
||||
class="level-item"
|
||||
href="/api/comment-delete/{{ comment.comments_id }}?location={{ selected }}">
|
||||
<span class="icon is-medium"><i class="mdi mdi-24px mdi-trash-can"></i></span>
|
||||
</a>
|
||||
<a title="Delete comment and block mail address"
|
||||
<a data-tippy-content="{{ i18n['manage_comments_delete_and_block'] }}"
|
||||
class="level-item"
|
||||
href="/api/comment-block-mail/{{ comment.comments_id }}?location={{ selected }}">
|
||||
<span class="icon is-medium"><i class="mdi mdi-24px mdi-shield-lock"></i></span>
|
||||
<span class="icon is-medium"><i class="mdi mdi-24px mdi-close-box"></i></span>
|
||||
</a>
|
||||
<a title="Publish this comment, don't allow mail"
|
||||
<a data-tippy-content="{{ i18n['manage_comments_allow_comment'] }}"
|
||||
class="level-item"
|
||||
href="/api/comment-allow/{{ comment.comments_id }}?location={{ selected }}">
|
||||
<span class="icon is-medium"><i class="mdi mdi-24px mdi-check"></i></span>
|
||||
</a>
|
||||
<a title="Allow email to bypass spam detection and allow comment"
|
||||
<a data-tippy-content="{{ i18n['manage_comments_allow_and_approve'] }}"
|
||||
class="level-item"
|
||||
href="/api/comment-allow-user/{{ comment.comments_id }}?location={{ selected }}">
|
||||
<span class="icon is-medium"><i class="mdi mdi-24px mdi-check-all"></i></span>
|
||||
|
@ -1,15 +1,16 @@
|
||||
{% extends "base.html" %}
|
||||
{% block main %}
|
||||
<div style="min-height: 100vh;" class="container bg-deepmatte p-6 brdr-yayellow">
|
||||
<h1 class="title has-text-white has-text-centered">Manage mail addresses</h1>
|
||||
<h1 class="title has-text-white has-text-centered">{{ i18n['manage_mail'] }}</h1>
|
||||
<div class="field">
|
||||
<div class="control has-icons-left">
|
||||
<input class="input"
|
||||
type="text"
|
||||
id="mail-search"
|
||||
oninput="dashboard_mailsearch(this);"
|
||||
placeholder="Search mail..."
|
||||
placeholder="{{ i18n['placeholder_search_mail'] }}..."
|
||||
aria-placeholder="type to search mail addresses">
|
||||
<label for="mail-search"></label>
|
||||
<span class="icon is-small is-left">
|
||||
<span class="mdi mdi-24px mdi-account-search"></span>
|
||||
</span>
|
||||
@ -19,8 +20,8 @@
|
||||
<table class="table is-fullwidth">
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="has-text-centered">Address</th>
|
||||
<th class="has-text-centered">Status</th>
|
||||
<th class="has-text-centered is-uppercase">{{ i18n['address'] }}</th>
|
||||
<th class="has-text-centered is-uppercase">{{ i18n['status'] }}</th>
|
||||
<th class="has-text-centered"></th>
|
||||
</tr>
|
||||
</thead>
|
||||
@ -31,13 +32,13 @@
|
||||
<td>
|
||||
<p class="has-text-centered">
|
||||
{% if each.is_blocked %}
|
||||
<a title="Email is currently blocked. Click to unblock."
|
||||
<a title="{{ i18n['tooltip_email_blocked'] }}"
|
||||
class="has-text-black"
|
||||
href="/api/mail-toggle-status/{{ each.id_email }}">
|
||||
<i class="mdi mdi-24px mdi-check"></i>
|
||||
</a>
|
||||
{% else %}
|
||||
<a title="Email is currently excempt from spam detection. Click to block."
|
||||
<a data-tippy-content="{{ i18n['tooltip_email_allowed'] }}"
|
||||
class="has-text-danger"
|
||||
href="/dashboard/toggle-mail-allowed/{{ each.id_email }}">
|
||||
<i class="mdi mdi-24px mdi-block-helper"></i>
|
||||
@ -47,7 +48,7 @@
|
||||
</td>
|
||||
<td>
|
||||
<p class="has-text-centered">
|
||||
<a title="Delete entry, this resets the reputation"
|
||||
<a data-tippy-content="{{ i18n['tooltip_delete_email'] }}"
|
||||
class="has-text-danger-dark"
|
||||
href="/api/mail-reset-reputation/{{ each.id_email }}">
|
||||
<i class="mdi mdi-24px mdi-trash-can"></i>
|
||||
|
@ -1,14 +1,14 @@
|
||||
{% extends "base.html" %}
|
||||
{% block main %}
|
||||
<div style="min-height: 100vh;" class="container bg-deepmatte p-6 brdr-yayellow">
|
||||
<h1 class="is-size-2 mb-3 is-uppercase">Select project</h1>
|
||||
<h1 class="is-size-2 mb-3 is-uppercase">{{ i18n['select_project_to_manage']}}</h1>
|
||||
<div class="columns is-multiline">
|
||||
<div class="column is-4">
|
||||
<div class="card my-shadow-subtle brdr-darkslate">
|
||||
<div class="card-header">
|
||||
<div class="card-header-title">
|
||||
<p class="is-size-4 is-uppercase">
|
||||
NEW PROJECT
|
||||
{{ i18n['new_project']}}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
@ -16,19 +16,19 @@
|
||||
<div class="level is-mobile">
|
||||
<div class="level-item has-text-centered">
|
||||
<div>
|
||||
<p class="heading is-capitalized">Comments</p>
|
||||
<p class="heading is-capitalized">{{ i18n['comments']}}</p>
|
||||
<p class="is-size-4 has-text-weight-bold has-text-white">n/a</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="level-item has-text-centered">
|
||||
<div>
|
||||
<p class="heading is-capitalized">Unpublished</p>
|
||||
<p class="heading is-capitalized">{{ i18n['unpublished']}}</p>
|
||||
<p class="is-size-4 has-text-weight-bold has-text-white">n/a</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="level-item has-text-centered">
|
||||
<div class="ml-4">
|
||||
<p class="heading is-capitalized">Spam</p>
|
||||
<p class="heading is-capitalized">{{ i18n['spam']}}</p>
|
||||
<p class="is-size-4 has-text-weight-bold has-text-white">n/a</p>
|
||||
</div>
|
||||
</div>
|
||||
@ -39,8 +39,8 @@
|
||||
<!-- TODO: onclick -->
|
||||
<a class="has-text-weight-bold has-text-black is-uppercase"
|
||||
onclick="show_modal_with_project('modal-project-edit', null)"
|
||||
data-tippy-content="Create a new project" href="#"
|
||||
>NEW</a>
|
||||
data-tippy-content="{{ i18n['tooltip_create_new_project'] }}" href="#"
|
||||
>{{ i18n['new']}}</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -59,19 +59,19 @@
|
||||
<div class="level is-mobile">
|
||||
<div class="level-item has-text-centered">
|
||||
<div>
|
||||
<p class="heading is-capitalized">Comments</p>
|
||||
<p class="heading is-capitalized">{{ i18n['comments']}}</p>
|
||||
<p class="is-size-4 has-text-weight-bold has-text-white">{{ each['total_comments'] }}</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="level-item has-text-centered">
|
||||
<div>
|
||||
<p class="heading is-capitalized">Unpublished</p>
|
||||
<p class="heading is-capitalized">{{ i18n['unpublished']}}</p>
|
||||
<p class="is-size-4 has-text-weight-bold has-text-white">{{ each['total_unpublished'] }}</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="level-item has-text-centered">
|
||||
<div class="ml-4">
|
||||
<p class="heading is-capitalized">Spam</p>
|
||||
<p class="heading is-capitalized">{{ i18n['spam']}}</p>
|
||||
<p class="is-size-4 has-text-weight-bold has-text-white">{{ each['total_spam'] }}</p>
|
||||
</div>
|
||||
</div>
|
||||
@ -80,25 +80,34 @@
|
||||
<div class="card-footer">
|
||||
<div class="card-footer-item has-background-danger-dark">
|
||||
<a class="has-text-weight-bold has-text-white is-uppercase"
|
||||
data-tippy-content="Delete the project and all of its content"
|
||||
onclick="show_modal('modal-project-delete', '{{ each['name'] }}');">DELETE</a>
|
||||
data-tippy-content="{{ i18n['tooltip_delete_project'] }}"
|
||||
onclick="show_modal('modal-project-delete', '{{ each['name'] }}');">
|
||||
{# {{ i18n['delete']}}#}
|
||||
<span class="icon"><span class="mdi mdi-24px mdi-delete"></span></span>
|
||||
</a>
|
||||
</div>
|
||||
<div class="card-footer-item">
|
||||
<a class="has-text-weight-bold has-text-black is-uppercase"
|
||||
onclick="show_modal_with_project('modal-project-edit', '{{ each['name'] }}');"
|
||||
data-tippy-content="Edit the name of the project and it's properties"
|
||||
href="#">EDIT</a>
|
||||
data-tippy-content="{{ i18n['tooltip_edit_project'] }}"
|
||||
href="#">
|
||||
<span class="icon"><span class="mdi mdi-24px mdi-database-edit"></span></span>
|
||||
</a>
|
||||
</div>
|
||||
<div class="card-footer-item">
|
||||
<a class="has-text-weight-bold has-text-black is-uppercase"
|
||||
onclick="show_modal('modal-comments-export', '{{ each['name'] }}')"
|
||||
data-tippy-content="Export all comments to Hugo.<br>This is normally not needed."
|
||||
href="#">EXPORT</a>
|
||||
data-tippy-content="{{ i18n['tooltip_export_all_comments'] }}"
|
||||
href="#">
|
||||
<span class="icon"><span class="mdi mdi-24px mdi-webhook"></span></span>
|
||||
</a>
|
||||
</div>
|
||||
<div class="card-footer-item">
|
||||
<a class="has-text-weight-bold has-text-black is-uppercase"
|
||||
data-tippy-content="Manage this project"
|
||||
href="{{ url_for('bp_dashboard.dashboard_project_stats', project=each['name']) }}">manage</a>
|
||||
data-tippy-content="{{ i18n['tooltip_manage_this_project'] }}"
|
||||
href="{{ url_for('bp_dashboard.dashboard_project_stats', project=each['name']) }}">
|
||||
<span class="icon"><span class="mdi mdi-24px mdi-view-comfy"></span></span>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -111,9 +120,3 @@
|
||||
{% include "modals/project_edit.html" %}
|
||||
{% include "modals/comments-export-all.html"%}
|
||||
{% endblock %}
|
||||
{% block javascript %}
|
||||
tippy('[data-tippy-content]', {
|
||||
allowHTML: true,
|
||||
delay: 500
|
||||
});
|
||||
{% endblock %}
|
||||
|
@ -1,37 +1,91 @@
|
||||
{% extends "base.html" %}
|
||||
{% block main %}
|
||||
<div style="min-height: 100vh;" class="container bg-deepmatte p-6 brdr-yayellow">
|
||||
<h1 class="title has-text-white has-text-centered">Overview</h1>
|
||||
<h1 class="title is-size-2 has-text-white has-text-centered is-uppercase">{{ i18n['statistics'] }}</h1>
|
||||
<div class="columns">
|
||||
<div class="column is-full">
|
||||
<p class="is-size-4 mb-4 mt-4">Last 7 days</p>
|
||||
<canvas id="chart-7d"></canvas>
|
||||
<p class="is-size-4 mb-4 mt-4">{{ i18n['stats_total_percentage'] }}</p>
|
||||
<canvas id="chart-total"
|
||||
data-spam="{{ total_spam }}"
|
||||
data-comments="{{ total_comments }}"
|
||||
data-unpublished="{{ total_unpublished }}">
|
||||
Your Browser does not support a HTML5 canvas :(.
|
||||
</canvas>
|
||||
</div>
|
||||
</div>
|
||||
<div class="columns">
|
||||
<div class="column is-full">
|
||||
<p class="is-size-4 mb-4 mt-4">{{ i18n['stats_last_7_days'] }}</p>
|
||||
<canvas id="chart-7d">Your Browser does not support a HTML5 canvas :(.</canvas>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<!--suppress JSValidateTypes -->
|
||||
<script>
|
||||
window.addEventListener('DOMContentLoaded', () => {
|
||||
let chart_total = document.getElementById('chart-total');
|
||||
|
||||
let total_spam = parseInt(chart_total.dataset.spam);
|
||||
let total_comments = parseInt(chart_total.dataset.comments);
|
||||
let total_unpublished = parseInt(chart_total.dataset.unpublished);
|
||||
let total = (total_spam + total_comments + total_unpublished);
|
||||
|
||||
let spam_perc = (total_spam/total) * 100;
|
||||
let comm_perc = (total_comments/total) * 100;
|
||||
let unpub_perc = (total_unpublished/total) * 100;
|
||||
|
||||
console.log(total);
|
||||
console.log(spam_perc);
|
||||
console.log(comm_perc);
|
||||
console.log(unpub_perc);
|
||||
|
||||
new Chart(document.getElementById('chart-total'), {
|
||||
type: "pie",
|
||||
data: {
|
||||
datasets: [{
|
||||
data: [spam_perc, comm_perc, unpub_perc],
|
||||
backgroundColor: [
|
||||
"rgba(182, 106, 254, 0.8)",
|
||||
"rgba(254, 218, 106, 0.8)",
|
||||
"rgba(108, 106, 254, 0.8)"
|
||||
],
|
||||
}
|
||||
],
|
||||
labels:[
|
||||
"{{ i18n['spam'] }}",
|
||||
"{{ i18n['stats_label_regular_comments'] }}",
|
||||
"{{ i18n['stats_label_unpublished_comments'] }}"
|
||||
]
|
||||
},
|
||||
options:{
|
||||
responsive: true,
|
||||
legend: {
|
||||
labels: {
|
||||
fontColor: 'white'
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
new Chart( document.getElementById('chart-7d'), {
|
||||
type: "line",
|
||||
data: {
|
||||
labels:[{% for days in dates %}"{{ days }}"{% if not loop.last %},{% endif %}{% endfor %}],
|
||||
datasets: [
|
||||
{
|
||||
label: "spam",
|
||||
label: "{{ i18n['spam'] }}",
|
||||
borderColor: "rgba(182, 106, 254, 1)",
|
||||
backgroundColor: "rgba(182, 106, 254, 0.1)",
|
||||
data: {{ spam }}
|
||||
},
|
||||
{
|
||||
label: "published comments",
|
||||
label: "{{ i18n['stats_label_regular_comments'] }}",
|
||||
borderColor: "rgba(254, 218, 106, 1)",
|
||||
backgroundColor: "rgba(254, 218, 106, 0.1)",
|
||||
data: {{published}}
|
||||
},
|
||||
{
|
||||
label: "unpublished comments",
|
||||
label: "{{ i18n['stats_label_unpublished_comments'] }}",
|
||||
borderColor: "rgba(108, 106, 254, 1)",
|
||||
backgroundColor: "rgba(108, 106, 254, 0.1)",
|
||||
data: {{ unpublished }}
|
||||
|
Loading…
x
Reference in New Issue
Block a user