-
Notifications
You must be signed in to change notification settings - Fork 20
Implement ReactionClient for message reactions API #280
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
Merged
Merged
Changes from all commits
Commits
Show all changes
11 commits
Select commit
Hold shift + click to select a range
c2be33a
Initial plan
Copilot 028422c
Implement ReactionClient for message reactions API
Copilot 4f05e0d
Complete ReactionClient implementation with validation
Copilot c4e1da2
Add reactions example demonstrating ReactionClient usage
Copilot a554f84
Refactor reaction handling by removing validation and simplifying res…
rido-min 4ebab44
Remove unsupported reaction types from help message in reaction handling
rido-min e017c73
Merge branch 'main' into copilot/implement-reactions-feature
rido-min 3d4551b
Refactor message reactions example and update reaction types for cons…
rido-min 8de3c5a
Remove microsoft-teams-devtools dependency from reactions example
rido-min d7c9f20
update test with assertions and venv activate
6c3209e
update uv lock
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,61 @@ | ||
| # Example: Message Reactions | ||
|
|
||
| A bot that demonstrates adding and removing reactions to messages in Microsoft Teams. | ||
|
|
||
| This example shows how to use the `ReactionClient` to programmatically add and remove reactions (like, heart, laugh, etc.) on messages. | ||
|
|
||
| ## Commands | ||
|
|
||
| | Command | Behavior | | ||
| |---------|----------| | ||
| | `react <type>` | Adds a reaction to your message (e.g., `react like`, `react heart`) | | ||
| | `unreact <type>` | Removes a reaction from your message | | ||
| | `help` | Shows available commands | | ||
|
|
||
| ## Supported Reaction Types | ||
|
|
||
| - `like` - 👍 Like | ||
| - `heart` - ❤️ Heart | ||
| - `laugh` - 😂 Laugh | ||
| - `surprised` - 😮 Surprised | ||
| - `sad` - 😢 Sad | ||
| - `angry` - 😠 Angry | ||
| - `plusOne` - ➕ Plus one | ||
|
|
||
| ## How It Works | ||
|
|
||
| The bot listens for incoming messages and: | ||
| 1. When you send `react <type>`, it adds that reaction to your message | ||
| 2. When you send `unreact <type>`, it removes that reaction from your message | ||
|
|
||
| The reactions are added/removed using the Bot Framework v3 API: | ||
| - **Add**: `PUT /v3/conversations/{conversationId}/activities/{activityId}/reactions/{reactionType}` | ||
| - **Remove**: `DELETE /v3/conversations/{conversationId}/activities/{activityId}/reactions/{reactionType}` | ||
|
|
||
| ## Testing | ||
|
|
||
| 1. Add the bot to a Teams chat or channel | ||
| 2. Send a message: `react like` | ||
| 3. **Expected result**: A 👍 reaction appears on your message | ||
| 4. Send another message: `unreact like` | ||
| 5. **Expected result**: The 👍 reaction is removed from that message | ||
|
|
||
| ## Run | ||
|
|
||
| ```bash | ||
| cd examples/reactions | ||
|
|
||
| # Activate venv | ||
| .venv\Scripts\activate | ||
|
|
||
| python src/main.py | ||
| ``` | ||
|
|
||
| ## Environment Variables | ||
|
|
||
| Create a `.env` file: | ||
|
|
||
| ```env | ||
| CLIENT_ID=<your-azure-bot-app-id> | ||
| CLIENT_SECRET=<your-azure-bot-app-secret> | ||
| ``` | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,14 @@ | ||
| [project] | ||
| name = "reactions" | ||
| version = "0.1.0" | ||
| description = "Message reactions example" | ||
| readme = "README.md" | ||
| requires-python = ">=3.12,<3.15" | ||
| dependencies = [ | ||
| "dotenv>=0.9.9", | ||
| "microsoft-teams-apps", | ||
| "microsoft-teams-api", | ||
| ] | ||
|
|
||
| [tool.uv.sources] | ||
| microsoft-teams-apps = { workspace = true } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,83 @@ | ||
| """ | ||
| Copyright (c) Microsoft Corporation. All rights reserved. | ||
| Licensed under the MIT License. | ||
| """ | ||
|
|
||
| import asyncio | ||
|
|
||
| from microsoft_teams.api import MessageActivity | ||
| from microsoft_teams.api.activities.typing import TypingActivityInput | ||
| from microsoft_teams.apps import ActivityContext, App | ||
|
|
||
| """ | ||
| Example: Message Reactions | ||
|
|
||
| A bot that demonstrates adding and removing reactions to messages in Microsoft Teams. | ||
| This example shows how to use the ReactionClient to programmatically add and remove | ||
| reactions (like, heart, laugh, etc.) on messages. | ||
| """ | ||
|
|
||
| app = App() | ||
|
|
||
|
|
||
| @app.on_message | ||
| async def handle_message(ctx: ActivityContext[MessageActivity]): | ||
| """Handle message activities.""" | ||
| await ctx.reply(TypingActivityInput()) | ||
|
|
||
| text = (ctx.activity.text or "").lower().strip() | ||
| conversation_id = ctx.activity.conversation.id | ||
| activity_id = ctx.activity.id | ||
|
|
||
| # ============================================ | ||
| # Add Reaction | ||
| # ============================================ | ||
| if text.startswith("react "): | ||
| reaction_type = text[6:].strip() | ||
|
|
||
| await ctx.api.reactions.add( | ||
| conversation_id=conversation_id, | ||
| activity_id=activity_id, | ||
| reaction_type=reaction_type, | ||
| ) | ||
|
|
||
| await ctx.reply(f"✅ Added {reaction_type} reaction to your message!") | ||
| print(f"[REACTION] Added '{reaction_type}' to activity {activity_id}") | ||
| return | ||
|
|
||
| # ============================================ | ||
| # Remove Reaction | ||
| # ============================================ | ||
| if text.startswith("unreact "): | ||
| reaction_type = text[8:].strip() | ||
|
|
||
| await ctx.api.reactions.delete( | ||
| conversation_id=conversation_id, | ||
| activity_id=activity_id, | ||
| reaction_type=reaction_type, | ||
| ) | ||
|
|
||
| await ctx.reply(f"✅ Removed {reaction_type} reaction from your message!") | ||
| print(f"[REACTION] Removed '{reaction_type}' from activity {activity_id}") | ||
| return | ||
|
|
||
| # ============================================ | ||
| # Help / Default | ||
| # ============================================ | ||
| if "help" in text: | ||
| await ctx.reply( | ||
| "**Message Reactions Bot**\n\n" | ||
| "**Commands:**\n" | ||
| "- `react <type>` - Add a reaction to your message\n" | ||
| "- `unreact <type>` - Remove a reaction from your message\n\n" | ||
| "- `react like` - Adds a 👍 to your message\n" | ||
| "- `unreact like` - Removes the 👍 from your message" | ||
| ) | ||
| return | ||
|
|
||
| # Default | ||
| await ctx.reply('Say "help" for available commands, or try "react like"!') | ||
|
lilyydu marked this conversation as resolved.
|
||
|
|
||
|
|
||
| if __name__ == "__main__": | ||
| asyncio.run(app.start()) | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
10 changes: 10 additions & 0 deletions
10
packages/api/src/microsoft_teams/api/clients/reaction/__init__.py
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,10 @@ | ||
| """ | ||
| Copyright (c) Microsoft Corporation. All rights reserved. | ||
| Licensed under the MIT License. | ||
| """ | ||
|
|
||
| from .client import ReactionClient | ||
|
|
||
| __all__ = [ | ||
| "ReactionClient", | ||
| ] |
73 changes: 73 additions & 0 deletions
73
packages/api/src/microsoft_teams/api/clients/reaction/client.py
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,73 @@ | ||
| """ | ||
| Copyright (c) Microsoft Corporation. All rights reserved. | ||
| Licensed under the MIT License. | ||
| """ | ||
|
|
||
| from typing import Optional | ||
|
|
||
| from microsoft_teams.common.http import Client | ||
|
|
||
| from ...models.message import MessageReactionType | ||
| from ..api_client_settings import ApiClientSettings | ||
| from ..base_client import BaseClient | ||
|
|
||
|
|
||
| class ReactionClient(BaseClient): | ||
| """ | ||
| Client for working with app message reactions for a given conversation/activity. | ||
| """ | ||
|
|
||
| def __init__( | ||
| self, | ||
| service_url: str, | ||
| http_client: Optional[Client] = None, | ||
| api_client_settings: Optional[ApiClientSettings] = None, | ||
| ): | ||
| """ | ||
| Initialize the reaction client. | ||
|
|
||
| Args: | ||
| service_url: The base URL for the Teams service | ||
| http_client: Optional HTTP client to use. If not provided, a new one will be created. | ||
| api_client_settings: Optional API client settings. | ||
| """ | ||
| super().__init__(http_client, api_client_settings) | ||
| self.service_url = service_url | ||
|
|
||
| async def add( | ||
| self, | ||
| conversation_id: str, | ||
| activity_id: str, | ||
| reaction_type: MessageReactionType, | ||
| ) -> None: | ||
| """ | ||
| Adds a reaction on an activity in a conversation. | ||
|
|
||
| Args: | ||
| conversation_id: The conversation id. | ||
| activity_id: The id of the activity to react to. | ||
| reaction_type: The reaction type (for example: "like", "heart", "laugh", etc.). | ||
| """ | ||
| url = ( | ||
| f"{self.service_url}/v3/conversations/{conversation_id}/activities/{activity_id}/reactions/{reaction_type}" | ||
| ) | ||
| await self.http.put(url) | ||
|
|
||
| async def delete( | ||
| self, | ||
| conversation_id: str, | ||
| activity_id: str, | ||
| reaction_type: MessageReactionType, | ||
| ) -> None: | ||
| """ | ||
| Removes a reaction from an activity in a conversation. | ||
|
|
||
| Args: | ||
| conversation_id: The conversation id. | ||
| activity_id: The id of the activity the reaction is on. | ||
| reaction_type: The reaction type to remove (for example: "like", "heart", "laugh", etc.). | ||
| """ | ||
| url = ( | ||
| f"{self.service_url}/v3/conversations/{conversation_id}/activities/{activity_id}/reactions/{reaction_type}" | ||
| ) | ||
| await self.http.delete(url) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.