Erstellen Sie ein benutzerdefiniertes Abzeichen mit einem Bild über die API

Sicher, die enthaltenen Abzeichen sind … nett. An ihnen ist absolut nichts auszusetzen. Aber was, wenn Sie mehr wollen? Was, wenn Sie über den vordefinierten Symbolsatz hinausgehen möchten? Sicher, es gibt eine Admin-Seite, auf der Sie sie hochladen können. Aber was, wenn Sie eine ganze Menge Abzeichen erstellen möchten?

Nun, gute Nachrichten! Sie können dies über die API tun. Hier ist Python-Code, der zeigt, wie es funktioniert. (Und er verleiht das Abzeichen am Ende, zur Sicherheit.)

Dies sollte ziemlich einfach zu lesen sein, auch wenn Sie kein Python-Programmierer sind. Sie können es sogar mit curl auf der Kommandozeile replizieren, wenn Sie möchten.

Dies erwartet, dass Ihr API-Schlüssel in einer Umgebungsvariable DISCOURSE_API_KEY vorhanden ist.

#!/usr/bin/python3

import os         # Zum Lesen der Umgebung
import sys        # Zum Beenden. :)
import hashlib    # Für den Bild-Hash

import requests   # Erledigt die eigentliche Arbeit


# Website- und Authentifizierungsinformationen
DISCOURSE = "discussion.fedoraproject.org"
DISCOURSE_API_USER = "mattdm"
DISCOURSE_API_KEY = os.getenv("DISCOURSE_API_KEY")
if not DISCOURSE_API_KEY:
    print(f"Fehler: DISCOURSE_API_KEY muss in der Umgebung gesetzt sein", file=sys.stderr)
    sys.exit(2)

# Informationen für Ihr Abzeichen. Vermutlich würden Sie dies in der realen Anwendung nicht fest codieren.
NAME = "Apex"
IMAGE = "apex.png"
DESCRIPTION = "Segen des FPL"
MORE = "Du bist großartig und jeder sollte es wissen!"
TARGET_USER = "mattdm"

# Unsere Authentifizierungsheader von oben.
HEADERS = {'Api-Key': DISCOURSE_API_KEY, 'Api-Username': DISCOURSE_API_USER}

# Von hier aus können Sie die IDs und Beschreibungen von Abzeichensammlungen und
# die verschiedenen Abzeichentypen abrufen. Wenn Sie möchten. In diesem Beispiel wird dies nicht verwendet.
r = requests.get(f"https://{DISCOURSE}/admin/badges.json", headers=HEADERS)
if r.status_code != 200:
    print(f"Fehler beim Abrufen der Abzeichenliste: Erhalten {r.status_code}", file=sys.stderr)
    sys.exit(1)

# Prüfen, ob der Name nicht bereits existiert.
# Wahrscheinlich gibt es eine bessere Methode, aber diese reicht aus.
if NAME in list(map(lambda x: x['name'], r.json()['badges'])):
    print(f"Fehler: Abzeichen '{NAME}' existiert bereits.")
    sys.exit(3)

# Bild lesen. In echtem Code würden Sie hier eine bessere Fehlerbehandlung wünschen!
with open(IMAGE, "rb") as f:
    image_data = f.read()

# Wahrscheinlich sollten Sie hier einige Plausibilitätsprüfungen für die
# Bildgröße/Dimensionen durchführen....

# Aber trotzdem, stellen Sie ein Informationspaket darüber zusammen, um es hochzuladen.
# Das einzig wirklich knifflige hier ist, die Prüfsumme des Bildes zu erhalten.
file_info = {'file_name': f'{IMAGE}',
             'file_size': f'{len(image_data)}',
             'type': 'badge_image',
             'metadata[sha1-checksum]': hashlib.sha1(image_data).hexdigest(),
             }


# Und fragen Sie Discourse, wohin es gesendet werden soll.
r = requests.post(
    f"https://{DISCOURSE}/uploads/generate-presigned-put", json=file_info, headers=HEADERS)
if r.status_code != 200:
    print(
        f"Fehler beim Anfragen, wohin das Bild hochgeladen werden soll: Erhalten {r.status_code}", file=sys.stderr)
    sys.exit(1)

upload_url = r.json()['url']
upload_uid = r.json()['unique_identifier']

# Jetzt legen Sie es dorthin, wo es uns gesagt wurde.
r = requests.put(upload_url, data=image_data)
if r.status_code != 200:
    print(
        f"Fehler beim Hochladen des Bildes in den externen Speicher: Erhalten {r.status_code}", file=sys.stderr)
    sys.exit(1)

# Und teilen Sie Discourse mit, dass es funktioniert hat, und erhalten Sie eine ID zurück, auf die wir später verweisen können.
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"Fehler beim Abschließen des Uploads: Erhalten {r.status_code}", file=sys.stderr)
    sys.exit(1)
image_id = r.json()['id']


# Hinweis: Wenn Sie Font Awesome verwenden möchten, lassen Sie `image_upload_id` leer und
# setzen Sie stattdessen `icon` auf den entsprechenden Font Awesome-Namen. Und natürlich
# können Sie sich in diesem Fall den gesamten Bild-Upload-Aufwand sparen!
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"Fehler beim Erstellen des Abzeichens: Erhalten {r.status_code}", file=sys.stderr)
    sys.exit(1)

badge_id = r.json()['badge']['id']

print(f'Abzeichen "{NAME}: {DESCRIPTION}" wurde als {badge_id} erstellt!')


# Und zur Vollständigkeit, verleihen Sie das Abzeichen!

# Sie können auch einen "Grund" hinzufügen, der auf einen Beitrag oder ein Thema verweisen muss.
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"Fehler beim Verleihen des Abzeichens: Erhalten {r.status_code}", file=sys.stderr)
    sys.exit(1)

print(f'Benutzer {TARGET_USER} hat das neue Abzeichen erhalten!')

7 „Gefällt mir“

Leider benötigen Sie dafür einen globalen Admin-API-Schlüssel. Ich hoffe, das Team wird eine Möglichkeit implementieren, granulare Prüfungen für Upload-Rechte, die Erstellung und Bearbeitung von Abzeichen sowie die Zuweisung und Entfernung von Abzeichen vorzunehmen.

Sie benötigen keinen globalen Admin-API-Schlüssel mehr dafür – bei der Erstellung eines API-Schlüssels können Sie verschiedene spezifische Dinge angeben, die sich auf die Erstellung, Gewährung oder Löschung von Abzeichen beziehen. Vergessen Sie nicht „upload“, wenn Sie das tun möchten, was dieses Beispiel zeigt, und Ihre eigenen Bilder hinzufügen möchten. Dies befindet sich in einem separaten Abschnitt von den Berechtigungen der Abzeichen-API.

2 „Gefällt mir“

In der ursprünglichen Veröffentlichung habe ich versehentlich die SHA-Hash-Digest-Funktion in einen String gesetzt, sodass dieser buchstäblich als Python-Code und nicht als Digest übernommen wurde. Das schien trotzdem zu funktionieren, aber wahrscheinlich sollte es stattdessen richtig sein. Ich bin mir nicht sicher, was das überprüft, aber wahrscheinlich wird das Image, wenn Sie dies falsch machen, irgendwann in der Zukunft als beschädigt markiert. Jedenfalls habe ich den obigen Code bearbeitet, sodass er richtig sein sollte. Wenn Sie andere Fehler entdecken, lassen Sie es mich bitte wissen!

3 „Gefällt mir“