Gitlab支持优化
This commit is contained in:
parent
4d8ff0ea0c
commit
b1691e0d4f
@ -69,6 +69,7 @@ StackEdit中文版
|
|||||||
- 支持图片直接存储到当前文档空间(2022-10-29)
|
- 支持图片直接存储到当前文档空间(2022-10-29)
|
||||||
- 支持MD文档之间链接跳转(2022-11-20)
|
- 支持MD文档之间链接跳转(2022-11-20)
|
||||||
- 支持预览区域选择主题样式(2022-12-04)
|
- 支持预览区域选择主题样式(2022-12-04)
|
||||||
|
- Gitlab的支持优化(2023-02-23)
|
||||||
|
|
||||||
## 国外开源版本弊端:
|
## 国外开源版本弊端:
|
||||||
- 作者已经不维护了
|
- 作者已经不维护了
|
||||||
@ -151,6 +152,9 @@ docker run -itd --name stackedit \
|
|||||||
|
|
||||||
- Gitea可选择性配置环境变量(未配置则在关联时前端指定,有配置则仅允许配置的应用信息):GITEA_CLIENT_ID、GITEA_CLIENT_SECRET、GITEA_URL,**[如何创建Gitea应用](./docs/部署之Gitea应用创建.md)**
|
- Gitea可选择性配置环境变量(未配置则在关联时前端指定,有配置则仅允许配置的应用信息):GITEA_CLIENT_ID、GITEA_CLIENT_SECRET、GITEA_URL,**[如何创建Gitea应用](./docs/部署之Gitea应用创建.md)**
|
||||||
|
|
||||||
|
- Gitlab可选择性配置环境变量(未配置则在关联时前端指定,有配置则仅允许配置的应用信息):GITLAB_CLIENT_ID、GITEA_URL **如何创建Gitlab应用(待补充文档)**
|
||||||
|
|
||||||
|
(特别说明:自建的Gitea、Gitlab要能接入stackedit必须支持跨域)
|
||||||
|
|
||||||
## 编译与运行
|
## 编译与运行
|
||||||
> 编译运行的nodejs版本选择11.15.0版本
|
> 编译运行的nodejs版本选择11.15.0版本
|
||||||
|
@ -18,6 +18,8 @@ awsSecretAccessKey: ""
|
|||||||
giteaClientId: ""
|
giteaClientId: ""
|
||||||
giteaClientSecret: ""
|
giteaClientSecret: ""
|
||||||
giteaUrl: ""
|
giteaUrl: ""
|
||||||
|
gitlabClientId: ""
|
||||||
|
gitlabUrl: ""
|
||||||
|
|
||||||
replicaCount: 1
|
replicaCount: 1
|
||||||
|
|
||||||
|
@ -12,4 +12,6 @@ module.exports = merge(prodEnv, {
|
|||||||
// GITEA_CLIENT_ID: '"fe30f8f9-b1e8-4531-8f72-c1a5d3912805"',
|
// GITEA_CLIENT_ID: '"fe30f8f9-b1e8-4531-8f72-c1a5d3912805"',
|
||||||
// GITEA_CLIENT_SECRET: '"lus7oMnb3H6M1hsChndphArE20Txr7erwJLf7SDBQWTw"',
|
// GITEA_CLIENT_SECRET: '"lus7oMnb3H6M1hsChndphArE20Txr7erwJLf7SDBQWTw"',
|
||||||
// GITEA_URL: '"https://gitea.test.com"',
|
// GITEA_URL: '"https://gitea.test.com"',
|
||||||
|
// GITLAB_CLIENT_ID: '"33e01128c27fe75df3e5b35218d710c7df280e6ee9c90b6ca27ac9d9fdfb92f7"',
|
||||||
|
// GITLAB_URL: '"http://gitlab.qicoder.com"',
|
||||||
})
|
})
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "stackedit",
|
"name": "stackedit",
|
||||||
"version": "5.15.17",
|
"version": "5.15.18",
|
||||||
"description": "免费, 开源, 功能齐全的 Markdown 编辑器",
|
"description": "免费, 开源, 功能齐全的 Markdown 编辑器",
|
||||||
"author": "Benoit Schweblin, 豆萁",
|
"author": "Benoit Schweblin, 豆萁",
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
|
@ -14,6 +14,8 @@ const wordpressClientId = process.env.WORDPRESS_CLIENT_ID;
|
|||||||
const giteaClientId = process.env.GITEA_CLIENT_ID;
|
const giteaClientId = process.env.GITEA_CLIENT_ID;
|
||||||
const giteaClientSecret = process.env.GITEA_CLIENT_SECRET;
|
const giteaClientSecret = process.env.GITEA_CLIENT_SECRET;
|
||||||
const giteaUrl = process.env.GITEA_URL;
|
const giteaUrl = process.env.GITEA_URL;
|
||||||
|
const gitlabClientId = process.env.GITLAB_CLIENT_ID;
|
||||||
|
const gitlabUrl = process.env.GITLAB_URL;
|
||||||
|
|
||||||
exports.values = {
|
exports.values = {
|
||||||
pandocPath,
|
pandocPath,
|
||||||
@ -43,4 +45,6 @@ exports.publicValues = {
|
|||||||
allowSponsorship: !!paypalReceiverEmail,
|
allowSponsorship: !!paypalReceiverEmail,
|
||||||
giteaClientId,
|
giteaClientId,
|
||||||
giteaUrl,
|
giteaUrl,
|
||||||
|
gitlabClientId,
|
||||||
|
gitlabUrl,
|
||||||
};
|
};
|
||||||
|
@ -41,6 +41,7 @@
|
|||||||
import modalTemplate from '../common/modalTemplate';
|
import modalTemplate from '../common/modalTemplate';
|
||||||
import constants from '../../../data/constants';
|
import constants from '../../../data/constants';
|
||||||
import store from '../../../store';
|
import store from '../../../store';
|
||||||
|
import networkSvc from '../../../services/networkSvc';
|
||||||
|
|
||||||
export default modalTemplate({
|
export default modalTemplate({
|
||||||
data: () => ({
|
data: () => ({
|
||||||
@ -65,6 +66,9 @@ export default modalTemplate({
|
|||||||
return !!confClientId && !!confServerUrl;
|
return !!confClientId && !!confServerUrl;
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
mounted() {
|
||||||
|
networkSvc.getServerConf();
|
||||||
|
},
|
||||||
methods: {
|
methods: {
|
||||||
resolve() {
|
resolve() {
|
||||||
if (this.useServerConf) {
|
if (this.useServerConf) {
|
||||||
|
@ -5,22 +5,27 @@
|
|||||||
<icon-provider provider-id="gitlab"></icon-provider>
|
<icon-provider provider-id="gitlab"></icon-provider>
|
||||||
</div>
|
</div>
|
||||||
<p>将您的<b>GitLab</b>链接到<b>StackEdit中文版</b>。</p>
|
<p>将您的<b>GitLab</b>链接到<b>StackEdit中文版</b>。</p>
|
||||||
<form-entry label="GitLab URL" error="serverUrl">
|
<template v-if="!useServerConf">
|
||||||
<input v-if="config.forceServerUrl" slot="field" class="textfield" type="text" disabled="disabled" v-model="config.forceServerUrl">
|
<form-entry label="GitLab URL" error="serverUrl">
|
||||||
<input v-else slot="field" class="textfield" type="text" v-model.trim="serverUrl" @keydown.enter="resolve()">
|
<input v-if="config.forceServerUrl" slot="field" class="textfield" type="text" disabled="disabled" v-model="config.forceServerUrl">
|
||||||
<div class="form-entry__info">
|
<input v-else slot="field" class="textfield" type="text" v-model.trim="serverUrl" @keydown.enter="resolve()">
|
||||||
<b>例如:</b> https://gitlab.example.com/
|
<div class="form-entry__info">
|
||||||
</div>
|
<b>例如:</b> https://gitlab.example.com/
|
||||||
</form-entry>
|
<span v-if="httpAppUrl">
|
||||||
<form-entry label="Application ID" error="applicationId">
|
,非https的URL,请跳转到 <a :href="httpAppUrl" target="_blank">HTTP链接</a> 添加Gitlab。
|
||||||
<input slot="field" class="textfield" type="text" v-model.trim="applicationId" @keydown.enter="resolve()">
|
</span>
|
||||||
<div class="form-entry__info">
|
</div>
|
||||||
您必须使用重定向url <b>{{redirectUrl}}</b>配置OAuth2应用程序
|
</form-entry>
|
||||||
</div>
|
<form-entry label="Application ID" error="applicationId">
|
||||||
<div class="form-entry__actions">
|
<input slot="field" class="textfield" type="text" v-model.trim="applicationId" @keydown.enter="resolve()">
|
||||||
<a href="https://docs.gitlab.com/ee/integration/oauth_provider.html" target="_blank">更多信息</a>
|
<div class="form-entry__info">
|
||||||
</div>
|
您必须使用重定向url <b>{{redirectUrl}}</b>配置OAuth2应用程序
|
||||||
</form-entry>
|
</div>
|
||||||
|
<div class="form-entry__actions">
|
||||||
|
<a href="https://docs.gitlab.com/ee/integration/oauth_provider.html" target="_blank">更多信息</a>
|
||||||
|
</div>
|
||||||
|
</form-entry>
|
||||||
|
</template>
|
||||||
</div>
|
</div>
|
||||||
<div class="modal__button-bar">
|
<div class="modal__button-bar">
|
||||||
<button class="button" @click="config.reject()">取消</button>
|
<button class="button" @click="config.reject()">取消</button>
|
||||||
@ -32,6 +37,8 @@
|
|||||||
<script>
|
<script>
|
||||||
import modalTemplate from '../common/modalTemplate';
|
import modalTemplate from '../common/modalTemplate';
|
||||||
import constants from '../../../data/constants';
|
import constants from '../../../data/constants';
|
||||||
|
import store from '../../../store';
|
||||||
|
import networkSvc from '../../../services/networkSvc';
|
||||||
|
|
||||||
export default modalTemplate({
|
export default modalTemplate({
|
||||||
data: () => ({
|
data: () => ({
|
||||||
@ -41,8 +48,29 @@ export default modalTemplate({
|
|||||||
serverUrl: 'gitlabServerUrl',
|
serverUrl: 'gitlabServerUrl',
|
||||||
applicationId: 'gitlabApplicationId',
|
applicationId: 'gitlabApplicationId',
|
||||||
},
|
},
|
||||||
|
computed: {
|
||||||
|
httpAppUrl() {
|
||||||
|
if (constants.origin.indexOf('https://') === 0 && this.serverUrl.indexOf('http://') === 0) {
|
||||||
|
return `${constants.origin.replace('https://', 'http://')}/app`;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
},
|
||||||
|
// 是否使用服务端配置
|
||||||
|
useServerConf() {
|
||||||
|
const confClientId = store.getters['data/serverConf'].gitlabClientId;
|
||||||
|
const confServerUrl = store.getters['data/serverConf'].gitlabUrl;
|
||||||
|
return !!confClientId && !!confServerUrl;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
networkSvc.getServerConf();
|
||||||
|
},
|
||||||
methods: {
|
methods: {
|
||||||
resolve() {
|
resolve() {
|
||||||
|
if (this.useServerConf) {
|
||||||
|
this.config.resolve({});
|
||||||
|
return;
|
||||||
|
}
|
||||||
const serverUrl = this.config.forceServerUrl || this.serverUrl;
|
const serverUrl = this.config.forceServerUrl || this.serverUrl;
|
||||||
if (!serverUrl) {
|
if (!serverUrl) {
|
||||||
this.setError('serverUrl');
|
this.setError('serverUrl');
|
||||||
@ -51,7 +79,7 @@ export default modalTemplate({
|
|||||||
this.setError('applicationId');
|
this.setError('applicationId');
|
||||||
}
|
}
|
||||||
if (serverUrl && this.applicationId) {
|
if (serverUrl && this.applicationId) {
|
||||||
const parsedUrl = serverUrl.match(/^(https:\/\/[^/]+)/);
|
const parsedUrl = serverUrl.match(/^(http[s]?:\/\/[^/]+)/);
|
||||||
if (!parsedUrl) {
|
if (!parsedUrl) {
|
||||||
this.setError('serverUrl');
|
this.setError('serverUrl');
|
||||||
} else {
|
} else {
|
||||||
|
@ -173,6 +173,18 @@ export default new Provider({
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
async downloadFile({ token, path }) {
|
||||||
|
const { sha, data } = await gitlabHelper.downloadFile({
|
||||||
|
...store.getters['workspace/currentWorkspace'],
|
||||||
|
token,
|
||||||
|
path,
|
||||||
|
isImg: true,
|
||||||
|
});
|
||||||
|
return {
|
||||||
|
content: data,
|
||||||
|
sha,
|
||||||
|
};
|
||||||
|
},
|
||||||
async downloadWorkspaceData({ token, syncData }) {
|
async downloadWorkspaceData({ token, syncData }) {
|
||||||
if (!syncData) {
|
if (!syncData) {
|
||||||
return {};
|
return {};
|
||||||
@ -200,18 +212,27 @@ export default new Provider({
|
|||||||
file,
|
file,
|
||||||
commitMessage,
|
commitMessage,
|
||||||
}) {
|
}) {
|
||||||
|
const isImg = file.type === 'img';
|
||||||
const path = store.getters.gitPathsByItemId[file.id];
|
const path = store.getters.gitPathsByItemId[file.id];
|
||||||
const absolutePath = `${store.getters['workspace/currentWorkspace'].path || ''}${path}`;
|
const absolutePath = !isImg ? `${store.getters['workspace/currentWorkspace'].path || ''}${path}` : file.path;
|
||||||
const sha = gitWorkspaceSvc.shaByPath[path];
|
const sha = gitWorkspaceSvc.shaByPath[!isImg ? path : file.path];
|
||||||
await gitlabHelper.uploadFile({
|
await gitlabHelper.uploadFile({
|
||||||
...store.getters['workspace/currentWorkspace'],
|
...store.getters['workspace/currentWorkspace'],
|
||||||
token,
|
token,
|
||||||
path: absolutePath,
|
path: absolutePath,
|
||||||
content: Provider.serializeContent(content),
|
content: !isImg ? Provider.serializeContent(content) : file.content,
|
||||||
sha,
|
sha,
|
||||||
|
isImg,
|
||||||
commitMessage,
|
commitMessage,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if (isImg) {
|
||||||
|
const res2 = await this.downloadFile({ token, path: absolutePath });
|
||||||
|
return {
|
||||||
|
sha: res2.sha,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
// Return new sync data
|
// Return new sync data
|
||||||
return {
|
return {
|
||||||
contentSyncData: {
|
contentSyncData: {
|
||||||
|
@ -51,11 +51,22 @@ export default {
|
|||||||
* https://docs.gitlab.com/ee/api/oauth2.html
|
* https://docs.gitlab.com/ee/api/oauth2.html
|
||||||
*/
|
*/
|
||||||
async startOauth2(serverUrl, applicationId, sub = null, silent = false) {
|
async startOauth2(serverUrl, applicationId, sub = null, silent = false) {
|
||||||
|
let apiUrl = serverUrl;
|
||||||
|
let clientId = applicationId;
|
||||||
|
// 获取gitea配置的参数
|
||||||
|
await networkSvc.getServerConf();
|
||||||
|
const confClientId = store.getters['data/serverConf'].gitlabClientId;
|
||||||
|
const confServerUrl = store.getters['data/serverConf'].gitlabUrl;
|
||||||
|
// 存在gitea配置则使用后端配置
|
||||||
|
if (confClientId && confServerUrl) {
|
||||||
|
apiUrl = confServerUrl;
|
||||||
|
clientId = confClientId;
|
||||||
|
}
|
||||||
// Get an OAuth2 code
|
// Get an OAuth2 code
|
||||||
const { accessToken } = await networkSvc.startOauth2(
|
const { accessToken } = await networkSvc.startOauth2(
|
||||||
`${serverUrl}/oauth/authorize`,
|
`${apiUrl}/oauth/authorize`,
|
||||||
{
|
{
|
||||||
client_id: applicationId,
|
client_id: clientId,
|
||||||
response_type: 'token',
|
response_type: 'token',
|
||||||
scope: 'api',
|
scope: 'api',
|
||||||
},
|
},
|
||||||
@ -157,14 +168,20 @@ export default {
|
|||||||
path,
|
path,
|
||||||
content,
|
content,
|
||||||
sha,
|
sha,
|
||||||
|
isImg,
|
||||||
commitMessage,
|
commitMessage,
|
||||||
}) {
|
}) {
|
||||||
|
let uploadContent = content;
|
||||||
|
if (isImg && typeof content !== 'string') {
|
||||||
|
uploadContent = await utils.encodeFiletoBase64(content);
|
||||||
|
}
|
||||||
return request(token, {
|
return request(token, {
|
||||||
method: sha ? 'PUT' : 'POST',
|
method: sha ? 'PUT' : 'POST',
|
||||||
url: `projects/${encodeURIComponent(projectId)}/repository/files/${encodeURIComponent(path)}`,
|
url: `projects/${encodeURIComponent(projectId)}/repository/files/${encodeURIComponent(path)}`,
|
||||||
body: {
|
body: {
|
||||||
commit_message: commitMessage || getCommitMessage(sha ? 'updateFileMessage' : 'createFileMessage', path),
|
commit_message: commitMessage || getCommitMessage(sha ? 'updateFileMessage' : 'createFileMessage', path),
|
||||||
content,
|
encoding: 'base64',
|
||||||
|
content: isImg ? uploadContent : utils.encodeBase64(content),
|
||||||
last_commit_id: sha,
|
last_commit_id: sha,
|
||||||
branch,
|
branch,
|
||||||
},
|
},
|
||||||
@ -200,6 +217,7 @@ export default {
|
|||||||
projectId,
|
projectId,
|
||||||
branch,
|
branch,
|
||||||
path,
|
path,
|
||||||
|
isImg,
|
||||||
}) {
|
}) {
|
||||||
const res = await request(token, {
|
const res = await request(token, {
|
||||||
url: `projects/${encodeURIComponent(projectId)}/repository/files/${encodeURIComponent(path)}`,
|
url: `projects/${encodeURIComponent(projectId)}/repository/files/${encodeURIComponent(path)}`,
|
||||||
@ -207,7 +225,7 @@ export default {
|
|||||||
});
|
});
|
||||||
return {
|
return {
|
||||||
sha: res.last_commit_id,
|
sha: res.last_commit_id,
|
||||||
data: utils.decodeBase64(res.content),
|
data: !isImg ? utils.decodeBase64(res.content) : res.content,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
@ -317,7 +317,7 @@ export default {
|
|||||||
};
|
};
|
||||||
},
|
},
|
||||||
parseGitlabProjectPath(url) {
|
parseGitlabProjectPath(url) {
|
||||||
const parsedProject = url && url.match(/^https:\/\/[^/]+\/(.+?)(?:\.git|\/)?$/);
|
const parsedProject = url && url.match(/^http[s]?:\/\/[^/]+\/(.+?)(?:\.git|\/)?$/);
|
||||||
return parsedProject && parsedProject[1];
|
return parsedProject && parsedProject[1];
|
||||||
},
|
},
|
||||||
parseGiteaProjectPath(url) {
|
parseGiteaProjectPath(url) {
|
||||||
|
Loading…
Reference in New Issue
Block a user