Skip to content

Commit ae29807

Browse files
authored
Merge pull request #130 from MerleLiuKun/feat-dm
Feat dm events
2 parents d44c6b1 + d75eefb commit ae29807

File tree

14 files changed

+601
-0
lines changed

14 files changed

+601
-0
lines changed

README.rst

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,10 @@ Now covers these features:
119119
- List follows
120120
- Pinned Lists
121121

122+
- Direct Messages
123+
- Direct Messages lookup
124+
- Manage Direct Messages
125+
122126
-----------
123127
INSTANTIATE
124128
-----------
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
## Direct Messages lookup
2+
3+
Direct Messages enable private conversations on Twitter. Direct Messages are one of the most popular features of Twitter, with a wide variety of use cases. These use cases range from group chats among friends to powering customer support for brands around the world. New v2 versions of Direct Messages endpoints will be introduced in stages, and this first stage includes fundamental endpoints for creating Direct Messages and listing Direct Message conversation events. For the first time, the Twitter API v2 supports group conversations.
4+
5+
You can get more information for this at [docs](https://developer.twitter.com/en/docs/twitter-api/direct-messages/lookup/introduction)
6+
7+
### Get all messages in a 1-1 conversation
8+
9+
Returns a list of Direct Messages (DM) events within a 1-1 conversation with the user specified in the participant_id path parameter.
10+
11+
Messages are returned in reverse chronological order.
12+
13+
```python
14+
my_api.get_dm_events_by_participant("1334059193268011010", max_results=1)
15+
# Response(data=[DirectMessageEvent(id='1593226322066567177', event_type='MessageCreate', text='from api to III')])
16+
```
17+
18+
### Get all messages in a specific conversation (both group and 1-1 conversations)
19+
20+
Returns a list of Direct Messages within a conversation specified in the dm_conversation_id path parameter.
21+
22+
Messages are returned in reverse chronological order.
23+
24+
```python
25+
my_api.get_dm_events_by_conversation("1593091374437781506", max_results=1)
26+
# Response(data=[DirectMessageEvent(id='1593091374437781510', event_type='MessageCreate', text='New group by api')])
27+
```
28+
29+
### Get all messages across a user's DM conversations (both sent and received, group and 1-1 conversations)
30+
31+
Returns a list of Direct Messages for the authenticated user, both sent and received. Direct Message events are returned in reverse chronological order.
32+
33+
Supports retrieving events from the previous 30 days.
34+
35+
```python
36+
my_api.get_dm_events(max_results=2)
37+
# Response(data=[DirectMessageEvent(id='1593226454237487108', event_type='MessageCreate', text='from api to III'), DirectMessageEvent(id='1593226322066567177', event_type='MessageCreate', text='from api to III')])
38+
```
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
## Manage Direct Messages
2+
3+
Direct Messages enable private conversations on Twitter. Direct Messages are one of the most popular features of Twitter, with a wide variety of use cases. These use cases range from group chats among friends, to powering customer support for brands around the world. New v2 versions of Direct Messages endpoints will be introduced in stages, and this first stage includes fundamental endpoints for creating Direct Messages and listing Direct Message conversation events. For the first time, the Twitter API v2 supports group conversations.
4+
5+
You can get more information for this at [docs](https://developer.twitter.com/en/docs/twitter-api/direct-messages/manage/introduction)
6+
7+
8+
### Create a message in a 1-1 conversation with the participant
9+
10+
Creates a one-to-one Direct Message and adds it to the one-to-one conversation.
11+
12+
This method either creates a new one-to-one conversation or retrieves the current conversation and adds the Direct Message to it.
13+
14+
```python
15+
my_api.create_message_to_participant("1334059193268011010", text="dm by api")
16+
# DirectMessageCreateResponse(dm_conversation_id='1301152652357595137-1334059193268011010', dm_event_id='1593234034146279428')
17+
```
18+
19+
### Create a group conversation and add a DM to it
20+
21+
Creates a Direct Message on behalf of an authenticated user, and adds it to the specified conversation.
22+
23+
```python
24+
my_api.create_message_to_conversation("1593091374437781506", text="message by api")
25+
# DirectMessageCreateResponse(dm_conversation_id='1301152652357595137-1334059193268011010', dm_event_id='1593234034146279428')
26+
```
27+
28+
### Adding a DM to an existing conversation (for both group and 1-1)
29+
30+
Creates a new group conversation and adds a Direct Message to it on behalf of an authenticated user.
31+
32+
```python
33+
my_api.create_conversation(
34+
conversation_type="group",
35+
message={"text": "hello"},
36+
participant_ids=["1334059193268011010", "906948460078698496"]
37+
)
38+
# DirectMessageCreateResponse(dm_conversation_id='1301152652357595137-1334059193268011010', dm_event_id='1593234034146279428')
39+
```

docs/mkdocs.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,9 @@ nav:
6262
- Pinned Lists: usage/lists/pinned-lists.md
6363
- Compliance:
6464
- Batch compliance: usage/compliance/batch_compliance.md
65+
- Direct Messages:
66+
- Direct Messages lookup: usage/direct-messages/direct-messages-lookup.md
67+
- Manage Direct Messages: usage/direct-messages/manage-direct-messages.md
6568
- Steaming: usage/streaming.md
6669
- Changelog: CHANGELOG.md
6770

pytwitter/api.py

Lines changed: 278 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -370,6 +370,7 @@ def generate_oauth2_access_token(
370370
url=self.BASE_OAUTH2_ACCESS_TOKEN_URL,
371371
authorization_response=response,
372372
code_verifier=code_verifier,
373+
proxies=self.proxies,
373374
)
374375
self._auth = OAuth2Auth(token=token)
375376
return token
@@ -2707,3 +2708,280 @@ def create_compliance_job(
27072708
return data
27082709
else:
27092710
return md.ComplianceJob.new_from_json_dict(data["data"])
2711+
2712+
def get_dm_events_by_participant(
2713+
self,
2714+
participant_id: str,
2715+
*,
2716+
dm_event_fields: Optional[Union[str, List, Tuple]] = None,
2717+
event_types: Optional[str] = None,
2718+
expansions: Optional[Union[str, List, Tuple]] = None,
2719+
media_fields: Optional[Union[str, List, Tuple]] = None,
2720+
user_fields: Optional[Union[str, List, Tuple]] = None,
2721+
tweet_fields: Optional[Union[str, List, Tuple]] = None,
2722+
pagination_token: Optional[str] = None,
2723+
max_results: Optional[int] = None,
2724+
return_json: bool = False,
2725+
) -> Union[dict, md.Response]:
2726+
"""
2727+
Returns a list of Direct Messages (DM) events within a 1-1 conversation with the user
2728+
specified in the participant_id path parameter.
2729+
2730+
:param participant_id: The participant_id of the user is having a 1-1 conversation with.
2731+
:param dm_event_fields: Fields for the direct message events.
2732+
:param event_types: Type of Direct Message event to return. In the context of one-to-one conversations,
2733+
only `MessageCreate` is relevant.
2734+
:param expansions: Fields for the expansions.
2735+
:param media_fields: Fields for the media object, Expansion required.
2736+
:param user_fields: Fields for the user object, Expansion required.
2737+
:param tweet_fields: Fields for the tweet object, Expansion required.
2738+
:param pagination_token: Token for the pagination.
2739+
:param max_results: The maximum number of results to be returned per page. Number between 1 and up to 100.
2740+
By default, each page will return 100 results.
2741+
:param return_json: Type for returned data. If you set True JSON data will be returned.
2742+
:return: Response instance or json.
2743+
"""
2744+
2745+
args = {
2746+
"dm_event.fields": enf_comma_separated(
2747+
name="dm_event_fields",
2748+
value=dm_event_fields,
2749+
),
2750+
"event_types": event_types,
2751+
"expansions": enf_comma_separated(name="expansions", value=expansions),
2752+
"media.fields": enf_comma_separated(
2753+
name="media_fields", value=media_fields
2754+
),
2755+
"user.fields": enf_comma_separated(name="user_fields", value=user_fields),
2756+
"tweet.fields": enf_comma_separated(
2757+
name="tweet_fields", value=tweet_fields
2758+
),
2759+
"max_results": max_results,
2760+
"pagination_token": pagination_token,
2761+
}
2762+
return self._get(
2763+
url=f"{self.BASE_URL_V2}/dm_conversations/with/{participant_id}/dm_events",
2764+
params=args,
2765+
cls=md.DirectMessageEvent,
2766+
multi=True,
2767+
return_json=return_json,
2768+
)
2769+
2770+
def get_dm_events_by_conversation(
2771+
self,
2772+
dm_conversation_id: str,
2773+
*,
2774+
dm_event_fields: Optional[Union[str, List, Tuple]] = None,
2775+
event_types: Optional[str] = None,
2776+
expansions: Optional[Union[str, List, Tuple]] = None,
2777+
media_fields: Optional[Union[str, List, Tuple]] = None,
2778+
user_fields: Optional[Union[str, List, Tuple]] = None,
2779+
tweet_fields: Optional[Union[str, List, Tuple]] = None,
2780+
pagination_token: Optional[str] = None,
2781+
max_results: Optional[int] = None,
2782+
return_json: bool = False,
2783+
) -> Union[dict, md.Response]:
2784+
"""
2785+
Returns a list of Direct Messages within a conversation specified in the `dm_conversation_id` path parameter.
2786+
2787+
:param dm_conversation_id: The `id` of the Direct Message conversation for which events are being retrieved.
2788+
:param dm_event_fields: Fields for the direct message events.
2789+
:param event_types: Type of Direct Message event to return. In the context of one-to-one conversations,
2790+
only `MessageCreate` is relevant.
2791+
:param expansions: Fields for the expansions.
2792+
:param media_fields: Fields for the media object, Expansion required.
2793+
:param user_fields: Fields for the user object, Expansion required.
2794+
:param tweet_fields: Fields for the tweet object, Expansion required.
2795+
:param pagination_token: Token for the pagination.
2796+
:param max_results: The maximum number of results to be returned per page. Number between 1 and up to 100.
2797+
By default, each page will return 100 results.
2798+
:param return_json: Type for returned data. If you set True JSON data will be returned.
2799+
:return: Response instance or json.
2800+
"""
2801+
2802+
args = {
2803+
"dm_event.fields": enf_comma_separated(
2804+
name="dm_event_fields",
2805+
value=dm_event_fields,
2806+
),
2807+
"event_types": event_types,
2808+
"expansions": enf_comma_separated(name="expansions", value=expansions),
2809+
"media.fields": enf_comma_separated(
2810+
name="media_fields", value=media_fields
2811+
),
2812+
"user.fields": enf_comma_separated(name="user_fields", value=user_fields),
2813+
"tweet.fields": enf_comma_separated(
2814+
name="tweet_fields", value=tweet_fields
2815+
),
2816+
"max_results": max_results,
2817+
"pagination_token": pagination_token,
2818+
}
2819+
return self._get(
2820+
url=f"{self.BASE_URL_V2}/dm_conversations/{dm_conversation_id}/dm_events",
2821+
params=args,
2822+
cls=md.DirectMessageEvent,
2823+
multi=True,
2824+
return_json=return_json,
2825+
)
2826+
2827+
def get_dm_events(
2828+
self,
2829+
*,
2830+
dm_event_fields: Optional[Union[str, List, Tuple]] = None,
2831+
event_types: Optional[str] = None,
2832+
expansions: Optional[Union[str, List, Tuple]] = None,
2833+
media_fields: Optional[Union[str, List, Tuple]] = None,
2834+
user_fields: Optional[Union[str, List, Tuple]] = None,
2835+
tweet_fields: Optional[Union[str, List, Tuple]] = None,
2836+
pagination_token: Optional[str] = None,
2837+
max_results: Optional[int] = None,
2838+
return_json: bool = False,
2839+
) -> Union[dict, md.Response]:
2840+
"""
2841+
Returns a list of Direct Messages for the authenticated user, both sent and received.
2842+
Supports retrieving events from the previous 30 days.
2843+
2844+
:param dm_event_fields: Fields for the direct message events.
2845+
:param event_types: Type of Direct Message event to return. In the context of one-to-one conversations,
2846+
only `MessageCreate` is relevant.
2847+
:param expansions: Fields for the expansions.
2848+
:param media_fields: Fields for the media object, Expansion required.
2849+
:param user_fields: Fields for the user object, Expansion required.
2850+
:param tweet_fields: Fields for the tweet object, Expansion required.
2851+
:param pagination_token: Token for the pagination.
2852+
:param max_results: The maximum number of results to be returned per page. Number between 1 and up to 100.
2853+
By default, each page will return 100 results.
2854+
:param return_json: Type for returned data. If you set True JSON data will be returned.
2855+
:return: Response instance or json.
2856+
"""
2857+
args = {
2858+
"dm_event.fields": enf_comma_separated(
2859+
name="dm_event_fields",
2860+
value=dm_event_fields,
2861+
),
2862+
"event_types": event_types,
2863+
"expansions": enf_comma_separated(name="expansions", value=expansions),
2864+
"media.fields": enf_comma_separated(
2865+
name="media_fields", value=media_fields
2866+
),
2867+
"user.fields": enf_comma_separated(name="user_fields", value=user_fields),
2868+
"tweet.fields": enf_comma_separated(
2869+
name="tweet_fields", value=tweet_fields
2870+
),
2871+
"max_results": max_results,
2872+
"pagination_token": pagination_token,
2873+
}
2874+
return self._get(
2875+
url=f"{self.BASE_URL_V2}/dm_events",
2876+
params=args,
2877+
cls=md.DirectMessageEvent,
2878+
multi=True,
2879+
return_json=return_json,
2880+
)
2881+
2882+
def create_message_to_participant(
2883+
self,
2884+
participant_id: str,
2885+
*,
2886+
attachments: Optional[List[dict]] = None,
2887+
text: Optional[str] = None,
2888+
return_json: bool = False,
2889+
) -> Union[dict, md.DirectMessageCreateResponse]:
2890+
"""
2891+
Creates a one-to-one Direct Message and adds it to the one-to-one conversation.
2892+
2893+
:param participant_id: The User ID of the account this one-to-one Direct Message is to be sent to.
2894+
:param attachments: A single Media ID being attached to the Direct Message.
2895+
This field is required if text is not present. Only 1 attachment is supported.
2896+
:param text: Text of the Direct Message being created. This field is required if attachments is not present.
2897+
Text messages support up to 10,000 characters.
2898+
:param return_json: Type for returned data. If you set True JSON data will be returned.
2899+
:return: Response instance or json.
2900+
"""
2901+
data = {}
2902+
if attachments is not None:
2903+
data["attachments"] = attachments
2904+
if text is not None:
2905+
data["text"] = text
2906+
resp = self._request(
2907+
url=f"{self.BASE_URL_V2}/dm_conversations/with/{participant_id}/messages",
2908+
verb="POST",
2909+
json=data,
2910+
)
2911+
data = self._parse_response(resp=resp)
2912+
return (
2913+
data
2914+
if return_json
2915+
else md.DirectMessageCreateResponse.new_from_json_dict(data["data"])
2916+
)
2917+
2918+
def create_message_to_conversation(
2919+
self,
2920+
dm_conversation_id: str,
2921+
*,
2922+
attachments: Optional[List[dict]] = None,
2923+
text: Optional[str] = None,
2924+
return_json: bool = False,
2925+
) -> Union[dict, md.DirectMessageCreateResponse]:
2926+
"""
2927+
Creates a Direct Message on behalf of an authenticated user, and adds it to the specified conversation.
2928+
2929+
:param dm_conversation_id: ID of the conversation to add the Direct Message to.
2930+
Supports both 1-1 and group conversations.
2931+
:param attachments: A single Media ID being attached to the Direct Message.
2932+
This field is required if text is not present. Only 1 attachment is supported.
2933+
:param text: Text of the Direct Message being created. This field is required if attachments is not present.
2934+
Text messages support up to 10,000 characters.
2935+
:param return_json: Type for returned data. If you set True JSON data will be returned.
2936+
:return: Response instance or json.
2937+
"""
2938+
data = {}
2939+
if attachments is not None:
2940+
data["attachments"] = attachments
2941+
if text is not None:
2942+
data["text"] = text
2943+
resp = self._request(
2944+
url=f"{self.BASE_URL_V2}/dm_conversations/{dm_conversation_id}/messages",
2945+
verb="POST",
2946+
json=data,
2947+
)
2948+
data = self._parse_response(resp=resp)
2949+
return (
2950+
data
2951+
if return_json
2952+
else md.DirectMessageCreateResponse.new_from_json_dict(data["data"])
2953+
)
2954+
2955+
def create_conversation(
2956+
self,
2957+
conversation_type: Optional[str],
2958+
message: Optional[dict],
2959+
participant_ids: Optional[List[str]],
2960+
*,
2961+
return_json: bool = False,
2962+
) -> Union[dict, md.DirectMessageCreateResponse]:
2963+
"""
2964+
Creates a new group conversation and adds a Direct Message to it on behalf of an authenticated user.
2965+
2966+
:param conversation_type: Must be set to "Group" (case sensitive).
2967+
:param message: A JSON object that contains either or both the text and attachments parameters.
2968+
:param participant_ids: An array of User IDs that the conversation is created with.
2969+
Conversations can have up to 50 participants.
2970+
:param return_json: Type for returned data. If you set True JSON data will be returned.
2971+
:return: Response instance or json.
2972+
"""
2973+
resp = self._request(
2974+
url=f"{self.BASE_URL_V2}/dm_conversations",
2975+
verb="POST",
2976+
json={
2977+
"conversation_type": conversation_type,
2978+
"message": message,
2979+
"participant_ids": participant_ids,
2980+
},
2981+
)
2982+
data = self._parse_response(resp=resp)
2983+
return (
2984+
data
2985+
if return_json
2986+
else md.DirectMessageCreateResponse.new_from_json_dict(data["data"])
2987+
)

pytwitter/models/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,4 +7,5 @@
77
from .space import * # noqa
88
from .list import * # noqa
99
from .stream import * # noqa
10+
from .dm_event import * # noqa
1011
from .ext import * # noqa

0 commit comments

Comments
 (0)