2848 lines
173 KiB
Kotlin
2848 lines
173 KiB
Kotlin
package web
|
|
|
|
import StreamerOutputs
|
|
import barix.BarixConnection
|
|
import codes.Somecodes
|
|
import codes.Somecodes.Companion.GetAppUpTime
|
|
import codes.Somecodes.Companion.GetSensorsInfo
|
|
import codes.Somecodes.Companion.GetUptime
|
|
import codes.Somecodes.Companion.ListAudioFiles
|
|
import codes.Somecodes.Companion.String_To_List
|
|
import codes.Somecodes.Companion.ValiDateForLogHtml
|
|
import codes.Somecodes.Companion.ValidDirectory
|
|
import codes.Somecodes.Companion.ValidFile
|
|
import codes.Somecodes.Companion.ValidIPV4
|
|
import codes.Somecodes.Companion.ValidScheduleDay
|
|
import codes.Somecodes.Companion.ValidScheduleTime
|
|
import codes.Somecodes.Companion.ValidString
|
|
import codes.Somecodes.Companion.ValidStrings
|
|
import codes.Somecodes.Companion.datetimeformat1
|
|
import codes.configFile
|
|
import com.fasterxml.jackson.databind.JsonNode
|
|
import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper
|
|
import content.Category
|
|
import content.Language
|
|
import content.ScheduleDay
|
|
import content.VoiceType
|
|
import database.data.BroadcastZones
|
|
import database.data.LanguageLink
|
|
import database.MariaDB
|
|
import database.data.Messagebank
|
|
import database.data.ScheduleBank
|
|
import database.data.SoundChannel
|
|
import database.data.Soundbank
|
|
import database.data.UserDB
|
|
import db
|
|
import io.javalin.Javalin
|
|
import io.javalin.apibuilder.ApiBuilder.*
|
|
import io.javalin.http.Context
|
|
import io.javalin.json.JavalinJackson
|
|
import io.javalin.websocket.WsMessageContext
|
|
import org.apache.poi.xssf.usermodel.XSSFWorkbook
|
|
import java.nio.file.Files
|
|
import java.time.LocalDateTime
|
|
import codes.configKeys
|
|
import config
|
|
import database.data.LogSemiauto
|
|
import database.data.QueueTable
|
|
import google.GoogleTTS
|
|
import google.autoadd
|
|
import google.fileoperation
|
|
import io.javalin.websocket.WsCloseStatus
|
|
import org.tinylog.Logger
|
|
import version
|
|
import java.io.File
|
|
import java.nio.ByteBuffer
|
|
import java.nio.file.Path
|
|
import java.util.UUID
|
|
|
|
|
|
@Suppress("unused")
|
|
class WebApp(val listenPort: Int, var userlist: List<Pair<String, String>>, val _config: configFile) {
|
|
|
|
lateinit var app: Javalin
|
|
lateinit var semiauto: Javalin
|
|
val objectmapper = jacksonObjectMapper()
|
|
val WsContextMap = mutableMapOf<String, LiveListenData>()
|
|
val ttsjob = GoogleTTS()
|
|
|
|
private fun SendReply(context: WsMessageContext, command: String, value: String) {
|
|
try {
|
|
if (context.session.isOpen) {
|
|
context.send(objectmapper.writeValueAsString(WebsocketReply(command, value)))
|
|
}
|
|
} catch (_: Exception) {
|
|
}
|
|
}
|
|
|
|
fun Start() {
|
|
Start_WebServer()
|
|
Start_SemiAutoServer()
|
|
|
|
}
|
|
|
|
private fun Start_WebServer() {
|
|
Logger.info { "Starting Web Application on port $listenPort" }
|
|
app = Javalin.create { config ->
|
|
config.useVirtualThreads = true
|
|
config.staticFiles.add("/webpage")
|
|
config.jsonMapper(JavalinJackson(jacksonObjectMapper()))
|
|
config.router.apiBuilder {
|
|
before {
|
|
//Logger.info {"${it.ip()} connecting ${it.method()} to ${it.path()}"}
|
|
}
|
|
path("/") {
|
|
get { ctx ->
|
|
// Serve the main page
|
|
ctx.cookie("aas-user", "")
|
|
//ctx.sessionAttribute("user", null) // Clear user session
|
|
ctx.redirect("login.html")
|
|
}
|
|
|
|
}
|
|
path("logout") {
|
|
get { ctx ->
|
|
ctx.cookie("aas-user", "")
|
|
//ctx.sessionAttribute<String>("user", null) // Clear user session
|
|
ctx.redirect("login.html")
|
|
}
|
|
}
|
|
path("login.html") {
|
|
post { it ->
|
|
// get username and password from form
|
|
val username = it.formParam("username")
|
|
val password = it.formParam("password")
|
|
if (username == null || password == null) {
|
|
it.status(400)
|
|
.result(objectmapper.writeValueAsString(resultMessage("Username and password are required")))
|
|
return@post
|
|
}
|
|
// Check if user exists in userlist
|
|
val user = userlist.find { it.first == username && it.second == password }
|
|
if (user == null) {
|
|
it.status(401)
|
|
.result(objectmapper.writeValueAsString(resultMessage("Invalid username or password")))
|
|
return@post
|
|
}
|
|
// Set user session
|
|
//it.sessionAttribute("user", user.first)
|
|
it.cookie("aas-user", user.first)
|
|
// Redirect to home page
|
|
if (user.first == GetAdminUserFromConfig()) {
|
|
it.redirect("homeadmin.html")
|
|
} else {
|
|
it.redirect("homeviewer.html")
|
|
}
|
|
}
|
|
}
|
|
// home for admin user
|
|
path("homeadmin.html") {
|
|
before { CheckUsers(it) }
|
|
ws("/ws") { ws ->
|
|
// WebSocket endpoint for home
|
|
ws.onConnect {
|
|
it.enableAutomaticPings()
|
|
}
|
|
ws.onMessage { wsMessageContext ->
|
|
|
|
try {
|
|
val cmd =
|
|
objectmapper.readValue(wsMessageContext.message(), WebsocketCommand::class.java)
|
|
when (cmd.command) {
|
|
"getAppVersion" -> {
|
|
SendReply(wsMessageContext, cmd.command, version)
|
|
}
|
|
|
|
"getSystemTime" -> {
|
|
|
|
val systemtime = LocalDateTime.now().format(datetimeformat1)
|
|
val uptime = GetUptime()
|
|
val apptime = GetAppUpTime()
|
|
// create JSON object of systemtime, uptime and apptime
|
|
val timejson = objectmapper.writeValueAsString(
|
|
mapOf(
|
|
"systemtime" to systemtime,
|
|
"uptime" to uptime,
|
|
"apptime" to apptime
|
|
)
|
|
)
|
|
SendReply(
|
|
wsMessageContext,
|
|
cmd.command,
|
|
timejson
|
|
)
|
|
}
|
|
|
|
"getCPUStatus" -> {
|
|
Somecodes.getCPUUsage { vv ->
|
|
val sv = GetSensorsInfo()
|
|
if (sv.isNotEmpty()) {
|
|
SendReply(wsMessageContext, cmd.command, vv + "\n" + sv)
|
|
} else {
|
|
SendReply(wsMessageContext, cmd.command, vv)
|
|
}
|
|
}
|
|
}
|
|
|
|
"getMemoryStatus" -> {
|
|
SendReply(
|
|
wsMessageContext,
|
|
cmd.command,
|
|
objectmapper.writeValueAsString(Somecodes.getMemoryUsage())
|
|
)
|
|
}
|
|
|
|
"getDiskStatus" -> {
|
|
SendReply(
|
|
wsMessageContext,
|
|
cmd.command,
|
|
objectmapper.writeValueAsString(Somecodes.getDiskUsage())
|
|
)
|
|
}
|
|
|
|
"getNetworkStatus" -> {
|
|
Somecodes.GetNetworkStatus { nn ->
|
|
SendReply(
|
|
wsMessageContext,
|
|
cmd.command,
|
|
objectmapper.writeValueAsString(nn)
|
|
)
|
|
}
|
|
}
|
|
|
|
"getPagingQueue" -> {
|
|
SendReply(
|
|
wsMessageContext,
|
|
cmd.command,
|
|
objectmapper.writeValueAsString(db.queuepagingDB.List)
|
|
)
|
|
}
|
|
|
|
"getAASQueue" -> {
|
|
SendReply(
|
|
wsMessageContext,
|
|
cmd.command,
|
|
objectmapper.writeValueAsString(db.queuetableDB.List)
|
|
)
|
|
}
|
|
|
|
"getStreamerOutputs" -> {
|
|
val reply: List<StreamerOutputData> =
|
|
StreamerOutputs.map { so -> StreamerOutputData.fromBarixConnection(so.value) }
|
|
SendReply(wsMessageContext, cmd.command, objectmapper.writeValueAsString(reply))
|
|
}
|
|
|
|
"start_generate_tts" -> {
|
|
val js: JsonNode = objectmapper.readTree(cmd.data)
|
|
SendReply(wsMessageContext, cmd.command, "ok")
|
|
val voicetype = js.get("voicetype")?.asText("Wavenet-A") ?: "Wavenet-A"
|
|
val languagecode = js.get("languagecode")?.asText("id-ID") ?: "id-ID"
|
|
val databasesource = js.get("databasesource")?.asText("VOICE_1") ?: "VOICE_1"
|
|
val targetas = js.get("targetas")?.asText("VOICE_2") ?: "VOICE_2"
|
|
val fop = js.get("fileoperation")?.asText("overwrite") ?: "overwrite"
|
|
val aa = js.get("autoadd")?.asText("add") ?: "add"
|
|
Logger.info { "Starting TTS Soundbank Generation, VoiceType=$voicetype, Language" }
|
|
ttsjob.GenerateSoundbank(
|
|
voicetype, Language.from_GoogleTTSLanguage(languagecode)!!,
|
|
VoiceType.fromString(databasesource),
|
|
VoiceType.fromString(targetas), fileoperation.fromString(fop),
|
|
autoadd.fromString(aa)
|
|
) { progress, message ->
|
|
SendReply(
|
|
wsMessageContext,
|
|
"tts_generate_progress",
|
|
objectmapper.writeValueAsString(
|
|
mapOf(
|
|
"progress" to progress,
|
|
"message" to message
|
|
)
|
|
)
|
|
)
|
|
}
|
|
}
|
|
|
|
"stop_generate_tts" -> {
|
|
SendReply(wsMessageContext, cmd.command, "ok")
|
|
ttsjob.StopGenerate()
|
|
|
|
}
|
|
|
|
else -> {
|
|
SendReply(wsMessageContext, cmd.command, "Unknown command")
|
|
}
|
|
}
|
|
} catch (e: Exception) {
|
|
if (e.message != null && (e.message is String) && e.message!!.isNotEmpty()) {
|
|
Logger.error { "Error processing WebSocket message: ${e.message}" }
|
|
}
|
|
}
|
|
|
|
}
|
|
}
|
|
}
|
|
// home for viewer user
|
|
path("homeviewer.html") {
|
|
before { CheckUsers(it) }
|
|
ws("/ws") { ws ->
|
|
// WebSocket endpoint for home
|
|
ws.onConnect {
|
|
it.enableAutomaticPings()
|
|
}
|
|
ws.onMessage { wsMessageContext ->
|
|
|
|
try {
|
|
val cmd =
|
|
objectmapper.readValue(wsMessageContext.message(), WebsocketCommand::class.java)
|
|
when (cmd.command) {
|
|
"getSystemTime" -> {
|
|
val systemtime = LocalDateTime.now().format(datetimeformat1)
|
|
val uptime = GetUptime()
|
|
val apptime = GetAppUpTime()
|
|
// create JSON object of systemtime, uptime and apptime
|
|
val timejson = objectmapper.writeValueAsString(
|
|
mapOf(
|
|
"systemtime" to systemtime,
|
|
"uptime" to uptime,
|
|
"apptime" to apptime
|
|
)
|
|
)
|
|
|
|
SendReply(
|
|
wsMessageContext,
|
|
cmd.command,
|
|
timejson
|
|
)
|
|
}
|
|
|
|
"getCPUStatus" -> {
|
|
Somecodes.getCPUUsage { vv ->
|
|
val sv = GetSensorsInfo()
|
|
if (sv.isNotEmpty()) {
|
|
SendReply(wsMessageContext, cmd.command, vv + "\n" + sv)
|
|
} else {
|
|
SendReply(wsMessageContext, cmd.command, vv)
|
|
}
|
|
}
|
|
}
|
|
|
|
"getMemoryStatus" -> {
|
|
SendReply(
|
|
wsMessageContext,
|
|
cmd.command,
|
|
objectmapper.writeValueAsString(Somecodes.getMemoryUsage())
|
|
)
|
|
}
|
|
|
|
"getDiskStatus" -> {
|
|
SendReply(
|
|
wsMessageContext,
|
|
cmd.command,
|
|
objectmapper.writeValueAsString(Somecodes.getDiskUsage())
|
|
)
|
|
}
|
|
|
|
"getNetworkStatus" -> {
|
|
Somecodes.GetNetworkStatus { nn ->
|
|
SendReply(
|
|
wsMessageContext,
|
|
cmd.command,
|
|
objectmapper.writeValueAsString(nn)
|
|
)
|
|
}
|
|
}
|
|
|
|
"getPagingQueue" -> {
|
|
SendReply(
|
|
wsMessageContext,
|
|
cmd.command,
|
|
objectmapper.writeValueAsString(db.queuepagingDB.List)
|
|
)
|
|
}
|
|
|
|
"getAASQueue" -> {
|
|
SendReply(
|
|
wsMessageContext,
|
|
cmd.command,
|
|
objectmapper.writeValueAsString(db.queuetableDB.List)
|
|
)
|
|
}
|
|
|
|
"getStreamerOutputs" -> {
|
|
val reply: List<StreamerOutputData> =
|
|
StreamerOutputs.map { so -> StreamerOutputData.fromBarixConnection(so.value) }
|
|
SendReply(wsMessageContext, cmd.command, objectmapper.writeValueAsString(reply))
|
|
}
|
|
|
|
else -> {
|
|
SendReply(wsMessageContext, cmd.command, "Unknown command")
|
|
}
|
|
}
|
|
} catch (e: Exception) {
|
|
if (e.message != null && (e.message is String) && e.message!!.isNotEmpty()) {
|
|
Logger.error { "Error processing WebSocket message: ${e.message}" }
|
|
}
|
|
}
|
|
|
|
}
|
|
}
|
|
}
|
|
path("soundbank.html") {
|
|
before {
|
|
val user = CheckUsers(it)
|
|
// only admin user can access soundbank page
|
|
if (GetAdminUserFromConfig() != user) {
|
|
it.redirect("overview.html")
|
|
}
|
|
}
|
|
}
|
|
path("messagebank.html") {
|
|
before {
|
|
val user = CheckUsers(it)
|
|
// only admin user can access messagebank page
|
|
if (GetAdminUserFromConfig() != user) {
|
|
it.redirect("overview.html")
|
|
}
|
|
}
|
|
}
|
|
path("language.html") {
|
|
before {
|
|
val user = CheckUsers(it)
|
|
// only admin user can access language link page
|
|
if (GetAdminUserFromConfig() != user) {
|
|
it.redirect("overview.html")
|
|
}
|
|
}
|
|
}
|
|
path("log.html") {
|
|
before { CheckUsers(it) }
|
|
}
|
|
path("setting.html") {
|
|
before {
|
|
val user = CheckUsers(it)
|
|
// only admin user can access settings page
|
|
if (GetAdminUserFromConfig() != user) {
|
|
it.redirect("overview.html")
|
|
}
|
|
}
|
|
}
|
|
path("timer.html") {
|
|
before {
|
|
val user = CheckUsers(it)
|
|
// only admin user can access timer page
|
|
if (GetAdminUserFromConfig() != user) {
|
|
it.redirect("overview.html")
|
|
}
|
|
}
|
|
}
|
|
path("filemanagement.html") {
|
|
before {
|
|
val user = CheckUsers(it)
|
|
// only admin user can access file management page
|
|
if (GetAdminUserFromConfig() != user) {
|
|
it.redirect("overview.html")
|
|
}
|
|
}
|
|
}
|
|
path("broadcastzones.html") {
|
|
before {
|
|
val user = CheckUsers(it)
|
|
// only admin user can access broadcast zones page
|
|
if (GetAdminUserFromConfig() != user) {
|
|
it.redirect("overview.html")
|
|
}
|
|
}
|
|
}
|
|
path("overview.html") {
|
|
before { CheckUsers(it) }
|
|
}
|
|
|
|
path("streamerstatus.html") {
|
|
before { CheckUsers(it) }
|
|
}
|
|
|
|
path("usermanagement.html") {
|
|
before {
|
|
val user = CheckUsers(it)
|
|
// only admin user can access user management page
|
|
if (GetAdminUserFromConfig() != user) {
|
|
it.redirect("overview.html")
|
|
}
|
|
}
|
|
}
|
|
path("api") {
|
|
//TODO https://stackoverflow.com/questions/70002015/streaming-into-audio-element
|
|
path("LiveAudio") {
|
|
post { ctx ->
|
|
val json: JsonNode = objectmapper.readTree(ctx.body())
|
|
val broadcastzone = json.get("broadcastzone")?.asText("") ?: ""
|
|
val command = json.get("command")?.asText("") ?: ""
|
|
if (command == "Open" || command == "Close") {
|
|
if (broadcastzone.isNotEmpty()) {
|
|
val bc = Get_Barix_Connection_by_ZoneName(broadcastzone)
|
|
if (bc != null) {
|
|
val key = ctx.cookie("client-stream-id")
|
|
if (command == "Open") {
|
|
// open command
|
|
if (!key.isNullOrEmpty()) {
|
|
// ada connection sebelumnya, kemungkinan reconnect
|
|
val prev = WsContextMap[key]
|
|
if (prev != null) {
|
|
prev.bc?.Remove_Mp3_Consumer(key)
|
|
prev.ws?.closeSession(
|
|
WsCloseStatus.NORMAL_CLOSURE,
|
|
"Reopen Live Audio Stream"
|
|
)
|
|
}
|
|
WsContextMap.remove(key)
|
|
ctx.cookie("client-stream-id", "")
|
|
}
|
|
val newkey = UUID.randomUUID().toString()
|
|
.also { ctx.cookie("client-stream-id", it) }
|
|
WsContextMap[newkey] = LiveListenData(newkey, bc, null)
|
|
ResultMessageString(ctx, 200, newkey)
|
|
|
|
|
|
} else {
|
|
// close command
|
|
if (!key.isNullOrEmpty()) {
|
|
// close connection
|
|
val prev = WsContextMap[key]
|
|
if (prev != null) {
|
|
prev.bc?.Remove_Mp3_Consumer(key)
|
|
prev.ws?.closeSession(
|
|
WsCloseStatus.NORMAL_CLOSURE,
|
|
"Close Live Audio Stream"
|
|
)
|
|
}
|
|
WsContextMap.remove(key)
|
|
ctx.cookie("client-stream-id", "")
|
|
ResultMessageString(ctx, 200, "OK")
|
|
} else ResultMessageString(ctx, 400, "No client-id cookie found")
|
|
}
|
|
} else ResultMessageString(ctx, 400, "Broadcastzone not found")
|
|
} else ResultMessageString(ctx, 400, "Invalid broadcastzone")
|
|
} else ResultMessageString(ctx, 400, "Invalid command")
|
|
|
|
}
|
|
ws("ws") { wscontext ->
|
|
wscontext.onConnect {
|
|
val key = it.cookie("client-stream-id")
|
|
if (!key.isNullOrEmpty()) {
|
|
val lld = WsContextMap[key]
|
|
if (lld != null) {
|
|
it.enableAutomaticPings()
|
|
lld.ws = it
|
|
lld.bc?.Add_Mp3_Consumer(key) { mp3data ->
|
|
try {
|
|
if (it.session.isOpen) {
|
|
it.send(ByteBuffer.wrap(mp3data))
|
|
}
|
|
} catch (e: Exception) {
|
|
Logger.error { "Error sending LiveAudio mp3 data for key $key, Message: ${e.message}" }
|
|
}
|
|
}
|
|
} else {
|
|
it.closeSession(WsCloseStatus.POLICY_VIOLATION, "WsContextMap key not found")
|
|
Logger.info { "LiveAudio WebSocket connection rejected, WsContextMap key not found" }
|
|
}
|
|
} else {
|
|
it.closeSession(WsCloseStatus.POLICY_VIOLATION, "Invalid client-stream-id")
|
|
Logger.info { "LiveAudio WebSocket connection rejected, invalid client-stream-id" }
|
|
}
|
|
}
|
|
wscontext.onClose {
|
|
val key = it.cookie("client-stream-id")
|
|
if (!key.isNullOrEmpty()) {
|
|
val lld = WsContextMap[key]
|
|
lld?.bc?.Remove_Mp3_Consumer(key)
|
|
lld?.ws?.closeSession()
|
|
lld?.bc = null
|
|
lld?.ws = null
|
|
WsContextMap.remove(key)
|
|
Logger.info { "LiveAudio WebSocket closed for key $key" }
|
|
|
|
}
|
|
|
|
}
|
|
wscontext.onError {
|
|
val key = it.cookie("client-stream-id")
|
|
val msg = it.error()?.message ?: ""
|
|
Logger.info { "LiveAudio WebSocket error for key $key, Message: $msg" }
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
path("VoiceType") {
|
|
get {
|
|
it.result(objectmapper.writeValueAsString(VoiceType.entries.map { vt -> vt.name }))
|
|
}
|
|
}
|
|
path("Category") {
|
|
get {
|
|
it.result(objectmapper.writeValueAsString(Category.entries.map { cat -> cat.name }))
|
|
}
|
|
}
|
|
path("Language") {
|
|
get {
|
|
it.result(objectmapper.writeValueAsString(Language.entries.map { lang -> lang.name }))
|
|
}
|
|
}
|
|
path("ScheduleDay") {
|
|
get {
|
|
it.result(objectmapper.writeValueAsString(ScheduleDay.entries.map { day -> day.toString() }))
|
|
}
|
|
}
|
|
path("ListFiles/{Language}/{VoiceType}/{Category}") {
|
|
get { ctx ->
|
|
val language = ctx.pathParam("Language")
|
|
val voiceType = ctx.pathParam("VoiceType")
|
|
val category = ctx.pathParam("Category")
|
|
if (ValidString(language) && Language.entries.any { lang -> lang.name == language }) {
|
|
if (ValidString(voiceType) && VoiceType.entries.any { vt -> vt.name == voiceType }) {
|
|
if (ValidString(category) && Category.entries.any { cat -> cat.name == category }) {
|
|
val dir = Somecodes.SoundbankDirectory(
|
|
Language.valueOf(language),
|
|
VoiceType.valueOf(voiceType),
|
|
Category.valueOf(category)
|
|
)
|
|
if (Files.isDirectory(dir)) {
|
|
val list = ListAudioFiles(dir)
|
|
ctx.result(objectmapper.writeValueAsString(list))
|
|
|
|
} else ctx.status(400)
|
|
.result(objectmapper.writeValueAsString(resultMessage("Directory does not exist")))
|
|
} else ctx.status(400)
|
|
.result(objectmapper.writeValueAsString(resultMessage("Invalid Category")))
|
|
} else ctx.status(400)
|
|
.result(objectmapper.writeValueAsString(resultMessage("Invalid VoiceType")))
|
|
} else ctx.status(400)
|
|
.result(objectmapper.writeValueAsString(resultMessage("Invalid Language")))
|
|
}
|
|
}
|
|
path("SoundBank") {
|
|
get("FileCheck"){ ctx ->
|
|
db.soundDB.FileCheck { result ->
|
|
ctx.result(objectmapper.writeValueAsString(result))
|
|
}
|
|
}
|
|
get("List") { ctx ->
|
|
db.soundDB.Get({
|
|
ctx.result(MariaDB.ArrayListtoString(db.soundDB.List))
|
|
}, { msgFail ->
|
|
ctx.status(500)
|
|
.result(objectmapper.writeValueAsString(resultMessage(msgFail)))
|
|
})
|
|
}
|
|
get("ListFiles") {
|
|
it.result(objectmapper.writeValueAsString(ListAudioFiles(Somecodes.Soundbank_directory)))
|
|
}
|
|
get("GetPhrases/{Language}/{VoiceType}") {
|
|
val language = it.pathParam("Language")
|
|
val voiceType = it.pathParam("VoiceType")
|
|
if (ValidString(language) && Language.entries.any { lang -> lang.name == language }) {
|
|
if (ValidString(voiceType) && VoiceType.entries.any { vt -> vt.name == voiceType }) {
|
|
val phrases = db.soundDB.List
|
|
.asSequence()
|
|
.filter { sb -> sb.Language == language }
|
|
.filter { sb -> sb.VoiceType == voiceType }
|
|
.filter { sb -> sb.Category == Category.Phrase.name }
|
|
.distinctBy { sb -> sb.TAG }
|
|
.sortedBy { sb -> sb.TAG }
|
|
.toList()
|
|
it.result(objectmapper.writeValueAsString(phrases))
|
|
} else it.status(400)
|
|
.result(objectmapper.writeValueAsString(resultMessage("Invalid VoiceType")))
|
|
} else it.status(400)
|
|
.result(objectmapper.writeValueAsString(resultMessage("Invalid Language")))
|
|
}
|
|
get("AirlineTags") { ctx ->
|
|
val tags = db.soundDB.Get_AirlineCode_Tags()
|
|
val value = db.soundDB.List
|
|
.asSequence()
|
|
.filter { f1 -> f1.Category.equals(Category.Airplane_Name.name, true) }
|
|
.filter { f2 -> tags.any { t -> t.equals(f2.TAG, true) } }
|
|
.distinctBy { it.TAG }
|
|
.sortedBy { it.TAG }
|
|
.map { KeyValueMessage(it.TAG, it.Description) }
|
|
.toList()
|
|
ctx.result(objectmapper.writeValueAsString(value))
|
|
}
|
|
get("CityTags") { ctx ->
|
|
val value = db.soundDB.List
|
|
.filter { it.Category == Category.City.name }
|
|
.distinctBy { it.TAG }
|
|
.sortedBy { it.TAG }
|
|
.map { KeyValueMessage(it.TAG, it.Description) }
|
|
ctx.result(objectmapper.writeValueAsString(value))
|
|
}
|
|
post("Add") {
|
|
try {
|
|
val addvalue = objectmapper.readValue(it.body(), Soundbank::class.java)
|
|
if (addvalue.isNotEmpty()) {
|
|
// check apakah TAG sudah ada untuk language, category dan voicetype yang sama
|
|
val exists = db.soundDB.List.any { sb ->
|
|
sb.TAG == addvalue.TAG && sb.Language == addvalue.Language && sb.Category == addvalue.Category && sb.VoiceType == addvalue.VoiceType
|
|
}
|
|
if (!exists) {
|
|
val absolutepath = Somecodes.SoundbankDirectory(
|
|
Language.valueOf(addvalue.Language),
|
|
VoiceType.valueOf(addvalue.VoiceType),
|
|
Category.valueOf(addvalue.Category)
|
|
).resolve(addvalue.Path)
|
|
if (ValidFile(absolutepath)) {
|
|
addvalue.Path = absolutepath.toAbsolutePath().toString()
|
|
if (db.soundDB.Add(addvalue)) {
|
|
db.soundDB.Resort()
|
|
it.result(objectmapper.writeValueAsString(resultMessage("OK")))
|
|
} else it.status(500)
|
|
.result(objectmapper.writeValueAsString(resultMessage("Failed to add soundbank to database")))
|
|
} else it.status(400)
|
|
.result(objectmapper.writeValueAsString(resultMessage("Invalid Path, file does not exist")))
|
|
} else it.status(400)
|
|
.result(objectmapper.writeValueAsString(resultMessage("TAG=${addvalue.TAG} already exists for the same Language=${addvalue.Language} and Category=${addvalue.Category}")))
|
|
} else it.status(400)
|
|
.result(objectmapper.writeValueAsString(resultMessage("Some fields are empty")))
|
|
|
|
} catch (e: Exception) {
|
|
it.status(400)
|
|
.result(objectmapper.writeValueAsString(resultMessage("Invalid request body, Message: ${e.message}")))
|
|
}
|
|
}
|
|
delete("List") {
|
|
// truncate soundbank table
|
|
if (db.soundDB.Clear()) {
|
|
db.soundDB.Get()
|
|
it.result(objectmapper.writeValueAsString(resultMessage("OK")))
|
|
} else {
|
|
it.status(500)
|
|
.result(objectmapper.writeValueAsString(resultMessage("Failed to truncate soundbank table")))
|
|
}
|
|
}
|
|
delete("DeleteByIndex/{index}") {
|
|
// delete by index
|
|
val index = it.pathParam("index").toUIntOrNull()
|
|
if (index == null) {
|
|
it.status(400)
|
|
.result(objectmapper.writeValueAsString(resultMessage("Invalid index")))
|
|
} else {
|
|
if (db.soundDB.DeleteByIndex(index.toInt())) {
|
|
db.soundDB.Resort()
|
|
it.result(objectmapper.writeValueAsString(resultMessage("OK")))
|
|
|
|
db.logDB.Add("AAS", "Deleted sound bank with index $index")
|
|
} else {
|
|
it.status(500)
|
|
.result(objectmapper.writeValueAsString(resultMessage("Failed to delete soundbank with index $index")))
|
|
}
|
|
}
|
|
}
|
|
patch("UpdateByIndex/{index}") {
|
|
// update by index
|
|
val index = it.pathParam("index").toUIntOrNull()
|
|
if (index != null) {
|
|
val sb = db.soundDB.List.find { xx -> xx.index == index }
|
|
if (sb != null) {
|
|
try {
|
|
val newsb = objectmapper.readValue(it.body(), Soundbank::class.java)
|
|
if (newsb.isNotEmpty()) {
|
|
var varchanged = false
|
|
if (newsb.Description != sb.Description) {
|
|
sb.Description = newsb.Description
|
|
varchanged = true
|
|
}
|
|
if (newsb.TAG != sb.TAG) {
|
|
sb.TAG = newsb.TAG
|
|
varchanged = true
|
|
}
|
|
if (newsb.ValidCategory()) {
|
|
if (newsb.Category != sb.Category) {
|
|
sb.Category = newsb.Category
|
|
varchanged = true
|
|
}
|
|
} else {
|
|
it.status(400)
|
|
.result(objectmapper.writeValueAsString(resultMessage("Invalid Category")))
|
|
return@patch
|
|
}
|
|
if (newsb.ValidLanguage()) {
|
|
if (newsb.Language != sb.Language) {
|
|
sb.Language = newsb.Language
|
|
varchanged = true
|
|
}
|
|
} else {
|
|
it.status(400)
|
|
.result(objectmapper.writeValueAsString(resultMessage("Invalid Language")))
|
|
return@patch
|
|
}
|
|
if (newsb.ValidVoiceType()) {
|
|
if (newsb.VoiceType != sb.VoiceType) {
|
|
sb.VoiceType = newsb.VoiceType
|
|
varchanged = true
|
|
}
|
|
} else {
|
|
it.status(400)
|
|
.result(objectmapper.writeValueAsString(resultMessage("Invalid VoiceType")))
|
|
return@patch
|
|
}
|
|
|
|
val newpath = Somecodes.SoundbankDirectory(
|
|
newsb.Language,
|
|
newsb.VoiceType,
|
|
newsb.Category
|
|
).resolve(newsb.Path)
|
|
if (ValidFile(newpath)) {
|
|
if (newpath.toAbsolutePath().toString() != sb.Path) {
|
|
sb.Path = newpath.toAbsolutePath().toString()
|
|
varchanged = true
|
|
}
|
|
} else {
|
|
it.status(400)
|
|
.result(objectmapper.writeValueAsString(resultMessage("Invalid path")))
|
|
return@patch
|
|
}
|
|
|
|
if (varchanged) {
|
|
if (db.soundDB.UpdateByIndex(index.toInt(), sb)) {
|
|
db.soundDB.Resort()
|
|
it.result(objectmapper.writeValueAsString(resultMessage("OK")))
|
|
} else it.status(500)
|
|
.result(objectmapper.writeValueAsString(resultMessage("Failed to update soundbank with index $index")))
|
|
} else it.status(400)
|
|
.result(objectmapper.writeValueAsString(resultMessage("Nothing has changed for soundbank with index $index")))
|
|
}
|
|
} catch (e: Exception) {
|
|
it.status(400)
|
|
.result(objectmapper.writeValueAsString(resultMessage("Unable to parse request body to Soundbank, Message: ${e.message}")))
|
|
}
|
|
|
|
} else it.status(404)
|
|
.result(objectmapper.writeValueAsString(resultMessage("Soundbank with index $index not found")))
|
|
} else it.status(400)
|
|
.result(objectmapper.writeValueAsString(resultMessage("Invalid index")))
|
|
|
|
}
|
|
get("ExportXLSX") {
|
|
val xlsxdata = db.soundDB.Export_XLSX()
|
|
if (xlsxdata != null) {
|
|
it.header(
|
|
"Content-Type",
|
|
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
|
|
)
|
|
it.header("Content-Disposition", "attachment; filename=\"soundbank.xlsx\"")
|
|
it.outputStream().use { out ->
|
|
xlsxdata.write(out)
|
|
}
|
|
} else {
|
|
it.status(500)
|
|
.result(objectmapper.writeValueAsString(resultMessage("Failed to export soundbank to XLSX")))
|
|
}
|
|
}
|
|
post("ImportXLSX") {
|
|
val uploaded = it.uploadedFile("file")
|
|
if (uploaded == null) {
|
|
it.status(400)
|
|
.result(objectmapper.writeValueAsString(resultMessage("No file uploaded")))
|
|
return@post
|
|
}
|
|
try {
|
|
val xlsx = XSSFWorkbook(uploaded.content())
|
|
if (db.soundDB.Import_XLSX(xlsx)) {
|
|
db.soundDB.Resort()
|
|
it.result(objectmapper.writeValueAsString(resultMessage("OK")))
|
|
} else {
|
|
it.status(500)
|
|
.result(objectmapper.writeValueAsString(resultMessage("Failed to import soundbank from XLSX")))
|
|
}
|
|
} catch (e: Exception) {
|
|
it.status(400)
|
|
.result(objectmapper.writeValueAsString(resultMessage("Invalid XLSX file")))
|
|
}
|
|
}
|
|
}
|
|
path("MessageBank") {
|
|
get("List") { ctx ->
|
|
// get messagebank list
|
|
db.messageDB.Get({
|
|
ctx.result(MariaDB.ArrayListtoString(db.messageDB.List))
|
|
}, { msgFail ->
|
|
ctx.status(500).result(objectmapper.writeValueAsString(resultMessage(msgFail)))
|
|
})
|
|
|
|
}
|
|
get("MessageIDs") { ctx ->
|
|
val value = db.messageDB.List
|
|
.distinctBy { it.ANN_ID }
|
|
.sortedBy { it.ANN_ID }
|
|
.map { KeyValueMessage(it.ANN_ID.toString(), it.Description) }
|
|
ctx.result(objectmapper.writeValueAsString(value))
|
|
}
|
|
post("Add") {
|
|
val json: JsonNode = objectmapper.readTree(it.body())
|
|
Logger.info { "Add MessageBank JSON: $json" }
|
|
val description = json.get("Description")?.asText("") ?: ""
|
|
val language = json.get("Language")?.asText("") ?: ""
|
|
val ann_id = json.get("ANN_ID")?.asInt()?.toUInt() ?: 0u
|
|
val voice_type = json.get("Voice_Type")?.asText("") ?: ""
|
|
val message_detail = json.get("Message_Detail")?.asText("") ?: ""
|
|
val message_tags = json.get("Message_TAGS")?.asText("") ?: ""
|
|
if (description.isNotEmpty()) {
|
|
if (language.isNotEmpty() && Language.entries.any { lang -> lang.name == language }) {
|
|
if (ann_id > 0u) {
|
|
if (voice_type.isNotEmpty() && VoiceType.entries.any { vt -> vt.name == voice_type }) {
|
|
if (message_detail.isNotEmpty()) {
|
|
if (message_tags.isNotEmpty()) {
|
|
val mb = Messagebank(
|
|
0u,
|
|
description,
|
|
language,
|
|
ann_id,
|
|
voice_type,
|
|
message_detail,
|
|
message_tags
|
|
)
|
|
val existed =
|
|
db.messageDB.List.any { it.ANN_ID == mb.ANN_ID && it.Language == mb.Language && it.Voice_Type == mb.Voice_Type }
|
|
if (!existed) {
|
|
if (db.messageDB.Add(mb)) {
|
|
db.messageDB.Resort()
|
|
it.result(objectmapper.writeValueAsString(resultMessage("OK")))
|
|
} else it.status(500)
|
|
.result(objectmapper.writeValueAsString(resultMessage("Failed to add messagebank to database")))
|
|
} else it.status(400)
|
|
.result(objectmapper.writeValueAsString(resultMessage("Messagebank with ANN_ID=${mb.ANN_ID}, Language=${mb.Language} and Voice_Type=${mb.Voice_Type} already exists")))
|
|
} else it.status(400)
|
|
.result(objectmapper.writeValueAsString(resultMessage("Invalid Message_TAGS")))
|
|
} else it.status(400)
|
|
.result(objectmapper.writeValueAsString(resultMessage("Invalid Message_Detail")))
|
|
} else it.status(400)
|
|
.result(objectmapper.writeValueAsString(resultMessage("Invalid Voice_Type")))
|
|
} else it.status(400)
|
|
.result(objectmapper.writeValueAsString(resultMessage("Invalid ANN_ID")))
|
|
} else it.status(400)
|
|
.result(objectmapper.writeValueAsString(resultMessage("Invalid Language")))
|
|
} else it.status(400)
|
|
.result(objectmapper.writeValueAsString(resultMessage("Invalid Description")))
|
|
}
|
|
delete("List") {
|
|
// truncate messagebank table
|
|
if (db.messageDB.Clear()) {
|
|
db.messageDB.Get()
|
|
it.result(objectmapper.writeValueAsString(resultMessage("OK")))
|
|
} else {
|
|
it.status(500)
|
|
.result(objectmapper.writeValueAsString(resultMessage("Failed to truncate messagebank table")))
|
|
}
|
|
}
|
|
delete("DeleteByIndex/{index}") {
|
|
// delete by index
|
|
val index = it.pathParam("index").toUIntOrNull()
|
|
if (index == null) {
|
|
it.status(400)
|
|
.result(objectmapper.writeValueAsString(resultMessage("Invalid index")))
|
|
} else {
|
|
if (db.messageDB.DeleteByIndex(index.toInt())) {
|
|
db.messageDB.Resort()
|
|
it.result(objectmapper.writeValueAsString(resultMessage("OK")))
|
|
db.logDB.Add("AAS", "Deleted message bank with index $index")
|
|
} else {
|
|
it.status(500)
|
|
.result(objectmapper.writeValueAsString(resultMessage("Failed to delete messagebank with index $index")))
|
|
}
|
|
}
|
|
}
|
|
patch("UpdateByIndex/{index}") {
|
|
// update messagebank by index
|
|
val index = it.pathParam("index").toUIntOrNull()
|
|
if (index == null) {
|
|
it.status(400)
|
|
.result(objectmapper.writeValueAsString(resultMessage("Invalid index")))
|
|
} else {
|
|
val mb = db.messageDB.List.find { xx -> xx.index == index }
|
|
if (mb == null) {
|
|
it.status(404)
|
|
.result(objectmapper.writeValueAsString(resultMessage("Messagebank with index $index not found")))
|
|
} else {
|
|
val json: JsonNode = objectmapper.readTree(it.body())
|
|
if (json.isEmpty) {
|
|
it.status(400)
|
|
.result(objectmapper.writeValueAsString(resultMessage("UpdateByIndex with index=$index has empty body")))
|
|
} else {
|
|
val _description = json.get("Description").asText("")
|
|
val _language = json.get("Language").asText("")
|
|
val _ann_id = json.get("ANN_ID").asInt().toUInt()
|
|
val _voice_type = json.get("Voice_Type").asText("")
|
|
val _message_detail = json.get("Message_Detail").asText("")
|
|
val _message_tags = json.get("Message_TAGS").asText("")
|
|
|
|
var changed = false
|
|
if (ValidString(_description) && _description != mb.Description) {
|
|
mb.Description = _description
|
|
changed = true
|
|
}
|
|
if (ValidString(_language) && _language != mb.Language) {
|
|
mb.Language = _language
|
|
changed = true
|
|
}
|
|
if (_ann_id > 0u && _ann_id != mb.ANN_ID) {
|
|
mb.ANN_ID = _ann_id
|
|
changed = true
|
|
}
|
|
if (ValidString(_voice_type) && _voice_type != mb.Voice_Type) {
|
|
if (VoiceType.entries.any { vt -> vt.name == _voice_type }) {
|
|
mb.Voice_Type = _voice_type
|
|
changed = true
|
|
} else {
|
|
it.status(400)
|
|
.result(objectmapper.writeValueAsString(resultMessage("Invalid Voice_Type")))
|
|
return@patch
|
|
}
|
|
}
|
|
if (ValidString(_message_detail) && _message_detail != mb.Message_Detail) {
|
|
mb.Message_Detail = _message_detail
|
|
changed = true
|
|
}
|
|
if (ValidString(_message_tags) && _message_tags != mb.Message_TAGS) {
|
|
mb.Message_TAGS = _message_tags
|
|
changed = true
|
|
}
|
|
if (changed) {
|
|
if (db.messageDB.UpdateByIndex(index.toInt(), mb)) {
|
|
db.messageDB.Resort()
|
|
it.result(objectmapper.writeValueAsString(resultMessage("OK")))
|
|
} else it.status(500)
|
|
.result(objectmapper.writeValueAsString(resultMessage("Failed to update messagebank with index $index")))
|
|
} else it.status(400)
|
|
.result(objectmapper.writeValueAsString(resultMessage("Nothing has changed for messagebank with index $index")))
|
|
}
|
|
}
|
|
}
|
|
}
|
|
get("ExportXLSX") {
|
|
val xlsxdata = db.messageDB.Export_XLSX()
|
|
if (xlsxdata != null) {
|
|
it.header(
|
|
"Content-Type",
|
|
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
|
|
)
|
|
it.header("Content-Disposition", "attachment; filename=\"messagebank.xlsx\"")
|
|
it.outputStream().use { out ->
|
|
xlsxdata.write(out)
|
|
}
|
|
} else {
|
|
it.status(500)
|
|
.result(objectmapper.writeValueAsString(resultMessage("Failed to export messagebank to XLSX")))
|
|
}
|
|
}
|
|
post("ImportXLSX") {
|
|
val uploaded = it.uploadedFile("file")
|
|
if (uploaded == null) {
|
|
it.status(400)
|
|
.result(objectmapper.writeValueAsString(resultMessage("No file uploaded")))
|
|
return@post
|
|
}
|
|
try {
|
|
val xlsx = XSSFWorkbook(uploaded.content())
|
|
if (db.messageDB.Import_XLSX(xlsx)) {
|
|
db.messageDB.Resort()
|
|
it.result(objectmapper.writeValueAsString(resultMessage("OK")))
|
|
} else {
|
|
it.status(500)
|
|
.result(objectmapper.writeValueAsString(resultMessage("Failed to import messagebank from XLSX")))
|
|
}
|
|
} catch (e: Exception) {
|
|
it.status(400)
|
|
.result(objectmapper.writeValueAsString(resultMessage("Invalid XLSX file")))
|
|
}
|
|
}
|
|
}
|
|
path("LanguageLink") {
|
|
get("List") { ctx ->
|
|
db.languageDB.Get({
|
|
// get language link list
|
|
ctx.result(MariaDB.ArrayListtoString(db.languageDB.List))
|
|
}, { msgFail ->
|
|
ctx.status(500).result(objectmapper.writeValueAsString(resultMessage(msgFail)))
|
|
})
|
|
|
|
}
|
|
post("DefaultInit") { ctx ->
|
|
// clear languageDB and init with default values
|
|
// default value : every CITY in soundDB will have language linked to
|
|
db.languageDB.Clear()
|
|
db.soundDB.Get_City_Tags().forEach { city ->
|
|
val newvalue = LanguageLink(0u, city, Language.DefaultLanguageLink())
|
|
db.languageDB.Add(newvalue)
|
|
}
|
|
db.languageDB.Resort()
|
|
ctx.result(objectmapper.writeValueAsString(resultMessage("OK")))
|
|
}
|
|
post("Add") {
|
|
// Parse JSON from request body
|
|
val json: JsonNode = objectmapper.readTree(it.body())
|
|
val tag = json.get("tag").asText("")
|
|
val languages = json.get("language").asText("").split(";")
|
|
if (ValidString(tag)) {
|
|
if (languages.all { xx ->
|
|
Language.entries.any { yy ->
|
|
yy.name.equals(
|
|
xx,
|
|
true
|
|
)
|
|
}
|
|
}) {
|
|
if (!db.languageDB.List.any { ll -> ll.TAG.equals(tag, true) }) {
|
|
val newvalue = LanguageLink(0u, tag, languages.joinToString(";"))
|
|
if (db.languageDB.Add(newvalue)) {
|
|
db.languageDB.Resort()
|
|
it.result(objectmapper.writeValueAsString(resultMessage("OK")))
|
|
} else {
|
|
it.status(500)
|
|
.result(objectmapper.writeValueAsString(resultMessage("Failed to add language link to database")))
|
|
}
|
|
} else {
|
|
it.status(400)
|
|
.result(objectmapper.writeValueAsString(resultMessage("TAG=$tag already exists")))
|
|
}
|
|
} else {
|
|
it.status(400)
|
|
.result(objectmapper.writeValueAsString(resultMessage("Contains unsupported language")))
|
|
}
|
|
} else {
|
|
it.status(400)
|
|
.result(objectmapper.writeValueAsString(resultMessage("Invalid tag or language")))
|
|
}
|
|
}
|
|
delete("List") {
|
|
// truncate language link table
|
|
if (db.languageDB.Clear()) {
|
|
db.languageDB.Resort()
|
|
it.result(objectmapper.writeValueAsString(resultMessage("OK")))
|
|
} else {
|
|
it.status(500)
|
|
.result(objectmapper.writeValueAsString(resultMessage("Failed to truncate language link table")))
|
|
}
|
|
}
|
|
delete("DeleteByIndex/{index}") {
|
|
// delete by index
|
|
val index = it.pathParam("index").toUIntOrNull()
|
|
if (index == null) {
|
|
it.status(400)
|
|
.result(objectmapper.writeValueAsString(resultMessage("Invalid index")))
|
|
} else {
|
|
if (db.languageDB.DeleteByIndex(index.toInt())) {
|
|
db.languageDB.Resort()
|
|
it.result(objectmapper.writeValueAsString(resultMessage("OK")))
|
|
db.logDB.Add("AAS", "Deleted language link with index $index")
|
|
} else {
|
|
it.status(500)
|
|
.result(objectmapper.writeValueAsString(resultMessage("Failed to delete language link with index $index")))
|
|
}
|
|
}
|
|
}
|
|
patch("UpdateByIndex/{index}") {
|
|
// update by index
|
|
val index = it.pathParam("index").toUIntOrNull()
|
|
if (index == null) {
|
|
it.status(400)
|
|
.result(objectmapper.writeValueAsString(resultMessage("Invalid index")))
|
|
} else {
|
|
val ll = db.languageDB.List.find { xx -> xx.index == index }
|
|
if (ll == null) {
|
|
it.status(404)
|
|
.result(objectmapper.writeValueAsString(resultMessage("Language link with index $index not found")))
|
|
} else {
|
|
val json: JsonNode = objectmapper.readTree(it.body())
|
|
if (json.isEmpty) {
|
|
it.status(400)
|
|
.result(objectmapper.writeValueAsString(resultMessage("UpdateByIndex with index=$index has empty body")))
|
|
} else {
|
|
val _tag = json.get("tag").asText("")
|
|
val _language = json.get("language").asText("")
|
|
var changed = false
|
|
if (ValidString(_language) && _language != ll.Language) {
|
|
ll.Language = _language
|
|
changed = true
|
|
}
|
|
if (ValidString(_tag) && _tag != ll.TAG) {
|
|
ll.TAG = _tag
|
|
changed = true
|
|
}
|
|
if (changed) {
|
|
if (db.languageDB.UpdateByIndex(index.toInt(), ll)) {
|
|
db.languageDB.Resort()
|
|
it.result(objectmapper.writeValueAsString(resultMessage("OK")))
|
|
} else it.status(500)
|
|
.result(objectmapper.writeValueAsString(resultMessage("Failed to update language link with index $index")))
|
|
} else it.status(400)
|
|
.result(objectmapper.writeValueAsString(resultMessage("Nothing has changed for language link with index $index")))
|
|
}
|
|
}
|
|
}
|
|
}
|
|
get("ExportXLSX") {
|
|
val xlsxdata = db.languageDB.Export_XLSX()
|
|
if (xlsxdata != null) {
|
|
it.header(
|
|
"Content-Type",
|
|
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
|
|
)
|
|
it.header("Content-Disposition", "attachment; filename=\"languagelink.xlsx\"")
|
|
it.outputStream().use { out ->
|
|
xlsxdata.write(out)
|
|
}
|
|
} else {
|
|
it.status(500)
|
|
.result(objectmapper.writeValueAsString(resultMessage("Failed to export language link to XLSX")))
|
|
}
|
|
}
|
|
post("ImportXLSX") {
|
|
val uploaded = it.uploadedFile("file")
|
|
if (uploaded == null) {
|
|
it.status(400)
|
|
.result(objectmapper.writeValueAsString(resultMessage("No file uploaded")))
|
|
return@post
|
|
}
|
|
try {
|
|
val xlsx = XSSFWorkbook(uploaded.content())
|
|
if (db.languageDB.Import_XLSX(xlsx)) {
|
|
db.languageDB.Resort()
|
|
it.result(objectmapper.writeValueAsString(resultMessage("OK")))
|
|
} else {
|
|
it.status(500)
|
|
.result(objectmapper.writeValueAsString(resultMessage("Failed to import language link from XLSX")))
|
|
}
|
|
} catch (e: Exception) {
|
|
it.status(400)
|
|
.result(objectmapper.writeValueAsString(resultMessage("Invalid XLSX file")))
|
|
}
|
|
}
|
|
}
|
|
path("ScheduleBank") {
|
|
get("List") { ctx ->
|
|
|
|
db.scheduleDB.Get({
|
|
// get timer list
|
|
ctx.result(MariaDB.ArrayListtoString(db.scheduleDB.List))
|
|
}, { msgFail ->
|
|
ctx.status(500).result(objectmapper.writeValueAsString(resultMessage(msgFail)))
|
|
})
|
|
// get timer list
|
|
}
|
|
delete("List") {
|
|
// truncate timer table
|
|
if (db.scheduleDB.Clear()) {
|
|
db.scheduleDB.Get()
|
|
it.result(objectmapper.writeValueAsString(resultMessage("OK")))
|
|
} else {
|
|
it.status(500)
|
|
.result(objectmapper.writeValueAsString(resultMessage("Failed to truncate schedulebank table")))
|
|
}
|
|
}
|
|
post("Add") {
|
|
val json: JsonNode = objectmapper.readTree(it.body())
|
|
val description = json.get("Description")?.asText("") ?: ""
|
|
val day = json.get("Day")?.asText("") ?: ""
|
|
val time = json.get("Time")?.asText("") ?: ""
|
|
val soundpath = json.get("Soundpath")?.asText("") ?: ""
|
|
val repeat = json.get("Repeat")?.asInt()?.toUByte() ?: 0u
|
|
val enable = json.get("Enable")?.asBoolean() ?: false
|
|
val broadcast_zones = json.get("BroadcastZones")?.asText("") ?: ""
|
|
val language = json.get("Language")?.asText("") ?: ""
|
|
if (ValidString(description)) {
|
|
if (ValidScheduleDay(day)) {
|
|
if (ValidScheduleTime(time)) {
|
|
if (ValidString(soundpath)) {
|
|
if (repeat in 0u..127u) {
|
|
if (ValidString(broadcast_zones)) {
|
|
val zones = broadcast_zones.split(";")
|
|
if (zones.all { zz ->
|
|
db.broadcastDB.List.any { xx ->
|
|
xx.description.equals(
|
|
zz,
|
|
true
|
|
)
|
|
}
|
|
}) {
|
|
if (ValidString(language)) {
|
|
val newvalue = ScheduleBank(
|
|
0u,
|
|
description,
|
|
day,
|
|
time,
|
|
soundpath,
|
|
repeat,
|
|
enable,
|
|
broadcast_zones,
|
|
language
|
|
)
|
|
if (db.scheduleDB.Add(newvalue)) {
|
|
db.scheduleDB.Resort()
|
|
it.result(
|
|
objectmapper.writeValueAsString(
|
|
resultMessage(
|
|
"OK"
|
|
)
|
|
)
|
|
)
|
|
} else it.status(500)
|
|
.result(
|
|
objectmapper.writeValueAsString(
|
|
resultMessage("Failed to add schedule to database")
|
|
)
|
|
)
|
|
} else it.status(400)
|
|
.result(objectmapper.writeValueAsString(resultMessage("Invalid Language")))
|
|
} else it.status(400)
|
|
.result(objectmapper.writeValueAsString(resultMessage("Contains unsupported BroadcastZones")))
|
|
} else it.status(400)
|
|
.result(objectmapper.writeValueAsString(resultMessage("Invalid BroadcastZones")))
|
|
} else it.status(400)
|
|
.result(objectmapper.writeValueAsString(resultMessage("Invalid Repeat, must be between 0-127")))
|
|
} else it.status(400)
|
|
.result(objectmapper.writeValueAsString(resultMessage("Invalid Soundpath")))
|
|
} else it.status(400)
|
|
.result(objectmapper.writeValueAsString(resultMessage("Invalid Time format, must be HH:mm")))
|
|
} else it.status(400)
|
|
.result(objectmapper.writeValueAsString(resultMessage("Invalid Day format")))
|
|
} else it.status(400)
|
|
.result(objectmapper.writeValueAsString(resultMessage("Invalid Description")))
|
|
}
|
|
delete("DeleteByIndex/{index}") {
|
|
// delete by index
|
|
val index = it.pathParam("index").toUIntOrNull()
|
|
if (index == null) {
|
|
it.status(400)
|
|
.result(objectmapper.writeValueAsString(resultMessage("Invalid index")))
|
|
} else {
|
|
if (db.scheduleDB.DeleteByIndex(index.toInt())) {
|
|
db.scheduleDB.Resort()
|
|
it.result(objectmapper.writeValueAsString(resultMessage("OK")))
|
|
db.logDB.Add("AAS", "Deleted schedule bank with index $index")
|
|
} else {
|
|
it.status(500)
|
|
.result(objectmapper.writeValueAsString(resultMessage("Failed to delete schedule with index $index")))
|
|
}
|
|
}
|
|
}
|
|
patch("UpdateByIndex/{index}") {
|
|
// update by index
|
|
val index = it.pathParam("index").toUIntOrNull()
|
|
if (index != null) {
|
|
val sb = db.scheduleDB.List.find { xx -> xx.index == index }
|
|
if (sb != null) {
|
|
val json = objectmapper.readTree(it.body())
|
|
val _description = json.get("Description").asText("")
|
|
val _time = json.get("Time").asText("")
|
|
val _day = json.get("Day").asText("")
|
|
val _soundpath = json.get("Soundpath").asText("")
|
|
val _repeat = json.get("Repeat").asInt().toUByte()
|
|
val _enable = json.get("Enable").asBoolean()
|
|
val _broadcast_zones = json.get("BroadcastZones").asText("")
|
|
val _language = json.get("Language").asText("")
|
|
val newsb = ScheduleBank(
|
|
index,
|
|
_description,
|
|
_day,
|
|
_time,
|
|
_soundpath,
|
|
_repeat,
|
|
_enable,
|
|
_broadcast_zones,
|
|
_language
|
|
)
|
|
if (newsb.isNotEmpty()) {
|
|
if (!sb.isEqual(newsb)) {
|
|
if (db.scheduleDB.UpdateByIndex(index.toInt(), newsb)) {
|
|
db.scheduleDB.Resort()
|
|
it.result(objectmapper.writeValueAsString(resultMessage("OK")))
|
|
} else it.status(500)
|
|
.result(objectmapper.writeValueAsString(resultMessage("Failed to update schedule with index $index")))
|
|
} else it.status(400)
|
|
.result(objectmapper.writeValueAsString(resultMessage("Nothing has changed for schedule with index $index")))
|
|
} else it.status(400)
|
|
.result(objectmapper.writeValueAsString(resultMessage("Some fields are empty")))
|
|
|
|
} else it.status(400)
|
|
.result(objectmapper.writeValueAsString(resultMessage("Schedule with index $index not found")))
|
|
} else it.status(400)
|
|
.result(objectmapper.writeValueAsString(resultMessage("Invalid index")))
|
|
}
|
|
get("ExportXLSX") {
|
|
val xlsxdata = db.scheduleDB.Export_XLSX()
|
|
if (xlsxdata != null) {
|
|
it.header(
|
|
"Content-Type",
|
|
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
|
|
)
|
|
it.header("Content-Disposition", "attachment; filename=\"schedulebank.xlsx\"")
|
|
it.outputStream().use { out ->
|
|
xlsxdata.write(out)
|
|
}
|
|
} else {
|
|
it.status(500)
|
|
.result(objectmapper.writeValueAsString(resultMessage("Failed to export schedulebank to XLSX")))
|
|
}
|
|
}
|
|
post("ImportXLSX") {
|
|
val uploaded = it.uploadedFile("file")
|
|
if (uploaded == null) {
|
|
it.status(400)
|
|
.result(objectmapper.writeValueAsString(resultMessage("No file uploaded")))
|
|
return@post
|
|
}
|
|
try {
|
|
val xlsx = XSSFWorkbook(uploaded.content())
|
|
if (db.scheduleDB.Import_XLSX(xlsx)) {
|
|
db.scheduleDB.Resort()
|
|
it.result(objectmapper.writeValueAsString(resultMessage("OK")))
|
|
} else {
|
|
it.status(500)
|
|
.result(objectmapper.writeValueAsString(resultMessage("Failed to import schedulebank from XLSX")))
|
|
}
|
|
} catch (e: Exception) {
|
|
it.status(400)
|
|
.result(objectmapper.writeValueAsString(resultMessage("Invalid XLSX file")))
|
|
}
|
|
}
|
|
get("GetMessageAndBroadcastZones") {
|
|
val result = object {
|
|
val messages = db.messageDB.List
|
|
.filter { mb ->
|
|
!mb.Message_Detail.contains("[") && !mb.Message_Detail.contains(
|
|
"]"
|
|
)
|
|
}
|
|
.map { mb -> "${mb.Description} [${mb.ANN_ID}]" }
|
|
val broadcastzones = db.broadcastDB.List
|
|
}
|
|
it.result(objectmapper.writeValueAsString(result))
|
|
}
|
|
|
|
// Kirim list language dari Messagebank berdasarkan ANN_ID
|
|
get("GetLanguageList/{ANN_ID}") { get1 ->
|
|
val langlist = db.messageDB.List
|
|
.filter { it.ANN_ID == get1.pathParam("ANN_ID").toInt().toUInt() }
|
|
.map { it.Language }.distinct()
|
|
get1.result(objectmapper.writeValueAsString(langlist))
|
|
}
|
|
|
|
}
|
|
path("UserManagement") {
|
|
get("List") { ctx ->
|
|
db.userDB.Get({
|
|
ctx.result(objectmapper.writeValueAsString(db.userDB.List))
|
|
}, { msgFail ->
|
|
ctx.status(500).result(objectmapper.writeValueAsString(resultMessage(msgFail)))
|
|
})
|
|
|
|
}
|
|
delete("List") {
|
|
if (db.userDB.Clear()) {
|
|
db.userDB.Get()
|
|
it.result(objectmapper.writeValueAsString(resultMessage("OK")))
|
|
} else {
|
|
it.status(500)
|
|
.result(objectmapper.writeValueAsString(resultMessage("Failed to truncate user table")))
|
|
}
|
|
}
|
|
post("Add") { ctx ->
|
|
val json: JsonNode = objectmapper.readTree(ctx.body())
|
|
val username = json.get("username").asText("")
|
|
val password = json.get("password").asText("")
|
|
val location = json.get("location").asText("N/A")
|
|
val airline_tags = json.get("airline_tags").asText("")
|
|
val city_tags = json.get("city_tags").asText("")
|
|
val messagebank_ann_id = json.get("messagebank_ann_id").asText("")
|
|
val broadcastzones = json.get("broadcastzones").asText("")
|
|
// revisi 30012026
|
|
// city, airline, messagebank_ann_id boleh kosong, untuk user yang paging saja
|
|
// location juga optional
|
|
// yang wajib ada adalah username, password, broadcastzones
|
|
if (ValidStrings(username, password, broadcastzones)) {
|
|
if (!db.userDB.Username_exists(username)) {
|
|
if (ValidString(airline_tags)) {
|
|
// ada airline_tags, berarti harus di cek apakah ada di table soundbank
|
|
// kalau tidak ada airline_tags, tidak perlu cek
|
|
val atags = airline_tags.split(";").map { it.trim() }
|
|
.filter { it.isNotEmpty() }.distinct()
|
|
val airlinetags = db.soundDB.Get_AirlineCode_Tags()
|
|
val missing_airlinetags = ArrayList<String>()
|
|
atags.forEach { tag ->
|
|
if (!airlinetags.any { it.equals(tag, true) }) {
|
|
missing_airlinetags.add(tag)
|
|
}
|
|
}
|
|
if (missing_airlinetags.isNotEmpty()) {
|
|
ctx.status(400)
|
|
.result(
|
|
objectmapper.writeValueAsString(
|
|
resultMessage(
|
|
"Airline tags not found in soundbank: ${
|
|
missing_airlinetags.joinToString(
|
|
", "
|
|
)
|
|
}"
|
|
)
|
|
)
|
|
)
|
|
return@post
|
|
}
|
|
}
|
|
if (ValidString(city_tags)) {
|
|
// ada city_tags, berarti harus di cek apakah ada di table soundbank
|
|
// kalau tidak ada city_tags, tidak perlu cek
|
|
val ctags = city_tags.split(";").map { it.trim() }
|
|
.filter { it.isNotEmpty() }.distinct()
|
|
val citytags = db.soundDB.Get_City_Tags()
|
|
val missing_citytags = ArrayList<String>()
|
|
ctags.forEach { tag ->
|
|
if (!citytags.any { it.equals(tag, true) }) {
|
|
missing_citytags.add(tag)
|
|
}
|
|
}
|
|
if (missing_citytags.isNotEmpty()) {
|
|
ctx.status(400)
|
|
.result(
|
|
objectmapper.writeValueAsString(
|
|
resultMessage(
|
|
"City tags not found in soundbank: ${
|
|
missing_citytags.joinToString(
|
|
", "
|
|
)
|
|
}"
|
|
)
|
|
)
|
|
)
|
|
return@post
|
|
}
|
|
|
|
}
|
|
if (ValidString(messagebank_ann_id)) {
|
|
// ada messagebank_ann_id, berarti harus di cek apakah ada di table messagebank
|
|
// kalau tidak ada messagebank_ann_id, tidak perlu cek
|
|
val mbids = messagebank_ann_id.split(";")
|
|
.map { it.trim() }
|
|
.filter { it.isNotEmpty() }.distinct()
|
|
.mapNotNull { it.toUIntOrNull() }
|
|
val mbankids = db.messageDB.Get_MessageID_List()
|
|
if (!mbids.all { id -> mbankids.any { it == id } }) {
|
|
ctx.status(400)
|
|
.result(objectmapper.writeValueAsString(resultMessage("Some ANN_ID not found in Messagebank")))
|
|
return@post
|
|
}
|
|
}
|
|
|
|
// check apakah semua broadcast zones ada di soundbank
|
|
val bzdesc =
|
|
broadcastzones.split(";").map { it.trim() }
|
|
.filter { it.isNotEmpty() }.distinct()
|
|
val bzlist = db.broadcastDB.Get_BroadcastZone_List()
|
|
val missing_broadcastzones = ArrayList<String>()
|
|
bzdesc.forEach { bz ->
|
|
if (!bzlist.any { it.equals(bz, true) }) {
|
|
missing_broadcastzones.add(bz)
|
|
}
|
|
}
|
|
if (missing_broadcastzones.isNotEmpty()) {
|
|
ctx.status(400)
|
|
.result(
|
|
objectmapper.writeValueAsString(
|
|
resultMessage(
|
|
"Broadcast zone tags not found in soundbank: ${
|
|
missing_broadcastzones.joinToString(
|
|
", "
|
|
)
|
|
}"
|
|
)
|
|
)
|
|
)
|
|
return@post
|
|
}
|
|
|
|
|
|
// sampe sini valid semua
|
|
// semua valid, tambain ke database
|
|
val newuser = UserDB(
|
|
0u,
|
|
username,
|
|
password,
|
|
location,
|
|
airline_tags,
|
|
city_tags,
|
|
messagebank_ann_id,
|
|
broadcastzones
|
|
)
|
|
if (db.userDB.Add(newuser)) {
|
|
db.userDB.Resort()
|
|
ctx.result(objectmapper.writeValueAsString(resultMessage("OK")))
|
|
} else ctx.status(500)
|
|
.result(objectmapper.writeValueAsString(resultMessage("Failed to add user to database")))
|
|
|
|
} else ctx.status(400)
|
|
.result(objectmapper.writeValueAsString("Username already exists"))
|
|
} else ctx.status(400)
|
|
.result(objectmapper.writeValueAsString(resultMessage("Not all fields have value")))
|
|
}
|
|
delete("DeleteByIndex/{index}") {
|
|
// delete by index
|
|
val index = it.pathParam("index").toUIntOrNull()
|
|
if (index == null) {
|
|
it.status(400)
|
|
.result(objectmapper.writeValueAsString(resultMessage("Invalid index")))
|
|
} else {
|
|
if (db.userDB.DeleteByIndex(index.toInt())) {
|
|
db.userDB.Resort()
|
|
it.result(objectmapper.writeValueAsString(resultMessage("OK")))
|
|
db.logDB.Add("AAS", "Deleted user with index $index")
|
|
} else it.status(500)
|
|
.result(objectmapper.writeValueAsString(resultMessage("Failed to delete user with index $index")))
|
|
}
|
|
}
|
|
patch("UpdateByIndex/{index}") { ctx ->
|
|
// update by index
|
|
val index = ctx.pathParam("index").toUIntOrNull()
|
|
if (index != null) {
|
|
val user = db.userDB.List.find { xx -> xx.index == index }
|
|
if (user != null) {
|
|
val json: JsonNode = objectmapper.readTree(ctx.body())
|
|
if (!json.isEmpty) {
|
|
val _username = json.get("username").asText("")
|
|
val _password = json.get("password").asText("")
|
|
val _location = json.get("location").asText("N/A")
|
|
val _airline_tags = json.get("airline_tags").asText("")
|
|
val _city_tags = json.get("city_tags").asText("")
|
|
val _messagebank_ann_id = json.get("messagebank_ann_id").asText("")
|
|
val _broadcastzones = json.get("broadcastzones").asText("")
|
|
// revisi 30012026
|
|
// city, airline, messagebank_ann_id boleh kosong, untuk user yang paging saja
|
|
// location juga optional
|
|
// yang wajib ada adalah username, password, broadcastzones
|
|
if (ValidStrings(_username, _password, _broadcastzones)) {
|
|
val _otherusername = db.userDB.List.find { xx ->
|
|
xx.username.equals(
|
|
_username,
|
|
true
|
|
) && xx.index != index
|
|
}
|
|
if (_otherusername != null) {
|
|
Logger.info { "Found other username with same name: ${_otherusername.username} at index ${_otherusername.index}" }
|
|
ctx.status(400).result(
|
|
objectmapper.writeValueAsString(
|
|
resultMessage("Username already exists for another user")
|
|
)
|
|
)
|
|
return@patch
|
|
}
|
|
|
|
if (ValidString(_airline_tags)) {
|
|
// ada airline_tags, berarti harus di cek apakah ada di table soundbank
|
|
// kalau tidak ada airline_tags, tidak perlu cek
|
|
val atags = _airline_tags.split(";").map { it.trim() }
|
|
.filter { it.isNotEmpty() }.distinct()
|
|
val airlinetags = db.soundDB.Get_AirlineCode_Tags()
|
|
val missing_airlinetags = ArrayList<String>()
|
|
atags.forEach { tag ->
|
|
if (!airlinetags.any { it.equals(tag, true) }) {
|
|
missing_airlinetags.add(tag)
|
|
}
|
|
}
|
|
if (missing_airlinetags.isNotEmpty()) {
|
|
ctx.status(400)
|
|
.result(
|
|
objectmapper.writeValueAsString(
|
|
resultMessage(
|
|
"Airline tags not found in soundbank: ${
|
|
missing_airlinetags.joinToString(
|
|
", "
|
|
)
|
|
}"
|
|
)
|
|
)
|
|
)
|
|
return@patch
|
|
}
|
|
|
|
}
|
|
if (ValidString(_city_tags)) {
|
|
// ada city_tags, berarti harus di cek apakah ada di table soundbank
|
|
// kalau tidak ada city_tags, tidak perlu cek
|
|
val ctags = _city_tags.split(";").map { it.trim() }
|
|
.filter { it.isNotEmpty() }.distinct()
|
|
val citytags = db.soundDB.Get_City_Tags()
|
|
val missing_citytags = ArrayList<String>()
|
|
ctags.forEach { tag ->
|
|
if (!citytags.any { it.equals(tag, true) }) {
|
|
missing_citytags.add(tag)
|
|
}
|
|
}
|
|
if (missing_citytags.isNotEmpty()) {
|
|
ctx.status(400)
|
|
.result(
|
|
objectmapper.writeValueAsString(
|
|
resultMessage(
|
|
"City tags not found in soundbank: ${
|
|
missing_citytags.joinToString(
|
|
", "
|
|
)
|
|
}"
|
|
)
|
|
)
|
|
)
|
|
return@patch
|
|
}
|
|
|
|
}
|
|
if (ValidString(_messagebank_ann_id)) {
|
|
// ada messagebank_ann_id, berarti harus di cek apakah ada di table messagebank
|
|
// kalau tidak ada messagebank_ann_id, tidak perlu cek
|
|
val mbids = _messagebank_ann_id.split(";")
|
|
.map { it.trim() }
|
|
.filter { it.isNotEmpty() }.distinct()
|
|
.mapNotNull { it.toUIntOrNull() }
|
|
val mbankids = db.messageDB.Get_MessageID_List()
|
|
val missing_broadcastids = ArrayList<UInt>()
|
|
mbids.forEach { mbid ->
|
|
if (!mbankids.any { it == mbid }) {
|
|
missing_broadcastids.add(mbid)
|
|
}
|
|
}
|
|
if (missing_broadcastids.isNotEmpty()) {
|
|
ctx.status(400)
|
|
.result(
|
|
objectmapper.writeValueAsString(
|
|
resultMessage(
|
|
"ANN_ID not found in Messagebank: ${
|
|
missing_broadcastids.joinToString(
|
|
", "
|
|
)
|
|
}"
|
|
)
|
|
)
|
|
)
|
|
return@patch
|
|
}
|
|
|
|
}
|
|
|
|
val bzdesc = _broadcastzones.split(";").map { it.trim() }
|
|
.filter { it.isNotEmpty() }.distinct()
|
|
val bzlist = db.broadcastDB.Get_BroadcastZone_List()
|
|
val missing_broadcastzones = ArrayList<String>()
|
|
bzdesc.forEach { bz ->
|
|
if (!bzlist.any { it.equals(bz, true) }) {
|
|
missing_broadcastzones.add(bz)
|
|
}
|
|
}
|
|
if (missing_broadcastzones.isNotEmpty()) {
|
|
ctx.status(400)
|
|
.result(
|
|
objectmapper.writeValueAsString(
|
|
resultMessage(
|
|
"Broadcast zone tags not found in soundbank: ${
|
|
missing_broadcastzones.joinToString(
|
|
", "
|
|
)
|
|
}"
|
|
)
|
|
)
|
|
)
|
|
return@patch
|
|
}
|
|
|
|
|
|
// sampe sini valid semua
|
|
val editeduser = UserDB(
|
|
index,
|
|
_username,
|
|
_password,
|
|
_location,
|
|
_airline_tags,
|
|
_city_tags,
|
|
_messagebank_ann_id,
|
|
_broadcastzones
|
|
)
|
|
if (!user.isEqual(editeduser)) {
|
|
if (db.userDB.UpdateByIndex(
|
|
index.toInt(),
|
|
editeduser
|
|
)
|
|
) {
|
|
db.userDB.Resort()
|
|
ctx.result(
|
|
objectmapper.writeValueAsString(
|
|
resultMessage("OK")
|
|
)
|
|
)
|
|
|
|
} else ctx.status(500).result(
|
|
objectmapper.writeValueAsString(
|
|
resultMessage("Failed to update user with index $index")
|
|
)
|
|
)
|
|
} else ctx.status(400).result(
|
|
objectmapper.writeValueAsString(resultMessage("Nothing has changed for user with index $index"))
|
|
)
|
|
} else ctx.status(400)
|
|
.result(objectmapper.writeValueAsString(resultMessage("Not all fiels have value")))
|
|
} else ctx.status(400)
|
|
.result(objectmapper.writeValueAsString(resultMessage("UpdateByIndex with index=$index has empty body")))
|
|
} else ctx.status(400)
|
|
.result(objectmapper.writeValueAsString(resultMessage("User with index $index not found")))
|
|
} else ctx.status(400)
|
|
.result(objectmapper.writeValueAsString(resultMessage("Invalid index")))
|
|
}
|
|
get("ExportXLSX") {
|
|
val xlsxdata = db.userDB.Export_XLSX()
|
|
if (xlsxdata != null) {
|
|
it.header(
|
|
"Content-Type",
|
|
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
|
|
)
|
|
it.header("Content-Disposition", "attachment; filename=\"userdb.xlsx\"")
|
|
it.outputStream().use { out ->
|
|
xlsxdata.write(out)
|
|
}
|
|
} else {
|
|
it.status(500)
|
|
.result(objectmapper.writeValueAsString(resultMessage("Failed to export user table to XLSX")))
|
|
}
|
|
}
|
|
post("ImportXLSX") {
|
|
val uploaded = it.uploadedFile("file")
|
|
if (uploaded == null) {
|
|
it.status(400)
|
|
.result(objectmapper.writeValueAsString(resultMessage("No file uploaded")))
|
|
return@post
|
|
}
|
|
try {
|
|
val xlsx = XSSFWorkbook(uploaded.content())
|
|
if (db.userDB.Import_XLSX(xlsx)) {
|
|
db.userDB.Resort()
|
|
it.result(objectmapper.writeValueAsString(resultMessage("OK")))
|
|
} else {
|
|
it.status(500)
|
|
.result(objectmapper.writeValueAsString(resultMessage("Failed to import user table from XLSX")))
|
|
}
|
|
} catch (e: Exception) {
|
|
it.status(400)
|
|
.result(objectmapper.writeValueAsString(resultMessage("Invalid XLSX file")))
|
|
}
|
|
}
|
|
|
|
get("GetMessageAndBroadcastZones") {
|
|
val result = object {
|
|
val messages = db.messageDB.List
|
|
val broadcastzones = db.broadcastDB.List
|
|
}
|
|
it.result(objectmapper.writeValueAsString(result))
|
|
}
|
|
}
|
|
path("Log") {
|
|
get("List") { get1 ->
|
|
val logdate = get1.queryParam("date") ?: ""
|
|
val logfilter = get1.queryParam("filter")
|
|
db.logDB.GetLogForHtml(logdate, logfilter, { loglist ->
|
|
get1.result(objectmapper.writeValueAsString(loglist))
|
|
}, { msgFail ->
|
|
get1.status(500).result(objectmapper.writeValueAsString(resultMessage(msgFail)))
|
|
})
|
|
}
|
|
get("ExportXLSX") { get1 ->
|
|
val logdate = get1.queryParam("date") ?: ""
|
|
val logfilter = get1.queryParam("filter") ?: ""
|
|
if (ValiDateForLogHtml(logdate)) {
|
|
val xlsxdata = if (ValidString(logfilter)) {
|
|
db.logDB.Export_Log_XLSX(logdate.replace('-', '/'), logfilter)
|
|
} else {
|
|
db.logDB.Export_Log_XLSX(logdate.replace('-', '/'), "")
|
|
}
|
|
if (xlsxdata != null) {
|
|
get1.header(
|
|
"Content-Type",
|
|
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
|
|
)
|
|
get1.header("Content-Disposition", "attachment; filename=\"log_$logdate.xlsx\"")
|
|
get1.outputStream().use { out ->
|
|
xlsxdata.write(out)
|
|
}
|
|
} else {
|
|
get1.status(500)
|
|
.result(objectmapper.writeValueAsString(resultMessage("Failed to export log to XLSX")))
|
|
}
|
|
} else get1.status(400)
|
|
.result(objectmapper.writeValueAsString(resultMessage("Invalid logdate")))
|
|
}
|
|
}
|
|
path("BroadcastZones") {
|
|
get("List") { ctx ->
|
|
db.broadcastDB.Get({
|
|
ctx.result(MariaDB.ArrayListtoString(db.broadcastDB.List))
|
|
}, { msgFail ->
|
|
ctx.status(500).result(objectmapper.writeValueAsString(resultMessage(msgFail)))
|
|
})
|
|
}
|
|
get("BroadcastZoneDescriptions") { ctx ->
|
|
val value = db.broadcastDB.List
|
|
.distinctBy { it.description }
|
|
.map { it.description }
|
|
ctx.result(objectmapper.writeValueAsString(value))
|
|
}
|
|
delete("List") {
|
|
// truncate broadcast zones table
|
|
if (db.broadcastDB.Clear()) {
|
|
db.broadcastDB.Get()
|
|
it.result(objectmapper.writeValueAsString(resultMessage("OK")))
|
|
} else {
|
|
it.status(500)
|
|
.result(objectmapper.writeValueAsString(resultMessage("Failed to truncate broadcast zones table")))
|
|
}
|
|
}
|
|
post("Add") {
|
|
val json: JsonNode = objectmapper.readTree(it.body())
|
|
val _description = json.get("description").asText("")
|
|
val _soundchannel = json.get("SoundChannel").asText("")
|
|
val _box = json.get("Box").asText("")
|
|
val _relay = json.get("Relay").asText("")
|
|
if (ValidString(_description)) {
|
|
if (ValidString(_soundchannel)) {
|
|
if (ValidString(_box)) {
|
|
if (ValidString(_relay)) {
|
|
val newbp =
|
|
BroadcastZones(0u, _description, _soundchannel, _box, _relay)
|
|
if (db.broadcastDB.Add(newbp)) {
|
|
db.broadcastDB.Resort()
|
|
it.result(objectmapper.writeValueAsString(resultMessage("OK")))
|
|
} else it.status(500)
|
|
.result(objectmapper.writeValueAsString(resultMessage("Failed to add broadcast zone to database")))
|
|
} else it.status(400)
|
|
.result(objectmapper.writeValueAsString(resultMessage("Invalid Relay")))
|
|
} else it.status(400)
|
|
.result(objectmapper.writeValueAsString(resultMessage("Invalid Box")))
|
|
} else it.status(400)
|
|
.result(objectmapper.writeValueAsString(resultMessage("Invalid SoundChannel")))
|
|
} else it.status(400)
|
|
.result(objectmapper.writeValueAsString(resultMessage("Invalid description")))
|
|
}
|
|
delete("DeleteByIndex/{index}") {
|
|
// delete by index
|
|
val index = it.pathParam("index").toUIntOrNull()
|
|
if (index == null) {
|
|
it.status(400)
|
|
.result(objectmapper.writeValueAsString(resultMessage("Invalid index")))
|
|
} else {
|
|
if (db.broadcastDB.DeleteByIndex(index.toInt())) {
|
|
db.broadcastDB.Resort()
|
|
it.result(objectmapper.writeValueAsString(resultMessage("OK")))
|
|
db.logDB.Add("AAS", "Deleted broadcast zone with index $index")
|
|
} else {
|
|
it.status(500)
|
|
.result(objectmapper.writeValueAsString(resultMessage("Failed to delete broadcast zone with index $index")))
|
|
}
|
|
}
|
|
}
|
|
patch("UpdateByIndex/{index}") {
|
|
// update by index
|
|
val index = it.pathParam("index").toUIntOrNull()
|
|
if (index == null) {
|
|
it.status(400)
|
|
.result(objectmapper.writeValueAsString(resultMessage("Invalid index")))
|
|
} else {
|
|
val bz = db.broadcastDB.List.find { xx -> xx.index == index }
|
|
if (bz == null) {
|
|
it.status(404)
|
|
.result(objectmapper.writeValueAsString(resultMessage("Broadcast zone with index $index not found")))
|
|
} else {
|
|
val json: JsonNode = objectmapper.readTree(it.body())
|
|
if (json.isEmpty) {
|
|
it.status(400)
|
|
.result(objectmapper.writeValueAsString(resultMessage("UpdateByIndex with index=$index has empty body")))
|
|
} else {
|
|
val _description = json.get("description").asText("")
|
|
val _soundchannel = json.get("SoundChannel").asText("")
|
|
val _box = json.get("Box").asText("")
|
|
val _relay = json.get("Relay").asText("")
|
|
var changed = false
|
|
if (ValidString(_description) && _description != bz.description) {
|
|
bz.description = _description
|
|
changed = true
|
|
}
|
|
if (ValidString(_soundchannel) && _soundchannel != bz.SoundChannel) {
|
|
bz.SoundChannel = _soundchannel
|
|
changed = true
|
|
}
|
|
if (ValidString(_box) && _box != bz.id) {
|
|
bz.id = _box
|
|
changed = true
|
|
}
|
|
if (ValidString(_relay) && _relay != bz.bp) {
|
|
bz.bp = _relay
|
|
changed = true
|
|
}
|
|
if (changed) {
|
|
if (db.broadcastDB.UpdateByIndex(index.toInt(), bz)) {
|
|
db.broadcastDB.Resort()
|
|
it.result(objectmapper.writeValueAsString(resultMessage("OK")))
|
|
} else it.status(500)
|
|
.result(objectmapper.writeValueAsString(resultMessage("Failed to update broadcast zone with index $index")))
|
|
} else it.status(400)
|
|
.result(objectmapper.writeValueAsString(resultMessage("Nothing has changed for broadcast zone with index $index")))
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
get("ExportXLSX") {
|
|
val xlsxdata = db.broadcastDB.Export_XLSX()
|
|
if (xlsxdata != null) {
|
|
it.header(
|
|
"Content-Type",
|
|
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
|
|
)
|
|
it.header("Content-Disposition", "attachment; filename=\"broadcastzones.xlsx\"")
|
|
it.outputStream().use { out ->
|
|
xlsxdata.write(out)
|
|
}
|
|
} else {
|
|
it.status(500)
|
|
.result(objectmapper.writeValueAsString(resultMessage("Failed to export broadcast zones to XLSX")))
|
|
}
|
|
}
|
|
post("ImportXLSX") {
|
|
val uploaded = it.uploadedFile("file")
|
|
if (uploaded == null) {
|
|
it.status(400)
|
|
.result(objectmapper.writeValueAsString(resultMessage("No file uploaded")))
|
|
return@post
|
|
}
|
|
try {
|
|
val xlsx = XSSFWorkbook(uploaded.content())
|
|
if (db.broadcastDB.Import_XLSX(xlsx)) {
|
|
db.broadcastDB.Resort()
|
|
it.result(objectmapper.writeValueAsString(resultMessage("OK")))
|
|
} else {
|
|
it.status(500)
|
|
.result(objectmapper.writeValueAsString(resultMessage("Failed to import broadcast zones from XLSX")))
|
|
}
|
|
} catch (e: Exception) {
|
|
it.status(400)
|
|
.result(objectmapper.writeValueAsString(resultMessage("Invalid XLSX file")))
|
|
}
|
|
}
|
|
|
|
}
|
|
path("SoundChannel") {
|
|
get("List") { ctx ->
|
|
db.soundchannelDB.Get({
|
|
ctx.result(MariaDB.ArrayListtoString(db.soundchannelDB.List))
|
|
}, { msgFail ->
|
|
ctx.status(500).result(objectmapper.writeValueAsString(resultMessage(msgFail)))
|
|
})
|
|
|
|
}
|
|
get("SoundChannelDescriptions") {
|
|
it.result(objectmapper.writeValueAsString(db.soundchannelDB.Get_SoundChannel_List()))
|
|
}
|
|
delete("List") {
|
|
// truncate sound channel table
|
|
if (db.soundchannelDB.Clear()) {
|
|
db.soundchannelDB.Get()
|
|
it.result(objectmapper.writeValueAsString(resultMessage("OK")))
|
|
} else {
|
|
it.status(500)
|
|
.result(objectmapper.writeValueAsString(resultMessage("Failed to truncate sound channel table")))
|
|
}
|
|
}
|
|
patch("UpdateByIndex/{index}") {
|
|
|
|
val index = it.pathParam("index").toUIntOrNull()
|
|
if (index == null) {
|
|
it.status(400)
|
|
.result(objectmapper.writeValueAsString(resultMessage("Invalid index")))
|
|
} else {
|
|
val sc = db.soundchannelDB.List.find { xx -> xx.index == index }
|
|
if (sc == null) {
|
|
it.status(404)
|
|
.result(objectmapper.writeValueAsString(resultMessage("Sound channel with index $index not found")))
|
|
} else {
|
|
val json: JsonNode = objectmapper.readTree(it.body())
|
|
if (json.isEmpty) {
|
|
it.status(400)
|
|
.result(objectmapper.writeValueAsString(resultMessage("UpdateByIndex with index=$index has empty body")))
|
|
} else {
|
|
val _channel = json.get("description").asText("")
|
|
val _ip = json.get("ip").asText("")
|
|
if (ValidString(_channel)) {
|
|
if (ValidIPV4(_ip)) {
|
|
if (_channel.equals(sc.channel) && _ip.equals(sc.ip)) {
|
|
it.status(400)
|
|
.result(objectmapper.writeValueAsString(resultMessage("Nothing has changed for sound channel with index $index")))
|
|
return@patch
|
|
} else {
|
|
|
|
// cek apakah ada soundchannel lain yang pakai ip dan channel yang sama
|
|
val othersc =
|
|
db.soundchannelDB.List.filter { sc -> sc.ip == _ip }
|
|
.filter { sc -> sc.index != index }
|
|
if (othersc.isNotEmpty()) {
|
|
it.status(400)
|
|
.result(objectmapper.writeValueAsString(resultMessage("This IP address is already used by another sound channel")))
|
|
} else {
|
|
// ada sesuatu yang ganti
|
|
val newsc = SoundChannel(0u, _channel, _ip)
|
|
if (db.soundchannelDB.UpdateByIndex(index.toInt(), newsc)) {
|
|
db.soundchannelDB.Resort()
|
|
it.result(
|
|
objectmapper.writeValueAsString(
|
|
resultMessage(
|
|
"OK"
|
|
)
|
|
)
|
|
)
|
|
} else {
|
|
it.status(500)
|
|
.result(
|
|
objectmapper.writeValueAsString(
|
|
resultMessage("Failed to update sound channel with index $index")
|
|
)
|
|
)
|
|
}
|
|
}
|
|
|
|
|
|
}
|
|
|
|
} else {
|
|
it.status(400)
|
|
.result(objectmapper.writeValueAsString(resultMessage("Invalid IP address")))
|
|
}
|
|
} else {
|
|
it.status(400)
|
|
.result(objectmapper.writeValueAsString(resultMessage("Invalid channel")))
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
|
|
}
|
|
get("ExportXLSX") {
|
|
val xlsxdata = db.soundchannelDB.Export_XLSX()
|
|
if (xlsxdata != null) {
|
|
it.header(
|
|
"Content-Type",
|
|
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
|
|
)
|
|
it.header("Content-Disposition", "attachment; filename=\"soundchannel.xlsx\"")
|
|
it.outputStream().use { out ->
|
|
xlsxdata.write(out)
|
|
}
|
|
} else {
|
|
it.status(500)
|
|
.result(objectmapper.writeValueAsString(resultMessage("Failed to export sound channel to XLSX")))
|
|
}
|
|
}
|
|
post("ImportXLSX") {
|
|
val uploaded = it.uploadedFile("file")
|
|
if (uploaded == null) {
|
|
it.status(400)
|
|
.result(objectmapper.writeValueAsString(resultMessage("No file uploaded")))
|
|
return@post
|
|
}
|
|
try {
|
|
val xlsx = XSSFWorkbook(uploaded.content())
|
|
if (db.soundchannelDB.Import_XLSX(xlsx)) {
|
|
db.soundchannelDB.Resort()
|
|
it.result(objectmapper.writeValueAsString(resultMessage("OK")))
|
|
} else {
|
|
it.status(500)
|
|
.result(objectmapper.writeValueAsString(resultMessage("Failed to import sound channel from XLSX")))
|
|
}
|
|
} catch (e: Exception) {
|
|
it.status(400)
|
|
.result(objectmapper.writeValueAsString(resultMessage("Invalid XLSX file")))
|
|
}
|
|
}
|
|
}
|
|
|
|
path("QueuePaging") {
|
|
get("List") { ctx ->
|
|
db.queuepagingDB.Get({
|
|
ctx.result(MariaDB.ArrayListtoString(db.queuepagingDB.List))
|
|
}, { msgFail ->
|
|
ctx.status(500).result(objectmapper.writeValueAsString(resultMessage(msgFail)))
|
|
})
|
|
|
|
}
|
|
delete("List") {
|
|
// truncate queue paging table
|
|
if (db.queuepagingDB.Clear()) {
|
|
db.queuepagingDB.Get()
|
|
it.result(objectmapper.writeValueAsString(resultMessage("OK")))
|
|
} else {
|
|
it.status(500)
|
|
.result(objectmapper.writeValueAsString(resultMessage("Failed to truncate queue paging table")))
|
|
}
|
|
}
|
|
delete("DeleteByIndex/{index}") {
|
|
// delete by index
|
|
val index = it.pathParam("index").toUIntOrNull()
|
|
if (index == null) {
|
|
it.status(400)
|
|
.result(objectmapper.writeValueAsString(resultMessage("Invalid index")))
|
|
} else {
|
|
if (db.queuepagingDB.DeleteByIndex(index.toInt())) {
|
|
db.queuepagingDB.Resort()
|
|
it.result(objectmapper.writeValueAsString(resultMessage("OK")))
|
|
db.logDB.Add("AAS", "Deleted queue paging with index $index")
|
|
} else {
|
|
it.status(500)
|
|
.result(objectmapper.writeValueAsString(resultMessage("Failed to delete queue paging with index $index")))
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
path("QueueTable") {
|
|
get("List") { ctx ->
|
|
db.queuetableDB.Get({
|
|
ctx.result(MariaDB.ArrayListtoString(db.queuetableDB.List))
|
|
}, { msgFail ->
|
|
ctx.status(500).result(objectmapper.writeValueAsString(resultMessage(msgFail)))
|
|
})
|
|
|
|
}
|
|
delete("List") {
|
|
// truncate queue table
|
|
if (db.queuetableDB.Clear()) {
|
|
db.queuetableDB.Get()
|
|
it.result(objectmapper.writeValueAsString(resultMessage("OK")))
|
|
} else {
|
|
it.status(500)
|
|
.result(objectmapper.writeValueAsString(resultMessage("Failed to truncate queue sound table")))
|
|
}
|
|
}
|
|
delete("DeleteByIndex/{index}") {
|
|
// delete by index
|
|
val index = it.pathParam("index").toUIntOrNull()
|
|
if (index == null) {
|
|
it.status(400)
|
|
.result(objectmapper.writeValueAsString(resultMessage("Invalid index")))
|
|
} else {
|
|
if (db.queuetableDB.DeleteByIndex(index.toInt())) {
|
|
db.queuetableDB.Resort()
|
|
it.result(objectmapper.writeValueAsString(resultMessage("OK")))
|
|
db.logDB.Add("AAS", "Deleted queue sound with index $index")
|
|
|
|
} else {
|
|
it.status(500)
|
|
.result(objectmapper.writeValueAsString(resultMessage("Failed to delete queue sound with index $index")))
|
|
}
|
|
}
|
|
}
|
|
}
|
|
path("FileManager") {
|
|
get("PagingResultList") {
|
|
it.result(objectmapper.writeValueAsString(ListAudioFiles(Somecodes.PagingResult_directory)))
|
|
}
|
|
delete("DeleteOldPagingResultFiles/{days}") {
|
|
// kalau tidak ada, default 7 hari
|
|
val days = it.pathParam("days").toIntOrNull() ?: 7
|
|
Somecodes.Delete_Old_PagingResult_Files(days) { success, failed ->
|
|
it.result(objectmapper.writeValueAsString(resultMessage("Old paging result files deleted. Deleted: $success, Failed: $failed")))
|
|
}
|
|
}
|
|
delete("ClearPagingResultFiles") {
|
|
Somecodes.Clear_PagingResult_Directory { success, failed ->
|
|
it.result(objectmapper.writeValueAsString(resultMessage("Paging result files cleared. Deleted: $success, Failed: $failed")))
|
|
}
|
|
}
|
|
post("DownloadPagingResultFile") {
|
|
val json: JsonNode = objectmapper.readTree(it.body())
|
|
val filename = json.get("filename").asText("")
|
|
if (filename.isNotEmpty()) {
|
|
val p: Path = Somecodes.PagingResult_directory.resolve(filename)
|
|
if (ValidFile(p)) {
|
|
it.header("Content-Disposition", "attachment; filename=\"$filename\"")
|
|
it.outputStream().use { out ->
|
|
Files.newInputStream(p).use { inp ->
|
|
inp.copyTo(out)
|
|
}
|
|
}
|
|
} else it.status(400)
|
|
.result(objectmapper.writeValueAsString(resultMessage("File not found")))
|
|
} else it.status(400)
|
|
.result(objectmapper.writeValueAsString(resultMessage("Filename is empty")))
|
|
}
|
|
post("PlayPagingResultFile") {
|
|
val json: JsonNode = objectmapper.readTree(it.body())
|
|
val filename = json.get("filename").asText("")
|
|
if (filename.isNotEmpty()) {
|
|
val p: Path = Somecodes.PagingResult_directory.resolve(filename)
|
|
if (ValidFile(p)) {
|
|
val mimeType = Files.probeContentType(p) ?: "audio/wav"
|
|
it.contentType(mimeType)
|
|
it.header("Accept-Ranges", "bytes")
|
|
it.result(Files.newInputStream(p))
|
|
} else it.status(400)
|
|
.result(objectmapper.writeValueAsString(resultMessage("File not found")))
|
|
} else it.status(400)
|
|
.result(objectmapper.writeValueAsString(resultMessage("Filename is empty")))
|
|
}
|
|
get("SoundbankResultList") {
|
|
it.result(objectmapper.writeValueAsString(ListAudioFiles(Somecodes.SoundbankResult_directory)))
|
|
}
|
|
delete("DeleteOldSoundbankResultFiles/{days}") {
|
|
// kalau tidak ada, default 7 hari
|
|
val days = it.pathParam("days").toIntOrNull() ?: 7
|
|
Somecodes.Delete_Old_SoundbankResult_Files(days) { success, failed ->
|
|
it.result(objectmapper.writeValueAsString(resultMessage("Old soundbank result files deleted. Deleted: $success, Failed: $failed")))
|
|
}
|
|
}
|
|
delete("ClearSoundbankResultFiles") {
|
|
Somecodes.Clear_PagingResult_Directory { success, failed ->
|
|
it.result(objectmapper.writeValueAsString(resultMessage("Soundbank result files cleared. Deleted: $success, Failed: $failed")))
|
|
}
|
|
}
|
|
post("DownloadSoundbankResultFile") {
|
|
val json: JsonNode = objectmapper.readTree(it.body())
|
|
val filename = json.get("filename").asText("")
|
|
if (filename.isNotEmpty()) {
|
|
val p: Path = Somecodes.SoundbankResult_directory.resolve(filename)
|
|
if (ValidFile(p)) {
|
|
it.header("Content-Disposition", "attachment; filename=\"$filename\"")
|
|
it.outputStream().use { out ->
|
|
Files.newInputStream(p).use { inp ->
|
|
inp.copyTo(out)
|
|
}
|
|
}
|
|
} else it.status(400)
|
|
.result(objectmapper.writeValueAsString(resultMessage("File not found")))
|
|
} else it.status(400)
|
|
.result(objectmapper.writeValueAsString(resultMessage("Filename is empty")))
|
|
}
|
|
post("PlaySoundbankResultFile") {
|
|
val json: JsonNode = objectmapper.readTree(it.body())
|
|
val filename = json.get("filename").asText("")
|
|
if (filename.isNotEmpty()) {
|
|
val p: Path = Somecodes.SoundbankResult_directory.resolve(filename)
|
|
if (ValidFile(p)) {
|
|
val mimeType = Files.probeContentType(p) ?: "audio/wav"
|
|
it.contentType(mimeType)
|
|
it.header("Accept-Ranges", "bytes")
|
|
it.result(Files.newInputStream(p))
|
|
} else it.status(400)
|
|
.result(objectmapper.writeValueAsString(resultMessage("File not found")))
|
|
} else it.status(400)
|
|
.result(objectmapper.writeValueAsString(resultMessage("Filename is empty")))
|
|
}
|
|
get("ListSoundbank/{language}/{voice}/{category}") {
|
|
val language = it.pathParam("language")
|
|
val voice = it.pathParam("voice")
|
|
val category = it.pathParam("category")
|
|
if (ValidString(language) && Language.entries.any { lang -> lang.name == language }) {
|
|
if (ValidString(voice) && VoiceType.entries.any { vtype -> vtype.name == voice }) {
|
|
if (ValidString(category) && Category.entries.any { cat -> cat.name == category }) {
|
|
val targetdir = Somecodes.SoundbankDirectory(
|
|
Language.valueOf(language),
|
|
VoiceType.valueOf(voice),
|
|
Category.valueOf(category)
|
|
)
|
|
val result = ListAudioFiles(targetdir).map { mm ->
|
|
// just the filename, without path
|
|
mm.substring(mm.lastIndexOf(File.separator) + 1)
|
|
}
|
|
it.result(objectmapper.writeValueAsString(result))
|
|
} else {
|
|
it.status(400)
|
|
.result(objectmapper.writeValueAsString(resultMessage("Category parameter is invalid")))
|
|
}
|
|
} else {
|
|
it.status(400)
|
|
.result(objectmapper.writeValueAsString(resultMessage("VoiceType parameter is invalid")))
|
|
}
|
|
} else {
|
|
it.status(400)
|
|
.result(objectmapper.writeValueAsString(resultMessage("Language parameter is invalid")))
|
|
}
|
|
}
|
|
// tested ok
|
|
post("UploadSoundbank/{language}/{voice}/{category}") {
|
|
val language = it.pathParam("language")
|
|
val voice = it.pathParam("voice")
|
|
val category = it.pathParam("category")
|
|
|
|
val uploaded = it.uploadedFiles()
|
|
if (ValidString(language) && Language.entries.any { lang -> lang.name == language }) {
|
|
if (ValidString(voice) && VoiceType.entries.any { vtype -> vtype.name == voice }) {
|
|
if (ValidString(category) && Category.entries.any { cat -> cat.name == category }) {
|
|
if (uploaded.isNotEmpty()) {
|
|
val targetdir = Somecodes.SoundbankDirectory(
|
|
Language.valueOf(language),
|
|
VoiceType.valueOf(voice),
|
|
Category.valueOf(category)
|
|
)
|
|
if (!Files.isDirectory(targetdir)) Files.createDirectories(targetdir)
|
|
val successfiles = mutableListOf<String>()
|
|
val failedfiles = mutableListOf<String>()
|
|
val alreadyexists = mutableListOf<String>()
|
|
uploaded.forEach { ff ->
|
|
val targetfile = targetdir.resolve(ff.filename())
|
|
if (Files.exists(targetfile)) {
|
|
alreadyexists.add(ff.filename())
|
|
} else {
|
|
try {
|
|
Files.newOutputStream(targetfile).use { out ->
|
|
ff.content().use { inp ->
|
|
inp.copyTo(out)
|
|
}
|
|
}
|
|
Logger.info { "Uploaded soundbank file to ${targetfile.toAbsolutePath()}" }
|
|
successfiles.add(ff.filename())
|
|
} catch (e: Exception) {
|
|
Logger.error {
|
|
"Failed to upload soundbank file to ${targetfile.toAbsolutePath()}: ${e.message}"
|
|
}
|
|
failedfiles.add(ff.filename())
|
|
}
|
|
}
|
|
|
|
|
|
}
|
|
if (successfiles.size == uploaded.size) {
|
|
it.result(
|
|
objectmapper.writeValueAsString(
|
|
resultMessage(
|
|
"All files uploaded successfully: ${
|
|
successfiles.joinToString(
|
|
", "
|
|
)
|
|
}"
|
|
)
|
|
)
|
|
)
|
|
} else {
|
|
it.result(
|
|
objectmapper.writeValueAsString(
|
|
resultMessage(
|
|
"Some files uploaded successfully: ${
|
|
successfiles.joinToString(
|
|
", "
|
|
)
|
|
}, failed: ${failedfiles.joinToString(", ")}, already exists: ${
|
|
alreadyexists.joinToString(
|
|
", "
|
|
)
|
|
}"
|
|
)
|
|
)
|
|
)
|
|
}
|
|
} else {
|
|
it.status(400)
|
|
.result(objectmapper.writeValueAsString(resultMessage("No file uploaded")))
|
|
}
|
|
} else {
|
|
it.status(400)
|
|
.result(objectmapper.writeValueAsString(resultMessage("Category parameter is invalid")))
|
|
}
|
|
} else {
|
|
it.status(400)
|
|
.result(objectmapper.writeValueAsString(resultMessage("VoiceType parameter is invalid")))
|
|
}
|
|
} else {
|
|
it.status(400)
|
|
.result(objectmapper.writeValueAsString(resultMessage("Language parameter is invalid")))
|
|
}
|
|
}
|
|
}
|
|
path("Settings") {
|
|
path("OldResultDays") {
|
|
get {
|
|
it.result(objectmapper.writeValueAsString(resultMessage(_config.Get(configKeys.AUTO_DELETE_RESULT_DAYS.key))))
|
|
}
|
|
post {
|
|
val json: JsonNode = objectmapper.readTree(it.body())
|
|
val days = json.get("days").asInt(3)
|
|
_config.Set(configKeys.AUTO_DELETE_RESULT_DAYS.key, days.toString())
|
|
_config.Save()
|
|
Logger.info { "Changed Auto Delete Result Days to $days" }
|
|
it.result(objectmapper.writeValueAsString(resultMessage("OK")))
|
|
}
|
|
}
|
|
path("SoundbankDirectory") {
|
|
get {
|
|
val dir = _config.Get(configKeys.SOUNDBANK_DIRECTORY.key)
|
|
it.result(objectmapper.writeValueAsString(resultMessage(dir)))
|
|
}
|
|
post {
|
|
val json: JsonNode = objectmapper.readTree(it.body())
|
|
val newdir = json.get("directory").asText("")
|
|
if (ValidDirectory(newdir)) {
|
|
_config.Set(configKeys.SOUNDBANK_DIRECTORY.key, newdir)
|
|
_config.Save()
|
|
Somecodes.Soundbank_directory = Path.of(newdir)
|
|
|
|
Logger.info { "Changed Soundbank Directory to $newdir" }
|
|
it.result(objectmapper.writeValueAsString(resultMessage("OK")))
|
|
} else {
|
|
it.status(400)
|
|
.result(objectmapper.writeValueAsString(resultMessage("Invalid directory value")))
|
|
}
|
|
}
|
|
}
|
|
path("FISCode") {
|
|
get {
|
|
val value = object {
|
|
//get from config file
|
|
val GOP = _config.Get(configKeys.REMARK_GOP.key)
|
|
val GBD = _config.Get(configKeys.REMARK_GBD.key)
|
|
val GFC = _config.Get(configKeys.REMARK_GFC.key)
|
|
val FLD = _config.Get(configKeys.REMARK_FLD.key)
|
|
val defaultvoice = _config.Get(configKeys.DEFAULT_VOICE_TYPE.key)
|
|
val autodeleteresult = _config.Get(configKeys.AUTO_DELETE_RESULT_DAYS.key)
|
|
}
|
|
it.result(objectmapper.writeValueAsString(value))
|
|
}
|
|
post {
|
|
val json: JsonNode = objectmapper.readTree(it.body())
|
|
val _gop = json.get("GOP").asText("")
|
|
val _gbd = json.get("GBD").asText("")
|
|
val _gfc = json.get("GFC").asText("")
|
|
val _fld = json.get("FLD").asText("")
|
|
val defaultvoice = json.get("defaultvoice").asText("")
|
|
if (ValidString(_gop) && ValidString(_gbd) && ValidString(_gfc) && ValidString(_fld)) {
|
|
// save to config file
|
|
_config.Set(configKeys.REMARK_GOP.key, _gop)
|
|
_config.Set(configKeys.REMARK_GBD.key, _gbd)
|
|
_config.Set(configKeys.REMARK_GFC.key, _gfc)
|
|
_config.Set(configKeys.REMARK_FLD.key, _fld)
|
|
_config.Set(configKeys.DEFAULT_VOICE_TYPE.key, defaultvoice)
|
|
_config.Save()
|
|
Logger.info { "Changed FIS Codes" }
|
|
db.logDB.Add(
|
|
"AAS",
|
|
"Save FIS Codes Message: GOP=$_gop, GBD=$_gbd, GFC=$_gfc, FLD=$_fld, DefaultVoice=$defaultvoice"
|
|
)
|
|
it.result(objectmapper.writeValueAsString(resultMessage("OK")))
|
|
} else {
|
|
it.status(400)
|
|
.result(objectmapper.writeValueAsString(resultMessage("Invalid FIS code value")))
|
|
}
|
|
}
|
|
}
|
|
path("WebAccess") {
|
|
get {
|
|
val value = object {
|
|
val adminpass = _config.Get(configKeys.WEBAPP_ADMIN_PASSWORD.key)
|
|
val viewerpass = _config.Get(configKeys.WEBAPP_VIEWER_PASSWORD.key)
|
|
}
|
|
it.result(objectmapper.writeValueAsString(value))
|
|
}
|
|
post {
|
|
val json: JsonNode = objectmapper.readTree(it.body())
|
|
val adminpass = json.get("adminpass").asText("")
|
|
val viewerpass = json.get("viewerpass").asText("")
|
|
if (ValidString(adminpass) && ValidString(viewerpass)) {
|
|
_config.Set(configKeys.WEBAPP_ADMIN_PASSWORD.key, adminpass)
|
|
_config.Set(configKeys.WEBAPP_VIEWER_PASSWORD.key, viewerpass)
|
|
_config.Save()
|
|
Logger.info { "Changed Web Access Passwords" }
|
|
// update userlist
|
|
userlist = listOf(
|
|
Pair(
|
|
_config.Get(configKeys.WEBAPP_ADMIN_USERNAME.key),
|
|
_config.Get(configKeys.WEBAPP_ADMIN_PASSWORD.key)
|
|
),
|
|
Pair(
|
|
_config.Get(configKeys.WEBAPP_VIEWER_USERNAME.key),
|
|
_config.Get(configKeys.WEBAPP_VIEWER_PASSWORD.key)
|
|
)
|
|
)
|
|
it.result(objectmapper.writeValueAsString(resultMessage("OK")))
|
|
} else {
|
|
it.status(400)
|
|
.result(objectmapper.writeValueAsString(resultMessage("Password cannot be empty")))
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
}
|
|
}.start(listenPort)
|
|
|
|
}
|
|
|
|
private fun Start_SemiAutoServer() {
|
|
Logger.info { "Starting SemiAuto web server at port ${listenPort + 1}" }
|
|
semiauto = Javalin.create { config ->
|
|
config.useVirtualThreads = true
|
|
config.staticFiles.add("/semiauto")
|
|
config.jsonMapper(JavalinJackson(jacksonObjectMapper()))
|
|
config.router.apiBuilder {
|
|
before {
|
|
//Logger.info{"${it.ip()} method ${it.method()} connect to ${it.path()}"}
|
|
}
|
|
path("/") {
|
|
get {
|
|
it.cookie("semiauto-user", "")
|
|
it.redirect("login.html")
|
|
}
|
|
}
|
|
path("logout") {
|
|
get {
|
|
it.cookie("semiauto-user", "")
|
|
it.redirect("login.html")
|
|
}
|
|
}
|
|
path("login.html") {
|
|
post {
|
|
val formuser = it.formParam("username") ?: ""
|
|
val formpass = it.formParam("password") ?: ""
|
|
if (formuser.isNotEmpty() && formpass.isNotEmpty()) {
|
|
val user = db.userDB.List.find { u -> u.username == formuser && u.password == formpass }
|
|
if (user != null) {
|
|
it.cookie("semiauto-user", user.username)
|
|
it.redirect("index.html")
|
|
|
|
db.logSemiAuto.Add(
|
|
LogSemiauto.NewLog(
|
|
"SEMIAUTOWEB",
|
|
"User logged in: ${user.username} from ip ${it.ip()}"
|
|
)
|
|
)
|
|
} else ResultMessageString(it, 400, "Invalid username or password")
|
|
} else ResultMessageString(it, 400, "Username or password cannot be empty")
|
|
}
|
|
}
|
|
path("index.html") {
|
|
before { CheckSemiAutoUsers(it) }
|
|
}
|
|
path("log.html") {
|
|
before { CheckSemiAutoUsers(it) }
|
|
}
|
|
path("api") {
|
|
|
|
path("Initialize") {
|
|
get { ctx ->
|
|
val username = ctx.cookie("semiauto-user") ?: ""
|
|
if (username.isNotEmpty()) {
|
|
val user = db.userDB.List.find { u -> u.username == username }
|
|
if (user != null) {
|
|
val result = SemiAutoInitData(username)
|
|
// messages
|
|
String_To_List(user.messagebank_ann_id).forEach { msg ->
|
|
//println("Looking for message ANN_ID: $msg")
|
|
db.messageDB.List.filter { it.ANN_ID == msg.toUInt() }.forEach { xx ->
|
|
//println("Adding message: ${xx.ANN_ID};${xx.Description};${xx.Language};${xx.Message_Detail}")
|
|
result.messages.add("${xx.ANN_ID};${xx.Description};${xx.Language};${xx.Message_Detail}")
|
|
}
|
|
}
|
|
// broacdcast zones
|
|
result.broadcastzones = String_To_List(user.broadcastzones)
|
|
// cities
|
|
String_To_List(user.city_tags).forEach { ct ->
|
|
db.soundDB.List.firstOrNull { it.TAG == ct && it.Category == Category.City.name }
|
|
?.let {
|
|
result.cities.add("${it.TAG};${it.Description}")
|
|
}
|
|
}
|
|
// airplane names
|
|
String_To_List(user.airline_tags).forEach { at ->
|
|
db.soundDB.List.firstOrNull { it.TAG == at && it.Category == Category.Airplane_Name.name }
|
|
?.let {
|
|
result.airlines.add("${it.TAG};${it.Description}")
|
|
}
|
|
}
|
|
// places
|
|
db.soundDB.List.filter { it.Category == Category.Places.name }.distinctBy { it.TAG }
|
|
.forEach { xx ->
|
|
result.places.add("${xx.TAG};${xx.Description}")
|
|
}
|
|
// shalat
|
|
db.soundDB.List.filter { it.Category == Category.Shalat.name }.distinctBy { it.TAG }
|
|
.forEach { xx ->
|
|
result.shalat.add("${xx.TAG};${xx.Description}")
|
|
}
|
|
// sequences
|
|
db.soundDB.List.filter { it.Category == Category.Sequence.name }
|
|
.distinctBy { it.TAG }.forEach { xx ->
|
|
result.sequences.add("${xx.TAG};${xx.Description}")
|
|
}
|
|
// reasons
|
|
db.soundDB.List.filter { it.Category == Category.Reason.name }.distinctBy { it.TAG }
|
|
.forEach { xx ->
|
|
result.reasons.add("${xx.TAG};${xx.Description}")
|
|
}
|
|
// procedures
|
|
db.soundDB.List.filter { it.Category == Category.Procedure.name }
|
|
.distinctBy { it.TAG }.forEach { xx ->
|
|
result.procedures.add("${xx.TAG};${xx.Description}")
|
|
}
|
|
// gates
|
|
db.soundDB.List.filter { it.Category == Category.Gate.name }.distinctBy { it.TAG }
|
|
.forEach { xx ->
|
|
result.gates.add("${xx.TAG};${xx.Description}")
|
|
}
|
|
// compensation
|
|
db.soundDB.List.filter { it.Category == Category.Compensation.name }
|
|
.distinctBy { it.TAG }.forEach { xx ->
|
|
result.compensation.add("${xx.TAG};${xx.Description}")
|
|
}
|
|
// greetings
|
|
db.soundDB.List.filter { it.Category == Category.Greeting.name }
|
|
.distinctBy { it.TAG }.forEach { xx ->
|
|
result.greetings.add("${xx.TAG};${xx.Description}")
|
|
}
|
|
|
|
ctx.result(objectmapper.writeValueAsString(result))
|
|
db.logSemiAuto.Add(
|
|
LogSemiauto.NewLog(
|
|
"SEMIAUTOWEB",
|
|
"Initialized Web variables for user: ${user.username}"
|
|
)
|
|
)
|
|
} else ResultMessageString(ctx, 400, "User not found")
|
|
} else ResultMessageString(ctx, 400, "Username is empty")
|
|
}
|
|
}
|
|
path("SemiAuto") {
|
|
post { ctx ->
|
|
val json: JsonNode = objectmapper.readTree(ctx.body())
|
|
// butuh description, languages, tags, dan broadcastzones
|
|
val description = json.get("description").asText("")
|
|
val languages = json.get("languages").asText("")
|
|
val tags = json.get("tags").asText("")
|
|
val broadcastzones = json.get("broadcastzones").asText("")
|
|
if (description.isNotEmpty()) {
|
|
if (languages.isNotEmpty()) {
|
|
if (tags.isNotEmpty()) {
|
|
if (broadcastzones.isNotEmpty()) {
|
|
val qt = QueueTable(
|
|
0u,
|
|
LocalDateTime.now().format(datetimeformat1),
|
|
"SEMIAUTOWEB",
|
|
"SOUNDBANK",
|
|
description,
|
|
tags,
|
|
broadcastzones,
|
|
1u,
|
|
languages
|
|
)
|
|
if (db.queuetableDB.Add(qt)) {
|
|
db.queuetableDB.Resort()
|
|
Logger.info { "SemiAutoWeb added to queue table: $qt" }
|
|
ctx.result(objectmapper.writeValueAsString(resultMessage("OK")))
|
|
db.logSemiAuto.Add(
|
|
LogSemiauto.NewLog(
|
|
"SEMIAUTOWEB",
|
|
"Added to queue table: $qt"
|
|
)
|
|
)
|
|
} else ResultMessageString(ctx, 500, "Failed to add to queue table")
|
|
} else ResultMessageString(ctx, 400, "Broadcast zones cannot be empty")
|
|
} else ResultMessageString(ctx, 400, "Tags cannot be empty")
|
|
} else ResultMessageString(ctx, 400, "Languages cannot be empty")
|
|
} else ResultMessageString(ctx, 400, "Description cannot be empty")
|
|
|
|
}
|
|
}
|
|
get("ExportXLSX") { get1 ->
|
|
val logdate = get1.queryParam("date") ?: ""
|
|
val logfilter = get1.queryParam("filter") ?: ""
|
|
if (ValiDateForLogHtml(logdate)) {
|
|
val xlsxdata = if (ValidString(logfilter)) {
|
|
db.logDB.Export_Log_XLSX(logdate.replace('-', '/'), logfilter)
|
|
} else {
|
|
db.logDB.Export_Log_XLSX(logdate.replace('-', '/'), "")
|
|
}
|
|
if (xlsxdata != null) {
|
|
get1.header(
|
|
"Content-Type",
|
|
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
|
|
)
|
|
get1.header("Content-Disposition", "attachment; filename=\"log_$logdate.xlsx\"")
|
|
get1.outputStream().use { out ->
|
|
xlsxdata.write(out)
|
|
}
|
|
} else {
|
|
get1.status(500)
|
|
.result(objectmapper.writeValueAsString(resultMessage("Failed to export log to XLSX")))
|
|
}
|
|
} else get1.status(400)
|
|
.result(objectmapper.writeValueAsString(resultMessage("Invalid date format must be dd-MM-yyyy")))
|
|
}
|
|
path("Log") {
|
|
get("/{datelog}") { ctx ->
|
|
val datelog = ctx.pathParam("datelog")
|
|
println("Request log for date: $datelog")
|
|
db.logSemiAuto.GetLogSemiAutoForHtml(datelog, null, {
|
|
ctx.result(MariaDB.ArrayListtoString(it))
|
|
}, { err ->
|
|
ctx.status(500).result(objectmapper.writeValueAsString(resultMessage(err)))
|
|
})
|
|
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}.start(listenPort + 1)
|
|
}
|
|
|
|
fun ResultMessageString(ctx: Context, code: Int, message: String) {
|
|
ctx.status(code).result(objectmapper.writeValueAsString(resultMessage(message)))
|
|
}
|
|
|
|
fun CheckSemiAutoUsers(ctx: Context) {
|
|
val user = ctx.cookie("semiauto-user")
|
|
if (user == null) {
|
|
ctx.redirect("login.html")
|
|
}
|
|
val foundUser = db.userDB.List.find { u -> u.username == user }
|
|
if (foundUser == null) {
|
|
ctx.redirect("login.html")
|
|
}
|
|
}
|
|
|
|
fun CheckUsers(ctx: Context): String? {
|
|
//val user = ctx.sessionAttribute<String?>("user")
|
|
val user = ctx.cookie("aas-user")
|
|
if (user == null) {
|
|
ctx.redirect("login.html")
|
|
return null
|
|
}
|
|
val foundUser = userlist.find { it.first == user }
|
|
if (foundUser == null) {
|
|
ctx.redirect("login.html")
|
|
return null
|
|
}
|
|
return foundUser.first
|
|
}
|
|
|
|
fun GetAdminUserFromConfig(): String {
|
|
return config.Get(configKeys.WEBAPP_ADMIN_USERNAME.key)
|
|
}
|
|
|
|
|
|
fun Get_Barix_Connection_by_ZoneName(zonename: String): BarixConnection? {
|
|
if (ValidString(zonename)) {
|
|
val bz = db.broadcastDB.List.find { it.description == zonename }
|
|
val sc = if (bz != null) db.soundchannelDB.List.find { it.channel == bz.SoundChannel } else null
|
|
val ip = sc?.ip ?: ""
|
|
if (ValidIPV4(ip)) {
|
|
// ketemu ip-nya
|
|
return StreamerOutputs[ip]
|
|
|
|
}
|
|
}
|
|
return null
|
|
}
|
|
|
|
fun Stop() {
|
|
app.stop()
|
|
semiauto.stop()
|
|
}
|
|
} |