Merge pull request #19 from kianby/feature-improvements

Feature improvements
This commit is contained in:
Yax 2024-05-31 17:39:43 +02:00 committed by GitHub
commit 8d663c7ee7
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
9 changed files with 166 additions and 26 deletions

View file

@ -0,0 +1,17 @@
import configparser
import os
class Messages:
def __init__(self):
self.property_dict = {}
def load_messages(self, lang):
config = configparser.ConfigParser()
config.read(os.path.join(os.path.dirname(__file__), 'messages_' + lang + '.properties'))
for key, value in config.items('messages'):
self.property_dict[key] = value
def get(self, key):
return self.property_dict.get(key)

View file

@ -0,0 +1,6 @@
[messages]
login.failure.username=Username or password incorrect
logout.flash=You have been logged out.
admin.comment.notfound=Comment not found.
admin.comment.approved=Comment published.
admin.comment.deleted=Comment deleted.

View file

@ -0,0 +1,6 @@
[messages]
login.failure.username=Identifiant ou mot de passe incorrect
logout.flash=Vous avez été déconnecté.
admin.comment.notfound=Commentaire introuvable
admin.comment.approved=Commentaire publié
admin.comment.deleted=Commentaire supprimé

View file

@ -0,0 +1,64 @@
<!doctype html>
<html lang="en-US">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Stacosys Comment Moderation</title>
<link rel="stylesheet" href="https://cdn.simplecss.org/simple.min.css">
</head>
<body>
<header>
<h2>Comment Moderation</h2>
<nav>
<a href="/web/logout">Log out</a>
</nav>
</header>
<main>
{% with messages = get_flashed_messages() %}
{% if messages %}
<blockquote>
{% for message in messages %}
<p>{{ message }}</p>
{% endfor %}
</blockquote>
{% endif %}
{% endwith %}
<table>
<thead>
<tr>
<th>Date</th>
<th>Author</th>
<th>Comment</th>
<th>Article</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
{% for comment in comments %}
<tr>
<td>{{ comment.created }}</td>
<td>{{ comment.author_name }}</td>
<td>{{ comment.content }}</td>
<td><a href="{{ baseurl + comment.url }}">{{ comment.url }}</a></td>
<td>
<form action="/web/admin" method="post">
<input type="hidden" name="comment" value="{{comment.id}}">
<input type="hidden" name="action" value="APPROVE">
<button type="submit">Approve</button>
</form>
<form action="/web/admin" method="post">
<input type="hidden" name="comment" value="{{comment.id}}">
<input type="hidden" name="action" value="REJECT">
<button type="submit">Reject</button>
</form>
</td>
</tr>
{% endfor %}
</tbody>
</table>
</main>
<footer>
<p>This page was designed by Yax with <a href="https://simplecss.org">Simple.css</a>.</p>
</footer>
</body>
</html>

View file

@ -0,0 +1,42 @@
<!doctype html>
<html lang="en-US">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Stacosys</title>
<link rel="stylesheet" href="https://cdn.simplecss.org/simple.min.css">
<style>
form {
width: 350px;
margin: 0 auto;
text-align: center;
}
</style>
</head>
<body>
<header>
<h2>Comment Moderation Login</h2>
</header>
<main>
{% with messages = get_flashed_messages() %}
{% if messages %}
<blockquote>
{% for message in messages %}
<p>{{ message }}</p>
{% endfor %}
</blockquote>
{% endif %}
{% endwith %}
<form action="/web/login" method="POST">
<p><label>Username:</label></p>
<p><input type="text" name="username" /></p>
<p><label>Password:</label></p>
<p><input type="password" name="password" /></p>
<input type="submit" value="Log in" />
</form>
</main>
<footer>
<p>This page was designed with <a href="https://simplecss.org">Simple.css</a>.</p>
</footer>
</body>
</html>

View file

@ -37,8 +37,7 @@ def login():
if is_login_ok(username, password): if is_login_ok(username, password):
session["user"] = username session["user"] = username
return redirect("/web/admin") return redirect("/web/admin")
# TODO localization flash(app.config["MESSAGES"].get("login.failure.username"))
flash("Identifiant ou mot de passe incorrect")
return redirect("/web/login") return redirect("/web/login")
# GET # GET
return render_template( return render_template(
@ -49,6 +48,7 @@ def login():
@app.route("/web/logout", methods=["GET"]) @app.route("/web/logout", methods=["GET"])
def logout(): def logout():
session.pop("user") session.pop("user")
flash(app.config["MESSAGES"].get("logout.flash"))
return redirect("/web/admin") return redirect("/web/admin")
@ -58,8 +58,6 @@ def admin_homepage():
"user" in session "user" in session
and session["user"] == app.config["CONFIG"].get(ConfigParameter.WEB_USERNAME) and session["user"] == app.config["CONFIG"].get(ConfigParameter.WEB_USERNAME)
): ):
# TODO localization
flash("Vous avez été déconnecté.")
return redirect("/web/login") return redirect("/web/login")
comments = dao.find_not_published_comments() comments = dao.find_not_published_comments()
@ -74,15 +72,12 @@ def admin_homepage():
def admin_action(): def admin_action():
comment = dao.find_comment_by_id(request.form.get("comment")) comment = dao.find_comment_by_id(request.form.get("comment"))
if comment is None: if comment is None:
# TODO localization flash(app.config["MESSAGES"].get("admin.comment.notfound"))
flash("Commentaire introuvable")
elif request.form.get("action") == "APPROVE": elif request.form.get("action") == "APPROVE":
dao.publish_comment(comment) dao.publish_comment(comment)
app.config["RSS"].generate() app.config["RSS"].generate()
# TODO localization flash(app.config["MESSAGES"].get("admin.comment.approved"))
flash("Commentaire publié")
else: else:
dao.delete_comment(comment) dao.delete_comment(comment)
# TODO localization flash(app.config["MESSAGES"].get("admin.comment.deleted"))
flash("Commentaire supprimé")
return redirect("/web/admin") return redirect("/web/admin")

View file

@ -7,6 +7,7 @@ import os
import sys import sys
from stacosys.db import database from stacosys.db import database
from stacosys.i18n.messages import Messages
from stacosys.interface import api, app, form from stacosys.interface import api, app, form
from stacosys.interface.web import admin from stacosys.interface.web import admin
from stacosys.service.configuration import Config, ConfigParameter from stacosys.service.configuration import Config, ConfigParameter
@ -64,6 +65,12 @@ def configure_rss(config):
return rss return rss
def configure_localization(config):
messages = Messages()
messages.load_messages(config.get(ConfigParameter.LANG))
return messages
def main(config_pathname): def main(config_pathname):
logger = configure_logging() logger = configure_logging()
config = load_and_validate_config(config_pathname, logger) config = load_and_validate_config(config_pathname, logger)
@ -72,11 +79,13 @@ def main(config_pathname):
logger.info("Start Stacosys application") logger.info("Start Stacosys application")
rss = configure_rss(config) rss = configure_rss(config)
mailer = configure_and_validate_mailer(config, logger) mailer = configure_and_validate_mailer(config, logger)
messages = configure_localization(config)
logger.info("start interfaces %s %s %s", api, form, admin) logger.info("start interfaces %s %s %s", api, form, admin)
app.config["CONFIG"] = config app.config["CONFIG"] = config
app.config["MAILER"] = mailer app.config["MAILER"] = mailer
app.config["RSS"] = rss app.config["RSS"] = rss
app.config["MESSAGES"] = messages
app.run( app.run(
host=config.get(ConfigParameter.HTTP_HOST), host=config.get(ConfigParameter.HTTP_HOST),
port=config.get_int(ConfigParameter.HTTP_PORT), port=config.get_int(ConfigParameter.HTTP_PORT),

View file

@ -38,21 +38,22 @@ class Mailer:
def send(self, subject: str, message: str) -> bool: def send(self, subject: str, message: str) -> bool:
sender = self._smtp_login sender = self._smtp_login
receivers = [self._site_admin_email]
msg = MIMEText(message)
msg["Subject"] = subject
msg["To"] = self._site_admin_email
msg["From"] = sender
try: try:
msg = MIMEText(message)
msg["Subject"] = subject
msg["From"] = sender
msg["To"] = self._site_admin_email
with SMTP_SSL(self._smtp_host, self._smtp_port) as server: with SMTP_SSL(self._smtp_host, self._smtp_port) as server:
try:
server.login(self._smtp_login, self._smtp_password) server.login(self._smtp_login, self._smtp_password)
server.send_message(msg, sender, receivers)
return True
except SMTPAuthenticationError: except SMTPAuthenticationError:
logger.exception("Invalid credentials") logger.exception("Invalid credentials")
return False return False
except Exception as e:
logger.exception(f"Error sending email: {e}") server.send_message(msg)
return True
except Exception:
logger.error("Error sending email", exc_info=True)
return False return False

View file

@ -52,5 +52,5 @@ class Rss:
lastBuildDate=datetime.now(), lastBuildDate=datetime.now(),
items=items, items=items,
) )
# pylint: disable=consider-using-with with open(self._rss_file, "w", encoding="utf-8") as outfile:
rss.write_xml(open(self._rss_file, "w", encoding="utf-8"), encoding="utf-8") rss.write_xml(outfile, encoding="utf-8")