feat: Improve announcements API (#192)

Announcements can have tags now instead of being grouped into a single channel. You can get an announcement using its ID. You can page announcements and filter them by tags and whether they are archived. You can see a list of all available tags. Some route API overhaul.
This commit is contained in:
oSumAtrIX
2024-11-01 02:49:36 +01:00
committed by GitHub
parent 50b81fd337
commit 56a00ddb85
14 changed files with 632 additions and 443 deletions

View File

@@ -1,35 +1,29 @@
package app.revanced.api.configuration.services
import app.revanced.api.configuration.repository.AnnouncementRepository
import app.revanced.api.configuration.schema.APIAnnouncement
import app.revanced.api.configuration.schema.APIResponseAnnouncementId
import kotlinx.datetime.LocalDateTime
import app.revanced.api.configuration.schema.ApiAnnouncement
internal class AnnouncementService(
private val announcementRepository: AnnouncementRepository,
) {
fun latestId(channel: String): APIResponseAnnouncementId? = announcementRepository.latestId(channel)
fun latestId(): APIResponseAnnouncementId? = announcementRepository.latestId()
suspend fun latest(tags: Set<Int>) = announcementRepository.latest(tags)
fun latest(channel: String) = announcementRepository.latest(channel)
fun latest() = announcementRepository.latest()
suspend fun latest() = announcementRepository.latest()
suspend fun all(channel: String) = announcementRepository.all(channel)
suspend fun all() = announcementRepository.all()
fun latestId(tags: Set<Int>) = announcementRepository.latestId(tags)
suspend fun new(new: APIAnnouncement) {
announcementRepository.new(new)
}
suspend fun archive(id: Int, archivedAt: LocalDateTime?) {
announcementRepository.archive(id, archivedAt)
}
suspend fun unarchive(id: Int) {
announcementRepository.unarchive(id)
}
suspend fun update(id: Int, new: APIAnnouncement) {
announcementRepository.update(id, new)
}
suspend fun delete(id: Int) {
announcementRepository.delete(id)
}
fun latestId() = announcementRepository.latestId()
suspend fun paged(cursor: Int, limit: Int, tags: Set<Int>?, archived: Boolean) =
announcementRepository.paged(cursor, limit, tags, archived)
suspend fun get(id: Int) = announcementRepository.get(id)
suspend fun update(id: Int, new: ApiAnnouncement) = announcementRepository.update(id, new)
suspend fun delete(id: Int) = announcementRepository.delete(id)
suspend fun new(new: ApiAnnouncement) = announcementRepository.new(new)
suspend fun tags() = announcementRepository.tags()
}

View File

@@ -21,7 +21,7 @@ internal class ApiService(
APIContributable(
it,
backendRepository.contributors(configurationRepository.organization, it).map {
APIContributor(it.name, it.avatarUrl, it.url, it.contributions)
ApiContributor(it.name, it.avatarUrl, it.url, it.contributions)
},
)
}
@@ -29,13 +29,13 @@ internal class ApiService(
}.awaitAll()
suspend fun team() = backendRepository.members(configurationRepository.organization).map { member ->
APIMember(
ApiMember(
member.name,
member.avatarUrl,
member.url,
member.bio,
if (member.gpgKeys.ids.isNotEmpty()) {
APIGpgKey(
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,
@@ -47,6 +47,6 @@ internal class ApiService(
}
suspend fun rateLimit() = backendRepository.rateLimit()?.let {
APIRateLimit(it.limit, it.remaining, it.reset)
ApiRateLimit(it.limit, it.remaining, it.reset)
}
}

View File

@@ -1,6 +1,6 @@
package app.revanced.api.configuration.services
import app.revanced.api.configuration.schema.APIToken
import app.revanced.api.configuration.schema.ApiToken
import com.auth0.jwt.JWT
import com.auth0.jwt.algorithms.Algorithm
import io.ktor.server.auth.*
@@ -43,7 +43,7 @@ internal class AuthenticationService private constructor(
}
}
fun newToken() = APIToken(
fun newToken() = ApiToken(
JWT.create()
.withIssuer(issuer)
.withExpiresAt(Instant.now().plus(validityInMin, ChronoUnit.MINUTES))

View File

@@ -9,17 +9,17 @@ internal class ManagerService(
private val backendRepository: BackendRepository,
private val configurationRepository: ConfigurationRepository,
) {
suspend fun latestRelease(): APIRelease<APIManagerAsset> {
suspend fun latestRelease(): ApiRelease<ApiManagerAsset> {
val managerRelease = backendRepository.release(
configurationRepository.organization,
configurationRepository.manager.repository,
)
val managerAsset = APIManagerAsset(
val managerAsset = ApiManagerAsset(
managerRelease.assets.first(configurationRepository.manager.assetRegex).downloadUrl,
)
return APIRelease(
return ApiRelease(
managerRelease.tag,
managerRelease.createdAt,
managerRelease.releaseNote,
@@ -27,12 +27,12 @@ internal class ManagerService(
)
}
suspend fun latestVersion(): APIReleaseVersion {
suspend fun latestVersion(): ApiReleaseVersion {
val managerRelease = backendRepository.release(
configurationRepository.organization,
configurationRepository.manager.repository,
)
return APIReleaseVersion(managerRelease.tag)
return ApiReleaseVersion(managerRelease.tag)
}
}

View File

@@ -17,7 +17,7 @@ internal class PatchesService(
private val backendRepository: BackendRepository,
private val configurationRepository: ConfigurationRepository,
) {
suspend fun latestRelease(): APIRelease<APIPatchesAsset> {
suspend fun latestRelease(): ApiRelease<ApiPatchesAsset> {
val patchesRelease = backendRepository.release(
configurationRepository.organization,
configurationRepository.patches.repository,
@@ -30,8 +30,8 @@ internal class PatchesService(
fun ConfigurationRepository.SignedAssetConfiguration.asset(
release: BackendRepository.BackendOrganization.BackendRepository.BackendRelease,
assetName: APIAssetName,
) = APIPatchesAsset(
assetName: ApiAssetName,
) = ApiPatchesAsset(
release.assets.first(assetRegex).downloadUrl,
release.assets.first(signatureAssetRegex).downloadUrl,
assetName,
@@ -39,14 +39,14 @@ internal class PatchesService(
val patchesAsset = configurationRepository.patches.asset(
patchesRelease,
APIAssetName.PATCHES,
ApiAssetName.PATCHES,
)
val integrationsAsset = configurationRepository.integrations.asset(
integrationsRelease,
APIAssetName.INTEGRATION,
ApiAssetName.INTEGRATION,
)
return APIRelease(
return ApiRelease(
patchesRelease.tag,
patchesRelease.createdAt,
patchesRelease.releaseNote,
@@ -54,13 +54,13 @@ internal class PatchesService(
)
}
suspend fun latestVersion(): APIReleaseVersion {
suspend fun latestVersion(): ApiReleaseVersion {
val patchesRelease = backendRepository.release(
configurationRepository.organization,
configurationRepository.patches.repository,
)
return APIReleaseVersion(patchesRelease.tag)
return ApiReleaseVersion(patchesRelease.tag)
}
private val patchesListCache = Caffeine
@@ -111,12 +111,12 @@ internal class PatchesService(
}
}
fun publicKeys(): APIAssetPublicKeys {
fun publicKeys(): ApiAssetPublicKeys {
fun readPublicKey(
getSignedAssetConfiguration: ConfigurationRepository.() -> ConfigurationRepository.SignedAssetConfiguration,
) = configurationRepository.getSignedAssetConfiguration().publicKeyFile.readText()
return APIAssetPublicKeys(
return ApiAssetPublicKeys(
readPublicKey { patches },
readPublicKey { integrations },
)