Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6135c7e911 | ||
|
|
1ff0c4c10f | ||
|
|
9cc9a6d6ab | ||
|
|
d2225d565b | ||
|
|
e61911027c | ||
|
|
f29d2f81eb | ||
|
|
4b5ec39b8e | ||
|
|
5dc2752cc1 | ||
|
|
cf6e687a2d | ||
|
|
69ea7de22e | ||
|
|
8fb7027186 | ||
|
|
88615f9a88 | ||
|
|
f104629b40 | ||
|
|
2f6b30deaf | ||
|
|
2f7b9fa816 | ||
|
|
6d1041dc69 | ||
|
|
9fb191976c | ||
|
|
f20454bd00 | ||
|
|
64854107ef | ||
|
|
ac54eae179 | ||
|
|
aa92a92961 | ||
|
|
d54652264b | ||
|
|
d6ececd014 | ||
|
|
04ef002da1 | ||
|
|
a6b559d682 | ||
|
|
67b37b4612 | ||
|
|
3e81b2a8f2 | ||
|
|
8a9480d05a | ||
|
|
b3ed639be7 | ||
|
|
6a0e06ea75 | ||
|
|
92484cfa66 | ||
|
|
1b0eff9568 | ||
|
|
2efd34248d | ||
|
|
c0a3026890 | ||
|
|
392b6b15cf | ||
|
|
6b58fd8a9d | ||
|
|
80e5ca5dc7 | ||
|
|
50e967f71c | ||
|
|
cf58a545b5 | ||
|
|
270558129f | ||
|
|
059bac8b5f | ||
|
|
f1a86d59ca | ||
|
|
adcb75a2e2 | ||
|
|
4d7e157ff0 | ||
|
|
528847de7b | ||
|
|
2b9d6bb573 | ||
|
|
393224cdb1 | ||
|
|
a925806d29 | ||
|
|
b97167a718 | ||
|
|
587523f0df | ||
|
|
08f58cd38b | ||
|
|
0803e235a4 | ||
|
|
125a66611f | ||
|
|
92a0e23c85 | ||
|
|
c75b630e8a | ||
|
|
d22d34c223 | ||
|
|
6fe8ffd2c4 | ||
|
|
f4d33fcf24 | ||
|
|
640f9904fb | ||
|
|
df62de09f3 | ||
|
|
68bcdbe3e8 | ||
|
|
e663893fd1 | ||
|
|
b85d845b71 | ||
|
|
acf7480b91 | ||
|
|
be0dcd6b59 | ||
|
|
4d9445c84c | ||
|
|
1337e81cd4 | ||
|
|
d053b953a6 | ||
|
|
2549052558 | ||
|
|
b8da04e308 | ||
|
|
c4a7162302 | ||
|
|
6012993fe9 | ||
|
|
d4ed7f64b2 | ||
|
|
93e3b2f184 | ||
|
|
0e75457499 | ||
|
|
b8151bb789 | ||
|
|
67922f34ad | ||
|
|
7093e7e1c5 | ||
|
|
c3558b7beb | ||
|
|
5fdf3a27ce | ||
|
|
f8f509c0de | ||
|
|
437d943691 | ||
|
|
401cf5c21a | ||
|
|
77e9a687ac | ||
|
|
85f88cbba5 | ||
|
|
efb34c23e5 | ||
|
|
822a85c9e3 | ||
|
|
630a3b1ff8 | ||
|
|
ca6f8ed09c | ||
|
|
a0b0a33862 | ||
|
|
4868cd9992 | ||
|
|
2dfee533da | ||
|
|
dcaaefc71b | ||
|
|
499a57213e | ||
|
|
b7fc86b3c6 | ||
|
|
161ff8bfc3 | ||
|
|
1e36d45ec3 | ||
|
|
d2161cc0fb | ||
|
|
abbddfe9b4 | ||
|
|
860dd698e7 | ||
|
|
acb087887c | ||
|
|
dbb3c55148 | ||
|
|
fdfeef8042 | ||
|
|
824f122dcb | ||
|
|
53d46d82b6 | ||
|
|
bb218d0ba4 | ||
|
|
984071d4b6 | ||
|
|
34b24a1f36 | ||
|
|
58657524cf | ||
|
|
b5db161697 | ||
|
|
4dd0ae40e2 | ||
|
|
5dea08a3f2 | ||
|
|
92464085e6 | ||
|
|
28f1fa11bd | ||
|
|
3de1f11f47 | ||
|
|
dff1813fa5 | ||
|
|
f4475830da | ||
|
|
9c85a85153 | ||
|
|
5a63d4c63d | ||
|
|
b8afcbb21a | ||
|
|
0c0a207068 | ||
|
|
be939816aa | ||
|
|
45d1bc1241 | ||
|
|
ef5899e079 | ||
|
|
7187d0f058 | ||
|
|
88aec7e767 | ||
|
|
a09628c4e8 | ||
|
|
23d0d868de | ||
|
|
f3e356e450 | ||
|
|
170db0fc2a | ||
|
|
c3f730b0e7 | ||
|
|
e132c31150 | ||
|
|
fa6648ecf5 | ||
|
|
a9331b426e | ||
|
|
fbd1cd984d | ||
|
|
accd10cef4 | ||
|
|
690eb47eaa | ||
|
|
fc0dcee06c | ||
|
|
895bfbd5e2 | ||
|
|
e254350211 | ||
|
|
f226d476e5 | ||
|
|
ee131fe6ef | ||
|
|
43e4c901b8 | ||
|
|
bd5da20dd6 | ||
|
|
116d8f1919 | ||
|
|
99b71a15f8 | ||
|
|
3255cb4b66 | ||
|
|
35d5f778b2 | ||
|
|
9375ef812a | ||
|
|
44742c149e | ||
|
|
a4d5135379 | ||
|
|
ddfaa603ca | ||
|
|
6e13152fc1 | ||
|
|
0b16c9627a | ||
|
|
b613a4368c | ||
|
|
3098a75a05 | ||
|
|
d71ac6d156 | ||
|
|
6c9a7e3884 | ||
|
|
65b440416d | ||
|
|
f9084cbfb4 | ||
|
|
3c7ad1d0ef | ||
|
|
1930d842f2 | ||
|
|
751e4a866f | ||
|
|
01364d1ddc | ||
|
|
ec6d2b2e60 | ||
|
|
915b5f48b4 | ||
|
|
16527ec4f3 | ||
|
|
a7af2b7aaa | ||
|
|
3ff891be90 | ||
|
|
7d6faf6431 | ||
|
|
73d8ea97ed | ||
|
|
c482e19f19 | ||
|
|
8c3042cdb1 | ||
|
|
ed9a78472d | ||
|
|
ae5543df52 | ||
|
|
c2c5a80d8d | ||
|
|
de5e1b4000 | ||
|
|
b60cb585b6 | ||
|
|
44bca8d2f4 | ||
|
|
9103a923a6 | ||
|
|
e4242512f8 | ||
|
|
0ebd16a5db | ||
|
|
0eb75f612a | ||
|
|
18e6ae5b17 | ||
|
|
1ee3c41199 | ||
|
|
8af713636c | ||
|
|
5bf6e5f1dc | ||
|
|
929faf0722 | ||
|
|
5322f90383 | ||
|
|
fa3575cbae | ||
|
|
c94a34ffd7 | ||
|
|
50b49448b6 | ||
|
|
8ff3f5e875 | ||
|
|
640fa7ded4 | ||
|
|
18123f7002 | ||
|
|
cf2094667d | ||
|
|
2cd2165f06 | ||
|
|
4eada4b628 | ||
|
|
05f3ad043a | ||
|
|
6e9083e75d | ||
|
|
7bbdb5900f | ||
|
|
5be45315dc | ||
|
|
5d20ff1ef5 | ||
|
|
86e0eeafd1 | ||
|
|
49c1a87a67 | ||
|
|
ec7f81cb83 | ||
|
|
4b115d7b6a | ||
|
|
1bae6d8d2a | ||
|
|
bdafa19470 | ||
|
|
342236b6a7 | ||
|
|
ffce9f9e85 | ||
|
|
0097e041b1 | ||
|
|
42da621dfc | ||
|
|
2f5dbaa022 | ||
|
|
e181a6d5dd | ||
|
|
7873b21fb7 | ||
|
|
2a219518a4 | ||
|
|
afa7888db0 | ||
|
|
f6a589d5b2 | ||
|
|
41a09d5996 | ||
|
|
191977c0df | ||
|
|
5a4c06daee | ||
|
|
c4942ab807 | ||
|
|
6b83a9f632 | ||
|
|
3c88c0c29c | ||
|
|
35aab6bedc | ||
|
|
17033dc111 | ||
|
|
559df60f0d | ||
|
|
22d4ec1c31 | ||
|
|
d97ad5c843 | ||
|
|
34a67f647b | ||
|
|
9c3228b8fc | ||
|
|
4012d3e090 | ||
|
|
bc1c4d315c | ||
|
|
2a6f0c56a4 | ||
|
|
46e2a15116 | ||
|
|
c068f5a240 | ||
|
|
29bf49958f | ||
|
|
2fcad539ca | ||
|
|
45b79124c9 | ||
|
|
2b44452234 | ||
|
|
0e0b53fe9e | ||
|
|
dba5ba5277 | ||
|
|
942aaf654f | ||
|
|
37e0091502 | ||
|
|
a7c3f1bbda | ||
|
|
a40a070bdb | ||
|
|
082bfc63d1 | ||
|
|
0de8009e65 | ||
|
|
a5e4c81e72 | ||
|
|
c52c26145c | ||
|
|
f5e310a182 | ||
|
|
0828b91602 | ||
|
|
c4f664e412 | ||
|
|
a084c50095 | ||
|
|
9dacd0954d | ||
|
|
50b0a6068c | ||
|
|
4689492bf5 | ||
|
|
6ee9ee9ea4 | ||
|
|
8e3a743ed8 | ||
|
|
9550a16a0c | ||
|
|
a9edac3ce0 | ||
|
|
589850d311 | ||
|
|
9ba9439831 | ||
|
|
38f6b6996a | ||
|
|
1e16570b2f | ||
|
|
889adc6bae | ||
|
|
0de59911b3 | ||
|
|
f22e557b1c | ||
|
|
92ff757efc | ||
|
|
63165599ce | ||
|
|
a5b428d1ec | ||
|
|
cf3f9b1ac3 | ||
|
|
c212d67f49 | ||
|
|
b00a257699 | ||
|
|
3698c0c593 | ||
|
|
32a398609c | ||
|
|
54729fbafc | ||
|
|
b74e5cf94c | ||
|
|
475dd933fe | ||
|
|
60e0e7e61a | ||
|
|
e4a42d3a90 | ||
|
|
d86cd73ea6 | ||
|
|
67280f2ca2 | ||
|
|
a8bcd41f36 | ||
|
|
04cf137a74 | ||
|
|
d542e98581 | ||
|
|
dfaf95bf1d | ||
|
|
0a89426c93 | ||
|
|
7a026ef0e2 | ||
|
|
855f6c261f | ||
|
|
7099598a92 | ||
|
|
ad8851ea94 | ||
|
|
def9dc2707 | ||
|
|
91228a9446 | ||
|
|
7a0a9dbd92 | ||
|
|
441c4fa6a9 | ||
|
|
a16169f69d | ||
|
|
da42676656 | ||
|
|
f3a42e892f | ||
|
|
6a53597485 | ||
|
|
60336e567d | ||
|
|
8918c62ffd | ||
|
|
362fc19cd8 | ||
|
|
1b938752ff | ||
|
|
835a886dc8 | ||
|
|
f390b57fe7 | ||
|
|
6d21a0f204 | ||
|
|
a1d0c37828 | ||
|
|
763fbc417e | ||
|
|
776d5e66fe | ||
|
|
10c0975ce0 | ||
|
|
7286642fc9 | ||
|
|
8db4fb3524 | ||
|
|
08be04979d | ||
|
|
d7ea9ba43f | ||
|
|
bad248534c | ||
|
|
f56ac4eabc | ||
|
|
bbe2e8416c | ||
|
|
d44e79b1f4 | ||
|
|
e816dd686c | ||
|
|
c9ea8f6162 | ||
|
|
87102cd3b0 | ||
|
|
8b6bab828d | ||
|
|
9fb658599a | ||
|
|
f8c33003a8 | ||
|
|
b97136b83f | ||
|
|
df3e983e7f | ||
|
|
1b878fb3cc | ||
|
|
aa87ab94f5 | ||
|
|
4e9afd9761 | ||
|
|
2b7d0ecb72 | ||
|
|
603c7d9439 | ||
|
|
fb93231b35 | ||
|
|
fed83263e2 | ||
|
|
9dc2d83486 | ||
|
|
d918caaf81 | ||
|
|
d44212bd90 | ||
|
|
37d4ca76fa | ||
|
|
8cc39f322c | ||
|
|
2b4e80651a | ||
|
|
415fa0f2e3 | ||
|
|
91809002d7 | ||
|
|
dcaad1b2d5 | ||
|
|
5e635bba68 | ||
|
|
d136d086eb | ||
|
|
9fe765f874 | ||
|
|
72317ead34 | ||
|
|
75c7914fb1 | ||
|
|
863b4deec0 | ||
|
|
6e6fd8d587 | ||
|
|
1608911328 | ||
|
|
87a62961b6 | ||
|
|
e6a9748e70 | ||
|
|
0f35532f0b | ||
|
|
d21e47f881 | ||
|
|
8d11a239fa | ||
|
|
8867eb296c | ||
|
|
a53ddc9f76 | ||
|
|
5ee9e76dcf | ||
|
|
3d5f77ab35 | ||
|
|
25a4f48e5e | ||
|
|
2dc3bc8934 | ||
|
|
7b1bb25d6a | ||
|
|
9bed5be236 | ||
|
|
ec0ef12b0e | ||
|
|
5d2950f842 | ||
|
|
25c2f30165 | ||
|
|
d8b49773b3 | ||
|
|
2c8107a4b7 | ||
|
|
9f8aba068e | ||
|
|
e40235b1c7 | ||
|
|
e050544d21 | ||
|
|
da692649bc | ||
|
|
a0892fc4c0 | ||
|
|
c1e365fdfd | ||
|
|
e6e6d2aa54 | ||
|
|
ac70cd4c9d | ||
|
|
600030b528 |
No files matched your search
@@ -1,7 +1,8 @@
|
||||
version: 2.1
|
||||
|
||||
orbs:
|
||||
node: circleci/node@5.0.3
|
||||
node: circleci/node@5.2.0
|
||||
codecov: codecov/codecov@3.3.0
|
||||
|
||||
executors:
|
||||
base:
|
||||
@@ -9,18 +10,15 @@ executors:
|
||||
- image: cimg/base:stable
|
||||
node:
|
||||
docker:
|
||||
- image: 'cimg/node:18.17.1'
|
||||
- image: "cimg/node:20.17.0"
|
||||
go:
|
||||
docker:
|
||||
- image: cimg/go:1.21.0
|
||||
- image: cimg/go:1.22.6
|
||||
|
||||
parameters:
|
||||
trigger-app:
|
||||
type: boolean
|
||||
default: false
|
||||
trigger-ui:
|
||||
type: boolean
|
||||
default: false
|
||||
run-them-all:
|
||||
type: boolean
|
||||
default: false
|
||||
@@ -28,59 +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.0-{{ checksum "go.sum" }}
|
||||
- run:
|
||||
name: Install Dependencies
|
||||
command: go mod download
|
||||
- save_cache:
|
||||
key: go-mod-1.21.0-{{ 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
|
||||
- store_test_results:
|
||||
path: /tmp/test-reports
|
||||
|
||||
## Frontend
|
||||
test_ui:
|
||||
executor: node
|
||||
steps:
|
||||
- node/install
|
||||
- checkout
|
||||
- run:
|
||||
name: Print the node version
|
||||
command: node -v
|
||||
- run:
|
||||
name: Install pnpm
|
||||
command: npm i -g pnpm@8.7.0
|
||||
- run:
|
||||
name: Install Dependencies
|
||||
command: pnpm --dir ./ui install --frozen-lockfile
|
||||
- run:
|
||||
name: Build Artalk
|
||||
command: pnpm --dir ./ui build:all
|
||||
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.6-{{ checksum "go.sum" }}
|
||||
- run:
|
||||
name: Install Dependencies
|
||||
command: go mod download
|
||||
- save_cache:
|
||||
key: go-mod-1.22.6-{{ 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:
|
||||
@@ -91,14 +73,6 @@ workflows:
|
||||
jobs:
|
||||
- test_app
|
||||
|
||||
build-ui:
|
||||
when:
|
||||
or:
|
||||
- << pipeline.parameters.trigger-ui >>
|
||||
- << pipeline.parameters.run-them-all >>
|
||||
jobs:
|
||||
- test_ui
|
||||
|
||||
build-shared-other:
|
||||
when: << pipeline.parameters.run-them-all >>
|
||||
jobs:
|
||||
|
||||
@@ -17,10 +17,11 @@ workflows:
|
||||
mapping: |
|
||||
(cmd|internal|server|pkg|test|conf)/.* trigger-app true
|
||||
main.go|go.mod|go.sum trigger-app true
|
||||
(ui)/.* trigger-ui 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
|
||||
@@ -0,0 +1 @@
|
||||
node_modules
|
||||
+3
-2
@@ -2,7 +2,8 @@
|
||||
|
||||
github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
|
||||
patreon: # Replace with a single Patreon username
|
||||
open_collective: artalk # Replace with a single Open Collective username
|
||||
open_collective: # Replace with a single Open Collective username
|
||||
buy_me_a_coffee: artalk
|
||||
ko_fi: # Replace with a single Ko-fi username
|
||||
tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
|
||||
community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
|
||||
@@ -11,4 +12,4 @@ issuehunt: # Replace with a single IssueHunt username
|
||||
otechie: # Replace with a single Otechie username
|
||||
lfx_crowdfunding: # Replace with a single LFX Crowdfunding project-name e.g., cloud-foundry
|
||||
custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2']
|
||||
- https://afdian.net/a/artalk
|
||||
- https://afdian.com/a/artalk
|
||||
@@ -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
|
||||
})
|
||||
@@ -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:
|
||||
|
||||
@@ -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
|
||||
@@ -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.0'
|
||||
PKG_NAME: 'github.com/ArtalkJS/Artalk'
|
||||
GO_VERSION: 1.22.6
|
||||
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' || '' }}
|
||||
@@ -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@v6
|
||||
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 }}
|
||||
@@ -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 }})).
|
||||
@@ -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 }}
|
||||
@@ -0,0 +1,361 @@
|
||||
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@v4
|
||||
with:
|
||||
version: 9.9.0
|
||||
|
||||
- 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
|
||||
# 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@v6
|
||||
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
|
||||
@@ -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 }}
|
||||
@@ -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@v4
|
||||
with:
|
||||
version: 9.9.0
|
||||
|
||||
- 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 }}
|
||||
@@ -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"]
|
||||
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
|
||||
@@ -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}}"
|
||||
@@ -2,61 +2,41 @@ 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@v4
|
||||
with:
|
||||
version: 9.9.0
|
||||
|
||||
- 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
|
||||
@@ -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 }}
|
||||
@@ -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 }}
|
||||
@@ -0,0 +1,38 @@
|
||||
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@v4
|
||||
with:
|
||||
version: 9.9.0
|
||||
|
||||
- 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
|
||||
|
||||
- name: Lint Docs
|
||||
run: pnpm eslint docs && pnpm prettier --check docs
|
||||
@@ -0,0 +1,56 @@
|
||||
name: Test Frontend
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: ["*", "!release/*", "!nightly"]
|
||||
paths: ["ui/**"]
|
||||
tags-ignore: ["v*"]
|
||||
pull_request:
|
||||
paths: ["ui/**"]
|
||||
branches: ["*", "!release/*", "!nightly"]
|
||||
|
||||
jobs:
|
||||
test_ui:
|
||||
strategy:
|
||||
matrix:
|
||||
node: [18, 20]
|
||||
os: [ubuntu-latest, windows-latest]
|
||||
|
||||
runs-on: ${{ matrix.os }}
|
||||
|
||||
steps:
|
||||
- if: matrix.os == 'windows-latest'
|
||||
name: Set git to use LF (for Windows environment)
|
||||
run: |
|
||||
git config --global core.autocrlf false
|
||||
git config --global core.eol lf
|
||||
|
||||
- name: Checkout Code
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- uses: pnpm/action-setup@v4
|
||||
with:
|
||||
version: 9.9.0
|
||||
|
||||
- name: Use Node.js ${{ matrix.node }}
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: ${{ matrix.node }}
|
||||
cache: pnpm
|
||||
|
||||
- name: Install Dependencies
|
||||
run: pnpm install --frozen-lockfile
|
||||
|
||||
- name: Package Build Test
|
||||
run: pnpm build:all
|
||||
|
||||
- name: Unit test
|
||||
run: pnpm test
|
||||
|
||||
- name: Lint
|
||||
run: pnpm eslint ui && pnpm prettier --check ui
|
||||
|
||||
# https://github.com/arethetypeswrong/arethetypeswrong.github.io
|
||||
- name: "arethetypeswrong test"
|
||||
if: runner.os == 'ubuntu-latest'
|
||||
run: pnpm -F artalk test:attw || true
|
||||
@@ -65,3 +65,6 @@ node_modules
|
||||
# always compile latest version
|
||||
/public/sidebar
|
||||
/public/dist
|
||||
|
||||
playwright-report
|
||||
test-results
|
||||
+8
-6
@@ -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}}"
|
||||
@@ -175,3 +175,5 @@ release:
|
||||
name: Artalk
|
||||
prerelease: auto
|
||||
draft: false
|
||||
extra_files:
|
||||
- glob: ./local/release_includes/*
|
||||
File renamed without changes.
@@ -0,0 +1,18 @@
|
||||
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
|
||||
**/dist/**
|
||||
+26
@@ -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
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
Vendored
+17
-13
@@ -1,14 +1,18 @@
|
||||
{
|
||||
"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}/local/local.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",
|
||||
"env": {
|
||||
"ATK_SITE_DEFAULT": "ArtalkDocs",
|
||||
"ATK_TRUSTED_DOMAINS": "http://localhost:5173 http://localhost:23367"
|
||||
},
|
||||
"args": ["server", "-c", "${workspaceFolder}/artalk.yml"]
|
||||
}
|
||||
]
|
||||
}
|
||||
Vendored
+62
-18
@@ -1,19 +1,63 @@
|
||||
{
|
||||
"cSpell.words": [
|
||||
"akismet",
|
||||
"artalk",
|
||||
"artran",
|
||||
"artrans",
|
||||
"artransfer",
|
||||
"gomail",
|
||||
"Goreleaser",
|
||||
"gorm",
|
||||
"ldflags",
|
||||
"lfshook",
|
||||
"Metas",
|
||||
"pgsql",
|
||||
"sendmail",
|
||||
"sqlite",
|
||||
"pkged"
|
||||
]
|
||||
}
|
||||
// Enable the ESlint flat config support
|
||||
"eslint.experimental.useFlatConfig": true,
|
||||
|
||||
// Disable the default formatter, use eslint instead
|
||||
// "prettier.enable": false,
|
||||
"editor.formatOnSave": false,
|
||||
|
||||
// Auto fix
|
||||
"editor.codeActionsOnSave": {
|
||||
"source.fixAll.eslint": "explicit",
|
||||
"source.organizeImports": "never"
|
||||
},
|
||||
|
||||
"eslint.runtime": "node",
|
||||
|
||||
// Silent the stylistic rules in you IDE, but still auto fix them
|
||||
"eslint.rules.customizations": [
|
||||
{ "rule": "style/*", "severity": "off" },
|
||||
{ "rule": "*-indent", "severity": "off" },
|
||||
{ "rule": "*-spacing", "severity": "off" },
|
||||
{ "rule": "*-spaces", "severity": "off" },
|
||||
{ "rule": "*-order", "severity": "off" },
|
||||
{ "rule": "*-dangle", "severity": "off" },
|
||||
{ "rule": "*-newline", "severity": "off" },
|
||||
{ "rule": "*quotes", "severity": "off" },
|
||||
{ "rule": "*semi", "severity": "off" }
|
||||
],
|
||||
|
||||
// Enable eslint for all supported languages
|
||||
"eslint.validate": [
|
||||
"javascript",
|
||||
"javascriptreact",
|
||||
"typescript",
|
||||
"typescriptreact",
|
||||
"vue",
|
||||
"html",
|
||||
"markdown",
|
||||
"json",
|
||||
"jsonc",
|
||||
"yaml",
|
||||
"toml",
|
||||
"xml"
|
||||
],
|
||||
|
||||
"cSpell.words": [
|
||||
"akismet",
|
||||
"artalk",
|
||||
"artran",
|
||||
"artrans",
|
||||
"artransfer",
|
||||
"gomail",
|
||||
"Goreleaser",
|
||||
"gorm",
|
||||
"ldflags",
|
||||
"lfshook",
|
||||
"Metas",
|
||||
"pgsql",
|
||||
"sendmail",
|
||||
"sqlite",
|
||||
"pkged"
|
||||
]
|
||||
}
|
||||
Vendored
+12
-12
@@ -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
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
+495
@@ -1,4 +1,499 @@
|
||||
|
||||
## [v2.9.0](https://github.com/ArtalkJS/Artalk/compare/v2.8.7...v2.9.0) (2024-09-03)
|
||||
|
||||
### Features
|
||||
|
||||
* **auth:** add user profile and password changing ([#966](https://github.com/ArtalkJS/Artalk/issues/966))
|
||||
* **config:** add `site_url` config option ([#967](https://github.com/ArtalkJS/Artalk/issues/967))
|
||||
* **go:** upgrade golang to v1.22.6 and some deps
|
||||
* **ui/dashboard:** new dashboard ui refresh for desktop devices ([#957](https://github.com/ArtalkJS/Artalk/issues/957))
|
||||
* **ui/date:** add `dateFormatter` config option ([#940](https://github.com/ArtalkJS/Artalk/issues/940))
|
||||
* **ui/plugin:** make ui plugin configurable
|
||||
* **ui/sidebar:** add dark mode toggle for dashboard ([#790](https://github.com/ArtalkJS/Artalk/issues/790))
|
||||
* **ui/sidebar:** add page search by keywords in sidebar ([#603](https://github.com/ArtalkJS/Artalk/issues/603))
|
||||
* **ui/sidebar:** add user search by keywords in sidebar ([#710](https://github.com/ArtalkJS/Artalk/issues/710))
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **anti_spam:** handle empty `referer` variable in anti-spam check ([#853](https://github.com/ArtalkJS/Artalk/issues/853))
|
||||
* **api/auth:** fix missing Microsoft oauth provider configuration ([#929](https://github.com/ArtalkJS/Artalk/issues/929))
|
||||
* **api/auth:** migrate auth_identities when account merging ([#920](https://github.com/ArtalkJS/Artalk/issues/920))
|
||||
* **api/auth:** register issue due to unremoved auth records after user deletion ([#919](https://github.com/ArtalkJS/Artalk/issues/919))
|
||||
* **api/comment_add:** improve the security of comment add api ([#964](https://github.com/ArtalkJS/Artalk/issues/964))
|
||||
* **auth:** correct email verification code send button
|
||||
* **plugin/lightbox:** fix import for non-browser env ([#931](https://github.com/ArtalkJS/Artalk/issues/931))
|
||||
* **plugin_kit:** fix typescript lib path retrieval on win
|
||||
* **plugin_kit:** import source path case error on linux
|
||||
* **sidebar:** correct total item count for pagination in sidebar
|
||||
* **ui/dark_mode:** apply dark mode config option before mounting ui ([#890](https://github.com/ArtalkJS/Artalk/issues/890))
|
||||
* **ui/plugin-kit:** fix typescript lib folder for api-extractor in monorepo
|
||||
* **ui/sidebar:** disable admin password check dialog in sidebar
|
||||
* **ui/sidebar:** show env variables in sidebar settings ui ([#946](https://github.com/ArtalkJS/Artalk/issues/946)) ([#956](https://github.com/ArtalkJS/Artalk/issues/956))
|
||||
* **ui/stat:** fix invalid backward compatible strategy ([#880](https://github.com/ArtalkJS/Artalk/issues/880))
|
||||
* **validator:** restrict to allow only HTTP protocol
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
* **api/auth:** add more specific error messages for login failures
|
||||
* **app/init:** generate translated config file by env variable `ATK_LOCALE`
|
||||
* **auth:** add loading skeleton for login methods list
|
||||
* **auth:** enhance visibility of skip button ([#863](https://github.com/ArtalkJS/Artalk/issues/863))
|
||||
* **auth:** perform optical adjustment for consistent icon sizing
|
||||
* **auth:** correct verify button position in register form
|
||||
* **i18n:** auto-load frontend i18n locale js sources
|
||||
* **notify:** improve error messages for notify ([#943](https://github.com/ArtalkJS/Artalk/issues/943))
|
||||
* **plugin_kit:** improve typescript diagnostics output
|
||||
* **style/sidebar:** modify font-family for sidebar
|
||||
* **ui/sidebar:** enhance i18n translations for sidebar
|
||||
* **ui/sidebar:** mask sensitive input values in sidebar settings ([#494](https://github.com/ArtalkJS/Artalk/issues/494))
|
||||
* **ui/sidebar:** optimize setup process and i18n lazy load ([#962](https://github.com/ArtalkJS/Artalk/issues/962))
|
||||
|
||||
### Code Refactoring
|
||||
|
||||
* **plugin_katex:** use tokenizer extension of marked ([#955](https://github.com/ArtalkJS/Artalk/issues/955))
|
||||
* **ui/deps:** remove `abortcontroller-polyfill` ([#923](https://github.com/ArtalkJS/Artalk/issues/923))
|
||||
* **ui/marked:** replace pkg-level marked with new class instance ([#954](https://github.com/ArtalkJS/Artalk/issues/954))
|
||||
* **ui/types:** add `Layer` interface
|
||||
* **ui/user:** rename `nick` to `name` in `LocalUser` data structure ([#961](https://github.com/ArtalkJS/Artalk/issues/961))
|
||||
|
||||
### Documentation
|
||||
|
||||
* **auth:** set `auth.anonymous` to false as default
|
||||
* **ui/i18n:** add more locale support for sidebar
|
||||
* **ui/i18n:** add translations for French, Korean, and Russian
|
||||
|
||||
|
||||
## [v2.8.7](https://github.com/ArtalkJS/Artalk/compare/v2.8.6...v2.8.7) (2024-06-09)
|
||||
|
||||
### Features
|
||||
|
||||
* **go:** upgrade golang to v1.22.3 and some deps
|
||||
* **plugin_kit:** add vite plugin for developing artalk plugins ([#904](https://github.com/ArtalkJS/Artalk/issues/904))
|
||||
* **sync:** add keyed rw-mutex
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **api/auth:** include render mustache params for verification email subject ([#910](https://github.com/ArtalkJS/Artalk/issues/910))
|
||||
* **api/stats:** fix `site_pv` response body and add unit tests ([#896](https://github.com/ArtalkJS/Artalk/issues/896))
|
||||
* **api/transfer_upload:** close temp file in transfer upload endpoint ([#877](https://github.com/ArtalkJS/Artalk/issues/877))
|
||||
* **auth:** failed to register by social account on mysql database ([#902](https://github.com/ArtalkJS/Artalk/issues/902))
|
||||
* **conf_env:** enhance environment variable loading for config ([#892](https://github.com/ArtalkJS/Artalk/issues/892))
|
||||
* **plugin_katex:** fix event issue causing katex integration failure ([#897](https://github.com/ArtalkJS/Artalk/issues/897))
|
||||
* **ui/height_limit:** height limit issue for collapsed comments ([#865](https://github.com/ArtalkJS/Artalk/issues/865))
|
||||
* **ui/sidebar:** unable to logout if user is not admin in control center
|
||||
* **ui/types:** remove marked dependency in dts ([#868](https://github.com/ArtalkJS/Artalk/issues/868))
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
* **conf:** add cache for config metadata to boost startup speed ([#892](https://github.com/ArtalkJS/Artalk/issues/892))
|
||||
* **dao:** add singleflight for no-cache db find func
|
||||
* **gravatar:** support both sha256 and md5 hash for gravatar ([#912](https://github.com/ArtalkJS/Artalk/issues/912))
|
||||
* **gravatar:** convert email to lowercase before hashing for gravatar
|
||||
* **gravatar:** use sha256 hashing algorithm for gravatar ([#874](https://github.com/ArtalkJS/Artalk/issues/874))
|
||||
* **ui/conf:** exclude conf `pvEl`, `countEl` and `statPageKeyAttr` from remove server ([#905](https://github.com/ArtalkJS/Artalk/issues/905))
|
||||
* **ui/dev:** bump eslint to v9 ([#915](https://github.com/ArtalkJS/Artalk/issues/915))
|
||||
|
||||
### Code Refactoring
|
||||
|
||||
* **dao:** add `date` field to the page json entity
|
||||
* **dao:** improve `QueryDBWithCache` func and concurrent unit tests ([#884](https://github.com/ArtalkJS/Artalk/issues/884))
|
||||
* **transfer:** improve the reliability of the transfer ([#883](https://github.com/ArtalkJS/Artalk/issues/883))
|
||||
* **transfer:** strip domain from page key by default ([#873](https://github.com/ArtalkJS/Artalk/issues/873))
|
||||
* **ui:** fix linter issues for ui and docs ([#917](https://github.com/ArtalkJS/Artalk/issues/917))
|
||||
* **ui/stat:** use class selector for pageview elements by default ([#880](https://github.com/ArtalkJS/Artalk/issues/880))
|
||||
|
||||
### Documentation
|
||||
|
||||
* refine documentation
|
||||
* **dev:** refine contributing.md and translate to chinese
|
||||
* **i18n:** revise French translation ([#913](https://github.com/ArtalkJS/Artalk/issues/913))
|
||||
* **ip_region:** add instructions for obtaining accurate IP under proxy
|
||||
|
||||
|
||||
## [v2.8.6](https://github.com/ArtalkJS/Artalk/compare/v2.8.5...v2.8.6) (2024-05-09)
|
||||
|
||||
### Features
|
||||
|
||||
* **auth:** user accounts merge tool ([#854](https://github.com/ArtalkJS/Artalk/issues/854))
|
||||
* **auth:** social login api endpoints ([#854](https://github.com/ArtalkJS/Artalk/issues/854))
|
||||
* **ci:** include frontend dist files in release ([#860](https://github.com/ArtalkJS/Artalk/issues/860))
|
||||
* **i18n:** add incremental updates feature for i18n code scan tool
|
||||
* **multi_push/lark:** add card mode for lark push ([#839](https://github.com/ArtalkJS/Artalk/issues/839))
|
||||
* **sync:** add keyed mutex
|
||||
* **ui/auth:** plugin-auth for integrating social login ([#854](https://github.com/ArtalkJS/Artalk/issues/854))
|
||||
* **ui/img_lazyload:** add support for lazy loading images ([#850](https://github.com/ArtalkJS/Artalk/issues/850))
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **api/pv:** add mutex for page pv record endpoint
|
||||
* **cache/user:** user id cache from email lookup not cleared
|
||||
* **comments_get:** include `site_name` for isolation in associated query for comment's page
|
||||
* **dao:** ensure find and create functions thread safe ([#845](https://github.com/ArtalkJS/Artalk/issues/845))
|
||||
* **db/migrate:** fix root_id migrate for database lacking recursive CTE support ([#848](https://github.com/ArtalkJS/Artalk/issues/848)) ([#846](https://github.com/ArtalkJS/Artalk/issues/846))
|
||||
* **db_migrate:** drop `fk_comments_user` foreign key constraint of the users table
|
||||
* **sidebar/site:** unable to edit the new site urls
|
||||
* **ui/dark_mode:** add support for configuring dark mode in backend ([#790](https://github.com/ArtalkJS/Artalk/issues/790))
|
||||
* **ui/dark_mode:** unable to toggle dark mode for sidebar in auto mode
|
||||
* **ui/height_limit:** height limit not working while loading images ([#849](https://github.com/ArtalkJS/Artalk/issues/849))
|
||||
* **ui/marked:** optimize same origin link judgment logic
|
||||
|
||||
### Documentation
|
||||
|
||||
* update introduction document
|
||||
* **auth:** add social login feature ([#854](https://github.com/ArtalkJS/Artalk/issues/854))
|
||||
* **i18n:** add translation for Korean and Russian
|
||||
|
||||
|
||||
## [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
|
||||
|
||||
* **build:** generate source maps to ease debugging
|
||||
* **cout-widget:** `loadCountWidget` issue
|
||||
* **ui:** static method export issue in JS module ([#669](https://github.com/ArtalkJS/Artalk/issues/669))
|
||||
|
||||
### Documentation
|
||||
|
||||
* **i18n:** add translation of update notice
|
||||
|
||||
|
||||
## [v2.7.0](https://github.com/ArtalkJS/Artalk/compare/v2.6.4...v2.7.0) (2023-12-17)
|
||||
|
||||
### Features
|
||||
|
||||
* **ui:** support `scrollRelativeTo` config option
|
||||
* **ui/test:** add end-to-end (e2e) testing using Playwright
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **api/img-upload:** `public_path` config enables the use of full url ([#659](https://github.com/ArtalkJS/Artalk/issues/659)) ([#664](https://github.com/ArtalkJS/Artalk/issues/664))
|
||||
* **lifecycle:** create multi-instances at the same time ([#660](https://github.com/ArtalkJS/Artalk/issues/660)) ([#663](https://github.com/ArtalkJS/Artalk/issues/663))
|
||||
* **notify_pusher:** panic when admin ids array is empty ([#634](https://github.com/ArtalkJS/Artalk/issues/634))
|
||||
* **style/list:** replace `float` to `text-align` in footer part ([#619](https://github.com/ArtalkJS/Artalk/issues/619))
|
||||
* **ui:** scroll to the center of the viewport issue
|
||||
* **ui/conf:** sanitize `noComment` conf option for security ([#624](https://github.com/ArtalkJS/Artalk/issues/624))
|
||||
* **ui/dark-mode:** `setDarkMode` cannot save to instance config ([#661](https://github.com/ArtalkJS/Artalk/issues/661))
|
||||
* **ui/editor:** fix position of the comment box when replying ([#643](https://github.com/ArtalkJS/Artalk/issues/643)) ([#648](https://github.com/ArtalkJS/Artalk/issues/648))
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
* **cache:** implement GC feature for simple_cache pkg ([#656](https://github.com/ArtalkJS/Artalk/issues/656))
|
||||
|
||||
### Code Refactoring
|
||||
|
||||
* **editor:** refactor editor plugin manager ([#609](https://github.com/ArtalkJS/Artalk/issues/609))
|
||||
* **editor:** refactor plug kit and events ([#613](https://github.com/ArtalkJS/Artalk/issues/613))
|
||||
* **ui:** reduce coupling with `ContextApi`
|
||||
* **ui:** separate standalone admin-only-elem checker
|
||||
* **ui/api:** loose coupling between `Api` and `Context`
|
||||
* **ui/conf:** loose coupling between config and list fetch
|
||||
* **ui/event:** refactor core event manager ([#611](https://github.com/ArtalkJS/Artalk/issues/611))
|
||||
* **ui/layer:** better layer implements and independence ([#662](https://github.com/ArtalkJS/Artalk/issues/662))
|
||||
* **ui/list:** separate list into standalone components ([#618](https://github.com/ArtalkJS/Artalk/issues/618))
|
||||
* **ui/marked:** separate markdown related codes
|
||||
* **ui/marked:** loose coupling with `marked` func
|
||||
* **ui/plugin:** further divide functionality into plugins ([#615](https://github.com/ArtalkJS/Artalk/issues/615))
|
||||
* **ui/stat:** losing coupling of `CountWidget`
|
||||
* **ui/types:** better `ArtalkType` import and export ([#620](https://github.com/ArtalkJS/Artalk/issues/620))
|
||||
|
||||
### Documentation
|
||||
|
||||
* revise and add more examples
|
||||
* provide clearer and more detailed instructions in CONTRIBUTING.md
|
||||
* **conf:** disable `frontend.uaBadge` config option by default
|
||||
* **deploy:** add deployment guide for render.com ([#649](https://github.com/ArtalkJS/Artalk/issues/649))
|
||||
* **import:** update the examples in import-framework.md ([#665](https://github.com/ArtalkJS/Artalk/issues/665))
|
||||
|
||||
### BREAKING CHANGE
|
||||
|
||||
|
||||
The following top-level functions exported by the 'artalk' npm package have been deprecated: `Artalk.update`, `Artalk.reload`, and `Artalk.destroy`. These methods now require invocation on an instance created by either `Artalk.init` or `new Artalk`. Please utilize instance-level methods instead, such as `artalkInstance.update`. For more information, refer to [the documentation](https://artalk.js.org/guide/frontend/import-framework.html). The update was implemented to enable the concurrent creation of multiple instances, adapting to situations where Vue components are simultaneously referenced across various pages. Initially, only a singular instance was permitted to mitigate memory leak concerns. However, this proved limiting for scenarios involving the caching of multiple component instances through 'keep-alive.' To better suit intricate SPA application needs, the choice was made to permit the creation of multiple independent instances. It's crucial to remember to manually invoke the `artalk.destroy` method when releasing components to avoid memory leaks (Issue [#660](https://github.com/ArtalkJS/Artalk/issues/660)).
|
||||
|
||||
|
||||
## [v2.6.4](https://github.com/ArtalkJS/Artalk/compare/v2.6.3...v2.6.4) (2023-10-12)
|
||||
|
||||
### Features
|
||||
|
||||
* **go:** upgrade golang to v1.21.3 and some deps
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **editor:** fix duplicate event binding when update conf ([#605](https://github.com/ArtalkJS/Artalk/issues/605))
|
||||
* **email:** sender not initialized correctly
|
||||
* **style:** fix copyright text overlay on send button ([#607](https://github.com/ArtalkJS/Artalk/issues/607))
|
||||
|
||||
### Code Refactoring
|
||||
|
||||
* **anti_spam:** refactor anti_spam pkg and add unit test ([#589](https://github.com/ArtalkJS/Artalk/issues/589))
|
||||
|
||||
|
||||
## [v2.6.3](https://github.com/ArtalkJS/Artalk/compare/v2.6.2...v2.6.3) (2023-09-20)
|
||||
|
||||
### Features
|
||||
|
||||
* **config:** add `db.ssl` to enable db ssl mode ([#587](https://github.com/ArtalkJS/Artalk/issues/587))
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **notify_tpl:** fix template render result in notify case
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
* **config:** add error message for timezone setting ([#586](https://github.com/ArtalkJS/Artalk/issues/586))
|
||||
|
||||
### Code Refactoring
|
||||
|
||||
* **renderer:** abstract func of template renderer for multi-cases ([#585](https://github.com/ArtalkJS/Artalk/issues/585))
|
||||
|
||||
### Documentation
|
||||
|
||||
* new landing page
|
||||
|
||||
|
||||
## [v2.6.2](https://github.com/ArtalkJS/Artalk/compare/v2.6.1...v2.6.2) (2023-09-12)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **cmd:** remove app instance creation when mini boot ([#577](https://github.com/ArtalkJS/Artalk/issues/577))
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
* **style:** modify `z-index` less than 5 ([#578](https://github.com/ArtalkJS/Artalk/issues/578))
|
||||
|
||||
|
||||
## [v2.6.1](https://github.com/ArtalkJS/Artalk/compare/v2.6.0...v2.6.1) (2023-09-11)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
+11
-11
@@ -17,23 +17,23 @@ diverse, inclusive, and healthy community.
|
||||
Examples of behavior that contributes to a positive environment for our
|
||||
community include:
|
||||
|
||||
* Demonstrating empathy and kindness toward other people
|
||||
* Being respectful of differing opinions, viewpoints, and experiences
|
||||
* Giving and gracefully accepting constructive feedback
|
||||
* Accepting responsibility and apologizing to those affected by our mistakes,
|
||||
- Demonstrating empathy and kindness toward other people
|
||||
- Being respectful of differing opinions, viewpoints, and experiences
|
||||
- Giving and gracefully accepting constructive feedback
|
||||
- Accepting responsibility and apologizing to those affected by our mistakes,
|
||||
and learning from the experience
|
||||
* Focusing on what is best not just for us as individuals, but for the overall
|
||||
- Focusing on what is best not just for us as individuals, but for the overall
|
||||
community
|
||||
|
||||
Examples of unacceptable behavior include:
|
||||
|
||||
* The use of sexualized language or imagery, and sexual attention or advances of
|
||||
- The use of sexualized language or imagery, and sexual attention or advances of
|
||||
any kind
|
||||
* Trolling, insulting or derogatory comments, and personal or political attacks
|
||||
* Public or private harassment
|
||||
* Publishing others' private information, such as a physical or email address,
|
||||
- Trolling, insulting or derogatory comments, and personal or political attacks
|
||||
- Public or private harassment
|
||||
- Publishing others' private information, such as a physical or email address,
|
||||
without their explicit permission
|
||||
* Other conduct which could reasonably be considered inappropriate in a
|
||||
- Other conduct which could reasonably be considered inappropriate in a
|
||||
professional setting
|
||||
|
||||
## Enforcement Responsibilities
|
||||
@@ -59,7 +59,7 @@ representative at an online or offline event.
|
||||
## Enforcement
|
||||
|
||||
Instances of abusive, harassing, or otherwise unacceptable behavior may be
|
||||
reported to the community leaders responsible for enforcement at artalkjs@gmail.com.
|
||||
reported to the community leaders responsible for enforcement at <artalkjs@gmail.com>.
|
||||
All complaints will be reviewed and investigated promptly and fairly.
|
||||
|
||||
All community leaders are obligated to respect the privacy and security of the
|
||||
|
||||
+258
-59
@@ -1,99 +1,298 @@
|
||||
# Developer Contributing Guide
|
||||
|
||||
This guide is for developers who want to contribute to the project.
|
||||
This guide helps developers understand how to contribute code, documentation, tests, and feedback to the Artalk project. We welcome all forms of contributions, whether it's large feature development, small fixes, documentation improvements, or testing. We believe that every contribution is an important part of moving the project forward.
|
||||
|
||||
## Development Environment
|
||||
This guide is available in multiple languages: [English](https://github.com/ArtalkJS/Artalk/blob/master/CONTRIBUTING.md) • [简体中文](https://artalk.js.org/develop/contributing.html)
|
||||
|
||||
To develop Artalk, including the frontend and backend, you need to install the following tools:
|
||||
## Setup
|
||||
|
||||
- [Node.js](https://nodejs.org/en/) (>= 16.0.0)
|
||||
- [Go](https://golang.org/) (>= 1.21)
|
||||
- [Docker](https://www.docker.com/) (>= 20.10.0) (optional)
|
||||
- [Docker Compose](https://docs.docker.com/compose/) (>= 1.29.0) (optional)
|
||||
|
||||
Then we'll setup the development environment.
|
||||
|
||||
### Get the source code
|
||||
|
||||
Run the following command to clone the repository:
|
||||
Clone the repository:
|
||||
|
||||
```sh
|
||||
git clone https://github.com/ArtalkJS/Artalk
|
||||
git clone https://github.com/ArtalkJS/Artalk.git
|
||||
```
|
||||
|
||||
It is recommended to fork the repository first, and then clone the forked repository.
|
||||
It's recommended to fork the repository first, and then clone the forked repository.
|
||||
|
||||
Enter the directory:
|
||||
Navigate to the directory:
|
||||
|
||||
```sh
|
||||
cd Artalk
|
||||
```
|
||||
|
||||
### Build frontend and backend
|
||||
## Development Environment
|
||||
|
||||
First, we need to install the dependencies for backend written in Go. Simply run the following command:
|
||||
To develop Artalk, both frontend and backend, install the following tools:
|
||||
|
||||
```sh
|
||||
make build-debug
|
||||
```
|
||||
- [Node.js](https://nodejs.org/en/) (>= 20.17.0)
|
||||
- [PNPM](https://pnpm.io/) (>= 9.9.0)
|
||||
- [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)
|
||||
|
||||
This will build both the frontend and backend, with debugging symbols.
|
||||
## Development Workflow Overview
|
||||
|
||||
- **Frontend** will be built under `./ui/packages/artalk` and copied to `./public` directory.
|
||||
- **Backend** will be built under `./bin` directory.
|
||||
The development workflow consists of the following steps:
|
||||
|
||||
### Optional: Use one-key script to run a demo site
|
||||
1. **Set Up Complete Development Instance**:
|
||||
|
||||
If you want to run a demo site, you can use the following command:
|
||||
- Navigate to the Artalk Repo directory.
|
||||
- Execute `make dev` to run the backend on port `23366`.
|
||||
- Execute `pnpm dev` to run the frontend on port `5173`.
|
||||
- Optionally, execute `pnpm dev:sidebar` to run the sidebar frontend on port `23367`.
|
||||
|
||||
```sh
|
||||
./scripts/setup-example-site.sh
|
||||
```
|
||||
2. **Access Frontend for Development**:
|
||||
|
||||
This script sets up a local example site for testing at `local` folder, with Artalk integrated into its theme.
|
||||
- Open your browser and go to `http://localhost:5173` to perform your development and testing.
|
||||
|
||||
After running this script, run:
|
||||
3. **Testing**:
|
||||
|
||||
```sh
|
||||
./bin/artalk server -c ./local/local.yml
|
||||
```
|
||||
- Run the backend unit tests using `make test`.
|
||||
- Run the ui unit tests using `pnpm test`.
|
||||
- Run the ui E2E tests using `make test-frontend-e2e`.
|
||||
|
||||
to start the artalk server.
|
||||
4. **Building Frontend Code**:
|
||||
|
||||
And open <http://localhost:1313/> in your browser to view the example site.
|
||||
- When you make changes to the frontend code, build the complete frontend program using `pnpm build:all`.
|
||||
- The JavaScript and CSS code will be found in `ui/artalk/dist`.
|
||||
- The frontend code is automatically deployed to NPM by GitHub Actions.
|
||||
|
||||
Here is the default admin account (only created in test mode):
|
||||
5. **Building Backend Code**:
|
||||
|
||||
```yaml
|
||||
name: "admin"
|
||||
email: "admin@test.com"
|
||||
password: "admin"
|
||||
```
|
||||
- When you make changes to the backend code, note that the backend program embeds the frontend code.
|
||||
- Before building the backend, run `make build-frontend` (which runs `scripts/build-frontend.sh`). This will place the embedded frontend main program and sidebar frontend program in `/public`.
|
||||
- Then, build the backend program using `make build`.
|
||||
|
||||
More exploration:
|
||||
|
||||
- **Developing Artalk Plugins or Themes**:
|
||||
Refer to the [Artalk Plugin Development Guide](https://artalk.js.org/develop/plugin.html).
|
||||
|
||||
- **Makefile**:
|
||||
You can explore the process and commands in the `Makefile`.
|
||||
|
||||
- **Automated CI on GitHub**:
|
||||
The automated CI pipeline on GitHub, located in the `.github/workflows` directory, builds the frontend, backend, and Docker images. It publishes Docker images to Docker Hub, handles npm package publishing, and creates GitHub Releases. And also testing the frontend and backend.
|
||||
|
||||
The following sections provide more detailed information on the development workflow.
|
||||
|
||||
## Project Structure
|
||||
|
||||
Artalk is a monorepo project, which means all the source code is in the same repository. However, the frontend and backend are separated. The frontend part is located in `./ui` directory.
|
||||
Artalk is a monorepo project, meaning all the source code resides in a single repository. Despite this, the frontend and backend are kept separate. The frontend part is located in the `./ui` directory.
|
||||
|
||||
- `bin/` - The compiled binary files. This directory is ignored by git.
|
||||
- `cmd/` - The source code for the command line tools.
|
||||
- `conf/` - The sample configuration files.
|
||||
- `docs/` - The documentation site source code.
|
||||
- `i18n/` - The translation files.
|
||||
- `internal/` - The internal packages.
|
||||
- `local/` - The local example site. This directory is ignored by git.
|
||||
- `public/` - The static files. Built frontend files will be copied here.
|
||||
- `scripts/` - The scripts for development.
|
||||
- `server/` - The source code for the server.
|
||||
- `ui/` - The source code for the frontend.
|
||||
### Directory Overview
|
||||
|
||||
## Translation
|
||||
- `bin/`: The compiled binary files. (This directory is ignored by git).
|
||||
- `cmd/`: The source code for the command line tools.
|
||||
- `conf/`: The sample configuration files.
|
||||
- `data/`: The local data. (This directory is ignored by git).
|
||||
- `docs/`: The documentation site source code.
|
||||
- `i18n/`: The translation files.
|
||||
- `local/`: The local files. (This directory is ignored by git).
|
||||
- `internal/`: The Go source code for the internal packages.
|
||||
- `public/`: The static files. Built frontend files will be copied here.
|
||||
- `scripts/`: The scripts for development and building.
|
||||
- `server/`: The Go source code for the backend.
|
||||
- `ui/`: The UI source code for the frontend.
|
||||
- `.github/`: The GitHub Actions workflows.
|
||||
- `.vscode/`: The VSCode settings.
|
||||
|
||||
Artalk aims to be a multilingual project. If you would like to contribute to the translation, here are some tips:
|
||||
## Backend Development
|
||||
|
||||
If you just write some new features or do some fixes/refactoring, use the following command to generate the translation template
|
||||
### Run Backend
|
||||
|
||||
1. **Create Configuration File**:
|
||||
|
||||
- Copy `./conf/artalk.example.yml` to the root directory.
|
||||
- Rename it to `artalk.yml`.
|
||||
- Modify the file as needed.
|
||||
|
||||
2. **Start Backend Program**:
|
||||
|
||||
- Run `make dev` to start the backend on port `23366`.
|
||||
- Access it via `http://localhost:23366`.
|
||||
- It's recommended to keep the default port for testing.
|
||||
- (Alternative) Use `ARGS="version" make dev` to pass startup parameters (default is `ARGS="server"`).
|
||||
|
||||
The `make dev` builds the backend with debugging symbols, which is convenient for debugging with GDB.
|
||||
|
||||
If you are using the VSCode, you can use the `F5` key (or RUN button) to start debugging the backend program directly.
|
||||
|
||||
### Build Backend
|
||||
|
||||
1. **Fetch Latest Git Tag**:
|
||||
Execute `git fetch --tags` to get the latest git tag information. This tag will be used as the version number of the backend app. Alternatively, specify it using environment variables: `VERSION="v1.0.0"` and `COMMIT_HASH="66128e"`.
|
||||
|
||||
2. **Build Frontend**:
|
||||
Run `make build-fronted` to build the frontend, as the backend app embeds the frontend code.
|
||||
|
||||
3. **Build Backend**:
|
||||
Execute `make build` to build the backend program.
|
||||
|
||||
The built binary file will be located in the `./bin` directory.
|
||||
|
||||
## Frontend Development (UI)
|
||||
|
||||
### Run Frontend
|
||||
|
||||
1. **Install Dependencies**:
|
||||
Run `pnpm install` to install all necessary dependencies.
|
||||
|
||||
2. **Start Development Server**:
|
||||
Execute `pnpm dev --port 5173` to start the frontend development server.
|
||||
|
||||
3. **Access the Frontend**:
|
||||
The frontend application will run on port `5173` by default. Access it in your browser at `http://localhost:5173`.
|
||||
|
||||
4. **Sidebar Development**:
|
||||
To run the sidebar part of the frontend, use `pnpm dev:sidebar`.
|
||||
|
||||
The ports `5173` and `23367` are used for frontend development and testing. These ports are included in the `ATK_TRUSTED_DOMAINS` configuration of the backend program.
|
||||
|
||||
### Build Frontend
|
||||
|
||||
To build the frontend, run the following command:
|
||||
|
||||
```sh
|
||||
go run ./internal/i18n/gen -w . -d .
|
||||
make build-frontend
|
||||
```
|
||||
|
||||
If you're not a programmer and would like to help us improve the translation, you can edit the translation files directly in the `.i18n' directory and then submit a pull request.
|
||||
The compiled JavaScript and CSS files will be located in the `/public` directory, embedded into the backend program.
|
||||
|
||||
For more details, refer to the `scripts/build-frontend.sh` script.
|
||||
|
||||
## Docker Development
|
||||
|
||||
### Build Docker Image
|
||||
|
||||
To build the Docker image, run the following command:
|
||||
|
||||
```sh
|
||||
docker build -t artalk:TAG .
|
||||
```
|
||||
|
||||
Replace `TAG` with the desired tag name (e.g., `latest`).
|
||||
|
||||
### Skip Frontend Build
|
||||
|
||||
If you have already built the frontend outside the Docker container, you can skip the frontend build process inside the container to speed up the build. Use the following command:
|
||||
|
||||
```sh
|
||||
docker build --build-arg SKIP_FRONTEND_BUILD=true -t artalk:latest .
|
||||
```
|
||||
|
||||
For more details, refer to the `Dockerfile`.
|
||||
|
||||
## Testing
|
||||
|
||||
### Testing the Backend
|
||||
|
||||
To test the backend Go program, you can use the following commands:
|
||||
|
||||
- **Unit Testing**:
|
||||
Run `make test` to execute unit tests. The results will be outputted in the terminal.
|
||||
|
||||
- **Test Coverage**:
|
||||
Run `make test-coverage` to check the code test coverage.
|
||||
|
||||
- **HTML Coverage Report**:
|
||||
Run `make test-coverage-html` to generate and browse the test coverage report in HTML format.
|
||||
|
||||
- **Run Specific Tests**:
|
||||
To run specific tests, use the command with an environment variable:
|
||||
```sh
|
||||
TEST_PATHS="./server/..." make test
|
||||
```
|
||||
|
||||
### Testing the Frontend
|
||||
|
||||
Frontend testing includes unit tests and end-to-end (E2E) tests.
|
||||
|
||||
- **Unit Testing**:
|
||||
The unit tests for the frontend are conducted using Vitest. Run `pnpm test` to start the unit testing.
|
||||
|
||||
- **End-to-End Testing**:
|
||||
E2E testing is conducted using Playwright. To start the E2E testing, run:
|
||||
```sh
|
||||
make test-frontend-e2e
|
||||
```
|
||||
|
||||
### Continuous Integration for Testing
|
||||
|
||||
Both frontend and backend testing are automated and will be performed during Git pull requests and as part of the build process using CircleCI or GitHub Actions.
|
||||
|
||||
## Configurations
|
||||
|
||||
The template configuration files are located in the `/conf` directory, with templates annotated in multiple languages named in the format `artalk.example.[lang].yml` (e.g., `artalk.example.zh-CN.yml`). Artalk will parse these template configuration files to generate the settings interface, environment variable names, and documentation. To improve performance, some data will be cached during the program's runtime to eliminate parsing time.
|
||||
|
||||
In the `internal/config/config.go` file, there is a definition of the `Config` struct, which is used to parse the yml files into Go structs. This struct contains more precise type definitions. If you need to add, modify, or delete a configuration item, you must make changes to both the configuration file templates in `/conf` and the `Config` struct.
|
||||
|
||||
When you modify the configuration files, please run the following command to update the configuration data cache:
|
||||
|
||||
```sh
|
||||
make update-conf
|
||||
```
|
||||
|
||||
To update the environment variable documentation, you can run the command:
|
||||
|
||||
```sh
|
||||
make update-conf-docs
|
||||
```
|
||||
|
||||
## Documentations
|
||||
|
||||
The documentation consists of three parts, each associated with a specific package: **Guide documentation**, **Landing page**, and **Swagger API documentation**. Below is an organized summary of the relevant commands and their outputs for each package.
|
||||
|
||||
### Guide Documentation (`docs`)
|
||||
|
||||
- **Directory**: `docs/docs/guide`
|
||||
- **Dev Command**: `pnpm -F docs dev:docs`
|
||||
- **Build Command**: `pnpm -F docs build:docs`
|
||||
- **Output Directory**: `docs/docs/.vitepress/dist`
|
||||
|
||||
### Landing Page (`docs-landing`)
|
||||
|
||||
- **Directory**: `docs/landing`
|
||||
- **Dev Command**: `pnpm -F docs-landing dev:landing`
|
||||
- **Build Command**: `pnpm -F docs-landing build:landing`
|
||||
- **Output Directory**: `docs/landing/dist`
|
||||
|
||||
### Swagger API Documentation (`docs-swagger`)
|
||||
|
||||
- **Directory**: `docs/swagger`
|
||||
- **Build Command**: `make update-swagger`
|
||||
- **Output Directory**: `docs/swagger`
|
||||
|
||||
Swagger definitions are located in the backend code at `/server`. After modifying the Swagger definitions, running the build command will update the Swagger docs and generate HTTP client code at `/ui/artalk/src/api/v2.ts`.
|
||||
|
||||
### Combined Build
|
||||
|
||||
- **Command to Build All Packages**: `pnpm build:docs`
|
||||
- **Combined Output Directory**: `docs/docs/.vitepress/dist`
|
||||
|
||||
This command builds and combines all three packages into a single directory, ready for publishing.
|
||||
|
||||
### Environment Variable Documentation
|
||||
|
||||
- **File**: `docs/docs/guide/env.md`
|
||||
- **Command to Update**: `make update-conf-docs`
|
||||
|
||||
This command reads the configuration template file located in `/conf` to update the environment variable documentation. Run this command after modifying the configuration template file.
|
||||
|
||||
## Translation (i18n)
|
||||
|
||||
If you write new features or make fixes/refactoring, use the following command to incrementally generate the translation files by parsing the source code for `i18n.T` function calls:
|
||||
|
||||
```sh
|
||||
make update-i18n
|
||||
```
|
||||
|
||||
If you're not a programmer and would like to help improve the translation, you can edit the translation files directly in the `/i18n` directory and then submit a pull request.
|
||||
|
||||
## The End
|
||||
|
||||
Thank you for your patience in reading this and for your interest and support in Artalk. We understand that the success of an open-source project relies on the contributions of every developer. Whether through code, documentation, testing, or feedback, your participation is the driving force behind the project's continuous progress. We sincerely invite you to join us in improving and enhancing Artalk.
|
||||
|
||||
By collaborating, we can create a more robust and versatile platform that benefits the entire community. Your unique insights and expertise are invaluable, and together, we can achieve remarkable advancements. Whether you are a seasoned developer or just starting, there is always a place for your contributions in our project.
|
||||
|
||||
If you have any questions or need assistance, please feel free to ask in the issue section on our GitHub page: https://github.com/ArtalkJS/Artalk/issues. Thank you once again for your support, and we look forward to working with you.
|
||||
+25
-8
@@ -1,12 +1,11 @@
|
||||
### build Artalk
|
||||
FROM golang:1.21.0-alpine3.18 as builder
|
||||
FROM golang:1.22.6-alpine3.20 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.7.0
|
||||
&& apk add --no-cache make git gcc musl-dev bash
|
||||
|
||||
# download go deps
|
||||
# (cache by separating the downloading of deps)
|
||||
@@ -16,20 +15,38 @@ 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@9.9.0 \
|
||||
;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.20
|
||||
|
||||
# we set the timezone `Asia/Shanghai` by default, you can be modified
|
||||
# by `docker build --build-arg="TZ=Other_Timezone ..."`
|
||||
ARG TZ="Asia/Shanghai"
|
||||
|
||||
ENV TZ ${TZ}
|
||||
ENV TZ=${TZ}
|
||||
|
||||
COPY --from=builder /source/bin/artalk /artalk
|
||||
|
||||
|
||||
@@ -1,165 +1,21 @@
|
||||
GNU LESSER GENERAL PUBLIC LICENSE
|
||||
Version 3, 29 June 2007
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
Copyright (c) 2018-present, qwqcode and other contributors
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
This version of the GNU Lesser General Public License incorporates
|
||||
the terms and conditions of version 3 of the GNU General Public
|
||||
License, supplemented by the additional permissions listed below.
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
0. Additional Definitions.
|
||||
|
||||
As used herein, "this License" refers to version 3 of the GNU Lesser
|
||||
General Public License, and the "GNU GPL" refers to version 3 of the GNU
|
||||
General Public License.
|
||||
|
||||
"The Library" refers to a covered work governed by this License,
|
||||
other than an Application or a Combined Work as defined below.
|
||||
|
||||
An "Application" is any work that makes use of an interface provided
|
||||
by the Library, but which is not otherwise based on the Library.
|
||||
Defining a subclass of a class defined by the Library is deemed a mode
|
||||
of using an interface provided by the Library.
|
||||
|
||||
A "Combined Work" is a work produced by combining or linking an
|
||||
Application with the Library. The particular version of the Library
|
||||
with which the Combined Work was made is also called the "Linked
|
||||
Version".
|
||||
|
||||
The "Minimal Corresponding Source" for a Combined Work means the
|
||||
Corresponding Source for the Combined Work, excluding any source code
|
||||
for portions of the Combined Work that, considered in isolation, are
|
||||
based on the Application, and not on the Linked Version.
|
||||
|
||||
The "Corresponding Application Code" for a Combined Work means the
|
||||
object code and/or source code for the Application, including any data
|
||||
and utility programs needed for reproducing the Combined Work from the
|
||||
Application, but excluding the System Libraries of the Combined Work.
|
||||
|
||||
1. Exception to Section 3 of the GNU GPL.
|
||||
|
||||
You may convey a covered work under sections 3 and 4 of this License
|
||||
without being bound by section 3 of the GNU GPL.
|
||||
|
||||
2. Conveying Modified Versions.
|
||||
|
||||
If you modify a copy of the Library, and, in your modifications, a
|
||||
facility refers to a function or data to be supplied by an Application
|
||||
that uses the facility (other than as an argument passed when the
|
||||
facility is invoked), then you may convey a copy of the modified
|
||||
version:
|
||||
|
||||
a) under this License, provided that you make a good faith effort to
|
||||
ensure that, in the event an Application does not supply the
|
||||
function or data, the facility still operates, and performs
|
||||
whatever part of its purpose remains meaningful, or
|
||||
|
||||
b) under the GNU GPL, with none of the additional permissions of
|
||||
this License applicable to that copy.
|
||||
|
||||
3. Object Code Incorporating Material from Library Header Files.
|
||||
|
||||
The object code form of an Application may incorporate material from
|
||||
a header file that is part of the Library. You may convey such object
|
||||
code under terms of your choice, provided that, if the incorporated
|
||||
material is not limited to numerical parameters, data structure
|
||||
layouts and accessors, or small macros, inline functions and templates
|
||||
(ten or fewer lines in length), you do both of the following:
|
||||
|
||||
a) Give prominent notice with each copy of the object code that the
|
||||
Library is used in it and that the Library and its use are
|
||||
covered by this License.
|
||||
|
||||
b) Accompany the object code with a copy of the GNU GPL and this license
|
||||
document.
|
||||
|
||||
4. Combined Works.
|
||||
|
||||
You may convey a Combined Work under terms of your choice that,
|
||||
taken together, effectively do not restrict modification of the
|
||||
portions of the Library contained in the Combined Work and reverse
|
||||
engineering for debugging such modifications, if you also do each of
|
||||
the following:
|
||||
|
||||
a) Give prominent notice with each copy of the Combined Work that
|
||||
the Library is used in it and that the Library and its use are
|
||||
covered by this License.
|
||||
|
||||
b) Accompany the Combined Work with a copy of the GNU GPL and this license
|
||||
document.
|
||||
|
||||
c) For a Combined Work that displays copyright notices during
|
||||
execution, include the copyright notice for the Library among
|
||||
these notices, as well as a reference directing the user to the
|
||||
copies of the GNU GPL and this license document.
|
||||
|
||||
d) Do one of the following:
|
||||
|
||||
0) Convey the Minimal Corresponding Source under the terms of this
|
||||
License, and the Corresponding Application Code in a form
|
||||
suitable for, and under terms that permit, the user to
|
||||
recombine or relink the Application with a modified version of
|
||||
the Linked Version to produce a modified Combined Work, in the
|
||||
manner specified by section 6 of the GNU GPL for conveying
|
||||
Corresponding Source.
|
||||
|
||||
1) Use a suitable shared library mechanism for linking with the
|
||||
Library. A suitable mechanism is one that (a) uses at run time
|
||||
a copy of the Library already present on the user's computer
|
||||
system, and (b) will operate properly with a modified version
|
||||
of the Library that is interface-compatible with the Linked
|
||||
Version.
|
||||
|
||||
e) Provide Installation Information, but only if you would otherwise
|
||||
be required to provide such information under section 6 of the
|
||||
GNU GPL, and only to the extent that such information is
|
||||
necessary to install and execute a modified version of the
|
||||
Combined Work produced by recombining or relinking the
|
||||
Application with a modified version of the Linked Version. (If
|
||||
you use option 4d0, the Installation Information must accompany
|
||||
the Minimal Corresponding Source and Corresponding Application
|
||||
Code. If you use option 4d1, you must provide the Installation
|
||||
Information in the manner specified by section 6 of the GNU GPL
|
||||
for conveying Corresponding Source.)
|
||||
|
||||
5. Combined Libraries.
|
||||
|
||||
You may place library facilities that are a work based on the
|
||||
Library side by side in a single library together with other library
|
||||
facilities that are not Applications and are not covered by this
|
||||
License, and convey such a combined library under terms of your
|
||||
choice, if you do both of the following:
|
||||
|
||||
a) Accompany the combined library with a copy of the same work based
|
||||
on the Library, uncombined with any other library facilities,
|
||||
conveyed under the terms of this License.
|
||||
|
||||
b) Give prominent notice with the combined library that part of it
|
||||
is a work based on the Library, and explaining where to find the
|
||||
accompanying uncombined form of the same work.
|
||||
|
||||
6. Revised Versions of the GNU Lesser General Public License.
|
||||
|
||||
The Free Software Foundation may publish revised and/or new versions
|
||||
of the GNU Lesser General Public License from time to time. Such new
|
||||
versions will be similar in spirit to the present version, but may
|
||||
differ in detail to address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the
|
||||
Library as you received it specifies that a certain numbered version
|
||||
of the GNU Lesser General Public License "or any later version"
|
||||
applies to it, you have the option of following the terms and
|
||||
conditions either of that published version or of any later version
|
||||
published by the Free Software Foundation. If the Library as you
|
||||
received it does not specify a version number of the GNU Lesser
|
||||
General Public License, you may choose any version of the GNU Lesser
|
||||
General Public License ever published by the Free Software Foundation.
|
||||
|
||||
If the Library as you received it specifies that a proxy can decide
|
||||
whether future versions of the GNU Lesser General Public License shall
|
||||
apply, that proxy's public statement of acceptance of any version is
|
||||
permanent authorization for you to choose that version for the
|
||||
Library.
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
@@ -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,10 @@ all: install build
|
||||
install:
|
||||
go mod tidy
|
||||
|
||||
build: build-frontend
|
||||
run: all
|
||||
$(BIN_NAME) $(ARGS)
|
||||
|
||||
build:
|
||||
go build \
|
||||
-ldflags "-s -w -X $(PKG_NAME)/internal/config.Version=$(VERSION) \
|
||||
-X $(PKG_NAME)/internal/config.CommitHash=$(COMMIT_HASH)" \
|
||||
@@ -23,9 +25,6 @@ build: build-frontend
|
||||
build-frontend:
|
||||
./scripts/build-frontend.sh
|
||||
|
||||
run: all
|
||||
$(BIN_NAME) $(ARGS)
|
||||
|
||||
build-debug:
|
||||
@echo "Building Artalk $(VERSION) for debugging..."
|
||||
@go build \
|
||||
@@ -36,23 +35,36 @@ build-debug:
|
||||
$(PKG_NAME)
|
||||
|
||||
dev: build-debug
|
||||
ATK_SITE_DEFAULT="ArtalkDocs" \
|
||||
ATK_TRUSTED_DOMAINS="http://localhost:5173 http://localhost:23367" \
|
||||
$(BIN_NAME) $(ARGS)
|
||||
|
||||
test:
|
||||
$(GOTEST) -timeout 20m ./internal/...
|
||||
$(GOTEST) -timeout 20m $(or $(TEST_PATHS), ./...)
|
||||
|
||||
test-coverage:
|
||||
$(GOTEST) -cover ./...
|
||||
$(GOTEST) -cover $(or $(TEST_PATHS), ./...)
|
||||
|
||||
test-coverage-html:
|
||||
$(GOTEST) -v -coverprofile=coverage.out ./...
|
||||
$(GOTEST) -v -coverprofile=coverage.out $(or $(TEST_PATHS), ./...)
|
||||
go tool cover -html=coverage.out
|
||||
|
||||
test-frontend-e2e:
|
||||
./scripts/frontend-e2e-test.sh $(if $(REPORT), --show-report)
|
||||
|
||||
update-i18n:
|
||||
go generate ./internal/i18n
|
||||
|
||||
update-conf:
|
||||
go generate ./internal/config
|
||||
|
||||
update-conf-docs:
|
||||
go run ./internal/config/meta/gen --format markdown --locale zh-CN -o ./docs/docs/guide/env.md
|
||||
|
||||
update-swagger:
|
||||
swag init -g server/server.go --output ./docs/swagger
|
||||
go install github.com/swaggo/swag/cmd/swag@latest
|
||||
swag init -g server/server.go --output ./docs/swagger --requiredByDefault
|
||||
pnpm -r swagger:build-http-client
|
||||
|
||||
docker-build:
|
||||
./scripts/docker-build.sh
|
||||
@@ -60,6 +72,7 @@ docker-build:
|
||||
docker-push:
|
||||
./scripts/docker-build.sh --push
|
||||
|
||||
.PHONY: all install build build-frontend build-debug \
|
||||
dev test test-coverage test-coverage-html update-i18n \
|
||||
.PHONY: all install run build build-frontend build-debug dev \
|
||||
test test-coverage test-coverage-html test-frontend-e2e \
|
||||
update-i18n update-conf update-conf-docs update-swagger \
|
||||
docker-build docker-push;
|
||||
+83
-92
@@ -1,129 +1,120 @@
|
||||
<p align="center">
|
||||
<img src="https://user-images.githubusercontent.com/22412567/137740516-d9e97af0-fb3b-4dab-b331-671a9a2a3a63.png" alt="Artalk" width="100%">
|
||||
<img src="https://user-images.githubusercontent.com/22412567/171680920-6e74b77c-c565-487b-bff1-4f94976ecbe7.png" alt="Artalk" width="100%">
|
||||
</p>
|
||||
|
||||
# Artalk
|
||||
|
||||
[](https://www.npmjs.com/package/artalk)
|
||||
[](https://www.npmjs.com/package/artalk)
|
||||
[](https://bundlephobia.com/package/artalk)
|
||||
[](https://circleci.com/gh/ArtalkJS/Artalk/tree/master)
|
||||
[](https://www.npmjs.com/package/artalk)
|
||||
[](https://www.npmjs.com/package/artalk)
|
||||
[](https://hub.docker.com/r/artalk/artalk-go)
|
||||
[](https://goreportcard.com/report/github.com/ArtalkJS/Artalk)
|
||||
[](https://circleci.com/gh/ArtalkJS/Artalk/tree/master)
|
||||
[](https://codecov.io/gh/ArtalkJS/Artalk)
|
||||
[](https://bundlephobia.com/package/artalk)
|
||||
|
||||
> 🌌 A Self-hosted comment system
|
||||
[中文](./README.md) • [Official Website](https://artalk.js.org) • [Latest Release](https://github.com/ArtalkJS/Artalk/releases) • [Changelog](https://github.com/ArtalkJS/Artalk/blob/master/CHANGELOG.md)
|
||||
|
||||
[简体中文](./README.md) / [Documentation](https://artalk.js.org) / [Releases](https://github.com/ArtalkJS/Artalk/releases) / [Artalk](https://github.com/ArtalkJS/Artalk)
|
||||
🌌 Artalk is a simple yet feature-rich commenting system that you can deploy out of the box and integrate into any blog, website, or web application.
|
||||
|
||||
---
|
||||
|
||||
- 🍃 Lightweight (~30kB)
|
||||
- 👨👧👦 Secure (Self-hosted)
|
||||
- 🐳 Easy to use (Very Easy)
|
||||
- 🍱 Golang backend (Fast and Cross Platform)
|
||||
- 🌊 TypeScript × Vanilla × Vite (No Dependencies)
|
||||
- 🍃 Frontend ~40KB, pure Vanilla JS
|
||||
- 🍱 Backend Golang, efficient lightweight cross-platform
|
||||
- 🐳 One-click deployment via Docker, convenient and fast
|
||||
- 🌈 Open-source program, self-hosted, privacy-first
|
||||
|
||||
## Features
|
||||
|
||||
- Sidebar: Multi-site centralized management
|
||||
- Notification Center: Red badge alert / Mark as read
|
||||
- Verification: User Verification Badge / Password access
|
||||
- Moderation: Anti-spam detection / Captcha frequency limit
|
||||
- Emoticons: Insert emoji / Quickly import presets
|
||||
- Email Notify: Template customization / Send to multi-admin
|
||||
- Site Isolation: Multi-site management / Admin assignment
|
||||
- Page Management: Provide page title / Easy to look up
|
||||
- Image Upload: Upload to localhost / various remote image host
|
||||
- Private Space Mode: Only visible to yourself / Message board
|
||||
- Multiple Msg Pushers: Support Telegram / Slack / LINE
|
||||
- Nested Comments: Switchable to Flat Mode
|
||||
- Comment Vote: For or against comments
|
||||
- Comment Sort: Sort by popularity or time
|
||||
- Comment PIN: Pin important comments
|
||||
- Track only author: Show only author's comments
|
||||
- Asynchronous: Send comments without waiting
|
||||
- Infinite Scrolling: Provide various comment content pagination custom
|
||||
- AutoSave: A anti-lost editor
|
||||
- AutoFill: Autofill user profile
|
||||
- Preview: Real-time preview of markdown
|
||||
- Dark Mode: Prevents eye disease damage
|
||||
- Collapse Comment: I do not want you to see this comment
|
||||
- Data Backup: Prevent comment data loss
|
||||
- Data Migration: Switch back and forth between different commenting systems
|
||||
- Multiple comments on one page: Multiple comment areas on one page (seems useless
|
||||
- Markdown: Markdown syntax was supported by default
|
||||
- LaTex support: Import KaTex plugin to integrate LaTex parser for artalk
|
||||
- Using [Vite](https://github.com/vitejs/vite): The ultimate developer experience
|
||||
<!-- prettier-ignore-start -->
|
||||
|
||||
## Getting Started
|
||||
<!-- features -->
|
||||
* [Sidebar](https://artalk.js.org/guide/frontend/sidebar.html): Quick management, intuitive browsing
|
||||
* [Social Login](https://artalk.js.org/guide/frontend/auth.html): Quick login via social accounts
|
||||
* [Email Notification](https://artalk.js.org/guide/backend/email.html): Multiple sending methods, email templates
|
||||
* [Multi-channel Push](https://artalk.js.org/guide/backend/admin_notify.html): Multiple push methods, notification templates
|
||||
* [In-site Notifications](https://artalk.js.org/guide/frontend/sidebar.html): Red dot marking, mention list
|
||||
* [CAPTCHA](https://artalk.js.org/guide/backend/captcha.html): Multiple verification types, frequency limitation
|
||||
* [Comment Moderation](https://artalk.js.org/guide/backend/moderator.html): Content detection, spam interception
|
||||
* [Image Upload](https://artalk.js.org/guide/backend/img-upload.html): Custom upload, support for image hosting
|
||||
* [Markdown](https://artalk.js.org/guide/intro.html): Support Markdown syntax
|
||||
* [Emoticons](https://artalk.js.org/guide/frontend/emoticons.html): Compatible with OwO, quick integration
|
||||
* [Multi-site](https://artalk.js.org/guide/backend/multi-site.html): Site isolation, centralized management
|
||||
* [Admin](https://artalk.js.org/guide/backend/multi-site.html): Password verification, badge identification
|
||||
* [Page Management](https://artalk.js.org/guide/frontend/sidebar.html): Quick view, one-click title jump
|
||||
* [Page Views Statistics](https://artalk.js.org/guide/frontend/pv.html): Easily track page views
|
||||
* [Hierarchy](https://artalk.js.org/guide/frontend/config.html#nestmax): Nested paginated lists, scroll loading
|
||||
* [Comment Voting](https://artalk.js.org/guide/frontend/config.html#vote): Upvote or downvote comments
|
||||
* [Comment Sorting](https://artalk.js.org/guide/frontend/config.html#listsort): Multiple sorting options, freedom to choose
|
||||
* [Comment Search](https://artalk.js.org/guide/frontend/sidebar.html): Quickly search comment content
|
||||
* [Comment Pinning](https://artalk.js.org/guide/frontend/sidebar.html): Pin important messages
|
||||
* [Author-only View](https://artalk.js.org/guide/frontend/config.html): Show only comments from the author
|
||||
* [Comment Jumping](https://artalk.js.org/guide/intro.html): Quickly jump to referenced comments
|
||||
* [Auto Save](https://artalk.js.org/guide/frontend/config.html): Content input auto-saving
|
||||
* [IP Geolocation](https://artalk.js.org/guide/frontend/ip-region.html): User IP location display
|
||||
* [Data Migration](https://artalk.js.org/guide/transfer.html): Free migration, quick backup
|
||||
* [Image Lightbox](https://artalk.js.org/guide/frontend/lightbox.html): Quickly integrate image lightbox
|
||||
* [Image Lazy Loading](https://artalk.js.org/guide/frontend/img-lazy-load.html): Delay loading images, optimize experience
|
||||
* [Latex](https://artalk.js.org/guide/frontend/latex.html): Latex formula parsing integration
|
||||
* [Dark Mode](https://artalk.js.org/guide/frontend/config.html#darkmode): Dark mode switching
|
||||
* [Extension Plugins](https://artalk.js.org/develop/): Create more possibilities
|
||||
* [Multi-language](https://artalk.js.org/guide/frontend/i18n.html): Multi-language switching
|
||||
* [Command Line](https://artalk.js.org/guide/backend/config.html): Command line operation management capability
|
||||
* [API Documentation](https://artalk.js.org/develop/): Provides OpenAPI format documentation
|
||||
* [Program Upgrade](https://artalk.js.org/guide/backend/update.html): Version detection, one-click upgrade
|
||||
<!-- /features -->
|
||||
|
||||
Reference to:[**Documentation**](https://artalk.js.org/guide/deploy.html)
|
||||
<!-- prettier-ignore-end -->
|
||||
|
||||
```sh
|
||||
$ pnpm add artalk
|
||||
## Installation
|
||||
|
||||
Deploy via Docker with one click:
|
||||
|
||||
```bash
|
||||
docker run -d \
|
||||
--name artalk \
|
||||
-p 8080:23366 \
|
||||
-v $(pwd)/data:/data \
|
||||
-e "TZ=America/New_York" \
|
||||
-e "ATK_LOCALE=en" \
|
||||
-e "ATK_SITE_DEFAULT=Artalk Blog" \
|
||||
-e "ATK_SITE_URL=https://example.com" \
|
||||
artalk/artalk-go
|
||||
```
|
||||
|
||||
```ts
|
||||
import Artalk from 'artalk'
|
||||
Integrate Artalk into your webpage:
|
||||
|
||||
<!-- prettier-ignore-start -->
|
||||
|
||||
```ts
|
||||
Artalk.init({
|
||||
el: '#Comments',
|
||||
pageKey: 'http://your_domain/post/1', // Page Link
|
||||
pageTitle: 'The title of your page', // Page Title
|
||||
server: 'http://localhost:8080/api', // Server URL
|
||||
site: 'Site Name',
|
||||
locale: 'en'
|
||||
el: '#Comments',
|
||||
site: 'Artalk Blog',
|
||||
server: 'https://artalk.example.com',
|
||||
pageKey: '/2018/10/02/hello-world.html'
|
||||
})
|
||||
```
|
||||
|
||||
### Docker
|
||||
<!-- prettier-ignore-end -->
|
||||
|
||||
```sh
|
||||
docker run -d \
|
||||
--name artalk \
|
||||
-p 8080:23366 \
|
||||
-v $(pwd)/data:/data \
|
||||
artalk/artalk-go
|
||||
```
|
||||
[**Learn More →**](https://artalk.js.org/guide/deploy.html)
|
||||
|
||||
### Docker Compose
|
||||
## For Developers
|
||||
|
||||
```sh
|
||||
mkdir Artalk
|
||||
cd Artalk
|
||||
Pull requests are welcome!
|
||||
|
||||
vim docker-compose.yaml
|
||||
```
|
||||
|
||||
```yaml
|
||||
version: "3.5"
|
||||
services:
|
||||
artalk:
|
||||
container_name: artalk
|
||||
image: artalk/artalk-go
|
||||
ports:
|
||||
- 8080:23366
|
||||
volumes:
|
||||
- ./data:/data
|
||||
```
|
||||
|
||||
```sh
|
||||
docker-compose up -d
|
||||
```
|
||||
|
||||
## Development
|
||||
|
||||
see [CONTRIBUTING.md](./CONTRIBUTING.md)
|
||||
See [Development](https://artalk.js.org/develop/) and [Contributing](./CONTRIBUTING.md) for information on working with the codebase, getting a local development setup, and contributing changes.
|
||||
|
||||
## Contributors
|
||||
|
||||
Your contributions enrich the open-source community, fostering learning, inspiration, and innovation. We deeply value your involvement. Thank you for being a vital part of our community! 🥰
|
||||
|
||||
[](https://github.com/ArtalkJS/Artalk/graphs/contributors)
|
||||
|
||||
## Supporters
|
||||
|
||||
[](https://github.com/ArtalkJS/Artalk/stargazers)
|
||||
|
||||
## Feedback
|
||||
## Repobeats Analytics
|
||||
|
||||
Thanks for the help and feedback provided by the community, if you have good suggestions or comments, please go to [issues](https://github.com/ArtalkJS/Artalk/issues) to let us know at any time.
|
||||

|
||||
|
||||
## Stargazers over time
|
||||
|
||||
@@ -131,7 +122,7 @@ Thanks for the help and feedback provided by the community, if you have good sug
|
||||
|
||||
## License
|
||||
|
||||
[LGPL-3.0](./LICENSE)
|
||||
[MIT](./LICENSE)
|
||||
|
||||
[](https://app.fossa.com/projects/git%2Bgithub.com%2FArtalkJS%2FArtalk?ref=badge_shield)
|
||||
|
||||
|
||||
@@ -4,107 +4,108 @@
|
||||
|
||||
# Artalk
|
||||
|
||||
[](https://www.npmjs.com/package/artalk)
|
||||
[](https://www.npmjs.com/package/artalk)
|
||||
[](https://bundlephobia.com/package/artalk)
|
||||
[](https://www.npmjs.com/package/artalk)
|
||||
[](https://www.npmjs.com/package/artalk)
|
||||
[](https://hub.docker.com/r/artalk/artalk-go)
|
||||
[](https://circleci.com/gh/ArtalkJS/Artalk/tree/master)
|
||||
[](https://goreportcard.com/report/github.com/ArtalkJS/Artalk)
|
||||
[](https://circleci.com/gh/ArtalkJS/Artalk/tree/master)
|
||||
[](https://codecov.io/gh/ArtalkJS/Artalk)
|
||||
[](https://bundlephobia.com/package/artalk)
|
||||
|
||||
> 🌌 Golang 自托管评论系统
|
||||
[English](./README.en.md) • [官方网站](https://artalk.js.org) • [最新版本](https://github.com/ArtalkJS/Artalk/releases) • [更新日志](https://github.com/ArtalkJS/Artalk/blob/master/CHANGELOG.md)
|
||||
|
||||
[English](./README.en.md) / [官方文档](https://artalk.js.org) / [最新版本](https://github.com/ArtalkJS/Artalk/releases)
|
||||
Artalk 是一款简单易用但功能丰富的评论系统,你可以开箱即用地部署并置入任何博客、网站、Web 应用。
|
||||
|
||||
---
|
||||
|
||||
- 🍃 轻量 (~30kB)
|
||||
- 👨👧👦 安全 (自托管)
|
||||
- 🐳 易上手 (防脱发)
|
||||
- 🍱 Golang 后端 (快速 / 跨平台)
|
||||
- 🌊 Vanilla × TypeScript × Vite (纯天然 / 无依赖)
|
||||
- 🍃 前端 ~40KB,纯天然 Vanilla JS
|
||||
- 🍱 后端 Golang,高效轻量跨平台
|
||||
- 🐳 通过 Docker 一键部署,方便快捷
|
||||
- 🌈 开源程序,自托管,隐私至上
|
||||
|
||||
## 特性
|
||||
|
||||
- 侧 边 栏 :支持多站点集中化管理
|
||||
- 通知中心:红点的标记 / 提及列表
|
||||
- 身份验证:徽标自定义 / 密码验证
|
||||
- 评论审核:反垃圾检测 / 频率限制
|
||||
- 表情符号:插入表情包 / 快速导入
|
||||
- 邮件提醒:模版自定义 / 多管理员
|
||||
- 站点隔离:管理员分配 / 多个站点
|
||||
- 页面管理:标题可显示 / 快速跳转
|
||||
- 图片上传:上传到本地 / 多种图床
|
||||
- 多元推送:支持 钉钉 飞书 TG
|
||||
- 无限层级:可切换为平铺模式
|
||||
- 评论投票:赞同还是反对评论
|
||||
- 评论排序:按热度或时间排序
|
||||
- 评论置顶:重要消息置顶显示
|
||||
- 只看作者:仅显示作者的评论
|
||||
- 说说模式:仅自己可发布评论
|
||||
- 异步处理:发送评论无需等待
|
||||
- 滚动加载:评论内容分页处置
|
||||
- 自动保存:用户输入防丢功能
|
||||
- 自动填充:用户链接自动填充
|
||||
- 实时预览:评论内容实时预览
|
||||
- 夜间模式:防止眼部疾病伤害
|
||||
- 评论折叠:这个不打算给你康
|
||||
- 数据备份:防止评论数据丢失
|
||||
- 数据迁移:快速切换评论系统
|
||||
- Markdown:默认支持 MD 语法
|
||||
- 支持 Latex:提供集成 Katex 插件
|
||||
- 使用 [Vite](https://github.com/vitejs/vite):属于开发者的极致体验
|
||||
<!-- prettier-ignore-start -->
|
||||
|
||||
更多内容请查看:[“**介绍文档**”](https://artalk.js.org/guide/intro.html)
|
||||
<!-- features -->
|
||||
* [侧边栏](https://artalk.js.org/guide/frontend/sidebar.html): 快速管理、直观浏览
|
||||
* [社交登录](https://artalk.js.org/guide/frontend/auth.html): 通过社交账号快速登录
|
||||
* [邮件通知](https://artalk.js.org/guide/backend/email.html): 多种发送方式、邮件模板
|
||||
* [多元推送](https://artalk.js.org/guide/backend/admin_notify.html): 多种推送方式、通知模版
|
||||
* [站内通知](https://artalk.js.org/guide/frontend/sidebar.html): 红点标记、提及列表
|
||||
* [验证码](https://artalk.js.org/guide/backend/captcha.html): 多种验证类型、频率限制
|
||||
* [评论审核](https://artalk.js.org/guide/backend/moderator.html): 内容检测、垃圾拦截
|
||||
* [图片上传](https://artalk.js.org/guide/backend/img-upload.html): 自定义上传、支持图床
|
||||
* [Markdown](https://artalk.js.org/guide/intro.html): 支持 Markdown 语法
|
||||
* [表情包](https://artalk.js.org/guide/frontend/emoticons.html): 兼容 OwO,快速集成
|
||||
* [多站点](https://artalk.js.org/guide/backend/multi-site.html): 站点隔离、集中管理
|
||||
* [管理员](https://artalk.js.org/guide/backend/multi-site.html): 密码验证、徽章标识
|
||||
* [页面管理](https://artalk.js.org/guide/frontend/sidebar.html): 快速查看、标题一键跳转
|
||||
* [浏览量统计](https://artalk.js.org/guide/frontend/pv.html): 轻松统计网页浏览量
|
||||
* [层级结构](https://artalk.js.org/guide/frontend/config.html#nestmax): 嵌套分页列表、滚动加载
|
||||
* [评论投票](https://artalk.js.org/guide/frontend/config.html#vote): 赞同或反对评论
|
||||
* [评论排序](https://artalk.js.org/guide/frontend/config.html#listsort): 多种排序方式,自由选择
|
||||
* [评论搜索](https://artalk.js.org/guide/frontend/sidebar.html): 快速搜索评论内容
|
||||
* [评论置顶](https://artalk.js.org/guide/frontend/sidebar.html): 重要消息置顶显示
|
||||
* [仅看作者](https://artalk.js.org/guide/frontend/config.html): 仅显示作者的评论
|
||||
* [评论跳转](https://artalk.js.org/guide/intro.html): 快速跳转到引用的评论
|
||||
* [自动保存](https://artalk.js.org/guide/frontend/config.html): 输入内容防丢功能
|
||||
* [IP 属地](https://artalk.js.org/guide/frontend/ip-region.html): 用户 IP 属地展示
|
||||
* [数据迁移](https://artalk.js.org/guide/transfer.html): 自由迁移、快速备份
|
||||
* [图片灯箱](https://artalk.js.org/guide/frontend/lightbox.html): 图片灯箱快速集成
|
||||
* [图片懒加载](https://artalk.js.org/guide/frontend/img-lazy-load.html): 延迟加载图片,优化体验
|
||||
* [Latex](https://artalk.js.org/guide/frontend/latex.html): Latex 公式解析集成
|
||||
* [夜间模式](https://artalk.js.org/guide/frontend/config.html#darkmode): 夜间模式切换
|
||||
* [扩展插件](https://artalk.js.org/develop/): 创造更多可能性
|
||||
* [多语言](https://artalk.js.org/guide/frontend/i18n.html): 多国语言切换
|
||||
* [命令行](https://artalk.js.org/guide/backend/config.html): 命令行操作管理能力
|
||||
* [API 文档](https://artalk.js.org/develop/): 提供 OpenAPI 格式文档
|
||||
* [程序升级](https://artalk.js.org/guide/backend/update.html): 版本检测,一键升级
|
||||
<!-- /features -->
|
||||
|
||||
## 食用方针
|
||||
<!-- prettier-ignore-end -->
|
||||
|
||||
前往:[“**部署文档**”](https://artalk.js.org/guide/deploy.html)
|
||||
## 安装
|
||||
|
||||
```ts
|
||||
Artalk.init({
|
||||
el: '#Comments',
|
||||
site: 'Artalk 的博客',
|
||||
server: 'https://artalk.example.com'
|
||||
})
|
||||
```
|
||||
|
||||
### Docker
|
||||
通过 Docker 一键部署:
|
||||
|
||||
```bash
|
||||
docker run -d \
|
||||
--name artalk \
|
||||
-p 8080:23366 \
|
||||
-v $(pwd)/data:/data \
|
||||
artalk/artalk-go
|
||||
--name artalk \
|
||||
-p 8080:23366 \
|
||||
-v $(pwd)/data:/data \
|
||||
-e "TZ=Asia/Shanghai" \
|
||||
-e "ATK_LOCALE=zh-CN" \
|
||||
-e "ATK_SITE_DEFAULT=Artalk 的博客" \
|
||||
-e "ATK_SITE_URL=https://example.com" \
|
||||
artalk/artalk-go
|
||||
```
|
||||
|
||||
### Docker Compose
|
||||
在网页中引入 Artalk:
|
||||
|
||||
```bash
|
||||
vim docker-compose.yaml
|
||||
<!-- prettier-ignore-start -->
|
||||
|
||||
```ts
|
||||
Artalk.init({
|
||||
el: '#Comments',
|
||||
site: 'Artalk 的博客',
|
||||
server: 'https://artalk.example.com',
|
||||
pageKey: '/2018/10/02/hello-world.html'
|
||||
})
|
||||
```
|
||||
|
||||
```yaml
|
||||
version: "3.5"
|
||||
services:
|
||||
artalk:
|
||||
container_name: artalk
|
||||
image: artalk/artalk-go
|
||||
ports:
|
||||
- 8080:23366
|
||||
volumes:
|
||||
- ./data:/data
|
||||
```
|
||||
<!-- prettier-ignore-end -->
|
||||
|
||||
```bash
|
||||
docker-compose up -d
|
||||
```
|
||||
[**了解更多 →**](https://artalk.js.org/guide/deploy.html)
|
||||
|
||||
## Development
|
||||
## For Developers
|
||||
|
||||
see [CONTRIBUTING.md](./CONTRIBUTING.md)
|
||||
Pull requests are welcome!
|
||||
|
||||
See [Development](https://artalk.js.org/develop/) and [Contributing](./CONTRIBUTING.md) for information on working with the codebase, getting a local development setup, and contributing changes.
|
||||
|
||||
## Contributors
|
||||
|
||||
Your contributions enrich the open-source community, fostering learning, inspiration, and innovation. We deeply value your involvement. Thank you for being a vital part of our community! 🥰
|
||||
|
||||
[](https://github.com/ArtalkJS/Artalk/graphs/contributors)
|
||||
|
||||
## Supporters
|
||||
@@ -113,105 +114,7 @@ see [CONTRIBUTING.md](./CONTRIBUTING.md)
|
||||
|
||||
## Repobeats Analytics
|
||||
|
||||

|
||||
|
||||
## 特别致谢
|
||||
|
||||
感谢社区提供的帮助与反馈,若有好的建议与意见欢迎前往 [ISSUES](https://github.com/ArtalkJS/Artalk/issues) 随时告知。
|
||||
|
||||
## TODOs
|
||||
|
||||
- [x] Golang 后端
|
||||
- [x] 多数据库支持
|
||||
- [x] SQLite
|
||||
- [x] MySQL
|
||||
- [x] Postgres
|
||||
- [x] SQLServer
|
||||
- [x] 多缓存数据库支持
|
||||
- [x] In-memory (内建缓存)
|
||||
- [x] Redis
|
||||
- [x] Memcache
|
||||
- [x] 多站点支持
|
||||
- [x] 评论获取分页
|
||||
- [x] 评论点赞投票
|
||||
- [x] 浏览量统计
|
||||
- [x] 评论分页加载
|
||||
- [x] 评论置顶 / 精华
|
||||
- [x] 评论排序 (热度 / 时间)
|
||||
- [x] 通知中心
|
||||
- [x] 提及
|
||||
- [x] 全部
|
||||
- [x] 我的
|
||||
- [x] 待审
|
||||
- [x] 管理员控制台
|
||||
- [x] 评论
|
||||
- [x] 页面
|
||||
- [x] 站点
|
||||
- [x] 用户
|
||||
- [x] 设置 (GUI)
|
||||
- [x] 数据导入 ([Artransfer](https://artalk.js.org/guide/transfer.html))
|
||||
- [x] Artrans
|
||||
- [x] WordPress
|
||||
- [x] Typecho ([插件](https://github.com/ArtalkJS/Artrans-Typecho) / [Artransfer-CLI](https://github.com/ArtalkJS/Artransfer-CLI))
|
||||
- [x] Valine
|
||||
- [x] Disqus
|
||||
- [x] Commento
|
||||
- [x] Waline ([Artransfer-CLI](https://github.com/ArtalkJS/Artransfer-CLI))
|
||||
- [x] Twikoo
|
||||
- [x] Artalk v1 (PHP)
|
||||
- [x] 数据导出
|
||||
- [x] 邮件多种发送方式
|
||||
- [x] SMTP
|
||||
- [x] 阿里云邮件
|
||||
- [x] 系统调用 sendmail
|
||||
- [x] 邮件多模板自定义
|
||||
- [x] 邮件异步队列发送
|
||||
- [ ] 队列持久化
|
||||
- [x] 用户已读标记
|
||||
- [x] 验证码
|
||||
- [x] 图片验证码
|
||||
- [x] [Turnstile](https://www.cloudflare.com/products/turnstile/)
|
||||
- [x] [ReCAPTCHA](https://www.google.com/recaptcha/about/)
|
||||
- [x] [hCaptcha](https://www.hcaptcha.com/)
|
||||
- [x] [极验](https://www.geetest.com/)滑动验证码
|
||||
- [x] 反垃圾
|
||||
- [x] [Akismet](https://akismet.com/)
|
||||
- [x] [阿里云内容安全](https://help.aliyun.com/document_detail/28417.html)
|
||||
- [x] [腾讯云内容安全](https://cloud.tencent.com/document/product/1124/64508)
|
||||
- [x] 关键字过滤
|
||||
- [x] 评论通知管理员 ([notify](https://github.com/nikoksr/notify))
|
||||
- [x] Telegram Bot
|
||||
- [x] 飞书 WebHook Bot
|
||||
- [x] 钉钉
|
||||
- [x] Bark
|
||||
- [x] Slack
|
||||
- [x] LINE
|
||||
- [x] 自定义 HTTP 回调
|
||||
- [ ] 命令行管理
|
||||
- [ ] 博客邮件订阅
|
||||
- [x] 用户鉴权机制
|
||||
- [x] 跨域非法请求阻止
|
||||
- [x] 全局验证码操作次数限制
|
||||
- [x] JWT 登陆状态验证
|
||||
- [x] 时区自定义
|
||||
- [x] 只看作者功能
|
||||
- [x] 图片上传
|
||||
- [x] 图片上传到图床 ([upgit](https://github.com/pluveto/upgit))
|
||||
- [ ] 图片管理
|
||||
- [ ] 附件上传 / 管理
|
||||
- [ ] 表情包统一管理
|
||||
- [ ] 导入表情包
|
||||
- [ ] 表情包图片地址控制
|
||||
- [ ] AT 提及 (@)
|
||||
- [ ] 评论话题 (#)
|
||||
- [ ] 评论标签分类系统
|
||||
- [ ] 主题样式更换
|
||||
- [ ] 规范化 API
|
||||
- [ ] 扩展中心
|
||||
- [ ] 开放用户注册
|
||||
- [ ] 第三方登录接入
|
||||
- [x] 多语言 / 国际化 (i18n)
|
||||
- [x] 一键升级
|
||||

|
||||
|
||||
## Stargazers over time
|
||||
|
||||
@@ -219,7 +122,7 @@ see [CONTRIBUTING.md](./CONTRIBUTING.md)
|
||||
|
||||
## License
|
||||
|
||||
[LGPL-3.0](./LICENSE)
|
||||
[MIT](./LICENSE)
|
||||
|
||||
[](https://app.fossa.com/projects/git%2Bgithub.com%2FArtalkJS%2FArtalk?ref=badge_shield)
|
||||
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
# Reporting Security Issues
|
||||
|
||||
The features of Artalk are continuously being improved, and we are also striving to enhance security. However, potential issues may still exist. If you discover any security vulnerabilities in Artalk, please promptly contact us via [GitHub Issues](https://github.com/ArtalkJS/Artalk/issues) or email at artalkjs@gmail.com. We will make every effort to address the issue as quickly as possible. Thank you for your support!
|
||||
+17
-5
@@ -7,7 +7,6 @@ import (
|
||||
"strings"
|
||||
"syscall"
|
||||
|
||||
"github.com/ArtalkJS/Artalk/internal/core"
|
||||
"github.com/ArtalkJS/Artalk/internal/entity"
|
||||
"github.com/ArtalkJS/Artalk/internal/i18n"
|
||||
"github.com/ArtalkJS/Artalk/internal/log"
|
||||
@@ -16,7 +15,7 @@ import (
|
||||
"golang.org/x/term"
|
||||
)
|
||||
|
||||
func NewAdminCommand(app *core.App) *cobra.Command {
|
||||
func NewAdminCommand(app *ArtalkCmd) *cobra.Command {
|
||||
adminCmd := &cobra.Command{
|
||||
Use: "admin",
|
||||
Short: "Create or edit an administrator account",
|
||||
@@ -26,14 +25,23 @@ func NewAdminCommand(app *core.App) *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)
|
||||
}
|
||||
@@ -63,6 +71,10 @@ func NewAdminCommand(app *core.App) *cobra.Command {
|
||||
},
|
||||
}
|
||||
|
||||
flag(adminCmd, "name", "", i18n.T("Username"))
|
||||
flag(adminCmd, "email", "", i18n.T("Email"))
|
||||
flag(adminCmd, "password", "", i18n.T("Password"))
|
||||
|
||||
return adminCmd
|
||||
}
|
||||
|
||||
|
||||
+36
-27
@@ -26,7 +26,7 @@ var Banner = `
|
||||
|
||||
Artalk (` + Version + `)
|
||||
|
||||
-> A Selfhosted Comment System.
|
||||
-> A Self-hosted Comment System.
|
||||
-> https://artalk.js.org
|
||||
`
|
||||
|
||||
@@ -50,7 +50,7 @@ func New() *ArtalkCmd {
|
||||
cmd := &ArtalkCmd{
|
||||
RootCmd: &cobra.Command{
|
||||
Use: "artalk",
|
||||
Short: "Artalk: Your self-hosted comment system",
|
||||
Short: "Artalk: A self-hosted comment system",
|
||||
Long: Banner,
|
||||
Version: Version,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
@@ -62,23 +62,17 @@ func New() *ArtalkCmd {
|
||||
}
|
||||
|
||||
cmd.RootCmd.SetVersionTemplate("Artalk ({{printf \"%s\" .Version}})\n")
|
||||
cmd.eagerParseFlags() // parse base flags
|
||||
|
||||
// 切换工作目录
|
||||
// Parse base flags
|
||||
cmd.eagerParseFlags()
|
||||
|
||||
// Change work directory
|
||||
if cmd.workDir != "" {
|
||||
if err := os.Chdir(cmd.workDir); err != nil {
|
||||
log.Fatal("Working directory change error: ", err)
|
||||
}
|
||||
}
|
||||
|
||||
// initialize app instance
|
||||
config, err := getConfig(cmd.cfgFile)
|
||||
if err != nil {
|
||||
log.Fatal("Config fail: ", err)
|
||||
}
|
||||
|
||||
cmd.App = core.NewApp(config)
|
||||
|
||||
return cmd
|
||||
}
|
||||
|
||||
@@ -99,7 +93,17 @@ func (atk *ArtalkCmd) addCommand(cmd *cobra.Command) {
|
||||
// APP Bootstrap
|
||||
// ================
|
||||
if cmd.Annotations[BootModeKey] != string(MODE_MINI_BOOT) {
|
||||
if err := atk.Bootstrap(); err != nil {
|
||||
// Load config
|
||||
config, err := getConfig(atk.cfgFile)
|
||||
if err != nil {
|
||||
log.Fatal("Config fail: ", err)
|
||||
}
|
||||
|
||||
// Create new instance
|
||||
atk.App = core.NewApp(config)
|
||||
|
||||
// Bootstrap APP
|
||||
if err := atk.App.Bootstrap(); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
@@ -113,14 +117,14 @@ func (atk *ArtalkCmd) addCommand(cmd *cobra.Command) {
|
||||
}
|
||||
|
||||
func (atk *ArtalkCmd) mountCommands() {
|
||||
atk.addCommand(NewServeCommand(atk.App))
|
||||
atk.addCommand(NewAdminCommand(atk.App))
|
||||
atk.addCommand(NewExportCommand(atk.App))
|
||||
atk.addCommand(NewImportCommand(atk.App))
|
||||
atk.addCommand(NewConfigCommand(atk.App))
|
||||
atk.addCommand(NewGenCommand(atk.App))
|
||||
atk.addCommand(NewUpgradeCommand(atk.App))
|
||||
atk.addCommand(NewVersionCommand(atk.App))
|
||||
atk.addCommand(NewServeCommand(atk))
|
||||
atk.addCommand(NewAdminCommand(atk))
|
||||
atk.addCommand(NewExportCommand(atk))
|
||||
atk.addCommand(NewImportCommand(atk))
|
||||
atk.addCommand(NewConfigCommand())
|
||||
atk.addCommand(NewGenCommand())
|
||||
atk.addCommand(NewUpgradeCommand())
|
||||
atk.addCommand(NewVersionCommand())
|
||||
}
|
||||
|
||||
func (atk *ArtalkCmd) Launch() error {
|
||||
@@ -156,24 +160,29 @@ func (atk *ArtalkCmd) Launch() error {
|
||||
// ===================
|
||||
// 3. App Cleanups
|
||||
// ===================
|
||||
return atk.OnTerminate().Trigger(&core.TerminateEvent{
|
||||
App: atk.App,
|
||||
})
|
||||
if atk.App != nil {
|
||||
return atk.App.OnTerminate().Trigger(&core.TerminateEvent{
|
||||
App: atk.App,
|
||||
})
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// 获取配置
|
||||
// Create new config instance by specific config filename
|
||||
func getConfig(cfgFile string) (*config.Config, error) {
|
||||
// 尝试查找配置文件
|
||||
// Retrieve config file by default names when specific filename is empty
|
||||
if cfgFile == "" {
|
||||
cfgFile = config.RetrieveConfigFile()
|
||||
}
|
||||
|
||||
// 自动生成新配置文件
|
||||
// Generate new config file when retrieve failed
|
||||
if cfgFile == "" {
|
||||
cfgFile = config.CONF_DEFAULT_FILENAMES[0]
|
||||
core.Gen("config", cfgFile, false)
|
||||
}
|
||||
|
||||
// Create new config instance and return
|
||||
return config.NewFromFile(cfgFile)
|
||||
}
|
||||
|
||||
|
||||
+13
-3
@@ -4,16 +4,26 @@ import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
|
||||
"github.com/ArtalkJS/Artalk/internal/core"
|
||||
"github.com/ArtalkJS/Artalk/internal/log"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
func NewConfigCommand(app *core.App) *cobra.Command {
|
||||
func NewConfigCommand() *cobra.Command {
|
||||
configCmd := &cobra.Command{
|
||||
Use: "config",
|
||||
Short: "Output Config Information",
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
buf, _ := json.MarshalIndent(app.Conf(), "", " ")
|
||||
// Get config filename from cmd flags
|
||||
filename, _ := cmd.Flags().GetString("config")
|
||||
|
||||
// Get new config instance
|
||||
config, err := getConfig(filename)
|
||||
if err != nil {
|
||||
log.Fatal("Config fail: ", err)
|
||||
}
|
||||
|
||||
// Output JSON of config
|
||||
buf, _ := json.MarshalIndent(config, "", " ")
|
||||
fmt.Println(string(buf))
|
||||
},
|
||||
Annotations: map[string]string{
|
||||
|
||||
+1
-2
@@ -8,14 +8,13 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/ArtalkJS/Artalk/internal/artransfer"
|
||||
"github.com/ArtalkJS/Artalk/internal/core"
|
||||
"github.com/ArtalkJS/Artalk/internal/i18n"
|
||||
"github.com/ArtalkJS/Artalk/internal/log"
|
||||
"github.com/ArtalkJS/Artalk/internal/utils"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
func NewExportCommand(app *core.App) *cobra.Command {
|
||||
func NewExportCommand(app *ArtalkCmd) *cobra.Command {
|
||||
exportCmd := &cobra.Command{
|
||||
Use: "export",
|
||||
Aliases: []string{},
|
||||
|
||||
+1
-8
@@ -5,20 +5,13 @@ import (
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
func NewGenCommand(app *core.App) *cobra.Command {
|
||||
func NewGenCommand() *cobra.Command {
|
||||
genCmd := &cobra.Command{
|
||||
Use: "gen <TYPE> <DEST>",
|
||||
Short: "A collection of several useful generators",
|
||||
Long: "Generate some content\ne.g. `artalk gen config ./artalk.yml`",
|
||||
Args: cobra.RangeArgs(1, 2),
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
// change working directory
|
||||
// if workDir != "" {
|
||||
// if err := os.Chdir(workDir); err != nil {
|
||||
// log.Fatal("change working directory error ", err)
|
||||
// }
|
||||
// }
|
||||
|
||||
var (
|
||||
specificPath string
|
||||
isForce bool
|
||||
|
||||
+31
-13
@@ -1,42 +1,60 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"os"
|
||||
|
||||
"github.com/ArtalkJS/Artalk/internal/artransfer"
|
||||
"github.com/ArtalkJS/Artalk/internal/core"
|
||||
"github.com/ArtalkJS/Artalk/internal/i18n"
|
||||
"github.com/ArtalkJS/Artalk/internal/log"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
func NewImportCommand(app *core.App) *cobra.Command {
|
||||
func NewImportCommand(app *ArtalkCmd) *cobra.Command {
|
||||
importCmd := &cobra.Command{
|
||||
Use: "import <FILENAME>",
|
||||
Aliases: []string{},
|
||||
Short: "Artransfer import",
|
||||
Long: "\n# Artransfer - Import\n\n See the documentation to learn more: https://artalk.js.org/guide/transfer.html",
|
||||
Args: cobra.MinimumNArgs(1),
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
parcelFile := args[0]
|
||||
if _, err := os.Stat(parcelFile); errors.Is(err, os.ErrNotExist) {
|
||||
log.Fatal(i18n.T("{{name}} not found", map[string]interface{}{"name": i18n.T("File")}))
|
||||
// Prepare params
|
||||
params := &artransfer.ImportParams{}
|
||||
|
||||
// Parse JSON parameters from flags
|
||||
if jsonParams, _ := cmd.Flags().GetString("parameters"); jsonParams != "" {
|
||||
if err := json.Unmarshal([]byte(jsonParams), params); err != nil {
|
||||
log.Fatal("Failed to parse JSON parameters: ", err)
|
||||
}
|
||||
}
|
||||
|
||||
payload := args[1:]
|
||||
payload = append(payload, "json_file:"+parcelFile)
|
||||
// If JSON file or JSON data is not provided in flags, try to get it from arguments
|
||||
if params.JsonFile == "" && params.JsonData == "" {
|
||||
if len(args) == 0 {
|
||||
log.Fatal(i18n.T("{{name}} is required", map[string]interface{}{"name": "FILENAME"}))
|
||||
}
|
||||
params.JsonFile = args[0]
|
||||
}
|
||||
|
||||
// import Artrans
|
||||
params := artransfer.ArrToImportParams(payload)
|
||||
params.Assumeyes, _ = cmd.Flags().GetBool("assumeyes")
|
||||
// Parse flags to params
|
||||
if flagAssumeyes, err := cmd.Flags().GetBool("assumeyes"); err == nil {
|
||||
params.Assumeyes = flagAssumeyes
|
||||
}
|
||||
|
||||
// Check if file exists if JsonFile is provided
|
||||
if params.JsonFile != "" {
|
||||
if _, err := os.Stat(params.JsonFile); errors.Is(err, os.ErrNotExist) {
|
||||
log.Fatal(i18n.T("{{name}} not found", map[string]interface{}{"name": i18n.T("File")}))
|
||||
}
|
||||
}
|
||||
|
||||
// Run import
|
||||
artransfer.RunImportArtrans(app.Dao(), params)
|
||||
|
||||
log.Info(i18n.T("Import complete"))
|
||||
},
|
||||
}
|
||||
|
||||
flagPV(importCmd, "assumeyes", "y", false, "Automatically answer yes for all questions.")
|
||||
flagPV(importCmd, "parameters", "p", "", "JSON format parameters for the import command.")
|
||||
|
||||
return importCmd
|
||||
}
|
||||
+2
-3
@@ -3,14 +3,13 @@ package cmd
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/ArtalkJS/Artalk/internal/core"
|
||||
"github.com/ArtalkJS/Artalk/internal/log"
|
||||
"github.com/ArtalkJS/Artalk/server"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
func NewServeCommand(app *core.App) *cobra.Command {
|
||||
func NewServeCommand(app *ArtalkCmd) *cobra.Command {
|
||||
var serverCmd = &cobra.Command{
|
||||
Use: "server",
|
||||
Aliases: []string{"serve"},
|
||||
@@ -22,7 +21,7 @@ func NewServeCommand(app *core.App) *cobra.Command {
|
||||
fmt.Print("-------------------------------\n\n")
|
||||
|
||||
// init fiber app
|
||||
_, err := server.Serve(app)
|
||||
_, err := server.Serve(app.App)
|
||||
if err != nil {
|
||||
log.Fatalln(err)
|
||||
}
|
||||
|
||||
+9
-11
@@ -6,7 +6,6 @@ import (
|
||||
"strings"
|
||||
|
||||
"github.com/ArtalkJS/Artalk/internal/config"
|
||||
"github.com/ArtalkJS/Artalk/internal/core"
|
||||
"github.com/ArtalkJS/Artalk/internal/i18n"
|
||||
"github.com/ArtalkJS/Artalk/internal/log"
|
||||
"github.com/blang/semver"
|
||||
@@ -14,7 +13,7 @@ import (
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
func NewUpgradeCommand(app *core.App) *cobra.Command {
|
||||
func NewUpgradeCommand() *cobra.Command {
|
||||
upgradeCmd := &cobra.Command{
|
||||
Use: "upgrade",
|
||||
Aliases: []string{"update"},
|
||||
@@ -22,8 +21,6 @@ func NewUpgradeCommand(app *core.App) *cobra.Command {
|
||||
Long: "Upgrade Artalk to the latest version, \n update source is GitHub Releases, \n update need to restart Artalk to take effect.",
|
||||
Args: cobra.NoArgs,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
// core.LoadConfOnly(cfgFile, workDir)
|
||||
|
||||
log.Info(i18n.T("Checking for updates") + "...")
|
||||
|
||||
latest, found, err := selfupdate.DetectLatest("ArtalkJS/Artalk")
|
||||
@@ -35,7 +32,7 @@ func NewUpgradeCommand(app *core.App) *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
|
||||
}
|
||||
}
|
||||
@@ -52,12 +49,13 @@ func NewUpgradeCommand(app *core.App) *cobra.Command {
|
||||
log.Fatal(i18n.T("Update failed")+" ", err)
|
||||
}
|
||||
|
||||
log.Println(i18n.T("Update complete"))
|
||||
fmt.Println("\n-------------------------------\n v" +
|
||||
latest.Version.String() +
|
||||
" Release Note\n" +
|
||||
"-------------------------------\n\n" +
|
||||
latest.ReleaseNotes)
|
||||
log.Info(i18n.T("Update complete"))
|
||||
fmt.Printf("\n"+
|
||||
"-------------------------------\n"+
|
||||
" v%s Release Note\n"+
|
||||
"-------------------------------\n\n"+
|
||||
"%s\n",
|
||||
latest.Version.String(), latest.ReleaseNotes)
|
||||
},
|
||||
Annotations: map[string]string{
|
||||
BootModeKey: MODE_MINI_BOOT,
|
||||
|
||||
+1
-2
@@ -3,11 +3,10 @@ package cmd
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/ArtalkJS/Artalk/internal/core"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
func NewVersionCommand(app *core.App) *cobra.Command {
|
||||
func NewVersionCommand() *cobra.Command {
|
||||
versionCmd := &cobra.Command{
|
||||
Use: "version",
|
||||
Short: "Output version information",
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
ignore:
|
||||
- "docs/*"
|
||||
+130
-44
@@ -2,31 +2,37 @@ 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
|
||||
site_url: ""
|
||||
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
|
||||
@@ -35,7 +41,6 @@ ssl:
|
||||
enabled: false
|
||||
cert_path: ""
|
||||
key_path: ""
|
||||
admin_users:
|
||||
moderator:
|
||||
pending_default: false
|
||||
api_fail_block: false
|
||||
@@ -44,22 +49,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: []
|
||||
files:
|
||||
- ./data/keywords_1.txt
|
||||
file_sep: "\n"
|
||||
replac_to: "x"
|
||||
replace_to: x
|
||||
captcha:
|
||||
enabled: true
|
||||
always: false
|
||||
captcha_type: "image"
|
||||
captcha_type: image
|
||||
action_limit: 3
|
||||
action_reset: 60
|
||||
turnstile:
|
||||
@@ -74,32 +80,34 @@ captcha:
|
||||
geetest:
|
||||
captcha_id: ""
|
||||
captcha_key: ""
|
||||
email:
|
||||
enabled: false
|
||||
send_type: "smtp"
|
||||
send_name: "{{reply_nick}}"
|
||||
send_addr: "noreply@example.com"
|
||||
mail_tpl: "default"
|
||||
smtp:
|
||||
host: "smtp.qq.com"
|
||||
port: 587
|
||||
username: "example@qq.com"
|
||||
password: ""
|
||||
ali_dm:
|
||||
access_key_id: ""
|
||||
access_key_secret: ""
|
||||
account_name: "noreply@example.com"
|
||||
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_name: "{{reply_nick}}"
|
||||
send_addr: noreply@example.com
|
||||
mail_subject: "[{{site_name}}] You got a reply from @{{reply_nick}}"
|
||||
mail_tpl: default
|
||||
smtp:
|
||||
host: smtp.qq.com
|
||||
port: 587
|
||||
username: example@qq.com
|
||||
password: ""
|
||||
ali_dm:
|
||||
access_key_id: ""
|
||||
access_key_secret: ""
|
||||
account_name: noreply@example.com
|
||||
admin_notify:
|
||||
notify_tpl: "default"
|
||||
notify_tpl: default
|
||||
notify_pending: false
|
||||
noise_mode: false
|
||||
email:
|
||||
enabled: true
|
||||
@@ -112,10 +120,11 @@ admin_notify:
|
||||
- 7777777
|
||||
bark:
|
||||
enabled: false
|
||||
server: "http://day.app/xxxxxxx/"
|
||||
server: http://day.app/xxxxxxx/
|
||||
lark:
|
||||
enabled: false
|
||||
webhook_url: ""
|
||||
msg_type: "text"
|
||||
webhook:
|
||||
enabled: false
|
||||
url: ""
|
||||
@@ -135,25 +144,100 @@ admin_notify:
|
||||
receivers:
|
||||
- "USER_ID_1"
|
||||
- "GROUP_ID_1"
|
||||
auth:
|
||||
enabled: false
|
||||
anonymous: false
|
||||
callback: "http://localhost:23366/api/v2/auth/{provider}/callback"
|
||||
email:
|
||||
enabled: true
|
||||
verify_subject: "Your Code - {{code}}"
|
||||
verify_tpl: default
|
||||
github:
|
||||
enabled: false
|
||||
client_id: ""
|
||||
client_secret: ""
|
||||
gitlab:
|
||||
enabled: false
|
||||
client_id: ""
|
||||
client_secret: ""
|
||||
gitea:
|
||||
enabled: false
|
||||
client_id: ""
|
||||
client_secret: ""
|
||||
google:
|
||||
enabled: false
|
||||
client_id: ""
|
||||
client_secret: ""
|
||||
mastodon:
|
||||
enabled: false
|
||||
client_id: ""
|
||||
client_secret: ""
|
||||
twitter:
|
||||
enabled: false
|
||||
client_id: ""
|
||||
client_secret: ""
|
||||
facebook:
|
||||
enabled: false
|
||||
client_id: ""
|
||||
client_secret: ""
|
||||
discord:
|
||||
enabled: false
|
||||
client_id: ""
|
||||
client_secret: ""
|
||||
steam:
|
||||
enabled: false
|
||||
api_key: ""
|
||||
apple:
|
||||
enabled: false
|
||||
client_id: ""
|
||||
client_secret: ""
|
||||
microsoft:
|
||||
enabled: false
|
||||
client_id: ""
|
||||
client_secret: ""
|
||||
wechat:
|
||||
enabled: false
|
||||
client_id: ""
|
||||
client_secret: ""
|
||||
tiktok:
|
||||
enabled: false
|
||||
client_id: ""
|
||||
client_secret: ""
|
||||
slack:
|
||||
enabled: false
|
||||
client_id: ""
|
||||
client_secret: ""
|
||||
line:
|
||||
enabled: false
|
||||
client_id: ""
|
||||
client_secret: ""
|
||||
patreon:
|
||||
enabled: false
|
||||
client_id: ""
|
||||
client_secret: ""
|
||||
auth0:
|
||||
enabled: false
|
||||
client_id: ""
|
||||
client_secret: ""
|
||||
domain: ""
|
||||
frontend:
|
||||
placeholder: ""
|
||||
noComment: ""
|
||||
sendBtn: ""
|
||||
editorTravel: true
|
||||
emoticons: ""
|
||||
emoticons: https://cdn.jsdelivr.net/gh/ArtalkJS/Emoticons/grps/default.json
|
||||
vote: true
|
||||
voteDown: false
|
||||
uaBadge: true
|
||||
uaBadge: false
|
||||
listSort: true
|
||||
pvEl: "#ArtalkPV"
|
||||
countEl: "#ArtalkCount"
|
||||
preview: true
|
||||
flatMode: "auto"
|
||||
flatMode: auto
|
||||
darkMode: inherit
|
||||
nestMax: 2
|
||||
nestSort: DATE_ASC
|
||||
gravatar:
|
||||
mirror: "https://www.gravatar.com/"
|
||||
params: "d=mp&s=240"
|
||||
mirror: https://www.gravatar.com/avatar/
|
||||
params: sha256=1&d=mp&s=240
|
||||
pagination:
|
||||
pageSize: 20
|
||||
readMore: true
|
||||
@@ -162,5 +246,7 @@ frontend:
|
||||
content: 300
|
||||
children: 400
|
||||
scrollable: false
|
||||
imgLazyLoad: false
|
||||
reqTimeout: 15000
|
||||
versionCheck: true
|
||||
pluginURLs: []
|
||||
+164
-40
@@ -10,16 +10,19 @@ app_key: ""
|
||||
# Debug mode
|
||||
debug: false
|
||||
|
||||
# Language (follow Unicode BCP 47) ["en", "zh-CN", "zh-TW", "jp"]
|
||||
# Language (follow Unicode BCP 47) ["en", "zh-CN", "zh-TW", "ja", "fr", "ko", "ru"]
|
||||
# -- 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
|
||||
|
||||
# Default site url
|
||||
site_url: ""
|
||||
|
||||
# Login timeout (in seconds)
|
||||
login_timeout: 259200
|
||||
@@ -27,38 +30,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)
|
||||
@@ -69,7 +83,7 @@ cache:
|
||||
# Redis config
|
||||
redis:
|
||||
# Connection type ["tcp", "unix"]
|
||||
network: "tcp"
|
||||
network: tcp
|
||||
# Redis username
|
||||
username: ""
|
||||
# Redis password
|
||||
@@ -109,7 +123,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 --
|
||||
@@ -117,7 +131,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
|
||||
@@ -126,9 +140,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"
|
||||
replace_to: x
|
||||
|
||||
# Captcha
|
||||
captcha:
|
||||
@@ -137,7 +151,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
|
||||
@@ -167,7 +181,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/")
|
||||
@@ -177,7 +191,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
|
||||
|
||||
@@ -186,23 +200,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
|
||||
@@ -210,12 +224,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, --
|
||||
@@ -238,14 +254,18 @@ admin_notify:
|
||||
# Bark
|
||||
bark:
|
||||
enabled: false
|
||||
server: "http://day.app/xxxxxxx/"
|
||||
server: http://day.app/xxxxxxx/
|
||||
# Lark
|
||||
lark:
|
||||
enabled: false
|
||||
webhook_url: ""
|
||||
# Message type ["text", "card"]
|
||||
msg_type: "text"
|
||||
# WebHook
|
||||
webhook:
|
||||
enabled: false
|
||||
url: ""
|
||||
# DingTalk
|
||||
ding_talk:
|
||||
enabled: false
|
||||
token: ""
|
||||
@@ -262,8 +282,110 @@ admin_notify:
|
||||
channel_secret: ""
|
||||
channel_access_token: ""
|
||||
receivers:
|
||||
- "USER_ID_1"
|
||||
- "GROUP_ID_1"
|
||||
- USER_ID_1
|
||||
- GROUP_ID_1
|
||||
|
||||
# Social Login
|
||||
auth:
|
||||
# Enable Social Login
|
||||
enabled: false
|
||||
# Allow anonymous commenting (Allow skipping verification, only fill in an anonymous nickname and email)
|
||||
anonymous: false
|
||||
# Callback URL (https://example.com/api/v2/auth/{provider}/callback)
|
||||
callback: "http://localhost:23366/api/v2/auth/{provider}/callback"
|
||||
# Email
|
||||
email:
|
||||
# Enable email password login
|
||||
enabled: true
|
||||
# Verification email subject
|
||||
verify_subject: "Your Code - {{code}}"
|
||||
# Verification email template (set to file path to use custom template)
|
||||
verify_tpl: default
|
||||
# GitHub
|
||||
github:
|
||||
enabled: false
|
||||
client_id: ""
|
||||
client_secret: ""
|
||||
# GitLab
|
||||
gitlab:
|
||||
enabled: false
|
||||
client_id: ""
|
||||
client_secret: ""
|
||||
# Gitea
|
||||
gitea:
|
||||
enabled: false
|
||||
client_id: ""
|
||||
client_secret: ""
|
||||
# Google
|
||||
google:
|
||||
enabled: false
|
||||
client_id: ""
|
||||
client_secret: ""
|
||||
# Mastodon
|
||||
mastodon:
|
||||
enabled: false
|
||||
client_id: ""
|
||||
client_secret: ""
|
||||
# Twitter
|
||||
twitter:
|
||||
enabled: false
|
||||
client_id: ""
|
||||
client_secret: ""
|
||||
# Facebook
|
||||
facebook:
|
||||
enabled: false
|
||||
client_id: ""
|
||||
client_secret: ""
|
||||
# Discord
|
||||
discord:
|
||||
enabled: false
|
||||
client_id: ""
|
||||
client_secret: ""
|
||||
# Steam
|
||||
steam:
|
||||
enabled: false
|
||||
api_key: ""
|
||||
# Apple
|
||||
apple:
|
||||
enabled: false
|
||||
client_id: ""
|
||||
client_secret: ""
|
||||
# Microsoft
|
||||
microsoft:
|
||||
enabled: false
|
||||
client_id: ""
|
||||
client_secret: ""
|
||||
# WeChat
|
||||
wechat:
|
||||
enabled: false
|
||||
client_id: ""
|
||||
client_secret: ""
|
||||
# Tiktok
|
||||
tiktok:
|
||||
enabled: false
|
||||
client_id: ""
|
||||
client_secret: ""
|
||||
# Slack
|
||||
slack:
|
||||
enabled: false
|
||||
client_id: ""
|
||||
client_secret: ""
|
||||
# Line
|
||||
line:
|
||||
enabled: false
|
||||
client_id: ""
|
||||
client_secret: ""
|
||||
# Patreon
|
||||
patreon:
|
||||
enabled: false
|
||||
client_id: ""
|
||||
client_secret: ""
|
||||
# Auth0
|
||||
auth0:
|
||||
enabled: false
|
||||
client_id: ""
|
||||
client_secret: ""
|
||||
domain: ""
|
||||
|
||||
# UI Settings
|
||||
frontend:
|
||||
@@ -276,23 +398,21 @@ 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
|
||||
voteDown: false
|
||||
# User UA badge
|
||||
uaBadge: true
|
||||
uaBadge: false
|
||||
# Comment sorting
|
||||
listSort: true
|
||||
# Page PV binding element
|
||||
pvEl: "#ArtalkPV"
|
||||
# Comment count binding element
|
||||
countEl: "#ArtalkCount"
|
||||
# Editor real-time preview
|
||||
preview: true
|
||||
# Flatten mode ["auto", true, false]
|
||||
flatMode: "auto"
|
||||
flatMode: auto
|
||||
# Dark mode ["inherit", "auto"]
|
||||
darkMode: inherit
|
||||
# Maximum nesting level
|
||||
nestMax: 2
|
||||
# Nesting comment sorting rules ["DATE_ASC", "DATE_DESC", "VOTE_UP_DESC"]
|
||||
@@ -300,9 +420,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: sha256=1&d=mp&s=240
|
||||
# Comment pagination
|
||||
pagination:
|
||||
# Number of comments per page
|
||||
@@ -319,7 +439,11 @@ frontend:
|
||||
children: 400
|
||||
# Scrollable (scrollable height limit area)
|
||||
scrollable: false
|
||||
# Image lazy load [false, "native", "data-src"]
|
||||
imgLazyLoad: false
|
||||
# Request timeout (unit: ms)
|
||||
reqTimeout: 15000
|
||||
# Version check
|
||||
versionCheck: true
|
||||
# Plugins
|
||||
pluginURLs: []
|
||||
+178
-53
@@ -10,52 +10,66 @@ app_key: ""
|
||||
# 调试模式
|
||||
debug: false
|
||||
|
||||
# 语言 ["en", "zh-CN", "zh-TW", "jp"]
|
||||
locale: "zh-CN"
|
||||
# 语言 ["en", "zh-CN", "zh-TW", "ja", "fr", "ko", "ru"]
|
||||
locale: zh-CN
|
||||
|
||||
# 时间区域
|
||||
timezone: "Asia/Shanghai"
|
||||
timezone: Asia/Shanghai
|
||||
|
||||
# 默认站点名
|
||||
site_default: "默认站点"
|
||||
site_default: 默认站点
|
||||
|
||||
# 登陆有效时长 (单位:秒)
|
||||
# 默认站点地址
|
||||
site_url: ""
|
||||
|
||||
# 登录有效时长 (单位:秒)
|
||||
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
|
||||
# 缓存启动预热 (程序启动时预热缓存)
|
||||
@@ -65,7 +79,7 @@ cache:
|
||||
# Redis 配置
|
||||
redis:
|
||||
# 连接方式 ["tcp", "unix"]
|
||||
network: "tcp"
|
||||
network: tcp
|
||||
# 用户名
|
||||
username: ""
|
||||
# 密码
|
||||
@@ -74,7 +88,8 @@ cache:
|
||||
db: 0
|
||||
|
||||
# 可信域名
|
||||
trusted_domains: [] # 例如:["https://artalk.example.com:23366"]
|
||||
# -- 例如:["https://artalk.example.com:23366"] --
|
||||
trusted_domains: []
|
||||
|
||||
# SSL
|
||||
ssl:
|
||||
@@ -86,12 +101,14 @@ ssl:
|
||||
key_path: ""
|
||||
|
||||
# 管理员账户
|
||||
admin_users:
|
||||
# - name: "admin"
|
||||
# email: "admin@example.com"
|
||||
# password: "" # 支持 bcrypt 或 md5 加密,如:"(md5)50c21190c6e4e5418c6a90d2b5031119"
|
||||
# badge_name: "管理员"
|
||||
# badge_color: "#0083FF"
|
||||
# --
|
||||
# - name: "admin"
|
||||
# email: "admin@example.com"
|
||||
# password: "" # 支持 bcrypt 或 md5 加密,如:"(bcrypt)$2y$10$ti4vZYIrxVN8rLcYXVgXCO.GJND0dyI49r7IoF3xqIx8bBRmIBZRm"
|
||||
# badge_name: "管理员"
|
||||
# badge_color: "#0083FF"
|
||||
# --
|
||||
admin_users: []
|
||||
|
||||
# 评论审核
|
||||
moderator:
|
||||
@@ -108,14 +125,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
|
||||
@@ -123,11 +140,11 @@ moderator:
|
||||
pending: false
|
||||
# 词库文件 (支持多个词库文件)
|
||||
files:
|
||||
- "./data/词库_1.txt"
|
||||
- ./data/词库_1.txt
|
||||
# 词库文件内容分割符 (例如填写 "\n" 文件中一行一个关键词)
|
||||
file_sep: "\n"
|
||||
# 替换字符
|
||||
replac_to: "x"
|
||||
replace_to: x
|
||||
|
||||
# 验证码
|
||||
captcha:
|
||||
@@ -136,7 +153,7 @@ captcha:
|
||||
# 总是需要验证码
|
||||
always: false
|
||||
# 验证类型 ["image", "turnstile", "recaptcha", "hcaptcha", "geetest"]
|
||||
captcha_type: "image"
|
||||
captcha_type: image
|
||||
# 激活验证码所需操作次数
|
||||
action_limit: 3
|
||||
# 重置操作计数器超时 (单位:s, 设为 -1 不重置)
|
||||
@@ -160,21 +177,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/")
|
||||
@@ -185,7 +202,7 @@ img_upload:
|
||||
# 启用 Upgit
|
||||
enabled: false
|
||||
# 命令行参数
|
||||
exec: "./upgit -c <upgit配置文件路径> -t /artalk-img"
|
||||
exec: upgit -c <upgit配置文件路径> -t /artalk-img
|
||||
# 上传后删除本地的图片
|
||||
del_local: true
|
||||
|
||||
@@ -194,23 +211,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: ""
|
||||
# 阿里云邮件推送
|
||||
@@ -218,12 +235,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
|
||||
# 邮件通知管理员
|
||||
@@ -243,11 +262,13 @@ admin_notify:
|
||||
# Bark
|
||||
bark:
|
||||
enabled: false
|
||||
server: "http://day.app/xxxxxxx/"
|
||||
server: http://day.app/xxxxxxx/
|
||||
# 飞书
|
||||
lark:
|
||||
enabled: false
|
||||
webhook_url: ""
|
||||
# 消息类型 ["text", "card"]
|
||||
msg_type: "text"
|
||||
# WebHook
|
||||
webhook:
|
||||
enabled: false
|
||||
@@ -262,17 +283,119 @@ 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
|
||||
|
||||
# 前端配置
|
||||
# 社交登录
|
||||
auth:
|
||||
# 启用社交登录
|
||||
enabled: false
|
||||
# 允许匿名评论 (允许跳过验证,仅填写匿名的昵称和邮箱)
|
||||
anonymous: false
|
||||
# 回调地址 (https://example.com/api/v2/auth/{provider}/callback)
|
||||
callback: "http://localhost:23366/api/v2/auth/{provider}/callback"
|
||||
# Email
|
||||
email:
|
||||
# 启用邮箱密码登录
|
||||
enabled: true
|
||||
# 邮箱验证邮件标题
|
||||
verify_subject: "您的验证码是 - {{code}}"
|
||||
# 邮箱验证邮件模板 (填入文件路径使用自定义模板)
|
||||
verify_tpl: default
|
||||
# GitHub
|
||||
github:
|
||||
enabled: false
|
||||
client_id: ""
|
||||
client_secret: ""
|
||||
# GitLab
|
||||
gitlab:
|
||||
enabled: false
|
||||
client_id: ""
|
||||
client_secret: ""
|
||||
# Gitea
|
||||
gitea:
|
||||
enabled: false
|
||||
client_id: ""
|
||||
client_secret: ""
|
||||
# Google
|
||||
google:
|
||||
enabled: false
|
||||
client_id: ""
|
||||
client_secret: ""
|
||||
# Mastodon
|
||||
mastodon:
|
||||
enabled: false
|
||||
client_id: ""
|
||||
client_secret: ""
|
||||
# Twitter
|
||||
twitter:
|
||||
enabled: false
|
||||
client_id: ""
|
||||
client_secret: ""
|
||||
# Facebook
|
||||
facebook:
|
||||
enabled: false
|
||||
client_id: ""
|
||||
client_secret: ""
|
||||
# Discord
|
||||
discord:
|
||||
enabled: false
|
||||
client_id: ""
|
||||
client_secret: ""
|
||||
# Steam
|
||||
steam:
|
||||
enabled: false
|
||||
api_key: ""
|
||||
# Apple
|
||||
apple:
|
||||
enabled: false
|
||||
client_id: ""
|
||||
client_secret: ""
|
||||
# Microsoft
|
||||
microsoft:
|
||||
enabled: false
|
||||
client_id: ""
|
||||
client_secret: ""
|
||||
# 微信
|
||||
wechat:
|
||||
enabled: false
|
||||
client_id: ""
|
||||
client_secret: ""
|
||||
# Tiktok
|
||||
tiktok:
|
||||
enabled: false
|
||||
client_id: ""
|
||||
client_secret: ""
|
||||
# Slack
|
||||
slack:
|
||||
enabled: false
|
||||
client_id: ""
|
||||
client_secret: ""
|
||||
# Line
|
||||
line:
|
||||
enabled: false
|
||||
client_id: ""
|
||||
client_secret: ""
|
||||
# Patreon
|
||||
patreon:
|
||||
enabled: false
|
||||
client_id: ""
|
||||
client_secret: ""
|
||||
# Auth0
|
||||
auth0:
|
||||
enabled: false
|
||||
client_id: ""
|
||||
client_secret: ""
|
||||
domain: ""
|
||||
|
||||
# 界面配置
|
||||
frontend:
|
||||
# 评论框占位文字
|
||||
placeholder: ""
|
||||
@@ -283,23 +406,21 @@ 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
|
||||
# 反对按钮
|
||||
voteDown: false
|
||||
# 用户 UA 徽标
|
||||
uaBadge: true
|
||||
uaBadge: false
|
||||
# 评论排序功能
|
||||
listSort: true
|
||||
# 页面 PV 绑定元素
|
||||
pvEl: "#ArtalkPV"
|
||||
# 评论数绑定元素
|
||||
countEl: "#ArtalkCount"
|
||||
# 编辑器实时预览功能
|
||||
preview: true
|
||||
# 平铺模式 ["auto", true, false]
|
||||
flatMode: "auto"
|
||||
flatMode: auto
|
||||
# 夜间模式 ["inherit", "auto"]
|
||||
darkMode: inherit
|
||||
# 最大嵌套层数
|
||||
nestMax: 2
|
||||
# 嵌套评论排序规则 ["DATE_ASC", "DATE_DESC", "VOTE_UP_DESC"]
|
||||
@@ -307,9 +428,9 @@ frontend:
|
||||
# 头像 Gravatar
|
||||
gravatar:
|
||||
# API 地址
|
||||
mirror: "https://cravatar.cn/avatar/"
|
||||
mirror: https://weavatar.com/avatar/
|
||||
# API 参数
|
||||
params: "d=mp&s=240"
|
||||
params: sha256=1&d=mp&s=240
|
||||
# 评论分页
|
||||
pagination:
|
||||
# 每页评论数
|
||||
@@ -326,7 +447,11 @@ frontend:
|
||||
children: 400
|
||||
# 滚动限高 (允许限高区域滚动)
|
||||
scrollable: false
|
||||
# 图片懒加载 [false, "native", "data-src"]
|
||||
imgLazyLoad: false
|
||||
# 请求超时 (单位:毫秒)
|
||||
reqTimeout: 15000
|
||||
# 版本检测
|
||||
versionCheck: true
|
||||
# 插件
|
||||
pluginURLs: []
|
||||
+7
-1
@@ -1,8 +1,9 @@
|
||||
version: "3.5"
|
||||
version: "3.8"
|
||||
services:
|
||||
artalk:
|
||||
container_name: artalk
|
||||
image: artalk/artalk-go
|
||||
restart: unless-stopped
|
||||
build:
|
||||
context: ./
|
||||
dockerfile: Dockerfile
|
||||
@@ -10,3 +11,8 @@ services:
|
||||
- 8080:23366
|
||||
volumes:
|
||||
- ./data:/data
|
||||
environment:
|
||||
- TZ=Asia/Shanghai
|
||||
- ATK_LOCALE=zh-CN
|
||||
- ATK_SITE_DEFAULT=Artalk 的博客
|
||||
- ATK_SITE_URL=https://example.com
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
/.vitepress/dist/
|
||||
/.vitepress/cache/
|
||||
/public/http-api.html
|
||||
@@ -1,2 +0,0 @@
|
||||
shamefully-hoist=true
|
||||
auto-install-peers=true
|
||||
@@ -1,85 +0,0 @@
|
||||
<template>
|
||||
<div ref="artalkEl" style="margin-top: 20px;"></div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { watch, nextTick, ref, onMounted } from 'vue'
|
||||
import { useData, useRouter } from 'vitepress'
|
||||
|
||||
const artalkEl = ref<HTMLElement | null>(null)
|
||||
|
||||
const router = useRouter()
|
||||
const page = useData().page
|
||||
|
||||
onMounted(() => {
|
||||
const script = document.createElement('script')
|
||||
script.src = `https://artalk.qwqaq.com/dist/Artalk.js`
|
||||
document.getElementsByTagName('head')[0].appendChild(script)
|
||||
script.onload = () => {
|
||||
initArtalk(page.value)
|
||||
}
|
||||
})
|
||||
|
||||
watch(() => router.route.data.relativePath, (path) => {
|
||||
nextTick(() => {
|
||||
Artalk.update(getArtalkConfByPage(page.value))
|
||||
Artalk.reload()
|
||||
})
|
||||
})
|
||||
|
||||
function getArtalkConfByPage(page: any) {
|
||||
return {
|
||||
pageKey: 'https://artalk.js.org'+location.pathname,
|
||||
pageTitle: page.title,
|
||||
server: 'https://artalk.qwqaq.com',
|
||||
site: 'ArtalkDocs',
|
||||
}
|
||||
}
|
||||
|
||||
function initArtalk(page: any) {
|
||||
Artalk.init({
|
||||
el: artalkEl.value,
|
||||
emoticons: '/assets/emoticons/default.json',
|
||||
gravatar: {
|
||||
mirror: 'https://cravatar.cn/avatar/'
|
||||
},
|
||||
...getArtalkConfByPage(page)
|
||||
})
|
||||
|
||||
// 图片灯箱插件
|
||||
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>
|
||||
Vendored
-5
@@ -1,5 +0,0 @@
|
||||
declare module '*.vue' {
|
||||
import { defineComponent } from 'vue';
|
||||
const component: ReturnType<typeof defineComponent>;
|
||||
export default component;
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
{
|
||||
"latest": "2.6.1"
|
||||
}
|
||||
@@ -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 | 否 | 导入数据 |
|
||||
|
||||
**响应** 无
|
||||
@@ -1,36 +0,0 @@
|
||||
# Event
|
||||
|
||||
## 基本事件
|
||||
|
||||
|事件名|描述|
|
||||
|-|-|
|
||||
| `list-load` | 评论加载事件 |
|
||||
| `list-loaded` | 评论加载完成事件 |
|
||||
| `list-inserted` | 新增评论插入事件 |
|
||||
| `editor-submit` | 编辑器提交事件 |
|
||||
| `editor-submitted` | 编辑器提交完成事件 |
|
||||
| `user-changed` | 本地用户数据变更事件 |
|
||||
| `conf-loaded` | 配置变更事件 |
|
||||
| `sidebar-show` | 侧边栏显示事件 |
|
||||
| `sidebar-hide` | 侧边栏隐藏事件 |
|
||||
|
||||
## 添加事件监听
|
||||
|
||||
```js
|
||||
Artalk.use(ctx => {
|
||||
ctx.on('list-loaded', () => {
|
||||
alert('评论已加载完毕')
|
||||
})
|
||||
})
|
||||
```
|
||||
|
||||
## 解除事件监听
|
||||
|
||||
```js
|
||||
let foo = function() { /* do something */ }
|
||||
|
||||
Artalk.use(ctx => {
|
||||
ctx.on('list-loaded', foo)
|
||||
ctx.off('list-loaded', foo)
|
||||
})
|
||||
```
|
||||
@@ -1,106 +0,0 @@
|
||||
# Frontend API
|
||||
|
||||
## 初始化 `Artalk.init`
|
||||
|
||||
创建 Artalk 实例化对象。
|
||||
|
||||
```js
|
||||
Artalk.init({
|
||||
el: '#Comments',
|
||||
pageKey: '/post/1',
|
||||
pageTitle: '关于引入 Artalk 的这档子事',
|
||||
server: 'http://your_domain:8080',
|
||||
site: 'Artalk 的博客',
|
||||
})
|
||||
```
|
||||
|
||||
## 更新配置 `Artalk.update`
|
||||
|
||||
修改 Artalk 当前配置。
|
||||
|
||||
```js
|
||||
Artalk.update({
|
||||
// 新的配置...
|
||||
})
|
||||
```
|
||||
|
||||
该函数调用后,`conf-loaded` 事件将被触发。
|
||||
|
||||
更新配置不会自动刷新评论列表,可按需继续执行 `Artalk.reload()` 函数。
|
||||
|
||||
注:前端的一些配置将会被后端的配置覆盖,详情见:[在后端控制前端](../guide/backend/fe-control.md)
|
||||
|
||||
## 重新加载 `Artalk.reload`
|
||||
|
||||
刷新 Artalk 评论列表。
|
||||
|
||||
```js
|
||||
Artalk.reload()
|
||||
```
|
||||
|
||||
列表加载前将触发 `list-load` 事件,加载完毕后将触发 `list-loaded` 事件。
|
||||
|
||||
## 释放资源 `Artalk.destroy`
|
||||
|
||||
销毁 Artalk 实例,用于资源释放。
|
||||
|
||||
```js
|
||||
Artalk.destroy()
|
||||
```
|
||||
|
||||
## 事件监听 `Artalk.on`
|
||||
|
||||
添加 Artalk 事件监听。
|
||||
|
||||
```js
|
||||
Artalk.on('list-loaded', () => {
|
||||
alert('评论列表加载完毕')
|
||||
})
|
||||
```
|
||||
|
||||
可监听事件类型见:[前端界面事件](./event.md)
|
||||
|
||||
## 解除监听 `Artalk.off`
|
||||
|
||||
解除 Artalk 事件监听。
|
||||
|
||||
```js
|
||||
const handler = () => {
|
||||
alert('评论列表加载完毕')
|
||||
}
|
||||
|
||||
Artalk.on('list-loaded', handler)
|
||||
Artalk.off('list-loaded', handler)
|
||||
```
|
||||
|
||||
## 触发事件 `Artalk.trigger`
|
||||
|
||||
触发 Artalk 事件。
|
||||
|
||||
```js
|
||||
Artalk.trigger('list-loaded')
|
||||
```
|
||||
|
||||
## 扩展插件 `Artalk.use`
|
||||
|
||||
该 API 用于扩展 Artalk。
|
||||
|
||||
```js
|
||||
Artalk.use((ctx) => {
|
||||
ctx.editor.setContent("Hello World")
|
||||
})
|
||||
```
|
||||
|
||||
详情见:[插件开发](./plugs.md)
|
||||
|
||||
## 夜间模式 `Artalk.setDarkMode`
|
||||
|
||||
修改夜间模式,可以配合博客主题调用,例如当用户点击夜间模式切换按钮。
|
||||
|
||||
```js
|
||||
Artalk.setDarkMode(true)
|
||||
```
|
||||
|
||||
## 浏览量组件 `Artalk.loadCountWidget`
|
||||
|
||||
详情见:[浏览量统计](../guide/frontend/pv.md)
|
||||
@@ -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.d.ts](https://github.com/ArtalkJS/Artalk/blob/master/ui/packages/artalk/types/event.d.ts)
|
||||
|
||||
通过 Artalk 提供的 `API` 和 `Event`,你可以实现很多高级功能,比如编写评论管理机器人、评论提醒推送插件等。Artalk 并不为此提供技术指导,但鼓励你参考此处的文档自行定制。
|
||||
@@ -1,17 +0,0 @@
|
||||
# 插件开发
|
||||
|
||||
你可以使用 `Artalk.use` 来扩展 Artalk。
|
||||
|
||||
```js
|
||||
Artalk.use((ctx) => {
|
||||
ctx.editor.setContent("Hello World")
|
||||
})
|
||||
```
|
||||
|
||||
## Context
|
||||
|
||||
::: warning
|
||||
Context API 目前仍不稳定,开发可能会有变动,升级请关注 CHANGELOG。
|
||||
:::
|
||||
|
||||
参考:[@artalk/types/context.d.ts](https://github.com/ArtalkJS/Artalk/blob/master/ui/packages/artalk/types/context.d.ts)
|
||||
@@ -0,0 +1,2 @@
|
||||
.vitepress/dist/**
|
||||
.vitepress/cache/**
|
||||
@@ -9,18 +9,14 @@ 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 }],
|
||||
// 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' }],
|
||||
// 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' }],
|
||||
[
|
||||
'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',
|
||||
},
|
||||
],
|
||||
],
|
||||
|
||||
lastUpdated: true,
|
||||
@@ -33,88 +29,94 @@ 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: '/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' },
|
||||
{ text: '邮件通知', link: '/guide/backend/email.md' },
|
||||
{ text: '多元推送', link: '/guide/backend/admin_notify.md' },
|
||||
{ text: '社交登录', link: '/guide/frontend/auth.md' },
|
||||
{ text: '评论审核', link: '/guide/backend/moderator.md' },
|
||||
{ text: '验证码', link: '/guide/backend/captcha.md' },
|
||||
{ text: '图片上传', link: '/guide/backend/img-upload.md' },
|
||||
{ text: '账户与多站点', link: '/guide/backend/multi-site.md' },
|
||||
{ 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: 'LaTeX', link: '/guide/frontend/latex.md' },
|
||||
{ text: '图片灯箱', link: '/guide/frontend/lightbox.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: '开发文档', link: '/develop/index.md', },
|
||||
{ text: '图片懒加载', link: '/guide/frontend/img-lazy-load.md' },
|
||||
{ text: 'IP 属地', link: '/guide/frontend/ip-region.md' },
|
||||
{ text: '多语言', link: '/guide/frontend/i18n.md' },
|
||||
{ text: '开发文档', link: '/develop/index.md' },
|
||||
],
|
||||
},
|
||||
{
|
||||
text: "配置文档",
|
||||
collapsed: true,
|
||||
text: '配置文档',
|
||||
collapsed: false,
|
||||
items: [
|
||||
{ text: '后端配置', link: '/guide/backend/config.md' },
|
||||
{ text: '前端配置', link: '/guide/frontend/config.md' },
|
||||
]
|
||||
{ text: '环境变量', link: '/guide/env.md' },
|
||||
{ text: '配置文件', link: '/guide/backend/config.md' },
|
||||
{ text: '界面配置', link: '/guide/frontend/config.md' },
|
||||
],
|
||||
},
|
||||
{
|
||||
text: "部署说明",
|
||||
text: '部署说明',
|
||||
collapsed: true,
|
||||
items: [
|
||||
{ text: 'Docker', link: '/guide/backend/docker.md' },
|
||||
{ text: '守护进程', link: '/guide/backend/daemon.md' },
|
||||
{ text: '反向代理', link: '/guide/backend/reverse-proxy.md' },
|
||||
{ text: '编译构建', link: '/guide/backend/build.md' },
|
||||
{ text: '编译构建', link: '/develop/contributing.md' },
|
||||
{ text: '程序升级', link: '/guide/backend/update.md' },
|
||||
]
|
||||
{ text: 'Docker', link: '/guide/backend/docker.md' },
|
||||
],
|
||||
},
|
||||
{
|
||||
text: '更多内容',
|
||||
@@ -124,23 +126,28 @@ 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/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: '开发说明', link: '/develop/index.md' },
|
||||
{ text: '贡献指南', link: '/develop/contributing.md' },
|
||||
{ text: '置入博客', link: '/develop/import-blog.md' },
|
||||
{ text: '置入框架', link: '/develop/import-framework.md' },
|
||||
{ text: '前端 API', link: '/develop/fe-api.md' },
|
||||
{ text: '前端 Event', link: '/develop/event.md' },
|
||||
{ text: '插件开发', link: '/develop/plugin.md' },
|
||||
{ text: '兼容性', link: '/develop/compatibility.md' },
|
||||
{
|
||||
text: 'HTTP API',
|
||||
link: 'https://artalk.js.org/http-api.html',
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
nav: [
|
||||
@@ -177,30 +184,39 @@ 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' },
|
||||
],
|
||||
|
||||
algolia: {
|
||||
appId: 'BH4D9OD16A',
|
||||
apiKey: '37ab96e3f5a774cbbf0571b035b42adb',
|
||||
indexName: 'artalk-js',
|
||||
searchParameters: {
|
||||
facetFilters: ['lang:zh-CN']
|
||||
}
|
||||
search: {
|
||||
provider: 'algolia',
|
||||
options: {
|
||||
appId: '2WNJ32WVTY',
|
||||
apiKey: '6c6ebc345a87b738264f19095b78c91c',
|
||||
indexName: 'artalk-js',
|
||||
searchParameters: {
|
||||
facetFilters: ['lang:zh-CN'],
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
editLink: {
|
||||
pattern: 'https://github.com/ArtalkJS/Artalk/edit/master/docs/:path',
|
||||
text: '完善文档'
|
||||
pattern: 'https://github.com/ArtalkJS/Artalk/edit/master/docs/docs/:path',
|
||||
text: '完善文档',
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
vite: {
|
||||
server: {
|
||||
open: '/guide/intro.html',
|
||||
},
|
||||
},
|
||||
})
|
||||
@@ -0,0 +1,82 @@
|
||||
<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 { ArtalkKatexPlugin } from '@artalk/plugin-katex'
|
||||
import { ArtalkLightboxPlugin } from '@artalk/plugin-lightbox'
|
||||
import 'lightgallery/css/lightgallery.css'
|
||||
import 'katex/dist/katex.min.css'
|
||||
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.use(ArtalkKatexPlugin)
|
||||
Artalk.use(ArtalkLightboxPlugin, {
|
||||
lightGallery: {
|
||||
lib: async () => (await import('lightgallery')).default
|
||||
}
|
||||
})
|
||||
|
||||
artalk = Artalk.init({
|
||||
el: el.value,
|
||||
emoticons: '/assets/emoticons/default.json',
|
||||
...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() {
|
||||
// 夜间模式
|
||||
const darkMode = document.querySelector('html').classList.contains('dark')
|
||||
artalk.setDarkMode(darkMode)
|
||||
|
||||
new MutationObserver((mList) => {
|
||||
mList.forEach((m) => {
|
||||
if (m.attributeName !== 'class') return
|
||||
|
||||
const darkMode = (<HTMLElement>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
|
||||
id="artransferIframe"
|
||||
src="https://artransfer.netlify.app/?iframe=1"
|
||||
style="width: 100%; height: 520px; border: 0"
|
||||
></iframe>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
@@ -24,15 +28,10 @@ export default defineComponent({
|
||||
mList.forEach((m) => {
|
||||
if (m.attributeName !== 'class') return
|
||||
|
||||
// @ts-ignore
|
||||
const darkMode = m.target.classList.contains('dark')
|
||||
const darkMode = (<HTMLElement>m.target).classList.contains('dark')
|
||||
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.
@@ -1,8 +1,8 @@
|
||||
import DefaultTheme from 'vitepress/theme'
|
||||
import { Theme } from 'vitepress'
|
||||
import Layout from './Layout.vue'
|
||||
import Artalk from './Artalk.vue'
|
||||
import Artransfer from './Artransfer.vue'
|
||||
import { Theme } from 'vitepress'
|
||||
|
||||
export default {
|
||||
...DefaultTheme,
|
||||
@@ -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
@@ -0,0 +1,5 @@
|
||||
declare module '*.vue' {
|
||||
import { defineComponent } from 'vue'
|
||||
const component: ReturnType<typeof defineComponent>
|
||||
export default component
|
||||
}
|
||||
@@ -1,19 +1,20 @@
|
||||
## Artalk Documentation
|
||||
# Artalk Documentation
|
||||
|
||||
> The Documentation of Artalk
|
||||
[](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
|
||||
|
||||
[](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.
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"latest": "2.9.0"
|
||||
}
|
||||
@@ -1,15 +1,15 @@
|
||||
<!-- CSS -->
|
||||
<link href="https://unpkg.com/artalk@2.4.4/dist/Artalk.css" rel="stylesheet">
|
||||
<link href="http://localhost:8080/dist/Artalk.css" rel="stylesheet">
|
||||
|
||||
<!-- JS -->
|
||||
<script src="https://unpkg.com/artalk@2.4.4/dist/Artalk.js"></script>
|
||||
<script src="http://localhost:8080/dist/Artalk.js"></script>
|
||||
|
||||
<!-- Artalk -->
|
||||
<div id="Comments"></div>
|
||||
<script>
|
||||
Artalk.init({
|
||||
el: '#Comments', // 绑定元素的 Selector
|
||||
pageKey: '/post/1', // 固定链接 (留空自动获取)
|
||||
pageKey: '/post/1', // 固定链接
|
||||
pageTitle: '关于引入 Artalk 这档子事', // 页面标题 (留空自动获取)
|
||||
server: 'http://localhost:8080', // 后端地址
|
||||
site: 'Artalk 的博客', // 你的站点名
|
||||
File renamed without changes.
@@ -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 | - | 评论者邮箱 SHA256 加密值 |
|
||||
| `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.
@@ -0,0 +1,18 @@
|
||||
# 兼容性
|
||||
|
||||
## 浏览器兼容性
|
||||
|
||||
Artalk 客户端生产环境代码的构建通过 esbuild 执行,构建目标为 `es2015`。但请注意,构建仅会处理语法转义遵循 `es2015` 标准,不会处理 API 的兼容性(不包含任何 polyfill)。
|
||||
|
||||
如果你的项目需要支持较旧的浏览器和设备,请考虑在捆绑应用程序中包含全局 polyfill。我们推荐使用 [Polyfill.io](https://polyfill.io/) 服务,它会根据用户的 User-Agent 动态返回所需的 polyfill。另外,你也可以使用 [core-js](https://github.com/zloirock/core-js) 或 [Babel](https://babeljs.io/) 来手动添加 polyfill。
|
||||
|
||||
以下是 Artalk 使用的现代功能的列表:
|
||||
|
||||
- [All ECMAScript 2015 (ES6) features](https://compat-table.github.io/compat-table/es6/)
|
||||
- [Fetch](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API)
|
||||
- [AbortController](https://developer.mozilla.org/en-US/docs/Web/API/AbortController)
|
||||
- [Intersection Observer](https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API)
|
||||
|
||||
## 服务器兼容性
|
||||
|
||||
Artalk 服务端程序基于 Golang 开发,支持 Linux、Windows 和 macOS 等操作系统。当前 Artalk 的 Golang 版本可通过 [go.mod](https://github.com/ArtalkJS/Artalk/blob/master/go.mod#L3) 查看。关于 Golang 的最低操作系统要求,可参考 [Go Wiki](https://go.dev/wiki/MinimumRequirements)。
|
||||
@@ -0,0 +1,298 @@
|
||||
# 开发者贡献指南
|
||||
|
||||
本指南帮助开发者了解如何在 Artalk 项目中贡献代码、文档、测试和反馈。我们欢迎所有形式的贡献,无论是大型功能开发、小型修复、文档改进还是测试。我们相信每一个贡献都是推动项目前进的重要一环。
|
||||
|
||||
本指南包含多语言版本:[English](https://github.com/ArtalkJS/Artalk/blob/master/CONTRIBUTING.md) • [简体中文](https://artalk.js.org/develop/contributing.html)
|
||||
|
||||
## 克隆仓库
|
||||
|
||||
克隆仓库:
|
||||
|
||||
```sh
|
||||
git clone https://github.com/ArtalkJS/Artalk.git
|
||||
```
|
||||
|
||||
建议您先 fork 仓库,然后克隆 fork 后的仓库。
|
||||
|
||||
导航到目录:
|
||||
|
||||
```sh
|
||||
cd Artalk
|
||||
```
|
||||
|
||||
## 开发环境
|
||||
|
||||
为了开发 Artalk 的前端和后端,请安装以下工具:
|
||||
|
||||
- [Node.js](https://nodejs.org/en/) (>= 20.17.0)
|
||||
- [PNPM](https://pnpm.io/) (>= 9.9.0)
|
||||
- [Go](https://golang.org/) (>= 1.22)
|
||||
- [Docker](https://www.docker.com/) (>= 20.10.0)(可选)
|
||||
- [Docker Compose](https://docs.docker.com/compose/) (>= 1.29.0)(可选)
|
||||
|
||||
## 开发工作流程概述
|
||||
|
||||
开发工作流程包括以下步骤:
|
||||
|
||||
1. **搭建完整的开发实例**:
|
||||
|
||||
- 导航到 Artalk 仓库目录。
|
||||
- 执行 `make dev` 在端口 `23366` 上运行后端。
|
||||
- 执行 `pnpm dev` 在端口 `5173` 上运行前端。
|
||||
- 可选地,执行 `pnpm dev:sidebar` 在端口 `23367` 上运行侧边栏前端。
|
||||
|
||||
2. **访问前端进行开发**:
|
||||
|
||||
- 打开浏览器,访问 `http://localhost:5173` 进行开发和测试。
|
||||
|
||||
3. **测试**:
|
||||
|
||||
- 使用 `make test` 运行后端单元测试。
|
||||
- 使用 `pnpm test` 运行 UI 单元测试。
|
||||
- 使用 `make test-frontend-e2e` 运行 UI 端到端测试。
|
||||
|
||||
4. **构建前端代码**:
|
||||
|
||||
- 当您对前端代码进行更改后,使用 `pnpm build:all` 构建完整的前端程序。
|
||||
- JavaScript 和 CSS 代码将在 `ui/artalk/dist` 目录中找到。
|
||||
- 前端代码由 GitHub Actions 自动部署到 NPM。
|
||||
|
||||
5. **构建后端代码**:
|
||||
|
||||
- 当您对后端代码进行更改后,注意后端程序会嵌入前端代码。
|
||||
- 在构建后端之前,运行 `make build-frontend`(它运行 `scripts/build-frontend.sh`)。这将把嵌入的前端主程序和侧边栏前端程序放入 `/public` 目录。
|
||||
- 然后,使用 `make build` 构建后端程序。
|
||||
|
||||
更多探索:
|
||||
|
||||
- **开发 Artalk 插件或主题**:
|
||||
请参考 [Artalk 插件开发指南](https://artalk.js.org/develop/plugin.html)。
|
||||
|
||||
- **Makefile**:
|
||||
您可以探索 `Makefile` 中的过程和命令。
|
||||
|
||||
- **GitHub 上的自动化 CI**:
|
||||
GitHub 上的自动化 CI 流水线位于 `.github/workflows` 目录中,负责构建前端、后端和 Docker 镜像,发布 Docker 镜像到 Docker Hub,处理 npm 包发布,并创建 GitHub Releases,同时测试前端和后端。
|
||||
|
||||
以下部分提供了更详细的开发工作流程信息。
|
||||
|
||||
## 项目结构
|
||||
|
||||
Artalk 是一个 monorepo 项目,这意味着所有源代码都在一个仓库中。尽管如此,前端和后端保持分离。前端部分位于 `./ui` 目录中。
|
||||
|
||||
### 目录概览
|
||||
|
||||
- `bin/`:编译的二进制文件。(此目录被 git 忽略)
|
||||
- `cmd/`:命令行工具的源代码。
|
||||
- `conf/`:示例配置文件。
|
||||
- `data/`:本地数据。(此目录被 git 忽略)
|
||||
- `docs/`:文档站点的源代码。
|
||||
- `i18n/`:翻译文件。
|
||||
- `local/`:本地文件。(此目录被 git 忽略)
|
||||
- `internal/`:内部包的 Go 源代码。
|
||||
- `public/`:静态文件。构建的前端文件将被复制到这里。
|
||||
- `scripts/`:开发和构建的脚本。
|
||||
- `server/`:后端的 Go 源代码。
|
||||
- `ui/`:前端的 UI 源代码。
|
||||
- `.github/`:GitHub Actions 工作流。
|
||||
- `.vscode/`:VSCode 设置。
|
||||
|
||||
## 后端开发
|
||||
|
||||
### 运行后端
|
||||
|
||||
1. **创建配置文件**:
|
||||
|
||||
- 将 `./conf/artalk.example.yml` 复制到根目录。
|
||||
- 重命名为 `artalk.yml`。
|
||||
- 根据需要修改文件。
|
||||
|
||||
2. **启动后端程序**:
|
||||
|
||||
- 运行 `make dev` 启动后端,端口为 `23366`。
|
||||
- 通过 `http://localhost:23366` 访问。
|
||||
- 建议保留默认端口进行测试。
|
||||
- (替代)使用 `ARGS="version" make dev` 传递启动参数(默认是 `ARGS="server"`)。
|
||||
|
||||
`make dev` 命令会带有调试符号构建后端,这方便使用 GDB 进行调试。
|
||||
|
||||
如果您使用 VSCode,可以使用 `F5` 键(或运行按钮)直接启动调试后端程序。
|
||||
|
||||
### 构建后端
|
||||
|
||||
1. **获取最新的 Git 标签**:
|
||||
执行 `git fetch --tags` 获取最新的 Git 标签信息。此标签将用作后端应用程序的版本号。或者,通过环境变量指定:`VERSION="v1.0.0"` 和 `COMMIT_HASH="66128e"`。
|
||||
|
||||
2. **构建前端**:
|
||||
运行 `make build-frontend` 构建前端,因为后端应用程序会嵌入前端代码。
|
||||
|
||||
3. **构建后端**:
|
||||
执行 `make build` 构建后端程序。
|
||||
|
||||
构建的二进制文件将位于 `./bin` 目录中。
|
||||
|
||||
## 前端开发(UI)
|
||||
|
||||
### 运行前端
|
||||
|
||||
1. **安装依赖**:
|
||||
运行 `pnpm install` 安装所有必要的依赖。
|
||||
|
||||
2. **启动开发服务器**:
|
||||
执行 `pnpm dev --port 5173` 启动前端开发服务器。
|
||||
|
||||
3. **访问前端**:
|
||||
前端应用程序默认将在端口 `5173` 上运行。在浏览器中访问 `http://localhost:5173`。
|
||||
|
||||
4. **侧边栏开发**:
|
||||
要运行侧边栏部分的前端,请使用 `pnpm dev:sidebar`。
|
||||
|
||||
端口 `5173` 和 `23367` 用于前端开发和测试。这些端口被包括在后端程序的 `ATK_TRUSTED_DOMAINS` 配置中。
|
||||
|
||||
### 构建前端
|
||||
|
||||
要构建前端,请运行以下命令:
|
||||
|
||||
```sh
|
||||
make build-frontend
|
||||
```
|
||||
|
||||
编译的 JavaScript 和 CSS 文件将位于 `/public` 目录中,嵌入到后端程序中。
|
||||
|
||||
更多详细信息,请参考 `scripts/build-frontend.sh` 脚本。
|
||||
|
||||
## Docker 开发
|
||||
|
||||
### 构建 Docker 镜像
|
||||
|
||||
要构建 Docker 镜像,请运行以下命令:
|
||||
|
||||
```sh
|
||||
docker build -t artalk:TAG .
|
||||
```
|
||||
|
||||
将 `TAG` 替换为所需的标签名(例如 `latest`)。
|
||||
|
||||
### 跳过前端构建
|
||||
|
||||
如果您已经在 Docker 容器外部构建了前端,可以跳过容器内的前端构建过程以加快构建速度。使用以下命令:
|
||||
|
||||
```sh
|
||||
docker build --build-arg SKIP_FRONTEND_BUILD=true -t artalk:latest .
|
||||
```
|
||||
|
||||
更多详细信息,请参考 `Dockerfile`。
|
||||
|
||||
## 测试
|
||||
|
||||
### 测试后端
|
||||
|
||||
要测试后端 Go 程序,可以使用以下命令:
|
||||
|
||||
- **单元测试**:
|
||||
运行 `make test` 执行单元测试。结果将输出在终端。
|
||||
|
||||
- **测试覆盖率**:
|
||||
运行 `make test-coverage` 检查代码测试覆盖率。
|
||||
|
||||
- **HTML 覆盖率报告**:
|
||||
运行 `make test-coverage-html` 生成并浏览 HTML 格式的测试覆盖率报告。
|
||||
|
||||
- **运行特定测试**:
|
||||
要运行特定测试,请使用带有环境变量的命令:
|
||||
```sh
|
||||
TEST_PATHS="./server/..." make test
|
||||
```
|
||||
|
||||
### 测试前端
|
||||
|
||||
前端测试包括单元测试和端到端(E2E)测试。
|
||||
|
||||
- **单元测试**:
|
||||
前端的单元测试使用 Vitest 进行。运行 `pnpm test` 开始单元测试。
|
||||
|
||||
- **端到端测试**:
|
||||
E2E 测试使用 Playwright 进行。要启动 E2E 测试,运行:
|
||||
```sh
|
||||
make test-frontend-e2e
|
||||
```
|
||||
|
||||
### 持续集成测试
|
||||
|
||||
前端和后端的测试都是自动化的,并将在 Git pull 请求和构建过程中使用 CircleCI 或 GitHub Actions 执行。
|
||||
|
||||
## 配置
|
||||
|
||||
模板配置文件位于 `/conf` 目录中,模板以多种语言注释,命名格式为 `artalk.example.[lang].yml`(例如,`artalk.example.zh-CN.yml`)。Artalk 将解析这些模板配置文件以生成设置界面、环境变量名称和文档。为了提高性能,程序运行期间将缓存部分数据以消除解析时间。
|
||||
|
||||
在 `internal/config/config.go` 文件中,有一个名为 `Config` 的结构体定义,该结构体用于将 yml 文件解析为 Go 结构体。该结构体包含更精确的类型定义。如果需要添加、修改或删除配置项,必须同时修改 `/conf` 目录中的配置文件模板和 `Config` 结构体。
|
||||
|
||||
当您修改配置文件后,请运行以下命令以更新配置数据缓存:
|
||||
|
||||
```sh
|
||||
make update-conf
|
||||
```
|
||||
|
||||
要更新环境变量文档,可以运行以下命令:
|
||||
|
||||
```sh
|
||||
make update-conf-docs
|
||||
```
|
||||
|
||||
## 文档
|
||||
|
||||
文档由三个部分组成,每个部分与特定包相关:**指南文档**、**着陆页**和 **Swagger API 文档**。下面是每个包的相关命令及其输出的总结。
|
||||
|
||||
### 指南文档 (`docs`)
|
||||
|
||||
- **目录**:`docs/docs/guide`
|
||||
- **开发命令**:`pnpm -F docs dev:docs`
|
||||
- **构建命令**:`pnpm -F docs build:docs`
|
||||
- **输出目录**:`docs/docs/.vitepress/dist`
|
||||
|
||||
### 着陆页 (`docs-landing`)
|
||||
|
||||
- **目录**:`docs/landing`
|
||||
- **开发命令**:`pnpm -F docs-landing dev:landing`
|
||||
- **构建命令**:`pnpm -F docs-landing build:landing`
|
||||
- **输出目录**:`docs/landing/dist`
|
||||
|
||||
### Swagger API 文档 (`docs-swagger`)
|
||||
|
||||
- **目录**:`docs/swagger`
|
||||
- **构建命令**:`make update-swagger`
|
||||
- **输出目录**:`docs/swagger`
|
||||
|
||||
Swagger 定义位于后端代码的 `/server` 目录中。修改 Swagger 定义后,运行构建命令将更新 Swagger 文档并在 `/ui/artalk/src/api/v2.ts` 生成 HTTP 客户端代码。
|
||||
|
||||
### 综合构建
|
||||
|
||||
- **构建所有包的命令**:`pnpm build:docs`
|
||||
- **综合输出目录**:`docs/docs/.vitepress/dist`
|
||||
|
||||
此命令构建并组合所有三个包到单个目录中,准备发布。
|
||||
|
||||
### 环境变量文档
|
||||
|
||||
- **文件**:`docs/docs/guide/env.md`
|
||||
- **更新命令**:`make update-conf-docs`
|
||||
|
||||
此命令读取位于 `/conf` 的配置模板文件以更新环境变量文档。在修改配置模板文件后运行此命令。
|
||||
|
||||
## 翻译 (i18n)
|
||||
|
||||
如果您编写了新功能或进行了修复/重构,请使用以下命令通过解析源代码中的 `i18n.T` 函数调用来增量生成翻译文件:
|
||||
|
||||
```sh
|
||||
make update-i18n
|
||||
```
|
||||
|
||||
如果您不是程序员,但希望帮助改进翻译,可以直接编辑 `/i18n` 目录中的翻译文件,然后提交 pull 请求。
|
||||
|
||||
## 结尾
|
||||
|
||||
感谢您耐心阅读本指南,并感谢您对 Artalk 的兴趣和支持。我们深知,一个开源项目的成功依赖于每一位开发者的贡献。无论是通过代码、文档、测试还是反馈,您的参与是推动项目持续进步的动力。我们诚挚邀请您加入我们,共同改进和增强 Artalk。
|
||||
|
||||
通过合作,我们可以创建一个更加健壮和多功能的平台,造福整个社区。您的独特见解和专业知识是无价的,只有共同努力,我们才能实现显著的进步。无论您是经验丰富的开发者,还是刚刚起步的新手,我们的项目中总有您可以贡献的一席之地。
|
||||
|
||||
如果您有任何问题或需要帮助,请随时在我们的 GitHub 页面上的 issue 部分提问:<https://github.com/ArtalkJS/Artalk/issues>。再次感谢您的支持,我们期待与您合作。
|
||||
@@ -0,0 +1,50 @@
|
||||
# Frontend 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)
|
||||
```
|
||||
@@ -0,0 +1,195 @@
|
||||
# Frontend API
|
||||
|
||||
## 安装依赖
|
||||
|
||||
用你喜欢的包管理器安装 Artalk:
|
||||
|
||||
```bash
|
||||
pnpm add artalk
|
||||
# 或者使用 npm
|
||||
npm install artalk
|
||||
```
|
||||
|
||||
## 创建实例 `init`
|
||||
|
||||
调用该函数将创建并得到一个 Artalk 的实例化对象,可用于后续操作。
|
||||
|
||||
<!-- prettier-ignore-start -->
|
||||
|
||||
```js
|
||||
import Artalk from 'artalk'
|
||||
|
||||
const artalk = Artalk.init({
|
||||
el: '#Comments',
|
||||
pageKey: '/post/1',
|
||||
pageTitle: '关于引入 Artalk 的这档子事',
|
||||
server: 'http://your_domain:8080',
|
||||
site: 'Artalk 的博客',
|
||||
})
|
||||
```
|
||||
|
||||
<!-- prettier-ignore-end -->
|
||||
|
||||
调用该函数会异步地向后端发起请求:
|
||||
|
||||
1. 获取前端配置
|
||||
2. 获取评论列表
|
||||
|
||||
配置和插件加载完毕后会触发 `mounted` 事件。
|
||||
|
||||
评论列表加载完毕后会触发 `list-loaded` 事件。
|
||||
|
||||
> 注:前端界面配置可能会被覆盖,详情见:[界面配置](../guide/frontend/config.md)。
|
||||
|
||||
## 释放资源 `destroy`
|
||||
|
||||
销毁 Artalk 实例,用于资源释放。
|
||||
|
||||
```js
|
||||
const artalk = Artalk.init({ ... })
|
||||
|
||||
artalk.destroy()
|
||||
```
|
||||
|
||||
调用该函数时,将触发 `unmounted` 事件。释放资源将执行 Artalk 挂载的 DOM 节点删除,以及解除 Artalk 事件监听等操作。当该函数执行完毕后,Artalk 实例将不再可用。
|
||||
|
||||
在 Vue / React 等框架中,务必在组件销毁时调用该函数,否则会造成内存泄漏:
|
||||
|
||||
```ts
|
||||
import { onUnmounted } from 'vue'
|
||||
|
||||
onUnmounted(() => {
|
||||
artalk.destroy()
|
||||
})
|
||||
```
|
||||
|
||||
## 更新配置 `update`
|
||||
|
||||
修改 Artalk 当前配置。
|
||||
|
||||
```js
|
||||
const artalk = Artalk.init({ ... })
|
||||
|
||||
artalk.update({
|
||||
// 新的配置...
|
||||
})
|
||||
```
|
||||
|
||||
调用该函数将触发 `updated` 事件。
|
||||
|
||||
更新配置不会自动刷新评论列表,可按需继续执行 `artalk.reload()` 函数。
|
||||
|
||||
请注意,该函数是一个实例化对象中的成员方法,并非全局函数。
|
||||
|
||||
前端配置参考:[前端配置](../guide/frontend/config.md)
|
||||
|
||||
## 重新加载 `reload`
|
||||
|
||||
重新从后端加载 Artalk 评论列表数据。
|
||||
|
||||
```js
|
||||
const artalk = Artalk.init({ ... })
|
||||
|
||||
artalk.reload()
|
||||
```
|
||||
|
||||
列表加载前将触发 `list-load` 事件,加载完毕后将触发 `list-loaded` 事件。
|
||||
|
||||
## 监听事件 `on`
|
||||
|
||||
添加 Artalk 事件监听。
|
||||
|
||||
```js
|
||||
const artalk = Artalk.init({ ... })
|
||||
|
||||
artalk.on('list-loaded', (comments) => {
|
||||
// comments 包含当前页面所有评论数据 (而非仅本次请求获取的部分评论)
|
||||
console.log('评论列表加载完毕: ', comments)
|
||||
})
|
||||
```
|
||||
|
||||
可参考:[前端 Event](./event.md)。
|
||||
|
||||
## 解除监听 `off`
|
||||
|
||||
解除 Artalk 事件监听。
|
||||
|
||||
```js
|
||||
const artalk = Artalk.init({ ... })
|
||||
|
||||
const handler = () => {
|
||||
alert('评论列表加载完毕')
|
||||
}
|
||||
|
||||
artalk.on('list-loaded', handler)
|
||||
artalk.off('list-loaded', handler)
|
||||
```
|
||||
|
||||
## 触发事件 `trigger`
|
||||
|
||||
触发 Artalk 事件。
|
||||
|
||||
```js
|
||||
const artalk = Artalk.init({ ... })
|
||||
|
||||
artalk.trigger('list-loaded', [...])
|
||||
```
|
||||
|
||||
## 加载插件 `use`
|
||||
|
||||
通过 `Artalk.use` 函数加载插件。请注意,该函数是一个全局函数,并非实例化对象中的方法。通过该函数加载的插件将对所有 Artalk 实例生效。
|
||||
|
||||
```js
|
||||
import Artalk from 'artalk'
|
||||
|
||||
Artalk.use((ctx) => {
|
||||
ctx.editor.setContent("Hello World")
|
||||
})
|
||||
|
||||
const artalk = Artalk.init({ ... })
|
||||
```
|
||||
|
||||
详情见:[插件开发](./plugin.md)
|
||||
|
||||
## 夜间模式 `setDarkMode`
|
||||
|
||||
修改夜间模式,可以配合博客主题调用,例如当用户点击夜间模式切换按钮。
|
||||
|
||||
```js
|
||||
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()
|
||||
```
|
||||
@@ -4,12 +4,19 @@
|
||||
|
||||
<<< @/code/quick-start/cdn.html
|
||||
|
||||
#### 什么时候执行 `Artalk.init({})`?
|
||||
|
||||
- 可以在任意位置引入 JS 和 CSS 资源,但需确保 JS 引入在执行 `Artalk.init({})` 前。
|
||||
- 执行 `Artalk.init({ el: '#artalk' })` 前需要确保 `<div id="artalk"></div>` 在页面当中。
|
||||
|
||||
## Hugo
|
||||
|
||||
创建模板文件 `/主题目录/layouts/partials/comment/artalk.html`:
|
||||
|
||||
<!-- prettier-ignore-start -->
|
||||
|
||||
```html
|
||||
<link href="/lib/artalk/Artalk.css" rel="stylesheet">
|
||||
<link href="/lib/artalk/Artalk.css" rel="stylesheet" />
|
||||
<script src="/lib/artalk/Artalk.js"></script>
|
||||
|
||||
<!-- Artalk -->
|
||||
@@ -17,22 +24,22 @@
|
||||
|
||||
<script>
|
||||
Artalk.init({
|
||||
el: '#Comments',
|
||||
pageKey: '{{ .Permalink }}',
|
||||
el: '#Comments',
|
||||
pageKey: '{{ .Permalink }}',
|
||||
pageTitle: '{{ .Title }}',
|
||||
server: '{{ $.Site.Params.artalk.server }}',
|
||||
site: '{{ $.Site.Params.artalk.site }}',
|
||||
server: '{{ $.Site.Params.artalk.server }}',
|
||||
site: '{{ $.Site.Params.artalk.site }}',
|
||||
// ...你的其他配置
|
||||
})
|
||||
</script>
|
||||
```
|
||||
|
||||
<!-- prettier-ignore-end -->
|
||||
|
||||
文章页模板 `/主题目录/layouts/_default/single.html` 合适的位置添加:
|
||||
|
||||
```html
|
||||
<div class="article-comments">
|
||||
{{- partial "comment/artalk" . -}}
|
||||
</div>
|
||||
<div class="article-comments">{{- partial "comment/artalk" . -}}</div>
|
||||
```
|
||||
|
||||
修改 Hugo 配置文件:
|
||||
@@ -45,7 +52,6 @@ server = 'https://artalk.example.org'
|
||||
site = '你的站点名'
|
||||
```
|
||||
|
||||
|
||||
```yaml [config.yaml]
|
||||
params:
|
||||
artalk:
|
||||
@@ -60,7 +66,7 @@ params:
|
||||
创建 `/主题目录/layout/comment/artalk.ejs`:
|
||||
|
||||
```html
|
||||
<link href="/lib/artalk/Artalk.css" rel="stylesheet">
|
||||
<link href="/lib/artalk/Artalk.css" rel="stylesheet" />
|
||||
<script src="/lib/artalk/Artalk.js"></script>
|
||||
|
||||
<div id="Comments"></div>
|
||||
@@ -70,7 +76,7 @@ params:
|
||||
el: '#Comments',
|
||||
pageKey: '<%= page.permalink %>',
|
||||
pageTitle: '<%= page.title %>',
|
||||
server: '<%= theme.comment.artalk.server %>'
|
||||
server: '<%= theme.comment.artalk.server %>',
|
||||
site: '<%= theme.comment.artalk.site %>',
|
||||
})
|
||||
</script>
|
||||
@@ -79,9 +85,7 @@ params:
|
||||
修改文章模板文件,例如 `/主题目录/layout/post.ejs`:
|
||||
|
||||
```html
|
||||
<div class="article-comments">
|
||||
<%- partial('comment/artalk') %>
|
||||
</div>
|
||||
<div class="article-comments"><%- partial('comment/artalk') %></div>
|
||||
```
|
||||
|
||||
编辑主题配置 `/主题目录/_config.example.yml`:
|
||||
@@ -99,66 +103,26 @@ NexT 主题可以安装 [Hexo NexT 主题的 Artalk 插件](https://github.com/l
|
||||
|
||||
:::
|
||||
|
||||
## VitePress
|
||||
|
||||
可参考:[docs/.vitepress](https://github.com/ArtalkJS/Artalk/tree/master/docs/docs/.vitepress)
|
||||
|
||||
- `config.ts` 修改配置引入 CSS 资源
|
||||
- `theme/Artalk.vue` 创建组件
|
||||
- `theme/index.ts` 注册组件
|
||||
- `theme/Layout.vue` 使用组件
|
||||
|
||||
参考代码:[docs/.vitepress/theme/Artalk.vue](https://github.com/ArtalkJS/Artalk/blob/master/docs/docs/.vitepress/theme/Artalk.vue)
|
||||
|
||||
## VuePress
|
||||
|
||||
以 [VuePress v2](https://github.com/vuepress/vuepress-next) 为例,继承默认主题 `@vuepress/theme-default`
|
||||
(待补充)
|
||||
|
||||
可参考:[“/.vuepress/theme/Artalk.vue”](https://github.com/ArtalkJS/Docs/blob/eef37bca8cc0c9973bf121fdef4014dcd940f104/docs/.vuepress/theme/Artalk.vue) 创建 Artalk 评论组件。
|
||||
::: tip 提示
|
||||
|
||||
在 `/.vuepress/theme/clientAppEnhance.ts` 文件中全局注册组件:
|
||||
可参考:[置入框架](./import-framework.md)
|
||||
|
||||
```ts
|
||||
import { defineClientAppEnhance } from '@vuepress/client'
|
||||
|
||||
import Artalk from './Artalk.vue'
|
||||
|
||||
export default defineClientAppEnhance(({ app, router, siteData }) => {
|
||||
app.component('Artalk', Artalk)
|
||||
})
|
||||
```
|
||||
|
||||
主题布局 `/.vuepress/theme/Layout.vue`:
|
||||
|
||||
```vue
|
||||
<template>
|
||||
<Layout>
|
||||
<template #page-bottom>
|
||||
<div class="page-meta">
|
||||
<!-- Artalk -->
|
||||
<Artalk />
|
||||
</div>
|
||||
</template>
|
||||
</Layout>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent, nextTick } from 'vue'
|
||||
import { useRouter } from 'vue-router'
|
||||
import Layout from '@vuepress/theme-default/lib/client/layouts/Layout.vue'
|
||||
|
||||
export default defineComponent({
|
||||
components: { Layout },
|
||||
mounted: () => {
|
||||
}
|
||||
})
|
||||
</script>
|
||||
```
|
||||
|
||||
主题配置文件 `/.vuepress/theme/index.ts`:
|
||||
|
||||
```ts
|
||||
import { path } from '@vuepress/utils'
|
||||
|
||||
export default ({
|
||||
name: 'vuepress-theme-local',
|
||||
extends: '@vuepress/theme-default',
|
||||
layouts: {
|
||||
Layout: path.resolve(__dirname, 'Layout.vue'),
|
||||
},
|
||||
clientAppEnhanceFiles: path.resolve(__dirname, 'clientAppEnhance.ts'),
|
||||
})
|
||||
```
|
||||
:::
|
||||
|
||||
## Typecho
|
||||
|
||||
@@ -0,0 +1,227 @@
|
||||
# 置入框架
|
||||
|
||||
## 安装 Artalk
|
||||
|
||||
通过包管理工具引入 Artalk,推荐使用 [pnpm](https://pnpm.io/zh/)
|
||||
|
||||
```bash
|
||||
pnpm add artalk
|
||||
```
|
||||
|
||||
## Vue
|
||||
|
||||
::: code-group
|
||||
|
||||
```vue [Vue 3]
|
||||
<script lang="ts" setup>
|
||||
import Artalk from 'artalk'
|
||||
import { onMounted, onBeforeUnmount, ref } from 'vue'
|
||||
|
||||
import 'artalk/dist/Artalk.css'
|
||||
|
||||
const el = ref<HTMLElement>()
|
||||
|
||||
let artalk: Artalk
|
||||
|
||||
onMounted(() => {
|
||||
artalk = Artalk.init({
|
||||
el: el.value,
|
||||
pageKey: location.pathname,
|
||||
pageTitle: `${document.title}`,
|
||||
server: 'http://localhost:8080',
|
||||
site: 'Artalk 的博客',
|
||||
// ...
|
||||
})
|
||||
})
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
artalk.destroy()
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<view ref="el"></view>
|
||||
</template>
|
||||
```
|
||||
|
||||
```vue [Vue 3 + Vue Router]
|
||||
<script lang="ts" setup>
|
||||
import Artalk from 'artalk'
|
||||
import { onMounted, onBeforeUnmount, ref, watch, nextTick } from 'vue'
|
||||
import { useRouter } from 'vue-router'
|
||||
|
||||
import 'artalk/dist/Artalk.css'
|
||||
|
||||
const el = ref<HTMLElement>()
|
||||
const router = useRouter()
|
||||
|
||||
let artalk: Artalk
|
||||
|
||||
onMounted(() => {
|
||||
artalk = Artalk.init({
|
||||
el: el.value,
|
||||
pageKey: router.route.path,
|
||||
pageTitle: document.title,
|
||||
server: 'http://localhost:8080',
|
||||
site: 'Artalk 的博客',
|
||||
// ...
|
||||
})
|
||||
})
|
||||
|
||||
watch(
|
||||
() => router.route.path,
|
||||
(path) => {
|
||||
nextTick(() => {
|
||||
artalk.update({
|
||||
pageKey: path,
|
||||
pageTitle: document.title,
|
||||
})
|
||||
artalk.reload()
|
||||
})
|
||||
}
|
||||
)
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
artalk.destroy()
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<view ref="el"></view>
|
||||
</template>
|
||||
```
|
||||
|
||||
:::
|
||||
|
||||
## React
|
||||
|
||||
::: code-group
|
||||
|
||||
```tsx [React Hooks]
|
||||
import React, { useEffect, useRef } from 'react'
|
||||
import { useLocation } from 'react-router-dom'
|
||||
import 'artalk/dist/Artalk.css'
|
||||
import Artalk from 'artalk'
|
||||
|
||||
const ArtalkComment = () => {
|
||||
const container = useRef<HTMLDivElement>(null)
|
||||
const location = useLocation()
|
||||
const artalk = useRef<Artalk>()
|
||||
|
||||
useEffect(() => {
|
||||
artalk.current = Artalk.init({
|
||||
el: container.current!,
|
||||
pageKey: location.pathname,
|
||||
pageTitle: document.title,
|
||||
server: 'http://localhost:8080',
|
||||
site: 'Artalk 的博客',
|
||||
// ...
|
||||
})
|
||||
|
||||
return () => {
|
||||
artalk.current?.destroy()
|
||||
}
|
||||
}, [container, location.pathname])
|
||||
|
||||
return <div ref={container}></div>
|
||||
}
|
||||
|
||||
export default ArtalkComment
|
||||
```
|
||||
|
||||
|
||||
|
||||
```jsx [React Class]
|
||||
import React, { createRef } from 'react'
|
||||
import 'artalk/dist/Artalk.css'
|
||||
import Artalk from 'artalk'
|
||||
|
||||
export default class Artalk extends React.Component {
|
||||
el = createRef()
|
||||
artalk = null
|
||||
|
||||
componentDidMount() {
|
||||
this.artalk = Artalk.init({
|
||||
el: this.el.current,
|
||||
pageKey: location.pathname,
|
||||
pageTitle: document.title,
|
||||
server: 'http://localhost:8080',
|
||||
site: 'Artalk 的博客',
|
||||
// ...
|
||||
})
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
this.artalk?.destroy()
|
||||
}
|
||||
|
||||
render() {
|
||||
return <div ref={this.el} />
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
:::
|
||||
|
||||
## SolidJS
|
||||
|
||||
```tsx
|
||||
import { onCleanup, onMount } from 'solid-js'
|
||||
import Artalk from 'artalk'
|
||||
import 'artalk/dist/Artalk.css'
|
||||
|
||||
const ArtalkComment = () => {
|
||||
let el: HTMLDivElement
|
||||
let artalk: Artalk
|
||||
|
||||
onMount(() => {
|
||||
artalk = Artalk.init({
|
||||
el: el,
|
||||
pageKey: location.pathname,
|
||||
pageTitle: document.title,
|
||||
server: 'http://localhost:8080',
|
||||
site: 'Artalk 的博客',
|
||||
// ...
|
||||
})
|
||||
|
||||
onCleanup(() => {
|
||||
artalk.destroy()
|
||||
})
|
||||
})
|
||||
|
||||
return <div ref={el} />
|
||||
}
|
||||
```
|
||||
|
||||
## Svelte
|
||||
|
||||
```html
|
||||
<script>
|
||||
import Artalk from 'artalk'
|
||||
import { onMount, onDestroy } from 'svelte'
|
||||
|
||||
import 'artalk/dist/Artalk.css'
|
||||
|
||||
let el
|
||||
let artalk
|
||||
|
||||
onMount(() => {
|
||||
artalk = Artalk.init({
|
||||
el: el,
|
||||
pageKey: location.pathname,
|
||||
pageTitle: document.title,
|
||||
server: 'http://localhost:8080',
|
||||
site: 'Artalk 的博客',
|
||||
// ...
|
||||
})
|
||||
|
||||
onDestroy(() => {
|
||||
if (artalk) {
|
||||
artalk.destroy()
|
||||
}
|
||||
})
|
||||
})
|
||||
</script>
|
||||
|
||||
<div bind:this="{el}"></div>
|
||||
```
|
||||
@@ -0,0 +1,39 @@
|
||||
# 开发文档
|
||||
|
||||
欢迎来到 Artalk 官方开发文档,这里提供了构建 Artalk 插件和主题的指南。如果你需要搭建 Artalk 的开发环境,可以阅读 [开发者贡献指南](./contributing.md)。
|
||||
|
||||
感谢对 Artalk 的关注和支持。我们深知开源项目的成功离不开每一位开发者的贡献,无论是代码、文档、测试还是意见反馈,您的参与都是推动项目不断前进的动力。诚挚地邀请您加入我们,共同完善和提升 Artalk。
|
||||
|
||||
## 索引
|
||||
|
||||
- [开发者贡献指南](./contributing.md) ⭐️
|
||||
|
||||
**前端界面**
|
||||
|
||||
- [置入博客](./import-blog.md)
|
||||
- [置入框架](./import-framework.md)
|
||||
- [前端 API 文档](./fe-api.md)
|
||||
- [前端 Event](./event.md)
|
||||
- [前端配置](../guide/frontend/config.md)
|
||||
|
||||
**插件开发**
|
||||
|
||||
- [插件开发](./plugin.md)
|
||||
- [插件开发 Vite 集成](https://github.com/ArtalkJS/Artalk/blob/master/ui/plugin-kit/README.md)
|
||||
|
||||
**后端程序**
|
||||
|
||||
- <a href="/http-api.html" target="_blank">HTTP API 文档</a>
|
||||
- [环境变量](../guide/env.md)
|
||||
- [配置文件](../guide/backend/config.md)
|
||||
|
||||
**其他内容**
|
||||
|
||||
- [兼容性](../develop/compatibility.md)
|
||||
- [更新日志](https://github.com/ArtalkJS/Artalk/blob/master/CHANGELOG.md)
|
||||
- [i18n 多语言贡献指南](../guide/frontend/i18n.md#贡献翻译)
|
||||
- [贡献者契约行为准则](https://github.com/ArtalkJS/Artalk/blob/master/CODE_OF_CONDUCT.md)
|
||||
|
||||
::: tip
|
||||
Artalk 正处于积极维护阶段,请注意 API 版本兼容性。升级可能有突破性变更参考 [更新日志](https://github.com/ArtalkJS/Artalk/blob/master/CHANGELOG.md)。
|
||||
:::
|
||||
@@ -0,0 +1,130 @@
|
||||
# 插件开发
|
||||
|
||||
## 使用 Vite 开发
|
||||
|
||||
我们提供了 Vite 的集成插件,使用 Vite 开发能够开箱即用地构建 Artalk 插件,简化 Vite 配置。
|
||||
|
||||
参考文档:[@artalk/plugin-kit](https://github.com/ArtalkJS/Artalk/blob/master/ui/plugin-kit/README.md)。
|
||||
|
||||
同时,我们提供了一个模版代码仓库,你可以直接 fork 来开发插件:[artalk-plugin-sample](https://github.com/ArtalkJS/artalk-plugin-sample)。
|
||||
|
||||
通过 Vite 结合前端生态,你可以任选你喜欢的技术栈,如 Vue、React、Svelte、SolidJS 等框架开发 Artalk 插件。
|
||||
|
||||
## `Artalk.use`
|
||||
|
||||
使用 `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 对象。
|
||||
|
||||
### 插件可配置选项
|
||||
|
||||
在 TypeScript 中,你可以通过 `ArtalkPlugin<T>` 来定义一个带选项的插件类型。
|
||||
|
||||
```ts
|
||||
export interface DemoPluginOptions {
|
||||
foo?: string
|
||||
}
|
||||
|
||||
export const ArtalkDemoPlugin: ArtalkPlugin<DemoPluginOptions> = (ctx, options = {}) => {
|
||||
console.log(options.foo)
|
||||
}
|
||||
```
|
||||
|
||||
在执行 `Artalk.use` 时,传入选项:
|
||||
|
||||
```ts
|
||||
import { ArtalkDemoPlugin } from 'artalk-plugin-demo'
|
||||
|
||||
Artalk.use(ArtalkDemoPlugin, { foo: 'bar' })
|
||||
```
|
||||
|
||||
## ContextAPI
|
||||
|
||||
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 官方维护的外置插件列表:
|
||||
|
||||
| 插件 | 说明 |
|
||||
| -------------------------------------------------------------------------------------------- | -------------- |
|
||||
| [artalk-plugin-sample](https://github.com/ArtalkJS/artalk-plugin-sample) | 示例插件 |
|
||||
| [@artalk/plugin-katex](https://github.com/ArtalkJS/Artalk/tree/master/ui/plugin-katex) | LaTeX 公式插件 |
|
||||
| [@artalk/plugin-auth](https://github.com/ArtalkJS/Artalk/tree/master/ui/plugin-auth) | Auth 插件 (SolidJS) |
|
||||
| [@artalk/plugin-lightbox](https://github.com/ArtalkJS/Artalk/tree/master/ui/plugin-lightbox) | 图片灯箱基础插件 |
|
||||
|
||||
同时 Artalk 内部也有很多插件的实现,你可以参考源码来开发插件:
|
||||
|
||||
[@ArtalkJS/Artalk - src/plugins](https://github.com/ArtalkJS/Artalk/tree/master/ui/artalk/src/plugins)
|
||||
|
||||
## 后端插件开发
|
||||
|
||||
【TODO】
|
||||
@@ -0,0 +1,7 @@
|
||||
# 插件开发
|
||||
|
||||
本页面内容已移动至 <https://artalk.js.org/develop/plugin.html>。
|
||||
|
||||
<script setup lang="ts">
|
||||
if (!import.meta.env.SSR) window.location = 'https://artalk.js.org/develop/plugin.html';
|
||||
</script>
|
||||
@@ -2,11 +2,11 @@
|
||||
layout: home
|
||||
|
||||
title: Artalk
|
||||
titleTemplate: The Selfhosted Comment System
|
||||
titleTemplate: A Self-hosted Comment System
|
||||
|
||||
hero:
|
||||
name: Artalk
|
||||
text: The Selfhosted Comment System
|
||||
text: A Self-hosted Comment System
|
||||
tagline: Elevate your online conversations with a comment system that embodies the trifecta of lightness, security, and refinement.
|
||||
actions:
|
||||
- theme: brand
|
||||
@@ -30,4 +30,3 @@ features:
|
||||
title: Flexible
|
||||
details: Use Golang to interpret the excellence of multiple platforms
|
||||
---
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
# 🥬 关于我们
|
||||
|
||||
## ~~开发团队有人想自我介绍一下~~
|
||||
|
||||
[@qwqcode](https://github.com/qwqcode):🥬 + 🦜
|
||||
|
||||
The Artalk. Made with <span style="color: red;">♥️</span>.
|
||||
@@ -4,7 +4,7 @@ Artalk 支持通过多元推送功能以多种方式发送管理员通知。
|
||||
|
||||
支持 **Telegram**、**飞书**、**钉钉**、**Bark**、**Slack**、**LINE**,并且多种方式可以同时启用。
|
||||
|
||||
你可以在[控制中心](/guide/frontend/sidebar.md#控制中心)找到「设置」界面修改此配置。
|
||||
你可以在 [控制中心](/guide/frontend/sidebar.md#设置) 的设置界面修改此配置,也可以通过 [配置文件](/guide/backend/config.md#多元推送-admin-notify) 或 [环境变量](/guide/env.md#多元推送) 进行配置。
|
||||
|
||||
## 配置文件
|
||||
|
||||
@@ -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
|
||||
```
|
||||
@@ -113,7 +113,7 @@ admin_notify:
|
||||
|
||||

|
||||
|
||||
详情可参考:[“Bots: An introduction for developers - Telegram”](https://core.telegram.org/bots)
|
||||
详情可参考:[Bots: An introduction for developers - Telegram](https://core.telegram.org/bots)
|
||||
|
||||
::: tip
|
||||
|
||||
@@ -132,7 +132,7 @@ admin_notify:
|
||||
# 飞书
|
||||
lark:
|
||||
enabled: true
|
||||
webhook_url: ""
|
||||
webhook_url: ''
|
||||
```
|
||||
|
||||
- `webhook_url`:填入创建群组机器人时得到的 WebHook 地址。
|
||||
@@ -151,7 +151,7 @@ admin_notify:
|
||||
|
||||
<img src="/images/notify/lark-3.png" width="400px">
|
||||
|
||||
可参考:[“飞书帮助中心文档”](https://www.feishu.cn/hc/zh-CN/articles/360024984973)
|
||||
可参考:[飞书帮助中心文档](https://www.feishu.cn/hc/zh-CN/articles/360024984973)
|
||||
|
||||
## 钉钉
|
||||
|
||||
@@ -160,11 +160,11 @@ admin_notify:
|
||||
# 钉钉
|
||||
ding_talk:
|
||||
enabled: true
|
||||
token: ""
|
||||
secret: ""
|
||||
token: ''
|
||||
secret: ''
|
||||
```
|
||||
|
||||
可参考:[“钉钉开放文档”](https://open.dingtalk.com/document/robots/custom-robot-access)
|
||||
可参考:[钉钉开放文档](https://open.dingtalk.com/document/robots/custom-robot-access)
|
||||
|
||||
## Bark
|
||||
|
||||
@@ -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` 可设置为自定义通知模版「文件路径」,默认的通知模版为:
|
||||
@@ -227,7 +225,16 @@ admin_notify:
|
||||
{{link_to_reply}}
|
||||
```
|
||||
|
||||
可用变量和邮件模板相同,可参考:[“邮件模版”](./email.md#邮件模板)
|
||||
可用变量和邮件模板相同,可参考:[邮件模版](./email.md#邮件模板)
|
||||
|
||||
## 待审评论仍然发送通知 `notify_pending`
|
||||
|
||||
```yaml
|
||||
admin_notify:
|
||||
notify_pending: false
|
||||
```
|
||||
|
||||
`notify_pending` 默认为关闭状态,当该项设置为 `false` 时,待审评论不会发送通知。你可以在控制中心查看所有待审核的评论。
|
||||
|
||||
## 嘈杂模式 `noise_mode`
|
||||
|
||||
@@ -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| Root 根节点评论类型改项为 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))
|
||||
}
|
||||
```
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
# 后端构建
|
||||
|
||||
本页面内容已移动至 <https://artalk.js.org/develop/contributing.html>。
|
||||
|
||||
<script setup lang="ts">
|
||||
if (!import.meta.env.SSR) window.location = 'https://artalk.js.org/develop/contributing.html';
|
||||
</script>
|
||||
@@ -6,7 +6,7 @@ Artalk 内置图片验证码功能,你可以配置操作频率限制,当超
|
||||
|
||||
目前 Artalk 支持:Turnstile、reCAPTCHA、hCaptcha、极验。
|
||||
|
||||
你可以在[控制中心](/guide/frontend/sidebar.md#控制中心)找到「设置」界面修改此配置。
|
||||
你可以在 [控制中心](/guide/frontend/sidebar.md#设置) 的设置界面修改此配置,也可以通过 [配置文件](/guide/backend/config.md#验证码-captcha) 或 [环境变量](/guide/env.md#验证码) 进行配置。
|
||||
|
||||
## 配置文件
|
||||
|
||||
@@ -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: ''
|
||||
```
|
||||
|
||||
@@ -1,9 +1,13 @@
|
||||
# 后端配置
|
||||
# 配置文件
|
||||
|
||||
## 轻松配置
|
||||
|
||||
推荐在侧边栏 “[控制中心](/guide/frontend/sidebar.md)” 通过图形界面修改配置,无需手动编辑配置文件。
|
||||
|
||||
## 环境变量
|
||||
|
||||
可通过环境变量配置,参考文档:[环境变量](../env.md)。
|
||||
|
||||
## 指定配置文件路径
|
||||
|
||||
Artalk 默认以工作目录下的 `artalk.yml` 作为配置文件,可使用参数 `-c` 来指定具体文件:
|
||||
@@ -12,30 +16,11 @@ Artalk 默认以工作目录下的 `artalk.yml` 作为配置文件,可使用
|
||||
artalk -c ./conf.yml
|
||||
```
|
||||
|
||||
## 通过环境变量配置
|
||||
|
||||
Artalk 读取以 `ATK_` 为前缀的环境变量,并且全部大写,子节点用单个下划线表示,配置名含下划线请用双下划线表示:
|
||||
|
||||
- `_` (单下划线) 转为 `.` 表示子节点
|
||||
- `__` (双下划线) 转为 `_` 表示配置名的下划线
|
||||
|
||||
e.g.
|
||||
|
||||
```bash
|
||||
ATK_TIMEZONE -> timezone
|
||||
ATK_LOGIN__TIMEOUT -> login_timeout
|
||||
ATK_SITE__DEFAULT -> site_default
|
||||
ATK_DB_TYPE -> db.type
|
||||
ATK_DB_TABLE__PREFIX -> db.table_prefix
|
||||
ATK_CACHE_REDIS_USERNAME -> cache.redis.username
|
||||
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 +28,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 +39,7 @@ wget -O artalk.yml https://raw.githubusercontent.com/ArtalkJS/Artalk/master/conf
|
||||
在 Artalk 启动之前,你需要配置一个 `app_key` 用于对网站内容进行安全加密:
|
||||
|
||||
```yaml
|
||||
app_key: "<任意的字符>"
|
||||
app_key: <任意的字符>
|
||||
```
|
||||
|
||||
## 语言 `locale`
|
||||
@@ -62,10 +47,10 @@ app_key: "<任意的字符>"
|
||||
设置 Artalk 的语言。遵循 Unicode BCP 47 规范,该项默认为 "zh-CN" (简体中文)。
|
||||
|
||||
```yml
|
||||
locale: "zh-CN"
|
||||
locale: zh-CN
|
||||
```
|
||||
|
||||
详情参考:[“多语言”](../frontend/i18n.md)
|
||||
详情参考:[多语言](../frontend/i18n.md)
|
||||
|
||||
## 数据库 `db`
|
||||
|
||||
@@ -77,8 +62,8 @@ SQLite 是轻型数据库,使用单个文件存储数据,无需额外运行
|
||||
|
||||
```yaml
|
||||
db:
|
||||
type: "sqlite"
|
||||
file: "./data/artalk.db"
|
||||
type: sqlite
|
||||
file: ./data/artalk.db
|
||||
```
|
||||
|
||||
#### MySQL / PostgreSQL / SQL Server
|
||||
@@ -87,126 +72,153 @@ db:
|
||||
|
||||
```yaml
|
||||
db:
|
||||
type: "mysql" # sqlite, mysql, pgsql, mssql
|
||||
name: "artalk" # 数据库名
|
||||
host: "localhost" # 地址
|
||||
port: "3306" # 端口
|
||||
user: "root" # 账号
|
||||
password: "" # 密码
|
||||
charset: "utf8mb4" # 编码格式
|
||||
table_prefix: "" # 表前缀 (例如:"atk_")
|
||||
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 启动时自动完成创建,无需额外操作。
|
||||
|
||||
#### 数据库连接字符串 (DSN)
|
||||
|
||||
如有需要,你还可以手动配置 `db.dsn` 来指定数据库连接字符串,例如:
|
||||
|
||||
```yaml
|
||||
db:
|
||||
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)
|
||||
|
||||
## 服务器 `http`
|
||||
|
||||
```yaml
|
||||
http:
|
||||
# 请求体大小限制 (单位:MB)
|
||||
body_limit: 100
|
||||
# 代理标头名 (当使用 CDN 时填写 `X-Forwarded-For` 获取用户真实 IP)
|
||||
proxy_header: ""
|
||||
```
|
||||
|
||||
## 管理员 `admin_users`
|
||||
|
||||
你需要配置管理员账户,这样才能通过「[控制中心](../frontend/sidebar.md)」对站点内容进行管理。
|
||||
|
||||
Artalk 支持多站点,你可以创建多个管理员账户,为其分配站点,让你的朋友们共用同一个后端程序。
|
||||
|
||||
详情参考:[“管理员 × 多站点”](/guide/backend/multi-site.md)
|
||||
详情参考:[管理员 × 多站点](/guide/backend/multi-site.md)
|
||||
|
||||
## 可信域名 `trusted_domains`
|
||||
|
||||
```yaml
|
||||
trusted_domains:
|
||||
- "https://前端使用域名A.com"
|
||||
- "https://前端使用域名B.com"
|
||||
- https://前端使用域名A.com
|
||||
- https://前端使用域名B.com
|
||||
```
|
||||
|
||||
配置该项能限制来自列表外的 Referer 和跨域请求。
|
||||
仅允许列表中的域名访问后端 API,限制来自列表外的域名跨域请求。
|
||||
|
||||
:::tip
|
||||
|
||||
你需要将「使用该后端的前端」URL 地址加入可信域名列表中,
|
||||
你需要将「前端页面」的 URL 地址加入可信域名列表中,
|
||||
|
||||
若非默认 80/443 端口需额外附带端口号,例如:`https://example.com:8080`
|
||||
|
||||
:::
|
||||
|
||||
在侧边栏[控制中心](../frontend/sidebar.md#控制中心)「站点」选项卡 - 选择站点「修改 URL」,填入站点 URL 也具有相同的效果;添加多个 URL 可使用 `","` 英文逗号分隔,修改后请重启 Artalk。
|
||||
在侧边栏 [控制中心](../frontend/sidebar.md#控制中心) 的「站点」选项卡 - 选择站点「修改 URL」,填入站点 URL 也具有相同的设置效果;添加多个 URL 可使用 `,` 英文逗号分隔,修改后请手动重启 Artalk。
|
||||
|
||||
可以将其关闭:
|
||||
默认站点地址 `ATK_SITE_URL` 配置项也会被自动加入可信域名列表。
|
||||
|
||||
```yaml
|
||||
trusted_domains:
|
||||
- "*"
|
||||
另外,你也可以在启动时通过环境变量 `ATK_TRUSTED_DOMAINS` 来配置可信域名,例如:
|
||||
|
||||
```bash
|
||||
ATK_TRUSTED_DOMAINS="https://a.com https://b.org" artalk server
|
||||
```
|
||||
|
||||
::: danger
|
||||
请注意,环境变量将覆盖配置文件中的设置。
|
||||
|
||||
但并不建议这样做,关闭后将存在潜在安全风险,例如可能遭受 CSRF 跨域攻击。
|
||||
|
||||
:::
|
||||
|
||||
细节:`trusted_domains` 配置项实际上是对响应标头:
|
||||
|
||||
- `Access-Control-Allow-Origin` 的控制 (参考:[W3C Cross-Origin Resource Sharing](https://fetch.spec.whatwg.org/#http-cors-protocol))
|
||||
- `Referer` 的限制 (参考:[Referer - HTTP | MDN](https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Headers/Referer))
|
||||
|
||||
CSRF 跨域攻击防范措施参考:[OWASP 安全备忘单](https://cheatsheetseries.owasp.org/cheatsheets/Cross-Site_Request_Forgery_Prevention_Cheat_Sheet.html)
|
||||
技术细节:`trusted_domains` 配置通过控制 HTTP 响应标头 `Access-Control-Allow-Origin` 来对跨域请求进行限制 (参考:[W3C Cross-Origin Resource Sharing](https://fetch.spec.whatwg.org/#http-cors-protocol) / [OWASP 安全备忘单](https://cheatsheetseries.owasp.org/cheatsheets/Cross-Site_Request_Forgery_Prevention_Cheat_Sheet.html)).
|
||||
|
||||
## 默认站点 `site_default`
|
||||
|
||||
如果你觉得大概是不会用到 Artalk 的多站点功能,可以直接将该项配置为你的站点名,例如:
|
||||
|
||||
```yaml
|
||||
site_default: "Artalk 官网"
|
||||
site_default: Artalk 官网
|
||||
```
|
||||
|
||||
然后在前端直接使用这个站点名:
|
||||
|
||||
```js
|
||||
Artalk.init({ site: "Artalk 官网" })
|
||||
Artalk.init({ site: 'Artalk 官网' })
|
||||
```
|
||||
|
||||
这样,你就无需在侧边栏的[控制中心](../frontend/sidebar.md#控制中心)手动创建站点。
|
||||
|
||||
## 前端配置 `frontend`
|
||||
## 界面配置 `frontend`
|
||||
|
||||
增加 `frontend` 字段内容可以在后端控制前端的配置,详情可参考:[“在后端控制前端”](/guide/backend/fe-control)。
|
||||
在 Artalk 的配置文件 `artalk.yml` 可以配置 `frontend` 字段来控制前端界面,例如:
|
||||
|
||||
```yaml
|
||||
frontend:
|
||||
placeholder: 键入内容...
|
||||
noComment: 「此时无声胜有声」
|
||||
sendBtn: 发送评论
|
||||
emoticons: 'https://raw.githubusercontent.com/ArtalkJS/Emoticons/master/grps/default.json'
|
||||
# ----- 此处省略 -------
|
||||
# 与前端配置项名称保持一致
|
||||
```
|
||||
|
||||
一份完整的后端 `frontend` 字段配置文件可供参考:[artalk.example.zh-CN.yml](https://github.com/ArtalkJS/Artalk/blob/master/conf/artalk.example.zh-CN.yml)
|
||||
|
||||
## 邮件通知 `email`
|
||||
|
||||
配置邮件通知,让回复通过邮件的形式通知目标用户,你可以自定义邮件发送者名称、标题、模版等。
|
||||
|
||||
详情参考:[“后端 · 邮件通知”](/guide/backend/email.md)
|
||||
详情参考:[后端 · 邮件通知](/guide/backend/email.md)
|
||||
|
||||
## 多元推送 `admin_notify`
|
||||
|
||||
你可以配置多种消息发送方式,例如飞书、Telegram 等,当收到新的评论时通知管理员。
|
||||
|
||||
详情参考:[“后端 · 多元推送”](/guide/backend/admin_notify.md)
|
||||
详情参考:[后端 · 多元推送](/guide/backend/admin_notify.md)
|
||||
|
||||
## 评论审核 `moderator`
|
||||
|
||||
配置评论审核来自动拦截垃圾评论。
|
||||
|
||||
详情参考:[“后端 · 评论审核”](/guide/backend/moderator.md)
|
||||
详情参考:[后端 · 评论审核](/guide/backend/moderator.md)
|
||||
|
||||
## 验证码 `captcha`
|
||||
|
||||
支持图片、滑动验证码,通过验证码对请求频率进行限制。
|
||||
|
||||
详情参考:[“后端 · 验证码”](/guide/backend/captcha.md)
|
||||
详情参考:[后端 · 验证码](/guide/backend/captcha.md)
|
||||
|
||||
## 缓存配置 `cache`
|
||||
## 高速缓存 `cache`
|
||||
|
||||
为了提高评论系统的响应速度和性能,Artalk 内置一套缓存机制,并且默认开启,无需额外配置。但如果有需要,你也可以连接外部缓存服务器,支持 Redis 和 Memcache。
|
||||
为节省内存资源占用,缓存默认关闭。如果你对网站性能有较高要求,请手动开启。你还可以连接外部缓存服务器,支持 Redis 和 Memcache。
|
||||
|
||||
```yaml
|
||||
cache:
|
||||
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 启动时会立刻对数据库内容进行全面缓存,如果你的评论数据较多,多达上万条,启动时间可能会延长。
|
||||
- **type**:缓存类型。可选:`redis`, `memcache`, `builtin`。
|
||||
|
||||
type 默认为 `builtin`,如遇特殊情况可将缓存关闭,将其设置为 `disabled`。
|
||||
- **type**:缓存类型,默认为 `builtin`。可选:`redis`, `memcache`, `builtin`。
|
||||
|
||||
注:如果在 Artalk 程序外部修改数据库内容,需要刷新 Artalk 缓存才能更新。
|
||||
|
||||
@@ -219,22 +231,21 @@ 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)
|
||||
|
||||

|
||||
<!-- 技术细节:[Artalk 缓存机制 时序图.png](/images/artalk/artalk-cache.png) -->
|
||||
<!--  -->
|
||||
|
||||
## 监听地址 `host`
|
||||
|
||||
Artalk 的默认 HTTP 端口为 23366,你可以在配置文件中指定:
|
||||
|
||||
```yaml
|
||||
host: "0.0.0.0"
|
||||
host: '0.0.0.0'
|
||||
port: 23366
|
||||
```
|
||||
|
||||
@@ -253,8 +264,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 协议加密传输数据。
|
||||
@@ -267,7 +278,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)。
|
||||
@@ -296,9 +307,17 @@ login_timeout: 259200
|
||||
```yaml
|
||||
log:
|
||||
enabled: true # 总开关
|
||||
filename: "./data/artalk.log" # 日志文件路径
|
||||
filename: ./data/artalk.log # 日志文件路径
|
||||
```
|
||||
|
||||
日志为 JSON 格式,可以通过使用 Linux 的 `tail` 命令结合 `jq` 工具查看:
|
||||
|
||||
```bash
|
||||
tail -f ./data/artalk.log | jq
|
||||
```
|
||||
|
||||
如果你是 Grafana 用户,可以结合 Loki 和 Promtail 来实现日志的收集和查询。
|
||||
|
||||
## 调试模式 `debug`
|
||||
|
||||
将 `debug` 配置为 `true` 启用调试模式。
|
||||
@@ -328,7 +347,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`。
|
||||
@@ -337,5 +356,5 @@ test_file: "./data/artalk.log"
|
||||
|
||||
配置文件相关代码:[/internal/config/config.go](https://github.com/ArtalkJS/Artalk/blob/master/internal/config/config.go)
|
||||
|
||||
前往:[“前端配置”](/guide/frontend/config.md)
|
||||
前往:[前端配置](/guide/frontend/config.md)
|
||||
:::
|
||||
@@ -0,0 +1,144 @@
|
||||
# 守护进程
|
||||
|
||||
## Systemd
|
||||
|
||||
前提条件:
|
||||
|
||||
- Artalk 二进制文件,可在 [GitHub Release](https://github.com/ArtalkJS/Artalk/releases) 下载
|
||||
- `systemctl --version` 232 或更新的版本
|
||||
- `sudo` 管理员权限
|
||||
|
||||
移动 Artalk 到 `$PATH`,例如:
|
||||
|
||||
```bash
|
||||
sudo mv artalk /usr/bin/
|
||||
```
|
||||
|
||||
测试是否有效:
|
||||
|
||||
```bash
|
||||
artalk version
|
||||
```
|
||||
|
||||
创建名为 artalk 的用户组:
|
||||
|
||||
```bash
|
||||
sudo groupadd --system artalk
|
||||
```
|
||||
|
||||
创建一个名为 artalk 的用户,并且拥有一个可写的 home 目录:
|
||||
|
||||
```bash
|
||||
sudo useradd --system \
|
||||
--gid artalk \
|
||||
--create-home \
|
||||
--home-dir /var/lib/artalk \
|
||||
--shell /usr/sbin/nologin \
|
||||
--comment "Artalk server" \
|
||||
artalk
|
||||
```
|
||||
|
||||
如果你有 Artalk 的配置文件,请确保刚刚创建的 artalk 用户有权限可以读取。
|
||||
|
||||
创建服务文件:
|
||||
|
||||
```bash
|
||||
sudo vim /etc/systemd/system/artalk.service
|
||||
```
|
||||
|
||||
```ini
|
||||
[Unit]
|
||||
Description=Artalk
|
||||
Documentation=https://artalk.js.org
|
||||
After=network.target network-online.target
|
||||
Requires=network-online.target
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
User=artalk
|
||||
Group=artalk
|
||||
ExecStart=/usr/bin/artalk server -w /var/lib/artalk -c /etc/artalk/artalk.yml
|
||||
ExecReload=/bin/kill -s HUP $MAINPID
|
||||
ExecStop=/bin/kill -s QUIT $MAINPID
|
||||
TimeoutStopSec=5s
|
||||
LimitNOFILE=1048576
|
||||
LimitNPROC=512
|
||||
PrivateTmp=true
|
||||
ProtectSystem=full
|
||||
AmbientCapabilities=CAP_NET_ADMIN CAP_NET_BIND_SERVICE
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
```
|
||||
|
||||
请仔细检查 `ExecStart` 和 `ExecReload`。 确保二进制文件的位置和程序启动参数是正确的
|
||||
|
||||
例如:更改 `-c` 参数的路径来指定配置文件,`-w` 参数可以更改工作目录。
|
||||
|
||||
请注意配置文件中的所有相对路径都是基于工作目录,例如配置文件中的 `./data/` 文件夹,如果启动参数 `-w /var/lib/artalk`,将读取 `/var/lib/artalk/data/` 目录。请确保该目录中的文件对于创建的 `artalk` 账户有权限可读写。
|
||||
|
||||
保存服务文件后,你可以设置自动启动服务:
|
||||
|
||||
```bash
|
||||
sudo systemctl daemon-reload
|
||||
sudo systemctl enable --now artalk
|
||||
```
|
||||
|
||||
验证服务是否正常运行:
|
||||
|
||||
```bash
|
||||
systemctl status artalk
|
||||
```
|
||||
|
||||
一些常用的命令:
|
||||
|
||||
- 启动服务:`systemctl start artalk`
|
||||
- 停止服务:`systemctl stop artalk`
|
||||
- 查看状态:`systemctl status artalk`
|
||||
- 查看日志:`journalctl -u artalk --no-pager | less +G`
|
||||
|
||||
## Tmux
|
||||
|
||||
tmux 将创建一个持续的命令行会话,在 SSH 或 tty 断开后保持在后台。
|
||||
|
||||
Note: 服务器关闭或重启后,tmux 会话将被清除,需要手动重新运行程序。
|
||||
|
||||
1. 创建会话 `tmux new -s artalk`
|
||||
2. 运行程序 `./artalk server`
|
||||
|
||||
恢复接入会话:`tmux attach -t artalk`
|
||||
|
||||
查看所有会话:`tmux ls`
|
||||
|
||||
## Supervisor
|
||||
|
||||
以宝塔面板举例:打开「软件商店」,搜索并安装「Supervisor管理器」:
|
||||
|
||||

|
||||
|
||||
安装后,打开插件,点击「添加守护程序」:
|
||||
|
||||

|
||||
|
||||
> - 启动用户:`root` 或其他
|
||||
> - 运行目录:点击右侧图标,选择 Artalk 所在目录
|
||||
> - 启动命令:`./artalk server`
|
||||
|
||||
## Docker
|
||||
|
||||
更新 Docker 容器的 [Restart 策略](https://docs.docker.com/config/containers/start-containers-automatically/#use-a-restart-policy) 以达到进程守护效果。
|
||||
|
||||
```bash
|
||||
docker update --restart=unless-stopped artalk
|
||||
```
|
||||
|
||||
## Docker Compose
|
||||
|
||||
在 `docker-compose.yml` 文件给服务添加 `restart: unless-stopped` 策略:
|
||||
|
||||
```diff
|
||||
version: '3'
|
||||
services:
|
||||
artalk:
|
||||
+ restart: unless-stopped
|
||||
```
|
||||
@@ -0,0 +1,7 @@
|
||||
# 数据
|
||||
|
||||
本页面内容已移动至 <https://artalk.js.org/guide/transfer.html>。
|
||||
|
||||
<script setup lang="ts">
|
||||
if (!import.meta.env.SSR) window.location = 'https://artalk.js.org/guide/transfer.html';
|
||||
</script>
|
||||
@@ -6,44 +6,22 @@ Artalk 提供后端程序的 Docker 镜像,以便加速部署流程,提供
|
||||
|
||||
## 镜像拉取
|
||||
|
||||
`docker pull artalk/artalk-go`
|
||||
```bash
|
||||
docker pull artalk/artalk-go
|
||||
```
|
||||
|
||||
## 容器创建
|
||||
|
||||
:::tip
|
||||
|
||||
推荐使用 Docker Compose:[“后端部署”](/guide/backend/install) 页面已详细讲解。
|
||||
推荐使用 Docker Compose,可参考 [程序部署](/guide/deploy) 页面的步骤。
|
||||
|
||||
:::
|
||||
|
||||
常规的 Docker 容器创建可参考:
|
||||
## 生成配置文件
|
||||
|
||||
```bash
|
||||
# 为 Artalk 创建一个目录
|
||||
mkdir Artalk
|
||||
cd Artalk
|
||||
|
||||
# 拉取 docker 镜像
|
||||
docker pull artalk/artalk-go
|
||||
|
||||
# 生成配置文件
|
||||
docker run -it -v $(pwd)/data:/data --rm artalk/artalk-go gen config data/artalk.yml
|
||||
|
||||
# 编辑配置文件
|
||||
vim data/artalk.yml
|
||||
|
||||
# 运行 docker 容器
|
||||
docker run -d \
|
||||
--name artalk \
|
||||
-p 0.0.0.0:8080:23366 \
|
||||
-v $(pwd)/data:/data \
|
||||
artalk/artalk-go
|
||||
```
|
||||
|
||||
然后,在前端配置填入后端地址:
|
||||
|
||||
```js
|
||||
Artalk.init({ server: "http://your_domain:8080" })
|
||||
```
|
||||
|
||||
## 重启
|
||||
@@ -92,12 +70,20 @@ docker pull artalk/artalk-go
|
||||
突破性变动请注意查看版本更新日志中的提示:[CHANGELOG.md](https://github.com/ArtalkJS/Artalk/blob/master/CHANGELOG.md)
|
||||
:::
|
||||
|
||||
## 拉取历史镜像
|
||||
## 测试版本
|
||||
|
||||
Nightly 镜像为测试版本,每日更新,通过代码仓库最新代码自动构建。
|
||||
|
||||
```bash
|
||||
docker pull artalk/artalk-go:nightly
|
||||
```
|
||||
|
||||
## 历史版本
|
||||
|
||||
镜像会随代码仓库 tags 自动构建发布,您可拉取不同版本号的镜像。
|
||||
|
||||
```bash
|
||||
docker pull artalk/artalk-go@版本号
|
||||
docker pull artalk/artalk-go:版本号
|
||||
```
|
||||
|
||||
## 进入容器
|
||||
@@ -112,4 +98,4 @@ docker exec -it artalk bash
|
||||
|
||||
## 多平台兼容性
|
||||
|
||||
Docker 镜像暂仅提供 amd_64 构建,若需要在 ARM 架构运行,请下载 [二进制编译构建](/guide/backend/install.md#普通方式)
|
||||
Docker 镜像暂仅提供 x86、arm64 的镜像构建,如需更多平台架构版本,请下载 [二进制构建部署](/guide/deploy.md#普通方式部署)。
|
||||
@@ -1,8 +1,8 @@
|
||||
# 邮件通知
|
||||
|
||||
Artalk 支持 SMTP 协议、阿里云邮件推送、调用系统 sendmail 命令等方式向用户发送邮件通知。
|
||||
Artalk 支持通过 SMTP 协议、阿里云邮件推送、调用系统 Sendmail 命令等方式向用户发送邮件通知。
|
||||
|
||||
你可以在[控制中心](/guide/frontend/sidebar.md#控制中心)找到「设置」界面修改此配置。
|
||||
你可以在 [控制中心](/guide/frontend/sidebar.md#设置) 的设置界面修改此配置,也可以通过 [配置文件](/guide/backend/config.md#邮件通知-email) 或 [环境变量](/guide/env.md#邮件通知) 进行配置。
|
||||
|
||||
## 配置文件
|
||||
|
||||
@@ -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,19 +298,17 @@ 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>
|
||||
```
|
||||
|
||||
Artalk 内置许多预设的邮件模板,例如 `mail_tpl: "default"` 使用的就是:[/email-tpl/default.html](https://github.com/ArtalkJS/Artalk/blob/master/email-tpl/default.html)
|
||||
Artalk 内置许多预设的邮件模板,例如 `mail_tpl: "default"` 使用的就是:[@ArtalkJS/Artalk:/internal/template/email_tpl/default.html](https://github.com/ArtalkJS/Artalk/blob/master/internal/template/email_tpl/default.html)
|
||||
|
||||
## 发向管理员的邮件
|
||||
|
||||
@@ -319,9 +317,9 @@ 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` 配置项已弃用,请使用以上替代。
|
||||
|
||||
不局限于邮件,Artalk 支持多种方式向管理员发送通知,参考:[“多元推送”](./admin_notify.md#邮件通知)。
|
||||
不局限于邮件,Artalk 支持多种方式向管理员发送通知,参考:[多元推送](./admin_notify.md#邮件通知)。
|
||||
@@ -0,0 +1,7 @@
|
||||
# 如何配置界面
|
||||
|
||||
本页面内容已移动至 <https://artalk.js.org/guide/frontend/config.html>。
|
||||
|
||||
<script setup lang="ts">
|
||||
if (!import.meta.env.SSR) window.location = 'https://artalk.js.org/guide/frontend/config.html';
|
||||
</script>
|
||||
Loaded 100 of 961 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user