diff --git a/github/core/http.py b/github/core/http.py index d4befcc4..68fcbe91 100644 --- a/github/core/http.py +++ b/github/core/http.py @@ -19,6 +19,7 @@ from github.interfaces import Node, Resource from github.interfaces.assignable import AssignableData from github.interfaces.labelable import LabelableData + from github.interfaces.reactable import ReactableData from github.interfaces.starrable import StarrableData from github.interfaces.subscribable import SubscribableData from github.organization.organization import OrganizationData @@ -1785,6 +1786,24 @@ async def mutate_labelable_remove_labels( return data # type: ignore + async def mutate_reactable_add_reaction( + self: Self, + /, + reactable_id: str, + content: str, + *, + reactable_fields: Iterable[str] = MISSING, + reaction_fields: Iterable[str] = MISSING, + ) -> tuple[ReactableData, ReactionData]: + reactable_fields = ("__typename",) if reactable_fields is MISSING else reactable_fields + reaction_fields = github.utility.get_merged_graphql_fields(github.Reaction, reaction_fields) + query = "mutation($reactable_id:ID!,$content:ReactionContent!,$mutation_id:String!){addReaction(input:{clientMutationId:$mutation_id,subjectId:$reactable_id,content:$content}){subject{%s},reaction{%s}}}" % (",".join(reactable_fields), ",".join(reaction_fields)) + path = ("addReaction",) + + data = await self._mutate(query, *path, reactable_id=reactable_id, content=content) + + return (data["subject"], data["reaction"]) # type: ignore + async def mutate_starrable_star( self: Self, /, diff --git a/github/interfaces/reactable.py b/github/interfaces/reactable.py index 3ba5aff3..ffaca72a 100644 --- a/github/interfaces/reactable.py +++ b/github/interfaces/reactable.py @@ -5,7 +5,7 @@ from typing_extensions import Self from github.connection import Connection, ReactionOrder - from github.content import Reaction + from github.content import Reaction, ReactionContent from github.interfaces import Node import github @@ -156,6 +156,46 @@ def fetch_reactions( reverse=reverse if reverse is not MISSING else False, ) + async def add_reaction( + self: Self, + content: ReactionContent, + /, + ) -> Reaction: + """ + |coro| + + Adds a reaction to the reactable. + + + .. note:: + + Use of this mutation will also update the following fields: + + - :attr:`~.reaction_count` + + + Parameters + ---------- + + content: :class:`~github.ReactionContent` + The content of the reaction. + + + :rtype: :class:`~github.Reaction` + """ + + if TYPE_CHECKING and not isinstance(self, Node): + raise NotImplementedError + + reactable_data, reaction_data = await self._http.mutate_reactable_add_reaction(self.id, content.value, reactable_fields=("reactions{totalCount}",)) + + if "reactions" not in self._data.keys(): + self._data["reactions"] = dict() # type: ignore + + self._data["reactions"]["totalCount"] = reactable_data["reactions"]["totalCount"] + + return github.Reaction._from_data(reaction_data, http=self._http) + __all__ = [ "Reactable",