diff --git a/src/main/scala/com/danielasfregola/twitter4s/entities/enums/FilterLevel.scala b/src/main/scala/com/danielasfregola/twitter4s/entities/enums/FilterLevel.scala new file mode 100644 index 00000000..641e533c --- /dev/null +++ b/src/main/scala/com/danielasfregola/twitter4s/entities/enums/FilterLevel.scala @@ -0,0 +1,9 @@ +package com.danielasfregola.twitter4s.entities.enums + +object FilterLevel extends Enumeration { + type FilterLevel = Value + + val None = Value("none") + val Low = Value("low") + val Medium = Value("medium") +} diff --git a/src/main/scala/com/danielasfregola/twitter4s/http/clients/streaming/sites/TwitterSiteClient.scala b/src/main/scala/com/danielasfregola/twitter4s/http/clients/streaming/sites/TwitterSiteClient.scala index 65b4a653..27edeff9 100644 --- a/src/main/scala/com/danielasfregola/twitter4s/http/clients/streaming/sites/TwitterSiteClient.scala +++ b/src/main/scala/com/danielasfregola/twitter4s/http/clients/streaming/sites/TwitterSiteClient.scala @@ -19,7 +19,7 @@ trait TwitterSiteClient { /** Starts a streaming connection from Twitter's site API. Streams messages for a set of users, * as described in Site streams. - * The function returns a future of a `TwitterStream` that can be use to close or replace the stream when needed. + * The function returns a future of a `TwitterStream` that can be used to close or replace the stream when needed. * If there are failures in establishing the initial connection, the Future returned will be completed with a failure. * Since it's an asynchronous event stream, all the events will be parsed as entities of type `SiteStreamingMessage` * and processed accordingly to the partial function `f`. All the messages that do not match `f` are automatically ignored. @@ -27,24 +27,24 @@ trait TwitterSiteClient { * * https://developer.twitter.com/en/docs/accounts-and-users/subscribe-account-activity/api-reference/site-stream. * - * @param follow : Empty by default. A comma separated list of user IDs, indicating the users to return statuses for in the stream. + * @param follow : Empty by default. List of user IDs, indicating the users whose Tweets should be delivered on the stream. * For more information * https://developer.twitter.com/en/docs/accounts-and-users/subscribe-account-activity/api-reference/site-stream - * @param with: `User` by default. Specifies whether to return information for just the users specified in the follow parameter, or include messages from accounts they follow. + * @param with : `User` by default. Specifies whether to return information for just the users specified in the follow parameter, or include messages from accounts they follow. * For more information see * https://developer.twitter.com/en/docs/accounts-and-users/subscribe-account-activity/api-reference/site-stream - * @param replies: Optional. By default @replies are only sent if the current user follows both the sender and receiver of the reply. + * @param replies : Optional. By default @replies are only sent if the current user follows both the sender and receiver of the reply. * To receive all the replies, set the argument to `true`. * For more information see * https://developer.twitter.com/en/docs/accounts-and-users/subscribe-account-activity/api-reference/site-stream - * @param stringify_friend_ids: Optional. Specifies whether to send the Friend List preamble as an array of integers or an array of strings. + * @param stringify_friend_ids : Optional. Specifies whether to send the Friend List preamble as an array of integers or an array of strings. * For more information see * https://developer.twitter.com/en/docs/accounts-and-users/subscribe-account-activity/api-reference/site-stream - * @param languages : Empty by default. A comma separated list of 'BCP 47' language identifiers. + * @param languages : Empty by default. List of 'BCP 47' language identifiers. * For more information * https://developer.twitter.com/en/docs/tweets/filter-realtime/guides/basic-stream-parameters * @param stall_warnings : Default to false. Specifies whether stall warnings (`WarningMessage`) should be delivered as part of the updates. - * @param f: the function that defines how to process the received messages + * @param f : Function that defines how to process the received messages. */ def siteEvents(follow: Seq[Long] = Seq.empty, `with`: WithFilter = WithFilter.User, diff --git a/src/main/scala/com/danielasfregola/twitter4s/http/clients/streaming/statuses/TwitterStatusClient.scala b/src/main/scala/com/danielasfregola/twitter4s/http/clients/streaming/statuses/TwitterStatusClient.scala index 4c215e15..927fee7d 100644 --- a/src/main/scala/com/danielasfregola/twitter4s/http/clients/streaming/statuses/TwitterStatusClient.scala +++ b/src/main/scala/com/danielasfregola/twitter4s/http/clients/streaming/statuses/TwitterStatusClient.scala @@ -1,6 +1,8 @@ package com.danielasfregola.twitter4s package http.clients.streaming.statuses +import com.danielasfregola.twitter4s.entities.enums.FilterLevel +import com.danielasfregola.twitter4s.entities.enums.FilterLevel.FilterLevel import com.danielasfregola.twitter4s.entities.enums.Language.Language import com.danielasfregola.twitter4s.entities.streaming.CommonStreamingMessage import com.danielasfregola.twitter4s.http.clients.streaming.statuses.parameters._ @@ -18,7 +20,7 @@ trait TwitterStatusClient { /** Starts a streaming connection from Twitter's public API, filtered with the 'follow', 'track' and 'location' parameters. * Although all of those three params are optional, at least one must be specified. * The track, follow, and locations fields should be considered to be combined with an OR operator. - * The function returns a future of a `TwitterStream` that can be use to close or replace the stream when needed. + * The function returns a future of a `TwitterStream` that can be used to close or replace the stream when needed. * If there are failures in establishing the initial connection, the Future returned will be completed with a failure. * Since it's an asynchronous event stream, all the events will be parsed as entities of type `CommonStreamingMessage` * and processed accordingly to the partial function `f`. All the messages that do not match `f` are automatically ignored. @@ -26,36 +28,40 @@ trait TwitterStatusClient { * * https://developer.twitter.com/en/docs/tweets/filter-realtime/api-reference/post-statuses-filter.html. * - * @param follow : Empty by default. A comma separated list of user IDs, indicating the users to return statuses for in the stream. + * @param follow : Empty by default. List of user IDs, indicating the users whose Tweets should be delivered on the stream. * For more information * https://developer.twitter.com/en/docs/tweets/filter-realtime/api-reference/post-statuses-filter.html - * @param tracks : Empty by default. Keywords to track. Phrases of keywords are specified by a comma-separated list. - * For more information + * @param tracks : Empty by default. List of phrases which will be used to determine what Tweets will be delivered on the stream. + * Each phrase must be between 1 and 60 bytes, inclusive. + * For more information * https://developer.twitter.com/en/docs/tweets/filter-realtime/api-reference/post-statuses-filter.html * @param locations : Empty by default. Specifies a set of bounding boxes to track. * For more information * https://developer.twitter.com/en/docs/tweets/filter-realtime/api-reference/post-statuses-filter.html - * @param languages : Empty by default. A comma separated list of 'BCP 47' language identifiers. + * @param languages : Empty by default. List of 'BCP 47' language identifiers. * For more information * https://developer.twitter.com/en/docs/tweets/filter-realtime/guides/basic-stream-parameters * @param stall_warnings : Default to false. Specifies whether stall warnings (`WarningMessage`) should be delivered as part of the updates. - * @param f: the function that defines how to process the received messages + * @param filter_level : Default value is none, which includes all available Tweets. + * Set the minimum value of the filter_level Tweet attribute required to be included in the stream. + * @param f : Function that defines how to process the received messages. */ def filterStatuses(follow: Seq[Long] = Seq.empty, tracks: Seq[String] = Seq.empty, locations: Seq[Double] = Seq.empty, languages: Seq[Language] = Seq.empty, - stall_warnings: Boolean = false)(f: PartialFunction[CommonStreamingMessage, Unit]): Future[TwitterStream] = { + stall_warnings: Boolean = false, + filter_level: FilterLevel = FilterLevel.None)(f: PartialFunction[CommonStreamingMessage, Unit]): Future[TwitterStream] = { import streamingClient._ require(follow.nonEmpty || tracks.nonEmpty || locations.nonEmpty, "At least one of 'follow', 'tracks' or 'locations' needs to be non empty") - val filters = StatusFilters(follow, tracks, locations, languages, stall_warnings) + val filters = StatusFilters(follow, tracks, locations, languages, stall_warnings, filter_level) preProcessing() Post(s"$statusUrl/filter.json", filters).processStream(f) } /** Starts a streaming connection from Twitter's public API, which is a a small random sample of all public statuses. * The Tweets returned by the default access level are the same, so if two different clients connect to this endpoint, they will see the same Tweets. - * The function returns a future of a `TwitterStream` that can be use to close or replace the stream when needed. + * The function returns a future of a `TwitterStream` that can be used to close or replace the stream when needed. * If there are failures in establishing the initial connection, the Future returned will be completed with a failure. * Since it's an asynchronous event stream, all the events will be parsed as entities of type `CommonStreamingMessage` * and processed accordingly to the partial function `f`. All the messages that do not match `f` are automatically ignored. @@ -63,17 +69,25 @@ trait TwitterStatusClient { * * https://developer.twitter.com/en/docs/tweets/sample-realtime/overview/GET_statuse_sample. * - * @param languages : Empty by default. A comma separated list of 'BCP 47' language identifiers. + * @param languages : Empty by default. List of 'BCP 47' language identifiers. * For more information * https://developer.twitter.com/en/docs/tweets/filter-realtime/guides/basic-stream-parameters * @param stall_warnings : Default to false. Specifies whether stall warnings (`WarningMessage`) should be delivered as part of the updates. - * @param f: the function that defines how to process the received messages + * @param tracks : Empty by default. List of phrases which will be used to determine what Tweets will be delivered on the stream. + * Each phrase must be between 1 and 60 bytes, inclusive. + * For more information + * https://developer.twitter.com/en/docs/tweets/filter-realtime/api-reference/post-statuses-filter.html + * @param filter_level : Default value is none, which includes all available Tweets. + * Set the minimum value of the filter_level Tweet attribute required to be included in the stream. + * @param f : Function that defines how to process the received messages. */ def sampleStatuses(languages: Seq[Language] = Seq.empty, - stall_warnings: Boolean = false) + stall_warnings: Boolean = false, + tracks: Seq[String] = Seq.empty, + filter_level: FilterLevel = FilterLevel.None) (f: PartialFunction[CommonStreamingMessage, Unit]): Future[TwitterStream] = { import streamingClient._ - val parameters = StatusSampleParameters(languages, stall_warnings) + val parameters = StatusSampleParameters(languages, stall_warnings, tracks, filter_level) preProcessing() Get(s"$statusUrl/sample.json", parameters).processStream(f) } @@ -83,19 +97,19 @@ trait TwitterStatusClient { * Creative use of a combination of other resources and various access levels can satisfy nearly every application use case. * For more information see * https://dev.twitter.com/streaming/reference/get/statuses/firehose. - * The function returns a future of a `TwitterStream` that can be use to close or replace the stream when needed. + * The function returns a future of a `TwitterStream` that can be used to close or replace the stream when needed. * If there are failures in establishing the initial connection, the Future returned will be completed with a failure. * Since it's an asynchronous event stream, all the events will be parsed as entities of type `CommonStreamingMessage` * and processed accordingly to the partial function `f`. All the messages that do not match `f` are automatically ignored. * - * @param count: Optional. The number of messages to backfill. + * @param count : Optional. The number of messages to backfill. * For more information see * https://dev.twitter.com/streaming/overview/request-parameters#count - * @param languages : Empty by default. A comma separated list of 'BCP 47' language identifiers. + * @param languages : Empty by default. List of 'BCP 47' language identifiers. * For more information * https://developer.twitter.com/en/docs/tweets/filter-realtime/guides/basic-stream-parameters * @param stall_warnings : Default to false. Specifies whether stall warnings (`WarningMessage`) should be delivered as part of the updates. - * @param f: the function that defines how to process the received messages. + * @param f : Function that defines how to process the received messages. */ def firehoseStatuses(count: Option[Int] = None, languages: Seq[Language] = Seq.empty, diff --git a/src/main/scala/com/danielasfregola/twitter4s/http/clients/streaming/statuses/parameters/StatusFilters.scala b/src/main/scala/com/danielasfregola/twitter4s/http/clients/streaming/statuses/parameters/StatusFilters.scala index 22d51f2a..36af0029 100644 --- a/src/main/scala/com/danielasfregola/twitter4s/http/clients/streaming/statuses/parameters/StatusFilters.scala +++ b/src/main/scala/com/danielasfregola/twitter4s/http/clients/streaming/statuses/parameters/StatusFilters.scala @@ -1,9 +1,11 @@ package com.danielasfregola.twitter4s.http.clients.streaming.statuses.parameters +import com.danielasfregola.twitter4s.entities.enums.FilterLevel.FilterLevel import com.danielasfregola.twitter4s.entities.enums.Language.Language private[twitter4s] final case class StatusFilters(follow: Seq[Long], track: Seq[String], locations: Seq[Double], language: Seq[Language], - stall_warnings: Boolean) + stall_warnings: Boolean, + filter_level: FilterLevel) diff --git a/src/main/scala/com/danielasfregola/twitter4s/http/clients/streaming/statuses/parameters/StatusSampleParameters.scala b/src/main/scala/com/danielasfregola/twitter4s/http/clients/streaming/statuses/parameters/StatusSampleParameters.scala index 3b5cceef..5551385c 100644 --- a/src/main/scala/com/danielasfregola/twitter4s/http/clients/streaming/statuses/parameters/StatusSampleParameters.scala +++ b/src/main/scala/com/danielasfregola/twitter4s/http/clients/streaming/statuses/parameters/StatusSampleParameters.scala @@ -1,6 +1,10 @@ package com.danielasfregola.twitter4s.http.clients.streaming.statuses.parameters +import com.danielasfregola.twitter4s.entities.enums.FilterLevel.FilterLevel import com.danielasfregola.twitter4s.entities.enums.Language.Language import com.danielasfregola.twitter4s.http.marshalling.Parameters -private[twitter4s] final case class StatusSampleParameters(language: Seq[Language], stall_warnings: Boolean) extends Parameters +private[twitter4s] final case class StatusSampleParameters(language: Seq[Language], + stall_warnings: Boolean, + tracks: Seq[String], + filter_level: FilterLevel) extends Parameters diff --git a/src/main/scala/com/danielasfregola/twitter4s/http/clients/streaming/users/TwitterUserClient.scala b/src/main/scala/com/danielasfregola/twitter4s/http/clients/streaming/users/TwitterUserClient.scala index 1ece5a06..748ca3c0 100644 --- a/src/main/scala/com/danielasfregola/twitter4s/http/clients/streaming/users/TwitterUserClient.scala +++ b/src/main/scala/com/danielasfregola/twitter4s/http/clients/streaming/users/TwitterUserClient.scala @@ -1,8 +1,9 @@ package com.danielasfregola.twitter4s package http.clients.streaming.users +import com.danielasfregola.twitter4s.entities.enums.FilterLevel.FilterLevel import com.danielasfregola.twitter4s.entities.enums.Language.Language -import com.danielasfregola.twitter4s.entities.enums.WithFilter +import com.danielasfregola.twitter4s.entities.enums.{FilterLevel, WithFilter} import com.danielasfregola.twitter4s.entities.enums.WithFilter.WithFilter import com.danielasfregola.twitter4s.entities.streaming.UserStreamingMessage import com.danielasfregola.twitter4s.http.clients.streaming.users.parameters._ @@ -19,7 +20,7 @@ trait TwitterUserClient { /** Starts a streaming connection from Twitter's user API. Streams messages for a single user as * described in User streams. - * The function returns a future of a `TwitterStream` that can be use to close or replace the stream when needed. + * The function returns a future of a `TwitterStream` that can be used to close or replace the stream when needed. * If there are failures in establishing the initial connection, the Future returned will be completed with a failure. * Since it's an asynchronous event stream, all the events will be parsed as entities of type `UserStreamingMessage` * and processed accordingly to the partial function `f`. All the messages that do not match `f` are automatically ignored. @@ -27,7 +28,7 @@ trait TwitterUserClient { * * https://developer.twitter.com/en/docs/accounts-and-users/subscribe-account-activity/api-reference/user-stream. * - * @param with: `Followings` by default. Specifies whether to return information for just the authenticating user, + * @param with : `Followings` by default. Specifies whether to return information for just the authenticating user, * or include messages from accounts the user follows. * For more information see * https://developer.twitter.com/en/docs/accounts-and-users/subscribe-account-activity/api-reference/user-stream @@ -35,8 +36,9 @@ trait TwitterUserClient { * To receive all the replies, set the argument to `true`. * For more information see * https://developer.twitter.com/en/docs/accounts-and-users/subscribe-account-activity/api-reference/user-stream - * @param tracks : Empty by default. Keywords to track. Phrases of keywords are specified by a comma-separated list. - * For more information see + * @param tracks : Empty by default. List of phrases which will be used to determine what Tweets will be delivered on the stream. + * Each phrase must be between 1 and 60 bytes, inclusive. + * For more information see * https://developer.twitter.com/en/docs/accounts-and-users/subscribe-account-activity/api-reference/user-stream * @param locations : Empty by default. Specifies a set of bounding boxes to track. * For more information see @@ -44,11 +46,11 @@ trait TwitterUserClient { * @param stringify_friend_ids: Optional. Specifies whether to send the Friend List preamble as an array of integers or an array of strings. * For more information see * https://developer.twitter.com/en/docs/accounts-and-users/subscribe-account-activity/api-reference/user-stream - * @param languages : Empty by default. A comma separated list of 'BCP 47' language identifiers. + * @param languages : Empty by default. List of 'BCP 47' language identifiers. * For more information * https://developer.twitter.com/en/docs/accounts-and-users/subscribe-account-activity/api-reference/user-stream * @param stall_warnings : Default to false. Specifies whether stall warnings (`WarningMessage`) should be delivered as part of the updates. - * @param f: the function that defines how to process the received messages + * @param f : Function that defines how to process the received messages. */ def userEvents(`with`: WithFilter = WithFilter.Followings, replies: Option[Boolean] = None, @@ -56,10 +58,11 @@ trait TwitterUserClient { locations: Seq[Double] = Seq.empty, stringify_friend_ids: Boolean = false, languages: Seq[Language] = Seq.empty, - stall_warnings: Boolean = false)(f: PartialFunction[UserStreamingMessage, Unit]): Future[TwitterStream] = { + stall_warnings: Boolean = false, + filter_level: FilterLevel = FilterLevel.None)(f: PartialFunction[UserStreamingMessage, Unit]): Future[TwitterStream] = { import streamingClient._ val repliesAll = replies.flatMap(x => if (x) Some("all") else None) - val parameters = UserParameters(`with`, repliesAll, tracks, locations, stringify_friend_ids, languages, stall_warnings) + val parameters = UserParameters(`with`, repliesAll, tracks, locations, stringify_friend_ids, languages, stall_warnings, filter_level) preProcessing() Get(s"$userUrl/user.json", parameters).processStream(f) } diff --git a/src/main/scala/com/danielasfregola/twitter4s/http/clients/streaming/users/parameters/UserParameters.scala b/src/main/scala/com/danielasfregola/twitter4s/http/clients/streaming/users/parameters/UserParameters.scala index d454d242..f4346129 100644 --- a/src/main/scala/com/danielasfregola/twitter4s/http/clients/streaming/users/parameters/UserParameters.scala +++ b/src/main/scala/com/danielasfregola/twitter4s/http/clients/streaming/users/parameters/UserParameters.scala @@ -1,5 +1,6 @@ package com.danielasfregola.twitter4s.http.clients.streaming.users.parameters +import com.danielasfregola.twitter4s.entities.enums.FilterLevel.FilterLevel import com.danielasfregola.twitter4s.entities.enums.Language.Language import com.danielasfregola.twitter4s.entities.enums.WithFilter.WithFilter import com.danielasfregola.twitter4s.http.marshalling.Parameters @@ -10,4 +11,5 @@ private[twitter4s] final case class UserParameters(`with`: WithFilter, locations: Seq[Double], stringify_friend_ids: Boolean, language: Seq[Language], - stall_warnings: Boolean) extends Parameters + stall_warnings: Boolean, + filter_level: FilterLevel) extends Parameters diff --git a/src/main/scala/com/danielasfregola/twitter4s/http/marshalling/BodyEncoder.scala b/src/main/scala/com/danielasfregola/twitter4s/http/marshalling/BodyEncoder.scala index 3428c90e..85b8a267 100644 --- a/src/main/scala/com/danielasfregola/twitter4s/http/marshalling/BodyEncoder.scala +++ b/src/main/scala/com/danielasfregola/twitter4s/http/marshalling/BodyEncoder.scala @@ -18,9 +18,9 @@ trait BodyEncoder { private def toBodyAsMap(cc: Product): Map[String, String] = asMap(cc).flatMap { case (k, head :: tail) => Some(k -> (head +: tail).mkString(",")) - case (k, Nil) => None - case (k, None) => None - case (k, Some("")) => None + case (_, Nil) => None + case (_, None) => None + case (_, Some("")) => None case (k, Some(v)) => Some(k -> v.toString) case (k, v) => Some(k -> v.toString) } diff --git a/src/test/scala/com/danielasfregola/twitter4s/http/clients/streaming/statuses/TwitterStatusClientSpec.scala b/src/test/scala/com/danielasfregola/twitter4s/http/clients/streaming/statuses/TwitterStatusClientSpec.scala index ab65f438..386ccaa2 100644 --- a/src/test/scala/com/danielasfregola/twitter4s/http/clients/streaming/statuses/TwitterStatusClientSpec.scala +++ b/src/test/scala/com/danielasfregola/twitter4s/http/clients/streaming/statuses/TwitterStatusClientSpec.scala @@ -19,7 +19,7 @@ class TwitterStatusClientSpec extends ClientSpec { request.method === HttpMethods.POST request.uri.endpoint === "https://stream.twitter.com/1.1/statuses/filter.json" request.entity === HttpEntity(`application/x-www-form-urlencoded`, - "follow=1%2C2%2C3&language=hu%2Cbn&stall_warnings=false&track=trending%2Cother") + "filter_level=none&follow=1%2C2%2C3&language=hu%2Cbn&stall_warnings=false&track=trending%2Cother") } .respondWithOk .await @@ -32,7 +32,7 @@ class TwitterStatusClientSpec extends ClientSpec { .expectRequest { request => request.method === HttpMethods.GET request.uri.endpoint === "https://stream.twitter.com/1.1/statuses/sample.json" - request.uri.queryString() === Some("language=hu,bn&stall_warnings=false") + request.uri.queryString() === Some("filter_level=none&language=hu,bn&stall_warnings=false") } .respondWithOk .await diff --git a/src/test/scala/com/danielasfregola/twitter4s/http/clients/streaming/users/TwitterUserClientSpec.scala b/src/test/scala/com/danielasfregola/twitter4s/http/clients/streaming/users/TwitterUserClientSpec.scala index 6cb14a59..eff2303a 100644 --- a/src/test/scala/com/danielasfregola/twitter4s/http/clients/streaming/users/TwitterUserClientSpec.scala +++ b/src/test/scala/com/danielasfregola/twitter4s/http/clients/streaming/users/TwitterUserClientSpec.scala @@ -15,7 +15,7 @@ class TwitterUserClientSpec extends ClientSpec { when(userEvents(tracks = Seq("trending"), languages = Seq(Language.English))(dummyProcessing)).expectRequest { request => request.method === HttpMethods.GET request.uri.endpoint === "https://userstream.twitter.com/1.1/user.json" - request.uri.queryString() === Some("language=en&stall_warnings=false&stringify_friend_ids=false&track=trending&with=followings") + request.uri.queryString() === Some("filter_level=none&language=en&stall_warnings=false&stringify_friend_ids=false&track=trending&with=followings") }.respondWithOk.await result.isInstanceOf[Unit] should beTrue }