Skip to content

Commit 1d54b2e

Browse files
committed
fix: migrate notifications to Spring Boot 3
1 parent 8823857 commit 1d54b2e

File tree

46 files changed

+720
-543
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

46 files changed

+720
-543
lines changed

backend/api/src/main/kotlin/io/tolgee/api/v2/controllers/notifications/NotificationPreferencesController.kt

Lines changed: 21 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -59,17 +59,20 @@ class NotificationPreferencesController(
5959
fun updateGlobalPreferences(
6060
@RequestBody @Validated preferencesDto: NotificationPreferencesDto,
6161
): NotificationPreferencesDto {
62-
val updated = notificationPreferencesService.setPreferencesOfUser(
63-
authenticationFacade.authenticatedUser.id,
64-
preferencesDto,
65-
)
62+
val updated =
63+
notificationPreferencesService.setPreferencesOfUser(
64+
authenticationFacade.authenticatedUser.id,
65+
preferencesDto,
66+
)
6667

6768
return NotificationPreferencesDto.fromEntity(updated)
6869
}
6970

7071
@GetMapping("/project/{id}")
7172
@Operation(summary = "Fetch the notification preferences of the current user for a specific project")
72-
fun getPerProjectPreferences(@PathVariable("id") id: Long): NotificationPreferencesDto {
73+
fun getPerProjectPreferences(
74+
@PathVariable("id") id: Long,
75+
): NotificationPreferencesDto {
7376
return notificationPreferencesService.getProjectPreferences(
7477
authenticationFacade.authenticatedUser.id,
7578
id,
@@ -82,19 +85,22 @@ class NotificationPreferencesController(
8285
@PathVariable("id") id: Long,
8386
@RequestBody @Validated preferencesDto: NotificationPreferencesDto,
8487
): NotificationPreferencesDto {
85-
val updated = notificationPreferencesService.setProjectPreferencesOfUser(
86-
authenticationFacade.authenticatedUser.id,
87-
id,
88-
preferencesDto,
89-
)
88+
val updated =
89+
notificationPreferencesService.setProjectPreferencesOfUser(
90+
authenticationFacade.authenticatedUser.id,
91+
id,
92+
preferencesDto,
93+
)
9094

9195
return NotificationPreferencesDto.fromEntity(updated)
9296
}
9397

9498
@DeleteMapping("/project/{id}")
9599
@ResponseStatus(HttpStatus.NO_CONTENT)
96100
@Operation(summary = "Delete the notification preferences of the current user for a specific project")
97-
fun deletePerProjectPreferences(@PathVariable("id") id: Long) {
101+
fun deletePerProjectPreferences(
102+
@PathVariable("id") id: Long,
103+
) {
98104
notificationPreferencesService.deleteProjectPreferencesOfUser(
99105
authenticationFacade.authenticatedUser.id,
100106
id,
@@ -103,15 +109,17 @@ class NotificationPreferencesController(
103109

104110
@PostMapping("/project/{id}/subscribe")
105111
@Operation(summary = "Subscribe to notifications for a given project")
106-
fun subscribeToProject(@PathVariable("id") id: Long): ResponseEntity<String> {
112+
fun subscribeToProject(
113+
@PathVariable("id") id: Long,
114+
): ResponseEntity<String> {
107115
return ResponseEntity(
108116
"Coming soon! Please see https://github.com/tolgee/tolgee-platform/issues/1360 for progress on this. :D",
109117
HttpHeaders().also {
110118
@Suppress("UastIncorrectHttpHeaderInspection")
111119
it.add(
112120
"x-hey-curious-reader",
113121
"oh hey there, didn't expect you here... " +
114-
"if you're here, might as well join us! https://tolgee.io/career"
122+
"if you're here, might as well join us! https://tolgee.io/career",
115123
)
116124
},
117125
HttpStatus.NOT_IMPLEMENTED,

backend/api/src/main/kotlin/io/tolgee/api/v2/controllers/notifications/NotificationsController.kt

Lines changed: 19 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ import io.tolgee.hateoas.notifications.UserNotificationModelAssembler
2323
import io.tolgee.notifications.NotificationStatus
2424
import io.tolgee.notifications.UserNotificationService
2525
import io.tolgee.security.authentication.AuthenticationFacade
26-
import org.springdoc.api.annotations.ParameterObject
26+
import org.springdoc.core.annotations.ParameterObject
2727
import org.springframework.data.domain.Pageable
2828
import org.springframework.http.HttpStatus
2929
import org.springframework.web.bind.annotation.GetMapping
@@ -48,19 +48,22 @@ class NotificationsController(
4848
@RequestParam("status", defaultValue = "UNREAD,READ") status: Set<NotificationStatus>,
4949
@ParameterObject pageable: Pageable,
5050
): List<UserNotificationModel> {
51-
val notifications = userNotificationService.findNotificationsOfUserFilteredPaged(
52-
authenticationFacade.authenticatedUser.id,
53-
status,
54-
pageable,
55-
)
51+
val notifications =
52+
userNotificationService.findNotificationsOfUserFilteredPaged(
53+
authenticationFacade.authenticatedUser.id,
54+
status,
55+
pageable,
56+
)
5657

5758
return notifications.map { userNotificationModelAssembler.toModel(it) }
5859
}
5960

6061
@PostMapping("/mark-as-read")
6162
@ResponseStatus(HttpStatus.NO_CONTENT)
6263
@Operation(summary = "Marks a given set of notifications as read.")
63-
fun markNotificationsAsRead(@RequestBody notifications: List<Long>) {
64+
fun markNotificationsAsRead(
65+
@RequestBody notifications: List<Long>,
66+
) {
6467
userNotificationService.markAsRead(
6568
authenticationFacade.authenticatedUser.id,
6669
notifications,
@@ -77,7 +80,9 @@ class NotificationsController(
7780
@PostMapping("/mark-as-unread")
7881
@ResponseStatus(HttpStatus.NO_CONTENT)
7982
@Operation(summary = "Marks a given set of notifications as unread.")
80-
fun markNotificationsAsUnread(@RequestBody notifications: List<Long>) {
83+
fun markNotificationsAsUnread(
84+
@RequestBody notifications: List<Long>,
85+
) {
8186
userNotificationService.markAsUnread(
8287
authenticationFacade.authenticatedUser.id,
8388
notifications,
@@ -87,7 +92,9 @@ class NotificationsController(
8792
@PostMapping("/mark-as-done")
8893
@ResponseStatus(HttpStatus.NO_CONTENT)
8994
@Operation(summary = "Marks a given set of notifications as done.")
90-
fun markNotificationsAsDone(@RequestBody notifications: List<Long>) {
95+
fun markNotificationsAsDone(
96+
@RequestBody notifications: List<Long>,
97+
) {
9198
userNotificationService.markAsDone(
9299
authenticationFacade.authenticatedUser.id,
93100
notifications,
@@ -104,7 +111,9 @@ class NotificationsController(
104111
@PostMapping("/unmark-as-done")
105112
@ResponseStatus(HttpStatus.NO_CONTENT)
106113
@Operation(summary = "Un-marks a given set of notifications as done.")
107-
fun unmarkNotificationsAsDone(@RequestBody notifications: Collection<Long>) {
114+
fun unmarkNotificationsAsDone(
115+
@RequestBody notifications: Collection<Long>,
116+
) {
108117
userNotificationService.unmarkAsDone(
109118
authenticationFacade.authenticatedUser.id,
110119
notifications,

backend/api/src/main/kotlin/io/tolgee/hateoas/notifications/UserNotificationModelAssembler.kt

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -35,15 +35,17 @@ class UserNotificationModelAssembler(
3535
private val batchJobModelAssembler: BatchJobModelAssembler,
3636
private val applicationContext: ApplicationContext,
3737
) : RepresentationModelAssemblerSupport<UserNotification, UserNotificationModel>(
38-
NotificationsController::class.java, UserNotificationModel::class.java
39-
) {
38+
NotificationsController::class.java,
39+
UserNotificationModel::class.java,
40+
) {
4041
override fun toModel(entity: UserNotification): UserNotificationModel {
4142
val project = entity.project?.let { simpleProjectModelAssembler.toModel(it) }
4243
val modifiedEntities = assembleEntityChanges(entity.modifiedEntities).ifEmpty { null }
43-
val batchJob = entity.batchJob?.let {
44-
val view = batchJobService.getView(it)
45-
batchJobModelAssembler.toModel(view)
46-
}
44+
val batchJob =
45+
entity.batchJob?.let {
46+
val view = batchJobService.getView(it)
47+
batchJobModelAssembler.toModel(view)
48+
}
4749

4850
return UserNotificationModel(
4951
id = entity.id,
@@ -58,10 +60,11 @@ class UserNotificationModelAssembler(
5860
}
5961

6062
private fun assembleEntityChanges(modifiedEntities: List<ActivityModifiedEntity>): List<SimpleModifiedEntityView> {
61-
val provider = ModifiedEntitiesViewProvider(
62-
applicationContext,
63-
modifiedEntities
64-
)
63+
val provider =
64+
ModifiedEntitiesViewProvider(
65+
applicationContext,
66+
modifiedEntities,
67+
)
6568

6669
return provider.getSimple()
6770
}

backend/api/src/main/kotlin/io/tolgee/hateoas/project/ProjectModelAssembler.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ class ProjectModelAssembler(
4949
avatar = avatarService.getAvatarLinks(view.avatarHash),
5050
organizationRole = view.organizationRole,
5151
organizationOwner = view.organizationOwner.let { simpleOrganizationModelAssembler.toModel(it) },
52-
baseLanguage = baseLanguage?.let { languageModelAssembler.toModel(LanguageDto.fromEntity(it, it.id)) },
52+
baseLanguage = baseLanguage.let { languageModelAssembler.toModel(LanguageDto.fromEntity(it, it.id)) },
5353
directPermission = view.directPermission?.let { permissionModelAssembler.toModel(it) },
5454
computedPermission = computedPermissionModelAssembler.toModel(computedPermissions),
5555
).add(link).also { model ->

backend/app/src/test/kotlin/io/tolgee/notifications/AbstractNotificationTest.kt

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -55,11 +55,12 @@ abstract class AbstractNotificationTest : AuthorizedControllerTest() {
5555

5656
entityManager.refresh(it.arguments[0])
5757

58+
println("Dispatched!")
5859
// Wait a bit to make sure everything's *actually* persisted
5960
// Kind of an ugly way to synchronize everything, but it is what it is
6061
taskScheduler.schedule(
6162
{ semaphore.release() },
62-
Date().addMilliseconds(100)
63+
Date().addMilliseconds(100),
6364
)
6465

6566
it.arguments[0]
@@ -76,7 +77,7 @@ abstract class AbstractNotificationTest : AuthorizedControllerTest() {
7677
// Kind of an ugly way to synchronize everything, but it is what it is
7778
taskScheduler.schedule(
7879
{ semaphore.release(list.size) },
79-
Date().addMilliseconds(100)
80+
Date().addMilliseconds(100),
8081
)
8182

8283
it.arguments[0]

backend/app/src/test/kotlin/io/tolgee/notifications/RemappedNotificationsTest.kt

Lines changed: 38 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -43,20 +43,27 @@ class RemappedNotificationsTest : AbstractNotificationTest() {
4343
fun `it does properly remap imports to key and translation notifications`() {
4444
performAuthMultipart(
4545
url = "/v2/projects/${testData.project1.id}/import",
46-
files = listOf(
47-
MockMultipartFile(
48-
"files", "en.json", "application/json",
49-
"""{"new-key1": "New string 1", "new-key2": "New string 2"}""".toByteArray()
46+
files =
47+
listOf(
48+
MockMultipartFile(
49+
"files",
50+
"en.json",
51+
"application/json",
52+
"""{"new-key1": "New string 1", "new-key2": "New string 2"}""".toByteArray(),
53+
),
54+
MockMultipartFile(
55+
"files",
56+
"fr.json",
57+
"application/json",
58+
"""{"some-key": "Updated", "new-key1": "New FR string 1", "new-key2": "New FR string 2"}""".toByteArray(),
59+
),
60+
MockMultipartFile(
61+
"files",
62+
"cs.json",
63+
"application/json",
64+
"""{"new-key1": "New CZ string 1", "new-key2": "New CZ string 2"}""".toByteArray(),
65+
),
5066
),
51-
MockMultipartFile(
52-
"files", "fr.json", "application/json",
53-
"""{"some-key": "Updated", "new-key1": "New FR string 1", "new-key2": "New FR string 2"}""".toByteArray()
54-
),
55-
MockMultipartFile(
56-
"files", "cs.json", "application/json",
57-
"""{"new-key1": "New CZ string 1", "new-key2": "New CZ string 2"}""".toByteArray()
58-
)
59-
)
6067
).andIsOk
6168

6269
performAuthPut("/v2/projects/${testData.project1.id}/import/apply?forceMode=OVERRIDE", null).andIsOk
@@ -155,26 +162,31 @@ class RemappedNotificationsTest : AbstractNotificationTest() {
155162

156163
@Test
157164
fun `it does remap complex key edits to relevant notification types`() {
158-
val screenshotId = performAuthMultipart(
159-
url = "/v2/image-upload",
160-
files = listOf(
161-
MockMultipartFile(
162-
"image", "image.png", "image/png",
163-
generateImage(100, 100).inputStream.readAllBytes()
164-
)
165-
)
166-
).andIsCreated.andGetContentAsJsonMap["id"].let { (it as Int).toLong() }
165+
val screenshotId =
166+
performAuthMultipart(
167+
url = "/v2/image-upload",
168+
files =
169+
listOf(
170+
MockMultipartFile(
171+
"image",
172+
"image.png",
173+
"image/png",
174+
generateImage(100, 100).inputStream.readAllBytes(),
175+
),
176+
),
177+
).andIsCreated.andGetContentAsJsonMap["id"].let { (it as Int).toLong() }
167178

168179
performAuthPut(
169180
"/v2/projects/${testData.project1.id}/keys/${testData.keyProject1.id}/complex-update",
170181
ComplexEditKeyDto(
171182
name = "new-name",
172183
namespace = "new-namespace",
173184
translations = mapOf("en" to "New EN string", "fr" to "New FR string"),
174-
screenshotsToAdd = listOf(
175-
KeyScreenshotDto(uploadedImageId = screenshotId)
176-
)
177-
)
185+
screenshotsToAdd =
186+
listOf(
187+
KeyScreenshotDto(uploadedImageId = screenshotId),
188+
),
189+
),
178190
).andIsOk
179191

180192
waitUntilUserNotificationDispatch(25)

backend/app/src/test/kotlin/io/tolgee/notifications/UserNotificationDebounceTest.kt

Lines changed: 17 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
package io.tolgee.notifications
1818

1919
import io.tolgee.development.testDataBuilder.data.NotificationsTestData
20-
import io.tolgee.dtos.request.LanguageDto
20+
import io.tolgee.dtos.request.LanguageRequest
2121
import io.tolgee.dtos.request.key.CreateKeyDto
2222
import io.tolgee.dtos.request.translation.comment.TranslationCommentWithLangKeyDto
2323
import io.tolgee.fixtures.andIsCreated
@@ -41,27 +41,28 @@ class UserNotificationDebounceTest : AbstractNotificationTest() {
4141
fun `it debounces notifications of the same type`() {
4242
performAuthPost(
4343
"/v2/projects/${testData.calmProject.id}/keys/create",
44-
CreateKeyDto(name = "test-key-1")
44+
CreateKeyDto(name = "test-key-1"),
4545
).andIsCreated
4646

4747
waitUntilUserNotificationDispatch()
4848
userNotificationRepository.findAllByRecipient(testData.alice).assert.hasSize(1)
4949

5050
performAuthPost(
5151
"/v2/projects/${testData.calmProject.id}/keys/create",
52-
CreateKeyDto(name = "test-key-2")
52+
CreateKeyDto(name = "test-key-2"),
5353
).andIsCreated
5454

5555
waitUntilUserNotificationDispatch()
5656
userNotificationRepository.findAllByRecipient(testData.alice).assert.hasSize(1)
5757

5858
performAuthPost(
5959
url = "/v2/projects/${testData.calmProject.id}/languages",
60-
content = LanguageDto(
61-
name = "Meow",
62-
originalName = "meow",
63-
tag = "meow-en",
64-
)
60+
content =
61+
LanguageRequest(
62+
name = "Meow",
63+
originalName = "meow",
64+
tag = "meow-en",
65+
),
6566
).andIsOk
6667

6768
waitUntilUserNotificationDispatch()
@@ -72,15 +73,15 @@ class UserNotificationDebounceTest : AbstractNotificationTest() {
7273
fun `it only debounces notifications within the same project`() {
7374
performAuthPost(
7475
"/v2/projects/${testData.calmProject.id}/keys/create",
75-
CreateKeyDto(name = "test-key-1")
76+
CreateKeyDto(name = "test-key-1"),
7677
).andIsCreated
7778

7879
waitUntilUserNotificationDispatch()
7980
userNotificationRepository.findAllByRecipient(testData.alice).assert.hasSize(1)
8081

8182
performAuthPost(
8283
"/v2/projects/${testData.project2.id}/keys/create",
83-
CreateKeyDto(name = "test-key-2")
84+
CreateKeyDto(name = "test-key-2"),
8485
).andIsCreated
8586

8687
waitUntilUserNotificationDispatch()
@@ -94,8 +95,8 @@ class UserNotificationDebounceTest : AbstractNotificationTest() {
9495
TranslationCommentWithLangKeyDto(
9596
keyId = testData.keyCalmProject.id,
9697
languageId = testData.keyCalmEnTranslation.language.id,
97-
text = "This is a test"
98-
)
98+
text = "This is a test",
99+
),
99100
).andIsCreated
100101

101102
waitUntilUserNotificationDispatch()
@@ -106,8 +107,8 @@ class UserNotificationDebounceTest : AbstractNotificationTest() {
106107
TranslationCommentWithLangKeyDto(
107108
keyId = testData.keyCalmProject.id,
108109
languageId = testData.keyCalmEnTranslation.language.id,
109-
text = "This is a test 2"
110-
)
110+
text = "This is a test 2",
111+
),
111112
).andIsCreated
112113

113114
waitUntilUserNotificationDispatch()
@@ -118,8 +119,8 @@ class UserNotificationDebounceTest : AbstractNotificationTest() {
118119
TranslationCommentWithLangKeyDto(
119120
keyId = testData.keyCalmProject.id,
120121
languageId = testData.calmProjectFr.id,
121-
text = "This is a test"
122-
)
122+
text = "This is a test",
123+
),
123124
).andIsCreated
124125

125126
waitUntilUserNotificationDispatch()

0 commit comments

Comments
 (0)