mirror of
https://github.com/wassname/talk.git
synced 2026-08-08 11:28:12 +08:00
[CORL-318] Overhaul Permissions Checks on the Client (#2246)
* feat: overhaul admin permission checks * feat: overhaul stream permission checks
This commit is contained in:
@@ -10,13 +10,13 @@ import {
|
||||
import { TabBarContainer_story as StoryData } from "talk-stream/__generated__/TabBarContainer_story.graphql";
|
||||
import { TabBarContainer_viewer as ViewerData } from "talk-stream/__generated__/TabBarContainer_viewer.graphql";
|
||||
import { TabBarContainerLocal as Local } from "talk-stream/__generated__/TabBarContainerLocal.graphql";
|
||||
import { roleIsAtLeast } from "talk-stream/helpers";
|
||||
import {
|
||||
SetActiveTabInput,
|
||||
SetActiveTabMutation,
|
||||
withSetActiveTabMutation,
|
||||
} from "talk-stream/mutations";
|
||||
|
||||
import { Ability, can } from "talk-stream/permissions";
|
||||
import TabBar from "../components/TabBar";
|
||||
|
||||
interface Props {
|
||||
@@ -45,7 +45,7 @@ export class TabBarContainer extends Component<Props> {
|
||||
showProfileTab={loggedIn}
|
||||
showConfigureTab={
|
||||
!!this.props.viewer &&
|
||||
roleIsAtLeast(this.props.viewer.role, "MODERATOR")
|
||||
can(this.props.viewer, Ability.CHANGE_STORY_CONFIGURATION)
|
||||
}
|
||||
onTabClick={this.handleSetActiveTab}
|
||||
/>
|
||||
|
||||
@@ -1,13 +1,15 @@
|
||||
// TODO: use generated schema types.
|
||||
type Role =
|
||||
| "ADMIN"
|
||||
| "MODERATOR"
|
||||
| "STAFF"
|
||||
| "COMMENTER"
|
||||
| "%future added value";
|
||||
import { GQLUSER_ROLE, GQLUSER_ROLE_RL } from "talk-framework/schema";
|
||||
|
||||
const hierarchy: Role[] = ["COMMENTER", "STAFF", "MODERATOR", "ADMIN"];
|
||||
export default function roleIsAtLeast(role: Role, atLeast: Role) {
|
||||
const hierarchy: GQLUSER_ROLE_RL[] = [
|
||||
GQLUSER_ROLE.COMMENTER,
|
||||
GQLUSER_ROLE.STAFF,
|
||||
GQLUSER_ROLE.MODERATOR,
|
||||
GQLUSER_ROLE.ADMIN,
|
||||
];
|
||||
export default function roleIsAtLeast(
|
||||
role: GQLUSER_ROLE_RL,
|
||||
atLeast: GQLUSER_ROLE_RL
|
||||
) {
|
||||
[role, atLeast].forEach(r => {
|
||||
if (!hierarchy.includes(r)) {
|
||||
throw new Error(`Unknown role ${r}`);
|
||||
|
||||
@@ -14,6 +14,7 @@ import {
|
||||
MutationInput,
|
||||
MutationResponsePromise,
|
||||
} from "talk-framework/lib/relay";
|
||||
import { GQLUSER_ROLE } from "talk-framework/schema";
|
||||
import { CreateCommentMutation as MutationTypes } from "talk-stream/__generated__/CreateCommentMutation.graphql";
|
||||
|
||||
import {
|
||||
@@ -117,7 +118,8 @@ function commit(
|
||||
|
||||
// TODO: Generate and use schema types.
|
||||
const expectPremoderation =
|
||||
!roleIsAtLeast(me.role, "STAFF") && storySettings.moderation === "PRE";
|
||||
!roleIsAtLeast(me.role, GQLUSER_ROLE.STAFF) &&
|
||||
storySettings.moderation === "PRE";
|
||||
|
||||
return commitMutationPromiseNormalized<MutationTypes>(environment, {
|
||||
mutation,
|
||||
|
||||
@@ -14,6 +14,7 @@ import {
|
||||
MutationInput,
|
||||
MutationResponsePromise,
|
||||
} from "talk-framework/lib/relay";
|
||||
import { GQLUSER_ROLE } from "talk-framework/schema";
|
||||
import { CreateCommentReplyMutation as MutationTypes } from "talk-stream/__generated__/CreateCommentReplyMutation.graphql";
|
||||
|
||||
import {
|
||||
@@ -144,7 +145,8 @@ function commit(
|
||||
|
||||
// TODO: Generate and use schema types.
|
||||
const expectPremoderation =
|
||||
!roleIsAtLeast(viewer.role, "STAFF") && storySettings.moderation === "PRE";
|
||||
!roleIsAtLeast(viewer.role, GQLUSER_ROLE.STAFF) &&
|
||||
storySettings.moderation === "PRE";
|
||||
|
||||
return commitMutationPromiseNormalized<MutationTypes>(environment, {
|
||||
mutation,
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
import { mapValues } from "lodash";
|
||||
import { GQLUSER_ROLE, GQLUSER_ROLE_RL } from "talk-framework/schema";
|
||||
|
||||
/**
|
||||
* permissionMap describes what abilities certain roles have.
|
||||
*
|
||||
* This list is currently manually managed. We want to
|
||||
* get to a point where this is generated from the schema.
|
||||
*
|
||||
* We currently specify in the comments which endpoints of
|
||||
* the graph is important for the ability, which we can later
|
||||
* used to auto generate the map making the schema become
|
||||
* the single point of truth.
|
||||
*/
|
||||
const permissionMap = {
|
||||
// Mutation.updateStorySettings
|
||||
CHANGE_STORY_CONFIGURATION: [GQLUSER_ROLE.ADMIN, GQLUSER_ROLE.MODERATOR],
|
||||
};
|
||||
|
||||
export type AbilityType = keyof typeof permissionMap;
|
||||
export const Ability = mapValues(permissionMap, (_, key) => key) as {
|
||||
[P in AbilityType]: P
|
||||
};
|
||||
|
||||
/**
|
||||
* can is used to check if the `viewer` has permission for `ability`.
|
||||
*
|
||||
* Example: `can(props.me, Ability.CHANGE_ROLE)`.
|
||||
*/
|
||||
export function can(viewer: { role: GQLUSER_ROLE_RL }, ability: AbilityType) {
|
||||
return permissionMap[ability].includes(viewer.role as GQLUSER_ROLE);
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
import { GQLUSER_ROLE } from "talk-framework/schema";
|
||||
import {
|
||||
denormalizeComment,
|
||||
denormalizeComments,
|
||||
@@ -76,17 +77,17 @@ export const users = [
|
||||
{
|
||||
id: "user-0",
|
||||
username: "Markus",
|
||||
role: "COMMENTER",
|
||||
role: GQLUSER_ROLE.COMMENTER,
|
||||
},
|
||||
{
|
||||
id: "user-1",
|
||||
username: "Lukas",
|
||||
role: "COMMENTER",
|
||||
role: GQLUSER_ROLE.COMMENTER,
|
||||
},
|
||||
{
|
||||
id: "user-2",
|
||||
username: "Isabelle",
|
||||
role: "COMMENTER",
|
||||
role: GQLUSER_ROLE.COMMENTER,
|
||||
},
|
||||
];
|
||||
|
||||
@@ -399,13 +400,13 @@ export const storyWithDeepestReplies = denormalizeStory({
|
||||
export const viewerAsModerator = {
|
||||
id: "me-as-moderator",
|
||||
username: "Moderator",
|
||||
role: "MODERATOR",
|
||||
role: GQLUSER_ROLE.MODERATOR,
|
||||
};
|
||||
|
||||
export const viewerWithComments = {
|
||||
id: "me-with-comments",
|
||||
username: "Markus",
|
||||
role: "COMMENTER",
|
||||
role: GQLUSER_ROLE.COMMENTER,
|
||||
comments: {
|
||||
edges: [
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user