Skip to content

Commit e7c2631

Browse files
committed
cleanup + fix some policy problems
1 parent aaa4083 commit e7c2631

File tree

4 files changed

+64
-76
lines changed

4 files changed

+64
-76
lines changed

packages/web-backend/src/Folders/FoldersPolicy.ts

Lines changed: 12 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,42 +1,32 @@
1-
import * as Db from "@cap/database/schema";
21
import { type Folder, Policy } from "@cap/web-domain";
3-
import * as Dz from "drizzle-orm";
42
import { Effect } from "effect";
53

64
import { Database } from "../Database.ts";
5+
import { SpacesPolicy } from "../Spaces/SpacesPolicy.ts";
6+
import { FoldersRepo } from "./FoldersRepo.ts";
77

88
export class FoldersPolicy extends Effect.Service<FoldersPolicy>()(
99
"FoldersPolicy",
1010
{
1111
effect: Effect.gen(function* () {
12-
const db = yield* Database;
12+
const repo = yield* FoldersRepo;
13+
const spacesPolicy = yield* SpacesPolicy;
1314

1415
const canEdit = (id: Folder.FolderId) =>
1516
Policy.policy((user) =>
1617
Effect.gen(function* () {
17-
const [folder] = yield* db.execute((db) =>
18-
db.select().from(Db.folders).where(Dz.eq(Db.folders.id, id)),
18+
const folder = yield* (yield* repo.getById(id)).pipe(
19+
Effect.catchTag(
20+
"NoSuchElementException",
21+
() => new Policy.PolicyDeniedError(),
22+
),
1923
);
2024

21-
// All space members can edit space properties
22-
if (!folder?.spaceId) {
23-
return folder?.createdById === user.id;
24-
}
25+
if (folder.spaceId === null) return folder.createdById === user.id;
2526

26-
const { spaceId } = folder;
27-
const [spaceMember] = yield* db.execute((db) =>
28-
db
29-
.select()
30-
.from(Db.spaceMembers)
31-
.where(
32-
Dz.and(
33-
Dz.eq(Db.spaceMembers.userId, user.id),
34-
Dz.eq(Db.spaceMembers.spaceId, spaceId),
35-
),
36-
),
37-
);
27+
yield* spacesPolicy.isMember(folder.spaceId);
3828

39-
return spaceMember !== undefined;
29+
return true;
4030
}),
4131
);
4232

packages/web-backend/src/Folders/index.ts

Lines changed: 46 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -130,66 +130,65 @@ export class Folders extends Effect.Service<Folders>()("Folders", {
130130
folderId: Folder.FolderId,
131131
data: Folder.FolderUpdate,
132132
) {
133-
const folder = yield* repo
133+
const folder = yield* (yield* repo
134134
.getById(folderId)
135-
.pipe(
136-
Policy.withPolicy(policy.canEdit(folderId)),
137-
Effect.flatMap(
138-
Effect.catchTag(
139-
"NoSuchElementException",
140-
() => new Folder.NotFoundError(),
141-
),
142-
),
143-
);
135+
.pipe(Policy.withPolicy(policy.canEdit(folderId)))).pipe(
136+
Effect.catchTag(
137+
"NoSuchElementException",
138+
() => new Folder.NotFoundError(),
139+
),
140+
);
144141

145142
// If parentId is provided and not null, verify it exists and belongs to the same organization
146-
if (!data.parentId) return;
147-
const parentId = data.parentId;
148-
149-
// Check that we're not creating an immediate circular reference
150-
if (parentId === folderId)
151-
return yield* new Folder.RecursiveDefinitionError();
152-
153-
const parentFolder = yield* repo
154-
.getById(parentId, {
155-
organizationId: Organisation.OrganisationId.make(
156-
folder.organizationId,
157-
),
158-
})
159-
.pipe(
160-
Policy.withPolicy(policy.canEdit(parentId)),
161-
Effect.flatMap(
162-
Effect.catchTag(
163-
"NoSuchElementException",
164-
() => new Folder.ParentNotFoundError(),
143+
if (data.parentId && Option.isSome(data.parentId)) {
144+
const parentId = data.parentId.value;
145+
// Check that we're not creating an immediate circular reference
146+
if (parentId === folderId)
147+
return yield* new Folder.RecursiveDefinitionError();
148+
149+
const parentFolder = yield* repo
150+
.getById(parentId, {
151+
organizationId: Organisation.OrganisationId.make(
152+
folder.organizationId,
165153
),
166-
),
167-
);
154+
})
155+
.pipe(
156+
Policy.withPolicy(policy.canEdit(parentId)),
157+
Effect.flatMap(
158+
Effect.catchTag(
159+
"NoSuchElementException",
160+
() => new Folder.ParentNotFoundError(),
161+
),
162+
),
163+
);
168164

169-
// Check for circular references in the folder hierarchy
170-
let currentParentId = parentFolder.parentId;
171-
while (currentParentId) {
172-
if (currentParentId === folderId)
173-
return yield* new Folder.RecursiveDefinitionError();
165+
// Check for circular references in the folder hierarchy
166+
let currentParentId = parentFolder.parentId;
167+
while (currentParentId) {
168+
if (currentParentId === folderId)
169+
return yield* new Folder.RecursiveDefinitionError();
174170

175-
const parentId = currentParentId;
176-
const nextParent = yield* repo.getById(parentId, {
177-
organizationId: Organisation.OrganisationId.make(
178-
folder.organizationId,
179-
),
180-
});
171+
const parentId = currentParentId;
172+
const nextParent = yield* repo.getById(parentId, {
173+
organizationId: Organisation.OrganisationId.make(
174+
folder.organizationId,
175+
),
176+
});
181177

182-
if (Option.isNone(nextParent)) break;
183-
currentParentId = nextParent.value.parentId;
178+
if (Option.isNone(nextParent)) break;
179+
currentParentId = nextParent.value.parentId;
180+
}
184181
}
185182

186183
yield* db.execute((db) =>
187184
db
188185
.update(Db.folders)
189186
.set({
190-
...(data.name ? { name: data.name } : {}),
191-
...(data.color ? { color: data.color } : {}),
192-
...(data.parentId ? { parentId: data.parentId } : {}),
187+
name: data.name,
188+
color: data.color,
189+
parentId: data.parentId
190+
? Option.getOrNull(data.parentId)
191+
: undefined,
193192
})
194193
.where(Dz.eq(Db.folders.id, folderId)),
195194
);

packages/web-backend/src/Spaces/SpacesPolicy.ts

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,8 @@ export class SpacesPolicy extends Effect.Service<SpacesPolicy>()(
1212
const repo = yield* SpacesRepo;
1313

1414
const hasMembership = (spaceId: string) =>
15-
Policy.policy(
16-
Effect.fn(function* (user) {
17-
return Option.isSome(yield* repo.membership(user.id, spaceId));
18-
}),
15+
Policy.policy((user) =>
16+
repo.membership(user.id, spaceId).pipe(Effect.map(Option.isSome)),
1917
);
2018

2119
const isOwner = (spaceId: string) =>

packages/web-domain/src/Folder.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -44,12 +44,13 @@ export class Folder extends Schema.Class<Folder>("Folder")({
4444
parentId: Schema.OptionFromNullOr(FolderId),
4545
}) {}
4646

47-
export class FolderUpdate extends Schema.Class<FolderUpdate>("FolderPatch")({
47+
export const FolderUpdate = Schema.Struct({
4848
id: FolderId,
4949
name: Schema.optional(Schema.String),
5050
color: Schema.optional(FolderColor),
51-
parentId: Schema.optional(FolderId),
52-
}) {}
51+
parentId: Schema.optional(Schema.Option(FolderId)),
52+
});
53+
export type FolderUpdate = Schema.Schema.Type<typeof FolderUpdate>;
5354

5455
export class FolderRpcs extends RpcGroup.make(
5556
Rpc.make("FolderDelete", {

0 commit comments

Comments
 (0)