@axium/tasks 0.2.4 → 0.3.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/db.json +71 -0
- package/dist/common.d.ts +0 -2
- package/dist/hooks.d.ts +0 -3
- package/dist/hooks.js +1 -50
- package/dist/server.d.ts +1 -6
- package/dist/server.js +18 -46
- package/package.json +8 -6
package/db.json
ADDED
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "../server/schemas/db.json",
|
|
3
|
+
"format": 0,
|
|
4
|
+
"versions": [
|
|
5
|
+
{
|
|
6
|
+
"delta": false,
|
|
7
|
+
"tables": {
|
|
8
|
+
"task_lists": {
|
|
9
|
+
"columns": {
|
|
10
|
+
"id": { "type": "uuid", "required": true, "primary": true, "default": "gen_random_uuid()" },
|
|
11
|
+
"userId": { "type": "uuid", "required": true, "references": "users.id", "onDelete": "cascade" },
|
|
12
|
+
"created": { "type": "timestamptz", "required": true, "default": "now()" },
|
|
13
|
+
"publicPermission": { "type": "integer", "required": true, "default": 0 },
|
|
14
|
+
"name": { "type": "text", "required": true },
|
|
15
|
+
"description": { "type": "text" }
|
|
16
|
+
}
|
|
17
|
+
},
|
|
18
|
+
"tasks": {
|
|
19
|
+
"columns": {
|
|
20
|
+
"id": { "type": "uuid", "required": true, "primary": true, "default": "gen_random_uuid()" },
|
|
21
|
+
"created": { "type": "timestamptz", "required": true, "default": "now()" },
|
|
22
|
+
"listId": { "type": "uuid", "required": true, "references": "task_lists.id", "onDelete": "cascade" },
|
|
23
|
+
"summary": { "type": "text", "required": true },
|
|
24
|
+
"description": { "type": "text" },
|
|
25
|
+
"parentId": { "type": "uuid", "references": "tasks.id", "onDelete": "cascade" },
|
|
26
|
+
"completed": { "type": "boolean", "required": true, "default": false },
|
|
27
|
+
"due": { "type": "timestamptz" }
|
|
28
|
+
}
|
|
29
|
+
},
|
|
30
|
+
"acl.task_lists": {
|
|
31
|
+
"columns": {
|
|
32
|
+
"userId": { "type": "uuid", "required": true, "references": "users.id", "onDelete": "cascade" },
|
|
33
|
+
"itemId": { "type": "uuid", "required": true, "references": "task_lists.id", "onDelete": "cascade" },
|
|
34
|
+
"createdAt": { "type": "timestamptz", "required": true, "default": "now()" },
|
|
35
|
+
"permission": { "type": "integer", "required": true, "check": "permission >= 0 AND permission <= 5" }
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
},
|
|
39
|
+
"indexes": ["task_lists:userId", "acl.task_lists:userId", "acl.task_lists:itemId", "tasks:listId", "tasks:parentId"]
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
"delta": true,
|
|
43
|
+
"alter_tables": {
|
|
44
|
+
"task_lists": {
|
|
45
|
+
"drop_columns": ["publicPermission"]
|
|
46
|
+
},
|
|
47
|
+
"acl.task_lists": {
|
|
48
|
+
"drop_constraints": ["PK_acl_task_lists"],
|
|
49
|
+
"drop_columns": ["permission"],
|
|
50
|
+
"add_columns": {
|
|
51
|
+
"role": { "type": "text" },
|
|
52
|
+
"tag": { "type": "text" },
|
|
53
|
+
"read": { "type": "boolean", "required": true, "default": false },
|
|
54
|
+
"edit": { "type": "boolean", "required": true, "default": false },
|
|
55
|
+
"manage": { "type": "boolean", "required": true, "default": false }
|
|
56
|
+
},
|
|
57
|
+
"alter_columns": {
|
|
58
|
+
"userId": { "ops": ["drop_required"] }
|
|
59
|
+
},
|
|
60
|
+
"add_constraints": {
|
|
61
|
+
"unique_task_lists": { "type": "unique", "on": ["itemId", "userId", "role", "tag"], "nulls_not_distinct": true }
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
],
|
|
67
|
+
"wipe": ["task_lists", "tasks", "acl.task_lists"],
|
|
68
|
+
"acl_tables": {
|
|
69
|
+
"task_lists": "acl.task_lists"
|
|
70
|
+
}
|
|
71
|
+
}
|
package/dist/common.d.ts
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import type { Permission } from '@axium/core';
|
|
2
1
|
import type { WithRequired } from 'utilium';
|
|
3
2
|
import * as z from 'zod';
|
|
4
3
|
export declare const TaskInit: z.ZodObject<{
|
|
@@ -27,7 +26,6 @@ export interface TaskList extends TaskListInit {
|
|
|
27
26
|
id: string;
|
|
28
27
|
userId: string;
|
|
29
28
|
created: Date;
|
|
30
|
-
publicPermission: Permission;
|
|
31
29
|
tasks?: Task[];
|
|
32
30
|
}
|
|
33
31
|
declare module '@axium/core/api' {
|
package/dist/hooks.d.ts
CHANGED
package/dist/hooks.js
CHANGED
|
@@ -1,56 +1,7 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import * as acl from '@axium/server/acl';
|
|
3
|
-
import { count, createIndex, database, warnExists } from '@axium/server/database';
|
|
4
|
-
import { sql } from 'kysely';
|
|
1
|
+
import { count } from '@axium/server/database';
|
|
5
2
|
import './common.js';
|
|
6
3
|
import './server.js';
|
|
7
4
|
export async function statusText() {
|
|
8
5
|
const { tasks, task_lists } = await count('tasks', 'task_lists');
|
|
9
6
|
return `${tasks} tasks, ${task_lists} lists`;
|
|
10
7
|
}
|
|
11
|
-
export async function db_init() {
|
|
12
|
-
start('Creating table task_lists');
|
|
13
|
-
await database.schema
|
|
14
|
-
.createTable('task_lists')
|
|
15
|
-
.addColumn('id', 'uuid', col => col.primaryKey().defaultTo(sql `gen_random_uuid()`))
|
|
16
|
-
.addColumn('userId', 'uuid', col => col.notNull().references('users.id').onDelete('cascade'))
|
|
17
|
-
.addColumn('created', 'timestamptz', col => col.notNull().defaultTo(sql `now()`))
|
|
18
|
-
.addColumn('publicPermission', 'integer', col => col.notNull().defaultTo(0))
|
|
19
|
-
.addColumn('name', 'text', col => col.notNull())
|
|
20
|
-
.addColumn('description', 'text')
|
|
21
|
-
.execute()
|
|
22
|
-
.then(done)
|
|
23
|
-
.catch(warnExists);
|
|
24
|
-
await createIndex('task_lists', 'userId');
|
|
25
|
-
await acl.createTable('task_lists');
|
|
26
|
-
start('Creating table tasks');
|
|
27
|
-
await database.schema
|
|
28
|
-
.createTable('tasks')
|
|
29
|
-
.addColumn('id', 'uuid', col => col.primaryKey().defaultTo(sql `gen_random_uuid()`))
|
|
30
|
-
.addColumn('created', 'timestamptz', col => col.notNull().defaultTo(sql `now()`))
|
|
31
|
-
.addColumn('listId', 'uuid', col => col.notNull().references('task_lists.id').onDelete('cascade'))
|
|
32
|
-
.addColumn('summary', 'text', col => col.notNull())
|
|
33
|
-
.addColumn('description', 'text')
|
|
34
|
-
.addColumn('parentId', 'uuid', col => col.references('tasks.id').onDelete('cascade'))
|
|
35
|
-
.addColumn('completed', 'boolean', col => col.notNull().defaultTo(false))
|
|
36
|
-
.addColumn('due', 'timestamptz')
|
|
37
|
-
.execute()
|
|
38
|
-
.then(done)
|
|
39
|
-
.catch(warnExists);
|
|
40
|
-
await createIndex('tasks', 'listId');
|
|
41
|
-
await createIndex('tasks', 'parentId');
|
|
42
|
-
}
|
|
43
|
-
export async function db_wipe() {
|
|
44
|
-
start('Wiping data from tasks');
|
|
45
|
-
await database.deleteFrom('tasks').execute().then(done);
|
|
46
|
-
start('Wiping data from task_lists');
|
|
47
|
-
await database.deleteFrom('task_lists').execute().then(done);
|
|
48
|
-
await acl.wipeTable('task_lists');
|
|
49
|
-
}
|
|
50
|
-
export async function remove() {
|
|
51
|
-
start('Dropping table tasks');
|
|
52
|
-
await database.schema.dropTable('tasks').execute().then(done);
|
|
53
|
-
start('Dropping table task_lists');
|
|
54
|
-
await database.schema.dropTable('task_lists').execute().then(done);
|
|
55
|
-
await acl.dropTable('task_lists');
|
|
56
|
-
}
|
package/dist/server.d.ts
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { Permission } from '@axium/core';
|
|
2
1
|
import type { Generated, GeneratedAlways } from 'kysely';
|
|
3
2
|
declare module '@axium/server/database' {
|
|
4
3
|
interface Schema {
|
|
@@ -16,13 +15,9 @@ declare module '@axium/server/database' {
|
|
|
16
15
|
id: GeneratedAlways<string>;
|
|
17
16
|
userId: string;
|
|
18
17
|
created: GeneratedAlways<Date>;
|
|
19
|
-
publicPermission: Generated<Permission>;
|
|
20
18
|
name: string;
|
|
21
19
|
description?: string | null;
|
|
22
20
|
};
|
|
23
|
-
|
|
24
|
-
interface ExpectedSchema {
|
|
25
|
-
tasks: ColumnTypes<Schema['tasks']>;
|
|
26
|
-
task_lists: ColumnTypes<Schema['task_lists']>;
|
|
21
|
+
'acl.task_lists': DBAccessControl & DBBool<'read' | 'edit' | 'manage'>;
|
|
27
22
|
}
|
|
28
23
|
}
|
package/dist/server.js
CHANGED
|
@@ -1,34 +1,14 @@
|
|
|
1
|
-
import { Permission } from '@axium/core';
|
|
2
1
|
import { checkAuthForItem, checkAuthForUser } from '@axium/server/auth';
|
|
3
|
-
import { database
|
|
2
|
+
import { database } from '@axium/server/database';
|
|
4
3
|
import { parseBody, withError } from '@axium/server/requests';
|
|
5
4
|
import { addRoute } from '@axium/server/routes';
|
|
5
|
+
import { jsonArrayFrom } from 'kysely/helpers/postgres';
|
|
6
6
|
import * as z from 'zod';
|
|
7
7
|
import { TaskInit, TaskListInit, TaskListUpdate } from './common.js';
|
|
8
|
-
import { jsonArrayFrom } from 'kysely/helpers/postgres';
|
|
9
|
-
expectedTypes.tasks = {
|
|
10
|
-
id: { type: 'uuid', required: true, hasDefault: true },
|
|
11
|
-
created: { type: 'timestamptz', required: true, hasDefault: true },
|
|
12
|
-
summary: { type: 'text', required: true },
|
|
13
|
-
description: { type: 'text' },
|
|
14
|
-
listId: { type: 'uuid', required: true },
|
|
15
|
-
parentId: { type: 'uuid' },
|
|
16
|
-
completed: { type: 'bool', required: true, hasDefault: true },
|
|
17
|
-
due: { type: 'timestamptz' },
|
|
18
|
-
};
|
|
19
|
-
expectedTypes.task_lists = {
|
|
20
|
-
id: { type: 'uuid', required: true, hasDefault: true },
|
|
21
|
-
userId: { type: 'uuid', required: true },
|
|
22
|
-
created: { type: 'timestamptz', required: true, hasDefault: true },
|
|
23
|
-
publicPermission: { type: 'int4', required: true, hasDefault: true },
|
|
24
|
-
name: { type: 'text', required: true },
|
|
25
|
-
description: { type: 'text' },
|
|
26
|
-
};
|
|
27
8
|
addRoute({
|
|
28
9
|
path: '/api/users/:id/task_lists',
|
|
29
10
|
params: { id: z.uuid() },
|
|
30
|
-
async GET(request,
|
|
31
|
-
const userId = params.id;
|
|
11
|
+
async GET(request, { id: userId }) {
|
|
32
12
|
await checkAuthForUser(request, userId);
|
|
33
13
|
const lists = await database
|
|
34
14
|
.selectFrom('task_lists')
|
|
@@ -42,9 +22,8 @@ addRoute({
|
|
|
42
22
|
tasks: list.tasks.map(t => ({ ...t, created: new Date(t.created), due: t.due ? new Date(t.due) : null })),
|
|
43
23
|
}));
|
|
44
24
|
},
|
|
45
|
-
async PUT(request,
|
|
25
|
+
async PUT(request, { id: userId }) {
|
|
46
26
|
const init = await parseBody(request, TaskListInit);
|
|
47
|
-
const userId = params.id;
|
|
48
27
|
await checkAuthForUser(request, userId);
|
|
49
28
|
return await database
|
|
50
29
|
.insertInto('task_lists')
|
|
@@ -57,9 +36,8 @@ addRoute({
|
|
|
57
36
|
addRoute({
|
|
58
37
|
path: '/api/task_lists/:id',
|
|
59
38
|
params: { id: z.uuid() },
|
|
60
|
-
async GET(request,
|
|
61
|
-
const
|
|
62
|
-
const { item } = await checkAuthForItem(request, 'task_lists', id, Permission.Read);
|
|
39
|
+
async GET(request, { id }) {
|
|
40
|
+
const { item } = await checkAuthForItem(request, 'task_lists', id, { read: true });
|
|
63
41
|
const tasks = await database
|
|
64
42
|
.selectFrom('tasks')
|
|
65
43
|
.selectAll()
|
|
@@ -68,10 +46,9 @@ addRoute({
|
|
|
68
46
|
.catch(withError('Could not get tasks'));
|
|
69
47
|
return Object.assign(item, { tasks });
|
|
70
48
|
},
|
|
71
|
-
async PUT(request,
|
|
72
|
-
const listId = params.id;
|
|
49
|
+
async PUT(request, { id: listId }) {
|
|
73
50
|
const init = await parseBody(request, TaskInit.omit({ listId: true }));
|
|
74
|
-
await checkAuthForItem(request, 'task_lists', listId,
|
|
51
|
+
await checkAuthForItem(request, 'task_lists', listId, { edit: true });
|
|
75
52
|
return await database
|
|
76
53
|
.insertInto('tasks')
|
|
77
54
|
.values({ summary: '', ...init, listId })
|
|
@@ -79,9 +56,8 @@ addRoute({
|
|
|
79
56
|
.executeTakeFirstOrThrow()
|
|
80
57
|
.catch(withError('Could not update task list'));
|
|
81
58
|
},
|
|
82
|
-
async PATCH(request,
|
|
83
|
-
|
|
84
|
-
await checkAuthForItem(request, 'task_lists', id, Permission.Edit);
|
|
59
|
+
async PATCH(request, { id }) {
|
|
60
|
+
await checkAuthForItem(request, 'task_lists', id, { edit: true });
|
|
85
61
|
const init = await parseBody(request, TaskListInit);
|
|
86
62
|
return await database
|
|
87
63
|
.updateTable('task_lists')
|
|
@@ -91,10 +67,9 @@ addRoute({
|
|
|
91
67
|
.executeTakeFirstOrThrow()
|
|
92
68
|
.catch(withError('Could not update task list'));
|
|
93
69
|
},
|
|
94
|
-
async POST(request,
|
|
70
|
+
async POST(request, { id }) {
|
|
95
71
|
const body = await parseBody(request, TaskListUpdate);
|
|
96
|
-
|
|
97
|
-
await checkAuthForItem(request, 'task_lists', id, Permission.Edit);
|
|
72
|
+
await checkAuthForItem(request, 'task_lists', id, { edit: true });
|
|
98
73
|
if (typeof body.all_completed == 'boolean') {
|
|
99
74
|
await database
|
|
100
75
|
.updateTable('tasks')
|
|
@@ -107,9 +82,8 @@ addRoute({
|
|
|
107
82
|
}
|
|
108
83
|
return {};
|
|
109
84
|
},
|
|
110
|
-
async DELETE(request,
|
|
111
|
-
|
|
112
|
-
await checkAuthForItem(request, 'task_lists', id, Permission.Manage);
|
|
85
|
+
async DELETE(request, { id }) {
|
|
86
|
+
await checkAuthForItem(request, 'task_lists', id, { manage: true });
|
|
113
87
|
return await database
|
|
114
88
|
.deleteFrom('task_lists')
|
|
115
89
|
.where('id', '=', id)
|
|
@@ -121,16 +95,15 @@ addRoute({
|
|
|
121
95
|
addRoute({
|
|
122
96
|
path: '/api/tasks/:id',
|
|
123
97
|
params: { id: z.uuid() },
|
|
124
|
-
async PATCH(request,
|
|
98
|
+
async PATCH(request, { id }) {
|
|
125
99
|
const init = await parseBody(request, TaskInit.omit({ listId: true }));
|
|
126
|
-
const id = params.id;
|
|
127
100
|
const task = await database
|
|
128
101
|
.selectFrom('tasks')
|
|
129
102
|
.select('listId')
|
|
130
103
|
.where('id', '=', id)
|
|
131
104
|
.executeTakeFirstOrThrow()
|
|
132
105
|
.catch(withError('Could not get task'));
|
|
133
|
-
await checkAuthForItem(request, 'task_lists', task.listId,
|
|
106
|
+
await checkAuthForItem(request, 'task_lists', task.listId, { edit: true });
|
|
134
107
|
return await database
|
|
135
108
|
.updateTable('tasks')
|
|
136
109
|
.set(init)
|
|
@@ -139,15 +112,14 @@ addRoute({
|
|
|
139
112
|
.executeTakeFirstOrThrow()
|
|
140
113
|
.catch(withError('Could not update task'));
|
|
141
114
|
},
|
|
142
|
-
async DELETE(request,
|
|
143
|
-
const id = params.id;
|
|
115
|
+
async DELETE(request, { id }) {
|
|
144
116
|
const task = await database
|
|
145
117
|
.selectFrom('tasks')
|
|
146
118
|
.select('listId')
|
|
147
119
|
.where('id', '=', id)
|
|
148
120
|
.executeTakeFirstOrThrow()
|
|
149
121
|
.catch(withError('Could not fetch task'));
|
|
150
|
-
await checkAuthForItem(request, 'task_lists', task.listId,
|
|
122
|
+
await checkAuthForItem(request, 'task_lists', task.listId, { manage: true });
|
|
151
123
|
return await database
|
|
152
124
|
.deleteFrom('tasks')
|
|
153
125
|
.where('id', '=', id)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@axium/tasks",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"author": "James Prevett <axium@jamespre.dev>",
|
|
5
5
|
"description": "Tasks for Axium",
|
|
6
6
|
"funding": {
|
|
@@ -28,15 +28,16 @@
|
|
|
28
28
|
"files": [
|
|
29
29
|
"dist",
|
|
30
30
|
"lib",
|
|
31
|
-
"routes"
|
|
31
|
+
"routes",
|
|
32
|
+
"db.json"
|
|
32
33
|
],
|
|
33
34
|
"scripts": {
|
|
34
35
|
"build": "tsc"
|
|
35
36
|
},
|
|
36
37
|
"peerDependencies": {
|
|
37
|
-
"@axium/client": ">=0.
|
|
38
|
-
"@axium/core": ">=0.
|
|
39
|
-
"@axium/server": ">=0.
|
|
38
|
+
"@axium/client": ">=0.9.0",
|
|
39
|
+
"@axium/core": ">=0.12.0",
|
|
40
|
+
"@axium/server": ">=0.28.0",
|
|
40
41
|
"@sveltejs/kit": "^2.27.3",
|
|
41
42
|
"utilium": "^2.3.8"
|
|
42
43
|
},
|
|
@@ -46,7 +47,8 @@
|
|
|
46
47
|
"axium": {
|
|
47
48
|
"server": {
|
|
48
49
|
"routes": "routes",
|
|
49
|
-
"hooks": "./dist/hooks.js"
|
|
50
|
+
"hooks": "./dist/hooks.js",
|
|
51
|
+
"db": "./db.json"
|
|
50
52
|
},
|
|
51
53
|
"apps": [
|
|
52
54
|
{
|