Im Rahmen eines kleinen, neuen Projektes nutze ich eine gesonderte Ghost Instanz, um Bilder, die ich mit meiner Nikon gemacht habe (bzw. machen werde), aller Welt zu zeigen :-). Nachdem die relative stupide - immer wiederkehrende - Arbeit des Bilder umwandelns, Einbetten in die jquery basierte Gallerie etc. auf Dauer eher nervt, machte ich mich dran mir die Ghost API mal genauer anzusehen, allerdings wird mit Aussnahme der Client / User Authentication kaum auf den privaten Teil eingegangen, der für das Erzeugen und Modifizieren von Content aber nötig ist.
Ein wenig Stöbern im WWW aber hauptsächlich einiges an Reverse Engineering hat aber den gewünschen Erfolgt gebracht. Daher hier ein kurzer Überblick was man machen muss, um mittels API Blog-Post zu erzeugen.
Im ersten Schritt muss man die client_id bzw. das client_secret direkt aus der DB ermitteln
select secret from clients where slug='ghost-admin';
Das ermittelte secret muss dann in der Tabelle client_trusted_domains eintragen, quasi auf die Whitelist setzen
insert into client_trusted_domains(id, client_id, trusted_domain)
values ('<ID>','<SECRET>','<IP ADRESSE>' );
der Wert den man als Wert für die Spalte id eintragen muss, generiert man in dem man im ghost Applikationsverzeichnis eine node shell startet
# node
> require('bson-objectid')()
ObjectID(5a7c4485904d0946371da09e)
Einen gepflegten Neustart von Ghost später, haben wir serverseitig soweit alles vorbereitet, so dass wir uns an die Client Seite machen.
Ein vorhandenes ghost-client pip, lies sich in meiner Umgebung nicht sauber installieren, deswegen hies es "Back to the roots" und ich nahm mir das requests Modul zur Hilfe.
Wie in der offiziellen Doku beschrieben ist, benötigt man das Bearer Token, um sich erfolgreich am Blog zu authentifizieren
res = requests.post(url + '/ghost/api/v0.1/authentication/token', data={
'username': user_name,
'password': user_password,
'grant_type': 'password',
'client_id': client_id,
'client_secret': client_secret,
})
return json.loads(res.content)['access_token']
Den eigentlichen Post erstellt man dann mittels
post_content = post_content.replace('"', '\\"').replace('\n', '\\n')
pd = dict(author="1",
featured=False,
feature_image=post_image,
meta_description=None,
meta_title=post_title,
mobiledoc='{"version":"0.3.1","markups":[],"atoms":[],"cards":
[["card-markdown",{"cardName":"card-markdown","markdown":"' +
post_content +'"}]],"sections":[[10,0]]}',
page=False,
published_by=None,
slug=post_title,
status="published",
title=post_title,
published_at=created_time)
die interesanntesten Attribute sind an dieser Stelle
Attribut | Beschreibung |
feature_image | Feature Image des Blog Posts, sprich das Post Logo |
mobiledoc | der JSON Wert des Attributes mobiledoc enthält unter anderem den tatsächlichen Post-Markdown |
slug | Kontext unter dem der Blog-Post referenziert werden kann, ich halte den immer parallel zu dem eigentlichen Post-Titel |
title | Titel des Blog-Eintrages |
status | published, um sicher zustellen, dass der Eintrag gleich öffentlich zugänglich ist |
Ein simples Beispiel habe ich mal uf Github als Gist hinterlegt
das zugehörige yaml config File sieht wie folgt aus
log:
url: https://yourblog.de
username: blogadmin@yourblog.de
password: 12234_sdfs-§$23-wDM;a
client_id: ghost-admin
client_secret: 87Rdbd2br5d4
Ruft man den Snippet mit Werten für den Blog-Titel und den Content ala
ghost_api_demo.py "Blogpost Test" "<h1>Test via API</h1> <br/>A simple <b>test</b> using the <i>Ghost</i> api<br/>"
auf, wird der entsprechende Post erzeugt