artalk 2.3.3 → 2.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (105) hide show
  1. package/dist/Artalk.css +1 -1
  2. package/dist/Artalk.es.js +3184 -2888
  3. package/dist/Artalk.iife.js +1 -1
  4. package/dist/Artalk.js +1 -1
  5. package/dist/ArtalkLite.css +1 -1
  6. package/dist/ArtalkLite.es.js +3157 -2887
  7. package/dist/ArtalkLite.iife.js +1 -1
  8. package/dist/ArtalkLite.js +1 -1
  9. package/dist/src/api/admin.d.ts +10 -0
  10. package/dist/src/api/api-base.d.ts +14 -0
  11. package/dist/src/api/captcha.d.ts +14 -0
  12. package/dist/src/api/comment.d.ts +29 -0
  13. package/dist/src/api/index.d.ts +31 -0
  14. package/dist/src/api/page.d.ts +22 -0
  15. package/dist/src/api/request.d.ts +12 -0
  16. package/dist/src/api/site.d.ts +17 -0
  17. package/dist/src/api/system.d.ts +13 -0
  18. package/dist/src/api/upload.d.ts +11 -0
  19. package/dist/src/api/user.d.ts +28 -0
  20. package/dist/src/artalk.d.ts +56 -0
  21. package/dist/src/comment/actions.d.ts +17 -0
  22. package/dist/src/comment/comment.d.ts +67 -0
  23. package/dist/src/comment/index.d.ts +2 -0
  24. package/dist/src/comment/render.d.ts +76 -0
  25. package/dist/src/components/action-btn.d.ts +52 -0
  26. package/dist/src/components/dialog.d.ts +18 -0
  27. package/dist/src/components/pagination.d.ts +30 -0
  28. package/dist/src/components/read-more-btn.d.ts +33 -0
  29. package/dist/src/context.d.ts +72 -0
  30. package/dist/src/defaults.d.ts +3 -0
  31. package/dist/src/editor/editor.d.ts +84 -0
  32. package/dist/src/editor/index.d.ts +2 -0
  33. package/dist/src/editor/plugs/editor-plug.d.ts +26 -0
  34. package/dist/src/editor/plugs/emoticons-plug.d.ts +36 -0
  35. package/dist/src/editor/plugs/header-input-plug.d.ts +13 -0
  36. package/dist/src/editor/plugs/preview-plug.d.ts +10 -0
  37. package/dist/src/editor/plugs/upload-plug.d.ts +10 -0
  38. package/dist/src/i18n/en.d.ts +69 -0
  39. package/dist/src/i18n/index.d.ts +294 -0
  40. package/dist/src/i18n/zh-CN.d.ts +3 -0
  41. package/dist/src/layer/index.d.ts +3 -0
  42. package/dist/src/layer/layer.d.ts +32 -0
  43. package/dist/src/layer/sidebar-layer.d.ts +20 -0
  44. package/dist/src/lib/checker/admin-checker.d.ts +3 -0
  45. package/dist/src/lib/checker/captcha-checker.d.ts +3 -0
  46. package/dist/src/lib/checker/index.d.ts +42 -0
  47. package/dist/src/lib/component.d.ts +12 -0
  48. package/dist/src/lib/detect.d.ts +10 -0
  49. package/dist/src/lib/stat.d.ts +15 -0
  50. package/dist/src/lib/ui.d.ts +23 -0
  51. package/dist/src/lib/user.d.ts +13 -0
  52. package/dist/src/lib/utils.d.ts +39 -0
  53. package/dist/src/list/index.d.ts +2 -0
  54. package/dist/src/list/list-lite.d.ts +63 -0
  55. package/dist/src/list/list-nest.d.ts +10 -0
  56. package/dist/src/list/list.d.ts +26 -0
  57. package/dist/src/main.d.ts +4 -0
  58. package/dist/types/artalk-config.d.ts +132 -0
  59. package/dist/types/artalk-data.d.ts +204 -0
  60. package/dist/types/context.d.ts +146 -0
  61. package/dist/types/event.d.ts +28 -0
  62. package/dist/types/global.d.ts +0 -0
  63. package/dist/types/plug.d.ts +4 -0
  64. package/index.html +3 -3
  65. package/package.json +5 -5
  66. package/src/api/admin.ts +18 -0
  67. package/src/api/api-base.ts +27 -0
  68. package/src/api/captcha.ts +24 -0
  69. package/src/api/comment.ts +84 -0
  70. package/src/api/index.ts +25 -361
  71. package/src/api/page.ts +85 -0
  72. package/src/api/request.ts +12 -8
  73. package/src/api/site.ts +51 -0
  74. package/src/api/system.ts +39 -0
  75. package/src/api/upload.ts +29 -0
  76. package/src/api/user.ts +75 -0
  77. package/src/artalk.ts +75 -76
  78. package/src/comment/actions.ts +3 -3
  79. package/src/comment/comment.ts +6 -9
  80. package/src/comment/render.ts +93 -47
  81. package/src/components/pagination.ts +0 -1
  82. package/src/context.ts +57 -18
  83. package/src/editor/editor.ts +111 -18
  84. package/src/editor/plugs/header-input-plug.ts +1 -1
  85. package/src/editor/plugs/upload-plug.ts +1 -1
  86. package/src/i18n/en.ts +3 -0
  87. package/src/i18n/index.ts +117 -2
  88. package/src/i18n/zh-CN.ts +4 -1
  89. package/src/layer/sidebar-layer.ts +1 -3
  90. package/src/lib/checker/admin-checker.ts +1 -1
  91. package/src/lib/checker/captcha-checker.ts +3 -3
  92. package/src/lib/stat.ts +2 -2
  93. package/src/lib/ui.ts +6 -0
  94. package/src/list/list-lite.ts +33 -25
  95. package/src/list/list.ts +3 -4
  96. package/src/main.ts +3 -0
  97. package/src/style/comment.less +2 -3
  98. package/src/style/main.less +6 -0
  99. package/test/CSRF.html +26 -0
  100. package/types/artalk-data.d.ts +3 -0
  101. package/types/context.d.ts +19 -1
  102. package/types/global.d.ts +0 -2
  103. package/vite-base.config.ts +9 -5
  104. package/vite.config.ts +5 -1
  105. package/types/index.d.ts +0 -3
@@ -0,0 +1,28 @@
1
+ import { CommentData } from './artalk-data'
2
+ import { LocalUser } from './artalk-config'
3
+
4
+ /** EventName to EventPayload Type */
5
+ export interface EventPayloadMap {
6
+ 'list-load': undefined // 评论加载时
7
+ 'list-loaded': undefined // 评论装载后
8
+ 'list-inserted': CommentData // 评论插入后
9
+ 'editor-submit': undefined // 编辑器提交时
10
+ 'editor-submitted': undefined // 编辑器提交后
11
+ 'user-changed': LocalUser // 本地用户数据变更时
12
+ 'conf-updated': undefined // Artalk 配置变更时
13
+ 'sidebar-show': undefined // 侧边栏显示
14
+ 'sidebar-hide': undefined // 侧边栏隐藏
15
+ }
16
+
17
+ // ============================================
18
+ export interface Handler<P> {
19
+ (payload: P): void
20
+ }
21
+
22
+ export type EventScopeType = 'internal'|'external'
23
+
24
+ export interface Event<K extends keyof EventPayloadMap = keyof EventPayloadMap> {
25
+ name: keyof EventPayloadMap
26
+ handler: Handler<EventPayloadMap[K]>
27
+ scope: EventScopeType
28
+ }
File without changes
@@ -0,0 +1,4 @@
1
+ import ContextApi from './context'
2
+
3
+ type ArtalkPlug = (ctx: ContextApi) => void
4
+ export default ArtalkPlug
package/index.html CHANGED
@@ -31,8 +31,8 @@
31
31
  .to-top { right: 25px; }
32
32
  </style>
33
33
  <!--<link rel="stylesheet"
34
- href="//cdnjs.cloudflare.com/ajax/libs/highlight.js/11.5.1/styles/arta.min.css">
35
- <script src="//cdnjs.cloudflare.com/ajax/libs/highlight.js/11.5.1/highlight.min.js"></script>-->
34
+ href="//cdnjs.cloudflare.com/ajax/libs/highlight.js/11.6.0/styles/arta.min.css">
35
+ <script src="//cdnjs.cloudflare.com/ajax/libs/highlight.js/11.6.0/highlight.min.js"></script>-->
36
36
 
37
37
  <!-- For mobile testing -->
38
38
  <script src="https://unpkg.com/vconsole@latest/dist/vconsole.min.js"></script>
@@ -65,7 +65,7 @@
65
65
  import Artalk from './src/main'
66
66
  var artalk = new Artalk({
67
67
  el: '#comments',
68
- pageKey: 'https://artalk.js.org/',
68
+ pageKey: 'https://artalk.js.org/guide/intro.html',
69
69
  pageTitle: 'Artalk Home',
70
70
  server: (import.meta.env.DEV) ? 'http://localhost:23366' : 'https://artalk.qwqaq.com',
71
71
  site: 'ArtalkDocs',
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "artalk",
3
- "version": "2.3.3",
4
- "backendMinVersion": "2.1.7",
3
+ "version": "2.4.0",
4
+ "backendMinVersion": "2.2.0",
5
5
  "license": "LGPL-3.0",
6
6
  "description": "A Selfhosted Comment System",
7
7
  "keywords": [
@@ -22,14 +22,14 @@
22
22
  "unpkg": "./dist/Artalk.iife.js",
23
23
  "jsdelivr": "./dist/Artalk.iife.js",
24
24
  "module": "./dist/Artalk.es.js",
25
- "types": "./types/index.d.ts",
25
+ "types": "./dist/src/main.d.ts",
26
26
  "devDependencies": {
27
- "@types/marked": "4.0.3"
27
+ "@types/marked": "4.0.6"
28
28
  },
29
29
  "dependencies": {
30
30
  "hanabi": "^0.4.0",
31
31
  "insane": "^2.6.2",
32
- "marked": "^4.0.16",
32
+ "marked": "^4.0.19",
33
33
  "abortcontroller-polyfill": "^1.7.3"
34
34
  },
35
35
  "scripts": {
@@ -0,0 +1,18 @@
1
+ import ApiBase from './api-base'
2
+
3
+ /**
4
+ * 管理员 API
5
+ */
6
+ export default class AdminApi extends ApiBase {
7
+ /** 缓存清除 */
8
+ public cacheFlushAll() {
9
+ const params: any = { flush_all: true }
10
+ return this.POST('/admin/cache-flush', params)
11
+ }
12
+
13
+ /** 缓存预热 */
14
+ public cacheWarmUp() {
15
+ const params: any = {}
16
+ return this.POST('/admin/cache-warm', params)
17
+ }
18
+ }
@@ -0,0 +1,27 @@
1
+ import Context from '~/types/context'
2
+ import Api from '.'
3
+ import { POST, Fetch } from './request'
4
+
5
+ abstract class ApiBase {
6
+ protected api: Api
7
+ protected ctx: Context
8
+
9
+ constructor(api: Api, ctx: Context) {
10
+ this.api = api
11
+ this.ctx = ctx
12
+ }
13
+
14
+ protected async POST<T>(path: string, data?: {[key: string]: any}) {
15
+ return POST<T>(this.ctx, this.api.baseURL+path, data)
16
+ }
17
+
18
+ protected async Fetch(path: string, init: RequestInit, timeout?: number): Promise<any> {
19
+ return Fetch(this.ctx, this.api.baseURL+path, init, timeout)
20
+ }
21
+ }
22
+
23
+ interface ApiBase {
24
+
25
+ }
26
+
27
+ export default ApiBase
@@ -0,0 +1,24 @@
1
+ import ApiBase from './api-base'
2
+
3
+ /**
4
+ * 验证码 API
5
+ */
6
+ export default class CaptchaApi extends ApiBase {
7
+ /** 验证码 · 获取 */
8
+ public async captchaGet() {
9
+ const data = await this.POST<any>('/captcha/refresh')
10
+ return (data.img_data || '') as string
11
+ }
12
+
13
+ /** 验证码 · 检验 */
14
+ public async captchaCheck(value: string) {
15
+ const data = await this.POST<any>('/captcha/check', { value })
16
+ return (data.img_data || '') as string
17
+ }
18
+
19
+ /** 验证码 · 状态 */
20
+ public async captchaStatus() {
21
+ const data = await this.POST<any>('/captcha/status')
22
+ return (data || { is_pass: false }) as { is_pass: boolean }
23
+ }
24
+ }
@@ -0,0 +1,84 @@
1
+ import { CommentData, ListData } from '~/types/artalk-data'
2
+ import * as Utils from '../lib/utils'
3
+ import ApiBase from './api-base'
4
+
5
+ /**
6
+ * 评论 API
7
+ */
8
+ export default class CommentApi extends ApiBase {
9
+ /** 评论 · 获取 */
10
+ public get(offset: number, pageSize: number, flatMode?: boolean, paramsEditor?: (params: any) => void) {
11
+ const params: any = {
12
+ page_key: this.ctx.conf.pageKey,
13
+ site_name: this.ctx.conf.site || '',
14
+ limit: pageSize,
15
+ offset,
16
+ }
17
+
18
+ if (flatMode) params.flat_mode = flatMode // 平铺模式
19
+ if (this.ctx.user.checkHasBasicUserInfo()) {
20
+ params.name = this.ctx.user.data.nick
21
+ params.email = this.ctx.user.data.email
22
+ }
23
+
24
+ if (paramsEditor) paramsEditor(params)
25
+
26
+ return this.POST<ListData>('/get', params)
27
+ }
28
+
29
+ /** 评论 · 创建 */
30
+ public async add(comment: { nick: string, email: string, link: string, content: string, rid: number, page_key: string, page_title?: string, site_name?: string }) {
31
+ const params: any = {
32
+ name: comment.nick,
33
+ email: comment.email,
34
+ link: comment.link,
35
+ content: comment.content,
36
+ rid: comment.rid,
37
+ page_key: comment.page_key,
38
+ ua: await Utils.getCorrectUserAgent(), // 需要后端支持,获取修正后的 UA
39
+ }
40
+
41
+ if (comment.page_title) params.page_title = comment.page_title
42
+ if (comment.site_name) params.site_name = comment.site_name
43
+
44
+ const data = await this.POST<any>('/add', params)
45
+ return (data.comment as CommentData)
46
+ }
47
+
48
+ /** 评论 · 修改 */
49
+ public async commentEdit(data: Partial<CommentData>) {
50
+ const params: any = {
51
+ ...data,
52
+ }
53
+
54
+ const d = await this.POST<any>('/admin/comment-edit', params)
55
+ return (d.comment as CommentData)
56
+ }
57
+
58
+ /** 评论 · 删除 */
59
+ public commentDel(commentID: number, siteName?: string) {
60
+ const params: any = {
61
+ id: String(commentID),
62
+ site_name: siteName || '',
63
+ }
64
+
65
+ return this.POST('/admin/comment-del', params)
66
+ }
67
+
68
+ /** 投票 */
69
+ public async vote(targetID: number, type: string) {
70
+ const params: any = {
71
+ site_name: this.ctx.conf.site || '',
72
+ target_id: targetID,
73
+ type,
74
+ }
75
+
76
+ if (this.ctx.user.checkHasBasicUserInfo()) {
77
+ params.name = this.ctx.user.data.nick
78
+ params.email = this.ctx.user.data.email
79
+ }
80
+
81
+ const data = await this.POST<any>('/vote', params)
82
+ return (data as {up: number, down: number})
83
+ }
84
+ }
package/src/api/index.ts CHANGED
@@ -1,373 +1,37 @@
1
- import { CommentData, ListData, UserData, PageData, SiteData, NotifyData } from '~/types/artalk-data'
2
- import ArtalkConfig from '~/types/artalk-config'
3
1
  import Context from '~/types/context'
4
- import { Fetch, ToFormData, POST, GET } from './request'
5
- import * as Utils from '../lib/utils'
6
2
  import 'abortcontroller-polyfill/dist/polyfill-patch-fetch'
7
3
 
8
- export default class Api {
9
- private ctx: Context
10
- private baseURL: string
4
+ import comment from './comment'
5
+ import page from './page'
6
+ import site from './site'
7
+ import user from './user'
8
+ import system from './system'
9
+ import captcha from './captcha'
10
+ import admin from './admin'
11
+ import upload from './upload'
12
+
13
+ const ApiComponents = {
14
+ comment, page, site,
15
+ user, system, captcha,
16
+ admin, upload
17
+ }
18
+
19
+ class Api {
20
+ protected ctx: Context
21
+ public baseURL: string
11
22
 
12
23
  constructor (ctx: Context) {
13
24
  this.ctx = ctx
14
25
  this.baseURL = `${ctx.conf.server}/api`
15
- }
16
-
17
- // ============================
18
- // 评论 Comment
19
- // ============================
20
-
21
- /** 评论 · 获取 */
22
- public get(offset: number, pageSize: number, flatMode?: boolean, paramsEditor?: (params: any) => void) {
23
- const params: any = {
24
- page_key: this.ctx.conf.pageKey,
25
- site_name: this.ctx.conf.site || '',
26
- limit: pageSize,
27
- offset,
28
- }
29
-
30
- if (flatMode) params.flat_mode = flatMode // 平铺模式
31
- if (this.ctx.user.checkHasBasicUserInfo()) {
32
- params.name = this.ctx.user.data.nick
33
- params.email = this.ctx.user.data.email
34
- }
35
-
36
- if (paramsEditor) paramsEditor(params)
37
-
38
- return POST<ListData>(this.ctx, `${this.baseURL}/get`, params)
39
- }
40
-
41
- /** 评论 · 创建 */
42
- public async add(comment: { nick: string, email: string, link: string, content: string, rid: number, page_key: string, page_title?: string, site_name?: string }) {
43
- const params: any = {
44
- name: comment.nick,
45
- email: comment.email,
46
- link: comment.link,
47
- content: comment.content,
48
- rid: comment.rid,
49
- page_key: comment.page_key,
50
- ua: await Utils.getCorrectUserAgent(), // 需要后端支持,获取修正后的 UA
51
- }
52
-
53
- if (comment.page_title) params.page_title = comment.page_title
54
- if (comment.site_name) params.site_name = comment.site_name
55
-
56
- const data = await POST<any>(this.ctx, `${this.baseURL}/add`, params)
57
- return (data.comment as CommentData)
58
- }
59
-
60
- /** 评论 · 修改 */
61
- public async commentEdit(data: CommentData) {
62
- const params: any = {
63
- ...data,
64
- }
65
-
66
- const d = await POST<any>(this.ctx, `${this.baseURL}/admin/comment-edit`, params)
67
- return (d.comment as CommentData)
68
- }
69
-
70
- /** 评论 · 删除 */
71
- public commentDel(commentID: number, siteName?: string) {
72
- const params: any = {
73
- id: String(commentID),
74
- site_name: siteName || '',
75
- }
76
-
77
- return POST(this.ctx, `${this.baseURL}/admin/comment-del`, params)
78
- }
79
-
80
- // ============================
81
- // 用户 User
82
- // ============================
83
-
84
- /** 用户 · 登录 */
85
- public async login(name: string, email: string, password: string) {
86
- const params: any = {
87
- name, email, password
88
- }
89
-
90
- if (this.ctx.conf.site) params.site_name = this.ctx.conf.site
91
-
92
- const data = await POST<any>(this.ctx, `${this.baseURL}/login`, params)
93
- return (data.token as string)
94
- }
95
26
 
96
- /** 用户 · 获取 */
97
- public userGet(name: string, email: string) {
98
- const ctrl = new AbortController()
99
- const params: any = {
100
- name, email, site_name: (this.ctx.conf.site || '')
101
- }
102
-
103
- const req = Fetch(this.ctx, `${this.baseURL}/user-get`, {
104
- method: 'POST',
105
- body: ToFormData(params),
106
- signal: ctrl.signal,
107
- }).then((json) => ({
108
- user: json.data.user as UserData|null,
109
- is_login: json.data.is_login as boolean,
110
- unread: (json.data.unread || []) as NotifyData[],
111
- unread_count: json.data.unread_count || 0,
112
- }))
113
-
114
- return {
115
- req,
116
- abort: () => { ctrl.abort() },
117
- }
118
- }
119
-
120
- /** 用户 · 登录状态 */
121
- public async loginStatus() {
122
- const data = await POST<any>(this.ctx, `${this.baseURL}/login-status`, {
123
- name: this.ctx.user.data.nick,
124
- email: this.ctx.user.data.email
27
+ Object.entries(ApiComponents).forEach(([key, ApiComponent]) => {
28
+ this[key] = new ApiComponent(this, this.ctx)
125
29
  })
126
- return (data || { is_login: false, is_admin: false }) as { is_login: boolean, is_admin: boolean }
127
- }
128
-
129
- // ============================
130
- // 页面 Page
131
- // ============================
132
-
133
- /** 页面 · 获取 */
134
- public async pageGet(siteName?: string, offset?: number, limit?: number) {
135
- const params: any = {
136
- site_name: siteName || '',
137
- offset: offset || 0,
138
- limit: limit || 15,
139
- }
140
-
141
- const d = await POST<any>(this.ctx, `${this.baseURL}/admin/page-get`, params)
142
- return (d as { pages: PageData[], total: number })
143
- }
144
-
145
- /** 页面 · 修改 */
146
- public async pageEdit(data: PageData) {
147
- const params: any = {
148
- id: data.id,
149
- key: data.key,
150
- title: data.title,
151
- admin_only: data.admin_only,
152
- site_name: data.site_name || this.ctx.conf.site,
153
- }
154
-
155
- const d = await POST<any>(this.ctx, `${this.baseURL}/admin/page-edit`, params)
156
- return (d.page as PageData)
157
- }
158
-
159
- /** 页面 · 删除 */
160
- public pageDel(pageKey: string, siteName?: string) {
161
- const params: any = {
162
- key: String(pageKey),
163
- site_name: siteName || '',
164
- }
165
-
166
- return POST(this.ctx, `${this.baseURL}/admin/page-del`, params)
167
- }
168
-
169
- /** 页面 · 数据更新 */
170
- public async pageFetch(id?: number, siteName?: string, getStatus?: boolean) {
171
- const params: any = {}
172
- if (id) params.id = id
173
- if (siteName) params.site_name = siteName
174
- if (getStatus) params.get_status = getStatus
175
-
176
- const d = await POST<any>(this.ctx, `${this.baseURL}/admin/page-fetch`, params)
177
- return (d as any)
178
- }
179
-
180
- // ============================
181
- // 站点 Site
182
- // ============================
183
-
184
- /** 站点 · 获取 */
185
- public async siteGet() {
186
- const params: any = {}
187
-
188
- const d = await POST<any>(this.ctx, `${this.baseURL}/admin/site-get`, params)
189
- return (d.sites as SiteData[])
190
- }
191
-
192
- /** 站点 · 创建 */
193
- public async siteAdd(name: string, urls: string) {
194
- const params: any = {
195
- name, urls,
196
- }
197
-
198
- const d = await POST<any>(this.ctx, `${this.baseURL}/admin/site-add`, params)
199
- return (d.site as SiteData)
200
- }
201
-
202
- /** 站点 · 修改 */
203
- public async siteEdit(data: SiteData) {
204
- const params: any = {
205
- id: data.id,
206
- name: data.name || '',
207
- urls: data.urls || '',
208
- }
209
-
210
- const d = await POST<any>(this.ctx, `${this.baseURL}/admin/site-edit`, params)
211
- return (d.site as SiteData)
212
- }
213
-
214
- /** 站点 · 删除 */
215
- public siteDel(id: number, delContent = false) {
216
- const params: any = { id, del_content: delContent }
217
-
218
- return POST(this.ctx, `${this.baseURL}/admin/site-del`, params)
219
- }
220
-
221
- /** 导出 */
222
- public async export() {
223
- const d = await Fetch(this.ctx, `${this.baseURL}/admin/export`, { method: 'POST' }, 0)
224
- return (d.data?.data || '' as string)
225
- }
226
-
227
- // ============================
228
- // 杂项
229
- // ============================
230
-
231
- /** 投票 */
232
- public async vote(targetID: number, type: string) {
233
- const params: any = {
234
- site_name: this.ctx.conf.site || '',
235
- target_id: targetID,
236
- type,
237
- }
238
-
239
- if (this.ctx.user.checkHasBasicUserInfo()) {
240
- params.name = this.ctx.user.data.nick
241
- params.email = this.ctx.user.data.email
242
- }
243
-
244
- const data = await POST<any>(this.ctx, `${this.baseURL}/vote`, params)
245
- return (data as {up: number, down: number})
246
- }
247
-
248
- /** 已读标记 */
249
- public markRead(notifyKey: string, readAll = false) {
250
- const params: any = {
251
- site_name: this.ctx.conf.site || '',
252
- notify_key: notifyKey,
253
- }
254
-
255
- if (readAll) {
256
- delete params.notify_key
257
- params.read_all = true
258
- params.name = this.ctx.user.data.nick
259
- params.email = this.ctx.user.data.email
260
- }
261
-
262
- return POST(this.ctx, `${this.baseURL}/mark-read`, params)
263
30
  }
31
+ }
264
32
 
265
- /** PV */
266
- public async pv() {
267
- const params: any = {
268
- site_name: this.ctx.conf.site || '',
269
- page_key: this.ctx.conf.pageKey || '',
270
- page_title: this.ctx.conf.pageTitle || ''
271
- }
272
-
273
- const p = await POST<any>(this.ctx, `${this.baseURL}/pv`, params)
274
- return p.pv as number
275
- }
276
-
277
- /** 统计 */
278
- public async stat(
279
- type: 'latest_comments'|'latest_pages'|'pv_most_pages'|'comment_most_pages'|
280
- 'page_pv'|'site_pv'|'page_comment'|'site_comment',
281
- pageKeys?: string|string[],
282
- limit?: number
283
- ) {
284
- const params: any = {
285
- type,
286
- site_name: this.ctx.conf.site || '',
287
- }
288
-
289
- if (pageKeys) params.page_keys = Array.isArray(pageKeys) ? pageKeys.join(',') : pageKeys
290
- if (limit) params.limit = limit
291
-
292
- const data = await POST<PageData[]|CommentData[]|object|number>(this.ctx, `${this.baseURL}/stat`, params)
293
- return data
294
- }
295
-
296
- /** 图片上传 */
297
- public async imgUpload(file: File) {
298
- const params: any = {
299
- name: this.ctx.user.data.nick,
300
- email: this.ctx.user.data.email,
301
- page_key: this.ctx.conf.pageKey,
302
- }
303
-
304
- if (this.ctx.conf.site) params.site_name = this.ctx.conf.site
305
-
306
- const form = ToFormData(params)
307
- form.set('file', file)
308
-
309
- const init: RequestInit = {
310
- method: 'POST',
311
- body: form
312
- }
313
-
314
- const json = await Fetch(this.ctx, `${this.baseURL}/img-upload`, init)
315
- return ((json.data || {}) as any) as { img_file: string, img_url: string }
316
- }
317
-
318
- /** 获取配置 */
319
- public async conf() {
320
- const data = await POST<any>(this.ctx, `${this.baseURL}/conf`)
321
- const conf = (data.frontend_conf || {}) as ArtalkConfig
322
-
323
- // Patch: `emoticons` config string to json
324
- if (conf.emoticons && typeof conf.emoticons === "string") {
325
- conf.emoticons = conf.emoticons.trim()
326
- if (conf.emoticons.startsWith("[") || conf.emoticons.startsWith("{")) {
327
- conf.emoticons = JSON.parse(conf.emoticons) // pase json
328
- } else if (conf.emoticons === "false") {
329
- conf.emoticons = false
330
- }
331
- }
332
-
333
- return conf
334
- }
335
-
336
- // ============================
337
- // 验证码
338
- // ============================
339
-
340
- /** 验证码 · 获取 */
341
- public async captchaGet() {
342
- const data = await POST<any>(this.ctx, `${this.baseURL}/captcha/refresh`)
343
- return (data.img_data || '') as string
344
- }
345
-
346
- /** 验证码 · 检验 */
347
- public async captchaCheck(value: string) {
348
- const data = await POST<any>(this.ctx, `${this.baseURL}/captcha/check`, { value })
349
- return (data.img_data || '') as string
350
- }
351
-
352
- /** 验证码 · 状态 */
353
- public async captchaStatus() {
354
- const data = await POST<any>(this.ctx, `${this.baseURL}/captcha/status`)
355
- return (data || { is_pass: false }) as { is_pass: boolean }
356
- }
357
-
358
- // ============================
359
- // 管理员缓存操作
360
- // ============================
361
-
362
- /** 缓存清除 */
363
- public cacheFlushAll() {
364
- const params: any = { flush_all: true }
365
- return POST(this.ctx, `${this.baseURL}/admin/cache-flush`, params)
366
- }
33
+ type TC = typeof ApiComponents
34
+ type AC = { [K in keyof TC]: InstanceType<TC[K]> }
35
+ interface Api extends AC {}
367
36
 
368
- /** 缓存预热 */
369
- public cacheWarmUp() {
370
- const params: any = {}
371
- return POST(this.ctx, `${this.baseURL}/admin/cache-warm`, params)
372
- }
373
- }
37
+ export default Api