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.
- package/dist/Artalk.css +1 -1
- package/dist/Artalk.es.js +3184 -2888
- package/dist/Artalk.iife.js +1 -1
- package/dist/Artalk.js +1 -1
- package/dist/ArtalkLite.css +1 -1
- package/dist/ArtalkLite.es.js +3157 -2887
- package/dist/ArtalkLite.iife.js +1 -1
- package/dist/ArtalkLite.js +1 -1
- package/dist/src/api/admin.d.ts +10 -0
- package/dist/src/api/api-base.d.ts +14 -0
- package/dist/src/api/captcha.d.ts +14 -0
- package/dist/src/api/comment.d.ts +29 -0
- package/dist/src/api/index.d.ts +31 -0
- package/dist/src/api/page.d.ts +22 -0
- package/dist/src/api/request.d.ts +12 -0
- package/dist/src/api/site.d.ts +17 -0
- package/dist/src/api/system.d.ts +13 -0
- package/dist/src/api/upload.d.ts +11 -0
- package/dist/src/api/user.d.ts +28 -0
- package/dist/src/artalk.d.ts +56 -0
- package/dist/src/comment/actions.d.ts +17 -0
- package/dist/src/comment/comment.d.ts +67 -0
- package/dist/src/comment/index.d.ts +2 -0
- package/dist/src/comment/render.d.ts +76 -0
- package/dist/src/components/action-btn.d.ts +52 -0
- package/dist/src/components/dialog.d.ts +18 -0
- package/dist/src/components/pagination.d.ts +30 -0
- package/dist/src/components/read-more-btn.d.ts +33 -0
- package/dist/src/context.d.ts +72 -0
- package/dist/src/defaults.d.ts +3 -0
- package/dist/src/editor/editor.d.ts +84 -0
- package/dist/src/editor/index.d.ts +2 -0
- package/dist/src/editor/plugs/editor-plug.d.ts +26 -0
- package/dist/src/editor/plugs/emoticons-plug.d.ts +36 -0
- package/dist/src/editor/plugs/header-input-plug.d.ts +13 -0
- package/dist/src/editor/plugs/preview-plug.d.ts +10 -0
- package/dist/src/editor/plugs/upload-plug.d.ts +10 -0
- package/dist/src/i18n/en.d.ts +69 -0
- package/dist/src/i18n/index.d.ts +294 -0
- package/dist/src/i18n/zh-CN.d.ts +3 -0
- package/dist/src/layer/index.d.ts +3 -0
- package/dist/src/layer/layer.d.ts +32 -0
- package/dist/src/layer/sidebar-layer.d.ts +20 -0
- package/dist/src/lib/checker/admin-checker.d.ts +3 -0
- package/dist/src/lib/checker/captcha-checker.d.ts +3 -0
- package/dist/src/lib/checker/index.d.ts +42 -0
- package/dist/src/lib/component.d.ts +12 -0
- package/dist/src/lib/detect.d.ts +10 -0
- package/dist/src/lib/stat.d.ts +15 -0
- package/dist/src/lib/ui.d.ts +23 -0
- package/dist/src/lib/user.d.ts +13 -0
- package/dist/src/lib/utils.d.ts +39 -0
- package/dist/src/list/index.d.ts +2 -0
- package/dist/src/list/list-lite.d.ts +63 -0
- package/dist/src/list/list-nest.d.ts +10 -0
- package/dist/src/list/list.d.ts +26 -0
- package/dist/src/main.d.ts +4 -0
- package/dist/types/artalk-config.d.ts +132 -0
- package/dist/types/artalk-data.d.ts +204 -0
- package/dist/types/context.d.ts +146 -0
- package/dist/types/event.d.ts +28 -0
- package/dist/types/global.d.ts +0 -0
- package/dist/types/plug.d.ts +4 -0
- package/index.html +3 -3
- package/package.json +5 -5
- package/src/api/admin.ts +18 -0
- package/src/api/api-base.ts +27 -0
- package/src/api/captcha.ts +24 -0
- package/src/api/comment.ts +84 -0
- package/src/api/index.ts +25 -361
- package/src/api/page.ts +85 -0
- package/src/api/request.ts +12 -8
- package/src/api/site.ts +51 -0
- package/src/api/system.ts +39 -0
- package/src/api/upload.ts +29 -0
- package/src/api/user.ts +75 -0
- package/src/artalk.ts +75 -76
- package/src/comment/actions.ts +3 -3
- package/src/comment/comment.ts +6 -9
- package/src/comment/render.ts +93 -47
- package/src/components/pagination.ts +0 -1
- package/src/context.ts +57 -18
- package/src/editor/editor.ts +111 -18
- package/src/editor/plugs/header-input-plug.ts +1 -1
- package/src/editor/plugs/upload-plug.ts +1 -1
- package/src/i18n/en.ts +3 -0
- package/src/i18n/index.ts +117 -2
- package/src/i18n/zh-CN.ts +4 -1
- package/src/layer/sidebar-layer.ts +1 -3
- package/src/lib/checker/admin-checker.ts +1 -1
- package/src/lib/checker/captcha-checker.ts +3 -3
- package/src/lib/stat.ts +2 -2
- package/src/lib/ui.ts +6 -0
- package/src/list/list-lite.ts +33 -25
- package/src/list/list.ts +3 -4
- package/src/main.ts +3 -0
- package/src/style/comment.less +2 -3
- package/src/style/main.less +6 -0
- package/test/CSRF.html +26 -0
- package/types/artalk-data.d.ts +3 -0
- package/types/context.d.ts +19 -1
- package/types/global.d.ts +0 -2
- package/vite-base.config.ts +9 -5
- package/vite.config.ts +5 -1
- 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
|
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.
|
|
35
|
-
<script src="//cdnjs.cloudflare.com/ajax/libs/highlight.js/11.
|
|
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.
|
|
4
|
-
"backendMinVersion": "2.
|
|
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": "./
|
|
25
|
+
"types": "./dist/src/main.d.ts",
|
|
26
26
|
"devDependencies": {
|
|
27
|
-
"@types/marked": "4.0.
|
|
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.
|
|
32
|
+
"marked": "^4.0.19",
|
|
33
33
|
"abortcontroller-polyfill": "^1.7.3"
|
|
34
34
|
},
|
|
35
35
|
"scripts": {
|
package/src/api/admin.ts
ADDED
|
@@ -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
|
-
|
|
9
|
-
|
|
10
|
-
|
|
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
|
-
|
|
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
|
-
|
|
266
|
-
|
|
267
|
-
|
|
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
|