Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Backend #240

Merged
merged 4 commits into from
Feb 29, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading