support gitea
This commit is contained in:
parent
329d00c707
commit
666db76f3c
@ -3,6 +3,7 @@ var prodEnv = require('./prod.env')
|
|||||||
|
|
||||||
module.exports = merge(prodEnv, {
|
module.exports = merge(prodEnv, {
|
||||||
NODE_ENV: '"development"',
|
NODE_ENV: '"development"',
|
||||||
|
// 以下配置是开发临时用的配置 随时可能失效 请替换为自己的
|
||||||
GITHUB_CLIENT_ID: '"845b8f75df48f2ee0563"',
|
GITHUB_CLIENT_ID: '"845b8f75df48f2ee0563"',
|
||||||
GITHUB_CLIENT_SECRET: '"80df676597abded1450926861965cc3f9bead6a0"',
|
GITHUB_CLIENT_SECRET: '"80df676597abded1450926861965cc3f9bead6a0"',
|
||||||
GITEE_CLIENT_ID: '"925ba7c78b85dec984f7877e4aca5cab10ae333c6d68e761bdb0b9dfb8f55672"',
|
GITEE_CLIENT_ID: '"925ba7c78b85dec984f7877e4aca5cab10ae333c6d68e761bdb0b9dfb8f55672"',
|
||||||
|
@ -2,11 +2,7 @@ const qs = require('qs'); // eslint-disable-line import/no-extraneous-dependenci
|
|||||||
const request = require('request');
|
const request = require('request');
|
||||||
const conf = require('./conf');
|
const conf = require('./conf');
|
||||||
|
|
||||||
function giteeToken(clientId, code) {
|
function giteeToken(clientId, code, oauth2RedirectUri) {
|
||||||
console.log('clientId: ' + clientId);
|
|
||||||
console.log('code: ' + code);
|
|
||||||
console.log('client_secret: ' + conf.values.giteeClientSecret);
|
|
||||||
console.log('redirect_uri: ' + conf.values.giteeCallback);
|
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
request({
|
request({
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
@ -17,7 +13,7 @@ function giteeToken(clientId, code) {
|
|||||||
code,
|
code,
|
||||||
grant_type: 'authorization_code',
|
grant_type: 'authorization_code',
|
||||||
scope: 'authorization_code',
|
scope: 'authorization_code',
|
||||||
redirect_uri: conf.values.giteeCallback,
|
redirect_uri: oauth2RedirectUri,
|
||||||
},
|
},
|
||||||
json: true
|
json: true
|
||||||
}, (err, res, body) => {
|
}, (err, res, body) => {
|
||||||
@ -35,7 +31,7 @@ function giteeToken(clientId, code) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
exports.giteeToken = (req, res) => {
|
exports.giteeToken = (req, res) => {
|
||||||
giteeToken(req.query.clientId, req.query.code)
|
giteeToken(req.query.clientId, req.query.code, req.query.oauth2RedirectUri)
|
||||||
.then(
|
.then(
|
||||||
token => res.send(token),
|
token => res.send(token),
|
||||||
err => res
|
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 GitlabPublishModal from './modals/providers/GitlabPublishModal';
|
||||||
import GitlabSaveModal from './modals/providers/GitlabSaveModal';
|
import GitlabSaveModal from './modals/providers/GitlabSaveModal';
|
||||||
import GitlabWorkspaceModal from './modals/providers/GitlabWorkspaceModal';
|
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 WordpressPublishModal from './modals/providers/WordpressPublishModal';
|
||||||
import BloggerPublishModal from './modals/providers/BloggerPublishModal';
|
import BloggerPublishModal from './modals/providers/BloggerPublishModal';
|
||||||
import BloggerPagePublishModal from './modals/providers/BloggerPagePublishModal';
|
import BloggerPagePublishModal from './modals/providers/BloggerPagePublishModal';
|
||||||
@ -122,6 +127,11 @@ export default {
|
|||||||
GitlabPublishModal,
|
GitlabPublishModal,
|
||||||
GitlabSaveModal,
|
GitlabSaveModal,
|
||||||
GitlabWorkspaceModal,
|
GitlabWorkspaceModal,
|
||||||
|
GiteaAccountModal,
|
||||||
|
GiteaOpenModal,
|
||||||
|
GiteaPublishModal,
|
||||||
|
GiteaSaveModal,
|
||||||
|
GiteaWorkspaceModal,
|
||||||
WordpressPublishModal,
|
WordpressPublishModal,
|
||||||
BloggerPublishModal,
|
BloggerPublishModal,
|
||||||
BloggerPagePublishModal,
|
BloggerPagePublishModal,
|
||||||
|
@ -29,6 +29,9 @@
|
|||||||
<span v-else-if="currentWorkspace.providerId === 'gitlabWorkspace'">
|
<span v-else-if="currentWorkspace.providerId === 'gitlabWorkspace'">
|
||||||
<b>{{currentWorkspace.name}}</b> synced with a <a :href="workspaceLocationUrl" target="_blank">GitLab project</a>.
|
<b>{{currentWorkspace.name}}</b> synced with a <a :href="workspaceLocationUrl" target="_blank">GitLab project</a>.
|
||||||
</span>
|
</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>
|
||||||
<div class="menu-entry menu-entry--info flex flex--row flex--align-center" v-else>
|
<div class="menu-entry menu-entry--info flex flex--row flex--align-center" v-else>
|
||||||
<div class="menu-entry__icon menu-entry__icon--disabled">
|
<div class="menu-entry__icon menu-entry__icon--disabled">
|
||||||
|
@ -66,6 +66,13 @@
|
|||||||
<span>{{token.name}}</span>
|
<span>{{token.name}}</span>
|
||||||
</menu-entry>
|
</menu-entry>
|
||||||
</div>
|
</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">
|
<div v-for="token in googleDriveTokens" :key="token.sub">
|
||||||
<menu-entry @click.native="publishGoogleDrive(token)">
|
<menu-entry @click.native="publishGoogleDrive(token)">
|
||||||
<icon-provider slot="icon" provider-id="googleDrive"></icon-provider>
|
<icon-provider slot="icon" provider-id="googleDrive"></icon-provider>
|
||||||
@ -108,6 +115,10 @@
|
|||||||
<icon-provider slot="icon" provider-id="gitlab"></icon-provider>
|
<icon-provider slot="icon" provider-id="gitlab"></icon-provider>
|
||||||
<span>Add GitLab account</span>
|
<span>Add GitLab account</span>
|
||||||
</menu-entry>
|
</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">
|
<menu-entry @click.native="addGoogleDriveAccount">
|
||||||
<icon-provider slot="icon" provider-id="googleDrive"></icon-provider>
|
<icon-provider slot="icon" provider-id="googleDrive"></icon-provider>
|
||||||
<span>Add Google Drive account</span>
|
<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 githubHelper from '../../services/providers/helpers/githubHelper';
|
||||||
import giteeHelper from '../../services/providers/helpers/giteeHelper';
|
import giteeHelper from '../../services/providers/helpers/giteeHelper';
|
||||||
import gitlabHelper from '../../services/providers/helpers/gitlabHelper';
|
import gitlabHelper from '../../services/providers/helpers/gitlabHelper';
|
||||||
|
import giteaHelper from '../../services/providers/helpers/giteaHelper';
|
||||||
import wordpressHelper from '../../services/providers/helpers/wordpressHelper';
|
import wordpressHelper from '../../services/providers/helpers/wordpressHelper';
|
||||||
import zendeskHelper from '../../services/providers/helpers/zendeskHelper';
|
import zendeskHelper from '../../services/providers/helpers/zendeskHelper';
|
||||||
import publishSvc from '../../services/publishSvc';
|
import publishSvc from '../../services/publishSvc';
|
||||||
@ -186,6 +198,9 @@ export default {
|
|||||||
gitlabTokens() {
|
gitlabTokens() {
|
||||||
return tokensToArray(store.getters['data/gitlabTokensBySub']);
|
return tokensToArray(store.getters['data/gitlabTokensBySub']);
|
||||||
},
|
},
|
||||||
|
giteaTokens() {
|
||||||
|
return tokensToArray(store.getters['data/giteaTokensBySub']);
|
||||||
|
},
|
||||||
googleDriveTokens() {
|
googleDriveTokens() {
|
||||||
return tokensToArray(store.getters['data/googleTokensBySub'], token => token.isDrive);
|
return tokensToArray(store.getters['data/googleTokensBySub'], token => token.isDrive);
|
||||||
},
|
},
|
||||||
@ -199,7 +214,9 @@ export default {
|
|||||||
return !this.bloggerTokens.length
|
return !this.bloggerTokens.length
|
||||||
&& !this.dropboxTokens.length
|
&& !this.dropboxTokens.length
|
||||||
&& !this.githubTokens.length
|
&& !this.githubTokens.length
|
||||||
|
&& !this.giteeTokens.length
|
||||||
&& !this.gitlabTokens.length
|
&& !this.gitlabTokens.length
|
||||||
|
&& !this.giteaTokens.length
|
||||||
&& !this.googleDriveTokens.length
|
&& !this.googleDriveTokens.length
|
||||||
&& !this.wordpressTokens.length
|
&& !this.wordpressTokens.length
|
||||||
&& !this.zendeskTokens.length;
|
&& !this.zendeskTokens.length;
|
||||||
@ -245,6 +262,12 @@ export default {
|
|||||||
await gitlabHelper.addAccount(serverUrl, applicationId);
|
await gitlabHelper.addAccount(serverUrl, applicationId);
|
||||||
} catch (e) { /* cancel */ }
|
} 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() {
|
async addGoogleDriveAccount() {
|
||||||
try {
|
try {
|
||||||
await store.dispatch('modal/open', { type: 'googleDriveAccount' });
|
await store.dispatch('modal/open', { type: 'googleDriveAccount' });
|
||||||
@ -269,6 +292,7 @@ export default {
|
|||||||
publishGitee: publishModalOpener('giteePublish', 'publishToGitee'),
|
publishGitee: publishModalOpener('giteePublish', 'publishToGitee'),
|
||||||
publishGist: publishModalOpener('gistPublish', 'publishToGist'),
|
publishGist: publishModalOpener('gistPublish', 'publishToGist'),
|
||||||
publishGitlab: publishModalOpener('gitlabPublish', 'publishToGitlab'),
|
publishGitlab: publishModalOpener('gitlabPublish', 'publishToGitlab'),
|
||||||
|
publishGitea: publishModalOpener('giteaPublish', 'publishToGitea'),
|
||||||
publishGoogleDrive: publishModalOpener('googleDrivePublish', 'publishToGoogleDrive'),
|
publishGoogleDrive: publishModalOpener('googleDrivePublish', 'publishToGoogleDrive'),
|
||||||
publishWordpress: publishModalOpener('wordpressPublish', 'publishToWordPress'),
|
publishWordpress: publishModalOpener('wordpressPublish', 'publishToWordPress'),
|
||||||
publishZendesk: publishModalOpener('zendeskPublish', 'publishToZendesk'),
|
publishZendesk: publishModalOpener('zendeskPublish', 'publishToZendesk'),
|
||||||
|
@ -74,6 +74,18 @@
|
|||||||
<span>{{token.name}}</span>
|
<span>{{token.name}}</span>
|
||||||
</menu-entry>
|
</menu-entry>
|
||||||
</div>
|
</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">
|
<div v-for="token in googleDriveTokens" :key="token.sub">
|
||||||
<menu-entry @click.native="openGoogleDrive(token)">
|
<menu-entry @click.native="openGoogleDrive(token)">
|
||||||
<icon-provider slot="icon" provider-id="googleDrive"></icon-provider>
|
<icon-provider slot="icon" provider-id="googleDrive"></icon-provider>
|
||||||
@ -103,6 +115,10 @@
|
|||||||
<icon-provider slot="icon" provider-id="gitlab"></icon-provider>
|
<icon-provider slot="icon" provider-id="gitlab"></icon-provider>
|
||||||
<span>Add GitLab account</span>
|
<span>Add GitLab account</span>
|
||||||
</menu-entry>
|
</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">
|
<menu-entry @click.native="addGoogleDriveAccount">
|
||||||
<icon-provider slot="icon" provider-id="googleDrive"></icon-provider>
|
<icon-provider slot="icon" provider-id="googleDrive"></icon-provider>
|
||||||
<span>Add Google Drive account</span>
|
<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 githubHelper from '../../services/providers/helpers/githubHelper';
|
||||||
import giteeHelper from '../../services/providers/helpers/giteeHelper';
|
import giteeHelper from '../../services/providers/helpers/giteeHelper';
|
||||||
import gitlabHelper from '../../services/providers/helpers/gitlabHelper';
|
import gitlabHelper from '../../services/providers/helpers/gitlabHelper';
|
||||||
|
import giteaHelper from '../../services/providers/helpers/giteaHelper';
|
||||||
import googleDriveProvider from '../../services/providers/googleDriveProvider';
|
import googleDriveProvider from '../../services/providers/googleDriveProvider';
|
||||||
import dropboxProvider from '../../services/providers/dropboxProvider';
|
import dropboxProvider from '../../services/providers/dropboxProvider';
|
||||||
import githubProvider from '../../services/providers/githubProvider';
|
import githubProvider from '../../services/providers/githubProvider';
|
||||||
import giteeProvider from '../../services/providers/giteeProvider';
|
import giteeProvider from '../../services/providers/giteeProvider';
|
||||||
import gitlabProvider from '../../services/providers/gitlabProvider';
|
import gitlabProvider from '../../services/providers/gitlabProvider';
|
||||||
|
import giteaProvider from '../../services/providers/giteaProvider';
|
||||||
import syncSvc from '../../services/syncSvc';
|
import syncSvc from '../../services/syncSvc';
|
||||||
import store from '../../store';
|
import store from '../../store';
|
||||||
import badgeSvc from '../../services/badgeSvc';
|
import badgeSvc from '../../services/badgeSvc';
|
||||||
@ -172,6 +190,9 @@ export default {
|
|||||||
gitlabTokens() {
|
gitlabTokens() {
|
||||||
return tokensToArray(store.getters['data/gitlabTokensBySub']);
|
return tokensToArray(store.getters['data/gitlabTokensBySub']);
|
||||||
},
|
},
|
||||||
|
giteaTokens() {
|
||||||
|
return tokensToArray(store.getters['data/giteaTokensBySub']);
|
||||||
|
},
|
||||||
googleDriveTokens() {
|
googleDriveTokens() {
|
||||||
return tokensToArray(store.getters['data/googleTokensBySub'], token => token.isDrive);
|
return tokensToArray(store.getters['data/googleTokensBySub'], token => token.isDrive);
|
||||||
},
|
},
|
||||||
@ -217,6 +238,12 @@ export default {
|
|||||||
await gitlabHelper.addAccount(serverUrl, applicationId);
|
await gitlabHelper.addAccount(serverUrl, applicationId);
|
||||||
} catch (e) { /* cancel */ }
|
} 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() {
|
async addGoogleDriveAccount() {
|
||||||
try {
|
try {
|
||||||
await store.dispatch('modal/open', { type: 'googleDriveAccount' });
|
await store.dispatch('modal/open', { type: 'googleDriveAccount' });
|
||||||
@ -318,12 +345,33 @@ export default {
|
|||||||
);
|
);
|
||||||
} catch (e) { /* cancel */ }
|
} 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) {
|
async saveGitlab(token) {
|
||||||
try {
|
try {
|
||||||
await openSyncModal(token, 'gitlabSave');
|
await openSyncModal(token, 'gitlabSave');
|
||||||
badgeSvc.addBadge('saveOnGitlab');
|
badgeSvc.addBadge('saveOnGitlab');
|
||||||
} catch (e) { /* cancel */ }
|
} catch (e) { /* cancel */ }
|
||||||
},
|
},
|
||||||
|
async saveGitea(token) {
|
||||||
|
try {
|
||||||
|
await openSyncModal(token, 'giteaSave');
|
||||||
|
badgeSvc.addBadge('saveOnGitea');
|
||||||
|
} catch (e) { /* cancel */ }
|
||||||
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
@ -29,6 +29,10 @@
|
|||||||
<icon-provider slot="icon" provider-id="gitlabWorkspace"></icon-provider>
|
<icon-provider slot="icon" provider-id="gitlabWorkspace"></icon-provider>
|
||||||
<span>Add a <b>GitLab</b> workspace</span>
|
<span>Add a <b>GitLab</b> workspace</span>
|
||||||
</menu-entry>
|
</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">
|
<menu-entry @click.native="addGoogleDriveWorkspace">
|
||||||
<icon-provider slot="icon" provider-id="googleDriveWorkspace"></icon-provider>
|
<icon-provider slot="icon" provider-id="googleDriveWorkspace"></icon-provider>
|
||||||
<span>Add a <b>Google Drive</b> workspace</span>
|
<span>Add a <b>Google Drive</b> workspace</span>
|
||||||
@ -41,6 +45,7 @@ import { mapGetters } from 'vuex';
|
|||||||
import MenuEntry from './common/MenuEntry';
|
import MenuEntry from './common/MenuEntry';
|
||||||
import googleHelper from '../../services/providers/helpers/googleHelper';
|
import googleHelper from '../../services/providers/helpers/googleHelper';
|
||||||
import gitlabHelper from '../../services/providers/helpers/gitlabHelper';
|
import gitlabHelper from '../../services/providers/helpers/gitlabHelper';
|
||||||
|
import giteaHelper from '../../services/providers/helpers/giteaHelper';
|
||||||
import store from '../../store';
|
import store from '../../store';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
@ -88,6 +93,16 @@ export default {
|
|||||||
});
|
});
|
||||||
} catch (e) { /* Cancel */ }
|
} 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() {
|
async addGoogleDriveWorkspace() {
|
||||||
try {
|
try {
|
||||||
const token = await googleHelper.addDriveAccount(true);
|
const token = await googleHelper.addDriveAccount(true);
|
||||||
|
@ -57,6 +57,10 @@
|
|||||||
<icon-provider slot="icon" provider-id="gitlab"></icon-provider>
|
<icon-provider slot="icon" provider-id="gitlab"></icon-provider>
|
||||||
<span>Add GitLab account</span>
|
<span>Add GitLab account</span>
|
||||||
</menu-entry>
|
</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">
|
<menu-entry @click.native="addGoogleDriveAccount">
|
||||||
<icon-provider slot="icon" provider-id="googleDrive"></icon-provider>
|
<icon-provider slot="icon" provider-id="googleDrive"></icon-provider>
|
||||||
<span>Add Google Drive account</span>
|
<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 githubHelper from '../../services/providers/helpers/githubHelper';
|
||||||
import giteeHelper from '../../services/providers/helpers/giteeHelper';
|
import giteeHelper from '../../services/providers/helpers/giteeHelper';
|
||||||
import gitlabHelper from '../../services/providers/helpers/gitlabHelper';
|
import gitlabHelper from '../../services/providers/helpers/gitlabHelper';
|
||||||
|
import giteaHelper from '../../services/providers/helpers/giteaHelper';
|
||||||
import wordpressHelper from '../../services/providers/helpers/wordpressHelper';
|
import wordpressHelper from '../../services/providers/helpers/wordpressHelper';
|
||||||
import zendeskHelper from '../../services/providers/helpers/zendeskHelper';
|
import zendeskHelper from '../../services/providers/helpers/zendeskHelper';
|
||||||
import badgeSvc from '../../services/badgeSvc';
|
import badgeSvc from '../../services/badgeSvc';
|
||||||
@ -148,6 +153,14 @@ export default {
|
|||||||
name: token.name,
|
name: token.name,
|
||||||
scopes: ['api'],
|
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 => ({
|
...Object.values(store.getters['data/wordpressTokensBySub']).map(token => ({
|
||||||
token,
|
token,
|
||||||
providerId: 'wordpress',
|
providerId: 'wordpress',
|
||||||
@ -204,6 +217,12 @@ export default {
|
|||||||
await gitlabHelper.addAccount(serverUrl, applicationId);
|
await gitlabHelper.addAccount(serverUrl, applicationId);
|
||||||
} catch (e) { /* cancel */ }
|
} 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() {
|
async addGoogleDriveAccount() {
|
||||||
try {
|
try {
|
||||||
await store.dispatch('modal/open', { type: 'googleDriveAccount' });
|
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',
|
gistPublishTemplate: 'plainText',
|
||||||
giteeRepoUrl: '',
|
giteeRepoUrl: '',
|
||||||
giteeWorkspaceRepoUrl: '',
|
giteeWorkspaceRepoUrl: '',
|
||||||
|
giteePublishTemplate: 'jekyllSite',
|
||||||
gitlabServerUrl: '',
|
gitlabServerUrl: '',
|
||||||
gitlabApplicationId: '',
|
gitlabApplicationId: '',
|
||||||
gitlabProjectUrl: '',
|
gitlabProjectUrl: '',
|
||||||
gitlabWorkspaceProjectUrl: '',
|
gitlabWorkspaceProjectUrl: '',
|
||||||
gitlabPublishTemplate: 'plainText',
|
gitlabPublishTemplate: 'plainText',
|
||||||
|
giteaServerUrl: '',
|
||||||
|
giteaApplicationId: '',
|
||||||
|
giteaApplicationSecret: '',
|
||||||
|
giteaProjectUrl: '',
|
||||||
|
giteaWorkspaceProjectUrl: '',
|
||||||
|
giteaPublishTemplate: 'plainText',
|
||||||
wordpressDomain: '',
|
wordpressDomain: '',
|
||||||
wordpressPublishTemplate: 'plainHtml',
|
wordpressPublishTemplate: 'plainHtml',
|
||||||
zendeskSiteUrl: '',
|
zendeskSiteUrl: '',
|
||||||
|
@ -77,7 +77,7 @@ turndown:
|
|||||||
linkStyle: inlined
|
linkStyle: inlined
|
||||||
linkReferenceStyle: full
|
linkReferenceStyle: full
|
||||||
|
|
||||||
# GitHub/GitLab commit messages
|
# GitHub/GitLab/Gitee/Gitea commit messages
|
||||||
git:
|
git:
|
||||||
createFileMessage: '{{path}} created from https://edit.qicoder.com/'
|
createFileMessage: '{{path}} created from https://edit.qicoder.com/'
|
||||||
updateFileMessage: '{{path}} updated from https://edit.qicoder.com/'
|
updateFileMessage: '{{path}} updated from https://edit.qicoder.com/'
|
||||||
|
@ -182,6 +182,11 @@ export default [
|
|||||||
'GitLab workspace creator',
|
'GitLab workspace creator',
|
||||||
'Use the workspace menu to create a GitLab workspace.',
|
'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(
|
new Feature(
|
||||||
'addGoogleDriveWorkspace',
|
'addGoogleDriveWorkspace',
|
||||||
'Google Drive workspace creator',
|
'Google Drive workspace creator',
|
||||||
@ -229,6 +234,11 @@ export default [
|
|||||||
'GitLab user',
|
'GitLab user',
|
||||||
'Link your GitLab account to StackEdit.',
|
'Link your GitLab account to StackEdit.',
|
||||||
),
|
),
|
||||||
|
new Feature(
|
||||||
|
'addGiteaAccount',
|
||||||
|
'Gitea user',
|
||||||
|
'Link your Gitea account to StackEdit.',
|
||||||
|
),
|
||||||
new Feature(
|
new Feature(
|
||||||
'addGoogleDriveAccount',
|
'addGoogleDriveAccount',
|
||||||
'Google Drive user',
|
'Google Drive user',
|
||||||
@ -306,6 +316,16 @@ export default [
|
|||||||
'GitLab writer',
|
'GitLab writer',
|
||||||
'Use the "Synchronize" menu to save a file in a GitLab repository.',
|
'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(
|
new Feature(
|
||||||
'openFromGoogleDrive',
|
'openFromGoogleDrive',
|
||||||
'Google Drive reader',
|
'Google Drive reader',
|
||||||
@ -373,6 +393,11 @@ export default [
|
|||||||
'GitLab publisher',
|
'GitLab publisher',
|
||||||
'Use the "Publish" menu to publish a file to a GitLab repository.',
|
'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(
|
new Feature(
|
||||||
'publishToGoogleDrive',
|
'publishToGoogleDrive',
|
||||||
'Google Drive publisher',
|
'Google Drive publisher',
|
||||||
|
@ -22,6 +22,8 @@ export default {
|
|||||||
return 'github';
|
return 'github';
|
||||||
case 'gitlabWorkspace':
|
case 'gitlabWorkspace':
|
||||||
return 'gitlab';
|
return 'gitlab';
|
||||||
|
case 'giteaWorkspace':
|
||||||
|
return 'gitea';
|
||||||
case 'bloggerPage':
|
case 'bloggerPage':
|
||||||
return 'blogger';
|
return 'blogger';
|
||||||
case 'couchdbWorkspace':
|
case 'couchdbWorkspace':
|
||||||
@ -65,6 +67,10 @@ export default {
|
|||||||
background-image: url(../assets/iconGitlab.svg);
|
background-image: url(../assets/iconGitlab.svg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.icon-provider--gitea {
|
||||||
|
background-image: url(../assets/iconGitea.svg);
|
||||||
|
}
|
||||||
|
|
||||||
.icon-provider--google {
|
.icon-provider--google {
|
||||||
background-image: url(../assets/iconGoogle.svg);
|
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 store from '../../../store';
|
||||||
import userSvc from '../../userSvc';
|
import userSvc from '../../userSvc';
|
||||||
import badgeSvc from '../../badgeSvc';
|
import badgeSvc from '../../badgeSvc';
|
||||||
|
import constants from '../../../data/constants';
|
||||||
|
|
||||||
const request = (token, options) => networkSvc.request({
|
const request = (token, options) => networkSvc.request({
|
||||||
...options,
|
...options,
|
||||||
@ -81,6 +82,7 @@ export default {
|
|||||||
params: {
|
params: {
|
||||||
clientId,
|
clientId,
|
||||||
code,
|
code,
|
||||||
|
oauth2RedirectUri: constants.oauth2RedirectUri,
|
||||||
},
|
},
|
||||||
})).body;
|
})).body;
|
||||||
|
|
||||||
|
@ -9,6 +9,7 @@ import './providers/couchdbWorkspaceProvider';
|
|||||||
import './providers/githubWorkspaceProvider';
|
import './providers/githubWorkspaceProvider';
|
||||||
import './providers/giteeWorkspaceProvider';
|
import './providers/giteeWorkspaceProvider';
|
||||||
import './providers/gitlabWorkspaceProvider';
|
import './providers/gitlabWorkspaceProvider';
|
||||||
|
import './providers/giteaWorkspaceProvider';
|
||||||
import './providers/googleDriveWorkspaceProvider';
|
import './providers/googleDriveWorkspaceProvider';
|
||||||
import tempFileSvc from './tempFileSvc';
|
import tempFileSvc from './tempFileSvc';
|
||||||
import workspaceSvc from './workspaceSvc';
|
import workspaceSvc from './workspaceSvc';
|
||||||
|
@ -296,6 +296,10 @@ export default {
|
|||||||
const parsedProject = url && url.match(/^https:\/\/[^/]+\/(.+?)(?:\.git|\/)?$/);
|
const parsedProject = url && url.match(/^https:\/\/[^/]+\/(.+?)(?:\.git|\/)?$/);
|
||||||
return parsedProject && parsedProject[1];
|
return parsedProject && parsedProject[1];
|
||||||
},
|
},
|
||||||
|
parseGiteaProjectPath(url) {
|
||||||
|
const parsedProject = url && url.match(/^http[s]?:\/\/[^/]+\/(.+?)(?:\.git|\/)?$/);
|
||||||
|
return parsedProject && parsedProject[1];
|
||||||
|
},
|
||||||
createHiddenIframe(url) {
|
createHiddenIframe(url) {
|
||||||
const iframeElt = document.createElement('iframe');
|
const iframeElt = document.createElement('iframe');
|
||||||
iframeElt.style.position = 'absolute';
|
iframeElt.style.position = 'absolute';
|
||||||
|
@ -213,6 +213,7 @@ export default {
|
|||||||
githubTokensBySub: (state, { tokensByType }) => tokensByType.github || {},
|
githubTokensBySub: (state, { tokensByType }) => tokensByType.github || {},
|
||||||
giteeTokensBySub: (state, { tokensByType }) => tokensByType.gitee || {},
|
giteeTokensBySub: (state, { tokensByType }) => tokensByType.gitee || {},
|
||||||
gitlabTokensBySub: (state, { tokensByType }) => tokensByType.gitlab || {},
|
gitlabTokensBySub: (state, { tokensByType }) => tokensByType.gitlab || {},
|
||||||
|
giteaTokensBySub: (state, { tokensByType }) => tokensByType.gitea || {},
|
||||||
wordpressTokensBySub: (state, { tokensByType }) => tokensByType.wordpress || {},
|
wordpressTokensBySub: (state, { tokensByType }) => tokensByType.wordpress || {},
|
||||||
zendeskTokensBySub: (state, { tokensByType }) => tokensByType.zendesk || {},
|
zendeskTokensBySub: (state, { tokensByType }) => tokensByType.zendesk || {},
|
||||||
badgeCreations: getter('badgeCreations'),
|
badgeCreations: getter('badgeCreations'),
|
||||||
@ -306,6 +307,7 @@ export default {
|
|||||||
addGithubToken: tokenAdder('github'),
|
addGithubToken: tokenAdder('github'),
|
||||||
addGiteeToken: tokenAdder('gitee'),
|
addGiteeToken: tokenAdder('gitee'),
|
||||||
addGitlabToken: tokenAdder('gitlab'),
|
addGitlabToken: tokenAdder('gitlab'),
|
||||||
|
addGiteaToken: tokenAdder('gitea'),
|
||||||
addWordpressToken: tokenAdder('wordpress'),
|
addWordpressToken: tokenAdder('wordpress'),
|
||||||
addZendeskToken: tokenAdder('zendesk'),
|
addZendeskToken: tokenAdder('zendesk'),
|
||||||
patchBadgeCreations: patcher('badgeCreations'),
|
patchBadgeCreations: patcher('badgeCreations'),
|
||||||
|
@ -45,11 +45,13 @@ export default {
|
|||||||
currentWorkspaceIsGit: (state, { currentWorkspace }) =>
|
currentWorkspaceIsGit: (state, { currentWorkspace }) =>
|
||||||
currentWorkspace.providerId === 'githubWorkspace'
|
currentWorkspace.providerId === 'githubWorkspace'
|
||||||
|| currentWorkspace.providerId === 'giteeWorkspace'
|
|| currentWorkspace.providerId === 'giteeWorkspace'
|
||||||
|| currentWorkspace.providerId === 'gitlabWorkspace',
|
|| currentWorkspace.providerId === 'gitlabWorkspace'
|
||||||
|
|| currentWorkspace.providerId === 'giteaWorkspace',
|
||||||
currentWorkspaceHasUniquePaths: (state, { currentWorkspace }) =>
|
currentWorkspaceHasUniquePaths: (state, { currentWorkspace }) =>
|
||||||
currentWorkspace.providerId === 'githubWorkspace'
|
currentWorkspace.providerId === 'githubWorkspace'
|
||||||
|| currentWorkspace.providerId === 'giteeWorkspace'
|
|| currentWorkspace.providerId === 'giteeWorkspace'
|
||||||
|| currentWorkspace.providerId === 'gitlabWorkspace',
|
|| currentWorkspace.providerId === 'gitlabWorkspace'
|
||||||
|
|| currentWorkspace.providerId === 'giteaWorkspace',
|
||||||
lastSyncActivityKey: (state, { currentWorkspace }) => `${currentWorkspace.id}/lastSyncActivity`,
|
lastSyncActivityKey: (state, { currentWorkspace }) => `${currentWorkspace.id}/lastSyncActivity`,
|
||||||
lastFocusKey: (state, { currentWorkspace }) => `${currentWorkspace.id}/lastWindowFocus`,
|
lastFocusKey: (state, { currentWorkspace }) => `${currentWorkspace.id}/lastWindowFocus`,
|
||||||
mainWorkspaceToken: (state, getters, rootState, rootGetters) =>
|
mainWorkspaceToken: (state, getters, rootState, rootGetters) =>
|
||||||
@ -69,6 +71,8 @@ export default {
|
|||||||
return rootGetters['data/giteeTokensBySub'][currentWorkspace.sub];
|
return rootGetters['data/giteeTokensBySub'][currentWorkspace.sub];
|
||||||
case 'gitlabWorkspace':
|
case 'gitlabWorkspace':
|
||||||
return rootGetters['data/gitlabTokensBySub'][currentWorkspace.sub];
|
return rootGetters['data/gitlabTokensBySub'][currentWorkspace.sub];
|
||||||
|
case 'giteaWorkspace':
|
||||||
|
return rootGetters['data/giteaTokensBySub'][currentWorkspace.sub];
|
||||||
case 'couchdbWorkspace':
|
case 'couchdbWorkspace':
|
||||||
return rootGetters['data/couchdbTokensBySub'][currentWorkspace.id];
|
return rootGetters['data/couchdbTokensBySub'][currentWorkspace.id];
|
||||||
default:
|
default:
|
||||||
@ -86,6 +90,8 @@ export default {
|
|||||||
return 'gitee';
|
return 'gitee';
|
||||||
case 'gitlabWorkspace':
|
case 'gitlabWorkspace':
|
||||||
return 'gitlab';
|
return 'gitlab';
|
||||||
|
case 'giteaWorkspace':
|
||||||
|
return 'gitea';
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
loginToken: (state, { loginType, currentWorkspace }, rootState, rootGetters) => {
|
loginToken: (state, { loginType, currentWorkspace }, rootState, rootGetters) => {
|
||||||
|
Loading…
Reference in New Issue
Block a user