Compare commits

...

14 Commits

Author SHA1 Message Date
semantic-release-bot
712ab3be8c chore: Release v1.6.0-dev.2 [skip ci]
# [1.6.0-dev.2](https://github.com/ReVanced/revanced-api/compare/v1.6.0-dev.1...v1.6.0-dev.2) (2024-12-20)

### Features

* Make some announcements schema fields nullable ([db22874](db22874f06))
2024-12-20 23:27:48 +00:00
oSumAtrIX
db22874f06 feat: Make some announcements schema fields nullable 2024-12-21 00:25:26 +01:00
semantic-release-bot
5d5533a920 chore: Release v1.6.0-dev.1 [skip ci]
# [1.6.0-dev.1](https://github.com/ReVanced/revanced-api/compare/v1.5.0...v1.6.0-dev.1) (2024-11-23)

### Features

* Allow setting `Announcement.createdAt` when creating an announcement ([7f6e29d](7f6e29de52))
2024-11-23 18:26:28 +00:00
oSumAtrIX
7f6e29de52 feat: Allow setting Announcement.createdAt when creating an announcement 2024-11-13 22:23:05 +01:00
semantic-release-bot
48469d32c2 chore: Release v1.5.0 [skip ci]
# [1.5.0](https://github.com/ReVanced/revanced-api/compare/v1.4.0...v1.5.0) (2024-11-06)

### Features

* Allow updating `createdAt` field for announcements ([58ba4cb](58ba4cb11c))
* Move spec url to versioned path ([e871b23](e871b23210))
* Simplify log pattern ([d5d9e04](d5d9e04325))
2024-11-06 21:17:51 +00:00
oSumAtrIX
7f9159fef1 chore: Merge branch dev to main(#195) 2024-11-06 22:15:06 +01:00
semantic-release-bot
b063b4daf2 chore: Release v1.5.0-dev.2 [skip ci]
# [1.5.0-dev.2](https://github.com/ReVanced/revanced-api/compare/v1.5.0-dev.1...v1.5.0-dev.2) (2024-11-06)

### Features

* Allow updating `createdAt` field for announcements ([58ba4cb](58ba4cb11c))
* Simplify log pattern ([d5d9e04](d5d9e04325))
2024-11-06 15:36:26 +00:00
oSumAtrIX
58ba4cb11c feat: Allow updating createdAt field for announcements 2024-11-06 16:34:18 +01:00
semantic-release-bot
55e3774f07 chore: Release v1.5.0-dev.1 [skip ci]
# [1.5.0-dev.1](https://github.com/ReVanced/revanced-api/compare/v1.4.0...v1.5.0-dev.1) (2024-11-06)

### Features

* Move spec url to versioned path ([e871b23](e871b23210))
* Simplify log pattern ([d5d9e04](d5d9e04325))
2024-11-06 04:41:55 +00:00
oSumAtrIX
d5d9e04325 feat: Simplify log pattern 2024-11-06 05:39:39 +01:00
semantic-release-bot
6c8153ba98 chore: Release v1.5.0-dev.1 [skip ci]
# [1.5.0-dev.1](https://github.com/ReVanced/revanced-api/compare/v1.4.0...v1.5.0-dev.1) (2024-11-06)

### Features

* Move spec url to versioned path ([e871b23](e871b23210))
2024-11-06 04:32:10 +00:00
oSumAtrIX
e871b23210 feat: Move spec url to versioned path 2024-11-06 05:30:09 +01:00
semantic-release-bot
e22ec16e40 chore: Release v1.4.0 [skip ci]
# [1.4.0](https://github.com/ReVanced/revanced-api/compare/v1.3.0...v1.4.0) (2024-11-06)

### Bug Fixes

* Add missing logging level environment variable to .env.example ([3b62120](3b6212065a))
* Use new patches file extension ([d42a3a3](d42a3a3933))

### Features

* Add URL and use friendly name for `APIContributable` ([a5498ab](a5498aba2b))
* Allow versioning by arbitrary path string ([814d3c9](814d3c946e))
* Improve announcements API ([#192](https://github.com/ReVanced/revanced-api/issues/192)) ([56a00dd](56a00ddb85))
* Make backend configurable ([f91f3a6](f91f3a65c5))
* Remove "archived" query parameter ([8ad614e](8ad614ef4f))
* Remove deprecated routes and old API ([eca40a6](eca40a6979))
* Remove ReVanced Integrations ([f1c1092](f1c10928ae))
* Use tag name directly instead of ID ([fc40427](fc40427fba))
2024-11-06 04:06:21 +00:00
oSumAtrIX
440fbbc6c2 chore: Merge branch dev to main (#194) 2024-11-06 05:04:05 +01:00
9 changed files with 125 additions and 38 deletions

View File

@@ -1,3 +1,69 @@
# [1.6.0-dev.2](https://github.com/ReVanced/revanced-api/compare/v1.6.0-dev.1...v1.6.0-dev.2) (2024-12-20)
### Features
* Make some announcements schema fields nullable ([db22874](https://github.com/ReVanced/revanced-api/commit/db22874f063bae0c9e7f0c99a20cdf1b16addd89))
# [1.6.0-dev.1](https://github.com/ReVanced/revanced-api/compare/v1.5.0...v1.6.0-dev.1) (2024-11-23)
### Features
* Allow setting `Announcement.createdAt` when creating an announcement ([7f6e29d](https://github.com/ReVanced/revanced-api/commit/7f6e29de5205f63ac4aaea490c844b58e14000c8))
# [1.5.0](https://github.com/ReVanced/revanced-api/compare/v1.4.0...v1.5.0) (2024-11-06)
### Features
* Allow updating `createdAt` field for announcements ([58ba4cb](https://github.com/ReVanced/revanced-api/commit/58ba4cb11c789507826cd70ac548943a94da4223))
* Move spec url to versioned path ([e871b23](https://github.com/ReVanced/revanced-api/commit/e871b23210798723c34bce93c7567d8fbcf4e060))
* Simplify log pattern ([d5d9e04](https://github.com/ReVanced/revanced-api/commit/d5d9e04325fa93540be0438e7b51243e2aeeab3d))
# [1.5.0-dev.2](https://github.com/ReVanced/revanced-api/compare/v1.5.0-dev.1...v1.5.0-dev.2) (2024-11-06)
### Features
* Allow updating `createdAt` field for announcements ([58ba4cb](https://github.com/ReVanced/revanced-api/commit/58ba4cb11c789507826cd70ac548943a94da4223))
* Simplify log pattern ([d5d9e04](https://github.com/ReVanced/revanced-api/commit/d5d9e04325fa93540be0438e7b51243e2aeeab3d))
# [1.5.0-dev.1](https://github.com/ReVanced/revanced-api/compare/v1.4.0...v1.5.0-dev.1) (2024-11-06)
### Features
* Move spec url to versioned path ([e871b23](https://github.com/ReVanced/revanced-api/commit/e871b23210798723c34bce93c7567d8fbcf4e060))
* Simplify log pattern ([d5d9e04](https://github.com/ReVanced/revanced-api/commit/d5d9e04325fa93540be0438e7b51243e2aeeab3d))
# [1.5.0-dev.1](https://github.com/ReVanced/revanced-api/compare/v1.4.0...v1.5.0-dev.1) (2024-11-06)
### Features
* Move spec url to versioned path ([e871b23](https://github.com/ReVanced/revanced-api/commit/e871b23210798723c34bce93c7567d8fbcf4e060))
# [1.4.0](https://github.com/ReVanced/revanced-api/compare/v1.3.0...v1.4.0) (2024-11-06)
### Bug Fixes
* Add missing logging level environment variable to .env.example ([3b62120](https://github.com/ReVanced/revanced-api/commit/3b6212065a5cfb95c303b6d0551747ba1eb317f6))
* Use new patches file extension ([d42a3a3](https://github.com/ReVanced/revanced-api/commit/d42a3a393396a0f4e9085cda46e0af2c12b63cb1))
### Features
* Add URL and use friendly name for `APIContributable` ([a5498ab](https://github.com/ReVanced/revanced-api/commit/a5498aba2b99db89c28a65738cc58cc4c852c327))
* Allow versioning by arbitrary path string ([814d3c9](https://github.com/ReVanced/revanced-api/commit/814d3c946e31068e12e3886aa8beb3238ef126ae))
* Improve announcements API ([#192](https://github.com/ReVanced/revanced-api/issues/192)) ([56a00dd](https://github.com/ReVanced/revanced-api/commit/56a00ddb85f302d441f0b222a9902ea2c1c18897))
* Make backend configurable ([f91f3a6](https://github.com/ReVanced/revanced-api/commit/f91f3a65c5e07b5b58ccbff1d4b0a5ba9b15fc50))
* Remove "archived" query parameter ([8ad614e](https://github.com/ReVanced/revanced-api/commit/8ad614ef4fdaf45af87a3316ef4db7e7236fd64a))
* Remove deprecated routes and old API ([eca40a6](https://github.com/ReVanced/revanced-api/commit/eca40a69799240f7803aa8851eb3ee961937e4d6))
* Remove ReVanced Integrations ([f1c1092](https://github.com/ReVanced/revanced-api/commit/f1c10928ae3be1c6b1d675819755b3046fad70d8))
* Use tag name directly instead of ID ([fc40427](https://github.com/ReVanced/revanced-api/commit/fc40427fbaafb523045eb6f5285d90949b206b8b))
# [1.4.0-dev.6](https://github.com/ReVanced/revanced-api/compare/v1.4.0-dev.5...v1.4.0-dev.6) (2024-11-06)

View File

@@ -1,4 +1,4 @@
org.gradle.parallel = true
org.gradle.caching = true
kotlin.code.style = official
version = 1.4.0-dev.6
version = 1.6.0-dev.2

View File

@@ -1,6 +1,9 @@
package app.revanced.api.configuration
import kotlinx.datetime.Clock
import kotlinx.datetime.LocalDateTime
import kotlinx.datetime.TimeZone
import kotlinx.datetime.toLocalDateTime
import kotlinx.serialization.Serializable
interface ApiUser {
@@ -60,9 +63,10 @@ class ApiAnnouncement(
val title: String,
val content: String? = null,
// Using a list instead of a set because set semantics are unnecessary here.
val attachments: List<String> = emptyList(),
val attachments: List<String>? = null,
// Using a list instead of a set because set semantics are unnecessary here.
val tags: List<String> = emptyList(),
val tags: List<String>? = null,
val createdAt: LocalDateTime = Clock.System.now().toLocalDateTime(TimeZone.currentSystemDefault()),
val archivedAt: LocalDateTime? = null,
val level: Int = 0,
)
@@ -74,9 +78,9 @@ class ApiResponseAnnouncement(
val title: String,
val content: String? = null,
// Using a list instead of a set because set semantics are unnecessary here.
val attachments: List<String> = emptyList(),
val attachments: List<String>? = null,
// Using a list instead of a set because set semantics are unnecessary here.
val tags: List<String> = emptyList(),
val tags: List<String>? = null,
val createdAt: LocalDateTime,
val archivedAt: LocalDateTime? = null,
val level: Int = 0,

View File

@@ -11,7 +11,7 @@ import org.koin.ktor.ext.get
import kotlin.time.Duration.Companion.minutes
fun Application.configureHTTP() {
val configurationRepository = get<ConfigurationRepository>()
val configuration = get<ConfigurationRepository>()
install(CORS) {
HttpMethod.DefaultMethods.minus(HttpMethod.Options).forEach(::allowMethod)
@@ -22,7 +22,7 @@ fun Application.configureHTTP() {
allowCredentials = true
configurationRepository.corsAllowedHosts.forEach { host ->
configuration.corsAllowedHosts.forEach { host ->
allowHost(host = host, schemes = listOf("https"))
}
}

View File

@@ -2,6 +2,7 @@ package app.revanced.api.configuration
import app.revanced.api.command.applicationVersion
import app.revanced.api.configuration.repository.ConfigurationRepository
import io.bkbn.kompendium.core.attribute.KompendiumAttributes
import io.bkbn.kompendium.core.plugin.NotarizedApplication
import io.bkbn.kompendium.json.schema.KotlinXSchemaConfigurator
import io.bkbn.kompendium.oas.OpenApiSpec
@@ -12,13 +13,22 @@ import io.bkbn.kompendium.oas.info.License
import io.bkbn.kompendium.oas.security.BearerAuth
import io.bkbn.kompendium.oas.server.Server
import io.ktor.server.application.*
import org.koin.ktor.ext.get
import io.ktor.server.response.*
import io.ktor.server.routing.*
import java.net.URI
import org.koin.ktor.ext.get as koinGet
internal fun Application.configureOpenAPI() {
val configurationRepository = get<ConfigurationRepository>()
val configuration = koinGet<ConfigurationRepository>()
install(NotarizedApplication()) {
openApiJson = {
route("/${configuration.apiVersion}/openapi.json") {
get {
call.respond(application.attributes[KompendiumAttributes.openApiSpec])
}
}
}
spec = OpenApiSpec(
info = Info(
title = "ReVanced API",
@@ -41,7 +51,7 @@ internal fun Application.configureOpenAPI() {
),
).apply {
servers += Server(
url = URI(configurationRepository.endpoint),
url = URI(configuration.endpoint),
description = "ReVanced API server",
)
}

View File

@@ -52,6 +52,7 @@ internal fun Application.configureRouting() = routing {
extensions("json", "asc")
}
swagger(pageTitle = "ReVanced API", path = "/")
redoc(pageTitle = "ReVanced API", path = "/redoc")
val specUrl = "/${configuration.apiVersion}/openapi.json"
swagger(pageTitle = "ReVanced API", path = "/", specUrl = specUrl)
redoc(pageTitle = "ReVanced API", path = "/redoc", specUrl = specUrl)
}

View File

@@ -69,8 +69,7 @@ internal class AnnouncementRepository(private val database: Database) {
fun latestId() = latestAnnouncement?.id?.value.toApiResponseAnnouncementId()
fun latestId(tags: Set<String>) =
tags.map { tag -> latestAnnouncementByTag[tag]?.id?.value }.toApiResponseAnnouncementId()
fun latestId(tags: Set<String>) = tags.map { tag -> latestAnnouncementByTag[tag]?.id?.value }.toApiResponseAnnouncementId()
suspend fun paged(cursor: Int, count: Int, tags: Set<String>?) = transaction {
Announcement.find {
@@ -100,13 +99,16 @@ internal class AnnouncementRepository(private val database: Database) {
author = new.author
title = new.title
content = new.content
createdAt = new.createdAt
archivedAt = new.archivedAt
level = new.level
tags = SizedCollection(
new.tags.map { tag -> Tag.find { Tags.name eq tag }.firstOrNull() ?: Tag.new { name = tag } },
)
if (new.tags != null) {
tags = SizedCollection(
new.tags.map { tag -> Tag.find { Tags.name eq tag }.firstOrNull() ?: Tag.new { name = tag } },
)
}
}.apply {
new.attachments.map { attachmentUrl ->
new.attachments?.map { attachmentUrl ->
Attachment.new {
url = attachmentUrl
announcement = this@apply
@@ -120,27 +122,32 @@ internal class AnnouncementRepository(private val database: Database) {
it.author = new.author
it.title = new.title
it.content = new.content
it.createdAt = new.createdAt
it.archivedAt = new.archivedAt
it.level = new.level
// Get the old tags, create new tags if they don't exist,
// and delete tags that are not in the new tags, after updating the announcement.
val oldTags = it.tags.toList()
val updatedTags = new.tags.map { name ->
Tag.find { Tags.name eq name }.firstOrNull() ?: Tag.new { this.name = name }
}
it.tags = SizedCollection(updatedTags)
oldTags.forEach { tag ->
if (tag in updatedTags || !tag.announcements.empty()) return@forEach
tag.delete()
if (new.tags != null) {
// Get the old tags, create new tags if they don't exist,
// and delete tags that are not in the new tags, after updating the announcement.
val oldTags = it.tags.toList()
val updatedTags = new.tags.map { name ->
Tag.find { Tags.name eq name }.firstOrNull() ?: Tag.new { this.name = name }
}
it.tags = SizedCollection(updatedTags)
oldTags.forEach { tag ->
if (tag in updatedTags || !tag.announcements.empty()) return@forEach
tag.delete()
}
}
// Delete old attachments and create new attachments.
it.attachments.forEach { attachment -> attachment.delete() }
new.attachments.map { attachment ->
Attachment.new {
url = attachment
announcement = it
if (new.attachments != null) {
it.attachments.forEach { attachment -> attachment.delete() }
new.attachments.map { attachment ->
Attachment.new {
url = attachment
announcement = it
}
}
}
}?.let(::updateLatestAnnouncement) ?: Unit
@@ -173,8 +180,7 @@ internal class AnnouncementRepository(private val database: Database) {
Tag.all().toList().toApiTag()
}
private suspend fun <T> transaction(statement: suspend Transaction.() -> T) =
newSuspendedTransaction(Dispatchers.IO, database, statement = statement)
private suspend fun <T> transaction(statement: suspend Transaction.() -> T) = newSuspendedTransaction(Dispatchers.IO, database, statement = statement)
private object Announcements : IntIdTable() {
val author = varchar("author", 32).nullable()

View File

@@ -1,7 +1,7 @@
<configuration>
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%d{YYYY-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
<pattern>%d{YYYY-MM-dd HH:mm:ss.SSS} %-5level %msg%n</pattern>
</encoder>
</appender>
<root level="\${LOG_LEVEL:-INFO}">

View File

@@ -135,7 +135,7 @@ private object AnnouncementServiceTest {
val latestAnnouncement = announcementService.latest()!!
val latestId = latestAnnouncement.id
val attachments = latestAnnouncement.attachments
val attachments = latestAnnouncement.attachments!!
assertEquals(2, attachments.size)
assert(attachments.any { it == "attachment1" })
assert(attachments.any { it == "attachment2" })
@@ -144,7 +144,7 @@ private object AnnouncementServiceTest {
latestId,
ApiAnnouncement(title = "title", attachments = listOf("attachment1", "attachment3")),
)
assert(announcementService.get(latestId)!!.attachments.any { it == "attachment3" })
assert(announcementService.get(latestId)!!.attachments!!.any { it == "attachment3" })
}
@Test