We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Add subscription for team in `endpoints/group_notes.py`
A few changes we will need to make here
1) Update `extract_user_ids_from_mentions` to no longer unpack teams into `user_id`
2) Update the call to `bulk_subscribe` to handle the new output of the function above

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `src/sentry/api/serializers/rest_framework/mentions.py`
Content:
```
1 from __future__ import annotations
2 
3 from typing import Sequence
4 
5 from rest_framework import serializers
6 
7 from sentry.models import ActorTuple, OrganizationMember, OrganizationMemberTeam, Team, User
8 from sentry.services.hybrid_cloud.user import RpcUser
9 
10 
11 def extract_user_ids_from_mentions(organization_id, mentions):
12     """
13     Extracts user ids from a set of mentions. Mentions should be a list of
14     `ActorTuple` instances. Returns a dictionary with 'users' and 'team_users' keys.
15     'users' is the user ids for all explicitly mentioned users, and 'team_users'
16     is all user ids from explicitly mentioned teams, excluding any already
17     mentioned users.
18     """
19     actors: Sequence[RpcUser | Team] = ActorTuple.resolve_many(mentions)
20     actor_mentions = separate_resolved_actors(actors)
21 
22     team_user_ids = set(
23         OrganizationMemberTeam.objects.filter(
24             team_id__in=[t.id for t in actor_mentions["teams"]],
25             organizationmember__user_id__isnull=False,
26             organizationmember__user_is_active=True,
27             organizationmember__organization_id=organization_id,
28             is_active=True,
29         ).values_list("organizationmember__user_id", flat=True)
30     )
31     mentioned_team_users = team_user_ids - set({u.id for u in actor_mentions["users"]})
32 
33     return {
34         "users": {user.id for user in actor_mentions["users"]},
35         "team_users": set(mentioned_team_users),
36     }
37 
38 
39 def separate_actors(actors):
40     users = [actor for actor in actors if actor.type is User]
41     teams = [actor for actor in actors if actor.type is Team]
42 
43     return {"users": users, "teams": teams}
44 
45 
46 def separate_resolved_actors(actors: Sequence[RpcUser | Team]):
47     users = [actor for actor in actors if actor.class_name() == "User"]
48     teams = [actor for actor in actors if isinstance(actor, Team)]
49 
50     return {"users": users, "teams": teams}
51 
52 
53 class MentionsMixin:
54     def validate_mentions(self, mentions):
55         if mentions and "projects" in self.context:
56 
57             separated_actors = separate_actors(mentions)
58             # Validate that all mentioned users exist and are on the project.
59             users = separated_actors["users"]
60 
61             mentioned_user_ids = {user.id for user in users}
62 
63             projects = self.context["projects"]
64             user_ids = list(
65                 OrganizationMember.objects.filter(
66                     teams__projectteam__project__in=[p.id for p in projects],
67                     user_id__in=mentioned_user_ids,
68                 ).values_list("user_id", flat=True)
69             )
70 
71             if len(mentioned_user_ids) > len(user_ids):
72                 raise serializers.ValidationError("Cannot mention a non team member")
73 
74             # Validate that all mentioned teams exist and are on the project.
75             teams = separated_actors["teams"]
76             mentioned_team_ids = {team.id for team in teams}
77             if (
78                 len(mentioned_team_ids)
79                 > Team.objects.filter(
80                     id__in=mentioned_team_ids, projectteam__project__in=projects
81                 ).count()
82             ):
83                 raise serializers.ValidationError(
84                     "Mentioned team not found or not associated with project"
85                 )
86 
87         return mentions
88
```

Path: `src/sentry/api/endpoints/group_notes.py`
Content:
```
1 from datetime import timedelta
2 
3 from django.utils import timezone
4 from rest_framework import status
5 from rest_framework.request import Request
6 from rest_framework.response import Response
7 
8 from sentry.api.api_publish_status import ApiPublishStatus
9 from sentry.api.base import region_silo_endpoint
10 from sentry.api.bases.group import GroupEndpoint
11 from sentry.api.paginator import DateTimePaginator
12 from sentry.api.serializers import serialize
13 from sentry.api.serializers.rest_framework.group_notes import NoteSerializer
14 from sentry.api.serializers.rest_framework.mentions import extract_user_ids_from_mentions
15 from sentry.models import Activity, GroupSubscription
16 from sentry.notifications.types import GroupSubscriptionReason
17 from sentry.signals import comment_created
18 from sentry.types.activity import ActivityType
19 
20 
21 @region_silo_endpoint
22 class GroupNotesEndpoint(GroupEndpoint):
23     publish_status = {
24         "GET": ApiPublishStatus.UNKNOWN,
25         "POST": ApiPublishStatus.UNKNOWN,
26     }
27 
28     def get(self, request: Request, group) -> Response:
29         notes = Activity.objects.filter(group=group, type=ActivityType.NOTE.value)
30 
31         return self.paginate(
32             request=request,
33             queryset=notes,
34             paginator_cls=DateTimePaginator,
35             order_by="-datetime",
36             on_results=lambda x: serialize(x, request.user),
37         )
38 
39     def post(self, request: Request, group) -> Response:
40         serializer = NoteSerializer(
41             data=request.data,
42             context={
43                 "organization": group.organization,
44                 "organization_id": group.organization.id,
45                 "projects": [group.project],
46             },
47         )
48 
49         if not serializer.is_valid():
50             return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
51 
52         data = dict(serializer.validated_data)
53 
54         mentions = data.pop("mentions", [])
55 
56         if Activity.objects.filter(
57             group=group,
58             type=ActivityType.NOTE.value,
59             user_id=request.user.id,
60             data=data,
61             datetime__gte=timezone.now() - timedelta(hours=1),
62         ).exists():
63             return Response(
64                 '{"detail": "You have already posted that comment."}',
65                 status=status.HTTP_400_BAD_REQUEST,
66             )
67 
68         GroupSubscription.objects.subscribe(
69             group=group, subscriber=request.user, reason=GroupSubscriptionReason.comment
70         )
71 
72         mentioned_users = extract_user_ids_from_mentions(group.organization.id, mentions)
73         GroupSubscription.objects.bulk_subscribe(
74             group=group, user_ids=mentioned_users["users"], reason=GroupSubscriptionReason.mentioned
75         )
76 
77         GroupSubscription.objects.bulk_subscribe(
78             group=group,
79             user_ids=mentioned_users["team_users"],
80             reason=GroupSubscriptionReason.team_mentioned,
81         )
82 
83         activity = Activity.objects.create_group_activity(
84             group, ActivityType.NOTE, user_id=request.user.id, data=data
85         )
86 
87         self.create_external_comment(request, group, activity)
88 
89         webhook_data = {
90             "comment_id": activity.id,
91             "timestamp": activity.datetime,
92             "comment": activity.data.get("text"),
93             "project_slug": activity.project.slug,
94         }
95 
96         comment_created.send_robust(
97             project=group.project,
98             user=request.user,
99             group=group,
100             data=webhook_data,
101             sender="post",
102         )
103         return Response(serialize(activity, request.user), status=201)
104
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/src/sentry/api/endpoints/group_notes.py b/src/sentry/api/endpoints/group_notes.py
--- a/src/sentry/api/endpoints/group_notes.py
+++ b/src/sentry/api/endpoints/group_notes.py
@@ -5,6 +5,7 @@
 from rest_framework.request import Request
 from rest_framework.response import Response
 
+from sentry import features
 from sentry.api.api_publish_status import ApiPublishStatus
 from sentry.api.base import region_silo_endpoint
 from sentry.api.bases.group import GroupEndpoint
@@ -74,11 +75,18 @@
             group=group, user_ids=mentioned_users["users"], reason=GroupSubscriptionReason.mentioned
         )
 
-        GroupSubscription.objects.bulk_subscribe(
-            group=group,
-            user_ids=mentioned_users["team_users"],
-            reason=GroupSubscriptionReason.team_mentioned,
-        )
+        if features.has("organizations:team-workflow-notifications", group.organization):
+            GroupSubscription.objects.bulk_subscribe(
+                group=group,
+                team_ids=mentioned_users["teams"],
+                reason=GroupSubscriptionReason.team_mentioned,
+            )
+        else:
+            GroupSubscription.objects.bulk_subscribe(
+                group=group,
+                user_ids=mentioned_users["team_users"],
+                reason=GroupSubscriptionReason.team_mentioned,
+            )
 
         activity = Activity.objects.create_group_activity(
             group, ActivityType.NOTE, user_id=request.user.id, data=data
diff --git a/src/sentry/api/serializers/rest_framework/mentions.py b/src/sentry/api/serializers/rest_framework/mentions.py
--- a/src/sentry/api/serializers/rest_framework/mentions.py
+++ b/src/sentry/api/serializers/rest_framework/mentions.py
@@ -11,10 +11,10 @@
 def extract_user_ids_from_mentions(organization_id, mentions):
     """
     Extracts user ids from a set of mentions. Mentions should be a list of
-    `ActorTuple` instances. Returns a dictionary with 'users' and 'team_users' keys.
-    'users' is the user ids for all explicitly mentioned users, and 'team_users'
+    `ActorTuple` instances. Returns a dictionary with 'users', 'team_users', and 'teams' keys.
+    'users' is the user ids for all explicitly mentioned users, 'team_users'
     is all user ids from explicitly mentioned teams, excluding any already
-    mentioned users.
+    mentioned users, and 'teams' is the team ids for all explicitly mentioned teams.
     """
     actors: Sequence[RpcUser | Team] = ActorTuple.resolve_many(mentions)
     actor_mentions = separate_resolved_actors(actors)
@@ -33,6 +33,7 @@
     return {
         "users": {user.id for user in actor_mentions["users"]},
         "team_users": set(mentioned_team_users),
+        "teams": {team.id for team in actor_mentions["teams"]},
     }

{"golden_diff": "diff --git a/src/sentry/api/endpoints/group_notes.py b/src/sentry/api/endpoints/group_notes.py\n--- a/src/sentry/api/endpoints/group_notes.py\n+++ b/src/sentry/api/endpoints/group_notes.py\n@@ -5,6 +5,7 @@\n from rest_framework.request import Request\n from rest_framework.response import Response\n \n+from sentry import features\n from sentry.api.api_publish_status import ApiPublishStatus\n from sentry.api.base import region_silo_endpoint\n from sentry.api.bases.group import GroupEndpoint\n@@ -74,11 +75,18 @@\n             group=group, user_ids=mentioned_users[\"users\"], reason=GroupSubscriptionReason.mentioned\n         )\n \n-        GroupSubscription.objects.bulk_subscribe(\n-            group=group,\n-            user_ids=mentioned_users[\"team_users\"],\n-            reason=GroupSubscriptionReason.team_mentioned,\n-        )\n+        if features.has(\"organizations:team-workflow-notifications\", group.organization):\n+            GroupSubscription.objects.bulk_subscribe(\n+                group=group,\n+                team_ids=mentioned_users[\"teams\"],\n+                reason=GroupSubscriptionReason.team_mentioned,\n+            )\n+        else:\n+            GroupSubscription.objects.bulk_subscribe(\n+                group=group,\n+                user_ids=mentioned_users[\"team_users\"],\n+                reason=GroupSubscriptionReason.team_mentioned,\n+            )\n \n         activity = Activity.objects.create_group_activity(\n             group, ActivityType.NOTE, user_id=request.user.id, data=data\ndiff --git a/src/sentry/api/serializers/rest_framework/mentions.py b/src/sentry/api/serializers/rest_framework/mentions.py\n--- a/src/sentry/api/serializers/rest_framework/mentions.py\n+++ b/src/sentry/api/serializers/rest_framework/mentions.py\n@@ -11,10 +11,10 @@\n def extract_user_ids_from_mentions(organization_id, mentions):\n     \"\"\"\n     Extracts user ids from a set of mentions. Mentions should be a list of\n-    `ActorTuple` instances. Returns a dictionary with 'users' and 'team_users' keys.\n-    'users' is the user ids for all explicitly mentioned users, and 'team_users'\n+    `ActorTuple` instances. Returns a dictionary with 'users', 'team_users', and 'teams' keys.\n+    'users' is the user ids for all explicitly mentioned users, 'team_users'\n     is all user ids from explicitly mentioned teams, excluding any already\n-    mentioned users.\n+    mentioned users, and 'teams' is the team ids for all explicitly mentioned teams.\n     \"\"\"\n     actors: Sequence[RpcUser | Team] = ActorTuple.resolve_many(mentions)\n     actor_mentions = separate_resolved_actors(actors)\n@@ -33,6 +33,7 @@\n     return {\n         \"users\": {user.id for user in actor_mentions[\"users\"]},\n         \"team_users\": set(mentioned_team_users),\n+        \"teams\": {team.id for team in actor_mentions[\"teams\"]},\n     }\n", "issue": "Add subscription for team in `endpoints/group_notes.py`\nA few changes we will need to make here\r\n1) Update `extract_user_ids_from_mentions` to no longer unpack teams into `user_id`\r\n2) Update the call to `bulk_subscribe` to handle the new output of the function above\n", "before_files": [{"content": "from __future__ import annotations\n\nfrom typing import Sequence\n\nfrom rest_framework import serializers\n\nfrom sentry.models import ActorTuple, OrganizationMember, OrganizationMemberTeam, Team, User\nfrom sentry.services.hybrid_cloud.user import RpcUser\n\n\ndef extract_user_ids_from_mentions(organization_id, mentions):\n    \"\"\"\n    Extracts user ids from a set of mentions. Mentions should be a list of\n    `ActorTuple` instances. Returns a dictionary with 'users' and 'team_users' keys.\n    'users' is the user ids for all explicitly mentioned users, and 'team_users'\n    is all user ids from explicitly mentioned teams, excluding any already\n    mentioned users.\n    \"\"\"\n    actors: Sequence[RpcUser | Team] = ActorTuple.resolve_many(mentions)\n    actor_mentions = separate_resolved_actors(actors)\n\n    team_user_ids = set(\n        OrganizationMemberTeam.objects.filter(\n            team_id__in=[t.id for t in actor_mentions[\"teams\"]],\n            organizationmember__user_id__isnull=False,\n            organizationmember__user_is_active=True,\n            organizationmember__organization_id=organization_id,\n            is_active=True,\n        ).values_list(\"organizationmember__user_id\", flat=True)\n    )\n    mentioned_team_users = team_user_ids - set({u.id for u in actor_mentions[\"users\"]})\n\n    return {\n        \"users\": {user.id for user in actor_mentions[\"users\"]},\n        \"team_users\": set(mentioned_team_users),\n    }\n\n\ndef separate_actors(actors):\n    users = [actor for actor in actors if actor.type is User]\n    teams = [actor for actor in actors if actor.type is Team]\n\n    return {\"users\": users, \"teams\": teams}\n\n\ndef separate_resolved_actors(actors: Sequence[RpcUser | Team]):\n    users = [actor for actor in actors if actor.class_name() == \"User\"]\n    teams = [actor for actor in actors if isinstance(actor, Team)]\n\n    return {\"users\": users, \"teams\": teams}\n\n\nclass MentionsMixin:\n    def validate_mentions(self, mentions):\n        if mentions and \"projects\" in self.context:\n\n            separated_actors = separate_actors(mentions)\n            # Validate that all mentioned users exist and are on the project.\n            users = separated_actors[\"users\"]\n\n            mentioned_user_ids = {user.id for user in users}\n\n            projects = self.context[\"projects\"]\n            user_ids = list(\n                OrganizationMember.objects.filter(\n                    teams__projectteam__project__in=[p.id for p in projects],\n                    user_id__in=mentioned_user_ids,\n                ).values_list(\"user_id\", flat=True)\n            )\n\n            if len(mentioned_user_ids) > len(user_ids):\n                raise serializers.ValidationError(\"Cannot mention a non team member\")\n\n            # Validate that all mentioned teams exist and are on the project.\n            teams = separated_actors[\"teams\"]\n            mentioned_team_ids = {team.id for team in teams}\n            if (\n                len(mentioned_team_ids)\n                > Team.objects.filter(\n                    id__in=mentioned_team_ids, projectteam__project__in=projects\n                ).count()\n            ):\n                raise serializers.ValidationError(\n                    \"Mentioned team not found or not associated with project\"\n                )\n\n        return mentions\n", "path": "src/sentry/api/serializers/rest_framework/mentions.py"}, {"content": "from datetime import timedelta\n\nfrom django.utils import timezone\nfrom rest_framework import status\nfrom rest_framework.request import Request\nfrom rest_framework.response import Response\n\nfrom sentry.api.api_publish_status import ApiPublishStatus\nfrom sentry.api.base import region_silo_endpoint\nfrom sentry.api.bases.group import GroupEndpoint\nfrom sentry.api.paginator import DateTimePaginator\nfrom sentry.api.serializers import serialize\nfrom sentry.api.serializers.rest_framework.group_notes import NoteSerializer\nfrom sentry.api.serializers.rest_framework.mentions import extract_user_ids_from_mentions\nfrom sentry.models import Activity, GroupSubscription\nfrom sentry.notifications.types import GroupSubscriptionReason\nfrom sentry.signals import comment_created\nfrom sentry.types.activity import ActivityType\n\n\n@region_silo_endpoint\nclass GroupNotesEndpoint(GroupEndpoint):\n    publish_status = {\n        \"GET\": ApiPublishStatus.UNKNOWN,\n        \"POST\": ApiPublishStatus.UNKNOWN,\n    }\n\n    def get(self, request: Request, group) -> Response:\n        notes = Activity.objects.filter(group=group, type=ActivityType.NOTE.value)\n\n        return self.paginate(\n            request=request,\n            queryset=notes,\n            paginator_cls=DateTimePaginator,\n            order_by=\"-datetime\",\n            on_results=lambda x: serialize(x, request.user),\n        )\n\n    def post(self, request: Request, group) -> Response:\n        serializer = NoteSerializer(\n            data=request.data,\n            context={\n                \"organization\": group.organization,\n                \"organization_id\": group.organization.id,\n                \"projects\": [group.project],\n            },\n        )\n\n        if not serializer.is_valid():\n            return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)\n\n        data = dict(serializer.validated_data)\n\n        mentions = data.pop(\"mentions\", [])\n\n        if Activity.objects.filter(\n            group=group,\n            type=ActivityType.NOTE.value,\n            user_id=request.user.id,\n            data=data,\n            datetime__gte=timezone.now() - timedelta(hours=1),\n        ).exists():\n            return Response(\n                '{\"detail\": \"You have already posted that comment.\"}',\n                status=status.HTTP_400_BAD_REQUEST,\n            )\n\n        GroupSubscription.objects.subscribe(\n            group=group, subscriber=request.user, reason=GroupSubscriptionReason.comment\n        )\n\n        mentioned_users = extract_user_ids_from_mentions(group.organization.id, mentions)\n        GroupSubscription.objects.bulk_subscribe(\n            group=group, user_ids=mentioned_users[\"users\"], reason=GroupSubscriptionReason.mentioned\n        )\n\n        GroupSubscription.objects.bulk_subscribe(\n            group=group,\n            user_ids=mentioned_users[\"team_users\"],\n            reason=GroupSubscriptionReason.team_mentioned,\n        )\n\n        activity = Activity.objects.create_group_activity(\n            group, ActivityType.NOTE, user_id=request.user.id, data=data\n        )\n\n        self.create_external_comment(request, group, activity)\n\n        webhook_data = {\n            \"comment_id\": activity.id,\n            \"timestamp\": activity.datetime,\n            \"comment\": activity.data.get(\"text\"),\n            \"project_slug\": activity.project.slug,\n        }\n\n        comment_created.send_robust(\n            project=group.project,\n            user=request.user,\n            group=group,\n            data=webhook_data,\n            sender=\"post\",\n        )\n        return Response(serialize(activity, request.user), status=201)\n", "path": "src/sentry/api/endpoints/group_notes.py"}], "after_files": [{"content": "from __future__ import annotations\n\nfrom typing import Sequence\n\nfrom rest_framework import serializers\n\nfrom sentry.models import ActorTuple, OrganizationMember, OrganizationMemberTeam, Team, User\nfrom sentry.services.hybrid_cloud.user import RpcUser\n\n\ndef extract_user_ids_from_mentions(organization_id, mentions):\n    \"\"\"\n    Extracts user ids from a set of mentions. Mentions should be a list of\n    `ActorTuple` instances. Returns a dictionary with 'users', 'team_users', and 'teams' keys.\n    'users' is the user ids for all explicitly mentioned users, 'team_users'\n    is all user ids from explicitly mentioned teams, excluding any already\n    mentioned users, and 'teams' is the team ids for all explicitly mentioned teams.\n    \"\"\"\n    actors: Sequence[RpcUser | Team] = ActorTuple.resolve_many(mentions)\n    actor_mentions = separate_resolved_actors(actors)\n\n    team_user_ids = set(\n        OrganizationMemberTeam.objects.filter(\n            team_id__in=[t.id for t in actor_mentions[\"teams\"]],\n            organizationmember__user_id__isnull=False,\n            organizationmember__user_is_active=True,\n            organizationmember__organization_id=organization_id,\n            is_active=True,\n        ).values_list(\"organizationmember__user_id\", flat=True)\n    )\n    mentioned_team_users = team_user_ids - set({u.id for u in actor_mentions[\"users\"]})\n\n    return {\n        \"users\": {user.id for user in actor_mentions[\"users\"]},\n        \"team_users\": set(mentioned_team_users),\n        \"teams\": {team.id for team in actor_mentions[\"teams\"]},\n    }\n\n\ndef separate_actors(actors):\n    users = [actor for actor in actors if actor.type is User]\n    teams = [actor for actor in actors if actor.type is Team]\n\n    return {\"users\": users, \"teams\": teams}\n\n\ndef separate_resolved_actors(actors: Sequence[RpcUser | Team]):\n    users = [actor for actor in actors if actor.class_name() == \"User\"]\n    teams = [actor for actor in actors if isinstance(actor, Team)]\n\n    return {\"users\": users, \"teams\": teams}\n\n\nclass MentionsMixin:\n    def validate_mentions(self, mentions):\n        if mentions and \"projects\" in self.context:\n\n            separated_actors = separate_actors(mentions)\n            # Validate that all mentioned users exist and are on the project.\n            users = separated_actors[\"users\"]\n\n            mentioned_user_ids = {user.id for user in users}\n\n            projects = self.context[\"projects\"]\n            user_ids = list(\n                OrganizationMember.objects.filter(\n                    teams__projectteam__project__in=[p.id for p in projects],\n                    user_id__in=mentioned_user_ids,\n                ).values_list(\"user_id\", flat=True)\n            )\n\n            if len(mentioned_user_ids) > len(user_ids):\n                raise serializers.ValidationError(\"Cannot mention a non team member\")\n\n            # Validate that all mentioned teams exist and are on the project.\n            teams = separated_actors[\"teams\"]\n            mentioned_team_ids = {team.id for team in teams}\n            if (\n                len(mentioned_team_ids)\n                > Team.objects.filter(\n                    id__in=mentioned_team_ids, projectteam__project__in=projects\n                ).count()\n            ):\n                raise serializers.ValidationError(\n                    \"Mentioned team not found or not associated with project\"\n                )\n\n        return mentions\n", "path": "src/sentry/api/serializers/rest_framework/mentions.py"}, {"content": "from datetime import timedelta\n\nfrom django.utils import timezone\nfrom rest_framework import status\nfrom rest_framework.request import Request\nfrom rest_framework.response import Response\n\nfrom sentry import features\nfrom sentry.api.api_publish_status import ApiPublishStatus\nfrom sentry.api.base import region_silo_endpoint\nfrom sentry.api.bases.group import GroupEndpoint\nfrom sentry.api.paginator import DateTimePaginator\nfrom sentry.api.serializers import serialize\nfrom sentry.api.serializers.rest_framework.group_notes import NoteSerializer\nfrom sentry.api.serializers.rest_framework.mentions import extract_user_ids_from_mentions\nfrom sentry.models import Activity, GroupSubscription\nfrom sentry.notifications.types import GroupSubscriptionReason\nfrom sentry.signals import comment_created\nfrom sentry.types.activity import ActivityType\n\n\n@region_silo_endpoint\nclass GroupNotesEndpoint(GroupEndpoint):\n    publish_status = {\n        \"GET\": ApiPublishStatus.UNKNOWN,\n        \"POST\": ApiPublishStatus.UNKNOWN,\n    }\n\n    def get(self, request: Request, group) -> Response:\n        notes = Activity.objects.filter(group=group, type=ActivityType.NOTE.value)\n\n        return self.paginate(\n            request=request,\n            queryset=notes,\n            paginator_cls=DateTimePaginator,\n            order_by=\"-datetime\",\n            on_results=lambda x: serialize(x, request.user),\n        )\n\n    def post(self, request: Request, group) -> Response:\n        serializer = NoteSerializer(\n            data=request.data,\n            context={\n                \"organization\": group.organization,\n                \"organization_id\": group.organization.id,\n                \"projects\": [group.project],\n            },\n        )\n\n        if not serializer.is_valid():\n            return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)\n\n        data = dict(serializer.validated_data)\n\n        mentions = data.pop(\"mentions\", [])\n\n        if Activity.objects.filter(\n            group=group,\n            type=ActivityType.NOTE.value,\n            user_id=request.user.id,\n            data=data,\n            datetime__gte=timezone.now() - timedelta(hours=1),\n        ).exists():\n            return Response(\n                '{\"detail\": \"You have already posted that comment.\"}',\n                status=status.HTTP_400_BAD_REQUEST,\n            )\n\n        GroupSubscription.objects.subscribe(\n            group=group, subscriber=request.user, reason=GroupSubscriptionReason.comment\n        )\n\n        mentioned_users = extract_user_ids_from_mentions(group.organization.id, mentions)\n        GroupSubscription.objects.bulk_subscribe(\n            group=group, user_ids=mentioned_users[\"users\"], reason=GroupSubscriptionReason.mentioned\n        )\n\n        if features.has(\"organizations:team-workflow-notifications\", group.organization):\n            GroupSubscription.objects.bulk_subscribe(\n                group=group,\n                team_ids=mentioned_users[\"teams\"],\n                reason=GroupSubscriptionReason.team_mentioned,\n            )\n        else:\n            GroupSubscription.objects.bulk_subscribe(\n                group=group,\n                user_ids=mentioned_users[\"team_users\"],\n                reason=GroupSubscriptionReason.team_mentioned,\n            )\n\n        activity = Activity.objects.create_group_activity(\n            group, ActivityType.NOTE, user_id=request.user.id, data=data\n        )\n\n        self.create_external_comment(request, group, activity)\n\n        webhook_data = {\n            \"comment_id\": activity.id,\n            \"timestamp\": activity.datetime,\n            \"comment\": activity.data.get(\"text\"),\n            \"project_slug\": activity.project.slug,\n        }\n\n        comment_created.send_robust(\n            project=group.project,\n            user=request.user,\n            group=group,\n            data=webhook_data,\n            sender=\"post\",\n        )\n        return Response(serialize(activity, request.user), status=201)\n", "path": "src/sentry/api/endpoints/group_notes.py"}]}