vtex-cms-sauce
Version:
Tool for handling VTEX CMS requests.
235 lines (195 loc) • 7.88 kB
JavaScript
import '@babel/register'
import '@babel/polyfill'
import rl from 'readline'
import { createReadStream } from 'fs'
import { createHash } from 'crypto'
import FormData from 'form-data'
import cheerio from 'cheerio'
import apisauce from 'apisauce'
const ask = (question) => {
const r = rl.createInterface({
input: process.stdin,
output: process.stdout
})
return new Promise((resolve, reject) => {
r.question(question + '\n', function(answer) {
r.close()
if (answer) resolve(answer)
else { reject('No answer!') }
})
})
}
const create = (baseURL) => {
// Create and configure an apisauce-based api object.
const api = apisauce.create({
baseURL,
headers: {
'Cache-Control': 'no-cache',
'Accept': '*/*',
'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'
},
timeout: 10000
})
// Transforms JSON request data into x-www-form-urlencoded
api.addRequestTransform(request => {
let str = []
for (const p in request.data) {
str.push(encodeURIComponent(p) + '=' + encodeURIComponent(request.data[p]));
}
request.data = str.join('&')
})
let _getAuthCookie = async () => {
try {
const authCookie = await ask('Insert authentication cookie:')
_getAuthCookie = () => authCookie
return authCookie
} catch(err) { console.error(err) }
}
const _getTemplateId = (templatename) => createHash('md5').update(templatename).digest('hex')
const _getRequestToken = async () => {
try {
const authCookie = await _getAuthCookie()
api.setHeader('Cookie', `VtexIdclientAutCookie=${authCookie};`)
const { data } = await api.post('/admin/a/PortalManagement/AddFile?fileType=css')
const $ = cheerio.load(data)
const requestToken = $('#fileUploadRequestToken').val()
if (!requestToken) throw new Error('Couldn\'t get request token!')
return requestToken
} catch(err) { console.error(`Couldn't get request token: ${err}`) }
}
const _saveTemplate = async (data = {}, isSub, type, actionForm = 'Save') => {
try {
const authCookie = await _getAuthCookie()
const { templateName, templatename, template, templateId } = data
const endpoint = (type === 'shelf' || type === 'shelfTemplate') ? 'admin/a/PortalManagement/SaveShelfTemplate' : 'admin/a/PortalManagement/SaveTemplate'
if (!authCookie) throw new Error('You must provide a valid auth cookie!')
if (!templatename && !templateName) throw new Error('You must provide a name when saving a template!')
if (!template) throw new Error('You must provide content when saving a template!')
api.setHeader('Cookie', `VtexIdclientAutCookie=${authCookie};`)
api.setHeader('Content-Type', 'application/x-www-form-urlencoded; charset=UTF-8')
return api.post(endpoint, {
...data,
isSub,
actionForm,
textConfirm: 'sim'
})
} catch(err) { console.error(err) }
}
const _parseErrorMessage = (data, templatename) => {
const x = data.indexOf('<applicationexceptionobject>') + 28
const y = data.indexOf('</applicationexceptionobject>')
const obj = JSON.parse(data.substr(x, y - x))
return `Couldn't save template (${templatename}): ${obj.message}`
}
let _getTemplates = async (type, isSub = false) => {
try {
_getTemplates.cache = _getTemplates.cache || {}
const key = `${type}-${isSub}`
const endpoint = `admin/a/PortalManagement/GetTemplateList?type=${type}&IsSub=${isSub ? 1 : 0}`
const authCookie = await _getAuthCookie()
api.setHeader('Cookie', `VtexIdclientAutCookie=${authCookie};`)
api.setHeader('Content-Type', 'application/x-www-form-urlencoded; charset=UTF-8')
if (!_getTemplates.cache[key]) {
const { data } = await api.post(endpoint)
_getTemplates.cache[key] = data
}
return _getTemplates.cache[key]
} catch(err) { console.error(err) }
}
const _getLegacyTemplateId = async (reqData, type, isSub = false) => {
try {
const templatesList = await _getTemplates(type, isSub)
const name = reqData.templateName || reqData.templatename
const regex = new RegExp(`(${name})([\\s\\S]+?)(templateId=)([\\s\\S]+?(?="))`)
const matches = templatesList.match(regex)
const templateId = matches[4]
if (!templateId) throw new Error('template not found!')
return templateId
} catch(err) { console.error(`Couldn't get legacy template id: ${err}`) }
}
const _saveLegacyTemplate = async (reqData, type = 'viewTemplate', isSub) => {
try {
const action = type === 'shelfTemplate' ? 'Update' : 'Save'
reqData.templateId = await _getLegacyTemplateId(reqData, type, isSub)
return _saveTemplate(reqData, isSub, type, action)
} catch(err) { console.error(err) }
}
const saveShelfTemplate = async (templateName, HTML, shelfClass) => {
try {
const reqData = {
templateName,
templateId: _getTemplateId(templateName),
template: HTML,
roundCorners: false,
templateCssClass: shelfClass,
}
let term = 'saved'
let { status, data } = await _saveTemplate(reqData, true, 'shelf')
if (~data.indexOf('already exists')) {
term = 'updated'
const res = await _saveLegacyTemplate(reqData, 'shelfTemplate', true)
status = res.status
data = res.data
}
if (status.toString().substr(0, 1) !== '2') throw new Error(`Couldn't save template (${templateName}). Status: ${status}`)
else if (~data.indexOf('originalMessage')) throw new Error(_parseErrorMessage(data, templateName))
return `Shelf template (${templateName}) ${term}!`
} catch(err) { console.error(err) }
}
const saveTemplate = async (templatename, HTML, isSub = false) => {
try {
const reqData = {
templatename,
templateId: _getTemplateId(templatename),
template: HTML
}
let { status, data } = await _saveTemplate(reqData, isSub)
if (~data.indexOf('already exists')) {
const res = await _saveLegacyTemplate(reqData, 'viewTemplate', isSub)
status = res.status
data = res.data
}
if (status.toString().substr(0, 1) !== '2') throw new Error(`Couldn't save template (${templatename}). Status: ${status}`)
else if (~data.indexOf('originalMessage')) throw new Error(_parseErrorMessage(data, templatename))
return `Template (${templatename}) saved!`
} catch(err) { console.error(err) }
}
const saveFile = async (filepath) => {
try {
const authCookie = await _getAuthCookie()
const requestToken = await _getRequestToken()
const host = baseURL.replace(/(http:|https:|\/)/g, '')
const form = new FormData()
form.append('Filename', filepath)
form.append('fileext', '*.jpg;*.png;*.gif;*.jpeg;*.ico;*.js;*.css')
form.append('folder', '/uploads')
form.append('Upload', 'Submit Query')
form.append('requestToken', requestToken)
form.append('Filedata', createReadStream(filepath))
const { statusCode } = await new Promise((resolve, reject) => {
form.submit({
host,
'path': '/admin/a/FilePicker/UploadFile',
'headers': {
'Cookie': `VtexIdclientAutCookie=${authCookie};`,
'Content-Type': form.getHeaders()['content-type']
}
}, (err, res) => {
if (err) reject(err)
resolve(res)
})
})
if (statusCode.toString().substr(0, 1) !== '2') throw new Error(`Couldn\'t save file: ${filepath} (Error: ${statusCode})`)
return `File: ${filepath} saved!`
} catch(err) { console.error(err) }
}
// The public API
return {
saveTemplate,
saveShelfTemplate,
saveFile
}
}
module.exports = {
create
}