Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Live view parameter #146

Merged
merged 4 commits into from
Nov 9, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ jobs:
- name: Grant execute permission for gradlew
run: chmod +x gradlew
- name: Test with Gradle
run: ./gradlew --stacktrace --info check generateOpenApiDocs
run: ./gradlew --stacktrace --info check
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Upload coverage
Expand Down
Original file line number Diff line number Diff line change
@@ -1,16 +1,29 @@
package com.katalisindonesia.banyuwangi.controller

import au.com.console.jpaspecificationdsl.and
import au.com.console.jpaspecificationdsl.equal
import au.com.console.jpaspecificationdsl.`in`
import au.com.console.jpaspecificationdsl.like
import au.com.console.jpaspecificationdsl.or
import com.katalisindonesia.banyuwangi.model.Camera
import com.katalisindonesia.banyuwangi.model.DetectionType
import com.katalisindonesia.banyuwangi.repo.CameraRepo
import io.swagger.v3.oas.annotations.Operation
import io.swagger.v3.oas.annotations.responses.ApiResponse
import io.swagger.v3.oas.annotations.responses.ApiResponses
import io.swagger.v3.oas.annotations.security.SecurityRequirement
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.ResponseEntity
import org.springframework.security.access.prepost.PreAuthorize
import org.springframework.web.bind.annotation.GetMapping
import org.springframework.web.bind.annotation.RequestMapping
import org.springframework.web.bind.annotation.RequestParam
import org.springframework.web.bind.annotation.RestController
import java.util.UUID
import javax.validation.constraints.Min

@RestController
@RequestMapping("/v1/live")
Expand All @@ -36,18 +49,129 @@ class LiveViewController(
),
]
)
@GetMapping("/camera")
@GetMapping("/camera", "/camera/list")
@PreAuthorize("hasAuthority('camera:liveview')")
fun list(): ResponseEntity<WebResponse<List<LiveCamera>>> {
fun list(
@RequestParam(required = false) keyword: String?,

@Min(0) @RequestParam(required = false, defaultValue = "0") page: Int,
@Min(1) @RequestParam(required = false, defaultValue = "1000") size: Int,
@RequestParam(required = false, name = "location") locations: Set<String>?,
@RequestParam(required = false, name = "id") ids: Set<UUID>?,
@RequestParam(required = false, name = "type") types: Set<DetectionType>?,
): ResponseEntity<WebResponse<List<LiveCamera>>> {
return ResponseEntity.ok(
WebResponse(
success = true,
message = "ok",
data =
cameraRepo.findWithIsActive(true, Pageable.unpaged())
.toList()
cameraRepo.findAll(
and(
specs(
keyword = keyword,
locations = locations,
ids = ids,
types = types,
)
),
PageRequest.of(
page, size, Sort.by(Camera::name.name).ascending()
)
)
.map { LiveCamera(it) }
)
)
}

@GetMapping("/camera/count")
@PreAuthorize("hasAuthority('camera:liveview')")
fun count(
@RequestParam(required = false) keyword: String?,

@RequestParam(required = false, name = "location") locations: Set<String>?,
@RequestParam(required = false, name = "id") ids: Set<UUID>?,
@RequestParam(required = false, name = "type") types: Set<DetectionType>?,

): ResponseEntity<WebResponse<Long>> {
return ResponseEntity.ok(
WebResponse(
success = true,
message = "ok",
data =
cameraRepo.countAll(
and(
specs(
keyword = keyword,
locations = locations,
ids = ids,
types = types,
)
)
)
)
)
}

@GetMapping("/location/list")
@PreAuthorize("hasAuthority('camera:liveview')")
fun locations(
@RequestParam(required = false) keyword: String?,
@Min(0) @RequestParam(required = false, defaultValue = "0") page: Int,
@Min(1) @RequestParam(required = false, defaultValue = "1000") size: Int,
): ResponseEntity<WebResponse<List<String>>> {
return ResponseEntity.ok(
WebResponse(
success = true,
message = "ok",
data = cameraRepo.findCameraLocations(
keyword = keyword?.wrapWithPercent() ?: "",
pageable = Pageable.ofSize(size).withPage(page)
)
)
)
}

private fun specs(
keyword: String?,

locations: Set<String>?,
ids: Set<UUID>?,
types: Set<DetectionType>?,
): List<Specification<Camera>> {
val list = mutableListOf<Specification<Camera>>()
if (keyword != null) {
val keywordSpecs = or(
Camera::name.like(keyword.wrapWithPercent()),
Camera::location.like(keyword.wrapWithPercent()),
Camera::vmsCameraIndexCode.like(keyword.wrapWithPercent()),
)
list.add(keywordSpecs)
}
if (!locations.isNullOrEmpty()) {
list.add(Camera::location.`in`(locations))
}

if (!ids.isNullOrEmpty()) {
list.add(Camera::id.`in`(ids))
}
if (!types.isNullOrEmpty()) {
val map = mapOf(
DetectionType.FLOOD to Camera::isFlood,
DetectionType.CROWD to Camera::isCrowd,
DetectionType.STREETVENDOR to Camera::isStreetvendor,
DetectionType.TRASH to Camera::isTrash,
DetectionType.TRAFFIC to Camera::isTraffic,
)
list.addAll(
types.mapNotNull { map[it] }
.map { it.equal(true) }
)
}

list.add(Camera::isActive.equal(true))

return list
}
}

fun String.wrapWithPercent(): String = "%$this%"
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,5 @@ interface BaseRepository<T, ID : Serializable?> : JpaRepository<T, ID> {
fun findAll(spec: Specification<T>, offset: Long, maxResults: Int, sort: Sort): List<T>
fun findAll(spec: Specification<T>, offset: Long, maxResults: Int): List<T>
fun findAll(spec: Specification<T>, pageable: Pageable): List<T>
fun countAll(spec: Specification<T>): Long
}
Original file line number Diff line number Diff line change
Expand Up @@ -37,4 +37,8 @@ class BaseRepositoryImpl<T, ID : Serializable?> : SimpleJpaRepository<T, ID>, Ba
query.maxResults = maxResults
return query.resultList
}

override fun countAll(spec: Specification<T>): Long {
return super.count(spec)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,6 @@ package com.katalisindonesia.banyuwangi.repo
import com.katalisindonesia.banyuwangi.model.Camera
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.Modifying
import org.springframework.data.jpa.repository.Query
import org.springframework.stereotype.Repository
Expand All @@ -13,7 +11,7 @@ import java.util.Optional
import java.util.UUID

@Repository
interface CameraRepo : JpaRepository<Camera, UUID>, JpaSpecificationExecutor<Camera> {
interface CameraRepo : BaseRepository<Camera, UUID> {

fun getCameraByVmsCameraIndexCode(vmsCameraIndexCode: String): Optional<Camera>

Expand All @@ -38,4 +36,11 @@ interface CameraRepo : JpaRepository<Camera, UUID>, JpaSpecificationExecutor<Cam
"and t.face=:face order by t.vmsCameraIndexCode"
)
fun findVmsCameraIndexCodeWithFace(face: Boolean): List<String>

@Query(
"select distinct t.location from Camera t " +
"where t.location is not null " +
"and (:keyword ='' or t.location like :keyword) order by t.location"
)
fun findCameraLocations(keyword: String, pageable: Pageable): List<String>
}
Original file line number Diff line number Diff line change
@@ -1,12 +1,16 @@
package com.katalisindonesia.banyuwangi.streaming

import com.burgstaller.okhttp.AuthenticationCacheInterceptor
import mu.KotlinLogging
import okhttp3.OkHttpClient
import okhttp3.logging.HttpLoggingInterceptor
import retrofit2.Retrofit
import retrofit2.converter.scalars.ScalarsConverterFactory
import java.util.concurrent.ConcurrentHashMap
import java.util.concurrent.TimeUnit

private val log = KotlinLogging.logger { }

private const val DEFAULT_TIMEOUT = 60L
internal object RetrofitConfig {

Expand All @@ -15,13 +19,21 @@ internal object RetrofitConfig {
// user: String,
// password: String
): Retrofit {
val interceptor = HttpLoggingInterceptor { message -> log.debug { message } }
if (log.isDebugEnabled) {
interceptor.level = HttpLoggingInterceptor.Level.BODY
} else {
interceptor.level = HttpLoggingInterceptor.Level.BASIC
}

// val authenticator = DigestAuthenticator(Credentials(user, password))

// val gson = GsonBuilder()
// .setLenient()
// .create()

val okHttpClient = OkHttpClient.Builder()
.addInterceptor(interceptor)
// .authenticator(CachingAuthenticatorDecorator(authenticator, authCache))
.addInterceptor(AuthenticationCacheInterceptor(ConcurrentHashMap()))
.readTimeout(DEFAULT_TIMEOUT, TimeUnit.SECONDS)
Expand Down
Loading