style: Lint code

This commit is contained in:
oSumAtrIX 2024-02-06 00:21:58 +01:00
parent 6b34aaf5db
commit e798a4c070
No known key found for this signature in database
GPG Key ID: A9B3094ACDB604B4
13 changed files with 156 additions and 106 deletions

3
.editorconfig Normal file
View File

@ -0,0 +1,3 @@
[*.{kt,kts}]
ktlint_code_style = intellij_idea
ktlint_standard_no-wildcard-imports = disabled

View File

@ -11,7 +11,7 @@ import kotlinx.serialization.Serializable
* @param httpClientConfig The configuration of the HTTP client.
*/
abstract class Backend(
httpClientConfig: HttpClientConfig<OkHttpConfig>.() -> Unit = {}
httpClientConfig: HttpClientConfig<OkHttpConfig>.() -> Unit = {},
) {
protected val client: HttpClient = HttpClient(OkHttp, httpClientConfig)
@ -34,7 +34,7 @@ abstract class Backend(
* @property members The members of the organization.
*/
class BackendOrganization(
val members: Set<BackendMember>
val members: Set<BackendMember>,
) {
/**
* A member of an organization.
@ -46,12 +46,12 @@ abstract class Backend(
* @property gpgKeysUrl The URL to the GPG keys of the member.
*/
@Serializable
class BackendMember (
class BackendMember(
override val name: String,
override val avatarUrl: String,
override val url: String,
val bio: String?,
val gpgKeysUrl: String
val gpgKeysUrl: String,
) : BackendUser
/**
@ -60,7 +60,7 @@ abstract class Backend(
* @property contributors The contributors of the repository.
*/
class BackendRepository(
val contributors: Set<BackendContributor>
val contributors: Set<BackendContributor>,
) {
/**
* A contributor of a repository.
@ -75,7 +75,7 @@ abstract class Backend(
override val name: String,
override val avatarUrl: String,
override val url: String,
val contributions: Int
val contributions: Int,
) : BackendUser
/**
@ -91,7 +91,7 @@ abstract class Backend(
val tag: String,
val releaseNote: String,
val createdAt: LocalDateTime,
val assets: Set<BackendAsset>
val assets: Set<BackendAsset>,
) {
/**
* An asset of a release.
@ -100,7 +100,7 @@ abstract class Backend(
*/
@Serializable
class BackendAsset(
val downloadUrl: String
val downloadUrl: String,
)
}
}

View File

@ -1,7 +1,18 @@
package app.revanced.api.backend.github
import app.revanced.api.backend.Backend
import app.revanced.api.backend.Backend.BackendOrganization.BackendMember
import app.revanced.api.backend.Backend.BackendOrganization.BackendRepository.BackendContributor
import app.revanced.api.backend.Backend.BackendOrganization.BackendRepository.BackendRelease
import app.revanced.api.backend.Backend.BackendOrganization.BackendRepository.BackendRelease.BackendAsset
import app.revanced.api.backend.github.api.Request
import app.revanced.api.backend.github.api.Request.Organization.Members
import app.revanced.api.backend.github.api.Request.Organization.Repository.Contributors
import app.revanced.api.backend.github.api.Request.Organization.Repository.Releases
import app.revanced.api.backend.github.api.Response
import app.revanced.api.backend.github.api.Response.GitHubOrganization.GitHubMember
import app.revanced.api.backend.github.api.Response.GitHubOrganization.GitHubRepository.GitHubContributor
import app.revanced.api.backend.github.api.Response.GitHubOrganization.GitHubRepository.GitHubRelease
import io.ktor.client.call.*
import io.ktor.client.plugins.*
import io.ktor.client.plugins.auth.*
@ -9,17 +20,6 @@ import io.ktor.client.plugins.auth.providers.*
import io.ktor.client.plugins.cache.*
import io.ktor.client.plugins.contentnegotiation.*
import io.ktor.client.plugins.resources.*
import app.revanced.api.backend.Backend.BackendOrganization.BackendMember
import app.revanced.api.backend.Backend.BackendOrganization.BackendRepository.BackendRelease
import app.revanced.api.backend.Backend.BackendOrganization.BackendRepository.BackendContributor
import app.revanced.api.backend.Backend.BackendOrganization.BackendRepository.BackendRelease.BackendAsset
import app.revanced.api.backend.github.api.Request.Organization.Repository.Releases
import app.revanced.api.backend.github.api.Request.Organization.Repository.Contributors
import app.revanced.api.backend.github.api.Request.Organization.Members
import app.revanced.api.backend.github.api.Response
import app.revanced.api.backend.github.api.Response.GitHubOrganization.GitHubRepository.GitHubRelease
import app.revanced.api.backend.github.api.Response.GitHubOrganization.GitHubRepository.GitHubContributor
import app.revanced.api.backend.github.api.Response.GitHubOrganization.GitHubMember
import io.ktor.client.plugins.resources.Resources
import io.ktor.serialization.kotlinx.json.*
import kotlinx.coroutines.*
@ -28,18 +28,18 @@ import kotlinx.datetime.toLocalDateTime
import kotlinx.serialization.ExperimentalSerializationApi
import kotlinx.serialization.json.Json
import kotlinx.serialization.json.JsonNamingStrategy
import org.koin.dsl.bind
import org.koin.dsl.module
@OptIn(ExperimentalSerializationApi::class)
class GitHubBackend(token: String? = null) : Backend({
install(HttpCache)
install(Resources)
install(ContentNegotiation) {
json(Json {
json(
Json {
ignoreUnknownKeys = true
namingStrategy = JsonNamingStrategy.SnakeCase
})
},
)
}
defaultRequest { url("https://api.github.com") }
@ -50,7 +50,7 @@ class GitHubBackend(token: String? = null) : Backend({
loadTokens {
BearerTokens(
accessToken = it,
refreshToken = "" // Required dummy value
refreshToken = "", // Required dummy value
)
}
@ -64,11 +64,11 @@ class GitHubBackend(token: String? = null) : Backend({
repository: String,
tag: String?,
): BackendRelease {
val release: GitHubRelease = if (tag != null)
val release: GitHubRelease = if (tag != null) {
client.get(Releases.Tag(owner, repository, tag)).body()
else
} else {
client.get(Releases.Latest(owner, repository)).body()
}
return BackendRelease(
tag = release.tagName,
@ -76,13 +76,13 @@ class GitHubBackend(token: String? = null) : Backend({
createdAt = release.createdAt.toLocalDateTime(TimeZone.UTC),
assets = release.assets.map {
BackendAsset(downloadUrl = it.browserDownloadUrl)
}.toSet()
}.toSet(),
)
}
override suspend fun getContributors(
owner: String,
repository: String
repository: String,
): Set<BackendContributor> {
val contributors: Set<GitHubContributor> = client.get(Contributors(owner, repository)).body()
@ -91,7 +91,7 @@ class GitHubBackend(token: String? = null) : Backend({
name = it.login,
avatarUrl = it.avatarUrl,
url = it.url,
contributions = it.contributions
contributions = it.contributions,
)
}.toSet()
}

View File

@ -5,6 +5,7 @@ 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)

View File

@ -3,7 +3,6 @@ package app.revanced.api.backend.github.api
import kotlinx.datetime.Instant
import kotlinx.serialization.Serializable
class Response {
interface IGitHubUser {
val login: String
@ -12,7 +11,7 @@ class Response {
}
@Serializable
class GitHubUser (
class GitHubUser(
override val login: String,
override val avatarUrl: String,
override val url: String,
@ -41,11 +40,11 @@ class Response {
val tagName: String,
val assets: Set<GitHubAsset>,
val createdAt: Instant,
val body: String
val body: String,
) {
@Serializable
class GitHubAsset(
val browserDownloadUrl: String
val browserDownloadUrl: String,
)
}
}

View File

@ -1,11 +1,10 @@
package app.revanced.api.modules
import app.revanced.api.modules.AnnouncementService.Attachments.announcement
import app.revanced.api.schema.APIResponseAnnouncement
import app.revanced.api.schema.APIAnnouncement
import app.revanced.api.schema.APILatestAnnouncement
import app.revanced.api.schema.APIResponseAnnouncement
import kotlinx.datetime.*
import org.jetbrains.exposed.sql.transactions.transaction
import org.jetbrains.exposed.dao.IntEntity
import org.jetbrains.exposed.dao.IntEntityClass
import org.jetbrains.exposed.dao.id.EntityID
@ -13,7 +12,7 @@ import org.jetbrains.exposed.dao.id.IntIdTable
import org.jetbrains.exposed.sql.*
import org.jetbrains.exposed.sql.SqlExpressionBuilder.eq
import org.jetbrains.exposed.sql.kotlin.datetime.datetime
import org.jetbrains.exposed.sql.transactions.transaction
class AnnouncementService(private val database: Database) {
private object Announcements : IntIdTable() {
@ -52,7 +51,7 @@ class AnnouncementService(private val database: Database) {
channel,
createdAt,
archivedAt,
level
level,
)
}
@ -107,7 +106,7 @@ class AnnouncementService(private val database: Database) {
fun archive(
id: Int,
archivedAt: LocalDateTime?
archivedAt: LocalDateTime?,
) = transaction {
Announcement.findById(id)?.apply {
this.archivedAt = archivedAt ?: java.time.LocalDateTime.now().toKotlinLocalDateTime()

View File

@ -19,7 +19,7 @@ fun Application.configureDependencies() {
globalModule,
gitHubBackendModule,
databaseModule,
authModule
authModule,
)
}
}
@ -51,7 +51,7 @@ val databaseModule = module {
url = dotenv["DB_URL"],
user = dotenv["DB_USER"],
password = dotenv["DB_PASSWORD"],
driver = "org.h2.Driver"
driver = "org.h2.Driver",
)
}
factory<AnnouncementService> {

View File

@ -23,41 +23,68 @@ fun Application.configureRouting() {
routing {
route("/v${configuration.apiVersion}") {
route("/announcements") {
suspend fun PipelineContext<*, ApplicationCall>.announcement(
block: AnnouncementService.() -> APIResponseAnnouncement?
) = announcementService.block()?.let { call.respond(it) }
suspend fun PipelineContext<*, ApplicationCall>.announcement(block: AnnouncementService.() -> APIResponseAnnouncement?) =
announcementService.block()?.let { call.respond(it) }
?: call.respond(HttpStatusCode.NotFound)
suspend fun PipelineContext<*, ApplicationCall>.announcementId(
block: AnnouncementService.() -> APILatestAnnouncement?
) = announcementService.block()?.let { call.respond(it) }
suspend fun PipelineContext<*, ApplicationCall>.announcementId(block: AnnouncementService.() -> APILatestAnnouncement?) =
announcementService.block()?.let { call.respond(it) }
?: call.respond(HttpStatusCode.NotFound)
suspend fun PipelineContext<*, ApplicationCall>.channel(block: suspend (String) -> Unit) =
block(call.parameters["channel"]!!)
route("/{channel}/latest") {
get("/id") { channel { announcementId { latestId(it) } } }
get { channel { announcement { latest(it) } } }
get("/id") {
channel {
announcementId {
latestId(it)
}
}
}
get("/{channel}") { channel { call.respond(announcementService.read(it)) } }
get {
channel {
announcement {
latest(it)
}
}
}
}
get("/{channel}") {
channel {
call.respond(announcementService.read(it))
}
}
route("/latest") {
get("/id") { announcementId { latestId() } }
get { announcement { latest() } }
get("/id") {
announcementId {
latestId()
}
}
get { call.respond(announcementService.read()) }
get {
announcement {
latest()
}
}
}
get {
call.respond(announcementService.read())
}
authenticate("jwt") {
suspend fun PipelineContext<*, ApplicationCall>.id(block: suspend (Int) -> Unit) =
call.parameters["id"]!!.toIntOrNull()?.let { block(it) }
?: call.respond(HttpStatusCode.BadRequest)
call.parameters["id"]!!.toIntOrNull()?.let {
block(it)
} ?: call.respond(HttpStatusCode.BadRequest)
post { announcementService.new(call.receive<APIAnnouncement>()) }
post {
announcementService.new(call.receive<APIAnnouncement>())
}
post("/{id}/archive") {
id {
@ -66,11 +93,23 @@ fun Application.configureRouting() {
}
}
post("/{id}/unarchive") { id { announcementService.unarchive(it) } }
post("/{id}/unarchive") {
id {
announcementService.unarchive(it)
}
}
patch("/{id}") { id { announcementService.update(it, call.receive<APIAnnouncement>()) } }
patch("/{id}") {
id {
announcementService.update(it, call.receive<APIAnnouncement>())
}
}
delete("/{id}") { id { announcementService.delete(it) } }
delete("/{id}") {
id {
announcementService.delete(it)
}
}
}
}
@ -78,19 +117,22 @@ fun Application.configureRouting() {
route("latest") {
get {
val patches = backend.getRelease(configuration.organization, configuration.patchesRepository)
val integrations = configuration.integrationsRepositoryNames.map {
val integrations =
configuration.integrationsRepositoryNames.map {
async { backend.getRelease(configuration.organization, it) }
}.awaitAll()
val assets = (patches.assets + integrations.flatMap { it.assets }).filter {
val assets =
(patches.assets + integrations.flatMap { it.assets }).filter {
it.downloadUrl.endsWith(".apk") || it.downloadUrl.endsWith(".jar")
}.map { APIAsset(it.downloadUrl) }.toSet()
val release = APIRelease(
val release =
APIRelease(
patches.tag,
patches.createdAt,
patches.releaseNote,
assets
assets,
)
call.respond(release)
@ -112,13 +154,14 @@ fun Application.configureRouting() {
}
get("/contributors") {
val contributors = configuration.contributorsRepositoryNames.map {
val contributors =
configuration.contributorsRepositoryNames.map {
async {
APIContributable(
it,
backend.getContributors(configuration.organization, it).map {
APIContributor(it.name, it.avatarUrl, it.url, it.contributions)
}.toSet()
}.toSet(),
)
}
}.awaitAll()
@ -127,7 +170,8 @@ fun Application.configureRouting() {
}
get("/team") {
val team = backend.getMembers(configuration.organization).map {
val team =
backend.getMembers(configuration.organization).map {
APIMember(it.name, it.avatarUrl, it.url, it.gpgKeysUrl)
}
@ -140,7 +184,11 @@ fun Application.configureRouting() {
}
}
authenticate("basic") { get("/token") { call.respond(authService.newToken()) } }
authenticate("basic") {
get("/token") {
call.respond(authService.newToken())
}
}
}
}
}

View File

@ -22,7 +22,7 @@ class AuthService(
verifier(
JWT.require(Algorithm.HMAC256(jwtSecret))
.withIssuer(issuer)
.build()
.build(),
)
validate { credential -> JWTPrincipal(credential.payload) }
}

View File

@ -8,7 +8,7 @@ class APIRelease(
val version: String,
val createdAt: LocalDateTime,
val changelog: String,
val assets: Set<APIAsset>
val assets: Set<APIAsset>,
)
interface APIUser {
@ -22,7 +22,7 @@ class APIMember(
override val name: String,
override val avatarUrl: String,
override val url: String,
val gpgKeysUrl: String
val gpgKeysUrl: String,
) : APIUser
@Serializable
@ -36,7 +36,7 @@ class APIContributor(
@Serializable
class APIContributable(
val name: String,
val contributors: Set<APIContributor>
val contributors: Set<APIContributor>,
)
@Serializable
@ -52,7 +52,7 @@ class APIAsset(
@Serializable
class APIReleaseVersion(
val version: String
val version: String,
)
@Serializable
@ -63,7 +63,7 @@ class APIAnnouncement(
val attachmentUrls: Set<String> = emptySet(),
val channel: String? = null,
val archivedAt: LocalDateTime? = null,
val level: Int = 0
val level: Int = 0,
)
@Serializable
@ -76,15 +76,15 @@ class APIResponseAnnouncement(
val channel: String? = null,
val createdAt: LocalDateTime,
val archivedAt: LocalDateTime? = null,
val level: Int = 0
val level: Int = 0,
)
@Serializable
class APILatestAnnouncement(
val id: Int
val id: Int,
)
@Serializable
class APIAnnouncementArchivedAt(
val archivedAt: LocalDateTime
val archivedAt: LocalDateTime,
)

View File

@ -13,5 +13,5 @@ class APIConfiguration(
@SerialName("contributors-repositories")
val contributorsRepositoryNames: Set<String>,
@SerialName("api-version")
val apiVersion: Int = 1
val apiVersion: Int = 1,
)

View File

@ -23,8 +23,8 @@ class ApplicationTest {
organization = "ReVanced",
patchesRepository = "",
integrationsRepositoryNames = setOf(),
contributorsRepositoryNames = setOf()
)
contributorsRepositoryNames = setOf(),
),
).let(::writeText)
deleteOnExit()
@ -47,7 +47,7 @@ class ApplicationTest {
headers {
append(
HttpHeaders.Authorization,
"Basic ${"${dotenv["BASIC_USERNAME"]}:${dotenv["BASIC_PASSWORD"]}".encodeBase64()}"
"Basic ${"${dotenv["BASIC_USERNAME"]}:${dotenv["BASIC_PASSWORD"]}".encodeBase64()}",
)
}
}.bodyAsText()