support gitea
This commit is contained in:
parent
329d00c707
commit
666db76f3c
@ -3,6 +3,7 @@ var prodEnv = require('./prod.env')
|
||||
|
||||
module.exports = merge(prodEnv, {
|
||||
NODE_ENV: '"development"',
|
||||
// 以下配置是开发临时用的配置 随时可能失效 请替换为自己的
|
||||
GITHUB_CLIENT_ID: '"845b8f75df48f2ee0563"',
|
||||
GITHUB_CLIENT_SECRET: '"80df676597abded1450926861965cc3f9bead6a0"',
|
||||
GITEE_CLIENT_ID: '"925ba7c78b85dec984f7877e4aca5cab10ae333c6d68e761bdb0b9dfb8f55672"',
|
||||
|
@ -2,11 +2,7 @@ const qs = require('qs'); // eslint-disable-line import/no-extraneous-dependenci
|
||||
const request = require('request');
|
||||
const conf = require('./conf');
|
||||
|
||||
function giteeToken(clientId, code) {
|
||||
console.log('clientId: ' + clientId);
|
||||
console.log('code: ' + code);
|
||||
console.log('client_secret: ' + conf.values.giteeClientSecret);
|
||||
console.log('redirect_uri: ' + conf.values.giteeCallback);
|
||||
function giteeToken(clientId, code, oauth2RedirectUri) {
|
||||
return new Promise((resolve, reject) => {
|
||||
request({
|
||||
method: 'POST',
|
||||
@ -17,7 +13,7 @@ function giteeToken(clientId, code) {
|
||||
code,
|
||||
grant_type: 'authorization_code',
|
||||
scope: 'authorization_code',
|
||||
redirect_uri: conf.values.giteeCallback,
|
||||
redirect_uri: oauth2RedirectUri,
|
||||
},
|
||||
json: true
|
||||
}, (err, res, body) => {
|
||||
@ -35,7 +31,7 @@ function giteeToken(clientId, code) {
|
||||
}
|
||||
|
||||
exports.giteeToken = (req, res) => {
|
||||
giteeToken(req.query.clientId, req.query.code)
|
||||
giteeToken(req.query.clientId, req.query.code, req.query.oauth2RedirectUri)
|
||||
.then(
|
||||
token => res.send(token),
|
||||
err => res
|
||||
|
5
src/assets/iconGitea.svg
Normal file
5
src/assets/iconGitea.svg
Normal file
@ -0,0 +1,5 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 640 640" style="enable-background:new 0 0 640 640" xml:space="preserve" width="32" height="32">
|
||||
<path style="fill:#fff" d="m395.9 484.2-126.9-61c-12.5-6-17.9-21.2-11.8-33.8l61-126.9c6-12.5 21.2-17.9 33.8-11.8 17.2 8.3 27.1 13 27.1 13l-.1-109.2 16.7-.1.1 117.1s57.4 24.2 83.1 40.1c3.7 2.3 10.2 6.8 12.9 14.4 2.1 6.1 2 13.1-1 19.3l-61 126.9c-6.2 12.7-21.4 18.1-33.9 12z"/>
|
||||
<path style="fill:#609926" d="M622.7 149.8c-4.1-4.1-9.6-4-9.6-4s-117.2 6.6-177.9 8c-13.3.3-26.5.6-39.6.7v117.2c-5.5-2.6-11.1-5.3-16.6-7.9 0-36.4-.1-109.2-.1-109.2-29 .4-89.2-2.2-89.2-2.2s-141.4-7.1-156.8-8.5c-9.8-.6-22.5-2.1-39 1.5-8.7 1.8-33.5 7.4-53.8 26.9C-4.9 212.4 6.6 276.2 8 285.8c1.7 11.7 6.9 44.2 31.7 72.5 45.8 56.1 144.4 54.8 144.4 54.8s12.1 28.9 30.6 55.5c25 33.1 50.7 58.9 75.7 62 63 0 188.9-.1 188.9-.1s12 .1 28.3-10.3c14-8.5 26.5-23.4 26.5-23.4S547 483 565 451.5c5.5-9.7 10.1-19.1 14.1-28 0 0 55.2-117.1 55.2-231.1-1.1-34.5-9.6-40.6-11.6-42.6zM125.6 353.9c-25.9-8.5-36.9-18.7-36.9-18.7S69.6 321.8 60 295.4c-16.5-44.2-1.4-71.2-1.4-71.2s8.4-22.5 38.5-30c13.8-3.7 31-3.1 31-3.1s7.1 59.4 15.7 94.2c7.2 29.2 24.8 77.7 24.8 77.7s-26.1-3.1-43-9.1zm300.3 107.6s-6.1 14.5-19.6 15.4c-5.8.4-10.3-1.2-10.3-1.2s-.3-.1-5.3-2.1l-112.9-55s-10.9-5.7-12.8-15.6c-2.2-8.1 2.7-18.1 2.7-18.1L322 273s4.8-9.7 12.2-13c.6-.3 2.3-1 4.5-1.5 8.1-2.1 18 2.8 18 2.8L467.4 315s12.6 5.7 15.3 16.2c1.9 7.4-.5 14-1.8 17.2-6.3 15.4-55 113.1-55 113.1z"/>
|
||||
<path style="fill:#609926" d="M326.8 380.1c-8.2.1-15.4 5.8-17.3 13.8-1.9 8 2 16.3 9.1 20 7.7 4 17.5 1.8 22.7-5.4 5.1-7.1 4.3-16.9-1.8-23.1l24-49.1c1.5.1 3.7.2 6.2-.5 4.1-.9 7.1-3.6 7.1-3.6 4.2 1.8 8.6 3.8 13.2 6.1 4.8 2.4 9.3 4.9 13.4 7.3.9.5 1.8 1.1 2.8 1.9 1.6 1.3 3.4 3.1 4.7 5.5 1.9 5.5-1.9 14.9-1.9 14.9-2.3 7.6-18.4 40.6-18.4 40.6-8.1-.2-15.3 5-17.7 12.5-2.6 8.1 1.1 17.3 8.9 21.3 7.8 4 17.4 1.7 22.5-5.3 5-6.8 4.6-16.3-1.1-22.6 1.9-3.7 3.7-7.4 5.6-11.3 5-10.4 13.5-30.4 13.5-30.4.9-1.7 5.7-10.3 2.7-21.3-2.5-11.4-12.6-16.7-12.6-16.7-12.2-7.9-29.2-15.2-29.2-15.2s0-4.1-1.1-7.1c-1.1-3.1-2.8-5.1-3.9-6.3 4.7-9.7 9.4-19.3 14.1-29-4.1-2-8.1-4-12.2-6.1-4.8 9.8-9.7 19.7-14.5 29.5-6.7-.1-12.9 3.5-16.1 9.4-3.4 6.3-2.7 14.1 1.9 19.8l-24.6 50.4z"/>
|
||||
</svg>
|
After Width: | Height: | Size: 2.2 KiB |
@ -66,6 +66,11 @@ import GitlabOpenModal from './modals/providers/GitlabOpenModal';
|
||||
import GitlabPublishModal from './modals/providers/GitlabPublishModal';
|
||||
import GitlabSaveModal from './modals/providers/GitlabSaveModal';
|
||||
import GitlabWorkspaceModal from './modals/providers/GitlabWorkspaceModal';
|
||||
import GiteaAccountModal from './modals/providers/GiteaAccountModal';
|
||||
import GiteaOpenModal from './modals/providers/GiteaOpenModal';
|
||||
import GiteaPublishModal from './modals/providers/GiteaPublishModal';
|
||||
import GiteaSaveModal from './modals/providers/GiteaSaveModal';
|
||||
import GiteaWorkspaceModal from './modals/providers/GiteaWorkspaceModal';
|
||||
import WordpressPublishModal from './modals/providers/WordpressPublishModal';
|
||||
import BloggerPublishModal from './modals/providers/BloggerPublishModal';
|
||||
import BloggerPagePublishModal from './modals/providers/BloggerPagePublishModal';
|
||||
@ -122,6 +127,11 @@ export default {
|
||||
GitlabPublishModal,
|
||||
GitlabSaveModal,
|
||||
GitlabWorkspaceModal,
|
||||
GiteaAccountModal,
|
||||
GiteaOpenModal,
|
||||
GiteaPublishModal,
|
||||
GiteaSaveModal,
|
||||
GiteaWorkspaceModal,
|
||||
WordpressPublishModal,
|
||||
BloggerPublishModal,
|
||||
BloggerPagePublishModal,
|
||||
|
@ -29,6 +29,9 @@
|
||||
<span v-else-if="currentWorkspace.providerId === 'gitlabWorkspace'">
|
||||
<b>{{currentWorkspace.name}}</b> synced with a <a :href="workspaceLocationUrl" target="_blank">GitLab project</a>.
|
||||
</span>
|
||||
<span v-else-if="currentWorkspace.providerId === 'giteaWorkspace'">
|
||||
<b>{{currentWorkspace.name}}</b> synced with a <a :href="workspaceLocationUrl" target="_blank">Gitea project</a>.
|
||||
</span>
|
||||
</div>
|
||||
<div class="menu-entry menu-entry--info flex flex--row flex--align-center" v-else>
|
||||
<div class="menu-entry__icon menu-entry__icon--disabled">
|
||||
|
@ -66,6 +66,13 @@
|
||||
<span>{{token.name}}</span>
|
||||
</menu-entry>
|
||||
</div>
|
||||
<div v-for="token in giteaTokens" :key="token.sub">
|
||||
<menu-entry @click.native="publishGitea(token)">
|
||||
<icon-provider slot="icon" provider-id="gitea"></icon-provider>
|
||||
<div>Publish to Gitea</div>
|
||||
<span>{{token.name}}</span>
|
||||
</menu-entry>
|
||||
</div>
|
||||
<div v-for="token in googleDriveTokens" :key="token.sub">
|
||||
<menu-entry @click.native="publishGoogleDrive(token)">
|
||||
<icon-provider slot="icon" provider-id="googleDrive"></icon-provider>
|
||||
@ -108,6 +115,10 @@
|
||||
<icon-provider slot="icon" provider-id="gitlab"></icon-provider>
|
||||
<span>Add GitLab account</span>
|
||||
</menu-entry>
|
||||
<menu-entry @click.native="addGiteaAccount">
|
||||
<icon-provider slot="icon" provider-id="gitea"></icon-provider>
|
||||
<span>Add Gitea account</span>
|
||||
</menu-entry>
|
||||
<menu-entry @click.native="addGoogleDriveAccount">
|
||||
<icon-provider slot="icon" provider-id="googleDrive"></icon-provider>
|
||||
<span>Add Google Drive account</span>
|
||||
@ -132,6 +143,7 @@ import dropboxHelper from '../../services/providers/helpers/dropboxHelper';
|
||||
import githubHelper from '../../services/providers/helpers/githubHelper';
|
||||
import giteeHelper from '../../services/providers/helpers/giteeHelper';
|
||||
import gitlabHelper from '../../services/providers/helpers/gitlabHelper';
|
||||
import giteaHelper from '../../services/providers/helpers/giteaHelper';
|
||||
import wordpressHelper from '../../services/providers/helpers/wordpressHelper';
|
||||
import zendeskHelper from '../../services/providers/helpers/zendeskHelper';
|
||||
import publishSvc from '../../services/publishSvc';
|
||||
@ -186,6 +198,9 @@ export default {
|
||||
gitlabTokens() {
|
||||
return tokensToArray(store.getters['data/gitlabTokensBySub']);
|
||||
},
|
||||
giteaTokens() {
|
||||
return tokensToArray(store.getters['data/giteaTokensBySub']);
|
||||
},
|
||||
googleDriveTokens() {
|
||||
return tokensToArray(store.getters['data/googleTokensBySub'], token => token.isDrive);
|
||||
},
|
||||
@ -199,7 +214,9 @@ export default {
|
||||
return !this.bloggerTokens.length
|
||||
&& !this.dropboxTokens.length
|
||||
&& !this.githubTokens.length
|
||||
&& !this.giteeTokens.length
|
||||
&& !this.gitlabTokens.length
|
||||
&& !this.giteaTokens.length
|
||||
&& !this.googleDriveTokens.length
|
||||
&& !this.wordpressTokens.length
|
||||
&& !this.zendeskTokens.length;
|
||||
@ -245,6 +262,12 @@ export default {
|
||||
await gitlabHelper.addAccount(serverUrl, applicationId);
|
||||
} catch (e) { /* cancel */ }
|
||||
},
|
||||
async addGiteaAccount() {
|
||||
try {
|
||||
const { serverUrl, applicationId, applicationSecret } = await store.dispatch('modal/open', { type: 'giteaAccount' });
|
||||
await giteaHelper.addAccount(serverUrl, applicationId, applicationSecret);
|
||||
} catch (e) { /* cancel */ }
|
||||
},
|
||||
async addGoogleDriveAccount() {
|
||||
try {
|
||||
await store.dispatch('modal/open', { type: 'googleDriveAccount' });
|
||||
@ -269,6 +292,7 @@ export default {
|
||||
publishGitee: publishModalOpener('giteePublish', 'publishToGitee'),
|
||||
publishGist: publishModalOpener('gistPublish', 'publishToGist'),
|
||||
publishGitlab: publishModalOpener('gitlabPublish', 'publishToGitlab'),
|
||||
publishGitea: publishModalOpener('giteaPublish', 'publishToGitea'),
|
||||
publishGoogleDrive: publishModalOpener('googleDrivePublish', 'publishToGoogleDrive'),
|
||||
publishWordpress: publishModalOpener('wordpressPublish', 'publishToWordPress'),
|
||||
publishZendesk: publishModalOpener('zendeskPublish', 'publishToZendesk'),
|
||||
|
@ -74,6 +74,18 @@
|
||||
<span>{{token.name}}</span>
|
||||
</menu-entry>
|
||||
</div>
|
||||
<div v-for="token in giteaTokens" :key="token.sub">
|
||||
<menu-entry @click.native="openGitea(token)">
|
||||
<icon-provider slot="icon" provider-id="gitea"></icon-provider>
|
||||
<div>Open from Gitea</div>
|
||||
<span>{{token.name}}</span>
|
||||
</menu-entry>
|
||||
<menu-entry @click.native="saveGitea(token)">
|
||||
<icon-provider slot="icon" provider-id="gitea"></icon-provider>
|
||||
<div>Save on Gitea</div>
|
||||
<span>{{token.name}}</span>
|
||||
</menu-entry>
|
||||
</div>
|
||||
<div v-for="token in googleDriveTokens" :key="token.sub">
|
||||
<menu-entry @click.native="openGoogleDrive(token)">
|
||||
<icon-provider slot="icon" provider-id="googleDrive"></icon-provider>
|
||||
@ -103,6 +115,10 @@
|
||||
<icon-provider slot="icon" provider-id="gitlab"></icon-provider>
|
||||
<span>Add GitLab account</span>
|
||||
</menu-entry>
|
||||
<menu-entry @click.native="addGiteaAccount">
|
||||
<icon-provider slot="icon" provider-id="gitea"></icon-provider>
|
||||
<span>Add Gitea account</span>
|
||||
</menu-entry>
|
||||
<menu-entry @click.native="addGoogleDriveAccount">
|
||||
<icon-provider slot="icon" provider-id="googleDrive"></icon-provider>
|
||||
<span>Add Google Drive account</span>
|
||||
@ -119,11 +135,13 @@ import dropboxHelper from '../../services/providers/helpers/dropboxHelper';
|
||||
import githubHelper from '../../services/providers/helpers/githubHelper';
|
||||
import giteeHelper from '../../services/providers/helpers/giteeHelper';
|
||||
import gitlabHelper from '../../services/providers/helpers/gitlabHelper';
|
||||
import giteaHelper from '../../services/providers/helpers/giteaHelper';
|
||||
import googleDriveProvider from '../../services/providers/googleDriveProvider';
|
||||
import dropboxProvider from '../../services/providers/dropboxProvider';
|
||||
import githubProvider from '../../services/providers/githubProvider';
|
||||
import giteeProvider from '../../services/providers/giteeProvider';
|
||||
import gitlabProvider from '../../services/providers/gitlabProvider';
|
||||
import giteaProvider from '../../services/providers/giteaProvider';
|
||||
import syncSvc from '../../services/syncSvc';
|
||||
import store from '../../store';
|
||||
import badgeSvc from '../../services/badgeSvc';
|
||||
@ -172,6 +190,9 @@ export default {
|
||||
gitlabTokens() {
|
||||
return tokensToArray(store.getters['data/gitlabTokensBySub']);
|
||||
},
|
||||
giteaTokens() {
|
||||
return tokensToArray(store.getters['data/giteaTokensBySub']);
|
||||
},
|
||||
googleDriveTokens() {
|
||||
return tokensToArray(store.getters['data/googleTokensBySub'], token => token.isDrive);
|
||||
},
|
||||
@ -217,6 +238,12 @@ export default {
|
||||
await gitlabHelper.addAccount(serverUrl, applicationId);
|
||||
} catch (e) { /* cancel */ }
|
||||
},
|
||||
async addGiteaAccount() {
|
||||
try {
|
||||
const { serverUrl, applicationId, applicationSecret } = await store.dispatch('modal/open', { type: 'giteaAccount' });
|
||||
await giteaHelper.addAccount(serverUrl, applicationId, applicationSecret);
|
||||
} catch (e) { /* cancel */ }
|
||||
},
|
||||
async addGoogleDriveAccount() {
|
||||
try {
|
||||
await store.dispatch('modal/open', { type: 'googleDriveAccount' });
|
||||
@ -318,12 +345,33 @@ export default {
|
||||
);
|
||||
} catch (e) { /* cancel */ }
|
||||
},
|
||||
async openGitea(token) {
|
||||
try {
|
||||
const syncLocation = await store.dispatch('modal/open', {
|
||||
type: 'giteaOpen',
|
||||
token,
|
||||
});
|
||||
store.dispatch(
|
||||
'queue/enqueue',
|
||||
async () => {
|
||||
await giteaProvider.openFile(token, syncLocation);
|
||||
badgeSvc.addBadge('openFromGitea');
|
||||
},
|
||||
);
|
||||
} catch (e) { /* cancel */ }
|
||||
},
|
||||
async saveGitlab(token) {
|
||||
try {
|
||||
await openSyncModal(token, 'gitlabSave');
|
||||
badgeSvc.addBadge('saveOnGitlab');
|
||||
} catch (e) { /* cancel */ }
|
||||
},
|
||||
async saveGitea(token) {
|
||||
try {
|
||||
await openSyncModal(token, 'giteaSave');
|
||||
badgeSvc.addBadge('saveOnGitea');
|
||||
} catch (e) { /* cancel */ }
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
@ -29,6 +29,10 @@
|
||||
<icon-provider slot="icon" provider-id="gitlabWorkspace"></icon-provider>
|
||||
<span>Add a <b>GitLab</b> workspace</span>
|
||||
</menu-entry>
|
||||
<menu-entry @click.native="addGiteaWorkspace">
|
||||
<icon-provider slot="icon" provider-id="giteaWorkspace"></icon-provider>
|
||||
<span>Add a <b>Gitea</b> workspace</span>
|
||||
</menu-entry>
|
||||
<menu-entry @click.native="addGoogleDriveWorkspace">
|
||||
<icon-provider slot="icon" provider-id="googleDriveWorkspace"></icon-provider>
|
||||
<span>Add a <b>Google Drive</b> workspace</span>
|
||||
@ -41,6 +45,7 @@ import { mapGetters } from 'vuex';
|
||||
import MenuEntry from './common/MenuEntry';
|
||||
import googleHelper from '../../services/providers/helpers/googleHelper';
|
||||
import gitlabHelper from '../../services/providers/helpers/gitlabHelper';
|
||||
import giteaHelper from '../../services/providers/helpers/giteaHelper';
|
||||
import store from '../../store';
|
||||
|
||||
export default {
|
||||
@ -88,6 +93,16 @@ export default {
|
||||
});
|
||||
} catch (e) { /* Cancel */ }
|
||||
},
|
||||
async addGiteaWorkspace() {
|
||||
try {
|
||||
const { serverUrl, applicationId, applicationSecret } = await store.dispatch('modal/open', { type: 'giteaAccount' });
|
||||
const token = await giteaHelper.addAccount(serverUrl, applicationId, applicationSecret);
|
||||
store.dispatch('modal/open', {
|
||||
type: 'giteaWorkspace',
|
||||
token,
|
||||
});
|
||||
} catch (e) { /* Cancel */ }
|
||||
},
|
||||
async addGoogleDriveWorkspace() {
|
||||
try {
|
||||
const token = await googleHelper.addDriveAccount(true);
|
||||
|
@ -57,6 +57,10 @@
|
||||
<icon-provider slot="icon" provider-id="gitlab"></icon-provider>
|
||||
<span>Add GitLab account</span>
|
||||
</menu-entry>
|
||||
<menu-entry @click.native="addGiteaAccount">
|
||||
<icon-provider slot="icon" provider-id="gitea"></icon-provider>
|
||||
<span>Add Gitea account</span>
|
||||
</menu-entry>
|
||||
<menu-entry @click.native="addGoogleDriveAccount">
|
||||
<icon-provider slot="icon" provider-id="googleDrive"></icon-provider>
|
||||
<span>Add Google Drive account</span>
|
||||
@ -91,6 +95,7 @@ import dropboxHelper from '../../services/providers/helpers/dropboxHelper';
|
||||
import githubHelper from '../../services/providers/helpers/githubHelper';
|
||||
import giteeHelper from '../../services/providers/helpers/giteeHelper';
|
||||
import gitlabHelper from '../../services/providers/helpers/gitlabHelper';
|
||||
import giteaHelper from '../../services/providers/helpers/giteaHelper';
|
||||
import wordpressHelper from '../../services/providers/helpers/wordpressHelper';
|
||||
import zendeskHelper from '../../services/providers/helpers/zendeskHelper';
|
||||
import badgeSvc from '../../services/badgeSvc';
|
||||
@ -148,6 +153,14 @@ export default {
|
||||
name: token.name,
|
||||
scopes: ['api'],
|
||||
})),
|
||||
...Object.values(store.getters['data/giteaTokensBySub']).map(token => ({
|
||||
token,
|
||||
providerId: 'gitea',
|
||||
url: token.serverUrl,
|
||||
userId: token.sub,
|
||||
name: token.name,
|
||||
scopes: ['api'],
|
||||
})),
|
||||
...Object.values(store.getters['data/wordpressTokensBySub']).map(token => ({
|
||||
token,
|
||||
providerId: 'wordpress',
|
||||
@ -204,6 +217,12 @@ export default {
|
||||
await gitlabHelper.addAccount(serverUrl, applicationId);
|
||||
} catch (e) { /* cancel */ }
|
||||
},
|
||||
async addGiteaAccount() {
|
||||
try {
|
||||
const { serverUrl, applicationId, applicationSecret } = await store.dispatch('modal/open', { type: 'giteaAccount' });
|
||||
await giteaHelper.addAccount(serverUrl, applicationId, applicationSecret);
|
||||
} catch (e) { /* cancel */ }
|
||||
},
|
||||
async addGoogleDriveAccount() {
|
||||
try {
|
||||
await store.dispatch('modal/open', { type: 'googleDriveAccount' });
|
||||
|
75
src/components/modals/providers/GiteaAccountModal.vue
Normal file
75
src/components/modals/providers/GiteaAccountModal.vue
Normal file
@ -0,0 +1,75 @@
|
||||
<template>
|
||||
<modal-inner aria-label="Gitea account">
|
||||
<div class="modal__content">
|
||||
<div class="modal__image">
|
||||
<icon-provider provider-id="gitea"></icon-provider>
|
||||
</div>
|
||||
<p>Link your <b>Gitea</b> account to <b>StackEdit</b>.</p>
|
||||
<form-entry label="Gitea URL" error="serverUrl">
|
||||
<input v-if="config.forceServerUrl" slot="field" class="textfield" type="text" disabled="disabled" v-model="config.forceServerUrl">
|
||||
<input v-else slot="field" class="textfield" type="text" v-model.trim="serverUrl" @keydown.enter="resolve()">
|
||||
<div class="form-entry__info">
|
||||
<b>Example:</b> https://gitea.example.com/
|
||||
</div>
|
||||
</form-entry>
|
||||
<form-entry label="Application ID" error="applicationId">
|
||||
<input slot="field" class="textfield" type="text" v-model.trim="applicationId" @keydown.enter="resolve()">
|
||||
</form-entry>
|
||||
<form-entry label="Application Secret" error="applicationSecret">
|
||||
<input slot="field" class="textfield" type="text" v-model.trim="applicationSecret" @keydown.enter="resolve()">
|
||||
<div class="form-entry__info">
|
||||
You have to configure an OAuth2 Application with redirect URL <b>{{redirectUrl}}</b>
|
||||
</div>
|
||||
<div class="form-entry__actions">
|
||||
<a href="https://docs.gitea.io/en-us/oauth2-provider/" target="_blank">More info</a>
|
||||
</div>
|
||||
</form-entry>
|
||||
</div>
|
||||
<div class="modal__button-bar">
|
||||
<button class="button" @click="config.reject()">Cancel</button>
|
||||
<button class="button button--resolve" @click="resolve()">Ok</button>
|
||||
</div>
|
||||
</modal-inner>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import modalTemplate from '../common/modalTemplate';
|
||||
import constants from '../../../data/constants';
|
||||
|
||||
export default modalTemplate({
|
||||
data: () => ({
|
||||
redirectUrl: constants.oauth2RedirectUri,
|
||||
}),
|
||||
computedLocalSettings: {
|
||||
serverUrl: 'giteaServerUrl',
|
||||
applicationId: 'giteaApplicationId',
|
||||
applicationSecret: 'giteaApplicationSecret',
|
||||
},
|
||||
methods: {
|
||||
resolve() {
|
||||
const serverUrl = this.config.forceServerUrl || this.serverUrl;
|
||||
if (!serverUrl) {
|
||||
this.setError('serverUrl');
|
||||
}
|
||||
if (!this.applicationId) {
|
||||
this.setError('applicationId');
|
||||
}
|
||||
if (!this.applicationSecret) {
|
||||
this.setError('applicationSecret');
|
||||
}
|
||||
if (serverUrl && this.applicationId) {
|
||||
const parsedUrl = serverUrl.match(/^(https:\/\/[^/]+)/);
|
||||
if (!parsedUrl) {
|
||||
this.setError('serverUrl');
|
||||
} else {
|
||||
this.config.resolve({
|
||||
serverUrl: parsedUrl[1],
|
||||
applicationId: this.applicationId,
|
||||
applicationSecret: this.applicationSecret,
|
||||
});
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
});
|
||||
</script>
|
69
src/components/modals/providers/GiteaOpenModal.vue
Normal file
69
src/components/modals/providers/GiteaOpenModal.vue
Normal file
@ -0,0 +1,69 @@
|
||||
<template>
|
||||
<modal-inner aria-label="Synchronize with Gitea">
|
||||
<div class="modal__content">
|
||||
<div class="modal__image">
|
||||
<icon-provider provider-id="gitea"></icon-provider>
|
||||
</div>
|
||||
<p>Open a file from your <b>Gitea</b> project and keep it synced.</p>
|
||||
<form-entry label="Project URL" error="projectUrl">
|
||||
<input slot="field" class="textfield" type="text" v-model.trim="projectUrl" @keydown.enter="resolve()">
|
||||
<div class="form-entry__info">
|
||||
<b>Example:</b> {{config.token.serverUrl}}/path/to/project
|
||||
</div>
|
||||
</form-entry>
|
||||
<form-entry label="File path" error="path">
|
||||
<input slot="field" class="textfield" type="text" v-model.trim="path" @keydown.enter="resolve()">
|
||||
<div class="form-entry__info">
|
||||
<b>Example:</b> path/to/README.md
|
||||
</div>
|
||||
</form-entry>
|
||||
<form-entry label="Branch" info="optional">
|
||||
<input slot="field" class="textfield" type="text" v-model.trim="branch" @keydown.enter="resolve()">
|
||||
<div class="form-entry__info">
|
||||
If not supplied, the <code>master</code> branch will be used.
|
||||
</div>
|
||||
</form-entry>
|
||||
</div>
|
||||
<div class="modal__button-bar">
|
||||
<button class="button" @click="config.reject()">Cancel</button>
|
||||
<button class="button button--resolve" @click="resolve()">Ok</button>
|
||||
</div>
|
||||
</modal-inner>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import giteaProvider from '../../../services/providers/giteaProvider';
|
||||
import modalTemplate from '../common/modalTemplate';
|
||||
import utils from '../../../services/utils';
|
||||
|
||||
export default modalTemplate({
|
||||
data: () => ({
|
||||
branch: '',
|
||||
path: '',
|
||||
}),
|
||||
computedLocalSettings: {
|
||||
projectUrl: 'giteaProjectUrl',
|
||||
},
|
||||
methods: {
|
||||
resolve() {
|
||||
const projectPath = utils.parseGiteaProjectPath(this.projectUrl);
|
||||
if (!projectPath) {
|
||||
this.setError('projectUrl');
|
||||
}
|
||||
if (!this.path) {
|
||||
this.setError('path');
|
||||
}
|
||||
if (projectPath && this.path) {
|
||||
// Return new location
|
||||
const location = giteaProvider.makeLocation(
|
||||
this.config.token,
|
||||
projectPath,
|
||||
this.branch || 'master',
|
||||
this.path,
|
||||
);
|
||||
this.config.resolve(location);
|
||||
}
|
||||
},
|
||||
},
|
||||
});
|
||||
</script>
|
85
src/components/modals/providers/GiteaPublishModal.vue
Normal file
85
src/components/modals/providers/GiteaPublishModal.vue
Normal file
@ -0,0 +1,85 @@
|
||||
<template>
|
||||
<modal-inner aria-label="Publish to Gitea">
|
||||
<div class="modal__content">
|
||||
<div class="modal__image">
|
||||
<icon-provider provider-id="gitea"></icon-provider>
|
||||
</div>
|
||||
<p>Publish <b>{{currentFileName}}</b> to your <b>Gitea</b> project.</p>
|
||||
<form-entry label="Project URL" error="projectUrl">
|
||||
<input slot="field" class="textfield" type="text" v-model.trim="projectUrl" @keydown.enter="resolve()">
|
||||
<div class="form-entry__info">
|
||||
<b>Example:</b> {{config.token.serverUrl}}/path/to/project
|
||||
</div>
|
||||
</form-entry>
|
||||
<form-entry label="File path" error="path">
|
||||
<input slot="field" class="textfield" type="text" v-model.trim="path" @keydown.enter="resolve()">
|
||||
<div class="form-entry__info">
|
||||
<b>Example:</b> path/to/README.md<br>
|
||||
If the file exists, it will be overwritten.
|
||||
</div>
|
||||
</form-entry>
|
||||
<form-entry label="Branch" info="optional">
|
||||
<input slot="field" class="textfield" type="text" v-model.trim="branch" @keydown.enter="resolve()">
|
||||
<div class="form-entry__info">
|
||||
If not supplied, the <code>master</code> branch will be used.
|
||||
</div>
|
||||
</form-entry>
|
||||
<form-entry label="Template">
|
||||
<select slot="field" class="textfield" v-model="selectedTemplate" @keydown.enter="resolve()">
|
||||
<option v-for="(template, id) in allTemplatesById" :key="id" :value="id">
|
||||
{{ template.name }}
|
||||
</option>
|
||||
</select>
|
||||
<div class="form-entry__actions">
|
||||
<a href="javascript:void(0)" @click="configureTemplates">Configure templates</a>
|
||||
</div>
|
||||
</form-entry>
|
||||
</div>
|
||||
<div class="modal__button-bar">
|
||||
<button class="button" @click="config.reject()">Cancel</button>
|
||||
<button class="button button--resolve" @click="resolve()">Ok</button>
|
||||
</div>
|
||||
</modal-inner>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import giteaProvider from '../../../services/providers/giteaProvider';
|
||||
import modalTemplate from '../common/modalTemplate';
|
||||
import utils from '../../../services/utils';
|
||||
|
||||
export default modalTemplate({
|
||||
data: () => ({
|
||||
branch: '',
|
||||
path: '',
|
||||
}),
|
||||
computedLocalSettings: {
|
||||
projectUrl: 'giteaProjectUrl',
|
||||
selectedTemplate: 'giteaPublishTemplate',
|
||||
},
|
||||
created() {
|
||||
this.path = `${this.currentFileName}.md`;
|
||||
},
|
||||
methods: {
|
||||
resolve() {
|
||||
const projectPath = utils.parseGiteaProjectPath(this.projectUrl);
|
||||
if (!projectPath) {
|
||||
this.setError('projectUrl');
|
||||
}
|
||||
if (!this.path) {
|
||||
this.setError('path');
|
||||
}
|
||||
if (projectPath && this.path) {
|
||||
// Return new location
|
||||
const location = giteaProvider.makeLocation(
|
||||
this.config.token,
|
||||
projectPath,
|
||||
this.branch || 'master',
|
||||
this.path,
|
||||
);
|
||||
location.templateId = this.selectedTemplate;
|
||||
this.config.resolve(location);
|
||||
}
|
||||
},
|
||||
},
|
||||
});
|
||||
</script>
|
72
src/components/modals/providers/GiteaSaveModal.vue
Normal file
72
src/components/modals/providers/GiteaSaveModal.vue
Normal file
@ -0,0 +1,72 @@
|
||||
<template>
|
||||
<modal-inner aria-label="Synchronize with Gitea">
|
||||
<div class="modal__content">
|
||||
<div class="modal__image">
|
||||
<icon-provider provider-id="gitea"></icon-provider>
|
||||
</div>
|
||||
<p>Save <b>{{currentFileName}}</b> to your <b>Gitea</b> project and keep it synced.</p>
|
||||
<form-entry label="Project URL" error="projectUrl">
|
||||
<input slot="field" class="textfield" type="text" v-model.trim="projectUrl" @keydown.enter="resolve()">
|
||||
<div class="form-entry__info">
|
||||
<b>Example:</b> {{config.token.serverUrl}}/path/to/project
|
||||
</div>
|
||||
</form-entry>
|
||||
<form-entry label="File path" error="path">
|
||||
<input slot="field" class="textfield" type="text" v-model.trim="path" @keydown.enter="resolve()">
|
||||
<div class="form-entry__info">
|
||||
<b>Example:</b> path/to/README.md<br>
|
||||
If the file exists, it will be overwritten.
|
||||
</div>
|
||||
</form-entry>
|
||||
<form-entry label="Branch" info="optional">
|
||||
<input slot="field" class="textfield" type="text" v-model.trim="branch" @keydown.enter="resolve()">
|
||||
<div class="form-entry__info">
|
||||
If not supplied, the <code>master</code> branch will be used.
|
||||
</div>
|
||||
</form-entry>
|
||||
</div>
|
||||
<div class="modal__button-bar">
|
||||
<button class="button" @click="config.reject()">Cancel</button>
|
||||
<button class="button button--resolve" @click="resolve()">Ok</button>
|
||||
</div>
|
||||
</modal-inner>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import giteaProvider from '../../../services/providers/giteaProvider';
|
||||
import modalTemplate from '../common/modalTemplate';
|
||||
import utils from '../../../services/utils';
|
||||
|
||||
export default modalTemplate({
|
||||
data: () => ({
|
||||
branch: '',
|
||||
path: '',
|
||||
}),
|
||||
computedLocalSettings: {
|
||||
projectUrl: 'giteaProjectUrl',
|
||||
},
|
||||
created() {
|
||||
this.path = `${this.currentFileName}.md`;
|
||||
},
|
||||
methods: {
|
||||
resolve() {
|
||||
const projectPath = utils.parseGiteaProjectPath(this.projectUrl);
|
||||
if (!projectPath) {
|
||||
this.setError('projectUrl');
|
||||
}
|
||||
if (!this.path) {
|
||||
this.setError('path');
|
||||
}
|
||||
if (projectPath && this.path) {
|
||||
const location = giteaProvider.makeLocation(
|
||||
this.config.token,
|
||||
projectPath,
|
||||
this.branch || 'master',
|
||||
this.path,
|
||||
);
|
||||
this.config.resolve(location);
|
||||
}
|
||||
},
|
||||
},
|
||||
});
|
||||
</script>
|
67
src/components/modals/providers/GiteaWorkspaceModal.vue
Normal file
67
src/components/modals/providers/GiteaWorkspaceModal.vue
Normal file
@ -0,0 +1,67 @@
|
||||
<template>
|
||||
<modal-inner aria-label="Synchronize with Gitea">
|
||||
<div class="modal__content">
|
||||
<div class="modal__image">
|
||||
<icon-provider provider-id="gitea"></icon-provider>
|
||||
</div>
|
||||
<p>Create a workspace synced with a <b>Gitea</b> project folder.</p>
|
||||
<form-entry label="Project URL" error="projectUrl">
|
||||
<input slot="field" class="textfield" type="text" v-model.trim="projectUrl" @keydown.enter="resolve()">
|
||||
<div class="form-entry__info">
|
||||
<b>Example:</b> {{config.token.serverUrl}}/path/to/project
|
||||
</div>
|
||||
</form-entry>
|
||||
<form-entry label="Folder path" info="optional">
|
||||
<input slot="field" class="textfield" type="text" v-model.trim="path" @keydown.enter="resolve()">
|
||||
<div class="form-entry__info">
|
||||
If not supplied, the root folder will be used.
|
||||
</div>
|
||||
</form-entry>
|
||||
<form-entry label="Branch" info="optional">
|
||||
<input slot="field" class="textfield" type="text" v-model.trim="branch" @keydown.enter="resolve()">
|
||||
<div class="form-entry__info">
|
||||
If not supplied, the <code>master</code> branch will be used.
|
||||
</div>
|
||||
</form-entry>
|
||||
</div>
|
||||
<div class="modal__button-bar">
|
||||
<button class="button" @click="config.reject()">Cancel</button>
|
||||
<button class="button button--resolve" @click="resolve()">Ok</button>
|
||||
</div>
|
||||
</modal-inner>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import utils from '../../../services/utils';
|
||||
import modalTemplate from '../common/modalTemplate';
|
||||
|
||||
export default modalTemplate({
|
||||
data: () => ({
|
||||
branch: '',
|
||||
path: '',
|
||||
}),
|
||||
computedLocalSettings: {
|
||||
projectUrl: 'giteaWorkspaceProjectUrl',
|
||||
},
|
||||
methods: {
|
||||
resolve() {
|
||||
const projectPath = utils.parseGiteaProjectPath(this.projectUrl);
|
||||
if (!projectPath) {
|
||||
this.setError('projectUrl');
|
||||
} else {
|
||||
const path = this.path && this.path.replace(/^\//, '');
|
||||
const url = utils.addQueryParams('app', {
|
||||
providerId: 'giteaWorkspace',
|
||||
serverUrl: this.config.token.serverUrl,
|
||||
projectPath,
|
||||
branch: this.branch || 'master',
|
||||
path: path || undefined,
|
||||
sub: this.config.token.sub,
|
||||
}, true);
|
||||
this.config.resolve();
|
||||
window.open(url);
|
||||
}
|
||||
},
|
||||
},
|
||||
});
|
||||
</script>
|
@ -21,11 +21,18 @@ export default () => ({
|
||||
gistPublishTemplate: 'plainText',
|
||||
giteeRepoUrl: '',
|
||||
giteeWorkspaceRepoUrl: '',
|
||||
giteePublishTemplate: 'jekyllSite',
|
||||
gitlabServerUrl: '',
|
||||
gitlabApplicationId: '',
|
||||
gitlabProjectUrl: '',
|
||||
gitlabWorkspaceProjectUrl: '',
|
||||
gitlabPublishTemplate: 'plainText',
|
||||
giteaServerUrl: '',
|
||||
giteaApplicationId: '',
|
||||
giteaApplicationSecret: '',
|
||||
giteaProjectUrl: '',
|
||||
giteaWorkspaceProjectUrl: '',
|
||||
giteaPublishTemplate: 'plainText',
|
||||
wordpressDomain: '',
|
||||
wordpressPublishTemplate: 'plainHtml',
|
||||
zendeskSiteUrl: '',
|
||||
|
@ -77,7 +77,7 @@ turndown:
|
||||
linkStyle: inlined
|
||||
linkReferenceStyle: full
|
||||
|
||||
# GitHub/GitLab commit messages
|
||||
# GitHub/GitLab/Gitee/Gitea commit messages
|
||||
git:
|
||||
createFileMessage: '{{path}} created from https://edit.qicoder.com/'
|
||||
updateFileMessage: '{{path}} updated from https://edit.qicoder.com/'
|
||||
|
@ -182,6 +182,11 @@ export default [
|
||||
'GitLab workspace creator',
|
||||
'Use the workspace menu to create a GitLab workspace.',
|
||||
),
|
||||
new Feature(
|
||||
'addGiteaWorkspace',
|
||||
'Gitea workspace creator',
|
||||
'Use the workspace menu to create a Gitea workspace.',
|
||||
),
|
||||
new Feature(
|
||||
'addGoogleDriveWorkspace',
|
||||
'Google Drive workspace creator',
|
||||
@ -229,6 +234,11 @@ export default [
|
||||
'GitLab user',
|
||||
'Link your GitLab account to StackEdit.',
|
||||
),
|
||||
new Feature(
|
||||
'addGiteaAccount',
|
||||
'Gitea user',
|
||||
'Link your Gitea account to StackEdit.',
|
||||
),
|
||||
new Feature(
|
||||
'addGoogleDriveAccount',
|
||||
'Google Drive user',
|
||||
@ -306,6 +316,16 @@ export default [
|
||||
'GitLab writer',
|
||||
'Use the "Synchronize" menu to save a file in a GitLab repository.',
|
||||
),
|
||||
new Feature(
|
||||
'openFromGitea',
|
||||
'Gitea reader',
|
||||
'Use the "Synchronize" menu to open a file from a Gitea repository.',
|
||||
),
|
||||
new Feature(
|
||||
'saveOnGitea',
|
||||
'Gitea writer',
|
||||
'Use the "Synchronize" menu to save a file in a Gitea repository.',
|
||||
),
|
||||
new Feature(
|
||||
'openFromGoogleDrive',
|
||||
'Google Drive reader',
|
||||
@ -373,6 +393,11 @@ export default [
|
||||
'GitLab publisher',
|
||||
'Use the "Publish" menu to publish a file to a GitLab repository.',
|
||||
),
|
||||
new Feature(
|
||||
'publishToGitea',
|
||||
'Gitea publisher',
|
||||
'Use the "Publish" menu to publish a file to a Gitea repository.',
|
||||
),
|
||||
new Feature(
|
||||
'publishToGoogleDrive',
|
||||
'Google Drive publisher',
|
||||
|
@ -22,6 +22,8 @@ export default {
|
||||
return 'github';
|
||||
case 'gitlabWorkspace':
|
||||
return 'gitlab';
|
||||
case 'giteaWorkspace':
|
||||
return 'gitea';
|
||||
case 'bloggerPage':
|
||||
return 'blogger';
|
||||
case 'couchdbWorkspace':
|
||||
@ -65,6 +67,10 @@ export default {
|
||||
background-image: url(../assets/iconGitlab.svg);
|
||||
}
|
||||
|
||||
.icon-provider--gitea {
|
||||
background-image: url(../assets/iconGitea.svg);
|
||||
}
|
||||
|
||||
.icon-provider--google {
|
||||
background-image: url(../assets/iconGoogle.svg);
|
||||
}
|
||||
|
171
src/services/providers/giteaProvider.js
Normal file
171
src/services/providers/giteaProvider.js
Normal file
@ -0,0 +1,171 @@
|
||||
import store from '../../store';
|
||||
import giteaHelper from './helpers/giteaHelper';
|
||||
import Provider from './common/Provider';
|
||||
import utils from '../utils';
|
||||
import workspaceSvc from '../workspaceSvc';
|
||||
import userSvc from '../userSvc';
|
||||
|
||||
const savedSha = {};
|
||||
|
||||
export default new Provider({
|
||||
id: 'gitea',
|
||||
name: 'Gitea',
|
||||
getToken({ sub }) {
|
||||
return store.getters['data/giteaTokensBySub'][sub];
|
||||
},
|
||||
getLocationUrl({
|
||||
sub,
|
||||
projectPath,
|
||||
branch,
|
||||
path,
|
||||
}) {
|
||||
const token = this.getToken({ sub });
|
||||
return `${token.serverUrl}/${projectPath}/src/branch/${encodeURIComponent(branch)}/${utils.encodeUrlPath(path)}`;
|
||||
},
|
||||
getLocationDescription({ path }) {
|
||||
return path;
|
||||
},
|
||||
async downloadContent(token, syncLocation) {
|
||||
const { sha, data } = await giteaHelper.downloadFile({
|
||||
...syncLocation,
|
||||
token,
|
||||
});
|
||||
savedSha[syncLocation.id] = sha;
|
||||
return Provider.parseContent(data, `${syncLocation.fileId}/content`);
|
||||
},
|
||||
async uploadContent(token, content, syncLocation) {
|
||||
const updatedSyncLocation = {
|
||||
...syncLocation,
|
||||
projectId: await giteaHelper.getProjectId(syncLocation),
|
||||
};
|
||||
if (!savedSha[updatedSyncLocation.id]) {
|
||||
try {
|
||||
// Get the last sha
|
||||
await this.downloadContent(token, updatedSyncLocation);
|
||||
} catch (e) {
|
||||
// Ignore error
|
||||
}
|
||||
}
|
||||
const sha = savedSha[updatedSyncLocation.id];
|
||||
delete savedSha[updatedSyncLocation.id];
|
||||
await giteaHelper.uploadFile({
|
||||
...updatedSyncLocation,
|
||||
token,
|
||||
content: Provider.serializeContent(content),
|
||||
sha,
|
||||
});
|
||||
return updatedSyncLocation;
|
||||
},
|
||||
async publish(token, html, metadata, publishLocation) {
|
||||
const updatedPublishLocation = {
|
||||
...publishLocation,
|
||||
projectId: await giteaHelper.getProjectId(publishLocation),
|
||||
};
|
||||
try {
|
||||
// Get the last sha
|
||||
await this.downloadContent(token, updatedPublishLocation);
|
||||
} catch (e) {
|
||||
// Ignore error
|
||||
}
|
||||
const sha = savedSha[updatedPublishLocation.id];
|
||||
delete savedSha[updatedPublishLocation.id];
|
||||
await giteaHelper.uploadFile({
|
||||
...updatedPublishLocation,
|
||||
token,
|
||||
content: html,
|
||||
sha,
|
||||
});
|
||||
return updatedPublishLocation;
|
||||
},
|
||||
async openFile(token, syncLocation) {
|
||||
const updatedSyncLocation = {
|
||||
...syncLocation,
|
||||
projectId: await giteaHelper.getProjectId(syncLocation),
|
||||
};
|
||||
|
||||
// Check if the file exists and open it
|
||||
if (!Provider.openFileWithLocation(updatedSyncLocation)) {
|
||||
// Download content from Gitea
|
||||
let content;
|
||||
try {
|
||||
content = await this.downloadContent(token, updatedSyncLocation);
|
||||
} catch (e) {
|
||||
store.dispatch('notification/error', `Could not open file ${updatedSyncLocation.path}.`);
|
||||
return;
|
||||
}
|
||||
|
||||
// Create the file
|
||||
let name = updatedSyncLocation.path;
|
||||
const slashPos = name.lastIndexOf('/');
|
||||
if (slashPos > -1 && slashPos < name.length - 1) {
|
||||
name = name.slice(slashPos + 1);
|
||||
}
|
||||
const dotPos = name.lastIndexOf('.');
|
||||
if (dotPos > 0 && slashPos < name.length) {
|
||||
name = name.slice(0, dotPos);
|
||||
}
|
||||
const item = await workspaceSvc.createFile({
|
||||
name,
|
||||
parentId: store.getters['file/current'].parentId,
|
||||
text: content.text,
|
||||
properties: content.properties,
|
||||
discussions: content.discussions,
|
||||
comments: content.comments,
|
||||
}, true);
|
||||
store.commit('file/setCurrentId', item.id);
|
||||
workspaceSvc.addSyncLocation({
|
||||
...updatedSyncLocation,
|
||||
fileId: item.id,
|
||||
});
|
||||
store.dispatch('notification/info', `${store.getters['file/current'].name} was imported from Gitea.`);
|
||||
}
|
||||
},
|
||||
makeLocation(token, projectPath, branch, path) {
|
||||
return {
|
||||
providerId: this.id,
|
||||
sub: token.sub,
|
||||
projectPath,
|
||||
branch,
|
||||
path,
|
||||
};
|
||||
},
|
||||
async listFileRevisions({ token, syncLocation }) {
|
||||
const entries = await giteaHelper.getCommits({
|
||||
...syncLocation,
|
||||
token,
|
||||
});
|
||||
|
||||
return entries.map((entry) => {
|
||||
const email = entry.author_email || entry.committer_email;
|
||||
const sub = `${giteaHelper.subPrefix}:${token.serverUrl}/${email}`;
|
||||
userSvc.addUserInfo({
|
||||
id: sub,
|
||||
name: entry.author_name || entry.committer_name,
|
||||
imageUrl: '',
|
||||
});
|
||||
const date = entry.authored_date || entry.committed_date || 1;
|
||||
return {
|
||||
id: entry.id,
|
||||
sub,
|
||||
created: date ? new Date(date).getTime() : 1,
|
||||
};
|
||||
});
|
||||
},
|
||||
async loadFileRevision() {
|
||||
// Revision are already loaded
|
||||
return false;
|
||||
},
|
||||
async getFileRevisionContent({
|
||||
token,
|
||||
contentId,
|
||||
syncLocation,
|
||||
revisionId,
|
||||
}) {
|
||||
const { data } = await giteaHelper.downloadFile({
|
||||
...syncLocation,
|
||||
token,
|
||||
branch: revisionId,
|
||||
});
|
||||
return Provider.parseContent(data, contentId);
|
||||
},
|
||||
});
|
288
src/services/providers/giteaWorkspaceProvider.js
Normal file
288
src/services/providers/giteaWorkspaceProvider.js
Normal file
@ -0,0 +1,288 @@
|
||||
import store from '../../store';
|
||||
import giteaHelper from './helpers/giteaHelper';
|
||||
import Provider from './common/Provider';
|
||||
import utils from '../utils';
|
||||
import userSvc from '../userSvc';
|
||||
import gitWorkspaceSvc from '../gitWorkspaceSvc';
|
||||
import badgeSvc from '../badgeSvc';
|
||||
|
||||
const getAbsolutePath = ({ id }) =>
|
||||
`${store.getters['workspace/currentWorkspace'].path || ''}${id}`;
|
||||
|
||||
export default new Provider({
|
||||
id: 'giteaWorkspace',
|
||||
name: 'Gitea',
|
||||
getToken() {
|
||||
return store.getters['workspace/syncToken'];
|
||||
},
|
||||
getWorkspaceParams({
|
||||
serverUrl,
|
||||
projectPath,
|
||||
branch,
|
||||
path,
|
||||
}) {
|
||||
return {
|
||||
providerId: this.id,
|
||||
serverUrl,
|
||||
projectPath,
|
||||
branch,
|
||||
path,
|
||||
};
|
||||
},
|
||||
getWorkspaceLocationUrl({
|
||||
serverUrl,
|
||||
projectPath,
|
||||
branch,
|
||||
path,
|
||||
}) {
|
||||
return `${serverUrl}/${projectPath}/src/branch/${encodeURIComponent(branch)}/${utils.encodeUrlPath(path)}`;
|
||||
},
|
||||
getSyncDataUrl({ id }) {
|
||||
const { projectPath, branch } = store.getters['workspace/currentWorkspace'];
|
||||
const { serverUrl } = this.getToken();
|
||||
return `${serverUrl}/${projectPath}/src/branch/${encodeURIComponent(branch)}/${utils.encodeUrlPath(getAbsolutePath({ id }))}`;
|
||||
},
|
||||
getSyncDataDescription({ id }) {
|
||||
return getAbsolutePath({ id });
|
||||
},
|
||||
async initWorkspace() {
|
||||
const { serverUrl, branch } = utils.queryParams;
|
||||
const workspaceParams = this.getWorkspaceParams({ serverUrl, branch });
|
||||
if (!branch) {
|
||||
workspaceParams.branch = 'master';
|
||||
}
|
||||
|
||||
// Extract project path param
|
||||
const projectPath = (utils.queryParams.projectPath || '')
|
||||
.trim()
|
||||
.replace(/^\/*/, '') // Remove leading `/`
|
||||
.replace(/\/*$/, ''); // Remove trailing `/`
|
||||
workspaceParams.projectPath = projectPath;
|
||||
|
||||
// Extract path param
|
||||
const path = (utils.queryParams.path || '')
|
||||
.trim()
|
||||
.replace(/^\/*/, '') // Remove leading `/`
|
||||
.replace(/\/*$/, '/'); // Add trailing `/`
|
||||
if (path !== '/') {
|
||||
workspaceParams.path = path;
|
||||
}
|
||||
|
||||
const workspaceId = utils.makeWorkspaceId(workspaceParams);
|
||||
const workspace = store.getters['workspace/workspacesById'][workspaceId];
|
||||
|
||||
// See if we already have a token
|
||||
const sub = workspace ? workspace.sub : utils.queryParams.sub;
|
||||
let token = store.getters['data/giteaTokensBySub'][sub];
|
||||
if (!token) {
|
||||
const { applicationId, applicationSecret } = await store.dispatch('modal/open', {
|
||||
type: 'giteaAccount',
|
||||
forceServerUrl: serverUrl,
|
||||
});
|
||||
token = await giteaHelper.addAccount(serverUrl, applicationId, applicationSecret, sub);
|
||||
}
|
||||
|
||||
if (!workspace) {
|
||||
const projectId = await giteaHelper.getProjectId(workspaceParams);
|
||||
const pathEntries = (path || '').split('/');
|
||||
const projectPathEntries = (projectPath || '').split('/');
|
||||
const name = pathEntries[pathEntries.length - 2] // path ends with `/`
|
||||
|| projectPathEntries[projectPathEntries.length - 1];
|
||||
store.dispatch('workspace/patchWorkspacesById', {
|
||||
[workspaceId]: {
|
||||
...workspaceParams,
|
||||
projectId,
|
||||
id: workspaceId,
|
||||
sub: token.sub,
|
||||
name,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
badgeSvc.addBadge('addGiteaWorkspace');
|
||||
return store.getters['workspace/workspacesById'][workspaceId];
|
||||
},
|
||||
getChanges() {
|
||||
return giteaHelper.getTree({
|
||||
...store.getters['workspace/currentWorkspace'],
|
||||
token: this.getToken(),
|
||||
});
|
||||
},
|
||||
prepareChanges(tree) {
|
||||
return gitWorkspaceSvc.makeChanges(tree.tree.map(entry => ({
|
||||
...entry,
|
||||
id: entry.sha,
|
||||
})));
|
||||
},
|
||||
async saveWorkspaceItem({ item }) {
|
||||
const syncData = {
|
||||
id: store.getters.gitPathsByItemId[item.id],
|
||||
type: item.type,
|
||||
hash: item.hash,
|
||||
};
|
||||
|
||||
// Files and folders are not in git, only contents
|
||||
if (item.type === 'file' || item.type === 'folder') {
|
||||
return { syncData };
|
||||
}
|
||||
|
||||
// locations are stored as paths, so we upload an empty file
|
||||
const syncToken = store.getters['workspace/syncToken'];
|
||||
await giteaHelper.uploadFile({
|
||||
...store.getters['workspace/currentWorkspace'],
|
||||
token: syncToken,
|
||||
path: getAbsolutePath(syncData),
|
||||
content: '',
|
||||
sha: gitWorkspaceSvc.shaByPath[syncData.id],
|
||||
});
|
||||
|
||||
// Return sync data to save
|
||||
return { syncData };
|
||||
},
|
||||
async removeWorkspaceItem({ syncData }) {
|
||||
if (gitWorkspaceSvc.shaByPath[syncData.id]) {
|
||||
const syncToken = store.getters['workspace/syncToken'];
|
||||
await giteaHelper.removeFile({
|
||||
...store.getters['workspace/currentWorkspace'],
|
||||
token: syncToken,
|
||||
path: getAbsolutePath(syncData),
|
||||
sha: gitWorkspaceSvc.shaByPath[syncData.id],
|
||||
});
|
||||
}
|
||||
},
|
||||
async downloadWorkspaceContent({
|
||||
token,
|
||||
contentId,
|
||||
contentSyncData,
|
||||
fileSyncData,
|
||||
}) {
|
||||
const { sha, data } = await giteaHelper.downloadFile({
|
||||
...store.getters['workspace/currentWorkspace'],
|
||||
token,
|
||||
path: getAbsolutePath(fileSyncData),
|
||||
});
|
||||
gitWorkspaceSvc.shaByPath[fileSyncData.id] = sha;
|
||||
const content = Provider.parseContent(data, contentId);
|
||||
return {
|
||||
content,
|
||||
contentSyncData: {
|
||||
...contentSyncData,
|
||||
hash: content.hash,
|
||||
sha,
|
||||
},
|
||||
};
|
||||
},
|
||||
async downloadWorkspaceData({ token, syncData }) {
|
||||
if (!syncData) {
|
||||
return {};
|
||||
}
|
||||
|
||||
const { sha, data } = await giteaHelper.downloadFile({
|
||||
...store.getters['workspace/currentWorkspace'],
|
||||
token,
|
||||
path: getAbsolutePath(syncData),
|
||||
});
|
||||
gitWorkspaceSvc.shaByPath[syncData.id] = sha;
|
||||
const item = JSON.parse(data);
|
||||
return {
|
||||
item,
|
||||
syncData: {
|
||||
...syncData,
|
||||
hash: item.hash,
|
||||
sha,
|
||||
},
|
||||
};
|
||||
},
|
||||
async uploadWorkspaceContent({ token, content, file }) {
|
||||
const path = store.getters.gitPathsByItemId[file.id];
|
||||
const absolutePath = `${store.getters['workspace/currentWorkspace'].path || ''}${path}`;
|
||||
const sha = gitWorkspaceSvc.shaByPath[path];
|
||||
await giteaHelper.uploadFile({
|
||||
...store.getters['workspace/currentWorkspace'],
|
||||
token,
|
||||
path: absolutePath,
|
||||
content: Provider.serializeContent(content),
|
||||
sha,
|
||||
});
|
||||
|
||||
// Return new sync data
|
||||
return {
|
||||
contentSyncData: {
|
||||
id: store.getters.gitPathsByItemId[content.id],
|
||||
type: content.type,
|
||||
hash: content.hash,
|
||||
sha,
|
||||
},
|
||||
fileSyncData: {
|
||||
id: path,
|
||||
type: 'file',
|
||||
hash: file.hash,
|
||||
},
|
||||
};
|
||||
},
|
||||
async uploadWorkspaceData({ token, item }) {
|
||||
const path = store.getters.gitPathsByItemId[item.id];
|
||||
const syncData = {
|
||||
id: path,
|
||||
type: item.type,
|
||||
hash: item.hash,
|
||||
};
|
||||
const res = await giteaHelper.uploadFile({
|
||||
...store.getters['workspace/currentWorkspace'],
|
||||
token,
|
||||
path: getAbsolutePath(syncData),
|
||||
content: JSON.stringify(item),
|
||||
sha: gitWorkspaceSvc.shaByPath[path],
|
||||
});
|
||||
|
||||
return {
|
||||
syncData: {
|
||||
...syncData,
|
||||
sha: res.content.sha,
|
||||
},
|
||||
};
|
||||
},
|
||||
async listFileRevisions({ token, fileSyncDataId }) {
|
||||
const { projectId, branch } = store.getters['workspace/currentWorkspace'];
|
||||
const entries = await giteaHelper.getCommits({
|
||||
token,
|
||||
projectId,
|
||||
sha: branch,
|
||||
path: getAbsolutePath({ id: fileSyncDataId }),
|
||||
});
|
||||
|
||||
return entries.map((entry) => {
|
||||
const email = entry.author_email || entry.committer_email;
|
||||
const sub = `${giteaHelper.subPrefix}:${token.serverUrl}/${email}`;
|
||||
userSvc.addUserInfo({
|
||||
id: sub,
|
||||
name: entry.author_name || entry.committer_name,
|
||||
imageUrl: '', // No way to get user's avatar url...
|
||||
});
|
||||
const date = entry.authored_date || entry.committed_date || 1;
|
||||
return {
|
||||
id: entry.id,
|
||||
sub,
|
||||
created: date ? new Date(date).getTime() : 1,
|
||||
};
|
||||
});
|
||||
},
|
||||
async loadFileRevision() {
|
||||
// Revisions are already loaded
|
||||
return false;
|
||||
},
|
||||
async getFileRevisionContent({
|
||||
token,
|
||||
contentId,
|
||||
fileSyncDataId,
|
||||
revisionId,
|
||||
}) {
|
||||
const { data } = await giteaHelper.downloadFile({
|
||||
...store.getters['workspace/currentWorkspace'],
|
||||
token,
|
||||
branch: revisionId,
|
||||
path: getAbsolutePath({ id: fileSyncDataId }),
|
||||
});
|
||||
return Provider.parseContent(data, contentId);
|
||||
},
|
||||
});
|
222
src/services/providers/helpers/giteaHelper.js
Normal file
222
src/services/providers/helpers/giteaHelper.js
Normal file
@ -0,0 +1,222 @@
|
||||
import utils from '../../utils';
|
||||
import networkSvc from '../../networkSvc';
|
||||
import store from '../../../store';
|
||||
import userSvc from '../../userSvc';
|
||||
import badgeSvc from '../../badgeSvc';
|
||||
import constants from '../../../data/constants';
|
||||
|
||||
const request = ({ accessToken, serverUrl }, options) => networkSvc.request({
|
||||
...options,
|
||||
url: `${serverUrl}/api/v1/${options.url}`,
|
||||
headers: {
|
||||
...options.headers || {},
|
||||
Authorization: `Bearer ${accessToken}`,
|
||||
},
|
||||
})
|
||||
.then(res => res.body);
|
||||
|
||||
const getCommitMessage = (name, path) => {
|
||||
const message = store.getters['data/computedSettings'].git[name];
|
||||
return message.replace(/{{path}}/g, path);
|
||||
};
|
||||
|
||||
/**
|
||||
* https://try.gitea.io/api/swagger#/user/userGet
|
||||
*/
|
||||
const subPrefix = 'gt';
|
||||
userSvc.setInfoResolver('gitea', subPrefix, async (sub) => {
|
||||
try {
|
||||
const [, serverUrl, username] = sub.match(/^(.+)\/([^/]+)$/);
|
||||
const user = (await networkSvc.request({
|
||||
url: `${serverUrl}/api/v1/users/${username}`,
|
||||
})).body;
|
||||
const uniqueSub = `${serverUrl}/${user.username}`;
|
||||
|
||||
return {
|
||||
id: `${subPrefix}:${uniqueSub}`,
|
||||
name: user.username,
|
||||
imageUrl: user.avatar_url || '',
|
||||
};
|
||||
} catch (err) {
|
||||
if (err.status !== 404) {
|
||||
throw new Error('RETRY');
|
||||
}
|
||||
throw err;
|
||||
}
|
||||
});
|
||||
|
||||
export default {
|
||||
subPrefix,
|
||||
|
||||
/**
|
||||
* https://docs.gitea.io/en-us/oauth2-provider/
|
||||
*/
|
||||
async startOauth2(serverUrl, applicationId, applicationSecret, sub = null, silent = false) {
|
||||
// Get an OAuth2 code
|
||||
const { code } = await networkSvc.startOauth2(
|
||||
`${serverUrl}/login/oauth/authorize`,
|
||||
{
|
||||
client_id: applicationId,
|
||||
response_type: 'code',
|
||||
redirect_uri: constants.oauth2RedirectUri,
|
||||
},
|
||||
silent,
|
||||
);
|
||||
|
||||
// Exchange code with token
|
||||
const accessToken = (await networkSvc.request({
|
||||
method: 'POST',
|
||||
url: `${serverUrl}/login/oauth/access_token`,
|
||||
body: {
|
||||
client_id: applicationId,
|
||||
client_secret: applicationSecret,
|
||||
code,
|
||||
grant_type: 'authorization_code',
|
||||
redirect_uri: constants.oauth2RedirectUri,
|
||||
},
|
||||
})).body.access_token;
|
||||
|
||||
// Call the user info endpoint
|
||||
const user = await request({ accessToken, serverUrl }, {
|
||||
url: 'user',
|
||||
});
|
||||
const uniqueSub = `${serverUrl}/${user.username}`;
|
||||
userSvc.addUserInfo({
|
||||
id: `${subPrefix}:${uniqueSub}`,
|
||||
name: user.username,
|
||||
imageUrl: user.avatar_url || '',
|
||||
});
|
||||
|
||||
// Check the returned sub consistency
|
||||
if (sub && uniqueSub !== sub) {
|
||||
throw new Error('Gitea account ID not expected.');
|
||||
}
|
||||
|
||||
// Build token object including scopes and sub
|
||||
const token = {
|
||||
accessToken,
|
||||
name: user.username,
|
||||
serverUrl,
|
||||
sub: uniqueSub,
|
||||
};
|
||||
|
||||
// Add token to gitea tokens
|
||||
store.dispatch('data/addGiteaToken', token);
|
||||
return token;
|
||||
},
|
||||
async addAccount(serverUrl, applicationId, applicationSecret, sub = null) {
|
||||
const token = await this.startOauth2(serverUrl, applicationId, applicationSecret, sub);
|
||||
badgeSvc.addBadge('addGiteaAccount');
|
||||
return token;
|
||||
},
|
||||
|
||||
/**
|
||||
* https://try.gitea.io/api/swagger#/repository/repoGet
|
||||
*/
|
||||
async getProjectId({ projectPath, projectId }) {
|
||||
if (projectId) {
|
||||
return projectId;
|
||||
}
|
||||
const [, repoFullName] = projectPath.match(/([^/]+\/[^/]+)$/);
|
||||
return repoFullName;
|
||||
},
|
||||
|
||||
/**
|
||||
* https://try.gitea.io/api/swagger#/repository/GetTree
|
||||
*/
|
||||
async getTree({
|
||||
token,
|
||||
projectId,
|
||||
branch,
|
||||
}) {
|
||||
return request(token, {
|
||||
url: `repos/${projectId}/git/trees/${branch}`,
|
||||
params: {
|
||||
recursive: true,
|
||||
per_page: 9999,
|
||||
},
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* https://try.gitea.io/api/swagger#/repository/repoGetAllCommits
|
||||
*/
|
||||
async getCommits({
|
||||
token,
|
||||
projectId,
|
||||
branch,
|
||||
path,
|
||||
}) {
|
||||
return request(token, {
|
||||
url: `repos/${projectId}/commits`,
|
||||
params: {
|
||||
sha: branch,
|
||||
path,
|
||||
},
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* https://try.gitea.io/api/swagger#/repository/repoCreateFile
|
||||
* https://try.gitea.io/api/swagger#/repository/repoUpdateFile
|
||||
*/
|
||||
async uploadFile({
|
||||
token,
|
||||
projectId,
|
||||
branch,
|
||||
path,
|
||||
content,
|
||||
sha,
|
||||
}) {
|
||||
return request(token, {
|
||||
method: sha ? 'PUT' : 'POST',
|
||||
url: `repos/${projectId}/contents/${encodeURIComponent(path)}`,
|
||||
body: {
|
||||
message: getCommitMessage(sha ? 'updateFileMessage' : 'createFileMessage', path),
|
||||
content: utils.encodeBase64(content),
|
||||
sha,
|
||||
branch,
|
||||
},
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* https://try.gitea.io/api/swagger#/repository/repoDeleteFile
|
||||
*/
|
||||
async removeFile({
|
||||
token,
|
||||
projectId,
|
||||
branch,
|
||||
path,
|
||||
sha,
|
||||
}) {
|
||||
return request(token, {
|
||||
method: 'DELETE',
|
||||
url: `repos/${projectId}/contents/${encodeURIComponent(path)}`,
|
||||
body: {
|
||||
message: getCommitMessage('deleteFileMessage', path),
|
||||
sha,
|
||||
branch,
|
||||
},
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* https://try.gitea.io/api/swagger#/repository/repoGetContents
|
||||
*/
|
||||
async downloadFile({
|
||||
token,
|
||||
projectId,
|
||||
branch,
|
||||
path,
|
||||
}) {
|
||||
const { sha, content } = await request(token, {
|
||||
url: `repos/${projectId}/contents/${encodeURIComponent(path)}`,
|
||||
params: { ref: branch },
|
||||
});
|
||||
return {
|
||||
sha,
|
||||
data: utils.decodeBase64(content),
|
||||
};
|
||||
},
|
||||
};
|
@ -3,6 +3,7 @@ import networkSvc from '../../networkSvc';
|
||||
import store from '../../../store';
|
||||
import userSvc from '../../userSvc';
|
||||
import badgeSvc from '../../badgeSvc';
|
||||
import constants from '../../../data/constants';
|
||||
|
||||
const request = (token, options) => networkSvc.request({
|
||||
...options,
|
||||
@ -81,6 +82,7 @@ export default {
|
||||
params: {
|
||||
clientId,
|
||||
code,
|
||||
oauth2RedirectUri: constants.oauth2RedirectUri,
|
||||
},
|
||||
})).body;
|
||||
|
||||
|
@ -9,6 +9,7 @@ import './providers/couchdbWorkspaceProvider';
|
||||
import './providers/githubWorkspaceProvider';
|
||||
import './providers/giteeWorkspaceProvider';
|
||||
import './providers/gitlabWorkspaceProvider';
|
||||
import './providers/giteaWorkspaceProvider';
|
||||
import './providers/googleDriveWorkspaceProvider';
|
||||
import tempFileSvc from './tempFileSvc';
|
||||
import workspaceSvc from './workspaceSvc';
|
||||
|
@ -296,6 +296,10 @@ export default {
|
||||
const parsedProject = url && url.match(/^https:\/\/[^/]+\/(.+?)(?:\.git|\/)?$/);
|
||||
return parsedProject && parsedProject[1];
|
||||
},
|
||||
parseGiteaProjectPath(url) {
|
||||
const parsedProject = url && url.match(/^http[s]?:\/\/[^/]+\/(.+?)(?:\.git|\/)?$/);
|
||||
return parsedProject && parsedProject[1];
|
||||
},
|
||||
createHiddenIframe(url) {
|
||||
const iframeElt = document.createElement('iframe');
|
||||
iframeElt.style.position = 'absolute';
|
||||
|
@ -213,6 +213,7 @@ export default {
|
||||
githubTokensBySub: (state, { tokensByType }) => tokensByType.github || {},
|
||||
giteeTokensBySub: (state, { tokensByType }) => tokensByType.gitee || {},
|
||||
gitlabTokensBySub: (state, { tokensByType }) => tokensByType.gitlab || {},
|
||||
giteaTokensBySub: (state, { tokensByType }) => tokensByType.gitea || {},
|
||||
wordpressTokensBySub: (state, { tokensByType }) => tokensByType.wordpress || {},
|
||||
zendeskTokensBySub: (state, { tokensByType }) => tokensByType.zendesk || {},
|
||||
badgeCreations: getter('badgeCreations'),
|
||||
@ -306,6 +307,7 @@ export default {
|
||||
addGithubToken: tokenAdder('github'),
|
||||
addGiteeToken: tokenAdder('gitee'),
|
||||
addGitlabToken: tokenAdder('gitlab'),
|
||||
addGiteaToken: tokenAdder('gitea'),
|
||||
addWordpressToken: tokenAdder('wordpress'),
|
||||
addZendeskToken: tokenAdder('zendesk'),
|
||||
patchBadgeCreations: patcher('badgeCreations'),
|
||||
|
@ -45,11 +45,13 @@ export default {
|
||||
currentWorkspaceIsGit: (state, { currentWorkspace }) =>
|
||||
currentWorkspace.providerId === 'githubWorkspace'
|
||||
|| currentWorkspace.providerId === 'giteeWorkspace'
|
||||
|| currentWorkspace.providerId === 'gitlabWorkspace',
|
||||
|| currentWorkspace.providerId === 'gitlabWorkspace'
|
||||
|| currentWorkspace.providerId === 'giteaWorkspace',
|
||||
currentWorkspaceHasUniquePaths: (state, { currentWorkspace }) =>
|
||||
currentWorkspace.providerId === 'githubWorkspace'
|
||||
|| currentWorkspace.providerId === 'giteeWorkspace'
|
||||
|| currentWorkspace.providerId === 'gitlabWorkspace',
|
||||
|| currentWorkspace.providerId === 'gitlabWorkspace'
|
||||
|| currentWorkspace.providerId === 'giteaWorkspace',
|
||||
lastSyncActivityKey: (state, { currentWorkspace }) => `${currentWorkspace.id}/lastSyncActivity`,
|
||||
lastFocusKey: (state, { currentWorkspace }) => `${currentWorkspace.id}/lastWindowFocus`,
|
||||
mainWorkspaceToken: (state, getters, rootState, rootGetters) =>
|
||||
@ -69,6 +71,8 @@ export default {
|
||||
return rootGetters['data/giteeTokensBySub'][currentWorkspace.sub];
|
||||
case 'gitlabWorkspace':
|
||||
return rootGetters['data/gitlabTokensBySub'][currentWorkspace.sub];
|
||||
case 'giteaWorkspace':
|
||||
return rootGetters['data/giteaTokensBySub'][currentWorkspace.sub];
|
||||
case 'couchdbWorkspace':
|
||||
return rootGetters['data/couchdbTokensBySub'][currentWorkspace.id];
|
||||
default:
|
||||
@ -86,6 +90,8 @@ export default {
|
||||
return 'gitee';
|
||||
case 'gitlabWorkspace':
|
||||
return 'gitlab';
|
||||
case 'giteaWorkspace':
|
||||
return 'gitea';
|
||||
}
|
||||
},
|
||||
loginToken: (state, { loginType, currentWorkspace }, rootState, rootGetters) => {
|
||||
|
Loading…
Reference in New Issue
Block a user