Skip to content

Commit

Permalink
Update documentation url
Browse files Browse the repository at this point in the history
  • Loading branch information
balysv committed Jul 14, 2021
1 parent 21b21b0 commit dcee69b
Show file tree
Hide file tree
Showing 7 changed files with 28 additions and 50 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@

Backend service for the Sama app.

Api documentation can be found [here](https://app.meetsama.com.smtest.it/swagger-ui/index.html?configUrl=/api/docs/swagger-config#/)
Api documentation can be found [here](https://app.meetsama.com.smtest.it/api/swagger-ui/index.html?configUrl=/api/docs/swagger-config#/)
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package com.sama.meeting.application
import com.sama.calendar.application.BlockEventConsumer
import com.sama.calendar.domain.BlockRepository
import com.sama.common.ApplicationService
import com.sama.common.NotFoundException
import com.sama.common.findByIdOrThrow
import com.sama.common.toMinutes
import com.sama.meeting.domain.*
Expand Down Expand Up @@ -122,9 +123,9 @@ class MeetingApplicationService(

val proposedMeeting = when (val meeting = meetingFrom(intentEntity, meetingEntity).getOrThrow()) {
is ProposedMeeting -> meeting
is ConfirmedMeeting -> throw MeetingAlreadyConfirmedException(meeting.meetingId)
is ExpiredMeeting -> throw MeetingProposalExpiredException(meeting.meetingId)
else -> throw InvalidMeetingStatusException(meeting.meetingId, meeting.status)
is ConfirmedMeeting -> throw MeetingAlreadyConfirmedException(meetingCode)
is ExpiredMeeting -> throw NotFoundException(ProposedMeeting::class, meetingCode)
else -> throw InvalidMeetingStatusException(meetingCode, meeting.status)
}

val (start, end) = proposedMeeting.proposedSlotsRange()
Expand All @@ -146,9 +147,9 @@ class MeetingApplicationService(

val proposedMeeting = when (val meeting = meetingFrom(intentEntity, meetingEntity).getOrThrow()) {
is ProposedMeeting -> meeting
is ConfirmedMeeting -> throw MeetingAlreadyConfirmedException(meeting.meetingId)
is ExpiredMeeting -> throw MeetingProposalExpiredException(meeting.meetingId)
else -> throw InvalidMeetingStatusException(meeting.meetingId, meeting.status)
is ConfirmedMeeting -> throw MeetingAlreadyConfirmedException(meetingCode)
is ExpiredMeeting -> throw NotFoundException(ProposedMeeting::class, meetingCode)
else -> throw InvalidMeetingStatusException(meetingCode, meeting.status)
}

val meetingRecipient = command.recipientEmail.let { MeetingRecipient.fromEmail(it) }
Expand Down
28 changes: 12 additions & 16 deletions app/src/main/java/com/sama/meeting/domain/Exceptions.kt
Original file line number Diff line number Diff line change
Expand Up @@ -2,27 +2,23 @@ package com.sama.meeting.domain

import com.sama.common.DomainEntityStatusException
import com.sama.common.DomainInvalidActionException
import com.sama.common.DomainIntegrityException
import com.sama.common.DomainValidationException
import java.time.Duration

class InvalidDurationException(meetingIntentId: MeetingIntentId, duration: Duration) :
DomainValidationException("MeetingIntent#$meetingIntentId: Unsupported duration '${duration.toMinutes()} min'")
class InvalidDurationException(duration: Duration) :
DomainValidationException("Unsupported duration '${duration.toMinutes()} min'")

class InvalidMeetingSlotException(meetingIntentId: MeetingIntentId, slot: MeetingSlot) :
DomainValidationException("MeetingIntent#$meetingIntentId: Invalid slot '${slot.startDateTime} - ${slot.endDateTime}'")
class InvalidMeetingSlotException(slot: MeetingSlot) :
DomainValidationException("Invalid slot '${slot.startDateTime} - ${slot.endDateTime}'")

class InvalidMeetingProposalException(meetingIntentId: MeetingIntentId, message: String) :
DomainValidationException("MeetingIntent#$meetingIntentId cannot be proposed: $message")
class InvalidMeetingProposalException(message: String) :
DomainValidationException("Meeting cannot be proposed: $message")

class MeetingAlreadyConfirmedException(meetingId: MeetingId) :
DomainEntityStatusException("already_confirmed", "Meeting#$meetingId already confirmed")
class MeetingAlreadyConfirmedException(meetingCode: MeetingCode) :
DomainEntityStatusException("already_confirmed", "Meeting#$meetingCode already confirmed")

class MeetingProposalExpiredException(meetingId: MeetingId) :
DomainEntityStatusException("proposal_expired", "Meeting#$meetingId has expired")
class InvalidMeetingStatusException(meetingCode: MeetingCode, status: MeetingStatus):
DomainEntityStatusException("invalid_status", "Meeting#$meetingCode: Invalid status: $status")

class InvalidMeetingStatusException(meetingId: MeetingId, status: MeetingStatus):
DomainEntityStatusException("invalid_status", "Meeting#$meetingId: Invalid status: $status")

class MeetingSlotUnavailableException(meetingId: MeetingId, slot: MeetingSlot):
DomainInvalidActionException("slot_unavailable", "Meeting#$meetingId: Slot unavailable: '${slot.startDateTime} - ${slot.endDateTime}'")
class MeetingSlotUnavailableException(meetingCode: MeetingCode, slot: MeetingSlot):
DomainInvalidActionException("slot_unavailable", "Meeting#$meetingCode: Slot unavailable: '${slot.startDateTime} - ${slot.endDateTime}'")
2 changes: 1 addition & 1 deletion app/src/main/java/com/sama/meeting/domain/Meeting.kt
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ data class ProposedMeeting(
fun confirm(slot: MeetingSlot, recipient: MeetingRecipient): Result<ConfirmedMeeting> {
return kotlin.runCatching {
val confirmedSlot = expandedSlots().find { it == slot }
?: throw MeetingSlotUnavailableException(meetingId, slot)
?: throw MeetingSlotUnavailableException(meetingCode, slot)

ConfirmedMeeting(meetingId, initiatorId, duration, recipient, confirmedSlot)
}
Expand Down
8 changes: 3 additions & 5 deletions app/src/main/java/com/sama/meeting/domain/MeetingIntent.kt
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ data class MeetingIntent(

init {
if (duration < minimumDuration) {
throw InvalidDurationException(meetingIntentId, duration)
throw InvalidDurationException(duration)
}
validateSlots(suggestedSlots)
}
Expand All @@ -45,7 +45,7 @@ data class MeetingIntent(
proposedSlots: List<MeetingSlot>
): Result<ProposedMeeting> {
if (proposedSlots.isEmpty()) {
return Result.failure(InvalidMeetingProposalException(meetingIntentId, "No slots proposed"))
return Result.failure(InvalidMeetingProposalException("No slots proposed"))
}

kotlin.runCatching { validateSlots(proposedSlots) }
Expand All @@ -64,11 +64,9 @@ data class MeetingIntent(
}

private fun validateSlots(slots: List<MeetingSlot>) {
// TODO: validate duplicates

slots.firstOrNull { it.duration() < duration }
?.run {
throw InvalidMeetingSlotException(meetingIntentId, this)
throw InvalidMeetingSlotException(this)
}
}
}
21 changes: 2 additions & 19 deletions app/src/test/java/com/sama/api/meeting/MeetingControllerTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import com.sama.api.config.WebMvcConfiguration
import com.sama.meeting.application.*
import com.sama.meeting.domain.InvalidMeetingStatusException
import com.sama.meeting.domain.MeetingAlreadyConfirmedException
import com.sama.meeting.domain.MeetingProposalExpiredException
import com.sama.meeting.domain.MeetingStatus
import org.junit.jupiter.api.DynamicTest.dynamicTest
import org.junit.jupiter.api.Test
Expand Down Expand Up @@ -309,7 +308,7 @@ class MeetingControllerTest(
@Test
fun `meeting already confirmed`() {
whenever(meetingApplicationService.loadMeetingProposalFromCode(any()))
.thenThrow(MeetingAlreadyConfirmedException(1L))
.thenThrow(MeetingAlreadyConfirmedException("VGsUTGno"))

val expectedResponse = """
{
Expand All @@ -322,26 +321,10 @@ class MeetingControllerTest(
.andExpect(MockMvcResultMatchers.content().json(expectedResponse))
}

@Test
fun `meeting expired`() {
whenever(meetingApplicationService.loadMeetingProposalFromCode(any()))
.thenThrow(MeetingProposalExpiredException(1L))

val expectedResponse = """
{
"status": 410,
"reason": "proposal_expired"
}
"""
mockMvc.perform(get("/api/meeting/by-code/VGsUTGno"))
.andExpect(status().isGone)
.andExpect(MockMvcResultMatchers.content().json(expectedResponse))
}

@Test
fun `meeting status invalid`() {
whenever(meetingApplicationService.loadMeetingProposalFromCode(any()))
.thenThrow(InvalidMeetingStatusException(1L, MeetingStatus.REJECTED))
.thenThrow(InvalidMeetingStatusException("VGsUTGno", MeetingStatus.REJECTED))

val expectedResponse = """
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -265,7 +265,7 @@ class MeetingApplicationServiceTest(

return listOf(
MeetingStatus.CONFIRMED to MeetingAlreadyConfirmedException::class,
MeetingStatus.EXPIRED to MeetingProposalExpiredException::class,
MeetingStatus.EXPIRED to NotFoundException::class,
MeetingStatus.REJECTED to InvalidMeetingStatusException::class
).map { (status, expected) ->
DynamicTest.dynamicTest("Meeting status $status throws $expected") {
Expand Down Expand Up @@ -427,7 +427,7 @@ class MeetingApplicationServiceTest(

return listOf(
MeetingStatus.CONFIRMED to MeetingAlreadyConfirmedException::class,
MeetingStatus.EXPIRED to MeetingProposalExpiredException::class,
MeetingStatus.EXPIRED to NotFoundException::class,
MeetingStatus.REJECTED to InvalidMeetingStatusException::class
).map { (status, expected) ->
DynamicTest.dynamicTest("Meeting status $status throws $expected") {
Expand Down

0 comments on commit dcee69b

Please sign in to comment.