Skip to content

Commit

Permalink
feat(backend): support activities by partners.
Browse files Browse the repository at this point in the history
  • Loading branch information
GerardPaligot committed Oct 26, 2024
1 parent f25425a commit 1a8f0b1
Show file tree
Hide file tree
Showing 23 changed files with 369 additions and 56 deletions.
2 changes: 2 additions & 0 deletions backend/src/main/java/com/paligot/confily/backend/Server.kt
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.paligot.confily.backend

import com.paligot.confily.backend.activities.registerActivitiesRoutes
import com.paligot.confily.backend.categories.registerCategoriesRoutes
import com.paligot.confily.backend.events.registerEventRoutes
import com.paligot.confily.backend.formats.registerFormatsRoutes
Expand Down Expand Up @@ -93,6 +94,7 @@ fun main() {
registerCategoriesRoutes()
registerFormatsRoutes()
registerSchedulersRoutes()
registerActivitiesRoutes()
registerPartnersRoutes()
// Third parties
registerBilletWebRoutes()
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package com.paligot.confily.backend.activities

import com.google.cloud.firestore.Firestore
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.insert
import com.paligot.confily.backend.internals.helpers.database.update

private const val CollectionName = "activities"

class ActivityDao(
private val projectName: String,
private val firestore: Firestore
) {
fun get(eventId: String, id: String): ActivityDb? = firestore
.collection(projectName)
.document(eventId)
.collection(CollectionName)
.getDocument(id)

fun getAll(eventId: String): List<ActivityDb> = firestore
.collection(projectName)
.document(eventId)
.collection(CollectionName)
.getDocuments<ActivityDb>()

fun createOrUpdate(eventId: String, item: ActivityDb) {
if (item.id == null) {
firestore
.collection(projectName)
.document(eventId)
.collection(CollectionName)
.insert { item.copy(id = it) }
} else {
firestore
.collection(projectName)
.document(eventId)
.collection(CollectionName)
.update(item.id, item)
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package com.paligot.confily.backend.activities

data class ActivityDb(
val id: String? = null,
val name: String = "",
val startTime: String = "",
val endTime: String = "",
val partnerId: String = ""
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package com.paligot.confily.backend.activities

import com.paligot.confily.models.Activity
import com.paligot.confily.models.inputs.ActivityInput

fun ActivityDb.convertToModel() = Activity(
id = id ?: "",
name = name,
startTime = startTime,
endTime = endTime,
partnerId = partnerId
)

fun ActivityInput.convertToDb(id: String? = null) = ActivityDb(
id = id,
name = name,
startTime = startTime,
endTime = endTime,
partnerId = partnerId
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package com.paligot.confily.backend.activities

import com.paligot.confily.backend.events.EventModule.eventDao
import com.paligot.confily.backend.internals.GoogleServicesModule.cloudFirestore
import com.paligot.confily.backend.internals.SystemEnv.projectName
import com.paligot.confily.backend.partners.PartnerModule.partnerDao

object ActivityModule {
val activityDao = lazy { ActivityDao(projectName, cloudFirestore.value) }
val activityRepository = lazy {
ActivityRepository(eventDao.value, partnerDao.value, activityDao.value)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package com.paligot.confily.backend.activities

import com.paligot.confily.backend.NotFoundException
import com.paligot.confily.backend.events.EventDao
import com.paligot.confily.backend.partners.PartnerDao
import com.paligot.confily.models.inputs.ActivityInput
import kotlinx.coroutines.coroutineScope
import kotlinx.datetime.LocalDateTime

class ActivityRepository(
private val eventDao: EventDao,
private val partnerDao: PartnerDao,
private val activityDao: ActivityDao
) {
suspend fun create(eventId: String, apiKey: String, activity: ActivityInput) = coroutineScope {
val event = eventDao.getVerified(eventId, apiKey)
val partnerExist = partnerDao.exists(eventId, activity.partnerId)
if (!partnerExist) {
throw NotFoundException("Partner ${activity.partnerId} Not Found")
}
val eventStartDate = LocalDateTime.parse(event.startDate.dropLast(1))
val activityStartDate = LocalDateTime.parse(activity.startTime)
if (activityStartDate < eventStartDate) {
throw IllegalArgumentException("Activity start date must be after event start date")
}
val eventEndDate = LocalDateTime.parse(event.endDate.dropLast(1))
val activityEndDate = LocalDateTime.parse(activity.endTime)
if (activityEndDate > eventEndDate) {
throw IllegalArgumentException("Activity end date must be before event end date")
}
activityDao.createOrUpdate(eventId, activity.convertToDb())
eventDao.updateUpdatedAt(event)
return@coroutineScope eventId
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package com.paligot.confily.backend.activities

import com.paligot.confily.backend.activities.ActivityModule.activityRepository
import com.paligot.confily.backend.receiveValidated
import com.paligot.confily.models.inputs.ActivityInput
import io.ktor.http.HttpStatusCode
import io.ktor.server.response.respond
import io.ktor.server.routing.Routing
import io.ktor.server.routing.post

fun Routing.registerActivitiesRoutes() {
val repository by activityRepository

post("/activities") {
val eventId = call.parameters["eventId"]!!
val apiKey = call.request.headers["api_key"]!!
val activity = call.receiveValidated<ActivityInput>()
call.respond(HttpStatusCode.Created, repository.create(eventId, apiKey, activity))
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.paligot.confily.backend.partners

import com.google.cloud.firestore.Firestore
import com.paligot.confily.backend.internals.helpers.database.docExists
import com.paligot.confily.backend.internals.helpers.database.insert
import com.paligot.confily.backend.internals.helpers.database.isNotEmpty
import com.paligot.confily.backend.internals.helpers.database.map
Expand Down Expand Up @@ -29,6 +30,12 @@ class PartnerDao(
return@map it.copy(siteUrl = "https://${it.siteUrl}")
}

fun exists(eventId: String, partnerId: String): Boolean = firestore
.collection(projectName)
.document(eventId)
.collection(CollectionName)
.docExists(partnerId)

fun createOrUpdate(eventId: String, partner: PartnerDb): String {
if (partner.id == "") {
return firestore
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@ import com.paligot.confily.models.Partner
import com.paligot.confily.models.PartnerMedia
import com.paligot.confily.models.PartnerMediaPngs
import com.paligot.confily.models.PartnerV2
import com.paligot.confily.models.PartnerV3
import com.paligot.confily.models.SocialItem
import com.paligot.confily.models.SocialType
import com.paligot.confily.models.inputs.PartnerInput
import java.net.URI

Expand Down Expand Up @@ -65,6 +68,27 @@ fun PartnerDb.convertToModelV2(jobs: List<Job>) = PartnerV2(
jobs = jobs
)

fun PartnerDb.convertToModelV3(jobs: List<Job>) = PartnerV3(
id = this.id,
name = this.name,
description = this.description,
media = convertToPartnerMediaModel(),
types = this.sponsorings,
socials = mutableListOf<SocialItem>().apply {
add(SocialItem(type = SocialType.Website, url = this@convertToModelV3.siteUrl))
val xUrl = this@convertToModelV3.twitterUrl
if (xUrl != null && xUrl != "") {
add(SocialItem(type = SocialType.X, url = xUrl))
}
val linkedUrl = this@convertToModelV3.linkedinUrl
if (linkedUrl != null && linkedUrl != "") {
add(SocialItem(type = SocialType.LinkedIn, url = linkedUrl))
}
},
address = this.address.convertToModel(),
jobs = jobs
)

@Suppress("ReturnCount")
fun List<Upload>.convertToPartnerMediaDb(logoUrl: String): PartnerMediaDb? {
if (isEmpty()) return null
Expand All @@ -81,7 +105,11 @@ fun List<Upload>.convertToPartnerMediaDb(logoUrl: String): PartnerMediaDb? {
)
}

fun PartnerInput.convertToDb(id: String? = null, addressDb: AddressDb, uploads: List<Upload> = emptyList()) = PartnerDb(
fun PartnerInput.convertToDb(
id: String? = null,
addressDb: AddressDb,
uploads: List<Upload> = emptyList()
) = PartnerDb(
id = id ?: "",
name = name,
description = description,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.paligot.confily.backend.partners

import com.paligot.confily.backend.activities.ActivityModule.activityDao
import com.paligot.confily.backend.events.EventModule.eventDao
import com.paligot.confily.backend.internals.GoogleServicesModule.cloudFirestore
import com.paligot.confily.backend.internals.InternalModule.storage
Expand All @@ -15,6 +16,7 @@ object PartnerModule {
geocodeApi.value,
eventDao.value,
partnerDao.value,
activityDao.value,
jobDao.value,
transcoder.value
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,19 @@ package com.paligot.confily.backend.partners

import com.paligot.confily.backend.NotAcceptableException
import com.paligot.confily.backend.NotFoundException
import com.paligot.confily.backend.activities.ActivityDao
import com.paligot.confily.backend.activities.convertToModel
import com.paligot.confily.backend.events.EventDao
import com.paligot.confily.backend.internals.helpers.image.TranscoderImage
import com.paligot.confily.backend.jobs.JobDao
import com.paligot.confily.backend.third.parties.geocode.GeocodeApi
import com.paligot.confily.backend.third.parties.geocode.convertToDb
import com.paligot.confily.backend.third.parties.welovedevs.convertToModel
import com.paligot.confily.models.PartnerV2
import com.paligot.confily.models.PartnersActivities
import com.paligot.confily.models.inputs.PartnerInput
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.async
import kotlinx.coroutines.awaitAll
import kotlinx.coroutines.coroutineScope
Expand All @@ -18,10 +23,12 @@ class PartnerRepository(
private val geocodeApi: GeocodeApi,
private val eventDao: EventDao,
private val partnerDao: PartnerDao,
private val activityDao: ActivityDao,
private val jobDao: JobDao,
private val imageTranscoder: TranscoderImage
private val imageTranscoder: TranscoderImage,
private val dispatcher: CoroutineDispatcher = Dispatchers.IO
) {
suspend fun list(eventId: String): Map<String, List<PartnerV2>> {
fun list(eventId: String): Map<String, List<PartnerV2>> {
val event = eventDao.get(eventId) ?: throw NotFoundException("Event $eventId Not Found")
val partners = partnerDao.getAll(eventId)
val jobs = jobDao.getAll(eventId)
Expand All @@ -38,6 +45,27 @@ class PartnerRepository(
}
}

suspend fun activities(eventId: String): PartnersActivities = coroutineScope {
val event = eventDao.get(eventId) ?: throw NotFoundException("Event $eventId Not Found")
val partners = async(dispatcher) { partnerDao.getAll(eventId) }
val jobs = async(dispatcher) { jobDao.getAll(eventId) }
val activities = async(dispatcher) { activityDao.getAll(eventId) }
val fetchedJobs = jobs.await()
return@coroutineScope PartnersActivities(
types = event.sponsoringTypes,
partners = partners.await().map { partner ->
partner.convertToModelV3(
fetchedJobs
.filter { it.partnerId == partner.id }
.map { it.convertToModel() }
)
},
activities = activities.await()
.sortedBy { it.startTime }
.map { it.convertToModel() }
)
}

suspend fun create(eventId: String, apiKey: String, partnerInput: PartnerInput): String =
coroutineScope {
val event = eventDao.getVerified(eventId, apiKey)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,10 @@ fun Routing.registerPartnersRoutes() {
val eventId = call.parameters["eventId"]!!
call.respond(HttpStatusCode.OK, repository.list(eventId))
}
get("/partners/activities") {
val eventId = call.parameters["eventId"]!!
call.respond(HttpStatusCode.OK, repository.activities(eventId))
}
post("/partners") {
val eventId = call.parameters["eventId"]!!
val apiKey = call.request.headers["api_key"]!!
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import com.paligot.confily.models.Attendee
import com.paligot.confily.models.EventList
import com.paligot.confily.models.EventV3
import com.paligot.confily.models.PartnerV2
import com.paligot.confily.models.PartnersActivities
import com.paligot.confily.models.QuestionAndResponse
import io.ktor.client.HttpClient
import io.ktor.client.call.body
Expand Down Expand Up @@ -50,6 +51,9 @@ class ConferenceApi(
suspend fun fetchPartners(eventId: String): Map<String, List<PartnerV2>> =
client.get("$baseUrl/events/$eventId/partners").body()

suspend fun fetchPartnersActivities(eventId: String): PartnersActivities =
client.get("$baseUrl/events/$eventId/partners/activities").body()

suspend fun fetchAttendee(eventId: String, barcode: String) =
client.get("$baseUrl/events/$eventId/billet-web/$barcode")
.body<Attendee>()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@ package com.paligot.confily.core.agenda

import com.paligot.confily.models.AgendaV4
import com.paligot.confily.models.EventV3
import com.paligot.confily.models.PartnerV2
import com.paligot.confily.models.PartnersActivities
import com.paligot.confily.models.QuestionAndResponse

interface AgendaDao {
fun saveAgenda(eventId: String, agenda: AgendaV4)
fun insertEvent(event: EventV3, qAndA: List<QuestionAndResponse>)
fun insertPartners(eventId: String, partners: Map<String, List<PartnerV2>>)
fun insertPartners(eventId: String, partners: PartnersActivities)
}
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ class AgendaRepositoryImpl(
}
val event = api.fetchEvent(eventId)
val qanda = api.fetchQAndA(eventId)
val partners = api.fetchPartners(eventId)
val partners = api.fetchPartnersActivities(eventId)
agendaDao.insertEvent(event, qanda)
agendaDao.insertPartners(eventId, partners)
}
Expand Down
Loading

0 comments on commit 1a8f0b1

Please sign in to comment.