Skip to content

Commit d3c6a9e

Browse files
Implementing SymphonyGroup extension
1 parent bd36a15 commit d3c6a9e

File tree

12 files changed

+508
-26
lines changed

12 files changed

+508
-26
lines changed
+64
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
import asyncio
2+
import logging.config
3+
from pathlib import Path
4+
5+
from symphony.bdk.core.config.loader import BdkConfigLoader
6+
from symphony.bdk.core.symphony_bdk import SymphonyBdk
7+
from symphony.bdk.ext.group import SymphonyGroupBdkExtension, SymphonyGroupService
8+
from symphony.bdk.gen.group_model.base_profile import BaseProfile
9+
from symphony.bdk.gen.group_model.create_group import CreateGroup
10+
from symphony.bdk.gen.group_model.member import Member
11+
from symphony.bdk.gen.group_model.owner import Owner
12+
from symphony.bdk.gen.group_model.status import Status
13+
from symphony.bdk.gen.group_model.update_group import UpdateGroup
14+
15+
logging.config.fileConfig(Path(__file__).parent.parent / "logging.conf", disable_existing_loggers=False)
16+
17+
18+
async def run():
19+
async with SymphonyBdk(BdkConfigLoader.load_from_symphony_dir("configDevx3.yaml")) as bdk:
20+
bdk.extensions().register(SymphonyGroupBdkExtension)
21+
group_service: SymphonyGroupService = bdk.extensions().service(SymphonyGroupBdkExtension)
22+
await group_service._oauth_session.refresh()
23+
24+
# list groups
25+
groups = await group_service.list_groups(status=Status("ACTIVE"))
26+
logging.debug(f"List groups: {groups}")
27+
28+
# create a new group
29+
profile = BaseProfile(display_name="Mary's SDL")
30+
member = Member(member_tenant=190, member_id=13056700580915)
31+
create_group = CreateGroup(type="SDL", owner_type=Owner(value="TENANT"), owner_id=190, name="Another SDL",
32+
members=[member], profile=profile)
33+
group = await group_service.insert_group(create_group=create_group)
34+
logging.debug(f"Group created: {group}")
35+
36+
# update group name
37+
update_group = UpdateGroup(name="Updated name", type=group.type, owner_type=Owner(value="TENANT"),
38+
owner_id=group.owner_id, id=group.id, e_tag=group.e_tag,
39+
status=Status(value="ACTIVE"), profile=profile, members=[member])
40+
group = await group_service.update_group(if_match=group.e_tag, group_id=group.id, update_group=update_group)
41+
logging.debug(f"Group after name update: {group}")
42+
43+
# add member to a group
44+
group = await group_service.add_member_to_group(group.id, 13056700580913)
45+
logging.debug(f"Group after a new member is added: {group}")
46+
47+
# update group avatar
48+
image_base_64 = "base_64_format_image"
49+
group = await group_service.update_avatar(group_id=group.id, image=image_base_64)
50+
logging.debug(f"Group after avatar update: {group}")
51+
52+
# get a group by id
53+
group = await group_service.get_group(group_id=group.id)
54+
logging.debug(f"Retrieve group by id: {group}")
55+
56+
# Delete group
57+
update_group = UpdateGroup(name=group.name, type=group.type, owner_type=Owner(value="TENANT"),
58+
owner_id=group.owner_id, id=group.id, e_tag=group.e_tag,
59+
status=Status(value="DELETED"), profile=profile, members=[member])
60+
group = await group_service.update_group(if_match=group.e_tag, group_id=group.id, update_group=update_group)
61+
logging.debug(f"Group removed: {group}")
62+
63+
64+
asyncio.run(run())

poetry.lock

+25-25
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

symphony/bdk/core/client/api_client_factory.py

+13
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ def __init__(self, config):
3838
self._config.bot.certificate.path)
3939
self._app_session_auth_client = self._get_api_client_with_client_cert(self._config.session_auth, SESSION_AUTH,
4040
self._config.app.certificate.path)
41+
self._custom_clients = []
4142

4243
def get_login_client(self) -> ApiClient:
4344
"""Returns a fully initialized ApiClient for Login API.
@@ -53,6 +54,16 @@ def get_pod_client(self) -> ApiClient:
5354
"""
5455
return self._pod_client
5556

57+
def get_client(self, context_path):
58+
"""Returns a fully initialized custom ApiClient
59+
60+
:param context_path: custom path to be used in the client
61+
:return: an ApiClient instance
62+
"""
63+
client = self._get_api_client(self._config.pod, context_path)
64+
self._custom_clients.append(client)
65+
return client
66+
5667
def get_relay_client(self) -> ApiClient:
5768
"""Returns a fully initialized ApiClient for Key Manager API.
5869
@@ -99,6 +110,8 @@ async def close_clients(self):
99110
await self._session_auth_client.close()
100111
await self._key_auth_client.close()
101112
await self._app_session_auth_client.close()
113+
for client in self._custom_clients:
114+
await client.close()
102115

103116
def _get_api_client(self, server_config, context) -> ApiClient:
104117
configuration = self._get_client_config(context, server_config)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
"""Module containing utility function to extract the tenant ID from a user ID.
2+
The user ID is a combination of a unique tenant ID, and a unique sub-tenant ID, combined into a number.
3+
The tenant ID is stored in the 27 highest bits (minus the sign bit which is unused so that all IDs remain a
4+
positive value) which allows for 134 million pods.
5+
This leaves 36 lowest bits for the user ID, which allows 68.7 billion users per tenant.
6+
"""
7+
TENANT_ID_BIT_LENGTH = 27
8+
SUBTENANT_ID_BIT_LENGTH = 36
9+
TENANT_ID_INDEX = 1
10+
11+
12+
def extract_tenant_id(user_id: int):
13+
"""Extracts the tenant ID from a user ID.
14+
15+
:param user_id: the user ID.
16+
:return: the tenant ID.
17+
"""
18+
number_util = NumberUtil(sizes=[SUBTENANT_ID_BIT_LENGTH, TENANT_ID_BIT_LENGTH])
19+
return number_util.extract(user_id, TENANT_ID_INDEX)
20+
21+
22+
class NumberUtil:
23+
"""Used to compute the segments bases in the input sizes
24+
"""
25+
26+
def __init__(self, sizes: []):
27+
self._segments = []
28+
self._total_size = 0
29+
self._shift = 0
30+
31+
for size in sizes:
32+
segment = Segment(size, self._shift)
33+
self._shift += size
34+
self._segments.append(segment)
35+
self._total_size += size
36+
37+
if self._total_size > 64:
38+
raise ValueError("total size is larger than the bit-count of 64")
39+
40+
def extract(self, value: int, index: int):
41+
"""Extract the tenant_id given the user_id and the index
42+
"""
43+
segment = self._segments[index]
44+
return value >> segment._shift & segment._mask
45+
46+
47+
class Segment:
48+
"""Helper class to initialize a Segment
49+
"""
50+
51+
def __init__(self, size: int, shift: int):
52+
mask = 0
53+
for _ in range(size):
54+
mask |= 1
55+
mask <<= 1
56+
57+
mask >>= 1
58+
self._mask = mask
59+
self._shift = shift

symphony/bdk/core/symphony_bdk.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,7 @@ def _initialize_bot_services(self):
119119
self._activity_registry = ActivityRegistry(self._session_service)
120120
self._datafeed_loop.subscribe(self._activity_registry)
121121
# initialises extension service and register decorated extensions
122-
self._extension_service = ExtensionService(self._bot_session, self._config, self._api_client_factory)
122+
self._extension_service = ExtensionService(self._api_client_factory, self._bot_session, self._config)
123123

124124
@bot_service
125125
def bot_session(self) -> AuthSession:

symphony/bdk/ext/__init__.py

Whitespace-only changes.

0 commit comments

Comments
 (0)