Implement ReactionClient for message reactions API#280
Conversation
Co-authored-by: rido-min <14916339+rido-min@users.noreply.github.com>
Co-authored-by: rido-min <14916339+rido-min@users.noreply.github.com>
|
@copilot add one sample under examples/ to show how to use the new reaction client |
Co-authored-by: rido-min <14916339+rido-min@users.noreply.github.com>
Added example under The example demonstrates:
Run it with: cd examples/reactions
uv run python src/main.py |
There was a problem hiding this comment.
Pull request overview
This PR adds a ReactionClient to the Microsoft Teams SDK for Python, enabling bots to programmatically add and remove message reactions via the Bot Framework v3 API. The implementation follows established patterns from similar clients like ConversationActivityClient.
Changes:
- Implements ReactionClient with
add()anddelete()methods for managing message reactions - Integrates ReactionClient into ApiClient as the
reactionsproperty with HTTP client propagation - Adds comprehensive example bot demonstrating reaction functionality with commands like "react like" and "unreact like"
Reviewed changes
Copilot reviewed 9 out of 10 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
| packages/api/src/microsoft_teams/api/clients/reaction/client.py | Core ReactionClient implementation with add/delete methods using Bot Framework v3 API endpoints |
| packages/api/src/microsoft_teams/api/clients/reaction/init.py | Module exports for ReactionClient |
| packages/api/src/microsoft_teams/api/clients/api_client.py | Integration of ReactionClient as reactions property with HTTP client propagation |
| packages/api/src/microsoft_teams/api/clients/init.py | Exports ReactionClient from the clients package |
| packages/api/tests/unit/test_reaction_client.py | Unit tests for ReactionClient initialization and methods |
| packages/api/tests/conftest.py | Mock transport handler for reaction API endpoints |
| examples/reactions/src/main.py | Example bot demonstrating reaction add/remove functionality |
| examples/reactions/pyproject.toml | Project configuration for reactions example |
| examples/reactions/README.md | Documentation for reactions example with usage instructions |
| uv.lock | Lock file update to include reactions example package |
| 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}") | ||
|
|
||
| # ============================================ | ||
| # 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}") | ||
|
|
||
| # ============================================ | ||
| # 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"!') |
There was a problem hiding this comment.
The command parsing logic has a control flow issue. When a user sends "react like", both the "react " condition (line 34) and the "help" condition (line 64) will execute because there's no early return after the react/unreact handlers. This means every reaction command will also trigger the default help message.
Add a return statement after the react handler (after line 44) and after the unreact handler (after line 59) to prevent fall-through to subsequent conditions.
There was a problem hiding this comment.
Fixed in commit 0888d25. Added return statements after both the react and unreact handlers to prevent fall-through to subsequent conditions.
|
|
||
| ```bash | ||
| cd examples/reactions | ||
| uv run python src/main.py |
There was a problem hiding this comment.
suggesting pip instead of uv
There was a problem hiding this comment.
Fixed in commit 0888d25. Updated README to use pip install -e . instead of uv run.
|
|
||
| await client.add(conversation_id, activity_id, reaction_type) | ||
|
|
||
| # Verify the request was made to the correct URL |
There was a problem hiding this comment.
should there be assertions here?
There was a problem hiding this comment.
Fixed in commit 0888d25. Added assertions to verify that the methods return None and complete without raising exceptions, following the pattern used in other client tests.
|
|
||
| MessageReactionType = Union[Literal["like", "heart", "laugh", "surprised", "sad", "angry", "plusOne"], str] | ||
| MessageReactionType = Union[ | ||
| Literal["like", "heart", "1f440_eyes", "2705_whiteheavycheckmark", "launch", "1f4cc_pushpin"], str |
Implementation Complete: Reactions API Client
Based on teams.net PR #335, successfully implemented ReactionClient for managing message reactions in Teams.
Tasks Completed
Example: examples/reactions
Complete working example demonstrating the ReactionClient:
react <type>commands to add reactionsunreact <type>commands to remove reactionsSecurity Summary
✅ CodeQL analysis completed - 0 security alerts found
✨ Let Copilot coding agent set things up for you — coding agent works faster and does higher quality work when set up for your repo.