lapeh 1.0.1 → 1.0.2
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/.env.example +16 -16
- package/bin/index.js +105 -105
- package/framework.md +105 -0
- package/nodemon.json +6 -0
- package/package.json +73 -70
- package/prisma/base.prisma +8 -8
- package/prisma/migrations/20251225163737_init/migration.sql +236 -236
- package/prisma/migrations/migration_lock.toml +3 -3
- package/prisma/schema.prisma +0 -7
- package/prisma.config.ts +15 -15
- package/readme.md +123 -120
- package/scripts/generate-jwt-secret.js +38 -38
- package/scripts/init-project.js +71 -0
- package/scripts/make-model.js +42 -42
- package/scripts/make-module.js +158 -158
- package/src/controllers/rbacController.ts +353 -353
- package/src/middleware/auth.ts +56 -56
- package/src/middleware/error.ts +7 -7
- package/src/middleware/visitor.ts +180 -180
- package/src/models/schema.prisma +159 -159
- package/src/routes/rbac.ts +55 -55
- package/src/schema/auth-schema.ts +62 -62
- package/src/utils/pagination.ts +56 -56
package/src/models/schema.prisma
CHANGED
|
@@ -1,159 +1,159 @@
|
|
|
1
|
-
|
|
2
|
-
model cache {
|
|
3
|
-
key String @id @db.VarChar(255)
|
|
4
|
-
value String
|
|
5
|
-
expiration Int
|
|
6
|
-
}
|
|
7
|
-
|
|
8
|
-
model cache_locks {
|
|
9
|
-
key String @id @db.VarChar(255)
|
|
10
|
-
owner String @db.VarChar(255)
|
|
11
|
-
expiration Int
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
model failed_jobs {
|
|
15
|
-
id BigInt @id @default(autoincrement())
|
|
16
|
-
uuid String @unique(map: "failed_jobs_uuid_unique") @db.VarChar(255)
|
|
17
|
-
connection String
|
|
18
|
-
queue String
|
|
19
|
-
payload String
|
|
20
|
-
exception String
|
|
21
|
-
failed_at DateTime @default(now()) @db.Timestamp(0)
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
model job_batches {
|
|
25
|
-
id String @id @db.VarChar(255)
|
|
26
|
-
name String @db.VarChar(255)
|
|
27
|
-
total_jobs Int
|
|
28
|
-
pending_jobs Int
|
|
29
|
-
failed_jobs Int
|
|
30
|
-
failed_job_ids String
|
|
31
|
-
options String?
|
|
32
|
-
cancelled_at Int?
|
|
33
|
-
created_at Int
|
|
34
|
-
finished_at Int?
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
model jobs {
|
|
38
|
-
id BigInt @id @default(autoincrement())
|
|
39
|
-
queue String @db.VarChar(255)
|
|
40
|
-
payload String
|
|
41
|
-
attempts Int @db.SmallInt
|
|
42
|
-
reserved_at Int?
|
|
43
|
-
available_at Int
|
|
44
|
-
created_at Int
|
|
45
|
-
|
|
46
|
-
@@index([queue], map: "jobs_queue_index")
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
model migrations {
|
|
50
|
-
id Int @id @default(autoincrement())
|
|
51
|
-
migration String @db.VarChar(255)
|
|
52
|
-
batch Int
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
model password_reset_tokens {
|
|
56
|
-
email String @id @db.VarChar(255)
|
|
57
|
-
token String @db.VarChar(255)
|
|
58
|
-
created_at DateTime? @db.Timestamp(0)
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
model personal_access_tokens {
|
|
62
|
-
id BigInt @id @default(autoincrement())
|
|
63
|
-
tokenable_type String @db.VarChar(255)
|
|
64
|
-
tokenable_id BigInt
|
|
65
|
-
name String
|
|
66
|
-
token String @unique(map: "personal_access_tokens_token_unique") @db.VarChar(64)
|
|
67
|
-
abilities String?
|
|
68
|
-
last_used_at DateTime? @db.Timestamp(0)
|
|
69
|
-
expires_at DateTime? @db.Timestamp(0)
|
|
70
|
-
created_at DateTime? @db.Timestamp(0)
|
|
71
|
-
updated_at DateTime? @db.Timestamp(0)
|
|
72
|
-
|
|
73
|
-
@@index([expires_at], map: "personal_access_tokens_expires_at_index")
|
|
74
|
-
@@index([tokenable_type, tokenable_id], map: "personal_access_tokens_tokenable_type_tokenable_id_index")
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
model sessions {
|
|
78
|
-
id String @id @db.VarChar(255)
|
|
79
|
-
user_id BigInt?
|
|
80
|
-
ip_address String? @db.VarChar(45)
|
|
81
|
-
user_agent String?
|
|
82
|
-
payload String
|
|
83
|
-
last_activity Int
|
|
84
|
-
|
|
85
|
-
@@index([last_activity], map: "sessions_last_activity_index")
|
|
86
|
-
@@index([user_id], map: "sessions_user_id_index")
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
/// This table contains check constraints and requires additional setup for migrations. Visit https://pris.ly/d/check-constraints for more info.
|
|
90
|
-
model users {
|
|
91
|
-
id BigInt @id @default(autoincrement())
|
|
92
|
-
uuid String @unique(map: "users_uuid_unique") @db.Uuid
|
|
93
|
-
name String @db.VarChar(255)
|
|
94
|
-
email String @unique(map: "users_email_unique") @db.VarChar(255)
|
|
95
|
-
avatar String? @db.VarChar(255)
|
|
96
|
-
avatar_url String? @db.VarChar(255)
|
|
97
|
-
email_verified_at DateTime? @db.Timestamp(0)
|
|
98
|
-
password String @db.VarChar(255)
|
|
99
|
-
remember_token String? @db.VarChar(100)
|
|
100
|
-
created_at DateTime? @db.Timestamp(0)
|
|
101
|
-
updated_at DateTime? @db.Timestamp(0)
|
|
102
|
-
user_roles user_roles[]
|
|
103
|
-
user_permissions user_permissions[]
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
model roles {
|
|
107
|
-
id BigInt @id @default(autoincrement())
|
|
108
|
-
name String @db.VarChar(255)
|
|
109
|
-
slug String @unique @db.VarChar(255)
|
|
110
|
-
description String?
|
|
111
|
-
created_at DateTime? @db.Timestamp(0)
|
|
112
|
-
updated_at DateTime? @db.Timestamp(0)
|
|
113
|
-
user_roles user_roles[]
|
|
114
|
-
role_permissions role_permissions[]
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
model permissions {
|
|
118
|
-
id BigInt @id @default(autoincrement())
|
|
119
|
-
name String @db.VarChar(255)
|
|
120
|
-
slug String @unique @db.VarChar(255)
|
|
121
|
-
description String?
|
|
122
|
-
created_at DateTime? @db.Timestamp(0)
|
|
123
|
-
updated_at DateTime? @db.Timestamp(0)
|
|
124
|
-
user_permissions user_permissions[]
|
|
125
|
-
role_permissions role_permissions[]
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
model user_roles {
|
|
129
|
-
id BigInt @id @default(autoincrement())
|
|
130
|
-
user_id BigInt
|
|
131
|
-
role_id BigInt
|
|
132
|
-
created_at DateTime? @db.Timestamp(0)
|
|
133
|
-
users users @relation(fields: [user_id], references: [id], onDelete: Cascade, onUpdate: NoAction)
|
|
134
|
-
roles roles @relation(fields: [role_id], references: [id], onDelete: Cascade, onUpdate: NoAction)
|
|
135
|
-
|
|
136
|
-
@@unique([user_id, role_id])
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
model role_permissions {
|
|
140
|
-
id BigInt @id @default(autoincrement())
|
|
141
|
-
role_id BigInt
|
|
142
|
-
permission_id BigInt
|
|
143
|
-
created_at DateTime? @db.Timestamp(0)
|
|
144
|
-
roles roles @relation(fields: [role_id], references: [id], onDelete: Cascade, onUpdate: NoAction)
|
|
145
|
-
permissions permissions @relation(fields: [permission_id], references: [id], onDelete: Cascade, onUpdate: NoAction)
|
|
146
|
-
|
|
147
|
-
@@unique([role_id, permission_id])
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
model user_permissions {
|
|
151
|
-
id BigInt @id @default(autoincrement())
|
|
152
|
-
user_id BigInt
|
|
153
|
-
permission_id BigInt
|
|
154
|
-
created_at DateTime? @db.Timestamp(0)
|
|
155
|
-
users users @relation(fields: [user_id], references: [id], onDelete: Cascade, onUpdate: NoAction)
|
|
156
|
-
permissions permissions @relation(fields: [permission_id], references: [id], onDelete: Cascade, onUpdate: NoAction)
|
|
157
|
-
|
|
158
|
-
@@unique([user_id, permission_id])
|
|
159
|
-
}
|
|
1
|
+
|
|
2
|
+
model cache {
|
|
3
|
+
key String @id @db.VarChar(255)
|
|
4
|
+
value String
|
|
5
|
+
expiration Int
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
model cache_locks {
|
|
9
|
+
key String @id @db.VarChar(255)
|
|
10
|
+
owner String @db.VarChar(255)
|
|
11
|
+
expiration Int
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
model failed_jobs {
|
|
15
|
+
id BigInt @id @default(autoincrement())
|
|
16
|
+
uuid String @unique(map: "failed_jobs_uuid_unique") @db.VarChar(255)
|
|
17
|
+
connection String
|
|
18
|
+
queue String
|
|
19
|
+
payload String
|
|
20
|
+
exception String
|
|
21
|
+
failed_at DateTime @default(now()) @db.Timestamp(0)
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
model job_batches {
|
|
25
|
+
id String @id @db.VarChar(255)
|
|
26
|
+
name String @db.VarChar(255)
|
|
27
|
+
total_jobs Int
|
|
28
|
+
pending_jobs Int
|
|
29
|
+
failed_jobs Int
|
|
30
|
+
failed_job_ids String
|
|
31
|
+
options String?
|
|
32
|
+
cancelled_at Int?
|
|
33
|
+
created_at Int
|
|
34
|
+
finished_at Int?
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
model jobs {
|
|
38
|
+
id BigInt @id @default(autoincrement())
|
|
39
|
+
queue String @db.VarChar(255)
|
|
40
|
+
payload String
|
|
41
|
+
attempts Int @db.SmallInt
|
|
42
|
+
reserved_at Int?
|
|
43
|
+
available_at Int
|
|
44
|
+
created_at Int
|
|
45
|
+
|
|
46
|
+
@@index([queue], map: "jobs_queue_index")
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
model migrations {
|
|
50
|
+
id Int @id @default(autoincrement())
|
|
51
|
+
migration String @db.VarChar(255)
|
|
52
|
+
batch Int
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
model password_reset_tokens {
|
|
56
|
+
email String @id @db.VarChar(255)
|
|
57
|
+
token String @db.VarChar(255)
|
|
58
|
+
created_at DateTime? @db.Timestamp(0)
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
model personal_access_tokens {
|
|
62
|
+
id BigInt @id @default(autoincrement())
|
|
63
|
+
tokenable_type String @db.VarChar(255)
|
|
64
|
+
tokenable_id BigInt
|
|
65
|
+
name String
|
|
66
|
+
token String @unique(map: "personal_access_tokens_token_unique") @db.VarChar(64)
|
|
67
|
+
abilities String?
|
|
68
|
+
last_used_at DateTime? @db.Timestamp(0)
|
|
69
|
+
expires_at DateTime? @db.Timestamp(0)
|
|
70
|
+
created_at DateTime? @db.Timestamp(0)
|
|
71
|
+
updated_at DateTime? @db.Timestamp(0)
|
|
72
|
+
|
|
73
|
+
@@index([expires_at], map: "personal_access_tokens_expires_at_index")
|
|
74
|
+
@@index([tokenable_type, tokenable_id], map: "personal_access_tokens_tokenable_type_tokenable_id_index")
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
model sessions {
|
|
78
|
+
id String @id @db.VarChar(255)
|
|
79
|
+
user_id BigInt?
|
|
80
|
+
ip_address String? @db.VarChar(45)
|
|
81
|
+
user_agent String?
|
|
82
|
+
payload String
|
|
83
|
+
last_activity Int
|
|
84
|
+
|
|
85
|
+
@@index([last_activity], map: "sessions_last_activity_index")
|
|
86
|
+
@@index([user_id], map: "sessions_user_id_index")
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/// This table contains check constraints and requires additional setup for migrations. Visit https://pris.ly/d/check-constraints for more info.
|
|
90
|
+
model users {
|
|
91
|
+
id BigInt @id @default(autoincrement())
|
|
92
|
+
uuid String @unique(map: "users_uuid_unique") @db.Uuid
|
|
93
|
+
name String @db.VarChar(255)
|
|
94
|
+
email String @unique(map: "users_email_unique") @db.VarChar(255)
|
|
95
|
+
avatar String? @db.VarChar(255)
|
|
96
|
+
avatar_url String? @db.VarChar(255)
|
|
97
|
+
email_verified_at DateTime? @db.Timestamp(0)
|
|
98
|
+
password String @db.VarChar(255)
|
|
99
|
+
remember_token String? @db.VarChar(100)
|
|
100
|
+
created_at DateTime? @db.Timestamp(0)
|
|
101
|
+
updated_at DateTime? @db.Timestamp(0)
|
|
102
|
+
user_roles user_roles[]
|
|
103
|
+
user_permissions user_permissions[]
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
model roles {
|
|
107
|
+
id BigInt @id @default(autoincrement())
|
|
108
|
+
name String @db.VarChar(255)
|
|
109
|
+
slug String @unique @db.VarChar(255)
|
|
110
|
+
description String?
|
|
111
|
+
created_at DateTime? @db.Timestamp(0)
|
|
112
|
+
updated_at DateTime? @db.Timestamp(0)
|
|
113
|
+
user_roles user_roles[]
|
|
114
|
+
role_permissions role_permissions[]
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
model permissions {
|
|
118
|
+
id BigInt @id @default(autoincrement())
|
|
119
|
+
name String @db.VarChar(255)
|
|
120
|
+
slug String @unique @db.VarChar(255)
|
|
121
|
+
description String?
|
|
122
|
+
created_at DateTime? @db.Timestamp(0)
|
|
123
|
+
updated_at DateTime? @db.Timestamp(0)
|
|
124
|
+
user_permissions user_permissions[]
|
|
125
|
+
role_permissions role_permissions[]
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
model user_roles {
|
|
129
|
+
id BigInt @id @default(autoincrement())
|
|
130
|
+
user_id BigInt
|
|
131
|
+
role_id BigInt
|
|
132
|
+
created_at DateTime? @db.Timestamp(0)
|
|
133
|
+
users users @relation(fields: [user_id], references: [id], onDelete: Cascade, onUpdate: NoAction)
|
|
134
|
+
roles roles @relation(fields: [role_id], references: [id], onDelete: Cascade, onUpdate: NoAction)
|
|
135
|
+
|
|
136
|
+
@@unique([user_id, role_id])
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
model role_permissions {
|
|
140
|
+
id BigInt @id @default(autoincrement())
|
|
141
|
+
role_id BigInt
|
|
142
|
+
permission_id BigInt
|
|
143
|
+
created_at DateTime? @db.Timestamp(0)
|
|
144
|
+
roles roles @relation(fields: [role_id], references: [id], onDelete: Cascade, onUpdate: NoAction)
|
|
145
|
+
permissions permissions @relation(fields: [permission_id], references: [id], onDelete: Cascade, onUpdate: NoAction)
|
|
146
|
+
|
|
147
|
+
@@unique([role_id, permission_id])
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
model user_permissions {
|
|
151
|
+
id BigInt @id @default(autoincrement())
|
|
152
|
+
user_id BigInt
|
|
153
|
+
permission_id BigInt
|
|
154
|
+
created_at DateTime? @db.Timestamp(0)
|
|
155
|
+
users users @relation(fields: [user_id], references: [id], onDelete: Cascade, onUpdate: NoAction)
|
|
156
|
+
permissions permissions @relation(fields: [permission_id], references: [id], onDelete: Cascade, onUpdate: NoAction)
|
|
157
|
+
|
|
158
|
+
@@unique([user_id, permission_id])
|
|
159
|
+
}
|
package/src/routes/rbac.ts
CHANGED
|
@@ -1,55 +1,55 @@
|
|
|
1
|
-
import { Router } from "express";
|
|
2
|
-
import { requireAdmin } from "../middleware/auth";
|
|
3
|
-
import {
|
|
4
|
-
createRole,
|
|
5
|
-
listRoles,
|
|
6
|
-
updateRole,
|
|
7
|
-
deleteRole,
|
|
8
|
-
createPermission,
|
|
9
|
-
listPermissions,
|
|
10
|
-
updatePermission,
|
|
11
|
-
deletePermission,
|
|
12
|
-
assignRoleToUser,
|
|
13
|
-
removeRoleFromUser,
|
|
14
|
-
assignPermissionToRole,
|
|
15
|
-
removePermissionFromRole,
|
|
16
|
-
assignPermissionToUser,
|
|
17
|
-
removePermissionFromUser,
|
|
18
|
-
} from "../controllers/rbacController";
|
|
19
|
-
|
|
20
|
-
export const rbacRouter = Router();
|
|
21
|
-
|
|
22
|
-
rbacRouter.post("/roles", requireAdmin, createRole);
|
|
23
|
-
rbacRouter.get("/roles", requireAdmin, listRoles);
|
|
24
|
-
rbacRouter.put("/roles/:id", requireAdmin, updateRole);
|
|
25
|
-
rbacRouter.delete("/roles/:id", requireAdmin, deleteRole);
|
|
26
|
-
|
|
27
|
-
rbacRouter.post("/permissions", requireAdmin, createPermission);
|
|
28
|
-
rbacRouter.get("/permissions", requireAdmin, listPermissions);
|
|
29
|
-
rbacRouter.put("/permissions/:id", requireAdmin, updatePermission);
|
|
30
|
-
rbacRouter.delete("/permissions/:id", requireAdmin, deletePermission);
|
|
31
|
-
|
|
32
|
-
rbacRouter.post("/users/assign-role", requireAdmin, assignRoleToUser);
|
|
33
|
-
rbacRouter.post("/users/remove-role", requireAdmin, removeRoleFromUser);
|
|
34
|
-
|
|
35
|
-
rbacRouter.post(
|
|
36
|
-
"/roles/assign-permission",
|
|
37
|
-
requireAdmin,
|
|
38
|
-
assignPermissionToRole
|
|
39
|
-
);
|
|
40
|
-
rbacRouter.post(
|
|
41
|
-
"/roles/remove-permission",
|
|
42
|
-
requireAdmin,
|
|
43
|
-
removePermissionFromRole
|
|
44
|
-
);
|
|
45
|
-
|
|
46
|
-
rbacRouter.post(
|
|
47
|
-
"/users/assign-permission",
|
|
48
|
-
requireAdmin,
|
|
49
|
-
assignPermissionToUser
|
|
50
|
-
);
|
|
51
|
-
rbacRouter.post(
|
|
52
|
-
"/users/remove-permission",
|
|
53
|
-
requireAdmin,
|
|
54
|
-
removePermissionFromUser
|
|
55
|
-
);
|
|
1
|
+
import { Router } from "express";
|
|
2
|
+
import { requireAdmin } from "../middleware/auth";
|
|
3
|
+
import {
|
|
4
|
+
createRole,
|
|
5
|
+
listRoles,
|
|
6
|
+
updateRole,
|
|
7
|
+
deleteRole,
|
|
8
|
+
createPermission,
|
|
9
|
+
listPermissions,
|
|
10
|
+
updatePermission,
|
|
11
|
+
deletePermission,
|
|
12
|
+
assignRoleToUser,
|
|
13
|
+
removeRoleFromUser,
|
|
14
|
+
assignPermissionToRole,
|
|
15
|
+
removePermissionFromRole,
|
|
16
|
+
assignPermissionToUser,
|
|
17
|
+
removePermissionFromUser,
|
|
18
|
+
} from "../controllers/rbacController";
|
|
19
|
+
|
|
20
|
+
export const rbacRouter = Router();
|
|
21
|
+
|
|
22
|
+
rbacRouter.post("/roles", requireAdmin, createRole);
|
|
23
|
+
rbacRouter.get("/roles", requireAdmin, listRoles);
|
|
24
|
+
rbacRouter.put("/roles/:id", requireAdmin, updateRole);
|
|
25
|
+
rbacRouter.delete("/roles/:id", requireAdmin, deleteRole);
|
|
26
|
+
|
|
27
|
+
rbacRouter.post("/permissions", requireAdmin, createPermission);
|
|
28
|
+
rbacRouter.get("/permissions", requireAdmin, listPermissions);
|
|
29
|
+
rbacRouter.put("/permissions/:id", requireAdmin, updatePermission);
|
|
30
|
+
rbacRouter.delete("/permissions/:id", requireAdmin, deletePermission);
|
|
31
|
+
|
|
32
|
+
rbacRouter.post("/users/assign-role", requireAdmin, assignRoleToUser);
|
|
33
|
+
rbacRouter.post("/users/remove-role", requireAdmin, removeRoleFromUser);
|
|
34
|
+
|
|
35
|
+
rbacRouter.post(
|
|
36
|
+
"/roles/assign-permission",
|
|
37
|
+
requireAdmin,
|
|
38
|
+
assignPermissionToRole
|
|
39
|
+
);
|
|
40
|
+
rbacRouter.post(
|
|
41
|
+
"/roles/remove-permission",
|
|
42
|
+
requireAdmin,
|
|
43
|
+
removePermissionFromRole
|
|
44
|
+
);
|
|
45
|
+
|
|
46
|
+
rbacRouter.post(
|
|
47
|
+
"/users/assign-permission",
|
|
48
|
+
requireAdmin,
|
|
49
|
+
assignPermissionToUser
|
|
50
|
+
);
|
|
51
|
+
rbacRouter.post(
|
|
52
|
+
"/users/remove-permission",
|
|
53
|
+
requireAdmin,
|
|
54
|
+
removePermissionFromUser
|
|
55
|
+
);
|
|
@@ -1,62 +1,62 @@
|
|
|
1
|
-
import z from "zod";
|
|
2
|
-
|
|
3
|
-
export const registerSchema = z
|
|
4
|
-
.object({
|
|
5
|
-
email: z
|
|
6
|
-
.string({ required_error: "Email wajib diisi" })
|
|
7
|
-
.email("Format email tidak valid"),
|
|
8
|
-
name: z
|
|
9
|
-
.string({ required_error: "Nama wajib diisi" })
|
|
10
|
-
.min(1, "Nama wajib diisi"),
|
|
11
|
-
password: z
|
|
12
|
-
.string({ required_error: "Password wajib diisi" })
|
|
13
|
-
.min(4, "Password minimal 4 karakter"),
|
|
14
|
-
confirmPassword: z
|
|
15
|
-
.string({ required_error: "Konfirmasi password wajib diisi" })
|
|
16
|
-
.min(4, "Konfirmasi password minimal 4 karakter"),
|
|
17
|
-
})
|
|
18
|
-
.refine((data) => data.password === data.confirmPassword, {
|
|
19
|
-
path: ["confirmPassword"],
|
|
20
|
-
message: "Konfirmasi password tidak sama",
|
|
21
|
-
});
|
|
22
|
-
|
|
23
|
-
export const loginSchema = z.object({
|
|
24
|
-
email: z
|
|
25
|
-
.string({ required_error: "Email wajib diisi" })
|
|
26
|
-
.email("Format email tidak valid"),
|
|
27
|
-
password: z
|
|
28
|
-
.string({ required_error: "Password wajib diisi" })
|
|
29
|
-
.min(4, "Password minimal 4 karakter"),
|
|
30
|
-
});
|
|
31
|
-
|
|
32
|
-
export const refreshSchema = z.object({
|
|
33
|
-
refreshToken: z
|
|
34
|
-
.string({ required_error: "Refresh token wajib diisi" })
|
|
35
|
-
.min(1, "Refresh token wajib diisi"),
|
|
36
|
-
});
|
|
37
|
-
|
|
38
|
-
export const updatePasswordSchema = z
|
|
39
|
-
.object({
|
|
40
|
-
currentPassword: z
|
|
41
|
-
.string({ required_error: "Password saat ini wajib diisi" })
|
|
42
|
-
.min(4, "Password saat ini minimal 4 karakter"),
|
|
43
|
-
newPassword: z
|
|
44
|
-
.string({ required_error: "Password baru wajib diisi" })
|
|
45
|
-
.min(4, "Password baru minimal 4 karakter"),
|
|
46
|
-
confirmPassword: z
|
|
47
|
-
.string({ required_error: "Konfirmasi password wajib diisi" })
|
|
48
|
-
.min(4, "Konfirmasi password minimal 4 karakter"),
|
|
49
|
-
})
|
|
50
|
-
.refine((data) => data.newPassword === data.confirmPassword, {
|
|
51
|
-
path: ["confirmPassword"],
|
|
52
|
-
message: "Konfirmasi password tidak sama",
|
|
53
|
-
});
|
|
54
|
-
|
|
55
|
-
export const updateProfileSchema = z.object({
|
|
56
|
-
name: z
|
|
57
|
-
.string({ required_error: "Nama wajib diisi" })
|
|
58
|
-
.min(1, "Nama wajib diisi"),
|
|
59
|
-
email: z
|
|
60
|
-
.string({ required_error: "Email wajib diisi" })
|
|
61
|
-
.email("Format email tidak valid"),
|
|
62
|
-
});
|
|
1
|
+
import z from "zod";
|
|
2
|
+
|
|
3
|
+
export const registerSchema = z
|
|
4
|
+
.object({
|
|
5
|
+
email: z
|
|
6
|
+
.string({ required_error: "Email wajib diisi" })
|
|
7
|
+
.email("Format email tidak valid"),
|
|
8
|
+
name: z
|
|
9
|
+
.string({ required_error: "Nama wajib diisi" })
|
|
10
|
+
.min(1, "Nama wajib diisi"),
|
|
11
|
+
password: z
|
|
12
|
+
.string({ required_error: "Password wajib diisi" })
|
|
13
|
+
.min(4, "Password minimal 4 karakter"),
|
|
14
|
+
confirmPassword: z
|
|
15
|
+
.string({ required_error: "Konfirmasi password wajib diisi" })
|
|
16
|
+
.min(4, "Konfirmasi password minimal 4 karakter"),
|
|
17
|
+
})
|
|
18
|
+
.refine((data) => data.password === data.confirmPassword, {
|
|
19
|
+
path: ["confirmPassword"],
|
|
20
|
+
message: "Konfirmasi password tidak sama",
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
export const loginSchema = z.object({
|
|
24
|
+
email: z
|
|
25
|
+
.string({ required_error: "Email wajib diisi" })
|
|
26
|
+
.email("Format email tidak valid"),
|
|
27
|
+
password: z
|
|
28
|
+
.string({ required_error: "Password wajib diisi" })
|
|
29
|
+
.min(4, "Password minimal 4 karakter"),
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
export const refreshSchema = z.object({
|
|
33
|
+
refreshToken: z
|
|
34
|
+
.string({ required_error: "Refresh token wajib diisi" })
|
|
35
|
+
.min(1, "Refresh token wajib diisi"),
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
export const updatePasswordSchema = z
|
|
39
|
+
.object({
|
|
40
|
+
currentPassword: z
|
|
41
|
+
.string({ required_error: "Password saat ini wajib diisi" })
|
|
42
|
+
.min(4, "Password saat ini minimal 4 karakter"),
|
|
43
|
+
newPassword: z
|
|
44
|
+
.string({ required_error: "Password baru wajib diisi" })
|
|
45
|
+
.min(4, "Password baru minimal 4 karakter"),
|
|
46
|
+
confirmPassword: z
|
|
47
|
+
.string({ required_error: "Konfirmasi password wajib diisi" })
|
|
48
|
+
.min(4, "Konfirmasi password minimal 4 karakter"),
|
|
49
|
+
})
|
|
50
|
+
.refine((data) => data.newPassword === data.confirmPassword, {
|
|
51
|
+
path: ["confirmPassword"],
|
|
52
|
+
message: "Konfirmasi password tidak sama",
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
export const updateProfileSchema = z.object({
|
|
56
|
+
name: z
|
|
57
|
+
.string({ required_error: "Nama wajib diisi" })
|
|
58
|
+
.min(1, "Nama wajib diisi"),
|
|
59
|
+
email: z
|
|
60
|
+
.string({ required_error: "Email wajib diisi" })
|
|
61
|
+
.email("Format email tidak valid"),
|
|
62
|
+
});
|
package/src/utils/pagination.ts
CHANGED
|
@@ -1,56 +1,56 @@
|
|
|
1
|
-
export type PaginationQuery = {
|
|
2
|
-
page?: string | string[] | number;
|
|
3
|
-
per_page?: string | string[] | number;
|
|
4
|
-
};
|
|
5
|
-
|
|
6
|
-
export type PaginationParams = {
|
|
7
|
-
page: number;
|
|
8
|
-
perPage: number;
|
|
9
|
-
skip: number;
|
|
10
|
-
take: number;
|
|
11
|
-
};
|
|
12
|
-
|
|
13
|
-
export type PaginationMeta = {
|
|
14
|
-
page: number;
|
|
15
|
-
perPage: number;
|
|
16
|
-
total: number;
|
|
17
|
-
lastPage: number;
|
|
18
|
-
};
|
|
19
|
-
|
|
20
|
-
function toNumber(value: string | string[] | number | undefined) {
|
|
21
|
-
if (Array.isArray(value)) {
|
|
22
|
-
if (value.length === 0) return undefined;
|
|
23
|
-
return toNumber(value[0]);
|
|
24
|
-
}
|
|
25
|
-
if (typeof value === "number") {
|
|
26
|
-
return value;
|
|
27
|
-
}
|
|
28
|
-
if (typeof value === "string") {
|
|
29
|
-
const n = parseInt(value, 10);
|
|
30
|
-
if (!Number.isNaN(n)) {
|
|
31
|
-
return n;
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
return undefined;
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
export function getPagination(query: PaginationQuery): PaginationParams {
|
|
38
|
-
const pageRaw = toNumber(query.page);
|
|
39
|
-
const perPageRaw = toNumber(query.per_page);
|
|
40
|
-
const page = pageRaw && pageRaw > 0 ? pageRaw : 1;
|
|
41
|
-
const perPage =
|
|
42
|
-
perPageRaw && perPageRaw > 0 && perPageRaw <= 100 ? perPageRaw : 10;
|
|
43
|
-
const skip = (page - 1) * perPage;
|
|
44
|
-
const take = perPage;
|
|
45
|
-
return { page, perPage, skip, take };
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
export function buildPaginationMeta(
|
|
49
|
-
page: number,
|
|
50
|
-
perPage: number,
|
|
51
|
-
total: number
|
|
52
|
-
): PaginationMeta {
|
|
53
|
-
const lastPage = total === 0 ? 1 : Math.ceil(total / perPage);
|
|
54
|
-
return { page, perPage, total, lastPage };
|
|
55
|
-
}
|
|
56
|
-
|
|
1
|
+
export type PaginationQuery = {
|
|
2
|
+
page?: string | string[] | number;
|
|
3
|
+
per_page?: string | string[] | number;
|
|
4
|
+
};
|
|
5
|
+
|
|
6
|
+
export type PaginationParams = {
|
|
7
|
+
page: number;
|
|
8
|
+
perPage: number;
|
|
9
|
+
skip: number;
|
|
10
|
+
take: number;
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
export type PaginationMeta = {
|
|
14
|
+
page: number;
|
|
15
|
+
perPage: number;
|
|
16
|
+
total: number;
|
|
17
|
+
lastPage: number;
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
function toNumber(value: string | string[] | number | undefined) {
|
|
21
|
+
if (Array.isArray(value)) {
|
|
22
|
+
if (value.length === 0) return undefined;
|
|
23
|
+
return toNumber(value[0]);
|
|
24
|
+
}
|
|
25
|
+
if (typeof value === "number") {
|
|
26
|
+
return value;
|
|
27
|
+
}
|
|
28
|
+
if (typeof value === "string") {
|
|
29
|
+
const n = parseInt(value, 10);
|
|
30
|
+
if (!Number.isNaN(n)) {
|
|
31
|
+
return n;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
return undefined;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export function getPagination(query: PaginationQuery): PaginationParams {
|
|
38
|
+
const pageRaw = toNumber(query.page);
|
|
39
|
+
const perPageRaw = toNumber(query.per_page);
|
|
40
|
+
const page = pageRaw && pageRaw > 0 ? pageRaw : 1;
|
|
41
|
+
const perPage =
|
|
42
|
+
perPageRaw && perPageRaw > 0 && perPageRaw <= 100 ? perPageRaw : 10;
|
|
43
|
+
const skip = (page - 1) * perPage;
|
|
44
|
+
const take = perPage;
|
|
45
|
+
return { page, perPage, skip, take };
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export function buildPaginationMeta(
|
|
49
|
+
page: number,
|
|
50
|
+
perPage: number,
|
|
51
|
+
total: number
|
|
52
|
+
): PaginationMeta {
|
|
53
|
+
const lastPage = total === 0 ? 1 : Math.ceil(total / perPage);
|
|
54
|
+
return { page, perPage, total, lastPage };
|
|
55
|
+
}
|
|
56
|
+
|