Compare commits

..
430 Commits
Author SHA1 Message Date
qwqcode d25beede91 fix(scripts): detect unpublished npm versions
Query the npm registry for the exact local version instead of comparing only with the latest dist-tag.

Report unpublished packages accurately and avoid spawning pnpm for each lookup.
2026-07-25 04:01:48 +08:00
qwqcode 16b690c8c0 fix(plugins): prepare unpublished packages for release
Declare compatible Artalk ranges and npm repository metadata for the pending plugin versions.

Correct ESM and CommonJS declaration exports, trim plugin-kit package contents, and validate package types in CI.
2026-07-25 04:01:43 +08:00
qwqcode 2036a0261e fix(ci): publish npm package with trusted OIDC
Replace the long-lived npm token with GitHub OIDC credentials, verify the release version, and retain pnpm packaging so the published tarball still includes the repository license.
2026-07-25 03:26:34 +08:00
qwqcode 66c8f6b94b fix(docker): push release images by digest
Avoid assigning temporary platform tags to digest-only outputs so Buildx can push canonical per-platform digests before the manifest merge.
2026-07-25 03:26:33 +08:00
qwqcode 1bf21404bd fix(build): bind Docker metadata to release commit
Pass the resolved release commit into Docker builds, verify every checkout against it, and derive image version metadata and sha tags from the packaged source instead of the workflow invocation commit.
2026-07-24 14:24:00 +08:00
qwqcode 9ec0f1c74a fix(ci): pin release retries to reviewed commits
Resolve automatic releases from the merged release PR commit and require an explicit immutable commit when recovering a missing tag. Reuse existing tags idempotently, restore annotated release tags, and reject duplicate release preparation or inconsistent version files.
2026-07-24 14:23:26 +08:00
qwqcode 9b5e47d602 fix(ci): create release tags under tag ruleset
Create lightweight release refs directly at the checked-out commit so the v* linear-history rule evaluates the commit instead of an annotated tag object. Resolve existing tags through the remote API, verify their exact target without overwriting them, and accept an explicit version for safe manual release retries.
2026-07-23 23:52:35 +08:00
github-actions[bot] 03a433d94a chore: release v2.10.0 (#1158)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-07-23 23:41:37 +08:00
qwqcode 4a9b07e687 fix(ci): preserve nightly tag during release refresh
Keep the movable nightly tag while replacing the release, verify its exact commit through the Git refs API, and pass the build SHA as the release target. This avoids the tag visibility race caused by deleting and immediately recreating the tag before --verify-tag.
2026-07-23 14:04:01 +08:00
qwqcode d00b63c0af chore(ci): fix git-chglog installation 2026-07-23 13:20:48 +08:00
qwqcode 97352b583e fix(api/vote): return not found for deleted targets 2026-07-22 22:20:28 +08:00
qwqcode 0b44989e5f fix(cache): return database results on store failure
Treat cache writes as best-effort after a successful database query. Keep database errors authoritative and cover both paths with a failing store.

Fixes #1154
2026-07-22 22:20:28 +08:00
qwqcode a5308548ba fix(config): preserve keyword file separators
Represent control characters with reversible dashboard escapes, keep custom separators intact, and reject empty separators before loading keyword files. Document and test the full YAML round trip.

Fixes #1062
2026-07-22 22:20:28 +08:00
qwqcode 9225fc32f8 fix(email): add Message-ID header
Generate a unique RFC 5322 message identifier for every SMTP and sendmail message, using the sender domain when valid and a safe fallback otherwise.

Fixes #1111
2026-07-22 22:20:27 +08:00
qwqcode 37dc6a68d7 fix(api/stats): exclude pending comments
Use an explicit boolean condition so GORM cannot omit the moderation filter. Cover public comment lists and counts with regression tests.

Fixes #1110
2026-07-22 22:20:27 +08:00
qwqcode 69613beb88 fix(docs): support React 19 useRef types 2026-07-22 22:20:27 +08:00
qwqcode 9c5bd9653f fix(ci): satisfy workflow shell checks
Protect checksum globs and quote test artifact paths for ShellCheck. Pass release versions to Perl through the environment instead of interpolating shell variables into the program text.
2026-07-22 22:20:27 +08:00
qwqcode ca3d37fc2d fix(build): propagate image version metadata
Inject the requested release version and commit hash through Go linker variables so Docker images report the version they were built for, and make release preparation update the linkable version variable.\n\nAssert the version in release image smoke tests and trim unused files from Docker build contexts while preserving both prebuilt-UI and full frontend build paths.
2026-07-22 22:20:27 +08:00
qwqcode f554e6c438 test(ci): expand release validation
Run Go tests natively on Linux AMD64, Linux ARM64, and macOS; reduce the frontend matrix while keeping Node 22, Node 24, and Windows coverage; and make type-entry validation blocking.\n\nAdd the Playwright browser UAT flow to CI, pin test tools, isolate architecture-specific caches and artifacts, and cancel superseded pull-request runs.
2026-07-22 22:20:27 +08:00
qwqcode 76066bbdc0 fix(ci): harden release supply chain
Pin every third-party action to an immutable commit, enforce least-privilege tokens, avoid persisted checkout credentials, and validate all user-controlled values before they reach scripts.\n\nKeep dry-run GoReleaser jobs tokenless, publish npm provenance, generate tags through authenticated GitHub API calls, disable shared caches for release artifacts, and continuously audit workflow syntax and security policy.
2026-07-22 22:20:27 +08:00
qwqcode 3950ef8532 refactor(ci): accelerate nightly publishing
Run AMD64 and ARM64 Docker builds on native GitHub-hosted Linux runners, reuse architecture-scoped BuildKit caches, and merge validated image digests after both builds succeed.\n\nMake manual dry runs build, smoke-test, and upload artifacts without exposing DockerHub credentials or replacing the nightly tag and release.
2026-07-22 22:20:26 +08:00
qwqcode 3f6eb935e4 refactor(ci): optimize multi-architecture releases
Build Docker images once per native AMD64 and ARM64 runner, merge immutable digests into the release manifest, and reuse a single UI artifact across architectures.\n\nKeep dry runs local by separating the source ref from the release version, avoid remote tags and package publication, scope reusable-workflow secrets, and smoke-test each image before publication.
2026-07-22 22:20:26 +08:00
qwqcode 5364d191c7 test(ui): update comment e2e flow
Use the current English development-page labels and the configured base URL. Register the POST response wait before submission to avoid missing fast responses.
2026-07-22 22:20:26 +08:00
qwqcode 5e1b04326b test(ui): isolate Playwright end-to-end specs
Point Playwright directly at tests/e2e so Vitest unit suites are not collected as browser tests. The Chromium project now discovers only the intended comment UAT spec.
2026-07-22 22:20:26 +08:00
qwqcode add379c82c fix(ui/sidebar): handle null array preferences
Treat YAML null values as empty arrays before checking for YAML node serialization. This prevents the settings page from throwing while mounting optional array preferences.
2026-07-22 22:20:26 +08:00
qwqcode d7565e5b33 fix(ui): accept scoped comment lists without page data
Site and user scoped comment responses intentionally omit the page object. Only enforce page data for page-scoped requests and skip page state updates when it is absent.

Add regression coverage for sidebar scopes and the normal page flow.
2026-07-22 22:20:26 +08:00
qwqcode d46326788b docs: document dependency and security updates
Record the backend, frontend, container, and CI dependency refresh in both v2.10.0 release guides.

Explain JWT wire compatibility, the sanitizer replacement, patched transitive pins, generator reproducibility, and unchanged release artifact layout.
2026-07-22 22:20:26 +08:00
qwqcode 729fd9880a fix(ci): harden release tag handling
Pass the event ref through the environment instead of interpolating expression data into the shell, validate the derived semantic version, and quote Git refs and environment files.

Use rev-parse for an exact tag existence check before creating and pushing the release tag.
2026-07-22 22:20:26 +08:00
qwqcode 5b6a453349 fix(ui): preserve generated list response contract
Regenerate the Swagger specification and TypeScript client with the pinned generators, including accurate optional response fields and the verified-email SSO description.

Validate comment-list page data at the API boundary and normalize it back to the public ListData contract before storing or emitting the response.
2026-07-22 22:20:25 +08:00
qwqcode b7b6700407 fix(auth): require verified email for SSO exchange
Reject OIDC userinfo responses without email_verified=true before account lookup or JWT issuance.
2026-07-22 22:20:25 +08:00
qwqcode cb2860a778 docs: add v2.10.0 release notes
BREAKING CHANGE: Beyond #997, #1007, and #1011, v2.10.0 changes default config/data discovery and relative-path semantics; raises source builds to Go 1.26.5; replaces the CGO-backed SQLite driver with a pure-Go implementation; fixes application timezone at process initialization, requiring a full restart to change it; removes the useBackendConf opt-out and remoteConfModifier; changes DI registration, Context mutation, update() return value, and created timing; and requires marked 18 with modern package resolution. Migration guide: https://artalk.js.org/en/guide/releases/v2.10.0.html
2026-07-22 22:20:25 +08:00
qwqcode 705e220a81 test(ui): cover Marked 18 integration 2026-07-22 22:20:25 +08:00
qwqcode ef2d1e8552 test(server): verify plugin URL trust filtering 2026-07-22 22:20:25 +08:00
qwqcode 14e2d9e824 fix(ui): align plugin lifecycle with final config 2026-07-22 22:20:25 +08:00
qwqcode 9dba2ae43f fix(ui): reject direct context replacement 2026-07-22 22:20:25 +08:00
qwqcode f1784a1bd0 fix(ui): restore deprecated context services 2026-07-22 22:20:24 +08:00
qwqcode bc30c4d26d fix(ui/editor): restore deprecated aliases 2026-07-22 22:20:24 +08:00
qwqcode ad9abd643c fix(ui/types): restore deprecated public aliases 2026-07-22 22:20:24 +08:00
qwqcode 2e7a34fc9c fix(ui/types): preserve atomic config values 2026-07-22 22:20:24 +08:00
qwqcode 082e9b7fed fix(core): initialize process timezone once 2026-07-22 22:20:24 +08:00
qwqcode a95c1b9be6 fix(db): enforce Cloud SQL TLS verification 2026-07-22 22:20:24 +08:00
qwqcode dfe65ce621 fix(cmd): preserve config lookup before data chdir 2026-07-22 22:20:24 +08:00
qwqcode da6556ec3c fix(api): make vote updates transactional 2026-07-22 22:20:23 +08:00
qwqcode 9fe237660c chore(scripts): bound registry downloads 2026-07-22 22:20:23 +08:00
qwqcode eff4a0b15d test: remove races from async tests 2026-07-22 22:20:23 +08:00
qwqcode 5b0e4c866e fix(api): validate vote status targets 2026-07-22 22:20:23 +08:00
qwqcode 617de2cdf1 fix(scripts): harden npm publish check 2026-07-22 22:20:23 +08:00
qwqcode 36c47104ca test(ui): cover sanitizer attribute allowlist 2026-07-22 22:13:45 +08:00
qwqcode 8460ae387f chore(deps): bump ci deps
Update checkout, setup, cache, artifact, Docker, CodeQL, Codecov, repository-dispatch, and supporting GitHub Actions to their current major releases.

Move the builder and runtime images to Go 1.26.5 on Alpine 3.24 while preserving workflow inputs and release artifact layout.
2026-07-22 22:13:44 +08:00
qwqcode e6a5c2d4b9 fix(scripts): import Buffer explicitly
Use the node:buffer entry point instead of relying on an implicit global when the plugin registry fetch script computes response sizes.
2026-07-22 22:13:44 +08:00
qwqcode 1cd9cdb445 test(ui): isolate browser storage from Node
Disable Node's experimental Web Storage shim for Vitest and coverage runs so jsdom consistently provides window.localStorage on supported Node 22 and 24 releases.
2026-07-22 22:13:44 +08:00
qwqcode 117908e57b fix(ui): replace vulnerable HTML sanitizer
Replace the unmaintained insane parser with DOMPurify to remove its known ReDoS exposure while retaining Artalk's tag, attribute, class, style, and URL scheme allowlists.

Add malicious markup, URL filtering, allowlist compatibility, and former ReDoS payload tests.
2026-07-22 22:13:44 +08:00
qwqcode b47eed5303 chore(deps): bump frontend deps
Update the UI, sidebar, plugins, documentation, lint, test, and build toolchains, including Vite 8.1, Marked 18.0.7, TypeScript 6, and current framework packages.

Pin patched transitive dependencies, move pnpm policy to the workspace configuration, approve the esbuild install script, and refresh generated router metadata.
2026-07-22 22:13:44 +08:00
qwqcode f7a2aeac9b refactor(auth): migrate JWT handling to v5
Use RegisteredClaims and ParseWithClaims, restrict accepted tokens to HS256, and keep existing claim names and signatures wire-compatible.

Add regression coverage for generated and legacy tokens, expiry validation, and algorithm rejection.
2026-07-22 22:13:44 +08:00
qwqcode 5ff42483aa chore(deps): bump backend deps
Update the Go dependency graph, including x/crypto, x/image, x/net, Slack, database drivers, Fiber integrations, and supporting modules.

Bump the CGO-free SQLite driver to v1.2.1 and prepare golang-jwt/jwt v5 for the dedicated authentication migration.
2026-07-22 22:13:44 +08:00
qwqcode 8de7157a91 feat(go): upgrade golang to v1.26.5 2026-07-22 22:13:43 +08:00
qwqcode 747b184fa4 build: remove cgo from SQLite releases 2026-07-22 22:13:43 +08:00
Ikko Eltociear Ashimine f875fc4023 docs: add Japanese README (#1145) 2026-06-24 17:30:17 +01:00
Henrik Pettersenandqwqcode cf06808170 feat(auth): add SSO token exchange endpoint (#1134)
* feat(auth): add SSO token exchange endpoint

Adds POST /api/v2/sso/exchange — accepts an access token from an
external OIDC IdP (verified by calling the IdP's /userinfo) and issues
an Artalk session JWT for the user identified by the email claim.

Use case: a surrounding application that already runs OIDC (e.g. an
Auth0 SPA) can drive Artalk sign-in without showing Artalk's own popup
login UI. The widget reads the resulting JWT from
localStorage["ArtalkUser"].token and treats the user as fully
authenticated for is_login/is_admin checks.

Implementation:
- One new handler at server/handler/auth_sso_exchange.go (~110 lines)
- Reuses dao.FindCreateUser + common.LoginGetUserToken; same JWT
  format as /user/access_token, so no client-side changes needed
- Validation by calling {issuer}/userinfo with Authorization: Bearer
  — OIDC-standard, no JWKS dep added
- Gated by auth.enabled && auth.sso.enabled (404 otherwise)
- Returns the same ResponseUserLogin shape as /auth/email/login

Config additions (conf/artalk.example.yml):
  auth:
    sso:
      enabled: false
      issuer: ""   # e.g. "tenant.auth0.com"

Route registered alongside the existing social-login routes in
server/server.go.

Verified by go build ./... (clean).

* chore(config): regenerate env-path cache with auth.sso entries

Required so koanf actually maps ATK_AUTH_SSO_ENABLED/ISSUER env vars
to the new auth.sso config block introduced in feat: add SSO token
exchange endpoint. Without this regen the env vars are silently
ignored and the endpoint stays in its disabled state.

* docs: add sso token exchange section for auth docs

---------

Co-authored-by: qwqcode <qwqcode@gmail.com>
2026-06-14 17:02:58 +01:00
xaoxuu 3b00a5e356 chore(docs): add xaoxuu to showcase (#1098) 2026-06-14 10:57:38 +01:00
Eser Şahinerandqwqcode 3d9c484a5d docs(i18n): add Turkish (tr-TR) language support (#1119)
* feat(i18n): add Turkish (tr-TR) language support

* chore: fix lint

---------

Co-authored-by: qwqcode <qwqcode@gmail.com>
2026-06-14 10:53:33 +01:00
Garnet dcac8cc883 chore(docs): revise French landing page translations (#1075) 2026-06-14 09:37:02 +01:00
Hsüan b39ec2a0a6 feat(db): add TLS support for MySQL with Google Cloud SQL (#1104)
* Support Google cloud SQL Mysql SSL

* fix typo
2026-05-05 21:55:54 +08:00
qwqcode 5c3df4776e feat(go): upgrade golang to v1.26.2 and some deps 2026-05-05 20:33:17 +08:00
Howie Xie 6ba19150df feat: add 'ugc' to link rel attributes (#1120) 2026-04-12 19:27:35 +08:00
Kegongteng efe62e93e2 chore(docs): Improve the transfer document (#1109) 2026-04-12 19:27:09 +08:00
她和她的猫 71a651153b chore(docs): correct docker arg name for skipping ui build (#1086) 2025-06-09 19:27:38 +08:00
ᡥᠠᡳᡤᡳᠶᠠ ᡥᠠᠯᠠ·ᠨᡝᡴᠣ 猫 b4c139bf9e fix(ui/ua): support OpenHarmony and more browsers (#1087) 2025-06-09 19:22:48 +08:00
qwqcode 3e45bb9506 chore(landing): improve landing page and docs 2025-02-02 16:26:20 +08:00
qwqcode 64a2adbe1a chore(ci): revise github dependabot for checking ui deps 2024-12-13 13:12:38 +08:00
qwqcode 99736db27f chore(style): fix bg color of login dialog in sidebar for dark mode 2024-11-25 00:00:51 +08:00
qwqcode eb3310c537 chore(ci): tidy up frontend build shell scripts 2024-11-24 23:53:20 +08:00
duli ab2c2cf153 chore(ci): include artalk_ui_nightly.tar.gz in nightly release (#1027) 2024-11-23 21:34:49 +08:00
qwqcode 71b73a323a chore(docs/landing): fix tech icons in landing page 2024-11-06 22:22:23 +08:00
qwqcode 659023988e docs(landing): redesign landing page (#1020) 2024-11-06 21:53:23 +08:00
qwqcode c2b9afa1a1 feat(plugins): add plugin registry fetch script
- Introduce `fetch-registry.mjs` to download `registry.json` from `ArtalkJS/Community` repo for the latest release
- Update `build:docs` script to include registry fetch
2024-10-22 11:23:35 +08:00
qwqcode 258dfde60e docs: integrate git changelog plugin 2024-10-19 16:32:34 +08:00
qwqcode 91ac907778 chore(ui/deps): upgrade deps for ui 2024-10-19 16:25:48 +08:00
qwqcode 73da8740ee chore(docs): add frontend typedoc 2024-10-19 14:34:01 +08:00
qwqcode 4ad0cc1366 chore(i18n): update terminology for clarity
- Change 'Frontend' to 'Client'
- Change 'Backend' to 'Server'
2024-10-19 14:09:59 +08:00
Lance.Moe 15f2fb82a3 chore(docs): corrected react usage example (#1012) 2024-10-19 13:11:29 +08:00
qwqcode bd81b7c10c feat(ui/conf): add preferRemoteConf option (#1000) (#1011)
Add `preferRemoteConf` option (disabled by default).

Local config now takes priority, addressing the issue where remote config previously overrode local settings. (Closes #1000)

Updated config merging logic in `mount.ts`.

Deprecated `useBackendConf` in favor of `preferRemoteConf`.

(The prerequisite PR is #1007)

BREAKING CHANGE: UI client now prioritizes local config in the latest version, whereas previously, the remote config would override it. (See #1011)
2024-10-18 21:46:49 +08:00
qwqcode f6c99e949b feat(ui/eslint): update eslint-plugin-artalk to v1.0.2 (#1010)
- Add new ESLint rules for ArtalkPlugin:
  - Available rules: `noCycleDeps`, `noLifeCycleEventInNestedBlocks`, `noEventInWatchConf`, `noInjectInNestedBlocks`, `noInjectOutsidePlugin`, `onePluginPerFile`. For more details, see [eslint-plugin-artalk](https://github.com/ArtalkJS/Artalk/tree/master/ui/eslint-plugin-artalk).
- Add tests for the new ESLint rules.
- Implement Tarjan's algorithm for detecting SCCs in the `noCycleDeps` rule.
- Improve code organization and maintainability.
- Disable the 'import-x/namespace' rule for better performance. (https://github.com/import-js/eslint-plugin-import/issues/2340)
2024-10-18 19:43:01 +08:00
qwqcode dcde53f8ad refactor(ui/auth): ensure compatibility with new client types (#1009)
- Bump to new Artalk client export types
- Add `AuthContext` type definition for improved clarity
- Replace `ContextApi` with `AuthContext` for reducing the scope of variables
- Bump version to 0.0.2 for release

(The prerequisite PR is #1007)
2024-10-18 17:09:15 +08:00
qwqcode d3aacf0d14 refactor(ui/sidebar): ensure compatibility with new client types (#1008)
Since the client program already prioritizes local configuration over remote configuration by default, there's no need to use the `remoteConfModifier` magic function to alter the configuration priority.

The dependency injection function has changed from `get` to `inject`, or call a more specific method from the `Context` interface.

(The prerequisite PR is #1007)
2024-10-18 16:48:41 +08:00
qwqcode 20be96f6f8 refactor(ui): improve modularity, lifecycle, and types (#1007)
- Introduce a service dependency container for better management (#1006).
  - Replace original `services` definitions with `provide` and `inject` methods.
  - Recommend calling `inject` at the beginning of `ArtalkPlugin` to explicitly inject required dependencies.
- Replace `load` with `mount` for improved lifecycle handling.
  - Track local config.
  - Fix potential language setting not working issue. (Fixes #973)
- Refine Type definitions for clarity and maintainability.
  - See [TypeDoc](https://artalk.js.org/typedoc/) for updates.
- Enhance config logic with `ConfigManager`.
  - Deprecate `ctx.conf` and `ctx.$root`; use `getConf()` and `getEl()` instead.
  - Update client default config settings. (Fixes #1001)
- Improve event handling with `EventManager` refactor.
- Update plugin and editor architecture for greater flexibility.
  - Further eliminate global variables and avoid directly passing the `Context` interface as a function parameter. Instead, use more explicit and specific types and parameters.
- Remove deprecated and redundant code for a cleaner structure.

BREAKING CHANGE: This update changes the UI client's export Types. Although we aim to maintain backward compatibility, it may still affect downstream UI programs. Please refer to the [TypeDoc](https://artalk.js.org/typedoc/).
2024-10-18 16:40:18 +08:00
qwqcode 437892cdfa feat(ui): add dependency injection container (#1006)
- Implement `createInjectionContainer` for managing service lifecycles
- Implement `provide` and `inject` for dependency injection
- Support singleton and transient service lifecycles
- Add unit tests for container functionality
2024-10-17 22:53:25 +08:00
qwqcode 5065bb4763 chore: update CONTRIBUTING.md 2024-10-11 13:31:20 +08:00
Limeandqwqcode baa63866f4 feat(ui/page_vote): add page voting feature (#983)
* feat(plugin/page_vote): add `page_vote` plugin

* feat(plugin/page_vote): update vote count text

adjust code structure
disable `page vote` plugin by default

* feat(plugin/page_vote): reuse actions btn style

* perf(plugin/page-vote): make type strong

* feat: watch `darkMode` conf

* doc(plugin/page_vote): add config doc

* feat(ui/page_vote): add page voting feature

- Introduce page voting functionality
- Update configuration to enable/disable page voting
- Retrieve html elements for voting buttons and counts
- Enhance customization options for voting elements
- Reference: #983, #998, #997

---------

Co-authored-by: qwqcode <qwqcode@gmail.com>
2024-10-08 12:38:39 +08:00
qwqcode 7c251fd067 feat(api/vote): add get vote status endpoint (#998)
A new HTTP API endpoint `GET /votes/:target_name/:target_id` is now available. (See https://artalk.js.org/http-api.html#tag/Vote/operation/GetVote)

- Implement GET endpoint for retrieving vote status
- Add tests for vote functionality

Related to: #997

This is a prerequisite PR for #983.
2024-10-06 22:31:59 +08:00
qwqcode 02a369fe5c refactor(api/vote): refactor vote http endpoint and logic (#997)
The original `POST /votes/:type/:target_id` endpoint for creating votes has been updated to `POST /votes/:target_name/:target_id/:choice`. The `target_name` can be either `comment` or `page`, the `target_id` is a numeric value, and the `choice` can be `up` or `down`. (https://artalk.js.org/http-api.html#tag/Vote/operation/CreateVote)

The HTTP response now includes two additional fields: `is_up` and `is_down`, which indicate the user's current voting state. The `up` and `down` fields remain unchanged and continue to be of numeric type, ensuring backward compatibility with existing clients.

- Change vote endpoint to include `{target_name}` and `{choice}`
- Update vote logic to handle `up` and `down` choices
- Modify request data models and API interfaces for new vote structure
- Ensure backward compatibility with existing vote response data
- Improve vote handling and response structure

BREAKING CHANGE: Vote HTTP API endpoint have been updated. (See #997)
2024-10-06 22:15:15 +08:00
qwqcode bd0db8cd57 chore(docs): revise ui config docs 2024-10-06 21:45:01 +08:00
qwqcode 206a26d0c1 feat(ui): add npm published version check script
- Introduce check:publish script to verify npm versions
- Ensure all projects have the latest versions on npm
- Skip private packages during version checks
- Allow filtering by specific project name with -F option
2024-10-05 21:13:02 +08:00
qwqcode f1ae566134 refactor(ui/conf): introduce DeepPartial type for ui config (#996)
- Replace `Partial<ArtalkConfig>` with `ArtalkConfigPartial` for better type clarity.
- Introduce `DeepPartial` type for nested partial configurations.
- Update default configuration handling to use `RequiredExcept` and `FunctionKeys`.
- Adjust related functions and interfaces to use `ArtalkConfigPartial`.
2024-10-05 20:33:06 +08:00
qwqcode 3571a18b42 refactor(ui/comment): update reply button to use component
- Replaced manual reply button creation with ActionBtn component for consistency
- Moved styling from comment.scss to main.scss for common action button styles
2024-10-05 19:36:49 +08:00
qwqcode abac3f0f36 feat(ui/eslint): add eslint plugin for artalk ui development (#995)
- Implemented `eslint-plugin-artalk` to enforce Artalk's development conventions.
- Added setup script for UI development environment.
- Created test cases for Artalk plugin rules.
- Configured TypeScript and build settings for the plugin.
- Updated documentation with installation and configuration instructions.
2024-10-05 19:19:22 +08:00
qwqcode db960aa024 chore(deps): upgrade go deps 2024-10-04 00:31:31 +08:00
qwqcode 1b5ef279bb chore(ci/tests): fix branch filters and improve caching 2024-10-04 00:31:03 +08:00
qwqcode 754223571a chore(ci/tests): switch tests from circle ci to github actions 2024-10-03 23:02:50 +08:00
qwqcode a6eba361fc chore(ci): update branch ignore patterns on circle ci 2024-10-03 21:34:24 +08:00
qwqcode 1d5811a59c feat(config): enhance config file and data dir retrieval (#992)
* feat(config): enhance config file and data dir retrieval

- Add xdg package for XDG base directory support
- Update RetrieveConfigFile to search in XDG_CONFIG_HOME and /etc
- Add RetrieveDataDir to find data directory in XDG_DATA_HOME and /var/lib
- Improve comments for better understanding of search order

* add unit tests
2024-10-03 15:04:42 +08:00
qwqcode ea9c5d9ecb chore(docs): add install guide for fedora linux distro 2024-10-01 14:47:20 +08:00
qwqcode 8707f4f327 docs(landing): add more translations 2024-09-20 21:03:56 +08:00
qwqcode b89a1866f9 docs(i18n): add zh-TW translation for config template 2024-09-20 21:03:12 +08:00
qwqcode 7e082158cd chore(docs): add go reference badge in README.md 2024-09-19 21:41:48 +08:00
qwqcode d5d458de11 docs(landing): optimize responsive font size 2024-09-19 21:17:38 +08:00
qwqcode c087400a66 chore(docs): set up redirects for old pages 2024-09-19 21:14:07 +08:00
qwqcode 34d793697c chore(docs): refine deployment documentation 2024-09-19 18:27:24 +08:00
github-actions[bot] b9c3b2a1c3 chore: release v2.9.1 (#981)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2024-09-18 23:50:46 +08:00
qwqcode bd121f8f94 docs: refine deployment documentation 2024-09-18 23:47:35 +08:00
qwqcode 6b0e46c86c refactor(go): hardcode version and get commit_hash via runtime/debug 2024-09-18 22:01:21 +08:00
qwqcode 53aaf27fdf chore(deps): upgrade frontend deps 2024-09-18 21:56:38 +08:00
qwqcode a3d1ccc773 feat(go): upgrade golang to v1.22.7 and some deps 2024-09-18 21:56:38 +08:00
qwqcode cf7725edba refactor(go): bump the module version and support go install (#979)
BREAKING CHANGE: The original Go module name was `github.com/ArtalkJS/Artalk`, which has now been modified to `github.com/artalkjs/artalk/v2` (all lowercase). This change may affect the CI pipeline or other areas if you are compiling the Artalk server and have specified the fixed Go module name. Regarding the original `-ldflags -X github.com/ArtalkJS/Artalk/internal/config.Version` and `CommitHash` definitions, please remove them, as they are now obsolete. The `Version` has been hardcoded into the Go code, and the `CommitHash` is now read from the Go build info via runtime/debug’s vcs.revision value. This change only affects the server developers and does not impact the frontend UI client.
2024-09-18 21:43:43 +08:00
qwqcode 9cc3252c0f chore(docs): add support for auto-redirect to language-specific docs 2024-09-18 12:51:17 +08:00
qwqcode 349eb6f5c5 chore(docs): update the Chinese slogan on the homepage 2024-09-17 23:35:05 +08:00
qwqcode 55a96f12aa chore(docs): make English the default readme 2024-09-17 22:34:09 +08:00
qwqcode 36580b5fc3 chore(docs): apply artalk locale from html lang 2024-09-17 21:46:14 +08:00
qwqcode 9afa7ca555 docs(i18n): add English translations for docs (#978)
* docs: add support for multiple languages

* docs(i18n): add English translations
2024-09-17 21:19:48 +08:00
qwqcode 6d54b721da docs(landing): add multi-language and dark-mode for landing 2024-09-17 17:48:05 +08:00
qwqcode cb4596d59d docs(landing): add demo video in landing page 2024-09-17 17:44:17 +08:00
qwqcode 4913e1aebd chore(docs): update extras.md 2024-09-17 17:41:27 +08:00
qwqcode 7ffaa04541 perf(plugin_katex): add error message for missing katex deps 2024-09-17 17:41:24 +08:00
qwqcode 2a49c0e515 fix(ui/plugin): prevent exceptions from blocking other plugins loading 2024-09-17 17:35:36 +08:00
qwqcode a98a50abbe test(mutex): add tests for keyed mutex 2024-09-16 16:55:38 +08:00
qwqcode 4bd3537c0d fix(test): separate test db to isolate concurrent test instances (#975) 2024-09-16 16:46:38 +08:00
qwqcode 9dcfd9cd91 chore(deps): upgrade deps 2024-09-15 09:52:26 +08:00
qwqcode 9fde40d843 chore(ci): improve golang build workflow on circle ci 2024-09-04 21:23:23 +08:00
qwqcode 19c3317f64 refactor(dao): improve concurrent testing for FindCreateAction function 2024-09-04 21:17:53 +08:00
qwqcode 22ff47f9ce fix(transfer): ensure consistent time format in artrans export 2024-09-04 21:14:46 +08:00
qwqcode 4eb3dbaca2 fix(db): sql error with custom table prefix (#970) 2024-09-04 21:00:13 +08:00
qwqcode 90d8503d0e chore(docs): update cases.md 2024-09-04 11:42:47 +08:00
qwqcode 2354f7aa06 chore: update README.md 2024-09-04 11:20:57 +08:00
qwqcode 7bab69c4fd chore(docs): update artalk plugin for docs 2024-09-03 22:45:02 +08:00
qwqcode 301928da4b chore(build): fix build for plugin-lightbox 2024-09-03 22:17:34 +08:00
github-actions[bot] 6135c7e911 chore: release v2.9.0 (#968)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2024-09-03 22:03:03 +08:00
qwqcode 1ff0c4c10f chore(deps): upgrade deps 2024-09-03 21:18:16 +08:00
qwqcode 9cc9a6d6ab feat(config): add site_url config option (#967) 2024-09-03 20:07:43 +08:00
qwqcode d2225d565b fix(anti_spam): handle empty referer variable in anti-spam check (#853) 2024-09-03 19:37:39 +08:00
qwqcode e61911027c fix(auth): correct email verification code send button 2024-09-03 11:44:37 +08:00
qwqcode f29d2f81eb chore(sidebar/icon): swap sensitive hidden on/off icon 2024-09-02 16:52:52 +08:00
qwqcode 4b5ec39b8e feat(auth): add user profile and password changing (#966) 2024-09-02 15:56:04 +08:00
qwqcode 5dc2752cc1 fix(validator): restrict to allow only HTTP protocol 2024-09-02 14:52:57 +08:00
qwqcode cf6e687a2d fix(plugin_kit): import source path case error on linux 2024-09-02 11:16:23 +08:00
qwqcode 69ea7de22e chore(deps): update peerDependencies for plugin-auth 2024-09-01 23:03:43 +08:00
qwqcode 8fb7027186 chore(ci): add plugin-kit to artalk build process 2024-08-31 22:15:46 +08:00
qwqcode 88615f9a88 perf(auth): correct verify button position in register form 2024-08-31 21:56:25 +08:00
qwqcode f104629b40 perf(auth): add loading skeleton for login methods list 2024-08-31 21:54:28 +08:00
qwqcode 2f6b30deaf perf(auth): enhance visibility of skip button (#863) 2024-08-31 21:53:25 +08:00
qwqcode 2f7b9fa816 perf(auth): perform optical adjustment for consistent icon sizing 2024-08-31 21:45:53 +08:00
qwqcode 6d1041dc69 docs(auth): set auth.anonymous to false as default 2024-08-31 21:43:48 +08:00
qwqcode 9fb191976c refactor(ui/types): add Layer interface 2024-08-31 17:05:30 +08:00
qwqcode f20454bd00 perf(plugin_kit): improve typescript diagnostics output 2024-08-31 16:53:42 +08:00
qwqcode 64854107ef fix(plugin_kit): fix typescript lib path retrieval on win 2024-08-30 22:41:58 +08:00
qwqcode ac54eae179 chore(docs): add docker mirror tips 2024-08-30 12:05:24 +08:00
qwqcode aa92a92961 fix(api/comment_add): improve the security of comment add api (#964)
* fix(api/comment_add): refactor and improve the security of comment add api

* update
2024-08-29 23:29:36 +08:00
qwqcode d54652264b feat(ui/sidebar): add dark mode toggle for dashboard (#790) 2024-08-29 20:59:19 +08:00
qwqcode d6ececd014 fix(ui/stat): fix invalid backward compatible strategy (#880) 2024-08-29 20:54:30 +08:00
qwqcode 04ef002da1 fix(sidebar): correct total item count for pagination in sidebar 2024-08-29 18:43:49 +08:00
qwqcode a6b559d682 chore(icon): fix icon in sidebar on desktop devices 2024-08-29 18:31:39 +08:00
qwqcode 67b37b4612 chore(deps): upgrade frontend deps 2024-08-29 14:25:06 +08:00
qwqcode 3e81b2a8f2 chore(docker): resolve dockerfile rule violations 2024-08-29 14:22:03 +08:00
qwqcode 8a9480d05a feat(ui/sidebar): add page search by keywords in sidebar (#603) 2024-08-29 13:42:41 +08:00
qwqcode b3ed639be7 perf(style/sidebar): modify font-family for sidebar 2024-08-29 12:46:03 +08:00
qwqcode 6a0e06ea75 docs(ui/i18n): add more locale support for sidebar 2024-08-29 12:43:53 +08:00
qwqcode 92484cfa66 perf(ui/sidebar): enhance i18n translations for sidebar 2024-08-29 12:42:31 +08:00
qwqcode 1b0eff9568 perf(ui/sidebar): optimize setup process and i18n lazy load (#962) 2024-08-29 12:33:51 +08:00
qwqcode 2efd34248d perf(i18n): auto-load frontend i18n locale js sources 2024-08-29 11:47:57 +08:00
qwqcode c0a3026890 docs(ui/i18n): add translations for French, Korean, and Russian 2024-08-29 11:45:56 +08:00
qwqcode 392b6b15cf refactor(ui/user): rename nick to name in LocalUser data structure (#961) 2024-08-28 23:28:36 +08:00
qwqcode 6b58fd8a9d feat(ui/sidebar): add user search by keywords in sidebar (#710) 2024-08-28 19:50:38 +08:00
qwqcode 80e5ca5dc7 perf(ui/sidebar): mask sensitive input values in sidebar settings (#494) 2024-08-28 19:04:15 +08:00
qwqcode 50e967f71c feat(ui/date): add dateFormatter config option (#940) 2024-08-28 18:01:43 +08:00
qwqcode cf58a545b5 chore(deps): upgrade deps 2024-08-28 16:12:43 +08:00
qwqcode 270558129f fix(ui/dark_mode): apply dark mode config option before mounting ui (#890) 2024-08-28 12:40:47 +08:00
qwqcode 059bac8b5f perf(api/auth): add more specific error messages for login failures 2024-08-28 11:26:31 +08:00
qwqcode f1a86d59ca fix(ui/sidebar): disable admin password check dialog in sidebar 2024-08-28 11:12:30 +08:00
qwqcode adcb75a2e2 feat(ui/dashboard): new dashboard ui refresh for desktop devices (#957)
* feat(ui/dashboard): new dashboard ui refresh on desktop device

* add z-index for login dialog layer
2024-08-20 04:10:17 +08:00
qwqcode 4d7e157ff0 fix(ui/sidebar): show env variables in sidebar settings ui (#946) (#956)
* fix(ui/sidebar): show env variables in sidebar settings ui (#946)

* fix unit test
2024-08-19 16:27:20 +08:00
qwqcode 528847de7b chore(docs): add SECURITY.md 2024-08-18 23:41:31 +08:00
qwqcode 2b9d6bb573 chore(deps): upgrade docs and sidebar deps 2024-08-18 22:53:51 +08:00
qwqcode 393224cdb1 refactor(plugin_katex): use tokenizer extension of marked (#955) 2024-08-18 22:44:58 +08:00
qwqcode a925806d29 refactor(ui/marked): replace pkg-level marked with new class instance (#954)
* refactor(ui/marked): replace pkg-level marked with new class instance

* fix sidebar
2024-08-18 20:10:02 +08:00
qwqcode b97167a718 chore(docs): update FUNDING.yml 2024-08-17 16:10:48 +08:00
qwqcode 587523f0df feat(go): upgrade golang to v1.22.6 and some deps 2024-08-17 15:43:15 +08:00
qwqcode 08f58cd38b chore(deps/ui): upgrade deps for frontend 2024-08-17 15:07:56 +08:00
qwqcode 0803e235a4 chore(docker): update docker-compose.yml file sample 2024-08-07 18:50:14 +08:00
qwqcode 125a66611f chore(deps/go): upgrade gorilla/websocket 2024-08-05 17:13:11 +08:00
qwqcode 92a0e23c85 chore(plugin/katex): add artalk to peerDependencies in package.json 2024-08-02 10:54:16 +08:00
qwqcode c75b630e8a chore(plugin/lightbox): upgrade version of plugin-lightbox 2024-07-25 16:35:31 +08:00
qwqcode d22d34c223 fix(plugin/lightbox): fix import for non-browser env (#931)
* fix(plugin_lightbox): fix lightbox plugin import for non-browser env

* add artalk as peerDependency

* using default object of import result

* test and fix photoSwipe, fancyBox

* add minimal reproducible example

* refine docs
2024-07-25 16:30:34 +08:00
qwqcode 6fe8ffd2c4 chore(docs): remove obsolete cdn links 2024-07-21 19:35:30 +08:00
qwqcode f4d33fcf24 chore(auth/icon): fix missing microsoft auth icon (#929) 2024-07-16 14:28:43 +08:00
qwqcode 640f9904fb chore(docs): update config.md 2024-07-13 14:58:16 +08:00
qwqcode df62de09f3 fix(api/auth): register issue due to unremoved auth records after user deletion (#919) 2024-07-12 14:12:15 +08:00
qwqcode 68bcdbe3e8 fix(api/auth): migrate auth_identities when account merging (#920) 2024-07-12 13:26:27 +08:00
qwqcode e663893fd1 perf(notify): improve error messages for notify (#943) 2024-07-11 13:12:12 +08:00
qwqcode b85d845b71 chore(docs): revise docker compose env variable config (#933) 2024-06-21 21:20:31 +08:00
qwqcode acf7480b91 fix(api/auth): fix missing Microsoft oauth provider configuration (#929) 2024-06-19 22:10:11 +08:00
qwqcode be0dcd6b59 feat(ui/plugin): make ui plugin configurable 2024-06-19 21:00:32 +08:00
qwqcode 4d9445c84c chore(docs): refine some docs 2024-06-19 20:46:02 +08:00
qwqcode 1337e81cd4 fix(ui/plugin-kit): fix typescript lib folder for api-extractor in monorepo 2024-06-19 20:43:36 +08:00
qwqcode d053b953a6 refactor(ui/deps): remove abortcontroller-polyfill (#923) 2024-06-10 17:00:56 +08:00
qwqcode 2549052558 perf(app/init): generate translated config file by env variable ATK_LOCALE 2024-06-09 22:45:23 +08:00
qwqcode b8da04e308 chore(docs): update import-framework.md 2024-06-09 22:18:35 +08:00
github-actions[bot] c4a7162302 chore: release v2.8.7 (#918)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2024-06-09 19:14:50 +08:00
qwqcode 6012993fe9 chore(deps): upgrade go deps 2024-06-09 18:36:13 +08:00
qwqcode d4ed7f64b2 refactor(ui): fix linter issues for ui and docs (#917)
* refactor(ui): fix linter issues for ui and docs

* fix ci
2024-06-09 18:31:04 +08:00
qwqcode 93e3b2f184 perf(ui/dev): bump eslint to v9 (#915)
* perf(ui/dev): bump eslint to version 9

* add react eslint plugin and replace import with import-x
2024-06-09 15:20:04 +08:00
qwqcode 0e75457499 chore(deps): upgrade node and pnpm 2024-06-08 16:55:20 +08:00
zarev b8151bb789 docs(i18n): revise French translation (#913) 2024-06-08 16:50:06 +08:00
qwqcode 67922f34ad fix(api/auth): include render mustache params for verification email subject (#910) 2024-06-08 16:40:35 +08:00
qwqcode 7093e7e1c5 perf(gravatar): support both sha256 and md5 hash for gravatar (#912) 2024-06-08 16:22:26 +08:00
qwqcode c3558b7beb perf(dao): add singleflight for no-cache db find func 2024-06-08 13:48:37 +08:00
qwqcode 5fdf3a27ce fix(auth): failed to register by social account on mysql database (#902) 2024-06-06 14:57:35 +08:00
qwqcode f8f509c0de perf(gravatar): convert email to lowercase before hashing for gravatar 2024-06-04 18:39:51 +08:00
qwqcode 437d943691 chore(docs): tidy up and update links 2024-06-02 15:33:09 +08:00
qwqcode 401cf5c21a perf(conf): add cache for config metadata to boost startup speed (#892) 2024-06-02 15:04:29 +08:00
qwqcode 77e9a687ac docs(dev): refine contributing.md and translate to chinese 2024-06-01 21:27:00 +08:00
qwqcode 85f88cbba5 perf(ui/conf): exclude conf pvEl, countEl and statPageKeyAttr from remove server (#905) 2024-06-01 21:25:29 +08:00
qwqcode efb34c23e5 chore(docs): revise katex import introduction (#897) 2024-05-31 19:30:35 +08:00
qwqcode 822a85c9e3 chore(plugins): fix window not defined issue for plugin-kit 2024-05-30 21:47:46 +08:00
qwqcode 630a3b1ff8 chore(docs): fix docs katex css 2024-05-30 20:14:18 +08:00
qwqcode ca6f8ed09c fix(plugin_katex): fix event issue causing katex integration failure (#897) 2024-05-30 20:03:02 +08:00
qwqcode a0b0a33862 feat(plugin_kit): add vite plugin for developing artalk plugins (#904) 2024-05-30 19:31:55 +08:00
qwqcode 4868cd9992 docs: refine documentation 2024-05-30 19:10:55 +08:00
qwqcode 2dfee533da fix(api/stats): fix site_pv response body and add unit tests (#896) 2024-05-29 10:57:14 +08:00
qwqcode dcaaefc71b refactor(dao): add date field to the page json entity 2024-05-29 10:52:25 +08:00
qwqcode 499a57213e chore(docs): fix edit link and update cases.md 2024-05-28 17:49:47 +08:00
Ever Fu b7fc86b3c6 chore(docs): add hexo-theme-solitude to cases.md (#893) 2024-05-28 17:35:50 +08:00
qwqcode 161ff8bfc3 fix(conf_env): enhance environment variable loading for config (#892)
* fix(conf_env): enhance environment variable loading for config

* improve NumberKeysMapToSlice func and fix unit tests

* auto-generate docs table
2024-05-27 20:03:18 +08:00
qwqcode 1e36d45ec3 chore(ci): remove arm/v7 docker build 2024-05-26 17:36:00 +08:00
qwqcode d2161cc0fb refactor(dao): improve QueryDBWithCache func and concurrent unit tests (#884) 2024-05-26 17:15:32 +08:00
qwqcode abbddfe9b4 feat(sync): add keyed rw-mutex 2024-05-26 17:05:45 +08:00
qwqcode 860dd698e7 feat(go): upgrade golang to v1.22.3 and some deps 2024-05-25 18:36:52 +08:00
guangwu acb087887c fix(api/transfer_upload): close temp file in transfer upload endpoint (#877) 2024-05-25 18:22:50 +08:00
qwqcode dbb3c55148 refactor(transfer): improve the reliability of the transfer (#883) 2024-05-25 18:00:27 +08:00
qwqcode fdfeef8042 fix(ui/sidebar): unable to logout if user is not admin in control center 2024-05-24 16:39:22 +08:00
qwqcode 824f122dcb refactor(ui/stat): use class selector for pageview elements by default (#880)
The statistics UI component has been updated. The default selectors for `pvEl` and `countEl` have changed from `#ArtalkPV` and `#ArtalkCount` to `.artalk-pv-count` and `.artalk-comment-count` (see #826 for more details). However, it remains backward compatible with the `#ArtalkPV` and `#ArtalkCount` elements for older versions, no HTML client updates are necessary.

In this PR, we also introduced a configuration option called `statPageKeyAttr` (value `"data-page-key"` by default) for customizing the attribute name that the statistics component uses to fetch the page key.
2024-05-23 13:47:07 +08:00
qwqcode 53d46d82b6 perf(gravatar): use sha256 hashing algorithm for gravatar (#874) 2024-05-22 21:14:43 +08:00
qwqcode bb218d0ba4 docs(ip_region): add instructions for obtaining accurate IP under proxy 2024-05-15 21:37:16 +08:00
qwqcode 984071d4b6 refactor(transfer): strip domain from page key by default (#873) 2024-05-15 20:58:53 +08:00
qwqcode 34b24a1f36 fix(ui/height_limit): height limit issue for collapsed comments (#865) 2024-05-15 15:43:26 +08:00
qwqcode 58657524cf fix(ui/types): remove marked dependency in dts (#868) 2024-05-11 22:29:40 +08:00
Kent Liao b5db161697 chore(docs): fix syntax error in import-blog (#864)
hexo example.
2024-05-10 09:15:47 +08:00
github-actions[bot] 4dd0ae40e2 chore: release v2.8.6 (#862)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2024-05-09 13:43:53 +08:00
qwqcode 5dea08a3f2 feat(ci): include frontend dist files in release (#860) 2024-05-09 13:24:50 +08:00
qwqcode 92464085e6 chore(pkg_manager): upgrade pnpm to v9.1.0 2024-05-09 11:52:08 +08:00
qwqcode 28f1fa11bd chore: remove console logs 2024-05-07 14:00:28 +08:00
qwqcode 3de1f11f47 chore(docs/landing): add animation for ocean wave 2024-05-06 20:36:23 +08:00
qwqcode dff1813fa5 chore(docs/landing): fix airplane animation 2024-05-06 20:35:30 +08:00
vybfi f4475830da chore(docs): fix vue example code (#856) 2024-05-06 16:42:06 +08:00
qwqcode 9c85a85153 docs: update introduction document 2024-05-04 21:17:38 +08:00
qwqcode 5a63d4c63d fix(sidebar/site): unable to edit the new site urls 2024-05-04 16:15:02 +08:00
qwqcode b8afcbb21a fix(cache/user): user id cache from email lookup not cleared 2024-05-04 09:48:06 +08:00
qwqcode 0c0a207068 chore(deps): upgrade go and ui deps 2024-05-03 23:25:41 +08:00
qwqcode be939816aa chore(ip_region): mute ipv6 invalid log 2024-05-03 23:25:11 +08:00
qwqcode 45d1bc1241 fix(api/pv): add mutex for page pv record endpoint 2024-05-03 23:25:10 +08:00
qwqcode ef5899e079 docs(auth): add social login feature (#854) 2024-05-03 23:25:10 +08:00
qwqcode 7187d0f058 feat(ui/auth): plugin-auth for integrating social login (#854) 2024-05-03 23:24:58 +08:00
qwqcode 88aec7e767 feat(auth): user accounts merge tool (#854) 2024-05-03 21:54:15 +08:00
qwqcode a09628c4e8 feat(auth): social login api endpoints (#854) 2024-05-03 21:54:06 +08:00
qwqcode 23d0d868de feat(sync): add keyed mutex 2024-05-03 21:25:31 +08:00
qwqcode f3e356e450 chore(template): tidy up template pkg naming 2024-05-02 17:19:40 +08:00
qwqcode 170db0fc2a feat(ui/img_lazyload): add support for lazy loading images (#850) 2024-05-02 11:03:34 +08:00
qwqcode c3f730b0e7 fix(ui/height_limit): height limit not working while loading images (#849) 2024-05-01 22:53:33 +08:00
qwqcode e132c31150 fix(ui/marked): optimize same origin link judgment logic 2024-04-30 16:18:32 +08:00
qwqcode fa6648ecf5 fix(db/migrate): fix root_id migrate for database lacking recursive CTE support (#848) (#846) 2024-04-30 14:40:27 +08:00
qwqcode a9331b426e fix(dao): ensure find and create functions thread safe (#845)
* fix(dao): ensure find and create functions thread safe

* feat(db/migrator): provide tool for merging duplicate page
2024-04-30 14:17:24 +08:00
qwqcode fbd1cd984d fix(ui/dark_mode): add support for configuring dark mode in backend (#790) 2024-04-27 19:57:09 +08:00
qwqcode accd10cef4 fix(ui/dark_mode): unable to toggle dark mode for sidebar in auto mode 2024-04-27 19:55:20 +08:00
qwqcode 690eb47eaa docs(i18n): add translation for Korean and Russian 2024-04-27 19:11:29 +08:00
qwqcode fc0dcee06c feat(i18n): add incremental updates feature for i18n code scan tool 2024-04-27 19:09:34 +08:00
qwqcode 895bfbd5e2 chore(multi_push): add response status code check 2024-04-27 19:06:26 +08:00
qwqcode e254350211 feat(multi_push/lark): add card mode for lark push (#839) 2024-04-27 19:05:30 +08:00
qwqcode f226d476e5 chore(typo): fix typo for moderator.keywords.replace in conf 2024-04-27 13:26:49 +08:00
qwqcode ee131fe6ef fix(comments_get): include site_name for isolation in associated query for comment's page 2024-04-26 16:42:35 +08:00
qwqcode 43e4c901b8 chore(db_logger): increase the slow SQL warning threshold 2024-04-26 16:35:52 +08:00
qwqcode bd5da20dd6 fix(db_migrate): drop fk_comments_user foreign key constraint of the users table 2024-04-26 16:34:40 +08:00
qwqcode 116d8f1919 chore(ci): fix build workflow 2024-04-25 00:01:51 +08:00
github-actions[bot]andqwqcode 99b71a15f8 chore: release v2.8.5 (#844)
* chore: release v2.8.5

* Update CHANGELOG.md

---------

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

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

* chore: tweaks

* chore: mute attw

---------

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


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

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

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

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

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

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

* test: add unit test

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

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

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

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

* refactor: remove forced site_origin check

* refactor: update http client

* fix

* add more api description and error code

* reduce nestings in response structures

* separate unread

* refactor(api/comments): get comments

* refactor: frontend api module

* chore: remove vite temporary file

* chore: restore swagger file

* update

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

* refactor pagesAllFetch

* fix ci

* remove useless codes

* limiter protected paths

* add test for version endpoint

* rename handler code files

* code file separate

* fix some bug of interacting with backend

* add fetch error class for handling

* fix and rename

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

* fix new checker captcha iframe url

* rename and add swagger id field

* replace tab with spaces in go comment

* chore: refine

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

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

* replace original api client with auto-generated codes

* artalk pkg apply new api client

* artalk-sidebar pkg apply new api client

* fix issues

* fix sidebar locale conf and refactor user login

* fix and refactor captcha and limiter

* fix ui testing

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

---------

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

* perf(ui/build): better dts generation

* chore: update pnpm-lock.yaml

* chore: fix env variable on windows

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

* fix: config always get override by defaults

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

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

* chore: fix path issue on win env

* fix: mergeDeep avoid prototype pollution

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

---------

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

* update config files

* update github workflows

* update vscode settings.json

* update docs

* update build scripts

* tidy up

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

* chore: fix eslint

* ci: add docs build test

* update test-docs.yml

* fix script

* add netlify.toml

* fix docs:patch

---------

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

No files matched your search

-79
View File
@@ -1,79 +0,0 @@
version: 2.1
orbs:
node: circleci/node@5.0.3
codecov: codecov/codecov@3.3.0
executors:
base:
docker:
- image: cimg/base:stable
node:
docker:
- image: 'cimg/node:18.19.0'
go:
docker:
- image: cimg/go:1.21.3
parameters:
trigger-app:
type: boolean
default: false
run-them-all:
type: boolean
default: false
jobs:
## Backend
test_app:
executor: go
working_directory: ~/go/src/github.com/ArtalkJS/Artalk
environment:
GO111MODULE: "on"
steps:
- checkout
- run:
name: "Print the Go version"
command: >
go version
- restore_cache:
keys:
- go-mod-1.21.3-{{ checksum "go.sum" }}
- run:
name: Install Dependencies
command: go mod download
- save_cache:
key: go-mod-1.21.3-{{ checksum "go.sum" }}
paths:
- "~/go/pkg/mod"
- run:
name: Run tests
command: |
mkdir -p /tmp/test-reports
gotestsum --junitfile /tmp/test-reports/unit-tests.xml -- -coverprofile=/tmp/test-reports/coverage.out ./...
- store_test_results:
path: /tmp/test-reports
- codecov/upload:
flags: go
file: /tmp/test-reports/coverage.out
all_projects:
executor: base
steps:
- run:
command: |
echo "all"
workflows:
build-app:
when:
or:
- << pipeline.parameters.trigger-app >>
- << pipeline.parameters.run-them-all >>
jobs:
- test_app
build-shared-other:
when: << pipeline.parameters.run-them-all >>
jobs:
- all_projects
-25
View File
@@ -1,25 +0,0 @@
# https://circleci.com/docs/2.0/configuration-reference
version: 2.1
# this allows you to use CircleCI's dynamic configuration
# https://circleci.com/docs/2.0/dynamic-config/
setup: true
# the path-filtering orb is required to continue a pipeline based on
# https://circleci.com/developer/orbs/orb/circleci/path-filtering
orbs:
path-filtering: circleci/path-filtering@1.0.0
workflows:
setup:
jobs:
- path-filtering/filter:
mapping: |
(cmd|internal|server|pkg|test|conf)/.* trigger-app true
main.go|go.mod|go.sum trigger-app true
base-revision: master # git branch name
config-path: .circleci/conditional_config.yml
filters:
branches:
ignore:
- gh-pages
+14
View File
@@ -0,0 +1,14 @@
node_modules
.git
.github
.DS_Store
.vscode
bin
docs/docs/*
!docs/docs/package.json
!docs/docs/tsconfig.json
local
test
ui/**/dist
**/playwright-report
**/test-results
+3 -2
View File
@@ -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
+31
View File
@@ -0,0 +1,31 @@
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@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
env:
ISSUE_NUMBER: ${{ inputs.issue_number }}
STDOUT: ${{ inputs.content }}
with:
script: |
const issueNumber = Number.parseInt(process.env.ISSUE_NUMBER, 10)
if (!Number.isSafeInteger(issueNumber) || issueNumber <= 0) {
throw new Error('Invalid issue number')
}
github.rest.issues.createComment({
issue_number: issueNumber,
owner: context.repo.owner,
repo: context.repo.repo,
body: process.env.STDOUT
})
+5 -2
View File
@@ -4,8 +4,8 @@ info:
title: CHANGELOG
repository_url: https://github.com/ArtalkJS/Artalk
options:
tag_filter_pattern: '^v'
sort: "date"
tag_filter_pattern: "^v"
sort: date
commits:
filters:
Type:
@@ -13,6 +13,7 @@ options:
- fix
- perf
- refactor
- test
- docs
commit_groups:
sort_by: Custom
@@ -21,12 +22,14 @@ options:
- fix
- perf
- refactor
- test
- docs
title_maps:
feat: Features
fix: Bug Fixes
perf: Performance Improvements
refactor: Code Refactoring
test: Testing
docs: Documentation
header:
pattern: "^(\\w*)(?:\\(([\\w\\$\\.\\-\\*\\s\\/]*)\\))?\\:\\s(.*)$"
+15 -16
View File
@@ -9,18 +9,24 @@ updates:
directory: /
schedule:
interval: monthly
cooldown:
default-days: 7
commit-message:
prefix: "chore(deps/go): "
groups:
deps:
patterns:
- '*'
- "*"
open-pull-requests-limit: 15
- package-ecosystem: npm
directory: /ui
# setup only for whole workspace to fix issues with package.lock,
# SEE https://github.com/dependabot/dependabot-core/issues/4993#issuecomment-1739296001
directory: /
schedule:
interval: monthly
cooldown:
default-days: 7
commit-message:
prefix: "chore(deps/ui): "
groups:
@@ -29,39 +35,32 @@ updates:
dev-deps:
dependency-type: development
open-pull-requests-limit: 15
- package-ecosystem: npm
directory: /docs
schedule:
interval: monthly
commit-message:
prefix: "chore(deps/docs): "
groups:
deps:
patterns:
- '*'
open-pull-requests-limit: 15
versioning-strategy: increase
- package-ecosystem: docker
directory: /
schedule:
interval: monthly
cooldown:
default-days: 7
commit-message:
prefix: "chore(deps/docker): "
groups:
deps:
patterns:
- '*'
- "*"
open-pull-requests-limit: 15
- package-ecosystem: github-actions
directory: /.github/workflows
schedule:
interval: monthly
cooldown:
default-days: 7
commit-message:
prefix: "chore(deps/ci): "
groups:
deps:
patterns:
- '*'
- "*"
open-pull-requests-limit: 15
+76 -56
View File
@@ -1,15 +1,20 @@
name: Build App
run-name: Build Go App and Publish
on:
repository_dispatch:
types: [artalk-release]
workflow_call:
inputs:
version:
required: true
type: string
ref:
required: true
type: string
dry_run:
required: true
type: boolean
env:
GO_VERSION: '1.21.3'
PKG_NAME: 'github.com/ArtalkJS/Artalk'
DOCKER_IMG: ghcr.io/goreleaser/goreleaser-cross
CACHE_DIR: /tmp/cache/docker-image
permissions:
contents: write
jobs:
build_publish:
@@ -17,68 +22,83 @@ jobs:
steps:
- name: Checkout Code
uses: actions/checkout@v3
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
ref: ${{ inputs.ref }}
persist-credentials: false
# `go-releaser` will read the semver version from git tag name
# `git-chglog` will diff the tag and generate changelog
fetch-depth: 0
- name: Checkout latest tag
run: |
# fetch tags
git fetch --prune --unshallow --tags -f
- name: Setup Go
uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # v7.0.0
with:
go-version-file: go.mod
# Release inputs are verified from the lock files instead of shared caches.
cache: false
# checkout latest version
VERSION=$(git describe --tags --abbrev=0)
git checkout ${VERSION}
- name: Setup pnpm
uses: pnpm/action-setup@0ebf47130e4866e96fce0953f49152a61190b271 # v6.0.9
with:
version: 10.33.2
echo "VERSION=${VERSION}" >> $GITHUB_ENV
# disable cache because the err `no space left on device`
# - name: Docker Image Cache
# id: docker-cache
# uses: actions/cache@v3
# with:
# path: ${{ env.CACHE_DIR }}
# key: docker-image-go-cross-${{ env.GO_VERSION }}
- name: Pull Docker Image
# if: steps.docker-cache.outputs.cache-hit != 'true'
run: |
docker pull "${DOCKER_IMG}:v${GO_VERSION}"
# mkdir -p "${CACHE_DIR}"
# docker save -o "${CACHE_DIR}/go-cross.tar" "${DOCKER_IMG}:v${GO_VERSION}"
# - name: Restore Docker Image from Cache
# if: steps.docker-cache.outputs.cache-hit == 'true'
# run: docker load -i ${CACHE_DIR}/go-cross.tar
- name: Setup Node
uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
with:
node-version: 22.x
package-manager-cache: false
- 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
GOBIN="$RUNNER_TEMP/bin" go install github.com/git-chglog/git-chglog/cmd/git-chglog@v0.15.4
echo "$RUNNER_TEMP/bin" >> "$GITHUB_PATH"
go version -m "$RUNNER_TEMP/bin/git-chglog"
- name: Create local tag for dry run
if: ${{ inputs.dry_run }}
env:
VERSION: ${{ inputs.version }}
run: |
if git rev-parse --quiet --verify "refs/tags/$VERSION" > /dev/null; then
tag_commit="$(git rev-list -n 1 "$VERSION")"
head_commit="$(git rev-parse HEAD)"
if [[ "$tag_commit" != "$head_commit" ]]; then
echo "Tag $VERSION already points to $tag_commit, expected $head_commit."
exit 1
fi
else
git tag "$VERSION"
fi
- name: Pre Build
run: |-
mkdir -p local
# github token
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 "$VERSION" > local/release-notes.md
# copy config file
cp conf/artalk.example.yml artalk.yml
env:
VERSION: ${{ inputs.version }}
- name: Print Release Notes
run: cat local/release-notes.md
- name: Validate release build
if: ${{ inputs.dry_run }}
uses: goreleaser/goreleaser-action@f06c13b6b1a9625abc9e6e439d9c05a8f2190e94 # v7.2.3
with:
distribution: goreleaser
version: v2.17.0
args: release --clean --release-notes local/release-notes.md --skip=publish
- name: Build and Release
run: |
docker run \
--rm \
--privileged \
-v /var/run/docker.sock:/var/run/docker.sock \
-v $(pwd)/sysroot:/sysroot \
-v $(pwd):/go/src/${PKG_NAME} \
-w /go/src/${PKG_NAME} \
-e CGO_ENABLED=1 \
--env-file local/.release-env \
ghcr.io/goreleaser/goreleaser-cross:v${GO_VERSION} \
release --release-notes local/release-notes.md
if: ${{ !inputs.dry_run }}
uses: goreleaser/goreleaser-action@f06c13b6b1a9625abc9e6e439d9c05a8f2190e94 # v7.2.3
with:
distribution: goreleaser
version: v2.17.0
args: release --clean --release-notes local/release-notes.md
env:
GITHUB_TOKEN: ${{ github.token }}
+259 -81
View File
@@ -1,110 +1,288 @@
name: Build Docker
run-name: Build Docker Image and Publish
on:
repository_dispatch:
types: [artalk-release]
workflow_call:
inputs:
version:
required: true
type: string
ref:
required: true
type: string
commit:
required: true
type: string
dry_run:
required: true
type: boolean
secrets:
DOCKERHUB_USERNAME:
required: false
DOCKERHUB_TOKEN:
required: false
permissions:
contents: read
env:
DIGEST_DIR: /tmp/digests
DOCKER_IMG: artalk/artalk-go
jobs:
build_publish:
runs-on: ubuntu-latest
ui:
name: Build Docker UI assets
runs-on: ubuntu-24.04
steps:
- name: Checkout Code
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
ref: ${{ inputs.ref }}
persist-credentials: false
- name: Verify release source
env:
RELEASE_COMMIT: ${{ inputs.commit }}
run: |
if [[ ! "$RELEASE_COMMIT" =~ ^[0-9a-f]{40}$ ]]; then
echo "Invalid release commit: $RELEASE_COMMIT"
exit 1
fi
checkout_commit="$(git rev-parse HEAD)"
if [[ "$checkout_commit" != "$RELEASE_COMMIT" ]]; then
echo "Checked out $checkout_commit, expected $RELEASE_COMMIT."
exit 1
fi
- name: Setup pnpm
uses: pnpm/action-setup@0ebf47130e4866e96fce0953f49152a61190b271 # v6.0.9
with:
version: 10.33.2
- name: Setup Node
uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
with:
node-version: 22.x
cache: pnpm
- name: Install dependencies
run: pnpm install --frozen-lockfile
- name: Build UI
run: make build-frontend
- name: Upload UI assets
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: docker-ui-src
path: |
public
ui/artalk/dist
if-no-files-found: error
retention-days: 1
build:
name: Build Docker (${{ matrix.platform }})
needs: ui
runs-on: ${{ matrix.runner }}
strategy:
fail-fast: false
matrix:
include:
- runner: ubuntu-24.04
platform: linux/amd64
platform_pair: linux_amd64
- runner: ubuntu-24.04-arm
platform: linux/arm64
platform_pair: linux_arm64
steps:
- name: Checkout Code
uses: actions/checkout@v3
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
ref: ${{ inputs.ref }}
persist-credentials: false
- name: Checkout latest tag
- name: Verify release source
env:
RELEASE_COMMIT: ${{ inputs.commit }}
run: |
# fetch tags
git fetch --prune --unshallow --tags -f
if [[ ! "$RELEASE_COMMIT" =~ ^[0-9a-f]{40}$ ]]; then
echo "Invalid release commit: $RELEASE_COMMIT"
exit 1
fi
checkout_commit="$(git rev-parse HEAD)"
if [[ "$checkout_commit" != "$RELEASE_COMMIT" ]]; then
echo "Checked out $checkout_commit, expected $RELEASE_COMMIT."
exit 1
fi
# checkout latest version
VERSION=$(git describe --tags --abbrev=0)
git checkout ${VERSION}
- name: Download UI assets
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with:
name: docker-ui-src
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)"
- name: Generate Docker metadata
id: meta
uses: docker/metadata-action@dc802804100637a589fabce1cb79ff13a1411302 # v6.2.0
with:
images: ${{ env.DOCKER_IMG }}
tags: type=raw,value=build-${{ matrix.platform_pair }}
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
if: ${{ !inputs.dry_run }}
uses: docker/login-action@af1e73f918a031802d376d3c8bbc3fe56130a9b0 # v4.4.0
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
uses: docker/setup-buildx-action@bb05f3f5519dd87d3ba754cc423b652a5edd6d2c # v4.2.0
- name: Cache Docker layers
uses: actions/cache@v3
- name: Build dry-run image
if: ${{ inputs.dry_run }}
id: build_dry_run
uses: docker/build-push-action@53b7df96c91f9c12dcc8a07bcb9ccacbed38856a # v7.3.0
with:
path: /tmp/.buildx-cache
key: ${{ runner.os }}-buildx-${{ github.sha }}
restore-keys: |
${{ runner.os }}-buildx-
# https://github.com/docker/metadata-action
- name: Gen docker meta
id: meta
uses: docker/metadata-action@v4
with:
context: git
images: |
${{ env.DOCKER_IMG }}
tags: |
type=ref,event=branch
type=ref,event=pr
type=semver,pattern={{version}}
type=semver,pattern={{major}}.{{minor}}
type=sha
# https://github.com/docker/build-push-action
- name: Build and Push
id: docker_build
uses: docker/build-push-action@v4
with:
builder: ${{ steps.buildx.outputs.name }}
context: ./
context: .
file: ./Dockerfile
platforms: 'linux/amd64,linux/arm64'
push: true
tags: ${{ steps.meta.outputs.tags }}
platforms: ${{ matrix.platform }}
labels: ${{ steps.meta.outputs.labels }}
cache-from: type=local,src=/tmp/.buildx-cache
cache-to: type=local,dest=/tmp/.buildx-cache
tags: ${{ steps.meta.outputs.tags }}
build-args: |
APP_VERSION=${{ inputs.version }}
APP_COMMIT_HASH=${{ inputs.commit }}
SKIP_UI_BUILD=true
outputs: type=docker
cache-from: type=gha,scope=release-${{ matrix.platform_pair }}
cache-to: type=gha,mode=max,scope=release-${{ matrix.platform_pair }}
- 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 }})"
- name: Build and push image by digest
if: ${{ !inputs.dry_run }}
id: build
uses: docker/build-push-action@53b7df96c91f9c12dcc8a07bcb9ccacbed38856a # v7.3.0
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
})
context: .
file: ./Dockerfile
platforms: ${{ matrix.platform }}
labels: ${{ steps.meta.outputs.labels }}
build-args: |
APP_VERSION=${{ inputs.version }}
APP_COMMIT_HASH=${{ inputs.commit }}
SKIP_UI_BUILD=true
outputs: type=image,push=true,name=${{ env.DOCKER_IMG }},push-by-digest=true,name-canonical=true
cache-from: type=gha,scope=release-${{ matrix.platform_pair }}
cache-to: type=gha,mode=max,scope=release-${{ matrix.platform_pair }}
provenance: mode=max
sbom: true
- name: Print image digest
run: echo ${{ steps.docker_build.outputs.digest }}
- name: Smoke test dry-run image
if: ${{ inputs.dry_run }}
env:
IMAGE: ${{ steps.meta.outputs.tags }}
VERSION: ${{ inputs.version }}
run: |
output="$(docker run --rm --entrypoint /artalk "$IMAGE" version)"
grep --fixed-strings "Artalk ($VERSION/" <<< "$output"
- name: Smoke test published image
if: ${{ !inputs.dry_run }}
env:
IMAGE: ${{ env.DOCKER_IMG }}@${{ steps.build.outputs.digest }}
VERSION: ${{ inputs.version }}
run: |
docker pull "$IMAGE"
output="$(docker run --rm --entrypoint /artalk "$IMAGE" version)"
grep --fixed-strings "Artalk ($VERSION/" <<< "$output"
- name: Export digest
if: ${{ !inputs.dry_run }}
env:
DIGEST: ${{ steps.build.outputs.digest }}
run: |
mkdir -p "$DIGEST_DIR"
touch "$DIGEST_DIR/${DIGEST#sha256:}"
- name: Upload digest
if: ${{ !inputs.dry_run }}
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: release-digest-${{ matrix.platform_pair }}
path: ${{ env.DIGEST_DIR }}/*
if-no-files-found: error
retention-days: 1
merge:
name: Publish Docker manifest
if: ${{ !inputs.dry_run }}
needs: build
runs-on: ubuntu-24.04
steps:
- name: Download digests
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with:
path: ${{ env.DIGEST_DIR }}
pattern: release-digest-*
merge-multiple: true
- name: Setup Docker Buildx
uses: docker/setup-buildx-action@bb05f3f5519dd87d3ba754cc423b652a5edd6d2c # v4.2.0
- name: Prepare release metadata
env:
RELEASE_COMMIT: ${{ inputs.commit }}
run: |
if [[ ! "$RELEASE_COMMIT" =~ ^[0-9a-f]{40}$ ]]; then
echo "Invalid release commit: $RELEASE_COMMIT"
exit 1
fi
echo "RELEASE_COMMIT_SHORT=${RELEASE_COMMIT:0:7}" >> "$GITHUB_ENV"
- name: Generate Docker metadata
id: meta
uses: docker/metadata-action@dc802804100637a589fabce1cb79ff13a1411302 # v6.2.0
with:
images: ${{ env.DOCKER_IMG }}
tags: |
type=semver,pattern={{version}},value=${{ inputs.version }}
type=semver,pattern={{major}}.{{minor}},value=${{ inputs.version }}
type=raw,value=sha-${{ env.RELEASE_COMMIT_SHORT }}
- name: Login to DockerHub
uses: docker/login-action@af1e73f918a031802d376d3c8bbc3fe56130a9b0 # v4.4.0
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Create and push manifest
env:
METADATA: ${{ steps.meta.outputs.json }}
run: |
mapfile -t tags < <(jq -r '.tags[]' <<< "$METADATA")
tag_args=()
for tag in "${tags[@]}"; do
tag_args+=(--tag "$tag")
done
shopt -s nullglob
digest_files=("$DIGEST_DIR"/*)
if [[ "${#digest_files[@]}" -ne 2 ]]; then
echo "Expected 2 platform digests, found ${#digest_files[@]}."
exit 1
fi
sources=()
for digest_file in "${digest_files[@]}"; do
digest="$(basename "$digest_file")"
if [[ ! "$digest" =~ ^[0-9a-f]{64}$ ]]; then
echo "Invalid image digest: $digest"
exit 1
fi
sources+=("$DOCKER_IMG@sha256:$digest")
done
docker buildx imagetools create "${tag_args[@]}" "${sources[@]}"
- name: Inspect image
env:
IMAGE: ${{ env.DOCKER_IMG }}:${{ steps.meta.outputs.version }}
run: docker buildx imagetools inspect "$IMAGE"
+40
View File
@@ -0,0 +1,40 @@
name: Build Done
on:
workflow_call:
inputs:
version:
required: true
type: string
ref:
required: true
type: string
dry_run:
required: true
type: boolean
issue_number:
required: true
type: number
permissions:
contents: read
issues: write
pull-requests: write
jobs:
done:
runs-on: ubuntu-latest
steps:
- name: Checkout Code
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
ref: ${{ inputs.ref }}
persist-credentials: false
- name: Comment done info
uses: ./.github/actions/comment
if: ${{ !inputs.dry_run && inputs.issue_number != 0 }}
with:
issue_number: ${{ inputs.issue_number }}
content: |-
🎉 Finished build and publish ${{ inputs.version }} ([NPM Package](https://www.npmjs.com/package/artalk?activeTab=versions) / [Docker Image](https://hub.docker.com/r/artalk/artalk-go/tags) / [Github Release](https://github.com/ArtalkJS/Artalk/releases/tag/${{ inputs.version }})).
-58
View File
@@ -1,58 +0,0 @@
name: Build Frontend
run-name: Build Frontend and Publish
on:
repository_dispatch:
types: [artalk-release]
jobs:
build_publish:
runs-on: ubuntu-latest
defaults:
run:
working-directory: ./ui # set for building frontend
steps:
- name: Checkout Code
uses: actions/checkout@v3
- name: Checkout latest tag
run: |
git fetch --prune --unshallow --tags -f
git checkout $(git describe --tags --abbrev=0)
- name: Use pnpm
uses: pnpm/action-setup@v2
with:
version: 8
- name: Setup node
uses: actions/setup-node@v3
with:
node-version: 18.x
registry-url: https://registry.npmjs.org/
cache: 'pnpm'
cache-dependency-path: './ui/pnpm-lock.yaml'
- name: Install dependencies
run: pnpm install
- name: Build
run: pnpm build
- name: Publish
run: pnpm publish -F artalk --no-git-checks
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
# GitHub Packages
#
# Setup .npmrc file to publish to GitHub Packages
# - uses: actions/setup-node@v2
# with:
# registry-url: 'https://npm.pkg.github.com'
# # Publish to GitHub Packages
# - run: npm publish
# env:
# NODE_AUTH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+381
View File
@@ -0,0 +1,381 @@
name: Build Nightly
run-name: Build Nightly ${{ inputs.dry_run && '(🧪 Dry-Run)' || '' }}
on:
schedule:
- cron: "0 10 * * *"
workflow_dispatch:
inputs:
dry_run:
description: "Build without publishing"
type: boolean
default: true
permissions:
contents: read
concurrency:
group: build-nightly
cancel-in-progress: false
env:
DIST_DIR: /tmp/builds
DIGEST_DIR: /tmp/digests
DOCKER_IMG: artalk/artalk-go
jobs:
prepare:
runs-on: ubuntu-24.04
outputs:
skip: ${{ steps.check.outputs.skip }}
steps:
- name: Checkout Code
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- name: Check whether the scheduled build should run
id: check
if: github.event_name == 'schedule'
run: |
if [[ "$(git log --since='24 hours ago' --oneline | wc -l)" -eq 0 ]] || \
[[ "$GITHUB_REPOSITORY" != "ArtalkJS/Artalk" ]]; then
echo "skip=true" >> "$GITHUB_OUTPUT"
fi
ui:
name: Build Nightly UI assets
if: ${{ needs.prepare.outputs.skip != 'true' }}
needs: prepare
runs-on: ubuntu-24.04
steps:
- name: Checkout Code
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
fetch-depth: 0
persist-credentials: false
- name: Setup pnpm
uses: pnpm/action-setup@0ebf47130e4866e96fce0953f49152a61190b271 # v6.0.9
with:
version: 10.33.2
- name: Setup Node
uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
with:
node-version: 22.x
cache: pnpm
- name: Install dependencies
run: pnpm install --frozen-lockfile
- name: Build UI
id: build_ui
run: |
make build-frontend
echo "ui_tarball=$(make -s pack-frontend)" >> "$GITHUB_OUTPUT"
- name: Upload UI assets
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: nightly-ui-src
path: |
public
ui/artalk/dist
if-no-files-found: error
retention-days: 1
- name: Upload UI tarball
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: build-ui-tarball
path: ${{ steps.build_ui.outputs.ui_tarball }}
if-no-files-found: error
retention-days: 1
build:
name: Build Nightly (${{ matrix.platform }})
needs: ui
runs-on: ${{ matrix.runner }}
strategy:
fail-fast: false
matrix:
include:
- runner: ubuntu-24.04
platform: linux/amd64
platform_pair: linux_amd64
- runner: ubuntu-24.04-arm
platform: linux/arm64
platform_pair: linux_arm64
steps:
- name: Checkout Code
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
fetch-depth: 0
persist-credentials: false
- name: Download UI assets
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with:
name: nightly-ui-src
- name: Generate Docker metadata
id: meta
uses: docker/metadata-action@dc802804100637a589fabce1cb79ff13a1411302 # v6.2.0
with:
images: ${{ env.DOCKER_IMG }}
tags: type=raw,value=nightly-build-${{ matrix.platform_pair }}
- name: Login to DockerHub
if: ${{ github.event_name == 'schedule' || !inputs.dry_run }}
uses: docker/login-action@af1e73f918a031802d376d3c8bbc3fe56130a9b0 # v4.4.0
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Setup Docker Buildx
uses: docker/setup-buildx-action@bb05f3f5519dd87d3ba754cc423b652a5edd6d2c # v4.2.0
- name: Build dry-run image
if: ${{ github.event_name == 'workflow_dispatch' && inputs.dry_run }}
uses: docker/build-push-action@53b7df96c91f9c12dcc8a07bcb9ccacbed38856a # v7.3.0
with:
context: .
platforms: ${{ matrix.platform }}
labels: ${{ steps.meta.outputs.labels }}
build-args: |
APP_COMMIT_HASH=${{ github.sha }}
SKIP_UI_BUILD=true
outputs: type=docker,name=${{ steps.meta.outputs.tags }}
cache-from: type=gha,scope=nightly-${{ matrix.platform_pair }}
cache-to: type=gha,mode=max,scope=nightly-${{ matrix.platform_pair }}
- name: Build and push image by digest
if: ${{ github.event_name == 'schedule' || !inputs.dry_run }}
id: build
uses: docker/build-push-action@53b7df96c91f9c12dcc8a07bcb9ccacbed38856a # v7.3.0
with:
context: .
platforms: ${{ matrix.platform }}
labels: ${{ steps.meta.outputs.labels }}
build-args: |
APP_COMMIT_HASH=${{ github.sha }}
SKIP_UI_BUILD=true
outputs: |
type=docker,name=${{ steps.meta.outputs.tags }}
type=image,push=true,name=${{ env.DOCKER_IMG }},push-by-digest=true,name-canonical=true
cache-from: type=gha,scope=nightly-${{ matrix.platform_pair }}
cache-to: type=gha,mode=max,scope=nightly-${{ matrix.platform_pair }}
- name: Smoke test image
env:
IMAGE: ${{ steps.meta.outputs.tags }}
run: docker run --rm --entrypoint /artalk "$IMAGE" version
- name: Export digest
if: ${{ github.event_name == 'schedule' || !inputs.dry_run }}
env:
DIGEST: ${{ steps.build.outputs.digest }}
run: |
mkdir -p "$DIGEST_DIR"
touch "$DIGEST_DIR/${DIGEST#sha256:}"
- name: Upload digest
if: ${{ github.event_name == 'schedule' || !inputs.dry_run }}
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: nightly-digest-${{ matrix.platform_pair }}
path: ${{ env.DIGEST_DIR }}/*
if-no-files-found: error
retention-days: 1
- name: Export Docker image
id: docker
env:
IMAGE: ${{ steps.meta.outputs.tags }}
PLATFORM_PAIR: ${{ matrix.platform_pair }}
run: |
image_file="artalk_docker_nigthly_$(date +'%Y%m%d')_${PLATFORM_PAIR}.tar.gz"
docker save "$IMAGE" | gzip > "$image_file"
echo "image_file=$image_file" >> "$GITHUB_OUTPUT"
- name: Pack app
id: app
env:
IMAGE: ${{ steps.meta.outputs.tags }}
PLATFORM_PAIR: ${{ matrix.platform_pair }}
run: |
base_dir="/tmp/app_pkg"
name="artalk_nigthly_$(date +'%Y%m%d')_${PLATFORM_PAIR}"
package_dir="$base_dir/$name"
package_file="$base_dir/$name.tar.gz"
mkdir -p "$package_dir"
docker run --rm --entrypoint cat "$IMAGE" /artalk > "$package_dir/artalk"
chmod +x "$package_dir/artalk"
cp conf/artalk.example.yml "$package_dir/artalk.yml"
cp README.md LICENSE CHANGELOG.md "$package_dir"
tar -czf "$package_file" -C "$base_dir" "$name"
echo "package_file=$package_file" >> "$GITHUB_OUTPUT"
- name: Collect build artifacts
env:
APP_PACKAGE: ${{ steps.app.outputs.package_file }}
DOCKER_IMAGE: ${{ steps.docker.outputs.image_file }}
run: |
mkdir -p "$DIST_DIR"
mv "$APP_PACKAGE" "$DIST_DIR"
mv "$DOCKER_IMAGE" "$DIST_DIR"
- name: Upload build artifacts
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: build-${{ matrix.platform_pair }}
path: ${{ env.DIST_DIR }}/*
if-no-files-found: error
retention-days: 1
docker_merge:
name: Publish Nightly Docker manifest
if: ${{ github.event_name == 'schedule' || !inputs.dry_run }}
needs: build
runs-on: ubuntu-24.04
steps:
- name: Download digests
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with:
path: ${{ env.DIGEST_DIR }}
pattern: nightly-digest-*
merge-multiple: true
- name: Setup Docker Buildx
uses: docker/setup-buildx-action@bb05f3f5519dd87d3ba754cc423b652a5edd6d2c # v4.2.0
- name: Generate Docker metadata
id: meta
uses: docker/metadata-action@dc802804100637a589fabce1cb79ff13a1411302 # v6.2.0
with:
images: ${{ env.DOCKER_IMG }}
tags: type=raw,value=nightly
- name: Login to DockerHub
uses: docker/login-action@af1e73f918a031802d376d3c8bbc3fe56130a9b0 # v4.4.0
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Create and push manifest
env:
METADATA: ${{ steps.meta.outputs.json }}
run: |
mapfile -t tags < <(jq -r '.tags[]' <<< "$METADATA")
tag_args=()
for tag in "${tags[@]}"; do
tag_args+=(--tag "$tag")
done
shopt -s nullglob
digest_files=("$DIGEST_DIR"/*)
if [[ "${#digest_files[@]}" -ne 2 ]]; then
echo "Expected 2 platform digests, found ${#digest_files[@]}."
exit 1
fi
sources=()
for digest_file in "${digest_files[@]}"; do
digest="$(basename "$digest_file")"
if [[ ! "$digest" =~ ^[0-9a-f]{64}$ ]]; then
echo "Invalid image digest: $digest"
exit 1
fi
sources+=("$DOCKER_IMG@sha256:$digest")
done
docker buildx imagetools create "${tag_args[@]}" "${sources[@]}"
- name: Inspect image
env:
IMAGE: ${{ env.DOCKER_IMG }}:${{ steps.meta.outputs.version }}
run: docker buildx imagetools inspect "$IMAGE"
release:
name: Publish Nightly GitHub release
if: ${{ github.event_name == 'schedule' || !inputs.dry_run }}
needs: [build, docker_merge]
runs-on: ubuntu-24.04
permissions:
contents: write
steps:
- name: Checkout Code
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
fetch-depth: 0
persist-credentials: false
- name: Download builds
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with:
path: ${{ env.DIST_DIR }}
pattern: build-*
merge-multiple: true
- name: Setup Go
uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # v7.0.0
with:
go-version-file: go.mod
cache: false
- name: Setup git-chglog
run: |
GOBIN="$RUNNER_TEMP/bin" go install github.com/git-chglog/git-chglog/cmd/git-chglog@v0.15.4
echo "$RUNNER_TEMP/bin" >> "$GITHUB_PATH"
go version -m "$RUNNER_TEMP/bin/git-chglog"
- name: Generate changelog
run: |
git-chglog --config .github/chglog/config.yml --next-tag nightly nightly > /tmp/changelog.md
cat >> /tmp/changelog.md <<'EOF'
> [!NOTE]
> The Nightly version is automatically built from the latest code and may be unstable.
> Docker users can run `docker pull artalk/artalk-go:nightly` to get this build.
EOF
- name: Calculate checksums
run: |
cd "$DIST_DIR"
sha256sum -- * > checksums.txt
cat checksums.txt
- name: Move Nightly tag
env:
GH_TOKEN: ${{ github.token }}
run: |
if gh api "repos/$GITHUB_REPOSITORY/git/ref/tags/nightly" > /dev/null 2>&1; then
gh api --method PATCH "repos/$GITHUB_REPOSITORY/git/refs/tags/nightly" \
-f sha="$GITHUB_SHA" -F force=true > /dev/null
else
gh api --method POST "repos/$GITHUB_REPOSITORY/git/refs" \
-f ref=refs/tags/nightly -f sha="$GITHUB_SHA" > /dev/null
fi
tag_sha="$(gh api "repos/$GITHUB_REPOSITORY/git/ref/tags/nightly" --jq '.object.sha')"
if [[ "$tag_sha" != "$GITHUB_SHA" ]]; then
echo "Nightly tag points to $tag_sha, expected $GITHUB_SHA."
exit 1
fi
- name: Publish release
env:
GH_TOKEN: ${{ github.token }}
run: |
gh release delete nightly --yes || true
mapfile -d '' release_files < <(find "$DIST_DIR" -type f -print0)
gh release create nightly "${release_files[@]}" \
--title "🧪 Nightly Version" \
--notes-file /tmp/changelog.md \
--prerelease \
--target "$GITHUB_SHA"
+265
View File
@@ -0,0 +1,265 @@
name: Build Pre Tagging
on:
workflow_call:
inputs:
dry_run:
required: true
type: boolean
issue_number:
required: true
type: number
version:
required: false
type: string
default: ""
release_commit:
description: "Immutable commit to tag when the release tag does not exist"
required: false
type: string
default: ""
outputs:
version:
description: "Version"
value: ${{ jobs.tagging.outputs.version }}
ref:
description: "Git ref to build"
value: ${{ jobs.tagging.outputs.ref }}
commit:
description: "Release source commit"
value: ${{ jobs.tagging.outputs.commit }}
permissions:
contents: write
issues: write
pull-requests: write
jobs:
tagging:
runs-on: ubuntu-latest
steps:
- name: Get release version
id: version
env:
REF: ${{ github.head_ref || github.ref }}
REQUESTED_VERSION: ${{ inputs.version }}
run: |
if [[ -n "$REQUESTED_VERSION" ]]; then
VERSION="$REQUESTED_VERSION"
else
VERSION="${REF#refs/tags/}"
VERSION="${VERSION#refs/heads/}"
VERSION="${VERSION#release/}"
fi
if [[ ! "$VERSION" =~ ^v[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
echo "Invalid version format: $VERSION, please check git ref or tag."
exit 1
fi
echo "Version: $VERSION"
echo "version=$VERSION" >> "$GITHUB_OUTPUT"
- name: Resolve release target
id: target
env:
DEFAULT_COMMIT: ${{ github.sha }}
DRY_RUN: ${{ inputs.dry_run }}
GH_TOKEN: ${{ github.token }}
REQUESTED_COMMIT: ${{ inputs.release_commit }}
VERSION: ${{ steps.version.outputs.version }}
run: |
resolve_tag_commit() {
local object_type="$1"
local object_sha="$2"
local depth=0
while [[ "$object_type" == "tag" ]]; do
depth=$((depth + 1))
if (( depth > 8 )); then
echo "Tag $VERSION has too many nested tag objects." >&2
return 1
fi
IFS=$'\t' read -r object_type object_sha < <(
gh api "repos/$GITHUB_REPOSITORY/git/tags/$object_sha" \
--jq '.object | [.type, .sha] | @tsv'
)
done
if [[ "$object_type" != "commit" ]]; then
echo "Tag $VERSION resolves to unsupported object type $object_type." >&2
return 1
fi
printf '%s\n' "$object_sha"
}
requested_commit="$(tr '[:upper:]' '[:lower:]' <<< "$REQUESTED_COMMIT")"
if [[ -n "$requested_commit" && ! "$requested_commit" =~ ^[0-9a-f]{40}$ ]]; then
echo "release_commit must be a full 40-character commit SHA."
exit 1
fi
tag_ref="$(
gh api "repos/$GITHUB_REPOSITORY/git/matching-refs/tags/$VERSION" \
--jq ".[] | select(.ref == \"refs/tags/$VERSION\") | [.object.type, .object.sha] | @tsv"
)"
tag_exists=false
if [[ -n "$tag_ref" ]]; then
IFS=$'\t' read -r tag_type tag_sha <<< "$tag_ref"
release_commit="$(resolve_tag_commit "$tag_type" "$tag_sha")"
tag_exists=true
if [[ -n "$requested_commit" && "$release_commit" != "$requested_commit" ]]; then
echo "Tag $VERSION points to $release_commit, not requested commit $requested_commit."
exit 1
fi
elif [[ -n "$requested_commit" ]]; then
release_commit="$requested_commit"
elif [[ "$DRY_RUN" == "true" ]]; then
release_commit="$DEFAULT_COMMIT"
else
echo "Tag $VERSION does not exist and release_commit was not provided."
echo "Use the reviewed release pull request merge commit for a production retry."
exit 1
fi
verified_commit="$(
gh api "repos/$GITHUB_REPOSITORY/git/commits/$release_commit" --jq '.sha'
)"
if [[ "$verified_commit" != "$release_commit" ]]; then
echo "Unable to verify release commit $release_commit."
exit 1
fi
echo "commit=$release_commit" >> "$GITHUB_OUTPUT"
echo "tag_exists=$tag_exists" >> "$GITHUB_OUTPUT"
- name: Checkout Code
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
ref: ${{ steps.target.outputs.commit }}
fetch-depth: 0
persist-credentials: false
- name: Validate release source
env:
RELEASE_COMMIT: ${{ steps.target.outputs.commit }}
VERSION: ${{ steps.version.outputs.version }}
run: |
checkout_commit="$(git rev-parse HEAD)"
if [[ "$checkout_commit" != "$RELEASE_COMMIT" ]]; then
echo "Checked out $checkout_commit, expected $RELEASE_COMMIT."
exit 1
fi
git fetch --no-tags origin \
"+refs/heads/master:refs/remotes/origin/master"
if ! git merge-base --is-ancestor "$RELEASE_COMMIT" origin/master; then
echo "Release commit $RELEASE_COMMIT is not reachable from master."
exit 1
fi
package_version="${VERSION#v}"
app_version="$(
sed -n 's/^var Version = "\(v[0-9][0-9.]*\)"$/\1/p' internal/config/version.go
)"
ui_version="$(jq -r '.version' ui/artalk/package.json)"
docs_version="$(jq -r '.latest' docs/docs/code/ArtalkVersion.json)"
if [[ "$app_version" != "$VERSION" ||
"$ui_version" != "$package_version" ||
"$docs_version" != "$package_version" ]]; then
echo "Release commit versions do not match $VERSION: app=$app_version ui=$ui_version docs=$docs_version."
exit 1
fi
- name: Create Tag
if: ${{ !inputs.dry_run }}
env:
GH_TOKEN: ${{ github.token }}
RELEASE_COMMIT: ${{ steps.target.outputs.commit }}
TAG_EXISTS: ${{ steps.target.outputs.tag_exists }}
VERSION: ${{ steps.version.outputs.version }}
run: |
resolve_tag_commit() {
local object_type="$1"
local object_sha="$2"
local depth=0
while [[ "$object_type" == "tag" ]]; do
depth=$((depth + 1))
if (( depth > 8 )); then
echo "Tag $VERSION has too many nested tag objects." >&2
return 1
fi
IFS=$'\t' read -r object_type object_sha < <(
gh api "repos/$GITHUB_REPOSITORY/git/tags/$object_sha" \
--jq '.object | [.type, .sha] | @tsv'
)
done
if [[ "$object_type" != "commit" ]]; then
echo "Tag $VERSION resolves to unsupported object type $object_type." >&2
return 1
fi
printf '%s\n' "$object_sha"
}
get_tag_ref() {
gh api "repos/$GITHUB_REPOSITORY/git/matching-refs/tags/$VERSION" \
--jq ".[] | select(.ref == \"refs/tags/$VERSION\") | [.object.type, .object.sha] | @tsv"
}
if [[ "$TAG_EXISTS" != "true" ]]; then
tag_object_sha="$(
gh api --method POST "repos/$GITHUB_REPOSITORY/git/tags" \
-f tag="$VERSION" \
-f message="Release $VERSION" \
-f object="$RELEASE_COMMIT" \
-f type=commit \
--jq '.sha'
)"
if ! create_error="$(
gh api --method POST "repos/$GITHUB_REPOSITORY/git/refs" \
-f ref="refs/tags/$VERSION" \
-f sha="$tag_object_sha" 2>&1
)"; then
tag_ref="$(get_tag_ref)"
if [[ -z "$tag_ref" ]]; then
printf '%s\n' "$create_error" >&2
echo "GitHub rejected tag $VERSION. Check the active tag rulesets; tag targets must not require linear history." >&2
exit 1
fi
echo "Tag $VERSION was created concurrently; verifying it."
else
echo "Created annotated tag $VERSION at $RELEASE_COMMIT."
fi
fi
tag_ref="$(get_tag_ref)"
if [[ -z "$tag_ref" ]]; then
echo "Tag $VERSION is missing after creation."
exit 1
fi
IFS=$'\t' read -r tag_type tag_sha <<< "$tag_ref"
tag_commit="$(resolve_tag_commit "$tag_type" "$tag_sha")"
if [[ "$tag_commit" != "$RELEASE_COMMIT" ]]; then
echo "Tag $VERSION points to $tag_commit, expected $RELEASE_COMMIT."
exit 1
fi
echo "Verified tag $VERSION at $RELEASE_COMMIT."
- name: Comment tag info to PR
uses: ./.github/actions/comment
if: ${{ !inputs.dry_run && inputs.issue_number != 0 }}
with:
issue_number: ${{ inputs.issue_number }}
content: |-
🔖 Tagged version [${{ steps.version.outputs.version }}](https://github.com/ArtalkJS/Artalk/tree/${{ steps.version.outputs.version }}) and updated the [CHANGELOG.md](https://github.com/ArtalkJS/Artalk/blob/master/CHANGELOG.md).
outputs:
version: ${{ steps.version.outputs.version }}
ref: ${{ inputs.dry_run && steps.target.outputs.commit || steps.version.outputs.version }}
commit: ${{ steps.target.outputs.commit }}
+84
View File
@@ -0,0 +1,84 @@
name: Build UI
on:
workflow_call:
inputs:
version:
required: true
type: string
ref:
required: true
type: string
dry_run:
required: true
type: boolean
permissions:
contents: read
id-token: write
jobs:
build_publish:
runs-on: ubuntu-latest
steps:
- name: Checkout Code
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
ref: ${{ inputs.ref }}
persist-credentials: false
- name: Use pnpm
uses: pnpm/action-setup@0ebf47130e4866e96fce0953f49152a61190b271 # v6.0.9
with:
version: 10.33.2
- name: Setup node
uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
with:
node-version: 24.x
package-manager-cache: false
- name: Install dependencies
run: pnpm install --frozen-lockfile
- name: Build
run: pnpm build
- name: Pack npm package
env:
VERSION: ${{ inputs.version }}
run: |
package_version="v$(node --print "require('./ui/artalk/package.json').version")"
if [[ "$package_version" != "$VERSION" ]]; then
echo "Package version $package_version does not match release version $VERSION."
exit 1
fi
pnpm --filter artalk pack --pack-destination "$RUNNER_TEMP"
package_file="$RUNNER_TEMP/artalk-${package_version#v}.tgz"
if [[ ! -f "$package_file" ]]; then
echo "Expected package tarball was not created: $package_file"
exit 1
fi
echo "PACKAGE_FILE=$package_file" >> "$GITHUB_ENV"
- name: Validate package
if: ${{ inputs.dry_run }}
run: npm publish "$PACKAGE_FILE" --dry-run --access public
- name: Publish
if: ${{ !inputs.dry_run }}
# npm validates build.yml, the calling workflow, for trusted publishing.
run: npm publish "$PACKAGE_FILE" --access public
# GitHub Packages
#
# Setup .npmrc file to publish to GitHub Packages
# - uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
# with:
# registry-url: 'https://npm.pkg.github.com'
# # Publish to GitHub Packages
# - run: npm publish
# env:
# NODE_AUTH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+124
View File
@@ -0,0 +1,124 @@
name: Build and Publish
run-name: Build and Publish (${{ inputs.version || 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
version:
description: "Release version (for example, v2.10.0)"
type: string
required: true
release_commit:
description: "Full release commit SHA (required when a production retry has no tag)"
type: string
required: false
build_items:
description: "Build items"
type: choice
options:
- "ui,app,docker"
- "ui,app"
- "ui,docker"
- "app,docker"
- ui
- app
- docker
default: "ui,app,docker"
permissions:
contents: read
concurrency:
group: release-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: false
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 &&
github.event.pull_request.head.repo.full_name == github.repository &&
startsWith(github.head_ref, 'release/'))
uses: ./.github/workflows/build-tagging.yml
permissions:
contents: write
issues: write
pull-requests: write
with:
issue_number: ${{ github.event.pull_request.number || 0 }}
dry_run: ${{ inputs.dry_run || false }}
version: ${{ inputs.version || '' }}
release_commit: ${{ github.event.pull_request.merge_commit_sha || inputs.release_commit || '' }}
# Build the UI
ui:
if: inputs.build_items == '' || contains(format(',{0},', inputs.build_items), ',ui,')
needs: tagging
uses: ./.github/workflows/build-ui.yml
with:
version: ${{ needs.tagging.outputs.version }}
ref: ${{ needs.tagging.outputs.ref }}
dry_run: ${{ inputs.dry_run || false }}
permissions:
contents: read
id-token: write
# Build the Docker image
docker:
if: inputs.build_items == '' || contains(format(',{0},', inputs.build_items), ',docker,')
needs: tagging
uses: ./.github/workflows/build-docker.yml
with:
version: ${{ needs.tagging.outputs.version }}
ref: ${{ needs.tagging.outputs.ref }}
commit: ${{ needs.tagging.outputs.commit }}
dry_run: ${{ inputs.dry_run || false }}
permissions:
contents: read
secrets:
DOCKERHUB_USERNAME: ${{ secrets.DOCKERHUB_USERNAME }}
DOCKERHUB_TOKEN: ${{ secrets.DOCKERHUB_TOKEN }}
# Build the binary app
app:
if: inputs.build_items == '' || contains(format(',{0},', inputs.build_items), ',app,')
needs: tagging
uses: ./.github/workflows/build-app.yml
with:
version: ${{ needs.tagging.outputs.version }}
ref: ${{ needs.tagging.outputs.ref }}
dry_run: ${{ inputs.dry_run || false }}
permissions:
contents: write
# All builds are complete
done:
needs: [tagging, ui, docker, app]
if: |
always() &&
needs.tagging.result == 'success' &&
!contains(needs.*.result, 'failure') &&
!contains(needs.*.result, 'cancelled')
uses: ./.github/workflows/build-done.yml
permissions:
contents: read
issues: write
pull-requests: write
with:
version: ${{ needs.tagging.outputs.version }}
ref: ${{ needs.tagging.outputs.ref }}
issue_number: ${{ github.event.pull_request.number || 0 }}
dry_run: ${{ inputs.dry_run || false }}
+45 -33
View File
@@ -9,16 +9,25 @@
# 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"
permissions:
contents: read
concurrency:
group: codeql-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true
jobs:
analyze:
@@ -32,43 +41,46 @@ 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@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
# 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@e4fba868fa4b1b91e1fdab776edc8cfbe6e9fb81 # v4
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@e4fba868fa4b1b91e1fdab776edc8cfbe6e9fb81 # v4
# 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@e4fba868fa4b1b91e1fdab776edc8cfbe6e9fb81 # v4
with:
category: "/language:${{matrix.language}}"
+36 -47
View File
@@ -2,61 +2,50 @@ name: Docs CN Mirror Deploy
on:
push:
branches:
- master
paths:
- "docs/**"
branches: ["master"]
paths: ["docs/**"]
permissions:
contents: read
concurrency:
group: deploy-docs-cn
cancel-in-progress: false
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@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- name: Checkout
uses: actions/checkout@v3
- name: Use pnpm
uses: pnpm/action-setup@0ebf47130e4866e96fce0953f49152a61190b271 # v6.0.9
with:
version: 10.33.2
- name: Use pnpm
uses: pnpm/action-setup@v2
with:
version: 8
- name: Setup node
uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
with:
node-version: 22
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 --frozen-lockfile
- 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@5ee3807d5ff6fddadbbb1d3e658c0690863de8ec # 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
+213 -55
View File
@@ -1,5 +1,5 @@
name: 📦 Release New Version
run-name: 📦 Release ${{ inputs.custom || inputs.semver }} by @${{ github.actor }}
name: 0x📦 Release New Version
run-name: 📦 Release ${{ inputs.semver }} by @${{ github.actor }} ${{ inputs.dry_run && '(🧪 Dry-Run)' || '' }}
on:
workflow_dispatch:
@@ -12,82 +12,240 @@ on:
- minor
- major
required: true
# custom:
# description: 'Custom tag name (i.e v1.0.0-rc.1)'
# required: false
# default: ''
custom_version:
description: Manual Custom Version (Special Purpose, v*)
type: string
required: false
dry_run:
description: "Dry run?"
type: boolean
default: false
env:
REPO_DISPATCH_EVENT_TYPE: 'artalk-release'
UI_NPM_PKG_FILE: 'ui/packages/artalk/package.json'
permissions:
contents: read
concurrency:
group: prepare-release
cancel-in-progress: false
jobs:
release:
runs-on: ubuntu-latest
permissions:
contents: write
pull-requests: write
steps:
- name: Checkout Code
uses: actions/checkout@v3
- name: Git Fetch
run: git fetch --prune --unshallow --tags -f
- name: Setup Node
uses: actions/setup-node@v3
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
node-version: 18.x
registry-url: https://registry.npmjs.org/
ref: master
fetch-depth: 0
persist-credentials: false
- name: Handle Version Number
env:
CUSTOM_VERSION: ${{ inputs.custom_version }}
GH_TOKEN: ${{ github.token }}
SEMVER_INCREMENT: ${{ inputs.semver }}
run: |
if [ ! -z "${{ inputs.custom }}" ]; then
next_version="${{ inputs.custom }}"
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})"
fi
if [[ ! "${next_version}" =~ ^v.* ]]; then
echo "[err] custom tag name must be v*."
PREV_VERSION="$(git describe --tags --abbrev=0 --match 'v*')"
if [[ ! "$PREV_VERSION" =~ ^v([0-9]+)\.([0-9]+)\.([0-9]+)$ ]]; then
echo "Invalid previous version: $PREV_VERSION"
exit 1
fi
echo "next_version: ${next_version}"
echo "VERSION=${next_version}" >> $GITHUB_ENV
if ! git merge-base --is-ancestor "$PREV_VERSION" HEAD; then
echo "Latest release tag $PREV_VERSION is not an ancestor of master."
exit 1
fi
CURRENT_APP_VERSION="$(
sed -n 's/^var Version = "\(v[0-9][0-9.]*\)"$/\1/p' internal/config/version.go
)"
CURRENT_UI_VERSION="$(jq -r '.version' ui/artalk/package.json)"
CURRENT_DOCS_VERSION="$(jq -r '.latest' docs/docs/code/ArtalkVersion.json)"
CURRENT_PACKAGE_VERSION="${CURRENT_APP_VERSION#v}"
if [[ -z "$CURRENT_APP_VERSION" ||
"$CURRENT_UI_VERSION" != "$CURRENT_PACKAGE_VERSION" ||
"$CURRENT_DOCS_VERSION" != "$CURRENT_PACKAGE_VERSION" ]]; then
echo "Release versions are inconsistent: app=$CURRENT_APP_VERSION ui=$CURRENT_UI_VERSION docs=$CURRENT_DOCS_VERSION."
exit 1
fi
if [[ "$CURRENT_APP_VERSION" != "$PREV_VERSION" ]]; then
echo "Source version $CURRENT_APP_VERSION does not match the latest release tag $PREV_VERSION."
echo "If the release PR was already merged, recover it with Build and Publish instead of preparing the release again."
exit 1
fi
if [[ -n "$CUSTOM_VERSION" ]]; then
NEXT_VERSION="$CUSTOM_VERSION"
else
major="${BASH_REMATCH[1]}"
minor="${BASH_REMATCH[2]}"
patch="${BASH_REMATCH[3]}"
case "$SEMVER_INCREMENT" in
major) NEXT_VERSION="v$((major + 1)).0.0" ;;
minor) NEXT_VERSION="v${major}.$((minor + 1)).0" ;;
patch) NEXT_VERSION="v${major}.${minor}.$((patch + 1))" ;;
*) echo "Invalid version increment: $SEMVER_INCREMENT"; exit 1 ;;
esac
fi
if [[ ! "$NEXT_VERSION" =~ ^v[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
echo "Invalid version: $NEXT_VERSION"
exit 1
fi
version_is_greater() {
local next_version="${1#v}"
local previous_version="${2#v}"
local -a next_parts previous_parts
local index next_part previous_part
IFS='.' read -r -a next_parts <<< "$next_version"
IFS='.' read -r -a previous_parts <<< "$previous_version"
for index in 0 1 2; do
next_part=$((10#${next_parts[$index]}))
previous_part=$((10#${previous_parts[$index]}))
if (( next_part > previous_part )); then
return 0
fi
if (( next_part < previous_part )); then
return 1
fi
done
return 1
}
if ! version_is_greater "$NEXT_VERSION" "$PREV_VERSION"; then
echo "Release version $NEXT_VERSION must be greater than $PREV_VERSION."
exit 1
fi
if git show-ref --verify --quiet "refs/tags/$NEXT_VERSION"; then
echo "Release tag $NEXT_VERSION already exists."
exit 1
fi
release_branch="release/$NEXT_VERSION"
existing_pr="$(
gh pr list \
--repo "$GITHUB_REPOSITORY" \
--head "$release_branch" \
--base master \
--state open \
--json number,url \
--jq 'if length == 0 then "" else "#\(.[0].number) \(.[0].url)" end'
)"
if [[ -n "$existing_pr" ]]; then
echo "Release pull request $existing_pr already exists for $NEXT_VERSION."
exit 1
fi
echo "PREV_VERSION=${PREV_VERSION}" >> "$GITHUB_ENV"
echo "VERSION=${NEXT_VERSION}" >> "$GITHUB_ENV"
- name: Print Next Version
run: echo "${VERSION}"
- name: Setup Go
uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # v7.0.0
with:
go-version-file: go.mod
cache: false
- 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
GOBIN="$RUNNER_TEMP/bin" go install github.com/git-chglog/git-chglog/cmd/git-chglog@v0.15.4
echo "$RUNNER_TEMP/bin" >> "$GITHUB_PATH"
go version -m "$RUNNER_TEMP/bin/git-chglog"
- 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")"
temp_file="$(mktemp CHANGELOG.md.XXXXXX)"
printf '%s\n\n' "$changelog" | cat - CHANGELOG.md > "$temp_file"
mv "$temp_file" CHANGELOG.md
# modify the version of `package.json`
perl -i -pe 's/"version": ".*?"/"version": "'${VERSION#v}'"/g' "${UI_NPM_PKG_FILE}"
# modify the version for `internal/config/version.go`
perl -i -pe 's/var Version = ".*?"/var Version = "$ENV{VERSION}"/g' internal/config/version.go
# modify the version in docs
perl -pi -e 's#"latest"(\W+)?:(\W+)?".*?"#"latest": "'${VERSION#v}'"#g' docs/code/ArtalkVersion.json
# modify the version for `package.json`
PACKAGE_VERSION="${VERSION#v}"
PACKAGE_VERSION="$PACKAGE_VERSION" perl -i -pe \
's/"version": ".*?"/"version": "$ENV{PACKAGE_VERSION}"/g' ui/artalk/package.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}"
# modify the version in docs
PACKAGE_VERSION="$PACKAGE_VERSION" perl -pi -e \
's#"latest"(\W+)?:(\W+)?".*?"#"latest": "$ENV{PACKAGE_VERSION}"#g' docs/docs/code/ArtalkVersion.json
git push origin master "${VERSION}"
else
echo "skipped because git tag already exists."
- name: Validate Release Changes
run: |
PACKAGE_VERSION="${VERSION#v}"
APP_VERSION="$(
sed -n 's/^var Version = "\(v[0-9][0-9.]*\)"$/\1/p' internal/config/version.go
)"
UI_VERSION="$(jq -r '.version' ui/artalk/package.json)"
DOCS_VERSION="$(jq -r '.latest' docs/docs/code/ArtalkVersion.json)"
if [[ "$APP_VERSION" != "$VERSION" ||
"$UI_VERSION" != "$PACKAGE_VERSION" ||
"$DOCS_VERSION" != "$PACKAGE_VERSION" ]]; then
echo "Generated release versions are inconsistent: app=$APP_VERSION ui=$UI_VERSION docs=$DOCS_VERSION."
exit 1
fi
- name: Repository Dispatch
uses: peter-evans/repository-dispatch@v2
changelog_entries="$(grep -cF "## [$VERSION]" CHANGELOG.md || true)"
if [[ "$changelog_entries" != "1" ]]; then
echo "Expected one CHANGELOG entry for $VERSION, found $changelog_entries."
exit 1
fi
first_changelog_version="$(
sed -n 's/^## \[\(v[0-9][^]]*\)\].*/\1/p' CHANGELOG.md | head -n 1
)"
if [[ "$first_changelog_version" != "$VERSION" ]]; then
echo "The first CHANGELOG release is $first_changelog_version, expected $VERSION."
exit 1
fi
expected_changes="$(
printf '%s\n' \
CHANGELOG.md \
docs/docs/code/ArtalkVersion.json \
internal/config/version.go \
ui/artalk/package.json |
sort
)"
actual_changes="$(git diff --name-only | sort)"
if [[ "$actual_changes" != "$expected_changes" ]]; then
echo "Unexpected release file set:"
git diff --name-only
exit 1
fi
git diff --check
- name: Print Git Diff
run: git diff
- name: Create Pull Request
uses: peter-evans/create-pull-request@5f6978faf089d4d20b00c7766989d076bb2fc7f1 # v8.1.1
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 }}
+14 -2
View File
@@ -8,13 +8,25 @@ on:
type: string
description: Event Type
required: true
default: ''
default: ""
permissions:
contents: write
jobs:
release:
runs-on: ubuntu-latest
steps:
- name: Validate event type
env:
EVENT_TYPE: ${{ inputs.event_type }}
run: |
if [[ ! "$EVENT_TYPE" =~ ^[A-Za-z0-9_.-]{1,100}$ ]]; then
echo "Invalid repository dispatch event type."
exit 1
fi
- name: Repository Dispatch
uses: peter-evans/repository-dispatch@v2
uses: peter-evans/repository-dispatch@28959ce8df70de7be546dd1250a005dd32156697 # v4.0.1
with:
event-type: ${{ inputs.event_type }}
+119
View File
@@ -0,0 +1,119 @@
name: Test App
on:
push:
paths:
- ".github/workflows/test-app.yml"
- "cmd/**"
- "internal/**"
- "server/**"
- "test/**"
- "main.go"
- "go.mod"
- "go.sum"
branches-ignore: ["release/*", "nightly"]
tags-ignore: ["v*"]
pull_request:
paths:
- ".github/workflows/test-app.yml"
- "cmd/**"
- "internal/**"
- "server/**"
- "test/**"
- "main.go"
- "go.mod"
- "go.sum"
branches-ignore: ["release/*", "nightly"]
env:
REPORT_DIR: "/tmp/test-reports"
CGO_ENABLED: 0
permissions:
contents: read
concurrency:
group: test-app-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true
jobs:
test_app:
name: Test Go (${{ matrix.name }})
runs-on: ${{ matrix.runner }}
timeout-minutes: 20
strategy:
fail-fast: false
matrix:
include:
- name: Linux AMD64
runner: ubuntu-24.04
artifact: linux-amd64
coverage: true
- name: Linux ARM64
runner: ubuntu-24.04-arm
artifact: linux-arm64
coverage: false
- name: macOS
runner: macos-latest
artifact: macos
coverage: false
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- name: Setup Go
uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # v7.0.0
with:
go-version-file: go.mod
cache: false # https://github.com/actions/setup-go/issues/483
- id: go-vars
name: Get Go variables for cache
run: |
echo "GOCACHE=$(go env GOCACHE)" >> "$GITHUB_OUTPUT"
echo "GOMODCACHE=$(go env GOMODCACHE)" >> "$GITHUB_OUTPUT"
- name: Cache go modules
# v6.1.0; this test-only cache never feeds a publishing workflow.
uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # zizmor: ignore[cache-poisoning]
with:
path: |
${{ steps.go-vars.outputs.GOCACHE }}
${{ steps.go-vars.outputs.GOMODCACHE }}
key: go-test-${{ runner.os }}-${{ runner.arch }}-${{ hashFiles('go.sum') }}
restore-keys: |
go-test-${{ runner.os }}-${{ runner.arch }}-
- name: Install tools
run: go install gotest.tools/gotestsum@v1.13.0
- name: Download Go modules
run: go mod download
- name: Run vet
run: go vet ./...
- name: Run tests
run: |
mkdir -p "$REPORT_DIR"
gotestsum \
--junitfile "$REPORT_DIR/unit-tests.xml" \
--jsonfile "$REPORT_DIR/unit-tests.json" \
-- -coverprofile="$REPORT_DIR/coverage.out" ./...
- name: Upload test results
if: ${{ !cancelled() }}
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: Go-Test-Results-${{ matrix.artifact }}
path: ${{ env.REPORT_DIR }}
- if: ${{ matrix.coverage && !cancelled() }}
name: Upload coverage to Codecov
uses: codecov/codecov-action@fb8b3582c8e4def4969c97caa2f19720cb33a72f # v7.0.0
with:
flags: go
file: ${{ env.REPORT_DIR }}/coverage.out
token: ${{ secrets.CODECOV_TOKEN }}
+47
View File
@@ -0,0 +1,47 @@
name: Test Docs
on:
push:
paths: ["docs/**"]
branches-ignore: ["release/*", "nightly"]
tags-ignore: ["v*"]
pull_request:
paths: ["docs/**"]
branches-ignore: ["release/*", "nightly"]
permissions:
contents: read
concurrency:
group: test-docs-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true
jobs:
test_docs:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- name: Use pnpm
uses: pnpm/action-setup@0ebf47130e4866e96fce0953f49152a61190b271 # v6.0.9
with:
version: 10.33.2
- name: Use Node.js
uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
with:
node-version: 22.x
cache: pnpm # zizmor: ignore[cache-poisoning] test-only cache
- name: Install dependencies
run: pnpm install --frozen-lockfile
- name: Build Docs
run: pnpm build:docs
- name: Lint Docs
run: pnpm eslint docs && pnpm prettier --check docs
+86
View File
@@ -0,0 +1,86 @@
name: Test End-to-End
on:
push:
paths:
- ".github/workflows/test-e2e.yml"
- "cmd/**"
- "conf/**"
- "internal/**"
- "server/**"
- "ui/**"
- "go.mod"
- "go.sum"
- "package.json"
- "pnpm-lock.yaml"
branches-ignore: ["release/*", "nightly"]
tags-ignore: ["v*"]
pull_request:
paths:
- ".github/workflows/test-e2e.yml"
- "cmd/**"
- "conf/**"
- "internal/**"
- "server/**"
- "ui/**"
- "go.mod"
- "go.sum"
- "package.json"
- "pnpm-lock.yaml"
branches-ignore: ["release/*", "nightly"]
permissions:
contents: read
concurrency:
group: test-e2e-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true
env:
CGO_ENABLED: 0
jobs:
test_e2e:
name: Test browser UAT flow
runs-on: ubuntu-24.04
timeout-minutes: 20
steps:
- name: Checkout Code
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- name: Setup Go
uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # v7.0.0
with:
go-version-file: go.mod
cache: true # zizmor: ignore[cache-poisoning] test-only cache
- name: Setup pnpm
uses: pnpm/action-setup@0ebf47130e4866e96fce0953f49152a61190b271 # v6.0.9
with:
version: 10.33.2
- name: Setup Node
uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
with:
node-version: 22.x
cache: pnpm # zizmor: ignore[cache-poisoning] test-only cache
- name: Install dependencies
run: pnpm install --frozen-lockfile
- name: Install Chromium
run: pnpm exec playwright install --with-deps chromium
- name: Run end-to-end tests
run: pnpm -F artalk test:e2e
- name: Upload Playwright report
if: ${{ failure() }}
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: Playwright-Report
path: ui/artalk/playwright-report
if-no-files-found: ignore
retention-days: 7
+62 -21
View File
@@ -2,46 +2,87 @@ name: Test Frontend
on:
push:
paths:
- 'ui/**'
paths: [".github/workflows/test-frontend.yml", "ui/**", "package.json", "pnpm-lock.yaml"]
branches-ignore: ["release/*", "nightly"]
tags-ignore: ["v*"]
pull_request:
paths:
- 'ui/**'
paths: [".github/workflows/test-frontend.yml", "ui/**", "package.json", "pnpm-lock.yaml"]
branches-ignore: ["release/*", "nightly"]
permissions:
contents: read
concurrency:
group: test-frontend-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true
jobs:
test_ui:
strategy:
fail-fast: false
matrix:
node: [18, 20]
os: [ubuntu-latest, windows-latest]
include:
- os: ubuntu-24.04
node: 22
quality: true
- os: ubuntu-24.04
node: 24
quality: false
- os: windows-latest
node: 22
quality: false
runs-on: ${{ matrix.os }}
defaults:
run:
working-directory: ./ui
timeout-minutes: 20
steps:
- name: Checkout Code
uses: actions/checkout@v3
- 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
- uses: pnpm/action-setup@v2
- name: Checkout Code
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
version: 8
persist-credentials: false
- uses: pnpm/action-setup@0ebf47130e4866e96fce0953f49152a61190b271 # v6.0.9
with:
version: 10.33.2
- name: Use Node.js ${{ matrix.node }}
uses: actions/setup-node@v4
uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
with:
node-version: ${{ matrix.node }}
cache: pnpm
cache-dependency-path: './ui/pnpm-lock.yaml'
cache: pnpm # zizmor: ignore[cache-poisoning] test-only cache
- name: Install Dependencies
run: pnpm --dir ./ui install --frozen-lockfile
run: pnpm install --frozen-lockfile
- name: Package Build Test
run: pnpm build:all
# TODO: Add unit test
# - name: Unit test
# run: pnpm test
- name: Unit Test
run: pnpm test
- name: Plugins Build Test
if: ${{ matrix.quality }}
run: pnpm build:plugins
- name: Plugins Type Test
if: ${{ matrix.quality }}
run: pnpm test:plugins
- name: Plugins Package Test
if: ${{ matrix.quality }}
run: pnpm test:plugins:attw
- name: Lint
if: ${{ matrix.quality }}
run: pnpm eslint ui && pnpm prettier --check ui
# https://github.com/arethetypeswrong/arethetypeswrong.github.io
- name: "arethetypeswrong test"
if: ${{ matrix.quality }}
run: pnpm -F artalk test:attw
+46
View File
@@ -0,0 +1,46 @@
name: Test Workflows
on:
push:
paths: [".github/**"]
branches-ignore: ["release/*", "nightly"]
tags-ignore: ["v*"]
pull_request:
paths: [".github/**"]
branches-ignore: ["release/*", "nightly"]
permissions:
contents: read
concurrency:
group: test-workflows-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true
jobs:
lint:
name: Validate Actions and security policy
runs-on: ubuntu-24.04
timeout-minutes: 10
steps:
- name: Checkout Code
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- name: Setup Go
uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # v7.0.0
with:
go-version-file: go.mod
cache: false
- name: Validate workflow syntax
run: go run github.com/rhysd/actionlint/cmd/actionlint@v1.7.12 -color
- name: Install zizmor
run: |
python3 -m venv "$RUNNER_TEMP/zizmor"
"$RUNNER_TEMP/zizmor/bin/pip" install --disable-pip-version-check zizmor==1.28.0
- name: Audit workflow security
run: |
"$RUNNER_TEMP/zizmor/bin/zizmor" --format github .github
+4
View File
@@ -49,6 +49,7 @@ yarn-debug.log*
yarn-error.log*
.pnpm-debug.log*
__debug*
vite.config.ts.timestamp-*
# frontend
node_modules
@@ -68,3 +69,6 @@ node_modules
playwright-report
test-results
# TypeScript composite build declaration output
.tsbuildinfo-dts/
+18 -34
View File
@@ -6,17 +6,20 @@
# https://goreleaser.com/customization/fury/
# https://goreleaser.com/customization/announce/telegram/
version: 2
project_name: artalk
env:
- GO111MODULE=on
- CGO_ENABLED=1
- CGO_ENABLED=0
before:
hooks:
# install dependencies
- make install
- make build-frontend
# install dependencies
- make install
- make build-frontend
- make pack-frontend
# build multi-platform
builds:
@@ -30,14 +33,9 @@ builds:
- linux
goarch:
- amd64
env:
- CC=x86_64-linux-gnu-gcc
- CXX=x86_64-linux-gnu-g++
binary: "{{.ProjectName}}"
main: ./main.go
ldflags: &common_ldflags |
-X github.com/ArtalkJS/Artalk/internal/config.Version={{.Version}}
-X github.com/ArtalkJS/Artalk/internal/config.CommitHash={{ .ShortCommit }}
-s -w
# Linux (arm_64)
@@ -46,9 +44,6 @@ builds:
- linux
goarch:
- arm64
env:
- CC=aarch64-linux-gnu-gcc
- CXX=aarch64-linux-gnu-g++
binary: "{{.ProjectName}}"
main: ./main.go
ldflags: *common_ldflags
@@ -60,10 +55,7 @@ builds:
goarch:
- arm
goarm:
- '7'
env:
- CC=arm-linux-gnueabihf-gcc
- CXX=arm-linux-gnueabihf-g++
- "7"
binary: "{{.ProjectName}}"
main: ./main.go
ldflags: *common_ldflags
@@ -78,9 +70,6 @@ builds:
- darwin
goarch:
- amd64
env:
- CC=o64-clang
- CXX=o64-clang++
binary: "{{.ProjectName}}"
main: ./main.go
ldflags: *common_ldflags
@@ -91,9 +80,6 @@ builds:
- darwin
goarch:
- arm64
env:
- CC=oa64-clang
- CXX=oa64-clang++
binary: "{{.ProjectName}}"
main: ./main.go
ldflags: *common_ldflags
@@ -108,9 +94,6 @@ builds:
- windows
goarch:
- amd64
env:
- CC=x86_64-w64-mingw32-gcc
- CXX=x86_64-w64-mingw32-g++
binary: "{{.ProjectName}}"
main: ./main.go
ldflags: *common_ldflags
@@ -118,7 +101,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
@@ -126,9 +109,6 @@ builds:
- windows
goarch:
- arm64
env:
- CC=/llvm-mingw/bin/aarch64-w64-mingw32-gcc
- CXX=/llvm-mingw/bin/aarch64-w64-mingw32-g++
binary: "{{.ProjectName}}"
main: ./main.go
ldflags: *common_ldflags
@@ -136,7 +116,7 @@ builds:
archives:
- id: artalk
builds:
ids:
- linux-amd64
- darwin-amd64
- windows-amd64
@@ -145,10 +125,12 @@ archives:
- linux-arm64
- darwin-arm64
name_template: "{{.ProjectName}}_v{{.Version}}_{{.Os}}_{{.Arch}}{{.Arm}}"
format: tar.gz
formats:
- tar.gz
format_overrides:
- goos: windows
format: zip
formats:
- zip
wrap_in_directory: true
files:
- README*
@@ -156,10 +138,10 @@ archives:
- artalk.yml
checksum:
name_template: 'checksums.txt'
name_template: "checksums.txt"
snapshot:
name_template: "{{.Version}}-SNAPSHOT-{{.ShortCommit}}"
version_template: "{{.Version}}-SNAPSHOT-{{.ShortCommit}}"
# changelog:
# sort: asc
@@ -175,3 +157,5 @@ release:
name: Artalk
prerelease: auto
draft: false
extra_files:
- glob: ./local/release_includes/*
+57
View File
@@ -0,0 +1,57 @@
.DS_Store
node_modules/
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
.pnpm-debug.log*
.idea
.vscode
*.suo
*.ntvs*
*.njsproj
*.sln
.history
.editorconfig
# git
.gitignore
.gitattributes
# tests
test
coverage
# build tools
.travis.yml
.jenkins.yml
.codeclimate.yml
# linters
.jscsrc
.jshintrc
.eslintrc*
# vite configs
vite*.config*
# develop tool configs
.prettierrc
.eslintrc.js
.eslintignore
postcss.config.js
yarn.lock
package-lock.json
# local files
deploy
local
CNAME
index.html
#dist
.github
+21
View File
@@ -0,0 +1,21 @@
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
**/vite.config.ts.timestamp-*
ui/artalk/src/api/v2.ts
docs/swagger/swagger.json
docs/swagger/swagger.yaml
docs/docs/**/*.md
docs/docs/.vitepress/dist/**
docs/docs/.vitepress/cache/**
ui/artalk-sidebar/src/lib/md5.js
ui/artalk/src/lib/detect.ts
**/dist/**
+26
View File
@@ -0,0 +1,26 @@
{
"arrowParens": "always",
"bracketSpacing": true,
"htmlWhitespaceSensitivity": "css",
"insertPragma": false,
"bracketSameLine": false,
"jsxSingleQuote": false,
"printWidth": 100,
"proseWrap": "preserve",
"quoteProps": "as-needed",
"requirePragma": false,
"semi": false,
"singleQuote": true,
"tabWidth": 2,
"trailingComma": "all",
"useTabs": false,
"vueIndentScriptAndStyle": false,
"overrides": [
{
"files": ["*.yaml", "*.yml"],
"options": {
"singleQuote": false
}
}
]
}
+16 -12
View File
@@ -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}/data/artalk.yml"]
}
],
"version": "0.2.0",
"configurations": [
{
"name": "Launch Artalk for Debugging",
"type": "go",
"request": "launch",
"mode": "exec",
"program": "${workspaceFolder}/bin/artalk",
"preLaunchTask": "Build for debugging",
"env": {
"ATK_SITE_DEFAULT": "ArtalkDocs",
"ATK_TRUSTED_DOMAINS": "http://localhost:5173 http://localhost:23367"
},
"args": ["server", "-c", "${workspaceFolder}/artalk.yml"]
}
]
}
+61 -18
View File
@@ -1,20 +1,63 @@
{
"eslint.workingDirectories": ["./ui"],
"cSpell.words": [
"akismet",
"artalk",
"artran",
"artrans",
"artransfer",
"gomail",
"Goreleaser",
"gorm",
"ldflags",
"lfshook",
"Metas",
"pgsql",
"sendmail",
"sqlite",
"pkged"
]
// Enable the ESLint flat config support (ESLint 9+ / extension v3+)
"eslint.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"
]
}
+12 -12
View File
@@ -1,14 +1,14 @@
{
"version": "2.0.0",
"tasks": [
{
"label": "Build for debugging",
"type": "shell",
"command": "make build-debug",
"group": {
"kind": "build",
"isDefault": true
}
}
]
"version": "2.0.0",
"tasks": [
{
"label": "Build for debugging",
"type": "shell",
"command": "make build-debug",
"group": {
"kind": "build",
"isDefault": true
}
}
]
}
+517
View File
@@ -1,4 +1,521 @@
## [v2.10.0](https://github.com/ArtalkJS/Artalk/compare/v2.9.1...v2.10.0) (2026-07-23)
### Features
* add 'ugc' to link rel attributes ([#1120](https://github.com/ArtalkJS/Artalk/issues/1120))
* **api/vote:** add get vote status endpoint ([#998](https://github.com/ArtalkJS/Artalk/issues/998))
* **auth:** add SSO token exchange endpoint ([#1134](https://github.com/ArtalkJS/Artalk/issues/1134))
* **config:** enhance config file and data dir retrieval ([#992](https://github.com/ArtalkJS/Artalk/issues/992))
* **db:** add TLS support for MySQL with Google Cloud SQL ([#1104](https://github.com/ArtalkJS/Artalk/issues/1104))
* **go:** upgrade golang to v1.26.2 and some deps
* **go:** upgrade golang to v1.26.5
* **plugins:** add plugin registry fetch script
* **ui:** add dependency injection container ([#1006](https://github.com/ArtalkJS/Artalk/issues/1006))
* **ui:** add npm published version check script
* **ui/conf:** add `preferRemoteConf` option ([#1000](https://github.com/ArtalkJS/Artalk/issues/1000)) ([#1011](https://github.com/ArtalkJS/Artalk/issues/1011))
* **ui/eslint:** add eslint plugin for artalk ui development ([#995](https://github.com/ArtalkJS/Artalk/issues/995))
* **ui/eslint:** update `eslint-plugin-artalk` to v1.0.2 ([#1010](https://github.com/ArtalkJS/Artalk/issues/1010))
* **ui/page_vote:** add page voting feature ([#983](https://github.com/ArtalkJS/Artalk/issues/983))
### Bug Fixes
* **api:** validate vote status targets
* **api:** make vote updates transactional
* **api/stats:** exclude pending comments
* **api/vote:** return not found for deleted targets
* **auth:** require verified email for SSO exchange
* **build:** propagate image version metadata
* **cache:** return database results on store failure
* **ci:** satisfy workflow shell checks
* **ci:** harden release supply chain
* **ci:** harden release tag handling
* **ci:** preserve nightly tag during release refresh
* **cmd:** preserve config lookup before data chdir
* **config:** preserve keyword file separators
* **core:** initialize process timezone once
* **db:** enforce Cloud SQL TLS verification
* **docs:** support React 19 useRef types
* **email:** add Message-ID header
* **scripts:** import Buffer explicitly
* **scripts:** harden npm publish check
* **ui:** preserve generated list response contract
* **ui:** restore deprecated context services
* **ui:** reject direct context replacement
* **ui:** align plugin lifecycle with final config
* **ui:** accept scoped comment lists without page data
* **ui:** replace vulnerable HTML sanitizer
* **ui/editor:** restore deprecated aliases
* **ui/sidebar:** handle null array preferences
* **ui/types:** preserve atomic config values
* **ui/types:** restore deprecated public aliases
* **ui/ua:** support OpenHarmony and more browsers ([#1087](https://github.com/ArtalkJS/Artalk/issues/1087))
### Code Refactoring
* **api/vote:** refactor vote http endpoint and logic ([#997](https://github.com/ArtalkJS/Artalk/issues/997))
* **auth:** migrate JWT handling to v5
* **ci:** accelerate nightly publishing
* **ci:** optimize multi-architecture releases
* **ui:** improve modularity, lifecycle, and types ([#1007](https://github.com/ArtalkJS/Artalk/issues/1007))
* **ui/auth:** ensure compatibility with new client types ([#1009](https://github.com/ArtalkJS/Artalk/issues/1009))
* **ui/comment:** update reply button to use component
* **ui/conf:** introduce `DeepPartial` type for ui config ([#996](https://github.com/ArtalkJS/Artalk/issues/996))
* **ui/sidebar:** ensure compatibility with new client types ([#1008](https://github.com/ArtalkJS/Artalk/issues/1008))
### Testing
* remove races from async tests
* **ci:** expand release validation
* **server:** verify plugin URL trust filtering
* **ui:** update comment e2e flow
* **ui:** isolate Playwright end-to-end specs
* **ui:** cover Marked 18 integration
* **ui:** cover sanitizer attribute allowlist
* **ui:** isolate browser storage from Node
### Documentation
* document dependency and security updates
* add v2.10.0 release notes
* add Japanese README ([#1145](https://github.com/ArtalkJS/Artalk/issues/1145))
* integrate git changelog plugin
* **i18n:** add Turkish (tr-TR) language support ([#1119](https://github.com/ArtalkJS/Artalk/issues/1119))
* **i18n:** add `zh-TW` translation for config template
* **landing:** redesign landing page ([#1020](https://github.com/ArtalkJS/Artalk/issues/1020))
* **landing:** add more translations
* **landing:** optimize responsive font size
### BREAKING CHANGE
Beyond [#997](https://github.com/ArtalkJS/Artalk/issues/997), [#1007](https://github.com/ArtalkJS/Artalk/issues/1007), and [#1011](https://github.com/ArtalkJS/Artalk/issues/1011), v2.10.0 changes default config/data discovery and relative-path semantics; raises source builds to Go 1.26.5; replaces the CGO-backed SQLite driver with a pure-Go implementation; fixes application timezone at process initialization, requiring a full restart to change it; removes the useBackendConf opt-out and remoteConfModifier; changes DI registration, Context mutation, update() return value, and created timing; and requires marked 18 with modern package resolution. Migration guide: https://artalk.js.org/en/guide/releases/v2.10.0.html
UI client now prioritizes local config in the latest version, whereas previously, the remote config would override it. (See [#1011](https://github.com/ArtalkJS/Artalk/issues/1011))
This update changes the UI client's export Types. Although we aim to maintain backward compatibility, it may still affect downstream UI programs. Please refer to the [TypeDoc](https://artalk.js.org/typedoc/).
Vote HTTP API endpoint have been updated. (See [#997](https://github.com/ArtalkJS/Artalk/issues/997))
## [v2.9.1](https://github.com/ArtalkJS/Artalk/compare/v2.9.0...v2.9.1) (2024-09-18)
### Features
* **go:** upgrade golang to v1.22.7 and some deps
### Bug Fixes
* **db:** sql error with custom table prefix ([#970](https://github.com/ArtalkJS/Artalk/issues/970))
* **test:** separate test db to isolate concurrent test instances ([#975](https://github.com/ArtalkJS/Artalk/issues/975))
* **transfer:** ensure consistent time format in artrans export
* **ui/plugin:** prevent exceptions from blocking other plugins loading
### Performance Improvements
* **plugin_katex:** add error message for missing katex deps
### Code Refactoring
* **dao:** improve concurrent testing for `FindCreateAction` function
* **go:** hardcode version and get commit_hash via runtime/debug
* **go:** bump the module version and support go install ([#979](https://github.com/ArtalkJS/Artalk/issues/979))
### Testing
* **mutex:** add tests for keyed mutex
### Documentation
* refine deployment documentation
* **i18n:** add English translations for docs ([#978](https://github.com/ArtalkJS/Artalk/issues/978))
* **landing:** add multi-language and dark-mode for landing
* **landing:** add demo video in landing page
### BREAKING CHANGE
The original Go module name was `github.com/ArtalkJS/Artalk`, which has now been modified to `github.com/artalkjs/artalk/v2` (all lowercase). This change may affect the CI pipeline or other areas if you are compiling the Artalk server and have specified the fixed Go module name. Regarding the original `-ldflags -X github.com/ArtalkJS/Artalk/internal/config.Version` and `CommitHash` definitions, please remove them, as they are now obsolete. The `Version` has been hardcoded into the Go code, and the `CommitHash` is now read from the Go build info via runtime/debug’s vcs.revision value. This change only affects the server developers and does not impact the frontend UI client.
## [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
+297 -86
View File
@@ -1,126 +1,337 @@
# 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/) (>= 18.12.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 Backend
## Development Environment
First, you need to install the dependencies for the backend written in Go. Simply run the `make install` command to install the dependencies.
To develop Artalk, both frontend and backend, install the following tools:
Then, run the `make dev` to build and run `./bin/artalk`, and you can pass startup parameters to the program using `ARGS="version" make dev`.
- [Node.js](https://nodejs.org/en/) (>= 22.19.0)
- [PNPM](https://pnpm.io/) (>= 10.33.2)
- [Go](https://golang.org/) (>= 1.26)
- [Docker](https://www.docker.com/) (>= 20.10.0) (optional)
- [Docker Compose](https://docs.docker.com/compose/) (>= 1.29.0) (optional)
This will build the backend with debugging symbols. The binary file will be placed under the `./bin` directory.
## Development Workflow Overview
The backend program will run by default on port `23366`. You can access it through a browser at `http://localhost:23366`. It's recommended not to change this port number for testing the backend program.
The development workflow consists of the following steps:
### Build Frontend
1. **Set Up Complete Development Instance**:
- 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`.
First, you need to install the dependencies for the frontend. Simply run the `cd ui && pnpm install` command to install the dependencies.
2. **Access Frontend for Development**:
- Open your browser and go to `http://localhost:5173` to perform your development and testing.
Then, run the `cd ui && pnpm dev` to build and run the frontend, and you can pass startup parameters to the program using `ARGS="--port 5173" pnpm dev`.
3. **Testing**:
- 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`.
The frontend program will run by default on port `5173`, and you can access it in a browser at `http://localhost:5173`. The frontend testing client will, by default, request the backend on port `23366`, so it's essential to keep the backend on this port.
4. **Building Frontend Code**:
- 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.
The frontend program is divided into the main program and a sidebar program, with the sidebar program running on a separate port, which is `23367`.
5. **Building Backend Code**:
- 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`.
### Development Workflow
More exploration:
In most cases, to set up a complete development instance, you need to navigate to the Artalk Repo directory and then execute `make dev`. This will run the backend on port `23366`. Then, execute `cd ui && pnpm dev`, which will run the frontend on port `5173`. You can optionally execute `pnpm dev:sidebar` to run the sidebar frontend on port `23367`. For frontend development, you need to access `http://localhost:5173` in your browser to perform your development and testing.
- **Developing Artalk Plugins or Themes**:
Refer to the [Artalk Plugin Development Guide](https://artalk.js.org/develop/plugin.html).
When you make changes to the frontend code, you can build the complete frontend program using `cd ui && pnpm build:all`. The JavaScript and CSS code can be found in `ui/packages/artalk/dist`.
- **Makefile**:
You can explore the process and commands in the `Makefile`.
When you make changes to the backend code, running `make all` will build the complete backend program. Note that since the backend program also embeds the frontend code, the `scripts/build-frontend.sh` script will run during backend program building, which includes the embedded frontend main program and sidebar frontend program. If you are interested, you can explore the complete frontend build process in the `Makefile` code.
- **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.
Additionally, there is automated CI on GitHub for building. You can find the relevant code in the `.github/workflows` directory.
### Optional: Use a One-Key Script to Run a Demo Site
When you access `http://localhost:5173` during frontend development, you will get a minimalist interface that only contains the Artalk program interface and not a real blog environment. If you want to make testing closer to a real environment, you can create a demo blog site using the following steps.
Run the following command:
```sh
./scripts/setup-example-site.sh
```
This script sets up a local example site for testing at `data` folder, with Artalk integrated into its theme.
After running this script, run:
```sh
./bin/artalk server -c ./data/artalk.yml
```
to start the artalk server.
And open <http://localhost:1313/> in your browser to view the example site.
Here is the default admin account (only created in test mode):
```yaml
name: "admin"
email: "admin@test.com"
password: "admin"
```
## Testing
The backend Go program can be tested by running `make test` for unit testing. The test results will be outputted in the terminal. You can also execute `test-coverage` to check the code test coverage.
Frontend testing is conducted using Playwright for end-to-end (E2E) testing. To start the E2E testing, run `make test-frontend-e2e`.
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.
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.
- `data/` - The local data. 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-frontend` 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.
### Publish Frontend
The core artalk client code is automatically deployed to NPM by GitHub Actions. The deployment process is defined in the `.github/workflows/build-ui.yml` file.
If you are writing a artalk plugin in monorepo, it would not be automatically deployed. You should publish it manually. To publish the plugin, first ensure your version number is updated in the `package.json` file. Then, run the following command:
```sh
pnpm publish --access public
```
#### Check Published Versions
The `pnpm check:publish` script is designed to verify that all packages in the project have the latest versions published on npm. It skips private packages automatically and allows filtering to check specific packages using the `-F` option.
Check all packages:
```sh
pnpm check:publish
```
This will initiate the process of checking all public packages in the repository to ensure they are up to date on npm.
### Develop and Debug `@artalk/plugin-kit` and `eslint-plugin-artalk`
The monorepo will default to installing the latest version of `@artalk/plugin-kit` and `eslint-plugin-artalk` from NPM published packages. To develop and debug these packages, run the following commands from the root of the repository:
```sh
pnpm link --global --dir ui/eslint-plugin-artalk
pnpm link --global --dir ui/plugin-kit
pnpm link eslint-plugin-artalk
pnpm link @artalk/plugin-kit
```
After executing these commands, the `eslint-plugin-artalk` and `@artalk/plugin-kit` packages will be linked to the local development environment within the monorepo workspace. You can modify the source code located in the `ui/eslint-plugin-artalk` and `ui/plugin-kit` directories, and the changes will be automatically reflected in the monorepo workspace. If you wish to unlink the packages, run the following commands:
```sh
pnpm unlink eslint-plugin-artalk
pnpm unlink @artalk/plugin-kit
pnpm uninstall --global eslint-plugin-artalk
pnpm uninstall --global @artalk/plugin-kit
```
For more details, refer to the [pnpm link documentation](https://pnpm.io/cli/link).
## 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_UI_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
View File
@@ -1,12 +1,11 @@
### build Artalk
FROM golang:1.21.3-alpine3.18 as builder
FROM golang:1.26.5-alpine3.24 AS builder
WORKDIR /source
# install tools
RUN set -ex \
&& apk add --no-cache make git gcc musl-dev nodejs bash npm\
&& npm install -g pnpm@8.12.1
&& apk add --no-cache make git 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@10.33.2 \
;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 [[ -n "$APP_VERSION" ]]; then export VERSION="$APP_VERSION" ;fi \
&& if [[ -n "$APP_COMMIT_HASH" ]]; then export COMMIT_HASH="$APP_COMMIT_HASH" ;fi \
&& make build
### build final image
FROM alpine:3.18
FROM alpine:3.24
# 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
+46 -23
View File
@@ -1,59 +1,83 @@
PKG_NAME := github.com/ArtalkJS/Artalk
PKG_NAME := github.com/artalkjs/artalk/v2
BIN_NAME := ./bin/artalk
VERSION ?= $(shell git describe --tags --abbrev=0)
COMMIT_HASH := $(shell git rev-parse --short HEAD)
DEV_VERSION := dev-$(COMMIT_HASH)
LDFLAGS := -s -w
ifneq ($(strip $(VERSION)),)
LDFLAGS += -X '$(PKG_NAME)/internal/config.Version=$(VERSION)'
endif
ifneq ($(strip $(COMMIT_HASH)),)
LDFLAGS += -X '$(PKG_NAME)/internal/config.buildCommitHash=$(COMMIT_HASH)'
endif
HAS_RICHGO := $(shell which richgo)
GOTEST ?= $(if $(HAS_RICHGO), richgo test, go test)
ARGS ?= server
export CGO_ENABLED := 0
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)" \
-ldflags "$(LDFLAGS)" \
-o $(BIN_NAME) \
$(PKG_NAME)
build-frontend:
./scripts/build-frontend.sh
@./scripts/build-frontend.sh
run: all
$(BIN_NAME) $(ARGS)
pack-frontend:
@./scripts/pack-frontend.sh
build-debug:
@echo "Building Artalk $(VERSION) for debugging..."
@echo "Building Artalk for debugging..."
@go build \
-ldflags "-X $(PKG_NAME)/internal/config.Version=$(VERSION) \
-X $(PKG_NAME)/internal/config.CommitHash=$(COMMIT_HASH)" \
-gcflags "all=-N -l" \
-o $(BIN_NAME) \
$(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 en -o ./docs/docs/en/guide/env.md
go run ./internal/config/meta/gen --format markdown --locale zh-CN -o ./docs/docs/zh/guide/env.md
update-docs-features:
pnpm -F docs-landing update:readme
update-swagger:
go install github.com/swaggo/swag/cmd/swag@latest
swag init -g server/server.go --output ./docs/swagger
swag init -g server/server.go --output ./docs/swagger --requiredByDefault
pnpm -r swagger:build-http-client
docker-build:
./scripts/docker-build.sh
@@ -61,9 +85,8 @@ docker-build:
docker-push:
./scripts/docker-build.sh --push
test-frontend-e2e:
./scripts/frontend-e2e-test.sh $(if $(REPORT), --show-report)
.PHONY: all install build build-frontend build-debug \
dev test test-coverage test-coverage-html update-i18n \
docker-build docker-push test-frontend-e2e;
.PHONY: all install run build build-frontend pack-frontend build-debug dev \
test test-coverage test-coverage-html test-frontend-e2e \
update-i18n update-conf update-conf-docs \
update-docs-features update-swagger \
docker-build docker-push;
-138
View File
@@ -1,138 +0,0 @@
<p align="center">
<img src="https://user-images.githubusercontent.com/22412567/137740516-d9e97af0-fb3b-4dab-b331-671a9a2a3a63.png" alt="Artalk" width="100%">
</p>
# Artalk
[![npm 版本](https://img.shields.io/npm/v/artalk.svg?style=flat-square)](https://www.npmjs.com/package/artalk)
[![npm 下载量](https://img.shields.io/npm/dt/artalk.svg?style=flat-square)](https://www.npmjs.com/package/artalk)
[![尺寸](https://badgen.net/bundlephobia/minzip/artalk?style=flat-square)](https://bundlephobia.com/package/artalk)
[![CircleCI](https://circleci.com/gh/ArtalkJS/Artalk/tree/master.svg?style=svg)](https://circleci.com/gh/ArtalkJS/Artalk/tree/master)
> 🌌 A self-hosted comment system
[简体中文](./README.md) / [Documentation](https://artalk.js.org) / [Releases](https://github.com/ArtalkJS/Artalk/releases) / [Artalk](https://github.com/ArtalkJS/Artalk)
---
- 🍃 Lightweight (~30kB)
- 👨‍👧‍👦 Secure (Self-hosted)
- 🐳 Easy to use (Very Easy)
- 🍱 Golang backend (Fast and Cross Platform)
- 🌊 TypeScript × Vanilla × Vite (No Dependencies)
## 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
## Getting Started
Reference to:[**Documentation**](https://artalk.js.org/guide/deploy.html)
```sh
$ pnpm add artalk
```
```ts
import Artalk from 'artalk'
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'
})
```
### Docker
```sh
docker run -d \
--name artalk \
-p 8080:23366 \
-v $(pwd)/data:/data \
artalk/artalk-go
```
### Docker Compose
```sh
mkdir Artalk
cd Artalk
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)
## Contributors
[![](https://contrib.rocks/image?repo=ArtalkJS/Artalk)](https://github.com/ArtalkJS/Artalk/graphs/contributors)
## Supporters
[![Stargazers repo roster for @ArtalkJS/Artalk](https://reporoster.com/stars/ArtalkJS/Artalk)](https://github.com/ArtalkJS/Artalk/stargazers)
## Feedback
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
[![Stargazers over time](https://starchart.cc/ArtalkJS/Artalk.svg)](https://starchart.cc/ArtalkJS/Artalk)
## License
[MIT](./LICENSE)
[![FOSSA Status](https://app.fossa.com/api/projects/git%2Bgithub.com%2FArtalkJS%2FArtalk.svg?type=shield)](https://app.fossa.com/projects/git%2Bgithub.com%2FArtalkJS%2FArtalk?ref=badge_shield)
[![FOSSA Status](https://app.fossa.com/api/projects/git%2Bgithub.com%2FArtalkJS%2FArtalk.svg?type=large)](https://app.fossa.com/projects/git%2Bgithub.com%2FArtalkJS%2FArtalk?ref=badge_large)
+134
View File
@@ -0,0 +1,134 @@
<p align="center">
<img src="https://user-images.githubusercontent.com/22412567/171680920-6e74b77c-c565-487b-bff1-4f94976ecbe7.png" alt="Artalk" width="100%">
</p>
# Artalk
[![npm version](https://img.shields.io/npm/v/artalk.svg?style=flat-square)](https://www.npmjs.com/package/artalk)
[![npm downloads](https://img.shields.io/npm/dt/artalk.svg?style=flat-square)](https://www.npmjs.com/package/artalk)
[![Docker Pulls](https://img.shields.io/docker/pulls/artalk/artalk-go?style=flat-square)](https://hub.docker.com/r/artalk/artalk-go)
[![Go Reference](https://pkg.go.dev/badge/github.com/artalkjs/artalk/v2.svg)](https://pkg.go.dev/github.com/artalkjs/artalk/v2)
[![Go Report Card](https://goreportcard.com/badge/github.com/ArtalkJS/Artalk?style=flat-square)](https://goreportcard.com/report/github.com/ArtalkJS/Artalk)
[![CircleCI](https://img.shields.io/circleci/build/gh/ArtalkJS/Artalk?style=flat-square)](https://circleci.com/gh/ArtalkJS/Artalk/tree/master)
[![Codecov](https://img.shields.io/codecov/c/gh/ArtalkJS/Artalk?style=flat-square)](https://codecov.io/gh/ArtalkJS/Artalk)
[![npm bundle size](https://img.shields.io/bundlephobia/minzip/artalk?style=flat-square)](https://bundlephobia.com/package/artalk)
[ホームページ](https://artalk.js.org) • [ドキュメント](https://artalk.js.org/en/guide/deploy.html) • [最新リリース](https://github.com/ArtalkJS/Artalk/releases) • [変更履歴](https://github.com/ArtalkJS/Artalk/blob/master/CHANGELOG.md) • [English](./README.md) • [简体中文](./README.zh.md)
Artalk は直感的かつ高機能なコメントシステムで、あらゆるブログ、ウェブサイト、ウェブアプリケーションにすぐに導入できます。
- 🍃 クライアントは約 40KB、純粋な Vanilla JS で作られており、フレームワークに依存しません
- 🍱 サーバーは Golang を採用し、効率的かつ軽量なクロスプラットフォーム性能を提供します
- 🐳 Docker によるワンクリックデプロイで、手軽かつ高速に導入できます
- 🌈 オープンソースソフトウェアで、プライバシーを最優先にセルフホストできます
## 機能
<!-- prettier-ignore-start -->
<!-- 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/plugin.html): さらなる可能性を創出
* [多言語対応](https://artalk.js.org/guide/frontend/i18n.html): 複数の言語を切り替え
* [コマンドライン](https://artalk.js.org/guide/backend/config.html): コマンドラインによる操作管理
* [API ドキュメント](https://artalk.js.org/http-api.html): OpenAPI 形式のドキュメントを提供
* [プログラムのアップグレード](https://artalk.js.org/guide/backend/update.html): バージョンチェックとワンクリックアップグレード
<!-- /features -->
<!-- prettier-ignore-end -->
## インストール
Docker でワンステップで Artalk サーバーをデプロイ:
```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
```
Artalk クライアントをウェブページに組み込む:
<!-- prettier-ignore-start -->
```ts
Artalk.init({
el: '#Comments',
site: 'Artalk Blog',
server: 'https://artalk.example.com',
pageKey: '/2018/10/02/hello-world.html'
})
```
<!-- prettier-ignore-end -->
バイナリファイル、go install、Linux ディストリビューション向けのパッケージマネージャーなど、さまざまなインストール方法を提供しています。
[**詳しく見る →**](https://artalk.js.org/en/guide/deploy.html)
## 開発者の方へ
プルリクエストを歓迎します!
コードベースの扱い方、ローカル開発環境のセットアップ、変更の貢献については [開発](https://artalk.js.org/en/develop/) と [コントリビューション](./CONTRIBUTING.md) をご覧ください。
## コントリビューター
皆さんの貢献はオープンソースコミュニティを豊かにし、学び、ひらめき、イノベーションを育みます。私たちは皆さんの参加を心から大切にしています。私たちのコミュニティに欠かせない存在でいてくれて、ありがとうございます!🥰
[![](https://contrib.rocks/image?repo=ArtalkJS/Artalk)](https://github.com/ArtalkJS/Artalk/graphs/contributors)
## サポーター
[![Stargazers repo roster for @ArtalkJS/Artalk](https://reporoster.com/stars/ArtalkJS/Artalk)](https://github.com/ArtalkJS/Artalk/stargazers)
## Repobeats アナリティクス
![Alt](https://repobeats.axiom.co/api/embed/a9fc9191ac561bc5a8ee2cddc81e635ecaebafb6.svg 'Repobeats analytics image')
## Stargazer の推移
<a href="https://trendshift.io/repositories/6290" target="_blank"><img src="https://trendshift.io/api/badge/repositories/6290" alt="ArtalkJS%2FArtalk | Trendshift" style="width: 250px; height: 55px;" width="250" height="55"/></a>
[![Stargazers over time](https://starchart.cc/ArtalkJS/Artalk.svg)](https://starchart.cc/ArtalkJS/Artalk)
## ライセンス
[MIT](./LICENSE)
[![FOSSA Status](https://app.fossa.com/api/projects/git%2Bgithub.com%2FArtalkJS%2FArtalk.svg?type=shield)](https://app.fossa.com/projects/git%2Bgithub.com%2FArtalkJS%2FArtalk?ref=badge_shield)
[![FOSSA Status](https://app.fossa.com/api/projects/git%2Bgithub.com%2FArtalkJS%2FArtalk.svg?type=large)](https://app.fossa.com/projects/git%2Bgithub.com%2FArtalkJS%2FArtalk?ref=badge_large)
+78 -180
View File
@@ -7,114 +7,108 @@
[![npm version](https://img.shields.io/npm/v/artalk.svg?style=flat-square)](https://www.npmjs.com/package/artalk)
[![npm downloads](https://img.shields.io/npm/dt/artalk.svg?style=flat-square)](https://www.npmjs.com/package/artalk)
[![Docker Pulls](https://img.shields.io/docker/pulls/artalk/artalk-go?style=flat-square)](https://hub.docker.com/r/artalk/artalk-go)
[![Go Reference](https://pkg.go.dev/badge/github.com/artalkjs/artalk/v2.svg)](https://pkg.go.dev/github.com/artalkjs/artalk/v2)
[![Go Report Card](https://goreportcard.com/badge/github.com/ArtalkJS/Artalk?style=flat-square)](https://goreportcard.com/report/github.com/ArtalkJS/Artalk)
[![CircleCI](https://img.shields.io/circleci/build/gh/ArtalkJS/Artalk?style=flat-square)](https://circleci.com/gh/ArtalkJS/Artalk/tree/master)
[![Codecov](https://img.shields.io/codecov/c/gh/ArtalkJS/Artalk?style=flat-square)](https://codecov.io/gh/ArtalkJS/Artalk)
[![npm bundle size](https://img.shields.io/bundlephobia/minzip/artalk?style=flat-square)](https://bundlephobia.com/package/artalk)
> 🌌 Golang 自托管评论系统
[Homepage](https://artalk.js.org) • [Documentation](https://artalk.js.org/en/guide/deploy.html) • [Latest Release](https://github.com/ArtalkJS/Artalk/releases) • [Changelog](https://github.com/ArtalkJS/Artalk/blob/master/CHANGELOG.md) • [简体中文](./README.zh.md) • [日本語](./README.ja.md)
[English](./README.en.md) / [官方文档](https://artalk.js.org) / [最新版本](https://github.com/ArtalkJS/Artalk/releases)
Artalk is an intuitive yet feature-rich comment system, ready for immediate deployment into any blog, website, or web application.
---
- 🍃 Client ~40KB, crafted with pure Vanilla JS, framework-agnostic
- 🍱 Server powered by Golang, offering efficient and lightweight cross-platform performance
- 🐳 One-click deployment via Docker, ensuring ease and speed
- 🌈 Open-source software, self-hosted with privacy as a priority
- 🍃 轻量 (~30kB)
- 👨‍👧‍👦 安全 (自托管)
- 🐳 易上手 (防脱发)
- 🍱 Golang 后端 (快速 / 跨平台)
- 🌊 Vanilla × TypeScript × Vite (纯天然 / 无依赖)
## Features
## 特性
<!-- prettier-ignore-start -->
- 侧 边 栏 :支持多站点集中化管理
- 通知中心:红点的标记 / 提及列表
- 身份验证:徽标自定义 / 密码验证
- 评论审核:反垃圾检测 / 频率限制
- 表情符号:插入表情包 / 快速导入
- 邮件提醒:模版自定义 / 多管理员
- 站点隔离:管理员分配 / 多个站点
- 页面管理:标题可显示 / 快速跳转
- 图片上传:上传到本地 / 多种图床
- 多元推送:支持 钉钉 飞书 TG
- 无限层级:可切换为平铺模式
- 评论投票:赞同还是反对评论
- 评论排序:按热度或时间排序
- 评论置顶:重要消息置顶显示
- 只看作者:仅显示作者的评论
- 说说模式:仅自己可发布评论
- 异步处理:发送评论无需等待
- 滚动加载:评论内容分页处置
- 自动保存:用户输入防丢功能
- 自动填充:用户链接自动填充
- 实时预览:评论内容实时预览
- 夜间模式:防止眼部疾病伤害
- 评论折叠:这个不打算给你康
- 数据备份:防止评论数据丢失
- 数据迁移:快速切换评论系统
- Markdown:默认支持 MD 语法
- 支持 Latex:提供集成 Katex 插件
- 使用 [Vite](https://github.com/vitejs/vite):属于开发者的极致体验
<!-- features -->
* [Sidebar](https://artalk.js.org/guide/frontend/sidebar.html): Quick management, intuitive browsing
* [Social Login](https://artalk.js.org/guide/frontend/auth.html): Fast login via social accounts
* [Email Notification](https://artalk.js.org/guide/backend/email.html): Various sending methods, email templates
* [Diverse Push](https://artalk.js.org/guide/backend/admin_notify.html): Multiple push methods, notification templates
* [Site Notification](https://artalk.js.org/guide/frontend/sidebar.html): Red dot marks, mention list
* [Captcha](https://artalk.js.org/guide/backend/captcha.html): Various verification types, frequency limits
* [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, supports image hosting
* [Markdown](https://artalk.js.org/guide/intro.html): Supports Markdown syntax
* [Emoji Pack](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 navigation
* [Page View Statistics](https://artalk.js.org/guide/frontend/pv.html): Easily track page views
* [Hierarchical Structure](https://artalk.js.org/guide/frontend/config.html#nestmax): Nested paginated list, infinite scroll
* [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): Various sorting options, freely selectable
* [Comment Search](https://artalk.js.org/guide/frontend/sidebar.html): Quick comment content search
* [Comment Pinning](https://artalk.js.org/guide/frontend/sidebar.html): Pin important messages
* [View Author Only](https://artalk.js.org/guide/frontend/config.html): Show only the author's comments
* [Comment Jump](https://artalk.js.org/guide/intro.html): Quickly jump to quoted comment
* [Auto Save](https://artalk.js.org/guide/frontend/config.html): Content loss prevention
* [IP Region](https://artalk.js.org/guide/frontend/ip-region.html): Display user's IP region
* [Data Migration](https://artalk.js.org/guide/transfer.html): Free migration, quick backup
* [Image Lightbox](https://artalk.js.org/guide/frontend/lightbox.html): Quick integration of image lightbox
* [Image Lazy Load](https://artalk.js.org/guide/frontend/img-lazy-load.html): Lazy load images, optimize experience
* [Latex](https://artalk.js.org/guide/frontend/latex.html): Integrate Latex formula parsing
* [Night Mode](https://artalk.js.org/guide/frontend/config.html#darkmode): Switch to night mode
* [Extension Plugin](https://artalk.js.org/develop/plugin.html): Create more possibilities
* [Multi-Language](https://artalk.js.org/guide/frontend/i18n.html): Switch between multiple languages
* [Command Line](https://artalk.js.org/guide/backend/config.html): Command line operation management
* [API Documentation](https://artalk.js.org/http-api.html): Provides OpenAPI format documentation
* [Program Upgrade](https://artalk.js.org/guide/backend/update.html): Version check, one-click upgrade
<!-- /features -->
更多内容请查看:[**介绍文档**](https://artalk.js.org/guide/intro.html)
<!-- prettier-ignore-end -->
## 安装
## Installation
参考:[**部署文档**](https://artalk.js.org/guide/deploy.html)
```bash
npm install artalk
```
```ts
import Artalk from 'artalk'
Artalk.init({
el: '#Comments',
site: 'Artalk 的博客',
server: 'https://artalk.example.com'
})
```
### Docker
Deploy Artalk Server with Docker in one step:
```bash
docker run -d \
--name artalk \
-p 8080:23366 \
-v $(pwd)/data:/data \
--restart=always \
artalk/artalk-go
--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
```
### Docker Compose
Integrate Artalk Client into your webpage:
```bash
vim docker-compose.yaml
<!-- prettier-ignore-start -->
```ts
Artalk.init({
el: '#Comments',
site: 'Artalk Blog',
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
restart: always
ports:
- 8080:23366
volumes:
- ./data:/data
```
<!-- prettier-ignore-end -->
```bash
docker-compose up -d
```
We offer various installation methods, including binary files, go install, and package managers for Linux distributions.
## Development
[**Learn More →**](https://artalk.js.org/en/guide/deploy.html)
see [CONTRIBUTING.md](./CONTRIBUTING.md)
## For Developers
Pull requests are welcome!
See [Development](https://artalk.js.org/en/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://contrib.rocks/image?repo=ArtalkJS/Artalk)](https://github.com/ArtalkJS/Artalk/graphs/contributors)
## Supporters
@@ -123,108 +117,12 @@ see [CONTRIBUTING.md](./CONTRIBUTING.md)
## Repobeats Analytics
![Alt](https://repobeats.axiom.co/api/embed/a9fc9191ac561bc5a8ee2cddc81e635ecaebafb6.svg "Repobeats analytics image")
## 特别致谢
感谢社区提供的帮助与反馈,若有好的建议与意见欢迎前往 [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] 一键升级
![Alt](https://repobeats.axiom.co/api/embed/a9fc9191ac561bc5a8ee2cddc81e635ecaebafb6.svg 'Repobeats analytics image')
## Stargazers over time
<a href="https://trendshift.io/repositories/6290" target="_blank"><img src="https://trendshift.io/api/badge/repositories/6290" alt="ArtalkJS%2FArtalk | Trendshift" style="width: 250px; height: 55px;" width="250" height="55"/></a>
[![Stargazers over time](https://starchart.cc/ArtalkJS/Artalk.svg)](https://starchart.cc/ArtalkJS/Artalk)
## License
+134
View File
@@ -0,0 +1,134 @@
<p align="center">
<img src="https://user-images.githubusercontent.com/22412567/171680920-6e74b77c-c565-487b-bff1-4f94976ecbe7.png" alt="Artalk" width="100%">
</p>
# Artalk
[![npm version](https://img.shields.io/npm/v/artalk.svg?style=flat-square)](https://www.npmjs.com/package/artalk)
[![npm downloads](https://img.shields.io/npm/dt/artalk.svg?style=flat-square)](https://www.npmjs.com/package/artalk)
[![Docker Pulls](https://img.shields.io/docker/pulls/artalk/artalk-go?style=flat-square)](https://hub.docker.com/r/artalk/artalk-go)
[![Go Reference](https://pkg.go.dev/badge/github.com/artalkjs/artalk/v2.svg)](https://pkg.go.dev/github.com/artalkjs/artalk/v2)
[![Go Report Card](https://goreportcard.com/badge/github.com/ArtalkJS/Artalk?style=flat-square)](https://goreportcard.com/report/github.com/ArtalkJS/Artalk)
[![CircleCI](https://img.shields.io/circleci/build/gh/ArtalkJS/Artalk?style=flat-square)](https://circleci.com/gh/ArtalkJS/Artalk/tree/master)
[![Codecov](https://img.shields.io/codecov/c/gh/ArtalkJS/Artalk?style=flat-square)](https://codecov.io/gh/ArtalkJS/Artalk)
[![npm bundle size](https://img.shields.io/bundlephobia/minzip/artalk?style=flat-square)](https://bundlephobia.com/package/artalk)
[官方网站](https://artalk.js.org) • [最新版本](https://github.com/ArtalkJS/Artalk/releases) • [更新日志](https://github.com/ArtalkJS/Artalk/blob/master/CHANGELOG.md) • [English](./README.md) • [日本語](./README.ja.md)
Artalk 是一款简单易用但功能丰富的评论系统,你可以开箱即用地部署并置入任何博客、网站、Web 应用。
- 🍃 前端 ~40KB,纯天然 Vanilla JS
- 🍱 后端 Golang,高效轻量跨平台
- 🐳 通过 Docker 一键部署,方便快捷
- 🌈 开源程序,自托管,隐私至上
## 特性
<!-- prettier-ignore-start -->
<!-- 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/plugin.html): 创造更多可能性
* [多语言](https://artalk.js.org/guide/frontend/i18n.html): 多国语言切换
* [命令行](https://artalk.js.org/guide/backend/config.html): 命令行操作管理能力
* [API 文档](https://artalk.js.org/http-api.html): 提供 OpenAPI 格式文档
* [程序升级](https://artalk.js.org/guide/backend/update.html): 版本检测,一键升级
<!-- /features -->
<!-- prettier-ignore-end -->
## 安装
通过 Docker 一键部署 Artalk 服务器:
```bash
docker run -d \
--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
```
在你的网页中引入 Artalk 客户端:
<!-- prettier-ignore-start -->
```ts
Artalk.init({
el: '#Comments',
site: 'Artalk 的博客',
server: 'https://artalk.example.com',
pageKey: '/2018/10/02/hello-world.html'
})
```
<!-- prettier-ignore-end -->
我们提供多种安装方法,包括二进制文件、`go install` 和通过 Linux 发行版的包管理器安装。
[**了解更多 →**](https://artalk.js.org/zh/guide/deploy.html)
## 参与开发
我们欢迎你的 Pull Request!
有关如何使用代码库、设置本地开发环境和贡献更改的信息,请参阅 [开发文档](https://artalk.js.org/zh/develop/) 和 [贡献指南](./CONTRIBUTING.md)。
## 贡献者们
你的贡献丰富了开源社区,促进了学习、灵感和创新。我们非常重视你的参与。感谢你成为我们社区的重要一员!🥰
[![](https://contrib.rocks/image?repo=ArtalkJS/Artalk)](https://github.com/ArtalkJS/Artalk/graphs/contributors)
## 支持者们
[![Stargazers repo roster for @ArtalkJS/Artalk](https://reporoster.com/stars/ArtalkJS/Artalk)](https://github.com/ArtalkJS/Artalk/stargazers)
## Repobeats 分析
![Alt](https://repobeats.axiom.co/api/embed/a9fc9191ac561bc5a8ee2cddc81e635ecaebafb6.svg 'Repobeats analytics image')
## Star 趋势
<a href="https://trendshift.io/repositories/6290" target="_blank"><img src="https://trendshift.io/api/badge/repositories/6290" alt="ArtalkJS%2FArtalk | Trendshift" style="width: 250px; height: 55px;" width="250" height="55"/></a>
[![Stargazers over time](https://starchart.cc/ArtalkJS/Artalk.svg)](https://starchart.cc/ArtalkJS/Artalk)
## 开源许可协议
[MIT](./LICENSE) (麻省理工学院许可证)
[![FOSSA Status](https://app.fossa.com/api/projects/git%2Bgithub.com%2FArtalkJS%2FArtalk.svg?type=shield)](https://app.fossa.com/projects/git%2Bgithub.com%2FArtalkJS%2FArtalk?ref=badge_shield)
[![FOSSA Status](https://app.fossa.com/api/projects/git%2Bgithub.com%2FArtalkJS%2FArtalk.svg?type=large)](https://app.fossa.com/projects/git%2Bgithub.com%2FArtalkJS%2FArtalk?ref=badge_large)
+3
View File
@@ -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!
+20 -7
View File
@@ -7,10 +7,10 @@ import (
"strings"
"syscall"
"github.com/ArtalkJS/Artalk/internal/entity"
"github.com/ArtalkJS/Artalk/internal/i18n"
"github.com/ArtalkJS/Artalk/internal/log"
"github.com/ArtalkJS/Artalk/internal/utils"
"github.com/artalkjs/artalk/v2/internal/entity"
"github.com/artalkjs/artalk/v2/internal/i18n"
"github.com/artalkjs/artalk/v2/internal/log"
"github.com/artalkjs/artalk/v2/internal/utils"
"github.com/spf13/cobra"
"golang.org/x/term"
)
@@ -25,14 +25,23 @@ func NewAdminCommand(app *ArtalkCmd) *cobra.Command {
fmt.Println(" " + i18n.T("Create admin account"))
fmt.Println("--------------------------------")
username, email, password, err := credentials()
if err != nil {
log.Fatal(err)
// get from flags
username, _ := cmd.Flags().GetString("name")
email, _ := cmd.Flags().GetString("email")
password, _ := cmd.Flags().GetString("password")
if username == "" || email == "" || password == "" {
var err error
username, email, password, err = credentials()
if err != nil {
log.Fatal(err)
}
}
findUser := app.Dao().FindUser(username, email)
if !findUser.IsEmpty() {
findUser.SetPasswordEncrypt(password)
findUser.IsAdmin = true
if err := app.Dao().UpdateUser(&findUser); err != nil {
log.Fatal(err)
}
@@ -62,6 +71,10 @@ func NewAdminCommand(app *ArtalkCmd) *cobra.Command {
},
}
flag(adminCmd, "name", "", i18n.T("Username"))
flag(adminCmd, "email", "", i18n.T("Email"))
flag(adminCmd, "password", "", i18n.T("Password"))
return adminCmd
}
+79 -15
View File
@@ -4,17 +4,19 @@ import (
"fmt"
"os"
"os/signal"
"path"
"path/filepath"
"syscall"
"github.com/ArtalkJS/Artalk/internal/config"
"github.com/ArtalkJS/Artalk/internal/core"
"github.com/ArtalkJS/Artalk/internal/log"
"github.com/adrg/xdg"
"github.com/artalkjs/artalk/v2/internal/config"
"github.com/artalkjs/artalk/v2/internal/core"
"github.com/artalkjs/artalk/v2/internal/log"
"github.com/artalkjs/artalk/v2/internal/utils"
"github.com/fatih/color"
"github.com/spf13/cobra"
)
var Version = config.Version + `/` + config.CommitHash
var Banner = `
________ ________ _________ ________ ___ ___ __
|\ __ \|\ __ \|\___ ___\\ __ \|\ \ |\ \|\ \
@@ -24,7 +26,7 @@ var Banner = `
\ \__\ \__\ \__\\ _\ \ \__\ \ \__\ \__\ \_______\ \__\\ \__\
\|__|\|__|\|__|\|__| \|__| \|__|\|__|\|_______|\|__| \|__|
Artalk (` + Version + `)
Artalk (` + config.VersionString() + `)
-> A Self-hosted Comment System.
-> https://artalk.js.org
@@ -52,7 +54,7 @@ func New() *ArtalkCmd {
Use: "artalk",
Short: "Artalk: A self-hosted comment system",
Long: Banner,
Version: Version,
Version: config.VersionString(),
Run: func(cmd *cobra.Command, args []string) {
fmt.Println(Banner)
fmt.Print("-------------------------------\n\n")
@@ -66,16 +68,44 @@ func New() *ArtalkCmd {
// 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)
}
// Resolve config from the invocation directory before an implicit data-dir chdir.
if cfgFile, err := resolveConfigFileBeforeDataDir(cmd.cfgFile, cmd.workDir); err == nil {
cmd.cfgFile = cfgFile
} else {
log.Fatal("Config path fail: ", err)
}
// Init data directory (work directory)
if workDir, err := initDataDir(cmd.workDir); err == nil {
cmd.workDir = workDir
} else {
log.Fatal("Data directory fail: ", err)
}
return cmd
}
func resolveConfigFileBeforeDataDir(cfgFile string, workDir string) (string, error) {
// An explicit work directory keeps the historical behavior: relative config
// paths and default config discovery are resolved after changing to workDir.
if workDir != "" {
return cfgFile, nil
}
if cfgFile == "" {
cfgFile = config.RetrieveConfigFile()
}
if cfgFile == "" || filepath.IsAbs(cfgFile) {
return cfgFile, nil
}
absPath, err := filepath.Abs(cfgFile)
if err != nil {
return "", fmt.Errorf("resolve config file %q: %w", cfgFile, err)
}
return absPath, nil
}
// Parses the global app flags before calling atk.RootCmd.Execute().
// so we can have all flags ready for use on initialization.
func (atk *ArtalkCmd) eagerParseFlags() error {
@@ -169,16 +199,50 @@ func (atk *ArtalkCmd) Launch() error {
return nil
}
func initDataDir(workDir string) (string, error) {
// If work directory is not specified, try to find it
if workDir == "" {
// If `data` in current directory exists, not change work directory
if utils.CheckDirExist("./data") {
// log.Warn("[DEPRECATED] The `data` directory is deprecated, please move to `~/.local/share/artalk/data`")
return "", nil
}
// Retrieve data directory assuming it's already exists
workDir = config.RetrieveDataDir()
}
// Create new data directory if not exists
if workDir == "" {
// default data path is `~/.local/share/artalk`
workDir = path.Join(xdg.DataHome, "artalk")
if err := utils.EnsureDir(workDir); err != nil {
return "", fmt.Errorf("data directory creation error: %v", err)
}
}
// Change work directory
if workDir != "" {
if err := os.Chdir(workDir); err != nil {
return "", fmt.Errorf("working directory change error: %v", err)
}
}
return workDir, 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 config file is not specified, try to find it
if cfgFile == "" {
// Retrieve config file assuming it's already exists
cfgFile = config.RetrieveConfigFile()
}
// Generate new config file when retrieve failed
// Generate new config file if not exists
if cfgFile == "" {
cfgFile = config.CONF_DEFAULT_FILENAMES[0]
// default config path is `~/.config/artalk/artalk.yml`
cfgFile = path.Join(xdg.ConfigHome, "artalk", config.CONF_DEFAULT_FILENAMES[0])
core.Gen("config", cfgFile, false)
}
+72
View File
@@ -0,0 +1,72 @@
package cmd
import (
"os"
"path/filepath"
"testing"
"github.com/adrg/xdg"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestResolveConfigFileBeforeDataDir(t *testing.T) {
originalDir, err := os.Getwd()
require.NoError(t, err)
originalDataHome := xdg.DataHome
defer func() {
require.NoError(t, os.Chdir(originalDir))
xdg.DataHome = originalDataHome
}()
invocationDir := t.TempDir()
dataHome := t.TempDir()
invocationDir, err = filepath.EvalSymlinks(invocationDir)
require.NoError(t, err)
dataHome, err = filepath.EvalSymlinks(dataHome)
require.NoError(t, err)
dataDir := filepath.Join(dataHome, "artalk")
require.NoError(t, os.Mkdir(dataDir, 0o755))
require.NoError(t, os.WriteFile(
filepath.Join(invocationDir, "artalk.yml"),
[]byte("timezone: UTC\n"),
0o600,
))
require.NoError(t, os.Chdir(invocationDir))
xdg.DataHome = dataHome
cfgFile, err := resolveConfigFileBeforeDataDir("", "")
require.NoError(t, err)
assert.Equal(t, filepath.Join(invocationDir, "artalk.yml"), cfgFile)
workDir, err := initDataDir("")
require.NoError(t, err)
assert.Equal(t, dataDir, workDir)
currentDir, err := os.Getwd()
require.NoError(t, err)
assert.Equal(t, dataDir, currentDir)
conf, err := getConfig(cfgFile)
require.NoError(t, err)
assert.Equal(t, "UTC", conf.TimeZone)
}
func TestResolveConfigFileWithExplicitPaths(t *testing.T) {
originalDir, err := os.Getwd()
require.NoError(t, err)
defer func() { require.NoError(t, os.Chdir(originalDir)) }()
invocationDir := t.TempDir()
invocationDir, err = filepath.EvalSymlinks(invocationDir)
require.NoError(t, err)
require.NoError(t, os.Chdir(invocationDir))
cfgFile, err := resolveConfigFileBeforeDataDir("custom.yml", "")
require.NoError(t, err)
assert.Equal(t, filepath.Join(invocationDir, "custom.yml"), cfgFile)
cfgFile, err = resolveConfigFileBeforeDataDir("custom.yml", "./runtime")
require.NoError(t, err)
assert.Equal(t, "custom.yml", cfgFile)
}
+1 -1
View File
@@ -4,7 +4,7 @@ import (
"encoding/json"
"fmt"
"github.com/ArtalkJS/Artalk/internal/log"
"github.com/artalkjs/artalk/v2/internal/log"
"github.com/spf13/cobra"
)
+4 -4
View File
@@ -7,10 +7,10 @@ import (
"path/filepath"
"time"
"github.com/ArtalkJS/Artalk/internal/artransfer"
"github.com/ArtalkJS/Artalk/internal/i18n"
"github.com/ArtalkJS/Artalk/internal/log"
"github.com/ArtalkJS/Artalk/internal/utils"
"github.com/artalkjs/artalk/v2/internal/artransfer"
"github.com/artalkjs/artalk/v2/internal/i18n"
"github.com/artalkjs/artalk/v2/internal/log"
"github.com/artalkjs/artalk/v2/internal/utils"
"github.com/spf13/cobra"
)
+1 -1
View File
@@ -1,7 +1,7 @@
package cmd
import (
"github.com/ArtalkJS/Artalk/internal/core"
"github.com/artalkjs/artalk/v2/internal/core"
"github.com/spf13/cobra"
)
+33 -14
View File
@@ -1,12 +1,13 @@
package cmd
import (
"encoding/json"
"errors"
"os"
"github.com/ArtalkJS/Artalk/internal/artransfer"
"github.com/ArtalkJS/Artalk/internal/i18n"
"github.com/ArtalkJS/Artalk/internal/log"
"github.com/artalkjs/artalk/v2/internal/artransfer"
"github.com/artalkjs/artalk/v2/internal/i18n"
"github.com/artalkjs/artalk/v2/internal/log"
"github.com/spf13/cobra"
)
@@ -16,26 +17,44 @@ func NewImportCommand(app *ArtalkCmd) *cobra.Command {
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 -2
View File
@@ -3,8 +3,8 @@ package cmd
import (
"fmt"
"github.com/ArtalkJS/Artalk/internal/log"
"github.com/ArtalkJS/Artalk/server"
"github.com/artalkjs/artalk/v2/internal/log"
"github.com/artalkjs/artalk/v2/server"
"github.com/spf13/cobra"
)
+5 -5
View File
@@ -5,9 +5,9 @@ import (
"os"
"strings"
"github.com/ArtalkJS/Artalk/internal/config"
"github.com/ArtalkJS/Artalk/internal/i18n"
"github.com/ArtalkJS/Artalk/internal/log"
"github.com/artalkjs/artalk/v2/internal/config"
"github.com/artalkjs/artalk/v2/internal/i18n"
"github.com/artalkjs/artalk/v2/internal/log"
"github.com/blang/semver"
"github.com/rhysd/go-github-selfupdate/selfupdate"
"github.com/spf13/cobra"
@@ -32,7 +32,7 @@ func NewUpgradeCommand() *cobra.Command {
if !ignoreVersionCheck {
v := semver.MustParse(strings.TrimPrefix(config.Version, "v"))
if !found || latest.Version.LTE(v) {
log.Println(i18n.T("Current version is the latest") + " (v" + v.String() + ")")
log.Info(i18n.T("Current version is the latest") + " (v" + v.String() + ")")
return
}
}
@@ -49,7 +49,7 @@ func NewUpgradeCommand() *cobra.Command {
log.Fatal(i18n.T("Update failed")+" ", err)
}
log.Println(i18n.T("Update complete"))
log.Info(i18n.T("Update complete"))
fmt.Printf("\n"+
"-------------------------------\n"+
" v%s Release Note\n"+
+2 -1
View File
@@ -3,6 +3,7 @@ package cmd
import (
"fmt"
"github.com/artalkjs/artalk/v2/internal/config"
"github.com/spf13/cobra"
)
@@ -11,7 +12,7 @@ func NewVersionCommand() *cobra.Command {
Use: "version",
Short: "Output version information",
Run: func(cmd *cobra.Command, args []string) {
fmt.Println("Artalk (" + Version + ")")
fmt.Println("Artalk (" + config.VersionString() + ")")
},
Annotations: map[string]string{
BootModeKey: MODE_MINI_BOOT,
+2
View File
@@ -0,0 +1,2 @@
ignore:
- "docs/*"
+120 -33
View File
@@ -2,32 +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
@@ -44,23 +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:
- "./data/keywords_1.txt"
- ./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:
@@ -77,31 +82,32 @@ captcha:
captcha_key: ""
img_upload:
enabled: true
path: "./data/artalk-img/"
path: ./data/artalk-img/
max_size: 5
public_path: null
upgit:
enabled: false
exec: "./upgit -c UPGIT_CONF_FILE_PATH -t /artalk-img"
exec: upgit -c UPGIT_CONF_FILE_PATH -t /artalk-img
del_local: true
email:
enabled: false
send_type: "smtp"
send_type: smtp
send_name: "{{reply_nick}}"
send_addr: "noreply@example.com"
send_addr: noreply@example.com
mail_subject: "[{{site_name}}] You got a reply from @{{reply_nick}}"
mail_tpl: "default"
mail_tpl: default
smtp:
host: "smtp.qq.com"
host: smtp.qq.com
port: 587
username: "example@qq.com"
username: example@qq.com
password: ""
ali_dm:
access_key_id: ""
access_key_secret: ""
account_name: "noreply@example.com"
account_name: noreply@example.com
admin_notify:
notify_tpl: "default"
notify_tpl: default
notify_pending: false
noise_mode: false
email:
enabled: true
@@ -114,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: ""
@@ -137,25 +144,103 @@ 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: ""
sso:
enabled: false
issuer: ""
frontend:
placeholder: ""
noComment: ""
sendBtn: ""
editorTravel: true
emoticons: "https://cdn.jsdelivr.net/gh/ArtalkJS/Emoticons/grps/default.json"
emoticons: https://cdn.jsdelivr.net/gh/ArtalkJS/Emoticons/grps/default.json
vote: true
voteDown: false
uaBadge: false
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/avatar/"
params: "d=mp&s=240"
mirror: https://www.gravatar.com/avatar/
params: sha256=1&d=mp&s=240
pagination:
pageSize: 20
readMore: true
@@ -164,5 +249,7 @@ frontend:
content: 300
children: 400
scrollable: false
imgLazyLoad: false
reqTimeout: 15000
versionCheck: true
pluginURLs: []
+456
View File
@@ -0,0 +1,456 @@
# Dinleme adresi
host: "0.0.0.0"
# Dinleme portu
port: 23366
# Uygulama Anahtarı (JWT üretimi için)
app_key: ""
# Hata ayıklama modu
debug: false
# Dil (Unicode BCP 47 formatında) ["en", "zh-CN", "zh-TW", "ja", "fr", "ko", "ru", "tr"]
# -- bkz. https://www.techonthenet.com/js/language_tags.php --
locale: tr
# Zaman dilimi (IANA Zaman Dilimi Veritabanı formatında)
# -- bkz. https://en.wikipedia.org/wiki/List_of_tz_database_time_zones --
timezone: Europe/Istanbul
# Varsayılan site adı (uygulama ilk başlatıldığında oluşturulur)
site_default: Varsayılan Site
# Varsayılan site URL'si
site_url: ""
# Giriş zaman aşımı (saniye cinsinden)
login_timeout: 259200
# Veritabanı
db:
# Veritabanı türü ["sqlite", "mysql", "pgsql", "mssql"]
type: sqlite
# Veritabanı dosyası (yalnızca SQLite için)
file: ./data/artalk.db
# Tablo öneki (örn. "atk_")
table_prefix: ""
# -- Aşağıdakiler SQLite için gerekli değildir --
# Veritabanı adı
name: artalk
# Ana makine adresi
host: localhost
# Ana makine portu
port: 3306
# Veritabanı kullanıcısı
user: root
# Veritabanı şifresi
password: ""
# Veritabanı karakter seti
charset: utf8mb4
# SSL modunu etkinleştir
ssl: false
# Hazır İfadeler (Prepared Statement)
prepare_stmt: true
# Web sunucusu
http:
# Gövde boyutu sınırı (birim: MB)
body_limit: 100
# Proxy Başlığı (güvenilir bir ters proxy veya CDN arkasındaysa kullanıcının gerçek IP'sini almak için `X-Forwarded-For` doldurun)
proxy_header: ""
# Günlük Kaydı (Logging)
log:
# Günlük kaydını etkinleştir
enabled: true
# Günlük dosyası yolu
filename: ./data/artalk.log
# Önbellek (Cache)
cache:
# Önbelleği etkinleştir
enabled: false
# Önbellek türü ["redis", "memcache", "builtin"]
type: builtin
# Önbellek geçerlilik süresi (dakika cinsinden)
expires: 30
# Önbellek ön yükleme (program başladığında önbelleği ısıtır)
warm_up: false
# -- Aşağıdakiler `builtin` (yerleşik) önbellek için gerekli değildir --
# Önbellek sunucu adresi (örn. "localhost:6379")
server: ""
# Redis yapılandırması
redis:
# Bağlantı türü ["tcp", "unix"]
network: tcp
# Redis kullanıcı adı
username: ""
# Redis şifresi
password: ""
# Redis veritabanı numarası (örn. 0)
db: 0
# Güvenilir alan adları
# -- örn. ["https://artalk.example.com:23366"] sitenizin URL'sini buraya ekleyin --
trusted_domains: []
# SSL
ssl:
# SSL'i etkinleştir
enabled: false
# Sertifika dosyası yolu
# (örn. "/etc/letsencrypt/live/example.com/fullchain.pem")
cert_path: ""
# Anahtar dosyası yolu
# (örn. "/etc/letsencrypt/live/example.com/privkey.pem")
key_path: ""
# Moderatör
# -- Yorumların herkese açık olmadan önce incelenmesi --
moderator:
# Varsayılan bekleme durumu (yeni yorumların yönetici tarafından onaylanması gerekir)
pending_default: false
# API isteği başarısız olduğunda engelle (API isteği başarısız olduğunda yorumların geçmesine izin vermek için false yapın)
api_fail_block: false
# Akismet Anahtarı
# (Akismet spam önleme servisi, https://akismet.com)
akismet_key: ""
# Tencent Bulut İçerik Güvenliği
# (Tencent Bulut İçerik Güvenliği ile yorumları otomatik inceleyin)
# -- bkz. https://cloud.tencent.com/document/product/1124/64508 --
tencent:
enabled: false
secret_id: ""
secret_key: ""
region: ap-guangzhou
# Aliyun İçerik Güvenliği
# (Aliyun İçerik Güvenliği ile yorumları otomatik inceleyin)
# -- bkz. https://help.aliyun.com/document_detail/28417.html --
aliyun:
enabled: false
access_key_id: ""
access_key_secret: ""
region: cn-shanghai
# Kelime filtresi (yerel çevrimdışı sözlük)
keywords:
# Kelime filtresini etkinleştir
enabled: false
# Eşleşme olduğunda beklemeye al
pending: false
# Sözlük dosyası (birden fazla sözlük dosyasını destekler)
files:
- ./data/keywords_1.txt
file_sep: "\n"
replace_to: x
# Doğrulama (Captcha)
captcha:
# Doğrulamayı etkinleştir
enabled: true
# Her zaman doğrulama gerekli
always: false
# Doğrulama türü ["image", "turnstile", "recaptcha", "hcaptcha", "geetest"]
captcha_type: image
# İşlem sınırı
# (doğrulamayı etkinleştirmek için gereken işlem sayısı)
action_limit: 3
# Sıfırlama Zaman Aşımı (işlem sayacını sıfırlama süresi. birim: saniye, devre dışı bırakmak için -1 yapın)
action_reset: 60
# Turnstile
# (https://www.cloudflare.com/products/turnstile/)
turnstile:
site_key: ""
secret_key: ""
# reCaptcha
# (https://www.google.com/recaptcha/about/)
recaptcha:
site_key: ""
secret_key: ""
# hCaptcha (https://www.hcaptcha.com/)
hcaptcha:
site_key: ""
secret_key: ""
# Geetest (https://www.geetest.com)
geetest:
captcha_id: ""
captcha_key: ""
# Yükleme
img_upload:
# Resim yüklemeyi etkinleştir
enabled: true
# Resim depolama yolu
path: ./data/artalk-img/
# Resim boyutu sınırı (birim: MB)
max_size: 5
# Resim bağlantısı temel yolu (varsayılan: "/static/images/")
public_path: null
# Upgit yapılandırması
upgit:
# Upgit'i etkinleştir
enabled: false
# Komut satırı argümanları
exec: upgit -c UPGIT_CONF_FILE_PATH -t /artalk-img
# Yükleme başarılı olduktan sonra yerel resmi sil
del_local: true
# E-posta
email:
# E-posta bildirimini etkinleştir
enabled: false
# Gönderim yöntemi ["smtp", "ali_dm", "sendmail"]
send_type: smtp
# Gönderen takma adı
send_name: "{{reply_nick}}"
# Gönderen e-posta adresi
send_addr: noreply@example.com
# E-posta konusu
mail_subject: "[{{site_name}}] @{{reply_nick}} tarafından bir yanıt aldınız"
# E-posta şablon dosyası (özel şablon kullanmak için dosya yolunu ayarlayın)
mail_tpl: default
# SMTP gönderimi (etkinleştirmek için gönderim yöntemini "smtp" yapın)
smtp:
# Gönderen e-posta sunucusu
host: smtp.qq.com
# E-posta portu
port: 587
# Kullanıcı adı
username: example@qq.com
# Şifre
password: ""
# Aliyun posta push
# (etkinleştirmek için gönderim yöntemini "ali_dm" yapın; bkz: https://help.aliyun.com/document_detail/29444.html)
ali_dm:
access_key_id: ""
access_key_secret: ""
account_name: noreply@example.com
# Çoklu Push
admin_notify:
# Bildirim şablonu (özel şablon kullanmak için dosya yolunu ayarlayın)
notify_tpl: default
# Bekleyen yorumlar için hala bildirim gönder (yorumlar engellendiğinde bile bildirimler gönderilir)
notify_pending: false
# Gürültü modu
# -- gürültü modu varsayılan olarak devre dışıdır. --
# -- Bu seçenek `false` olarak ayarlandığında, yalnızca yöneticiye gönderilen mesajlar bildirilir, --
# -- "kullanıcı A"nın "kullanıcı B"ye yanıt vermesi gibi iki kullanıcı arasındaki iletişim yöneticiye bildirilmez. --
noise_mode: false
# Yöneticiyi bildir
email:
# Etkinleştir (diğer push yöntemlerini kullanırken devre dışı bırakılabilir)
enabled: true
# E-posta konusu (yöneticiye gönderilen e-posta konusu)
mail_subject: '[{{site_name}}] "{{page_title}}" sayfası yeni bir yoruma sahip'
# Yönetici e-posta şablon dosyası (özel şablon kullanmak için dosya yolunu ayarlayın)
mail_tpl: ""
# Telegram
telegram:
enabled: false
api_token: ""
receivers:
- 7777777
# Bark
bark:
enabled: false
server: http://day.app/xxxxxxx/
# Lark
lark:
enabled: false
webhook_url: ""
# Mesaj türü ["text", "card"]
msg_type: "text"
# WebHook
webhook:
enabled: false
url: ""
# DingTalk
ding_talk:
enabled: false
token: ""
secret: ""
# Slack
slack:
enabled: false
oauth_token: ""
receivers:
- "CHANNEL_ID"
# LINE
line:
enabled: false
channel_secret: ""
channel_access_token: ""
receivers:
- USER_ID_1
- GROUP_ID_1
# Sosyal Giriş
auth:
# Sosyal Girişi Etkinleştir
enabled: false
# Anonim yorum yapmaya izin ver (Doğrulamayı atlamaya izin ver, yalnızca anonim bir takma ad ve e-posta doldurmak yeterlidir)
anonymous: false
# Geri dönüş URL'si (https://example.com/api/v2/auth/{provider}/callback)
callback: "http://localhost:23366/api/v2/auth/{provider}/callback"
# E-posta
email:
# E-posta şifre girişini etkinleştir
enabled: true
# Doğrulama e-postası konusu
verify_subject: "Kodunuz - {{code}}"
# Doğrulama e-postası şablonu (özel şablon kullanmak için dosya yolunu ayarlayın)
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: ""
# SSO (Harici OIDC erişim belirteçlerini Artalk oturumuyla değiştirir, IdP'nin /userinfo uç noktası ile doğrulanır)
# -- Gömülü uygulama zaten OIDC çalıştırıyorsa ve Artalk'ın kendi açılır giriş ekranını göstermeden bu oturumu devralmasını istiyorsanız kullanın. --
sso:
# SSO belirteç değişimini etkinleştir
enabled: false
# OIDC issuer URL'si (örn. "tenant.auth0.com" veya "https://tenant.auth0.com")
issuer: ""
# Kullanıcı Arayüzü Ayarları
frontend:
# Yorum kutusu yer tutucu metni
placeholder: ""
# Yorum olmadığında görüntülenecek metin
noComment: ""
# Gönder düğmesi metni
sendBtn: ""
# Hareketli yorum kutusu
editorTravel: true
# İfadeler (Emoticonlar)
emoticons: https://cdn.jsdelivr.net/gh/ArtalkJS/Emoticons/grps/default.json
# Oy verme düğmesi
vote: true
# Beğenmeme düğmesi
voteDown: false
# Kullanıcı UA rozeti
uaBadge: false
# Yorum sıralama
listSort: true
# Editör gerçek zamanlı önizleme
preview: true
# Düzleştirme modu ["auto", true, false]
flatMode: auto
# Karanlık mod ["inherit", "auto"]
darkMode: inherit
# Maksimum yuvalama seviyesi
nestMax: 2
# Yuvalama yorum sıralama kuralları ["DATE_ASC", "DATE_DESC", "VOTE_UP_DESC"]
nestSort: DATE_ASC
# Gravatar
gravatar:
# API URL'si
mirror: https://www.gravatar.com/avatar/
# API parametreleri
params: sha256=1&d=mp&s=240
# Yorum sayfalama
pagination:
# Sayfa başına yorum sayısı
pageSize: 20
# Daha fazla yükle modu (sayfalama çubuğunu kullanmak için devre dışı bırakın)
readMore: true
# Kaydırmalı yükleme
autoLoad: true
# İçerik yükseklik sınırı
heightLimit:
# Yorum içeriği yükseklik sınırı (birim: px)
content: 300
# Alt yorum alanı yükseklik sınırı (birim: px)
children: 400
# Kaydırılabilir (yükseklik sınırı alanı kaydırılabilir olsun)
scrollable: false
# Resim geç yükleme [false, "native", "data-src"]
imgLazyLoad: false
# İstek zaman aşımı (birim: ms)
reqTimeout: 15000
# Sürüm kontrolü
versionCheck: true
# Eklentiler
pluginURLs: []
+169 -40
View File
@@ -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", "tr"]
# -- 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,40 +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)
@@ -71,7 +83,7 @@ cache:
# Redis config
redis:
# Connection type ["tcp", "unix"]
network: "tcp"
network: tcp
# Redis username
username: ""
# Redis password
@@ -111,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 --
@@ -119,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
@@ -128,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:
@@ -139,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
@@ -169,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/")
@@ -179,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
@@ -188,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
@@ -212,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, --
@@ -240,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: ""
@@ -264,8 +282,117 @@ 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: ""
# SSO (Exchange external OIDC access tokens for Artalk login sessions, verified via the IdP's /userinfo endpoint)
# -- Use this when the embedding app already runs OIDC and you want Artalk to inherit that session without its own popup login UI. --
sso:
# Enable SSO token exchange
enabled: false
# OIDC issuer URL (e.g. "tenant.auth0.com" or "https://tenant.auth0.com")
issuer: ""
# UI Settings
frontend:
@@ -278,23 +405,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
# Vote down button
voteDown: false
# User UA badge
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"]
@@ -302,9 +427,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
@@ -321,7 +446,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: []
+182 -52
View File
@@ -10,54 +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
# 缓存启动预热 (程序启动时预热缓存)
@@ -67,7 +79,7 @@ cache:
# Redis 配置
redis:
# 连接方式 ["tcp", "unix"]
network: "tcp"
network: tcp
# 用户名
username: ""
# 密码
@@ -76,7 +88,8 @@ cache:
db: 0
# 可信域名
trusted_domains: [] # 例如:["https://artalk.example.com:23366"]
# -- 例如:["https://artalk.example.com:23366"] --
trusted_domains: []
# SSL
ssl:
@@ -88,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:
@@ -110,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
@@ -125,11 +140,11 @@ moderator:
pending: false
# 词库文件 (支持多个词库文件)
files:
- "./data/词库_1.txt"
- ./data/词库_1.txt
# 词库文件内容分割符 (例如填写 "\n" 文件中一行一个关键词)
file_sep: "\n"
# 替换字符
replac_to: "x"
replace_to: x
# 验证码
captcha:
@@ -138,7 +153,7 @@ captcha:
# 总是需要验证码
always: false
# 验证类型 ["image", "turnstile", "recaptcha", "hcaptcha", "geetest"]
captcha_type: "image"
captcha_type: image
# 激活验证码所需操作次数
action_limit: 3
# 重置操作计数器超时 (单位:s, 设为 -1 不重置)
@@ -162,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/")
@@ -187,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
@@ -196,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: ""
# 阿里云邮件推送
@@ -220,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
# 邮件通知管理员
@@ -245,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
@@ -264,17 +283,126 @@ 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: ""
# SSO (用外部 OIDC 身份提供商的访问令牌换取 Artalk 登录会话,通过调用 IdP 的 /userinfo 端点校验)
# -- 当嵌入页面已运行 OIDC 且希望 Artalk 复用该登录态、不显示自身弹窗登录界面时使用。 --
sso:
# 启用 SSO 令牌交换
enabled: false
# OIDC issuer 地址 (如 "tenant.auth0.com" 或 "https://tenant.auth0.com")
issuer: ""
# 界面配置
frontend:
# 评论框占位文字
placeholder: ""
@@ -285,7 +413,7 @@ frontend:
# 评论框穿梭
editorTravel: true
# 表情包
emoticons: "https://cdn.jsdelivr.net/gh/ArtalkJS/Emoticons/grps/default.json"
emoticons: https://cdn.jsdelivr.net/gh/ArtalkJS/Emoticons/grps/default.json
# 投票按钮
vote: true
# 反对按钮
@@ -294,14 +422,12 @@ frontend:
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"]
@@ -309,9 +435,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:
# 每页评论数
@@ -328,7 +454,11 @@ frontend:
children: 400
# 滚动限高 (允许限高区域滚动)
scrollable: false
# 图片懒加载 [false, "native", "data-src"]
imgLazyLoad: false
# 请求超时 (单位:毫秒)
reqTimeout: 15000
# 版本检测
versionCheck: true
# 插件
pluginURLs: []
+464
View File
@@ -0,0 +1,464 @@
# 伺服器地址
host: "0.0.0.0"
# 伺服器端口
port: 23366
# 加密密鑰
app_key: ""
# 偵錯模式
debug: false
# 語言 ["en", "zh-CN", "zh-TW", "ja", "fr", "ko", "ru"]
locale: zh-TW
# 時區
timezone: Asia/Taipei
# 預設站點名稱
site_default: 預設站點
# 預設站點地址
site_url: ""
# 登入有效時長 (單位:秒)
login_timeout: 259200
# 資料庫
db:
# 資料庫類型 ["sqlite", "mysql", "pgsql", "mssql"]
type: sqlite
# 資料庫文件 (僅 SQLite 資料庫需填寫)
file: ./data/artalk.db
# 資料庫名稱
name: artalk
# 資料庫地址
host: localhost
# 資料庫端口
port: 3306
# 資料庫帳號
user: root
# 資料庫密碼
password: ""
# 編碼格式
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
# 快取
cache:
# 啟用快取
enabled: false
# 快取類型 ["redis", "memcache", "builtin"]
type: builtin
# 快取過期時間 (單位:分鐘)
expires: 30
# 快取啟動預熱 (程式啟動時預熱快取)
warm_up: false
# 快取伺服器地址 (例如:"localhost:6379")
server: ""
# Redis 配置
redis:
# 連接方式 ["tcp", "unix"]
network: tcp
# 用戶名
username: ""
# 密碼
password: ""
# 資料庫編號 (例如使用零號資料庫填寫 0)
db: 0
# 可信網域
# -- 例如:["https://artalk.example.com:23366"] --
trusted_domains: []
# SSL
ssl:
# 啟用 SSL
enabled: false
# 憑證文件路徑
cert_path: ""
# 密鑰文件路徑
key_path: ""
# 管理員帳戶
# --
# - name: "admin"
# email: "admin@example.com"
# password: "" # 支持 bcrypt 或 md5 加密,如:"(bcrypt)$2y$10$ti4vZYIrxVN8rLcYXVgXCO.GJND0dyI49r7IoF3xqIx8bBRmIBZRm"
# badge_name: "管理員"
# badge_color: "#0083FF"
# --
admin_users: []
# 評論審核
moderator:
# 預設待審 (發表新評論需要後台人工審核後才能顯示)
pending_default: false
# API 請求錯誤時攔截 (關閉此項當請求錯誤時讓評論放行)
api_fail_block: false
# Akismet Key
# (Akismet 反垃圾服務,https://akismet.com)
akismet_key: ""
# 騰訊雲文本內容安全
# (https://cloud.tencent.com/document/product/1124/64508)
tencent:
enabled: false
secret_id: ""
secret_key: ""
region: ap-guangzhou
# 阿里雲內容安全
# (https://help.aliyun.com/document_detail/28417.html)
aliyun:
enabled: false
access_key_id: ""
access_key_secret: ""
region: cn-shanghai
# 關鍵詞過濾 (本地離線詞庫)
keywords:
enabled: false
# 匹配成功設為待審狀態
pending: false
# 詞庫文件 (支持多個詞庫文件)
files:
- ./data/詞庫_1.txt
# 詞庫文件內容分割符 (例如填寫 "\n" 文件中一行一個關鍵詞)
file_sep: "\n"
# 替換字符
replace_to: x
# 驗證碼
captcha:
# 啟用驗證碼
enabled: true
# 總是需要驗證碼
always: false
# 驗證類型 ["image", "turnstile", "recaptcha", "hcaptcha", "geetest"]
captcha_type: image
# 激活驗證碼所需操作次數
action_limit: 3
# 重置操作計數器超時 (單位:s, 設為 -1 不重置)
action_reset: 60
# Turnstile
# (https://www.cloudflare.com/products/turnstile/)
turnstile:
site_key: ""
secret_key: ""
# reCaptcha
# (https://www.google.com/recaptcha/about/)
recaptcha:
site_key: ""
secret_key: ""
# hCaptcha (https://www.hcaptcha.com/)
hcaptcha:
site_key: ""
secret_key: ""
# Geetest 極驗 (https://www.geetest.com)
geetest:
captcha_id: ""
captcha_key: ""
# IP 屬地
ip_region:
# 啟用 IP 屬地展示
enabled: false
# 數據文件路徑 (.xdb 格式)
db_path: ./data/ip2region.xdb
# 顯示精度 ["province", "city", "country"]
precision: province
# 圖片上傳
img_upload:
# 啟用圖片上傳
enabled: true
# 圖片存放路徑
path: ./data/artalk-img/
# 圖片大小限制 (單位:MB)
max_size: 5
# 圖片連結基礎路徑 (默認為 "/static/images/")
public_path: null
# Upgit 配置
# (使用 Upgit 將圖片上傳到 GitHub 或圖床:https://github.com/pluveto/upgit)
upgit:
# 啟用 Upgit
enabled: false
# 命令行參數
exec: upgit -c <upgit配置文件路徑> -t /artalk-img
# 上傳後刪除本地的圖片
del_local: true
# 郵件通知
email:
# 啟用郵件通知
enabled: false
# 發送方式 ["smtp", "ali_dm", "sendmail"]
send_type: smtp
# 發信人暱稱
send_name: "{{reply_nick}}"
# 發信人地址
send_addr: noreply@example.com
# 郵件標題
mail_subject: "[{{site_name}}] 您收到了來自 @{{reply_nick}} 的回覆"
# 郵件模板文件 (填入文件路徑使用自定義模板)
mail_tpl: default
# SMTP 發送 (啟用請將發送方式設為 "smtp")
smtp:
# 發件地址
host: smtp.qq.com
# 發件端口
port: 587
# 用戶名
username: example@qq.com
# 密碼
password: ""
# 阿里雲郵件推送
# (啟用請將發送方式設為 "ali_dm";參考:https://help.aliyun.com/document_detail/29444.html)
ali_dm:
access_key_id: ""
access_key_secret: ""
account_name: noreply@example.com
# 多元推送
admin_notify:
# 通知模板 (填入文件路徑使用自定義模板)
notify_tpl: default
# 待審評論仍然發送通知 (當評論被攔截時仍然發送通知)
notify_pending: false
# 嘈雜模式
noise_mode: false
# 郵件通知管理員
email:
# 開啟 (當使用其他推送方式時,可以關閉管理員郵件通知)
enabled: true
# 郵件標題 (發送給管理員的郵件標題)
mail_subject: "[{{site_name}}] 您的文章「{{page_title}}」有新回覆"
# 管理員郵件模板文件 (填入文件路徑使用自定義模板)
mail_tpl: ""
# Telegram
telegram:
enabled: false
api_token: ""
receivers:
- 7777777
# Bark
bark:
enabled: false
server: http://day.app/xxxxxxx/
# 飛書
lark:
enabled: false
webhook_url: ""
# 消息類型 ["text", "card"]
msg_type: "text"
# WebHook
webhook:
enabled: false
url: ""
# 釘釘
ding_talk:
enabled: false
token: ""
secret: ""
# Slack
slack:
enabled: false
oauth_token: ""
receivers:
- CHANNEL_ID
# LINE
line:
enabled: false
channel_secret: ""
channel_access_token: ""
receivers:
- 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: ""
# SSO (用外部 OIDC 身分提供商的存取權杖換取 Artalk 登入工作階段,透過呼叫 IdP 的 /userinfo 端點驗證)
# -- 當嵌入頁面已執行 OIDC 且希望 Artalk 沿用該登入狀態、不顯示自身彈窗登入介面時使用。 --
sso:
# 啟用 SSO 權杖交換
enabled: false
# OIDC issuer 位址 (如 "tenant.auth0.com" 或 "https://tenant.auth0.com")
issuer: ""
# 介面配置
frontend:
# 評論框占位文字
placeholder: ""
# 無評論顯示文字
noComment: ""
# 發送按鈕文字
sendBtn: ""
# 評論框穿梭
editorTravel: true
# 表情包
emoticons: https://cdn.jsdelivr.net/gh/ArtalkJS/Emoticons/grps/default.json
# 投票按鈕
vote: true
# 反對按鈕
voteDown: false
# 用戶 UA 徽章
uaBadge: false
# 評論排序功能
listSort: true
# 編輯器實時預覽功能
preview: true
# 平鋪模式 ["auto", true, false]
flatMode: auto
# 夜間模式 ["inherit", "auto"]
darkMode: inherit
# 最大嵌套層數
nestMax: 2
# 嵌套評論排序規則 ["DATE_ASC", "DATE_DESC", "VOTE_UP_DESC"]
nestSort: DATE_ASC
# 頭像 Gravatar
gravatar:
# API 地址
mirror: https://weavatar.com/avatar/
# API 參數
params: sha256=1&d=mp&s=240
# 評論分頁
pagination:
# 每頁評論數
pageSize: 20
# 加載更多模式 (關閉則使用分頁條)
readMore: true
# 滾動加載
autoLoad: true
# 內容限高
heightLimit:
# 評論內容限高 (單位:px)
content: 300
# 子評論區域限高 (單位:px)
children: 400
# 滾動限高 (允許限高區域滾動)
scrollable: false
# 圖片懶加載 [false, "native", "data-src"]
imgLazyLoad: false
# 請求超時 (單位:毫秒)
reqTimeout: 15000
# 版本檢測
versionCheck: true
# 插件
pluginURLs: []
+7 -1
View File
@@ -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
+2 -2
View File
@@ -14,11 +14,11 @@ if [ "$1" != 'gen' ] && ( [ ! -e /data/artalk.yml ] && [ ! -e /data/artalk-go.ym
upMsg+=$'# please unmount the config file volume from your container\n'
upMsg+=$'# and edit "/data/artalk.yml" for configuration.'
echo "$upMsg" > /conf.yml
echo "$(date) [info] Copy config file from '/conf.yml' to '/data/artalk.yml' for upgrade"
echo "$(date) [info][docker] Copy config file from '/conf.yml' to '/data/artalk.yml' for upgrade"
else
# Generate new config
artalk gen conf /data/artalk.yml
echo "$(date) [info] Generate new config file to '/data/artalk.yml'"
echo "$(date) [info][docker] Generate new config file to '/data/artalk.yml'"
fi
fi
-3
View File
@@ -1,3 +0,0 @@
/.vitepress/dist/
/.vitepress/cache/
/public/http-api.html
-2
View File
@@ -1,2 +0,0 @@
shamefully-hoist=true
auto-install-peers=true
-211
View File
@@ -1,211 +0,0 @@
import { defineConfig } from 'vitepress'
import iterator from 'markdown-it-for-inline'
import * as Version from '../code/ArtalkVersion.json'
export default defineConfig({
title: 'Artalk',
description: '一款简洁的自托管评论系统',
lang: 'zh-CN',
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' }],
],
lastUpdated: true,
markdown: {
// @link https://github.com/shikijs/shiki
theme: {
light: 'github-light',
dark: 'github-dark',
},
config: (md) => {
md.use(iterator, 'artalk_version', 'text', function (tokens, idx) {
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))
});
},
},
locales: {
root: {
label: '简体中文',
lang: 'zh'
},
en: {
label: 'English',
lang: 'en',
link: 'https://artalk-js-org.translate.goog/guide/intro?_x_tr_sl=auto&_x_tr_tl=en-US&_x_tr_hl=en-US&_x_tr_pto=wapp'
// link: '/en/'
}
},
themeConfig: {
sidebar: {
"/guide/": [
{
text: "快速开始",
collapsed: false,
items: [
{ text: '项目介绍', link: '/guide/intro.md' },
{ text: '程序部署', link: '/guide/deploy.md' },
{ text: '数据迁移', link: '/guide/transfer.md' },
]
},
{
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/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: "进阶指南",
collapsed: false,
items: [
{ text: '表情包', link: '/guide/frontend/emoticons.md' },
{ text: '浏览量统计', link: '/guide/frontend/pv.md' },
{ text: 'Latex', link: '/guide/frontend/latex.md' },
{ text: '图片灯箱', link: '/guide/frontend/lightbox.md' },
{ text: 'IP 归属地', link: '/guide/frontend/ip-region.md' },
{ text: '精简版本', link: '/guide/frontend/artalk-lite.md' },
{ text: '置入博客', link: '/guide/frontend/import-blog.md' },
{ text: '置入框架', link: '/guide/frontend/import-framework.md' },
{ text: '前端 API', link: '/develop/fe-api.md', },
{ text: '开发文档', link: '/develop/index.md', },
],
},
{
text: "配置文档",
collapsed: true,
items: [
{ text: '后端配置', link: '/guide/backend/config.md' },
{ text: '前端配置', link: '/guide/frontend/config.md' },
]
},
{
text: "部署说明",
collapsed: true,
items: [
{ text: '守护进程', link: '/guide/backend/daemon.md' },
{ text: '反向代理', link: '/guide/backend/reverse-proxy.md' },
{ text: '编译构建', link: '/guide/backend/build.md' },
{ text: '程序升级', link: '/guide/backend/update.md' },
{ text: 'Docker', link: '/guide/backend/docker.md' },
]
},
{
text: '更多内容',
collapsed: true,
items: [
{ text: '安全防范', link: '/guide/security.md' },
{ text: '扩展阅读', link: '/guide/extras.md' },
{ text: '案例展示', link: '/guide/cases.md' },
{ text: '关于我们', link: '/guide/about.md' },
]
}
],
"/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' },
]
}
]
},
nav: [
// NavbarItem
{
text: '介绍',
link: '/guide/intro',
},
{
text: '部署',
link: '/guide/deploy',
},
{
text: '配置',
link: '/guide/backend/config',
},
{
text: '迁移',
link: '/guide/transfer',
},
{
text: '案例',
link: '/guide/cases',
},
{
text: '开发',
link: '/develop/',
},
// NavbarGroup
{
text: '传送',
items: [
{
text: '代码仓库',
link: 'https://github.com/ArtalkJS/Artalk',
},
{
text: '文档镜像 (国内)',
link: 'https://artalk-docs.qwqaq.com'
}
],
},
],
socialLinks: [
{ icon: 'github', link: 'https://github.com/ArtalkJS/Artalk' }
],
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: '完善文档'
},
}
})
-95
View File
@@ -1,95 +0,0 @@
<template>
<ClientOnly>
<div ref="el" style="margin-top: 20px;"></div>
</ClientOnly>
</template>
<script setup lang="ts">
import { watch, nextTick, ref, onMounted, onUnmounted } from 'vue'
import { useData, useRouter } from 'vitepress'
import type Artalk from 'artalk'
const el = ref<HTMLElement | null>(null)
const router = useRouter()
const page = useData().page
let artalk: Artalk
onMounted(() => {
initArtalk(getConfByPage())
})
watch(() => router.route.data.relativePath, () => {
nextTick(() => {
artalk.update(getConfByPage())
artalk.reload()
})
})
onUnmounted(() => {
artalk.destroy()
})
function initArtalk(conf: any) {
import('artalk').then(({ default: Artalk }) => {
artalk = Artalk.init({
el: el.value,
emoticons: '/assets/emoticons/default.json',
gravatar: {
mirror: 'https://cravatar.cn/avatar/'
},
...conf
})
}).then(() => {
loadExtraFuncs()
})
}
function getConfByPage() {
return {
pageKey: 'https://artalk.js.org'+location.pathname,
pageTitle: page.value.title,
server: 'https://artalk.qwqaq.com',
site: 'ArtalkDocs',
}
}
function loadExtraFuncs() {
// 图片灯箱插件
artalk.on('list-loaded', () => {
document.querySelectorAll('.atk-comment .atk-content').forEach(($content) => {
const imgEls = $content.querySelectorAll<HTMLImageElement>('img:not([atk-emoticon]):not([atk-lightbox])');
imgEls.forEach((imgEl) => {
imgEl.setAttribute('atk-lightbox', '')
const linkEl = document.createElement('a')
linkEl.setAttribute('class', 'atk-img-link')
linkEl.setAttribute('href', imgEl.src)
linkEl.setAttribute('data-src', imgEl.src)
linkEl.append(imgEl.cloneNode())
imgEl.replaceWith(linkEl)
})
// @ts-ignore
if (imgEls.length) lightGallery($content, { selector: '.atk-img-link' })
})
})
// 夜间模式
const darkMode = document.querySelector('html').classList.contains('dark')
artalk.setDarkMode(darkMode)
new MutationObserver((mList) => {
mList.forEach((m) => {
if (m.attributeName !== 'class') return
// @ts-ignore
const darkMode = m.target.classList.contains('dark')
artalk.setDarkMode(darkMode)
})
}).observe(document.querySelector('html'), { attributes: true })
}
</script>
<style>
</style>
-18
View File
@@ -1,18 +0,0 @@
<script setup>
import DefaultTheme from 'vitepress/theme'
import { onMounted } from 'vue'
import './style.scss'
const { Layout } = DefaultTheme
onMounted(() => {
})
</script>
<template>
<Layout>
<template #doc-after>
<Artalk />
</template>
</Layout>
</template>
-5
View File
@@ -1,5 +0,0 @@
declare module '*.vue' {
import { defineComponent } from 'vue';
const component: ReturnType<typeof defineComponent>;
export default component;
}
-3
View File
@@ -1,3 +0,0 @@
{
"latest": "2.7.1"
}
-592
View File
@@ -1,592 +0,0 @@
# HTTP API
::: warning
该 HTTP API 文档已过时
:::
::: tip 无特殊说明时 API 调用响应格式
| 字段名 | 类型 | 说明 |
| ----- | ------- | --- |
| `success` | Boolean | 接口调用结果 |
| `msg` | String | 返回消息,出错时此字段包含错误消息 |
| `data` | Any | 返回数据,可能为 Object / String / Array 类型 |
:::
## Normal API
### 评论新增
**POST** `/api/add`
**参数**
| 字段名 | 数据类型 | 必需 | 说明 |
| ----- | ------- | :---: | --- |
| `name` | String | 是 | 待新增评论者昵称 |
| `email` | String | 是 | 待新增评论者邮箱 |
| `link` | String | 否 | 待新增评论者链接 |
| `content` | String | 是 | 待新增评论内容 |
| `rid` | Number | 否 | 待新增评论为回复评论时传入父评论 `ID`,否则为 `0` |
| `page_key` | String | 是 | 待新增评论目标页面唯一标识符 |
| `page_title` | String | 否 | 待新增评论目标页面标题 |
| `token` | String | 否 | 评论请求 Token |
| `site_name` | String | 否 | 待新增评论目标站点名称 |
**响应**
| 字段名 | 数据类型 | 默认 | 说明 |
| ----- | ------- | :-: | --- |
| `success` | Boolean | `true` | 评论新增成功 |
| `data.comment` | Object | - | 评论数据 |
| `data.comment.id` | Number | - | 评论 ID |
| `data.comment.content` | String | - | 评论正文 |
| `data.comment.nick` | String | - | 评论者昵称 |
| `data.comment.email_encrypted` | String | - | 评论者邮箱 MD5 加密值 |
| `data.comment.link` | String | - | 评论者链接 |
| `data.comment.ua` | String | - | 评论者 User-Agent |
| `data.comment.date` | String | - | 评论时间,格式为 `1970-01-01 00:00:00` |
| `data.comment.is_collapsed` | Boolean | - | 评论是否折叠 |
| `data.comment.is_pending` | Boolean | - | 评论是否待审 |
| `data.comment.is_allow_reply` | Boolean | - | 评论是否允许回复 |
| `data.comment.rid` | Number | `0` | 待新增评论为回复评论时返回父评论 `ID` |
| `data.comment.badge_name` | String | - | 评论者徽章文字 |
| `data.comment.badge_color` | String | - | 评论者徽章颜色 |
| `data.comment.visible` | Boolean | `true` | 评论是否可见 |
| `data.comment.vote_up` | Number | `0` | 评论赞同数 |
| `data.comment.vote_down` | Number | `0` | 评论反对数 |
| `data.comment.page_key` | String | - | 评论所在页面唯一标识符 |
| `data.comment.site_name` | String | - | 评论所在站点名称 |
### 评论获取
**POST** `/api/get`
**参数**
| 字段名 | 数据类型 | 必需 | 说明 |
| ----- | ------- | :---: | --- |
| `page_key` | String | 是 | 待获取评论页面的唯一标识符 |
| `limit` | Number | 否 | 待获取评论的数量限制 |
| `offset` | Number | 否 | 待获取评论的起始位置偏移 |
| `type` | String | 否 | 获取指定类型的评论 |
| `name` | String | 否 | 获取指定昵称的评论 |
| `email` | String | 否 | 获取指定邮箱的评论 |
| `site_name` | String | 否 | 获取指定站点名称的评论 |
| `flat_mode` | Boolean | 否 | 待获取评论是否平铺模式 |
**响应**
| 字段名 | 数据类型 | 默认 | 说明 |
| ----- | ------- | :-: | --- |
| `success` | Boolean | `true` | 评论获取成功 |
| `data.comments` | Array | - | 页面评论数据 |
| `data.total` | Number | - | 页面评论总数(包括所有子评论) |
| `data.total_parents` | Number | - | 页面评论中父级评论总数 |
| `data.page` | Object | - | 页面数据 |
| `data.page.id` | Number | - | 页面 ID |
| `data.page.admin_only` | Boolean | - | 页面是否仅管理员可评论 |
| `data.page.key` | String | - | 页面唯一标识符 |
| `data.page.url` | String | - | 页面链接 |
| `data.page.title` | String | - | 页面标题 |
| `data.page.site_name` | String | - | 页面所在站点名称 |
| `data.page.vote_up` | Number | - | 页面赞同数 |
| `data.page.vote_down` | Number | - | 页面反对数 |
| `data.unread` | Array | - | 未读的评论提醒数据 |
| `data.unread_count` | Number | - | 未读的评论提醒数据总数 |
| `data.api_version` | Object | - | 目标 Artalk 后端版本数据 |
::: tip
- `data.comments` 数组中元素结构参考 [评论新增接口](#评论新增) `/api/add` 响应的 `data.comment`
- `data.unread` 数组中元素结构如下
| 字段名 | 数据类型 | 默认 | 说明 |
| ----- | ------- | :-: | --- |
| `id` | Number | - | 评论提醒 ID |
| `user_id` | Number | - | 评论提醒目标用户 ID |
| `comment_id` | Number | - | 评论提醒来源评论 ID |
| `is_read` | Boolean | - | 评论提醒是否已读 |
| `is_emailed` | Boolean | - | 评论提醒是否已发送邮件 |
| `read_link` | String | - | 评论提醒已读地址 |
- `data.api_version` 对象结构参考 [Artalk 版本接口](#artalk-版本) `/api/version` 响应
:::
### 用户获取
**POST** `/api/user-get`
**参数**
| 字段名 | 数据类型 | 必需 | 说明 |
| ----- | ------- | :---: | --- |
| `name` | String | 否 | 待获取用户的昵称 |
| `email` | String | 否 | 待获取用户的邮箱 |
**响应**
| 字段名 | 数据类型 | 默认 | 说明 |
| ----- | ------- | :-: | --- |
| `success` | Boolean | `true` | 用户获取成功 |
| `data.user` | Object | `null` | 获取的用户数据,若用户不存在返回空 |
| `data.user.id` | Number | - | 用户 ID |
| `data.user.name` | String | - | 用户昵称 |
| `data.user.email` | String | - | 用户邮箱 |
| `data.user.link` | String | - | 用户链接 |
| `data.user.badge_name` | String | - | 用户徽章文字 |
| `data.user.badge_color` | String | - | 用户徽章颜色 |
| `data.user.is_admin` | Boolean | - | 用户是否管理员 |
| `data.is_login` | Boolean | - | 用户是否登录 |
| `data.unread` | Array | `[]` | 用户未读的评论提醒数据 |
| `data.unread_count` | Number | `0` | 用户未读的评论提醒数据总数 |
::: tip
- `data.unread` 数组中元素结构参考 [评论获取接口](#评论获取) `/api/get` **TIP**
:::
### 用户登录
**GET/POST** `/api/login`
**参数**
| 字段名 | 数据类型 | 必需 | 说明 |
| ----- | ------- | :---: | --- |
| `name` | String | 是 | 待登录用户的昵称 |
| `email` | String | 是 | 待登录用户的邮箱 |
| `password` | String | 是 | 待登录用户的密码(管理员身份验证) |
**响应**
| 字段名 | 数据类型 | 默认 | 说明 |
| ----- | ------- | :-: | --- |
| `success` | Boolean | `true` | 用户登录成功 |
| `data.token` | String | - | 登录的用户 Token |
### 提醒已读
**POST** `/api/mark-read`
**参数**
| 字段名 | 数据类型 | 必需 | 说明 |
| ----- | ------- | :---: | --- |
| `notify_key` | String | 否 | 评论提醒唯一标识符 |
| `name` | String | 否 | 评论提醒用户的昵称 |
| `email` | String | 否 | 评论提醒用户的邮箱 |
| `all_read` | Boolean | 否 | 评论提醒是否已读 |
| `site_name` | String | 否 | 评论提醒所在站点名称 |
**响应**
| 字段名 | 数据类型 | 默认 | 说明 |
| ----- | ------- | :-: | --- |
| `success` | Boolean | `true` | 提醒已读成功 |
### 评论投票
**POST** `/api/vote`
**参数**
| 字段名 | 数据类型 | 必需 | 说明 |
| ----- | ------- | :---: | --- |
| `target_id` | Number | 是 | 待投票评论 ID |
| `type` | String | 否 | 待投票类型,前缀 `comment_`、`page_` 依次代表对评论投票、对页面投票,后缀 `_up`、`_down` 依次代表赞同、反对 |
| `name` | String | 否 | 投票用户昵称 |
| `email` | String | 否 | 投票用户邮箱 |
| `site_name` | String | 否 | 投票目标评论或页面所在站点名称 |
**响应**
| 字段名 | 数据类型 | 默认 | 说明 |
| ----- | ------- | :-: | --- |
| `success` | Boolean | `true` | 评论投票成功 |
| `data.vote_num` | Number | - | 目标评论或页面指定类型投票数据 |
### Artalk 版本
::: warning
此接口较特殊,返回结果不包含 `success`、`msg`、`data` 字段,直接返回包含指定字段的 JSON。
:::
**GET/POST** `/api/version`
**参数** 无
**响应**
| 字段名 | 数据类型 | 默认 | 说明 |
| ----- | ------- | :-: | --- |
| `app` | String | `artalk` | Artalk 后端程序名 |
| `version` | String | - | Artalk 后端程序版本号 |
| `commit_hash` | String | - | Artalk 后端程序 Git 提交哈希值 |
| `fe_min_version` | String | - | Artalk 后端程序所需前端最低版本 |
## Captcha API
### 验证码刷新
**GET** `/api/captcha/refresh`
**参数** 无
**响应**
| 字段名 | 数据类型 | 默认 | 说明 |
| ----- | ------- | :-: | --- |
| `success` | Boolean | `true` | 验证码刷新成功 |
| `data.img_data` | String | - | 根据 IP 获取的验证码图片 Base64 编码 |
### 验证码检验
**GET** `/api/captcha/check`
**参数**
| 字段名 | 数据类型 | 必需 | 说明 |
| ----- | ------- | :---: | --- |
| `value` | String | 是 | 验证码 |
**响应**
| 字段名 | 数据类型 | 默认 | 说明 |
| ----- | ------- | :-: | --- |
| `success` | Boolean | `true` | 验证码检验成功 |
| `data.img_data` | String | - | 新的验证码图片 Base64 编码,仅验证码检验出错时存在此字段 |
## Admin API
### 评论编辑
**POST** `/api/admin/comment-edit`
**参数**
| 字段名 | 数据类型 | 必需 | 说明 |
| ----- | ------- | :---: | --- |
| `id` | Number | 是 | 待编辑评论 ID,**不可修改** |
| `site_name` | String | 否 | 待编辑评论所在站点名称,**不可修改** |
| `content` | String | 否 | 待编辑评论正文 |
| `page_key` | String | 否 | 待编辑评论所在页面唯一标识符 |
| `nick` | String | 否 | 待编辑评论所属用户昵称 |
| `email` | String | 否 | 待编辑评论所属用户邮箱 |
| `link` | String | 否 | 待编辑评论所属用户链接 |
| `rid` | String | 否 | 待编辑评论为回复评论时传入父评论 `ID`,否则为 `0` |
| `ua` | String | 否 | 待编辑评论所属用户 User-Agent |
| `ip` | String | 否 | 待编辑评论所属用户 IP |
| `is_collapsed` | Boolean | 否 | 待编辑评论是否折叠 |
| `is_pending` | Boolean | 否 | 待编辑评论是否待审 |
**响应**
| 字段名 | 数据类型 | 默认 | 说明 |
| ----- | ------- | :-: | --- |
| `success` | Boolean | `true` | 评论编辑成功 |
| `data.comment` | Object | - | 编辑评论的新数据 |
::: tip
- `data.comment` 对象结构参考 [评论新增接口](#评论新增) `/api/add` 响应的 `data.comment`
:::
### 评论删除
::: danger
此接口不推荐外部调用。
调用此接口前请务必核实评论 ID,一旦调用成功将删除该评论下所有相关数据。
:::
**POST** `/api/admin/comment-del`
**参数**
| 字段名 | 数据类型 | 必需 | 说明 |
| ----- | ------- | :---: | --- |
| `id` | Number | 是 | 待删除评论 ID |
| `site_name` | String | 是 | 待删除评论所在站点名称 |
**响应**
| 字段名 | 数据类型 | 默认 | 说明 |
| ----- | ------- | :-: | --- |
| `success` | Boolean | `true` | 评论删除成功 |
### 页面获取
**POST** `/api/admin/page-get`
**参数**
| 字段名 | 数据类型 | 必需 | 说明 |
| ----- | ------- | :---: | --- |
| `site_name` | String | 是 | 待获取页面目标站点名称 |
**响应**
| 字段名 | 数据类型 | 默认 | 说明 |
| ----- | ------- | :-: | --- |
| `success` | Boolean | `true` | 页面获取成功 |
| `data.pages` | Array | - | 目标站点的页面数据 |
| `data.sites` | Array | - | 所有站点数据 |
::: tip
- `data.pages` 数组中元素结构参考 [评论获取接口](#评论获取) `/api/get` 响应的 `data.page`
- `data.sites` 数组中元素结构参考 [站点编辑接口](#站点编辑) `/api/admin/site-edit` 响应的 `data.site`
:::
### 页面编辑
**POST** `/api/admin/page-edit`
**参数**
| 字段名 | 数据类型 | 必需 | 说明 |
| ----- | ------- | :---: | --- |
| `id` | Number | 是 | 待编辑页面 ID,**不可修改** |
| `site_name` | String | 否 | 待编辑页面所在站点名称,**不可修改** |
| `key` | String | 否 | 待编辑页面唯一标识符 |
| `title` | String | 否 | 待编辑页面标题 |
| `admin_only` | Boolean | 否 | 待编辑页面是否仅管理员可评论 |
**响应**
| 字段名 | 数据类型 | 默认 | 说明 |
| ----- | ------- | :-: | --- |
| `success` | Boolean | `true` | 页面编辑成功 |
| `data.page` | Object | - | 编辑页面的新数据 |
::: tip
- `data.page` 对象结构参考 [评论获取接口](#评论获取) `/api/get` 响应的 `data.page`
:::
### 页面删除
::: danger
此接口不推荐外部调用。
调用此接口前请务必核实页面 ID,一旦调用成功将删除该页面下所有相关数据。
:::
**POST** `/api/admin/page-del`
**参数**
| 字段名 | 数据类型 | 必需 | 说明 |
| ----- | ------- | :---: | --- |
| `key` | String | 是 | 待删除页面唯一标识符 |
| `site_name` | String | 是 | 待删除页面所在站点名称 |
**响应**
| 字段名 | 数据类型 | 默认 | 说明 |
| ----- | ------- | :-: | --- |
| `success` | Boolean | `true` | 页面删除成功 |
### 页面更新
**POST** `/api/admin/page-fetch`
**参数**
| 字段名 | 数据类型 | 必需 | 说明 |
| ----- | ------- | :---: | --- |
| `id` | Number | 是 | 待更新页面 ID |
**响应**
| 字段名 | 数据类型 | 默认 | 说明 |
| ----- | ------- | :-: | --- |
| `success` | Boolean | `true` | 页面更新成功 |
| `data.page` | Object | - | 更新页面的新数据 |
::: tip
- `data.page` 对象结构参考 [评论获取接口](#评论获取) `/api/get` 响应的 `data.page`
:::
### 站点获取
**POST** `/api/admin/site-get`
**参数** 无
**响应**
| 字段名 | 数据类型 | 默认 | 说明 |
| ----- | ------- | :-: | --- |
| `success` | Boolean | `true` | 站点获取成功 |
| `data.sites` | Array | - | 所有站点数据 |
::: tip
- `data.sites` 数组中元素结构参考 [站点编辑接口](#站点编辑) `/api/admin/site-edit` 响应的 `data.site`
:::
### 站点新增
**POST** `/api/admin/site-add`
**参数**
| 字段名 | 数据类型 | 必需 | 说明 |
| ----- | ------- | :---: | --- |
| `name` | String | 是 | 待新增站点名称 |
| `urls` | String | 是 | 待新增站点链接,如有多个需以英文半角符号 `,` 分割 |
**响应**
| 字段名 | 数据类型 | 默认 | 说明 |
| ----- | ------- | :-: | --- |
| `success` | Boolean | `true` | 站点新增成功 |
| `data.site` | Object | - | 新增站点的数据 |
| `data.site.id` | Number | - | 站点 ID |
| `data.site.name` | String | - | 站点名称 |
| `data.site.urls` | Array | - | 站点链接数组,元素为单个站点链接字符串 |
| `data.site.urls_raw` | String | - | 站点链接数组合并字符串,以英文半角符号 `,` 分割 |
| `data.site.first_url` | String | - | 站点第一链接 |
### 站点编辑
**POST** `/api/admin/site-edit`
**参数**
| 字段名 | 数据类型 | 必需 | 说明 |
| ----- | ------- | :---: | --- |
| `id` | Number | 是 | 待编辑站点 ID |
| `name` | String | 是 | 待编辑站点新名称 |
| `urls` | String | 是 | 待编辑站点新链接 |
**响应**
| 字段名 | 数据类型 | 默认 | 说明 |
| ----- | ------- | :-: | --- |
| `success` | Boolean | `true` | 站点编辑成功 |
| `data.site` | Object | - | 编辑站点的新数据 |
| `data.site.id` | Number | - | 站点 ID |
| `data.site.name` | String | - | 站点名称 |
| `data.site.urls` | Array | - | 站点链接数组,元素为单个站点链接字符串 |
| `data.site.urls_raw` | String | - | 站点链接数组合并字符串,以英文半角符号 `,` 分割 |
| `data.site.first_url` | String | - | 站点第一链接 |
### 站点删除
::: danger
此接口不推荐外部调用。
调用此接口前请务必核实站点 ID,一旦调用成功将删除该站点下所有相关数据。
:::
**POST** `/api/admin/site-del`
**参数**
| 字段名 | 数据类型 | 必需 | 说明 |
| ----- | ------- | :---: | --- |
| `id` | Number | 是 | 待删除站点 ID |
| `del_content` | Boolean | 否 | 是否删除站点所有数据,为 `false` 时仅删除站点配置而保留站点评论数据 |
**响应**
| 字段名 | 数据类型 | 默认 | 说明 |
| ----- | ------- | :-: | --- |
| `success` | Boolean | `true` | 站点删除成功 |
### 设置获取
**POST** `/api/admin/setting-get`
**参数**
| 字段名 | 数据类型 | 必需 | 说明 |
| ----- | ------- | :---: | --- |
| `id` | Number | 是 | 管理员用户 ID |
| `name` | String | 否 | 管理员用户昵称 |
| `url` | String | 否 | 管理员用户链接 |
**响应**
| 字段名 | 数据类型 | 默认 | 说明 |
| ----- | ------- | :-: | --- |
| `success` | Boolean | `true` | 设置获取成功 |
### 设置保存
**POST** `/api/admin/setting-save`
**参数**
| 字段名 | 数据类型 | 必需 | 说明 |
| ----- | ------- | :---: | --- |
| `id` | Number | 是 | 管理员用户 ID |
| `name` | String | 否 | 管理员用户昵称 |
| `url` | String | 否 | 管理员用户链接 |
**响应**
| 字段名 | 数据类型 | 默认 | 说明 |
| ----- | ------- | :-: | --- |
| `success` | Boolean | `true` | 设置保存成功 |
### 邮件发送
::: warning
页面收到评论、评论收到回复等满足需要发送邮件提醒条件时,后端将自动向目标地址发送邮件提醒,不需手动处理邮件发送。请勿滥用此接口。
:::
**POST** `/api/admin/send-mail`
**参数**
| 字段名 | 数据类型 | 必需 | 说明 |
| ----- | ------- | :---: | --- |
| `subject` | String | 是 | 邮件主题 |
| `body` | String | 是 | 邮件正文 |
| `to_addr` | String | 是 | 邮件收件人 |
**响应**
| 字段名 | 数据类型 | 默认 | 说明 |
| ----- | ------- | :-: | --- |
| `success` | Boolean | `true` | 邮件发送成功 |
### Artrans 接口
::: warning
此接口暂不稳定,请避免使用!
:::
**POST** `/api/admin/artransfer`
**参数**
| 字段名 | 数据类型 | 必需 | 说明 |
| ----- | ------- | :---: | --- |
| `type` | String | 是 | 导入数据类型 |
| `payload` | String | 否 | 导入数据 |
**响应** 无
-3
View File
@@ -1,3 +0,0 @@
# HTTP API
参考:<a href="/http-api.html" target="_blank">Artalk API 文档 (OpenAPI)</a>
-50
View File
@@ -1,50 +0,0 @@
# Event
## 基本事件
|事件名|描述|
|-|-|
| `inited` | 初始化后 |
| `destroy` | 实例销毁时 |
| `list-fetch` | 评论列表请求时 |
| `list-fetched` | 评论列表请求后 |
| `list-load` | 评论装载前 |
| `list-loaded` | 评论装载后 |
| `list-error` | 评论加载错误时 |
| `list-goto-first` | 评论列表归位时 |
| `list-reach-bottom` | 评论列表滚动到底部时 |
| `list-reach-bottom` | 评论列表滚动到底部时 |
| `comment-inserted` | 评论插入后 |
| `comment-updated` | 评论更新后 |
| `comment-deleted` | 评论删除后 |
| `comment-rendered` | 评论节点渲染后 |
| `unreads-updated` | 未读消息变更时 |
| `list-goto` | 评论跳转时 |
| `page-loaded` | 页面数据更新后 |
| `editor-submit` | 编辑器提交时 |
| `editor-submitted` | 编辑器提交后 |
| `user-changed` | 本地用户数据变更时 |
| `conf-loaded` | 配置变更时 |
| `dark-mode-changed` | 深色模式变更时 |
| `sidebar-show` | 侧边栏显示 |
| `sidebar-hide` | 侧边栏隐藏 |
事件声明代码:[@ArtalkJS/Artalk - types/event.ts](https://github.com/ArtalkJS/Artalk/blob/master/ui/packages/artalk/types/event.ts)
## 添加事件监听
```js
artalk.on('list-loaded', () => {
alert('评论已加载完毕')
})
```
## 解除事件监听
```js
let foo = function() { /* do something */ }
artalk.on('list-loaded', foo)
artalk.off('list-loaded', foo)
```
-28
View File
@@ -1,28 +0,0 @@
# 开发说明
## 参考资源
📖 <a href="https://github.com/ArtalkJS/Artalk/blob/master/CONTRIBUTING.md" target="_blank">开发者贡献指南 (CONTRIBUTING.md)</a>
🔬 <a href="/http-api.html" target="_blank">HTTP API 文档 (OpenAPI)</a>
🔖 <a href="https://github.com/ArtalkJS/Artalk/blob/master/CODE_OF_CONDUCT.md" target="_blank">贡献者契约行为准则 (CODE_OF_CONDUCT.md)</a>
## 配置文档
- [后端配置](../guide/backend/config.md)
- [前端配置](../guide/frontend/config.md)
## 补充说明
由于 Artalk 正处于开发阶段,使用此文档中 `API`、`Event` 前请务必检查时效性。
- `API` 部分参考源码
* [@ArtalkJS/Artalk - src/api/](https://github.com/ArtalkJS/Artalk/tree/master/ui/packages/artalk/src/api)
* [@ArtalkJS/Artalk - server/server.go](https://github.com/ArtalkJS/Artalk/blob/master/server/server.go)
- `UI` 及 `Event` 部分参考源码
* [@ArtalkJS/Artalk - src/artalk.ts](https://github.com/ArtalkJS/Artalk/blob/master/ui/packages/artalk/src/artalk.ts)
* [@ArtalkJS/Artalk - types/event.ts](https://github.com/ArtalkJS/Artalk/blob/master/ui/packages/artalk/types/event.ts)
通过 Artalk 提供的 `API` 和 `Event`,你可以实现很多高级功能,比如编写评论管理机器人、评论提醒推送插件等。Artalk 并不为此提供技术指导,但鼓励你参考此处的文档自行定制。
-64
View File
@@ -1,64 +0,0 @@
# 插件开发
使用 `Artalk.use` 来扩展 Artalk。
```js
import Artalk from 'artalk'
Artalk.use((ctx) => {
ctx.on('inited', () => {
ctx.get('editor').setContent("Hello World")
})
ctx.on('list-loaded', () => {
console.log('评论列表加载完毕')
})
})
const artalk = Artalk.init({ ... })
```
请注意:
- `Artalk.use` 必须在 `Artalk.init` 之前调用。
- 请勿依赖插件的加载顺序,请监听事件来执行插件逻辑。
- 当所有的插件加载完毕后,会触发 `inited` 事件。
在 use 函数中,你可以通过 `ctx` 来访问 Artalk 的上下文。
## Context
Context 对象包含了 Artalk 的上下文信息。
| 成员 | 说明 |
| --- | --- |
| `ctx.$root` | Artalk 容器元素 |
| `ctx.conf` | Artalk 配置 |
| `ctx.fetch` | 加载数据数据 |
| `ctx.reload` | 重载评论列表 |
| `ctx.on` | 添加事件监听 |
| `ctx.off` | 解除事件监听 |
| `ctx.trigger` | 触发事件 |
| `ctx.inject` | 依赖注入 |
| `ctx.get` | 获取依赖 |
::: warning
Context API 目前仍不稳定,开发可能会有变动,升级请关注 CHANGELOG。
:::
参考:[@artalk/types/context.ts](https://github.com/ArtalkJS/Artalk/blob/master/ui/packages/artalk/types/context.ts)
Artalk 拥有完整的 TypeScript 类型定义,你可以通过编辑器的自动补全来查看 API。
## 示例插件
Artalk 有很多内置的插件,你可以参考它们的源码来开发自己的插件。
[@ArtalkJS/Artalk - src/plugins](https://github.com/ArtalkJS/Artalk/tree/master/ui/packages/artalk/src/plugins)
我们还提供了一些外置的插件,同样可以参考:
| 插件 | 说明 |
| --- | --- |
| [@artalk/plugin-katex](https://github.com/ArtalkJS/Artalk/tree/master/ui/packages/plugin-katex) | LaTeX 公式插件 |
| [@artalk/plugin-lightbox](https://github.com/ArtalkJS/Artalk/tree/master/ui/packages/plugin-lightbox) | 图片灯箱插件 |
+3
View File
@@ -0,0 +1,3 @@
.vitepress/dist/**
.vitepress/cache/**
.vitepress/.temp/**
+127
View File
@@ -0,0 +1,127 @@
import { defineConfig } from 'vitepress'
export const en = defineConfig({
lang: 'en-US',
description: 'A Self-hosted Comment System.',
themeConfig: {
sidebar: {
'/en/guide/': [
{
text: 'Quick Start',
collapsed: false,
items: [
{ text: 'Introduction', link: '/en/guide/intro.md' },
{ text: 'Getting Started', link: '/en/guide/deploy.md' },
{ text: 'Data Migration', link: '/en/guide/transfer.md' },
],
},
{
text: 'Basic Usage',
collapsed: false,
items: [
{ text: 'Sidebar', link: '/en/guide/frontend/sidebar.md' },
{ text: 'Email Notification', link: '/en/guide/backend/email.md' },
{ text: 'Multi-channel Notification', link: '/en/guide/backend/admin_notify.md' },
{ text: 'Social Login', link: '/en/guide/frontend/auth.md' },
{ text: 'Comment Moderation', link: '/en/guide/backend/moderator.md' },
{ text: 'Captcha', link: '/en/guide/backend/captcha.md' },
{ text: 'Image Upload', link: '/en/guide/backend/img-upload.md' },
{ text: 'Admins and Multi-Site', link: '/en/guide/backend/multi-site.md' },
{ text: 'Resolve Relative Path', link: '/en/guide/backend/relative-path.md' },
],
},
{
text: 'Extensions',
collapsed: false,
items: [
{ text: 'Emoticons', link: '/en/guide/frontend/emoticons.md' },
{ text: 'Page View Statistics', link: '/en/guide/frontend/pv.md' },
{ text: 'LaTeX', link: '/en/guide/frontend/latex.md' },
{ text: 'Image Lightbox', link: '/en/guide/frontend/lightbox.md' },
{ text: 'Image Lazy Load', link: '/en/guide/frontend/img-lazy-load.md' },
{ text: 'Voting', link: '/zh/guide/frontend/voting.md' },
{ text: 'IP Region', link: '/en/guide/frontend/ip-region.md' },
{ text: 'Localization', link: '/en/guide/frontend/i18n.md' },
{ text: 'Development Documentation', link: '/en/develop/index.md' },
],
},
{
text: 'Configurations',
collapsed: false,
items: [
{ text: 'Environment Variables', link: '/en/guide/env.md' },
{ text: 'Configuration File', link: '/en/guide/backend/config.md' },
{ text: 'UI Configuration', link: '/en/guide/frontend/config.md' },
],
},
{
text: 'Deployment details',
collapsed: false,
items: [
{ text: 'Daemon Process', link: '/en/guide/backend/daemon.md' },
{ text: 'Reverse Proxy', link: '/en/guide/backend/reverse-proxy.md' },
{
text: 'Compile Source',
link: 'https://github.com/ArtalkJS/Artalk/blob/master/CONTRIBUTING.md',
},
{ text: 'Program Upgrade', link: '/en/guide/backend/update.md' },
{ text: 'Docker', link: '/en/guide/backend/docker.md' },
],
},
],
'/en/develop/': [
{
text: 'Development Documentation',
items: [
{ text: 'Development Instructions', link: '/en/develop/index.md' },
{
text: 'Contribution Guide',
link: 'https://github.com/ArtalkJS/Artalk/blob/master/CONTRIBUTING.md',
target: '_blank',
},
{ text: 'Import to Blog', link: '/en/develop/import-blog.md' },
{ text: 'Import to Framework', link: '/en/develop/import-framework.md' },
{ text: 'Frontend API', link: '/en/develop/fe-api.md' },
{ text: 'Frontend Events', link: '/en/develop/event.md' },
{ text: 'Frontend Types', link: 'https://artalk.js.org/typedoc/' },
{ text: 'Plugin Development', link: '/en/develop/plugin.md' },
{ text: 'Compatibility', link: '/en/develop/compatibility.md' },
{
text: 'HTTP API',
link: 'https://artalk.js.org/http-api.html',
},
],
},
],
},
nav: [
{
text: 'Introduction',
link: '/en/guide/intro',
},
{
text: 'Installation',
link: '/en/guide/deploy',
},
{
text: 'Configuration',
link: '/en/guide/backend/config',
},
{
text: 'Migration',
link: '/en/guide/transfer',
},
{
text: 'Development',
link: '/en/develop/',
},
],
editLink: {
pattern: 'https://github.com/ArtalkJS/Artalk/edit/master/docs/docs/:path',
text: 'Improve this document',
},
},
})
+12
View File
@@ -0,0 +1,12 @@
import { defineConfig } from 'vitepress'
import { shared } from './shared'
import { zh } from './zh'
import { en } from './en'
export default defineConfig({
...shared,
locales: {
en: { label: 'English', ...en },
zh: { label: '简体中文', ...zh },
},
})
+98
View File
@@ -0,0 +1,98 @@
import { defineConfig } from 'vitepress'
import {
GitChangelog,
GitChangelogMarkdownSection,
} from '@nolebase/vitepress-plugin-git-changelog/vite'
import * as Version from '../../code/ArtalkVersion.json'
export const shared = defineConfig({
title: 'Artalk',
/* prettier-ignore */
head: [
['link', { rel: 'icon', type: 'image/png', href: '/favicon.png' }],
['meta', { property: 'og:type', content: 'website' }],
['meta', { property: 'og:locale', content: 'en' }],
['meta', { property: 'og:title', content: 'Artalk - A Self-hosted Comment System'}],
['meta', { property: 'og:site_name', content: 'Artalk' }],
['meta', { property: 'og:image', content: 'https://artalk.js.org/assets/images/artalk-banner.png' }],
['meta', { property: 'og:url', content: 'https://artalk.js.org/' }],
['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' }],
],
markdown: {
// @link https://github.com/shikijs/shiki
theme: {
light: 'github-light',
dark: 'github-dark',
},
config: (md) => {
const renderVersion = (c: string) => String(c).replace(/:ArtalkVersion:/g, Version.latest)
md.core.ruler.push('artalk_version', (state) => {
state.tokens?.forEach((token) => {
if (token.type === 'inline') {
token.children?.forEach((child) => {
if (['text', 'link_open', 'code_inline'].includes(child.type))
child.content = renderVersion(child.content)
})
} else if (token.type === 'fence') {
token.content = renderVersion(token.content)
}
})
})
},
},
sitemap: {
hostname: 'https://artalk.js.org',
transformItems(items) {
return items.filter((item) => !item.url.includes('migration'))
},
},
lastUpdated: true,
cleanUrls: false,
metaChunk: true,
themeConfig: {
socialLinks: [{ icon: 'github', link: 'https://github.com/ArtalkJS/Artalk' }],
search: {
provider: 'algolia',
options: {
appId: '2WNJ32WVTY',
apiKey: '6c6ebc345a87b738264f19095b78c91c',
indexName: 'artalk-js',
},
},
},
vite: {
server: {
open: '/zh/guide/intro.html',
},
plugins: [
GitChangelog({
repoURL: () => 'https://github.com/ArtalkJS/Artalk',
mapAuthors: [
{
name: 'qwqcode',
username: 'qwqcode',
mapByEmailAliases: ['qwqcode@gmail.com', '22412567+qwqcode@users.noreply.github.com'],
},
{
name: 'pluveto',
username: 'pluveto',
mapByEmailAliases: ['i@pluvet.com', '50045289+pluveto@users.noreply.github.com'],
},
{
name: 'Mr.Hope',
username: 'Mister-Hope',
mapByEmailAliases: ['mister-hope@outlook.com'],
},
],
}),
GitChangelogMarkdownSection(),
],
},
})
+135
View File
@@ -0,0 +1,135 @@
import { defineConfig } from 'vitepress'
export const zh = defineConfig({
lang: 'zh-CN',
description: '由 Golang 驱动的自托管评论系统',
themeConfig: {
sidebar: {
'/zh/guide/': [
{
text: '快速开始',
collapsed: false,
items: [
{ text: '项目介绍', link: '/zh/guide/intro.md' },
{ text: '程序部署', link: '/zh/guide/deploy.md' },
{ text: '数据迁移', link: '/zh/guide/transfer.md' },
],
},
{
text: '核心指南',
collapsed: false,
items: [
{ text: '侧边栏', link: '/zh/guide/frontend/sidebar.md' },
{ text: '邮件通知', link: '/zh/guide/backend/email.md' },
{ text: '多元推送', link: '/zh/guide/backend/admin_notify.md' },
{ text: '社交登录', link: '/zh/guide/frontend/auth.md' },
{ text: '评论审核', link: '/zh/guide/backend/moderator.md' },
{ text: '验证码', link: '/zh/guide/backend/captcha.md' },
{ text: '图片上传', link: '/zh/guide/backend/img-upload.md' },
{ text: '账户与多站点', link: '/zh/guide/backend/multi-site.md' },
{ text: '解析相对路径', link: '/zh/guide/backend/relative-path.md' },
],
},
{
text: '进阶指南',
collapsed: false,
items: [
{ text: '表情包', link: '/zh/guide/frontend/emoticons.md' },
{ text: '浏览量统计', link: '/zh/guide/frontend/pv.md' },
{ text: 'LaTeX', link: '/zh/guide/frontend/latex.md' },
{ text: '图片灯箱', link: '/zh/guide/frontend/lightbox.md' },
{ text: '图片懒加载', link: '/zh/guide/frontend/img-lazy-load.md' },
{ text: '投票功能', link: '/zh/guide/frontend/voting.md' },
{ text: 'IP 属地', link: '/zh/guide/frontend/ip-region.md' },
{ text: '多语言', link: '/zh/guide/frontend/i18n.md' },
{ text: '开发文档', link: '/zh/develop/index.md' },
],
},
{
text: '配置文档',
collapsed: false,
items: [
{ text: '环境变量', link: '/zh/guide/env.md' },
{ text: '配置文件', link: '/zh/guide/backend/config.md' },
{ text: '界面配置', link: '/zh/guide/frontend/config.md' },
],
},
{
text: '部署说明',
collapsed: true,
items: [
{ text: '守护进程', link: '/zh/guide/backend/daemon.md' },
{ text: '反向代理', link: '/zh/guide/backend/reverse-proxy.md' },
{ text: '编译构建', link: '/zh/develop/contributing.md' },
{ text: '程序升级', link: '/zh/guide/backend/update.md' },
{ text: 'Docker', link: '/zh/guide/backend/docker.md' },
],
},
{
text: '更多内容',
collapsed: true,
items: [
{ text: '安全防范', link: '/zh/guide/security.md' },
{ text: '扩展阅读', link: '/zh/guide/extras.md' },
{ text: '案例展示', link: '/zh/guide/cases.md' },
{ text: '关于我们', link: '/zh/guide/about.md' },
],
},
],
'/zh/develop/': [
{
text: '开发文档',
items: [
{ text: '开发说明', link: '/zh/develop/index.md' },
{ text: '贡献指南', link: '/zh/develop/contributing.md' },
{ text: '置入博客', link: '/zh/develop/import-blog.md' },
{ text: '置入框架', link: '/zh/develop/import-framework.md' },
{ text: '前端 API', link: '/zh/develop/fe-api.md' },
{ text: '前端 Events', link: '/zh/develop/event.md' },
{ text: '前端 Types', link: 'https://artalk.js.org/typedoc/' },
{ text: '插件开发', link: '/zh/develop/plugin.md' },
{ text: '兼容性', link: '/zh/develop/compatibility.md' },
{
text: 'HTTP API',
link: 'https://artalk.js.org/http-api.html',
},
],
},
],
},
nav: [
// NavbarItem
{
text: '介绍',
link: '/zh/guide/intro',
},
{
text: '部署',
link: '/zh/guide/deploy',
},
{
text: '配置',
link: '/zh/guide/backend/config',
},
{
text: '迁移',
link: '/zh/guide/transfer',
},
{
text: '案例',
link: '/zh/guide/cases',
},
{
text: '开发',
link: '/zh/develop/',
},
],
editLink: {
pattern: 'https://github.com/ArtalkJS/Artalk/edit/master/docs/docs/:path',
text: '完善文档',
},
},
})
+93
View File
@@ -0,0 +1,93 @@
<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/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.use((ctx) => {
ctx.on('mounted', () => {
// TODO: Optimize the locale setting, which is overwritten by the remote server config
const locale = document.documentElement.lang.includes('zh') ? 'zh-CN' : 'en'
if (locale !== ctx.getConf().locale) ctx.updateConf({ locale })
})
})
artalk = Artalk.init({
el: el.value,
emoticons: '/assets/emoticons/default.json',
...conf,
})
loadExtraFuncs()
}
function getConfByPage() {
return {
pageKey: `https://artalk.js.org/${router.route.path
.replace(/^\/+/, '')
.replace(/^zh\//, '')
.replace(/\.html$/, '')}.html`,
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>
+22
View File
@@ -0,0 +1,22 @@
<script setup>
import DefaultTheme from 'vitepress/theme'
import { inBrowser, useData } from 'vitepress'
import { watchEffect } from 'vue'
import './style.scss'
const { Layout } = DefaultTheme
const { lang } = useData()
watchEffect(() => {
if (inBrowser)
document.cookie = `nf_lang=${lang.value}; expires=Mon, 1 Jan 2030 00:00:00 UTC; path=/`
})
</script>
<template>
<Layout>
<template #doc-after>
<Artalk />
</template>
</Layout>
</template>
File renamed without changes.
@@ -1,8 +1,11 @@
import DefaultTheme from 'vitepress/theme'
import { Theme } from 'vitepress'
import { NolebaseGitChangelogPlugin } from '@nolebase/vitepress-plugin-git-changelog/client'
import Layout from './Layout.vue'
import Artalk from './Artalk.vue'
import Artransfer from './Artransfer.vue'
import { Theme } from 'vitepress'
import '@nolebase/vitepress-plugin-git-changelog/client/style.css'
export default {
...DefaultTheme,
@@ -12,9 +15,10 @@ export default {
enhanceApp({ app, router, siteData }) {
app.component('Artransfer', Artransfer)
app.component('Artalk', Artalk)
app.use(NolebaseGitChangelogPlugin)
// app is the Vue 3 app instance from `createApp()`.
// router is VitePress' custom router. `siteData` is
// a `ref` of current site-level metadata.
}
},
} as Theme
@@ -8,7 +8,7 @@
--vp-c-divider: #dfe2e5;
--vp-home-hero-name-color: transparent;
--vp-home-hero-name-background: linear-gradient(90deg,#0083ff, #37dfd9);
--vp-home-hero-name-background: linear-gradient(90deg, #0083ff, #37dfd9);
}
.dark {
@@ -38,9 +38,9 @@
background-color: #0083ff;
&:hover {
border-color: #007CF0;
border-color: #007cf0;
color: #fff;
background-color: #007CF0;
background-color: #007cf0;
}
}
@@ -48,52 +48,52 @@
.wave {
display: inline-block;
transform-origin: center bottom;
animation:upAnimation 2.33s ease .8s 3 both;
animation: upAnimation 2.33s ease 0.8s 3 both;
}
@keyframes upAnimation {
0% {
transform: rotate(0deg);
transition-timing-function:cubic-bezier(0.215, .61, .355, 1);
transition-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1);
}
10% {
transform: rotate(-12deg);
transition-timing-function:cubic-bezier(0.215, .61, .355, 1);
transition-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1);
}
20% {
transform: rotate(12deg);
transition-timing-function:cubic-bezier(0.215, .61, .355, 1);
transition-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1);
}
28% {
transform: rotate(-10deg);
transition-timing-function:cubic-bezier(0.215, .61, .355, 1);
transition-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1);
}
36% {
transform: rotate(10deg);
transition-timing-function:cubic-bezier(0.755, .5, .855, .06);
transition-timing-function: cubic-bezier(0.755, 0.5, 0.855, 0.06);
}
42% {
transform: rotate(-8deg);
transition-timing-function:cubic-bezier(0.755, .5, .855, .06);
transition-timing-function: cubic-bezier(0.755, 0.5, 0.855, 0.06);
}
48% {
transform: rotate(8deg);
transition-timing-function:cubic-bezier(0.755, .5, .855, .06);
transition-timing-function: cubic-bezier(0.755, 0.5, 0.855, 0.06);
}
52% {
transform: rotate(-4deg);
transition-timing-function:cubic-bezier(0.755, .5, .855, .06);
transition-timing-function: cubic-bezier(0.755, 0.5, 0.855, 0.06);
}
56% {
transform: rotate(4deg);
transition-timing-function:cubic-bezier(0.755, .5, .855, .06);
transition-timing-function: cubic-bezier(0.755, 0.5, 0.855, 0.06);
}
60% {
transform: rotate(0deg);
transition-timing-function:cubic-bezier(0.755, .5, .855, .06);
transition-timing-function: cubic-bezier(0.755, 0.5, 0.855, 0.06);
}
100% {
transform: rotate(0deg);
transition-timing-function:cubic-bezier(0.215, .61, .355, 1);
transition-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1);
}
}
@@ -107,33 +107,38 @@ img[atk-emoticon] {
}
/* 由于 body 未添加一致的 transition,导致其他地方暗黑模式切换加 transition 比较怪 */
.vp-doc div[class*='language-'] { transition: none; }
.vp-doc :not(pre) > code { transition: none; }
.vp-doc div[class*='language-'] {
transition: none;
}
.vp-doc :not(pre) > code {
transition: none;
}
.vp-doc {
table {
border-collapse: collapse;
margin: 1rem 0;
display: block;
overflow-x: auto
overflow-x: auto;
}
td,th {
padding: .6em 1em;
td,
th {
padding: 0.6em 1em;
}
}
/* 侧边栏 */
.VPSidebar::-webkit-scrollbar {
width: 7px
width: 7px;
}
.VPSidebar::-webkit-scrollbar-track {
background-color: transparent
background-color: transparent;
}
.VPSidebar::-webkit-scrollbar-thumb {
background-color: var(--vp-c-divider)
background-color: var(--vp-c-divider);
}
// details block patch
@@ -146,5 +151,5 @@ img[atk-emoticon] {
}
.vp-code-group .tabs::after {
background-color: var(--vp-c-divider)
background-color: var(--vp-c-divider);
}
+5
View File
@@ -0,0 +1,5 @@
declare module '*.vue' {
import { defineComponent } from 'vue'
const component: ReturnType<typeof defineComponent>
export default component
}
+7 -6
View File
@@ -1,19 +1,20 @@
## Artalk Documentation
# Artalk Documentation
> The Documentation of Artalk
[![Netlify Status](https://api.netlify.com/api/v1/badges/6580cce0-4b27-465e-8d73-1e6a832942e9/deploy-status)](https://app.netlify.com/sites/artalk/deploys)
Documentation of Artalk
## Build
```bash
pnpm docs:dev
pnpm docs:build
pnpm dev:docs
pnpm build:docs
```
## Deploy
[![Netlify Status](https://api.netlify.com/api/v1/badges/6580cce0-4b27-465e-8d73-1e6a832942e9/deploy-status)](https://app.netlify.com/sites/artalk/deploys)
文档通过 [Netlify](https://www.netlify.com/) 对 master 分支进行自动部署。
## Licensed
CC BY-NC-SA 4.0
+3
View File
@@ -0,0 +1,3 @@
{
"latest": "2.10.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 的博客', // 你的站点名
+18
View File
@@ -0,0 +1,18 @@
# Compatibility
## Browser Compatibility
The Artalk client production environment code is built using esbuild with a target of `es2015`. However, please note that the build process only handles syntax transpilation to comply with the `es2015` standard and does not address API compatibility (no polyfills are included).
If your project needs to support older browsers and devices, consider including global polyfills in your bundled application. We recommend using the [Polyfill.io](https://polyfill.io/) service, which dynamically returns the necessary polyfills based on the user's User-Agent. Alternatively, you can manually add polyfills using [core-js](https://github.com/zloirock/core-js) or [Babel](https://babeljs.io/).
Here is a list of modern features used by 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)
## Server Compatibility
The Artalk server program is developed in Golang and supports operating systems such as Linux, Windows, and macOS. The current Golang version for Artalk can be found in the [go.mod](https://github.com/ArtalkJS/Artalk/blob/master/go.mod#L3). For the minimum operating system requirements for Golang, refer to the [Go Wiki](https://go.dev/wiki/MinimumRequirements).
+3
View File
@@ -0,0 +1,3 @@
<script setup lang="ts">
if (!import.meta.env.SSR) window.location = 'https://github.com/ArtalkJS/Artalk/blob/master/CONTRIBUTING.md';
</script>
+50
View File
@@ -0,0 +1,50 @@
# Frontend Event
## Basic Events
| Event Name | Description |
| ------------------- | ------------------------------- |
| `created` | After initialization |
| `mounted` | After data loading |
| `updated` | After data update |
| `unmounted` | After destruction |
| `list-fetch` | During comment list request |
| `list-fetched` | After comment list request |
| `list-load` | Before comment loading |
| `list-loaded` | After comment loading |
| `list-failed` | When comment loading fails |
| `list-goto-first` | When comment list resets |
| `list-reach-bottom` | When comment list reaches bottom|
| `comment-inserted` | After comment insertion |
| `comment-updated` | After comment update |
| `comment-deleted` | After comment deletion |
| `comment-rendered` | After comment node rendering |
| `notifies-updated` | When unread messages change |
| `list-goto` | During comment jump |
| `page-loaded` | After page data update |
| `editor-submit` | When editor submits |
| `editor-submitted` | After editor submission |
| `user-changed` | When local user data changes |
| `sidebar-show` | When sidebar is shown |
| `sidebar-hide` | When sidebar is hidden |
Event declaration code: [@ArtalkJS/Artalk - src/types/event.ts](https://github.com/ArtalkJS/Artalk/blob/master/ui/artalk/src/types/event.ts)
## Adding Event Listeners
```js
artalk.on('list-loaded', () => {
alert('Comments have been loaded')
})
```
## Removing Event Listeners
```js
let foo = function () {
/* do something */
}
artalk.on('list-loaded', foo)
artalk.off('list-loaded', foo)
```
+199
View File
@@ -0,0 +1,199 @@
# Frontend API
Here are some of the main Artalk client APIs for operating the Artalk instance in frontend code.
For more detailed API information, you can browse the [TypeDoc documentation](https://artalk.js.org/typedoc/).
## Install Dependencies
Use your preferred package manager to install Artalk:
```bash
pnpm add artalk
# or using npm
npm install artalk
```
## Create Instance `init`
Calling this function creates and returns an instantiated Artalk object for subsequent operations.
<!-- prettier-ignore-start -->
```js
import Artalk from 'artalk'
const artalk = Artalk.init({
el: '#Comments',
pageKey: '/post/1',
pageTitle: 'About Introducing Artalk',
server: 'http://your_domain:8080',
site: 'Artalk Blog',
})
```
<!-- prettier-ignore-end -->
Calling this function will asynchronously send requests to the backend to:
1. Fetch frontend configuration
2. Fetch comment list
The `mounted` event is triggered after configuration and plugins are loaded.
The `list-loaded` event is triggered after the comment list is loaded.
> Note: The frontend UI configuration may be overridden. See: [UI Configuration](../guide/frontend/config.md).
## Release Resources `destroy`
Destroy the Artalk instance to release resources.
```js
const artalk = Artalk.init({ ... })
artalk.destroy()
```
Calling this function triggers the `unmounted` event. Releasing resources involves deleting DOM nodes mounted by Artalk and removing Artalk event listeners. After this function completes, the Artalk instance will no longer be usable.
In frameworks like Vue/React, make sure to call this function when the component is destroyed to prevent memory leaks:
```ts
import { onUnmounted } from 'vue'
onUnmounted(() => {
artalk.destroy()
})
```
## Update Configuration `update`
Modify the current Artalk configuration.
```js
const artalk = Artalk.init({ ... })
artalk.update({
// new configuration...
})
```
Calling this function will trigger the `updated` event.
Updating the configuration will not automatically refresh the comment list. You can continue to call the `artalk.reload()` function as needed.
Note that this function is a member method of an instantiated object, not a global function.
Frontend configuration reference: [Frontend Configuration](../guide/frontend/config.md)
## Reload `reload`
Reload the Artalk comment list data from the backend.
```js
const artalk = Artalk.init({ ... })
artalk.reload()
```
The `list-load` event is triggered before loading the list, and the `list-loaded` event is triggered after the loading is complete.
## Listen to Events `on`
Add Artalk event listeners.
```js
const artalk = Artalk.init({ ... })
artalk.on('list-loaded', (comments) => {
// 'comments' contains all comments on the current page (not just the comments fetched in this request)
console.log('Comments have been loaded: ', comments)
})
```
Refer to: [Frontend Event](./event.md).
## Remove Event Listeners `off`
Remove Artalk event listeners.
```js
const artalk = Artalk.init({ ... })
const handler = () => {
alert('Comments have been loaded')
}
artalk.on('list-loaded', handler)
artalk.off('list-loaded', handler)
```
## Trigger Events `trigger`
Trigger Artalk events.
```js
const artalk = Artalk.init({ ... })
artalk.trigger('list-loaded', [...])
```
## Load Plugins `use`
Load plugins using the `Artalk.use` function. Note that this function is a global function, not a method of an instantiated object. Plugins loaded through this function will be effective for all Artalk instances.
```js
import Artalk from 'artalk'
Artalk.use((ctx) => {
ctx.editor.setContent("Hello World")
})
const artalk = Artalk.init({ ... })
```
See: [Plugin Development](./plugin.md)
## Dark Mode `setDarkMode`
Toggle dark mode, which can be called in conjunction with the blog theme, such as when a user clicks a dark mode toggle button.
```js
const artalk = Artalk.init({ ... })
artalk.setDarkMode(true)
```
You can also set the initial dark mode by passing the `darkMode` parameter when calling `Artalk.init`.
```js
const artalk = Artalk.init({
// ...other configurations
darkMode: 'auto',
})
```
## View Count Widget `loadCountWidget`
See: [Page View Statistics](../guide/frontend/pv.md)
## Get Configuration `getConf`
Get the current Artalk configuration.
```js
const artalk = Artalk.init({ ... })
const conf = artalk.getConf()
```
## Get Mounted Element `getEl`
Get the DOM element that Artalk is currently mounted to.
```js
const artalk = Artalk.init({ ... })
const el = artalk.getEl()
```
+175
View File
@@ -0,0 +1,175 @@
# Import to Blog
## General Method
<<< @/code/quick-start/cdn.html
### When to execute `Artalk.init({})`?
- You can include JS and CSS resources anywhere, but ensure the JS is included before executing `Artalk.init({})`.
- Ensure `<div id="artalk"></div>` is present in the page before executing `Artalk.init({ el: '#artalk' })`.
## Hugo
Create the template file `/themes/YOUR_THEME/layouts/partials/comment/artalk.html`:
<!-- prettier-ignore-start -->
```html
<link href="/lib/artalk/Artalk.css" rel="stylesheet" />
<script src="/lib/artalk/Artalk.js"></script>
<!-- Artalk -->
<div id="Comments"></div>
<script>
Artalk.init({
el: '#Comments',
pageKey: '{{ .Permalink }}',
pageTitle: '{{ .Title }}',
server: '{{ $.Site.Params.artalk.server }}',
site: '{{ $.Site.Params.artalk.site }}',
// ...your additional configuration
})
</script>
```
<!-- prettier-ignore-end -->
Add the following to the appropriate place in your article template `/themes/YOUR_THEME/layouts/_default/single.html`:
```html
<div class="article-comments">{{- partial "comment/artalk" . -}}</div>
```
Modify the Hugo configuration file:
::: code-group
```toml [config.toml]
[params.artalk]
server = 'https://artalk.example.org'
site = 'Your Site Name'
```
```yaml [config.yaml]
params:
artalk:
server: 'https://artalk.example.org'
site: 'Your Site Name'
```
:::
## Hexo
Create `/themes/YOUR_THEME/layout/comment/artalk.ejs`:
```html
<link href="/lib/artalk/Artalk.css" rel="stylesheet" />
<script src="/lib/artalk/Artalk.js"></script>
<div id="Comments"></div>
<script>
var artalk = Artalk.init({
el: '#Comments',
pageKey: '<%= page.permalink %>',
pageTitle: '<%= page.title %>',
server: '<%= theme.comment.artalk.server %>',
site: '<%= theme.comment.artalk.site %>',
})
</script>
```
Modify the article template file, for example `/themes/YOUR_THEME/layout/post.ejs`:
```html
<div class="article-comments"><%- partial('comment/artalk') %></div>
```
Edit the theme configuration `/themes/YOUR_THEME/_config.yml`:
```yaml
comment:
artalk:
site: 'Your Site Name'
server: 'https://artalk.example.org'
```
::: tip
For NexT theme, you can install the [Artalk plugin for Hexo NexT theme](https://github.com/leirock/hexo-next-artalk)
:::
## VitePress
Refer to: [docs/.vitepress](https://github.com/ArtalkJS/Artalk/tree/master/docs/docs/.vitepress)
- Modify `config.ts` to include CSS resources
- Create `theme/Artalk.vue` component
- Register the component in `theme/index.ts`
- Use the component in `theme/Layout.vue`
Sample code: [docs/.vitepress/theme/Artalk.vue](https://github.com/ArtalkJS/Artalk/blob/master/docs/docs/.vitepress/theme/Artalk.vue)
## VuePress
(To be supplemented)
::: tip
Refer to: [Import to Frameworks](./import-framework.md)
:::
## Typecho
Modify the theme article template file, for example, `post.php`:
```php
<!-- CSS -->
<link href="/lib/artalk/Artalk.css" rel="stylesheet">
<!-- JS -->
<script src="/lib/artalk/Artalk.js"></script>
<!-- Artalk -->
<div id="Comments"></div>
<script>
Artalk.init({
el: '#Comments',
pageKey: '<?php $this->permalink() ?>',
pageTitle: '<?php $this->title() ?>',
server: '<Server Address>',
site: '<?php $this->options->title() ?>',
// ...your additional configuration
})
</script>
```
## WordPress
Modify the theme article template file, for example, `single.php`:
```php
<!-- CSS -->
<link href="/lib/artalk/Artalk.css" rel="stylesheet">
<!-- JS -->
<script src="/lib/artalk/Artalk.js"></script>
<!-- Artalk -->
<div id="Comments"></div>
<script>
Artalk.init({
el: '#Comments',
pageKey: '<?= addslashes(get_permalink()) ?>',
pageTitle: '<?= addslashes(get_the_title()) ?>',
server: '<Server Address>',
site: '<?= addslashes(get_bloginfo('name')) ?>',
// ...your additional configuration
})
</script>
```
+230
View File
@@ -0,0 +1,230 @@
# Import to Frameworks
## Install Artalk
Install Artalk using a package manager. It is recommended to use [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/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 Blog',
// ...
})
})
onBeforeUnmount(() => {
artalk.destroy()
})
</script>
<template>
<div ref="el"></div>
</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/Artalk.css'
const el = ref<HTMLElement>()
const router = useRouter()
let artalk: Artalk
onMounted(() => {
artalk = Artalk.init({
el: el.value,
pageKey: router.currentRoute.value.path,
pageTitle: document.title,
server: 'http://localhost:8080',
site: 'Artalk Blog',
// ...
})
})
watch(
() => router.currentRoute.value.path,
(path) => {
nextTick(() => {
artalk.update({
pageKey: path,
pageTitle: document.title,
})
artalk.reload()
})
}
)
onBeforeUnmount(() => {
artalk.destroy()
})
</script>
<template>
<div ref="el"></div>
</template>
```
:::
## React
::: code-group
```tsx [React Hooks]
import { useCallback, useRef } from 'react'
import { useLocation } from 'react-router-dom'
import 'artalk/Artalk.css'
import Artalk from 'artalk'
const ArtalkComment = () => {
const { pathname } = useLocation()
const artalk = useRef<Artalk | null>(null)
const handleContainerInit = useCallback(
(node: HTMLDivElement | null) => {
if (!node) {
return
}
if (artalk.current) {
artalk.current.destroy()
artalk.current = null
}
artalk.current = Artalk.init({
el: node,
pageKey: pathname,
pageTitle: document.title,
server: 'http://localhost:8080',
site: 'Artalk Blog',
// ...
})
},
[pathname],
)
return <div ref={handleContainerInit}></div>
}
export default ArtalkComment
```
```jsx [React Class]
import React, { createRef } from 'react'
import 'artalk/Artalk.css'
import Artalk from 'artalk'
export default class ArtalkComponent 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 Blog',
// ...
})
}
componentWillUnmount() {
this.artalk?.destroy()
}
render() {
return <div ref={this.el} />
}
}
```
:::
## SolidJS
```tsx
import { onCleanup, onMount } from 'solid-js'
import Artalk from 'artalk'
import 'artalk/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 Blog',
// ...
})
onCleanup(() => {
artalk.destroy()
})
})
return <div ref={el} />
}
```
## Svelte
```html
<script>
import Artalk from 'artalk'
import { onMount, onDestroy } from 'svelte'
import 'artalk/Artalk.css'
let el
let artalk
onMount(() => {
artalk = Artalk.init({
el: el,
pageKey: location.pathname,
pageTitle: document.title,
server: 'http://localhost:8080',
site: 'Artalk Blog',
// ...
})
onDestroy(() => {
if (artalk) {
artalk.destroy()
}
})
})
</script>
<div bind:this="{el}"></div>
```
+40
View File
@@ -0,0 +1,40 @@
# Development Instructions
Welcome to the official Artalk development documentation, where you will find guidelines for building Artalk plugins and themes. Should you need to set up the Artalk development environment, please refer to the [Developer Contribution Guide](./contributing.md).
Thank you for your interest and support of Artalk. We deeply understand that the success of an open-source project relies on the contributions of every developer. Whether it is code, documentation, testing, or feedback, your participation is the driving force behind the project's continuous advancement. We sincerely invite you to join us in perfecting and enhancing Artalk.
## Index
- [Developer Contribution Guide](./contributing.md) ⭐️
**Frontend Interface**
- [Embed in Blog](./import-blog.md)
- [Embed in Framework](./import-framework.md)
- [Frontend API](./fe-api.md)
- [Frontend Events](./event.md)
- [Frontend Types](https://artalk.js.org/typedoc/)
- [Frontend Configuration](../guide/frontend/config.md)
**Plugin Development**
- [Plugin Development](./plugin.md)
- [Plugin Development Vite Integration](https://github.com/ArtalkJS/Artalk/blob/master/ui/plugin-kit/README.md)
**Backend Program**
- <a href="/http-api.html" target="_blank">HTTP API Documentation</a>
- [Environment Variables](../guide/env.md)
- [Configuration Files](../guide/backend/config.md)
**Other Content**
- [Compatibility](../develop/compatibility.md)
- [Changelog](https://github.com/ArtalkJS/Artalk/blob/master/CHANGELOG.md)
- [i18n Multi-language Contribution Guide](../guide/frontend/i18n.md#贡献翻译)
- [Contributor Covenant Code of Conduct](https://github.com/ArtalkJS/Artalk/blob/master/CODE_OF_CONDUCT.md)
::: tip
Artalk is under active maintenance. Please be mindful of API version compatibility. Upgrades may include breaking changes, refer to the [Changelog](https://github.com/ArtalkJS/Artalk/blob/master/CHANGELOG.md).
:::
+130
View File
@@ -0,0 +1,130 @@
# Plugin Development
## Developing with Vite
We provide an integrated Vite plugin, enabling you to effortlessly build Artalk plugins with out-of-the-box Vite configuration.
Reference Documentation: [@artalk/plugin-kit](https://github.com/ArtalkJS/Artalk/blob/master/ui/plugin-kit/README.md).
Additionally, we offer a template repository that you can fork to develop your plugins: [artalk-plugin-sample](https://github.com/ArtalkJS/artalk-plugin-sample).
Utilizing Vite in combination with the frontend ecosystem, you can develop Artalk plugins using any framework you prefer, such as Vue, React, Svelte, or SolidJS.
## `Artalk.use`
Extend Artalk's functionality using `Artalk.use`.
```js
import Artalk from 'artalk'
Artalk.use((ctx) => {
ctx.on('list-loaded', () => {
console.log('Comment list loaded')
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 instance mounted')
})
ctx.on('unmounted', () => {
el.remove()
console.log('Artalk instance unmounted')
})
})
const artalk = Artalk.init({ ... })
```
Please note:
- `Artalk.use` must be called before `Artalk.init` to take effect.
- Do not rely on the order of plugin loading; instead, listen for events to execute plugin logic.
- The `created` event is triggered once all plugins are loaded.
- The `mounted` event is triggered when the instance and configuration are fully loaded.
- The `unmounted` event is triggered when the Artalk instance is destroyed.
- The `updated` event is triggered when the configuration changes.
Within the use function, you can access Artalk's Context object via `ctx`.
### Configurable Plugin Options
In TypeScript, you can define a plugin with options using `ArtalkPlugin<T>`.
```ts
export interface DemoPluginOptions {
foo?: string
}
export const ArtalkDemoPlugin: ArtalkPlugin<DemoPluginOptions> = (ctx, options = {}) => {
console.log(options.foo)
}
```
Pass options when calling `Artalk.use`:
```ts
import { ArtalkDemoPlugin } from 'artalk-plugin-demo'
Artalk.use(ArtalkDemoPlugin, { foo: 'bar' })
```
## Context API
The Context object contains Artalk's contextual information.
| Member | Description |
| -------------------- | ----------------------- |
| `ctx.getEl` | Get container element |
| `ctx.getConf` | Get configuration |
| `ctx.updateConf` | Update configuration |
| `ctx.watchConf` | Watch configuration |
| `ctx.setDarkMode` | Set dark mode |
| `ctx.getApi` | Get API client object |
| -- | -- |
| `ctx.fetch` | Fetch comment data |
| `ctx.reload` | Reload comment list |
| `ctx.getComments` | Get all comment data |
| `ctx.getCommentNodes`| Get all comment nodes |
| -- | -- |
| `ctx.on` | Add event listener |
| `ctx.off` | Remove event listener |
| `ctx.trigger` | Trigger event |
| -- | -- |
| `ctx.get` | Get dependency |
| `ctx.inject` | Inject dependency |
::: warning
The Context API is currently unstable and subject to change. Please refer to the CHANGELOG when upgrading.
:::
Reference: [@artalk/src/types/context.ts](https://github.com/ArtalkJS/Artalk/blob/master/ui/artalk/src/types/context.ts)
Artalk includes comprehensive TypeScript type definitions, allowing you to explore the API through editor autocompletion.
## Sample Plugins
Below is a list of externally maintained Artalk plugins:
| Plugin | Description |
| -------------------------------------------------------------------------------------------- | ----------------------- |
| [artalk-plugin-sample](https://github.com/ArtalkJS/artalk-plugin-sample) | Sample Plugin |
| [@artalk/plugin-katex](https://github.com/ArtalkJS/Artalk/tree/master/ui/plugin-katex) | LaTeX Formula Plugin |
| [@artalk/plugin-auth](https://github.com/ArtalkJS/Artalk/tree/master/ui/plugin-auth) | Auth Plugin (SolidJS) |
| [@artalk/plugin-lightbox](https://github.com/ArtalkJS/Artalk/tree/master/ui/plugin-lightbox) | Basic Image Lightbox |
Additionally, many plugins are implemented within Artalk itself, which you can reference for developing your own plugins:
[@ArtalkJS/Artalk - src/plugins](https://github.com/ArtalkJS/Artalk/tree/master/ui/artalk/src/plugins)
## Backend Plugin Development
【TODO】
+3
View File
@@ -0,0 +1,3 @@
# About Us
【TODO】
+403
View File
@@ -0,0 +1,403 @@
# Multi-channel Notifications
Artalk supports sending administrator notifications through its multi-channel notification feature in various ways.
Supported platforms include **Telegram**, **Feishu**, **DingTalk**, **Bark**, **Slack**, and **LINE**, with the ability to enable multiple methods simultaneously.
You can modify these configurations in the settings interface of the [Dashboard](../frontend/sidebar.md#Settings) or via the [configuration file](../backend/config.md#multi-channel-notifications-admin-notify) or [environment variables](../env.md#multi-channel-notifications).
## Configuration File
The complete `admin_notify` configuration is as follows:
::: details Click to reveal
```yaml
# Multi-channel Notifications
admin_notify:
# Notification Template
notify_tpl: default
noise_mode: false
# Email notification for administrators
email:
enabled: true # Disable email notifications for administrators when using other push methods
mail_subject: '[{{site_name}}] Your article "{{page_title}}" has a new reply'
mail_tpl: ''
# Telegram
telegram:
enabled: false
api_token: ''
receivers:
- 7777777
# Feishu
lark:
enabled: false
webhook_url: ''
# DingTalk
ding_talk:
enabled: false
token: ''
secret: ''
# Bark
bark:
enabled: false
server: http://day.app/xxxxxxx/
# Slack
slack:
enabled: false
oauth_token: ''
receivers:
- CHANNEL_ID
# LINE
line:
enabled: false
channel_secret: ''
channel_access_token: ''
receivers:
- USER_ID_1
- GROUP_ID_1
# WebHook
webhook:
enabled: false
url: ''
```
:::
## Email Notifications
Send message notifications to administrators via email.
```yaml
admin_notify:
enabled: true # Disable email notifications for administrators when using other push methods
mail_subject: '[{{site_name}}] Your article "{{page_title}}" has a new reply'
mail_tpl: ''
```
You can disable email notifications when using other push methods.
Before doing this, you need to configure the global email sending functionality: [refer here](./email.md).
### Administrator Email Template
- The `mail_subject` configuration item is the email subject sent to the administrator.
- The `mail_tpl` configuration item specifies the email template for the administrator (fill in the email template file path).
(If this item is empty, it will inherit the `email.mail_tpl` configuration item).
## Telegram
```yaml
admin_notify:
# Telegram
telegram:
enabled: true
api_token: ''
receivers:
- 7777777
```
- `api_token`: The API token for the TG Bot.
- `receivers`: The numeric IDs of the message recipients, multiple recipients can be set.
### Creating a TG Bot
Search for `@BotFather`, reply with `/newbot`, and follow the prompts to create a new TG bot.
![](/images/notify/tg-1.png)
The red text is the `api_token` you need to fill in Artalk's configuration.
Fill in the `receivers` field with the numeric IDs of the accounts that need to receive messages. You can use `@RawDataBot` to get these IDs, as shown:
![](/images/notify/tg-2.png)
For more details, refer to: [Bots: An introduction for developers - Telegram](https://core.telegram.org/bots)
::: tip
Given the complex network environment, if you need to use a proxy, configure the environment variable before starting Artalk, for example:
```sh
export https_proxy=http://127.0.0.1:7890
```
:::
## Feishu
```yaml
admin_notify:
# Feishu
lark:
enabled: true
webhook_url: ''
```
- `webhook_url`: The WebHook address obtained when creating the group bot.
### Creating a Group Bot
Click the plus sign at the top to create a new group:
![](/images/notify/lark-1.png)
Find "Group Settings" on the right, select "Group Bot", click "Add Bot", choose "Custom Bot", and follow the prompts to create it.
<img src="/images/notify/lark-2.png" width="700px">
Copy the WebHook address as shown above and modify Artalk's `webhook_url` configuration.
<img src="/images/notify/lark-3.png" width="400px">
For more details, refer to: [Feishu Help Center Documentation](https://www.feishu.cn/hc/zh-CN/articles/360024984973)
## DingTalk
```yaml
admin_notify:
# DingTalk
ding_talk:
enabled: true
token: ''
secret: ''
```
Refer to: [DingTalk Open Documentation](https://open.dingtalk.com/document/robots/custom-robot-access)
## Bark
```yaml
admin_notify:
# Bark
bark:
enabled: true
server: http://day.app/xxxxxxx/
```
[Bark](https://github.com/Finb/Bark) is an open-source iOS app that [supports self-hosting](https://github.com/Finb/bark-server), allowing you to easily push messages to your iOS device.
You can search and download it from the App Store and get the `server` configuration item to fill in Artalk:
<img src="/images/notify/bark.png" width="700px">
## Slack
```yaml
admin_notify:
# Slack
slack:
enabled: true
oauth_token: ''
receivers:
- CHANNEL_ID
```
## LINE
```yaml
admin_notify:
# LINE
line:
enabled: true
channel_secret: ''
channel_access_token: ''
receivers:
- USER_ID_1
- GROUP_ID_1
```
## Notification Template
```yaml
admin_notify:
notify_tpl: default
```
The `admin_notify.notify_tpl` configuration item can be set to a custom notification template file path. The default notification template is:
```
@{{reply_nick}}:
{{reply_content}}
{{link_to_reply}}
```
The available variables are the same as in the email template, refer to: [Email Template](./email.md#邮件模板)
## Notify Pending Comments `notify_pending`
```yaml
admin_notify:
notify_pending: false
```
`notify_pending` is turned off by default. When set to `false`, pending comments will not send notifications. You can view all pending comments in the Dashboard.
## Noise Mode `noise_mode`
```yaml
admin_notify:
noise_mode: false
```
`noise_mode` is turned off by default. When set to `false`, only messages directed to the administrator will send notifications. For example, communication between "User A" and "User B" will not notify the administrator.
Note: When `moderator.pending_default` is set to `true`, noise_mode is always enabled.
## WebHook Callback
When WebHook is enabled, a new comment will send a **POST** request with `application/json` type Body data to the specified WebHook address.
You can write your own server-side code to handle requests from Artalk.
**Artalk Configuration File**
```yaml
admin_notify:
webhook:
enabled: true
url: http://localhost:8080/
```
**Body Data Content**
`application/json` type
| Key | Description | Type | Remarks |
| ---------------- | ----------------- | ------ | ----------------------------------------- |
| `notify_subject` | Notification Title | String | Corresponds to the admin_notify.notify_subject configuration item |
| `notify_body` | Notification Content | String | Rendered according to the admin_notify.notify_tpl template |
| `comment` | Comment Content | Object | New comment data object |
| `parent_comment` | Target of Comment Reply | Object | If it's a root comment, the value is null |
**Body Data Sample**
```js
{
"notify_subject": "",
"notify_body": "@TestUser:\n\nTestContent\n\nhttps://127.0.0.1/index.html?atk_comment=1057",
"comment": {
"id": 1057,
"content": "TestContent",
"user_id": 226,
"nick": "TestUser",
"email_encrypted": "654236c1e78i4c09a17c4869c9d43910",
"link": "https://qwqaq.com",
"ua": "Mozilla/5.0 (Macintosh; Intel Mac OS X 12_4_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/101.0.4951.64 Safari/537.36",
"date": "2022-05-23 17:00:23",
"is_collapsed": false,
"is_pending": false,
"is_pinned": false,
"is_allow_reply": false,
"rid": 0,
"badge_name": "",
"badge_color": "",
"visible": true,
"vote_up": 0,
"vote_down": 0,
"page_key": "/index.html",
"page_url": "https://127.0.0.1/index.html",
"site_name": "ArtalkDocs"
},
"parent_comment": null
}
```
**Node.js Express Handling Example**
```js
const express = require('express')
const app = express()
app.use(express.json()) // Use JSON middleware
app.post('/', (request, response) => {
console.log(request.body)
const notifySubject = request.body.notify_subject
const notifyBody = request.body.notify_body
console.log(notifySubject, notifyBody)
response.send(request.body)
})
app.listen(8080)
```
**Node.js HTTP Handling Example**
```js
const http = require('http')
const requestListener = (req, res) => {
// receive json request
let body = ''
req.on('data', (data) => {
body += data
})
req.on('end', () => {
let json = ''
try {
json = JSON.parse(body)
} catch {}
// do something with json
console.log(json)
res.end()
})
res.writeHead(200)
res.end('Hello, World!')
}
const server = http.createServer(requestListener)
server.listen(8080)
```
**PHP Laravel Handling Example**
```php
Route::get('/', function (Request $request) {
$data = $request->json()->all();
$notify_subject = $data["notify_subject"];
$notify_body = $data["notify_body"];
});
```
**Golang net/http Handling Example**
```go
package main
import (
"encoding/json"
"log"
"net/http"
)
type ArtalkNotify struct {
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) {
decoder := json.NewDecoder(req.Body)
var notify ArtalkNotify
err := decoder.Decode(&notify)
if err != nil {
panic(err)
}
log.Println(notify.NotifyBody)
}
func main() {
http.HandleFunc("/webhook", webhookHandler)
log.Fatal(http.ListenAndServe(":8080", nil))
}
```
+159
View File
@@ -0,0 +1,159 @@
# Captcha
Artalk comes with a built-in image captcha feature, allowing you to configure operation frequency limits that activate the captcha when exceeded.
Additionally, you can integrate various verification service providers to gain diversified verification functionality.
Currently, Artalk supports: Turnstile, reCAPTCHA, hCaptcha, and Geetest.
You can modify these settings in the [Dashboard](../frontend/sidebar.md#Settings) or via the [configuration file](./config.md#captcha) or [environment variables](../env.md#captcha).
## Configuration File
The full `captcha` configuration is as follows:
```yaml
# Captcha
captcha:
enabled: true # Master switch
always: false # Always require captcha
captcha_type: image # Type of captcha
action_limit: 3 # Number of actions required to activate captcha
action_reset: 60 # Timeout to reset action counter (unit: s, set to -1 to never reset)
# Turnstile
# (https://www.cloudflare.com/products/turnstile/)
turnstile:
site_key: ''
secret_key: ''
# reCAPTCHA
# (https://www.google.com/recaptcha/about/)
recaptcha:
site_key: ''
secret_key: ''
# hCaptcha (https://www.hcaptcha.com/)
hcaptcha:
site_key: ''
secret_key: ''
# Geetest (https://www.geetest.com)
geetest:
captcha_id: ''
captcha_key: ''
```
- **always**: When set to `true`, captcha is always required.
- **captcha_type**: Type of captcha, options include: `image`, `turnstile`, `recaptcha`, `hcaptcha`, `geetest`.
- **action_limit**: The number of actions required to activate the captcha.
- **action_reset**: When the time exceeds this value, the action counter resets. Unit is seconds; set to `-1` to never reset.
Note: When `always` is enabled, `action_limit` and `action_reset` configurations are ignored.
## Configuration Examples
### Example 1
Within a 60-second time frame, if the number of actions exceeds 3, captcha will be required:
```yaml
captcha:
action_limit: 3
action_reset: 60
```
The counter will automatically reset after 60 seconds, allowing for 3 more actions without requiring a captcha.
### Example 2
Regardless of the time frame, if the number of actions from an IP address exceeds 5, captcha will be required:
```yaml
captcha:
action_limit: 5
action_reset: -1
```
### Example 3
Always require captcha, regardless of the number of actions:
```yaml
captcha:
always: true
```
## Definition of Actions
Each "comment, vote, image upload, password verification" by an IP address counts as an "action."
## Turnstile
[Turnstile](https://www.cloudflare.com/zh-cn/products/turnstile/) is a verification service from Cloudflare. You can obtain the `site_key` and `secret_key` from the CF dashboard, then fill in these keys in the Artalk settings and change `captcha_type` to `turnstile`.
Illustrations:
<img src="/images/captcha/cf-turnstile-1.png" width="400px">
<img src="/images/captcha/cf-turnstile-2.png" width="400px">
Corresponding configuration file:
```yaml
captcha:
# Omit other configurations...
captcha_type: turnstile
turnstile:
site_key: ''
secret_key: ''
```
## reCAPTCHA
[reCAPTCHA](https://developers.google.com/recaptcha) is a verification service from Google, and Artalk supports reCAPTCHA v3. You can obtain the `site_key` and `secret_key` from the Google developer dashboard, then fill in these keys in the Artalk settings and change `captcha_type` to `recaptcha`.
Corresponding configuration file:
```yaml
captcha:
# Omit other configurations...
captcha_type: recaptcha
recaptcha:
site_key: ''
secret_key: ''
```
Note: Accessing Google APIs from within China may require configuring a system proxy.
Google provides test keys for reCAPTCHA: [see here](https://developers.google.com/recaptcha/docs/faq?hl=en#id-like-to-run-automated-tests-with-recaptcha.-what-should-i-do).
## hCaptcha
[hCaptcha](https://www.hcaptcha.com/) is a verification service. You can obtain the `site_key` and `secret_key` from its official website, then fill in these keys in the Artalk settings and change `captcha_type` to `hcaptcha`.
Corresponding configuration file:
```yaml
captcha:
# Omit other configurations...
captcha_type: hcaptcha
hcaptcha:
site_key: ''
secret_key: ''
```
hCaptcha provides test keys: [see here](https://docs.hcaptcha.com/#integration-testing-test-keys).
## Geetest
Artalk supports integrating [Geetest](https://www.geetest.com/adaptive-captcha) for advanced behavior verification.
First, register an account on the Geetest website to obtain the `captcha_id` and `captcha_key`, then modify the configuration in the Artalk settings and change `captcha_type` to `geetest`.
Corresponding configuration file:
```yaml
captcha:
# Omit other configurations...
captcha_type: geetest
geetest:
captcha_id: ''
captcha_key: ''
```
+370
View File
@@ -0,0 +1,370 @@
# Configuration File
## Easy Configuration
It is recommended to modify the configuration through the graphical interface in the sidebar "[Dashboard](../frontend/sidebar.md)" without manually editing the configuration file.
## Environment Variables
You can configure via environment variables, refer to the documentation: [Environment Variables](../env.md).
## Specifying the Configuration File Path
By default, Artalk uses `artalk.yml` in the working directory as the configuration file. You can specify a specific file using the `-c` parameter:
```bash
artalk -c ./conf.yml
```
## Obtaining a Template Configuration File
You can refer to a "complete configuration file": [artalk.example.zh-CN.yml](https://github.com/ArtalkJS/Artalk/blob/master/conf/artalk.example.zh-CN.yml)
### Generate Configuration File Using the `gen` Command
Artalk provides the `gen` command, allowing you to quickly generate a new configuration file:
```bash
artalk gen conf -lang zh-CN ./artalk.yml
```
### Download Configuration File via Command Line
```bash
wget -O artalk.yml https://raw.githubusercontent.com/ArtalkJS/Artalk/master/conf/artalk.example.zh-CN.yml
```
## Encryption Key `app_key`
Before starting Artalk, you need to configure an `app_key` for securely encrypting site content:
```yaml
app_key: <any random characters>
```
## Language `locale`
Set the language for Artalk. Follows the Unicode BCP 47 standard, with the default being "zh-CN" (Simplified Chinese).
```yaml
locale: zh-CN
```
For details, refer to: [Multilingual](../frontend/i18n.md)
## Database `db`
Artalk supports connecting to various databases, including SQLite, MySQL, PostgreSQL, and SQL Server. The configurations are as follows:
#### SQLite
SQLite is a lightweight database that stores data in a single file, requiring no additional running programs. It is especially suitable for small sites, such as personal blogs.
```yaml
db:
type: sqlite
file: ./data/artalk.db
```
#### MySQL / PostgreSQL / SQL Server
Modify `type` to your database type:
```yaml
db:
type: mysql # sqlite, mysql, pgsql, mssql
name: artalk # Database name
host: localhost # Address
port: 3306 # Port
user: root # Username
password: '' # Password
charset: utf8mb4 # Charset
table_prefix: '' # Table prefix (e.g., "atk_")
ssl: false # Enable SSL
prepare_stmt: true # Prepared statements
```
The data tables will be automatically created when Artalk starts, no additional operation is required.
#### Database Connection String (DSN)
If needed, you can manually configure `db.dsn` to specify the database connection string, for example:
```yaml
db:
type: mysql
dsn: mysql://myuser:mypassword@localhost:3306/mydatabase?tls=skip-verify
```
For more details, refer to: [@go-sql-driver/mysql:README.md](https://github.com/go-sql-driver/mysql)
## Server `http`
```yaml
http:
# Request body size limit (unit: MB)
body_limit: 100
# Proxy header name (when using CDN, fill in `X-Forwarded-For` to get the user's real IP)
proxy_header: ""
```
## Admin Users `admin_users`
You need to configure administrator accounts to manage site content through the "[Dashboard](../frontend/sidebar.md)".
Artalk supports multiple sites, allowing you to create multiple administrator accounts and assign sites to them, enabling your friends to share the same backend program.
For details, refer to: [Admin Users × Multi-site](./multi-site.md)
## Trusted Domains `trusted_domains`
```yaml
trusted_domains:
- https://frontend.domainA.com
- https://frontend.domainB.com
```
Only the domains in the list are allowed to access the backend API, restricting cross-domain requests from external domains.
::: tip
You need to add the URL address of the "frontend page" to the trusted domains list.
If it's not the default 80/443 port, include the port number, e.g., `https://example.com:8080`.
:::
In the sidebar [Dashboard](../frontend/sidebar.md#控制中心), under the "Site" tab - select the site and "Modify URL", fill in the site URL to achieve the same setting effect; to add multiple URLs, separate them with commas `,`. After modification, manually restart Artalk.
The default site address `ATK_SITE_URL` configuration item will also be automatically added to the trusted domains list.
Additionally, you can configure trusted domains via the environment variable `ATK_TRUSTED_DOMAINS` when starting, for example:
```bash
ATK_TRUSTED_DOMAINS="https://a.com https://b.org" artalk server
```
Note that environment variables will override the settings in the configuration file.
Technical details: `trusted_domains` configuration controls cross-origin requests by setting the HTTP response header `Access-Control-Allow-Origin` (refer to: [W3C Cross-Origin Resource Sharing](https://fetch.spec.whatwg.org/#http-cors-protocol) / [OWASP Security Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Cross-Site_Request_Forgery_Prevention_Cheat_Sheet.html)).
## Default Site `site_default`
If you think you won't use the multi-site feature of Artalk, you can directly set this item to your site name, for example:
```yaml
site_default: Artalk Official Website
```
Then use this site name in the frontend:
```js
Artalk.init({ site: 'Artalk Official Website' })
```
This way, you don't need to manually create the site in the sidebar [Dashboard](../frontend/sidebar.md#控制中心).
## Frontend Configuration `frontend`
In Artalk's configuration file `artalk.yml`, you can configure the `frontend` field to control the frontend interface, for example:
```yaml
frontend:
placeholder: Type content...
noComment: "Silence is golden"
sendBtn: Send Comment
emoticons: 'https://raw.githubusercontent.com/ArtalkJS/Emoticons/master/grps/default.json'
# ----- Omitted -------
# Keep the same as the frontend configuration item name
```
A complete backend `frontend` field configuration file can be referred to: [artalk.example.zh-CN.yml](https://github.com/ArtalkJS/Artalk/blob/master/conf/artalk.example.zh-CN.yml)
## Email Notifications `email`
Configure email notifications to notify the target user of replies via email. You can customize the sender name, title, template, etc.
For details, refer to: [Backend · Email Notifications](./email.md)
## Multi-channel Notifications `admin_notify`
You can configure various message sending methods, such as Feishu, Telegram, etc., to notify administrators when new comments are received.
For details, refer to: [Backend · Multi-channel Notifications](./admin_notify.md)
## Comment Moderation `moderator`
Configure comment moderation to automatically intercept spam comments.
For details, refer to: [Backend · Comment Moderation](./moderator.md)
## Captcha `captcha`
Supports image and slide captchas to limit request frequency.
For details, refer to: [Backend · Captcha](./captcha.md)
## Cache `cache`
To save memory resources, caching is disabled by default. If you have high performance requirements for your site, enable it manually. You can also connect to external cache servers, supporting Redis and Memcache.
```yaml
cache:
enabled: true # Enable cache (default is off)
type: builtin # Supports redis, memcache, builtin (built-in cache)
expires: 30 # Cache expiration time (unit: minutes)
warm_up: false # Warm up cache on program startup
server: '' # Connect to cache server (e.g., "localhost:6379")
```
- **warm_up**: Cache warm-up feature. Set to `true`, it will immediately cache all database content when Artalk starts. If you have a large number of comments, this may extend the startup time.
- **type**: Cache type, defaults to `builtin`. Options: `redis`, `memcache`, `builtin`.
Note: If you modify the database content outside the Artalk program, you need to refresh the Artalk cache to update it.
---
Redis authentication and database configuration:
```yaml
# Cache
cache:
# Omit other configurations...
redis:
network: tcp # Connection method (tcp or unix)
username: '' # Username
password: '' # Password
db: 0 # Use database 0
```
<!-- Technical details: [Artalk Cache Mechanism Sequence Diagram.png](/images/artalk/artalk-cache.png) -->
<!-- ![](/images/artalk/artalk-cache.png) -->
## Listening Address `host`
The default HTTP port for Artalk is 23366. You can specify it in the configuration file:
```yaml
host: '0.0.0.0'
port: 23366
```
Configuring the `host` listening address to `0.0.0.0` will expose the Artalk service to the entire network.
If you want Artalk to be accessible only locally, configure `host` to `127.0.0.1`.
When starting Artalk via the command line, you can specify the address and port using the `--host` and `--port` parameters, for example:
```bash
artalk server --host 127.0.0.1 --port 8080
```
## Encrypted Transmission `ssl`
```yaml
ssl:
enabled: true
cert_path: ''
key_path: ''
```
You can configure this item to upgrade HTTP to HTTPS, encrypting data transmission via SSL.
- `cert_path`: Path to the SSL certificate public key file.
- `key_path`: Path to the SSL certificate private key file.
You can also directly reverse proxy the Artalk local server and then enable HTTPS in, for example, Nginx.
## Time Zone Configuration `timezone`
```yaml
timezone: Asia/Shanghai
```
Fill in the time zone where you are located, corresponding to the IANA database time zone name, refer to: [Wikipedia](https://en.wikipedia.org/wiki/List_of_tz_database_time_zones) / [RFC-6557](https://www.rfc-editor.org/rfc/rfc6557.html).
`timezone` controls the timezone used by the Artalk application. It may differ from the host system or container `TZ` setting. The same configuration can be supplied through `ATK_TIMEZONE`:
```bash
ATK_TIMEZONE=America/New_York artalk server
```
::: warning Restart required
The application timezone is a process-level fixed value and is set only when the Artalk process initializes. It cannot be changed dynamically at runtime. After changing it in the configuration file, environment, or Dashboard, fully restart the Artalk process or container for the new value to take effect.
:::
```
UTC+08:00 Asia/Shanghai
UTC+09:00 Asia/Tokyo
UTC-07:00 America/Los_Angeles
UTC-04:00 America/New_York
```
## Login Timeout `login_timeout`
This value sets the validity period of the administrator account login JWT token, in seconds.
For example, valid for 3 days:
```yaml
login_timeout: 259200
```
## Log Configuration `log`
When logging is enabled, system errors and other information will be recorded in the specified file.
```yaml
log:
enabled: true # Master switch
filename: ./data/artalk.log # Log file path
```
Logs are in JSON format, which can be viewed using the `tail` command combined with the `jq` tool in Linux:
```bash
tail -f ./data/artalk.log | jq
```
If you are a Grafana user, you can use Loki and Promtail to collect and query logs.
## Debug Mode `debug`
Set `debug` to `true` to enable debug mode.
```yaml
debug: true
```
## Working Directory `-w` Parameter
If the working directory is not specified, Artalk will use the "directory where the program is started" as the working directory.
```bash
pwd # Display the current directory path
```
Use the `-w` parameter to specify the working directory, which is usually an "absolute path", for example:
```bash
artalk -w /root/artalk -c ./conf.yml
```
Note: The relative path of `-c` will be based on the path of `-w`, and Artalk will read `/root/artalk/conf.yml` as the configuration file.
Additionally, the "relative path" used in the "configuration file" will also be based on the "working directory".
For example, if the configuration in `conf.yml` is:
```yaml
test_file: ./data/artalk.log
```
It will read `/root/artalk/data/artalk.log`.
::: tip
Configuration file related code: [/internal/config/config.go](https://github.com/ArtalkJS/Artalk/blob/master/internal/config/config.go)
Go to: [Frontend Configuration](../frontend/config.md)
:::
+144
View File
@@ -0,0 +1,144 @@
# Daemon Process
## Systemd
Prerequisites:
- The Artalk binary file, which can be downloaded from [GitHub Release](https://github.com/ArtalkJS/Artalk/releases)
- `systemctl --version` 232 or later
- `sudo` administrator privileges
Move Artalk to `$PATH`, for example:
```bash
sudo mv artalk /usr/bin/
```
Test if it works:
```bash
artalk version
```
Create a user group named `artalk`:
```bash
sudo groupadd --system artalk
```
Create a user named `artalk` with a writable home directory:
```bash
sudo useradd --system \
--gid artalk \
--create-home \
--home-dir /var/lib/artalk \
--shell /usr/sbin/nologin \
--comment "Artalk server" \
artalk
```
If you have the Artalk configuration file, ensure that the newly created `artalk` user has read permissions.
Create the service file:
```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
```
Carefully check `ExecStart` and `ExecReload`. Ensure that the binary file location and program startup parameters are correct.
For example, change the path of the `-c` parameter to specify the configuration file and the `-w` parameter to change the working directory.
Note that all relative paths in the configuration file are based on the working directory. For example, the `./data/` folder in the configuration file, if the startup parameter is `-w /var/lib/artalk`, will read from the `/var/lib/artalk/data/` directory. Ensure the files in this directory are readable and writable by the created `artalk` account.
After saving the service file, you can set the service to start automatically:
```bash
sudo systemctl daemon-reload
sudo systemctl enable --now artalk
```
Verify that the service is running correctly:
```bash
systemctl status artalk
```
Some common commands:
- Start the service: `systemctl start artalk`
- Stop the service: `systemctl stop artalk`
- Check the status: `systemctl status artalk`
- View logs: `journalctl -u artalk --no-pager | less +G`
## Tmux
tmux will create a persistent command-line session that remains in the background after SSH or tty disconnection.
Note: tmux sessions will be cleared after the server shuts down or restarts, and you will need to manually rerun the program.
1. Create a session `tmux new -s artalk`
2. Run the program `./artalk server`
Reconnect to the session: `tmux attach -t artalk`
View all sessions: `tmux ls`
## Supervisor
Taking Baota Panel as an example: Open the "Software Store," search for and install the "Supervisor Manager":
![](/images/baota-supervisor/0.png)
After installation, open the plugin and click "Add Daemon":
![](/images/baota-supervisor/1.png)
> - Startup User: `root` or others
> - Working Directory: Click the icon on the right and select the Artalk directory
> - Startup Command: `./artalk server`
## Docker
Update the Docker container's [Restart Policy](https://docs.docker.com/config/containers/start-containers-automatically/#use-a-restart-policy) to achieve the effect of process daemonization.
```bash
docker update --restart=unless-stopped artalk
```
## Docker Compose
Add the `restart: unless-stopped` policy to the service in the `docker-compose.yml` file:
```diff
version: '3'
services:
artalk:
+ restart: unless-stopped
```
Loaded 100 of 1170 files, more files were not shown because too many files have changed in this diff. Show more