mirror of
https://github.com/almet/copanier.git
synced 2025-04-28 19:42:37 +02:00
For now, log all incoming POST
We want to be able to debug any issue during a command. Hint: DO MORE TESTS!
This commit is contained in:
parent
8227f1566c
commit
782c08d5ee
6 changed files with 51 additions and 53 deletions
|
@ -1,16 +1,14 @@
|
||||||
import csv
|
import csv
|
||||||
from datetime import timedelta
|
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from time import perf_counter
|
from time import perf_counter
|
||||||
|
|
||||||
import jwt
|
|
||||||
import ujson as json
|
import ujson as json
|
||||||
import minicli
|
import minicli
|
||||||
from jinja2 import Environment, PackageLoader, select_autoescape
|
from jinja2 import Environment, PackageLoader, select_autoescape
|
||||||
from roll import Roll, Response
|
from roll import Roll, Response
|
||||||
from roll.extensions import cors, options, traceback, simple_server, static
|
from roll.extensions import cors, options, traceback, simple_server, static
|
||||||
|
|
||||||
from . import config, reports, session, utils, emails
|
from . import config, reports, session, utils, emails, loggers
|
||||||
from .models import Delivery, Order, Person, Product, ProductOrder
|
from .models import Delivery, Order, Person, Product, ProductOrder
|
||||||
|
|
||||||
|
|
||||||
|
@ -72,46 +70,38 @@ cors(app, methods="*", headers="*")
|
||||||
options(app)
|
options(app)
|
||||||
|
|
||||||
|
|
||||||
def auth_required(view):
|
@app.listen("request")
|
||||||
async def redirect(request, response, *a, **k):
|
async def auth_required(request, response):
|
||||||
# FIXME do not return a view when Roll allows it.
|
if not request.route.payload.get("genuine"):
|
||||||
response.redirect = f"/sésame?next={request.path}"
|
|
||||||
|
|
||||||
def wrapper(request, response, *args, **kwargs):
|
|
||||||
token = request.cookies.get("token")
|
token = request.cookies.get("token")
|
||||||
email = None
|
email = None
|
||||||
if token:
|
if token:
|
||||||
decoded = read_token(token)
|
decoded = utils.read_token(token)
|
||||||
email = decoded.get("sub")
|
email = decoded.get("sub")
|
||||||
if not email:
|
if not email:
|
||||||
return redirect(request, response, *args, **kwargs)
|
response.redirect = f"/sésame?next={request.path}"
|
||||||
|
return response
|
||||||
user = Person(email=email)
|
user = Person(email=email)
|
||||||
request["user"] = user
|
request["user"] = user
|
||||||
session.user.set(user)
|
session.user.set(user)
|
||||||
return view(request, response, *args, **kwargs)
|
|
||||||
|
|
||||||
return wrapper
|
|
||||||
|
|
||||||
|
|
||||||
def create_token(email):
|
|
||||||
return jwt.encode(
|
|
||||||
{"sub": str(email), "exp": utils.utcnow() + timedelta(days=7)},
|
|
||||||
config.SECRET,
|
|
||||||
config.JWT_ALGORITHM,
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def read_token(token):
|
|
||||||
try:
|
|
||||||
return jwt.decode(token, config.SECRET, algorithms=[config.JWT_ALGORITHM])
|
|
||||||
except (jwt.DecodeError, jwt.ExpiredSignatureError):
|
|
||||||
return {}
|
|
||||||
|
|
||||||
|
|
||||||
@app.listen("request")
|
@app.listen("request")
|
||||||
async def attach_request(request, response):
|
async def attach_request(request, response):
|
||||||
response.request = request
|
response.request = request
|
||||||
|
|
||||||
|
@app.listen("request")
|
||||||
|
async def log_request(request, response):
|
||||||
|
if request.method == "POST":
|
||||||
|
message = {
|
||||||
|
"date": utils.utcnow().isoformat(),
|
||||||
|
"data": request.form,
|
||||||
|
"user": request.get("user"),
|
||||||
|
}
|
||||||
|
loggers.request_logger.info(
|
||||||
|
json.dumps(message, sort_keys=True, ensure_ascii=False)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
@app.listen("startup")
|
@app.listen("startup")
|
||||||
async def on_startup():
|
async def on_startup():
|
||||||
|
@ -119,15 +109,15 @@ async def on_startup():
|
||||||
Delivery.init_fs()
|
Delivery.init_fs()
|
||||||
|
|
||||||
|
|
||||||
@app.route("/sésame", methods=["GET"])
|
@app.route("/sésame", methods=["GET"], genuine=True)
|
||||||
async def sesame(request, response):
|
async def sesame(request, response):
|
||||||
response.html("sesame.html")
|
response.html("sesame.html")
|
||||||
|
|
||||||
|
|
||||||
@app.route("/sésame", methods=["POST"])
|
@app.route("/sésame", methods=["POST"])
|
||||||
async def send_sesame(request, response):
|
async def send_sesame(request, response, genuine=True):
|
||||||
email = request.form.get("email")
|
email = request.form.get("email")
|
||||||
token = create_token(email)
|
token = utils.create_token(email)
|
||||||
emails.send(
|
emails.send(
|
||||||
email,
|
email,
|
||||||
"Sésame Copanier",
|
"Sésame Copanier",
|
||||||
|
@ -137,9 +127,9 @@ async def send_sesame(request, response):
|
||||||
response.redirect = "/"
|
response.redirect = "/"
|
||||||
|
|
||||||
|
|
||||||
@app.route("/sésame/{token}", methods=["GET"])
|
@app.route("/sésame/{token}", methods=["GET"], genuine=True)
|
||||||
async def set_sesame(request, response, token):
|
async def set_sesame(request, response, token):
|
||||||
decoded = read_token(token)
|
decoded = utils.read_token(token)
|
||||||
if not decoded:
|
if not decoded:
|
||||||
response.message("Sésame invalide :(", status="error")
|
response.message("Sésame invalide :(", status="error")
|
||||||
else:
|
else:
|
||||||
|
@ -151,19 +141,16 @@ async def set_sesame(request, response, token):
|
||||||
|
|
||||||
|
|
||||||
@app.route("/", methods=["GET"])
|
@app.route("/", methods=["GET"])
|
||||||
@auth_required
|
|
||||||
async def home(request, response):
|
async def home(request, response):
|
||||||
response.html("home.html", incoming=Delivery.incoming(), former=Delivery.former())
|
response.html("home.html", incoming=Delivery.incoming(), former=Delivery.former())
|
||||||
|
|
||||||
|
|
||||||
@app.route("/livraison", methods=["GET"])
|
@app.route("/livraison", methods=["GET"])
|
||||||
@auth_required
|
|
||||||
async def new_delivery(request, response):
|
async def new_delivery(request, response):
|
||||||
response.html("edit_delivery.html", delivery={})
|
response.html("edit_delivery.html", delivery={})
|
||||||
|
|
||||||
|
|
||||||
@app.route("/livraison", methods=["POST"])
|
@app.route("/livraison", methods=["POST"])
|
||||||
@auth_required
|
|
||||||
async def create_delivery(request, response):
|
async def create_delivery(request, response):
|
||||||
form = request.form
|
form = request.form
|
||||||
data = {}
|
data = {}
|
||||||
|
@ -179,7 +166,6 @@ async def create_delivery(request, response):
|
||||||
|
|
||||||
|
|
||||||
@app.route("/livraison/{id}/importer/produits", methods=["POST"])
|
@app.route("/livraison/{id}/importer/produits", methods=["POST"])
|
||||||
@auth_required
|
|
||||||
async def import_products(request, response, id):
|
async def import_products(request, response, id):
|
||||||
delivery = Delivery.load(id)
|
delivery = Delivery.load(id)
|
||||||
delivery.products = []
|
delivery.products = []
|
||||||
|
@ -194,14 +180,12 @@ async def import_products(request, response, id):
|
||||||
|
|
||||||
|
|
||||||
@app.route("/livraison/{id}/edit", methods=["GET"])
|
@app.route("/livraison/{id}/edit", methods=["GET"])
|
||||||
@auth_required
|
|
||||||
async def edit_delivery(request, response, id):
|
async def edit_delivery(request, response, id):
|
||||||
delivery = Delivery.load(id)
|
delivery = Delivery.load(id)
|
||||||
response.html("edit_delivery.html", {"delivery": delivery})
|
response.html("edit_delivery.html", {"delivery": delivery})
|
||||||
|
|
||||||
|
|
||||||
@app.route("/livraison/{id}/edit", methods=["POST"])
|
@app.route("/livraison/{id}/edit", methods=["POST"])
|
||||||
@auth_required
|
|
||||||
async def post_delivery(request, response, id):
|
async def post_delivery(request, response, id):
|
||||||
delivery = Delivery.load(id)
|
delivery = Delivery.load(id)
|
||||||
form = request.form
|
form = request.form
|
||||||
|
@ -216,14 +200,12 @@ async def post_delivery(request, response, id):
|
||||||
|
|
||||||
|
|
||||||
@app.route("/livraison/{id}", methods=["GET"])
|
@app.route("/livraison/{id}", methods=["GET"])
|
||||||
@auth_required
|
|
||||||
async def view_delivery(request, response, id):
|
async def view_delivery(request, response, id):
|
||||||
delivery = Delivery.load(id)
|
delivery = Delivery.load(id)
|
||||||
response.html("delivery.html", {"delivery": delivery})
|
response.html("delivery.html", {"delivery": delivery})
|
||||||
|
|
||||||
|
|
||||||
@app.route("/livraison/{id}/commander", methods=["POST", "GET"])
|
@app.route("/livraison/{id}/commander", methods=["POST", "GET"])
|
||||||
@auth_required
|
|
||||||
async def place_order(request, response, id):
|
async def place_order(request, response, id):
|
||||||
delivery = Delivery.load(id)
|
delivery = Delivery.load(id)
|
||||||
email = request.query.get("email", None)
|
email = request.query.get("email", None)
|
||||||
|
@ -269,7 +251,6 @@ async def place_order(request, response, id):
|
||||||
|
|
||||||
|
|
||||||
@app.route("/livraison/{id}/courriel", methods=["GET"])
|
@app.route("/livraison/{id}/courriel", methods=["GET"])
|
||||||
@auth_required
|
|
||||||
async def send_order(request, response, id):
|
async def send_order(request, response, id):
|
||||||
delivery = Delivery.load(id)
|
delivery = Delivery.load(id)
|
||||||
email = request.query.get("email")
|
email = request.query.get("email")
|
||||||
|
@ -285,14 +266,12 @@ async def send_order(request, response, id):
|
||||||
|
|
||||||
|
|
||||||
@app.route("/livraison/{id}/émargement", methods=["GET"])
|
@app.route("/livraison/{id}/émargement", methods=["GET"])
|
||||||
@auth_required
|
|
||||||
async def signing_sheet(request, response, id):
|
async def signing_sheet(request, response, id):
|
||||||
delivery = Delivery.load(id)
|
delivery = Delivery.load(id)
|
||||||
response.html("signing_sheet.html", {"delivery": delivery})
|
response.html("signing_sheet.html", {"delivery": delivery})
|
||||||
|
|
||||||
|
|
||||||
@app.route("/livraison/{id}/importer/commande", methods=["POST"])
|
@app.route("/livraison/{id}/importer/commande", methods=["POST"])
|
||||||
@auth_required
|
|
||||||
async def import_commande(request, response, id):
|
async def import_commande(request, response, id):
|
||||||
email = request.form.get("email")
|
email = request.form.get("email")
|
||||||
order = Order()
|
order = Order()
|
||||||
|
@ -311,7 +290,6 @@ async def import_commande(request, response, id):
|
||||||
|
|
||||||
|
|
||||||
@app.route("/livraison/{id}/rapport.xlsx", methods=["GET"])
|
@app.route("/livraison/{id}/rapport.xlsx", methods=["GET"])
|
||||||
@auth_required
|
|
||||||
async def xls_report(request, response, id):
|
async def xls_report(request, response, id):
|
||||||
delivery = Delivery.load(id)
|
delivery = Delivery.load(id)
|
||||||
response.body = reports.summary(delivery)
|
response.body = reports.summary(delivery)
|
||||||
|
@ -321,7 +299,6 @@ async def xls_report(request, response, id):
|
||||||
|
|
||||||
|
|
||||||
@app.route("/livraison/{id}/rapport-complet.xlsx", methods=["GET"])
|
@app.route("/livraison/{id}/rapport-complet.xlsx", methods=["GET"])
|
||||||
@auth_required
|
|
||||||
async def xls_full_report(request, response, id):
|
async def xls_full_report(request, response, id):
|
||||||
delivery = Delivery.load(id)
|
delivery = Delivery.load(id)
|
||||||
response.body = reports.full(delivery)
|
response.body = reports.full(delivery)
|
||||||
|
|
|
@ -2,6 +2,7 @@ import os
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
DATA_ROOT = Path(__file__).parent.parent / "db"
|
DATA_ROOT = Path(__file__).parent.parent / "db"
|
||||||
|
LOG_ROOT = Path("/tmp")
|
||||||
SECRET = "sikretfordevonly"
|
SECRET = "sikretfordevonly"
|
||||||
JWT_ALGORITHM = "HS256"
|
JWT_ALGORITHM = "HS256"
|
||||||
SEND_EMAILS = False
|
SEND_EMAILS = False
|
||||||
|
|
|
@ -43,7 +43,7 @@ def send_order(env, person, delivery, order):
|
||||||
)
|
)
|
||||||
send(
|
send(
|
||||||
person.email,
|
person.email,
|
||||||
f"Copanier: résumé de la commande {delivery.producer}",
|
f"Copanier: résumé de votre commande {delivery.producer}",
|
||||||
body=txt,
|
body=txt,
|
||||||
html=html,
|
html=html,
|
||||||
)
|
)
|
||||||
|
|
|
@ -1,5 +1,24 @@
|
||||||
from datetime import datetime, timezone
|
from datetime import datetime, timezone, timedelta
|
||||||
|
|
||||||
|
import jwt
|
||||||
|
|
||||||
|
from . import config
|
||||||
|
|
||||||
|
|
||||||
def utcnow():
|
def utcnow():
|
||||||
return datetime.now(timezone.utc)
|
return datetime.now(timezone.utc)
|
||||||
|
|
||||||
|
|
||||||
|
def create_token(email):
|
||||||
|
return jwt.encode(
|
||||||
|
{"sub": str(email), "exp": utcnow() + timedelta(days=7)},
|
||||||
|
config.SECRET,
|
||||||
|
config.JWT_ALGORITHM,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def read_token(token):
|
||||||
|
try:
|
||||||
|
return jwt.decode(token, config.SECRET, algorithms=[config.JWT_ALGORITHM])
|
||||||
|
except (jwt.DecodeError, jwt.ExpiredSignatureError):
|
||||||
|
return {}
|
||||||
|
|
|
@ -173,6 +173,7 @@ def upload_env():
|
||||||
"""
|
"""
|
||||||
vars_ = {
|
vars_ = {
|
||||||
"COPANIER_DATA_ROOT": "/srv/copanier/data",
|
"COPANIER_DATA_ROOT": "/srv/copanier/data",
|
||||||
|
"COPANIER_LOG_ROOT": "/srv/copanier/log",
|
||||||
"COPANIER_SEND_EMAILS": "1",
|
"COPANIER_SEND_EMAILS": "1",
|
||||||
"COPANIER_SMTP_PASSWORD": None,
|
"COPANIER_SMTP_PASSWORD": None,
|
||||||
"COPANIER_SMTP_LOGIN": None,
|
"COPANIER_SMTP_LOGIN": None,
|
||||||
|
|
|
@ -7,7 +7,7 @@ from roll.testing import Client as BaseClient
|
||||||
|
|
||||||
from copanier import app as copanier_app
|
from copanier import app as copanier_app
|
||||||
from copanier import config as kconfig
|
from copanier import config as kconfig
|
||||||
from copanier import create_token
|
from copanier.utils import create_token
|
||||||
from copanier.models import Delivery, Person, Product
|
from copanier.models import Delivery, Person, Product
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue