const path = require('path') const https = require('https') const Stream = require('stream').Transform const hasha = require('hasha') const md = require('markdown-it')() const {httpsGetAsync, parseJSONData} = require('../../lib/request') const GLITCH_API_ROOT = '/ghost/api/v0.1/' // Retrieve ghost access token const getToken = config => { return new Promise((resolve, reject) => { const tokenReqData = `grant_type=password&username=${config.ghost.username}&password=${config.ghost.password}&client_id=${config.ghost.id}&client_secret=${config.ghost.secret}` const tokenReqOptions = { host: config.ghost.host, path: `${GLITCH_API_ROOT}authentication/token`, method: 'POST', headers: { 'Content-Type': 'application/x-www-form-urlencoded', 'Content-Length': Buffer.byteLength(tokenReqData, 'utf8')}} const collectToken = https.request(tokenReqOptions, res => { const data = new Stream() res.on('data', chunk => data.push(chunk)) res.on('end', parseJSONData.bind(null, data, resolve, reject)) }) collectToken.write(tokenReqData) collectToken.end() collectToken.on('error', error => reject(error)) }) } const download = (image, config) => { return new Promise(async (resolve, reject) => { const src = `https://${config.ghost.host}${image}` const dest = path.join(config.basepath, config.image_path, image) const data = new Stream() const res = await httpsGetAsync(src) res.on('data', chunk => data.push(chunk)) res.on('end', () => { const buf = data.read() resolve({src, dest, hash: hasha(buf), original: buf, optimized: null, responsive: []}) }) }) } // download images const downloadImages = async (posts, config) => { let images = [] posts.posts.forEach((post, idx) => { let postImages = [] if (post.image) postImages.push(post.image) // parse inline images md.parse(post.markdown).forEach(token => { if (token.type === 'image') postImages.push(token.attrs[0][1]) if (Array.isArray(token.children)) { token.children.forEach(async child => { if (child.type === 'image') postImages.push(child.attrs[0][1]) }) } }) images.push(Promise.all(postImages.map(image => download(image, config)))) }) return Promise.all(images) } const mapPostPages = async (posts, images, config) => { const postsWithMappedImages = posts.posts.map((post, idx) => Object.assign({}, post, {image: images[idx].pop()}, {images: images[idx]})) const postsWithMappedFields = postsWithMappedImages.map(post => { return { id: post.id, uuid: post.uuid, title: post.title, slug: post.slug, url: post.url, article: !post.page, status: post.status, language: post.language, visibility: post.visibility, meta_title: post.meta_title || post.title, meta_description: post.meta_description, created_at: new Date(post.created_at), created_by: post.created_by, updated_at: new Date(post.updated_at), updated_by: post.updated_by, published_at: new Date(post.published_at), published_by: post.published_by, tags: post.tags, author: post.author, image: post.image, images: post.images, markdown: post.markdown } }) return postsWithMappedFields } // fetch ghost posts const getPosts = async config => { const loadPosts = () => { return new Promise(async (resolve, reject) => { const token = await getToken(config) const postsReqOptions = { host: config.ghost.host, path: `${GLITCH_API_ROOT}posts/?status=all&staticPages=all&include=tags&limit=30`, headers: { 'authorization': `Bearer ${token.access_token}`, 'accept': 'application/json'}} const data = new Stream() const res = await httpsGetAsync(postsReqOptions) res.on('data', chunk => data.push(chunk)) res.on('end', parseJSONData.bind(null, data, resolve, reject)) }) } const posts = await loadPosts() const images = await downloadImages(posts, config) return mapPostPages(posts, images, config) } module.exports.getPosts = getPosts