From 11663033db4ffbf9ebee5bab5b5ce99fe63e45fa Mon Sep 17 00:00:00 2001 From: NovaFox161 Date: Sun, 27 Oct 2024 14:49:41 -0500 Subject: [PATCH] Implement new GoogleCalendarApiWrapper component Now to build up the main abstraction layer for calendars. Maybe PartialCalendar/FullCalendar? TBD --- .../cam/business/google/GoogleAuthService.kt | 8 +- .../core/business/api/GoogleAuthApiWrapper.kt | 43 ++ .../business/api/GoogleCalendarApiWrapper.kt | 388 ++++++++++++++++-- .../discal/core/config/CacheConfig.kt | 4 + .../discal/core/config/Config.kt | 1 + .../object/network/discal/CredentialData.kt | 2 +- .../core/wrapper/google/AclRuleWrapper.kt | 3 +- .../core/wrapper/google/CalendarWrapper.kt | 3 +- .../core/wrapper/google/EventWrapper.kt | 3 +- .../core/wrapper/google/GoogleAuthWrapper.kt | 1 + .../org/dreamexposure/discal/typealiases.kt | 2 + 11 files changed, 424 insertions(+), 34 deletions(-) create mode 100644 core/src/main/kotlin/org/dreamexposure/discal/core/business/api/GoogleAuthApiWrapper.kt diff --git a/cam/src/main/kotlin/org/dreamexposure/discal/cam/business/google/GoogleAuthService.kt b/cam/src/main/kotlin/org/dreamexposure/discal/cam/business/google/GoogleAuthService.kt index 8b0070c39..3e999c87f 100644 --- a/cam/src/main/kotlin/org/dreamexposure/discal/cam/business/google/GoogleAuthService.kt +++ b/cam/src/main/kotlin/org/dreamexposure/discal/cam/business/google/GoogleAuthService.kt @@ -2,7 +2,7 @@ package org.dreamexposure.discal.cam.business.google import org.dreamexposure.discal.core.business.CalendarService import org.dreamexposure.discal.core.business.CredentialService -import org.dreamexposure.discal.core.business.api.GoogleCalendarApiWrapper +import org.dreamexposure.discal.core.business.api.GoogleAuthApiWrapper import org.dreamexposure.discal.core.exceptions.EmptyNotAllowedException import org.dreamexposure.discal.core.exceptions.NotFoundException import org.dreamexposure.discal.core.extensions.isExpiredTtl @@ -17,14 +17,14 @@ import java.time.Instant class GoogleAuthService( private val credentialService: CredentialService, private val calendarService: CalendarService, - private val googleCalendarApiWrapper: GoogleCalendarApiWrapper, + private val googleAuthApiWrapper: GoogleAuthApiWrapper, ) { suspend fun requestNewAccessToken(calendar: CalendarMetadata): TokenV1Model? { if (!calendar.secrets.expiresAt.isExpiredTtl()) return TokenV1Model(calendar.secrets.accessToken, calendar.secrets.expiresAt) LOGGER.debug("Refreshing access token | guildId:{} | calendar:{}", calendar.guildId, calendar.number) - val refreshed = googleCalendarApiWrapper.refreshAccessToken(calendar.secrets.refreshToken).entity ?: return null + val refreshed = googleAuthApiWrapper.refreshAccessToken(calendar.secrets.refreshToken).entity ?: return null calendar.secrets.accessToken = refreshed.accessToken calendar.secrets.expiresAt = Instant.now().plusSeconds(refreshed.expiresIn.toLong()).minus(Duration.ofMinutes(5)) // Add some wiggle room calendarService.updateCalendarMetadata(calendar) @@ -40,7 +40,7 @@ class GoogleAuthService( LOGGER.debug("Refreshing access token | credentialId:$credentialId") - val refreshed = googleCalendarApiWrapper.refreshAccessToken(credential.refreshToken).entity ?: throw EmptyNotAllowedException() + val refreshed = googleAuthApiWrapper.refreshAccessToken(credential.refreshToken).entity ?: throw EmptyNotAllowedException() credential.accessToken = refreshed.accessToken credential.expiresAt = Instant.now().plusSeconds(refreshed.expiresIn.toLong()).minus(Duration.ofMinutes(5)) // Add some wiggle room credentialService.updateCredential(credential) diff --git a/core/src/main/kotlin/org/dreamexposure/discal/core/business/api/GoogleAuthApiWrapper.kt b/core/src/main/kotlin/org/dreamexposure/discal/core/business/api/GoogleAuthApiWrapper.kt new file mode 100644 index 000000000..7f48b544e --- /dev/null +++ b/core/src/main/kotlin/org/dreamexposure/discal/core/business/api/GoogleAuthApiWrapper.kt @@ -0,0 +1,43 @@ +package org.dreamexposure.discal.core.business.api + +import okhttp3.FormBody +import okhttp3.Request +import org.dreamexposure.discal.core.config.Config +import org.dreamexposure.discal.core.exceptions.AccessRevokedException +import org.dreamexposure.discal.core.logger.LOGGER +import org.dreamexposure.discal.core.`object`.new.model.ResponseModel +import org.dreamexposure.discal.core.`object`.new.model.google.OauthV4RefreshTokenResponse +import org.dreamexposure.discal.core.utils.GlobalVal.DEFAULT +import org.springframework.stereotype.Component + +@Component +class GoogleAuthApiWrapper( + private val apiWrapperClient: ApiWrapperClient, +) { + suspend fun refreshAccessToken(refreshToken: String): ResponseModel { + val requestFormBody = FormBody.Builder() + .addEncoded("client_id", Config.SECRET_GOOGLE_CLIENT_ID.getString()) + .addEncoded("client_secret", Config.SECRET_GOOGLE_CLIENT_SECRET.getString()) + .addEncoded("refresh_token", refreshToken) + .addEncoded("grant_type", "refresh_token") + .build() + val request = Request.Builder() + .url("https://www.googleapis.com/oauth2/v4/token") + .post(requestFormBody) + .header("Content-Type", "application/x-www-form-urlencoded") + .build() + + val response = apiWrapperClient.makeRequest(request, OauthV4RefreshTokenResponse::class.java) + + + // TODO: Handling of this should be moved up higher in the impl? + if (response.error?.error == "invalid_grant") { + LOGGER.debug(DEFAULT, "Google Oauth invalid_grant for access token refresh") + throw AccessRevokedException() // TODO: How should I handle this for external calendars? Right now we just delete everything + } else if (response.error != null) { + LOGGER.error(DEFAULT, "[Google] Error requesting new access token | ${response.code} | ${response.error.error}") + } + + return response + } +} diff --git a/core/src/main/kotlin/org/dreamexposure/discal/core/business/api/GoogleCalendarApiWrapper.kt b/core/src/main/kotlin/org/dreamexposure/discal/core/business/api/GoogleCalendarApiWrapper.kt index 8a6260354..fa1f23203 100644 --- a/core/src/main/kotlin/org/dreamexposure/discal/core/business/api/GoogleCalendarApiWrapper.kt +++ b/core/src/main/kotlin/org/dreamexposure/discal/core/business/api/GoogleCalendarApiWrapper.kt @@ -1,43 +1,379 @@ package org.dreamexposure.discal.core.business.api -import okhttp3.FormBody -import okhttp3.Request +import com.google.api.client.googleapis.auth.oauth2.GoogleCredential +import com.google.api.client.googleapis.json.GoogleJsonResponseException +import com.google.api.client.http.javanet.NetHttpTransport +import com.google.api.client.json.gson.GsonFactory +import com.google.api.client.util.DateTime +import com.google.api.services.calendar.model.AclRule +import com.google.api.services.calendar.model.Calendar +import com.google.api.services.calendar.model.CalendarListEntry +import com.google.api.services.calendar.model.Event +import discord4j.common.util.Snowflake +import org.dreamexposure.discal.CalendarTokenCache import org.dreamexposure.discal.core.config.Config -import org.dreamexposure.discal.core.exceptions.AccessRevokedException +import org.dreamexposure.discal.core.enums.calendar.CalendarHost +import org.dreamexposure.discal.core.extensions.asSnowflake +import org.dreamexposure.discal.core.extensions.isExpiredTtl import org.dreamexposure.discal.core.logger.LOGGER -import org.dreamexposure.discal.core.`object`.new.model.ResponseModel -import org.dreamexposure.discal.core.`object`.new.model.google.OauthV4RefreshTokenResponse -import org.dreamexposure.discal.core.utils.GlobalVal.DEFAULT +import org.dreamexposure.discal.core.`object`.new.CalendarMetadata +import org.springframework.http.HttpStatus import org.springframework.stereotype.Component +import java.time.Instant +import kotlin.random.Random +import com.google.api.services.calendar.Calendar as GoogleCalendarService + @Component class GoogleCalendarApiWrapper( - private val apiWrapperClient: ApiWrapperClient, + private val camApiWrapper: CamApiWrapper, + private val calendarTokenCache: CalendarTokenCache, // Technically an antipattern, but it is domain-specific so... ) { - suspend fun refreshAccessToken(refreshToken: String): ResponseModel { - val requestFormBody = FormBody.Builder() - .addEncoded("client_id", Config.SECRET_GOOGLE_CLIENT_ID.getString()) - .addEncoded("client_secret", Config.SECRET_GOOGLE_CLIENT_SECRET.getString()) - .addEncoded("refresh_token", refreshToken) - .addEncoded("grant_type", "refresh_token") - .build() - val request = Request.Builder() - .url("https://www.googleapis.com/oauth2/v4/token") - .post(requestFormBody) - .header("Content-Type", "application/x-www-form-urlencoded") + // Using this as guildId for caching discal owned credentials with guild owned ones cuz its efficient + private val discalId = Config.DISCORD_APP_ID.getLong().asSnowflake() + + ///////// + /// Auth + ///////// + + /* Get access token to calendar from cache or CAM */ + private suspend fun getAccessToken(credentialId: Int): String { + val token = calendarTokenCache.get(guildId = discalId, credentialId) + if (token != null && !token.validUntil.isExpiredTtl()) return token.accessToken + + LOGGER.debug("Fetching new local-copy of global google calendar token via CAM | credentialId:$credentialId") + + val tokenResponse = camApiWrapper.getCalendarToken(credentialId) + return if (tokenResponse.entity != null) { + calendarTokenCache.put(guildId = discalId, credentialId, tokenResponse.entity) + tokenResponse.entity.accessToken + } else { + throw RuntimeException("Error requesting local google calendar token from CAM for credentialId: $credentialId | response: error: ${tokenResponse.error?.error}") + } + } + + private suspend fun getAccessToken(guildId: Snowflake, calendarNumber: Int): String { + val token = calendarTokenCache.get(guildId, calendarNumber) + if (token != null && !token.validUntil.isExpiredTtl()) return token.accessToken + + LOGGER.debug("Fetching new local-copy of external google calendar token via CAM | guild:${guildId.asLong()} calendarNumber:$calendarNumber") + + val tokenResponse = camApiWrapper.getCalendarToken(guildId, calendarNumber, CalendarHost.GOOGLE) + return if (tokenResponse.entity != null) { + calendarTokenCache.put(guildId, calendarNumber, tokenResponse.entity) + tokenResponse.entity.accessToken + } else if (tokenResponse.code == HttpStatus.FORBIDDEN.value() && tokenResponse.error?.error.equals("Access to resource revoked")) { + // User MUST reauthorize DisCal in Google if we are seeing this error as the refresh token is invalid + // TODO: Call to delete calendar here to mimic old behavior. Consider marking instead so they can re-auth? + throw NotImplementedError("Call to delete calendar on refresh token revoked (or alternative) not yet implemented") + } else { + throw RuntimeException("Error requesting local google calendar token from CAM for guild:${guildId.asString()} calendarNumber: $calendarNumber | response: error: ${tokenResponse.error?.error}") + } + } + + private suspend fun buildGoogleCalendarService(accessToken: String): GoogleCalendarService { + val credential = GoogleCredential().setAccessToken(accessToken) + + return GoogleCalendarService.Builder(NetHttpTransport(), GsonFactory.getDefaultInstance(), credential) + .setApplicationName("DisCal") .build() + } + + private suspend fun getGoogleCalendarService(credentialId: Int) = buildGoogleCalendarService(getAccessToken(credentialId)) + + private suspend fun getGoogleCalendarService(guildId: Snowflake, calendarNumber: Int) = buildGoogleCalendarService(getAccessToken(guildId, calendarNumber)) + + private suspend fun getGoogleCalendarService(calendarMetadata: CalendarMetadata): GoogleCalendarService { + return if (calendarMetadata.external) getGoogleCalendarService(calendarMetadata.guildId, calendarMetadata.number) + else getGoogleCalendarService(calendarMetadata.secrets.credentialId) + } + + ///////// + /// ACL Rule + ///////// + suspend fun insertAclRule(rule: AclRule, calMetadata: CalendarMetadata): AclRule? { + val service = getGoogleCalendarService(calMetadata) + + return try { + service.acl() + .insert(calMetadata.id, rule) + .setQuotaUser(calMetadata.guildId.asString()) + .execute() //TODO: Figure out if I should put this on a different scheduler? + } catch (e: Exception) { + // I think I'm okay with preventing this exception from propagating? + LOGGER.error("Failed to insert ACL rule for Google Calendar", e) + null + } + } + + ///////// + /// Calendars + ///////// + suspend fun createCalendar(calendar: Calendar, credentialId: Int, guildId: Snowflake): Calendar? { + val service = getGoogleCalendarService(credentialId) + + return try { + service.calendars() + .insert(calendar) + .setQuotaUser(guildId.asString()) + .execute() + } catch (e: Exception) { + LOGGER.error("Failed to create calendar for Google Calendar", e) + null + } + } + + suspend fun patchCalendar(calendar: Calendar, metadata: CalendarMetadata): Calendar? { + val service = getGoogleCalendarService(metadata) + + return try { + service.calendars() + .patch(calendar.id, calendar) + .setQuotaUser(metadata.guildId.asString()) + .execute() + } catch (e: Exception) { + LOGGER.error("Failed to patch calendar for Google Calendar", e) + null + } + } + + suspend fun updateCalendar(calendar: Calendar, metadata: CalendarMetadata): Calendar? { + val service = getGoogleCalendarService(metadata) + + return try { + service.calendars() + .patch(calendar.id, calendar) + .setQuotaUser(metadata.guildId.asString()) + .execute() + } catch (e: Exception){ + LOGGER.error("Failed to update calendar for Google Calendar", e) + null + } + } + + suspend fun getCalendar(metadata: CalendarMetadata): Calendar? { + val service = getGoogleCalendarService(metadata) + + return try { + service.calendars() + .get(metadata.address) + .setQuotaUser(metadata.guildId.asString()) + .execute() + } catch (e: Exception) { + LOGGER.error("Failed to get calendar from Google Calendar", e) + null + } + } + + suspend fun deleteCalendar(metadata: CalendarMetadata): Boolean { + // Sanity check if calendar can be deleted + if (metadata.external || metadata.address.equals("primary", true)) return false + + val service = getGoogleCalendarService(metadata) + + return try { + service.calendars() + .delete(metadata.address) + .setQuotaUser(metadata.guildId.asString()) + .execute() + true + } catch (e: Exception) { + LOGGER.error("Failed to delete calendar from Google Calendar", e) + false + } + } + + suspend fun getUsersExternalCalendars(metadata: CalendarMetadata): List { + val service = getGoogleCalendarService(metadata) + + return try { + service.calendarList() + .list() + .setMinAccessRole("writer") + .setQuotaUser(metadata.guildId.asString()) + .execute() + .items + } catch (e: Exception) { + LOGGER.error("Failed to list external calendars", e) + emptyList() + } + } - val response = apiWrapperClient.makeRequest(request, OauthV4RefreshTokenResponse::class.java) + ///////// + /// Events + ///////// + suspend fun createEvent(metadata: CalendarMetadata, event: Event): Event? { + val service = getGoogleCalendarService(metadata) + return try { + service.events() + .insert(metadata.id, event) + .setQuotaUser(metadata.guildId.asString()) + .execute() + } catch (e: Exception) { + LOGGER.error("Failed to create event on Google Calendar", e) + null + } + } + + suspend fun patchEvent(metadata: CalendarMetadata, event: Event): Event? { + val service = getGoogleCalendarService(metadata) - // TODO: Handling of this should be moved up higher in the impl? - if (response.error?.error == "invalid_grant") { - LOGGER.debug(DEFAULT, "Google Oauth invalid_grant for access token refresh") - throw AccessRevokedException() // TODO: How should I handle this for external calendars? Right now we just delete everything - } else if (response.error != null) { - LOGGER.error(DEFAULT, "[Google] Error requesting new access token | ${response.code} | ${response.error.error}") + return try { + service.events() + .patch(metadata.id, event.id, event) + .setQuotaUser(metadata.guildId.asString()) + .execute() + } catch (e: Exception) { + LOGGER.error("Failed to patch event on Google Calendar", e) + null } + } + + suspend fun updateEvent(metadata: CalendarMetadata, event: Event): Event? { + val service = getGoogleCalendarService(metadata) - return response + return try { + service.events() + .update(metadata.id, event.id, event) + .setQuotaUser(metadata.guildId.asString()) + .execute() + } catch (e: Exception) { + LOGGER.error("Failed to update event on Google Calendar", e) + null + } } + + suspend fun getEvent(metadata: CalendarMetadata, id: String): Event? { + val service = getGoogleCalendarService(metadata) + + // This whole block can probably be shortened once old impl behavior is moved to a higher abstraction layer + return try { + val event = service.events() + .get(metadata.id, id) + .setQuotaUser(metadata.guildId.asString()) + .execute() + + // TODO: Old impl deleted related announcements here, this should be moved higher in the impl imho + if (event.status.equals("cancelled", true)) null + else event + } catch (e: GoogleJsonResponseException) { + when (HttpStatus.valueOf(e.statusCode)) { + HttpStatus.GONE -> { + // Event is gone. Sometimes Google will return this if the event is deleted + // TODO: Old impl also deleted related announcements here + null + } + HttpStatus.NOT_FOUND -> { + // Event not found. Was this ever an event? + // TODO: Old impl deleting announcements again + null + } else -> { + LOGGER.error("Failed to get event on Google Calendar w/ GoogleResponseException", e) + null + } + } + } catch (e: Exception) { + LOGGER.error("Failed to get event from Google Calendar", e) + null + } + } + + suspend fun getEvents(metadata: CalendarMetadata, amount: Int, start: Instant): List { + val service = getGoogleCalendarService(metadata) + + return try { + service.events() + .list(metadata.id) + .setMaxResults(amount) + .setTimeMin(DateTime(start.toEpochMilli())) + .setOrderBy("startTime") + .setSingleEvents(true) + .setShowDeleted(false) + .setQuotaUser(metadata.guildId.asString()) + .execute() + .items + } catch (e: Exception) { + LOGGER.error("Failed to get events from Google Calendar by start date (variant 1)", e) + emptyList() + } + } + + suspend fun getEvents(metadata: CalendarMetadata, amount: Int, start: Instant, end: Instant): List { + val service = getGoogleCalendarService(metadata) + + return try { + service.events() + .list(metadata.id) + .setMaxResults(amount) + .setTimeMin(DateTime(start.toEpochMilli())) + .setTimeMax(DateTime(end.toEpochMilli())) + .setOrderBy("startTime") + .setSingleEvents(true) + .setShowDeleted(false) + .setQuotaUser(metadata.guildId.asString()) + .execute() + .items + } catch (e: Exception) { + LOGGER.error("Failed to get events from Google Calendar by start and end date (variant 2)", e) + emptyList() + } + } + + suspend fun getEvents(metadata: CalendarMetadata, start: Instant, end: Instant): List { + val service = getGoogleCalendarService(metadata) + + return try { + service.events() + .list(metadata.id) + .setTimeMin(DateTime(start.toEpochMilli())) + .setTimeMax(DateTime(end.toEpochMilli())) + .setOrderBy("startTime") + .setSingleEvents(true) + .setShowDeleted(false) + .setQuotaUser(metadata.guildId.asString()) + .execute() + .items + } catch (e: Exception) { + LOGGER.error("Failed to get events from Google Calendar by start and end date without amount (variant 3)", e) + emptyList() + } + } + + suspend fun deleteEvent(metadata: CalendarMetadata, id: String): Boolean { + val service = getGoogleCalendarService(metadata) + + return try { + val response = service.events() + .delete(metadata.id, id) + .setQuotaUser(metadata.guildId.asString()) + .executeUnparsed() + + //Google sends 4 possible status codes, 200, 204, 404, 410. + // First 2 should be treated as successful, and the other 2 as not found. + when (response.statusCode) { + 200, 204 -> true + 404, 410 -> false + else -> { + //Log response data and return false as google sent an unexpected response code. + LOGGER.debug("Failed to delete event from Google Calendar w/ unknown response | ${response.statusCode} | ${response.statusMessage}") + false + } + } + } catch (e: GoogleJsonResponseException) { + if (e.statusCode != 410 || e.statusCode != 404) { + LOGGER.error("Failed to delete event from Google Calendar", e) + false + } else true + } catch (e: Exception) { + LOGGER.error("Failed to delete event from Google Calendar w/ unknown error", e) + false + } + } + + ///////// + /// Misc/Utility + ///////// + // TODO: Should I consider placing this somewhere else more sensible??? + fun randomCredentialId() = Random.nextInt(Config.SECRET_GOOGLE_CREDENTIAL_COUNT.getInt()) } diff --git a/core/src/main/kotlin/org/dreamexposure/discal/core/config/CacheConfig.kt b/core/src/main/kotlin/org/dreamexposure/discal/core/config/CacheConfig.kt index 951b11f37..a57b2a2f1 100644 --- a/core/src/main/kotlin/org/dreamexposure/discal/core/config/CacheConfig.kt +++ b/core/src/main/kotlin/org/dreamexposure/discal/core/config/CacheConfig.kt @@ -21,6 +21,7 @@ class CacheConfig { private val staticMessageTtl = Config.CACHE_TTL_STATIC_MESSAGE_MINUTES.getLong().asMinutes() private val announcementTll = Config.CACHE_TTL_ANNOUNCEMENT_MINUTES.getLong().asMinutes() private val wizardTtl = Config.TIMING_WIZARD_TIMEOUT_MINUTES.getLong().asMinutes() + private val calendarTokenTtl = Config.CACHE_TTL_CALENDAR_TOKEN_MINUTES.getLong().asMinutes() // Redis caching @@ -97,4 +98,7 @@ class CacheConfig { @Bean fun announcementWizardFallbackCache(): AnnouncementWizardStateCache = JdkCacheRepository(wizardTtl) + + @Bean + fun calendarTokenFallbackCache(): CalendarTokenCache = JdkCacheRepository(calendarTokenTtl) } diff --git a/core/src/main/kotlin/org/dreamexposure/discal/core/config/Config.kt b/core/src/main/kotlin/org/dreamexposure/discal/core/config/Config.kt index 2b90ea3f7..e88986103 100644 --- a/core/src/main/kotlin/org/dreamexposure/discal/core/config/Config.kt +++ b/core/src/main/kotlin/org/dreamexposure/discal/core/config/Config.kt @@ -29,6 +29,7 @@ enum class Config(private val key: String, private var value: Any? = null) { CACHE_TTL_RSVP_MINUTES("bot.cache.ttl-minutes.rsvp", 60), CACHE_TTL_STATIC_MESSAGE_MINUTES("bot.cache.ttl-minutes.static-messages", 60), CACHE_TTL_ANNOUNCEMENT_MINUTES("bot.cache.ttl-minutes.announcements", 120), + CACHE_TTL_CALENDAR_TOKEN_MINUTES("bot.cache.ttl-minutes.calendar", 60), // Security configuration diff --git a/core/src/main/kotlin/org/dreamexposure/discal/core/object/network/discal/CredentialData.kt b/core/src/main/kotlin/org/dreamexposure/discal/core/object/network/discal/CredentialData.kt index 7ab121431..ca886d677 100644 --- a/core/src/main/kotlin/org/dreamexposure/discal/core/object/network/discal/CredentialData.kt +++ b/core/src/main/kotlin/org/dreamexposure/discal/core/object/network/discal/CredentialData.kt @@ -6,7 +6,7 @@ import org.dreamexposure.discal.core.serializers.InstantAsStringSerializer import java.time.Instant @Serializable -@Deprecated("Really shouldn't need this after the auth wrapper has been redone") +@Deprecated("Really shouldn't need this after the auth wrapper has been redone, replaced with the TokenV1Model") data class CredentialData( @SerialName("access_token") val accessToken: String, diff --git a/core/src/main/kotlin/org/dreamexposure/discal/core/wrapper/google/AclRuleWrapper.kt b/core/src/main/kotlin/org/dreamexposure/discal/core/wrapper/google/AclRuleWrapper.kt index 890be1c78..ee9b933e4 100644 --- a/core/src/main/kotlin/org/dreamexposure/discal/core/wrapper/google/AclRuleWrapper.kt +++ b/core/src/main/kotlin/org/dreamexposure/discal/core/wrapper/google/AclRuleWrapper.kt @@ -1,12 +1,13 @@ package org.dreamexposure.discal.core.wrapper.google import com.google.api.services.calendar.model.AclRule -import org.dreamexposure.discal.core.`object`.calendar.CalendarData import org.dreamexposure.discal.core.logger.LOGGER +import org.dreamexposure.discal.core.`object`.calendar.CalendarData import org.dreamexposure.discal.core.utils.GlobalVal import reactor.core.publisher.Mono import reactor.core.scheduler.Schedulers +@Deprecated("Use the new GoogleCalendarApiWrapper component") object AclRuleWrapper { fun insertRule(rule: AclRule, calData: CalendarData): Mono { return GoogleAuthWrapper.getCalendarService(calData).flatMap { service -> diff --git a/core/src/main/kotlin/org/dreamexposure/discal/core/wrapper/google/CalendarWrapper.kt b/core/src/main/kotlin/org/dreamexposure/discal/core/wrapper/google/CalendarWrapper.kt index 1f21dd236..80b49d3fd 100644 --- a/core/src/main/kotlin/org/dreamexposure/discal/core/wrapper/google/CalendarWrapper.kt +++ b/core/src/main/kotlin/org/dreamexposure/discal/core/wrapper/google/CalendarWrapper.kt @@ -3,12 +3,13 @@ package org.dreamexposure.discal.core.wrapper.google import com.google.api.services.calendar.model.Calendar import com.google.api.services.calendar.model.CalendarListEntry import discord4j.common.util.Snowflake -import org.dreamexposure.discal.core.`object`.calendar.CalendarData import org.dreamexposure.discal.core.logger.LOGGER +import org.dreamexposure.discal.core.`object`.calendar.CalendarData import org.dreamexposure.discal.core.utils.GlobalVal import reactor.core.publisher.Mono import reactor.core.scheduler.Schedulers +@Deprecated("User new GoogleCalendarApiWrapper component") object CalendarWrapper { fun createCalendar(calendar: Calendar, credId: Int, guildId: Snowflake): Mono { return GoogleAuthWrapper.getCalendarService(credId).flatMap { service -> diff --git a/core/src/main/kotlin/org/dreamexposure/discal/core/wrapper/google/EventWrapper.kt b/core/src/main/kotlin/org/dreamexposure/discal/core/wrapper/google/EventWrapper.kt index bc3c1d253..7dcbba7cc 100644 --- a/core/src/main/kotlin/org/dreamexposure/discal/core/wrapper/google/EventWrapper.kt +++ b/core/src/main/kotlin/org/dreamexposure/discal/core/wrapper/google/EventWrapper.kt @@ -5,14 +5,15 @@ import com.google.api.client.util.DateTime import com.google.api.services.calendar.Calendar import com.google.api.services.calendar.model.Event import org.apache.http.HttpStatus -import org.dreamexposure.discal.core.`object`.calendar.CalendarData import org.dreamexposure.discal.core.database.DatabaseManager import org.dreamexposure.discal.core.logger.LOGGER +import org.dreamexposure.discal.core.`object`.calendar.CalendarData import org.dreamexposure.discal.core.utils.GlobalVal import reactor.core.publisher.Mono import reactor.core.scheduler.Schedulers import java.util.function.Predicate +@Deprecated("Use new GoogleCalendarApiWrapper component") object EventWrapper { fun createEvent(calData: CalendarData, event: Event): Mono { return GoogleAuthWrapper.getCalendarService(calData).flatMap { service -> diff --git a/core/src/main/kotlin/org/dreamexposure/discal/core/wrapper/google/GoogleAuthWrapper.kt b/core/src/main/kotlin/org/dreamexposure/discal/core/wrapper/google/GoogleAuthWrapper.kt index e10c8ed45..d837b41f0 100644 --- a/core/src/main/kotlin/org/dreamexposure/discal/core/wrapper/google/GoogleAuthWrapper.kt +++ b/core/src/main/kotlin/org/dreamexposure/discal/core/wrapper/google/GoogleAuthWrapper.kt @@ -25,6 +25,7 @@ import java.util.concurrent.ConcurrentHashMap import kotlin.random.Random import com.google.api.services.calendar.Calendar as GoogleCalendarService +@Deprecated("Use GoogleCalendarApiWrapper") object GoogleAuthWrapper { private val discalTokens: MutableMap = ConcurrentHashMap() private val externalTokens: MutableMap = ConcurrentHashMap() diff --git a/core/src/main/kotlin/org/dreamexposure/discal/typealiases.kt b/core/src/main/kotlin/org/dreamexposure/discal/typealiases.kt index 9524b4a70..b37d9f9c7 100644 --- a/core/src/main/kotlin/org/dreamexposure/discal/typealiases.kt +++ b/core/src/main/kotlin/org/dreamexposure/discal/typealiases.kt @@ -3,6 +3,7 @@ package org.dreamexposure.discal import discord4j.common.util.Snowflake import org.dreamexposure.discal.core.cache.CacheRepository import org.dreamexposure.discal.core.`object`.new.* +import org.dreamexposure.discal.core.`object`.new.model.discal.cam.TokenV1Model // Cache typealias GuildSettingsCache = CacheRepository @@ -13,3 +14,4 @@ typealias RsvpCache = CacheRepository typealias StaticMessageCache = CacheRepository typealias AnnouncementCache = CacheRepository> typealias AnnouncementWizardStateCache = CacheRepository +typealias CalendarTokenCache = CacheRepository