Skip to content

Commit 0973b89

Browse files
committed
Use membership formIds to calculate permissions and list of forms in switcher
1 parent 5f6c773 commit 0973b89

File tree

8 files changed

+289
-204
lines changed

8 files changed

+289
-204
lines changed

core/app/api/v0/c/[communitySlug]/site/[...ts-rest]/route.ts

+3-5
Original file line numberDiff line numberDiff line change
@@ -387,7 +387,7 @@ const handler = createNextHandler(
387387
create: async ({ body }) => {
388388
const { authorization, community, lastModifiedBy } = await checkAuthorization({
389389
token: { scope: ApiAccessScope.pub, type: ApiAccessType.write },
390-
// TODO: figure out capability here
390+
// TODO: refactor so we call userCanCreatePub here
391391
cookies: false,
392392
});
393393

@@ -423,10 +423,8 @@ const handler = createNextHandler(
423423
update: async ({ params, body }) => {
424424
const { user, community, lastModifiedBy } = await checkAuthorization({
425425
token: { scope: ApiAccessScope.pub, type: ApiAccessType.write },
426-
cookies: {
427-
capability: Capabilities.updatePubValues,
428-
target: { type: MembershipType.pub, pubId: params.pubId as PubsId },
429-
},
426+
// TODO: refactor so we call userCanEditPub here
427+
cookies: false,
430428
});
431429

432430
const { exists } = await doesPubExist(

core/app/c/[communitySlug]/pubs/[pubId]/edit/page.tsx

+7-11
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,14 @@ import Link from "next/link";
55
import { notFound, redirect } from "next/navigation";
66

77
import type { CommunitiesId, PubsId, UsersId } from "db/public";
8-
import { Capabilities, MembershipType } from "db/public";
98
import { Button } from "ui/button";
109

1110
import { ContentLayout } from "~/app/c/[communitySlug]/ContentLayout";
11+
import { FormSwitcher } from "~/app/components/FormSwitcher/FormSwitcher";
1212
import { PageTitleWithStatus } from "~/app/components/pubs/PubEditor/PageTitleWithStatus";
1313
import { PubEditor } from "~/app/components/pubs/PubEditor/PubEditor";
1414
import { getPageLoginData } from "~/lib/authentication/loginData";
15-
import { userCan } from "~/lib/authorization/capabilities";
15+
import { getAuthorizedUpdateForms, userCanEditPub } from "~/lib/authorization/capabilities";
1616
import { getPubTitle } from "~/lib/pubs";
1717
import { getPubsWithRelatedValues } from "~/lib/server";
1818
import { findCommunityBySlug } from "~/lib/server/community";
@@ -80,19 +80,12 @@ export default async function Page(props: {
8080

8181
const { user } = await getPageLoginData();
8282

83-
const canUpdatePub = await userCan(
84-
Capabilities.updatePubValues,
85-
{
86-
type: MembershipType.pub,
87-
pubId,
88-
},
89-
user.id
90-
);
91-
9283
if (!pubId || !communitySlug) {
9384
return null;
9485
}
9586

87+
const canUpdatePub = await userCanEditPub({ userId: user.id, pubId });
88+
9689
if (!canUpdatePub) {
9790
redirect(`/c/${communitySlug}/unauthorized`);
9891
}
@@ -113,6 +106,8 @@ export default async function Page(props: {
113106
return null;
114107
}
115108

109+
const availableForms = await getAuthorizedUpdateForms(user.id, pub.id).execute();
110+
116111
const htmlFormId = `edit-pub-${pub.id}`;
117112

118113
return (
@@ -131,6 +126,7 @@ export default async function Page(props: {
131126
>
132127
<div className="flex justify-center py-10">
133128
<div className="max-w-prose flex-1">
129+
<FormSwitcher forms={availableForms} />
134130
{/** TODO: Add suspense */}
135131
<PubEditor
136132
searchParams={searchParams}

core/app/c/[communitySlug]/pubs/[pubId]/page.tsx

+3-3
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,13 @@ import { CreatePubButton } from "~/app/components/pubs/CreatePubButton";
1717
import { RemovePubButton } from "~/app/components/pubs/RemovePubButton";
1818
import { db } from "~/kysely/database";
1919
import { getPageLoginData } from "~/lib/authentication/loginData";
20-
import { userCan } from "~/lib/authorization/capabilities";
20+
import { getAuthorizedUpdateForms, userCan } from "~/lib/authorization/capabilities";
2121
import { getStageActions } from "~/lib/db/queries";
2222
import { getPubByForm, getPubTitle } from "~/lib/pubs";
2323
import { getPubsWithRelatedValues, pubValuesByVal } from "~/lib/server";
2424
import { autoCache } from "~/lib/server/cache/autoCache";
2525
import { findCommunityBySlug } from "~/lib/server/community";
26-
import { getForm, getSimpleForms } from "~/lib/server/form";
26+
import { getForm } from "~/lib/server/form";
2727
import { selectAllCommunityMemberships } from "~/lib/server/member";
2828
import { getStages } from "~/lib/server/stages";
2929
import {
@@ -157,7 +157,7 @@ export default async function Page(props: {
157157
{ type: MembershipType.pub, pubId: pub.id },
158158
user.id
159159
),
160-
getSimpleForms(pub.pubType.id),
160+
getAuthorizedUpdateForms(user.id, pub.id).execute(),
161161
]);
162162

163163
const pubTypeHasRelatedPubs = pub.pubType.fields.some((field) => field.isRelation);

core/app/c/[communitySlug]/pubs/create/page.tsx

+10-11
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,14 @@ import type { Metadata } from "next";
22

33
import { notFound, redirect } from "next/navigation";
44

5-
import { Capabilities, MembershipType } from "db/public";
5+
import { type PubTypesId } from "db/public";
66
import { Button } from "ui/button";
77

88
import { ContentLayout } from "~/app/c/[communitySlug]/ContentLayout";
99
import { PageTitleWithStatus } from "~/app/components/pubs/PubEditor/PageTitleWithStatus";
1010
import { PubEditor } from "~/app/components/pubs/PubEditor/PubEditor";
1111
import { getPageLoginData } from "~/lib/authentication/loginData";
12-
import { userCan } from "~/lib/authorization/capabilities";
12+
import { userCanCreatePub } from "~/lib/authorization/capabilities";
1313
import { findCommunityBySlug } from "~/lib/server/community";
1414

1515
export async function generateMetadata(props: {
@@ -29,7 +29,7 @@ export async function generateMetadata(props: {
2929

3030
export default async function Page(props: {
3131
params: Promise<{ communitySlug: string }>;
32-
searchParams: Promise<Record<string, string>>;
32+
searchParams: Promise<Record<string, string> & { pubTypeId: PubTypesId }>;
3333
}) {
3434
const searchParams = await props.searchParams;
3535
const params = await props.params;
@@ -43,14 +43,13 @@ export default async function Page(props: {
4343
notFound();
4444
}
4545

46-
const canCreatePub = await userCan(
47-
Capabilities.createPub,
48-
{
49-
type: MembershipType.community,
50-
communityId: community.id,
51-
},
52-
user.id
53-
);
46+
const canCreatePub = await userCanCreatePub({
47+
communityId: community.id,
48+
userId: user.id,
49+
pubTypeId: searchParams.pubTypeId,
50+
// No formSlug because we're just checking if there are any authorized forms
51+
// We validate that the user can create a pub with the specified form in the create action
52+
});
5453

5554
if (!canCreatePub) {
5655
redirect(`/c/${communitySlug}/unauthorized`);

core/app/components/pubs/PubEditor/actions.ts

+12-21
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,20 @@
11
"use server";
22

33
import type { JsonValue } from "contracts";
4-
import type { PubsId, StagesId, UsersId } from "db/public";
4+
import type { PubsId, PubTypesId, StagesId, UsersId } from "db/public";
55
import { Capabilities, FormAccessType, MemberRole, MembershipType } from "db/public";
66
import { logger } from "logger";
77

88
import { db } from "~/kysely/database";
99
import { getLoginData } from "~/lib/authentication/loginData";
1010
import { isCommunityAdmin } from "~/lib/authentication/roles";
11-
import { userCan } from "~/lib/authorization/capabilities";
11+
import { userCan, userCanCreatePub, userCanEditPub } from "~/lib/authorization/capabilities";
1212
import { parseRichTextForPubFieldsAndRelatedPubs } from "~/lib/fields/richText";
1313
import { createLastModifiedBy } from "~/lib/lastModifiedBy";
1414
import { ApiError, createPubRecursiveNew } from "~/lib/server";
1515
import { findCommunityBySlug } from "~/lib/server/community";
1616
import { defineServerAction } from "~/lib/server/defineServerAction";
17-
import { getForm, grantFormAccess, userHasPermissionToForm } from "~/lib/server/form";
17+
import { getForm, grantFormAccess } from "~/lib/server/form";
1818
import { deletePub, maybeWithTrx, normalizePubValues } from "~/lib/server/pub";
1919
import { PubOp } from "~/lib/server/pub-op";
2020

@@ -34,21 +34,21 @@ export const createPubRecursive = defineServerAction(async function createPubRec
3434
}
3535
const { user } = loginData;
3636

37-
const [form, canCreatePub, canCreateFromForm] = await Promise.all([
37+
const [form, canCreatePub] = await Promise.all([
3838
formSlug
3939
? await getForm({ communityId: props.communityId, slug: formSlug }).executeTakeFirst()
4040
: null,
41-
userCan(
42-
Capabilities.createPub,
43-
{ type: MembershipType.community, communityId: props.communityId },
44-
user.id
45-
),
46-
formSlug ? userHasPermissionToForm({ formSlug, userId: loginData.user.id }) : false,
41+
userCanCreatePub({
42+
userId: user.id,
43+
communityId: props.communityId,
44+
formSlug,
45+
pubTypeId: createPubProps.body.pubTypeId as PubTypesId,
46+
}),
4747
]);
4848

4949
const isPublicForm = form?.access === FormAccessType.public;
5050

51-
if (!canCreatePub && !canCreateFromForm && !isPublicForm) {
51+
if (!canCreatePub && !isPublicForm) {
5252
return ApiError.UNAUTHORIZED;
5353
}
5454

@@ -128,16 +128,7 @@ export const updatePub = defineServerAction(async function updatePub({
128128
return ApiError.COMMUNITY_NOT_FOUND;
129129
}
130130

131-
const [canUpdateFromForm, canUpdatePubValues] = await Promise.all([
132-
formSlug ? userHasPermissionToForm({ formSlug, userId: loginData.user.id, pubId }) : false,
133-
userCan(
134-
Capabilities.updatePubValues,
135-
{ type: MembershipType.pub, pubId },
136-
loginData.user.id
137-
),
138-
]);
139-
140-
if (!canUpdatePubValues && !canUpdateFromForm) {
131+
if (!userCanEditPub({ pubId, userId: loginData.user.id, formSlug })) {
141132
return ApiError.UNAUTHORIZED;
142133
}
143134

core/lib/authorization/capabilities.db.test.ts

-3
Original file line numberDiff line numberDiff line change
@@ -107,9 +107,6 @@ describe("Community membership grants appropriate capabilities", async () => {
107107
Capabilities.movePub,
108108
Capabilities.viewPub,
109109
Capabilities.deletePub,
110-
Capabilities.updatePubValues,
111-
Capabilities.createRelatedPub,
112-
Capabilities.editPubWithForm,
113110
Capabilities.runAction,
114111
Capabilities.seeExtraPubValues,
115112
] as const;

0 commit comments

Comments
 (0)