From c37ce2b8203116a9ab1fe25c9fa575541bbd26d3 Mon Sep 17 00:00:00 2001 From: Yufan Sheng Date: Sun, 23 Jun 2024 23:01:02 +0800 Subject: [PATCH] feat: change the commenter avatar link. (#53) * feat: add new comment user merge service. * feat: better hide the commenter email. --- .gitignore | 3 + .prettierignore | 1 + .vscode/settings.json | 2 + README.md | 60 ++-- astro.config.ts | 3 - licenses/LICENSE.oppo-sans.txt | 6 - options.ts | 10 + src/actions/index.ts | 29 +- src/components/comment/Comment.astro | 7 +- src/components/comment/CommentItem.astro | 11 +- src/components/comment/Comments.astro | 15 +- src/components/comment/artalk.ts | 29 +- src/components/comment/types.ts | 16 +- src/content/LICENSE | 438 +++++++++++++++++++++++ src/helpers/db/query.ts | 32 ++ src/helpers/tools.ts | 5 + src/pages/avatar/[hash].png.ts | 41 +++ tools/README.md | 17 +- tools/cmd/artalk.go | 121 +++++++ tools/cmd/image.go | 8 +- tools/go.mod | 2 + tools/go.sum | 15 +- 22 files changed, 728 insertions(+), 143 deletions(-) delete mode 100644 licenses/LICENSE.oppo-sans.txt create mode 100644 src/content/LICENSE create mode 100644 src/pages/avatar/[hash].png.ts create mode 100644 tools/cmd/artalk.go diff --git a/.gitignore b/.gitignore index 216c1ea..db81af3 100644 --- a/.gitignore +++ b/.gitignore @@ -27,3 +27,6 @@ pnpm-debug.log* # Hide the SQL session *.session.sql + +# Blog Tools +./tools diff --git a/.prettierignore b/.prettierignore index 6e564af..71604a4 100644 --- a/.prettierignore +++ b/.prettierignore @@ -5,3 +5,4 @@ public/images # The MDX files *.mdx +*.md diff --git a/.vscode/settings.json b/.vscode/settings.json index 59d322d..e4558fc 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -106,6 +106,7 @@ "recma", "redmi", "regclass", + "rivo", "sauvignon", "sheng", "shiki", @@ -120,6 +121,7 @@ "timestamptz", "toolsmp", "tsconfigs", + "tview", "ultrahtml", "unpic", "unsharp", diff --git a/README.md b/README.md index 741ac93..820be68 100644 --- a/README.md +++ b/README.md @@ -58,7 +58,7 @@ The default username is `your system username`, with no password. Create and initialize the database and user with these commands: -```sql +```postgresql -- Create a database. CREATE DATABASE ; @@ -76,23 +76,25 @@ GRANT ALL PRIVILEGES ON DATABASE TO ; GRANT ALL ON SCHEMA public TO ; ``` -Most tables are created by the Artalk. [Execute the Artalk](https://artalk.js.org/guide/deploy.html) to create the tables. +Most tables are created by the Artalk. [Execute the Artalk](https://artalk.js.org/guide/deploy.html) to create the +tables. The like table should be created manually. Execute the SQL below. -```sql +```postgresql -- Sequence and defined type CREATE SEQUENCE IF NOT EXISTS atk_likes_id_seq; -- Table Definition -CREATE TABLE "public"."atk_likes" ( - "id" int8 NOT NULL DEFAULT nextval('atk_likes_id_seq'::regclass), - "created_at" timestamptz, - "updated_at" timestamptz, - "deleted_at" timestamptz, - "token" varchar(255), - "page_key" varchar(255), - PRIMARY KEY ("id") +CREATE TABLE "public"."atk_likes" +( + "id" int8 NOT NULL DEFAULT nextval('atk_likes_id_seq'::regclass), + "created_at" timestamptz, + "updated_at" timestamptz, + "deleted_at" timestamptz, + "token" varchar(255), + "page_key" varchar(255), + PRIMARY KEY ("id") ); -- Create table index @@ -101,8 +103,9 @@ CREATE INDEX IF NOT EXISTS "idx_atk_likes_token" ON "public"."atk_likes" ("token ### Comments Integration -This weblog use artalk as its backend comment service. But since artalk didn't provide the latest comments API. -We decide to query it directly from Postgres database. So the comments and fav clicks are living in the same database. +This weblog uses artalk as its backend comment service. But since artalk didn't provide the latest comments API. +We decide to query it directly from the Postgres database. So the comments and fav clicks are living in the same +database. ## Writing @@ -125,7 +128,7 @@ date: 2013/7/13 20:46:25 ### Post Front Matter Settings | Setting | Description | Required | Default | -| ----------- | ------------------------------------ | -------- | -------------------- | +|-------------|--------------------------------------|----------|----------------------| | `id` | ID (unique), used as the permalink | true | Filename | | `title` | Title | true | Filename | | `date` | Published date | true | | @@ -140,7 +143,7 @@ date: 2013/7/13 20:46:25 ### Pages Front Matter Settings | Setting | Description | Required | Default | -| ----------- | ------------------------------------ | -------- | -------------- | +|-------------|--------------------------------------|----------|----------------| | `id` | ID (unique), used as the permalink | true | Filename | | `title` | Title | true | Filename | | `date` | Published date | true | | @@ -168,25 +171,27 @@ to get it worked everywhere. This weblog is deployed on the [zeabur](https://zeabur.com) platform. You can check their documents and get your own weblog to be published without any budget at first. -Or you can host on your own machine. Use [Dockerfile](./Dockerfile) to build a image and run it locally. +Or you can host on your own machine. Use [Dockerfile](./Dockerfile) to build an image and run it locally. The comment system is leverage the [Artalk](https://artalk.js.org), a self-hosted comment system. You should host it on your own machine. -But it can be modified and changed to any other comment solutions. -For instance, the [giscus](https://giscus.app) is an opinionated choice. ## TODO Checklist - [ ] Check article grammar errors by using ChatGPT. Remain **54** posts. - [ ] Add music to the articles. Remain **54** posts. -- [ ] External the article inner links with different target. +- [ ] External article inner links with different targets. - [ ] Slide share components integration. -### Long Term Goals +### Comments TODO Checklist + +- [ ] Support modification after commenting in 60 minutes even if you have refreshed the page. +- [ ] Use self-developed duoshuo as the comment's solution. + +### Long-Term Goals - [ ] Add han.js support for better typography. - [ ] Drop bootstrap, in favor of tailwind css. -- [ ] Use self developed duoshuo as the comments solution. ## License @@ -194,7 +199,7 @@ The source code of this blog is licensed under the [MIT](LICENSE) license, feel to free to use it without any legal risks. The [content](src/content) of this blog's posts is licensed under the -[CC BY-NC-SA 4.0](https://creativecommons.org/licenses/by-nc-sa/4.0/) license. +[CC BY-NC-SA 4.0](src/content/LICENSE) license. ### Logo Fonts License @@ -204,23 +209,16 @@ and [Iroha Mochi](https://modi.jpn.org/font_iroha-mochi.php) with [license](lice They are the fonts that can be used in business without any charge. -### Article Font License - -The [OPPOSans 3.0](https://www.coloros.com/article/A00000050) is used for reading in my weblog. -It can be used in business scenarios without any modification. -I just placed it under the [opposans](src/assets/styles/opposans/) directory for better integration. -The license file is [here](licenses/LICENSE.oppo-sans.txt) - ### Open Graph Font License The [Noto Sans Simplified Chinese](https://fonts.google.com/noto/specimen/Noto+Sans+SC) is used for rendering the open graph image in my weblog. It can be used in business scenarios without any modification. -The license file is [here](LICENSE.noto-sans-sc.txt) +The license file is [here](licenses/LICENSE.noto-sans-sc.txt) ### Third Party Codes License -Some codes in this project is copied from other project. I have add the comments in the files's header. +Some codes in this project are copied from other projects. I have added the comments in the files' header. The source codes used from third party projects are: diff --git a/astro.config.ts b/astro.config.ts index 3fb9aa2..2857a63 100644 --- a/astro.config.ts +++ b/astro.config.ts @@ -64,9 +64,6 @@ export default defineConfig({ vite: { // Add this for avoiding the needless import optimize in Vite. optimizeDeps: { exclude: ['@napi-rs/canvas'] }, - esbuild: { - drop: ['console', 'debugger'], - }, }, build: { assets: 'cats', diff --git a/licenses/LICENSE.oppo-sans.txt b/licenses/LICENSE.oppo-sans.txt deleted file mode 100644 index 94cea9f..0000000 --- a/licenses/LICENSE.oppo-sans.txt +++ /dev/null @@ -1,6 +0,0 @@ -* OPPO Sans(含中文及西文,3 款字重)允许个人或企业免费使用,含商业用途,版权归 OPPO 广东移动通信有限公司所有。 -您应遵守以下条款,违者将会被追究法律责任: -1. 不对字体进行改编或二次开发; -2. 不对外售卖字体; -3. 不向他方提供其他下载渠道; -4. 不用于违法用途。 diff --git a/options.ts b/options.ts index f63f5ff..0531e67 100644 --- a/options.ts +++ b/options.ts @@ -65,6 +65,11 @@ const Options = z comments: z.object({ server: z.string().url().readonly(), admins: z.array(z.number()), + size: z.number().default(10).readonly(), + avatar: z.object({ + mirror: z.string().url().readonly(), + size: z.number(), + }), }), }), thumbnail: z @@ -175,6 +180,11 @@ const options: z.input = { comments: { server: 'https://comment.yufan.me', admins: [3], + size: 10, + avatar: { + mirror: 'https://weavatar.com/avatar', + size: 80, + }, }, }, thumbnail: ({ src, width, height }) => { diff --git a/src/actions/index.ts b/src/actions/index.ts index 0c056dd..bac2b2d 100644 --- a/src/actions/index.ts +++ b/src/actions/index.ts @@ -1,13 +1,12 @@ import Comment from '@/components/comment/Comment.astro'; import CommentItem from '@/components/comment/CommentItem.astro'; -import { commentConfig, createComment, loadComments } from '@/components/comment/artalk'; +import { createComment, loadComments } from '@/components/comment/artalk'; import { partialRender } from '@/helpers/container'; -import { decreaseLikes, increaseLikes, queryLikes } from '@/helpers/db/query'; +import { decreaseLikes, increaseLikes, queryLikes, queryUserId } from '@/helpers/db/query'; import { pages, posts } from '@/helpers/schema'; -import { urlJoin } from '@/helpers/tools'; +import { encodedEmail, urlJoin } from '@/helpers/tools'; import { z } from 'astro/zod'; import { ActionError, defineAction } from 'astro:actions'; -import crypto from 'node:crypto'; const keys = [...posts.map((post) => post.permalink), ...pages.map((page) => page.permalink)]; const CommentConnectError = new ActionError({ @@ -48,13 +47,9 @@ export const server = { accept: 'json', input: z.object({ email: z.string().email() }), handler: async ({ email }) => { - const config = await commentConfig(); - if (config === null) { - throw CommentConnectError; - } - - const hash = crypto.createHash('md5').update(email.trim().toLowerCase()).digest('hex'); - return { avatar: urlJoin(config.frontend_conf.gravatar.mirror, `${hash}?d=mm&s=80`) }; + const id = await queryUserId(email); + const hash = id === null ? encodedEmail(email) : `${id}`; + return { avatar: urlJoin(import.meta.env.SITE, 'avatar', `${hash}.png`) }; }, }), comment: defineAction({ @@ -76,9 +71,8 @@ export const server = { }); } - const config = await commentConfig(); const content = await partialRender(CommentItem, { - props: { depth: resp.rid === 0 ? 1 : 2, comment: resp, pending: resp.is_pending, config: config }, + props: { depth: resp.rid === 0 ? 1 : 2, comment: resp, pending: resp.is_pending }, }); return { content }; @@ -91,17 +85,12 @@ export const server = { offset: z.number(), }), handler: async ({ page_key, offset }) => { - const config = await commentConfig(); - if (config === null) { - throw CommentConnectError; - } - - const comments = await loadComments(page_key, null, Number(offset), config); + const comments = await loadComments(page_key, null, Number(offset)); if (comments === null) { throw CommentConnectError; } - const content = await partialRender(Comment, { props: { comments: comments, config: config } }); + const content = await partialRender(Comment, { props: { comments: comments } }); return { content }; }, diff --git a/src/components/comment/Comment.astro b/src/components/comment/Comment.astro index 2a95a5e..576b1d2 100644 --- a/src/components/comment/Comment.astro +++ b/src/components/comment/Comment.astro @@ -4,15 +4,14 @@ */ import CommentItem from '@/components/comment/CommentItem.astro'; import { parseComments } from '@/components/comment/artalk'; -import type { CommentConfig, Comments } from '@/components/comment/types'; +import type { Comments } from '@/components/comment/types'; interface Props { comments: Comments; - config: CommentConfig; } -const { comments, config } = Astro.props; +const { comments } = Astro.props; const parsedComments = await parseComments(comments.comments); --- -{parsedComments.map((item) => )} +{parsedComments.map((item) => )} diff --git a/src/components/comment/CommentItem.astro b/src/components/comment/CommentItem.astro index adb332a..e2635e3 100644 --- a/src/components/comment/CommentItem.astro +++ b/src/components/comment/CommentItem.astro @@ -1,16 +1,15 @@ --- -import type { CommentConfig, CommentItem } from '@/components/comment/types'; +import type { CommentItem } from '@/components/comment/types'; import { formatLocalDate } from '@/helpers/formatter'; import { urlJoin } from '@/helpers/tools'; interface Props { depth: number; comment: CommentItem; - config: CommentConfig; pending?: false; } -const { comment, config, depth, pending } = Astro.props; +const { comment, depth, pending } = Astro.props; ---
  • @@ -18,7 +17,7 @@ const { comment, config, depth, pending } = Astro.props;
    {comment.nick} {comment.children.map((childComment) => ( - + ))} ) @@ -62,7 +61,7 @@ const { comment, config, depth, pending } = Astro.props; comment.children && depth !== 1 && ( <> {comment.children.map((childComment) => ( - + ))} ) diff --git a/src/components/comment/Comments.astro b/src/components/comment/Comments.astro index f86ae37..a2d1b6c 100644 --- a/src/components/comment/Comments.astro +++ b/src/components/comment/Comments.astro @@ -1,5 +1,5 @@ --- -import { commentConfig, loadComments } from '@/components/comment/artalk'; +import { loadComments } from '@/components/comment/artalk'; import Comment from '@/components/comment/Comment.astro'; import { urlJoin } from '@/helpers/tools'; import options from '@/options'; @@ -11,13 +11,12 @@ interface Props { } const { commentKey, title } = Astro.props; -const config = await commentConfig(); -const comments = config != null ? await loadComments(commentKey, title, 0, config) : null; +const comments = await loadComments(commentKey, title, 0); ---
    { - comments != null && config != null ? ( + comments != null ? ( <>
    评论 ({comments.count}) @@ -60,15 +59,15 @@ const comments = config != null ? await loadComments(commentKey, title, 0, confi
      - +
    - {comments.roots_count > config.frontend_conf.pagination.pageSize && ( + {comments.roots_count > options.settings.comments.size && (