Got ahead of myself

Recreated some of the V2 endpoints that the legacy website still needs.

Definitely could do a better job at fixing this code, but for now I'm looking just to make sure it works functionally the same and I care less about making this respect new patterns since its deprecated anyways
This commit is contained in:
NovaFox161
2024-12-08 18:18:00 -06:00
parent 2a4ce80511
commit 1212dba7bc
5 changed files with 294 additions and 0 deletions

View File

@@ -0,0 +1,40 @@
package org.dreamexposure.discal.core.`object`.new.model.discal.v2
import com.fasterxml.jackson.annotation.JsonProperty
import discord4j.common.util.Snowflake
import org.dreamexposure.discal.core.`object`.new.Calendar
import java.time.ZoneId
@Deprecated("Prefer to use V3 APIs, this is for compatibility for the old site old")
data class CalendarV2Model(
@JsonProperty("guild_id")
val guildId: Snowflake,
@JsonProperty("calendar_id")
val calendarId: String,
@JsonProperty("calendar_address")
val calendarAddress: String,
@JsonProperty("calendar_number")
val calendarNumber: Int,
val host: String,
@JsonProperty("host_link")
val hostLink: String,
val external: Boolean,
val name: String,
val description: String,
val timezone: ZoneId,
val link: String,
) {
constructor(calendar: Calendar): this(
guildId = calendar.metadata.guildId,
calendarId = calendar.metadata.id,
calendarAddress = calendar.metadata.address,
calendarNumber = calendar.metadata.number,
host = calendar.metadata.host.name,
hostLink = calendar.hostLink,
external = calendar.metadata.external,
name = calendar.name,
description = calendar.description,
timezone = calendar.timezone,
link = calendar.link,
)
}

View File

@@ -0,0 +1,47 @@
package org.dreamexposure.discal.core.`object`.new.model.discal.v2
import com.fasterxml.jackson.annotation.JsonProperty
import discord4j.common.util.Snowflake
import org.dreamexposure.discal.core.`object`.event.Recurrence
import org.dreamexposure.discal.core.`object`.new.Calendar
import org.dreamexposure.discal.core.`object`.new.Event
@Deprecated("Prefer to use V3 API implementation. This exists to maintain compatibility for the legacy website")
data class EventV2Model(
@JsonProperty("guild_id")
val guildId: Snowflake,
val calendar: CalendarV2Model,
@JsonProperty("event_id")
val eventId: String,
@JsonProperty("epoch_start")
val epochStart: Long,
@JsonProperty("epoch_end")
val epochEnd: Long,
val name: String,
val description: String,
val location: String,
@JsonProperty("is_parent")
val isParent: Boolean,
val color: String,
val recur: Boolean,
val recurrence: Recurrence,
val rrule: String,
val image: String,
) {
constructor(event: Event, calendar: Calendar): this(
guildId = event.guildId,
calendar = CalendarV2Model(calendar),
eventId = event.id,
epochStart = event.start.toEpochMilli(),
epochEnd = event.end.toEpochMilli(),
name = event.name,
description = event.description,
location = event.location,
isParent = !event.id.contains("_"),
color = event.color.name,
recur = event.recur,
recurrence = event.recurrence,
rrule = event.recurrence.toRRule(),
image = event.image,
)
}

View File

@@ -0,0 +1,63 @@
package org.dreamexposure.discal.server.endpoints.v2.calendar
import com.fasterxml.jackson.databind.ObjectMapper
import discord4j.common.util.Snowflake
import kotlinx.coroutines.reactor.mono
import kotlinx.serialization.encodeToString
import org.dreamexposure.discal.core.annotations.SecurityRequirement
import org.dreamexposure.discal.core.business.CalendarService
import org.dreamexposure.discal.core.logger.LOGGER
import org.dreamexposure.discal.core.`object`.new.model.discal.v2.CalendarV2Model
import org.dreamexposure.discal.core.utils.GlobalVal
import org.dreamexposure.discal.server.utils.Authentication
import org.dreamexposure.discal.server.utils.responseMessage
import org.json.JSONException
import org.json.JSONObject
import org.springframework.http.server.reactive.ServerHttpResponse
import org.springframework.web.bind.annotation.PostMapping
import org.springframework.web.bind.annotation.RequestBody
import org.springframework.web.bind.annotation.RequestMapping
import org.springframework.web.bind.annotation.RestController
import org.springframework.web.server.ServerWebExchange
import reactor.core.publisher.Mono
@RestController
@RequestMapping("/v2/calendar")
class GetCalendarEndpoint(
private val authentication: Authentication,
private val calendarService: CalendarService,
private val objectMapper: ObjectMapper,
) {
@PostMapping("/get", produces = ["application/json"])
@SecurityRequirement(disableSecurity = true, scopes = [])
fun getCalendar(swe: ServerWebExchange, response: ServerHttpResponse, @RequestBody rBody: String): Mono<String> {
return authentication.authenticate(swe).flatMap { authState ->
if (!authState.success) {
response.rawStatusCode = authState.status
return@flatMap Mono.just(GlobalVal.JSON_FORMAT.encodeToString(authState))
}
//Handle request
val body = JSONObject(rBody)
val guildId = Snowflake.of(body.getString("guild_id"))
val calNumber = body.getInt("calendar_number")
return@flatMap mono {calendarService.getCalendar(guildId, calNumber) }
.map(::CalendarV2Model)
.map { objectMapper.writeValueAsString(it) }
.switchIfEmpty(responseMessage("Calendar not found")
.doOnNext { response.rawStatusCode = GlobalVal.STATUS_NOT_FOUND }
)
}.onErrorResume(JSONException::class.java) {
LOGGER.trace("[API-v2] JSON error. Bad request?", it)
response.rawStatusCode = GlobalVal.STATUS_BAD_REQUEST
return@onErrorResume responseMessage("Bad Request")
}.onErrorResume {
LOGGER.error(GlobalVal.DEFAULT, "[API-v2] get calendar error", it)
response.rawStatusCode = GlobalVal.STATUS_INTERNAL_ERROR
return@onErrorResume responseMessage("Internal Server Error")
}
}
}

View File

@@ -0,0 +1,73 @@
package org.dreamexposure.discal.server.endpoints.v2.calendar
import com.fasterxml.jackson.databind.ObjectMapper
import discord4j.common.util.Snowflake
import kotlinx.coroutines.reactor.mono
import org.dreamexposure.discal.core.logger.LOGGER
import org.dreamexposure.discal.core.annotations.SecurityRequirement
import org.dreamexposure.discal.core.business.CalendarService
import org.dreamexposure.discal.core.utils.GlobalVal
import org.dreamexposure.discal.server.utils.Authentication
import org.dreamexposure.discal.server.utils.responseMessage
import org.json.JSONArray
import org.json.JSONException
import org.json.JSONObject
import org.springframework.http.server.reactive.ServerHttpResponse
import org.springframework.web.bind.annotation.PostMapping
import org.springframework.web.bind.annotation.RequestBody
import org.springframework.web.bind.annotation.RequestMapping
import org.springframework.web.bind.annotation.RestController
import org.springframework.web.server.ServerWebExchange
import reactor.core.publisher.Mono
import java.time.Instant
import kotlinx.serialization.encodeToString
import org.dreamexposure.discal.core.`object`.new.model.discal.v2.EventV2Model
@RestController
@RequestMapping("/v2/events/list")
class ListEventMonthEndpoint(
private val authentication: Authentication,
private val calendarService: CalendarService,
private val objectMapper: ObjectMapper,
) {
@PostMapping("/month", produces = ["application/json"])
@SecurityRequirement(disableSecurity = true, scopes = [])
fun listByMonth(swe: ServerWebExchange, response: ServerHttpResponse, @RequestBody rBody: String): Mono<String> {
return authentication.authenticate(swe).flatMap { authState ->
if (!authState.success) {
response.rawStatusCode = authState.status
return@flatMap Mono.just(GlobalVal.JSON_FORMAT.encodeToString(authState))
}
//Handle request
val body = JSONObject(rBody)
val guildId = Snowflake.of(body.getString("guild_id"))
val calendarNumber = body.getInt("calendar_number")
val start = Instant.ofEpochMilli(body.getLong("epoch_start"))
val daysInMonth = body.getInt("days_in_month")
mono { calendarService.getCalendar(guildId, calendarNumber) }.flatMap { calendar ->
mono { calendarService.getEventsInMonth(guildId, calendarNumber, start, daysInMonth) }.map { events ->
events.map { objectMapper.writeValueAsString(EventV2Model(it, calendar)) }
}
}.map(::JSONArray)
.map { JSONObject().put("events", it).put("message", "Success").toString() }
.doOnNext { response.rawStatusCode = GlobalVal.STATUS_SUCCESS }
.switchIfEmpty(responseMessage("Calendar not found")
.doOnNext { response.rawStatusCode = GlobalVal.STATUS_NOT_FOUND }
)
}.onErrorResume(JSONException::class.java) {
LOGGER.trace("[API-v2] JSON error. Bad request?", it)
response.rawStatusCode = GlobalVal.STATUS_BAD_REQUEST
return@onErrorResume responseMessage("Bad Request")
}.onErrorResume {
LOGGER.error(GlobalVal.DEFAULT, "[API-v2] list events by month error", it)
response.rawStatusCode = GlobalVal.STATUS_INTERNAL_ERROR
return@onErrorResume responseMessage("Internal Server Error")
}
}
}

View File

@@ -0,0 +1,71 @@
package org.dreamexposure.discal.server.endpoints.v2.event.list
import com.fasterxml.jackson.databind.ObjectMapper
import discord4j.common.util.Snowflake
import kotlinx.coroutines.reactor.mono
import kotlinx.serialization.encodeToString
import org.dreamexposure.discal.core.annotations.SecurityRequirement
import org.dreamexposure.discal.core.business.CalendarService
import org.dreamexposure.discal.core.logger.LOGGER
import org.dreamexposure.discal.core.`object`.new.model.discal.v2.EventV2Model
import org.dreamexposure.discal.core.utils.GlobalVal
import org.dreamexposure.discal.server.utils.Authentication
import org.dreamexposure.discal.server.utils.responseMessage
import org.json.JSONArray
import org.json.JSONException
import org.json.JSONObject
import org.springframework.http.server.reactive.ServerHttpResponse
import org.springframework.web.bind.annotation.PostMapping
import org.springframework.web.bind.annotation.RequestBody
import org.springframework.web.bind.annotation.RequestMapping
import org.springframework.web.bind.annotation.RestController
import org.springframework.web.server.ServerWebExchange
import reactor.core.publisher.Mono
import java.time.Instant
@RestController
@RequestMapping("/v2/events/list")
class ListEventRangeEndpoint(
private val authentication: Authentication,
private val calendarService: CalendarService,
private val objectMapper: ObjectMapper,
) {
@PostMapping("/range", produces = ["application/json"])
@SecurityRequirement(disableSecurity = true, scopes = [])
fun listByRange(swe: ServerWebExchange, response: ServerHttpResponse, @RequestBody rBody: String): Mono<String> {
return authentication.authenticate(swe).flatMap { authState ->
if (!authState.success) {
response.rawStatusCode = authState.status
return@flatMap Mono.just(GlobalVal.JSON_FORMAT.encodeToString(authState))
}
//Handle request
val body = JSONObject(rBody)
val guildId = Snowflake.of(body.getString("guild_id"))
val calendarNumber = body.getInt("calendar_number")
val start = Instant.ofEpochMilli(body.getLong("epoch_start"))
val end = Instant.ofEpochMilli(body.getLong("epoch_end"))
mono { calendarService.getCalendar(guildId, calendarNumber) }.flatMap { calendar ->
mono { calendarService.getEventsInTimeRange(guildId, calendarNumber, start, end) }.map { events ->
events.map { objectMapper.writeValueAsString(EventV2Model(it, calendar)) }
}
}.map(::JSONArray)
.map { JSONObject().put("events", it).put("message", "Success").toString() }
.doOnNext { response.rawStatusCode = GlobalVal.STATUS_SUCCESS }
.switchIfEmpty(responseMessage("Calendar not found")
.doOnNext { response.rawStatusCode = GlobalVal.STATUS_NOT_FOUND }
)
}.onErrorResume(JSONException::class.java) {
LOGGER.trace("[API-v2] JSON error. Bad request?", it)
response.rawStatusCode = GlobalVal.STATUS_BAD_REQUEST
return@onErrorResume responseMessage("Bad Request")
}.onErrorResume {
LOGGER.error(GlobalVal.DEFAULT, "[API-v2] list events by range error", it)
response.rawStatusCode = GlobalVal.STATUS_INTERNAL_ERROR
return@onErrorResume responseMessage("Internal Server Error")
}
}
}