Compare commits

..

1 Commits

Author SHA1 Message Date
4c0cc7faed Manage user space users #15
Some checks failed
Test API before pr merge / test-lint (pull_request) Successful in 11s
Test before pr merge / test-translation-lint (pull_request) Successful in 40s
Test before pr merge / test-lint (pull_request) Failing after 44s
Test before pr merge / test-before-merge (pull_request) Failing after 1m35s
2025-05-01 16:04:22 +02:00
19 changed files with 50 additions and 144 deletions

View File

@ -1,5 +1,5 @@
from abc import abstractmethod from abc import abstractmethod
from typing import Type, Union, Any from typing import Type, Union
from api_graphql.abc.query_abc import QueryABC from api_graphql.abc.query_abc import QueryABC
from api_graphql.field.mutation_field_builder import MutationFieldBuilder from api_graphql.field.mutation_field_builder import MutationFieldBuilder

View File

@ -240,18 +240,6 @@ class QueryABC(ObjectType):
): ):
await self._require_any_permission(field.require_any_permission) await self._require_any_permission(field.require_any_permission)
if isinstance(field, MutationField):
if field.require_any is not None:
await self._require_any(
None,
*field.require_any,
*args,
**kwargs,
)
result = await resolver(*args, **kwargs)
return result
result = await resolver(*args, **kwargs) result = await resolver(*args, **kwargs)
if field.require_any is not None: if field.require_any is not None:

View File

@ -1,6 +1,4 @@
from api_graphql.abc.mutation_abc import MutationABC from api_graphql.abc.mutation_abc import MutationABC
from api_graphql.require_any_resolvers import has_assigned_user_spaces
from api_graphql.service.query_context import QueryContext
from service.permission.permissions_enum import Permissions from service.permission.permissions_enum import Permissions
@ -53,32 +51,26 @@ class Mutation(MutationABC):
Permissions.user_spaces_update, Permissions.user_spaces_update,
Permissions.user_spaces_delete, Permissions.user_spaces_delete,
], ],
[lambda ctx: True], [self._test],
), ),
) )
self.add_mutation_type( self.add_mutation_type(
"group", "group",
"Group", "Group",
require_any=( require_any_permission=[
[
Permissions.groups_create, Permissions.groups_create,
Permissions.groups_update, Permissions.groups_update,
Permissions.groups_delete, Permissions.groups_delete,
], ],
[has_assigned_user_spaces],
),
) )
self.add_mutation_type( self.add_mutation_type(
"shortUrl", "shortUrl",
"ShortUrl", "ShortUrl",
require_any=( require_any_permission=[
[
Permissions.short_urls_create, Permissions.short_urls_create,
Permissions.short_urls_update, Permissions.short_urls_update,
Permissions.short_urls_delete, Permissions.short_urls_delete,
], ],
[has_assigned_user_spaces],
),
) )
self.add_mutation_type( self.add_mutation_type(
@ -103,3 +95,7 @@ class Mutation(MutationABC):
"privacy", "privacy",
"Privacy", "Privacy",
) )
@staticmethod
async def _test(*args, **kwargs):
return True

View File

@ -4,7 +4,6 @@ from api_graphql.abc.mutation_abc import MutationABC
from api_graphql.field.mutation_field_builder import MutationFieldBuilder from api_graphql.field.mutation_field_builder import MutationFieldBuilder
from api_graphql.input.group_create_input import GroupCreateInput from api_graphql.input.group_create_input import GroupCreateInput
from api_graphql.input.group_update_input import GroupUpdateInput from api_graphql.input.group_update_input import GroupUpdateInput
from api_graphql.require_any_resolvers import has_assigned_user_spaces
from core.logger import APILogger from core.logger import APILogger
from core.string import first_to_lower from core.string import first_to_lower
from data.schemas.public.group import Group from data.schemas.public.group import Group
@ -27,7 +26,7 @@ class GroupMutation(MutationABC):
.with_change_broadcast( .with_change_broadcast(
f"{first_to_lower(self.name.replace("Mutation", ""))}Change" f"{first_to_lower(self.name.replace("Mutation", ""))}Change"
) )
.with_require_any([Permissions.groups_create], [has_assigned_user_spaces]) .with_require_any_permission([Permissions.groups_create])
) )
self.field( self.field(
@ -37,7 +36,7 @@ class GroupMutation(MutationABC):
.with_change_broadcast( .with_change_broadcast(
f"{first_to_lower(self.name.replace("Mutation", ""))}Change" f"{first_to_lower(self.name.replace("Mutation", ""))}Change"
) )
.with_require_any([Permissions.groups_update], [has_assigned_user_spaces]) .with_require_any_permission([Permissions.groups_update])
) )
self.field( self.field(
@ -46,7 +45,7 @@ class GroupMutation(MutationABC):
.with_change_broadcast( .with_change_broadcast(
f"{first_to_lower(self.name.replace("Mutation", ""))}Change" f"{first_to_lower(self.name.replace("Mutation", ""))}Change"
) )
.with_require_any([Permissions.groups_delete], [has_assigned_user_spaces]) .with_require_any_permission([Permissions.groups_delete])
) )
self.field( self.field(
@ -55,7 +54,7 @@ class GroupMutation(MutationABC):
.with_change_broadcast( .with_change_broadcast(
f"{first_to_lower(self.name.replace("Mutation", ""))}Change" f"{first_to_lower(self.name.replace("Mutation", ""))}Change"
) )
.with_require_any([Permissions.groups_delete], [has_assigned_user_spaces]) .with_require_any_permission([Permissions.groups_delete])
) )
@staticmethod @staticmethod
@ -114,7 +113,9 @@ class GroupMutation(MutationABC):
raise ValueError(f"Group with id {obj.id} not found") raise ValueError(f"Group with id {obj.id} not found")
if obj.name is not None: if obj.name is not None:
already_exists = await groupDao.find_by({Group.name: obj.name}) already_exists = await groupDao.find_by(
{Group.name: obj.name, Group.id: {"ne": obj.id}}
)
if len(already_exists) > 0: if len(already_exists) > 0:
raise ValueError(f"Group {obj.name} already exists") raise ValueError(f"Group {obj.name} already exists")

View File

@ -3,7 +3,6 @@ from api_graphql.abc.mutation_abc import MutationABC
from api_graphql.field.mutation_field_builder import MutationFieldBuilder from api_graphql.field.mutation_field_builder import MutationFieldBuilder
from api_graphql.input.short_url_create_input import ShortUrlCreateInput from api_graphql.input.short_url_create_input import ShortUrlCreateInput
from api_graphql.input.short_url_update_input import ShortUrlUpdateInput from api_graphql.input.short_url_update_input import ShortUrlUpdateInput
from api_graphql.require_any_resolvers import has_assigned_user_spaces
from core.logger import APILogger from core.logger import APILogger
from core.string import first_to_lower from core.string import first_to_lower
from data.schemas.public.domain_dao import domainDao from data.schemas.public.domain_dao import domainDao
@ -28,9 +27,7 @@ class ShortUrlMutation(MutationABC):
.with_change_broadcast( .with_change_broadcast(
f"{first_to_lower(self.name.replace("Mutation", ""))}Change" f"{first_to_lower(self.name.replace("Mutation", ""))}Change"
) )
.with_require_any( .with_require_any_permission([Permissions.short_urls_create])
[Permissions.short_urls_create], [has_assigned_user_spaces]
)
) )
self.field( self.field(
@ -40,9 +37,7 @@ class ShortUrlMutation(MutationABC):
.with_change_broadcast( .with_change_broadcast(
f"{first_to_lower(self.name.replace("Mutation", ""))}Change" f"{first_to_lower(self.name.replace("Mutation", ""))}Change"
) )
.with_require_any( .with_require_any_permission([Permissions.short_urls_update])
[Permissions.short_urls_update], [has_assigned_user_spaces]
)
) )
self.field( self.field(
@ -51,9 +46,7 @@ class ShortUrlMutation(MutationABC):
.with_change_broadcast( .with_change_broadcast(
f"{first_to_lower(self.name.replace("Mutation", ""))}Change" f"{first_to_lower(self.name.replace("Mutation", ""))}Change"
) )
.with_require_any( .with_require_any_permission([Permissions.short_urls_delete])
[Permissions.short_urls_delete], [has_assigned_user_spaces]
)
) )
self.field( self.field(
@ -62,9 +55,7 @@ class ShortUrlMutation(MutationABC):
.with_change_broadcast( .with_change_broadcast(
f"{first_to_lower(self.name.replace("Mutation", ""))}Change" f"{first_to_lower(self.name.replace("Mutation", ""))}Change"
) )
.with_require_any( .with_require_any_permission([Permissions.short_urls_delete])
[Permissions.short_urls_delete], [has_assigned_user_spaces]
)
) )
self.field( self.field(

View File

@ -29,6 +29,9 @@ class UserSpaceMutation(MutationABC):
) )
) )
async def _xzy(ctx: QueryContext):
pass
self.field( self.field(
MutationFieldBuilder("update") MutationFieldBuilder("update")
.with_resolver(self.resolve_update) .with_resolver(self.resolve_update)
@ -36,10 +39,7 @@ class UserSpaceMutation(MutationABC):
.with_change_broadcast( .with_change_broadcast(
f"{first_to_lower(self.name.replace("Mutation", ""))}Change" f"{first_to_lower(self.name.replace("Mutation", ""))}Change"
) )
.with_require_any( .with_require_any([Permissions.user_spaces_update], [_xzy])
[Permissions.user_spaces_update],
[self._resolve_input_user_space_assigned],
)
) )
self.field( self.field(
@ -48,10 +48,7 @@ class UserSpaceMutation(MutationABC):
.with_change_broadcast( .with_change_broadcast(
f"{first_to_lower(self.name.replace("Mutation", ""))}Change" f"{first_to_lower(self.name.replace("Mutation", ""))}Change"
) )
.with_require_any( .with_require_any([Permissions.user_spaces_delete], [_xzy])
[Permissions.user_spaces_delete],
[self._resolve_input_user_space_assigned],
)
) )
self.field( self.field(
@ -71,8 +68,7 @@ class UserSpaceMutation(MutationABC):
f"{first_to_lower(self.name.replace("Mutation", ""))}Change" f"{first_to_lower(self.name.replace("Mutation", ""))}Change"
) )
.with_require_any( .with_require_any(
[Permissions.user_spaces_create, Permissions.user_spaces_update], [Permissions.user_spaces_create, Permissions.user_spaces_update], [_xzy]
[self._resolve_input_user_space_assigned],
) )
) )
@ -143,13 +139,3 @@ class UserSpaceMutation(MutationABC):
async def resolve_invite_users(self, emails: list[str], *_): async def resolve_invite_users(self, emails: list[str], *_):
pass pass
@staticmethod
async def _resolve_input_user_space_assigned(ctx: QueryContext):
check_dict = ctx.kwargs
if "input" in ctx.kwargs:
check_dict = ctx.kwargs["input"]
return "id" in check_dict and check_dict["id"] in [
x.id for x in await userSpaceDao.get_assigned_by_user_id(ctx.user.id)
]

View File

@ -15,8 +15,6 @@ from api_graphql.filter.user_filter import UserFilter
from api_graphql.filter.user_space_filter import UserSpaceFilter from api_graphql.filter.user_space_filter import UserSpaceFilter
from api_graphql.require_any_resolvers import ( from api_graphql.require_any_resolvers import (
by_group_assignment_resolver, by_group_assignment_resolver,
by_user_space_assignment_resolver,
has_assigned_user_spaces,
) )
from data.schemas.administration.api_key import ApiKey from data.schemas.administration.api_key import ApiKey
from data.schemas.administration.api_key_dao import apiKeyDao from data.schemas.administration.api_key_dao import apiKeyDao
@ -59,21 +57,19 @@ class Query(QueryABC):
.with_filter(PermissionFilter) .with_filter(PermissionFilter)
.with_sort(Sort[Permission]) .with_sort(Sort[Permission])
) )
self.field( self.field(
DaoFieldBuilder("roles") DaoFieldBuilder("roles")
.with_dao(roleDao) .with_dao(roleDao)
.with_filter(RoleFilter) .with_filter(RoleFilter)
.with_sort(Sort[Role]) .with_sort(Sort[Role])
.with_require_any( .with_require_any_permission(
[ [
Permissions.roles, Permissions.roles,
Permissions.users_create, Permissions.users_create,
Permissions.users_update, Permissions.users_update,
Permissions.groups_create, Permissions.groups_create,
Permissions.groups_update, Permissions.groups_update,
], ]
[has_assigned_user_spaces],
) )
) )
@ -111,13 +107,12 @@ class Query(QueryABC):
.with_dao(domainDao) .with_dao(domainDao)
.with_filter(DomainFilter) .with_filter(DomainFilter)
.with_sort(Sort[Domain]) .with_sort(Sort[Domain])
.with_require_any( .with_require_any_permission(
[ [
Permissions.domains, Permissions.domains,
Permissions.domains_create, Permissions.domains_create,
Permissions.domains_update, Permissions.domains_update,
], ]
[has_assigned_user_spaces]
) )
) )
@ -132,11 +127,10 @@ class Query(QueryABC):
.with_dao(userSpaceDao) .with_dao(userSpaceDao)
.with_filter(UserSpaceFilter) .with_filter(UserSpaceFilter)
.with_sort(Sort[UserSpace]) .with_sort(Sort[UserSpace])
.with_require_any( .with_require_any_permission(
[ [
Permissions.user_spaces, Permissions.user_spaces,
], ]
[lambda ctx: all(x.owner_id == ctx.user.id for x in ctx.data.nodes)]
) )
) )
@ -151,7 +145,7 @@ class Query(QueryABC):
Permissions.short_urls_create, Permissions.short_urls_create,
Permissions.short_urls_update, Permissions.short_urls_update,
], ],
[by_user_space_assignment_resolver, by_group_assignment_resolver], [by_group_assignment_resolver],
) )
) )
@ -162,7 +156,7 @@ class Query(QueryABC):
.with_sort(Sort[ShortUrl]) .with_sort(Sort[ShortUrl])
.with_require_any( .with_require_any(
[Permissions.short_urls], [Permissions.short_urls],
[by_user_space_assignment_resolver, by_group_assignment_resolver], [by_group_assignment_resolver],
) )
) )

View File

@ -1,7 +1,6 @@
from api_graphql.service.collection_result import CollectionResult from api_graphql.service.collection_result import CollectionResult
from api_graphql.service.query_context import QueryContext from api_graphql.service.query_context import QueryContext
from data.schemas.public.group_dao import groupDao from data.schemas.public.group_dao import groupDao
from data.schemas.public.user_space_dao import userSpaceDao
from data.schemas.public.user_space_user_dao import userSpaceUserDao from data.schemas.public.user_space_user_dao import userSpaceUserDao
from service.permission.permissions_enum import Permissions from service.permission.permissions_enum import Permissions
@ -10,13 +9,10 @@ async def by_user_space_assignment_resolver(ctx: QueryContext) -> bool:
if not isinstance(ctx.data, CollectionResult): if not isinstance(ctx.data, CollectionResult):
return False return False
if len(ctx.data.nodes) == 0:
return True
user = ctx.user user = ctx.user
assigned_user_space_ids = { assigned_user_space_ids = {
us.user_space_id for us in await userSpaceUserDao.get_by_user_id(user.id) us.user_space_id for us in await userSpaceUserDao.find_by_user_id(user.id)
} }
for node in ctx.data.nodes: for node in ctx.data.nodes:
@ -27,7 +23,7 @@ async def by_user_space_assignment_resolver(ctx: QueryContext) -> bool:
if user_space.owner_id == user.id or user_space.id in assigned_user_space_ids: if user_space.owner_id == user.id or user_space.id in assigned_user_space_ids:
return True return True
return len(ctx.data.nodes) == 0 return False
async def by_group_assignment_resolver(ctx: QueryContext) -> bool: async def by_group_assignment_resolver(ctx: QueryContext) -> bool:
@ -51,8 +47,3 @@ async def by_group_assignment_resolver(ctx: QueryContext) -> bool:
) )
return False return False
async def has_assigned_user_spaces(ctx: QueryContext):
user_spaces = await userSpaceDao.get_assigned_by_user_id(ctx.user.id)
return len(user_spaces) > 0

View File

@ -1,6 +1,5 @@
from api_graphql.abc.subscription_abc import SubscriptionABC from api_graphql.abc.subscription_abc import SubscriptionABC
from api_graphql.field.subscription_field_builder import SubscriptionFieldBuilder from api_graphql.field.subscription_field_builder import SubscriptionFieldBuilder
from api_graphql.require_any_resolvers import has_assigned_user_spaces
from service.permission.permissions_enum import Permissions from service.permission.permissions_enum import Permissions
@ -69,10 +68,10 @@ class Subscription(SubscriptionABC):
self.subscribe( self.subscribe(
SubscriptionFieldBuilder("groupChange") SubscriptionFieldBuilder("groupChange")
.with_resolver(lambda message, *_: message.message) .with_resolver(lambda message, *_: message.message)
.with_require_any([Permissions.groups], [has_assigned_user_spaces]) .with_require_any_permission([Permissions.groups])
) )
self.subscribe( self.subscribe(
SubscriptionFieldBuilder("shortUrlChange") SubscriptionFieldBuilder("shortUrlChange")
.with_resolver(lambda message, *_: message.message) .with_resolver(lambda message, *_: message.message)
.with_require_any([Permissions.short_urls], [has_assigned_user_spaces]) .with_require_any_permission([Permissions.short_urls])
) )

View File

@ -4,7 +4,6 @@ import { Logger } from 'src/app/service/logger.service';
import { ToastService } from 'src/app/service/toast.service'; import { ToastService } from 'src/app/service/toast.service';
import { AuthService } from 'src/app/service/auth.service'; import { AuthService } from 'src/app/service/auth.service';
import { PermissionsEnum } from 'src/app/model/auth/permissionsEnum'; import { PermissionsEnum } from 'src/app/model/auth/permissionsEnum';
import { SidebarService } from 'src/app/service/sidebar.service';
const log = new Logger('PermissionGuard'); const log = new Logger('PermissionGuard');
@ -15,20 +14,11 @@ export class PermissionGuard {
constructor( constructor(
private router: Router, private router: Router,
private toast: ToastService, private toast: ToastService,
private auth: AuthService, private auth: AuthService
private sidebar: SidebarService
) {} ) {}
async canActivate(route: ActivatedRouteSnapshot): Promise<boolean> { async canActivate(route: ActivatedRouteSnapshot): Promise<boolean> {
const permissions = route.data['permissions'] as PermissionsEnum[]; const permissions = route.data['permissions'] as PermissionsEnum[];
const isInUserSpace = route.data['isInUserSpace'] as boolean;
if (isInUserSpace) {
return (
this.sidebar.selectedUserSpace$.value !== undefined &&
this.sidebar.selectedUserSpace$.value !== null
);
}
if (!permissions || permissions.length === 0) { if (!permissions || permissions.length === 0) {
return true; return true;

View File

@ -13,7 +13,6 @@ export function initializeKeycloak(
}, },
initOptions: { initOptions: {
onLoad: 'check-sso', onLoad: 'check-sso',
checkLoginIframe: false,
}, },
enableBearerInterceptor: false, enableBearerInterceptor: false,
}); });

View File

@ -4,7 +4,6 @@ import { DbModelWithHistory } from 'src/app/model/entities/db-model';
export interface UserSpace extends DbModelWithHistory { export interface UserSpace extends DbModelWithHistory {
id: number; id: number;
name: string; name: string;
owner?: User;
users?: User[]; users?: User[];
} }

View File

@ -18,7 +18,7 @@ const routes: Routes = [
m => m.GroupsModule m => m.GroupsModule
), ),
canActivate: [PermissionGuard], canActivate: [PermissionGuard],
data: { permissions: [PermissionsEnum.groups], isInUserSpace: true }, data: { permissions: [PermissionsEnum.groups] },
}, },
{ {
path: 'urls', path: 'urls',
@ -32,7 +32,6 @@ const routes: Routes = [
PermissionsEnum.shortUrls, PermissionsEnum.shortUrls,
PermissionsEnum.shortUrlsByAssignment, PermissionsEnum.shortUrlsByAssignment,
], ],
isInUserSpace: true,
}, },
}, },
{ {

View File

@ -22,7 +22,6 @@ const routes: Routes = [
canActivate: [PermissionGuard], canActivate: [PermissionGuard],
data: { data: {
permissions: [PermissionsEnum.groupsCreate], permissions: [PermissionsEnum.groupsCreate],
isInUserSpace: true,
}, },
}, },
{ {
@ -31,7 +30,6 @@ const routes: Routes = [
canActivate: [PermissionGuard], canActivate: [PermissionGuard],
data: { data: {
permissions: [PermissionsEnum.groupsUpdate], permissions: [PermissionsEnum.groupsUpdate],
isInUserSpace: true,
}, },
}, },
{ {
@ -40,7 +38,6 @@ const routes: Routes = [
canActivate: [PermissionGuard], canActivate: [PermissionGuard],
data: { data: {
permissions: [PermissionsEnum.groups], permissions: [PermissionsEnum.groups],
isInUserSpace: true,
}, },
}, },
], ],

View File

@ -22,7 +22,6 @@ const routes: Routes = [
canActivate: [PermissionGuard], canActivate: [PermissionGuard],
data: { data: {
permissions: [PermissionsEnum.shortUrlsCreate], permissions: [PermissionsEnum.shortUrlsCreate],
isInUserSpace: true,
}, },
}, },
{ {
@ -31,7 +30,6 @@ const routes: Routes = [
canActivate: [PermissionGuard], canActivate: [PermissionGuard],
data: { data: {
permissions: [PermissionsEnum.shortUrlsUpdate], permissions: [PermissionsEnum.shortUrlsUpdate],
isInUserSpace: true,
}, },
}, },
{ {
@ -40,7 +38,6 @@ const routes: Routes = [
canActivate: [PermissionGuard], canActivate: [PermissionGuard],
data: { data: {
permissions: [PermissionsEnum.shortUrls], permissions: [PermissionsEnum.shortUrls],
isInUserSpace: true,
}, },
}, },
], ],

View File

@ -13,7 +13,6 @@ import { ConfigService } from 'src/app/service/config.service';
import { ResolvedTableColumn } from 'src/app/modules/shared/components/table/table.model'; import { ResolvedTableColumn } from 'src/app/modules/shared/components/table/table.model';
import { SidebarService } from 'src/app/service/sidebar.service'; import { SidebarService } from 'src/app/service/sidebar.service';
import { takeUntil } from 'rxjs/operators'; import { takeUntil } from 'rxjs/operators';
import { Router } from '@angular/router';
@Component({ @Component({
selector: 'app-short-urls', selector: 'app-short-urls',
@ -62,8 +61,7 @@ export class ShortUrlsPage extends PageBase<
private toast: ToastService, private toast: ToastService,
private confirmation: ConfirmationDialogService, private confirmation: ConfirmationDialogService,
private config: ConfigService, private config: ConfigService,
private sidebar: SidebarService, private sidebar: SidebarService
private router: Router
) { ) {
super(true, { super(true, {
read: [], read: [],

View File

@ -57,10 +57,6 @@ export class UserSpacesDataService
nodes { nodes {
id id
name name
owner {
id
username
}
...DB_MODEL ...DB_MODEL
} }
@ -89,11 +85,6 @@ export class UserSpacesDataService
id id
name name
owner {
id
username
}
users { users {
id id
username username

View File

@ -24,11 +24,6 @@ export class SidebarDataService {
nodes { nodes {
id id
name name
owner {
id
username
}
} }
} }
} }

View File

@ -72,9 +72,6 @@ export class SidebarService {
// trust me, you'll need this async // trust me, you'll need this async
async setElements() { async setElements() {
const isSelectedUserSpaceOwner =
this.selectedUserSpace$.value?.owner?.id === this.auth.user$.value?.id;
const elements: MenuElement[] = [ const elements: MenuElement[] = [
{ {
label: 'sidebar.user_spaces', label: 'sidebar.user_spaces',
@ -111,7 +108,6 @@ export class SidebarService {
{ {
label: 'sidebar.user_space_edit', label: 'sidebar.user_space_edit',
icon: 'pi pi-pencil', icon: 'pi pi-pencil',
visible: isSelectedUserSpaceOwner,
routerLink: [ routerLink: [
`/admin/rooms/edit/${this.selectedUserSpace$.value?.id}`, `/admin/rooms/edit/${this.selectedUserSpace$.value?.id}`,
], ],
@ -121,7 +117,7 @@ export class SidebarService {
icon: 'pi pi-tags', icon: 'pi pi-tags',
routerLink: ['/admin/groups'], routerLink: ['/admin/groups'],
visible: visible:
!!this.selectedUserSpace$.value || this.selectedUserSpace$.value !== null &&
(await this.auth.hasAnyPermissionLazy([PermissionsEnum.groups])), (await this.auth.hasAnyPermissionLazy([PermissionsEnum.groups])),
}, },
{ {
@ -129,7 +125,7 @@ export class SidebarService {
icon: 'pi pi-tag', icon: 'pi pi-tag',
routerLink: ['/admin/urls'], routerLink: ['/admin/urls'],
visible: visible:
!!this.selectedUserSpace$.value || this.selectedUserSpace$.value !== null &&
(await this.auth.hasAnyPermissionLazy([ (await this.auth.hasAnyPermissionLazy([
PermissionsEnum.shortUrls, PermissionsEnum.shortUrls,
PermissionsEnum.shortUrlsByAssignment, PermissionsEnum.shortUrlsByAssignment,
@ -138,7 +134,6 @@ export class SidebarService {
{ {
label: 'sidebar.user_space_delete', label: 'sidebar.user_space_delete',
icon: 'pi pi-trash', icon: 'pi pi-trash',
visible: isSelectedUserSpaceOwner,
command: () => { command: () => {
this.confirmation.confirmDialog({ this.confirmation.confirmDialog({
header: 'dialog.delete.header', header: 'dialog.delete.header',