diff --git a/backend/src/main/java/com/paligot/confily/backend/events/EventDao.kt b/backend/src/main/java/com/paligot/confily/backend/events/EventDao.kt index b143a4a05..3f39e7706 100644 --- a/backend/src/main/java/com/paligot/confily/backend/events/EventDao.kt +++ b/backend/src/main/java/com/paligot/confily/backend/events/EventDao.kt @@ -7,10 +7,17 @@ import com.paligot.confily.backend.internals.helpers.database.getDocument import com.paligot.confily.backend.internals.helpers.database.getDocuments import com.paligot.confily.backend.internals.helpers.database.update import com.paligot.confily.backend.internals.helpers.database.upsert +import com.paligot.confily.backend.internals.helpers.storage.MimeType +import com.paligot.confily.backend.internals.helpers.storage.Storage +import com.paligot.confily.backend.internals.helpers.storage.Upload +import com.paligot.confily.models.AgendaV4 +import kotlinx.serialization.encodeToString +import kotlinx.serialization.json.Json class EventDao( private val projectName: String, - private val firestore: Firestore + private val firestore: Firestore, + private val storage: Storage ) { fun list(): List = firestore .collection(projectName) @@ -73,4 +80,15 @@ class EventDao( .collection(projectName) .update(event.slugId, event.copy(agendaUpdatedAt = System.currentTimeMillis())) } + + suspend fun getAgendaFile(eventId: String, updateAt: Long): AgendaV4? = + storage.download("$eventId/agenda/$updateAt.json") + ?.let { Json.decodeFromString(it.decodeToString()) } + + suspend fun uploadAgendaFile(eventId: String, updateAt: Long, agendaV4: AgendaV4): Upload = + storage.upload( + filename = "$eventId/agenda/$updateAt.json", + content = Json.encodeToString(agendaV4).toByteArray(), + mimeType = MimeType.JSON + ) } diff --git a/backend/src/main/java/com/paligot/confily/backend/events/EventModule.kt b/backend/src/main/java/com/paligot/confily/backend/events/EventModule.kt index f4eaebc7e..a4c7515d8 100644 --- a/backend/src/main/java/com/paligot/confily/backend/events/EventModule.kt +++ b/backend/src/main/java/com/paligot/confily/backend/events/EventModule.kt @@ -3,6 +3,7 @@ package com.paligot.confily.backend.events import com.paligot.confily.backend.categories.CategoryModule.categoryDao import com.paligot.confily.backend.formats.FormatModule.formatDao import com.paligot.confily.backend.internals.GoogleServicesModule.cloudFirestore +import com.paligot.confily.backend.internals.InternalModule import com.paligot.confily.backend.internals.SystemEnv.projectName import com.paligot.confily.backend.partners.PartnerModule.partnerDao import com.paligot.confily.backend.qanda.QAndAModule.qAndADao @@ -12,7 +13,9 @@ import com.paligot.confily.backend.speakers.SpeakerModule.speakerDao import com.paligot.confily.backend.third.parties.geocode.GeocodeModule.geocodeApi object EventModule { - val eventDao = lazy { EventDao(projectName, cloudFirestore.value) } + val eventDao = lazy { + EventDao(projectName, cloudFirestore.value, InternalModule.storage.value) + } val eventRepository = lazy { EventRepository( geocodeApi.value, @@ -52,6 +55,7 @@ object EventModule { } val eventRepositoryV4 = lazy { EventRepositoryV4( + eventDao.value, speakerDao.value, sessionDao.value, categoryDao.value, diff --git a/backend/src/main/java/com/paligot/confily/backend/events/EventRepositoryV4.kt b/backend/src/main/java/com/paligot/confily/backend/events/EventRepositoryV4.kt index 98083e36d..55e17cc8b 100644 --- a/backend/src/main/java/com/paligot/confily/backend/events/EventRepositoryV4.kt +++ b/backend/src/main/java/com/paligot/confily/backend/events/EventRepositoryV4.kt @@ -17,7 +17,9 @@ import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.async import kotlinx.coroutines.coroutineScope +@Suppress("LongParameterList") class EventRepositoryV4( + private val eventDao: EventDao, private val speakerDao: SpeakerDao, private val sessionDao: SessionDao, private val categoryDao: CategoryDao, @@ -25,7 +27,17 @@ class EventRepositoryV4( private val scheduleItemDao: ScheduleItemDao, private val dispatcher: CoroutineDispatcher = Dispatchers.IO ) { - suspend fun agenda(eventDb: EventDb) = coroutineScope { + suspend fun agenda(eventDb: EventDb): AgendaV4 = + eventDao.getAgendaFile(eventDb.slugId, eventDb.agendaUpdatedAt) ?: buildAgenda(eventDb) + + suspend fun generateAgenda(eventId: String, apiKey: String) = coroutineScope { + val eventDb = eventDao.getVerified(eventId, apiKey) + val agenda = buildAgenda(eventDb) + eventDao.uploadAgendaFile(eventId, eventDb.agendaUpdatedAt, agenda) + return@coroutineScope agenda + } + + private suspend fun buildAgenda(eventDb: EventDb) = coroutineScope { val schedules = async(context = dispatcher) { scheduleItemDao.getAll(eventDb.slugId).map { it.convertToModelV4() } }.await() diff --git a/backend/src/main/java/com/paligot/confily/backend/events/EventRouting.kt b/backend/src/main/java/com/paligot/confily/backend/events/EventRouting.kt index 63f3b9005..be2b74216 100644 --- a/backend/src/main/java/com/paligot/confily/backend/events/EventRouting.kt +++ b/backend/src/main/java/com/paligot/confily/backend/events/EventRouting.kt @@ -126,6 +126,11 @@ fun Routing.registerEventRoutes() { } } } + put("/events/{eventId}/agenda") { + val eventId = call.parameters["eventId"]!! + val apiKey = call.request.headers["api_key"]!! + call.respond(HttpStatusCode.OK, repositoryV4.generateAgenda(eventId, apiKey)) + } get("/events/{eventId}/openfeedback") { val eventId = call.parameters["eventId"]!! call.respond(HttpStatusCode.OK, repositoryV2.openFeedback(eventId)) diff --git a/backend/src/main/java/com/paligot/confily/backend/internals/helpers/storage/BucketStorage.kt b/backend/src/main/java/com/paligot/confily/backend/internals/helpers/storage/BucketStorage.kt index a1d2c3f40..84634cd49 100644 --- a/backend/src/main/java/com/paligot/confily/backend/internals/helpers/storage/BucketStorage.kt +++ b/backend/src/main/java/com/paligot/confily/backend/internals/helpers/storage/BucketStorage.kt @@ -3,6 +3,7 @@ package com.paligot.confily.backend.internals.helpers.storage import com.google.cloud.storage.Acl import com.google.cloud.storage.BlobId import com.google.cloud.storage.BlobInfo +import com.google.cloud.storage.StorageException import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.withContext @@ -13,6 +14,16 @@ class BucketStorage( private val bucketName: String, private val dispatcher: CoroutineDispatcher = Dispatchers.Default ) : Storage { + @Suppress("SwallowedException") + override suspend fun download(filename: String): ByteArray? = withContext(dispatcher) { + val blobId = BlobId.of(bucketName, filename) + return@withContext try { + storage.readAllBytes(blobId) + } catch (ex: StorageException) { + null + } + } + override suspend fun upload(filename: String, content: ByteArray, mimeType: MimeType): Upload = withContext(dispatcher) { val blobId = BlobId.of(bucketName, filename) diff --git a/backend/src/main/java/com/paligot/confily/backend/internals/helpers/storage/LocalStorage.kt b/backend/src/main/java/com/paligot/confily/backend/internals/helpers/storage/LocalStorage.kt index 8f0c8933e..afb082c9c 100644 --- a/backend/src/main/java/com/paligot/confily/backend/internals/helpers/storage/LocalStorage.kt +++ b/backend/src/main/java/com/paligot/confily/backend/internals/helpers/storage/LocalStorage.kt @@ -10,6 +10,10 @@ class LocalStorage( private val location: String = "/tmp", private val dispatcher: CoroutineDispatcher = Dispatchers.Default ) : Storage { + override suspend fun download(filename: String): ByteArray? = withContext(dispatcher) { + File("$location/$directory/$filename").readBytes() + } + override suspend fun upload( filename: String, content: ByteArray, diff --git a/backend/src/main/java/com/paligot/confily/backend/internals/helpers/storage/Storage.kt b/backend/src/main/java/com/paligot/confily/backend/internals/helpers/storage/Storage.kt index 2d094c012..6bc8922aa 100644 --- a/backend/src/main/java/com/paligot/confily/backend/internals/helpers/storage/Storage.kt +++ b/backend/src/main/java/com/paligot/confily/backend/internals/helpers/storage/Storage.kt @@ -3,6 +3,7 @@ package com.paligot.confily.backend.internals.helpers.storage import com.google.cloud.storage.Storage as CloudStorage interface Storage { + suspend fun download(filename: String): ByteArray? suspend fun upload(filename: String, content: ByteArray, mimeType: MimeType): Upload object Factory { @@ -22,6 +23,7 @@ enum class MimeType(val value: String) { GIF("image/gif"), SVG("image/svg+xml"), WEBP("image/webp"), + JSON("application/json"), OCTET_STREAM("application/octet-stream") }