diff --git a/bigbone-rx/src/main/kotlin/social/bigbone/rx/admin/RxAdminEmailDomainBlockMethods.kt b/bigbone-rx/src/main/kotlin/social/bigbone/rx/admin/RxAdminEmailDomainBlockMethods.kt
new file mode 100644
index 000000000..721ca494d
--- /dev/null
+++ b/bigbone-rx/src/main/kotlin/social/bigbone/rx/admin/RxAdminEmailDomainBlockMethods.kt
@@ -0,0 +1,65 @@
+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.AdminEmailDomainBlock
+import social.bigbone.api.method.admin.AdminEmailDomainBlockMethods
+
+/**
+ * Reactive implementation of [AdminEmailDomainBlockMethods].
+ *
+ * Disallow certain email domains from signing up.
+ *
+ * @see Mastodon admin/email_domain_blocks API methods
+ */
+class RxAdminEmailDomainBlockMethods(client: MastodonClient) {
+
+ private val adminEmailDomainBlockMethods = AdminEmailDomainBlockMethods(client)
+
+ /**
+ * Show information about all email domains blocked from signing up.
+ *
+ * @param range optional Range for the pageable return value
+ *
+ * @see Mastodon API documentation: admin/email_domain_blocks/#get
+ */
+ @JvmOverloads
+ fun getAllEmailDomainBlocks(range: Range = Range()): Single> = Single.fromCallable {
+ adminEmailDomainBlockMethods.getAllEmailDomainBlocks(range).execute()
+ }
+
+ /**
+ * Show information about a single email domain that is blocked from signups.
+ *
+ * @param id The ID of the EmailDomainBlock in the database.
+ * @see
+ * Mastodon API documentation: admin/email_domain_blocks/#get-one
+ */
+ fun getEmailDomainBlock(id: String): Single = Single.fromCallable {
+ adminEmailDomainBlockMethods.getEmailDomainBlock(id).execute()
+ }
+
+ /**
+ * Add a domain to the list of email domains blocked from signups.
+ *
+ * @param domain The domain to block federation with.
+ * @see Mastodon API documentation: admin/email_domain_blocks/#create
+ */
+ fun blockEmailDomain(domain: String): Single = Single.fromCallable {
+ adminEmailDomainBlockMethods.blockEmailDomain(domain).execute()
+ }
+
+ /**
+ * Lift a block against an email domain.
+ *
+ * @param id The ID of the EmailDomainBlock in the database.
+ *
+ * @see Mastodon API documentation: admin/email_domain_blocks/#delete
+ */
+ fun removeEmailDomainBlock(id: String) = Completable.fromAction {
+ adminEmailDomainBlockMethods.removeEmailDomainBlock(id)
+ }
+}
diff --git a/bigbone/src/main/kotlin/social/bigbone/MastodonClient.kt b/bigbone/src/main/kotlin/social/bigbone/MastodonClient.kt
index f3218b035..1c3e6b08e 100644
--- a/bigbone/src/main/kotlin/social/bigbone/MastodonClient.kt
+++ b/bigbone/src/main/kotlin/social/bigbone/MastodonClient.kt
@@ -67,6 +67,7 @@ import social.bigbone.api.method.TimelineMethods
import social.bigbone.api.method.TrendMethods
import social.bigbone.api.method.admin.AdminDimensionMethods
import social.bigbone.api.method.admin.AdminDomainBlockMethods
+import social.bigbone.api.method.admin.AdminEmailDomainBlockMethods
import social.bigbone.api.method.admin.AdminIpBlockMethods
import social.bigbone.api.method.admin.AdminMeasureMethods
import social.bigbone.api.method.admin.AdminRetentionMethods
@@ -117,8 +118,15 @@ private constructor(
* Access API methods under the "admin/domain_blocks" endpoint.
*/
@Suppress("unused") // public API
- @get:JvmName("adminDomainBlock")
- val adminDomainBlock: AdminDomainBlockMethods by lazy { AdminDomainBlockMethods(this) }
+ @get:JvmName("adminDomainBlocks")
+ val adminDomainBlocks: AdminDomainBlockMethods by lazy { AdminDomainBlockMethods(this) }
+
+ /**
+ * Access API methods under the "admin/email_domain_blocks" endpoint.
+ */
+ @Suppress("unused") // public API
+ @get:JvmName("adminEmailDomainBlocks")
+ val adminEmailDomainBlocks: AdminEmailDomainBlockMethods by lazy { AdminEmailDomainBlockMethods(this) }
/**
* Access API methods under the "admin/ip_blocks" endpoint.
diff --git a/bigbone/src/main/kotlin/social/bigbone/api/entity/admin/AdminEmailDomainBlock.kt b/bigbone/src/main/kotlin/social/bigbone/api/entity/admin/AdminEmailDomainBlock.kt
new file mode 100644
index 000000000..bae4be029
--- /dev/null
+++ b/bigbone/src/main/kotlin/social/bigbone/api/entity/admin/AdminEmailDomainBlock.kt
@@ -0,0 +1,41 @@
+package social.bigbone.api.entity.admin
+
+import kotlinx.serialization.SerialName
+import kotlinx.serialization.Serializable
+import social.bigbone.DateTimeSerializer
+import social.bigbone.PrecisionDateTime
+import social.bigbone.api.entity.data.History
+
+/**
+ * Represents an email domain that cannot be used to sign up.
+ *
+ * @see Mastodon API Admin::EmailDomainBlock documentation
+ */
+@Serializable
+data class AdminEmailDomainBlock(
+ /**
+ * The ID of the EmailDomainBlock in the database.
+ * String cast from an Integer, but not guaranteed to be a number.
+ */
+ @SerialName("id")
+ val id: String,
+
+ /**
+ * The email domain that is not allowed to be used for signups.
+ */
+ @SerialName("domain")
+ val domain: String,
+
+ /**
+ * The timestamp of the notification.
+ */
+ @SerialName("created_at")
+ @Serializable(with = DateTimeSerializer::class)
+ val createdAt: PrecisionDateTime = PrecisionDateTime.InvalidPrecisionDateTime.Unavailable,
+
+ /**
+ * Usage statistics for given days (typically the past week).
+ */
+ @SerialName("history")
+ val history: List
+)
diff --git a/bigbone/src/main/kotlin/social/bigbone/api/entity/data/History.kt b/bigbone/src/main/kotlin/social/bigbone/api/entity/data/History.kt
index e25db1e28..2d3cec6c9 100644
--- a/bigbone/src/main/kotlin/social/bigbone/api/entity/data/History.kt
+++ b/bigbone/src/main/kotlin/social/bigbone/api/entity/data/History.kt
@@ -7,6 +7,7 @@ import kotlinx.serialization.Serializable
* Usage statistics for given days (typically the past week).
* @see Mastodon API Tag history
* @see Mastodon API PreviewCard history
+ * @see Mastodon API Admin::EmailDomainBlock history
*/
@Serializable
data class History(
diff --git a/bigbone/src/main/kotlin/social/bigbone/api/method/admin/AdminEmailDomainBlockMethods.kt b/bigbone/src/main/kotlin/social/bigbone/api/method/admin/AdminEmailDomainBlockMethods.kt
new file mode 100644
index 000000000..00973bff5
--- /dev/null
+++ b/bigbone/src/main/kotlin/social/bigbone/api/method/admin/AdminEmailDomainBlockMethods.kt
@@ -0,0 +1,76 @@
+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.AdminEmailDomainBlock
+
+/**
+ * Disallow certain email domains from signing up.
+ *
+ * @see Mastodon admin/email_domain_blocks API methods
+ */
+class AdminEmailDomainBlockMethods(private val client: MastodonClient) {
+
+ private val adminEmailDomainBlockEndpoint = "api/v1/admin/email_domain_blocks"
+
+ /**
+ * Show information about all email domains blocked from signing up.
+ *
+ * @param range optional Range for the pageable return value
+ *
+ * @see Mastodon API documentation: admin/email_domain_blocks/#get
+ */
+ @JvmOverloads
+ fun getAllEmailDomainBlocks(range: Range = Range()): MastodonRequest> {
+ return client.getPageableMastodonRequest(
+ endpoint = adminEmailDomainBlockEndpoint,
+ method = MastodonClient.Method.GET,
+ parameters = range.toParameters()
+ )
+ }
+
+ /**
+ * Show information about a single email domain that is blocked from signups.
+ *
+ * @param id The ID of the EmailDomainBlock in the database.
+ * @see
+ * Mastodon API documentation: admin/email_domain_blocks/#get-one
+ */
+ fun getEmailDomainBlock(id: String): MastodonRequest {
+ return client.getMastodonRequest(
+ endpoint = "$adminEmailDomainBlockEndpoint/$id",
+ method = MastodonClient.Method.GET
+ )
+ }
+
+ /**
+ * Add a domain to the list of email domains blocked from signups.
+ *
+ * @param domain The domain to block federation with.
+ * @see Mastodon API documentation: admin/email_domain_blocks/#create
+ */
+ fun blockEmailDomain(domain: String): MastodonRequest {
+ return client.getMastodonRequest(
+ endpoint = adminEmailDomainBlockEndpoint,
+ method = MastodonClient.Method.POST,
+ parameters = Parameters().append("domain", domain)
+ )
+ }
+
+ /**
+ * Lift a block against an email domain.
+ *
+ * @param id The ID of the EmailDomainBlock in the database.
+ *
+ * @see Mastodon API documentation: admin/email_domain_blocks/#delete
+ */
+ fun removeEmailDomainBlock(id: String) {
+ client.performAction(
+ endpoint = "$adminEmailDomainBlockEndpoint/$id",
+ method = MastodonClient.Method.DELETE
+ )
+ }
+}
diff --git a/bigbone/src/test/assets/admin_email_domain_blocks_all_blocked_success.json b/bigbone/src/test/assets/admin_email_domain_blocks_all_blocked_success.json
new file mode 100644
index 000000000..3080f569b
--- /dev/null
+++ b/bigbone/src/test/assets/admin_email_domain_blocks_all_blocked_success.json
@@ -0,0 +1,44 @@
+[
+ {
+ "id": "1",
+ "domain": "foo",
+ "created_at": "2022-11-16T06:09:36.176Z",
+ "history": [
+ {
+ "day": "1668556800",
+ "accounts": "0",
+ "uses": "0"
+ },
+ {
+ "day": "1668470400",
+ "accounts": "0",
+ "uses": "0"
+ },
+ {
+ "day": "1668384000",
+ "accounts": "0",
+ "uses": "0"
+ },
+ {
+ "day": "1668297600",
+ "accounts": "0",
+ "uses": "0"
+ },
+ {
+ "day": "1668211200",
+ "accounts": "0",
+ "uses": "0"
+ },
+ {
+ "day": "1668124800",
+ "accounts": "0",
+ "uses": "0"
+ },
+ {
+ "day": "1668038400",
+ "accounts": "0",
+ "uses": "0"
+ }
+ ]
+ }
+]
diff --git a/bigbone/src/test/assets/admin_email_domain_blocks_block_success.json b/bigbone/src/test/assets/admin_email_domain_blocks_block_success.json
new file mode 100644
index 000000000..4b12867b7
--- /dev/null
+++ b/bigbone/src/test/assets/admin_email_domain_blocks_block_success.json
@@ -0,0 +1,42 @@
+{
+ "id": "1",
+ "domain": "foo",
+ "created_at": "2022-11-16T06:09:36.176Z",
+ "history": [
+ {
+ "day": "1668556800",
+ "accounts": "0",
+ "uses": "0"
+ },
+ {
+ "day": "1668470400",
+ "accounts": "0",
+ "uses": "0"
+ },
+ {
+ "day": "1668384000",
+ "accounts": "0",
+ "uses": "0"
+ },
+ {
+ "day": "1668297600",
+ "accounts": "0",
+ "uses": "0"
+ },
+ {
+ "day": "1668211200",
+ "accounts": "0",
+ "uses": "0"
+ },
+ {
+ "day": "1668124800",
+ "accounts": "0",
+ "uses": "0"
+ },
+ {
+ "day": "1668038400",
+ "accounts": "0",
+ "uses": "0"
+ }
+ ]
+}
diff --git a/bigbone/src/test/assets/admin_email_domain_blocks_delete_success.json b/bigbone/src/test/assets/admin_email_domain_blocks_delete_success.json
new file mode 100644
index 000000000..0967ef424
--- /dev/null
+++ b/bigbone/src/test/assets/admin_email_domain_blocks_delete_success.json
@@ -0,0 +1 @@
+{}
diff --git a/bigbone/src/test/assets/admin_email_domain_blocks_single_success.json b/bigbone/src/test/assets/admin_email_domain_blocks_single_success.json
new file mode 100644
index 000000000..4b12867b7
--- /dev/null
+++ b/bigbone/src/test/assets/admin_email_domain_blocks_single_success.json
@@ -0,0 +1,42 @@
+{
+ "id": "1",
+ "domain": "foo",
+ "created_at": "2022-11-16T06:09:36.176Z",
+ "history": [
+ {
+ "day": "1668556800",
+ "accounts": "0",
+ "uses": "0"
+ },
+ {
+ "day": "1668470400",
+ "accounts": "0",
+ "uses": "0"
+ },
+ {
+ "day": "1668384000",
+ "accounts": "0",
+ "uses": "0"
+ },
+ {
+ "day": "1668297600",
+ "accounts": "0",
+ "uses": "0"
+ },
+ {
+ "day": "1668211200",
+ "accounts": "0",
+ "uses": "0"
+ },
+ {
+ "day": "1668124800",
+ "accounts": "0",
+ "uses": "0"
+ },
+ {
+ "day": "1668038400",
+ "accounts": "0",
+ "uses": "0"
+ }
+ ]
+}
diff --git a/bigbone/src/test/kotlin/social/bigbone/api/method/admin/AdminEmailDomainBlockMethodsTest.kt b/bigbone/src/test/kotlin/social/bigbone/api/method/admin/AdminEmailDomainBlockMethodsTest.kt
new file mode 100644
index 000000000..9deef63fc
--- /dev/null
+++ b/bigbone/src/test/kotlin/social/bigbone/api/method/admin/AdminEmailDomainBlockMethodsTest.kt
@@ -0,0 +1,151 @@
+package social.bigbone.api.method.admin
+
+import io.mockk.slot
+import io.mockk.verify
+import org.amshove.kluent.shouldBeEmpty
+import org.amshove.kluent.shouldBeEqualTo
+import org.amshove.kluent.shouldHaveSize
+import org.junit.jupiter.api.Test
+import social.bigbone.MastodonClient
+import social.bigbone.Parameters
+import social.bigbone.PrecisionDateTime.ValidPrecisionDateTime.ExactTime
+import social.bigbone.api.Pageable
+import social.bigbone.api.Range
+import social.bigbone.api.entity.admin.AdminEmailDomainBlock
+import social.bigbone.testtool.MockClient
+import java.time.Instant
+
+class AdminEmailDomainBlockMethodsTest {
+
+ @Test
+ fun `Given client returning success, when getting all blocked Email domains without Range, then call correct endpoint and parse response`() {
+ val client = MockClient.mock("admin_email_domain_blocks_all_blocked_success.json")
+ val adminEmailDomainBlockMethods = AdminEmailDomainBlockMethods(client)
+
+ val emailDomainBlocks: Pageable = adminEmailDomainBlockMethods
+ .getAllEmailDomainBlocks()
+ .execute()
+
+ with(emailDomainBlocks.part) {
+ shouldHaveSize(1)
+
+ with(get(0)) {
+ id shouldBeEqualTo "1"
+ domain shouldBeEqualTo "foo"
+ createdAt shouldBeEqualTo ExactTime(Instant.parse("2022-11-16T06:09:36.176Z"))
+
+ history shouldHaveSize 7
+ history[0].day shouldBeEqualTo "1668556800"
+ history[0].accounts shouldBeEqualTo "0"
+ history[0].uses shouldBeEqualTo "0"
+ }
+ }
+ val parametersCapturingSlot = slot()
+ verify {
+ client.get(
+ path = "api/v1/admin/email_domain_blocks",
+ query = capture(parametersCapturingSlot)
+ )
+ }
+ with(parametersCapturingSlot.captured) {
+ toQuery().shouldBeEmpty()
+ }
+ }
+
+ @Test
+ fun `Given client returning success, when getting all blocked Email domains with Range, then use correct parameters`() {
+ val client = MockClient.mock("admin_email_domain_blocks_all_blocked_success.json")
+ val adminEmailDomainBlockMethods = AdminEmailDomainBlockMethods(client)
+ val range = Range(limit = 5, sinceId = "1234")
+
+ adminEmailDomainBlockMethods.getAllEmailDomainBlocks(range).execute()
+
+ val parametersCapturingSlot = slot()
+ verify {
+ client.get(
+ path = "api/v1/admin/email_domain_blocks",
+ query = capture(parametersCapturingSlot)
+ )
+ }
+ with(parametersCapturingSlot.captured) {
+ toQuery() shouldBeEqualTo "since_id=${range.sinceId}&limit=${range.limit}"
+ }
+ }
+
+ @Test
+ fun `Given client returning success, when getting single Email domain, then call correct endpoint and parse response`() {
+ val client = MockClient.mock("admin_email_domain_blocks_single_success.json")
+ val adminEmailDomainBlockMethods = AdminEmailDomainBlockMethods(client)
+ val requestedId = "1"
+
+ val emailDomainBlock: AdminEmailDomainBlock = adminEmailDomainBlockMethods
+ .getEmailDomainBlock(requestedId)
+ .execute()
+
+ with(emailDomainBlock) {
+ id shouldBeEqualTo "1"
+ domain shouldBeEqualTo "foo"
+ createdAt shouldBeEqualTo ExactTime(Instant.parse("2022-11-16T06:09:36.176Z"))
+
+ history shouldHaveSize 7
+ history[0].day shouldBeEqualTo "1668556800"
+ history[0].accounts shouldBeEqualTo "0"
+ history[0].uses shouldBeEqualTo "0"
+ }
+ verify {
+ client.get(
+ path = "api/v1/admin/email_domain_blocks/$requestedId",
+ query = null
+ )
+ }
+ }
+
+ @Test
+ fun `Given client returning success, when blocking an Email domain, then call correct endpoint and parse response`() {
+ val client = MockClient.mock("admin_email_domain_blocks_block_success.json")
+ val adminEmailDomainBlockMethods = AdminEmailDomainBlockMethods(client)
+ val requestedDomain = "foo"
+
+ val emailDomainBlock: AdminEmailDomainBlock = adminEmailDomainBlockMethods
+ .blockEmailDomain(requestedDomain)
+ .execute()
+
+ with(emailDomainBlock) {
+ id shouldBeEqualTo "1"
+ domain shouldBeEqualTo "foo"
+ createdAt shouldBeEqualTo ExactTime(Instant.parse("2022-11-16T06:09:36.176Z"))
+
+ history shouldHaveSize 7
+ history[0].day shouldBeEqualTo "1668556800"
+ history[0].accounts shouldBeEqualTo "0"
+ history[0].uses shouldBeEqualTo "0"
+ }
+ val parametersCapturingSlot = slot()
+ verify {
+ client.post(
+ path = "api/v1/admin/email_domain_blocks",
+ body = capture(parametersCapturingSlot)
+ )
+ }
+ with(parametersCapturingSlot.captured) {
+ toQuery() shouldBeEqualTo "domain=$requestedDomain"
+ }
+ }
+
+ @Test
+ fun `Given client returning success, when removing an Email domain block, then call correct endpoint`() {
+ val client = MockClient.mock("admin_email_domain_blocks_delete_success.json")
+ val adminEmailDomainBlockMethods = AdminEmailDomainBlockMethods(client)
+ val requestedId = "foo"
+
+ adminEmailDomainBlockMethods.removeEmailDomainBlock(requestedId)
+
+ verify {
+ client.performAction(
+ endpoint = "api/v1/admin/email_domain_blocks/$requestedId",
+ method = MastodonClient.Method.DELETE,
+ parameters = null
+ )
+ }
+ }
+}
diff --git a/docs/api-coverage/admin/email-domain-blocks.md b/docs/api-coverage/admin/email-domain-blocks.md
index bf4740c0d..1273e83a8 100644
--- a/docs/api-coverage/admin/email-domain-blocks.md
+++ b/docs/api-coverage/admin/email-domain-blocks.md
@@ -10,9 +10,9 @@ nav_order: 8
https://docs.joinmastodon.org/methods/admin/email_domain_blocks/
-| Method | Description | Status | Comments |
-|------------------------------------------------|------------------------------------|--------|----------|
-| `GET /api/v1/admin/email_domain_blocks` | List all blocked email domains | 🔴 | |
-| `GET /api/v1/admin/email_domain_blocks/:id` | Get a single blocked email domain | 🔴 | |
-| `POST /api/v1/admin/email_domain_blocks` | Block an email domain from signups | 🔴 | |
-| `DELETE /api/v1/admin/email_domain_blocks/:id` | Delete an email domain block | 🔴 | |
+| Method | Description | Status | Comments |
+|------------------------------------------------|------------------------------------|---------------------------------|-----------------|
+| `GET /api/v1/admin/email_domain_blocks` | List all blocked email domains | | Fully supported |
+| `GET /api/v1/admin/email_domain_blocks/:id` | Get a single blocked email domain | | Fully supported |
+| `POST /api/v1/admin/email_domain_blocks` | Block an email domain from signups | | Fully supported |
+| `DELETE /api/v1/admin/email_domain_blocks/:id` | Delete an email domain block | | Fully supported |