dn-react-router-toolkit 0.9.0 → 0.9.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/dist/api/default_api_handler.d.mts +13 -0
- package/dist/api/default_api_handler.d.ts +13 -0
- package/dist/api/{create_handler.js → default_api_handler.js} +49 -52
- package/dist/api/{create_handler.mjs → default_api_handler.mjs} +45 -48
- package/dist/api/index.d.mts +8 -7
- package/dist/api/index.d.ts +8 -7
- package/dist/api/index.js +233 -147
- package/dist/api/index.mjs +238 -151
- package/dist/api/put_resource_handler.d.mts +25 -0
- package/dist/api/put_resource_handler.d.ts +25 -0
- package/dist/api/put_resource_handler.js +214 -0
- package/dist/api/put_resource_handler.mjs +194 -0
- package/dist/api/resource_handler.d.mts +26 -0
- package/dist/api/resource_handler.d.ts +26 -0
- package/dist/api/resource_handler.js +280 -0
- package/dist/api/resource_handler.mjs +265 -0
- package/dist/auth/cookie_manager.d.mts +1 -1
- package/dist/auth/cookie_manager.d.ts +1 -1
- package/dist/auth/index.d.mts +2 -2
- package/dist/auth/index.d.ts +2 -2
- package/dist/auth/index.js +18 -18
- package/dist/auth/index.mjs +18 -18
- package/dist/auth/with_auth.d.mts +2 -2
- package/dist/auth/with_auth.d.ts +2 -2
- package/dist/auth/with_auth.js +18 -18
- package/dist/auth/with_auth.mjs +18 -18
- package/dist/client/editor.d.mts +2 -2
- package/dist/client/editor.d.ts +2 -2
- package/dist/client/editor.js +9 -3
- package/dist/client/editor.mjs +9 -3
- package/dist/client/index.d.mts +2 -2
- package/dist/client/index.d.ts +2 -2
- package/dist/client/index.js +9 -3
- package/dist/client/index.mjs +9 -3
- package/dist/crud/crud_form.js +22 -4
- package/dist/crud/crud_form.mjs +11 -3
- package/dist/crud/crud_form_provider.js +16 -3
- package/dist/crud/crud_form_provider.mjs +14 -1
- package/dist/crud/index.js +22 -4
- package/dist/crud/index.mjs +11 -3
- package/dist/db/backup/index.d.mts +1 -1
- package/dist/db/backup/index.d.ts +1 -1
- package/dist/form/create_form_component.js +21 -2
- package/dist/form/create_form_component.mjs +10 -1
- package/dist/form/form_components.js +21 -2
- package/dist/form/form_components.mjs +10 -1
- package/dist/form/index.js +21 -2
- package/dist/form/index.mjs +10 -1
- package/dist/post/editor_toolbar.js +20 -3
- package/dist/post/editor_toolbar.mjs +9 -2
- package/dist/post/index.js +31 -11
- package/dist/post/index.mjs +19 -9
- package/dist/post/post_form_page.js +29 -11
- package/dist/post/post_form_page.mjs +17 -9
- package/dist/post/thumbnail_picker.js +21 -2
- package/dist/post/thumbnail_picker.mjs +10 -1
- package/dist/table/buttons.js +11 -14
- package/dist/table/buttons.mjs +10 -13
- package/dist/table/index.js +14 -18
- package/dist/table/index.mjs +13 -17
- package/dist/table/table.js +10 -4
- package/dist/table/table.mjs +5 -1
- package/dist/table/table_form.js +12 -18
- package/dist/table/table_form.mjs +9 -15
- package/dist/utils/cn.d.mts +3 -0
- package/dist/utils/cn.d.ts +3 -0
- package/dist/utils/cn.js +32 -0
- package/dist/utils/cn.mjs +7 -0
- package/dist/utils/date.d.mts +5 -0
- package/dist/utils/date.d.ts +5 -0
- package/dist/utils/date.js +65 -0
- package/dist/utils/date.mjs +29 -0
- package/dist/utils/index.d.mts +7 -0
- package/dist/utils/index.d.ts +7 -0
- package/dist/utils/index.js +116 -0
- package/dist/utils/index.mjs +73 -0
- package/dist/utils/korean.d.mts +6 -0
- package/dist/utils/korean.d.ts +6 -0
- package/dist/utils/korean.js +41 -0
- package/dist/utils/korean.mjs +16 -0
- package/dist/utils/singleton.d.mts +3 -0
- package/dist/utils/singleton.d.ts +3 -0
- package/dist/utils/singleton.js +37 -0
- package/dist/utils/singleton.mjs +12 -0
- package/dist/utils/sleep.d.mts +3 -0
- package/dist/utils/sleep.d.ts +3 -0
- package/dist/utils/sleep.js +32 -0
- package/dist/utils/sleep.mjs +7 -0
- package/dist/utils/slug.d.mts +3 -0
- package/dist/utils/slug.d.ts +3 -0
- package/dist/utils/slug.js +32 -0
- package/dist/utils/slug.mjs +7 -0
- package/package.json +8 -4
- package/dist/api/create_api_handler.d.mts +0 -30
- package/dist/api/create_api_handler.d.ts +0 -30
- package/dist/api/create_api_handler.js +0 -155
- package/dist/api/create_api_handler.mjs +0 -139
- package/dist/api/create_handler.d.mts +0 -13
- package/dist/api/create_handler.d.ts +0 -13
- package/dist/api/item_api_handler.d.mts +0 -21
- package/dist/api/item_api_handler.d.ts +0 -21
- package/dist/api/item_api_handler.js +0 -63
- package/dist/api/item_api_handler.mjs +0 -38
package/dist/api/index.mjs
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
// src/api/
|
|
2
|
-
import { NOT_FOUND } from "dn-react-toolkit/http";
|
|
1
|
+
// src/api/default_api_handler.ts
|
|
3
2
|
import {
|
|
4
3
|
findAuthHandler,
|
|
5
4
|
loginHandler,
|
|
@@ -11,7 +10,7 @@ import {
|
|
|
11
10
|
signupHandler,
|
|
12
11
|
signUpWithThirdpartyHandler,
|
|
13
12
|
thirdpartyAuthCallbackHandler
|
|
14
|
-
} from "
|
|
13
|
+
} from "gw-auth/server";
|
|
15
14
|
|
|
16
15
|
// src/auth/with_auth.ts
|
|
17
16
|
var toResponse = (result) => {
|
|
@@ -37,31 +36,31 @@ function createWithStrictAuthHandler({ authService }) {
|
|
|
37
36
|
arg.request
|
|
38
37
|
);
|
|
39
38
|
if (accessToken) {
|
|
40
|
-
const
|
|
41
|
-
if (
|
|
42
|
-
|
|
39
|
+
const verifyResult = await authService.accessTokenManager.verify(accessToken);
|
|
40
|
+
if (verifyResult.isOk) {
|
|
41
|
+
const payload = verifyResult.value;
|
|
42
|
+
if (payload) {
|
|
43
|
+
return respond(payload);
|
|
44
|
+
}
|
|
43
45
|
}
|
|
44
46
|
}
|
|
45
47
|
const refreshToken = await authService.getRefreshTokenFromCookies(
|
|
46
48
|
arg.request
|
|
47
49
|
);
|
|
48
50
|
if (refreshToken) {
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
const
|
|
52
|
-
|
|
53
|
-
);
|
|
54
|
-
|
|
55
|
-
headers.append("Set-Cookie", setCookieHeader);
|
|
56
|
-
const payload = authService.accessTokenManager.decode(newAccessToken);
|
|
57
|
-
return respond(payload, headers);
|
|
58
|
-
} catch (e) {
|
|
59
|
-
console.log(e);
|
|
60
|
-
const setCookieHeader = await authService.getRefreshTokenSetCookie(void 0);
|
|
61
|
-
const headers = new Headers();
|
|
62
|
-
headers.append("Set-Cookie", setCookieHeader);
|
|
63
|
-
return respond(void 0, headers);
|
|
51
|
+
const refreshResult = await authService.refreshAccessToken(refreshToken);
|
|
52
|
+
if (refreshResult.isErr) {
|
|
53
|
+
const setCookieHeader2 = await authService.getRefreshTokenSetCookie(void 0);
|
|
54
|
+
const headers2 = new Headers();
|
|
55
|
+
headers2.append("Set-Cookie", setCookieHeader2);
|
|
56
|
+
return respond(void 0, headers2);
|
|
64
57
|
}
|
|
58
|
+
const newAccessToken = refreshResult.value;
|
|
59
|
+
const setCookieHeader = await authService.getAccessTokenSetCookie(newAccessToken);
|
|
60
|
+
const headers = new Headers();
|
|
61
|
+
headers.append("Set-Cookie", setCookieHeader);
|
|
62
|
+
const payload = authService.accessTokenManager.decode(newAccessToken);
|
|
63
|
+
return respond(payload, headers);
|
|
65
64
|
}
|
|
66
65
|
return respond(void 0);
|
|
67
66
|
};
|
|
@@ -72,16 +71,17 @@ function createWithStrictAuthHandler({ authService }) {
|
|
|
72
71
|
// src/auth/cookie_manager.ts
|
|
73
72
|
import { createCookie } from "react-router";
|
|
74
73
|
|
|
75
|
-
// src/api/
|
|
74
|
+
// src/api/default_api_handler.ts
|
|
76
75
|
import {
|
|
77
76
|
deleteFileHandler,
|
|
78
77
|
uploadFileHandler
|
|
79
|
-
} from "
|
|
80
|
-
|
|
78
|
+
} from "gw-file/server";
|
|
79
|
+
import { httpNotFound } from "gw-response";
|
|
80
|
+
var defaultAPIHandler = ({
|
|
81
81
|
authService,
|
|
82
82
|
fileService,
|
|
83
83
|
passwordRecoveryService,
|
|
84
|
-
|
|
84
|
+
authProviders,
|
|
85
85
|
signupTokenManager
|
|
86
86
|
}) => {
|
|
87
87
|
const handler = async (args) => {
|
|
@@ -96,7 +96,7 @@ var createAPIHandler = ({
|
|
|
96
96
|
switch (method) {
|
|
97
97
|
case "GET": {
|
|
98
98
|
return withAuth(
|
|
99
|
-
(auth) => ({ request: request2 }) => findAuthHandler(auth)(
|
|
99
|
+
(auth) => ({ request: request2 }) => findAuthHandler(auth)()
|
|
100
100
|
);
|
|
101
101
|
}
|
|
102
102
|
}
|
|
@@ -116,13 +116,10 @@ var createAPIHandler = ({
|
|
|
116
116
|
const provider = slug[2];
|
|
117
117
|
switch (method) {
|
|
118
118
|
case "POST": {
|
|
119
|
-
return loginWithThirdPartyHandler(
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
getThirdPartyAuth
|
|
124
|
-
}
|
|
125
|
-
);
|
|
119
|
+
return loginWithThirdPartyHandler(request, {
|
|
120
|
+
provider,
|
|
121
|
+
authProviders
|
|
122
|
+
});
|
|
126
123
|
}
|
|
127
124
|
}
|
|
128
125
|
}
|
|
@@ -161,14 +158,11 @@ var createAPIHandler = ({
|
|
|
161
158
|
default: {
|
|
162
159
|
switch (method) {
|
|
163
160
|
case "POST": {
|
|
164
|
-
return signUpWithThirdpartyHandler(
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
signupTokenManager
|
|
170
|
-
}
|
|
171
|
-
);
|
|
161
|
+
return signUpWithThirdpartyHandler(request, {
|
|
162
|
+
authService,
|
|
163
|
+
fileService,
|
|
164
|
+
signupTokenManager
|
|
165
|
+
});
|
|
172
166
|
}
|
|
173
167
|
}
|
|
174
168
|
}
|
|
@@ -181,7 +175,7 @@ var createAPIHandler = ({
|
|
|
181
175
|
return thirdpartyAuthCallbackHandler(request, {
|
|
182
176
|
provider,
|
|
183
177
|
authService,
|
|
184
|
-
|
|
178
|
+
authProviders
|
|
185
179
|
});
|
|
186
180
|
}
|
|
187
181
|
}
|
|
@@ -204,9 +198,9 @@ var createAPIHandler = ({
|
|
|
204
198
|
switch (method) {
|
|
205
199
|
case "POST": {
|
|
206
200
|
return withAuth(
|
|
207
|
-
(auth) => ({ request: request2 }) => uploadFileHandler({ fileService })(
|
|
208
|
-
auth
|
|
209
|
-
)
|
|
201
|
+
(auth) => ({ request: request2 }) => uploadFileHandler({ fileService })(request2, {
|
|
202
|
+
userId: auth?.userId
|
|
203
|
+
})
|
|
210
204
|
)(args);
|
|
211
205
|
}
|
|
212
206
|
}
|
|
@@ -218,7 +212,7 @@ var createAPIHandler = ({
|
|
|
218
212
|
return withAuth(
|
|
219
213
|
(auth) => () => deleteFileHandler({
|
|
220
214
|
fileRepository: fileService.fileRepository
|
|
221
|
-
})({ fileId })(
|
|
215
|
+
})({ fileId, userId: auth?.userId })()
|
|
222
216
|
);
|
|
223
217
|
}
|
|
224
218
|
}
|
|
@@ -226,26 +220,41 @@ var createAPIHandler = ({
|
|
|
226
220
|
}
|
|
227
221
|
}
|
|
228
222
|
default: {
|
|
229
|
-
return
|
|
223
|
+
return httpNotFound({
|
|
224
|
+
code: "RESOURCE_NOT_FOUND",
|
|
225
|
+
message: "\uB9AC\uC18C\uC2A4\uB97C \uCC3E\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4."
|
|
226
|
+
});
|
|
230
227
|
}
|
|
231
228
|
}
|
|
232
229
|
};
|
|
233
230
|
return handler;
|
|
234
231
|
};
|
|
235
232
|
|
|
236
|
-
// src/api/
|
|
233
|
+
// src/api/resource_handler.ts
|
|
237
234
|
import {
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
235
|
+
httpForbidden as httpForbidden2,
|
|
236
|
+
httpMethodNotAllowed,
|
|
237
|
+
httpNoContent,
|
|
238
|
+
httpNotFound as httpNotFound3
|
|
239
|
+
} from "gw-response";
|
|
240
|
+
import { ok } from "gw-result";
|
|
241
|
+
|
|
242
|
+
// src/api/put_resource_handler.ts
|
|
245
243
|
import {
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
244
|
+
httpBadRequest,
|
|
245
|
+
httpConflict,
|
|
246
|
+
httpCreated,
|
|
247
|
+
httpForbidden,
|
|
248
|
+
httpNotFound as httpNotFound2
|
|
249
|
+
} from "gw-response";
|
|
250
|
+
|
|
251
|
+
// src/crud/crud_form_provider.tsx
|
|
252
|
+
import { useNavigate } from "react-router";
|
|
253
|
+
import { useStore } from "react-store-input";
|
|
254
|
+
import {
|
|
255
|
+
createContext,
|
|
256
|
+
useContext
|
|
257
|
+
} from "react";
|
|
249
258
|
|
|
250
259
|
// src/crud/serialize.ts
|
|
251
260
|
function deserialize(data) {
|
|
@@ -284,119 +293,197 @@ function deserialize(data) {
|
|
|
284
293
|
return void 0;
|
|
285
294
|
}
|
|
286
295
|
|
|
287
|
-
// src/
|
|
288
|
-
|
|
289
|
-
|
|
296
|
+
// src/crud/crud_form_provider.tsx
|
|
297
|
+
import { jsx } from "react/jsx-runtime";
|
|
298
|
+
var FormContext = createContext({});
|
|
299
|
+
|
|
300
|
+
// src/form/create_form_component.tsx
|
|
301
|
+
import "react";
|
|
302
|
+
|
|
303
|
+
// src/utils/cn.ts
|
|
304
|
+
function cn(...classes) {
|
|
305
|
+
return classes.filter(Boolean).join(" ").trim();
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
// src/utils/date.ts
|
|
309
|
+
import moment from "moment-timezone";
|
|
310
|
+
|
|
311
|
+
// src/form/create_form_component.tsx
|
|
312
|
+
import { jsx as jsx2 } from "react/jsx-runtime";
|
|
313
|
+
function createComponent(tag, options) {
|
|
314
|
+
return function FormComponent({ className, ...props }) {
|
|
315
|
+
const Tag = tag;
|
|
316
|
+
return /* @__PURE__ */ jsx2(Tag, { ...props, className: cn(options.className, className) });
|
|
317
|
+
};
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
// src/form/form_components.tsx
|
|
321
|
+
var FormEntry = createComponent("div", {
|
|
322
|
+
className: "flex-1"
|
|
323
|
+
});
|
|
324
|
+
var FormRow = createComponent("div", {
|
|
325
|
+
className: "flex-1 flex gap-4 mb-6"
|
|
326
|
+
});
|
|
327
|
+
var FormLabel = createComponent("label", {
|
|
328
|
+
className: "flex-1 font-semibold mb-2.5 block"
|
|
329
|
+
});
|
|
330
|
+
|
|
331
|
+
// src/crud/crud_form.tsx
|
|
332
|
+
import { useStoreComponent } from "react-store-input";
|
|
333
|
+
|
|
334
|
+
// src/client/env_loader.tsx
|
|
335
|
+
import { useRouteLoaderData } from "react-router";
|
|
336
|
+
import { jsx as jsx3 } from "react/jsx-runtime";
|
|
337
|
+
|
|
338
|
+
// src/client/file_input.tsx
|
|
339
|
+
import {
|
|
340
|
+
useRef
|
|
341
|
+
} from "react";
|
|
342
|
+
import { Fragment, jsx as jsx4, jsxs } from "react/jsx-runtime";
|
|
343
|
+
|
|
344
|
+
// src/client/use_user_agent.tsx
|
|
345
|
+
import { useRouteLoaderData as useRouteLoaderData2 } from "react-router";
|
|
346
|
+
|
|
347
|
+
// src/client/store_text_editor.tsx
|
|
348
|
+
import {
|
|
349
|
+
TextEditor
|
|
350
|
+
} from "dn-react-text-editor";
|
|
351
|
+
import { useStoreController } from "react-store-input";
|
|
352
|
+
import { useImperativeHandle, useRef as useRef2 } from "react";
|
|
353
|
+
import { jsx as jsx5 } from "react/jsx-runtime";
|
|
354
|
+
|
|
355
|
+
// src/client/editor.tsx
|
|
356
|
+
import { generateMetadata } from "gw-file/client";
|
|
357
|
+
|
|
358
|
+
// src/crud/crud_form.tsx
|
|
359
|
+
import { Fragment as Fragment2, jsx as jsx6, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
360
|
+
|
|
361
|
+
// src/api/put_resource_handler.ts
|
|
362
|
+
import {
|
|
363
|
+
and
|
|
364
|
+
} from "drizzle-orm";
|
|
365
|
+
import { v4 } from "uuid";
|
|
366
|
+
function putResourceHandler({
|
|
290
367
|
repository,
|
|
291
368
|
validators,
|
|
292
369
|
existingConditions,
|
|
293
370
|
injectUserId,
|
|
294
|
-
|
|
371
|
+
isOwnedBy
|
|
295
372
|
}) {
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
if (
|
|
301
|
-
|
|
373
|
+
return async (auth, request) => {
|
|
374
|
+
const serilaizedParams = await request.json();
|
|
375
|
+
const params = deserialize(serilaizedParams);
|
|
376
|
+
const itemId = params.id || v4();
|
|
377
|
+
if (params.id) {
|
|
378
|
+
const existing = await repository.find(itemId);
|
|
379
|
+
if (!existing) {
|
|
380
|
+
return httpNotFound2();
|
|
381
|
+
}
|
|
382
|
+
if (isOwnedBy && (!auth || !isOwnedBy(auth, existing))) {
|
|
383
|
+
return httpForbidden();
|
|
384
|
+
}
|
|
302
385
|
}
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
const
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
(key) => Object.prototype.hasOwnProperty.call(params, key)
|
|
329
|
-
);
|
|
330
|
-
if (paramsForExistenceCheck.length > 0) {
|
|
331
|
-
const where = and(
|
|
332
|
-
...paramsForExistenceCheck.reduce((acc, key) => {
|
|
333
|
-
const condition = existingConditions[key];
|
|
334
|
-
if (condition) {
|
|
335
|
-
acc.push(condition(params[key]));
|
|
336
|
-
}
|
|
337
|
-
return acc;
|
|
338
|
-
}, [])
|
|
339
|
-
);
|
|
340
|
-
const existing = await repository.findAll({
|
|
341
|
-
limit: 1,
|
|
342
|
-
where
|
|
343
|
-
});
|
|
344
|
-
if (existing.length > 0) {
|
|
345
|
-
throw CONFLICT("\uC790\uB8CC\uAC00 \uC774\uBBF8 \uC874\uC7AC\uD569\uB2C8\uB2E4.");
|
|
346
|
-
}
|
|
386
|
+
if (validators) {
|
|
387
|
+
const paramsForValidation = Object.keys(validators).filter(
|
|
388
|
+
(key) => Object.prototype.hasOwnProperty.call(validators, key)
|
|
389
|
+
);
|
|
390
|
+
for (const paramKey of paramsForValidation) {
|
|
391
|
+
const value = params[paramKey];
|
|
392
|
+
const validator = validators[paramKey];
|
|
393
|
+
if (validator?.validate && !validator.validate(value)) {
|
|
394
|
+
return httpBadRequest({
|
|
395
|
+
code: "BAD_REQUEST",
|
|
396
|
+
message: validator.message ? validator.message(value) : "\uC798\uBABB\uB41C \uC694\uCCAD\uC785\uB2C8\uB2E4."
|
|
397
|
+
});
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
}
|
|
401
|
+
if (!params.id && existingConditions) {
|
|
402
|
+
const paramsForExistenceCheck = Object.keys(existingConditions).filter(
|
|
403
|
+
(key) => Object.prototype.hasOwnProperty.call(params, key)
|
|
404
|
+
);
|
|
405
|
+
if (paramsForExistenceCheck.length > 0) {
|
|
406
|
+
const where = and(
|
|
407
|
+
...paramsForExistenceCheck.reduce((acc, key) => {
|
|
408
|
+
const condition = existingConditions[key];
|
|
409
|
+
if (condition) {
|
|
410
|
+
acc.push(condition(params[key]));
|
|
347
411
|
}
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
if (error instanceof Error) {
|
|
358
|
-
throw INTERNAL_SERVER_ERROR(error.message);
|
|
359
|
-
}
|
|
360
|
-
throw error;
|
|
412
|
+
return acc;
|
|
413
|
+
}, [])
|
|
414
|
+
);
|
|
415
|
+
const existing = await repository.findAll({
|
|
416
|
+
limit: 1,
|
|
417
|
+
where
|
|
418
|
+
});
|
|
419
|
+
if (existing.length > 0) {
|
|
420
|
+
return httpConflict();
|
|
361
421
|
}
|
|
362
422
|
}
|
|
363
|
-
default:
|
|
364
|
-
throw METHOD_NOT_ALLOWED();
|
|
365
423
|
}
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
424
|
+
const values = {
|
|
425
|
+
id: itemId,
|
|
426
|
+
userId: injectUserId ? auth?.userId : void 0,
|
|
427
|
+
...params
|
|
428
|
+
};
|
|
429
|
+
const item = await repository.save(values);
|
|
430
|
+
return httpCreated(item);
|
|
370
431
|
};
|
|
371
432
|
}
|
|
372
433
|
|
|
373
|
-
// src/api/
|
|
374
|
-
|
|
375
|
-
function itemApiHandler({
|
|
434
|
+
// src/api/resource_handler.ts
|
|
435
|
+
function resourceHandler({
|
|
376
436
|
withAuthAction,
|
|
377
437
|
repository,
|
|
378
|
-
|
|
379
|
-
|
|
438
|
+
validators,
|
|
439
|
+
existingConditions,
|
|
440
|
+
injectUserId,
|
|
441
|
+
roles,
|
|
442
|
+
isOwnedBy
|
|
380
443
|
}) {
|
|
381
444
|
const loader = async ({ request }) => {
|
|
382
|
-
return {};
|
|
445
|
+
return ok({});
|
|
383
446
|
};
|
|
384
|
-
const action = withAuthAction((auth) => async ({
|
|
447
|
+
const action = withAuthAction((auth) => async ({ request, params }) => {
|
|
385
448
|
if (roles && roles.length > 0 && (!auth || !roles.includes(auth.role))) {
|
|
386
|
-
|
|
449
|
+
return httpForbidden2({
|
|
450
|
+
code: "FORBIDDEN",
|
|
451
|
+
message: "\uAD8C\uD55C\uC774 \uC5C6\uC2B5\uB2C8\uB2E4."
|
|
452
|
+
});
|
|
387
453
|
}
|
|
388
454
|
const itemId = params.itemId;
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
455
|
+
if (itemId) {
|
|
456
|
+
const existing = await repository.find(itemId);
|
|
457
|
+
if (!existing) {
|
|
458
|
+
return httpNotFound3();
|
|
459
|
+
}
|
|
460
|
+
if (isOwnedBy && (!auth || !isOwnedBy(auth, existing))) {
|
|
461
|
+
return httpForbidden2();
|
|
462
|
+
}
|
|
463
|
+
switch (request.method) {
|
|
464
|
+
case "DELETE": {
|
|
465
|
+
await repository.delete(itemId);
|
|
466
|
+
return httpNoContent();
|
|
467
|
+
}
|
|
468
|
+
default: {
|
|
469
|
+
return httpMethodNotAllowed();
|
|
470
|
+
}
|
|
471
|
+
}
|
|
395
472
|
}
|
|
396
473
|
switch (request.method) {
|
|
397
|
-
case "
|
|
398
|
-
|
|
399
|
-
|
|
474
|
+
case "POST":
|
|
475
|
+
case "PUT": {
|
|
476
|
+
const handler = putResourceHandler({
|
|
477
|
+
repository,
|
|
478
|
+
validators,
|
|
479
|
+
existingConditions,
|
|
480
|
+
injectUserId,
|
|
481
|
+
isOwnedBy
|
|
482
|
+
});
|
|
483
|
+
return handler(auth, request);
|
|
484
|
+
}
|
|
485
|
+
default: {
|
|
486
|
+
return httpMethodNotAllowed();
|
|
400
487
|
}
|
|
401
488
|
}
|
|
402
489
|
});
|
|
@@ -406,7 +493,7 @@ function itemApiHandler({
|
|
|
406
493
|
};
|
|
407
494
|
}
|
|
408
495
|
export {
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
496
|
+
defaultAPIHandler,
|
|
497
|
+
putResourceHandler,
|
|
498
|
+
resourceHandler
|
|
412
499
|
};
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { InferSelectModel, SQLWrapper } from 'drizzle-orm';
|
|
2
|
+
import { AccessTokenPayload } from 'gw-auth';
|
|
3
|
+
import { PgTableWithColumns } from 'drizzle-orm/pg-core';
|
|
4
|
+
import { TableRepository } from '../table/repository.mjs';
|
|
5
|
+
import 'drizzle-orm/node-postgres';
|
|
6
|
+
|
|
7
|
+
type PutResourceValidators<T extends PgTableWithColumns<any>> = {
|
|
8
|
+
[K in keyof InferSelectModel<T>]?: {
|
|
9
|
+
validate?: (value?: InferSelectModel<T>[K]) => boolean;
|
|
10
|
+
message?: (value?: InferSelectModel<T>[K]) => string;
|
|
11
|
+
};
|
|
12
|
+
};
|
|
13
|
+
type PutResourceExistingConditions<T extends PgTableWithColumns<any>> = {
|
|
14
|
+
[K in keyof InferSelectModel<T>]?: (value: InferSelectModel<T>[K]) => SQLWrapper;
|
|
15
|
+
};
|
|
16
|
+
type PutResourceHandlerOptions<T extends PgTableWithColumns<any>, TSelect> = {
|
|
17
|
+
repository: TableRepository<T, TSelect>;
|
|
18
|
+
validators?: PutResourceValidators<T>;
|
|
19
|
+
existingConditions?: PutResourceExistingConditions<T>;
|
|
20
|
+
injectUserId?: boolean;
|
|
21
|
+
isOwnedBy?: (auth: AccessTokenPayload, item: TSelect) => boolean;
|
|
22
|
+
};
|
|
23
|
+
declare function putResourceHandler<T extends PgTableWithColumns<any>, TSelect>({ repository, validators, existingConditions, injectUserId, isOwnedBy, }: PutResourceHandlerOptions<T, TSelect>): (auth: AccessTokenPayload | undefined, request: Request) => Promise<Response>;
|
|
24
|
+
|
|
25
|
+
export { type PutResourceExistingConditions, type PutResourceHandlerOptions, type PutResourceValidators, putResourceHandler };
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { InferSelectModel, SQLWrapper } from 'drizzle-orm';
|
|
2
|
+
import { AccessTokenPayload } from 'gw-auth';
|
|
3
|
+
import { PgTableWithColumns } from 'drizzle-orm/pg-core';
|
|
4
|
+
import { TableRepository } from '../table/repository.js';
|
|
5
|
+
import 'drizzle-orm/node-postgres';
|
|
6
|
+
|
|
7
|
+
type PutResourceValidators<T extends PgTableWithColumns<any>> = {
|
|
8
|
+
[K in keyof InferSelectModel<T>]?: {
|
|
9
|
+
validate?: (value?: InferSelectModel<T>[K]) => boolean;
|
|
10
|
+
message?: (value?: InferSelectModel<T>[K]) => string;
|
|
11
|
+
};
|
|
12
|
+
};
|
|
13
|
+
type PutResourceExistingConditions<T extends PgTableWithColumns<any>> = {
|
|
14
|
+
[K in keyof InferSelectModel<T>]?: (value: InferSelectModel<T>[K]) => SQLWrapper;
|
|
15
|
+
};
|
|
16
|
+
type PutResourceHandlerOptions<T extends PgTableWithColumns<any>, TSelect> = {
|
|
17
|
+
repository: TableRepository<T, TSelect>;
|
|
18
|
+
validators?: PutResourceValidators<T>;
|
|
19
|
+
existingConditions?: PutResourceExistingConditions<T>;
|
|
20
|
+
injectUserId?: boolean;
|
|
21
|
+
isOwnedBy?: (auth: AccessTokenPayload, item: TSelect) => boolean;
|
|
22
|
+
};
|
|
23
|
+
declare function putResourceHandler<T extends PgTableWithColumns<any>, TSelect>({ repository, validators, existingConditions, injectUserId, isOwnedBy, }: PutResourceHandlerOptions<T, TSelect>): (auth: AccessTokenPayload | undefined, request: Request) => Promise<Response>;
|
|
24
|
+
|
|
25
|
+
export { type PutResourceExistingConditions, type PutResourceHandlerOptions, type PutResourceValidators, putResourceHandler };
|