dineway 0.1.3 → 0.1.5
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/README.md +6 -3
- package/dist/{apply-CAPvMfoU.mjs → apply-iVSqz2qs.mjs} +132 -39
- package/dist/astro/index.d.mts +18 -9
- package/dist/astro/index.mjs +238 -16
- package/dist/astro/middleware/auth.d.mts +16 -5
- package/dist/astro/middleware/auth.mjs +74 -37
- package/dist/astro/middleware/redirect.mjs +24 -8
- package/dist/astro/middleware/request-context.mjs +18 -5
- package/dist/astro/middleware/setup.mjs +1 -1
- package/dist/astro/middleware.mjs +411 -169
- package/dist/astro/types.d.mts +25 -8
- package/dist/{byline-DeWCMU_i.mjs → byline-OhH2dlRu.mjs} +6 -21
- package/dist/{bylines-DyqBV9EQ.mjs → bylines-BGpD9_hy.mjs} +16 -6
- package/dist/cache-BdSY-gQN.mjs +42 -0
- package/dist/chunks--4F8ddV4.mjs +18 -0
- package/dist/cli/index.mjs +935 -15
- package/dist/client/external-auth-headers.d.mts +1 -1
- package/dist/client/index.d.mts +11 -3
- package/dist/client/index.mjs +4 -3
- package/dist/{connection-C9pxzuag.mjs → connection-BCNICDWN.mjs} +22 -5
- package/dist/{content-zSgdNmnt.mjs → content-DWi4d0rT.mjs} +41 -2
- package/dist/database/instrumentation.d.mts +34 -0
- package/dist/database/instrumentation.mjs +53 -0
- package/dist/db/index.d.mts +3 -3
- package/dist/db/index.mjs +2 -2
- package/dist/db/libsql.d.mts +1 -1
- package/dist/db/libsql.mjs +11 -5
- package/dist/db/postgres.d.mts +1 -1
- package/dist/db/sqlite.d.mts +1 -1
- package/dist/db/sqlite.mjs +7 -1
- package/dist/db-errors-CEqD7qH9.mjs +23 -0
- package/dist/{default-WYlzADZL.mjs → default-VjJyuuG9.mjs} +2 -0
- package/dist/{dialect-helpers-B9uSp2GJ.mjs → dialect-helpers-DhTzaUxP.mjs} +3 -0
- package/dist/{error-DrxtnGPg.mjs → error-BmL6QipT.mjs} +7 -3
- package/dist/{index-C-jx21qs.d.mts → index-yvc6E_17.d.mts} +157 -30
- package/dist/index.d.mts +11 -11
- package/dist/index.mjs +24 -22
- package/dist/{loader-qKmo0wAY.mjs → loader-sMG4TZ-u.mjs} +9 -3
- package/dist/media/index.d.mts +1 -1
- package/dist/media/index.mjs +1 -1
- package/dist/media/local-runtime.d.mts +7 -7
- package/dist/page/index.d.mts +10 -2
- package/dist/page/index.mjs +22 -1
- package/dist/patterns-CrCYkMBb.mjs +92 -0
- package/dist/{placeholder-bOx1xCTY.d.mts → placeholder--wOi4TbO.d.mts} +1 -1
- package/dist/{placeholder-B3knXwNc.mjs → placeholder-Cp8g5Emj.mjs} +1 -1
- package/dist/plugins/adapt-sandbox-entry.d.mts +5 -5
- package/dist/plugins/adapt-sandbox-entry.mjs +1 -1
- package/dist/{query-BiaPl_g2.mjs → query-kDmwCsHh.mjs} +118 -50
- package/dist/{redirect-JPqLAbxa.mjs → redirect-DnEWAkVg.mjs} +43 -99
- package/dist/{registry-DSd1GWB8.mjs → registry-C0zjeB9P.mjs} +191 -123
- package/dist/request-cache-Dk5qPSOx.mjs +66 -0
- package/dist/request-context.d.mts +4 -16
- package/dist/{runner-B5l1JfOj.d.mts → runner-CFI6B6J2.d.mts} +1 -1
- package/dist/{runner-BGUGywgG.mjs → runner-DWZm2KQm.mjs} +589 -137
- package/dist/runtime.d.mts +6 -6
- package/dist/runtime.mjs +2 -2
- package/dist/{search-BNruJHDL.mjs → search-ByRGV2pq.mjs} +570 -424
- package/dist/seed/index.d.mts +2 -2
- package/dist/seed/index.mjs +11 -10
- package/dist/seo/index.d.mts +1 -1
- package/dist/storage/local.d.mts +1 -1
- package/dist/storage/local.mjs +1 -1
- package/dist/storage/s3.d.mts +11 -3
- package/dist/storage/s3.mjs +78 -15
- package/dist/taxonomies-1s5PaS_8.mjs +266 -0
- package/dist/transaction-Cn2rjY78.mjs +27 -0
- package/dist/{types-BgQeVaPj.d.mts → types-BuMDPy5C.d.mts} +52 -3
- package/dist/{types-DuNbGKjF.mjs → types-COeOq9nK.mjs} +6 -1
- package/dist/{types-ju-_ORz7.d.mts → types-CWbdtiux.d.mts} +13 -5
- package/dist/{types-D38djUXv.d.mts → types-Cj0KMIZV.d.mts} +16 -3
- package/dist/{types-DkvMXalq.d.mts → types-DOrVigru.d.mts} +159 -0
- package/dist/{validate-CXnRKfJK.mjs → validate-BZ5wnLLp.mjs} +2 -1
- package/dist/{validate-DVKJJ-M_.d.mts → validate-IPf8n4Fj.d.mts} +4 -51
- package/dist/{validate-CqRJb_xU.mjs → validate-VPnKoIzW.mjs} +10 -10
- package/dist/version-BKXPsfmJ.mjs +6 -0
- package/package.json +53 -39
- package/src/astro/routes/PluginRegistry.tsx +21 -0
- package/src/astro/routes/admin.astro +99 -0
- package/src/astro/routes/api/admin/allowed-domains/[domain].ts +112 -0
- package/src/astro/routes/api/admin/allowed-domains/index.ts +108 -0
- package/src/astro/routes/api/admin/api-tokens/[id].ts +44 -0
- package/src/astro/routes/api/admin/api-tokens/index.ts +90 -0
- package/src/astro/routes/api/admin/briefing.ts +76 -0
- package/src/astro/routes/api/admin/bylines/[id]/index.ts +90 -0
- package/src/astro/routes/api/admin/bylines/index.ts +74 -0
- package/src/astro/routes/api/admin/comments/[id]/status.ts +120 -0
- package/src/astro/routes/api/admin/comments/[id].ts +64 -0
- package/src/astro/routes/api/admin/comments/bulk.ts +42 -0
- package/src/astro/routes/api/admin/comments/counts.ts +30 -0
- package/src/astro/routes/api/admin/comments/index.ts +46 -0
- package/src/astro/routes/api/admin/context/[id]/history.ts +35 -0
- package/src/astro/routes/api/admin/context/[id]/index.ts +35 -0
- package/src/astro/routes/api/admin/context/[id]/review.ts +57 -0
- package/src/astro/routes/api/admin/context/[id]/supersede.ts +58 -0
- package/src/astro/routes/api/admin/context/diff.ts +35 -0
- package/src/astro/routes/api/admin/context/index.ts +69 -0
- package/src/astro/routes/api/admin/context/stale.ts +35 -0
- package/src/astro/routes/api/admin/hitl-requests/[id]/index.ts +38 -0
- package/src/astro/routes/api/admin/hitl-requests/[id]/resolve.ts +54 -0
- package/src/astro/routes/api/admin/hitl-requests/index.ts +38 -0
- package/src/astro/routes/api/admin/hooks/exclusive/[hookName].ts +132 -0
- package/src/astro/routes/api/admin/hooks/exclusive/index.ts +51 -0
- package/src/astro/routes/api/admin/oauth-clients/[id].ts +137 -0
- package/src/astro/routes/api/admin/oauth-clients/index.ts +95 -0
- package/src/astro/routes/api/admin/plugins/[id]/disable.ts +91 -0
- package/src/astro/routes/api/admin/plugins/[id]/enable.ts +91 -0
- package/src/astro/routes/api/admin/plugins/[id]/index.ts +38 -0
- package/src/astro/routes/api/admin/plugins/[id]/uninstall.ts +98 -0
- package/src/astro/routes/api/admin/plugins/[id]/update.ts +154 -0
- package/src/astro/routes/api/admin/plugins/index.ts +32 -0
- package/src/astro/routes/api/admin/plugins/marketplace/[id]/icon.ts +62 -0
- package/src/astro/routes/api/admin/plugins/marketplace/[id]/index.ts +33 -0
- package/src/astro/routes/api/admin/plugins/marketplace/[id]/install.ts +135 -0
- package/src/astro/routes/api/admin/plugins/marketplace/index.ts +38 -0
- package/src/astro/routes/api/admin/plugins/updates.ts +28 -0
- package/src/astro/routes/api/admin/review-requests/[id]/index.ts +35 -0
- package/src/astro/routes/api/admin/review-requests/[id]/resolve.ts +52 -0
- package/src/astro/routes/api/admin/review-requests/index.ts +35 -0
- package/src/astro/routes/api/admin/themes/marketplace/[id]/index.ts +33 -0
- package/src/astro/routes/api/admin/themes/marketplace/[id]/thumbnail.ts +62 -0
- package/src/astro/routes/api/admin/themes/marketplace/index.ts +45 -0
- package/src/astro/routes/api/admin/users/[id]/disable.ts +72 -0
- package/src/astro/routes/api/admin/users/[id]/enable.ts +48 -0
- package/src/astro/routes/api/admin/users/[id]/index.ts +166 -0
- package/src/astro/routes/api/admin/users/[id]/send-recovery.ts +72 -0
- package/src/astro/routes/api/admin/users/index.ts +66 -0
- package/src/astro/routes/api/auth/dev-bypass.ts +139 -0
- package/src/astro/routes/api/auth/invite/accept.ts +52 -0
- package/src/astro/routes/api/auth/invite/complete.ts +86 -0
- package/src/astro/routes/api/auth/invite/index.ts +99 -0
- package/src/astro/routes/api/auth/invite/register-options.ts +73 -0
- package/src/astro/routes/api/auth/logout.ts +40 -0
- package/src/astro/routes/api/auth/magic-link/send.ts +90 -0
- package/src/astro/routes/api/auth/magic-link/verify.ts +71 -0
- package/src/astro/routes/api/auth/me.ts +60 -0
- package/src/astro/routes/api/auth/oauth/[provider]/callback.ts +221 -0
- package/src/astro/routes/api/auth/oauth/[provider].ts +120 -0
- package/src/astro/routes/api/auth/passkey/[id].ts +124 -0
- package/src/astro/routes/api/auth/passkey/index.ts +54 -0
- package/src/astro/routes/api/auth/passkey/options.ts +85 -0
- package/src/astro/routes/api/auth/passkey/register/options.ts +88 -0
- package/src/astro/routes/api/auth/passkey/register/verify.ts +119 -0
- package/src/astro/routes/api/auth/passkey/verify.ts +72 -0
- package/src/astro/routes/api/auth/signup/complete.ts +87 -0
- package/src/astro/routes/api/auth/signup/request.ts +89 -0
- package/src/astro/routes/api/auth/signup/verify.ts +53 -0
- package/src/astro/routes/api/comments/[collection]/[contentId]/index.ts +310 -0
- package/src/astro/routes/api/content/[collection]/[id]/compare.ts +28 -0
- package/src/astro/routes/api/content/[collection]/[id]/discard-draft.ts +68 -0
- package/src/astro/routes/api/content/[collection]/[id]/duplicate.ts +77 -0
- package/src/astro/routes/api/content/[collection]/[id]/permanent.ts +42 -0
- package/src/astro/routes/api/content/[collection]/[id]/preview-url.ts +107 -0
- package/src/astro/routes/api/content/[collection]/[id]/publish.ts +100 -0
- package/src/astro/routes/api/content/[collection]/[id]/restore.ts +64 -0
- package/src/astro/routes/api/content/[collection]/[id]/revisions.ts +31 -0
- package/src/astro/routes/api/content/[collection]/[id]/schedule.ts +129 -0
- package/src/astro/routes/api/content/[collection]/[id]/terms/[taxonomy].ts +143 -0
- package/src/astro/routes/api/content/[collection]/[id]/translations.ts +50 -0
- package/src/astro/routes/api/content/[collection]/[id]/unpublish.ts +69 -0
- package/src/astro/routes/api/content/[collection]/[id].ts +173 -0
- package/src/astro/routes/api/content/[collection]/index.ts +103 -0
- package/src/astro/routes/api/content/[collection]/trash.ts +33 -0
- package/src/astro/routes/api/dashboard.ts +32 -0
- package/src/astro/routes/api/dev/emails.ts +36 -0
- package/src/astro/routes/api/health.ts +54 -0
- package/src/astro/routes/api/import/probe.ts +47 -0
- package/src/astro/routes/api/import/wordpress/analyze.ts +523 -0
- package/src/astro/routes/api/import/wordpress/execute.ts +330 -0
- package/src/astro/routes/api/import/wordpress/media.ts +338 -0
- package/src/astro/routes/api/import/wordpress/prepare.ts +212 -0
- package/src/astro/routes/api/import/wordpress/rewrite-urls.ts +425 -0
- package/src/astro/routes/api/import/wordpress-plugin/analyze.ts +111 -0
- package/src/astro/routes/api/import/wordpress-plugin/callback.ts +58 -0
- package/src/astro/routes/api/import/wordpress-plugin/execute.ts +399 -0
- package/src/astro/routes/api/manifest.ts +75 -0
- package/src/astro/routes/api/mcp.ts +125 -0
- package/src/astro/routes/api/media/[id]/confirm.ts +93 -0
- package/src/astro/routes/api/media/[id].ts +145 -0
- package/src/astro/routes/api/media/file/[...key].ts +79 -0
- package/src/astro/routes/api/media/providers/[providerId]/[itemId].ts +91 -0
- package/src/astro/routes/api/media/providers/[providerId]/index.ts +111 -0
- package/src/astro/routes/api/media/providers/index.ts +30 -0
- package/src/astro/routes/api/media/upload-url.ts +146 -0
- package/src/astro/routes/api/media.ts +204 -0
- package/src/astro/routes/api/menus/[name]/items.ts +206 -0
- package/src/astro/routes/api/menus/[name]/reorder.ts +79 -0
- package/src/astro/routes/api/menus/[name].ts +145 -0
- package/src/astro/routes/api/menus/index.ts +91 -0
- package/src/astro/routes/api/oauth/authorize.ts +430 -0
- package/src/astro/routes/api/oauth/device/authorize.ts +45 -0
- package/src/astro/routes/api/oauth/device/code.ts +56 -0
- package/src/astro/routes/api/oauth/device/token.ts +70 -0
- package/src/astro/routes/api/oauth/register.ts +182 -0
- package/src/astro/routes/api/oauth/token/refresh.ts +38 -0
- package/src/astro/routes/api/oauth/token/revoke.ts +38 -0
- package/src/astro/routes/api/oauth/token.ts +195 -0
- package/src/astro/routes/api/openapi.json.ts +33 -0
- package/src/astro/routes/api/plugins/[pluginId]/[...path].ts +109 -0
- package/src/astro/routes/api/redirects/404s/index.ts +72 -0
- package/src/astro/routes/api/redirects/404s/summary.ts +33 -0
- package/src/astro/routes/api/redirects/[id].ts +183 -0
- package/src/astro/routes/api/redirects/index.ts +100 -0
- package/src/astro/routes/api/revisions/[revisionId]/index.ts +29 -0
- package/src/astro/routes/api/revisions/[revisionId]/restore.ts +62 -0
- package/src/astro/routes/api/schema/collections/[slug]/fields/[fieldSlug].ts +104 -0
- package/src/astro/routes/api/schema/collections/[slug]/fields/index.ts +67 -0
- package/src/astro/routes/api/schema/collections/[slug]/fields/reorder.ts +45 -0
- package/src/astro/routes/api/schema/collections/[slug]/index.ts +107 -0
- package/src/astro/routes/api/schema/collections/index.ts +61 -0
- package/src/astro/routes/api/schema/index.ts +109 -0
- package/src/astro/routes/api/schema/orphans/[slug].ts +36 -0
- package/src/astro/routes/api/schema/orphans/index.ts +26 -0
- package/src/astro/routes/api/search/enable.ts +64 -0
- package/src/astro/routes/api/search/index.ts +52 -0
- package/src/astro/routes/api/search/rebuild.ts +72 -0
- package/src/astro/routes/api/search/stats.ts +35 -0
- package/src/astro/routes/api/search/suggest.ts +50 -0
- package/src/astro/routes/api/sections/[slug].ts +203 -0
- package/src/astro/routes/api/sections/index.ts +107 -0
- package/src/astro/routes/api/settings/email.ts +150 -0
- package/src/astro/routes/api/settings.ts +116 -0
- package/src/astro/routes/api/setup/admin-verify.ts +122 -0
- package/src/astro/routes/api/setup/admin.ts +104 -0
- package/src/astro/routes/api/setup/dev-bypass.ts +200 -0
- package/src/astro/routes/api/setup/dev-reset.ts +40 -0
- package/src/astro/routes/api/setup/index.ts +128 -0
- package/src/astro/routes/api/setup/status.ts +122 -0
- package/src/astro/routes/api/snapshot.ts +76 -0
- package/src/astro/routes/api/taxonomies/[name]/terms/[slug].ts +232 -0
- package/src/astro/routes/api/taxonomies/[name]/terms/index.ts +131 -0
- package/src/astro/routes/api/taxonomies/index.ts +114 -0
- package/src/astro/routes/api/themes/preview.ts +78 -0
- package/src/astro/routes/api/typegen.ts +114 -0
- package/src/astro/routes/api/well-known/auth.ts +71 -0
- package/src/astro/routes/api/well-known/oauth-authorization-server.ts +48 -0
- package/src/astro/routes/api/well-known/oauth-protected-resource.ts +39 -0
- package/src/astro/routes/api/widget-areas/[name]/reorder.ts +114 -0
- package/src/astro/routes/api/widget-areas/[name]/widgets/[id].ts +213 -0
- package/src/astro/routes/api/widget-areas/[name]/widgets.ts +126 -0
- package/src/astro/routes/api/widget-areas/[name].ts +135 -0
- package/src/astro/routes/api/widget-areas/index.ts +149 -0
- package/src/astro/routes/api/widget-components.ts +22 -0
- package/src/astro/routes/robots.txt.ts +81 -0
- package/src/astro/routes/sitemap-[collection].xml.ts +104 -0
- package/src/astro/routes/sitemap.xml.ts +92 -0
- package/src/components/Break.astro +45 -0
- package/src/components/Button.astro +71 -0
- package/src/components/Buttons.astro +49 -0
- package/src/components/Code.astro +59 -0
- package/src/components/Columns.astro +59 -0
- package/src/components/CommentForm.astro +315 -0
- package/src/components/Comments.astro +232 -0
- package/src/components/Cover.astro +128 -0
- package/src/components/DinewayBodyEnd.astro +32 -0
- package/src/components/DinewayBodyStart.astro +32 -0
- package/src/components/DinewayHead.astro +61 -0
- package/src/components/DinewayImage.astro +178 -0
- package/src/components/DinewayMedia.astro +167 -0
- package/src/components/Embed.astro +128 -0
- package/src/components/File.astro +122 -0
- package/src/components/Gallery.astro +93 -0
- package/src/components/HtmlBlock.astro +33 -0
- package/src/components/Image.astro +178 -0
- package/src/components/InlineEditor.astro +27 -0
- package/src/components/InlinePortableTextEditor.tsx +1937 -0
- package/src/components/LiveSearch.astro +614 -0
- package/src/components/PortableText.astro +51 -0
- package/src/components/Pullquote.astro +51 -0
- package/src/components/Table.astro +135 -0
- package/src/components/WidgetArea.astro +22 -0
- package/src/components/WidgetRenderer.astro +72 -0
- package/src/components/index.ts +106 -0
- package/src/components/marks/Link.astro +31 -0
- package/src/components/marks/StrikeThrough.astro +7 -0
- package/src/components/marks/Subscript.astro +7 -0
- package/src/components/marks/Superscript.astro +7 -0
- package/src/components/marks/Underline.astro +7 -0
- package/src/components/marks.ts +19 -0
- package/src/components/widgets/Archives.astro +65 -0
- package/src/components/widgets/Categories.astro +35 -0
- package/src/components/widgets/RecentPosts.astro +51 -0
- package/src/components/widgets/Search.astro +18 -0
- package/src/components/widgets/Tags.astro +38 -0
- package/src/ui.ts +75 -0
- package/LICENSE +0 -9
- /package/dist/{adapters-BlzWJG82.d.mts → adapters-C2ypTrZZ.d.mts} +0 -0
- /package/dist/{config-Cq8H0SfX.mjs → config-BXwuX8Bx.mjs} +0 -0
- /package/dist/{load-C6FCD1FU.mjs → load-Coc9HpHH.mjs} +0 -0
- /package/dist/{manifest-schema-CTSEyIJ3.mjs → manifest-schema-D1MSVnoI.mjs} +0 -0
- /package/dist/{mode-BlyYtIFO.mjs → mode-47goXBBK.mjs} +0 -0
- /package/dist/{tokens-4vgYuXsZ.mjs → tokens-CJz9ubV6.mjs} +0 -0
- /package/dist/{transport-C5FYnid7.mjs → transport-DB5eDN4x.mjs} +0 -0
- /package/dist/{transport-gIL-e43D.d.mts → transport-Wge_IzKl.d.mts} +0 -0
- /package/dist/{types-CLLdsG3g.d.mts → types-BzcUjoqg.d.mts} +0 -0
- /package/dist/{types-DShnjzb6.mjs → types-griIBQOQ.mjs} +0 -0
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Comment status change
|
|
3
|
+
*
|
|
4
|
+
* PUT /_dineway/api/admin/comments/:id/status - Change comment status
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import type { APIRoute } from "astro";
|
|
8
|
+
|
|
9
|
+
import { requirePerm } from "#api/authorize.js";
|
|
10
|
+
import { apiError, apiSuccess, handleError, requireDb, unwrapResult } from "#api/error.js";
|
|
11
|
+
import { handleCommentGet } from "#api/handlers/comments.js";
|
|
12
|
+
import { isParseError, parseBody } from "#api/parse.js";
|
|
13
|
+
import { commentStatusBody } from "#api/schemas.js";
|
|
14
|
+
import { getSiteBaseUrl } from "#api/site-url.js";
|
|
15
|
+
import { lookupContentAuthor, sendCommentNotification } from "#comments/notifications.js";
|
|
16
|
+
import { moderateComment, type CommentHookRunner } from "#comments/service.js";
|
|
17
|
+
import type { CommentStatus } from "#db/repositories/comment.js";
|
|
18
|
+
import type { ModerationDecision } from "#plugins/types.js";
|
|
19
|
+
|
|
20
|
+
export const prerender = false;
|
|
21
|
+
|
|
22
|
+
export const PUT: APIRoute = async ({ params, request, locals }) => {
|
|
23
|
+
const { dineway, user } = locals;
|
|
24
|
+
const { id } = params;
|
|
25
|
+
|
|
26
|
+
if (!id) {
|
|
27
|
+
return apiError("VALIDATION_ERROR", "Comment ID required", 400);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const dbErr = requireDb(dineway?.db);
|
|
31
|
+
if (dbErr) return dbErr;
|
|
32
|
+
|
|
33
|
+
const denied = requirePerm(user, "comments:moderate");
|
|
34
|
+
if (denied) return denied;
|
|
35
|
+
|
|
36
|
+
try {
|
|
37
|
+
const body = await parseBody(request, commentStatusBody);
|
|
38
|
+
if (isParseError(body)) return body;
|
|
39
|
+
|
|
40
|
+
const newStatus = body.status as CommentStatus;
|
|
41
|
+
|
|
42
|
+
// Build hook runner for the service
|
|
43
|
+
const hookRunner: CommentHookRunner = {
|
|
44
|
+
async runBeforeCreate(event) {
|
|
45
|
+
return dineway.hooks.runCommentBeforeCreate(event);
|
|
46
|
+
},
|
|
47
|
+
async runModerate(event) {
|
|
48
|
+
const result = await dineway.hooks.invokeExclusiveHook("comment:moderate", event);
|
|
49
|
+
if (!result) return { status: "pending" as const, reason: "No moderator configured" };
|
|
50
|
+
if (result.error) return { status: "pending" as const, reason: "Moderation error" };
|
|
51
|
+
return result.result as ModerationDecision;
|
|
52
|
+
},
|
|
53
|
+
fireAfterCreate(event) {
|
|
54
|
+
dineway.hooks
|
|
55
|
+
.runCommentAfterCreate(event)
|
|
56
|
+
.catch((err) =>
|
|
57
|
+
console.error(
|
|
58
|
+
"[comments] afterCreate error:",
|
|
59
|
+
err instanceof Error ? err.message : err,
|
|
60
|
+
),
|
|
61
|
+
);
|
|
62
|
+
},
|
|
63
|
+
fireAfterModerate(event) {
|
|
64
|
+
dineway.hooks
|
|
65
|
+
.runCommentAfterModerate(event)
|
|
66
|
+
.catch((err) =>
|
|
67
|
+
console.error(
|
|
68
|
+
"[comments] afterModerate error:",
|
|
69
|
+
err instanceof Error ? err.message : err,
|
|
70
|
+
),
|
|
71
|
+
);
|
|
72
|
+
},
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
// Read the comment before updating so we know the previous status
|
|
76
|
+
const existing = await handleCommentGet(dineway.db, id);
|
|
77
|
+
if (!existing.success) {
|
|
78
|
+
return unwrapResult(existing);
|
|
79
|
+
}
|
|
80
|
+
const previousStatus = existing.data.status;
|
|
81
|
+
|
|
82
|
+
const updated = await moderateComment(
|
|
83
|
+
dineway.db,
|
|
84
|
+
id,
|
|
85
|
+
newStatus,
|
|
86
|
+
{ id: user!.id, name: user!.name ?? null },
|
|
87
|
+
hookRunner,
|
|
88
|
+
);
|
|
89
|
+
|
|
90
|
+
if (!updated) {
|
|
91
|
+
return apiError("NOT_FOUND", "Comment not found", 404);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// Send notification when a comment is newly approved
|
|
95
|
+
if (newStatus === "approved" && previousStatus !== "approved" && dineway.email) {
|
|
96
|
+
try {
|
|
97
|
+
const adminBaseUrl = await getSiteBaseUrl(dineway.db, request);
|
|
98
|
+
const content = await lookupContentAuthor(
|
|
99
|
+
dineway.db,
|
|
100
|
+
updated.collection,
|
|
101
|
+
updated.contentId,
|
|
102
|
+
);
|
|
103
|
+
if (content?.author) {
|
|
104
|
+
await sendCommentNotification({
|
|
105
|
+
email: dineway.email,
|
|
106
|
+
comment: updated,
|
|
107
|
+
contentAuthor: content.author,
|
|
108
|
+
adminBaseUrl,
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
} catch (err) {
|
|
112
|
+
console.error("[comments] notification error:", err instanceof Error ? err.message : err);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
return apiSuccess(updated);
|
|
117
|
+
} catch (error) {
|
|
118
|
+
return handleError(error, "Failed to update comment status", "COMMENT_STATUS_ERROR");
|
|
119
|
+
}
|
|
120
|
+
};
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Single comment admin endpoints
|
|
3
|
+
*
|
|
4
|
+
* GET /_dineway/api/admin/comments/:id - Get comment detail
|
|
5
|
+
* DELETE /_dineway/api/admin/comments/:id - Hard delete (ADMIN only)
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import type { APIRoute } from "astro";
|
|
9
|
+
|
|
10
|
+
import { requirePerm } from "#api/authorize.js";
|
|
11
|
+
import { apiError, handleError, requireDb, unwrapResult } from "#api/error.js";
|
|
12
|
+
import { handleCommentGet, handleCommentDelete } from "#api/handlers/comments.js";
|
|
13
|
+
|
|
14
|
+
export const prerender = false;
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Get single comment detail (includes moderation_metadata)
|
|
18
|
+
*/
|
|
19
|
+
export const GET: APIRoute = async ({ params, locals }) => {
|
|
20
|
+
const { dineway, user } = locals;
|
|
21
|
+
const { id } = params;
|
|
22
|
+
|
|
23
|
+
if (!id) {
|
|
24
|
+
return apiError("VALIDATION_ERROR", "Comment ID required", 400);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
const dbErr = requireDb(dineway?.db);
|
|
28
|
+
if (dbErr) return dbErr;
|
|
29
|
+
|
|
30
|
+
const denied = requirePerm(user, "comments:moderate");
|
|
31
|
+
if (denied) return denied;
|
|
32
|
+
|
|
33
|
+
try {
|
|
34
|
+
const result = await handleCommentGet(dineway.db, id);
|
|
35
|
+
return unwrapResult(result);
|
|
36
|
+
} catch (error) {
|
|
37
|
+
return handleError(error, "Failed to get comment", "COMMENT_GET_ERROR");
|
|
38
|
+
}
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Hard delete a comment (ADMIN only)
|
|
43
|
+
*/
|
|
44
|
+
export const DELETE: APIRoute = async ({ params, locals }) => {
|
|
45
|
+
const { dineway, user } = locals;
|
|
46
|
+
const { id } = params;
|
|
47
|
+
|
|
48
|
+
if (!id) {
|
|
49
|
+
return apiError("VALIDATION_ERROR", "Comment ID required", 400);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
const dbErr = requireDb(dineway?.db);
|
|
53
|
+
if (dbErr) return dbErr;
|
|
54
|
+
|
|
55
|
+
const denied = requirePerm(user, "comments:delete");
|
|
56
|
+
if (denied) return denied;
|
|
57
|
+
|
|
58
|
+
try {
|
|
59
|
+
const result = await handleCommentDelete(dineway.db, id);
|
|
60
|
+
return unwrapResult(result);
|
|
61
|
+
} catch (error) {
|
|
62
|
+
return handleError(error, "Failed to delete comment", "COMMENT_DELETE_ERROR");
|
|
63
|
+
}
|
|
64
|
+
};
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Bulk comment operations
|
|
3
|
+
*
|
|
4
|
+
* POST /_dineway/api/admin/comments/bulk - Bulk status change or delete
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import type { APIRoute } from "astro";
|
|
8
|
+
|
|
9
|
+
import { requirePerm } from "#api/authorize.js";
|
|
10
|
+
import { handleError, requireDb, unwrapResult } from "#api/error.js";
|
|
11
|
+
import { handleCommentBulk } from "#api/handlers/comments.js";
|
|
12
|
+
import { isParseError, parseBody } from "#api/parse.js";
|
|
13
|
+
import { commentBulkBody } from "#api/schemas.js";
|
|
14
|
+
|
|
15
|
+
export const prerender = false;
|
|
16
|
+
|
|
17
|
+
export const POST: APIRoute = async ({ request, locals }) => {
|
|
18
|
+
const { dineway, user } = locals;
|
|
19
|
+
|
|
20
|
+
const dbErr = requireDb(dineway?.db);
|
|
21
|
+
if (dbErr) return dbErr;
|
|
22
|
+
|
|
23
|
+
try {
|
|
24
|
+
const body = await parseBody(request, commentBulkBody);
|
|
25
|
+
if (isParseError(body)) return body;
|
|
26
|
+
|
|
27
|
+
// Bulk delete requires ADMIN, bulk status change requires EDITOR
|
|
28
|
+
if (body.action === "delete") {
|
|
29
|
+
const denied = requirePerm(user, "comments:delete");
|
|
30
|
+
if (denied) return denied;
|
|
31
|
+
} else {
|
|
32
|
+
const denied = requirePerm(user, "comments:moderate");
|
|
33
|
+
if (denied) return denied;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
const result = await handleCommentBulk(dineway.db, body.ids, body.action);
|
|
37
|
+
|
|
38
|
+
return unwrapResult(result);
|
|
39
|
+
} catch (error) {
|
|
40
|
+
return handleError(error, "Failed to perform bulk operation", "COMMENT_BULK_ERROR");
|
|
41
|
+
}
|
|
42
|
+
};
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Comment status counts for inbox badges
|
|
3
|
+
*
|
|
4
|
+
* GET /_dineway/api/admin/comments/counts
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import type { APIRoute } from "astro";
|
|
8
|
+
|
|
9
|
+
import { requirePerm } from "#api/authorize.js";
|
|
10
|
+
import { handleError, requireDb, unwrapResult } from "#api/error.js";
|
|
11
|
+
import { handleCommentCounts } from "#api/handlers/comments.js";
|
|
12
|
+
|
|
13
|
+
export const prerender = false;
|
|
14
|
+
|
|
15
|
+
export const GET: APIRoute = async ({ locals }) => {
|
|
16
|
+
const { dineway, user } = locals;
|
|
17
|
+
|
|
18
|
+
const dbErr = requireDb(dineway?.db);
|
|
19
|
+
if (dbErr) return dbErr;
|
|
20
|
+
|
|
21
|
+
const denied = requirePerm(user, "comments:moderate");
|
|
22
|
+
if (denied) return denied;
|
|
23
|
+
|
|
24
|
+
try {
|
|
25
|
+
const result = await handleCommentCounts(dineway.db);
|
|
26
|
+
return unwrapResult(result);
|
|
27
|
+
} catch (error) {
|
|
28
|
+
return handleError(error, "Failed to get comment counts", "COMMENT_COUNTS_ERROR");
|
|
29
|
+
}
|
|
30
|
+
};
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Admin comment inbox
|
|
3
|
+
*
|
|
4
|
+
* GET /_dineway/api/admin/comments - List comments (filterable by status, collection, search)
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import type { APIRoute } from "astro";
|
|
8
|
+
|
|
9
|
+
import { requirePerm } from "#api/authorize.js";
|
|
10
|
+
import { handleError, requireDb, unwrapResult } from "#api/error.js";
|
|
11
|
+
import { handleCommentInbox } from "#api/handlers/comments.js";
|
|
12
|
+
import { isParseError, parseQuery } from "#api/parse.js";
|
|
13
|
+
import { commentListQuery } from "#api/schemas.js";
|
|
14
|
+
import type { CommentStatus } from "#db/repositories/comment.js";
|
|
15
|
+
|
|
16
|
+
export const prerender = false;
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* List comments for moderation inbox
|
|
20
|
+
*/
|
|
21
|
+
export const GET: APIRoute = async ({ url, locals }) => {
|
|
22
|
+
const { dineway, user } = locals;
|
|
23
|
+
|
|
24
|
+
const dbErr = requireDb(dineway?.db);
|
|
25
|
+
if (dbErr) return dbErr;
|
|
26
|
+
|
|
27
|
+
const denied = requirePerm(user, "comments:moderate");
|
|
28
|
+
if (denied) return denied;
|
|
29
|
+
|
|
30
|
+
try {
|
|
31
|
+
const query = parseQuery(url, commentListQuery);
|
|
32
|
+
if (isParseError(query)) return query;
|
|
33
|
+
|
|
34
|
+
const result = await handleCommentInbox(dineway.db, {
|
|
35
|
+
status: query.status as CommentStatus | undefined,
|
|
36
|
+
collection: query.collection,
|
|
37
|
+
search: query.search,
|
|
38
|
+
limit: query.limit,
|
|
39
|
+
cursor: query.cursor,
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
return unwrapResult(result);
|
|
43
|
+
} catch (error) {
|
|
44
|
+
return handleError(error, "Failed to list comments", "COMMENT_INBOX_ERROR");
|
|
45
|
+
}
|
|
46
|
+
};
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Admin context supersede history
|
|
3
|
+
*
|
|
4
|
+
* GET /_dineway/api/admin/context/:id/history - Get a context entry supersede chain
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import type { APIRoute } from "astro";
|
|
8
|
+
|
|
9
|
+
import { requirePerm } from "#api/authorize.js";
|
|
10
|
+
import { apiError, handleError, requireDb, unwrapResult } from "#api/error.js";
|
|
11
|
+
import { handleContextEntryHistory } from "#api/handlers/context.js";
|
|
12
|
+
|
|
13
|
+
export const prerender = false;
|
|
14
|
+
|
|
15
|
+
export const GET: APIRoute = async ({ params, locals }) => {
|
|
16
|
+
const { dineway, user } = locals;
|
|
17
|
+
const { id } = params;
|
|
18
|
+
|
|
19
|
+
if (!id) {
|
|
20
|
+
return apiError("VALIDATION_ERROR", "Context entry ID required", 400);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
const dbErr = requireDb(dineway?.db);
|
|
24
|
+
if (dbErr) return dbErr;
|
|
25
|
+
|
|
26
|
+
const denied = requirePerm(user, "settings:read");
|
|
27
|
+
if (denied) return denied;
|
|
28
|
+
|
|
29
|
+
try {
|
|
30
|
+
const result = await handleContextEntryHistory(dineway.db, id);
|
|
31
|
+
return unwrapResult(result);
|
|
32
|
+
} catch (error) {
|
|
33
|
+
return handleError(error, "Failed to load context history", "CONTEXT_HISTORY_ERROR");
|
|
34
|
+
}
|
|
35
|
+
};
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Admin context entry detail
|
|
3
|
+
*
|
|
4
|
+
* GET /_dineway/api/admin/context/:id - Get a context entry
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import type { APIRoute } from "astro";
|
|
8
|
+
|
|
9
|
+
import { requirePerm } from "#api/authorize.js";
|
|
10
|
+
import { apiError, handleError, requireDb, unwrapResult } from "#api/error.js";
|
|
11
|
+
import { handleContextEntryGet } from "#api/handlers/context.js";
|
|
12
|
+
|
|
13
|
+
export const prerender = false;
|
|
14
|
+
|
|
15
|
+
export const GET: APIRoute = async ({ params, locals }) => {
|
|
16
|
+
const { dineway, user } = locals;
|
|
17
|
+
const { id } = params;
|
|
18
|
+
|
|
19
|
+
if (!id) {
|
|
20
|
+
return apiError("VALIDATION_ERROR", "Context entry ID required", 400);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
const dbErr = requireDb(dineway?.db);
|
|
24
|
+
if (dbErr) return dbErr;
|
|
25
|
+
|
|
26
|
+
const denied = requirePerm(user, "settings:read");
|
|
27
|
+
if (denied) return denied;
|
|
28
|
+
|
|
29
|
+
try {
|
|
30
|
+
const result = await handleContextEntryGet(dineway.db, id);
|
|
31
|
+
return unwrapResult(result);
|
|
32
|
+
} catch (error) {
|
|
33
|
+
return handleError(error, "Failed to get context entry", "CONTEXT_GET_ERROR");
|
|
34
|
+
}
|
|
35
|
+
};
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Admin context review
|
|
3
|
+
*
|
|
4
|
+
* POST /_dineway/api/admin/context/:id/review - Mark a context entry reviewed
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import type { APIRoute } from "astro";
|
|
8
|
+
|
|
9
|
+
import { requirePerm } from "#api/authorize.js";
|
|
10
|
+
import { logContextRouteActivity, resolveContextRouteActor } from "#api/context-route-helpers.js";
|
|
11
|
+
import { apiError, handleError, requireDb, unwrapResult } from "#api/error.js";
|
|
12
|
+
import { handleContextEntryReview } from "#api/handlers/context.js";
|
|
13
|
+
import { isParseError, parseBody } from "#api/parse.js";
|
|
14
|
+
import { contextEntryReviewBody } from "#api/schemas.js";
|
|
15
|
+
|
|
16
|
+
export const prerender = false;
|
|
17
|
+
|
|
18
|
+
export const POST: APIRoute = async ({ params, request, locals }) => {
|
|
19
|
+
const { dineway, user } = locals;
|
|
20
|
+
const { id } = params;
|
|
21
|
+
|
|
22
|
+
if (!id) {
|
|
23
|
+
return apiError("VALIDATION_ERROR", "Context entry ID required", 400);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const dbErr = requireDb(dineway?.db);
|
|
27
|
+
if (dbErr) return dbErr;
|
|
28
|
+
|
|
29
|
+
const denied = requirePerm(user, "content:edit_any");
|
|
30
|
+
if (denied) return denied;
|
|
31
|
+
|
|
32
|
+
try {
|
|
33
|
+
const body = await parseBody(request, contextEntryReviewBody);
|
|
34
|
+
if (isParseError(body)) return body;
|
|
35
|
+
|
|
36
|
+
const result = await handleContextEntryReview(
|
|
37
|
+
dineway.db,
|
|
38
|
+
id,
|
|
39
|
+
body,
|
|
40
|
+
resolveContextRouteActor(locals),
|
|
41
|
+
);
|
|
42
|
+
if (!result.success) return unwrapResult(result);
|
|
43
|
+
|
|
44
|
+
await logContextRouteActivity(dineway.db, locals, {
|
|
45
|
+
actionType: "context.reviewed",
|
|
46
|
+
entry: result.data.item,
|
|
47
|
+
summary: `Reviewed context entry ${result.data.item.title}`,
|
|
48
|
+
detail: {
|
|
49
|
+
validUntil: result.data.item.validUntil,
|
|
50
|
+
},
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
return unwrapResult(result);
|
|
54
|
+
} catch (error) {
|
|
55
|
+
return handleError(error, "Failed to review context entry", "CONTEXT_REVIEW_ERROR");
|
|
56
|
+
}
|
|
57
|
+
};
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Admin context supersede
|
|
3
|
+
*
|
|
4
|
+
* POST /_dineway/api/admin/context/:id/supersede - Replace a context entry
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import type { APIRoute } from "astro";
|
|
8
|
+
|
|
9
|
+
import { requirePerm } from "#api/authorize.js";
|
|
10
|
+
import { logContextRouteActivity, resolveContextRouteActor } from "#api/context-route-helpers.js";
|
|
11
|
+
import { apiError, handleError, requireDb, unwrapResult } from "#api/error.js";
|
|
12
|
+
import { handleContextEntrySupersede } from "#api/handlers/context.js";
|
|
13
|
+
import { isParseError, parseBody } from "#api/parse.js";
|
|
14
|
+
import { contextEntrySupersedeBody } from "#api/schemas.js";
|
|
15
|
+
|
|
16
|
+
export const prerender = false;
|
|
17
|
+
|
|
18
|
+
export const POST: APIRoute = async ({ params, request, locals }) => {
|
|
19
|
+
const { dineway, user } = locals;
|
|
20
|
+
const { id } = params;
|
|
21
|
+
|
|
22
|
+
if (!id) {
|
|
23
|
+
return apiError("VALIDATION_ERROR", "Context entry ID required", 400);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const dbErr = requireDb(dineway?.db);
|
|
27
|
+
if (dbErr) return dbErr;
|
|
28
|
+
|
|
29
|
+
const denied = requirePerm(user, "content:edit_any");
|
|
30
|
+
if (denied) return denied;
|
|
31
|
+
|
|
32
|
+
try {
|
|
33
|
+
const body = await parseBody(request, contextEntrySupersedeBody);
|
|
34
|
+
if (isParseError(body)) return body;
|
|
35
|
+
|
|
36
|
+
const result = await handleContextEntrySupersede(
|
|
37
|
+
dineway.db,
|
|
38
|
+
id,
|
|
39
|
+
body,
|
|
40
|
+
resolveContextRouteActor(locals),
|
|
41
|
+
);
|
|
42
|
+
if (!result.success) return unwrapResult(result);
|
|
43
|
+
|
|
44
|
+
await logContextRouteActivity(dineway.db, locals, {
|
|
45
|
+
actionType: "context.superseded",
|
|
46
|
+
entry: result.data.item,
|
|
47
|
+
summary: `Superseded context entry ${id}`,
|
|
48
|
+
detail: {
|
|
49
|
+
supersedesId: id,
|
|
50
|
+
replacementId: result.data.item.id,
|
|
51
|
+
},
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
return unwrapResult(result);
|
|
55
|
+
} catch (error) {
|
|
56
|
+
return handleError(error, "Failed to supersede context entry", "CONTEXT_SUPERSEDE_ERROR");
|
|
57
|
+
}
|
|
58
|
+
};
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Admin context diff
|
|
3
|
+
*
|
|
4
|
+
* GET /_dineway/api/admin/context/diff - Diff context entries since a timestamp
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import type { APIRoute } from "astro";
|
|
8
|
+
|
|
9
|
+
import { requirePerm } from "#api/authorize.js";
|
|
10
|
+
import { handleError, requireDb, unwrapResult } from "#api/error.js";
|
|
11
|
+
import { handleContextEntryDiff } from "#api/handlers/context.js";
|
|
12
|
+
import { isParseError, parseQuery } from "#api/parse.js";
|
|
13
|
+
import { contextEntryDiffQuery } from "#api/schemas.js";
|
|
14
|
+
|
|
15
|
+
export const prerender = false;
|
|
16
|
+
|
|
17
|
+
export const GET: APIRoute = async ({ url, locals }) => {
|
|
18
|
+
const { dineway, user } = locals;
|
|
19
|
+
|
|
20
|
+
const dbErr = requireDb(dineway?.db);
|
|
21
|
+
if (dbErr) return dbErr;
|
|
22
|
+
|
|
23
|
+
const denied = requirePerm(user, "settings:read");
|
|
24
|
+
if (denied) return denied;
|
|
25
|
+
|
|
26
|
+
try {
|
|
27
|
+
const query = parseQuery(url, contextEntryDiffQuery);
|
|
28
|
+
if (isParseError(query)) return query;
|
|
29
|
+
|
|
30
|
+
const result = await handleContextEntryDiff(dineway.db, query);
|
|
31
|
+
return unwrapResult(result);
|
|
32
|
+
} catch (error) {
|
|
33
|
+
return handleError(error, "Failed to diff context entries", "CONTEXT_DIFF_ERROR");
|
|
34
|
+
}
|
|
35
|
+
};
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Admin context entry browser
|
|
3
|
+
*
|
|
4
|
+
* GET /_dineway/api/admin/context - List/search context entries
|
|
5
|
+
* POST /_dineway/api/admin/context - Add a context entry
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import type { APIRoute } from "astro";
|
|
9
|
+
|
|
10
|
+
import { requirePerm } from "#api/authorize.js";
|
|
11
|
+
import { logContextRouteActivity, resolveContextRouteActor } from "#api/context-route-helpers.js";
|
|
12
|
+
import { handleError, requireDb, unwrapResult } from "#api/error.js";
|
|
13
|
+
import { handleContextEntryCreate, handleContextEntryList } from "#api/handlers/context.js";
|
|
14
|
+
import { isParseError, parseBody, parseQuery } from "#api/parse.js";
|
|
15
|
+
import { contextEntryCreateBody, contextEntryListQuery } from "#api/schemas.js";
|
|
16
|
+
|
|
17
|
+
export const prerender = false;
|
|
18
|
+
|
|
19
|
+
export const GET: APIRoute = async ({ url, locals }) => {
|
|
20
|
+
const { dineway, user } = locals;
|
|
21
|
+
|
|
22
|
+
const dbErr = requireDb(dineway?.db);
|
|
23
|
+
if (dbErr) return dbErr;
|
|
24
|
+
|
|
25
|
+
const denied = requirePerm(user, "settings:read");
|
|
26
|
+
if (denied) return denied;
|
|
27
|
+
|
|
28
|
+
try {
|
|
29
|
+
const query = parseQuery(url, contextEntryListQuery);
|
|
30
|
+
if (isParseError(query)) return query;
|
|
31
|
+
|
|
32
|
+
const result = await handleContextEntryList(dineway.db, query);
|
|
33
|
+
return unwrapResult(result);
|
|
34
|
+
} catch (error) {
|
|
35
|
+
return handleError(error, "Failed to list context entries", "CONTEXT_LIST_ERROR");
|
|
36
|
+
}
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
export const POST: APIRoute = async ({ request, locals }) => {
|
|
40
|
+
const { dineway, user } = locals;
|
|
41
|
+
|
|
42
|
+
const dbErr = requireDb(dineway?.db);
|
|
43
|
+
if (dbErr) return dbErr;
|
|
44
|
+
|
|
45
|
+
const denied = requirePerm(user, "content:edit_any");
|
|
46
|
+
if (denied) return denied;
|
|
47
|
+
|
|
48
|
+
try {
|
|
49
|
+
const body = await parseBody(request, contextEntryCreateBody);
|
|
50
|
+
if (isParseError(body)) return body;
|
|
51
|
+
|
|
52
|
+
const result = await handleContextEntryCreate(
|
|
53
|
+
dineway.db,
|
|
54
|
+
body,
|
|
55
|
+
resolveContextRouteActor(locals),
|
|
56
|
+
);
|
|
57
|
+
if (!result.success) return unwrapResult(result);
|
|
58
|
+
|
|
59
|
+
await logContextRouteActivity(dineway.db, locals, {
|
|
60
|
+
actionType: "context.added",
|
|
61
|
+
entry: result.data.item,
|
|
62
|
+
summary: `Added ${result.data.item.contextType} context: ${result.data.item.title}`,
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
return unwrapResult(result, 201);
|
|
66
|
+
} catch (error) {
|
|
67
|
+
return handleError(error, "Failed to create context entry", "CONTEXT_CREATE_ERROR");
|
|
68
|
+
}
|
|
69
|
+
};
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Admin stale context entries
|
|
3
|
+
*
|
|
4
|
+
* GET /_dineway/api/admin/context/stale - List current entries past valid_until
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import type { APIRoute } from "astro";
|
|
8
|
+
|
|
9
|
+
import { requirePerm } from "#api/authorize.js";
|
|
10
|
+
import { handleError, requireDb, unwrapResult } from "#api/error.js";
|
|
11
|
+
import { handleContextEntryStale } from "#api/handlers/context.js";
|
|
12
|
+
import { isParseError, parseQuery } from "#api/parse.js";
|
|
13
|
+
import { contextEntryStaleQuery } from "#api/schemas.js";
|
|
14
|
+
|
|
15
|
+
export const prerender = false;
|
|
16
|
+
|
|
17
|
+
export const GET: APIRoute = async ({ url, locals }) => {
|
|
18
|
+
const { dineway, user } = locals;
|
|
19
|
+
|
|
20
|
+
const dbErr = requireDb(dineway?.db);
|
|
21
|
+
if (dbErr) return dbErr;
|
|
22
|
+
|
|
23
|
+
const denied = requirePerm(user, "settings:read");
|
|
24
|
+
if (denied) return denied;
|
|
25
|
+
|
|
26
|
+
try {
|
|
27
|
+
const query = parseQuery(url, contextEntryStaleQuery);
|
|
28
|
+
if (isParseError(query)) return query;
|
|
29
|
+
|
|
30
|
+
const result = await handleContextEntryStale(dineway.db, query);
|
|
31
|
+
return unwrapResult(result);
|
|
32
|
+
} catch (error) {
|
|
33
|
+
return handleError(error, "Failed to list stale context entries", "CONTEXT_STALE_ERROR");
|
|
34
|
+
}
|
|
35
|
+
};
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Admin HITL request detail
|
|
3
|
+
*
|
|
4
|
+
* GET /_dineway/api/admin/hitl-requests/:id - Get a generic HITL request
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { Role } from "@dineway-ai/auth";
|
|
8
|
+
import type { APIRoute } from "astro";
|
|
9
|
+
|
|
10
|
+
import { apiError, handleError, requireDb, unwrapResult } from "#api/error.js";
|
|
11
|
+
import { handleHitlRequestGet } from "#api/handlers/hitl-requests.js";
|
|
12
|
+
import { resolveHitlRouteActor } from "#api/hitl-route-helpers.js";
|
|
13
|
+
|
|
14
|
+
export const prerender = false;
|
|
15
|
+
|
|
16
|
+
export const GET: APIRoute = async ({ params, locals }) => {
|
|
17
|
+
const { dineway, user } = locals;
|
|
18
|
+
const { id } = params;
|
|
19
|
+
|
|
20
|
+
if (!id) {
|
|
21
|
+
return apiError("VALIDATION_ERROR", "HITL request ID required", 400);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const dbErr = requireDb(dineway?.db);
|
|
25
|
+
if (dbErr) return dbErr;
|
|
26
|
+
|
|
27
|
+
if (!user || user.role < Role.ADMIN) {
|
|
28
|
+
return apiError("FORBIDDEN", "Admin privileges required", 403);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
try {
|
|
32
|
+
const actor = resolveHitlRouteActor(locals);
|
|
33
|
+
const result = await handleHitlRequestGet(dineway.db, id, actor.access);
|
|
34
|
+
return unwrapResult(result);
|
|
35
|
+
} catch (error) {
|
|
36
|
+
return handleError(error, "Failed to fetch HITL request", "WORKFLOW_HITL_GET_ERROR");
|
|
37
|
+
}
|
|
38
|
+
};
|