Insertion d'une image dans un template HTML

J’utilise les information de ce fil pour construire un publipostage :

Mon publipostage contient une image. Pour l’instant, la seule solution que j’ai trouvée est de l’intégrer au format base64 dans le template.
Néanmoins, ce template construit le code html utilisé dans le widget markdown pour chaque ligne (1300 dans ma table) et fait donc exploser la taille du fichier et grève ses performances.
Voyez-vous une façon plus économe de procéder ?
NB : je ne peux pas stocker cette image (signature) sur un espace ouvert

Si il est acceptable de rendre le document Grist public, il existe un moyen.

Via l’API publique

étape 1
Utiliser cette formule pour générer l’url

# extraction de l'url et de l'id du document
url, end = SELF_HYPERLINK().split("/o/docs")
doc_id = end.split("/")[1]
# extraction du premier attachment (changer le nom de la colonne si besoin)
if not $Signature:
    return None
attach_id = $Signature.id[0]
# utilisation de l'API pour visualiser la signature
return f"{url}/api/docs/{doc_id}/attachments/{attach_id}/download"

Étape 2: utiliser la syntaxe propre au markdown avec cette url dans le template, par exemple

Signature:
![]({signature})

Étape 3: ajouter la colonne de l’url généré dans le template.

Malheuresement, cette astuce d’accéder via l’API ne fonctionne que si le document est publique. Autrement, la partie de votre navigateur responsable d’afficher le markdown ne sait pas comment communiquer de manière sécurisée avec Grist.

En récupérant le « session ID » Voir une meilleure solution plus bas

Si vous cliquez sur l’attachment Grist et que vous regardez l’URL, vous observerez quelque chose comme:

https://grist.simone-de-beauvoir.indiehosters.net/dw/10-244-149-34/v/unknown/o/docs/attachment?clientId=08fc984fb604b837&docFD=0&name=bycicle.jpg&rowId=1&colId=A&tableId=Table1&maybeNew=1&attId=1

Grist ne propose pas de fonction pour générer cette url à partir de l’attachment, mais on peut le bricoler à la main.
Pour générer cette url, on a besoin de:

  • l’URL (:white_check_mark:, via SELF_HYPERLINK())
  • le chemin d’accès (:thinking: dw/10-244-149-34/v/unknown semble obscur, mais il ne devrait pas changer au cours du temps
  • le nom (:white_check_mark: via $Signature[0].fileName)
  • le rowId (:white_check_mark: via $Signature[0]._row_id)
  • la table (:white_check_mark: on la connait)
  • l’attribute ID (:white_check_mark: via $Signature.id)
  • le clientId (:x:)

Le problème, c’est le clientId. C’est un token qui est généré à la volée par Grist pour que le navigateur puisse afficher des images depuis un document non public.
Une procédure possible est celle ci:

  • créer une table spéciale Client_id_data avec une unique cellule qui accueillera une URL
  • à chaque connexion au document Grist, cliquer sur une des signatures, cliquer sur « copier le lien » et coller le résultat dans cette cellule
  • extraire la partie « clientID » de cette URL
  • utiliser cette donnée avec Client_id_data.lookupOne().cliend_id pour reconstituer l’URL

C’est un peu lourd et « hacky », mais c’est la seule possibilité que je connaisse.

En utilisant mon nouveau widget !

Je trouvé ce cas d’usage très intéressant, j’ai donc créé un widget pour remplir cette mission.
Il génère des liens à la volée pour les attachments. Je me suis inspiré de la documentation Grist: grist-plugin-api - Grist Help Center
Le widget est disponible ici. Normalement il est intuitif à utiliser.
https://rambip.github.io/grist-attachment-widgets

2 « J'aime »

Bonjour et merci du temps passé.
je suis pas mal occupé en ce moment et ai dû laisser ce problème de côté. Je regarde ce widget et vous fait un retour.
L’idéal, dans mon cas d’usage, serait de générer mon template html au besoin et pas dans chacune de mes 1300 cellules. Après, la fourniture du lien dans le template serait une bonne solution alternative.
Merci encore

Bonjour @Arnault, si tu as seulement quelques html à générer, tu pourrais ajouter une colonne booléen « Générer » à ta table, et ne construire le html que si le booléen est True. Dans la formule qui va chercher le html, tu retournerais None si Generer == False

Je vais mieux décrire mon cas d’usage car je me rend compte que je ne vous aide pas à bien comprendre et que je vous entraine peut-être dans des complications :smile:

Je développe une application qui permet d’affecter des personnes à des élèves. Ces élèves sont dans des établissements.
Je génère à partir de ces affectations, un état de service qui reprend les informations du couplage personne/établissement pour chaque personne affectée. J’ai utilisé le tuto d’@audezu (référence dans mon premier post) pour construire cet état de service et je suis parvenu à mes fins.
La démarche de ce post est de créer un template html et de faire appel à ce template où une formule construit le code html personnalisé dans une colonne. Ma formule est une formule d’initialisation qui se recalcule sur modification de quelques colonnes (modification de date ou d’établissement d’affectation). J’ai inséré ma signature en base64 dans le template mais elle est reproduite dans tous les enregistrements de ma table contenant la colonne html, ce qui fait exploser la taille de mon document.
Potentiellement, tous les html sont ou seront à générer. Dans l’idéal il faudrait qu’il ne soit générés que lorsque mes fameuses colonnes de déclenchement le demandent.
Après, si je peux insérer un lien dans le template, c’est aussi une solution.
Pas sûr d’être beaucoup plus clair.

@Antonin_P j’affiche bien une image en utilisant le lien https://rambip.github.io/grist-attachment-widgets/url-generator/ dans un custom widget mais je ne vois pas comment l’insérer dans mon template

C’est la même signature pour tous les html ? Dans ce cas, peux-tu la stocker dans une autre table et l’intégrer à ta formule html en l’appelant avec un lookupOne ?

Bon sang ! je creuse.

Bon, je ne trouve pas comment l’appeler. Ma signature est actuellement en base64 dans la colonne Signature dans la même table que le template, Menu_accueil
Voici le code que j’utilise dans mon autre table pour générer le html :

import datetime
import numbers

class Find_Data(dict):
  def __missing__(self, key):
    attr = getattr(rec, key)

    if attr is None:
      return ""

    if isinstance(attr, datetime.date):
      return attr.strftime('%d/%m/%Y')

    if isinstance(attr, numbers.Number):
      return round(attr, 2)

    return attr

# 1. Récupère le template et l'image depuis Menu_accueil
menu = Menu_accueil.lookupOne()
template = menu.Modele
signature = menu.Signature   # ← Use Signature

# 2. Prépare les données de publipostage
data = Find_Data()
data["Signature"] = signature  # ← Injection dans le template

# 3. Génère le document
template.format_map(data)

Il récupère bien l’image en base64 mais je ne vois pas où remplacer l’appel pour qu’il récupère l’image qui est en pièce jointe dans la colonne PJ de la table Menu_accueil

Re, tu peux y arriver avec ceci par ex :

# Classe utilisée pour la recherche des données
class Find_Data(dict):
  def __missing__(self, key):
    # Ignore le mapping pour la signature
    if key == "signature":
      return "{signature}" 
    else:
      return getattr(rec, key)
       

# 1. Récupère le modèle du document    
template = Template_simple.lookupOne().Modele

# 2. Formate le modèle avec les champs de la table actuelle
result = template.format_map(Find_Data())

#3. Remplace signature
sign = Template_simple.lookupOne().Signature
result = result.replace("{signature}", sign)

return result