mirror of
https://github.com/revanced/revanced-api.git
synced 2025-04-29 22:24:31 +02:00
feat: Add GPG key to team members
This commit is contained in:
parent
6b3dbab90b
commit
71f58cf352
@ -1,9 +1,9 @@
|
|||||||
package app.revanced.api.configuration
|
package app.revanced.api.configuration
|
||||||
|
|
||||||
import app.revanced.api.configuration.repository.AnnouncementRepository
|
import app.revanced.api.configuration.repository.AnnouncementRepository
|
||||||
|
import app.revanced.api.configuration.repository.BackendRepository
|
||||||
import app.revanced.api.configuration.repository.ConfigurationRepository
|
import app.revanced.api.configuration.repository.ConfigurationRepository
|
||||||
import app.revanced.api.configuration.repository.backend.BackendRepository
|
import app.revanced.api.configuration.repository.GitHubBackendRepository
|
||||||
import app.revanced.api.configuration.repository.backend.github.GitHubBackendRepository
|
|
||||||
import app.revanced.api.configuration.services.AnnouncementService
|
import app.revanced.api.configuration.services.AnnouncementService
|
||||||
import app.revanced.api.configuration.services.ApiService
|
import app.revanced.api.configuration.services.ApiService
|
||||||
import app.revanced.api.configuration.services.AuthService
|
import app.revanced.api.configuration.services.AuthService
|
||||||
|
@ -0,0 +1,7 @@
|
|||||||
|
package app.revanced.api.configuration
|
||||||
|
|
||||||
|
import io.ktor.http.*
|
||||||
|
import io.ktor.server.application.*
|
||||||
|
import io.ktor.server.response.*
|
||||||
|
|
||||||
|
suspend fun ApplicationCall.respondOrNotFound(value: Any?) = respond(value ?: HttpStatusCode.NotFound)
|
@ -13,6 +13,7 @@ fun Application.configureSerialization() {
|
|||||||
json(
|
json(
|
||||||
Json {
|
Json {
|
||||||
namingStrategy = JsonNamingStrategy.SnakeCase
|
namingStrategy = JsonNamingStrategy.SnakeCase
|
||||||
|
explicitNulls = false
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,7 @@
|
|||||||
package app.revanced.api.configuration.repository.backend
|
package app.revanced.api.configuration.repository
|
||||||
|
|
||||||
import io.ktor.client.*
|
import io.ktor.client.*
|
||||||
import kotlinx.datetime.LocalDateTime
|
import kotlinx.datetime.LocalDateTime
|
||||||
import kotlinx.serialization.Serializable
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The backend of the application used to get data for the API.
|
* The backend of the application used to get data for the API.
|
||||||
@ -40,7 +39,7 @@ abstract class BackendRepository internal constructor(
|
|||||||
* @property avatarUrl The URL to the avatar of the member.
|
* @property avatarUrl The URL to the avatar of the member.
|
||||||
* @property url The URL to the profile of the member.
|
* @property url The URL to the profile of the member.
|
||||||
* @property bio The bio of the member.
|
* @property bio The bio of the member.
|
||||||
* @property gpgKeysUrl The URL to the GPG keys of the member.
|
* @property gpgKeys The GPG key of the member.
|
||||||
*/
|
*/
|
||||||
@Serializable
|
@Serializable
|
||||||
class BackendMember(
|
class BackendMember(
|
||||||
@ -48,8 +47,19 @@ abstract class BackendRepository internal constructor(
|
|||||||
override val avatarUrl: String,
|
override val avatarUrl: String,
|
||||||
override val url: String,
|
override val url: String,
|
||||||
val bio: String?,
|
val bio: String?,
|
||||||
val gpgKeysUrl: String,
|
val gpgKeys: GpgKeys,
|
||||||
) : BackendUser
|
) : BackendUser {
|
||||||
|
/**
|
||||||
|
* The GPG keys of a member.
|
||||||
|
*
|
||||||
|
* @property ids The IDs of the GPG keys.
|
||||||
|
* @property url The URL to the GPG master key.
|
||||||
|
*/
|
||||||
|
class GpgKeys(
|
||||||
|
val ids: Set<String>,
|
||||||
|
val url: String,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A repository of an organization.
|
* A repository of an organization.
|
||||||
@ -67,7 +77,6 @@ abstract class BackendRepository internal constructor(
|
|||||||
* @property url The URL to the profile of the contributor.
|
* @property url The URL to the profile of the contributor.
|
||||||
* @property contributions The number of contributions of the contributor.
|
* @property contributions The number of contributions of the contributor.
|
||||||
*/
|
*/
|
||||||
@Serializable
|
|
||||||
class BackendContributor(
|
class BackendContributor(
|
||||||
override val name: String,
|
override val name: String,
|
||||||
override val avatarUrl: String,
|
override val avatarUrl: String,
|
||||||
@ -83,7 +92,6 @@ abstract class BackendRepository internal constructor(
|
|||||||
* @property createdAt The date and time the release was created.
|
* @property createdAt The date and time the release was created.
|
||||||
* @property releaseNote The release note of the release.
|
* @property releaseNote The release note of the release.
|
||||||
*/
|
*/
|
||||||
@Serializable
|
|
||||||
class BackendRelease(
|
class BackendRelease(
|
||||||
val tag: String,
|
val tag: String,
|
||||||
val releaseNote: String,
|
val releaseNote: String,
|
||||||
@ -95,7 +103,6 @@ abstract class BackendRepository internal constructor(
|
|||||||
*
|
*
|
||||||
* @property downloadUrl The URL to download the asset.
|
* @property downloadUrl The URL to download the asset.
|
||||||
*/
|
*/
|
||||||
@Serializable
|
|
||||||
class BackendAsset(
|
class BackendAsset(
|
||||||
val downloadUrl: String,
|
val downloadUrl: String,
|
||||||
)
|
)
|
@ -0,0 +1,203 @@
|
|||||||
|
package app.revanced.api.configuration.repository
|
||||||
|
|
||||||
|
import app.revanced.api.configuration.repository.BackendRepository.BackendOrganization.BackendMember
|
||||||
|
import app.revanced.api.configuration.repository.BackendRepository.BackendOrganization.BackendRepository.BackendContributor
|
||||||
|
import app.revanced.api.configuration.repository.BackendRepository.BackendOrganization.BackendRepository.BackendRelease
|
||||||
|
import app.revanced.api.configuration.repository.BackendRepository.BackendOrganization.BackendRepository.BackendRelease.BackendAsset
|
||||||
|
import app.revanced.api.configuration.repository.GitHubOrganization.GitHubRepository.GitHubContributor
|
||||||
|
import app.revanced.api.configuration.repository.GitHubOrganization.GitHubRepository.GitHubRelease
|
||||||
|
import app.revanced.api.configuration.repository.Organization.Repository.Contributors
|
||||||
|
import app.revanced.api.configuration.repository.Organization.Repository.Releases
|
||||||
|
import io.ktor.client.*
|
||||||
|
import io.ktor.client.call.*
|
||||||
|
import io.ktor.client.plugins.resources.*
|
||||||
|
import io.ktor.resources.*
|
||||||
|
import kotlinx.coroutines.*
|
||||||
|
import kotlinx.datetime.Instant
|
||||||
|
import kotlinx.datetime.TimeZone
|
||||||
|
import kotlinx.datetime.toLocalDateTime
|
||||||
|
import kotlinx.serialization.Serializable
|
||||||
|
|
||||||
|
class GitHubBackendRepository(client: HttpClient) : BackendRepository(client) {
|
||||||
|
override suspend fun release(
|
||||||
|
owner: String,
|
||||||
|
repository: String,
|
||||||
|
tag: String?,
|
||||||
|
): BackendRelease {
|
||||||
|
val release: GitHubRelease = if (tag != null) {
|
||||||
|
client.get(Releases.Tag(owner, repository, tag)).body()
|
||||||
|
} else {
|
||||||
|
client.get(Releases.Latest(owner, repository)).body()
|
||||||
|
}
|
||||||
|
|
||||||
|
return BackendRelease(
|
||||||
|
tag = release.tagName,
|
||||||
|
releaseNote = release.body,
|
||||||
|
createdAt = release.createdAt.toLocalDateTime(TimeZone.UTC),
|
||||||
|
assets = release.assets.map {
|
||||||
|
BackendAsset(downloadUrl = it.browserDownloadUrl)
|
||||||
|
}.toSet(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun contributors(
|
||||||
|
owner: String,
|
||||||
|
repository: String,
|
||||||
|
): Set<BackendContributor> {
|
||||||
|
val contributors: Set<GitHubContributor> = client.get(
|
||||||
|
Contributors(
|
||||||
|
owner,
|
||||||
|
repository,
|
||||||
|
),
|
||||||
|
).body()
|
||||||
|
|
||||||
|
return contributors.map {
|
||||||
|
BackendContributor(
|
||||||
|
name = it.login,
|
||||||
|
avatarUrl = it.avatarUrl,
|
||||||
|
url = it.htmlUrl,
|
||||||
|
contributions = it.contributions,
|
||||||
|
)
|
||||||
|
}.toSet()
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun members(organization: String): Set<BackendMember> {
|
||||||
|
// Get the list of members of the organization.
|
||||||
|
val members: Set<GitHubOrganization.GitHubMember> = client.get(Organization.Members(organization)).body()
|
||||||
|
|
||||||
|
return coroutineScope {
|
||||||
|
members.map { member ->
|
||||||
|
async {
|
||||||
|
awaitAll(
|
||||||
|
async {
|
||||||
|
// Get the user.
|
||||||
|
client.get(User(member.login)).body<GitHubUser>()
|
||||||
|
},
|
||||||
|
async {
|
||||||
|
// Get the GPG key of the user.
|
||||||
|
client.get(User.GpgKeys(member.login)).body<Set<GitHubUser.GitHubGpgKey>>()
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}.awaitAll().map { responses ->
|
||||||
|
val user = responses[0] as GitHubUser
|
||||||
|
|
||||||
|
@Suppress("UNCHECKED_CAST")
|
||||||
|
val gpgKeys = responses[1] as Set<GitHubUser.GitHubGpgKey>
|
||||||
|
|
||||||
|
BackendMember(
|
||||||
|
name = user.login,
|
||||||
|
avatarUrl = user.avatarUrl,
|
||||||
|
url = user.htmlUrl,
|
||||||
|
bio = user.bio,
|
||||||
|
gpgKeys =
|
||||||
|
BackendMember.GpgKeys(
|
||||||
|
ids = gpgKeys.map { it.keyId }.toSet(),
|
||||||
|
url = "https://api.github.com/users/${user.login}.gpg",
|
||||||
|
),
|
||||||
|
)
|
||||||
|
}.toSet()
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun rateLimit(): BackendRateLimit {
|
||||||
|
val rateLimit: GitHubRateLimit = client.get(RateLimit()).body()
|
||||||
|
|
||||||
|
return BackendRateLimit(
|
||||||
|
limit = rateLimit.rate.limit,
|
||||||
|
remaining = rateLimit.rate.remaining,
|
||||||
|
reset = Instant.fromEpochSeconds(rateLimit.rate.reset).toLocalDateTime(TimeZone.UTC),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
interface IGitHubUser {
|
||||||
|
val login: String
|
||||||
|
val avatarUrl: String
|
||||||
|
val htmlUrl: String
|
||||||
|
}
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
class GitHubUser(
|
||||||
|
override val login: String,
|
||||||
|
override val avatarUrl: String,
|
||||||
|
override val htmlUrl: String,
|
||||||
|
val bio: String?,
|
||||||
|
) : IGitHubUser {
|
||||||
|
@Serializable
|
||||||
|
class GitHubGpgKey(
|
||||||
|
val keyId: String,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
class GitHubOrganization {
|
||||||
|
@Serializable
|
||||||
|
class GitHubMember(
|
||||||
|
override val login: String,
|
||||||
|
override val avatarUrl: String,
|
||||||
|
override val htmlUrl: String,
|
||||||
|
) : IGitHubUser
|
||||||
|
|
||||||
|
class GitHubRepository {
|
||||||
|
@Serializable
|
||||||
|
class GitHubContributor(
|
||||||
|
override val login: String,
|
||||||
|
override val avatarUrl: String,
|
||||||
|
override val htmlUrl: String,
|
||||||
|
val contributions: Int,
|
||||||
|
) : IGitHubUser
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
class GitHubRelease(
|
||||||
|
val tagName: String,
|
||||||
|
val assets: Set<GitHubAsset>,
|
||||||
|
val createdAt: Instant,
|
||||||
|
val body: String,
|
||||||
|
) {
|
||||||
|
@Serializable
|
||||||
|
class GitHubAsset(
|
||||||
|
val browserDownloadUrl: String,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
class GitHubRateLimit(
|
||||||
|
val rate: Rate,
|
||||||
|
) {
|
||||||
|
@Serializable
|
||||||
|
class Rate(
|
||||||
|
val limit: Int,
|
||||||
|
val remaining: Int,
|
||||||
|
val reset: Long,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Resource("/users/{login}")
|
||||||
|
class User(val login: String) {
|
||||||
|
@Resource("/users/{login}/gpg_keys")
|
||||||
|
class GpgKeys(val login: String)
|
||||||
|
}
|
||||||
|
|
||||||
|
class Organization {
|
||||||
|
@Resource("/orgs/{org}/members")
|
||||||
|
class Members(val org: String)
|
||||||
|
|
||||||
|
class Repository {
|
||||||
|
@Resource("/repos/{owner}/{repo}/contributors")
|
||||||
|
class Contributors(val owner: String, val repo: String)
|
||||||
|
|
||||||
|
@Resource("/repos/{owner}/{repo}/releases")
|
||||||
|
class Releases(val owner: String, val repo: String) {
|
||||||
|
@Resource("/repos/{owner}/{repo}/releases/tags/{tag}")
|
||||||
|
class Tag(val owner: String, val repo: String, val tag: String)
|
||||||
|
|
||||||
|
@Resource("/repos/{owner}/{repo}/releases/latest")
|
||||||
|
class Latest(val owner: String, val repo: String)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Resource("/rate_limit")
|
||||||
|
class RateLimit
|
@ -1,83 +0,0 @@
|
|||||||
package app.revanced.api.configuration.repository.backend.github
|
|
||||||
|
|
||||||
import app.revanced.api.configuration.repository.backend.BackendRepository
|
|
||||||
import app.revanced.api.configuration.repository.backend.BackendRepository.BackendOrganization.BackendMember
|
|
||||||
import app.revanced.api.configuration.repository.backend.BackendRepository.BackendOrganization.BackendRepository.BackendContributor
|
|
||||||
import app.revanced.api.configuration.repository.backend.BackendRepository.BackendOrganization.BackendRepository.BackendRelease
|
|
||||||
import app.revanced.api.configuration.repository.backend.BackendRepository.BackendOrganization.BackendRepository.BackendRelease.BackendAsset
|
|
||||||
import app.revanced.api.configuration.repository.backend.github.api.Request
|
|
||||||
import app.revanced.api.configuration.repository.backend.github.api.Request.Organization.Members
|
|
||||||
import app.revanced.api.configuration.repository.backend.github.api.Request.Organization.Repository.Contributors
|
|
||||||
import app.revanced.api.configuration.repository.backend.github.api.Request.Organization.Repository.Releases
|
|
||||||
import app.revanced.api.configuration.repository.backend.github.api.Response
|
|
||||||
import app.revanced.api.configuration.repository.backend.github.api.Response.GitHubOrganization.GitHubMember
|
|
||||||
import app.revanced.api.configuration.repository.backend.github.api.Response.GitHubOrganization.GitHubRepository.GitHubContributor
|
|
||||||
import app.revanced.api.configuration.repository.backend.github.api.Response.GitHubOrganization.GitHubRepository.GitHubRelease
|
|
||||||
import io.ktor.client.*
|
|
||||||
import io.ktor.client.call.*
|
|
||||||
import io.ktor.client.plugins.resources.*
|
|
||||||
import kotlinx.coroutines.*
|
|
||||||
import kotlinx.datetime.TimeZone
|
|
||||||
import kotlinx.datetime.toLocalDateTime
|
|
||||||
|
|
||||||
class GitHubBackendRepository(client: HttpClient) : BackendRepository(client) {
|
|
||||||
override suspend fun release(
|
|
||||||
owner: String,
|
|
||||||
repository: String,
|
|
||||||
tag: String?,
|
|
||||||
): BackendRelease {
|
|
||||||
val release: GitHubRelease = if (tag != null) {
|
|
||||||
client.get(Releases.Tag(owner, repository, tag)).body()
|
|
||||||
} else {
|
|
||||||
client.get(Releases.Latest(owner, repository)).body()
|
|
||||||
}
|
|
||||||
|
|
||||||
return BackendRelease(
|
|
||||||
tag = release.tagName,
|
|
||||||
releaseNote = release.body,
|
|
||||||
createdAt = release.createdAt.toLocalDateTime(TimeZone.UTC),
|
|
||||||
assets = release.assets.map {
|
|
||||||
BackendAsset(downloadUrl = it.browserDownloadUrl)
|
|
||||||
}.toSet(),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
override suspend fun contributors(
|
|
||||||
owner: String,
|
|
||||||
repository: String,
|
|
||||||
): Set<BackendContributor> {
|
|
||||||
val contributors: Set<GitHubContributor> = client.get(Contributors(owner, repository)).body()
|
|
||||||
|
|
||||||
return contributors.map {
|
|
||||||
BackendContributor(
|
|
||||||
name = it.login,
|
|
||||||
avatarUrl = it.avatarUrl,
|
|
||||||
url = it.url,
|
|
||||||
contributions = it.contributions,
|
|
||||||
)
|
|
||||||
}.toSet()
|
|
||||||
}
|
|
||||||
|
|
||||||
override suspend fun members(organization: String): Set<BackendMember> {
|
|
||||||
// Get the list of members of the organization.
|
|
||||||
val members: Set<GitHubMember> = client.get(Members(organization)).body()
|
|
||||||
|
|
||||||
return runBlocking(Dispatchers.Default) {
|
|
||||||
members.map { member ->
|
|
||||||
// Map the member to a user in order to get the bio.
|
|
||||||
async {
|
|
||||||
client.get(Request.User(member.login)).body<Response.GitHubUser>()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}.awaitAll().map { user ->
|
|
||||||
// Map the user back to a member.
|
|
||||||
BackendMember(
|
|
||||||
name = user.login,
|
|
||||||
avatarUrl = user.avatarUrl,
|
|
||||||
url = user.url,
|
|
||||||
bio = user.bio,
|
|
||||||
gpgKeysUrl = "https://github.com/${user.login}.gpg",
|
|
||||||
)
|
|
||||||
}.toSet()
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,27 +0,0 @@
|
|||||||
package app.revanced.api.configuration.repository.backend.github.api
|
|
||||||
|
|
||||||
import io.ktor.resources.*
|
|
||||||
|
|
||||||
class Request {
|
|
||||||
@Resource("/users/{username}")
|
|
||||||
class User(val username: String)
|
|
||||||
|
|
||||||
class Organization {
|
|
||||||
@Resource("/orgs/{org}/members")
|
|
||||||
class Members(val org: String)
|
|
||||||
|
|
||||||
class Repository {
|
|
||||||
@Resource("/repos/{owner}/{repo}/contributors")
|
|
||||||
class Contributors(val owner: String, val repo: String)
|
|
||||||
|
|
||||||
@Resource("/repos/{owner}/{repo}/releases")
|
|
||||||
class Releases(val owner: String, val repo: String) {
|
|
||||||
@Resource("/repos/{owner}/{repo}/releases/tags/{tag}")
|
|
||||||
class Tag(val owner: String, val repo: String, val tag: String)
|
|
||||||
|
|
||||||
@Resource("/repos/{owner}/{repo}/releases/latest")
|
|
||||||
class Latest(val owner: String, val repo: String)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,52 +0,0 @@
|
|||||||
package app.revanced.api.configuration.repository.backend.github.api
|
|
||||||
|
|
||||||
import kotlinx.datetime.Instant
|
|
||||||
import kotlinx.serialization.Serializable
|
|
||||||
|
|
||||||
class Response {
|
|
||||||
interface IGitHubUser {
|
|
||||||
val login: String
|
|
||||||
val avatarUrl: String
|
|
||||||
val url: String
|
|
||||||
}
|
|
||||||
|
|
||||||
@Serializable
|
|
||||||
class GitHubUser(
|
|
||||||
override val login: String,
|
|
||||||
override val avatarUrl: String,
|
|
||||||
override val url: String,
|
|
||||||
val bio: String?,
|
|
||||||
) : IGitHubUser
|
|
||||||
|
|
||||||
class GitHubOrganization {
|
|
||||||
@Serializable
|
|
||||||
class GitHubMember(
|
|
||||||
override val login: String,
|
|
||||||
override val avatarUrl: String,
|
|
||||||
override val url: String,
|
|
||||||
) : IGitHubUser
|
|
||||||
|
|
||||||
class GitHubRepository {
|
|
||||||
@Serializable
|
|
||||||
class GitHubContributor(
|
|
||||||
override val login: String,
|
|
||||||
override val avatarUrl: String,
|
|
||||||
override val url: String,
|
|
||||||
val contributions: Int,
|
|
||||||
) : IGitHubUser
|
|
||||||
|
|
||||||
@Serializable
|
|
||||||
class GitHubRelease(
|
|
||||||
val tagName: String,
|
|
||||||
val assets: Set<GitHubAsset>,
|
|
||||||
val createdAt: Instant,
|
|
||||||
val body: String,
|
|
||||||
) {
|
|
||||||
@Serializable
|
|
||||||
class GitHubAsset(
|
|
||||||
val browserDownloadUrl: String,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,9 +1,9 @@
|
|||||||
package app.revanced.api.configuration.routing.routes
|
package app.revanced.api.configuration.routing.routes
|
||||||
|
|
||||||
|
import app.revanced.api.configuration.respondOrNotFound
|
||||||
import app.revanced.api.configuration.schema.APIAnnouncement
|
import app.revanced.api.configuration.schema.APIAnnouncement
|
||||||
import app.revanced.api.configuration.schema.APIAnnouncementArchivedAt
|
import app.revanced.api.configuration.schema.APIAnnouncementArchivedAt
|
||||||
import app.revanced.api.configuration.services.AnnouncementService
|
import app.revanced.api.configuration.services.AnnouncementService
|
||||||
import io.ktor.http.*
|
|
||||||
import io.ktor.server.application.*
|
import io.ktor.server.application.*
|
||||||
import io.ktor.server.auth.*
|
import io.ktor.server.auth.*
|
||||||
import io.ktor.server.request.*
|
import io.ktor.server.request.*
|
||||||
@ -19,17 +19,13 @@ internal fun Route.announcementsRoute() = route("announcements") {
|
|||||||
get("id") {
|
get("id") {
|
||||||
val channel: String by call.parameters
|
val channel: String by call.parameters
|
||||||
|
|
||||||
call.respond(
|
call.respondOrNotFound(announcementService.latestId(channel))
|
||||||
announcementService.latestId(channel) ?: return@get call.respond(HttpStatusCode.NotFound),
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
get {
|
get {
|
||||||
val channel: String by call.parameters
|
val channel: String by call.parameters
|
||||||
|
|
||||||
call.respond(
|
call.respondOrNotFound(announcementService.latest(channel))
|
||||||
announcementService.latest(channel) ?: return@get call.respond(HttpStatusCode.NotFound),
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -41,11 +37,11 @@ internal fun Route.announcementsRoute() = route("announcements") {
|
|||||||
|
|
||||||
route("latest") {
|
route("latest") {
|
||||||
get("id") {
|
get("id") {
|
||||||
call.respond(announcementService.latestId() ?: return@get call.respond(HttpStatusCode.NotFound))
|
call.respondOrNotFound(announcementService.latestId())
|
||||||
}
|
}
|
||||||
|
|
||||||
get {
|
get {
|
||||||
call.respond(announcementService.latest() ?: return@get call.respond(HttpStatusCode.NotFound))
|
call.respondOrNotFound(announcementService.latest())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -73,8 +69,9 @@ internal fun Route.announcementsRoute() = route("announcements") {
|
|||||||
|
|
||||||
patch("{id}") {
|
patch("{id}") {
|
||||||
val id: Int by call.parameters
|
val id: Int by call.parameters
|
||||||
|
val announcement = call.receive<APIAnnouncement>()
|
||||||
|
|
||||||
announcementService.update(id, call.receive<APIAnnouncement>())
|
announcementService.update(id, announcement)
|
||||||
}
|
}
|
||||||
|
|
||||||
delete("{id}") {
|
delete("{id}") {
|
||||||
|
@ -23,9 +23,15 @@ class APIMember(
|
|||||||
override val name: String,
|
override val name: String,
|
||||||
override val avatarUrl: String,
|
override val avatarUrl: String,
|
||||||
override val url: String,
|
override val url: String,
|
||||||
val gpgKeysUrl: String,
|
val gpgKey: APIGpgKey?,
|
||||||
) : APIUser
|
) : APIUser
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
class APIGpgKey(
|
||||||
|
val id: String,
|
||||||
|
val url: String,
|
||||||
|
)
|
||||||
|
|
||||||
@Serializable
|
@Serializable
|
||||||
class APIContributor(
|
class APIContributor(
|
||||||
override val name: String,
|
override val name: String,
|
||||||
|
@ -1,10 +1,8 @@
|
|||||||
package app.revanced.api.configuration.services
|
package app.revanced.api.configuration.services
|
||||||
|
|
||||||
|
import app.revanced.api.configuration.repository.BackendRepository
|
||||||
import app.revanced.api.configuration.repository.ConfigurationRepository
|
import app.revanced.api.configuration.repository.ConfigurationRepository
|
||||||
import app.revanced.api.configuration.repository.backend.BackendRepository
|
import app.revanced.api.configuration.schema.*
|
||||||
import app.revanced.api.configuration.schema.APIContributable
|
|
||||||
import app.revanced.api.configuration.schema.APIContributor
|
|
||||||
import app.revanced.api.configuration.schema.APIMember
|
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.async
|
import kotlinx.coroutines.async
|
||||||
import kotlinx.coroutines.awaitAll
|
import kotlinx.coroutines.awaitAll
|
||||||
@ -27,7 +25,21 @@ internal class ApiService(
|
|||||||
}
|
}
|
||||||
}.awaitAll()
|
}.awaitAll()
|
||||||
|
|
||||||
suspend fun team() = backendRepository.members(configurationRepository.organization).map {
|
suspend fun team() = backendRepository.members(configurationRepository.organization).map { member ->
|
||||||
APIMember(it.name, it.avatarUrl, it.url, it.gpgKeysUrl)
|
APIMember(
|
||||||
|
member.name,
|
||||||
|
member.avatarUrl,
|
||||||
|
member.url,
|
||||||
|
if (member.gpgKeys.ids.isNotEmpty()) {
|
||||||
|
APIGpgKey(
|
||||||
|
// Must choose one of the GPG keys, because it does not make sense to have multiple GPG keys for the API.
|
||||||
|
member.gpgKeys.ids.first(),
|
||||||
|
member.gpgKeys.url,
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
null
|
||||||
|
},
|
||||||
|
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
package app.revanced.api.configuration.services
|
package app.revanced.api.configuration.services
|
||||||
|
|
||||||
|
import app.revanced.api.configuration.repository.BackendRepository
|
||||||
import app.revanced.api.configuration.repository.ConfigurationRepository
|
import app.revanced.api.configuration.repository.ConfigurationRepository
|
||||||
import app.revanced.api.configuration.repository.backend.BackendRepository
|
|
||||||
import app.revanced.api.configuration.schema.APIAsset
|
import app.revanced.api.configuration.schema.APIAsset
|
||||||
import app.revanced.api.configuration.schema.APIRelease
|
import app.revanced.api.configuration.schema.APIRelease
|
||||||
import app.revanced.api.configuration.schema.APIReleaseVersion
|
import app.revanced.api.configuration.schema.APIReleaseVersion
|
||||||
|
Loading…
x
Reference in New Issue
Block a user