-
Notifications
You must be signed in to change notification settings - Fork 16
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* Add Admin::Account and Role entities * Add Admin::Account methods * Move AccountOrigin, AccountStatus, ActionAgainstAccount to separate file * Offer parsed permissions in addition to raw permissions from API * Add explanatory comments for bitwise operations
- Loading branch information
1 parent
6960044
commit 90c8259
Showing
22 changed files
with
1,542 additions
and
14 deletions.
There are no files selected for viewing
184 changes: 184 additions & 0 deletions
184
bigbone-rx/src/main/kotlin/social/bigbone/rx/admin/RxAdminAccountMethods.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,184 @@ | ||
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.AccountOrigin | ||
import social.bigbone.api.entity.admin.AccountStatus | ||
import social.bigbone.api.entity.admin.ActionAgainstAccount | ||
import social.bigbone.api.entity.admin.AdminAccount | ||
import social.bigbone.api.method.admin.AdminAccountMethods | ||
|
||
/** | ||
* Reactive implementation of [AdminAccountMethods]. | ||
* | ||
* Perform moderation actions with accounts. | ||
* | ||
* @see <a href="https://docs.joinmastodon.org/methods/admin/accounts/">Mastodon admin/accounts API methods</a> | ||
*/ | ||
class RxAdminAccountMethods(client: MastodonClient) { | ||
|
||
private val adminAccountMethods = AdminAccountMethods(client) | ||
|
||
/** | ||
* View all accounts, optionally matching certain criteria for filtering, up to 100 at a time. | ||
* | ||
* @param range optional Range for the pageable return value | ||
* @param origin Filter for [AccountOrigin.Local] or [AccountOrigin.Remote] | ||
* @param status Filter for [AccountStatus] accounts | ||
* @param permissions Filter for accounts with <code>staff</code> permissions (users that can manage reports) | ||
* @param roleIds Filter for users with these roles | ||
* @param invitedById Lookup users invited by the account with this ID | ||
* @param username Search for the given username | ||
* @param displayName Search for the given display name | ||
* @param byDomain Filter by the given domain | ||
* @param emailAddress Lookup a user with this email | ||
* @param ipAddress Lookup users with this IP address | ||
* | ||
* @see <a href="https://docs.joinmastodon.org/methods/admin/accounts/#v2">Mastodon API documentation: admin/accounts/#v2</a> | ||
*/ | ||
@JvmOverloads | ||
fun viewAccounts( | ||
range: Range = Range(), | ||
origin: AccountOrigin? = null, | ||
status: AccountStatus? = null, | ||
permissions: String? = null, | ||
roleIds: List<String>? = null, | ||
invitedById: String? = null, | ||
username: String? = null, | ||
displayName: String? = null, | ||
byDomain: String? = null, | ||
emailAddress: String? = null, | ||
ipAddress: String? = null | ||
): Single<Pageable<AdminAccount>> = Single.fromCallable { | ||
adminAccountMethods.viewAccounts( | ||
range = range, | ||
origin = origin, | ||
status = status, | ||
permissions = permissions, | ||
roleIds = roleIds, | ||
invitedById = invitedById, | ||
username = username, | ||
displayName = displayName, | ||
byDomain = byDomain, | ||
emailAddress = emailAddress, | ||
ipAddress = ipAddress | ||
).execute() | ||
} | ||
|
||
/** | ||
* View admin-level information about the given account. | ||
* | ||
* @param withId The ID of the account in the database. | ||
* | ||
* @see <a href="https://docs.joinmastodon.org/methods/admin/accounts/#get-one">Mastodon API documentation: admin/accounts/#get-one</a> | ||
*/ | ||
fun viewAccount(withId: String): Single<AdminAccount> = Single.fromCallable { | ||
adminAccountMethods.viewAccount(withId = withId).execute() | ||
} | ||
|
||
/** | ||
* Approve the given local account if it is currently pending approval. | ||
* | ||
* @param withId The ID of the account in the database. | ||
* | ||
* @see <a href="https://docs.joinmastodon.org/methods/admin/accounts/#approve">Mastodon API documentation: admin/accounts/#approve</a> | ||
*/ | ||
fun approvePendingAccount(withId: String): Single<AdminAccount> = Single.fromCallable { | ||
adminAccountMethods.approvePendingAccount(withId = withId).execute() | ||
} | ||
|
||
/** | ||
* Reject the given local account if it is currently pending approval. | ||
* | ||
* @param withId The ID of the account in the database. | ||
* | ||
* @see <a href="https://docs.joinmastodon.org/methods/admin/accounts/#reject">Mastodon API documentation: admin/accounts/#reject</a> | ||
*/ | ||
fun rejectPendingAccount(withId: String): Single<AdminAccount> = Single.fromCallable { | ||
adminAccountMethods.rejectPendingAccount(withId = withId).execute() | ||
} | ||
|
||
/** | ||
* Permanently delete data for a suspended account. | ||
* | ||
* @param withId The ID of the account in the database. | ||
* | ||
* @see <a href="https://docs.joinmastodon.org/methods/admin/accounts/#delete">Mastodon API documentation: admin/accounts/#delete</a> | ||
*/ | ||
fun deleteAccount(withId: String): Single<AdminAccount> = Single.fromCallable { | ||
adminAccountMethods.deleteAccount(withId = withId).execute() | ||
} | ||
|
||
/** | ||
* Perform an action against an account and log this action in the moderation history. | ||
* Also resolves any open reports against this account. | ||
* | ||
* @param withId The ID of the account in the database. | ||
* @param type The type of action to be taken. One of [ActionAgainstAccount]. | ||
* @param text Additional clarification for why this action was taken. | ||
* @param reportId The ID of an associated report that caused this action to be taken. | ||
* @param warningPresetId The ID of a preset warning. | ||
* @param sendEmailNotification Whether an email should be sent to the user with the above information. | ||
* | ||
* @see <a href="https://docs.joinmastodon.org/methods/admin/accounts/#action">Mastodon API documentation: admin/accounts/#action</a> | ||
*/ | ||
@JvmOverloads | ||
fun performActionAgainstAccount( | ||
withId: String, | ||
type: ActionAgainstAccount, | ||
text: String? = null, | ||
reportId: String? = null, | ||
warningPresetId: String? = null, | ||
sendEmailNotification: Boolean? = null | ||
): Completable { | ||
return Completable.fromAction { | ||
adminAccountMethods.performActionAgainstAccount( | ||
withId = withId, | ||
type = type, | ||
text = text, | ||
reportId = reportId, | ||
warningPresetId = warningPresetId, | ||
sendEmailNotification = sendEmailNotification | ||
) | ||
} | ||
} | ||
|
||
/** | ||
* Re-enable a local account whose login is currently disabled. | ||
* | ||
* @see <a href="https://docs.joinmastodon.org/methods/admin/accounts/#enable">Mastodon API documentation: admin/accounts/#enable</a> | ||
*/ | ||
fun enableDisabledAccount(withId: String): Single<AdminAccount> = Single.fromCallable { | ||
adminAccountMethods.enableDisabledAccount(withId = withId).execute() | ||
} | ||
|
||
/** | ||
* Unsilence an account if it is currently silenced. | ||
* | ||
* @see <a href="https://docs.joinmastodon.org/methods/admin/accounts/#unsilence">Mastodon API documentation: admin/accounts/#unsilence</a> | ||
*/ | ||
fun unsilenceAccount(withId: String): Single<AdminAccount> = Single.fromCallable { | ||
adminAccountMethods.unsilenceAccount(withId = withId).execute() | ||
} | ||
|
||
/** | ||
* Unsuspend a currently suspended account. | ||
* | ||
* @see <a href="https://docs.joinmastodon.org/methods/admin/accounts/#unsuspend">Mastodon API documentation: admin/accounts/#unsuspend</a> | ||
*/ | ||
fun unsuspendAccount(withId: String): Single<AdminAccount> = Single.fromCallable { | ||
adminAccountMethods.unsuspendAccount(withId = withId).execute() | ||
} | ||
|
||
/** | ||
* Stops marking an account's posts as sensitive, if it was previously flagged as sensitive. | ||
* | ||
* @see <a href="https://docs.joinmastodon.org/methods/admin/accounts/#unsensitive">Mastodon API documentation: admin/accounts/#unsensitive</a> | ||
*/ | ||
fun unmarkAccountAsSensitive(withId: String): Single<AdminAccount> = Single.fromCallable { | ||
adminAccountMethods.unmarkAccountAsSensitive(withId = withId).execute() | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
134 changes: 134 additions & 0 deletions
134
bigbone/src/main/kotlin/social/bigbone/api/entity/Role.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,134 @@ | ||
package social.bigbone.api.entity | ||
|
||
import kotlinx.serialization.SerialName | ||
import kotlinx.serialization.Serializable | ||
import social.bigbone.DateTimeSerializer | ||
import social.bigbone.PrecisionDateTime | ||
import social.bigbone.api.entity.Role.Permission | ||
|
||
/** | ||
* Represents a custom user role that grants permissions. | ||
* | ||
* @see <a href="https://docs.joinmastodon.org/entities/Role/">Mastodon API Role</a> | ||
*/ | ||
@Serializable | ||
data class Role( | ||
/** | ||
* The ID of the Role in the database. | ||
*/ | ||
@SerialName("id") | ||
val id: Int, | ||
|
||
/** | ||
* The name of the role. | ||
*/ | ||
@SerialName("name") | ||
val name: String, | ||
|
||
/** | ||
* The hex code assigned to this role. | ||
* If no hex code is assigned, the string will be empty. | ||
*/ | ||
@SerialName("color") | ||
val color: String, | ||
|
||
/** | ||
* A bitmask that represents the sum of all permissions granted to the role. | ||
* Possible values can be found in [Permission]. | ||
* | ||
* For convenience, use [getParsedPermissions] to directly get a list of [Permission]s seen in this field. | ||
*/ | ||
@SerialName("permissions") | ||
val rawPermissions: Int, | ||
|
||
/** | ||
* Whether the role is publicly visible as a badge on user profiles. | ||
*/ | ||
@SerialName("highlighted") | ||
val highlighted: Boolean, | ||
|
||
/** | ||
* When the role was first assigned. | ||
*/ | ||
@SerialName("created_at") | ||
@Serializable(with = DateTimeSerializer::class) | ||
val createdAt: PrecisionDateTime = PrecisionDateTime.InvalidPrecisionDateTime.Unavailable, | ||
|
||
/** | ||
* When the role was last updated. | ||
*/ | ||
@SerialName("updated_at") | ||
@Serializable(with = DateTimeSerializer::class) | ||
val updatedAt: PrecisionDateTime = PrecisionDateTime.InvalidPrecisionDateTime.Unavailable | ||
) { | ||
|
||
/** | ||
* Returns whether this role grants the [Permission] specified in [permission]. | ||
* The Mastodon API returns permissions as a bitmask in [rawPermissions]. | ||
* | ||
* Example: [rawPermissions] reading 65536 (0b10000000000000000) would return true for [Permission.InviteUsers] | ||
* because its bits match when comparing bitwise. | ||
*/ | ||
@Suppress("DataClassContainsFunctions") | ||
fun hasPermission(permission: Permission): Boolean = rawPermissions and permission.bitValue == permission.bitValue | ||
|
||
/** | ||
* Gets [rawPermissions] and checks for all available [Permission]s which of them are part of the bitmask. | ||
* | ||
* 458_736 returned by the API. | ||
* In binary, that would be: 1101111111111110000 | ||
* | ||
* 1101111111111110000 contains all the following permissions represented by their binary values: | ||
* 10000 --- ManageReports | ||
* 100000 --- ManageFederation | ||
* 1000000 --- ManageSettings | ||
* 10000000 --- ManageBlocks | ||
* 100000000 --- ManageTaxonomies | ||
* 1000000000 --- ManageAppeals | ||
* 10000000000 --- ManageUsers | ||
* 100000000000 --- ManageInvites | ||
* 1000000000000 --- ManageRules | ||
* 10000000000000 --- ManageAnnouncements | ||
* 100000000000000 --- ManageCustomEmojis | ||
* 1000000000000000 --- ManageWebhooks | ||
* 100000000000000000 --- ManageRoles | ||
* 1000000000000000000 --- ManageUserAccess | ||
* | ||
* @return [Permission]s masked in [rawPermissions], i.e. permissions this Role has. | ||
*/ | ||
@Suppress("DataClassContainsFunctions") | ||
fun getParsedPermissions(): List<Permission> = Permission.entries.filter(::hasPermission) | ||
|
||
/** | ||
* Possible Permission Flag values masked in [rawPermissions]. | ||
* | ||
* Use [hasPermission] to check for a specific permission’s availability, or [getParsedPermissions] to get a list | ||
* of [Permission]s. | ||
*/ | ||
enum class Permission(val bitValue: Int) { | ||
Administrator(0b1), // 0x1 / 1 | ||
DevOps(0b10), // 0x2 / 2 | ||
|
||
ViewAuditLog(0b100), // 0x4 / 4 | ||
ViewDashboard(0b1000), // 0x8 / 8 | ||
|
||
ManageReports(0b10000), // 0x10 / 16 | ||
ManageFederation(0b100000), // 0x20 / 32 | ||
ManageSettings(0b1000000), // 0x40 / 64 | ||
ManageBlocks(0b10000000), // 0x80 / 128 | ||
ManageTaxonomies(0b100000000), // 0x100 / 256 | ||
ManageAppeals(0b1000000000), // 0x200 / 512 | ||
ManageUsers(0b10000000000), // 0x400 / 1024 | ||
ManageInvites(0b100000000000), // 0x800 / 2048 | ||
ManageRules(0b1000000000000), // 0x1000 / 4096 | ||
ManageAnnouncements(0b10000000000000), // 0x2000 / 8192 | ||
ManageCustomEmojis(0b100000000000000), // 0x4000 / 16384 | ||
ManageWebhooks(0b1000000000000000), // 0x8000 / 32768 | ||
ManageRoles(0b100000000000000000), // 0x20000 / 131072 | ||
ManageUserAccess(0b1000000000000000000), // 0x40000 / 262144 | ||
|
||
InviteUsers(0b10000000000000000), // 0x10000 / 65536 | ||
|
||
DeleteUserData(0b10000000000000000000) // 0x80000 / 524288 | ||
} | ||
} |
16 changes: 16 additions & 0 deletions
16
bigbone/src/main/kotlin/social/bigbone/api/entity/admin/AccountOrigin.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
package social.bigbone.api.entity.admin | ||
|
||
import social.bigbone.api.method.admin.AdminAccountMethods | ||
import java.util.Locale | ||
|
||
/** | ||
* Filter that can be used when viewing all accounts via [AdminAccountMethods.viewAccounts]. | ||
* Filters for accounts that are either only local or only remote. | ||
*/ | ||
enum class AccountOrigin { | ||
|
||
Local, | ||
Remote; | ||
|
||
fun apiName(): String = name.lowercase(Locale.ENGLISH) | ||
} |
19 changes: 19 additions & 0 deletions
19
bigbone/src/main/kotlin/social/bigbone/api/entity/admin/AccountStatus.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
package social.bigbone.api.entity.admin | ||
|
||
import social.bigbone.api.method.admin.AdminAccountMethods | ||
import java.util.Locale | ||
|
||
/** | ||
* Filter that can be used when viewing all accounts via [AdminAccountMethods.viewAccounts]. | ||
* Filters for accounts that have one of the available status types of this class. | ||
*/ | ||
enum class AccountStatus { | ||
|
||
Active, | ||
Pending, | ||
Disabled, | ||
Silenced, | ||
Suspended; | ||
|
||
fun apiName(): String = name.lowercase(Locale.ENGLISH) | ||
} |
Oops, something went wrong.