mirror of
https://github.com/Significant-Gravitas/AutoGPT.git
synced 2026-04-08 03:00:28 -04:00
fix linting
This commit is contained in:
@@ -1,10 +1,10 @@
|
||||
from typing import Literal
|
||||
|
||||
from autogpt_libs.supabase_integration_credentials_store.types import OAuth2Credentials
|
||||
from backend.integrations.oauth.twitter import TwitterOAuthHandler
|
||||
from pydantic import SecretStr
|
||||
|
||||
from backend.data.model import CredentialsField, CredentialsMetaInput
|
||||
from backend.integrations.oauth.twitter import TwitterOAuthHandler
|
||||
from backend.util.settings import Secrets
|
||||
|
||||
# --8<-- [start:TwitterOAuthIsConfigured]
|
||||
|
||||
@@ -1,48 +1,73 @@
|
||||
from typing import Any, Dict
|
||||
|
||||
from backend.blocks.twitter._mappers import (
|
||||
get_backend_expansion,
|
||||
get_backend_field,
|
||||
get_backend_list_expansion,
|
||||
get_backend_list_field,
|
||||
get_backend_media_field,
|
||||
get_backend_place_field,
|
||||
get_backend_poll_field,
|
||||
get_backend_space_expansion,
|
||||
get_backend_space_field,
|
||||
get_backend_user_field,
|
||||
)
|
||||
from backend.blocks.twitter._types import TweetExpansions, TweetReplySettings
|
||||
from backend.blocks.twitter._mappers import get_backend_expansion, get_backend_field, get_backend_list_expansion, get_backend_list_field, get_backend_media_field, get_backend_place_field, get_backend_poll_field, get_backend_space_expansion, get_backend_space_field, get_backend_user_field
|
||||
|
||||
|
||||
# Common Builder
|
||||
class TweetExpansionsBuilder:
|
||||
def __init__(self, param : Dict[str, Any]):
|
||||
def __init__(self, param: Dict[str, Any]):
|
||||
self.params: Dict[str, Any] = param
|
||||
|
||||
def add_expansions(self, expansions: list[TweetExpansions]):
|
||||
if expansions:
|
||||
self.params["expansions"] = ",".join([get_backend_expansion(exp.name) for exp in expansions])
|
||||
self.params["expansions"] = ",".join(
|
||||
[get_backend_expansion(exp.name) for exp in expansions]
|
||||
)
|
||||
return self
|
||||
|
||||
def add_media_fields(self, media_fields: list):
|
||||
if media_fields:
|
||||
self.params["media.fields"] = ",".join([get_backend_media_field(field.name) for field in media_fields])
|
||||
self.params["media.fields"] = ",".join(
|
||||
[get_backend_media_field(field.name) for field in media_fields]
|
||||
)
|
||||
return self
|
||||
|
||||
def add_place_fields(self, place_fields: list):
|
||||
if place_fields:
|
||||
self.params["place.fields"] = ",".join([get_backend_place_field(field.name) for field in place_fields])
|
||||
self.params["place.fields"] = ",".join(
|
||||
[get_backend_place_field(field.name) for field in place_fields]
|
||||
)
|
||||
return self
|
||||
|
||||
def add_poll_fields(self, poll_fields: list):
|
||||
if poll_fields:
|
||||
self.params["poll.fields"] = ",".join([get_backend_poll_field(field.name) for field in poll_fields])
|
||||
self.params["poll.fields"] = ",".join(
|
||||
[get_backend_poll_field(field.name) for field in poll_fields]
|
||||
)
|
||||
return self
|
||||
|
||||
def add_tweet_fields(self, tweet_fields: list):
|
||||
if tweet_fields:
|
||||
self.params["tweet.fields"] = ",".join([get_backend_field(field.name) for field in tweet_fields])
|
||||
self.params["tweet.fields"] = ",".join(
|
||||
[get_backend_field(field.name) for field in tweet_fields]
|
||||
)
|
||||
return self
|
||||
|
||||
def add_user_fields(self, user_fields: list):
|
||||
if user_fields:
|
||||
self.params["user.fields"] = ",".join([get_backend_user_field(field.name) for field in user_fields])
|
||||
self.params["user.fields"] = ",".join(
|
||||
[get_backend_user_field(field.name) for field in user_fields]
|
||||
)
|
||||
return self
|
||||
|
||||
def build(self):
|
||||
return self.params
|
||||
|
||||
|
||||
class UserExpansionsBuilder:
|
||||
def __init__(self, param : Dict[str, Any]):
|
||||
def __init__(self, param: Dict[str, Any]):
|
||||
self.params: Dict[str, Any] = param
|
||||
|
||||
def add_expansions(self, expansions: list):
|
||||
@@ -52,63 +77,82 @@ class UserExpansionsBuilder:
|
||||
|
||||
def add_tweet_fields(self, tweet_fields: list):
|
||||
if tweet_fields:
|
||||
self.params["tweet.fields"] = ",".join([get_backend_field(field.name) for field in tweet_fields])
|
||||
self.params["tweet.fields"] = ",".join(
|
||||
[get_backend_field(field.name) for field in tweet_fields]
|
||||
)
|
||||
return self
|
||||
|
||||
def add_user_fields(self, user_fields: list):
|
||||
if user_fields:
|
||||
self.params["user.fields"] = ",".join([get_backend_user_field(field.name) for field in user_fields])
|
||||
self.params["user.fields"] = ",".join(
|
||||
[get_backend_user_field(field.name) for field in user_fields]
|
||||
)
|
||||
return self
|
||||
|
||||
def build(self):
|
||||
return self.params
|
||||
|
||||
|
||||
class ListExpansionsBuilder:
|
||||
def __init__(self, param : Dict[str, Any]):
|
||||
def __init__(self, param: Dict[str, Any]):
|
||||
self.params: Dict[str, Any] = param
|
||||
|
||||
def add_expansions(self, expansions: list):
|
||||
if expansions:
|
||||
self.params["expansions"] = ",".join([get_backend_list_expansion(exp.name) for exp in expansions])
|
||||
self.params["expansions"] = ",".join(
|
||||
[get_backend_list_expansion(exp.name) for exp in expansions]
|
||||
)
|
||||
return self
|
||||
|
||||
def add_list_fields(self, list_fields: list):
|
||||
if list_fields:
|
||||
self.params["list.fields"] = ",".join([get_backend_list_field(field.name) for field in list_fields])
|
||||
self.params["list.fields"] = ",".join(
|
||||
[get_backend_list_field(field.name) for field in list_fields]
|
||||
)
|
||||
return self
|
||||
|
||||
def add_user_fields(self, user_fields: list):
|
||||
if user_fields:
|
||||
self.params["user.fields"] = ",".join([get_backend_user_field(field.name) for field in user_fields])
|
||||
self.params["user.fields"] = ",".join(
|
||||
[get_backend_user_field(field.name) for field in user_fields]
|
||||
)
|
||||
return self
|
||||
|
||||
def build(self):
|
||||
return self.params
|
||||
|
||||
|
||||
class SpaceExpansionsBuilder:
|
||||
def __init__(self, param : Dict[str, Any]):
|
||||
def __init__(self, param: Dict[str, Any]):
|
||||
self.params: Dict[str, Any] = param
|
||||
|
||||
def add_expansions(self, expansions: list):
|
||||
if expansions:
|
||||
self.params["expansions"] = ",".join([get_backend_space_expansion(exp.name) for exp in expansions])
|
||||
self.params["expansions"] = ",".join(
|
||||
[get_backend_space_expansion(exp.name) for exp in expansions]
|
||||
)
|
||||
return self
|
||||
|
||||
def add_space_fields(self, space_fields: list):
|
||||
if space_fields:
|
||||
self.params["space.fields"] = ",".join([get_backend_space_field(field.name) for field in space_fields])
|
||||
self.params["space.fields"] = ",".join(
|
||||
[get_backend_space_field(field.name) for field in space_fields]
|
||||
)
|
||||
return self
|
||||
|
||||
def add_user_fields(self, user_fields: list):
|
||||
if user_fields:
|
||||
self.params["user.fields"] = ",".join([get_backend_user_field(field.name) for field in user_fields])
|
||||
self.params["user.fields"] = ",".join(
|
||||
[get_backend_user_field(field.name) for field in user_fields]
|
||||
)
|
||||
return self
|
||||
|
||||
def build(self):
|
||||
return self.params
|
||||
|
||||
|
||||
class TweetDurationBuilder:
|
||||
def __init__(self, param : Dict[str, Any]):
|
||||
def __init__(self, param: Dict[str, Any]):
|
||||
self.params: Dict[str, Any] = param
|
||||
|
||||
def add_start_time(self, start_time: str):
|
||||
@@ -139,8 +183,9 @@ class TweetDurationBuilder:
|
||||
def build(self):
|
||||
return self.params
|
||||
|
||||
|
||||
class DMExpansionsBuilder:
|
||||
def __init__(self, param : Dict[str, Any]):
|
||||
def __init__(self, param: Dict[str, Any]):
|
||||
self.params: Dict[str, Any] = param
|
||||
|
||||
def add_expansions(self, expansions: list):
|
||||
@@ -150,22 +195,30 @@ class DMExpansionsBuilder:
|
||||
|
||||
def add_event_types(self, event_types: list):
|
||||
if event_types:
|
||||
self.params["event_types"] = ",".join([field.value for field in event_types])
|
||||
self.params["event_types"] = ",".join(
|
||||
[field.value for field in event_types]
|
||||
)
|
||||
return self
|
||||
|
||||
def add_media_fields(self, media_fields: list):
|
||||
if media_fields:
|
||||
self.params["media.fields"] = ",".join([field.value for field in media_fields])
|
||||
self.params["media.fields"] = ",".join(
|
||||
[field.value for field in media_fields]
|
||||
)
|
||||
return self
|
||||
|
||||
def add_tweet_fields(self, tweet_fields: list):
|
||||
if tweet_fields:
|
||||
self.params["tweet.fields"] = ",".join([field.value for field in tweet_fields])
|
||||
self.params["tweet.fields"] = ",".join(
|
||||
[field.value for field in tweet_fields]
|
||||
)
|
||||
return self
|
||||
|
||||
def add_user_fields(self, user_fields: list):
|
||||
if user_fields:
|
||||
self.params["user.fields"] = ",".join([field.value for field in user_fields])
|
||||
self.params["user.fields"] = ",".join(
|
||||
[field.value for field in user_fields]
|
||||
)
|
||||
return self
|
||||
|
||||
def build(self):
|
||||
@@ -192,6 +245,7 @@ class TweetSearchBuilder:
|
||||
def build(self):
|
||||
return self.params
|
||||
|
||||
|
||||
class TweetPostBuilder:
|
||||
def __init__(self):
|
||||
self.params: Dict[str, Any] = {"user_auth": False}
|
||||
@@ -228,7 +282,7 @@ class TweetPostBuilder:
|
||||
self.params["poll_options"] = poll_options
|
||||
return self
|
||||
|
||||
def add_poll_duration(self, poll_duration_minutes: int ):
|
||||
def add_poll_duration(self, poll_duration_minutes: int):
|
||||
if poll_duration_minutes:
|
||||
self.params["poll_duration_minutes"] = poll_duration_minutes
|
||||
return self
|
||||
@@ -238,7 +292,9 @@ class TweetPostBuilder:
|
||||
self.params["quote_tweet_id"] = quote_id
|
||||
return self
|
||||
|
||||
def add_reply_settings(self, exclude_user_ids: list, reply_to_id: str, settings: TweetReplySettings):
|
||||
def add_reply_settings(
|
||||
self, exclude_user_ids: list, reply_to_id: str, settings: TweetReplySettings
|
||||
):
|
||||
if exclude_user_ids:
|
||||
self.params["exclude_reply_user_ids"] = exclude_user_ids
|
||||
if reply_to_id:
|
||||
@@ -252,6 +308,7 @@ class TweetPostBuilder:
|
||||
def build(self):
|
||||
return self.params
|
||||
|
||||
|
||||
class TweetGetsBuilder:
|
||||
def __init__(self):
|
||||
self.params: Dict[str, Any] = {"user_auth": False}
|
||||
|
||||
@@ -13,19 +13,22 @@ EXPANSION_FRONTEND_TO_BACKEND_MAPPING = {
|
||||
"referenced_tweets_id_author_id": "referenced_tweets.id.author_id",
|
||||
}
|
||||
|
||||
|
||||
def get_backend_expansion(frontend_key: str) -> str:
|
||||
result = EXPANSION_FRONTEND_TO_BACKEND_MAPPING.get(frontend_key)
|
||||
if result is None:
|
||||
raise KeyError(f"Invalid expansion key: {frontend_key}")
|
||||
return result
|
||||
|
||||
|
||||
# TweetReplySettings
|
||||
REPLY_SETTINGS_FRONTEND_TO_BACKEND_MAPPING = {
|
||||
"mentioned_users": "mentionedUsers",
|
||||
"following": "following",
|
||||
"all_users": "all"
|
||||
"all_users": "all",
|
||||
}
|
||||
|
||||
|
||||
# TweetUserFields
|
||||
def get_backend_reply_setting(frontend_key: str) -> str:
|
||||
result = REPLY_SETTINGS_FRONTEND_TO_BACKEND_MAPPING.get(frontend_key)
|
||||
@@ -33,6 +36,7 @@ def get_backend_reply_setting(frontend_key: str) -> str:
|
||||
raise KeyError(f"Invalid reply setting key: {frontend_key}")
|
||||
return result
|
||||
|
||||
|
||||
USER_FIELDS_FRONTEND_TO_BACKEND_MAPPING = {
|
||||
"created_at": "created_at",
|
||||
"description": "description",
|
||||
@@ -49,15 +53,17 @@ USER_FIELDS_FRONTEND_TO_BACKEND_MAPPING = {
|
||||
"username": "username",
|
||||
"verified": "verified",
|
||||
"verified_type": "verified_type",
|
||||
"withheld": "withheld"
|
||||
"withheld": "withheld",
|
||||
}
|
||||
|
||||
|
||||
def get_backend_user_field(frontend_key: str) -> str:
|
||||
result = USER_FIELDS_FRONTEND_TO_BACKEND_MAPPING.get(frontend_key)
|
||||
if result is None:
|
||||
raise KeyError(f"Invalid user field key: {frontend_key}")
|
||||
return result
|
||||
|
||||
|
||||
# TweetFields
|
||||
FIELDS_FRONTEND_TO_BACKEND_MAPPING = {
|
||||
"attachments": "attachments",
|
||||
@@ -77,30 +83,34 @@ FIELDS_FRONTEND_TO_BACKEND_MAPPING = {
|
||||
"reply_settings": "reply_settings",
|
||||
"source": "source",
|
||||
"text": "text",
|
||||
"withheld": "withheld"
|
||||
"withheld": "withheld",
|
||||
}
|
||||
|
||||
|
||||
def get_backend_field(frontend_key: str) -> str:
|
||||
result = FIELDS_FRONTEND_TO_BACKEND_MAPPING.get(frontend_key)
|
||||
if result is None:
|
||||
raise KeyError(f"Invalid field key: {frontend_key}")
|
||||
return result
|
||||
|
||||
|
||||
# TweetPollFields
|
||||
POLL_FIELDS_FRONTEND_TO_BACKEND_MAPPING = {
|
||||
"duration_minutes": "duration_minutes",
|
||||
"end_datetime": "end_datetime",
|
||||
"id": "id",
|
||||
"options": "options",
|
||||
"voting_status": "voting_status"
|
||||
"voting_status": "voting_status",
|
||||
}
|
||||
|
||||
|
||||
def get_backend_poll_field(frontend_key: str) -> str:
|
||||
result = POLL_FIELDS_FRONTEND_TO_BACKEND_MAPPING.get(frontend_key)
|
||||
if result is None:
|
||||
raise KeyError(f"Invalid poll field key: {frontend_key}")
|
||||
return result
|
||||
|
||||
|
||||
PLACE_FIELDS_FRONTEND_TO_BACKEND_MAPPING = {
|
||||
"contained_within": "contained_within",
|
||||
"country": "country",
|
||||
@@ -109,15 +119,17 @@ PLACE_FIELDS_FRONTEND_TO_BACKEND_MAPPING = {
|
||||
"geo": "geo",
|
||||
"id": "id",
|
||||
"place_name": "name",
|
||||
"place_type": "place_type"
|
||||
"place_type": "place_type",
|
||||
}
|
||||
|
||||
|
||||
def get_backend_place_field(frontend_key: str) -> str:
|
||||
result = PLACE_FIELDS_FRONTEND_TO_BACKEND_MAPPING.get(frontend_key)
|
||||
if result is None:
|
||||
raise KeyError(f"Invalid place field key: {frontend_key}")
|
||||
return result
|
||||
|
||||
|
||||
# TweetMediaFields
|
||||
MEDIA_FIELDS_FRONTEND_TO_BACKEND_MAPPING = {
|
||||
"duration_ms": "duration_ms",
|
||||
@@ -132,15 +144,17 @@ MEDIA_FIELDS_FRONTEND_TO_BACKEND_MAPPING = {
|
||||
"organic_metrics": "organic_metrics",
|
||||
"promoted_metrics": "promoted_metrics",
|
||||
"alt_text": "alt_text",
|
||||
"variants": "variants"
|
||||
"variants": "variants",
|
||||
}
|
||||
|
||||
|
||||
def get_backend_media_field(frontend_key: str) -> str:
|
||||
result = MEDIA_FIELDS_FRONTEND_TO_BACKEND_MAPPING.get(frontend_key)
|
||||
if result is None:
|
||||
raise KeyError(f"Invalid media field key: {frontend_key}")
|
||||
return result
|
||||
|
||||
|
||||
# -------------- Spaces -----------------
|
||||
|
||||
# SpaceExpansions
|
||||
@@ -149,15 +163,17 @@ EXPANSION_FRONTEND_TO_BACKEND_MAPPING_SPACE = {
|
||||
"speaker_ids": "speaker_ids",
|
||||
"creator_id": "creator_id",
|
||||
"host_ids": "host_ids",
|
||||
"topic_ids": "topic_ids"
|
||||
"topic_ids": "topic_ids",
|
||||
}
|
||||
|
||||
|
||||
def get_backend_space_expansion(frontend_key: str) -> str:
|
||||
result = EXPANSION_FRONTEND_TO_BACKEND_MAPPING_SPACE.get(frontend_key)
|
||||
if result is None:
|
||||
raise KeyError(f"Invalid expansion key: {frontend_key}")
|
||||
return result
|
||||
|
||||
|
||||
# SpaceFields
|
||||
SPACE_FIELDS_FRONTEND_TO_BACKEND_MAPPING = {
|
||||
"id": "id",
|
||||
@@ -175,21 +191,22 @@ SPACE_FIELDS_FRONTEND_TO_BACKEND_MAPPING = {
|
||||
"started_at": "started_at",
|
||||
"title_": "title",
|
||||
"topic_ids": "topic_ids",
|
||||
"updated_at": "updated_at"
|
||||
"updated_at": "updated_at",
|
||||
}
|
||||
|
||||
|
||||
def get_backend_space_field(frontend_key: str) -> str:
|
||||
result = SPACE_FIELDS_FRONTEND_TO_BACKEND_MAPPING.get(frontend_key)
|
||||
if result is None:
|
||||
raise KeyError(f"Invalid space field key: {frontend_key}")
|
||||
return result
|
||||
|
||||
|
||||
# -------------- List Expansions -----------------
|
||||
|
||||
# ListExpansions
|
||||
LIST_EXPANSION_FRONTEND_TO_BACKEND_MAPPING = {
|
||||
"owner_id": "owner_id"
|
||||
}
|
||||
LIST_EXPANSION_FRONTEND_TO_BACKEND_MAPPING = {"owner_id": "owner_id"}
|
||||
|
||||
|
||||
def get_backend_list_expansion(frontend_key: str) -> str:
|
||||
result = LIST_EXPANSION_FRONTEND_TO_BACKEND_MAPPING.get(frontend_key)
|
||||
@@ -197,6 +214,7 @@ def get_backend_list_expansion(frontend_key: str) -> str:
|
||||
raise KeyError(f"Invalid list expansion key: {frontend_key}")
|
||||
return result
|
||||
|
||||
|
||||
LIST_FIELDS_FRONTEND_TO_BACKEND_MAPPING = {
|
||||
"id": "id",
|
||||
"list_name": "name",
|
||||
@@ -205,9 +223,10 @@ LIST_FIELDS_FRONTEND_TO_BACKEND_MAPPING = {
|
||||
"follower_count": "follower_count",
|
||||
"member_count": "member_count",
|
||||
"private": "private",
|
||||
"owner_id": "owner_id"
|
||||
"owner_id": "owner_id",
|
||||
}
|
||||
|
||||
|
||||
def get_backend_list_field(frontend_key: str) -> str:
|
||||
result = LIST_FIELDS_FRONTEND_TO_BACKEND_MAPPING.get(frontend_key)
|
||||
if result is None:
|
||||
|
||||
@@ -1,13 +1,15 @@
|
||||
from typing import Any, Dict, List
|
||||
|
||||
|
||||
class BaseSerializer:
|
||||
@staticmethod
|
||||
def _serialize_value(value: Any) -> Any:
|
||||
"""Helper method to serialize individual values"""
|
||||
if hasattr(value, 'data'):
|
||||
if hasattr(value, "data"):
|
||||
return value.data
|
||||
return value
|
||||
|
||||
|
||||
class IncludesSerializer(BaseSerializer):
|
||||
@classmethod
|
||||
def serialize(cls, includes: Dict[str, Any]) -> Dict[str, Any]:
|
||||
@@ -26,13 +28,14 @@ class IncludesSerializer(BaseSerializer):
|
||||
|
||||
return serialized_includes
|
||||
|
||||
|
||||
class ResponseDataSerializer(BaseSerializer):
|
||||
@classmethod
|
||||
def serialize_dict(cls, item: Dict[str, Any]) -> Dict[str, Any]:
|
||||
"""Serializes a single dictionary item"""
|
||||
serialized_item = {}
|
||||
|
||||
if hasattr(item, '__dict__'):
|
||||
if hasattr(item, "__dict__"):
|
||||
items = item.__dict__.items()
|
||||
else:
|
||||
items = item.items()
|
||||
@@ -52,24 +55,22 @@ class ResponseDataSerializer(BaseSerializer):
|
||||
"""Serializes a list of dictionary items"""
|
||||
return [cls.serialize_dict(item) for item in data]
|
||||
|
||||
|
||||
class ResponseSerializer:
|
||||
@classmethod
|
||||
def serialize(cls, response) -> Dict[str, Any]:
|
||||
"""Main serializer that handles both data and includes"""
|
||||
result = {
|
||||
'data': None,
|
||||
'included': {}
|
||||
}
|
||||
result = {"data": None, "included": {}}
|
||||
|
||||
# Handle response.data
|
||||
if response.data:
|
||||
if isinstance(response.data, list):
|
||||
result['data'] = ResponseDataSerializer.serialize_list(response.data)
|
||||
result["data"] = ResponseDataSerializer.serialize_list(response.data)
|
||||
else:
|
||||
result['data'] = ResponseDataSerializer.serialize_dict(response.data)
|
||||
result["data"] = ResponseDataSerializer.serialize_dict(response.data)
|
||||
|
||||
# Handle includes
|
||||
if hasattr(response, 'includes') and response.includes:
|
||||
result['included'] = IncludesSerializer.serialize(response.includes)
|
||||
if hasattr(response, "includes") and response.includes:
|
||||
result["included"] = IncludesSerializer.serialize(response.includes)
|
||||
|
||||
return result
|
||||
|
||||
@@ -5,11 +5,13 @@ from backend.data.model import SchemaField
|
||||
|
||||
# -------------- Tweets -----------------
|
||||
|
||||
|
||||
class TweetReplySettings(str, Enum):
|
||||
mentioned_users = "Mentioned_Users_Only"
|
||||
following = "Following_Users_Only"
|
||||
all_users = "All_Users"
|
||||
|
||||
|
||||
class TweetUserFields(str, Enum):
|
||||
created_at = "Account_Creation_Date"
|
||||
description = "User_Bio"
|
||||
@@ -28,6 +30,7 @@ class TweetUserFields(str, Enum):
|
||||
verified_type = "Verification_Type"
|
||||
withheld = "Content_Withholding_Info"
|
||||
|
||||
|
||||
class TweetFields(str, Enum):
|
||||
attachments = "Tweet_Attachments"
|
||||
author_id = "Author_ID"
|
||||
@@ -48,6 +51,7 @@ class TweetFields(str, Enum):
|
||||
text = "Tweet_Text"
|
||||
withheld = "Withheld_Content"
|
||||
|
||||
|
||||
class PersonalTweetFields(str, Enum):
|
||||
attachments = "attachments"
|
||||
author_id = "author_id"
|
||||
@@ -71,6 +75,7 @@ class PersonalTweetFields(str, Enum):
|
||||
text = "text"
|
||||
withheld = "withheld"
|
||||
|
||||
|
||||
class TweetPollFields(str, Enum):
|
||||
duration_minutes = "Duration_Minutes"
|
||||
end_datetime = "End_DateTime"
|
||||
@@ -78,6 +83,7 @@ class TweetPollFields(str, Enum):
|
||||
options = "Poll_Options"
|
||||
voting_status = "Voting_Status"
|
||||
|
||||
|
||||
class TweetPlaceFields(str, Enum):
|
||||
contained_within = "Contained_Within_Places"
|
||||
country = "Country"
|
||||
@@ -88,6 +94,7 @@ class TweetPlaceFields(str, Enum):
|
||||
place_name = "Place_Name"
|
||||
place_type = "Place_Type"
|
||||
|
||||
|
||||
class TweetMediaFields(str, Enum):
|
||||
duration_ms = "Duration_in_Milliseconds"
|
||||
height = "Height"
|
||||
@@ -103,6 +110,7 @@ class TweetMediaFields(str, Enum):
|
||||
alt_text = "Alternative_Text"
|
||||
variants = "Media_Variants"
|
||||
|
||||
|
||||
class TweetExpansions(str, Enum):
|
||||
attachments_poll_ids = "Poll_IDs"
|
||||
attachments_media_keys = "Media_Keys"
|
||||
@@ -114,18 +122,22 @@ class TweetExpansions(str, Enum):
|
||||
referenced_tweets_id = "Referenced_Tweet_ID"
|
||||
referenced_tweets_id_author_id = "Referenced_Tweet_Author_ID"
|
||||
|
||||
|
||||
class TweetExcludes(str, Enum):
|
||||
retweets = "retweets"
|
||||
replies = "replies"
|
||||
|
||||
|
||||
# -------------- Users -----------------
|
||||
|
||||
|
||||
class UserExpansions(str, Enum):
|
||||
pinned_tweet_id = "pinned_tweet_id"
|
||||
|
||||
|
||||
# -------------- DM's' -----------------
|
||||
|
||||
|
||||
class DMEventField(str, Enum):
|
||||
ID = "id"
|
||||
TEXT = "text"
|
||||
@@ -137,17 +149,20 @@ class DMEventField(str, Enum):
|
||||
REFERENCED_TWEETS = "referenced_tweets"
|
||||
ATTACHMENTS = "attachments"
|
||||
|
||||
|
||||
class DMEventType(str, Enum):
|
||||
MESSAGE_CREATE = "MessageCreate"
|
||||
PARTICIPANTS_JOIN = "ParticipantsJoin"
|
||||
PARTICIPANTS_LEAVE = "ParticipantsLeave"
|
||||
|
||||
|
||||
class DMEventExpansion(str, Enum):
|
||||
ATTACHMENTS_MEDIA_KEYS = "attachments.media_keys"
|
||||
REFERENCED_TWEETS_ID = "referenced_tweets.id"
|
||||
SENDER_ID = "sender_id"
|
||||
PARTICIPANT_IDS = "participant_ids"
|
||||
|
||||
|
||||
class DMMediaField(str, Enum):
|
||||
DURATION_MS = "duration_ms"
|
||||
HEIGHT = "height"
|
||||
@@ -160,6 +175,7 @@ class DMMediaField(str, Enum):
|
||||
ALT_TEXT = "alt_text"
|
||||
VARIANTS = "variants"
|
||||
|
||||
|
||||
class DMTweetField(str, Enum):
|
||||
ATTACHMENTS = "attachments"
|
||||
AUTHOR_ID = "author_id"
|
||||
@@ -180,8 +196,10 @@ class DMTweetField(str, Enum):
|
||||
TEXT = "text"
|
||||
WITHHELD = "withheld"
|
||||
|
||||
|
||||
# -------------- Spaces -----------------
|
||||
|
||||
|
||||
class SpaceExpansions(str, Enum):
|
||||
invited_user_ids = "Invited_Users"
|
||||
speaker_ids = "Speakers"
|
||||
@@ -189,6 +207,7 @@ class SpaceExpansions(str, Enum):
|
||||
host_ids = "Hosts"
|
||||
topic_ids = "Topics"
|
||||
|
||||
|
||||
class SpaceFields(str, Enum):
|
||||
id = "Space_ID"
|
||||
state = "Space_State"
|
||||
@@ -207,6 +226,7 @@ class SpaceFields(str, Enum):
|
||||
topic_ids = "Topic_IDs"
|
||||
updated_at = "Last_Updated_Time"
|
||||
|
||||
|
||||
class SpaceStates(str, Enum):
|
||||
LIVE = "live"
|
||||
SCHEDULED = "scheduled"
|
||||
@@ -215,9 +235,11 @@ class SpaceStates(str, Enum):
|
||||
|
||||
# -------------- List Expansions -----------------
|
||||
|
||||
|
||||
class ListExpansions(str, Enum):
|
||||
owner_id = "List_Owner_ID"
|
||||
|
||||
|
||||
class ListFields(str, Enum):
|
||||
id = "List_ID"
|
||||
list_name = "List_Name"
|
||||
@@ -233,7 +255,7 @@ class ListFields(str, Enum):
|
||||
class TweetExpansionInputs(BlockSchema):
|
||||
expansions: list[TweetExpansions] = SchemaField(
|
||||
description="Choose what extra information you want to get with your tweets. For example:\n- Select 'Media_Keys' to get media details\n- Select 'Author_User_ID' to get user information\n- Select 'Place_ID' to get location details",
|
||||
enum = TweetExpansions,
|
||||
enum=TweetExpansions,
|
||||
placeholder="Pick the extra information you want to see",
|
||||
default=[],
|
||||
is_multi_select=True,
|
||||
@@ -242,11 +264,11 @@ class TweetExpansionInputs(BlockSchema):
|
||||
|
||||
media_fields: list[TweetMediaFields] = SchemaField(
|
||||
description="Select what media information you want to see (images, videos, etc). To use this, you must first select 'Media_Keys' in the expansions above.",
|
||||
enum = TweetMediaFields,
|
||||
enum=TweetMediaFields,
|
||||
placeholder="Choose what media details you want to see",
|
||||
default=[],
|
||||
is_multi_select=True,
|
||||
advanced=True
|
||||
advanced=True,
|
||||
)
|
||||
|
||||
place_fields: list[TweetPlaceFields] = SchemaField(
|
||||
@@ -255,7 +277,7 @@ class TweetExpansionInputs(BlockSchema):
|
||||
default=[],
|
||||
advanced=True,
|
||||
is_multi_select=True,
|
||||
enum = TweetPlaceFields
|
||||
enum=TweetPlaceFields,
|
||||
)
|
||||
|
||||
poll_fields: list[TweetPollFields] = SchemaField(
|
||||
@@ -264,7 +286,7 @@ class TweetExpansionInputs(BlockSchema):
|
||||
default=[],
|
||||
advanced=True,
|
||||
is_multi_select=True,
|
||||
enum = TweetPollFields
|
||||
enum=TweetPollFields,
|
||||
)
|
||||
|
||||
tweet_fields: list[TweetFields] = SchemaField(
|
||||
@@ -273,7 +295,7 @@ class TweetExpansionInputs(BlockSchema):
|
||||
default=[],
|
||||
advanced=True,
|
||||
is_multi_select=True,
|
||||
enum = TweetFields
|
||||
enum=TweetFields,
|
||||
)
|
||||
|
||||
user_fields: list[TweetUserFields] = SchemaField(
|
||||
@@ -282,13 +304,14 @@ class TweetExpansionInputs(BlockSchema):
|
||||
default=[],
|
||||
advanced=True,
|
||||
is_multi_select=True,
|
||||
enum = TweetUserFields
|
||||
enum=TweetUserFields,
|
||||
)
|
||||
|
||||
|
||||
class DMEventExpansionInputs(BlockSchema):
|
||||
expansions: list[DMEventExpansion] = SchemaField(
|
||||
description="Select expansions to include related data objects in the 'includes' section.",
|
||||
enum = DMEventExpansion,
|
||||
enum=DMEventExpansion,
|
||||
placeholder="Enter expansions",
|
||||
default=[],
|
||||
is_multi_select=True,
|
||||
@@ -301,7 +324,7 @@ class DMEventExpansionInputs(BlockSchema):
|
||||
default=[],
|
||||
advanced=True,
|
||||
is_multi_select=True,
|
||||
enum = DMEventType
|
||||
enum=DMEventType,
|
||||
)
|
||||
|
||||
media_fields: list[DMMediaField] = SchemaField(
|
||||
@@ -310,7 +333,7 @@ class DMEventExpansionInputs(BlockSchema):
|
||||
default=[],
|
||||
advanced=True,
|
||||
is_multi_select=True,
|
||||
enum = DMMediaField
|
||||
enum=DMMediaField,
|
||||
)
|
||||
|
||||
tweet_fields: list[DMTweetField] = SchemaField(
|
||||
@@ -319,7 +342,7 @@ class DMEventExpansionInputs(BlockSchema):
|
||||
default=[],
|
||||
advanced=True,
|
||||
is_multi_select=True,
|
||||
enum = DMTweetField
|
||||
enum=DMTweetField,
|
||||
)
|
||||
|
||||
user_fields: list[TweetUserFields] = SchemaField(
|
||||
@@ -328,41 +351,43 @@ class DMEventExpansionInputs(BlockSchema):
|
||||
default=[],
|
||||
advanced=True,
|
||||
is_multi_select=True,
|
||||
enum = TweetUserFields
|
||||
enum=TweetUserFields,
|
||||
)
|
||||
|
||||
|
||||
class UserExpansionInputs(BlockSchema):
|
||||
expansions: list[UserExpansions] = SchemaField(
|
||||
description="Choose what extra information you want to get with user data. Currently only 'pinned_tweet_id' is available to see a user's pinned tweet.",
|
||||
enum = UserExpansions,
|
||||
placeholder="Select extra user information to include",
|
||||
default=[],
|
||||
is_multi_select=True,
|
||||
advanced=True,
|
||||
)
|
||||
expansions: list[UserExpansions] = SchemaField(
|
||||
description="Choose what extra information you want to get with user data. Currently only 'pinned_tweet_id' is available to see a user's pinned tweet.",
|
||||
enum=UserExpansions,
|
||||
placeholder="Select extra user information to include",
|
||||
default=[],
|
||||
is_multi_select=True,
|
||||
advanced=True,
|
||||
)
|
||||
|
||||
tweet_fields: list[TweetFields] = SchemaField(
|
||||
description="Select what tweet information you want to see in pinned tweets. This only works if you select 'pinned_tweet_id' in expansions above.",
|
||||
placeholder="Choose what details to see in pinned tweets",
|
||||
default=[],
|
||||
advanced=True,
|
||||
is_multi_select=True,
|
||||
enum = TweetFields
|
||||
)
|
||||
tweet_fields: list[TweetFields] = SchemaField(
|
||||
description="Select what tweet information you want to see in pinned tweets. This only works if you select 'pinned_tweet_id' in expansions above.",
|
||||
placeholder="Choose what details to see in pinned tweets",
|
||||
default=[],
|
||||
advanced=True,
|
||||
is_multi_select=True,
|
||||
enum=TweetFields,
|
||||
)
|
||||
|
||||
user_fields: list[TweetUserFields] = SchemaField(
|
||||
description="Select what user information you want to see, like username, bio, profile picture, etc.",
|
||||
placeholder="Choose what user details you want to see",
|
||||
default=[],
|
||||
advanced=True,
|
||||
is_multi_select=True,
|
||||
enum=TweetUserFields,
|
||||
)
|
||||
|
||||
user_fields: list[TweetUserFields] = SchemaField(
|
||||
description="Select what user information you want to see, like username, bio, profile picture, etc.",
|
||||
placeholder="Choose what user details you want to see",
|
||||
default=[],
|
||||
advanced=True,
|
||||
is_multi_select=True,
|
||||
enum = TweetUserFields
|
||||
)
|
||||
|
||||
class SpaceExpansionInputs(BlockSchema):
|
||||
expansions: list[SpaceExpansions] = SchemaField(
|
||||
description="Choose additional information you want to get with your Twitter Spaces:\n- Select 'Invited_Users' to see who was invited\n- Select 'Speakers' to see who can speak\n- Select 'Creator' to get details about who made the Space\n- Select 'Hosts' to see who's hosting\n- Select 'Topics' to see Space topics",
|
||||
enum = SpaceExpansions,
|
||||
enum=SpaceExpansions,
|
||||
placeholder="Pick what extra information you want to see about the Space",
|
||||
default=[],
|
||||
is_multi_select=True,
|
||||
@@ -372,10 +397,10 @@ class SpaceExpansionInputs(BlockSchema):
|
||||
space_fields: list[SpaceFields] = SchemaField(
|
||||
description="Choose what Space details you want to see, such as:\n- Title\n- Start/End times\n- Number of participants\n- Language\n- State (live/scheduled)\n- And more",
|
||||
placeholder="Choose what Space information you want to get",
|
||||
default=[SpaceFields.title_,SpaceFields.host_ids],
|
||||
default=[SpaceFields.title_, SpaceFields.host_ids],
|
||||
advanced=True,
|
||||
is_multi_select=True,
|
||||
enum = SpaceFields
|
||||
enum=SpaceFields,
|
||||
)
|
||||
|
||||
user_fields: list[TweetUserFields] = SchemaField(
|
||||
@@ -384,13 +409,14 @@ class SpaceExpansionInputs(BlockSchema):
|
||||
default=[],
|
||||
advanced=True,
|
||||
is_multi_select=True,
|
||||
enum = TweetUserFields
|
||||
enum=TweetUserFields,
|
||||
)
|
||||
|
||||
|
||||
class ListExpansionInputs(BlockSchema):
|
||||
expansions: list[ListExpansions] = SchemaField(
|
||||
description="Choose what extra information you want to get with your Twitter Lists:\n- Select 'List_Owner_ID' to get details about who owns the list\n\nThis will let you see more details about the list owner when you also select user fields below.",
|
||||
enum = ListExpansions,
|
||||
enum=ListExpansions,
|
||||
placeholder="Pick what extra list information you want to see",
|
||||
default=[ListExpansions.owner_id],
|
||||
is_multi_select=True,
|
||||
@@ -400,10 +426,10 @@ class ListExpansionInputs(BlockSchema):
|
||||
user_fields: list[TweetUserFields] = SchemaField(
|
||||
description="Choose what information you want to see about list owners. This only works when you select 'List_Owner_ID' in expansions above.\n\nYou can see things like:\n- Their username\n- Profile picture\n- Account details\n- And more",
|
||||
placeholder="Select what details you want to see about list owners",
|
||||
default=[TweetUserFields.id,TweetUserFields.username],
|
||||
default=[TweetUserFields.id, TweetUserFields.username],
|
||||
advanced=True,
|
||||
is_multi_select=True,
|
||||
enum = TweetUserFields
|
||||
enum=TweetUserFields,
|
||||
)
|
||||
|
||||
list_fields: list[ListFields] = SchemaField(
|
||||
@@ -412,9 +438,10 @@ class ListExpansionInputs(BlockSchema):
|
||||
default=[ListFields.owner_id],
|
||||
advanced=True,
|
||||
is_multi_select=True,
|
||||
enum = ListFields
|
||||
enum=ListFields,
|
||||
)
|
||||
|
||||
|
||||
class TweetTimeWindowInputs(BlockSchema):
|
||||
start_time: str = SchemaField(
|
||||
description="Start time in YYYY-MM-DDTHH:mm:ssZ format",
|
||||
@@ -434,7 +461,7 @@ class TweetTimeWindowInputs(BlockSchema):
|
||||
placeholder="Enter since ID",
|
||||
)
|
||||
|
||||
until_id: str = SchemaField(
|
||||
until_id: str = SchemaField(
|
||||
description="Returns results with Tweet ID less than this (that is, older than), and used with since_id",
|
||||
default="",
|
||||
placeholder="Enter until ID",
|
||||
|
||||
@@ -1,12 +1,6 @@
|
||||
# from typing import cast
|
||||
import tweepy
|
||||
# from tweepy.client import Response
|
||||
|
||||
from backend.data.block import Block, BlockCategory, BlockOutput, BlockSchema
|
||||
from backend.data.model import SchemaField
|
||||
# from backend.blocks.twitter._builders import UserExpansionsBuilder
|
||||
# from backend.blocks.twitter._types import TweetFields, TweetUserFields, UserExpansionInputs, UserExpansions
|
||||
from backend.blocks.twitter.tweepy_exceptions import handle_tweepy_exception
|
||||
from backend.blocks.twitter._auth import (
|
||||
TEST_CREDENTIALS,
|
||||
TEST_CREDENTIALS_INPUT,
|
||||
@@ -15,6 +9,15 @@ from backend.blocks.twitter._auth import (
|
||||
TwitterCredentialsInput,
|
||||
)
|
||||
|
||||
# from backend.blocks.twitter._builders import UserExpansionsBuilder
|
||||
# from backend.blocks.twitter._types import TweetFields, TweetUserFields, UserExpansionInputs, UserExpansions
|
||||
from backend.blocks.twitter.tweepy_exceptions import handle_tweepy_exception
|
||||
from backend.data.block import Block, BlockCategory, BlockOutput, BlockSchema
|
||||
from backend.data.model import SchemaField
|
||||
|
||||
# from tweepy.client import Response
|
||||
|
||||
|
||||
class TwitterUnfollowListBlock(Block):
|
||||
"""
|
||||
Unfollows a Twitter list for the authenticated user
|
||||
@@ -41,10 +44,7 @@ class TwitterUnfollowListBlock(Block):
|
||||
categories={BlockCategory.SOCIAL},
|
||||
input_schema=TwitterUnfollowListBlock.Input,
|
||||
output_schema=TwitterUnfollowListBlock.Output,
|
||||
test_input={
|
||||
"list_id": "123456789",
|
||||
"credentials": TEST_CREDENTIALS_INPUT
|
||||
},
|
||||
test_input={"list_id": "123456789", "credentials": TEST_CREDENTIALS_INPUT},
|
||||
test_credentials=TEST_CREDENTIALS,
|
||||
test_output=[
|
||||
("success", True),
|
||||
@@ -52,16 +52,13 @@ class TwitterUnfollowListBlock(Block):
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def unfollow_list(
|
||||
credentials: TwitterCredentials,
|
||||
list_id: str
|
||||
):
|
||||
def unfollow_list(credentials: TwitterCredentials, list_id: str):
|
||||
try:
|
||||
client = tweepy.Client(
|
||||
bearer_token=credentials.access_token.get_secret_value()
|
||||
)
|
||||
|
||||
client.unfollow_list(list_id=list_id,user_auth=False)
|
||||
client.unfollow_list(list_id=list_id, user_auth=False)
|
||||
|
||||
return True
|
||||
|
||||
@@ -76,14 +73,12 @@ class TwitterUnfollowListBlock(Block):
|
||||
**kwargs,
|
||||
) -> BlockOutput:
|
||||
try:
|
||||
success = self.unfollow_list(
|
||||
credentials,
|
||||
input_data.list_id
|
||||
)
|
||||
success = self.unfollow_list(credentials, input_data.list_id)
|
||||
yield "success", success
|
||||
except Exception as e:
|
||||
yield "error", handle_tweepy_exception(e)
|
||||
|
||||
|
||||
class TwitterFollowListBlock(Block):
|
||||
"""
|
||||
Follows a Twitter list for the authenticated user
|
||||
@@ -91,7 +86,7 @@ class TwitterFollowListBlock(Block):
|
||||
|
||||
class Input(BlockSchema):
|
||||
credentials: TwitterCredentialsInput = TwitterCredentialsField(
|
||||
["tweet.read","users.read","list.write", "offline.access"]
|
||||
["tweet.read", "users.read", "list.write", "offline.access"]
|
||||
)
|
||||
|
||||
list_id: str = SchemaField(
|
||||
@@ -110,28 +105,19 @@ class TwitterFollowListBlock(Block):
|
||||
categories={BlockCategory.SOCIAL},
|
||||
input_schema=TwitterFollowListBlock.Input,
|
||||
output_schema=TwitterFollowListBlock.Output,
|
||||
test_input={
|
||||
"list_id": "123456789",
|
||||
"credentials": TEST_CREDENTIALS_INPUT
|
||||
},
|
||||
test_input={"list_id": "123456789", "credentials": TEST_CREDENTIALS_INPUT},
|
||||
test_credentials=TEST_CREDENTIALS,
|
||||
test_output=[
|
||||
("success", True),
|
||||
("error", None)
|
||||
],
|
||||
test_output=[("success", True), ("error", None)],
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def follow_list(
|
||||
credentials: TwitterCredentials,
|
||||
list_id: str
|
||||
):
|
||||
def follow_list(credentials: TwitterCredentials, list_id: str):
|
||||
try:
|
||||
client = tweepy.Client(
|
||||
bearer_token=credentials.access_token.get_secret_value()
|
||||
)
|
||||
|
||||
client.follow_list(list_id=list_id,user_auth=False)
|
||||
client.follow_list(list_id=list_id, user_auth=False)
|
||||
|
||||
return True
|
||||
|
||||
@@ -146,14 +132,12 @@ class TwitterFollowListBlock(Block):
|
||||
**kwargs,
|
||||
) -> BlockOutput:
|
||||
try:
|
||||
success = self.follow_list(
|
||||
credentials,
|
||||
input_data.list_id
|
||||
)
|
||||
success = self.follow_list(credentials, input_data.list_id)
|
||||
yield "success", success
|
||||
except Exception as e:
|
||||
yield "error", handle_tweepy_exception(e)
|
||||
|
||||
|
||||
# Enterprise Level [Need to do Manual testing]
|
||||
|
||||
# class TwitterListGetFollowersBlock(Block):
|
||||
|
||||
@@ -3,12 +3,6 @@ from typing import cast
|
||||
import tweepy
|
||||
from tweepy.client import Response
|
||||
|
||||
from backend.blocks.twitter._serializer import IncludesSerializer, ResponseDataSerializer
|
||||
from backend.data.block import Block, BlockCategory, BlockOutput, BlockSchema
|
||||
from backend.data.model import SchemaField
|
||||
from backend.blocks.twitter._types import ListExpansionInputs, ListExpansions, ListFields, TweetUserFields
|
||||
from backend.blocks.twitter.tweepy_exceptions import handle_tweepy_exception
|
||||
from backend.blocks.twitter._builders import ListExpansionsBuilder
|
||||
from backend.blocks.twitter._auth import (
|
||||
TEST_CREDENTIALS,
|
||||
TEST_CREDENTIALS_INPUT,
|
||||
@@ -16,6 +10,21 @@ from backend.blocks.twitter._auth import (
|
||||
TwitterCredentialsField,
|
||||
TwitterCredentialsInput,
|
||||
)
|
||||
from backend.blocks.twitter._builders import ListExpansionsBuilder
|
||||
from backend.blocks.twitter._serializer import (
|
||||
IncludesSerializer,
|
||||
ResponseDataSerializer,
|
||||
)
|
||||
from backend.blocks.twitter._types import (
|
||||
ListExpansionInputs,
|
||||
ListExpansions,
|
||||
ListFields,
|
||||
TweetUserFields,
|
||||
)
|
||||
from backend.blocks.twitter.tweepy_exceptions import handle_tweepy_exception
|
||||
from backend.data.block import Block, BlockCategory, BlockOutput, BlockSchema
|
||||
from backend.data.model import SchemaField
|
||||
|
||||
|
||||
class TwitterGetListBlock(Block):
|
||||
"""
|
||||
@@ -30,7 +39,7 @@ class TwitterGetListBlock(Block):
|
||||
list_id: str = SchemaField(
|
||||
description="The ID of the List to lookup",
|
||||
placeholder="Enter list ID",
|
||||
required=True
|
||||
required=True,
|
||||
)
|
||||
|
||||
class Output(BlockSchema):
|
||||
@@ -42,7 +51,9 @@ class TwitterGetListBlock(Block):
|
||||
|
||||
# Complete outputs
|
||||
data: dict = SchemaField(description="Complete list data")
|
||||
included: dict = SchemaField(description="Additional data requested via expansions")
|
||||
included: dict = SchemaField(
|
||||
description="Additional data requested via expansions"
|
||||
)
|
||||
meta: dict = SchemaField(description="Metadata about the response")
|
||||
error: str = SchemaField(description="Error message if the request failed")
|
||||
|
||||
@@ -58,7 +69,7 @@ class TwitterGetListBlock(Block):
|
||||
"credentials": TEST_CREDENTIALS_INPUT,
|
||||
"expansions": [],
|
||||
"list_fields": [],
|
||||
"user_fields": []
|
||||
"user_fields": [],
|
||||
},
|
||||
test_credentials=TEST_CREDENTIALS,
|
||||
test_output=[
|
||||
@@ -69,14 +80,14 @@ class TwitterGetListBlock(Block):
|
||||
("data", {"id": "84839422", "name": "Official Twitter Accounts"}),
|
||||
("included", {}),
|
||||
("meta", {}),
|
||||
("error", "")
|
||||
("error", ""),
|
||||
],
|
||||
test_mock={
|
||||
"get_list": lambda *args, **kwargs: ({
|
||||
"id": "84839422",
|
||||
"name": "Official Twitter Accounts"
|
||||
}, {})
|
||||
}
|
||||
"get_list": lambda *args, **kwargs: (
|
||||
{"id": "84839422", "name": "Official Twitter Accounts"},
|
||||
{},
|
||||
)
|
||||
},
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
@@ -92,24 +103,18 @@ class TwitterGetListBlock(Block):
|
||||
bearer_token=credentials.access_token.get_secret_value()
|
||||
)
|
||||
|
||||
params = {
|
||||
"id": list_id,
|
||||
"user_auth": False
|
||||
}
|
||||
params = {"id": list_id, "user_auth": False}
|
||||
|
||||
params = (ListExpansionsBuilder(params)
|
||||
.add_expansions(expansions)
|
||||
.add_user_fields(user_fields)
|
||||
.add_list_fields(list_fields)
|
||||
.build())
|
||||
|
||||
response = cast(
|
||||
Response,
|
||||
client.get_list(
|
||||
**params
|
||||
)
|
||||
params = (
|
||||
ListExpansionsBuilder(params)
|
||||
.add_expansions(expansions)
|
||||
.add_user_fields(user_fields)
|
||||
.add_list_fields(list_fields)
|
||||
.build()
|
||||
)
|
||||
|
||||
response = cast(Response, client.get_list(**params))
|
||||
|
||||
meta = {}
|
||||
owner_id = ""
|
||||
owner_username = ""
|
||||
@@ -145,7 +150,7 @@ class TwitterGetListBlock(Block):
|
||||
input_data.list_id,
|
||||
input_data.expansions,
|
||||
input_data.user_fields,
|
||||
input_data.list_fields
|
||||
input_data.list_fields,
|
||||
)
|
||||
|
||||
yield "id", str(list_data["id"])
|
||||
@@ -163,6 +168,7 @@ class TwitterGetListBlock(Block):
|
||||
except Exception as e:
|
||||
yield "error", handle_tweepy_exception(e)
|
||||
|
||||
|
||||
class TwitterGetOwnedListsBlock(Block):
|
||||
"""
|
||||
Gets all Lists owned by the specified user
|
||||
@@ -170,13 +176,13 @@ class TwitterGetOwnedListsBlock(Block):
|
||||
|
||||
class Input(ListExpansionInputs):
|
||||
credentials: TwitterCredentialsInput = TwitterCredentialsField(
|
||||
["tweet.read", "users.read","list.read", "offline.access"]
|
||||
["tweet.read", "users.read", "list.read", "offline.access"]
|
||||
)
|
||||
|
||||
user_id: str = SchemaField(
|
||||
description="The user ID whose owned Lists to retrieve",
|
||||
placeholder="Enter user ID",
|
||||
required=True
|
||||
required=True,
|
||||
)
|
||||
|
||||
max_results: int = SchemaField(
|
||||
@@ -190,7 +196,7 @@ class TwitterGetOwnedListsBlock(Block):
|
||||
description="Token for pagination",
|
||||
placeholder="Enter pagination token",
|
||||
advanced=True,
|
||||
default=""
|
||||
default="",
|
||||
)
|
||||
|
||||
class Output(BlockSchema):
|
||||
@@ -201,7 +207,9 @@ class TwitterGetOwnedListsBlock(Block):
|
||||
|
||||
# Complete outputs
|
||||
data: list[dict] = SchemaField(description="Complete owned lists data")
|
||||
included: dict = SchemaField(description="Additional data requested via expansions")
|
||||
included: dict = SchemaField(
|
||||
description="Additional data requested via expansions"
|
||||
)
|
||||
meta: dict = SchemaField(description="Metadata about the response")
|
||||
error: str = SchemaField(description="Error message if the request failed")
|
||||
|
||||
@@ -218,23 +226,39 @@ class TwitterGetOwnedListsBlock(Block):
|
||||
"credentials": TEST_CREDENTIALS_INPUT,
|
||||
"expansions": [],
|
||||
"list_fields": [],
|
||||
"user_fields": []
|
||||
"user_fields": [],
|
||||
},
|
||||
test_credentials=TEST_CREDENTIALS,
|
||||
test_output=[
|
||||
("list_ids", ["84839422"]),
|
||||
("list_names", ["Official Twitter Accounts"]),
|
||||
("next_token", None),
|
||||
("data", {"owned_lists": [{"id": "84839422", "name": "Official Twitter Accounts"}]}),
|
||||
(
|
||||
"data",
|
||||
{
|
||||
"owned_lists": [
|
||||
{"id": "84839422", "name": "Official Twitter Accounts"}
|
||||
]
|
||||
},
|
||||
),
|
||||
("included", {}),
|
||||
("meta", {}),
|
||||
("error", "")
|
||||
("error", ""),
|
||||
],
|
||||
test_mock={
|
||||
"get_owned_lists": lambda *args, **kwargs: ({
|
||||
"owned_lists": [{"id": "84839422", "name": "Official Twitter Accounts"}]
|
||||
}, {}, {}, ["84839422"], ["Official Twitter Accounts"], None)
|
||||
}
|
||||
"get_owned_lists": lambda *args, **kwargs: (
|
||||
{
|
||||
"owned_lists": [
|
||||
{"id": "84839422", "name": "Official Twitter Accounts"}
|
||||
]
|
||||
},
|
||||
{},
|
||||
{},
|
||||
["84839422"],
|
||||
["Official Twitter Accounts"],
|
||||
None,
|
||||
)
|
||||
},
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
@@ -245,7 +269,7 @@ class TwitterGetOwnedListsBlock(Block):
|
||||
pagination_token: str,
|
||||
expansions: list[ListExpansions],
|
||||
user_fields: list[TweetUserFields],
|
||||
list_fields: list[ListFields]
|
||||
list_fields: list[ListFields],
|
||||
):
|
||||
try:
|
||||
client = tweepy.Client(
|
||||
@@ -255,21 +279,21 @@ class TwitterGetOwnedListsBlock(Block):
|
||||
params = {
|
||||
"id": user_id,
|
||||
"max_results": max_results,
|
||||
"pagination_token": None if pagination_token == "" else pagination_token,
|
||||
"user_auth": False
|
||||
"pagination_token": (
|
||||
None if pagination_token == "" else pagination_token
|
||||
),
|
||||
"user_auth": False,
|
||||
}
|
||||
|
||||
params = (ListExpansionsBuilder(params)
|
||||
.add_expansions(expansions)
|
||||
.add_user_fields(user_fields)
|
||||
.add_list_fields(list_fields)
|
||||
.build())
|
||||
|
||||
response = cast(
|
||||
Response,
|
||||
client.get_owned_lists(**params)
|
||||
params = (
|
||||
ListExpansionsBuilder(params)
|
||||
.add_expansions(expansions)
|
||||
.add_user_fields(user_fields)
|
||||
.add_list_fields(list_fields)
|
||||
.build()
|
||||
)
|
||||
|
||||
response = cast(Response, client.get_owned_lists(**params))
|
||||
|
||||
meta = {}
|
||||
list_ids = []
|
||||
@@ -289,7 +313,6 @@ class TwitterGetOwnedListsBlock(Block):
|
||||
|
||||
return data, included, meta, list_ids, list_names, next_token
|
||||
|
||||
|
||||
raise Exception("Lists not found")
|
||||
|
||||
except tweepy.TweepyException:
|
||||
@@ -303,14 +326,16 @@ class TwitterGetOwnedListsBlock(Block):
|
||||
**kwargs,
|
||||
) -> BlockOutput:
|
||||
try:
|
||||
list_data, included, meta, list_ids, list_names, next_token = self.get_owned_lists(
|
||||
credentials,
|
||||
input_data.user_id,
|
||||
input_data.max_results,
|
||||
input_data.pagination_token,
|
||||
input_data.expansions,
|
||||
input_data.user_fields,
|
||||
input_data.list_fields
|
||||
list_data, included, meta, list_ids, list_names, next_token = (
|
||||
self.get_owned_lists(
|
||||
credentials,
|
||||
input_data.user_id,
|
||||
input_data.max_results,
|
||||
input_data.pagination_token,
|
||||
input_data.expansions,
|
||||
input_data.user_fields,
|
||||
input_data.list_fields,
|
||||
)
|
||||
)
|
||||
|
||||
if list_ids:
|
||||
|
||||
@@ -1,14 +1,8 @@
|
||||
from typing import cast
|
||||
|
||||
from backend.blocks.twitter._serializer import IncludesSerializer, ResponseDataSerializer
|
||||
import tweepy
|
||||
from tweepy.client import Response
|
||||
|
||||
from backend.data.block import Block, BlockCategory, BlockOutput, BlockSchema
|
||||
from backend.data.model import SchemaField
|
||||
from backend.blocks.twitter._builders import ListExpansionsBuilder, UserExpansionsBuilder
|
||||
from backend.blocks.twitter._types import ListExpansionInputs, ListExpansions, ListFields, TweetFields, TweetUserFields, UserExpansionInputs, UserExpansions
|
||||
from backend.blocks.twitter.tweepy_exceptions import handle_tweepy_exception
|
||||
from backend.blocks.twitter._auth import (
|
||||
TEST_CREDENTIALS,
|
||||
TEST_CREDENTIALS_INPUT,
|
||||
@@ -16,6 +10,26 @@ from backend.blocks.twitter._auth import (
|
||||
TwitterCredentialsField,
|
||||
TwitterCredentialsInput,
|
||||
)
|
||||
from backend.blocks.twitter._builders import (
|
||||
ListExpansionsBuilder,
|
||||
UserExpansionsBuilder,
|
||||
)
|
||||
from backend.blocks.twitter._serializer import (
|
||||
IncludesSerializer,
|
||||
ResponseDataSerializer,
|
||||
)
|
||||
from backend.blocks.twitter._types import (
|
||||
ListExpansionInputs,
|
||||
ListExpansions,
|
||||
ListFields,
|
||||
TweetFields,
|
||||
TweetUserFields,
|
||||
UserExpansionInputs,
|
||||
UserExpansions,
|
||||
)
|
||||
from backend.blocks.twitter.tweepy_exceptions import handle_tweepy_exception
|
||||
from backend.data.block import Block, BlockCategory, BlockOutput, BlockSchema
|
||||
from backend.data.model import SchemaField
|
||||
|
||||
|
||||
class TwitterRemoveListMemberBlock(Block):
|
||||
@@ -25,28 +39,26 @@ class TwitterRemoveListMemberBlock(Block):
|
||||
|
||||
class Input(BlockSchema):
|
||||
credentials: TwitterCredentialsInput = TwitterCredentialsField(
|
||||
["list.write","users.read","tweet.read", "offline.access"]
|
||||
["list.write", "users.read", "tweet.read", "offline.access"]
|
||||
)
|
||||
|
||||
list_id: str = SchemaField(
|
||||
description="The ID of the List to remove the member from",
|
||||
placeholder="Enter list ID",
|
||||
required=True
|
||||
required=True,
|
||||
)
|
||||
|
||||
user_id: str = SchemaField(
|
||||
description="The ID of the user to remove from the List",
|
||||
placeholder="Enter user ID to remove",
|
||||
required=True
|
||||
required=True,
|
||||
)
|
||||
|
||||
class Output(BlockSchema):
|
||||
success: bool = SchemaField(
|
||||
description="Whether the member was successfully removed"
|
||||
)
|
||||
error: str = SchemaField(
|
||||
description="Error message if the removal failed"
|
||||
)
|
||||
error: str = SchemaField(description="Error message if the removal failed")
|
||||
|
||||
def __init__(self):
|
||||
super().__init__(
|
||||
@@ -58,30 +70,20 @@ class TwitterRemoveListMemberBlock(Block):
|
||||
test_input={
|
||||
"list_id": "123456789",
|
||||
"user_id": "987654321",
|
||||
"credentials": TEST_CREDENTIALS_INPUT
|
||||
"credentials": TEST_CREDENTIALS_INPUT,
|
||||
},
|
||||
test_credentials=TEST_CREDENTIALS,
|
||||
test_output=[("success", True)],
|
||||
test_mock={
|
||||
"remove_list_member": lambda *args, **kwargs: True
|
||||
},
|
||||
test_mock={"remove_list_member": lambda *args, **kwargs: True},
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def remove_list_member(
|
||||
credentials: TwitterCredentials,
|
||||
list_id: str,
|
||||
user_id: str
|
||||
):
|
||||
def remove_list_member(credentials: TwitterCredentials, list_id: str, user_id: str):
|
||||
try:
|
||||
client = tweepy.Client(
|
||||
bearer_token=credentials.access_token.get_secret_value()
|
||||
)
|
||||
client.remove_list_member(
|
||||
id=list_id,
|
||||
user_id=user_id,
|
||||
user_auth=False
|
||||
)
|
||||
client.remove_list_member(id=list_id, user_id=user_id, user_auth=False)
|
||||
return True
|
||||
except tweepy.TweepyException:
|
||||
raise
|
||||
@@ -98,15 +100,14 @@ class TwitterRemoveListMemberBlock(Block):
|
||||
) -> BlockOutput:
|
||||
try:
|
||||
success = self.remove_list_member(
|
||||
credentials,
|
||||
input_data.list_id,
|
||||
input_data.user_id
|
||||
credentials, input_data.list_id, input_data.user_id
|
||||
)
|
||||
yield "success", success
|
||||
|
||||
except Exception as e:
|
||||
yield "error", handle_tweepy_exception(e)
|
||||
|
||||
|
||||
class TwitterAddListMemberBlock(Block):
|
||||
"""
|
||||
Adds a member to a Twitter List that the authenticated user owns
|
||||
@@ -120,22 +121,20 @@ class TwitterAddListMemberBlock(Block):
|
||||
list_id: str = SchemaField(
|
||||
description="The ID of the List to add the member to",
|
||||
placeholder="Enter list ID",
|
||||
required=True
|
||||
required=True,
|
||||
)
|
||||
|
||||
user_id: str = SchemaField(
|
||||
description="The ID of the user to add to the List",
|
||||
placeholder="Enter user ID to add",
|
||||
required=True
|
||||
required=True,
|
||||
)
|
||||
|
||||
class Output(BlockSchema):
|
||||
success: bool = SchemaField(
|
||||
description="Whether the member was successfully added"
|
||||
)
|
||||
error: str = SchemaField(
|
||||
description="Error message if the addition failed"
|
||||
)
|
||||
error: str = SchemaField(description="Error message if the addition failed")
|
||||
|
||||
def __init__(self):
|
||||
super().__init__(
|
||||
@@ -147,30 +146,20 @@ class TwitterAddListMemberBlock(Block):
|
||||
test_input={
|
||||
"list_id": "123456789",
|
||||
"user_id": "987654321",
|
||||
"credentials": TEST_CREDENTIALS_INPUT
|
||||
"credentials": TEST_CREDENTIALS_INPUT,
|
||||
},
|
||||
test_credentials=TEST_CREDENTIALS,
|
||||
test_output=[("success", True)],
|
||||
test_mock={
|
||||
"add_list_member": lambda *args, **kwargs: True
|
||||
},
|
||||
test_mock={"add_list_member": lambda *args, **kwargs: True},
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def add_list_member(
|
||||
credentials: TwitterCredentials,
|
||||
list_id: str,
|
||||
user_id: str
|
||||
):
|
||||
def add_list_member(credentials: TwitterCredentials, list_id: str, user_id: str):
|
||||
try:
|
||||
client = tweepy.Client(
|
||||
bearer_token=credentials.access_token.get_secret_value()
|
||||
)
|
||||
client.add_list_member(
|
||||
id=list_id,
|
||||
user_id=user_id,
|
||||
user_auth=False
|
||||
)
|
||||
client.add_list_member(id=list_id, user_id=user_id, user_auth=False)
|
||||
return True
|
||||
except tweepy.TweepyException:
|
||||
raise
|
||||
@@ -187,15 +176,14 @@ class TwitterAddListMemberBlock(Block):
|
||||
) -> BlockOutput:
|
||||
try:
|
||||
success = self.add_list_member(
|
||||
credentials,
|
||||
input_data.list_id,
|
||||
input_data.user_id
|
||||
credentials, input_data.list_id, input_data.user_id
|
||||
)
|
||||
yield "success", success
|
||||
|
||||
except Exception as e:
|
||||
yield "error", handle_tweepy_exception(e)
|
||||
|
||||
|
||||
class TwitterGetListMembersBlock(Block):
|
||||
"""
|
||||
Gets the members of a specified Twitter List
|
||||
@@ -209,21 +197,21 @@ class TwitterGetListMembersBlock(Block):
|
||||
list_id: str = SchemaField(
|
||||
description="The ID of the List to get members from",
|
||||
placeholder="Enter list ID",
|
||||
required=True
|
||||
required=True,
|
||||
)
|
||||
|
||||
max_results: int = SchemaField(
|
||||
description="Maximum number of results per page (1-100)",
|
||||
placeholder="Enter max results",
|
||||
default=10,
|
||||
advanced=True
|
||||
advanced=True,
|
||||
)
|
||||
|
||||
pagination_token: str = SchemaField(
|
||||
description="Token for pagination of results",
|
||||
placeholder="Enter pagination token",
|
||||
default="",
|
||||
advanced=True
|
||||
advanced=True,
|
||||
)
|
||||
|
||||
class Output(BlockSchema):
|
||||
@@ -231,8 +219,12 @@ class TwitterGetListMembersBlock(Block):
|
||||
usernames: list[str] = SchemaField(description="List of member usernames")
|
||||
next_token: str = SchemaField(description="Next token for pagination")
|
||||
|
||||
data: list[dict] = SchemaField(description="Complete user data for list members")
|
||||
included: dict = SchemaField(description="Additional data requested via expansions")
|
||||
data: list[dict] = SchemaField(
|
||||
description="Complete user data for list members"
|
||||
)
|
||||
included: dict = SchemaField(
|
||||
description="Additional data requested via expansions"
|
||||
)
|
||||
meta: dict = SchemaField(description="Metadata including pagination info")
|
||||
|
||||
error: str = SchemaField(description="Error message if the request failed")
|
||||
@@ -251,30 +243,36 @@ class TwitterGetListMembersBlock(Block):
|
||||
"credentials": TEST_CREDENTIALS_INPUT,
|
||||
"expansions": [],
|
||||
"tweet_fields": [],
|
||||
"user_fields": []
|
||||
"user_fields": [],
|
||||
},
|
||||
test_credentials=TEST_CREDENTIALS,
|
||||
test_output=[
|
||||
("ids", ["12345", "67890"]),
|
||||
("usernames", ["testuser1", "testuser2"]),
|
||||
("data", [
|
||||
{"id": "12345", "username": "testuser1"},
|
||||
{"id": "67890", "username": "testuser2"}
|
||||
]),
|
||||
(
|
||||
"data",
|
||||
[
|
||||
{"id": "12345", "username": "testuser1"},
|
||||
{"id": "67890", "username": "testuser2"},
|
||||
],
|
||||
),
|
||||
("included", {}),
|
||||
("meta", {"next_token": "next_token_value"}),
|
||||
("next_token", "next_token_value")
|
||||
("next_token", "next_token_value"),
|
||||
],
|
||||
test_mock={
|
||||
"get_list_members": lambda *args, **kwargs: (
|
||||
["12345", "67890"],
|
||||
["testuser1", "testuser2"],
|
||||
[{"id": "12345", "username": "testuser1"}, {"id": "67890", "username": "testuser2"}],
|
||||
[
|
||||
{"id": "12345", "username": "testuser1"},
|
||||
{"id": "67890", "username": "testuser2"},
|
||||
],
|
||||
{},
|
||||
{"next_token": "next_token_value"},
|
||||
"next_token_value"
|
||||
"next_token_value",
|
||||
)
|
||||
}
|
||||
},
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
@@ -295,21 +293,22 @@ class TwitterGetListMembersBlock(Block):
|
||||
params = {
|
||||
"id": list_id,
|
||||
"max_results": max_results,
|
||||
"pagination_token": None if pagination_token == "" else pagination_token,
|
||||
"user_auth": False
|
||||
"pagination_token": (
|
||||
None if pagination_token == "" else pagination_token
|
||||
),
|
||||
"user_auth": False,
|
||||
}
|
||||
|
||||
params = (UserExpansionsBuilder(params)
|
||||
.add_expansions(expansions)
|
||||
.add_tweet_fields(tweet_fields)
|
||||
.add_user_fields(user_fields)
|
||||
.build())
|
||||
|
||||
response = cast(
|
||||
Response,
|
||||
client.get_list_members(**params)
|
||||
params = (
|
||||
UserExpansionsBuilder(params)
|
||||
.add_expansions(expansions)
|
||||
.add_tweet_fields(tweet_fields)
|
||||
.add_user_fields(user_fields)
|
||||
.build()
|
||||
)
|
||||
|
||||
response = cast(Response, client.get_list_members(**params))
|
||||
|
||||
meta = {}
|
||||
next_token = None
|
||||
user_ids = []
|
||||
@@ -347,7 +346,7 @@ class TwitterGetListMembersBlock(Block):
|
||||
input_data.pagination_token,
|
||||
input_data.expansions,
|
||||
input_data.tweet_fields,
|
||||
input_data.user_fields
|
||||
input_data.user_fields,
|
||||
)
|
||||
|
||||
if ids:
|
||||
@@ -366,6 +365,7 @@ class TwitterGetListMembersBlock(Block):
|
||||
except Exception as e:
|
||||
yield "error", handle_tweepy_exception(e)
|
||||
|
||||
|
||||
class TwitterGetListMembershipsBlock(Block):
|
||||
"""
|
||||
Gets all Lists that a specified user is a member of
|
||||
@@ -379,7 +379,7 @@ class TwitterGetListMembershipsBlock(Block):
|
||||
user_id: str = SchemaField(
|
||||
description="The ID of the user whose List memberships to retrieve",
|
||||
placeholder="Enter user ID",
|
||||
required=True
|
||||
required=True,
|
||||
)
|
||||
|
||||
max_results: int = SchemaField(
|
||||
@@ -389,11 +389,11 @@ class TwitterGetListMembershipsBlock(Block):
|
||||
default=10,
|
||||
)
|
||||
|
||||
pagination_token: str = SchemaField(
|
||||
pagination_token: str = SchemaField(
|
||||
description="Token for pagination of results",
|
||||
placeholder="Enter pagination token",
|
||||
advanced=True,
|
||||
default=""
|
||||
default="",
|
||||
)
|
||||
|
||||
class Output(BlockSchema):
|
||||
@@ -401,7 +401,9 @@ class TwitterGetListMembershipsBlock(Block):
|
||||
next_token: str = SchemaField(description="Next token for pagination")
|
||||
|
||||
data: list[dict] = SchemaField(description="List membership data")
|
||||
included: dict = SchemaField(description="Additional data requested via expansions")
|
||||
included: dict = SchemaField(
|
||||
description="Additional data requested via expansions"
|
||||
)
|
||||
meta: dict = SchemaField(description="Metadata about pagination")
|
||||
error: str = SchemaField(description="Error message if the request failed")
|
||||
|
||||
@@ -419,7 +421,7 @@ class TwitterGetListMembershipsBlock(Block):
|
||||
"credentials": TEST_CREDENTIALS_INPUT,
|
||||
"expansions": [],
|
||||
"list_fields": [],
|
||||
"user_fields": []
|
||||
"user_fields": [],
|
||||
},
|
||||
test_credentials=TEST_CREDENTIALS,
|
||||
test_output=[
|
||||
@@ -427,7 +429,7 @@ class TwitterGetListMembershipsBlock(Block):
|
||||
("data", {"lists": [{"id": "84839422"}]}),
|
||||
("included", {}),
|
||||
("meta", {"next_token": None}),
|
||||
("next_token", None)
|
||||
("next_token", None),
|
||||
],
|
||||
test_mock={
|
||||
"get_list_memberships": lambda *args, **kwargs: (
|
||||
@@ -435,9 +437,9 @@ class TwitterGetListMembershipsBlock(Block):
|
||||
{},
|
||||
{"next_token": None},
|
||||
["84839422"],
|
||||
None
|
||||
None,
|
||||
)
|
||||
}
|
||||
},
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
@@ -448,7 +450,7 @@ class TwitterGetListMembershipsBlock(Block):
|
||||
pagination_token: str,
|
||||
expansions: list[ListExpansions],
|
||||
user_fields: list[TweetUserFields],
|
||||
list_fields: list[ListFields]
|
||||
list_fields: list[ListFields],
|
||||
):
|
||||
try:
|
||||
client = tweepy.Client(
|
||||
@@ -458,21 +460,22 @@ class TwitterGetListMembershipsBlock(Block):
|
||||
params = {
|
||||
"id": user_id,
|
||||
"max_results": max_results,
|
||||
"pagination_token": None if pagination_token == "" else pagination_token,
|
||||
"user_auth": False
|
||||
"pagination_token": (
|
||||
None if pagination_token == "" else pagination_token
|
||||
),
|
||||
"user_auth": False,
|
||||
}
|
||||
|
||||
params = (ListExpansionsBuilder(params)
|
||||
.add_expansions(expansions)
|
||||
.add_user_fields(user_fields)
|
||||
.add_list_fields(list_fields)
|
||||
.build())
|
||||
|
||||
response = cast(
|
||||
Response,
|
||||
client.get_list_memberships(**params)
|
||||
params = (
|
||||
ListExpansionsBuilder(params)
|
||||
.add_expansions(expansions)
|
||||
.add_user_fields(user_fields)
|
||||
.add_list_fields(list_fields)
|
||||
.build()
|
||||
)
|
||||
|
||||
response = cast(Response, client.get_list_memberships(**params))
|
||||
|
||||
meta = {}
|
||||
next_token = None
|
||||
list_ids = []
|
||||
@@ -510,7 +513,7 @@ class TwitterGetListMembershipsBlock(Block):
|
||||
input_data.pagination_token,
|
||||
input_data.expansions,
|
||||
input_data.user_fields,
|
||||
input_data.list_fields
|
||||
input_data.list_fields,
|
||||
)
|
||||
|
||||
if list_ids:
|
||||
|
||||
@@ -1,14 +1,8 @@
|
||||
from typing import cast
|
||||
|
||||
from backend.blocks.twitter._serializer import IncludesSerializer, ResponseDataSerializer
|
||||
import tweepy
|
||||
from tweepy.client import Response
|
||||
|
||||
from backend.blocks.twitter._builders import TweetExpansionsBuilder
|
||||
from backend.blocks.twitter._types import TweetExpansionInputs, TweetExpansions, TweetFields, TweetMediaFields, TweetPlaceFields, TweetPollFields, TweetUserFields
|
||||
from backend.blocks.twitter.tweepy_exceptions import handle_tweepy_exception
|
||||
from backend.data.block import Block, BlockCategory, BlockOutput, BlockSchema
|
||||
from backend.data.model import SchemaField
|
||||
from backend.blocks.twitter._auth import (
|
||||
TEST_CREDENTIALS,
|
||||
TEST_CREDENTIALS_INPUT,
|
||||
@@ -16,6 +10,24 @@ from backend.blocks.twitter._auth import (
|
||||
TwitterCredentialsField,
|
||||
TwitterCredentialsInput,
|
||||
)
|
||||
from backend.blocks.twitter._builders import TweetExpansionsBuilder
|
||||
from backend.blocks.twitter._serializer import (
|
||||
IncludesSerializer,
|
||||
ResponseDataSerializer,
|
||||
)
|
||||
from backend.blocks.twitter._types import (
|
||||
TweetExpansionInputs,
|
||||
TweetExpansions,
|
||||
TweetFields,
|
||||
TweetMediaFields,
|
||||
TweetPlaceFields,
|
||||
TweetPollFields,
|
||||
TweetUserFields,
|
||||
)
|
||||
from backend.blocks.twitter.tweepy_exceptions import handle_tweepy_exception
|
||||
from backend.data.block import Block, BlockCategory, BlockOutput, BlockSchema
|
||||
from backend.data.model import SchemaField
|
||||
|
||||
|
||||
class TwitterGetListTweetsBlock(Block):
|
||||
"""
|
||||
@@ -30,7 +42,7 @@ class TwitterGetListTweetsBlock(Block):
|
||||
list_id: str = SchemaField(
|
||||
description="The ID of the List whose Tweets you would like to retrieve",
|
||||
placeholder="Enter list ID",
|
||||
required=True
|
||||
required=True,
|
||||
)
|
||||
|
||||
max_results: int = SchemaField(
|
||||
@@ -43,7 +55,7 @@ class TwitterGetListTweetsBlock(Block):
|
||||
pagination_token: str = SchemaField(
|
||||
description="Token for paginating through results",
|
||||
placeholder="Enter pagination token",
|
||||
default = "",
|
||||
default="",
|
||||
advanced=True,
|
||||
)
|
||||
|
||||
@@ -55,8 +67,12 @@ class TwitterGetListTweetsBlock(Block):
|
||||
|
||||
# Complete outputs
|
||||
data: list[dict] = SchemaField(description="Complete list tweets data")
|
||||
included: dict = SchemaField(description="Additional data requested via expansions")
|
||||
meta: dict = SchemaField(description="Response metadata including pagination tokens")
|
||||
included: dict = SchemaField(
|
||||
description="Additional data requested via expansions"
|
||||
)
|
||||
meta: dict = SchemaField(
|
||||
description="Response metadata including pagination tokens"
|
||||
)
|
||||
error: str = SchemaField(description="Error message if the request failed")
|
||||
|
||||
def __init__(self):
|
||||
@@ -76,7 +92,7 @@ class TwitterGetListTweetsBlock(Block):
|
||||
"place_fields": [],
|
||||
"poll_fields": [],
|
||||
"tweet_fields": [],
|
||||
"user_fields": []
|
||||
"user_fields": [],
|
||||
},
|
||||
test_credentials=TEST_CREDENTIALS,
|
||||
test_output=[
|
||||
@@ -86,13 +102,18 @@ class TwitterGetListTweetsBlock(Block):
|
||||
("data", {"list_tweets": [{"id": "1234567890", "text": "Test tweet"}]}),
|
||||
("included", {}),
|
||||
("meta", {}),
|
||||
("error", "")
|
||||
("error", ""),
|
||||
],
|
||||
test_mock={
|
||||
"get_list_tweets": lambda *args, **kwargs: ({
|
||||
"list_tweets": [{"id": "1234567890", "text": "Test tweet"}]
|
||||
}, {}, {}, ["1234567890"], ["Test tweet"], None)
|
||||
}
|
||||
"get_list_tweets": lambda *args, **kwargs: (
|
||||
{"list_tweets": [{"id": "1234567890", "text": "Test tweet"}]},
|
||||
{},
|
||||
{},
|
||||
["1234567890"],
|
||||
["Test tweet"],
|
||||
None,
|
||||
)
|
||||
},
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
@@ -106,7 +127,7 @@ class TwitterGetListTweetsBlock(Block):
|
||||
place_fields: list[TweetPlaceFields],
|
||||
poll_fields: list[TweetPollFields],
|
||||
tweet_fields: list[TweetFields],
|
||||
user_fields: list[TweetUserFields]
|
||||
user_fields: list[TweetUserFields],
|
||||
):
|
||||
try:
|
||||
client = tweepy.Client(
|
||||
@@ -116,24 +137,25 @@ class TwitterGetListTweetsBlock(Block):
|
||||
params = {
|
||||
"id": list_id,
|
||||
"max_results": max_results,
|
||||
"pagination_token": None if pagination_token == "" else pagination_token,
|
||||
"user_auth": False
|
||||
"pagination_token": (
|
||||
None if pagination_token == "" else pagination_token
|
||||
),
|
||||
"user_auth": False,
|
||||
}
|
||||
|
||||
params = (TweetExpansionsBuilder(params)
|
||||
.add_expansions(expansions)
|
||||
.add_media_fields(media_fields)
|
||||
.add_place_fields(place_fields)
|
||||
.add_poll_fields(poll_fields)
|
||||
.add_tweet_fields(tweet_fields)
|
||||
.add_user_fields(user_fields)
|
||||
.build())
|
||||
|
||||
response = cast(
|
||||
Response,
|
||||
client.get_list_tweets(**params)
|
||||
params = (
|
||||
TweetExpansionsBuilder(params)
|
||||
.add_expansions(expansions)
|
||||
.add_media_fields(media_fields)
|
||||
.add_place_fields(place_fields)
|
||||
.add_poll_fields(poll_fields)
|
||||
.add_tweet_fields(tweet_fields)
|
||||
.add_user_fields(user_fields)
|
||||
.build()
|
||||
)
|
||||
|
||||
response = cast(Response, client.get_list_tweets(**params))
|
||||
|
||||
meta = {}
|
||||
tweet_ids = []
|
||||
texts = []
|
||||
@@ -165,17 +187,19 @@ class TwitterGetListTweetsBlock(Block):
|
||||
**kwargs,
|
||||
) -> BlockOutput:
|
||||
try:
|
||||
list_data, included, meta, tweet_ids, texts, next_token = self.get_list_tweets(
|
||||
credentials,
|
||||
input_data.list_id,
|
||||
input_data.max_results,
|
||||
input_data.pagination_token,
|
||||
input_data.expansions,
|
||||
input_data.media_fields,
|
||||
input_data.place_fields,
|
||||
input_data.poll_fields,
|
||||
input_data.tweet_fields,
|
||||
input_data.user_fields
|
||||
list_data, included, meta, tweet_ids, texts, next_token = (
|
||||
self.get_list_tweets(
|
||||
credentials,
|
||||
input_data.list_id,
|
||||
input_data.max_results,
|
||||
input_data.pagination_token,
|
||||
input_data.expansions,
|
||||
input_data.media_fields,
|
||||
input_data.place_fields,
|
||||
input_data.poll_fields,
|
||||
input_data.tweet_fields,
|
||||
input_data.user_fields,
|
||||
)
|
||||
)
|
||||
|
||||
if tweet_ids:
|
||||
|
||||
@@ -3,9 +3,6 @@ from typing import cast
|
||||
import tweepy
|
||||
from tweepy.client import Response
|
||||
|
||||
from backend.data.block import Block, BlockCategory, BlockOutput, BlockSchema
|
||||
from backend.data.model import SchemaField
|
||||
from backend.blocks.twitter.tweepy_exceptions import handle_tweepy_exception
|
||||
from backend.blocks.twitter._auth import (
|
||||
TEST_CREDENTIALS,
|
||||
TEST_CREDENTIALS_INPUT,
|
||||
@@ -13,6 +10,9 @@ from backend.blocks.twitter._auth import (
|
||||
TwitterCredentialsField,
|
||||
TwitterCredentialsInput,
|
||||
)
|
||||
from backend.blocks.twitter.tweepy_exceptions import handle_tweepy_exception
|
||||
from backend.data.block import Block, BlockCategory, BlockOutput, BlockSchema
|
||||
from backend.data.model import SchemaField
|
||||
|
||||
|
||||
class TwitterDeleteListBlock(Block):
|
||||
@@ -28,7 +28,7 @@ class TwitterDeleteListBlock(Block):
|
||||
list_id: str = SchemaField(
|
||||
description="The ID of the List to be deleted",
|
||||
placeholder="Enter list ID",
|
||||
required=True
|
||||
required=True,
|
||||
)
|
||||
|
||||
class Output(BlockSchema):
|
||||
@@ -42,31 +42,20 @@ class TwitterDeleteListBlock(Block):
|
||||
categories={BlockCategory.SOCIAL},
|
||||
input_schema=TwitterDeleteListBlock.Input,
|
||||
output_schema=TwitterDeleteListBlock.Output,
|
||||
test_input={
|
||||
"list_id": "1234567890",
|
||||
"credentials": TEST_CREDENTIALS_INPUT
|
||||
},
|
||||
test_input={"list_id": "1234567890", "credentials": TEST_CREDENTIALS_INPUT},
|
||||
test_credentials=TEST_CREDENTIALS,
|
||||
test_output=[("success", True)],
|
||||
test_mock={
|
||||
"delete_list": lambda *args, **kwargs: True
|
||||
},
|
||||
test_mock={"delete_list": lambda *args, **kwargs: True},
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def delete_list(
|
||||
credentials: TwitterCredentials,
|
||||
list_id: str
|
||||
):
|
||||
def delete_list(credentials: TwitterCredentials, list_id: str):
|
||||
try:
|
||||
client = tweepy.Client(
|
||||
bearer_token=credentials.access_token.get_secret_value()
|
||||
)
|
||||
|
||||
client.delete_list(
|
||||
id=list_id,
|
||||
user_auth=False
|
||||
)
|
||||
client.delete_list(id=list_id, user_auth=False)
|
||||
return True
|
||||
|
||||
except tweepy.TweepyException:
|
||||
@@ -83,15 +72,13 @@ class TwitterDeleteListBlock(Block):
|
||||
**kwargs,
|
||||
) -> BlockOutput:
|
||||
try:
|
||||
success = self.delete_list(
|
||||
credentials,
|
||||
input_data.list_id
|
||||
)
|
||||
success = self.delete_list(credentials, input_data.list_id)
|
||||
yield "success", success
|
||||
|
||||
except Exception as e:
|
||||
yield "error", handle_tweepy_exception(e)
|
||||
|
||||
|
||||
class TwitterUpdateListBlock(Block):
|
||||
"""
|
||||
Updates a Twitter List owned by the authenticated user
|
||||
@@ -108,7 +95,6 @@ class TwitterUpdateListBlock(Block):
|
||||
advanced=False,
|
||||
)
|
||||
|
||||
|
||||
name: str = SchemaField(
|
||||
description="New name for the List",
|
||||
placeholder="Enter list name",
|
||||
@@ -139,21 +125,16 @@ class TwitterUpdateListBlock(Block):
|
||||
"name": "Updated List Name",
|
||||
"description": "Updated List Description",
|
||||
"private": True,
|
||||
"credentials": TEST_CREDENTIALS_INPUT
|
||||
"credentials": TEST_CREDENTIALS_INPUT,
|
||||
},
|
||||
test_credentials=TEST_CREDENTIALS,
|
||||
test_output=[("success", True)],
|
||||
test_mock={
|
||||
"update_list": lambda *args, **kwargs: True
|
||||
},
|
||||
test_mock={"update_list": lambda *args, **kwargs: True},
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def update_list(
|
||||
credentials: TwitterCredentials,
|
||||
list_id: str,
|
||||
name: str ,
|
||||
description: str
|
||||
credentials: TwitterCredentials, list_id: str, name: str, description: str
|
||||
):
|
||||
try:
|
||||
client = tweepy.Client(
|
||||
@@ -164,7 +145,7 @@ class TwitterUpdateListBlock(Block):
|
||||
id=list_id,
|
||||
name=None if name == "" else name,
|
||||
description=None if description == "" else description,
|
||||
user_auth=False
|
||||
user_auth=False,
|
||||
)
|
||||
return True
|
||||
|
||||
@@ -193,6 +174,7 @@ class TwitterUpdateListBlock(Block):
|
||||
except Exception as e:
|
||||
yield "error", handle_tweepy_exception(e)
|
||||
|
||||
|
||||
class TwitterCreateListBlock(Block):
|
||||
"""
|
||||
Creates a Twitter List owned by the authenticated user
|
||||
@@ -214,13 +196,13 @@ class TwitterCreateListBlock(Block):
|
||||
description="Description of the List",
|
||||
placeholder="Enter list description",
|
||||
advanced=False,
|
||||
default=""
|
||||
default="",
|
||||
)
|
||||
|
||||
private: bool = SchemaField(
|
||||
description="Whether the List should be private",
|
||||
advanced=False,
|
||||
default=False
|
||||
default=False,
|
||||
)
|
||||
|
||||
class Output(BlockSchema):
|
||||
@@ -239,33 +221,38 @@ class TwitterCreateListBlock(Block):
|
||||
"name": "New List Name",
|
||||
"description": "New List Description",
|
||||
"private": True,
|
||||
"credentials": TEST_CREDENTIALS_INPUT
|
||||
"credentials": TEST_CREDENTIALS_INPUT,
|
||||
},
|
||||
test_credentials=TEST_CREDENTIALS,
|
||||
test_output=[("list_id", "1234567890"), ("url", "https://twitter.com/i/lists/1234567890")],
|
||||
test_output=[
|
||||
("list_id", "1234567890"),
|
||||
("url", "https://twitter.com/i/lists/1234567890"),
|
||||
],
|
||||
test_mock={
|
||||
"create_list": lambda *args, **kwargs: cast(Response, {"data": {"id": "1234567890"}})
|
||||
"create_list": lambda *args, **kwargs: cast(
|
||||
Response, {"data": {"id": "1234567890"}}
|
||||
)
|
||||
},
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def create_list(
|
||||
credentials: TwitterCredentials,
|
||||
name: str,
|
||||
description: str,
|
||||
private: bool
|
||||
credentials: TwitterCredentials, name: str, description: str, private: bool
|
||||
):
|
||||
try:
|
||||
client = tweepy.Client(
|
||||
bearer_token=credentials.access_token.get_secret_value()
|
||||
)
|
||||
|
||||
response = cast(Response, client.create_list(
|
||||
name=None if name == "" else name,
|
||||
description=None if description == "" else description,
|
||||
private=private,
|
||||
user_auth=False
|
||||
))
|
||||
response = cast(
|
||||
Response,
|
||||
client.create_list(
|
||||
name=None if name == "" else name,
|
||||
description=None if description == "" else description,
|
||||
private=private,
|
||||
user_auth=False,
|
||||
),
|
||||
)
|
||||
return response
|
||||
|
||||
except tweepy.TweepyException:
|
||||
@@ -283,10 +270,7 @@ class TwitterCreateListBlock(Block):
|
||||
) -> BlockOutput:
|
||||
try:
|
||||
response = self.create_list(
|
||||
credentials,
|
||||
input_data.name,
|
||||
input_data.description,
|
||||
input_data.private
|
||||
credentials, input_data.name, input_data.description, input_data.private
|
||||
)
|
||||
list_id = str(response.data["id"])
|
||||
yield "list_id", list_id
|
||||
|
||||
@@ -1,14 +1,8 @@
|
||||
from typing import cast
|
||||
|
||||
from backend.blocks.twitter._serializer import IncludesSerializer, ResponseDataSerializer
|
||||
import tweepy
|
||||
from tweepy.client import Response
|
||||
|
||||
from backend.data.block import Block, BlockCategory, BlockOutput, BlockSchema
|
||||
from backend.data.model import SchemaField
|
||||
from backend.blocks.twitter._builders import ListExpansionsBuilder
|
||||
from backend.blocks.twitter._types import ListExpansionInputs, ListExpansions, ListFields, TweetUserFields
|
||||
from backend.blocks.twitter.tweepy_exceptions import handle_tweepy_exception
|
||||
from backend.blocks.twitter._auth import (
|
||||
TEST_CREDENTIALS,
|
||||
TEST_CREDENTIALS_INPUT,
|
||||
@@ -16,6 +10,20 @@ from backend.blocks.twitter._auth import (
|
||||
TwitterCredentialsField,
|
||||
TwitterCredentialsInput,
|
||||
)
|
||||
from backend.blocks.twitter._builders import ListExpansionsBuilder
|
||||
from backend.blocks.twitter._serializer import (
|
||||
IncludesSerializer,
|
||||
ResponseDataSerializer,
|
||||
)
|
||||
from backend.blocks.twitter._types import (
|
||||
ListExpansionInputs,
|
||||
ListExpansions,
|
||||
ListFields,
|
||||
TweetUserFields,
|
||||
)
|
||||
from backend.blocks.twitter.tweepy_exceptions import handle_tweepy_exception
|
||||
from backend.data.block import Block, BlockCategory, BlockOutput, BlockSchema
|
||||
from backend.data.model import SchemaField
|
||||
|
||||
|
||||
class TwitterUnpinListBlock(Block):
|
||||
@@ -25,13 +33,13 @@ class TwitterUnpinListBlock(Block):
|
||||
|
||||
class Input(BlockSchema):
|
||||
credentials: TwitterCredentialsInput = TwitterCredentialsField(
|
||||
["list.write", "users.read","tweet.read", "offline.access"]
|
||||
["list.write", "users.read", "tweet.read", "offline.access"]
|
||||
)
|
||||
|
||||
list_id: str = SchemaField(
|
||||
description="The ID of the List to unpin",
|
||||
placeholder="Enter list ID",
|
||||
required=True
|
||||
required=True,
|
||||
)
|
||||
|
||||
class Output(BlockSchema):
|
||||
@@ -45,31 +53,20 @@ class TwitterUnpinListBlock(Block):
|
||||
categories={BlockCategory.SOCIAL},
|
||||
input_schema=TwitterUnpinListBlock.Input,
|
||||
output_schema=TwitterUnpinListBlock.Output,
|
||||
test_input={
|
||||
"list_id": "123456789",
|
||||
"credentials": TEST_CREDENTIALS_INPUT
|
||||
},
|
||||
test_input={"list_id": "123456789", "credentials": TEST_CREDENTIALS_INPUT},
|
||||
test_credentials=TEST_CREDENTIALS,
|
||||
test_output=[("success", True)],
|
||||
test_mock={
|
||||
"unpin_list": lambda *args, **kwargs: True
|
||||
},
|
||||
test_mock={"unpin_list": lambda *args, **kwargs: True},
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def unpin_list(
|
||||
credentials: TwitterCredentials,
|
||||
list_id: str
|
||||
):
|
||||
def unpin_list(credentials: TwitterCredentials, list_id: str):
|
||||
try:
|
||||
client = tweepy.Client(
|
||||
bearer_token=credentials.access_token.get_secret_value()
|
||||
)
|
||||
|
||||
client.unpin_list(
|
||||
list_id=list_id,
|
||||
user_auth=False
|
||||
)
|
||||
client.unpin_list(list_id=list_id, user_auth=False)
|
||||
|
||||
return True
|
||||
|
||||
@@ -87,15 +84,13 @@ class TwitterUnpinListBlock(Block):
|
||||
**kwargs,
|
||||
) -> BlockOutput:
|
||||
try:
|
||||
success = self.unpin_list(
|
||||
credentials,
|
||||
input_data.list_id
|
||||
)
|
||||
success = self.unpin_list(credentials, input_data.list_id)
|
||||
yield "success", success
|
||||
|
||||
except Exception as e:
|
||||
yield "error", handle_tweepy_exception(e)
|
||||
|
||||
|
||||
class TwitterPinListBlock(Block):
|
||||
"""
|
||||
Enables the authenticated user to pin a List.
|
||||
@@ -103,13 +98,13 @@ class TwitterPinListBlock(Block):
|
||||
|
||||
class Input(BlockSchema):
|
||||
credentials: TwitterCredentialsInput = TwitterCredentialsField(
|
||||
["list.write", "users.read","tweet.read", "offline.access"]
|
||||
["list.write", "users.read", "tweet.read", "offline.access"]
|
||||
)
|
||||
|
||||
list_id: str = SchemaField(
|
||||
description="The ID of the List to pin",
|
||||
placeholder="Enter list ID",
|
||||
required=True
|
||||
required=True,
|
||||
)
|
||||
|
||||
class Output(BlockSchema):
|
||||
@@ -123,31 +118,20 @@ class TwitterPinListBlock(Block):
|
||||
categories={BlockCategory.SOCIAL},
|
||||
input_schema=TwitterPinListBlock.Input,
|
||||
output_schema=TwitterPinListBlock.Output,
|
||||
test_input={
|
||||
"list_id": "123456789",
|
||||
"credentials": TEST_CREDENTIALS_INPUT
|
||||
},
|
||||
test_input={"list_id": "123456789", "credentials": TEST_CREDENTIALS_INPUT},
|
||||
test_credentials=TEST_CREDENTIALS,
|
||||
test_output=[("success", True)],
|
||||
test_mock={
|
||||
"pin_list": lambda *args, **kwargs: True
|
||||
},
|
||||
test_mock={"pin_list": lambda *args, **kwargs: True},
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def pin_list(
|
||||
credentials: TwitterCredentials,
|
||||
list_id: str
|
||||
):
|
||||
def pin_list(credentials: TwitterCredentials, list_id: str):
|
||||
try:
|
||||
client = tweepy.Client(
|
||||
bearer_token=credentials.access_token.get_secret_value()
|
||||
)
|
||||
|
||||
client.pin_list(
|
||||
list_id=list_id,
|
||||
user_auth=False
|
||||
)
|
||||
client.pin_list(list_id=list_id, user_auth=False)
|
||||
|
||||
return True
|
||||
|
||||
@@ -165,15 +149,13 @@ class TwitterPinListBlock(Block):
|
||||
**kwargs,
|
||||
) -> BlockOutput:
|
||||
try:
|
||||
success = self.pin_list(
|
||||
credentials,
|
||||
input_data.list_id
|
||||
)
|
||||
success = self.pin_list(credentials, input_data.list_id)
|
||||
yield "success", success
|
||||
|
||||
except Exception as e:
|
||||
yield "error", handle_tweepy_exception(e)
|
||||
|
||||
|
||||
class TwitterGetPinnedListsBlock(Block):
|
||||
"""
|
||||
Returns the Lists pinned by the authenticated user.
|
||||
@@ -185,11 +167,17 @@ class TwitterGetPinnedListsBlock(Block):
|
||||
)
|
||||
|
||||
class Output(BlockSchema):
|
||||
list_ids : list[str] = SchemaField(description="List IDs of the pinned lists")
|
||||
list_names : list[str] = SchemaField(description="List names of the pinned lists")
|
||||
list_ids: list[str] = SchemaField(description="List IDs of the pinned lists")
|
||||
list_names: list[str] = SchemaField(
|
||||
description="List names of the pinned lists"
|
||||
)
|
||||
|
||||
data: list[dict] = SchemaField(description="Response data containing pinned lists")
|
||||
included: dict = SchemaField(description="Additional data requested via expansions")
|
||||
data: list[dict] = SchemaField(
|
||||
description="Response data containing pinned lists"
|
||||
)
|
||||
included: dict = SchemaField(
|
||||
description="Additional data requested via expansions"
|
||||
)
|
||||
meta: dict = SchemaField(description="Metadata about the response")
|
||||
error: str = SchemaField(description="Error message if the request failed")
|
||||
|
||||
@@ -204,15 +192,18 @@ class TwitterGetPinnedListsBlock(Block):
|
||||
"expansions": [],
|
||||
"list_fields": [],
|
||||
"user_fields": [],
|
||||
"credentials": TEST_CREDENTIALS_INPUT
|
||||
"credentials": TEST_CREDENTIALS_INPUT,
|
||||
},
|
||||
test_credentials=TEST_CREDENTIALS,
|
||||
test_output=[
|
||||
("list_ids", ["84839422"]),
|
||||
("list_names", ["Twitter List"]),
|
||||
("data", {"pinned_lists": [{"id": "84839422", "name": "Twitter List"}]}),
|
||||
(
|
||||
"data",
|
||||
{"pinned_lists": [{"id": "84839422", "name": "Twitter List"}]},
|
||||
),
|
||||
("included", {}),
|
||||
("meta", {})
|
||||
("meta", {}),
|
||||
],
|
||||
test_mock={
|
||||
"get_pinned_lists": lambda *args, **kwargs: (
|
||||
@@ -220,7 +211,7 @@ class TwitterGetPinnedListsBlock(Block):
|
||||
{},
|
||||
{},
|
||||
["84839422"],
|
||||
["Twitter List"]
|
||||
["Twitter List"],
|
||||
)
|
||||
},
|
||||
)
|
||||
@@ -230,28 +221,25 @@ class TwitterGetPinnedListsBlock(Block):
|
||||
credentials: TwitterCredentials,
|
||||
expansions: list[ListExpansions],
|
||||
user_fields: list[TweetUserFields],
|
||||
list_fields: list[ListFields]
|
||||
list_fields: list[ListFields],
|
||||
):
|
||||
try:
|
||||
client = tweepy.Client(
|
||||
bearer_token=credentials.access_token.get_secret_value()
|
||||
)
|
||||
|
||||
params = {
|
||||
"user_auth": False
|
||||
}
|
||||
params = {"user_auth": False}
|
||||
|
||||
params = (ListExpansionsBuilder(params)
|
||||
.add_expansions(expansions)
|
||||
.add_user_fields(user_fields)
|
||||
.add_list_fields(list_fields)
|
||||
.build())
|
||||
|
||||
response = cast(
|
||||
Response,
|
||||
client.get_pinned_lists(**params)
|
||||
params = (
|
||||
ListExpansionsBuilder(params)
|
||||
.add_expansions(expansions)
|
||||
.add_user_fields(user_fields)
|
||||
.add_list_fields(list_fields)
|
||||
.build()
|
||||
)
|
||||
|
||||
response = cast(Response, client.get_pinned_lists(**params))
|
||||
|
||||
meta = {}
|
||||
list_ids = []
|
||||
list_names = []
|
||||
@@ -284,7 +272,7 @@ class TwitterGetPinnedListsBlock(Block):
|
||||
credentials,
|
||||
input_data.expansions,
|
||||
input_data.user_fields,
|
||||
input_data.list_fields
|
||||
input_data.list_fields,
|
||||
)
|
||||
|
||||
if list_ids:
|
||||
|
||||
@@ -1,14 +1,8 @@
|
||||
from typing import cast
|
||||
|
||||
from backend.blocks.twitter._serializer import IncludesSerializer, ResponseDataSerializer
|
||||
import tweepy
|
||||
from tweepy.client import Response
|
||||
|
||||
from backend.data.block import Block, BlockCategory, BlockOutput, BlockSchema
|
||||
from backend.data.model import SchemaField
|
||||
from backend.blocks.twitter._builders import SpaceExpansionsBuilder
|
||||
from backend.blocks.twitter.tweepy_exceptions import handle_tweepy_exception
|
||||
from backend.blocks.twitter._types import TweetUserFields, SpaceExpansionInputs, SpaceExpansions, SpaceFields, SpaceStates
|
||||
from backend.blocks.twitter._auth import (
|
||||
TEST_CREDENTIALS,
|
||||
TEST_CREDENTIALS_INPUT,
|
||||
@@ -16,14 +10,31 @@ from backend.blocks.twitter._auth import (
|
||||
TwitterCredentialsField,
|
||||
TwitterCredentialsInput,
|
||||
)
|
||||
from backend.blocks.twitter._builders import SpaceExpansionsBuilder
|
||||
from backend.blocks.twitter._serializer import (
|
||||
IncludesSerializer,
|
||||
ResponseDataSerializer,
|
||||
)
|
||||
from backend.blocks.twitter._types import (
|
||||
SpaceExpansionInputs,
|
||||
SpaceExpansions,
|
||||
SpaceFields,
|
||||
SpaceStates,
|
||||
TweetUserFields,
|
||||
)
|
||||
from backend.blocks.twitter.tweepy_exceptions import handle_tweepy_exception
|
||||
from backend.data.block import Block, BlockCategory, BlockOutput, BlockSchema
|
||||
from backend.data.model import SchemaField
|
||||
|
||||
|
||||
class TwitterSearchSpacesBlock(Block):
|
||||
"""
|
||||
Returns live or scheduled Spaces matching specified search terms [for a week only]
|
||||
"""
|
||||
|
||||
class Input(SpaceExpansionInputs):
|
||||
credentials: TwitterCredentialsInput = TwitterCredentialsField(
|
||||
["spaces.read","users.read","tweet.read", "offline.access"]
|
||||
["spaces.read", "users.read", "tweet.read", "offline.access"]
|
||||
)
|
||||
|
||||
query: str = SchemaField(
|
||||
@@ -35,7 +46,7 @@ class TwitterSearchSpacesBlock(Block):
|
||||
description="Maximum number of results to return (1-100)",
|
||||
placeholder="Enter max results",
|
||||
default=10,
|
||||
advanced=True
|
||||
advanced=True,
|
||||
)
|
||||
|
||||
state: SpaceStates = SchemaField(
|
||||
@@ -44,7 +55,6 @@ class TwitterSearchSpacesBlock(Block):
|
||||
default=SpaceStates.ALL,
|
||||
)
|
||||
|
||||
|
||||
class Output(BlockSchema):
|
||||
# Common outputs that user commonly uses
|
||||
ids: list[str] = SchemaField(description="List of space IDs")
|
||||
@@ -54,7 +64,9 @@ class TwitterSearchSpacesBlock(Block):
|
||||
|
||||
# Complete outputs for advanced use
|
||||
data: dict = SchemaField(description="Complete space data")
|
||||
includes: dict = SchemaField(description="Additional data requested via expansions")
|
||||
includes: dict = SchemaField(
|
||||
description="Additional data requested via expansions"
|
||||
)
|
||||
meta: dict = SchemaField(description="Metadata including pagination info")
|
||||
|
||||
error: str = SchemaField(description="Error message if the request failed")
|
||||
@@ -74,7 +86,7 @@ class TwitterSearchSpacesBlock(Block):
|
||||
"pagination": "",
|
||||
"expansions": [],
|
||||
"space_fields": [],
|
||||
"user_fields": []
|
||||
"user_fields": [],
|
||||
},
|
||||
test_credentials=TEST_CREDENTIALS,
|
||||
test_output=[
|
||||
@@ -82,20 +94,31 @@ class TwitterSearchSpacesBlock(Block):
|
||||
("titles", ["Tech Talk"]),
|
||||
("host_ids", ["5678"]),
|
||||
("next_token", "next_token_value"),
|
||||
("data", {"spaces": [{"id": "1234", "title": "Tech Talk", "host_id": "5678"}]}),
|
||||
(
|
||||
"data",
|
||||
{
|
||||
"spaces": [
|
||||
{"id": "1234", "title": "Tech Talk", "host_id": "5678"}
|
||||
]
|
||||
},
|
||||
),
|
||||
("includes", {}),
|
||||
("meta", {"next_token": "next_token_value"}),
|
||||
("error", "")
|
||||
("error", ""),
|
||||
],
|
||||
test_mock={
|
||||
"search_spaces": lambda *args, **kwargs: (
|
||||
{"spaces": [{"id": "1234", "title": "Tech Talk", "host_id": "5678"}]},
|
||||
{
|
||||
"spaces": [
|
||||
{"id": "1234", "title": "Tech Talk", "host_id": "5678"}
|
||||
]
|
||||
},
|
||||
{},
|
||||
{"next_token": "next_token_value"},
|
||||
"next_token_value",
|
||||
""
|
||||
"",
|
||||
)
|
||||
}
|
||||
},
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
@@ -106,30 +129,25 @@ class TwitterSearchSpacesBlock(Block):
|
||||
state: SpaceStates,
|
||||
expansions: list[SpaceExpansions],
|
||||
space_fields: list[SpaceFields],
|
||||
user_fields: list[TweetUserFields]
|
||||
user_fields: list[TweetUserFields],
|
||||
):
|
||||
try:
|
||||
client = tweepy.Client(
|
||||
bearer_token=credentials.access_token.get_secret_value()
|
||||
)
|
||||
|
||||
params = {
|
||||
"query": query,
|
||||
"max_results": max_results,
|
||||
"state": state.value
|
||||
}
|
||||
params = {"query": query, "max_results": max_results, "state": state.value}
|
||||
|
||||
params = (SpaceExpansionsBuilder(params)
|
||||
.add_expansions(expansions)
|
||||
.add_space_fields(space_fields)
|
||||
.add_user_fields(user_fields)
|
||||
.build())
|
||||
|
||||
response = cast(
|
||||
Response,
|
||||
client.search_spaces(**params)
|
||||
params = (
|
||||
SpaceExpansionsBuilder(params)
|
||||
.add_expansions(expansions)
|
||||
.add_space_fields(space_fields)
|
||||
.add_user_fields(user_fields)
|
||||
.build()
|
||||
)
|
||||
|
||||
response = cast(Response, client.search_spaces(**params))
|
||||
|
||||
meta = {}
|
||||
next_token = ""
|
||||
if response.meta:
|
||||
@@ -160,14 +178,16 @@ class TwitterSearchSpacesBlock(Block):
|
||||
**kwargs,
|
||||
) -> BlockOutput:
|
||||
try:
|
||||
data, included, meta, ids, titles, host_ids, next_token = self.search_spaces(
|
||||
credentials,
|
||||
input_data.query,
|
||||
input_data.max_results,
|
||||
input_data.state,
|
||||
input_data.expansions,
|
||||
input_data.space_fields,
|
||||
input_data.user_fields
|
||||
data, included, meta, ids, titles, host_ids, next_token = (
|
||||
self.search_spaces(
|
||||
credentials,
|
||||
input_data.query,
|
||||
input_data.max_results,
|
||||
input_data.state,
|
||||
input_data.expansions,
|
||||
input_data.space_fields,
|
||||
input_data.user_fields,
|
||||
)
|
||||
)
|
||||
|
||||
if ids:
|
||||
|
||||
@@ -1,14 +1,8 @@
|
||||
from typing import cast
|
||||
|
||||
from backend.blocks.twitter._serializer import IncludesSerializer, ResponseDataSerializer
|
||||
import tweepy
|
||||
from tweepy.client import Response
|
||||
|
||||
from backend.data.block import Block, BlockCategory, BlockOutput, BlockSchema
|
||||
from backend.data.model import SchemaField
|
||||
from backend.blocks.twitter._builders import SpaceExpansionsBuilder, TweetExpansionsBuilder, UserExpansionsBuilder
|
||||
from backend.blocks.twitter._types import SpaceExpansionInputs, SpaceExpansions, SpaceFields, TweetExpansionInputs, TweetExpansions, TweetFields, TweetMediaFields, TweetPlaceFields, TweetPollFields, TweetUserFields, UserExpansionInputs, UserExpansions
|
||||
from backend.blocks.twitter.tweepy_exceptions import handle_tweepy_exception
|
||||
from backend.blocks.twitter._auth import (
|
||||
TEST_CREDENTIALS,
|
||||
TEST_CREDENTIALS_INPUT,
|
||||
@@ -16,6 +10,33 @@ from backend.blocks.twitter._auth import (
|
||||
TwitterCredentialsField,
|
||||
TwitterCredentialsInput,
|
||||
)
|
||||
from backend.blocks.twitter._builders import (
|
||||
SpaceExpansionsBuilder,
|
||||
TweetExpansionsBuilder,
|
||||
UserExpansionsBuilder,
|
||||
)
|
||||
from backend.blocks.twitter._serializer import (
|
||||
IncludesSerializer,
|
||||
ResponseDataSerializer,
|
||||
)
|
||||
from backend.blocks.twitter._types import (
|
||||
SpaceExpansionInputs,
|
||||
SpaceExpansions,
|
||||
SpaceFields,
|
||||
TweetExpansionInputs,
|
||||
TweetExpansions,
|
||||
TweetFields,
|
||||
TweetMediaFields,
|
||||
TweetPlaceFields,
|
||||
TweetPollFields,
|
||||
TweetUserFields,
|
||||
UserExpansionInputs,
|
||||
UserExpansions,
|
||||
)
|
||||
from backend.blocks.twitter.tweepy_exceptions import handle_tweepy_exception
|
||||
from backend.data.block import Block, BlockCategory, BlockOutput, BlockSchema
|
||||
from backend.data.model import SchemaField
|
||||
|
||||
|
||||
class TwitterGetSpacesBlock(Block):
|
||||
"""
|
||||
@@ -31,17 +52,16 @@ class TwitterGetSpacesBlock(Block):
|
||||
description="List of Space IDs to lookup (up to 100)",
|
||||
placeholder="Enter Space IDs",
|
||||
default=[],
|
||||
advanced=False
|
||||
advanced=False,
|
||||
)
|
||||
|
||||
user_ids: list[str] = SchemaField(
|
||||
user_ids: list[str] = SchemaField(
|
||||
description="List of user IDs to lookup their Spaces (up to 100)",
|
||||
placeholder="Enter user IDs",
|
||||
default=[],
|
||||
advanced=False
|
||||
advanced=False,
|
||||
)
|
||||
|
||||
|
||||
class Output(BlockSchema):
|
||||
# Common outputs
|
||||
ids: list[str] = SchemaField(description="List of space IDs")
|
||||
@@ -49,7 +69,9 @@ class TwitterGetSpacesBlock(Block):
|
||||
|
||||
# Complete outputs for advanced use
|
||||
data: list[dict] = SchemaField(description="Complete space data")
|
||||
includes: dict = SchemaField(description="Additional data requested via expansions")
|
||||
includes: dict = SchemaField(
|
||||
description="Additional data requested via expansions"
|
||||
)
|
||||
error: str = SchemaField(description="Error message if the request failed")
|
||||
|
||||
def __init__(self):
|
||||
@@ -65,15 +87,26 @@ class TwitterGetSpacesBlock(Block):
|
||||
"credentials": TEST_CREDENTIALS_INPUT,
|
||||
"expansions": [],
|
||||
"space_fields": [],
|
||||
"user_fields": []
|
||||
"user_fields": [],
|
||||
},
|
||||
test_credentials=TEST_CREDENTIALS,
|
||||
test_output=[
|
||||
("ids", ["1DXxyRYNejbKM"]),
|
||||
("titles", ["Test Space"]),
|
||||
("host_ids", ["1234567"]),
|
||||
("data", {"spaces": [{"id": "1DXxyRYNejbKM", "title": "Test Space", "host_id": "1234567"}]}),
|
||||
("includes", {})
|
||||
(
|
||||
"data",
|
||||
{
|
||||
"spaces": [
|
||||
{
|
||||
"id": "1DXxyRYNejbKM",
|
||||
"title": "Test Space",
|
||||
"host_id": "1234567",
|
||||
}
|
||||
]
|
||||
},
|
||||
),
|
||||
("includes", {}),
|
||||
],
|
||||
)
|
||||
|
||||
@@ -93,22 +126,20 @@ class TwitterGetSpacesBlock(Block):
|
||||
|
||||
params = {
|
||||
"ids": None if space_ids == [] else space_ids,
|
||||
"user_ids": None if user_ids == [] else user_ids
|
||||
"user_ids": None if user_ids == [] else user_ids,
|
||||
}
|
||||
|
||||
params = (SpaceExpansionsBuilder(params)
|
||||
.add_expansions(expansions)
|
||||
.add_space_fields(space_fields)
|
||||
.add_user_fields(user_fields)
|
||||
.build())
|
||||
params = (
|
||||
SpaceExpansionsBuilder(params)
|
||||
.add_expansions(expansions)
|
||||
.add_space_fields(space_fields)
|
||||
.add_user_fields(user_fields)
|
||||
.build()
|
||||
)
|
||||
|
||||
print(" before space response")
|
||||
|
||||
response = cast(
|
||||
Response,
|
||||
client.get_spaces(**params)
|
||||
)
|
||||
|
||||
response = cast(Response, client.get_spaces(**params))
|
||||
|
||||
ids = []
|
||||
titles = []
|
||||
@@ -157,6 +188,7 @@ class TwitterGetSpacesBlock(Block):
|
||||
except Exception as e:
|
||||
yield "error", handle_tweepy_exception(e)
|
||||
|
||||
|
||||
class TwitterGetSpaceByIdBlock(Block):
|
||||
"""
|
||||
Gets information about a single Twitter Space specified by Space ID
|
||||
@@ -170,10 +202,9 @@ class TwitterGetSpaceByIdBlock(Block):
|
||||
space_id: str = SchemaField(
|
||||
description="Space ID to lookup",
|
||||
placeholder="Enter Space ID",
|
||||
required=True
|
||||
required=True,
|
||||
)
|
||||
|
||||
|
||||
class Output(BlockSchema):
|
||||
# Common outputs
|
||||
id: str = SchemaField(description="Space ID")
|
||||
@@ -182,7 +213,9 @@ class TwitterGetSpaceByIdBlock(Block):
|
||||
|
||||
# Complete outputs for advanced use
|
||||
data: dict = SchemaField(description="Complete space data")
|
||||
includes: dict = SchemaField(description="Additional data requested via expansions")
|
||||
includes: dict = SchemaField(
|
||||
description="Additional data requested via expansions"
|
||||
)
|
||||
error: str = SchemaField(description="Error message if the request failed")
|
||||
|
||||
def __init__(self):
|
||||
@@ -197,16 +230,23 @@ class TwitterGetSpaceByIdBlock(Block):
|
||||
"credentials": TEST_CREDENTIALS_INPUT,
|
||||
"expansions": [],
|
||||
"space_fields": [],
|
||||
"user_fields": []
|
||||
"user_fields": [],
|
||||
},
|
||||
test_credentials=TEST_CREDENTIALS,
|
||||
test_output=[
|
||||
("id", "1DXxyRYNejbKM"),
|
||||
("title", "Test Space"),
|
||||
("host_id", "1234567"),
|
||||
("data", {"id": "1DXxyRYNejbKM", "title": "Test Space", "host_id": "1234567"}),
|
||||
(
|
||||
"data",
|
||||
{
|
||||
"id": "1DXxyRYNejbKM",
|
||||
"title": "Test Space",
|
||||
"host_id": "1234567",
|
||||
},
|
||||
),
|
||||
("includes", {}),
|
||||
("error", None)
|
||||
("error", None),
|
||||
],
|
||||
)
|
||||
|
||||
@@ -227,42 +267,40 @@ class TwitterGetSpaceByIdBlock(Block):
|
||||
"id": space_id,
|
||||
}
|
||||
|
||||
params = (SpaceExpansionsBuilder(params)
|
||||
.add_expansions(expansions)
|
||||
.add_space_fields(space_fields)
|
||||
.add_user_fields(user_fields)
|
||||
.build())
|
||||
|
||||
response = cast(
|
||||
Response,
|
||||
client.get_space(**params)
|
||||
params = (
|
||||
SpaceExpansionsBuilder(params)
|
||||
.add_expansions(expansions)
|
||||
.add_space_fields(space_fields)
|
||||
.add_user_fields(user_fields)
|
||||
.build()
|
||||
)
|
||||
|
||||
response = cast(Response, client.get_space(**params))
|
||||
|
||||
includes = {}
|
||||
if response.includes:
|
||||
for key, value in response.includes.items():
|
||||
if isinstance(value, list):
|
||||
includes[key] = [
|
||||
item.data if hasattr(item, 'data') else item
|
||||
item.data if hasattr(item, "data") else item
|
||||
for item in value
|
||||
]
|
||||
else:
|
||||
includes[key] = value.data if hasattr(value, 'data') else value
|
||||
includes[key] = value.data if hasattr(value, "data") else value
|
||||
|
||||
data = {}
|
||||
if response.data:
|
||||
for key, value in response.data.items():
|
||||
if isinstance(value, list):
|
||||
data[key] = [
|
||||
item.data if hasattr(item, 'data') else item
|
||||
item.data if hasattr(item, "data") else item
|
||||
for item in value
|
||||
]
|
||||
else:
|
||||
data[key] = value.data if hasattr(value, 'data') else value
|
||||
data[key] = value.data if hasattr(value, "data") else value
|
||||
|
||||
return data, includes
|
||||
|
||||
|
||||
raise Exception("Space not found")
|
||||
|
||||
except tweepy.TweepyException:
|
||||
@@ -291,13 +329,14 @@ class TwitterGetSpaceByIdBlock(Block):
|
||||
yield "host_ids", space_data.get("host_ids")
|
||||
|
||||
if space_data:
|
||||
yield "data", space_data
|
||||
yield "data", space_data
|
||||
if includes:
|
||||
yield "includes", includes
|
||||
yield "includes", includes
|
||||
|
||||
except Exception as e:
|
||||
yield "error", handle_tweepy_exception(e)
|
||||
|
||||
|
||||
# Not tested yet, might have some problem
|
||||
class TwitterGetSpaceBuyersBlock(Block):
|
||||
"""
|
||||
@@ -312,7 +351,7 @@ class TwitterGetSpaceBuyersBlock(Block):
|
||||
space_id: str = SchemaField(
|
||||
description="Space ID to lookup buyers for",
|
||||
placeholder="Enter Space ID",
|
||||
required=True
|
||||
required=True,
|
||||
)
|
||||
|
||||
class Output(BlockSchema):
|
||||
@@ -322,7 +361,9 @@ class TwitterGetSpaceBuyersBlock(Block):
|
||||
|
||||
# Complete outputs for advanced use
|
||||
data: list[dict] = SchemaField(description="Complete space buyers data")
|
||||
includes: dict = SchemaField(description="Additional data requested via expansions")
|
||||
includes: dict = SchemaField(
|
||||
description="Additional data requested via expansions"
|
||||
)
|
||||
error: str = SchemaField(description="Error message if the request failed")
|
||||
|
||||
def __init__(self):
|
||||
@@ -336,15 +377,18 @@ class TwitterGetSpaceBuyersBlock(Block):
|
||||
"space_id": "1DXxyRYNejbKM",
|
||||
"credentials": TEST_CREDENTIALS_INPUT,
|
||||
"expansions": [],
|
||||
"user_fields": []
|
||||
"user_fields": [],
|
||||
},
|
||||
test_credentials=TEST_CREDENTIALS,
|
||||
test_output=[
|
||||
("buyer_ids", ["2244994945"]),
|
||||
("usernames", ["testuser"]),
|
||||
("data", {"id": "2244994945", "username": "testuser", "name": "Test User"}),
|
||||
(
|
||||
"data",
|
||||
{"id": "2244994945", "username": "testuser", "name": "Test User"},
|
||||
),
|
||||
("includes", {}),
|
||||
("error", None)
|
||||
("error", None),
|
||||
],
|
||||
)
|
||||
|
||||
@@ -364,16 +408,15 @@ class TwitterGetSpaceBuyersBlock(Block):
|
||||
"id": space_id,
|
||||
}
|
||||
|
||||
params = (UserExpansionsBuilder(params)
|
||||
.add_expansions(expansions)
|
||||
.add_user_fields(user_fields)
|
||||
.build())
|
||||
|
||||
response = cast(
|
||||
Response,
|
||||
client.get_space_buyers(**params)
|
||||
params = (
|
||||
UserExpansionsBuilder(params)
|
||||
.add_expansions(expansions)
|
||||
.add_user_fields(user_fields)
|
||||
.build()
|
||||
)
|
||||
|
||||
response = cast(Response, client.get_space_buyers(**params))
|
||||
|
||||
included = IncludesSerializer.serialize(response.includes)
|
||||
|
||||
if response.data:
|
||||
@@ -400,7 +443,7 @@ class TwitterGetSpaceBuyersBlock(Block):
|
||||
credentials,
|
||||
input_data.space_id,
|
||||
input_data.expansions,
|
||||
input_data.user_fields
|
||||
input_data.user_fields,
|
||||
)
|
||||
|
||||
if buyer_ids:
|
||||
@@ -416,6 +459,7 @@ class TwitterGetSpaceBuyersBlock(Block):
|
||||
except Exception as e:
|
||||
yield "error", handle_tweepy_exception(e)
|
||||
|
||||
|
||||
class TwitterGetSpaceTweetsBlock(Block):
|
||||
"""
|
||||
Gets list of Tweets shared in the requested Space
|
||||
@@ -429,7 +473,7 @@ class TwitterGetSpaceTweetsBlock(Block):
|
||||
space_id: str = SchemaField(
|
||||
description="Space ID to lookup tweets for",
|
||||
placeholder="Enter Space ID",
|
||||
required=True
|
||||
required=True,
|
||||
)
|
||||
|
||||
class Output(BlockSchema):
|
||||
@@ -439,7 +483,9 @@ class TwitterGetSpaceTweetsBlock(Block):
|
||||
|
||||
# Complete outputs for advanced use
|
||||
data: list[dict] = SchemaField(description="Complete space tweets data")
|
||||
includes: dict = SchemaField(description="Additional data requested via expansions")
|
||||
includes: dict = SchemaField(
|
||||
description="Additional data requested via expansions"
|
||||
)
|
||||
meta: dict = SchemaField(description="Response metadata")
|
||||
error: str = SchemaField(description="Error message if the request failed")
|
||||
|
||||
@@ -458,7 +504,7 @@ class TwitterGetSpaceTweetsBlock(Block):
|
||||
"place_fields": [],
|
||||
"poll_fields": [],
|
||||
"tweet_fields": [],
|
||||
"user_fields": []
|
||||
"user_fields": [],
|
||||
},
|
||||
test_credentials=TEST_CREDENTIALS,
|
||||
test_output=[
|
||||
@@ -467,7 +513,7 @@ class TwitterGetSpaceTweetsBlock(Block):
|
||||
("data", {"tweets": [{"id": "1234567890", "text": "Test tweet"}]}),
|
||||
("includes", {}),
|
||||
("meta", {}),
|
||||
("error", None)
|
||||
("error", None),
|
||||
],
|
||||
)
|
||||
|
||||
@@ -480,7 +526,7 @@ class TwitterGetSpaceTweetsBlock(Block):
|
||||
place_fields: list[TweetPlaceFields],
|
||||
poll_fields: list[TweetPollFields],
|
||||
tweet_fields: list[TweetFields],
|
||||
user_fields: list[TweetUserFields]
|
||||
user_fields: list[TweetUserFields],
|
||||
):
|
||||
try:
|
||||
client = tweepy.Client(
|
||||
@@ -491,20 +537,19 @@ class TwitterGetSpaceTweetsBlock(Block):
|
||||
"id": space_id,
|
||||
}
|
||||
|
||||
params = (TweetExpansionsBuilder(params)
|
||||
.add_expansions(expansions)
|
||||
.add_media_fields(media_fields)
|
||||
.add_place_fields(place_fields)
|
||||
.add_poll_fields(poll_fields)
|
||||
.add_tweet_fields(tweet_fields)
|
||||
.add_user_fields(user_fields)
|
||||
.build())
|
||||
|
||||
response = cast(
|
||||
Response,
|
||||
client.get_space_tweets(**params)
|
||||
params = (
|
||||
TweetExpansionsBuilder(params)
|
||||
.add_expansions(expansions)
|
||||
.add_media_fields(media_fields)
|
||||
.add_place_fields(place_fields)
|
||||
.add_poll_fields(poll_fields)
|
||||
.add_tweet_fields(tweet_fields)
|
||||
.add_user_fields(user_fields)
|
||||
.build()
|
||||
)
|
||||
|
||||
response = cast(Response, client.get_space_tweets(**params))
|
||||
|
||||
included = IncludesSerializer.serialize(response.includes)
|
||||
|
||||
if response.data:
|
||||
@@ -537,7 +582,7 @@ class TwitterGetSpaceTweetsBlock(Block):
|
||||
input_data.place_fields,
|
||||
input_data.poll_fields,
|
||||
input_data.tweet_fields,
|
||||
input_data.user_fields
|
||||
input_data.user_fields,
|
||||
)
|
||||
|
||||
if tweet_ids:
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import tweepy
|
||||
|
||||
|
||||
def handle_tweepy_exception(e: Exception) -> str:
|
||||
if isinstance(e, tweepy.BadRequest):
|
||||
return f"Bad Request (400): {str(e)}"
|
||||
|
||||
@@ -1,15 +1,8 @@
|
||||
from typing import cast
|
||||
|
||||
from backend.blocks.twitter._serializer import IncludesSerializer, ResponseDataSerializer
|
||||
import tweepy
|
||||
from tweepy.client import Response
|
||||
|
||||
from backend.data.block import Block, BlockCategory, BlockOutput, BlockSchema
|
||||
from backend.data.model import SchemaField
|
||||
from backend.blocks.twitter._builders import TweetExpansionsBuilder
|
||||
from backend.blocks.twitter._types import TweetExpansions, TweetFields, TweetMediaFields, TweetPlaceFields, TweetPollFields, TweetUserFields, TweetExpansionInputs
|
||||
from backend.blocks.twitter.tweepy_exceptions import handle_tweepy_exception
|
||||
|
||||
from backend.blocks.twitter._auth import (
|
||||
TEST_CREDENTIALS,
|
||||
TEST_CREDENTIALS_INPUT,
|
||||
@@ -17,6 +10,24 @@ from backend.blocks.twitter._auth import (
|
||||
TwitterCredentialsField,
|
||||
TwitterCredentialsInput,
|
||||
)
|
||||
from backend.blocks.twitter._builders import TweetExpansionsBuilder
|
||||
from backend.blocks.twitter._serializer import (
|
||||
IncludesSerializer,
|
||||
ResponseDataSerializer,
|
||||
)
|
||||
from backend.blocks.twitter._types import (
|
||||
TweetExpansionInputs,
|
||||
TweetExpansions,
|
||||
TweetFields,
|
||||
TweetMediaFields,
|
||||
TweetPlaceFields,
|
||||
TweetPollFields,
|
||||
TweetUserFields,
|
||||
)
|
||||
from backend.blocks.twitter.tweepy_exceptions import handle_tweepy_exception
|
||||
from backend.data.block import Block, BlockCategory, BlockOutput, BlockSchema
|
||||
from backend.data.model import SchemaField
|
||||
|
||||
|
||||
class TwitterBookmarkTweetBlock(Block):
|
||||
"""
|
||||
@@ -25,7 +36,7 @@ class TwitterBookmarkTweetBlock(Block):
|
||||
|
||||
class Input(BlockSchema):
|
||||
credentials: TwitterCredentialsInput = TwitterCredentialsField(
|
||||
["tweet.read","bookmark.write", "users.read", "offline.access"]
|
||||
["tweet.read", "bookmark.write", "users.read", "offline.access"]
|
||||
)
|
||||
|
||||
tweet_id: str = SchemaField(
|
||||
@@ -84,6 +95,7 @@ class TwitterBookmarkTweetBlock(Block):
|
||||
except Exception as e:
|
||||
yield "error", handle_tweepy_exception(e)
|
||||
|
||||
|
||||
class TwitterGetBookmarkedTweetsBlock(Block):
|
||||
"""
|
||||
Get All your bookmarked tweets from Twitter
|
||||
@@ -98,28 +110,32 @@ class TwitterGetBookmarkedTweetsBlock(Block):
|
||||
description="Maximum number of results to return (1-100)",
|
||||
placeholder="Enter max results",
|
||||
default=10,
|
||||
advanced=True
|
||||
advanced=True,
|
||||
)
|
||||
|
||||
pagination_token: str = SchemaField(
|
||||
description="Token for pagination",
|
||||
placeholder="Enter pagination token",
|
||||
default = "",
|
||||
default="",
|
||||
advanced=True,
|
||||
)
|
||||
|
||||
class Output(BlockSchema):
|
||||
# Common Outputs that user commonly uses
|
||||
id : list[str] = SchemaField(description="All Tweet IDs")
|
||||
text : list[str] = SchemaField(description="All Tweet texts")
|
||||
id: list[str] = SchemaField(description="All Tweet IDs")
|
||||
text: list[str] = SchemaField(description="All Tweet texts")
|
||||
userId: list[str] = SchemaField(description="IDs of the tweet authors")
|
||||
userName: list[str] = SchemaField(description="Usernames of the tweet authors")
|
||||
|
||||
# Complete Outputs for advanced use
|
||||
data : list[dict] = SchemaField(description="Complete Tweet data")
|
||||
included: dict = SchemaField(description="Additional data that you have requested (Optional) via Expansions field")
|
||||
meta : dict = SchemaField(description="Provides metadata such as pagination info (next_token) or result counts")
|
||||
next_token : str = SchemaField(description="Next token for pagination")
|
||||
data: list[dict] = SchemaField(description="Complete Tweet data")
|
||||
included: dict = SchemaField(
|
||||
description="Additional data that you have requested (Optional) via Expansions field"
|
||||
)
|
||||
meta: dict = SchemaField(
|
||||
description="Provides metadata such as pagination info (next_token) or result counts"
|
||||
)
|
||||
next_token: str = SchemaField(description="Next token for pagination")
|
||||
|
||||
error: str = SchemaField(description="Error message if the request failed")
|
||||
|
||||
@@ -150,7 +166,7 @@ class TwitterGetBookmarkedTweetsBlock(Block):
|
||||
("data", [{"id": "1234567890", "text": "Test tweet"}]),
|
||||
("included", {"users": [{"id": "12345", "username": "testuser"}]}),
|
||||
("meta", {"result_count": 1}),
|
||||
("next_token", "next_token_value")
|
||||
("next_token", "next_token_value"),
|
||||
],
|
||||
)
|
||||
|
||||
@@ -164,7 +180,7 @@ class TwitterGetBookmarkedTweetsBlock(Block):
|
||||
place_fields: list[TweetPlaceFields],
|
||||
poll_fields: list[TweetPollFields],
|
||||
tweet_fields: list[TweetFields],
|
||||
user_fields: list[TweetUserFields]
|
||||
user_fields: list[TweetUserFields],
|
||||
):
|
||||
try:
|
||||
client = tweepy.Client(
|
||||
@@ -173,23 +189,25 @@ class TwitterGetBookmarkedTweetsBlock(Block):
|
||||
|
||||
params = {
|
||||
"max_results": max_results,
|
||||
"pagination_token": None if pagination_token == "" else pagination_token,
|
||||
"pagination_token": (
|
||||
None if pagination_token == "" else pagination_token
|
||||
),
|
||||
}
|
||||
|
||||
params = (TweetExpansionsBuilder(params)
|
||||
params = (
|
||||
TweetExpansionsBuilder(params)
|
||||
.add_expansions(expansions)
|
||||
.add_media_fields(media_fields)
|
||||
.add_place_fields(place_fields)
|
||||
.add_poll_fields(poll_fields)
|
||||
.add_tweet_fields(tweet_fields)
|
||||
.add_user_fields(user_fields)
|
||||
.build())
|
||||
.build()
|
||||
)
|
||||
|
||||
response = cast(
|
||||
Response,
|
||||
client.get_bookmarks(
|
||||
**params
|
||||
),
|
||||
client.get_bookmarks(**params),
|
||||
)
|
||||
|
||||
meta = {}
|
||||
@@ -215,7 +233,16 @@ class TwitterGetBookmarkedTweetsBlock(Block):
|
||||
user_ids.append(str(user["id"]))
|
||||
user_names.append(user["username"])
|
||||
|
||||
return tweet_ids, tweet_texts, user_ids, user_names, data, included, meta, next_token
|
||||
return (
|
||||
tweet_ids,
|
||||
tweet_texts,
|
||||
user_ids,
|
||||
user_names,
|
||||
data,
|
||||
included,
|
||||
meta,
|
||||
next_token,
|
||||
)
|
||||
|
||||
raise Exception("No bookmarked tweets found")
|
||||
|
||||
@@ -230,16 +257,18 @@ class TwitterGetBookmarkedTweetsBlock(Block):
|
||||
**kwargs,
|
||||
) -> BlockOutput:
|
||||
try:
|
||||
ids, texts, user_ids, user_names, data, included, meta, next_token = self.get_bookmarked_tweets(
|
||||
credentials,
|
||||
input_data.max_results,
|
||||
input_data.pagination_token,
|
||||
input_data.expansions,
|
||||
input_data.media_fields,
|
||||
input_data.place_fields,
|
||||
input_data.poll_fields,
|
||||
input_data.tweet_fields,
|
||||
input_data.user_fields
|
||||
ids, texts, user_ids, user_names, data, included, meta, next_token = (
|
||||
self.get_bookmarked_tweets(
|
||||
credentials,
|
||||
input_data.max_results,
|
||||
input_data.pagination_token,
|
||||
input_data.expansions,
|
||||
input_data.media_fields,
|
||||
input_data.place_fields,
|
||||
input_data.poll_fields,
|
||||
input_data.tweet_fields,
|
||||
input_data.user_fields,
|
||||
)
|
||||
)
|
||||
if ids:
|
||||
yield "id", ids
|
||||
@@ -260,6 +289,7 @@ class TwitterGetBookmarkedTweetsBlock(Block):
|
||||
except Exception as e:
|
||||
yield "error", handle_tweepy_exception(e)
|
||||
|
||||
|
||||
class TwitterRemoveBookmarkTweetBlock(Block):
|
||||
"""
|
||||
Remove a bookmark for a tweet on Twitter
|
||||
@@ -298,9 +328,7 @@ class TwitterRemoveBookmarkTweetBlock(Block):
|
||||
test_output=[
|
||||
("success", True),
|
||||
],
|
||||
test_mock={
|
||||
"remove_bookmark_tweet": lambda *args, **kwargs: True
|
||||
}
|
||||
test_mock={"remove_bookmark_tweet": lambda *args, **kwargs: True},
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
import tweepy
|
||||
from backend.data.block import Block, BlockCategory, BlockOutput, BlockSchema
|
||||
from backend.data.model import SchemaField
|
||||
from backend.blocks.twitter.tweepy_exceptions import handle_tweepy_exception
|
||||
|
||||
from backend.blocks.twitter._auth import (
|
||||
TEST_CREDENTIALS,
|
||||
TEST_CREDENTIALS_INPUT,
|
||||
@@ -9,6 +7,9 @@ from backend.blocks.twitter._auth import (
|
||||
TwitterCredentialsField,
|
||||
TwitterCredentialsInput,
|
||||
)
|
||||
from backend.blocks.twitter.tweepy_exceptions import handle_tweepy_exception
|
||||
from backend.data.block import Block, BlockCategory, BlockOutput, BlockSchema
|
||||
from backend.data.model import SchemaField
|
||||
|
||||
|
||||
class TwitterHideReplyBlock(Block):
|
||||
@@ -80,6 +81,7 @@ class TwitterHideReplyBlock(Block):
|
||||
except Exception as e:
|
||||
yield "error", handle_tweepy_exception(e)
|
||||
|
||||
|
||||
class TwitterUnhideReplyBlock(Block):
|
||||
"""
|
||||
Unhides a reply to a tweet
|
||||
|
||||
@@ -1,14 +1,8 @@
|
||||
from typing import cast
|
||||
|
||||
from backend.blocks.twitter._serializer import IncludesSerializer, ResponseDataSerializer
|
||||
import tweepy
|
||||
from tweepy.client import Response
|
||||
|
||||
from backend.data.block import Block, BlockCategory, BlockOutput, BlockSchema
|
||||
from backend.data.model import SchemaField
|
||||
from backend.blocks.twitter._builders import TweetExpansionsBuilder, UserExpansionsBuilder
|
||||
from backend.blocks.twitter._types import TweetExpansionInputs, TweetExpansions, TweetFields, TweetMediaFields, TweetPlaceFields, TweetPollFields, TweetUserFields, UserExpansionInputs, UserExpansions
|
||||
from backend.blocks.twitter.tweepy_exceptions import handle_tweepy_exception
|
||||
from backend.blocks.twitter._auth import (
|
||||
TEST_CREDENTIALS,
|
||||
TEST_CREDENTIALS_INPUT,
|
||||
@@ -16,6 +10,29 @@ from backend.blocks.twitter._auth import (
|
||||
TwitterCredentialsField,
|
||||
TwitterCredentialsInput,
|
||||
)
|
||||
from backend.blocks.twitter._builders import (
|
||||
TweetExpansionsBuilder,
|
||||
UserExpansionsBuilder,
|
||||
)
|
||||
from backend.blocks.twitter._serializer import (
|
||||
IncludesSerializer,
|
||||
ResponseDataSerializer,
|
||||
)
|
||||
from backend.blocks.twitter._types import (
|
||||
TweetExpansionInputs,
|
||||
TweetExpansions,
|
||||
TweetFields,
|
||||
TweetMediaFields,
|
||||
TweetPlaceFields,
|
||||
TweetPollFields,
|
||||
TweetUserFields,
|
||||
UserExpansionInputs,
|
||||
UserExpansions,
|
||||
)
|
||||
from backend.blocks.twitter.tweepy_exceptions import handle_tweepy_exception
|
||||
from backend.data.block import Block, BlockCategory, BlockOutput, BlockSchema
|
||||
from backend.data.model import SchemaField
|
||||
|
||||
|
||||
class TwitterLikeTweetBlock(Block):
|
||||
"""
|
||||
@@ -86,6 +103,7 @@ class TwitterLikeTweetBlock(Block):
|
||||
except Exception as e:
|
||||
yield "error", handle_tweepy_exception(e)
|
||||
|
||||
|
||||
class TwitterGetLikingUsersBlock(Block):
|
||||
"""
|
||||
Gets information about users who liked a one of your tweet
|
||||
@@ -93,7 +111,7 @@ class TwitterGetLikingUsersBlock(Block):
|
||||
|
||||
class Input(UserExpansionInputs):
|
||||
credentials: TwitterCredentialsInput = TwitterCredentialsField(
|
||||
["tweet.read", "users.read","like.read", "offline.access"]
|
||||
["tweet.read", "users.read", "like.read", "offline.access"]
|
||||
)
|
||||
|
||||
tweet_id: str = SchemaField(
|
||||
@@ -115,14 +133,20 @@ class TwitterGetLikingUsersBlock(Block):
|
||||
|
||||
class Output(BlockSchema):
|
||||
# Common Outputs that user commonly uses
|
||||
id : list[str] = SchemaField(description="All User IDs who liked the tweet")
|
||||
username : list[str] = SchemaField(description="All User usernames who liked the tweet")
|
||||
next_token : str = SchemaField(description="Next token for pagination")
|
||||
id: list[str] = SchemaField(description="All User IDs who liked the tweet")
|
||||
username: list[str] = SchemaField(
|
||||
description="All User usernames who liked the tweet"
|
||||
)
|
||||
next_token: str = SchemaField(description="Next token for pagination")
|
||||
|
||||
# Complete Outputs for advanced use
|
||||
data : list[dict] = SchemaField(description="Complete Tweet data")
|
||||
included : dict = SchemaField(description="Additional data that you have requested (Optional) via Expansions field")
|
||||
meta : dict = SchemaField(description="Provides metadata such as pagination info (next_token) or result counts")
|
||||
data: list[dict] = SchemaField(description="Complete Tweet data")
|
||||
included: dict = SchemaField(
|
||||
description="Additional data that you have requested (Optional) via Expansions field"
|
||||
)
|
||||
meta: dict = SchemaField(
|
||||
description="Provides metadata such as pagination info (next_token) or result counts"
|
||||
)
|
||||
|
||||
# error
|
||||
error: str = SchemaField(description="Error message if the request failed")
|
||||
@@ -141,39 +165,36 @@ class TwitterGetLikingUsersBlock(Block):
|
||||
"credentials": TEST_CREDENTIALS_INPUT,
|
||||
"expansions": [],
|
||||
"tweet_fields": [],
|
||||
"user_fields": []
|
||||
"user_fields": [],
|
||||
},
|
||||
test_credentials=TEST_CREDENTIALS,
|
||||
test_output=[
|
||||
("id", ["12345", "67890"]),
|
||||
("username", ["user1", "user2"]),
|
||||
("data", [
|
||||
{
|
||||
"id": "12345",
|
||||
"username": "user1"
|
||||
},
|
||||
{
|
||||
"id": "67890",
|
||||
"username": "user2"
|
||||
}
|
||||
]),
|
||||
(
|
||||
"data",
|
||||
[
|
||||
{"id": "12345", "username": "user1"},
|
||||
{"id": "67890", "username": "user2"},
|
||||
],
|
||||
),
|
||||
("included", {}),
|
||||
("meta", {
|
||||
"result_count": 2,
|
||||
"next_token": "next_token_value"
|
||||
}),
|
||||
("next_token", "next_token_value")
|
||||
("meta", {"result_count": 2, "next_token": "next_token_value"}),
|
||||
("next_token", "next_token_value"),
|
||||
],
|
||||
test_mock={
|
||||
"get_liking_users": lambda *args, **kwargs: (
|
||||
["12345", "67890"],
|
||||
["user1", "user2"],
|
||||
[{"id": "12345", "username": "user1"}, {"id": "67890", "username": "user2"}],
|
||||
[
|
||||
{"id": "12345", "username": "user1"},
|
||||
{"id": "67890", "username": "user2"},
|
||||
],
|
||||
{},
|
||||
{"result_count": 2, "next_token": "next_token_value"},
|
||||
"next_token_value"
|
||||
"next_token_value",
|
||||
)
|
||||
}
|
||||
},
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
@@ -184,7 +205,7 @@ class TwitterGetLikingUsersBlock(Block):
|
||||
pagination_token: str,
|
||||
expansions: list[UserExpansions],
|
||||
tweet_fields: list[TweetFields],
|
||||
user_fields: list[TweetUserFields]
|
||||
user_fields: list[TweetUserFields],
|
||||
):
|
||||
try:
|
||||
client = tweepy.Client(
|
||||
@@ -194,21 +215,22 @@ class TwitterGetLikingUsersBlock(Block):
|
||||
params = {
|
||||
"id": tweet_id,
|
||||
"max_results": max_results,
|
||||
"pagination_token": None if pagination_token == "" else pagination_token,
|
||||
"user_auth": False
|
||||
"pagination_token": (
|
||||
None if pagination_token == "" else pagination_token
|
||||
),
|
||||
"user_auth": False,
|
||||
}
|
||||
|
||||
params = (UserExpansionsBuilder(params)
|
||||
params = (
|
||||
UserExpansionsBuilder(params)
|
||||
.add_expansions(expansions)
|
||||
.add_tweet_fields(tweet_fields)
|
||||
.add_user_fields(user_fields)
|
||||
.build())
|
||||
|
||||
response = cast(
|
||||
Response,
|
||||
client.get_liking_users(**params)
|
||||
.build()
|
||||
)
|
||||
|
||||
response = cast(Response, client.get_liking_users(**params))
|
||||
|
||||
if not response.data and not response.meta:
|
||||
raise Exception("No liking users found")
|
||||
|
||||
@@ -250,7 +272,7 @@ class TwitterGetLikingUsersBlock(Block):
|
||||
input_data.pagination_token,
|
||||
input_data.expansions,
|
||||
input_data.tweet_fields,
|
||||
input_data.user_fields
|
||||
input_data.user_fields,
|
||||
)
|
||||
if ids:
|
||||
yield "id", ids
|
||||
@@ -267,6 +289,7 @@ class TwitterGetLikingUsersBlock(Block):
|
||||
except Exception as e:
|
||||
yield "error", handle_tweepy_exception(e)
|
||||
|
||||
|
||||
class TwitterGetLikedTweetsBlock(Block):
|
||||
"""
|
||||
Gets information about tweets liked by you
|
||||
@@ -274,7 +297,7 @@ class TwitterGetLikedTweetsBlock(Block):
|
||||
|
||||
class Input(TweetExpansionInputs):
|
||||
credentials: TwitterCredentialsInput = TwitterCredentialsField(
|
||||
["tweet.read", "users.read","like.read", "offline.access"]
|
||||
["tweet.read", "users.read", "like.read", "offline.access"]
|
||||
)
|
||||
|
||||
user_id: str = SchemaField(
|
||||
@@ -285,7 +308,7 @@ class TwitterGetLikedTweetsBlock(Block):
|
||||
description="Maximum number of results to return (5-100)",
|
||||
placeholder="100",
|
||||
default=10,
|
||||
advanced=True
|
||||
advanced=True,
|
||||
)
|
||||
pagination_token: str = SchemaField(
|
||||
description="Token for getting next/previous page of results",
|
||||
@@ -296,16 +319,24 @@ class TwitterGetLikedTweetsBlock(Block):
|
||||
|
||||
class Output(BlockSchema):
|
||||
# Common Outputs that user commonly uses
|
||||
ids : list[str] = SchemaField(description="All Tweet IDs")
|
||||
texts : list[str] = SchemaField(description="All Tweet texts")
|
||||
userIds: list[str] = SchemaField(description="List of user ids that authored the tweets")
|
||||
userNames: list[str] = SchemaField(description="List of user names that authored the tweets")
|
||||
next_token : str = SchemaField(description="Next token for pagination")
|
||||
ids: list[str] = SchemaField(description="All Tweet IDs")
|
||||
texts: list[str] = SchemaField(description="All Tweet texts")
|
||||
userIds: list[str] = SchemaField(
|
||||
description="List of user ids that authored the tweets"
|
||||
)
|
||||
userNames: list[str] = SchemaField(
|
||||
description="List of user names that authored the tweets"
|
||||
)
|
||||
next_token: str = SchemaField(description="Next token for pagination")
|
||||
|
||||
# Complete Outputs for advanced use
|
||||
data : list[dict] = SchemaField(description="Complete Tweet data")
|
||||
included : dict = SchemaField(description="Additional data that you have requested (Optional) via Expansions field")
|
||||
meta : dict = SchemaField(description="Provides metadata such as pagination info (next_token) or result counts")
|
||||
data: list[dict] = SchemaField(description="Complete Tweet data")
|
||||
included: dict = SchemaField(
|
||||
description="Additional data that you have requested (Optional) via Expansions field"
|
||||
)
|
||||
meta: dict = SchemaField(
|
||||
description="Provides metadata such as pagination info (next_token) or result counts"
|
||||
)
|
||||
|
||||
# error
|
||||
error: str = SchemaField(description="Error message if the request failed")
|
||||
@@ -327,7 +358,7 @@ class TwitterGetLikedTweetsBlock(Block):
|
||||
"place_fields": [],
|
||||
"poll_fields": [],
|
||||
"tweet_fields": [],
|
||||
"user_fields": []
|
||||
"user_fields": [],
|
||||
},
|
||||
test_credentials=TEST_CREDENTIALS,
|
||||
test_output=[
|
||||
@@ -335,27 +366,24 @@ class TwitterGetLikedTweetsBlock(Block):
|
||||
("texts", ["Tweet 1", "Tweet 2"]),
|
||||
("userIds", ["67890", "67891"]),
|
||||
("userNames", ["testuser1", "testuser2"]),
|
||||
("data", [
|
||||
(
|
||||
"data",
|
||||
[
|
||||
{"id": "12345", "text": "Tweet 1"},
|
||||
{"id": "67890", "text": "Tweet 2"},
|
||||
],
|
||||
),
|
||||
(
|
||||
"included",
|
||||
{
|
||||
"id": "12345",
|
||||
"text": "Tweet 1"
|
||||
"users": [
|
||||
{"id": "67890", "username": "testuser1"},
|
||||
{"id": "67891", "username": "testuser2"},
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "67890",
|
||||
"text": "Tweet 2"
|
||||
}
|
||||
]),
|
||||
("included", {
|
||||
"users": [
|
||||
{"id": "67890", "username": "testuser1"},
|
||||
{"id": "67891", "username": "testuser2"}
|
||||
]
|
||||
}),
|
||||
("meta", {
|
||||
"result_count": 2,
|
||||
"next_token": "next_token_value"
|
||||
}),
|
||||
("next_token", "next_token_value")
|
||||
),
|
||||
("meta", {"result_count": 2, "next_token": "next_token_value"}),
|
||||
("next_token", "next_token_value"),
|
||||
],
|
||||
test_mock={
|
||||
"get_liked_tweets": lambda *args, **kwargs: (
|
||||
@@ -363,12 +391,20 @@ class TwitterGetLikedTweetsBlock(Block):
|
||||
["Tweet 1", "Tweet 2"],
|
||||
["67890", "67891"],
|
||||
["testuser1", "testuser2"],
|
||||
[{"id": "12345", "text": "Tweet 1"}, {"id": "67890", "text": "Tweet 2"}],
|
||||
{"users": [{"id": "67890", "username": "testuser1"}, {"id": "67891", "username": "testuser2"}]},
|
||||
[
|
||||
{"id": "12345", "text": "Tweet 1"},
|
||||
{"id": "67890", "text": "Tweet 2"},
|
||||
],
|
||||
{
|
||||
"users": [
|
||||
{"id": "67890", "username": "testuser1"},
|
||||
{"id": "67891", "username": "testuser2"},
|
||||
]
|
||||
},
|
||||
{"result_count": 2, "next_token": "next_token_value"},
|
||||
"next_token_value"
|
||||
"next_token_value",
|
||||
)
|
||||
}
|
||||
},
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
@@ -382,7 +418,7 @@ class TwitterGetLikedTweetsBlock(Block):
|
||||
place_fields: list[TweetPlaceFields],
|
||||
poll_fields: list[TweetPollFields],
|
||||
tweet_fields: list[TweetFields],
|
||||
user_fields: list[TweetUserFields]
|
||||
user_fields: list[TweetUserFields],
|
||||
):
|
||||
try:
|
||||
client = tweepy.Client(
|
||||
@@ -392,24 +428,25 @@ class TwitterGetLikedTweetsBlock(Block):
|
||||
params = {
|
||||
"id": user_id,
|
||||
"max_results": max_results,
|
||||
"pagination_token":None if pagination_token == "" else pagination_token,
|
||||
"user_auth": False
|
||||
"pagination_token": (
|
||||
None if pagination_token == "" else pagination_token
|
||||
),
|
||||
"user_auth": False,
|
||||
}
|
||||
|
||||
params = (TweetExpansionsBuilder(params)
|
||||
params = (
|
||||
TweetExpansionsBuilder(params)
|
||||
.add_expansions(expansions)
|
||||
.add_media_fields(media_fields)
|
||||
.add_place_fields(place_fields)
|
||||
.add_poll_fields(poll_fields)
|
||||
.add_tweet_fields(tweet_fields)
|
||||
.add_user_fields(user_fields)
|
||||
.build())
|
||||
|
||||
response = cast(
|
||||
Response,
|
||||
client.get_liked_tweets(**params)
|
||||
.build()
|
||||
)
|
||||
|
||||
response = cast(Response, client.get_liked_tweets(**params))
|
||||
|
||||
if not response.data and not response.meta:
|
||||
raise Exception("No liked tweets found")
|
||||
|
||||
@@ -433,9 +470,20 @@ class TwitterGetLikedTweetsBlock(Block):
|
||||
|
||||
if "users" in response.includes:
|
||||
user_ids = [str(user["id"]) for user in response.includes["users"]]
|
||||
user_names = [user["username"] for user in response.includes["users"]]
|
||||
user_names = [
|
||||
user["username"] for user in response.includes["users"]
|
||||
]
|
||||
|
||||
return tweet_ids, tweet_texts, user_ids, user_names, data, included, meta, next_token
|
||||
return (
|
||||
tweet_ids,
|
||||
tweet_texts,
|
||||
user_ids,
|
||||
user_names,
|
||||
data,
|
||||
included,
|
||||
meta,
|
||||
next_token,
|
||||
)
|
||||
|
||||
raise Exception("No liked tweets found")
|
||||
|
||||
@@ -450,17 +498,19 @@ class TwitterGetLikedTweetsBlock(Block):
|
||||
**kwargs,
|
||||
) -> BlockOutput:
|
||||
try:
|
||||
ids, texts, user_ids, user_names, data, included, meta, next_token = self.get_liked_tweets(
|
||||
credentials,
|
||||
input_data.user_id,
|
||||
input_data.max_results,
|
||||
input_data.pagination_token,
|
||||
input_data.expansions,
|
||||
input_data.media_fields,
|
||||
input_data.place_fields,
|
||||
input_data.poll_fields,
|
||||
input_data.tweet_fields,
|
||||
input_data.user_fields
|
||||
ids, texts, user_ids, user_names, data, included, meta, next_token = (
|
||||
self.get_liked_tweets(
|
||||
credentials,
|
||||
input_data.user_id,
|
||||
input_data.max_results,
|
||||
input_data.pagination_token,
|
||||
input_data.expansions,
|
||||
input_data.media_fields,
|
||||
input_data.place_fields,
|
||||
input_data.poll_fields,
|
||||
input_data.tweet_fields,
|
||||
input_data.user_fields,
|
||||
)
|
||||
)
|
||||
if ids:
|
||||
yield "ids", ids
|
||||
@@ -481,6 +531,7 @@ class TwitterGetLikedTweetsBlock(Block):
|
||||
except Exception as e:
|
||||
yield "error", handle_tweepy_exception(e)
|
||||
|
||||
|
||||
class TwitterUnlikeTweetBlock(Block):
|
||||
"""
|
||||
Unlikes a tweet that was previously liked
|
||||
|
||||
@@ -1,15 +1,8 @@
|
||||
from typing import cast
|
||||
|
||||
from backend.blocks.twitter._serializer import IncludesSerializer, ResponseDataSerializer
|
||||
import tweepy
|
||||
from tweepy.client import Response
|
||||
|
||||
from backend.blocks.twitter._types import TweetExpansionInputs, TweetTimeWindowInputs
|
||||
from backend.blocks.twitter.tweepy_exceptions import handle_tweepy_exception
|
||||
from backend.data.block import Block, BlockCategory, BlockOutput, BlockSchema
|
||||
from backend.data.model import SchemaField
|
||||
from backend.blocks.twitter._builders import TweetExpansionsBuilder,TweetDurationBuilder, TweetPostBuilder, TweetSearchBuilder
|
||||
from backend.blocks.twitter._types import TweetExpansions, TweetMediaFields, TweetPlaceFields, TweetPollFields, TweetReplySettings, TweetFields, TweetUserFields
|
||||
from backend.blocks.twitter._auth import (
|
||||
TEST_CREDENTIALS,
|
||||
TEST_CREDENTIALS_INPUT,
|
||||
@@ -17,11 +10,35 @@ from backend.blocks.twitter._auth import (
|
||||
TwitterCredentialsField,
|
||||
TwitterCredentialsInput,
|
||||
)
|
||||
from backend.blocks.twitter._builders import (
|
||||
TweetDurationBuilder,
|
||||
TweetExpansionsBuilder,
|
||||
TweetPostBuilder,
|
||||
TweetSearchBuilder,
|
||||
)
|
||||
from backend.blocks.twitter._serializer import (
|
||||
IncludesSerializer,
|
||||
ResponseDataSerializer,
|
||||
)
|
||||
from backend.blocks.twitter._types import (
|
||||
TweetExpansionInputs,
|
||||
TweetExpansions,
|
||||
TweetFields,
|
||||
TweetMediaFields,
|
||||
TweetPlaceFields,
|
||||
TweetPollFields,
|
||||
TweetReplySettings,
|
||||
TweetTimeWindowInputs,
|
||||
TweetUserFields,
|
||||
)
|
||||
from backend.blocks.twitter.tweepy_exceptions import handle_tweepy_exception
|
||||
from backend.data.block import Block, BlockCategory, BlockOutput, BlockSchema
|
||||
from backend.data.model import SchemaField
|
||||
|
||||
|
||||
class TwitterPostTweetBlock(Block):
|
||||
"""
|
||||
Create a tweet on Twitter with the option to include one additional element such as a media, quote, or deep link except poll.
|
||||
Create a tweet on Twitter with the option to include one additional element such as a media, quote, or deep link.
|
||||
"""
|
||||
|
||||
class Input(BlockSchema):
|
||||
@@ -29,11 +46,11 @@ class TwitterPostTweetBlock(Block):
|
||||
["tweet.read", "tweet.write", "users.read", "offline.access"]
|
||||
)
|
||||
|
||||
tweet_text: str = SchemaField(
|
||||
tweet_text: str = SchemaField(
|
||||
description="Text of the tweet to post [It's Optional if you want to add media, quote, or deep link]",
|
||||
placeholder="Enter your tweet",
|
||||
advanced=False,
|
||||
default=""
|
||||
default="",
|
||||
)
|
||||
|
||||
media_ids: list = SchemaField(
|
||||
@@ -60,7 +77,7 @@ class TwitterPostTweetBlock(Block):
|
||||
default=[],
|
||||
)
|
||||
|
||||
poll_duration_minutes: int = SchemaField(
|
||||
poll_duration_minutes: int = SchemaField(
|
||||
description="Duration of the poll in minutes",
|
||||
placeholder="Enter poll duration in minutes",
|
||||
default=0,
|
||||
@@ -82,7 +99,7 @@ class TwitterPostTweetBlock(Block):
|
||||
description="Link to the Tweet being quoted, [ex- 1455953449422516226]",
|
||||
advanced=True,
|
||||
placeholder="Enter quote tweet ID",
|
||||
default=""
|
||||
default="",
|
||||
)
|
||||
|
||||
exclude_reply_user_ids: list = SchemaField(
|
||||
@@ -92,11 +109,11 @@ class TwitterPostTweetBlock(Block):
|
||||
default=[],
|
||||
)
|
||||
|
||||
in_reply_to_tweet_id: str = SchemaField(
|
||||
in_reply_to_tweet_id: str = SchemaField(
|
||||
description="Tweet ID being replied to. Please note that in_reply_to_tweet_id needs to be in the request if exclude_reply_user_ids is present",
|
||||
default="",
|
||||
placeholder="Enter in reply to tweet ID",
|
||||
advanced=True
|
||||
advanced=True,
|
||||
)
|
||||
|
||||
reply_settings: TweetReplySettings = SchemaField(
|
||||
@@ -149,17 +166,17 @@ class TwitterPostTweetBlock(Block):
|
||||
@staticmethod
|
||||
def post_tweet(
|
||||
credentials: TwitterCredentials,
|
||||
input_txt: str ,
|
||||
input_txt: str,
|
||||
media_ids: list,
|
||||
media_tagged_user_ids: list,
|
||||
direct_message_deep_link: str ,
|
||||
for_super_followers_only: bool ,
|
||||
place_id: str ,
|
||||
direct_message_deep_link: str,
|
||||
for_super_followers_only: bool,
|
||||
place_id: str,
|
||||
poll_options: list,
|
||||
poll_duration_minutes: int,
|
||||
quote_tweet_id: str ,
|
||||
exclude_reply_user_ids: list ,
|
||||
in_reply_to_tweet_id: str ,
|
||||
quote_tweet_id: str,
|
||||
exclude_reply_user_ids: list,
|
||||
in_reply_to_tweet_id: str,
|
||||
reply_settings: TweetReplySettings,
|
||||
):
|
||||
try:
|
||||
@@ -167,7 +184,8 @@ class TwitterPostTweetBlock(Block):
|
||||
bearer_token=credentials.access_token.get_secret_value()
|
||||
)
|
||||
|
||||
params = (TweetPostBuilder()
|
||||
params = (
|
||||
TweetPostBuilder()
|
||||
.add_text(input_txt)
|
||||
.add_media(media_ids, media_tagged_user_ids)
|
||||
.add_deep_link(direct_message_deep_link)
|
||||
@@ -176,14 +194,14 @@ class TwitterPostTweetBlock(Block):
|
||||
.add_poll_duration(poll_duration_minutes)
|
||||
.add_place(place_id)
|
||||
.add_quote(quote_tweet_id)
|
||||
.add_reply_settings(exclude_reply_user_ids, in_reply_to_tweet_id, reply_settings)
|
||||
.build())
|
||||
|
||||
tweet = cast(
|
||||
Response,
|
||||
client.create_tweet(**params)
|
||||
.add_reply_settings(
|
||||
exclude_reply_user_ids, in_reply_to_tweet_id, reply_settings
|
||||
)
|
||||
.build()
|
||||
)
|
||||
|
||||
tweet = cast(Response, client.create_tweet(**params))
|
||||
|
||||
if not tweet.data:
|
||||
raise Exception("Failed to create tweet")
|
||||
|
||||
@@ -226,6 +244,7 @@ class TwitterPostTweetBlock(Block):
|
||||
except Exception as e:
|
||||
yield "error", handle_tweepy_exception(e)
|
||||
|
||||
|
||||
class TwitterDeleteTweetBlock(Block):
|
||||
"""
|
||||
Deletes a tweet on Twitter using twitter Id
|
||||
@@ -262,9 +281,7 @@ class TwitterDeleteTweetBlock(Block):
|
||||
},
|
||||
test_credentials=TEST_CREDENTIALS,
|
||||
test_output=[("success", True)],
|
||||
test_mock={
|
||||
"delete_tweet": lambda *args, **kwargs: True
|
||||
},
|
||||
test_mock={"delete_tweet": lambda *args, **kwargs: True},
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
@@ -298,6 +315,7 @@ class TwitterDeleteTweetBlock(Block):
|
||||
except Exception as e:
|
||||
yield "error", handle_tweepy_exception(e)
|
||||
|
||||
|
||||
class TwitterSearchRecentTweetsBlock(Block):
|
||||
"""
|
||||
Searches all public Tweets in Twitter history
|
||||
@@ -329,14 +347,18 @@ class TwitterSearchRecentTweetsBlock(Block):
|
||||
|
||||
class Output(BlockSchema):
|
||||
# Common Outputs that user commonly uses
|
||||
tweet_ids : list[str] = SchemaField(description="All Tweet IDs")
|
||||
tweet_texts : list[str] = SchemaField(description="All Tweet texts")
|
||||
next_token : str = SchemaField(description="Next token for pagination")
|
||||
tweet_ids: list[str] = SchemaField(description="All Tweet IDs")
|
||||
tweet_texts: list[str] = SchemaField(description="All Tweet texts")
|
||||
next_token: str = SchemaField(description="Next token for pagination")
|
||||
|
||||
# Complete Outputs for advanced use
|
||||
data : list[dict] = SchemaField(description="Complete Tweet data")
|
||||
included : dict = SchemaField(description="Additional data that you have requested (Optional) via Expansions field")
|
||||
meta : dict = SchemaField(description="Provides metadata such as pagination info (next_token) or result counts")
|
||||
data: list[dict] = SchemaField(description="Complete Tweet data")
|
||||
included: dict = SchemaField(
|
||||
description="Additional data that you have requested (Optional) via Expansions field"
|
||||
)
|
||||
meta: dict = SchemaField(
|
||||
description="Provides metadata such as pagination info (next_token) or result counts"
|
||||
)
|
||||
|
||||
# error
|
||||
error: str = SchemaField(description="Error message if the request failed")
|
||||
@@ -363,53 +385,66 @@ class TwitterSearchRecentTweetsBlock(Block):
|
||||
"place_fields": [],
|
||||
"poll_fields": [],
|
||||
"tweet_fields": [],
|
||||
"user_fields": []
|
||||
"user_fields": [],
|
||||
},
|
||||
test_credentials=TEST_CREDENTIALS,
|
||||
test_output=[
|
||||
("tweet_ids", ["1373001119480344583", "1372627771717869568"]),
|
||||
("tweet_texts", ["Looking to get started with the Twitter API but new to APIs in general?",
|
||||
"Thanks to everyone who joined and made today a great session!"]),
|
||||
("data", [
|
||||
{
|
||||
"id": "1373001119480344583",
|
||||
"text": "Looking to get started with the Twitter API but new to APIs in general?"
|
||||
},
|
||||
{
|
||||
"id": "1372627771717869568",
|
||||
"text": "Thanks to everyone who joined and made today a great session!"
|
||||
}
|
||||
]),
|
||||
(
|
||||
"tweet_texts",
|
||||
[
|
||||
"Looking to get started with the Twitter API but new to APIs in general?",
|
||||
"Thanks to everyone who joined and made today a great session!",
|
||||
],
|
||||
),
|
||||
(
|
||||
"data",
|
||||
[
|
||||
{
|
||||
"id": "1373001119480344583",
|
||||
"text": "Looking to get started with the Twitter API but new to APIs in general?",
|
||||
},
|
||||
{
|
||||
"id": "1372627771717869568",
|
||||
"text": "Thanks to everyone who joined and made today a great session!",
|
||||
},
|
||||
],
|
||||
),
|
||||
("included", {}),
|
||||
("meta", {
|
||||
"newest_id": "1373001119480344583",
|
||||
"oldest_id": "1372627771717869568",
|
||||
"next_token": "next_token_value"
|
||||
}),
|
||||
("next_token", "next_token_value")
|
||||
(
|
||||
"meta",
|
||||
{
|
||||
"newest_id": "1373001119480344583",
|
||||
"oldest_id": "1372627771717869568",
|
||||
"next_token": "next_token_value",
|
||||
},
|
||||
),
|
||||
("next_token", "next_token_value"),
|
||||
],
|
||||
test_mock={
|
||||
"search_tweets": lambda *args, **kwargs: (
|
||||
["1373001119480344583", "1372627771717869568"],
|
||||
["Looking to get started with the Twitter API but new to APIs in general?",
|
||||
"Thanks to everyone who joined and made today a great session!"],
|
||||
[
|
||||
"Looking to get started with the Twitter API but new to APIs in general?",
|
||||
"Thanks to everyone who joined and made today a great session!",
|
||||
],
|
||||
[
|
||||
{
|
||||
"id": "1373001119480344583",
|
||||
"text": "Looking to get started with the Twitter API but new to APIs in general?"
|
||||
"text": "Looking to get started with the Twitter API but new to APIs in general?",
|
||||
},
|
||||
{
|
||||
"id": "1372627771717869568",
|
||||
"text": "Thanks to everyone who joined and made today a great session!"
|
||||
}
|
||||
"text": "Thanks to everyone who joined and made today a great session!",
|
||||
},
|
||||
],
|
||||
{},
|
||||
{
|
||||
"newest_id": "1373001119480344583",
|
||||
"oldest_id": "1372627771717869568",
|
||||
"next_token": "next_token_value"
|
||||
"next_token": "next_token_value",
|
||||
},
|
||||
"next_token_value"
|
||||
"next_token_value",
|
||||
)
|
||||
},
|
||||
)
|
||||
@@ -430,7 +465,7 @@ class TwitterSearchRecentTweetsBlock(Block):
|
||||
place_fields: list[TweetPlaceFields],
|
||||
poll_fields: list[TweetPollFields],
|
||||
tweet_fields: list[TweetFields],
|
||||
user_fields: list[TweetUserFields]
|
||||
user_fields: list[TweetUserFields],
|
||||
):
|
||||
try:
|
||||
client = tweepy.Client(
|
||||
@@ -438,35 +473,38 @@ class TwitterSearchRecentTweetsBlock(Block):
|
||||
)
|
||||
|
||||
# Building common params
|
||||
params = (TweetSearchBuilder()
|
||||
params = (
|
||||
TweetSearchBuilder()
|
||||
.add_query(query)
|
||||
.add_pagination(max_results, pagination)
|
||||
.build())
|
||||
.build()
|
||||
)
|
||||
|
||||
# Adding expansions to params If required by the user
|
||||
params = (TweetExpansionsBuilder(params)
|
||||
params = (
|
||||
TweetExpansionsBuilder(params)
|
||||
.add_expansions(expansions)
|
||||
.add_media_fields(media_fields)
|
||||
.add_place_fields(place_fields)
|
||||
.add_poll_fields(poll_fields)
|
||||
.add_tweet_fields(tweet_fields)
|
||||
.add_user_fields(user_fields)
|
||||
.build())
|
||||
.build()
|
||||
)
|
||||
|
||||
# Adding time window to params If required by the user
|
||||
params = (TweetDurationBuilder(params)
|
||||
params = (
|
||||
TweetDurationBuilder(params)
|
||||
.add_start_time(start_time)
|
||||
.add_end_time(end_time)
|
||||
.add_since_id(since_id)
|
||||
.add_until_id(until_id)
|
||||
.add_sort_order(sort_order)
|
||||
.build())
|
||||
|
||||
response = cast(
|
||||
Response,
|
||||
client.search_recent_tweets(**params)
|
||||
.build()
|
||||
)
|
||||
|
||||
response = cast(Response, client.search_recent_tweets(**params))
|
||||
|
||||
if not response.data and not response.meta:
|
||||
raise Exception("No tweets found")
|
||||
|
||||
@@ -516,7 +554,7 @@ class TwitterSearchRecentTweetsBlock(Block):
|
||||
input_data.place_fields,
|
||||
input_data.poll_fields,
|
||||
input_data.tweet_fields,
|
||||
input_data.user_fields
|
||||
input_data.user_fields,
|
||||
)
|
||||
if ids:
|
||||
yield "tweet_ids", ids
|
||||
|
||||
@@ -1,14 +1,8 @@
|
||||
from typing import cast
|
||||
|
||||
from backend.blocks.twitter._serializer import IncludesSerializer, ResponseDataSerializer
|
||||
import tweepy
|
||||
from tweepy.client import Response
|
||||
|
||||
from backend.data.block import Block, BlockCategory, BlockOutput, BlockSchema
|
||||
from backend.data.model import SchemaField
|
||||
from backend.blocks.twitter._builders import TweetExpansionsBuilder
|
||||
from backend.blocks.twitter._types import TweetExcludes, TweetExpansionInputs,TweetExpansions, TweetFields, TweetMediaFields, TweetPlaceFields, TweetPollFields, TweetUserFields
|
||||
from backend.blocks.twitter.tweepy_exceptions import handle_tweepy_exception
|
||||
from backend.blocks.twitter._auth import (
|
||||
TEST_CREDENTIALS,
|
||||
TEST_CREDENTIALS_INPUT,
|
||||
@@ -16,6 +10,25 @@ from backend.blocks.twitter._auth import (
|
||||
TwitterCredentialsField,
|
||||
TwitterCredentialsInput,
|
||||
)
|
||||
from backend.blocks.twitter._builders import TweetExpansionsBuilder
|
||||
from backend.blocks.twitter._serializer import (
|
||||
IncludesSerializer,
|
||||
ResponseDataSerializer,
|
||||
)
|
||||
from backend.blocks.twitter._types import (
|
||||
TweetExcludes,
|
||||
TweetExpansionInputs,
|
||||
TweetExpansions,
|
||||
TweetFields,
|
||||
TweetMediaFields,
|
||||
TweetPlaceFields,
|
||||
TweetPollFields,
|
||||
TweetUserFields,
|
||||
)
|
||||
from backend.blocks.twitter.tweepy_exceptions import handle_tweepy_exception
|
||||
from backend.data.block import Block, BlockCategory, BlockOutput, BlockSchema
|
||||
from backend.data.model import SchemaField
|
||||
|
||||
|
||||
class TwitterGetQuoteTweetsBlock(Block):
|
||||
"""
|
||||
@@ -47,7 +60,7 @@ class TwitterGetQuoteTweetsBlock(Block):
|
||||
default=[],
|
||||
)
|
||||
|
||||
pagination_token: str = SchemaField(
|
||||
pagination_token: str = SchemaField(
|
||||
description="Token for pagination",
|
||||
required=False,
|
||||
advanced=True,
|
||||
@@ -56,14 +69,18 @@ class TwitterGetQuoteTweetsBlock(Block):
|
||||
|
||||
class Output(BlockSchema):
|
||||
# Common Outputs that user commonly uses
|
||||
ids : list = SchemaField(description="All Tweet IDs ")
|
||||
texts : list = SchemaField(description="All Tweet texts")
|
||||
next_token : str = SchemaField(description="Next token for pagination")
|
||||
ids: list = SchemaField(description="All Tweet IDs ")
|
||||
texts: list = SchemaField(description="All Tweet texts")
|
||||
next_token: str = SchemaField(description="Next token for pagination")
|
||||
|
||||
# Complete Outputs for advanced use
|
||||
data : list[dict] = SchemaField(description="Complete Tweet data")
|
||||
included : dict = SchemaField(description="Additional data that you have requested (Optional) via Expansions field")
|
||||
meta : dict = SchemaField(description="Provides metadata such as pagination info (next_token) or result counts")
|
||||
data: list[dict] = SchemaField(description="Complete Tweet data")
|
||||
included: dict = SchemaField(
|
||||
description="Additional data that you have requested (Optional) via Expansions field"
|
||||
)
|
||||
meta: dict = SchemaField(
|
||||
description="Provides metadata such as pagination info (next_token) or result counts"
|
||||
)
|
||||
|
||||
# error
|
||||
error: str = SchemaField(description="Error message if the request failed")
|
||||
@@ -86,51 +103,36 @@ class TwitterGetQuoteTweetsBlock(Block):
|
||||
"place_fields": [],
|
||||
"poll_fields": [],
|
||||
"tweet_fields": [],
|
||||
"user_fields": []
|
||||
"user_fields": [],
|
||||
},
|
||||
test_credentials=TEST_CREDENTIALS,
|
||||
test_output=[
|
||||
("ids", ["12345", "67890"]),
|
||||
("texts", ["Tweet 1", "Tweet 2"]),
|
||||
("data", [
|
||||
{
|
||||
"id": "12345",
|
||||
"text": "Tweet 1"
|
||||
},
|
||||
{
|
||||
"id": "67890",
|
||||
"text": "Tweet 2"
|
||||
}
|
||||
]),
|
||||
(
|
||||
"data",
|
||||
[
|
||||
{"id": "12345", "text": "Tweet 1"},
|
||||
{"id": "67890", "text": "Tweet 2"},
|
||||
],
|
||||
),
|
||||
("included", {}),
|
||||
("meta", {
|
||||
"result_count": 2,
|
||||
"next_token": "next_token_value"
|
||||
}),
|
||||
("next_token", "next_token_value")
|
||||
("meta", {"result_count": 2, "next_token": "next_token_value"}),
|
||||
("next_token", "next_token_value"),
|
||||
],
|
||||
test_mock={
|
||||
"get_quote_tweets": lambda *args, **kwargs: (
|
||||
["12345", "67890"],
|
||||
["Tweet 1", "Tweet 2"],
|
||||
[
|
||||
{
|
||||
"id": "12345",
|
||||
"text": "Tweet 1"
|
||||
},
|
||||
{
|
||||
"id": "67890",
|
||||
"text": "Tweet 2"
|
||||
}
|
||||
{"id": "12345", "text": "Tweet 1"},
|
||||
{"id": "67890", "text": "Tweet 2"},
|
||||
],
|
||||
{},
|
||||
{
|
||||
"result_count": 2,
|
||||
"next_token": "next_token_value"
|
||||
},
|
||||
"next_token_value"
|
||||
{"result_count": 2, "next_token": "next_token_value"},
|
||||
"next_token_value",
|
||||
)
|
||||
}
|
||||
},
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
@@ -138,39 +140,43 @@ class TwitterGetQuoteTweetsBlock(Block):
|
||||
credentials: TwitterCredentials,
|
||||
tweet_id: str,
|
||||
max_results: int,
|
||||
exclude: list[TweetExcludes] ,
|
||||
pagination_token: str ,
|
||||
exclude: list[TweetExcludes],
|
||||
pagination_token: str,
|
||||
expansions: list[TweetExpansions],
|
||||
media_fields: list[TweetMediaFields],
|
||||
place_fields: list[TweetPlaceFields],
|
||||
poll_fields: list[TweetPollFields],
|
||||
tweet_fields: list[TweetFields],
|
||||
user_fields: list[TweetUserFields]
|
||||
user_fields: list[TweetUserFields],
|
||||
):
|
||||
try:
|
||||
client = tweepy.Client(
|
||||
bearer_token=credentials.access_token.get_secret_value()
|
||||
)
|
||||
|
||||
params = {"id": tweet_id,"max_results": max_results,
|
||||
"pagination_token":None if pagination_token == "" else pagination_token,
|
||||
"exclude": None if exclude == [] else exclude,
|
||||
"user_auth": False}
|
||||
params = {
|
||||
"id": tweet_id,
|
||||
"max_results": max_results,
|
||||
"pagination_token": (
|
||||
None if pagination_token == "" else pagination_token
|
||||
),
|
||||
"exclude": None if exclude == [] else exclude,
|
||||
"user_auth": False,
|
||||
}
|
||||
|
||||
params = (TweetExpansionsBuilder(params)
|
||||
params = (
|
||||
TweetExpansionsBuilder(params)
|
||||
.add_expansions(expansions)
|
||||
.add_media_fields(media_fields)
|
||||
.add_place_fields(place_fields)
|
||||
.add_poll_fields(poll_fields)
|
||||
.add_tweet_fields(tweet_fields)
|
||||
.add_user_fields(user_fields)
|
||||
.build())
|
||||
|
||||
response = cast(
|
||||
Response,
|
||||
client.get_quote_tweets(**params)
|
||||
.build()
|
||||
)
|
||||
|
||||
response = cast(Response, client.get_quote_tweets(**params))
|
||||
|
||||
meta = {}
|
||||
tweet_ids = []
|
||||
tweet_texts = []
|
||||
@@ -213,7 +219,7 @@ class TwitterGetQuoteTweetsBlock(Block):
|
||||
input_data.place_fields,
|
||||
input_data.poll_fields,
|
||||
input_data.tweet_fields,
|
||||
input_data.user_fields
|
||||
input_data.user_fields,
|
||||
)
|
||||
if ids:
|
||||
yield "ids", ids
|
||||
|
||||
@@ -1,16 +1,8 @@
|
||||
from typing import cast
|
||||
|
||||
from backend.blocks.twitter._serializer import IncludesSerializer, ResponseDataSerializer
|
||||
import tweepy
|
||||
from tweepy.client import Response
|
||||
|
||||
from backend.data.block import Block, BlockCategory, BlockOutput, BlockSchema
|
||||
from backend.data.model import SchemaField
|
||||
from backend.blocks.twitter._builders import UserExpansionsBuilder
|
||||
from backend.blocks.twitter._types import TweetFields, TweetUserFields, UserExpansionInputs, UserExpansions
|
||||
from backend.blocks.twitter.tweepy_exceptions import handle_tweepy_exception
|
||||
|
||||
|
||||
from backend.blocks.twitter._auth import (
|
||||
TEST_CREDENTIALS,
|
||||
TEST_CREDENTIALS_INPUT,
|
||||
@@ -18,6 +10,20 @@ from backend.blocks.twitter._auth import (
|
||||
TwitterCredentialsField,
|
||||
TwitterCredentialsInput,
|
||||
)
|
||||
from backend.blocks.twitter._builders import UserExpansionsBuilder
|
||||
from backend.blocks.twitter._serializer import (
|
||||
IncludesSerializer,
|
||||
ResponseDataSerializer,
|
||||
)
|
||||
from backend.blocks.twitter._types import (
|
||||
TweetFields,
|
||||
TweetUserFields,
|
||||
UserExpansionInputs,
|
||||
UserExpansions,
|
||||
)
|
||||
from backend.blocks.twitter.tweepy_exceptions import handle_tweepy_exception
|
||||
from backend.data.block import Block, BlockCategory, BlockOutput, BlockSchema
|
||||
from backend.data.model import SchemaField
|
||||
|
||||
|
||||
class TwitterRetweetBlock(Block):
|
||||
@@ -36,7 +42,7 @@ class TwitterRetweetBlock(Block):
|
||||
)
|
||||
|
||||
class Output(BlockSchema):
|
||||
success : bool = SchemaField(description="Whether the retweet was successful")
|
||||
success: bool = SchemaField(description="Whether the retweet was successful")
|
||||
error: str = SchemaField(description="Error message if the retweet failed")
|
||||
|
||||
def __init__(self):
|
||||
@@ -51,10 +57,7 @@ class TwitterRetweetBlock(Block):
|
||||
"credentials": TEST_CREDENTIALS_INPUT,
|
||||
},
|
||||
test_credentials=TEST_CREDENTIALS,
|
||||
test_output=[
|
||||
("success", True),
|
||||
("error", "")
|
||||
],
|
||||
test_output=[("success", True), ("error", "")],
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
@@ -67,13 +70,11 @@ class TwitterRetweetBlock(Block):
|
||||
bearer_token=credentials.access_token.get_secret_value()
|
||||
)
|
||||
|
||||
|
||||
client.retweet(
|
||||
tweet_id=tweet_id,
|
||||
user_auth=False,
|
||||
)
|
||||
|
||||
|
||||
return True
|
||||
|
||||
except tweepy.TweepyException:
|
||||
@@ -95,6 +96,7 @@ class TwitterRetweetBlock(Block):
|
||||
except Exception as e:
|
||||
yield "error", handle_tweepy_exception(e)
|
||||
|
||||
|
||||
class TwitterRemoveRetweetBlock(Block):
|
||||
"""
|
||||
Removes a retweet on Twitter
|
||||
@@ -143,14 +145,11 @@ class TwitterRemoveRetweetBlock(Block):
|
||||
bearer_token=credentials.access_token.get_secret_value()
|
||||
)
|
||||
|
||||
|
||||
|
||||
client.unretweet(
|
||||
source_tweet_id=tweet_id,
|
||||
user_auth=False,
|
||||
)
|
||||
|
||||
|
||||
return True
|
||||
|
||||
except tweepy.TweepyException:
|
||||
@@ -172,6 +171,7 @@ class TwitterRemoveRetweetBlock(Block):
|
||||
except Exception as e:
|
||||
yield "error", handle_tweepy_exception(e)
|
||||
|
||||
|
||||
class TwitterGetRetweetersBlock(Block):
|
||||
"""
|
||||
Gets information about who has retweeted a tweet
|
||||
@@ -204,13 +204,19 @@ class TwitterGetRetweetersBlock(Block):
|
||||
# Common Outputs that user commonly uses
|
||||
ids: list = SchemaField(description="List of user ids who retweeted")
|
||||
names: list = SchemaField(description="List of user names who retweeted")
|
||||
usernames: list = SchemaField(description="List of user usernames who retweeted")
|
||||
usernames: list = SchemaField(
|
||||
description="List of user usernames who retweeted"
|
||||
)
|
||||
next_token: str = SchemaField(description="Token for next page of results")
|
||||
|
||||
# Complete Outputs for advanced use
|
||||
data : list[dict] = SchemaField(description="Complete Tweet data")
|
||||
included : dict = SchemaField(description="Additional data that you have requested (Optional) via Expansions field")
|
||||
meta : dict = SchemaField(description="Provides metadata such as pagination info (next_token) or result counts")
|
||||
data: list[dict] = SchemaField(description="Complete Tweet data")
|
||||
included: dict = SchemaField(
|
||||
description="Additional data that you have requested (Optional) via Expansions field"
|
||||
)
|
||||
meta: dict = SchemaField(
|
||||
description="Provides metadata such as pagination info (next_token) or result counts"
|
||||
)
|
||||
|
||||
error: str = SchemaField(description="Error message if the request failed")
|
||||
|
||||
@@ -231,7 +237,7 @@ class TwitterGetRetweetersBlock(Block):
|
||||
"place_fields": [],
|
||||
"poll_fields": [],
|
||||
"tweet_fields": [],
|
||||
"user_fields": []
|
||||
"user_fields": [],
|
||||
},
|
||||
test_credentials=TEST_CREDENTIALS,
|
||||
test_output=[
|
||||
@@ -239,7 +245,10 @@ class TwitterGetRetweetersBlock(Block):
|
||||
("names", ["Test User"]),
|
||||
("usernames", ["testuser"]),
|
||||
("next_token", "next_token_value"),
|
||||
("data", [{"id": "12345", "name": "Test User", "username": "testuser"}]),
|
||||
(
|
||||
"data",
|
||||
[{"id": "12345", "name": "Test User", "username": "testuser"}],
|
||||
),
|
||||
("included", {}),
|
||||
("meta", {"next_token": "next_token_value"}),
|
||||
],
|
||||
@@ -251,9 +260,9 @@ class TwitterGetRetweetersBlock(Block):
|
||||
["12345"],
|
||||
["Test User"],
|
||||
["testuser"],
|
||||
"next_token_value"
|
||||
"next_token_value",
|
||||
)
|
||||
}
|
||||
},
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
@@ -261,10 +270,10 @@ class TwitterGetRetweetersBlock(Block):
|
||||
credentials: TwitterCredentials,
|
||||
tweet_id: str,
|
||||
max_results: int,
|
||||
pagination_token: str ,
|
||||
pagination_token: str,
|
||||
expansions: list[UserExpansions],
|
||||
tweet_fields: list[TweetFields],
|
||||
user_fields: list[TweetUserFields]
|
||||
user_fields: list[TweetUserFields],
|
||||
):
|
||||
try:
|
||||
client = tweepy.Client(
|
||||
@@ -274,15 +283,19 @@ class TwitterGetRetweetersBlock(Block):
|
||||
params = {
|
||||
"id": tweet_id,
|
||||
"max_results": max_results,
|
||||
"pagination_token":None if pagination_token == "" else pagination_token,
|
||||
"user_auth": False
|
||||
"pagination_token": (
|
||||
None if pagination_token == "" else pagination_token
|
||||
),
|
||||
"user_auth": False,
|
||||
}
|
||||
|
||||
params = (UserExpansionsBuilder(params)
|
||||
params = (
|
||||
UserExpansionsBuilder(params)
|
||||
.add_expansions(expansions)
|
||||
.add_tweet_fields(tweet_fields)
|
||||
.add_user_fields(user_fields)
|
||||
.build())
|
||||
.build()
|
||||
)
|
||||
|
||||
response = cast(Response, client.get_retweeters(**params))
|
||||
|
||||
@@ -318,14 +331,16 @@ class TwitterGetRetweetersBlock(Block):
|
||||
**kwargs,
|
||||
) -> BlockOutput:
|
||||
try:
|
||||
data, included, meta, ids, names, usernames, next_token = self.get_retweeters(
|
||||
credentials,
|
||||
input_data.tweet_id,
|
||||
input_data.max_results,
|
||||
input_data.pagination_token,
|
||||
input_data.expansions,
|
||||
input_data.tweet_fields,
|
||||
input_data.user_fields
|
||||
data, included, meta, ids, names, usernames, next_token = (
|
||||
self.get_retweeters(
|
||||
credentials,
|
||||
input_data.tweet_id,
|
||||
input_data.max_results,
|
||||
input_data.pagination_token,
|
||||
input_data.expansions,
|
||||
input_data.tweet_fields,
|
||||
input_data.user_fields,
|
||||
)
|
||||
)
|
||||
|
||||
if ids:
|
||||
|
||||
@@ -1,14 +1,8 @@
|
||||
from typing import cast
|
||||
|
||||
from backend.blocks.twitter._serializer import IncludesSerializer, ResponseDataSerializer
|
||||
import tweepy
|
||||
from tweepy.client import Response
|
||||
|
||||
from backend.data.block import Block, BlockCategory, BlockOutput, BlockSchema
|
||||
from backend.data.model import SchemaField
|
||||
from backend.blocks.twitter._builders import TweetDurationBuilder, TweetExpansionsBuilder
|
||||
from backend.blocks.twitter._types import TweetExpansionInputs, TweetExpansions, TweetFields, TweetMediaFields, TweetPlaceFields, TweetPollFields, TweetTimeWindowInputs, TweetUserFields
|
||||
from backend.blocks.twitter.tweepy_exceptions import handle_tweepy_exception
|
||||
from backend.blocks.twitter._auth import (
|
||||
TEST_CREDENTIALS,
|
||||
TEST_CREDENTIALS_INPUT,
|
||||
@@ -16,52 +10,79 @@ from backend.blocks.twitter._auth import (
|
||||
TwitterCredentialsField,
|
||||
TwitterCredentialsInput,
|
||||
)
|
||||
from backend.blocks.twitter._builders import (
|
||||
TweetDurationBuilder,
|
||||
TweetExpansionsBuilder,
|
||||
)
|
||||
from backend.blocks.twitter._serializer import (
|
||||
IncludesSerializer,
|
||||
ResponseDataSerializer,
|
||||
)
|
||||
from backend.blocks.twitter._types import (
|
||||
TweetExpansionInputs,
|
||||
TweetExpansions,
|
||||
TweetFields,
|
||||
TweetMediaFields,
|
||||
TweetPlaceFields,
|
||||
TweetPollFields,
|
||||
TweetTimeWindowInputs,
|
||||
TweetUserFields,
|
||||
)
|
||||
from backend.blocks.twitter.tweepy_exceptions import handle_tweepy_exception
|
||||
from backend.data.block import Block, BlockCategory, BlockOutput, BlockSchema
|
||||
from backend.data.model import SchemaField
|
||||
|
||||
|
||||
class TwitterGetUserMentionsBlock(Block):
|
||||
"""
|
||||
Returns Tweets where a single user is mentioned, just put that user id
|
||||
"""
|
||||
|
||||
class Input(TweetExpansionInputs,TweetTimeWindowInputs):
|
||||
class Input(TweetExpansionInputs, TweetTimeWindowInputs):
|
||||
credentials: TwitterCredentialsInput = TwitterCredentialsField(
|
||||
["tweet.read", "users.read", "offline.access"]
|
||||
)
|
||||
|
||||
user_id: str = SchemaField(
|
||||
description="Unique identifier of the user for whom to return Tweets mentioning the user",
|
||||
placeholder="Enter user ID"
|
||||
placeholder="Enter user ID",
|
||||
)
|
||||
|
||||
max_results: int = SchemaField(
|
||||
description="Number of tweets to retrieve (5-100)",
|
||||
default=10,
|
||||
advanced=True
|
||||
advanced=True,
|
||||
)
|
||||
|
||||
pagination_token: str = SchemaField(
|
||||
description="Token for pagination",
|
||||
default="",
|
||||
advanced=True
|
||||
pagination_token: str = SchemaField(
|
||||
description="Token for pagination", default="", advanced=True
|
||||
)
|
||||
|
||||
class Output(BlockSchema):
|
||||
# Common Outputs that user commonly uses
|
||||
ids : list[str] = SchemaField(description="List of Tweet IDs")
|
||||
texts : list[str] = SchemaField(description="All Tweet texts")
|
||||
ids: list[str] = SchemaField(description="List of Tweet IDs")
|
||||
texts: list[str] = SchemaField(description="All Tweet texts")
|
||||
|
||||
userIds: list[str] = SchemaField(description="List of user ids that mentioned the user")
|
||||
userNames: list[str] = SchemaField(description="List of user names that mentioned the user")
|
||||
next_token : str = SchemaField(description="Next token for pagination")
|
||||
userIds: list[str] = SchemaField(
|
||||
description="List of user ids that mentioned the user"
|
||||
)
|
||||
userNames: list[str] = SchemaField(
|
||||
description="List of user names that mentioned the user"
|
||||
)
|
||||
next_token: str = SchemaField(description="Next token for pagination")
|
||||
|
||||
# Complete Outputs for advanced use
|
||||
data : list[dict] = SchemaField(description="Complete Tweet data")
|
||||
included : dict = SchemaField(description="Additional data that you have requested (Optional) via Expansions field")
|
||||
meta : dict = SchemaField(description="Provides metadata such as pagination info (next_token) or result counts")
|
||||
data: list[dict] = SchemaField(description="Complete Tweet data")
|
||||
included: dict = SchemaField(
|
||||
description="Additional data that you have requested (Optional) via Expansions field"
|
||||
)
|
||||
meta: dict = SchemaField(
|
||||
description="Provides metadata such as pagination info (next_token) or result counts"
|
||||
)
|
||||
|
||||
# error
|
||||
error: str = SchemaField(description="Error message if the request failed")
|
||||
|
||||
|
||||
def __init__(self):
|
||||
super().__init__(
|
||||
id="e01c890c-a630-11ef-9e20-37da24888bd0",
|
||||
@@ -84,7 +105,7 @@ class TwitterGetUserMentionsBlock(Block):
|
||||
"place_fields": [],
|
||||
"poll_fields": [],
|
||||
"tweet_fields": [],
|
||||
"user_fields": []
|
||||
"user_fields": [],
|
||||
},
|
||||
test_credentials=TEST_CREDENTIALS,
|
||||
test_output=[
|
||||
@@ -92,28 +113,31 @@ class TwitterGetUserMentionsBlock(Block):
|
||||
("texts", ["Test mention 1", "Test mention 2"]),
|
||||
("userIds", ["67890", "67891"]),
|
||||
("userNames", ["testuser1", "testuser2"]),
|
||||
("data", [
|
||||
(
|
||||
"data",
|
||||
[
|
||||
{"id": "1373001119480344583", "text": "Test mention 1"},
|
||||
{"id": "1372627771717869568", "text": "Test mention 2"},
|
||||
],
|
||||
),
|
||||
(
|
||||
"included",
|
||||
{
|
||||
"id": "1373001119480344583",
|
||||
"text": "Test mention 1"
|
||||
"users": [
|
||||
{"id": "67890", "username": "testuser1"},
|
||||
{"id": "67891", "username": "testuser2"},
|
||||
]
|
||||
},
|
||||
),
|
||||
(
|
||||
"meta",
|
||||
{
|
||||
"id": "1372627771717869568",
|
||||
"text": "Test mention 2"
|
||||
}
|
||||
]),
|
||||
("included", {
|
||||
"users": [
|
||||
{"id": "67890", "username": "testuser1"},
|
||||
{"id": "67891", "username": "testuser2"}
|
||||
]
|
||||
}),
|
||||
("meta", {
|
||||
"newest_id": "1373001119480344583",
|
||||
"oldest_id": "1372627771717869568",
|
||||
"next_token": "next_token_value"
|
||||
}),
|
||||
("next_token", "next_token_value")
|
||||
"newest_id": "1373001119480344583",
|
||||
"oldest_id": "1372627771717869568",
|
||||
"next_token": "next_token_value",
|
||||
},
|
||||
),
|
||||
("next_token", "next_token_value"),
|
||||
],
|
||||
test_mock={
|
||||
"get_mentions": lambda *args, **kwargs: (
|
||||
@@ -123,22 +147,22 @@ class TwitterGetUserMentionsBlock(Block):
|
||||
["testuser1", "testuser2"],
|
||||
[
|
||||
{"id": "1373001119480344583", "text": "Test mention 1"},
|
||||
{"id": "1372627771717869568", "text": "Test mention 2"}
|
||||
{"id": "1372627771717869568", "text": "Test mention 2"},
|
||||
],
|
||||
{
|
||||
"users": [
|
||||
{"id": "67890", "username": "testuser1"},
|
||||
{"id": "67891", "username": "testuser2"}
|
||||
{"id": "67891", "username": "testuser2"},
|
||||
]
|
||||
},
|
||||
{
|
||||
"newest_id": "1373001119480344583",
|
||||
"oldest_id": "1372627771717869568",
|
||||
"next_token": "next_token_value"
|
||||
"next_token": "next_token_value",
|
||||
},
|
||||
"next_token_value"
|
||||
"next_token_value",
|
||||
)
|
||||
}
|
||||
},
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
@@ -157,7 +181,7 @@ class TwitterGetUserMentionsBlock(Block):
|
||||
place_fields: list[TweetPlaceFields],
|
||||
poll_fields: list[TweetPollFields],
|
||||
tweet_fields: list[TweetFields],
|
||||
user_fields: list[TweetUserFields]
|
||||
user_fields: list[TweetUserFields],
|
||||
):
|
||||
try:
|
||||
client = tweepy.Client(
|
||||
@@ -168,33 +192,35 @@ class TwitterGetUserMentionsBlock(Block):
|
||||
"id": user_id,
|
||||
"max_results": max_results,
|
||||
"pagination_token": None if pagination == "" else pagination,
|
||||
"user_auth": False
|
||||
"user_auth": False,
|
||||
}
|
||||
|
||||
# Adding expansions to params If required by the user
|
||||
params = (TweetExpansionsBuilder(params)
|
||||
params = (
|
||||
TweetExpansionsBuilder(params)
|
||||
.add_expansions(expansions)
|
||||
.add_media_fields(media_fields)
|
||||
.add_place_fields(place_fields)
|
||||
.add_poll_fields(poll_fields)
|
||||
.add_tweet_fields(tweet_fields)
|
||||
.add_user_fields(user_fields)
|
||||
.build())
|
||||
.build()
|
||||
)
|
||||
|
||||
# Adding time window to params If required by the user
|
||||
params = (TweetDurationBuilder(params)
|
||||
params = (
|
||||
TweetDurationBuilder(params)
|
||||
.add_start_time(start_time)
|
||||
.add_end_time(end_time)
|
||||
.add_since_id(since_id)
|
||||
.add_until_id(until_id)
|
||||
.add_sort_order(sort_order)
|
||||
.build())
|
||||
.build()
|
||||
)
|
||||
|
||||
response = cast(
|
||||
Response,
|
||||
client.get_users_mentions(
|
||||
**params
|
||||
),
|
||||
client.get_users_mentions(**params),
|
||||
)
|
||||
|
||||
if not response.data and not response.meta:
|
||||
@@ -218,7 +244,16 @@ class TwitterGetUserMentionsBlock(Block):
|
||||
user_ids = [str(user["id"]) for user in included["users"]]
|
||||
user_names = [user["username"] for user in included["users"]]
|
||||
|
||||
return tweet_ids, tweet_texts, user_ids, user_names, data, included, meta, next_token
|
||||
return (
|
||||
tweet_ids,
|
||||
tweet_texts,
|
||||
user_ids,
|
||||
user_names,
|
||||
data,
|
||||
included,
|
||||
meta,
|
||||
next_token,
|
||||
)
|
||||
|
||||
except tweepy.TweepyException:
|
||||
raise
|
||||
@@ -231,22 +266,24 @@ class TwitterGetUserMentionsBlock(Block):
|
||||
**kwargs,
|
||||
) -> BlockOutput:
|
||||
try:
|
||||
ids, texts, user_ids, user_names, data, included, meta, next_token = self.get_mentions(
|
||||
credentials,
|
||||
input_data.user_id,
|
||||
input_data.max_results,
|
||||
input_data.start_time,
|
||||
input_data.end_time,
|
||||
input_data.since_id,
|
||||
input_data.until_id,
|
||||
input_data.sort_order,
|
||||
input_data.pagination_token,
|
||||
input_data.expansions,
|
||||
input_data.media_fields,
|
||||
input_data.place_fields,
|
||||
input_data.poll_fields,
|
||||
input_data.tweet_fields,
|
||||
input_data.user_fields
|
||||
ids, texts, user_ids, user_names, data, included, meta, next_token = (
|
||||
self.get_mentions(
|
||||
credentials,
|
||||
input_data.user_id,
|
||||
input_data.max_results,
|
||||
input_data.start_time,
|
||||
input_data.end_time,
|
||||
input_data.since_id,
|
||||
input_data.until_id,
|
||||
input_data.sort_order,
|
||||
input_data.pagination_token,
|
||||
input_data.expansions,
|
||||
input_data.media_fields,
|
||||
input_data.place_fields,
|
||||
input_data.poll_fields,
|
||||
input_data.tweet_fields,
|
||||
input_data.user_fields,
|
||||
)
|
||||
)
|
||||
if ids:
|
||||
yield "ids", ids
|
||||
@@ -268,12 +305,13 @@ class TwitterGetUserMentionsBlock(Block):
|
||||
except Exception as e:
|
||||
yield "error", handle_tweepy_exception(e)
|
||||
|
||||
|
||||
class TwitterGetHomeTimelineBlock(Block):
|
||||
"""
|
||||
Returns a collection of the most recent Tweets and Retweets posted by you and users you follow
|
||||
"""
|
||||
|
||||
class Input(TweetExpansionInputs,TweetTimeWindowInputs):
|
||||
class Input(TweetExpansionInputs, TweetTimeWindowInputs):
|
||||
credentials: TwitterCredentialsInput = TwitterCredentialsField(
|
||||
["tweet.read", "users.read", "offline.access"]
|
||||
)
|
||||
@@ -281,28 +319,34 @@ class TwitterGetHomeTimelineBlock(Block):
|
||||
max_results: int = SchemaField(
|
||||
description="Number of tweets to retrieve (5-100)",
|
||||
default=10,
|
||||
advanced=True
|
||||
advanced=True,
|
||||
)
|
||||
|
||||
pagination_token: str = SchemaField(
|
||||
description="Token for pagination",
|
||||
default="",
|
||||
advanced=True
|
||||
pagination_token: str = SchemaField(
|
||||
description="Token for pagination", default="", advanced=True
|
||||
)
|
||||
|
||||
class Output(BlockSchema):
|
||||
# Common Outputs that user commonly uses
|
||||
ids : list[str] = SchemaField(description="List of Tweet IDs")
|
||||
texts : list[str] = SchemaField(description="All Tweet texts")
|
||||
ids: list[str] = SchemaField(description="List of Tweet IDs")
|
||||
texts: list[str] = SchemaField(description="All Tweet texts")
|
||||
|
||||
userIds: list[str] = SchemaField(description="List of user ids that authored the tweets")
|
||||
userNames: list[str] = SchemaField(description="List of user names that authored the tweets")
|
||||
next_token : str = SchemaField(description="Next token for pagination")
|
||||
userIds: list[str] = SchemaField(
|
||||
description="List of user ids that authored the tweets"
|
||||
)
|
||||
userNames: list[str] = SchemaField(
|
||||
description="List of user names that authored the tweets"
|
||||
)
|
||||
next_token: str = SchemaField(description="Next token for pagination")
|
||||
|
||||
# Complete Outputs for advanced use
|
||||
data : list[dict] = SchemaField(description="Complete Tweet data")
|
||||
included : dict = SchemaField(description="Additional data that you have requested (Optional) via Expansions field")
|
||||
meta : dict = SchemaField(description="Provides metadata such as pagination info (next_token) or result counts")
|
||||
data: list[dict] = SchemaField(description="Complete Tweet data")
|
||||
included: dict = SchemaField(
|
||||
description="Additional data that you have requested (Optional) via Expansions field"
|
||||
)
|
||||
meta: dict = SchemaField(
|
||||
description="Provides metadata such as pagination info (next_token) or result counts"
|
||||
)
|
||||
|
||||
# error
|
||||
error: str = SchemaField(description="Error message if the request failed")
|
||||
@@ -328,7 +372,7 @@ class TwitterGetHomeTimelineBlock(Block):
|
||||
"place_fields": [],
|
||||
"poll_fields": [],
|
||||
"tweet_fields": [],
|
||||
"user_fields": []
|
||||
"user_fields": [],
|
||||
},
|
||||
test_credentials=TEST_CREDENTIALS,
|
||||
test_output=[
|
||||
@@ -336,28 +380,31 @@ class TwitterGetHomeTimelineBlock(Block):
|
||||
("texts", ["Test tweet 1", "Test tweet 2"]),
|
||||
("userIds", ["67890", "67891"]),
|
||||
("userNames", ["testuser1", "testuser2"]),
|
||||
("data", [
|
||||
(
|
||||
"data",
|
||||
[
|
||||
{"id": "1373001119480344583", "text": "Test tweet 1"},
|
||||
{"id": "1372627771717869568", "text": "Test tweet 2"},
|
||||
],
|
||||
),
|
||||
(
|
||||
"included",
|
||||
{
|
||||
"id": "1373001119480344583",
|
||||
"text": "Test tweet 1"
|
||||
"users": [
|
||||
{"id": "67890", "username": "testuser1"},
|
||||
{"id": "67891", "username": "testuser2"},
|
||||
]
|
||||
},
|
||||
),
|
||||
(
|
||||
"meta",
|
||||
{
|
||||
"id": "1372627771717869568",
|
||||
"text": "Test tweet 2"
|
||||
}
|
||||
]),
|
||||
("included", {
|
||||
"users": [
|
||||
{"id": "67890", "username": "testuser1"},
|
||||
{"id": "67891", "username": "testuser2"}
|
||||
]
|
||||
}),
|
||||
("meta", {
|
||||
"newest_id": "1373001119480344583",
|
||||
"oldest_id": "1372627771717869568",
|
||||
"next_token": "next_token_value"
|
||||
}),
|
||||
("next_token", "next_token_value")
|
||||
"newest_id": "1373001119480344583",
|
||||
"oldest_id": "1372627771717869568",
|
||||
"next_token": "next_token_value",
|
||||
},
|
||||
),
|
||||
("next_token", "next_token_value"),
|
||||
],
|
||||
test_mock={
|
||||
"get_timeline": lambda *args, **kwargs: (
|
||||
@@ -367,22 +414,22 @@ class TwitterGetHomeTimelineBlock(Block):
|
||||
["testuser1", "testuser2"],
|
||||
[
|
||||
{"id": "1373001119480344583", "text": "Test tweet 1"},
|
||||
{"id": "1372627771717869568", "text": "Test tweet 2"}
|
||||
{"id": "1372627771717869568", "text": "Test tweet 2"},
|
||||
],
|
||||
{
|
||||
"users": [
|
||||
{"id": "67890", "username": "testuser1"},
|
||||
{"id": "67891", "username": "testuser2"}
|
||||
{"id": "67891", "username": "testuser2"},
|
||||
]
|
||||
},
|
||||
{
|
||||
"newest_id": "1373001119480344583",
|
||||
"oldest_id": "1372627771717869568",
|
||||
"next_token": "next_token_value"
|
||||
"next_token": "next_token_value",
|
||||
},
|
||||
"next_token_value"
|
||||
"next_token_value",
|
||||
)
|
||||
}
|
||||
},
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
@@ -400,7 +447,7 @@ class TwitterGetHomeTimelineBlock(Block):
|
||||
place_fields: list[TweetPlaceFields],
|
||||
poll_fields: list[TweetPollFields],
|
||||
tweet_fields: list[TweetFields],
|
||||
user_fields: list[TweetUserFields]
|
||||
user_fields: list[TweetUserFields],
|
||||
):
|
||||
try:
|
||||
client = tweepy.Client(
|
||||
@@ -410,33 +457,35 @@ class TwitterGetHomeTimelineBlock(Block):
|
||||
params = {
|
||||
"max_results": max_results,
|
||||
"pagination_token": None if pagination == "" else pagination,
|
||||
"user_auth": False
|
||||
"user_auth": False,
|
||||
}
|
||||
|
||||
# Adding expansions to params If required by the user
|
||||
params = (TweetExpansionsBuilder(params)
|
||||
params = (
|
||||
TweetExpansionsBuilder(params)
|
||||
.add_expansions(expansions)
|
||||
.add_media_fields(media_fields)
|
||||
.add_place_fields(place_fields)
|
||||
.add_poll_fields(poll_fields)
|
||||
.add_tweet_fields(tweet_fields)
|
||||
.add_user_fields(user_fields)
|
||||
.build())
|
||||
.build()
|
||||
)
|
||||
|
||||
# Adding time window to params If required by the user
|
||||
params = (TweetDurationBuilder(params)
|
||||
params = (
|
||||
TweetDurationBuilder(params)
|
||||
.add_start_time(start_time)
|
||||
.add_end_time(end_time)
|
||||
.add_since_id(since_id)
|
||||
.add_until_id(until_id)
|
||||
.add_sort_order(sort_order)
|
||||
.build())
|
||||
.build()
|
||||
)
|
||||
|
||||
response = cast(
|
||||
Response,
|
||||
client.get_home_timeline(
|
||||
**params
|
||||
),
|
||||
client.get_home_timeline(**params),
|
||||
)
|
||||
|
||||
if not response.data and not response.meta:
|
||||
@@ -460,7 +509,16 @@ class TwitterGetHomeTimelineBlock(Block):
|
||||
user_ids = [str(user["id"]) for user in included["users"]]
|
||||
user_names = [user["username"] for user in included["users"]]
|
||||
|
||||
return tweet_ids, tweet_texts, user_ids, user_names, data, included, meta, next_token
|
||||
return (
|
||||
tweet_ids,
|
||||
tweet_texts,
|
||||
user_ids,
|
||||
user_names,
|
||||
data,
|
||||
included,
|
||||
meta,
|
||||
next_token,
|
||||
)
|
||||
|
||||
except tweepy.TweepyException:
|
||||
raise
|
||||
@@ -473,21 +531,23 @@ class TwitterGetHomeTimelineBlock(Block):
|
||||
**kwargs,
|
||||
) -> BlockOutput:
|
||||
try:
|
||||
ids, texts, user_ids, user_names, data, included, meta, next_token = self.get_timeline(
|
||||
credentials,
|
||||
input_data.max_results,
|
||||
input_data.start_time,
|
||||
input_data.end_time,
|
||||
input_data.since_id,
|
||||
input_data.until_id,
|
||||
input_data.sort_order,
|
||||
input_data.pagination_token,
|
||||
input_data.expansions,
|
||||
input_data.media_fields,
|
||||
input_data.place_fields,
|
||||
input_data.poll_fields,
|
||||
input_data.tweet_fields,
|
||||
input_data.user_fields
|
||||
ids, texts, user_ids, user_names, data, included, meta, next_token = (
|
||||
self.get_timeline(
|
||||
credentials,
|
||||
input_data.max_results,
|
||||
input_data.start_time,
|
||||
input_data.end_time,
|
||||
input_data.since_id,
|
||||
input_data.until_id,
|
||||
input_data.sort_order,
|
||||
input_data.pagination_token,
|
||||
input_data.expansions,
|
||||
input_data.media_fields,
|
||||
input_data.place_fields,
|
||||
input_data.poll_fields,
|
||||
input_data.tweet_fields,
|
||||
input_data.user_fields,
|
||||
)
|
||||
)
|
||||
if ids:
|
||||
yield "ids", ids
|
||||
@@ -509,46 +569,53 @@ class TwitterGetHomeTimelineBlock(Block):
|
||||
except Exception as e:
|
||||
yield "error", handle_tweepy_exception(e)
|
||||
|
||||
|
||||
class TwitterGetUserTweetsBlock(Block):
|
||||
"""
|
||||
Returns Tweets composed by a single user, specified by the requested user ID
|
||||
"""
|
||||
|
||||
class Input(TweetExpansionInputs,TweetTimeWindowInputs):
|
||||
class Input(TweetExpansionInputs, TweetTimeWindowInputs):
|
||||
credentials: TwitterCredentialsInput = TwitterCredentialsField(
|
||||
["tweet.read", "users.read", "offline.access"]
|
||||
)
|
||||
|
||||
user_id: str = SchemaField(
|
||||
description="Unique identifier of the Twitter account (user ID) for whom to return results",
|
||||
placeholder="Enter user ID"
|
||||
placeholder="Enter user ID",
|
||||
)
|
||||
|
||||
max_results: int = SchemaField(
|
||||
description="Number of tweets to retrieve (5-100)",
|
||||
default=10,
|
||||
advanced=True
|
||||
advanced=True,
|
||||
)
|
||||
|
||||
pagination_token: str = SchemaField(
|
||||
description="Token for pagination",
|
||||
default="",
|
||||
advanced=True
|
||||
pagination_token: str = SchemaField(
|
||||
description="Token for pagination", default="", advanced=True
|
||||
)
|
||||
|
||||
class Output(BlockSchema):
|
||||
# Common Outputs that user commonly uses
|
||||
ids : list[str] = SchemaField(description="List of Tweet IDs")
|
||||
texts : list[str] = SchemaField(description="All Tweet texts")
|
||||
ids: list[str] = SchemaField(description="List of Tweet IDs")
|
||||
texts: list[str] = SchemaField(description="All Tweet texts")
|
||||
|
||||
userIds: list[str] = SchemaField(description="List of user ids that authored the tweets")
|
||||
userNames: list[str] = SchemaField(description="List of user names that authored the tweets")
|
||||
next_token : str = SchemaField(description="Next token for pagination")
|
||||
userIds: list[str] = SchemaField(
|
||||
description="List of user ids that authored the tweets"
|
||||
)
|
||||
userNames: list[str] = SchemaField(
|
||||
description="List of user names that authored the tweets"
|
||||
)
|
||||
next_token: str = SchemaField(description="Next token for pagination")
|
||||
|
||||
# Complete Outputs for advanced use
|
||||
data : list[dict] = SchemaField(description="Complete Tweet data")
|
||||
included : dict = SchemaField(description="Additional data that you have requested (Optional) via Expansions field")
|
||||
meta : dict = SchemaField(description="Provides metadata such as pagination info (next_token) or result counts")
|
||||
data: list[dict] = SchemaField(description="Complete Tweet data")
|
||||
included: dict = SchemaField(
|
||||
description="Additional data that you have requested (Optional) via Expansions field"
|
||||
)
|
||||
meta: dict = SchemaField(
|
||||
description="Provides metadata such as pagination info (next_token) or result counts"
|
||||
)
|
||||
|
||||
# error
|
||||
error: str = SchemaField(description="Error message if the request failed")
|
||||
@@ -575,7 +642,7 @@ class TwitterGetUserTweetsBlock(Block):
|
||||
"place_fields": [],
|
||||
"poll_fields": [],
|
||||
"tweet_fields": [],
|
||||
"user_fields": []
|
||||
"user_fields": [],
|
||||
},
|
||||
test_credentials=TEST_CREDENTIALS,
|
||||
test_output=[
|
||||
@@ -583,28 +650,31 @@ class TwitterGetUserTweetsBlock(Block):
|
||||
("texts", ["Test tweet 1", "Test tweet 2"]),
|
||||
("userIds", ["67890", "67891"]),
|
||||
("userNames", ["testuser1", "testuser2"]),
|
||||
("data", [
|
||||
(
|
||||
"data",
|
||||
[
|
||||
{"id": "1373001119480344583", "text": "Test tweet 1"},
|
||||
{"id": "1372627771717869568", "text": "Test tweet 2"},
|
||||
],
|
||||
),
|
||||
(
|
||||
"included",
|
||||
{
|
||||
"id": "1373001119480344583",
|
||||
"text": "Test tweet 1"
|
||||
"users": [
|
||||
{"id": "67890", "username": "testuser1"},
|
||||
{"id": "67891", "username": "testuser2"},
|
||||
]
|
||||
},
|
||||
),
|
||||
(
|
||||
"meta",
|
||||
{
|
||||
"id": "1372627771717869568",
|
||||
"text": "Test tweet 2"
|
||||
}
|
||||
]),
|
||||
("included", {
|
||||
"users": [
|
||||
{"id": "67890", "username": "testuser1"},
|
||||
{"id": "67891", "username": "testuser2"}
|
||||
]
|
||||
}),
|
||||
("meta", {
|
||||
"newest_id": "1373001119480344583",
|
||||
"oldest_id": "1372627771717869568",
|
||||
"next_token": "next_token_value"
|
||||
}),
|
||||
("next_token", "next_token_value")
|
||||
"newest_id": "1373001119480344583",
|
||||
"oldest_id": "1372627771717869568",
|
||||
"next_token": "next_token_value",
|
||||
},
|
||||
),
|
||||
("next_token", "next_token_value"),
|
||||
],
|
||||
test_mock={
|
||||
"get_user_tweets": lambda *args, **kwargs: (
|
||||
@@ -614,22 +684,22 @@ class TwitterGetUserTweetsBlock(Block):
|
||||
["testuser1", "testuser2"],
|
||||
[
|
||||
{"id": "1373001119480344583", "text": "Test tweet 1"},
|
||||
{"id": "1372627771717869568", "text": "Test tweet 2"}
|
||||
{"id": "1372627771717869568", "text": "Test tweet 2"},
|
||||
],
|
||||
{
|
||||
"users": [
|
||||
{"id": "67890", "username": "testuser1"},
|
||||
{"id": "67891", "username": "testuser2"}
|
||||
{"id": "67891", "username": "testuser2"},
|
||||
]
|
||||
},
|
||||
{
|
||||
"newest_id": "1373001119480344583",
|
||||
"oldest_id": "1372627771717869568",
|
||||
"next_token": "next_token_value"
|
||||
"next_token": "next_token_value",
|
||||
},
|
||||
"next_token_value"
|
||||
"next_token_value",
|
||||
)
|
||||
}
|
||||
},
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
@@ -648,7 +718,7 @@ class TwitterGetUserTweetsBlock(Block):
|
||||
place_fields: list[TweetPlaceFields],
|
||||
poll_fields: list[TweetPollFields],
|
||||
tweet_fields: list[TweetFields],
|
||||
user_fields: list[TweetUserFields]
|
||||
user_fields: list[TweetUserFields],
|
||||
):
|
||||
try:
|
||||
client = tweepy.Client(
|
||||
@@ -659,33 +729,35 @@ class TwitterGetUserTweetsBlock(Block):
|
||||
"id": user_id,
|
||||
"max_results": max_results,
|
||||
"pagination_token": None if pagination == "" else pagination,
|
||||
"user_auth": False
|
||||
"user_auth": False,
|
||||
}
|
||||
|
||||
# Adding expansions to params If required by the user
|
||||
params = (TweetExpansionsBuilder(params)
|
||||
params = (
|
||||
TweetExpansionsBuilder(params)
|
||||
.add_expansions(expansions)
|
||||
.add_media_fields(media_fields)
|
||||
.add_place_fields(place_fields)
|
||||
.add_poll_fields(poll_fields)
|
||||
.add_tweet_fields(tweet_fields)
|
||||
.add_user_fields(user_fields)
|
||||
.build())
|
||||
.build()
|
||||
)
|
||||
|
||||
# Adding time window to params If required by the user
|
||||
params = (TweetDurationBuilder(params)
|
||||
params = (
|
||||
TweetDurationBuilder(params)
|
||||
.add_start_time(start_time)
|
||||
.add_end_time(end_time)
|
||||
.add_since_id(since_id)
|
||||
.add_until_id(until_id)
|
||||
.add_sort_order(sort_order)
|
||||
.build())
|
||||
.build()
|
||||
)
|
||||
|
||||
response = cast(
|
||||
Response,
|
||||
client.get_users_tweets(
|
||||
**params
|
||||
),
|
||||
client.get_users_tweets(**params),
|
||||
)
|
||||
|
||||
if not response.data and not response.meta:
|
||||
@@ -709,7 +781,16 @@ class TwitterGetUserTweetsBlock(Block):
|
||||
user_ids = [str(user["id"]) for user in included["users"]]
|
||||
user_names = [user["username"] for user in included["users"]]
|
||||
|
||||
return tweet_ids, tweet_texts, user_ids, user_names, data, included, meta, next_token
|
||||
return (
|
||||
tweet_ids,
|
||||
tweet_texts,
|
||||
user_ids,
|
||||
user_names,
|
||||
data,
|
||||
included,
|
||||
meta,
|
||||
next_token,
|
||||
)
|
||||
|
||||
except tweepy.TweepyException:
|
||||
raise
|
||||
@@ -722,22 +803,24 @@ class TwitterGetUserTweetsBlock(Block):
|
||||
**kwargs,
|
||||
) -> BlockOutput:
|
||||
try:
|
||||
ids, texts, user_ids, user_names, data, included, meta, next_token = self.get_user_tweets(
|
||||
credentials,
|
||||
input_data.user_id,
|
||||
input_data.max_results,
|
||||
input_data.start_time,
|
||||
input_data.end_time,
|
||||
input_data.since_id,
|
||||
input_data.until_id,
|
||||
input_data.sort_order,
|
||||
input_data.pagination_token,
|
||||
input_data.expansions,
|
||||
input_data.media_fields,
|
||||
input_data.place_fields,
|
||||
input_data.poll_fields,
|
||||
input_data.tweet_fields,
|
||||
input_data.user_fields
|
||||
ids, texts, user_ids, user_names, data, included, meta, next_token = (
|
||||
self.get_user_tweets(
|
||||
credentials,
|
||||
input_data.user_id,
|
||||
input_data.max_results,
|
||||
input_data.start_time,
|
||||
input_data.end_time,
|
||||
input_data.since_id,
|
||||
input_data.until_id,
|
||||
input_data.sort_order,
|
||||
input_data.pagination_token,
|
||||
input_data.expansions,
|
||||
input_data.media_fields,
|
||||
input_data.place_fields,
|
||||
input_data.poll_fields,
|
||||
input_data.tweet_fields,
|
||||
input_data.user_fields,
|
||||
)
|
||||
)
|
||||
if ids:
|
||||
yield "ids", ids
|
||||
|
||||
@@ -1,15 +1,8 @@
|
||||
from typing import cast
|
||||
|
||||
from backend.blocks.twitter._serializer import IncludesSerializer, ResponseDataSerializer
|
||||
import tweepy
|
||||
from tweepy.client import Response
|
||||
|
||||
from backend.data.block import Block, BlockCategory, BlockOutput, BlockSchema
|
||||
from backend.data.model import SchemaField
|
||||
from backend.blocks.twitter._types import TweetExpansions, TweetMediaFields, TweetPlaceFields, TweetPollFields, TweetFields, TweetUserFields, TweetExpansionInputs
|
||||
from backend.blocks.twitter._builders import TweetExpansionsBuilder
|
||||
from backend.blocks.twitter.tweepy_exceptions import handle_tweepy_exception
|
||||
|
||||
from backend.blocks.twitter._auth import (
|
||||
TEST_CREDENTIALS,
|
||||
TEST_CREDENTIALS_INPUT,
|
||||
@@ -17,6 +10,24 @@ from backend.blocks.twitter._auth import (
|
||||
TwitterCredentialsField,
|
||||
TwitterCredentialsInput,
|
||||
)
|
||||
from backend.blocks.twitter._builders import TweetExpansionsBuilder
|
||||
from backend.blocks.twitter._serializer import (
|
||||
IncludesSerializer,
|
||||
ResponseDataSerializer,
|
||||
)
|
||||
from backend.blocks.twitter._types import (
|
||||
TweetExpansionInputs,
|
||||
TweetExpansions,
|
||||
TweetFields,
|
||||
TweetMediaFields,
|
||||
TweetPlaceFields,
|
||||
TweetPollFields,
|
||||
TweetUserFields,
|
||||
)
|
||||
from backend.blocks.twitter.tweepy_exceptions import handle_tweepy_exception
|
||||
from backend.data.block import Block, BlockCategory, BlockOutput, BlockSchema
|
||||
from backend.data.model import SchemaField
|
||||
|
||||
|
||||
class TwitterGetTweetBlock(Block):
|
||||
"""
|
||||
@@ -30,19 +41,21 @@ class TwitterGetTweetBlock(Block):
|
||||
|
||||
tweet_id: str = SchemaField(
|
||||
description="Unique identifier of the Tweet to request (ex: 1460323737035677698)",
|
||||
placeholder="Enter tweet ID"
|
||||
placeholder="Enter tweet ID",
|
||||
)
|
||||
|
||||
class Output(BlockSchema):
|
||||
# Common Outputs that user commonly uses
|
||||
id : str = SchemaField(description="Tweet ID")
|
||||
text : str = SchemaField(description="Tweet text")
|
||||
id: str = SchemaField(description="Tweet ID")
|
||||
text: str = SchemaField(description="Tweet text")
|
||||
userId: str = SchemaField(description="ID of the tweet author")
|
||||
userName: str = SchemaField(description="Username of the tweet author")
|
||||
|
||||
# Complete Outputs for advanced use
|
||||
data: dict = SchemaField(description="Tweet data")
|
||||
included: dict = SchemaField(description="Additional data that you have requested (Optional) via Expansions field")
|
||||
included: dict = SchemaField(
|
||||
description="Additional data that you have requested (Optional) via Expansions field"
|
||||
)
|
||||
meta: dict = SchemaField(description="Metadata about the tweet")
|
||||
|
||||
error: str = SchemaField(description="Error message if the request failed")
|
||||
@@ -62,7 +75,7 @@ class TwitterGetTweetBlock(Block):
|
||||
"place_fields": [],
|
||||
"poll_fields": [],
|
||||
"tweet_fields": [],
|
||||
"user_fields": []
|
||||
"user_fields": [],
|
||||
},
|
||||
test_credentials=TEST_CREDENTIALS,
|
||||
test_output=[
|
||||
@@ -75,11 +88,11 @@ class TwitterGetTweetBlock(Block):
|
||||
("meta", {"result_count": 1}),
|
||||
],
|
||||
test_mock={
|
||||
"get_tweet": lambda *args, **kwargs: ({
|
||||
"id": "1460323737035677698",
|
||||
"text": "Test tweet content"
|
||||
}, {})
|
||||
}
|
||||
"get_tweet": lambda *args, **kwargs: (
|
||||
{"id": "1460323737035677698", "text": "Test tweet content"},
|
||||
{},
|
||||
)
|
||||
},
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
@@ -91,23 +104,25 @@ class TwitterGetTweetBlock(Block):
|
||||
place_fields: list[TweetPlaceFields],
|
||||
poll_fields: list[TweetPollFields],
|
||||
tweet_fields: list[TweetFields],
|
||||
user_fields: list[TweetUserFields]
|
||||
user_fields: list[TweetUserFields],
|
||||
):
|
||||
try:
|
||||
client = tweepy.Client(
|
||||
bearer_token=credentials.access_token.get_secret_value()
|
||||
)
|
||||
params = {"id": tweet_id,"user_auth": False}
|
||||
params = {"id": tweet_id, "user_auth": False}
|
||||
|
||||
# Adding expansions to params If required by the user
|
||||
params = (TweetExpansionsBuilder(params)
|
||||
params = (
|
||||
TweetExpansionsBuilder(params)
|
||||
.add_expansions(expansions)
|
||||
.add_media_fields(media_fields)
|
||||
.add_place_fields(place_fields)
|
||||
.add_poll_fields(poll_fields)
|
||||
.add_tweet_fields(tweet_fields)
|
||||
.add_user_fields(user_fields)
|
||||
.build())
|
||||
.build()
|
||||
)
|
||||
|
||||
response = cast(Response, client.get_tweet(**params))
|
||||
|
||||
@@ -142,8 +157,6 @@ class TwitterGetTweetBlock(Block):
|
||||
) -> BlockOutput:
|
||||
try:
|
||||
|
||||
|
||||
|
||||
tweet_data, included, meta, user_id, user_name = self.get_tweet(
|
||||
credentials,
|
||||
input_data.tweet_id,
|
||||
@@ -152,7 +165,7 @@ class TwitterGetTweetBlock(Block):
|
||||
input_data.place_fields,
|
||||
input_data.poll_fields,
|
||||
input_data.tweet_fields,
|
||||
input_data.user_fields
|
||||
input_data.user_fields,
|
||||
)
|
||||
|
||||
yield "id", str(tweet_data["id"])
|
||||
@@ -170,6 +183,7 @@ class TwitterGetTweetBlock(Block):
|
||||
except Exception as e:
|
||||
yield "error", handle_tweepy_exception(e)
|
||||
|
||||
|
||||
class TwitterGetTweetsBlock(Block):
|
||||
"""
|
||||
Returns information about multiple Tweets specified by the requested IDs
|
||||
@@ -182,19 +196,25 @@ class TwitterGetTweetsBlock(Block):
|
||||
|
||||
tweet_ids: list[str] = SchemaField(
|
||||
description="List of Tweet IDs to request (up to 100)",
|
||||
placeholder="Enter tweet IDs"
|
||||
placeholder="Enter tweet IDs",
|
||||
)
|
||||
|
||||
class Output(BlockSchema):
|
||||
# Common Outputs that user commonly uses
|
||||
ids : list[str] = SchemaField(description="All Tweet IDs")
|
||||
texts : list[str] = SchemaField(description="All Tweet texts")
|
||||
userIds: list[str] = SchemaField(description="List of user ids that authored the tweets")
|
||||
userNames: list[str] = SchemaField(description="List of user names that authored the tweets")
|
||||
ids: list[str] = SchemaField(description="All Tweet IDs")
|
||||
texts: list[str] = SchemaField(description="All Tweet texts")
|
||||
userIds: list[str] = SchemaField(
|
||||
description="List of user ids that authored the tweets"
|
||||
)
|
||||
userNames: list[str] = SchemaField(
|
||||
description="List of user names that authored the tweets"
|
||||
)
|
||||
|
||||
# Complete Outputs for advanced use
|
||||
data: list[dict] = SchemaField(description="Complete Tweet data")
|
||||
included: dict = SchemaField(description="Additional data that you have requested (Optional) via Expansions field")
|
||||
included: dict = SchemaField(
|
||||
description="Additional data that you have requested (Optional) via Expansions field"
|
||||
)
|
||||
meta: dict = SchemaField(description="Metadata about the tweets")
|
||||
|
||||
error: str = SchemaField(description="Error message if the request failed")
|
||||
@@ -214,7 +234,7 @@ class TwitterGetTweetsBlock(Block):
|
||||
"place_fields": [],
|
||||
"poll_fields": [],
|
||||
"tweet_fields": [],
|
||||
"user_fields": []
|
||||
"user_fields": [],
|
||||
},
|
||||
test_credentials=TEST_CREDENTIALS,
|
||||
test_output=[
|
||||
@@ -224,14 +244,14 @@ class TwitterGetTweetsBlock(Block):
|
||||
("userNames", ["testuser1"]),
|
||||
("data", [{"id": "1460323737035677698", "text": "Test tweet content"}]),
|
||||
("included", {"users": [{"id": "67890", "username": "testuser1"}]}),
|
||||
("meta", {"result_count": 1})
|
||||
("meta", {"result_count": 1}),
|
||||
],
|
||||
test_mock={
|
||||
"get_tweets": lambda *args, **kwargs: ({
|
||||
"id": "1460323737035677698",
|
||||
"text": "Test tweet content"
|
||||
}, {})
|
||||
}
|
||||
"get_tweets": lambda *args, **kwargs: (
|
||||
{"id": "1460323737035677698", "text": "Test tweet content"},
|
||||
{},
|
||||
)
|
||||
},
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
@@ -243,23 +263,25 @@ class TwitterGetTweetsBlock(Block):
|
||||
place_fields: list[TweetPlaceFields],
|
||||
poll_fields: list[TweetPollFields],
|
||||
tweet_fields: list[TweetFields],
|
||||
user_fields: list[TweetUserFields]
|
||||
user_fields: list[TweetUserFields],
|
||||
):
|
||||
try:
|
||||
client = tweepy.Client(
|
||||
bearer_token=credentials.access_token.get_secret_value()
|
||||
)
|
||||
params = {"ids": tweet_ids,"user_auth": False}
|
||||
params = {"ids": tweet_ids, "user_auth": False}
|
||||
|
||||
# Adding expansions to params If required by the user
|
||||
params = (TweetExpansionsBuilder(params)
|
||||
params = (
|
||||
TweetExpansionsBuilder(params)
|
||||
.add_expansions(expansions)
|
||||
.add_media_fields(media_fields)
|
||||
.add_place_fields(place_fields)
|
||||
.add_poll_fields(poll_fields)
|
||||
.add_tweet_fields(tweet_fields)
|
||||
.add_user_fields(user_fields)
|
||||
.build())
|
||||
.build()
|
||||
)
|
||||
|
||||
response = cast(Response, client.get_tweets(**params))
|
||||
|
||||
@@ -308,7 +330,7 @@ class TwitterGetTweetsBlock(Block):
|
||||
input_data.place_fields,
|
||||
input_data.poll_fields,
|
||||
input_data.tweet_fields,
|
||||
input_data.user_fields
|
||||
input_data.user_fields,
|
||||
)
|
||||
if ids:
|
||||
yield "ids", ids
|
||||
|
||||
@@ -1,14 +1,8 @@
|
||||
from typing import cast
|
||||
|
||||
from backend.blocks.twitter._serializer import IncludesSerializer
|
||||
import tweepy
|
||||
from tweepy.client import Response
|
||||
|
||||
from backend.blocks.twitter._types import TweetFields, TweetUserFields, UserExpansionInputs, UserExpansions
|
||||
from backend.blocks.twitter.tweepy_exceptions import handle_tweepy_exception
|
||||
from backend.data.block import Block, BlockCategory, BlockOutput, BlockSchema
|
||||
from backend.data.model import SchemaField
|
||||
from backend.blocks.twitter._builders import UserExpansionsBuilder
|
||||
from backend.blocks.twitter._auth import (
|
||||
TEST_CREDENTIALS,
|
||||
TEST_CREDENTIALS_INPUT,
|
||||
@@ -16,6 +10,18 @@ from backend.blocks.twitter._auth import (
|
||||
TwitterCredentialsField,
|
||||
TwitterCredentialsInput,
|
||||
)
|
||||
from backend.blocks.twitter._builders import UserExpansionsBuilder
|
||||
from backend.blocks.twitter._serializer import IncludesSerializer
|
||||
from backend.blocks.twitter._types import (
|
||||
TweetFields,
|
||||
TweetUserFields,
|
||||
UserExpansionInputs,
|
||||
UserExpansions,
|
||||
)
|
||||
from backend.blocks.twitter.tweepy_exceptions import handle_tweepy_exception
|
||||
from backend.data.block import Block, BlockCategory, BlockOutput, BlockSchema
|
||||
from backend.data.model import SchemaField
|
||||
|
||||
|
||||
class TwitterUnblockUserBlock(Block):
|
||||
"""
|
||||
@@ -29,7 +35,7 @@ class TwitterUnblockUserBlock(Block):
|
||||
|
||||
target_user_id: str = SchemaField(
|
||||
description="The user ID of the user that you would like to unblock",
|
||||
placeholder="Enter target user ID"
|
||||
placeholder="Enter target user ID",
|
||||
)
|
||||
|
||||
class Output(BlockSchema):
|
||||
@@ -45,7 +51,7 @@ class TwitterUnblockUserBlock(Block):
|
||||
output_schema=TwitterUnblockUserBlock.Output,
|
||||
test_input={
|
||||
"target_user_id": "12345",
|
||||
"credentials": TEST_CREDENTIALS_INPUT
|
||||
"credentials": TEST_CREDENTIALS_INPUT,
|
||||
},
|
||||
test_credentials=TEST_CREDENTIALS,
|
||||
test_output=[
|
||||
@@ -54,20 +60,13 @@ class TwitterUnblockUserBlock(Block):
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def unblock_user(
|
||||
credentials: TwitterCredentials,
|
||||
target_user_id: str
|
||||
):
|
||||
def unblock_user(credentials: TwitterCredentials, target_user_id: str):
|
||||
try:
|
||||
client = tweepy.Client(
|
||||
bearer_token=credentials.access_token.get_secret_value()
|
||||
)
|
||||
|
||||
client.unblock(
|
||||
target_user_id=target_user_id,
|
||||
user_auth=False
|
||||
)
|
||||
|
||||
client.unblock(target_user_id=target_user_id, user_auth=False)
|
||||
|
||||
return True
|
||||
|
||||
@@ -82,14 +81,12 @@ class TwitterUnblockUserBlock(Block):
|
||||
**kwargs,
|
||||
) -> BlockOutput:
|
||||
try:
|
||||
success = self.unblock_user(
|
||||
credentials,
|
||||
input_data.target_user_id
|
||||
)
|
||||
success = self.unblock_user(credentials, input_data.target_user_id)
|
||||
yield "success", success
|
||||
except Exception as e:
|
||||
yield "error", handle_tweepy_exception(e)
|
||||
|
||||
|
||||
class TwitterGetBlockedUsersBlock(Block):
|
||||
"""
|
||||
Get a list of users who are blocked by the authenticating user
|
||||
@@ -104,20 +101,22 @@ class TwitterGetBlockedUsersBlock(Block):
|
||||
description="Maximum number of results to return (1-1000, default 100)",
|
||||
placeholder="Enter max results",
|
||||
default=10,
|
||||
advanced=True
|
||||
advanced=True,
|
||||
)
|
||||
|
||||
pagination_token: str = SchemaField(
|
||||
description="Token for retrieving next/previous page of results",
|
||||
placeholder="Enter pagination token",
|
||||
default="",
|
||||
advanced=True
|
||||
advanced=True,
|
||||
)
|
||||
|
||||
class Output(BlockSchema):
|
||||
user_ids: list[str] = SchemaField(description="List of blocked user IDs")
|
||||
usernames_: list[str] = SchemaField(description="List of blocked usernames")
|
||||
included: dict = SchemaField(description="Additional data requested via expansions")
|
||||
included: dict = SchemaField(
|
||||
description="Additional data requested via expansions"
|
||||
)
|
||||
meta: dict = SchemaField(description="Metadata including pagination info")
|
||||
next_token: str = SchemaField(description="Next token for pagination")
|
||||
error: str = SchemaField(description="Error message if the request failed")
|
||||
@@ -135,7 +134,7 @@ class TwitterGetBlockedUsersBlock(Block):
|
||||
"credentials": TEST_CREDENTIALS_INPUT,
|
||||
"expansions": [],
|
||||
"tweet_fields": [],
|
||||
"user_fields": []
|
||||
"user_fields": [],
|
||||
},
|
||||
test_credentials=TEST_CREDENTIALS,
|
||||
test_output=[
|
||||
@@ -143,7 +142,7 @@ class TwitterGetBlockedUsersBlock(Block):
|
||||
("usernames_", ["testuser1", "testuser2"]),
|
||||
("included", {}),
|
||||
("meta", {"next_token": "next_token_value"}),
|
||||
("next_token", "next_token_value")
|
||||
("next_token", "next_token_value"),
|
||||
],
|
||||
)
|
||||
|
||||
@@ -163,23 +162,22 @@ class TwitterGetBlockedUsersBlock(Block):
|
||||
|
||||
params = {
|
||||
"max_results": max_results,
|
||||
"pagination_token": None if pagination_token == "" else pagination_token,
|
||||
"user_auth": False
|
||||
"pagination_token": (
|
||||
None if pagination_token == "" else pagination_token
|
||||
),
|
||||
"user_auth": False,
|
||||
}
|
||||
|
||||
params = (UserExpansionsBuilder(params)
|
||||
.add_expansions(expansions)
|
||||
.add_tweet_fields(tweet_fields)
|
||||
.add_user_fields(user_fields)
|
||||
.build())
|
||||
|
||||
response = cast(
|
||||
Response,
|
||||
client.get_blocked(
|
||||
**params
|
||||
)
|
||||
params = (
|
||||
UserExpansionsBuilder(params)
|
||||
.add_expansions(expansions)
|
||||
.add_tweet_fields(tweet_fields)
|
||||
.add_user_fields(user_fields)
|
||||
.build()
|
||||
)
|
||||
|
||||
response = cast(Response, client.get_blocked(**params))
|
||||
|
||||
meta = {}
|
||||
user_ids = []
|
||||
usernames = []
|
||||
@@ -219,7 +217,7 @@ class TwitterGetBlockedUsersBlock(Block):
|
||||
input_data.pagination_token,
|
||||
input_data.expansions,
|
||||
input_data.tweet_fields,
|
||||
input_data.user_fields
|
||||
input_data.user_fields,
|
||||
)
|
||||
if user_ids:
|
||||
yield "user_ids", user_ids
|
||||
@@ -234,6 +232,7 @@ class TwitterGetBlockedUsersBlock(Block):
|
||||
except Exception as e:
|
||||
yield "error", handle_tweepy_exception(e)
|
||||
|
||||
|
||||
class TwitterBlockUserBlock(Block):
|
||||
"""
|
||||
Block a specific user on Twitter
|
||||
@@ -246,7 +245,7 @@ class TwitterBlockUserBlock(Block):
|
||||
|
||||
target_user_id: str = SchemaField(
|
||||
description="The user ID of the user that you would like to block",
|
||||
placeholder="Enter target user ID"
|
||||
placeholder="Enter target user ID",
|
||||
)
|
||||
|
||||
class Output(BlockSchema):
|
||||
@@ -262,7 +261,7 @@ class TwitterBlockUserBlock(Block):
|
||||
output_schema=TwitterBlockUserBlock.Output,
|
||||
test_input={
|
||||
"target_user_id": "12345",
|
||||
"credentials": TEST_CREDENTIALS_INPUT
|
||||
"credentials": TEST_CREDENTIALS_INPUT,
|
||||
},
|
||||
test_credentials=TEST_CREDENTIALS,
|
||||
test_output=[
|
||||
@@ -271,16 +270,13 @@ class TwitterBlockUserBlock(Block):
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def block_user(
|
||||
credentials: TwitterCredentials,
|
||||
target_user_id: str
|
||||
):
|
||||
def block_user(credentials: TwitterCredentials, target_user_id: str):
|
||||
try:
|
||||
client = tweepy.Client(
|
||||
bearer_token=credentials.access_token.get_secret_value()
|
||||
)
|
||||
|
||||
client.block(target_user_id=target_user_id,user_auth=False)
|
||||
client.block(target_user_id=target_user_id, user_auth=False)
|
||||
|
||||
return True
|
||||
|
||||
@@ -295,10 +291,7 @@ class TwitterBlockUserBlock(Block):
|
||||
**kwargs,
|
||||
) -> BlockOutput:
|
||||
try:
|
||||
success = self.block_user(
|
||||
credentials,
|
||||
input_data.target_user_id
|
||||
)
|
||||
success = self.block_user(credentials, input_data.target_user_id)
|
||||
yield "success", success
|
||||
except Exception as e:
|
||||
yield "error", handle_tweepy_exception(e)
|
||||
|
||||
@@ -1,14 +1,8 @@
|
||||
from typing import cast
|
||||
|
||||
from backend.blocks.twitter._serializer import IncludesSerializer, ResponseDataSerializer
|
||||
import tweepy
|
||||
from tweepy.client import Response
|
||||
|
||||
from backend.data.block import Block, BlockCategory, BlockOutput, BlockSchema
|
||||
from backend.data.model import SchemaField
|
||||
from backend.blocks.twitter._builders import UserExpansionsBuilder
|
||||
from backend.blocks.twitter._types import TweetUserFields, TweetFields, UserExpansionInputs, UserExpansions
|
||||
from backend.blocks.twitter.tweepy_exceptions import handle_tweepy_exception
|
||||
from backend.blocks.twitter._auth import (
|
||||
TEST_CREDENTIALS,
|
||||
TEST_CREDENTIALS_INPUT,
|
||||
@@ -16,6 +10,21 @@ from backend.blocks.twitter._auth import (
|
||||
TwitterCredentialsField,
|
||||
TwitterCredentialsInput,
|
||||
)
|
||||
from backend.blocks.twitter._builders import UserExpansionsBuilder
|
||||
from backend.blocks.twitter._serializer import (
|
||||
IncludesSerializer,
|
||||
ResponseDataSerializer,
|
||||
)
|
||||
from backend.blocks.twitter._types import (
|
||||
TweetFields,
|
||||
TweetUserFields,
|
||||
UserExpansionInputs,
|
||||
UserExpansions,
|
||||
)
|
||||
from backend.blocks.twitter.tweepy_exceptions import handle_tweepy_exception
|
||||
from backend.data.block import Block, BlockCategory, BlockOutput, BlockSchema
|
||||
from backend.data.model import SchemaField
|
||||
|
||||
|
||||
class TwitterUnfollowUserBlock(Block):
|
||||
"""
|
||||
@@ -24,16 +33,18 @@ class TwitterUnfollowUserBlock(Block):
|
||||
|
||||
class Input(BlockSchema):
|
||||
credentials: TwitterCredentialsInput = TwitterCredentialsField(
|
||||
["users.read", "users.write","follows.write", "offline.access"]
|
||||
["users.read", "users.write", "follows.write", "offline.access"]
|
||||
)
|
||||
|
||||
target_user_id: str = SchemaField(
|
||||
description="The user ID of the user that you would like to unfollow",
|
||||
placeholder="Enter target user ID"
|
||||
placeholder="Enter target user ID",
|
||||
)
|
||||
|
||||
class Output(BlockSchema):
|
||||
success: bool = SchemaField(description="Whether the unfollow action was successful")
|
||||
success: bool = SchemaField(
|
||||
description="Whether the unfollow action was successful"
|
||||
)
|
||||
error: str = SchemaField(description="Error message if the request failed")
|
||||
|
||||
def __init__(self):
|
||||
@@ -45,7 +56,7 @@ class TwitterUnfollowUserBlock(Block):
|
||||
output_schema=TwitterUnfollowUserBlock.Output,
|
||||
test_input={
|
||||
"target_user_id": "12345",
|
||||
"credentials": TEST_CREDENTIALS_INPUT
|
||||
"credentials": TEST_CREDENTIALS_INPUT,
|
||||
},
|
||||
test_credentials=TEST_CREDENTIALS,
|
||||
test_output=[
|
||||
@@ -54,16 +65,13 @@ class TwitterUnfollowUserBlock(Block):
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def unfollow_user(
|
||||
credentials: TwitterCredentials,
|
||||
target_user_id: str
|
||||
):
|
||||
def unfollow_user(credentials: TwitterCredentials, target_user_id: str):
|
||||
try:
|
||||
client = tweepy.Client(
|
||||
bearer_token=credentials.access_token.get_secret_value()
|
||||
)
|
||||
|
||||
client.unfollow_user(target_user_id=target_user_id,user_auth=False)
|
||||
client.unfollow_user(target_user_id=target_user_id, user_auth=False)
|
||||
|
||||
return True
|
||||
|
||||
@@ -78,15 +86,13 @@ class TwitterUnfollowUserBlock(Block):
|
||||
**kwargs,
|
||||
) -> BlockOutput:
|
||||
try:
|
||||
success = self.unfollow_user(
|
||||
credentials,
|
||||
input_data.target_user_id
|
||||
)
|
||||
success = self.unfollow_user(credentials, input_data.target_user_id)
|
||||
yield "success", success
|
||||
|
||||
except Exception as e:
|
||||
yield "error", handle_tweepy_exception(e)
|
||||
|
||||
|
||||
class TwitterFollowUserBlock(Block):
|
||||
"""
|
||||
Allows a user to follow another user specified by target user ID
|
||||
@@ -94,16 +100,18 @@ class TwitterFollowUserBlock(Block):
|
||||
|
||||
class Input(BlockSchema):
|
||||
credentials: TwitterCredentialsInput = TwitterCredentialsField(
|
||||
["users.read", "users.write","follows.write", "offline.access"]
|
||||
["users.read", "users.write", "follows.write", "offline.access"]
|
||||
)
|
||||
|
||||
target_user_id: str = SchemaField(
|
||||
description="The user ID of the user that you would like to follow",
|
||||
placeholder="Enter target user ID"
|
||||
placeholder="Enter target user ID",
|
||||
)
|
||||
|
||||
class Output(BlockSchema):
|
||||
success: bool = SchemaField(description="Whether the follow action was successful")
|
||||
success: bool = SchemaField(
|
||||
description="Whether the follow action was successful"
|
||||
)
|
||||
error: str = SchemaField(description="Error message if the request failed")
|
||||
|
||||
def __init__(self):
|
||||
@@ -115,26 +123,20 @@ class TwitterFollowUserBlock(Block):
|
||||
output_schema=TwitterFollowUserBlock.Output,
|
||||
test_input={
|
||||
"target_user_id": "12345",
|
||||
"credentials": TEST_CREDENTIALS_INPUT
|
||||
"credentials": TEST_CREDENTIALS_INPUT,
|
||||
},
|
||||
test_credentials=TEST_CREDENTIALS,
|
||||
test_output=[
|
||||
("success", True),
|
||||
("error", "")
|
||||
],
|
||||
test_output=[("success", True), ("error", "")],
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def follow_user(
|
||||
credentials: TwitterCredentials,
|
||||
target_user_id: str
|
||||
):
|
||||
def follow_user(credentials: TwitterCredentials, target_user_id: str):
|
||||
try:
|
||||
client = tweepy.Client(
|
||||
bearer_token=credentials.access_token.get_secret_value()
|
||||
)
|
||||
|
||||
client.follow_user(target_user_id=target_user_id,user_auth=False)
|
||||
client.follow_user(target_user_id=target_user_id, user_auth=False)
|
||||
|
||||
return True
|
||||
|
||||
@@ -149,15 +151,13 @@ class TwitterFollowUserBlock(Block):
|
||||
**kwargs,
|
||||
) -> BlockOutput:
|
||||
try:
|
||||
success = self.follow_user(
|
||||
credentials,
|
||||
input_data.target_user_id
|
||||
)
|
||||
success = self.follow_user(credentials, input_data.target_user_id)
|
||||
yield "success", success
|
||||
|
||||
except Exception as e:
|
||||
yield "error", handle_tweepy_exception(e)
|
||||
|
||||
|
||||
class TwitterGetFollowersBlock(Block):
|
||||
"""
|
||||
Retrieves a list of followers for a specified Twitter user ID
|
||||
@@ -165,26 +165,26 @@ class TwitterGetFollowersBlock(Block):
|
||||
|
||||
class Input(UserExpansionInputs):
|
||||
credentials: TwitterCredentialsInput = TwitterCredentialsField(
|
||||
["users.read", "offline.access","follows.read"]
|
||||
["users.read", "offline.access", "follows.read"]
|
||||
)
|
||||
|
||||
target_user_id: str = SchemaField(
|
||||
description="The user ID whose followers you would like to retrieve",
|
||||
placeholder="Enter target user ID"
|
||||
placeholder="Enter target user ID",
|
||||
)
|
||||
|
||||
max_results: int = SchemaField(
|
||||
description="Maximum number of results to return (1-1000, default 100)",
|
||||
placeholder="Enter max results",
|
||||
default=10,
|
||||
advanced=True
|
||||
advanced=True,
|
||||
)
|
||||
|
||||
pagination_token: str = SchemaField(
|
||||
description="Token for retrieving next/previous page of results",
|
||||
placeholder="Enter pagination token",
|
||||
default="",
|
||||
advanced=True
|
||||
advanced=True,
|
||||
)
|
||||
|
||||
class Output(BlockSchema):
|
||||
@@ -193,7 +193,9 @@ class TwitterGetFollowersBlock(Block):
|
||||
next_token: str = SchemaField(description="Next token for pagination")
|
||||
|
||||
data: list[dict] = SchemaField(description="Complete user data for followers")
|
||||
includes: dict = SchemaField(description="Additional data requested via expansions")
|
||||
includes: dict = SchemaField(
|
||||
description="Additional data requested via expansions"
|
||||
)
|
||||
meta: dict = SchemaField(description="Metadata including pagination info")
|
||||
|
||||
error: str = SchemaField(description="Error message if the request failed")
|
||||
@@ -212,7 +214,7 @@ class TwitterGetFollowersBlock(Block):
|
||||
"expansions": [],
|
||||
"tweet_fields": [],
|
||||
"user_fields": [],
|
||||
"credentials": TEST_CREDENTIALS_INPUT
|
||||
"credentials": TEST_CREDENTIALS_INPUT,
|
||||
},
|
||||
test_credentials=TEST_CREDENTIALS,
|
||||
test_output=[
|
||||
@@ -221,7 +223,7 @@ class TwitterGetFollowersBlock(Block):
|
||||
("data", [{"id": "1234567890", "username": "testuser"}]),
|
||||
("includes", {}),
|
||||
("meta", {"result_count": 1}),
|
||||
("next_token", "next_token_value")
|
||||
("next_token", "next_token_value"),
|
||||
],
|
||||
test_mock={
|
||||
"get_followers": lambda *args, **kwargs: (
|
||||
@@ -230,9 +232,9 @@ class TwitterGetFollowersBlock(Block):
|
||||
[{"id": "1234567890", "username": "testuser"}],
|
||||
{},
|
||||
{"result_count": 1},
|
||||
"next_token_value"
|
||||
"next_token_value",
|
||||
)
|
||||
}
|
||||
},
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
@@ -253,23 +255,22 @@ class TwitterGetFollowersBlock(Block):
|
||||
params = {
|
||||
"id": target_user_id,
|
||||
"max_results": max_results,
|
||||
"pagination_token": None if pagination_token == "" else pagination_token,
|
||||
"user_auth": False
|
||||
"pagination_token": (
|
||||
None if pagination_token == "" else pagination_token
|
||||
),
|
||||
"user_auth": False,
|
||||
}
|
||||
|
||||
params = (UserExpansionsBuilder(params)
|
||||
.add_expansions(expansions)
|
||||
.add_tweet_fields(tweet_fields)
|
||||
.add_user_fields(user_fields)
|
||||
.build())
|
||||
|
||||
response = cast(
|
||||
Response,
|
||||
client.get_users_followers(
|
||||
**params
|
||||
)
|
||||
params = (
|
||||
UserExpansionsBuilder(params)
|
||||
.add_expansions(expansions)
|
||||
.add_tweet_fields(tweet_fields)
|
||||
.add_user_fields(user_fields)
|
||||
.build()
|
||||
)
|
||||
|
||||
response = cast(Response, client.get_users_followers(**params))
|
||||
|
||||
meta = {}
|
||||
follower_ids = []
|
||||
follower_usernames = []
|
||||
@@ -286,7 +287,14 @@ class TwitterGetFollowersBlock(Block):
|
||||
follower_ids = [str(user.id) for user in response.data]
|
||||
follower_usernames = [user.username for user in response.data]
|
||||
|
||||
return follower_ids, follower_usernames, data, included, meta, next_token
|
||||
return (
|
||||
follower_ids,
|
||||
follower_usernames,
|
||||
data,
|
||||
included,
|
||||
meta,
|
||||
next_token,
|
||||
)
|
||||
|
||||
raise Exception("Followers not found")
|
||||
|
||||
@@ -308,7 +316,7 @@ class TwitterGetFollowersBlock(Block):
|
||||
input_data.pagination_token,
|
||||
input_data.expansions,
|
||||
input_data.tweet_fields,
|
||||
input_data.user_fields
|
||||
input_data.user_fields,
|
||||
)
|
||||
if ids:
|
||||
yield "ids", ids
|
||||
@@ -325,6 +333,7 @@ class TwitterGetFollowersBlock(Block):
|
||||
except Exception as e:
|
||||
yield "error", handle_tweepy_exception(e)
|
||||
|
||||
|
||||
class TwitterGetFollowingBlock(Block):
|
||||
"""
|
||||
Retrieves a list of users that a specified Twitter user ID is following
|
||||
@@ -332,26 +341,26 @@ class TwitterGetFollowingBlock(Block):
|
||||
|
||||
class Input(UserExpansionInputs):
|
||||
credentials: TwitterCredentialsInput = TwitterCredentialsField(
|
||||
["users.read", "offline.access","follows.read"]
|
||||
["users.read", "offline.access", "follows.read"]
|
||||
)
|
||||
|
||||
target_user_id: str = SchemaField(
|
||||
description="The user ID whose following you would like to retrieve",
|
||||
placeholder="Enter target user ID"
|
||||
placeholder="Enter target user ID",
|
||||
)
|
||||
|
||||
max_results: int = SchemaField(
|
||||
description="Maximum number of results to return (1-1000, default 100)",
|
||||
placeholder="Enter max results",
|
||||
default=10,
|
||||
advanced=True
|
||||
advanced=True,
|
||||
)
|
||||
|
||||
pagination_token: str = SchemaField(
|
||||
description="Token for retrieving next/previous page of results",
|
||||
placeholder="Enter pagination token",
|
||||
default="",
|
||||
advanced=True
|
||||
advanced=True,
|
||||
)
|
||||
|
||||
class Output(BlockSchema):
|
||||
@@ -360,7 +369,9 @@ class TwitterGetFollowingBlock(Block):
|
||||
next_token: str = SchemaField(description="Next token for pagination")
|
||||
|
||||
data: list[dict] = SchemaField(description="Complete user data for following")
|
||||
includes: dict = SchemaField(description="Additional data requested via expansions")
|
||||
includes: dict = SchemaField(
|
||||
description="Additional data requested via expansions"
|
||||
)
|
||||
meta: dict = SchemaField(description="Metadata including pagination info")
|
||||
|
||||
error: str = SchemaField(description="Error message if the request failed")
|
||||
@@ -379,7 +390,7 @@ class TwitterGetFollowingBlock(Block):
|
||||
"expansions": [],
|
||||
"tweet_fields": [],
|
||||
"user_fields": [],
|
||||
"credentials": TEST_CREDENTIALS_INPUT
|
||||
"credentials": TEST_CREDENTIALS_INPUT,
|
||||
},
|
||||
test_credentials=TEST_CREDENTIALS,
|
||||
test_output=[
|
||||
@@ -388,7 +399,7 @@ class TwitterGetFollowingBlock(Block):
|
||||
("data", [{"id": "1234567890", "username": "testuser"}]),
|
||||
("includes", {}),
|
||||
("meta", {"result_count": 1}),
|
||||
("next_token", "next_token_value")
|
||||
("next_token", "next_token_value"),
|
||||
],
|
||||
test_mock={
|
||||
"get_following": lambda *args, **kwargs: (
|
||||
@@ -397,9 +408,9 @@ class TwitterGetFollowingBlock(Block):
|
||||
[{"id": "1234567890", "username": "testuser"}],
|
||||
{},
|
||||
{"result_count": 1},
|
||||
"next_token_value"
|
||||
"next_token_value",
|
||||
)
|
||||
}
|
||||
},
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
@@ -420,23 +431,22 @@ class TwitterGetFollowingBlock(Block):
|
||||
params = {
|
||||
"id": target_user_id,
|
||||
"max_results": max_results,
|
||||
"pagination_token": None if pagination_token == "" else pagination_token,
|
||||
"user_auth": False
|
||||
"pagination_token": (
|
||||
None if pagination_token == "" else pagination_token
|
||||
),
|
||||
"user_auth": False,
|
||||
}
|
||||
|
||||
params = (UserExpansionsBuilder(params)
|
||||
.add_expansions(expansions)
|
||||
.add_tweet_fields(tweet_fields)
|
||||
.add_user_fields(user_fields)
|
||||
.build())
|
||||
|
||||
response = cast(
|
||||
Response,
|
||||
client.get_users_following(
|
||||
**params
|
||||
)
|
||||
params = (
|
||||
UserExpansionsBuilder(params)
|
||||
.add_expansions(expansions)
|
||||
.add_tweet_fields(tweet_fields)
|
||||
.add_user_fields(user_fields)
|
||||
.build()
|
||||
)
|
||||
|
||||
response = cast(Response, client.get_users_following(**params))
|
||||
|
||||
meta = {}
|
||||
following_ids = []
|
||||
following_usernames = []
|
||||
@@ -453,7 +463,14 @@ class TwitterGetFollowingBlock(Block):
|
||||
following_ids = [str(user.id) for user in response.data]
|
||||
following_usernames = [user.username for user in response.data]
|
||||
|
||||
return following_ids, following_usernames, data, included, meta, next_token
|
||||
return (
|
||||
following_ids,
|
||||
following_usernames,
|
||||
data,
|
||||
included,
|
||||
meta,
|
||||
next_token,
|
||||
)
|
||||
|
||||
raise Exception("Following not found")
|
||||
|
||||
@@ -475,7 +492,7 @@ class TwitterGetFollowingBlock(Block):
|
||||
input_data.pagination_token,
|
||||
input_data.expansions,
|
||||
input_data.tweet_fields,
|
||||
input_data.user_fields
|
||||
input_data.user_fields,
|
||||
)
|
||||
if ids:
|
||||
yield "ids", ids
|
||||
|
||||
@@ -1,14 +1,8 @@
|
||||
from typing import cast
|
||||
|
||||
from backend.blocks.twitter._serializer import IncludesSerializer, ResponseDataSerializer
|
||||
import tweepy
|
||||
from tweepy.client import Response
|
||||
|
||||
from backend.data.block import Block, BlockCategory, BlockOutput, BlockSchema
|
||||
from backend.data.model import SchemaField
|
||||
from backend.blocks.twitter._builders import UserExpansionsBuilder
|
||||
from backend.blocks.twitter._types import TweetFields, TweetUserFields, UserExpansionInputs, UserExpansions
|
||||
from backend.blocks.twitter.tweepy_exceptions import handle_tweepy_exception
|
||||
from backend.blocks.twitter._auth import (
|
||||
TEST_CREDENTIALS,
|
||||
TEST_CREDENTIALS_INPUT,
|
||||
@@ -16,6 +10,21 @@ from backend.blocks.twitter._auth import (
|
||||
TwitterCredentialsField,
|
||||
TwitterCredentialsInput,
|
||||
)
|
||||
from backend.blocks.twitter._builders import UserExpansionsBuilder
|
||||
from backend.blocks.twitter._serializer import (
|
||||
IncludesSerializer,
|
||||
ResponseDataSerializer,
|
||||
)
|
||||
from backend.blocks.twitter._types import (
|
||||
TweetFields,
|
||||
TweetUserFields,
|
||||
UserExpansionInputs,
|
||||
UserExpansions,
|
||||
)
|
||||
from backend.blocks.twitter.tweepy_exceptions import handle_tweepy_exception
|
||||
from backend.data.block import Block, BlockCategory, BlockOutput, BlockSchema
|
||||
from backend.data.model import SchemaField
|
||||
|
||||
|
||||
class TwitterUnmuteUserBlock(Block):
|
||||
"""
|
||||
@@ -29,11 +38,13 @@ class TwitterUnmuteUserBlock(Block):
|
||||
|
||||
target_user_id: str = SchemaField(
|
||||
description="The user ID of the user that you would like to unmute",
|
||||
placeholder="Enter target user ID"
|
||||
placeholder="Enter target user ID",
|
||||
)
|
||||
|
||||
class Output(BlockSchema):
|
||||
success: bool = SchemaField(description="Whether the unmute action was successful")
|
||||
success: bool = SchemaField(
|
||||
description="Whether the unmute action was successful"
|
||||
)
|
||||
error: str = SchemaField(description="Error message if the request failed")
|
||||
|
||||
def __init__(self):
|
||||
@@ -45,7 +56,7 @@ class TwitterUnmuteUserBlock(Block):
|
||||
output_schema=TwitterUnmuteUserBlock.Output,
|
||||
test_input={
|
||||
"target_user_id": "12345",
|
||||
"credentials": TEST_CREDENTIALS_INPUT
|
||||
"credentials": TEST_CREDENTIALS_INPUT,
|
||||
},
|
||||
test_credentials=TEST_CREDENTIALS,
|
||||
test_output=[
|
||||
@@ -54,16 +65,13 @@ class TwitterUnmuteUserBlock(Block):
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def unmute_user(
|
||||
credentials: TwitterCredentials,
|
||||
target_user_id: str
|
||||
):
|
||||
def unmute_user(credentials: TwitterCredentials, target_user_id: str):
|
||||
try:
|
||||
client = tweepy.Client(
|
||||
bearer_token=credentials.access_token.get_secret_value()
|
||||
)
|
||||
|
||||
client.unmute(target_user_id=target_user_id,user_auth=False)
|
||||
client.unmute(target_user_id=target_user_id, user_auth=False)
|
||||
|
||||
return True
|
||||
|
||||
@@ -78,15 +86,13 @@ class TwitterUnmuteUserBlock(Block):
|
||||
**kwargs,
|
||||
) -> BlockOutput:
|
||||
try:
|
||||
success = self.unmute_user(
|
||||
credentials,
|
||||
input_data.target_user_id
|
||||
)
|
||||
success = self.unmute_user(credentials, input_data.target_user_id)
|
||||
yield "success", success
|
||||
|
||||
except Exception as e:
|
||||
yield "error", handle_tweepy_exception(e)
|
||||
|
||||
|
||||
class TwitterGetMutedUsersBlock(Block):
|
||||
"""
|
||||
Returns a list of users who are muted by the authenticating user
|
||||
@@ -101,14 +107,14 @@ class TwitterGetMutedUsersBlock(Block):
|
||||
description="The maximum number of results to be returned per page (1-1000). Default is 100.",
|
||||
placeholder="Enter max results",
|
||||
default=10,
|
||||
advanced=True
|
||||
advanced=True,
|
||||
)
|
||||
|
||||
pagination_token: str = SchemaField(
|
||||
description="Token to request next/previous page of results",
|
||||
placeholder="Enter pagination token",
|
||||
default="",
|
||||
advanced=True
|
||||
advanced=True,
|
||||
)
|
||||
|
||||
class Output(BlockSchema):
|
||||
@@ -117,7 +123,9 @@ class TwitterGetMutedUsersBlock(Block):
|
||||
next_token: str = SchemaField(description="Next token for pagination")
|
||||
|
||||
data: list[dict] = SchemaField(description="Complete user data for muted users")
|
||||
includes: dict = SchemaField(description="Additional data requested via expansions")
|
||||
includes: dict = SchemaField(
|
||||
description="Additional data requested via expansions"
|
||||
)
|
||||
meta: dict = SchemaField(description="Metadata including pagination info")
|
||||
|
||||
error: str = SchemaField(description="Error message if the request failed")
|
||||
@@ -135,30 +143,36 @@ class TwitterGetMutedUsersBlock(Block):
|
||||
"credentials": TEST_CREDENTIALS_INPUT,
|
||||
"expansions": [],
|
||||
"tweet_fields": [],
|
||||
"user_fields": []
|
||||
"user_fields": [],
|
||||
},
|
||||
test_credentials=TEST_CREDENTIALS,
|
||||
test_output=[
|
||||
("ids", ["12345", "67890"]),
|
||||
("usernames", ["testuser1", "testuser2"]),
|
||||
("data", [
|
||||
{"id": "12345", "username": "testuser1"},
|
||||
{"id": "67890", "username": "testuser2"}
|
||||
]),
|
||||
(
|
||||
"data",
|
||||
[
|
||||
{"id": "12345", "username": "testuser1"},
|
||||
{"id": "67890", "username": "testuser2"},
|
||||
],
|
||||
),
|
||||
("includes", {}),
|
||||
("meta", {"next_token": "next_token_value"}),
|
||||
("next_token", "next_token_value")
|
||||
("next_token", "next_token_value"),
|
||||
],
|
||||
test_mock={
|
||||
"get_muted_users": lambda *args, **kwargs: (
|
||||
["12345", "67890"],
|
||||
["testuser1", "testuser2"],
|
||||
[{"id": "12345", "username": "testuser1"}, {"id": "67890", "username": "testuser2"}],
|
||||
[
|
||||
{"id": "12345", "username": "testuser1"},
|
||||
{"id": "67890", "username": "testuser2"},
|
||||
],
|
||||
{},
|
||||
{"next_token": "next_token_value"},
|
||||
"next_token_value"
|
||||
"next_token_value",
|
||||
)
|
||||
}
|
||||
},
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
@@ -177,21 +191,22 @@ class TwitterGetMutedUsersBlock(Block):
|
||||
|
||||
params = {
|
||||
"max_results": max_results,
|
||||
"pagination_token": None if pagination_token == "" else pagination_token,
|
||||
"user_auth": False
|
||||
"pagination_token": (
|
||||
None if pagination_token == "" else pagination_token
|
||||
),
|
||||
"user_auth": False,
|
||||
}
|
||||
|
||||
params = (UserExpansionsBuilder(params)
|
||||
.add_expansions(expansions)
|
||||
.add_tweet_fields(tweet_fields)
|
||||
.add_user_fields(user_fields)
|
||||
.build())
|
||||
|
||||
response = cast(
|
||||
Response,
|
||||
client.get_muted(**params)
|
||||
params = (
|
||||
UserExpansionsBuilder(params)
|
||||
.add_expansions(expansions)
|
||||
.add_tweet_fields(tweet_fields)
|
||||
.add_user_fields(user_fields)
|
||||
.build()
|
||||
)
|
||||
|
||||
response = cast(Response, client.get_muted(**params))
|
||||
|
||||
meta = {}
|
||||
user_ids = []
|
||||
usernames = []
|
||||
@@ -229,7 +244,7 @@ class TwitterGetMutedUsersBlock(Block):
|
||||
input_data.pagination_token,
|
||||
input_data.expansions,
|
||||
input_data.tweet_fields,
|
||||
input_data.user_fields
|
||||
input_data.user_fields,
|
||||
)
|
||||
if ids:
|
||||
yield "ids", ids
|
||||
@@ -246,6 +261,7 @@ class TwitterGetMutedUsersBlock(Block):
|
||||
except Exception as e:
|
||||
yield "error", handle_tweepy_exception(e)
|
||||
|
||||
|
||||
class TwitterMuteUserBlock(Block):
|
||||
"""
|
||||
Allows a user to mute another user specified by target user ID
|
||||
@@ -258,11 +274,13 @@ class TwitterMuteUserBlock(Block):
|
||||
|
||||
target_user_id: str = SchemaField(
|
||||
description="The user ID of the user that you would like to mute",
|
||||
placeholder="Enter target user ID"
|
||||
placeholder="Enter target user ID",
|
||||
)
|
||||
|
||||
class Output(BlockSchema):
|
||||
success: bool = SchemaField(description="Whether the mute action was successful")
|
||||
success: bool = SchemaField(
|
||||
description="Whether the mute action was successful"
|
||||
)
|
||||
error: str = SchemaField(description="Error message if the request failed")
|
||||
|
||||
def __init__(self):
|
||||
@@ -274,7 +292,7 @@ class TwitterMuteUserBlock(Block):
|
||||
output_schema=TwitterMuteUserBlock.Output,
|
||||
test_input={
|
||||
"target_user_id": "12345",
|
||||
"credentials": TEST_CREDENTIALS_INPUT
|
||||
"credentials": TEST_CREDENTIALS_INPUT,
|
||||
},
|
||||
test_credentials=TEST_CREDENTIALS,
|
||||
test_output=[
|
||||
@@ -283,16 +301,13 @@ class TwitterMuteUserBlock(Block):
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def mute_user(
|
||||
credentials: TwitterCredentials,
|
||||
target_user_id: str
|
||||
):
|
||||
def mute_user(credentials: TwitterCredentials, target_user_id: str):
|
||||
try:
|
||||
client = tweepy.Client(
|
||||
bearer_token=credentials.access_token.get_secret_value()
|
||||
)
|
||||
|
||||
client.mute(target_user_id=target_user_id,user_auth=False)
|
||||
client.mute(target_user_id=target_user_id, user_auth=False)
|
||||
|
||||
return True
|
||||
|
||||
@@ -307,10 +322,7 @@ class TwitterMuteUserBlock(Block):
|
||||
**kwargs,
|
||||
) -> BlockOutput:
|
||||
try:
|
||||
success = self.mute_user(
|
||||
credentials,
|
||||
input_data.target_user_id
|
||||
)
|
||||
success = self.mute_user(credentials, input_data.target_user_id)
|
||||
yield "success", success
|
||||
except Exception as e:
|
||||
yield "error", handle_tweepy_exception(e)
|
||||
|
||||
@@ -1,14 +1,8 @@
|
||||
from typing import cast
|
||||
|
||||
from backend.blocks.twitter._serializer import IncludesSerializer, ResponseDataSerializer
|
||||
import tweepy
|
||||
from tweepy.client import Response
|
||||
|
||||
from backend.data.block import Block, BlockCategory, BlockOutput, BlockSchema
|
||||
from backend.data.model import SchemaField
|
||||
from backend.blocks.twitter._builders import UserExpansionsBuilder
|
||||
from backend.blocks.twitter._types import TweetFields, TweetUserFields, UserExpansionInputs, UserExpansions
|
||||
from backend.blocks.twitter.tweepy_exceptions import handle_tweepy_exception
|
||||
from backend.blocks.twitter._auth import (
|
||||
TEST_CREDENTIALS,
|
||||
TEST_CREDENTIALS_INPUT,
|
||||
@@ -16,6 +10,21 @@ from backend.blocks.twitter._auth import (
|
||||
TwitterCredentialsField,
|
||||
TwitterCredentialsInput,
|
||||
)
|
||||
from backend.blocks.twitter._builders import UserExpansionsBuilder
|
||||
from backend.blocks.twitter._serializer import (
|
||||
IncludesSerializer,
|
||||
ResponseDataSerializer,
|
||||
)
|
||||
from backend.blocks.twitter._types import (
|
||||
TweetFields,
|
||||
TweetUserFields,
|
||||
UserExpansionInputs,
|
||||
UserExpansions,
|
||||
)
|
||||
from backend.blocks.twitter.tweepy_exceptions import handle_tweepy_exception
|
||||
from backend.data.block import Block, BlockCategory, BlockOutput, BlockSchema
|
||||
from backend.data.model import SchemaField
|
||||
|
||||
|
||||
class TwitterGetUserBlock(Block):
|
||||
"""
|
||||
@@ -27,18 +36,18 @@ class TwitterGetUserBlock(Block):
|
||||
["users.read", "offline.access"]
|
||||
)
|
||||
|
||||
user_id: str = SchemaField(
|
||||
user_id: str = SchemaField(
|
||||
description="The ID of the user to lookup",
|
||||
placeholder="Enter user ID",
|
||||
default="",
|
||||
advanced=False
|
||||
advanced=False,
|
||||
)
|
||||
|
||||
username: str = SchemaField(
|
||||
description="The Twitter username (handle) of the user",
|
||||
placeholder="Enter username",
|
||||
default="",
|
||||
advanced=False
|
||||
advanced=False,
|
||||
)
|
||||
|
||||
class Output(BlockSchema):
|
||||
@@ -49,7 +58,9 @@ class TwitterGetUserBlock(Block):
|
||||
|
||||
# Complete outputs
|
||||
data: dict = SchemaField(description="Complete user data")
|
||||
included: dict = SchemaField(description="Additional data requested via expansions")
|
||||
included: dict = SchemaField(
|
||||
description="Additional data requested via expansions"
|
||||
)
|
||||
error: str = SchemaField(description="Error message if the request failed")
|
||||
|
||||
def __init__(self):
|
||||
@@ -65,16 +76,25 @@ class TwitterGetUserBlock(Block):
|
||||
"credentials": TEST_CREDENTIALS_INPUT,
|
||||
"expansions": [],
|
||||
"tweet_fields": [],
|
||||
"user_fields": []
|
||||
"user_fields": [],
|
||||
},
|
||||
test_credentials=TEST_CREDENTIALS,
|
||||
test_output=[
|
||||
("id", "783214"),
|
||||
("username_", "twitter"),
|
||||
("name_", "Twitter"),
|
||||
("data", {"user": {"id": "783214", "username": "twitter", "name": "Twitter"}}),
|
||||
(
|
||||
"data",
|
||||
{
|
||||
"user": {
|
||||
"id": "783214",
|
||||
"username": "twitter",
|
||||
"name": "Twitter",
|
||||
}
|
||||
},
|
||||
),
|
||||
("included", {}),
|
||||
("error", None)
|
||||
("error", None),
|
||||
],
|
||||
)
|
||||
|
||||
@@ -85,7 +105,7 @@ class TwitterGetUserBlock(Block):
|
||||
username: str,
|
||||
expansions: list[UserExpansions],
|
||||
tweet_fields: list[TweetFields],
|
||||
user_fields: list[TweetUserFields]
|
||||
user_fields: list[TweetUserFields],
|
||||
):
|
||||
try:
|
||||
client = tweepy.Client(
|
||||
@@ -98,18 +118,17 @@ class TwitterGetUserBlock(Block):
|
||||
"user_auth": False,
|
||||
}
|
||||
|
||||
params = (UserExpansionsBuilder(params)
|
||||
.add_expansions(expansions)
|
||||
.add_tweet_fields(tweet_fields)
|
||||
.add_user_fields(user_fields)
|
||||
.build())
|
||||
params = (
|
||||
UserExpansionsBuilder(params)
|
||||
.add_expansions(expansions)
|
||||
.add_tweet_fields(tweet_fields)
|
||||
.add_user_fields(user_fields)
|
||||
.build()
|
||||
)
|
||||
|
||||
print("params : ", params)
|
||||
|
||||
response = cast(
|
||||
Response,
|
||||
client.get_user(**params)
|
||||
)
|
||||
response = cast(Response, client.get_user(**params))
|
||||
|
||||
username = ""
|
||||
id = ""
|
||||
@@ -145,7 +164,7 @@ class TwitterGetUserBlock(Block):
|
||||
input_data.username,
|
||||
input_data.expansions,
|
||||
input_data.tweet_fields,
|
||||
input_data.user_fields
|
||||
input_data.user_fields,
|
||||
)
|
||||
if id:
|
||||
yield "id", id
|
||||
@@ -160,6 +179,7 @@ class TwitterGetUserBlock(Block):
|
||||
except Exception as e:
|
||||
yield "error", handle_tweepy_exception(e)
|
||||
|
||||
|
||||
class TwitterGetUsersBlock(Block):
|
||||
"""
|
||||
Gets information about multiple Twitter users specified by IDs or usernames
|
||||
@@ -174,14 +194,14 @@ class TwitterGetUsersBlock(Block):
|
||||
description="List of user IDs to lookup (max 100)",
|
||||
placeholder="Enter user IDs",
|
||||
default=[],
|
||||
advanced=False
|
||||
advanced=False,
|
||||
)
|
||||
|
||||
usernames: list[str] = SchemaField(
|
||||
description="List of Twitter usernames/handles to lookup (max 100)",
|
||||
placeholder="Enter usernames",
|
||||
default=[],
|
||||
advanced=False
|
||||
advanced=False,
|
||||
)
|
||||
|
||||
class Output(BlockSchema):
|
||||
@@ -192,7 +212,9 @@ class TwitterGetUsersBlock(Block):
|
||||
|
||||
# Complete outputs
|
||||
data: list[dict] = SchemaField(description="Complete users data")
|
||||
included: dict = SchemaField(description="Additional data requested via expansions")
|
||||
included: dict = SchemaField(
|
||||
description="Additional data requested via expansions"
|
||||
)
|
||||
error: str = SchemaField(description="Error message if the request failed")
|
||||
|
||||
def __init__(self):
|
||||
@@ -208,19 +230,28 @@ class TwitterGetUsersBlock(Block):
|
||||
"credentials": TEST_CREDENTIALS_INPUT,
|
||||
"expansions": [],
|
||||
"tweet_fields": [],
|
||||
"user_fields": []
|
||||
"user_fields": [],
|
||||
},
|
||||
test_credentials=TEST_CREDENTIALS,
|
||||
test_output=[
|
||||
("ids", ["783214", "2244994945"]),
|
||||
("usernames_", ["twitter", "twitterdev"]),
|
||||
("names_", ["Twitter", "Twitter Dev"]),
|
||||
("data", {"users": [
|
||||
{"id": "783214", "username": "twitter", "name": "Twitter"},
|
||||
{"id": "2244994945", "username": "twitterdev", "name": "Twitter Dev"}
|
||||
]}),
|
||||
(
|
||||
"data",
|
||||
{
|
||||
"users": [
|
||||
{"id": "783214", "username": "twitter", "name": "Twitter"},
|
||||
{
|
||||
"id": "2244994945",
|
||||
"username": "twitterdev",
|
||||
"name": "Twitter Dev",
|
||||
},
|
||||
]
|
||||
},
|
||||
),
|
||||
("included", {}),
|
||||
("error", None)
|
||||
("error", None),
|
||||
],
|
||||
)
|
||||
|
||||
@@ -231,7 +262,7 @@ class TwitterGetUsersBlock(Block):
|
||||
usernames: list[str],
|
||||
expansions: list[UserExpansions],
|
||||
tweet_fields: list[TweetFields],
|
||||
user_fields: list[TweetUserFields]
|
||||
user_fields: list[TweetUserFields],
|
||||
):
|
||||
try:
|
||||
client = tweepy.Client(
|
||||
@@ -241,20 +272,19 @@ class TwitterGetUsersBlock(Block):
|
||||
params = {
|
||||
"ids": None if not user_ids else user_ids,
|
||||
"usernames": None if not usernames else usernames,
|
||||
"user_auth": False
|
||||
"user_auth": False,
|
||||
}
|
||||
|
||||
params = (UserExpansionsBuilder(params)
|
||||
.add_expansions(expansions)
|
||||
.add_tweet_fields(tweet_fields)
|
||||
.add_user_fields(user_fields)
|
||||
.build())
|
||||
|
||||
response = cast(
|
||||
Response,
|
||||
client.get_users(**params)
|
||||
params = (
|
||||
UserExpansionsBuilder(params)
|
||||
.add_expansions(expansions)
|
||||
.add_tweet_fields(tweet_fields)
|
||||
.add_user_fields(user_fields)
|
||||
.build()
|
||||
)
|
||||
|
||||
response = cast(Response, client.get_users(**params))
|
||||
|
||||
usernames = []
|
||||
ids = []
|
||||
names = []
|
||||
@@ -290,7 +320,7 @@ class TwitterGetUsersBlock(Block):
|
||||
input_data.usernames,
|
||||
input_data.expansions,
|
||||
input_data.tweet_fields,
|
||||
input_data.user_fields
|
||||
input_data.user_fields,
|
||||
)
|
||||
if ids:
|
||||
yield "ids", ids
|
||||
|
||||
@@ -173,8 +173,6 @@ class IntegrationCredentialsStore:
|
||||
|
||||
def update_creds(self, user_id: str, updated: Credentials) -> None:
|
||||
with self.locked_user_integrations(user_id):
|
||||
print("user_id : ", user_id)
|
||||
print("updated : ", updated)
|
||||
current = self.get_creds_by_id(user_id, updated.id)
|
||||
if not current:
|
||||
raise ValueError(
|
||||
|
||||
@@ -4,6 +4,7 @@ from typing import ClassVar, Optional
|
||||
|
||||
import requests
|
||||
from autogpt_libs.supabase_integration_credentials_store import OAuth2Credentials
|
||||
|
||||
from backend.integrations.oauth.base import BaseOAuthHandler
|
||||
|
||||
|
||||
@@ -27,7 +28,7 @@ class TwitterOAuthHandler(BaseOAuthHandler):
|
||||
"block.read",
|
||||
"block.write",
|
||||
"bookmark.read",
|
||||
"bookmark.write"
|
||||
"bookmark.write",
|
||||
]
|
||||
|
||||
AUTHORIZE_URL = "https://twitter.com/i/oauth2/authorize"
|
||||
@@ -121,7 +122,7 @@ class TwitterOAuthHandler(BaseOAuthHandler):
|
||||
|
||||
auth = (self.client_id, self.client_secret)
|
||||
|
||||
response = requests.post(self.TOKEN_URL, headers=header, data=data, auth = auth)
|
||||
response = requests.post(self.TOKEN_URL, headers=header, data=data, auth=auth)
|
||||
|
||||
try:
|
||||
response.raise_for_status()
|
||||
@@ -146,7 +147,6 @@ class TwitterOAuthHandler(BaseOAuthHandler):
|
||||
refresh_token_expires_at=None,
|
||||
)
|
||||
|
||||
|
||||
def revoke_tokens(self, credentials: OAuth2Credentials) -> bool:
|
||||
"""Revoke the access token"""
|
||||
|
||||
@@ -154,12 +154,12 @@ class TwitterOAuthHandler(BaseOAuthHandler):
|
||||
|
||||
data = {
|
||||
"token": credentials.access_token.get_secret_value(),
|
||||
"token_type_hint": "access_token"
|
||||
"token_type_hint": "access_token",
|
||||
}
|
||||
|
||||
auth = (self.client_id, self.client_secret)
|
||||
|
||||
response = requests.post(self.REVOKE_URL,headers=header, data=data, auth=auth)
|
||||
response = requests.post(self.REVOKE_URL, headers=header, data=data, auth=auth)
|
||||
|
||||
try:
|
||||
response.raise_for_status()
|
||||
|
||||
@@ -91,8 +91,9 @@ def callback(
|
||||
) -> CredentialsMetaResponse:
|
||||
logger.debug(f"Received OAuth callback for provider: {provider}")
|
||||
handler = _get_provider_oauth_handler(request, provider)
|
||||
code_verifier = creds_manager.store._get_code_verifier(user_id, provider,state_token)
|
||||
|
||||
code_verifier = creds_manager.store._get_code_verifier(
|
||||
user_id, provider, state_token
|
||||
)
|
||||
|
||||
# Verify the state token
|
||||
if not creds_manager.store.verify_state_token(user_id, state_token, provider):
|
||||
|
||||
Reference in New Issue
Block a user