|
@@ -0,0 +1,368 @@
|
|
|
|
+package com.swagger.rest.controllers
|
|
|
|
+
|
|
|
|
+import com.swagger.rest.models.Bug
|
|
|
|
+import com.swagger.rest.models.BugInput
|
|
|
|
+import com.swagger.rest.models.BugOutput
|
|
|
|
+import com.swagger.rest.models.Enum
|
|
|
|
+import com.swagger.rest.repositories.*
|
|
|
|
+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
|
|
|
|
+import org.springframework.web.bind.annotation.*
|
|
|
|
+import java.text.SimpleDateFormat
|
|
|
|
+import java.util.*
|
|
|
|
+import java.util.regex.Pattern
|
|
|
|
+
|
|
|
|
+@RestController
|
|
|
|
+@RequestMapping("/api/v1")
|
|
|
|
+class BugController(
|
|
|
|
+ private val bugRepository: BugRepository,
|
|
|
|
+ private val userRepository: UserRepository,
|
|
|
|
+ private val platformRepository: PlatformRepository,
|
|
|
|
+ private val commentRepository: CommentRepository,
|
|
|
|
+ private val memberRepository: MemberRepository
|
|
|
|
+) {
|
|
|
|
+
|
|
|
|
+ private fun regex(input: String): Boolean {
|
|
|
|
+// "(http:\\/\\/|https:\\/\\/)?(www.)?([a-zA-Z0-9]+).[a-zA-Z0-9]*.[a-z]{3}.?([a-z]+)?"
|
|
|
|
+// "^(http:\\/\\/|https:\\/\\/)?(www.)?([a-zA-Z0-9]+).[a-zA-Z0-9]*.[a-z]{3}.?([a-z]+)?\$"
|
|
|
|
+// "(https:\/\/www\.|http:\/\/www\.|https:\/\/|http:\/\/)?[a-zA-Z0-9]{2,}(\.[a-zA-Z0-9]{2,})(\.[a-zA-Z0-9]{2,})?"
|
|
|
|
+// "(https:\/\/www\.|http:\/\/www\.|https:\/\/|http:\/\/)?[a-zA-Z0-9]{2,}(\.[a-zA-Z0-9]{2,})(\.[a-zA-Z0-9]{2,})?\/[a-zA-Z0-9]{2,}"
|
|
|
|
+// "(https:\/\/www\.|http:\/\/www\.|https:\/\/|http:\/\/)?[a-zA-Z0-9]{2,}\.[a-zA-Z0-9]{2,}\.[a-zA-Z0-9]{2,}(\.[a-zA-Z0-9]{2,})?"
|
|
|
|
+// "(https:\/\/www\.|http:\/\/www\.|https:\/\/|http:\/\/)?[a-zA-Z]{2,}(\.[a-zA-Z]{2,})(\.[a-zA-Z]{2,})?\/[a-zA-Z0-9]{2,}|((https:\/\/www\.|http:\/\/www\.|https:\/\/|http:\/\/)?[a-zA-Z]{2,}(\.[a-zA-Z]{2,})(\.[a-zA-Z]{2,})?)|(https:\/\/www\.|http:\/\/www\.|https:\/\/|http:\/\/)?[a-zA-Z0-9]{2,}\.[a-zA-Z0-9]{2,}\.[a-zA-Z0-9]{2,}(\.[a-zA-Z0-9]{2,})?"
|
|
|
|
+
|
|
|
|
+ val regex = "(http://|https://)?(www.)?([a-zA-Z0-9]+).[a-zA-Z0-9]*.[a-z]{3}.?([a-z]+)?"
|
|
|
|
+ val pattern = Pattern.compile(regex, Pattern.MULTILINE)
|
|
|
|
+ val matcher = pattern.matcher(input)
|
|
|
|
+ var ret = false
|
|
|
|
+ while (matcher.find()) {
|
|
|
|
+ ret = true
|
|
|
|
+ }
|
|
|
|
+ return ret
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ private fun getSortDirection(direction: String): Sort.Direction {
|
|
|
|
+ if (direction == "asc") {
|
|
|
|
+ return Sort.Direction.ASC
|
|
|
|
+ } else if (direction == "desc") {
|
|
|
|
+ return Sort.Direction.DESC
|
|
|
|
+ }
|
|
|
|
+ return Sort.Direction.ASC
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @GetMapping("/bugs")
|
|
|
|
+ fun getBug(
|
|
|
|
+ @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()
|
|
|
|
+ val column = listOf(
|
|
|
|
+ "id",
|
|
|
|
+ "created",
|
|
|
|
+ "description",
|
|
|
|
+ "qc",
|
|
|
|
+ "dev",
|
|
|
|
+ "platform",
|
|
|
|
+ "goodday_url",
|
|
|
|
+ "image_url",
|
|
|
|
+ "level",
|
|
|
|
+ "status",
|
|
|
|
+ "dev_status"
|
|
|
|
+ )
|
|
|
|
+ val sort2 = if (!sort.contains(",")) {
|
|
|
|
+ sort + ",desc"
|
|
|
|
+ } else {
|
|
|
|
+ sort
|
|
|
|
+ }
|
|
|
|
+ if (!column.contains(sort2[0])) {
|
|
|
|
+ ResponseEntity<Bug>(HttpStatus.BAD_REQUEST)
|
|
|
|
+ } else {
|
|
|
|
+ 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 bugs = bugRepository.findAll(pagingSort)
|
|
|
|
+ val output = bugs.map {
|
|
|
|
+ BugOutput(
|
|
|
|
+ id = it.id,
|
|
|
|
+ created = SimpleDateFormat("dd-MM-yyyy").format(it.created),
|
|
|
|
+ description = it.description.trim(),
|
|
|
|
+ qc = it.qc!!.name,
|
|
|
|
+ dev = it.dev!!.name,
|
|
|
|
+ platform = it.platform!!.name,
|
|
|
|
+ goodday_url = it.goodday_url,
|
|
|
|
+ image_url = it.image_url,
|
|
|
|
+ level = Enum.Level.values()[it.level],
|
|
|
|
+ status = Enum.Status.values()[it.status],
|
|
|
|
+ dev_status = Enum.Dev_Status.values()[it.dev_status]
|
|
|
|
+ )
|
|
|
|
+ }
|
|
|
|
+ val ret = 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>()
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ } catch (e: Exception) {
|
|
|
|
+ e.printStackTrace()
|
|
|
|
+ ResponseEntity(e, HttpStatus.INTERNAL_SERVER_ERROR)
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @GetMapping("/bugs/{id}")
|
|
|
|
+ fun getBugById(@PathVariable("id") id: Long): Any {
|
|
|
|
+ val bugData = bugRepository.findById(id)
|
|
|
|
+ val output = bugData.map {
|
|
|
|
+ BugOutput(
|
|
|
|
+ id = it.id,
|
|
|
|
+ created = SimpleDateFormat("dd-MM-yyyy").format(it.created),
|
|
|
|
+ description = it.description.trim(),
|
|
|
|
+ qc = it.qc!!.name,
|
|
|
|
+ dev = it.dev!!.name,
|
|
|
|
+ platform = it.platform!!.name,
|
|
|
|
+ goodday_url = it.goodday_url,
|
|
|
|
+ image_url = it.image_url,
|
|
|
|
+ level = Enum.Level.values()[it.level],
|
|
|
|
+ status = Enum.Status.values()[it.status],
|
|
|
|
+ dev_status = Enum.Dev_Status.values()[it.dev_status]
|
|
|
|
+ )
|
|
|
|
+ }
|
|
|
|
+ return if (bugData.isPresent) {
|
|
|
|
+ ResponseEntity<BugOutput>(output.get(), HttpStatus.OK)
|
|
|
|
+ } else {
|
|
|
|
+ ResponseEntity<BugOutput>(HttpStatus.NOT_FOUND)
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @PostMapping("/bugs")
|
|
|
|
+ fun addBug(@RequestBody bugInput: BugInput): Any {
|
|
|
|
+ return try {
|
|
|
|
+ val specBug = Specification<Bug> { root, _, builder ->
|
|
|
|
+ val list: MutableList<Predicate> = mutableListOf()
|
|
|
|
+ list.add(builder.equal(root.get<Bug>("description"), bugInput.description.trim()))
|
|
|
|
+ builder.and(*list.toTypedArray())
|
|
|
|
+ }
|
|
|
|
+ val found = bugRepository.count(specBug)
|
|
|
|
+ val userId = userRepository.getUserByUsername(SecurityContextHolder.getContext().authentication.name)
|
|
|
|
+ val countPlat = platformRepository.findPlatform2(userId.id.toString(), bugInput.platform)
|
|
|
|
+ val countQc = userRepository.findById(bugInput.qc)
|
|
|
|
+ val countDev = userRepository.findById(bugInput.dev)
|
|
|
|
+ if (!enumValues<Enum.Level>().any {
|
|
|
|
+ it.name == bugInput.level.uppercase()
|
|
|
|
+ } || !enumValues<Enum.Status>().any {
|
|
|
|
+ it.name == bugInput.status.uppercase()
|
|
|
|
+ } || !enumValues<Enum.Dev_Status>().any { it.name == bugInput.dev_status.uppercase() }) {
|
|
|
|
+ ResponseEntity(HttpStatus.BAD_REQUEST)
|
|
|
|
+ } else if (!regex(bugInput.goodday_url) || !regex(bugInput.image_url)) {
|
|
|
|
+ ResponseEntity(HttpStatus.BAD_REQUEST)
|
|
|
|
+ } else if (countPlat == 0 || countQc.isEmpty || countDev.isEmpty) {
|
|
|
|
+ ResponseEntity(HttpStatus.NOT_FOUND)
|
|
|
|
+ } else if (bugInput.description.isNotBlank()) {
|
|
|
|
+ val foundPlat = platformRepository.findPlatform(userId.id.toString(), bugInput.platform)
|
|
|
|
+ val qc = userRepository.findById(bugInput.qc).get()
|
|
|
|
+ val dev = userRepository.findById(bugInput.dev).get()
|
|
|
|
+ if (bugInput.description.length > 500) {//too long
|
|
|
|
+ ResponseEntity(HttpStatus.PAYLOAD_TOO_LARGE)
|
|
|
|
+ } else if (found > 0) {//duplicate
|
|
|
|
+ ResponseEntity(HttpStatus.CONFLICT)
|
|
|
|
+ } else {
|
|
|
|
+ val saveBug = Bug()
|
|
|
|
+ saveBug.created = Date()
|
|
|
|
+ saveBug.description = bugInput.description.trim()
|
|
|
|
+ saveBug.qc = qc
|
|
|
|
+ saveBug.dev = dev
|
|
|
|
+ saveBug.platform = foundPlat
|
|
|
|
+ saveBug.goodday_url = bugInput.goodday_url.trim()
|
|
|
|
+ saveBug.image_url = bugInput.image_url.trim()
|
|
|
|
+ saveBug.level = Enum.Level.valueOf(bugInput.level.uppercase()).ordinal
|
|
|
|
+ saveBug.status = Enum.Status.valueOf(bugInput.status.uppercase()).ordinal
|
|
|
|
+ saveBug.dev_status = Enum.Dev_Status.valueOf(bugInput.dev_status.uppercase()).ordinal
|
|
|
|
+ val save = bugRepository.save(saveBug)
|
|
|
|
+ if (listOf(save).isNotEmpty()) {
|
|
|
|
+ val output = BugOutput(
|
|
|
|
+ id = save.id,
|
|
|
|
+ created = SimpleDateFormat("dd-MM-yyyy").format(save.created),
|
|
|
|
+ description = save.description.trim(),
|
|
|
|
+ qc = save.qc!!.name,
|
|
|
|
+ dev = save.dev!!.name,
|
|
|
|
+ platform = save.platform!!.name,
|
|
|
|
+ goodday_url = save.goodday_url,
|
|
|
|
+ image_url = save.image_url,
|
|
|
|
+ level = Enum.Level.values()[save.level],
|
|
|
|
+ status = Enum.Status.values()[save.status],
|
|
|
|
+ dev_status = Enum.Dev_Status.values()[save.dev_status]
|
|
|
|
+ )
|
|
|
|
+ ResponseEntity(output, HttpStatus.CREATED)
|
|
|
|
+ } else {
|
|
|
|
+ ResponseEntity(null, HttpStatus.INTERNAL_SERVER_ERROR)
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ } else {//invalid
|
|
|
|
+ ResponseEntity(HttpStatus.BAD_REQUEST)
|
|
|
|
+ }
|
|
|
|
+ } catch (e: Exception) {
|
|
|
|
+ e.printStackTrace()
|
|
|
|
+ ResponseEntity(e, HttpStatus.INTERNAL_SERVER_ERROR)
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ private fun validColumn(id: Long, bugInput: BugInput): Boolean {
|
|
|
|
+ val userId = userRepository.getUserByUsername(SecurityContextHolder.getContext().authentication.name)
|
|
|
|
+ val role = memberRepository.getRole(userId.id.toString(), bugInput.platform)
|
|
|
|
+ val roleEnum =
|
|
|
|
+ if (Enum.Member.values().any { it.ordinal == role }) Enum.Member.values()[role] else Enum.Member.UNDEFINED
|
|
|
|
+ val valid = bugRepository.validOwnerAdmin(userId.id.toString())
|
|
|
|
+ val bugData: Bug = bugRepository.findById(id).get()
|
|
|
|
+ var col = arrayOf<Number>()
|
|
|
|
+ if (bugInput.description.trim() !== bugData.description.trim()) { //col += "description,"
|
|
|
|
+ col += 1
|
|
|
|
+ }
|
|
|
|
+ if (userRepository.findById(bugInput.qc).get().name !== bugData.qc!!.name) {//col += "qc,"
|
|
|
|
+ col += 2
|
|
|
|
+ }
|
|
|
|
+ if (userRepository.findById(bugInput.dev).get().name !== bugData.dev!!.name) {//col += "dev,"
|
|
|
|
+ col += 3
|
|
|
|
+ }
|
|
|
|
+ if (bugInput.platform.trim() !== bugData.platform!!.name) {//col += "platform,"
|
|
|
|
+ col += 4
|
|
|
|
+ }
|
|
|
|
+ if (bugInput.goodday_url.trim() !== bugData.goodday_url.trim()) {//col += "goodday_url,"
|
|
|
|
+ col += 5
|
|
|
|
+ }
|
|
|
|
+ if (bugInput.image_url.trim() !== bugData.image_url.trim()) {//col += "image_url,"
|
|
|
|
+ col += 6
|
|
|
|
+ }
|
|
|
|
+ if (Enum.Level.values()[bugData.level] !== Enum.Level.valueOf(bugInput.level.uppercase())) {//col += "level,"
|
|
|
|
+ col += 6
|
|
|
|
+ }
|
|
|
|
+ if (Enum.Status.values()[bugData.status] !== Enum.Status.valueOf(bugInput.status.uppercase())) {//col += "level,"
|
|
|
|
+ col += 7
|
|
|
|
+ }
|
|
|
|
+ if (Enum.Dev_Status.values()[bugData.dev_status] !== Enum.Dev_Status.valueOf(bugInput.dev_status.uppercase())) {//col += "level,"
|
|
|
|
+ col += 8
|
|
|
|
+ }
|
|
|
|
+ var ret = false
|
|
|
|
+ if (roleEnum == Enum.Member.PROGRAMMER && col.contains(9)) {
|
|
|
|
+ ret = true
|
|
|
|
+ }
|
|
|
|
+ if (roleEnum == Enum.Member.QC && (col.contains(6) || col.contains(7) || col.contains(8))) {
|
|
|
|
+ ret = true
|
|
|
|
+ }
|
|
|
|
+ if (roleEnum == Enum.Member.ADMIN || valid > 0) {
|
|
|
|
+ ret = true
|
|
|
|
+ }
|
|
|
|
+ return ret
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @PutMapping("/bugs/{id}")
|
|
|
|
+ fun updateBugById(@PathVariable("id") id: Long, @RequestBody bugInput: BugInput): ResponseEntity<out Any> {
|
|
|
|
+ val bugData = bugRepository.findById(id)
|
|
|
|
+ val specBug = Specification<Bug> { root, _, builder ->
|
|
|
|
+ val list: MutableList<Predicate> = mutableListOf()
|
|
|
|
+ list.add(builder.equal(root.get<Bug>("description"), bugInput.description.trim()))
|
|
|
|
+ builder.and(*list.toTypedArray())
|
|
|
|
+ }
|
|
|
|
+ val found = bugRepository.count(specBug)
|
|
|
|
+ val userId = userRepository.getUserByUsername(SecurityContextHolder.getContext().authentication.name)
|
|
|
|
+ val countPlat = platformRepository.findPlatform2(userId.id.toString(), bugInput.platform.trim())
|
|
|
|
+ val countQc = userRepository.findById(bugInput.qc)
|
|
|
|
+ val countDev = userRepository.findById(bugInput.dev)
|
|
|
|
+ return if (bugData.isPresent && countPlat > 0 && countQc.isPresent && countDev.isPresent) {
|
|
|
|
+ val foundPlat = platformRepository.findPlatform(userId.id.toString(), bugInput.platform.trim())
|
|
|
|
+ val qc = userRepository.findById(bugInput.qc).get()
|
|
|
|
+ val dev = userRepository.findById(bugInput.dev).get()
|
|
|
|
+ if (validColumn(id, bugInput)) {
|
|
|
|
+ if (bugInput.description.isNotBlank()) {
|
|
|
|
+ if (bugInput.description.length > 500) {//too long
|
|
|
|
+ ResponseEntity<Bug>(HttpStatus.PAYLOAD_TOO_LARGE)
|
|
|
|
+ } else {
|
|
|
|
+ if ((bugInput.description == bugData.get().description && found > 0) || (bugInput.description !== bugData.get().description && found.toInt() == 0)) {
|
|
|
|
+ val saveBug = bugData.get()
|
|
|
|
+ saveBug.description = bugInput.description.trim()
|
|
|
|
+ saveBug.qc = qc
|
|
|
|
+ saveBug.dev = dev
|
|
|
|
+ saveBug.platform = foundPlat
|
|
|
|
+ saveBug.goodday_url = bugInput.goodday_url.trim()
|
|
|
|
+ saveBug.image_url = bugInput.image_url.trim()
|
|
|
|
+ saveBug.level = Enum.Level.valueOf(bugInput.level.uppercase()).ordinal
|
|
|
|
+ saveBug.status = Enum.Status.valueOf(bugInput.status.uppercase()).ordinal
|
|
|
|
+ saveBug.dev_status = Enum.Dev_Status.valueOf(bugInput.dev_status.uppercase()).ordinal
|
|
|
|
+ val save = bugRepository.save(saveBug)
|
|
|
|
+ if (listOf(save).isNotEmpty()) {
|
|
|
|
+ val output = BugOutput(
|
|
|
|
+ id = save.id,
|
|
|
|
+ description = save.description.trim(),
|
|
|
|
+ qc = save.qc!!.name,
|
|
|
|
+ dev = save.dev!!.name,
|
|
|
|
+ platform = save.platform!!.name,
|
|
|
|
+ goodday_url = save.goodday_url,
|
|
|
|
+ image_url = save.image_url,
|
|
|
|
+ level = Enum.Level.values()[save.level],
|
|
|
|
+ status = Enum.Status.values()[save.status],
|
|
|
|
+ dev_status = Enum.Dev_Status.values()[save.dev_status]
|
|
|
|
+ )
|
|
|
|
+ ResponseEntity<Any>(output, HttpStatus.OK)
|
|
|
|
+ } else {
|
|
|
|
+ ResponseEntity<Any>(null, HttpStatus.INTERNAL_SERVER_ERROR)
|
|
|
|
+ }
|
|
|
|
+ } else {//duplicate
|
|
|
|
+ ResponseEntity<Bug>(HttpStatus.CONFLICT)
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ } else {//invalid
|
|
|
|
+ ResponseEntity<Bug>(HttpStatus.BAD_REQUEST)
|
|
|
|
+ }
|
|
|
|
+ } else {
|
|
|
|
+ ResponseEntity<Bug>(HttpStatus.FORBIDDEN)
|
|
|
|
+ }
|
|
|
|
+ } else {
|
|
|
|
+ ResponseEntity<Bug>(HttpStatus.NOT_FOUND)
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @DeleteMapping("/bugs/{id}")
|
|
|
|
+ fun deleteBugById(@PathVariable("id") id: Long): ResponseEntity<HttpStatus> {
|
|
|
|
+ val find = bugRepository.findById(id)
|
|
|
|
+ val used = commentRepository.findByBug(id.toString())
|
|
|
|
+ val userId = userRepository.getUserByUsername(SecurityContextHolder.getContext().authentication.name)
|
|
|
|
+ val validOwnerAdmin = bugRepository.validOwnerAdmin(userId.id.toString())
|
|
|
|
+ return try {
|
|
|
|
+ if (validOwnerAdmin > 0) {
|
|
|
|
+ if (used > 0) {//child used in transaction
|
|
|
|
+ ResponseEntity(HttpStatus.RESET_CONTENT)
|
|
|
|
+ } else if (find.isPresent) {
|
|
|
|
+ bugRepository.deleteById(id)
|
|
|
|
+ ResponseEntity(HttpStatus.OK)
|
|
|
|
+ } else {//bug not found
|
|
|
|
+ ResponseEntity(HttpStatus.NOT_FOUND)
|
|
|
|
+ }
|
|
|
|
+ } else {
|
|
|
|
+ ResponseEntity(HttpStatus.FORBIDDEN)
|
|
|
|
+ }
|
|
|
|
+ } catch (e: Exception) {
|
|
|
|
+ ResponseEntity(HttpStatus.INTERNAL_SERVER_ERROR)
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+}
|