Skip to content

Commit

Permalink
Add Admin::DomainAllow methods (#413)
Browse files Browse the repository at this point in the history
* add methods for admin-related domain allowing
  • Loading branch information
G10xy authored Dec 30, 2023
1 parent 90c8259 commit 887d8f6
Show file tree
Hide file tree
Showing 9 changed files with 311 additions and 11 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
package social.bigbone.rx.admin

import io.reactivex.rxjava3.core.Completable
import io.reactivex.rxjava3.core.Single
import social.bigbone.MastodonClient
import social.bigbone.api.Pageable
import social.bigbone.api.Range
import social.bigbone.api.entity.admin.AdminDomainAllow
import social.bigbone.api.method.admin.AdminDomainAllowMethods

/**
* Reactive implementation of [AdminDomainAllowMethods].
*
* Allow certain domains to federate.
* @see <a href="https://docs.joinmastodon.org/methods/admin/domain_allows/">Mastodon admin/domain_allows API methods</a>
*/
class RxAdminDomainAllowMethods(client: MastodonClient) {

private val adminAllowMethods = AdminDomainAllowMethods(client)

/**
* Show information about all allowed domains.
* @param range optional Range for the pageable return value
* @see <a href="https://docs.joinmastodon.org/methods/domain_allows/#get">Mastodon API documentation: methods/domain_allows/#get</a>
*/
@JvmOverloads
fun getAllAllowedDomains(range: Range = Range()): Single<Pageable<AdminDomainAllow>> = Single.fromCallable {
adminAllowMethods.getAllAllowedDomains(range = range).execute()
}

/**
* Show information about a single allowed domain.
* @param id The ID of the DomainAllow in the database.
* @see <a href="https://docs.joinmastodon.org/methods/domain_allows/#get-one">Mastodon API documentation: methods/domain_allows/#get-one</a>
*/
fun getAllowedDomain(id: String): Single<AdminDomainAllow> = Single.fromCallable {
adminAllowMethods.getAllowedDomain(id = id).execute()
}

/**
* Add a domain to the list of domains allowed to federate, to be used when the instance is in allow-list federation mode.
* @param domain The domain to allow federation with.
* @see <a href="https://docs.joinmastodon.org/methods/admin/domain_allows/#create">Mastodon API documentation: admin/domain_allows/#create</a>
*/
fun allowDomainToFederate(domain: String): Single<AdminDomainAllow> = Single.fromCallable {
adminAllowMethods.allowDomainToFederate(domain = domain).execute()
}

/**
* Delete a domain from the allowed domains list.
* @param id The ID of the DomainAllow in the database.
* @see <a href="https://docs.joinmastodon.org/methods/admin/domain_allows/#delete">Mastodon API documentation: admin/domain_allows/#delete</a>
*/
fun removeAllowedDomain(id: String): Completable = Completable.fromAction {
adminAllowMethods.removeAllowedDomain(id = id)
}
}
8 changes: 8 additions & 0 deletions bigbone/src/main/kotlin/social/bigbone/MastodonClient.kt
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ import social.bigbone.api.method.TrendMethods
import social.bigbone.api.method.admin.AdminAccountMethods
import social.bigbone.api.method.admin.AdminCanonicalEmailBlockMethods
import social.bigbone.api.method.admin.AdminDimensionMethods
import social.bigbone.api.method.admin.AdminDomainAllowMethods
import social.bigbone.api.method.admin.AdminDomainBlockMethods
import social.bigbone.api.method.admin.AdminEmailDomainBlockMethods
import social.bigbone.api.method.admin.AdminIpBlockMethods
Expand Down Expand Up @@ -130,6 +131,13 @@ private constructor(
@get:JvmName("adminDimensions")
val adminDimensions: AdminDimensionMethods by lazy { AdminDimensionMethods(this) }

/**
* Access API methods under the "admin/domain_allows" endpoint.
*/
@Suppress("unused") // public API
@get:JvmName("adminDomainAllow")
val adminDomainAllow: AdminDomainAllowMethods by lazy { AdminDomainAllowMethods(this) }

/**
* Access API methods under the "admin/domain_blocks" endpoint.
*/
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package social.bigbone.api.entity.admin

import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
import social.bigbone.DateTimeSerializer
import social.bigbone.PrecisionDateTime

/**
* Represents a domain allowed to federate.
* @see <a href="https://docs.joinmastodon.org/entities/Admin_DomainAllow/">Mastodon API Admin::DomainAllow/</a>
*/
@Serializable
data class AdminDomainAllow(
/**
* The ID of the DomainAllow in the database.
*/
@SerialName("id")
val id: String = "0",

/**
* The domain that is allowed to federate.
*/
@SerialName("domain")
val domain: String = "",

/**
* When the domain was allowed to federate.
*/
@SerialName("created_at")
@Serializable(with = DateTimeSerializer::class)
val createdAt: PrecisionDateTime = PrecisionDateTime.InvalidPrecisionDateTime.Unavailable
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
package social.bigbone.api.method.admin

import social.bigbone.MastodonClient
import social.bigbone.MastodonRequest
import social.bigbone.Parameters
import social.bigbone.api.Pageable
import social.bigbone.api.Range
import social.bigbone.api.entity.admin.AdminDomainAllow

/**
* Allow certain domains to federate.
* @see <a href="https://docs.joinmastodon.org/methods/admin/domain_allows/">Mastodon admin/domain_allows API methods</a>
*/
class AdminDomainAllowMethods(private val client: MastodonClient) {

private val adminDomainAllowEndpoint = "api/v1/admin/domain_allows"

/**
* Show information about all allowed domains.
* @param range optional Range for the pageable return value
* @see <a href="https://docs.joinmastodon.org/methods/domain_allows/#get">Mastodon API documentation: methods/domain_allows/#get</a>
*/
@JvmOverloads
fun getAllAllowedDomains(range: Range = Range()): MastodonRequest<Pageable<AdminDomainAllow>> {
return client.getPageableMastodonRequest(
endpoint = adminDomainAllowEndpoint,
method = MastodonClient.Method.GET,
parameters = range.toParameters()
)
}

/**
* Show information about a single allowed domain.
* @param id The ID of the DomainAllow in the database.
* @see <a href="https://docs.joinmastodon.org/methods/domain_allows/#get-one">Mastodon API documentation: methods/domain_allows/#get-one</a>
*/
fun getAllowedDomain(id: String): MastodonRequest<AdminDomainAllow> {
return client.getMastodonRequest(
endpoint = "$adminDomainAllowEndpoint/$id",
method = MastodonClient.Method.GET
)
}

/**
* Add a domain to the list of domains allowed to federate, to be used when the instance is in allow-list federation mode.
* @param domain The domain to allow federation with.
* @see <a href="https://docs.joinmastodon.org/methods/admin/domain_allows/#create">Mastodon API documentation: admin/domain_allows/#create</a>
*/
fun allowDomainToFederate(domain: String): MastodonRequest<AdminDomainAllow> {
return client.getMastodonRequest(
endpoint = adminDomainAllowEndpoint,
method = MastodonClient.Method.POST,
parameters = Parameters().apply {
append("domain", domain)
}
)
}

/**
* Delete a domain from the allowed domains list.
* @param id The ID of the DomainAllow in the database.
* @see <a href="https://docs.joinmastodon.org/methods/admin/domain_allows/#delete">Mastodon API documentation: admin/domain_allows/#delete</a>
*/
fun removeAllowedDomain(id: String) {
client.performAction(
endpoint = "$adminDomainAllowEndpoint/$id",
method = MastodonClient.Method.DELETE
)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import social.bigbone.api.entity.admin.AdminDomainBlock.Severity
*/
class AdminDomainBlockMethods(private val client: MastodonClient) {

private val adminDomainBlocksEndpoint = "api/v1/admin/domain_blocks"
private val endpoint = "api/v1/admin/domain_blocks"

/**
* Show information about all blocked domains.
Expand All @@ -27,7 +27,7 @@ class AdminDomainBlockMethods(private val client: MastodonClient) {
@JvmOverloads
fun getAllBlockedDomains(range: Range = Range()): MastodonRequest<Pageable<AdminDomainBlock>> {
return client.getPageableMastodonRequest(
endpoint = adminDomainBlocksEndpoint,
endpoint = endpoint,
method = MastodonClient.Method.GET,
parameters = range.toParameters()
)
Expand All @@ -42,7 +42,7 @@ class AdminDomainBlockMethods(private val client: MastodonClient) {
*/
fun getBlockedDomain(id: String): MastodonRequest<AdminDomainBlock> {
return client.getMastodonRequest(
endpoint = "$adminDomainBlocksEndpoint/$id",
endpoint = "$endpoint/$id",
method = MastodonClient.Method.GET
)
}
Expand Down Expand Up @@ -71,7 +71,7 @@ class AdminDomainBlockMethods(private val client: MastodonClient) {
publicComment: String? = null
): MastodonRequest<AdminDomainBlock> {
return client.getMastodonRequest(
endpoint = adminDomainBlocksEndpoint,
endpoint = endpoint,
method = MastodonClient.Method.POST,
parameters = Parameters().apply {
append("domain", domain)
Expand Down Expand Up @@ -113,7 +113,7 @@ class AdminDomainBlockMethods(private val client: MastodonClient) {
publicComment: String? = null
): MastodonRequest<AdminDomainBlock> {
return client.getMastodonRequest(
endpoint = "$adminDomainBlocksEndpoint/$id",
endpoint = "$endpoint/$id",
method = MastodonClient.Method.PUT,
parameters = Parameters().apply {
severity?.let { append("severity", severity.apiName) }
Expand All @@ -138,7 +138,7 @@ class AdminDomainBlockMethods(private val client: MastodonClient) {
*/
fun removeBlockedDomain(id: String) {
client.performAction(
endpoint = "$adminDomainBlocksEndpoint/$id",
endpoint = "$endpoint/$id",
method = MastodonClient.Method.DELETE
)
}
Expand Down
5 changes: 5 additions & 0 deletions bigbone/src/test/assets/admin_domain_allow.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"id": "1",
"domain": "mastodon.social",
"created_at": "2022-09-14T21:23:02.755Z"
}
12 changes: 12 additions & 0 deletions bigbone/src/test/assets/admin_domain_allow_list.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
[
{
"id": "2",
"domain": "mastodon",
"created_at": "2022-09-14T21:24:15.360Z"
},
{
"id": "1",
"domain": "mastodon.social",
"created_at": "2022-09-14T21:23:02.755Z"
}
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
package social.bigbone.api.method.admin

import io.mockk.slot
import io.mockk.verify
import org.amshove.kluent.AnyException
import org.amshove.kluent.invoking
import org.amshove.kluent.shouldBeEqualTo
import org.amshove.kluent.shouldNotThrow
import org.amshove.kluent.shouldThrow
import org.amshove.kluent.withMessage
import org.junit.jupiter.api.Test
import social.bigbone.MastodonClient
import social.bigbone.Parameters
import social.bigbone.api.Range
import social.bigbone.api.exception.BigBoneRequestException
import social.bigbone.testtool.MockClient

class AdminDomainAllowMethodsTest {

private val adminDomainAllowEndpoint = "api/v1/admin/domain_allows"

@Test
fun `Given client returning success, when getting all allowed domains, then return list of allowed domains`() {
val client = MockClient.mock("admin_domain_allow_list.json")
val adminDomainAllowMethods = AdminDomainAllowMethods(client)
val range = Range("1", "10", "1", 10)
val allowedDomains = adminDomainAllowMethods.getAllAllowedDomains(range).execute()
allowedDomains.part.size shouldBeEqualTo 2
with(allowedDomains.part[1]) {
id shouldBeEqualTo "1"
domain shouldBeEqualTo "mastodon.social"
}

val parametersCapturingSlot = slot<Parameters>()
verify {
client.get(
path = adminDomainAllowEndpoint,
query = capture(parametersCapturingSlot)
)
}
with(parametersCapturingSlot.captured) {
toQuery() shouldBeEqualTo "max_id=${range.maxId}&min_id=${range.minId}&since_id=${range.sinceId}&limit=${range.limit}"
}
}

@Test
fun `Given client returning success, when getting specific allowed domain, then return expected data for single domain`() {
val client = MockClient.mock("admin_domain_allow.json")
val adminDomainAllowMethods = AdminDomainAllowMethods(client)
val pathVariable = "1"
val adminDomainAllowed = adminDomainAllowMethods.getAllowedDomain(pathVariable).execute()
with(adminDomainAllowed) {
id shouldBeEqualTo pathVariable
domain shouldBeEqualTo "mastodon.social"
}

verify {
client.get(
path = "$adminDomainAllowEndpoint/$pathVariable"
)
}
}

@Test
fun `Given client returning success, when posting a domain to be allowed to federate, then return expected data about the domain`() {
val client = MockClient.mock("admin_domain_allow.json")
val adminDomainAllowMethods = AdminDomainAllowMethods(client)

invoking {
adminDomainAllowMethods.allowDomainToFederate(domain = "mastodon.social").execute()
} shouldNotThrow AnyException

val parametersCapturingSlot = slot<Parameters>()
verify {
client.post(
path = adminDomainAllowEndpoint,
body = capture(parametersCapturingSlot),
addIdempotencyKey = false
)
}
with(parametersCapturingSlot.captured) {
toQuery() shouldBeEqualTo "domain=mastodon.social"
}
}

@Test
fun `Given client returning success, when removing specific domain from being allowd, then check data for single ip`() {
val client = MockClient.mock("admin_domain_allow.json")
val adminDomainAllowMethods = AdminDomainAllowMethods(client)
val id = "1"

invoking {
adminDomainAllowMethods.removeAllowedDomain(id = id)
} shouldNotThrow AnyException

verify {
client.performAction(
endpoint = "$adminDomainAllowEndpoint/$id",
method = MastodonClient.Method.DELETE
)
}
}

@Test
fun `Given a client returning forbidden, when getting specific allowed domain, then propagate error`() {
val client = MockClient.failWithResponse(
responseJsonAssetPath = "error_403_forbidden.json",
responseCode = 403,
message = "Forbidden"
)

invoking {
AdminDomainAllowMethods(client).getAllowedDomain(id = "1").execute()
} shouldThrow BigBoneRequestException::class withMessage "Forbidden"
}
}
10 changes: 5 additions & 5 deletions docs/api-coverage/admin/domain-allows.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@ nav_order: 7
<a href="https://docs.joinmastodon.org/methods/admin/domain_allows/" target="_blank">https://docs.joinmastodon.org/methods/admin/domain_allows/</a>

| Method | Description | Status | Comments |
|------------------------------------------|-----------------------------|--------|----------|
| `GET /api/v1/admin/domain_allows` | List all allowed domains | 🔴 | |
| `GET /api/v1/admin/domain_allows/:id` | Get a single allowed domain | 🔴 | |
| `POST /api/v1/admin/domain_allows` | Allow a domain to federate | 🔴 | |
| `DELETE /api/v1/admin/domain_allows/:id` | Delete an allowed domain | 🔴 | |
|------------------------------------------|-----------------------------|----|--|
| `GET /api/v1/admin/domain_allows` | List all allowed domains | <img src="/assets/green16.png"> | Fully supported. |
| `GET /api/v1/admin/domain_allows/:id` | Get a single allowed domain | <img src="/assets/green16.png"> | Fully supported. |
| `POST /api/v1/admin/domain_allows` | Allow a domain to federate | <img src="/assets/green16.png"> | Fully supported. |
| `DELETE /api/v1/admin/domain_allows/:id` | Delete an allowed domain | <img src="/assets/green16.png"> | Fully supported. |

0 comments on commit 887d8f6

Please sign in to comment.