Skip to content

Commit 64911d4

Browse files
committed
Add canPublish permission
1 parent 1f09b0e commit 64911d4

File tree

7 files changed

+175
-41
lines changed

7 files changed

+175
-41
lines changed

apps/builder/app/builder/features/topbar/publish.tsx

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ import { $isPublishDialogOpen } from "../../shared/nano-states";
3939
import { validateProjectDomain, type Project } from "@webstudio-is/project";
4040
import {
4141
$authPermit,
42+
$authTokenPermissions,
4243
$project,
4344
$publishedOrigin,
4445
$userPlanFeatures,
@@ -837,16 +838,16 @@ type PublishProps = {
837838

838839
export const PublishButton = ({ projectId }: PublishProps) => {
839840
const isPublishDialogOpen = useStore($isPublishDialogOpen);
840-
const authPermit = useStore($authPermit);
841+
const authTokenPermissions = useStore($authTokenPermissions);
841842
const [dialogContentType, setDialogContentType] = useState<
842843
"publish" | "export"
843844
>("publish");
844845

845-
const isPublishEnabled = authPermit === "own" || authPermit === "admin";
846+
const isPublishEnabled = authTokenPermissions.canPublish;
846847

847848
const tooltipContent = isPublishEnabled
848849
? undefined
849-
: "Only owner or admin can publish projects";
850+
: "Only the owner, an admin, or content editors with publish permissions can publish projects";
850851

851852
const handleExportClick = () => {
852853
setDialogContentType("export");

apps/builder/app/shared/nano-states/misc.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -331,6 +331,7 @@ export const $authPermit = atom<AuthPermit>("view");
331331
export const $authTokenPermissions = atom<TokenPermissions>({
332332
canClone: true,
333333
canCopy: true,
334+
canPublish: false,
334335
});
335336

336337
export const $authToken = atom<string | undefined>(undefined);

apps/builder/app/shared/share-project/share-project.tsx

Lines changed: 67 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@ type MenuProps = {
9494
};
9595

9696
const Menu = ({ name, hasProPlan, value, onChange, onDelete }: MenuProps) => {
97-
const ids = useIds(["name", "canClone", "canCopy"]);
97+
const ids = useIds(["name", "canClone", "canCopy", "canPublish"]);
9898
const [isOpen, setIsOpen] = useState(false);
9999
const [customLinkName, setCustomLinkName] = useState<string>(name);
100100

@@ -234,36 +234,71 @@ const Menu = ({ name, hasProPlan, value, onChange, onDelete }: MenuProps) => {
234234
</Grid>
235235

236236
{isFeatureEnabled("contentEditableMode") && (
237-
<Permission
238-
disabled={hasProPlan !== true}
239-
onCheckedChange={handleCheckedChange("editors")}
240-
checked={value.relation === "editors"}
241-
title="Content"
242-
info={
243-
<Flex direction="column">
244-
Recipients can edit content only, such as text, images, and
245-
predefined components.
246-
{hasProPlan !== true && (
247-
<>
248-
<br />
249-
<br />
250-
Upgrade to a Pro account to share with Content Edit
251-
permissions.
252-
<br /> <br />
253-
<Link
254-
className={buttonStyle({ color: "gradient" })}
255-
color="contrast"
256-
underline="none"
257-
href="https://webstudio.is/pricing"
258-
target="_blank"
259-
>
260-
Upgrade
261-
</Link>
262-
</>
263-
)}
264-
</Flex>
265-
}
266-
/>
237+
<>
238+
<Permission
239+
disabled={hasProPlan !== true}
240+
onCheckedChange={handleCheckedChange("editors")}
241+
checked={value.relation === "editors"}
242+
title="Content"
243+
info={
244+
<Flex direction="column">
245+
Recipients can edit content only, such as text, images, and
246+
predefined components.
247+
{hasProPlan !== true && (
248+
<>
249+
<br />
250+
<br />
251+
Upgrade to a Pro account to share with Content Edit
252+
permissions.
253+
<br /> <br />
254+
<Link
255+
className={buttonStyle({ color: "gradient" })}
256+
color="contrast"
257+
underline="none"
258+
href="https://webstudio.is/pricing"
259+
target="_blank"
260+
>
261+
Upgrade
262+
</Link>
263+
</>
264+
)}
265+
</Flex>
266+
}
267+
/>
268+
<Grid
269+
css={{
270+
ml: theme.spacing[6],
271+
}}
272+
>
273+
<Grid
274+
gap={1}
275+
flow={"column"}
276+
css={{
277+
alignItems: "center",
278+
justifyContent: "start",
279+
}}
280+
>
281+
<Checkbox
282+
disabled={
283+
hasProPlan !== true || value.relation !== "editors"
284+
}
285+
checked={value.canPublish}
286+
onCheckedChange={(canPublish) => {
287+
onChange({ ...value, canPublish: Boolean(canPublish) });
288+
}}
289+
id={ids.canPublish}
290+
/>
291+
<Label
292+
htmlFor={ids.canPublish}
293+
disabled={
294+
hasProPlan !== true || value.relation !== "editors"
295+
}
296+
>
297+
Can publish
298+
</Label>
299+
</Grid>
300+
</Grid>
301+
</>
267302
)}
268303

269304
<Permission
@@ -336,6 +371,7 @@ export type LinkOptions = {
336371
relation: Relation;
337372
canCopy: boolean;
338373
canClone: boolean;
374+
canPublish: boolean;
339375
};
340376

341377
type SharedLinkItemType = {

packages/authorization-token/src/db/authorization-token.ts

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,15 +11,31 @@ type AuthorizationToken =
1111
const applyTokenPermissions = (
1212
token: AuthorizationToken
1313
): AuthorizationToken => {
14+
let result = token;
15+
1416
if (token.relation !== "viewers") {
15-
return {
16-
...token,
17+
result = {
18+
...result,
1719
canClone: true,
1820
canCopy: true,
1921
};
2022
}
2123

22-
return token;
24+
if (token.relation === "viewers") {
25+
result = {
26+
...result,
27+
canPublish: false,
28+
};
29+
}
30+
31+
if (token.relation === "builders") {
32+
result = {
33+
...result,
34+
canPublish: false,
35+
};
36+
}
37+
38+
return result;
2339
};
2440

2541
export const findMany = async (
@@ -55,6 +71,7 @@ export const findMany = async (
5571
export const tokenDefaultPermissions = {
5672
canClone: true,
5773
canCopy: true,
74+
canPublish: true,
5875
};
5976

6077
export type TokenPermissions = typeof tokenDefaultPermissions;
@@ -89,6 +106,7 @@ export const getTokenPermissions = async (
89106
return {
90107
canClone: dbToken.canClone,
91108
canCopy: dbToken.canCopy,
109+
canPublish: dbToken.canPublish,
92110
};
93111
};
94112

@@ -168,6 +186,7 @@ export const update = async (
168186
relation: props.relation,
169187
canClone: props.canClone,
170188
canCopy: props.canCopy,
189+
canPublish: props.canPublish,
171190
})
172191
.eq("projectId", projectId)
173192
.eq("token", props.token)

packages/authorization-token/src/trpc/authorization-tokens-router.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ export const authorizationTokenRouter = router({
6868
relation: TokenProjectRelation,
6969
canClone: z.boolean(),
7070
canCopy: z.boolean(),
71+
canPublish: z.boolean(),
7172
})
7273
)
7374
.mutation(async ({ input, ctx }) => {
@@ -77,6 +78,7 @@ export const authorizationTokenRouter = router({
7778
token: input.token,
7879
name: input.name,
7980
relation: input.relation,
81+
canPublish: input.canPublish,
8082
canClone: input.canClone,
8183
canCopy: input.canCopy,
8284
},

packages/postgrest/src/__generated__/db-types.ts

Lines changed: 70 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)