mirror of
https://github.com/DreamExposure/DisCal-Discord-Bot.git
synced 2026-01-25 13:28:26 -06:00
Start using Dependency Injection
Starting small for now, will slowly expand it
This commit is contained in:
@@ -19,6 +19,7 @@ import discord4j.store.jdk.JdkStoreService
|
||||
import discord4j.store.redis.RedisStoreService
|
||||
import io.lettuce.core.RedisClient
|
||||
import io.lettuce.core.RedisURI
|
||||
import org.dreamexposure.discal.Application
|
||||
import org.dreamexposure.discal.client.listeners.discord.ChannelDeleteListener
|
||||
import org.dreamexposure.discal.client.listeners.discord.MessageCreateListener
|
||||
import org.dreamexposure.discal.client.listeners.discord.ReadyEventListener
|
||||
@@ -35,8 +36,7 @@ import org.dreamexposure.discal.core.logger.LogFeed
|
||||
import org.dreamexposure.discal.core.logger.`object`.LogObject
|
||||
import org.dreamexposure.discal.core.network.google.Authorization
|
||||
import org.springframework.boot.SpringApplication
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication
|
||||
import org.springframework.boot.autoconfigure.session.SessionAutoConfiguration
|
||||
import org.springframework.stereotype.Component
|
||||
import reactor.core.publisher.Flux
|
||||
import reactor.core.publisher.Mono
|
||||
import java.io.FileReader
|
||||
@@ -45,7 +45,7 @@ import java.util.*
|
||||
import javax.annotation.PreDestroy
|
||||
import kotlin.system.exitProcess
|
||||
|
||||
@SpringBootApplication(exclude = [SessionAutoConfiguration::class])
|
||||
@Component
|
||||
class DisCalClient {
|
||||
companion object {
|
||||
@JvmStatic
|
||||
@@ -94,7 +94,7 @@ class DisCalClient {
|
||||
|
||||
//Start Spring
|
||||
try {
|
||||
val app = SpringApplication(DisCalClient::class.java)
|
||||
val app = SpringApplication(Application::class.java)
|
||||
app.setAdditionalProfiles(BotSettings.PROFILE.get())
|
||||
app.run(*args)
|
||||
} catch (e: Exception) {
|
||||
|
||||
@@ -4,7 +4,6 @@ import io.r2dbc.spi.ConnectionFactories
|
||||
import io.r2dbc.spi.ConnectionFactory
|
||||
import io.r2dbc.spi.ConnectionFactoryOptions
|
||||
import org.dreamexposure.discal.core.`object`.BotSettings
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration
|
||||
import org.springframework.boot.web.server.ConfigurableWebServerFactory
|
||||
import org.springframework.boot.web.server.ErrorPage
|
||||
import org.springframework.boot.web.server.WebServerFactoryCustomizer
|
||||
@@ -20,7 +19,6 @@ import org.springframework.web.reactive.config.WebFluxConfigurer
|
||||
|
||||
@Configuration
|
||||
@EnableWebFlux
|
||||
@EnableAutoConfiguration
|
||||
class WebFluxConfig : WebFluxConfigurer, WebServerFactoryCustomizer<ConfigurableWebServerFactory> {
|
||||
|
||||
override fun customize(factory: ConfigurableWebServerFactory?) {
|
||||
|
||||
@@ -10,6 +10,8 @@ import org.joda.time.Interval;
|
||||
import org.joda.time.Period;
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONObject;
|
||||
import org.springframework.stereotype.Component;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import java.lang.management.ManagementFactory;
|
||||
import java.lang.management.RuntimeMXBean;
|
||||
@@ -17,8 +19,6 @@ import java.util.ArrayList;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
/**
|
||||
* @author NovaFox161
|
||||
* Date Created: 9/8/2018
|
||||
@@ -28,6 +28,7 @@ import reactor.core.publisher.Mono;
|
||||
* Contact: nova@dreamexposure.org
|
||||
*/
|
||||
@SuppressWarnings("Duplicates")
|
||||
@Component
|
||||
public class NetworkInfo {
|
||||
private final List<ConnectedClient> clients = new ArrayList<>();
|
||||
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
package org.dreamexposure.discal
|
||||
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication
|
||||
import org.springframework.boot.autoconfigure.session.SessionAutoConfiguration
|
||||
|
||||
@SpringBootApplication(exclude = [SessionAutoConfiguration::class])
|
||||
class Application
|
||||
@@ -1,7 +1,6 @@
|
||||
package org.dreamexposure.discal.server
|
||||
|
||||
import discord4j.core.DiscordClient
|
||||
import discord4j.core.DiscordClientBuilder
|
||||
import org.dreamexposure.discal.Application
|
||||
import org.dreamexposure.discal.core.`object`.BotSettings
|
||||
import org.dreamexposure.discal.core.`object`.network.discal.NetworkInfo
|
||||
import org.dreamexposure.discal.core.calendar.CalendarAuth
|
||||
@@ -9,32 +8,42 @@ import org.dreamexposure.discal.core.database.DatabaseManager
|
||||
import org.dreamexposure.discal.core.logger.LogFeed
|
||||
import org.dreamexposure.discal.core.logger.`object`.LogObject
|
||||
import org.dreamexposure.discal.core.network.google.Authorization
|
||||
import org.dreamexposure.discal.server.network.dbotsgg.UpdateDBotsData
|
||||
import org.dreamexposure.discal.server.network.discal.NetworkMediator
|
||||
import org.dreamexposure.discal.server.network.topgg.UpdateTopStats
|
||||
import org.dreamexposure.discal.server.utils.Authentication
|
||||
import org.dreamexposure.novautils.database.DatabaseSettings
|
||||
import org.flywaydb.core.Flyway
|
||||
import org.flywaydb.core.api.exception.FlywayValidateException
|
||||
import org.flywaydb.core.internal.command.DbMigrate
|
||||
import org.springframework.boot.ApplicationArguments
|
||||
import org.springframework.boot.ApplicationRunner
|
||||
import org.springframework.boot.SpringApplication
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication
|
||||
import org.springframework.boot.autoconfigure.session.SessionAutoConfiguration
|
||||
import org.springframework.boot.system.ApplicationPid
|
||||
import org.springframework.stereotype.Component
|
||||
import java.io.FileReader
|
||||
import java.util.*
|
||||
import javax.annotation.PreDestroy
|
||||
import kotlin.system.exitProcess
|
||||
import org.dreamexposure.novautils.database.DatabaseManager as NovaUtilsDatabaseManager
|
||||
|
||||
@SpringBootApplication(exclude = [SessionAutoConfiguration::class])
|
||||
class DisCalServer {
|
||||
@Component
|
||||
class DisCalServer(val networkInfo: NetworkInfo) : ApplicationRunner {
|
||||
|
||||
override fun run(args: ApplicationArguments) {
|
||||
//Handle the rest of the bullshit
|
||||
Authentication.init()
|
||||
|
||||
//Save pid
|
||||
networkInfo.pid = ApplicationPid().toString()
|
||||
LogFeed.log(LogObject.forStatus("Started Server/API", "Server and API are now online!"))
|
||||
}
|
||||
|
||||
@PreDestroy
|
||||
fun onShutdown() {
|
||||
LogFeed.log(LogObject.forStatus("API shutting down", "Server/API shutting down..."))
|
||||
Authentication.shutdown()
|
||||
DatabaseManager.disconnectFromMySQL()
|
||||
}
|
||||
|
||||
companion object {
|
||||
val networkInfo = NetworkInfo()
|
||||
|
||||
lateinit var client: DiscordClient
|
||||
internal set
|
||||
|
||||
@JvmStatic
|
||||
fun main(args: Array<String>) {
|
||||
//Get settings
|
||||
@@ -56,11 +65,9 @@ class DisCalServer {
|
||||
//Start Google Authorization daemon
|
||||
Authorization.getAuth().init()
|
||||
|
||||
client = DiscordClientBuilder.create(BotSettings.TOKEN.get()).build()
|
||||
|
||||
//Start up spring
|
||||
try {
|
||||
val app = SpringApplication(DisCalServer::class.java)
|
||||
val app = SpringApplication(Application::class.java)
|
||||
app.setAdditionalProfiles(BotSettings.PROFILE.get())
|
||||
app.run(*args)
|
||||
} catch (e: Exception) {
|
||||
@@ -68,31 +75,8 @@ class DisCalServer {
|
||||
LogFeed.log(LogObject.forException("Spring error", "by 'PANIC! AT THE API'", e, DisCalServer::class.java))
|
||||
exitProcess(4)
|
||||
}
|
||||
|
||||
//Start network monitoring
|
||||
NetworkMediator.init()
|
||||
|
||||
//Handle the rest of the bullshit
|
||||
UpdateTopStats.init()
|
||||
UpdateDBotsData.init()
|
||||
Authentication.init()
|
||||
|
||||
//Save pid
|
||||
networkInfo.pid = ApplicationPid().toString()
|
||||
|
||||
LogFeed.log(LogObject.forStatus("Started Server/API", "Server and API are now online!"))
|
||||
}
|
||||
}
|
||||
|
||||
@PreDestroy
|
||||
fun onShutdown() {
|
||||
LogFeed.log(LogObject.forStatus("API shutting down", "Server/API shutting down..."))
|
||||
Authentication.shutdown()
|
||||
NetworkMediator.shutdown()
|
||||
UpdateTopStats.shutdown()
|
||||
UpdateDBotsData.shutdown()
|
||||
DatabaseManager.disconnectFromMySQL()
|
||||
}
|
||||
}
|
||||
|
||||
private fun handleMigrations(repair: Boolean) {
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
package org.dreamexposure.discal.server.conf
|
||||
|
||||
import discord4j.core.DiscordClient
|
||||
import discord4j.core.DiscordClientBuilder
|
||||
import org.dreamexposure.discal.core.`object`.BotSettings
|
||||
import org.springframework.context.annotation.Bean
|
||||
import org.springframework.context.annotation.Configuration
|
||||
|
||||
@Configuration
|
||||
class DiscordConfiguration {
|
||||
|
||||
@Bean
|
||||
fun discordClient(): DiscordClient {
|
||||
return DiscordClientBuilder.create(BotSettings.TOKEN.get()).build()
|
||||
}
|
||||
}
|
||||
@@ -4,7 +4,6 @@ import io.r2dbc.spi.ConnectionFactories
|
||||
import io.r2dbc.spi.ConnectionFactory
|
||||
import io.r2dbc.spi.ConnectionFactoryOptions
|
||||
import org.dreamexposure.discal.core.`object`.BotSettings
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration
|
||||
import org.springframework.boot.web.server.ConfigurableWebServerFactory
|
||||
import org.springframework.boot.web.server.ErrorPage
|
||||
import org.springframework.boot.web.server.WebServerFactoryCustomizer
|
||||
@@ -21,7 +20,6 @@ import org.springframework.web.reactive.config.EnableWebFlux
|
||||
|
||||
@Configuration
|
||||
@EnableWebFlux
|
||||
@EnableAutoConfiguration
|
||||
class WebFluxConfig : WebServerFactoryCustomizer<ConfigurableWebServerFactory> {
|
||||
|
||||
override fun customize(factory: ConfigurableWebServerFactory?) {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package org.dreamexposure.discal.server.endpoints.v2.announcement
|
||||
|
||||
import discord4j.common.util.Snowflake
|
||||
import discord4j.core.DiscordClient
|
||||
import kotlinx.serialization.encodeToString
|
||||
import kotlinx.serialization.json.Json
|
||||
import org.dreamexposure.discal.core.`object`.announcement.Announcement
|
||||
@@ -11,7 +12,6 @@ import org.dreamexposure.discal.core.extensions.discord4j.createAnnouncement
|
||||
import org.dreamexposure.discal.core.logger.LogFeed
|
||||
import org.dreamexposure.discal.core.logger.`object`.LogObject
|
||||
import org.dreamexposure.discal.core.utils.GlobalConst
|
||||
import org.dreamexposure.discal.server.DisCalServer
|
||||
import org.dreamexposure.discal.server.utils.Authentication
|
||||
import org.dreamexposure.discal.server.utils.responseMessage
|
||||
import org.json.JSONException
|
||||
@@ -26,7 +26,7 @@ import reactor.core.publisher.Mono
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/v2/announcement")
|
||||
class CreateAnnouncementEndpoint {
|
||||
class CreateAnnouncementEndpoint(val client: DiscordClient) {
|
||||
@PostMapping("/create", produces = ["application/json"])
|
||||
fun create(swe: ServerWebExchange, response: ServerHttpResponse, @RequestBody rBody: String): Mono<String> {
|
||||
return Authentication.authenticate(swe).flatMap { authState ->
|
||||
@@ -65,7 +65,7 @@ class CreateAnnouncementEndpoint {
|
||||
|
||||
announcement.publish = body.optBoolean("publish", false)
|
||||
|
||||
return@flatMap DisCalServer.client.getGuildById(guildId).createAnnouncement(announcement).flatMap { success ->
|
||||
return@flatMap client.getGuildById(guildId).createAnnouncement(announcement).flatMap { success ->
|
||||
if (success) {
|
||||
response.rawStatusCode = GlobalConst.STATUS_SUCCESS
|
||||
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
package org.dreamexposure.discal.server.endpoints.v2.announcement
|
||||
|
||||
import discord4j.common.util.Snowflake
|
||||
import discord4j.core.DiscordClient
|
||||
import kotlinx.serialization.encodeToString
|
||||
import kotlinx.serialization.json.Json
|
||||
import org.dreamexposure.discal.core.extensions.discord4j.deleteAnnouncement
|
||||
import org.dreamexposure.discal.core.logger.LogFeed
|
||||
import org.dreamexposure.discal.core.logger.`object`.LogObject
|
||||
import org.dreamexposure.discal.core.utils.GlobalConst
|
||||
import org.dreamexposure.discal.server.DisCalServer
|
||||
import org.dreamexposure.discal.server.utils.Authentication
|
||||
import org.dreamexposure.discal.server.utils.responseMessage
|
||||
import org.json.JSONException
|
||||
@@ -23,7 +23,7 @@ import java.util.*
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/v2/announcement")
|
||||
class DeleteAnnouncementEndpoint {
|
||||
class DeleteAnnouncementEndpoint(val client: DiscordClient) {
|
||||
@PostMapping("/delete", produces = ["application/json"])
|
||||
fun delete(swe: ServerWebExchange, response: ServerHttpResponse, @RequestBody rBody: String): Mono<String> {
|
||||
return Authentication.authenticate(swe).flatMap { authState ->
|
||||
@@ -40,7 +40,7 @@ class DeleteAnnouncementEndpoint {
|
||||
val guildId = Snowflake.of(body.getString("guild_id"))
|
||||
val announcementId = UUID.fromString(body.getString("announcement_id"))
|
||||
|
||||
return@flatMap DisCalServer.client.getGuildById(guildId).deleteAnnouncement(announcementId)
|
||||
return@flatMap client.getGuildById(guildId).deleteAnnouncement(announcementId)
|
||||
.then(responseMessage("Success")
|
||||
.doOnNext { response.rawStatusCode = GlobalConst.STATUS_SUCCESS }
|
||||
)
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
package org.dreamexposure.discal.server.endpoints.v2.announcement
|
||||
|
||||
import discord4j.common.util.Snowflake
|
||||
import discord4j.core.DiscordClient
|
||||
import kotlinx.serialization.encodeToString
|
||||
import kotlinx.serialization.json.Json
|
||||
import org.dreamexposure.discal.core.extensions.discord4j.getAnnouncement
|
||||
import org.dreamexposure.discal.core.logger.LogFeed
|
||||
import org.dreamexposure.discal.core.logger.`object`.LogObject
|
||||
import org.dreamexposure.discal.core.utils.GlobalConst
|
||||
import org.dreamexposure.discal.server.DisCalServer
|
||||
import org.dreamexposure.discal.server.utils.Authentication
|
||||
import org.dreamexposure.discal.server.utils.responseMessage
|
||||
import org.json.JSONException
|
||||
@@ -23,7 +23,7 @@ import java.util.*
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/v2/announcement")
|
||||
class GetAnnouncementEndpoint {
|
||||
class GetAnnouncementEndpoint(val client: DiscordClient) {
|
||||
@PostMapping("/get", produces = ["application/json"])
|
||||
fun get(swe: ServerWebExchange, response: ServerHttpResponse, @RequestBody rBody: String): Mono<String> {
|
||||
return Authentication.authenticate(swe).flatMap { authState ->
|
||||
@@ -37,7 +37,7 @@ class GetAnnouncementEndpoint {
|
||||
val guildId = Snowflake.of(body.getString("guild_id"))
|
||||
val announcementId = UUID.fromString(body.getString("announcement_id"))
|
||||
|
||||
return@flatMap DisCalServer.client.getGuildById(guildId).getAnnouncement(announcementId)
|
||||
return@flatMap client.getGuildById(guildId).getAnnouncement(announcementId)
|
||||
.map(Json.Default::encodeToString)
|
||||
.doOnNext { response.rawStatusCode = GlobalConst.STATUS_SUCCESS }
|
||||
.switchIfEmpty(responseMessage("Announcement not found")
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
package org.dreamexposure.discal.server.endpoints.v2.announcement
|
||||
|
||||
import discord4j.common.util.Snowflake
|
||||
import discord4j.core.DiscordClient
|
||||
import kotlinx.serialization.encodeToString
|
||||
import kotlinx.serialization.json.Json
|
||||
import org.dreamexposure.discal.core.extensions.discord4j.getAllAnnouncements
|
||||
import org.dreamexposure.discal.core.logger.LogFeed
|
||||
import org.dreamexposure.discal.core.logger.`object`.LogObject
|
||||
import org.dreamexposure.discal.core.utils.GlobalConst
|
||||
import org.dreamexposure.discal.server.DisCalServer
|
||||
import org.dreamexposure.discal.server.utils.Authentication
|
||||
import org.dreamexposure.discal.server.utils.responseMessage
|
||||
import org.json.JSONArray
|
||||
@@ -23,7 +23,7 @@ import reactor.core.publisher.Mono
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/v2/announcement")
|
||||
class ListAnnouncementEndpoint {
|
||||
class ListAnnouncementEndpoint(val client: DiscordClient) {
|
||||
@PostMapping("/list", produces = ["application/json"])
|
||||
fun list(swe: ServerWebExchange, response: ServerHttpResponse, @RequestBody rBody: String): Mono<String> {
|
||||
return Authentication.authenticate(swe).flatMap { authState ->
|
||||
@@ -36,7 +36,7 @@ class ListAnnouncementEndpoint {
|
||||
val body = JSONObject(rBody)
|
||||
val guildId = Snowflake.of(body.getString("guild_id"))
|
||||
|
||||
return@flatMap DisCalServer.client.getGuildById(guildId).getAllAnnouncements()
|
||||
return@flatMap client.getGuildById(guildId).getAllAnnouncements()
|
||||
.map(Json.Default::encodeToString)
|
||||
.collectList()
|
||||
.map { JSONArray(it) }
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package org.dreamexposure.discal.server.endpoints.v2.announcement
|
||||
|
||||
import discord4j.common.util.Snowflake
|
||||
import discord4j.core.DiscordClient
|
||||
import kotlinx.serialization.encodeToString
|
||||
import kotlinx.serialization.json.Json
|
||||
import org.dreamexposure.discal.core.enums.announcement.AnnouncementModifier
|
||||
@@ -11,7 +12,6 @@ import org.dreamexposure.discal.core.extensions.discord4j.updateAnnouncement
|
||||
import org.dreamexposure.discal.core.logger.LogFeed
|
||||
import org.dreamexposure.discal.core.logger.`object`.LogObject
|
||||
import org.dreamexposure.discal.core.utils.GlobalConst
|
||||
import org.dreamexposure.discal.server.DisCalServer
|
||||
import org.dreamexposure.discal.server.utils.Authentication
|
||||
import org.dreamexposure.discal.server.utils.responseMessage
|
||||
import org.json.JSONException
|
||||
@@ -27,7 +27,7 @@ import java.util.*
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/v2/announcement")
|
||||
class UpdateAnnouncementEndpoint {
|
||||
class UpdateAnnouncementEndpoint(val client: DiscordClient) {
|
||||
@PostMapping("/update", produces = ["application/json"])
|
||||
fun update(swe: ServerWebExchange, response: ServerHttpResponse, @RequestBody rBody: String): Mono<String> {
|
||||
return Authentication.authenticate(swe).flatMap { authState ->
|
||||
@@ -44,7 +44,7 @@ class UpdateAnnouncementEndpoint {
|
||||
val guildId = Snowflake.of(body.getString("guild_id"))
|
||||
val announcementId = UUID.fromString(body.getString("announcement_id"))
|
||||
|
||||
val guild = DisCalServer.client.getGuildById(guildId)
|
||||
val guild = client.getGuildById(guildId)
|
||||
|
||||
return@flatMap guild.getAnnouncement(announcementId).flatMap { ann ->
|
||||
ann.announcementChannelId = body.optString("channel", ann.announcementChannelId)
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package org.dreamexposure.discal.server.endpoints.v2.calendar
|
||||
|
||||
import discord4j.common.util.Snowflake
|
||||
import discord4j.core.DiscordClient
|
||||
import kotlinx.serialization.encodeToString
|
||||
import kotlinx.serialization.json.Json
|
||||
import org.dreamexposure.discal.core.entities.Calendar
|
||||
@@ -8,7 +9,6 @@ import org.dreamexposure.discal.core.extensions.discord4j.getCalendar
|
||||
import org.dreamexposure.discal.core.logger.LogFeed
|
||||
import org.dreamexposure.discal.core.logger.`object`.LogObject
|
||||
import org.dreamexposure.discal.core.utils.GlobalConst
|
||||
import org.dreamexposure.discal.server.DisCalServer
|
||||
import org.dreamexposure.discal.server.utils.Authentication
|
||||
import org.dreamexposure.discal.server.utils.responseMessage
|
||||
import org.json.JSONException
|
||||
@@ -23,7 +23,7 @@ import reactor.core.publisher.Mono
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/v2/calendar")
|
||||
class DeleteCalendarEndpoint {
|
||||
class DeleteCalendarEndpoint(val client: DiscordClient) {
|
||||
@PostMapping("/delete", produces = ["application/json"])
|
||||
fun deleteCalendar(swe: ServerWebExchange, response: ServerHttpResponse, @RequestBody rBody: String): Mono<String> {
|
||||
return Authentication.authenticate(swe).flatMap { authState ->
|
||||
@@ -40,7 +40,7 @@ class DeleteCalendarEndpoint {
|
||||
val guildId = Snowflake.of(body.getString("guild_id"))
|
||||
val calendarNumber = body.getInt("calendar_number")
|
||||
|
||||
return@flatMap DisCalServer.client.getGuildById(guildId).getCalendar(calendarNumber)
|
||||
return@flatMap client.getGuildById(guildId).getCalendar(calendarNumber)
|
||||
.flatMap(Calendar::delete)
|
||||
.doOnNext { response.rawStatusCode = GlobalConst.STATUS_SUCCESS }
|
||||
.then(responseMessage("Success"))
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package org.dreamexposure.discal.server.endpoints.v2.calendar
|
||||
|
||||
import discord4j.common.util.Snowflake
|
||||
import discord4j.core.DiscordClient
|
||||
import kotlinx.serialization.encodeToString
|
||||
import kotlinx.serialization.json.Json
|
||||
import org.dreamexposure.discal.core.entities.Calendar
|
||||
@@ -8,7 +9,6 @@ import org.dreamexposure.discal.core.extensions.discord4j.getCalendar
|
||||
import org.dreamexposure.discal.core.logger.LogFeed
|
||||
import org.dreamexposure.discal.core.logger.`object`.LogObject
|
||||
import org.dreamexposure.discal.core.utils.GlobalConst
|
||||
import org.dreamexposure.discal.server.DisCalServer
|
||||
import org.dreamexposure.discal.server.utils.Authentication
|
||||
import org.dreamexposure.discal.server.utils.responseMessage
|
||||
import org.json.JSONException
|
||||
@@ -23,7 +23,7 @@ import reactor.core.publisher.Mono
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/v2/calendar")
|
||||
class GetCalendarEndpoint {
|
||||
class GetCalendarEndpoint(val client: DiscordClient) {
|
||||
@PostMapping("/get", produces = ["application/json"])
|
||||
fun getCalendar(swe: ServerWebExchange, response: ServerHttpResponse, @RequestBody rBody: String): Mono<String> {
|
||||
return Authentication.authenticate(swe).flatMap { authState ->
|
||||
@@ -37,7 +37,7 @@ class GetCalendarEndpoint {
|
||||
val guildId = Snowflake.of(body.getString("guild_id"))
|
||||
val calNumber = body.getInt("calendar_number")
|
||||
|
||||
return@flatMap DisCalServer.client.getGuildById(guildId).getCalendar(calNumber)
|
||||
return@flatMap client.getGuildById(guildId).getCalendar(calNumber)
|
||||
.map(Calendar::toJson)
|
||||
.map(JSONObject::toString)
|
||||
.switchIfEmpty(responseMessage("Calendar not found")
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package org.dreamexposure.discal.server.endpoints.v2.calendar
|
||||
|
||||
import discord4j.common.util.Snowflake
|
||||
import discord4j.core.DiscordClient
|
||||
import kotlinx.serialization.encodeToString
|
||||
import kotlinx.serialization.json.Json
|
||||
import org.dreamexposure.discal.core.entities.Calendar
|
||||
@@ -8,7 +9,6 @@ import org.dreamexposure.discal.core.extensions.discord4j.getAllCalendars
|
||||
import org.dreamexposure.discal.core.logger.LogFeed
|
||||
import org.dreamexposure.discal.core.logger.`object`.LogObject
|
||||
import org.dreamexposure.discal.core.utils.GlobalConst
|
||||
import org.dreamexposure.discal.server.DisCalServer
|
||||
import org.dreamexposure.discal.server.utils.Authentication
|
||||
import org.dreamexposure.discal.server.utils.responseMessage
|
||||
import org.json.JSONArray
|
||||
@@ -24,7 +24,7 @@ import reactor.core.publisher.Mono
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/v2/calendar")
|
||||
class ListCalendarEndpoint {
|
||||
class ListCalendarEndpoint(val client: DiscordClient) {
|
||||
@PostMapping("/list", produces = ["application/json"])
|
||||
fun listCalendars(swe: ServerWebExchange, response: ServerHttpResponse, @RequestBody rBody: String): Mono<String> {
|
||||
return Authentication.authenticate(swe).flatMap { authState ->
|
||||
@@ -37,7 +37,7 @@ class ListCalendarEndpoint {
|
||||
val body = JSONObject(rBody)
|
||||
val guildId = Snowflake.of(body.getString("guild_id"))
|
||||
|
||||
return@flatMap DisCalServer.client.getGuildById(guildId).getAllCalendars()
|
||||
return@flatMap client.getGuildById(guildId).getAllCalendars()
|
||||
.map(Calendar::toJson)
|
||||
.collectList()
|
||||
.map { JSONArray(it) }
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package org.dreamexposure.discal.server.endpoints.v2.calendar
|
||||
|
||||
import discord4j.common.util.Snowflake
|
||||
import discord4j.core.DiscordClient
|
||||
import kotlinx.serialization.encodeToString
|
||||
import kotlinx.serialization.json.Json
|
||||
import org.dreamexposure.discal.core.entities.spec.update.UpdateCalendarSpec
|
||||
@@ -9,7 +10,6 @@ import org.dreamexposure.discal.core.logger.LogFeed
|
||||
import org.dreamexposure.discal.core.logger.`object`.LogObject
|
||||
import org.dreamexposure.discal.core.utils.GlobalConst
|
||||
import org.dreamexposure.discal.core.utils.TimeZoneUtils
|
||||
import org.dreamexposure.discal.server.DisCalServer
|
||||
import org.dreamexposure.discal.server.utils.Authentication
|
||||
import org.dreamexposure.discal.server.utils.responseMessage
|
||||
import org.json.JSONException
|
||||
@@ -25,7 +25,7 @@ import java.time.ZoneId
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/v2/calendar")
|
||||
class UpdateCalendarEndpoint {
|
||||
class UpdateCalendarEndpoint(val client: DiscordClient) {
|
||||
@PostMapping("/update", produces = ["application/json"])
|
||||
fun updateCalendar(swe: ServerWebExchange, response: ServerHttpResponse, @RequestBody rBody: String): Mono<String> {
|
||||
return Authentication.authenticate(swe).flatMap { authState ->
|
||||
@@ -42,7 +42,7 @@ class UpdateCalendarEndpoint {
|
||||
val guildId = Snowflake.of(body.getString("guild_id"))
|
||||
val calendarNumber = body.getInt("calendar_number")
|
||||
|
||||
DisCalServer.client.getGuildById(guildId).getCalendar(calendarNumber).flatMap { calendar ->
|
||||
client.getGuildById(guildId).getCalendar(calendarNumber).flatMap { calendar ->
|
||||
var spec = UpdateCalendarSpec()
|
||||
|
||||
if (body.has("name")) {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package org.dreamexposure.discal.server.endpoints.v2.event
|
||||
|
||||
import discord4j.common.util.Snowflake
|
||||
import discord4j.core.DiscordClient
|
||||
import kotlinx.serialization.encodeToString
|
||||
import kotlinx.serialization.json.Json
|
||||
import org.dreamexposure.discal.core.`object`.event.Recurrence
|
||||
@@ -11,7 +12,6 @@ import org.dreamexposure.discal.core.extensions.discord4j.getCalendar
|
||||
import org.dreamexposure.discal.core.logger.LogFeed
|
||||
import org.dreamexposure.discal.core.logger.`object`.LogObject
|
||||
import org.dreamexposure.discal.core.utils.GlobalConst
|
||||
import org.dreamexposure.discal.server.DisCalServer
|
||||
import org.dreamexposure.discal.server.utils.Authentication
|
||||
import org.dreamexposure.discal.server.utils.responseMessage
|
||||
import org.json.JSONException
|
||||
@@ -27,7 +27,7 @@ import java.time.Instant
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/v2/event")
|
||||
class CreateEventEndpoint {
|
||||
class CreateEventEndpoint(val client: DiscordClient) {
|
||||
@PostMapping("/create", produces = ["application/json"])
|
||||
fun create(swe: ServerWebExchange, response: ServerHttpResponse, @RequestBody rBody: String): Mono<String> {
|
||||
return Authentication.authenticate(swe).flatMap { authState ->
|
||||
@@ -44,7 +44,7 @@ class CreateEventEndpoint {
|
||||
val guildId = Snowflake.of(body.getString("guild_id"))
|
||||
val calendarNumber = body.getInt("calendar_number")
|
||||
|
||||
return@flatMap DisCalServer.client.getGuildById(guildId).getCalendar(calendarNumber)
|
||||
return@flatMap client.getGuildById(guildId).getCalendar(calendarNumber)
|
||||
.flatMap { calendar ->
|
||||
var spec = CreateEventSpec(
|
||||
start = Instant.ofEpochMilli(body.getString("epoch_start").toLong()),
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package org.dreamexposure.discal.server.endpoints.v2.event
|
||||
|
||||
import discord4j.common.util.Snowflake
|
||||
import discord4j.core.DiscordClient
|
||||
import kotlinx.serialization.encodeToString
|
||||
import kotlinx.serialization.json.Json
|
||||
import org.dreamexposure.discal.core.entities.Event
|
||||
@@ -8,7 +9,6 @@ import org.dreamexposure.discal.core.extensions.discord4j.getCalendar
|
||||
import org.dreamexposure.discal.core.logger.LogFeed
|
||||
import org.dreamexposure.discal.core.logger.`object`.LogObject
|
||||
import org.dreamexposure.discal.core.utils.GlobalConst
|
||||
import org.dreamexposure.discal.server.DisCalServer
|
||||
import org.dreamexposure.discal.server.utils.Authentication
|
||||
import org.dreamexposure.discal.server.utils.responseMessage
|
||||
import org.json.JSONException
|
||||
@@ -23,7 +23,7 @@ import reactor.core.publisher.Mono
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/v2/event")
|
||||
class DeleteEventEndpoint {
|
||||
class DeleteEventEndpoint(val client: DiscordClient) {
|
||||
@PostMapping("/delete", produces = ["application/json"])
|
||||
fun delete(swe: ServerWebExchange, response: ServerHttpResponse, @RequestBody rBody: String): Mono<String> {
|
||||
return Authentication.authenticate(swe).flatMap { authState ->
|
||||
@@ -41,7 +41,7 @@ class DeleteEventEndpoint {
|
||||
val calendarNumber = body.getInt("calendar_number")
|
||||
val eventId = body.getString("event_id")
|
||||
|
||||
return@flatMap DisCalServer.client.getGuildById(guildId).getCalendar(calendarNumber)
|
||||
return@flatMap client.getGuildById(guildId).getCalendar(calendarNumber)
|
||||
.flatMap { it.getEvent(eventId) }
|
||||
.flatMap(Event::delete)
|
||||
.flatMap { success ->
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package org.dreamexposure.discal.server.endpoints.v2.event
|
||||
|
||||
import discord4j.common.util.Snowflake
|
||||
import discord4j.core.DiscordClient
|
||||
import kotlinx.serialization.encodeToString
|
||||
import kotlinx.serialization.json.Json
|
||||
import org.dreamexposure.discal.core.entities.Event
|
||||
@@ -8,7 +9,6 @@ import org.dreamexposure.discal.core.extensions.discord4j.getCalendar
|
||||
import org.dreamexposure.discal.core.logger.LogFeed
|
||||
import org.dreamexposure.discal.core.logger.`object`.LogObject
|
||||
import org.dreamexposure.discal.core.utils.GlobalConst
|
||||
import org.dreamexposure.discal.server.DisCalServer
|
||||
import org.dreamexposure.discal.server.utils.Authentication
|
||||
import org.dreamexposure.discal.server.utils.responseMessage
|
||||
import org.json.JSONException
|
||||
@@ -23,7 +23,7 @@ import reactor.core.publisher.Mono
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/v2/event")
|
||||
class GetEventEndpoint {
|
||||
class GetEventEndpoint(val client: DiscordClient) {
|
||||
@PostMapping("/get", produces = ["application/json"])
|
||||
fun get(swe: ServerWebExchange, response: ServerHttpResponse, @RequestBody rBody: String): Mono<String> {
|
||||
return Authentication.authenticate(swe).flatMap { authState ->
|
||||
@@ -38,7 +38,7 @@ class GetEventEndpoint {
|
||||
val calendarNumber = body.getInt("calendar_number")
|
||||
val eventId = body.getString("event_id")
|
||||
|
||||
return@flatMap DisCalServer.client.getGuildById(guildId).getCalendar(calendarNumber)
|
||||
return@flatMap client.getGuildById(guildId).getCalendar(calendarNumber)
|
||||
.flatMap { it.getEvent(eventId) }
|
||||
.map(Event::toJson)
|
||||
.map(JSONObject::toString)
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package org.dreamexposure.discal.server.endpoints.v2.event
|
||||
|
||||
import discord4j.common.util.Snowflake
|
||||
import discord4j.core.DiscordClient
|
||||
import kotlinx.serialization.encodeToString
|
||||
import kotlinx.serialization.json.Json
|
||||
import org.dreamexposure.discal.core.`object`.event.Recurrence
|
||||
@@ -10,7 +11,6 @@ import org.dreamexposure.discal.core.extensions.discord4j.getCalendar
|
||||
import org.dreamexposure.discal.core.logger.LogFeed
|
||||
import org.dreamexposure.discal.core.logger.`object`.LogObject
|
||||
import org.dreamexposure.discal.core.utils.GlobalConst
|
||||
import org.dreamexposure.discal.server.DisCalServer
|
||||
import org.dreamexposure.discal.server.utils.Authentication
|
||||
import org.dreamexposure.discal.server.utils.responseMessage
|
||||
import org.json.JSONException
|
||||
@@ -26,7 +26,7 @@ import java.time.Instant
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/v2/event")
|
||||
class UpdateEventEndpoint {
|
||||
class UpdateEventEndpoint(val client: DiscordClient) {
|
||||
@PostMapping("/update", produces = ["application/json"])
|
||||
fun update(swe: ServerWebExchange, response: ServerHttpResponse, @RequestBody rBody: String): Mono<String> {
|
||||
return Authentication.authenticate(swe).flatMap { authState ->
|
||||
@@ -44,7 +44,7 @@ class UpdateEventEndpoint {
|
||||
val calendarNumber = body.getInt("calendar_number")
|
||||
val eventId = body.getString("event_id")
|
||||
|
||||
return@flatMap DisCalServer.client.getGuildById(guildId).getCalendar(calendarNumber).flatMap { it.getEvent(eventId) }
|
||||
return@flatMap client.getGuildById(guildId).getCalendar(calendarNumber).flatMap { it.getEvent(eventId) }
|
||||
.flatMap { event ->
|
||||
var spec = UpdateEventSpec()
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package org.dreamexposure.discal.server.endpoints.v2.event.list
|
||||
|
||||
import discord4j.common.util.Snowflake
|
||||
import discord4j.core.DiscordClient
|
||||
import kotlinx.serialization.encodeToString
|
||||
import kotlinx.serialization.json.Json
|
||||
import org.dreamexposure.discal.core.entities.Event
|
||||
@@ -8,7 +9,6 @@ import org.dreamexposure.discal.core.extensions.discord4j.getCalendar
|
||||
import org.dreamexposure.discal.core.logger.LogFeed
|
||||
import org.dreamexposure.discal.core.logger.`object`.LogObject
|
||||
import org.dreamexposure.discal.core.utils.GlobalConst
|
||||
import org.dreamexposure.discal.server.DisCalServer
|
||||
import org.dreamexposure.discal.server.utils.Authentication
|
||||
import org.dreamexposure.discal.server.utils.responseMessage
|
||||
import org.json.JSONArray
|
||||
@@ -25,7 +25,7 @@ import java.time.Instant
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/v2/events/list")
|
||||
class ListEventDateEndpoint {
|
||||
class ListEventDateEndpoint(val client: DiscordClient) {
|
||||
@PostMapping("/date", produces = ["application/json"])
|
||||
fun listByDate(swe: ServerWebExchange, response: ServerHttpResponse, @RequestBody rBody: String): Mono<String> {
|
||||
return Authentication.authenticate(swe).flatMap { authState ->
|
||||
@@ -41,7 +41,7 @@ class ListEventDateEndpoint {
|
||||
val start = Instant.ofEpochMilli(body.getLong("epoch_start"))
|
||||
val end = Instant.ofEpochMilli(body.getLong("epoch_end"))
|
||||
|
||||
return@flatMap DisCalServer.client.getGuildById(guildId).getCalendar(calendarNumber)
|
||||
return@flatMap client.getGuildById(guildId).getCalendar(calendarNumber)
|
||||
.flatMapMany { it.getEventsInTimeRange(start, end) }
|
||||
.map(Event::toJson)
|
||||
.collectList()
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package org.dreamexposure.discal.server.endpoints.v2.event.list
|
||||
|
||||
import discord4j.common.util.Snowflake
|
||||
import discord4j.core.DiscordClient
|
||||
import kotlinx.serialization.encodeToString
|
||||
import kotlinx.serialization.json.Json
|
||||
import org.dreamexposure.discal.core.entities.Event
|
||||
@@ -8,7 +9,6 @@ import org.dreamexposure.discal.core.extensions.discord4j.getCalendar
|
||||
import org.dreamexposure.discal.core.logger.LogFeed
|
||||
import org.dreamexposure.discal.core.logger.`object`.LogObject
|
||||
import org.dreamexposure.discal.core.utils.GlobalConst
|
||||
import org.dreamexposure.discal.server.DisCalServer
|
||||
import org.dreamexposure.discal.server.utils.Authentication
|
||||
import org.dreamexposure.discal.server.utils.responseMessage
|
||||
import org.json.JSONArray
|
||||
@@ -25,7 +25,7 @@ import java.time.Instant
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/v2/events/list")
|
||||
class ListEventMonthEndpoint {
|
||||
class ListEventMonthEndpoint(val client: DiscordClient) {
|
||||
@PostMapping("/month", produces = ["application/json"])
|
||||
fun listByMonth(swe: ServerWebExchange, response: ServerHttpResponse, @RequestBody rBody: String): Mono<String> {
|
||||
return Authentication.authenticate(swe).flatMap { authState ->
|
||||
@@ -41,7 +41,7 @@ class ListEventMonthEndpoint {
|
||||
val start = Instant.ofEpochMilli(body.getLong("epoch_start"))
|
||||
val daysInMonth = body.getInt("days_in_month")
|
||||
|
||||
return@flatMap DisCalServer.client.getGuildById(guildId).getCalendar(calendarNumber)
|
||||
return@flatMap client.getGuildById(guildId).getCalendar(calendarNumber)
|
||||
.flatMapMany { it.getEventsInMonth(start, daysInMonth) }
|
||||
.map(Event::toJson)
|
||||
.collectList()
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package org.dreamexposure.discal.server.endpoints.v2.event.list
|
||||
|
||||
import discord4j.common.util.Snowflake
|
||||
import discord4j.core.DiscordClient
|
||||
import kotlinx.serialization.encodeToString
|
||||
import kotlinx.serialization.json.Json
|
||||
import org.dreamexposure.discal.core.entities.Calendar
|
||||
@@ -9,7 +10,6 @@ import org.dreamexposure.discal.core.extensions.discord4j.getCalendar
|
||||
import org.dreamexposure.discal.core.logger.LogFeed
|
||||
import org.dreamexposure.discal.core.logger.`object`.LogObject
|
||||
import org.dreamexposure.discal.core.utils.GlobalConst
|
||||
import org.dreamexposure.discal.server.DisCalServer
|
||||
import org.dreamexposure.discal.server.utils.Authentication
|
||||
import org.dreamexposure.discal.server.utils.responseMessage
|
||||
import org.json.JSONArray
|
||||
@@ -25,7 +25,7 @@ import reactor.core.publisher.Mono
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/v2/events/list")
|
||||
class ListEventOngoingEndpoint {
|
||||
class ListEventOngoingEndpoint(val client: DiscordClient) {
|
||||
@PostMapping("/ongoing", produces = ["application/json"])
|
||||
fun listOngoing(swe: ServerWebExchange, response: ServerHttpResponse, @RequestBody rBody: String): Mono<String> {
|
||||
return Authentication.authenticate(swe).flatMap { authState ->
|
||||
@@ -39,7 +39,7 @@ class ListEventOngoingEndpoint {
|
||||
val guildId = Snowflake.of(body.getString("guild_id"))
|
||||
val calendarNumber = body.getInt("calendar_number")
|
||||
|
||||
return@flatMap DisCalServer.client.getGuildById(guildId).getCalendar(calendarNumber)
|
||||
return@flatMap client.getGuildById(guildId).getCalendar(calendarNumber)
|
||||
.flatMapMany(Calendar::getOngoingEvents)
|
||||
.map(Event::toJson)
|
||||
.collectList()
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package org.dreamexposure.discal.server.endpoints.v2.event.list
|
||||
|
||||
import discord4j.common.util.Snowflake
|
||||
import discord4j.core.DiscordClient
|
||||
import kotlinx.serialization.encodeToString
|
||||
import kotlinx.serialization.json.Json
|
||||
import org.dreamexposure.discal.core.entities.Event
|
||||
@@ -8,7 +9,6 @@ import org.dreamexposure.discal.core.extensions.discord4j.getCalendar
|
||||
import org.dreamexposure.discal.core.logger.LogFeed
|
||||
import org.dreamexposure.discal.core.logger.`object`.LogObject
|
||||
import org.dreamexposure.discal.core.utils.GlobalConst
|
||||
import org.dreamexposure.discal.server.DisCalServer
|
||||
import org.dreamexposure.discal.server.utils.Authentication
|
||||
import org.dreamexposure.discal.server.utils.responseMessage
|
||||
import org.json.JSONArray
|
||||
@@ -25,7 +25,7 @@ import java.time.Instant
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/v2/events/list")
|
||||
class ListEventRangeEndpoint {
|
||||
class ListEventRangeEndpoint(val client: DiscordClient) {
|
||||
@PostMapping("/range", produces = ["application/json"])
|
||||
fun listByRange(swe: ServerWebExchange, response: ServerHttpResponse, @RequestBody rBody: String): Mono<String> {
|
||||
return Authentication.authenticate(swe).flatMap { authState ->
|
||||
@@ -41,7 +41,7 @@ class ListEventRangeEndpoint {
|
||||
val start = Instant.ofEpochMilli(body.getLong("epoch_start"))
|
||||
val end = Instant.ofEpochMilli(body.getLong("epoch_end"))
|
||||
|
||||
return@flatMap DisCalServer.client.getGuildById(guildId).getCalendar(calendarNumber)
|
||||
return@flatMap client.getGuildById(guildId).getCalendar(calendarNumber)
|
||||
.flatMapMany { it.getEventsInTimeRange(start, end) }
|
||||
.map(Event::toJson)
|
||||
.collectList()
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package org.dreamexposure.discal.server.endpoints.v2.guild
|
||||
|
||||
import discord4j.common.util.Snowflake
|
||||
import discord4j.core.DiscordClient
|
||||
import kotlinx.serialization.encodeToString
|
||||
import kotlinx.serialization.json.Json
|
||||
import org.dreamexposure.discal.core.`object`.web.WebGuild
|
||||
@@ -10,7 +11,6 @@ import org.dreamexposure.discal.core.logger.LogFeed
|
||||
import org.dreamexposure.discal.core.logger.`object`.LogObject
|
||||
import org.dreamexposure.discal.core.utils.GlobalConst
|
||||
import org.dreamexposure.discal.core.utils.PermissionChecker
|
||||
import org.dreamexposure.discal.server.DisCalServer
|
||||
import org.dreamexposure.discal.server.utils.Authentication
|
||||
import org.dreamexposure.discal.server.utils.responseMessage
|
||||
import org.json.JSONException
|
||||
@@ -27,7 +27,7 @@ import reactor.function.TupleUtils
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/v2/guild")
|
||||
class GetWebGuildEndpoint {
|
||||
class GetWebGuildEndpoint(val client: DiscordClient) {
|
||||
@PostMapping(value = ["/get"], produces = ["application/json"])
|
||||
fun getSettings(swe: ServerWebExchange, response: ServerHttpResponse, @RequestBody rBody: String): Mono<String> {
|
||||
return Authentication.authenticate(swe).flatMap { authState ->
|
||||
@@ -41,7 +41,7 @@ class GetWebGuildEndpoint {
|
||||
val guildId = Snowflake.of(body.getString("guild_id"))
|
||||
val userId = Snowflake.of(body.getString("user_id"))
|
||||
|
||||
val g = DisCalServer.client.getGuildById(guildId)
|
||||
val g = client.getGuildById(guildId)
|
||||
|
||||
WebGuild.fromGuild(g).onErrorResume(BotNotInGuildException::class.java) { Mono.empty() }.flatMap { wg ->
|
||||
val member = g.member(userId)
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
package org.dreamexposure.discal.server.endpoints.v2.guild
|
||||
|
||||
import discord4j.common.util.Snowflake
|
||||
import discord4j.core.DiscordClient
|
||||
import discord4j.discordjson.json.ImmutableNicknameModifyData
|
||||
import kotlinx.serialization.encodeToString
|
||||
import kotlinx.serialization.json.Json
|
||||
import org.dreamexposure.discal.core.logger.LogFeed
|
||||
import org.dreamexposure.discal.core.logger.`object`.LogObject
|
||||
import org.dreamexposure.discal.core.utils.GlobalConst
|
||||
import org.dreamexposure.discal.server.DisCalServer
|
||||
import org.dreamexposure.discal.server.utils.Authentication
|
||||
import org.dreamexposure.discal.server.utils.responseMessage
|
||||
import org.json.JSONException
|
||||
@@ -23,7 +23,7 @@ import java.util.*
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/v2/guild")
|
||||
class UpdateWebGuildEndpoint {
|
||||
class UpdateWebGuildEndpoint(val client: DiscordClient) {
|
||||
@PostMapping(value = ["/update"], produces = ["application/json"])
|
||||
fun updateGuild(swe: ServerWebExchange, response: ServerHttpResponse, @RequestBody rBody: String): Mono<String> {
|
||||
return Authentication.authenticate(swe).flatMap { authState ->
|
||||
@@ -39,7 +39,7 @@ class UpdateWebGuildEndpoint {
|
||||
val body = JSONObject(rBody)
|
||||
val guildId = Snowflake.of(body.getString("guild_id"))
|
||||
|
||||
val guild = DisCalServer.client.getGuildById(guildId)
|
||||
val guild = client.getGuildById(guildId)
|
||||
|
||||
//Handle nickname change
|
||||
val nicknameMono = Mono.defer {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package org.dreamexposure.discal.server.endpoints.v2.rsvp
|
||||
|
||||
import discord4j.common.util.Snowflake
|
||||
import discord4j.core.DiscordClient
|
||||
import kotlinx.serialization.encodeToString
|
||||
import kotlinx.serialization.json.Json
|
||||
import org.dreamexposure.discal.core.database.DatabaseManager
|
||||
@@ -8,7 +9,6 @@ import org.dreamexposure.discal.core.logger.LogFeed
|
||||
import org.dreamexposure.discal.core.logger.`object`.LogObject
|
||||
import org.dreamexposure.discal.core.utils.GlobalConst
|
||||
import org.dreamexposure.discal.core.utils.RoleUtils
|
||||
import org.dreamexposure.discal.server.DisCalServer
|
||||
import org.dreamexposure.discal.server.utils.Authentication
|
||||
import org.dreamexposure.discal.server.utils.responseMessage
|
||||
import org.json.JSONException
|
||||
@@ -25,7 +25,7 @@ import reactor.function.TupleUtils
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/v2/rsvp")
|
||||
class UpdateRsvpEndpoint {
|
||||
class UpdateRsvpEndpoint(val client: DiscordClient) {
|
||||
@PostMapping(value = ["/update"], produces = ["application/json"])
|
||||
fun updateRsvp(swe: ServerWebExchange, response: ServerHttpResponse, @RequestBody rBody: String): Mono<String> {
|
||||
return Authentication.authenticate(swe).flatMap { authState ->
|
||||
@@ -53,13 +53,13 @@ class UpdateRsvpEndpoint {
|
||||
it.has("role_id") && (settings.patronGuild || settings.devGuild)
|
||||
}.flatMap { jsonBody ->
|
||||
if (jsonBody.isNull("role_id") || jsonBody.getString("role_id").equals("none", true)) {
|
||||
rsvp.clearRole(DisCalServer.client)
|
||||
rsvp.clearRole(client)
|
||||
} else {
|
||||
val roleId = Snowflake.of(jsonBody.getString("role_id"))
|
||||
|
||||
RoleUtils.roleExists(DisCalServer.client, guildId, roleId)
|
||||
RoleUtils.roleExists(client, guildId, roleId)
|
||||
.filter { it }
|
||||
.flatMap { rsvp.setRole(roleId, DisCalServer.client) }
|
||||
.flatMap { rsvp.setRole(roleId, client) }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -88,7 +88,7 @@ class UpdateRsvpEndpoint {
|
||||
(0 until ar.length()).forEach { toRemove.add(ar.getString(it)) }
|
||||
}
|
||||
|
||||
Flux.fromIterable(toRemove).flatMap { rsvp.removeCompletely(it, DisCalServer.client) }.then()
|
||||
Flux.fromIterable(toRemove).flatMap { rsvp.removeCompletely(it, client) }.then()
|
||||
}
|
||||
|
||||
//Handle additions
|
||||
@@ -103,8 +103,8 @@ class UpdateRsvpEndpoint {
|
||||
val ar = toAddJson.getJSONArray("on_time")
|
||||
for (i in 0 until ar.length()) {
|
||||
if (rsvp.hasRoom(ar.getString(i))) {
|
||||
allTheMonos.add(rsvp.removeCompletely(ar.getString(i), DisCalServer.client)
|
||||
.then(rsvp.addGoingOnTime(ar.getString(i), DisCalServer.client)))
|
||||
allTheMonos.add(rsvp.removeCompletely(ar.getString(i), client)
|
||||
.then(rsvp.addGoingOnTime(ar.getString(i), client)))
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -113,8 +113,8 @@ class UpdateRsvpEndpoint {
|
||||
val ar = toAddJson.getJSONArray("late")
|
||||
for (i in 0 until ar.length()) {
|
||||
if (rsvp.hasRoom(ar.getString(i))) {
|
||||
allTheMonos.add(rsvp.removeCompletely(ar.getString(i), DisCalServer.client)
|
||||
.then(rsvp.addGoingLate(ar.getString(i), DisCalServer.client)))
|
||||
allTheMonos.add(rsvp.removeCompletely(ar.getString(i), client)
|
||||
.then(rsvp.addGoingLate(ar.getString(i), client)))
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -123,7 +123,7 @@ class UpdateRsvpEndpoint {
|
||||
val ar = toAddJson.getJSONArray("on_time")
|
||||
for (i in 0 until ar.length()) {
|
||||
if (rsvp.hasRoom(ar.getString(i))) {
|
||||
allTheMonos.add(rsvp.removeCompletely(ar.getString(i), DisCalServer.client)
|
||||
allTheMonos.add(rsvp.removeCompletely(ar.getString(i), client)
|
||||
.then(Mono.from { rsvp.notGoing.add(ar.getString(i)) }))
|
||||
}
|
||||
}
|
||||
@@ -133,7 +133,7 @@ class UpdateRsvpEndpoint {
|
||||
val ar = toAddJson.getJSONArray("undecided")
|
||||
for (i in 0 until ar.length()) {
|
||||
if (rsvp.hasRoom(ar.getString(i))) {
|
||||
allTheMonos.add(rsvp.removeCompletely(ar.getString(i), DisCalServer.client)
|
||||
allTheMonos.add(rsvp.removeCompletely(ar.getString(i), client)
|
||||
.then(Mono.from { rsvp.undecided.add(ar.getString(i)) }))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,10 +2,10 @@ package org.dreamexposure.discal.server.endpoints.v2.status
|
||||
|
||||
import kotlinx.serialization.encodeToString
|
||||
import kotlinx.serialization.json.Json
|
||||
import org.dreamexposure.discal.core.`object`.network.discal.NetworkInfo
|
||||
import org.dreamexposure.discal.core.logger.LogFeed
|
||||
import org.dreamexposure.discal.core.logger.`object`.LogObject
|
||||
import org.dreamexposure.discal.core.utils.GlobalConst
|
||||
import org.dreamexposure.discal.server.DisCalServer
|
||||
import org.dreamexposure.discal.server.utils.Authentication
|
||||
import org.dreamexposure.discal.server.utils.responseMessage
|
||||
import org.json.JSONException
|
||||
@@ -18,7 +18,7 @@ import reactor.core.publisher.Mono
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/v2/status")
|
||||
class GetStatusEndpoint {
|
||||
class GetStatusEndpoint(val networkInfo: NetworkInfo) {
|
||||
|
||||
@PostMapping("/get", produces = ["application/json"])
|
||||
fun getStatus(swe: ServerWebExchange, response: ServerHttpResponse): Mono<String> {
|
||||
@@ -30,8 +30,8 @@ class GetStatusEndpoint {
|
||||
|
||||
//Handle request
|
||||
response.rawStatusCode = GlobalConst.STATUS_SUCCESS
|
||||
return@flatMap DisCalServer.networkInfo.update()
|
||||
.thenReturn(DisCalServer.networkInfo.toJson().toString())
|
||||
return@flatMap networkInfo.update()
|
||||
.thenReturn(networkInfo.toJson().toString())
|
||||
}.onErrorResume(JSONException::class.java) {
|
||||
it.printStackTrace()
|
||||
|
||||
|
||||
@@ -3,10 +3,10 @@ package org.dreamexposure.discal.server.endpoints.v2.status
|
||||
import kotlinx.serialization.encodeToString
|
||||
import kotlinx.serialization.json.Json
|
||||
import org.dreamexposure.discal.core.`object`.network.discal.ConnectedClient
|
||||
import org.dreamexposure.discal.core.`object`.network.discal.NetworkInfo
|
||||
import org.dreamexposure.discal.core.logger.LogFeed
|
||||
import org.dreamexposure.discal.core.logger.`object`.LogObject
|
||||
import org.dreamexposure.discal.core.utils.GlobalConst
|
||||
import org.dreamexposure.discal.server.DisCalServer
|
||||
import org.dreamexposure.discal.server.utils.Authentication
|
||||
import org.dreamexposure.discal.server.utils.responseMessage
|
||||
import org.json.JSONException
|
||||
@@ -21,7 +21,7 @@ import reactor.core.publisher.Mono
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/v2/status")
|
||||
class KeepAliveEndpoint {
|
||||
class KeepAliveEndpoint(val networkInfo: NetworkInfo) {
|
||||
|
||||
@PostMapping(value = ["/keep-alive"], produces = ["application/json"])
|
||||
fun keepAlive(swe: ServerWebExchange, response: ServerHttpResponse, @RequestBody rBody: String): Mono<String> {
|
||||
@@ -38,9 +38,9 @@ class KeepAliveEndpoint {
|
||||
val body = JSONObject(rBody)
|
||||
val index = body.getInt("index")
|
||||
|
||||
if (DisCalServer.networkInfo.doesClientExist(index)) {
|
||||
if (networkInfo.doesClientExist(index)) {
|
||||
//In network, update info
|
||||
val cc = DisCalServer.networkInfo.getClient(index)
|
||||
val cc = networkInfo.getClient(index)
|
||||
val oldPid = cc.pid
|
||||
|
||||
val newClient = cc.copy(
|
||||
@@ -59,7 +59,7 @@ class KeepAliveEndpoint {
|
||||
LogFeed.log(LogObject.forStatus("Client pid changed", "Shard index: ${cc.clientIndex}"))
|
||||
}
|
||||
|
||||
DisCalServer.networkInfo.updateClient(newClient)
|
||||
networkInfo.updateClient(newClient)
|
||||
} else {
|
||||
//Not in network, add info
|
||||
val cc = ConnectedClient(
|
||||
@@ -75,7 +75,7 @@ class KeepAliveEndpoint {
|
||||
body.getString("pid")
|
||||
)
|
||||
|
||||
DisCalServer.networkInfo.addClient(cc)
|
||||
networkInfo.addClient(cc)
|
||||
}
|
||||
|
||||
response.rawStatusCode = GlobalConst.STATUS_SUCCESS
|
||||
|
||||
@@ -4,37 +4,26 @@ import okhttp3.OkHttpClient
|
||||
import okhttp3.Request
|
||||
import okhttp3.RequestBody
|
||||
import org.dreamexposure.discal.core.`object`.BotSettings
|
||||
import org.dreamexposure.discal.core.`object`.network.discal.NetworkInfo
|
||||
import org.dreamexposure.discal.core.logger.LogFeed
|
||||
import org.dreamexposure.discal.core.logger.`object`.LogObject
|
||||
import org.dreamexposure.discal.core.utils.GlobalConst
|
||||
import org.dreamexposure.discal.server.DisCalServer
|
||||
import org.json.JSONObject
|
||||
import org.springframework.boot.ApplicationArguments
|
||||
import org.springframework.boot.ApplicationRunner
|
||||
import org.springframework.stereotype.Component
|
||||
import reactor.core.publisher.Flux
|
||||
import reactor.core.publisher.Mono
|
||||
import java.util.*
|
||||
import kotlin.concurrent.timerTask
|
||||
import java.time.Duration
|
||||
|
||||
object UpdateDBotsData {
|
||||
//TODO: Use flux interval instead of timer eventually
|
||||
private var timer: Timer? = null
|
||||
|
||||
fun init() {
|
||||
if (BotSettings.UPDATE_SITES.get().equals("true", true)) {
|
||||
timer = Timer(true)
|
||||
timer?.schedule(timerTask {
|
||||
update().subscribe()
|
||||
}, GlobalConst.oneHourMs)
|
||||
}
|
||||
}
|
||||
|
||||
fun shutdown() {
|
||||
if (timer != null) timer?.cancel()
|
||||
}
|
||||
@Component
|
||||
class UpdateDBotsData(private val networkInfo: NetworkInfo) : ApplicationRunner {
|
||||
|
||||
private fun update(): Mono<Void> {
|
||||
return Mono.fromCallable {
|
||||
val json = JSONObject()
|
||||
.put("guildCount", DisCalServer.networkInfo.totalGuildCount)
|
||||
.put("shardCount", DisCalServer.networkInfo.expectedClientCount)
|
||||
.put("guildCount", networkInfo.totalGuildCount)
|
||||
.put("shardCount", networkInfo.expectedClientCount)
|
||||
|
||||
val client = OkHttpClient()
|
||||
|
||||
@@ -55,4 +44,12 @@ object UpdateDBotsData {
|
||||
Mono.empty()
|
||||
}.then()
|
||||
}
|
||||
|
||||
override fun run(args: ApplicationArguments?) {
|
||||
if (BotSettings.UPDATE_SITES.get().equals("true", true)) {
|
||||
Flux.interval(Duration.ofHours(1))
|
||||
.flatMap { update() }
|
||||
.subscribe()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,49 +7,26 @@ import com.jcraft.jsch.JSchException
|
||||
import com.jcraft.jsch.Session
|
||||
import org.dreamexposure.discal.core.`object`.BotSettings
|
||||
import org.dreamexposure.discal.core.`object`.network.discal.ConnectedClient
|
||||
import org.dreamexposure.discal.core.`object`.network.discal.NetworkInfo
|
||||
import org.dreamexposure.discal.core.logger.LogFeed
|
||||
import org.dreamexposure.discal.core.logger.`object`.LogObject
|
||||
import org.dreamexposure.discal.core.utils.GlobalConst
|
||||
import org.dreamexposure.discal.server.DisCalServer
|
||||
import org.springframework.boot.ApplicationArguments
|
||||
import org.springframework.boot.ApplicationRunner
|
||||
import org.springframework.stereotype.Component
|
||||
import reactor.core.publisher.Flux
|
||||
import reactor.core.publisher.Mono
|
||||
import java.io.IOException
|
||||
import java.io.InputStreamReader
|
||||
import java.time.Duration
|
||||
import java.util.*
|
||||
import kotlin.concurrent.timerTask
|
||||
|
||||
object NetworkMediator {
|
||||
//TODO: Use flux interval instead of timer eventually
|
||||
private var timer: Timer? = null
|
||||
|
||||
fun init() {
|
||||
timer = Timer(true)
|
||||
|
||||
timer?.schedule(timerTask {
|
||||
val downShards = mutableListOf<ConnectedClient>()
|
||||
|
||||
for (client in DisCalServer.networkInfo.clients) {
|
||||
if (System.currentTimeMillis() > client.lastKeepAlive + (5 * GlobalConst.oneMinuteMs))
|
||||
downShards.add(client) //Missed last 5+ heartbeats...
|
||||
}
|
||||
|
||||
//Now we issue the restarts for the shards
|
||||
Flux.fromIterable(downShards)
|
||||
.flatMap(this@NetworkMediator::issueRestart)
|
||||
.subscribe()
|
||||
|
||||
downShards.forEach(this@NetworkMediator::issueRestart)
|
||||
|
||||
}, GlobalConst.oneMinuteMs, GlobalConst.oneMinuteMs)
|
||||
}
|
||||
|
||||
fun shutdown() {
|
||||
if (timer != null) timer?.cancel()
|
||||
}
|
||||
@Component
|
||||
class NetworkMediator(private val networkInfo: NetworkInfo) : ApplicationRunner {
|
||||
|
||||
private fun issueRestart(client: ConnectedClient): Mono<Void> {
|
||||
if (BotSettings.USE_RESTART_SERVICE.get().equals("true", true)) {
|
||||
DisCalServer.networkInfo.removeClient(client.clientIndex, "Restart service not active!")
|
||||
networkInfo.removeClient(client.clientIndex, "Restart service not active!")
|
||||
return Mono.empty()
|
||||
}
|
||||
|
||||
@@ -60,8 +37,7 @@ object NetworkMediator {
|
||||
val channel = session.openChannel("exec") as ChannelExec
|
||||
|
||||
//Tell network manager to remove this client until it restarts.
|
||||
DisCalServer.networkInfo
|
||||
.removeClient(client.clientIndex, "Restart issued by mediator for missed heartbeats")
|
||||
networkInfo.removeClient(client.clientIndex, "Restart issued by mediator for missed heartbeats")
|
||||
|
||||
//Do it
|
||||
try {
|
||||
@@ -110,4 +86,12 @@ object NetworkMediator {
|
||||
}
|
||||
session.disconnect()
|
||||
}
|
||||
|
||||
override fun run(args: ApplicationArguments?) {
|
||||
Flux.interval(Duration.ofMinutes(1))
|
||||
.flatMapIterable { networkInfo.clients }
|
||||
.filter { System.currentTimeMillis() > it.lastKeepAlive + (5 * GlobalConst.oneMinuteMs) }
|
||||
.flatMap(::issueRestart)
|
||||
.subscribe()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,38 +3,21 @@ package org.dreamexposure.discal.server.network.topgg
|
||||
import org.discordbots.api.client.DiscordBotListAPI
|
||||
import org.dreamexposure.discal.core.`object`.BotSettings
|
||||
import org.dreamexposure.discal.core.`object`.network.discal.ConnectedClient
|
||||
import org.dreamexposure.discal.core.utils.GlobalConst
|
||||
import org.dreamexposure.discal.server.DisCalServer
|
||||
import java.util.*
|
||||
import org.dreamexposure.discal.core.`object`.network.discal.NetworkInfo
|
||||
import org.springframework.boot.ApplicationArguments
|
||||
import org.springframework.boot.ApplicationRunner
|
||||
import org.springframework.stereotype.Component
|
||||
import reactor.core.publisher.Flux
|
||||
import java.time.Duration
|
||||
import java.util.stream.Collectors
|
||||
import kotlin.concurrent.timerTask
|
||||
|
||||
object UpdateTopStats {
|
||||
//TODO: Use flux interval instead of timer eventually
|
||||
private var timer: Timer? = null
|
||||
@Component
|
||||
class UpdateTopStats(private val networkInfo: NetworkInfo): ApplicationRunner {
|
||||
private var api: DiscordBotListAPI? = null
|
||||
|
||||
fun init() {
|
||||
if (BotSettings.UPDATE_SITES.get().equals("true", true)) {
|
||||
api = DiscordBotListAPI.Builder()
|
||||
.token(BotSettings.TOP_GG_TOKEN.get())
|
||||
.build()
|
||||
|
||||
timer = Timer(true)
|
||||
|
||||
timer?.schedule(timerTask {
|
||||
update()
|
||||
}, GlobalConst.oneHourMs)
|
||||
}
|
||||
}
|
||||
|
||||
fun shutdown() {
|
||||
if (timer != null) timer?.cancel()
|
||||
}
|
||||
|
||||
private fun update() {
|
||||
if (api != null) {
|
||||
val guildsOnShard: List<Int> = DisCalServer.networkInfo.clients
|
||||
val guildsOnShard: List<Int> = networkInfo.clients
|
||||
.stream()
|
||||
.map(ConnectedClient::connectedServers)
|
||||
.collect(Collectors.toList())
|
||||
@@ -42,4 +25,16 @@ object UpdateTopStats {
|
||||
api?.setStats(guildsOnShard)
|
||||
}
|
||||
}
|
||||
|
||||
override fun run(args: ApplicationArguments?) {
|
||||
if (BotSettings.UPDATE_SITES.get().equals("true", true)) {
|
||||
api = DiscordBotListAPI.Builder()
|
||||
.token(BotSettings.TOP_GG_TOKEN.get())
|
||||
.build()
|
||||
|
||||
Flux.interval(Duration.ofHours(1))
|
||||
.map { update() }
|
||||
.subscribe()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package org.dreamexposure.discal.web
|
||||
|
||||
import org.dreamexposure.discal.Application
|
||||
import org.dreamexposure.discal.core.`object`.BotSettings
|
||||
import org.dreamexposure.discal.core.calendar.CalendarAuth
|
||||
import org.dreamexposure.discal.core.logger.LogFeed
|
||||
@@ -10,11 +11,13 @@ import org.springframework.boot.SpringApplication
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication
|
||||
import org.springframework.boot.autoconfigure.r2dbc.R2dbcAutoConfiguration
|
||||
import org.springframework.boot.autoconfigure.session.SessionAutoConfiguration
|
||||
import org.springframework.stereotype.Component
|
||||
import java.io.FileReader
|
||||
import java.util.*
|
||||
import javax.annotation.PreDestroy
|
||||
import kotlin.system.exitProcess
|
||||
|
||||
@Component
|
||||
@SpringBootApplication(exclude = [SessionAutoConfiguration::class, R2dbcAutoConfiguration::class])
|
||||
class DisCalWeb {
|
||||
companion object {
|
||||
@@ -39,7 +42,7 @@ class DisCalWeb {
|
||||
//Start up spring
|
||||
try {
|
||||
DiscordAccountHandler.init()
|
||||
val app = SpringApplication(DisCalWeb::class.java)
|
||||
val app = SpringApplication(Application::class.java)
|
||||
app.setAdditionalProfiles(BotSettings.PROFILE.get())
|
||||
app.run(*args)
|
||||
} catch (e: Exception) {
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package org.dreamexposure.discal.web.config
|
||||
|
||||
import org.dreamexposure.discal.core.`object`.BotSettings
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration
|
||||
import org.springframework.boot.web.server.ConfigurableWebServerFactory
|
||||
import org.springframework.boot.web.server.ErrorPage
|
||||
import org.springframework.boot.web.server.WebServerFactoryCustomizer
|
||||
@@ -28,7 +27,6 @@ import org.thymeleaf.templatemode.TemplateMode
|
||||
|
||||
@Configuration
|
||||
@EnableWebFlux
|
||||
@EnableAutoConfiguration
|
||||
class WebFluxConfig : WebServerFactoryCustomizer<ConfigurableWebServerFactory>,
|
||||
ApplicationContextAware, WebFluxConfigurer {
|
||||
|
||||
|
||||
Reference in New Issue
Block a user