Better URL handling, thanks to a new url_for() utility

This commit is contained in:
Daniel Atwood 2020-04-08 21:17:19 +02:00
parent 1c8a409e92
commit 90c0f037cd
16 changed files with 77 additions and 46 deletions

1
TODO
View file

@ -22,5 +22,4 @@ x Repasser sur les tests
x Changer les liens d'emergement, de paiements et ???, trouver de meilleurs dénominations
Faire un refactoring des modèles
Create an "url_for" utility to simplify URL management.

View file

@ -27,18 +27,18 @@
<h1 id="sitename">{{ config.SITE_NAME }}</h1>
<ul class="pure-menu-list">
<li class="pure-menu-item">
<a href="/"><i class="icon-happy"></i>&nbsp;Voir les distrib</a>
<a href="{{ url_for('home') }}"><i class="icon-happy"></i>&nbsp;Voir les distrib</a>
</li>
{% if request.user and request.user.is_staff %}
<li class="pure-menu-item">
<a href="/distribution"><i class="icon-hotairballoon"></i>&nbsp;Nouvelle distribution</a>
<a href="{{ url_for('new_delivery') }}"><i class="icon-hotairballoon"></i>&nbsp;Nouvelle distribution</a>
</li>
{% endif %}
<li class="pure-menu-item">
<a class="pure-menu-link" href="/groupes"><i class="icon-globe"></i>&nbsp;Gérer les groupes</a>
<a class="pure-menu-link" href="{{ url_for('groups') }}"><i class="icon-globe"></i>&nbsp;Gérer les groupes</a>
</li>
<li class="pure-menu-item">
<a href="/déconnexion" class="pure-menu-link"><i class="icon-lock"></i>&nbsp;Se déconnecter</a>
<a href="{{ url_for('logout') }}"><i class="icon-lock"></i>&nbsp;Se déconnecter</a>
</li>
</ul>
</div>

View file

@ -2,7 +2,7 @@
{% block body %}
<article>
<h3><a href="/distribution/{{ delivery.id }}">{{ delivery.producer }}</a> — Ajuster le produit «{{ product.name }}»</h3>
<h3><a href="{{ url_for('show_delivery', id=delivery.id) }}">{{ delivery.producer }}</a> — Ajuster le produit «{{ product.name }}»</h3>
<p><strong>Conditionnement</strong> {{ product.packing }} x {{ product.unit }}</p>
<p><strong>Total commandé</strong> {{ delivery.product_wanted(product) }}</p>
<p><strong>Manquant</strong> {{ delivery.product_missing(product) }}</p>

View file

@ -5,7 +5,7 @@
<div class="pure-menu pure-menu-horizontal">
<ul class="pure-menu-list">
<li class="pure-menu-item">
<a class="pure-menu-link" href="/distribution/{{ delivery.id }}/paiements.pdf">Télécharger</a>
<a class="pure-menu-link" href="{{ url_for('compute_payments', id=delivery.id) }}.pdf">Télécharger</a>
</li>
</ul>
</div>

View file

@ -1,5 +1,5 @@
{% extends "base.html" %}
{% block toplink %}{% if delivery.id %}<a href="/distribution/{{ delivery.id }}">↶ Retourner à la distribution</a>{% endif %}{% endblock %}
{% block toplink %}{% if delivery.id %}<a href="{{ url_for('show_delivery', id=delivery.id) }}">↶ Retourner à la distribution</a>{% endif %}{% endblock %}
{% block body %}
<div class="header">
{% if delivery.id %}
@ -8,11 +8,11 @@
<ul class="pure-menu-list">
{% if delivery.status == delivery.CLOSED %}
<li class="pure-menu-item">
<a class="pure-menu-link danger" href="/distribution/{{ delivery.id }}/archiver"><i class="icon-layers"></i>&nbsp;Archiver</a>
<a class="pure-menu-link danger" href="{{ url_for('archive_delivery', id=delivery.id) }}"><i class="icon-layers"></i>&nbsp;Archiver</a>
</li>
{% endif %}
<li class="pure-menu-item">
<a class="pure-menu-link" href="/produits/{{ delivery.id }}"><i class="icon-pencil"></i> Gérer les produits / product⋅eur⋅rice⋅s</a>
<a class="pure-menu-link" href="{{ url_for('list_products', id=delivery.id) }}"><i class="icon-pencil"></i> Gérer les produits / product⋅eur⋅rice⋅s</a>
</li>
</ul>
</div>

View file

@ -6,10 +6,10 @@
<div class="pure-menu pure-menu-horizontal">
<ul class="pure-menu-list">
<li class="pure-menu-item">
<a class="pure-menu-link" href="/distribution"><i class="icon-hotairballoon"></i>&nbsp;Créer une nouvelle distribution</a>&nbsp;
<a class="pure-menu-link" href="{{ url_for('new_delivery') }}"><i class="icon-hotairballoon"></i>&nbsp;Créer une nouvelle distribution</a>&nbsp;
</li>
<li class="pure-menu-item">
<a class="pure-menu-link" href="/archives"><i class="icon-telescope"></i>&nbsp;Voir les distributions archivées</a>&nbsp;
<a class="pure-menu-link" href="{{ url_for('list_archives') }}"><i class="icon-telescope"></i>&nbsp;Voir les distributions archivées</a>&nbsp;
</li>
</ul>
</div>

View file

@ -57,7 +57,7 @@
<input type="submit" value="Enregistrer la commande" class="primary">
{% endif %}
{% if request.user.is_staff and delivery.status == delivery.CLOSED %}
<a class="button danger" href="/distribution/{{ delivery.id }}/commander?email={{ person.email }}&adjust">Ajuster</a>
<a class="button danger" href="{{ url_for('place_order', id=delivery.id) }}?email={{ person.email }}&adjust">Ajuster</a>
{% endif %}
</form>
</article>

View file

@ -1,5 +1,5 @@
{% extends "base.html" %}
{% block toplink %}<a href="/distribution/{{ delivery.id }}/gérer">↶ Retourner à la boîte à outils</a>{% endblock %}
{% block toplink %}<a href="{{ url_for('show_delivery_toolbox', id=delivery.id) }}">↶ Retourner à la boîte à outils</a>{% endblock %}
{% block body %}
<h1>Envoi d'un mail aux référent⋅e⋅s</h1>
@ -13,7 +13,7 @@ Bonjour,
Et voilà, les commandes maintenant terminées, il est maintenant temps de passer à l'action !
En pièce-jointe, les informations pour les producteurs⋅rices dont tu est référent⋅e.
Tu peux aussi retrouver le doc à cette URL : https://{{ request.host }}/produits/{{ delivery.id }}
Tu peux aussi retrouver le doc à cette URL : https://{{ request.host }}{{ url_for('list_products', id=delivery.id) }}
Rendez-vous pour la distribution, le {{ delivery.from_date|date }} de {{ delivery.from_date|time }} à {{ delivery.to_date|time }} à {{ delivery.where }}.

View file

@ -21,26 +21,26 @@
<li class="pure-menu-item pure-menu-has-children pure-menu-allow-hover">
<a href="#" class="pure-menu-link"><i class="icon-printer"></i>&nbsp;Imprimer…</a>
<ul class="pure-menu-children">
<li class="pure-menu-item"><a href="/produits/{{ delivery.id }}/produits.pdf" class="pure-menu-link"><i class="icon-ribbon"></i>&nbsp;Commande producteurs⋅rices</a></li>
<li class="pure-menu-item"><a href="/distribution/{{ delivery.id }}/résumé-de-commandes" class="pure-menu-link"><i class="icon-grid"></i>&nbsp;Résumé de commande par groupe</a></li>
<li class="pure-menu-item"><a href="/distribution/{{ delivery.id }}/paiements" class="pure-menu-link"><i class="icon-wallet"></i>&nbsp;Répartition des paiements</a></li>
<li class="pure-menu-item"><a href="{{ url_for('list_products', id=delivery.id) }}/produits.pdf" class="pure-menu-link"><i class="icon-ribbon"></i>&nbsp;Commande producteurs⋅rices</a></li>
<li class="pure-menu-item"><a href="{{ url_for('orders_summary', id=delivery.id) }}" class="pure-menu-link"><i class="icon-grid"></i>&nbsp;Résumé de commande par groupe</a></li>
<li class="pure-menu-item"><a href="{{ url_for('compute_payments', id=delivery.id) }}" class="pure-menu-link"><i class="icon-wallet"></i>&nbsp;Répartition des paiements</a></li>
</ul>
</li>
{% if request['user'].email == delivery.contact and delivery.status > delivery.EMPTY %}
<li class="pure-menu-item"><a class="pure-menu-link" href="/distribution/{{ delivery.id }}/gérer"><i class="icon-tools"></i>&nbsp;Boîte à outils</a></li> {% endif %}
{% if request.user and request.user.is_staff %}
{% if delivery.is_archived %}
{% if request['user'].email == delivery.contact and delivery.status > delivery.EMPTY %}
<li class="pure-menu-item"><a class="pure-menu-link" href="{{ url_for('show_delivery_toolbox', id=delivery.id) }}"><i class="icon-tools"></i>&nbsp;Boîte à outils</a></li> {% endif %}
{% if request.user and request.user.is_staff %}
{% if delivery.is_archived %}
<li class="pure-menu-item">
<a class="pure-menu-link" href="/distribution/{{ delivery.id }}/désarchiver"><i class="icon-hazardous"></i>&nbsp;Désarchiver</a>
<a class="pure-menu-link" href="{{ url_for('unarchive_delivery', id=delivery.id) }}"><i class="icon-hazardous"></i>&nbsp;Désarchiver</a>
</li>
{% endif %}
{% endif %}
<li class="pure-menu-item">
<a class="pure-menu-link" href="/distribution/{{ delivery.id }}/edit"><i class="icon-adjustments"></i>&nbsp;Modifier la distrib</a>
<a class="pure-menu-link" href="{{ url_for('edit_delivery', id=delivery.id) }}"><i class="icon-adjustments"></i>&nbsp;Modifier la distrib</a>
</li>
<li class="pure-menu-item">
<a class="pure-menu-link" href="/produits/{{ delivery.id }}"><i class="icon-pricetags"></i>&nbsp;Produits</a>
<a class="pure-menu-link" href="{{ url_for('list_products', id=delivery.id) }}"><i class="icon-pricetags"></i>&nbsp;Produits</a>
</li>
{% endif %}
{% endif %}
</ul
</li>
</ul>
@ -54,7 +54,7 @@
{% if delivery.has_products %}
{% for (id, producer) in delivery.get_producers_for_referent(request.user.email).items() %}
{% if producer.needs_price_update(delivery) %}
<p class="notification info">Merci de <a href="/produits/{{ delivery.id }}/producteurs/{{ producer.id}}">mettre à jour les prix pour « {{ producer.name }} ».</a></p>
<p class="notification info">Merci de <a href="{{ url_for('edit_producer', delivery_id=delivery.id, producer_id=producer.id) }}">mettre à jour les prix pour « {{ producer.name }} ».</a></p>
{% endif %}
{% endfor %}
{% include "includes/delivery_table.html" %}
@ -64,8 +64,8 @@
{% if request.user and request.user.is_staff %}
Occupons-nous donc de ça ! Deux options :
<ol>
<li><a href="/produits/{{ delivery.id }}/producteurs/créer">Ajouter les product⋅eurs⋅rices</a> à la main ;</li>
<li>Ou bien <a href="/produits/{{ delivery.id }}/copier">copier les produits d'une autre distribution</a>.</li>
<li><a href="{{ url_for('create_producer', id=delivery.id) }}">Ajouter les product⋅eurs⋅rices</a> à la main ;</li>
<li>Ou bien <a href="{{ url_for('copy_products', id=delivery.id) }}">copier les produits d'une autre distribution</a>.</li>
</ol>
</div>
{% endif %}

View file

@ -1,6 +1,6 @@
{% extends "base.html" %}
{% block toplink %}<a href="/distribution/{{ delivery.id }}">↶ Retourner à la distribution</a>{% endblock %}
{% block toplink %}<a href="{{ url_for('show_delivery', id=delivery.id) }}">↶ Retourner à la distribution</a>{% endblock %}
{% block body %}
@ -46,19 +46,19 @@
<tr>
<th>Approvisionnements</th>
<td>Du {{ delivery.dates.adjustment_deadline | date }} au {{ delivery.dates.delivery_date | date }}</td>
<td><a href="/distribution/{{ delivery.id }}/envoi-email-referentes">Envoyer les infos de commande aux référent⋅e⋅s</a></td>
<td><a href="{{ url_for('send_referent_emails', id=delivery.id) }}">Envoyer les infos de commande aux référent⋅e⋅s</a></td>
<td>Faire les commandes aux producteurs⋅rices, <strong>récupérer les produits</strong></td>
</tr>
<tr>
<th>Préparation de la distribution</th>
<td>La veille du {{ delivery.dates.delivery_date | date }}</td>
<td><a href="/distribution/{{ delivery.id }}/résumé-de-commandes">Imprimer les bons de commandes par colocation</a></td>
<td><a href="{{ url_for('show_orders_summary', id=delivery.id) }}">Imprimer les bons de commandes par colocation</a></td>
<td></td>
</tr>
<tr>
<th>Distribution</th>
<td>{{ delivery.dates.delivery_date | date }}</td>
<td>Coordoner la distribution, <a href="/distribution/{{ delivery.id }}/paiements">faire la répartition des chèques</a></td>
<td>Coordoner la distribution, <a href="{{ url_for('compute_payments', id=delivery.id) }}">faire la répartition des chèques</a></td>
<td>Arriver 30mn avant le début de la distribution, répartir les produits par coloc</td>
</tr>
</tbody>

View file

@ -2,7 +2,7 @@
<ul class="delivery">
{% for delivery in deliveries %}
<li>
<h3><a href="/distribution/{{ delivery.id }}"><i class="icon-hotairballoon"></i> {{ delivery.name }}</a> {% include "includes/order_button.html" %} <a class="button" href="/distribution/{{ delivery.id }}">Voir les commandes</a></h3>
<h3><a href="{{ url_for('show_delivery', id=delivery.id) }}"><i class="icon-hotairballoon"></i> {{ delivery.name }}</a> {% include "includes/order_button.html" %} <a class="button" href="{{ url_for('show_delivery', id=delivery.id) }}">Voir les commandes</a></h3>
{% include "includes/delivery_head.html" %}
</li>
<hr>

View file

@ -18,6 +18,7 @@ class Response(RollResponse):
context["request"] = self.request
context["config"] = config
context["request"] = self.request
context["url_for"] = app.url_for
if self.request.cookies.get("message"):
context["message"] = json.loads(self.request.cookies["message"])
self.cookies.set("message", "")
@ -64,6 +65,17 @@ class Response(RollResponse):
self.cookies.set("message", json.dumps((text, status)))
def get_function_name(node):
if not node.payload:
return False
func = node.payload["GET"]
if hasattr(func, "decorates"):
return func.decorates.__name__
else:
return func.__name__
class Roll(BaseRoll):
Response = Response
@ -78,10 +90,29 @@ class Roll(BaseRoll):
def register_context(self, func):
self._context_func.append(func)
def url_for(self, view_name):
from pdb import set_trace
def _find_route_by_name(self, name, node=None):
node = node or self.routes.root
if get_function_name(node) == name:
return node
set_trace()
if node.edges:
for edge in node.edges:
if edge.child:
route = self._find_route_by_name(name, edge.child)
if route:
return route
def url_for(self, name, *args, **kwargs):
route = self._find_route_by_name(name)
if not route:
from pdb import set_trace
set_trace()
raise Exception(f"Route for '{name}' wasn't found")
try:
return route.path.format(*args, **kwargs)
except KeyError as e:
raise Exception(f"Unable to build URL for {name} : '{e}' is missing")
def staff_only(view):
@ -93,6 +124,7 @@ def staff_only(view):
return
return await view(request, response, *args, **kwargs)
decorator.decorates = view
return decorator

View file

@ -28,7 +28,7 @@ async def home(request, response):
@app.route("/archives", methods=["GET"])
async def view_archives(request, response):
async def list_archives(request, response):
response.html(
"delivery/list_archives.html", {"deliveries": Delivery.all(is_archived=True)}
)
@ -90,7 +90,7 @@ async def pdf_for_producer(request, response, id, producer):
@app.route("/distribution/{id}/gérer", methods=["GET"])
async def delivery_toolbox(request, response, id):
async def show_delivery_toolbox(request, response, id):
delivery = Delivery.load(id)
response.html(
"delivery/show_toolbox.html",
@ -174,7 +174,7 @@ async def post_delivery(request, response, id):
@app.route("/distribution/{id}", methods=["GET"])
async def view_delivery(request, response, id):
async def show_delivery(request, response, id):
delivery = Delivery.load(id)
response.html("delivery/show_delivery.html", {"delivery": delivery})
@ -273,7 +273,7 @@ async def place_order(request, response, id):
@app.route("/distribution/{id}/résumé-de-commandes", methods=["GET"])
async def orders_summary(request, response, id):
async def show_orders_summary(request, response, id):
delivery = Delivery.load(id)
response.pdf(
"delivery/show_orders_summary.html",
@ -324,7 +324,7 @@ async def adjust_product(request, response, id, ref):
@app.route("/distribution/{id}/paiements", methods=["GET"])
@app.route("/distribution/{id}/paiements.pdf", methods=["GET"])
@staff_only
async def delivery_balance(request, response, id):
async def compute_payments(request, response, id):
delivery = Delivery.load(id)
groups = request["groups"]

View file

@ -9,7 +9,7 @@ async def on_startup():
@app.route("/groupes", methods=["GET"])
async def handle_groups(request, response):
async def groups(request, response):
response.html("groups/list_groups.html", {"groups": request["groups"]})

View file

@ -34,7 +34,7 @@ async def auth_required(request, response):
@app.route("/connexion", methods=["GET"], unprotected=True)
async def sesame(request, response):
async def connexion(request, response):
response.html("login.html")

View file

@ -242,7 +242,7 @@ async def set_shipping_price(request, response, delivery_id, producer_id):
@app.route("/produits/{id}/copier", methods=["GET"])
async def copy_products_get(request, response, id):
async def copy_products(request, response, id):
deliveries = Delivery.all()
response.html("products/copy_products.html", {"deliveries": deliveries})