Ghost API & Python 3.x, #4
ghostAdmin.py
import json, requests, jwt
from datetime import datetime as dt
from io import BytesIO
class GhostAdmin():
def __init__(self, siteName):
self.siteName = siteName
self.site = None
self.setSiteData()
self.token = None
self.headers = None
self.createHeaders()
def setSiteData(self):
sites = [{'name': 'somedomain1', 'url': 'https://somedomain1.com/', 'AdminAPIKey': '5f...1', 'ContentAPIKey': '0b...9'},\
{'name': 'somedomain2', 'url': 'https://somedomain2.com/', 'AdminAPIKey': '5f...', 'ContentAPIKey': '25...e'}]
self.site = next((site for site in sites if site['name'] == self.siteName), None)
return None
def createToken(self):
key = self.site['AdminAPIKey']
id, secret = key.split(':')
iat = int(dt.now().timestamp())
header = {'alg': 'HS256', 'typ': 'JWT', 'kid': id}
payload = {'iat': iat, 'exp': iat + (5 * 60), 'aud': '/v3/admin/'}
self.token = jwt.encode(payload, bytes.fromhex(secret), algorithm='HS256', headers=header)
return self.token
def createHeaders(self):
if self.site != None:
self.createToken()
self.headers = {'Authorization': 'Ghost {}'.format(self.token.decode())}
return self.headers
def getMembers(self):
members = {}
url = self.site['url']+'ghost/api/v3/admin/members/'
result = requests.get(url, headers=self.headers)
if result.ok:
members = json.loads(result.content)['members']
for i in members:
if i['name'] == None: i['name'] = ''
return members
def getSettings(self):
settings = {}
url = self.site['url']+'ghost/api/v3/content/settings/?key='+self.site['ContentAPIKey']
result = requests.get(url, headers=self.headers)
if result.ok:
settings = json.loads(result.content)['settings']
return settings
def getPostById(self, id):
url = self.site['url'] + 'ghost/api/v3/admin/posts/' + id + '/'
params = {'formats':'html,mobiledoc'}
result = requests.get(url, params=params, headers=self.headers)
if result.ok: post = json.loads(result.text)['posts'][0] # post = dict with keys: slug,id,uuid,title etc.
else: post = json.loads(result.text) # post = dict with key 'errors'
return post
def getPostBySlug(self,slug):
url = self.site['url'] + 'ghost/api/v3/admin/posts/slug/'+slug+'/'
params = {'formats':'html,mobiledoc'}
result = requests.get(url, params=params, headers=self.headers)
if result.ok: post = json.loads(result.text)['posts'][0] # post = dict with keys: slug,id,uuid,title etc.
else: post = json.loads(result.text) # post = dict with key 'errors'
return post
def getPostsByFilter(self,filter):
url = self.site['url'] + 'ghost/api/v3/admin/posts/'
params = filter
params['formats'] = 'html,mobiledoc'
result = requests.get(url, params=params, headers=self.headers)
if result.ok:
posts = json.loads(result.text)['posts'] # posts = list with dicts with keys: slug,id,uuid,title etc.
if len(posts) == 0: posts = [{'empty': 'list'}]
else: posts = [json.loads(result.text)] # posts = list with 1 element of dict with key 'errors'
return posts
def getAllPosts(self):
url = self.site['url'] + 'ghost/api/v3/admin/posts/'
params = {'formats': 'html,mobiledoc', 'limit': 'all', 'filter': 'slug: -tags'}
result = requests.get(url, params=params, headers=self.headers)
posts = json.loads(result.text)['posts']
return posts
def getPostByTitle(self,title):
allPosts = self.getAllPosts()
posts = []
for i in allPosts:
if i['title'] == title:
posts.append(i)
return posts
def deletePostById(self, id):
url = self.site['url'] + 'ghost/api/v3/admin/posts/' + id + '/'
result = requests.delete(url, headers=self.headers)
if result.ok: result = 'success: post deleted (status_code:' + str(result.status_code) + ')'
else: result = 'error: post NOT deleted (status_code:' + str(result.status_code) + ')'
return result
def loadImage(self, imagePathAndName):
image = open(imagePathAndName, 'rb')
imageObject = image.read()
image.close()
image = BytesIO(imageObject)
return image
def imageUpload(self, imageName, imageObject):
url = self.site['url'] + 'ghost/api/v3/admin/images/upload/'
files = {"file": (imageName, imageObject, 'image/jpeg')}
params = {'purpose': 'image', 'ref': imageName} # 'image', 'profile_image', 'icon'
result = requests.post(url, files=files, params=params, headers=self.headers)
if result.ok: result = 'success: '+json.loads(result.text)['images'][0]['url']
else: result = 'error: upload failed (' + str(result.status_code) + ')'
return result
def createPost(self, title, body, bodyFormat='html', excerpt = None, tags=None, authors=None, status='draft', featured=False, featureImage=None, slug=None):
"""
Args:
body (string): the content of a post
bodyFormat (string): 'html','markdown'
excerpt (string): the excerpt for a post
tags (list): a list of dictionaries e.g. [{'name':'my new tag', 'description': 'a very new tag'}]
authors (list): a list of dictionaries e.g. [{'name':'Jacques Bopp', 'slug': 'jacques'}]
status (string): 'published' or 'draft'
featured (bool): if the post should be featured
featureImage (string): the image url (e.g. "content/images/2020/09/featureImage1.jpg" -> see uploadImage()
Returns:
result (string): if the creation was successful or not
"""
content = {'title': title}
if bodyFormat == 'markdown': content['mobiledoc'] = json.dumps({ 'version': '0.3.1', 'markups': [], 'atoms': [], 'cards': [['markdown', {'cardName': 'markdown', 'markdown': body}]], 'sections': [[10, 0]]});
else: content['html'] = body
if excerpt != None: content['custom_excerpt'] = excerpt
if tags != None: content['tags'] = tags
if authors != None: content['authors'] = authors
content['status'] = status
content['featured'] = featured
if featureImage != None: content['feature_image'] = self.site['url']+featureImage
if slug != None: content['slug'] = slug
url = self.site['url']+'ghost/api/v3/admin/posts/'
params = {'source': 'html'}
result = requests.post(url, params=params, json={"posts": [content]}, headers=self.headers)
if result.ok: result = 'success: post created (status_code:'+str(result.status_code)+')'
else: result = 'error: post not created (status_code:'+str(result.status_code)+')'
return result
def updatePostByTitle(self, oldTitle, newTitle, body, bodyFormat='html', excerpt = None, tags=None, authors=None, status='draft', featured=False, featureImage=None):
posts = self.getPostByTitle(oldTitle)
if len(posts) > 1: result = 'error: more than 1 post found'
elif len(posts) == 0: result = 'error: no post found'
else:
post = posts[0]
content = {'title': newTitle}
if bodyFormat == 'markdown': content['mobiledoc'] = json.dumps({ 'version': '0.3.1', 'markups': [], 'atoms': [], 'cards': [['markdown', {'cardName': 'markdown', 'markdown': body}]], 'sections': [[10, 0]]});
else: content['html'] = body
if excerpt != None: content['custom_excerpt'] = excerpt
if tags != None: content['tags'] = tags
if authors != None: content['authors'] = authors
content['status'] = status
content['featured'] = featured
if featureImage != None: content['feature_image'] = self.site['url']+featureImage
content['updated_at'] = post['updated_at']
url = self.site['url']+'ghost/api/v3/admin/posts/'+post['id']+'/'
result = requests.put(url, json={"posts": [content]}, headers=self.headers)
if result.ok: result = 'success: post updated (status_code:' + str(result.status_code) + ')'
else: result = 'error: post not updated (status_code:' + str(result.status_code) + ')'
return result
if __name__ == '__main__':
ga = GhostAdmin('somedomain1')
members = ga.getMembers()
settings = ga.getSettings()
post = ga.getPostById('5f...5c')
post = ga.getPostBySlug('new-post')
posts = ga.getPostsByFilter({'filter': 'featured:true'})
posts = ga.getPostsByFilter({'limit': 'all', 'filter': 'slug: -tags'})
posts = ga.getAllPosts()
posts = ga.getPostByTitle('New Post')
result = ga.deletePostById('0c...f')
image = ga.loadImage('c:/tmp/image1')
result = ga.imageUpload('featureImage1.jpg', image)
# create post ---------------------------------------
title = 'new post x'
body = """<div>Lorem ipsum dolor sit amet, ...</div>"""
excerpt = 'this post is about ...'
tags = [{'name':'my new tag x', 'description': 'a new tag'}]
authors = [{'name':'Jacques Bopp', 'slug': 'jacques'}]
featureImage = 'content/images/2020/09/featureImage1.jpg'
slug = 'my-new-postx'
result = ga.createPost(title, body, bodyFormat='html', excerpt=excerpt, tags=tags, authors=authors, status='draft', featured=False, featureImage=featureImage)
# update post ---------------------------------------
oldTitle = 'new post x'
newTitle = 'updated post x'
body = """<div>Lorem ipsum ...</div>"""
excerpt = 'this post is about an update ...'
tags = [{'name':'my new tag', 'description': 'a new tag'},{'name':'my second new tag', 'description': 'a second new tag'}]
authors = [{'name':'Jacques Bopp', 'slug': 'jacques'},{'name':'Ghost', 'slug': 'ghost'}]
featureImage = 'content/images/2020/09/featureImage2.jpg'
result = ga.updatePostByTitle(oldTitle, newTitle, body, bodyFormat='html', excerpt=excerpt, tags=tags, authors=authors, status='draft', featured=False, featureImage=featureImage)