feat(phase2): channel permission overrides + expanded role UI + audit log cleanup
This commit is contained in:
@@ -0,0 +1,109 @@
|
||||
import { create } from 'zustand';
|
||||
import { api } from '../lib/api.ts';
|
||||
|
||||
// ponytail: mirror backend permission bitflags exactly.
|
||||
export const PERMS = {
|
||||
VIEW_CHANNEL: 1,
|
||||
SEND_MESSAGES: 2,
|
||||
MANAGE_MESSAGES: 4,
|
||||
KICK_MEMBERS: 8,
|
||||
BAN_MEMBERS: 16,
|
||||
MANAGE_SERVER: 32,
|
||||
MANAGE_CHANNELS: 64,
|
||||
ADMINISTRATOR: 128,
|
||||
CONNECT_VOICE: 256,
|
||||
SPEAK_VOICE: 512,
|
||||
SHARE_SCREEN: 1024,
|
||||
MUTE_MEMBERS: 2048,
|
||||
CREATE_INSTANT_INVITE: 4096,
|
||||
CHANGE_NICKNAME: 8192,
|
||||
MANAGE_NICKNAMES: 16384,
|
||||
MANAGE_ROLES: 32768,
|
||||
MANAGE_WEBHOOKS: 65536,
|
||||
EMBED_LINKS: 131072,
|
||||
ATTACH_FILES: 262144,
|
||||
ADD_REACTIONS: 524288,
|
||||
USE_EXTERNAL_EMOJIS: 1048576,
|
||||
MENTION_EVERYONE: 2097152,
|
||||
} as const;
|
||||
|
||||
export type PermissionKey = keyof typeof PERMS;
|
||||
|
||||
export const PERMISSION_LABELS: Record<PermissionKey, string> = {
|
||||
VIEW_CHANNEL: 'View Channel',
|
||||
SEND_MESSAGES: 'Send Messages',
|
||||
MANAGE_MESSAGES: 'Manage Messages',
|
||||
KICK_MEMBERS: 'Kick Members',
|
||||
BAN_MEMBERS: 'Ban Members',
|
||||
MANAGE_SERVER: 'Manage Server',
|
||||
MANAGE_CHANNELS: 'Manage Channels',
|
||||
ADMINISTRATOR: 'Administrator',
|
||||
CONNECT_VOICE: 'Connect Voice',
|
||||
SPEAK_VOICE: 'Speak Voice',
|
||||
SHARE_SCREEN: 'Share Screen',
|
||||
MUTE_MEMBERS: 'Mute Members',
|
||||
CREATE_INSTANT_INVITE: 'Create Instant Invite',
|
||||
CHANGE_NICKNAME: 'Change Nickname',
|
||||
MANAGE_NICKNAMES: 'Manage Nicknames',
|
||||
MANAGE_ROLES: 'Manage Roles',
|
||||
MANAGE_WEBHOOKS: 'Manage Webhooks',
|
||||
EMBED_LINKS: 'Embed Links',
|
||||
ATTACH_FILES: 'Attach Files',
|
||||
ADD_REACTIONS: 'Add Reactions',
|
||||
USE_EXTERNAL_EMOJIS: 'Use External Emojis',
|
||||
MENTION_EVERYONE: 'Mention @everyone',
|
||||
};
|
||||
|
||||
export function hasPermission(perms: number, flag: number): boolean {
|
||||
return (perms & flag) !== 0;
|
||||
}
|
||||
|
||||
export interface ChannelOverride {
|
||||
id: string;
|
||||
channel_id: string;
|
||||
target_type: 'role' | 'user';
|
||||
target_id: string;
|
||||
allow_bitflags: number;
|
||||
deny_bitflags: number;
|
||||
}
|
||||
|
||||
interface PermissionState {
|
||||
overridesByChannel: Record<string, ChannelOverride[]>;
|
||||
fetchOverrides: (channelId: string) => Promise<void>;
|
||||
setOverride: (channelId: string, targetType: 'role' | 'user', targetId: string, allow: number, deny: number) => Promise<ChannelOverride>;
|
||||
deleteOverride: (channelId: string, targetType: 'role' | 'user', targetId: string) => Promise<void>;
|
||||
}
|
||||
|
||||
export const usePermissionStore = create<PermissionState>((set) => ({
|
||||
overridesByChannel: {},
|
||||
|
||||
fetchOverrides: async (channelId) => {
|
||||
const overrides = await api.get<ChannelOverride[]>(`/servers/_/channels/${channelId}/permissions`);
|
||||
set((state) => ({
|
||||
overridesByChannel: { ...state.overridesByChannel, [channelId]: Array.isArray(overrides) ? overrides : [] },
|
||||
}));
|
||||
},
|
||||
|
||||
setOverride: async (channelId, targetType, targetId, allow, deny) => {
|
||||
const override = await api.put<ChannelOverride>(`/servers/_/channels/${channelId}/permissions/${targetType}/${targetId}`, { allow, deny });
|
||||
set((state) => {
|
||||
const list = state.overridesByChannel[channelId] || [];
|
||||
const filtered = list.filter((o) => !(o.target_type === targetType && o.target_id === targetId));
|
||||
return { overridesByChannel: { ...state.overridesByChannel, [channelId]: [...filtered, override] } };
|
||||
});
|
||||
return override;
|
||||
},
|
||||
|
||||
deleteOverride: async (channelId, targetType, targetId) => {
|
||||
await api.delete(`/servers/_/channels/${channelId}/permissions/${targetType}/${targetId}`);
|
||||
set((state) => {
|
||||
const list = state.overridesByChannel[channelId] || [];
|
||||
return {
|
||||
overridesByChannel: {
|
||||
...state.overridesByChannel,
|
||||
[channelId]: list.filter((o) => !(o.target_type === targetType && o.target_id === targetId)),
|
||||
},
|
||||
};
|
||||
});
|
||||
},
|
||||
}));
|
||||
Reference in New Issue
Block a user