From ff7b3a522d0458260586b9e839e93b946c61cb81 Mon Sep 17 00:00:00 2001 From: Giovanni Abbatepaolo <30571828+bbtgnn@users.noreply.github.com> Date: Tue, 7 Jan 2025 20:47:41 +0100 Subject: [PATCH 01/29] feat: add missing migrations --- Makefile | 12 +++++ pb_migrations/1685000000_seed_admin.js | 23 +++++++++ pb_migrations/1685000001_seed_settings.js | 5 ++ pb_migrations/1685000002_seed_features.js | 57 +++++++++++++++++++++++ pb_migrations/1685000003_seed_users.js | 43 +++++++++++++++++ pb_migrations/1700000000_seed_roles.js | 20 ++++++++ 6 files changed, 160 insertions(+) create mode 100644 pb_migrations/1685000000_seed_admin.js create mode 100644 pb_migrations/1685000001_seed_settings.js create mode 100644 pb_migrations/1685000002_seed_features.js create mode 100644 pb_migrations/1685000003_seed_users.js create mode 100644 pb_migrations/1700000000_seed_roles.js diff --git a/Makefile b/Makefile index bd31ba3..ae31e09 100644 --- a/Makefile +++ b/Makefile @@ -158,3 +158,15 @@ help: ## Show this help. if (/^[a-zA-Z_-]+:.*?##.*$$/) {printf " ${YELLOW}%-20s${GREEN}%s${RESET}\n", $$1, $$2} \ else if (/^## .*$$/) {printf " ${CYAN}%s${RESET}\n", substr($$1,4)} \ }' $(MAKEFILE_LIST) + +# + +DATA := $(ROOT_DIR)/pb_data + +purge: ## ⛔ Purge the database + @echo "⛔ Purge the database" + @rm -rf $(DATA) + +backend: + @echo "⚙️ Running backend" + @go run cmd/didimo/didimo.go serve \ No newline at end of file diff --git a/pb_migrations/1685000000_seed_admin.js b/pb_migrations/1685000000_seed_admin.js new file mode 100644 index 0000000..675955b --- /dev/null +++ b/pb_migrations/1685000000_seed_admin.js @@ -0,0 +1,23 @@ +/// +// @ts-check + +const ADMIN_EMAIL = "admin@example.org"; +const SUPERUSERS = "_superusers"; + +migrate( + (app) => { + try { + app.findAuthRecordByEmail(SUPERUSERS, ADMIN_EMAIL); + } catch { + const superusers = app.findCollectionByNameOrId(SUPERUSERS); + const admin = new Record(superusers); + admin.setEmail(ADMIN_EMAIL); + admin.setPassword("adminadmin"); + app.save(admin); + } + }, + (app) => { + const admin = app.findAuthRecordByEmail(SUPERUSERS, ADMIN_EMAIL); + app.delete(admin); + } +); diff --git a/pb_migrations/1685000001_seed_settings.js b/pb_migrations/1685000001_seed_settings.js new file mode 100644 index 0000000..c352bef --- /dev/null +++ b/pb_migrations/1685000001_seed_settings.js @@ -0,0 +1,5 @@ +migrate((app) => { + const settings = app.settings(); + settings.meta.appName = "{{cookiecutter.project_name}}"; + app.save(settings); +}); diff --git a/pb_migrations/1685000002_seed_features.js b/pb_migrations/1685000002_seed_features.js new file mode 100644 index 0000000..52f931f --- /dev/null +++ b/pb_migrations/1685000002_seed_features.js @@ -0,0 +1,57 @@ +// @ts-check +/// + +/** @type {{name:string, envVariables?:Record, active?:boolean}[]} */ +const features = [ + { + name: "keypairoom", + envVariables: { + SALT: "bWltbW8K", + }, + }, + { + name: "DID", + envVariables: { + DID_URL: "url", + DID_SPEC: "string", + DID_SIGNER_SPEC: "string", + DID_IDENTITY: "string", + DID_KEYRING: "json, currently passed base64 encoded", + }, + }, + { + name: "auth", + }, + { + name: "maintenance", + active: false, + }, + { + name: "organizations", + }, + { + name: "webauthn", + envVariables: { + DISPLAY_NAME: "{{cookiecutter.project_name}}", + RPID: "localhost", + RPORIGINS: "http://localhost:5173", + }, + }, + { + name: "oauth", + }, +]; + +// + +migrate((app) => { + const featuresCollection = app.findCollectionByNameOrId("features"); + + features + .map((feature) => { + const record = new Record(featuresCollection); + record.set("name", feature.name); + return record; + }) + .forEach((featureRecord) => app.save(featureRecord)); +}); diff --git a/pb_migrations/1685000003_seed_users.js b/pb_migrations/1685000003_seed_users.js new file mode 100644 index 0000000..b5de707 --- /dev/null +++ b/pb_migrations/1685000003_seed_users.js @@ -0,0 +1,43 @@ +// @ts-check +/// + +const USERS_COLLECTION_NAME = "users"; + +/** + * @param {string} letter + */ +function createSampleUserData(letter) { + const name = `user${letter}`; + return { + email: `user${letter}@example.org`, + password: `user${letter}user${letter}`, + username: name, + name: name, + }; +} + +/** + * + * @param {excludeHooks} app + * @param {string} letter + * @returns + */ +function addSampleUser(app, letter) { + const { email, password, name } = createSampleUserData(letter); + const collection = app.findCollectionByNameOrId(USERS_COLLECTION_NAME); + + const record = new Record(collection); + record.setEmail(email); + record.setPassword(password); + record.setVerified(true); + record.set("name", name); + record.set("emailVisibility", true); + + app.save(record); +} + +migrate((app) => { + addSampleUser(app, "A"); + addSampleUser(app, "B"); + addSampleUser(app, "C"); +}); diff --git a/pb_migrations/1700000000_seed_roles.js b/pb_migrations/1700000000_seed_roles.js new file mode 100644 index 0000000..1cb6884 --- /dev/null +++ b/pb_migrations/1700000000_seed_roles.js @@ -0,0 +1,20 @@ +// @ts-check + +/// + +/** @type {Array<{name:string, level:number}>} */ +const roles = [ + { name: "owner", level: 0 }, + { name: "admin", level: 1 }, + { name: "member", level: 9 }, +]; + +// + +migrate((app) => { + const rolesCollection = app.findCollectionByNameOrId("orgRoles"); + + roles + .map((role) => new Record(rolesCollection, role)) + .forEach((roleRecord) => app.save(roleRecord)); +}); From 35e89d66829466f8e499106824d4f320df21a251 Mon Sep 17 00:00:00 2001 From: Giovanni Abbatepaolo <30571828+bbtgnn@users.noreply.github.com> Date: Wed, 8 Jan 2025 09:42:53 +0100 Subject: [PATCH 02/29] fix: features schema --- migrations/pb_schema.json | 6 +++--- ...d_features.js => 1685000002_seed_flags.js} | 20 ++++++++++--------- .../features/generate.features-list.ts | 2 +- 3 files changed, 15 insertions(+), 13 deletions(-) rename pb_migrations/{1685000002_seed_features.js => 1685000002_seed_flags.js} (73%) diff --git a/migrations/pb_schema.json b/migrations/pb_schema.json index 59aa0cb..2e242a7 100644 --- a/migrations/pb_schema.json +++ b/migrations/pb_schema.json @@ -209,10 +209,10 @@ } ], "id": "z4cc0g76ciqx13v", - "indexes": ["CREATE UNIQUE INDEX `idx_T3xOIQy` ON `features` (`name`)"], + "indexes": ["CREATE UNIQUE INDEX `idx_T3xOIQy` ON `flags` (`name`)"], "listRule": "", - "name": "features", - "system": false, + "name": "flags", + "system": true, "type": "base", "updateRule": null, "viewRule": "" diff --git a/pb_migrations/1685000002_seed_features.js b/pb_migrations/1685000002_seed_flags.js similarity index 73% rename from pb_migrations/1685000002_seed_features.js rename to pb_migrations/1685000002_seed_flags.js index 52f931f..95ee23b 100644 --- a/pb_migrations/1685000002_seed_features.js +++ b/pb_migrations/1685000002_seed_flags.js @@ -2,7 +2,7 @@ /// /** @type {{name:string, envVariables?:Record, active?:boolean}[]} */ -const features = [ +const flags = [ { name: "keypairoom", envVariables: { @@ -45,13 +45,15 @@ const features = [ // migrate((app) => { - const featuresCollection = app.findCollectionByNameOrId("features"); + const featuresCollection = app.findCollectionByNameOrId("flags"); - features - .map((feature) => { - const record = new Record(featuresCollection); - record.set("name", feature.name); - return record; - }) - .forEach((featureRecord) => app.save(featureRecord)); + flags + .map( + (flag) => + new Record(featuresCollection, { + ...flag, + active: flag.active ?? true, + }) + ) + .forEach((flagRecord) => app.save(flagRecord)); }); diff --git a/webapp/src/modules/features/generate.features-list.ts b/webapp/src/modules/features/generate.features-list.ts index 193dfbf..60b338b 100644 --- a/webapp/src/modules/features/generate.features-list.ts +++ b/webapp/src/modules/features/generate.features-list.ts @@ -8,7 +8,7 @@ const TYPE_NAME = 'Feature'; const OBJECT_NAME = `${TYPE_NAME}s`; const pb = await initAdminPocketbase(); -const featuresRecords = await pb.collection('features').getFullList(); +const featuresRecords = await pb.collection('flags').getFullList(); const featuresEntries = featuresRecords.map((f) => `${f.name.toUpperCase()}: '${f.name}'`); const code = ` From 78da78092ad79e92b8f969f4eea750bf0c3e0cc0 Mon Sep 17 00:00:00 2001 From: Giovanni Abbatepaolo <30571828+bbtgnn@users.noreply.github.com> Date: Wed, 8 Jan 2025 09:57:46 +0100 Subject: [PATCH 03/29] fix: features schema --- webapp/src/modules/features/index.ts | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/webapp/src/modules/features/index.ts b/webapp/src/modules/features/index.ts index 4bda7fe..96a31dc 100644 --- a/webapp/src/modules/features/index.ts +++ b/webapp/src/modules/features/index.ts @@ -1,6 +1,5 @@ import { Features } from './features-list.generated'; import { pb } from '@/pocketbase'; -import { Collections, type FeaturesResponse } from '@/pocketbase/types'; import { writable } from 'svelte/store'; import { browser } from '$app/environment'; @@ -14,9 +13,7 @@ export type FeatureFlags = Record; export async function loadFeatureFlags(fetchFn = fetch): Promise { const flags: Partial = {}; - const list = await pb - .collection(Collections.Features) - .getFullList({ requestKey: null, fetch: fetchFn }); + const list = await pb.collection('flags').getFullList({ requestKey: null, fetch: fetchFn }); for (const [key, name] of Object.entries(Features)) { const feature = list.find((f) => f.name === name); From ff227f919a22177af3812c0402436514468d2d1d Mon Sep 17 00:00:00 2001 From: Giovanni Abbatepaolo <30571828+bbtgnn@users.noreply.github.com> Date: Wed, 8 Jan 2025 10:00:52 +0100 Subject: [PATCH 04/29] fix: types --- webapp/src/modules/keypairoom/utils.ts | 26 +++++----- webapp/src/modules/pocketbase/types/index.ts | 7 +++ .../modules/pocketbase/zod-schema/config.ts | 52 ++++++++++++------- webapp/src/routes/keypairoom/+page.svelte | 2 +- .../routes/my/organizations/join/+page.svelte | 24 ++++++--- webapp/vite.config.ts | 2 +- 6 files changed, 71 insertions(+), 42 deletions(-) diff --git a/webapp/src/modules/keypairoom/utils.ts b/webapp/src/modules/keypairoom/utils.ts index f9ae859..950bbe8 100644 --- a/webapp/src/modules/keypairoom/utils.ts +++ b/webapp/src/modules/keypairoom/utils.ts @@ -1,16 +1,13 @@ import { pb } from '@/pocketbase'; -import { - Collections, - type UsersPublicKeysRecord, - type UsersPublicKeysResponse -} from '@/pocketbase/types'; +import { type Data, type UsersPublicKeysRecord } from '@/pocketbase/types'; import _ from 'lodash'; import type { Keypair } from './keypair'; import { createSessionStorageHandlers } from '@/utils/sessionStorage'; +import { String } from 'effect'; -export type PublicKeys = Omit; +export type PublicKeys = Omit, 'owner'>; -export function getPublicKeysFromKeypair(keypair: Keypair): PublicKeys { +export function getPublicKeysFromKeypair(keypair: Keypair): Data { const publicKeys = _.cloneDeep(keypair); // @ts-expect-error Cannot use delete on required field delete publicKeys.seed; @@ -20,20 +17,21 @@ export function getPublicKeysFromKeypair(keypair: Keypair): PublicKeys { } export async function getUserPublicKeys(userId: string | undefined = undefined, fetchFn = fetch) { - const id = userId ?? pb.authStore.model?.id ?? ''; + const id = userId ?? pb.authStore.record?.id ?? ''; + if (String.isEmpty(id)) throw new Error('Missing user ID'); try { return await pb - .collection(Collections.UsersPublicKeys) - .getFirstListItem(`owner.id = '${id}'`, { fetch: fetchFn }); - } catch (e) { + .collection('users_public_keys') + .getFirstListItem(`owner.id = '${id}'`, { fetch: fetchFn }); + } catch { return undefined; } } -export async function saveUserPublicKeys(publicKeys: PublicKeys) { - const data: UsersPublicKeysRecord = { +export async function saveUserPublicKeys(userId: string, publicKeys: PublicKeys) { + const data: Data = { ...publicKeys, - owner: pb.authStore.model?.id + owner: userId }; await pb.collection('users_public_keys').create(data); } diff --git a/webapp/src/modules/pocketbase/types/index.ts b/webapp/src/modules/pocketbase/types/index.ts index 34c16e2..b0e26a5 100644 --- a/webapp/src/modules/pocketbase/types/index.ts +++ b/webapp/src/modules/pocketbase/types/index.ts @@ -1,2 +1,9 @@ export * from './index.generated'; export * from './extra.generated'; + +// + +import type { SimplifyDeep } from 'type-fest'; +export type Data> = SimplifyDeep< + Omit +>; diff --git a/webapp/src/modules/pocketbase/zod-schema/config.ts b/webapp/src/modules/pocketbase/zod-schema/config.ts index d5a5c79..93bb3d7 100644 --- a/webapp/src/modules/pocketbase/zod-schema/config.ts +++ b/webapp/src/modules/pocketbase/zod-schema/config.ts @@ -13,8 +13,8 @@ type SchemaFieldToZodTypeMap = { }; export const schemaFieldToZodTypeMap: SchemaFieldToZodTypeMap = { - text: (config) => { - const { max, min, pattern } = config.options; + text: (field) => { + const { max, min, pattern } = field; let s = z.string(); if (max) s = s.max(max); if (min) s = s.min(min); @@ -31,21 +31,25 @@ export const schemaFieldToZodTypeMap: SchemaFieldToZodTypeMap = { return z.boolean(); }, - email: ({ options }) => { - const { exceptDomains, onlyDomains } = options; + email: (field) => { + const { exceptDomains, onlyDomains } = field; return pipe(z.string().email(), (zodEmail) => - validateDomains(zodEmail, exceptDomains, onlyDomains) + validateDomains( + zodEmail, + exceptDomains as unknown as string[], + onlyDomains as unknown as string[] + ) ); }, - file: ({ options }) => { - const { mimeTypes, maxSize } = options; + file: (field) => { + const { mimeTypes, maxSize } = field; const mimes = mimeTypes as string[] | undefined; return zodFileSchema({ mimeTypes: mimes, maxSize }); }, - date: ({ options }) => { - const { min, max } = options; + date: (field) => { + const { min, max } = field; return z .string() .refine( @@ -62,8 +66,8 @@ export const schemaFieldToZodTypeMap: SchemaFieldToZodTypeMap = { ); }, - json: ({ options }) => { - const { maxSize } = options; + json: (field) => { + const { maxSize } = field; return z.unknown().refine((json) => { if (maxSize) return getJsonDataSize(json) < maxSize; else return true; @@ -74,17 +78,17 @@ export const schemaFieldToZodTypeMap: SchemaFieldToZodTypeMap = { return z.string(); }, - number: ({ options }) => { - const { min, max, noDecimal } = options; + number: (field) => { + const { min, max, onlyInt } = field; let s = z.number(); if (min) s = s.min(min); if (max) s = s.max(max); - if (noDecimal) s = s.int(); + if (onlyInt) s = s.int(); return s; }, - select: ({ options }) => { - const { values } = options; + select: (field) => { + const { values } = field; if (!values) throw new SelectSchemaFieldNoOptionsError(); return z.string().refine((s) => values.includes(s)); }, @@ -93,9 +97,19 @@ export const schemaFieldToZodTypeMap: SchemaFieldToZodTypeMap = { return z.string(); }, - url: ({ options }) => { - const { exceptDomains, onlyDomains } = options; - return pipe(z.string().url(), (zodUrl) => validateDomains(zodUrl, exceptDomains, onlyDomains)); + url: (field) => { + const { exceptDomains, onlyDomains } = field; + return pipe(z.string().url(), (zodUrl) => + validateDomains(zodUrl, exceptDomains as unknown as string[], onlyDomains) + ); + }, + + password: () => { + return z.string(); + }, + + autodate: () => { + return z.string(); } }; diff --git a/webapp/src/routes/keypairoom/+page.svelte b/webapp/src/routes/keypairoom/+page.svelte index 1d8c151..ede0f06 100644 --- a/webapp/src/routes/keypairoom/+page.svelte +++ b/webapp/src/routes/keypairoom/+page.svelte @@ -62,7 +62,7 @@ const storedPublicKeys = await getUserPublicKeys(); if (!storedPublicKeys) { - await saveUserPublicKeys(publicKeys); + await saveUserPublicKeys($currentUser!.id, publicKeys); } else { try { await matchPublicAndPrivateKeys(storedPublicKeys, privateKeys); diff --git a/webapp/src/routes/my/organizations/join/+page.svelte b/webapp/src/routes/my/organizations/join/+page.svelte index 7880b81..ddf99da 100644 --- a/webapp/src/routes/my/organizations/join/+page.svelte +++ b/webapp/src/routes/my/organizations/join/+page.svelte @@ -2,6 +2,7 @@ import { currentUser, pb } from '@/pocketbase/index.js'; import { OrgJoinRequestsStatusOptions, + type Data, type OrgJoinRequestsRecord, type OrganizationsResponse } from '@/pocketbase/types'; @@ -12,7 +13,6 @@ import SectionTitle from '@/components/ui-custom/sectionTitle.svelte'; import PageContent from '@/components/layout/pageContent.svelte'; import PageCard from '@/components/layout/pageCard.svelte'; - import EmptyState from '@/components/ui-custom/emptyState.svelte'; import PlainCard from '@/components/ui-custom/itemCard.svelte'; import { CollectionManager } from '@/collections-components'; import Dialog from '@/components/ui-custom/dialog.svelte'; @@ -28,7 +28,7 @@ organization: org.id!, status: OrgJoinRequestsStatusOptions.pending, reminders: 0 - } satisfies OrgJoinRequestsRecord); + } satisfies Data); } @@ -64,7 +64,8 @@ {#snippet records({ records })}
{#each records as org} - {@const sentMembershipRequest = org.expand?.orgJoinRequests_via_organization?.at(0)} + {@const sentMembershipRequest = + org.expand?.orgJoinRequests_via_organization?.at(0)} {#snippet left()} @@ -96,19 +97,28 @@ {/snippet} {#snippet content({ closeDialog })} - {m.Please_confirm_that_you_want_to_join_this_organization_()} -
+ {m.Please_confirm_that_you_want_to_join_this_organization_()} +
-
{/snippet} {:else} - + {/if}
{/snippet} diff --git a/webapp/vite.config.ts b/webapp/vite.config.ts index d4afb49..332220d 100644 --- a/webapp/vite.config.ts +++ b/webapp/vite.config.ts @@ -15,7 +15,7 @@ export default defineConfig({ include: ['src/**/*.{test,spec}.{js,ts}'] }, server: { - port: process.env.PORT || 5173, + port: Number(process.env.PORT) || 5173, open: `http://localhost:8090/` } }); From 21ae9c0eed5e96c0781839b3cff359946d9dabab Mon Sep 17 00:00:00 2001 From: Giovanni Abbatepaolo <30571828+bbtgnn@users.noreply.github.com> Date: Wed, 8 Jan 2025 10:10:36 +0100 Subject: [PATCH 05/29] chore: update shadcn --- webapp/bun.lockb | Bin 290837 -> 293227 bytes webapp/package.json | 18 +++++++------- .../form/collectionFormSetup.ts | 22 +++++++++++------- .../modules/components/ui/badge/badge.svelte | 2 +- .../components/ui/button/button.svelte | 4 ++-- .../ui/sidebar/sidebar-provider.svelte | 10 ++------ .../components/ui/sidebar/sidebar.svelte | 4 +--- 7 files changed, 28 insertions(+), 32 deletions(-) diff --git a/webapp/bun.lockb b/webapp/bun.lockb index cd8998bc1ca545e429745e994de1662847c7f49f..9195bb122889b0a90eeb06c1fcafecf7de12a527 100755 GIT binary patch delta 36703 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 delta 35663 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ÒjjWK!nkT?{nZsumyfJ4q2^7aw(p||D2b3Rr0Y)_ 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 diff --git a/webapp/package.json b/webapp/package.json index cc0d5fe..528821c 100644 --- a/webapp/package.json +++ b/webapp/package.json @@ -42,7 +42,7 @@ }, "devDependencies": { "@inlang/cli": "^2.18.1", - "@internationalized/date": "^3.5.6", + "@internationalized/date": "^3.6.0", "@playwright/test": "^1.45.3", "@sveltejs/kit": "^2.12.2", "@sveltejs/vite-plugin-svelte": "^4.0.0", @@ -53,26 +53,26 @@ "@types/eslint": "^9.6.0", "@types/lodash": "^4.17.13", "autoprefixer": "^10.4.20", - "bits-ui": "1.0.0-next.74", + "bits-ui": "^1.0.0-next.77", "clsx": "^2.1.1", "dotenv": "^16.4.5", "eslint": "^9.7.0", "eslint-config-prettier": "^9.1.0", "eslint-plugin-svelte": "^2.36.0", - "formsnap": "2.0.0-next.1", + "formsnap": "^2.0.0", "globals": "^15.0.0", "json-to-ts": "^2.1.0", - "lucide-svelte": "^0.454.0", - "mode-watcher": "^0.4.1", - "paneforge": "1.0.0-next.2", + "lucide-svelte": "^0.469.0", + "mode-watcher": "^0.5.0", + "paneforge": "^1.0.0-next.2", "prettier": "^3.3.2", "prettier-plugin-svelte": "^3.2.6", "prettier-plugin-tailwindcss": "^0.6.5", - "svelte": "^5.14.4", + "svelte": "^5.16.6", "svelte-adapter-bun": "^0.5.2", "svelte-check": "^4.0.0", "svelte-sonner": "^0.3.28", - "sveltekit-superforms": "^2.20.0", + "sveltekit-superforms": "^2.22.1", "tailwind-merge": "^2.5.4", "tailwind-variants": "^0.2.1", "tailwindcss": "^3.4.9", @@ -82,7 +82,7 @@ "vite": "^5.0.3", "vite-node": "^2.1.4", "vitest": "^2.0.4", - "zod": "^3.23.8" + "zod": "^3.24.1" }, "dependencies": { "@inlang/paraglide-sveltekit": "^0.15.0", diff --git a/webapp/src/modules/collections-components/form/collectionFormSetup.ts b/webapp/src/modules/collections-components/form/collectionFormSetup.ts index 7997a5c..a3d4f3c 100644 --- a/webapp/src/modules/collections-components/form/collectionFormSetup.ts +++ b/webapp/src/modules/collections-components/form/collectionFormSetup.ts @@ -1,6 +1,6 @@ import type { CollectionName, - FileSchemaField, + FileCollectionField, SchemaFields } from '@/pocketbase/collections-models'; import { pipe, Record, String } from 'effect'; @@ -98,7 +98,9 @@ export function setupCollectionForm({ let record: CollectionResponses[C]; if (recordId) { - record = await pb.collection(collection).update(recordId, data); + record = await pb + .collection(collection) + .update(recordId, data); } else { record = await pb.collection(collection).create(data); } @@ -136,7 +138,7 @@ export function setupCollectionForm({ // - return form as SuperForm; + return form as unknown as SuperForm; } // @@ -146,7 +148,7 @@ function removeExcessProperties( collectionModel: CollectionModel, exclude: string[] = [] ): Partial { - const collectionFields = collectionModel.schema.map((f) => f.name); + const collectionFields = collectionModel.fields.map((f) => f.name); return Record.filter(recordData, (v, k) => { const isRecordField = collectionFields.includes(k); const isNotExcluded = !exclude.includes(k); @@ -177,9 +179,9 @@ function mockInitialDataFiles( ) as Partial; } -function mockFile(filename: string, fileFieldConfig: FileSchemaField) { +function mockFile(filename: string, fileFieldConfig: FileCollectionField) { let fileOptions: FilePropertyBag | undefined = undefined; - const mimeTypes = fileFieldConfig.options.mimeTypes; + const mimeTypes = fileFieldConfig.mimeTypes; if (Array.isArray(mimeTypes) && mimeTypes.length > 0) { fileOptions = { type: mimeTypes[0] }; } @@ -212,7 +214,7 @@ export function cleanFormDataFiles( initialData, Record.filter((_, fieldName) => { return Boolean( - model.schema.find( + model.fields.find( (fieldConfig) => fieldConfig.name == fieldName && fieldConfig.type == 'file' ) ); @@ -236,7 +238,9 @@ export function cleanFormDataFiles( else if (Array.isArray(newFieldValue) && newFieldValue.every((v) => v instanceof File)) { const allFilenames = newFieldValue.map((file) => file.name); const newFiles = newFieldValue.filter((file) => !initialFilenames.includes(file.name)); - const filesToRemove = initialFilenames.filter((filename) => !allFilenames.includes(filename)); + const filesToRemove = initialFilenames.filter( + (filename) => !allFilenames.includes(filename) + ); if (newFiles.length === 0) delete data[field]; else data[field] = newFiles; @@ -261,7 +265,7 @@ function mapRecordDataByFieldType( return pipe( recordData, Record.map((fieldValue, fieldName) => { - const fieldConfig = model.schema.find((field) => field.name == fieldName); + const fieldConfig = model.fields.find((field) => field.name == fieldName); if (!fieldConfig) throw new FieldConfigNotFound(); if (fieldConfig.type != fieldType) return fieldValue; return handler(fieldValue, fieldConfig as SchemaFields[T]); diff --git a/webapp/src/modules/components/ui/badge/badge.svelte b/webapp/src/modules/components/ui/badge/badge.svelte index 0c3a927..f467641 100644 --- a/webapp/src/modules/components/ui/badge/badge.svelte +++ b/webapp/src/modules/components/ui/badge/badge.svelte @@ -43,7 +43,7 @@ this={href ? "a" : "span"} bind:this={ref} {href} - class={cn(badgeVariants({ variant, className }))} + class={cn(badgeVariants({ variant }), className)} {...restProps} > {@render children?.()} diff --git a/webapp/src/modules/components/ui/button/button.svelte b/webapp/src/modules/components/ui/button/button.svelte index 2ff6a02..80c29d0 100644 --- a/webapp/src/modules/components/ui/button/button.svelte +++ b/webapp/src/modules/components/ui/button/button.svelte @@ -56,7 +56,7 @@ {#if href} @@ -65,7 +65,7 @@ {:else}
{:else if sidebar.isMobile} sidebar.openMobile, (v) => sidebar.setOpenMobile(v)} {...restProps} > Date: Wed, 8 Jan 2025 10:17:45 +0100 Subject: [PATCH 06/29] fix: types --- webapp/src/modules/auth/oauth/oauth.svelte | 6 ++-- webapp/src/modules/pocketbase/types/index.ts | 13 +++++++- .../pocketbase/zod-schema/index.test.ts | 30 ++++++++++--------- webapp/src/modules/webauthn/index.ts | 7 +++-- 4 files changed, 36 insertions(+), 20 deletions(-) diff --git a/webapp/src/modules/auth/oauth/oauth.svelte b/webapp/src/modules/auth/oauth/oauth.svelte index 43fa9d2..132c98f 100644 --- a/webapp/src/modules/auth/oauth/oauth.svelte +++ b/webapp/src/modules/auth/oauth/oauth.svelte @@ -5,7 +5,7 @@ import type { ClientResponseError } from 'pocketbase'; import Alert from '@/components/ui-custom/alert.svelte'; import { goto, m } from '@/i18n'; - import type { UsersRecord } from '@/pocketbase/types'; + import type { Data, UsersRecord } from '@/pocketbase/types'; import { nanoid } from 'nanoid'; import LoadingDialog from '@/components/ui-custom/loadingDialog.svelte'; import { Separator } from '@/components/ui/separator'; @@ -27,14 +27,14 @@ .collection('users') .listAuthMethods() .then((list) => - list.authProviders.map((provider) => { + list.oauth2.providers.map((provider) => { return { displayName: provider.displayName, image: `${PUBLIC_POCKETBASE_URL}_/images/oauth2/${provider.name}.svg`, // TODO - This won't work with `oidc2` for example initializer: async () => { loading = true; try { - const createData: UsersRecord = { name: nanoid(5) }; + const createData: Data = { name: nanoid(5) }; const authData = await pb.collection('users').authWithOAuth2({ provider: provider.name, createData diff --git a/webapp/src/modules/pocketbase/types/index.ts b/webapp/src/modules/pocketbase/types/index.ts index b0e26a5..0294014 100644 --- a/webapp/src/modules/pocketbase/types/index.ts +++ b/webapp/src/modules/pocketbase/types/index.ts @@ -4,6 +4,17 @@ export * from './extra.generated'; // import type { SimplifyDeep } from 'type-fest'; + export type Data> = SimplifyDeep< - Omit + Omit< + R, + // base system fields + | 'id' + | 'created' + | 'updated' + // user/auth fields + | 'password' + | 'tokenKey' + | 'username' + > >; diff --git a/webapp/src/modules/pocketbase/zod-schema/index.test.ts b/webapp/src/modules/pocketbase/zod-schema/index.test.ts index b17c852..3fabf67 100644 --- a/webapp/src/modules/pocketbase/zod-schema/index.test.ts +++ b/webapp/src/modules/pocketbase/zod-schema/index.test.ts @@ -1,11 +1,13 @@ import { describe, it, expect } from 'vitest'; import { createCollectionZodSchema } from '.'; -import type { CollectionFormData } from '@/pocketbase/types'; +import type { CollectionFormData, Data } from '@/pocketbase/types'; import { getCollectionModel } from '@/pocketbase/collections-models'; import { subYears, addYears, differenceInMilliseconds, addMilliseconds } from 'date-fns'; // +type ZTestFormData = Data; + describe('generated collection zod schema', () => { const schema = createCollectionZodSchema('z_test_collection'); @@ -14,7 +16,7 @@ describe('generated collection zod schema', () => { expect(parseResult.success).toBe(false); }); - const baseData: CollectionFormData['z_test_collection'] = { + const baseData: ZTestFormData = { number_field: 3, relation_field: 'generic-id', text_field: 'sampletext', @@ -29,7 +31,7 @@ describe('generated collection zod schema', () => { }); it('fails the validation for file with bad mimeType', () => { - const data: CollectionFormData['z_test_collection'] = { + const data: ZTestFormData = { ...baseData, file_field: dummyFile('text/json') }; @@ -41,7 +43,7 @@ describe('generated collection zod schema', () => { }); it('accepts empty string for optional url', () => { - const data: CollectionFormData['z_test_collection'] = { + const data: ZTestFormData = { ...baseData, url_field: '' }; @@ -50,7 +52,7 @@ describe('generated collection zod schema', () => { }); it('doesn`t accept url with bad domain', () => { - const data: CollectionFormData['z_test_collection'] = { + const data: ZTestFormData = { ...baseData, url_field: 'https://miao.com' }; @@ -61,7 +63,7 @@ describe('generated collection zod schema', () => { }); it('fails the regex test', () => { - const data: CollectionFormData['z_test_collection'] = { + const data: ZTestFormData = { ...baseData, text_with_regex: 'abc 123-24' }; @@ -71,7 +73,7 @@ describe('generated collection zod schema', () => { // JSON Field Checks - const jsonField = getCollectionModel('z_test_collection').schema.find( + const jsonField = getCollectionModel('z_test_collection').fields.find( (schemaField) => schemaField.type == 'json' ); if (!jsonField) throw new Error('field not found'); @@ -79,7 +81,7 @@ describe('generated collection zod schema', () => { if (!jsonMaxSize) throw new Error('missing json max size'); it('fails the json size check with a large JSON object', () => { - const data: CollectionFormData['z_test_collection'] = { + const data: ZTestFormData = { ...baseData, json_field: generateLargeJSONObject(jsonMaxSize * 1.5) }; @@ -90,9 +92,9 @@ describe('generated collection zod schema', () => { }); it('passes the json size check with a small JSON object', () => { - const jsonMaxSize = getCollectionModel('z_test_collection').schema[12].options.maxSize; + const jsonMaxSize = getCollectionModel('z_test_collection').fields[12].options.maxSize; const jsonObject = generateLargeJSONObject(jsonMaxSize * 0.5); - const data: CollectionFormData['z_test_collection'] = { + const data: ZTestFormData = { ...baseData, json_field: jsonObject }; @@ -102,7 +104,7 @@ describe('generated collection zod schema', () => { // Date checks - const dateField = getCollectionModel('z_test_collection').schema.find( + const dateField = getCollectionModel('z_test_collection').fields.find( (schemaField) => schemaField.type == 'date' ); if (!dateField) throw new Error('field not found'); @@ -112,7 +114,7 @@ describe('generated collection zod schema', () => { it('fails the date check with a date earlier than minimum', () => { const earlierDate = subYears(minDate, 10); - const data: CollectionFormData['z_test_collection'] = { + const data: ZTestFormData = { ...baseData, date_field: earlierDate.toISOString() }; @@ -123,7 +125,7 @@ describe('generated collection zod schema', () => { it('fails the date check with a date later than maximum', () => { const laterDate = addYears(maxDate, 10); - const data: CollectionFormData['z_test_collection'] = { + const data: ZTestFormData = { ...baseData, date_field: laterDate.toISOString() }; @@ -137,7 +139,7 @@ describe('generated collection zod schema', () => { console.log(minDate, betweenDate.toISOString(), maxDate); - const data: CollectionFormData['z_test_collection'] = { + const data: ZTestFormData = { ...baseData, date_field: betweenDate.toISOString() }; diff --git a/webapp/src/modules/webauthn/index.ts b/webapp/src/modules/webauthn/index.ts index 5e209c4..4b457a4 100644 --- a/webapp/src/modules/webauthn/index.ts +++ b/webapp/src/modules/webauthn/index.ts @@ -62,7 +62,8 @@ export async function loginUser(username: string) { const clientDataJSON = resp.clientDataJSON; const rawId = assertion.rawId; const sig = resp.signature; - const userHandle = resp.userHandle || new Uint8Array(); + const userHandle = resp.userHandle; + if (!userHandle) throw new Error('WEBAUTHN: Missing user handle'); const token = await pb.send('/api/webauthn/login/finish/' + username, { body: { @@ -97,7 +98,9 @@ export async function isPlatformAuthenticatorAvailable() { // Base64 to ArrayBuffer function bufferDecode(value: string) { - return Uint8Array.from(atob(value.replace(/-/g, '+').replace(/_/g, '/')), (c) => c.charCodeAt(0)); + return Uint8Array.from(atob(value.replace(/-/g, '+').replace(/_/g, '/')), (c) => + c.charCodeAt(0) + ); } function bufferEncode(buffer: ArrayBuffer) { From 8b48ae70252bb11e40c3104ed1aa965264500e0d Mon Sep 17 00:00:00 2001 From: Giovanni Abbatepaolo <30571828+bbtgnn@users.noreply.github.com> Date: Wed, 8 Jan 2025 10:38:11 +0100 Subject: [PATCH 07/29] fix: types --- webapp/bun.lockb | Bin 293227 -> 293227 bytes webapp/package.json | 2 +- .../form/collectionForm.svelte | 10 +++-- .../form/collectionFormField.svelte | 37 ++++++++++-------- .../modules/pocketbase/zod-schema/index.ts | 8 ++-- .../src/routes/ui-tests/schema/+page.svelte | 4 +- webapp/tsconfig.json | 2 +- 7 files changed, 34 insertions(+), 29 deletions(-) diff --git a/webapp/bun.lockb b/webapp/bun.lockb index 9195bb122889b0a90eeb06c1fcafecf7de12a527..d41a9aeba8f7e7ae40baa2cb6f205c3881b38d5d 100755 GIT binary patch delta 27 jcmaF;N$~Y2!G;#bEllEnnGN*}+ok?8ZI}AX99RPYu|x}f delta 27 jcmaF;N$~Y2!G;#bEllEnnGN&|+NJ(7ZI}AX99RPYu`COF diff --git a/webapp/package.json b/webapp/package.json index 528821c..a509c6f 100644 --- a/webapp/package.json +++ b/webapp/package.json @@ -70,7 +70,7 @@ "prettier-plugin-tailwindcss": "^0.6.5", "svelte": "^5.16.6", "svelte-adapter-bun": "^0.5.2", - "svelte-check": "^4.0.0", + "svelte-check": "^4.1.1", "svelte-sonner": "^0.3.28", "sveltekit-superforms": "^2.22.1", "tailwind-merge": "^2.5.4", diff --git a/webapp/src/modules/collections-components/form/collectionForm.svelte b/webapp/src/modules/collections-components/form/collectionForm.svelte index a069f3d..0061594 100644 --- a/webapp/src/modules/collections-components/form/collectionForm.svelte +++ b/webapp/src/modules/collections-components/form/collectionForm.svelte @@ -1,5 +1,5 @@ @@ -45,31 +48,31 @@ {:else if snippet} {@render snippet({ - form: form as SuperForm, + form: form as unknown as SuperForm, field: name as FormPath })} -{:else if fieldConfig.type == 'text' || fieldConfig.type == 'url' || fieldConfig.type == 'date' || fieldConfig.type == 'email'} - -{:else if fieldConfig.type == 'number'} +{:else if config.type == 'text' || config.type == 'url' || config.type == 'date' || config.type == 'email'} + +{:else if config.type == 'number'} -{:else if fieldConfig.type == 'json'} +{:else if config.type == 'json'} -{:else if fieldConfig.type == 'bool'} +{:else if config.type == 'bool'} -{:else if fieldConfig.type == 'file'} - {@const accept = fieldConfig.options.mimeTypes?.join(',')} +{:else if config.type == 'file'} + {@const accept = config.mimeTypes?.join(',')} -{:else if fieldConfig.type == 'select'} - {@const items = fieldConfig.options.values?.map((v) => ({ label: v, value: v }))} +{:else if config.type == 'select'} + {@const items = config.values?.map((v) => ({ label: v, value: v }))} -{:else if fieldConfig.type == 'editor'} +{:else if config.type == 'editor'} -{:else if fieldConfig.type == 'relation'} - {@const collectionName = getCollectionNameFromId(fieldConfig.options.collectionId!) as C} +{:else if config.type == 'relation'} + {@const collectionName = getCollectionNameFromId(config.collectionId) as C} ( collection: C ): CollectionZodSchema { const { schema } = getCollectionModel(collection); - const schemaFields = schema as AnySchemaField[]; + const schemaFields = schema as AnyCollectionField[]; const entries = schemaFields.map((fieldConfig) => { const zodTypeConstructor = schemaFieldToZodTypeMap[fieldConfig.type] as ( - c: AnySchemaField + c: AnyCollectionField ) => z.ZodTypeAny; const zodType = pipe( @@ -36,7 +36,7 @@ export function createCollectionZodSchema( minSelect: z.number().nullish(), maxSelect: z.number().nullish() }) - .parse(fieldConfig.options); + .parse(fieldConfig); if (minSelect) s = s.min(minSelect); if (maxSelect) s = s.max(maxSelect); return s; diff --git a/webapp/src/routes/ui-tests/schema/+page.svelte b/webapp/src/routes/ui-tests/schema/+page.svelte index d035e6b..aa67791 100644 --- a/webapp/src/routes/ui-tests/schema/+page.svelte +++ b/webapp/src/routes/ui-tests/schema/+page.svelte @@ -1,7 +1,7 @@ -
+ {#each fields as field} {/each} - -{#snippet submitButtonContent()} - {#if buttonContent} - {@render buttonContent()} - {:else if formMode == 'edit'} - {m.Edit_record()} - {:else if formMode == 'create'} - {m.Create_record()} - {/if} -{/snippet} + {#snippet submitButtonContent()} + {#if buttonContent} + {@render buttonContent()} + {:else if formMode == 'edit'} + {m.Edit_record()} + {:else if formMode == 'create'} + {m.Create_record()} + {/if} + {/snippet} + From 3a7c8eb7c995299455c0e1158e367340eedf1172 Mon Sep 17 00:00:00 2001 From: Giovanni Abbatepaolo <30571828+bbtgnn@users.noreply.github.com> Date: Wed, 8 Jan 2025 10:58:43 +0100 Subject: [PATCH 11/29] fix: name --- migrations/pb_schema.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/migrations/pb_schema.json b/migrations/pb_schema.json index e1f3130..1745cdb 100644 --- a/migrations/pb_schema.json +++ b/migrations/pb_schema.json @@ -1627,7 +1627,7 @@ "id": "relation1542800728", "maxSelect": 1, "minSelect": 0, - "name": "field", + "name": "organization", "presentable": false, "required": false, "system": false, From f19f35b23f49508e2ac2a167b5204791ba07044b Mon Sep 17 00:00:00 2001 From: Giovanni Abbatepaolo <30571828+bbtgnn@users.noreply.github.com> Date: Wed, 8 Jan 2025 12:18:57 +0100 Subject: [PATCH 12/29] feat: update hooks --- pb_hooks/features.pb.js | 4 ++++ pb_hooks/oauth.pb.js | 2 ++ pb_hooks/organizations.pb.js | 6 +++++ pb_hooks/organizations_authorizations.pb.js | 20 ++++++++++++++-- pb_hooks/organizations_invites.pb.js | 7 +++++- .../organizations_request_membership.pb.js | 21 ++++++++++++++++- pb_hooks/users.pb.js | 6 +++++ pb_hooks/utils.js | 18 +++++++-------- webapp/src/modules/pocketbase/types/index.ts | 23 ++++++++++--------- .../pocketbase/zod-schema/index.test.ts | 6 ++--- .../modules/pocketbase/zod-schema/index.ts | 11 +++++---- 11 files changed, 92 insertions(+), 32 deletions(-) diff --git a/pb_hooks/features.pb.js b/pb_hooks/features.pb.js index 15e9c67..c1e93cc 100644 --- a/pb_hooks/features.pb.js +++ b/pb_hooks/features.pb.js @@ -10,6 +10,8 @@ onRecordViewRequest((e) => { if (utils.isAdminContext(e)) return; e.record?.set("envVariables", null); + + e.next(); }, "features"); onRecordsListRequest((e) => { @@ -21,4 +23,6 @@ onRecordsListRequest((e) => { e.records.forEach((r) => { r?.set("envVariables", null); }); + + e.next(); }, "features"); diff --git a/pb_hooks/oauth.pb.js b/pb_hooks/oauth.pb.js index 165d4ed..04532f6 100644 --- a/pb_hooks/oauth.pb.js +++ b/pb_hooks/oauth.pb.js @@ -5,6 +5,8 @@ /* Updating user info on first register */ onRecordAuthWithOAuth2Request((e) => { + e.next(); + if (!e.isNewRecord) return; /** @type {Utils} */ diff --git a/pb_hooks/organizations.pb.js b/pb_hooks/organizations.pb.js index 9032229..91b042a 100644 --- a/pb_hooks/organizations.pb.js +++ b/pb_hooks/organizations.pb.js @@ -75,6 +75,8 @@ routerAdd("POST", "/organizations/verify-user-role", (e) => { // On Organization Create – Creating owner authorization onRecordCreateRequest((e) => { + e.next(); + /** @type {Utils} */ const utils = require(`${__hooks}/utils.js`); /** @type {AuditLogger} */ @@ -115,6 +117,8 @@ onRecordCreateRequest((e) => { // Log organization creation onRecordCreateRequest((e) => { + e.next(); + /** @type {AuditLogger} */ const auditLogger = require(`${__hooks}/auditLogger.js`); @@ -132,6 +136,8 @@ onRecordCreateRequest((e) => { // Send email after organization creation onRecordCreateRequest((e) => { + e.next(); + /** @type {Utils} */ const utils = require(`${__hooks}/utils.js`); diff --git a/pb_hooks/organizations_authorizations.pb.js b/pb_hooks/organizations_authorizations.pb.js index 49a62da..05caa2c 100644 --- a/pb_hooks/organizations_authorizations.pb.js +++ b/pb_hooks/organizations_authorizations.pb.js @@ -3,8 +3,8 @@ /// /** @typedef {import('./utils.js')} Utils */ /** @typedef {import('./auditLogger.js')} AuditLogger */ -/** @typedef {import("../../webapp/src/modules/pocketbase/types").OrgAuthorizationsRecord} OrgAuthorization */ -/** @typedef {import("../../webapp/src/modules/pocketbase/types").OrgRolesResponse} OrgRole */ +/** @typedef {import("../webapp/src/modules/pocketbase/types").OrgAuthorizationsRecord} OrgAuthorization */ +/** @typedef {import("../webapp/src/modules/pocketbase/types").OrgRolesResponse} OrgRole */ /** * INDEX @@ -44,6 +44,8 @@ onRecordCreateRequest((e) => { utils.errors.cant_create_role_higher_than_or_equal_to_yours ); } + + e.next(); }, "orgAuthorizations"); // [UPDATE] Cannot update to/from a role higher than the user @@ -91,6 +93,8 @@ onRecordUpdateRequest((e) => { throw new ForbiddenError( utils.errors.cant_edit_role_higher_than_or_equal_to_yours ); + + e.next(); }, "orgAuthorizations"); // [DELETE] Cannot delete an authorization with a level higher than or equal to yours @@ -122,6 +126,8 @@ onRecordDeleteRequest((e) => { throw new ForbiddenError( utils.errors.cant_delete_role_higher_than_or_equal_to_yours ); + + e.next(); }, "orgAuthorizations"); // [DELETE] Cannot delete last owner role @@ -135,6 +141,8 @@ onRecordDeleteRequest((e) => { if (e.record && utils.isLastOwnerAuthorization(e.record)) { throw new BadRequestError(utils.errors.cant_edit_last_owner_role); } + + e.next(); }, "orgAuthorizations"); // [UPDATE] Cannot edit last owner role @@ -152,11 +160,15 @@ onRecordUpdateRequest((e) => { if (originalRecord && utils.isLastOwnerAuthorization(originalRecord)) { throw new BadRequestError(utils.errors.cant_delete_last_owner_role); } + + e.next(); }, "orgAuthorizations"); /* Audit + Email hooks */ onRecordCreateRequest((e) => { + e.next(); + /** @type {AuditLogger} */ const auditLogger = require(`${__hooks}/auditLogger.js`); @@ -187,6 +199,8 @@ onRecordCreateRequest((e) => { }, "orgAuthorizations"); onRecordUpdateRequest((e) => { + e.next(); + /** @type {AuditLogger} */ const auditLogger = require(`${__hooks}/auditLogger.js`); @@ -250,6 +264,8 @@ onRecordUpdateRequest((e) => { }, "orgAuthorizations"); onRecordDeleteRequest((e) => { + e.next(); + /** @type {AuditLogger} */ const auditLogger = require(`${__hooks}/auditLogger.js`); diff --git a/pb_hooks/organizations_invites.pb.js b/pb_hooks/organizations_invites.pb.js index 5944332..e9d4f62 100644 --- a/pb_hooks/organizations_invites.pb.js +++ b/pb_hooks/organizations_invites.pb.js @@ -13,6 +13,8 @@ /* Hooks */ onRecordCreateRequest((e) => { + e.next(); + /** @type {Utils} */ const utils = require(`${__hooks}/utils.js`); @@ -41,7 +43,8 @@ routerAdd("POST", "/organizations/invites/accept", (c) => { /* -- Logic -- */ - const orgAuthorizationsCollection = $app.findCollectionByNameOrId("orgAuthorizations"); + const orgAuthorizationsCollection = + $app.findCollectionByNameOrId("orgAuthorizations"); const organizationId = invite.get("organization"); @@ -221,6 +224,8 @@ routerAdd("POST", "/organizations/invite", (c) => { /* */ onRecordDeleteRequest((e) => { + e.next(); + /** @type {AuditLogger} */ const auditLogger = require(`${__hooks}/auditLogger.js`); diff --git a/pb_hooks/organizations_request_membership.pb.js b/pb_hooks/organizations_request_membership.pb.js index 6fcc20e..5226c9c 100644 --- a/pb_hooks/organizations_request_membership.pb.js +++ b/pb_hooks/organizations_request_membership.pb.js @@ -15,6 +15,8 @@ onRecordCreateRequest((e) => { e.record?.set("status", "pending"); e.record?.set("reminders", 0); + + e.next(); }, "orgJoinRequests"); // Cannot create join request if user is already member @@ -35,11 +37,15 @@ onRecordCreateRequest((e) => { if (authorization) throw new BadRequestError(utils.errors.user_is_already_member); + + e.next(); }, "orgJoinRequests"); // Create orgAuthorization after accepting membership request onRecordUpdateRequest((e) => { + e.next(); + /** @type {Utils} */ const utils = require(`${__hooks}/utils.js`); @@ -48,7 +54,8 @@ onRecordUpdateRequest((e) => { const status = e.record.get("status"); if (status != "accepted") return; - const orgAuthorizationsCollection = $app.findCollectionByNameOrId("orgAuthorizations"); + const orgAuthorizationsCollection = + $app.findCollectionByNameOrId("orgAuthorizations"); if (!orgAuthorizationsCollection) throw utils.createMissingDataError("orgAuthorizationsCollection"); @@ -70,6 +77,8 @@ onRecordUpdateRequest((e) => { /* Email hooks - Notifications to Admins */ onRecordCreateRequest((e) => { + e.next(); + /** @type {Utils} */ const utils = require(`${__hooks}/utils.js`); @@ -155,6 +164,8 @@ cronAdd("remind admins about join requests", "0 9 * * 1", () => { /* Email hooks - Notifications to Users */ onRecordUpdateRequest((e) => { + e.next(); + /** @type {Utils} */ const utils = require(`${__hooks}/utils.js`); @@ -205,6 +216,8 @@ onRecordUpdateRequest((e) => { /* Audit logs */ onRecordCreateRequest((e) => { + e.next(); + /** @type {AuditLogger} */ const auditLogger = require(`${__hooks}/auditLogger.js`); @@ -218,6 +231,8 @@ onRecordCreateRequest((e) => { }, "orgJoinRequests"); onRecordUpdateRequest((e) => { + e.next(); + /** @type {AuditLogger} */ const auditLogger = require(`${__hooks}/auditLogger.js`); @@ -233,6 +248,8 @@ onRecordUpdateRequest((e) => { }, "orgJoinRequests"); onRecordDeleteRequest((e) => { + e.next(); + /** @type {AuditLogger} */ const auditLogger = require(`${__hooks}/auditLogger.js`); @@ -250,6 +267,8 @@ onRecordDeleteRequest((e) => { /* IMPORTANT: This hook must be registered last */ onRecordUpdateRequest((e) => { + e.next(); + /** @type {Utils} */ const utils = require(`${__hooks}/utils.js`); diff --git a/pb_hooks/users.pb.js b/pb_hooks/users.pb.js index 9d0ad95..74bc5b6 100644 --- a/pb_hooks/users.pb.js +++ b/pb_hooks/users.pb.js @@ -24,6 +24,8 @@ onMailerRecordPasswordResetSend((e) => { e.message.html = emailData.html; e.message.subject = emailData.subject; + + e.next(); }, "users"); onMailerRecordVerificationSend((e) => { @@ -47,9 +49,13 @@ onMailerRecordVerificationSend((e) => { e.message.html = emailData.html; e.message.subject = emailData.subject; + + e.next(); }, "users"); onRecordCreateRequest((e) => { + e.next(); + /** @type {Utils} */ const utils = require(`${__hooks}/utils.js`); diff --git a/pb_hooks/utils.js b/pb_hooks/utils.js index c9efe31..8cb4bb5 100644 --- a/pb_hooks/utils.js +++ b/pb_hooks/utils.js @@ -3,11 +3,11 @@ /// /// -/** @typedef {import("../../webapp/src/modules/pocketbase/types").OrgRolesRecord} OrgRole */ -/** @typedef {import("../../webapp/src/modules/pocketbase/types").OrgAuthorizationsRecord} OrgAuthorization */ -/** @typedef {import("../../webapp/src/modules/pocketbase/types").UsersRecord} User */ +/** @typedef {import("../webapp/src/modules/pocketbase/types").OrgRolesRecord} OrgRole */ +/** @typedef {import("../webapp/src/modules/pocketbase/types").OrgAuthorizationsRecord} OrgAuthorization */ +/** @typedef {import("../webapp/src/modules/pocketbase/types").UsersRecord} User */ -/** @typedef {Omit} Address */ +/** @typedef {MailerMessage["to"][number]} Address */ // @@ -68,7 +68,7 @@ function isLastOwnerAuthorization(orgAuthorization) { const ownerAuthorizations = findRecordsByFilter( "orgAuthorizations", - `organization="${organizationId}" && role="${ownerRoleId}"`, + `organization="${organizationId}" && role="${ownerRoleId}"` ); return ownerAuthorizations.length == 1; @@ -84,7 +84,7 @@ function getUserRole(userId, organizationId, app = $app) { const authorization = findFirstRecordByFilter( "orgAuthorizations", `user = "${userId}" && organization = "${organizationId}"`, - app, + app ); if (!authorization) return undefined; return getExpanded(authorization, "role", app); @@ -202,13 +202,11 @@ function getUserEmailAddressData(user) { function sendEmail(data) { try { const message = new MailerMessage({ - // @ts-expect-error Missing string() object from: { address: data.from?.address ?? $app.settings().meta.senderAddress, name: data.from?.name ?? $app.settings().meta.senderName, }, - // @ts-expect-error Missing string() object to: Array.isArray(data.to) ? data.to : [data.to], subject: data.subject, html: data.html, @@ -238,7 +236,7 @@ function getOrganizationAdminsAddresses(organizationId, app = $app) { const recipients = findRecordsByFilter( "orgAuthorizations", `organization.id = "${organizationId}" && ( role.name = "admin" || role.name = "owner" )`, - app, + app ); return recipients @@ -336,7 +334,7 @@ const renderEmail = (name, data) => { "webapp", "static", "emails", - `${name}.html`, + `${String(name)}.html` ); const html = $template .loadFiles(emailPath) diff --git a/webapp/src/modules/pocketbase/types/index.ts b/webapp/src/modules/pocketbase/types/index.ts index 0294014..c4989db 100644 --- a/webapp/src/modules/pocketbase/types/index.ts +++ b/webapp/src/modules/pocketbase/types/index.ts @@ -5,16 +5,17 @@ export * from './extra.generated'; import type { SimplifyDeep } from 'type-fest'; +export const systemFields = [ + // base system fields + 'id', + 'created', + 'updated', + // user/auth fields + 'password', + 'tokenKey', + 'username' +] as const; + export type Data> = SimplifyDeep< - Omit< - R, - // base system fields - | 'id' - | 'created' - | 'updated' - // user/auth fields - | 'password' - | 'tokenKey' - | 'username' - > + Omit >; diff --git a/webapp/src/modules/pocketbase/zod-schema/index.test.ts b/webapp/src/modules/pocketbase/zod-schema/index.test.ts index 3fabf67..0621be7 100644 --- a/webapp/src/modules/pocketbase/zod-schema/index.test.ts +++ b/webapp/src/modules/pocketbase/zod-schema/index.test.ts @@ -77,7 +77,7 @@ describe('generated collection zod schema', () => { (schemaField) => schemaField.type == 'json' ); if (!jsonField) throw new Error('field not found'); - const { maxSize: jsonMaxSize } = jsonField.options; + const { maxSize: jsonMaxSize } = jsonField; if (!jsonMaxSize) throw new Error('missing json max size'); it('fails the json size check with a large JSON object', () => { @@ -92,7 +92,7 @@ describe('generated collection zod schema', () => { }); it('passes the json size check with a small JSON object', () => { - const jsonMaxSize = getCollectionModel('z_test_collection').fields[12].options.maxSize; + const jsonMaxSize = getCollectionModel('z_test_collection').fields[12].maxSize; const jsonObject = generateLargeJSONObject(jsonMaxSize * 0.5); const data: ZTestFormData = { ...baseData, @@ -108,7 +108,7 @@ describe('generated collection zod schema', () => { (schemaField) => schemaField.type == 'date' ); if (!dateField) throw new Error('field not found'); - const { max: maxDate, min: minDate } = dateField.options; + const { max: maxDate, min: minDate } = dateField; if (!maxDate || !minDate) throw new Error('missing min and max date'); it('fails the date check with a date earlier than minimum', () => { diff --git a/webapp/src/modules/pocketbase/zod-schema/index.ts b/webapp/src/modules/pocketbase/zod-schema/index.ts index 4f9e85e..b1579d1 100644 --- a/webapp/src/modules/pocketbase/zod-schema/index.ts +++ b/webapp/src/modules/pocketbase/zod-schema/index.ts @@ -7,7 +7,7 @@ import { type AnyCollectionField, type CollectionName } from '@/pocketbase/collections-models'; -import type { CollectionZodRawShapes } from '../types'; +import { systemFields, type CollectionZodRawShapes } from '../types'; // @@ -16,10 +16,13 @@ export type CollectionZodSchema = z.ZodObject( collection: C ): CollectionZodSchema { - const { schema } = getCollectionModel(collection); - const schemaFields = schema as AnyCollectionField[]; + const { fields } = getCollectionModel(collection); + const collectionFields = (fields as AnyCollectionField[]).filter( + (f) => !(systemFields as unknown as string[]).includes(f.name) + ); + console.log(collectionFields); - const entries = schemaFields.map((fieldConfig) => { + const entries = collectionFields.map((fieldConfig) => { const zodTypeConstructor = schemaFieldToZodTypeMap[fieldConfig.type] as ( c: AnyCollectionField ) => z.ZodTypeAny; From 2b0566d7df3387bae7c8231d9c3b36f74dea30e7 Mon Sep 17 00:00:00 2001 From: Giovanni Abbatepaolo <30571828+bbtgnn@users.noreply.github.com> Date: Wed, 8 Jan 2025 12:20:02 +0100 Subject: [PATCH 13/29] fix: types --- pb_hooks/organizations_request_membership.pb.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/pb_hooks/organizations_request_membership.pb.js b/pb_hooks/organizations_request_membership.pb.js index 5226c9c..bc7ccce 100644 --- a/pb_hooks/organizations_request_membership.pb.js +++ b/pb_hooks/organizations_request_membership.pb.js @@ -96,7 +96,7 @@ onRecordCreateRequest((e) => { for (const adminAddress of recipients) { const email = utils.renderEmail("membership-request-new", { OrganizationName: organization.getString("name"), - Admin: adminAddress.name, + Admin: adminAddress.name ?? "Admin", UserName: user.getString("name"), DashboardLink: utils.getOrganizationMembersPageUrl(organizationId), AppName: utils.getAppName(), @@ -145,7 +145,7 @@ cronAdd("remind admins about join requests", "0 9 * * 1", () => { OrganizationName, DashboardLink: utils.getOrganizationMembersPageUrl(organizationId), - Admin: recipient.name, + Admin: recipient.name ?? "Admin", PendingNumber: requests.length.toString(), AppName: utils.getAppName(), }); @@ -196,7 +196,7 @@ onRecordUpdateRequest((e) => { /** @type {EmailContent} */ const successEmail = utils.renderEmail("membership-request-accepted", { OrganizationName, - UserName: userAddress.name, + UserName: userAddress.name ?? "User", DashboardLink: utils.getOrganizationPageUrl(organization.id), AppName: utils.getAppName(), }); @@ -204,7 +204,7 @@ onRecordUpdateRequest((e) => { /** @type {EmailContent} */ const rejectEmail = utils.renderEmail("membership-request-declined", { OrganizationName, - UserName: userAddress.name, + UserName: userAddress.name ?? "User", DashboardLink: utils.getAppUrl() + "/my/organizations", AppName: utils.getAppName(), }); From dd292614fc638e11094855682206e874ef567b2d Mon Sep 17 00:00:00 2001 From: Giovanni Abbatepaolo <30571828+bbtgnn@users.noreply.github.com> Date: Wed, 8 Jan 2025 13:28:06 +0100 Subject: [PATCH 14/29] fix --- pb_migrations/1685000001_seed_settings.js | 2 +- .../modules/pocketbase/subscriptions/index.ts | 2 +- webapp/src/routes/my/+layout.svelte | 28 +++++++++---------- 3 files changed, 16 insertions(+), 16 deletions(-) diff --git a/pb_migrations/1685000001_seed_settings.js b/pb_migrations/1685000001_seed_settings.js index c352bef..1796b58 100644 --- a/pb_migrations/1685000001_seed_settings.js +++ b/pb_migrations/1685000001_seed_settings.js @@ -1,5 +1,5 @@ migrate((app) => { const settings = app.settings(); - settings.meta.appName = "{{cookiecutter.project_name}}"; + settings.meta.appName = "DIDimo"; app.save(settings); }); diff --git a/webapp/src/modules/pocketbase/subscriptions/index.ts b/webapp/src/modules/pocketbase/subscriptions/index.ts index 2871b95..a72cfce 100644 --- a/webapp/src/modules/pocketbase/subscriptions/index.ts +++ b/webapp/src/modules/pocketbase/subscriptions/index.ts @@ -63,7 +63,7 @@ function getRelatedCollectionsFromExpandOption( .find((field) => field.name == expandItem); if (!relationField) throw new Error('relation_field_not_found'); - return getCollectionNameFromId(relationField.options.collectionId!); + return getCollectionNameFromId(relationField.collectionId); }); return [...inverseRelations, ...directRelations]; diff --git a/webapp/src/routes/my/+layout.svelte b/webapp/src/routes/my/+layout.svelte index 8264be3..3257273 100644 --- a/webapp/src/routes/my/+layout.svelte +++ b/webapp/src/routes/my/+layout.svelte @@ -1,10 +1,10 @@ -
+ {@render children?.()} From 309ef5095a10a06c92798e70e992b637a42e7733 Mon Sep 17 00:00:00 2001 From: FilippoTrotter Date: Wed, 8 Jan 2025 14:25:13 +0100 Subject: [PATCH 15/29] fix: collection name and error handling --- pocketbase/feature/feature.go | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/pocketbase/feature/feature.go b/pocketbase/feature/feature.go index 89e12f2..06e38ae 100644 --- a/pocketbase/feature/feature.go +++ b/pocketbase/feature/feature.go @@ -130,7 +130,14 @@ func fetchDict(env string) (map[string]interface{}, error) { func newConfig(app core.App, feature string) (map[string]string, error) { var envConfig map[string]string - record, err := app.FindFirstRecordByData("features", "name", feature) + record, err := app.FindFirstRecordByData("flags", "name", feature) + if err != nil { + return envConfig, err + } + if record == nil { + return envConfig, fmt.Errorf("record not found for flag: %s", feature) + } + envString, err := record.Get("envVariables").(types.JSONRaw).MarshalJSON() if err != nil { return envConfig, err From 1de19277fae0bb056c7ac2410f73961b66cde6f3 Mon Sep 17 00:00:00 2001 From: Giovanni Abbatepaolo <30571828+bbtgnn@users.noreply.github.com> Date: Wed, 8 Jan 2025 14:38:40 +0100 Subject: [PATCH 16/29] fix: changed features to flags --- pb_hooks/features.pb.js | 4 ++-- pocketbase/webauthn/webauthn.go | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/pb_hooks/features.pb.js b/pb_hooks/features.pb.js index c1e93cc..d9bdc3e 100644 --- a/pb_hooks/features.pb.js +++ b/pb_hooks/features.pb.js @@ -12,7 +12,7 @@ onRecordViewRequest((e) => { e.record?.set("envVariables", null); e.next(); -}, "features"); +}, "flags"); onRecordsListRequest((e) => { /** @type {Utils} */ @@ -25,4 +25,4 @@ onRecordsListRequest((e) => { }); e.next(); -}, "features"); +}, "flags"); diff --git a/pocketbase/webauthn/webauthn.go b/pocketbase/webauthn/webauthn.go index 65e1bcb..d80018a 100644 --- a/pocketbase/webauthn/webauthn.go +++ b/pocketbase/webauthn/webauthn.go @@ -91,7 +91,7 @@ func (u User) WebAuthnCredentials() []webauthn.Credential { } func NewWebAuthnFromEnv(app *pocketbase.PocketBase) (*webauthn.WebAuthn, error) { - record, err := app.FindFirstRecordByData("features", "name", "webauthn") + record, err := app.FindFirstRecordByData("flags", "name", "webauthn") if err != nil { return nil, err } From b83147e8387dbdb968b1de77b3995511a82137a8 Mon Sep 17 00:00:00 2001 From: Giovanni Abbatepaolo <30571828+bbtgnn@users.noreply.github.com> Date: Wed, 8 Jan 2025 15:10:52 +0100 Subject: [PATCH 17/29] Update settings.json --- .vscode/settings.json | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/.vscode/settings.json b/.vscode/settings.json index eda96dc..de9f20f 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -2,5 +2,13 @@ "tailwindCSS.classAttributes": ["class", "className", "contentClass"], "editor.quickSuggestions": { "strings": "on" + }, + "go.goroot": "/Users/giovanniabbatepaolo/.local/share/mise/installs/go/1.23.4", + "debug.javascript.defaultRuntimeExecutable": { + "pwa-node": "/Users/giovanniabbatepaolo/.local/share/mise/shims/node" + }, + "go.alternateTools": { + "go": "/Users/giovanniabbatepaolo/.local/share/mise/shims/go", + "dlv": "/Users/giovanniabbatepaolo/.local/share/mise/shims/dlv" } } From 1d2b3fab1cb3cbf48dce48728209fa422de82ff6 Mon Sep 17 00:00:00 2001 From: Puria Nafisi Azizi Date: Thu, 9 Jan 2025 09:41:33 +0100 Subject: [PATCH 18/29] fix: default ui on 5100, upgrade pocketbase --- go.mod | 38 ++++---- go.sum | 59 +++++++++++-- webapp/package.json | 200 +++++++++++++++++++++--------------------- webapp/vite.config.ts | 2 +- 4 files changed, 171 insertions(+), 128 deletions(-) diff --git a/go.mod b/go.mod index ca459d2..6e59769 100644 --- a/go.mod +++ b/go.mod @@ -6,8 +6,8 @@ require ( github.com/dyne/slangroom-exec/bindings/go v0.0.0-20241017085658-fb538b02efa3 github.com/go-webauthn/webauthn v0.10.2 github.com/pocketbase/dbx v1.11.0 - github.com/pocketbase/pocketbase v0.23.12 - golang.org/x/exp v0.0.0-20241217172543-b2144cdd0a67 + github.com/pocketbase/pocketbase v0.24.1 + golang.org/x/exp v0.0.0-20250106191152-7588d65b2ba8 ) require ( @@ -15,10 +15,10 @@ require ( github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 // indirect github.com/aws/aws-sdk-go-v2 v1.32.7 // indirect github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.7 // indirect - github.com/aws/aws-sdk-go-v2/config v1.28.7 // indirect - github.com/aws/aws-sdk-go-v2/credentials v1.17.48 // indirect + github.com/aws/aws-sdk-go-v2/config v1.28.8 // indirect + github.com/aws/aws-sdk-go-v2/credentials v1.17.49 // indirect github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.22 // indirect - github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.17.44 // indirect + github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.17.46 // indirect github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.26 // indirect github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.26 // indirect github.com/aws/aws-sdk-go-v2/internal/ini v1.8.1 // indirect @@ -27,10 +27,10 @@ require ( github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.4.7 // indirect github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.7 // indirect github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.18.7 // indirect - github.com/aws/aws-sdk-go-v2/service/s3 v1.71.1 // indirect + github.com/aws/aws-sdk-go-v2/service/s3 v1.72.1 // indirect github.com/aws/aws-sdk-go-v2/service/sso v1.24.8 // indirect github.com/aws/aws-sdk-go-v2/service/ssooidc v1.28.7 // indirect - github.com/aws/aws-sdk-go-v2/service/sts v1.33.3 // indirect + github.com/aws/aws-sdk-go-v2/service/sts v1.33.4 // indirect github.com/aws/smithy-go v1.22.1 // indirect github.com/disintegration/imaging v1.6.2 // indirect github.com/dlclark/regexp2 v1.11.4 // indirect @@ -42,7 +42,7 @@ require ( github.com/fatih/color v1.18.0 // indirect github.com/fsnotify/fsnotify v1.7.0 // indirect github.com/fxamacker/cbor/v2 v2.6.0 // indirect - github.com/gabriel-vasile/mimetype v1.4.7 // indirect + github.com/gabriel-vasile/mimetype v1.4.8 // indirect github.com/ganigeorgiev/fexpr v0.4.1 // indirect github.com/go-ozzo/ozzo-validation/v4 v4.3.0 // indirect github.com/go-sourcemap/sourcemap v2.1.4+incompatible // indirect @@ -69,23 +69,23 @@ require ( github.com/x448/float16 v0.8.4 // indirect go.opencensus.io v0.24.0 // indirect gocloud.dev v0.40.0 // indirect - golang.org/x/crypto v0.31.0 // indirect + golang.org/x/crypto v0.32.0 // indirect golang.org/x/image v0.23.0 // indirect - golang.org/x/net v0.33.0 // indirect - golang.org/x/oauth2 v0.24.0 // indirect + golang.org/x/net v0.34.0 // indirect + golang.org/x/oauth2 v0.25.0 // indirect golang.org/x/sync v0.10.0 // indirect - golang.org/x/sys v0.28.0 // indirect - golang.org/x/term v0.27.0 // indirect + golang.org/x/sys v0.29.0 // indirect + golang.org/x/term v0.28.0 // indirect golang.org/x/text v0.21.0 // indirect golang.org/x/xerrors v0.0.0-20240903120638-7835f813f4da // indirect - google.golang.org/api v0.214.0 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20241223144023-3abc09e42ca8 // indirect + google.golang.org/api v0.215.0 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20250106144421-5f5ef82da422 // indirect google.golang.org/grpc v1.69.2 // indirect - google.golang.org/protobuf v1.36.1 // indirect - modernc.org/gc/v3 v3.0.0-20241223112719-96e2e1e4408d // indirect - modernc.org/libc v1.61.5 // indirect + google.golang.org/protobuf v1.36.2 // indirect + modernc.org/gc/v3 v3.0.0-20250105121824-520be1a3aee6 // indirect + modernc.org/libc v1.61.7 // indirect modernc.org/mathutil v1.7.1 // indirect - modernc.org/memory v1.8.0 // indirect + modernc.org/memory v1.8.1 // indirect modernc.org/sqlite v1.34.4 // indirect modernc.org/strutil v1.2.1 // indirect modernc.org/token v1.1.0 // indirect diff --git a/go.sum b/go.sum index 8eefbc3..c6188d3 100644 --- a/go.sum +++ b/go.sum @@ -31,12 +31,18 @@ github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.7 h1:lL7IfaFzngfx0ZwU github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.7/go.mod h1:QraP0UcVlQJsmHfioCrveWOC1nbiWUl3ej08h4mXWoc= github.com/aws/aws-sdk-go-v2/config v1.28.7 h1:GduUnoTXlhkgnxTD93g1nv4tVPILbdNQOzav+Wpg7AE= github.com/aws/aws-sdk-go-v2/config v1.28.7/go.mod h1:vZGX6GVkIE8uECSUHB6MWAUsd4ZcG2Yq/dMa4refR3M= +github.com/aws/aws-sdk-go-v2/config v1.28.8 h1:4nUeC9TsZoHm9GHlQ5tnoIklNZgISXXVGPKP5/CS0fk= +github.com/aws/aws-sdk-go-v2/config v1.28.8/go.mod h1:2C+fhFxnx1ymomFjj5NBUc/vbjyIUR7mZ/iNRhhb7BU= github.com/aws/aws-sdk-go-v2/credentials v1.17.48 h1:IYdLD1qTJ0zanRavulofmqut4afs45mOWEI+MzZtTfQ= github.com/aws/aws-sdk-go-v2/credentials v1.17.48/go.mod h1:tOscxHN3CGmuX9idQ3+qbkzrjVIx32lqDSU1/0d/qXs= +github.com/aws/aws-sdk-go-v2/credentials v1.17.49 h1:+7u6eC8K6LLGQwWMYKHSsHAPQl+CGACQmnzd/EPMW0k= +github.com/aws/aws-sdk-go-v2/credentials v1.17.49/go.mod h1:0SgZcTAEIlKoYw9g+kuYUwbtUUVjfxnR03YkCOhMbQ0= github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.22 h1:kqOrpojG71DxJm/KDPO+Z/y1phm1JlC8/iT+5XRmAn8= github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.22/go.mod h1:NtSFajXVVL8TA2QNngagVZmUtXciyrHOt7xgz4faS/M= github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.17.44 h1:2zxMLXLedpB4K1ilbJFxtMKsVKaexOqDttOhc0QGm3Q= github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.17.44/go.mod h1:VuLHdqwjSvgftNC7yqPWyGVhEwPmJpeRi07gOgOfHF8= +github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.17.46 h1:03ylK6hyAhB9E6U2kWcBi9EIORe8vJGox1fi9DQ7tRQ= +github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.17.46/go.mod h1:XIZKyo7DYSsFXsFdrwRAYc3b1bHZpX2boIxXuJw9OS8= github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.26 h1:I/5wmGMffY4happ8NOCuIUEWGUvvFp5NSeQcXl9RHcI= github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.26/go.mod h1:FR8f4turZtNy6baO0KJ5FJUmXH/cSkI9fOngs0yl6mA= github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.26 h1:zXFLuEuMMUOvEARXFUVJdfqZ4bvvSgdGRq/ATcrQxzM= @@ -55,12 +61,16 @@ github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.18.7 h1:Hi0KGbrnr57bEH github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.18.7/go.mod h1:wKNgWgExdjjrm4qvfbTorkvocEstaoDl4WCvGfeCy9c= github.com/aws/aws-sdk-go-v2/service/s3 v1.71.1 h1:aOVVZJgWbaH+EJYPvEgkNhCEbXXvH7+oML36oaPK3zE= github.com/aws/aws-sdk-go-v2/service/s3 v1.71.1/go.mod h1:r+xl5yzMk9083rMR+sJ5TYj9Tihvf/l1oxzZXDgGj2Q= +github.com/aws/aws-sdk-go-v2/service/s3 v1.72.1 h1:+IrM0EXV6ozLqJs3Kq2iwQGJBWmgRiYBXWETQQUMZRY= +github.com/aws/aws-sdk-go-v2/service/s3 v1.72.1/go.mod h1:r+xl5yzMk9083rMR+sJ5TYj9Tihvf/l1oxzZXDgGj2Q= github.com/aws/aws-sdk-go-v2/service/sso v1.24.8 h1:CvuUmnXI7ebaUAhbJcDy9YQx8wHR69eZ9I7q5hszt/g= github.com/aws/aws-sdk-go-v2/service/sso v1.24.8/go.mod h1:XDeGv1opzwm8ubxddF0cgqkZWsyOtw4lr6dxwmb6YQg= github.com/aws/aws-sdk-go-v2/service/ssooidc v1.28.7 h1:F2rBfNAL5UyswqoeWv9zs74N/NanhK16ydHW1pahX6E= github.com/aws/aws-sdk-go-v2/service/ssooidc v1.28.7/go.mod h1:JfyQ0g2JG8+Krq0EuZNnRwX0mU0HrwY/tG6JNfcqh4k= github.com/aws/aws-sdk-go-v2/service/sts v1.33.3 h1:Xgv/hyNgvLda/M9l9qxXc4UFSgppnRczLxlMs5Ae/QY= github.com/aws/aws-sdk-go-v2/service/sts v1.33.3/go.mod h1:5Gn+d+VaaRgsjewpMvGazt0WfcFO+Md4wLOuBfGR9Bc= +github.com/aws/aws-sdk-go-v2/service/sts v1.33.4 h1:EzofOvWNMtG9ELt9mPOJjLYh1hz6kN4f5hNCyTtS7Hg= +github.com/aws/aws-sdk-go-v2/service/sts v1.33.4/go.mod h1:5Gn+d+VaaRgsjewpMvGazt0WfcFO+Md4wLOuBfGR9Bc= github.com/aws/smithy-go v1.22.1 h1:/HPHZQ0g7f4eUeK6HKglFz8uwVfZKgoI25rb/J+dnro= github.com/aws/smithy-go v1.22.1/go.mod h1:irrKGvNn1InZwb2d7fkIRNucdfwR8R+Ts3wxYa/cJHg= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= @@ -104,6 +114,8 @@ github.com/fxamacker/cbor/v2 v2.6.0 h1:sU6J2usfADwWlYDAFhZBQ6TnLFBHxgesMrQfQgk1t github.com/fxamacker/cbor/v2 v2.6.0/go.mod h1:pxXPTn3joSm21Gbwsv0w9OSA2y1HFR9qXEeXQVeNoDQ= github.com/gabriel-vasile/mimetype v1.4.7 h1:SKFKl7kD0RiPdbht0s7hFtjl489WcQ1VyPW8ZzUMYCA= github.com/gabriel-vasile/mimetype v1.4.7/go.mod h1:GDlAgAyIRT27BhFl53XNAFtfjzOkLaF35JdEG0P7LtU= +github.com/gabriel-vasile/mimetype v1.4.8 h1:FfZ3gj38NjllZIeJAmMhr+qKL8Wu+nOoI3GqacKw1NM= +github.com/gabriel-vasile/mimetype v1.4.8/go.mod h1:ByKUIKGjh1ODkGM1asKUbQZOLGrPjydw3hYPU2YU9t8= github.com/ganigeorgiev/fexpr v0.4.1 h1:hpUgbUEEWIZhSDBtf4M9aUNfQQ0BZkGRaMePy7Gcx5k= github.com/ganigeorgiev/fexpr v0.4.1/go.mod h1:RyGiGqmeXhEQ6+mlGdnUleLHgtzzu/VGO2WtJkF5drE= github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY= @@ -199,6 +211,8 @@ github.com/pocketbase/dbx v1.11.0 h1:LpZezioMfT3K4tLrqA55wWFw1EtH1pM4tzSVa7kgszU github.com/pocketbase/dbx v1.11.0/go.mod h1:xXRCIAKTHMgUCyCKZm55pUOdvFziJjQfXaWKhu2vhMs= github.com/pocketbase/pocketbase v0.23.12 h1:HB4THFbzaliF0C3wvpx+kNOZxIwCEMDqN3/17gn5N7E= github.com/pocketbase/pocketbase v0.23.12/go.mod h1:OcFJNMO0Vzt3f9+lweMbup6iL7V13ckxu1pdEY6FeM0= +github.com/pocketbase/pocketbase v0.24.1 h1:Hhx3L4eap7g3kyBQ8OuWneZo7mYu1lrMvqQpxjK+zcs= +github.com/pocketbase/pocketbase v0.24.1/go.mod h1:VVaUmgKgjCBW3s/ob2SSHuDNtTboTbwK/VyTUguTt3o= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE= github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= @@ -247,9 +261,13 @@ golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPh golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.31.0 h1:ihbySMvVjLAeSH1IbfcRTkD/iNscyz8rGzjF/E5hV6U= golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk= +golang.org/x/crypto v0.32.0 h1:euUpcYgM8WcP71gNpTqQCn6rC2t6ULUPiOzfWaXVVfc= +golang.org/x/crypto v0.32.0/go.mod h1:ZnnJkOaASj8g0AjIduWNlq2NRxL0PlBrbKVyZ6V/Ugc= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20241217172543-b2144cdd0a67 h1:1UoZQm6f0P/ZO0w1Ri+f+ifG/gXhegadRdwBIXEFWDo= golang.org/x/exp v0.0.0-20241217172543-b2144cdd0a67/go.mod h1:qj5a5QZpwLU2NLQudwIN5koi3beDhSAlJwa67PuM98c= +golang.org/x/exp v0.0.0-20250106191152-7588d65b2ba8 h1:yqrTHse8TCMW1M1ZCP+VAR/l0kKxwaAIqN/il7x4voA= +golang.org/x/exp v0.0.0-20250106191152-7588d65b2ba8/go.mod h1:tujkw807nyEEAamNbDrEGzRav+ilXA7PCRAd6xsmwiU= golang.org/x/image v0.0.0-20191009234506-e7c1f5e7dbb8/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/image v0.23.0 h1:HseQ7c2OpPKTPVzNjG5fwJsOTCiiwS4QdsYi5XU6H68= golang.org/x/image v0.23.0/go.mod h1:wJJBTdLfCCf3tiHa1fNxpZmUI4mmoZvwMCPP0ddoNKY= @@ -271,9 +289,13 @@ golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.33.0 h1:74SYHlV8BIgHIFC/LrYkOGIwL19eTYXQ5wc6TBuO36I= golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4= +golang.org/x/net v0.34.0 h1:Mb7Mrk043xzHgnRM88suvJFwzVrRfHEHJEl5/71CKw0= +golang.org/x/net v0.34.0/go.mod h1:di0qlW3YNM5oh6GqDGQr92MyTozJPmybPK4Ev/Gm31k= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.24.0 h1:KTBBxWqUa0ykRPLtV69rRto9TLXcqYkeswu48x/gvNE= golang.org/x/oauth2 v0.24.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= +golang.org/x/oauth2 v0.25.0 h1:CY4y7XT9v0cRI9oupztF8AgiIu99L/ksR/Xp/6jrZ70= +golang.org/x/oauth2 v0.25.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -293,10 +315,14 @@ golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA= golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.29.0 h1:TPYlXGxvx1MGTn2GiZDhnjPA9wZzZeGKHHmKhHYvgaU= +golang.org/x/sys v0.29.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.27.0 h1:WP60Sv1nlK1T6SupCHbXzSaN0b9wUmsPoRS9b61A23Q= golang.org/x/term v0.27.0/go.mod h1:iMsnZpn0cago0GOrHO2+Y7u7JPn5AylBrcoWkElMTSM= +golang.org/x/term v0.28.0 h1:/Ts8HFuMR2E6IP/jlo7QVLZHggjKQbhu/7H0LJFr3Gg= +golang.org/x/term v0.28.0/go.mod h1:Sw/lC2IAUZ92udQNf3WodGtn4k/XoLyZoh8v/8uiwek= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= @@ -321,6 +347,8 @@ golang.org/x/xerrors v0.0.0-20240903120638-7835f813f4da h1:noIWHXmPHxILtqtCOPIhS golang.org/x/xerrors v0.0.0-20240903120638-7835f813f4da/go.mod h1:NDW/Ps6MPRej6fsCIbMTohpP40sJ/P/vI1MoTEGwX90= google.golang.org/api v0.214.0 h1:h2Gkq07OYi6kusGOaT/9rnNljuXmqPnaig7WGPmKbwA= google.golang.org/api v0.214.0/go.mod h1:bYPpLG8AyeMWwDU6NXoB00xC0DFkikVvd5MfwoxjLqE= +google.golang.org/api v0.215.0 h1:jdYF4qnyczlEz2ReWIsosNLDuzXyvFHJtI5gcr0J7t0= +google.golang.org/api v0.215.0/go.mod h1:fta3CVtuJYOEdugLNWm6WodzOS8KdFckABwN4I40hzY= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= @@ -333,6 +361,8 @@ google.golang.org/genproto/googleapis/api v0.0.0-20241209162323-e6fa225c2576 h1: google.golang.org/genproto/googleapis/api v0.0.0-20241209162323-e6fa225c2576/go.mod h1:1R3kvZ1dtP3+4p4d3G8uJ8rFk/fWlScl38vanWACI08= google.golang.org/genproto/googleapis/rpc v0.0.0-20241223144023-3abc09e42ca8 h1:TqExAhdPaB60Ux47Cn0oLV07rGnxZzIsaRhQaqS666A= google.golang.org/genproto/googleapis/rpc v0.0.0-20241223144023-3abc09e42ca8/go.mod h1:lcTa1sDdWEIHMWlITnIczmw5w60CF9ffkb8Z+DVmmjA= +google.golang.org/genproto/googleapis/rpc v0.0.0-20250106144421-5f5ef82da422 h1:3UsHvIr4Wc2aW4brOaSCmcxh9ksica6fHEr8P1XhkYw= +google.golang.org/genproto/googleapis/rpc v0.0.0-20250106144421-5f5ef82da422/go.mod h1:3ENsm/5D1mzDyhpzeRi1NR784I0BcofWBoSc5QqqMK4= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= @@ -351,6 +381,8 @@ google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpAD google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= google.golang.org/protobuf v1.36.1 h1:yBPeRvTftaleIgM3PZ/WBIZ7XM/eEYAaEyCwvyjq/gk= google.golang.org/protobuf v1.36.1/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= +google.golang.org/protobuf v1.36.2 h1:R8FeyR1/eLmkutZOM5CWghmo5itiG9z0ktFlTVLuTmU= +google.golang.org/protobuf v1.36.2/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= @@ -360,26 +392,37 @@ gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -modernc.org/cc/v4 v4.24.1 h1:mLykA8iIlZ/SZbwI2JgYIURXQMSgmOb/+5jaielxPi4= -modernc.org/cc/v4 v4.24.1/go.mod h1:T1lKJZhXIi2VSqGBiB4LIbKs9NsKTbUXj4IDrmGqtTI= -modernc.org/ccgo/v4 v4.23.5 h1:6uAwu8u3pnla3l/+UVUrDDO1HIGxHTYmFH6w+X9nsyw= -modernc.org/ccgo/v4 v4.23.5/go.mod h1:FogrWfBdzqLWm1ku6cfr4IzEFouq2fSAPf6aSAHdAJQ= +modernc.org/cc/v4 v4.21.4 h1:3Be/Rdo1fpr8GrQ7IVw9OHtplU4gWbb+wNgeoBMmGLQ= +modernc.org/cc/v4 v4.21.4/go.mod h1:HM7VJTZbUCR3rV8EYBi9wxnJ0ZBRiGE5OeGXNA0IsLQ= +modernc.org/cc/v4 v4.24.4 h1:TFkx1s6dCkQpd6dKurBNmpo+G8Zl4Sq/ztJ+2+DEsh0= +modernc.org/ccgo/v4 v4.19.2 h1:lwQZgvboKD0jBwdaeVCTouxhxAyN6iawF3STraAal8Y= +modernc.org/ccgo/v4 v4.19.2/go.mod h1:ysS3mxiMV38XGRTTcgo0DQTeTmAO4oCmJl1nX9VFI3s= +modernc.org/ccgo/v4 v4.23.10 h1:DnDZT/H6TtoJvQmVf7d8W+lVqEZpIJY/+0ENFh1LIHE= modernc.org/fileutil v1.3.0 h1:gQ5SIzK3H9kdfai/5x41oQiKValumqNTDXMvKo62HvE= modernc.org/fileutil v1.3.0/go.mod h1:XatxS8fZi3pS8/hKG2GH/ArUogfxjpEKs3Ku3aK4JyQ= -modernc.org/gc/v2 v2.6.0 h1:Tiw3pezQj7PfV8k4Dzyu/vhRHR2e92kOXtTFU8pbCl4= -modernc.org/gc/v2 v2.6.0/go.mod h1:wzN5dK1AzVGoH6XOzc3YZ+ey/jPgYHLuVckd62P0GYU= +modernc.org/gc/v2 v2.4.1 h1:9cNzOqPyMJBvrUipmynX0ZohMhcxPtMccYgGOJdOiBw= +modernc.org/gc/v2 v2.4.1/go.mod h1:wzN5dK1AzVGoH6XOzc3YZ+ey/jPgYHLuVckd62P0GYU= +modernc.org/gc/v2 v2.6.1 h1:+Qf6xdG8l7B27TQ8D8lw/iFMUj1RXRBOuMUWziJOsk8= modernc.org/gc/v3 v3.0.0-20241223112719-96e2e1e4408d h1:d0JExN5U5FjUVHCP6L9DIlLJBZveR6KUM4AvfDUL3+k= modernc.org/gc/v3 v3.0.0-20241223112719-96e2e1e4408d/go.mod h1:qBSLm/exCqouT2hrfyTKikWKG9IPq8EoX5fS00l3jqk= -modernc.org/libc v1.61.5 h1:WzsPUvWl2CvsRmk2foyWWHUEUmQ2iW4oFyWOVR0O5ho= -modernc.org/libc v1.61.5/go.mod h1:llBdEGIywhnRgAFuTF+CWaKV8/2bFgACcQZTXhkAuAM= +modernc.org/gc/v3 v3.0.0-20250105121824-520be1a3aee6 h1:JoKwHjIFumiKrjMbp1cNbC5E9UyCgA/ZcID0xOWQ2N8= +modernc.org/gc/v3 v3.0.0-20250105121824-520be1a3aee6/go.mod h1:LG5UO1Ran4OO0JRKz2oNiXhR5nNrgz0PzH7UKhz0aMU= +modernc.org/libc v1.55.3 h1:AzcW1mhlPNrRtjS5sS+eW2ISCgSOLLNyFzRh/V3Qj/U= +modernc.org/libc v1.55.3/go.mod h1:qFXepLhz+JjFThQ4kzwzOjA/y/artDeg+pcYnY+Q83w= +modernc.org/libc v1.61.7 h1:exz8rasFniviSgh3dH7QBnQHqYh9lolA5hVYfsiwkfo= +modernc.org/libc v1.61.7/go.mod h1:xspSrXRNVSfWfcfqgvZDVe/Hw5kv4FVC6IRfoms5v/0= modernc.org/mathutil v1.7.1 h1:GCZVGXdaN8gTqB1Mf/usp1Y/hSqgI2vAGGP4jZMCxOU= modernc.org/mathutil v1.7.1/go.mod h1:4p5IwJITfppl0G4sUEDtCr4DthTaT47/N3aT6MhfgJg= modernc.org/memory v1.8.0 h1:IqGTL6eFMaDZZhEWwcREgeMXYwmW83LYW8cROZYkg+E= modernc.org/memory v1.8.0/go.mod h1:XPZ936zp5OMKGWPqbD3JShgd/ZoQ7899TUuQqxY+peU= +modernc.org/memory v1.8.1 h1:HS1HRg1jEohnuONobEq2WrLEhLyw8+J42yLFTnllm2A= +modernc.org/memory v1.8.1/go.mod h1:ZbjSvMO5NQ1A2i3bWeDiVMxIorXwdClKE/0SZ+BMotU= modernc.org/opt v0.1.3 h1:3XOZf2yznlhC+ibLltsDGzABUGVx8J6pnFMS3E4dcq4= modernc.org/opt v0.1.3/go.mod h1:WdSiB5evDcignE70guQKxYUl14mgWtbClRi5wmkkTX0= +modernc.org/opt v0.1.4 h1:2kNGMRiUjrp4LcaPuLY2PzUfqM/w9N23quVwhKt5Qm8= modernc.org/sortutil v1.2.0 h1:jQiD3PfS2REGJNzNCMMaLSp/wdMNieTbKX920Cqdgqc= modernc.org/sortutil v1.2.0/go.mod h1:TKU2s7kJMf1AE84OoiGppNHJwvB753OYfNl2WRb++Ss= +modernc.org/sortutil v1.2.1 h1:+xyoGf15mM3NMlPDnFqrteY07klSFxLElE2PVuWIJ7w= modernc.org/sqlite v1.34.4 h1:sjdARozcL5KJBvYQvLlZEmctRgW9xqIZc2ncN7PU0P8= modernc.org/sqlite v1.34.4/go.mod h1:3QQFCG2SEMtc2nv+Wq4cQCH7Hjcg+p/RMlS1XK+zwbk= modernc.org/strutil v1.2.1 h1:UneZBkQA+DX2Rp35KcM69cSsNES9ly8mQWD71HKlOA0= diff --git a/webapp/package.json b/webapp/package.json index a509c6f..60f8965 100644 --- a/webapp/package.json +++ b/webapp/package.json @@ -1,102 +1,102 @@ { - "name": "DIDimo - webapp", - "author": { - "name": "Forkbomb", - "email": "info@forkbomb.com" - }, - "description": "Your trustworthy compliance checker for decentralized identity solutions", - "version": "0.0.1", - "type": "module", - "engines": { - "node": ">=17", - "pnpm": ">=8" - }, - "scripts": { - "predev": "bun run generate:definitions", - "dev": "vite dev", - "prebuild": "bun run generate:definitions", - "build": "vite build", - "bin": "bun run build && bun build --compile --minify-whitespace --minify-syntax --target bun --outfile didimo-ui ./build/index.js", - "preview": "vite preview", - "check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json", - "check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch", - "format": "prettier --write .", - "lint": "prettier --check . && eslint .", - "test:unit": "vitest", - "test": "bun run test:unit -- --run && bun run test:e2e", - "test:e2e": "playwright test", - "test:e2e:ui": "playwright test --ui", - "serve": "bun run build && bun run preview --host", - "vite-run": "node ./vite-run.js", - "generate:collections-models": "bun run vite-run ./src/modules/pocketbase/collections-models/generate.collections-models.ts", - "generate:types": "bun x pocketbase-typegen --db ../pb_data/data.db --out src/modules/pocketbase/types/index.generated.ts && bun run generate:types-extra", - "generate:types-extra": "bun run vite-run src/modules/pocketbase/types/generate.types-extra.ts", - "generate:features": "bun run vite-run src/modules/features/generate.features-list.ts", - "generate:roles": "bun run vite-run ./src/modules/organizations/generate.roles-list.ts", - "generate:definitions": "bun run generate:collections-models && bun run generate:types && bun run generate:features && bun run generate:roles", - "i18n:remove-unused-strings": "bun run vite-run ./src/modules/i18n/remove-unused-strings.ts", - "i18n:lint": "bun run inlang lint --project ./project.inlang", - "i18n:lint:en": "bun run inlang lint --project ./project.inlang --languageTags en", - "emails": "rm -rf static/emails/* && mkdir -p static/emails && find ./ -name _components -prune -o -name '*.mjml' -exec sh -c 'mjml \"$1\" -o static/emails/$(basename \"${1%.mjml}.html\")' sh {} \\;", - "postemails": "node ./emails/_generateEmailList.mjs" - }, - "devDependencies": { - "@inlang/cli": "^2.18.1", - "@internationalized/date": "^3.6.0", - "@playwright/test": "^1.45.3", - "@sveltejs/kit": "^2.12.2", - "@sveltejs/vite-plugin-svelte": "^4.0.0", - "@tailwindcss/aspect-ratio": "^0.4.2", - "@tailwindcss/container-queries": "^0.1.1", - "@tailwindcss/forms": "^0.5.9", - "@tailwindcss/typography": "^0.5.15", - "@types/eslint": "^9.6.0", - "@types/lodash": "^4.17.13", - "autoprefixer": "^10.4.20", - "bits-ui": "^1.0.0-next.77", - "clsx": "^2.1.1", - "dotenv": "^16.4.5", - "eslint": "^9.7.0", - "eslint-config-prettier": "^9.1.0", - "eslint-plugin-svelte": "^2.36.0", - "formsnap": "^2.0.0", - "globals": "^15.0.0", - "json-to-ts": "^2.1.0", - "lucide-svelte": "^0.469.0", - "mode-watcher": "^0.5.0", - "paneforge": "^1.0.0-next.2", - "prettier": "^3.3.2", - "prettier-plugin-svelte": "^3.2.6", - "prettier-plugin-tailwindcss": "^0.6.5", - "svelte": "^5.16.6", - "svelte-adapter-bun": "^0.5.2", - "svelte-check": "^4.1.1", - "svelte-sonner": "^0.3.28", - "sveltekit-superforms": "^2.22.1", - "tailwind-merge": "^2.5.4", - "tailwind-variants": "^0.2.1", - "tailwindcss": "^3.4.9", - "tailwindcss-animate": "^1.0.7", - "typescript": "^5.0.0", - "typescript-eslint": "^8.0.0", - "vite": "^5.0.3", - "vite-node": "^2.1.4", - "vitest": "^2.0.4", - "zod": "^3.24.1" - }, - "dependencies": { - "@inlang/paraglide-sveltekit": "^0.15.0", - "@melt-ui/svelte": "^0.86.0", - "@types/node": "^22.10.2", - "date-fns": "^4.1.0", - "effect": "^3.10.12", - "lodash": "^4.17.21", - "mjml": "^4.15.3", - "nanoid": "^5.0.8", - "pocketbase": "0.25", - "runed": "^0.15.3", - "svelte-loading-spinners": "^0.3.6", - "type-fest": "^4.26.1", - "zenroom": "^4.45.3" - } + "name": "DIDimo - webapp", + "author": { + "name": "Forkbomb", + "email": "info@forkbomb.com" + }, + "description": "Your trustworthy compliance checker for decentralized identity solutions", + "version": "0.0.1", + "type": "module", + "engines": { + "node": ">=17", + "pnpm": ">=8" + }, + "scripts": { + "predev": "bun run generate:definitions", + "dev": "vite dev", + "prebuild": "bun run generate:definitions", + "build": "vite build", + "bin": "bun run build && bun build --compile --minify-whitespace --minify-syntax --target bun --outfile didimo-ui ./build/index.js", + "preview": "vite preview --port 5100", + "check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json", + "check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch", + "format": "prettier --write .", + "lint": "prettier --check . && eslint .", + "test:unit": "vitest", + "test": "bun run test:unit -- --run && bun run test:e2e", + "test:e2e": "playwright test", + "test:e2e:ui": "playwright test --ui", + "serve": "bun run build && bun run preview --host --port 5100", + "vite-run": "node ./vite-run.js", + "generate:collections-models": "bun run vite-run ./src/modules/pocketbase/collections-models/generate.collections-models.ts", + "generate:types": "bun x pocketbase-typegen --db ../pb_data/data.db --out src/modules/pocketbase/types/index.generated.ts && bun run generate:types-extra", + "generate:types-extra": "bun run vite-run src/modules/pocketbase/types/generate.types-extra.ts", + "generate:features": "bun run vite-run src/modules/features/generate.features-list.ts", + "generate:roles": "bun run vite-run ./src/modules/organizations/generate.roles-list.ts", + "generate:definitions": "bun run generate:collections-models && bun run generate:types && bun run generate:features && bun run generate:roles", + "i18n:remove-unused-strings": "bun run vite-run ./src/modules/i18n/remove-unused-strings.ts", + "i18n:lint": "bun run inlang lint --project ./project.inlang", + "i18n:lint:en": "bun run inlang lint --project ./project.inlang --languageTags en", + "emails": "rm -rf static/emails/* && mkdir -p static/emails && find ./ -name _components -prune -o -name '*.mjml' -exec sh -c 'mjml \"$1\" -o static/emails/$(basename \"${1%.mjml}.html\")' sh {} \\;", + "postemails": "node ./emails/_generateEmailList.mjs" + }, + "devDependencies": { + "@inlang/cli": "^2.18.1", + "@internationalized/date": "^3.6.0", + "@playwright/test": "^1.45.3", + "@sveltejs/kit": "^2.12.2", + "@sveltejs/vite-plugin-svelte": "^4.0.0", + "@tailwindcss/aspect-ratio": "^0.4.2", + "@tailwindcss/container-queries": "^0.1.1", + "@tailwindcss/forms": "^0.5.9", + "@tailwindcss/typography": "^0.5.15", + "@types/eslint": "^9.6.0", + "@types/lodash": "^4.17.13", + "autoprefixer": "^10.4.20", + "bits-ui": "^1.0.0-next.77", + "clsx": "^2.1.1", + "dotenv": "^16.4.5", + "eslint": "^9.7.0", + "eslint-config-prettier": "^9.1.0", + "eslint-plugin-svelte": "^2.36.0", + "formsnap": "^2.0.0", + "globals": "^15.0.0", + "json-to-ts": "^2.1.0", + "lucide-svelte": "^0.469.0", + "mode-watcher": "^0.5.0", + "paneforge": "^1.0.0-next.2", + "prettier": "^3.3.2", + "prettier-plugin-svelte": "^3.2.6", + "prettier-plugin-tailwindcss": "^0.6.5", + "svelte": "^5.16.6", + "svelte-adapter-bun": "^0.5.2", + "svelte-check": "^4.1.1", + "svelte-sonner": "^0.3.28", + "sveltekit-superforms": "^2.22.1", + "tailwind-merge": "^2.5.4", + "tailwind-variants": "^0.2.1", + "tailwindcss": "^3.4.9", + "tailwindcss-animate": "^1.0.7", + "typescript": "^5.0.0", + "typescript-eslint": "^8.0.0", + "vite": "^5.0.3", + "vite-node": "^2.1.4", + "vitest": "^2.0.4", + "zod": "^3.24.1" + }, + "dependencies": { + "@inlang/paraglide-sveltekit": "^0.15.0", + "@melt-ui/svelte": "^0.86.0", + "@types/node": "^22.10.2", + "date-fns": "^4.1.0", + "effect": "^3.10.12", + "lodash": "^4.17.21", + "mjml": "^4.15.3", + "nanoid": "^5.0.8", + "pocketbase": "0.25", + "runed": "^0.15.3", + "svelte-loading-spinners": "^0.3.6", + "type-fest": "^4.26.1", + "zenroom": "^4.45.3" + } } diff --git a/webapp/vite.config.ts b/webapp/vite.config.ts index 332220d..1d1fe7f 100644 --- a/webapp/vite.config.ts +++ b/webapp/vite.config.ts @@ -15,7 +15,7 @@ export default defineConfig({ include: ['src/**/*.{test,spec}.{js,ts}'] }, server: { - port: Number(process.env.PORT) || 5173, + port: Number(process.env.PORT) || 5100, open: `http://localhost:8090/` } }); From a76c0a783da48b89d7fba3d2c0f8899c3fa88080 Mon Sep 17 00:00:00 2001 From: Giovanni Abbatepaolo <30571828+bbtgnn@users.noreply.github.com> Date: Thu, 9 Jan 2025 10:09:50 +0100 Subject: [PATCH 19/29] Revert "Update settings.json" This reverts commit b83147e8387dbdb968b1de77b3995511a82137a8. --- .vscode/settings.json | 8 -------- 1 file changed, 8 deletions(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index de9f20f..eda96dc 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -2,13 +2,5 @@ "tailwindCSS.classAttributes": ["class", "className", "contentClass"], "editor.quickSuggestions": { "strings": "on" - }, - "go.goroot": "/Users/giovanniabbatepaolo/.local/share/mise/installs/go/1.23.4", - "debug.javascript.defaultRuntimeExecutable": { - "pwa-node": "/Users/giovanniabbatepaolo/.local/share/mise/shims/node" - }, - "go.alternateTools": { - "go": "/Users/giovanniabbatepaolo/.local/share/mise/shims/go", - "dlv": "/Users/giovanniabbatepaolo/.local/share/mise/shims/dlv" } } From c3a15b8d06bdfc8f2f4c77c41e7054d55cd4781f Mon Sep 17 00:00:00 2001 From: Giovanni Abbatepaolo <30571828+bbtgnn@users.noreply.github.com> Date: Thu, 9 Jan 2025 13:06:10 +0100 Subject: [PATCH 20/29] fix: update hooks --- cmd/didimo/didimo.go | 6 +- migrations/pb_schema.json | 6 +- pb_hooks/features.pb.js | 20 +- pb_hooks/oauth.pb.js | 21 +- pb_hooks/organizations.pb.js | 76 ++--- pb_hooks/organizations_authorizations.pb.js | 19 +- pb_hooks/organizations_invites.pb.js | 32 +- .../organizations_request_membership.pb.js | 320 ++++++++---------- ...d_flags.js => 1685000002_seed_features.js} | 14 +- pocketbase/feature/feature.go | 2 +- pocketbase/webauthn/webauthn.go | 8 +- webapp/src/modules/auth/oauth/oauth.svelte | 16 +- .../features/generate.features-list.ts | 2 +- webapp/src/modules/features/index.ts | 4 +- 14 files changed, 244 insertions(+), 302 deletions(-) rename pb_migrations/{1685000002_seed_flags.js => 1685000002_seed_features.js} (79%) diff --git a/cmd/didimo/didimo.go b/cmd/didimo/didimo.go index 2f25b65..b2fa8be 100644 --- a/cmd/didimo/didimo.go +++ b/cmd/didimo/didimo.go @@ -11,7 +11,6 @@ import ( _ "github.com/forkbombeu/didimo/migrations" "github.com/forkbombeu/didimo/pocketbase/did" "github.com/forkbombeu/didimo/pocketbase/feature" - "github.com/forkbombeu/didimo/pocketbase/hooks" "github.com/forkbombeu/didimo/pocketbase/webauthn" "github.com/forkbombeu/didimo/pocketbase/zencode" @@ -104,7 +103,10 @@ func main() { }) webauthn.Register(app) - hooks.Register(app) + + // ** BAD LINE ** + // hooks.Register(app) + jsvm.MustRegister(app, jsvm.Config{ HooksWatch: true, }) diff --git a/migrations/pb_schema.json b/migrations/pb_schema.json index 1745cdb..7ee5d82 100644 --- a/migrations/pb_schema.json +++ b/migrations/pb_schema.json @@ -341,7 +341,7 @@ "username": "username", "avatarURL": "" }, - "enabled": false + "enabled": true }, "passwordAuth": { "enabled": true, @@ -896,7 +896,7 @@ "createRule": null, "updateRule": null, "deleteRule": null, - "name": "flags", + "name": "features", "type": "base", "fields": [ { @@ -967,7 +967,7 @@ "type": "autodate" } ], - "indexes": ["CREATE UNIQUE INDEX `idx_T3xOIQy` ON `flags` (`name`)"], + "indexes": ["CREATE UNIQUE INDEX `idx_T3xOIQy` ON `features` (`name`)"], "system": true }, { diff --git a/pb_hooks/features.pb.js b/pb_hooks/features.pb.js index d9bdc3e..d425c3e 100644 --- a/pb_hooks/features.pb.js +++ b/pb_hooks/features.pb.js @@ -7,22 +7,22 @@ onRecordViewRequest((e) => { /** @type {Utils} */ const utils = require(`${__hooks}/utils.js`); - if (utils.isAdminContext(e)) return; - - e.record?.set("envVariables", null); + if (!utils.isAdminContext(e)) { + e.record?.set("envVariables", null); + } e.next(); -}, "flags"); +}, "features"); onRecordsListRequest((e) => { /** @type {Utils} */ const utils = require(`${__hooks}/utils.js`); - if (utils.isAdminContext(e)) return; - - e.records.forEach((r) => { - r?.set("envVariables", null); - }); + if (!utils.isAdminContext(e)) { + e.records.forEach((r) => { + r?.set("envVariables", null); + }); + } e.next(); -}, "flags"); +}, "features"); diff --git a/pb_hooks/oauth.pb.js b/pb_hooks/oauth.pb.js index 04532f6..5bdceb6 100644 --- a/pb_hooks/oauth.pb.js +++ b/pb_hooks/oauth.pb.js @@ -4,19 +4,20 @@ /** @typedef {import('./utils.js')} Utils */ /* Updating user info on first register */ + onRecordAuthWithOAuth2Request((e) => { e.next(); - if (!e.isNewRecord) return; - - /** @type {Utils} */ - const utils = require(`${__hooks}/utils.js`); + if (e.isNewRecord) { + /** @type {Utils} */ + const utils = require(`${__hooks}/utils.js`); - const { record: user, oAuth2User } = e; - if (!user || !oAuth2User) - throw utils.createMissingDataError("user", "oAuth2User"); + const { record: user, oAuth2User } = e; + if (!user || !oAuth2User) + throw utils.createMissingDataError("user", "oAuth2User"); - user.set("name", oAuth2User.name); - user.markAsNotNew(); - $app.Save(user); + user.set("name", oAuth2User.name); + user.markAsNotNew(); + $app.Save(user); + } }, "users"); diff --git a/pb_hooks/organizations.pb.js b/pb_hooks/organizations.pb.js index 91b042a..a3aa9d0 100644 --- a/pb_hooks/organizations.pb.js +++ b/pb_hooks/organizations.pb.js @@ -72,82 +72,62 @@ routerAdd("POST", "/organizations/verify-user-role", (e) => { /* Business logic hooks */ -// On Organization Create – Creating owner authorization - onRecordCreateRequest((e) => { - e.next(); - /** @type {Utils} */ const utils = require(`${__hooks}/utils.js`); /** @type {AuditLogger} */ const auditLogger = require(`${__hooks}/auditLogger.js`); - // Don't create orgAuthorization if organization is created from admin panel - if (utils.isAdminContext(e)) return; + // 0 - Backend logic - const userId = utils.getUserFromContext(e)?.id; - const organizationId = e.record?.id; - - const ownerRole = utils.getRoleByName("owner"); - const ownerRoleId = ownerRole?.id; + e.next(); - const collection = $app.findCollectionByNameOrId("orgAuthorizations"); - const record = new Record(collection, { - organization: organizationId, - role: ownerRoleId, - user: userId, - }); - $app.Save(record); + if (!e.record) throw utils.createMissingDataError("organization record"); - // + // 1 - Audit logging auditLogger(e).info( - "Created owner role for organization", + "Created organization", "organizationId", e.record?.id, "organizationName", - e.record?.get("name"), - "userId", - userId + e.record?.get("name") ); -}, "organizations"); -/* Audit hooks */ + if (!utils.isAdminContext(e)) return; -// Log organization creation + // 2 - Creating owner `orgAuthorization` for user that crated the org -onRecordCreateRequest((e) => { - e.next(); + const user = utils.getUserFromContext(e); + if (!user) throw utils.createMissingDataError("user creating organization"); - /** @type {AuditLogger} */ - const auditLogger = require(`${__hooks}/auditLogger.js`); + const organizationId = e.record.id; + const organizationName = e.record.getString("name"); + + const ownerRole = utils.getRoleByName("owner"); + const ownerRoleId = ownerRole?.id; + + const collection = $app.findCollectionByNameOrId("orgAuthorizations"); + const record = new Record(collection, { + organization: organizationId, + role: ownerRoleId, + user: user.id, + }); + $app.Save(record); auditLogger(e).info( - "Created organization", + "Created owner role for organization", "organizationId", e.record?.id, "organizationName", - e.record?.get("name") + organizationName, + "userId", + user.id ); -}, "organizations"); - -/* Email hooks */ - -// Send email after organization creation - -onRecordCreateRequest((e) => { - e.next(); - /** @type {Utils} */ - const utils = require(`${__hooks}/utils.js`); - - if (!e.record) throw utils.createMissingDataError("organization"); - - const user = utils.getUserFromContext(e); - if (!user) throw utils.createMissingDataError("user creating organization"); + // 3 - Finally, notifying user const userAddress = utils.getUserEmailAddressData(user); - const organizationName = e.record.get("name"); const emailData = utils.renderEmail("new-organization", { OrganizationName: organizationName, diff --git a/pb_hooks/organizations_authorizations.pb.js b/pb_hooks/organizations_authorizations.pb.js index 05caa2c..2734483 100644 --- a/pb_hooks/organizations_authorizations.pb.js +++ b/pb_hooks/organizations_authorizations.pb.js @@ -20,7 +20,7 @@ onRecordCreateRequest((e) => { /** @type {Utils} */ const utils = require(`${__hooks}/utils.js`); - if (utils.isAdminContext(e)) return; + if (utils.isAdminContext(e)) e.next(); const { isSelf, userRoleLevel } = utils.getUserContextInOrgAuthorizationHookEvent(e); @@ -54,7 +54,7 @@ onRecordUpdateRequest((e) => { /** @type {Utils} */ const utils = require(`${__hooks}/utils.js`); - if (utils.isAdminContext(e)) return; + if (utils.isAdminContext(e)) e.next(); const { isSelf, userRoleLevel: requestingUserRoleLevel } = utils.getUserContextInOrgAuthorizationHookEvent(e); @@ -103,13 +103,13 @@ onRecordDeleteRequest((e) => { /** @type {Utils} */ const utils = require(`${__hooks}/utils.js`); - if (utils.isAdminContext(e)) return; + if (utils.isAdminContext(e)) e.next(); const { isSelf, userRoleLevel: requestingUserRoleLevel } = utils.getUserContextInOrgAuthorizationHookEvent(e); // If user requests delete for itself, it's fine - if (isSelf) return; + if (isSelf) e.next(); // Getting role of authorization to delete @@ -136,7 +136,7 @@ onRecordDeleteRequest((e) => { /** @type {Utils} */ const utils = require(`${__hooks}/utils.js`); - if (utils.isAdminContext(e)) return; + if (utils.isAdminContext(e)) e.next(); if (e.record && utils.isLastOwnerAuthorization(e.record)) { throw new BadRequestError(utils.errors.cant_edit_last_owner_role); @@ -151,7 +151,7 @@ onRecordUpdateRequest((e) => { /** @type {Utils} */ const utils = require(`${__hooks}/utils.js`); - if (utils.isAdminContext(e)) return; + if (utils.isAdminContext(e)) e.next(); const originalRecord = e.record?.original(); // e.record is already the "modified" version, so it is not a "owner" role anymore @@ -175,7 +175,7 @@ onRecordCreateRequest((e) => { /** @type {Utils} */ const utils = require(`${__hooks}/utils.js`); - if (!e.record) return; + if (!e.record) throw utils.createMissingDataError("orgAuthorization"); const organization = utils.getExpanded(e.record, "organization"); const user = utils.getExpanded(e.record, "user"); @@ -207,7 +207,7 @@ onRecordUpdateRequest((e) => { /** @type {Utils} */ const utils = require(`${__hooks}/utils.js`); - if (!e.record) return; + if (!e.record) throw utils.createMissingDataError("orgAuthorization"); const organization = utils.getExpanded(e.record, "organization"); if (!organization) throw utils.createMissingDataError("organization"); @@ -272,7 +272,7 @@ onRecordDeleteRequest((e) => { /** @type {Utils} */ const utils = require(`${__hooks}/utils.js`); - if (!e.record) return; + if (!e.record) throw utils.createMissingDataError("orgAuthorization"); const record = e.record.original(); @@ -281,7 +281,6 @@ onRecordDeleteRequest((e) => { const user = utils.getExpanded(record, "user"); const role = utils.getExpanded(record, "role"); - if (!user) throw utils.createMissingDataError("user of orgAuthorization"); if (!role) throw utils.createMissingDataError("role of orgAuthorization"); diff --git a/pb_hooks/organizations_invites.pb.js b/pb_hooks/organizations_invites.pb.js index e9d4f62..f314550 100644 --- a/pb_hooks/organizations_invites.pb.js +++ b/pb_hooks/organizations_invites.pb.js @@ -29,6 +29,21 @@ onRecordCreateRequest((e) => { }); }, "users"); +onRecordDeleteRequest((e) => { + e.next(); + + /** @type {AuditLogger} */ + const auditLogger = require(`${__hooks}/auditLogger.js`); + + auditLogger(e).info( + "Deleted organization invite", + "inviteId", + e.record?.id, + "organizationId", + e.record?.get("organization") + ); +}); + /* Routes */ routerAdd("POST", "/organizations/invites/accept", (c) => { @@ -220,20 +235,3 @@ routerAdd("POST", "/organizations/invite", (c) => { } }); }); - -/* */ - -onRecordDeleteRequest((e) => { - e.next(); - - /** @type {AuditLogger} */ - const auditLogger = require(`${__hooks}/auditLogger.js`); - - auditLogger(e).info( - "Deleted organization invite", - "inviteId", - e.record?.id, - "organizationId", - e.record?.get("organization") - ); -}); diff --git a/pb_hooks/organizations_request_membership.pb.js b/pb_hooks/organizations_request_membership.pb.js index bc7ccce..8c7b1f7 100644 --- a/pb_hooks/organizations_request_membership.pb.js +++ b/pb_hooks/organizations_request_membership.pb.js @@ -4,31 +4,20 @@ /** @typedef {import('./utils.js')} Utils */ /** @typedef {import('./auditLogger.js')} AuditLogger */ -/** - * INDEX - * - Base hooks - * - Email hooks - */ - -/* Base hooks */ +/* CRUD hooks for orgJoinRequest */ onRecordCreateRequest((e) => { - e.record?.set("status", "pending"); - e.record?.set("reminders", 0); + /** @type {Utils} */ + const utils = require(`${__hooks}/utils.js`); - e.next(); -}, "orgJoinRequests"); + // 0 - Base check -// Cannot create join request if user is already member + if (!e.record) throw utils.createMissingDataError("orgJoinRequest"); -onRecordCreateRequest((e) => { - /** @type {Utils} */ - const utils = require(`${__hooks}/utils.js`); + // 1 – Check if a membership already exists for that user and org - /** @type {string | undefined} */ - const organizationId = e.record?.get("organization"); - /** @type {string | undefined} */ - const userId = e.record?.get("user"); + const organizationId = e.record.getString("organization"); + const userId = e.record.getString("user"); const authorization = utils.findFirstRecordByFilter( "orgAuthorizations", @@ -38,51 +27,29 @@ onRecordCreateRequest((e) => { if (authorization) throw new BadRequestError(utils.errors.user_is_already_member); - e.next(); -}, "orgJoinRequests"); - -// Create orgAuthorization after accepting membership request - -onRecordUpdateRequest((e) => { - e.next(); - - /** @type {Utils} */ - const utils = require(`${__hooks}/utils.js`); - - if (!e.record) throw utils.createMissingDataError("orgJoinRequest"); - - const status = e.record.get("status"); - if (status != "accepted") return; - - const orgAuthorizationsCollection = - $app.findCollectionByNameOrId("orgAuthorizations"); - if (!orgAuthorizationsCollection) - throw utils.createMissingDataError("orgAuthorizationsCollection"); + // 2 - Set default values for the record - const organizationId = e.record.get("organization"); - const userId = e.record.get("user"); - - const memberRole = utils.getRoleByName("member"); - const roleId = memberRole?.id; + e.record?.set("status", "pending"); + e.record?.set("reminders", 0); - const record = new Record(orgAuthorizationsCollection, { - user: userId, - organization: organizationId, - role: roleId, - }); + // 3 - Do the backend logic - $app.saveRecord(record); -}, "orgJoinRequests"); + e.next(); -/* Email hooks - Notifications to Admins */ + // 4 - Audit log the fact -onRecordCreateRequest((e) => { - e.next(); + /** @type {AuditLogger} */ + const auditLogger = require(`${__hooks}/auditLogger.js`); - /** @type {Utils} */ - const utils = require(`${__hooks}/utils.js`); + auditLogger(e).info( + "Created membership request", + "organizationId", + e.record?.get("organization"), + "requestId", + e.record?.id + ); - if (!e.record) throw utils.createMissingDataError("orgJoinRequest"); + // 5 - Notify the admins const organization = utils.getExpanded(e.record, "organization"); if (!organization) @@ -90,7 +57,6 @@ onRecordCreateRequest((e) => { const user = utils.getExpanded(e.record, "user"); if (!user) throw utils.createMissingDataError("user of orgJoinRequest"); - const organizationId = organization.id; const recipients = utils.getOrganizationAdminsAddresses(organizationId); for (const adminAddress of recipients) { @@ -113,6 +79,122 @@ onRecordCreateRequest((e) => { } }, "orgJoinRequests"); +// + +onRecordUpdateRequest((e) => { + // `orgJoinRequests` can be updated only by admins of the org + // This is expressed inside API rules + + e.next(); + + /** @type {Utils} */ + const utils = require(`${__hooks}/utils.js`); + + if (!e.record) throw utils.createMissingDataError("orgJoinRequest"); + + const status = e.record.getString("status"); + + // 0 - Audit log + + /** @type {AuditLogger} */ + const auditLogger = require(`${__hooks}/auditLogger.js`); + + auditLogger(e).info( + "Updated membership request", + "organizationId", + e.record.getString("organization"), + "status", + status, + "requestId", + e.record.id + ); + + // 1 - Create orgAuthorization after if membership request is accepted + + if (status == "accepted") { + const orgAuthorizationsCollection = + $app.findCollectionByNameOrId("orgAuthorizations"); + if (!orgAuthorizationsCollection) + throw utils.createMissingDataError("orgAuthorizationsCollection"); + + const organizationId = e.record.getString("organization"); + const userId = e.record.getString("user"); + + const memberRole = utils.getRoleByName("member"); + const roleId = memberRole?.id; + + const record = new Record(orgAuthorizationsCollection, { + user: userId, + organization: organizationId, + role: roleId, + }); + + $app.saveRecord(record); + } + + // 2 - Notifying user about the change + + if (status == "accepted" || status == "rejected") { + const organization = utils.getExpanded(e.record, "organization"); + if (!organization) + throw utils.createMissingDataError( + "organization of orgJoinRequest" + ); + const user = utils.getExpanded(e.record, "user"); + if (!user) throw utils.createMissingDataError("user of orgJoinRequest"); + + const OrganizationName = organization.getString("name"); + const userAddress = utils.getUserEmailAddressData(user); + + const successEmail = utils.renderEmail("membership-request-accepted", { + OrganizationName, + UserName: userAddress.name ?? "User", + DashboardLink: utils.getOrganizationPageUrl(organization.id), + AppName: utils.getAppName(), + }); + + const rejectEmail = utils.renderEmail("membership-request-declined", { + OrganizationName, + UserName: userAddress.name ?? "User", + DashboardLink: utils.getAppUrl() + "/my/organizations", + AppName: utils.getAppName(), + }); + + const emailContent = status == "accepted" ? successEmail : rejectEmail; + utils.sendEmail({ to: [userAddress], ...emailContent }); + } + + // 3 - Finally, deleting the record + + if (status == "accepted" || status == "rejected") { + $app.Delete(e.record); + } +}, "orgJoinRequests"); + +// + +onRecordDeleteRequest((e) => { + // `orgJoinRequests` can be deleted only by the creator of the request + // This is expressed inside API rules + + e.next(); + + /** @type {AuditLogger} */ + const auditLogger = require(`${__hooks}/auditLogger.js`); + + auditLogger(e).info( + "Deleted membership request", + "organizationId", + e.record?.getString("organization"), + "status", + e.record?.getString("status"), + "requestId", + e.record?.id + ); +}, "orgJoinRequests"); + +// + cronAdd("remind admins about join requests", "0 9 * * 1", () => { /** @type {Utils} */ const utils = require(`${__hooks}/utils.js`); @@ -160,125 +242,3 @@ cronAdd("remind admins about join requests", "0 9 * * 1", () => { } }); }); - -/* Email hooks - Notifications to Users */ - -onRecordUpdateRequest((e) => { - e.next(); - - /** @type {Utils} */ - const utils = require(`${__hooks}/utils.js`); - - if (!e.record) throw utils.createMissingDataError("orgJoinRequest"); - - /** @type {string} */ - const status = e.record.get("status"); - - const isRelevantChange = status == "accepted" || status == "rejected"; - if (!isRelevantChange) return; - - const organization = utils.getExpanded(e.record, "organization"); - if (!organization) - throw utils.createMissingDataError("organization of orgJoinRequest"); - const user = utils.getExpanded(e.record, "user"); - if (!user) throw utils.createMissingDataError("user of orgJoinRequest"); - - /** @type {string} */ - const OrganizationName = organization.get("name"); - const userAddress = utils.getUserEmailAddressData(user); - - /** - * @typedef {Object} EmailContent - * @property {string} subject - * @property {string} html - */ - - /** @type {EmailContent} */ - const successEmail = utils.renderEmail("membership-request-accepted", { - OrganizationName, - UserName: userAddress.name ?? "User", - DashboardLink: utils.getOrganizationPageUrl(organization.id), - AppName: utils.getAppName(), - }); - - /** @type {EmailContent} */ - const rejectEmail = utils.renderEmail("membership-request-declined", { - OrganizationName, - UserName: userAddress.name ?? "User", - DashboardLink: utils.getAppUrl() + "/my/organizations", - AppName: utils.getAppName(), - }); - - const emailContent = status == "accepted" ? successEmail : rejectEmail; - utils.sendEmail({ to: [userAddress], ...emailContent }); -}, "orgJoinRequests"); - -/* Audit logs */ - -onRecordCreateRequest((e) => { - e.next(); - - /** @type {AuditLogger} */ - const auditLogger = require(`${__hooks}/auditLogger.js`); - - auditLogger(e).info( - "Created membership request", - "organizationId", - e.record?.get("organization"), - "requestId", - e.record?.id - ); -}, "orgJoinRequests"); - -onRecordUpdateRequest((e) => { - e.next(); - - /** @type {AuditLogger} */ - const auditLogger = require(`${__hooks}/auditLogger.js`); - - auditLogger(e).info( - "Updated membership request", - "organizationId", - e.record?.get("organization"), - "status", - e.record?.get("status"), - "requestId", - e.record?.id - ); -}, "orgJoinRequests"); - -onRecordDeleteRequest((e) => { - e.next(); - - /** @type {AuditLogger} */ - const auditLogger = require(`${__hooks}/auditLogger.js`); - - auditLogger(e).info( - "Deleted membership request", - "organizationId", - e.record?.get("organization"), - "status", - e.record?.get("status"), - "requestId", - e.record?.id - ); -}, "orgJoinRequests"); - -/* IMPORTANT: This hook must be registered last */ - -onRecordUpdateRequest((e) => { - e.next(); - - /** @type {Utils} */ - const utils = require(`${__hooks}/utils.js`); - - if (!e.record) throw utils.createMissingDataError("orgJoinRequest"); - - /** @type {string} */ - const status = e.record.get("status"); - - const isRelevantChange = status == "accepted" || status == "rejected"; - if (!isRelevantChange) return; - - $app.Delete(e.record); -}, "orgJoinRequests"); diff --git a/pb_migrations/1685000002_seed_flags.js b/pb_migrations/1685000002_seed_features.js similarity index 79% rename from pb_migrations/1685000002_seed_flags.js rename to pb_migrations/1685000002_seed_features.js index 95ee23b..1760757 100644 --- a/pb_migrations/1685000002_seed_flags.js +++ b/pb_migrations/1685000002_seed_features.js @@ -2,7 +2,7 @@ /// /** @type {{name:string, envVariables?:Record, active?:boolean}[]} */ -const flags = [ +const features = [ { name: "keypairoom", envVariables: { @@ -45,15 +45,15 @@ const flags = [ // migrate((app) => { - const featuresCollection = app.findCollectionByNameOrId("flags"); + const featuresCollection = app.findCollectionByNameOrId("features"); - flags + features .map( - (flag) => + (feature) => new Record(featuresCollection, { - ...flag, - active: flag.active ?? true, + ...feature, + active: feature.active ?? true, }) ) - .forEach((flagRecord) => app.save(flagRecord)); + .forEach((featureRecord) => app.save(featureRecord)); }); diff --git a/pocketbase/feature/feature.go b/pocketbase/feature/feature.go index 06e38ae..69b6745 100644 --- a/pocketbase/feature/feature.go +++ b/pocketbase/feature/feature.go @@ -130,7 +130,7 @@ func fetchDict(env string) (map[string]interface{}, error) { func newConfig(app core.App, feature string) (map[string]string, error) { var envConfig map[string]string - record, err := app.FindFirstRecordByData("flags", "name", feature) + record, err := app.FindFirstRecordByData("features", "name", feature) if err != nil { return envConfig, err } diff --git a/pocketbase/webauthn/webauthn.go b/pocketbase/webauthn/webauthn.go index d80018a..1bd664e 100644 --- a/pocketbase/webauthn/webauthn.go +++ b/pocketbase/webauthn/webauthn.go @@ -91,7 +91,7 @@ func (u User) WebAuthnCredentials() []webauthn.Credential { } func NewWebAuthnFromEnv(app *pocketbase.PocketBase) (*webauthn.WebAuthn, error) { - record, err := app.FindFirstRecordByData("flags", "name", "webauthn") + record, err := app.FindFirstRecordByData("features", "name", "webauthn") if err != nil { return nil, err } @@ -268,7 +268,7 @@ func Register(app *pocketbase.PocketBase) error { return e.JSON(http.StatusOK, make(map[string]interface{})) }) - se.Router.GET("/api/webauthn/login/begin/:email", func(e *core.RequestEvent) error { + se.Router.GET("/api/webauthn/login/begin/:email", func(e *core.RequestEvent) error { w, err := NewWebAuthnFromEnv(app) if err != nil { return err @@ -297,8 +297,8 @@ func Register(app *pocketbase.PocketBase) error { return e.JSON(http.StatusOK, options) }) - - se.Router.POST("/api/webauthn/login/finish/:email", func(e *core.RequestEvent) error { + + se.Router.POST("/api/webauthn/login/finish/:email", func(e *core.RequestEvent) error { w, err := NewWebAuthnFromEnv(app) if err != nil { return err diff --git a/webapp/src/modules/auth/oauth/oauth.svelte b/webapp/src/modules/auth/oauth/oauth.svelte index 132c98f..87e2f8e 100644 --- a/webapp/src/modules/auth/oauth/oauth.svelte +++ b/webapp/src/modules/auth/oauth/oauth.svelte @@ -60,6 +60,14 @@ {m.Continue_with_oauthProvider({ oauthProvider: method.displayName })} {/each} + + {#if methods.length > 0 && !hideOr} +
+ +

{m.or()}

+ +
+ {/if} {/await} {#if error} @@ -75,11 +83,3 @@ {#if loading} {/if} - -{#if !hideOr} -
- -

{m.or()}

- -
-{/if} diff --git a/webapp/src/modules/features/generate.features-list.ts b/webapp/src/modules/features/generate.features-list.ts index 60b338b..193dfbf 100644 --- a/webapp/src/modules/features/generate.features-list.ts +++ b/webapp/src/modules/features/generate.features-list.ts @@ -8,7 +8,7 @@ const TYPE_NAME = 'Feature'; const OBJECT_NAME = `${TYPE_NAME}s`; const pb = await initAdminPocketbase(); -const featuresRecords = await pb.collection('flags').getFullList(); +const featuresRecords = await pb.collection('features').getFullList(); const featuresEntries = featuresRecords.map((f) => `${f.name.toUpperCase()}: '${f.name}'`); const code = ` diff --git a/webapp/src/modules/features/index.ts b/webapp/src/modules/features/index.ts index 96a31dc..91a2715 100644 --- a/webapp/src/modules/features/index.ts +++ b/webapp/src/modules/features/index.ts @@ -13,7 +13,7 @@ export type FeatureFlags = Record; export async function loadFeatureFlags(fetchFn = fetch): Promise { const flags: Partial = {}; - const list = await pb.collection('flags').getFullList({ requestKey: null, fetch: fetchFn }); + const list = await pb.collection('features').getFullList({ requestKey: null, fetch: fetchFn }); for (const [key, name] of Object.entries(Features)) { const feature = list.find((f) => f.name === name); @@ -24,4 +24,6 @@ export async function loadFeatureFlags(fetchFn = fetch): Promise { return flags as FeatureFlags; } +// + export * from './features-list.generated'; From 7a639a950344bc8a12cc5fa87f3fa883d510ac43 Mon Sep 17 00:00:00 2001 From: Giovanni Abbatepaolo <30571828+bbtgnn@users.noreply.github.com> Date: Thu, 9 Jan 2025 13:06:22 +0100 Subject: [PATCH 21/29] fix: collection form --- .../form/collectionForm.svelte | 5 +++-- webapp/src/modules/pocketbase/zod-schema/index.ts | 13 ++++++++----- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/webapp/src/modules/collections-components/form/collectionForm.svelte b/webapp/src/modules/collections-components/form/collectionForm.svelte index 9d5a11d..dc03839 100644 --- a/webapp/src/modules/collections-components/form/collectionForm.svelte +++ b/webapp/src/modules/collections-components/form/collectionForm.svelte @@ -16,6 +16,7 @@ type CollectionFormProps, type FieldsOptions } from './collectionFormTypes'; + import { getCollectionFields } from '@/pocketbase/zod-schema'; /* Props and unpacking */ @@ -52,8 +53,8 @@ /* Fields */ const fieldsConfigs = $derived( - getCollectionModel(collection) - .fields.sort(createFieldConfigSorter(fieldsOrder)) + getCollectionFields(collection) + .sort(createFieldConfigSorter(fieldsOrder)) .filter((config) => !excludeFields.includes(config.name)) ); diff --git a/webapp/src/modules/pocketbase/zod-schema/index.ts b/webapp/src/modules/pocketbase/zod-schema/index.ts index b1579d1..87f5330 100644 --- a/webapp/src/modules/pocketbase/zod-schema/index.ts +++ b/webapp/src/modules/pocketbase/zod-schema/index.ts @@ -13,14 +13,17 @@ import { systemFields, type CollectionZodRawShapes } from '../types'; export type CollectionZodSchema = z.ZodObject; -export function createCollectionZodSchema( - collection: C -): CollectionZodSchema { +export function getCollectionFields(collection: CollectionName) { const { fields } = getCollectionModel(collection); - const collectionFields = (fields as AnyCollectionField[]).filter( + return (fields as AnyCollectionField[]).filter( (f) => !(systemFields as unknown as string[]).includes(f.name) ); - console.log(collectionFields); +} + +export function createCollectionZodSchema( + collection: C +): CollectionZodSchema { + const collectionFields = getCollectionFields(collection); const entries = collectionFields.map((fieldConfig) => { const zodTypeConstructor = schemaFieldToZodTypeMap[fieldConfig.type] as ( From 3ecf660e2987d057b70715b89f44906e9df0d30d Mon Sep 17 00:00:00 2001 From: Giovanni Abbatepaolo <30571828+bbtgnn@users.noreply.github.com> Date: Thu, 9 Jan 2025 13:16:16 +0100 Subject: [PATCH 22/29] fix: organizations --- pb_hooks/organizations.pb.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pb_hooks/organizations.pb.js b/pb_hooks/organizations.pb.js index a3aa9d0..137de37 100644 --- a/pb_hooks/organizations.pb.js +++ b/pb_hooks/organizations.pb.js @@ -94,7 +94,7 @@ onRecordCreateRequest((e) => { e.record?.get("name") ); - if (!utils.isAdminContext(e)) return; + if (utils.isAdminContext(e)) e.next(); // 2 - Creating owner `orgAuthorization` for user that crated the org @@ -113,7 +113,7 @@ onRecordCreateRequest((e) => { role: ownerRoleId, user: user.id, }); - $app.Save(record); + $app.save(record); auditLogger(e).info( "Created owner role for organization", From e62101ba33d006d97de8cd05feb243c6f5def07c Mon Sep 17 00:00:00 2001 From: Giovanni Abbatepaolo <30571828+bbtgnn@users.noreply.github.com> Date: Thu, 9 Jan 2025 13:29:03 +0100 Subject: [PATCH 23/29] fix: migration stuff --- pb_hooks/oauth.pb.js | 2 +- pb_hooks/organizations_invites.pb.js | 23 +++++++++---------- .../organizations_request_membership.pb.js | 4 ++-- pb_hooks/utils.js | 3 +-- 4 files changed, 15 insertions(+), 17 deletions(-) diff --git a/pb_hooks/oauth.pb.js b/pb_hooks/oauth.pb.js index 5bdceb6..69d4c44 100644 --- a/pb_hooks/oauth.pb.js +++ b/pb_hooks/oauth.pb.js @@ -18,6 +18,6 @@ onRecordAuthWithOAuth2Request((e) => { user.set("name", oAuth2User.name); user.markAsNotNew(); - $app.Save(user); + $app.save(user); } }, "users"); diff --git a/pb_hooks/organizations_invites.pb.js b/pb_hooks/organizations_invites.pb.js index f314550..bcbc814 100644 --- a/pb_hooks/organizations_invites.pb.js +++ b/pb_hooks/organizations_invites.pb.js @@ -25,7 +25,7 @@ onRecordCreateRequest((e) => { invites.forEach((invite) => { invite.markAsNotNew(); invite.set("user", e.record?.id); - $app.Save(invite); + $app.save(invite); }); }, "users"); @@ -68,8 +68,8 @@ routerAdd("POST", "/organizations/invites/accept", (c) => { authorization.set("role", utils.getRoleByName("member")?.id); authorization.set("organization", organizationId); - $app.Save(authorization); - $app.Delete(invite); + $app.save(authorization); + $app.delete(invite); auditLogger(c).info( "user_accepted_invite", @@ -88,7 +88,7 @@ routerAdd("POST", "/organizations/invites/decline", (c) => { invite.markAsNotNew(); invite.set("declined", true); - $app.Save(invite); + $app.save(invite); auditLogger(c).info( "user_accepted_invite", @@ -99,7 +99,7 @@ routerAdd("POST", "/organizations/invites/decline", (c) => { // -routerAdd("POST", "/organizations/invite", (c) => { +routerAdd("POST", "/organizations/invite", (e) => { /** @type {Utils} */ const utils = require(`${__hooks}/utils.js`); /** @type {AuditLogger} */ @@ -109,12 +109,11 @@ routerAdd("POST", "/organizations/invite", (c) => { /** @type {{organizationId: string | undefined, emails: string[] | undefined}} */ // @ts-ignore - const data = $apis.requestInfo(c).data; - const { emails, organizationId } = data; + const { emails, organizationId } = e.requestInfo().body; if (!organizationId || !emails) throw utils.createMissingDataError("organizationId", "emails"); - const actor = utils.getUserFromContext(c); + const actor = utils.getUserFromContext(e); const actorId = actor?.id; const actorName = actor?.get("name"); if (!actorId) throw utils.createMissingDataError("userId"); @@ -164,7 +163,7 @@ routerAdd("POST", "/organizations/invite", (c) => { invite.set("organization", organizationId); invite.set("user_email", email); if (user) invite.set("user", user.id); - txApp.Save(invite); + txApp.save(invite); // Send email @@ -206,7 +205,7 @@ routerAdd("POST", "/organizations/invite", (c) => { }); if (!err) { - auditLogger(c).info( + auditLogger(e).info( "invited_person_to_organization", "organizationId", organizationId, @@ -218,9 +217,9 @@ routerAdd("POST", "/organizations/invite", (c) => { } else { invite.markAsNotNew(); invite.set("failed_email_send", true); - txApp.Save(invite); + txApp.save(invite); - auditLogger(c).info( + auditLogger(e).info( "failed_to_send_organization_invite", "organizationId", organizationId, diff --git a/pb_hooks/organizations_request_membership.pb.js b/pb_hooks/organizations_request_membership.pb.js index 8c7b1f7..51f424c 100644 --- a/pb_hooks/organizations_request_membership.pb.js +++ b/pb_hooks/organizations_request_membership.pb.js @@ -129,7 +129,7 @@ onRecordUpdateRequest((e) => { role: roleId, }); - $app.saveRecord(record); + $app.save(record); } // 2 - Notifying user about the change @@ -167,7 +167,7 @@ onRecordUpdateRequest((e) => { // 3 - Finally, deleting the record if (status == "accepted" || status == "rejected") { - $app.Delete(e.record); + $app.delete(e.record); } }, "orgJoinRequests"); diff --git a/pb_hooks/utils.js b/pb_hooks/utils.js index 8cb4bb5..ccbf4fc 100644 --- a/pb_hooks/utils.js +++ b/pb_hooks/utils.js @@ -277,8 +277,7 @@ function getOrganizationMembersPageUrl(organizationId) { function runOrganizationInviteEndpointChecks(e) { /** @type {{inviteId: string | undefined}} */ // @ts-ignore - const data = $apis.requestInfo(e).data; - const { inviteId } = data; + const { inviteId } = e.requestInfo().body; if (!inviteId || typeof inviteId != "string") throw createMissingDataError("inviteId"); From c653c68907226f64841e00039d8c3d46626b2a9e Mon Sep 17 00:00:00 2001 From: Giovanni Abbatepaolo <30571828+bbtgnn@users.noreply.github.com> Date: Thu, 9 Jan 2025 13:29:30 +0100 Subject: [PATCH 24/29] Update pb_schema.json --- migrations/pb_schema.json | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/migrations/pb_schema.json b/migrations/pb_schema.json index 7ee5d82..8c76ef5 100644 --- a/migrations/pb_schema.json +++ b/migrations/pb_schema.json @@ -1570,8 +1570,8 @@ }, { "id": "pbc_863811952", - "listRule": null, - "viewRule": null, + "listRule": "", + "viewRule": "", "createRule": null, "updateRule": null, "deleteRule": null, @@ -1730,8 +1730,8 @@ }, { "id": "pbc_3643163317", - "listRule": null, - "viewRule": null, + "listRule": "", + "viewRule": "", "createRule": null, "updateRule": null, "deleteRule": null, From 195c0fe1db1b2956ffdb778189f68231ad39cc0f Mon Sep 17 00:00:00 2001 From: Giovanni Abbatepaolo <30571828+bbtgnn@users.noreply.github.com> Date: Thu, 9 Jan 2025 15:36:36 +0100 Subject: [PATCH 25/29] small fixes --- .../components/ui-custom/userAvatar.svelte | 2 +- .../components/organizationAvatar.svelte | 2 +- .../src/routes/my/organizations/+page.svelte | 23 ++++++++++++++---- .../organizations/[id]/members/+page.svelte | 24 +++++++++++++------ 4 files changed, 37 insertions(+), 14 deletions(-) diff --git a/webapp/src/modules/components/ui-custom/userAvatar.svelte b/webapp/src/modules/components/ui-custom/userAvatar.svelte index 59fe0e1..22b01e0 100644 --- a/webapp/src/modules/components/ui-custom/userAvatar.svelte +++ b/webapp/src/modules/components/ui-custom/userAvatar.svelte @@ -10,7 +10,7 @@ let { user = pb.authStore.model as UsersResponse, ...rest }: Props = $props(); if (!user) throw new Error('missing user'); - const src = $derived(pb.files.getUrl(user, user.avatar)); + const src = $derived(pb.files.getURL(user, user.avatar)); const fallback = $derived(user.name.slice(0, 2)); diff --git a/webapp/src/modules/organizations/components/organizationAvatar.svelte b/webapp/src/modules/organizations/components/organizationAvatar.svelte index 93bfce0..ff8ee04 100644 --- a/webapp/src/modules/organizations/components/organizationAvatar.svelte +++ b/webapp/src/modules/organizations/components/organizationAvatar.svelte @@ -10,7 +10,7 @@ let { organization, ...rest }: Props = $props(); - let src = $derived(pb.files.getUrl(organization, organization.avatar ?? '')); + let src = $derived(pb.files.getURL(organization, organization.avatar ?? '')); let fallback = $derived(organization.name.slice(0, 2)); diff --git a/webapp/src/routes/my/organizations/+page.svelte b/webapp/src/routes/my/organizations/+page.svelte index e8f67dd..e12063f 100644 --- a/webapp/src/routes/my/organizations/+page.svelte +++ b/webapp/src/routes/my/organizations/+page.svelte @@ -71,10 +71,16 @@ {record.expand?.organization?.name} {#snippet right()} - - {/snippet} @@ -100,7 +106,7 @@ {#each records as request} {@const organization = request.expand?.organization} {#if organization} - {@const avatarUrl = pb.files.getUrl(organization, organization.avatar)} + {@const avatarUrl = pb.files.getURL(organization, organization.avatar)} {#snippet left()} @@ -135,7 +141,12 @@ {#snippet right()} - @@ -170,7 +181,9 @@
{org.name} {#if role.name == ADMIN || role.name == OWNER} - {capitalize(role.name)} + {capitalize(role.name)} {/if}
{#if org.description} diff --git a/webapp/src/routes/my/organizations/[id]/members/+page.svelte b/webapp/src/routes/my/organizations/[id]/members/+page.svelte index 742b6d1..288ec39 100644 --- a/webapp/src/routes/my/organizations/[id]/members/+page.svelte +++ b/webapp/src/routes/my/organizations/[id]/members/+page.svelte @@ -34,9 +34,6 @@ // const showInviteModal = createToggleStore(false); - $effect(() => { - console.log($showInviteModal); - }); @@ -105,18 +102,27 @@ {m.You()} {/if} {#if role.name != OrgRoles.MEMBER} - {capitalize(role.name)} + {capitalize(role.name)} {/if} {#snippet right()} - +
{#if userRole.level < role.level} {#snippet button({ triggerAttributes })} - @@ -125,7 +131,11 @@ {#snippet button({ triggerAttributes })} - From be9cc3a7889781f809bfb73ba192028a8818c9b5 Mon Sep 17 00:00:00 2001 From: Giovanni Abbatepaolo <30571828+bbtgnn@users.noreply.github.com> Date: Thu, 9 Jan 2025 15:39:49 +0100 Subject: [PATCH 26/29] update versions --- webapp/bun.lockb | Bin 293227 -> 293980 bytes webapp/package.json | 8 ++++---- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/webapp/bun.lockb b/webapp/bun.lockb index d41a9aeba8f7e7ae40baa2cb6f205c3881b38d5d..682c4974f88d54a117b44c0597afdfa5bce69a26 100755 GIT binary patch delta 1387 zcmb7@e@t6d6vyAa?-lz4*0r)x7(d$KHjq$S%2Iww+EI}Jfq`Z)#f@btKMb-gAa3BY zp<%E&vUU%+`iCMj8DLBddzu%+6wR38vYD1&EvOk#7Ez`qAd|sho?F!Tr{3iAzW1Da z?!D*UbKkiZRyLmwOQ+^NixvN+tZ>=3q@t|VRSlXcez##)bN&Atxy?T$w_zI+SS*qh;#_9c&URgNi)cb`Wa>~ zOp)+~U1nJeSO%~Hc=zjOnFv-gSRC&(m}S5HW4ZU4@t&*v&CfH0>_JO(&=91P0&y6& zSMsXVxJw_&&>Vk$HUr!IB6C23bS2EIjAqF&SkLfnvuRj)mp|{zKt;kgzBILN3(Svz z`#_+Pe`ypbZB&u4>;5rLPfvMAvKclFO1GT_rS0EJm+?u2RiFI7E*<~BmKIN{(9jKw zHZ#Uz+{hPhe$mr9{MMC~<@AuyCCiO_!F8uQ+;NVEf>LXXeE#dg6VAot)Lzq*-wt=p zZNHvk&ChzFW=ZV-m7MY*4O#Z0Tx2EZJgAr?dr=Vi#RHB^lHvu&JaxPS5u#-hH5>AJ zUQRDK7-9PGhsAtNX>;I0PVPZvM0rp5i!mQ`y;0L~d@*vj=f}oY=Cl5fM;?Zy7kirv zdVhcRkHNq%59p-b##i9R5VN7&fEyYmpUQAC8Y3z>$T+D2AsPh^BDdu@7kNmi0{mX_ zxB?F($96%P>BH*-r4N!`{ojxAXmyqTrP|GMtP`sZ??Fvsl?`8fla#5kQJ(Ck(F_yg zA=rhVA~qMkfbNKH7d|YJmv}Y@OMRqf7Vjjb6L>n67PA#{q{VgtZeRo$1;&7JU;^*} zUSJZK0=|=wdJn#@Q^K231CIm2z&1bwgaTnexY*`}EYURiWD@&Or1~%rBF>Ox zLVt}If5Op3yM(o5{}O(}KiMLlT*4s|6%7ss=s%DHY9ZY#xJyUf)HMj|cZ0&k``7j> zIr0D>BlGh(X(x@n4r61W6Tmp&1+v%R1MNUN`S}6f%|e$bSFt^OuRf8<2P+&Z*>U;( zkR#XFb5e9DNpH|6iH=nqg;|q6kz9R52mi)bTx)-!ga@omR#Ca!MhUA9MP47^nSj4ln{bXW*)sl;5 zE`WHR<`T$V8+VUHWph$;n0_9$vkFm{#qBVX!Vxx{5B&;8!- zdComK_j#W0SIsw<&3zSi*N5!v7mu8e*&Mg@XLeuijkWCh<%iEBWuMxW(F=u#-kuA} zOhlr;u>@AHj|H_BrN>gL4Rp12oNQw({F&vrYL+ z@&q%G8pE}PcUhEY?4{b9p@m~LAB2j+FWZmH;Z(V{PuZDvXvY|wopMF%RnN);O;Vq>3>OLbsA(sgs)i4I6)1)H) zt73g7Y|a|~=ay>H%*U^Ks_tO+LV4h7#8CEx@AexTufBNjQM~@sJI$u1ro+E4&+UwN zcSWjyJhJ*;yQBWQZK>Ne!>4}jcI{n1>}D6Y&peIuabAQ^CAg2*;!uJ&;$VUsaYH2P z@L-Y>-Xtadh;yGhlH}c$_?8}gd>XImp^?v^%|LPkUn9Yw0gO0rpyjw~zZFF zmb9kPpMeMQxj3Y1#3uL9?oN`1NRb#MhKMu7N5om;W8xEHm>40>aqLXM9h*4Bt;D@V zAyGu!N8C?5K$NK6Ng9(!adZ|kyg==rgLm`zlxj^w9oP4zH)l$%r`WU(CyJ-Z-XLa(I8m@p4~oHl z+?ItM=*>ba--DxBDCU*ww^=9wX-~ytxU>PsxI=yRPk7UhHGb)kI?*b1aJ9!TrFQXg z{7sRp+>5#aX)j%qeFKtJ|8u{TYwcCAc|h{yD} kryAs2_*JKzhf70}2`@FsrD*cW1?q%X-r-QoUzc~o--L@#w*UYD diff --git a/webapp/package.json b/webapp/package.json index 60f8965..c5b1828 100644 --- a/webapp/package.json +++ b/webapp/package.json @@ -44,8 +44,8 @@ "@inlang/cli": "^2.18.1", "@internationalized/date": "^3.6.0", "@playwright/test": "^1.45.3", - "@sveltejs/kit": "^2.12.2", - "@sveltejs/vite-plugin-svelte": "^4.0.0", + "@sveltejs/kit": "^2.15.2", + "@sveltejs/vite-plugin-svelte": "^4.0.4", "@tailwindcss/aspect-ratio": "^0.4.2", "@tailwindcss/container-queries": "^0.1.1", "@tailwindcss/forms": "^0.5.9", @@ -66,11 +66,11 @@ "mode-watcher": "^0.5.0", "paneforge": "^1.0.0-next.2", "prettier": "^3.3.2", - "prettier-plugin-svelte": "^3.2.6", + "prettier-plugin-svelte": "^3.3.2", "prettier-plugin-tailwindcss": "^0.6.5", "svelte": "^5.16.6", "svelte-adapter-bun": "^0.5.2", - "svelte-check": "^4.1.1", + "svelte-check": "^4.1.3", "svelte-sonner": "^0.3.28", "sveltekit-superforms": "^2.22.1", "tailwind-merge": "^2.5.4", From 0f73fc1d87104afd408bfc49a44e057034446011 Mon Sep 17 00:00:00 2001 From: Giovanni Abbatepaolo <30571828+bbtgnn@users.noreply.github.com> Date: Thu, 9 Jan 2025 15:45:17 +0100 Subject: [PATCH 27/29] feat: removed vite-run --- webapp/bun.lockb | Bin 293980 -> 293948 bytes webapp/package.json | 198 ++++++++++++++++++++++---------------------- webapp/vite-run.js | 52 ------------ 3 files changed, 98 insertions(+), 152 deletions(-) delete mode 100644 webapp/vite-run.js diff --git a/webapp/bun.lockb b/webapp/bun.lockb index 682c4974f88d54a117b44c0597afdfa5bce69a26..970b3b9fb365768b163a041de36aec9854ef5c06 100755 GIT binary patch delta 28414 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

3(C?m^Z&9lDpyu5WXz>bR2E8`w@c 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 delta 28417 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 a+`P;zQT4DERNVJzEi1qH?J8amj{h&IL1$Y4 diff --git a/webapp/package.json b/webapp/package.json index c5b1828..6a155d5 100644 --- a/webapp/package.json +++ b/webapp/package.json @@ -1,102 +1,100 @@ { - "name": "DIDimo - webapp", - "author": { - "name": "Forkbomb", - "email": "info@forkbomb.com" - }, - "description": "Your trustworthy compliance checker for decentralized identity solutions", - "version": "0.0.1", - "type": "module", - "engines": { - "node": ">=17", - "pnpm": ">=8" - }, - "scripts": { - "predev": "bun run generate:definitions", - "dev": "vite dev", - "prebuild": "bun run generate:definitions", - "build": "vite build", - "bin": "bun run build && bun build --compile --minify-whitespace --minify-syntax --target bun --outfile didimo-ui ./build/index.js", - "preview": "vite preview --port 5100", - "check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json", - "check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch", - "format": "prettier --write .", - "lint": "prettier --check . && eslint .", - "test:unit": "vitest", - "test": "bun run test:unit -- --run && bun run test:e2e", - "test:e2e": "playwright test", - "test:e2e:ui": "playwright test --ui", - "serve": "bun run build && bun run preview --host --port 5100", - "vite-run": "node ./vite-run.js", - "generate:collections-models": "bun run vite-run ./src/modules/pocketbase/collections-models/generate.collections-models.ts", - "generate:types": "bun x pocketbase-typegen --db ../pb_data/data.db --out src/modules/pocketbase/types/index.generated.ts && bun run generate:types-extra", - "generate:types-extra": "bun run vite-run src/modules/pocketbase/types/generate.types-extra.ts", - "generate:features": "bun run vite-run src/modules/features/generate.features-list.ts", - "generate:roles": "bun run vite-run ./src/modules/organizations/generate.roles-list.ts", - "generate:definitions": "bun run generate:collections-models && bun run generate:types && bun run generate:features && bun run generate:roles", - "i18n:remove-unused-strings": "bun run vite-run ./src/modules/i18n/remove-unused-strings.ts", - "i18n:lint": "bun run inlang lint --project ./project.inlang", - "i18n:lint:en": "bun run inlang lint --project ./project.inlang --languageTags en", - "emails": "rm -rf static/emails/* && mkdir -p static/emails && find ./ -name _components -prune -o -name '*.mjml' -exec sh -c 'mjml \"$1\" -o static/emails/$(basename \"${1%.mjml}.html\")' sh {} \\;", - "postemails": "node ./emails/_generateEmailList.mjs" - }, - "devDependencies": { - "@inlang/cli": "^2.18.1", - "@internationalized/date": "^3.6.0", - "@playwright/test": "^1.45.3", - "@sveltejs/kit": "^2.15.2", - "@sveltejs/vite-plugin-svelte": "^4.0.4", - "@tailwindcss/aspect-ratio": "^0.4.2", - "@tailwindcss/container-queries": "^0.1.1", - "@tailwindcss/forms": "^0.5.9", - "@tailwindcss/typography": "^0.5.15", - "@types/eslint": "^9.6.0", - "@types/lodash": "^4.17.13", - "autoprefixer": "^10.4.20", - "bits-ui": "^1.0.0-next.77", - "clsx": "^2.1.1", - "dotenv": "^16.4.5", - "eslint": "^9.7.0", - "eslint-config-prettier": "^9.1.0", - "eslint-plugin-svelte": "^2.36.0", - "formsnap": "^2.0.0", - "globals": "^15.0.0", - "json-to-ts": "^2.1.0", - "lucide-svelte": "^0.469.0", - "mode-watcher": "^0.5.0", - "paneforge": "^1.0.0-next.2", - "prettier": "^3.3.2", - "prettier-plugin-svelte": "^3.3.2", - "prettier-plugin-tailwindcss": "^0.6.5", - "svelte": "^5.16.6", - "svelte-adapter-bun": "^0.5.2", - "svelte-check": "^4.1.3", - "svelte-sonner": "^0.3.28", - "sveltekit-superforms": "^2.22.1", - "tailwind-merge": "^2.5.4", - "tailwind-variants": "^0.2.1", - "tailwindcss": "^3.4.9", - "tailwindcss-animate": "^1.0.7", - "typescript": "^5.0.0", - "typescript-eslint": "^8.0.0", - "vite": "^5.0.3", - "vite-node": "^2.1.4", - "vitest": "^2.0.4", - "zod": "^3.24.1" - }, - "dependencies": { - "@inlang/paraglide-sveltekit": "^0.15.0", - "@melt-ui/svelte": "^0.86.0", - "@types/node": "^22.10.2", - "date-fns": "^4.1.0", - "effect": "^3.10.12", - "lodash": "^4.17.21", - "mjml": "^4.15.3", - "nanoid": "^5.0.8", - "pocketbase": "0.25", - "runed": "^0.15.3", - "svelte-loading-spinners": "^0.3.6", - "type-fest": "^4.26.1", - "zenroom": "^4.45.3" - } + "name": "DIDimo - webapp", + "author": { + "name": "Forkbomb", + "email": "info@forkbomb.com" + }, + "description": "Your trustworthy compliance checker for decentralized identity solutions", + "version": "0.0.1", + "type": "module", + "engines": { + "node": ">=17", + "pnpm": ">=8" + }, + "scripts": { + "predev": "bun run generate:definitions", + "dev": "vite dev", + "prebuild": "bun run generate:definitions", + "build": "vite build", + "bin": "bun run build && bun build --compile --minify-whitespace --minify-syntax --target bun --outfile didimo-ui ./build/index.js", + "preview": "vite preview --port 5100", + "check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json", + "check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch", + "format": "prettier --write .", + "lint": "prettier --check . && eslint .", + "test:unit": "vitest", + "test": "bun run test:unit -- --run && bun run test:e2e", + "test:e2e": "playwright test", + "test:e2e:ui": "playwright test --ui", + "serve": "bun run build && bun run preview --host --port 5100", + "generate:collections-models": "bun run ./src/modules/pocketbase/collections-models/generate.collections-models.ts", + "generate:types": "bun x pocketbase-typegen --db ../pb_data/data.db --out src/modules/pocketbase/types/index.generated.ts && bun run generate:types-extra", + "generate:types-extra": "bun run src/modules/pocketbase/types/generate.types-extra.ts", + "generate:features": "bun run src/modules/features/generate.features-list.ts", + "generate:roles": "bun run ./src/modules/organizations/generate.roles-list.ts", + "generate:definitions": "bun run generate:collections-models && bun run generate:types && bun run generate:features && bun run generate:roles", + "i18n:remove-unused-strings": "bun run ./src/modules/i18n/remove-unused-strings.ts", + "i18n:lint": "bun run inlang lint --project ./project.inlang", + "i18n:lint:en": "bun run inlang lint --project ./project.inlang --languageTags en", + "emails": "rm -rf static/emails/* && mkdir -p static/emails && find ./ -name _components -prune -o -name '*.mjml' -exec sh -c 'mjml \"$1\" -o static/emails/$(basename \"${1%.mjml}.html\")' sh {} \\;", + "postemails": "node ./emails/_generateEmailList.mjs" + }, + "devDependencies": { + "@inlang/cli": "^2.18.1", + "@internationalized/date": "^3.6.0", + "@playwright/test": "^1.45.3", + "@sveltejs/kit": "^2.15.2", + "@sveltejs/vite-plugin-svelte": "^4.0.4", + "@tailwindcss/aspect-ratio": "^0.4.2", + "@tailwindcss/container-queries": "^0.1.1", + "@tailwindcss/forms": "^0.5.9", + "@tailwindcss/typography": "^0.5.15", + "@types/eslint": "^9.6.0", + "@types/lodash": "^4.17.13", + "autoprefixer": "^10.4.20", + "bits-ui": "^1.0.0-next.77", + "clsx": "^2.1.1", + "dotenv": "^16.4.5", + "eslint": "^9.7.0", + "eslint-config-prettier": "^9.1.0", + "eslint-plugin-svelte": "^2.36.0", + "formsnap": "^2.0.0", + "globals": "^15.0.0", + "json-to-ts": "^2.1.0", + "lucide-svelte": "^0.469.0", + "mode-watcher": "^0.5.0", + "paneforge": "^1.0.0-next.2", + "prettier": "^3.3.2", + "prettier-plugin-svelte": "^3.3.2", + "prettier-plugin-tailwindcss": "^0.6.5", + "svelte": "^5.16.6", + "svelte-adapter-bun": "^0.5.2", + "svelte-check": "^4.1.3", + "svelte-sonner": "^0.3.28", + "sveltekit-superforms": "^2.22.1", + "tailwind-merge": "^2.5.4", + "tailwind-variants": "^0.2.1", + "tailwindcss": "^3.4.9", + "tailwindcss-animate": "^1.0.7", + "typescript": "^5.0.0", + "typescript-eslint": "^8.0.0", + "vite": "^5.0.3", + "vitest": "^2.0.4", + "zod": "^3.24.1" + }, + "dependencies": { + "@inlang/paraglide-sveltekit": "^0.15.0", + "@melt-ui/svelte": "^0.86.0", + "@types/node": "^22.10.2", + "date-fns": "^4.1.0", + "effect": "^3.10.12", + "lodash": "^4.17.21", + "mjml": "^4.15.3", + "nanoid": "^5.0.8", + "pocketbase": "0.25", + "runed": "^0.15.3", + "svelte-loading-spinners": "^0.3.6", + "type-fest": "^4.26.1", + "zenroom": "^4.45.3" + } } diff --git a/webapp/vite-run.js b/webapp/vite-run.js deleted file mode 100644 index ad056a8..0000000 --- a/webapp/vite-run.js +++ /dev/null @@ -1,52 +0,0 @@ -import { createServer } from 'vite'; -import { ViteNodeRunner } from 'vite-node/client'; -import { fileURLToPath } from 'node:url'; -import path from 'node:path'; - -import config from './svelte.config.js'; - -// - -/** @param {string} script Path to the script to execute */ -async function run(script) { - const dirname = path.dirname(fileURLToPath(import.meta.url)); - const scriptPath = path.resolve(dirname, script); - - /** @type {import('vite').ViteDevServer} */ - let server; - - try { - server = await createServer({ - root: dirname, - resolve: { - alias: config.kit.alias - } - }); - - const runner = new ViteNodeRunner({ - root: server.config.root, - base: server.config.base, - fetchModule: (id) => server.ssrFetchModule(id) - }); - - await runner.executeFile(scriptPath); - } catch (error) { - console.error(`Error executing script: ${script}`); - console.error(error); - } finally { - if (server) await server.close(); - } -} - -// Get the script path from command line arguments -const scriptPath = process.argv[2]; - -if (!scriptPath) { - console.error('Please provide a script path as an argument'); - console.error('Usage: node script.js '); - process.exit(1); -} - -run(scriptPath).catch(() => { - process.exit(1); -}); From 007cd7b221fff0d6ef0042ca4fa56ca2038d7d96 Mon Sep 17 00:00:00 2001 From: Giovanni Abbatepaolo <30571828+bbtgnn@users.noreply.github.com> Date: Thu, 9 Jan 2025 15:58:24 +0100 Subject: [PATCH 28/29] Update Makefile --- Makefile | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) diff --git a/Makefile b/Makefile index ae31e09..95d5670 100644 --- a/Makefile +++ b/Makefile @@ -157,16 +157,4 @@ help: ## Show this help. @awk 'BEGIN {FS = ":.*?## "} { \ if (/^[a-zA-Z_-]+:.*?##.*$$/) {printf " ${YELLOW}%-20s${GREEN}%s${RESET}\n", $$1, $$2} \ else if (/^## .*$$/) {printf " ${CYAN}%s${RESET}\n", substr($$1,4)} \ - }' $(MAKEFILE_LIST) - -# - -DATA := $(ROOT_DIR)/pb_data - -purge: ## ⛔ Purge the database - @echo "⛔ Purge the database" - @rm -rf $(DATA) - -backend: - @echo "⚙️ Running backend" - @go run cmd/didimo/didimo.go serve \ No newline at end of file + }' $(MAKEFILE_LIST) \ No newline at end of file From ee088d17fdee7d4ee920f9403b14b055d9d58720 Mon Sep 17 00:00:00 2001 From: Giovanni Abbatepaolo <30571828+bbtgnn@users.noreply.github.com> Date: Thu, 9 Jan 2025 16:12:31 +0100 Subject: [PATCH 29/29] fix: merge main --- Makefile | 1 + pb_migrations/1685000002_seed_flags.js | 59 ------------------- .../features/generate.features-list.ts | 2 +- 3 files changed, 2 insertions(+), 60 deletions(-) delete mode 100644 pb_migrations/1685000002_seed_flags.js diff --git a/Makefile b/Makefile index 310941b..e723345 100644 --- a/Makefile +++ b/Makefile @@ -5,6 +5,7 @@ ROOT_DIR ?= $(shell dirname $(realpath $(firstword $(MAKEFILE_LIST)))) BINARY_NAME ?= $(PROJECT_NAME) SUBDIRS ?= ./... MAIN_SRC ?= $(ROOT_DIR)/cmd/didimo/didimo.go +DATA ?= $(ROOT_DIR)/pb_data WEBAPP ?= $(ROOT_DIR)/webapp GO_SRC := $(wildcard **/*.go) UI_SRC := $(shell find $(WEBAPP)/src -type f \( -name '*.svelte' -o -name '*.js' -o -name '*.ts' -o -name '*.css' \) ! -name '*.generated.ts' ! -path 'webapp/src/modules/i18n/paraglide/*') diff --git a/pb_migrations/1685000002_seed_flags.js b/pb_migrations/1685000002_seed_flags.js deleted file mode 100644 index 96ccebd..0000000 --- a/pb_migrations/1685000002_seed_flags.js +++ /dev/null @@ -1,59 +0,0 @@ -// @ts-check -/// - -/** @type {{name:string, envVariables?:Record, active?:boolean}[]} */ -const flags = [ - { - name: "keypairoom", - envVariables: { - SALT: "bWltbW8K", - }, - }, - { - name: "DID", - envVariables: { - DID_URL: "url", - DID_SPEC: "string", - DID_SIGNER_SPEC: "string", - DID_IDENTITY: "string", - DID_KEYRING: "json, currently passed base64 encoded", - }, - }, - { - name: "auth", - }, - { - name: "maintenance", - active: false, - }, - { - name: "organizations", - }, - { - name: "webauthn", - envVariables: { - DISPLAY_NAME: "DIDimo", - RPID: "localhost", - RPORIGINS: "http://localhost:5173", - }, - }, - { - name: "oauth", - }, -]; - -// - -migrate((app) => { - const featuresCollection = app.findCollectionByNameOrId("flags"); - - flags - .map( - (flag) => - new Record(featuresCollection, { - ...flag, - active: flag.active ?? true, - }), - ) - .forEach((flagRecord) => app.save(flagRecord)); -}); diff --git a/webapp/src/modules/features/generate.features-list.ts b/webapp/src/modules/features/generate.features-list.ts index 60b338b..193dfbf 100644 --- a/webapp/src/modules/features/generate.features-list.ts +++ b/webapp/src/modules/features/generate.features-list.ts @@ -8,7 +8,7 @@ const TYPE_NAME = 'Feature'; const OBJECT_NAME = `${TYPE_NAME}s`; const pb = await initAdminPocketbase(); -const featuresRecords = await pb.collection('flags').getFullList(); +const featuresRecords = await pb.collection('features').getFullList(); const featuresEntries = featuresRecords.map((f) => `${f.name.toUpperCase()}: '${f.name}'`); const code = `