-
-
Notifications
You must be signed in to change notification settings - Fork 220
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Partially implements #2577.
- Loading branch information
Showing
24 changed files
with
592 additions
and
13 deletions.
There are no files selected for viewing
44 changes: 44 additions & 0 deletions
44
backend/api/src/main/kotlin/io/tolgee/api/v2/controllers/NotificationController.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
package io.tolgee.api.v2.controllers | ||
|
||
import io.swagger.v3.oas.annotations.Operation | ||
import io.swagger.v3.oas.annotations.tags.Tag | ||
import io.tolgee.hateoas.notification.NotificationEnhancer | ||
import io.tolgee.hateoas.notification.NotificationModel | ||
import io.tolgee.hateoas.notification.NotificationModelAssembler | ||
import io.tolgee.model.Notification | ||
import io.tolgee.security.authentication.AllowApiAccess | ||
import io.tolgee.security.authentication.AuthenticationFacade | ||
import io.tolgee.service.notification.NotificationService | ||
import org.springdoc.core.annotations.ParameterObject | ||
import org.springframework.data.domain.Pageable | ||
import org.springframework.data.web.PagedResourcesAssembler | ||
import org.springframework.hateoas.PagedModel | ||
import org.springframework.web.bind.annotation.CrossOrigin | ||
import org.springframework.web.bind.annotation.GetMapping | ||
import org.springframework.web.bind.annotation.RequestMapping | ||
import org.springframework.web.bind.annotation.RestController | ||
|
||
@RestController | ||
@CrossOrigin(origins = ["*"]) | ||
@RequestMapping( | ||
value = [ | ||
"/v2/notifications", | ||
], | ||
) | ||
@Tag(name = "Notifications", description = "Manipulates notifications") | ||
class NotificationController( | ||
private val notificationService: NotificationService, | ||
private val authenticationFacade: AuthenticationFacade, | ||
private val enhancers: List<NotificationEnhancer>, | ||
private val pagedResourcesAssembler: PagedResourcesAssembler<Notification>, | ||
) { | ||
@GetMapping | ||
@Operation(summary = "Gets notifications of the currently logged in user, newest is first.") | ||
@AllowApiAccess | ||
fun getNotifications( | ||
@ParameterObject pageable: Pageable, | ||
): PagedModel<NotificationModel> { | ||
val notifications = notificationService.getNotifications(authenticationFacade.authenticatedUser.id, pageable) | ||
return pagedResourcesAssembler.toModel(notifications, NotificationModelAssembler(enhancers, notifications)) | ||
} | ||
} |
15 changes: 15 additions & 0 deletions
15
backend/api/src/main/kotlin/io/tolgee/hateoas/notification/NotificationEnhancer.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
package io.tolgee.hateoas.notification | ||
|
||
import io.tolgee.model.Notification | ||
|
||
/** | ||
* Dynamic component enhancing notifications by additional information if eligible, | ||
* e.g. adding linked task. | ||
*/ | ||
fun interface NotificationEnhancer { | ||
/** | ||
* Takes list of input Notification and output NotificationModel. | ||
* It iterates over the pairs and alters the output NotificationModel by enhancing it of the new information. | ||
*/ | ||
fun enhanceNotifications(notifications: Map<Notification, NotificationModel>) | ||
} |
12 changes: 12 additions & 0 deletions
12
backend/api/src/main/kotlin/io/tolgee/hateoas/notification/NotificationModel.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
package io.tolgee.hateoas.notification | ||
|
||
import io.tolgee.hateoas.project.SimpleProjectModel | ||
import io.tolgee.hateoas.task.TaskModel | ||
import org.springframework.hateoas.RepresentationModel | ||
import java.io.Serializable | ||
|
||
data class NotificationModel( | ||
val id: Long, | ||
var project: SimpleProjectModel? = null, | ||
var linkedTask: TaskModel? = null, | ||
) : RepresentationModel<NotificationModel>(), Serializable |
32 changes: 32 additions & 0 deletions
32
backend/api/src/main/kotlin/io/tolgee/hateoas/notification/NotificationModelAssembler.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
package io.tolgee.hateoas.notification | ||
|
||
import io.tolgee.api.v2.controllers.NotificationController | ||
import io.tolgee.model.Notification | ||
import org.springframework.data.domain.Page | ||
import org.springframework.hateoas.server.mvc.RepresentationModelAssemblerSupport | ||
|
||
class NotificationModelAssembler( | ||
private val enhancers: List<NotificationEnhancer>, | ||
private val notifications: Page<Notification>, | ||
) : RepresentationModelAssemblerSupport<Notification, NotificationModel>( | ||
NotificationController::class.java, | ||
NotificationModel::class.java, | ||
) { | ||
private val prefetchedNotifications = | ||
run { | ||
val notificationsWithModel = | ||
notifications.content.associateWith { notification -> | ||
NotificationModel( | ||
id = notification.id, | ||
) | ||
} | ||
enhancers.forEach { enhancer -> | ||
enhancer.enhanceNotifications(notificationsWithModel) | ||
} | ||
notificationsWithModel | ||
} | ||
|
||
override fun toModel(view: Notification): NotificationModel { | ||
return prefetchedNotifications[view] ?: throw IllegalStateException("Notification $view was not found") | ||
} | ||
} |
21 changes: 21 additions & 0 deletions
21
backend/api/src/main/kotlin/io/tolgee/hateoas/notification/ProjectNotificationEnhancer.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
package io.tolgee.hateoas.notification | ||
|
||
import io.tolgee.hateoas.project.SimpleProjectModelAssembler | ||
import io.tolgee.model.Notification | ||
import io.tolgee.service.project.ProjectService | ||
import org.springframework.stereotype.Component | ||
|
||
@Component | ||
class ProjectNotificationEnhancer( | ||
private val projectService: ProjectService, | ||
private val simpleProjectModelAssembler: SimpleProjectModelAssembler, | ||
) : NotificationEnhancer { | ||
override fun enhanceNotifications(notifications: Map<Notification, NotificationModel>) { | ||
val projectIds = notifications.mapNotNull { (source, _) -> source.project?.id }.distinct() | ||
val projects = projectService.findAll(projectIds).associateBy { it.id } | ||
|
||
notifications.forEach { (source, target) -> | ||
target.project = source.project?.id.let { projects[it] }?.let { simpleProjectModelAssembler.toModel(it) } | ||
} | ||
} | ||
} |
41 changes: 41 additions & 0 deletions
41
backend/app/src/test/kotlin/io/tolgee/api/v2/controllers/NotificationControllerTest.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
package io.tolgee.api.v2.controllers | ||
|
||
import io.tolgee.development.testDataBuilder.data.NotificationsTestData | ||
import io.tolgee.fixtures.andAssertThatJson | ||
import io.tolgee.testing.AuthorizedControllerTest | ||
import org.junit.jupiter.api.Test | ||
|
||
class NotificationControllerTest : AuthorizedControllerTest() { | ||
@Test | ||
fun `gets notifications from newest`() { | ||
val testData = NotificationsTestData() | ||
|
||
(101L..103).forEach { i -> | ||
executeInNewTransaction { | ||
val task = | ||
testData.projectBuilder.addTask { | ||
this.name = "Notification task $i" | ||
this.language = testData.englishLanguage | ||
this.author = testData.originatingUser.self | ||
this.number = i | ||
} | ||
|
||
testData.userAccountBuilder.addNotification { | ||
this.user = testData.user | ||
this.project = testData.project | ||
this.linkedTask = task.self | ||
this.originatingUser = testData.originatingUser.self | ||
} | ||
} | ||
} | ||
|
||
testDataService.saveTestData(testData.root) | ||
loginAsUser(testData.user.username) | ||
|
||
performAuthGet("/v2/notifications").andAssertThatJson { | ||
node("_embedded.notificationModelList[0].linkedTask.name").isEqualTo("Notification task 103") | ||
node("_embedded.notificationModelList[1].linkedTask.name").isEqualTo("Notification task 102") | ||
node("_embedded.notificationModelList[2].linkedTask.name").isEqualTo("Notification task 101") | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
13 changes: 13 additions & 0 deletions
13
...ata/src/main/kotlin/io/tolgee/development/testDataBuilder/builders/NotificationBuilder.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
package io.tolgee.development.testDataBuilder.builders | ||
|
||
import io.tolgee.development.testDataBuilder.EntityDataBuilder | ||
import io.tolgee.model.Notification | ||
|
||
class NotificationBuilder( | ||
val userAccountBuilder: UserAccountBuilder, | ||
) : EntityDataBuilder<Notification, NotificationBuilder> { | ||
override var self: Notification = | ||
Notification().apply { | ||
this.user = userAccountBuilder.self | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
26 changes: 26 additions & 0 deletions
26
.../data/src/main/kotlin/io/tolgee/development/testDataBuilder/data/NotificationsTestData.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
package io.tolgee.development.testDataBuilder.data | ||
|
||
class NotificationsTestData : BaseTestData() { | ||
val originatingUser = | ||
root.addUserAccount { | ||
name = "originating user" | ||
username = "originatingUser" | ||
} | ||
|
||
val task = | ||
projectBuilder.addTask { | ||
this.name = "Notification task" | ||
this.language = englishLanguage | ||
this.author = originatingUser.self | ||
} | ||
|
||
val notificationBuilder = | ||
userAccountBuilder.addNotification { | ||
this.user = this@NotificationsTestData.user | ||
this.project = this@NotificationsTestData.project | ||
this.linkedTask = task.self | ||
this.originatingUser = this@NotificationsTestData.originatingUser.self | ||
} | ||
|
||
val notification = notificationBuilder.self | ||
} |
24 changes: 24 additions & 0 deletions
24
backend/data/src/main/kotlin/io/tolgee/model/Notification.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
package io.tolgee.model | ||
|
||
import io.tolgee.model.task.Task | ||
import jakarta.persistence.* | ||
|
||
@Entity | ||
@Table( | ||
indexes = [ | ||
Index(columnList = "user_id"), | ||
], | ||
) | ||
class Notification : StandardAuditModel() { | ||
@ManyToOne(fetch = FetchType.LAZY) | ||
lateinit var user: UserAccount | ||
|
||
@ManyToOne(fetch = FetchType.LAZY) | ||
var project: Project? = null | ||
|
||
@ManyToOne(fetch = FetchType.LAZY) | ||
var originatingUser: UserAccount? = null | ||
|
||
@ManyToOne(fetch = FetchType.LAZY) | ||
var linkedTask: Task? = null | ||
} |
29 changes: 29 additions & 0 deletions
29
backend/data/src/main/kotlin/io/tolgee/repository/NotificationRepository.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
package io.tolgee.repository | ||
|
||
import io.tolgee.model.Notification | ||
import org.springframework.context.annotation.Lazy | ||
import org.springframework.data.domain.Page | ||
import org.springframework.data.domain.Pageable | ||
import org.springframework.data.jpa.repository.JpaRepository | ||
import org.springframework.data.jpa.repository.Query | ||
import org.springframework.stereotype.Repository | ||
|
||
@Repository | ||
@Lazy | ||
interface NotificationRepository : JpaRepository<Notification, Long> { | ||
@Query( | ||
""" | ||
SELECT n | ||
FROM Notification n | ||
LEFT JOIN FETCH n.user AS u | ||
LEFT JOIN FETCH n.originatingUser | ||
LEFT JOIN FETCH n.linkedTask | ||
WHERE u.id = :userId | ||
ORDER BY n.id DESC | ||
""", | ||
) | ||
fun fetchNotificationsByUserId( | ||
userId: Long, | ||
pageable: Pageable, | ||
): Page<Notification> | ||
} |
23 changes: 23 additions & 0 deletions
23
backend/data/src/main/kotlin/io/tolgee/service/notification/NotificationService.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
package io.tolgee.service.notification | ||
|
||
import io.tolgee.model.Notification | ||
import io.tolgee.repository.NotificationRepository | ||
import org.springframework.data.domain.Page | ||
import org.springframework.data.domain.Pageable | ||
import org.springframework.stereotype.Service | ||
|
||
@Service | ||
class NotificationService( | ||
private val notificationRepository: NotificationRepository, | ||
) { | ||
fun getNotifications( | ||
userId: Long, | ||
pageable: Pageable, | ||
): Page<Notification> { | ||
return notificationRepository.fetchNotificationsByUserId(userId, pageable) | ||
} | ||
|
||
fun save(notification: Notification) { | ||
notificationRepository.save(notification) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.