Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

msgext-search-auth-config python code fix and image update #1476

Merged
merged 3 commits into from
Jan 6, 2025
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file modified samples/msgext-search-auth-config/python/Images/1-add_app.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified samples/msgext-search-auth-config/python/Images/3.search.PNG
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified samples/msgext-search-auth-config/python/Images/6.search.PNG
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified samples/msgext-search-auth-config/python/Images/7.search.PNG
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
7 changes: 3 additions & 4 deletions samples/msgext-search-auth-config/python/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -118,12 +118,11 @@ Once the Messaging Extension is installed, click the icon for **Config Auth Sear

![search ](Images/3.search.PNG)

![search ](Images/4.search.PNG)

![search ](Images/5.search.PNG)

![search ](Images/6.search.PNG)

![search ](Images/7.search.PNG)

![search ](Images/8.zero_install.PNG)

## Deploy the bot to Azure

Expand Down
2 changes: 1 addition & 1 deletion samples/msgext-search-auth-config/python/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
TurnContext,
BotFrameworkAdapter,
MemoryStorage,
UserState,
UserState
)
from botbuilder.core.integration import aiohttp_error_middleware

Expand Down
23 changes: 18 additions & 5 deletions samples/msgext-search-auth-config/python/appManifest/manifest.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"$schema": "https://developer.microsoft.com/json-schemas/teams/v1.19/MicrosoftTeams.schema.json",
"manifestVersion": "1.19",
Harikrishnan-MSFT marked this conversation as resolved.
Show resolved Hide resolved
"$schema": "https://developer.microsoft.com/json-schemas/teams/v1.16/MicrosoftTeams.schema.json",
"manifestVersion": "1.16",
"version": "1.0.0",
"id": "${{TEAMS_APP_ID}}",
"packageName": "com.microsoft.teams.sample",
Expand All @@ -15,8 +15,8 @@
"outline": "icon-outline.png"
},
"name": {
"short": "Config Auth Search",
"full": "Config Auth Search"
"short": "Messaging Extension Auth",
"full": "ME Auth for Search, Action and link unfurling"
},
"description": {
"short": "Python Messaging Extension with authentication and configuration page.",
Expand All @@ -37,7 +37,8 @@
"fetchTask": false,
"context": [
"commandBox",
"compose"
"compose",
"message"
],
"parameters": [
{
Expand Down Expand Up @@ -67,6 +68,18 @@
}
]
}
],
"messageHandlers": [
{
"type": "link",
"value": {
"domains": [
"*.botframework.com",
"${{BOT_DOMAIN}}"
],
"supportsAnonymizedPayloads": true
}
}
]
}
],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,16 @@
# Licensed under the MIT License.

import urllib.parse
import xmlrpc.client
from botbuilder.core import CardFactory, MessageFactory, TurnContext, UserState
from botbuilder.schema import (
ThumbnailCard,
CardImage,
HeroCard,
CardAction,
ActionTypes,
InvokeResponse
)
from bs4 import BeautifulSoup
from botbuilder.schema.teams import (
MessagingExtensionAction,
MessagingExtensionAttachment,
Expand All @@ -21,6 +23,8 @@
TaskModuleContinueResponse,
TaskModuleTaskInfo,
)
import requests
from http import HTTPStatus
from botbuilder.core.teams import TeamsActivityHandler
from simple_graph_client import SimpleGraphClient

Expand Down Expand Up @@ -77,6 +81,66 @@ async def on_teams_messaging_extension_configuration_query_settings_url(
)
)

async def on_invoke_activity(self, turn_context: TurnContext):
if turn_context.activity.name == "composeExtension/anonymousQueryLink":
# Handle the anonymous query link
response = await self.handle_teams_app_based_anonymous_link_query(
turn_context, turn_context.activity.value
)
return InvokeResponse(status=HTTPStatus.OK, body=self.convert_to_dict(response))
else:
return await super().on_invoke_activity(turn_context)

async def handle_teams_app_based_anonymous_link_query(self, turn_context: TurnContext, value):
# Create the Adaptive Card JSON directly
adaptive_card = {
"type": "AdaptiveCard",
"version": "1.5",
"body": [
{
"type": "TextBlock",
"text": "Zero Installation Link Unfurling Card",
"size": "ExtraLarge",
},
{
"type": "TextBlock",
"text": "Install the app or sign in to view full content of the card.",
"size": "Medium",
},
],
}
# Create a MessagingExtensionAttachment for the card
attachment = MessagingExtensionAttachment(
content_type="application/vnd.microsoft.card.adaptive",
content=adaptive_card,
)
# Create a MessagingExtensionResult
result = MessagingExtensionResult(
attachment_layout="list",
type="auth",
attachments=[attachment],
)
# Return the MessagingExtensionResponse
return MessagingExtensionResponse(compose_extension=result)

def convert_to_dict(self, response: MessagingExtensionResponse) -> dict:
Jegadeesh-MSFT marked this conversation as resolved.
Show resolved Hide resolved
"""Manually convert MessagingExtensionResponse and MessagingExtensionResult to a JSON-serializable dictionary."""
compose_extension = response.compose_extension
# Manually serialize the MessagingExtensionResult
result_dict = {
"attachmentLayout": compose_extension.attachment_layout,
"type": compose_extension.type,
"attachments": [
{
"contentType": attachment.content_type,
"content": attachment.content,
}
for attachment in compose_extension.attachments
],
}
# Return the dictionary in the expected format
return {"composeExtension": result_dict}

async def on_teams_messaging_extension_configuration_setting(
self, turn_context: TurnContext, settings
):
Expand Down Expand Up @@ -118,14 +182,14 @@ async def on_teams_messaging_extension_query(
content_type=CardFactory.content_types.hero_card,
content=HeroCard(title=obj["name"]),
preview=CardFactory.hero_card(hero_card),
)
)
attachments.append(attachment)
return MessagingExtensionResponse(
compose_extension=MessagingExtensionResult(
type="result", attachment_layout="list", attachments=attachments
)
)

async def _get_auth_or_search_result(
self,
turn_context: TurnContext,
Expand Down Expand Up @@ -246,10 +310,10 @@ async def on_teams_messaging_extension_fetch_task(
card=card, height=200, title="Adaptive Card Example", width=400
)
continue_response = TaskModuleContinueResponse(
type="continue", value=task_info
value=task_info
)
return MessagingExtensionActionResponse(task=continue_response)

return None

async def on_teams_messaging_extension_select_item(
Expand All @@ -275,6 +339,40 @@ async def on_teams_messaging_extension_select_item(
)

def _get_search_results(self, query: str):
client = xmlrpc.client.ServerProxy("https://pypi.org/pypi")
search_results = client.search({"name": query})
return search_results[:10] if len(search_results) > 10 else search_results
"""
Fetch the top 10 search results from PyPI using HTML scraping.

:param query: The package name or search query
:return: List of search results
"""
search_url = f"https://pypi.org/search/?q={query}&page=1"
Jegadeesh-MSFT marked this conversation as resolved.
Show resolved Hide resolved
search_results = []

try:
# Send GET request to the PyPI search page
response = requests.get(search_url, headers={"User-Agent": "TeamsBot/1.0"})
Jegadeesh-MSFT marked this conversation as resolved.
Show resolved Hide resolved
response.raise_for_status() # Raise an exception for HTTP errors

# Parse the HTML response to extract package information
soup = BeautifulSoup(response.text, "html.parser")
for package in soup.find_all("a", class_="package-snippet", limit=10): # Limit to 10 results
name_tag = package.find("span", class_="package-snippet__name")
version_tag = package.find("span", class_="package-snippet__version")
summary_tag = package.find("p", class_="package-snippet__description")

# Safely extract text from tags, ensuring no NoneType error
name = name_tag.text if name_tag else "Unknown"
version = version_tag.text if version_tag else "N/A"
summary = summary_tag.text if summary_tag else "No description provided."

search_results.append({
"name": name,
"version": version,
"summary": summary
})
except requests.exceptions.RequestException as e:
print(f"Error fetching search results: {e}")
except Exception as e:
print(f"An unexpected error occurred: {e}")

return search_results
2 changes: 1 addition & 1 deletion samples/msgext-search-auth-config/python/requirements.txt
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
botbuilder-integration-aiohttp>=4.14.0
botbuilder-integration-aiohttp>=4.16.2
requests_oauthlib>=1.3.0