mirror of
https://github.com/pocket-id/pocket-id.git
synced 2026-03-24 05:00:05 +00:00
feat: restrict oidc clients by user groups per default (#1164)
This commit is contained in:
@@ -12,6 +12,8 @@
|
||||
title,
|
||||
description,
|
||||
defaultExpanded = false,
|
||||
forcedExpanded,
|
||||
button,
|
||||
icon,
|
||||
children
|
||||
}: {
|
||||
@@ -19,7 +21,9 @@
|
||||
title: string;
|
||||
description?: string;
|
||||
defaultExpanded?: boolean;
|
||||
forcedExpanded?: boolean;
|
||||
icon?: typeof IconType;
|
||||
button?: Snippet;
|
||||
children: Snippet;
|
||||
} = $props();
|
||||
|
||||
@@ -47,6 +51,12 @@
|
||||
}
|
||||
loadExpandedState();
|
||||
});
|
||||
|
||||
$effect(() => {
|
||||
if (forcedExpanded !== undefined) {
|
||||
expanded = forcedExpanded;
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<Card.Root>
|
||||
@@ -63,11 +73,18 @@
|
||||
<Card.Description>{description}</Card.Description>
|
||||
{/if}
|
||||
</div>
|
||||
<Button class="ml-10 h-8 p-3" variant="ghost" aria-label={m.expand_card()}>
|
||||
<LucideChevronDown
|
||||
class={cn('size-5 transition-transform duration-200', expanded && 'rotate-180 transform')}
|
||||
/>
|
||||
</Button>
|
||||
{#if button}
|
||||
{@render button()}
|
||||
{:else}
|
||||
<Button class="ml-10 h-8 p-3" variant="ghost" aria-label={m.expand_card()}>
|
||||
<LucideChevronDown
|
||||
class={cn(
|
||||
'size-5 transition-transform duration-200',
|
||||
expanded && 'rotate-180 transform'
|
||||
)}
|
||||
/>
|
||||
</Button>
|
||||
{/if}
|
||||
</div>
|
||||
</Card.Header>
|
||||
{#if expanded}
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
selectedIds = $bindable(),
|
||||
withoutSearch = false,
|
||||
selectionDisabled = false,
|
||||
rowSelectionDisabled,
|
||||
fetchCallback,
|
||||
defaultSort,
|
||||
columns,
|
||||
@@ -34,6 +35,7 @@
|
||||
selectedIds?: string[];
|
||||
withoutSearch?: boolean;
|
||||
selectionDisabled?: boolean;
|
||||
rowSelectionDisabled?: (item: T) => boolean;
|
||||
fetchCallback: (requestOptions: ListRequestOptions) => Promise<Paginated<T>>;
|
||||
defaultSort?: SortRequest;
|
||||
columns: AdvancedTableColumn<T>[];
|
||||
@@ -91,7 +93,9 @@
|
||||
});
|
||||
|
||||
async function onAllCheck(checked: boolean) {
|
||||
const pageIds = items!.data.map((item) => item.id);
|
||||
const pageIds = items!.data
|
||||
.filter((item) => !rowSelectionDisabled?.(item))
|
||||
.map((item) => item.id);
|
||||
const current = selectedIds ?? [];
|
||||
|
||||
if (checked) {
|
||||
@@ -264,7 +268,7 @@
|
||||
{#if selectedIds}
|
||||
<Table.Cell class="w-12">
|
||||
<Checkbox
|
||||
disabled={selectionDisabled}
|
||||
disabled={selectionDisabled || rowSelectionDisabled?.(item)}
|
||||
checked={selectedIds.includes(item.id)}
|
||||
onCheckedChange={(c: boolean) => onCheck(c, item.id)}
|
||||
/>
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
import { m } from '$lib/paraglide/messages';
|
||||
import UserGroupService from '$lib/services/user-group-service';
|
||||
import type { AdvancedTableColumn } from '$lib/types/advanced-table.type';
|
||||
import type { UserGroupWithUserCount } from '$lib/types/user-group.type';
|
||||
import type { UserGroupMinimal } from '$lib/types/user-group.type';
|
||||
|
||||
let {
|
||||
selectionDisabled = false,
|
||||
@@ -15,7 +15,7 @@
|
||||
|
||||
const userGroupService = new UserGroupService();
|
||||
|
||||
const columns: AdvancedTableColumn<UserGroupWithUserCount>[] = [
|
||||
const columns: AdvancedTableColumn<UserGroupMinimal>[] = [
|
||||
{ label: 'ID', column: 'id', hidden: true },
|
||||
{ label: m.friendly_name(), column: 'friendlyName', sortable: true },
|
||||
{ label: m.name(), column: 'name', sortable: true },
|
||||
|
||||
@@ -1,30 +1,26 @@
|
||||
import type { ListRequestOptions, Paginated } from '$lib/types/list-request.type';
|
||||
import type {
|
||||
UserGroupCreate,
|
||||
UserGroupWithUserCount,
|
||||
UserGroupWithUsers
|
||||
} from '$lib/types/user-group.type';
|
||||
import type { UserGroup, UserGroupCreate, UserGroupMinimal } from '$lib/types/user-group.type';
|
||||
import APIService from './api-service';
|
||||
|
||||
export default class UserGroupService extends APIService {
|
||||
list = async (options?: ListRequestOptions) => {
|
||||
const res = await this.api.get('/user-groups', { params: options });
|
||||
return res.data as Paginated<UserGroupWithUserCount>;
|
||||
return res.data as Paginated<UserGroupMinimal>;
|
||||
};
|
||||
|
||||
get = async (id: string) => {
|
||||
const res = await this.api.get(`/user-groups/${id}`);
|
||||
return res.data as UserGroupWithUsers;
|
||||
return res.data as UserGroup;
|
||||
};
|
||||
|
||||
create = async (user: UserGroupCreate) => {
|
||||
const res = await this.api.post('/user-groups', user);
|
||||
return res.data as UserGroupWithUsers;
|
||||
return res.data as UserGroup;
|
||||
};
|
||||
|
||||
update = async (id: string, user: UserGroupCreate) => {
|
||||
const res = await this.api.put(`/user-groups/${id}`, user);
|
||||
return res.data as UserGroupWithUsers;
|
||||
return res.data as UserGroup;
|
||||
};
|
||||
|
||||
remove = async (id: string) => {
|
||||
@@ -33,6 +29,11 @@ export default class UserGroupService extends APIService {
|
||||
|
||||
updateUsers = async (id: string, userIds: string[]) => {
|
||||
const res = await this.api.put(`/user-groups/${id}/users`, { userIds });
|
||||
return res.data as UserGroupWithUsers;
|
||||
return res.data as UserGroup;
|
||||
};
|
||||
|
||||
updateAllowedOidcClients = async (id: string, oidcClientIds: string[]) => {
|
||||
const res = await this.api.put(`/user-groups/${id}/allowed-oidc-clients`, { oidcClientIds });
|
||||
return res.data as UserGroup;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -28,6 +28,7 @@ export type OidcClient = OidcClientMetaData & {
|
||||
requiresReauthentication: boolean;
|
||||
credentials?: OidcClientCredentials;
|
||||
launchURL?: string;
|
||||
isGroupRestricted: boolean;
|
||||
};
|
||||
|
||||
export type OidcClientWithAllowedUserGroups = OidcClient & {
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import type { CustomClaim } from './custom-claim.type';
|
||||
import type { OidcClientMetaData } from './oidc.type';
|
||||
import type { User } from './user.type';
|
||||
|
||||
export type UserGroup = {
|
||||
@@ -8,13 +9,11 @@ export type UserGroup = {
|
||||
createdAt: string;
|
||||
customClaims: CustomClaim[];
|
||||
ldapId?: string;
|
||||
};
|
||||
|
||||
export type UserGroupWithUsers = UserGroup & {
|
||||
users: User[];
|
||||
allowedOidcClients: OidcClientMetaData[];
|
||||
};
|
||||
|
||||
export type UserGroupWithUserCount = UserGroup & {
|
||||
export type UserGroupMinimal = Omit<UserGroup, 'users' | 'allowedOidcClients'> & {
|
||||
userCount: number;
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user