athrainsky před 11 měsíci
rodič
revize
b711cce2e4

+ 0 - 3
qc.txt

@@ -1,7 +1,4 @@
 insert  into `user`(`user_id`,`name`,`password`,`username`) values 
 (1,'test user','$2a$10$Y8LgDPJiAsbw7n5pURhGVOmi5.LWpfJaX7ZgSDbjsQXEnsCFPdhB2','user')
 
-- Semua api yang menghasilkan list/array ditambahkan pagging
-- /projects/{projectId}/member ditambahkan filter untuk role
-- project hanya bisa dilihat oleh owner dan member saja
 

+ 58 - 41
src/main/kotlin/com/swagger/rest/controllers/MemberController.kt

@@ -1,15 +1,15 @@
 package com.swagger.rest.controllers
 
+import com.swagger.rest.models.*
 import com.swagger.rest.models.Enum
-import com.swagger.rest.models.MemberInput
-import com.swagger.rest.models.MemberOutput
-import com.swagger.rest.models.ProjectMember
 import com.swagger.rest.repositories.MemberRepository
 import com.swagger.rest.repositories.ProjectRepository
 import com.swagger.rest.repositories.UserRepository
+import jakarta.persistence.criteria.Predicate
 import org.springframework.data.domain.PageRequest
 import org.springframework.data.domain.Pageable
 import org.springframework.data.domain.Sort
+import org.springframework.data.jpa.domain.Specification
 import org.springframework.http.HttpStatus
 import org.springframework.http.ResponseEntity
 import org.springframework.security.core.context.SecurityContextHolder
@@ -36,50 +36,67 @@ class MemberController(
         @PathVariable("id") id: Long,
         @RequestParam(defaultValue = 0.toString()) page: Int,
         @RequestParam(defaultValue = 3.toString()) limit: Int,
-        @RequestParam(defaultValue = "member_id, desc") sort: Array<String>,
+        @RequestParam(defaultValue = "id, desc") sort: Array<String>,
         @RequestParam(required = false) role: String?
     ): Any {
-        val orders: MutableList<Sort.Order> = ArrayList()
-        if (sort[0].contains(",")) {
-            for (sortOrder in sort) {
-                val sort_ = sortOrder.split(",".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()
-                orders.add(Sort.Order(getSortDirection(sort_[1]), sort_[0]))
-            }
-        } else {
-            orders.add(Sort.Order(Sort.Direction.DESC, sort[0]))
-        }
-        val pagingSort: Pageable = PageRequest.of(page, limit, Sort.by(orders as List<Sort.Order>))
-        if (enumValues<Enum.Member>().any { it.name == role!!.uppercase() }) {
-            val memberData = if (role == null) {
-                memberRepository.findByProject1(
-                    id.toString(), pagingSort
-                )
+        return try {
+            val orders: MutableList<Sort.Order> = ArrayList()
+            val column = listOf("id", "role", "project", "user")
+            val sort2 = if (!sort.contains(",")) {
+                sort + ",desc"
             } else {
-                memberRepository.findByProject2(
-                    id.toString(), Enum.Member.valueOf(role.uppercase()).ordinal.toString(), pagingSort
-                )
-            }
-            val output = memberData.map {
-                MemberOutput(
-                    id = it.id,
-                    project = it.project!!.description,
-                    user = it.user!!.name,
-                    role = Enum.Member.values()[it.role]
-                )
+                sort
             }
-            val ret: List<MemberOutput?> = output.content
-            val response: MutableMap<String, Any> = HashMap()
-            response["currentPage"] = output.number
-            response["totalRecord"] = output.totalElements
-            response["totalPage"] = output.totalPages
-            response["results"] = ret
-            return if (ret.isNotEmpty()) {
-                ResponseEntity(response, HttpStatus.OK)
+            if (!column.contains(sort2[0])) {
+                ResponseEntity<ProjectMember>(HttpStatus.BAD_REQUEST)
             } else {
-                arrayOf<String>()
+                if (sort[0].contains(",")) {
+                    // will sort more than 2 fields
+                    // sortOrder="field, direction"
+                    for (sortOrder in sort2) {
+                        val _sort = sortOrder.split(",".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()
+                        orders.add(Sort.Order(getSortDirection(_sort[1]), _sort[0]))
+                    }
+                } else {
+                    // sort=[field, direction]
+                    orders.add(Sort.Order(getSortDirection(sort2[1]), sort2[0]))
+                }
+                val pagingSort: Pageable = PageRequest.of(page, limit, Sort.by(orders as List<Sort.Order>))
+                val spec = Specification<ProjectMember> { root, query, builder ->
+                    val list: MutableList<Predicate> = mutableListOf()
+                    list.add(builder.equal(root.get<Project>("project").get<Long>("id"), id))
+                    role?.let {
+                        val r = if (Enum.Member.values()
+                                .any { it.name == role.uppercase() }
+                        ) Enum.Member.valueOf(role.uppercase()).ordinal else Enum.Member.UNDEFINED.ordinal
+                        list.add(builder.equal(root.get<Int>("role"), r))
+                    }
+                    builder.and(*list.toTypedArray())
+                }
+                val memberData = memberRepository.findAll(spec, pagingSort)
+                val output = memberData.map {
+                    MemberOutput(
+                        id = it.id,
+                        project = it.project!!.description,
+                        user = it.user!!.name,
+                        role = Enum.Member.values()[it.role]
+                    )
+                }
+                val ret: List<MemberOutput?> = output.content
+                val response: MutableMap<String, Any> = HashMap()
+                response["currentPage"] = output.number
+                response["totalRecord"] = output.totalElements
+                response["totalPage"] = output.totalPages
+                response["results"] = ret
+                if (ret.isNotEmpty()) {
+                    ResponseEntity(response, HttpStatus.OK)
+                } else {
+                    arrayOf<String>()
+                }
             }
-        } else {
-             return ResponseEntity<ProjectMember>(HttpStatus.BAD_REQUEST)
+        } catch (e: Exception) {
+            e.printStackTrace()
+            ResponseEntity(e, HttpStatus.INTERNAL_SERVER_ERROR)
         }
     }
 

+ 47 - 28
src/main/kotlin/com/swagger/rest/controllers/PlatformController.kt

@@ -2,14 +2,16 @@ package com.swagger.rest.controllers
 
 import com.swagger.rest.models.Platform
 import com.swagger.rest.models.PlatformInput
+import com.swagger.rest.models.Project
 import com.swagger.rest.repositories.MemberRepository
 import com.swagger.rest.repositories.PlatformRepository
 import com.swagger.rest.repositories.ProjectRepository
 import com.swagger.rest.repositories.UserRepository
-import org.springframework.data.domain.Page
+import jakarta.persistence.criteria.Predicate
 import org.springframework.data.domain.PageRequest
 import org.springframework.data.domain.Pageable
 import org.springframework.data.domain.Sort
+import org.springframework.data.jpa.domain.Specification
 import org.springframework.http.HttpStatus
 import org.springframework.http.ResponseEntity
 import org.springframework.security.core.context.SecurityContextHolder
@@ -42,33 +44,50 @@ class PlatformController(
     ): Any {
         return try {
             val orders: MutableList<Sort.Order> = ArrayList()
-            if (sort[0].contains(",")) {
-                for (sortOrder in sort) {
-                    val sort_ = sortOrder.split(",".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()
-                    orders.add(Sort.Order(getSortDirection(sort_[1]), sort_[0]))
-                }
-            } else {
-                orders.add(Sort.Order(Sort.Direction.DESC, sort[0]))
-            }
-            val pagingSort: Pageable = PageRequest.of(page, limit, Sort.by(orders as List<Sort.Order>))
-            val platforms: Page<Platform> = if (project == null) {
-                platformRepository.findAll(pagingSort)
+            val column = listOf("id", "name", "project_id")
+            val sort2 = if (!sort.contains(",")) {
+                sort + ",desc"
             } else {
-                platformRepository.findByProject(project, pagingSort)
+                sort
             }
-            val ret: List<Platform?> = platforms.content
-            val response: MutableMap<String, Any> = HashMap()
-            response["currentPage"] = platforms.number
-            response["totalRecord"] = platforms.totalElements
-            response["totalPage"] = platforms.totalPages
-            response["results"] = ret
-            if (ret.isNotEmpty()) {
-                ResponseEntity(response, HttpStatus.OK)
+            if (!column.contains(sort2[0])) {
+                ResponseEntity<Platform>(HttpStatus.BAD_REQUEST)
             } else {
-                arrayOf<String>()
+                if (sort2[0].contains(",")) {
+                    // will sort more than 2 fields
+                    // sortOrder="field, direction"
+                    for (sortOrder in sort2) {
+                        val _sort = sortOrder.split(",".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()
+                        orders.add(Sort.Order(getSortDirection(_sort[1]), _sort[0]))
+                    }
+                } else {
+                    // sort=[field, direction]
+                    orders.add(Sort.Order(getSortDirection(sort2[1]), sort2[0]))
+                }
+                val pagingSort: Pageable = PageRequest.of(page, limit, Sort.by(orders as List<Sort.Order>))
+                val spec = Specification<Platform> { root, query, builder ->
+                    val list: MutableList<Predicate> = mutableListOf()
+                    project?.let {
+                        list.add(builder.equal(root.get<Project>("project").get<Long>("id"), project))
+                    }
+                    builder.and(*list.toTypedArray())
+                }
+                val platforms = platformRepository.findAll(spec, pagingSort)
+                val ret: List<Platform?> = platforms.content
+                val response: MutableMap<String, Any> = HashMap()
+                response["currentPage"] = platforms.number
+                response["totalRecord"] = platforms.totalElements
+                response["totalPage"] = platforms.totalPages
+                response["results"] = ret
+                if (ret.isNotEmpty()) {
+                    ResponseEntity(response, HttpStatus.OK)
+                } else {
+                    arrayOf<String>()
+                }
             }
         } catch (e: Exception) {
-            ResponseEntity(null, HttpStatus.INTERNAL_SERVER_ERROR)
+            e.printStackTrace()
+            ResponseEntity(e, HttpStatus.INTERNAL_SERVER_ERROR)
         }
     }
 
@@ -102,7 +121,7 @@ class PlatformController(
                     } else {
                         val newPlatform = Platform()
                         newPlatform.name = platform.name!!.trim()
-                        newPlatform.project_id = foundProject
+                        newPlatform.project = foundProject
                         ResponseEntity<Platform>(platformRepository.save(newPlatform), HttpStatus.CREATED)
                     }
                 } else {//invalid name
@@ -133,9 +152,9 @@ class PlatformController(
                         ResponseEntity<Platform>(HttpStatus.NOT_FOUND)
                     } else {
                         val check = platformRepository.findByName(input.name, targetProject.id.toString())
-                        if (check.isEmpty() || (input.name == platformExist.get().name && targetProject.id.toString() == platformExist.get().project_id!!.id.toString())) {//tidak ada yg sama
+                        if (check.isEmpty() || (input.name == platformExist.get().name && targetProject.id.toString() == platformExist.get().project!!.id.toString())) {//tidak ada yg sama
                             val savePlatform = platformExist.get()
-                            savePlatform.project_id = targetProject
+                            savePlatform.project = targetProject
                             savePlatform.name = input.name!!.trim()
                             ResponseEntity<Platform>(platformRepository.save(savePlatform), HttpStatus.OK)
                         } else {
@@ -161,9 +180,9 @@ class PlatformController(
                 val find = platformRepository.findById(id)
                 val userId = userRepository.getUserByUsername(SecurityContextHolder.getContext().authentication.name)
                 val validOwner =
-                    projectRepository.validOwner(find.get().project_id!!.id.toString(), userId.id.toString())
+                    projectRepository.validOwner(find.get().project!!.id.toString(), userId.id.toString())
                 val validAdmin =
-                    memberRepository.validRole(find.get().project_id!!.id.toString(), userId.id.toString(), "2")
+                    memberRepository.validRole(find.get().project!!.id.toString(), userId.id.toString(), "2")
                 if (validOwner > 0 || validAdmin > 0) {
                     if (find.isPresent) {
                         platformRepository.deleteById(id)

+ 37 - 28
src/main/kotlin/com/swagger/rest/controllers/ProjectController.kt

@@ -33,40 +33,49 @@ class ProjectController(
 
     @GetMapping("/projects")
     fun getProject(
-        @RequestParam(required = false) name: String?,
         @RequestParam(defaultValue = 0.toString()) page: Int,
         @RequestParam(defaultValue = 3.toString()) limit: Int,
         @RequestParam(defaultValue = "id, desc") sort: Array<String>
     ): Any {
         return try {
             val orders: MutableList<Sort.Order> = ArrayList()
-            if (sort[0].contains(",")) {
-                for (sortOrder in sort) {
-                    val sort_ = sortOrder.split(",".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()
-                    orders.add(Sort.Order(getSortDirection(sort_[1]), sort_[0]))
-                }
+            val column = listOf("id", "name", "description", "owner")
+            val sort2 = if (!sort.contains(",")) {
+                sort + ",desc"
             } else {
-//                orders.add(Sort.Order(getSortDirection(sort[1]), sort[0]))
-                orders.add(Sort.Order(Sort.Direction.DESC, sort[0]))
+                sort
             }
-            val pagingSort: Pageable = PageRequest.of(page, limit, Sort.by(orders as List<Sort.Order>))
-            val projects =
-                if (name == null) projectRepository.findAll(pagingSort) else projectRepository.findByNameContaining(
-                    name, pagingSort
-                )
-            val ret = projects.content
-            val response: MutableMap<String, Any> = HashMap()
-            response["currentPage"] = projects.number
-            response["totalRecord"] = projects.totalElements
-            response["totalPage"] = projects.totalPages
-            response["results"] = ret
-            if (ret.isEmpty()) {
-                arrayOf<String>()
+            if (!column.contains(sort2[0])) {
+                ResponseEntity<Project>(HttpStatus.BAD_REQUEST)
             } else {
-                ResponseEntity(response, HttpStatus.OK)
+                if (sort2[0].contains(",")) {
+                    // will sort more than 2 fields
+                    // sortOrder="field, direction"
+                    for (sortOrder in sort2) {
+                        val _sort = sortOrder.split(",".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()
+                        orders.add(Sort.Order(getSortDirection(_sort[1]), _sort[0]))
+                    }
+                } else {
+                    // sort=[field, direction]
+                    orders.add(Sort.Order(getSortDirection(sort2[1]), sort2[0]))
+                }
+                val pagingSort: Pageable = PageRequest.of(page, limit, Sort.by(orders))
+                val projects = projectRepository.findAll(pagingSort)
+                val ret = projects.content
+                val response: MutableMap<String, Any> = HashMap()
+                response["currentPage"] = projects.number
+                response["totalRecord"] = projects.totalElements
+                response["totalPage"] = projects.totalPages
+                response["results"] = ret
+                if (ret.isEmpty()) {
+                    arrayOf<String>()
+                } else {
+                    ResponseEntity(response, HttpStatus.OK)
+                }
             }
         } catch (e: Exception) {
-            ResponseEntity(null, HttpStatus.INTERNAL_SERVER_ERROR)
+            e.printStackTrace()
+            ResponseEntity(e, HttpStatus.INTERNAL_SERVER_ERROR)
         }
     }
 
@@ -76,14 +85,14 @@ class ProjectController(
         val validOwner = projectRepository.validOwner(id.toString(), userId.id.toString())
         val validMember = memberRepository.validMember(id.toString(), userId.id.toString())
         val projectData: Optional<Project?> = projectRepository.findById(id)
-        return if (validOwner > 0 || validMember > 0) {
-            if (projectData.isPresent) {
+        return if (projectData.isEmpty) {
+            ResponseEntity<Project>(HttpStatus.NOT_FOUND)
+        } else {
+            if (validOwner > 0 || validMember > 0) {
                 ResponseEntity<Project>(projectData.get(), HttpStatus.OK)
             } else {
-                ResponseEntity<Project>(HttpStatus.NOT_FOUND)
+                ResponseEntity<Project>(HttpStatus.FORBIDDEN)
             }
-        } else {
-            ResponseEntity<Project>(HttpStatus.FORBIDDEN)
         }
     }
 

+ 30 - 25
src/main/kotlin/com/swagger/rest/controllers/UserController.kt

@@ -1,6 +1,5 @@
 package com.swagger.rest.controllers
 
-import com.swagger.rest.models.MemberOutput
 import com.swagger.rest.models.User
 import com.swagger.rest.models.UserInput
 import com.swagger.rest.repositories.MemberRepository
@@ -13,8 +12,6 @@ import org.springframework.http.ResponseEntity
 import org.springframework.security.core.context.SecurityContextHolder
 import org.springframework.security.crypto.password.PasswordEncoder
 import org.springframework.web.bind.annotation.*
-import java.util.ArrayList
-import java.util.HashMap
 
 @RestController
 @RequestMapping("/api/v1")
@@ -35,37 +32,45 @@ class UserController(
 
     @GetMapping("/users")
     fun getUser(
-        @RequestParam(required = false) username: String?,
         @RequestParam(defaultValue = 0.toString()) page: Int,
         @RequestParam(defaultValue = 3.toString()) limit: Int,
         @RequestParam(defaultValue = "id, desc") sort: Array<String>
     ): Any {
         return try {
             val orders: MutableList<Sort.Order> = ArrayList()
-            if (sort[0].contains(",")) {
-                for (sortOrder in sort) {
-                    val sort_ = sortOrder.split(",".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()
-                    orders.add(Sort.Order(getSortDirection(sort_[1]), sort_[0]))
-                }
-            } else {
-                orders.add(Sort.Order(Sort.Direction.DESC, sort[0]))
-            }
-            val pagingSort: Pageable = PageRequest.of(page, limit, Sort.by(orders as List<Sort.Order>))
-            val users = if (username == null) {
-                userRepository.findAll(pagingSort)
+            val column = listOf("id", "name", "username")
+            val sort2 = if (!sort.contains(",")) {
+                sort + ",desc"
             } else {
-                userRepository.findByUsernameContaining(username, pagingSort)
+                sort
             }
-            val ret: List<User?> = users.content
-            val response: MutableMap<String, Any> = HashMap()
-            response["currentPage"] = users.number
-            response["totalRecord"] = users.totalElements
-            response["totalPage"] = users.totalPages
-            response["results"] = ret
-            if (ret.isNotEmpty()) {
-                ResponseEntity(response, HttpStatus.OK)
+            if (!column.contains(sort2[0])) {
+                ResponseEntity<User>(HttpStatus.BAD_REQUEST)
             } else {
-                arrayOf<String>()
+                if (sort2[0].contains(",")) {
+                    // will sort more than 2 fields
+                    // sortOrder="field, direction"
+                    for (sortOrder in sort2) {
+                        val _sort = sortOrder.split(",".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()
+                        orders.add(Sort.Order(getSortDirection(_sort[1]), _sort[0]))
+                    }
+                } else {
+                    // sort=[field, direction]
+                    orders.add(Sort.Order(getSortDirection(sort2[1]), sort2[0]))
+                }
+                val pagingSort: Pageable = PageRequest.of(page, limit, Sort.by(orders as List<Sort.Order>))
+                val users = userRepository.findAll(pagingSort)
+                val ret: List<User?> = users.content
+                val response: MutableMap<String, Any> = HashMap()
+                response["currentPage"] = users.number
+                response["totalRecord"] = users.totalElements
+                response["totalPage"] = users.totalPages
+                response["results"] = ret
+                if (ret.isNotEmpty()) {
+                    ResponseEntity(response, HttpStatus.OK)
+                } else {
+                    arrayOf<String>()
+                }
             }
         } catch (e: Exception) {
             ResponseEntity(null, HttpStatus.INTERNAL_SERVER_ERROR)

+ 1 - 1
src/main/kotlin/com/swagger/rest/models/Enum.kt

@@ -3,7 +3,7 @@ package com.swagger.rest.models
 class Enum {
 
     enum class Member{
-        QC, PROGRAMMER, ADMIN
+        QC, PROGRAMMER, ADMIN, UNDEFINED
     }
 
 }

+ 2 - 2
src/main/kotlin/com/swagger/rest/models/Platform.kt

@@ -15,10 +15,10 @@ class Platform {
 
     @ManyToOne
     @JoinColumn(name = "project_id", referencedColumnName = "project_id", foreignKey = ForeignKey(name = "FK_plaPro"))
-    var project_id: Project? = null
+    var project: Project? = null
 
     override fun toString(): String {
-        return "Platform [id=$id, name=$name, project_Id=$project_id]"
+        return "Platform [id=$id, name=$name, project_Id=$project]"
     }
 
 }

+ 1 - 1
src/main/kotlin/com/swagger/rest/models/Project.kt

@@ -18,7 +18,7 @@ class Project {
     @Column(name = "description")
     var description: String? = null
 
-    @OneToMany(mappedBy = "project_id", cascade = [CascadeType.ALL])
+    @OneToMany(mappedBy = "project", cascade = [CascadeType.ALL])
     @JsonIgnore
     var project_id: List<Platform> = mutableListOf()
 

+ 2 - 8
src/main/kotlin/com/swagger/rest/repositories/MemberRepository.kt

@@ -1,17 +1,11 @@
 package com.swagger.rest.repositories
 
 import com.swagger.rest.models.ProjectMember
-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.JpaSpecificationExecutor
 import org.springframework.data.jpa.repository.Query
 
-interface MemberRepository : JpaRepository<ProjectMember, Long> {
-    @Query("SELECT * FROM project_member WHERE project_id=?1", nativeQuery = true)
-    fun findByProject1(project: String?, pageable: Pageable?): Page<ProjectMember>
-
-    @Query("SELECT * FROM project_member WHERE project_id=?1 AND role=?2", nativeQuery = true)
-    fun findByProject2(project: String?, role: String, pageable: Pageable?): Page<ProjectMember>
+interface MemberRepository : JpaRepository<ProjectMember, Long>, JpaSpecificationExecutor<ProjectMember> {
 
     @Query("SELECT f.* FROM project_member f WHERE project_id=?1 and role=?2 and user_id=?3", nativeQuery = true)
     fun findDup(project: String?, role: String?, user: String?): List<ProjectMember>

+ 2 - 6
src/main/kotlin/com/swagger/rest/repositories/PlatformRepository.kt

@@ -1,18 +1,14 @@
 package com.swagger.rest.repositories
 
 import com.swagger.rest.models.Platform
-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.JpaSpecificationExecutor
 import org.springframework.data.jpa.repository.Query
 
-interface PlatformRepository : JpaRepository<Platform, Long> {
+interface PlatformRepository : JpaRepository<Platform, Long>, JpaSpecificationExecutor<Platform> {
     @Query("SELECT f.* FROM platform f WHERE name=?1 AND project_id=?2", nativeQuery = true)
     fun findByName(name: String?, project: String?): List<Platform>
 
-    @Query("SELECT f.* FROM platform f WHERE project_id=?1", nativeQuery = true)
-    fun findByProject(project: String?, pageable: Pageable?): Page<Platform>
-
     @Query("SELECT f.* FROM platform f WHERE project_id=?1", nativeQuery = true)
     fun findByProjectId(project: String?): List<Platform>
 }

+ 0 - 4
src/main/kotlin/com/swagger/rest/repositories/UserRepository.kt

@@ -1,8 +1,6 @@
 package com.swagger.rest.repositories
 
 import com.swagger.rest.models.User
-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
 
@@ -12,8 +10,6 @@ interface UserRepository:JpaRepository<User, Long> {
 
     fun findByUsername(username: String?): List<User>
 
-    fun findByUsernameContaining(username:String?, pageable: Pageable?): Page<User>
-
     @Query("SELECT COUNT(0) FROM user where user_id=?1 AND username=?2", nativeQuery = true)
     fun countByUser(userId: String, username: String): Int
 }

+ 15 - 1
swagger3 project.yml

@@ -34,6 +34,8 @@ paths:
       responses:
         200:
           $ref: '#/components/responses/getArrayProject'
+        400:
+          $ref: '#/components/responses/400'
         401:
           $ref: '#/components/responses/UnauthorizedError'
       security: 
@@ -98,6 +100,8 @@ paths:
           $ref: '#/components/responses/UnauthorizedError'
         403:
           $ref: '#/components/responses/403'
+        404:
+          $ref: '#/components/responses/404'
         409:
           $ref: '#/components/responses/409'
         413:
@@ -220,7 +224,11 @@ paths:
         - $ref: '#/components/parameters/projectQuery'
         - $ref: '#/components/parameters/page'
         - $ref: '#/components/parameters/limit'
-        - $ref: '#/components/parameters/sortQuery'
+        - name: sort
+          in: query
+          description: sort direction (default 'platform_id, desc')
+          schema:
+            type: string
       responses:
         200:
           $ref: '#/components/responses/getArrayPlatform'
@@ -331,6 +339,8 @@ paths:
       responses:
         200:
           $ref: '#/components/responses/getArrayUser'
+        400:
+          $ref: '#/components/responses/400'
         401:
           $ref: '#/components/responses/UnauthorizedError'
       security: 
@@ -426,6 +436,8 @@ paths:
           description: Unable to delete. Data is used.
         401:
           $ref: '#/components/responses/UnauthorizedError'
+        403:
+          $ref: '#/components/responses/403'
         404:
           $ref: '#/components/responses/404'
       security: 
@@ -599,12 +611,14 @@ components:
       description: Number of records to return (default 3)
       schema:
         type: number
+        minimum: 1
     page:
       name: page
       in: query
       description: Number of page to return (default 0)
       schema:
         type: number
+        minimum: 0
     roleQuery:
       name: role
       in: query