From 82eed8cef48fad61f5f2f6ff43b450629040c730 Mon Sep 17 00:00:00 2001 From: xberger Date: Wed, 23 Mar 2022 16:32:17 +0100 Subject: [PATCH 1/2] add non-public tweet metrics and misc fields for API v2 --- .../redouane59/twitter/ITwitterClientV2.java | 48 +++ .../redouane59/twitter/TwitterClient.java | 93 +++-- .../twitter/dto/tweet/Attachments.java | 2 + .../redouane59/twitter/dto/tweet/Tweet.java | 159 +++++++++ .../redouane59/twitter/dto/tweet/TweetV1.java | 105 ++++++ .../redouane59/twitter/dto/tweet/TweetV2.java | 328 +++++++++++++++++- .../redouane59/twitter/dto/user/User.java | 14 + .../redouane59/twitter/dto/user/UserV1.java | 13 + .../redouane59/twitter/dto/user/UserV2.java | 22 ++ .../helpers/AbstractRequestHelper.java | 3 + .../twitter/helpers/RequestHelperV2.java | 22 +- 11 files changed, 786 insertions(+), 23 deletions(-) diff --git a/src/main/java/io/github/redouane59/twitter/ITwitterClientV2.java b/src/main/java/io/github/redouane59/twitter/ITwitterClientV2.java index f19b8127..63e1baee 100644 --- a/src/main/java/io/github/redouane59/twitter/ITwitterClientV2.java +++ b/src/main/java/io/github/redouane59/twitter/ITwitterClientV2.java @@ -27,6 +27,15 @@ public interface ITwitterClientV2 { + public static enum REQUEST_TWEET_FIELDS_SCOPE { + /** Retrieve public fields of tweets only (any token)*/ + PUBLIC, + /** Retrieve also non-public fields of tweets (needs user token) */ + NON_PUBLIC, + /** Retrieve non-public and promoted fields of tweets (needs user token, tweet must be promoted or request fails) */ + NON_PUBLIC_PROMOTED + } + /** * Retreive a user from his screen name calling https://api.twitter.com/2/users/ * @@ -96,20 +105,40 @@ public interface ITwitterClientV2 { /** * Get a tweet from its id calling https://api.twitter.com/2/tweets + * with public fields only * * @param tweetId id of the tweet * @return a tweet object */ Tweet getTweet(String tweetId); + + /** + * Get a tweet from its id calling https://api.twitter.com/2/tweets + * with given fields scope + * + * @param tweetId id of the tweet + * @return a tweet object + */ + Tweet getTweet(String tweetId, REQUEST_TWEET_FIELDS_SCOPE requestTweetFieldsScope); /** * Get a tweet list from their id calling https://api.twitter.com/2/tweets + * with public fields only * * @param tweetIds the ids of the tweets * @return a tweet object list */ TweetList getTweets(List tweetIds); + /** + * Get a tweet list from their id calling https://api.twitter.com/2/tweets + * with given fields scope + * + * @param tweetIds the ids of the tweets + * @return a tweet object list + */ + TweetList getTweets(List tweetIds, REQUEST_TWEET_FIELDS_SCOPE requestTweetFieldsScope); + /** * Hide/Unide a reply using https://api.twitter.com/labs/2/tweets/:id/hidden * @@ -289,6 +318,25 @@ public interface ITwitterClientV2 { */ TweetList getUserTimeline(String userId, AdditionalParameters additionalParameters); + /** + * Get the most recent Tweets posted by the user calling https://api.twitter.com/2/users/:id/tweets (time & tweet id arguments can be null) + * + * @param userId identifier of the Twitter account (user ID) for whom to return results. + * @param requestTweetFieldsScope + * @return a TweetList object containing a list of tweets and the next token if recursiveCall is set to false + */ + public TweetList getUserTimeline(final String userId, REQUEST_TWEET_FIELDS_SCOPE requestTweetFieldsScope); + + /** + * Get the most recent Tweets posted by the user calling https://api.twitter.com/2/users/:id/tweets (time & tweet id arguments can be null) + * + * @param userId identifier of the Twitter account (user ID) for whom to return results. + * @param additionalParameters accepted parameters recursiveCall, startTime, endTime, sinceId, untilId, maxResults + * @param requestTweetFieldsScope + * @return a TweetList object containing a list of tweets and the next token if recursiveCall is set to false + */ + public TweetList getUserTimeline(String userId, AdditionalParameters additionalParameters, REQUEST_TWEET_FIELDS_SCOPE requestTweetFieldsScope); + /** * Get the most recent mentions received posted by the user calling https://api.twitter.com/2/users/:id/mentions * diff --git a/src/main/java/io/github/redouane59/twitter/TwitterClient.java b/src/main/java/io/github/redouane59/twitter/TwitterClient.java index 2093ccb9..49870b7c 100644 --- a/src/main/java/io/github/redouane59/twitter/TwitterClient.java +++ b/src/main/java/io/github/redouane59/twitter/TwitterClient.java @@ -102,9 +102,12 @@ public class TwitterClient implements ITwitterClientV1, ITwitterClientV2, ITwitt .setSerializationInclusion(JsonInclude.Include.NON_NULL) .findAndRegisterModules(); public static final String TWEET_FIELDS = "tweet.fields"; - public static final String - ALL_TWEET_FIELDS = - "attachments,author_id,created_at,entities,geo,id,in_reply_to_user_id,lang,possibly_sensitive,public_metrics,referenced_tweets,source,text,withheld,context_annotations,conversation_id,reply_settings"; + public static final String ALL_TWEET_FIELDS_PUBLIC = + "attachments,author_id,created_at,entities,geo,id,in_reply_to_user_id,lang,possibly_sensitive,referenced_tweets,source,text,withheld,context_annotations,conversation_id,reply_settings,public_metrics"; + public static final String ALL_TWEET_FIELDS_NON_PUBLIC = + ALL_TWEET_FIELDS_PUBLIC + ",non_public_metrics,organic_metrics"; + public static final String ALL_TWEET_FIELDS_NON_PUBLIC_PROMOTED = + ALL_TWEET_FIELDS_NON_PUBLIC + ",promoted_metrics"; public static final String EXPANSION = "expansions"; public static final String ALL_EXPANSIONS = @@ -154,7 +157,12 @@ public TwitterClient() { public TwitterClient(TwitterCredentials credentials) { this(credentials, new ServiceBuilder(credentials.getApiKey()).apiSecret(credentials.getApiSecretKey())); } - + + public TwitterClient(TwitterCredentials credentials, boolean useConsumerKey) { + this(credentials, new ServiceBuilder(credentials.getApiKey()).apiSecret(credentials.getApiSecretKey())); + setUseConsumerKey(useConsumerKey); + } + public TwitterClient(TwitterCredentials credentials, HttpClient httpClient) { this(credentials, new ServiceBuilder(credentials.getApiKey()).apiSecret(credentials.getApiSecretKey()).httpClient(httpClient)); @@ -235,6 +243,15 @@ public void setAutomaticRetry(boolean automaticRetry) { requestHelperV2.setAutomaticRetry(automaticRetry); } + /** + * Set the behavior of authentication context used in requests. + * + * @param useConsumerKey Using consumer key for user context if true; or else app-only bearer token. Default is false. + */ + public void setUseConsumerKey(boolean useConsumerKey) { + requestHelperV2.setUseConsumerKey(useConsumerKey); + } + // can manage up to 5000 results / call . Max 15 calls / 15min ==> 75.000 // results max. / 15min private List getUserIdsByRelation(String url) { @@ -515,7 +532,7 @@ public TweetList getLikedTweets(final String userId) { public TweetList getLikedTweets(final String userId, AdditionalParameters additionalParameters) { String url = getUrlHelper().getLikedTweetsUrl(userId); Map parameters = new HashMap<>(); - parameters.put(TWEET_FIELDS, ALL_TWEET_FIELDS); + parameters.put(TWEET_FIELDS, ALL_TWEET_FIELDS_PUBLIC); if (!additionalParameters.isRecursiveCall()) { return getRequestHelper().getRequestWithParameters(url, parameters, TweetList.class).orElseThrow(NoSuchElementException::new); } @@ -576,7 +593,7 @@ public UserList getMutedUsers() { parameters.put(USER_FIELDS, ALL_USER_FIELDS); parameters.put(EXPANSION, PINNED_TWEET_ID); parameters.put(MAX_RESULTS, "1000"); - parameters.put(TWEET_FIELDS, ALL_TWEET_FIELDS); + parameters.put(TWEET_FIELDS, ALL_TWEET_FIELDS_PUBLIC); return requestHelperV1.getRequestWithParameters(url, parameters, UserList.class).orElseThrow(NoSuchElementException::new); } @@ -646,7 +663,7 @@ public UserList getSpaceBuyers(final String spaceId) { Map parameters = new HashMap<>(); parameters.put(EXPANSION, PINNED_TWEET_ID); parameters.put(USER_FIELDS, ALL_USER_FIELDS); - parameters.put(TWEET_FIELDS, ALL_TWEET_FIELDS); + parameters.put(TWEET_FIELDS, ALL_TWEET_FIELDS_PUBLIC); return getRequestHelperV2().getRequestWithParameters(url, parameters, UserList.class) .orElseThrow(NoSuchElementException::new); } @@ -751,7 +768,7 @@ public UserList getListMembers(final String listId) { Map parameters = new HashMap<>(); parameters.put(EXPANSION, PINNED_TWEET_ID); parameters.put(USER_FIELDS, ALL_USER_FIELDS); - parameters.put(TWEET_FIELDS, ALL_TWEET_FIELDS); + parameters.put(TWEET_FIELDS, ALL_TWEET_FIELDS_PUBLIC); return getUsersRecursively(Integer.MAX_VALUE, url, parameters); } @@ -788,10 +805,15 @@ public boolean deleteTweet(final String tweetId) { @Override public Tweet getTweet(String tweetId) { + return getTweet(tweetId, REQUEST_TWEET_FIELDS_SCOPE.PUBLIC); + } + + @Override + public Tweet getTweet(String tweetId, REQUEST_TWEET_FIELDS_SCOPE requestTweetFieldsScope) { String url = getUrlHelper().getTweetUrl(tweetId); Map parameters = new HashMap<>(); parameters.put(EXPANSION, ALL_EXPANSIONS); - parameters.put(TWEET_FIELDS, ALL_TWEET_FIELDS); + parameters.put(TWEET_FIELDS, getFieldsForRequestTweetFieldsScope(requestTweetFieldsScope)); parameters.put(USER_FIELDS, ALL_USER_FIELDS); parameters.put(MEDIA_FIELD, ALL_MEDIA_FIELDS); return getRequestHelper().getRequestWithParameters(url, parameters, TweetV2.class).orElseThrow(NoSuchElementException::new); @@ -799,10 +821,15 @@ public Tweet getTweet(String tweetId) { @Override public TweetList getTweets(List tweetIds) { + return getTweets(tweetIds, REQUEST_TWEET_FIELDS_SCOPE.PUBLIC); + } + + @Override + public TweetList getTweets(List tweetIds, REQUEST_TWEET_FIELDS_SCOPE requestTweetFieldsScope) { String url = getUrlHelper().getTweetsUrl(); Map parameters = new HashMap<>(); parameters.put(EXPANSION, ALL_EXPANSIONS); - parameters.put(TWEET_FIELDS, ALL_TWEET_FIELDS); + parameters.put(TWEET_FIELDS, getFieldsForRequestTweetFieldsScope(requestTweetFieldsScope)); parameters.put(USER_FIELDS, ALL_USER_FIELDS); parameters.put(MEDIA_FIELD, ALL_MEDIA_FIELDS); StringBuilder result = new StringBuilder(); @@ -841,7 +868,7 @@ public TweetList searchTweets(String query) { public TweetList searchTweets(String query, AdditionalParameters additionalParameters) { Map parameters = additionalParameters.getMapFromParameters(); parameters.put(QUERY, query); - parameters.put(TWEET_FIELDS, ALL_TWEET_FIELDS); + parameters.put(TWEET_FIELDS, ALL_TWEET_FIELDS_PUBLIC); parameters.put(USER_FIELDS, ALL_USER_FIELDS); parameters.put(EXPANSION, ALL_EXPANSIONS); parameters.put(MEDIA_FIELD, ALL_MEDIA_FIELDS); @@ -865,10 +892,10 @@ public TweetList searchAllTweets(final String query, AdditionalParameters additi Map parameters = additionalParameters.getMapFromParameters(); parameters.put(QUERY, query); if (additionalParameters.getMaxResults() <= 100) { - parameters.put(TWEET_FIELDS, ALL_TWEET_FIELDS); + parameters.put(TWEET_FIELDS, ALL_TWEET_FIELDS_PUBLIC); } else { LOGGER.warn("removing context_annotations from tweet_fields because max_result is greater 100"); - parameters.put(TWEET_FIELDS, ALL_TWEET_FIELDS.replace(",context_annotations", "")); + parameters.put(TWEET_FIELDS, ALL_TWEET_FIELDS_PUBLIC.replace(",context_annotations", "")); } parameters.put(USER_FIELDS, ALL_USER_FIELDS); parameters.put(EXPANSION, ALL_EXPANSIONS); @@ -1004,7 +1031,7 @@ public Future startFilteredStream(Consumer consumer) { String url = urlHelper.getFilteredStreamUrl(); Map parameters = new HashMap<>(); parameters.put(EXPANSION, ALL_EXPANSIONS); - parameters.put(TWEET_FIELDS, ALL_TWEET_FIELDS); + parameters.put(TWEET_FIELDS, ALL_TWEET_FIELDS_PUBLIC); parameters.put(USER_FIELDS, ALL_USER_FIELDS); parameters.put(MEDIA_FIELD, ALL_MEDIA_FIELDS); return requestHelperV2.getAsyncRequest(url, parameters, consumer); @@ -1020,7 +1047,7 @@ public Future startFilteredStream(IAPIEventListener listener, int back String url = urlHelper.getFilteredStreamUrl(); Map parameters = new HashMap<>(); parameters.put(EXPANSION, ALL_EXPANSIONS); - parameters.put(TWEET_FIELDS, ALL_TWEET_FIELDS); + parameters.put(TWEET_FIELDS, ALL_TWEET_FIELDS_PUBLIC); parameters.put(USER_FIELDS, ALL_USER_FIELDS); parameters.put(MEDIA_FIELD, ALL_MEDIA_FIELDS); if (backfillMinutes > 0) { @@ -1100,7 +1127,7 @@ public Future startSampledStream(Consumer consumer) { String url = urlHelper.getSampledStreamUrl(); Map parameters = new HashMap<>(); parameters.put(EXPANSION, ALL_EXPANSIONS); - parameters.put(TWEET_FIELDS, ALL_TWEET_FIELDS); + parameters.put(TWEET_FIELDS, ALL_TWEET_FIELDS_PUBLIC); parameters.put(USER_FIELDS, ALL_USER_FIELDS); parameters.put(MEDIA_FIELD, ALL_MEDIA_FIELDS); return requestHelperV2.getAsyncRequest(url, parameters, consumer); @@ -1116,7 +1143,7 @@ public Future startSampledStream(IAPIEventListener listener, int backf String url = urlHelper.getSampledStreamUrl(); Map parameters = new HashMap<>(); parameters.put(EXPANSION, ALL_EXPANSIONS); - parameters.put(TWEET_FIELDS, ALL_TWEET_FIELDS); + parameters.put(TWEET_FIELDS, ALL_TWEET_FIELDS_PUBLIC); parameters.put(USER_FIELDS, ALL_USER_FIELDS); parameters.put(MEDIA_FIELD, ALL_MEDIA_FIELDS); if (backfillMinutes > 0) { @@ -1127,13 +1154,23 @@ public Future startSampledStream(IAPIEventListener listener, int backf @Override public TweetList getUserTimeline(final String userId) { - return getUserTimeline(userId, AdditionalParameters.builder().maxResults(100).build()); + return getUserTimeline(userId, AdditionalParameters.builder().maxResults(100).build(), REQUEST_TWEET_FIELDS_SCOPE.PUBLIC); + } + + @Override + public TweetList getUserTimeline(final String userId, AdditionalParameters additionalParameters) { + return getUserTimeline(userId, additionalParameters, REQUEST_TWEET_FIELDS_SCOPE.PUBLIC); + } + + @Override + public TweetList getUserTimeline(final String userId, REQUEST_TWEET_FIELDS_SCOPE requestTweetFieldsScope) { + return getUserTimeline(userId, AdditionalParameters.builder().maxResults(100).build(), requestTweetFieldsScope); } @Override - public TweetList getUserTimeline(String userId, AdditionalParameters additionalParameters) { + public TweetList getUserTimeline(String userId, AdditionalParameters additionalParameters, REQUEST_TWEET_FIELDS_SCOPE requestTweetFieldsScope) { Map parameters = additionalParameters.getMapFromParameters(); - parameters.put(TWEET_FIELDS, ALL_TWEET_FIELDS); + parameters.put(TWEET_FIELDS, getFieldsForRequestTweetFieldsScope(requestTweetFieldsScope)); parameters.put(USER_FIELDS, ALL_USER_FIELDS); parameters.put(PLACE_FIELDS, ALL_PLACE_FIELDS); parameters.put(POLL_FIELDS, ALL_POLL_FIELDS); @@ -1157,7 +1194,7 @@ public TweetList getUserMentions(final String userId) { @Override public TweetList getUserMentions(final String userId, AdditionalParameters additionalParameters) { Map parameters = additionalParameters.getMapFromParameters(); - parameters.put(TWEET_FIELDS, ALL_TWEET_FIELDS); + parameters.put(TWEET_FIELDS, ALL_TWEET_FIELDS_PUBLIC); String url = urlHelper.getUserMentionsUrl(userId); if (!additionalParameters.isRecursiveCall()) { return getRequestHelperV2().getRequestWithParameters(url, parameters, TweetList.class).orElseThrow(NoSuchElementException::new); @@ -1378,4 +1415,18 @@ public String getUserIdFromAccessToken() { } return accessToken.substring(0, accessToken.indexOf("-")); } + + public String getFieldsForRequestTweetFieldsScope(REQUEST_TWEET_FIELDS_SCOPE requestTweetFieldsScope) { + switch (requestTweetFieldsScope) { + case NON_PUBLIC: + return ALL_TWEET_FIELDS_NON_PUBLIC; + case NON_PUBLIC_PROMOTED: + return ALL_TWEET_FIELDS_NON_PUBLIC_PROMOTED; + case PUBLIC: + return ALL_TWEET_FIELDS_PUBLIC; + default: + throw new RuntimeException("REQUEST_TWEET_FIELDS_SCOPE " + requestTweetFieldsScope + " not implemented."); + } + } + } diff --git a/src/main/java/io/github/redouane59/twitter/dto/tweet/Attachments.java b/src/main/java/io/github/redouane59/twitter/dto/tweet/Attachments.java index f1e332b4..3de59dcb 100644 --- a/src/main/java/io/github/redouane59/twitter/dto/tweet/Attachments.java +++ b/src/main/java/io/github/redouane59/twitter/dto/tweet/Attachments.java @@ -16,5 +16,7 @@ public class Attachments { @JsonProperty("media_keys") private String[] mediaKeys; + @JsonProperty("poll_ids") + private String[] pollIds; } diff --git a/src/main/java/io/github/redouane59/twitter/dto/tweet/Tweet.java b/src/main/java/io/github/redouane59/twitter/dto/tweet/Tweet.java index 2f11f621..213b8c82 100644 --- a/src/main/java/io/github/redouane59/twitter/dto/tweet/Tweet.java +++ b/src/main/java/io/github/redouane59/twitter/dto/tweet/Tweet.java @@ -66,6 +66,165 @@ public interface Tweet { */ int getQuoteCount(); + /** + * Get the number of times the Tweet has been viewed. This is a private metric, and requires the + * use of OAuth 1.0a or OAuth 2.0 User Context authentication. + * + * API v2 only! + * + * @return the number of times the Tweet has been viewed. + */ + int getImpressionCount(); + + /** + * Get the number of times a user clicks on a URL link or URL preview card in a Tweet. This is a + * private metric, and requires the use of OAuth 1.0a or OAuth 2.0 User Context authentication. + * + * API v2 only! + * + * @return the number of times a user clicks on a URL link or URL preview card in a Tweet. + */ + int getUrlLinkClicks(); + + /** + * Get the number of times a user clicks the following portions of a Tweet - display name, user + * name, profile picture. This is a private metric, and requires the use of OAuth 1.0a or OAuth + * 2.0 User Context authentication. + * + * API v2 only! + * + * @return the number of times a user clicks the following portions of a Tweet - display name, + * user name, profile picture. + */ + int getUserProfileClicks(); + + /** + * Get the number of times the Tweet has been viewed organically. This is a private metric, and + * requires the use of OAuth 1.0a or OAuth 2.0 User Context authentication. + * + * API v2 only! + * + * @return the number of times the Tweet has been viewed organically. + */ + int getOrganicImpressionCount(); + + /** + * Get the number of likes the Tweet has received organically. This is a private metric, and + * requires the use of OAuth 1.0a or OAuth 2.0 User Context authentication. + * + * API v2 only! + * + * @return the number of likes the Tweet has received organically. + */ + int getOrganicLikeCount(); + + /** + * Get the number of replies the Tweet has received organically. This is a private metric, and + * requires the use of OAuth 1.0a or OAuth 2.0 User Context authentication. + * + * API v2 only! + * + * @return the number of replies the Tweet has received organically. + */ + int getOrganicReplyCount(); + + /** + * Get the number of times the Tweet has been Retweeted organically. This is a private metric, and + * requires the use of OAuth 1.0a or OAuth 2.0 User Context authentication. + * + * API v2 only! + * + * @return the number of times the Tweet has been Retweeted organically. This is a private metric, + * and requires the use of OAuth 1.0a or OAuth 2.0 User Context authentication. + */ + int getOrganicRetweetCount(); + + /** + * Get the number of times a user clicks on a URL link or URL preview card in a Tweet organically. + * This is a private metric, and requires the use of OAuth 1.0a or OAuth 2.0 User Context + * authentication. + * + * API v2 only! + * + * @return the number of times a user clicks on a URL link or URL preview card in a Tweet + * organically. + */ + int getOrganicUrlLinkClicks(); + + /** + * Get the number of times a user clicks the following portions of a Tweet organically - display + * name, user name, profile picture. This is a private metric, and requires the use of OAuth 1.0a + * or OAuth 2.0 User Context authentication. + * + * API v2 only! + * + * @return the number of times a user clicks the following portions of a Tweet organically - + * display name, user name, profile picture. + */ + int getOrganicUserProfileClicks(); + + /** + * Number of times the Tweet has been viewed when that Tweet is being promoted. This is a private + * metric, and requires the use of OAuth 1.0a or OAuth 2.0 User Context authentication. + * + * API v2 only! + * + * @return + */ + int getPromotedImpressionCount(); + + /** + * Number of Likes of this Tweet when that Tweet is being promoted. This is a private metric, and + * requires the use of OAuth 1.0a or OAuth 2.0 User Context authentication. + * + * API v2 only! + * + * @return + */ + int getPromotedLikeCount(); + + /** + * Number of Replies to this Tweet when that Tweet is being promoted. This is a private metric, + * and requires the use of OAuth 1.0a or OAuth 2.0 User Context authentication. + * + * API v2 only! + * + * @return + */ + int getPromotedReplyCount(); + + /** + * Number of times this Tweet has been Retweeted when that Tweet is being promoted. This is a + * private metric, and requires the use of OAuth 1.0a or OAuth 2.0 User Context authentication. + * + * API v2 only! + * + * @return + */ + int getPromotedRetweetCount(); + + /** + * Number of times a user clicks on a URL link or URL preview card in a Tweet when it is being + * promoted. This is a private metric, and requires the use of OAuth 1.0a or OAuth 2.0 User + * Context authentication. + * + * API v2 only! + * + * @return + */ + int getPromotedUrlLinkClicks(); + + /** + * Number of times a user clicks the following portions of a Tweet when it is being promoted - + * display name, user name, profile picture. This is a private metric, and requires the use of + * OAuth 1.0a or OAuth 2.0 User Context authentication. + * + * API v2 only! + * + * @return + */ + int getPromotedUserProfileClicks(); + /** * Get the creation date of the tweet * diff --git a/src/main/java/io/github/redouane59/twitter/dto/tweet/TweetV1.java b/src/main/java/io/github/redouane59/twitter/dto/tweet/TweetV1.java index 3b438d18..1218512e 100644 --- a/src/main/java/io/github/redouane59/twitter/dto/tweet/TweetV1.java +++ b/src/main/java/io/github/redouane59/twitter/dto/tweet/TweetV1.java @@ -1,6 +1,7 @@ package io.github.redouane59.twitter.dto.tweet; import com.fasterxml.jackson.annotation.JsonAlias; +import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; import io.github.redouane59.twitter.dto.stream.StreamRules.StreamRule; @@ -146,6 +147,110 @@ public String getAuthorId() { return user.getId(); } + /* Not available in API v1! */ + @Override + @JsonIgnore + public int getImpressionCount() { + return 0; + } + + /* Not available in API v1! */ + @Override + @JsonIgnore + public int getUrlLinkClicks() { + return 0; + } + + /* Not available in API v1! */ + @Override + @JsonIgnore + public int getUserProfileClicks() { + return 0; + } + + /* Not available in API v1! */ + @Override + @JsonIgnore + public int getOrganicImpressionCount() { + return 0; + } + + /* Not available in API v1! */ + @Override + @JsonIgnore + public int getOrganicLikeCount() { + return 0; + } + + /* Not available in API v1! */ + @Override + @JsonIgnore + public int getOrganicReplyCount() { + return 0; + } + + /* Not available in API v1! */ + @Override + @JsonIgnore + public int getOrganicRetweetCount() { + return 0; + } + + /* Not available in API v1! */ + @Override + @JsonIgnore + public int getOrganicUrlLinkClicks() { + return 0; + } + + /* Not available in API v1! */ + @Override + @JsonIgnore + public int getOrganicUserProfileClicks() { + return 0; + } + + /* Not available in API v1! */ + @Override + @JsonIgnore + public int getPromotedImpressionCount() { + return 0; + } + + /* Not available in API v1! */ + @Override + @JsonIgnore + public int getPromotedLikeCount() { + return 0; + } + + /* Not available in API v1! */ + @Override + @JsonIgnore + public int getPromotedReplyCount() { + return 0; + } + + /* Not available in API v1! */ + @Override + @JsonIgnore + public int getPromotedRetweetCount() { + return 0; + } + + /* Not available in API v1! */ + @Override + @JsonIgnore + public int getPromotedUrlLinkClicks() { + return 0; + } + + /* Not available in API v1! */ + @Override + @JsonIgnore + public int getPromotedUserProfileClicks() { + return 0; + } @Getter @Setter diff --git a/src/main/java/io/github/redouane59/twitter/dto/tweet/TweetV2.java b/src/main/java/io/github/redouane59/twitter/dto/tweet/TweetV2.java index 2c093330..b8302a27 100644 --- a/src/main/java/io/github/redouane59/twitter/dto/tweet/TweetV2.java +++ b/src/main/java/io/github/redouane59/twitter/dto/tweet/TweetV2.java @@ -188,6 +188,126 @@ public int getQuoteCount() { return data.getPublicMetrics().getQuoteCount(); } + @Override + public int getImpressionCount() { + if (data == null || data.getNonPublicMetrics() == null) { + return 0; + } + return data.getNonPublicMetrics().getImpressionCount(); + } + + @Override + public int getUrlLinkClicks() { + if (data == null || data.getNonPublicMetrics() == null) { + return 0; + } + return data.getNonPublicMetrics().getUrlLinkClicks(); + } + + @Override + public int getUserProfileClicks() { + if (data == null || data.getNonPublicMetrics() == null) { + return 0; + } + return data.getNonPublicMetrics().getUserProfileClicks(); + } + + @Override + public int getOrganicImpressionCount() { + if (data == null || data.getOrganicMetrics() == null) { + return 0; + } + return data.getOrganicMetrics().getImpressionCount(); + } + + @Override + public int getOrganicLikeCount() { + if (data == null || data.getOrganicMetrics() == null) { + return 0; + } + return data.getOrganicMetrics().getLikeCount(); + } + + @Override + public int getOrganicReplyCount() { + if (data == null || data.getOrganicMetrics() == null) { + return 0; + } + return data.getOrganicMetrics().getReplyCount(); + } + + @Override + public int getOrganicRetweetCount() { + if (data == null || data.getOrganicMetrics() == null) { + return 0; + } + return data.getOrganicMetrics().getRetweetCount(); + } + + @Override + public int getOrganicUrlLinkClicks() { + if (data == null || data.getOrganicMetrics() == null) { + return 0; + } + return data.getOrganicMetrics().getUrlLinkClicks(); + } + + @Override + public int getOrganicUserProfileClicks() { + if (data == null || data.getOrganicMetrics() == null) { + return 0; + } + return data.getOrganicMetrics().getUserProfileClicks(); + } + + @Override + public int getPromotedImpressionCount() { + if (data == null || data.getPromotedMetrics() == null) { + return 0; + } + return data.getPromotedMetrics().getImpressionCount(); + } + + @Override + public int getPromotedLikeCount() { + if (data == null || data.getPromotedMetrics() == null) { + return 0; + } + return data.getPromotedMetrics().getLikeCount(); + } + + @Override + public int getPromotedReplyCount() { + if (data == null || data.getPromotedMetrics() == null) { + return 0; + } + return data.getPromotedMetrics().getReplyCount(); + } + + @Override + public int getPromotedRetweetCount() { + if (data == null || data.getPromotedMetrics() == null) { + return 0; + } + return data.getPromotedMetrics().getRetweetCount(); + } + + @Override + public int getPromotedUrlLinkClicks() { + if (data == null || data.getPromotedMetrics() == null) { + return 0; + } + return data.getPromotedMetrics().getUrlLinkClicks(); + } + + @Override + public int getPromotedUserProfileClicks() { + if (data == null || data.getPromotedMetrics() == null) { + return 0; + } + return data.getPromotedMetrics().getUserProfileClicks(); + } + @Override public String getInReplyToUserId() { if (data == null) { @@ -240,6 +360,26 @@ public TweetType getTweetType() { return data.getReferencedTweets().get(0).getType(); } + /** Returns whether the TweetPublicMetricsDTO object exists. Probably the field public_metrics was not requested if not. */ + public boolean hasTweetPublicMetrics() { + return data!=null && data.hasPublicMetrics(); + } + + /** Returns whether the TweetNonPublicMetricsDTO object exists. Probably the field non_public_metrics was not requested if not. */ + public boolean hasTweetNonPublicMetrics() { + return data!=null && data.hasNonPublicMetrics(); + } + + /** Returns whether the TweetOrganicMetricsDTO object exists. Probably the field organic_metrics was not requested if not. */ + public boolean hasTweetOrganicMetrics() { + return data!=null && data.hasOrganicMetrics(); + } + + /** Returns whether the TweetPromotedMetricsDTO object exists. Probably the field promoted_metrics was not requested if not. */ + public boolean hasTweetPromotedMetrics() { + return data!=null && data.hasPromotedMetrics(); + } + @Getter @Setter @Builder @@ -262,6 +402,15 @@ public static class TweetData implements Tweet { @JsonProperty("public_metrics") @JsonInclude(Include.NON_NULL) private TweetPublicMetricsDTO publicMetrics; + @JsonProperty("non_public_metrics") + @JsonInclude(Include.NON_NULL) + private TweetNonPublicMetricsDTO nonPublicMetrics; + @JsonProperty("organic_metrics") + @JsonInclude(Include.NON_NULL) + private TweetOrganicMetricsDTO organicMetrics; + @JsonProperty("promoted_metrics") + @JsonInclude(Include.NON_NULL) + private TweetPromotedMetricsDTO promotedMetrics; @JsonProperty("possibly_sensitive") private boolean possiblySensitive; private String lang; @@ -301,6 +450,115 @@ public int getQuoteCount() { return publicMetrics.getQuoteCount(); } + /** Returns whether the TweetPublicMetricsDTO object exists. Probably the field public_metrics was not requested if not. */ + public boolean hasPublicMetrics() { + return publicMetrics!=null; + } + + @Override + @JsonIgnore + public int getImpressionCount() { + return nonPublicMetrics.getImpressionCount(); + } + + @Override + @JsonIgnore + public int getUrlLinkClicks() { + return nonPublicMetrics.getUrlLinkClicks(); + } + @Override + @JsonIgnore + public int getUserProfileClicks() { + return nonPublicMetrics.getUserProfileClicks(); + } + + /** Returns whether the TweetNonPublicMetricsDTO object exists. Probably the field non_public_metrics was not requested if not. */ + public boolean hasNonPublicMetrics() { + return nonPublicMetrics!=null; + } + + @Override + @JsonIgnore + public int getOrganicImpressionCount() { + return organicMetrics.getImpressionCount(); + } + + @Override + @JsonIgnore + public int getOrganicLikeCount() { + return organicMetrics.getLikeCount(); + } + + @Override + @JsonIgnore + public int getOrganicReplyCount() { + return organicMetrics.getReplyCount(); + } + + @Override + @JsonIgnore + public int getOrganicRetweetCount() { + return organicMetrics.getRetweetCount(); + } + + @Override + @JsonIgnore + public int getOrganicUrlLinkClicks() { + return organicMetrics.getUrlLinkClicks(); + } + + @Override + @JsonIgnore + public int getOrganicUserProfileClicks() { + return organicMetrics.getUserProfileClicks(); + } + + /** Returns whether the TweetOrganicMetricsDTO object exists. Probably the field organic_metrics was not requested if not. */ + public boolean hasOrganicMetrics() { + return organicMetrics!=null; + } + + @Override + @JsonIgnore + public int getPromotedImpressionCount() { + return promotedMetrics.getImpressionCount(); + } + + @Override + @JsonIgnore + public int getPromotedLikeCount() { + return promotedMetrics.getLikeCount(); + } + + @Override + @JsonIgnore + public int getPromotedReplyCount() { + return promotedMetrics.getReplyCount(); + } + + @Override + @JsonIgnore + public int getPromotedRetweetCount() { + return promotedMetrics.getRetweetCount(); + } + + @Override + @JsonIgnore + public int getPromotedUrlLinkClicks() { + return promotedMetrics.getUrlLinkClicks(); + } + + @Override + @JsonIgnore + public int getPromotedUserProfileClicks() { + return promotedMetrics.getUserProfileClicks(); + } + + /** Returns whether the TweetPromotedMetricsDTO object exists. Probably the field promoted_metrics was not requested if not. */ + public boolean hasPromotedMetrics() { + return promotedMetrics!=null; + } + @Override public String getInReplyToStatusId() { if (referencedTweets == null || referencedTweets.isEmpty()) { @@ -385,7 +643,6 @@ public static class Includes { private List places; } - @Getter @Setter public static class TweetPublicMetricsDTO { @@ -400,6 +657,75 @@ public static class TweetPublicMetricsDTO { private int quoteCount; } + /** Non-public engagement metrics for the Tweet at the time of the request. This is a private metric, and requires the use of OAuth 1.0a or OAuth 2.0 User Context authentication. + * To return this field, add tweet.fields=non_public_metrics in the request's query parameter.*/ + @Getter + @Setter + public static class TweetNonPublicMetricsDTO { + + /** Number of times the Tweet has been viewed. This is a private metric, and requires the use of OAuth 1.0a or OAuth 2.0 User Context authentication. **/ + @JsonProperty("impression_count") + private int impressionCount; + /** Number of times a user clicks on a URL link or URL preview card in a Tweet. This is a private metric, and requires the use of OAuth 1.0a or OAuth 2.0 User Context authentication. */ + @JsonProperty("url_link_clicks") + private int urlLinkClicks; + /** Number of times a user clicks the following portions of a Tweet - display name, user name, profile picture. This is a private metric, and requires the use of OAuth 1.0a or OAuth 2.0 User Context authentication. */ + @JsonProperty("user_profile_clicks") + private int userProfileClicks; + } + + /** Organic engagement metrics for the Tweet at the time of the request. Requires user context authentication. */ + @Getter + @Setter + public static class TweetOrganicMetricsDTO { + + /** Number of times the Tweet has been viewed organically. This is a private metric, and requires the use of OAuth 1.0a or OAuth 2.0 User Context authentication. */ + @JsonProperty("impression_count") + private int impressionCount; + /** Number of times a user clicks on a URL link or URL preview card in a Tweet organically. This is a private metric, and requires the use of OAuth 1.0a or OAuth 2.0 User Context authentication. */ + @JsonProperty("url_link_clicks") + private int urlLinkClicks; + /** Number of times a user clicks the following portions of a Tweet organically - display name, user name, profile picture. This is a private metric, and requires the use of OAuth 1.0a or OAuth 2.0 User Context authentication. */ + @JsonProperty("user_profile_clicks") + private int userProfileClicks; + /** Number of times the Tweet has been Retweeted organically. */ + @JsonProperty("retweet_count") + private int retweetCount; + /** Number of replies the Tweet has received organically. */ + @JsonProperty("reply_count") + private int replyCount; + /** Number of likes the Tweet has received organically. */ + @JsonProperty("like_count") + private int likeCount; + + } + + /** Engagement metrics for the Tweet at the time of the request in a promoted context. Requires user context authentication. */ + @Getter + @Setter + public static class TweetPromotedMetricsDTO { + + /** Number of times the Tweet has been viewed when that Tweet is being promoted. This is a private metric, and requires the use of OAuth 1.0a or OAuth 2.0 User Context authentication. */ + @JsonProperty("impression_count") + private int impressionCount; + /** Number of times a user clicks on a URL link or URL preview card in a Tweet when it is being promoted. This is a private metric, and requires the use of OAuth 1.0a or OAuth 2.0 User Context authentication. */ + @JsonProperty("url_link_clicks") + private int urlLinkClicks; + /** Number of times a user clicks the following portions of a Tweet when it is being promoted - display name, user name, profile picture. This is a private metric, and requires the use of OAuth 1.0a or OAuth 2.0 User Context authentication. */ + @JsonProperty("user_profile_clicks") + private int userProfileClicks; + /** Number of times this Tweet has been Retweeted when that Tweet is being promoted. */ + @JsonProperty("retweet_count") + private int retweetCount; + /** Number of Replies to this Tweet when that Tweet is being promoted. */ + @JsonProperty("reply_count") + private int replyCount; + /** Number of Likes of this Tweet when that Tweet is being promoted. */ + @JsonProperty("like_count") + private int likeCount; + + } + @Getter @Setter public static class EntitiesV2 implements Entities { diff --git a/src/main/java/io/github/redouane59/twitter/dto/user/User.java b/src/main/java/io/github/redouane59/twitter/dto/user/User.java index 9c1a6390..fab4d23d 100644 --- a/src/main/java/io/github/redouane59/twitter/dto/user/User.java +++ b/src/main/java/io/github/redouane59/twitter/dto/user/User.java @@ -70,6 +70,20 @@ public interface User { */ int getTweetCount(); + /** + * Get the number of lists that include this user. + * + * @return number of lists that include this user. + */ + public int getListedCount(); + + /** + * Returns whether the users public metrics is included in the response. + * + * @return whether users public metrics exists + */ + public boolean hasPublicMetrics(); + /** * Get the language of the user * diff --git a/src/main/java/io/github/redouane59/twitter/dto/user/UserV1.java b/src/main/java/io/github/redouane59/twitter/dto/user/UserV1.java index 00774306..fe3bbe0b 100644 --- a/src/main/java/io/github/redouane59/twitter/dto/user/UserV1.java +++ b/src/main/java/io/github/redouane59/twitter/dto/user/UserV1.java @@ -69,6 +69,19 @@ public int hashCode() { return id.hashCode(); } + /* This is not supported in API v1. */ + @Override + public int getListedCount() { + LOGGER.debug("UnsupportedOperation"); + return 0; + } + + /* Returns whether the users public metrics is included in the response. This is always the case in API v1. */ + @Override + public boolean hasPublicMetrics() { + return true; + } + @Override public LocalDateTime getDateOfCreation() { return ConverterHelper.getDateFromTwitterString(dateOfCreation); diff --git a/src/main/java/io/github/redouane59/twitter/dto/user/UserV2.java b/src/main/java/io/github/redouane59/twitter/dto/user/UserV2.java index 902d4276..a6a11f84 100644 --- a/src/main/java/io/github/redouane59/twitter/dto/user/UserV2.java +++ b/src/main/java/io/github/redouane59/twitter/dto/user/UserV2.java @@ -78,6 +78,18 @@ public int getTweetCount() { return data.getPublicMetrics().getTweetCount(); } + @Override + @JsonIgnore + public int getListedCount() { + return data.getPublicMetrics().getListedCount(); + } + + /* Returns whether the UserPublicMetrics object exists. Probably the field public_metrics was not requested if not. */ + @Override + public boolean hasPublicMetrics() { + return data!=null && data.hasPublicMetrics(); + } + @Override @JsonIgnore public String getLang() { @@ -184,11 +196,21 @@ public int getFollowingCount() { return publicMetrics.getFollowingCount(); } + @Override + public int getListedCount() { + return publicMetrics.getListedCount(); + } + @Override public int getTweetCount() { return publicMetrics.getTweetCount(); } + /* Returns whether the UserPublicMetrics object exists. Probably the field public_metrics was not requested if not. */ + public boolean hasPublicMetrics() { + return publicMetrics!=null; + } + @Override @JsonIgnore public Tweet getPinnedTweet() { diff --git a/src/main/java/io/github/redouane59/twitter/helpers/AbstractRequestHelper.java b/src/main/java/io/github/redouane59/twitter/helpers/AbstractRequestHelper.java index 2c807b2b..21936f62 100644 --- a/src/main/java/io/github/redouane59/twitter/helpers/AbstractRequestHelper.java +++ b/src/main/java/io/github/redouane59/twitter/helpers/AbstractRequestHelper.java @@ -13,6 +13,7 @@ import java.util.Map; import java.util.Optional; import javax.naming.LimitExceededException; +import javax.naming.NoPermissionException; import lombok.Getter; import lombok.Setter; import lombok.SneakyThrows; @@ -108,6 +109,8 @@ public Optional makeRequest(OAuthRequest request, boolean signRequired, C return makeRequest(request, false, classType); // We have already signed if it was requested } else if (response.getCode() < 200 || response.getCode() > 299) { logApiError(request.getVerb().name(), request.getUrl(), stringResponse, response.getCode()); + } else if (stringResponse != null && stringResponse.startsWith("{\"errors\":")) { + throw new NoPermissionException(stringResponse); } result = convert(stringResponse, classType); return Optional.ofNullable(result); diff --git a/src/main/java/io/github/redouane59/twitter/helpers/RequestHelperV2.java b/src/main/java/io/github/redouane59/twitter/helpers/RequestHelperV2.java index 11706f95..45796fcd 100644 --- a/src/main/java/io/github/redouane59/twitter/helpers/RequestHelperV2.java +++ b/src/main/java/io/github/redouane59/twitter/helpers/RequestHelperV2.java @@ -23,6 +23,8 @@ import java.util.concurrent.Future; import java.util.function.Consumer; import java.util.stream.Collectors; +import lombok.Getter; +import lombok.Setter; import lombok.SneakyThrows; import lombok.extern.slf4j.Slf4j; import org.apache.http.NameValuePair; @@ -32,14 +34,28 @@ @Slf4j public class RequestHelperV2 extends AbstractRequestHelper { + /** Use consumer key for user context if true; or else app-only bearer token. Default is false. */ + @Getter @Setter + private boolean useConsumerKey = false; + public RequestHelperV2(TwitterCredentials twitterCredentials) { super(twitterCredentials); } + public RequestHelperV2(TwitterCredentials twitterCredentials, boolean useConsumerKey) { + this(twitterCredentials); + this.useConsumerKey = useConsumerKey; + } + public RequestHelperV2(TwitterCredentials twitterCredentials, OAuth10aService service) { super(twitterCredentials, service); } + public RequestHelperV2(TwitterCredentials twitterCredentials, OAuth10aService service, boolean useConsumerKey) { + this(twitterCredentials, service); + this.useConsumerKey = useConsumerKey; + } + @Override public Optional getRequest(String url, Class classType) { return getRequestWithParameters(url, null, classType); @@ -128,7 +144,11 @@ public Optional getRequestWithHeader(String url, Map head @Override protected void signRequest(OAuthRequest request) { - request.addHeader(OAuthConstants.HEADER, "Bearer " + getBearerToken()); + if (useConsumerKey) { + getService().signRequest(getTwitterCredentials().asAccessToken(), request); + } else { + request.addHeader(OAuthConstants.HEADER, "Bearer " + getBearerToken()); + } } public String getBearerToken() { From 45c8d7f11c4bf4194082de00254dc3547ccc2c13 Mon Sep 17 00:00:00 2001 From: xberger Date: Mon, 14 Nov 2022 22:14:12 +0100 Subject: [PATCH 2/2] Change return value behavior of new metric getter methods and fix merge --- .../redouane59/twitter/TwitterClient.java | 15 +- .../redouane59/twitter/dto/tweet/Tweet.java | 72 ++++++---- .../redouane59/twitter/dto/tweet/TweetV1.java | 60 ++++---- .../redouane59/twitter/dto/tweet/TweetV2.java | 135 ++++++++++++------ .../helpers/AbstractRequestHelper.java | 1 - 5 files changed, 168 insertions(+), 115 deletions(-) diff --git a/src/main/java/io/github/redouane59/twitter/TwitterClient.java b/src/main/java/io/github/redouane59/twitter/TwitterClient.java index 7f236584..6fd49a99 100644 --- a/src/main/java/io/github/redouane59/twitter/TwitterClient.java +++ b/src/main/java/io/github/redouane59/twitter/TwitterClient.java @@ -100,12 +100,9 @@ @Slf4j public class TwitterClient implements ITwitterClientV1, ITwitterClientV2, ITwitterClientArchive { - public static final ObjectMapper OBJECT_MAPPER = new ObjectMapper() - .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false) - .setSerializationInclusion(JsonInclude.Include.NON_NULL) - .findAndRegisterModules(); public static final String TWEET_FIELDS = "tweet.fields"; - public static final String ALL_TWEET_FIELDS_PUBLIC = + public static final String + ALL_TWEET_FIELDS_PUBLIC = "attachments,author_id,created_at,entities,geo,id,in_reply_to_user_id,lang,possibly_sensitive,referenced_tweets,source,text,withheld,context_annotations,conversation_id,reply_settings,public_metrics"; public static final String ALL_TWEET_FIELDS_NON_PUBLIC = ALL_TWEET_FIELDS_PUBLIC + ",non_public_metrics,organic_metrics"; public static final String ALL_TWEET_FIELDS_NON_PUBLIC_PROMOTED = ALL_TWEET_FIELDS_NON_PUBLIC + ",promoted_metrics"; @@ -794,7 +791,7 @@ public TweetList getListTweets(String listId, AdditionalParameters additionalPar String url = getUrlHelper().getListTweetsUrl(listId); Map parameters = additionalParameters.getMapFromParameters(); parameters.put(EXPANSION, ALL_EXPANSIONS); - parameters.put(TWEET_FIELDS, ALL_TWEET_FIELDS); + parameters.put(TWEET_FIELDS, ALL_TWEET_FIELDS_PUBLIC); parameters.put(USER_FIELDS, ALL_USER_FIELDS); parameters.put(MEDIA_FIELD, ALL_MEDIA_FIELDS); @@ -841,7 +838,7 @@ public DirectMessage getDirectMessageEvents(final AdditionalParameters additiona Map parameters = additionalParameters.getMapFromParameters(); parameters.put(DM_FIELDS, ALL_DM_FIELDS); parameters.put(EXPANSION, ALL_DM_EXPANSIONS); - parameters.put(TWEET_FIELDS, ALL_TWEET_FIELDS); + parameters.put(TWEET_FIELDS, ALL_TWEET_FIELDS_PUBLIC); parameters.put(USER_FIELDS, ALL_USER_FIELDS); parameters.put(MEDIA_FIELD, ALL_MEDIA_FIELDS); return getRequestHelperV1().getRequestWithParameters(url, parameters, DirectMessage.class).orElseThrow(NoSuchElementException::new); @@ -858,7 +855,7 @@ public DirectMessage getDirectMessagesByConversation(String conversationId, fina Map parameters = additionalParameters.getMapFromParameters(); parameters.put(DM_FIELDS, ALL_DM_FIELDS); parameters.put(EXPANSION, ALL_DM_EXPANSIONS); - parameters.put(TWEET_FIELDS, ALL_TWEET_FIELDS); + parameters.put(TWEET_FIELDS, ALL_TWEET_FIELDS_PUBLIC); parameters.put(USER_FIELDS, ALL_USER_FIELDS); parameters.put(MEDIA_FIELD, ALL_MEDIA_FIELDS); return getRequestHelperV1().getRequestWithParameters(url, parameters, DirectMessage.class).orElseThrow(NoSuchElementException::new); @@ -875,7 +872,7 @@ public DirectMessage getDirectMessagesByUser(final String participantId, final A Map parameters = additionalParameters.getMapFromParameters(); parameters.put(DM_FIELDS, ALL_DM_FIELDS); parameters.put(EXPANSION, ALL_DM_EXPANSIONS); - parameters.put(TWEET_FIELDS, ALL_TWEET_FIELDS); + parameters.put(TWEET_FIELDS, ALL_TWEET_FIELDS_PUBLIC); parameters.put(USER_FIELDS, ALL_USER_FIELDS); parameters.put(MEDIA_FIELD, ALL_MEDIA_FIELDS); return getRequestHelperV1().getRequestWithParameters(url, parameters, DirectMessage.class).orElseThrow(NoSuchElementException::new); diff --git a/src/main/java/io/github/redouane59/twitter/dto/tweet/Tweet.java b/src/main/java/io/github/redouane59/twitter/dto/tweet/Tweet.java index 213b8c82..f58019b3 100644 --- a/src/main/java/io/github/redouane59/twitter/dto/tweet/Tweet.java +++ b/src/main/java/io/github/redouane59/twitter/dto/tweet/Tweet.java @@ -72,9 +72,9 @@ public interface Tweet { * * API v2 only! * - * @return the number of times the Tweet has been viewed. + * @return the number of times the Tweet has been viewed or null if no nonPublicMetrics exists. */ - int getImpressionCount(); + Integer getImpressionCount(); /** * Get the number of times a user clicks on a URL link or URL preview card in a Tweet. This is a @@ -82,9 +82,10 @@ public interface Tweet { * * API v2 only! * - * @return the number of times a user clicks on a URL link or URL preview card in a Tweet. + * @return the number of times a user clicks on a URL link or URL preview card in a Tweet or null + * if no nonPublicMetrics exists. */ - int getUrlLinkClicks(); + Integer getUrlLinkClicks(); /** * Get the number of times a user clicks the following portions of a Tweet - display name, user @@ -94,9 +95,9 @@ public interface Tweet { * API v2 only! * * @return the number of times a user clicks the following portions of a Tweet - display name, - * user name, profile picture. + * user name, profile picture or null if no nonPublicMetrics exists. */ - int getUserProfileClicks(); + Integer getUserProfileClicks(); /** * Get the number of times the Tweet has been viewed organically. This is a private metric, and @@ -104,9 +105,10 @@ public interface Tweet { * * API v2 only! * - * @return the number of times the Tweet has been viewed organically. + * @return the number of times the Tweet has been viewed organically or null if no organicMetrics + * exists. */ - int getOrganicImpressionCount(); + Integer getOrganicImpressionCount(); /** * Get the number of likes the Tweet has received organically. This is a private metric, and @@ -114,9 +116,10 @@ public interface Tweet { * * API v2 only! * - * @return the number of likes the Tweet has received organically. + * @return the number of likes the Tweet has received organically or null if no organicMetrics + * exists. */ - int getOrganicLikeCount(); + Integer getOrganicLikeCount(); /** * Get the number of replies the Tweet has received organically. This is a private metric, and @@ -124,9 +127,10 @@ public interface Tweet { * * API v2 only! * - * @return the number of replies the Tweet has received organically. + * @return the number of replies the Tweet has received organically or null if no organicMetrics + * exists. */ - int getOrganicReplyCount(); + Integer getOrganicReplyCount(); /** * Get the number of times the Tweet has been Retweeted organically. This is a private metric, and @@ -135,9 +139,10 @@ public interface Tweet { * API v2 only! * * @return the number of times the Tweet has been Retweeted organically. This is a private metric, - * and requires the use of OAuth 1.0a or OAuth 2.0 User Context authentication. + * and requires the use of OAuth 1.0a or OAuth 2.0 User Context authentication or null if + * no organicMetrics exists. */ - int getOrganicRetweetCount(); + Integer getOrganicRetweetCount(); /** * Get the number of times a user clicks on a URL link or URL preview card in a Tweet organically. @@ -147,9 +152,9 @@ public interface Tweet { * API v2 only! * * @return the number of times a user clicks on a URL link or URL preview card in a Tweet - * organically. + * organically or null if no organicMetrics exists. */ - int getOrganicUrlLinkClicks(); + Integer getOrganicUrlLinkClicks(); /** * Get the number of times a user clicks the following portions of a Tweet organically - display @@ -159,9 +164,9 @@ public interface Tweet { * API v2 only! * * @return the number of times a user clicks the following portions of a Tweet organically - - * display name, user name, profile picture. + * display name, user name, profile picture or null if no organicMetrics exists. */ - int getOrganicUserProfileClicks(); + Integer getOrganicUserProfileClicks(); /** * Number of times the Tweet has been viewed when that Tweet is being promoted. This is a private @@ -169,9 +174,10 @@ public interface Tweet { * * API v2 only! * - * @return + * @return the number of times the Tweet has been viewed when that Tweet is being promoted or null + * if no promotedMetrics exists. */ - int getPromotedImpressionCount(); + Integer getPromotedImpressionCount(); /** * Number of Likes of this Tweet when that Tweet is being promoted. This is a private metric, and @@ -179,9 +185,10 @@ public interface Tweet { * * API v2 only! * - * @return + * @return the number of Likes of this Tweet when that Tweet is being promoted or null if no + * promotedMetrics exists. */ - int getPromotedLikeCount(); + Integer getPromotedLikeCount(); /** * Number of Replies to this Tweet when that Tweet is being promoted. This is a private metric, @@ -189,9 +196,10 @@ public interface Tweet { * * API v2 only! * - * @return + * @return number of Replies to this Tweet when that Tweet is being promoted or null if no + * promotedMetrics exists. */ - int getPromotedReplyCount(); + Integer getPromotedReplyCount(); /** * Number of times this Tweet has been Retweeted when that Tweet is being promoted. This is a @@ -199,9 +207,10 @@ public interface Tweet { * * API v2 only! * - * @return + * @return the number of times this Tweet has been Retweeted when that Tweet is being promoted or + * null if no promotedMetrics exists. */ - int getPromotedRetweetCount(); + Integer getPromotedRetweetCount(); /** * Number of times a user clicks on a URL link or URL preview card in a Tweet when it is being @@ -210,9 +219,10 @@ public interface Tweet { * * API v2 only! * - * @return + * @return the number of times a user clicks on a URL link or URL preview card in a Tweet when it + * is being promoted or null if no promotedMetrics exists. */ - int getPromotedUrlLinkClicks(); + Integer getPromotedUrlLinkClicks(); /** * Number of times a user clicks the following portions of a Tweet when it is being promoted - @@ -221,9 +231,11 @@ public interface Tweet { * * API v2 only! * - * @return + * @return the number of times a user clicks the following portions of a Tweet when it is being + * promoted - display name, user name, profile picture or null if no promotedMetrics + * exists. */ - int getPromotedUserProfileClicks(); + Integer getPromotedUserProfileClicks(); /** * Get the creation date of the tweet diff --git a/src/main/java/io/github/redouane59/twitter/dto/tweet/TweetV1.java b/src/main/java/io/github/redouane59/twitter/dto/tweet/TweetV1.java index 1218512e..0efe7b16 100644 --- a/src/main/java/io/github/redouane59/twitter/dto/tweet/TweetV1.java +++ b/src/main/java/io/github/redouane59/twitter/dto/tweet/TweetV1.java @@ -150,106 +150,106 @@ public String getAuthorId() { /* Not available in API v1! */ @Override @JsonIgnore - public int getImpressionCount() { - return 0; + public Integer getImpressionCount() { + throw new RuntimeException("Mectric Impression is not vailable in Twitter API v1."); } /* Not available in API v1! */ @Override @JsonIgnore - public int getUrlLinkClicks() { - return 0; + public Integer getUrlLinkClicks() { + throw new RuntimeException("Mectric UrlLinkClicks is not vailable in Twitter API v1."); } /* Not available in API v1! */ @Override @JsonIgnore - public int getUserProfileClicks() { - return 0; + public Integer getUserProfileClicks() { + throw new RuntimeException("Mectric UserProfileClicks is not vailable in Twitter API v1."); } /* Not available in API v1! */ @Override @JsonIgnore - public int getOrganicImpressionCount() { - return 0; + public Integer getOrganicImpressionCount() { + throw new RuntimeException("Mectric OrganicImpressionCount is not vailable in Twitter API v1."); } /* Not available in API v1! */ @Override @JsonIgnore - public int getOrganicLikeCount() { - return 0; + public Integer getOrganicLikeCount() { + throw new RuntimeException("Mectric OrganicLikeCount is not vailable in Twitter API v1."); } /* Not available in API v1! */ @Override @JsonIgnore - public int getOrganicReplyCount() { - return 0; + public Integer getOrganicReplyCount() { + throw new RuntimeException("Mectric OrganicReplyCount is not vailable in Twitter API v1."); } /* Not available in API v1! */ @Override @JsonIgnore - public int getOrganicRetweetCount() { - return 0; + public Integer getOrganicRetweetCount() { + throw new RuntimeException("Mectric OrganicRetweetCount is not vailable in Twitter API v1."); } /* Not available in API v1! */ @Override @JsonIgnore - public int getOrganicUrlLinkClicks() { - return 0; + public Integer getOrganicUrlLinkClicks() { + throw new RuntimeException("Mectric OrganicUrlLinkClicks is not vailable in Twitter API v1."); } /* Not available in API v1! */ @Override @JsonIgnore - public int getOrganicUserProfileClicks() { - return 0; + public Integer getOrganicUserProfileClicks() { + throw new RuntimeException("Mectric OrganicUserProfileClicks is not vailable in Twitter API v1."); } /* Not available in API v1! */ @Override @JsonIgnore - public int getPromotedImpressionCount() { - return 0; + public Integer getPromotedImpressionCount() { + throw new RuntimeException("Mectric PromotedImpressionCount is not vailable in Twitter API v1."); } /* Not available in API v1! */ @Override @JsonIgnore - public int getPromotedLikeCount() { - return 0; + public Integer getPromotedLikeCount() { + throw new RuntimeException("Mectric PromotedLikeCount is not vailable in Twitter API v1."); } /* Not available in API v1! */ @Override @JsonIgnore - public int getPromotedReplyCount() { - return 0; + public Integer getPromotedReplyCount() { + throw new RuntimeException("Mectric PromotedReplyCount is not vailable in Twitter API v1."); } /* Not available in API v1! */ @Override @JsonIgnore - public int getPromotedRetweetCount() { - return 0; + public Integer getPromotedRetweetCount() { + throw new RuntimeException("Mectric PromotedRetweetCount is not vailable in Twitter API v1."); } /* Not available in API v1! */ @Override @JsonIgnore - public int getPromotedUrlLinkClicks() { - return 0; + public Integer getPromotedUrlLinkClicks() { + throw new RuntimeException("Mectric PromotedUrlLinkClicks is not vailable in Twitter API v1."); } /* Not available in API v1! */ @Override @JsonIgnore - public int getPromotedUserProfileClicks() { - return 0; + public Integer getPromotedUserProfileClicks() { + throw new RuntimeException("Mectric PromotedUserProfileClicks is not vailable in Twitter API v1."); } @Getter diff --git a/src/main/java/io/github/redouane59/twitter/dto/tweet/TweetV2.java b/src/main/java/io/github/redouane59/twitter/dto/tweet/TweetV2.java index 6d81b528..92a8d24a 100644 --- a/src/main/java/io/github/redouane59/twitter/dto/tweet/TweetV2.java +++ b/src/main/java/io/github/redouane59/twitter/dto/tweet/TweetV2.java @@ -189,121 +189,121 @@ public int getQuoteCount() { } @Override - public int getImpressionCount() { + public Integer getImpressionCount() { if (data == null || data.getNonPublicMetrics() == null) { - return 0; + return null; } return data.getNonPublicMetrics().getImpressionCount(); } @Override - public int getUrlLinkClicks() { + public Integer getUrlLinkClicks() { if (data == null || data.getNonPublicMetrics() == null) { - return 0; + return null; } return data.getNonPublicMetrics().getUrlLinkClicks(); } @Override - public int getUserProfileClicks() { + public Integer getUserProfileClicks() { if (data == null || data.getNonPublicMetrics() == null) { - return 0; + return null; } return data.getNonPublicMetrics().getUserProfileClicks(); } @Override - public int getOrganicImpressionCount() { + public Integer getOrganicImpressionCount() { if (data == null || data.getOrganicMetrics() == null) { - return 0; + return null; } return data.getOrganicMetrics().getImpressionCount(); } @Override - public int getOrganicLikeCount() { + public Integer getOrganicLikeCount() { if (data == null || data.getOrganicMetrics() == null) { - return 0; + return null; } return data.getOrganicMetrics().getLikeCount(); } @Override - public int getOrganicReplyCount() { + public Integer getOrganicReplyCount() { if (data == null || data.getOrganicMetrics() == null) { - return 0; + return null; } return data.getOrganicMetrics().getReplyCount(); } @Override - public int getOrganicRetweetCount() { + public Integer getOrganicRetweetCount() { if (data == null || data.getOrganicMetrics() == null) { - return 0; + return null; } return data.getOrganicMetrics().getRetweetCount(); } @Override - public int getOrganicUrlLinkClicks() { + public Integer getOrganicUrlLinkClicks() { if (data == null || data.getOrganicMetrics() == null) { - return 0; + return null; } return data.getOrganicMetrics().getUrlLinkClicks(); } @Override - public int getOrganicUserProfileClicks() { + public Integer getOrganicUserProfileClicks() { if (data == null || data.getOrganicMetrics() == null) { - return 0; + return null; } return data.getOrganicMetrics().getUserProfileClicks(); } @Override - public int getPromotedImpressionCount() { + public Integer getPromotedImpressionCount() { if (data == null || data.getPromotedMetrics() == null) { - return 0; + return null; } return data.getPromotedMetrics().getImpressionCount(); } @Override - public int getPromotedLikeCount() { + public Integer getPromotedLikeCount() { if (data == null || data.getPromotedMetrics() == null) { - return 0; + return null; } return data.getPromotedMetrics().getLikeCount(); } @Override - public int getPromotedReplyCount() { + public Integer getPromotedReplyCount() { if (data == null || data.getPromotedMetrics() == null) { - return 0; + return null; } return data.getPromotedMetrics().getReplyCount(); } @Override - public int getPromotedRetweetCount() { + public Integer getPromotedRetweetCount() { if (data == null || data.getPromotedMetrics() == null) { - return 0; + return null; } return data.getPromotedMetrics().getRetweetCount(); } @Override - public int getPromotedUrlLinkClicks() { + public Integer getPromotedUrlLinkClicks() { if (data == null || data.getPromotedMetrics() == null) { - return 0; + return null; } return data.getPromotedMetrics().getUrlLinkClicks(); } @Override - public int getPromotedUserProfileClicks() { + public Integer getPromotedUserProfileClicks() { if (data == null || data.getPromotedMetrics() == null) { - return 0; + return null; } return data.getPromotedMetrics().getUserProfileClicks(); } @@ -457,18 +457,27 @@ public boolean hasPublicMetrics() { @Override @JsonIgnore - public int getImpressionCount() { + public Integer getImpressionCount() { + if (nonPublicMetrics == null) { + return null; + } return nonPublicMetrics.getImpressionCount(); } @Override @JsonIgnore - public int getUrlLinkClicks() { + public Integer getUrlLinkClicks() { + if (nonPublicMetrics == null) { + return null; + } return nonPublicMetrics.getUrlLinkClicks(); } @Override @JsonIgnore - public int getUserProfileClicks() { + public Integer getUserProfileClicks() { + if (nonPublicMetrics == null) { + return null; + } return nonPublicMetrics.getUserProfileClicks(); } @@ -479,37 +488,55 @@ public boolean hasNonPublicMetrics() { @Override @JsonIgnore - public int getOrganicImpressionCount() { + public Integer getOrganicImpressionCount() { + if (organicMetrics == null) { + return null; + } return organicMetrics.getImpressionCount(); } @Override @JsonIgnore - public int getOrganicLikeCount() { + public Integer getOrganicLikeCount() { + if (organicMetrics == null) { + return null; + } return organicMetrics.getLikeCount(); } @Override @JsonIgnore - public int getOrganicReplyCount() { + public Integer getOrganicReplyCount() { + if (organicMetrics == null) { + return null; + } return organicMetrics.getReplyCount(); } @Override @JsonIgnore - public int getOrganicRetweetCount() { + public Integer getOrganicRetweetCount() { + if (organicMetrics == null) { + return null; + } return organicMetrics.getRetweetCount(); } @Override @JsonIgnore - public int getOrganicUrlLinkClicks() { + public Integer getOrganicUrlLinkClicks() { + if (organicMetrics == null) { + return null; + } return organicMetrics.getUrlLinkClicks(); } @Override @JsonIgnore - public int getOrganicUserProfileClicks() { + public Integer getOrganicUserProfileClicks() { + if (organicMetrics == null) { + return null; + } return organicMetrics.getUserProfileClicks(); } @@ -520,37 +547,55 @@ public boolean hasOrganicMetrics() { @Override @JsonIgnore - public int getPromotedImpressionCount() { + public Integer getPromotedImpressionCount() { + if (promotedMetrics == null) { + return null; + } return promotedMetrics.getImpressionCount(); } @Override @JsonIgnore - public int getPromotedLikeCount() { + public Integer getPromotedLikeCount() { + if (promotedMetrics == null) { + return null; + } return promotedMetrics.getLikeCount(); } @Override @JsonIgnore - public int getPromotedReplyCount() { + public Integer getPromotedReplyCount() { + if (promotedMetrics == null) { + return null; + } return promotedMetrics.getReplyCount(); } @Override @JsonIgnore - public int getPromotedRetweetCount() { + public Integer getPromotedRetweetCount() { + if (promotedMetrics == null) { + return null; + } return promotedMetrics.getRetweetCount(); } @Override @JsonIgnore - public int getPromotedUrlLinkClicks() { + public Integer getPromotedUrlLinkClicks() { + if (promotedMetrics == null) { + return null; + } return promotedMetrics.getUrlLinkClicks(); } @Override @JsonIgnore - public int getPromotedUserProfileClicks() { + public Integer getPromotedUserProfileClicks() { + if (promotedMetrics == null) { + return null; + } return promotedMetrics.getUserProfileClicks(); } diff --git a/src/main/java/io/github/redouane59/twitter/helpers/AbstractRequestHelper.java b/src/main/java/io/github/redouane59/twitter/helpers/AbstractRequestHelper.java index 40c21a9e..6cf3123b 100644 --- a/src/main/java/io/github/redouane59/twitter/helpers/AbstractRequestHelper.java +++ b/src/main/java/io/github/redouane59/twitter/helpers/AbstractRequestHelper.java @@ -16,7 +16,6 @@ import java.util.Map; import java.util.Optional; import javax.naming.LimitExceededException; -import javax.naming.NoPermissionException; import lombok.Getter; import lombok.Setter; import lombok.SneakyThrows;