Skip to content

Commit

Permalink
Implement featured_tags API (andregasser#283)
Browse files Browse the repository at this point in the history
* Add getFeaturedTags endpoint

* Add featureTag endpoint

* Add unfeatureTag endpoint

* Add suggested tags for featuredTags endpoint

* Add client-side validation for tag to be featured

* Add client-side validation for tag id blankness when unfeaturing

* Add Rx implementation

* Use Kotlin stdlib's require instead of throwing ourselves
  • Loading branch information
PattaFeuFeu authored Oct 15, 2023
1 parent 6ad62ac commit 06c53e5
Show file tree
Hide file tree
Showing 12 changed files with 470 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
package social.bigbone.rx

import io.reactivex.rxjava3.core.Single
import social.bigbone.MastodonClient
import social.bigbone.MastodonRequest
import social.bigbone.api.entity.FeaturedTag
import social.bigbone.api.entity.Tag
import social.bigbone.api.exception.BigBoneRequestException
import social.bigbone.api.method.FeaturedTagsMethods

/**
* Reactive implementation of [FeaturedTagsMethods].
* View information about Feature tags that you use frequently on your profile.
* @see <a href="https://docs.joinmastodon.org/methods/featured_tags/">Mastodon featured_tags API methods</a>
*/
class RxFeaturedTagsMethods(client: MastodonClient) {

private val featuredTagsMethods = FeaturedTagsMethods(client)

/**
* List all hashtags featured on your profile.
* @return List of [FeaturedTag]s on your profile
*/
fun getFeaturedTags(): Single<MastodonRequest<List<FeaturedTag>>> {
return Single.create {
try {
it.onSuccess(featuredTagsMethods.getFeaturedTags())
} catch (e: Throwable) {
it.onError(e)
}
}
}

/**
* Promote a hashtag on your profile.
* @param tagName The hashtag to be featured, without the hash sign.
* @return The [FeaturedTag] successfully created
*/
fun featureTag(tagName: String): Single<MastodonRequest<FeaturedTag>> {
return Single.create {
try {
it.onSuccess(featuredTagsMethods.featureTag(tagName))
} catch (e: Throwable) {
it.onError(e)
}
}
}

/**
* Stop promoting a hashtag on your profile.
* @param tagId The ID of the FeaturedTag in the database you want to stop promoting.
*/
@Throws(BigBoneRequestException::class)
fun unfeatureTag(tagId: String): Single<Any> {
return Single.create {
try {
it.onSuccess(featuredTagsMethods.unfeatureTag(tagId))
} catch (e: Throwable) {
it.onError(e)
}
}
}

/**
* Shows up to 10 recently-used tags.
* @return List of up to 10 recently-used [Tag]s to feature.
*/
fun getSuggestedTags(): Single<MastodonRequest<List<Tag>>> {
return Single.create {
try {
it.onSuccess(featuredTagsMethods.getSuggestedTags())
} catch (e: Throwable) {
it.onError(e)
}
}
}
}
39 changes: 39 additions & 0 deletions bigbone/src/main/kotlin/social/bigbone/api/entity/FeaturedTag.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package social.bigbone.api.entity

import com.google.gson.annotations.SerializedName

/**
* Represents a hashtag that is featured on a profile.
* @see <a href="https://docs.joinmastodon.org/entities/FeaturedTag/">Mastodon API FeaturedTag</a>
*/
data class FeaturedTag(
/**
* The internal ID of the featured tag in the database.
*/
@SerializedName("id")
val id: String = "",

/**
* The name of the hashtag being featured.
*/
@SerializedName("name")
val name: String = "",

/**
* A link to all statuses by a user that contain this hashtag.
*/
@SerializedName("url")
val url: String = "",

/**
* A link to all statuses by a user that contain this hashtag.
*/
@SerializedName("statuses_count")
val statusesCount: Int = 0,

/**
* The timestamp of the last authored status containing this hashtag.
*/
@SerializedName("last_status_at")
val lastStatusAt: String = ""
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
package social.bigbone.api.method

import social.bigbone.MastodonClient
import social.bigbone.MastodonRequest
import social.bigbone.Parameters
import social.bigbone.api.entity.FeaturedTag
import social.bigbone.api.entity.Tag
import social.bigbone.api.exception.BigBoneRequestException

/**
* View information about Feature tags that you use frequently on your profile.
* @see <a href="https://docs.joinmastodon.org/methods/featured_tags/">Mastodon featured_tags API methods</a>
*/
class FeaturedTagsMethods(private val client: MastodonClient) {

private val featuredTagsEndpoint = "api/v1/featured_tags"

/**
* List all hashtags featured on your profile.
* @return List of [FeaturedTag]s on your profile
*/
fun getFeaturedTags(): MastodonRequest<List<FeaturedTag>> {
return client.getMastodonRequestForList(
endpoint = featuredTagsEndpoint,
method = MastodonClient.Method.GET
)
}

/**
* Promote a hashtag on your profile.
* @param tagName The hashtag to be featured, without the hash character.
* @return The [FeaturedTag] successfully created
* @throws IllegalArgumentException if [tagName] contains a #
*/
@Throws(IllegalArgumentException::class)
fun featureTag(tagName: String): MastodonRequest<FeaturedTag> {
require(!tagName.contains('#')) { "Tag name to be featured must not contain '#'" }

return client.getMastodonRequest(
endpoint = featuredTagsEndpoint,
method = MastodonClient.Method.POST,
parameters = Parameters().append("name", tagName)
)
}

/**
* Stop promoting a hashtag on your profile.
* @param tagId The ID of the FeaturedTag in the database you want to stop promoting.
* @throws IllegalArgumentException if [tagId] is blank
* @throws BigBoneRequestException if request to unfeature tag failed for any reason
*/
@Throws(BigBoneRequestException::class, IllegalArgumentException::class)
fun unfeatureTag(tagId: String) {
require(tagId.isNotBlank()) { "Tag ID must not be blank" }

client.performAction(
endpoint = featuredTagsEndpoint,
method = MastodonClient.Method.DELETE,
parameters = Parameters().append("id", tagId)
)
}

/**
* Shows up to 10 recently-used tags.
* @return List of up to 10 recently-used [Tag]s to feature.
*/
fun getSuggestedTags(): MastodonRequest<List<Tag>> {
return client.getMastodonRequestForList(
endpoint = "$featuredTagsEndpoint/suggestions",
method = MastodonClient.Method.GET
)
}

}
3 changes: 3 additions & 0 deletions bigbone/src/test/assets/error_401_unauthorized.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"error": "The access token is invalid"
}
3 changes: 3 additions & 0 deletions bigbone/src/test/assets/error_404.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"error": "Record not found"
}
1 change: 1 addition & 0 deletions bigbone/src/test/assets/featured_tags_delete_success.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{}
3 changes: 3 additions & 0 deletions bigbone/src/test/assets/featured_tags_post_error_422.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"error": "Validation failed: Tag is invalid"
}
7 changes: 7 additions & 0 deletions bigbone/src/test/assets/featured_tags_post_success.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"id": "13174",
"name": "nowplaying",
"url": "https://mastodon.example/@user/tagged/nowplaying",
"statuses_count": 23,
"last_status_at": "2021-10-22T14:47:35.357Z"
}
9 changes: 9 additions & 0 deletions bigbone/src/test/assets/featured_tags_view_success.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
[
{
"id": "627",
"name": "nowplaying",
"url": "https://mastodon.example/@user/tagged/nowplaying",
"statuses_count": 70,
"last_status_at": "2022-08-29T12:03:35.061Z"
}
]
74 changes: 74 additions & 0 deletions bigbone/src/test/assets/featured_tags_view_suggested_success.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
[
{
"name": "nowplaying",
"url": "https://mastodon.example/tags/nowplaying",
"history": [
{
"day": "1574553600",
"uses": "200",
"accounts": "31"
},
{
"day": "1574467200",
"uses": "272",
"accounts": "39"
},
{
"day": "1574380800",
"uses": "345",
"accounts": "40"
},
{
"day": "1574294400",
"uses": "366",
"accounts": "46"
},
{
"day": "1574208000",
"uses": "226",
"accounts": "32"
},
{
"day": "1574121600",
"uses": "217",
"accounts": "42"
},
{
"day": "1574035200",
"uses": "214",
"accounts": "34"
}
]
},
{
"name": "mastothemes",
"url": "https://mastodon.example/tags/mastothemes",
"history": [
{
"day": "1574553600",
"uses": "0",
"accounts": "0"
},
{
"day": "1574467200",
"uses": "0",
"accounts": "0"
},
{
"day": "1574380800",
"uses": "0",
"accounts": "0"
},
{
"day": "1574294400",
"uses": "0",
"accounts": "0"
},
{
"day": "1574208000",
"uses": "0",
"accounts": "0"
}
]
}
]
Loading

0 comments on commit 06c53e5

Please sign in to comment.