Skip to content

Commit 9890943

Browse files
authored
chore: Merge branch dev to main (#196)
This pull request will Merge branch `dev` to `main`.
2 parents 48469d3 + 5b447aa commit 9890943

File tree

13 files changed

+125
-51
lines changed

13 files changed

+125
-51
lines changed

CHANGELOG.md

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,25 @@
1+
# [1.6.0-dev.3](https://github.com/ReVanced/revanced-api/compare/v1.6.0-dev.2...v1.6.0-dev.3) (2024-12-25)
2+
3+
4+
### Features
5+
6+
* Add status page link to about ([8a957cd](https://github.com/ReVanced/revanced-api/commit/8a957cd797e7e42f43670baaed60ac0d3543342f))
7+
* Add support for prereleases ([c25bc8b](https://github.com/ReVanced/revanced-api/commit/c25bc8b4ba2bd4bf1708f19dc8bc228a7f54d548))
8+
9+
# [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)
10+
11+
12+
### Features
13+
14+
* Make some announcements schema fields nullable ([db22874](https://github.com/ReVanced/revanced-api/commit/db22874f063bae0c9e7f0c99a20cdf1b16addd89))
15+
16+
# [1.6.0-dev.1](https://github.com/ReVanced/revanced-api/compare/v1.5.0...v1.6.0-dev.1) (2024-11-23)
17+
18+
19+
### Features
20+
21+
* Allow setting `Announcement.createdAt` when creating an announcement ([7f6e29d](https://github.com/ReVanced/revanced-api/commit/7f6e29de5205f63ac4aaea490c844b58e14000c8))
22+
123
# [1.5.0](https://github.com/ReVanced/revanced-api/compare/v1.4.0...v1.5.0) (2024-11-06)
224

325

about.example.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
"branding": {
66
"logo": "https://raw.githubusercontent.com/ReVanced/revanced-branding/main/assets/revanced-logo/revanced-logo.svg"
77
},
8+
"status": "https://status.revanced.app",
89
"contact": {
910
"email": "[email protected]"
1011
},

gradle.properties

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
org.gradle.parallel = true
22
org.gradle.caching = true
33
kotlin.code.style = official
4-
version = 1.5.0
4+
version = 1.6.0-dev.3

src/main/kotlin/app/revanced/api/configuration/APISchema.kt

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
package app.revanced.api.configuration
22

3+
import kotlinx.datetime.Clock
34
import kotlinx.datetime.LocalDateTime
5+
import kotlinx.datetime.TimeZone
6+
import kotlinx.datetime.toLocalDateTime
47
import kotlinx.serialization.Serializable
58

69
interface ApiUser {
@@ -60,10 +63,10 @@ class ApiAnnouncement(
6063
val title: String,
6164
val content: String? = null,
6265
// Using a list instead of a set because set semantics are unnecessary here.
63-
val attachments: List<String> = emptyList(),
66+
val attachments: List<String>? = null,
6467
// Using a list instead of a set because set semantics are unnecessary here.
65-
val tags: List<String> = emptyList(),
66-
val createdAt: LocalDateTime,
68+
val tags: List<String>? = null,
69+
val createdAt: LocalDateTime = Clock.System.now().toLocalDateTime(TimeZone.currentSystemDefault()),
6770
val archivedAt: LocalDateTime? = null,
6871
val level: Int = 0,
6972
)
@@ -75,9 +78,9 @@ class ApiResponseAnnouncement(
7578
val title: String,
7679
val content: String? = null,
7780
// Using a list instead of a set because set semantics are unnecessary here.
78-
val attachments: List<String> = emptyList(),
81+
val attachments: List<String>? = null,
7982
// Using a list instead of a set because set semantics are unnecessary here.
80-
val tags: List<String> = emptyList(),
83+
val tags: List<String>? = null,
8184
val createdAt: LocalDateTime,
8285
val archivedAt: LocalDateTime? = null,
8386
val level: Int = 0,
@@ -120,6 +123,7 @@ class APIAbout(
120123
// Using a list instead of a set because set semantics are unnecessary here.
121124
val socials: List<Social>?,
122125
val donations: Donations?,
126+
val status: String,
123127
) {
124128
@Serializable
125129
class Branding(

src/main/kotlin/app/revanced/api/configuration/repository/AnnouncementRepository.kt

Lines changed: 28 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -69,8 +69,7 @@ internal class AnnouncementRepository(private val database: Database) {
6969

7070
fun latestId() = latestAnnouncement?.id?.value.toApiResponseAnnouncementId()
7171

72-
fun latestId(tags: Set<String>) =
73-
tags.map { tag -> latestAnnouncementByTag[tag]?.id?.value }.toApiResponseAnnouncementId()
72+
fun latestId(tags: Set<String>) = tags.map { tag -> latestAnnouncementByTag[tag]?.id?.value }.toApiResponseAnnouncementId()
7473

7574
suspend fun paged(cursor: Int, count: Int, tags: Set<String>?) = transaction {
7675
Announcement.find {
@@ -100,13 +99,16 @@ internal class AnnouncementRepository(private val database: Database) {
10099
author = new.author
101100
title = new.title
102101
content = new.content
102+
createdAt = new.createdAt
103103
archivedAt = new.archivedAt
104104
level = new.level
105-
tags = SizedCollection(
106-
new.tags.map { tag -> Tag.find { Tags.name eq tag }.firstOrNull() ?: Tag.new { name = tag } },
107-
)
105+
if (new.tags != null) {
106+
tags = SizedCollection(
107+
new.tags.map { tag -> Tag.find { Tags.name eq tag }.firstOrNull() ?: Tag.new { name = tag } },
108+
)
109+
}
108110
}.apply {
109-
new.attachments.map { attachmentUrl ->
111+
new.attachments?.map { attachmentUrl ->
110112
Attachment.new {
111113
url = attachmentUrl
112114
announcement = this@apply
@@ -124,24 +126,28 @@ internal class AnnouncementRepository(private val database: Database) {
124126
it.archivedAt = new.archivedAt
125127
it.level = new.level
126128

127-
// Get the old tags, create new tags if they don't exist,
128-
// and delete tags that are not in the new tags, after updating the announcement.
129-
val oldTags = it.tags.toList()
130-
val updatedTags = new.tags.map { name ->
131-
Tag.find { Tags.name eq name }.firstOrNull() ?: Tag.new { this.name = name }
132-
}
133-
it.tags = SizedCollection(updatedTags)
134-
oldTags.forEach { tag ->
135-
if (tag in updatedTags || !tag.announcements.empty()) return@forEach
136-
tag.delete()
129+
if (new.tags != null) {
130+
// Get the old tags, create new tags if they don't exist,
131+
// and delete tags that are not in the new tags, after updating the announcement.
132+
val oldTags = it.tags.toList()
133+
val updatedTags = new.tags.map { name ->
134+
Tag.find { Tags.name eq name }.firstOrNull() ?: Tag.new { this.name = name }
135+
}
136+
it.tags = SizedCollection(updatedTags)
137+
oldTags.forEach { tag ->
138+
if (tag in updatedTags || !tag.announcements.empty()) return@forEach
139+
tag.delete()
140+
}
137141
}
138142

139143
// Delete old attachments and create new attachments.
140-
it.attachments.forEach { attachment -> attachment.delete() }
141-
new.attachments.map { attachment ->
142-
Attachment.new {
143-
url = attachment
144-
announcement = it
144+
if (new.attachments != null) {
145+
it.attachments.forEach { attachment -> attachment.delete() }
146+
new.attachments.map { attachment ->
147+
Attachment.new {
148+
url = attachment
149+
announcement = it
150+
}
145151
}
146152
}
147153
}?.let(::updateLatestAnnouncement) ?: Unit
@@ -174,8 +180,7 @@ internal class AnnouncementRepository(private val database: Database) {
174180
Tag.all().toList().toApiTag()
175181
}
176182

177-
private suspend fun <T> transaction(statement: suspend Transaction.() -> T) =
178-
newSuspendedTransaction(Dispatchers.IO, database, statement = statement)
183+
private suspend fun <T> transaction(statement: suspend Transaction.() -> T) = newSuspendedTransaction(Dispatchers.IO, database, statement = statement)
179184

180185
private object Announcements : IntIdTable() {
181186
val author = varchar("author", 32).nullable()

src/main/kotlin/app/revanced/api/configuration/repository/BackendRepository.kt

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -135,12 +135,14 @@ abstract class BackendRepository internal constructor(
135135
* @property tag The tag of the release.
136136
* @property assets The assets of the release.
137137
* @property createdAt The date and time the release was created.
138+
* @property prerelease Whether the release is a prerelease.
138139
* @property releaseNote The release note of the release.
139140
*/
140141
class BackendRelease(
141142
val tag: String,
142143
val releaseNote: String,
143144
val createdAt: LocalDateTime,
145+
val prerelease: Boolean,
144146
// Using a list instead of a set because set semantics are unnecessary here.
145147
val assets: List<BackendAsset>,
146148
) {
@@ -180,13 +182,13 @@ abstract class BackendRepository internal constructor(
180182
*
181183
* @param owner The owner of the repository.
182184
* @param repository The name of the repository.
183-
* @param tag The tag of the release. If null, the latest release is returned.
185+
* @param prerelease Whether to get a prerelease.
184186
* @return The release.
185187
*/
186188
abstract suspend fun release(
187189
owner: String,
188190
repository: String,
189-
tag: String? = null,
191+
prerelease: Boolean,
190192
): BackendOrganization.BackendRepository.BackendRelease
191193

192194
/**

src/main/kotlin/app/revanced/api/configuration/repository/GitHubBackendRepository.kt

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -24,10 +24,10 @@ class GitHubBackendRepository : BackendRepository("https://api.github.com", "htt
2424
override suspend fun release(
2525
owner: String,
2626
repository: String,
27-
tag: String?,
27+
prerelease: Boolean,
2828
): BackendRelease {
29-
val release: GitHubRelease = if (tag != null) {
30-
client.get(Releases.Tag(owner, repository, tag)).body()
29+
val release: GitHubRelease = if (prerelease) {
30+
client.get(Releases(owner, repository)).body<List<GitHubRelease>>().first { it.prerelease }
3131
} else {
3232
client.get(Releases.Latest(owner, repository)).body()
3333
}
@@ -36,6 +36,7 @@ class GitHubBackendRepository : BackendRepository("https://api.github.com", "htt
3636
tag = release.tagName,
3737
releaseNote = release.body,
3838
createdAt = release.createdAt.toLocalDateTime(TimeZone.UTC),
39+
prerelease = release.prerelease,
3940
assets = release.assets.map {
4041
BackendAsset(
4142
name = it.name,
@@ -163,6 +164,7 @@ class GitHubOrganization {
163164
// Using a list instead of a set because set semantics are unnecessary here.
164165
val assets: List<GitHubAsset>,
165166
val createdAt: Instant,
167+
val prerelease: Boolean,
166168
val body: String,
167169
) {
168170
@Serializable
@@ -200,10 +202,8 @@ class Organization {
200202
@Resource("/repos/{owner}/{repo}/contributors")
201203
class Contributors(val owner: String, val repo: String, @SerialName("per_page") val perPage: Int = 100)
202204

203-
class Releases {
204-
@Resource("/repos/{owner}/{repo}/releases/tags/{tag}")
205-
class Tag(val owner: String, val repo: String, val tag: String)
206-
205+
@Resource("/repos/{owner}/{repo}/releases")
206+
class Releases(val owner: String, val repo: String) {
207207
@Resource("/repos/{owner}/{repo}/releases/latest")
208208
class Latest(val owner: String, val repo: String)
209209
}

src/main/kotlin/app/revanced/api/configuration/routes/ManagerRoute.kt

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ import app.revanced.api.configuration.ApiReleaseVersion
55
import app.revanced.api.configuration.installNotarizedRoute
66
import app.revanced.api.configuration.services.ManagerService
77
import io.bkbn.kompendium.core.metadata.GetInfo
8+
import io.bkbn.kompendium.json.schema.definition.TypeDefinition
9+
import io.bkbn.kompendium.oas.payload.Parameter
810
import io.ktor.http.*
911
import io.ktor.server.application.*
1012
import io.ktor.server.plugins.ratelimit.*
@@ -19,25 +21,38 @@ internal fun Route.managerRoute() = route("manager") {
1921

2022
rateLimit(RateLimitName("weak")) {
2123
get {
22-
call.respond(managerService.latestRelease())
24+
val prerelease = call.parameters["prerelease"]?.toBoolean() ?: false
25+
26+
call.respond(managerService.latestRelease(prerelease))
2327
}
2428

2529
route("version") {
2630
installManagerVersionRouteDocumentation()
2731

2832
get {
29-
call.respond(managerService.latestVersion())
33+
val prerelease = call.parameters["prerelease"]?.toBoolean() ?: false
34+
35+
call.respond(managerService.latestVersion(prerelease))
3036
}
3137
}
3238
}
3339
}
3440

41+
private val prereleaseParameter = Parameter(
42+
name = "prerelease",
43+
`in` = Parameter.Location.query,
44+
schema = TypeDefinition.STRING,
45+
description = "Whether to get the current manager prerelease",
46+
required = false,
47+
)
48+
3549
private fun Route.installManagerRouteDocumentation() = installNotarizedRoute {
3650
tags = setOf("Manager")
3751

3852
get = GetInfo.builder {
3953
description("Get the current manager release")
4054
summary("Get current manager release")
55+
parameters(prereleaseParameter)
4156
response {
4257
description("The latest manager release")
4358
mediaTypes("application/json")
@@ -53,6 +68,7 @@ private fun Route.installManagerVersionRouteDocumentation() = installNotarizedRo
5368
get = GetInfo.builder {
5469
description("Get the current manager release version")
5570
summary("Get current manager release version")
71+
parameters(prereleaseParameter)
5672
response {
5773
description("The current manager release version")
5874
mediaTypes("application/json")

src/main/kotlin/app/revanced/api/configuration/routes/PatchesRoute.kt

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ import app.revanced.api.configuration.installCache
77
import app.revanced.api.configuration.installNotarizedRoute
88
import app.revanced.api.configuration.services.PatchesService
99
import io.bkbn.kompendium.core.metadata.GetInfo
10+
import io.bkbn.kompendium.json.schema.definition.TypeDefinition
11+
import io.bkbn.kompendium.oas.payload.Parameter
1012
import io.ktor.http.*
1113
import io.ktor.server.application.*
1214
import io.ktor.server.plugins.ratelimit.*
@@ -22,14 +24,18 @@ internal fun Route.patchesRoute() = route("patches") {
2224

2325
rateLimit(RateLimitName("weak")) {
2426
get {
25-
call.respond(patchesService.latestRelease())
27+
val prerelease = call.parameters["prerelease"]?.toBoolean() ?: false
28+
29+
call.respond(patchesService.latestRelease(prerelease))
2630
}
2731

2832
route("version") {
2933
installPatchesVersionRouteDocumentation()
3034

3135
get {
32-
call.respond(patchesService.latestVersion())
36+
val prerelease = call.parameters["prerelease"]?.toBoolean() ?: false
37+
38+
call.respond(patchesService.latestVersion(prerelease))
3339
}
3440
}
3541
}
@@ -39,7 +45,9 @@ internal fun Route.patchesRoute() = route("patches") {
3945
installPatchesListRouteDocumentation()
4046

4147
get {
42-
call.respondBytes(ContentType.Application.Json) { patchesService.list() }
48+
val prerelease = call.parameters["prerelease"]?.toBoolean() ?: false
49+
50+
call.respondBytes(ContentType.Application.Json) { patchesService.list(prerelease) }
4351
}
4452
}
4553
}
@@ -57,12 +65,21 @@ internal fun Route.patchesRoute() = route("patches") {
5765
}
5866
}
5967

68+
private val prereleaseParameter = Parameter(
69+
name = "prerelease",
70+
`in` = Parameter.Location.query,
71+
schema = TypeDefinition.STRING,
72+
description = "Whether to get the current patches prerelease",
73+
required = false,
74+
)
75+
6076
private fun Route.installPatchesRouteDocumentation() = installNotarizedRoute {
6177
tags = setOf("Patches")
6278

6379
get = GetInfo.builder {
6480
description("Get the current patches release")
6581
summary("Get current patches release")
82+
parameters(prereleaseParameter)
6683
response {
6784
description("The current patches release")
6885
mediaTypes("application/json")
@@ -78,6 +95,7 @@ private fun Route.installPatchesVersionRouteDocumentation() = installNotarizedRo
7895
get = GetInfo.builder {
7996
description("Get the current patches release version")
8097
summary("Get current patches release version")
98+
parameters(prereleaseParameter)
8199
response {
82100
description("The current patches release version")
83101
mediaTypes("application/json")
@@ -93,6 +111,7 @@ private fun Route.installPatchesListRouteDocumentation() = installNotarizedRoute
93111
get = GetInfo.builder {
94112
description("Get the list of patches from the current patches release")
95113
summary("Get list of patches from current patches release")
114+
parameters(prereleaseParameter)
96115
response {
97116
description("The list of patches")
98117
mediaTypes("application/json")

0 commit comments

Comments
 (0)