diff --git a/backend/api/src/main/kotlin/io/tolgee/api/v2/controllers/TaskController.kt b/backend/api/src/main/kotlin/io/tolgee/api/v2/controllers/TaskController.kt index 59b10d7b7e..2a0c10864b 100644 --- a/backend/api/src/main/kotlin/io/tolgee/api/v2/controllers/TaskController.kt +++ b/backend/api/src/main/kotlin/io/tolgee/api/v2/controllers/TaskController.kt @@ -33,7 +33,7 @@ class TaskController( private val taskService: TaskService, private val taskModelAssembler: TaskModelAssembler, private val pagedResourcesAssembler: PagedResourcesAssembler, - private val projectHolder: ProjectHolder + private val projectHolder: ProjectHolder, ) { @GetMapping("") @Operation(summary = "Get tasks") @@ -59,7 +59,6 @@ class TaskController( return taskModelAssembler.toModel(task) } - @PutMapping("/{taskId}") @Operation(summary = "Update task") @UseDefaultPermissions @@ -73,5 +72,4 @@ class TaskController( val task = taskService.updateTask(projectHolder.projectEntity, taskId, dto) return taskModelAssembler.toModel(task) } - } diff --git a/backend/api/src/main/kotlin/io/tolgee/hateoas/task/TaskModel.kt b/backend/api/src/main/kotlin/io/tolgee/hateoas/task/TaskModel.kt index bc9d85752d..abaf5fd9d4 100644 --- a/backend/api/src/main/kotlin/io/tolgee/hateoas/task/TaskModel.kt +++ b/backend/api/src/main/kotlin/io/tolgee/hateoas/task/TaskModel.kt @@ -8,12 +8,12 @@ import org.springframework.hateoas.server.core.Relation import java.util.* @Relation(collectionRelation = "tasks", itemRelation = "task") -class TaskModel ( +class TaskModel( var id: Long = 0L, var name: String = "", var description: String = "", var type: TaskType = TaskType.TRANSLATE, var language: LanguageModel, var dueDate: Date? = null, - var assignees: MutableSet = mutableSetOf() -): RepresentationModel() {} + var assignees: MutableSet = mutableSetOf(), +) : RepresentationModel() diff --git a/backend/api/src/main/kotlin/io/tolgee/hateoas/task/TaskModelAssembler.kt b/backend/api/src/main/kotlin/io/tolgee/hateoas/task/TaskModelAssembler.kt index d560b55867..ecea0f8b76 100644 --- a/backend/api/src/main/kotlin/io/tolgee/hateoas/task/TaskModelAssembler.kt +++ b/backend/api/src/main/kotlin/io/tolgee/hateoas/task/TaskModelAssembler.kt @@ -13,25 +13,26 @@ class TaskModelAssembler( private val userAccountModelAssembler: UserAccountModelAssembler, private val languageModelAssembler: LanguageModelAssembler, ) : RepresentationModelAssemblerSupport( - TaskController::class.java, - TaskModel::class.java -) { + TaskController::class.java, + TaskModel::class.java, + ) { override fun toModel(entity: Task): TaskModel { return TaskModel( id = entity.id, name = entity.name, description = entity.description, type = entity.type, - language = entity.language.let { - languageModelAssembler.toModel( - LanguageDto.fromEntity( - it, - entity.project.baseLanguage?.id + language = + entity.language.let { + languageModelAssembler.toModel( + LanguageDto.fromEntity( + it, + entity.project.baseLanguage?.id, + ), ) - ) - }, + }, dueDate = entity.dueDate, - assignees = entity.assignees.map { userAccountModelAssembler.toModel(it) }.toMutableSet() + assignees = entity.assignees.map { userAccountModelAssembler.toModel(it) }.toMutableSet(), ) } } diff --git a/backend/app/src/test/kotlin/io/tolgee/api/v2/controllers/task/TaskControllerTest.kt b/backend/app/src/test/kotlin/io/tolgee/api/v2/controllers/task/TaskControllerTest.kt index 960aee76dc..7855547421 100644 --- a/backend/app/src/test/kotlin/io/tolgee/api/v2/controllers/task/TaskControllerTest.kt +++ b/backend/app/src/test/kotlin/io/tolgee/api/v2/controllers/task/TaskControllerTest.kt @@ -41,15 +41,19 @@ class TaskControllerTest : ProjectAuthControllerTest("/v2/projects/") { @Test @ProjectJWTAuthTestMethod fun `creates new task`() { - performProjectAuthPost("tasks", CreateTaskRequest( - name = "Another task", - description = "...", - type = TaskType.TRANSLATE, - languageId = testData.englishLanguage.id, - assignees = mutableListOf( - testData.orgMember.self.id - ) - )).andAssertThatJson { + performProjectAuthPost( + "tasks", + CreateTaskRequest( + name = "Another task", + description = "...", + type = TaskType.TRANSLATE, + languageId = testData.englishLanguage.id, + assignees = + mutableListOf( + testData.orgMember.self.id, + ), + ), + ).andAssertThatJson { node("id").isNumber node("name").isEqualTo("Another task") node("assignees[0].name").isEqualTo(testData.orgMember.self.name) @@ -64,15 +68,19 @@ class TaskControllerTest : ProjectAuthControllerTest("/v2/projects/") { @Test @ProjectJWTAuthTestMethod fun `fails to create task with assignee from different project`() { - performProjectAuthPost("tasks", CreateTaskRequest( - name = "Another task", - description = "...", - type = TaskType.TRANSLATE, - languageId = testData.englishLanguage.id, - assignees = mutableListOf( - testData.unrelatedUser.self.id - ) - )).andIsBadRequest.andAssertThatJson { + performProjectAuthPost( + "tasks", + CreateTaskRequest( + name = "Another task", + description = "...", + type = TaskType.TRANSLATE, + languageId = testData.englishLanguage.id, + assignees = + mutableListOf( + testData.unrelatedUser.self.id, + ), + ), + ).andIsBadRequest.andAssertThatJson { node("code").isEqualTo(Message.USER_HAS_NO_PROJECT_ACCESS) } } @@ -80,13 +88,16 @@ class TaskControllerTest : ProjectAuthControllerTest("/v2/projects/") { @Test @ProjectJWTAuthTestMethod fun `fails to create task with language from different project`() { - performProjectAuthPost("tasks", CreateTaskRequest( - name = "Another task", - description = "...", - type = TaskType.TRANSLATE, - languageId = testData.unrelatedEnglish.self.id, - assignees = mutableListOf() - )).andIsBadRequest.andAssertThatJson { + performProjectAuthPost( + "tasks", + CreateTaskRequest( + name = "Another task", + description = "...", + type = TaskType.TRANSLATE, + languageId = testData.unrelatedEnglish.self.id, + assignees = mutableListOf(), + ), + ).andIsBadRequest.andAssertThatJson { node("code").isEqualTo(Message.LANGUAGE_NOT_FROM_PROJECT) } } @@ -94,11 +105,14 @@ class TaskControllerTest : ProjectAuthControllerTest("/v2/projects/") { @Test @ProjectJWTAuthTestMethod fun `updates existing task`() { - performProjectAuthPut("tasks/${testData.createdTask.self.id}", UpdateTaskRequest( - name = "Updated task", - description = "updated description", - assignees = mutableListOf() - )).andIsOk.andAssertThatJson { + performProjectAuthPut( + "tasks/${testData.createdTask.self.id}", + UpdateTaskRequest( + name = "Updated task", + description = "updated description", + assignees = mutableListOf(), + ), + ).andIsOk.andAssertThatJson { node("id").isEqualTo(testData.createdTask.self.id) node("name").isEqualTo("Updated task") node("description").isEqualTo("updated description") @@ -109,9 +123,12 @@ class TaskControllerTest : ProjectAuthControllerTest("/v2/projects/") { @Test @ProjectJWTAuthTestMethod fun `fails when updating assignees to non-members`() { - performProjectAuthPut("tasks/${testData.createdTask.self.id}", UpdateTaskRequest( - assignees = mutableListOf(testData.unrelatedUser.self.id) - )).andIsBadRequest.andAssertThatJson { + performProjectAuthPut( + "tasks/${testData.createdTask.self.id}", + UpdateTaskRequest( + assignees = mutableListOf(testData.unrelatedUser.self.id), + ), + ).andIsBadRequest.andAssertThatJson { node("code").isEqualTo(Message.USER_HAS_NO_PROJECT_ACCESS) } } diff --git a/backend/data/src/main/kotlin/io/tolgee/constants/Message.kt b/backend/data/src/main/kotlin/io/tolgee/constants/Message.kt index 4a8b2b5f53..9655016a48 100644 --- a/backend/data/src/main/kotlin/io/tolgee/constants/Message.kt +++ b/backend/data/src/main/kotlin/io/tolgee/constants/Message.kt @@ -233,7 +233,7 @@ enum class Message { SLACK_NOT_CONFIGURED, SLACK_WORKSPACE_ALREADY_CONNECTED, SLACK_CONNECTION_ERROR, - TASK_NOT_FOUND + TASK_NOT_FOUND, ; val code: String diff --git a/backend/data/src/main/kotlin/io/tolgee/development/testDataBuilder/builders/TaskBuilder.kt b/backend/data/src/main/kotlin/io/tolgee/development/testDataBuilder/builders/TaskBuilder.kt index 72215bc6c7..781c9c43af 100644 --- a/backend/data/src/main/kotlin/io/tolgee/development/testDataBuilder/builders/TaskBuilder.kt +++ b/backend/data/src/main/kotlin/io/tolgee/development/testDataBuilder/builders/TaskBuilder.kt @@ -6,7 +6,8 @@ import io.tolgee.model.task.Task class TaskBuilder( val projectBuilder: ProjectBuilder, ) : EntityDataBuilder { - override var self: Task = Task().apply { - this.project = projectBuilder.self - } + override var self: Task = + Task().apply { + this.project = projectBuilder.self + } } diff --git a/backend/data/src/main/kotlin/io/tolgee/development/testDataBuilder/data/TaskTestData.kt b/backend/data/src/main/kotlin/io/tolgee/development/testDataBuilder/data/TaskTestData.kt index 55bb0dfd1e..98c196a8e6 100644 --- a/backend/data/src/main/kotlin/io/tolgee/development/testDataBuilder/data/TaskTestData.kt +++ b/backend/data/src/main/kotlin/io/tolgee/development/testDataBuilder/data/TaskTestData.kt @@ -37,22 +37,23 @@ class TaskTestData : BaseTestData("tagsTestUser", "tagsTestProject") { } } - projectBuilder.apply { addPermission { user = projectUser.self type = ProjectPermissionType.EDIT } - createdTask = addTask { - name = "New task" - type = TaskType.TRANSLATE - assignees = mutableSetOf( - projectUser.self, - ) - project = projectBuilder.self - language = englishLanguage - } + createdTask = + addTask { + name = "New task" + type = TaskType.TRANSLATE + assignees = + mutableSetOf( + projectUser.self, + ) + project = projectBuilder.self + language = englishLanguage + } } unrelatedOrg.self.apply { diff --git a/backend/data/src/main/kotlin/io/tolgee/dtos/request/task/CreateTaskRequest.kt b/backend/data/src/main/kotlin/io/tolgee/dtos/request/task/CreateTaskRequest.kt index 85b668e747..8fb1032256 100644 --- a/backend/data/src/main/kotlin/io/tolgee/dtos/request/task/CreateTaskRequest.kt +++ b/backend/data/src/main/kotlin/io/tolgee/dtos/request/task/CreateTaskRequest.kt @@ -1,12 +1,10 @@ package io.tolgee.dtos.request.task import io.swagger.v3.oas.annotations.media.Schema -import io.tolgee.dtos.request.LanguageRequest import io.tolgee.model.enums.TaskType import jakarta.persistence.EnumType import jakarta.persistence.Enumerated import jakarta.validation.constraints.NotBlank -import jakarta.validation.constraints.NotEmpty import jakarta.validation.constraints.NotNull import jakarta.validation.constraints.Size @@ -14,27 +12,22 @@ data class CreateTaskRequest( @field:NotBlank @field:Size(min = 3, max = 255) var name: String = "", - @field:NotBlank @field:Size(min = 0, max = 2000) var description: String = "", - @Enumerated(EnumType.STRING) val type: TaskType, - @Schema( description = "Due to date in epoch format (milliseconds).", example = "1661172869000", ) var dueDate: Long? = null, - @Schema( description = "Id of language, this task is attached to.", example = "1", ) @field:NotNull var languageId: Long? = null, - @field:NotNull var assignees: List? = null, ) diff --git a/backend/data/src/main/kotlin/io/tolgee/dtos/request/task/UpdateTaskRequest.kt b/backend/data/src/main/kotlin/io/tolgee/dtos/request/task/UpdateTaskRequest.kt index ab64693f77..3be3525bea 100644 --- a/backend/data/src/main/kotlin/io/tolgee/dtos/request/task/UpdateTaskRequest.kt +++ b/backend/data/src/main/kotlin/io/tolgee/dtos/request/task/UpdateTaskRequest.kt @@ -1,24 +1,17 @@ package io.tolgee.dtos.request.task import io.swagger.v3.oas.annotations.media.Schema -import io.tolgee.model.enums.TaskType -import jakarta.persistence.EnumType -import jakarta.persistence.Enumerated import jakarta.validation.constraints.Size data class UpdateTaskRequest( @field:Size(min = 3, max = 255) var name: String? = null, - @field:Size(min = 0, max = 2000) var description: String? = null, - @Schema( description = "Due to date in epoch format (milliseconds).", example = "1661172869000", ) var dueDate: Long? = null, - var assignees: List? = null, ) - diff --git a/backend/data/src/main/kotlin/io/tolgee/model/task/Task.kt b/backend/data/src/main/kotlin/io/tolgee/model/task/Task.kt index 6ca30c2f6f..0918507caa 100644 --- a/backend/data/src/main/kotlin/io/tolgee/model/task/Task.kt +++ b/backend/data/src/main/kotlin/io/tolgee/model/task/Task.kt @@ -8,13 +8,12 @@ import jakarta.persistence.* import jakarta.validation.constraints.Size import java.util.* - @Entity @IdClass(TaskId::class) class Task { @Id @ManyToOne(fetch = FetchType.LAZY) - var project: Project = Project() // Initialize to avoid null issues + var project: Project = Project() // Initialize to avoid null issues @Id var id: Long = 1L diff --git a/backend/data/src/main/kotlin/io/tolgee/model/task/TaskId.kt b/backend/data/src/main/kotlin/io/tolgee/model/task/TaskId.kt index 265767bbe4..9af100561a 100644 --- a/backend/data/src/main/kotlin/io/tolgee/model/task/TaskId.kt +++ b/backend/data/src/main/kotlin/io/tolgee/model/task/TaskId.kt @@ -2,14 +2,11 @@ package io.tolgee.model.task import io.tolgee.model.Project import jakarta.persistence.FetchType -import jakarta.persistence.GeneratedValue -import jakarta.persistence.GenerationType import jakarta.persistence.ManyToOne import java.io.Serializable -data class TaskId ( +data class TaskId( @ManyToOne(fetch = FetchType.LAZY) - var project: Project = Project(), // Initialize to avoid null issues - - var id: Long = 1L + var project: Project, + var id: Long = 1L, ) : Serializable diff --git a/backend/data/src/main/kotlin/io/tolgee/service/TaskService.kt b/backend/data/src/main/kotlin/io/tolgee/service/TaskService.kt index 1f102419c0..9838707d9c 100644 --- a/backend/data/src/main/kotlin/io/tolgee/service/TaskService.kt +++ b/backend/data/src/main/kotlin/io/tolgee/service/TaskService.kt @@ -7,8 +7,8 @@ import io.tolgee.exceptions.BadRequestException import io.tolgee.exceptions.NotFoundException import io.tolgee.model.Language import io.tolgee.model.Project -import io.tolgee.model.task.Task import io.tolgee.model.UserAccount +import io.tolgee.model.task.Task import io.tolgee.model.task.TaskId import io.tolgee.repository.TaskRepository import io.tolgee.service.language.LanguageService @@ -27,13 +27,18 @@ class TaskService( private val languageService: LanguageService, private val securityService: SecurityService, ) { - fun getAllPaged(project: Project, pageable: Pageable): Page { + fun getAllPaged( + project: Project, + pageable: Pageable, + ): Page { return taskRepository.getAllByProjectId(project.id, pageable) } - @Transactional - fun createTask(project: Project, dto: CreateTaskRequest): Task { + fun createTask( + project: Project, + dto: CreateTaskRequest, + ): Task { // Find the maximum ID for the given project val lastTask = taskRepository.findByProjectOrderByIdDesc(project).firstOrNull() val newId = (lastTask?.id ?: 0L) + 1 @@ -54,10 +59,15 @@ class TaskService( return task } - fun updateTask(projectEntity: Project, taskId: Long, dto: UpdateTaskRequest): Task { - val task = taskRepository.findById(TaskId(projectEntity, taskId)).or { - throw NotFoundException(Message.TASK_NOT_FOUND) - }.get() + fun updateTask( + projectEntity: Project, + taskId: Long, + dto: UpdateTaskRequest, + ): Task { + val task = + taskRepository.findById(TaskId(projectEntity, taskId)).or { + throw NotFoundException(Message.TASK_NOT_FOUND) + }.get() dto.name?.let { task.name = it } @@ -75,18 +85,22 @@ class TaskService( } private fun checkAssignees( - assignees: List, - project: Project + assignees: List, + project: Project, ): MutableSet { return assignees.map { - val permission = securityService.getProjectPermissionScopesNoApiKey(project.id, it) - if (permission.isNullOrEmpty()) { - throw BadRequestException(Message.USER_HAS_NO_PROJECT_ACCESS) - } - entityManager.getReference(UserAccount::class.java, it) - }.toMutableSet() + val permission = securityService.getProjectPermissionScopesNoApiKey(project.id, it) + if (permission.isNullOrEmpty()) { + throw BadRequestException(Message.USER_HAS_NO_PROJECT_ACCESS) + } + entityManager.getReference(UserAccount::class.java, it) + }.toMutableSet() } - private fun checkLanguage(language: Long, project: Project): Language { + + private fun checkLanguage( + language: Long, + project: Project, + ): Language { val allLanguages = languageService.findAll(project.id).associateBy { it.id } if (allLanguages[language] == null) { throw BadRequestException(Message.LANGUAGE_NOT_FROM_PROJECT)