Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
C
cake-bot
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Oleksandr Barabash
cake-bot
Commits
a168a012
Commit
a168a012
authored
May 12, 2022
by
Oleksandr Barabash
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
updates on structures, error handlers added
parent
761d2bd9
Show whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
126 additions
and
40 deletions
+126
-40
messaging_extension_action_preview_bot.py
bots/messaging_extension_action_preview_bot.py
+17
-27
config.py
config.py
+4
-7
conversation_reference.py
entities/json/conversation_reference.py
+80
-0
cosmos_client.py
utils/cosmos_client.py
+25
-6
No files found.
bots/messaging_extension_action_preview_bot.py
View file @
a168a012
""" Message extension bot """
""" Message extension bot """
import
asyncio
import
asyncio
import
uuid
from
asyncio
import
Future
from
asyncio
import
Future
from
typing
import
Optional
from
typing
import
Optional
from
urllib.parse
import
urlparse
,
parse_qsl
,
urlencode
from
urllib.parse
import
urlparse
,
parse_qsl
,
urlencode
...
@@ -16,12 +17,11 @@ from marshmallow import EXCLUDE
...
@@ -16,12 +17,11 @@ from marshmallow import EXCLUDE
from
bots.exceptions
import
ConversationNotFound
from
bots.exceptions
import
ConversationNotFound
from
config
import
TaskModuleConfig
,
AppConfig
from
config
import
TaskModuleConfig
,
AppConfig
from
entities.json.acknowledge
import
Acknowledge
from
entities.json.conversation_reference_schema
import
(
from
entities.json.conversation_reference_schema
import
(
ConversationReferenceSchema
ConversationReferenceSchema
)
)
from
entities.json.medx
import
MedX
,
MXTypes
from
entities.json.medx
import
MedX
,
MXTypes
from
entities.json.notification
import
Notification
,
Notification
Cosmos
from
entities.json.notification
import
NotificationCosmos
from
utils.card_helper
import
CardHelper
from
utils.card_helper
import
CardHelper
from
utils.cosmos_client
import
CosmosClient
,
ItemNotFound
from
utils.cosmos_client
import
CosmosClient
,
ItemNotFound
from
utils.function
import
get_first_or_none
from
utils.function
import
get_first_or_none
...
@@ -83,23 +83,31 @@ class TeamsMessagingExtensionsActionPreviewBot(TeamsActivityHandler):
...
@@ -83,23 +83,31 @@ class TeamsMessagingExtensionsActionPreviewBot(TeamsActivityHandler):
future
=
Future
()
future
=
Future
()
# reset parameters
# reset parameters
notification
.
id
=
None
notification
.
id
=
uuid
.
uuid4
()
.
__str__
()
notification
.
tenant_id
=
AppConfig
.
TENANT_ID
notification
.
tenant_id
=
AppConfig
.
TENANT_ID
async
def
routine
():
async
def
routine
():
""" async routine """
""" async routine """
_saved_notification
=
await
self
.
cosmos_client
.
create_notification
(
try
:
notification
reference
=
await
self
.
cosmos_client
.
get_conversation
(
notification
.
destination
)
)
destination
=
notification
.
destination
except
ItemNotFound
:
reference
=
await
self
.
get_conversation_reference
(
destination
)
future
.
set_exception
(
ConversationNotFound
(
"not found"
))
except
Exception
as
e
:
future
.
set_exception
(
e
)
return
async
def
callback
(
turn_context
:
TurnContext
)
->
None
:
async
def
callback
(
turn_context
:
TurnContext
)
->
None
:
""" Turn Context callback. Kinda awful syntax, I know """
""" Turn Context callback. Kinda awful syntax, I know """
# TODO(s1z): Add exception handler
# TODO(s1z): Add exception handler
# (like conversation not found etc...)
# (like conversation not found etc...)
try
:
try
:
card
=
CardHelper
.
create_notification_card
(
notification
)
card
=
CardHelper
.
create_notification_card
(
await
self
.
cosmos_client
.
create_notification
(
notification
)
)
attachments
=
[
CardFactory
.
adaptive_card
(
card
)]
attachments
=
[
CardFactory
.
adaptive_card
(
card
)]
message
=
Activity
(
type
=
ActivityTypes
.
message
,
message
=
Activity
(
type
=
ActivityTypes
.
message
,
attachments
=
attachments
)
attachments
=
attachments
)
...
@@ -122,27 +130,9 @@ class TeamsMessagingExtensionsActionPreviewBot(TeamsActivityHandler):
...
@@ -122,27 +130,9 @@ class TeamsMessagingExtensionsActionPreviewBot(TeamsActivityHandler):
# noinspection PyProtectedMember
# noinspection PyProtectedMember
return
parsed_url
.
_replace
(
query
=
urlencode
(
params
))
.
geturl
()
return
parsed_url
.
_replace
(
query
=
urlencode
(
params
))
.
geturl
()
# noinspection SqlNoDataSourceInspection,SqlDialectInspection
async
def
get_conversation_reference
(
self
,
conversation_id
:
Optional
[
str
])
\
->
ConversationReference
:
""" Get conversation reference from DB """
if
conversation_id
is
None
:
raise
ConversationNotFound
(
"conversation_id is None"
)
container
=
await
self
.
cosmos_client
.
get_conversations_container
()
tenant_id
=
AppConfig
.
TENANT_ID
item
=
get_first_or_none
(
list
(
container
.
query_items
(
query
=
f
"SELECT * FROM c WHERE c.id=@id"
,
partition_key
=
tenant_id
,
parameters
=
[{
"name"
:
"@id"
,
"value"
:
conversation_id
}],
)))
if
item
is
None
:
raise
ConversationNotFound
(
"conversation_id is not Found"
)
return
ConversationReferenceSchema
(
unknown
=
EXCLUDE
)
.
load
(
item
)
async
def
on_conversation_update_activity
(
self
,
turn_context
:
TurnContext
):
async
def
on_conversation_update_activity
(
self
,
turn_context
:
TurnContext
):
""" On update conversation """
""" On update conversation """
print
(
"activity:"
,
turn_context
.
activity
)
await
self
.
cosmos_client
.
create_conversation_reference
(
turn_context
)
await
self
.
cosmos_client
.
create_conversation_reference
(
turn_context
)
async
def
handle_submit_action
(
self
,
turn_context
:
TurnContext
)
->
None
:
async
def
handle_submit_action
(
self
,
turn_context
:
TurnContext
)
->
None
:
...
...
config.py
View file @
a168a012
...
@@ -24,16 +24,13 @@ class AppConfig:
...
@@ -24,16 +24,13 @@ class AppConfig:
""" Bot Configuration """
""" Bot Configuration """
PORT
=
os
.
environ
.
get
(
"HOST_PORT"
,
8000
)
PORT
=
os
.
environ
.
get
(
"HOST_PORT"
,
8000
)
# APP_ID = os.environ.get("MS_APP_ID",
# "d472f12a-323b-4058-b89b-7a4b15c48ab7")
# APP_PASSWORD = os.environ.get("MS_APP_PASSWORD",
# "ZdL|zw:]Io_}goFfWs2{w70g+.FXwQ")
TENANT_ID
=
os
.
environ
.
get
(
"TENANT_ID"
,
TENANT_ID
=
os
.
environ
.
get
(
"TENANT_ID"
,
"5df91ebc-64fa-4aa1-862c-bdc0cba3c656"
)
"5df91ebc-64fa-4aa1-862c-bdc0cba3c656"
)
APP_PASSWORD
=
os
.
environ
.
get
(
"MS_APP_PASSWORD"
,
"ahO8Q~tSDvGJUcfN8ACZ51e21hh411vLwkal_dv."
)
APP_ID
=
os
.
environ
.
get
(
"MS_APP_ID"
,
APP_ID
=
os
.
environ
.
get
(
"MS_APP_ID"
,
"82109577-846a-442d-9320-776148d77442"
)
"34b032df-9532-48f8-a8a1-0e864f9e5562"
)
APP_PASSWORD
=
os
.
environ
.
get
(
"MS_APP_PASSWORD"
,
"7Ll8Q~XeV3D8vNmM3Q4BNyxYUcMrM1SQtghOndxT"
)
class
CosmosDBConfig
:
class
CosmosDBConfig
:
...
...
entities/json/conversation_reference.py
0 → 100644
View file @
a168a012
""" Conversation reference object """
from
dataclasses
import
dataclass
,
field
from
typing
import
Optional
,
Any
,
Dict
from
botbuilder.schema
import
(
ConversationReference
as
MSConversationReference
,
ConversationAccount
,
ChannelAccount
)
from
entities.json.camel_case_mixin
import
CamelCaseMixin
,
timestamp_factory
@dataclass
class
Account
(
CamelCaseMixin
):
""" Account Channel object """
id
:
str
# This is a bullshit, microsoft sends null name!
name
:
Optional
[
str
]
=
field
(
default
=
None
)
# may be null if it's a bot
aad_object_id
:
Optional
[
str
]
=
field
(
default
=
None
)
role
:
Optional
[
str
]
=
field
(
default
=
None
)
@dataclass
class
Conversation
(
CamelCaseMixin
):
""" Conversation URL """
id
:
str
tenant_id
:
str
conversation_type
:
str
=
field
(
default
=
None
)
is_group
:
Optional
[
bool
]
=
field
(
default
=
None
)
name
:
Optional
[
str
]
=
field
(
default
=
None
)
aad_object_id
:
Optional
[
str
]
=
field
(
default
=
None
)
role
:
Optional
[
str
]
=
field
(
default
=
None
)
# Microsoft does not describe this object at all
properties
:
Optional
[
Dict
[
str
,
Any
]]
=
field
(
default
=
None
)
@dataclass
class
ConversationReference
(
CamelCaseMixin
):
""" Conversation Reference schema """
bot
:
Optional
[
Account
]
conversation
:
Conversation
channel_id
:
str
service_url
:
str
# has to be not null but MS sends null
locale
:
Optional
[
str
]
=
field
(
default
=
None
)
activity_id
:
Optional
[
str
]
=
field
(
default
=
None
)
user
:
Optional
[
Account
]
=
field
(
default
=
None
)
def
to_ms_reference
(
self
)
->
MSConversationReference
:
""" Convert dataclass to microsoft conversation reference object """
return
MSConversationReference
(
activity_id
=
self
.
activity_id
,
channel_id
=
self
.
channel_id
,
locale
=
self
.
locale
,
service_url
=
self
.
service_url
,
user
=
ChannelAccount
(
id
=
self
.
user
.
id
,
name
=
self
.
user
.
name
,
aad_object_id
=
self
.
user
.
aad_object_id
,
role
=
self
.
user
.
role
),
bot
=
ChannelAccount
(
id
=
self
.
bot
.
id
,
name
=
self
.
bot
.
name
,
aad_object_id
=
self
.
bot
.
aad_object_id
,
role
=
self
.
bot
.
role
),
conversation
=
ConversationAccount
(
is_group
=
self
.
conversation
.
is_group
,
conversation_type
=
self
.
conversation
.
conversation_type
,
id
=
self
.
conversation
.
id
,
name
=
self
.
conversation
.
name
,
aad_object_id
=
self
.
conversation
.
aad_object_id
,
role
=
self
.
conversation
.
role
,
tenant_id
=
self
.
conversation
.
tenant_id
,
properties
=
self
.
conversation
.
properties
)
)
utils/cosmos_client.py
View file @
a168a012
...
@@ -15,6 +15,7 @@ from marshmallow import EXCLUDE
...
@@ -15,6 +15,7 @@ from marshmallow import EXCLUDE
from
entities.json.acknowledge
import
Acknowledge
from
entities.json.acknowledge
import
Acknowledge
from
entities.json.acknowledge_schema
import
AcknowledgeSchema
from
entities.json.acknowledge_schema
import
AcknowledgeSchema
from
entities.json.camel_case_mixin
import
timestamp_factory
from
entities.json.camel_case_mixin
import
timestamp_factory
from
entities.json.conversation_reference
import
ConversationReference
from
entities.json.conversation_reference_schema
import
\
from
entities.json.conversation_reference_schema
import
\
ConversationReferenceSchema
ConversationReferenceSchema
from
entities.json.initiation
import
Initiation
from
entities.json.initiation
import
Initiation
...
@@ -188,7 +189,6 @@ class CosmosClient:
...
@@ -188,7 +189,6 @@ class CosmosClient:
body
.
update
(
dict
(
id
=
uuid
.
uuid4
()
.
__str__
()))
body
.
update
(
dict
(
id
=
uuid
.
uuid4
()
.
__str__
()))
while
tries
<
max_tries
:
while
tries
<
max_tries
:
try
:
try
:
return
await
self
.
execute_blocking
(
bl
)
return
await
self
.
execute_blocking
(
bl
)
except
exceptions
.
CosmosHttpResponseError
as
e
:
except
exceptions
.
CosmosHttpResponseError
as
e
:
...
@@ -282,6 +282,17 @@ class CosmosClient:
...
@@ -282,6 +282,17 @@ class CosmosClient:
except
ItemNotFound
:
except
ItemNotFound
:
return
None
return
None
async
def
get_conversation
(
self
,
conversation_id
:
str
)
\
->
ConversationReference
:
""" Get Conversation Reference """
from
config
import
AppConfig
container
=
await
self
.
get_conversations_container
()
item
=
await
self
.
get_item
(
container
,
conversation_id
,
AppConfig
.
TENANT_ID
)
return
ConversationReference
.
get_schema
(
unknown
=
EXCLUDE
)
\
.
load
(
item
)
.
to_ms_reference
()
async
def
get_notification
(
self
,
notification_id
:
str
)
\
async
def
get_notification
(
self
,
notification_id
:
str
)
\
->
NotificationCosmos
:
->
NotificationCosmos
:
""" Get Notification """
""" Get Notification """
...
@@ -299,15 +310,23 @@ class CosmosClient:
...
@@ -299,15 +310,23 @@ class CosmosClient:
activity
=
turn_context
.
activity
activity
=
turn_context
.
activity
reference
=
TurnContext
.
get_conversation_reference
(
activity
)
reference
=
TurnContext
.
get_conversation_reference
(
activity
)
reference_dict
=
ConversationReferenceSchema
()
.
dump
(
reference
)
reference_json
=
ConversationReference
.
get_schema
()
.
dump
(
reference
)
# reference_dict = ConversationReferenceSchema().dump(reference)
container
=
await
self
.
get_conversations_container
()
container
=
await
self
.
get_conversations_container
()
reference_
dict
.
update
({
reference_
json
.
update
({
CosmosDBConfig
.
Conversations
.
PK
:
reference
.
conversation
.
id
CosmosDBConfig
.
Conversations
.
PK
:
reference
.
conversation
.
id
})
})
def
bl
()
->
Dict
[
str
,
str
]:
""" Potential blocking code """
return
container
.
create_item
(
body
=
reference_json
)
try
:
try
:
await
self
.
create_item
(
container
,
body
=
reference_dict
,
max_tries
=
1
)
return
await
self
.
execute_blocking
(
bl
)
except
ItemExists
:
except
exceptions
.
CosmosHttpResponseError
as
e
:
pass
if
e
.
status_code
==
409
:
# Already exists
return
raise
SaveItemError
(
e
.
http_error_message
)
async
def
create_initiation
(
self
,
initiator
:
str
,
async
def
create_initiation
(
self
,
initiator
:
str
,
notification_id
:
str
)
->
None
:
notification_id
:
str
)
->
None
:
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment