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)

Back to Part 1

Back to Part 2

Back to Part 3

Sie haben sich erfolgreich bei xBopp registriert
Willkommen zurück! Ihre Anmeldung war erfolgreich.
Super! Ihre Registrierung war erfolgreich.
Gemacht! Ihre neue Email-Adresse wurde erfolgreich registriert.
Ihr Link ist abgelaufen
Super! Prüfen Sie Ihren Email-Eingang auf unseren Link zur Anmeldung.