Skip to content

Commit 489af92

Browse files
PLAT-10531 Signal service implementation (#138)
1 parent 4d614bf commit 489af92

16 files changed

+585
-28
lines changed

docsrc/index.md

+3-1
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ Contents
88
* [Stream service](markdown/stream_service.md)
99
* [Connection service](markdown/connection_service.md)
1010
* [Application service](markdown/application_service.md)
11+
* [Signal service](markdown/signal_service.md)
1112
* [Datafeed](markdown/datafeed.md)
1213
* [Presence service](markdown/presence_service.md)
1314

@@ -35,7 +36,8 @@ The reference documentation consists of the following sections:
3536
* [Message service](markdown/message_service.md): Sending or searching messages, usage of templates
3637
* [Stream service](markdown/stream_service.md): Creating, searching streams, manage stream membership
3738
* [Connection service](markdown/connection_service.md): Managing connections between users
38-
* [Datafeed](markdown/datafeed.md): Listening and reacting to real-time events
39+
* [Signal service](markdown/signal_service.md): Managing signals, subscribing/unsubscribing to signals
40+
* [Datafeed](markdown/datafeed.md): Listening and reacting to real-time events
3941
* [Presence service](markdown/presence_service.md): Reacting and managing presences
4042
### Technical Documentation
4143
* Information on how we generate client side code from swagger specs in the

docsrc/markdown/signal_service.md

+30
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
# Signal Service
2+
3+
The Signal Service is a component at the service layer of the BDK which aims to cover the Signal part of the [REST API documentation](https://developers.symphony.com/restapi/reference).
4+
More precisely:
5+
* [List signals](https://developers.symphony.com/restapi/reference#list-signals)
6+
* [Get a signal](https://developers.symphony.com/restapi/reference#get-signal)
7+
* [Create a signal](https://developers.symphony.com/restapi/reference#create-signal)
8+
* [Update a signal](https://developers.symphony.com/restapi/reference#update-signal)
9+
* [Delete a signal](https://developers.symphony.com/restapi/reference#delete-signal)
10+
* [Subscribe Signal](https://developers.symphony.com/restapi/reference#subscribe-signal)
11+
* [Unsubscribe Signal](https://developers.symphony.com/restapi/reference#unsubscribe-signal)
12+
* [Subscribers](https://developers.symphony.com/restapi/reference#subscribers)
13+
14+
15+
## How to use
16+
The central component for the Signal Service is the `SignalService` class.
17+
This class exposes the user-friendly service APIs which serve all the services mentioned above
18+
and is accessible from the `SymphonyBdk` object by calling the `signals()` method:
19+
```python
20+
class ApplicationMain:
21+
@staticmethod
22+
async def run():
23+
bdk_config = BdkConfigLoader.load_from_file("path/to/config.yaml")
24+
async with SymphonyBdk(bdk_config) as bdk:
25+
signal_service = bdk.signals()
26+
signal_list = await signal_service.list_signals()
27+
print(signal_list)
28+
if __name__ == "__main__":
29+
asyncio.run(ApplicationMain.run())
30+
```

examples/signals.py

+42
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
import asyncio
2+
import logging
3+
4+
from symphony.bdk.core.config.loader import BdkConfigLoader
5+
from symphony.bdk.core.symphony_bdk import SymphonyBdk
6+
from symphony.bdk.gen.agent_model.base_signal import BaseSignal
7+
8+
9+
async def run():
10+
config = BdkConfigLoader.load_from_symphony_dir("config.yaml")
11+
12+
async with SymphonyBdk(config) as bdk:
13+
signal_service = bdk.signals()
14+
attribute_map = {
15+
'name': 'Testing signal',
16+
'query': 'HASHTAG:hashtag',
17+
'visible_on_profile': False,
18+
'company_wide': False
19+
}
20+
logging.info('Creating new signal.')
21+
signal = await signal_service.create_signal(BaseSignal(**attribute_map))
22+
logging.info(signal)
23+
await signal_service.list_signals(0, 3)
24+
attribute_map_update = {
25+
'name': 'Testing signal updated',
26+
'query': 'HASHTAG:hashtag',
27+
'visible_on_profile': False,
28+
'company_wide': False
29+
}
30+
logging.info('Updating signal.')
31+
await signal_service.update_signal(signal.id, BaseSignal(**attribute_map_update))
32+
logging.info(await signal_service.get_signal(signal.id))
33+
logging.info('Add a subscriber to the signal.')
34+
await signal_service.subscribe_users_to_signal(signal.id, True, [13056700580913])
35+
logging.info(await signal_service.list_subscribers(signal.id))
36+
logging.info('Unsubscribe added user to the signal.')
37+
await signal_service.unsubscribe_users_to_signal(signal.id, [13056700580913])
38+
logging.info(await signal_service.list_subscribers(signal.id))
39+
logging.info(await signal_service.delete_signal(signal.id))
40+
41+
logging.basicConfig(level=logging.DEBUG)
42+
asyncio.run(run())

symphony/bdk/core/service/presence/presence_service.py

+16-16
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ async def get_all_presence(self, last_user_id: int, limit: int) -> List[V2Presen
5353
See: `Get All Presence <https://developers.symphony.com/restapi/reference#get-all-presence>`_.
5454
5555
:param last_user_id: Last user ID retrieved, used for paging. If provided, results skip users with IDs less
56-
than this parameter.
56+
than this parameter.
5757
:param limit: Maximum number of records to return. The maximum supported value is 5000.
5858
:return: Presence info of the looked up user.
5959
"""
@@ -67,8 +67,8 @@ async def get_user_presence(self, user_id: int, local: bool) -> V2Presence:
6767
6868
:param user_id: User Id
6969
:param local: If true then Perform a local query and set the presence to OFFLINE for users who are not local to
70-
the calling user’s pod. If false or absent then query the presence of all local and external users who are
71-
connected to the calling user.
70+
the calling user’s pod. If false or absent then query the presence of all local and external users who are
71+
connected to the calling user.
7272
:return: Presence info of the looked up user.
7373
"""
7474
return await self._presence_api.v3_user_uid_presence_get(uid=user_id,
@@ -77,8 +77,8 @@ async def get_user_presence(self, user_id: int, local: bool) -> V2Presence:
7777

7878
async def external_presence_interest(self, user_ids: List[int]):
7979
""" Register interest in a list of external users to get their presence info.
80-
See: `External Presence Interest <https://developers.symphony.com/restapi/reference#register-user-presence
81-
-interest>`_.
80+
See: `External Presence Interest
81+
<https://developers.symphony.com/restapi/reference#register-user-presence-interest>`_.
8282
8383
:param user_ids: List of user ids to be registered.
8484
"""
@@ -90,12 +90,12 @@ async def set_presence(self, status: PresenceStatus, soft: bool) -> V2Presence:
9090
See: `Set Presence <https://developers.symphony.com/restapi/reference#set-presence>`_.
9191
9292
:param status: The new presence state for the user.
93-
Possible values are AVAILABLE, BUSY, AWAY, ON_THE_PHONE, BE_RIGHT_BACK, IN_A_MEETING, OUT_OF_OFFICE, OFF_WORK.
93+
Possible values are AVAILABLE, BUSY, AWAY, ON_THE_PHONE, BE_RIGHT_BACK, IN_A_MEETING, OUT_OF_OFFICE, OFF_WORK.
9494
:param soft: If true, the user's current status is taken into consideration. If the user is currently OFFLINE,
95-
the user's presence will still be OFFLINE, but the new presence will take effect when the user comes online. If
96-
the user is currently online, the user's activity state will be applied to the presence if applicable. (e.g. if
97-
you are setting their presence to AVAILABLE, but the user is currently idle, their status will be represented as
98-
AWAY)
95+
the user's presence will still be OFFLINE, but the new presence will take effect when the user comes online. If
96+
the user is currently online, the user's activity state will be applied to the presence if applicable. (e.g. if
97+
you are setting their presence to AVAILABLE, but the user is currently idle, their status will be represented as
98+
AWAY)
9999
:return: Presence info of the calling user.
100100
"""
101101
presence_status: V2PresenceStatus = V2PresenceStatus(category=status.name)
@@ -121,7 +121,7 @@ async def read_presence_feed(self, feed_id: str) -> List[V2Presence]:
121121
See: `Read Presence Feed <https://developers.symphony.com/restapi/reference#read-presence-feed>`_.
122122
123123
:param feed_id: The presence feed id to be read.
124-
:return:The list of user presences has changed since the last presence read.
124+
:return: The list of user presences has changed since the last presence read.
125125
"""
126126
return await self._presence_api.v1_presence_feed_feed_id_read_get(
127127
session_token=await self._auth_session.session_token,
@@ -145,12 +145,12 @@ async def set_user_presence(self, user_id: int, status: PresenceStatus, soft: bo
145145
146146
:param user_id: The id of the specified user.
147147
:param status: Presence state to set.
148-
Possible values are AVAILABLE, BUSY, AWAY, ON_THE_PHONE, BE_RIGHT_BACK, IN_A_MEETING, OUT_OF_OFFICE, OFF_WORK.
148+
Possible values are AVAILABLE, BUSY, AWAY, ON_THE_PHONE, BE_RIGHT_BACK, IN_A_MEETING, OUT_OF_OFFICE, OFF_WORK.
149149
:param soft: If true, the user's current status is taken into consideration. If the user is currently OFFLINE,
150-
the user's presence will still be OFFLINE, but the new presence will take effect when the user comes online. If
151-
the user is currently online, the user's activity state will be applied to the presence if applicable. (e.g. if
152-
you are setting their presence to AVAILABLE, but the user is currently idle, their status will be represented as
153-
AWAY)
150+
the user's presence will still be OFFLINE, but the new presence will take effect when the user comes online. If
151+
the user is currently online, the user's activity state will be applied to the presence if applicable. (e.g. if
152+
you are setting their presence to AVAILABLE, but the user is currently idle, their status will be represented as
153+
AWAY)
154154
:return: The presence info of the specified user.
155155
"""
156156
user_presence: V2UserPresence = V2UserPresence(category=status.name, user_id=user_id)

symphony/bdk/core/service/signal/__init__.py

Whitespace-only changes.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,153 @@
1+
from symphony.bdk.core.auth.auth_session import AuthSession
2+
from symphony.bdk.gen.agent_api.signals_api import SignalsApi
3+
from symphony.bdk.gen.agent_model.base_signal import BaseSignal
4+
from symphony.bdk.gen.agent_model.channel_subscriber import ChannelSubscriber
5+
from symphony.bdk.gen.agent_model.channel_subscription_response import ChannelSubscriptionResponse
6+
from symphony.bdk.gen.agent_model.signal import Signal
7+
from symphony.bdk.gen.agent_model.signal_list import SignalList
8+
9+
10+
class OboSignalService:
11+
"""Service class exposing OBO-enabled endpoints to manage signal information.
12+
13+
This service is used for listing signals related to the OBO user, get information of a specified signal
14+
or perform some actions related to the signal like:
15+
16+
* List signals
17+
* Get a signal
18+
* Create a signal
19+
* Update a signal
20+
* Delete a signal
21+
* Subscribe or unsubscribe a signal
22+
"""
23+
24+
def __init__(self, signals_api: SignalsApi, auth_session: AuthSession):
25+
self._signals_api = signals_api
26+
self._auth_session = auth_session
27+
28+
async def list_signals(self, skip: int = 0, limit: int = 50) -> SignalList:
29+
""" Lists signals on behalf of the user. The response includes signals that the user has created and
30+
public signals to which they have subscribed.
31+
32+
See: 'List signals <https://developers.symphony.com/restapi/reference#list-signals>'_
33+
34+
:param skip: The number of signals to skip.
35+
:param limit: Maximum number of signals to return. Default is 50, maximum value is 500.
36+
:return: List of signals found.
37+
"""
38+
39+
return await self._signals_api.v1_signals_list_get(
40+
skip=skip, limit=limit, session_token=await self._auth_session.session_token,
41+
key_manager_token=await self._auth_session.key_manager_token)
42+
43+
async def get_signal(self, signal_id: str) -> Signal:
44+
""" Gets details about the specified signal.
45+
46+
See: 'Get signal <https://developers.symphony.com/restapi/reference#get-signal>'_
47+
48+
:param signal_id: Id of the signal to display.
49+
:return: The signal found.
50+
"""
51+
52+
return await self._signals_api.v1_signals_id_get_get(
53+
id=signal_id, session_token=await self._auth_session.session_token,
54+
key_manager_token=await self._auth_session.key_manager_token)
55+
56+
async def create_signal(self, signal: BaseSignal) -> Signal:
57+
""" Creates a new Signal.
58+
59+
See: 'Create signal <https://developers.symphony.com/restapi/reference#create-signal>'_
60+
61+
:param signal: The new Signal object to be created.
62+
:return: The signal created.
63+
"""
64+
65+
return await self._signals_api.v1_signals_create_post(
66+
signal=signal, session_token=await self._auth_session.session_token,
67+
key_manager_token=await self._auth_session.key_manager_token)
68+
69+
async def update_signal(self, signal_id: str, signal: BaseSignal) -> Signal:
70+
""" Updates an existing Signal.
71+
72+
See: 'Update signal <https://developers.symphony.com/restapi/reference#update-signal>'_
73+
74+
:param signal_id: The Id of the signal to be modified.
75+
:param signal: The Signal object to be updated.
76+
:return: The updated signal.
77+
"""
78+
79+
return await self._signals_api.v1_signals_id_update_post(
80+
id=signal_id, signal=signal, session_token=await self._auth_session.session_token,
81+
key_manager_token=await self._auth_session.key_manager_token)
82+
83+
async def delete_signal(self, signal_id: str) -> None:
84+
""" Deletes an existing Signal.
85+
86+
See: 'Delete signal <https://developers.symphony.com/restapi/reference#delete-signal>'_
87+
88+
:param signal_id: The Id of the existing signal to be deleted.
89+
"""
90+
91+
return await self._signals_api.v1_signals_id_delete_post(
92+
id=signal_id, session_token=await self._auth_session.session_token,
93+
key_manager_token=await self._auth_session.key_manager_token)
94+
95+
async def subscribe_users_to_signal(self, signal_id: str, pushed: bool,
96+
user_ids: [int]) -> ChannelSubscriptionResponse:
97+
""" Subscribe an array of users to a Signal.
98+
99+
See: 'Subscribe signal <https://developers.symphony.com/restapi/reference#subscribe-signal>'_
100+
101+
:param signal_id: The Id of the signal to be subscribed.
102+
:param pushed: Prevents the user from unsubscribing from the Signal
103+
:param user_ids: An array of User Ids to subscribe to the Signal
104+
:return: Result of the bulk subscriptions
105+
"""
106+
107+
return await self._signals_api.v1_signals_id_subscribe_post(
108+
id=signal_id, pushed=pushed, users=user_ids, session_token=await self._auth_session.session_token,
109+
key_manager_token=await self._auth_session.key_manager_token)
110+
111+
async def unsubscribe_users_to_signal(self, signal_id: str, user_ids: [int]) -> ChannelSubscriptionResponse:
112+
""" Unsubscribes an array of users from the specified Signal.
113+
114+
See: 'Unsubscribe signal <https://developers.symphony.com/restapi/reference#unsubscribe-signal>'_
115+
116+
:param signal_id: The Id of the signal to be subscribed.
117+
:param user_ids: An array of User Ids to subscribe to the Signal
118+
:return: Result of the bulk unsubscriptions
119+
"""
120+
121+
return await self._signals_api.v1_signals_id_unsubscribe_post(
122+
id=signal_id, users=user_ids, session_token=await self._auth_session.session_token,
123+
key_manager_token=await self._auth_session.key_manager_token)
124+
125+
async def list_subscribers(self, signal_id: str, skip: int = 0, limit: int = 50) -> [ChannelSubscriber]:
126+
""" Gets the subscribers for the specified signal.
127+
128+
See: 'Subscribers <https://developers.symphony.com/restapi/reference#subscribers>'_
129+
130+
:param signal_id: The Id of the signal.
131+
:param skip: The number of results to skip.
132+
:param limit: The maximum number of subscribers to return. The maximum value accepted for this parameter is 100
133+
and the default value is 50.
134+
:return: The list of users subscribed to the signal.
135+
"""
136+
137+
return await self._signals_api.v1_signals_id_subscribers_get(
138+
id=signal_id, skip=skip, limit=limit, session_token=await self._auth_session.session_token,
139+
key_manager_token=await self._auth_session.key_manager_token)
140+
141+
142+
class SignalService(OboSignalService):
143+
"""Service class for managing signal information.
144+
This service is used for listing signals related to the user, get information of a specified signal
145+
or perform some actions related to the signal like:
146+
147+
* List signals
148+
* Get a signal
149+
* Create a signal
150+
* Update a signal
151+
* Delete a signal
152+
* Subscribe or unsubscribe a signal
153+
"""

0 commit comments

Comments
 (0)