Repository navigation
Expand file tree
/
Copy pathworkspaceRepository.ts
More file actions
184 lines (164 loc) · 4.62 KB
/
Copy pathworkspaceRepository.ts
File metadata and controls
184 lines (164 loc) · 4.62 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
/**
* 工作区仓储。
*
* 这里只处理工作区维度的数据读写,不掺杂内容块或附件逻辑,
* 这样后续要调整密码、过期策略或工作区元信息时,定位会更直接。
*/
import type { WorkspaceRecord } from "../types";
import { addMinutes, db, now, withTransaction } from "./shared";
/**
* 创建新工作区。
*/
export function createWorkspace(input: {
slug: string;
title: string;
description: string | null;
passwordHash: string | null;
expiresInMinutes: number;
}): WorkspaceRecord {
const timestamp = now();
const expiresAt = addMinutes(new Date(timestamp), input.expiresInMinutes);
const result = db
.prepare(
`
INSERT INTO workspaces (
slug, title, description, password_hash,
access_password_hash, access_password_updated_at,
expires_in_minutes, expires_at, created_at, updated_at
)
VALUES (?, ?, ?, ?, NULL, NULL, ?, ?, ?, ?)
`
)
.run(
input.slug,
input.title,
input.description,
input.passwordHash,
input.expiresInMinutes,
expiresAt,
timestamp,
timestamp
) as { lastInsertRowid: number | bigint };
return getWorkspaceById(Number(result.lastInsertRowid));
}
/**
* 根据 ID 获取工作区。
*/
export function getWorkspaceById(id: number): WorkspaceRecord {
const workspace = db.prepare("SELECT * FROM workspaces WHERE id = ?").get(id) as
| WorkspaceRecord
| undefined;
if (!workspace) {
throw new Error("Workspace not found");
}
return workspace;
}
/**
* 根据 slug 查找工作区。
*/
export function findWorkspaceBySlug(slug: string): WorkspaceRecord | null {
const workspace = db.prepare("SELECT * FROM workspaces WHERE slug = ?").get(slug) as
| WorkspaceRecord
| undefined;
return workspace ?? null;
}
/**
* 清理过期工作区。
*
* 这里只负责删除数据库记录;文件目录删除由上层服务统一处理,
* 避免 repository 直接操作文件系统带来职责混杂。
*/
export function purgeExpiredWorkspaces(referenceTime: string = now()): Array<{
id: number;
slug: string;
}> {
const expired = db
.prepare("SELECT id, slug FROM workspaces WHERE expires_at <= ?")
.all(referenceTime) as Array<{ id: number; slug: string }>;
if (expired.length === 0) {
return [];
}
withTransaction(() => {
const statement = db.prepare("DELETE FROM workspaces WHERE id = ?");
expired.forEach((workspace) => {
statement.run(workspace.id);
});
});
return expired;
}
/**
* 删除工作区。
*/
export function deleteWorkspace(id: number): WorkspaceRecord | null {
const workspace = db.prepare("SELECT * FROM workspaces WHERE id = ?").get(id) as
| WorkspaceRecord
| undefined;
if (!workspace) {
return null;
}
db.prepare("DELETE FROM workspaces WHERE id = ?").run(id);
return workspace;
}
/**
* 更新工作区标题、描述和有效期。
*/
export function updateWorkspaceMetadata(
id: number,
input: {
title: string;
description: string | null;
expiresInMinutes: number;
}
): WorkspaceRecord | null {
const workspace = db.prepare("SELECT * FROM workspaces WHERE id = ?").get(id) as
| WorkspaceRecord
| undefined;
if (!workspace) {
return null;
}
const timestamp = now();
const newExpiresAt = addMinutes(new Date(workspace.created_at), input.expiresInMinutes);
db.prepare(
"UPDATE workspaces SET title = ?, description = ?, expires_in_minutes = ?, expires_at = ?, updated_at = ? WHERE id = ?"
).run(input.title, input.description, input.expiresInMinutes, newExpiresAt, timestamp, id);
return getWorkspaceById(id);
}
/**
* 更新管理密码。
*/
export function updateWorkspaceEditPassword(
id: number,
passwordHash: string | null
): WorkspaceRecord | null {
const exists = db.prepare("SELECT 1 FROM workspaces WHERE id = ?").get(id) as
| { 1: number }
| undefined;
if (!exists) {
return null;
}
db.prepare("UPDATE workspaces SET password_hash = ?, updated_at = ? WHERE id = ?").run(
passwordHash,
now(),
id
);
return getWorkspaceById(id);
}
/**
* 更新访问密码。
*/
export function updateAccessPassword(
id: number,
passwordHash: string | null
): WorkspaceRecord | null {
const exists = db.prepare("SELECT 1 FROM workspaces WHERE id = ?").get(id) as
| { 1: number }
| undefined;
if (!exists) {
return null;
}
const timestamp = now();
db.prepare(
"UPDATE workspaces SET access_password_hash = ?, access_password_updated_at = ?, updated_at = ? WHERE id = ?"
).run(passwordHash, passwordHash ? timestamp : null, timestamp, id);
return getWorkspaceById(id);
}