picgo-plugin-gitee-uploader
Version:
picgo uploader for gitee
282 lines (273 loc) • 7.96 kB
text/typescript
import picgo from 'picgo'
import { getNow, getPath } from './helper'
import { PluginConfig, ImgType } from './interface'
import urlJoin from 'url-join'
import { ImgInfo } from 'picgo/dist/utils/interfaces'
export class Octo {
username: string = ''
password: string = ''
clientId: string = ''
clientSecret: string = ''
owner: string = ''
repo: string = ''
branch: string = ''
path: string = ''
token: string = ''
customUrl: string = ''
ctx: picgo
baseUrl = 'https://gitee.com/api/v5'
constructor({
repo,
branch,
path = '',
token,
customPath = '',
customUrl = ''
}: PluginConfig, ctx: picgo) {
const [owner, r] = repo.split('/')
if (!r) throw new Error('Error in repo name')
this.owner = owner
this.repo = r
this.branch = branch || 'master'
this.token = token
this.customUrl = customUrl
this.ctx = ctx
this.path = getPath(path, customPath)
}
async getTree(sha): Promise<{ path: string; sha: string }[]> {
const url = urlJoin(
this.baseUrl,
'repos',
this.owner,
this.repo,
'git/gitee/trees',
sha
)
// this.ctx.log.info('url:' + url)
let params = {
method: 'GET',
json: true,
resolveWithFullResponse: true,
url: url,
qs: {
access_token: this.token
}
}
let result = await this.ctx.Request.request(params)
// this.ctx.log.info('getTree result')
// this.ctx.log.info(JSON.stringify(result.body))
if (result && result.statusCode === 200) {
const { tree } = result.body
return tree
} else {
this.ctx.log.error('getTree error')
this.ctx.log.error(JSON.stringify(result))
throw result
}
}
async getPathTree(): Promise<{ sha: string; tree: any[] }> {
const { path } = this
let tree = await this.getTree(this.branch)
const arr = path.split('/').filter(each => each)
let sha = this.branch
for (let i = 0; i < arr.length; i++) {
const item = tree.filter(each => arr[i].endsWith(each.path))[0]
if (!item) return Promise.reject(new Error(`Can\'t find ${path}`))
sha = item.sha
tree = await this.getTree(sha)
}
return { sha, tree }
}
async getDataJson(): Promise<{ lastSync: string, data: any[], sha?: string }> {
const defaultRet = {
lastSync: '',
data: []
}
const { tree } = await this.getPathTree()
/* this.ctx.log.info('tree info')
tree.forEach(element => {
this.ctx.log.info(JSON.stringify(element))
}) */
const dataJson = tree.filter(each => each.path === 'data.json')[0]
// this.ctx.log.info('dataJson info')
// this.ctx.log.info(JSON.stringify(dataJson))
if (dataJson) {
const url = urlJoin(
this.baseUrl,
'repos',
this.owner,
this.repo,
'git/blobs',
dataJson.sha
)
// this.ctx.log.info('url:' + url)
const params = {
method: 'GET',
json: true,
resolveWithFullResponse: true,
url: url,
qs: {
access_token: this.token
}
}
let result = await this.ctx.Request.request(params)
// this.ctx.log.info('getBlob result')
// this.ctx.log.info(JSON.stringify(result.body))
if (result && result.statusCode === 200) {
const buf = Buffer.from(result.body.content, result.body.encoding)
const json = JSON.parse(buf.toString())
return {
...defaultRet,
...json,
sha: dataJson.sha
}
} else {
this.ctx.log.error('getBlob error')
this.ctx.log.error(JSON.stringify(result))
throw result
}
}
return defaultRet
}
async updateDataJson({ data, sha }) {
const fileName = 'data.json'
const url = this.fileOptions(fileName)
// this.ctx.log.info('updateDataJson url:' + url)
const params = this.uploadOptions(url, 'PUT',
Buffer.from(JSON.stringify(data)).toString('base64'),
`Sync dataJson by PicGo at ${getNow()}`)
params.formData['sha'] = sha
// this.ctx.log.info(JSON.stringify(params))
let result = await this.ctx.Request.request(params)
// this.ctx.log.info('sync update data.json')
// this.ctx.log.info(JSON.stringify(result))
if (result && result.statusCode === 200) {
return true
} else {
this.ctx.log.error('sync update data.json error')
this.ctx.log.error(JSON.stringify(result))
throw result
}
}
async createDataJson(data) {
const fileName = 'data.json'
const url = this.fileOptions(fileName)
// this.ctx.log.info('createDataJson url:' + url)
const params = this.uploadOptions(url, 'POST',
Buffer.from(JSON.stringify(data)).toString('base64'),
`Sync dataJson by PicGo at ${getNow()}`)
let result = await this.ctx.Request.request(params)
/* this.ctx.log.info('sync data.json')
this.ctx.log.info(JSON.stringify(result)) */
if (result && result.statusCode === 201) {
return true
} else {
this.ctx.log.error('sync data.json error')
this.ctx.log.error(JSON.stringify(result))
throw result
}
}
async upload(img: ImgInfo) {
// 取出对象中同名的属性并赋值,神奇的写法,可以取出多个
const { fileName } = img
const url = this.fileOptions(fileName)
// this.ctx.log.info('url:' + url)
const params = this.uploadOptions(url, 'POST',
img.base64Image || Buffer.from(img.buffer).toString('base64'),
`Upload ${fileName} by picGo - ${getNow()}`);
let result = await this.ctx.Request.request(params)
/* this.ctx.log.info('upload result')
this.ctx.log.info(JSON.stringify(result)) */
if (result && result.statusCode === 201) {
return {
// result.body.content.download_url
imgUrl: this.parseUrl(result.body.content.name),
sha: result.body.content.sha
}
} else {
this.ctx.log.error('upload error')
this.ctx.log.error(JSON.stringify(result))
throw result
}
}
async removeFile(img: ImgType) {
const ctx = this.ctx
const url = this.fileOptions(img.fileName)
const params = {
method: 'DELETE',
json: true,
resolveWithFullResponse: true,
url: url,
qs: {
access_token: this.token,
sha: img.sha,
message: `Deleted ${img.fileName} by picGo - ${getNow()}`,
branch: this.branch
}
}
let result = await this.ctx.Request.request(params)
/* this.ctx.log.info('Deleted result')
this.ctx.log.info(JSON.stringify(result)) */
if (result && result.statusCode === 200) {
return true
} else {
this.ctx.log.error('deleted error')
this.ctx.log.error(JSON.stringify(result))
return result
}
}
uploadOptions = function (url, method, content, msg) {
return {
method: method,
json: true,
resolveWithFullResponse: true,
url: url,
formData: {
access_token: this.token,
content: content,
message: msg,
branch: this.branch
}
}
}
fileOptions = function (fileName) {
return encodeURI(urlJoin(
this.baseUrl,
'repos',
this.owner,
this.repo,
'contents',
this.path,
fileName
))
}
parseUrl(fileName) {
const { owner, repo, path, customUrl, branch } = this
if (customUrl) {
return urlJoin(customUrl, path, fileName)
}
return urlJoin(
`https://gitee.com/`,
owner,
repo,
'raw',
branch,
path,
fileName
)
}
}
let ins: Octo = null
let _cacheOption: string = ''
export function getIns(config: PluginConfig, ctx: picgo): Octo {
const str = JSON.stringify(config)
if (ins && _cacheOption === str) return ins
_cacheOption = str
ins = new Octo(config, ctx)
return ins
}
/* istanbul ignore next */
export function clearIns() {
// just for test
ins = null
}