Certo, le badge incluse sono… carine. Non c’è niente di sbagliato in esse. Ma, cosa succede se ne vuoi di più? Cosa succede se vuoi andare oltre il set di simboli predefinito? Certo, c’è una pagina di amministrazione dove puoi caricarle. Ma cosa succede se vuoi creare un sacco di badge?
Bene, buone notizie! Puoi farlo tramite l’API. Ecco il codice Python che mostra come funziona. (E alla fine assegna la badge, per sicurezza.)
Questo dovrebbe essere abbastanza facile da leggere anche se non sei un programmatore Python. Puoi persino replicarlo con curl dalla riga di comando, se ti piace.
Questo si aspetta che la tua chiave API sia in una variabile d’ambiente DISCOURSE_API_KEY.
#!/usr/bin/python3
import os # Per leggere l'ambiente
import sys # Per uscire. :)
import hashlib # Per l'hash dell'immagine
import requests # Fa tutto il lavoro vero
# Informazioni sul sito e autenticazione
DISCOURSE = "discussion.fedoraproject.org"
DISCOURSE_API_USER = "mattdm"
DISCOURSE_API_KEY = os.getenv("DISCOURSE_API_KEY")
if not DISCOURSE_API_KEY:
print(f"Errore: DISCOURSE_API_KEY deve essere impostato nell'ambiente", file=sys.stderr)
sys.exit(2)
# Informazioni per la tua badge. Presumibilmente, nell'uso reale non le codificheresti qui.
NAME = "Apex"
IMAGE = "apex.png"
DESCRIPTION = "Blessing of the FPL"
MORE = "You are awesome and everyone should know!"
TARGET_USER = "mattdm"
# Le nostre intestazioni di autenticazione, da sopra.
HEADERS = {'Api-Key': DISCOURSE_API_KEY, 'Api-Username': DISCOURSE_API_USER}
# Da qui, puoi ottenere gli ID e le descrizioni dei gruppi di badge, e
# i vari tipi di badge. Se vuoi. Non li uso in questo esempio.
r = requests.get(f"https://{DISCOURSE}/admin/badges.json", headers=HEADERS)
if r.status_code != 200:
print(f"Errore nel recuperare l'elenco delle badge: ottenuto {r.status_code}", file=sys.stderr)
sys.exit(1)
# Controlla che il nome non esista già.
# Probabilmente c'è un modo migliore per farlo, ma questo sarà sufficiente.
if NAME in list(map(lambda x: x['name'], r.json()['badges'])):
print(f"Errore: la badge '{NAME}' esiste già.")
sys.exit(3)
# Leggi l'immagine. Vorresti una migliore gestione degli errori qui nel codice reale!
with open(IMAGE, "rb") as f:
image_data = f.read()
# Probabilmente dovresti fare qualche controllo di sanità sulla
# dimensione/dimensioni del file immagine proprio qui....
# Ma comunque, assembla un pacchetto di informazioni su di esso da caricare.
# L'unica cosa complicata qui è ottenere il checksum dell'immagine.
file_info = {'file_name': f'{IMAGE}',
'file_size': f'{len(image_data)}',
'type': 'badge_image',
'metadata[sha1-checksum]': hashlib.sha1(image_data).hexdigest(),
}
# E chiedi a Discourse dove inviarlo.
r = requests.post(
f"https://{DISCOURSE}/uploads/generate-presigned-put", json=file_info, headers=HEADERS)
if r.status_code != 200:
print(
f"Errore nel chiedere dove caricare l'immagine: ottenuto {r.status_code}", file=sys.stderr)
sys.exit(1)
upload_url = r.json()['url']
upload_uid = r.json()['unique_identifier']
# Ora mettilo dove ci è stato detto di farlo.
r = requests.put(upload_url, data=image_data)
if r.status_code != 200:
print(
f"Errore nel caricare l'immagine nello storage esterno: ottenuto {r.status_code}", file=sys.stderr)
sys.exit(1)
# E comunica a Discourse che ha funzionato, e ottieni un ID che possiamo referenziare in seguito.
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"Errore nel completare il caricamento: ottenuto {r.status_code}", file=sys.stderr)
sys.exit(1)
image_id = r.json()['id']
# Nota: se vuoi usare font awesome, lascia vuoto `image_upload_id` e
# invece imposta `icon` al nome corrispondente di font awesome. E ovviamente
# puoi saltare tutto il caricamento dell'immagine in quel caso!
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"Errore nella creazione della badge: ottenuto {r.status_code}", file=sys.stderr)
sys.exit(1)
badge_id = r.json()['badge']['id']
print(f'La badge "{NAME}: {DESCRIPTION}" è stata creata come {badge_id}!')
# E per completezza, assegna la badge!
# Puoi anche aggiungere una "ragione", che deve collegarsi a un post o argomento.
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"Errore nell'assegnazione della badge: ottenuto {r.status_code}", file=sys.stderr)
sys.exit(1)
print(f'L\'utente {TARGET_USER} ha ricevuto la nuova badge!')