diff --git a/config/dev.env.js b/config/dev.env.js index 0620891b..f31dba18 100644 --- a/config/dev.env.js +++ b/config/dev.env.js @@ -8,5 +8,5 @@ module.exports = merge(prodEnv, { GITHUB_CLIENT_SECRET: '"80df676597abded1450926861965cc3f9bead6a0"', GITEE_CLIENT_ID: '"925ba7c78b85dec984f7877e4aca5cab10ae333c6d68e761bdb0b9dfb8f55672"', GITEE_CLIENT_SECRET: '"f05731066e42d307339dc8ebbb037a103881dafc7207a359a393b87749f1c562"', - GITEE_CALLBACK: '"http://test.local.com/oauth2/callback"' + CLIENT_ID: '"thF3qCGLN39OtafjGnqHyj6n02WwE6xD"', }) \ No newline at end of file diff --git a/server/conf.js b/server/conf.js index e71d6dd8..9b2d550b 100644 --- a/server/conf.js +++ b/server/conf.js @@ -10,7 +10,6 @@ const githubClientId = process.env.GITHUB_CLIENT_ID; const githubClientSecret = process.env.GITHUB_CLIENT_SECRET; const giteeClientId = process.env.GITEE_CLIENT_ID; const giteeClientSecret = process.env.GITEE_CLIENT_SECRET; -const giteeCallback = process.env.GITEE_CALLBACK; const googleClientId = process.env.GOOGLE_CLIENT_ID; const googleApiKey = process.env.GOOGLE_API_KEY; const wordpressClientId = process.env.WORDPRESS_CLIENT_ID; @@ -27,7 +26,6 @@ exports.values = { githubClientSecret, giteeClientId, giteeClientSecret, - giteeCallback, googleClientId, googleApiKey, wordpressClientId, diff --git a/src/components/menus/HistoryMenu.vue b/src/components/menus/HistoryMenu.vue index 3389cffc..c8c9f63f 100644 --- a/src/components/menus/HistoryMenu.vue +++ b/src/components/menus/HistoryMenu.vue @@ -9,17 +9,17 @@

同步 {{currentFileName}} 以启用修订历史 或者 登录 Google 以同步您的主工作区。

-

Loading history…

-

{{currentFileName}} has no history.

+

历史版本加载中…

+

{{currentFileName}} 没有历史版本.

- The following revisions are stored in {{ syncLocationProviderName }}. + 下面的历史版本存储在 {{ syncLocationProviderName }}. - The following revisions are stored in {{ syncLocationProviderName }}. + 下面的历史版本存储在 {{ syncLocationProviderName }}.
@@ -39,7 +39,7 @@
- +
diff --git a/src/data/welcomeFile.md b/src/data/welcomeFile.md index 972fc39b..1bb5c10e 100644 --- a/src/data/welcomeFile.md +++ b/src/data/welcomeFile.md @@ -15,7 +15,7 @@ StackEdit 将您的文件存储在您的浏览器中,这意味着您的所有 您的所有文件和文件夹在文件资源管理器中都显示为树。您可以通过单击树中的文件从一个文件切换到另一个文件。 -##重命名文件 +## 重命名文件 您可以通过单击导航栏中的文件名或单击文件资源管理器中的**重命名**按钮来重命名当前文件。 diff --git a/src/services/providers/giteaProvider.js b/src/services/providers/giteaProvider.js index bb77496f..df88d84c 100644 --- a/src/services/providers/giteaProvider.js +++ b/src/services/providers/giteaProvider.js @@ -135,17 +135,24 @@ export default new Provider({ 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 entries.map(({ + author, + committer, + commit, + sha, + }) => { + let user; + if (author && author.login) { + user = author; + } else if (committer && committer.login) { + user = committer; + } + const sub = `${giteaHelper.subPrefix}:${user.login}`; + userSvc.addUserInfo({ id: sub, name: user.login, imageUrl: user.avatar_url }); + const date = (commit.author && commit.author.date) + || (commit.committer && commit.committer.date); return { - id: entry.id, + id: sha, sub, created: date ? new Date(date).getTime() : 1, }; diff --git a/src/services/providers/giteaWorkspaceProvider.js b/src/services/providers/giteaWorkspaceProvider.js index 0ae8d0d5..fc1cd52a 100644 --- a/src/services/providers/giteaWorkspaceProvider.js +++ b/src/services/providers/giteaWorkspaceProvider.js @@ -251,19 +251,27 @@ export default new Provider({ 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 entries.map(({ + author, + committer, + commit, + sha, + }) => { + let user; + if (author && author.login) { + user = author; + } else if (committer && committer.login) { + user = committer; + } + const sub = `${giteaHelper.subPrefix}:${user.login}`; + userSvc.addUserInfo({ id: sub, name: user.login, imageUrl: user.avatar_url }); + const date = (commit.author && commit.author.date) + || (commit.committer && commit.committer.date) + || 1; return { - id: entry.id, + id: sha, sub, - created: date ? new Date(date).getTime() : 1, + created: new Date(date).getTime(), }; }); }, diff --git a/src/services/providers/giteeProvider.js b/src/services/providers/giteeProvider.js index 9c68dacd..0e719d47 100644 --- a/src/services/providers/giteeProvider.js +++ b/src/services/providers/giteeProvider.js @@ -135,6 +135,9 @@ export default new Provider({ user = committer; } const sub = `${giteeHelper.subPrefix}:${user.login}`; + if (user.avatar_url && user.avatar_url.endsWith('.png')) { + user.avatar_url = `${user.avatar_url}!avatar60`; + } userSvc.addUserInfo({ id: sub, name: user.login, imageUrl: user.avatar_url }); const date = (commit.author && commit.author.date) || (commit.committer && commit.committer.date); diff --git a/src/services/providers/giteeWorkspaceProvider.js b/src/services/providers/giteeWorkspaceProvider.js index 3d5ec740..4617d3a5 100644 --- a/src/services/providers/giteeWorkspaceProvider.js +++ b/src/services/providers/giteeWorkspaceProvider.js @@ -249,6 +249,9 @@ export default new Provider({ user = committer; } const sub = `${giteeHelper.subPrefix}:${user.login}`; + if (user.avatar_url && user.avatar_url.endsWith('.png')) { + user.avatar_url = `${user.avatar_url}!avatar60`; + } userSvc.addUserInfo({ id: sub, name: user.login, imageUrl: user.avatar_url }); const date = (commit.author && commit.author.date) || (commit.committer && commit.committer.date) diff --git a/src/services/providers/helpers/giteaHelper.js b/src/services/providers/helpers/giteaHelper.js index 62d5268d..53fc8618 100644 --- a/src/services/providers/helpers/giteaHelper.js +++ b/src/services/providers/helpers/giteaHelper.js @@ -5,6 +5,8 @@ import userSvc from '../../userSvc'; import badgeSvc from '../../badgeSvc'; import constants from '../../../data/constants'; +const tokenExpirationMargin = 5 * 60 * 1000; + const request = ({ accessToken, serverUrl }, options) => networkSvc.request({ ...options, url: `${serverUrl}/api/v1/${options.url}`, @@ -51,30 +53,50 @@ export default { /** * 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, - ); + async startOauth2( + serverUrl, applicationId, applicationSecret, + sub = null, silent = false, refreshToken, + ) { + let tokenBody; + if (!silent) { + // 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 + tokenBody = (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; + } else { + // Exchange refreshToken with token + tokenBody = (await networkSvc.request({ + method: 'POST', + url: `${serverUrl}/login/oauth/access_token`, + body: { + client_id: applicationId, + client_secret: applicationSecret, + refresh_token: refreshToken, + grant_type: 'refresh_token', + redirect_uri: constants.oauth2RedirectUri, + }, + })).body; + } - // 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; + const accessToken = tokenBody.access_token; // Call the user info endpoint const user = await request({ accessToken, serverUrl }, { @@ -96,6 +118,8 @@ export default { const token = { accessToken, name: user.username, + refreshToken: tokenBody.refresh_token, + expiresOn: Date.now() + (tokenBody.expires_in * 1000), serverUrl, sub: uniqueSub, }; @@ -104,6 +128,47 @@ export default { store.dispatch('data/addGiteaToken', token); return token; }, + // 刷新token + async refreshToken(token) { + const { + serverUrl, + applicationId, + applicationSecret, + sub, + } = token; + const lastToken = store.getters['data/giteaTokensBySub'][sub]; + // 兼容旧的没有过期时间 + if (!lastToken.expiresOn) { + await store.dispatch('modal/open', { + type: 'providerRedirection', + name: 'Gitea', + }); + return this.startOauth2(serverUrl, applicationId, applicationSecret, sub); + } + // lastToken is not expired + if (lastToken.expiresOn > Date.now() + tokenExpirationMargin) { + return lastToken; + } + + // existing token is about to expire. + // Try to get a new token in background + try { + return await this.startOauth2( + serverUrl, applicationId, applicationSecret, + sub, true, lastToken.refreshToken, + ); + } catch (err) { + // If it fails try to popup a window + if (store.state.offline) { + throw err; + } + await store.dispatch('modal/open', { + type: 'providerRedirection', + name: 'Gitea', + }); + return this.startOauth2(serverUrl, applicationId, applicationSecret, sub); + } + }, async addAccount(serverUrl, applicationId, applicationSecret, sub = null) { const token = await this.startOauth2(serverUrl, applicationId, applicationSecret, sub); badgeSvc.addBadge('addGiteaAccount'); @@ -129,7 +194,8 @@ export default { projectId, branch, }) { - return request(token, { + const refreshedToken = await this.refreshToken(token); + return request(refreshedToken, { url: `repos/${projectId}/git/trees/${branch}`, params: { recursive: true, @@ -147,7 +213,8 @@ export default { branch, path, }) { - return request(token, { + const refreshedToken = await this.refreshToken(token); + return request(refreshedToken, { url: `repos/${projectId}/commits`, params: { sha: branch, @@ -168,7 +235,8 @@ export default { content, sha, }) { - return request(token, { + const refreshedToken = await this.refreshToken(token); + return request(refreshedToken, { method: sha ? 'PUT' : 'POST', url: `repos/${projectId}/contents/${encodeURIComponent(path)}`, body: { @@ -190,7 +258,8 @@ export default { path, sha, }) { - return request(token, { + const refreshedToken = await this.refreshToken(token); + return request(refreshedToken, { method: 'DELETE', url: `repos/${projectId}/contents/${encodeURIComponent(path)}`, body: { @@ -210,7 +279,8 @@ export default { branch, path, }) { - const { sha, content } = await request(token, { + const refreshedToken = await this.refreshToken(token); + const { sha, content } = await request(refreshedToken, { url: `repos/${projectId}/contents/${encodeURIComponent(path)}`, params: { ref: branch }, }); diff --git a/src/services/providers/helpers/giteeHelper.js b/src/services/providers/helpers/giteeHelper.js index ffae68ab..59b02227 100644 --- a/src/services/providers/helpers/giteeHelper.js +++ b/src/services/providers/helpers/giteeHelper.js @@ -139,7 +139,7 @@ export default { return this.startOauth2(); } // lastToken is not expired - if (lastToken.expiresOn > Date.now() - tokenExpirationMargin) { + if (lastToken.expiresOn > Date.now() + tokenExpirationMargin) { return lastToken; } diff --git a/src/services/timeSvc.js b/src/services/timeSvc.js index 8b157ed2..f8895639 100644 --- a/src/services/timeSvc.js +++ b/src/services/timeSvc.js @@ -138,21 +138,21 @@ class RelativeTime { const hr = Math.round(min / 60); const day = Math.round(hr / 24); if (ms < 0) { - return 'just now'; + return '刚刚'; } else if (sec < 45) { - return 'just now'; + return '刚刚'; } else if (sec < 90) { - return 'a minute ago'; + return '1分钟前'; } else if (min < 45) { - return `${min} minutes ago`; + return `${min}分钟前`; } else if (min < 90) { - return 'an hour ago'; + return '1小时前'; } else if (hr < 24) { - return `${hr} hours ago`; + return `${hr}小时前`; } else if (hr < 36) { - return 'a day ago'; + return '1天前'; } else if (day < 30) { - return `${day} days ago`; + return `${day}天前`; } return null; }