Skip to content

Commit

Permalink
Merge pull request #234 from effectivemade/backendApp/hotfix/booking
Browse files Browse the repository at this point in the history
booking fix
  • Loading branch information
zavyalov-daniil authored Feb 6, 2024
2 parents 3711840 + be60bf8 commit 973fb5f
Show file tree
Hide file tree
Showing 10 changed files with 105 additions and 87 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -18,4 +18,6 @@ object BookingConstants {
val WORKSPACE_CALENDAR: String = System.getenv("WORKSPACE_CALENDAR")
?: config.propertyOrNull("calendar.workspaceCalendar")?.getString()
?: throw Exception("Environment and config file does not contain workspace Google calendar id")

const val UNTIL_FORMAT = "yyyyMMdd"
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package office.effective.common.di

import office.effective.common.utils.DatabaseTransactionManager
import office.effective.common.utils.impl.DatabaseTransactionManagerImpl
import office.effective.common.utils.UuidValidator
import org.koin.dsl.module
import org.ktorm.database.Database
Expand All @@ -22,6 +23,6 @@ val commonDiModule = module(createdAtStart = true) {
password = password
)
}
single { DatabaseTransactionManager(get()) }
single<DatabaseTransactionManager> { DatabaseTransactionManagerImpl(get()) }
single { UuidValidator() }
}
Original file line number Diff line number Diff line change
@@ -1,20 +1,11 @@
package office.effective.common.utils
package office.effective.common.utils;

import org.ktorm.database.Database
import org.ktorm.database.TransactionIsolation
import org.ktorm.database.TransactionManager
import org.slf4j.LoggerFactory
import org.ktorm.database.TransactionIsolation;

/**
* Class used for creation database transaction on the facade layer
* Interface for classes used for creation database transaction on the facade layer
*/
class DatabaseTransactionManager(database: Database) {
private val transactionManager: TransactionManager
private val logger = LoggerFactory.getLogger(this::class.java)
init {
transactionManager = database.transactionManager
}

interface DatabaseTransactionManager {
/**
* Executes code in a database transaction.
*
Expand All @@ -23,22 +14,5 @@ class DatabaseTransactionManager(database: Database) {
* @param serviceCall lambda function to be executed
* @param isolation transaction isolation
*/
fun <T> useTransaction(serviceCall: () -> T,
isolation: TransactionIsolation = TransactionIsolation.READ_COMMITTED): T {
logger.debug("Opening new database {} transaction", isolation.name)
val transaction = transactionManager.newTransaction(isolation = isolation)
val result: T
try {
result = serviceCall()
transaction.commit()
logger.debug("Transaction committed")
} catch (e: Throwable) {
logger.debug("Rollback transaction")
transaction.rollback()
throw e
} finally {
transaction.close()
}
return result
}
fun <T> useTransaction(serviceCall: () -> T, isolation: TransactionIsolation = TransactionIsolation.READ_COMMITTED): T
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package office.effective.common.utils.impl

import office.effective.common.utils.DatabaseTransactionManager
import org.ktorm.database.Database
import org.ktorm.database.TransactionIsolation
import org.ktorm.database.TransactionManager
import org.slf4j.LoggerFactory

/**
* Class used for creation database transaction on the facade layer
*/
class DatabaseTransactionManagerImpl(database: Database) : DatabaseTransactionManager {
private val transactionManager: TransactionManager = database.transactionManager
private val logger = LoggerFactory.getLogger(this::class.java)

/**
* Executes code in a database transaction.
*
* Rollbacks the transaction if an exception was thrown.
*
* @param serviceCall lambda function to be executed
* @param isolation transaction isolation
*/
override fun <T> useTransaction(serviceCall: () -> T, isolation: TransactionIsolation): T {
logger.debug("Opening new database {} transaction", isolation.name)
val transaction = transactionManager.newTransaction(isolation = isolation)
val result: T
try {
result = serviceCall()
transaction.commit()
logger.debug("Transaction committed")
} catch (e: Throwable) {
logger.debug("Rollback transaction")
transaction.rollback()
throw e
} finally {
transaction.close()
}
return result
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import com.google.api.services.calendar.model.Event
import com.google.api.services.calendar.model.Event.Organizer
import com.google.api.services.calendar.model.EventAttendee
import com.google.api.services.calendar.model.EventDateTime
import model.Recurrence.Companion.toRecurrence
import office.effective.model.Recurrence.Companion.toRecurrence
import office.effective.common.constants.BookingConstants
import office.effective.common.utils.UuidValidator
import office.effective.dto.BookingDTO
Expand Down Expand Up @@ -184,9 +184,8 @@ class GoogleCalendarConverter(
fun toGoogleEvent(dto: BookingDTO): Event {
logger.debug("[toGoogleEvent] converting meeting room booking dto to calendar event")
val event = Event().apply {
summary = "${dto.owner.fullName}: create from office application"
description =
"${dto.owner.email} - почта организатора"//"${dto.owner.integrations?.first { it.name == "email" }} - почта организатора"
summary = createDetailedEventSummary(dto)
description = "${dto.owner.email} - почта организатора"
organizer = dto.owner.toGoogleOrganizer()
attendees = dto.participants.map { it.toAttendee() } + dto.owner.toAttendee()
.apply { organizer = true } + dto.workspace.toAttendee()
Expand Down Expand Up @@ -264,6 +263,10 @@ class GoogleCalendarConverter(
return bookingConverter.dtoToModel(toBookingDTO(event));
}

private fun createDetailedEventSummary(dto: BookingDTO): String {
return "Meet ${dto.owner.fullName}"
}

/**
* Converts milliseconds to [EventDateTime]
*
Expand All @@ -272,7 +275,7 @@ class GoogleCalendarConverter(
*/
private fun Long.toGoogleDateTime(): EventDateTime {
return EventDateTime().also {
it.dateTime = DateTime(this)
it.dateTime = DateTime(this - TimeZone.getDefault().rawOffset)
it.timeZone = TimeZone.getDefault().id
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,8 @@
package office.effective.features.booking.converters

import model.Ending
import model.Freq
import model.Recurrence
import java.text.SimpleDateFormat
import java.util.Formatter
import java.util.GregorianCalendar
import office.effective.model.Ending
import office.effective.model.Freq
import office.effective.model.Recurrence

/**
* Object for creating Google calendar recurrence rule
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import com.google.api.client.googleapis.json.GoogleJsonResponseException
import com.google.api.client.util.DateTime
import com.google.api.services.calendar.Calendar
import com.google.api.services.calendar.model.Event
import office.effective.common.constants.BookingConstants
import office.effective.common.exception.InstanceNotFoundException
import office.effective.common.exception.MissingIdException
import office.effective.common.exception.WorkspaceUnavailableException
Expand All @@ -29,8 +30,7 @@ class BookingCalendarRepository(
private val googleCalendarConverter: GoogleCalendarConverter
) : IBookingRepository {
private val calendarEvents = calendar.Events()
private val defaultCalendar = config.propertyOrNull("calendar.defaultCalendar")?.getString()
?: throw Exception("Config file does not contain Google default calendar id")
private val defaultCalendar = BookingConstants.DEFAULT_CALENDAR
private val logger = LoggerFactory.getLogger(this::class.java)

/**
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
package model
package office.effective.model

import com.google.api.client.util.DateTime
import model.RecurrenceDTO
import office.effective.common.constants.BookingConstants
import java.lang.IllegalArgumentException
import java.lang.StringBuilder
import java.text.SimpleDateFormat
import java.util.*

Expand Down Expand Up @@ -45,40 +45,29 @@ data class Recurrence(
* Converts milliseconds date into exdate format from RFC5545
*
* @param millisDate - date in milliseconds ([Long])
* @return [String] - date in DATE-TIME (RFC5545). Example: 20231015T200000Z
* @return [String] - date in DATE-TIME (RFC5545). Example: [BookingConstants.UNTIL_FORMAT]
* @author Kiselev Danil
* */
private fun toDateRfc5545(millisDate: Long): String {
val time = GregorianCalendar().apply { timeInMillis = millisDate }
return SimpleDateFormat("yyyyMMdd").format(time.time)
val time = GregorianCalendar().apply { timeInMillis = millisDate + 86400000 }
return SimpleDateFormat(BookingConstants.UNTIL_FORMAT).format(time.time)
}
}

fun toDto(): RecurrenceDTO = RecurrenceDTO(
public fun toDto(): RecurrenceDTO = RecurrenceDTO(
interval = if (interval != 0) interval else null,
freq = freq.name,
count = if (ending is Ending.Count) ending.value else null,
until = if (ending is Ending.Until) parceUntil(ending.value) else null,
until = if (ending is Ending.Until) parseUntil(ending.value) else null,
byDay = byDay,
byMonth = byMonth,
byYearDay = byYearDay,
byHour = byHour
)

private fun parceUntil(untilStr: String): Long {
//old
//2023 10 15 T 20 00 00 Z
//0123 45 67 8 90 12 34 5

//new
// 2023 12 24


val year: Int = untilStr.substring(0,4).toInt()
val month: Int = untilStr.substring(4,6).toInt()
val day: Int = untilStr.substring(6,8).toInt()

val dt = Date(year - 1900, month, day)
return dt.time
private fun parseUntil(untilStr: String): Long {
val date: Date = SimpleDateFormat(BookingConstants.UNTIL_FORMAT).parse(untilStr)
println("UNTIL: $untilStr")
return date.time
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ package office.effective.booking

import junit.framework.TestCase.assertEquals
import office.effective.common.exception.InstanceNotFoundException
import office.effective.common.utils.DatabaseTransactionManager
import office.effective.common.utils.impl.DatabaseTransactionManagerImpl
import office.effective.common.utils.UuidValidator
import office.effective.features.booking.converters.BookingFacadeConverter
import office.effective.dto.BookingDTO
Expand Down Expand Up @@ -33,7 +33,7 @@ class BookingFacadeTest {
@Mock
private lateinit var uuidValidator: UuidValidator
@Mock
private lateinit var transactionManager: DatabaseTransactionManager
private lateinit var transactionManager: DatabaseTransactionManagerImpl
@Mock
private lateinit var bookingFacadeConverter: BookingFacadeConverter
@Mock
Expand Down Expand Up @@ -75,27 +75,28 @@ class BookingFacadeTest {

@Test
fun testFindById() {
val bookingId = UUID.fromString("8896abc1-457b-41e4-b80b-2fe7cfb3dbaf")
val instant = Instant.now()
val existingBooking = Booking(
user,
emptyList(),
workspace,
bookingId,
"8896abc1-457b-41e4-b80b-2fe7cfb3dbaf",
instant,
instant,
instant)
null)
val expectedBookingDTO = BookingDTO(
userDto, emptyList(),
userDto,
emptyList(),
workspaceDto,
bookingId.toString(),
"8896abc1-457b-41e4-b80b-2fe7cfb3dbaf",
instant.toEpochMilli(),
instant.toEpochMilli())

setUpMockTransactionManager()
whenever(service.findById(anyOrNull())).thenReturn(existingBooking)
setUpMockConverter(existingBooking, expectedBookingDTO)

val result = facade.findById(bookingId.toString())
val result = facade.findById("8896abc1-457b-41e4-b80b-2fe7cfb3dbaf")

assertEquals(expectedBookingDTO, result)
}
Expand All @@ -118,12 +119,14 @@ class BookingFacadeTest {
val expectedList = listOf(bookingMockDto, bookingMockDto)

setUpMockTransactionManager()
whenever(service.findAll(anyOrNull(), anyOrNull())).thenReturn(existingList)
whenever(service.findAll(anyOrNull(), anyOrNull(), anyOrNull(), anyOrNull())).thenReturn(existingList)
whenever(bookingFacadeConverter.modelToDto(anyOrNull())).thenReturn(expectedList[0], expectedList[1])

val result = facade.findAll(
"8896abc1-457b-41e4-b80b-2fe7cfb3dbaf",
"8896abc2-457b-41e4-b80b-2fe7cfb3dbaf"
"8896abc2-457b-41e4-b80b-2fe7cfb3dbaf",
null,
Instant.now().toEpochMilli()
)

assertEquals(expectedList, result)
Expand All @@ -146,14 +149,22 @@ class BookingFacadeTest {
@Test
fun testPut() {
setUpMockTransactionManager()
val instant = Instant.now()
val expectedBookingDTO = BookingDTO(
userDto,
emptyList(),
workspaceDto,
"8896abc1-457b-41e4-b80b-2fe7cfb3dbaf",
instant.toEpochMilli(),
instant.toEpochMilli())
val resultMockDto = mock<BookingDTO>()
val resultMock = mock<Booking>()
whenever(bookingFacadeConverter.dtoToModel(bookingMockDto)).thenReturn(bookingMock)
whenever(bookingFacadeConverter.dtoToModel(expectedBookingDTO)).thenReturn(bookingMock)
whenever(service.update(bookingMock)).thenReturn(resultMock)
whenever(bookingFacadeConverter.modelToDto(resultMock)).thenReturn(resultMockDto)
whenever(bookingFacadeConverter.modelToDto(resultMock)).thenReturn(expectedBookingDTO)

val result = facade.put(bookingMockDto)
val result = facade.put(expectedBookingDTO)

assertEquals(resultMockDto, result)
assertEquals(expectedBookingDTO, result)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ package office.effective.workspace

import junit.framework.TestCase.assertEquals
import office.effective.common.exception.InstanceNotFoundException
import office.effective.common.utils.DatabaseTransactionManager
import office.effective.common.utils.impl.DatabaseTransactionManagerImpl
import office.effective.common.utils.UuidValidator
import office.effective.features.workspace.converters.WorkspaceFacadeConverter
import office.effective.dto.WorkspaceDTO
Expand All @@ -28,7 +28,7 @@ class WorkspaceFacadeTest {
@Mock
private lateinit var mockConverter: WorkspaceFacadeConverter
@Mock
private lateinit var mockTransactionManager: DatabaseTransactionManager
private lateinit var mockTransactionManager: DatabaseTransactionManagerImpl
@Mock
private lateinit var mockUuidValidator: UuidValidator

Expand Down Expand Up @@ -63,7 +63,7 @@ class WorkspaceFacadeTest {
fun testFindById() {
val workspaceId = UUID.randomUUID()
val existingWorkspace = Workspace(workspaceId, "Workspace 1", "Tag", emptyList())
val expectedWorkspaceDTO = WorkspaceDTO(workspaceId.toString(), "Workspace 1", emptyList())
val expectedWorkspaceDTO = WorkspaceDTO(workspaceId.toString(), "Workspace 1", emptyList(), null, "Tag")

setUpMockTransactionManager()
setUpMockService(existingWorkspace)
Expand Down Expand Up @@ -95,8 +95,8 @@ class WorkspaceFacadeTest {
Workspace(workspace2Id, "Workspace 2", "Tag", emptyList())
)
val expectedList = listOf(
WorkspaceDTO(workspace1Id.toString(), "Workspace 1", emptyList()),
WorkspaceDTO(workspace2Id.toString(), "Workspace 2", emptyList())
WorkspaceDTO(workspace1Id.toString(), "Workspace 1", emptyList(), null, "Tag"),
WorkspaceDTO(workspace2Id.toString(), "Workspace 2", emptyList(), null, "Tag")
)

setUpMockTransactionManager()
Expand Down

0 comments on commit 973fb5f

Please sign in to comment.