支持Github图床
This commit is contained in:
parent
09416c75a4
commit
1352ea0a9a
@ -54,6 +54,7 @@ import GithubOpenModal from './modals/providers/GithubOpenModal';
|
|||||||
import GithubSaveModal from './modals/providers/GithubSaveModal';
|
import GithubSaveModal from './modals/providers/GithubSaveModal';
|
||||||
import GithubWorkspaceModal from './modals/providers/GithubWorkspaceModal';
|
import GithubWorkspaceModal from './modals/providers/GithubWorkspaceModal';
|
||||||
import GithubPublishModal from './modals/providers/GithubPublishModal';
|
import GithubPublishModal from './modals/providers/GithubPublishModal';
|
||||||
|
import GithubImgStorageModal from './modals/providers/GithubImgStorageModal';
|
||||||
import GistSyncModal from './modals/providers/GistSyncModal';
|
import GistSyncModal from './modals/providers/GistSyncModal';
|
||||||
import GistPublishModal from './modals/providers/GistPublishModal';
|
import GistPublishModal from './modals/providers/GistPublishModal';
|
||||||
import GiteeAccountModal from './modals/providers/GiteeAccountModal';
|
import GiteeAccountModal from './modals/providers/GiteeAccountModal';
|
||||||
@ -118,6 +119,7 @@ export default {
|
|||||||
GithubSaveModal,
|
GithubSaveModal,
|
||||||
GithubWorkspaceModal,
|
GithubWorkspaceModal,
|
||||||
GithubPublishModal,
|
GithubPublishModal,
|
||||||
|
GithubImgStorageModal,
|
||||||
GistSyncModal,
|
GistSyncModal,
|
||||||
GistPublishModal,
|
GistPublishModal,
|
||||||
GiteeAccountModal,
|
GiteeAccountModal,
|
||||||
|
@ -30,19 +30,25 @@
|
|||||||
<span class="line-entry" v-if="token.params">自定义Form参数:{{token.params}}</span>
|
<span class="line-entry" v-if="token.params">自定义Form参数:{{token.params}}</span>
|
||||||
</menu-item>
|
</menu-item>
|
||||||
</menu-entry>
|
</menu-entry>
|
||||||
<menu-entry @click.native="checkedImgDest(tokenStorage.sid, 'gitea')" v-for="tokenStorage in giteaTokensImgStorages" :key="tokenStorage.sid">
|
<menu-entry @click.native="checkedImgDest(tokenStorage.sid, tokenStorage.providerId)" v-for="tokenStorage in tokensImgStorages" :key="tokenStorage.sid">
|
||||||
<icon-check-circle v-if="checkedStorage.sub === tokenStorage.sid" slot="icon"></icon-check-circle>
|
<icon-check-circle v-if="checkedStorage.sub === tokenStorage.sid" slot="icon"></icon-check-circle>
|
||||||
<icon-check-circle-un v-if="checkedStorage.sub !== tokenStorage.sid" slot="icon"></icon-check-circle-un>
|
<icon-check-circle-un v-if="checkedStorage.sub !== tokenStorage.sid" slot="icon"></icon-check-circle-un>
|
||||||
<menu-item>
|
<menu-item>
|
||||||
<icon-provider slot="icon" provider-id="gitea"></icon-provider>
|
<icon-provider slot="icon" :provider-id="tokenStorage.providerId"></icon-provider>
|
||||||
<div>Gitea图床
|
<div>{{tokenStorage.providerName}}
|
||||||
<button class="menu-item__button button" @click.stop="remove('gitea', tokenStorage)" v-title="'删除'">
|
<button class="menu-item__button button" @click.stop="remove(tokenStorage.providerId, tokenStorage)" v-title="'删除'">
|
||||||
<icon-delete></icon-delete>
|
<icon-delete></icon-delete>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<span> {{tokenStorage.uname}}, 仓库URL: {{tokenStorage.repoUrl}}, 路径: {{tokenStorage.path}}, 分支: {{tokenStorage.branch}}</span>
|
<span> {{tokenStorage.uname}}, 仓库URL: {{tokenStorage.repoUrl}}, 路径: {{tokenStorage.path}}, 分支: {{tokenStorage.branch}}</span>
|
||||||
</menu-item>
|
</menu-item>
|
||||||
</menu-entry>
|
</menu-entry>
|
||||||
|
</div>
|
||||||
|
<div class="modal__button-bar">
|
||||||
|
<button class="button" @click="reject()">取消</button>
|
||||||
|
<button class="button button--resolve" @click="resolve" :disabled="uploading">确认</button>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
<menu-entry @click.native="addSmmsAccount">
|
<menu-entry @click.native="addSmmsAccount">
|
||||||
<icon-provider slot="icon" provider-id="smms"></icon-provider>
|
<icon-provider slot="icon" provider-id="smms"></icon-provider>
|
||||||
<span>添加SM.MS图床账号</span>
|
<span>添加SM.MS图床账号</span>
|
||||||
@ -55,10 +61,10 @@
|
|||||||
<icon-provider slot="icon" provider-id="gitea"></icon-provider>
|
<icon-provider slot="icon" provider-id="gitea"></icon-provider>
|
||||||
<span>添加Gitea图床仓库</span>
|
<span>添加Gitea图床仓库</span>
|
||||||
</menu-entry>
|
</menu-entry>
|
||||||
</div>
|
<menu-entry @click.native="addGithubImgStorage">
|
||||||
<div class="modal__button-bar">
|
<icon-provider slot="icon" provider-id="github"></icon-provider>
|
||||||
<button class="button" @click="reject()">取消</button>
|
<span>添加GitHub图床仓库</span>
|
||||||
<button class="button button--resolve" @click="resolve" :disabled="uploading">确认</button>
|
</menu-entry>
|
||||||
</div>
|
</div>
|
||||||
</modal-inner>
|
</modal-inner>
|
||||||
</template>
|
</template>
|
||||||
@ -70,6 +76,7 @@ import MenuItem from '../menus/common/MenuItem';
|
|||||||
import smmsHelper from '../../services/providers/helpers/smmsHelper';
|
import smmsHelper from '../../services/providers/helpers/smmsHelper';
|
||||||
import store from '../../store';
|
import store from '../../store';
|
||||||
import giteaHelper from '../../services/providers/helpers/giteaHelper';
|
import giteaHelper from '../../services/providers/helpers/giteaHelper';
|
||||||
|
import githubHelper from '../../services/providers/helpers/githubHelper';
|
||||||
import customHelper from '../../services/providers/helpers/customHelper';
|
import customHelper from '../../services/providers/helpers/customHelper';
|
||||||
import utils from '../../services/utils';
|
import utils from '../../services/utils';
|
||||||
|
|
||||||
@ -103,21 +110,34 @@ export default modalTemplate({
|
|||||||
})),
|
})),
|
||||||
];
|
];
|
||||||
},
|
},
|
||||||
giteaTokensImgStorages() {
|
tokensImgStorages() {
|
||||||
const giteaTokensBySub = store.getters['data/giteaTokensBySub'];
|
const providerTokens = [
|
||||||
|
...Object.values(store.getters['data/giteaTokensBySub']).map(token => ({
|
||||||
|
token,
|
||||||
|
providerId: 'gitea',
|
||||||
|
providerName: 'Gitea图床',
|
||||||
|
})),
|
||||||
|
...Object.values(store.getters['data/githubTokensBySub']).map(token => ({
|
||||||
|
token,
|
||||||
|
providerId: 'github',
|
||||||
|
providerName: 'GitHub图床',
|
||||||
|
})),
|
||||||
|
];
|
||||||
const imgStorages = [];
|
const imgStorages = [];
|
||||||
Object.values(giteaTokensBySub)
|
Object.values(providerTokens)
|
||||||
.sort((token1, token2) => token1.name.localeCompare(token2.name))
|
.sort((item1, item2) => item1.token.name.localeCompare(item2.token.name))
|
||||||
.forEach((it) => {
|
.forEach((it) => {
|
||||||
if (!it.imgStorages || it.imgStorages.length === 0) {
|
if (!it.token.imgStorages || it.token.imgStorages.length === 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// 拼接上当前用户名
|
// 拼接上当前用户名
|
||||||
it.imgStorages.forEach(storage => imgStorages.push({
|
it.token.imgStorages.forEach(storage => imgStorages.push({
|
||||||
...storage,
|
...storage,
|
||||||
token: it,
|
token: it.token,
|
||||||
uname: it.name,
|
uname: it.token.name,
|
||||||
repoUrl: `${it.serverUrl}/${storage.repoUri}`,
|
providerId: it.providerId,
|
||||||
|
providerName: it.providerName,
|
||||||
|
repoUrl: it.providerId === 'gitea' ? `${it.serverUrl}/${storage.repoUri}` : `${storage.owner}/${storage.repo}`,
|
||||||
}));
|
}));
|
||||||
});
|
});
|
||||||
return imgStorages;
|
return imgStorages;
|
||||||
@ -153,8 +173,8 @@ export default modalTemplate({
|
|||||||
} catch (err) {
|
} catch (err) {
|
||||||
store.dispatch('notification/error', err);
|
store.dispatch('notification/error', err);
|
||||||
}
|
}
|
||||||
} else if (currStorage.provider === 'gitea') {
|
} else if (currStorage.provider === 'gitea' || currStorage.provider === 'github') {
|
||||||
const filterTokenStorages = this.giteaTokensImgStorages
|
const filterTokenStorages = this.tokensImgStorages
|
||||||
.filter(it => it.sid === currStorage.sub);
|
.filter(it => it.sid === currStorage.sub);
|
||||||
if (!filterTokenStorages.length) {
|
if (!filterTokenStorages.length) {
|
||||||
store.dispatch('notification/info', 'Gitea图床已失效,未自动上传图片!请选择图床后重新粘贴/拖拽图片!');
|
store.dispatch('notification/info', 'Gitea图床已失效,未自动上传图片!请选择图床后重新粘贴/拖拽图片!');
|
||||||
@ -169,15 +189,28 @@ export default modalTemplate({
|
|||||||
.replace('{MM}', `0${month}`.slice(-2)).replace('{DD}', `0${date}`.slice(-2));
|
.replace('{MM}', `0${month}`.slice(-2)).replace('{DD}', `0${date}`.slice(-2));
|
||||||
path = `${path}${path.endsWith('/') ? '' : '/'}${utils.uid()}.${imgFile.type.split('/')[1]}`;
|
path = `${path}${path.endsWith('/') ? '' : '/'}${utils.uid()}.${imgFile.type.split('/')[1]}`;
|
||||||
try {
|
try {
|
||||||
const result = await giteaHelper.uploadFile({
|
if (currStorage.provider === 'gitea') {
|
||||||
token: tokenStorage.token,
|
const result = await giteaHelper.uploadFile({
|
||||||
projectId: tokenStorage.repoUri,
|
token: tokenStorage.token,
|
||||||
branch: tokenStorage.branch,
|
projectId: tokenStorage.repoUri,
|
||||||
path,
|
branch: tokenStorage.branch,
|
||||||
content: imgFile,
|
path,
|
||||||
isFile: true,
|
content: imgFile,
|
||||||
});
|
isFile: true,
|
||||||
this.url = result.content.download_url;
|
});
|
||||||
|
this.url = result.content.download_url;
|
||||||
|
} else if (currStorage.provider === 'github') {
|
||||||
|
const result = await githubHelper.uploadFile({
|
||||||
|
token: tokenStorage.token,
|
||||||
|
owner: tokenStorage.owner,
|
||||||
|
repo: tokenStorage.repo,
|
||||||
|
branch: tokenStorage.branch,
|
||||||
|
path,
|
||||||
|
content: imgFile,
|
||||||
|
isFile: true,
|
||||||
|
});
|
||||||
|
this.url = result.content.download_url;
|
||||||
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
store.dispatch('notification/error', err);
|
store.dispatch('notification/error', err);
|
||||||
}
|
}
|
||||||
@ -218,6 +251,8 @@ export default modalTemplate({
|
|||||||
});
|
});
|
||||||
} else if (proivderId === 'gitea') {
|
} else if (proivderId === 'gitea') {
|
||||||
giteaHelper.removeTokenImgStorage(item.token, item.sid);
|
giteaHelper.removeTokenImgStorage(item.token, item.sid);
|
||||||
|
} else if (proivderId === 'github') {
|
||||||
|
githubHelper.removeTokenImgStorage(item.token, item.sid);
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
// Cancel
|
// Cancel
|
||||||
@ -242,9 +277,20 @@ export default modalTemplate({
|
|||||||
giteaHelper.updateToken(token, imgStorageInfo);
|
giteaHelper.updateToken(token, imgStorageInfo);
|
||||||
} catch (e) { /* Cancel */ }
|
} catch (e) { /* Cancel */ }
|
||||||
},
|
},
|
||||||
|
async addGithubImgStorage() {
|
||||||
|
try {
|
||||||
|
await store.dispatch('modal/open', { type: 'githubAccount' });
|
||||||
|
const token = await githubHelper.addAccount(store.getters['data/localSettings'].githubRepoFullAccess);
|
||||||
|
const imgStorageInfo = await store.dispatch('modal/open', {
|
||||||
|
type: 'githubImgStorage',
|
||||||
|
token,
|
||||||
|
});
|
||||||
|
githubHelper.updateToken(token, imgStorageInfo);
|
||||||
|
} catch (e) { /* Cancel */ }
|
||||||
|
},
|
||||||
async checkedImgDest(sub, provider) {
|
async checkedImgDest(sub, provider) {
|
||||||
let type = 'token';
|
let type = 'token';
|
||||||
if (provider === 'gitea') {
|
if (provider === 'gitea' || provider === 'github') {
|
||||||
type = 'tokenRepo';
|
type = 'tokenRepo';
|
||||||
}
|
}
|
||||||
store.dispatch('img/changeCheckedStorage', {
|
store.dispatch('img/changeCheckedStorage', {
|
||||||
|
77
src/components/modals/providers/GithubImgStorageModal.vue
Normal file
77
src/components/modals/providers/GithubImgStorageModal.vue
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
<template>
|
||||||
|
<modal-inner aria-label="GitHub 公开仓库图床">
|
||||||
|
<div class="modal__content">
|
||||||
|
<div class="modal__image">
|
||||||
|
<icon-provider provider-id="github"></icon-provider>
|
||||||
|
</div>
|
||||||
|
<p>创建一个用于存储图片的<b> GitHub </b>公开仓库文件夹图床。</p>
|
||||||
|
<form-entry label="公开仓库URL" error="repoUrl">
|
||||||
|
<input slot="field" class="textfield" type="text" v-model.trim="repoUrl" @keydown.enter="resolve()">
|
||||||
|
<div class="form-entry__info">
|
||||||
|
<b>例如:</b> https://github.com/owner/my-repo
|
||||||
|
</div>
|
||||||
|
</form-entry>
|
||||||
|
<form-entry label="文件夹路径" info="可选的">
|
||||||
|
<input slot="field" class="textfield" type="text" placeholder="如:imgs/{YYYY}/{MM}" v-model.trim="path" @keydown.enter="resolve()">
|
||||||
|
<div class="form-entry__info">
|
||||||
|
如果不提供,默认为 {YYYY}/{MM}/{DD} ,其中{YYYY}为年变量、{MM}为月变量、{DD}为日变量。
|
||||||
|
</div>
|
||||||
|
</form-entry>
|
||||||
|
<form-entry label="分支" info="可选的">
|
||||||
|
<input slot="field" class="textfield" type="text" v-model.trim="branch" @keydown.enter="resolve()">
|
||||||
|
<div class="form-entry__info">
|
||||||
|
如果未提供,将使用<code> master </code>分支。
|
||||||
|
</div>
|
||||||
|
</form-entry>
|
||||||
|
</div>
|
||||||
|
<div class="modal__button-bar">
|
||||||
|
<button class="button" @click="config.reject()">取消</button>
|
||||||
|
<button class="button button--resolve" @click="resolve()">确认</button>
|
||||||
|
</div>
|
||||||
|
</modal-inner>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import utils from '../../../services/utils';
|
||||||
|
import modalTemplate from '../common/modalTemplate';
|
||||||
|
import githubHelper from '../../../services/providers/helpers/githubHelper';
|
||||||
|
import store from '../../../store';
|
||||||
|
|
||||||
|
export default modalTemplate({
|
||||||
|
data: () => ({
|
||||||
|
branch: '',
|
||||||
|
path: '',
|
||||||
|
}),
|
||||||
|
computedLocalSettings: {
|
||||||
|
repoUrl: 'githubImgStorageRepoUrl',
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
async resolve() {
|
||||||
|
const { owner, repo } = utils.parseGithubRepoUrl(this.repoUrl);
|
||||||
|
if (!owner && !repo) {
|
||||||
|
this.setError('repoUrl');
|
||||||
|
} else {
|
||||||
|
// 判断 仓库URL是否存在 如果存在是否公开仓库 只有公开仓库才允许添加
|
||||||
|
try {
|
||||||
|
const repoInfo = await githubHelper.getRepoInfo(this.config.token, owner, repo);
|
||||||
|
if (repoInfo.private) {
|
||||||
|
store.dispatch('notification/error', '作为图床的仓库URL必须是公开仓库!');
|
||||||
|
this.setError('repoUrl');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const path = this.path && this.path.replace(/^\//, '');
|
||||||
|
this.config.resolve({
|
||||||
|
owner,
|
||||||
|
repo,
|
||||||
|
path: path || '{YYYY}/{MM}/{DD}',
|
||||||
|
branch: this.branch || 'master',
|
||||||
|
});
|
||||||
|
} catch (err) {
|
||||||
|
store.dispatch('notification/error', err);
|
||||||
|
this.setError('repoUrl');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
</script>
|
@ -58,7 +58,6 @@ export default {
|
|||||||
sub = null, silent = false, refreshToken,
|
sub = null, silent = false, refreshToken,
|
||||||
) {
|
) {
|
||||||
let tokenBody;
|
let tokenBody;
|
||||||
const imgStorages = refreshToken && refreshToken.imgStorages;
|
|
||||||
if (!silent) {
|
if (!silent) {
|
||||||
// Get an OAuth2 code
|
// Get an OAuth2 code
|
||||||
const { code } = await networkSvc.startOauth2(
|
const { code } = await networkSvc.startOauth2(
|
||||||
@ -115,13 +114,14 @@ export default {
|
|||||||
throw new Error('Gitea account ID not expected.');
|
throw new Error('Gitea account ID not expected.');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const oldToken = store.getters['data/giteaTokensBySub'][uniqueSub];
|
||||||
// Build token object including scopes and sub
|
// Build token object including scopes and sub
|
||||||
const token = {
|
const token = {
|
||||||
accessToken,
|
accessToken,
|
||||||
name: user.username,
|
name: user.username,
|
||||||
applicationId,
|
applicationId,
|
||||||
applicationSecret,
|
applicationSecret,
|
||||||
imgStorages,
|
imgStorages: oldToken && oldToken.imgStorages,
|
||||||
refreshToken: tokenBody.refresh_token,
|
refreshToken: tokenBody.refresh_token,
|
||||||
expiresOn: Date.now() + (tokenBody.expires_in * 1000),
|
expiresOn: Date.now() + (tokenBody.expires_in * 1000),
|
||||||
serverUrl,
|
serverUrl,
|
||||||
|
@ -104,12 +104,14 @@ export default {
|
|||||||
throw new Error('GitHub account ID not expected.');
|
throw new Error('GitHub account ID not expected.');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const oldToken = store.getters['data/githubTokensBySub'][user.id];
|
||||||
// Build token object including scopes and sub
|
// Build token object including scopes and sub
|
||||||
const token = {
|
const token = {
|
||||||
scopes,
|
scopes,
|
||||||
accessToken,
|
accessToken,
|
||||||
name: user.login,
|
name: user.login,
|
||||||
sub: `${user.id}`,
|
sub: `${user.id}`,
|
||||||
|
imgStorages: oldToken && oldToken.imgStorages,
|
||||||
repoFullAccess: scopes.includes('repo'),
|
repoFullAccess: scopes.includes('repo'),
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -173,13 +175,14 @@ export default {
|
|||||||
path,
|
path,
|
||||||
content,
|
content,
|
||||||
sha,
|
sha,
|
||||||
|
isFile,
|
||||||
}) {
|
}) {
|
||||||
return repoRequest(token, owner, repo, {
|
return repoRequest(token, owner, repo, {
|
||||||
method: 'PUT',
|
method: 'PUT',
|
||||||
url: `contents/${encodeURIComponent(path)}`,
|
url: `contents/${encodeURIComponent(path)}`,
|
||||||
body: {
|
body: {
|
||||||
message: getCommitMessage(sha ? 'updateFileMessage' : 'createFileMessage', path),
|
message: getCommitMessage(sha ? 'updateFileMessage' : 'createFileMessage', path),
|
||||||
content: utils.encodeBase64(content),
|
content: isFile ? await utils.encodeFiletoBase64(content) : utils.encodeBase64(content),
|
||||||
sha,
|
sha,
|
||||||
branch,
|
branch,
|
||||||
},
|
},
|
||||||
@ -227,6 +230,44 @@ export default {
|
|||||||
data: utils.decodeBase64(content),
|
data: utils.decodeBase64(content),
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
/**
|
||||||
|
* 获取仓库信息
|
||||||
|
*/
|
||||||
|
async getRepoInfo(token, owner, repo) {
|
||||||
|
return request(token, {
|
||||||
|
url: `https://api.github.com/repos/${encodeURIComponent(owner)}/${encodeURIComponent(repo)}`,
|
||||||
|
}).then(res => res.body);
|
||||||
|
},
|
||||||
|
async updateToken(token, imgStorageInfo) {
|
||||||
|
const imgStorages = token.imgStorages || [];
|
||||||
|
// 存储仓库唯一标识
|
||||||
|
const sid = utils.hash(`${imgStorageInfo.owner}${imgStorageInfo.repo}${imgStorageInfo.path}${imgStorageInfo.branch}`);
|
||||||
|
// 查询是否存在 存在则更新
|
||||||
|
const filterStorages = imgStorages.filter(it => it.sid === sid);
|
||||||
|
if (filterStorages && filterStorages.length > 0) {
|
||||||
|
filterStorages.owner = imgStorageInfo.owner;
|
||||||
|
filterStorages.repo = imgStorageInfo.repo;
|
||||||
|
filterStorages.path = imgStorageInfo.path;
|
||||||
|
filterStorages.branch = imgStorageInfo.branch;
|
||||||
|
} else {
|
||||||
|
imgStorages.push({
|
||||||
|
sid,
|
||||||
|
owner: imgStorageInfo.owner,
|
||||||
|
repo: imgStorageInfo.repo,
|
||||||
|
path: imgStorageInfo.path,
|
||||||
|
branch: imgStorageInfo.branch,
|
||||||
|
});
|
||||||
|
token.imgStorages = imgStorages;
|
||||||
|
}
|
||||||
|
store.dispatch('data/addGithubToken', token);
|
||||||
|
},
|
||||||
|
async removeTokenImgStorage(token, sid) {
|
||||||
|
if (!token.imgStorages || token.imgStorages.length === 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
token.imgStorages = token.imgStorages.filter(it => it.sid !== sid);
|
||||||
|
store.dispatch('data/addGithubToken', token);
|
||||||
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* https://developer.github.com/v3/gists/#create-a-gist
|
* https://developer.github.com/v3/gists/#create-a-gist
|
||||||
|
Loading…
Reference in New Issue
Block a user