Skip to content

Commit 4e9a333

Browse files
authored
v4.2.7 RC
v4.2.7 RC
2 parents 55d803f + 56d0738 commit 4e9a333

197 files changed

Lines changed: 5131 additions & 6527 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

build.gradle.kts

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import org.gradle.api.tasks.wrapper.Wrapper.DistributionType.ALL
2+
import org.jetbrains.kotlin.gradle.dsl.JvmTarget
23
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
34

45
plugins {
@@ -27,7 +28,7 @@ buildscript {
2728
allprojects {
2829
//Project props
2930
group = "org.dreamexposure.discal"
30-
version = "4.2.6"
31+
version = "4.2.7"
3132
description = "DisCal"
3233

3334
//Plugins
@@ -50,6 +51,7 @@ allprojects {
5051
val googleServicesCalendarVersion: String by properties
5152
val googleOauthClientVersion: String by properties
5253
// Various libs
54+
val okhttpVersion: String by properties
5355
val copyDownVersion: String by properties
5456
val jsoupVersion: String by properties
5557

@@ -88,7 +90,7 @@ allprojects {
8890
implementation("org.springframework.boot:spring-boot-starter-actuator")
8991

9092
// Database
91-
implementation("io.asyncer:r2dbc-mysql")
93+
implementation("io.asyncer:r2dbc-mysql:1.3.0") // TODO: Remove hard coded version once spring includes this in bom as it is a breaking change
9294
implementation("com.mysql:mysql-connector-j")
9395

9496
// Serialization
@@ -101,6 +103,7 @@ allprojects {
101103
implementation("ch.qos.logback.contrib:logback-json-classic:$logbackContribVersion")
102104
implementation("ch.qos.logback.contrib:logback-jackson:$logbackContribVersion")
103105
implementation("io.micrometer:micrometer-registry-prometheus")
106+
implementation("io.projectreactor:reactor-core-micrometer")
104107

105108
// Google libs
106109
implementation("com.google.api-client:google-api-client:$googleApiClientVersion")
@@ -111,6 +114,7 @@ allprojects {
111114

112115
// Various Libs
113116
implementation("com.squareup.okhttp3:okhttp")
117+
implementation("com.squareup.okhttp3:okhttp-coroutines:$okhttpVersion")
114118
implementation("io.github.furstenheim:copy_down:$copyDownVersion")
115119
implementation("org.jsoup:jsoup:$jsoupVersion")
116120
}
@@ -135,9 +139,9 @@ allprojects {
135139
subprojects {
136140
tasks {
137141
withType<KotlinCompile> {
138-
kotlinOptions {
139-
freeCompilerArgs = listOf("-Xjsr305=strict")
140-
jvmTarget = java.targetCompatibility.majorVersion
142+
compilerOptions {
143+
freeCompilerArgs.set(listOf("-Xjsr305=strict"))
144+
jvmTarget.set(JvmTarget.fromTarget(java.targetCompatibility.majorVersion))
141145
}
142146
}
143147
}
@@ -146,7 +150,7 @@ subprojects {
146150
tasks {
147151
wrapper {
148152
distributionType = ALL
149-
gradleVersion = "8.2.1"
153+
gradleVersion = "8.10.2"
150154
}
151155

152156
bootJar {

cam/src/main/kotlin/org/dreamexposure/discal/cam/Cam.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ class Cam {
2727
.run(*args)
2828
LOGGER.info(GlobalVal.STATUS, "CAM is now online")
2929
} catch (e: Exception) {
30-
LOGGER.error(GlobalVal.DEFAULT, "'Spring error' by PANIC! at the CAM")
30+
LOGGER.error(GlobalVal.DEFAULT, "'Spring error' by PANIC! at the CAM", e)
3131
exitProcess(4)
3232
}
3333
}

cam/src/main/kotlin/org/dreamexposure/discal/cam/business/cronjob/HeartbeatCronJob.kt

Lines changed: 19 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import org.dreamexposure.discal.core.logger.LOGGER
1212
import org.dreamexposure.discal.core.`object`.network.discal.InstanceData
1313
import org.dreamexposure.discal.core.`object`.rest.HeartbeatRequest
1414
import org.dreamexposure.discal.core.`object`.rest.HeartbeatType
15-
import org.dreamexposure.discal.core.utils.GlobalVal
15+
import org.dreamexposure.discal.core.utils.GlobalVal.DEFAULT
1616
import org.dreamexposure.discal.core.utils.GlobalVal.JSON
1717
import org.springframework.boot.ApplicationArguments
1818
import org.springframework.boot.ApplicationRunner
@@ -31,26 +31,30 @@ class HeartbeatCronJob(
3131
override fun run(args: ApplicationArguments?) {
3232
Flux.interval(Config.HEARTBEAT_INTERVAL.getLong().asSeconds())
3333
.flatMap { heartbeat() }
34-
.doOnError { LOGGER.error(GlobalVal.DEFAULT, "[Heartbeat] Failed to heartbeat", it) }
34+
.doOnError { LOGGER.error(DEFAULT, "[Heartbeat] Failed to heartbeat", it) }
3535
.onErrorResume { Mono.empty() }
3636
.subscribe()
3737
}
3838

3939
private fun heartbeat() = mono {
40-
val requestBody = HeartbeatRequest(HeartbeatType.CAM, instanceData = InstanceData())
40+
try {
41+
val requestBody = HeartbeatRequest(HeartbeatType.CAM, instanceData = InstanceData())
4142

42-
val request = Request.Builder()
43-
.url("$apiUrl/v3/status/heartbeat")
44-
.post(objectMapper.writeValueAsString(requestBody).toRequestBody(JSON))
45-
.header("Authorization", "Int ${Config.SECRET_DISCAL_API_KEY.getString()}")
46-
.header("Content-Type", "application/json")
47-
.build()
43+
val request = Request.Builder()
44+
.url("$apiUrl/v3/status/heartbeat")
45+
.post(objectMapper.writeValueAsString(requestBody).toRequestBody(JSON))
46+
.header("Authorization", "Int ${Config.SECRET_DISCAL_API_KEY.getString()}")
47+
.header("Content-Type", "application/json")
48+
.build()
4849

49-
Mono.fromCallable(httpClient.newCall(request)::execute)
50-
.map(Response::close)
51-
.subscribeOn(Schedulers.boundedElastic())
52-
.doOnError { LOGGER.error(GlobalVal.DEFAULT, "[Heartbeat] Failed to heartbeat", it) }
53-
.onErrorResume { Mono.empty() }
54-
.subscribe()
50+
Mono.fromCallable(httpClient.newCall(request)::execute)
51+
.map(Response::close)
52+
.subscribeOn(Schedulers.boundedElastic())
53+
.doOnError { LOGGER.error(DEFAULT, "[Heartbeat] Failed to heartbeat", it) }
54+
.onErrorResume { Mono.empty() }
55+
.subscribe()
56+
} catch (ex: Exception) {
57+
LOGGER.error(DEFAULT, "[Heartbeat] Failed to heartbeat", ex)
58+
}
5559
}
5660
}
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
package org.dreamexposure.discal.cam.business.google
2+
3+
import org.dreamexposure.discal.core.business.CalendarService
4+
import org.dreamexposure.discal.core.business.CredentialService
5+
import org.dreamexposure.discal.core.business.google.GoogleAuthApiWrapper
6+
import org.dreamexposure.discal.core.exceptions.EmptyNotAllowedException
7+
import org.dreamexposure.discal.core.exceptions.NotFoundException
8+
import org.dreamexposure.discal.core.extensions.isExpiredTtl
9+
import org.dreamexposure.discal.core.logger.LOGGER
10+
import org.dreamexposure.discal.core.`object`.new.CalendarMetadata
11+
import org.dreamexposure.discal.core.`object`.new.model.discal.cam.TokenV1Model
12+
import org.springframework.stereotype.Component
13+
import java.time.Duration
14+
import java.time.Instant
15+
16+
@Component
17+
class GoogleAuthService(
18+
private val credentialService: CredentialService,
19+
private val calendarService: CalendarService,
20+
private val googleAuthApiWrapper: GoogleAuthApiWrapper,
21+
) {
22+
suspend fun requestNewAccessToken(calendar: CalendarMetadata): TokenV1Model? {
23+
if (!calendar.secrets.expiresAt.isExpiredTtl()) return TokenV1Model(calendar.secrets.accessToken, calendar.secrets.expiresAt)
24+
25+
LOGGER.debug("Refreshing access token | guildId:{} | calendar:{}", calendar.guildId, calendar.number)
26+
27+
val refreshed = googleAuthApiWrapper.refreshAccessToken(calendar.secrets.refreshToken).entity ?: return null
28+
calendar.secrets.accessToken = refreshed.accessToken
29+
calendar.secrets.expiresAt = Instant.now().plusSeconds(refreshed.expiresIn.toLong()).minus(Duration.ofMinutes(5)) // Add some wiggle room
30+
calendarService.updateCalendarMetadata(calendar)
31+
32+
LOGGER.debug("Refreshed access token | guildId:{} | calendar:{}, validUntil:{}", calendar.guildId, calendar.number, calendar.external)
33+
34+
return TokenV1Model(calendar.secrets.accessToken, calendar.secrets.expiresAt)
35+
}
36+
37+
suspend fun requestNewAccessToken(credentialId: Int): TokenV1Model {
38+
val credential = credentialService.getCredential(credentialId) ?: throw NotFoundException()
39+
if (!credential.expiresAt.isExpiredTtl()) return TokenV1Model(credential.accessToken, credential.expiresAt)
40+
41+
LOGGER.debug("Refreshing access token | credentialId:$credentialId")
42+
43+
val refreshed = googleAuthApiWrapper.refreshAccessToken(credential.refreshToken).entity ?: throw EmptyNotAllowedException()
44+
credential.accessToken = refreshed.accessToken
45+
credential.expiresAt = Instant.now().plusSeconds(refreshed.expiresIn.toLong()).minus(Duration.ofMinutes(5)) // Add some wiggle room
46+
credentialService.updateCredential(credential)
47+
48+
LOGGER.debug("Refreshed access token | credentialId:{} | validUntil:{}", credentialId, credential.expiresAt)
49+
50+
return TokenV1Model(credential.accessToken, credential.expiresAt)
51+
}
52+
}

cam/src/main/kotlin/org/dreamexposure/discal/cam/controllers/v1/SecurityController.kt

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,10 @@ package org.dreamexposure.discal.cam.controllers.v1
22

33
import org.dreamexposure.discal.cam.business.SecurityService
44
import org.dreamexposure.discal.core.annotations.SecurityRequirement
5+
import org.dreamexposure.discal.core.`object`.new.model.discal.cam.SecurityValidateV1Request
6+
import org.dreamexposure.discal.core.`object`.new.model.discal.cam.SecurityValidateV1Response
57
import org.dreamexposure.discal.core.`object`.new.security.Scope.INTERNAL_CAM_VALIDATE_TOKEN
68
import org.dreamexposure.discal.core.`object`.new.security.TokenType.INTERNAL
7-
import org.dreamexposure.discal.core.`object`.rest.v1.security.ValidateRequest
8-
import org.dreamexposure.discal.core.`object`.rest.v1.security.ValidateResponse
99
import org.springframework.http.HttpStatus
1010
import org.springframework.web.bind.annotation.PostMapping
1111
import org.springframework.web.bind.annotation.RequestBody
@@ -19,13 +19,13 @@ class SecurityController(
1919
) {
2020
@SecurityRequirement(schemas = [INTERNAL], scopes = [INTERNAL_CAM_VALIDATE_TOKEN])
2121
@PostMapping("/validate", produces = ["application/json"])
22-
suspend fun validate(@RequestBody request: ValidateRequest): ValidateResponse {
22+
suspend fun validate(@RequestBody request: SecurityValidateV1Request): SecurityValidateV1Response {
2323
val result = securityService.authenticateAndAuthorizeToken(
2424
request.token,
2525
request.schemas,
2626
request.scopes,
2727
)
2828

29-
return ValidateResponse(result.first == HttpStatus.OK, result.first, result.second)
29+
return SecurityValidateV1Response(result.first == HttpStatus.OK, result.first, result.second)
3030
}
3131
}

cam/src/main/kotlin/org/dreamexposure/discal/cam/controllers/v1/TokenController.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import discord4j.common.util.Snowflake
44
import org.dreamexposure.discal.cam.managers.CalendarAuthManager
55
import org.dreamexposure.discal.core.annotations.SecurityRequirement
66
import org.dreamexposure.discal.core.enums.calendar.CalendarHost
7-
import org.dreamexposure.discal.core.`object`.network.discal.CredentialData
7+
import org.dreamexposure.discal.core.`object`.new.model.discal.cam.TokenV1Model
88
import org.dreamexposure.discal.core.`object`.new.security.Scope.CALENDAR_TOKEN_READ
99
import org.dreamexposure.discal.core.`object`.new.security.TokenType.INTERNAL
1010
import org.springframework.web.bind.annotation.GetMapping
@@ -19,7 +19,7 @@ class TokenController(
1919
) {
2020
@SecurityRequirement(schemas = [INTERNAL], scopes = [CALENDAR_TOKEN_READ])
2121
@GetMapping(produces = ["application/json"])
22-
suspend fun getToken(@RequestParam host: CalendarHost, @RequestParam id: Int, @RequestParam guild: Snowflake?): CredentialData? {
22+
suspend fun getToken(@RequestParam host: CalendarHost, @RequestParam id: Int, @RequestParam guild: Snowflake?): TokenV1Model? {
2323
return calendarAuthManager.getCredentialData(host, id, guild)
2424
}
2525
}

cam/src/main/kotlin/org/dreamexposure/discal/cam/google/GoogleAuth.kt

Lines changed: 0 additions & 118 deletions
This file was deleted.

cam/src/main/kotlin/org/dreamexposure/discal/cam/json/google/ErrorData.kt

Lines changed: 0 additions & 6 deletions
This file was deleted.

cam/src/main/kotlin/org/dreamexposure/discal/cam/json/google/RefreshData.kt

Lines changed: 0 additions & 11 deletions
This file was deleted.

0 commit comments

Comments
 (0)