Compare commits

...
151 Commits
Author SHA1 Message Date
qwqcode 116d8f1919 chore(ci): fix build workflow 2024-04-25 00:01:51 +08:00
github-actions[bot]andqwqcode 99b71a15f8 chore: release v2.8.5 (#844)
* chore: release v2.8.5

* Update CHANGELOG.md

---------

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: qwqcode <22412567+qwqcode@users.noreply.github.com>
2024-04-24 23:19:18 +08:00
qwqcode 3255cb4b66 chore(deps): upgrade go deps 2024-04-24 23:11:29 +08:00
qwqcode 35d5f778b2 fix(transfer): retrieve root_id for imported comment data 2024-04-24 23:04:10 +08:00
qwqcode 9375ef812a fix(dao): prevent potential infinite loop in FindCommentRootID 2024-04-24 23:04:10 +08:00
qwqcode 44742c149e fix(db/migrate): issue with root id generation 2024-04-24 23:04:09 +08:00
qwqcode a4d5135379 perf(i18n): add translation for 'parameter is required' 2024-04-24 23:04:09 +08:00
qwqcode ddfaa603ca feat(conf/http): add http.proxy_header config option 2024-04-24 23:03:58 +08:00
qwqcode 6e13152fc1 fix(upload): add config option to solve request entity too large issue (#834) 2024-04-18 18:30:51 +08:00
qwqcode 0b16c9627a fix(ui/upload): unable to upload image when file extension is uppercase 2024-04-18 18:25:25 +08:00
qwqcode b613a4368c fix(log): improve log system and fix memory leaks (#843) 2024-04-18 18:25:19 +08:00
qwqcode 3098a75a05 perf(ui/version_check): beautify version upgrade notice 2024-04-15 15:05:42 +08:00
qwqcode d71ac6d156 chore(docs): update daemon.md 2024-04-15 14:42:13 +08:00
qwqcode 6c9a7e3884 chore(deps): upgrade go deps 2024-04-15 14:38:03 +08:00
qwqcode 65b440416d chore(ci): release workflow allows manual custom version 2024-04-15 14:32:36 +08:00
qwqcode f9084cbfb4 chore(changelog): skip v2.8.4 2024-04-15 14:32:36 +08:00
qwqcode 3c7ad1d0ef fix(ui/sidebar): user list not refresh when data is modified 2024-04-15 14:32:31 +08:00
qwqcode 1930d842f2 fix(ui/comment): missing reply comment data when inserting (#838) 2024-04-15 13:55:51 +08:00
qwqcode 751e4a866f fix(ui/comment): incorrect reply comment data in nested mode (#771) (#837) 2024-04-15 13:09:20 +08:00
Big_Cake 01364d1ddc docs(extras): add deploy guide for Valaxy (#836) 2024-04-15 12:20:09 +08:00
qwqcode ec6d2b2e60 fix(db/migrator): remove foreign key constraints and better root_id generation (#835)
Add function to delete all foreign key constraints when migration.

Leave relationship maintenance to the program and reduce the difficulty of database management. Because there are many different DBs and the implementation of foreign keys may be different, and the DB may not support foreign keys, so don't rely on the foreign key function of the DB system.
2024-04-14 23:46:22 +08:00
qwqcode 915b5f48b4 refactor(ui/prettier): add prettier code formatter 2024-04-14 23:42:06 +08:00
Mr.Hopeandqwqcode 16527ec4f3 perf(ui/pkg): add shorter export names (#821)
* feat(artalk): add shorter export names

* chore: tweaks

* chore: mute attw

---------

Co-authored-by: qwqcode <qwqcode@gmail.com>
2024-04-08 14:51:32 +08:00
Mr.Hope a7af2b7aaa chore(ui/deps): update deps for ui (#820) 2024-04-08 14:42:24 +08:00
github-actions[bot] 3ff891be90 chore: release v2.8.4 (#818)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2024-04-07 21:51:42 +08:00
dependabot[bot] 7d6faf6431 chore(deps/ci): bump the deps group in /.github/workflows with 4 updates (#784)
Bumps the deps group in /.github/workflows with 4 updates: [pnpm/action-setup](https://github.com/pnpm/action-setup), [github/codeql-action](https://github.com/github/codeql-action), [peter-evans/create-pull-request](https://github.com/peter-evans/create-pull-request) and [peter-evans/repository-dispatch](https://github.com/peter-evans/repository-dispatch).


Updates `pnpm/action-setup` from 2 to 3
- [Release notes](https://github.com/pnpm/action-setup/releases)
- [Commits](https://github.com/pnpm/action-setup/compare/v2...v3)

Updates `github/codeql-action` from 2 to 3
- [Release notes](https://github.com/github/codeql-action/releases)
- [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md)
- [Commits](https://github.com/github/codeql-action/compare/v2...v3)

Updates `peter-evans/create-pull-request` from 5 to 6
- [Release notes](https://github.com/peter-evans/create-pull-request/releases)
- [Commits](https://github.com/peter-evans/create-pull-request/compare/v5...v6)

Updates `peter-evans/repository-dispatch` from 2 to 3
- [Release notes](https://github.com/peter-evans/repository-dispatch/releases)
- [Commits](https://github.com/peter-evans/repository-dispatch/compare/v2...v3)

---
updated-dependencies:
- dependency-name: pnpm/action-setup
  dependency-type: direct:production
  update-type: version-update:semver-major
  dependency-group: deps
- dependency-name: github/codeql-action
  dependency-type: direct:production
  update-type: version-update:semver-major
  dependency-group: deps
- dependency-name: peter-evans/create-pull-request
  dependency-type: direct:production
  update-type: version-update:semver-major
  dependency-group: deps
- dependency-name: peter-evans/repository-dispatch
  dependency-type: direct:production
  update-type: version-update:semver-major
  dependency-group: deps
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-04-07 21:47:42 +08:00
qwqcode 73d8ea97ed perf(conf/upgit): disallow custom executable path of upgit for security (#817)
BREAKING CHANGE: For UpGit users: Due to security reasons, Artalk no longer allows configuring the executable file path (img_upload.upgit.exec) for upgit. Please add it to system environment variables instead.
2024-04-07 21:43:44 +08:00
qwqcode c482e19f19 chore(sidebar): fix build type issue when upgrade deps
https://github.com/posva/unplugin-vue-router/issues/353
2024-04-07 20:10:19 +08:00
qwqcode 8c3042cdb1 chore(ui/deps): bump deps for ui 2024-04-07 19:57:03 +08:00
qwqcode ed9a78472d chore(ui/dev): bump node to v20.12.1 2024-04-07 19:49:39 +08:00
qwqcode ae5543df52 feat(go): upgrade golang to v1.22.1 and some deps 2024-04-07 19:29:47 +08:00
qwqcode c2c5a80d8d refactor(comments_get): reduce api complexity by introducing LiteDB (#800)
* refactor(comments_get): reduce interface complexity by introducing LiteDB

* test: add unit test

* add more unit test case
2024-04-07 19:17:01 +08:00
Otstar Lin de5e1b4000 fix(ui/lifecycle): keep root element during destroy (#810) 2024-04-02 22:29:08 +08:00
qwqcode b60cb585b6 perf(db): optimize N+1 query in comment list (#799) 2024-03-17 21:01:42 +08:00
qwqcode 44bca8d2f4 fix(cmd/gen): ensure directory before saving in gen cmd (#612) 2024-03-16 16:07:20 +08:00
qwqcode 9103a923a6 chore(ci/nightly): build arm64 on M1 macOS runner
https://github.blog/changelog/2024-01-30-github-actions-introducing-the-new-m1-macos-runner-available-to-open-source/
https://docs.docker.com/build/ci/github-actions/multi-platform/#distribute-build-across-multiple-runners
2024-03-16 15:23:53 +08:00
thun888 e4242512f8 chore(docs): update case link (#793)
* Update cases.md

* Update extras.md
2024-03-16 01:37:47 +08:00
zarev 0ebd16a5db docs(i18n): add French translation (#797) 2024-03-16 01:24:13 +08:00
qwqcode 0eb75f612a chore(ci/nightly): build arm64 on M1 macOS runner
https://github.blog/changelog/2024-01-30-github-actions-introducing-the-new-m1-macos-runner-available-to-open-source/
https://docs.docker.com/build/ci/github-actions/multi-platform/#distribute-build-across-multiple-runners
2024-03-16 01:12:39 +08:00
qwqcode 18e6ae5b17 chore(ci/nightly): improve nightly build workflow 2024-03-15 17:57:17 +08:00
qwqcode 1ee3c41199 feat(ci/build): add nightly build workflow 2024-03-15 12:54:19 +08:00
github-actions[bot] 8af713636c chore: release v2.8.3 (#788)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2024-03-04 22:13:11 +08:00
qwqcode 5bf6e5f1dc fix(exception): missing message field after refactoring exception data structure 2024-03-04 21:04:38 +08:00
qwqcode 929faf0722 fix(sidebar/login): cannot select a name with the same email upon login (#781) 2024-03-04 21:01:04 +08:00
qwqcode 5322f90383 fix(captcha/image): unable to display image captcha on initial load 2024-03-04 20:56:31 +08:00
qwqcode fa3575cbae fix(conf): skip patching IP region conf if disabled 2024-03-04 20:05:20 +08:00
qwqcode c94a34ffd7 feat(comment): add is_verified field for comment entity 2024-02-16 19:43:35 +08:00
qwqcode 50b49448b6 feat(app): add onConfUpdated hook 2024-02-15 23:02:33 +08:00
qwqcode 8ff3f5e875 refactor(dao): validate the args of the FindCreateUser function 2024-02-14 00:21:48 +08:00
qwqcode 640fa7ded4 feat(ui/plugins): support dynamic loading of ui plug-in scripts (#774) 2024-02-12 21:12:55 +08:00
qwqcode 18123f7002 refactor(origin): extract CheckURLTrusted function 2024-02-12 20:36:43 +08:00
qwqcode cf2094667d feat(api/domain): add GET /conf/domain endpoint 2024-02-11 23:47:04 +08:00
qwqcode 2cd2165f06 refactor(entity/user): extract CheckPassword function 2024-02-11 23:36:19 +08:00
qwqcode 4eada4b628 feat(api/auth): invalidate old auth tokens after changing password 2024-02-11 23:34:32 +08:00
qwqcode 05f3ad043a feat(ui/editor): add beforeSubmit hook for editor submitting 2024-02-11 23:11:04 +08:00
qwqcode 6e9083e75d feat(ui/api): add ctx.getApiHandlers() to handle error responses and expose hooks 2024-02-11 23:00:22 +08:00
qwqcode 7bbdb5900f fix(ui/layer): ensure immediate operation when calling show() after hide() 2024-02-11 22:36:18 +08:00
qwqcode 5be45315dc chore(style/icon): standardized icon css styles 2024-02-09 16:59:58 +08:00
qwqcode 5d20ff1ef5 chore(fiber_logger): correct the http status code range for err log 2024-02-06 16:03:04 +08:00
qwqcode 86e0eeafd1 perf(ui/editor): improve the icon details for editor 2024-02-05 21:49:04 +08:00
github-actions[bot] 49c1a87a67 chore: release v2.8.2 (#769)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2024-02-05 19:09:15 +08:00
qwqcode ec7f81cb83 chore(docs): import artalk css via node 2024-02-05 19:01:39 +08:00
qwqcode 4b115d7b6a perf(ui/editor): optimize editor styles for narrow-width screens 2024-02-05 17:19:53 +08:00
qwqcode 1bae6d8d2a perf(ui/editor): modify editor plug-in text buttons to icons for brevity 2024-02-05 17:19:53 +08:00
qwqcode bdafa19470 perf(ui/editor): place Cancel Reply at the bottom of editor area (#644) 2024-02-05 17:19:40 +08:00
qwqcode 342236b6a7 perf(ui/lite): disable ArtalkLite preview config option by default 2024-02-05 17:05:00 +08:00
qwqcode ffce9f9e85 fix(style): replace style break-all with break-word in content el (#644) 2024-02-05 15:05:58 +08:00
qwqcode 0097e041b1 fix(api/comments): ua field is optional and not required (#767) 2024-02-05 14:30:17 +08:00
github-actions[bot] 42da621dfc chore: release v2.8.1 (#766)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2024-02-04 22:21:43 +08:00
qwqcode 2f5dbaa022 chore(i18n): update zh-CN 2024-02-04 22:02:13 +08:00
qwqcode e181a6d5dd perf(style/sidebar): improve some detail in sidebar 2024-02-04 21:55:59 +08:00
qwqcode 7873b21fb7 fix(ui/scroll): scroll into view issue when relativeTo parameter is provided 2024-02-04 21:53:02 +08:00
qwqcode 2a219518a4 feat(ui/goto): improved solution of navigating to comment via link hash (#693) (#765) 2024-02-04 21:47:06 +08:00
qwqcode afa7888db0 chore(typo): fix comment typo 2024-02-04 20:26:34 +08:00
qwqcode f6a589d5b2 refactor(ui/list): refactor the list layout manager 2024-02-04 20:25:21 +08:00
qwqcode 41a09d5996 refactor(ui/comment): loose coupling between Comment and Context 2024-02-04 20:15:28 +08:00
qwqcode 191977c0df feat(api): add GET /comments/:id endpoint (#764) 2024-02-04 20:08:38 +08:00
qwqcode 5a4c06daee chore(ip_region): skip empty string 2024-02-04 19:48:26 +08:00
qwqcode c4942ab807 chore(Makefile): add http-client build cmd to update-swagger 2024-02-04 03:24:58 +08:00
qwqcode 6b83a9f632 chore(transfer): remove the url_resolver disabled warning msg 2024-02-04 02:25:33 +08:00
qwqcode 3c88c0c29c docs: supplement and refine fe-api.md 2024-02-04 02:22:49 +08:00
qwqcode 35aab6bedc fix(ui/list): unable to reply or delete comments after switching pagination 2024-02-04 01:40:07 +08:00
qwqcode 17033dc111 fix(ui/no_comment): always appears when creating comment 2024-02-03 23:45:48 +08:00
qwqcode 559df60f0d fix(ui/pv): missing pageTitle field in the PV request 2024-02-03 23:12:12 +08:00
qwqcode 22d4ec1c31 chore(docs): rename IP region in zh-CN 2024-02-03 21:44:37 +08:00
qwqcode d97ad5c843 fix(ip_region): unable to output the IP region correctly (#760) 2024-02-03 21:43:42 +08:00
qwqcode 34a67f647b chore(docs): update cdn source links 2024-02-03 19:58:38 +08:00
qwqcode 9c3228b8fc feat(config): add db.prepare_stmt config option (#760) (#762)
The Prepared Statement database feature is enabled by default. You can disable it in config file or a env variable `ATK_DB_PREPARE__STMT=0`.
2024-02-03 19:19:00 +08:00
qwqcode 4012d3e090 fix(cmd/admin): update user role to admin if already exists 2024-02-03 16:54:13 +08:00
qwqcode bc1c4d315c fix(api/comments): counting comments issue in PostgreSQL db (#760) (#761) 2024-02-03 15:34:25 +08:00
qwqcode 2a6f0c56a4 chore(docs): fix script cdn links 2024-02-01 21:43:52 +08:00
github-actions[bot] 46e2a15116 chore: release v2.8.0 (#756)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2024-02-01 00:19:18 +08:00
qwqcode c068f5a240 chore(deps): bump golang deps 2024-02-01 00:11:34 +08:00
qwqcode 29bf49958f perf(ui/pagination): replace the prev/next text on pagination buttons with icons (#743) 2024-01-31 23:59:58 +08:00
qwqcode 2fcad539ca perf(ui/i18n): refine some translation (#743) 2024-01-31 23:28:56 +08:00
qwqcode 45b79124c9 chore(ui/deps): bump deps for ui 2024-01-31 20:27:14 +08:00
qwqcode 2b44452234 refactor(ui): optimize init and update lifecycle events 2024-01-31 19:44:40 +08:00
qwqcode 0e0b53fe9e perf(ui/sidebar): prevent potential token leakage by clearing query in iframe url
The previous referrer policy was already set to `strict-origin`, but to further enhance security, this modification was made.
2024-01-30 23:07:37 +08:00
qwqcode dba5ba5277 fix(ui/no_comment): flickering when clearing list before fetch 2024-01-30 22:24:53 +08:00
qwqcode 942aaf654f fix(ui/sidebar): incorrectly increasing pv count in sidebar (#724) 2024-01-30 20:27:19 +08:00
qwqcode 37e0091502 perf(ui/conf): support for watching partial changes in config with watchConf() (#755) 2024-01-30 19:14:09 +08:00
qwqcode a7c3f1bbda feat(notify): add notify_pending config option (#728) (#754) 2024-01-29 21:22:36 +08:00
qwqcode a40a070bdb chore(fix/pin): fix pinned comment sort rule 2024-01-29 14:46:19 +08:00
Frost Ming 082bfc63d1 fix(ui/editor): prevent propagation of click event in editor (#734)
Signed-off-by: Frost Ming <me@frostming.com>
2024-01-29 14:12:21 +08:00
qwqcode 0de8009e65 feat(ui/admin): add logout button in admin panel (#488) (#753)
fixes #488
2024-01-29 13:56:02 +08:00
qwqcode a5e4c81e72 fix(ui/sidebar_layer): sidebar still displays when login is required 2024-01-29 13:34:51 +08:00
qwqcode c52c26145c fix(ui/layer): unexpected behavior with multiple items when closing 2024-01-29 00:47:50 +08:00
qwqcode f5e310a182 chore(ui/ctx): remove token public in context 2024-01-28 22:14:24 +08:00
qwqcode 0828b91602 refactor(ui/comment): rename class Comment to CommentNode 2024-01-28 22:13:20 +08:00
qwqcode c4f664e412 refactor(ui/ctx): add getComments and getCommentNodes in context (#752)
* refactor(ui/ctx): add `getComments` and `getCommentNodes` func in context

* fix import
2024-01-28 22:03:15 +08:00
qwqcode a084c50095 refactor(transfer): normalize transfer payload parameter name 2024-01-28 13:33:03 +08:00
qwqcode 9dacd0954d fix(cache): unable to change admin list after caching (#748) (#750) 2024-01-26 22:27:10 +08:00
qwqcode 50b0a6068c chore(ci): fix ui test trigger rules 2024-01-26 17:16:18 +08:00
qwqcode 4689492bf5 fix(ui/pagination): auto load list when scroll reaches bottom 2024-01-26 17:09:56 +08:00
qwqcode 6ee9ee9ea4 fix(ui/lite): correct the instance name for compiling ArtalkLite (#740) 2024-01-26 11:45:22 +08:00
qwqcode 8e3a743ed8 fix(i18n): sidebar language cannot be changed
Also follow 0d35e66
2024-01-26 11:42:39 +08:00
qwqcode 9550a16a0c chore(fetch): returns empty object when json deserialize failed 2024-01-25 01:07:48 +08:00
qwqcode a9edac3ce0 refactor(api): update swagger file of API v2
BREAKING CHANGE: For Developers: The HTTP API has now been updated to version v2, with a lot of adjustments made, such as changing to Restful API style, request type, request body, response body, etc. data structure, adding error response codes. You can refer to #735 or https://artalk.js.org/http-api Please update all your existing clients to adapt to the new v2 server. The new base path is `/api/v2/`. The UI package's HTTP client has been implemented to auto-generate based on `Swagger.json`, and there have been a lot of adjustments to the `artalk.ctx.getApi()` related code. In addition, the HTTP API no longer enforces checks on the header's `Origin` and `Referer` (to implement strict isolation of different sites) but still maintains the original CORS origin check.

For General Users: Now all administrators have the same level of authority (there is no longer super admin authority), the function of assigning sub-administrators with independent scope authority to individual sites has been removed, which can simplify the HTTP server maintenance and implementation. Upgrading only requires updating the client and server application at the same time, and there are no additional operations.
2024-01-24 21:53:34 +08:00
qwqcode 589850d311 refactor(api): refactor HTTP API to version 2 (#735)
* refactor(api): refactor HTTP API to version 2

* refactor: remove forced site_origin check

* refactor: update http client

* fix

* add more api description and error code

* reduce nestings in response structures

* separate unread

* refactor(api/comments): get comments

* refactor: frontend api module

* chore: remove vite temporary file

* chore: restore swagger file

* update

* 移除为管理员分配站点名的站点隔离功能,简化实现

* refactor pagesAllFetch

* fix ci

* remove useless codes

* limiter protected paths

* add test for version endpoint

* rename handler code files

* code file separate

* fix some bug of interacting with backend

* add fetch error class for handling

* fix and rename

* refactor: checker support both `Promise` and callback fn

* fix new checker captcha iframe url

* rename and add swagger id field

* replace tab with spaces in go comment

* chore: refine

* complete the validate tag for request fields and enable `--defaultRequired`

90% of the request fields of our API are required,100% of response fields in our API are required.
Each field add validate:"required" is easy to miss.

* replace original api client with auto-generated codes

* artalk pkg apply new api client

* artalk-sidebar pkg apply new api client

* fix issues

* fix sidebar locale conf and refactor user login

* fix and refactor captcha and limiter

* fix ui testing

* add script to build http client by swagger.json
2024-01-24 21:33:30 +08:00
qwqcode 9ba9439831 chore(typo): fix typo for login in zh 2024-01-24 21:14:50 +08:00
qwqcode 38f6b6996a docs: update multi-sites manual (#747) 2024-01-24 21:01:56 +08:00
qwqcode 1e16570b2f chore(ci): fix ui test trigger rules 2024-01-24 16:24:36 +08:00
qwqcode 889adc6bae chore(docs): update security.md 2023-12-31 23:46:34 +08:00
qwqcode 0de59911b3 chore(docs): fix broken links 2023-12-29 12:40:04 +08:00
qwqcode f22e557b1c feat(go): upgrade golang to v1.21.5 and some deps 2023-12-28 23:26:56 +08:00
qwqcode 92ff757efc chore: fix docker build ci workflow 2023-12-28 21:43:17 +08:00
github-actions[bot]andqwqcode 63165599ce chore: release v2.7.3 (#726)
* chore: release v2.7.3

---------

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: qwqcode <22412567+qwqcode@users.noreply.github.com>
2023-12-28 17:06:57 +08:00
qwqcode a5b428d1ec refactor(test/ui): add more ui api tests 2023-12-28 16:56:00 +08:00
qwqcode cf3f9b1ac3 chore: patch pacakge.json for i18n exports 2023-12-28 15:43:30 +08:00
qwqcode c212d67f49 perf(ui/build): better dts generation (#689)
* chore: move types as a subfolder of src

* perf(ui/build): better dts generation

* chore: update pnpm-lock.yaml

* chore: fix env variable on windows

* fix i18n types
2023-12-28 15:25:01 +08:00
qwqcode b00a257699 docs: update ui api documentation 2023-12-26 22:18:43 +08:00
3698c0c593 refactor(ui/conf): better handling of mutable config (#722)
* fix(ui): mergeDeep causes some configurations to be overridden by the default configuration

* fix: config always get override by defaults

Signed-off-by: Frost Ming <me@frostming.com>

* refactor(ui/conf): better handling of mutable config

* chore: fix path issue on win env

* fix: mergeDeep avoid prototype pollution

BREAKING CHANGE: Directly referencing `artalk.conf` and `artalk.$root` is deprecated. Please use functions instead: `artalk.getConf()` and `artalk.getEl()`.

---------

Signed-off-by: Frost Ming <me@frostming.com>
Co-authored-by: syfxlin <i@ixk.me>
Co-authored-by: Frost Ming <me@frostming.com>
2023-12-26 22:13:37 +08:00
qwqcode 32a398609c chore(tsconfig): modify moduleResolution to bundler 2023-12-26 00:30:50 +08:00
qwqcode 54729fbafc chore(build): use vite internal mergeConfig func 2023-12-26 00:06:21 +08:00
qwqcode b74e5cf94c refactor(ui/test): add vitest for unit testing 2023-12-26 00:03:08 +08:00
Frost Ming 475dd933fe fix(ui/init): stack overflow when merging with config defaults (#717)
Close #716
2023-12-23 21:40:18 +08:00
qwqcode 60e0e7e61a chore(ci): fixed tag version for git checkout branch 2023-12-23 01:32:19 +08:00
qwqcode e4a42d3a90 refactor(docker): add --build-arg argument to skip ui build 2023-12-22 23:54:32 +08:00
qwqcode d86cd73ea6 refactor(ci): better release workflow 2023-12-22 22:06:09 +08:00
qwqcode 67280f2ca2 feat(ci): add dry-run mode for build workflow 2023-12-22 02:30:54 +08:00
qwqcode a8bcd41f36 refactor(ui): refactor directory structure (#712)
* refactor(ui): refactor directory structure

* update config files

* update github workflows

* update vscode settings.json

* update docs

* update build scripts

* tidy up

* fix docs build
2023-12-21 23:51:26 +08:00
qwqcode 04cf137a74 feat(cmd): support cli flag for creating admin account 2023-12-21 22:35:10 +08:00
qwqcode d542e98581 chore(eslint): fix sidebar eslint configuration 2023-12-21 22:28:24 +08:00
qwqcode dfaf95bf1d chore(docs): bump Artalk to v2.7.2 2023-12-21 01:51:36 +08:00
github-actions[bot] 0a89426c93 chore: release v2.7.2 2023-12-20 17:20:40 +00:00
qwqcode 7a026ef0e2 fix(sidebar): sidebar language switch and config save issue (#708) 2023-12-21 01:14:49 +08:00
qwqcode 855f6c261f docs(i18n): add translation for open button 2023-12-20 23:35:58 +08:00
qwqcode 7099598a92 fix(ui): add referrerpolicy attribute for iframe (#687) (#707) 2023-12-20 23:34:46 +08:00
qwqcode ad8851ea94 fix(ui/pagination): auto switch page by url hashtag issue (#693) 2023-12-20 21:44:06 +08:00
qwqcode def9dc2707 fix(ui/sidebar): refactor settings and fix save issue (#677) (#706) 2023-12-20 20:53:04 +08:00
Mr.Hopeandqwqcode 91228a9446 docs(refactor): organize the pkgs and fix some issues (#702)
* docs: rebuild docs

* chore: fix eslint

* ci: add docs build test

* update test-docs.yml

* fix script

* add netlify.toml

* fix docs:patch

---------

Co-authored-by: qwqcode <qwqcode@gmail.com>
2023-12-19 21:55:04 +08:00
634 changed files with 35122 additions and 30204 deletions

No files matched your search

+38 -38
View File
@@ -1,7 +1,7 @@
version: 2.1
orbs:
node: circleci/node@5.0.3
node: circleci/node@5.2.0
codecov: codecov/codecov@3.3.0
executors:
@@ -10,10 +10,10 @@ executors:
- image: cimg/base:stable
node:
docker:
- image: 'cimg/node:18.19.0'
- image: "cimg/node:20.12.1"
go:
docker:
- image: cimg/go:1.21.3
- image: cimg/go:1.22.2
parameters:
trigger-app:
@@ -26,43 +26,43 @@ parameters:
jobs:
## Backend
test_app:
executor: go
working_directory: ~/go/src/github.com/ArtalkJS/Artalk
environment:
GO111MODULE: "on"
steps:
- checkout
- run:
name: "Print the Go version"
command: >
go version
- restore_cache:
keys:
- go-mod-1.21.3-{{ checksum "go.sum" }}
- run:
name: Install Dependencies
command: go mod download
- save_cache:
key: go-mod-1.21.3-{{ checksum "go.sum" }}
paths:
- "~/go/pkg/mod"
- run:
name: Run tests
command: |
mkdir -p /tmp/test-reports
gotestsum --junitfile /tmp/test-reports/unit-tests.xml -- -coverprofile=/tmp/test-reports/coverage.out ./...
- store_test_results:
path: /tmp/test-reports
- codecov/upload:
flags: go
file: /tmp/test-reports/coverage.out
executor: go
working_directory: ~/go/src/github.com/ArtalkJS/Artalk
environment:
GO111MODULE: "on"
steps:
- checkout
- run:
name: "Print the Go version"
command: >
go version
- restore_cache:
keys:
- go-mod-1.22.2-{{ checksum "go.sum" }}
- run:
name: Install Dependencies
command: go mod download
- save_cache:
key: go-mod-1.22.2-{{ checksum "go.sum" }}
paths:
- "~/go/pkg/mod"
- run:
name: Run tests
command: |
mkdir -p /tmp/test-reports
gotestsum --junitfile /tmp/test-reports/unit-tests.xml -- -coverprofile=/tmp/test-reports/coverage.out ./...
- store_test_results:
path: /tmp/test-reports
- codecov/upload:
flags: go
file: /tmp/test-reports/coverage.out
all_projects:
executor: base
steps:
- run:
command: |
echo "all"
executor: base
steps:
- run:
command: |
echo "all"
workflows:
build-app:
+3 -1
View File
@@ -17,9 +17,11 @@ workflows:
mapping: |
(cmd|internal|server|pkg|test|conf)/.* trigger-app true
main.go|go.mod|go.sum trigger-app true
base-revision: master # git branch name
base-revision: master # git branch name
config-path: .circleci/conditional_config.yml
filters:
branches:
ignore:
- gh-pages
- /release\/.+/
- nightly
+1
View File
@@ -0,0 +1 @@
node_modules
+1 -1
View File
@@ -8,7 +8,7 @@ coverage
vite*.config*
# ignore all js files
**/*.js
**/*.*js
# ignore all config files
*.config.ts
+2 -4
View File
@@ -5,7 +5,7 @@ module.exports = {
parser: '@typescript-eslint/parser',
env: { browser: true },
parserOptions: {
project: ['./packages/*/tsconfig.json'],
project: ['./ui/*/tsconfig.json'],
tsconfigRootDir: __dirname,
},
extends: [
@@ -40,9 +40,7 @@ module.exports = {
settings: {
'import/resolver': {
typescript: {
project: ['packages/artalk/tsconfig.json'].map((p) =>
path.resolve(__dirname, p),
),
project: ['ui/artalk/tsconfig.json'].map((p) => path.resolve(__dirname, p)),
},
},
polyfills: ['AbortController'],
+25
View File
@@ -0,0 +1,25 @@
name: Comment issue
description: Create comment on a issue
inputs:
issue_number:
required: true
description: The issue number you want to comment
content:
required: true
description: The content of comment
runs:
using: "composite"
steps:
- uses: actions/github-script@v7
env:
STDOUT: ${{ inputs.content }}
with:
script: |
github.rest.issues.createComment({
issue_number: ${{ inputs.issue_number }},
owner: context.repo.owner,
repo: context.repo.repo,
body: process.env.STDOUT
})
+2 -2
View File
@@ -4,8 +4,8 @@ info:
title: CHANGELOG
repository_url: https://github.com/ArtalkJS/Artalk
options:
tag_filter_pattern: '^v'
sort: "date"
tag_filter_pattern: "^v"
sort: date
commits:
filters:
Type:
+4 -4
View File
@@ -14,7 +14,7 @@ updates:
groups:
deps:
patterns:
- '*'
- "*"
open-pull-requests-limit: 15
- package-ecosystem: npm
@@ -39,7 +39,7 @@ updates:
groups:
deps:
patterns:
- '*'
- "*"
open-pull-requests-limit: 15
- package-ecosystem: docker
@@ -51,7 +51,7 @@ updates:
groups:
deps:
patterns:
- '*'
- "*"
open-pull-requests-limit: 15
- package-ecosystem: github-actions
@@ -63,5 +63,5 @@ updates:
groups:
deps:
patterns:
- '*'
- "*"
open-pull-requests-limit: 15
+24 -22
View File
@@ -1,13 +1,18 @@
name: Build App
run-name: Build Go App and Publish
on:
repository_dispatch:
types: [artalk-release]
workflow_call:
inputs:
version:
required: true
type: string
dry_run:
required: true
type: boolean
env:
GO_VERSION: '1.21.3'
PKG_NAME: 'github.com/ArtalkJS/Artalk'
GO_VERSION: 1.22.2
PKG_NAME: github.com/ArtalkJS/Artalk
DOCKER_IMG: ghcr.io/goreleaser/goreleaser-cross
CACHE_DIR: /tmp/cache/docker-image
@@ -17,18 +22,12 @@ jobs:
steps:
- name: Checkout Code
uses: actions/checkout@v3
- name: Checkout latest tag
run: |
# fetch tags
git fetch --prune --unshallow --tags -f
# checkout latest version
VERSION=$(git describe --tags --abbrev=0)
git checkout ${VERSION}
echo "VERSION=${VERSION}" >> $GITHUB_ENV
uses: actions/checkout@v4
with:
ref: ${{ inputs.version }}
# `go-releaser` will read the semver version from git tag name
# `git-chglog` will diff the tag and generate changelog
fetch-depth: 0
# disable cache because the err `no space left on device`
# - name: Docker Image Cache
@@ -52,9 +51,9 @@ jobs:
- name: Setup git-chglog
run: |
curl -sL $(curl -s https://api.github.com/repos/git-chglog/git-chglog/releases/latest \
| grep -oP '"https://.+linux_amd64.tar.gz"' | tr -d \") | tar -C /usr/local/bin -xz git-chglog
git-chglog --version
curl -sL $(curl -s https://api.github.com/repos/git-chglog/git-chglog/releases/latest \
| grep -oP '"https://.+linux_amd64.tar.gz"' | tr -d \") | tar -C /usr/local/bin -xz git-chglog
git-chglog --version
- name: Pre Build
run: |-
@@ -64,11 +63,14 @@ jobs:
echo "GITHUB_TOKEN=${{ secrets.GITHUB_TOKEN }}" > local/.release-env
# changelog
git-chglog --config .github/chglog/config.yml ${VERSION} > local/release-notes.md
git-chglog --config .github/chglog/config.yml ${{ inputs.version }} > local/release-notes.md
# copy config file
cp conf/artalk.example.yml artalk.yml
- name: Print Relase Notes
run: cat local/release-notes.md
- name: Build and Release
run: |
docker run \
@@ -81,4 +83,4 @@ jobs:
-e CGO_ENABLED=1 \
--env-file local/.release-env \
ghcr.io/goreleaser/goreleaser-cross:v${GO_VERSION} \
release --release-notes local/release-notes.md
release --release-notes local/release-notes.md ${{ inputs.dry_run && '--skip=publish' || '' }}
+45 -73
View File
@@ -1,9 +1,17 @@
name: Build Docker
run-name: Build Docker Image and Publish
on:
repository_dispatch:
types: [artalk-release]
workflow_call:
inputs:
version:
required: true
type: string
dry_run:
required: true
type: boolean
target:
required: true
type: string
env:
DOCKER_IMG: artalk/artalk-go
@@ -14,58 +22,14 @@ jobs:
steps:
- name: Checkout Code
uses: actions/checkout@v3
- name: Checkout latest tag
run: |
# fetch tags
git fetch --prune --unshallow --tags -f
# checkout latest version
VERSION=$(git describe --tags --abbrev=0)
git checkout ${VERSION}
VERSION_SHORT="$(cut -d '.' -f 1,2 <<< ${VERSION#v})" # (i.e "v1.2.3" -> "1.2")
COMMIT_HASH="$(git rev-parse --short HEAD)"
COMMIT_HASH_FULL="$(git rev-parse HEAD)"
echo "VERSION=${VERSION}" >> $GITHUB_ENV
echo "VERSION_SHORT=${VERSION_SHORT}" >> $GITHUB_ENV
echo "COMMIT_HASH=${COMMIT_HASH}" >> $GITHUB_ENV
echo "COMMIT_HASH_FULL=${COMMIT_HASH_FULL}" >> $GITHUB_ENV
# https://github.com/docker/login-action
- name: Login to DockerHub
if: github.event_name != 'pull_request'
uses: docker/login-action@v2
uses: actions/checkout@v4
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
# https://github.com/docker/setup-qemu-action
- name: Setup QEMU
id: qemu
uses: docker/setup-qemu-action@v2
with:
platforms: 'amd64,arm64'
# https://github.com/docker/setup-buildx-action
- name: Setup Docker Buildx
id: buildx
uses: docker/setup-buildx-action@v2
- name: Cache Docker layers
uses: actions/cache@v3
with:
path: /tmp/.buildx-cache
key: ${{ runner.os }}-buildx-${{ github.sha }}
restore-keys: |
${{ runner.os }}-buildx-
ref: ${{ inputs.version }}
# https://github.com/docker/metadata-action
- name: Gen docker meta
id: meta
uses: docker/metadata-action@v4
uses: docker/metadata-action@v5
with:
context: git
images: |
@@ -77,34 +41,42 @@ jobs:
type=semver,pattern={{major}}.{{minor}}
type=sha
# https://github.com/docker/login-action
- name: Login to DockerHub
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
# https://github.com/docker/setup-qemu-action
- name: Setup QEMU
uses: docker/setup-qemu-action@v3
with:
platforms: ${{ inputs.target }}
# https://github.com/docker/setup-buildx-action
- name: Setup Docker Buildx
uses: docker/setup-buildx-action@v3
# Build UI outside of Docker to speed up cross-platform builds
- name: Build UI
run: |
make build-frontend
# https://github.com/docker/build-push-action
- name: Build and Push
id: docker_build
uses: docker/build-push-action@v4
id: build
uses: docker/build-push-action@v5
with:
builder: ${{ steps.buildx.outputs.name }}
context: ./
push: ${{ !inputs.dry_run }}
context: .
file: ./Dockerfile
platforms: 'linux/amd64,linux/arm64'
push: true
build-args: |
APP_VERSION=${{ inputs.version }}
SKIP_UI_BUILD=true
platforms: ${{ inputs.target }}
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
cache-from: type=local,src=/tmp/.buildx-cache
cache-to: type=local,dest=/tmp/.buildx-cache
- name: Comment build info in commit
uses: actions/github-script@v6
env:
STDOUT: "🐳 Published new docker image: [${{ env.DOCKER_IMG }}](https://hub.docker.com/r/${{ env.DOCKER_IMG }}) (${{ env.VERSION }} / sha-${{ env.COMMIT_HASH }})"
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
script: |
github.rest.repos.createCommitComment({
owner: context.repo.owner,
repo: context.repo.repo,
commit_sha: process.env.COMMIT_HASH_FULL, // context.sha
body: process.env.STDOUT
})
- name: Print image digest
run: echo ${{ steps.docker_build.outputs.digest }}
run: echo ${{ steps.build.outputs.digest }}
+31
View File
@@ -0,0 +1,31 @@
name: Build Done
on:
workflow_call:
inputs:
version:
required: true
type: string
dry_run:
required: true
type: boolean
issue_number:
required: true
type: number
jobs:
done:
runs-on: ubuntu-latest
steps:
- name: Checkout Code
uses: actions/checkout@v4
with:
ref: ${{ inputs.version }}
- name: Comment done info
uses: ./.github/actions/comment
if: ${{ inputs.issue_number != 0 }}
with:
issue_number: ${{ inputs.issue_number }}
content: |-
🎉 Finished build and publish ${{ inputs.version }} ([NPM Package](https://www.npmjs.com/package/artalk?activeTab=versions) / [Docker Image](https://hub.docker.com/r/artalk/artalk-go/tags) / [Github Release](https://github.com/ArtalkJS/Artalk/releases/tag/${{ inputs.version }})).
-58
View File
@@ -1,58 +0,0 @@
name: Build Frontend
run-name: Build Frontend and Publish
on:
repository_dispatch:
types: [artalk-release]
jobs:
build_publish:
runs-on: ubuntu-latest
defaults:
run:
working-directory: ./ui # set for building frontend
steps:
- name: Checkout Code
uses: actions/checkout@v3
- name: Checkout latest tag
run: |
git fetch --prune --unshallow --tags -f
git checkout $(git describe --tags --abbrev=0)
- name: Use pnpm
uses: pnpm/action-setup@v2
with:
version: 8
- name: Setup node
uses: actions/setup-node@v3
with:
node-version: 18.x
registry-url: https://registry.npmjs.org/
cache: 'pnpm'
cache-dependency-path: './ui/pnpm-lock.yaml'
- name: Install dependencies
run: pnpm install
- name: Build
run: pnpm build
- name: Publish
run: pnpm publish -F artalk --no-git-checks
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
# GitHub Packages
#
# Setup .npmrc file to publish to GitHub Packages
# - uses: actions/setup-node@v2
# with:
# registry-url: 'https://npm.pkg.github.com'
# # Publish to GitHub Packages
# - run: npm publish
# env:
# NODE_AUTH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+362
View File
@@ -0,0 +1,362 @@
name: Build Nightly
run-name: Build Nightly
on:
schedule:
- cron: "0 10 * * *"
workflow_dispatch:
inputs:
dry_run:
description: "Dry run"
type: boolean
default: true
env:
DIST_DIR: /tmp/builds
DIGEST_DIR: /tmp/digests
DOCKER_IMG: artalk/artalk-go
DOCKER_BUILD_ARGS: |-
SKIP_UI_BUILD=true
jobs:
# Prepare check should run
prepare:
runs-on: ubuntu-latest
outputs:
skip: ${{ steps.check.outputs.skip }}
steps:
- name: Checkout Code
uses: actions/checkout@v4
- name: Check should run
id: check
if: github.event_name == 'schedule'
run: |
if [[ "$(git log --since='24 hours ago' | wc -l)" -eq 0 ]] || \
[[ "$GITHUB_REPOSITORY" != "ArtalkJS/Artalk" ]]; then
echo "skip=true" >> $GITHUB_OUTPUT
fi
# Bulid UI first
# (build ui outside of docker to speed up cross-platform builds)
ui:
if: ${{ needs.prepare.outputs.skip != 'true' }}
needs: prepare
runs-on: macos-14
steps:
- name: Checkout Code
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Setup pnpm
uses: pnpm/action-setup@v3
with:
version: 8
- name: Setup node
uses: actions/setup-node@v4
with:
node-version: 20.x
registry-url: https://registry.npmjs.org/
cache: "pnpm"
- name: Get pnpm store directory
shell: bash
run: |
echo "PNPM_STORE_PATH=$(pnpm store path --silent)" >> $GITHUB_ENV
- uses: actions/cache@v4
name: Setup pnpm cache
with:
path: ${{ env.PNPM_STORE_PATH }}
key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}
restore-keys: |
${{ runner.os }}-pnpm-store-
- name: Install dependencies
run: pnpm install --frozen-lockfile
- name: Build UI
run: |
make build-frontend
- name: Pack UI
id: pack
run: |
SRC_FILE=$(pnpm pack -C ui/artalk --pack-destination ../.. | tail -n 1)
mkdir -p bin
PKG_FILE="bin/artalk_frontend_nigthly_$(date +'%Y%m%d').tar.gz"
mv $SRC_FILE $PKG_FILE
echo "pkg_file=$PKG_FILE" >> $GITHUB_OUTPUT
- name: Upload UI
uses: actions/upload-artifact@v4
with:
name: ui-src
path: |
public
ui/artalk/dist
if-no-files-found: error
retention-days: 1
- name: Upload UI package
uses: actions/upload-artifact@v4
with:
name: build-ui-pkg
path: ${{ steps.pack.outputs.pkg_file }}
retention-days: 1
#
# Build app on different platforms
#
build:
needs: ui
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os:
- ubuntu-latest
# - macos-14
# :(
# native Apple m1 arm64 is not supported nested virtualization yet, so docker qemu is not working.
# https://github.com/actions/runner-images/issues/9460
# https://docs.veertu.com/anka/anka-virtualization-cli/nested-virtualization/
#
# wait for arm64 linux runner support on github actions.
platform:
- linux/amd64
- linux/arm64
- linux/arm/v7
# exclude:
# # exclude build x86 on arm, and vice versa.
# - { os: macos-14, platform: linux/amd64 }
# - { os: ubuntu-latest, platform: linux/arm64 }
steps:
- name: Prepare
run: |
PF="${{ matrix.platform }}"
echo "PLATFORM_PAIR=${PF//\//_}" >> $GITHUB_ENV
- name: Checkout Code
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Setup docker on macos
if: startsWith(matrix.os, 'macos')
uses: crazy-max/ghaction-setup-docker@v3
- name: Gen docker meta
id: meta
uses: docker/metadata-action@v5
with:
images: ${{ env.DOCKER_IMG }}
tags: type=raw,value=nightly
- name: Set up QEMU
uses: docker/setup-qemu-action@v3
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Login to DockerHub
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Download UI before build
uses: actions/download-artifact@v4
with:
name: ui-src
- name: Build and push by digest
uses: docker/build-push-action@v5
id: build
with:
context: .
platforms: ${{ matrix.platform }}
labels: ${{ steps.meta.outputs.labels }}
build-args: ${{ env.DOCKER_BUILD_ARGS }}
# The `type=image,push=true` must the last one,
# because the `build.outputs.digest` will output the last image's digest.
# The digests will be used in the merge step.
outputs: |
type=docker,name=${{ env.DOCKER_IMG }}
type=image,push=true,name=${{ env.DOCKER_IMG }},push-by-digest=true,name-canonical=true
- name: Export digest
run: |
mkdir -p $DIGEST_DIR
digest="${{ steps.build.outputs.digest }}"
touch "$DIGEST_DIR/${digest#sha256:}"
- name: Upload digest
uses: actions/upload-artifact@v4
with:
name: digests-${{ env.PLATFORM_PAIR }}
path: ${{ env.DIGEST_DIR }}/*
if-no-files-found: error
retention-days: 1
# Export docker image
- name: Export Docker Image
id: docker
run: |
IMG_FILE="artalk_docker_nigthly_$(date +'%Y%m%d')_${PLATFORM_PAIR}.tar.gz"
docker save ${{ env.DOCKER_IMG }} | gzip > $IMG_FILE
echo "img_file=$IMG_FILE" >> $GITHUB_OUTPUT
# App
- name: Pack app
id: app
run: |
BASE_DIR="/tmp/app_pkg"
NAME="artalk_nigthly_$(date +'%Y%m%d')_${PLATFORM_PAIR}"
SUB_DIR="$BASE_DIR/$NAME"
PKG_FILE="$BASE_DIR/$NAME.tar.gz"
# bin file
mkdir -p $SUB_DIR
docker run --rm --entrypoint cat ${{ env.DOCKER_IMG }} /artalk > "$SUB_DIR/artalk"
chmod +x "$SUB_DIR/artalk"
# doc file
cp conf/artalk.example.yml "$SUB_DIR/artalk.yml"
cp README.md LICENSE CHANGELOG.md "$SUB_DIR"
# create package file
tar -czf $PKG_FILE -C $BASE_DIR $NAME
echo "app_pkg_file=$PKG_FILE" >> $GITHUB_OUTPUT
# Move build artifacts
- name: Move build artifacts
run: |
mkdir -p $DIST_DIR
mv ${{ steps.app.outputs.app_pkg_file }} $DIST_DIR
mv ${{ steps.docker.outputs.img_file }} $DIST_DIR
# Upload build artifacts
- name: Upload build artifacts
uses: actions/upload-artifact@v4
with:
name: build-${{ env.PLATFORM_PAIR }}
path: ${{ env.DIST_DIR }}/*
if-no-files-found: error
retention-days: 1
# Merge docker digests from different platforms
# Reference: https://docs.docker.com/build/ci/github-actions/multi-platform/#distribute-build-across-multiple-runners
docker_merge:
runs-on: ubuntu-latest
needs: build
steps:
- name: Download digests
uses: actions/download-artifact@v4
with:
path: ${{ env.DIGEST_DIR }}
pattern: digests-*
merge-multiple: true
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Docker meta
id: meta
uses: docker/metadata-action@v5
with:
images: ${{ env.DOCKER_IMG }}
tags: type=raw,value=nightly
- name: Login to Docker Hub
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Create manifest list and push
working-directory: ${{ env.DIGEST_DIR }}
run: |
TAGS_ARG=$(jq -cr '.tags | map("-t " + .) | join(" ")' <<< "$DOCKER_METADATA_OUTPUT_JSON")
MINIFEST_SRCS=$(printf '${{ env.DOCKER_IMG }}@sha256:%s ' *)
docker buildx imagetools create ${TAGS_ARG} ${MINIFEST_SRCS}
- name: Inspect image
run: |
docker buildx imagetools inspect ${{ env.DOCKER_IMG }}:${{ steps.meta.outputs.version }}
# Release
release:
runs-on: ubuntu-latest
needs: build
steps:
- name: Checkout Code
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Download builds
uses: actions/download-artifact@v4
with:
path: ${{ env.DIST_DIR }}
pattern: build-*
merge-multiple: true
# Generate CHANGELOG
- name: Generate Changelog
run: |
# install git-chglog
curl -sL $(curl -s https://api.github.com/repos/git-chglog/git-chglog/releases/latest \
| grep -oP '"https://.+linux_amd64.tar.gz"' | tr -d \") | tar -C /usr/local/bin -xz git-chglog
CHANGELOG=$(git-chglog --config .github/chglog/config.yml --next-tag nightly nightly)
MD_FILE="/tmp/changelog.md"
echo -e "$CHANGELOG" > $MD_FILE
echo -e "\n> [!NOTE]\n" \
"> The Nightly version, automatically built based on the latest code, " \
"is not yet released and may be unstable. Please use it with caution. " \
"Docker user can run \`docker pull artalk/artalk-go:nightly\` to get " \
"the nightly build." >> $MD_FILE
# checksums.txt
- name: Calculate checksums.txt
run: |
cd $DIST_DIR
sha256sum * > checksums.txt
# print checksums.txt
cat checksums.txt
FILES=$(find ${DIST_DIR} -type f -exec readlink -f {} \;)
echo -e "RELEASE_FILES<<EOF" >> $GITHUB_ENV
echo -e "$FILES" >> $GITHUB_ENV
echo -e "EOF" >> $GITHUB_ENV
- name: Create tag and push
env:
GH_TOKEN: ${{ github.token }}
run: |
git config user.name github-actions[bot]
git config user.email 41898282+github-actions[bot]@users.noreply.github.com
gh release delete nightly --yes || true
git push origin :refs/tags/nightly || true
git tag -f nightly
git push -f origin nightly
- name: Release
uses: softprops/action-gh-release@v2
with:
prerelease: true
tag_name: nightly
name: 🧪 Nightly Version
body_path: /tmp/changelog.md
files: ${{ env.RELEASE_FILES }}
draft: false
+61
View File
@@ -0,0 +1,61 @@
name: Build Pre Tagging
on:
workflow_call:
inputs:
dry_run:
required: true
type: boolean
issue_number:
required: true
type: number
outputs:
version:
description: "Version"
value: ${{ jobs.tagging.outputs.version }}
jobs:
tagging:
runs-on: ubuntu-latest
steps:
- name: Get release version
run: |
# `github.head_ref` only exists for pull_request events
REF="${{ github.head_ref || github.ref }}"
VERSION="${REF#refs/tags/}"
VERSION="${VERSION#refs/heads/}"
VERSION="${VERSION#release/}"
echo "Version: $VERSION"
echo "VERSION=$VERSION" >> $GITHUB_ENV
if [[ ! "$VERSION" =~ ^v[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
echo "Invalid version format: $VERSION, please check git ref or tag."
exit 1
fi
- name: Checkout Code
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Create Tag
run: |
if [ ! $(git tag -l "${VERSION}") ]; then
git config user.name github-actions[bot]
git config user.email 41898282+github-actions[bot]@users.noreply.github.com
git tag -a $VERSION -m "Release $VERSION"
git push origin $VERSION
else
echo "Skip creating tag $VERSION, already exists."
fi
- name: Comment tag info to PR
uses: ./.github/actions/comment
if: ${{ inputs.issue_number != 0 }}
with:
issue_number: ${{ inputs.issue_number }}
content: |-
🔖 Tagged version [${{ env.VERSION }}](https://github.com/ArtalkJS/Artalk/tree/${{ env.VERSION }}) and updated the [CHANGELOG.md](https://github.com/ArtalkJS/Artalk/blob/master/CHANGELOG.md).
outputs:
version: ${{ env.VERSION }}
+55
View File
@@ -0,0 +1,55 @@
name: Build UI
on:
workflow_call:
inputs:
version:
required: true
type: string
dry_run:
required: true
type: boolean
jobs:
build_publish:
runs-on: ubuntu-latest
steps:
- name: Checkout Code
uses: actions/checkout@v4
with:
ref: ${{ inputs.version }}
- name: Use pnpm
uses: pnpm/action-setup@v3
with:
version: 8
- name: Setup node
uses: actions/setup-node@v4
with:
node-version: 20.x
registry-url: https://registry.npmjs.org/
cache: "pnpm"
- name: Install dependencies
run: pnpm install --frozen-lockfile
- name: Build
run: pnpm build
- name: Publish
run: pnpm publish -F artalk --no-git-checks ${{ inputs.dry_run && '--dry-run' || '' }}
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
# GitHub Packages
#
# Setup .npmrc file to publish to GitHub Packages
# - uses: actions/setup-node@v4
# with:
# registry-url: 'https://npm.pkg.github.com'
# # Publish to GitHub Packages
# - run: npm publish
# env:
# NODE_AUTH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+82
View File
@@ -0,0 +1,82 @@
name: Build and Publish
run-name: Build and Publish (${{ github.head_ref || github.ref }}) ${{ inputs.dry_run && '(🧪 Dry-Run)' || '' }}
on:
pull_request:
branches: [master]
types: [closed]
workflow_dispatch:
inputs:
dry_run:
description: "Dry run"
type: boolean
default: true
build_items:
description: "Build items"
type: string
default: "ui,app,docker"
jobs:
# Tag the release version code before building
# Getting the version code from the branch name or git ref.
tagging:
# Only run on manual trigger
# or when a PR is merged into master.
# (which the branch name start with `relase/`)
if: |
github.event_name == 'workflow_dispatch' ||
(github.event.pull_request.merged == true && startsWith(github.head_ref, 'release/'))
uses: ./.github/workflows/build-tagging.yml
with:
issue_number: ${{ github.event.pull_request.number || 0 }}
dry_run: ${{ inputs.dry_run || false }}
secrets: inherit
# Build the UI
ui:
if: inputs.build_items == '' || contains(inputs.build_items, 'ui')
needs: tagging
uses: ./.github/workflows/build-ui.yml
with:
version: ${{ needs.tagging.outputs.version }}
dry_run: ${{ inputs.dry_run || false }}
secrets: inherit
# Build the Docker image
docker:
if: inputs.build_items == '' || contains(inputs.build_items, 'docker')
needs: tagging
uses: ./.github/workflows/build-docker.yml
# Parallel build the multi-arch docker image
strategy:
matrix:
# since docker push actions will override the previous images,
# so need to build `linux/amd64` and push first,
# then build `linux/amd64` twice with other archs (build very slow so keep it last).
target: ["linux/amd64", "linux/amd64,linux/arm64,linux/arm/v7"]
with:
version: ${{ needs.tagging.outputs.version }}
dry_run: ${{ inputs.dry_run || false }}
target: ${{ matrix.target }}
secrets: inherit
# Build the binary app
app:
if: inputs.build_items == '' || contains(inputs.build_items, 'app')
needs: tagging
uses: ./.github/workflows/build-app.yml
with:
version: ${{ needs.tagging.outputs.version }}
dry_run: ${{ inputs.dry_run || false }}
secrets: inherit
# All builds are complete
done:
needs: [tagging, ui, docker, app]
uses: ./.github/workflows/build-done.yml
with:
version: ${{ needs.tagging.outputs.version }}
issue_number: ${{ github.event.pull_request.number || 0 }}
dry_run: ${{ inputs.dry_run || false }}
secrets: inherit
+36 -33
View File
@@ -9,16 +9,18 @@
# the `language` matrix defined below to confirm you have the correct set of
# supported CodeQL languages.
#
name: "CodeQL"
name: CodeQL
on:
push:
branches: [ "master" ]
branches:
- master
pull_request:
# The branches below must be a subset of the branches above
branches: [ "master" ]
branches:
- master
schedule:
- cron: '40 17 * * 4'
- cron: "40 17 * * 4"
jobs:
analyze:
@@ -32,43 +34,44 @@ jobs:
strategy:
fail-fast: false
matrix:
language: [ 'go', 'javascript' ]
language:
- go
- javascript
# CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ]
# Learn more about CodeQL language support at https://aka.ms/codeql-docs/language-support
steps:
- name: Checkout repository
uses: actions/checkout@v3
- name: Checkout repository
uses: actions/checkout@v4
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@v2
with:
languages: ${{ matrix.language }}
# If you wish to specify custom queries, you can do so here or in a config file.
# By default, queries listed here will override any specified in a config file.
# Prefix the list here with "+" to use these queries and those in the config file.
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@v3
with:
languages: ${{ matrix.language }}
# If you wish to specify custom queries, you can do so here or in a config file.
# By default, queries listed here will override any specified in a config file.
# Prefix the list here with "+" to use these queries and those in the config file.
# Details on CodeQL's query packs refer to : https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs
# queries: security-extended,security-and-quality
# Details on CodeQL's query packs refer to : https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs
# queries: security-extended,security-and-quality
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
# If this step fails, then you should remove it and run the build manually (see below)
- name: Autobuild
uses: github/codeql-action/autobuild@v3
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
# If this step fails, then you should remove it and run the build manually (see below)
- name: Autobuild
uses: github/codeql-action/autobuild@v2
# ℹ️ Command-line programs to run using the OS shell.
# 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun
# ℹ️ Command-line programs to run using the OS shell.
# 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun
# If the Autobuild fails above, remove it and uncomment the following three lines.
# modify them (or add more) to build your code if your project, please refer to the EXAMPLE below for guidance.
# If the Autobuild fails above, remove it and uncomment the following three lines.
# modify them (or add more) to build your code if your project, please refer to the EXAMPLE below for guidance.
# - run: |
# echo "Run, Build Application using script"
# ./location_of_script_within_repo/buildscript.sh
# - run: |
# echo "Run, Build Application using script"
# ./location_of_script_within_repo/buildscript.sh
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v2
with:
category: "/language:${{matrix.language}}"
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v3
with:
category: "/language:${{matrix.language}}"
+25 -47
View File
@@ -2,61 +2,39 @@ name: Docs CN Mirror Deploy
on:
push:
branches:
- master
paths:
- "docs/**"
branches: ["master"]
paths: ["docs/**"]
jobs:
deploy:
if: github.repository == 'ArtalkJS/Artalk'
runs-on: ubuntu-latest
defaults:
run:
# set for building docs
working-directory: ./docs
steps:
# - name: Wait for other docs build to succeed
# uses: lewagon/wait-on-check-action@v1.2.0
# with:
# running-workflow-name: 'Docs CN Mirror Deploy'
# check-name: 'Build Docs'
# ref: ${{ github.ref }}
# repo-token: ${{ secrets.GITHUB_TOKEN }}
# allowed-conclusions: success,skipped,cancelled
# wait-interval: 10
- name: Checkout
uses: actions/checkout@v4
- name: Checkout
uses: actions/checkout@v3
- name: Use pnpm
uses: pnpm/action-setup@v3
- name: Use pnpm
uses: pnpm/action-setup@v2
with:
version: 8
- name: Setup node
uses: actions/setup-node@v4
with:
node-version: 20
cache: pnpm
- name: Setup node
uses: actions/setup-node@v3
with:
node-version: 18.x
registry-url: https://registry.npmjs.org/
cache: 'pnpm'
- name: Install dependencies
run: pnpm install
- name: Install dependencies
run: pnpm install
- name: Build Docs
run: pnpm build:docs
- name: Build Docs
run: pnpm docs:build
- name: Deploy
uses: TencentCloud/cos-action@v1
with:
secret_id: ${{ secrets.TENCENT_CLOUD_SECRET_ID }}
secret_key: ${{ secrets.TENCENT_CLOUD_SECRET_KEY }}
cos_bucket: ${{ secrets.DOCS_CN_COS_BUCKET }}
cos_region: ${{ secrets.DOCS_CN_COS_REGION }}
local_path: .vitepress/dist/
remote_path: /
clean: true
- name: Deploy
uses: TencentCloud/cos-action@v1
with:
secret_id: ${{ secrets.TENCENT_CLOUD_SECRET_ID }}
secret_key: ${{ secrets.TENCENT_CLOUD_SECRET_KEY }}
cos_bucket: ${{ secrets.DOCS_CN_COS_BUCKET }}
cos_region: ${{ secrets.DOCS_CN_COS_REGION }}
local_path: docs/docs/.vitepress/dist/
remote_path: /
clean: true
+57 -54
View File
@@ -1,5 +1,5 @@
name: 📦 Release New Version
run-name: 📦 Release ${{ inputs.custom || inputs.semver }} by @${{ github.actor }}
name: 0x📦 Release New Version
run-name: 📦 Release ${{ inputs.semver }} by @${{ github.actor }} ${{ inputs.dry_run && '(🧪 Dry-Run)' || '' }}
on:
workflow_dispatch:
@@ -12,82 +12,85 @@ on:
- minor
- major
required: true
# custom:
# description: 'Custom tag name (i.e v1.0.0-rc.1)'
# required: false
# default: ''
env:
REPO_DISPATCH_EVENT_TYPE: 'artalk-release'
UI_NPM_PKG_FILE: 'ui/packages/artalk/package.json'
custom_version:
description: Manual Custom Version (Special Purpose, v*)
type: string
required: false
dry_run:
description: "Dry run?"
type: boolean
default: false
jobs:
release:
runs-on: ubuntu-latest
steps:
- name: Checkout Code
uses: actions/checkout@v3
- name: Git Fetch
run: git fetch --prune --unshallow --tags -f
uses: actions/checkout@v4
with:
ref: master
fetch-depth: 0
- name: Setup Node
uses: actions/setup-node@v3
uses: actions/setup-node@v4
with:
node-version: 18.x
node-version: 20.x
registry-url: https://registry.npmjs.org/
- name: Setup semver
run: npm install -g semver
- name: Handle Version Number
run: |
if [ ! -z "${{ inputs.custom }}" ]; then
next_version="${{ inputs.custom }}"
PREV_VERSION="$(git describe --tags --abbrev=0 --match 'v*')"
if [ -n "${{ inputs.custom_version }}" ]; then
NEXT_VERSION="${{ inputs.custom_version }}"
else
npm install -g semver
prev_version="$(git describe --tags --abbrev=0)"
echo "prev_version: ${prev_version}"
next_version="v$(semver --increment ${{ inputs.semver }} ${prev_version})"
NEXT_VERSION="v$(semver --increment ${{ inputs.semver }} ${PREV_VERSION})"
fi
if [[ ! "${next_version}" =~ ^v.* ]]; then
echo "[err] custom tag name must be v*."
exit 1
fi
echo "PREV_VERSION=${PREV_VERSION}" >> $GITHUB_ENV
echo "VERSION=${NEXT_VERSION}" >> $GITHUB_ENV
echo "next_version: ${next_version}"
echo "VERSION=${next_version}" >> $GITHUB_ENV
- name: Print Next Version
run: echo "${VERSION}"
- name: Setup git-chglog
run: |
curl -sL $(curl -s https://api.github.com/repos/git-chglog/git-chglog/releases/latest \
| grep -oP '"https://.+linux_amd64.tar.gz"' | tr -d \") | tar -C /usr/local/bin -xz git-chglog
git-chglog --version
curl -sL $(curl -s https://api.github.com/repos/git-chglog/git-chglog/releases/latest \
| grep -oP '"https://.+linux_amd64.tar.gz"' | tr -d \") | tar -C /usr/local/bin -xz git-chglog
git-chglog --version
- name: Version Changelog and Tagging
- name: Version Changelog
run: |
if [ ! $(git tag -l "${VERSION}") ]; then
# prepend changelog
changelog=$(git-chglog --config .github/chglog/config.yml --next-tag "${VERSION}" "${VERSION}")
echo -e "${changelog}\n" | cat - CHANGELOG.md > temp && mv temp CHANGELOG.md
# prepend changelog
changelog=$(git-chglog --config .github/chglog/config.yml --next-tag "${VERSION}" "${VERSION}")
echo -e "${changelog}\n" | cat - CHANGELOG.md > temp && mv temp CHANGELOG.md
# modify the version of `package.json`
perl -i -pe 's/"version": ".*?"/"version": "'${VERSION#v}'"/g' "${UI_NPM_PKG_FILE}"
# modify the version of `package.json`
perl -i -pe 's/"version": ".*?"/"version": "'${VERSION#v}'"/g' ui/artalk/package.json
# modify the version in docs
perl -pi -e 's#"latest"(\W+)?:(\W+)?".*?"#"latest": "'${VERSION#v}'"#g' docs/code/ArtalkVersion.json
# modify the version in docs
perl -pi -e 's#"latest"(\W+)?:(\W+)?".*?"#"latest": "'${VERSION#v}'"#g' docs/docs/code/ArtalkVersion.json
# git commit and push
git config user.name github-actions[bot]
git config user.email 41898282+github-actions[bot]@users.noreply.github.com
git add .
git commit -m "chore: release ${VERSION}"
git tag "${VERSION}"
- name: Print Git Diff
run: git diff
git push origin master "${VERSION}"
else
echo "skipped because git tag already exists."
fi
- name: Repository Dispatch
uses: peter-evans/repository-dispatch@v2
- name: Create Pull Request
uses: peter-evans/create-pull-request@v6
if: ${{ !inputs.dry_run }}
with:
event-type: ${{ env.REPO_DISPATCH_EVENT_TYPE }}
branch: "release/${{ env.VERSION }}"
commit-message: "chore: release ${{ env.VERSION }}"
title: "chore: release ${{ env.VERSION }}"
labels: release
body: |
## Release ${{ env.VERSION }} 📦🚀
This PR is auto-generated, please check the changelog and confirm the release. 😀
The build workflow will be triggered after the PR is merged.
committer: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
author: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
assignees: ${{ github.actor }}
+2 -2
View File
@@ -8,13 +8,13 @@ on:
type: string
description: Event Type
required: true
default: ''
default: ""
jobs:
release:
runs-on: ubuntu-latest
steps:
- name: Repository Dispatch
uses: peter-evans/repository-dispatch@v2
uses: peter-evans/repository-dispatch@v3
with:
event-type: ${{ inputs.event_type }}
+33
View File
@@ -0,0 +1,33 @@
name: Test Docs
on:
push:
branches: ["*", "!release/*", "!nightly"]
paths: ["docs/**"]
tags-ignore: ["v*"]
pull_request:
paths: ["docs/**"]
branches: ["*", "!release/*", "!nightly"]
jobs:
test_docs:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Use pnpm
uses: pnpm/action-setup@v3
- name: Use Node.js
uses: actions/setup-node@v4
with:
node-version: 20.x
cache: pnpm
- name: Install dependencies
run: pnpm install
- name: Build Docs
run: pnpm build:docs
+14 -15
View File
@@ -2,11 +2,12 @@ name: Test Frontend
on:
push:
paths:
- 'ui/**'
branches: ["*", "!release/*", "!nightly"]
paths: ["ui/**"]
tags-ignore: ["v*"]
pull_request:
paths:
- 'ui/**'
paths: ["ui/**"]
branches: ["*", "!release/*", "!nightly"]
jobs:
test_ui:
@@ -17,15 +18,11 @@ jobs:
runs-on: ${{ matrix.os }}
defaults:
run:
working-directory: ./ui
steps:
- name: Checkout Code
uses: actions/checkout@v3
uses: actions/checkout@v4
- uses: pnpm/action-setup@v2
- uses: pnpm/action-setup@v3
with:
version: 8
@@ -34,14 +31,16 @@ jobs:
with:
node-version: ${{ matrix.node }}
cache: pnpm
cache-dependency-path: './ui/pnpm-lock.yaml'
- name: Install Dependencies
run: pnpm --dir ./ui install --frozen-lockfile
run: pnpm install --frozen-lockfile
- name: Package Build Test
run: pnpm build:all
# TODO: Add unit test
# - name: Unit test
# run: pnpm test
- name: Unit test
run: pnpm test
# https://github.com/arethetypeswrong/arethetypeswrong.github.io
- name: "arethetypeswrong test"
run: pnpm -F artalk attw || true
+6 -6
View File
@@ -14,9 +14,9 @@ env:
before:
hooks:
# install dependencies
- make install
- make build-frontend
# install dependencies
- make install
- make build-frontend
# build multi-platform
builds:
@@ -60,7 +60,7 @@ builds:
goarch:
- arm
goarm:
- '7'
- "7"
env:
- CC=arm-linux-gnueabihf-gcc
- CXX=arm-linux-gnueabihf-g++
@@ -118,7 +118,7 @@ builds:
# https://go-review.googlesource.com/c/go/+/224588/
# https://github.com/ArtalkJS/Artalk/issues/35
&win_common_flags |
-tags=timetzdata
-tags=timetzdata
# Win (arm_64)
- id: windows-arm64
@@ -156,7 +156,7 @@ archives:
- artalk.yml
checksum:
name_template: 'checksums.txt'
name_template: "checksums.txt"
snapshot:
name_template: "{{.Version}}-SNAPSHOT-{{.ShortCommit}}"
View File
File renamed without changes.
+17
View File
@@ -0,0 +1,17 @@
CHANGELOG.md
CHANGELOG.tpl.md
CDN.html
internal/template/notify_tpl/default.html
# generated files
# @link https://github.com/prettier/prettier/issues/3634
pnpm-lock.yaml
**/auto-imports.d.ts
**/components.d.ts
**/typed-router.d.ts
ui/artalk/src/api/v2.ts
docs/swagger/swagger.json
docs/swagger/swagger.yaml
docs/**
ui/artalk-sidebar/src/lib/md5.js
ui/artalk/src/lib/detect.ts
+26
View File
@@ -0,0 +1,26 @@
{
"arrowParens": "always",
"bracketSpacing": true,
"htmlWhitespaceSensitivity": "css",
"insertPragma": false,
"bracketSameLine": false,
"jsxSingleQuote": false,
"printWidth": 100,
"proseWrap": "preserve",
"quoteProps": "as-needed",
"requirePragma": false,
"semi": false,
"singleQuote": true,
"tabWidth": 2,
"trailingComma": "all",
"useTabs": false,
"vueIndentScriptAndStyle": false,
"overrides": [
{
"files": ["*.yaml", "*.yml"],
"options": {
"singleQuote": false
}
}
]
}
+12 -12
View File
@@ -1,14 +1,14 @@
{
"version": "0.2.0",
"configurations": [
{
"name": "Launch Artalk for Debugging",
"type": "go",
"request": "launch",
"mode": "exec",
"program": "${workspaceFolder}/bin/artalk",
"preLaunchTask": "Build for debugging",
"args": ["server", "-c", "${workspaceFolder}/data/artalk.yml"]
}
],
"version": "0.2.0",
"configurations": [
{
"name": "Launch Artalk for Debugging",
"type": "go",
"request": "launch",
"mode": "exec",
"program": "${workspaceFolder}/bin/artalk",
"preLaunchTask": "Build for debugging",
"args": ["server", "-c", "${workspaceFolder}/data/artalk.yml"]
}
]
}
+17 -18
View File
@@ -1,20 +1,19 @@
{
"eslint.workingDirectories": ["./ui"],
"cSpell.words": [
"akismet",
"artalk",
"artran",
"artrans",
"artransfer",
"gomail",
"Goreleaser",
"gorm",
"ldflags",
"lfshook",
"Metas",
"pgsql",
"sendmail",
"sqlite",
"pkged"
]
"cSpell.words": [
"akismet",
"artalk",
"artran",
"artrans",
"artransfer",
"gomail",
"Goreleaser",
"gorm",
"ldflags",
"lfshook",
"Metas",
"pgsql",
"sendmail",
"sqlite",
"pkged"
]
}
+12 -12
View File
@@ -1,14 +1,14 @@
{
"version": "2.0.0",
"tasks": [
{
"label": "Build for debugging",
"type": "shell",
"command": "make build-debug",
"group": {
"kind": "build",
"isDefault": true
}
}
]
"version": "2.0.0",
"tasks": [
{
"label": "Build for debugging",
"type": "shell",
"command": "make build-debug",
"group": {
"kind": "build",
"isDefault": true
}
}
]
}
+233
View File
@@ -1,4 +1,237 @@
## [v2.8.5](https://github.com/ArtalkJS/Artalk/compare/v2.8.3...v2.8.5) (2024-04-21)
### Features
* **ci/build:** add nightly build workflow
* **conf/http:** add `http.proxy_header` config option
* **go:** upgrade golang to v1.22.2 and some deps
### Bug Fixes
* **cmd/gen:** ensure directory before saving in `gen` cmd ([#612](https://github.com/ArtalkJS/Artalk/issues/612))
* **dao:** prevent potential infinite loop in `FindCommentRootID`
* **db/migrate:** issue with root id generation
* **db/migrator:** remove foreign key constraints and better `root_id` generation ([#835](https://github.com/ArtalkJS/Artalk/issues/835))
* **log:** improve log system and fix memory leaks ([#843](https://github.com/ArtalkJS/Artalk/issues/843))
* **transfer:** retrieve root_id for imported comment data
* **ui/comment:** missing reply comment data when inserting ([#838](https://github.com/ArtalkJS/Artalk/issues/838))
* **ui/comment:** incorrect reply comment data in nested mode ([#771](https://github.com/ArtalkJS/Artalk/issues/771)) ([#837](https://github.com/ArtalkJS/Artalk/issues/837))
* **ui/lifecycle:** keep root element during destroy ([#810](https://github.com/ArtalkJS/Artalk/issues/810))
* **ui/sidebar:** user list not refresh when data is modified
* **ui/upload:** unable to upload image when file extension is uppercase
* **upload:** add config option to solve request entity too large issue ([#834](https://github.com/ArtalkJS/Artalk/issues/834))
### Performance Improvements
* **conf/upgit:** disallow custom executable path of `upgit` for security ([#817](https://github.com/ArtalkJS/Artalk/issues/817))
* **db:** optimize N+1 query in comment list ([#799](https://github.com/ArtalkJS/Artalk/issues/799))
* **i18n:** add translation for 'parameter is required'
* **ui/pkg:** add shorter export names ([#821](https://github.com/ArtalkJS/Artalk/issues/821))
* **ui/version_check:** beautify version upgrade notice
### Code Refactoring
* **comments_get:** reduce api complexity by introducing `LiteDB` ([#800](https://github.com/ArtalkJS/Artalk/issues/800))
* **ui/prettier:** add prettier code formatter
### Documentation
* **extras:** add deploy guide for Valaxy ([#836](https://github.com/ArtalkJS/Artalk/issues/836))
* **i18n:** add French translation ([#797](https://github.com/ArtalkJS/Artalk/issues/797))
### BREAKING CHANGE
For UpGit users: Due to security reasons, Artalk no longer allows configuring the executable file path (img_upload.upgit.exec) for upgit. Please add it to system environment variables instead.
## [v2.8.3](https://github.com/ArtalkJS/Artalk/compare/v2.8.2...v2.8.3) (2024-03-04)
### Features
* **api/auth:** invalidate old auth tokens after changing password
* **api/domain:** add GET `/conf/domain` endpoint
* **app:** add `onConfUpdated` hook
* **comment:** add `is_verified` field for comment entity
* **ui/api:** add `ctx.getApiHandlers()` to handle error responses and expose hooks
* **ui/editor:** add `beforeSubmit` hook for editor submitting
* **ui/plugins:** support dynamic loading of ui plug-in scripts ([#774](https://github.com/ArtalkJS/Artalk/issues/774))
### Bug Fixes
* **captcha/image:** unable to display image captcha on initial load
* **conf:** skip patching IP region conf if disabled
* **exception:** missing `message` field after refactoring exception data structure
* **sidebar/login:** cannot select a name with the same email upon login ([#781](https://github.com/ArtalkJS/Artalk/issues/781))
* **ui/layer:** ensure immediate operation when calling `show()` after `hide()`
### Performance Improvements
* **ui/editor:** improve the icon details for editor
### Code Refactoring
* **dao:** validate the args of the `FindCreateUser` function
* **entity/user:** extract `CheckPassword` function
* **origin:** extract `CheckURLTrusted` function
## [v2.8.2](https://github.com/ArtalkJS/Artalk/compare/v2.8.1...v2.8.2) (2024-02-05)
### Bug Fixes
* **api/comments:** `ua` field is optional and not required ([#767](https://github.com/ArtalkJS/Artalk/issues/767))
* **style:** replace style `break-all` with `break-word` in content el ([#644](https://github.com/ArtalkJS/Artalk/issues/644))
### Performance Improvements
* **ui/editor:** optimize editor styles for narrow-width screens
* **ui/editor:** modify editor plug-in text buttons to icons for brevity
* **ui/editor:** place `Cancel Reply` at the bottom of editor area ([#644](https://github.com/ArtalkJS/Artalk/issues/644))
* **ui/lite:** disable ArtalkLite `preview` config option by default
## [v2.8.1](https://github.com/ArtalkJS/Artalk/compare/v2.8.0...v2.8.1) (2024-02-04)
### Features
* **api:** add GET `/comments/:id` endpoint ([#764](https://github.com/ArtalkJS/Artalk/issues/764))
* **config:** add `db.prepare_stmt` config option ([#760](https://github.com/ArtalkJS/Artalk/issues/760)) ([#762](https://github.com/ArtalkJS/Artalk/issues/762))
* **ui/goto:** improved solution of navigating to comment via link hash ([#693](https://github.com/ArtalkJS/Artalk/issues/693)) ([#765](https://github.com/ArtalkJS/Artalk/issues/765))
### Bug Fixes
* **api/comments:** counting comments issue in PostgreSQL db ([#760](https://github.com/ArtalkJS/Artalk/issues/760)) ([#761](https://github.com/ArtalkJS/Artalk/issues/761))
* **cmd/admin:** update user role to admin if already exists
* **ip_region:** unable to output the IP region correctly ([#760](https://github.com/ArtalkJS/Artalk/issues/760))
* **ui/list:** unable to reply or delete comments after switching pagination
* **ui/no_comment:** always appears when creating comment
* **ui/pv:** missing `pageTitle` field in the PV request
* **ui/scroll:** scroll into view issue when `relativeTo` parameter is provided
### Performance Improvements
* **style/sidebar:** improve some detail in sidebar
### Code Refactoring
* **ui/comment:** loose coupling between `Comment` and `Context`
* **ui/list:** refactor the list layout manager
### Documentation
* supplement and refine `fe-api.md`
## [v2.8.0](https://github.com/ArtalkJS/Artalk/compare/v2.7.3...v2.8.0) (2024-01-31)
### Features
* **go:** upgrade golang to v1.21.5 and some deps
* **notify:** add `notify_pending` config option ([#728](https://github.com/ArtalkJS/Artalk/issues/728)) ([#754](https://github.com/ArtalkJS/Artalk/issues/754))
* **ui/admin:** add logout button in admin panel ([#488](https://github.com/ArtalkJS/Artalk/issues/488)) ([#753](https://github.com/ArtalkJS/Artalk/issues/753))
### Bug Fixes
* **cache:** unable to change admin list after caching ([#748](https://github.com/ArtalkJS/Artalk/issues/748)) ([#750](https://github.com/ArtalkJS/Artalk/issues/750))
* **i18n:** sidebar language cannot be changed
* **ui/editor:** prevent propagation of click event in editor ([#734](https://github.com/ArtalkJS/Artalk/issues/734))
* **ui/layer:** unexpected behavior with multiple items when closing
* **ui/lite:** correct the instance name for compiling ArtalkLite ([#740](https://github.com/ArtalkJS/Artalk/issues/740))
* **ui/no_comment:** flickering when clearing list before fetch
* **ui/pagination:** auto load list when scroll reaches bottom
* **ui/sidebar:** incorrectly increasing pv count in sidebar ([#724](https://github.com/ArtalkJS/Artalk/issues/724))
* **ui/sidebar_layer:** sidebar still displays when login is required
### Performance Improvements
* **ui/conf:** support for watching partial changes in config with `watchConf()` ([#755](https://github.com/ArtalkJS/Artalk/issues/755))
* **ui/i18n:** refine some translation ([#743](https://github.com/ArtalkJS/Artalk/issues/743))
* **ui/pagination:** replace the prev/next text on pagination buttons with icons ([#743](https://github.com/ArtalkJS/Artalk/issues/743))
* **ui/sidebar:** prevent potential token leakage by clearing query in iframe url
### Code Refactoring
* **api:** update swagger file of API v2
* **api:** refactor HTTP API to version 2 ([#735](https://github.com/ArtalkJS/Artalk/issues/735))
* **transfer:** normalize transfer payload parameter name
* **ui:** optimize init and update lifecycle events
* **ui/comment:** rename class `Comment` to `CommentNode`
* **ui/ctx:** add `getComments` and `getCommentNodes` in context ([#752](https://github.com/ArtalkJS/Artalk/issues/752))
### Documentation
* update multi-sites manual ([#747](https://github.com/ArtalkJS/Artalk/issues/747))
### BREAKING CHANGE
For Developers: The HTTP API has now been updated to version v2, with a lot of adjustments made, such as changing to Restful API style, request type, request body, response body, etc. data structure, adding error response codes. You can refer to [#735](https://github.com/ArtalkJS/Artalk/issues/735) or https://artalk.js.org/http-api Please update all your existing clients to adapt to the new v2 server. The new base path is `/api/v2/`. The UI package's HTTP client has been implemented to auto-generate based on `Swagger.json`, and there have been a lot of adjustments to the `artalk.ctx.getApi()` related code. In addition, the HTTP API no longer enforces checks on the header's `Origin` and `Referer` (to implement strict isolation of different sites) but still maintains the original CORS origin check.
For General Users: Now all administrators have the same level of authority (there is no longer super admin authority), the function of assigning sub-administrators with independent scope authority to individual sites has been removed, which can simplify the HTTP server maintenance and implementation. Upgrading only requires updating the client and server application at the same time, and there are no additional operations.
## [v2.7.3](https://github.com/ArtalkJS/Artalk/compare/v2.7.2...v2.7.3) (2023-12-28)
### Features
* **ci:** add dry-run mode for build workflow
* **cmd:** support cli flag for creating admin account
### Bug Fixes
* **ui/init:** stack overflow when merging with config defaults ([#717](https://github.com/ArtalkJS/Artalk/issues/717))
### Performance Improvements
* **ui/build:** better dts generation ([#689](https://github.com/ArtalkJS/Artalk/issues/689))
### Code Refactoring
* **ci:** better release workflow
* **docker:** add `--build-arg` argument to skip ui build
* **test/ui:** add more ui api tests
* **ui:** refactor directory structure ([#712](https://github.com/ArtalkJS/Artalk/issues/712))
* **ui/conf:** better handling of mutable config ([#722](https://github.com/ArtalkJS/Artalk/issues/722))
* **ui/test:** add vitest for unit testing
### Documentation
* update ui api documentation
### BREAKING CHANGE
Directly referencing `artalk.conf` and `artalk.$root` is deprecated. Please use functions instead: `artalk.getConf()` and `artalk.getEl()`.
## [v2.7.2](https://github.com/ArtalkJS/Artalk/compare/v2.7.1...v2.7.2) (2023-12-20)
### Features
* patch `locale` config from `zh-cn` to `zh-CN` ([#678](https://github.com/ArtalkJS/Artalk/issues/678))
### Bug Fixes
* **sidebar:** sidebar language switch and config save issue ([#708](https://github.com/ArtalkJS/Artalk/issues/708))
* **ui:** add `referrerpolicy` attribute for iframe ([#687](https://github.com/ArtalkJS/Artalk/issues/687)) ([#707](https://github.com/ArtalkJS/Artalk/issues/707))
* **ui/dark-mode:** potential memory leak issue in auto mode ([#688](https://github.com/ArtalkJS/Artalk/issues/688))
* **ui/pagination:** auto switch page by url hashtag issue ([#693](https://github.com/ArtalkJS/Artalk/issues/693))
* **ui/sidebar:** refactor settings and fix save issue ([#677](https://github.com/ArtalkJS/Artalk/issues/677)) ([#706](https://github.com/ArtalkJS/Artalk/issues/706))
### Code Refactoring
* **ui:** move window references into function scope ([#675](https://github.com/ArtalkJS/Artalk/issues/675))
* **ui/api:** losing coupling between `Api` and `User`
* **ui/user:** user class no longer globally singleton
### Documentation
* **i18n:** add translation for `open` button
* **refactor:** organize the pkgs and fix some issues ([#702](https://github.com/ArtalkJS/Artalk/issues/702))
## [v2.7.1](https://github.com/ArtalkJS/Artalk/compare/v2.7.0...v2.7.1) (2023-12-17)
### Bug Fixes
+9 -9
View File
@@ -6,8 +6,8 @@ This guide is for developers who want to contribute to the project.
To develop Artalk, including the frontend and backend, you need to install the following tools:
- [Node.js](https://nodejs.org/en/) (>= 18.12.0)
- [Go](https://golang.org/) (>= 1.21)
- [Node.js](https://nodejs.org/en/) (>= 20.12.1)
- [Go](https://golang.org/) (>= 1.22)
- [Docker](https://www.docker.com/) (>= 20.10.0) (optional)
- [Docker Compose](https://docs.docker.com/compose/) (>= 1.29.0) (optional)
@@ -41,9 +41,9 @@ The backend program will run by default on port `23366`. You can access it throu
### Build Frontend
First, you need to install the dependencies for the frontend. Simply run the `cd ui && pnpm install` command to install the dependencies.
First, you need to install the dependencies for the frontend. Simply run the `pnpm install` command to install the dependencies.
Then, run the `cd ui && pnpm dev` to build and run the frontend, and you can pass startup parameters to the program using `ARGS="--port 5173" pnpm dev`.
Then, run the `pnpm dev` to build and run the frontend, and you can pass startup parameters to the program using `ARGS="--port 5173" pnpm dev`.
The frontend program will run by default on port `5173`, and you can access it in a browser at `http://localhost:5173`. The frontend testing client will, by default, request the backend on port `23366`, so it's essential to keep the backend on this port.
@@ -51,9 +51,9 @@ The frontend program is divided into the main program and a sidebar program, wit
### Development Workflow
In most cases, to set up a complete development instance, you need to navigate to the Artalk Repo directory and then execute `make dev`. This will run the backend on port `23366`. Then, execute `cd ui && pnpm dev`, which will run the frontend on port `5173`. You can optionally execute `pnpm dev:sidebar` to run the sidebar frontend on port `23367`. For frontend development, you need to access `http://localhost:5173` in your browser to perform your development and testing.
In most cases, to set up a complete development instance, you need to navigate to the Artalk Repo directory and then execute `make dev`. This will run the backend on port `23366`. Then, execute `pnpm dev`, which will run the frontend on port `5173`. You can optionally execute `pnpm dev:sidebar` to run the sidebar frontend on port `23367`. For frontend development, you need to access `http://localhost:5173` in your browser to perform your development and testing.
When you make changes to the frontend code, you can build the complete frontend program using `cd ui && pnpm build:all`. The JavaScript and CSS code can be found in `ui/packages/artalk/dist`.
When you make changes to the frontend code, you can build the complete frontend program using `pnpm build:all`. The JavaScript and CSS code can be found in `ui/artalk/dist`.
When you make changes to the backend code, running `make all` will build the complete backend program. Note that since the backend program also embeds the frontend code, the `scripts/build-frontend.sh` script will run during backend program building, which includes the embedded frontend main program and sidebar frontend program. If you are interested, you can explore the complete frontend build process in the `Makefile` code.
@@ -84,9 +84,9 @@ And open <http://localhost:1313/> in your browser to view the example site.
Here is the default admin account (only created in test mode):
```yaml
name: "admin"
email: "admin@test.com"
password: "admin"
name: 'admin'
email: 'admin@test.com'
password: 'admin'
```
## Testing
+24 -7
View File
@@ -1,12 +1,11 @@
### build Artalk
FROM golang:1.21.3-alpine3.18 as builder
FROM golang:1.22.2-alpine3.19 as builder
WORKDIR /source
# install tools
RUN set -ex \
&& apk add --no-cache make git gcc musl-dev nodejs bash npm\
&& npm install -g pnpm@8.12.1
&& apk add --no-cache make git gcc musl-dev bash
# download go deps
# (cache by separating the downloading of deps)
@@ -16,14 +15,32 @@ RUN go mod download
# copy source code
COPY . .
# build
## build UI
ARG SKIP_UI_BUILD=false
# install ui build toolchain
RUN set -ex \
&& export VERSION=$(git describe --tags --abbrev=0) \
&& export COMMIT_SHA=$(git rev-parse --short HEAD) \
&& if [ "$SKIP_UI_BUILD" = "false" ]; then \
apk add --no-cache nodejs npm \
&& npm install -g pnpm@8.15.6 \
;fi
RUN set -ex \
&& if [ "$SKIP_UI_BUILD" = "false" ]; then \
make build-frontend \
;fi
## build App
ARG APP_VERSION=""
ARG APP_COMMIT_HASH=""
RUN set -ex \
&& if [[ ! -z "$APP_VERSION" ]]; then export VERSION=$APP_VERSION ;fi \
&& if [[ ! -z "$APP_COMMIT_HASH" ]]; then export COMMIT_HASH=$APP_COMMIT_HASH ;fi \
&& make build
### build final image
FROM alpine:3.18
FROM alpine:3.19
# we set the timezone `Asia/Shanghai` by default, you can be modified
# by `docker build --build-arg="TZ=Other_Timezone ..."`
+5 -5
View File
@@ -1,8 +1,7 @@
PKG_NAME := github.com/ArtalkJS/Artalk
BIN_NAME := ./bin/artalk
VERSION ?= $(shell git describe --tags --abbrev=0)
COMMIT_HASH := $(shell git rev-parse --short HEAD)
DEV_VERSION := dev-$(COMMIT_HASH)
VERSION ?= $(shell git describe --tags --abbrev=0 --match 'v*')
COMMIT_HASH ?= $(shell git rev-parse --short HEAD)
HAS_RICHGO := $(shell which richgo)
GOTEST ?= $(if $(HAS_RICHGO), richgo test, go test)
@@ -13,7 +12,7 @@ all: install build
install:
go mod tidy
build: build-frontend
build:
go build \
-ldflags "-s -w -X $(PKG_NAME)/internal/config.Version=$(VERSION) \
-X $(PKG_NAME)/internal/config.CommitHash=$(COMMIT_HASH)" \
@@ -53,7 +52,8 @@ update-i18n:
update-swagger:
go install github.com/swaggo/swag/cmd/swag@latest
swag init -g server/server.go --output ./docs/swagger
swag init -g server/server.go --output ./docs/swagger --requiredByDefault
pnpm -r swagger:build-http-client
docker-build:
./scripts/docker-build.sh
+6 -1
View File
@@ -61,6 +61,9 @@ Reference to:[**Documentation**](https://artalk.js.org/guide/deploy.html)
$ pnpm add artalk
```
<!-- prettier-ignore-start -->
```ts
import Artalk from 'artalk'
@@ -74,6 +77,8 @@ Artalk.init({
})
```
<!-- prettier-ignore-end -->
### Docker
```sh
@@ -94,7 +99,7 @@ vim docker-compose.yaml
```
```yaml
version: "3.5"
version: '3.5'
services:
artalk:
container_name: artalk
+11 -6
View File
@@ -65,16 +65,21 @@
npm install artalk
```
<!-- prettier-ignore-start -->
```ts
import Artalk from 'artalk'
Artalk.init({
el: '#Comments',
site: 'Artalk 的博客',
server: 'https://artalk.example.com'
el: '#Comments',
site: 'Artalk 的博客',
server: 'https://artalk.example.com',
pageKey: '/2018/10/02/hello-world.html'
})
```
<!-- prettier-ignore-end -->
### Docker
```bash
@@ -93,7 +98,7 @@ vim docker-compose.yaml
```
```yaml
version: "3.5"
version: '3.5'
services:
artalk:
container_name: artalk
@@ -123,7 +128,7 @@ see [CONTRIBUTING.md](./CONTRIBUTING.md)
## Repobeats Analytics
![Alt](https://repobeats.axiom.co/api/embed/a9fc9191ac561bc5a8ee2cddc81e635ecaebafb6.svg "Repobeats analytics image")
![Alt](https://repobeats.axiom.co/api/embed/a9fc9191ac561bc5a8ee2cddc81e635ecaebafb6.svg 'Repobeats analytics image')
## 特别致谢
@@ -202,7 +207,7 @@ see [CONTRIBUTING.md](./CONTRIBUTING.md)
- [x] 用户鉴权机制
- [x] 跨域非法请求阻止
- [x] 全局验证码操作次数限制
- [x] JWT 登陆状态验证
- [x] JWT 登录状态验证
- [x] 时区自定义
- [x] 只看作者功能
- [x] 图片上传
+16 -3
View File
@@ -25,14 +25,23 @@ func NewAdminCommand(app *ArtalkCmd) *cobra.Command {
fmt.Println(" " + i18n.T("Create admin account"))
fmt.Println("--------------------------------")
username, email, password, err := credentials()
if err != nil {
log.Fatal(err)
// get from flags
username, _ := cmd.Flags().GetString("name")
email, _ := cmd.Flags().GetString("email")
password, _ := cmd.Flags().GetString("password")
if username == "" || email == "" || password == "" {
var err error
username, email, password, err = credentials()
if err != nil {
log.Fatal(err)
}
}
findUser := app.Dao().FindUser(username, email)
if !findUser.IsEmpty() {
findUser.SetPasswordEncrypt(password)
findUser.IsAdmin = true
if err := app.Dao().UpdateUser(&findUser); err != nil {
log.Fatal(err)
}
@@ -62,6 +71,10 @@ func NewAdminCommand(app *ArtalkCmd) *cobra.Command {
},
}
flag(adminCmd, "name", "", i18n.T("Username"))
flag(adminCmd, "email", "", i18n.T("Email"))
flag(adminCmd, "password", "", i18n.T("Password"))
return adminCmd
}
-2
View File
@@ -30,8 +30,6 @@ func NewImportCommand(app *ArtalkCmd) *cobra.Command {
params := artransfer.ArrToImportParams(payload)
params.Assumeyes, _ = cmd.Flags().GetBool("assumeyes")
artransfer.RunImportArtrans(app.Dao(), params)
log.Info(i18n.T("Import complete"))
},
}
+2 -2
View File
@@ -32,7 +32,7 @@ func NewUpgradeCommand() *cobra.Command {
if !ignoreVersionCheck {
v := semver.MustParse(strings.TrimPrefix(config.Version, "v"))
if !found || latest.Version.LTE(v) {
log.Println(i18n.T("Current version is the latest") + " (v" + v.String() + ")")
log.Info(i18n.T("Current version is the latest") + " (v" + v.String() + ")")
return
}
}
@@ -49,7 +49,7 @@ func NewUpgradeCommand() *cobra.Command {
log.Fatal(i18n.T("Update failed")+" ", err)
}
log.Println(i18n.T("Update complete"))
log.Info(i18n.T("Update complete"))
fmt.Printf("\n"+
"-------------------------------\n"+
" v%s Release Note\n"+
+39 -33
View File
@@ -2,32 +2,36 @@ host: "0.0.0.0"
port: 23366
app_key: ""
debug: false
locale: "en"
timezone: "Asia/Shanghai"
site_default: "Default Site"
locale: en
timezone: Asia/Shanghai
site_default: Default Site
login_timeout: 259200
db:
type: "sqlite"
file: "./data/artalk.db"
type: sqlite
file: ./data/artalk.db
table_prefix: ""
name: "artalk"
host: "localhost"
name: artalk
host: localhost
port: 3306
user: "root"
user: root
password: ""
charset: "utf8mb4"
charset: utf8mb4
ssl: false
prepare_stmt: true
http:
body_limit: 100
proxy_header: ""
log:
enabled: true
filename: "./data/artalk.log"
filename: ./data/artalk.log
cache:
enabled: false
type: "builtin"
type: builtin
expires: 30
warm_up: false
server: ""
redis:
network: "tcp"
network: tcp
username: ""
password: ""
db: 0
@@ -44,23 +48,23 @@ moderator:
enabled: false
secret_id: ""
secret_key: ""
region: "ap-guangzhou"
region: ap-guangzhou
aliyun:
enabled: false
access_key_id: ""
access_key_secret: ""
region: "cn-shanghai"
region: cn-shanghai
keywords:
enabled: false
pending: false
files:
- "./data/keywords_1.txt"
- ./data/keywords_1.txt
file_sep: "\n"
replac_to: "x"
replac_to: x
captcha:
enabled: true
always: false
captcha_type: "image"
captcha_type: image
action_limit: 3
action_reset: 60
turnstile:
@@ -77,31 +81,32 @@ captcha:
captcha_key: ""
img_upload:
enabled: true
path: "./data/artalk-img/"
path: ./data/artalk-img/
max_size: 5
public_path: null
upgit:
enabled: false
exec: "./upgit -c UPGIT_CONF_FILE_PATH -t /artalk-img"
exec: upgit -c UPGIT_CONF_FILE_PATH -t /artalk-img
del_local: true
email:
enabled: false
send_type: "smtp"
send_type: smtp
send_name: "{{reply_nick}}"
send_addr: "noreply@example.com"
send_addr: noreply@example.com
mail_subject: "[{{site_name}}] You got a reply from @{{reply_nick}}"
mail_tpl: "default"
mail_tpl: default
smtp:
host: "smtp.qq.com"
host: smtp.qq.com
port: 587
username: "example@qq.com"
username: example@qq.com
password: ""
ali_dm:
access_key_id: ""
access_key_secret: ""
account_name: "noreply@example.com"
account_name: noreply@example.com
admin_notify:
notify_tpl: "default"
notify_tpl: default
notify_pending: false
noise_mode: false
email:
enabled: true
@@ -114,7 +119,7 @@ admin_notify:
- 7777777
bark:
enabled: false
server: "http://day.app/xxxxxxx/"
server: http://day.app/xxxxxxx/
lark:
enabled: false
webhook_url: ""
@@ -135,14 +140,14 @@ admin_notify:
channel_secret: ""
channel_access_token: ""
receivers:
- "USER_ID_1"
- "GROUP_ID_1"
- USER_ID_1
- GROUP_ID_1
frontend:
placeholder: ""
noComment: ""
sendBtn: ""
editorTravel: true
emoticons: "https://cdn.jsdelivr.net/gh/ArtalkJS/Emoticons/grps/default.json"
emoticons: https://cdn.jsdelivr.net/gh/ArtalkJS/Emoticons/grps/default.json
vote: true
voteDown: false
uaBadge: false
@@ -150,12 +155,12 @@ frontend:
pvEl: "#ArtalkPV"
countEl: "#ArtalkCount"
preview: true
flatMode: "auto"
flatMode: auto
nestMax: 2
nestSort: DATE_ASC
gravatar:
mirror: "https://www.gravatar.com/avatar/"
params: "d=mp&s=240"
mirror: https://www.gravatar.com/avatar/
params: d=mp&s=240
pagination:
pageSize: 20
readMore: true
@@ -166,3 +171,4 @@ frontend:
scrollable: false
reqTimeout: 15000
versionCheck: true
pluginURLs: []
+47 -34
View File
@@ -12,14 +12,14 @@ debug: false
# Language (follow Unicode BCP 47) ["en", "zh-CN", "zh-TW", "jp"]
# -- see https://www.techonthenet.com/js/language_tags.php --
locale: "en"
locale: en
# Timezone (follow IANA Time Zone Database)
# -- see https://en.wikipedia.org/wiki/List_of_tz_database_time_zones --
timezone: "Asia/Shanghai"
timezone: Asia/Shanghai
# Default site name (create when app is first launched)
site_default: "Default Site"
site_default: Default Site
# Login timeout (in seconds)
login_timeout: 259200
@@ -27,40 +27,49 @@ login_timeout: 259200
# Database
db:
# Database type ["sqlite", "mysql", "pgsql", "mssql"]
type: "sqlite"
type: sqlite
# Database file (only for SQLite)
file: "./data/artalk.db"
file: ./data/artalk.db
# Table prefix (e.g. "atk_")
table_prefix: ""
# -- The following is not necessary for SQLite --
# Database name
name: "artalk"
name: artalk
# Host address
host: "localhost"
host: localhost
# Host port
port: 3306
# Database user
user: "root"
user: root
# Database password
password: ""
# Database charset
charset: "utf8mb4"
charset: utf8mb4
# Enable SSL mode
ssl: false
# Prepared Statement
prepare_stmt: true
# Web server
http:
# Body size limit (unit: MB)
body_limit: 100
# Proxy Header (fill `X-Forwarded-For` to get user real IP if behind a trusted reverse proxy or CDN)
proxy_header: ""
# Logging
log:
# Enable logging
enabled: true
# Log file path
filename: "./data/artalk.log"
filename: ./data/artalk.log
# Cache
cache:
# Enable cache
enabled: false
# Cache type ["redis", "memcache", "builtin"]
type: "builtin"
type: builtin
# Cache expiration time (in minutes)
expires: 30
# Cache warm up (warm up cache when program starts)
@@ -71,7 +80,7 @@ cache:
# Redis config
redis:
# Connection type ["tcp", "unix"]
network: "tcp"
network: tcp
# Redis username
username: ""
# Redis password
@@ -111,7 +120,7 @@ moderator:
enabled: false
secret_id: ""
secret_key: ""
region: "ap-guangzhou"
region: ap-guangzhou
# Aliyun Content Security
# (Auto review comments with Aliyun Content Security)
# -- see https://help.aliyun.com/document_detail/28417.html --
@@ -119,7 +128,7 @@ moderator:
enabled: false
access_key_id: ""
access_key_secret: ""
region: "cn-shanghai"
region: cn-shanghai
# Keyword filter (local offline dictionary)
keywords:
# Enable keyword filter
@@ -128,9 +137,9 @@ moderator:
pending: false
# Dictionary file (support multiple dictionary files)
files:
- "./data/keywords_1.txt"
- ./data/keywords_1.txt
file_sep: "\n"
replac_to: "x"
replac_to: x
# Captcha
captcha:
@@ -139,7 +148,7 @@ captcha:
# Captcha is required always
always: false
# Captcha type ["image", "turnstile", "recaptcha", "hcaptcha", "geetest"]
captcha_type: "image"
captcha_type: image
# Action limit
# (the number of actions required to activate captcha)
action_limit: 3
@@ -169,7 +178,7 @@ img_upload:
# Enable image upload
enabled: true
# Image storage
path: "./data/artalk-img/"
path: ./data/artalk-img/
# Image size limit (unit: MB)
max_size: 5
# Image link base path (default: "/static/images/")
@@ -179,7 +188,7 @@ img_upload:
# Enable Upgit
enabled: false
# Command line arguments
exec: "./upgit -c UPGIT_CONF_FILE_PATH -t /artalk-img"
exec: upgit -c UPGIT_CONF_FILE_PATH -t /artalk-img
# Delete local image after upload success
del_local: true
@@ -188,23 +197,23 @@ email:
# Enable email notification
enabled: false
# Send method ["smtp", "ali_dm", "sendmail"]
send_type: "smtp"
send_type: smtp
# Nick name of sender
send_name: "{{reply_nick}}"
# Email address of sender
send_addr: "noreply@example.com"
send_addr: noreply@example.com
# Email subject
mail_subject: "[{{site_name}}] You got a reply from @{{reply_nick}}"
# Email template file (set to file path to use custom template)
mail_tpl: "default"
mail_tpl: default
# SMTP send (set send method to "smtp" to enable)
smtp:
# Email address of sender
host: "smtp.qq.com"
host: smtp.qq.com
# Email port
port: 587
# Email address of sender
username: "example@qq.com"
username: example@qq.com
# Password
password: ""
# Aliyun mail push
@@ -212,12 +221,14 @@ email:
ali_dm:
access_key_id: ""
access_key_secret: ""
account_name: "noreply@example.com"
account_name: noreply@example.com
# Multi-push
# Multi-Push
admin_notify:
# Notification template (set to file path to use custom template)
notify_tpl: "default"
notify_tpl: default
# Pending comment still send notification (notifications are still sent when comments are intercepted)
notify_pending: false
# Noise mode
# -- noise_mode is disabled by default. --
# -- When this option is set to `false`, only messages sent to the administrator will be notified, --
@@ -240,7 +251,7 @@ admin_notify:
# Bark
bark:
enabled: false
server: "http://day.app/xxxxxxx/"
server: http://day.app/xxxxxxx/
lark:
enabled: false
webhook_url: ""
@@ -264,8 +275,8 @@ admin_notify:
channel_secret: ""
channel_access_token: ""
receivers:
- "USER_ID_1"
- "GROUP_ID_1"
- USER_ID_1
- GROUP_ID_1
# UI Settings
frontend:
@@ -278,7 +289,7 @@ frontend:
# Movable comment box
editorTravel: true
# Emoticons
emoticons: "https://cdn.jsdelivr.net/gh/ArtalkJS/Emoticons/grps/default.json"
emoticons: https://cdn.jsdelivr.net/gh/ArtalkJS/Emoticons/grps/default.json
# Vote button
vote: true
# Dislike button
@@ -294,7 +305,7 @@ frontend:
# Editor real-time preview
preview: true
# Flatten mode ["auto", true, false]
flatMode: "auto"
flatMode: auto
# Maximum nesting level
nestMax: 2
# Nesting comment sorting rules ["DATE_ASC", "DATE_DESC", "VOTE_UP_DESC"]
@@ -302,9 +313,9 @@ frontend:
# Gravatar
gravatar:
# API URL
mirror: "https://www.gravatar.com/avatar/"
mirror: https://www.gravatar.com/avatar/
# API parameters
params: "d=mp&s=240"
params: d=mp&s=240
# Comment pagination
pagination:
# Number of comments per page
@@ -325,3 +336,5 @@ frontend:
reqTimeout: 15000
# Version check
versionCheck: true
# Plugins
pluginURLs: []
+53 -40
View File
@@ -11,53 +11,62 @@ app_key: ""
debug: false
# 语言 ["en", "zh-CN", "zh-TW", "jp"]
locale: "zh-CN"
locale: zh-CN
# 时间区域
timezone: "Asia/Shanghai"
timezone: Asia/Shanghai
# 默认站点名
site_default: "默认站点"
site_default: 默认站点
# 登陆有效时长 (单位:秒)
# 登录有效时长 (单位:秒)
login_timeout: 259200
# 数据库
db:
# 数据库类型 ["sqlite", "mysql", "pgsql", "mssql"]
type: "sqlite"
type: sqlite
# 数据库文件 (仅 SQLite 数据库需填写)
file: "./data/artalk.db"
file: ./data/artalk.db
# 数据库名称
name: "artalk"
name: artalk
# 数据库地址
host: "localhost"
host: localhost
# 数据库端口
port: 3306
# 数据库账户
user: "root"
user: root
# 数据库密码
password: ""
# 编码格式
charset: "utf8mb4"
charset: utf8mb4
# 表前缀 (例如:"atk_")
table_prefix: ""
# 启用 SSL
ssl: false
# 预编译语句
prepare_stmt: true
# 服务器
http:
# 请求体大小限制 (单位:MB)
body_limit: 100
# 代理标头名 (当使用 CDN 时填写 `X-Forwarded-For` 获取用户真实 IP)
proxy_header: ""
# 日志
log:
# 启用日志
enabled: true
# 日志文件路径
filename: "./data/artalk.log"
filename: ./data/artalk.log
# 缓存
cache:
# 启用缓存
enabled: false
# 缓存类型 ["redis", "memcache", "builtin"]
type: "builtin"
type: builtin
# 缓存过期时间 (单位:分钟)
expires: 30
# 缓存启动预热 (程序启动时预热缓存)
@@ -67,7 +76,7 @@ cache:
# Redis 配置
redis:
# 连接方式 ["tcp", "unix"]
network: "tcp"
network: tcp
# 用户名
username: ""
# 密码
@@ -110,14 +119,14 @@ moderator:
enabled: false
secret_id: ""
secret_key: ""
region: "ap-guangzhou"
region: ap-guangzhou
# 阿里云内容安全
# (https://help.aliyun.com/document_detail/28417.html)
aliyun:
enabled: false
access_key_id: ""
access_key_secret: ""
region: "cn-shanghai"
region: cn-shanghai
# 关键词过滤 (本地离线词库)
keywords:
enabled: false
@@ -125,11 +134,11 @@ moderator:
pending: false
# 词库文件 (支持多个词库文件)
files:
- "./data/词库_1.txt"
- ./data/词库_1.txt
# 词库文件内容分割符 (例如填写 "\n" 文件中一行一个关键词)
file_sep: "\n"
# 替换字符
replac_to: "x"
replac_to: x
# 验证码
captcha:
@@ -138,7 +147,7 @@ captcha:
# 总是需要验证码
always: false
# 验证类型 ["image", "turnstile", "recaptcha", "hcaptcha", "geetest"]
captcha_type: "image"
captcha_type: image
# 激活验证码所需操作次数
action_limit: 3
# 重置操作计数器超时 (单位:s, 设为 -1 不重置)
@@ -162,21 +171,21 @@ captcha:
captcha_id: ""
captcha_key: ""
# IP 归属地
# IP 属地
ip_region:
# 启用 IP 归属地展示
# 启用 IP 属地展示
enabled: false
# 数据文件路径 (.xdb 格式)
db_path: "./data/ip2region.xdb"
db_path: ./data/ip2region.xdb
# 显示精度 ["province", "city", "country"]
precision: "province"
precision: province
# 图片上传
img_upload:
# 启用图片上传
enabled: true
# 图片存放路径
path: "./data/artalk-img/"
path: ./data/artalk-img/
# 图片大小限制 (单位:MB)
max_size: 5
# 图片链接基础路径 (默认为 "/static/images/")
@@ -187,7 +196,7 @@ img_upload:
# 启用 Upgit
enabled: false
# 命令行参数
exec: "./upgit -c <upgit配置文件路径> -t /artalk-img"
exec: upgit -c <upgit配置文件路径> -t /artalk-img
# 上传后删除本地的图片
del_local: true
@@ -196,23 +205,23 @@ email:
# 启用邮件通知
enabled: false
# 发送方式 ["smtp", "ali_dm", "sendmail"]
send_type: "smtp"
send_type: smtp
# 发信人昵称
send_name: "{{reply_nick}}"
# 发信人地址
send_addr: "noreply@example.com"
send_addr: noreply@example.com
# 邮件标题
mail_subject: "[{{site_name}}] 您收到了来自 @{{reply_nick}} 的回复"
# 邮件模板文件 (填入文件路径使用自定义模板)
mail_tpl: "default"
mail_tpl: default
# SMTP 发送 (启用请将发送方式设为 "smtp")
smtp:
# 发件地址
host: "smtp.qq.com"
host: smtp.qq.com
# 发件端口
port: 587
# 用户名
username: "example@qq.com"
username: example@qq.com
# 密码
password: ""
# 阿里云邮件推送
@@ -220,12 +229,14 @@ email:
ali_dm:
access_key_id: ""
access_key_secret: ""
account_name: "noreply@example.com"
account_name: noreply@example.com
# 多元推送
admin_notify:
# 通知模版 (填入文件路径使用自定义模板)
notify_tpl: "default"
notify_tpl: default
# 待审评论仍然发送通知 (当评论被拦截时仍然发送通知)
notify_pending: false
# 嘈杂模式
noise_mode: false
# 邮件通知管理员
@@ -245,7 +256,7 @@ admin_notify:
# Bark
bark:
enabled: false
server: "http://day.app/xxxxxxx/"
server: http://day.app/xxxxxxx/
# 飞书
lark:
enabled: false
@@ -264,17 +275,17 @@ admin_notify:
enabled: false
oauth_token: ""
receivers:
- "CHANNEL_ID"
- CHANNEL_ID
# LINE
line:
enabled: false
channel_secret: ""
channel_access_token: ""
receivers:
- "USER_ID_1"
- "GROUP_ID_1"
- USER_ID_1
- GROUP_ID_1
# 前端配置
# 界面配置
frontend:
# 评论框占位文字
placeholder: ""
@@ -285,7 +296,7 @@ frontend:
# 评论框穿梭
editorTravel: true
# 表情包
emoticons: "https://cdn.jsdelivr.net/gh/ArtalkJS/Emoticons/grps/default.json"
emoticons: https://cdn.jsdelivr.net/gh/ArtalkJS/Emoticons/grps/default.json
# 投票按钮
vote: true
# 反对按钮
@@ -301,7 +312,7 @@ frontend:
# 编辑器实时预览功能
preview: true
# 平铺模式 ["auto", true, false]
flatMode: "auto"
flatMode: auto
# 最大嵌套层数
nestMax: 2
# 嵌套评论排序规则 ["DATE_ASC", "DATE_DESC", "VOTE_UP_DESC"]
@@ -309,9 +320,9 @@ frontend:
# 头像 Gravatar
gravatar:
# API 地址
mirror: "https://cravatar.cn/avatar/"
mirror: https://cravatar.cn/avatar/
# API 参数
params: "d=mp&s=240"
params: d=mp&s=240
# 评论分页
pagination:
# 每页评论数
@@ -332,3 +343,5 @@ frontend:
reqTimeout: 15000
# 版本检测
versionCheck: true
# 插件
pluginURLs: []
+2 -2
View File
@@ -14,11 +14,11 @@ if [ "$1" != 'gen' ] && ( [ ! -e /data/artalk.yml ] && [ ! -e /data/artalk-go.ym
upMsg+=$'# please unmount the config file volume from your container\n'
upMsg+=$'# and edit "/data/artalk.yml" for configuration.'
echo "$upMsg" > /conf.yml
echo "$(date) [info] Copy config file from '/conf.yml' to '/data/artalk.yml' for upgrade"
echo "$(date) [info][docker] Copy config file from '/conf.yml' to '/data/artalk.yml' for upgrade"
else
# Generate new config
artalk gen conf /data/artalk.yml
echo "$(date) [info] Generate new config file to '/data/artalk.yml'"
echo "$(date) [info][docker] Generate new config file to '/data/artalk.yml'"
fi
fi
-3
View File
@@ -1,3 +0,0 @@
/.vitepress/dist/
/.vitepress/cache/
/public/http-api.html
-2
View File
@@ -1,2 +0,0 @@
shamefully-hoist=true
auto-install-peers=true
-95
View File
@@ -1,95 +0,0 @@
<template>
<ClientOnly>
<div ref="el" style="margin-top: 20px;"></div>
</ClientOnly>
</template>
<script setup lang="ts">
import { watch, nextTick, ref, onMounted, onUnmounted } from 'vue'
import { useData, useRouter } from 'vitepress'
import type Artalk from 'artalk'
const el = ref<HTMLElement | null>(null)
const router = useRouter()
const page = useData().page
let artalk: Artalk
onMounted(() => {
initArtalk(getConfByPage())
})
watch(() => router.route.data.relativePath, () => {
nextTick(() => {
artalk.update(getConfByPage())
artalk.reload()
})
})
onUnmounted(() => {
artalk.destroy()
})
function initArtalk(conf: any) {
import('artalk').then(({ default: Artalk }) => {
artalk = Artalk.init({
el: el.value,
emoticons: '/assets/emoticons/default.json',
gravatar: {
mirror: 'https://cravatar.cn/avatar/'
},
...conf
})
}).then(() => {
loadExtraFuncs()
})
}
function getConfByPage() {
return {
pageKey: 'https://artalk.js.org'+location.pathname,
pageTitle: page.value.title,
server: 'https://artalk.qwqaq.com',
site: 'ArtalkDocs',
}
}
function loadExtraFuncs() {
// 图片灯箱插件
artalk.on('list-loaded', () => {
document.querySelectorAll('.atk-comment .atk-content').forEach(($content) => {
const imgEls = $content.querySelectorAll<HTMLImageElement>('img:not([atk-emoticon]):not([atk-lightbox])');
imgEls.forEach((imgEl) => {
imgEl.setAttribute('atk-lightbox', '')
const linkEl = document.createElement('a')
linkEl.setAttribute('class', 'atk-img-link')
linkEl.setAttribute('href', imgEl.src)
linkEl.setAttribute('data-src', imgEl.src)
linkEl.append(imgEl.cloneNode())
imgEl.replaceWith(linkEl)
})
// @ts-ignore
if (imgEls.length) lightGallery($content, { selector: '.atk-img-link' })
})
})
// 夜间模式
const darkMode = document.querySelector('html').classList.contains('dark')
artalk.setDarkMode(darkMode)
new MutationObserver((mList) => {
mList.forEach((m) => {
if (m.attributeName !== 'class') return
// @ts-ignore
const darkMode = m.target.classList.contains('dark')
artalk.setDarkMode(darkMode)
})
}).observe(document.querySelector('html'), { attributes: true })
}
</script>
<style>
</style>
-5
View File
@@ -1,5 +0,0 @@
declare module '*.vue' {
import { defineComponent } from 'vue';
const component: ReturnType<typeof defineComponent>;
export default component;
}
-3
View File
@@ -1,3 +0,0 @@
{
"latest": "2.7.1"
}
-592
View File
@@ -1,592 +0,0 @@
# HTTP API
::: warning
该 HTTP API 文档已过时
:::
::: tip 无特殊说明时 API 调用响应格式
| 字段名 | 类型 | 说明 |
| ----- | ------- | --- |
| `success` | Boolean | 接口调用结果 |
| `msg` | String | 返回消息,出错时此字段包含错误消息 |
| `data` | Any | 返回数据,可能为 Object / String / Array 类型 |
:::
## Normal API
### 评论新增
**POST** `/api/add`
**参数**
| 字段名 | 数据类型 | 必需 | 说明 |
| ----- | ------- | :---: | --- |
| `name` | String | 是 | 待新增评论者昵称 |
| `email` | String | 是 | 待新增评论者邮箱 |
| `link` | String | 否 | 待新增评论者链接 |
| `content` | String | 是 | 待新增评论内容 |
| `rid` | Number | 否 | 待新增评论为回复评论时传入父评论 `ID`,否则为 `0` |
| `page_key` | String | 是 | 待新增评论目标页面唯一标识符 |
| `page_title` | String | 否 | 待新增评论目标页面标题 |
| `token` | String | 否 | 评论请求 Token |
| `site_name` | String | 否 | 待新增评论目标站点名称 |
**响应**
| 字段名 | 数据类型 | 默认 | 说明 |
| ----- | ------- | :-: | --- |
| `success` | Boolean | `true` | 评论新增成功 |
| `data.comment` | Object | - | 评论数据 |
| `data.comment.id` | Number | - | 评论 ID |
| `data.comment.content` | String | - | 评论正文 |
| `data.comment.nick` | String | - | 评论者昵称 |
| `data.comment.email_encrypted` | String | - | 评论者邮箱 MD5 加密值 |
| `data.comment.link` | String | - | 评论者链接 |
| `data.comment.ua` | String | - | 评论者 User-Agent |
| `data.comment.date` | String | - | 评论时间,格式为 `1970-01-01 00:00:00` |
| `data.comment.is_collapsed` | Boolean | - | 评论是否折叠 |
| `data.comment.is_pending` | Boolean | - | 评论是否待审 |
| `data.comment.is_allow_reply` | Boolean | - | 评论是否允许回复 |
| `data.comment.rid` | Number | `0` | 待新增评论为回复评论时返回父评论 `ID` |
| `data.comment.badge_name` | String | - | 评论者徽章文字 |
| `data.comment.badge_color` | String | - | 评论者徽章颜色 |
| `data.comment.visible` | Boolean | `true` | 评论是否可见 |
| `data.comment.vote_up` | Number | `0` | 评论赞同数 |
| `data.comment.vote_down` | Number | `0` | 评论反对数 |
| `data.comment.page_key` | String | - | 评论所在页面唯一标识符 |
| `data.comment.site_name` | String | - | 评论所在站点名称 |
### 评论获取
**POST** `/api/get`
**参数**
| 字段名 | 数据类型 | 必需 | 说明 |
| ----- | ------- | :---: | --- |
| `page_key` | String | 是 | 待获取评论页面的唯一标识符 |
| `limit` | Number | 否 | 待获取评论的数量限制 |
| `offset` | Number | 否 | 待获取评论的起始位置偏移 |
| `type` | String | 否 | 获取指定类型的评论 |
| `name` | String | 否 | 获取指定昵称的评论 |
| `email` | String | 否 | 获取指定邮箱的评论 |
| `site_name` | String | 否 | 获取指定站点名称的评论 |
| `flat_mode` | Boolean | 否 | 待获取评论是否平铺模式 |
**响应**
| 字段名 | 数据类型 | 默认 | 说明 |
| ----- | ------- | :-: | --- |
| `success` | Boolean | `true` | 评论获取成功 |
| `data.comments` | Array | - | 页面评论数据 |
| `data.total` | Number | - | 页面评论总数(包括所有子评论) |
| `data.total_parents` | Number | - | 页面评论中父级评论总数 |
| `data.page` | Object | - | 页面数据 |
| `data.page.id` | Number | - | 页面 ID |
| `data.page.admin_only` | Boolean | - | 页面是否仅管理员可评论 |
| `data.page.key` | String | - | 页面唯一标识符 |
| `data.page.url` | String | - | 页面链接 |
| `data.page.title` | String | - | 页面标题 |
| `data.page.site_name` | String | - | 页面所在站点名称 |
| `data.page.vote_up` | Number | - | 页面赞同数 |
| `data.page.vote_down` | Number | - | 页面反对数 |
| `data.unread` | Array | - | 未读的评论提醒数据 |
| `data.unread_count` | Number | - | 未读的评论提醒数据总数 |
| `data.api_version` | Object | - | 目标 Artalk 后端版本数据 |
::: tip
- `data.comments` 数组中元素结构参考 [评论新增接口](#评论新增) `/api/add` 响应的 `data.comment`
- `data.unread` 数组中元素结构如下
| 字段名 | 数据类型 | 默认 | 说明 |
| ----- | ------- | :-: | --- |
| `id` | Number | - | 评论提醒 ID |
| `user_id` | Number | - | 评论提醒目标用户 ID |
| `comment_id` | Number | - | 评论提醒来源评论 ID |
| `is_read` | Boolean | - | 评论提醒是否已读 |
| `is_emailed` | Boolean | - | 评论提醒是否已发送邮件 |
| `read_link` | String | - | 评论提醒已读地址 |
- `data.api_version` 对象结构参考 [Artalk 版本接口](#artalk-版本) `/api/version` 响应
:::
### 用户获取
**POST** `/api/user-get`
**参数**
| 字段名 | 数据类型 | 必需 | 说明 |
| ----- | ------- | :---: | --- |
| `name` | String | 否 | 待获取用户的昵称 |
| `email` | String | 否 | 待获取用户的邮箱 |
**响应**
| 字段名 | 数据类型 | 默认 | 说明 |
| ----- | ------- | :-: | --- |
| `success` | Boolean | `true` | 用户获取成功 |
| `data.user` | Object | `null` | 获取的用户数据,若用户不存在返回空 |
| `data.user.id` | Number | - | 用户 ID |
| `data.user.name` | String | - | 用户昵称 |
| `data.user.email` | String | - | 用户邮箱 |
| `data.user.link` | String | - | 用户链接 |
| `data.user.badge_name` | String | - | 用户徽章文字 |
| `data.user.badge_color` | String | - | 用户徽章颜色 |
| `data.user.is_admin` | Boolean | - | 用户是否管理员 |
| `data.is_login` | Boolean | - | 用户是否登录 |
| `data.unread` | Array | `[]` | 用户未读的评论提醒数据 |
| `data.unread_count` | Number | `0` | 用户未读的评论提醒数据总数 |
::: tip
- `data.unread` 数组中元素结构参考 [评论获取接口](#评论获取) `/api/get` **TIP**
:::
### 用户登录
**GET/POST** `/api/login`
**参数**
| 字段名 | 数据类型 | 必需 | 说明 |
| ----- | ------- | :---: | --- |
| `name` | String | 是 | 待登录用户的昵称 |
| `email` | String | 是 | 待登录用户的邮箱 |
| `password` | String | 是 | 待登录用户的密码(管理员身份验证) |
**响应**
| 字段名 | 数据类型 | 默认 | 说明 |
| ----- | ------- | :-: | --- |
| `success` | Boolean | `true` | 用户登录成功 |
| `data.token` | String | - | 登录的用户 Token |
### 提醒已读
**POST** `/api/mark-read`
**参数**
| 字段名 | 数据类型 | 必需 | 说明 |
| ----- | ------- | :---: | --- |
| `notify_key` | String | 否 | 评论提醒唯一标识符 |
| `name` | String | 否 | 评论提醒用户的昵称 |
| `email` | String | 否 | 评论提醒用户的邮箱 |
| `all_read` | Boolean | 否 | 评论提醒是否已读 |
| `site_name` | String | 否 | 评论提醒所在站点名称 |
**响应**
| 字段名 | 数据类型 | 默认 | 说明 |
| ----- | ------- | :-: | --- |
| `success` | Boolean | `true` | 提醒已读成功 |
### 评论投票
**POST** `/api/vote`
**参数**
| 字段名 | 数据类型 | 必需 | 说明 |
| ----- | ------- | :---: | --- |
| `target_id` | Number | 是 | 待投票评论 ID |
| `type` | String | 否 | 待投票类型,前缀 `comment_`、`page_` 依次代表对评论投票、对页面投票,后缀 `_up`、`_down` 依次代表赞同、反对 |
| `name` | String | 否 | 投票用户昵称 |
| `email` | String | 否 | 投票用户邮箱 |
| `site_name` | String | 否 | 投票目标评论或页面所在站点名称 |
**响应**
| 字段名 | 数据类型 | 默认 | 说明 |
| ----- | ------- | :-: | --- |
| `success` | Boolean | `true` | 评论投票成功 |
| `data.vote_num` | Number | - | 目标评论或页面指定类型投票数据 |
### Artalk 版本
::: warning
此接口较特殊,返回结果不包含 `success`、`msg`、`data` 字段,直接返回包含指定字段的 JSON。
:::
**GET/POST** `/api/version`
**参数** 无
**响应**
| 字段名 | 数据类型 | 默认 | 说明 |
| ----- | ------- | :-: | --- |
| `app` | String | `artalk` | Artalk 后端程序名 |
| `version` | String | - | Artalk 后端程序版本号 |
| `commit_hash` | String | - | Artalk 后端程序 Git 提交哈希值 |
| `fe_min_version` | String | - | Artalk 后端程序所需前端最低版本 |
## Captcha API
### 验证码刷新
**GET** `/api/captcha/refresh`
**参数** 无
**响应**
| 字段名 | 数据类型 | 默认 | 说明 |
| ----- | ------- | :-: | --- |
| `success` | Boolean | `true` | 验证码刷新成功 |
| `data.img_data` | String | - | 根据 IP 获取的验证码图片 Base64 编码 |
### 验证码检验
**GET** `/api/captcha/check`
**参数**
| 字段名 | 数据类型 | 必需 | 说明 |
| ----- | ------- | :---: | --- |
| `value` | String | 是 | 验证码 |
**响应**
| 字段名 | 数据类型 | 默认 | 说明 |
| ----- | ------- | :-: | --- |
| `success` | Boolean | `true` | 验证码检验成功 |
| `data.img_data` | String | - | 新的验证码图片 Base64 编码,仅验证码检验出错时存在此字段 |
## Admin API
### 评论编辑
**POST** `/api/admin/comment-edit`
**参数**
| 字段名 | 数据类型 | 必需 | 说明 |
| ----- | ------- | :---: | --- |
| `id` | Number | 是 | 待编辑评论 ID,**不可修改** |
| `site_name` | String | 否 | 待编辑评论所在站点名称,**不可修改** |
| `content` | String | 否 | 待编辑评论正文 |
| `page_key` | String | 否 | 待编辑评论所在页面唯一标识符 |
| `nick` | String | 否 | 待编辑评论所属用户昵称 |
| `email` | String | 否 | 待编辑评论所属用户邮箱 |
| `link` | String | 否 | 待编辑评论所属用户链接 |
| `rid` | String | 否 | 待编辑评论为回复评论时传入父评论 `ID`,否则为 `0` |
| `ua` | String | 否 | 待编辑评论所属用户 User-Agent |
| `ip` | String | 否 | 待编辑评论所属用户 IP |
| `is_collapsed` | Boolean | 否 | 待编辑评论是否折叠 |
| `is_pending` | Boolean | 否 | 待编辑评论是否待审 |
**响应**
| 字段名 | 数据类型 | 默认 | 说明 |
| ----- | ------- | :-: | --- |
| `success` | Boolean | `true` | 评论编辑成功 |
| `data.comment` | Object | - | 编辑评论的新数据 |
::: tip
- `data.comment` 对象结构参考 [评论新增接口](#评论新增) `/api/add` 响应的 `data.comment`
:::
### 评论删除
::: danger
此接口不推荐外部调用。
调用此接口前请务必核实评论 ID,一旦调用成功将删除该评论下所有相关数据。
:::
**POST** `/api/admin/comment-del`
**参数**
| 字段名 | 数据类型 | 必需 | 说明 |
| ----- | ------- | :---: | --- |
| `id` | Number | 是 | 待删除评论 ID |
| `site_name` | String | 是 | 待删除评论所在站点名称 |
**响应**
| 字段名 | 数据类型 | 默认 | 说明 |
| ----- | ------- | :-: | --- |
| `success` | Boolean | `true` | 评论删除成功 |
### 页面获取
**POST** `/api/admin/page-get`
**参数**
| 字段名 | 数据类型 | 必需 | 说明 |
| ----- | ------- | :---: | --- |
| `site_name` | String | 是 | 待获取页面目标站点名称 |
**响应**
| 字段名 | 数据类型 | 默认 | 说明 |
| ----- | ------- | :-: | --- |
| `success` | Boolean | `true` | 页面获取成功 |
| `data.pages` | Array | - | 目标站点的页面数据 |
| `data.sites` | Array | - | 所有站点数据 |
::: tip
- `data.pages` 数组中元素结构参考 [评论获取接口](#评论获取) `/api/get` 响应的 `data.page`
- `data.sites` 数组中元素结构参考 [站点编辑接口](#站点编辑) `/api/admin/site-edit` 响应的 `data.site`
:::
### 页面编辑
**POST** `/api/admin/page-edit`
**参数**
| 字段名 | 数据类型 | 必需 | 说明 |
| ----- | ------- | :---: | --- |
| `id` | Number | 是 | 待编辑页面 ID,**不可修改** |
| `site_name` | String | 否 | 待编辑页面所在站点名称,**不可修改** |
| `key` | String | 否 | 待编辑页面唯一标识符 |
| `title` | String | 否 | 待编辑页面标题 |
| `admin_only` | Boolean | 否 | 待编辑页面是否仅管理员可评论 |
**响应**
| 字段名 | 数据类型 | 默认 | 说明 |
| ----- | ------- | :-: | --- |
| `success` | Boolean | `true` | 页面编辑成功 |
| `data.page` | Object | - | 编辑页面的新数据 |
::: tip
- `data.page` 对象结构参考 [评论获取接口](#评论获取) `/api/get` 响应的 `data.page`
:::
### 页面删除
::: danger
此接口不推荐外部调用。
调用此接口前请务必核实页面 ID,一旦调用成功将删除该页面下所有相关数据。
:::
**POST** `/api/admin/page-del`
**参数**
| 字段名 | 数据类型 | 必需 | 说明 |
| ----- | ------- | :---: | --- |
| `key` | String | 是 | 待删除页面唯一标识符 |
| `site_name` | String | 是 | 待删除页面所在站点名称 |
**响应**
| 字段名 | 数据类型 | 默认 | 说明 |
| ----- | ------- | :-: | --- |
| `success` | Boolean | `true` | 页面删除成功 |
### 页面更新
**POST** `/api/admin/page-fetch`
**参数**
| 字段名 | 数据类型 | 必需 | 说明 |
| ----- | ------- | :---: | --- |
| `id` | Number | 是 | 待更新页面 ID |
**响应**
| 字段名 | 数据类型 | 默认 | 说明 |
| ----- | ------- | :-: | --- |
| `success` | Boolean | `true` | 页面更新成功 |
| `data.page` | Object | - | 更新页面的新数据 |
::: tip
- `data.page` 对象结构参考 [评论获取接口](#评论获取) `/api/get` 响应的 `data.page`
:::
### 站点获取
**POST** `/api/admin/site-get`
**参数** 无
**响应**
| 字段名 | 数据类型 | 默认 | 说明 |
| ----- | ------- | :-: | --- |
| `success` | Boolean | `true` | 站点获取成功 |
| `data.sites` | Array | - | 所有站点数据 |
::: tip
- `data.sites` 数组中元素结构参考 [站点编辑接口](#站点编辑) `/api/admin/site-edit` 响应的 `data.site`
:::
### 站点新增
**POST** `/api/admin/site-add`
**参数**
| 字段名 | 数据类型 | 必需 | 说明 |
| ----- | ------- | :---: | --- |
| `name` | String | 是 | 待新增站点名称 |
| `urls` | String | 是 | 待新增站点链接,如有多个需以英文半角符号 `,` 分割 |
**响应**
| 字段名 | 数据类型 | 默认 | 说明 |
| ----- | ------- | :-: | --- |
| `success` | Boolean | `true` | 站点新增成功 |
| `data.site` | Object | - | 新增站点的数据 |
| `data.site.id` | Number | - | 站点 ID |
| `data.site.name` | String | - | 站点名称 |
| `data.site.urls` | Array | - | 站点链接数组,元素为单个站点链接字符串 |
| `data.site.urls_raw` | String | - | 站点链接数组合并字符串,以英文半角符号 `,` 分割 |
| `data.site.first_url` | String | - | 站点第一链接 |
### 站点编辑
**POST** `/api/admin/site-edit`
**参数**
| 字段名 | 数据类型 | 必需 | 说明 |
| ----- | ------- | :---: | --- |
| `id` | Number | 是 | 待编辑站点 ID |
| `name` | String | 是 | 待编辑站点新名称 |
| `urls` | String | 是 | 待编辑站点新链接 |
**响应**
| 字段名 | 数据类型 | 默认 | 说明 |
| ----- | ------- | :-: | --- |
| `success` | Boolean | `true` | 站点编辑成功 |
| `data.site` | Object | - | 编辑站点的新数据 |
| `data.site.id` | Number | - | 站点 ID |
| `data.site.name` | String | - | 站点名称 |
| `data.site.urls` | Array | - | 站点链接数组,元素为单个站点链接字符串 |
| `data.site.urls_raw` | String | - | 站点链接数组合并字符串,以英文半角符号 `,` 分割 |
| `data.site.first_url` | String | - | 站点第一链接 |
### 站点删除
::: danger
此接口不推荐外部调用。
调用此接口前请务必核实站点 ID,一旦调用成功将删除该站点下所有相关数据。
:::
**POST** `/api/admin/site-del`
**参数**
| 字段名 | 数据类型 | 必需 | 说明 |
| ----- | ------- | :---: | --- |
| `id` | Number | 是 | 待删除站点 ID |
| `del_content` | Boolean | 否 | 是否删除站点所有数据,为 `false` 时仅删除站点配置而保留站点评论数据 |
**响应**
| 字段名 | 数据类型 | 默认 | 说明 |
| ----- | ------- | :-: | --- |
| `success` | Boolean | `true` | 站点删除成功 |
### 设置获取
**POST** `/api/admin/setting-get`
**参数**
| 字段名 | 数据类型 | 必需 | 说明 |
| ----- | ------- | :---: | --- |
| `id` | Number | 是 | 管理员用户 ID |
| `name` | String | 否 | 管理员用户昵称 |
| `url` | String | 否 | 管理员用户链接 |
**响应**
| 字段名 | 数据类型 | 默认 | 说明 |
| ----- | ------- | :-: | --- |
| `success` | Boolean | `true` | 设置获取成功 |
### 设置保存
**POST** `/api/admin/setting-save`
**参数**
| 字段名 | 数据类型 | 必需 | 说明 |
| ----- | ------- | :---: | --- |
| `id` | Number | 是 | 管理员用户 ID |
| `name` | String | 否 | 管理员用户昵称 |
| `url` | String | 否 | 管理员用户链接 |
**响应**
| 字段名 | 数据类型 | 默认 | 说明 |
| ----- | ------- | :-: | --- |
| `success` | Boolean | `true` | 设置保存成功 |
### 邮件发送
::: warning
页面收到评论、评论收到回复等满足需要发送邮件提醒条件时,后端将自动向目标地址发送邮件提醒,不需手动处理邮件发送。请勿滥用此接口。
:::
**POST** `/api/admin/send-mail`
**参数**
| 字段名 | 数据类型 | 必需 | 说明 |
| ----- | ------- | :---: | --- |
| `subject` | String | 是 | 邮件主题 |
| `body` | String | 是 | 邮件正文 |
| `to_addr` | String | 是 | 邮件收件人 |
**响应**
| 字段名 | 数据类型 | 默认 | 说明 |
| ----- | ------- | :-: | --- |
| `success` | Boolean | `true` | 邮件发送成功 |
### Artrans 接口
::: warning
此接口暂不稳定,请避免使用!
:::
**POST** `/api/admin/artransfer`
**参数**
| 字段名 | 数据类型 | 必需 | 说明 |
| ----- | ------- | :---: | --- |
| `type` | String | 是 | 导入数据类型 |
| `payload` | String | 否 | 导入数据 |
**响应** 无
-50
View File
@@ -1,50 +0,0 @@
# Event
## 基本事件
|事件名|描述|
|-|-|
| `inited` | 初始化后 |
| `destroy` | 实例销毁时 |
| `list-fetch` | 评论列表请求时 |
| `list-fetched` | 评论列表请求后 |
| `list-load` | 评论装载前 |
| `list-loaded` | 评论装载后 |
| `list-error` | 评论加载错误时 |
| `list-goto-first` | 评论列表归位时 |
| `list-reach-bottom` | 评论列表滚动到底部时 |
| `list-reach-bottom` | 评论列表滚动到底部时 |
| `comment-inserted` | 评论插入后 |
| `comment-updated` | 评论更新后 |
| `comment-deleted` | 评论删除后 |
| `comment-rendered` | 评论节点渲染后 |
| `unreads-updated` | 未读消息变更时 |
| `list-goto` | 评论跳转时 |
| `page-loaded` | 页面数据更新后 |
| `editor-submit` | 编辑器提交时 |
| `editor-submitted` | 编辑器提交后 |
| `user-changed` | 本地用户数据变更时 |
| `conf-loaded` | 配置变更时 |
| `dark-mode-changed` | 深色模式变更时 |
| `sidebar-show` | 侧边栏显示 |
| `sidebar-hide` | 侧边栏隐藏 |
事件声明代码:[@ArtalkJS/Artalk - types/event.ts](https://github.com/ArtalkJS/Artalk/blob/master/ui/packages/artalk/types/event.ts)
## 添加事件监听
```js
artalk.on('list-loaded', () => {
alert('评论已加载完毕')
})
```
## 解除事件监听
```js
let foo = function() { /* do something */ }
artalk.on('list-loaded', foo)
artalk.off('list-loaded', foo)
```
-28
View File
@@ -1,28 +0,0 @@
# 开发说明
## 参考资源
📖 <a href="https://github.com/ArtalkJS/Artalk/blob/master/CONTRIBUTING.md" target="_blank">开发者贡献指南 (CONTRIBUTING.md)</a>
🔬 <a href="/http-api.html" target="_blank">HTTP API 文档 (OpenAPI)</a>
🔖 <a href="https://github.com/ArtalkJS/Artalk/blob/master/CODE_OF_CONDUCT.md" target="_blank">贡献者契约行为准则 (CODE_OF_CONDUCT.md)</a>
## 配置文档
- [后端配置](../guide/backend/config.md)
- [前端配置](../guide/frontend/config.md)
## 补充说明
由于 Artalk 正处于开发阶段,使用此文档中 `API`、`Event` 前请务必检查时效性。
- `API` 部分参考源码
* [@ArtalkJS/Artalk - src/api/](https://github.com/ArtalkJS/Artalk/tree/master/ui/packages/artalk/src/api)
* [@ArtalkJS/Artalk - server/server.go](https://github.com/ArtalkJS/Artalk/blob/master/server/server.go)
- `UI` 及 `Event` 部分参考源码
* [@ArtalkJS/Artalk - src/artalk.ts](https://github.com/ArtalkJS/Artalk/blob/master/ui/packages/artalk/src/artalk.ts)
* [@ArtalkJS/Artalk - types/event.ts](https://github.com/ArtalkJS/Artalk/blob/master/ui/packages/artalk/types/event.ts)
通过 Artalk 提供的 `API` 和 `Event`,你可以实现很多高级功能,比如编写评论管理机器人、评论提醒推送插件等。Artalk 并不为此提供技术指导,但鼓励你参考此处的文档自行定制。
-64
View File
@@ -1,64 +0,0 @@
# 插件开发
使用 `Artalk.use` 来扩展 Artalk。
```js
import Artalk from 'artalk'
Artalk.use((ctx) => {
ctx.on('inited', () => {
ctx.get('editor').setContent("Hello World")
})
ctx.on('list-loaded', () => {
console.log('评论列表加载完毕')
})
})
const artalk = Artalk.init({ ... })
```
请注意:
- `Artalk.use` 必须在 `Artalk.init` 之前调用。
- 请勿依赖插件的加载顺序,请监听事件来执行插件逻辑。
- 当所有的插件加载完毕后,会触发 `inited` 事件。
在 use 函数中,你可以通过 `ctx` 来访问 Artalk 的上下文。
## Context
Context 对象包含了 Artalk 的上下文信息。
| 成员 | 说明 |
| --- | --- |
| `ctx.$root` | Artalk 容器元素 |
| `ctx.conf` | Artalk 配置 |
| `ctx.fetch` | 加载数据数据 |
| `ctx.reload` | 重载评论列表 |
| `ctx.on` | 添加事件监听 |
| `ctx.off` | 解除事件监听 |
| `ctx.trigger` | 触发事件 |
| `ctx.inject` | 依赖注入 |
| `ctx.get` | 获取依赖 |
::: warning
Context API 目前仍不稳定,开发可能会有变动,升级请关注 CHANGELOG。
:::
参考:[@artalk/types/context.ts](https://github.com/ArtalkJS/Artalk/blob/master/ui/packages/artalk/types/context.ts)
Artalk 拥有完整的 TypeScript 类型定义,你可以通过编辑器的自动补全来查看 API。
## 示例插件
Artalk 有很多内置的插件,你可以参考它们的源码来开发自己的插件。
[@ArtalkJS/Artalk - src/plugins](https://github.com/ArtalkJS/Artalk/tree/master/ui/packages/artalk/src/plugins)
我们还提供了一些外置的插件,同样可以参考:
| 插件 | 说明 |
| --- | --- |
| [@artalk/plugin-katex](https://github.com/ArtalkJS/Artalk/tree/master/ui/packages/plugin-katex) | LaTeX 公式插件 |
| [@artalk/plugin-lightbox](https://github.com/ArtalkJS/Artalk/tree/master/ui/packages/plugin-lightbox) | 图片灯箱插件 |
+2
View File
@@ -0,0 +1,2 @@
.vitepress/dist/**
.vitepress/cache/**
@@ -9,18 +9,38 @@ export default defineConfig({
head: [
['link', { rel: 'icon', href: '/favicon.png' }],
['meta', { name: 'viewport', content: 'width=device-width, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0, user-scalable=no, target-densitydpi=device-dpi' }],
// artalk
// ['link', { href: `https://npm.elemecdn.com/artalk@${Version.latest}/dist/Artalk.css`, rel: 'stylesheet' }],
['link', { href: `https://artalk.qwqaq.com/dist/Artalk.css`, rel: 'stylesheet' }],
// ['script', { src: ArtalkCDN.JS }],
[
'meta',
{
name: 'viewport',
content:
'width=device-width, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0, user-scalable=no, target-densitydpi=device-dpi',
},
],
// light gallery
['link', { href: 'https://npm.elemecdn.com/lightgallery@2.3.0/css/lightgallery.css', rel: 'stylesheet' }],
['script', { src: 'https://npm.elemecdn.com/lightgallery@2.3.0/lightgallery.min.js' }],
[
'link',
{
href: 'https://cdnjs.cloudflare.com/ajax/libs/lightgallery/2.3.0/css/lightgallery.css',
rel: 'stylesheet',
},
],
[
'script',
{
src: 'https://cdnjs.cloudflare.com/ajax/libs/lightgallery/2.3.0/lightgallery.min.js',
},
],
// katex
// ['link', { href: "https://npm.elemecdn.com/katex@0.15.3/dist/katex.min.css", rel: 'stylesheet' }],
// ['script', { src: 'https://npm.elemecdn.com/katex@0.15.3/dist/katex.min.js' }],
// ['script', { src: 'https://npm.elemecdn.com/@artalkjs/plugin-katex/dist/artalk-plugin-katex.js' }],
[
'link',
{
href: 'https://unpkg.com/katex@0.15.3/dist/katex.min.css',
rel: 'stylesheet',
},
],
['script', { src: 'https://unpkg.com/katex@0.15.3/dist/katex.min.js' }],
// ['script', { src: 'https://unpkg.com/@artalk/plugin-katex/dist/artalk-plugin-katex.js' }],
],
lastUpdated: true,
@@ -33,42 +53,48 @@ export default defineConfig({
},
config: (md) => {
md.use(iterator, 'artalk_version', 'text', function (tokens, idx) {
tokens[idx].content = tokens[idx].content.replace(/:ArtalkVersion:/g, Version.latest)
});
tokens[idx].content = tokens[idx].content.replace(
/:ArtalkVersion:/g,
Version.latest,
)
})
md.use(iterator, 'artalk_version_link', 'link_open', (tokens, idx) => {
const href = tokens[idx].attrGet('href')
tokens[idx].attrSet('href', href.replace(/:ArtalkVersion:/g, Version.latest))
});
const href = tokens[idx].attrGet('href')
tokens[idx].attrSet(
'href',
href.replace(/:ArtalkVersion:/g, Version.latest),
)
})
},
},
locales: {
root: {
label: '简体中文',
lang: 'zh'
lang: 'zh',
link: 'https://artalk.js.org/',
},
en: {
label: 'English',
lang: 'en',
link: 'https://artalk-js-org.translate.goog/guide/intro?_x_tr_sl=auto&_x_tr_tl=en-US&_x_tr_hl=en-US&_x_tr_pto=wapp'
// link: '/en/'
}
link: 'https://artalk-js-org.translate.goog/guide/intro?_x_tr_sl=auto&_x_tr_tl=en-US&_x_tr_hl=en-US&_x_tr_pto=wapp',
},
},
themeConfig: {
sidebar: {
"/guide/": [
'/guide/': [
{
text: "快速开始",
text: '快速开始',
collapsed: false,
items: [
{ text: '项目介绍', link: '/guide/intro.md' },
{ text: '程序部署', link: '/guide/deploy.md' },
{ text: '数据迁移', link: '/guide/transfer.md' },
]
],
},
{
text: "核心指南",
text: '核心指南',
collapsed: false,
items: [
{ text: '侧边栏', link: '/guide/frontend/sidebar.md' },
@@ -81,34 +107,34 @@ export default defineConfig({
{ text: '解析相对路径', link: '/guide/backend/relative-path.md' },
{ text: '如何配置界面', link: '/guide/backend/fe-control.md' },
{ text: 'English (i18n)', link: '/guide/frontend/i18n.md' },
]
],
},
{
text: "进阶指南",
text: '进阶指南',
collapsed: false,
items: [
{ text: '表情包', link: '/guide/frontend/emoticons.md' },
{ text: '浏览量统计', link: '/guide/frontend/pv.md' },
{ text: 'Latex', link: '/guide/frontend/latex.md' },
{ text: '图片灯箱', link: '/guide/frontend/lightbox.md' },
{ text: 'IP 归属地', link: '/guide/frontend/ip-region.md' },
{ text: 'IP 属地', link: '/guide/frontend/ip-region.md' },
{ text: '精简版本', link: '/guide/frontend/artalk-lite.md' },
{ text: '置入博客', link: '/guide/frontend/import-blog.md' },
{ text: '置入框架', link: '/guide/frontend/import-framework.md' },
{ text: '前端 API', link: '/develop/fe-api.md', },
{ text: '开发文档', link: '/develop/index.md', },
{ text: '前端 API', link: '/develop/fe-api.md' },
{ text: '开发文档', link: '/develop/index.md' },
],
},
{
text: "配置文档",
text: '配置文档',
collapsed: true,
items: [
{ text: '后端配置', link: '/guide/backend/config.md' },
{ text: '前端配置', link: '/guide/frontend/config.md' },
]
],
},
{
text: "部署说明",
text: '部署说明',
collapsed: true,
items: [
{ text: '守护进程', link: '/guide/backend/daemon.md' },
@@ -116,7 +142,7 @@ export default defineConfig({
{ text: '编译构建', link: '/guide/backend/build.md' },
{ text: '程序升级', link: '/guide/backend/update.md' },
{ text: 'Docker', link: '/guide/backend/docker.md' },
]
],
},
{
text: '更多内容',
@@ -126,23 +152,32 @@ export default defineConfig({
{ text: '扩展阅读', link: '/guide/extras.md' },
{ text: '案例展示', link: '/guide/cases.md' },
{ text: '关于我们', link: '/guide/about.md' },
]
}
],
},
],
"/develop/": [
'/develop/': [
{
text: '开发文档',
items: [
{ text: '开发说明', link: '/develop/index.md', },
{ text: '前端 API', link: '/develop/fe-api.md', },
{ text: '前端 Event', link: '/develop/event.md', },
{ text: '开发说明', link: '/develop/index.md' },
{ text: '前端 API', link: '/develop/fe-api.md' },
{ text: '前端 Event', link: '/develop/event.md' },
{ text: '插件开发', link: '/develop/plugs.md' },
{ text: '🔬 HTTP API', link: 'https://artalk.js.org/http-api.html', },
{ text: '📖 Contributing Guide', link: 'https://github.com/ArtalkJS/Artalk/blob/master/CONTRIBUTING.md' },
{ text: '🔖 Code of Conduct', link: 'https://github.com/ArtalkJS/Artalk/blob/master/CODE_OF_CONDUCT.md' },
]
}
]
{
text: '🔬 HTTP API',
link: 'https://artalk.js.org/http-api.html',
},
{
text: '📖 Contributing Guide',
link: 'https://github.com/ArtalkJS/Artalk/blob/master/CONTRIBUTING.md',
},
{
text: '🔖 Code of Conduct',
link: 'https://github.com/ArtalkJS/Artalk/blob/master/CODE_OF_CONDUCT.md',
},
],
},
],
},
nav: [
@@ -179,16 +214,16 @@ export default defineConfig({
text: '代码仓库',
link: 'https://github.com/ArtalkJS/Artalk',
},
{
text: '文档镜像 (国内)',
link: 'https://artalk-docs.qwqaq.com'
}
// {
// text: "文档镜像 (国内)",
// link: "https://artalk-docs.qwqaq.com",
// },
],
},
],
socialLinks: [
{ icon: 'github', link: 'https://github.com/ArtalkJS/Artalk' }
{ icon: 'github', link: 'https://github.com/ArtalkJS/Artalk' },
],
search: {
@@ -198,14 +233,20 @@ export default defineConfig({
apiKey: '6c6ebc345a87b738264f19095b78c91c',
indexName: 'artalk-js',
searchParameters: {
facetFilters: ['lang:zh-CN']
}
}
facetFilters: ['lang:zh-CN'],
},
},
},
editLink: {
pattern: 'https://github.com/ArtalkJS/Artalk/edit/master/docs/:path',
text: '完善文档'
text: '完善文档',
},
}
},
vite: {
server: {
open: '/guide/intro.html',
},
},
})
+97
View File
@@ -0,0 +1,97 @@
<template>
<div ref="el" style="margin-top: 20px"></div>
</template>
<script setup lang="ts">
import { watch, nextTick, ref, onMounted, onUnmounted } from 'vue'
import { useData, useRouter } from 'vitepress'
import Artalk from 'artalk'
import 'artalk/dist/Artalk.css'
const el = ref<HTMLElement | null>(null)
const router = useRouter()
const page = useData().page
let artalk: Artalk
onMounted(() => {
nextTick(() => {
initArtalk(getConfByPage())
})
})
watch(
() => router.route.path,
() => {
nextTick(() => {
artalk.update(getConfByPage())
artalk.reload()
})
},
)
onUnmounted(() => {
artalk.destroy()
})
function initArtalk(conf: any) {
artalk = Artalk.init({
el: el.value,
emoticons: '/assets/emoticons/default.json',
gravatar: {
mirror: 'https://cravatar.cn/avatar/',
},
...conf,
})
loadExtraFuncs()
}
function getConfByPage() {
return {
pageKey: 'https://artalk.js.org' + router.route.path,
pageTitle: page.value.title,
server: 'https://artalk.qwqaq.com',
site: 'ArtalkDocs',
}
}
function loadExtraFuncs() {
// 图片灯箱插件
artalk.on('list-loaded', () => {
document
.querySelectorAll('.atk-comment .atk-content')
.forEach(($content) => {
const imgEls = $content.querySelectorAll<HTMLImageElement>(
'img:not([atk-emoticon]):not([atk-lightbox])',
)
imgEls.forEach((imgEl) => {
imgEl.setAttribute('atk-lightbox', '')
const linkEl = document.createElement('a')
linkEl.setAttribute('class', 'atk-img-link')
linkEl.setAttribute('href', imgEl.src)
linkEl.setAttribute('data-src', imgEl.src)
linkEl.append(imgEl.cloneNode())
imgEl.replaceWith(linkEl)
})
// @ts-ignore
if (imgEls.length) lightGallery($content, { selector: '.atk-img-link' })
})
})
// 夜间模式
const darkMode = document.querySelector('html').classList.contains('dark')
artalk.setDarkMode(darkMode)
new MutationObserver((mList) => {
mList.forEach((m) => {
if (m.attributeName !== 'class') return
// @ts-ignore
const darkMode = m.target.classList.contains('dark')
artalk.setDarkMode(darkMode)
})
}).observe(document.querySelector('html'), { attributes: true })
}
</script>
@@ -1,5 +1,9 @@
<template>
<iframe src="https://artransfer.netlify.app/?iframe=1" style="width: 100%;height: 520px;border: 0;" id="artransferIframe"></iframe>
<iframe
src="https://artransfer.netlify.app/?iframe=1"
style="width: 100%; height: 520px; border: 0"
id="artransferIframe"
></iframe>
</template>
<script lang="ts">
@@ -29,10 +33,6 @@ export default defineComponent({
setArtransferIframeDarkMode(darkMode)
})
}).observe(document.querySelector('html'), { attributes: true })
}
},
})
</script>
<style>
</style>
@@ -4,9 +4,6 @@ import { onMounted } from 'vue'
import './style.scss'
const { Layout } = DefaultTheme
onMounted(() => {
})
</script>
<template>
File renamed without changes.
@@ -16,5 +16,5 @@ export default {
// app is the Vue 3 app instance from `createApp()`.
// router is VitePress' custom router. `siteData` is
// a `ref` of current site-level metadata.
}
},
} as Theme
@@ -8,7 +8,7 @@
--vp-c-divider: #dfe2e5;
--vp-home-hero-name-color: transparent;
--vp-home-hero-name-background: linear-gradient(90deg,#0083ff, #37dfd9);
--vp-home-hero-name-background: linear-gradient(90deg, #0083ff, #37dfd9);
}
.dark {
@@ -38,9 +38,9 @@
background-color: #0083ff;
&:hover {
border-color: #007CF0;
border-color: #007cf0;
color: #fff;
background-color: #007CF0;
background-color: #007cf0;
}
}
@@ -48,52 +48,52 @@
.wave {
display: inline-block;
transform-origin: center bottom;
animation:upAnimation 2.33s ease .8s 3 both;
animation: upAnimation 2.33s ease 0.8s 3 both;
}
@keyframes upAnimation {
0% {
transform: rotate(0deg);
transition-timing-function:cubic-bezier(0.215, .61, .355, 1);
transition-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1);
}
10% {
transform: rotate(-12deg);
transition-timing-function:cubic-bezier(0.215, .61, .355, 1);
transition-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1);
}
20% {
transform: rotate(12deg);
transition-timing-function:cubic-bezier(0.215, .61, .355, 1);
transition-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1);
}
28% {
transform: rotate(-10deg);
transition-timing-function:cubic-bezier(0.215, .61, .355, 1);
transition-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1);
}
36% {
transform: rotate(10deg);
transition-timing-function:cubic-bezier(0.755, .5, .855, .06);
transition-timing-function: cubic-bezier(0.755, 0.5, 0.855, 0.06);
}
42% {
transform: rotate(-8deg);
transition-timing-function:cubic-bezier(0.755, .5, .855, .06);
transition-timing-function: cubic-bezier(0.755, 0.5, 0.855, 0.06);
}
48% {
transform: rotate(8deg);
transition-timing-function:cubic-bezier(0.755, .5, .855, .06);
transition-timing-function: cubic-bezier(0.755, 0.5, 0.855, 0.06);
}
52% {
transform: rotate(-4deg);
transition-timing-function:cubic-bezier(0.755, .5, .855, .06);
transition-timing-function: cubic-bezier(0.755, 0.5, 0.855, 0.06);
}
56% {
transform: rotate(4deg);
transition-timing-function:cubic-bezier(0.755, .5, .855, .06);
transition-timing-function: cubic-bezier(0.755, 0.5, 0.855, 0.06);
}
60% {
transform: rotate(0deg);
transition-timing-function:cubic-bezier(0.755, .5, .855, .06);
transition-timing-function: cubic-bezier(0.755, 0.5, 0.855, 0.06);
}
100% {
transform: rotate(0deg);
transition-timing-function:cubic-bezier(0.215, .61, .355, 1);
transition-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1);
}
}
@@ -107,33 +107,38 @@ img[atk-emoticon] {
}
/* 由于 body 未添加一致的 transition,导致其他地方暗黑模式切换加 transition 比较怪 */
.vp-doc div[class*='language-'] { transition: none; }
.vp-doc :not(pre) > code { transition: none; }
.vp-doc div[class*='language-'] {
transition: none;
}
.vp-doc :not(pre) > code {
transition: none;
}
.vp-doc {
table {
border-collapse: collapse;
margin: 1rem 0;
display: block;
overflow-x: auto
overflow-x: auto;
}
td,th {
padding: .6em 1em;
td,
th {
padding: 0.6em 1em;
}
}
/* 侧边栏 */
.VPSidebar::-webkit-scrollbar {
width: 7px
width: 7px;
}
.VPSidebar::-webkit-scrollbar-track {
background-color: transparent
background-color: transparent;
}
.VPSidebar::-webkit-scrollbar-thumb {
background-color: var(--vp-c-divider)
background-color: var(--vp-c-divider);
}
// details block patch
@@ -146,5 +151,5 @@ img[atk-emoticon] {
}
.vp-code-group .tabs::after {
background-color: var(--vp-c-divider)
background-color: var(--vp-c-divider);
}
+5
View File
@@ -0,0 +1,5 @@
declare module '*.vue' {
import { defineComponent } from 'vue'
const component: ReturnType<typeof defineComponent>
export default component
}
+7 -6
View File
@@ -1,19 +1,20 @@
## Artalk Documentation
# Artalk Documentation
> The Documentation of Artalk
[![Netlify Status](https://api.netlify.com/api/v1/badges/6580cce0-4b27-465e-8d73-1e6a832942e9/deploy-status)](https://app.netlify.com/sites/artalk/deploys)
Documentation of Artalk
## Build
```bash
pnpm docs:dev
pnpm docs:build
pnpm dev:docs
pnpm build:docs
```
## Deploy
[![Netlify Status](https://api.netlify.com/api/v1/badges/6580cce0-4b27-465e-8d73-1e6a832942e9/deploy-status)](https://app.netlify.com/sites/artalk/deploys)
文档通过 [Netlify](https://www.netlify.com/) 对 master 分支进行自动部署。
## Licensed
CC BY-NC-SA 4.0
File renamed without changes.
File renamed without changes.
+3
View File
@@ -0,0 +1,3 @@
{
"latest": "2.8.5"
}
File renamed without changes.
+592
View File
@@ -0,0 +1,592 @@
# HTTP API
::: warning
该 HTTP API 文档已过时
:::
::: tip 无特殊说明时 API 调用响应格式
| 字段名 | 类型 | 说明 |
| --------- | ------- | --------------------------------------------- |
| `success` | Boolean | 接口调用结果 |
| `msg` | String | 返回消息,出错时此字段包含错误消息 |
| `data` | Any | 返回数据,可能为 Object / String / Array 类型 |
:::
## Normal API
### 评论新增
**POST** `/api/add`
**参数**
| 字段名 | 数据类型 | 必需 | 说明 |
| ------------ | -------- | :--: | ------------------------------------------------- |
| `name` | String | 是 | 待新增评论者昵称 |
| `email` | String | 是 | 待新增评论者邮箱 |
| `link` | String | 否 | 待新增评论者链接 |
| `content` | String | 是 | 待新增评论内容 |
| `rid` | Number | 否 | 待新增评论为回复评论时传入父评论 `ID`,否则为 `0` |
| `page_key` | String | 是 | 待新增评论目标页面唯一标识符 |
| `page_title` | String | 否 | 待新增评论目标页面标题 |
| `token` | String | 否 | 评论请求 Token |
| `site_name` | String | 否 | 待新增评论目标站点名称 |
**响应**
| 字段名 | 数据类型 | 默认 | 说明 |
| ------------------------------ | -------- | :----: | -------------------------------------- |
| `success` | Boolean | `true` | 评论新增成功 |
| `data.comment` | Object | - | 评论数据 |
| `data.comment.id` | Number | - | 评论 ID |
| `data.comment.content` | String | - | 评论正文 |
| `data.comment.nick` | String | - | 评论者昵称 |
| `data.comment.email_encrypted` | String | - | 评论者邮箱 MD5 加密值 |
| `data.comment.link` | String | - | 评论者链接 |
| `data.comment.ua` | String | - | 评论者 User-Agent |
| `data.comment.date` | String | - | 评论时间,格式为 `1970-01-01 00:00:00` |
| `data.comment.is_collapsed` | Boolean | - | 评论是否折叠 |
| `data.comment.is_pending` | Boolean | - | 评论是否待审 |
| `data.comment.is_allow_reply` | Boolean | - | 评论是否允许回复 |
| `data.comment.rid` | Number | `0` | 待新增评论为回复评论时返回父评论 `ID` |
| `data.comment.badge_name` | String | - | 评论者徽章文字 |
| `data.comment.badge_color` | String | - | 评论者徽章颜色 |
| `data.comment.visible` | Boolean | `true` | 评论是否可见 |
| `data.comment.vote_up` | Number | `0` | 评论赞同数 |
| `data.comment.vote_down` | Number | `0` | 评论反对数 |
| `data.comment.page_key` | String | - | 评论所在页面唯一标识符 |
| `data.comment.site_name` | String | - | 评论所在站点名称 |
### 评论获取
**POST** `/api/get`
**参数**
| 字段名 | 数据类型 | 必需 | 说明 |
| ----------- | -------- | :--: | -------------------------- |
| `page_key` | String | 是 | 待获取评论页面的唯一标识符 |
| `limit` | Number | 否 | 待获取评论的数量限制 |
| `offset` | Number | 否 | 待获取评论的起始位置偏移 |
| `type` | String | 否 | 获取指定类型的评论 |
| `name` | String | 否 | 获取指定昵称的评论 |
| `email` | String | 否 | 获取指定邮箱的评论 |
| `site_name` | String | 否 | 获取指定站点名称的评论 |
| `flat_mode` | Boolean | 否 | 待获取评论是否平铺模式 |
**响应**
| 字段名 | 数据类型 | 默认 | 说明 |
| ---------------------- | -------- | :----: | ------------------------------ |
| `success` | Boolean | `true` | 评论获取成功 |
| `data.comments` | Array | - | 页面评论数据 |
| `data.total` | Number | - | 页面评论总数(包括所有子评论) |
| `data.total_parents` | Number | - | 页面评论中父级评论总数 |
| `data.page` | Object | - | 页面数据 |
| `data.page.id` | Number | - | 页面 ID |
| `data.page.admin_only` | Boolean | - | 页面是否仅管理员可评论 |
| `data.page.key` | String | - | 页面唯一标识符 |
| `data.page.url` | String | - | 页面链接 |
| `data.page.title` | String | - | 页面标题 |
| `data.page.site_name` | String | - | 页面所在站点名称 |
| `data.page.vote_up` | Number | - | 页面赞同数 |
| `data.page.vote_down` | Number | - | 页面反对数 |
| `data.unread` | Array | - | 未读的评论提醒数据 |
| `data.unread_count` | Number | - | 未读的评论提醒数据总数 |
| `data.api_version` | Object | - | 目标 Artalk 后端版本数据 |
::: tip
- `data.comments` 数组中元素结构参考 [评论新增接口](#评论新增) `/api/add` 响应的 `data.comment`
- `data.unread` 数组中元素结构如下
| 字段名 | 数据类型 | 默认 | 说明 |
| ----- | ------- | :-: | --- |
| `id` | Number | - | 评论提醒 ID |
| `user_id` | Number | - | 评论提醒目标用户 ID |
| `comment_id` | Number | - | 评论提醒来源评论 ID |
| `is_read` | Boolean | - | 评论提醒是否已读 |
| `is_emailed` | Boolean | - | 评论提醒是否已发送邮件 |
| `read_link` | String | - | 评论提醒已读地址 |
- `data.api_version` 对象结构参考 [Artalk 版本接口](#artalk-版本) `/api/version` 响应
:::
### 用户获取
**POST** `/api/user-get`
**参数**
| 字段名 | 数据类型 | 必需 | 说明 |
| ------- | -------- | :--: | ---------------- |
| `name` | String | 否 | 待获取用户的昵称 |
| `email` | String | 否 | 待获取用户的邮箱 |
**响应**
| 字段名 | 数据类型 | 默认 | 说明 |
| ----------------------- | -------- | :----: | ---------------------------------- |
| `success` | Boolean | `true` | 用户获取成功 |
| `data.user` | Object | `null` | 获取的用户数据,若用户不存在返回空 |
| `data.user.id` | Number | - | 用户 ID |
| `data.user.name` | String | - | 用户昵称 |
| `data.user.email` | String | - | 用户邮箱 |
| `data.user.link` | String | - | 用户链接 |
| `data.user.badge_name` | String | - | 用户徽章文字 |
| `data.user.badge_color` | String | - | 用户徽章颜色 |
| `data.user.is_admin` | Boolean | - | 用户是否管理员 |
| `data.is_login` | Boolean | - | 用户是否登录 |
| `data.unread` | Array | `[]` | 用户未读的评论提醒数据 |
| `data.unread_count` | Number | `0` | 用户未读的评论提醒数据总数 |
::: tip
- `data.unread` 数组中元素结构参考 [评论获取接口](#评论获取) `/api/get` **TIP**
:::
### 用户登录
**GET/POST** `/api/login`
**参数**
| 字段名 | 数据类型 | 必需 | 说明 |
| ---------- | -------- | :--: | ---------------------------------- |
| `name` | String | 是 | 待登录用户的昵称 |
| `email` | String | 是 | 待登录用户的邮箱 |
| `password` | String | 是 | 待登录用户的密码(管理员身份验证) |
**响应**
| 字段名 | 数据类型 | 默认 | 说明 |
| ------------ | -------- | :----: | ---------------- |
| `success` | Boolean | `true` | 用户登录成功 |
| `data.token` | String | - | 登录的用户 Token |
### 提醒已读
**POST** `/api/mark-read`
**参数**
| 字段名 | 数据类型 | 必需 | 说明 |
| ------------ | -------- | :--: | -------------------- |
| `notify_key` | String | 否 | 评论提醒唯一标识符 |
| `name` | String | 否 | 评论提醒用户的昵称 |
| `email` | String | 否 | 评论提醒用户的邮箱 |
| `all_read` | Boolean | 否 | 评论提醒是否已读 |
| `site_name` | String | 否 | 评论提醒所在站点名称 |
**响应**
| 字段名 | 数据类型 | 默认 | 说明 |
| --------- | -------- | :----: | ------------ |
| `success` | Boolean | `true` | 提醒已读成功 |
### 评论投票
**POST** `/api/vote`
**参数**
| 字段名 | 数据类型 | 必需 | 说明 |
| ----------- | -------- | :--: | ----------------------------------------------------------------------------------------------------------- |
| `target_id` | Number | 是 | 待投票评论 ID |
| `type` | String | 否 | 待投票类型,前缀 `comment_`、`page_` 依次代表对评论投票、对页面投票,后缀 `_up`、`_down` 依次代表赞同、反对 |
| `name` | String | 否 | 投票用户昵称 |
| `email` | String | 否 | 投票用户邮箱 |
| `site_name` | String | 否 | 投票目标评论或页面所在站点名称 |
**响应**
| 字段名 | 数据类型 | 默认 | 说明 |
| --------------- | -------- | :----: | ------------------------------ |
| `success` | Boolean | `true` | 评论投票成功 |
| `data.vote_num` | Number | - | 目标评论或页面指定类型投票数据 |
### Artalk 版本
::: warning
此接口较特殊,返回结果不包含 `success`、`msg`、`data` 字段,直接返回包含指定字段的 JSON。
:::
**GET/POST** `/api/version`
**参数** 无
**响应**
| 字段名 | 数据类型 | 默认 | 说明 |
| ---------------- | -------- | :------: | ------------------------------- |
| `app` | String | `artalk` | Artalk 后端程序名 |
| `version` | String | - | Artalk 后端程序版本号 |
| `commit_hash` | String | - | Artalk 后端程序 Git 提交哈希值 |
| `fe_min_version` | String | - | Artalk 后端程序所需前端最低版本 |
## Captcha API
### 验证码刷新
**GET** `/api/captcha/refresh`
**参数** 无
**响应**
| 字段名 | 数据类型 | 默认 | 说明 |
| --------------- | -------- | :----: | ------------------------------------ |
| `success` | Boolean | `true` | 验证码刷新成功 |
| `data.img_data` | String | - | 根据 IP 获取的验证码图片 Base64 编码 |
### 验证码检验
**GET** `/api/captcha/check`
**参数**
| 字段名 | 数据类型 | 必需 | 说明 |
| ------- | -------- | :--: | ------ |
| `value` | String | 是 | 验证码 |
**响应**
| 字段名 | 数据类型 | 默认 | 说明 |
| --------------- | -------- | :----: | -------------------------------------------------------- |
| `success` | Boolean | `true` | 验证码检验成功 |
| `data.img_data` | String | - | 新的验证码图片 Base64 编码,仅验证码检验出错时存在此字段 |
## Admin API
### 评论编辑
**POST** `/api/admin/comment-edit`
**参数**
| 字段名 | 数据类型 | 必需 | 说明 |
| -------------- | -------- | :--: | ------------------------------------------------- |
| `id` | Number | 是 | 待编辑评论 ID,**不可修改** |
| `site_name` | String | 否 | 待编辑评论所在站点名称,**不可修改** |
| `content` | String | 否 | 待编辑评论正文 |
| `page_key` | String | 否 | 待编辑评论所在页面唯一标识符 |
| `nick` | String | 否 | 待编辑评论所属用户昵称 |
| `email` | String | 否 | 待编辑评论所属用户邮箱 |
| `link` | String | 否 | 待编辑评论所属用户链接 |
| `rid` | String | 否 | 待编辑评论为回复评论时传入父评论 `ID`,否则为 `0` |
| `ua` | String | 否 | 待编辑评论所属用户 User-Agent |
| `ip` | String | 否 | 待编辑评论所属用户 IP |
| `is_collapsed` | Boolean | 否 | 待编辑评论是否折叠 |
| `is_pending` | Boolean | 否 | 待编辑评论是否待审 |
**响应**
| 字段名 | 数据类型 | 默认 | 说明 |
| -------------- | -------- | :----: | ---------------- |
| `success` | Boolean | `true` | 评论编辑成功 |
| `data.comment` | Object | - | 编辑评论的新数据 |
::: tip
- `data.comment` 对象结构参考 [评论新增接口](#评论新增) `/api/add` 响应的 `data.comment`
:::
### 评论删除
::: danger
此接口不推荐外部调用。
调用此接口前请务必核实评论 ID,一旦调用成功将删除该评论下所有相关数据。
:::
**POST** `/api/admin/comment-del`
**参数**
| 字段名 | 数据类型 | 必需 | 说明 |
| ----------- | -------- | :--: | ---------------------- |
| `id` | Number | 是 | 待删除评论 ID |
| `site_name` | String | 是 | 待删除评论所在站点名称 |
**响应**
| 字段名 | 数据类型 | 默认 | 说明 |
| --------- | -------- | :----: | ------------ |
| `success` | Boolean | `true` | 评论删除成功 |
### 页面获取
**POST** `/api/admin/page-get`
**参数**
| 字段名 | 数据类型 | 必需 | 说明 |
| ----------- | -------- | :--: | ---------------------- |
| `site_name` | String | 是 | 待获取页面目标站点名称 |
**响应**
| 字段名 | 数据类型 | 默认 | 说明 |
| ------------ | -------- | :----: | ------------------ |
| `success` | Boolean | `true` | 页面获取成功 |
| `data.pages` | Array | - | 目标站点的页面数据 |
| `data.sites` | Array | - | 所有站点数据 |
::: tip
- `data.pages` 数组中元素结构参考 [评论获取接口](#评论获取) `/api/get` 响应的 `data.page`
- `data.sites` 数组中元素结构参考 [站点编辑接口](#站点编辑) `/api/admin/site-edit` 响应的 `data.site`
:::
### 页面编辑
**POST** `/api/admin/page-edit`
**参数**
| 字段名 | 数据类型 | 必需 | 说明 |
| ------------ | -------- | :--: | ------------------------------------ |
| `id` | Number | 是 | 待编辑页面 ID,**不可修改** |
| `site_name` | String | 否 | 待编辑页面所在站点名称,**不可修改** |
| `key` | String | 否 | 待编辑页面唯一标识符 |
| `title` | String | 否 | 待编辑页面标题 |
| `admin_only` | Boolean | 否 | 待编辑页面是否仅管理员可评论 |
**响应**
| 字段名 | 数据类型 | 默认 | 说明 |
| ----------- | -------- | :----: | ---------------- |
| `success` | Boolean | `true` | 页面编辑成功 |
| `data.page` | Object | - | 编辑页面的新数据 |
::: tip
- `data.page` 对象结构参考 [评论获取接口](#评论获取) `/api/get` 响应的 `data.page`
:::
### 页面删除
::: danger
此接口不推荐外部调用。
调用此接口前请务必核实页面 ID,一旦调用成功将删除该页面下所有相关数据。
:::
**POST** `/api/admin/page-del`
**参数**
| 字段名 | 数据类型 | 必需 | 说明 |
| ----------- | -------- | :--: | ---------------------- |
| `key` | String | 是 | 待删除页面唯一标识符 |
| `site_name` | String | 是 | 待删除页面所在站点名称 |
**响应**
| 字段名 | 数据类型 | 默认 | 说明 |
| --------- | -------- | :----: | ------------ |
| `success` | Boolean | `true` | 页面删除成功 |
### 页面更新
**POST** `/api/admin/page-fetch`
**参数**
| 字段名 | 数据类型 | 必需 | 说明 |
| ------ | -------- | :--: | ------------- |
| `id` | Number | 是 | 待更新页面 ID |
**响应**
| 字段名 | 数据类型 | 默认 | 说明 |
| ----------- | -------- | :----: | ---------------- |
| `success` | Boolean | `true` | 页面更新成功 |
| `data.page` | Object | - | 更新页面的新数据 |
::: tip
- `data.page` 对象结构参考 [评论获取接口](#评论获取) `/api/get` 响应的 `data.page`
:::
### 站点获取
**POST** `/api/admin/site-get`
**参数** 无
**响应**
| 字段名 | 数据类型 | 默认 | 说明 |
| ------------ | -------- | :----: | ------------ |
| `success` | Boolean | `true` | 站点获取成功 |
| `data.sites` | Array | - | 所有站点数据 |
::: tip
- `data.sites` 数组中元素结构参考 [站点编辑接口](#站点编辑) `/api/admin/site-edit` 响应的 `data.site`
:::
### 站点新增
**POST** `/api/admin/site-add`
**参数**
| 字段名 | 数据类型 | 必需 | 说明 |
| ------ | -------- | :--: | ------------------------------------------------- |
| `name` | String | 是 | 待新增站点名称 |
| `urls` | String | 是 | 待新增站点链接,如有多个需以英文半角符号 `,` 分割 |
**响应**
| 字段名 | 数据类型 | 默认 | 说明 |
| --------------------- | -------- | :----: | ----------------------------------------------- |
| `success` | Boolean | `true` | 站点新增成功 |
| `data.site` | Object | - | 新增站点的数据 |
| `data.site.id` | Number | - | 站点 ID |
| `data.site.name` | String | - | 站点名称 |
| `data.site.urls` | Array | - | 站点链接数组,元素为单个站点链接字符串 |
| `data.site.urls_raw` | String | - | 站点链接数组合并字符串,以英文半角符号 `,` 分割 |
| `data.site.first_url` | String | - | 站点第一链接 |
### 站点编辑
**POST** `/api/admin/site-edit`
**参数**
| 字段名 | 数据类型 | 必需 | 说明 |
| ------ | -------- | :--: | ---------------- |
| `id` | Number | 是 | 待编辑站点 ID |
| `name` | String | 是 | 待编辑站点新名称 |
| `urls` | String | 是 | 待编辑站点新链接 |
**响应**
| 字段名 | 数据类型 | 默认 | 说明 |
| --------------------- | -------- | :----: | ----------------------------------------------- |
| `success` | Boolean | `true` | 站点编辑成功 |
| `data.site` | Object | - | 编辑站点的新数据 |
| `data.site.id` | Number | - | 站点 ID |
| `data.site.name` | String | - | 站点名称 |
| `data.site.urls` | Array | - | 站点链接数组,元素为单个站点链接字符串 |
| `data.site.urls_raw` | String | - | 站点链接数组合并字符串,以英文半角符号 `,` 分割 |
| `data.site.first_url` | String | - | 站点第一链接 |
### 站点删除
::: danger
此接口不推荐外部调用。
调用此接口前请务必核实站点 ID,一旦调用成功将删除该站点下所有相关数据。
:::
**POST** `/api/admin/site-del`
**参数**
| 字段名 | 数据类型 | 必需 | 说明 |
| ------------- | -------- | :--: | ------------------------------------------------------------------- |
| `id` | Number | 是 | 待删除站点 ID |
| `del_content` | Boolean | 否 | 是否删除站点所有数据,为 `false` 时仅删除站点配置而保留站点评论数据 |
**响应**
| 字段名 | 数据类型 | 默认 | 说明 |
| --------- | -------- | :----: | ------------ |
| `success` | Boolean | `true` | 站点删除成功 |
### 设置获取
**POST** `/api/admin/setting-get`
**参数**
| 字段名 | 数据类型 | 必需 | 说明 |
| ------ | -------- | :--: | -------------- |
| `id` | Number | 是 | 管理员用户 ID |
| `name` | String | 否 | 管理员用户昵称 |
| `url` | String | 否 | 管理员用户链接 |
**响应**
| 字段名 | 数据类型 | 默认 | 说明 |
| --------- | -------- | :----: | ------------ |
| `success` | Boolean | `true` | 设置获取成功 |
### 设置保存
**POST** `/api/admin/setting-save`
**参数**
| 字段名 | 数据类型 | 必需 | 说明 |
| ------ | -------- | :--: | -------------- |
| `id` | Number | 是 | 管理员用户 ID |
| `name` | String | 否 | 管理员用户昵称 |
| `url` | String | 否 | 管理员用户链接 |
**响应**
| 字段名 | 数据类型 | 默认 | 说明 |
| --------- | -------- | :----: | ------------ |
| `success` | Boolean | `true` | 设置保存成功 |
### 邮件发送
::: warning
页面收到评论、评论收到回复等满足需要发送邮件提醒条件时,后端将自动向目标地址发送邮件提醒,不需手动处理邮件发送。请勿滥用此接口。
:::
**POST** `/api/admin/send-mail`
**参数**
| 字段名 | 数据类型 | 必需 | 说明 |
| --------- | -------- | :--: | ---------- |
| `subject` | String | 是 | 邮件主题 |
| `body` | String | 是 | 邮件正文 |
| `to_addr` | String | 是 | 邮件收件人 |
**响应**
| 字段名 | 数据类型 | 默认 | 说明 |
| --------- | -------- | :----: | ------------ |
| `success` | Boolean | `true` | 邮件发送成功 |
### Artrans 接口
::: warning
此接口暂不稳定,请避免使用!
:::
**POST** `/api/admin/artransfer`
**参数**
| 字段名 | 数据类型 | 必需 | 说明 |
| --------- | -------- | :--: | ------------ |
| `type` | String | 是 | 导入数据类型 |
| `payload` | String | 否 | 导入数据 |
**响应** 无
File renamed without changes.
+50
View File
@@ -0,0 +1,50 @@
# Event
## 基本事件
| 事件名 | 描述 |
| ------------------- | -------------------- |
| `created` | 初始化后 |
| `mounted` | 数据加载后 |
| `updated` | 数据更新后 |
| `unmounted` | 销毁后 |
| `list-fetch` | 评论列表请求时 |
| `list-fetched` | 评论列表请求后 |
| `list-load` | 评论装载前 |
| `list-loaded` | 评论装载后 |
| `list-failed` | 评论加载错误时 |
| `list-goto-first` | 评论列表归位时 |
| `list-reach-bottom` | 评论列表滚动到底部时 |
| `comment-inserted` | 评论插入后 |
| `comment-updated` | 评论更新后 |
| `comment-deleted` | 评论删除后 |
| `comment-rendered` | 评论节点渲染后 |
| `notifies-updated` | 未读消息变更时 |
| `list-goto` | 评论跳转时 |
| `page-loaded` | 页面数据更新后 |
| `editor-submit` | 编辑器提交时 |
| `editor-submitted` | 编辑器提交后 |
| `user-changed` | 本地用户数据变更时 |
| `sidebar-show` | 侧边栏显示 |
| `sidebar-hide` | 侧边栏隐藏 |
事件声明代码:[@ArtalkJS/Artalk - src/types/event.ts](https://github.com/ArtalkJS/Artalk/blob/master/ui/artalk/src/types/event.ts)
## 添加事件监听
```js
artalk.on('list-loaded', () => {
alert('评论已加载完毕')
})
```
## 解除事件监听
```js
let foo = function () {
/* do something */
}
artalk.on('list-loaded', foo)
artalk.off('list-loaded', foo)
```
@@ -14,6 +14,8 @@ npm install artalk
调用该函数将创建并得到一个 Artalk 的实例化对象,可用于后续操作。
<!-- prettier-ignore-start -->
```js
import Artalk from 'artalk'
@@ -26,14 +28,18 @@ const artalk = Artalk.init({
})
```
调用该函数会向后端发起请求:
<!-- prettier-ignore-end -->
调用该函数会异步地向后端发起请求:
1. 获取前端配置
2. 获取评论列表
配置和评论加载完毕后会分别触发 `conf-loaded` 和 `list-loaded` 事件。
配置和插件加载完毕后会触发 `mounted` 事件。
注:前端配置可能会被覆盖,详情见:[在后端控制前端](../guide/backend/fe-control.md)。
评论列表加载完毕后会触发 `list-loaded` 事件。
注:前端界面配置可能会被覆盖,详情见:[在后端控制前端](../guide/backend/fe-control.md)。
## 释放资源 `destroy`
@@ -45,7 +51,7 @@ const artalk = Artalk.init({ ... })
artalk.destroy()
```
释放资源将执行 Artalk 挂载的 DOM 节点删除,以及解除 Artalk 事件监听等操作。
调用该函数时,将触发 `unmounted` 事件。释放资源将执行 Artalk 挂载的 DOM 节点删除,以及解除 Artalk 事件监听等操作。当该函数执行完毕后,Artalk 实例将不再可用。
在 Vue / React 等框架中,务必在组件销毁时调用该函数,否则会造成内存泄漏:
@@ -69,11 +75,11 @@ artalk.update({
})
```
调用该函数将触发 `conf-loaded` 事件。
调用该函数将触发 `updated` 事件。
更新配置不会自动刷新评论列表,可按需继续执行 `artalk.reload()` 函数。
请注意,该函数是一个实例化对象中的方法,并非全局函数。
请注意,该函数是一个实例化对象中的成员方法,并非全局函数。
前端配置参考:[前端配置](../guide/frontend/config.md)
@@ -96,8 +102,9 @@ artalk.reload()
```js
const artalk = Artalk.init({ ... })
artalk.on('list-loaded', () => {
alert('评论列表加载完毕')
artalk.on('list-loaded', (comments) => {
// comments 包含当前页面所有评论数据 (而非仅本次请求获取的部分评论)
console.log('评论列表加载完毕: ', comments)
})
```
@@ -125,7 +132,7 @@ artalk.off('list-loaded', handler)
```js
const artalk = Artalk.init({ ... })
artalk.trigger('list-loaded')
artalk.trigger('list-loaded', [...])
```
## 加载插件 `use`
@@ -154,6 +161,35 @@ const artalk = Artalk.init({ ... })
artalk.setDarkMode(true)
```
也可以通过调用 `Artalk.init` 时,通过 `darkMode` 参数设置初始夜间模式。
```js
const artalk = Artalk.init({
// ...其他配置
darkMode: 'auto',
})
```
## 浏览量组件 `loadCountWidget`
详情见:[浏览量统计](../guide/frontend/pv.md)
## 获取配置 `getConf`
获取当前 Artalk 配置。
```js
const artalk = Artalk.init({ ... })
const conf = artalk.getConf()
```
## 获取挂载元素 `getEl`
获取当前 Artalk 挂载的 DOM 元素。
```js
const artalk = Artalk.init({ ... })
const el = artalk.getEl()
```
+27
View File
@@ -0,0 +1,27 @@
# 开发说明
## 参考资源
📖 [开发者贡献指南 (CONTRIBUTING.md)](https://github.com/ArtalkJS/Artalk/blob/master/CONTRIBUTING.md)
🔬 <a href="/http-api.html" target="_blank">HTTP API 文档 (OpenAPI)</a>
🔖 [贡献者契约行为准则 (CODE_OF_CONDUCT.md)](https://github.com/ArtalkJS/Artalk/blob/master/CODE_OF_CONDUCT.md)
## 配置文档
- [后端配置](../guide/backend/config.md)
- [前端配置](../guide/frontend/config.md)
## 补充说明
由于 Artalk 正处于开发阶段,使用此文档中 `API`、`Event` 前请务必检查时效性。
- `API` 部分参考源码
- [@ArtalkJS/Artalk - src/api/](https://github.com/ArtalkJS/Artalk/tree/master/ui/artalk/src/api)
- [@ArtalkJS/Artalk - server/server.go](https://github.com/ArtalkJS/Artalk/blob/master/server/server.go)
- `UI` 及 `Event` 部分参考源码
- [@ArtalkJS/Artalk - src/artalk.ts](https://github.com/ArtalkJS/Artalk/blob/master/ui/artalk/src/artalk.ts)
- [@ArtalkJS/Artalk - src/types/event.ts](https://github.com/ArtalkJS/Artalk/blob/master/ui/artalk/src/types/event.ts)
通过 Artalk 提供的 `API` 和 `Event`,你可以实现很多高级功能,比如编写评论管理机器人、评论提醒推送插件等。Artalk 并不为此提供技术指导,但鼓励你参考此处的文档自行定制。
+90
View File
@@ -0,0 +1,90 @@
# 插件开发
使用 `Artalk.use` 来扩展 Artalk。
```js
import Artalk from 'artalk'
Artalk.use((ctx) => {
ctx.on('list-loaded', () => {
console.log('评论列表加载完毕')
ctx.getCommentNodes().forEach((node) => {
node.getEl().style.background = 'red'
})
})
})
Artalk.use((ctx) => {
let el = null
ctx.on('mounted', () => {
el = document.createElement('div')
document.body.appendChild(el)
console.log('Artalk 实例被挂载')
})
ctx.on('unmounted', () => {
el.remove()
console.log('Artalk 实例被销毁')
})
})
const artalk = Artalk.init({ ... })
```
请注意:
- `Artalk.use` 必须在 `Artalk.init` 之前调用才生效。
- 请勿依赖插件的加载顺序,请监听事件来执行插件逻辑。
- 当所有的插件加载完毕后,会触发 `created` 事件。
- 当插件和配置加载完毕后,会触发 `mounted` 事件。
- 当 Artalk 实例被销毁时,会触发 `unmounted` 事件。
- 当配置发生变化时,会触发 `updated` 事件。
在 use 函数中,你可以通过 `ctx` 来访问 Artalk 的 Context 对象。
## Context
Context 对象包含了 Artalk 的上下文信息。
| 成员 | 说明 |
| --------------------- | -------------------- |
| `ctx.getEl` | 获取容器元素 |
| `ctx.getConf` | 获取配置 |
| `ctx.updateConf` | 更新配置 |
| `ctx.watchConf` | 监听配置 |
| `ctx.setDarkMode` | 设置夜间模式 |
| `ctx.getApi` | 获取 API 客户端对象 |
| -- | -- |
| `ctx.fetch` | 获取评论数据 |
| `ctx.reload` | 重载评论列表 |
| `ctx.getComments` | 获取所有评论数据对象 |
| `ctx.getCommentNodes` | 获取所有评论节点对象 |
| -- | -- |
| `ctx.on` | 添加事件监听 |
| `ctx.off` | 解除事件监听 |
| `ctx.trigger` | 触发事件 |
| -- | -- |
| `ctx.get` | 获取依赖 |
| `ctx.inject` | 注入依赖 |
::: warning
Context API 目前仍不稳定,开发可能会有变动,升级请关注 CHANGELOG。
:::
参考:[@artalk/src/types/context.ts](https://github.com/ArtalkJS/Artalk/blob/master/ui/artalk/src/types/context.ts)
Artalk 包含完整的 TypeScript 类型定义,你可以通过编辑器的自动补全来查看 API。
## 示例插件
Artalk 有很多内置的插件,你可以参考它们的源码来开发自己的插件。
[@ArtalkJS/Artalk - src/plugins](https://github.com/ArtalkJS/Artalk/tree/master/ui/artalk/src/plugins)
我们还提供了一些外置的插件,同样可以参考:
| 插件 | 说明 |
| -------------------------------------------------------------------------------------------- | -------------- |
| [@artalk/plugin-katex](https://github.com/ArtalkJS/Artalk/tree/master/ui/plugin-katex) | LaTeX 公式插件 |
| [@artalk/plugin-lightbox](https://github.com/ArtalkJS/Artalk/tree/master/ui/plugin-lightbox) | 图片灯箱插件 |
File renamed without changes.
File renamed without changes.
@@ -16,50 +16,50 @@ Artalk 支持通过多元推送功能以多种方式发送管理员通知。
# 多元推送
admin_notify:
# 通知模版
notify_tpl: "default"
notify_tpl: default
noise_mode: false
# 邮件通知管理员
email:
enabled: true # 当使用其他推送方式时,可以关闭管理员邮件通知
mail_subject: "[{{site_name}}] 您的文章「{{page_title}}」有新回复"
mail_tpl: ""
mail_subject: '[{{site_name}}] 您的文章「{{page_title}}」有新回复'
mail_tpl: ''
# Telegram
telegram:
enabled: false
api_token: ""
api_token: ''
receivers:
- 7777777
# 飞书
lark:
enabled: false
webhook_url: ""
webhook_url: ''
# 钉钉
ding_talk:
enabled: false
token: ""
secret: ""
token: ''
secret: ''
# Bark
bark:
enabled: false
server: "http://day.app/xxxxxxx/"
server: http://day.app/xxxxxxx/
# Slack
slack:
enabled: false
oauth_token: ""
oauth_token: ''
receivers:
- "CHANNEL_ID"
- CHANNEL_ID
# LINE
line:
enabled: false
channel_secret: ""
channel_access_token: ""
channel_secret: ''
channel_access_token: ''
receivers:
- "USER_ID_1"
- "GROUP_ID_1"
- USER_ID_1
- GROUP_ID_1
# WebHook
webhook:
enabled: false
url: ""
url: ''
```
:::
@@ -71,8 +71,8 @@ admin_notify:
```yaml
admin_notify:
enabled: true # 当使用其他推送方式时,可以关闭管理员邮件通知
mail_subject: "[{{site_name}}] 您的文章「{{page_title}}」有新回复"
mail_tpl: ""
mail_subject: '[{{site_name}}] 您的文章「{{page_title}}」有新回复'
mail_tpl: ''
```
当使用其他推送方式时,可以关闭管理员邮件通知。
@@ -83,7 +83,7 @@ admin_notify:
- 配置项 `mail_subject` 为发送给管理员的邮件标题。
- 配置项 `mail_tpl` 为发送给管理员的邮件选用特定的[邮件模板](./email.md#邮件模板)(填写邮件模板文件路径)。
(当该项留空时,将继承 `email.mail_tpl` 配置项)
## Telegram
@@ -93,7 +93,7 @@ admin_notify:
# Telegram
telegram:
enabled: true
api_token: ""
api_token: ''
receivers:
- 7777777
```
@@ -132,7 +132,7 @@ admin_notify:
# 飞书
lark:
enabled: true
webhook_url: ""
webhook_url: ''
```
- `webhook_url`:填入创建群组机器人时得到的 WebHook 地址。
@@ -160,8 +160,8 @@ admin_notify:
# 钉钉
ding_talk:
enabled: true
token: ""
secret: ""
token: ''
secret: ''
```
可参考:[钉钉开放文档](https://open.dingtalk.com/document/robots/custom-robot-access)
@@ -173,17 +173,15 @@ admin_notify:
# Bark
bark:
enabled: true
server: "http://day.app/xxxxxxx/"
server: http://day.app/xxxxxxx/
```
[Bark](https://github.com/Finb/Bark) 是一款开源的 iOS App,并且[支持自托管](https://github.com/Finb/bark-server),你能使用 Bark 轻松地推送消息给你的 iOS 设备。
你可以在 App Store 搜索下载,并获得需要填入 Artalk 的 `server` 配置项:
<img src="/images/notify/bark.png" width="700px">
## Slack
```yaml
@@ -191,9 +189,9 @@ admin_notify:
# Slack
slack:
enabled: true
oauth_token: ""
oauth_token: ''
receivers:
- "CHANNEL_ID"
- CHANNEL_ID
```
## LINE
@@ -203,18 +201,18 @@ admin_notify:
# LINE
line:
enabled: true
channel_secret: ""
channel_access_token: ""
channel_secret: ''
channel_access_token: ''
receivers:
- "USER_ID_1"
- "GROUP_ID_1"
- USER_ID_1
- GROUP_ID_1
```
## 通知模版
```yaml
admin_notify:
notify_tpl: "default"
notify_tpl: default
```
配置项 `admin_notify.notify_tpl` 可设置为自定义通知模版「文件路径」,默认的通知模版为:
@@ -229,6 +227,15 @@ admin_notify:
可用变量和邮件模板相同,可参考:[邮件模版](./email.md#邮件模板)
## 待审评论仍然发送通知 `notify_pending`
```yaml
admin_notify:
notify_pending: false
```
`notify_pending` 默认为关闭状态,当该项设置为 `false` 时,待审评论不会发送通知。你可以在控制中心查看所有待审核的评论。
## 嘈杂模式 `noise_mode`
```yaml
@@ -236,7 +243,7 @@ admin_notify:
noise_mode: false
```
noise_mode 默认为关闭状态,当该项设置为 `false` 时,站内仅向管理员回复的消息会发送通知,例如「普通用户 A」回复「普通用户 B」,这两个用户之间的通讯不会通知管理员。
`noise_mode` 默认为关闭状态,当该项设置为 `false` 时,站内仅向管理员回复的消息会发送通知,例如「普通用户 A」回复「普通用户 B」,这两个用户之间的通讯不会通知管理员。
注:当 `moderator.pending_default` 为 `true` 时,noise_mode 为始终开启状态。
@@ -250,21 +257,21 @@ noise_mode 默认为关闭状态,当该项设置为 `false` 时,站内仅向
```yaml
admin_notify:
webhook:
enabled: true
url: "http://localhost:8080/"
webhook:
enabled: true
url: http://localhost:8080/
```
**Body 数据内容**
`application/json` 类型
|Key|描述|类型|备注|
| - | - | - | - |
|`notify_subject`|通知标题 |String| 对应 admin_notify.notify_subject 配置项 |
|`notify_body` |通知内容 |String| 根据 admin_notify.notify_tpl 模版渲染 |
|`comment` |评论内容 |Object| 新创建的评论数据对象 |
|`parent_comment`|评论回复的目标|Object| 如果是根节点评论值为 null |
| Key | 描述 | 类型 | 备注 |
| ---------------- | -------------- | ------ | --------------------------------------- |
| `notify_subject` | 通知标题 | String | 对应 admin_notify.notify_subject 配置项 |
| `notify_body` | 通知内容 | String | 根据 admin_notify.notify_tpl 模版渲染 |
| `comment` | 评论内容 | Object | 新创建的评论数据对象 |
| `parent_comment` | 评论回复的目标 | Object | 如果是根节点评论值为 null |
**Body 数据样本**
@@ -302,53 +309,53 @@ admin_notify:
**Node.js express 处理示例**
```js
const express = require('express');
const express = require('express')
const app = express();
const app = express()
app.use(express.json()); // Use JSON middleware
app.use(express.json()) // Use JSON middleware
app.post('/', function(request, response){
console.log(request.body);
app.post('/', (request, response) => {
console.log(request.body)
const notifySubject = request.body.notify_subject
const notifyBody = request.body.notify_body
console.log(notifySubject, notifyBody);
const notifyBody = request.body.notify_body
console.log(notifySubject, notifyBody)
response.send(request.body);
});
response.send(request.body)
})
app.listen(8080);
app.listen(8080)
```
**Node.js http 处理示例**
```js
const http = require("http");
const http = require('http')
const requestListener = function (req, res) {
const requestListener = (req, res) => {
// receive json request
let body = "";
req.on("data", function (data) {
body += data;
});
req.on("end", function () {
let json = "";
let body = ''
req.on('data', (data) => {
body += data
})
req.on('end', () => {
let json = ''
try {
json = JSON.parse(body);
json = JSON.parse(body)
} catch {}
// do something with json
console.log(json);
res.end();
});
console.log(json)
res.end()
})
res.writeHead(200);
res.end("Hello, World!");
};
res.writeHead(200)
res.end('Hello, World!')
}
const server = http.createServer(requestListener);
server.listen(8080);
const server = http.createServer(requestListener)
server.listen(8080)
```
**PHP Laravel 处理示例**
@@ -373,10 +380,10 @@ import (
)
type ArtalkNotify struct {
NotifySubject string `json:"notify_subject"`
NotifyBody string `json:"notify_body"`
Comment interface{} `json:"comment"`
ParentComment interface{} `json:"parent_comment"`
NotifySubject string `json:"notify_subject"`
NotifyBody string `json:"notify_body"`
Comment interface{} `json:"comment"`
ParentComment interface{} `json:"parent_comment"`
}
func webhookHandler(rw http.ResponseWriter, req *http.Request) {
@@ -394,4 +401,3 @@ func main() {
log.Fatal(http.ListenAndServe(":8080", nil))
}
```
+67
View File
@@ -0,0 +1,67 @@
# 后端构建
## 编译运行
```bash
# 拉取代码
git clone https://github.com/ArtalkJS/Artalk.git Artalk
# 编译程序
cd Artalk && make all
# 配置文件
cp conf/artalk.example.yml artalk.yml
vim artalk.yml
# 运行程序
./bin/artalk help
./bin/artalk -c artalk.yml server
```
## 构建二进制文件
```bash
# 拉取代码
git clone https://github.com/ArtalkJS/Artalk.git
# 执行编译
make all
```
编译二进制文件将会输出到 `bin` 目录中
## Docker Compose 编译运行
```bash
# 拉取代码
git clone https://github.com/ArtalkJS/Artalk
cd Artalk
# 构建镜像
docker-compose build
# 运行
docker-compose up -d
```
## Docker 镜像构建
```bash
# 拉取代码
git clone https://github.com/ArtalkJS/Artalk
cd Artalk
# 构建镜像
make docker-docker
# 发布镜像
make docker-push
```
## DevOps
程序由 [GitHub Actions](https://github.com/ArtalkJS/Artalk/actions) 自动化构建
| 版本发布 | Docker 镜像构建发布 | 二进制构建发布 | 前端构建发布 |
| ------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| [![Release](https://github.com/ArtalkJS/Artalk/actions/workflows/release.yml/badge.svg?branch=master)](https://github.com/ArtalkJS/Artalk/actions/workflows/release.yml) | [![Build Docker](https://github.com/ArtalkJS/Artalk/actions/workflows/build-docker.yml/badge.svg)](https://github.com/ArtalkJS/Artalk/actions/workflows/build-docker.yml) | [![Release](https://github.com/ArtalkJS/Artalk/actions/workflows/build-app.yml/badge.svg?branch=master)](https://github.com/ArtalkJS/Artalk/actions/workflows/build-app.yml) | [![Release](https://github.com/ArtalkJS/Artalk/actions/workflows/build-frontend.yml/badge.svg?branch=master)](https://github.com/ArtalkJS/Artalk/actions/workflows/build-frontend.yml) |
@@ -15,29 +15,29 @@ Artalk 内置图片验证码功能,你可以配置操作频率限制,当超
```yaml
# 验证码
captcha:
enabled: true # 总开关
always: false # 总是需要验证码
captcha_type: "image" # 验证码类型
action_limit: 3 # 激活验证码所需操作次数
enabled: true # 总开关
always: false # 总是需要验证码
captcha_type: image # 验证码类型
action_limit: 3 # 激活验证码所需操作次数
action_reset: 60 # 重置操作计数器超时 (单位:s, 设为 -1 不重置)
# Turnstile
# (https://www.cloudflare.com/products/turnstile/)
turnstile:
site_key: ""
secret_key: ""
site_key: ''
secret_key: ''
# reCaptcha
# (https://www.google.com/recaptcha/about/)
recaptcha:
site_key: ""
secret_key: ""
site_key: ''
secret_key: ''
# hCaptcha (https://www.hcaptcha.com/)
hcaptcha:
site_key: ""
secret_key: ""
site_key: ''
secret_key: ''
# Geetest 极验 (https://www.geetest.com)
geetest:
captcha_id: ""
captcha_key: ""
captcha_id: ''
captcha_key: ''
```
- **always**:当该项为 `true` 时,总是需要输入验证码。
@@ -49,7 +49,7 @@ captcha:
## 配置举例
#### 例 1
### 例 1
在 60s 时间范围内,当操作次数超过 3 次,将一直被要求输入验证码:
@@ -61,7 +61,7 @@ captcha:
在 60s 后将自动重置计数器,即重新获得 3 次不用输入验证码的机会。
#### 例 2
### 例 2
无论多少时间范围内,这个 IP 地址操作次数只要超过 5 次时,将一直被要求输入验证码:
@@ -71,7 +71,7 @@ captcha:
action_reset: -1
```
#### 例 3
### 例 3
总是要求输入验证码,无论这个 IP 操作多少次:
@@ -99,10 +99,10 @@ captcha:
```yaml
captcha:
# 省略其他配置...
captcha_type: "turnstile"
captcha_type: turnstile
turnstile:
site_key: ""
secret_key: ""
site_key: ''
secret_key: ''
```
## reCAPTCHA
@@ -114,10 +114,10 @@ captcha:
```yaml
captcha:
# 省略其他配置...
captcha_type: "recaptcha"
captcha_type: recaptcha
recaptcha:
site_key: ""
secret_key: ""
site_key: ''
secret_key: ''
```
注:国内访问 Google API 也许需要配置系统代理。
@@ -133,10 +133,10 @@ reCAPTCHA 官方提供了用于测试的 Keys:[可见此处](https://developer
```yaml
captcha:
# 省略其他配置...
captcha_type: "hcaptcha"
captcha_type: hcaptcha
hcaptcha:
site_key: ""
secret_key: ""
site_key: ''
secret_key: ''
```
hCaptcha 官方提供了用于测试的 Keys:[可见此处](https://docs.hcaptcha.com/#integration-testing-test-keys)。
@@ -152,9 +152,8 @@ Artalk 支持接入 [Geetest 极验](https://www.geetest.com/adaptive-captcha)
```yaml
captcha:
# 省略其他配置...
captcha_type: "geetest"
captcha_type: geetest
geetest:
captcha_id: ""
captcha_key: ""
captcha_id: ''
captcha_key: ''
```
@@ -16,8 +16,8 @@ artalk -c ./conf.yml
Artalk 读取以 `ATK_` 为前缀的环境变量,并且全部大写,子节点用单个下划线表示,配置名含下划线请用双下划线表示:
- `_` (单下划线) 转为 `.` 表示子节点
- `__` (双下划线) 转为 `_` 表示配置名的下划线
- `_` (单下划线) 转为 `.` 表示子节点
- `__` (双下划线) 转为 `_` 表示配置名的下划线
e.g.
@@ -35,7 +35,7 @@ ATK_ADMIN_USERS_0_NAME -> admin_users[0].name
可参考一份「完整的配置文件」:[artalk.example.zh-CN.yml](https://github.com/ArtalkJS/Artalk/blob/master/conf/artalk.example.zh-CN.yml)
#### 使用 gen 命令生成配置文件
### 使用 gen 命令生成配置文件
Artalk 提供 `gen` 命令,你可以快速生成一份新的配置文件:
@@ -43,7 +43,7 @@ Artalk 提供 `gen` 命令,你可以快速生成一份新的配置文件:
artalk gen conf -lang zh-CN ./artalk.yml
```
#### 命令行下载配置文件
### 命令行下载配置文件
```bash
wget -O artalk.yml https://raw.githubusercontent.com/ArtalkJS/Artalk/master/conf/artalk.example.zh-CN.yml
@@ -54,7 +54,7 @@ wget -O artalk.yml https://raw.githubusercontent.com/ArtalkJS/Artalk/master/conf
在 Artalk 启动之前,你需要配置一个 `app_key` 用于对网站内容进行安全加密:
```yaml
app_key: "<任意的字符>"
app_key: <任意的字符>
```
## 语言 `locale`
@@ -62,7 +62,7 @@ app_key: "<任意的字符>"
设置 Artalk 的语言。遵循 Unicode BCP 47 规范,该项默认为 "zh-CN" (简体中文)。
```yml
locale: "zh-CN"
locale: zh-CN
```
详情参考:[多语言](../frontend/i18n.md)
@@ -77,8 +77,8 @@ SQLite 是轻型数据库,使用单个文件存储数据,无需额外运行
```yaml
db:
type: "sqlite"
file: "./data/artalk.db"
type: sqlite
file: ./data/artalk.db
```
#### MySQL / PostgreSQL / SQL Server
@@ -87,15 +87,16 @@ db:
```yaml
db:
type: "mysql" # sqlite, mysql, pgsql, mssql
name: "artalk" # 数据库名
host: "localhost" # 地址
port: "3306" # 端口
user: "root" # 账号
password: "" # 密码
charset: "utf8mb4" # 编码格式
table_prefix: "" # 表前缀 (例如:"atk_")
ssl: false # 启用 SSL
type: mysql # sqlite, mysql, pgsql, mssql
name: artalk # 数据库名
host: localhost # 地址
port: 3306 # 端口
user: root # 账号
password: '' # 密码
charset: utf8mb4 # 编码格式
table_prefix: '' # 表前缀 (例如:"atk_")
ssl: false # 启用 SSL
prepare_stmt: true # 预编译语句
```
数据表将在 Artalk 启动时自动完成创建,无需额外操作。
@@ -106,8 +107,8 @@ db:
```yaml
db:
type: "mysql"
dsn: "mysql://myuser:mypassword@localhost:3306/mydatabase?tls=skip-verify"
type: mysql
dsn: mysql://myuser:mypassword@localhost:3306/mydatabase?tls=skip-verify
```
更多内容参考:[@go-sql-driver/mysql:README.md](https://github.com/go-sql-driver/mysql)
@@ -124,8 +125,8 @@ Artalk 支持多站点,你可以创建多个管理员账户,为其分配站
```yaml
trusted_domains:
- "https://前端使用域名A.com"
- "https://前端使用域名B.com"
- https://前端使用域名A.com
- https://前端使用域名B.com
```
配置该项能限制来自列表外的 Referer 和跨域请求。
@@ -144,7 +145,7 @@ trusted_domains:
```yaml
trusted_domains:
- "*"
- '*'
```
::: danger
@@ -165,13 +166,13 @@ CSRF 跨域攻击防范措施参考:[OWASP 安全备忘单](https://cheatsheet
如果你觉得大概是不会用到 Artalk 的多站点功能,可以直接将该项配置为你的站点名,例如:
```yaml
site_default: "Artalk 官网"
site_default: Artalk 官网
```
然后在前端直接使用这个站点名:
```js
Artalk.init({ site: "Artalk 官网" })
Artalk.init({ site: 'Artalk 官网' })
```
这样,你就无需在侧边栏的[控制中心](../frontend/sidebar.md#控制中心)手动创建站点。
@@ -210,11 +211,11 @@ Artalk.init({ site: "Artalk 官网" })
```yaml
cache:
enabled: true # 启用缓存 (默认关闭)
type: "builtin" # 支持 redis, memcache, builtin (自带缓存)
expires: 30 # 缓存过期时间 (单位:分钟)
warm_up: false # 程序启动时预热缓存
server: "" # 连接缓存服务器 (例如:"localhost:6379")
enabled: true # 启用缓存 (默认关闭)
type: builtin # 支持 redis, memcache, builtin (自带缓存)
expires: 30 # 缓存过期时间 (单位:分钟)
warm_up: false # 程序启动时预热缓存
server: '' # 连接缓存服务器 (例如:"localhost:6379")
```
- **warm_up**:缓存预热功能。设置为 `true`,在 Artalk 启动时会立刻对数据库内容进行全面缓存,如果你的评论数据较多,多达上万条,启动时间可能会延长。
@@ -231,10 +232,10 @@ Redis 身份认证、数据库配置:
cache:
# 省略其他配置项...
redis:
network: "tcp" # 连接方式 (tcp 或 unix)
username: "" # 用户名
password: "" # 密码
db: 0 # 使用零号数据库
network: tcp # 连接方式 (tcp 或 unix)
username: '' # 用户名
password: '' # 密码
db: 0 # 使用零号数据库
```
<!-- 技术细节:[Artalk 缓存机制 时序图.png](/images/artalk/artalk-cache.png) -->
@@ -245,7 +246,7 @@ cache:
Artalk 的默认 HTTP 端口为 23366,你可以在配置文件中指定:
```yaml
host: "0.0.0.0"
host: '0.0.0.0'
port: 23366
```
@@ -264,8 +265,8 @@ artalk server --host 127.0.0.1 --port 8080
```yaml
ssl:
enabled: true
cert_path: ""
key_path: ""
cert_path: ''
key_path: ''
```
你可以配置该项,让 HTTP 升级为 HTTPS,通过 SSL 协议加密传输数据。
@@ -278,7 +279,7 @@ ssl:
## 时区配置 `timezone`
```yaml
timezone: "Asia/Shanghai"
timezone: Asia/Shanghai
```
该值填写你所在地时区,对应 IANA 数据库时区名,参考:[Wikipedia](https://en.wikipedia.org/wiki/List_of_tz_database_time_zones) / [RFC-6557](https://www.rfc-editor.org/rfc/rfc6557.html)。
@@ -307,7 +308,7 @@ login_timeout: 259200
```yaml
log:
enabled: true # 总开关
filename: "./data/artalk.log" # 日志文件路径
filename: ./data/artalk.log # 日志文件路径
```
## 调试模式 `debug`
@@ -339,7 +340,7 @@ artalk -w /root/artalk -c ./conf.yml
例如 `conf.yml` 中有这样的配置:
```yaml
test_file: "./data/artalk.log"
test_file: ./data/artalk.log
```
将读取 `/root/artalk/data/artalk.log`。
@@ -54,7 +54,7 @@ After=network.target network-online.target
Requires=network-online.target
[Service]
Type=notify
Type=simple
User=artalk
Group=artalk
ExecStart=/usr/bin/artalk server -w /var/lib/artalk -c /etc/artalk/artalk.yml
@@ -79,7 +79,7 @@ WantedBy=multi-user.target
保存服务文件后,你可以设置自动启动服务:
```bash
```bash
sudo systemctl daemon-reload
sudo systemctl enable --now artalk
```
File renamed without changes.
@@ -43,7 +43,7 @@ docker run -d \
然后,在前端配置填入后端地址:
```js
Artalk.init({ server: "http://your_domain:8080" })
Artalk.init({ server: 'http://your_domain:8080' })
```
## 重启
@@ -11,21 +11,21 @@ Artalk 支持 SMTP 协议、阿里云邮件推送、调用系统 sendmail 命令
```yaml
# 邮件通知
email:
enabled: false # 总开关
send_type: "smtp" # 发送方式 [smtp, ali_dm, sendmail]
enabled: false # 总开关
send_type: smtp # 发送方式 [smtp, ali_dm, sendmail]
send_name: '{{reply_nick}}' # 发信人昵称
send_addr: "example@qq.com" # 发信人地址
mail_subject: "[{{site_name}}] 您收到了来自 @{{reply_nick}} 的回复"
mail_tpl: "default" # 邮件模板文件
send_addr: example@qq.com # 发信人地址
mail_subject: '[{{site_name}}] 您收到了来自 @{{reply_nick}} 的回复'
mail_tpl: default # 邮件模板文件
smtp:
host: "smtp.qq.com"
host: smtp.qq.com
port: 587
username: "example@qq.com"
password: ""
username: example@qq.com
password: ''
ali_dm: # https://help.aliyun.com/document_detail/29444.html
access_key_id: "" # 阿里云颁发给用户的访问服务所用的密钥 ID
access_key_secret: "" # 用于加密的密钥
account_name: "example@example.com" # 管理控制台中配置的发信地址
access_key_id: '' # 阿里云颁发给用户的访问服务所用的密钥 ID
access_key_secret: '' # 用于加密的密钥
account_name: example@example.com # 管理控制台中配置的发信地址
```
### 选择发件方式
@@ -35,7 +35,7 @@ email:
```yaml
email:
enabled: true
send_type: "smtp" # 发送方式
send_type: smtp # 发送方式
# 省略其他配置...
smtp:
# SMTP 配置...
@@ -49,12 +49,12 @@ email:
# 邮件通知
email:
enabled: true
send_type: "smtp" # 选择 smtp
send_type: smtp # 选择 smtp
smtp:
host: "smtp.qq.com"
host: smtp.qq.com
port: 587
username: "example@qq.com"
password: ""
username: example@qq.com
password: ''
```
### 阿里云推送配置
@@ -62,11 +62,11 @@ email:
```yaml
email:
enabled: true
send_type: "ali_dm" # 选择 ali_dm
send_type: ali_dm # 选择 ali_dm
ali_dm:
access_key_id: "" # 阿里云颁发给用户的访问服务所用的密钥 ID
access_key_secret: "" # 用于加密的密钥
account_name: "example@example.com" # 管理控制台中配置的发信地址
access_key_id: '' # 阿里云颁发给用户的访问服务所用的密钥 ID
access_key_secret: '' # 用于加密的密钥
account_name: example@example.com # 管理控制台中配置的发信地址
```
可参考:[阿里云官方文档](https://help.aliyun.com/document_detail/29444.html)
@@ -86,16 +86,16 @@ email:
```yaml
email:
# 省略其他配置...
mail_subject: "[{{site_name}}] 您收到了来自 @{{reply_nick}} 的回复"
mail_subject: '[{{site_name}}] 您收到了来自 @{{reply_nick}} 的回复'
mail_subject_to_admin: '[{{site_name}}] 您的文章 "{{page_title}}" 有新回复'
mail_tpl: "default" # 邮件模板文件
mail_tpl: default # 邮件模板文件
```
变量是 “Mustache” 的语法,`双大括号` + `变量名` 的形式即可输出一个变量:
变量是 “Mustache” 的语法,`双大括号` + `变量名` 的形式即可输出一个变量:
**基本内容变量**
```
```yaml
{{content}} # 评论内容
{{link_to_reply}} # 回复链接
{{nick}} # 评论者昵称
@@ -109,7 +109,7 @@ email:
::: details 查看其他变量
```
```yaml
# 评论创建者
{{comment.badge_color}}
{{comment.badge_name}}
@@ -276,7 +276,7 @@ email:
"parent_comment.ua": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/93.0.4577.82 Safari/537.36",
"parent_comment.visible": false,
"parent_comment.vote_down": 0,
"parent_comment.vote_up": 0,
"parent_comment.vote_up": 0
}
```
@@ -290,7 +290,7 @@ email:
```yaml
email:
mail_tpl: "/root/Artalk/data/mail_tpl/your_email_template.html"
mail_tpl: /root/Artalk/data/mail_tpl/your_email_template.html
# 其他配置省略...
```
@@ -298,15 +298,13 @@ email:
```html
<div>
<p>Hi, {{nick}}:</p>
<p>
您在 “{{page_title}}” 收到了回复:
</p>
<div>
<div>@{{reply_nick}}:</div>
<div>{{reply_content}}</div>
</div>
<p><a href="{{link_to_reply}}" target="_blank">回复消息 »</a></p>
<p>Hi, {{nick}}:</p>
<p>您在 “{{page_title}}” 收到了回复:</p>
<div>
<div>@{{reply_nick}}:</div>
<div>{{reply_content}}</div>
</div>
<p><a href="{{link_to_reply}}" target="_blank">回复消息 »</a></p>
</div>
```
@@ -319,7 +317,7 @@ Artalk 内置许多预设的邮件模板,例如 `mail_tpl: "default"` 使用
```yaml
admin_notify:
enabled: true
mail_subject: "[{{site_name}}] 您的文章「{{page_title}}」有新回复"
mail_subject: '[{{site_name}}] 您的文章「{{page_title}}」有新回复'
```
注:旧版 `email.mail_subject_to_admin` 配置项已弃用,请使用以上替代。
@@ -1,10 +1,10 @@
# 在后端控制前端
你可以在后端完全控制前端界面的行为(包括设定[前端的配置](/guide/frontend/config)),我们推荐使用这种方式部署 Artalk,并且这个特性「默认开启」。
你可以在后端完全控制前端界面的行为(包括设定几乎所有[前端配置项](/guide/frontend/config)),我们推荐使用这种方式配置 Artalk 界面,并且这个特性「默认开启」。
## 如何修改前端配置
## 如何修改前端界面配置
在侧边栏的[控制中心](/guide/frontend/sidebar.md#控制中心)提供了图形设置界面,你能快速轻松地对前端配置进行修改。
在侧边栏的[控制中心](/guide/frontend/sidebar.md#控制中心)提供了图形设置界面,你能快速轻松地对前端界面配置进行修改。
<img src="../../images/sidebar/fe-setting.png" width="400px">
@@ -14,7 +14,7 @@
```html
<!-- CSS -->
<link href="https://<artalk_go_server>/dist/Artalk.css" rel="stylesheet">
<link href="https://<artalk_go_server>/dist/Artalk.css" rel="stylesheet" />
<!-- JS -->
<script src="https://<artalk_go_server>/dist/Artalk.js"></script>
@@ -34,10 +34,10 @@ Artalk 提供图形界面简化配置,一般情况无需手动修改。
```yaml
frontend:
placeholder: "键入内容..."
noComment: "「此时无声胜有声」"
sendBtn: "发送评论"
emoticons: "https://raw.githubusercontent.com/ArtalkJS/Emoticons/master/grps/default.json"
placeholder: 键入内容...
noComment: 「此时无声胜有声」
sendBtn: 发送评论
emoticons: 'https://raw.githubusercontent.com/ArtalkJS/Emoticons/master/grps/default.json'
# ----- 此处省略 -------
# 与前端配置项名称保持一致
```
@@ -1,6 +1,6 @@
# 图片上传
Artalk 提供图片上传功能,支持限制图片大小、上传频率等,你还能结合 upgit 将图片上传到图床。
Artalk 提供图片上传功能,支持限制图片大小、上传频率等,你还能结合 UpGit 将图片上传到图床。
你可以在[控制中心](/guide/frontend/sidebar.md#控制中心)找到「设置」界面修改此配置。
@@ -11,30 +11,50 @@ Artalk 提供图片上传功能,支持限制图片大小、上传频率等,
```yaml
# 图片上传
img_upload:
enabled: true # 总开关
path: "./data/artalk-img/" # 图片存放路径
max_size: 5 # 图片大小限制 (单位:MB)
public_path: null # 指定图片链接基础路径 (默认为 "/static/images/")
enabled: true # 总开关
path: ./data/artalk-img/ # 图片存放路径
max_size: 5 # 图片大小限制 (单位:MB)
public_path: null # 指定图片链接基础路径 (默认为 "/static/images/")
# 使用 upgit 将图片上传到 GitHub 或图床
upgit:
enabled: false # 启用 upgit
exec: "./upgit -c <upgit配置文件路径> -t /artalk-img"
enabled: false # 启用 upgit
exec: upgit -c <upgit配置文件路径> -t /artalk-img
del_local: true # 上传后删除本地的图片
```
## 使用 Upgit 上传到图床
[Upgit](https://github.com/pluveto/upgit) 支持将图片上传到 Github、Gitee、腾讯云 COS、七牛云、又拍云、SM.MS 等图床或代码仓库。
[UpGit](https://github.com/pluveto/upgit) 支持将图片上传到 Github、Gitee、腾讯云 COS、七牛云、又拍云、SM.MS 等图床或代码仓库。
首先,根据 [README.md](https://github.com/pluveto/upgit) 的说明,下载 Upgit 并完成你需要上传的目标图床的配置。
首先,根据 [README.md](https://github.com/pluveto/upgit) 的说明,下载 UpGit 并完成你需要上传的目标图床的配置。
然后在 Artalk 的 `img_upload.upgit` 字段填入 Upgit 启动参数 (建议使用程序绝对路径),例如:
然后,将 UpGit 加入系统的环境变量中,在 `~/.bashrc` 加入:
```bash
export PATH=$PATH:/path/to/upgit
```
(或者直接移入 `/usr/bin`)
最后,在 Artalk 的 `img_upload.upgit` 字段填入 UpGit 启动参数:
```yaml
upgit:
enabled: true # 启用 upgit
exec: "/root/upgit -c <upgit配置文件路径> -t /artalk-img"
del_local: true # 上传后删除本地的图片
upgit:
enabled: true # 启用 upgit
exec: upgit -c <upgit配置文件路径> -t /artalk-img
del_local: true # 上传后删除本地的图片
```
::: warning 更新注意
从 `v2.8.4` 版本开始,为了增强安全性,Artalk 不再允许指定 UpGit 的可执行文件路径,请将其加入系统的环境变量中。:)
:::
### Docker 挂载 UpGit
如果你使用 Docker 部署 Artalk,可以将 UpGit 可执行文件挂载到容器中:
```bash
docker run -d --name artalk -v /path/to/upgit:/usr/bin/upgit -v /path/to/artalk:/app/data -p 8080:23366 artalk
```
## 上传频率限制
@@ -58,7 +78,7 @@ http://<后端地址>/static/images/
当该项为「相对路径」时,例如:`/static/images/` 前端上传图片得到的 HTML 标签将为:
```html
<img src="http://<后端地址>/static/images/1.png">
<img src="http://<后端地址>/static/images/1.png" />
```
注:这里的 `<后端地址>` 是前端 `conf.server` 配置。
@@ -66,7 +86,7 @@ http://<后端地址>/static/images/
当该项为「完整 URL 路径」时,例如:`https://cdn.github.com/img/` 时,图片标签将为:
```html
<img src="https://cdn.github.com/img/1.png">
<img src="https://cdn.github.com/img/1.png" />
```
提示:这个配置可以结合负载均衡等场景使用。
@@ -81,13 +101,13 @@ Artalk.init({
const form = new FormData()
form.set('file', file)
const imgUrl = await fetch("https://api.example.org/upload", {
const imgUrl = await fetch('https://api.example.org/upload', {
method: 'POST',
body: form
body: form,
})
return imgUrl
}
},
})
```
File renamed without changes.
File renamed without changes.
@@ -12,29 +12,29 @@ Artalk 支持多种评论过滤方式以拦截垃圾评论,支持通过 Akisme
# 评论审核
moderator:
pending_default: false # 发表新评论默认为 “待审状态”
api_fail_block: false # 垃圾检测 API 请求错误仍然拦截
api_fail_block: false # 垃圾检测 API 请求错误仍然拦截
# akismet.com 反垃圾
akismet_key: ""
akismet_key: ''
# 腾讯云文本内容安全 (tms)
tencent: # https://cloud.tencent.com/document/product/1124/64508
enabled: false
secret_id: ""
secret_key: ""
region: "ap-guangzhou"
secret_id: ''
secret_key: ''
region: ap-guangzhou
# 阿里云内容安全
aliyun: # https://help.aliyun.com/document_detail/28417.html
enabled: false
access_key_id: ""
access_key_secret: ""
region: "cn-shanghai"
access_key_id: ''
access_key_secret: ''
region: cn-shanghai
# 关键词词库过滤
keywords:
enabled: false
pending: false # 匹配成功设为待审状态
files: # 支持多个词库文件
- "./data/词库_1.txt"
files: # 支持多个词库文件
- './data/词库_1.txt'
file_sep: "\n" # 词库文件内容分割符
replac_to: "x" # 替换字符
replac_to: 'x' # 替换字符
```
## 默认待审模式
@@ -58,7 +58,7 @@ moderator:
```yaml
moderator:
akismet_key: "your_key"
akismet_key: your_key
```
## 腾讯云文本内容安全
@@ -71,9 +71,9 @@ moderator:
moderator:
tencent:
enabled: true
secret_id: ""
secret_key: ""
region: "ap-guangzhou"
secret_id: ''
secret_key: ''
region: ap-guangzhou
```
## 阿里云内容安全
@@ -86,9 +86,9 @@ moderator:
moderator:
aliyun:
enabled: true
access_key_id: ""
access_key_secret: ""
region: "cn-shanghai"
access_key_id: ''
access_key_secret: ''
region: cn-shanghai
```
## 关键词词库过滤
@@ -100,10 +100,10 @@ moderator:
keywords:
enabled: true
pending: false # 匹配成功设为待审状态
files: # 支持多个词库文件
- "./data/词库_1.txt"
files: # 支持多个词库文件
- ./data/词库_1.txt
file_sep: "\n" # 词库文件内容分割符
replac_to: "x" # 替换字符
replac_to: 'x' # 替换字符
```
- **pending**:当成功匹配时,是否将评论设为待审核状态。
+82
View File
@@ -0,0 +1,82 @@
# 管理员 × 多站点
Artalk 支持多站点,管理员可以创建多个站点,并对不同站点的评论、页面进行集中管理。
## 创建管理员
执行命令根据命令行提示快速创建管理员。
```sh
./artalk admin
```
如果使用 Docker 可以执行以下命令:
```sh
docker exec -it artalk artalk admin
```
之后可使用管理员账户登录控制中心,在用户管理页面的图形界面可创建更多账户,无需手动编辑配置文件。
## 站点的创建和管理
你可以在侧边栏「[控制中心](../frontend/sidebar.md#控制中心)」创建多个站点,管理站点和快速切换站点,详情可参考:[侧边栏](/guide/frontend/sidebar.html)。
## 管理员配置
你可以设置多个管理员账户,当输入框输入匹配管理员用户名和邮箱时,将弹出密码验证提示框,
并且只有管理员才能访问「[控制中心](../frontend/sidebar.md#控制中心)」,在前端对评论内容进行管理操作。
(可选操作)通过配置文件添加管理员:
```yaml
admin_users:
- name: admin
email: admin@example.com
password: (bcrypt)$2y$10$ti4vZYIrxVN8rLcYXVgXCO.GJND0dyI49r7IoF3xqIx8bBRmIBZRm
badge_name: 管理员
badge_color: '#0083FF'
- name: admin2
email: admin2@example.com
password: (bcrypt)$2y$10$ti4vZYIrxVN8rLcYXVgXCO.GJND0dyI49r7IoF3xqIx8bBRmIBZRm
badge_name: 小管理员
badge_color: '#0083FF'
```
每项配置的解释:
- **name** & **email**:用户名和邮箱,**不区分大小写**。
- **password**:用户密码。
支持 bcrypt 和 md5 加密,例如填写:`"(md5)50c21190c6e4e5418c6a90d2b5031119"`。
**建议使用更安全的 bcrypt 加密算法**,在 Linux 环境下,你可以使用 [htpasswd 命令](https://httpd.apache.org/docs/2.4/programs/htpasswd.html) 来生成密文:
```bash
unset HISTFILE # 临时禁用 history 防止密码在历史记录中出现
htpasswd -bnBC 10 "" "your_password" | tr -d ':'
```
然后配置填写:`"(bcrypt)$2y$10$ti4vZYIrxVN8rLcY..."`,以 `(bcrypt)` 开头。
命令解释参考:[Compute bcrypt hash from command line](https://unix.stackexchange.com/questions/307994/compute-bcrypt-hash-from-command-line#answer-419855)
- **badge_name**:用户显示的头衔徽标文字。
- **badge_color**:用户显示的头衔徽标背景颜色。
### 控制管理员接收邮件通知
当页面有新的评论时,默认配置是邮件会发送给全部管理员,但你可以配置 `receive_email` 强制禁用它。
这对于设定了多个邮箱,但又不希望某些邮箱收到评论邮件的情况很有帮助。
- **receive_email**:设置为 `false` 系统将不会发送邮件通知给该用户。
注:禁止后该管理员用户仍可以收到来自他人的 @AT 回复,只是当用户对页面进行评论时 (创建根评论时) 不发送邮件通知。
```yaml
admin_users:
- name: admin
receive_email: false # ← 强制不接收邮件
```
@@ -9,13 +9,12 @@ Artalk v2.1.8+ 配置项:
# 管理员多元推送
admin_notify:
# 通知模版
notify_tpl: "default"
notify_tpl: default
noise_mode: false
# 邮件通知管理员
email:
enabled: true # 当使用其他推送方式时,可以关闭管理员邮件通知
mail_subject: "[{{site_name}}] 您的文章「{{page_title}}」有新回复"
mail_subject: '[{{site_name}}] 您的文章「{{page_title}}」有新回复'
```
请参考新文档:[多元推送](./admin_notify.md)
@@ -4,8 +4,8 @@ Artalk 支持解析相对路径,因此你可以在前端页面进行如下配
```js
Artalk.init({
site: "举个栗子站点", // 你的站点名
pageKey: "/relative-path/xx.html", // 使用相对路径
site: '举个栗子站点', // 你的站点名
pageKey: '/relative-path/xx.html', // 使用相对路径
})
```
@@ -23,7 +23,7 @@ Artalk.init({
"https://设定的举个栗子站点URL.xxx/relative-path/xx.html"
```
### 解析后的 URL 用途
## 解析后的 URL 用途
站点 URL + 页面 相对路径 将用于:
@@ -32,7 +32,7 @@ Artalk.init({
- **控制中心**页面管理打开页面
- **获取页面标题**等信息时使用
### 配置多个站点 URL 的情况
## 配置多个站点 URL 的情况
你可能需要配置站点的多个 URL 来允许 Referer 和跨域。
@@ -40,13 +40,13 @@ Artalk.init({
**当站点存在多个 URL 时**,「相对路径」会基于多个 URL 中的「**第一个**」URL。
### 使用绝对路径的情况
## 使用绝对路径的情况
区别于使用相对路径,你可以使用绝对路径,例如前端这样配置:
```js
Artalk.init({
pageKey: "https://your_domain.com/relative-path/xx.html", // 使用绝对路径
pageKey: 'https://your_domain.com/relative-path/xx.html', // 使用绝对路径
})
```
@@ -76,7 +76,7 @@ sudo systemctl restart nginx
配置前端:
```js
Artalk.init({ server: "http://artalk.your_domain.com" })
Artalk.init({ server: 'http://artalk.your_domain.com' })
```
::: tip
@@ -118,4 +118,3 @@ Artalk.init({ server: "http://artalk.your_domain.com" })
打开「反向代理」选项卡,点击「添加反向代理」,「目标 URL」填写 `http://localhost:端口号`(端口号与 Artalk 端口对应),「发送域名」填写 `$host`,如图:
![](/images/baota-proxy/2.png)
File renamed without changes.
@@ -12,6 +12,7 @@
### 博客
- [晓雨杂记](https://www.lihaoyu.cn)
- [一蓑烟雨](https://easyf12.top/)
- [二丫讲梵](https://wiki.eryajf.net)
- [Alliot’s blog](https://www.iots.vip/)
@@ -23,7 +24,7 @@
- [频率](https://pinlyu.com/)
- [子舒](https://zburu.com/)
- [叶开](https://xn--qpru0x.cn/)
- [Thun888](https://blog.thun888.xyz/)
- [Thun888](https://blog.hzchu.top/)
- [青空之蓝](https://blog.ixk.me/)
- [Monstx](https://blog.monsterx.cn/)
- [QWQAQ](https://qwqaq.com/)
@@ -15,7 +15,7 @@ docker run -d \
> 假设域名 `http://your_domain` 已正确添加 DNS 记录并指向你的服务器 IP
浏览器打开 `http://your_domain:8080` 将出现 Artalk 后台登陆界面。
浏览器打开 `http://your_domain:8080` 将出现 Artalk 后台登录界面。
执行命令创建管理员账户:
@@ -27,9 +27,11 @@ docker exec -it artalk artalk admin
> 注:将 `http://your_domain:8080` 改为你的服务器域名,或使用 [公共 CDN 资源](#cdn-资源)。
<!-- prettier-ignore-start -->
```html
<!-- CSS -->
<link href="http://your_domain:8080/dist/Artalk.css" rel="stylesheet">
<link href="http://your_domain:8080/dist/Artalk.css" rel="stylesheet" />
<!-- JS -->
<script src="http://your_domain:8080/dist/Artalk.js"></script>
@@ -37,15 +39,16 @@ docker exec -it artalk artalk admin
<!-- Artalk -->
<div id="Comments"></div>
<script>
Artalk.init({
Artalk.init({
el: '#Comments', // 绑定元素的 Selector
pageKey: '/post/1', // 固定链接 (留空自动获取)
pageTitle: '关于引入 Artalk 的这档子事', // 页面标题 (留空自动获取)
server: 'http://your_domain:8080', // 后端地址
site: 'Artalk 的博客', // 你的站点名
})
})
</script>
```
<!-- prettier-ignore-end -->
在评论框输入管理员的用户名和邮箱,控制台入口按钮将出现在评论框右下角位置。
@@ -60,9 +63,9 @@ Artalk.init({
3. 运行程序 `./artalk server`
4. 前端配置
```js
Artalk.init({ server: "http://your_domain:23366" })
```
```js
Artalk.init({ server: 'http://your_domain:23366' })
```
**进一步操作:**
@@ -76,7 +79,7 @@ Artalk.init({
**compose.yaml**
```yaml
version: "3.5"
version: '3.5'
services:
artalk:
container_name: artalk
@@ -123,41 +126,47 @@ Artalk 静态资源通过上游 CDNJS 分发,以下镜像资源可供选择:
**CDNJS**
> https://cdnjs.cloudflare.com/ajax/libs/artalk/:ArtalkVersion:/Artalk.js
> <https://cdnjs.cloudflare.com/ajax/libs/artalk/:ArtalkVersion:/Artalk.js>
>
> https://cdnjs.cloudflare.com/ajax/libs/artalk/:ArtalkVersion:/Artalk.css
> <https://cdnjs.cloudflare.com/ajax/libs/artalk/:ArtalkVersion:/Artalk.css>
**Staticfile CDN (国内)**
**SUSTech Mirrors (境内)**
> https://cdn.staticfile.org/artalk/:ArtalkVersion:/Artalk.js
> <https://mirrors.sustech.edu.cn/cdnjs/ajax/libs/artalk/:ArtalkVersion:/Artalk.js>
>
> https://cdn.staticfile.org/artalk/:ArtalkVersion:/Artalk.css
> <https://mirrors.sustech.edu.cn/cdnjs/ajax/libs/artalk/:ArtalkVersion:/Artalk.css>
::: details 查看更多
**BootCDN (国内)**
**Staticfile CDN (境内)**
> https://cdn.bootcdn.net/ajax/libs/artalk/:ArtalkVersion:/Artalk.js
> <https://cdn.staticfile.org/artalk/:ArtalkVersion:/Artalk.js>
>
> https://cdn.bootcdn.net/ajax/libs/artalk/:ArtalkVersion:/Artalk.css
> <https://cdn.staticfile.org/artalk/:ArtalkVersion:/Artalk.css>
**75CDN (国内)**
**BootCDN (境内)**
> https://lib.baomitu.com/artalk/:ArtalkVersion:/Artalk.js
> <https://cdn.bootcdn.net/ajax/libs/artalk/:ArtalkVersion:/Artalk.js>
>
> https://lib.baomitu.com/artalk/:ArtalkVersion:/Artalk.css
> <https://cdn.bootcdn.net/ajax/libs/artalk/:ArtalkVersion:/Artalk.css>
**75CDN (境内)**
> <https://lib.baomitu.com/artalk/:ArtalkVersion:/Artalk.js>
>
> <https://lib.baomitu.com/artalk/:ArtalkVersion:/Artalk.css>
**UNPKG**
> https://unpkg.com/artalk@:ArtalkVersion:/dist/Artalk.js
>
> https://unpkg.com/artalk@:ArtalkVersion:/dist/Artalk.css
> <https://unpkg.com/artalk@:ArtalkVersion:/dist/Artalk.js>
>
> <https://unpkg.com/artalk@:ArtalkVersion:/dist/Artalk.css>
**JS DELIVR**
> https://cdn.jsdelivr.net/npm/artalk@:ArtalkVersion:/dist/Artalk.js
>
> https://cdn.jsdelivr.net/npm/artalk@:ArtalkVersion:/dist/Artalk.css
> <https://cdn.jsdelivr.net/npm/artalk@:ArtalkVersion:/dist/Artalk.js>
>
> <https://cdn.jsdelivr.net/npm/artalk@:ArtalkVersion:/dist/Artalk.css>
:::
@@ -4,7 +4,6 @@
目前文档仍在陆续完善中
:::
## 控制台(管理后台)
面向管理员用户,我们提供了 “控制台” 功能,通过控制台,你能对数据内容进行统一管理。
@@ -12,6 +11,7 @@
### 如何呼出控制台
控制台被集成到评论页中,您仅需:
1. 在评论框输入管理员的名字与邮箱
2. 密码验证框自动弹出,输入正确密码
3. 控制台按钮将会在评论框右下角显示
@@ -15,6 +15,7 @@ Artalk 离不开社区的支持与帮助,**是你们让 Artalk 走得更远!
- [Fly.io 部署 Artalk 评论系统](https://wayjam.me/posts/artalk-deploy-on-flyio/)
- [Railway.app 部署 Artalk 评论系统](https://blog.moraxyc.com/post/eidb8276/)
- [Render.com 部署Artalk自托管评论系统](https://www.leenhawk.com/posts/3932123804/)
- [在 Valaxy 中使用 Artalk 作为评论系统](https://www.lihaoyu.cn/posts/use-artalk-in-valaxy)
更多新版读物正在撰写当中...
@@ -26,16 +27,14 @@ Artalk v1 版本基于 [PHP 后端](https://github.com/ArtalkJS/ArtalkPHP),部
:::
- [[!!!] 一个 Artalk 的非官方文档 (By @thun888)](https://blog.thun888.xyz/wiki/Artalk/)
- [[!!!] 一个 Artalk 的非官方文档 (By @thun888)](https://blog.hzchu.top/wiki/Artalk-doc/)
- [为 Gridsome 添加 Artalk 自托管评论系统 - Monstx's Blog](https://blog.monsterx.cn/code/use-self-hosted-comment-system-in-gridsome/)
- [Artalk 自托管评论系统的后端部署 - Jalen's Blog](https://blog.jalenchuh.cn/posts/artalk-api-php/)
- [无服务器搭建 Artalk 评论系统后端 - 陈YFの博客](https://blog.cyfan.top/p/480ab6ed.html)
- [哔哩哔哩 [站内首发] Artalk 评论系统搭建教程 - @thun888](https://www.bilibili.com/s/video/BV1954y1E7uP)
- [Hexo Next 主题添加 Artalk 评论系统 - 心底的河流](https://lhy.life/20201126-artalk-next/)
- [Hexo 添加 Artalk 评论教程 - 我相信我可以](https://butterfly.imlete.cn/article/Hexo-Artalk.html)
- [基于 Butterfly 主题添加 Artalk 评论系统 - 卓越科技的 Blog](https://blog.imzykj.cn/posts/93afb348/)
## 衍生品
- [Artalk:一款 ~~简洁~~ 有趣的自托管评论系统 (By monsterxcn)](https://github.com/monsterxcn/Artalk)
File renamed without changes.
@@ -6,8 +6,8 @@ const artalk = Artalk.init({ ... })
artalk.update({ ... })
```
- 默认配置:[defaults.ts](https://github.com/ArtalkJS/Artalk/blob/master/ui/packages/artalk/src/defaults.ts)
- 声明文件:[config.ts](https://github.com/ArtalkJS/Artalk/blob/master/ui/packages/artalk/types/config.ts)
- 默认配置:[defaults.ts](https://github.com/ArtalkJS/Artalk/blob/master/ui/artalk/src/defaults.ts)
- 声明文件:[config.ts](https://github.com/ArtalkJS/Artalk/blob/master/ui/artalk/src/types/config.ts)
## 轻松配置
@@ -61,7 +61,7 @@ artalk.update({ ... })
::: warning 更新注意
v2.2.6+ 的后续版本,请填入不带 `/api/` 路径的后端 URL。
从 v2.2.6 版本开始,`server` 无需在结尾带上 `/api/` 路径。
:::
@@ -179,7 +179,7 @@ JS DELIVR 在中国大陆的 [ICP 牌照已被吊销](https://github.com/jsdeliv
artalk.setDarkMode(true)
```
> 参考代码:“[index.html](https://github.com/ArtalkJS/Artalk/blob/master/ui/packages/artalk/index.html#L97-L150)”
> 参考代码:“[index.html](https://github.com/ArtalkJS/Artalk/blob/master/ui/artalk/index.html#L97-L150)”
可设置为 `"auto"`,Artalk 将监听 `(prefers-color-scheme: dark)` 根据用户操作系统判断自动切换夜间模式。
@@ -218,7 +218,7 @@ artalk.setDarkMode(true)
### pvEl
**页面浏览量 (PV) 绑定元素**
**页面浏览量 (PV) 绑定元素**
- 类型:`String`
- 默认值:`"#ArtalkPV"`
@@ -231,7 +231,7 @@ artalk.setDarkMode(true)
### countEl
**评论数绑定元素**
**评论数绑定元素**
- 类型:`String`
- 默认值:`"#ArtalkCount"`
@@ -304,13 +304,13 @@ Artalk.init({
const form = new FormData()
form.set('file', file)
const imgUrl = await fetch("https://api.example.org/upload", {
const imgUrl = await fetch('https://api.example.org/upload', {
method: 'POST',
body: form
body: form,
})
return imgUrl
}
},
})
```
@@ -383,7 +383,7 @@ v2.5.5 已废弃 `gravatar.default` 配置项,请使用 `gravatar.params` 替
Artalk.init({
avatarURLBuilder: (comment) => {
return `/api/avatar?email=${comment.email_encrypted}`
}
},
})
```
@@ -4,7 +4,7 @@
```yaml
frontend:
emoticons: "https://raw.githubusercontent.com/ArtalkJS/Emoticons/master/grps/default.json"
emoticons: https://raw.githubusercontent.com/ArtalkJS/Emoticons/master/grps/default.json
```
## 表情包预设
@@ -21,7 +21,7 @@ Artalk 的表情包功能借鉴了其优秀的设计,并且 Artalk 原生适
```yaml
frontend:
emoticons: "https://raw.githubusercontent.com/DIYgod/OwO/master/demo/OwO.json"
emoticons: https://raw.githubusercontent.com/DIYgod/OwO/master/demo/OwO.json
# 直接食用 OwO 格式的表情包 ↑↑
```
@@ -32,32 +32,35 @@ frontend:
Artalk 除了支持 OwO 格式外,还内置支持一种标准的表情包列表文件格式:
```js
[{
"name": "颜表情",
"type": "emoticon", // 字符类型
"items": [
{ "key": "Hi", "val": "|´・ω・)ノ" },
{ "key": "开心", "val": "ヾ(≧∇≦*)ゝ" },
//...
]
}, {
"name": "滑稽",
"type": "image", // 图片类型
"items": [
{
"key": "原味稽",
"val": "<图片 URL>"
},
//...
]
}]
;[
{
name: '颜表情',
type: 'emoticon', // 字符类型
items: [
{ key: 'Hi', val: '|´・ω・)ノ' },
{ key: '开心', val: 'ヾ(≧∇≦*)ゝ' },
//...
],
},
{
name: '滑稽',
type: 'image', // 图片类型
items: [
{
key: '原味稽',
val: '<图片 URL>',
},
//...
],
},
]
```
## 前端配置
::: warning
前端的配置将默认被后端覆盖,详情参考:[在后端控制前端](/guide/backend/fe-control.html)
前端的配置可能会被后端所覆盖,详情参考:[在后端控制前端](/guide/backend/fe-control.html)
:::
@@ -65,8 +68,9 @@ Artalk 除了支持 OwO 格式外,还内置支持一种标准的表情包列
```js
Artalk.init({
// 默认表情包列表,动态引入 ↓↓
emoticons: "https://raw.githubusercontent.com/ArtalkJS/Emoticons/master/grps/default.json",
// 默认表情包列表,动态引入 ↓↓
emoticons:
'https://raw.githubusercontent.com/ArtalkJS/Emoticons/master/grps/default.json',
})
```
@@ -76,11 +80,10 @@ Artalk.init({
```js
Artalk.init({
emoticons: false
emoticons: false,
})
```
## 加载方式
### 动态加载
@@ -89,7 +92,7 @@ Artalk.init({
```js
Artalk.init({
emoticons: "<表情包数据文件 URL>",
emoticons: '<表情包数据文件 URL>',
})
```
@@ -101,25 +104,28 @@ Artalk.init({
```js
Artalk.init({
emoticons: [{
"name": "颜表情",
"type": "emoticon", // 字符类型
"items": [
{ "key": "Hi", "val": "|´・ω・)ノ" },
{ "key": "开心", "val": "ヾ(≧∇≦*)ゝ" },
//...
]
}, {
"name": "滑稽",
"type": "image", // 图片类型
"items": [
{
"key": "原味稽",
"val": "<图片 URL>"
},
//...
]
}],
emoticons: [
{
name: '颜表情',
type: 'emoticon', // 字符类型
items: [
{ key: 'Hi', val: '|´・ω・)ノ' },
{ key: '开心', val: 'ヾ(≧∇≦*)ゝ' },
//...
],
},
{
name: '滑稽',
type: 'image', // 图片类型
items: [
{
key: '原味稽',
val: '<图片 URL>',
},
//...
],
},
],
})
```
@@ -129,20 +135,20 @@ Artalk 支持 **动态**、**静态** 混合加载,例如:
```js
Artalk.init({
emoticons: [
// 动态加载
"https://raw.githubusercontent.com/DIYgod/OwO/master/demo/OwO.json", // OwO 格式表情包
"https://raw.githubusercontent.com/qwqcode/huaji/master/huaji.json",
// 静态加载
{
"name": "表情包名字",
"type": "emoticon", // 字符类型
"items": [
{ "key": "去吧大师球", "val": "(╯°A°)╯︵○○○" },
//...
]
}
]
emoticons: [
// 动态加载
'https://raw.githubusercontent.com/DIYgod/OwO/master/demo/OwO.json', // OwO 格式表情包
'https://raw.githubusercontent.com/qwqcode/huaji/master/huaji.json',
// 静态加载
{
name: '表情包名字',
type: 'emoticon', // 字符类型
items: [
{ key: '去吧大师球', val: '(╯°A°)╯︵○○○' },
//...
],
},
],
})
```
@@ -152,9 +158,7 @@ Artalk 支持远程表情包资源中**嵌套引入**另外的表情包资源,
```js
Artalk.init({
emoticons: [
"https://example.org/表情包.json"
]
emoticons: ['https://example.org/表情包.json'],
})
```
@@ -162,10 +166,11 @@ Artalk.init({
```json
[
"https://example.org/其他表情包.json",
"https://example.org/其他表情包.json",
//...
{
// Artalk 格式、OwO 格式
//...
{ // Artalk 格式、OwO 格式
//...
}
}
]
```
+64
View File
@@ -0,0 +1,64 @@
# 多语言
在配置文件 `artalk.yml` 中设置:
```yaml
locale: zh-CN
```
locale 配置项格式遵循 Unicode BCP 47 规范,默认为 "zh-CN" (简体中文)。
---
目前 Artalk 支持语言如下:
- "zh-CN" (简体中文)
- "en-US" (English)
## 贡献翻译
欢迎提交 PR 帮助翻译 Artalk 的多语言,为社区贡献一份力量!
| 翻译内容 | 语言文件目录 | 模板文件 |
| -------- | -------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------- |
| 后端程序 | [/i18n/[LANG].yml](https://github.com/ArtalkJS/Artalk/tree/master/i18n) | [zh-CN.yml](https://github.com/ArtalkJS/Artalk/blob/master/i18n/zh-CN.yml) |
| 前端界面 | [/ui/artalk/src/i18n/[LANG].ts](https://github.com/ArtalkJS/Artalk/tree/master/ui/artalk/src/i18n) | [zh-CN.ts](https://github.com/ArtalkJS/Artalk/blob/master/ui/artalk/src/i18n/zh-CN.ts) |
| 配置文件 | [/conf/artalk.example.[LANG].yml](https://github.com/ArtalkJS/Artalk/tree/master/conf) | [artalk.example.zh-CN.yml](https://github.com/ArtalkJS/Artalk/blob/master/conf/artalk.example.zh-CN.yml) |
| 说明文档 | [/docs/[LANG]/\*_\/_.md](https://github.com/ArtalkJS/Artalk/tree/master/docs) | [/docs/\*_\/_.md](https://github.com/ArtalkJS/Artalk/tree/master/docs) |
更多参考:[开发文档](../../develop/index.md) / [CONTRIBUTING.md](https://github.com/ArtalkJS/Artalk/blob/master/CONTRIBUTING.md#translation)
## 进阶配置
### 前端临时修改语言
前端会默认使用后端的语言配置,但你也可以在前端修改配置项 `locale` 来设定语言:
```js
Artalk.init({
locale: 'en-US',
})
```
### 前端语言自动切换
可将前端 locale 配置为 `"auto"`,根据用户浏览器自动切换语言,当语言不存在时,将被设置为 "en-US"。
```js
Artalk.init({
locale: 'auto',
})
```
### 前端自定义 locale 内容
在前端可传入 Object 类型,按照 [模板文件](https://github.com/ArtalkJS/Artalk/blob/master/ui/artalk/src/i18n/zh-CN.ts) 中的 Keys 编写自定义 locale 内容。
```js
Artalk.init({
locale: {
email: 'Eメール',
//...
},
})
```
Loaded 100 of 634 files, more files were not shown because too many files have changed in this diff. Show more