From bf0599a3bd08f34bb53b9d6ddd4f29c79ea46601 Mon Sep 17 00:00:00 2001 From: Tero Laakso Date: Tue, 17 Dec 2024 14:50:05 +0200 Subject: [PATCH] Keep old group acl rows when they should not change --- ...taffAttendanceControllerIntegrationTest.kt | 54 +++---- ...taffAttendanceControllerIntegrationTest.kt | 4 +- .../UnitAclControllerIntegrationTest.kt | 142 +++++++++++++++++- .../messaging/MessageAccountQueriesTest.kt | 4 +- .../evaka/messaging/MessageIntegrationTest.kt | 23 +-- ...activeEmployeesRoleResetIntegrationTest.kt | 4 +- .../kotlin/fi/espoo/evaka/daycare/UnitAcl.kt | 7 +- .../daycare/controllers/UnitAclController.kt | 21 +-- .../fi/espoo/evaka/shared/auth/AclQueries.kt | 24 +-- .../evaka/shared/dev/DataInitializers.kt | 4 +- 10 files changed, 199 insertions(+), 88 deletions(-) diff --git a/service/src/integrationTest/kotlin/fi/espoo/evaka/attendance/MobileRealtimeStaffAttendanceControllerIntegrationTest.kt b/service/src/integrationTest/kotlin/fi/espoo/evaka/attendance/MobileRealtimeStaffAttendanceControllerIntegrationTest.kt index bebb8ec3144..d0272f24cc0 100644 --- a/service/src/integrationTest/kotlin/fi/espoo/evaka/attendance/MobileRealtimeStaffAttendanceControllerIntegrationTest.kt +++ b/service/src/integrationTest/kotlin/fi/espoo/evaka/attendance/MobileRealtimeStaffAttendanceControllerIntegrationTest.kt @@ -13,7 +13,7 @@ import fi.espoo.evaka.shared.StaffAttendanceRealtimeId import fi.espoo.evaka.shared.auth.AuthenticatedUser import fi.espoo.evaka.shared.auth.UserRole import fi.espoo.evaka.shared.auth.insertDaycareAclRow -import fi.espoo.evaka.shared.auth.insertDaycareGroupAcl +import fi.espoo.evaka.shared.auth.syncDaycareGroupAcl import fi.espoo.evaka.shared.db.Database import fi.espoo.evaka.shared.dev.DevDaycareGroup import fi.espoo.evaka.shared.dev.DevDaycareGroupAcl @@ -84,8 +84,8 @@ class MobileRealtimeStaffAttendanceControllerIntegrationTest : tx.insert(employee) tx.insertDaycareAclRow(testDaycare.id, employee.id, UserRole.STAFF) tx.insertDaycareAclRow(testDaycare2.id, employee.id, UserRole.STAFF) - tx.insertDaycareGroupAcl(testDaycare.id, employee.id, listOf(groupId), now) - tx.insertDaycareGroupAcl(testDaycare2.id, employee.id, listOf(groupId2), now) + tx.syncDaycareGroupAcl(testDaycare.id, employee.id, listOf(groupId), now) + tx.syncDaycareGroupAcl(testDaycare2.id, employee.id, listOf(groupId2), now) tx.markStaffArrival( employee.id, @@ -110,7 +110,7 @@ class MobileRealtimeStaffAttendanceControllerIntegrationTest : tx.insert(employee) tx.insert(DevEmployeePin(userId = employee.id, pin = pinCode)) tx.insertDaycareAclRow(testDaycare.id, employee.id, UserRole.STAFF) - tx.insertDaycareGroupAcl(testDaycare.id, employee.id, listOf(groupId), now) + tx.syncDaycareGroupAcl(testDaycare.id, employee.id, listOf(groupId), now) } val arrivalTime = HelsinkiDateTime.of(today, LocalTime.of(8, 0)) @@ -146,7 +146,7 @@ class MobileRealtimeStaffAttendanceControllerIntegrationTest : tx.insert(employee) tx.insert(DevEmployeePin(userId = employee.id, pin = pinCode)) tx.insertDaycareAclRow(testDaycare.id, employee.id, UserRole.STAFF) - tx.insertDaycareGroupAcl(testDaycare.id, employee.id, listOf(groupId), now) + tx.syncDaycareGroupAcl(testDaycare.id, employee.id, listOf(groupId), now) } val arrivalTime = HelsinkiDateTime.of(today, LocalTime.of(8, 0)) @@ -176,7 +176,7 @@ class MobileRealtimeStaffAttendanceControllerIntegrationTest : tx.insert(employee) tx.insert(DevEmployeePin(userId = employee.id, pin = pinCode)) tx.insertDaycareAclRow(testDaycare.id, employee.id, UserRole.STAFF) - tx.insertDaycareGroupAcl(testDaycare.id, employee.id, listOf(groupId), now) + tx.syncDaycareGroupAcl(testDaycare.id, employee.id, listOf(groupId), now) } val arrivalTime = HelsinkiDateTime.of(today, LocalTime.of(8, 0)) @@ -211,7 +211,7 @@ class MobileRealtimeStaffAttendanceControllerIntegrationTest : tx.insert(employee) tx.insert(DevEmployeePin(userId = employee.id, pin = pinCode)) tx.insertDaycareAclRow(testDaycare.id, employee.id, UserRole.STAFF) - tx.insertDaycareGroupAcl(testDaycare.id, employee.id, listOf(groupId), now) + tx.syncDaycareGroupAcl(testDaycare.id, employee.id, listOf(groupId), now) tx.insert( DevStaffAttendancePlan( employeeId = employee.id, @@ -243,7 +243,7 @@ class MobileRealtimeStaffAttendanceControllerIntegrationTest : tx.insert(employee) tx.insert(DevEmployeePin(userId = employee.id, pin = pinCode)) tx.insertDaycareAclRow(testDaycare.id, employee.id, UserRole.STAFF) - tx.insertDaycareGroupAcl(testDaycare.id, employee.id, listOf(groupId), now) + tx.syncDaycareGroupAcl(testDaycare.id, employee.id, listOf(groupId), now) tx.insert( DevStaffAttendancePlan( employeeId = employee.id, @@ -276,7 +276,7 @@ class MobileRealtimeStaffAttendanceControllerIntegrationTest : tx.insert(employee) tx.insert(DevEmployeePin(userId = employee.id, pin = pinCode)) tx.insertDaycareAclRow(testDaycare.id, employee.id, UserRole.STAFF) - tx.insertDaycareGroupAcl(testDaycare.id, employee.id, listOf(groupId), now) + tx.syncDaycareGroupAcl(testDaycare.id, employee.id, listOf(groupId), now) tx.insert( DevStaffAttendancePlan( employeeId = employee.id, @@ -309,7 +309,7 @@ class MobileRealtimeStaffAttendanceControllerIntegrationTest : tx.insert(employee) tx.insert(DevEmployeePin(userId = employee.id, pin = pinCode)) tx.insertDaycareAclRow(testDaycare.id, employee.id, UserRole.STAFF) - tx.insertDaycareGroupAcl(testDaycare.id, employee.id, listOf(groupId), now) + tx.syncDaycareGroupAcl(testDaycare.id, employee.id, listOf(groupId), now) tx.insert( DevStaffAttendancePlan( employeeId = employee.id, @@ -351,7 +351,7 @@ class MobileRealtimeStaffAttendanceControllerIntegrationTest : tx.insert(employee) tx.insert(DevEmployeePin(userId = employee.id, pin = pinCode)) tx.insertDaycareAclRow(testDaycare.id, employee.id, UserRole.STAFF) - tx.insertDaycareGroupAcl(testDaycare.id, employee.id, listOf(groupId), now) + tx.syncDaycareGroupAcl(testDaycare.id, employee.id, listOf(groupId), now) tx.insert( DevStaffAttendancePlan( employeeId = employee.id, @@ -376,7 +376,7 @@ class MobileRealtimeStaffAttendanceControllerIntegrationTest : tx.insert(employee) tx.insert(DevEmployeePin(userId = employee.id, pin = pinCode)) tx.insertDaycareAclRow(testDaycare.id, employee.id, UserRole.STAFF) - tx.insertDaycareGroupAcl(testDaycare.id, employee.id, listOf(groupId), now) + tx.syncDaycareGroupAcl(testDaycare.id, employee.id, listOf(groupId), now) } val lastLoginBeforeArrival = db.read { db -> db.getEmployeeLastLogin(employee.id) } @@ -402,7 +402,7 @@ class MobileRealtimeStaffAttendanceControllerIntegrationTest : tx.insert(employee) tx.insert(DevEmployeePin(userId = employee.id, pin = pinCode)) tx.insertDaycareAclRow(testDaycare.id, employee.id, UserRole.STAFF) - tx.insertDaycareGroupAcl(testDaycare.id, employee.id, listOf(groupId), now) + tx.syncDaycareGroupAcl(testDaycare.id, employee.id, listOf(groupId), now) tx.insert( DevStaffAttendancePlan( employeeId = employee.id, @@ -438,7 +438,7 @@ class MobileRealtimeStaffAttendanceControllerIntegrationTest : tx.insert(employee) tx.insert(DevEmployeePin(userId = employee.id, pin = pinCode)) tx.insertDaycareAclRow(testDaycare.id, employee.id, UserRole.STAFF) - tx.insertDaycareGroupAcl(testDaycare.id, employee.id, listOf(groupId), now) + tx.syncDaycareGroupAcl(testDaycare.id, employee.id, listOf(groupId), now) tx.insert( DevStaffAttendancePlan( employeeId = employee.id, @@ -464,7 +464,7 @@ class MobileRealtimeStaffAttendanceControllerIntegrationTest : tx.insert(employee) tx.insert(DevEmployeePin(userId = employee.id, pin = pinCode)) tx.insertDaycareAclRow(testDaycare.id, employee.id, UserRole.STAFF) - tx.insertDaycareGroupAcl(testDaycare.id, employee.id, listOf(groupId), now) + tx.syncDaycareGroupAcl(testDaycare.id, employee.id, listOf(groupId), now) tx.insert( DevStaffAttendancePlan( employeeId = employee.id, @@ -488,7 +488,7 @@ class MobileRealtimeStaffAttendanceControllerIntegrationTest : tx.insert(employee) tx.insert(DevEmployeePin(userId = employee.id, pin = pinCode)) tx.insertDaycareAclRow(testDaycare.id, employee.id, UserRole.STAFF) - tx.insertDaycareGroupAcl(testDaycare.id, employee.id, listOf(groupId), now) + tx.syncDaycareGroupAcl(testDaycare.id, employee.id, listOf(groupId), now) tx.insert( DevStaffAttendancePlan( employeeId = employee.id, @@ -531,7 +531,7 @@ class MobileRealtimeStaffAttendanceControllerIntegrationTest : tx.insert(employee) tx.insert(DevEmployeePin(userId = employee.id, pin = pinCode)) tx.insertDaycareAclRow(testDaycare.id, employee.id, UserRole.STAFF) - tx.insertDaycareGroupAcl(testDaycare.id, employee.id, listOf(groupId), now) + tx.syncDaycareGroupAcl(testDaycare.id, employee.id, listOf(groupId), now) tx.insert( DevStaffAttendancePlan( employeeId = employee.id, @@ -570,7 +570,7 @@ class MobileRealtimeStaffAttendanceControllerIntegrationTest : tx.insert(employee) tx.insert(DevEmployeePin(userId = employee.id, pin = pinCode)) tx.insertDaycareAclRow(testDaycare.id, employee.id, UserRole.STAFF) - tx.insertDaycareGroupAcl(testDaycare.id, employee.id, listOf(groupId), now) + tx.syncDaycareGroupAcl(testDaycare.id, employee.id, listOf(groupId), now) tx.insert( DevStaffAttendancePlan( employeeId = employee.id, @@ -596,7 +596,7 @@ class MobileRealtimeStaffAttendanceControllerIntegrationTest : tx.insert(employee) tx.insert(DevEmployeePin(userId = employee.id, pin = pinCode)) tx.insertDaycareAclRow(testDaycare.id, employee.id, UserRole.STAFF) - tx.insertDaycareGroupAcl(testDaycare.id, employee.id, listOf(groupId), now) + tx.syncDaycareGroupAcl(testDaycare.id, employee.id, listOf(groupId), now) tx.insert( DevStaffAttendancePlan( employeeId = employee.id, @@ -629,7 +629,7 @@ class MobileRealtimeStaffAttendanceControllerIntegrationTest : tx.insert(employee) tx.insert(DevEmployeePin(userId = employee.id, pin = pinCode)) tx.insertDaycareAclRow(testDaycare.id, employee.id, UserRole.STAFF) - tx.insertDaycareGroupAcl(testDaycare.id, employee.id, listOf(groupId), now) + tx.syncDaycareGroupAcl(testDaycare.id, employee.id, listOf(groupId), now) tx.insert( DevStaffAttendancePlan( employeeId = employee.id, @@ -671,7 +671,7 @@ class MobileRealtimeStaffAttendanceControllerIntegrationTest : tx.insert(employee) tx.insert(DevEmployeePin(userId = employee.id, pin = pinCode)) tx.insertDaycareAclRow(testDaycare.id, employee.id, UserRole.STAFF) - tx.insertDaycareGroupAcl(testDaycare.id, employee.id, listOf(groupId), now) + tx.syncDaycareGroupAcl(testDaycare.id, employee.id, listOf(groupId), now) tx.insert( DevStaffAttendancePlan( employeeId = employee.id, @@ -708,7 +708,7 @@ class MobileRealtimeStaffAttendanceControllerIntegrationTest : tx.insert(employee) tx.insert(DevEmployeePin(userId = employee.id, pin = pinCode)) tx.insertDaycareAclRow(testDaycare.id, employee.id, UserRole.STAFF) - tx.insertDaycareGroupAcl(testDaycare.id, employee.id, listOf(groupId), now) + tx.syncDaycareGroupAcl(testDaycare.id, employee.id, listOf(groupId), now) tx.insert( DevStaffAttendancePlan( employeeId = employee.id, @@ -757,7 +757,7 @@ class MobileRealtimeStaffAttendanceControllerIntegrationTest : tx.insert(employee) tx.insert(DevEmployeePin(userId = employee.id, pin = pinCode)) tx.insertDaycareAclRow(testDaycare.id, employee.id, UserRole.STAFF) - tx.insertDaycareGroupAcl(testDaycare.id, employee.id, listOf(groupId), now) + tx.syncDaycareGroupAcl(testDaycare.id, employee.id, listOf(groupId), now) tx.insert( DevStaffAttendancePlan( employeeId = employee.id, @@ -792,7 +792,7 @@ class MobileRealtimeStaffAttendanceControllerIntegrationTest : tx.insert(employee) tx.insert(DevEmployeePin(userId = employee.id, pin = pinCode)) tx.insertDaycareAclRow(testDaycare.id, employee.id, UserRole.STAFF) - tx.insertDaycareGroupAcl(testDaycare.id, employee.id, listOf(groupId), now) + tx.syncDaycareGroupAcl(testDaycare.id, employee.id, listOf(groupId), now) tx.insert( DevStaffAttendancePlan( employeeId = employee.id, @@ -828,7 +828,7 @@ class MobileRealtimeStaffAttendanceControllerIntegrationTest : tx.insert(employee) tx.insert(DevEmployeePin(userId = employee.id, pin = pinCode)) tx.insertDaycareAclRow(testDaycare.id, employee.id, UserRole.STAFF) - tx.insertDaycareGroupAcl(testDaycare.id, employee.id, listOf(groupId), now) + tx.syncDaycareGroupAcl(testDaycare.id, employee.id, listOf(groupId), now) tx.insert( DevStaffAttendancePlan( employeeId = employee.id, @@ -873,7 +873,7 @@ class MobileRealtimeStaffAttendanceControllerIntegrationTest : tx.insert(employee) tx.insert(DevEmployeePin(userId = employee.id, pin = pinCode)) tx.insertDaycareAclRow(testDaycare.id, employee.id, UserRole.STAFF) - tx.insertDaycareGroupAcl(testDaycare.id, employee.id, listOf(groupId), now) + tx.syncDaycareGroupAcl(testDaycare.id, employee.id, listOf(groupId), now) tx.insert( DevStaffAttendancePlan( employeeId = employee.id, @@ -908,7 +908,7 @@ class MobileRealtimeStaffAttendanceControllerIntegrationTest : tx.insert(employee) tx.insert(DevEmployeePin(userId = employee.id, pin = pinCode)) tx.insertDaycareAclRow(testDaycare.id, employee.id, UserRole.STAFF) - tx.insertDaycareGroupAcl(testDaycare.id, employee.id, listOf(groupId), now) + tx.syncDaycareGroupAcl(testDaycare.id, employee.id, listOf(groupId), now) tx.insert( DevStaffAttendancePlan( employeeId = employee.id, diff --git a/service/src/integrationTest/kotlin/fi/espoo/evaka/attendance/RealtimeStaffAttendanceControllerIntegrationTest.kt b/service/src/integrationTest/kotlin/fi/espoo/evaka/attendance/RealtimeStaffAttendanceControllerIntegrationTest.kt index 386a17a549c..53c123bd61b 100644 --- a/service/src/integrationTest/kotlin/fi/espoo/evaka/attendance/RealtimeStaffAttendanceControllerIntegrationTest.kt +++ b/service/src/integrationTest/kotlin/fi/espoo/evaka/attendance/RealtimeStaffAttendanceControllerIntegrationTest.kt @@ -10,7 +10,7 @@ import fi.espoo.evaka.shared.GroupId import fi.espoo.evaka.shared.auth.AuthenticatedUser import fi.espoo.evaka.shared.auth.UserRole import fi.espoo.evaka.shared.auth.insertDaycareAclRow -import fi.espoo.evaka.shared.auth.insertDaycareGroupAcl +import fi.espoo.evaka.shared.auth.syncDaycareGroupAcl import fi.espoo.evaka.shared.dev.DevDaycareGroup import fi.espoo.evaka.shared.dev.insert import fi.espoo.evaka.shared.domain.BadRequest @@ -63,7 +63,7 @@ class RealtimeStaffAttendanceControllerIntegrationTest : tx.insertDaycareAclRow(testDaycare2.id, supervisor.id, UserRole.UNIT_SUPERVISOR) tx.insertDaycareAclRow(testDaycare.id, staff.id, UserRole.STAFF) tx.insertDaycareAclRow(testDaycare2.id, staff.id, UserRole.STAFF) - tx.insertDaycareGroupAcl(testDaycare.id, staff.id, listOf(groupId1), now) + tx.syncDaycareGroupAcl(testDaycare.id, staff.id, listOf(groupId1), now) tx.upsertOccupancyCoefficient( OccupancyCoefficientUpsert(testDaycare.id, staff.id, BigDecimal(7)) diff --git a/service/src/integrationTest/kotlin/fi/espoo/evaka/daycare/controllers/UnitAclControllerIntegrationTest.kt b/service/src/integrationTest/kotlin/fi/espoo/evaka/daycare/controllers/UnitAclControllerIntegrationTest.kt index ac5e856db0f..78300687ecd 100644 --- a/service/src/integrationTest/kotlin/fi/espoo/evaka/daycare/controllers/UnitAclControllerIntegrationTest.kt +++ b/service/src/integrationTest/kotlin/fi/espoo/evaka/daycare/controllers/UnitAclControllerIntegrationTest.kt @@ -14,12 +14,10 @@ import fi.espoo.evaka.pis.controllers.PinCode import fi.espoo.evaka.pis.deactivateInactiveEmployees import fi.espoo.evaka.shared.DaycareId import fi.espoo.evaka.shared.EmployeeId -import fi.espoo.evaka.shared.auth.AuthenticatedUser -import fi.espoo.evaka.shared.auth.DaycareAclRow -import fi.espoo.evaka.shared.auth.DaycareAclRowEmployee -import fi.espoo.evaka.shared.auth.UserRole -import fi.espoo.evaka.shared.auth.asUser +import fi.espoo.evaka.shared.GroupId +import fi.espoo.evaka.shared.auth.* import fi.espoo.evaka.shared.dev.DevDaycare +import fi.espoo.evaka.shared.dev.DevDaycareGroup import fi.espoo.evaka.shared.dev.DevEmployee import fi.espoo.evaka.shared.dev.insert import fi.espoo.evaka.shared.domain.EvakaClock @@ -472,6 +470,140 @@ class UnitAclControllerIntegrationTest : FullApplicationTest(resetDbBeforeEach = } } + @Test + fun groupAccessCanBeAddedAndRemoved() { + val clock = + MockEvakaClock(HelsinkiDateTime.of(LocalDate.of(2023, 3, 29), LocalTime.of(8, 37))) + val group2 = + DevDaycareGroup( + daycareId = testDaycare.id, + id = GroupId(UUID.randomUUID()), + name = "Group2", + ) + val unit2Group = + DevDaycareGroup(daycareId = testDaycare2.id, id = GroupId(UUID.randomUUID())) + db.transaction { tx -> + tx.insert(group2) + tx.insert(unit2Group) + tx.insertDaycareAclRow(testDaycare.id, employee.id, UserRole.STAFF) + tx.insertDaycareAclRow(testDaycare2.id, employee.id, UserRole.STAFF) + } + + data class DaycareGroupAcl( + val daycareGroupId: GroupId, + val employeeId: EmployeeId, + val created: HelsinkiDateTime, + val updated: HelsinkiDateTime, + ) + + fun readAllGroupAcls() = + db.read { tx -> + tx.createQuery { sql("SELECT * FROM daycare_group_acl") }.toList() + } + + // add access to two groups in daycare 1 + // daycare 2 has no groups + val moment1 = clock.now() + unitAclController.updateGroupAclWithOccupancyCoefficient( + dbInstance(), + admin, + MockEvakaClock(moment1), + testDaycare.id, + employee.id, + UnitAclController.AclUpdate( + groupIds = listOf(testDaycareGroup.id, group2.id), + hasStaffOccupancyEffect = null, + ), + ) + + val step1Acls = readAllGroupAcls() + assertThat(step1Acls) + .containsExactlyInAnyOrder( + DaycareGroupAcl( + daycareGroupId = testDaycareGroup.id, + employeeId = employee.id, + created = moment1, + updated = moment1, + ), + DaycareGroupAcl( + daycareGroupId = group2.id, + employeeId = employee.id, + created = moment1, + updated = moment1, + ), + ) + + // add access to one group in daycare 2 + // daycare 1 still has two groups + val moment2 = clock.now().plusMinutes(1) + unitAclController.updateGroupAclWithOccupancyCoefficient( + dbInstance(), + admin, + MockEvakaClock(moment2), + testDaycare2.id, + employee.id, + UnitAclController.AclUpdate( + groupIds = listOf(unit2Group.id), + hasStaffOccupancyEffect = null, + ), + ) + + val step2Acls = readAllGroupAcls() + assertThat(step2Acls) + .containsExactlyInAnyOrder( + DaycareGroupAcl( + daycareGroupId = testDaycareGroup.id, + employeeId = employee.id, + created = moment1, + updated = moment1, + ), + DaycareGroupAcl( + daycareGroupId = group2.id, + employeeId = employee.id, + created = moment1, + updated = moment1, + ), + DaycareGroupAcl( + daycareGroupId = unit2Group.id, + employeeId = employee.id, + created = moment2, + updated = moment2, + ), + ) + + // remove access to group 2 in daycare 1 + // daycare 2 still has one group + val moment3 = clock.now().plusMinutes(2) + unitAclController.updateGroupAclWithOccupancyCoefficient( + dbInstance(), + admin, + MockEvakaClock(moment3), + testDaycare.id, + employee.id, + UnitAclController.AclUpdate( + groupIds = listOf(testDaycareGroup.id), + hasStaffOccupancyEffect = null, + ), + ) + + val step3Acls = readAllGroupAcls() + assertThat(step3Acls) + .containsExactlyInAnyOrder( + DaycareGroupAcl( + daycareGroupId = testDaycareGroup.id, + employeeId = employee.id, + created = moment1, + updated = moment1, + ), + DaycareGroupAcl( + daycareGroupId = unit2Group.id, + employeeId = employee.id, + created = moment2, + updated = moment2, + ), + ) + } + @Test fun permanentEmployeeCannotBeUpdatedWithTemporaryEmployeeApi() { val clock = diff --git a/service/src/integrationTest/kotlin/fi/espoo/evaka/messaging/MessageAccountQueriesTest.kt b/service/src/integrationTest/kotlin/fi/espoo/evaka/messaging/MessageAccountQueriesTest.kt index c3ba9c67bb9..6c5ab0367c2 100644 --- a/service/src/integrationTest/kotlin/fi/espoo/evaka/messaging/MessageAccountQueriesTest.kt +++ b/service/src/integrationTest/kotlin/fi/espoo/evaka/messaging/MessageAccountQueriesTest.kt @@ -10,7 +10,7 @@ import fi.espoo.evaka.shared.PersonId import fi.espoo.evaka.shared.auth.AuthenticatedUser import fi.espoo.evaka.shared.auth.UserRole import fi.espoo.evaka.shared.auth.insertDaycareAclRow -import fi.espoo.evaka.shared.auth.insertDaycareGroupAcl +import fi.espoo.evaka.shared.auth.syncDaycareGroupAcl import fi.espoo.evaka.shared.dev.DevCareArea import fi.espoo.evaka.shared.dev.DevDaycare import fi.espoo.evaka.shared.dev.DevDaycareGroup @@ -84,7 +84,7 @@ class MessageAccountQueriesTest : PureJdbiTest(resetDbBeforeEach = true) { it.insertDaycareAclRow(daycareId, supervisorId, UserRole.UNIT_SUPERVISOR) it.insertDaycareAclRow(daycareId, employee1Id, UserRole.STAFF) - it.insertDaycareGroupAcl(daycareId, employee1Id, listOf(groupId), clock.now()) + it.syncDaycareGroupAcl(daycareId, employee1Id, listOf(groupId), clock.now()) // employee2 has no groups it.insertDaycareAclRow(daycareId, employee2Id, UserRole.STAFF) diff --git a/service/src/integrationTest/kotlin/fi/espoo/evaka/messaging/MessageIntegrationTest.kt b/service/src/integrationTest/kotlin/fi/espoo/evaka/messaging/MessageIntegrationTest.kt index 18da877c8ac..aed17a138ed 100644 --- a/service/src/integrationTest/kotlin/fi/espoo/evaka/messaging/MessageIntegrationTest.kt +++ b/service/src/integrationTest/kotlin/fi/espoo/evaka/messaging/MessageIntegrationTest.kt @@ -10,6 +10,7 @@ import fi.espoo.evaka.application.notes.getApplicationNotes import fi.espoo.evaka.application.persistence.daycare.DaycareFormV0 import fi.espoo.evaka.attachment.AttachmentsController import fi.espoo.evaka.daycare.CareType +import fi.espoo.evaka.insertServiceNeedOptions import fi.espoo.evaka.messaging.MessageController.PostMessagePreflightResponse import fi.espoo.evaka.pis.service.insertGuardian import fi.espoo.evaka.serviceneed.ShiftCareType @@ -27,23 +28,9 @@ import fi.espoo.evaka.shared.MessageThreadId import fi.espoo.evaka.shared.ServiceNeedOptionId import fi.espoo.evaka.shared.async.AsyncJob import fi.espoo.evaka.shared.async.AsyncJobRunner -import fi.espoo.evaka.shared.auth.AuthenticatedUser -import fi.espoo.evaka.shared.auth.CitizenAuthLevel -import fi.espoo.evaka.shared.auth.UserRole -import fi.espoo.evaka.shared.auth.insertDaycareAclRow -import fi.espoo.evaka.shared.auth.insertDaycareGroupAcl +import fi.espoo.evaka.shared.auth.* import fi.espoo.evaka.shared.db.Database -import fi.espoo.evaka.shared.dev.DevDaycare -import fi.espoo.evaka.shared.dev.DevDaycareGroup -import fi.espoo.evaka.shared.dev.DevDaycareGroupPlacement -import fi.espoo.evaka.shared.dev.DevEmployee -import fi.espoo.evaka.shared.dev.DevParentship -import fi.espoo.evaka.shared.dev.DevPerson -import fi.espoo.evaka.shared.dev.DevPersonType -import fi.espoo.evaka.shared.dev.DevPlacement -import fi.espoo.evaka.shared.dev.DevServiceNeed -import fi.espoo.evaka.shared.dev.insert -import fi.espoo.evaka.shared.dev.insertTestApplication +import fi.espoo.evaka.shared.dev.* import fi.espoo.evaka.shared.domain.* import fi.espoo.evaka.shared.security.PilotFeature import fi.espoo.evaka.test.validDaycareApplication @@ -276,7 +263,7 @@ class MessageIntegrationTest : FullApplicationTest(resetDbBeforeEach = true) { employee1Account = tx.upsertEmployeeMessageAccount(employee1.id) tx.insertDaycareAclRow(testDaycare.id, employee1.id, UserRole.UNIT_SUPERVISOR) - tx.insertDaycareGroupAcl( + tx.syncDaycareGroupAcl( testDaycare.id, employee1.id, listOf(groupId1, groupId2), @@ -1666,7 +1653,7 @@ class MessageIntegrationTest : FullApplicationTest(resetDbBeforeEach = true) { val employee = DevEmployee(firstName = "New", lastName = "Staff") tx.insert(employee) tx.insertDaycareAclRow(testDaycare.id, employee.id, userRole) - tx.insertDaycareGroupAcl(testDaycare.id, employee.id, listOf(groupId1), now) + tx.syncDaycareGroupAcl(testDaycare.id, employee.id, listOf(groupId1), now) employee.user } } diff --git a/service/src/integrationTest/kotlin/fi/espoo/evaka/pis/InactiveEmployeesRoleResetIntegrationTest.kt b/service/src/integrationTest/kotlin/fi/espoo/evaka/pis/InactiveEmployeesRoleResetIntegrationTest.kt index ae42913537e..859947d928f 100644 --- a/service/src/integrationTest/kotlin/fi/espoo/evaka/pis/InactiveEmployeesRoleResetIntegrationTest.kt +++ b/service/src/integrationTest/kotlin/fi/espoo/evaka/pis/InactiveEmployeesRoleResetIntegrationTest.kt @@ -12,7 +12,7 @@ import fi.espoo.evaka.shared.EmployeeId import fi.espoo.evaka.shared.GroupId import fi.espoo.evaka.shared.auth.UserRole import fi.espoo.evaka.shared.auth.insertDaycareAclRow -import fi.espoo.evaka.shared.auth.insertDaycareGroupAcl +import fi.espoo.evaka.shared.auth.syncDaycareGroupAcl import fi.espoo.evaka.shared.db.Database import fi.espoo.evaka.shared.dev.DevCareArea import fi.espoo.evaka.shared.dev.DevDaycare @@ -156,7 +156,7 @@ class InactiveEmployeesRoleResetIntegrationTest : PureJdbiTest(resetDbBeforeEach role = UserRole.STAFF, ) it.setDaycareAclUpdated(unitId, employeeId, firstOfAugust2021.minusDays(1000)) - it.insertDaycareGroupAcl( + it.syncDaycareGroupAcl( daycareId = unitId, employeeId = employeeId, groupIds = listOf(groupId), diff --git a/service/src/main/kotlin/fi/espoo/evaka/daycare/UnitAcl.kt b/service/src/main/kotlin/fi/espoo/evaka/daycare/UnitAcl.kt index 665f9519da1..9c1d98820ef 100644 --- a/service/src/main/kotlin/fi/espoo/evaka/daycare/UnitAcl.kt +++ b/service/src/main/kotlin/fi/espoo/evaka/daycare/UnitAcl.kt @@ -7,10 +7,7 @@ package fi.espoo.evaka.daycare import fi.espoo.evaka.messaging.deactivateEmployeeMessageAccount import fi.espoo.evaka.shared.DaycareId import fi.espoo.evaka.shared.EmployeeId -import fi.espoo.evaka.shared.auth.UserRole -import fi.espoo.evaka.shared.auth.clearDaycareGroupAcl -import fi.espoo.evaka.shared.auth.deleteDaycareAclRow -import fi.espoo.evaka.shared.auth.hasAnyDaycareAclRow +import fi.espoo.evaka.shared.auth.* import fi.espoo.evaka.shared.db.Database fun removeDaycareAclForRole( @@ -19,7 +16,7 @@ fun removeDaycareAclForRole( employeeId: EmployeeId, role: UserRole, ) { - tx.clearDaycareGroupAcl(daycareId, employeeId) + tx.syncDaycareGroupAcl(daycareId, employeeId, emptyList()) tx.deleteDaycareAclRow(daycareId, employeeId, role) deactivatePersonalMessageAccountIfNeeded(tx, employeeId) } diff --git a/service/src/main/kotlin/fi/espoo/evaka/daycare/controllers/UnitAclController.kt b/service/src/main/kotlin/fi/espoo/evaka/daycare/controllers/UnitAclController.kt index 485b9017c9b..c6172bc6e7f 100644 --- a/service/src/main/kotlin/fi/espoo/evaka/daycare/controllers/UnitAclController.kt +++ b/service/src/main/kotlin/fi/espoo/evaka/daycare/controllers/UnitAclController.kt @@ -26,15 +26,7 @@ import fi.espoo.evaka.pis.upsertPinCode import fi.espoo.evaka.shared.DaycareId import fi.espoo.evaka.shared.EmployeeId import fi.espoo.evaka.shared.GroupId -import fi.espoo.evaka.shared.auth.AuthenticatedUser -import fi.espoo.evaka.shared.auth.DaycareAclRow -import fi.espoo.evaka.shared.auth.UserRole -import fi.espoo.evaka.shared.auth.clearDaycareGroupAcl -import fi.espoo.evaka.shared.auth.deleteDaycareAclRow -import fi.espoo.evaka.shared.auth.getDaycareAclRows -import fi.espoo.evaka.shared.auth.hasAnyDaycareAclRow -import fi.espoo.evaka.shared.auth.insertDaycareAclRow -import fi.espoo.evaka.shared.auth.insertDaycareGroupAcl +import fi.espoo.evaka.shared.auth.* import fi.espoo.evaka.shared.db.Database import fi.espoo.evaka.shared.domain.* import fi.espoo.evaka.shared.security.AccessControl @@ -230,8 +222,7 @@ class UnitAclController(private val accessControl: AccessControl) { daycareId, ) validateIsPermanentEmployee(tx, employeeId) - tx.clearDaycareGroupAcl(daycareId, employeeId) - tx.insertDaycareGroupAcl(daycareId, employeeId, it, clock.now()) + tx.syncDaycareGroupAcl(daycareId, employeeId, it, clock.now()) } val occupancyCoefficientId = @@ -284,7 +275,6 @@ class UnitAclController(private val accessControl: AccessControl) { val roleAction = getRoleAddAction(aclInfo.role) accessControl.requirePermissionFor(tx, user, clock, roleAction, daycareId) validateIsPermanentEmployee(tx, employeeId) - tx.clearDaycareGroupAcl(daycareId, employeeId) tx.insertDaycareAclRow(daycareId, employeeId, aclInfo.role) tx.upsertEmployeeMessageAccount(employeeId) aclInfo.update.groupIds?.let { @@ -295,7 +285,7 @@ class UnitAclController(private val accessControl: AccessControl) { Action.Unit.UPDATE_STAFF_GROUP_ACL, daycareId, ) - tx.insertDaycareGroupAcl(daycareId, employeeId, it, clock.now()) + tx.syncDaycareGroupAcl(daycareId, employeeId, it, clock.now()) } val occupancyCoefficientId = aclInfo.update.hasStaffOccupancyEffect?.let { @@ -559,9 +549,8 @@ class UnitAclController(private val accessControl: AccessControl) { throw Forbidden("All groups must be in unit") } - tx.clearDaycareGroupAcl(unitId, employeeId) tx.insertDaycareAclRow(unitId, employeeId, UserRole.STAFF) - tx.insertDaycareGroupAcl(unitId, employeeId, input.groupIds.toList(), now) + tx.syncDaycareGroupAcl(unitId, employeeId, input.groupIds, now) tx.upsertEmployeeMessageAccount(employeeId) tx.upsertOccupancyCoefficient( @@ -596,7 +585,7 @@ class UnitAclController(private val accessControl: AccessControl) { unitId: DaycareId, employee: Employee, ) { - tx.clearDaycareGroupAcl(unitId, employee.id) + tx.syncDaycareGroupAcl(unitId, employee.id, emptyList()) tx.deleteDaycareAclRow(unitId, employee.id, UserRole.STAFF) if (!tx.hasAnyDaycareAclRow(employee.id)) { tx.deactivateEmployeeMessageAccount(employee.id) diff --git a/service/src/main/kotlin/fi/espoo/evaka/shared/auth/AclQueries.kt b/service/src/main/kotlin/fi/espoo/evaka/shared/auth/AclQueries.kt index 888303bc3f2..9af4a08341a 100644 --- a/service/src/main/kotlin/fi/espoo/evaka/shared/auth/AclQueries.kt +++ b/service/src/main/kotlin/fi/espoo/evaka/shared/auth/AclQueries.kt @@ -106,31 +106,37 @@ AND role = ${bind(role)} } .execute() -fun Database.Transaction.clearDaycareGroupAcl(daycareId: DaycareId, employeeId: EmployeeId) = +fun Database.Transaction.syncDaycareGroupAcl( + daycareId: DaycareId, + employeeId: EmployeeId, + groupIds: Collection, + now: HelsinkiDateTime = HelsinkiDateTime.now(), +) { + // Delete rows that are not in the supplied groupIds createUpdate { sql( """ DELETE FROM daycare_group_acl WHERE employee_id = ${bind(employeeId)} -AND daycare_group_id IN (SELECT id FROM daycare_group WHERE daycare_id = ${bind(daycareId)}) +AND daycare_group_id IN ( + SELECT id FROM daycare_group WHERE daycare_id = ${bind(daycareId)} +) +AND daycare_group_id <> ALL (${bind(groupIds)}) """ ) } .execute() -fun Database.Transaction.insertDaycareGroupAcl( - daycareId: DaycareId, - employeeId: EmployeeId, - groupIds: Collection, - now: HelsinkiDateTime, -) = + // Insert rows that are in the supplied groupIds and do not already exist executeBatch(groupIds) { sql( """ -INSERT INTO daycare_group_acl +INSERT INTO daycare_group_acl (daycare_group_id, employee_id, created, updated) SELECT id, ${bind(employeeId)}, ${bind(now)}, ${bind(now)} FROM daycare_group WHERE id = ${bind { it }} AND daycare_id = ${bind(daycareId)} +ON CONFLICT (daycare_group_id, employee_id) DO NOTHING """ ) } +} diff --git a/service/src/main/kotlin/fi/espoo/evaka/shared/dev/DataInitializers.kt b/service/src/main/kotlin/fi/espoo/evaka/shared/dev/DataInitializers.kt index 5861b9cc7be..f32fede8cd1 100755 --- a/service/src/main/kotlin/fi/espoo/evaka/shared/dev/DataInitializers.kt +++ b/service/src/main/kotlin/fi/espoo/evaka/shared/dev/DataInitializers.kt @@ -88,7 +88,7 @@ import fi.espoo.evaka.shared.VoucherValueDecisionId import fi.espoo.evaka.shared.auth.AuthenticatedUser import fi.espoo.evaka.shared.auth.UserRole import fi.espoo.evaka.shared.auth.insertDaycareAclRow -import fi.espoo.evaka.shared.auth.insertDaycareGroupAcl +import fi.espoo.evaka.shared.auth.syncDaycareGroupAcl import fi.espoo.evaka.shared.db.Database import fi.espoo.evaka.shared.domain.DateRange import fi.espoo.evaka.shared.domain.FiniteDateRange @@ -294,7 +294,7 @@ RETURNING id insertDaycareAclRow(daycareId, employeeId, role) } groupAcl.forEach { (daycareId, groups) -> - insertDaycareGroupAcl(daycareId, employeeId, groups, now) + syncDaycareGroupAcl(daycareId, employeeId, groups, now) } }