Commit 5612de6d by Oleksandr Barabash

api for sending messages added

parent f07a07e2
......@@ -4,6 +4,7 @@ import sys
import traceback
from datetime import datetime
from http import HTTPStatus
from typing import Dict, Union, List
import marshmallow_dataclass
from aiohttp import web
......@@ -24,6 +25,7 @@ from config import AppConfig, COSMOS_CLIENT, TeamsAppConfig, TOKEN_HELPER, \
CosmosDBConfig
from entities.json.admin_user import AdminUser
from entities.json.notification import Notification
from entities.json.pa_message import PAMessage
from utils.cosmos_client import ItemNotFound
from utils.functions import quote_b64encode_str_safe, quote_b64decode_str_safe
from utils.json_func import json_loads, json_dumps
......@@ -76,6 +78,16 @@ async def on_error(context: TurnContext, error: Exception):
ADAPTER.on_turn_error = on_error
def make_response(code: int, message: str,
data: Union[Dict[any, any], List[Dict[any, any]]] = None)\
-> Response:
""" Make an API json response """
body = dict(status=dict(code=code, message=message))
if data is not None:
body.update(dict(data=data))
return Response(status=HTTPStatus.OK, body=json_dumps(body))
@TOKEN_HELPER.is_auth
async def v1_get_initiations(request: Request) -> Response:
""" Get Initiations by Notification ID """
......@@ -234,6 +246,24 @@ async def v1_post_auth(request: Request) -> Response:
return Response(status=HTTPStatus.FORBIDDEN)
async def v1_pa_message(request: Request) -> Response:
""" Send card to the bot """
# noinspection PyBroadException
try:
body = json_loads(await request.text())
pa_message = marshmallow_dataclass.class_schema(PAMessage)().load(body)
notification_id = await BOT.send_message(pa_message.conversation_id,
pa_message.tenant_id,
pa_message.text,
pa_message.card)
Log.d(TAG, f"v1_pa_message::notification: '{notification_id}'")
except Exception:
Log.e(TAG, "v1_pa_message::error sending message",
exc_info=sys.exc_info())
return make_response(500, "Server Error")
return make_response(400, "Bad Request")
async def init_db_containers():
""" To speed up the process we have to create containers first """
await COSMOS_CLIENT.create_db(CosmosDBConfig.Conversations.DATABASE)
......@@ -275,6 +305,8 @@ async def app_factory(bot):
app.router.add_get("/{}".format(TeamsAppConfig.zip_name), v1_get_app_zip)
app.router.add_post("/api/v1/auth", v1_post_auth)
# PA endpoints
app.router.add_post("/api/pa/v1/message", v1_pa_message)
bot.add_web_app(app)
bot.add_cosmos_client(COSMOS_CLIENT)
......
......@@ -2,13 +2,13 @@
import asyncio
import uuid
from asyncio import Future
from typing import Optional
from typing import Optional, Dict
from urllib.parse import urlparse, parse_qsl, urlencode
from aiohttp.web_app import Application
from botbuilder.core import (TurnContext, CardFactory, BotFrameworkAdapter,
BotFrameworkAdapterSettings)
from botbuilder.schema import Activity, ActivityTypes
from botbuilder.schema import Activity, ActivityTypes, ResourceResponse
from botbuilder.schema.teams import (TaskModuleContinueResponse,
TaskModuleTaskInfo, TaskModuleResponse,
TaskModuleRequest)
......@@ -79,6 +79,49 @@ class TeamsMessagingExtensionsActionPreviewBot(TeamsActivityHandler):
mx = turn_context.activity.value.get("mx", {})
return mx.get("notificationId", None)
def send_message(self,
conversation_id: str,
tenant_id: str, text: str = None,
card: Dict[any, any] = None) -> Future[ResourceResponse]:
""" Send message as a bot """
io_loop = asyncio.get_event_loop()
future = Future()
async def routine():
""" async routine """
try:
reference = await self.cosmos_client.get_conversation(
conversation_id, tenant_id
)
except ItemNotFound:
future.set_exception(ConversationNotFound("not found"))
return
except Exception as e:
future.set_exception(e)
return
async def callback(turn_context: TurnContext) -> None:
""" Turn Context callback. Kinda awful syntax, I know """
try:
attachments = None
if card is not None:
attachments = [CardFactory.adaptive_card(card)]
response = await turn_context.send_activity(Activity(
type=ActivityTypes.message,
text=text,
attachments=attachments)
)
if response:
future.set_result(response)
except Exception as exception:
future.set_exception(exception)
await self.adapter.continue_conversation(reference, callback,
self.settings.app_id)
io_loop.create_task(routine())
return future
def send_notification(self, notification: NotificationCosmos)\
-> Future[str]:
""" Notify conversation that there's a message waiting in portal """
......
......@@ -327,14 +327,14 @@ class CosmosClient:
except ItemNotFound:
return None
async def get_conversation(self, conversation_id: str)\
-> ConversationReference:
async def get_conversation(self, conversation_id: str,
tenant_id: str = None) -> 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)
tenant_id or AppConfig.TENANT_ID)
return ConversationReference.get_schema(unknown=EXCLUDE)\
.load(item).to_ms_reference()
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment