From 780ff03bb6b22f909902edd0a030a42ff1e3a0c1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=9C=E6=99=93=E6=B5=A9?= <1923911906@qq.com> Date: Mon, 13 Nov 2023 17:57:59 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E8=B0=83=E7=94=A8github=E6=8E=A5?= =?UTF-8?q?=E5=8F=A3=E5=AE=8C=E6=88=90=E4=B8=8A=E4=BC=A0=E5=8D=9A=E5=AE=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/router.options.ts | 8 + components/BlogAffix.vue | 12 ++ components/BlogShow.vue | 198 +++++++++++++++--- components/BlogsTree.vue | 134 +++++++++--- components/navigation.vue | 6 +- composables/index.d.ts | 15 -- composables/useGithubAuth.ts | 4 +- index.d.ts | 53 +++++ nuxt.config.ts | 7 +- pages/blogs/[blogPath].vue | 54 +++-- pages/blogs/add/[blogPath].vue | 47 +++++ pages/blogs/edit/[blogPath].vue | 60 ++++++ ...3\272\346\226\260\345\215\232\345\256\242" | 1 - public/_blogs/undefinedtest | 1 - server/api/blogsTree.ts | 2 +- server/api/github/auth.ts | 10 +- server/api/github/commit/index.post.ts | 29 +-- server/api/github/index.d.ts | 7 - server/api/github/resetAuth.post.ts | 13 +- server/handler/blogsTree.ts | 9 +- 20 files changed, 534 insertions(+), 136 deletions(-) create mode 100644 components/BlogAffix.vue delete mode 100644 composables/index.d.ts create mode 100644 index.d.ts create mode 100644 pages/blogs/add/[blogPath].vue create mode 100644 pages/blogs/edit/[blogPath].vue delete mode 100644 "public/_blogs/JavaScript\346\265\213\350\257\225\345\210\233\345\273\272\346\226\260\345\215\232\345\256\242" delete mode 100644 public/_blogs/undefinedtest delete mode 100644 server/api/github/index.d.ts diff --git a/app/router.options.ts b/app/router.options.ts index 9fc56ed..3ee32f1 100644 --- a/app/router.options.ts +++ b/app/router.options.ts @@ -8,5 +8,13 @@ export default { path: '/blogs/:blogPath+', component: () => import('~/pages/blogs/[blogPath].vue'), }, + { + path: '/blogs/edit/:blogPath+', + component: () => import('~/pages/blogs/edit/[blogPath].vue'), + }, + { + path: '/blogs/add/:blogPath+', + component: () => import('~/pages/blogs/add/[blogPath].vue'), + }, ], }; diff --git a/components/BlogAffix.vue b/components/BlogAffix.vue new file mode 100644 index 0000000..66bb005 --- /dev/null +++ b/components/BlogAffix.vue @@ -0,0 +1,12 @@ + + + + + diff --git a/components/BlogShow.vue b/components/BlogShow.vue index 73a34c6..3aa03c2 100644 --- a/components/BlogShow.vue +++ b/components/BlogShow.vue @@ -1,41 +1,177 @@ - - - \ No newline at end of file diff --git a/components/BlogsTree.vue b/components/BlogsTree.vue index 20600e3..b0b1287 100644 --- a/components/BlogsTree.vue +++ b/components/BlogsTree.vue @@ -1,34 +1,118 @@ - diff --git a/components/navigation.vue b/components/navigation.vue index c0a0c49..89db5a5 100644 --- a/components/navigation.vue +++ b/components/navigation.vue @@ -80,7 +80,8 @@ const themeStyle = reactive({ backgroundColor: computed(() => (dataThemeNight.value ? '#363B40' : '#FFFFFF')), hoverColor: computed(() => (dataThemeNight.value ? '#5BAC87' : '#5BAC87')), }); -const { githubAccess } = useRuntimeConfig().public; +const { githubAccessDev, githubAccessServe } = useRuntimeConfig().public; +const githubAccess = import.meta.env.PROD ? githubAccessServe : githubAccessDev; const isLogin = ref(false); let githubUser = ref(); let githubAuth = ref(); @@ -104,13 +105,12 @@ onMounted(async () => { const newGithubAuth = await $fetch('/api/github/resetAuth', { method: 'post', body: { - refresh_token: githubAuth.value.access_token, + refresh_token: githubAuth.value.refresh_token, }, }); localStorage.setItem('githubAuth', JSON.stringify(newGithubAuth)); } } - if (githubUser.value && githubAuth.value) { isLogin.value = true; } else { diff --git a/composables/index.d.ts b/composables/index.d.ts deleted file mode 100644 index a35ea82..0000000 --- a/composables/index.d.ts +++ /dev/null @@ -1,15 +0,0 @@ -type GithubAuth = { - access_token: string; - expires_in: number; - refresh_token: string; - refresh_token_expires_in: number; - scope: string; - token_type: string; - createTime: number; - destroyTime: number; - refreshTime: number; -}; -type GithubUser = { - avatar_url: string; - name: string; -}; diff --git a/composables/useGithubAuth.ts b/composables/useGithubAuth.ts index 9ba6128..e4e1921 100644 --- a/composables/useGithubAuth.ts +++ b/composables/useGithubAuth.ts @@ -3,7 +3,7 @@ export const useGithubAuth = (): Ref => if (process.client) { return JSON.parse(localStorage.getItem('githubAuth') as string); } else { - return ''; + throw new Error('useGithubAuth 仅可在process.client时运行'); } }); export const useGithubUser = (): Ref => @@ -11,6 +11,6 @@ export const useGithubUser = (): Ref => if (process.client) { return JSON.parse(localStorage.getItem('githubUser') as string); } else { - return ''; + throw new Error('useGithubUser 仅可在process.client时运行'); } }); diff --git a/index.d.ts b/index.d.ts new file mode 100644 index 0000000..c5ea263 --- /dev/null +++ b/index.d.ts @@ -0,0 +1,53 @@ +import { Endpoints } from '@octokit/types'; +declare global { + type RepoGetRef = Endpoints['GET /repos/{owner}/{repo}/git/ref/{ref}']; + type RepoGetCommit = Endpoints['GET /repos/{owner}/{repo}/git/commits/{commit_sha}']; + type RepoCreateBlobs = Endpoints['POST /repos/{owner}/{repo}/git/blobs']; + type RepoCreateTree = Endpoints['POST /repos/{owner}/{repo}/git/trees']; + type RepoCreateCommit = Endpoints['POST /repos/{owner}/{repo}/git/commits']; + type RepoUpdateRef = Endpoints['PATCH /repos/{owner}/{repo}/git/refs/{ref}']; + + type BlogsTree = Array; + type BlogsTreeBranch = { + name: string; + /** 'dir' | 'file' */ + type: string; + path?: string; + expand?: boolean; + dirPath?: string; + children?: Array; + }; + + type GithubAuth = { + access_token: string; + expires_in: number; + refresh_token: string; + refresh_token_expires_in: number; + scope: string; + token_type: string; + createTime: number; + destroyTime: number; + refreshTime: number; + }; + type GithubUser = { + avatar_url: string; + name: string; + }; + + type ContentShowType = 'show' | 'edit' | 'add'; + + type CommitConfig = { + /** @description — The file referenced in the tree. */ + path: string; + /** @description — The new blob's content */ + content: string; + /** @description — The file mode; one of 100644 for file (blob), 100755 for executable (blob), 040000 for subdirectory (tree), 160000 for submodule (commit), or 120000 for a blob that specifies the path of a symlink. + * @enum */ + mode: '100644' | '100755' | '040000' | '160000' | '120000'; + /** @description — Either blob, tree, or commit. + * @enum */ + type: 'blob' | 'commit' | 'tree'; + /** @description — The commit message*/ + message: string; + }; +} diff --git a/nuxt.config.ts b/nuxt.config.ts index 72429fb..e0d8a92 100644 --- a/nuxt.config.ts +++ b/nuxt.config.ts @@ -50,11 +50,16 @@ export default defineNuxtConfig({ }, runtimeConfig: { public: { - githubAccess: { + githubAccessDev: { clientId: 'Iv1.5999dbc8911f0be3', clientSecret: 'b217aad003ec30bea365e2f103eee2079f1cad8e', redirectUrl: 'http://localhost:3000/api/github/auth', }, + githubAccessServe: { + clientId: 'Iv1.07bde629d78e1f2e', + clientSecret: '2f01a4c05d206e7101f1a4ad5c810998c8f36821', + redirectUrl: 'https://blog.mayuan.work/api/github/auth', + }, }, }, }); diff --git a/pages/blogs/[blogPath].vue b/pages/blogs/[blogPath].vue index 2d5c553..387a184 100644 --- a/pages/blogs/[blogPath].vue +++ b/pages/blogs/[blogPath].vue @@ -5,48 +5,62 @@
- - - + + + -
diff --git a/pages/blogs/edit/[blogPath].vue b/pages/blogs/edit/[blogPath].vue new file mode 100644 index 0000000..ea3674b --- /dev/null +++ b/pages/blogs/edit/[blogPath].vue @@ -0,0 +1,60 @@ + + + + + diff --git "a/public/_blogs/JavaScript\346\265\213\350\257\225\345\210\233\345\273\272\346\226\260\345\215\232\345\256\242" "b/public/_blogs/JavaScript\346\265\213\350\257\225\345\210\233\345\273\272\346\226\260\345\215\232\345\256\242" deleted file mode 100644 index ea4e401..0000000 --- "a/public/_blogs/JavaScript\346\265\213\350\257\225\345\210\233\345\273\272\346\226\260\345\215\232\345\256\242" +++ /dev/null @@ -1 +0,0 @@ -# 测试创建新博客 \ No newline at end of file diff --git a/public/_blogs/undefinedtest b/public/_blogs/undefinedtest deleted file mode 100644 index 30d74d2..0000000 --- a/public/_blogs/undefinedtest +++ /dev/null @@ -1 +0,0 @@ -test \ No newline at end of file diff --git a/server/api/blogsTree.ts b/server/api/blogsTree.ts index 7415994..b38a03a 100644 --- a/server/api/blogsTree.ts +++ b/server/api/blogsTree.ts @@ -1,7 +1,7 @@ import { getAllFiles, blogsTreeHandler } from '../handler/blogsTree'; export default defineEventHandler((even) => { return new Promise((resolve, reject) => { - const blogsTree = new Array(); + const blogsTree: BlogsTree = new Array(); try { getAllFiles('public/_blogs', blogsTree); blogsTreeHandler(blogsTree); diff --git a/server/api/github/auth.ts b/server/api/github/auth.ts index 5bc6c82..d007359 100644 --- a/server/api/github/auth.ts +++ b/server/api/github/auth.ts @@ -1,10 +1,12 @@ +import { NuxtError } from '#app'; import axios from 'axios'; import https from 'https'; export default defineEventHandler((event) => { return new Promise(async (resolve, reject) => { const body = getQuery(event); try { - const { githubAccess } = useRuntimeConfig().public; + const { githubAccessDev, githubAccessServe } = useRuntimeConfig().public; + const githubAccess = import.meta.env.PROD ? githubAccessServe : githubAccessDev; const { data: githubAuth } = await axios({ httpsAgent: new https.Agent({ rejectUnauthorized: false, @@ -38,7 +40,11 @@ export default defineEventHandler((event) => { 302, ); } catch (error) { - sendError(event, new Error(JSON.stringify(error))); + throw createError({ + statusCode: (error as NuxtError).statusCode, + statusMessage: (error as NuxtError).statusMessage, + message: (error as NuxtError).cause as string, + }); } }); }); diff --git a/server/api/github/commit/index.post.ts b/server/api/github/commit/index.post.ts index 03ccb54..96abe6b 100644 --- a/server/api/github/commit/index.post.ts +++ b/server/api/github/commit/index.post.ts @@ -1,11 +1,3 @@ -import type { - RepoCreateBlobs, - RepoCreateCommit, - RepoCreateTree, - RepoGetCommit, - RepoGetRef, - RepoUpdateRef, -} from '..'; export default defineEventHandler((event) => { return new Promise(async (resolve, reject) => { const body = await readBody(event); @@ -17,21 +9,10 @@ export default defineEventHandler((event) => { /** * The file mode; one of 100644 for file (blob), 100755 for executable (blob), 040000 for subdirectory (tree), 160000 for submodule (commit), or 120000 for a blob that specifies the path of a symlink. */ - const apiConfig = { - /** @description — The file referenced in the tree. */ - path: '', - /** @description — The new blob's content */ - content: '', - /** @description — The file mode; one of 100644 for file (blob), 100755 for executable (blob), 040000 for subdirectory (tree), 160000 for submodule (commit), or 120000 for a blob that specifies the path of a symlink. - @enum */ - mode: '' as '100644' | '100755' | '040000' | '160000' | '120000', - /** @description — Either blob, tree, or commit. - * @enum */ - type: '' as 'blob' | 'commit' | 'tree', - /** @description — The commit message*/ - message: '', - }; + const apiConfig = { + ...body.commitConfig, + } as CommitConfig; try { //1. 获取 Ref const getCommitRefConfig = { @@ -78,6 +59,8 @@ export default defineEventHandler((event) => { createBlobsConfig: createBlobsConfig, }, })) as RepoCreateBlobs['response']['data']; + console.log(createBlobs); + // 4. 生成 tree const createTreeConfig = { owner: baseConfig.owner, @@ -131,6 +114,8 @@ export default defineEventHandler((event) => { })) as RepoUpdateRef['response']['data']; resolve(updateRef); } catch (error) { + console.log(error); + resolve(error); } }); diff --git a/server/api/github/index.d.ts b/server/api/github/index.d.ts deleted file mode 100644 index e509b6c..0000000 --- a/server/api/github/index.d.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { Endpoints } from '@octokit/types'; -type RepoGetRef = Endpoints['GET /repos/{owner}/{repo}/git/ref/{ref}']; -type RepoGetCommit = Endpoints['GET /repos/{owner}/{repo}/git/commits/{commit_sha}']; -type RepoCreateBlobs = Endpoints['POST /repos/{owner}/{repo}/git/blobs']; -type RepoCreateTree = Endpoints['POST /repos/{owner}/{repo}/git/trees']; -type RepoCreateCommit = Endpoints['POST /repos/{owner}/{repo}/git/commits']; -type RepoUpdateRef = Endpoints['PATCH /repos/{owner}/{repo}/git/refs/{ref}']; diff --git a/server/api/github/resetAuth.post.ts b/server/api/github/resetAuth.post.ts index a78e895..c690ac3 100644 --- a/server/api/github/resetAuth.post.ts +++ b/server/api/github/resetAuth.post.ts @@ -3,7 +3,8 @@ import https from 'https'; export default defineEventHandler((event) => { return new Promise(async (resolve, reject) => { const body = await readBody(event); - const { githubAccess } = useRuntimeConfig().public; + const { githubAccessDev, githubAccessServe } = useRuntimeConfig().public; + const githubAccess = import.meta.env.PROD ? githubAccessServe : githubAccessDev; try { const { data: githubAuth } = await axios({ httpsAgent: new https.Agent({ @@ -20,7 +21,15 @@ export default defineEventHandler((event) => { accept: 'application/json', }, }); - resolve(githubAuth); + const now = new Date(); + resolve({ + ...githubAuth, + createTime: now.getTime(), + destroyTime: now.setSeconds(now.getSeconds() + githubAuth.refresh_token_expires_in), + refreshTime: now.setSeconds( + now.getSeconds() + githubAuth.expires_in - githubAuth.refresh_token_expires_in, + ), + }); } catch (error) { sendError(event, new Error(JSON.stringify(error))); } diff --git a/server/handler/blogsTree.ts b/server/handler/blogsTree.ts index dbf1f97..25c60fc 100644 --- a/server/handler/blogsTree.ts +++ b/server/handler/blogsTree.ts @@ -46,7 +46,7 @@ function isDir(filepath: string) { * @param path 路径 * @param arr 将结果存储到该数组中 */ -function getAllFiles(path: string, arr: Array) { +function getAllFiles(path: string, arr: BlogsTree) { // 结果将存储到arr数组中 const filesArr = getFiles(path); // 获取目录下所有文件 if (path.slice(-1) == '/') { @@ -57,13 +57,14 @@ function getAllFiles(path: string, arr: Array) { const filePath = `${path}/${fileName}`; if (isDir(filePath)) { //如果是文件夹 - const itemFileArr = new Array(); + const itemFileArr = new Array() as BlogsTree; getAllFiles(filePath, itemFileArr); const dir = { name: fileName, type: 'dir', dirPath: `${filePath}/`, children: itemFileArr, + expand: false, }; arr.push(dir); } else if (isFile(filePath)) { @@ -75,12 +76,12 @@ function getAllFiles(path: string, arr: Array) { // const arr = []; // getAllFiles('../blogs', arr); // console.log(arr); -const blogsTreeHandler = (blogsTree: Array) => { +const blogsTreeHandler = (blogsTree: BlogsTree) => { let obj; for (const key in blogsTree) { if (blogsTree[key].name == 'README.md') { obj = { ...blogsTree[key] }; - blogsTree.splice(key as any, 1); + blogsTree.splice(Number(key), 1); blogsTree.unshift(obj); return; }