[WIP] User space handling
Some checks failed
Test API before pr merge / test-lint (pull_request) Failing after 9s
Test before pr merge / test-lint (pull_request) Successful in 39s
Test before pr merge / test-translation-lint (pull_request) Successful in 34s
Test before pr merge / test-before-merge (pull_request) Successful in 1m36s
Some checks failed
Test API before pr merge / test-lint (pull_request) Failing after 9s
Test before pr merge / test-lint (pull_request) Successful in 39s
Test before pr merge / test-translation-lint (pull_request) Successful in 34s
Test before pr merge / test-before-merge (pull_request) Successful in 1m36s
This commit is contained in:
parent
d190d2f218
commit
0ed3cb846d
@ -1,7 +1,9 @@
|
|||||||
from api.route import Route
|
from api.route import Route
|
||||||
from api_graphql.abc.mutation_abc import MutationABC
|
from api_graphql.abc.mutation_abc import MutationABC
|
||||||
|
from api_graphql.field.mutation_field_builder import MutationFieldBuilder
|
||||||
from api_graphql.input.user_setting_input import UserSettingInput
|
from api_graphql.input.user_setting_input import UserSettingInput
|
||||||
from core.logger import APILogger
|
from core.logger import APILogger
|
||||||
|
from core.string import first_to_lower
|
||||||
from data.schemas.public.user_setting import UserSetting
|
from data.schemas.public.user_setting import UserSetting
|
||||||
from data.schemas.public.user_setting_dao import userSettingsDao
|
from data.schemas.public.user_setting_dao import userSettingsDao
|
||||||
from data.schemas.system.setting_dao import settingsDao
|
from data.schemas.system.setting_dao import settingsDao
|
||||||
@ -13,12 +15,19 @@ logger = APILogger(__name__)
|
|||||||
class UserSettingMutation(MutationABC):
|
class UserSettingMutation(MutationABC):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
MutationABC.__init__(self, "UserSetting")
|
MutationABC.__init__(self, "UserSetting")
|
||||||
self.mutation(
|
self.field(
|
||||||
"change",
|
MutationFieldBuilder("change")
|
||||||
self.resolve_change,
|
.with_resolver(self.resolve_change)
|
||||||
UserSettingInput,
|
.with_change_broadcast(
|
||||||
require_any_permission=[Permissions.settings_update],
|
f"{first_to_lower(self.name.replace("Mutation", ""))}Change"
|
||||||
)
|
)
|
||||||
|
.with_input(UserSettingInput, "input")
|
||||||
|
.with_require_any([], [self._x])
|
||||||
|
)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
async def _x(ctx):
|
||||||
|
return ctx.data.user_id == (await Route.get_user()).id
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
async def resolve_change(obj: UserSettingInput, *_):
|
async def resolve_change(obj: UserSettingInput, *_):
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
from typing import Union
|
||||||
|
|
||||||
from core.configuration.feature_flags_enum import FeatureFlagsEnum
|
from core.configuration.feature_flags_enum import FeatureFlagsEnum
|
||||||
from core.environment import Environment
|
from core.environment import Environment
|
||||||
from data.schemas.system.feature_flag_dao import featureFlagDao
|
from data.schemas.system.feature_flag_dao import featureFlagDao
|
||||||
@ -6,19 +8,31 @@ from data.schemas.system.feature_flag_dao import featureFlagDao
|
|||||||
class FeatureFlags:
|
class FeatureFlags:
|
||||||
_flags = {
|
_flags = {
|
||||||
FeatureFlagsEnum.version_endpoint.value: True, # 15.01.2025
|
FeatureFlagsEnum.version_endpoint.value: True, # 15.01.2025
|
||||||
|
FeatureFlagsEnum.technical_demo_banner.value: False, # 18.04.2025
|
||||||
FeatureFlagsEnum.per_user_setup.value: Environment.get(
|
FeatureFlagsEnum.per_user_setup.value: Environment.get(
|
||||||
"PER_USER_SETUP", bool, False
|
"PER_USER_SETUP", bool, False
|
||||||
), # 18.04.2025
|
), # 18.04.2025
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_overwrite_flags = [
|
||||||
|
FeatureFlagsEnum.per_user_setup.value,
|
||||||
|
]
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def overwrite_flag(key: str):
|
||||||
|
return key in FeatureFlags._overwrite_flags
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def get_default(key: FeatureFlagsEnum) -> bool:
|
def get_default(key: FeatureFlagsEnum) -> bool:
|
||||||
return FeatureFlags._flags[key.value]
|
return FeatureFlags._flags[key.value]
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
async def has_feature(key: FeatureFlagsEnum) -> bool:
|
async def has_feature(key: Union[str, FeatureFlagsEnum]) -> bool:
|
||||||
value = await featureFlagDao.find_by_key(key.value)
|
key_value = key.value if isinstance(key, FeatureFlagsEnum) else key
|
||||||
if value is None:
|
|
||||||
return FeatureFlags.get_default(key)
|
|
||||||
|
|
||||||
return value.value
|
value = await featureFlagDao.find_by_key(key_value)
|
||||||
|
return (
|
||||||
|
value.value
|
||||||
|
if value
|
||||||
|
else FeatureFlags.get_default(FeatureFlagsEnum(key_value))
|
||||||
|
)
|
||||||
|
@ -3,4 +3,5 @@ from enum import Enum
|
|||||||
|
|
||||||
class FeatureFlagsEnum(Enum):
|
class FeatureFlagsEnum(Enum):
|
||||||
version_endpoint = "VersionEndpoint"
|
version_endpoint = "VersionEndpoint"
|
||||||
|
technical_demo_banner = "TechnicalDemoBanner"
|
||||||
per_user_setup = "PerUserSetup"
|
per_user_setup = "PerUserSetup"
|
||||||
|
@ -21,6 +21,7 @@ class FeatureFlagsSeeder(DataSeederABC):
|
|||||||
x.value: FeatureFlags.get_default(x) for x in FeatureFlagsEnum
|
x.value: FeatureFlags.get_default(x) for x in FeatureFlagsEnum
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Create new feature flags
|
||||||
to_create = [
|
to_create = [
|
||||||
FeatureFlag(0, x, possible_feature_flags[x])
|
FeatureFlag(0, x, possible_feature_flags[x])
|
||||||
for x in possible_feature_flags.keys()
|
for x in possible_feature_flags.keys()
|
||||||
@ -31,6 +32,19 @@ class FeatureFlagsSeeder(DataSeederABC):
|
|||||||
to_create_dicts = {x.key: x.value for x in to_create}
|
to_create_dicts = {x.key: x.value for x in to_create}
|
||||||
logger.debug(f"Created feature flags: {to_create_dicts}")
|
logger.debug(f"Created feature flags: {to_create_dicts}")
|
||||||
|
|
||||||
|
# Update existing feature flags if they can be overwritten and have a different value
|
||||||
|
to_update = [
|
||||||
|
FeatureFlag(x.id, x.key, possible_feature_flags[x.key])
|
||||||
|
for x in feature_flags
|
||||||
|
if FeatureFlags.overwrite_flag(x.key)
|
||||||
|
and x.value != possible_feature_flags[x.key]
|
||||||
|
]
|
||||||
|
if len(to_update) > 0:
|
||||||
|
await featureFlagDao.update_many(to_update)
|
||||||
|
to_update_dicts = {x.key: x.value for x in to_update}
|
||||||
|
logger.debug(f"Updated feature flags: {to_update_dicts}")
|
||||||
|
|
||||||
|
# Delete feature flags that are no longer defined
|
||||||
to_delete = [
|
to_delete = [
|
||||||
x for x in feature_flags if x.key not in possible_feature_flags.keys()
|
x for x in feature_flags if x.key not in possible_feature_flags.keys()
|
||||||
]
|
]
|
||||||
|
@ -3,6 +3,7 @@ import { BehaviorSubject } from 'rxjs';
|
|||||||
import { MenuElement } from 'src/app/model/view/menu-element';
|
import { MenuElement } from 'src/app/model/view/menu-element';
|
||||||
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 { FeatureFlagService } from 'src/app/service/feature-flag.service';
|
||||||
|
|
||||||
@Injectable({
|
@Injectable({
|
||||||
providedIn: 'root',
|
providedIn: 'root',
|
||||||
@ -11,7 +12,10 @@ export class SidebarService {
|
|||||||
visible$ = new BehaviorSubject<boolean>(true);
|
visible$ = new BehaviorSubject<boolean>(true);
|
||||||
elements$ = new BehaviorSubject<MenuElement[]>([]);
|
elements$ = new BehaviorSubject<MenuElement[]>([]);
|
||||||
|
|
||||||
constructor(private auth: AuthService) {
|
constructor(
|
||||||
|
private auth: AuthService,
|
||||||
|
private featureFlags: FeatureFlagService
|
||||||
|
) {
|
||||||
this.auth.user$.subscribe(async () => {
|
this.auth.user$.subscribe(async () => {
|
||||||
await this.setElements();
|
await this.setElements();
|
||||||
});
|
});
|
||||||
@ -40,16 +44,19 @@ export class SidebarService {
|
|||||||
label: 'common.groups',
|
label: 'common.groups',
|
||||||
icon: 'pi pi-tags',
|
icon: 'pi pi-tags',
|
||||||
routerLink: ['/admin/groups'],
|
routerLink: ['/admin/groups'],
|
||||||
visible: await this.auth.hasAnyPermissionLazy([PermissionsEnum.groups]),
|
visible:
|
||||||
|
(await this.auth.hasAnyPermissionLazy([PermissionsEnum.groups])) ||
|
||||||
|
(await this.featureFlags.get('PerUserSetup')),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: 'common.urls',
|
label: 'common.urls',
|
||||||
icon: 'pi pi-tag',
|
icon: 'pi pi-tag',
|
||||||
routerLink: ['/admin/urls'],
|
routerLink: ['/admin/urls'],
|
||||||
visible: await this.auth.hasAnyPermissionLazy([
|
visible:
|
||||||
|
(await this.auth.hasAnyPermissionLazy([
|
||||||
PermissionsEnum.shortUrls,
|
PermissionsEnum.shortUrls,
|
||||||
PermissionsEnum.shortUrlsByAssignment,
|
PermissionsEnum.shortUrlsByAssignment,
|
||||||
]),
|
])) || (await this.featureFlags.get('PerUserSetup')),
|
||||||
},
|
},
|
||||||
await this.sectionAdmin(),
|
await this.sectionAdmin(),
|
||||||
];
|
];
|
||||||
|
Loading…
Reference in New Issue
Block a user