Skip to content

Commit

Permalink
Suppress notifications when updating own work day (#390) (#395)
Browse files Browse the repository at this point in the history
* Suppress notifications when updating own work day (#390)

* LocalDate#parse -> LocalDate#of for tests
  • Loading branch information
timsmelik authored Jan 9, 2025
1 parent 0c3081d commit fbd2852
Show file tree
Hide file tree
Showing 15 changed files with 334 additions and 85 deletions.
4 changes: 2 additions & 2 deletions readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,11 +59,11 @@ Use `ktlint` to lint kotlin files or `eslint` for javascript files
```bash
# check code style (it's also bound to "mvn verify")
$ ./mvnw antrun:run@ktlint
$ ./mvnw ktlint:check
src/main/kotlin/Main.kt:10:10: Unused import

# fix code style deviations (runs built-in formatter)
$ ./mvnw antrun:run@ktlint-format
$ ./mvnw ktlint:format

# fix code styles for js files with eslint
$ npm run lint
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,13 @@ class WorkdayController(
) = service.findByCode(code)
?.applyAuthentication(authentication)
?.applyAllowedToUpdate(form.status, authentication.isAdmin())
?.run { service.update(code, form) }
?.run {
service.update(
workDayCode = code,
form = form,
isOwnWorkDay = isOwnWorkDay(authentication),
)
}
.toResponse()

@DeleteMapping("/{code}")
Expand Down Expand Up @@ -125,11 +131,16 @@ class WorkdayController(

private fun WorkDay.applyAuthentication(authentication: Authentication) =
apply {
if (!(authentication.isAdmin() || this.assignment.person.isUser(authentication.name))) {
throw ResponseStatusException(UNAUTHORIZED, "User has not access to workday: ${this.code}")
if (!authentication.isAdmin() && !isOwnWorkDay(authentication)) {
throw ResponseStatusException(
UNAUTHORIZED,
"User has not access to workday: ${this.code}",
)
}
}

private fun WorkDay.isOwnWorkDay(authentication: Authentication) = assignment.person.isUser(authentication.name)

private fun getMediaType(name: String): MediaType {
val extension = java.io.File(name).extension.lowercase()
val mime = org.springframework.boot.web.server.MimeMappings.DEFAULT.get(extension)
Expand Down
14 changes: 10 additions & 4 deletions src/main/kotlin/community/flock/eco/workday/interfaces/Approve.kt
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,21 @@ interface Approve {
val status: Status
}

fun Approve.applyAllowedToUpdate(
fun <T : Approve> T.applyAllowedToUpdate(
status: Status,
isAdmin: Boolean,
) {
) = apply {
if (this.status !== Status.REQUESTED && !isAdmin) {
throw ResponseStatusException(HttpStatus.FORBIDDEN, "User is not allowed to change status")
throw ResponseStatusException(
HttpStatus.FORBIDDEN,
"User is not allowed to change status",
)
}
if (status !== this.status && !isAdmin) {
throw ResponseStatusException(HttpStatus.FORBIDDEN, "User is not allowed to change status field")
throw ResponseStatusException(
HttpStatus.FORBIDDEN,
"User is not allowed to change status field",
)
}
if (status !== this.status && !StatusTransition.check(this.status, status)) {
throw ResponseStatusException(HttpStatus.FORBIDDEN, "This status change is not allowed")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@ class WorkDayService(
fun update(
workDayCode: String,
form: WorkDayForm,
isOwnWorkDay: Boolean,
): WorkDay {
val currentWorkday = workDayRepository.findByCode(workDayCode).toNullable()
return currentWorkday
Expand All @@ -109,7 +110,9 @@ class WorkDayService(
.save()
}
.also {
emailService.sendUpdate(currentWorkday!!, it)
if (!isOwnWorkDay) {
emailService.sendUpdate(it)
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import community.flock.eco.workday.config.properties.MailjetTemplateProperties
import community.flock.eco.workday.model.Person
import community.flock.eco.workday.model.Status
import community.flock.eco.workday.model.WorkDay
import community.flock.eco.workday.utils.DateUtils.toHumanReadable
import org.slf4j.Logger
import org.slf4j.LoggerFactory
import org.springframework.context.i18n.LocaleContextHolder
Expand All @@ -12,28 +13,40 @@ import java.time.YearMonth
import java.time.format.TextStyle

@Service
class WorkdayEmailService(private val emailService: EmailService, private val mailjetTemplateProperties: MailjetTemplateProperties) {
class WorkdayEmailService(
private val emailService: EmailService,
private val mailjetTemplateProperties: MailjetTemplateProperties,
) {
private val log: Logger = LoggerFactory.getLogger(WorkdayEmailService::class.java)

fun sendUpdate(
old: WorkDay,
new: WorkDay,
) {
val recipient = new.assignment.person
fun sendUpdate(workDay: WorkDay) {
val recipient = workDay.assignment.person

var subject = "Update in Workday."
var emailMessage = "Er is een update in Workday."
val subject =
"Workday update (${workDay.from.toHumanReadable()} t/m ${workDay.to.toHumanReadable()} bij ${workDay.assignment.client.name})"

if (old.status !== new.status) {
subject = "Status update in Workday!"
emailMessage = "De status van je Workday is veranderd.\n\n" +
"Vorige status: ${old.status}.\n" +
"Nieuwe status: ${new.status}."
}
val project = workDay.assignment.project?.name?.replaceFirstChar { it.uppercase() } ?: "-"

val emailMessage =
"""
Je workday is bijgewerkt.
Klant: ${workDay.assignment.client.name}
Rol: ${workDay.assignment.role ?: "-"}
Project: $project
Van: ${workDay.from.toHumanReadable()}
Tot en met: ${workDay.to.toHumanReadable()}
Totaal aantal gewerkte uren: ${workDay.hours}
Status: ${workDay.status}
""".trimIndent()

log.info("Email generated for workday update for ${recipient.email}")

val templateVariables = emailService.createTemplateVariables(recipient.firstname, emailMessage)
val templateVariables =
emailService.createTemplateVariables(recipient.firstname, emailMessage)
emailService.sendEmailMessage(
recipient.receiveEmail,
recipient.email,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import community.flock.eco.workday.services.countWorkDaysInPeriod
import java.time.DayOfWeek
import java.time.LocalDate
import java.time.YearMonth
import java.time.format.DateTimeFormatter
import java.time.temporal.ChronoUnit

object DateUtils {
Expand Down Expand Up @@ -45,4 +46,8 @@ object DateUtils {
val to = YearMonth.of(this.year, this.month).atEndOfMonth()
return countWorkDaysInPeriod(from, to)
}

val humanReadableDateFormat = DateTimeFormatter.ofPattern("dd-MM-yyyy")

fun LocalDate.toHumanReadable() = format(humanReadableDateFormat)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package community.flock.eco.workday.forms

import java.time.LocalDate

fun aWorkDayForm() =
WorkDayForm(
from = LocalDate.of(2020, 1, 1),
to = LocalDate.of(2020, 3, 31),
assignmentCode = "some-assignment-code",
hours = 50.0,
sheets =
listOf(
aWorkDaySheetForm(),
),
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package community.flock.eco.workday.forms

import java.util.UUID

fun aWorkDaySheetForm() = WorkDaySheetForm("some-work-day-sheet", UUID.fromString("e03c0587-bb84-49f7-aaa8-34cfc76b4c8b"))
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package community.flock.eco.workday.model

import java.time.LocalDate

fun anAssignment(
person: Person = aPerson(),
client: Client = aClient(),
) = Assignment(
from = LocalDate.of(2024, 1, 1),
to = LocalDate.of(2024, 12, 31),
hourlyRate = 100.0,
hoursPerWeek = 40,
client = client,
person = person,
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package community.flock.eco.workday.model

fun aClient() =
Client(
id = 5,
code = "27620486-77f5-4484-b155-6e318bd24921",
name = "DHL",
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package community.flock.eco.workday.model

import java.time.LocalDate

fun aWorkDay(assignment: Assignment = anAssignment()) =
WorkDay(
id = 3,
code = "41b23e2e-bb80-45d3-aac5-f764aa7b2fc3",
from = LocalDate.of(2024, 1, 1),
to = LocalDate.of(2024, 1, 31),
hours = 160.0,
days = listOf(),
assignment = assignment,
status = Status.REQUESTED,
sheets =
listOf(
aWorkDaySheet(),
),
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package community.flock.eco.workday.model

import java.util.UUID

fun aWorkDaySheet() = WorkDaySheet("some-sheet", UUID.fromString("51b23e2e-bb80-45d3-aac5-f764aa7b2fc3"))
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
package community.flock.eco.workday.services

import community.flock.eco.workday.ApplicationConfiguration
import community.flock.eco.workday.config.AppTestConfig
import community.flock.eco.workday.forms.WorkDayForm
import community.flock.eco.workday.helpers.CreateHelper
import org.junit.jupiter.api.Test
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase
import org.springframework.boot.test.autoconfigure.orm.jpa.AutoConfigureDataJpa
import org.springframework.boot.test.autoconfigure.web.client.AutoConfigureWebClient
import org.springframework.boot.test.context.SpringBootTest
import org.springframework.context.annotation.Import
import org.springframework.test.context.ActiveProfiles
import java.time.LocalDate
import javax.transaction.Transactional
import kotlin.test.assertEquals
import kotlin.test.assertNotNull
import kotlin.test.assertNull

@SpringBootTest(classes = [ApplicationConfiguration::class, AppTestConfig::class])
@AutoConfigureTestDatabase
@AutoConfigureDataJpa
@AutoConfigureWebClient
@Transactional
@Import(CreateHelper::class)
@ActiveProfiles(profiles = ["test"])
class WorkDayServiceIntegrationTest(
@Autowired private val workDayService: WorkDayService,
@Autowired private val createHelper: CreateHelper,
) {
@Test
fun `Create, update and delete work day`() {
val from = LocalDate.of(2020, 1, 1)
val to = LocalDate.of(2020, 3, 31)
val client = createHelper.createClient()
val person = createHelper.createPerson()
val assignment = createHelper.createAssignment(client, person, from, to)

val createForm =
WorkDayForm(
from = from,
to = to,
assignmentCode = assignment.code,
hours = 50.0,
sheets = listOf(),
)

val created = workDayService.create(createForm)
assertNotNull(created.id)
assertEquals(50.0, created.hours)

val updateForm =
WorkDayForm(
from = from,
to = to,
assignmentCode = assignment.code,
hours = 25.0,
sheets = listOf(),
)
val updated =
workDayService.update(
workDayCode = created.code,
form = updateForm,
isOwnWorkDay = false,
)
assertNotNull(updated.id)
assertEquals(25.0, updated.hours)
assertEquals(created.code, updated.code)

assertNotNull(workDayService.findByCode(created.code))

workDayService.deleteByCode(created.code)

assertNull(workDayService.findByCode(created.code))
}
}
Loading

0 comments on commit fbd2852

Please sign in to comment.