@cosmicdrift/kumiko-bundled-features 0.14.0 → 0.16.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +2 -2
- package/src/__tests__/env-schemas.test.ts +1 -1
- package/src/__tests__/es-ops-e2e.integration.ts +10 -9
- package/src/audit/__tests__/audit.integration.ts +3 -3
- package/src/audit/handlers/list.query.ts +39 -51
- package/src/auth-email-password/__tests__/account-lockout-no-redis.integration.ts +4 -3
- package/src/auth-email-password/__tests__/account-lockout.integration.ts +4 -3
- package/src/auth-email-password/__tests__/auth-claims.integration.ts +5 -4
- package/src/auth-email-password/__tests__/auth.integration.ts +4 -3
- package/src/auth-email-password/__tests__/confirm-token-flow.test.ts +1 -1
- package/src/auth-email-password/__tests__/email-templates.test.ts +1 -1
- package/src/auth-email-password/__tests__/email-verification.integration.ts +7 -10
- package/src/auth-email-password/__tests__/identity-v3-hash.test.ts +1 -1
- package/src/auth-email-password/__tests__/identity-v3-login.integration.ts +4 -3
- package/src/auth-email-password/__tests__/invite-flow.integration.ts +16 -43
- package/src/auth-email-password/__tests__/multi-roles.integration.ts +6 -9
- package/src/auth-email-password/__tests__/password-reset.integration.ts +8 -7
- package/src/auth-email-password/__tests__/public-routes-rate-limit.integration.ts +4 -3
- package/src/auth-email-password/__tests__/seed-admin.integration.ts +19 -32
- package/src/auth-email-password/__tests__/session-callbacks.integration.ts +6 -5
- package/src/auth-email-password/__tests__/session-strict-mode.integration.ts +1 -1
- package/src/auth-email-password/__tests__/signed-token.test.ts +1 -1
- package/src/auth-email-password/__tests__/signup-flow.integration.ts +11 -15
- package/src/auth-email-password/handlers/invite-accept-with-login.write.ts +26 -26
- package/src/auth-email-password/handlers/invite-accept.write.ts +24 -21
- package/src/auth-email-password/handlers/invite-create.write.ts +3 -8
- package/src/auth-email-password/handlers/invite-signup-complete.write.ts +20 -17
- package/src/auth-email-password/handlers/signup-confirm.write.ts +3 -7
- package/src/auth-email-password/seeding.ts +1 -1
- package/src/auth-email-password/web/__tests__/auth-gate.test.tsx +1 -2
- package/src/auth-email-password/web/__tests__/forgot-password-screen.test.tsx +10 -19
- package/src/auth-email-password/web/__tests__/login-screen.test.tsx +12 -18
- package/src/auth-email-password/web/__tests__/reset-password-screen.test.tsx +12 -17
- package/src/auth-email-password/web/__tests__/session-roles.test.ts +1 -1
- package/src/auth-email-password/web/__tests__/tenant-switcher.test.tsx +1 -8
- package/src/auth-email-password/web/__tests__/test-utils.tsx +4 -8
- package/src/auth-email-password/web/__tests__/user-menu.test.tsx +2 -8
- package/src/auth-email-password/web/__tests__/verify-email-screen.test.tsx +10 -15
- package/src/billing-foundation/__tests__/billing-foundation.integration.ts +1 -1
- package/src/billing-foundation/__tests__/feature.test.ts +1 -1
- package/src/billing-foundation/__tests__/webhook-handler.test.ts +6 -5
- package/src/billing-foundation/db/queries/subscription-projection.ts +15 -0
- package/src/billing-foundation/get-subscription-for-tenant.ts +2 -6
- package/src/billing-foundation/handlers/create-portal-session.write.ts +2 -2
- package/src/billing-foundation/handlers/list-subscriptions.query.ts +4 -1
- package/src/billing-foundation/projection.ts +32 -13
- package/src/cap-counter/__tests__/cap-counter.integration.ts +1 -1
- package/src/cap-counter/__tests__/enforce-cap.test.ts +37 -32
- package/src/cap-counter/__tests__/with-cap-enforcement.integration.ts +1 -1
- package/src/cap-counter/enforce-cap.ts +14 -20
- package/src/cap-counter/handlers/get-counter.query.ts +7 -13
- package/src/cap-counter/handlers/increment.write.ts +2 -2
- package/src/cap-counter/handlers/mark-soft-warned.write.ts +2 -2
- package/src/channel-in-app/handlers/inbox.query.ts +7 -13
- package/src/channel-in-app/handlers/mark-all-read.write.ts +7 -9
- package/src/channel-in-app/handlers/mark-read.write.ts +8 -14
- package/src/channel-in-app/handlers/unread-count.query.ts +10 -9
- package/src/channel-in-app/in-app-channel.ts +10 -12
- package/src/channel-in-app/tables.ts +1 -1
- package/src/compliance-profiles/__tests__/compliance-profiles.integration.ts +1 -1
- package/src/compliance-profiles/__tests__/seeding.integration.ts +1 -1
- package/src/compliance-profiles/_internal/parse-override.ts +19 -0
- package/src/compliance-profiles/handlers/for-tenant.query.ts +10 -32
- package/src/compliance-profiles/handlers/needs-profile.query.ts +4 -7
- package/src/compliance-profiles/handlers/set-profile.write.ts +5 -7
- package/src/compliance-profiles/resolve-for-tenant.ts +11 -27
- package/src/compliance-profiles/schema/profile-selection.ts +2 -2
- package/src/compliance-profiles/seeding.ts +4 -7
- package/src/config/__tests__/app-overrides.test.ts +1 -1
- package/src/config/__tests__/cascade.integration.ts +1 -1
- package/src/config/__tests__/config.integration.ts +8 -27
- package/src/config/db/queries/resolver.ts +47 -0
- package/src/config/handlers/__tests__/prepare-config-write.test.ts +1 -1
- package/src/config/resolver.ts +14 -62
- package/src/config/table.ts +4 -4
- package/src/config/write-helpers.ts +7 -11
- package/src/custom-fields/__tests__/audit-integration.integration.ts +6 -6
- package/src/custom-fields/__tests__/custom-fields.integration.ts +7 -7
- package/src/custom-fields/__tests__/feature.test.ts +1 -1
- package/src/custom-fields/__tests__/field-access.integration.ts +6 -6
- package/src/custom-fields/__tests__/quota.integration.ts +6 -6
- package/src/custom-fields/__tests__/retention.integration.ts +12 -10
- package/src/custom-fields/__tests__/user-data-rights.integration.ts +27 -17
- package/src/custom-fields/__tests__/wire-for-entity.test.ts +5 -5
- package/src/custom-fields/db/queries/field-access.ts +16 -0
- package/src/custom-fields/db/queries/projection.ts +43 -0
- package/src/custom-fields/db/queries/quota.ts +14 -0
- package/src/custom-fields/db/queries/retention.ts +39 -0
- package/src/custom-fields/db/queries/user-data-rights.ts +54 -0
- package/src/custom-fields/lib/field-access.ts +2 -41
- package/src/custom-fields/lib/quota.ts +2 -25
- package/src/custom-fields/run-retention.ts +19 -21
- package/src/custom-fields/wire-for-entity.ts +30 -23
- package/src/custom-fields/wire-user-data-rights.ts +33 -85
- package/src/data-retention/__tests__/data-retention.integration.ts +1 -1
- package/src/data-retention/__tests__/keep-for.test.ts +1 -1
- package/src/data-retention/__tests__/override-schema.test.ts +1 -1
- package/src/data-retention/__tests__/policy-for.integration.ts +1 -1
- package/src/data-retention/__tests__/resolver.test.ts +1 -1
- package/src/data-retention/handlers/policy-for.query.ts +5 -8
- package/src/data-retention/resolve-for-tenant.ts +6 -8
- package/src/data-retention/schema/tenant-retention-override.ts +2 -2
- package/src/delivery/__tests__/delivery-events.integration.ts +8 -21
- package/src/delivery/__tests__/delivery.integration.ts +100 -190
- package/src/delivery/db/queries/preferences.ts +30 -0
- package/src/delivery/delivery-service.ts +8 -36
- package/src/delivery/feature.ts +10 -2
- package/src/delivery/handlers/log.query.ts +5 -7
- package/src/delivery/handlers/preferences.query.ts +2 -5
- package/src/delivery/tables.ts +26 -1
- package/src/delivery/upsert-preference.ts +8 -14
- package/src/feature-toggles/__tests__/feature-toggles.integration.ts +30 -30
- package/src/feature-toggles/__tests__/registered-system-tenant.test.ts +7 -6
- package/src/feature-toggles/db/queries/toggle-state.ts +25 -0
- package/src/feature-toggles/feature.ts +16 -2
- package/src/feature-toggles/global-feature-state-table.ts +1 -1
- package/src/feature-toggles/handlers/list.query.ts +9 -2
- package/src/feature-toggles/handlers/registered.query.ts +3 -7
- package/src/feature-toggles/handlers/set.write.ts +37 -25
- package/src/feature-toggles/toggle-runtime.ts +3 -6
- package/src/file-foundation/__tests__/feature.test.ts +1 -1
- package/src/file-foundation/__tests__/file-foundation.integration.ts +1 -1
- package/src/file-provider-inmemory/__tests__/feature.test.ts +1 -1
- package/src/file-provider-s3/__tests__/feature.test.ts +1 -1
- package/src/files/__tests__/files.integration.ts +18 -7
- package/src/files/schema/file-ref.ts +1 -1
- package/src/files-provider-s3/__tests__/env-helper.test.ts +1 -1
- package/src/files-provider-s3/__tests__/s3-provider.integration.ts +1 -1
- package/src/files-provider-s3/__tests__/s3-provider.test.ts +1 -1
- package/src/jobs/__tests__/job-system-user.integration.ts +1 -1
- package/src/jobs/__tests__/jobs-events.integration.ts +8 -21
- package/src/jobs/__tests__/jobs-feature.integration.ts +1 -1
- package/src/jobs/feature.ts +26 -15
- package/src/jobs/handlers/detail.query.ts +10 -8
- package/src/jobs/handlers/list.query.ts +9 -21
- package/src/jobs/handlers/retry.write.ts +2 -7
- package/src/jobs/job-run-logger.ts +3 -9
- package/src/jobs/job-run-table.ts +49 -17
- package/src/legal-pages/__tests__/legal-pages.integration.ts +1 -1
- package/src/mail-foundation/__tests__/feature.test.ts +1 -1
- package/src/mail-foundation/__tests__/mail-foundation.integration.ts +1 -1
- package/src/mail-transport-inmemory/__tests__/feature.test.ts +1 -1
- package/src/mail-transport-smtp/__tests__/feature.test.ts +1 -1
- package/src/rate-limiting/__tests__/rate-limiting.integration.ts +1 -1
- package/src/renderer-foundation/__tests__/api.test.ts +2 -2
- package/src/renderer-foundation/__tests__/collect-plugins.integration.ts +1 -1
- package/src/renderer-simple/__tests__/adapter.test.ts +2 -2
- package/src/renderer-simple/__tests__/simple-renderer.test.ts +1 -1
- package/src/secrets/__tests__/require-secrets-context.test.ts +6 -5
- package/src/secrets/__tests__/rotate.integration.ts +6 -9
- package/src/secrets/__tests__/secrets-events.integration.ts +6 -12
- package/src/secrets/__tests__/secrets.integration.ts +6 -11
- package/src/secrets/db/queries/read.ts +16 -0
- package/src/secrets/handlers/list.query.ts +16 -17
- package/src/secrets/handlers/rotate.job.ts +8 -12
- package/src/secrets/secrets-context.ts +9 -21
- package/src/secrets/table.ts +1 -1
- package/src/sessions/__tests__/cleanup.integration.ts +8 -6
- package/src/sessions/__tests__/password-auto-revoke.integration.ts +7 -6
- package/src/sessions/__tests__/sessions.integration.ts +23 -38
- package/src/sessions/__tests__/test-helpers.ts +1 -1
- package/src/sessions/db/queries/cleanup.ts +21 -0
- package/src/sessions/handlers/cleanup.job.ts +6 -29
- package/src/sessions/handlers/list.query.ts +24 -24
- package/src/sessions/handlers/mine.query.ts +24 -23
- package/src/sessions/handlers/revoke-all-for-user.write.ts +7 -11
- package/src/sessions/handlers/revoke-all-others.write.ts +7 -12
- package/src/sessions/handlers/revoke.write.ts +11 -18
- package/src/sessions/schema/user-session.ts +2 -2
- package/src/sessions/session-callbacks.ts +19 -21
- package/src/subscription-mollie/__tests__/feature.test.ts +1 -1
- package/src/subscription-mollie/__tests__/mollie-foundation.integration.ts +1 -1
- package/src/subscription-mollie/__tests__/verify-webhook.test.ts +8 -7
- package/src/subscription-stripe/__tests__/feature.test.ts +1 -1
- package/src/subscription-stripe/__tests__/plugin-methods.test.ts +14 -15
- package/src/subscription-stripe/__tests__/stripe-foundation.integration.ts +1 -1
- package/src/subscription-stripe/__tests__/verify-webhook.test.ts +14 -14
- package/src/subscription-stripe/verify-webhook.ts +1 -1
- package/src/template-resolver/__tests__/handlers.integration.ts +1 -1
- package/src/template-resolver/__tests__/template-resolver.integration.ts +3 -2
- package/src/template-resolver/api.ts +7 -13
- package/src/template-resolver/handlers/archive.write.ts +4 -7
- package/src/template-resolver/handlers/find-by-id.query.ts +4 -7
- package/src/template-resolver/handlers/list.query.ts +13 -21
- package/src/template-resolver/handlers/publish.write.ts +4 -7
- package/src/template-resolver/handlers/upsert-system.write.ts +7 -10
- package/src/template-resolver/handlers/upsert-tenant.write.ts +7 -10
- package/src/template-resolver/table.ts +2 -5
- package/src/tenant/__tests__/multi-tenant.integration.ts +1 -1
- package/src/tenant/__tests__/seed-testing.integration.ts +19 -45
- package/src/tenant/__tests__/tenant.integration.ts +1 -1
- package/src/tenant/handlers/active-tenant-ids.query.ts +3 -8
- package/src/tenant/handlers/add-member.write.ts +6 -8
- package/src/tenant/handlers/cancel-invitation.write.ts +5 -7
- package/src/tenant/handlers/invitations.query.ts +5 -10
- package/src/tenant/handlers/me.query.ts +2 -3
- package/src/tenant/handlers/members.query.ts +4 -5
- package/src/tenant/handlers/memberships.query.ts +2 -5
- package/src/tenant/handlers/remove-member.write.ts +6 -8
- package/src/tenant/handlers/resolve-user-ids.query.ts +6 -16
- package/src/tenant/handlers/update-member-roles.write.ts +6 -8
- package/src/tenant/invitation-table.ts +2 -5
- package/src/tenant/membership-table.ts +3 -6
- package/src/tenant/schema/tenant.ts +2 -2
- package/src/tenant/seeding.ts +12 -18
- package/src/text-content/README.md +1 -1
- package/src/text-content/__tests__/text-content.integration.ts +2 -2
- package/src/text-content/api.ts +2 -9
- package/src/text-content/handlers/by-slug.query.ts +6 -9
- package/src/text-content/handlers/by-tenant.query.ts +2 -2
- package/src/text-content/handlers/set.write.ts +7 -9
- package/src/text-content/seeding.ts +6 -9
- package/src/text-content/table.ts +2 -2
- package/src/text-content/web/__tests__/editor-read-only.test.tsx +31 -45
- package/src/text-content/web/__tests__/group-blocks.test.ts +1 -18
- package/src/text-content/web/client-plugin.tsx +11 -23
- package/src/tier-engine/__tests__/auto-default-tier.integration.ts +10 -16
- package/src/tier-engine/__tests__/compose-app.test.ts +1 -1
- package/src/tier-engine/__tests__/drift.test.ts +1 -1
- package/src/tier-engine/__tests__/resolver.integration.ts +6 -6
- package/src/tier-engine/__tests__/tier-engine.integration.ts +1 -1
- package/src/tier-engine/feature.ts +9 -16
- package/src/user/__tests__/seed-testing.integration.ts +10 -22
- package/src/user/__tests__/user-status.test.ts +1 -1
- package/src/user/__tests__/user.integration.ts +6 -5
- package/src/user/handlers/create.write.ts +5 -7
- package/src/user/handlers/find-for-auth.query.ts +5 -7
- package/src/user/schema/user.ts +2 -2
- package/src/user/seeding.ts +2 -3
- package/src/user-data-rights/__tests__/audit-log.integration.ts +24 -12
- package/src/user-data-rights/__tests__/cross-data-matrix.integration.ts +64 -37
- package/src/user-data-rights/__tests__/download.integration.ts +29 -46
- package/src/user-data-rights/__tests__/export-job-idempotency.integration.ts +35 -28
- package/src/user-data-rights/__tests__/export-job-schema.test.ts +2 -2
- package/src/user-data-rights/__tests__/policy-to-strategy.test.ts +1 -1
- package/src/user-data-rights/__tests__/request-cancel-deletion.integration.ts +11 -15
- package/src/user-data-rights/__tests__/request-deletion-callback.integration.ts +10 -12
- package/src/user-data-rights/__tests__/request-export.integration.ts +23 -16
- package/src/user-data-rights/__tests__/restriction-flow.integration.ts +24 -32
- package/src/user-data-rights/__tests__/run-export-jobs.integration.ts +142 -137
- package/src/user-data-rights/__tests__/run-forget-cleanup.integration.ts +46 -28
- package/src/user-data-rights/__tests__/run-user-export.integration.ts +20 -14
- package/src/user-data-rights/__tests__/token-helpers.test.ts +1 -1
- package/src/user-data-rights/__tests__/user-data-rights.integration.ts +1 -1
- package/src/user-data-rights/__tests__/zip-path.test.ts +1 -1
- package/src/user-data-rights/audit-download.ts +3 -3
- package/src/user-data-rights/db/queries/export-jobs.ts +23 -0
- package/src/user-data-rights/db/queries/forget-cleanup.ts +13 -0
- package/src/user-data-rights/handlers/cancel-deletion.write.ts +28 -22
- package/src/user-data-rights/handlers/download-by-job.query.ts +11 -21
- package/src/user-data-rights/handlers/download-by-token.query.ts +20 -35
- package/src/user-data-rights/handlers/export-status.query.ts +19 -33
- package/src/user-data-rights/handlers/lift-restriction.write.ts +7 -12
- package/src/user-data-rights/handlers/list-download-attempts.query.ts +14 -23
- package/src/user-data-rights/handlers/my-audit-log.query.ts +33 -23
- package/src/user-data-rights/handlers/request-deletion.write.ts +15 -15
- package/src/user-data-rights/handlers/request-export.write.ts +7 -11
- package/src/user-data-rights/handlers/restrict-account.write.ts +12 -12
- package/src/user-data-rights/run-export-jobs.ts +20 -60
- package/src/user-data-rights/run-forget-cleanup.ts +19 -33
- package/src/user-data-rights/run-user-export.ts +4 -6
- package/src/user-data-rights/schema/download-attempt.ts +2 -2
- package/src/user-data-rights/schema/download-token.ts +2 -2
- package/src/user-data-rights/schema/export-job.ts +2 -3
- package/src/user-data-rights-defaults/__tests__/user-data-rights-defaults.integration.ts +37 -30
- package/src/user-data-rights-defaults/db/queries/user-hook.ts +17 -0
- package/src/user-data-rights-defaults/hooks/file-ref.userdata-hook.ts +12 -27
- package/src/user-data-rights-defaults/hooks/user.userdata-hook.ts +16 -18
- package/CHANGELOG.md +0 -689
|
@@ -20,6 +20,7 @@
|
|
|
20
20
|
// landen. user-data-rights-defaults/hooks/user.userdata-hook expose
|
|
21
21
|
// expliziert KEIN passwordHash + KEINE roles (privileged columns).
|
|
22
22
|
|
|
23
|
+
import { selectMany } from "@cosmicdrift/kumiko-framework/bun-db";
|
|
23
24
|
import type { DbRunner } from "@cosmicdrift/kumiko-framework/db";
|
|
24
25
|
import {
|
|
25
26
|
EXT_USER_DATA,
|
|
@@ -29,7 +30,6 @@ import {
|
|
|
29
30
|
type UserDataExportSnippet,
|
|
30
31
|
} from "@cosmicdrift/kumiko-framework/engine";
|
|
31
32
|
import type { getTemporal } from "@cosmicdrift/kumiko-framework/time";
|
|
32
|
-
import { eq } from "drizzle-orm";
|
|
33
33
|
import { tenantMembershipsTable } from "../tenant";
|
|
34
34
|
import { buildFileRefZipPath } from "./zip-path";
|
|
35
35
|
|
|
@@ -116,11 +116,9 @@ export async function runUserExport(args: RunUserExportArgs): Promise<UserExport
|
|
|
116
116
|
const { db, registry, userId, now } = args;
|
|
117
117
|
|
|
118
118
|
// Memberships → Tenant-Liste fuer Hook-Iteration.
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
.from(tenantMembershipsTable)
|
|
123
|
-
.where(eq(tenantMembershipsTable["userId"], userId))) as Array<{ tenantId: TenantId }>;
|
|
119
|
+
const memberships = await selectMany<{ tenantId: TenantId }>(db, tenantMembershipsTable, {
|
|
120
|
+
userId,
|
|
121
|
+
});
|
|
124
122
|
|
|
125
123
|
const tenantList: TenantId[] = memberships.map((m) => m.tenantId);
|
|
126
124
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { buildEntityTable } from "@cosmicdrift/kumiko-framework/db";
|
|
2
2
|
import {
|
|
3
3
|
createEntity,
|
|
4
4
|
createTextField,
|
|
@@ -34,4 +34,4 @@ export const downloadAttemptEntity = createEntity({
|
|
|
34
34
|
retention: { keepFor: "90d", strategy: "hardDelete", reference: "attemptedAt" },
|
|
35
35
|
});
|
|
36
36
|
|
|
37
|
-
export const downloadAttemptsTable =
|
|
37
|
+
export const downloadAttemptsTable = buildEntityTable("downloadAttempt", downloadAttemptEntity);
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { buildEntityTable } from "@cosmicdrift/kumiko-framework/db";
|
|
2
2
|
import {
|
|
3
3
|
createBigIntField,
|
|
4
4
|
createEntity,
|
|
@@ -105,7 +105,7 @@ export const exportDownloadTokenEntity = createEntity({
|
|
|
105
105
|
],
|
|
106
106
|
});
|
|
107
107
|
|
|
108
|
-
export const exportDownloadTokensTable =
|
|
108
|
+
export const exportDownloadTokensTable = buildEntityTable(
|
|
109
109
|
"exportDownloadToken",
|
|
110
110
|
exportDownloadTokenEntity,
|
|
111
111
|
);
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { buildEntityTable, sql } from "@cosmicdrift/kumiko-framework/db";
|
|
2
2
|
import {
|
|
3
3
|
createBigIntField,
|
|
4
4
|
createEntity,
|
|
@@ -7,7 +7,6 @@ import {
|
|
|
7
7
|
createTextField,
|
|
8
8
|
createTimestampField,
|
|
9
9
|
} from "@cosmicdrift/kumiko-framework/engine";
|
|
10
|
-
import { sql } from "drizzle-orm";
|
|
11
10
|
|
|
12
11
|
// Export-Job-Lifecycle (S2.U3+U4 Atom 1).
|
|
13
12
|
//
|
|
@@ -163,4 +162,4 @@ export const exportJobEntity = createEntity({
|
|
|
163
162
|
],
|
|
164
163
|
});
|
|
165
164
|
|
|
166
|
-
export const exportJobsTable =
|
|
165
|
+
export const exportJobsTable = buildEntityTable("exportJob", exportJobEntity);
|
|
@@ -10,13 +10,13 @@
|
|
|
10
10
|
// - "cross data matrix checks" (Cross-Tenant-Isolation: Tenant A's
|
|
11
11
|
// fileRef-Forget beruehrt Tenant B's Files nicht)
|
|
12
12
|
|
|
13
|
+
import { afterAll, beforeAll, describe, expect, test } from "bun:test";
|
|
14
|
+
import { asRawClient, insertOne } from "@cosmicdrift/kumiko-framework/bun-db";
|
|
13
15
|
import {
|
|
14
16
|
setupTestStack,
|
|
15
17
|
type TestStack,
|
|
16
18
|
unsafeCreateEntityTable,
|
|
17
19
|
} from "@cosmicdrift/kumiko-framework/stack";
|
|
18
|
-
import { sql } from "drizzle-orm";
|
|
19
|
-
import { afterAll, beforeAll, describe, expect, test } from "vitest";
|
|
20
20
|
import { createComplianceProfilesFeature } from "../../compliance-profiles";
|
|
21
21
|
import { createDataRetentionFeature } from "../../data-retention";
|
|
22
22
|
import { createFilesFeature } from "../../files";
|
|
@@ -52,9 +52,9 @@ beforeAll(async () => {
|
|
|
52
52
|
await unsafeCreateEntityTable(stack.db, userEntity);
|
|
53
53
|
|
|
54
54
|
// file_refs ist framework-pgTable (nicht entity-getrieben, S1.5 hat
|
|
55
|
-
// die Schema-Sicht ohne
|
|
55
|
+
// die Schema-Sicht ohne buildEntityTable-Auto-Generation). Manuelle
|
|
56
56
|
// CREATE matched die Spalten aus framework/src/files/file-ref-table.ts
|
|
57
|
-
await stack.db.
|
|
57
|
+
await asRawClient(stack.db).unsafe(`
|
|
58
58
|
CREATE TABLE IF NOT EXISTS file_refs (
|
|
59
59
|
id UUID PRIMARY KEY,
|
|
60
60
|
tenant_id UUID NOT NULL,
|
|
@@ -90,21 +90,18 @@ async function seedUser(id: string, overrides: Record<string, unknown> = {}): Pr
|
|
|
90
90
|
// Schema hat tenant_id-Spalte automatisch (Framework-Default).
|
|
91
91
|
// Pragmatisch: SYSTEM_TENANT_ID fuer User-Rows in Tests.
|
|
92
92
|
const SYSTEM_TENANT = "00000000-0000-4000-8000-000000000001";
|
|
93
|
-
await stack.db
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
...overrides,
|
|
106
|
-
})
|
|
107
|
-
.onConflictDoNothing();
|
|
93
|
+
await insertOne(stack.db, userTable, {
|
|
94
|
+
id,
|
|
95
|
+
tenantId: SYSTEM_TENANT,
|
|
96
|
+
email: `user-${id}@example.com`,
|
|
97
|
+
passwordHash: "hashed-password",
|
|
98
|
+
displayName: `User ${id}`,
|
|
99
|
+
locale: "de",
|
|
100
|
+
emailVerified: true,
|
|
101
|
+
roles: '["Member"]',
|
|
102
|
+
status: USER_STATUS.Active,
|
|
103
|
+
...overrides,
|
|
104
|
+
});
|
|
108
105
|
}
|
|
109
106
|
|
|
110
107
|
async function seedFileRef(
|
|
@@ -113,18 +110,24 @@ async function seedFileRef(
|
|
|
113
110
|
insertedById: string | null,
|
|
114
111
|
fileName: string,
|
|
115
112
|
): Promise<void> {
|
|
116
|
-
await stack.db.
|
|
113
|
+
await asRawClient(stack.db).unsafe(
|
|
114
|
+
`
|
|
117
115
|
INSERT INTO file_refs (id, tenant_id, storage_key, file_name, mime_type, size, inserted_by_id)
|
|
118
|
-
VALUES ($
|
|
116
|
+
VALUES ($1, $2, $3, $4, 'application/pdf', 1024, $5)
|
|
119
117
|
ON CONFLICT (id) DO NOTHING
|
|
120
|
-
|
|
118
|
+
`,
|
|
119
|
+
[id, tenantId, `storage/${id}`, fileName, insertedById],
|
|
120
|
+
);
|
|
121
121
|
}
|
|
122
122
|
|
|
123
123
|
async function fetchUser(id: string) {
|
|
124
|
-
const result = await stack.db.
|
|
124
|
+
const result = await asRawClient(stack.db).unsafe(
|
|
125
|
+
`
|
|
125
126
|
SELECT id, email, display_name, password_hash, status, deleted_at
|
|
126
|
-
FROM read_users WHERE id = $
|
|
127
|
-
|
|
127
|
+
FROM read_users WHERE id = $1
|
|
128
|
+
`,
|
|
129
|
+
[id],
|
|
130
|
+
);
|
|
128
131
|
// biome-ignore lint/suspicious/noExplicitAny: drizzle execute returns any-typed array
|
|
129
132
|
const rows = ((result as any).rows ?? result) as Array<{
|
|
130
133
|
id: string;
|
|
@@ -140,13 +143,17 @@ async function fetchUser(id: string) {
|
|
|
140
143
|
async function fetchFileRefs(tenantId: string, insertedById?: string | null) {
|
|
141
144
|
const result =
|
|
142
145
|
insertedById === undefined
|
|
143
|
-
? await stack.db.
|
|
146
|
+
? await asRawClient(stack.db).unsafe(`SELECT * FROM file_refs WHERE tenant_id = $1`, [
|
|
147
|
+
tenantId,
|
|
148
|
+
])
|
|
144
149
|
: insertedById === null
|
|
145
|
-
? await stack.db.
|
|
146
|
-
|
|
150
|
+
? await asRawClient(stack.db).unsafe(
|
|
151
|
+
`SELECT * FROM file_refs WHERE tenant_id = $1 AND inserted_by_id IS NULL`,
|
|
152
|
+
[tenantId],
|
|
147
153
|
)
|
|
148
|
-
: await stack.db.
|
|
149
|
-
|
|
154
|
+
: await asRawClient(stack.db).unsafe(
|
|
155
|
+
`SELECT * FROM file_refs WHERE tenant_id = $1 AND inserted_by_id = $2`,
|
|
156
|
+
[tenantId, insertedById],
|
|
150
157
|
);
|
|
151
158
|
// biome-ignore lint/suspicious/noExplicitAny: drizzle execute typing
|
|
152
159
|
return (result as any).rows ?? result;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { asRawClient } from "@cosmicdrift/kumiko-framework/bun-db";
|
|
2
|
+
import type { DbRunner } from "@cosmicdrift/kumiko-framework/db";
|
|
3
|
+
|
|
4
|
+
export async function anonymizeDeletedUser(
|
|
5
|
+
db: DbRunner,
|
|
6
|
+
params: {
|
|
7
|
+
readonly email: string;
|
|
8
|
+
readonly displayName: string;
|
|
9
|
+
readonly status: string;
|
|
10
|
+
readonly userId: string;
|
|
11
|
+
},
|
|
12
|
+
): Promise<void> {
|
|
13
|
+
await asRawClient(db).unsafe(
|
|
14
|
+
'UPDATE "read_users" SET email = $1, display_name = $2, password_hash = $3, status = $4, deleted_at = now() WHERE id = $5',
|
|
15
|
+
[params.email, params.displayName, null, params.status, params.userId],
|
|
16
|
+
);
|
|
17
|
+
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
+
import { deleteMany, selectMany, updateMany } from "@cosmicdrift/kumiko-framework/bun-db";
|
|
1
2
|
import type { UserDataDeleteHook, UserDataExportHook } from "@cosmicdrift/kumiko-framework/engine";
|
|
2
3
|
import { fileRefsTable } from "@cosmicdrift/kumiko-framework/files";
|
|
3
|
-
import { and, eq } from "drizzle-orm";
|
|
4
4
|
|
|
5
5
|
// userData-Hook fuer fileRef-entity (S2.H2).
|
|
6
6
|
//
|
|
@@ -30,15 +30,10 @@ import { and, eq } from "drizzle-orm";
|
|
|
30
30
|
// Cleanup als TODO und faellen das in S2.U5 nochmal an.
|
|
31
31
|
|
|
32
32
|
export const fileRefExportHook: UserDataExportHook = async (ctx) => {
|
|
33
|
-
const rawRows = await ctx.db
|
|
34
|
-
.
|
|
35
|
-
.
|
|
36
|
-
|
|
37
|
-
and(
|
|
38
|
-
eq(fileRefsTable["tenantId"], ctx.tenantId),
|
|
39
|
-
eq(fileRefsTable["insertedById"], ctx.userId),
|
|
40
|
-
),
|
|
41
|
-
);
|
|
33
|
+
const rawRows = await selectMany(ctx.db, fileRefsTable, {
|
|
34
|
+
tenantId: ctx.tenantId,
|
|
35
|
+
insertedById: ctx.userId,
|
|
36
|
+
});
|
|
42
37
|
|
|
43
38
|
// @cast-boundary db-row: drizzle liefert insertedAt als Instant
|
|
44
39
|
// (framework-customType). Fuer JSON-Export brauchen wir String —
|
|
@@ -83,27 +78,17 @@ export const fileRefDeleteHook: UserDataDeleteHook = async (ctx, strategy) => {
|
|
|
83
78
|
// Hard-delete der FileRef-Rows fuer diesen User in diesem Tenant.
|
|
84
79
|
// Storage-Binary-Cleanup folgt in S2.U5 wenn der Forget-Job-Ctx
|
|
85
80
|
// den Storage-Provider exposed.
|
|
86
|
-
await ctx.db
|
|
87
|
-
.delete(fileRefsTable)
|
|
88
|
-
.where(
|
|
89
|
-
and(
|
|
90
|
-
eq(fileRefsTable["tenantId"], ctx.tenantId),
|
|
91
|
-
eq(fileRefsTable["insertedById"], ctx.userId),
|
|
92
|
-
),
|
|
93
|
-
);
|
|
81
|
+
await deleteMany(ctx.db, fileRefsTable, { tenantId: ctx.tenantId, insertedById: ctx.userId });
|
|
94
82
|
} else {
|
|
95
83
|
// anonymize: insertedById=null, FileRef + binary bleiben.
|
|
96
84
|
// Use-case: shared chat-Attachment in einem Multi-User-Channel —
|
|
97
85
|
// Author-Identifikation raus, Datei bleibt fuer andere User
|
|
98
86
|
// sichtbar.
|
|
99
|
-
await
|
|
100
|
-
.
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
eq(fileRefsTable["insertedById"], ctx.userId),
|
|
106
|
-
),
|
|
107
|
-
);
|
|
87
|
+
await updateMany(
|
|
88
|
+
ctx.db,
|
|
89
|
+
fileRefsTable,
|
|
90
|
+
{ insertedById: null },
|
|
91
|
+
{ tenantId: ctx.tenantId, insertedById: ctx.userId },
|
|
92
|
+
);
|
|
108
93
|
}
|
|
109
94
|
};
|
|
@@ -1,6 +1,5 @@
|
|
|
1
|
-
import { fetchOne } from "@cosmicdrift/kumiko-framework/db";
|
|
1
|
+
import { fetchOne, updateMany } from "@cosmicdrift/kumiko-framework/bun-db";
|
|
2
2
|
import type { UserDataDeleteHook, UserDataExportHook } from "@cosmicdrift/kumiko-framework/engine";
|
|
3
|
-
import { eq, sql } from "drizzle-orm";
|
|
4
3
|
import {
|
|
5
4
|
USER_ANONYMIZED_DISPLAY_NAME,
|
|
6
5
|
USER_ANONYMIZED_EMAIL_DOMAIN,
|
|
@@ -10,6 +9,7 @@ import {
|
|
|
10
9
|
USER_STATUS,
|
|
11
10
|
userTable,
|
|
12
11
|
} from "../../user";
|
|
12
|
+
import { anonymizeDeletedUser } from "../db/queries/user-hook";
|
|
13
13
|
|
|
14
14
|
// userData-Hook fuer user-entity (S2.H1).
|
|
15
15
|
//
|
|
@@ -32,7 +32,7 @@ import {
|
|
|
32
32
|
// Frist auf einer FK-target-Entity)
|
|
33
33
|
|
|
34
34
|
export const userExportHook: UserDataExportHook = async (ctx) => {
|
|
35
|
-
const row = (await fetchOne(ctx.db, userTable,
|
|
35
|
+
const row = (await fetchOne(ctx.db, userTable, { id: ctx.userId })) as {
|
|
36
36
|
id: string;
|
|
37
37
|
email: string;
|
|
38
38
|
displayName: string;
|
|
@@ -64,28 +64,26 @@ export const userDeleteHook: UserDataDeleteHook = async (ctx, strategy) => {
|
|
|
64
64
|
// Tenants Member sein), kein tenantId-Filter noetig.
|
|
65
65
|
|
|
66
66
|
if (strategy === "delete") {
|
|
67
|
-
await ctx.db
|
|
68
|
-
.
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
status: USER_STATUS.Deleted,
|
|
74
|
-
deletedAt: sql`now()`,
|
|
75
|
-
})
|
|
76
|
-
.where(eq(userTable["id"], ctx.userId));
|
|
67
|
+
await anonymizeDeletedUser(ctx.db, {
|
|
68
|
+
email: `${USER_DELETED_EMAIL_PREFIX}-${ctx.userId}@${USER_ANONYMIZED_EMAIL_DOMAIN}`,
|
|
69
|
+
displayName: USER_DELETED_DISPLAY_NAME,
|
|
70
|
+
status: USER_STATUS.Deleted,
|
|
71
|
+
userId: ctx.userId,
|
|
72
|
+
});
|
|
77
73
|
} else {
|
|
78
74
|
// anonymize: PII raus, aber Row bleibt active (damit FK-References
|
|
79
75
|
// weiter aufloesbar sind). Account ist effektiv weiter nutzbar
|
|
80
76
|
// wenn der User sich neu authentifiziert — pragmatisch akzeptabel
|
|
81
77
|
// weil "anonymize" auf user-entity ein seltener Edge-Case ist
|
|
82
78
|
// (typisch hard-delete fuer User).
|
|
83
|
-
await
|
|
84
|
-
.
|
|
85
|
-
|
|
79
|
+
await updateMany(
|
|
80
|
+
ctx.db,
|
|
81
|
+
userTable,
|
|
82
|
+
{
|
|
86
83
|
email: `${USER_ANONYMIZED_EMAIL_PREFIX}-${ctx.userId}@${USER_ANONYMIZED_EMAIL_DOMAIN}`,
|
|
87
84
|
displayName: USER_ANONYMIZED_DISPLAY_NAME,
|
|
88
|
-
}
|
|
89
|
-
|
|
85
|
+
},
|
|
86
|
+
{ id: ctx.userId },
|
|
87
|
+
);
|
|
90
88
|
}
|
|
91
89
|
};
|