Compare commits
133 Commits
healthchec
...
web/sideba
Author | SHA1 | Date | |
---|---|---|---|
b865ed4392 | |||
f0afac0b87 | |||
8f82dac84e | |||
89c08f2588 | |||
113d6cc45f | |||
05cfbca5f2 | |||
385f9bcbac | |||
86bc5b4cdb | |||
8d5d9f35ef | |||
439169d5e7 | |||
e405b33f9f | |||
a9c13d4d10 | |||
12b16b17a2 | |||
3473abee32 | |||
b5a0b3a521 | |||
837a0325ca | |||
b1050e8825 | |||
7bb90b1661 | |||
8f755785ea | |||
adc0ec8ee4 | |||
9379b3d178 | |||
18eef8ae05 | |||
f0e22fd08b | |||
ce5297a6cd | |||
74c8df8782 | |||
2d897fac48 | |||
2eb47c9efa | |||
9852041f38 | |||
7f74936212 | |||
4f40b1e27c | |||
041e407153 | |||
31b891428e | |||
4ab8247847 | |||
af24edf8c1 | |||
f8bfd12e31 | |||
993fc4b77b | |||
3ee2be09bf | |||
b3e3948f44 | |||
117a5cd88d | |||
342a40212e | |||
15ae11d9d5 | |||
e11df56f21 | |||
3771af5282 | |||
0718053c56 | |||
3e5014bfea | |||
78f49ddc04 | |||
744bc54231 | |||
44ba30ad75 | |||
63b991f137 | |||
7f9acb8a2b | |||
ce3ba32044 | |||
25e6a69331 | |||
78d07cc355 | |||
3c4df47fe3 | |||
8ed1805cb8 | |||
4d23db73ca | |||
72783953fb | |||
3b0fdb3dbd | |||
23161eed12 | |||
8918427588 | |||
5d858020f6 | |||
198e8b98a8 | |||
88e9c9b669 | |||
0c652a210d | |||
105a90d2e7 | |||
68f5abe318 | |||
59d4c18636 | |||
b67e2a1144 | |||
fc025651ce | |||
7cedc840b0 | |||
5ba731e48b | |||
c792534a50 | |||
a136fd8b54 | |||
fb63c1f3e9 | |||
0b15ab3f27 | |||
f9fd67c2b8 | |||
4ac19f9d44 | |||
74d3e92bac | |||
207fa13405 | |||
208e4a8bed | |||
ee245ab390 | |||
60c8837082 | |||
6cf418a37e | |||
254761e930 | |||
d85f8758fe | |||
84bfb37b60 | |||
a31588668d | |||
9768684c3c | |||
cde94c2377 | |||
b0e852afca | |||
e35cefb63e | |||
2a11356961 | |||
a3673906c7 | |||
f2834cc7e2 | |||
5b898bef01 | |||
6b9201907d | |||
2ec8932891 | |||
a9886b047e | |||
a0dfe7ce78 | |||
c471428c6b | |||
83e934f80c | |||
5386f0f4c3 | |||
d5875a597b | |||
25ecc21d6d | |||
ff78f2f00a | |||
3c277f14c8 | |||
d539884204 | |||
476adef4ea | |||
3e905cc956 | |||
e3b1ba63a6 | |||
2aed74bd9f | |||
2545815f08 | |||
657089eac9 | |||
19e8b675ae | |||
bdd92f63d8 | |||
829ad5d3f2 | |||
58639a5d03 | |||
67cae13f93 | |||
100a6f02f1 | |||
242e5b492b | |||
48495f3c53 | |||
77549753c2 | |||
3b19aa1915 | |||
6653bd8224 | |||
639a8ceb5a | |||
0449fd07c5 | |||
8e892373a1 | |||
8713a1d120 | |||
0123bf61ab | |||
e8edbdb4ae | |||
83338f8c32 | |||
e51b36c614 | |||
314d89b1b7 |
@ -58,7 +58,7 @@ from authentik.outposts.models import OutpostServiceConnection
|
||||
from authentik.policies.models import Policy, PolicyBindingModel
|
||||
from authentik.policies.reputation.models import Reputation
|
||||
from authentik.providers.oauth2.models import AccessToken, AuthorizationCode, RefreshToken
|
||||
from authentik.providers.scim.models import SCIMGroup, SCIMUser
|
||||
from authentik.providers.scim.models import SCIMProviderGroup, SCIMProviderUser
|
||||
from authentik.sources.scim.models import SCIMSourceGroup, SCIMSourceUser
|
||||
from authentik.stages.authenticator_webauthn.models import WebAuthnDeviceType
|
||||
from authentik.tenants.models import Tenant
|
||||
@ -97,8 +97,8 @@ def excluded_models() -> list[type[Model]]:
|
||||
# FIXME: these shouldn't need to be explicitly listed, but rather based off of a mixin
|
||||
FlowToken,
|
||||
LicenseUsage,
|
||||
SCIMGroup,
|
||||
SCIMUser,
|
||||
SCIMProviderGroup,
|
||||
SCIMProviderUser,
|
||||
Tenant,
|
||||
SystemTask,
|
||||
ConnectionToken,
|
||||
|
@ -2,6 +2,7 @@
|
||||
|
||||
from json import loads
|
||||
|
||||
from django.db.models import Prefetch
|
||||
from django.http import Http404
|
||||
from django_filters.filters import CharFilter, ModelMultipleChoiceFilter
|
||||
from django_filters.filterset import FilterSet
|
||||
@ -166,8 +167,14 @@ class GroupViewSet(UsedByMixin, ModelViewSet):
|
||||
|
||||
def get_queryset(self):
|
||||
base_qs = Group.objects.all().select_related("parent").prefetch_related("roles")
|
||||
|
||||
if self.serializer_class(context={"request": self.request})._should_include_users:
|
||||
base_qs = base_qs.prefetch_related("users")
|
||||
else:
|
||||
base_qs = base_qs.prefetch_related(
|
||||
Prefetch("users", queryset=User.objects.all().only("id"))
|
||||
)
|
||||
|
||||
return base_qs
|
||||
|
||||
@extend_schema(
|
||||
|
@ -80,8 +80,10 @@ class PropertyMappingViewSet(
|
||||
class PropertyMappingTestSerializer(PolicyTestSerializer):
|
||||
"""Test property mapping execution for a user/group with context"""
|
||||
|
||||
user = PrimaryKeyRelatedField(queryset=User.objects.all(), required=False)
|
||||
group = PrimaryKeyRelatedField(queryset=Group.objects.all(), required=False)
|
||||
user = PrimaryKeyRelatedField(queryset=User.objects.all(), required=False, allow_null=True)
|
||||
group = PrimaryKeyRelatedField(
|
||||
queryset=Group.objects.all(), required=False, allow_null=True
|
||||
)
|
||||
|
||||
queryset = PropertyMapping.objects.select_subclasses()
|
||||
serializer_class = PropertyMappingSerializer
|
||||
|
@ -39,12 +39,12 @@ def get_delete_action(manager: Manager) -> str:
|
||||
"""Get the delete action from the Foreign key, falls back to cascade"""
|
||||
if hasattr(manager, "field"):
|
||||
if manager.field.remote_field.on_delete.__name__ == SET_NULL.__name__:
|
||||
return DeleteAction.SET_NULL.name
|
||||
return DeleteAction.SET_NULL.value
|
||||
if manager.field.remote_field.on_delete.__name__ == SET_DEFAULT.__name__:
|
||||
return DeleteAction.SET_DEFAULT.name
|
||||
return DeleteAction.SET_DEFAULT.value
|
||||
if hasattr(manager, "source_field"):
|
||||
return DeleteAction.CASCADE_MANY.name
|
||||
return DeleteAction.CASCADE.name
|
||||
return DeleteAction.CASCADE_MANY.value
|
||||
return DeleteAction.CASCADE.value
|
||||
|
||||
|
||||
class UsedByMixin:
|
||||
|
@ -241,7 +241,7 @@ class TestCrypto(APITestCase):
|
||||
"model_name": "oauth2provider",
|
||||
"pk": str(provider.pk),
|
||||
"name": str(provider),
|
||||
"action": DeleteAction.SET_NULL.name,
|
||||
"action": DeleteAction.SET_NULL.value,
|
||||
}
|
||||
],
|
||||
)
|
||||
|
@ -19,6 +19,7 @@ class GoogleWorkspaceProviderGroupSerializer(ModelSerializer):
|
||||
model = GoogleWorkspaceProviderGroup
|
||||
fields = [
|
||||
"id",
|
||||
"google_id",
|
||||
"group",
|
||||
"group_obj",
|
||||
"provider",
|
||||
|
@ -19,6 +19,7 @@ class GoogleWorkspaceProviderUserSerializer(ModelSerializer):
|
||||
model = GoogleWorkspaceProviderUser
|
||||
fields = [
|
||||
"id",
|
||||
"google_id",
|
||||
"user",
|
||||
"user_obj",
|
||||
"provider",
|
||||
|
@ -92,12 +92,14 @@ class GoogleWorkspaceGroupClient(
|
||||
google_group = self.to_schema(group, connection)
|
||||
self.check_email_valid(google_group["email"])
|
||||
try:
|
||||
return self._request(
|
||||
response = self._request(
|
||||
self.directory_service.groups().update(
|
||||
groupKey=connection.google_id,
|
||||
body=google_group,
|
||||
)
|
||||
)
|
||||
connection.attributes = response
|
||||
connection.save()
|
||||
except NotFoundSyncException:
|
||||
# Resource missing is handled by self.write, which will re-create the group
|
||||
raise
|
||||
|
@ -88,9 +88,11 @@ class GoogleWorkspaceUserClient(GoogleWorkspaceSyncClient[User, GoogleWorkspaceP
|
||||
self.check_email_valid(
|
||||
google_user["primaryEmail"], *[x["address"] for x in google_user.get("emails", [])]
|
||||
)
|
||||
self._request(
|
||||
response = self._request(
|
||||
self.directory_service.users().update(userKey=connection.google_id, body=google_user)
|
||||
)
|
||||
connection.attributes = response
|
||||
connection.save()
|
||||
|
||||
def discover(self):
|
||||
"""Iterate through all users and connect them with authentik users if possible"""
|
||||
|
@ -19,6 +19,7 @@ class MicrosoftEntraProviderGroupSerializer(ModelSerializer):
|
||||
model = MicrosoftEntraProviderGroup
|
||||
fields = [
|
||||
"id",
|
||||
"microsoft_id",
|
||||
"group",
|
||||
"group_obj",
|
||||
"provider",
|
||||
|
@ -19,6 +19,7 @@ class MicrosoftEntraProviderUserSerializer(ModelSerializer):
|
||||
model = MicrosoftEntraProviderUser
|
||||
fields = [
|
||||
"id",
|
||||
"microsoft_id",
|
||||
"user",
|
||||
"user_obj",
|
||||
"provider",
|
||||
|
@ -23,6 +23,7 @@ from msgraph.graph_service_client import GraphServiceClient
|
||||
from msgraph_core import GraphClientFactory
|
||||
|
||||
from authentik.enterprise.providers.microsoft_entra.models import MicrosoftEntraProvider
|
||||
from authentik.events.utils import sanitize_item
|
||||
from authentik.lib.sync.outgoing import HTTP_CONFLICT
|
||||
from authentik.lib.sync.outgoing.base import BaseOutgoingSyncClient
|
||||
from authentik.lib.sync.outgoing.exceptions import (
|
||||
@ -106,4 +107,4 @@ class MicrosoftEntraSyncClient[TModel: Model, TConnection: Model, TSchema: dict]
|
||||
we can't JSON serialize"""
|
||||
raw_data = asdict(entity)
|
||||
raw_data.pop("backing_store", None)
|
||||
return raw_data
|
||||
return sanitize_item(raw_data)
|
||||
|
@ -1,3 +1,4 @@
|
||||
from deepmerge import always_merger
|
||||
from django.db import transaction
|
||||
from msgraph.generated.groups.groups_request_builder import GroupsRequestBuilder
|
||||
from msgraph.generated.models.group import Group as MSGroup
|
||||
@ -104,9 +105,12 @@ class MicrosoftEntraGroupClient(
|
||||
microsoft_group = self.to_schema(group, connection)
|
||||
microsoft_group.id = connection.microsoft_id
|
||||
try:
|
||||
return self._request(
|
||||
response = self._request(
|
||||
self.client.groups.by_group_id(connection.microsoft_id).patch(microsoft_group)
|
||||
)
|
||||
if response:
|
||||
always_merger.merge(connection.attributes, self.entity_as_dict(response))
|
||||
connection.save()
|
||||
except NotFoundSyncException:
|
||||
# Resource missing is handled by self.write, which will re-create the group
|
||||
raise
|
||||
|
@ -1,3 +1,4 @@
|
||||
from deepmerge import always_merger
|
||||
from django.db import transaction
|
||||
from msgraph.generated.models.user import User as MSUser
|
||||
from msgraph.generated.users.users_request_builder import UsersRequestBuilder
|
||||
@ -110,7 +111,12 @@ class MicrosoftEntraUserClient(MicrosoftEntraSyncClient[User, MicrosoftEntraProv
|
||||
"""Update existing user"""
|
||||
microsoft_user = self.to_schema(user, connection)
|
||||
self.check_email_valid(microsoft_user.user_principal_name)
|
||||
self._request(self.client.users.by_user_id(connection.microsoft_id).patch(microsoft_user))
|
||||
response = self._request(
|
||||
self.client.users.by_user_id(connection.microsoft_id).patch(microsoft_user)
|
||||
)
|
||||
if response:
|
||||
always_merger.merge(connection.attributes, self.entity_as_dict(response))
|
||||
connection.save()
|
||||
|
||||
def discover(self):
|
||||
"""Iterate through all users and connect them with authentik users if possible"""
|
||||
|
@ -102,6 +102,8 @@ def get_logger_config():
|
||||
"gunicorn": "INFO",
|
||||
"requests_mock": "WARNING",
|
||||
"hpack": "WARNING",
|
||||
"httpx": "WARNING",
|
||||
"azure": "WARNING",
|
||||
}
|
||||
for handler_name, level in handler_level_map.items():
|
||||
base_config["loggers"][handler_name] = {
|
||||
|
@ -57,6 +57,8 @@ class PropertyMappingManager:
|
||||
mapping.set_context(user, request, **kwargs)
|
||||
try:
|
||||
value = mapping.evaluate(mapping.model.expression)
|
||||
except PropertyMappingExpressionException as exc:
|
||||
raise exc from exc
|
||||
except Exception as exc:
|
||||
raise PropertyMappingExpressionException(exc, mapping.model) from exc
|
||||
if value is None:
|
||||
|
@ -91,10 +91,9 @@ class BaseOutgoingSyncClient[
|
||||
}
|
||||
eval_kwargs.setdefault("user", None)
|
||||
for value in self.mapper.iter_eval(**eval_kwargs):
|
||||
try:
|
||||
always_merger.merge(raw_final_object, value)
|
||||
except SkipObjectException as exc:
|
||||
raise exc from exc
|
||||
always_merger.merge(raw_final_object, value)
|
||||
except SkipObjectException as exc:
|
||||
raise exc from exc
|
||||
except PropertyMappingExpressionException as exc:
|
||||
# Value error can be raised when assigning invalid data to an attribute
|
||||
Event.new(
|
||||
@ -104,7 +103,7 @@ class BaseOutgoingSyncClient[
|
||||
).save()
|
||||
raise StopSync(exc, obj, exc.mapping) from exc
|
||||
if not raw_final_object:
|
||||
raise StopSync(ValueError("No user mappings configured"), obj)
|
||||
raise StopSync(ValueError("No mappings configured"), obj)
|
||||
for key, value in defaults.items():
|
||||
raw_final_object.setdefault(key, value)
|
||||
return raw_final_object
|
||||
|
@ -14,6 +14,7 @@ from authentik.core.models import Group, User
|
||||
from authentik.events.logs import LogEvent
|
||||
from authentik.events.models import TaskStatus
|
||||
from authentik.events.system_tasks import SystemTask
|
||||
from authentik.events.utils import sanitize_item
|
||||
from authentik.lib.sync.outgoing import PAGE_SIZE, PAGE_TIMEOUT
|
||||
from authentik.lib.sync.outgoing.base import Direction
|
||||
from authentik.lib.sync.outgoing.exceptions import (
|
||||
@ -125,6 +126,7 @@ class SyncTasks:
|
||||
try:
|
||||
client.write(obj)
|
||||
except SkipObjectException:
|
||||
self.logger.debug("skipping object due to SkipObject", obj=obj)
|
||||
continue
|
||||
except BadRequestSyncException as exc:
|
||||
self.logger.warning("failed to sync object", exc=exc, obj=obj)
|
||||
@ -144,8 +146,8 @@ class SyncTasks:
|
||||
)
|
||||
),
|
||||
log_level="warning",
|
||||
logger="",
|
||||
attributes={"arguments": exc.args[1:]},
|
||||
logger=f"{provider._meta.verbose_name}@{object_type}",
|
||||
attributes={"arguments": exc.args[1:], "obj": sanitize_item(obj)},
|
||||
)
|
||||
)
|
||||
)
|
||||
@ -167,7 +169,8 @@ class SyncTasks:
|
||||
)
|
||||
),
|
||||
log_level="warning",
|
||||
logger="",
|
||||
logger=f"{provider._meta.verbose_name}@{object_type}",
|
||||
attributes={"obj": sanitize_item(obj)},
|
||||
)
|
||||
)
|
||||
)
|
||||
@ -184,7 +187,8 @@ class SyncTasks:
|
||||
)
|
||||
),
|
||||
log_level="warning",
|
||||
logger="",
|
||||
logger=f"{provider._meta.verbose_name}@{object_type}",
|
||||
attributes={"obj": sanitize_item(obj)},
|
||||
)
|
||||
)
|
||||
)
|
||||
|
@ -102,7 +102,7 @@ class EventMatcherPolicy(Policy):
|
||||
result = checker(request, event)
|
||||
if result is None:
|
||||
continue
|
||||
LOGGER.info(
|
||||
LOGGER.debug(
|
||||
"Event matcher check result",
|
||||
checker=checker.__name__,
|
||||
result=result,
|
||||
|
43
authentik/providers/scim/api/groups.py
Normal file
43
authentik/providers/scim/api/groups.py
Normal file
@ -0,0 +1,43 @@
|
||||
"""SCIMProviderGroup API Views"""
|
||||
|
||||
from rest_framework import mixins
|
||||
from rest_framework.serializers import ModelSerializer
|
||||
from rest_framework.viewsets import GenericViewSet
|
||||
|
||||
from authentik.core.api.used_by import UsedByMixin
|
||||
from authentik.core.api.users import UserGroupSerializer
|
||||
from authentik.providers.scim.models import SCIMProviderGroup
|
||||
|
||||
|
||||
class SCIMProviderGroupSerializer(ModelSerializer):
|
||||
"""SCIMProviderGroup Serializer"""
|
||||
|
||||
group_obj = UserGroupSerializer(source="group", read_only=True)
|
||||
|
||||
class Meta:
|
||||
|
||||
model = SCIMProviderGroup
|
||||
fields = [
|
||||
"id",
|
||||
"scim_id",
|
||||
"group",
|
||||
"group_obj",
|
||||
"provider",
|
||||
]
|
||||
|
||||
|
||||
class SCIMProviderGroupViewSet(
|
||||
mixins.CreateModelMixin,
|
||||
mixins.RetrieveModelMixin,
|
||||
mixins.DestroyModelMixin,
|
||||
UsedByMixin,
|
||||
mixins.ListModelMixin,
|
||||
GenericViewSet,
|
||||
):
|
||||
"""SCIMProviderGroup Viewset"""
|
||||
|
||||
queryset = SCIMProviderGroup.objects.all().select_related("group")
|
||||
serializer_class = SCIMProviderGroupSerializer
|
||||
filterset_fields = ["provider__id", "group__name", "group__group_uuid"]
|
||||
search_fields = ["provider__name", "group__name"]
|
||||
ordering = ["group__name"]
|
43
authentik/providers/scim/api/users.py
Normal file
43
authentik/providers/scim/api/users.py
Normal file
@ -0,0 +1,43 @@
|
||||
"""SCIMProviderUser API Views"""
|
||||
|
||||
from rest_framework import mixins
|
||||
from rest_framework.serializers import ModelSerializer
|
||||
from rest_framework.viewsets import GenericViewSet
|
||||
|
||||
from authentik.core.api.groups import GroupMemberSerializer
|
||||
from authentik.core.api.used_by import UsedByMixin
|
||||
from authentik.providers.scim.models import SCIMProviderUser
|
||||
|
||||
|
||||
class SCIMProviderUserSerializer(ModelSerializer):
|
||||
"""SCIMProviderUser Serializer"""
|
||||
|
||||
user_obj = GroupMemberSerializer(source="user", read_only=True)
|
||||
|
||||
class Meta:
|
||||
|
||||
model = SCIMProviderUser
|
||||
fields = [
|
||||
"id",
|
||||
"scim_id",
|
||||
"user",
|
||||
"user_obj",
|
||||
"provider",
|
||||
]
|
||||
|
||||
|
||||
class SCIMProviderUserViewSet(
|
||||
mixins.CreateModelMixin,
|
||||
mixins.RetrieveModelMixin,
|
||||
mixins.DestroyModelMixin,
|
||||
UsedByMixin,
|
||||
mixins.ListModelMixin,
|
||||
GenericViewSet,
|
||||
):
|
||||
"""SCIMProviderUser Viewset"""
|
||||
|
||||
queryset = SCIMProviderUser.objects.all().select_related("user")
|
||||
serializer_class = SCIMProviderUserSerializer
|
||||
filterset_fields = ["provider__id", "user__username", "user__id"]
|
||||
search_fields = ["provider__name", "user__username"]
|
||||
ordering = ["user__username"]
|
@ -19,13 +19,18 @@ from authentik.providers.scim.clients.exceptions import (
|
||||
)
|
||||
from authentik.providers.scim.clients.schema import SCIM_GROUP_SCHEMA, PatchRequest
|
||||
from authentik.providers.scim.clients.schema import Group as SCIMGroupSchema
|
||||
from authentik.providers.scim.models import SCIMGroup, SCIMMapping, SCIMProvider, SCIMUser
|
||||
from authentik.providers.scim.models import (
|
||||
SCIMMapping,
|
||||
SCIMProvider,
|
||||
SCIMProviderGroup,
|
||||
SCIMProviderUser,
|
||||
)
|
||||
|
||||
|
||||
class SCIMGroupClient(SCIMClient[Group, SCIMGroup, SCIMGroupSchema]):
|
||||
class SCIMGroupClient(SCIMClient[Group, SCIMProviderGroup, SCIMGroupSchema]):
|
||||
"""SCIM client for groups"""
|
||||
|
||||
connection_type = SCIMGroup
|
||||
connection_type = SCIMProviderGroup
|
||||
connection_type_query = "group"
|
||||
mapper: PropertyMappingManager
|
||||
|
||||
@ -37,7 +42,7 @@ class SCIMGroupClient(SCIMClient[Group, SCIMGroup, SCIMGroupSchema]):
|
||||
["group", "provider", "connection"],
|
||||
)
|
||||
|
||||
def to_schema(self, obj: Group, connection: SCIMGroup) -> SCIMGroupSchema:
|
||||
def to_schema(self, obj: Group, connection: SCIMProviderGroup) -> SCIMGroupSchema:
|
||||
"""Convert authentik user into SCIM"""
|
||||
raw_scim_group = super().to_schema(
|
||||
obj,
|
||||
@ -52,7 +57,7 @@ class SCIMGroupClient(SCIMClient[Group, SCIMGroup, SCIMGroupSchema]):
|
||||
scim_group.externalId = str(obj.pk)
|
||||
|
||||
users = list(obj.users.order_by("id").values_list("id", flat=True))
|
||||
connections = SCIMUser.objects.filter(provider=self.provider, user__pk__in=users)
|
||||
connections = SCIMProviderUser.objects.filter(provider=self.provider, user__pk__in=users)
|
||||
members = []
|
||||
for user in connections:
|
||||
members.append(
|
||||
@ -66,7 +71,7 @@ class SCIMGroupClient(SCIMClient[Group, SCIMGroup, SCIMGroupSchema]):
|
||||
|
||||
def delete(self, obj: Group):
|
||||
"""Delete group"""
|
||||
scim_group = SCIMGroup.objects.filter(provider=self.provider, group=obj).first()
|
||||
scim_group = SCIMProviderGroup.objects.filter(provider=self.provider, group=obj).first()
|
||||
if not scim_group:
|
||||
self.logger.debug("Group does not exist in SCIM, skipping")
|
||||
return None
|
||||
@ -88,9 +93,11 @@ class SCIMGroupClient(SCIMClient[Group, SCIMGroup, SCIMGroupSchema]):
|
||||
scim_id = response.get("id")
|
||||
if not scim_id or scim_id == "":
|
||||
raise StopSync("SCIM Response with missing or invalid `id`")
|
||||
return SCIMGroup.objects.create(provider=self.provider, group=group, scim_id=scim_id)
|
||||
return SCIMProviderGroup.objects.create(
|
||||
provider=self.provider, group=group, scim_id=scim_id
|
||||
)
|
||||
|
||||
def update(self, group: Group, connection: SCIMGroup):
|
||||
def update(self, group: Group, connection: SCIMProviderGroup):
|
||||
"""Update existing group"""
|
||||
scim_group = self.to_schema(group, connection)
|
||||
scim_group.id = connection.scim_id
|
||||
@ -158,16 +165,16 @@ class SCIMGroupClient(SCIMClient[Group, SCIMGroup, SCIMGroupSchema]):
|
||||
"""Add users in users_set to group"""
|
||||
if len(users_set) < 1:
|
||||
return
|
||||
scim_group = SCIMGroup.objects.filter(provider=self.provider, group=group).first()
|
||||
scim_group = SCIMProviderGroup.objects.filter(provider=self.provider, group=group).first()
|
||||
if not scim_group:
|
||||
self.logger.warning(
|
||||
"could not sync group membership, group does not exist", group=group
|
||||
)
|
||||
return
|
||||
user_ids = list(
|
||||
SCIMUser.objects.filter(user__pk__in=users_set, provider=self.provider).values_list(
|
||||
"scim_id", flat=True
|
||||
)
|
||||
SCIMProviderUser.objects.filter(
|
||||
user__pk__in=users_set, provider=self.provider
|
||||
).values_list("scim_id", flat=True)
|
||||
)
|
||||
if len(user_ids) < 1:
|
||||
return
|
||||
@ -184,16 +191,16 @@ class SCIMGroupClient(SCIMClient[Group, SCIMGroup, SCIMGroupSchema]):
|
||||
"""Remove users in users_set from group"""
|
||||
if len(users_set) < 1:
|
||||
return
|
||||
scim_group = SCIMGroup.objects.filter(provider=self.provider, group=group).first()
|
||||
scim_group = SCIMProviderGroup.objects.filter(provider=self.provider, group=group).first()
|
||||
if not scim_group:
|
||||
self.logger.warning(
|
||||
"could not sync group membership, group does not exist", group=group
|
||||
)
|
||||
return
|
||||
user_ids = list(
|
||||
SCIMUser.objects.filter(user__pk__in=users_set, provider=self.provider).values_list(
|
||||
"scim_id", flat=True
|
||||
)
|
||||
SCIMProviderUser.objects.filter(
|
||||
user__pk__in=users_set, provider=self.provider
|
||||
).values_list("scim_id", flat=True)
|
||||
)
|
||||
if len(user_ids) < 1:
|
||||
return
|
||||
|
@ -9,13 +9,13 @@ from authentik.policies.utils import delete_none_values
|
||||
from authentik.providers.scim.clients.base import SCIMClient
|
||||
from authentik.providers.scim.clients.schema import SCIM_USER_SCHEMA
|
||||
from authentik.providers.scim.clients.schema import User as SCIMUserSchema
|
||||
from authentik.providers.scim.models import SCIMMapping, SCIMProvider, SCIMUser
|
||||
from authentik.providers.scim.models import SCIMMapping, SCIMProvider, SCIMProviderUser
|
||||
|
||||
|
||||
class SCIMUserClient(SCIMClient[User, SCIMUser, SCIMUserSchema]):
|
||||
class SCIMUserClient(SCIMClient[User, SCIMProviderUser, SCIMUserSchema]):
|
||||
"""SCIM client for users"""
|
||||
|
||||
connection_type = SCIMUser
|
||||
connection_type = SCIMProviderUser
|
||||
connection_type_query = "user"
|
||||
mapper: PropertyMappingManager
|
||||
|
||||
@ -27,7 +27,7 @@ class SCIMUserClient(SCIMClient[User, SCIMUser, SCIMUserSchema]):
|
||||
["provider", "connection"],
|
||||
)
|
||||
|
||||
def to_schema(self, obj: User, connection: SCIMUser) -> SCIMUserSchema:
|
||||
def to_schema(self, obj: User, connection: SCIMProviderUser) -> SCIMUserSchema:
|
||||
"""Convert authentik user into SCIM"""
|
||||
raw_scim_user = super().to_schema(
|
||||
obj,
|
||||
@ -44,7 +44,7 @@ class SCIMUserClient(SCIMClient[User, SCIMUser, SCIMUserSchema]):
|
||||
|
||||
def delete(self, obj: User):
|
||||
"""Delete user"""
|
||||
scim_user = SCIMUser.objects.filter(provider=self.provider, user=obj).first()
|
||||
scim_user = SCIMProviderUser.objects.filter(provider=self.provider, user=obj).first()
|
||||
if not scim_user:
|
||||
self.logger.debug("User does not exist in SCIM, skipping")
|
||||
return None
|
||||
@ -66,9 +66,9 @@ class SCIMUserClient(SCIMClient[User, SCIMUser, SCIMUserSchema]):
|
||||
scim_id = response.get("id")
|
||||
if not scim_id or scim_id == "":
|
||||
raise StopSync("SCIM Response with missing or invalid `id`")
|
||||
return SCIMUser.objects.create(provider=self.provider, user=user, scim_id=scim_id)
|
||||
return SCIMProviderUser.objects.create(provider=self.provider, user=user, scim_id=scim_id)
|
||||
|
||||
def update(self, user: User, connection: SCIMUser):
|
||||
def update(self, user: User, connection: SCIMProviderUser):
|
||||
"""Update existing user"""
|
||||
scim_user = self.to_schema(user, connection)
|
||||
scim_user.id = connection.scim_id
|
||||
|
@ -0,0 +1,24 @@
|
||||
# Generated by Django 5.0.6 on 2024-06-04 07:45
|
||||
|
||||
from django.conf import settings
|
||||
from django.db import migrations
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
("authentik_core", "0035_alter_group_options_and_more"),
|
||||
("authentik_providers_scim", "0007_scimgroup_scim_id_scimuser_scim_id_and_more"),
|
||||
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RenameModel(
|
||||
old_name="SCIMGroup",
|
||||
new_name="SCIMProviderGroup",
|
||||
),
|
||||
migrations.RenameModel(
|
||||
old_name="SCIMUser",
|
||||
new_name="SCIMProviderUser",
|
||||
),
|
||||
]
|
@ -10,6 +10,7 @@ from django.utils.translation import gettext_lazy as _
|
||||
from rest_framework.serializers import Serializer
|
||||
|
||||
from authentik.core.models import BackchannelProvider, Group, PropertyMapping, User, UserTypes
|
||||
from authentik.lib.models import SerializerModel
|
||||
from authentik.lib.sync.outgoing.base import BaseOutgoingSyncClient
|
||||
from authentik.lib.sync.outgoing.models import OutgoingSyncProvider
|
||||
|
||||
@ -106,7 +107,7 @@ class SCIMMapping(PropertyMapping):
|
||||
verbose_name_plural = _("SCIM Mappings")
|
||||
|
||||
|
||||
class SCIMUser(models.Model):
|
||||
class SCIMProviderUser(SerializerModel):
|
||||
"""Mapping of a user and provider to a SCIM user ID"""
|
||||
|
||||
id = models.UUIDField(primary_key=True, editable=False, default=uuid4)
|
||||
@ -114,14 +115,20 @@ class SCIMUser(models.Model):
|
||||
user = models.ForeignKey(User, on_delete=models.CASCADE)
|
||||
provider = models.ForeignKey(SCIMProvider, on_delete=models.CASCADE)
|
||||
|
||||
@property
|
||||
def serializer(self) -> type[Serializer]:
|
||||
from authentik.providers.scim.api.users import SCIMProviderUserSerializer
|
||||
|
||||
return SCIMProviderUserSerializer
|
||||
|
||||
class Meta:
|
||||
unique_together = (("scim_id", "user", "provider"),)
|
||||
|
||||
def __str__(self) -> str:
|
||||
return f"SCIM User {self.user_id} to {self.provider_id}"
|
||||
return f"SCIM Provider User {self.user_id} to {self.provider_id}"
|
||||
|
||||
|
||||
class SCIMGroup(models.Model):
|
||||
class SCIMProviderGroup(SerializerModel):
|
||||
"""Mapping of a group and provider to a SCIM user ID"""
|
||||
|
||||
id = models.UUIDField(primary_key=True, editable=False, default=uuid4)
|
||||
@ -129,8 +136,14 @@ class SCIMGroup(models.Model):
|
||||
group = models.ForeignKey(Group, on_delete=models.CASCADE)
|
||||
provider = models.ForeignKey(SCIMProvider, on_delete=models.CASCADE)
|
||||
|
||||
@property
|
||||
def serializer(self) -> type[Serializer]:
|
||||
from authentik.providers.scim.api.groups import SCIMProviderGroupSerializer
|
||||
|
||||
return SCIMProviderGroupSerializer
|
||||
|
||||
class Meta:
|
||||
unique_together = (("scim_id", "group", "provider"),)
|
||||
|
||||
def __str__(self) -> str:
|
||||
return f"SCIM Group {self.group_id} to {self.provider_id}"
|
||||
return f"SCIM Provider Group {self.group_id} to {self.provider_id}"
|
||||
|
@ -1,9 +1,17 @@
|
||||
"""API URLs"""
|
||||
|
||||
from authentik.providers.scim.api.groups import (
|
||||
SCIMProviderGroupViewSet,
|
||||
)
|
||||
from authentik.providers.scim.api.property_mappings import SCIMMappingViewSet
|
||||
from authentik.providers.scim.api.providers import SCIMProviderViewSet
|
||||
from authentik.providers.scim.api.users import (
|
||||
SCIMProviderUserViewSet,
|
||||
)
|
||||
|
||||
api_urlpatterns = [
|
||||
("providers/scim", SCIMProviderViewSet),
|
||||
("providers/scim_users", SCIMProviderUserViewSet),
|
||||
("providers/scim_groups", SCIMProviderGroupViewSet),
|
||||
("propertymappings/scim", SCIMMappingViewSet),
|
||||
]
|
||||
|
@ -25,7 +25,7 @@ class ObjectFilter(ObjectPermissionsFilter):
|
||||
# Outposts (which are the only objects using internal service accounts)
|
||||
# except requests to return an empty list when they have no objects
|
||||
# assigned
|
||||
if request.user.type == UserTypes.INTERNAL_SERVICE_ACCOUNT:
|
||||
if getattr(request.user, "type", None) == UserTypes.INTERNAL_SERVICE_ACCOUNT:
|
||||
return queryset
|
||||
if not queryset.exists():
|
||||
# User doesn't have direct permission to all objects
|
||||
|
@ -147,3 +147,11 @@ class TestAPIPerms(APITestCase):
|
||||
},
|
||||
)
|
||||
self.assertEqual(res.status_code, 403)
|
||||
|
||||
def test_anonymous_user_denied(self):
|
||||
"""Test anonymous user denied"""
|
||||
res = self.client.get(reverse("authentik_api:invitation-list"))
|
||||
self.assertEqual(res.status_code, 403)
|
||||
|
||||
res = self.client.get(reverse("authentik_api:user-detail", kwargs={"pk": self.user.pk}))
|
||||
self.assertEqual(res.status_code, 403)
|
||||
|
@ -5,6 +5,7 @@ from hashlib import sha512
|
||||
from time import perf_counter, time
|
||||
from typing import Any
|
||||
|
||||
from channels.exceptions import DenyConnection
|
||||
from django.conf import settings
|
||||
from django.contrib.sessions.backends.base import UpdateError
|
||||
from django.contrib.sessions.exceptions import SessionInterrupted
|
||||
@ -271,7 +272,11 @@ class ChannelsLoggingMiddleware:
|
||||
|
||||
async def __call__(self, scope, receive, send):
|
||||
self.log(scope)
|
||||
return await self.inner(scope, receive, send)
|
||||
try:
|
||||
return await self.inner(scope, receive, send)
|
||||
except Exception as exc:
|
||||
LOGGER.warning("Exception in ASGI application", exc=exc)
|
||||
raise DenyConnection() from None
|
||||
|
||||
def log(self, scope: dict, **kwargs):
|
||||
"""Log request"""
|
||||
|
@ -161,19 +161,18 @@ class BaseLDAPSynchronizer:
|
||||
dn=object_dn,
|
||||
source=self._source,
|
||||
):
|
||||
try:
|
||||
if isinstance(value, (bytes)):
|
||||
self._logger.warning("property mapping returned bytes", mapping=mapping)
|
||||
continue
|
||||
object_field = mapping.object_field
|
||||
if object_field.startswith("attributes."):
|
||||
# Because returning a list might desired, we can't
|
||||
# rely on flatten here. Instead, just save the result as-is
|
||||
set_path_in_dict(properties, object_field, value)
|
||||
else:
|
||||
properties[object_field] = flatten(value)
|
||||
except SkipObjectException as exc:
|
||||
raise exc from exc
|
||||
if isinstance(value, (bytes)):
|
||||
self._logger.warning("property mapping returned bytes", mapping=mapping)
|
||||
continue
|
||||
object_field = mapping.object_field
|
||||
if object_field.startswith("attributes."):
|
||||
# Because returning a list might desired, we can't
|
||||
# rely on flatten here. Instead, just save the result as-is
|
||||
set_path_in_dict(properties, object_field, value)
|
||||
else:
|
||||
properties[object_field] = flatten(value)
|
||||
except SkipObjectException as exc:
|
||||
raise exc from exc
|
||||
except PropertyMappingExpressionException as exc:
|
||||
# Value error can be raised when assigning invalid data to an attribute
|
||||
Event.new(
|
||||
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -12,7 +12,15 @@ class CaptchaStageSerializer(StageSerializer):
|
||||
|
||||
class Meta:
|
||||
model = CaptchaStage
|
||||
fields = StageSerializer.Meta.fields + ["public_key", "private_key", "js_url", "api_url"]
|
||||
fields = StageSerializer.Meta.fields + [
|
||||
"public_key",
|
||||
"private_key",
|
||||
"js_url",
|
||||
"api_url",
|
||||
"score_min_threshold",
|
||||
"score_max_threshold",
|
||||
"error_on_invalid_score",
|
||||
]
|
||||
extra_kwargs = {"private_key": {"write_only": True}}
|
||||
|
||||
|
||||
|
@ -0,0 +1,31 @@
|
||||
# Generated by Django 5.0.6 on 2024-06-03 15:18
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
("authentik_stages_captcha", "0002_captchastage_api_url_captchastage_js_url_and_more"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name="captchastage",
|
||||
name="error_on_invalid_score",
|
||||
field=models.BooleanField(
|
||||
default=True,
|
||||
help_text="When enabled and the received captcha score is outside of the given threshold, the stage will show an error message. When not enabled, the flow will continue, but the data from the captcha will be available in the context for policy decisions",
|
||||
),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name="captchastage",
|
||||
name="score_max_threshold",
|
||||
field=models.FloatField(default=1.0),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name="captchastage",
|
||||
name="score_min_threshold",
|
||||
field=models.FloatField(default=0.5),
|
||||
),
|
||||
]
|
@ -14,6 +14,18 @@ class CaptchaStage(Stage):
|
||||
public_key = models.TextField(help_text=_("Public key, acquired your captcha Provider."))
|
||||
private_key = models.TextField(help_text=_("Private key, acquired your captcha Provider."))
|
||||
|
||||
score_min_threshold = models.FloatField(default=0.5) # Default values for reCaptcha
|
||||
score_max_threshold = models.FloatField(default=1.0) # Default values for reCaptcha
|
||||
|
||||
error_on_invalid_score = models.BooleanField(
|
||||
default=True,
|
||||
help_text=_(
|
||||
"When enabled and the received captcha score is outside of the given threshold, "
|
||||
"the stage will show an error message. When not enabled, the flow will continue, "
|
||||
"but the data from the captcha will be available in the context for policy decisions"
|
||||
),
|
||||
)
|
||||
|
||||
js_url = models.TextField(default="https://www.recaptcha.net/recaptcha/api.js")
|
||||
api_url = models.TextField(default="https://www.recaptcha.net/recaptcha/api/siteverify")
|
||||
|
||||
|
@ -1,6 +1,7 @@
|
||||
"""authentik captcha stage"""
|
||||
|
||||
from django.http.response import HttpResponse
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
from requests import RequestException
|
||||
from rest_framework.fields import CharField
|
||||
from rest_framework.serializers import ValidationError
|
||||
@ -16,6 +17,8 @@ from authentik.lib.utils.http import get_http_session
|
||||
from authentik.root.middleware import ClientIPMiddleware
|
||||
from authentik.stages.captcha.models import CaptchaStage
|
||||
|
||||
PLAN_CONTEXT_CAPTCHA = "captcha"
|
||||
|
||||
|
||||
class CaptchaChallenge(WithUserInfoChallenge):
|
||||
"""Site public key"""
|
||||
@ -48,11 +51,24 @@ class CaptchaChallengeResponse(ChallengeResponse):
|
||||
)
|
||||
response.raise_for_status()
|
||||
data = response.json()
|
||||
if not data.get("success", False):
|
||||
raise ValidationError(f"Failed to validate token: {data.get('error-codes', '')}")
|
||||
except RequestException as exc:
|
||||
raise ValidationError("Failed to validate token") from exc
|
||||
return token
|
||||
if stage.error_on_invalid_score:
|
||||
if not data.get("success", False):
|
||||
raise ValidationError(
|
||||
_(
|
||||
"Failed to validate token: {error}".format(
|
||||
error=data.get("error-codes", _("Unknown error"))
|
||||
)
|
||||
)
|
||||
)
|
||||
if "score" in data:
|
||||
score = float(data.get("score"))
|
||||
if stage.score_max_threshold > -1 and score > stage.score_max_threshold:
|
||||
raise ValidationError(_("Invalid captcha response"))
|
||||
if stage.score_min_threshold > -1 and score < stage.score_min_threshold:
|
||||
raise ValidationError(_("Invalid captcha response"))
|
||||
except (RequestException, TypeError) as exc:
|
||||
raise ValidationError(_("Failed to validate token")) from exc
|
||||
return data
|
||||
|
||||
|
||||
class CaptchaStageView(ChallengeStageView):
|
||||
@ -69,5 +85,10 @@ class CaptchaStageView(ChallengeStageView):
|
||||
}
|
||||
)
|
||||
|
||||
def challenge_valid(self, response: ChallengeResponse) -> HttpResponse:
|
||||
def challenge_valid(self, response: CaptchaChallengeResponse) -> HttpResponse:
|
||||
response = response.validated_data["token"]
|
||||
self.executor.plan.context[PLAN_CONTEXT_CAPTCHA] = {
|
||||
"response": response,
|
||||
"stage": self.executor.current_stage,
|
||||
}
|
||||
return self.executor.stage_ok()
|
||||
|
@ -1,6 +1,7 @@
|
||||
"""captcha tests"""
|
||||
|
||||
from django.urls import reverse
|
||||
from requests_mock import Mocker
|
||||
|
||||
from authentik.core.tests.utils import create_test_admin_user, create_test_flow
|
||||
from authentik.flows.markers import StageMarker
|
||||
@ -30,8 +31,89 @@ class TestCaptchaStage(FlowTestCase):
|
||||
)
|
||||
self.binding = FlowStageBinding.objects.create(target=self.flow, stage=self.stage, order=2)
|
||||
|
||||
def test_valid(self):
|
||||
@Mocker()
|
||||
def test_valid(self, mock: Mocker):
|
||||
"""Test valid captcha"""
|
||||
mock.post(
|
||||
"https://www.recaptcha.net/recaptcha/api/siteverify",
|
||||
json={
|
||||
"success": True,
|
||||
"score": 0.5,
|
||||
},
|
||||
)
|
||||
plan = FlowPlan(flow_pk=self.flow.pk.hex, bindings=[self.binding], markers=[StageMarker()])
|
||||
session = self.client.session
|
||||
session[SESSION_KEY_PLAN] = plan
|
||||
session.save()
|
||||
response = self.client.post(
|
||||
reverse("authentik_api:flow-executor", kwargs={"flow_slug": self.flow.slug}),
|
||||
{"token": "PASSED"},
|
||||
)
|
||||
self.assertEqual(response.status_code, 200)
|
||||
self.assertStageRedirects(response, reverse("authentik_core:root-redirect"))
|
||||
|
||||
@Mocker()
|
||||
def test_invalid_score_high(self, mock: Mocker):
|
||||
"""Test invalid captcha (score too high)"""
|
||||
mock.post(
|
||||
"https://www.recaptcha.net/recaptcha/api/siteverify",
|
||||
json={
|
||||
"success": True,
|
||||
"score": 99,
|
||||
},
|
||||
)
|
||||
plan = FlowPlan(flow_pk=self.flow.pk.hex, bindings=[self.binding], markers=[StageMarker()])
|
||||
session = self.client.session
|
||||
session[SESSION_KEY_PLAN] = plan
|
||||
session.save()
|
||||
response = self.client.post(
|
||||
reverse("authentik_api:flow-executor", kwargs={"flow_slug": self.flow.slug}),
|
||||
{"token": "PASSED"},
|
||||
)
|
||||
self.assertEqual(response.status_code, 200)
|
||||
self.assertStageResponse(
|
||||
response,
|
||||
component="ak-stage-captcha",
|
||||
response_errors={"token": [{"string": "Invalid captcha response", "code": "invalid"}]},
|
||||
)
|
||||
|
||||
@Mocker()
|
||||
def test_invalid_score_low(self, mock: Mocker):
|
||||
"""Test invalid captcha (score too low)"""
|
||||
mock.post(
|
||||
"https://www.recaptcha.net/recaptcha/api/siteverify",
|
||||
json={
|
||||
"success": True,
|
||||
"score": -3,
|
||||
},
|
||||
)
|
||||
plan = FlowPlan(flow_pk=self.flow.pk.hex, bindings=[self.binding], markers=[StageMarker()])
|
||||
session = self.client.session
|
||||
session[SESSION_KEY_PLAN] = plan
|
||||
session.save()
|
||||
response = self.client.post(
|
||||
reverse("authentik_api:flow-executor", kwargs={"flow_slug": self.flow.slug}),
|
||||
{"token": "PASSED"},
|
||||
)
|
||||
self.assertEqual(response.status_code, 200)
|
||||
self.assertStageResponse(
|
||||
response,
|
||||
component="ak-stage-captcha",
|
||||
response_errors={"token": [{"string": "Invalid captcha response", "code": "invalid"}]},
|
||||
)
|
||||
|
||||
@Mocker()
|
||||
def test_invalid_score_low_continue(self, mock: Mocker):
|
||||
"""Test invalid captcha (score too low, but continue)"""
|
||||
self.stage.error_on_invalid_score = False
|
||||
self.stage.save()
|
||||
mock.post(
|
||||
"https://www.recaptcha.net/recaptcha/api/siteverify",
|
||||
json={
|
||||
"success": True,
|
||||
"score": -3,
|
||||
},
|
||||
)
|
||||
plan = FlowPlan(flow_pk=self.flow.pk.hex, bindings=[self.binding], markers=[StageMarker()])
|
||||
session = self.client.session
|
||||
session[SESSION_KEY_PLAN] = plan
|
||||
|
@ -96,7 +96,7 @@ class TestEmailStageTemplates(FlowTestCase):
|
||||
"""Test addresses are correctly parsed"""
|
||||
message = TemplateEmailMessage(to=[("foo@bar.baz", "foo@bar.baz")])
|
||||
[sanitize_address(addr, "utf-8") for addr in message.recipients()]
|
||||
self.assertEqual(message.recipients(), ["foo@bar.baz"])
|
||||
self.assertEqual(message.recipients(), ['"foo@bar.baz" <foo@bar.baz>'])
|
||||
message = TemplateEmailMessage(to=[("some-name", "foo@bar.baz")])
|
||||
[sanitize_address(addr, "utf-8") for addr in message.recipients()]
|
||||
self.assertEqual(message.recipients(), ["some-name <foo@bar.baz>"])
|
||||
|
@ -5,6 +5,7 @@ from functools import lru_cache
|
||||
from pathlib import Path
|
||||
|
||||
from django.core.mail import EmailMultiAlternatives
|
||||
from django.core.mail.message import sanitize_address
|
||||
from django.template.exceptions import TemplateDoesNotExist
|
||||
from django.template.loader import render_to_string
|
||||
from django.utils import translation
|
||||
@ -31,10 +32,7 @@ class TemplateEmailMessage(EmailMultiAlternatives):
|
||||
sanitized_to = []
|
||||
# Ensure that all recipients are valid
|
||||
for recipient_name, recipient_email in to:
|
||||
if recipient_name == recipient_email:
|
||||
sanitized_to.append(recipient_email)
|
||||
else:
|
||||
sanitized_to.append(f"{recipient_name} <{recipient_email}>")
|
||||
sanitized_to.append(sanitize_address((recipient_name, recipient_email), "utf-8"))
|
||||
super().__init__(to=sanitized_to, **kwargs)
|
||||
if not template_name:
|
||||
return
|
||||
|
@ -6164,6 +6164,19 @@
|
||||
"type": "string",
|
||||
"minLength": 1,
|
||||
"title": "Api url"
|
||||
},
|
||||
"score_min_threshold": {
|
||||
"type": "number",
|
||||
"title": "Score min threshold"
|
||||
},
|
||||
"score_max_threshold": {
|
||||
"type": "number",
|
||||
"title": "Score max threshold"
|
||||
},
|
||||
"error_on_invalid_score": {
|
||||
"type": "boolean",
|
||||
"title": "Error on invalid score",
|
||||
"description": "When enabled and the received captcha score is outside of the given threshold, the stage will show an error message. When not enabled, the flow will continue, but the data from the captcha will be available in the context for policy decisions"
|
||||
}
|
||||
},
|
||||
"required": []
|
||||
|
@ -9,8 +9,9 @@ entries:
|
||||
model: authentik_providers_google_workspace.googleworkspaceprovidermapping
|
||||
attrs:
|
||||
name: "authentik default Google Workspace Mapping: User"
|
||||
# https://developers.google.com/admin-sdk/directory/reference/rest/v1/users#User
|
||||
expression: |
|
||||
# Field reference:
|
||||
# https://developers.google.com/admin-sdk/directory/reference/rest/v1/users#User
|
||||
# Google require givenName and familyName to be set
|
||||
givenName, familyName = request.user.name, " "
|
||||
formatted = request.user.name + " "
|
||||
@ -20,23 +21,26 @@ entries:
|
||||
if " " in request.user.name:
|
||||
givenName, _, familyName = request.user.name.partition(" ")
|
||||
formatted = request.user.name
|
||||
return {
|
||||
user = {
|
||||
"name": {
|
||||
"fullName": formatted,
|
||||
"familyName": familyName.strip(),
|
||||
"givenName": givenName.strip(),
|
||||
"displayName": formatted,
|
||||
},
|
||||
"password": request.user.password,
|
||||
"suspended": not request.user.is_active,
|
||||
}
|
||||
if not connection:
|
||||
user["password"] = request.user.password
|
||||
return user
|
||||
- identifiers:
|
||||
managed: goauthentik.io/providers/google_workspace/group
|
||||
model: authentik_providers_google_workspace.googleworkspaceprovidermapping
|
||||
attrs:
|
||||
name: "authentik default Google Workspace Mapping: Group"
|
||||
# https://developers.google.com/admin-sdk/directory/reference/rest/v1/groups#Group
|
||||
expression: |
|
||||
# Field reference:
|
||||
# https://developers.google.com/admin-sdk/directory/reference/rest/v1/groups#Group
|
||||
return {
|
||||
"name": group.name,
|
||||
}
|
||||
|
@ -9,8 +9,9 @@ entries:
|
||||
model: authentik_providers_microsoft_entra.microsoftentraprovidermapping
|
||||
attrs:
|
||||
name: "authentik default Microsoft Entra Mapping: User"
|
||||
# https://learn.microsoft.com/en-us/graph/api/resources/user?view=graph-rest-1.0
|
||||
expression: |
|
||||
# Field reference: (note that keys have to converted to snake_case)
|
||||
# https://learn.microsoft.com/en-us/graph/api/resources/user?view=graph-rest-1.0
|
||||
from msgraph.generated.models.password_profile import PasswordProfile
|
||||
|
||||
user = {
|
||||
@ -35,8 +36,9 @@ entries:
|
||||
model: authentik_providers_microsoft_entra.microsoftentraprovidermapping
|
||||
attrs:
|
||||
name: "authentik default Microsoft Entra Mapping: Group"
|
||||
# https://learn.microsoft.com/en-us/graph/api/group-post-groups?view=graph-rest-1.0&tabs=http#request-body
|
||||
expression: |
|
||||
# Field reference: (note that keys have to converted to snake_case)
|
||||
# https://learn.microsoft.com/en-us/graph/api/group-post-groups?view=graph-rest-1.0&tabs=http#request-body
|
||||
return {
|
||||
"display_name": group.name,
|
||||
"mail_enabled": False,
|
||||
|
8
go.mod
8
go.mod
@ -16,21 +16,21 @@ require (
|
||||
github.com/gorilla/mux v1.8.1
|
||||
github.com/gorilla/securecookie v1.1.2
|
||||
github.com/gorilla/sessions v1.2.2
|
||||
github.com/gorilla/websocket v1.5.1
|
||||
github.com/gorilla/websocket v1.5.2
|
||||
github.com/jellydator/ttlcache/v3 v3.2.0
|
||||
github.com/mitchellh/mapstructure v1.5.0
|
||||
github.com/nmcclain/asn1-ber v0.0.0-20170104154839-2661553a0484
|
||||
github.com/pires/go-proxyproto v0.7.0
|
||||
github.com/prometheus/client_golang v1.19.1
|
||||
github.com/redis/go-redis/v9 v9.5.2
|
||||
github.com/redis/go-redis/v9 v9.5.3
|
||||
github.com/sethvargo/go-envconfig v1.0.3
|
||||
github.com/sirupsen/logrus v1.9.3
|
||||
github.com/spf13/cobra v1.8.0
|
||||
github.com/stretchr/testify v1.9.0
|
||||
github.com/wwt/guac v1.3.2
|
||||
goauthentik.io/api/v3 v3.2024042.9
|
||||
goauthentik.io/api/v3 v3.2024042.11
|
||||
golang.org/x/exp v0.0.0-20230210204819-062eb4c674ab
|
||||
golang.org/x/oauth2 v0.20.0
|
||||
golang.org/x/oauth2 v0.21.0
|
||||
golang.org/x/sync v0.7.0
|
||||
gopkg.in/yaml.v2 v2.4.0
|
||||
layeh.com/radius v0.0.0-20210819152912-ad72663a72ab
|
||||
|
16
go.sum
16
go.sum
@ -176,8 +176,8 @@ github.com/gorilla/sessions v1.2.1/go.mod h1:dk2InVEVJ0sfLlnXv9EAgkf6ecYs/i80K/z
|
||||
github.com/gorilla/sessions v1.2.2 h1:lqzMYz6bOfvn2WriPUjNByzeXIlVzURcPmgMczkmTjY=
|
||||
github.com/gorilla/sessions v1.2.2/go.mod h1:ePLdVu+jbEgHH+KWw8I1z2wqd0BAdAQh/8LRvBeoNcQ=
|
||||
github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||
github.com/gorilla/websocket v1.5.1 h1:gmztn0JnHVt9JZquRuzLw3g4wouNVzKL15iLr/zn/QY=
|
||||
github.com/gorilla/websocket v1.5.1/go.mod h1:x3kM2JMyaluk02fnUJpQuwD2dCS5NDG2ZHL0uE0tcaY=
|
||||
github.com/gorilla/websocket v1.5.2 h1:qoW6V1GT3aZxybsbC6oLnailWnB+qTMVwMreOso9XUw=
|
||||
github.com/gorilla/websocket v1.5.2/go.mod h1:0n9H61RBAcf5/38py2MCYbxzPIY9rOkpvvMT24Rqs30=
|
||||
github.com/hashicorp/go-uuid v1.0.2/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
|
||||
github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8=
|
||||
github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
|
||||
@ -242,8 +242,8 @@ github.com/prometheus/common v0.48.0 h1:QO8U2CdOzSn1BBsmXJXduaaW+dY/5QLjfB8svtSz
|
||||
github.com/prometheus/common v0.48.0/go.mod h1:0/KsvlIEfPQCQ5I2iNSAWKPZziNCvRs5EC6ILDTlAPc=
|
||||
github.com/prometheus/procfs v0.12.0 h1:jluTpSng7V9hY0O2R9DzzJHYb2xULk9VTR1V1R/k6Bo=
|
||||
github.com/prometheus/procfs v0.12.0/go.mod h1:pcuDEFsWDnvcgNzo4EEweacyhjeA9Zk3cnaOZAZEfOo=
|
||||
github.com/redis/go-redis/v9 v9.5.2 h1:L0L3fcSNReTRGyZ6AqAEN0K56wYeYAwapBIhkvh0f3E=
|
||||
github.com/redis/go-redis/v9 v9.5.2/go.mod h1:hdY0cQFCN4fnSYT6TkisLufl/4W5UIXyv0b/CLO2V2M=
|
||||
github.com/redis/go-redis/v9 v9.5.3 h1:fOAp1/uJG+ZtcITgZOfYFmTKPE7n4Vclj1wZFgRciUU=
|
||||
github.com/redis/go-redis/v9 v9.5.3/go.mod h1:hdY0cQFCN4fnSYT6TkisLufl/4W5UIXyv0b/CLO2V2M=
|
||||
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
||||
github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M=
|
||||
github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA=
|
||||
@ -294,8 +294,8 @@ go.opentelemetry.io/otel/trace v1.24.0 h1:CsKnnL4dUAr/0llH9FKuc698G04IrpWV0MQA/Y
|
||||
go.opentelemetry.io/otel/trace v1.24.0/go.mod h1:HPc3Xr/cOApsBI154IU0OI0HJexz+aw5uPdbs3UCjNU=
|
||||
go.uber.org/goleak v1.2.1 h1:NBol2c7O1ZokfZ0LEU9K6Whx/KnwvepVetCUhtKja4A=
|
||||
go.uber.org/goleak v1.2.1/go.mod h1:qlT2yGI9QafXHhZZLxlSuNsMw3FFLxBr+tBRlmO1xH4=
|
||||
goauthentik.io/api/v3 v3.2024042.9 h1:zj3nqmOEHNBsfANTv7Ec4yLZA755GKHU+WLz2t+nfaI=
|
||||
goauthentik.io/api/v3 v3.2024042.9/go.mod h1:zz+mEZg8rY/7eEjkMGWJ2DnGqk+zqxuybGCGrR2O4Kw=
|
||||
goauthentik.io/api/v3 v3.2024042.11 h1:cGgUz1E8rlMphGvv04VI7i+MgT8eidZbxTpza5zd96I=
|
||||
goauthentik.io/api/v3 v3.2024042.11/go.mod h1:zz+mEZg8rY/7eEjkMGWJ2DnGqk+zqxuybGCGrR2O4Kw=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
@ -382,8 +382,8 @@ golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4Iltr
|
||||
golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
||||
golang.org/x/oauth2 v0.20.0 h1:4mQdhULixXKP1rwYBW0vAijoXnkTG0BLCDRzfe1idMo=
|
||||
golang.org/x/oauth2 v0.20.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI=
|
||||
golang.org/x/oauth2 v0.21.0 h1:tsimM75w1tF/uws5rbeHzIWxEqElMehnc+iW793zsZs=
|
||||
golang.org/x/oauth2 v0.21.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI=
|
||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
|
@ -38,7 +38,6 @@ func (cs *CryptoStore) AddKeypair(uuid string) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
cs.fingerprints[uuid] = cs.getFingerprint(uuid)
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -73,6 +72,7 @@ func (cs *CryptoStore) Fetch(uuid string) error {
|
||||
return err
|
||||
}
|
||||
cs.certificates[uuid] = &x509cert
|
||||
cs.fingerprints[uuid] = cfp
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -8,7 +8,7 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2024-06-03 00:08+0000\n"
|
||||
"POT-Creation-Date: 2024-06-05 00:07+0000\n"
|
||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||
@ -2363,6 +2363,14 @@ msgstr ""
|
||||
msgid "Private key, acquired your captcha Provider."
|
||||
msgstr ""
|
||||
|
||||
#: authentik/stages/captcha/models.py
|
||||
msgid ""
|
||||
"When enabled and the received captcha score is outside of the given "
|
||||
"threshold, the stage will show an error message. When not enabled, the flow "
|
||||
"will continue, but the data from the captcha will be available in the "
|
||||
"context for policy decisions"
|
||||
msgstr ""
|
||||
|
||||
#: authentik/stages/captcha/models.py
|
||||
msgid "Captcha Stage"
|
||||
msgstr ""
|
||||
@ -2371,6 +2379,23 @@ msgstr ""
|
||||
msgid "Captcha Stages"
|
||||
msgstr ""
|
||||
|
||||
#: authentik/stages/captcha/stage.py
|
||||
msgid "Unknown error"
|
||||
msgstr ""
|
||||
|
||||
#: authentik/stages/captcha/stage.py
|
||||
#, python-brace-format
|
||||
msgid "Failed to validate token: {error}"
|
||||
msgstr ""
|
||||
|
||||
#: authentik/stages/captcha/stage.py
|
||||
msgid "Invalid captcha response"
|
||||
msgstr ""
|
||||
|
||||
#: authentik/stages/captcha/stage.py
|
||||
msgid "Failed to validate token"
|
||||
msgstr ""
|
||||
|
||||
#: authentik/stages/consent/models.py
|
||||
msgid ""
|
||||
"Offset after which consent expires. (Format: hours=1;minutes=2;seconds=3)."
|
||||
|
Binary file not shown.
@ -19,7 +19,7 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2024-05-03 00:08+0000\n"
|
||||
"POT-Creation-Date: 2024-06-05 00:07+0000\n"
|
||||
"PO-Revision-Date: 2022-09-26 16:47+0000\n"
|
||||
"Last-Translator: Marc Schmitt, 2024\n"
|
||||
"Language-Team: French (https://app.transifex.com/authentik/teams/119923/fr/)\n"
|
||||
@ -106,12 +106,14 @@ msgid "Brands"
|
||||
msgstr "Marques"
|
||||
|
||||
#: authentik/core/api/providers.py
|
||||
msgid "SAML Provider from Metadata"
|
||||
msgstr "Fournisseur SAML depuis métadonnées"
|
||||
|
||||
#: authentik/core/api/providers.py
|
||||
msgid "Create a SAML Provider by importing its Metadata."
|
||||
msgstr "Créer un fournisseur SAML en important ses métadonnées."
|
||||
msgid ""
|
||||
"When not set all providers are returned. When set to true, only backchannel "
|
||||
"providers are returned. When set to false, backchannel providers are "
|
||||
"excluded"
|
||||
msgstr ""
|
||||
"Si non défini, tous les fournisseurs sont retournés. Si vrai, seul les "
|
||||
"fournisseurs backchannels sont retournés. Si faux, les fournisseurs "
|
||||
"backchannels sont exclus"
|
||||
|
||||
#: authentik/core/api/users.py
|
||||
msgid "No leading or trailing slashes allowed."
|
||||
@ -466,6 +468,74 @@ msgstr "Entreprise est requis pour accéder à cette fonctionnalité."
|
||||
msgid "Feature only accessible for internal users."
|
||||
msgstr "Fonctionnalité accessible aux utilisateurs internes uniquement."
|
||||
|
||||
#: authentik/enterprise/providers/google_workspace/models.py
|
||||
#: authentik/enterprise/providers/microsoft_entra/models.py
|
||||
#: authentik/providers/scim/models.py authentik/sources/ldap/models.py
|
||||
msgid "Property mappings used for group creation/updating."
|
||||
msgstr ""
|
||||
"Mappages de propriétés utilisés lors de la création et de la mise à jour des"
|
||||
" groupes."
|
||||
|
||||
#: authentik/enterprise/providers/google_workspace/models.py
|
||||
msgid "Google Workspace Provider"
|
||||
msgstr "Fournisseur Google Workspace"
|
||||
|
||||
#: authentik/enterprise/providers/google_workspace/models.py
|
||||
msgid "Google Workspace Providers"
|
||||
msgstr "Fournisseurs Google Workspace"
|
||||
|
||||
#: authentik/enterprise/providers/google_workspace/models.py
|
||||
msgid "Google Workspace Provider Mapping"
|
||||
msgstr "Mappage de propriété Google Workspace"
|
||||
|
||||
#: authentik/enterprise/providers/google_workspace/models.py
|
||||
msgid "Google Workspace Provider Mappings"
|
||||
msgstr "Mappages de propriété Google Workspace"
|
||||
|
||||
#: authentik/enterprise/providers/google_workspace/models.py
|
||||
msgid "Google Workspace Provider User"
|
||||
msgstr "Utilisateur du fournisseur Google Workspace"
|
||||
|
||||
#: authentik/enterprise/providers/google_workspace/models.py
|
||||
msgid "Google Workspace Provider Users"
|
||||
msgstr "Utilisateurs du fournisseur Google Workspace"
|
||||
|
||||
#: authentik/enterprise/providers/google_workspace/models.py
|
||||
msgid "Google Workspace Provider Group"
|
||||
msgstr "Groupe du fournisseur Google Workspace"
|
||||
|
||||
#: authentik/enterprise/providers/google_workspace/models.py
|
||||
msgid "Google Workspace Provider Groups"
|
||||
msgstr "Groupes du fournisseur Google Workspace"
|
||||
|
||||
#: authentik/enterprise/providers/microsoft_entra/models.py
|
||||
msgid "Microsoft Entra Provider"
|
||||
msgstr "Fournisseur Microsoft Entra"
|
||||
|
||||
#: authentik/enterprise/providers/microsoft_entra/models.py
|
||||
msgid "Microsoft Entra Providers"
|
||||
msgstr "Fournisseurs Microsoft Entra"
|
||||
|
||||
#: authentik/enterprise/providers/microsoft_entra/models.py
|
||||
msgid "Microsoft Entra Provider Mapping"
|
||||
msgstr "Mappage de propriété Microsoft Entra"
|
||||
|
||||
#: authentik/enterprise/providers/microsoft_entra/models.py
|
||||
msgid "Microsoft Entra Provider Mappings"
|
||||
msgstr "Mappages de propriété Microsoft Entra"
|
||||
|
||||
#: authentik/enterprise/providers/microsoft_entra/models.py
|
||||
msgid "Microsoft Entra Provider User"
|
||||
msgstr "Utilisateur du fournisseur Microsoft Entra"
|
||||
|
||||
#: authentik/enterprise/providers/microsoft_entra/models.py
|
||||
msgid "Microsoft Entra Provider Group"
|
||||
msgstr "Groupe du fournisseur Microsoft Entra"
|
||||
|
||||
#: authentik/enterprise/providers/microsoft_entra/models.py
|
||||
msgid "Microsoft Entra Provider Groups"
|
||||
msgstr "Groupes du fournisseur Microsoft Entra"
|
||||
|
||||
#: authentik/enterprise/providers/rac/models.py
|
||||
#: authentik/stages/user_login/models.py
|
||||
msgid ""
|
||||
@ -838,6 +908,25 @@ msgstr "Jetons du flux"
|
||||
msgid "Invalid next URL"
|
||||
msgstr "URL suivante invalide"
|
||||
|
||||
#: authentik/lib/sync/outgoing/tasks.py
|
||||
msgid "Starting full provider sync"
|
||||
msgstr "Démarrage d'une synchronisation complète du fournisseur"
|
||||
|
||||
#: authentik/lib/sync/outgoing/tasks.py
|
||||
#, python-format
|
||||
msgid "Syncing page %(page)d of users"
|
||||
msgstr "Synchronisation de la page %(page)d d'utilisateurs"
|
||||
|
||||
#: authentik/lib/sync/outgoing/tasks.py
|
||||
#, python-format
|
||||
msgid "Syncing page %(page)d of groups"
|
||||
msgstr "Synchronisation de la page %(page)d de groupes"
|
||||
|
||||
#: authentik/lib/sync/outgoing/tasks.py
|
||||
#, python-brace-format
|
||||
msgid "Stopping sync due to error: {error}"
|
||||
msgstr "Arrêt de la synchronisation due à l'erreur : {error}"
|
||||
|
||||
#: authentik/lib/utils/time.py
|
||||
#, python-format
|
||||
msgid "%(value)s is not in the correct format of 'hours=3;minutes=1'."
|
||||
@ -1526,10 +1615,6 @@ msgstr "Compatibilité GitHub : accès aux adresses email"
|
||||
msgid "GitHub Compatibility: Access your Groups"
|
||||
msgstr "Compatibilité GitHub : accès aux groupes"
|
||||
|
||||
#: authentik/providers/oauth2/views/userinfo.py
|
||||
msgid "authentik API Access on behalf of your user"
|
||||
msgstr "Accès à l'API authentik au nom des utilisateurs"
|
||||
|
||||
#: authentik/providers/proxy/api.py
|
||||
msgid "User and password attributes must be set when basic auth is enabled."
|
||||
msgstr ""
|
||||
@ -1811,6 +1896,14 @@ msgstr "Mappages de propriétés SAML"
|
||||
msgid "SAML Property Mappings"
|
||||
msgstr "Mappages de propriétés SAML"
|
||||
|
||||
#: authentik/providers/saml/models.py
|
||||
msgid "SAML Provider from Metadata"
|
||||
msgstr "Fournisseur SAML depuis métadonnées"
|
||||
|
||||
#: authentik/providers/saml/models.py
|
||||
msgid "SAML Providers from Metadata"
|
||||
msgstr "Fournisseurs SAML depuis métadonnées"
|
||||
|
||||
#: authentik/providers/scim/models.py
|
||||
msgid "Base URL to SCIM requests, usually ends in /v2"
|
||||
msgstr "URL de base pour les requêtes SCIM, se terminant généralement par /v2"
|
||||
@ -1819,12 +1912,6 @@ msgstr "URL de base pour les requêtes SCIM, se terminant généralement par /v2
|
||||
msgid "Authentication token"
|
||||
msgstr "Jeton d'authentification"
|
||||
|
||||
#: authentik/providers/scim/models.py authentik/sources/ldap/models.py
|
||||
msgid "Property mappings used for group creation/updating."
|
||||
msgstr ""
|
||||
"Mappages de propriétés utilisés lors de la création et de la mise à jour des"
|
||||
" groupes."
|
||||
|
||||
#: authentik/providers/scim/models.py
|
||||
msgid "SCIM Provider"
|
||||
msgstr "Fournisseur SCIM"
|
||||
@ -1841,39 +1928,6 @@ msgstr "Mappage SCIM"
|
||||
msgid "SCIM Mappings"
|
||||
msgstr "Mappages SCIM"
|
||||
|
||||
#: authentik/providers/scim/tasks.py
|
||||
msgid "Starting full SCIM sync"
|
||||
msgstr "Démarrage d'une synchronisation SCIM complète"
|
||||
|
||||
#: authentik/providers/scim/tasks.py
|
||||
#, python-format
|
||||
msgid "Syncing page %(page)d of users"
|
||||
msgstr "Synchronisation de la page %(page)d d'utilisateurs"
|
||||
|
||||
#: authentik/providers/scim/tasks.py
|
||||
#, python-format
|
||||
msgid "Syncing page %(page)d of groups"
|
||||
msgstr "Synchronisation de la page %(page)d de groupes"
|
||||
|
||||
#: authentik/providers/scim/tasks.py
|
||||
#, python-brace-format
|
||||
msgid "Failed to sync user {user_name} due to remote error: {error}"
|
||||
msgstr ""
|
||||
"Échec de synchronisation de l'utilisateur {user_name} dû à une erreur "
|
||||
"distante : {error}"
|
||||
|
||||
#: authentik/providers/scim/tasks.py
|
||||
#, python-brace-format
|
||||
msgid "Stopping sync due to error: {error}"
|
||||
msgstr "Arrêt de la synchronisation due à l'erreur : {error}"
|
||||
|
||||
#: authentik/providers/scim/tasks.py
|
||||
#, python-brace-format
|
||||
msgid "Failed to sync group {group_name} due to remote error: {error}"
|
||||
msgstr ""
|
||||
"Échec de synchronisation du groupe {group_name} dû à une erreur distante : "
|
||||
"{error}"
|
||||
|
||||
#: authentik/rbac/models.py
|
||||
msgid "Role"
|
||||
msgstr "Rôle"
|
||||
@ -1894,14 +1948,6 @@ msgstr "Permissions système"
|
||||
msgid "Can view system info"
|
||||
msgstr "Peut voir les informations du système"
|
||||
|
||||
#: authentik/rbac/models.py
|
||||
msgid "Can view system tasks"
|
||||
msgstr "Peut voir les tâches du système"
|
||||
|
||||
#: authentik/rbac/models.py
|
||||
msgid "Can run system tasks"
|
||||
msgstr "Peut lancer des tâches système"
|
||||
|
||||
#: authentik/rbac/models.py
|
||||
msgid "Can access admin interface"
|
||||
msgstr "Peut accéder à l'interface d'administration"
|
||||
@ -2562,6 +2608,18 @@ msgstr "Clé publique, acquise auprès de votre fournisseur captcha."
|
||||
msgid "Private key, acquired your captcha Provider."
|
||||
msgstr "Clé privée, acquise auprès de votre fournisseur captcha."
|
||||
|
||||
#: authentik/stages/captcha/models.py
|
||||
msgid ""
|
||||
"When enabled and the received captcha score is outside of the given "
|
||||
"threshold, the stage will show an error message. When not enabled, the flow "
|
||||
"will continue, but the data from the captcha will be available in the "
|
||||
"context for policy decisions"
|
||||
msgstr ""
|
||||
"Si activé et le score captcha reçu est hors de la limite donnée, l'étape "
|
||||
"affichera un message d'erreur. Si désactivé, le flux continuera, mais la "
|
||||
"donnée du captcha sera disponible dans le contexte pour décision dans une "
|
||||
"politique."
|
||||
|
||||
#: authentik/stages/captcha/models.py
|
||||
msgid "Captcha Stage"
|
||||
msgstr "Étape de Captcha"
|
||||
@ -2570,6 +2628,23 @@ msgstr "Étape de Captcha"
|
||||
msgid "Captcha Stages"
|
||||
msgstr "Étapes de Captcha"
|
||||
|
||||
#: authentik/stages/captcha/stage.py
|
||||
msgid "Unknown error"
|
||||
msgstr "Erreur inconnue"
|
||||
|
||||
#: authentik/stages/captcha/stage.py
|
||||
#, python-brace-format
|
||||
msgid "Failed to validate token: {error}"
|
||||
msgstr "Échec de validation du jeton : {error}"
|
||||
|
||||
#: authentik/stages/captcha/stage.py
|
||||
msgid "Invalid captcha response"
|
||||
msgstr "Réponse captcha invalide"
|
||||
|
||||
#: authentik/stages/captcha/stage.py
|
||||
msgid "Failed to validate token"
|
||||
msgstr "Échec de validation du jeton"
|
||||
|
||||
#: authentik/stages/consent/models.py
|
||||
msgid ""
|
||||
"Offset after which consent expires. (Format: hours=1;minutes=2;seconds=3)."
|
||||
|
File diff suppressed because it is too large
Load Diff
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Binary file not shown.
@ -9,16 +9,16 @@
|
||||
# Nicholas Winterhalter, 2023
|
||||
# Ренат Шарафутдинов, 2023
|
||||
# Stepan Karavaev, 2024
|
||||
# Anton Babenko, 2024
|
||||
# Anton, 2024
|
||||
#
|
||||
#, fuzzy
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2024-06-03 00:08+0000\n"
|
||||
"POT-Creation-Date: 2024-06-05 00:07+0000\n"
|
||||
"PO-Revision-Date: 2022-09-26 16:47+0000\n"
|
||||
"Last-Translator: Anton Babenko, 2024\n"
|
||||
"Last-Translator: Anton, 2024\n"
|
||||
"Language-Team: Russian (https://app.transifex.com/authentik/teams/119923/ru/)\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
@ -162,7 +162,7 @@ msgstr "Сбросить пароль"
|
||||
|
||||
#: authentik/core/models.py
|
||||
msgid "Can impersonate other users"
|
||||
msgstr "Может выдавать себя за других пользователей"
|
||||
msgstr "Может имитировать других пользователей"
|
||||
|
||||
#: authentik/core/models.py authentik/rbac/models.py
|
||||
msgid "Can assign permissions to users"
|
||||
@ -2589,6 +2589,18 @@ msgstr "Открытый ключ, полученный от вашего про
|
||||
msgid "Private key, acquired your captcha Provider."
|
||||
msgstr "Закрытый ключ, полученный от вашего провайдера капчи."
|
||||
|
||||
#: authentik/stages/captcha/models.py
|
||||
msgid ""
|
||||
"When enabled and the received captcha score is outside of the given "
|
||||
"threshold, the stage will show an error message. When not enabled, the flow "
|
||||
"will continue, but the data from the captcha will be available in the "
|
||||
"context for policy decisions"
|
||||
msgstr ""
|
||||
"Когда эта опция включена, и полученная оценка капчи находится за пределами "
|
||||
"заданного порогового значения, на этом этапе будет показано сообщение об "
|
||||
"ошибке. Когда эта опция не включена, поток будет продолжаться, но данные "
|
||||
"капчи будут доступны в контексте для принятия решений политики"
|
||||
|
||||
#: authentik/stages/captcha/models.py
|
||||
msgid "Captcha Stage"
|
||||
msgstr "Этап с каптчей"
|
||||
@ -2597,6 +2609,23 @@ msgstr "Этап с каптчей"
|
||||
msgid "Captcha Stages"
|
||||
msgstr "Этапы с каптчей"
|
||||
|
||||
#: authentik/stages/captcha/stage.py
|
||||
msgid "Unknown error"
|
||||
msgstr "Неизвестная ошибка"
|
||||
|
||||
#: authentik/stages/captcha/stage.py
|
||||
#, python-brace-format
|
||||
msgid "Failed to validate token: {error}"
|
||||
msgstr "Ошибка валидации токена: {error}"
|
||||
|
||||
#: authentik/stages/captcha/stage.py
|
||||
msgid "Invalid captcha response"
|
||||
msgstr "Неверный ответ на капчу"
|
||||
|
||||
#: authentik/stages/captcha/stage.py
|
||||
msgid "Failed to validate token"
|
||||
msgstr "Ошибка валидации токена"
|
||||
|
||||
#: authentik/stages/consent/models.py
|
||||
msgid ""
|
||||
"Offset after which consent expires. (Format: hours=1;minutes=2;seconds=3)."
|
||||
@ -3054,7 +3083,7 @@ msgstr "Разделитель: Статическая разделительн
|
||||
#: authentik/stages/prompt/models.py
|
||||
msgid "Hidden: Hidden field, can be used to insert data into form."
|
||||
msgstr ""
|
||||
"Скрытый: Скрытое поле, может быть использовано для вставки данных в форму."
|
||||
"Скрыто: Скрытое поле, может быть использовано для вставки данных в форму."
|
||||
|
||||
#: authentik/stages/prompt/models.py
|
||||
msgid "Static: Static value, displayed as-is."
|
||||
@ -3086,7 +3115,7 @@ msgid ""
|
||||
msgstr ""
|
||||
"По желанию предварительно заполните поле ввода начальным значением. При "
|
||||
"создании поля с фиксированным выбором включите интерпретацию как выражение и"
|
||||
" возврат списка, чтобы вернуть несколько вариантов по умолчанию."
|
||||
" возвращайте список, чтобы вернуть несколько вариантов по умолчанию."
|
||||
|
||||
#: authentik/stages/prompt/models.py
|
||||
msgid "Prompt"
|
||||
|
@ -7,17 +7,17 @@
|
||||
# Chen Zhikai, 2022
|
||||
# 刘松, 2022
|
||||
# Jens L. <jens@goauthentik.io>, 2024
|
||||
# deluxghost, 2024
|
||||
# Tianhao Chai <cth451@gmail.com>, 2024
|
||||
# deluxghost, 2024
|
||||
#
|
||||
#, fuzzy
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2024-06-03 00:08+0000\n"
|
||||
"POT-Creation-Date: 2024-06-05 00:07+0000\n"
|
||||
"PO-Revision-Date: 2022-09-26 16:47+0000\n"
|
||||
"Last-Translator: Tianhao Chai <cth451@gmail.com>, 2024\n"
|
||||
"Last-Translator: deluxghost, 2024\n"
|
||||
"Language-Team: Chinese Simplified (https://app.transifex.com/authentik/teams/119923/zh-Hans/)\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
@ -2401,6 +2401,14 @@ msgstr "公钥,从您的验证码提供商处取得。"
|
||||
msgid "Private key, acquired your captcha Provider."
|
||||
msgstr "私钥,从您的验证码提供商处取得。"
|
||||
|
||||
#: authentik/stages/captcha/models.py
|
||||
msgid ""
|
||||
"When enabled and the received captcha score is outside of the given "
|
||||
"threshold, the stage will show an error message. When not enabled, the flow "
|
||||
"will continue, but the data from the captcha will be available in the "
|
||||
"context for policy decisions"
|
||||
msgstr "启用时,如果接收到的验证码分数超出给定的阈值,此阶段将显示错误信息。未启用时,流程会继续,但来自验证码的数据可在上下文中用于策略决定。"
|
||||
|
||||
#: authentik/stages/captcha/models.py
|
||||
msgid "Captcha Stage"
|
||||
msgstr "验证码阶段"
|
||||
@ -2409,6 +2417,23 @@ msgstr "验证码阶段"
|
||||
msgid "Captcha Stages"
|
||||
msgstr "验证码阶段"
|
||||
|
||||
#: authentik/stages/captcha/stage.py
|
||||
msgid "Unknown error"
|
||||
msgstr "未知错误"
|
||||
|
||||
#: authentik/stages/captcha/stage.py
|
||||
#, python-brace-format
|
||||
msgid "Failed to validate token: {error}"
|
||||
msgstr "验证令牌失败:{error}"
|
||||
|
||||
#: authentik/stages/captcha/stage.py
|
||||
msgid "Invalid captcha response"
|
||||
msgstr "验证码响应无效"
|
||||
|
||||
#: authentik/stages/captcha/stage.py
|
||||
msgid "Failed to validate token"
|
||||
msgstr "验证令牌失败"
|
||||
|
||||
#: authentik/stages/consent/models.py
|
||||
msgid ""
|
||||
"Offset after which consent expires. (Format: hours=1;minutes=2;seconds=3)."
|
||||
|
@ -14,7 +14,7 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2024-06-03 00:08+0000\n"
|
||||
"POT-Creation-Date: 2024-06-05 00:07+0000\n"
|
||||
"PO-Revision-Date: 2022-09-26 16:47+0000\n"
|
||||
"Last-Translator: deluxghost, 2024\n"
|
||||
"Language-Team: Chinese (China) (https://app.transifex.com/authentik/teams/119923/zh_CN/)\n"
|
||||
@ -2400,6 +2400,14 @@ msgstr "公钥,从您的验证码提供商处取得。"
|
||||
msgid "Private key, acquired your captcha Provider."
|
||||
msgstr "私钥,从您的验证码提供商处取得。"
|
||||
|
||||
#: authentik/stages/captcha/models.py
|
||||
msgid ""
|
||||
"When enabled and the received captcha score is outside of the given "
|
||||
"threshold, the stage will show an error message. When not enabled, the flow "
|
||||
"will continue, but the data from the captcha will be available in the "
|
||||
"context for policy decisions"
|
||||
msgstr "启用时,如果接收到的验证码分数超出给定的阈值,此阶段将显示错误信息。未启用时,流程会继续,但来自验证码的数据可在上下文中用于策略决定。"
|
||||
|
||||
#: authentik/stages/captcha/models.py
|
||||
msgid "Captcha Stage"
|
||||
msgstr "验证码阶段"
|
||||
@ -2408,6 +2416,23 @@ msgstr "验证码阶段"
|
||||
msgid "Captcha Stages"
|
||||
msgstr "验证码阶段"
|
||||
|
||||
#: authentik/stages/captcha/stage.py
|
||||
msgid "Unknown error"
|
||||
msgstr "未知错误"
|
||||
|
||||
#: authentik/stages/captcha/stage.py
|
||||
#, python-brace-format
|
||||
msgid "Failed to validate token: {error}"
|
||||
msgstr "验证令牌失败:{error}"
|
||||
|
||||
#: authentik/stages/captcha/stage.py
|
||||
msgid "Invalid captcha response"
|
||||
msgstr "验证码响应无效"
|
||||
|
||||
#: authentik/stages/captcha/stage.py
|
||||
msgid "Failed to validate token"
|
||||
msgstr "验证令牌失败"
|
||||
|
||||
#: authentik/stages/consent/models.py
|
||||
msgid ""
|
||||
"Offset after which consent expires. (Format: hours=1;minutes=2;seconds=3)."
|
||||
|
348
poetry.lock
generated
348
poetry.lock
generated
@ -1,4 +1,4 @@
|
||||
# This file is automatically @generated by Poetry 1.7.1 and should not be changed by hand.
|
||||
# This file is automatically @generated by Poetry 1.8.2 and should not be changed by hand.
|
||||
|
||||
[[package]]
|
||||
name = "aiohttp"
|
||||
@ -336,13 +336,13 @@ aio = ["aiohttp (>=3.0)"]
|
||||
|
||||
[[package]]
|
||||
name = "azure-identity"
|
||||
version = "1.16.0"
|
||||
version = "1.16.1"
|
||||
description = "Microsoft Azure Identity Library for Python"
|
||||
optional = false
|
||||
python-versions = ">=3.8"
|
||||
files = [
|
||||
{file = "azure-identity-1.16.0.tar.gz", hash = "sha256:6ff1d667cdcd81da1ceab42f80a0be63ca846629f518a922f7317a7e3c844e1b"},
|
||||
{file = "azure_identity-1.16.0-py3-none-any.whl", hash = "sha256:722fdb60b8fdd55fa44dc378b8072f4b419b56a5e54c0de391f644949f3a826f"},
|
||||
{file = "azure-identity-1.16.1.tar.gz", hash = "sha256:6d93f04468f240d59246d8afde3091494a5040d4f141cad0f49fc0c399d0d91e"},
|
||||
{file = "azure_identity-1.16.1-py3-none-any.whl", hash = "sha256:8fb07c25642cd4ac422559a8b50d3e77f73dcc2bbfaba419d06d6c9d7cff6726"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
@ -1020,43 +1020,43 @@ toml = ["tomli"]
|
||||
|
||||
[[package]]
|
||||
name = "cryptography"
|
||||
version = "42.0.7"
|
||||
version = "42.0.8"
|
||||
description = "cryptography is a package which provides cryptographic recipes and primitives to Python developers."
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
files = [
|
||||
{file = "cryptography-42.0.7-cp37-abi3-macosx_10_12_universal2.whl", hash = "sha256:a987f840718078212fdf4504d0fd4c6effe34a7e4740378e59d47696e8dfb477"},
|
||||
{file = "cryptography-42.0.7-cp37-abi3-macosx_10_12_x86_64.whl", hash = "sha256:bd13b5e9b543532453de08bcdc3cc7cebec6f9883e886fd20a92f26940fd3e7a"},
|
||||
{file = "cryptography-42.0.7-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a79165431551042cc9d1d90e6145d5d0d3ab0f2d66326c201d9b0e7f5bf43604"},
|
||||
{file = "cryptography-42.0.7-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a47787a5e3649008a1102d3df55424e86606c9bae6fb77ac59afe06d234605f8"},
|
||||
{file = "cryptography-42.0.7-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:02c0eee2d7133bdbbc5e24441258d5d2244beb31da5ed19fbb80315f4bbbff55"},
|
||||
{file = "cryptography-42.0.7-cp37-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:5e44507bf8d14b36b8389b226665d597bc0f18ea035d75b4e53c7b1ea84583cc"},
|
||||
{file = "cryptography-42.0.7-cp37-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:7f8b25fa616d8b846aef64b15c606bb0828dbc35faf90566eb139aa9cff67af2"},
|
||||
{file = "cryptography-42.0.7-cp37-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:93a3209f6bb2b33e725ed08ee0991b92976dfdcf4e8b38646540674fc7508e13"},
|
||||
{file = "cryptography-42.0.7-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:e6b8f1881dac458c34778d0a424ae5769de30544fc678eac51c1c8bb2183e9da"},
|
||||
{file = "cryptography-42.0.7-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:3de9a45d3b2b7d8088c3fbf1ed4395dfeff79d07842217b38df14ef09ce1d8d7"},
|
||||
{file = "cryptography-42.0.7-cp37-abi3-win32.whl", hash = "sha256:789caea816c6704f63f6241a519bfa347f72fbd67ba28d04636b7c6b7da94b0b"},
|
||||
{file = "cryptography-42.0.7-cp37-abi3-win_amd64.whl", hash = "sha256:8cb8ce7c3347fcf9446f201dc30e2d5a3c898d009126010cbd1f443f28b52678"},
|
||||
{file = "cryptography-42.0.7-cp39-abi3-macosx_10_12_universal2.whl", hash = "sha256:a3a5ac8b56fe37f3125e5b72b61dcde43283e5370827f5233893d461b7360cd4"},
|
||||
{file = "cryptography-42.0.7-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:779245e13b9a6638df14641d029add5dc17edbef6ec915688f3acb9e720a5858"},
|
||||
{file = "cryptography-42.0.7-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0d563795db98b4cd57742a78a288cdbdc9daedac29f2239793071fe114f13785"},
|
||||
{file = "cryptography-42.0.7-cp39-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:31adb7d06fe4383226c3e963471f6837742889b3c4caa55aac20ad951bc8ffda"},
|
||||
{file = "cryptography-42.0.7-cp39-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:efd0bf5205240182e0f13bcaea41be4fdf5c22c5129fc7ced4a0282ac86998c9"},
|
||||
{file = "cryptography-42.0.7-cp39-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:a9bc127cdc4ecf87a5ea22a2556cab6c7eda2923f84e4f3cc588e8470ce4e42e"},
|
||||
{file = "cryptography-42.0.7-cp39-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:3577d029bc3f4827dd5bf8bf7710cac13527b470bbf1820a3f394adb38ed7d5f"},
|
||||
{file = "cryptography-42.0.7-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:2e47577f9b18723fa294b0ea9a17d5e53a227867a0a4904a1a076d1646d45ca1"},
|
||||
{file = "cryptography-42.0.7-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:1a58839984d9cb34c855197043eaae2c187d930ca6d644612843b4fe8513c886"},
|
||||
{file = "cryptography-42.0.7-cp39-abi3-win32.whl", hash = "sha256:e6b79d0adb01aae87e8a44c2b64bc3f3fe59515280e00fb6d57a7267a2583cda"},
|
||||
{file = "cryptography-42.0.7-cp39-abi3-win_amd64.whl", hash = "sha256:16268d46086bb8ad5bf0a2b5544d8a9ed87a0e33f5e77dd3c3301e63d941a83b"},
|
||||
{file = "cryptography-42.0.7-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:2954fccea107026512b15afb4aa664a5640cd0af630e2ee3962f2602693f0c82"},
|
||||
{file = "cryptography-42.0.7-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:362e7197754c231797ec45ee081f3088a27a47c6c01eff2ac83f60f85a50fe60"},
|
||||
{file = "cryptography-42.0.7-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:4f698edacf9c9e0371112792558d2f705b5645076cc0aaae02f816a0171770fd"},
|
||||
{file = "cryptography-42.0.7-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:5482e789294854c28237bba77c4c83be698be740e31a3ae5e879ee5444166582"},
|
||||
{file = "cryptography-42.0.7-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:e9b2a6309f14c0497f348d08a065d52f3020656f675819fc405fb63bbcd26562"},
|
||||
{file = "cryptography-42.0.7-pp39-pypy39_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:d8e3098721b84392ee45af2dd554c947c32cc52f862b6a3ae982dbb90f577f14"},
|
||||
{file = "cryptography-42.0.7-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:c65f96dad14f8528a447414125e1fc8feb2ad5a272b8f68477abbcc1ea7d94b9"},
|
||||
{file = "cryptography-42.0.7-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:36017400817987670037fbb0324d71489b6ead6231c9604f8fc1f7d008087c68"},
|
||||
{file = "cryptography-42.0.7.tar.gz", hash = "sha256:ecbfbc00bf55888edda9868a4cf927205de8499e7fabe6c050322298382953f2"},
|
||||
{file = "cryptography-42.0.8-cp37-abi3-macosx_10_12_universal2.whl", hash = "sha256:81d8a521705787afe7a18d5bfb47ea9d9cc068206270aad0b96a725022e18d2e"},
|
||||
{file = "cryptography-42.0.8-cp37-abi3-macosx_10_12_x86_64.whl", hash = "sha256:961e61cefdcb06e0c6d7e3a1b22ebe8b996eb2bf50614e89384be54c48c6b63d"},
|
||||
{file = "cryptography-42.0.8-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e3ec3672626e1b9e55afd0df6d774ff0e953452886e06e0f1eb7eb0c832e8902"},
|
||||
{file = "cryptography-42.0.8-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e599b53fd95357d92304510fb7bda8523ed1f79ca98dce2f43c115950aa78801"},
|
||||
{file = "cryptography-42.0.8-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:5226d5d21ab681f432a9c1cf8b658c0cb02533eece706b155e5fbd8a0cdd3949"},
|
||||
{file = "cryptography-42.0.8-cp37-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:6b7c4f03ce01afd3b76cf69a5455caa9cfa3de8c8f493e0d3ab7d20611c8dae9"},
|
||||
{file = "cryptography-42.0.8-cp37-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:2346b911eb349ab547076f47f2e035fc8ff2c02380a7cbbf8d87114fa0f1c583"},
|
||||
{file = "cryptography-42.0.8-cp37-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:ad803773e9df0b92e0a817d22fd8a3675493f690b96130a5e24f1b8fabbea9c7"},
|
||||
{file = "cryptography-42.0.8-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:2f66d9cd9147ee495a8374a45ca445819f8929a3efcd2e3df6428e46c3cbb10b"},
|
||||
{file = "cryptography-42.0.8-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:d45b940883a03e19e944456a558b67a41160e367a719833c53de6911cabba2b7"},
|
||||
{file = "cryptography-42.0.8-cp37-abi3-win32.whl", hash = "sha256:a0c5b2b0585b6af82d7e385f55a8bc568abff8923af147ee3c07bd8b42cda8b2"},
|
||||
{file = "cryptography-42.0.8-cp37-abi3-win_amd64.whl", hash = "sha256:57080dee41209e556a9a4ce60d229244f7a66ef52750f813bfbe18959770cfba"},
|
||||
{file = "cryptography-42.0.8-cp39-abi3-macosx_10_12_universal2.whl", hash = "sha256:dea567d1b0e8bc5764b9443858b673b734100c2871dc93163f58c46a97a83d28"},
|
||||
{file = "cryptography-42.0.8-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c4783183f7cb757b73b2ae9aed6599b96338eb957233c58ca8f49a49cc32fd5e"},
|
||||
{file = "cryptography-42.0.8-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a0608251135d0e03111152e41f0cc2392d1e74e35703960d4190b2e0f4ca9c70"},
|
||||
{file = "cryptography-42.0.8-cp39-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:dc0fdf6787f37b1c6b08e6dfc892d9d068b5bdb671198c72072828b80bd5fe4c"},
|
||||
{file = "cryptography-42.0.8-cp39-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:9c0c1716c8447ee7dbf08d6db2e5c41c688544c61074b54fc4564196f55c25a7"},
|
||||
{file = "cryptography-42.0.8-cp39-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:fff12c88a672ab9c9c1cf7b0c80e3ad9e2ebd9d828d955c126be4fd3e5578c9e"},
|
||||
{file = "cryptography-42.0.8-cp39-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:cafb92b2bc622cd1aa6a1dce4b93307792633f4c5fe1f46c6b97cf67073ec961"},
|
||||
{file = "cryptography-42.0.8-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:31f721658a29331f895a5a54e7e82075554ccfb8b163a18719d342f5ffe5ecb1"},
|
||||
{file = "cryptography-42.0.8-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:b297f90c5723d04bcc8265fc2a0f86d4ea2e0f7ab4b6994459548d3a6b992a14"},
|
||||
{file = "cryptography-42.0.8-cp39-abi3-win32.whl", hash = "sha256:2f88d197e66c65be5e42cd72e5c18afbfae3f741742070e3019ac8f4ac57262c"},
|
||||
{file = "cryptography-42.0.8-cp39-abi3-win_amd64.whl", hash = "sha256:fa76fbb7596cc5839320000cdd5d0955313696d9511debab7ee7278fc8b5c84a"},
|
||||
{file = "cryptography-42.0.8-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:ba4f0a211697362e89ad822e667d8d340b4d8d55fae72cdd619389fb5912eefe"},
|
||||
{file = "cryptography-42.0.8-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:81884c4d096c272f00aeb1f11cf62ccd39763581645b0812e99a91505fa48e0c"},
|
||||
{file = "cryptography-42.0.8-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:c9bb2ae11bfbab395bdd072985abde58ea9860ed84e59dbc0463a5d0159f5b71"},
|
||||
{file = "cryptography-42.0.8-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:7016f837e15b0a1c119d27ecd89b3515f01f90a8615ed5e9427e30d9cdbfed3d"},
|
||||
{file = "cryptography-42.0.8-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:5a94eccb2a81a309806027e1670a358b99b8fe8bfe9f8d329f27d72c094dde8c"},
|
||||
{file = "cryptography-42.0.8-pp39-pypy39_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:dec9b018df185f08483f294cae6ccac29e7a6e0678996587363dc352dc65c842"},
|
||||
{file = "cryptography-42.0.8-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:343728aac38decfdeecf55ecab3264b015be68fc2816ca800db649607aeee648"},
|
||||
{file = "cryptography-42.0.8-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:013629ae70b40af70c9a7a5db40abe5d9054e6f4380e50ce769947b73bf3caad"},
|
||||
{file = "cryptography-42.0.8.tar.gz", hash = "sha256:8d09d05439ce7baa8e9e95b07ec5b6c886f548deb7e0f69ef25f64b3bce842f2"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
@ -1196,13 +1196,13 @@ bcrypt = ["bcrypt"]
|
||||
|
||||
[[package]]
|
||||
name = "django-cte"
|
||||
version = "1.3.2"
|
||||
version = "1.3.3"
|
||||
description = "Common Table Expressions (CTE) for Django"
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
files = [
|
||||
{file = "django-cte-1.3.2.tar.gz", hash = "sha256:841b264f83417d421393c8c4644f76300962c6c3ddbc37339cf99672eb3696a2"},
|
||||
{file = "django_cte-1.3.2-py2.py3-none-any.whl", hash = "sha256:9ca0a900df4819bbe86447a594f27272d67069f3ef13da61e905b0ace67704e9"},
|
||||
{file = "django-cte-1.3.3.tar.gz", hash = "sha256:0c1aeef067278a22886151c1d27f6f665a303952d058900e5ca82a24cde40697"},
|
||||
{file = "django_cte-1.3.3-py2.py3-none-any.whl", hash = "sha256:85bbc3efb30c2f8c9ae3080ca6f0b9570e43d2cb4b6be10846c8ef9f046873fa"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -1707,13 +1707,13 @@ grpcio-gcp = ["grpcio-gcp (>=0.2.2,<1.0.dev0)"]
|
||||
|
||||
[[package]]
|
||||
name = "google-api-python-client"
|
||||
version = "2.131.0"
|
||||
version = "2.133.0"
|
||||
description = "Google API Client Library for Python"
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
files = [
|
||||
{file = "google-api-python-client-2.131.0.tar.gz", hash = "sha256:1c03e24af62238a8817ecc24e9d4c32ddd4cb1f323b08413652d9a9a592fc00d"},
|
||||
{file = "google_api_python_client-2.131.0-py2.py3-none-any.whl", hash = "sha256:e325409bdcef4604d505d9246ce7199960a010a0569ac503b9f319db8dbdc217"},
|
||||
{file = "google-api-python-client-2.133.0.tar.gz", hash = "sha256:293092905b66a046d3187a99ac454e12b00cc2c70444f26eb2f1f9c1a82720b4"},
|
||||
{file = "google_api_python_client-2.133.0-py2.py3-none-any.whl", hash = "sha256:396fe676ea0dfed066654dcf9f8dea77a1342f9d9bb23bb88e45b7b81e773926"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
@ -2172,13 +2172,13 @@ zookeeper = ["kazoo (>=2.8.0)"]
|
||||
|
||||
[[package]]
|
||||
name = "kubernetes"
|
||||
version = "29.0.0"
|
||||
version = "30.1.0"
|
||||
description = "Kubernetes python client"
|
||||
optional = false
|
||||
python-versions = ">=3.6"
|
||||
files = [
|
||||
{file = "kubernetes-29.0.0-py2.py3-none-any.whl", hash = "sha256:ab8cb0e0576ccdfb71886366efb102c6a20f268d817be065ce7f9909c631e43e"},
|
||||
{file = "kubernetes-29.0.0.tar.gz", hash = "sha256:c4812e227ae74d07d53c88293e564e54b850452715a59a927e7e1bc6b9a60459"},
|
||||
{file = "kubernetes-30.1.0-py2.py3-none-any.whl", hash = "sha256:e212e8b7579031dd2e512168b617373bc1e03888d41ac4e04039240a292d478d"},
|
||||
{file = "kubernetes-30.1.0.tar.gz", hash = "sha256:41e4c77af9f28e7a6c314e3bd06a8c6229ddd787cad684e0ab9f69b498e98ebc"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
@ -3019,13 +3019,13 @@ attrs = ">=19.2.0"
|
||||
|
||||
[[package]]
|
||||
name = "packaging"
|
||||
version = "24.0"
|
||||
version = "24.1"
|
||||
description = "Core utilities for Python packages"
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
python-versions = ">=3.8"
|
||||
files = [
|
||||
{file = "packaging-24.0-py3-none-any.whl", hash = "sha256:2ddfb553fdf02fb784c234c7ba6ccc288296ceabec964ad2eae3777778130bc5"},
|
||||
{file = "packaging-24.0.tar.gz", hash = "sha256:eb82c5e3e56209074766e6885bb04b8c38a0c015d0a30036ebe7ece34c9989e9"},
|
||||
{file = "packaging-24.1-py3-none-any.whl", hash = "sha256:5b8f2217dbdbd2f7f384c41c628544e6d52f2d0f53c6d0c3ea61aa5d1d7ff124"},
|
||||
{file = "packaging-24.1.tar.gz", hash = "sha256:026ed72c8ed3fcce5bf8950572258698927fd1dbda10a5e981cdf0ac37f4f002"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -3376,19 +3376,19 @@ files = [
|
||||
|
||||
[[package]]
|
||||
name = "pydantic"
|
||||
version = "2.7.2"
|
||||
version = "2.7.3"
|
||||
description = "Data validation using Python type hints"
|
||||
optional = false
|
||||
python-versions = ">=3.8"
|
||||
files = [
|
||||
{file = "pydantic-2.7.2-py3-none-any.whl", hash = "sha256:834ab954175f94e6e68258537dc49402c4a5e9d0409b9f1b86b7e934a8372de7"},
|
||||
{file = "pydantic-2.7.2.tar.gz", hash = "sha256:71b2945998f9c9b7919a45bde9a50397b289937d215ae141c1d0903ba7149fd7"},
|
||||
{file = "pydantic-2.7.3-py3-none-any.whl", hash = "sha256:ea91b002777bf643bb20dd717c028ec43216b24a6001a280f83877fd2655d0b4"},
|
||||
{file = "pydantic-2.7.3.tar.gz", hash = "sha256:c46c76a40bb1296728d7a8b99aa73dd70a48c3510111ff290034f860c99c419e"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
annotated-types = ">=0.4.0"
|
||||
email-validator = {version = ">=2.0.0", optional = true, markers = "extra == \"email\""}
|
||||
pydantic-core = "2.18.3"
|
||||
pydantic-core = "2.18.4"
|
||||
typing-extensions = ">=4.6.1"
|
||||
|
||||
[package.extras]
|
||||
@ -3396,90 +3396,90 @@ email = ["email-validator (>=2.0.0)"]
|
||||
|
||||
[[package]]
|
||||
name = "pydantic-core"
|
||||
version = "2.18.3"
|
||||
version = "2.18.4"
|
||||
description = "Core functionality for Pydantic validation and serialization"
|
||||
optional = false
|
||||
python-versions = ">=3.8"
|
||||
files = [
|
||||
{file = "pydantic_core-2.18.3-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:744697428fcdec6be5670460b578161d1ffe34743a5c15656be7ea82b008197c"},
|
||||
{file = "pydantic_core-2.18.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:37b40c05ced1ba4218b14986fe6f283d22e1ae2ff4c8e28881a70fb81fbfcda7"},
|
||||
{file = "pydantic_core-2.18.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:544a9a75622357076efb6b311983ff190fbfb3c12fc3a853122b34d3d358126c"},
|
||||
{file = "pydantic_core-2.18.3-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:e2e253af04ceaebde8eb201eb3f3e3e7e390f2d275a88300d6a1959d710539e2"},
|
||||
{file = "pydantic_core-2.18.3-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:855ec66589c68aa367d989da5c4755bb74ee92ccad4fdb6af942c3612c067e34"},
|
||||
{file = "pydantic_core-2.18.3-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3d3e42bb54e7e9d72c13ce112e02eb1b3b55681ee948d748842171201a03a98a"},
|
||||
{file = "pydantic_core-2.18.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c6ac9ffccc9d2e69d9fba841441d4259cb668ac180e51b30d3632cd7abca2b9b"},
|
||||
{file = "pydantic_core-2.18.3-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:c56eca1686539fa0c9bda992e7bd6a37583f20083c37590413381acfc5f192d6"},
|
||||
{file = "pydantic_core-2.18.3-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:17954d784bf8abfc0ec2a633108207ebc4fa2df1a0e4c0c3ccbaa9bb01d2c426"},
|
||||
{file = "pydantic_core-2.18.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:98ed737567d8f2ecd54f7c8d4f8572ca7c7921ede93a2e52939416170d357812"},
|
||||
{file = "pydantic_core-2.18.3-cp310-none-win32.whl", hash = "sha256:9f9e04afebd3ed8c15d67a564ed0a34b54e52136c6d40d14c5547b238390e779"},
|
||||
{file = "pydantic_core-2.18.3-cp310-none-win_amd64.whl", hash = "sha256:45e4ffbae34f7ae30d0047697e724e534a7ec0a82ef9994b7913a412c21462a0"},
|
||||
{file = "pydantic_core-2.18.3-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:b9ebe8231726c49518b16b237b9fe0d7d361dd221302af511a83d4ada01183ab"},
|
||||
{file = "pydantic_core-2.18.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:b8e20e15d18bf7dbb453be78a2d858f946f5cdf06c5072453dace00ab652e2b2"},
|
||||
{file = "pydantic_core-2.18.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c0d9ff283cd3459fa0bf9b0256a2b6f01ac1ff9ffb034e24457b9035f75587cb"},
|
||||
{file = "pydantic_core-2.18.3-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:2f7ef5f0ebb77ba24c9970da18b771711edc5feaf00c10b18461e0f5f5949231"},
|
||||
{file = "pydantic_core-2.18.3-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:73038d66614d2e5cde30435b5afdced2b473b4c77d4ca3a8624dd3e41a9c19be"},
|
||||
{file = "pydantic_core-2.18.3-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6afd5c867a74c4d314c557b5ea9520183fadfbd1df4c2d6e09fd0d990ce412cd"},
|
||||
{file = "pydantic_core-2.18.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bd7df92f28d351bb9f12470f4c533cf03d1b52ec5a6e5c58c65b183055a60106"},
|
||||
{file = "pydantic_core-2.18.3-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:80aea0ffeb1049336043d07799eace1c9602519fb3192916ff525b0287b2b1e4"},
|
||||
{file = "pydantic_core-2.18.3-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:aaee40f25bba38132e655ffa3d1998a6d576ba7cf81deff8bfa189fb43fd2bbe"},
|
||||
{file = "pydantic_core-2.18.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:9128089da8f4fe73f7a91973895ebf2502539d627891a14034e45fb9e707e26d"},
|
||||
{file = "pydantic_core-2.18.3-cp311-none-win32.whl", hash = "sha256:fec02527e1e03257aa25b1a4dcbe697b40a22f1229f5d026503e8b7ff6d2eda7"},
|
||||
{file = "pydantic_core-2.18.3-cp311-none-win_amd64.whl", hash = "sha256:58ff8631dbab6c7c982e6425da8347108449321f61fe427c52ddfadd66642af7"},
|
||||
{file = "pydantic_core-2.18.3-cp311-none-win_arm64.whl", hash = "sha256:3fc1c7f67f34c6c2ef9c213e0f2a351797cda98249d9ca56a70ce4ebcaba45f4"},
|
||||
{file = "pydantic_core-2.18.3-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:f0928cde2ae416a2d1ebe6dee324709c6f73e93494d8c7aea92df99aab1fc40f"},
|
||||
{file = "pydantic_core-2.18.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:0bee9bb305a562f8b9271855afb6ce00223f545de3d68560b3c1649c7c5295e9"},
|
||||
{file = "pydantic_core-2.18.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e862823be114387257dacbfa7d78547165a85d7add33b446ca4f4fae92c7ff5c"},
|
||||
{file = "pydantic_core-2.18.3-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:6a36f78674cbddc165abab0df961b5f96b14461d05feec5e1f78da58808b97e7"},
|
||||
{file = "pydantic_core-2.18.3-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ba905d184f62e7ddbb7a5a751d8a5c805463511c7b08d1aca4a3e8c11f2e5048"},
|
||||
{file = "pydantic_core-2.18.3-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7fdd362f6a586e681ff86550b2379e532fee63c52def1c666887956748eaa326"},
|
||||
{file = "pydantic_core-2.18.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:24b214b7ee3bd3b865e963dbed0f8bc5375f49449d70e8d407b567af3222aae4"},
|
||||
{file = "pydantic_core-2.18.3-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:691018785779766127f531674fa82bb368df5b36b461622b12e176c18e119022"},
|
||||
{file = "pydantic_core-2.18.3-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:60e4c625e6f7155d7d0dcac151edf5858102bc61bf959d04469ca6ee4e8381bd"},
|
||||
{file = "pydantic_core-2.18.3-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:a4e651e47d981c1b701dcc74ab8fec5a60a5b004650416b4abbef13db23bc7be"},
|
||||
{file = "pydantic_core-2.18.3-cp312-none-win32.whl", hash = "sha256:ffecbb5edb7f5ffae13599aec33b735e9e4c7676ca1633c60f2c606beb17efc5"},
|
||||
{file = "pydantic_core-2.18.3-cp312-none-win_amd64.whl", hash = "sha256:2c8333f6e934733483c7eddffdb094c143b9463d2af7e6bd85ebcb2d4a1b82c6"},
|
||||
{file = "pydantic_core-2.18.3-cp312-none-win_arm64.whl", hash = "sha256:7a20dded653e516a4655f4c98e97ccafb13753987434fe7cf044aa25f5b7d417"},
|
||||
{file = "pydantic_core-2.18.3-cp38-cp38-macosx_10_12_x86_64.whl", hash = "sha256:eecf63195be644b0396f972c82598cd15693550f0ff236dcf7ab92e2eb6d3522"},
|
||||
{file = "pydantic_core-2.18.3-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:2c44efdd3b6125419c28821590d7ec891c9cb0dff33a7a78d9d5c8b6f66b9702"},
|
||||
{file = "pydantic_core-2.18.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6e59fca51ffbdd1638b3856779342ed69bcecb8484c1d4b8bdb237d0eb5a45e2"},
|
||||
{file = "pydantic_core-2.18.3-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:70cf099197d6b98953468461d753563b28e73cf1eade2ffe069675d2657ed1d5"},
|
||||
{file = "pydantic_core-2.18.3-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:63081a49dddc6124754b32a3774331467bfc3d2bd5ff8f10df36a95602560361"},
|
||||
{file = "pydantic_core-2.18.3-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:370059b7883485c9edb9655355ff46d912f4b03b009d929220d9294c7fd9fd60"},
|
||||
{file = "pydantic_core-2.18.3-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5a64faeedfd8254f05f5cf6fc755023a7e1606af3959cfc1a9285744cc711044"},
|
||||
{file = "pydantic_core-2.18.3-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:19d2e725de0f90d8671f89e420d36c3dd97639b98145e42fcc0e1f6d492a46dc"},
|
||||
{file = "pydantic_core-2.18.3-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:67bc078025d70ec5aefe6200ef094576c9d86bd36982df1301c758a9fff7d7f4"},
|
||||
{file = "pydantic_core-2.18.3-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:adf952c3f4100e203cbaf8e0c907c835d3e28f9041474e52b651761dc248a3c0"},
|
||||
{file = "pydantic_core-2.18.3-cp38-none-win32.whl", hash = "sha256:9a46795b1f3beb167eaee91736d5d17ac3a994bf2215a996aed825a45f897558"},
|
||||
{file = "pydantic_core-2.18.3-cp38-none-win_amd64.whl", hash = "sha256:200ad4e3133cb99ed82342a101a5abf3d924722e71cd581cc113fe828f727fbc"},
|
||||
{file = "pydantic_core-2.18.3-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:304378b7bf92206036c8ddd83a2ba7b7d1a5b425acafff637172a3aa72ad7083"},
|
||||
{file = "pydantic_core-2.18.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:c826870b277143e701c9ccf34ebc33ddb4d072612683a044e7cce2d52f6c3fef"},
|
||||
{file = "pydantic_core-2.18.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e201935d282707394f3668380e41ccf25b5794d1b131cdd96b07f615a33ca4b1"},
|
||||
{file = "pydantic_core-2.18.3-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:5560dda746c44b48bf82b3d191d74fe8efc5686a9ef18e69bdabccbbb9ad9442"},
|
||||
{file = "pydantic_core-2.18.3-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6b32c2a1f8032570842257e4c19288eba9a2bba4712af542327de9a1204faff8"},
|
||||
{file = "pydantic_core-2.18.3-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:929c24e9dea3990bc8bcd27c5f2d3916c0c86f5511d2caa69e0d5290115344a9"},
|
||||
{file = "pydantic_core-2.18.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e1a8376fef60790152564b0eab376b3e23dd6e54f29d84aad46f7b264ecca943"},
|
||||
{file = "pydantic_core-2.18.3-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:dccf3ef1400390ddd1fb55bf0632209d39140552d068ee5ac45553b556780e06"},
|
||||
{file = "pydantic_core-2.18.3-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:41dbdcb0c7252b58fa931fec47937edb422c9cb22528f41cb8963665c372caf6"},
|
||||
{file = "pydantic_core-2.18.3-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:666e45cf071669fde468886654742fa10b0e74cd0fa0430a46ba6056b24fb0af"},
|
||||
{file = "pydantic_core-2.18.3-cp39-none-win32.whl", hash = "sha256:f9c08cabff68704a1b4667d33f534d544b8a07b8e5d039c37067fceb18789e78"},
|
||||
{file = "pydantic_core-2.18.3-cp39-none-win_amd64.whl", hash = "sha256:4afa5f5973e8572b5c0dcb4e2d4fda7890e7cd63329bd5cc3263a25c92ef0026"},
|
||||
{file = "pydantic_core-2.18.3-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:77319771a026f7c7d29c6ebc623de889e9563b7087911b46fd06c044a12aa5e9"},
|
||||
{file = "pydantic_core-2.18.3-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:df11fa992e9f576473038510d66dd305bcd51d7dd508c163a8c8fe148454e059"},
|
||||
{file = "pydantic_core-2.18.3-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d531076bdfb65af593326ffd567e6ab3da145020dafb9187a1d131064a55f97c"},
|
||||
{file = "pydantic_core-2.18.3-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d33ce258e4e6e6038f2b9e8b8a631d17d017567db43483314993b3ca345dcbbb"},
|
||||
{file = "pydantic_core-2.18.3-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:1f9cd7f5635b719939019be9bda47ecb56e165e51dd26c9a217a433e3d0d59a9"},
|
||||
{file = "pydantic_core-2.18.3-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:cd4a032bb65cc132cae1fe3e52877daecc2097965cd3914e44fbd12b00dae7c5"},
|
||||
{file = "pydantic_core-2.18.3-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:82f2718430098bcdf60402136c845e4126a189959d103900ebabb6774a5d9fdb"},
|
||||
{file = "pydantic_core-2.18.3-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:c0037a92cf0c580ed14e10953cdd26528e8796307bb8bb312dc65f71547df04d"},
|
||||
{file = "pydantic_core-2.18.3-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:b95a0972fac2b1ff3c94629fc9081b16371dad870959f1408cc33b2f78ad347a"},
|
||||
{file = "pydantic_core-2.18.3-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:a62e437d687cc148381bdd5f51e3e81f5b20a735c55f690c5be94e05da2b0d5c"},
|
||||
{file = "pydantic_core-2.18.3-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b367a73a414bbb08507da102dc2cde0fa7afe57d09b3240ce82a16d608a7679c"},
|
||||
{file = "pydantic_core-2.18.3-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0ecce4b2360aa3f008da3327d652e74a0e743908eac306198b47e1c58b03dd2b"},
|
||||
{file = "pydantic_core-2.18.3-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:bd4435b8d83f0c9561a2a9585b1de78f1abb17cb0cef5f39bf6a4b47d19bafe3"},
|
||||
{file = "pydantic_core-2.18.3-pp39-pypy39_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:616221a6d473c5b9aa83fa8982745441f6a4a62a66436be9445c65f241b86c94"},
|
||||
{file = "pydantic_core-2.18.3-pp39-pypy39_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:7e6382ce89a92bc1d0c0c5edd51e931432202b9080dc921d8d003e616402efd1"},
|
||||
{file = "pydantic_core-2.18.3-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:ff58f379345603d940e461eae474b6bbb6dab66ed9a851ecd3cb3709bf4dcf6a"},
|
||||
{file = "pydantic_core-2.18.3.tar.gz", hash = "sha256:432e999088d85c8f36b9a3f769a8e2b57aabd817bbb729a90d1fe7f18f6f1f39"},
|
||||
{file = "pydantic_core-2.18.4-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:f76d0ad001edd426b92233d45c746fd08f467d56100fd8f30e9ace4b005266e4"},
|
||||
{file = "pydantic_core-2.18.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:59ff3e89f4eaf14050c8022011862df275b552caef8082e37b542b066ce1ff26"},
|
||||
{file = "pydantic_core-2.18.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a55b5b16c839df1070bc113c1f7f94a0af4433fcfa1b41799ce7606e5c79ce0a"},
|
||||
{file = "pydantic_core-2.18.4-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:4d0dcc59664fcb8974b356fe0a18a672d6d7cf9f54746c05f43275fc48636851"},
|
||||
{file = "pydantic_core-2.18.4-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8951eee36c57cd128f779e641e21eb40bc5073eb28b2d23f33eb0ef14ffb3f5d"},
|
||||
{file = "pydantic_core-2.18.4-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4701b19f7e3a06ea655513f7938de6f108123bf7c86bbebb1196eb9bd35cf724"},
|
||||
{file = "pydantic_core-2.18.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e00a3f196329e08e43d99b79b286d60ce46bed10f2280d25a1718399457e06be"},
|
||||
{file = "pydantic_core-2.18.4-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:97736815b9cc893b2b7f663628e63f436018b75f44854c8027040e05230eeddb"},
|
||||
{file = "pydantic_core-2.18.4-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:6891a2ae0e8692679c07728819b6e2b822fb30ca7445f67bbf6509b25a96332c"},
|
||||
{file = "pydantic_core-2.18.4-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:bc4ff9805858bd54d1a20efff925ccd89c9d2e7cf4986144b30802bf78091c3e"},
|
||||
{file = "pydantic_core-2.18.4-cp310-none-win32.whl", hash = "sha256:1b4de2e51bbcb61fdebd0ab86ef28062704f62c82bbf4addc4e37fa4b00b7cbc"},
|
||||
{file = "pydantic_core-2.18.4-cp310-none-win_amd64.whl", hash = "sha256:6a750aec7bf431517a9fd78cb93c97b9b0c496090fee84a47a0d23668976b4b0"},
|
||||
{file = "pydantic_core-2.18.4-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:942ba11e7dfb66dc70f9ae66b33452f51ac7bb90676da39a7345e99ffb55402d"},
|
||||
{file = "pydantic_core-2.18.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:b2ebef0e0b4454320274f5e83a41844c63438fdc874ea40a8b5b4ecb7693f1c4"},
|
||||
{file = "pydantic_core-2.18.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a642295cd0c8df1b86fc3dced1d067874c353a188dc8e0f744626d49e9aa51c4"},
|
||||
{file = "pydantic_core-2.18.4-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:5f09baa656c904807e832cf9cce799c6460c450c4ad80803517032da0cd062e2"},
|
||||
{file = "pydantic_core-2.18.4-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:98906207f29bc2c459ff64fa007afd10a8c8ac080f7e4d5beff4c97086a3dabd"},
|
||||
{file = "pydantic_core-2.18.4-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:19894b95aacfa98e7cb093cd7881a0c76f55731efad31073db4521e2b6ff5b7d"},
|
||||
{file = "pydantic_core-2.18.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0fbbdc827fe5e42e4d196c746b890b3d72876bdbf160b0eafe9f0334525119c8"},
|
||||
{file = "pydantic_core-2.18.4-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:f85d05aa0918283cf29a30b547b4df2fbb56b45b135f9e35b6807cb28bc47951"},
|
||||
{file = "pydantic_core-2.18.4-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:e85637bc8fe81ddb73fda9e56bab24560bdddfa98aa64f87aaa4e4b6730c23d2"},
|
||||
{file = "pydantic_core-2.18.4-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:2f5966897e5461f818e136b8451d0551a2e77259eb0f73a837027b47dc95dab9"},
|
||||
{file = "pydantic_core-2.18.4-cp311-none-win32.whl", hash = "sha256:44c7486a4228413c317952e9d89598bcdfb06399735e49e0f8df643e1ccd0558"},
|
||||
{file = "pydantic_core-2.18.4-cp311-none-win_amd64.whl", hash = "sha256:8a7164fe2005d03c64fd3b85649891cd4953a8de53107940bf272500ba8a788b"},
|
||||
{file = "pydantic_core-2.18.4-cp311-none-win_arm64.whl", hash = "sha256:4e99bc050fe65c450344421017f98298a97cefc18c53bb2f7b3531eb39bc7805"},
|
||||
{file = "pydantic_core-2.18.4-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:6f5c4d41b2771c730ea1c34e458e781b18cc668d194958e0112455fff4e402b2"},
|
||||
{file = "pydantic_core-2.18.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:2fdf2156aa3d017fddf8aea5adfba9f777db1d6022d392b682d2a8329e087cef"},
|
||||
{file = "pydantic_core-2.18.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4748321b5078216070b151d5271ef3e7cc905ab170bbfd27d5c83ee3ec436695"},
|
||||
{file = "pydantic_core-2.18.4-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:847a35c4d58721c5dc3dba599878ebbdfd96784f3fb8bb2c356e123bdcd73f34"},
|
||||
{file = "pydantic_core-2.18.4-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3c40d4eaad41f78e3bbda31b89edc46a3f3dc6e171bf0ecf097ff7a0ffff7cb1"},
|
||||
{file = "pydantic_core-2.18.4-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:21a5e440dbe315ab9825fcd459b8814bb92b27c974cbc23c3e8baa2b76890077"},
|
||||
{file = "pydantic_core-2.18.4-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:01dd777215e2aa86dfd664daed5957704b769e726626393438f9c87690ce78c3"},
|
||||
{file = "pydantic_core-2.18.4-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:4b06beb3b3f1479d32befd1f3079cc47b34fa2da62457cdf6c963393340b56e9"},
|
||||
{file = "pydantic_core-2.18.4-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:564d7922e4b13a16b98772441879fcdcbe82ff50daa622d681dd682175ea918c"},
|
||||
{file = "pydantic_core-2.18.4-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:0eb2a4f660fcd8e2b1c90ad566db2b98d7f3f4717c64fe0a83e0adb39766d5b8"},
|
||||
{file = "pydantic_core-2.18.4-cp312-none-win32.whl", hash = "sha256:8b8bab4c97248095ae0c4455b5a1cd1cdd96e4e4769306ab19dda135ea4cdb07"},
|
||||
{file = "pydantic_core-2.18.4-cp312-none-win_amd64.whl", hash = "sha256:14601cdb733d741b8958224030e2bfe21a4a881fb3dd6fbb21f071cabd48fa0a"},
|
||||
{file = "pydantic_core-2.18.4-cp312-none-win_arm64.whl", hash = "sha256:c1322d7dd74713dcc157a2b7898a564ab091ca6c58302d5c7b4c07296e3fd00f"},
|
||||
{file = "pydantic_core-2.18.4-cp38-cp38-macosx_10_12_x86_64.whl", hash = "sha256:823be1deb01793da05ecb0484d6c9e20baebb39bd42b5d72636ae9cf8350dbd2"},
|
||||
{file = "pydantic_core-2.18.4-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:ebef0dd9bf9b812bf75bda96743f2a6c5734a02092ae7f721c048d156d5fabae"},
|
||||
{file = "pydantic_core-2.18.4-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ae1d6df168efb88d7d522664693607b80b4080be6750c913eefb77e34c12c71a"},
|
||||
{file = "pydantic_core-2.18.4-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:f9899c94762343f2cc2fc64c13e7cae4c3cc65cdfc87dd810a31654c9b7358cc"},
|
||||
{file = "pydantic_core-2.18.4-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:99457f184ad90235cfe8461c4d70ab7dd2680e28821c29eca00252ba90308c78"},
|
||||
{file = "pydantic_core-2.18.4-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:18f469a3d2a2fdafe99296a87e8a4c37748b5080a26b806a707f25a902c040a8"},
|
||||
{file = "pydantic_core-2.18.4-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b7cdf28938ac6b8b49ae5e92f2735056a7ba99c9b110a474473fd71185c1af5d"},
|
||||
{file = "pydantic_core-2.18.4-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:938cb21650855054dc54dfd9120a851c974f95450f00683399006aa6e8abb057"},
|
||||
{file = "pydantic_core-2.18.4-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:44cd83ab6a51da80fb5adbd9560e26018e2ac7826f9626bc06ca3dc074cd198b"},
|
||||
{file = "pydantic_core-2.18.4-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:972658f4a72d02b8abfa2581d92d59f59897d2e9f7e708fdabe922f9087773af"},
|
||||
{file = "pydantic_core-2.18.4-cp38-none-win32.whl", hash = "sha256:1d886dc848e60cb7666f771e406acae54ab279b9f1e4143babc9c2258213daa2"},
|
||||
{file = "pydantic_core-2.18.4-cp38-none-win_amd64.whl", hash = "sha256:bb4462bd43c2460774914b8525f79b00f8f407c945d50881568f294c1d9b4443"},
|
||||
{file = "pydantic_core-2.18.4-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:44a688331d4a4e2129140a8118479443bd6f1905231138971372fcde37e43528"},
|
||||
{file = "pydantic_core-2.18.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:a2fdd81edd64342c85ac7cf2753ccae0b79bf2dfa063785503cb85a7d3593223"},
|
||||
{file = "pydantic_core-2.18.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:86110d7e1907ab36691f80b33eb2da87d780f4739ae773e5fc83fb272f88825f"},
|
||||
{file = "pydantic_core-2.18.4-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:46387e38bd641b3ee5ce247563b60c5ca098da9c56c75c157a05eaa0933ed154"},
|
||||
{file = "pydantic_core-2.18.4-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:123c3cec203e3f5ac7b000bd82235f1a3eced8665b63d18be751f115588fea30"},
|
||||
{file = "pydantic_core-2.18.4-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:dc1803ac5c32ec324c5261c7209e8f8ce88e83254c4e1aebdc8b0a39f9ddb443"},
|
||||
{file = "pydantic_core-2.18.4-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:53db086f9f6ab2b4061958d9c276d1dbe3690e8dd727d6abf2321d6cce37fa94"},
|
||||
{file = "pydantic_core-2.18.4-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:abc267fa9837245cc28ea6929f19fa335f3dc330a35d2e45509b6566dc18be23"},
|
||||
{file = "pydantic_core-2.18.4-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:a0d829524aaefdebccb869eed855e2d04c21d2d7479b6cada7ace5448416597b"},
|
||||
{file = "pydantic_core-2.18.4-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:509daade3b8649f80d4e5ff21aa5673e4ebe58590b25fe42fac5f0f52c6f034a"},
|
||||
{file = "pydantic_core-2.18.4-cp39-none-win32.whl", hash = "sha256:ca26a1e73c48cfc54c4a76ff78df3727b9d9f4ccc8dbee4ae3f73306a591676d"},
|
||||
{file = "pydantic_core-2.18.4-cp39-none-win_amd64.whl", hash = "sha256:c67598100338d5d985db1b3d21f3619ef392e185e71b8d52bceacc4a7771ea7e"},
|
||||
{file = "pydantic_core-2.18.4-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:574d92eac874f7f4db0ca653514d823a0d22e2354359d0759e3f6a406db5d55d"},
|
||||
{file = "pydantic_core-2.18.4-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:1f4d26ceb5eb9eed4af91bebeae4b06c3fb28966ca3a8fb765208cf6b51102ab"},
|
||||
{file = "pydantic_core-2.18.4-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:77450e6d20016ec41f43ca4a6c63e9fdde03f0ae3fe90e7c27bdbeaece8b1ed4"},
|
||||
{file = "pydantic_core-2.18.4-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d323a01da91851a4f17bf592faf46149c9169d68430b3146dcba2bb5e5719abc"},
|
||||
{file = "pydantic_core-2.18.4-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:43d447dd2ae072a0065389092a231283f62d960030ecd27565672bd40746c507"},
|
||||
{file = "pydantic_core-2.18.4-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:578e24f761f3b425834f297b9935e1ce2e30f51400964ce4801002435a1b41ef"},
|
||||
{file = "pydantic_core-2.18.4-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:81b5efb2f126454586d0f40c4d834010979cb80785173d1586df845a632e4e6d"},
|
||||
{file = "pydantic_core-2.18.4-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:ab86ce7c8f9bea87b9d12c7f0af71102acbf5ecbc66c17796cff45dae54ef9a5"},
|
||||
{file = "pydantic_core-2.18.4-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:90afc12421df2b1b4dcc975f814e21bc1754640d502a2fbcc6d41e77af5ec312"},
|
||||
{file = "pydantic_core-2.18.4-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:51991a89639a912c17bef4b45c87bd83593aee0437d8102556af4885811d59f5"},
|
||||
{file = "pydantic_core-2.18.4-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:293afe532740370aba8c060882f7d26cfd00c94cae32fd2e212a3a6e3b7bc15e"},
|
||||
{file = "pydantic_core-2.18.4-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b48ece5bde2e768197a2d0f6e925f9d7e3e826f0ad2271120f8144a9db18d5c8"},
|
||||
{file = "pydantic_core-2.18.4-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:eae237477a873ab46e8dd748e515c72c0c804fb380fbe6c85533c7de51f23a8f"},
|
||||
{file = "pydantic_core-2.18.4-pp39-pypy39_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:834b5230b5dfc0c1ec37b2fda433b271cbbc0e507560b5d1588e2cc1148cf1ce"},
|
||||
{file = "pydantic_core-2.18.4-pp39-pypy39_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:e858ac0a25074ba4bce653f9b5d0a85b7456eaddadc0ce82d3878c22489fa4ee"},
|
||||
{file = "pydantic_core-2.18.4-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:2fd41f6eff4c20778d717af1cc50eca52f5afe7805ee530a4fbd0bae284f16e9"},
|
||||
{file = "pydantic_core-2.18.4.tar.gz", hash = "sha256:ec3beeada09ff865c344ff3bc2f427f5e6c26401cc6113d77e372c3fdac73864"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
@ -3624,13 +3624,13 @@ files = [
|
||||
|
||||
[[package]]
|
||||
name = "pytest"
|
||||
version = "8.2.1"
|
||||
version = "8.2.2"
|
||||
description = "pytest: simple powerful testing with Python"
|
||||
optional = false
|
||||
python-versions = ">=3.8"
|
||||
files = [
|
||||
{file = "pytest-8.2.1-py3-none-any.whl", hash = "sha256:faccc5d332b8c3719f40283d0d44aa5cf101cec36f88cde9ed8f2bc0538612b1"},
|
||||
{file = "pytest-8.2.1.tar.gz", hash = "sha256:5046e5b46d8e4cac199c373041f26be56fdb81eb4e67dc11d4e10811fc3408fd"},
|
||||
{file = "pytest-8.2.2-py3-none-any.whl", hash = "sha256:c434598117762e2bd304e526244f67bf66bbd7b5d6cf22138be51ff661980343"},
|
||||
{file = "pytest-8.2.2.tar.gz", hash = "sha256:de4bb8104e201939ccdc688b27a89a7be2079b22e2bd2b07f806b6ba71117977"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
@ -4052,28 +4052,28 @@ pyasn1 = ">=0.1.3"
|
||||
|
||||
[[package]]
|
||||
name = "ruff"
|
||||
version = "0.4.7"
|
||||
version = "0.4.8"
|
||||
description = "An extremely fast Python linter and code formatter, written in Rust."
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
files = [
|
||||
{file = "ruff-0.4.7-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:e089371c67892a73b6bb1525608e89a2aca1b77b5440acf7a71dda5dac958f9e"},
|
||||
{file = "ruff-0.4.7-py3-none-macosx_11_0_arm64.whl", hash = "sha256:10f973d521d910e5f9c72ab27e409e839089f955be8a4c8826601a6323a89753"},
|
||||
{file = "ruff-0.4.7-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:59c3d110970001dfa494bcd95478e62286c751126dfb15c3c46e7915fc49694f"},
|
||||
{file = "ruff-0.4.7-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:fa9773c6c00f4958f73b317bc0fd125295110c3776089f6ef318f4b775f0abe4"},
|
||||
{file = "ruff-0.4.7-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:07fc80bbb61e42b3b23b10fda6a2a0f5a067f810180a3760c5ef1b456c21b9db"},
|
||||
{file = "ruff-0.4.7-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:fa4dafe3fe66d90e2e2b63fa1591dd6e3f090ca2128daa0be33db894e6c18648"},
|
||||
{file = "ruff-0.4.7-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a7c0083febdec17571455903b184a10026603a1de078428ba155e7ce9358c5f6"},
|
||||
{file = "ruff-0.4.7-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ad1b20e66a44057c326168437d680a2166c177c939346b19c0d6b08a62a37589"},
|
||||
{file = "ruff-0.4.7-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cbf5d818553add7511c38b05532d94a407f499d1a76ebb0cad0374e32bc67202"},
|
||||
{file = "ruff-0.4.7-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:50e9651578b629baec3d1513b2534de0ac7ed7753e1382272b8d609997e27e83"},
|
||||
{file = "ruff-0.4.7-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:8874a9df7766cb956b218a0a239e0a5d23d9e843e4da1e113ae1d27ee420877a"},
|
||||
{file = "ruff-0.4.7-py3-none-musllinux_1_2_i686.whl", hash = "sha256:b9de9a6e49f7d529decd09381c0860c3f82fa0b0ea00ea78409b785d2308a567"},
|
||||
{file = "ruff-0.4.7-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:13a1768b0691619822ae6d446132dbdfd568b700ecd3652b20d4e8bc1e498f78"},
|
||||
{file = "ruff-0.4.7-py3-none-win32.whl", hash = "sha256:769e5a51df61e07e887b81e6f039e7ed3573316ab7dd9f635c5afaa310e4030e"},
|
||||
{file = "ruff-0.4.7-py3-none-win_amd64.whl", hash = "sha256:9e3ab684ad403a9ed1226894c32c3ab9c2e0718440f6f50c7c5829932bc9e054"},
|
||||
{file = "ruff-0.4.7-py3-none-win_arm64.whl", hash = "sha256:10f2204b9a613988e3484194c2c9e96a22079206b22b787605c255f130db5ed7"},
|
||||
{file = "ruff-0.4.7.tar.gz", hash = "sha256:2331d2b051dc77a289a653fcc6a42cce357087c5975738157cd966590b18b5e1"},
|
||||
{file = "ruff-0.4.8-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:7663a6d78f6adb0eab270fa9cf1ff2d28618ca3a652b60f2a234d92b9ec89066"},
|
||||
{file = "ruff-0.4.8-py3-none-macosx_11_0_arm64.whl", hash = "sha256:eeceb78da8afb6de0ddada93112869852d04f1cd0f6b80fe464fd4e35c330913"},
|
||||
{file = "ruff-0.4.8-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:aad360893e92486662ef3be0a339c5ca3c1b109e0134fcd37d534d4be9fb8de3"},
|
||||
{file = "ruff-0.4.8-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:284c2e3f3396fb05f5f803c9fffb53ebbe09a3ebe7dda2929ed8d73ded736deb"},
|
||||
{file = "ruff-0.4.8-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a7354f921e3fbe04d2a62d46707e569f9315e1a613307f7311a935743c51a764"},
|
||||
{file = "ruff-0.4.8-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:72584676164e15a68a15778fd1b17c28a519e7a0622161eb2debdcdabdc71883"},
|
||||
{file = "ruff-0.4.8-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9678d5c9b43315f323af2233a04d747409d1e3aa6789620083a82d1066a35199"},
|
||||
{file = "ruff-0.4.8-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:704977a658131651a22b5ebeb28b717ef42ac6ee3b11e91dc87b633b5d83142b"},
|
||||
{file = "ruff-0.4.8-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d05f8d6f0c3cce5026cecd83b7a143dcad503045857bc49662f736437380ad45"},
|
||||
{file = "ruff-0.4.8-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:6ea874950daca5697309d976c9afba830d3bf0ed66887481d6bca1673fc5b66a"},
|
||||
{file = "ruff-0.4.8-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:fc95aac2943ddf360376be9aa3107c8cf9640083940a8c5bd824be692d2216dc"},
|
||||
{file = "ruff-0.4.8-py3-none-musllinux_1_2_i686.whl", hash = "sha256:384154a1c3f4bf537bac69f33720957ee49ac8d484bfc91720cc94172026ceed"},
|
||||
{file = "ruff-0.4.8-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:e9d5ce97cacc99878aa0d084c626a15cd21e6b3d53fd6f9112b7fc485918e1fa"},
|
||||
{file = "ruff-0.4.8-py3-none-win32.whl", hash = "sha256:6d795d7639212c2dfd01991259460101c22aabf420d9b943f153ab9d9706e6a9"},
|
||||
{file = "ruff-0.4.8-py3-none-win_amd64.whl", hash = "sha256:e14a3a095d07560a9d6769a72f781d73259655919d9b396c650fc98a8157555d"},
|
||||
{file = "ruff-0.4.8-py3-none-win_arm64.whl", hash = "sha256:14019a06dbe29b608f6b7cbcec300e3170a8d86efaddb7b23405cb7f7dcaf780"},
|
||||
{file = "ruff-0.4.8.tar.gz", hash = "sha256:16d717b1d57b2e2fd68bd0bf80fb43931b79d05a7131aa477d66fc40fbd86268"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -4130,13 +4130,13 @@ urllib3 = {version = ">=1.26,<3", extras = ["socks"]}
|
||||
|
||||
[[package]]
|
||||
name = "sentry-sdk"
|
||||
version = "2.3.1"
|
||||
version = "2.5.1"
|
||||
description = "Python client for Sentry (https://sentry.io)"
|
||||
optional = false
|
||||
python-versions = ">=3.6"
|
||||
files = [
|
||||
{file = "sentry_sdk-2.3.1-py2.py3-none-any.whl", hash = "sha256:c5aeb095ba226391d337dd42a6f9470d86c9fc236ecc71cfc7cd1942b45010c6"},
|
||||
{file = "sentry_sdk-2.3.1.tar.gz", hash = "sha256:139a71a19f5e9eb5d3623942491ce03cf8ebc14ea2e39ba3e6fe79560d8a5b1f"},
|
||||
{file = "sentry_sdk-2.5.1-py2.py3-none-any.whl", hash = "sha256:1f87acdce4a43a523ae5aa21a3fc37522d73ebd9ec04b1dbf01aa3d173852def"},
|
||||
{file = "sentry_sdk-2.5.1.tar.gz", hash = "sha256:fbc40a78a8a9c6675133031116144f0d0940376fa6e4e1acd5624c90b0aaf58b"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
@ -4451,22 +4451,22 @@ celery = "*"
|
||||
|
||||
[[package]]
|
||||
name = "tornado"
|
||||
version = "6.4"
|
||||
version = "6.4.1"
|
||||
description = "Tornado is a Python web framework and asynchronous networking library, originally developed at FriendFeed."
|
||||
optional = false
|
||||
python-versions = ">= 3.8"
|
||||
python-versions = ">=3.8"
|
||||
files = [
|
||||
{file = "tornado-6.4-cp38-abi3-macosx_10_9_universal2.whl", hash = "sha256:02ccefc7d8211e5a7f9e8bc3f9e5b0ad6262ba2fbb683a6443ecc804e5224ce0"},
|
||||
{file = "tornado-6.4-cp38-abi3-macosx_10_9_x86_64.whl", hash = "sha256:27787de946a9cffd63ce5814c33f734c627a87072ec7eed71f7fc4417bb16263"},
|
||||
{file = "tornado-6.4-cp38-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f7894c581ecdcf91666a0912f18ce5e757213999e183ebfc2c3fdbf4d5bd764e"},
|
||||
{file = "tornado-6.4-cp38-abi3-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e43bc2e5370a6a8e413e1e1cd0c91bedc5bd62a74a532371042a18ef19e10579"},
|
||||
{file = "tornado-6.4-cp38-abi3-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f0251554cdd50b4b44362f73ad5ba7126fc5b2c2895cc62b14a1c2d7ea32f212"},
|
||||
{file = "tornado-6.4-cp38-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:fd03192e287fbd0899dd8f81c6fb9cbbc69194d2074b38f384cb6fa72b80e9c2"},
|
||||
{file = "tornado-6.4-cp38-abi3-musllinux_1_1_i686.whl", hash = "sha256:88b84956273fbd73420e6d4b8d5ccbe913c65d31351b4c004ae362eba06e1f78"},
|
||||
{file = "tornado-6.4-cp38-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:71ddfc23a0e03ef2df1c1397d859868d158c8276a0603b96cf86892bff58149f"},
|
||||
{file = "tornado-6.4-cp38-abi3-win32.whl", hash = "sha256:6f8a6c77900f5ae93d8b4ae1196472d0ccc2775cc1dfdc9e7727889145c45052"},
|
||||
{file = "tornado-6.4-cp38-abi3-win_amd64.whl", hash = "sha256:10aeaa8006333433da48dec9fe417877f8bcc21f48dda8d661ae79da357b2a63"},
|
||||
{file = "tornado-6.4.tar.gz", hash = "sha256:72291fa6e6bc84e626589f1c29d90a5a6d593ef5ae68052ee2ef000dfd273dee"},
|
||||
{file = "tornado-6.4.1-cp38-abi3-macosx_10_9_universal2.whl", hash = "sha256:163b0aafc8e23d8cdc3c9dfb24c5368af84a81e3364745ccb4427669bf84aec8"},
|
||||
{file = "tornado-6.4.1-cp38-abi3-macosx_10_9_x86_64.whl", hash = "sha256:6d5ce3437e18a2b66fbadb183c1d3364fb03f2be71299e7d10dbeeb69f4b2a14"},
|
||||
{file = "tornado-6.4.1-cp38-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e2e20b9113cd7293f164dc46fffb13535266e713cdb87bd2d15ddb336e96cfc4"},
|
||||
{file = "tornado-6.4.1-cp38-abi3-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8ae50a504a740365267b2a8d1a90c9fbc86b780a39170feca9bcc1787ff80842"},
|
||||
{file = "tornado-6.4.1-cp38-abi3-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:613bf4ddf5c7a95509218b149b555621497a6cc0d46ac341b30bd9ec19eac7f3"},
|
||||
{file = "tornado-6.4.1-cp38-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:25486eb223babe3eed4b8aecbac33b37e3dd6d776bc730ca14e1bf93888b979f"},
|
||||
{file = "tornado-6.4.1-cp38-abi3-musllinux_1_2_i686.whl", hash = "sha256:454db8a7ecfcf2ff6042dde58404164d969b6f5d58b926da15e6b23817950fc4"},
|
||||
{file = "tornado-6.4.1-cp38-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:a02a08cc7a9314b006f653ce40483b9b3c12cda222d6a46d4ac63bb6c9057698"},
|
||||
{file = "tornado-6.4.1-cp38-abi3-win32.whl", hash = "sha256:d9a566c40b89757c9aa8e6f032bcdb8ca8795d7c1a9762910c722b1635c9de4d"},
|
||||
{file = "tornado-6.4.1-cp38-abi3-win_amd64.whl", hash = "sha256:b24b8982ed444378d7f21d563f4180a2de31ced9d8d84443907a0a64da2072e7"},
|
||||
{file = "tornado-6.4.1.tar.gz", hash = "sha256:92d3ab53183d8c50f8204a51e6f91d18a15d5ef261e84d452800d4ff6fc504e9"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -4505,13 +4505,13 @@ wsproto = ">=0.14"
|
||||
|
||||
[[package]]
|
||||
name = "twilio"
|
||||
version = "9.1.0"
|
||||
version = "9.1.1"
|
||||
description = "Twilio API client and TwiML generator"
|
||||
optional = false
|
||||
python-versions = ">=3.7.0"
|
||||
files = [
|
||||
{file = "twilio-9.1.0-py2.py3-none-any.whl", hash = "sha256:eb4687a9f81dc3118e8981c5a46d9f8184baee135c79afed47c714c759c31bbc"},
|
||||
{file = "twilio-9.1.0.tar.gz", hash = "sha256:ab2eb19c779855bf02cdca8a7e02ebaa64feee47da7b591ac9088ec07a6962e2"},
|
||||
{file = "twilio-9.1.1-py2.py3-none-any.whl", hash = "sha256:cc3e090c3884db7d70e7c647358b9cf1f4d30fd3fbe0412adcae0df8459d29b0"},
|
||||
{file = "twilio-9.1.1.tar.gz", hash = "sha256:cfe72b12cabac2f0997f1060d53cea14bd1196e2cbda14789e53c7dd762c4349"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
|
567
schema.yml
567
schema.yml
@ -19726,6 +19726,403 @@ paths:
|
||||
schema:
|
||||
$ref: '#/components/schemas/GenericError'
|
||||
description: ''
|
||||
/providers/scim_groups/:
|
||||
get:
|
||||
operationId: providers_scim_groups_list
|
||||
description: SCIMProviderGroup Viewset
|
||||
parameters:
|
||||
- in: query
|
||||
name: group__group_uuid
|
||||
schema:
|
||||
type: string
|
||||
format: uuid
|
||||
- in: query
|
||||
name: group__name
|
||||
schema:
|
||||
type: string
|
||||
- name: ordering
|
||||
required: false
|
||||
in: query
|
||||
description: Which field to use when ordering the results.
|
||||
schema:
|
||||
type: string
|
||||
- name: page
|
||||
required: false
|
||||
in: query
|
||||
description: A page number within the paginated result set.
|
||||
schema:
|
||||
type: integer
|
||||
- name: page_size
|
||||
required: false
|
||||
in: query
|
||||
description: Number of results to return per page.
|
||||
schema:
|
||||
type: integer
|
||||
- in: query
|
||||
name: provider__id
|
||||
schema:
|
||||
type: integer
|
||||
- name: search
|
||||
required: false
|
||||
in: query
|
||||
description: A search term.
|
||||
schema:
|
||||
type: string
|
||||
tags:
|
||||
- providers
|
||||
security:
|
||||
- authentik: []
|
||||
responses:
|
||||
'200':
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/PaginatedSCIMProviderGroupList'
|
||||
description: ''
|
||||
'400':
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/ValidationError'
|
||||
description: ''
|
||||
'403':
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/GenericError'
|
||||
description: ''
|
||||
post:
|
||||
operationId: providers_scim_groups_create
|
||||
description: SCIMProviderGroup Viewset
|
||||
tags:
|
||||
- providers
|
||||
requestBody:
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/SCIMProviderGroupRequest'
|
||||
required: true
|
||||
security:
|
||||
- authentik: []
|
||||
responses:
|
||||
'201':
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/SCIMProviderGroup'
|
||||
description: ''
|
||||
'400':
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/ValidationError'
|
||||
description: ''
|
||||
'403':
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/GenericError'
|
||||
description: ''
|
||||
/providers/scim_groups/{id}/:
|
||||
get:
|
||||
operationId: providers_scim_groups_retrieve
|
||||
description: SCIMProviderGroup Viewset
|
||||
parameters:
|
||||
- in: path
|
||||
name: id
|
||||
schema:
|
||||
type: string
|
||||
format: uuid
|
||||
description: A UUID string identifying this scim provider group.
|
||||
required: true
|
||||
tags:
|
||||
- providers
|
||||
security:
|
||||
- authentik: []
|
||||
responses:
|
||||
'200':
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/SCIMProviderGroup'
|
||||
description: ''
|
||||
'400':
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/ValidationError'
|
||||
description: ''
|
||||
'403':
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/GenericError'
|
||||
description: ''
|
||||
delete:
|
||||
operationId: providers_scim_groups_destroy
|
||||
description: SCIMProviderGroup Viewset
|
||||
parameters:
|
||||
- in: path
|
||||
name: id
|
||||
schema:
|
||||
type: string
|
||||
format: uuid
|
||||
description: A UUID string identifying this scim provider group.
|
||||
required: true
|
||||
tags:
|
||||
- providers
|
||||
security:
|
||||
- authentik: []
|
||||
responses:
|
||||
'204':
|
||||
description: No response body
|
||||
'400':
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/ValidationError'
|
||||
description: ''
|
||||
'403':
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/GenericError'
|
||||
description: ''
|
||||
/providers/scim_groups/{id}/used_by/:
|
||||
get:
|
||||
operationId: providers_scim_groups_used_by_list
|
||||
description: Get a list of all objects that use this object
|
||||
parameters:
|
||||
- in: path
|
||||
name: id
|
||||
schema:
|
||||
type: string
|
||||
format: uuid
|
||||
description: A UUID string identifying this scim provider group.
|
||||
required: true
|
||||
tags:
|
||||
- providers
|
||||
security:
|
||||
- authentik: []
|
||||
responses:
|
||||
'200':
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: array
|
||||
items:
|
||||
$ref: '#/components/schemas/UsedBy'
|
||||
description: ''
|
||||
'400':
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/ValidationError'
|
||||
description: ''
|
||||
'403':
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/GenericError'
|
||||
description: ''
|
||||
/providers/scim_users/:
|
||||
get:
|
||||
operationId: providers_scim_users_list
|
||||
description: SCIMProviderUser Viewset
|
||||
parameters:
|
||||
- name: ordering
|
||||
required: false
|
||||
in: query
|
||||
description: Which field to use when ordering the results.
|
||||
schema:
|
||||
type: string
|
||||
- name: page
|
||||
required: false
|
||||
in: query
|
||||
description: A page number within the paginated result set.
|
||||
schema:
|
||||
type: integer
|
||||
- name: page_size
|
||||
required: false
|
||||
in: query
|
||||
description: Number of results to return per page.
|
||||
schema:
|
||||
type: integer
|
||||
- in: query
|
||||
name: provider__id
|
||||
schema:
|
||||
type: integer
|
||||
- name: search
|
||||
required: false
|
||||
in: query
|
||||
description: A search term.
|
||||
schema:
|
||||
type: string
|
||||
- in: query
|
||||
name: user__id
|
||||
schema:
|
||||
type: integer
|
||||
- in: query
|
||||
name: user__username
|
||||
schema:
|
||||
type: string
|
||||
tags:
|
||||
- providers
|
||||
security:
|
||||
- authentik: []
|
||||
responses:
|
||||
'200':
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/PaginatedSCIMProviderUserList'
|
||||
description: ''
|
||||
'400':
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/ValidationError'
|
||||
description: ''
|
||||
'403':
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/GenericError'
|
||||
description: ''
|
||||
post:
|
||||
operationId: providers_scim_users_create
|
||||
description: SCIMProviderUser Viewset
|
||||
tags:
|
||||
- providers
|
||||
requestBody:
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/SCIMProviderUserRequest'
|
||||
required: true
|
||||
security:
|
||||
- authentik: []
|
||||
responses:
|
||||
'201':
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/SCIMProviderUser'
|
||||
description: ''
|
||||
'400':
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/ValidationError'
|
||||
description: ''
|
||||
'403':
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/GenericError'
|
||||
description: ''
|
||||
/providers/scim_users/{id}/:
|
||||
get:
|
||||
operationId: providers_scim_users_retrieve
|
||||
description: SCIMProviderUser Viewset
|
||||
parameters:
|
||||
- in: path
|
||||
name: id
|
||||
schema:
|
||||
type: string
|
||||
format: uuid
|
||||
description: A UUID string identifying this scim provider user.
|
||||
required: true
|
||||
tags:
|
||||
- providers
|
||||
security:
|
||||
- authentik: []
|
||||
responses:
|
||||
'200':
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/SCIMProviderUser'
|
||||
description: ''
|
||||
'400':
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/ValidationError'
|
||||
description: ''
|
||||
'403':
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/GenericError'
|
||||
description: ''
|
||||
delete:
|
||||
operationId: providers_scim_users_destroy
|
||||
description: SCIMProviderUser Viewset
|
||||
parameters:
|
||||
- in: path
|
||||
name: id
|
||||
schema:
|
||||
type: string
|
||||
format: uuid
|
||||
description: A UUID string identifying this scim provider user.
|
||||
required: true
|
||||
tags:
|
||||
- providers
|
||||
security:
|
||||
- authentik: []
|
||||
responses:
|
||||
'204':
|
||||
description: No response body
|
||||
'400':
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/ValidationError'
|
||||
description: ''
|
||||
'403':
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/GenericError'
|
||||
description: ''
|
||||
/providers/scim_users/{id}/used_by/:
|
||||
get:
|
||||
operationId: providers_scim_users_used_by_list
|
||||
description: Get a list of all objects that use this object
|
||||
parameters:
|
||||
- in: path
|
||||
name: id
|
||||
schema:
|
||||
type: string
|
||||
format: uuid
|
||||
description: A UUID string identifying this scim provider user.
|
||||
required: true
|
||||
tags:
|
||||
- providers
|
||||
security:
|
||||
- authentik: []
|
||||
responses:
|
||||
'200':
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: array
|
||||
items:
|
||||
$ref: '#/components/schemas/UsedBy'
|
||||
description: ''
|
||||
'400':
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/ValidationError'
|
||||
description: ''
|
||||
'403':
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/GenericError'
|
||||
description: ''
|
||||
/rac/connection_tokens/:
|
||||
get:
|
||||
operationId: rac_connection_tokens_list
|
||||
@ -34067,6 +34464,18 @@ components:
|
||||
type: string
|
||||
api_url:
|
||||
type: string
|
||||
score_min_threshold:
|
||||
type: number
|
||||
format: double
|
||||
score_max_threshold:
|
||||
type: number
|
||||
format: double
|
||||
error_on_invalid_score:
|
||||
type: boolean
|
||||
description: When enabled and the received captcha score is outside of the
|
||||
given threshold, the stage will show an error message. When not enabled,
|
||||
the flow will continue, but the data from the captcha will be available
|
||||
in the context for policy decisions
|
||||
required:
|
||||
- component
|
||||
- meta_model_name
|
||||
@ -34101,6 +34510,18 @@ components:
|
||||
api_url:
|
||||
type: string
|
||||
minLength: 1
|
||||
score_min_threshold:
|
||||
type: number
|
||||
format: double
|
||||
score_max_threshold:
|
||||
type: number
|
||||
format: double
|
||||
error_on_invalid_score:
|
||||
type: boolean
|
||||
description: When enabled and the received captcha score is outside of the
|
||||
given threshold, the stage will show an error message. When not enabled,
|
||||
the flow will continue, but the data from the captcha will be available
|
||||
in the context for policy decisions
|
||||
required:
|
||||
- name
|
||||
- private_key
|
||||
@ -36311,6 +36732,8 @@ components:
|
||||
type: string
|
||||
format: uuid
|
||||
readOnly: true
|
||||
google_id:
|
||||
type: string
|
||||
group:
|
||||
type: string
|
||||
format: uuid
|
||||
@ -36324,6 +36747,7 @@ components:
|
||||
readOnly: true
|
||||
required:
|
||||
- attributes
|
||||
- google_id
|
||||
- group
|
||||
- group_obj
|
||||
- id
|
||||
@ -36332,12 +36756,16 @@ components:
|
||||
type: object
|
||||
description: GoogleWorkspaceProviderGroup Serializer
|
||||
properties:
|
||||
google_id:
|
||||
type: string
|
||||
minLength: 1
|
||||
group:
|
||||
type: string
|
||||
format: uuid
|
||||
provider:
|
||||
type: integer
|
||||
required:
|
||||
- google_id
|
||||
- group
|
||||
- provider
|
||||
GoogleWorkspaceProviderMapping:
|
||||
@ -36460,6 +36888,8 @@ components:
|
||||
type: string
|
||||
format: uuid
|
||||
readOnly: true
|
||||
google_id:
|
||||
type: string
|
||||
user:
|
||||
type: integer
|
||||
user_obj:
|
||||
@ -36472,6 +36902,7 @@ components:
|
||||
readOnly: true
|
||||
required:
|
||||
- attributes
|
||||
- google_id
|
||||
- id
|
||||
- provider
|
||||
- user
|
||||
@ -36480,11 +36911,15 @@ components:
|
||||
type: object
|
||||
description: GoogleWorkspaceProviderUser Serializer
|
||||
properties:
|
||||
google_id:
|
||||
type: string
|
||||
minLength: 1
|
||||
user:
|
||||
type: integer
|
||||
provider:
|
||||
type: integer
|
||||
required:
|
||||
- google_id
|
||||
- provider
|
||||
- user
|
||||
Group:
|
||||
@ -37979,6 +38414,8 @@ components:
|
||||
type: string
|
||||
format: uuid
|
||||
readOnly: true
|
||||
microsoft_id:
|
||||
type: string
|
||||
group:
|
||||
type: string
|
||||
format: uuid
|
||||
@ -37995,11 +38432,15 @@ components:
|
||||
- group
|
||||
- group_obj
|
||||
- id
|
||||
- microsoft_id
|
||||
- provider
|
||||
MicrosoftEntraProviderGroupRequest:
|
||||
type: object
|
||||
description: MicrosoftEntraProviderGroup Serializer
|
||||
properties:
|
||||
microsoft_id:
|
||||
type: string
|
||||
minLength: 1
|
||||
group:
|
||||
type: string
|
||||
format: uuid
|
||||
@ -38007,6 +38448,7 @@ components:
|
||||
type: integer
|
||||
required:
|
||||
- group
|
||||
- microsoft_id
|
||||
- provider
|
||||
MicrosoftEntraProviderMapping:
|
||||
type: object
|
||||
@ -38125,6 +38567,8 @@ components:
|
||||
type: string
|
||||
format: uuid
|
||||
readOnly: true
|
||||
microsoft_id:
|
||||
type: string
|
||||
user:
|
||||
type: integer
|
||||
user_obj:
|
||||
@ -38138,6 +38582,7 @@ components:
|
||||
required:
|
||||
- attributes
|
||||
- id
|
||||
- microsoft_id
|
||||
- provider
|
||||
- user
|
||||
- user_obj
|
||||
@ -38145,11 +38590,15 @@ components:
|
||||
type: object
|
||||
description: MicrosoftEntraProviderUser Serializer
|
||||
properties:
|
||||
microsoft_id:
|
||||
type: string
|
||||
minLength: 1
|
||||
user:
|
||||
type: integer
|
||||
provider:
|
||||
type: integer
|
||||
required:
|
||||
- microsoft_id
|
||||
- provider
|
||||
- user
|
||||
ModelEnum:
|
||||
@ -40142,6 +40591,18 @@ components:
|
||||
required:
|
||||
- pagination
|
||||
- results
|
||||
PaginatedSCIMProviderGroupList:
|
||||
type: object
|
||||
properties:
|
||||
pagination:
|
||||
$ref: '#/components/schemas/Pagination'
|
||||
results:
|
||||
type: array
|
||||
items:
|
||||
$ref: '#/components/schemas/SCIMProviderGroup'
|
||||
required:
|
||||
- pagination
|
||||
- results
|
||||
PaginatedSCIMProviderList:
|
||||
type: object
|
||||
properties:
|
||||
@ -40154,6 +40615,18 @@ components:
|
||||
required:
|
||||
- pagination
|
||||
- results
|
||||
PaginatedSCIMProviderUserList:
|
||||
type: object
|
||||
properties:
|
||||
pagination:
|
||||
$ref: '#/components/schemas/Pagination'
|
||||
results:
|
||||
type: array
|
||||
items:
|
||||
$ref: '#/components/schemas/SCIMProviderUser'
|
||||
required:
|
||||
- pagination
|
||||
- results
|
||||
PaginatedSCIMSourceGroupList:
|
||||
type: object
|
||||
properties:
|
||||
@ -41182,6 +41655,18 @@ components:
|
||||
api_url:
|
||||
type: string
|
||||
minLength: 1
|
||||
score_min_threshold:
|
||||
type: number
|
||||
format: double
|
||||
score_max_threshold:
|
||||
type: number
|
||||
format: double
|
||||
error_on_invalid_score:
|
||||
type: boolean
|
||||
description: When enabled and the received captcha score is outside of the
|
||||
given threshold, the stage will show an error message. When not enabled,
|
||||
the flow will continue, but the data from the captcha will be available
|
||||
in the context for policy decisions
|
||||
PatchedCertificateKeyPairRequest:
|
||||
type: object
|
||||
description: CertificateKeyPair Serializer
|
||||
@ -44111,12 +44596,14 @@ components:
|
||||
properties:
|
||||
user:
|
||||
type: integer
|
||||
nullable: true
|
||||
context:
|
||||
type: object
|
||||
additionalProperties: {}
|
||||
group:
|
||||
type: string
|
||||
format: uuid
|
||||
nullable: true
|
||||
PropertyMappingTestResult:
|
||||
type: object
|
||||
description: Result of a Property-mapping test
|
||||
@ -45870,6 +46357,47 @@ components:
|
||||
- url
|
||||
- verbose_name
|
||||
- verbose_name_plural
|
||||
SCIMProviderGroup:
|
||||
type: object
|
||||
description: SCIMProviderGroup Serializer
|
||||
properties:
|
||||
id:
|
||||
type: string
|
||||
format: uuid
|
||||
readOnly: true
|
||||
scim_id:
|
||||
type: string
|
||||
group:
|
||||
type: string
|
||||
format: uuid
|
||||
group_obj:
|
||||
allOf:
|
||||
- $ref: '#/components/schemas/UserGroup'
|
||||
readOnly: true
|
||||
provider:
|
||||
type: integer
|
||||
required:
|
||||
- group
|
||||
- group_obj
|
||||
- id
|
||||
- provider
|
||||
- scim_id
|
||||
SCIMProviderGroupRequest:
|
||||
type: object
|
||||
description: SCIMProviderGroup Serializer
|
||||
properties:
|
||||
scim_id:
|
||||
type: string
|
||||
minLength: 1
|
||||
group:
|
||||
type: string
|
||||
format: uuid
|
||||
provider:
|
||||
type: integer
|
||||
required:
|
||||
- group
|
||||
- provider
|
||||
- scim_id
|
||||
SCIMProviderRequest:
|
||||
type: object
|
||||
description: SCIMProvider Serializer
|
||||
@ -45906,6 +46434,45 @@ components:
|
||||
- name
|
||||
- token
|
||||
- url
|
||||
SCIMProviderUser:
|
||||
type: object
|
||||
description: SCIMProviderUser Serializer
|
||||
properties:
|
||||
id:
|
||||
type: string
|
||||
format: uuid
|
||||
readOnly: true
|
||||
scim_id:
|
||||
type: string
|
||||
user:
|
||||
type: integer
|
||||
user_obj:
|
||||
allOf:
|
||||
- $ref: '#/components/schemas/GroupMember'
|
||||
readOnly: true
|
||||
provider:
|
||||
type: integer
|
||||
required:
|
||||
- id
|
||||
- provider
|
||||
- scim_id
|
||||
- user
|
||||
- user_obj
|
||||
SCIMProviderUserRequest:
|
||||
type: object
|
||||
description: SCIMProviderUser Serializer
|
||||
properties:
|
||||
scim_id:
|
||||
type: string
|
||||
minLength: 1
|
||||
user:
|
||||
type: integer
|
||||
provider:
|
||||
type: integer
|
||||
required:
|
||||
- provider
|
||||
- scim_id
|
||||
- user
|
||||
SCIMSource:
|
||||
type: object
|
||||
description: SCIMSource Serializer
|
||||
|
@ -1,5 +1,3 @@
|
||||
version: '3.7'
|
||||
|
||||
services:
|
||||
chrome:
|
||||
image: docker.io/selenium/standalone-chrome:122.0
|
||||
|
168
tests/wdio/package-lock.json
generated
168
tests/wdio/package-lock.json
generated
@ -6,21 +6,21 @@
|
||||
"": {
|
||||
"name": "@goauthentik/web-tests",
|
||||
"dependencies": {
|
||||
"chromedriver": "^125.0.3"
|
||||
"chromedriver": "^126.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@trivago/prettier-plugin-sort-imports": "^4.3.0",
|
||||
"@typescript-eslint/eslint-plugin": "^7.5.0",
|
||||
"@typescript-eslint/parser": "^7.5.0",
|
||||
"@wdio/cli": "^8.38.1",
|
||||
"@wdio/local-runner": "^8.38.0",
|
||||
"@wdio/mocha-framework": "^8.38.0",
|
||||
"@wdio/spec-reporter": "^8.38.0",
|
||||
"@wdio/cli": "^8.38.2",
|
||||
"@wdio/local-runner": "^8.38.2",
|
||||
"@wdio/mocha-framework": "^8.38.2",
|
||||
"@wdio/spec-reporter": "^8.38.2",
|
||||
"eslint": "^8.57.0",
|
||||
"eslint-config-google": "^0.14.0",
|
||||
"eslint-plugin-sonarjs": "^0.25.1",
|
||||
"npm-run-all": "^4.1.5",
|
||||
"prettier": "^3.3.0",
|
||||
"prettier": "^3.3.2",
|
||||
"ts-node": "^10.9.2",
|
||||
"typescript": "^5.4.5",
|
||||
"wdio-wait-for": "^3.0.11"
|
||||
@ -1189,19 +1189,19 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@wdio/cli": {
|
||||
"version": "8.38.1",
|
||||
"resolved": "https://registry.npmjs.org/@wdio/cli/-/cli-8.38.1.tgz",
|
||||
"integrity": "sha512-xif0RvJX+saXVdzrhlEafbEdptNyeyqm0pyilT4H7OI7OMa+23rWB67r2SPoIZbBrVeFv1iqtUx9hR73RRio2A==",
|
||||
"version": "8.38.2",
|
||||
"resolved": "https://registry.npmjs.org/@wdio/cli/-/cli-8.38.2.tgz",
|
||||
"integrity": "sha512-p9y6jxmpmw53OoB9v/uTLwMetmz7Q0K7NewdVONgmeTY/ERpkU15qL3fMw1rXb+E+vrV8dlce4srnXroec6SFA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@types/node": "^20.1.1",
|
||||
"@vitest/snapshot": "^1.2.1",
|
||||
"@wdio/config": "8.38.0",
|
||||
"@wdio/globals": "8.38.0",
|
||||
"@wdio/config": "8.38.2",
|
||||
"@wdio/globals": "8.38.2",
|
||||
"@wdio/logger": "8.38.0",
|
||||
"@wdio/protocols": "8.38.0",
|
||||
"@wdio/types": "8.37.0",
|
||||
"@wdio/utils": "8.38.0",
|
||||
"@wdio/types": "8.38.2",
|
||||
"@wdio/utils": "8.38.2",
|
||||
"async-exit-hook": "^2.0.1",
|
||||
"chalk": "^5.2.0",
|
||||
"chokidar": "^3.5.3",
|
||||
@ -1216,7 +1216,7 @@
|
||||
"lodash.union": "^4.6.0",
|
||||
"read-pkg-up": "10.0.0",
|
||||
"recursive-readdir": "^2.2.3",
|
||||
"webdriverio": "8.38.0",
|
||||
"webdriverio": "8.38.2",
|
||||
"yargs": "^17.7.2"
|
||||
},
|
||||
"bin": {
|
||||
@ -1239,14 +1239,14 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@wdio/config": {
|
||||
"version": "8.38.0",
|
||||
"resolved": "https://registry.npmjs.org/@wdio/config/-/config-8.38.0.tgz",
|
||||
"integrity": "sha512-9eMmHYkXw/0htj8Nok2vBa8Q+IS/wj7HXbLczKb5rEmDb57SW5iPMpZutFywGki1D/GIDLvejWaZvlxmS/yfBA==",
|
||||
"version": "8.38.2",
|
||||
"resolved": "https://registry.npmjs.org/@wdio/config/-/config-8.38.2.tgz",
|
||||
"integrity": "sha512-xlnapTr1vOA0h5HsHTIqj47729FbG3WjxmgHweDEQvcT4C1g9l+WKf+N3FM7DNNoIsAqxKi6rOHG02rJADQJtw==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@wdio/logger": "8.38.0",
|
||||
"@wdio/types": "8.37.0",
|
||||
"@wdio/utils": "8.38.0",
|
||||
"@wdio/types": "8.38.2",
|
||||
"@wdio/utils": "8.38.2",
|
||||
"decamelize": "^6.0.0",
|
||||
"deepmerge-ts": "^5.0.0",
|
||||
"glob": "^10.2.2",
|
||||
@ -1257,29 +1257,29 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@wdio/globals": {
|
||||
"version": "8.38.0",
|
||||
"resolved": "https://registry.npmjs.org/@wdio/globals/-/globals-8.38.0.tgz",
|
||||
"integrity": "sha512-3Lo7R305gwJrloUolrgSRaMbIFKwnj/SPoYUt94dsTF1oM3TpyWpomcVokElNQiOFx9WYjMmBla2M+YcnoGmgw==",
|
||||
"version": "8.38.2",
|
||||
"resolved": "https://registry.npmjs.org/@wdio/globals/-/globals-8.38.2.tgz",
|
||||
"integrity": "sha512-iIrUF1EODfHLh3V/CSNCqbNNxUTe3ND+c86zDjzJcPFjawLX1plvAApsU/eDmtsFShcOS2KHbfSjiydFoqQG1Q==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": "^16.13 || >=18"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"expect-webdriverio": "^4.11.2",
|
||||
"webdriverio": "8.38.0"
|
||||
"webdriverio": "8.38.2"
|
||||
}
|
||||
},
|
||||
"node_modules/@wdio/local-runner": {
|
||||
"version": "8.38.0",
|
||||
"resolved": "https://registry.npmjs.org/@wdio/local-runner/-/local-runner-8.38.0.tgz",
|
||||
"integrity": "sha512-++eVI+EQapBMRxtLSbeooK02uELAhIXNLzgBlC03s23OTZUUOxzl4WxFuGqaG8gpNHer5Bjg+uAy0rIbSMnklA==",
|
||||
"version": "8.38.2",
|
||||
"resolved": "https://registry.npmjs.org/@wdio/local-runner/-/local-runner-8.38.2.tgz",
|
||||
"integrity": "sha512-syW+R5VUHJ3GBkQGFcNYe6MYwWRgklc9W7A83xQDTvKWFNHCetLvc8AtKZ54vs8MItBejjU+Oh94ZNbNX1pBcg==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@types/node": "^20.1.0",
|
||||
"@wdio/logger": "8.38.0",
|
||||
"@wdio/repl": "8.24.12",
|
||||
"@wdio/runner": "8.38.0",
|
||||
"@wdio/types": "8.37.0",
|
||||
"@wdio/runner": "8.38.2",
|
||||
"@wdio/types": "8.38.2",
|
||||
"async-exit-hook": "^2.0.1",
|
||||
"split2": "^4.1.0",
|
||||
"stream-buffers": "^3.0.2"
|
||||
@ -1316,16 +1316,16 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@wdio/mocha-framework": {
|
||||
"version": "8.38.0",
|
||||
"resolved": "https://registry.npmjs.org/@wdio/mocha-framework/-/mocha-framework-8.38.0.tgz",
|
||||
"integrity": "sha512-LWwKslKIxqhQNskdffcS6QbxN45PzJN21b5zByELbEYd9PIGNbuXXqueVE09RwEAzBHtL86ZhSpFclAB+ulsBw==",
|
||||
"version": "8.38.2",
|
||||
"resolved": "https://registry.npmjs.org/@wdio/mocha-framework/-/mocha-framework-8.38.2.tgz",
|
||||
"integrity": "sha512-qJmRL5E6/ypjCUACH4hvCAAmTdU4YUrUlp9o/IKvTIAHMnZPE0/HgUFixCeu8Mop+rdzTPVBrbqxpRDdSnraYA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@types/mocha": "^10.0.0",
|
||||
"@types/node": "^20.1.0",
|
||||
"@wdio/logger": "8.38.0",
|
||||
"@wdio/types": "8.37.0",
|
||||
"@wdio/utils": "8.38.0",
|
||||
"@wdio/types": "8.38.2",
|
||||
"@wdio/utils": "8.38.2",
|
||||
"mocha": "^10.0.0"
|
||||
},
|
||||
"engines": {
|
||||
@ -1351,14 +1351,14 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@wdio/reporter": {
|
||||
"version": "8.38.0",
|
||||
"resolved": "https://registry.npmjs.org/@wdio/reporter/-/reporter-8.38.0.tgz",
|
||||
"integrity": "sha512-7eyBM06j0PAu2g14wOwJbSmUOaT8q1pmMukzeRl1YDoW2sLpQG0zMZNzQNsQyi7+1KgltTJJnvHCec5MBZrjpw==",
|
||||
"version": "8.38.2",
|
||||
"resolved": "https://registry.npmjs.org/@wdio/reporter/-/reporter-8.38.2.tgz",
|
||||
"integrity": "sha512-R78UdAtAnkaV22NYlCCcbPPhmYweiDURiw64LYhlVIQrKNuXUQcafR2kRlWKy31rZc9thSLs5LzrZDReENUlFQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@types/node": "^20.1.0",
|
||||
"@wdio/logger": "8.38.0",
|
||||
"@wdio/types": "8.37.0",
|
||||
"@wdio/types": "8.38.2",
|
||||
"diff": "^5.0.0",
|
||||
"object-inspect": "^1.12.0"
|
||||
},
|
||||
@ -1367,35 +1367,35 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@wdio/runner": {
|
||||
"version": "8.38.0",
|
||||
"resolved": "https://registry.npmjs.org/@wdio/runner/-/runner-8.38.0.tgz",
|
||||
"integrity": "sha512-pmoXwRMUxWXhqce64Y3gqoMqJn0YknJ1U9aHOMxp6uB3iHfzoPA+7Mf5ziSc0uDBcEyjXtau9qMfu7iBHUz62Q==",
|
||||
"version": "8.38.2",
|
||||
"resolved": "https://registry.npmjs.org/@wdio/runner/-/runner-8.38.2.tgz",
|
||||
"integrity": "sha512-5lPnKSX2BBLI2AbYW+hoGPiEUAJXj8F8I6NC2LaBVzf1CLN+w2HWZ7lUiqS14XT0b5/hlSUX6+JYwUXlDbpuuw==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@types/node": "^20.11.28",
|
||||
"@wdio/config": "8.38.0",
|
||||
"@wdio/globals": "8.38.0",
|
||||
"@wdio/config": "8.38.2",
|
||||
"@wdio/globals": "8.38.2",
|
||||
"@wdio/logger": "8.38.0",
|
||||
"@wdio/types": "8.37.0",
|
||||
"@wdio/utils": "8.38.0",
|
||||
"@wdio/types": "8.38.2",
|
||||
"@wdio/utils": "8.38.2",
|
||||
"deepmerge-ts": "^5.1.0",
|
||||
"expect-webdriverio": "^4.12.0",
|
||||
"gaze": "^1.1.3",
|
||||
"webdriver": "8.38.0",
|
||||
"webdriverio": "8.38.0"
|
||||
"webdriver": "8.38.2",
|
||||
"webdriverio": "8.38.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^16.13 || >=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@wdio/spec-reporter": {
|
||||
"version": "8.38.0",
|
||||
"resolved": "https://registry.npmjs.org/@wdio/spec-reporter/-/spec-reporter-8.38.0.tgz",
|
||||
"integrity": "sha512-Cuk/mqsBa+YgAL3OCtsYLUxRkGSYeaXM3LSE5muzY1mSqQlK3a/5GdAXlaOosuhYpUgI0A9xTsMiq7PQd75qHA==",
|
||||
"version": "8.38.2",
|
||||
"resolved": "https://registry.npmjs.org/@wdio/spec-reporter/-/spec-reporter-8.38.2.tgz",
|
||||
"integrity": "sha512-Dntk+lmrp+0I3HRRWkkXED+smshvgsW5cdLKwJhEJ1liI48MdBpdNGf9IHTVckE6nfxcWDyFI4icD9qYv/5bFA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@wdio/reporter": "8.38.0",
|
||||
"@wdio/types": "8.37.0",
|
||||
"@wdio/reporter": "8.38.2",
|
||||
"@wdio/types": "8.38.2",
|
||||
"chalk": "^5.1.2",
|
||||
"easy-table": "^1.2.0",
|
||||
"pretty-ms": "^7.0.0"
|
||||
@ -1417,9 +1417,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@wdio/types": {
|
||||
"version": "8.37.0",
|
||||
"resolved": "https://registry.npmjs.org/@wdio/types/-/types-8.37.0.tgz",
|
||||
"integrity": "sha512-36kmSlZcVhsMlbhaSCQUfL51iG81FlbzW4Dfkz4903cDkxmh64bgxydZbRB5aPLnJzzR7tI3chIME8zSVZFR8w==",
|
||||
"version": "8.38.2",
|
||||
"resolved": "https://registry.npmjs.org/@wdio/types/-/types-8.38.2.tgz",
|
||||
"integrity": "sha512-+wj1c1OSLdnN4WO5b44Ih4263dTl/eSwMGSI4/pCgIyXIuYQH38JQ+6WRa+c8vJEskUzboq2cSgEQumVZ39ozQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@types/node": "^20.1.0"
|
||||
@ -1429,14 +1429,14 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@wdio/utils": {
|
||||
"version": "8.38.0",
|
||||
"resolved": "https://registry.npmjs.org/@wdio/utils/-/utils-8.38.0.tgz",
|
||||
"integrity": "sha512-ios7MpyJk4kGW9ZOYxbPpdwVZBI7SzccIgiirqSf8rvJi62VpDA2nfa7i7BY1rs9p7lnenF8phwnuVFGMCoL0w==",
|
||||
"version": "8.38.2",
|
||||
"resolved": "https://registry.npmjs.org/@wdio/utils/-/utils-8.38.2.tgz",
|
||||
"integrity": "sha512-y5AnBwsGcu/XuCBGCgKmlvKdwEIFyzLA+Cr+denySxY3jbWDONtPUcGaVdFALwsIa5jcIjcATqGmZcCPGnkd7g==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@puppeteer/browsers": "^1.6.0",
|
||||
"@wdio/logger": "8.38.0",
|
||||
"@wdio/types": "8.37.0",
|
||||
"@wdio/types": "8.38.2",
|
||||
"decamelize": "^6.0.0",
|
||||
"deepmerge-ts": "^5.1.0",
|
||||
"edgedriver": "^5.5.0",
|
||||
@ -1879,12 +1879,12 @@
|
||||
}
|
||||
},
|
||||
"node_modules/braces": {
|
||||
"version": "3.0.2",
|
||||
"resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz",
|
||||
"integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==",
|
||||
"version": "3.0.3",
|
||||
"resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz",
|
||||
"integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"fill-range": "^7.0.1"
|
||||
"fill-range": "^7.1.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
@ -2084,9 +2084,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/chromedriver": {
|
||||
"version": "125.0.3",
|
||||
"resolved": "https://registry.npmjs.org/chromedriver/-/chromedriver-125.0.3.tgz",
|
||||
"integrity": "sha512-Qzuk5Wian2o3EVGjtbz6V/jv+pT/AV9246HbG6kUljZXXjsKZLZxqJC+kHR3qEh/wdv4EJD0YwAOWV72v9hogw==",
|
||||
"version": "126.0.0",
|
||||
"resolved": "https://registry.npmjs.org/chromedriver/-/chromedriver-126.0.0.tgz",
|
||||
"integrity": "sha512-rzwKp1okI9RmFtSyIzkk9+GTlTK62ai5P3/AS2qMwl86+gw84d2S/IyLkQMm5cqieFs4dgDAuqqPu0AqQACScg==",
|
||||
"hasInstallScript": true,
|
||||
"dependencies": {
|
||||
"@testim/chrome-version": "^1.1.4",
|
||||
@ -3655,9 +3655,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/fill-range": {
|
||||
"version": "7.0.1",
|
||||
"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",
|
||||
"integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==",
|
||||
"version": "7.1.1",
|
||||
"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz",
|
||||
"integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"to-regex-range": "^5.0.1"
|
||||
@ -6908,9 +6908,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/prettier": {
|
||||
"version": "3.3.0",
|
||||
"resolved": "https://registry.npmjs.org/prettier/-/prettier-3.3.0.tgz",
|
||||
"integrity": "sha512-J9odKxERhCQ10OC2yb93583f6UnYutOeiV5i0zEDS7UGTdUt0u+y8erxl3lBKvwo/JHyyoEdXjwp4dke9oyZ/g==",
|
||||
"version": "3.3.2",
|
||||
"resolved": "https://registry.npmjs.org/prettier/-/prettier-3.3.2.tgz",
|
||||
"integrity": "sha512-rAVeHYMcv8ATV5d508CFdn+8/pHPpXeIid1DdrPwXnaAdH7cqjVbpJaT5eq4yRAFU/lsbwYwSF/n5iNrdJHPQA==",
|
||||
"dev": true,
|
||||
"bin": {
|
||||
"prettier": "bin/prettier.cjs"
|
||||
@ -8969,18 +8969,18 @@
|
||||
}
|
||||
},
|
||||
"node_modules/webdriver": {
|
||||
"version": "8.38.0",
|
||||
"resolved": "https://registry.npmjs.org/webdriver/-/webdriver-8.38.0.tgz",
|
||||
"integrity": "sha512-BT3sd667AqcZ1lzaOd7lphjnc7MNG3WgduAq4vUUDYlJAbs6SyjYd0EZPIPv9KUUYr0BoSJTDa0Xuyl/6PPW0Q==",
|
||||
"version": "8.38.2",
|
||||
"resolved": "https://registry.npmjs.org/webdriver/-/webdriver-8.38.2.tgz",
|
||||
"integrity": "sha512-NGfjW0BDYwFgOIzeojOcWGn3tYloQdvHr+Y2xKKYVqa9Rs0x1mzlTjU1kWtC4DaV8DltskwaPa7o+s8hTNpuyA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@types/node": "^20.1.0",
|
||||
"@types/ws": "^8.5.3",
|
||||
"@wdio/config": "8.38.0",
|
||||
"@wdio/config": "8.38.2",
|
||||
"@wdio/logger": "8.38.0",
|
||||
"@wdio/protocols": "8.38.0",
|
||||
"@wdio/types": "8.37.0",
|
||||
"@wdio/utils": "8.38.0",
|
||||
"@wdio/types": "8.38.2",
|
||||
"@wdio/utils": "8.38.2",
|
||||
"deepmerge-ts": "^5.1.0",
|
||||
"got": "^12.6.1",
|
||||
"ky": "^0.33.0",
|
||||
@ -8991,18 +8991,18 @@
|
||||
}
|
||||
},
|
||||
"node_modules/webdriverio": {
|
||||
"version": "8.38.0",
|
||||
"resolved": "https://registry.npmjs.org/webdriverio/-/webdriverio-8.38.0.tgz",
|
||||
"integrity": "sha512-PxLtJPK8Aa+f/G/P8YGUwGH80uHowMA8cDHshhog6sKbp1BXEVB8x6PyC1AIswRlTWVijoes7cD0cUoVs6C87A==",
|
||||
"version": "8.38.2",
|
||||
"resolved": "https://registry.npmjs.org/webdriverio/-/webdriverio-8.38.2.tgz",
|
||||
"integrity": "sha512-r09y5UfivyYh5JOzT2SpJJ1zDmQl/R4OTH12opUqkjvp21BibCQm/uu1mrxGy4lzSHljrvqSVrrcGI+6UA1O8w==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@types/node": "^20.1.0",
|
||||
"@wdio/config": "8.38.0",
|
||||
"@wdio/config": "8.38.2",
|
||||
"@wdio/logger": "8.38.0",
|
||||
"@wdio/protocols": "8.38.0",
|
||||
"@wdio/repl": "8.24.12",
|
||||
"@wdio/types": "8.37.0",
|
||||
"@wdio/utils": "8.38.0",
|
||||
"@wdio/types": "8.38.2",
|
||||
"@wdio/utils": "8.38.2",
|
||||
"archiver": "^7.0.0",
|
||||
"aria-query": "^5.0.0",
|
||||
"css-shorthand-properties": "^1.1.1",
|
||||
@ -9020,7 +9020,7 @@
|
||||
"resq": "^1.9.1",
|
||||
"rgb2hex": "0.2.5",
|
||||
"serialize-error": "^11.0.1",
|
||||
"webdriver": "8.38.0"
|
||||
"webdriver": "8.38.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^16.13 || >=18"
|
||||
|
@ -6,15 +6,15 @@
|
||||
"@trivago/prettier-plugin-sort-imports": "^4.3.0",
|
||||
"@typescript-eslint/eslint-plugin": "^7.5.0",
|
||||
"@typescript-eslint/parser": "^7.5.0",
|
||||
"@wdio/cli": "^8.38.1",
|
||||
"@wdio/local-runner": "^8.38.0",
|
||||
"@wdio/mocha-framework": "^8.38.0",
|
||||
"@wdio/spec-reporter": "^8.38.0",
|
||||
"@wdio/cli": "^8.38.2",
|
||||
"@wdio/local-runner": "^8.38.2",
|
||||
"@wdio/mocha-framework": "^8.38.2",
|
||||
"@wdio/spec-reporter": "^8.38.2",
|
||||
"eslint": "^8.57.0",
|
||||
"eslint-config-google": "^0.14.0",
|
||||
"eslint-plugin-sonarjs": "^0.25.1",
|
||||
"npm-run-all": "^4.1.5",
|
||||
"prettier": "^3.3.0",
|
||||
"prettier": "^3.3.2",
|
||||
"ts-node": "^10.9.2",
|
||||
"typescript": "^5.4.5",
|
||||
"wdio-wait-for": "^3.0.11"
|
||||
@ -32,6 +32,6 @@
|
||||
"node": ">=20"
|
||||
},
|
||||
"dependencies": {
|
||||
"chromedriver": "^125.0.3"
|
||||
"chromedriver": "^126.0.0"
|
||||
}
|
||||
}
|
||||
|
2426
web/package-lock.json
generated
2426
web/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -38,15 +38,15 @@
|
||||
"@codemirror/theme-one-dark": "^6.1.2",
|
||||
"@formatjs/intl-listformat": "^7.5.7",
|
||||
"@fortawesome/fontawesome-free": "^6.5.2",
|
||||
"@goauthentik/api": "^2024.4.2-1717033226",
|
||||
"@goauthentik/api": "^2024.4.2-1717645682",
|
||||
"@lit-labs/task": "^3.1.0",
|
||||
"@lit/context": "^1.1.1",
|
||||
"@lit/context": "^1.1.2",
|
||||
"@lit/localize": "^0.12.1",
|
||||
"@lit/reactive-element": "^2.0.4",
|
||||
"@open-wc/lit-helpers": "^0.7.0",
|
||||
"@patternfly/elements": "^3.0.1",
|
||||
"@patternfly/patternfly": "^4.224.2",
|
||||
"@sentry/browser": "^8.7.0",
|
||||
"@sentry/browser": "^8.9.1",
|
||||
"@webcomponents/webcomponentsjs": "^2.8.0",
|
||||
"base64-js": "^1.5.1",
|
||||
"chart.js": "^4.4.3",
|
||||
@ -54,10 +54,10 @@
|
||||
"codemirror": "^6.0.1",
|
||||
"construct-style-sheets-polyfill": "^3.1.0",
|
||||
"core-js": "^3.37.1",
|
||||
"country-flag-icons": "^1.5.11",
|
||||
"country-flag-icons": "^1.5.12",
|
||||
"fuse.js": "^7.0.0",
|
||||
"guacamole-common-js": "^1.5.0",
|
||||
"lit": "^3.1.3",
|
||||
"lit": "^3.1.4",
|
||||
"md-front-matter": "^1.0.4",
|
||||
"mermaid": "^10.9.1",
|
||||
"rapidoc": "^9.3.4",
|
||||
@ -65,29 +65,29 @@
|
||||
"style-mod": "^4.1.2",
|
||||
"ts-pattern": "^5.1.2",
|
||||
"webcomponent-qr-code": "^1.2.0",
|
||||
"yaml": "^2.4.3"
|
||||
"yaml": "^2.4.5"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.24.6",
|
||||
"@babel/core": "^7.24.7",
|
||||
"@babel/plugin-proposal-class-properties": "^7.18.6",
|
||||
"@babel/plugin-proposal-decorators": "^7.24.6",
|
||||
"@babel/plugin-transform-private-methods": "^7.24.6",
|
||||
"@babel/plugin-transform-private-property-in-object": "^7.24.6",
|
||||
"@babel/plugin-transform-runtime": "^7.24.6",
|
||||
"@babel/preset-env": "^7.24.6",
|
||||
"@babel/preset-typescript": "^7.24.6",
|
||||
"@babel/plugin-proposal-decorators": "^7.24.7",
|
||||
"@babel/plugin-transform-private-methods": "^7.24.7",
|
||||
"@babel/plugin-transform-private-property-in-object": "^7.24.7",
|
||||
"@babel/plugin-transform-runtime": "^7.24.7",
|
||||
"@babel/preset-env": "^7.24.7",
|
||||
"@babel/preset-typescript": "^7.24.7",
|
||||
"@hcaptcha/types": "^1.0.3",
|
||||
"@jeysal/storybook-addon-css-user-preferences": "^0.2.0",
|
||||
"@lit/localize-tools": "^0.7.2",
|
||||
"@rollup/plugin-replace": "^5.0.5",
|
||||
"@rollup/plugin-replace": "^5.0.7",
|
||||
"@spotlightjs/spotlight": "^1.2.17",
|
||||
"@storybook/addon-essentials": "^8.1.5",
|
||||
"@storybook/addon-links": "^8.1.5",
|
||||
"@storybook/addon-essentials": "^8.1.6",
|
||||
"@storybook/addon-links": "^8.1.6",
|
||||
"@storybook/api": "^7.6.17",
|
||||
"@storybook/blocks": "^8.0.8",
|
||||
"@storybook/manager-api": "^8.1.5",
|
||||
"@storybook/web-components": "^8.1.5",
|
||||
"@storybook/web-components-vite": "^8.1.5",
|
||||
"@storybook/manager-api": "^8.1.6",
|
||||
"@storybook/web-components": "^8.1.6",
|
||||
"@storybook/web-components-vite": "^8.1.6",
|
||||
"@trivago/prettier-plugin-sort-imports": "^4.3.0",
|
||||
"@types/chart.js": "^2.9.41",
|
||||
"@types/codemirror": "5.60.15",
|
||||
@ -100,7 +100,7 @@
|
||||
"babel-plugin-tsconfig-paths": "^1.0.3",
|
||||
"chokidar": "^3.6.0",
|
||||
"cross-env": "^7.0.3",
|
||||
"esbuild": "^0.21.4",
|
||||
"esbuild": "^0.21.5",
|
||||
"eslint": "^8.57.0",
|
||||
"eslint-config-google": "^0.14.0",
|
||||
"eslint-plugin-custom-elements": "0.0.8",
|
||||
@ -111,16 +111,16 @@
|
||||
"glob": "^10.4.1",
|
||||
"lit-analyzer": "^2.0.3",
|
||||
"npm-run-all": "^4.1.5",
|
||||
"prettier": "^3.3.0",
|
||||
"prettier": "^3.3.2",
|
||||
"pseudolocale": "^2.0.0",
|
||||
"react": "^18.2.0",
|
||||
"react-dom": "^18.3.1",
|
||||
"rollup-plugin-modify": "^3.0.0",
|
||||
"rollup-plugin-postcss-lit": "^2.1.0",
|
||||
"storybook": "^8.1.5",
|
||||
"storybook": "^8.1.6",
|
||||
"storybook-addon-mock": "^5.0.0",
|
||||
"ts-lit-plugin": "^2.0.2",
|
||||
"tslib": "^2.6.2",
|
||||
"tslib": "^2.6.3",
|
||||
"turnstile-types": "^1.2.1",
|
||||
"typescript": "^5.4.5",
|
||||
"vite-tsconfig-paths": "^4.3.2"
|
||||
|
@ -17,7 +17,6 @@ import "@goauthentik/elements/notifications/NotificationDrawer";
|
||||
import { getURLParam, updateURLParams } from "@goauthentik/elements/router/RouteMatch";
|
||||
import "@goauthentik/elements/router/RouterOutlet";
|
||||
import "@goauthentik/elements/sidebar/Sidebar";
|
||||
import "@goauthentik/elements/sidebar/SidebarItem";
|
||||
|
||||
import { CSSResult, TemplateResult, css, html } from "lit";
|
||||
import { customElement, property, state } from "lit/decorators.js";
|
||||
|
@ -1,5 +1,6 @@
|
||||
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
|
||||
import { EVENT_SIDEBAR_TOGGLE, VERSION } from "@goauthentik/common/constants";
|
||||
import { eventActionLabels } from "@goauthentik/common/labels";
|
||||
import { me } from "@goauthentik/common/users";
|
||||
import { AKElement } from "@goauthentik/elements/Base";
|
||||
import {
|
||||
@ -7,17 +8,63 @@ import {
|
||||
WithCapabilitiesConfig,
|
||||
} from "@goauthentik/elements/Interface/capabilitiesProvider";
|
||||
import { ID_REGEX, SLUG_REGEX, UUID_REGEX } from "@goauthentik/elements/router/Route";
|
||||
import "@goauthentik/elements/sidebar/Sidebar";
|
||||
import {
|
||||
SidebarAttributes,
|
||||
SidebarEntry,
|
||||
SidebarEventHandler,
|
||||
} from "@goauthentik/elements/sidebar/types";
|
||||
import { getRootStyle } from "@goauthentik/elements/utils/getRootStyle";
|
||||
import { spread } from "@open-wc/lit-helpers";
|
||||
|
||||
import { msg, str } from "@lit/localize";
|
||||
import { TemplateResult, html, nothing } from "lit";
|
||||
import { html } from "lit";
|
||||
import { customElement, property, state } from "lit/decorators.js";
|
||||
import { map } from "lit/directives/map.js";
|
||||
|
||||
import { AdminApi, CoreApi, UiThemeEnum, Version } from "@goauthentik/api";
|
||||
import { AdminApi } from "@goauthentik/api";
|
||||
import { CoreApi, Version } from "@goauthentik/api";
|
||||
import type { SessionUser, UserSelf } from "@goauthentik/api";
|
||||
|
||||
import { flowDesignationTable } from "../flows/utils";
|
||||
import ConnectionTypesController from "./SidebarEntries/ConnectionTypesController";
|
||||
import PolicyTypesController from "./SidebarEntries/PolicyTypesController";
|
||||
import PropertyMappingsController from "./SidebarEntries/PropertyMappingsController";
|
||||
import ProviderTypesController from "./SidebarEntries/ProviderTypesController";
|
||||
import SourceTypesController from "./SidebarEntries/SourceTypesController";
|
||||
import StageTypesController from "./SidebarEntries/StageTypesController";
|
||||
|
||||
/**
|
||||
* AdminSidebar
|
||||
*
|
||||
* The AdminSidebar has two responsibilities:
|
||||
*
|
||||
* 1. Control the styling of the sidebar host, specifically when to show it and whether to show
|
||||
* it as an overlay or as a push.
|
||||
* 2. Control what content the sidebar will receive. The sidebar takes a tree, maximally three deep,
|
||||
* of type SidebarEventHandler.
|
||||
*/
|
||||
|
||||
type SidebarUrl = string;
|
||||
|
||||
export type LocalSidebarEntry = [
|
||||
// - null: This entry is not a link.
|
||||
// - string: the url for the entry
|
||||
// - SidebarEventHandler: a function to run if the entry is clicked.
|
||||
SidebarUrl | SidebarEventHandler | null,
|
||||
// The visible text of the entry.
|
||||
string,
|
||||
// Attributes to which the sidebar responds. See the sidebar for details.
|
||||
(SidebarAttributes | string[] | null)?, // eslint-disable-line
|
||||
// Children of the entry
|
||||
LocalSidebarEntry[]?,
|
||||
];
|
||||
|
||||
const localToSidebarEntry = (l: LocalSidebarEntry): SidebarEntry => ({
|
||||
path: l[0],
|
||||
label: l[1],
|
||||
...(l[2] ? { attributes: Array.isArray(l[2]) ? { activeWhen: l[2] } : l[2] } : {}),
|
||||
...(l[3] ? { children: l[3].map(localToSidebarEntry) } : {}),
|
||||
});
|
||||
|
||||
@customElement("ak-admin-sidebar")
|
||||
export class AkAdminSidebar extends WithCapabilitiesConfig(AKElement) {
|
||||
@property({ type: Boolean, reflect: true })
|
||||
@ -29,6 +76,13 @@ export class AkAdminSidebar extends WithCapabilitiesConfig(AKElement) {
|
||||
@state()
|
||||
impersonation: UserSelf["username"] | null = null;
|
||||
|
||||
private connectionTypes = new ConnectionTypesController(this);
|
||||
private policyTypes = new PolicyTypesController(this);
|
||||
private propertyMapper = new PropertyMappingsController(this);
|
||||
private providerTypes = new ProviderTypesController(this);
|
||||
private sourceTypes = new SourceTypesController(this);
|
||||
private stageTypes = new StageTypesController(this);
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
new AdminApi(DEFAULT_CONFIG).adminVersionRetrieve().then((version) => {
|
||||
@ -74,19 +128,6 @@ export class AkAdminSidebar extends WithCapabilitiesConfig(AKElement) {
|
||||
super.disconnectedCallback();
|
||||
}
|
||||
|
||||
render() {
|
||||
return html`
|
||||
<ak-sidebar
|
||||
class="pf-c-page__sidebar ${this.open ? "pf-m-expanded" : "pf-m-collapsed"} ${this
|
||||
.activeTheme === UiThemeEnum.Light
|
||||
? "pf-m-light"
|
||||
: ""}"
|
||||
>
|
||||
${this.renderSidebarItems()}
|
||||
</ak-sidebar>
|
||||
`;
|
||||
}
|
||||
|
||||
updated() {
|
||||
// This is permissible as`:host.classList` is not one of the properties Lit uses as a
|
||||
// scheduling trigger. This sort of shenanigans can trigger an loop, in that it will trigger
|
||||
@ -97,118 +138,86 @@ export class AkAdminSidebar extends WithCapabilitiesConfig(AKElement) {
|
||||
this.classList.add(this.open ? "pf-m-expanded" : "pf-m-collapsed");
|
||||
}
|
||||
|
||||
renderSidebarItems(): TemplateResult {
|
||||
// The second attribute type is of string[] to help with the 'activeWhen' control, which was
|
||||
// commonplace and singular enough to merit its own handler.
|
||||
type SidebarEntry = [
|
||||
path: string | null,
|
||||
label: string,
|
||||
attributes?: Record<string, any> | string[] | null, // eslint-disable-line
|
||||
children?: SidebarEntry[],
|
||||
];
|
||||
|
||||
// prettier-ignore
|
||||
const sidebarContent: SidebarEntry[] = [
|
||||
["/if/user/", msg("User interface"), { "?isAbsoluteLink": true, "?highlight": true }],
|
||||
[null, msg("Dashboards"), { "?expanded": true }, [
|
||||
["/administration/overview", msg("Overview")],
|
||||
["/administration/dashboard/users", msg("User Statistics")],
|
||||
["/administration/system-tasks", msg("System Tasks")]]],
|
||||
[null, msg("Applications"), null, [
|
||||
["/core/applications", msg("Applications"), [`^/core/applications/(?<slug>${SLUG_REGEX})$`]],
|
||||
["/core/providers", msg("Providers"), [`^/core/providers/(?<id>${ID_REGEX})$`]],
|
||||
["/outpost/outposts", msg("Outposts")]]],
|
||||
[null, msg("Events"), null, [
|
||||
["/events/log", msg("Logs"), [`^/events/log/(?<id>${UUID_REGEX})$`]],
|
||||
["/events/rules", msg("Notification Rules")],
|
||||
["/events/transports", msg("Notification Transports")]]],
|
||||
[null, msg("Customization"), null, [
|
||||
["/policy/policies", msg("Policies")],
|
||||
["/core/property-mappings", msg("Property Mappings")],
|
||||
["/blueprints/instances", msg("Blueprints")],
|
||||
["/policy/reputation", msg("Reputation scores")]]],
|
||||
[null, msg("Flows and Stages"), null, [
|
||||
["/flow/flows", msg("Flows"), [`^/flow/flows/(?<slug>${SLUG_REGEX})$`]],
|
||||
["/flow/stages", msg("Stages")],
|
||||
["/flow/stages/prompts", msg("Prompts")]]],
|
||||
[null, msg("Directory"), null, [
|
||||
["/identity/users", msg("Users"), [`^/identity/users/(?<id>${ID_REGEX})$`]],
|
||||
["/identity/groups", msg("Groups"), [`^/identity/groups/(?<id>${UUID_REGEX})$`]],
|
||||
["/identity/roles", msg("Roles"), [`^/identity/roles/(?<id>${UUID_REGEX})$`]],
|
||||
["/core/sources", msg("Federation and Social login"), [`^/core/sources/(?<slug>${SLUG_REGEX})$`]],
|
||||
["/core/tokens", msg("Tokens and App passwords")],
|
||||
["/flow/stages/invitations", msg("Invitations")]]],
|
||||
[null, msg("System"), null, [
|
||||
["/core/brands", msg("Brands")],
|
||||
["/crypto/certificates", msg("Certificates")],
|
||||
["/outpost/integrations", msg("Outpost Integrations")],
|
||||
["/admin/settings", msg("Settings")]]],
|
||||
];
|
||||
|
||||
// Typescript requires the type here to correctly type the recursive path
|
||||
type SidebarRenderer = (_: SidebarEntry) => TemplateResult;
|
||||
|
||||
const renderOneSidebarItem: SidebarRenderer = ([path, label, attributes, children]) => {
|
||||
const properties = Array.isArray(attributes)
|
||||
? { ".activeWhen": attributes }
|
||||
: attributes ?? {};
|
||||
if (path) {
|
||||
properties["path"] = path;
|
||||
}
|
||||
return html`<ak-sidebar-item ${spread(properties)}>
|
||||
${label ? html`<span slot="label">${label}</span>` : nothing}
|
||||
${map(children, renderOneSidebarItem)}
|
||||
</ak-sidebar-item>`;
|
||||
};
|
||||
|
||||
// prettier-ignore
|
||||
return html`
|
||||
${this.renderNewVersionMessage()}
|
||||
${this.renderImpersonationMessage()}
|
||||
${map(sidebarContent, renderOneSidebarItem)}
|
||||
${this.renderEnterpriseMenu()}
|
||||
`;
|
||||
}
|
||||
|
||||
renderNewVersionMessage() {
|
||||
return this.version && this.version !== VERSION
|
||||
? html`
|
||||
<ak-sidebar-item ?highlight=${true}>
|
||||
<span slot="label"
|
||||
>${msg("A newer version of the frontend is available.")}</span
|
||||
>
|
||||
</ak-sidebar-item>
|
||||
`
|
||||
: nothing;
|
||||
}
|
||||
|
||||
renderImpersonationMessage() {
|
||||
get sidebarItems(): SidebarEntry[] {
|
||||
const reload = () =>
|
||||
new CoreApi(DEFAULT_CONFIG).coreUsersImpersonateEndRetrieve().then(() => {
|
||||
window.location.reload();
|
||||
});
|
||||
|
||||
return this.impersonation
|
||||
? html`<ak-sidebar-item ?highlight=${true} @click=${reload}>
|
||||
<span slot="label"
|
||||
>${msg(
|
||||
str`You're currently impersonating ${this.impersonation}. Click to stop.`,
|
||||
)}</span
|
||||
>
|
||||
</ak-sidebar-item>`
|
||||
: nothing;
|
||||
// prettier-ignore
|
||||
const newVersionMessage: LocalSidebarEntry[] =
|
||||
this.version && this.version !== VERSION
|
||||
? [[ "https://goauthentik.io", msg("A newer version of the frontend is available."),
|
||||
{ highlight: true }]]
|
||||
: [];
|
||||
|
||||
// prettier-ignore
|
||||
const impersonationMessage: LocalSidebarEntry[] = this.impersonation
|
||||
? [[reload, msg(str`You're currently impersonating ${this.impersonation}. Click to stop.`)]]
|
||||
: [];
|
||||
|
||||
// prettier-ignore
|
||||
const enterpriseMenu: LocalSidebarEntry[] = this.can(CapabilitiesEnum.IsEnterprise)
|
||||
? [[null, msg("Enterprise"), null, [["/enterprise/licenses", msg("Licenses")]]]]
|
||||
: [];
|
||||
|
||||
const flowTypes: LocalSidebarEntry[] = flowDesignationTable.map(([_designation, label]) => [
|
||||
`/flow/flows;${encodeURIComponent(JSON.stringify({ search: label }))}`,
|
||||
label,
|
||||
]);
|
||||
|
||||
const eventTypes: LocalSidebarEntry[] = eventActionLabels.map(([_action, label]) => [
|
||||
`/events/log;${encodeURIComponent(JSON.stringify({ search: label }))}`,
|
||||
label,
|
||||
]);
|
||||
|
||||
// prettier-ignore
|
||||
const localSidebar: LocalSidebarEntry[] = [
|
||||
...(newVersionMessage),
|
||||
...(impersonationMessage),
|
||||
["/if/user/", msg("User interface"), { isAbsoluteLink: true, highlight: true }],
|
||||
[null, msg("Dashboards"), { expanded: true }, [
|
||||
["/administration/overview", msg("Overview")],
|
||||
["/administration/dashboard/users", msg("User Statistics")],
|
||||
["/administration/system-tasks", msg("System Tasks")]]],
|
||||
[null, msg("Applications"), null, [
|
||||
["/core/applications", msg("Applications"), [`^/core/applications(/(?<slug>${SLUG_REGEX}))?$`]],
|
||||
["/core/providers", msg("Providers"), [`^/core/providers(/(?<id>${ID_REGEX}))?$`], this.providerTypes.entries()],
|
||||
["/outpost/outposts", msg("Outposts")]]],
|
||||
[null, msg("Events"), null, [
|
||||
["/events/log", msg("Logs"), [`^/events/log(/(?<id>${UUID_REGEX}))?$`], eventTypes],
|
||||
["/events/rules", msg("Notification Rules")],
|
||||
["/events/transports", msg("Notification Transports")]]],
|
||||
[null, msg("Customisation"), null, [
|
||||
["/policy/policies", msg("Policies"), null, this.policyTypes.entries()],
|
||||
["/core/property-mappings", msg("Property Mappings"), null, this.propertyMapper.entries()],
|
||||
["/blueprints/instances", msg("Blueprints")],
|
||||
["/policy/reputation", msg("Reputation scores")]]],
|
||||
[null, msg("Flows and Stages"), null, [
|
||||
["/flow/flows", msg("Flows"), [`^/flow/flows(/(?<slug>${SLUG_REGEX}))?$`], flowTypes],
|
||||
["/flow/stages", msg("Stages"), null, this.stageTypes.entries()],
|
||||
["/flow/stages/prompts", msg("Prompts")]]],
|
||||
[null, msg("Directory"), null, [
|
||||
["/identity/users", msg("Users"), [`^/identity/users(/(?<id>${ID_REGEX}))?$`]],
|
||||
["/identity/groups", msg("Groups"), [`^/identity/groups(/(?<id>${UUID_REGEX}))?$`]],
|
||||
["/identity/roles", msg("Roles"), [`^/identity/roles/(?<id>${UUID_REGEX})$`]],
|
||||
["/core/sources", msg("Federation and Social login"), [`^/core/sources(/(?<slug>${SLUG_REGEX}))?$`], this.sourceTypes.entries()],
|
||||
["/core/tokens", msg("Tokens and App passwords")],
|
||||
["/flow/stages/invitations", msg("Invitations")]]],
|
||||
[null, msg("System"), null, [
|
||||
["/core/brands", msg("Brands")],
|
||||
["/crypto/certificates", msg("Certificates")],
|
||||
["/outpost/integrations", msg("Outpost Integrations"), null, this.connectionTypes.entries()],
|
||||
["/admin/settings", msg("Settings")]]],
|
||||
...(enterpriseMenu)
|
||||
];
|
||||
|
||||
return localSidebar.map(localToSidebarEntry);
|
||||
}
|
||||
|
||||
renderEnterpriseMenu() {
|
||||
return this.can(CapabilitiesEnum.IsEnterprise)
|
||||
? html`
|
||||
<ak-sidebar-item>
|
||||
<span slot="label">${msg("Enterprise")}</span>
|
||||
<ak-sidebar-item path="/enterprise/licenses">
|
||||
<span slot="label">${msg("Licenses")}</span>
|
||||
</ak-sidebar-item>
|
||||
</ak-sidebar-item>
|
||||
`
|
||||
: nothing;
|
||||
render() {
|
||||
return html`
|
||||
<ak-sidebar class="pf-c-page__sidebar" .entries=${this.sidebarItems}></ak-sidebar>
|
||||
`;
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,12 @@
|
||||
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
|
||||
|
||||
import { OutpostsApi } from "@goauthentik/api";
|
||||
|
||||
import { createTypesController } from "./GenericTypesController";
|
||||
|
||||
export const ConnectionTypesController = createTypesController(
|
||||
() => new OutpostsApi(DEFAULT_CONFIG).outpostsServiceConnectionsAllTypesList(),
|
||||
"/outpost/integrations",
|
||||
);
|
||||
|
||||
export default ConnectionTypesController;
|
@ -0,0 +1,55 @@
|
||||
import { ReactiveControllerHost } from "lit";
|
||||
|
||||
import { TypeCreate } from "@goauthentik/api";
|
||||
|
||||
import { LocalSidebarEntry } from "../AdminSidebar";
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
type Fetcher = () => Promise<TypeCreate[]>;
|
||||
|
||||
const typeCreateToSidebar = (baseUrl: string, tcreate: TypeCreate[]): LocalSidebarEntry[] =>
|
||||
tcreate.map((t) => [
|
||||
`${baseUrl};${encodeURIComponent(JSON.stringify({ search: t.name }))}`,
|
||||
t.name,
|
||||
]);
|
||||
|
||||
/**
|
||||
* createTypesController
|
||||
*
|
||||
* The Sidebar accesses a number objects of `TypeCreate`, which all have the exact same type, just
|
||||
* different accessors for generating the lists and different paths to which they respond. This
|
||||
* function is a template for a (simple) reactive controller that fetches the data for that type on
|
||||
* construction, then informs the host that the data is available.
|
||||
*/
|
||||
|
||||
/**
|
||||
* TODO (2023-11-17): This function is unlikely to survive in this form. It would be nice if it were more
|
||||
* generic, able to take a converter that can handle more that TypeCreate[] as its inbound argument,
|
||||
* since we need to refine what's displayed and on what the search is conducted.
|
||||
*
|
||||
*/
|
||||
|
||||
export function createTypesController(
|
||||
fetch: Fetcher,
|
||||
path: string,
|
||||
converter = typeCreateToSidebar,
|
||||
) {
|
||||
return class GenericTypesController {
|
||||
createTypes: TypeCreate[] = [];
|
||||
host: ReactiveControllerHost;
|
||||
|
||||
constructor(host: ReactiveControllerHost) {
|
||||
this.host = host;
|
||||
fetch().then((types) => {
|
||||
this.createTypes = types;
|
||||
host.requestUpdate();
|
||||
});
|
||||
}
|
||||
|
||||
entries(): LocalSidebarEntry[] {
|
||||
return converter(path, this.createTypes);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export default createTypesController;
|
@ -0,0 +1,12 @@
|
||||
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
|
||||
|
||||
import { PoliciesApi } from "@goauthentik/api";
|
||||
|
||||
import { createTypesController } from "./GenericTypesController";
|
||||
|
||||
export const PolicyTypesController = createTypesController(
|
||||
() => new PoliciesApi(DEFAULT_CONFIG).policiesAllTypesList(),
|
||||
"/policy/policies",
|
||||
);
|
||||
|
||||
export default PolicyTypesController;
|
@ -0,0 +1,12 @@
|
||||
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
|
||||
|
||||
import { PropertymappingsApi } from "@goauthentik/api";
|
||||
|
||||
import { createTypesController } from "./GenericTypesController";
|
||||
|
||||
export const PropertyMappingsController = createTypesController(
|
||||
() => new PropertymappingsApi(DEFAULT_CONFIG).propertymappingsAllTypesList(),
|
||||
"/core/property-mappings",
|
||||
);
|
||||
|
||||
export default PropertyMappingsController;
|
@ -0,0 +1,12 @@
|
||||
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
|
||||
|
||||
import { ProvidersApi } from "@goauthentik/api";
|
||||
|
||||
import { createTypesController } from "./GenericTypesController";
|
||||
|
||||
export const ProviderTypesController = createTypesController(
|
||||
() => new ProvidersApi(DEFAULT_CONFIG).providersAllTypesList(),
|
||||
"/core/providers",
|
||||
);
|
||||
|
||||
export default ProviderTypesController;
|
@ -0,0 +1,12 @@
|
||||
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
|
||||
|
||||
import { SourcesApi } from "@goauthentik/api";
|
||||
|
||||
import { createTypesController } from "./GenericTypesController";
|
||||
|
||||
export const SourceTypesController = createTypesController(
|
||||
() => new SourcesApi(DEFAULT_CONFIG).sourcesAllTypesList(),
|
||||
"/core/sources",
|
||||
);
|
||||
|
||||
export default SourceTypesController;
|
@ -0,0 +1,12 @@
|
||||
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
|
||||
|
||||
import { StagesApi } from "@goauthentik/api";
|
||||
|
||||
import { createTypesController } from "./GenericTypesController";
|
||||
|
||||
export const StageTypesController = createTypesController(
|
||||
() => new StagesApi(DEFAULT_CONFIG).stagesAllTypesList(),
|
||||
"/flow/stages",
|
||||
);
|
||||
|
||||
export default StageTypesController;
|
@ -6,40 +6,33 @@ export function RenderFlowOption(flow: Flow): string {
|
||||
return `${flow.slug} (${flow.name})`;
|
||||
}
|
||||
|
||||
type FlowDesignationPair = [FlowDesignationEnum, string];
|
||||
|
||||
export const flowDesignationTable: FlowDesignationPair[] = [
|
||||
[FlowDesignationEnum.Authentication, msg("Authentication")],
|
||||
[FlowDesignationEnum.Authorization, msg("Authorization")],
|
||||
[FlowDesignationEnum.Enrollment, msg("Enrollment")],
|
||||
[FlowDesignationEnum.Invalidation, msg("Invalidation")],
|
||||
[FlowDesignationEnum.Recovery, msg("Recovery")],
|
||||
[FlowDesignationEnum.StageConfiguration, msg("Stage Configuration")],
|
||||
[FlowDesignationEnum.Unenrollment, msg("Unenrollment")],
|
||||
];
|
||||
|
||||
// prettier-ignore
|
||||
const flowDesignations = new Map(flowDesignationTable);
|
||||
|
||||
export function DesignationToLabel(designation: FlowDesignationEnum): string {
|
||||
switch (designation) {
|
||||
case FlowDesignationEnum.Authentication:
|
||||
return msg("Authentication");
|
||||
case FlowDesignationEnum.Authorization:
|
||||
return msg("Authorization");
|
||||
case FlowDesignationEnum.Enrollment:
|
||||
return msg("Enrollment");
|
||||
case FlowDesignationEnum.Invalidation:
|
||||
return msg("Invalidation");
|
||||
case FlowDesignationEnum.Recovery:
|
||||
return msg("Recovery");
|
||||
case FlowDesignationEnum.StageConfiguration:
|
||||
return msg("Stage Configuration");
|
||||
case FlowDesignationEnum.Unenrollment:
|
||||
return msg("Unenrollment");
|
||||
case FlowDesignationEnum.UnknownDefaultOpenApi:
|
||||
return msg("Unknown designation");
|
||||
}
|
||||
return flowDesignations.get(designation) ?? msg("Unknown designation");
|
||||
}
|
||||
|
||||
const layoutToLabel = new Map<FlowLayoutEnum, string>([
|
||||
[FlowLayoutEnum.Stacked, msg("Stacked")],
|
||||
[FlowLayoutEnum.ContentLeft, msg("Content left")],
|
||||
[FlowLayoutEnum.ContentRight, msg("Content right")],
|
||||
[FlowLayoutEnum.SidebarLeft, msg("Sidebar left")],
|
||||
[FlowLayoutEnum.SidebarRight, msg("Sidebar right")],
|
||||
]);
|
||||
|
||||
export function LayoutToLabel(layout: FlowLayoutEnum): string {
|
||||
switch (layout) {
|
||||
case FlowLayoutEnum.Stacked:
|
||||
return msg("Stacked");
|
||||
case FlowLayoutEnum.ContentLeft:
|
||||
return msg("Content left");
|
||||
case FlowLayoutEnum.ContentRight:
|
||||
return msg("Content right");
|
||||
case FlowLayoutEnum.SidebarLeft:
|
||||
return msg("Sidebar left");
|
||||
case FlowLayoutEnum.SidebarRight:
|
||||
return msg("Sidebar right");
|
||||
case FlowLayoutEnum.UnknownDefaultOpenApi:
|
||||
return msg("Unknown layout");
|
||||
}
|
||||
return layoutToLabel.get(layout) ?? msg("Unknown layout");
|
||||
}
|
||||
|
@ -126,6 +126,7 @@ export class PolicyTestForm extends Form<PropertyMappingTestRequest> {
|
||||
renderForm(): TemplateResult {
|
||||
return html`<ak-form-element-horizontal label=${msg("User")} name="user">
|
||||
<ak-search-select
|
||||
blankable
|
||||
.fetchObjects=${async (query?: string): Promise<User[]> => {
|
||||
const args: CoreUsersListRequest = {
|
||||
ordering: "username",
|
||||
@ -153,6 +154,7 @@ export class PolicyTestForm extends Form<PropertyMappingTestRequest> {
|
||||
</ak-form-element-horizontal>
|
||||
<ak-form-element-horizontal label=${msg("Group")} name="group">
|
||||
<ak-search-select
|
||||
blankable
|
||||
.fetchObjects=${async (query?: string): Promise<Group[]> => {
|
||||
const args: CoreGroupsListRequest = {
|
||||
ordering: "name",
|
||||
|
@ -1,5 +1,6 @@
|
||||
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
|
||||
import { uiConfig } from "@goauthentik/common/ui/config";
|
||||
import "@goauthentik/elements/forms/DeleteBulkForm";
|
||||
import { PaginatedResponse, Table, TableColumn } from "@goauthentik/elements/table/Table";
|
||||
|
||||
import { msg } from "@lit/localize";
|
||||
@ -19,6 +20,26 @@ export class GoogleWorkspaceProviderGroupList extends Table<GoogleWorkspaceProvi
|
||||
return true;
|
||||
}
|
||||
|
||||
checkbox = true;
|
||||
clearOnRefresh = true;
|
||||
|
||||
renderToolbarSelected(): TemplateResult {
|
||||
const disabled = this.selectedElements.length < 1;
|
||||
return html`<ak-forms-delete-bulk
|
||||
objectLabel=${msg("Google Workspace Group(s)")}
|
||||
.objects=${this.selectedElements}
|
||||
.delete=${(item: GoogleWorkspaceProviderGroup) => {
|
||||
return new ProvidersApi(DEFAULT_CONFIG).providersGoogleWorkspaceGroupsDestroy({
|
||||
id: item.id,
|
||||
});
|
||||
}}
|
||||
>
|
||||
<button ?disabled=${disabled} slot="trigger" class="pf-c-button pf-m-danger">
|
||||
${msg("Delete")}
|
||||
</button>
|
||||
</ak-forms-delete-bulk>`;
|
||||
}
|
||||
|
||||
async apiEndpoint(page: number): Promise<PaginatedResponse<GoogleWorkspaceProviderGroup>> {
|
||||
return new ProvidersApi(DEFAULT_CONFIG).providersGoogleWorkspaceGroupsList({
|
||||
page: page,
|
||||
|
@ -1,5 +1,6 @@
|
||||
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
|
||||
import { uiConfig } from "@goauthentik/common/ui/config";
|
||||
import "@goauthentik/elements/forms/DeleteBulkForm";
|
||||
import { PaginatedResponse, Table, TableColumn } from "@goauthentik/elements/table/Table";
|
||||
|
||||
import { msg } from "@lit/localize";
|
||||
@ -19,6 +20,26 @@ export class GoogleWorkspaceProviderUserList extends Table<GoogleWorkspaceProvid
|
||||
|
||||
expandable = true;
|
||||
|
||||
checkbox = true;
|
||||
clearOnRefresh = true;
|
||||
|
||||
renderToolbarSelected(): TemplateResult {
|
||||
const disabled = this.selectedElements.length < 1;
|
||||
return html`<ak-forms-delete-bulk
|
||||
objectLabel=${msg("Google Workspace User(s)")}
|
||||
.objects=${this.selectedElements}
|
||||
.delete=${(item: GoogleWorkspaceProviderUser) => {
|
||||
return new ProvidersApi(DEFAULT_CONFIG).providersGoogleWorkspaceUsersDestroy({
|
||||
id: item.id,
|
||||
});
|
||||
}}
|
||||
>
|
||||
<button ?disabled=${disabled} slot="trigger" class="pf-c-button pf-m-danger">
|
||||
${msg("Delete")}
|
||||
</button>
|
||||
</ak-forms-delete-bulk>`;
|
||||
}
|
||||
|
||||
async apiEndpoint(page: number): Promise<PaginatedResponse<GoogleWorkspaceProviderUser>> {
|
||||
return new ProvidersApi(DEFAULT_CONFIG).providersGoogleWorkspaceUsersList({
|
||||
page: page,
|
||||
|
@ -1,5 +1,6 @@
|
||||
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
|
||||
import { uiConfig } from "@goauthentik/common/ui/config";
|
||||
import "@goauthentik/elements/forms/DeleteBulkForm";
|
||||
import { PaginatedResponse, Table, TableColumn } from "@goauthentik/elements/table/Table";
|
||||
|
||||
import { msg } from "@lit/localize";
|
||||
@ -19,6 +20,23 @@ export class MicrosoftEntraProviderGroupList extends Table<MicrosoftEntraProvide
|
||||
return true;
|
||||
}
|
||||
|
||||
renderToolbarSelected(): TemplateResult {
|
||||
const disabled = this.selectedElements.length < 1;
|
||||
return html`<ak-forms-delete-bulk
|
||||
objectLabel=${msg("Microsoft Entra Group(s)")}
|
||||
.objects=${this.selectedElements}
|
||||
.delete=${(item: MicrosoftEntraProviderGroup) => {
|
||||
return new ProvidersApi(DEFAULT_CONFIG).providersMicrosoftEntraGroupsDestroy({
|
||||
id: item.id,
|
||||
});
|
||||
}}
|
||||
>
|
||||
<button ?disabled=${disabled} slot="trigger" class="pf-c-button pf-m-danger">
|
||||
${msg("Delete")}
|
||||
</button>
|
||||
</ak-forms-delete-bulk>`;
|
||||
}
|
||||
|
||||
async apiEndpoint(page: number): Promise<PaginatedResponse<MicrosoftEntraProviderGroup>> {
|
||||
return new ProvidersApi(DEFAULT_CONFIG).providersMicrosoftEntraGroupsList({
|
||||
page: page,
|
||||
|
@ -1,5 +1,6 @@
|
||||
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
|
||||
import { uiConfig } from "@goauthentik/common/ui/config";
|
||||
import "@goauthentik/elements/forms/DeleteBulkForm";
|
||||
import { PaginatedResponse, Table, TableColumn } from "@goauthentik/elements/table/Table";
|
||||
|
||||
import { msg } from "@lit/localize";
|
||||
@ -19,6 +20,26 @@ export class MicrosoftEntraProviderUserList extends Table<MicrosoftEntraProvider
|
||||
return true;
|
||||
}
|
||||
|
||||
checkbox = true;
|
||||
clearOnRefresh = true;
|
||||
|
||||
renderToolbarSelected(): TemplateResult {
|
||||
const disabled = this.selectedElements.length < 1;
|
||||
return html`<ak-forms-delete-bulk
|
||||
objectLabel=${msg("Microsoft Entra User(s)")}
|
||||
.objects=${this.selectedElements}
|
||||
.delete=${(item: MicrosoftEntraProviderUser) => {
|
||||
return new ProvidersApi(DEFAULT_CONFIG).providersMicrosoftEntraUsersDestroy({
|
||||
id: item.id,
|
||||
});
|
||||
}}
|
||||
>
|
||||
<button ?disabled=${disabled} slot="trigger" class="pf-c-button pf-m-danger">
|
||||
${msg("Delete")}
|
||||
</button>
|
||||
</ak-forms-delete-bulk>`;
|
||||
}
|
||||
|
||||
async apiEndpoint(page: number): Promise<PaginatedResponse<MicrosoftEntraProviderUser>> {
|
||||
return new ProvidersApi(DEFAULT_CONFIG).providersMicrosoftEntraUsersList({
|
||||
page: page,
|
||||
|
63
web/src/admin/providers/scim/SCIMProviderGroupList.ts
Normal file
63
web/src/admin/providers/scim/SCIMProviderGroupList.ts
Normal file
@ -0,0 +1,63 @@
|
||||
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
|
||||
import { uiConfig } from "@goauthentik/common/ui/config";
|
||||
import "@goauthentik/elements/forms/DeleteBulkForm";
|
||||
import { PaginatedResponse, Table, TableColumn } from "@goauthentik/elements/table/Table";
|
||||
|
||||
import { msg } from "@lit/localize";
|
||||
import { TemplateResult, html } from "lit";
|
||||
import { customElement, property } from "lit/decorators.js";
|
||||
|
||||
import { ProvidersApi, SCIMProviderGroup } from "@goauthentik/api";
|
||||
|
||||
@customElement("ak-provider-scim-groups-list")
|
||||
export class SCIMProviderGroupList extends Table<SCIMProviderGroup> {
|
||||
@property({ type: Number })
|
||||
providerId?: number;
|
||||
|
||||
searchEnabled(): boolean {
|
||||
return true;
|
||||
}
|
||||
|
||||
checkbox = true;
|
||||
clearOnRefresh = true;
|
||||
|
||||
renderToolbarSelected(): TemplateResult {
|
||||
const disabled = this.selectedElements.length < 1;
|
||||
return html`<ak-forms-delete-bulk
|
||||
objectLabel=${msg("SCIM Group(s)")}
|
||||
.objects=${this.selectedElements}
|
||||
.delete=${(item: SCIMProviderGroup) => {
|
||||
return new ProvidersApi(DEFAULT_CONFIG).providersScimGroupsDestroy({
|
||||
id: item.id,
|
||||
});
|
||||
}}
|
||||
>
|
||||
<button ?disabled=${disabled} slot="trigger" class="pf-c-button pf-m-danger">
|
||||
${msg("Delete")}
|
||||
</button>
|
||||
</ak-forms-delete-bulk>`;
|
||||
}
|
||||
|
||||
async apiEndpoint(page: number): Promise<PaginatedResponse<SCIMProviderGroup>> {
|
||||
return new ProvidersApi(DEFAULT_CONFIG).providersScimGroupsList({
|
||||
page: page,
|
||||
pageSize: (await uiConfig()).pagination.perPage,
|
||||
ordering: this.order,
|
||||
search: this.search || "",
|
||||
providerId: this.providerId,
|
||||
});
|
||||
}
|
||||
|
||||
columns(): TableColumn[] {
|
||||
return [new TableColumn(msg("Name")), new TableColumn(msg("ID"))];
|
||||
}
|
||||
|
||||
row(item: SCIMProviderGroup): TemplateResult[] {
|
||||
return [
|
||||
html`<a href="#/identity/groups/${item.groupObj.pk}">
|
||||
<div>${item.groupObj.name}</div>
|
||||
</a>`,
|
||||
html`${item.id}`,
|
||||
];
|
||||
}
|
||||
}
|
64
web/src/admin/providers/scim/SCIMProviderUserList.ts
Normal file
64
web/src/admin/providers/scim/SCIMProviderUserList.ts
Normal file
@ -0,0 +1,64 @@
|
||||
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
|
||||
import { uiConfig } from "@goauthentik/common/ui/config";
|
||||
import "@goauthentik/elements/forms/DeleteBulkForm";
|
||||
import { PaginatedResponse, Table, TableColumn } from "@goauthentik/elements/table/Table";
|
||||
|
||||
import { msg } from "@lit/localize";
|
||||
import { TemplateResult, html } from "lit";
|
||||
import { customElement, property } from "lit/decorators.js";
|
||||
|
||||
import { ProvidersApi, SCIMProviderUser } from "@goauthentik/api";
|
||||
|
||||
@customElement("ak-provider-scim-users-list")
|
||||
export class SCIMProviderUserList extends Table<SCIMProviderUser> {
|
||||
@property({ type: Number })
|
||||
providerId?: number;
|
||||
|
||||
searchEnabled(): boolean {
|
||||
return true;
|
||||
}
|
||||
|
||||
checkbox = true;
|
||||
clearOnRefresh = true;
|
||||
|
||||
renderToolbarSelected(): TemplateResult {
|
||||
const disabled = this.selectedElements.length < 1;
|
||||
return html`<ak-forms-delete-bulk
|
||||
objectLabel=${msg("SCIM User(s)")}
|
||||
.objects=${this.selectedElements}
|
||||
.delete=${(item: SCIMProviderUser) => {
|
||||
return new ProvidersApi(DEFAULT_CONFIG).providersScimUsersDestroy({
|
||||
id: item.id,
|
||||
});
|
||||
}}
|
||||
>
|
||||
<button ?disabled=${disabled} slot="trigger" class="pf-c-button pf-m-danger">
|
||||
${msg("Delete")}
|
||||
</button>
|
||||
</ak-forms-delete-bulk>`;
|
||||
}
|
||||
|
||||
async apiEndpoint(page: number): Promise<PaginatedResponse<SCIMProviderUser>> {
|
||||
return new ProvidersApi(DEFAULT_CONFIG).providersScimUsersList({
|
||||
page: page,
|
||||
pageSize: (await uiConfig()).pagination.perPage,
|
||||
ordering: this.order,
|
||||
search: this.search || "",
|
||||
providerId: this.providerId,
|
||||
});
|
||||
}
|
||||
|
||||
columns(): TableColumn[] {
|
||||
return [new TableColumn(msg("Username")), new TableColumn(msg("ID"))];
|
||||
}
|
||||
|
||||
row(item: SCIMProviderUser): TemplateResult[] {
|
||||
return [
|
||||
html`<a href="#/identity/users/${item.userObj.pk}">
|
||||
<div>${item.userObj.username}</div>
|
||||
<small>${item.userObj.name}</small>
|
||||
</a>`,
|
||||
html`${item.id}`,
|
||||
];
|
||||
}
|
||||
}
|
@ -1,4 +1,6 @@
|
||||
import "@goauthentik/admin/providers/scim/SCIMProviderForm";
|
||||
import "@goauthentik/admin/providers/scim/SCIMProviderGroupList";
|
||||
import "@goauthentik/admin/providers/scim/SCIMProviderUserList";
|
||||
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
|
||||
import { EVENT_REFRESH } from "@goauthentik/common/constants";
|
||||
import "@goauthentik/components/events/ObjectChangelog";
|
||||
@ -102,6 +104,28 @@ export class SCIMProviderViewPage extends AKElement {
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
<section
|
||||
slot="page-users"
|
||||
data-tab-title="${msg("Provisioned Users")}"
|
||||
class="pf-c-page__main-section pf-m-no-padding-mobile"
|
||||
>
|
||||
<div class="pf-l-grid pf-m-gutter">
|
||||
<ak-provider-scim-users-list
|
||||
providerId=${this.provider.pk}
|
||||
></ak-provider-scim-users-list>
|
||||
</div>
|
||||
</section>
|
||||
<section
|
||||
slot="page-groups"
|
||||
data-tab-title="${msg("Provisioned Groups")}"
|
||||
class="pf-c-page__main-section pf-m-no-padding-mobile"
|
||||
>
|
||||
<div class="pf-l-grid pf-m-gutter">
|
||||
<ak-provider-scim-groups-list
|
||||
providerId=${this.provider.pk}
|
||||
></ak-provider-scim-groups-list>
|
||||
</div>
|
||||
</section>
|
||||
<ak-rbac-object-permission-page
|
||||
slot="page-permissions"
|
||||
data-tab-title="${msg("Permissions")}"
|
||||
|
@ -1,5 +1,7 @@
|
||||
import { BaseStageForm } from "@goauthentik/admin/stages/BaseStageForm";
|
||||
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
|
||||
import { first } from "@goauthentik/common/utils";
|
||||
import "@goauthentik/components/ak-number-input";
|
||||
import "@goauthentik/elements/forms/FormGroup";
|
||||
import "@goauthentik/elements/forms/HorizontalFormElement";
|
||||
|
||||
@ -78,6 +80,40 @@ export class CaptchaStageForm extends BaseStageForm<CaptchaStage> {
|
||||
)}
|
||||
</p>
|
||||
</ak-form-element-horizontal>
|
||||
<ak-number-input
|
||||
label=${msg("Score minimum threshold")}
|
||||
required
|
||||
name="scoreMinThreshold"
|
||||
value="${ifDefined(this.instance?.scoreMinThreshold || 0.5)}"
|
||||
help=${msg("Minimum required score to allow continuing")}
|
||||
></ak-number-input>
|
||||
<ak-number-input
|
||||
label=${msg("Score maximum threshold")}
|
||||
required
|
||||
name="scoreMaxThreshold"
|
||||
value="${ifDefined(this.instance?.scoreMaxThreshold || -1)}"
|
||||
help=${msg("Maximum allowed score to allow continuing")}
|
||||
></ak-number-input>
|
||||
<ak-form-element-horizontal name="errorOnInvalidScore">
|
||||
<label class="pf-c-switch">
|
||||
<input
|
||||
class="pf-c-switch__input"
|
||||
type="checkbox"
|
||||
?checked=${first(this.instance?.errorOnInvalidScore, true)}
|
||||
/>
|
||||
<span class="pf-c-switch__toggle">
|
||||
<span class="pf-c-switch__toggle-icon">
|
||||
<i class="fas fa-check" aria-hidden="true"></i>
|
||||
</span>
|
||||
</span>
|
||||
<span class="pf-c-switch__label">${msg("Error on invalid score")}</span>
|
||||
</label>
|
||||
<p class="pf-c-form__helper-text">
|
||||
${msg(
|
||||
"When enabled and the resultant score is outside the threshold, the user will not be able to continue. When disabled, the user will be able to continue and the score can be used in policies to customize further stages.",
|
||||
)}
|
||||
</p>
|
||||
</ak-form-element-horizontal>
|
||||
</div>
|
||||
</ak-form-group>
|
||||
<ak-form-group>
|
||||
|
@ -2,6 +2,8 @@ import { msg } from "@lit/localize";
|
||||
|
||||
import { Device, EventActions, IntentEnum, SeverityEnum, UserTypeEnum } from "@goauthentik/api";
|
||||
|
||||
type Pair<T> = [T, string];
|
||||
|
||||
/* Various tables in the API for which we need to supply labels */
|
||||
|
||||
export const intentEnumToLabel = new Map<IntentEnum, string>([
|
||||
@ -14,7 +16,7 @@ export const intentEnumToLabel = new Map<IntentEnum, string>([
|
||||
|
||||
export const intentToLabel = (intent: IntentEnum) => intentEnumToLabel.get(intent);
|
||||
|
||||
export const eventActionToLabel = new Map<EventActions | undefined, string>([
|
||||
export const eventActionLabels: Pair<EventActions>[] = [
|
||||
[EventActions.Login, msg("Login")],
|
||||
[EventActions.LoginFailed, msg("Failed login")],
|
||||
[EventActions.Logout, msg("Logout")],
|
||||
@ -43,7 +45,9 @@ export const eventActionToLabel = new Map<EventActions | undefined, string>([
|
||||
[EventActions.ModelDeleted, msg("Model deleted")],
|
||||
[EventActions.EmailSent, msg("Email sent")],
|
||||
[EventActions.UpdateAvailable, msg("Update available")],
|
||||
]);
|
||||
];
|
||||
|
||||
export const eventActionToLabel = new Map<EventActions | undefined, string>(eventActionLabels);
|
||||
|
||||
export const actionToLabel = (action?: EventActions): string =>
|
||||
eventActionToLabel.get(action) ?? action ?? "";
|
||||
|
56
web/src/elements/sidebar/Sidebar.css.ts
Normal file
56
web/src/elements/sidebar/Sidebar.css.ts
Normal file
@ -0,0 +1,56 @@
|
||||
import { css } from "lit";
|
||||
|
||||
import PFNav from "@patternfly/patternfly/components/Nav/nav.css";
|
||||
import PFPage from "@patternfly/patternfly/components/Page/page.css";
|
||||
import PFBase from "@patternfly/patternfly/patternfly-base.css";
|
||||
|
||||
export const sidebarStyles = [
|
||||
PFBase,
|
||||
PFPage,
|
||||
PFNav,
|
||||
css`
|
||||
:host {
|
||||
z-index: 100;
|
||||
}
|
||||
.pf-c-nav__link.pf-m-current::after,
|
||||
.pf-c-nav__link.pf-m-current:hover::after,
|
||||
.pf-c-nav__item.pf-m-current:not(.pf-m-expanded) .pf-c-nav__link::after {
|
||||
--pf-c-nav__link--m-current--after--BorderColor: #fd4b2d;
|
||||
}
|
||||
:host([theme="light"]) {
|
||||
border-right-color: transparent !important;
|
||||
}
|
||||
|
||||
.pf-c-nav__section + .pf-c-nav__section {
|
||||
--pf-c-nav__section--section--MarginTop: var(--pf-global--spacer--sm);
|
||||
}
|
||||
.pf-c-nav__list .sidebar-brand {
|
||||
max-height: 82px;
|
||||
margin-bottom: -0.5rem;
|
||||
}
|
||||
nav {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
max-height: 100vh;
|
||||
height: 100%;
|
||||
overflow-y: hidden;
|
||||
}
|
||||
|
||||
ak-sidebar-items {
|
||||
flex-grow: 1;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.pf-c-nav__link {
|
||||
--pf-c-nav__link--PaddingTop: 0.5rem;
|
||||
--pf-c-nav__link--PaddingRight: 0.5rem;
|
||||
--pf-c-nav__link--PaddingBottom: 0.5rem;
|
||||
}
|
||||
.pf-c-nav__section-title {
|
||||
font-size: 12px;
|
||||
}
|
||||
.pf-c-nav__item {
|
||||
--pf-c-nav__item--MarginTop: 0px;
|
||||
}
|
||||
`,
|
||||
];
|
@ -1,79 +1,32 @@
|
||||
import { AKElement } from "@goauthentik/elements/Base";
|
||||
import "@goauthentik/elements/sidebar/SidebarBrand";
|
||||
import "@goauthentik/elements/sidebar/SidebarItems";
|
||||
import "@goauthentik/elements/sidebar/SidebarUser";
|
||||
|
||||
import { CSSResult, TemplateResult, css, html } from "lit";
|
||||
import { customElement } from "lit/decorators.js";
|
||||
|
||||
import PFNav from "@patternfly/patternfly/components/Nav/nav.css";
|
||||
import PFPage from "@patternfly/patternfly/components/Page/page.css";
|
||||
import PFBase from "@patternfly/patternfly/patternfly-base.css";
|
||||
import { html } from "lit";
|
||||
import { customElement, property } from "lit/decorators.js";
|
||||
|
||||
import { UiThemeEnum } from "@goauthentik/api";
|
||||
|
||||
import { sidebarStyles } from "./Sidebar.css.js";
|
||||
import type { SidebarEntry } from "./types";
|
||||
|
||||
@customElement("ak-sidebar")
|
||||
export class Sidebar extends AKElement {
|
||||
static get styles(): CSSResult[] {
|
||||
return [
|
||||
PFBase,
|
||||
PFPage,
|
||||
PFNav,
|
||||
css`
|
||||
:host {
|
||||
z-index: 100;
|
||||
}
|
||||
.pf-c-nav__link.pf-m-current::after,
|
||||
.pf-c-nav__link.pf-m-current:hover::after,
|
||||
.pf-c-nav__item.pf-m-current:not(.pf-m-expanded) .pf-c-nav__link::after {
|
||||
--pf-c-nav__link--m-current--after--BorderColor: #fd4b2d;
|
||||
}
|
||||
:host([theme="light"]) {
|
||||
border-right-color: transparent !important;
|
||||
}
|
||||
@property({ type: Array })
|
||||
entries: SidebarEntry[] = [];
|
||||
|
||||
.pf-c-nav__section + .pf-c-nav__section {
|
||||
--pf-c-nav__section--section--MarginTop: var(--pf-global--spacer--sm);
|
||||
}
|
||||
.pf-c-nav__list .sidebar-brand {
|
||||
max-height: 82px;
|
||||
margin-bottom: -0.5rem;
|
||||
}
|
||||
nav {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
max-height: 100vh;
|
||||
height: 100%;
|
||||
overflow-y: hidden;
|
||||
}
|
||||
.pf-c-nav__list {
|
||||
flex-grow: 1;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.pf-c-nav__link {
|
||||
--pf-c-nav__link--PaddingTop: 0.5rem;
|
||||
--pf-c-nav__link--PaddingRight: 0.5rem;
|
||||
--pf-c-nav__link--PaddingBottom: 0.5rem;
|
||||
}
|
||||
.pf-c-nav__section-title {
|
||||
font-size: 12px;
|
||||
}
|
||||
.pf-c-nav__item {
|
||||
--pf-c-nav__item--MarginTop: 0px;
|
||||
}
|
||||
`,
|
||||
];
|
||||
static get styles() {
|
||||
return sidebarStyles;
|
||||
}
|
||||
|
||||
render(): TemplateResult {
|
||||
render() {
|
||||
return html`<nav
|
||||
class="pf-c-nav ${this.activeTheme === UiThemeEnum.Light ? "pf-m-light" : ""}"
|
||||
aria-label="Global"
|
||||
>
|
||||
<ak-sidebar-brand></ak-sidebar-brand>
|
||||
<ul class="pf-c-nav__list">
|
||||
<slot></slot>
|
||||
</ul>
|
||||
<ak-sidebar-items .entries=${this.entries}></ak-sidebar-items>
|
||||
<ak-sidebar-user></ak-sidebar-user>
|
||||
</nav>`;
|
||||
}
|
||||
|
86
web/src/elements/sidebar/SidebarItems.css.ts
Normal file
86
web/src/elements/sidebar/SidebarItems.css.ts
Normal file
@ -0,0 +1,86 @@
|
||||
import { css } from "lit";
|
||||
|
||||
import PFNav from "@patternfly/patternfly/components/Nav/nav.css";
|
||||
import PFPage from "@patternfly/patternfly/components/Page/page.css";
|
||||
import PFBase from "@patternfly/patternfly/patternfly-base.css";
|
||||
|
||||
export const sidebarItemStyles = [
|
||||
PFBase,
|
||||
PFPage,
|
||||
PFNav,
|
||||
css`
|
||||
:host {
|
||||
z-index: 100;
|
||||
box-shadow: none !important;
|
||||
}
|
||||
|
||||
.highlighted {
|
||||
background-color: var(--ak-accent);
|
||||
margin: 16px;
|
||||
}
|
||||
|
||||
.highlighted .pf-c-nav__link {
|
||||
padding-left: 0.5rem;
|
||||
}
|
||||
|
||||
.pf-c-nav__link.pf-m-current::after,
|
||||
.pf-c-nav__link.pf-m-current:hover::after,
|
||||
.pf-c-nav__item.pf-m-current:not(.pf-m-expanded) .pf-c-nav__link::after {
|
||||
--pf-c-nav__link--m-current--after--BorderColor: #fd4b2d;
|
||||
}
|
||||
|
||||
.pf-c-nav__item .pf-c-nav__item::before {
|
||||
border-bottom-width: 0;
|
||||
}
|
||||
|
||||
.pf-c-nav__section + .pf-c-nav__section {
|
||||
--pf-c-nav__section--section--MarginTop: var(--pf-global--spacer--sm);
|
||||
}
|
||||
.pf-c-nav__list .sidebar-brand {
|
||||
max-height: 82px;
|
||||
margin-bottom: -0.5rem;
|
||||
}
|
||||
.pf-c-nav__toggle {
|
||||
width: calc(var(--pf-c-nav__toggle--FontSize) + calc(2 * var(--pf-global--spacer--md)));
|
||||
}
|
||||
|
||||
nav {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
max-height: 100vh;
|
||||
height: 100%;
|
||||
overflow-y: hidden;
|
||||
}
|
||||
.pf-c-nav__list {
|
||||
flex: 1 0 1fr;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.pf-c-nav__link {
|
||||
--pf-c-nav__link--PaddingTop: 0.5rem;
|
||||
--pf-c-nav__link--PaddingRight: 0.5rem;
|
||||
--pf-c-nav__link--PaddingBottom: 0.5rem;
|
||||
}
|
||||
|
||||
.pf-c-nav__link a {
|
||||
flex: 1 0 max-content;
|
||||
color: var(--pf-c-nav__link--Color);
|
||||
}
|
||||
|
||||
a.pf-c-nav__link:hover {
|
||||
color: var(--pf-c-nav__link--Color);
|
||||
text-decoration: var(--pf-global--link--TextDecoration--hover);
|
||||
}
|
||||
|
||||
.pf-c-nav__section-title {
|
||||
font-size: 12px;
|
||||
}
|
||||
.pf-c-nav__item {
|
||||
--pf-c-nav__item--MarginTop: 0px;
|
||||
}
|
||||
|
||||
.pf-c-nav__toggle-icon {
|
||||
padding: var(--pf-global--spacer--sm) var(--pf-global--spacer--md);
|
||||
}
|
||||
`,
|
||||
];
|
247
web/src/elements/sidebar/SidebarItems.ts
Normal file
247
web/src/elements/sidebar/SidebarItems.ts
Normal file
@ -0,0 +1,247 @@
|
||||
import { ROUTE_SEPARATOR } from "@goauthentik/common/constants";
|
||||
import { AKElement } from "@goauthentik/elements/Base";
|
||||
import { findTable } from "@goauthentik/elements/table/TablePage";
|
||||
|
||||
import { TemplateResult, html, nothing } from "lit";
|
||||
import { customElement, property, state } from "lit/decorators.js";
|
||||
import { classMap } from "lit/directives/class-map.js";
|
||||
import { map } from "lit/directives/map.js";
|
||||
|
||||
import { UiThemeEnum } from "@goauthentik/api";
|
||||
|
||||
import { sidebarItemStyles } from "./SidebarItems.css.js";
|
||||
import type { SidebarEntry } from "./types";
|
||||
import { entryKey, findMatchForNavbarUrl, makeParentMap } from "./utils";
|
||||
|
||||
/**
|
||||
* Display the sidebar item tree.
|
||||
*
|
||||
* Along with the `reclick()` complaint down below, the other thing I dislike about this design is
|
||||
* that it's effectively two different programs glued together. The first responds to the `click`
|
||||
* and performs the navigation, which either triggers the router or triggers a new search on the
|
||||
* existing view. The second responds to the navigation change event when the URL is changed by the
|
||||
* navigation event, at which point it figures out which entry to highlight as "current," which
|
||||
* causes the re-render.
|
||||
*/
|
||||
|
||||
@customElement("ak-sidebar-items")
|
||||
export class SidebarItems extends AKElement {
|
||||
static get styles() {
|
||||
return sidebarItemStyles;
|
||||
}
|
||||
|
||||
@property({ type: Array })
|
||||
entries: SidebarEntry[] = [];
|
||||
|
||||
expanded: Set<string> = new Set();
|
||||
|
||||
@state()
|
||||
current = "";
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
this.renderItem = this.renderItem.bind(this);
|
||||
this.toggleExpand = this.toggleExpand.bind(this);
|
||||
this.onHashChange = this.onHashChange.bind(this);
|
||||
this.reclick = this.reclick.bind(this);
|
||||
}
|
||||
|
||||
connectedCallback() {
|
||||
super.connectedCallback();
|
||||
this.onHashChange();
|
||||
window.addEventListener("hashchange", this.onHashChange);
|
||||
}
|
||||
|
||||
disconnectedCallback() {
|
||||
window.removeEventListener("hashchange", this.onHashChange);
|
||||
super.disconnectedCallback();
|
||||
}
|
||||
|
||||
expandParents(entry: SidebarEntry) {
|
||||
const reverseMap = makeParentMap(this.entries);
|
||||
let start: SidebarEntry | undefined = reverseMap.get(entry);
|
||||
while (start) {
|
||||
this.expanded.add(entryKey(start));
|
||||
start = reverseMap.get(start);
|
||||
}
|
||||
}
|
||||
|
||||
onHashChange() {
|
||||
this.current = "";
|
||||
const match = findMatchForNavbarUrl(this.entries);
|
||||
if (match) {
|
||||
this.current = entryKey(match);
|
||||
this.expandParents(match);
|
||||
}
|
||||
}
|
||||
|
||||
toggleExpand(entry: SidebarEntry) {
|
||||
const key = entryKey(entry);
|
||||
if (this.expanded.has(key)) {
|
||||
this.expanded.delete(key);
|
||||
} else {
|
||||
this.expanded.add(key);
|
||||
}
|
||||
this.requestUpdate();
|
||||
}
|
||||
|
||||
// This is gross and feels like 2007: using a path from the root through the shadowDoms (see
|
||||
// `TablePage:findTable()`), this code finds the element that *should* be triggered by an event
|
||||
// on the URL, and forcibly injects the text of the search and the click of the search button.
|
||||
|
||||
reclick(ev: Event, path: string) {
|
||||
const oldPath = window.location.hash.split(ROUTE_SEPARATOR)[0];
|
||||
const [curPath, ...curSearchComponents] = path.split(ROUTE_SEPARATOR);
|
||||
const curSearch: string =
|
||||
curSearchComponents.length > 0 ? curSearchComponents.join(ROUTE_SEPARATOR) : "";
|
||||
|
||||
if (curPath !== oldPath) {
|
||||
// A Tier 1 or Tier 2 change should be handled by the router. (So should a Tier 3
|
||||
// change, but... here we are.)
|
||||
return;
|
||||
}
|
||||
|
||||
const table = findTable();
|
||||
if (!table) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Always wrap the minimal exceptional code possible in an IIFE and supply the failure
|
||||
// alternative. Turn exceptions into expressions with the smallest functional rewind
|
||||
// whenever possible.
|
||||
const search = (() => {
|
||||
try {
|
||||
return curSearch ? JSON.parse(decodeURIComponent(curSearch)) : { search: "" };
|
||||
} catch {
|
||||
return { search: "" };
|
||||
}
|
||||
})();
|
||||
|
||||
if ("search" in search) {
|
||||
ev.preventDefault();
|
||||
ev.stopPropagation();
|
||||
table.search = search.search;
|
||||
table.fetch();
|
||||
}
|
||||
}
|
||||
|
||||
render(): TemplateResult {
|
||||
console.log("C:", this.current);
|
||||
const lightThemed = { "pf-m-light": this.activeTheme === UiThemeEnum.Light };
|
||||
|
||||
return html` <nav class="pf-c-nav ${classMap(lightThemed)}" aria-label="Navigation">
|
||||
<ul class="pf-c-nav__list">
|
||||
${map(this.entries, this.renderItem)}
|
||||
</ul>
|
||||
</nav>`;
|
||||
}
|
||||
|
||||
renderItem(entry: SidebarEntry) {
|
||||
// Ensure the attributes are undefined, not null; they can be null in the placeholders, but
|
||||
// not when being forwarded to the correct renderer.
|
||||
const hasChildren = !!(entry.children && entry.children.length > 0);
|
||||
|
||||
// This is grossly imperative, in that it HAS to come before the content is rendered to make
|
||||
// sure the content gets the right settings with respect to expansion.
|
||||
if (entry.attributes?.expanded) {
|
||||
this.expanded.add(entryKey(entry));
|
||||
delete entry.attributes.expanded;
|
||||
}
|
||||
|
||||
const content =
|
||||
entry.path && hasChildren
|
||||
? this.renderLinkAndChildren(entry)
|
||||
: hasChildren
|
||||
? this.renderLabelAndChildren(entry)
|
||||
: entry.path
|
||||
? this.renderLink(entry)
|
||||
: this.renderLabel(entry);
|
||||
|
||||
const expanded = {
|
||||
"highlighted": !!entry.attributes?.highlight,
|
||||
"pf-m-expanded": this.expanded.has(entryKey(entry)),
|
||||
"pf-m-expandable": hasChildren,
|
||||
};
|
||||
|
||||
return html`<li class="pf-c-nav__item ${classMap(expanded)}">${content}</li>`;
|
||||
}
|
||||
|
||||
getLinkClasses(entry: SidebarEntry) {
|
||||
const a = entry.attributes ?? {};
|
||||
const key = entryKey(entry);
|
||||
return {
|
||||
"pf-m-current": key === this.current,
|
||||
"pf-c-nav__link": true,
|
||||
"highlight": !!(typeof a.highlight === "function" ? a.highlight() : a.highlight),
|
||||
};
|
||||
}
|
||||
|
||||
renderLabel(entry: SidebarEntry) {
|
||||
return html`<div class=${classMap(this.getLinkClasses(entry))}>${entry.label}</div>`;
|
||||
}
|
||||
|
||||
// note the responsibilities pushed up to the caller
|
||||
renderLink(entry: SidebarEntry) {
|
||||
if (typeof entry.path === "function") {
|
||||
return html` <a @click=${entry.path} class=${classMap(this.getLinkClasses(entry))}>
|
||||
${entry.label}
|
||||
</a>`;
|
||||
}
|
||||
const path = `${entry.attributes?.isAbsoluteLink ? "" : "#"}${entry.path}`;
|
||||
return html` <a
|
||||
href=${path}
|
||||
@click=${(ev: Event) => this.reclick(ev, path)}
|
||||
class=${classMap(this.getLinkClasses(entry))}
|
||||
>
|
||||
${entry.label}
|
||||
</a>`;
|
||||
}
|
||||
|
||||
renderChildren(children: SidebarEntry[]) {
|
||||
return html`<section class="pf-c-nav__subnav">
|
||||
<ul class="pf-c-nav__list">
|
||||
${map(children, this.renderItem)}
|
||||
</ul>
|
||||
</section>`;
|
||||
}
|
||||
|
||||
renderLabelAndChildren(entry: SidebarEntry): TemplateResult {
|
||||
const handler = () => this.toggleExpand(entry);
|
||||
const current = { "pf-m-current": this.current === entryKey(entry) };
|
||||
|
||||
return html` <div class="pf-c-nav__link ${classMap(current)}">
|
||||
<div class="ak-nav__link">${entry.label}</div>
|
||||
<span class="pf-c-nav__toggle" @click=${handler}>
|
||||
<span class="pf-c-nav__toggle-icon">
|
||||
<i class="fas fa-angle-right" aria-hidden="true"></i>
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
${this.expanded.has(entryKey(entry))
|
||||
? this.renderChildren(entry.children ?? [])
|
||||
: nothing}`;
|
||||
}
|
||||
|
||||
renderLinkAndChildren(entry: SidebarEntry): TemplateResult {
|
||||
const handler = () => this.toggleExpand(entry);
|
||||
const current = { "pf-m-current": this.current === entryKey(entry) };
|
||||
const path = `${entry.attributes?.isAbsoluteLink ? "" : "#"}${entry.path}`;
|
||||
return html` <div class="pf-c-nav__link ${classMap(current)}">
|
||||
<a
|
||||
href=${path}
|
||||
@click=${(ev: Event) => this.reclick(ev, path)}
|
||||
class="ak-nav__link"
|
||||
>
|
||||
${entry.label}
|
||||
</a>
|
||||
<span class="pf-c-nav__toggle" @click=${handler}>
|
||||
<span class="pf-c-nav__toggle-icon">
|
||||
<i class="fas fa-angle-right" aria-hidden="true"></i>
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
${this.expanded.has(entryKey(entry))
|
||||
? this.renderChildren(entry.children ?? [])
|
||||
: nothing}`;
|
||||
}
|
||||
}
|
21
web/src/elements/sidebar/types.ts
Normal file
21
web/src/elements/sidebar/types.ts
Normal file
@ -0,0 +1,21 @@
|
||||
import { TemplateResult } from "lit";
|
||||
|
||||
export type SidebarEventHandler = () => void;
|
||||
|
||||
export type SidebarAttributes = {
|
||||
isAbsoluteLink?: boolean | (() => boolean);
|
||||
highlight?: boolean | (() => boolean);
|
||||
expanded?: boolean | (() => boolean);
|
||||
activeWhen?: string[];
|
||||
isActive?: boolean;
|
||||
};
|
||||
|
||||
export type SidebarEntry = {
|
||||
path: string | SidebarEventHandler | null;
|
||||
label: string;
|
||||
attributes?: SidebarAttributes | null; // eslint-disable-line
|
||||
children?: SidebarEntry[];
|
||||
};
|
||||
|
||||
// Typescript requires the type here to correctly type the recursive path
|
||||
export type SidebarRenderer = (_: SidebarEntry) => TemplateResult;
|
60
web/src/elements/sidebar/utils.ts
Normal file
60
web/src/elements/sidebar/utils.ts
Normal file
@ -0,0 +1,60 @@
|
||||
import { ROUTE_SEPARATOR } from "@goauthentik/common/constants";
|
||||
|
||||
import { SidebarEntry } from "./types";
|
||||
|
||||
export function entryKey(entry: SidebarEntry) {
|
||||
return `${entry.path || "no-path"}:${entry.label}`;
|
||||
}
|
||||
|
||||
// "Never store what you can calculate." (At least, if it's cheap.)
|
||||
|
||||
/**
|
||||
* Takes tree and creates a map where every key is an entry in the tree and every value is that
|
||||
* entry's parent.
|
||||
*/
|
||||
|
||||
export function makeParentMap(entries: SidebarEntry[]) {
|
||||
const reverseMap = new WeakMap<SidebarEntry, SidebarEntry>();
|
||||
function reverse(entry: SidebarEntry) {
|
||||
(entry.children ?? []).forEach((e) => {
|
||||
reverseMap.set(e, entry);
|
||||
reverse(e);
|
||||
});
|
||||
}
|
||||
entries.forEach(reverse);
|
||||
return reverseMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* Given the current path and the collection of entries, identify which entry is currently live.
|
||||
*
|
||||
*/
|
||||
|
||||
const trailingSlash = new RegExp("/$");
|
||||
const fixed = (s: string) => s.replace(trailingSlash, "");
|
||||
|
||||
function scanner(entry: SidebarEntry, activePath: string): SidebarEntry | undefined {
|
||||
if (typeof entry.path === "string" && fixed(activePath) === fixed(entry.path)) {
|
||||
return entry;
|
||||
}
|
||||
|
||||
for (const matcher of entry.attributes?.activeWhen ?? []) {
|
||||
const matchtest = new RegExp(matcher);
|
||||
if (matchtest.test(activePath)) {
|
||||
return entry;
|
||||
}
|
||||
}
|
||||
|
||||
return (entry.children ?? []).find((e) => scanner(e, activePath));
|
||||
}
|
||||
|
||||
export function findMatchForNavbarUrl(entries: SidebarEntry[]) {
|
||||
const activePath = window.location.hash.slice(1, Infinity).split(ROUTE_SEPARATOR)[0];
|
||||
for (const entry of entries) {
|
||||
const result = scanner(entry, activePath);
|
||||
if (result) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
return undefined;
|
||||
}
|
@ -20,6 +20,11 @@ export abstract class TablePage<T> extends Table<T> {
|
||||
return super.styles.concat(PFPage, PFContent, PFSidebar);
|
||||
}
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
this.dataset.akApiTable = "true";
|
||||
}
|
||||
|
||||
renderSidebarBefore(): TemplateResult {
|
||||
return html``;
|
||||
}
|
||||
@ -92,3 +97,18 @@ export abstract class TablePage<T> extends Table<T> {
|
||||
${this.renderSectionAfter()}`;
|
||||
}
|
||||
}
|
||||
|
||||
// This painstakingly researched path is nonetheless surprisingly robust; it works for every extant
|
||||
// TablePage, but only because Jens has been utterly consistent in where he puts his TablePage
|
||||
// elements with respect to the Interface object. If we ever re-arrange this code, we're going
|
||||
// to have to re-arrange this as well.
|
||||
|
||||
export function findTable<T, U extends TablePage<T>>(): U | undefined {
|
||||
return (
|
||||
(document.body
|
||||
?.querySelector("[data-ak-interface-root]")
|
||||
?.shadowRoot?.querySelector("ak-locale-context")
|
||||
?.querySelector("ak-router-outlet")
|
||||
?.shadowRoot?.querySelector("[data-ak-api-table]") as U) ?? undefined
|
||||
);
|
||||
}
|
||||
|
@ -15,7 +15,7 @@ import PFProgressStepper from "@patternfly/patternfly/components/ProgressStepper
|
||||
import PFStack from "@patternfly/patternfly/layouts/Stack/stack.css";
|
||||
import PFBase from "@patternfly/patternfly/patternfly-base.css";
|
||||
|
||||
import { FlowInspection, FlowsApi, Stage } from "@goauthentik/api";
|
||||
import { FlowInspection, FlowsApi, ResponseError, Stage } from "@goauthentik/api";
|
||||
|
||||
@customElement("ak-flow-inspector")
|
||||
export class FlowInspector extends AKElement {
|
||||
@ -25,7 +25,7 @@ export class FlowInspector extends AKElement {
|
||||
state?: FlowInspection;
|
||||
|
||||
@property({ attribute: false })
|
||||
error?: Response;
|
||||
error?: ResponseError;
|
||||
|
||||
static get styles(): CSSResult[] {
|
||||
return [
|
||||
@ -70,6 +70,7 @@ export class FlowInspector extends AKElement {
|
||||
flowSlug: this.flowSlug,
|
||||
})
|
||||
.then((state) => {
|
||||
this.error = undefined;
|
||||
this.state = state;
|
||||
})
|
||||
.catch((exc) => {
|
||||
@ -100,7 +101,7 @@ export class FlowInspector extends AKElement {
|
||||
<div class="pf-l-stack pf-m-gutter">
|
||||
<div class="pf-l-stack__item">
|
||||
<div class="pf-c-card">
|
||||
<div class="pf-c-card__body">${this.error?.statusText}</div>
|
||||
<div class="pf-c-card__body">${this.error?.message}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -6641,6 +6641,42 @@ Bindings to groups/users are checked against the user of the event.</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="s001fd928369d4ddc">
|
||||
<source><x id="0" equiv-text="${versionString}"/> (FIPS)</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="sce17c2bdea3e6ace">
|
||||
<source>Score minimum threshold</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="sf2fcb974c62625fc">
|
||||
<source>Minimum required score to allow continuing</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="s7452199a73ce8b78">
|
||||
<source>Score maximum threshold</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="s2d3a6cd50b46b44d">
|
||||
<source>Maximum allowed score to allow continuing</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="s9d6e40d9a9a58fbf">
|
||||
<source>Error on invalid score</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="s2af59e2f9f12847a">
|
||||
<source>When enabled and the resultant score is outside the threshold, the user will not be able to continue. When disabled, the user will be able to continue and the score can be used in policies to customize further stages.</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="s10092327ad833090">
|
||||
<source>Microsoft Entra Group(s)</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="s811c45ad24a5feae">
|
||||
<source>Microsoft Entra User(s)</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="s7d2d3d298fdccfc8">
|
||||
<source>Google Workspace Group(s)</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="s8c9cf2c004755526">
|
||||
<source>Google Workspace User(s)</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="sd000b42fea07c34a">
|
||||
<source>SCIM Group(s)</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="s146769fb55f1ee50">
|
||||
<source>SCIM User(s)</source>
|
||||
</trans-unit>
|
||||
</body>
|
||||
</file>
|
||||
|
@ -6907,6 +6907,42 @@ Bindings to groups/users are checked against the user of the event.</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="s001fd928369d4ddc">
|
||||
<source><x id="0" equiv-text="${versionString}"/> (FIPS)</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="sce17c2bdea3e6ace">
|
||||
<source>Score minimum threshold</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="sf2fcb974c62625fc">
|
||||
<source>Minimum required score to allow continuing</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="s7452199a73ce8b78">
|
||||
<source>Score maximum threshold</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="s2d3a6cd50b46b44d">
|
||||
<source>Maximum allowed score to allow continuing</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="s9d6e40d9a9a58fbf">
|
||||
<source>Error on invalid score</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="s2af59e2f9f12847a">
|
||||
<source>When enabled and the resultant score is outside the threshold, the user will not be able to continue. When disabled, the user will be able to continue and the score can be used in policies to customize further stages.</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="s10092327ad833090">
|
||||
<source>Microsoft Entra Group(s)</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="s811c45ad24a5feae">
|
||||
<source>Microsoft Entra User(s)</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="s7d2d3d298fdccfc8">
|
||||
<source>Google Workspace Group(s)</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="s8c9cf2c004755526">
|
||||
<source>Google Workspace User(s)</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="sd000b42fea07c34a">
|
||||
<source>SCIM Group(s)</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="s146769fb55f1ee50">
|
||||
<source>SCIM User(s)</source>
|
||||
</trans-unit>
|
||||
</body>
|
||||
</file>
|
||||
|
@ -6558,6 +6558,42 @@ Bindings to groups/users are checked against the user of the event.</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="s001fd928369d4ddc">
|
||||
<source><x id="0" equiv-text="${versionString}"/> (FIPS)</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="sce17c2bdea3e6ace">
|
||||
<source>Score minimum threshold</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="sf2fcb974c62625fc">
|
||||
<source>Minimum required score to allow continuing</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="s7452199a73ce8b78">
|
||||
<source>Score maximum threshold</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="s2d3a6cd50b46b44d">
|
||||
<source>Maximum allowed score to allow continuing</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="s9d6e40d9a9a58fbf">
|
||||
<source>Error on invalid score</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="s2af59e2f9f12847a">
|
||||
<source>When enabled and the resultant score is outside the threshold, the user will not be able to continue. When disabled, the user will be able to continue and the score can be used in policies to customize further stages.</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="s10092327ad833090">
|
||||
<source>Microsoft Entra Group(s)</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="s811c45ad24a5feae">
|
||||
<source>Microsoft Entra User(s)</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="s7d2d3d298fdccfc8">
|
||||
<source>Google Workspace Group(s)</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="s8c9cf2c004755526">
|
||||
<source>Google Workspace User(s)</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="sd000b42fea07c34a">
|
||||
<source>SCIM Group(s)</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="s146769fb55f1ee50">
|
||||
<source>SCIM User(s)</source>
|
||||
</trans-unit>
|
||||
</body>
|
||||
</file>
|
||||
|
@ -8604,108 +8604,191 @@ Les liaisons avec les groupes/utilisateurs sont vérifiées par rapport à l'uti
|
||||
</trans-unit>
|
||||
<trans-unit id="s8cfd29891b2c93f0">
|
||||
<source>Google Workspace Provider</source>
|
||||
<target>Fournisseur Google Workspace</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="sa817aa9f6f88a991">
|
||||
<source>Credentials</source>
|
||||
<target>Identifiants</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="sc668815044e218c2">
|
||||
<source>Delegated Subject</source>
|
||||
<target>Sujet délégué</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="se89a9ecf275e4343">
|
||||
<source>Default group email domain</source>
|
||||
<target>Domaine de courriel de groupe par défaut</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="s64a0a6da6ed6d680">
|
||||
<source>Default domain that is used to generate a group's email address. Can be customized using property mappings.</source>
|
||||
<target>Domain par défaut utilisé pour générer le courriel d'un groupe. Peut être personnalisé avec des mappages de propriété.</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="sd061e65955e036ca">
|
||||
<source>User deletion action</source>
|
||||
<target>Action de suppression d'un utilisateur</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="s87f86f65b5e19ea7">
|
||||
<source>User is deleted</source>
|
||||
<target>L'utilisateur est supprimé</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="s3906cd4a102867a3">
|
||||
<source>Suspend</source>
|
||||
<target>Suspendre</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="s0bf5b364e2c79392">
|
||||
<source>User is suspended, and connection to user in authentik is removed.</source>
|
||||
<target>L'utilisateur est suspendu, et la connection à authentik est supprimée.</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="s4acb0250d735c2a9">
|
||||
<source>Do Nothing</source>
|
||||
<target>Ne rien faire</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="s5fe525d19499ed47">
|
||||
<source>The connection is removed but the user is not modified</source>
|
||||
<target>La connexion est supprimée mais l'utilisateur n'est pas modifié</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="s676a0127c35d240a">
|
||||
<source>Determines what authentik will do when a User is deleted.</source>
|
||||
<target>Détermine ce qu'authentik fera si un utilisateur est supprimé.</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="sd1aa04cc32caf2b0">
|
||||
<source>Group deletion action</source>
|
||||
<target>Action de suppression d'un groupe</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="s874c788479481131">
|
||||
<source>Group is deleted</source>
|
||||
<target>Le groupe est supprimé</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="s0983fa9b84e4a9f7">
|
||||
<source>The connection is removed but the group is not modified</source>
|
||||
<target>La connexion est supprimée mais le groupe n'est pas modifié</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="sdb872a9f425937fa">
|
||||
<source>Determines what authentik will do when a Group is deleted.</source>
|
||||
<target>Détermine ce qu'authentik fera si un groupe est supprimé.</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="sa5f28f1ad0bee45b">
|
||||
<source>Google Workspace Provider is in preview.</source>
|
||||
<target>Le fournisseur Google Workspace est en aperçu technique.</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="s958928ab6208d748">
|
||||
<source>Microsoft Entra Provider</source>
|
||||
<target>Fournisseur Microsoft Entra</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="sc7d6bc4aebb58fe9">
|
||||
<source>Google Cloud credentials file.</source>
|
||||
<target>Fichier d'identifiants Google Cloud.</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="s2e707072d5a9615d">
|
||||
<source>Email address of the user the actions of authentik will be delegated to.</source>
|
||||
<target>Courriel de l'utilisateur auquel les actions d'authentik seront déléguées.</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="s03a759e65ceb722d">
|
||||
<source>Client ID for the app registration.</source>
|
||||
<target>Client ID pour l'enregistrement de l'application.</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="s479980cf9252628c">
|
||||
<source>Client secret for the app registration.</source>
|
||||
<target>Client secret pour l'enregistrement de l'application.</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="s25c2392ffcb78df2">
|
||||
<source>Tenant ID</source>
|
||||
<target>Tenant ID</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="s89e4e698cdb1187f">
|
||||
<source>ID of the tenant accounts will be synced into.</source>
|
||||
<target>ID du tenant dans lequel les comptes seront synchronisés.</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="sf341f5dfc7a11633">
|
||||
<source>Microsoft Entra Provider is in preview.</source>
|
||||
<target>Le fournisseur Microsoft Entra est en aperçu technique.</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="s79dd6df244c05ae9">
|
||||
<source>Update Microsoft Entra Provider</source>
|
||||
<target>Mettre à jour le fournisseur Microsoft Entra</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="saf4b498d81141878">
|
||||
<source>Finished successfully</source>
|
||||
<target>Fini avec succès</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="s46f1d86ffec6223c">
|
||||
<source>Finished with errors</source>
|
||||
<target>Fini avec erreurs</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="sbd12ed8a1053a108">
|
||||
<source>Finished <x id="0" equiv-text="${getRelativeTime(task.finishTimestamp)}"/> (<x id="1" equiv-text="${task.finishTimestamp.toLocaleString()}"/>)</source>
|
||||
<target>Fini <x id="0" equiv-text="${getRelativeTime(task.finishTimestamp)}"/> (<x id="1" equiv-text="${task.finishTimestamp.toLocaleString()}"/>)</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="sc3c334d642866997">
|
||||
<source>Sync currently running</source>
|
||||
<target>Synchronisation en cours</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="sd520a4089006ca93">
|
||||
<source>Update Google Workspace Provider</source>
|
||||
<target>Mettre à jour le fournisseur Google Workspace</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="sfdfa5bb4ddd99d70">
|
||||
<source>Enterprise only</source>
|
||||
<target>Entreprise uniquement</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="scffa59cfac1951f2">
|
||||
<source><x id="0" equiv-text="${type.name}"/> Icon</source>
|
||||
<target>Icône <x id="0" equiv-text="${type.name}"/></target>
|
||||
</trans-unit>
|
||||
<trans-unit id="s1da3499258024860">
|
||||
<source><x id="0" equiv-text="${versionString}"/> (build <x id="1" equiv-text="${this.outpostHealth.buildHash.substring(0, 8)}"/>)</source>
|
||||
<target><x id="0" equiv-text="${versionString}"/> (build <x id="1" equiv-text="${this.outpostHealth.buildHash.substring(0, 8)}"/>)</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="s001fd928369d4ddc">
|
||||
<source><x id="0" equiv-text="${versionString}"/> (FIPS)</source>
|
||||
<target><x id="0" equiv-text="${versionString}"/> (FIPS)</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="sce17c2bdea3e6ace">
|
||||
<source>Score minimum threshold</source>
|
||||
<target>Seuil minimum du score</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="sf2fcb974c62625fc">
|
||||
<source>Minimum required score to allow continuing</source>
|
||||
<target>Score minimum requis pour continuer</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="s7452199a73ce8b78">
|
||||
<source>Score maximum threshold</source>
|
||||
<target>Seuil maximum du score</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="s2d3a6cd50b46b44d">
|
||||
<source>Maximum allowed score to allow continuing</source>
|
||||
<target>Score maximum requis pour continuer</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="s9d6e40d9a9a58fbf">
|
||||
<source>Error on invalid score</source>
|
||||
<target>Erreur sur score invalide</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="s2af59e2f9f12847a">
|
||||
<source>When enabled and the resultant score is outside the threshold, the user will not be able to continue. When disabled, the user will be able to continue and the score can be used in policies to customize further stages.</source>
|
||||
<target>Si activé et que le score résultant est hors des seuils, l'utilisateur ne pourra pas continuer. Si désactivé, l'utilisateur pourra continuer et le score pourra être utilisé dans des politiques pour configurer les étapes suivantes.</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="s10092327ad833090">
|
||||
<source>Microsoft Entra Group(s)</source>
|
||||
<target>Groupe(s) du fournisseur Microsoft Entra</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="s811c45ad24a5feae">
|
||||
<source>Microsoft Entra User(s)</source>
|
||||
<target>Utilisateur(s) du fournisseur Microsoft Entra</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="s7d2d3d298fdccfc8">
|
||||
<source>Google Workspace Group(s)</source>
|
||||
<target>Groupe(s) du fournisseur Google Workspace</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="s8c9cf2c004755526">
|
||||
<source>Google Workspace User(s)</source>
|
||||
<target>Utilisateur(s) du fournisseur Google Workspace</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="sd000b42fea07c34a">
|
||||
<source>SCIM Group(s)</source>
|
||||
<target>Groupe(s) du fournisseur SCIM</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="s146769fb55f1ee50">
|
||||
<source>SCIM User(s)</source>
|
||||
<target>Utilisateur(s) du fournisseur SCIM</target>
|
||||
</trans-unit>
|
||||
</body>
|
||||
</file>
|
||||
|
@ -8487,6 +8487,42 @@ Bindings to groups/users are checked against the user of the event.</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="s001fd928369d4ddc">
|
||||
<source><x id="0" equiv-text="${versionString}"/> (FIPS)</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="sce17c2bdea3e6ace">
|
||||
<source>Score minimum threshold</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="sf2fcb974c62625fc">
|
||||
<source>Minimum required score to allow continuing</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="s7452199a73ce8b78">
|
||||
<source>Score maximum threshold</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="s2d3a6cd50b46b44d">
|
||||
<source>Maximum allowed score to allow continuing</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="s9d6e40d9a9a58fbf">
|
||||
<source>Error on invalid score</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="s2af59e2f9f12847a">
|
||||
<source>When enabled and the resultant score is outside the threshold, the user will not be able to continue. When disabled, the user will be able to continue and the score can be used in policies to customize further stages.</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="s10092327ad833090">
|
||||
<source>Microsoft Entra Group(s)</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="s811c45ad24a5feae">
|
||||
<source>Microsoft Entra User(s)</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="s7d2d3d298fdccfc8">
|
||||
<source>Google Workspace Group(s)</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="s8c9cf2c004755526">
|
||||
<source>Google Workspace User(s)</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="sd000b42fea07c34a">
|
||||
<source>SCIM Group(s)</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="s146769fb55f1ee50">
|
||||
<source>SCIM User(s)</source>
|
||||
</trans-unit>
|
||||
</body>
|
||||
</file>
|
||||
|
@ -8331,6 +8331,42 @@ Bindingen naar groepen/gebruikers worden gecontroleerd tegen de gebruiker van de
|
||||
</trans-unit>
|
||||
<trans-unit id="s001fd928369d4ddc">
|
||||
<source><x id="0" equiv-text="${versionString}"/> (FIPS)</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="sce17c2bdea3e6ace">
|
||||
<source>Score minimum threshold</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="sf2fcb974c62625fc">
|
||||
<source>Minimum required score to allow continuing</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="s7452199a73ce8b78">
|
||||
<source>Score maximum threshold</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="s2d3a6cd50b46b44d">
|
||||
<source>Maximum allowed score to allow continuing</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="s9d6e40d9a9a58fbf">
|
||||
<source>Error on invalid score</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="s2af59e2f9f12847a">
|
||||
<source>When enabled and the resultant score is outside the threshold, the user will not be able to continue. When disabled, the user will be able to continue and the score can be used in policies to customize further stages.</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="s10092327ad833090">
|
||||
<source>Microsoft Entra Group(s)</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="s811c45ad24a5feae">
|
||||
<source>Microsoft Entra User(s)</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="s7d2d3d298fdccfc8">
|
||||
<source>Google Workspace Group(s)</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="s8c9cf2c004755526">
|
||||
<source>Google Workspace User(s)</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="sd000b42fea07c34a">
|
||||
<source>SCIM Group(s)</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="s146769fb55f1ee50">
|
||||
<source>SCIM User(s)</source>
|
||||
</trans-unit>
|
||||
</body>
|
||||
</file>
|
||||
|
2110
web/xliff/pl.xlf
2110
web/xliff/pl.xlf
File diff suppressed because it is too large
Load Diff
@ -8602,4 +8602,40 @@ Bindings to groups/users are checked against the user of the event.</source>
|
||||
<trans-unit id="s001fd928369d4ddc">
|
||||
<source><x id="0" equiv-text="${versionString}"/> (FIPS)</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="sce17c2bdea3e6ace">
|
||||
<source>Score minimum threshold</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="sf2fcb974c62625fc">
|
||||
<source>Minimum required score to allow continuing</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="s7452199a73ce8b78">
|
||||
<source>Score maximum threshold</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="s2d3a6cd50b46b44d">
|
||||
<source>Maximum allowed score to allow continuing</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="s9d6e40d9a9a58fbf">
|
||||
<source>Error on invalid score</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="s2af59e2f9f12847a">
|
||||
<source>When enabled and the resultant score is outside the threshold, the user will not be able to continue. When disabled, the user will be able to continue and the score can be used in policies to customize further stages.</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="s10092327ad833090">
|
||||
<source>Microsoft Entra Group(s)</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="s811c45ad24a5feae">
|
||||
<source>Microsoft Entra User(s)</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="s7d2d3d298fdccfc8">
|
||||
<source>Google Workspace Group(s)</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="s8c9cf2c004755526">
|
||||
<source>Google Workspace User(s)</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="sd000b42fea07c34a">
|
||||
<source>SCIM Group(s)</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="s146769fb55f1ee50">
|
||||
<source>SCIM User(s)</source>
|
||||
</trans-unit>
|
||||
</body></file></xliff>
|
||||
|
@ -6551,6 +6551,42 @@ Bindings to groups/users are checked against the user of the event.</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="s001fd928369d4ddc">
|
||||
<source><x id="0" equiv-text="${versionString}"/> (FIPS)</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="sce17c2bdea3e6ace">
|
||||
<source>Score minimum threshold</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="sf2fcb974c62625fc">
|
||||
<source>Minimum required score to allow continuing</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="s7452199a73ce8b78">
|
||||
<source>Score maximum threshold</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="s2d3a6cd50b46b44d">
|
||||
<source>Maximum allowed score to allow continuing</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="s9d6e40d9a9a58fbf">
|
||||
<source>Error on invalid score</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="s2af59e2f9f12847a">
|
||||
<source>When enabled and the resultant score is outside the threshold, the user will not be able to continue. When disabled, the user will be able to continue and the score can be used in policies to customize further stages.</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="s10092327ad833090">
|
||||
<source>Microsoft Entra Group(s)</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="s811c45ad24a5feae">
|
||||
<source>Microsoft Entra User(s)</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="s7d2d3d298fdccfc8">
|
||||
<source>Google Workspace Group(s)</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="s8c9cf2c004755526">
|
||||
<source>Google Workspace User(s)</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="sd000b42fea07c34a">
|
||||
<source>SCIM Group(s)</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="s146769fb55f1ee50">
|
||||
<source>SCIM User(s)</source>
|
||||
</trans-unit>
|
||||
</body>
|
||||
</file>
|
||||
|
@ -5473,6 +5473,42 @@ Bindings to groups/users are checked against the user of the event.</source>
|
||||
<trans-unit id="s001fd928369d4ddc">
|
||||
<source><x id="0" equiv-text="${versionString}"/> (FIPS)</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="sce17c2bdea3e6ace">
|
||||
<source>Score minimum threshold</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="sf2fcb974c62625fc">
|
||||
<source>Minimum required score to allow continuing</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="s7452199a73ce8b78">
|
||||
<source>Score maximum threshold</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="s2d3a6cd50b46b44d">
|
||||
<source>Maximum allowed score to allow continuing</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="s9d6e40d9a9a58fbf">
|
||||
<source>Error on invalid score</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="s2af59e2f9f12847a">
|
||||
<source>When enabled and the resultant score is outside the threshold, the user will not be able to continue. When disabled, the user will be able to continue and the score can be used in policies to customize further stages.</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="s10092327ad833090">
|
||||
<source>Microsoft Entra Group(s)</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="s811c45ad24a5feae">
|
||||
<source>Microsoft Entra User(s)</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="s7d2d3d298fdccfc8">
|
||||
<source>Google Workspace Group(s)</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="s8c9cf2c004755526">
|
||||
<source>Google Workspace User(s)</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="sd000b42fea07c34a">
|
||||
<source>SCIM Group(s)</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="s146769fb55f1ee50">
|
||||
<source>SCIM User(s)</source>
|
||||
</trans-unit>
|
||||
</body>
|
||||
</file>
|
||||
</xliff>
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user