studiocms 0.2.0 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +122 -0
- package/dist/cli/add/index.d.ts +2 -2
- package/dist/cli/add/index.js +4 -3
- package/dist/cli/add/npm-utils.d.ts +6 -6
- package/dist/cli/add/tryToInstallPlugins.d.ts +1 -1
- package/dist/cli/add/tryToInstallPlugins.js +6 -5
- package/dist/cli/add/updateStudioCMSConfig.d.ts +1 -1
- package/dist/cli/add/updateStudioCMSConfig.js +3 -4
- package/dist/cli/add/validatePlugins.d.ts +1 -2
- package/dist/cli/add/validatePlugins.js +15 -9
- package/dist/cli/crypto/genJWT/index.d.ts +1 -1
- package/dist/cli/crypto/genJWT/index.js +8 -9
- package/dist/cli/crypto/index.d.ts +1 -1
- package/dist/cli/init/steps/env.js +14 -4
- package/dist/cli/init/steps/next.d.ts +1 -1
- package/dist/cli/init/steps/next.js +6 -5
- package/dist/cli/migrator/index.d.ts +1 -1
- package/dist/cli/migrator/index.js +2 -2
- package/dist/cli/users/index.d.ts +1 -1
- package/dist/cli/users/shared.js +2 -2
- package/dist/cli/users/steps/createUsers.js +7 -7
- package/dist/cli/users/steps/modifyUsers.js +2 -2
- package/dist/cli/users/steps/next.d.ts +1 -1
- package/dist/cli/utils/checkRequiredEnvVars.js +2 -2
- package/dist/cli/utils/context.d.ts +2 -4
- package/dist/cli/utils/context.js +1 -3
- package/dist/cli/utils/getCliDbClient.d.ts +1 -1
- package/dist/cli/utils/intro.d.ts +1 -1
- package/dist/cli/utils/loadConfig.d.ts +54 -49
- package/dist/cli/utils/loadConfig.js +5 -8
- package/dist/cli/utils/logger.js +3 -3
- package/dist/cli/utils/user-utils.d.ts +1 -1
- package/dist/cli/utils/user-utils.js +4 -3
- package/dist/client/apiClient.d.ts +4923 -0
- package/dist/client/apiClient.js +72 -0
- package/dist/config.d.ts +1734 -1
- package/dist/consts.d.ts +5 -5
- package/dist/consts.js +3 -2
- package/dist/db/plugins.d.ts +1 -1
- package/dist/db/plugins.js +5 -8
- package/dist/handlers/frontend/routes.d.ts +4 -18
- package/dist/handlers/frontend/routes.js +13 -152
- package/dist/handlers/frontend/types.d.ts +1 -1
- package/dist/handlers/frontend/utils.js +0 -18
- package/dist/handlers/pluginHandler.d.ts +34 -257
- package/dist/handlers/pluginHandler.js +92 -46
- package/dist/handlers/routeHandler.js +32 -11
- package/dist/handlers/setupDbStudio.d.ts +3 -1
- package/dist/handlers/setupDbStudio.js +19 -10
- package/dist/handlers/storage-manager/core/effectify-astro-context.d.ts +25 -0
- package/dist/handlers/storage-manager/core/effectify-astro-context.js +78 -0
- package/dist/handlers/storage-manager/no-op.d.ts +2 -2
- package/dist/handlers/storage-manager/no-op.js +2 -3
- package/dist/index.d.ts +0 -1
- package/dist/index.js +10 -20
- package/dist/integrations/robots/index.d.ts +2 -2
- package/dist/integrations/robots/index.js +1 -3
- package/dist/integrations/robots/schema.d.ts +102 -273
- package/dist/integrations/robots/schema.js +220 -209
- package/dist/plugins/analytics/assets/schemas.d.ts +14 -9
- package/dist/plugins/analytics/assets/schemas.js +25 -17
- package/dist/plugins/analytics/db-client.d.ts +1 -1
- package/dist/plugins/analytics/index.d.ts +823 -3
- package/dist/plugins/analytics/index.js +4 -5
- package/dist/plugins/analytics/schemas.d.ts +54 -62
- package/dist/plugins/analytics/schemas.js +64 -13
- package/dist/plugins/analytics/table.d.ts +1 -1
- package/dist/plugins.d.ts +0 -1
- package/dist/schemas/config/api.d.ts +17 -0
- package/dist/schemas/config/api.js +14 -0
- package/dist/schemas/config/auth.d.ts +55 -59
- package/dist/schemas/config/auth.js +34 -11
- package/dist/schemas/config/dashboard.d.ts +43 -79
- package/dist/schemas/config/dashboard.js +43 -12
- package/dist/schemas/config/db.d.ts +15 -17
- package/dist/schemas/config/db.js +13 -5
- package/dist/schemas/config/developer.d.ts +33 -45
- package/dist/schemas/config/developer.js +22 -5
- package/dist/schemas/config/index.d.ts +398 -521
- package/dist/schemas/config/index.js +115 -57
- package/dist/schemas/config/sdk.d.ts +50 -196
- package/dist/schemas/config/sdk.js +61 -73
- package/dist/schemas/custom.d.ts +40 -0
- package/dist/schemas/custom.js +41 -0
- package/dist/schemas/external-schemas.d.ts +171 -0
- package/dist/schemas/external-schemas.js +179 -0
- package/dist/schemas/index.d.ts +2 -0
- package/dist/schemas/index.js +2 -0
- package/dist/schemas/plugins/i18n.d.ts +59 -39
- package/dist/schemas/plugins/i18n.js +42 -5
- package/dist/schemas/plugins/index.d.ts +7126 -10296
- package/dist/schemas/plugins/index.js +260 -276
- package/dist/schemas/plugins/shared.d.ts +1293 -3718
- package/dist/schemas/plugins/shared.js +320 -329
- package/dist/test-utils.d.ts +15 -4
- package/dist/test-utils.js +27 -11
- package/dist/toolbar/db-viewer/db-shared-types.d.ts +6 -6
- package/dist/toolbar/db-viewer/studio/connection.d.ts +8 -4
- package/dist/toolbar/db-viewer/studio/connection.js +2 -28
- package/dist/toolbar/db-viewer/studio/env/libsql.d.ts +7 -0
- package/dist/toolbar/db-viewer/studio/env/libsql.js +17 -0
- package/dist/toolbar/db-viewer/studio/env/mysql.d.ts +7 -0
- package/dist/toolbar/db-viewer/studio/env/mysql.js +23 -0
- package/dist/toolbar/db-viewer/studio/env/postgres.d.ts +7 -0
- package/dist/toolbar/db-viewer/studio/env/postgres.js +23 -0
- package/dist/toolbar/db-viewer/studio/index.js +20 -56
- package/dist/toolbar/db-viewer/studio/type.d.ts +1 -2
- package/dist/toolbar/db-viewer/studio/virtual-connection/libsql.d.ts +3 -0
- package/dist/toolbar/db-viewer/studio/virtual-connection/libsql.js +24 -0
- package/dist/toolbar/db-viewer/studio/virtual-connection/mysql.d.ts +3 -0
- package/dist/toolbar/db-viewer/studio/virtual-connection/mysql.js +9 -0
- package/dist/toolbar/db-viewer/studio/virtual-connection/postgres.d.ts +3 -0
- package/dist/toolbar/db-viewer/studio/virtual-connection/postgres.js +9 -0
- package/dist/toolbar/db-viewer/viewer.js +20 -21
- package/dist/types.d.ts +30 -0
- package/dist/utils/effects/smtp.d.ts +1 -1
- package/dist/utils/lang-helper.d.ts +10 -2
- package/dist/virtual.d.ts +35 -28
- package/dist/virtuals/auth/core.d.ts +5 -5
- package/dist/virtuals/auth/verify-email.d.ts +6 -6
- package/dist/virtuals/components/Generator.astro +2 -2
- package/dist/virtuals/components/Renderer.astro +9 -1
- package/dist/virtuals/components/renderFn.d.ts +3 -1
- package/dist/virtuals/components/renderFn.js +18 -0
- package/dist/virtuals/lib/headDefaults.d.ts +4 -2
- package/dist/virtuals/lib/headDefaults.js +0 -2
- package/dist/virtuals/lib/routeMap.d.ts +0 -12
- package/dist/virtuals/lib/routeMap.js +2 -14
- package/dist/virtuals/mailer/index.d.ts +3 -3
- package/dist/virtuals/notifier/index.d.ts +5 -5
- package/dist/virtuals/plugins/dashboard-pages.d.ts +2 -64
- package/dist/virtuals/scripts/StorageFileBrowser.d.ts +1 -172
- package/dist/virtuals/scripts/StorageFileBrowser.js +216 -119
- package/dist/virtuals/template-engine/index.d.ts +4 -4
- package/frontend/components/dashboard/configuration/ConfigForm.astro +218 -110
- package/frontend/components/dashboard/content-mgmt/ContentSearch.astro +21 -22
- package/frontend/components/dashboard/content-mgmt/CreateFolder.astro +66 -54
- package/frontend/components/dashboard/content-mgmt/CreatePage.astro +58 -104
- package/frontend/components/dashboard/content-mgmt/EditFolder.astro +65 -67
- package/frontend/components/dashboard/content-mgmt/EditPage.astro +86 -134
- package/frontend/components/dashboard/content-mgmt/InnerSidebarElement.astro +0 -1
- package/frontend/components/dashboard/content-mgmt/PageHeader.astro +33 -52
- package/frontend/components/dashboard/content-mgmt/PageTypeHandler.astro +2 -2
- package/frontend/components/dashboard/profile/APITokens.astro +219 -158
- package/frontend/components/dashboard/profile/BasicInfo.astro +165 -106
- package/frontend/components/dashboard/profile/Notifications.astro +27 -18
- package/frontend/components/dashboard/profile/UpdatePassword.astro +134 -94
- package/frontend/components/dashboard/sidebar/VersionCheck.astro +31 -16
- package/frontend/components/dashboard/sidebar/VersionCheckChangelog.astro +18 -11
- package/frontend/components/dashboard/sidebar-modals/VersionModal.astro +2 -2
- package/frontend/components/dashboard/smtp-config/TemplateEditor.astro +14 -14
- package/frontend/components/dashboard/taxonomy/InnerSidebarElement.astro +0 -1
- package/frontend/components/dashboard/taxonomy/MetaContainer.astro +0 -2
- package/frontend/components/dashboard/taxonomy/PageHeader.astro +16 -24
- package/frontend/components/dashboard/taxonomy/TaxonomySearch.astro +23 -27
- package/frontend/components/dashboard/user-mgmt/InnerSidebarElement.astro +111 -104
- package/frontend/components/dashboard/user-mgmt/UserListItem.astro +9 -22
- package/frontend/components/dashboard/user-mgmt/UserListItems.astro +18 -0
- package/frontend/components/first-time-setup/snippets/{opt2-studiocms.config.diff → studiocms.config.diff} +1 -0
- package/frontend/components/shared/Code.astro +1 -4
- package/frontend/components/shared/DynamicSettingsRenderer.astro +1 -1
- package/frontend/components/shared/SSRUser.astro +2 -4
- package/frontend/components/shared/foldertree/FolderTreeNode.astro +0 -6
- package/frontend/components/shared/storage-manager/StorageCopyOutput.astro +0 -1
- package/frontend/components/shared/taxonomy/TaxonomyTreeNode.astro +0 -6
- package/frontend/layouts/DashboardLayout.astro +1 -10
- package/frontend/layouts/TaxonomyLayout.astro +0 -1
- package/frontend/middleware/index.ts +102 -61
- package/frontend/pages/404.astro +5 -9
- package/frontend/pages/[dashboard]/[...pluginPage].astro +10 -1
- package/frontend/pages/[dashboard]/configuration.astro +10 -1
- package/frontend/pages/[dashboard]/content-management/createfolder.astro +10 -1
- package/frontend/pages/[dashboard]/content-management/createpage.astro +10 -1
- package/frontend/pages/[dashboard]/content-management/diff.astro +39 -14
- package/frontend/pages/[dashboard]/content-management/editfolder.astro +10 -1
- package/frontend/pages/[dashboard]/content-management/editpage.astro +10 -1
- package/frontend/pages/[dashboard]/content-management/index.astro +10 -1
- package/frontend/pages/[dashboard]/index.astro +10 -1
- package/frontend/pages/[dashboard]/login.astro +86 -25
- package/frontend/pages/[dashboard]/password-reset.astro +22 -16
- package/frontend/pages/[dashboard]/plugins/[plugin].astro +10 -1
- package/frontend/pages/[dashboard]/profile.astro +10 -1
- package/frontend/pages/[dashboard]/signup.astro +153 -52
- package/frontend/pages/[dashboard]/smtp-configuration.astro +77 -75
- package/frontend/pages/[dashboard]/system-management.astro +10 -1
- package/frontend/pages/[dashboard]/taxonomy/categories.astro +30 -41
- package/frontend/pages/[dashboard]/taxonomy/index.astro +10 -0
- package/frontend/pages/[dashboard]/taxonomy/tags.astro +33 -43
- package/frontend/pages/[dashboard]/unverified-email.astro +29 -21
- package/frontend/pages/[dashboard]/user-management/edit.astro +170 -90
- package/frontend/pages/[dashboard]/user-management/index.astro +10 -1
- package/frontend/pages/studiocms_api/[...all].ts +106 -0
- package/frontend/pages/studiocms_api/_handlers/_utils/auth.ts +26 -0
- package/frontend/pages/studiocms_api/_handlers/_utils/changelog.ts +147 -0
- package/frontend/pages/studiocms_api/_handlers/_utils/db-studio-driver.ts +46 -0
- package/frontend/pages/studiocms_api/_handlers/_utils/parseLogLevel.ts +27 -0
- package/frontend/pages/studiocms_api/_handlers/auth/auth.ts +459 -0
- package/frontend/pages/studiocms_api/_handlers/auth/index.ts +17 -0
- package/frontend/pages/studiocms_api/_handlers/auth/oauth.ts +91 -0
- package/frontend/pages/studiocms_api/_handlers/dashboard/_shared.ts +57 -0
- package/frontend/pages/studiocms_api/_handlers/dashboard/apiTokens.ts +134 -0
- package/frontend/pages/studiocms_api/_handlers/dashboard/config.ts +64 -0
- package/frontend/pages/studiocms_api/_handlers/dashboard/content.ts +741 -0
- package/frontend/pages/studiocms_api/_handlers/dashboard/create.ts +480 -0
- package/frontend/pages/studiocms_api/_handlers/dashboard/emailNotifications.ts +49 -0
- package/frontend/pages/studiocms_api/_handlers/dashboard/index.ts +45 -0
- package/frontend/pages/studiocms_api/_handlers/dashboard/mailer.ts +136 -0
- package/frontend/pages/studiocms_api/_handlers/dashboard/plugins.ts +80 -0
- package/frontend/pages/studiocms_api/_handlers/dashboard/profile.ts +275 -0
- package/frontend/pages/studiocms_api/_handlers/dashboard/resetPassword.ts +140 -0
- package/frontend/pages/studiocms_api/_handlers/dashboard/search.ts +63 -0
- package/frontend/pages/studiocms_api/_handlers/dashboard/taxonomy.ts +285 -0
- package/frontend/pages/studiocms_api/_handlers/dashboard/templates.ts +75 -0
- package/frontend/pages/studiocms_api/_handlers/dashboard/users.ts +312 -0
- package/frontend/pages/studiocms_api/_handlers/dashboard/verifyEndpoints.ts +307 -0
- package/frontend/pages/studiocms_api/_handlers/integration/dbStudio.ts +98 -0
- package/frontend/pages/studiocms_api/_handlers/integration/index.ts +17 -0
- package/frontend/pages/studiocms_api/_handlers/integration/storageManager.ts +107 -0
- package/frontend/pages/studiocms_api/_handlers/rest-api/index.ts +8 -0
- package/frontend/pages/studiocms_api/_handlers/rest-api/v1/_shared.ts +41 -0
- package/frontend/pages/studiocms_api/_handlers/rest-api/v1/index.ts +17 -0
- package/frontend/pages/studiocms_api/_handlers/rest-api/v1/public.ts +195 -0
- package/frontend/pages/studiocms_api/_handlers/rest-api/v1/secure.ts +1726 -0
- package/frontend/pages/studiocms_api/_handlers/sdk.ts +129 -0
- package/frontend/pages/studiocms_api/_middleware/astroLocals.ts +36 -0
- package/frontend/pages/studiocms_api/_middleware/restApi.ts +56 -0
- package/frontend/pages/studiocms_api/integrations/[...all].ts +8 -0
- package/frontend/scripts/formdata.ts +219 -0
- package/frontend/setup-pages/3-done.astro +4 -20
- package/frontend/setup-pages/studiocms_api/dashboard/step-2.ts +3 -6
- package/frontend/styles/dashboard-base.css +0 -1
- package/frontend/web-vitals/endpoint.ts +2 -1
- package/package.json +35 -31
- package/dist/global.d.ts +0 -9
- package/frontend/components/dashboard/LoginChecker.astro +0 -68
- package/frontend/components/dashboard/user-mgmt/RankCheck.astro +0 -57
- package/frontend/components/first-time-setup/snippets/opt1-astro.config.diff +0 -14
- package/frontend/components/first-time-setup/snippets/opt2-astro.config.diff +0 -9
- package/frontend/middleware/_authmap.ts +0 -63
- package/frontend/pages/studiocms_api/auth/[path].ts +0 -390
- package/frontend/pages/studiocms_api/auth/[provider]/[...id].ts +0 -64
- package/frontend/pages/studiocms_api/auth/[provider]/_effects/index.ts +0 -101
- package/frontend/pages/studiocms_api/auth/_shared.ts +0 -52
- package/frontend/pages/studiocms_api/dashboard/api-tokens.ts +0 -115
- package/frontend/pages/studiocms_api/dashboard/config.ts +0 -74
- package/frontend/pages/studiocms_api/dashboard/content/diff.ts +0 -73
- package/frontend/pages/studiocms_api/dashboard/content/folder.ts +0 -220
- package/frontend/pages/studiocms_api/dashboard/content/page.ts +0 -359
- package/frontend/pages/studiocms_api/dashboard/create-reset-link.ts +0 -77
- package/frontend/pages/studiocms_api/dashboard/create-user-invite.ts +0 -231
- package/frontend/pages/studiocms_api/dashboard/create-user.ts +0 -186
- package/frontend/pages/studiocms_api/dashboard/email-notification-settings-site.ts +0 -74
- package/frontend/pages/studiocms_api/dashboard/mailer/check-email.ts +0 -75
- package/frontend/pages/studiocms_api/dashboard/mailer/config.ts +0 -136
- package/frontend/pages/studiocms_api/dashboard/plugins/[plugin].ts +0 -80
- package/frontend/pages/studiocms_api/dashboard/profile.ts +0 -245
- package/frontend/pages/studiocms_api/dashboard/resend-verify-email.ts +0 -77
- package/frontend/pages/studiocms_api/dashboard/reset-password.ts +0 -124
- package/frontend/pages/studiocms_api/dashboard/search-list.ts +0 -59
- package/frontend/pages/studiocms_api/dashboard/taxonomy-search.ts +0 -47
- package/frontend/pages/studiocms_api/dashboard/taxonomy.ts +0 -230
- package/frontend/pages/studiocms_api/dashboard/templates.ts +0 -74
- package/frontend/pages/studiocms_api/dashboard/update-user-notifications.ts +0 -86
- package/frontend/pages/studiocms_api/dashboard/users.ts +0 -236
- package/frontend/pages/studiocms_api/dashboard/verify-email.ts +0 -83
- package/frontend/pages/studiocms_api/dashboard/verify-session.ts +0 -187
- package/frontend/pages/studiocms_api/integrations/[type]/[...id].ts +0 -15
- package/frontend/pages/studiocms_api/integrations/[type]/_routes/db-studio.ts +0 -173
- package/frontend/pages/studiocms_api/integrations/[type]/_routes/storage.ts +0 -88
- package/frontend/pages/studiocms_api/partials/editor.astro +0 -74
- package/frontend/pages/studiocms_api/partials/render.astro +0 -39
- package/frontend/pages/studiocms_api/partials/user-list-items.astro +0 -43
- package/frontend/pages/studiocms_api/rest/utils/auth-token.ts +0 -59
- package/frontend/pages/studiocms_api/rest/v1/[type]/[...id].ts +0 -23
- package/frontend/pages/studiocms_api/rest/v1/[type]/_routes/categories.ts +0 -267
- package/frontend/pages/studiocms_api/rest/v1/[type]/_routes/folders.ts +0 -283
- package/frontend/pages/studiocms_api/rest/v1/[type]/_routes/pages.ts +0 -505
- package/frontend/pages/studiocms_api/rest/v1/[type]/_routes/settings.ts +0 -100
- package/frontend/pages/studiocms_api/rest/v1/[type]/_routes/tags.ts +0 -229
- package/frontend/pages/studiocms_api/rest/v1/[type]/_routes/users.ts +0 -553
- package/frontend/pages/studiocms_api/rest/v1/public/[type]/[...id].ts +0 -19
- package/frontend/pages/studiocms_api/rest/v1/public/[type]/_routes/categories.ts +0 -74
- package/frontend/pages/studiocms_api/rest/v1/public/[type]/_routes/folders.ts +0 -85
- package/frontend/pages/studiocms_api/rest/v1/public/[type]/_routes/pages.ts +0 -103
- package/frontend/pages/studiocms_api/rest/v1/public/[type]/_routes/tags.ts +0 -67
- package/frontend/pages/studiocms_api/sdk/[...path].ts +0 -97
- package/frontend/pages/studiocms_api/sdk/utils/changelog.ts +0 -119
- package/frontend/scripts/auth/formListener.ts +0 -81
- package/frontend/scripts/formdata-utils.ts +0 -116
- package/frontend/utils/build-partial-schema.ts +0 -46
- package/frontend/utils/errors.ts +0 -6
- package/frontend/utils/param-extractor.ts +0 -83
- package/frontend/utils/rest-router.ts +0 -444
|
@@ -1,359 +0,0 @@
|
|
|
1
|
-
import { apiResponseLogger } from 'studiocms:logger';
|
|
2
|
-
import { Notifications } from 'studiocms:notifier';
|
|
3
|
-
import plugins from 'studiocms:plugins';
|
|
4
|
-
import { apiEndpoints } from 'studiocms:plugins/endpoints';
|
|
5
|
-
import { SDKCore } from 'studiocms:sdk';
|
|
6
|
-
import type {
|
|
7
|
-
CombinedInsertContent,
|
|
8
|
-
tsPageContentSelect,
|
|
9
|
-
tsPageData,
|
|
10
|
-
tsPageDataSelect,
|
|
11
|
-
} from 'studiocms:sdk/types';
|
|
12
|
-
import {
|
|
13
|
-
AllResponse,
|
|
14
|
-
createEffectAPIRoutes,
|
|
15
|
-
createJsonResponse,
|
|
16
|
-
Effect,
|
|
17
|
-
genLogger,
|
|
18
|
-
OptionsResponse,
|
|
19
|
-
readAPIContextJson,
|
|
20
|
-
Schema,
|
|
21
|
-
} from '@withstudiocms/effect';
|
|
22
|
-
import { StudioCMSPageData } from '@withstudiocms/sdk/tables';
|
|
23
|
-
import type { PluginAPIRoute } from '#plugins';
|
|
24
|
-
|
|
25
|
-
type ApiEndpoints = {
|
|
26
|
-
onCreate?: PluginAPIRoute<'onCreate'> | null;
|
|
27
|
-
onEdit?: PluginAPIRoute<'onEdit'> | null;
|
|
28
|
-
onDelete?: PluginAPIRoute<'onDelete'> | null;
|
|
29
|
-
};
|
|
30
|
-
|
|
31
|
-
type PageTypeOutput = {
|
|
32
|
-
identifier: string;
|
|
33
|
-
label: string;
|
|
34
|
-
description?: string | undefined;
|
|
35
|
-
pageContentComponent?: string | undefined;
|
|
36
|
-
apiEndpoint?: string;
|
|
37
|
-
apiEndpoints?: ApiEndpoints | undefined;
|
|
38
|
-
};
|
|
39
|
-
|
|
40
|
-
type UpdatePageData = Partial<tsPageDataSelect>;
|
|
41
|
-
type UpdatePageContent = Partial<tsPageContentSelect>;
|
|
42
|
-
|
|
43
|
-
const pageTypeOptions = plugins.flatMap(({ pageTypes }) => {
|
|
44
|
-
const pageTypeOutput: PageTypeOutput[] = [];
|
|
45
|
-
|
|
46
|
-
if (!pageTypes) return pageTypeOutput;
|
|
47
|
-
|
|
48
|
-
for (const pageType of pageTypes) {
|
|
49
|
-
pageTypeOutput.push({
|
|
50
|
-
...pageType,
|
|
51
|
-
apiEndpoints: apiEndpoints.find((endpoint) => endpoint.identifier === pageType.identifier),
|
|
52
|
-
});
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
return pageTypeOutput;
|
|
56
|
-
});
|
|
57
|
-
|
|
58
|
-
function getPageTypeEndpoints<T extends 'onCreate' | 'onEdit' | 'onDelete'>(pkg: string, type: T) {
|
|
59
|
-
const currentPageType = pageTypeOptions.find((pageType) => pageType.identifier === pkg);
|
|
60
|
-
|
|
61
|
-
if (!currentPageType) return undefined;
|
|
62
|
-
|
|
63
|
-
return currentPageType.apiEndpoints?.[type];
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
export const { POST, PATCH, DELETE, OPTIONS, ALL } = createEffectAPIRoutes(
|
|
67
|
-
{
|
|
68
|
-
POST: (ctx) =>
|
|
69
|
-
genLogger('studiocms/routes/api/dashboard/content/page.POST')(function* () {
|
|
70
|
-
const [sdk, notify] = yield* Effect.all([SDKCore, Notifications]);
|
|
71
|
-
|
|
72
|
-
// Get user data
|
|
73
|
-
const userData = ctx.locals.StudioCMS.security?.userSessionData;
|
|
74
|
-
|
|
75
|
-
// Check if user is logged in
|
|
76
|
-
if (!userData?.isLoggedIn) {
|
|
77
|
-
return apiResponseLogger(403, 'Unauthorized');
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
// Check if user has permission
|
|
81
|
-
const isAuthorized = ctx.locals.StudioCMS.security?.userPermissionLevel.isEditor;
|
|
82
|
-
if (!isAuthorized) {
|
|
83
|
-
return apiResponseLogger(403, 'Unauthorized');
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
const data = yield* readAPIContextJson<UpdatePageData>(ctx);
|
|
87
|
-
|
|
88
|
-
const content = {
|
|
89
|
-
id: crypto.randomUUID(),
|
|
90
|
-
// content is no longer supported during page creation due to current editor setup
|
|
91
|
-
// look into options in the future for how we can do this correctly.
|
|
92
|
-
// Requires being able to swap in editors which currently does not work.
|
|
93
|
-
content: '',
|
|
94
|
-
} as UpdatePageContent;
|
|
95
|
-
|
|
96
|
-
if (!data.title) {
|
|
97
|
-
return apiResponseLogger(400, 'Invalid form data, title is required');
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
const dataId = crypto.randomUUID();
|
|
101
|
-
|
|
102
|
-
// biome-ignore lint/style/noNonNullAssertion: this is a valid use case for non-null assertion
|
|
103
|
-
const apiRoute = getPageTypeEndpoints(data.package!, 'onCreate');
|
|
104
|
-
|
|
105
|
-
const pageContent: CombinedInsertContent = {
|
|
106
|
-
contentLang: 'default',
|
|
107
|
-
content: content.content || '',
|
|
108
|
-
};
|
|
109
|
-
|
|
110
|
-
const {
|
|
111
|
-
title,
|
|
112
|
-
slug,
|
|
113
|
-
description,
|
|
114
|
-
categories,
|
|
115
|
-
tags,
|
|
116
|
-
augments,
|
|
117
|
-
contributorIds,
|
|
118
|
-
updatedAt: ___updatedAt,
|
|
119
|
-
...rest
|
|
120
|
-
} = data as unknown as tsPageData['Insert']['Type'];
|
|
121
|
-
|
|
122
|
-
yield* Effect.logInfo('11111');
|
|
123
|
-
|
|
124
|
-
const newData = yield* sdk.POST.page({
|
|
125
|
-
pageData: {
|
|
126
|
-
...rest,
|
|
127
|
-
id: dataId,
|
|
128
|
-
title: title,
|
|
129
|
-
slug: slug || title.toLowerCase().replace(/\s/g, '-'),
|
|
130
|
-
description: description || '',
|
|
131
|
-
authorId: userData.user?.id || '',
|
|
132
|
-
updatedAt: new Date().toISOString(),
|
|
133
|
-
publishedAt: new Date().toISOString(),
|
|
134
|
-
categories: JSON.stringify(categories || []),
|
|
135
|
-
tags: JSON.stringify(tags || []),
|
|
136
|
-
augments: JSON.stringify(augments || []),
|
|
137
|
-
contributorIds: JSON.stringify(contributorIds || []),
|
|
138
|
-
contentLang: 'default',
|
|
139
|
-
},
|
|
140
|
-
pageContent: pageContent,
|
|
141
|
-
});
|
|
142
|
-
yield* Effect.logInfo('22222');
|
|
143
|
-
|
|
144
|
-
if (!newData) {
|
|
145
|
-
return apiResponseLogger(500, 'Failed to create page');
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
if (apiRoute) {
|
|
149
|
-
yield* Effect.tryPromise(() => apiRoute({ AstroCtx: ctx, pageData: newData }));
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
yield* Effect.all([sdk.CLEAR.pages, notify.sendEditorNotification('new_page', data.title)]);
|
|
153
|
-
|
|
154
|
-
return apiResponseLogger(200, 'Page created successfully');
|
|
155
|
-
}).pipe(Notifications.Provide),
|
|
156
|
-
PATCH: (ctx) =>
|
|
157
|
-
genLogger('studiocms/routes/api/dashboard/content/page.PATCH')(function* () {
|
|
158
|
-
const [sdk, notify] = yield* Effect.all([SDKCore, Notifications]);
|
|
159
|
-
|
|
160
|
-
// Get user data
|
|
161
|
-
const userData = ctx.locals.StudioCMS.security?.userSessionData;
|
|
162
|
-
|
|
163
|
-
// Check if user is logged in
|
|
164
|
-
if (!userData?.isLoggedIn) {
|
|
165
|
-
return apiResponseLogger(403, 'Unauthorized');
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
// Check if user has permission
|
|
169
|
-
const isAuthorized = ctx.locals.StudioCMS.security?.userPermissionLevel.isEditor;
|
|
170
|
-
if (!isAuthorized) {
|
|
171
|
-
return apiResponseLogger(403, 'Unauthorized');
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
const combinedData = yield* readAPIContextJson<
|
|
175
|
-
UpdatePageData & {
|
|
176
|
-
contentId: string;
|
|
177
|
-
content: string;
|
|
178
|
-
pluginFields: Record<string, FormDataEntryValue | null>;
|
|
179
|
-
augments?: string[];
|
|
180
|
-
}
|
|
181
|
-
>(ctx);
|
|
182
|
-
|
|
183
|
-
const { contentId, content: incomingContent, pluginFields, ...data } = combinedData;
|
|
184
|
-
|
|
185
|
-
if (!data.id) {
|
|
186
|
-
return apiResponseLogger(400, 'Invalid form data, id is required');
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
if (!contentId) {
|
|
190
|
-
return apiResponseLogger(400, 'Invalid form data, contentId is required');
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
const content = {
|
|
194
|
-
id: contentId,
|
|
195
|
-
contentId: data.id,
|
|
196
|
-
content: incomingContent,
|
|
197
|
-
contentLang: 'default',
|
|
198
|
-
};
|
|
199
|
-
|
|
200
|
-
const currentPageData = yield* sdk.GET.page.byId(data.id);
|
|
201
|
-
|
|
202
|
-
if (!currentPageData) {
|
|
203
|
-
return apiResponseLogger(404, 'Page not found');
|
|
204
|
-
}
|
|
205
|
-
|
|
206
|
-
const { authorId, contributorIds, defaultContent } = currentPageData;
|
|
207
|
-
|
|
208
|
-
let AuthorId = authorId;
|
|
209
|
-
|
|
210
|
-
if (!authorId) {
|
|
211
|
-
// biome-ignore lint/style/noNonNullAssertion: this is a valid use case for non-null assertion
|
|
212
|
-
AuthorId = userData.user!.id;
|
|
213
|
-
}
|
|
214
|
-
|
|
215
|
-
const ContributorIds = contributorIds || [];
|
|
216
|
-
|
|
217
|
-
// biome-ignore lint/style/noNonNullAssertion: this is a valid use case for non-null assertion
|
|
218
|
-
if (!ContributorIds.includes(userData.user!.id)) {
|
|
219
|
-
// biome-ignore lint/style/noNonNullAssertion: this is a valid use case for non-null assertion
|
|
220
|
-
ContributorIds.push(userData.user!.id);
|
|
221
|
-
}
|
|
222
|
-
|
|
223
|
-
const newData: tsPageData['Update']['Type'] = {
|
|
224
|
-
...(data as tsPageDataSelect),
|
|
225
|
-
authorId: AuthorId,
|
|
226
|
-
contributorIds: JSON.stringify(ContributorIds),
|
|
227
|
-
updatedAt: new Date().toISOString(),
|
|
228
|
-
publishedAt:
|
|
229
|
-
currentPageData.draft && data.draft === false
|
|
230
|
-
? new Date().toISOString()
|
|
231
|
-
: currentPageData.publishedAt?.toISOString() || new Date().toISOString(),
|
|
232
|
-
categories: JSON.stringify(data.categories || []),
|
|
233
|
-
tags: JSON.stringify(data.tags || []),
|
|
234
|
-
augments: JSON.stringify(data.augments || []),
|
|
235
|
-
contentLang: 'default',
|
|
236
|
-
};
|
|
237
|
-
|
|
238
|
-
const getMetaData = sdk.dbService.withCodec({
|
|
239
|
-
encoder: Schema.String,
|
|
240
|
-
decoder: StudioCMSPageData.Select,
|
|
241
|
-
callbackFn: (query, input) =>
|
|
242
|
-
query((db) =>
|
|
243
|
-
db
|
|
244
|
-
.selectFrom('StudioCMSPageData')
|
|
245
|
-
.selectAll()
|
|
246
|
-
.where('id', '=', input)
|
|
247
|
-
.executeTakeFirstOrThrow()
|
|
248
|
-
),
|
|
249
|
-
});
|
|
250
|
-
|
|
251
|
-
const startMetaData = yield* getMetaData(data.id);
|
|
252
|
-
|
|
253
|
-
// biome-ignore lint/style/noNonNullAssertion: this is a valid use case for non-null assertion
|
|
254
|
-
const apiRoute = getPageTypeEndpoints(data.package!, 'onEdit');
|
|
255
|
-
|
|
256
|
-
const updatedPage = yield* sdk.UPDATE.page.byId(data.id, {
|
|
257
|
-
pageData: newData,
|
|
258
|
-
pageContent: content,
|
|
259
|
-
});
|
|
260
|
-
|
|
261
|
-
if (!updatedPage) {
|
|
262
|
-
return apiResponseLogger(500, 'Failed to update page');
|
|
263
|
-
}
|
|
264
|
-
|
|
265
|
-
const updatedMetaData = yield* getMetaData(data.id);
|
|
266
|
-
|
|
267
|
-
const { enableDiffs, diffPerPage = 10 } = ctx.locals.StudioCMS.siteConfig.data;
|
|
268
|
-
|
|
269
|
-
if (enableDiffs) {
|
|
270
|
-
yield* sdk.diffTracking.insert(
|
|
271
|
-
// biome-ignore lint/style/noNonNullAssertion: this is a valid use case for non-null assertion
|
|
272
|
-
userData.user!.id,
|
|
273
|
-
data.id,
|
|
274
|
-
{
|
|
275
|
-
content: {
|
|
276
|
-
start: defaultContent?.content || '',
|
|
277
|
-
end: content.content || '',
|
|
278
|
-
},
|
|
279
|
-
// biome-ignore lint/style/noNonNullAssertion: this is a valid use case for non-null assertion
|
|
280
|
-
metaData: { start: startMetaData!, end: updatedMetaData! },
|
|
281
|
-
},
|
|
282
|
-
diffPerPage
|
|
283
|
-
);
|
|
284
|
-
}
|
|
285
|
-
|
|
286
|
-
if (apiRoute) {
|
|
287
|
-
yield* Effect.tryPromise(() =>
|
|
288
|
-
apiRoute({ AstroCtx: ctx, pageData: updatedPage, pluginFields })
|
|
289
|
-
);
|
|
290
|
-
}
|
|
291
|
-
|
|
292
|
-
yield* Effect.all([
|
|
293
|
-
sdk.CLEAR.pages,
|
|
294
|
-
notify.sendEditorNotification('page_updated', data.title || startMetaData?.title || ''),
|
|
295
|
-
]);
|
|
296
|
-
|
|
297
|
-
return apiResponseLogger(200, 'Page updated successfully');
|
|
298
|
-
}).pipe(Notifications.Provide),
|
|
299
|
-
DELETE: (ctx) =>
|
|
300
|
-
genLogger('studiocms/routes/api/dashboard/content/page.DELETE')(function* () {
|
|
301
|
-
const [sdk, notify] = yield* Effect.all([SDKCore, Notifications]);
|
|
302
|
-
|
|
303
|
-
// Get user data
|
|
304
|
-
const userData = ctx.locals.StudioCMS.security?.userSessionData;
|
|
305
|
-
|
|
306
|
-
// Check if user is logged in
|
|
307
|
-
if (!userData?.isLoggedIn) {
|
|
308
|
-
return apiResponseLogger(403, 'Unauthorized');
|
|
309
|
-
}
|
|
310
|
-
|
|
311
|
-
// Check if user has permission
|
|
312
|
-
const isAuthorized = ctx.locals.StudioCMS.security?.userPermissionLevel.isAdmin;
|
|
313
|
-
if (!isAuthorized) {
|
|
314
|
-
return apiResponseLogger(403, 'Unauthorized');
|
|
315
|
-
}
|
|
316
|
-
|
|
317
|
-
const { id, slug } = yield* readAPIContextJson<{ id: string; slug?: string }>(ctx);
|
|
318
|
-
|
|
319
|
-
const pageToDelete = yield* sdk.GET.page.byId(id);
|
|
320
|
-
|
|
321
|
-
if (!pageToDelete) {
|
|
322
|
-
return apiResponseLogger(404, 'Page not found');
|
|
323
|
-
}
|
|
324
|
-
if (pageToDelete.slug !== slug) {
|
|
325
|
-
return apiResponseLogger(400, 'Invalid request');
|
|
326
|
-
}
|
|
327
|
-
|
|
328
|
-
const apiRoute = getPageTypeEndpoints(pageToDelete.package, 'onDelete');
|
|
329
|
-
|
|
330
|
-
yield* sdk.DELETE.page(id);
|
|
331
|
-
|
|
332
|
-
if (apiRoute) {
|
|
333
|
-
yield* Effect.tryPromise(() => apiRoute({ AstroCtx: ctx, pageData: pageToDelete }));
|
|
334
|
-
}
|
|
335
|
-
|
|
336
|
-
yield* Effect.all([
|
|
337
|
-
sdk.CLEAR.pages,
|
|
338
|
-
notify.sendEditorNotification('page_deleted', pageToDelete.title),
|
|
339
|
-
]);
|
|
340
|
-
|
|
341
|
-
return apiResponseLogger(200, 'Page deleted successfully');
|
|
342
|
-
}).pipe(Notifications.Provide),
|
|
343
|
-
OPTIONS: () =>
|
|
344
|
-
Effect.try(() => OptionsResponse({ allowedMethods: ['POST', 'PATCH', 'DELETE'] })),
|
|
345
|
-
ALL: () => Effect.try(() => AllResponse()),
|
|
346
|
-
},
|
|
347
|
-
{
|
|
348
|
-
cors: { methods: ['POST', 'PATCH', 'DELETE', 'OPTIONS'] },
|
|
349
|
-
onError: (error) => {
|
|
350
|
-
console.error('API Error:', error);
|
|
351
|
-
return createJsonResponse(
|
|
352
|
-
{ error: 'Internal Server Error' },
|
|
353
|
-
{
|
|
354
|
-
status: 500,
|
|
355
|
-
}
|
|
356
|
-
);
|
|
357
|
-
},
|
|
358
|
-
}
|
|
359
|
-
);
|
|
@@ -1,77 +0,0 @@
|
|
|
1
|
-
import { developerConfig } from 'studiocms:config';
|
|
2
|
-
import { apiResponseLogger } from 'studiocms:logger';
|
|
3
|
-
import { Notifications } from 'studiocms:notifier';
|
|
4
|
-
import { SDKCore } from 'studiocms:sdk';
|
|
5
|
-
import {
|
|
6
|
-
AllResponse,
|
|
7
|
-
createEffectAPIRoutes,
|
|
8
|
-
createJsonResponse,
|
|
9
|
-
Effect,
|
|
10
|
-
genLogger,
|
|
11
|
-
OptionsResponse,
|
|
12
|
-
readAPIContextJson,
|
|
13
|
-
} from '@withstudiocms/effect';
|
|
14
|
-
|
|
15
|
-
export const { POST, OPTIONS, ALL } = createEffectAPIRoutes(
|
|
16
|
-
{
|
|
17
|
-
POST: (ctx) =>
|
|
18
|
-
genLogger('studiocms/routes/api/dashboard/create-reset-link.POST')(function* () {
|
|
19
|
-
const [notify, sdk] = yield* Effect.all([Notifications, SDKCore]);
|
|
20
|
-
|
|
21
|
-
// Check if demo mode is enabled
|
|
22
|
-
if (developerConfig.demoMode !== false) {
|
|
23
|
-
return apiResponseLogger(403, 'Demo mode is enabled, this action is not allowed.');
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
// Get user data
|
|
27
|
-
const userData = ctx.locals.StudioCMS.security?.userSessionData;
|
|
28
|
-
|
|
29
|
-
// Check if user is logged in
|
|
30
|
-
if (!userData?.isLoggedIn) {
|
|
31
|
-
return apiResponseLogger(403, 'Unauthorized');
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
// Check if user has permission
|
|
35
|
-
const isAuthorized = ctx.locals.StudioCMS.security?.userPermissionLevel.isAdmin;
|
|
36
|
-
if (!isAuthorized) {
|
|
37
|
-
return apiResponseLogger(403, 'Unauthorized');
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
const { userId } = yield* readAPIContextJson<{ userId: string }>(ctx);
|
|
41
|
-
|
|
42
|
-
if (!userId) {
|
|
43
|
-
return apiResponseLogger(400, 'Invalid form data, userId is required');
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
const token = yield* sdk.resetTokenBucket.new(userId);
|
|
47
|
-
|
|
48
|
-
if (!token) {
|
|
49
|
-
return apiResponseLogger(500, 'Failed to create reset link');
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
const user = yield* sdk.GET.users.byId(userId);
|
|
53
|
-
|
|
54
|
-
if (!user) {
|
|
55
|
-
return apiResponseLogger(404, 'User not found');
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
yield* notify.sendAdminNotification('user_updated', user.username);
|
|
59
|
-
|
|
60
|
-
return createJsonResponse(token);
|
|
61
|
-
}).pipe(Notifications.Provide),
|
|
62
|
-
OPTIONS: () => Effect.try(() => OptionsResponse({ allowedMethods: ['POST'] })),
|
|
63
|
-
ALL: () => Effect.try(() => AllResponse()),
|
|
64
|
-
},
|
|
65
|
-
{
|
|
66
|
-
cors: { methods: ['POST', 'OPTIONS'] },
|
|
67
|
-
onError: (error) => {
|
|
68
|
-
console.error('API Error:', error);
|
|
69
|
-
return createJsonResponse(
|
|
70
|
-
{ error: 'Internal Server Error' },
|
|
71
|
-
{
|
|
72
|
-
status: 500,
|
|
73
|
-
}
|
|
74
|
-
);
|
|
75
|
-
},
|
|
76
|
-
}
|
|
77
|
-
);
|
|
@@ -1,231 +0,0 @@
|
|
|
1
|
-
import { User } from 'studiocms:auth/lib';
|
|
2
|
-
import { apiResponseLogger } from 'studiocms:logger';
|
|
3
|
-
import { Mailer } from 'studiocms:mailer';
|
|
4
|
-
import { Notifications } from 'studiocms:notifier';
|
|
5
|
-
import { SDKCore } from 'studiocms:sdk';
|
|
6
|
-
import templateEngine from 'studiocms:template-engine';
|
|
7
|
-
import type { AvailablePermissionRanks } from '@withstudiocms/auth-kit/types';
|
|
8
|
-
import {
|
|
9
|
-
AllResponse,
|
|
10
|
-
appendSearchParamsToUrl,
|
|
11
|
-
createEffectAPIRoutes,
|
|
12
|
-
createJsonResponse,
|
|
13
|
-
Effect,
|
|
14
|
-
genLogger,
|
|
15
|
-
OptionsResponse,
|
|
16
|
-
pipe,
|
|
17
|
-
readAPIContextJson,
|
|
18
|
-
} from '@withstudiocms/effect';
|
|
19
|
-
import type { APIContext } from 'astro';
|
|
20
|
-
import { z } from 'astro/zod';
|
|
21
|
-
|
|
22
|
-
type JSONData = {
|
|
23
|
-
username: string | undefined;
|
|
24
|
-
email: string | undefined;
|
|
25
|
-
displayname: string | undefined;
|
|
26
|
-
rank: AvailablePermissionRanks | undefined;
|
|
27
|
-
originalUrl: string;
|
|
28
|
-
};
|
|
29
|
-
|
|
30
|
-
type Token = {
|
|
31
|
-
id: string;
|
|
32
|
-
userId: string;
|
|
33
|
-
token: string;
|
|
34
|
-
};
|
|
35
|
-
|
|
36
|
-
const generateResetUrl = (
|
|
37
|
-
{
|
|
38
|
-
locals: {
|
|
39
|
-
StudioCMS: {
|
|
40
|
-
routeMap: {
|
|
41
|
-
mainLinks: { dashboardIndex },
|
|
42
|
-
},
|
|
43
|
-
},
|
|
44
|
-
},
|
|
45
|
-
}: APIContext,
|
|
46
|
-
baseUrl: string,
|
|
47
|
-
{ id, userId, token }: Token
|
|
48
|
-
) => {
|
|
49
|
-
const resetURL = new URL(`${dashboardIndex}/password-reset`, baseUrl);
|
|
50
|
-
return pipe(
|
|
51
|
-
resetURL,
|
|
52
|
-
appendSearchParamsToUrl('userid', userId),
|
|
53
|
-
appendSearchParamsToUrl('token', token),
|
|
54
|
-
appendSearchParamsToUrl('id', id)
|
|
55
|
-
);
|
|
56
|
-
};
|
|
57
|
-
|
|
58
|
-
const noMailerError = (message: string, resetLink: URL) =>
|
|
59
|
-
`Failed to send email: ${message}. You can provide the following Reset link to your User: ${resetLink}`;
|
|
60
|
-
|
|
61
|
-
export const { POST, OPTIONS, ALL } = createEffectAPIRoutes(
|
|
62
|
-
{
|
|
63
|
-
POST: (ctx) =>
|
|
64
|
-
genLogger('studiocms/routes/api/dashboard/create-user-invite.POST')(function* () {
|
|
65
|
-
const [userHelper, mailer, notify, sdk] = yield* Effect.all([
|
|
66
|
-
User,
|
|
67
|
-
Mailer,
|
|
68
|
-
Notifications,
|
|
69
|
-
SDKCore,
|
|
70
|
-
]);
|
|
71
|
-
|
|
72
|
-
const siteConfig = ctx.locals.StudioCMS.siteConfig.data;
|
|
73
|
-
|
|
74
|
-
if (!siteConfig) {
|
|
75
|
-
return apiResponseLogger(500, 'Failed to get site config');
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
// Get user data
|
|
79
|
-
const userData = ctx.locals.StudioCMS.security?.userSessionData;
|
|
80
|
-
|
|
81
|
-
// Check if user is logged in
|
|
82
|
-
if (!userData?.isLoggedIn) {
|
|
83
|
-
return apiResponseLogger(403, 'Unauthorized');
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
// Check if user has permission
|
|
87
|
-
const isAuthorized = ctx.locals.StudioCMS.security?.userPermissionLevel.isAdmin;
|
|
88
|
-
if (!isAuthorized) {
|
|
89
|
-
return apiResponseLogger(403, 'Unauthorized');
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
const { username, email, displayname, rank, originalUrl } =
|
|
93
|
-
yield* readAPIContextJson<JSONData>(ctx);
|
|
94
|
-
|
|
95
|
-
// If the username, password, email, or display name is missing, return an error
|
|
96
|
-
if (!username) {
|
|
97
|
-
return apiResponseLogger(400, 'Missing field: Username is required');
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
if (!email) {
|
|
101
|
-
return apiResponseLogger(400, 'Missing field: Email is required');
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
if (!displayname) {
|
|
105
|
-
return apiResponseLogger(400, 'Missing field: Display name is required');
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
if (!rank) {
|
|
109
|
-
return apiResponseLogger(400, 'Missing field: Rank is required');
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
const userPerms = ctx.locals.StudioCMS.security?.userPermissionLevel;
|
|
113
|
-
if (rank === 'owner' && !userPerms?.isOwner) {
|
|
114
|
-
return apiResponseLogger(403, 'Unauthorized');
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
// If the email is invalid, return an error
|
|
118
|
-
const checkEmail = z.coerce
|
|
119
|
-
.string()
|
|
120
|
-
.email({ message: 'Email address is invalid' })
|
|
121
|
-
.safeParse(email);
|
|
122
|
-
|
|
123
|
-
if (!checkEmail.success) {
|
|
124
|
-
return apiResponseLogger(400, `Invalid email: ${checkEmail.error.message}`);
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
const [verifyUsernameResponse, { usernameSearch, emailSearch }] = yield* Effect.all([
|
|
128
|
-
userHelper.verifyUsernameInput(username),
|
|
129
|
-
sdk.AUTH.user.searchUsersForUsernameOrEmail(username, checkEmail.data),
|
|
130
|
-
]);
|
|
131
|
-
|
|
132
|
-
if (verifyUsernameResponse !== true) {
|
|
133
|
-
return apiResponseLogger(400, verifyUsernameResponse);
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
if (usernameSearch.length > 0) {
|
|
137
|
-
return apiResponseLogger(400, 'Invalid username: Username is already in use');
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
if (emailSearch.length > 0) {
|
|
141
|
-
return apiResponseLogger(400, 'Invalid email: Email is already in use');
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
// Creates a new user invite
|
|
145
|
-
const token = yield* sdk.AUTH.user
|
|
146
|
-
.create(
|
|
147
|
-
{
|
|
148
|
-
username,
|
|
149
|
-
email: checkEmail.data,
|
|
150
|
-
name: displayname,
|
|
151
|
-
createdAt: new Date().toISOString(),
|
|
152
|
-
id: crypto.randomUUID(),
|
|
153
|
-
avatar: undefined,
|
|
154
|
-
emailVerified: false,
|
|
155
|
-
notifications: undefined,
|
|
156
|
-
password: undefined,
|
|
157
|
-
updatedAt: new Date().toISOString(),
|
|
158
|
-
url: undefined,
|
|
159
|
-
},
|
|
160
|
-
rank
|
|
161
|
-
)
|
|
162
|
-
.pipe(Effect.flatMap((newUser) => sdk.resetTokenBucket.new(newUser.id)));
|
|
163
|
-
|
|
164
|
-
if (!token) {
|
|
165
|
-
return apiResponseLogger(500, 'Failed to create reset token');
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
const resetLink = generateResetUrl(ctx, originalUrl, token);
|
|
169
|
-
|
|
170
|
-
yield* notify.sendAdminNotification('new_user', username);
|
|
171
|
-
|
|
172
|
-
if (siteConfig.enableMailer) {
|
|
173
|
-
const checkMailConnection = yield* mailer.verifyMailConnection;
|
|
174
|
-
|
|
175
|
-
if (!checkMailConnection) {
|
|
176
|
-
return apiResponseLogger(
|
|
177
|
-
500,
|
|
178
|
-
noMailerError('Failed to connect to mail server', resetLink)
|
|
179
|
-
);
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
if ('error' in checkMailConnection) {
|
|
183
|
-
return apiResponseLogger(
|
|
184
|
-
500,
|
|
185
|
-
noMailerError('Failed to connect to mail server', resetLink)
|
|
186
|
-
);
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
const engine = yield* templateEngine;
|
|
190
|
-
const { title: siteTitle, description, siteIcon } = siteConfig;
|
|
191
|
-
|
|
192
|
-
const userInviteTemplate = yield* engine.render('userInvite', {
|
|
193
|
-
site: { title: siteTitle, description, icon: siteIcon ?? undefined },
|
|
194
|
-
data: { link: resetLink.toString() },
|
|
195
|
-
});
|
|
196
|
-
|
|
197
|
-
const mailResponse = yield* mailer.sendMail({
|
|
198
|
-
to: checkEmail.data,
|
|
199
|
-
subject: `You have been invited to join ${siteConfig.title}!`,
|
|
200
|
-
html: userInviteTemplate,
|
|
201
|
-
});
|
|
202
|
-
|
|
203
|
-
if (!mailResponse) {
|
|
204
|
-
return apiResponseLogger(500, noMailerError('Failed to send email', resetLink));
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
if ('error' in mailResponse) {
|
|
208
|
-
return apiResponseLogger(500, noMailerError(mailResponse.error, resetLink));
|
|
209
|
-
}
|
|
210
|
-
|
|
211
|
-
return apiResponseLogger(200, 'User invite created and email sent');
|
|
212
|
-
}
|
|
213
|
-
|
|
214
|
-
return apiResponseLogger(200, resetLink.toString());
|
|
215
|
-
}).pipe(Mailer.Provide, Notifications.Provide),
|
|
216
|
-
OPTIONS: () => Effect.try(() => OptionsResponse({ allowedMethods: ['POST'] })),
|
|
217
|
-
ALL: () => Effect.try(() => AllResponse()),
|
|
218
|
-
},
|
|
219
|
-
{
|
|
220
|
-
cors: { methods: ['POST', 'OPTIONS'] },
|
|
221
|
-
onError: (error) => {
|
|
222
|
-
console.error('API Error:', error);
|
|
223
|
-
return createJsonResponse(
|
|
224
|
-
{ error: 'Internal Server Error' },
|
|
225
|
-
{
|
|
226
|
-
status: 500,
|
|
227
|
-
}
|
|
228
|
-
);
|
|
229
|
-
},
|
|
230
|
-
}
|
|
231
|
-
);
|