Bien sûr, les badges inclus sont… sympas. Il n’y a rien de mal à cela. Mais, que faire si vous en voulez plus ? Que faire si vous voulez aller au-delà de l’ensemble de symboles prédéfini ? Bien sûr, il y a une page d’administration où vous pouvez les télécharger. Mais que faire si vous voulez créer beaucoup de badges ?
Eh bien, bonne nouvelle ! Vous pouvez le faire via l’API. Voici un code Python montrant comment cela fonctionne. (Et il décerne le badge à la fin, pour faire bonne mesure.)
Cela devrait être assez facile à lire, même si vous n’êtes pas un programmeur Python. Vous pouvez même le reproduire avec curl sur la ligne de commande, si vous le souhaitez.
Cela suppose que votre clé API est dans une variable d’environnement DISCOURSE_API_KEY.
#!/usr/bin/python3
import os # Pour lire l'environnement
import sys # Pour quitter. :)
import hashlib # Pour le hachage de l'image
import requests # Fait tout le travail réel
# Informations sur le site et l'authentification
DISCOURSE = "discussion.fedoraproject.org"
DISCOURSE_API_USER = "mattdm"
DISCOURSE_API_KEY = os.getenv("DISCOURSE_API_KEY")
if not DISCOURSE_API_KEY:
print(f"Erreur : DISCOURSE_API_KEY doit être défini dans l'environnement", file=sys.stderr)
sys.exit(2)
# Informations pour votre badge. Vraisemblablement, dans une utilisation réelle, vous ne coderiez pas cela en dur.
NAME = "Apex"
IMAGE = "apex.png"
DESCRIPTION = "Bénédiction du FPL"
MORE = "Vous êtes génial et tout le monde devrait le savoir !"
TARGET_USER = "mattdm"
# Nos en-têtes d'authentification, ci-dessus.
HEADERS = {'Api-Key': DISCOURSE_API_KEY, 'Api-Username': DISCOURSE_API_USER}
# À partir de là, vous pouvez obtenir les identifiants et les descriptions des groupes de badges, et
# les différents types de badges. Si vous le souhaitez. Pas utilisé dans cet exemple.
r = requests.get(f"https://{DISCOURSE}/admin/badges.json", headers=HEADERS)
if r.status_code != 200:
print(f"Erreur lors de la récupération de la liste des badges : reçu {r.status_code}", file=sys.stderr)
sys.exit(1)
# Vérifier que le nom n'existe pas déjà.
# Il y a probablement une meilleure façon de faire cela, mais cela suffira.
if NAME in list(map(lambda x: x['name'], r.json()['badges'])):
print(f"Erreur : le badge '{NAME}' existe déjà.")
sys.exit(3)
# Lire l'image. Vous voudriez une meilleure gestion des erreurs ici dans un code réel !
with open(IMAGE, "rb") as f:
image_data = f.read()
# Il faudrait probablement faire quelques vérifications de base sur la
# taille/dimensions du fichier image juste à ce moment...
# Mais en tout cas, assembler un paquet d'informations à télécharger.
# La seule chose délicate ici est vraiment d'obtenir la somme de contrôle de l'image.
file_info = {'file_name': f'{IMAGE}',
'file_size': f'{len(image_data)}',
'type': 'badge_image',
'metadata[sha1-checksum]': hashlib.sha1(image_data).hexdigest(),
}
# Et demander à Discourse où l'envoyer.
r = requests.post(
f"https://{DISCOURSE}/uploads/generate-presigned-put", json=file_info, headers=HEADERS)
if r.status_code != 200:
print(
f"Erreur lors de la demande de l'emplacement de téléchargement de l'image : reçu {r.status_code}", file=sys.stderr)
sys.exit(1)
upload_url = r.json()['url']
upload_uid = r.json()['unique_identifier']
# Maintenant, mettez-le là où on nous a dit de le faire.
r = requests.put(upload_url, data=image_data)
if r.status_code != 200:
print(
f"Erreur lors du téléchargement de l'image vers le stockage externe : reçu {r.status_code}", file=sys.stderr)
sys.exit(1)
# Et dire à Discourse que cela a fonctionné, et obtenir un identifiant que nous pourrons référencer plus tard.
r = requests.post(f"https://{DISCOURSE}/uploads/complete-external-upload",
data=f'unique_identifier={upload_uid}', headers=HEADERS)
if r.status_code != 200:
print(f"Erreur lors de la finalisation du téléchargement : reçu {r.status_code}", file=sys.stderr)
sys.exit(1)
image_id = r.json()['id']
# Remarque : si vous souhaitez utiliser Font Awesome, laissez `image_upload_id` vide et
# définissez plutôt `icon` sur le nom Font Awesome correspondant. Et bien sûr,
# vous pouvez ignorer tout le processus de téléchargement de l'image dans ce cas !
badge = {'allow_title': 'true',
'multiple_grant': 'false',
'listable': 'true',
'show_posts': 'false',
'target_posts': 'false',
'name': f'{NAME}',
'description': f'{DESCRIPTION}',
'long_description': f'{DESCRIPTION} {MORE}',
'image_upload_id': f'{image_id}',
'badge_grouping_id': '5',
'badge_type_id': '1',
}
r = requests.post(
f"https://{DISCOURSE}/admin/badges.json", json=badge, headers=HEADERS)
if r.status_code != 200:
print(f"Erreur lors de la création du badge : reçu {r.status_code}", file=sys.stderr)
sys.exit(1)
badge_id = r.json()['badge']['id']
print(f'Le badge "{NAME}: {DESCRIPTION}" a été créé sous l\'identifiant {badge_id} !')
# Et pour être complet, décerner le badge !
# Vous pouvez également ajouter une "raison", qui doit être liée à un message ou à un sujet.
bestow = {'username': f"{TARGET_USER}", 'badge_id': f'{badge_id}'}
r = requests.post(f"https://{DISCOURSE}/user_badges",
json=bestow, headers=HEADERS)
if r.status_code != 200:
print(f"Erreur lors de l'attribution du badge : reçu {r.status_code}", file=sys.stderr)
sys.exit(1)
print(f'L\'utilisateur {TARGET_USER} s\'est vu décerner le nouveau badge !')