From b692e2c2c9028009a7578754451acec64ba4d062 Mon Sep 17 00:00:00 2001 From: rdkartono Date: Thu, 11 Sep 2025 16:03:33 +0700 Subject: [PATCH] commit 11/09/2025 --- html/webpage/assets/js/script.js | 451 ++++++++++++++++++++++++------- html/webpage/language.html | 7 + html/webpage/messagebank.html | 7 + html/webpage/timer.html | 89 +++++- src/content/Language.kt | 2 +- src/database/MariaDB.kt | 127 ++++++++- src/web/WebApp.kt | 291 +++++++++++++------- src/web/resultMessage.kt | 4 + 8 files changed, 767 insertions(+), 211 deletions(-) create mode 100644 src/web/resultMessage.kt diff --git a/html/webpage/assets/js/script.js b/html/webpage/assets/js/script.js index a5cfe7c..f9577dd 100644 --- a/html/webpage/assets/js/script.js +++ b/html/webpage/assets/js/script.js @@ -323,7 +323,7 @@ let ws = null; function sendCommand(command, data) { if (ws.readyState === WebSocket.OPEN) { ws.send(JSON.stringify({ command, data })); - } + } } /** @@ -356,12 +356,12 @@ function fetchAPI(endpoint, method, headers = {}, body = null, cbOK, cbError) { } return response.json(); }) - .then(data => { + .then(data => { //console.log("fetchAPI: received data", data); cbOK(data); }) .catch(error => { - // console.error('There was a problem with the fetch operation:', error); + // console.error('There was a problem with the fetch operation:', error); cbError(error); }); } @@ -379,7 +379,7 @@ function reloadSoundBank(APIURL) { fill_soundbanktablebody(soundbankdata); } }, (errdata) => { - alert("Error loading soundbank: " + errdata.message); + alert("Error loading soundbank : " + errdata.message); }); } @@ -396,7 +396,7 @@ function reloadMessageBank(APIURL) { fill_messagebanktablebody(messagebankdata); } }, (errdata) => { - alert("Error loading messagebank: " + errdata.message); + alert("Error loading messagebank : " + errdata.message); }); } @@ -413,7 +413,7 @@ function reloadLanguageBank(APIURL) { fill_languagebanktablebody(languagebankdata); } }, (errdata) => { - alert("Error loading languagebank: " + errdata.message); + alert("Error loading languagebank : " + errdata.message); }); } @@ -425,12 +425,12 @@ function reloadTimerBank(APIURL) { schedulebankdata = []; fetchAPI(APIURL + "List", "GET", {}, null, (okdata) => { if (Array.isArray(okdata)) { - schedulebankdata = okdata.data; + schedulebankdata = okdata; selectedschedulerow = null; fill_schedulebanktablebody(schedulebankdata); } }, (errdata) => { - alert("Error loading schedulebank: " + errdata.message); + alert("Error loading schedulebank : " + errdata.message); }); } @@ -447,9 +447,12 @@ function reloadLogs(APIURL, date, filter) { }) fetchAPI(APIURL + "List?" + params.toString(), "GET", {}, null, (okdata) => { //console.log("Logs data received", okdata); - fill_logtablebody(okdata); + if (Array.isArray(okdata)) { + logdata = okdata; + fill_logtablebody(okdata); + } }, (errdata) => { - alert("Error loading logs: " + errdata.message); + alert("Error loading logs : " + errdata.message); }); } @@ -469,7 +472,7 @@ function regetSoundbankFiles(APIURL = "SoundBank/") { select2results.results = soundbankfiles.map((item, index) => ({ id: index + 1, text: item })); } else console.log("regetSoundbankFiles: okdata is not array"); }, (errdata) => { - alert("Error loading soundbank files: " + errdata.message); + alert("Error loading soundbank files : " + errdata.message); }); } @@ -485,7 +488,7 @@ function getVoiceTypes() { //console.log("Loaded " + voiceTypes.length + " voice types : " + voiceTypes.join(", ")); } else console.log("getVoiceTypes: okdata is not array"); }, (errdata) => { - alert("Error loading voice types: " + errdata.message); + alert("Error loading voice types : " + errdata.message); }); } @@ -501,7 +504,7 @@ function getCategories() { //console.log("Loaded " + categories.length + " categories : " + categories.join(", ")); } else console.log("getCategories: okdata is not array"); }, (errdata) => { - alert("Error loading categories: " + errdata.message); + alert("Error loading categories : " + errdata.message); }); } @@ -517,7 +520,7 @@ function getLanguages() { //console.log("Loaded " + languages.length + " languages : " + languages.join(", ") ); } else console.log("getLanguages: okdata is not array"); }, (errdata) => { - alert("Error loading languages: " + errdata.message); + alert("Error loading languages : " + errdata.message); }); } @@ -533,7 +536,7 @@ function getScheduledDays() { //console.log("Loaded " + scheduledays.length + " scheduled days : " + scheduledays.join(", ") ); } else console.log("getScheduledDays: okdata is not array"); }, (errdata) => { - alert("Error loading scheduled days: " + errdata.message); + alert("Error loading scheduled days : " + errdata.message); }); } @@ -729,7 +732,8 @@ $(document).ready(function () { reloadSoundBank(APIURL); $('#findsoundbank').on('input', function () { let searchTerm = $(this).val().trim().toLowerCase(); - if (searchTerm.length>0){ + if (searchTerm.length > 0) { + selectedsoundrow = null; let filtered = soundbankdata.filter(item => item.description.toLowerCase().includes(searchTerm) || item.tag.toLowerCase().includes(searchTerm) || item.path.toLowerCase().includes(searchTerm)); fill_soundbanktablebody(filtered); } else { @@ -739,14 +743,12 @@ $(document).ready(function () { }); $btnClear.click(() => { DoClear(APIURL, "Soundbank", (okdata) => { - alert("Success clear soundbank" + okdata.message); - soundbankdata = [] - selectedsoundrow = null; - fill_soundbanktablebody(soundbankdata); + reloadSoundBank(APIURL); + alert("Success clear soundbank : " + okdata.message); }, (errdata) => { - alert("Error clear soundbank: " + errdata.message); + alert("Error clear soundbank : " + errdata.message); }); - + }); $btnAdd.click(() => { $('.js-example-basic-single').select2({ @@ -779,12 +781,10 @@ $(document).ready(function () { } if (confirm(`Are you sure to delete soundbank [${sb.index}] Description=${sb.description} Tag=${sb.tag}?`)) { fetchAPI(APIURL + "DeleteByIndex/" + sb.index, "DELETE", {}, null, (okdata) => { - alert("Success delete soundbank" + okdata.message); - soundbankdata = soundbankdata.filter(item => item.index !== sb.index); - selectedsoundrow = null; - fill_soundbanktablebody(soundbankdata); + reloadSoundBank(APIURL); + alert("Success delete soundbank : " + okdata.message); }, (errdata) => { - alert("Error delete soundbank: " + errdata.message); + alert("Error delete soundbank : " + errdata.message); }); } } @@ -813,17 +813,18 @@ $(document).ready(function () { } }); $btnExport.click(() => { - DoExport(APIURL, "soundbank.xlsx",{}); + DoExport(APIURL, "soundbank.xlsx", {}); }); $btnImport.click(() => { DoImport(APIURL, (okdata) => { reloadSoundBank(APIURL); + alert("Success import soundbank : " + okdata.message); }, (errdata) => { - alert("Error importing soundbank from XLSX: " + errdata.message); + alert("Error importing soundbank from XLSX : " + errdata.message); }); }); } else { - console.error("Error loading soundbank content:", xhr.status, xhr.statusText); + console.error("Error loading soundbank content : ", xhr.status, xhr.statusText); } }); @@ -845,19 +846,30 @@ $(document).ready(function () { $btnRemove.prop('disabled', true); $btnEdit.prop('disabled', true); let APIURL = "MessageBank/"; + let $findmessage = $('#findmessage'); + + $findmessage.on('input', function () { + let searchTerm = $findmessage.val().toLowerCase(); + if (searchTerm.length > 0) { + selectedmessagerow = null; + let filtered = messagebankdata.filter(item => item.description.toLowerCase().includes(searchTerm) || item.message_Detail.toLowerCase().includes(searchTerm) || item.message_TAGS.toLowerCase().includes(searchTerm)); + fill_messagebanktablebody(filtered); + } else { + selectedmessagerow = null; + fill_messagebanktablebody(messagebankdata); + } + }); reloadMessageBank(APIURL); $btnClear.click(() => { DoClear(APIURL, "Messagebank", (okdata) => { - alert("Success clear messagebank" + okdata.message); - messagebankdata = [] - selectedmessagerow = null; - fill_messagebanktablebody(messagebankdata); + reloadMessageBank(APIURL); + alert("Success clear messagebank : " + okdata.message); }, (errdata) => { - alert("Error clear messagebank: " + errdata.message); + alert("Error clear messagebank : " + errdata.message); }); - + }); $btnAdd.click(() => { let $modal = $('#messagebankmodal'); @@ -892,12 +904,10 @@ $(document).ready(function () { if (confirm(`Are you sure to delete messagebank [${mb.index}] Description=${mb.description}? ANN_ID=${mb.aNN_ID} Language=${mb.language} Voice_Type=${mb.voice_Type} `)) { fetchAPI(APIURL + "DeleteByIndex/" + mb.index, "DELETE", {}, null, (okdata) => { - alert("Success delete messagebank" + okdata.message); - messagebankdata = messagebankdata.filter(item => item.index !== mb.index); - selectedmessagerow = null; - fill_messagebanktablebody(messagebankdata); + reloadMessageBank(APIURL); + alert("Success delete messagebank : " + okdata.message); }, (errdata) => { - alert("Error delete messagebank: " + errdata.message); + alert("Error delete messagebank : " + errdata.message); }); } } @@ -921,17 +931,18 @@ $(document).ready(function () { } }); $btnExport.click(() => { - DoExport(APIURL, "messagebank.xlsx",{}); + DoExport(APIURL, "messagebank.xlsx", {}); }); $btnImport.click(() => { DoImport(APIURL, (okdata) => { reloadMessageBank(APIURL); + alert("Success import messagebank : " + okdata.message); }, (errdata) => { - alert("Error importing messagebank from XLSX: " + errdata.message); + alert("Error importing messagebank from XLSX : " + errdata.message); }); }); } else { - console.error("Error loading messagebank content:", xhr.status, xhr.statusText); + console.error("Error loading messagebank content : ", xhr.status, xhr.statusText); } }); @@ -953,33 +964,54 @@ $(document).ready(function () { $btnRemove.prop('disabled', true); $btnEdit.prop('disabled', true); let APIURL = "LanguageLink/"; - + let $findlanguage = $('#findlanguage'); + let $modal = $('#languagemodal'); + let $langid = $modal.find('#languagelinkindex'); + let $langtag = $modal.find('#languagelinktag'); + let $cbInd = $modal.find('#langId'); + let $cbLocal = $modal.find('#langLocal'); + let $cbEn = $modal.find('#langEn'); + let $cbArb = $modal.find('#langArb'); + let $cbJap = $modal.find('#langJap'); + let $cbChi = $modal.find('#langChi'); + function clearLanguageModal() { + $langid.prop('disabled', true).val(''); + $langtag.val(''); + $cbInd.prop('checked', false); + $cbLocal.prop('checked', false); + $cbEn.prop('checked', false); + $cbArb.prop('checked', false); + $cbJap.prop('checked', false); + $cbChi.prop('checked', false); + } + $findlanguage.on('input', function () { + let searchTerm = $findlanguage.val().toLowerCase(); + if (searchTerm.length > 0) { + selectedlanguagerow = null; + let filtered = languagebankdata.filter(item => item.tag.toLowerCase().includes(searchTerm) || item.language.toLowerCase().includes(searchTerm)); + fill_languagebanktablebody(filtered); + } else { + selectedlanguagerow = null; + fill_languagebanktablebody(languagebankdata); + } + }); reloadLanguageBank(APIURL); $btnClear.click(() => { DoClear(APIURL, "LanguageLink", (okdata) => { - alert("Success clear languageLink" + okdata.message); - languagebankdata = [] - selectedlanguagerow = null; - fill_languagebanktablebody(languagebankdata); + reloadLanguageBank(APIURL); + alert("Success clear languageLink : " + okdata.message); }, (errdata) => { - alert("Error clear languagebank: " + errdata.message); + alert("Error clear languageLink : " + errdata.message); }); - + }); $btnAdd.click(() => { // show modal with id 'languagemodal' - let $modal = $('#languagemodal'); $modal.modal('show'); - let $langtag = $modal.find('#languagelinktag'); - let $cbInd = $modal.find('#langId'); - let $cbLocal = $modal.find('#langLocal'); - let $cbEn = $modal.find('#langEn'); - let $cbArb = $modal.find('#langArb'); - let $cbJap = $modal.find('#langJap'); - let $cbChi = $modal.find('#langChi'); + clearLanguageModal(); // save button click event $modal.off('click.languagelinksave').on('click.languagelinksave', '#languagelinksave', function () { @@ -1007,10 +1039,10 @@ $(document).ready(function () { language: langString } fetchAPI(APIURL + "Add", "POST", {}, ll, (okdata) => { - alert("Success add language" + okdata.message); + alert("Success add language : " + okdata.message); reloadLanguageBank(APIURL); }, (errdata) => { - alert("Error add language: " + errdata.message); + alert("Error add language : " + errdata.message); }); $modal.modal('hide'); @@ -1032,12 +1064,10 @@ $(document).ready(function () { } if (confirm(`Are you sure to delete language [${ll.index}] Tag=${ll.tag} Language=${ll.language}?`)) { fetchAPI(APIURL + "DeleteByIndex/" + ll.index, "DELETE", {}, null, (okdata) => { - alert("Success delete language" + okdata.message); - languagebankdata = languagebankdata.filter(item => item.index !== ll.index); - selectedlanguagerow = null; - fill_languagebanktablebody(languagebankdata); + reloadLanguageBank(APIURL); + alert("Success delete language : " + okdata.message); }, (errdata) => { - alert("Error delete language: " + errdata.message); + alert("Error delete language : " + errdata.message); }); } } @@ -1052,15 +1082,8 @@ $(document).ready(function () { language: cells.eq(2).text() } if (confirm(`Are you sure to edit language [${ll.index}] Tag=${ll.tag} Language=${ll.language}?`)) { - let $modal = $('#languagemodal'); - let $cbInd = $modal.find('#langId'); - let $cbLocal = $modal.find('#langLocal'); - let $cbEn = $modal.find('#langEn'); - let $cbArb = $modal.find('#langArb'); - let $cbJap = $modal.find('#langJap'); - let $cbChi = $modal.find('#langChi'); - let $langtag = $modal.find('#languagelinktag'); - let $langid = $modal.find('#languagelinkindex'); + + clearLanguageModal(); $langid.val(ll.index); $langtag.val(ll.tag); let langs = ll.language.toUpperCase().split(';'); @@ -1099,10 +1122,10 @@ $(document).ready(function () { ll.tag = tag; ll.language = langString; fetchAPI(APIURL + "UpdateByIndex/" + ll.index, "PATCH", {}, ll, (okdata) => { - alert("Success edit language" + okdata.message); reloadLanguageBank(APIURL); + alert("Success edit language : " + okdata.message); }, (errdata) => { - alert("Error edit language: " + errdata.message); + alert("Error edit language : " + errdata.message); }); $modal.modal('hide'); @@ -1117,19 +1140,20 @@ $(document).ready(function () { } }); $btnExport.click(() => { - DoExport(APIURL, "languagebank.xlsx",{}); + DoExport(APIURL, "languagebank.xlsx", {}); }); $btnImport.click(() => { DoImport(APIURL, (okdata) => { reloadLanguageBank(APIURL); + alert("Success import languagebank : " + okdata.message); }, (errdata) => { - alert("Error importing languagebank from XLSX: " + errdata.message); + alert("Error importing languagebank from XLSX : " + errdata.message); }); }); } else { - console.error("Error loading language content:", xhr.status, xhr.statusText); + console.error("Error loading language content : ", xhr.status, xhr.statusText); } }); }) @@ -1151,21 +1175,156 @@ $(document).ready(function () { $btnRemove.prop('disabled', true); let APIURL = "ScheduleBank/"; + let $schedulemodal = $('#schedulemodal'); + // text input + let $scheduleid = $schedulemodal.find('#scheduleid'); + // text input + let $scheduledescription = $schedulemodal.find('#scheduledescription'); + // number input 0-23 + let $schedulehour = $schedulemodal.find('#schedulehour'); + // number input 0-59 + let $scheduleminute = $schedulemodal.find('#scheduleminute'); + // text input + let $schedulesoundpath = $schedulemodal.find('#schedulesoundpath'); + // number input 0-5 + let $schedulerepeat = $schedulemodal.find('#schedulerepeat'); + // checkbox + let $scheduleenable = $schedulemodal.find('#scheduleenable'); + // div for list of checkboxes + let $schedulezones = $schedulemodal.find('#schedulezones'); + // radio button for everyday + let $scheduleeveryday = $schedulemodal.find('#scheduleeveryday'); + // radio button for weekdays + let $schedulesunday = $schedulemodal.find('#schedulesunday'); + let $schedulemonday = $schedulemodal.find('#schedulemonday'); + let $scheduletuesday = $schedulemodal.find('#scheduletuesday'); + let $schedulewednesday = $schedulemodal.find('#schedulewednesday'); + let $schedulethursday = $schedulemodal.find('#schedulethursday'); + let $schedulefriday = $schedulemodal.find('#schedulefriday'); + let $schedulesaturday = $schedulemodal.find('#schedulesaturday'); + // radio button for specific date + let $schedulespecialdate = $schedulemodal.find('#schedulespecialdate'); + // date input + let $scheduledate = $schedulemodal.find('#scheduledate'); + $schedulespecialdate.on('change', function () { + if ($(this).is(':checked')) { + $scheduledate.prop('disabled', false); + } else { + $scheduledate.prop('disabled', true); + } + }); + + function clearScheduleModal() { + $scheduleid.prop('disabled', true).val(''); + $scheduledescription.val(''); + $schedulehour.val('0'); + $scheduleminute.val('0'); + $schedulesoundpath.val(''); + $schedulerepeat.val('0'); + $scheduleenable.prop('checked', true); + $scheduleeveryday.prop('checked', false); + $schedulesunday.prop('checked', false); + $schedulemonday.prop('checked', false); + $scheduletuesday.prop('checked', false); + $schedulewednesday.prop('checked', false); + $schedulethursday.prop('checked', false); + $schedulefriday.prop('checked', false); + $schedulesaturday.prop('checked', false); + $schedulespecialdate.prop('checked', false); + $scheduledate.prop('disabled', true).val(''); + + + } + + let $findschedule = $('#findschedule'); + $findschedule.on('input', function () { + let searchTerm = $findschedule.val().toLowerCase(); + if (searchTerm.length > 0) { + selectedtimerow = null; + let filtered = schedulebankdata.filter(item => item.description.toLowerCase().includes(searchTerm) || item.soundpath.toLowerCase().includes(searchTerm) || item.broadcastZones.toLowerCase().includes(searchTerm)); + fill_schedulebanktablebody(filtered); + } else { + selectedtimerow = null; + fill_schedulebanktablebody(schedulebankdata); + } + }); + + reloadTimerBank(APIURL); $btnClear.click(() => { DoClear(APIURL, "Timerbank", (okdata) => { - alert("Success clear schedulebank" + okdata.message); - schedulebankdata = [] - selectedschedulerow = null; - fill_schedulebanktablebody(schedulebankdata); + reloadTimerBank(APIURL); + alert("Success clear schedulebank : " + okdata.message); }, (errdata) => { - alert("Error clear schedulebank: " + errdata.message); + alert("Error clear schedulebank : " + errdata.message); }); - + }); $btnAdd.click(() => { //TODO form add timer + $schedulemodal.modal('show'); + clearScheduleModal(); + + $schedulemodal.off('click.scheduleclose').on('click.scheduleclose', '#scheduleclose', function () { + $schedulemodal.modal('hide'); + }); + $schedulemodal.off('click.schedulesave').on('click.schedulesave', '#schedulesave', function () { + // Gather form values + const Description = $scheduledescription.val(); + const Soundpath = $schedulesoundpath.val(); + const Repeat = parseInt($schedulerepeat.val(), 10); + const Enable = $scheduleenable.is(':checked'); + // Collect selected days + let Day = ""; + if ($scheduleeveryday.is(':checked')) { + Day = "Everyday"; + } else if ($schedulespecialdate.is(':checked')) { + Day = $scheduledate.val(); + } else { + + if ($schedulesunday.is(':checked')) Day = "Sunday"; + if ($schedulemonday.is(':checked')) Day = "Monday"; + if ($scheduletuesday.is(':checked')) Day = "Tuesday"; + if ($schedulewednesday.is(':checked')) Day = "Wednesday"; + if ($schedulethursday.is(':checked')) Day = "Thursday"; + if ($schedulefriday.is(':checked')) Day = "Friday"; + if ($schedulesaturday.is(':checked')) Day = "Saturday"; + } + // Broadcast zones (assuming comma-separated string) + const BroadcastZones = $schedulezones.val(); + + // Validate required fields + if (!Description || !Soundpath || Day === "") { + alert("Description, sound path, and day are required."); + return; + } + + // Format time as HH:mm + const hour = parseInt($schedulehour.val(), 10); + const minute = parseInt($scheduleminute.val(), 10); + const Time = `${hour.toString().padStart(2, '0')}:${minute.toString().padStart(2, '0')}`; + + // Prepare object + const scheduleObj = { + Description, + Day, + Time, + Soundpath, + Repeat, + Enable, + BroadcastZones + }; + + fetchAPI(APIURL + "Add", "POST", {}, scheduleObj, (okdata) => { + alert("Success add schedule: " + okdata.message); + reloadTimerBank(APIURL); + }, (errdata) => { + alert("Error add schedule: " + errdata.message); + }); + + $schedulemodal.modal('hide'); + }); }); $btnRemove.click(() => { if (selectedtimerow) { @@ -1184,12 +1343,10 @@ $(document).ready(function () { } if (confirm(`Are you sure to delete schedule [${sr.index}] Description=${sr.description}?`)) { fetchAPI(APIURL + "DeleteByIndex/" + sr.index, "DELETE", {}, null, (okdata) => { - alert("Success delete schedule" + okdata.message); - schedulebankdata = schedulebankdata.filter(item => item.index !== sr.index); - selectedtimerow = null; - fill_schedulebanktablebody(schedulebankdata); + reloadTimerBank(APIURL); + alert("Success delete schedule : " + okdata.message); }, (errdata) => { - alert("Error delete schedule: " + errdata.message); + alert("Error delete schedule : " + errdata.message); }); } } @@ -1210,22 +1367,124 @@ $(document).ready(function () { language: cells.eq(8).text() } if (confirm(`Are you sure to edit schedule [${sr.index}] Description=${sr.description}?`)) { - //TODO send edit command + $schedulemodal.modal('show'); + // fill the form with existing data + $scheduleid.val(sr.index); + $scheduledescription.val(sr.description); + let [hour, minute] = sr.time.split(':').map(num => parseInt(num, 10)); + $schedulehour.val(hour.toString()); + $scheduleminute.val(minute.toString()); + $schedulesoundpath.val(sr.soundpath); + $schedulerepeat.val(sr.repeat.toString()); + $scheduleenable.prop('checked', sr.enable.toLowerCase() === 'true'); + switch (sr.day) { + case 'Everyday': + $scheduleeveryday.click(); + break; + case 'Sunday': + $schedulesunday.click(); + break; + case 'Monday': + $schedulemonday.click(); + break; + case 'Tuesday': + $scheduletuesday.click(); + break; + case 'Wednesday': + $schedulewednesday.click(); + break; + case 'Thursday': + $schedulethursday.click(); + break; + case 'Friday': + $schedulefriday.click(); + break; + case 'Saturday': + $schedulesaturday.click(); + break; + default: + // check if the day is in format dd/mm/yyyy + // and set the special date radio button and date input + if (/^\d{2}\/\d{2}\/\d{4}$/.test(sr.day)) { + $schedulespecialdate.click(); + $scheduledate.val(sr.day); + } + } + + $schedulemodal.off('click.scheduleclose').on('click.scheduleclose', '#scheduleclose', function () { + $schedulemodal.modal('hide'); + }); + $schedulemodal.off('click.schedulesave').on('click.schedulesave', '#schedulesave', function () { + // Gather form values + const Description = $scheduledescription.val(); + const Soundpath = $schedulesoundpath.val(); + const Repeat = parseInt($schedulerepeat.val(), 10); + const Enable = $scheduleenable.is(':checked'); + // Collect selected days + let Day = ""; + if ($scheduleeveryday.is(':checked')) { + Day = "Everyday"; + } else if ($schedulespecialdate.is(':checked')) { + Day = $scheduledate.val(); + } else { + if ($schedulesunday.is(':checked')) Day = "Sunday"; + if ($schedulemonday.is(':checked')) Day = "Monday"; + if ($scheduletuesday.is(':checked')) Day = "Tuesday"; + if ($schedulewednesday.is(':checked')) Day = "Wednesday"; + if ($schedulethursday.is(':checked')) Day = "Thursday"; + if ($schedulefriday.is(':checked')) Day = "Friday"; + if ($schedulesaturday.is(':checked')) Day = "Saturday"; + } + // Broadcast zones (assuming comma-separated string) + const BroadcastZones = $schedulezones.val(); + + // Validate required fields + if (!Description || !Soundpath || Day === "") { + alert("Description, sound path, and day are required."); + return; + } + + // Format time as HH:mm + const hour = parseInt($schedulehour.val(), 10); + const minute = parseInt($scheduleminute.val(), 10); + const Time = `${hour.toString().padStart(2, '0')}:${minute.toString().padStart(2, '0')}`; + + // Prepare object + const scheduleObj = { + Description, + Day, + Time, + Soundpath, + Repeat, + Enable, + BroadcastZones + }; + + fetchAPI(APIURL + "UpdateByIndex/" + sr.index, "PATCH", {}, scheduleObj, (okdata) => { + alert("Success edit schedule: " + okdata.message); + reloadTimerBank(APIURL); + }, (errdata) => { + alert("Error edit schedule: " + errdata.message); + }); + + $schedulemodal.modal('hide'); + }); } } }); $btnExport.click(() => { - DoExport(APIURL, "schedulebank.xlsx",{}); + DoExport(APIURL, "schedulebank.xlsx", {}); }); $btnImport.click(() => { DoImport(APIURL, (okdata) => { reloadTimerBank(APIURL); + alert("Success import schedulebank from XLSX : " + okdata.message); }, (errdata) => { - alert("Error importing schedulebank from XLSX: " + errdata.message); + alert("Error importing schedulebank from XLSX : " + errdata.message); }); }); } else { - console.error("Error loading timer content:", xhr.status, xhr.statusText); + console.error("Error loading timer content : ", xhr.status, xhr.statusText); } }); }) @@ -1267,7 +1526,7 @@ $(document).ready(function () { reloadLogs(APIURL, selectedlogdate, logfilter); }); $btnExport.off('click').on('click', function () { - DoExport(APIURL, "log.xlsx",{date:selectedlogdate,filter:logfilter}); + DoExport(APIURL, "log.xlsx", { date: selectedlogdate, filter: logfilter }); }); } else { diff --git a/html/webpage/language.html b/html/webpage/language.html index 682cac1..90372f3 100644 --- a/html/webpage/language.html +++ b/html/webpage/language.html @@ -16,6 +16,13 @@

Language Link

+
+
+ +
+
diff --git a/html/webpage/messagebank.html b/html/webpage/messagebank.html index c48fd9c..3b952ff 100644 --- a/html/webpage/messagebank.html +++ b/html/webpage/messagebank.html @@ -16,6 +16,13 @@

Message Bank

+
+
+ +
+
diff --git a/html/webpage/timer.html b/html/webpage/timer.html index f86cd3b..93e52da 100644 --- a/html/webpage/timer.html +++ b/html/webpage/timer.html @@ -16,6 +16,13 @@

Schedule Bank

+
+
+ +
+
@@ -59,58 +66,110 @@

Index

-
+

Description

-
+

Day

-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+

Time

-
+
+
+
+
+

(H)

+
+
+
+

(M)

+
+
+

Sound Path

-
+

Repeat

-
+

Enable

-
+

Broadcast Zones

-
-
    -
  • List Group Item 1
  • -
  • List Group Item 2
  • -
  • List Group Item 3
  • -
-
+
- + diff --git a/src/content/Language.kt b/src/content/Language.kt index 0274b87..c7ea77f 100644 --- a/src/content/Language.kt +++ b/src/content/Language.kt @@ -12,5 +12,5 @@ enum class Language(name: String) { Local("LOCAL"), Japanese("JAPANESE"), Chinese("CHINESE"), - Arabic("ARABIC"),; + Arabic("ARABIC"); } \ No newline at end of file diff --git a/src/database/MariaDB.kt b/src/database/MariaDB.kt index 2ff842f..3e8e355 100644 --- a/src/database/MariaDB.kt +++ b/src/database/MariaDB.kt @@ -222,15 +222,15 @@ class MariaDB( */ fun GetLogForHtml(date: String, consumer: Consumer>) { val logList = ArrayList() - println("GetLogForHtml Date: $date" ) + //println("GetLogForHtml Date: $date" ) if (ValiDateForLogHtml(date)) { try { // must convert from DD-MM-YYYY to DD/MM/YYYY, because in database we use DD/MM/YYYY val adjusteddate = date.replace("-", "/") val statement = connection?.prepareStatement("SELECT * FROM logs WHERE datenya = ?") statement?.setString(1, adjusteddate) - println("GetLogForHtml Date: $adjusteddate" ) - println("GetLogForHtml SQL: " +statement?.toString()) + //println("GetLogForHtml Date: $adjusteddate" ) + // println("GetLogForHtml SQL: " +statement?.toString()) val resultSet = statement?.executeQuery() while (resultSet?.next() == true) { val log = Log( @@ -258,7 +258,7 @@ class MariaDB( */ fun GetLogForHtml(date: String, filter: String, consumer: Consumer>) { val logList = ArrayList() - println("GetLogForHtml Date: $date Filter: $filter" ) + //println("GetLogForHtml Date: $date Filter: $filter" ) if (ValiDateForLogHtml(date)) { try { @@ -268,8 +268,8 @@ class MariaDB( connection?.prepareStatement("SELECT * FROM logs WHERE datenya = ? AND description LIKE ?") statement?.setString(1, adjusteddate) statement?.setString(2, "%$filter%") - println("GetLogForHtml Date: $adjusteddate , Filter=$filter" ) - println("GetLogForHtml SQL: " +statement?.toString()) + //println("GetLogForHtml Date: $adjusteddate , Filter=$filter" ) + //println("GetLogForHtml SQL: " +statement?.toString()) val resultSet = statement?.executeQuery() while (resultSet?.next() == true) { val log = Log( @@ -457,6 +457,29 @@ class MariaDB( return false } + /** + * Resort the schedulebank table, in order to reorder the index after deletions, and sort ascending by Day and Time. + * @return True if the resorting was successful, false otherwise. + */ + fun Resort_Schedulebank_by_Day_Time(): Boolean { + try { + val statement = connection?.createStatement() + // use a temporary table to reorder the index + statement?.executeUpdate("CREATE TABLE IF NOT EXISTS temp_schedulebank LIKE schedulebank") + statement?.executeUpdate("INSERT INTO temp_schedulebank (Description, Day, Time, Soundpath, Repeat, Enable, BroadcastZones, Language) SELECT Description, Day, Time, Soundpath, Repeat, Enable, BroadcastZones, Language FROM schedulebank ORDER BY Day ASC, Time ASC") + statement?.executeUpdate("TRUNCATE TABLE schedulebank") + statement?.executeUpdate("INSERT INTO schedulebank (Description, Day, Time, Soundpath, Repeat, Enable, BroadcastZones, Language) SELECT Description, Day, Time, Soundpath, Repeat, Enable, BroadcastZones, Language FROM temp_schedulebank") + statement?.executeUpdate("DROP TABLE temp_schedulebank") + Logger.info("schedulebank table resorted by Day and Time" as Any) + // reload the local list + Reload_Schedulebank() + return true + } catch (e: Exception) { + Logger.error("Error resorting schedulebank table by Day and Time: ${e.message}" as Any) + } + return false + } + /** * Clears all entries from the schedulebank table in the database and the local list. */ @@ -695,6 +718,29 @@ class MariaDB( return false } + /** + * Resort the language link table, in order to reorder the index after deletions, and sort ascending by TAG. + * @return True if the resorting was successful, false otherwise. + */ + fun Resort_LanguageLink_by_TAG() : Boolean { + try { + val statement = connection?.createStatement() + // use a temporary table to reorder the index + statement?.executeUpdate("CREATE TABLE IF NOT EXISTS temp_languagelinking LIKE languagelinking") + statement?.executeUpdate("INSERT INTO temp_languagelinking (TAG, Language) SELECT TAG, Language FROM languagelinking ORDER BY TAG ASC") + statement?.executeUpdate("TRUNCATE TABLE languagelinking") + statement?.executeUpdate("INSERT INTO languagelinking (TAG, Language) SELECT TAG, Language FROM temp_languagelinking") + statement?.executeUpdate("DROP TABLE temp_languagelinking") + Logger.info("languagelinking table resorted by TAG" as Any) + // reload the local list + Reload_LanguageLink() + return true + } catch (e: Exception) { + Logger.error("Error resorting languagelinking table by TAG: ${e.message}" as Any) + } + return false + } + /** * Clears all entries from the language link table in the database and the local list. */ @@ -945,6 +991,29 @@ class MariaDB( return false } + /** + * Resort the soundbank table, in order to reorder the index after deletions, and sort ascending by Description. + * @return True if the resorting was successful, false otherwise. + */ + fun Resort_Soundbank_by_Description(): Boolean { + try { + val statement = connection?.createStatement() + // use a temporary table to reorder the index + statement?.executeUpdate("CREATE TABLE IF NOT EXISTS temp_soundbank LIKE soundbank") + statement?.executeUpdate("INSERT INTO temp_soundbank (Description, TAG, Category, Language, VoiceType, Path) SELECT Description, TAG, Category, Language, VoiceType, Path FROM soundbank ORDER BY Description ASC") + statement?.executeUpdate("TRUNCATE TABLE soundbank") + statement?.executeUpdate("INSERT INTO soundbank (Description, TAG, Category, Language, VoiceType, Path) SELECT Description, TAG, Category, Language, VoiceType, Path FROM temp_soundbank") + statement?.executeUpdate("DROP TABLE temp_soundbank") + Logger.info("soundbank table resorted by Description" as Any) + // reload the local list + Reload_Soundbank() + return true + } catch (e: Exception) { + Logger.error("Error resorting soundbank table by Description: ${e.message}" as Any) + } + return false + } + /** * Clears all entries from the soundbank table in the database and the local list. */ @@ -1173,6 +1242,29 @@ class MariaDB( return false } + /** + * Resort the messagebank table, in order to reorder the index after deletions, and sort ascending by ANN_ID. + * @return True if the resorting was successful, false otherwise. + */ + fun Resort_Messagebank_by_ANN_ID(): Boolean { + try { + val statement = connection?.createStatement() + // use a temporary table to reorder the index + statement?.executeUpdate("CREATE TABLE IF NOT EXISTS temp_messagebank LIKE messagebank") + statement?.executeUpdate("INSERT INTO temp_messagebank (Description, Language, ANN_ID, Voice_Type, Message_Detail, Message_TAGS) SELECT Description, Language, ANN_ID, Voice_Type, Message_Detail, Message_TAGS FROM messagebank ORDER BY ANN_ID ASC") + statement?.executeUpdate("TRUNCATE TABLE messagebank") + statement?.executeUpdate("INSERT INTO messagebank (Description, Language, ANN_ID, Voice_Type, Message_Detail, Message_TAGS) SELECT Description, Language, ANN_ID, Voice_Type, Message_Detail, Message_TAGS FROM temp_messagebank") + statement?.executeUpdate("DROP TABLE temp_messagebank") + Logger.info("messagebank table resorted by Description" as Any) + // reload the local list + Reload_Messagebank() + return true + } catch (e: Exception) { + Logger.error("Error resorting messagebank table by Description: ${e.message}" as Any) + } + return false + } + /** * Exports the messagebank table to an XLSX workbook. * @return An XSSFWorkbook containing the messagebank data. @@ -1527,6 +1619,29 @@ class MariaDB( return false } + /** + * Resort the broadcast_zones table, in order to reorder the index after deletions, and sort ascending by description. + * @return True if the resorting was successful, false otherwise. + */ + fun Resort_BroadcastZones_by_description(): Boolean { + try { + val statement = connection?.createStatement() + // use a temporary table to reorder the index + statement?.executeUpdate("CREATE TABLE IF NOT EXISTS temp_broadcast_zones LIKE broadcast_zones") + statement?.executeUpdate("INSERT INTO temp_broadcast_zones (description, SoundChannel, Box, Relay) SELECT description, SoundChannel, Box, Relay FROM broadcast_zones ORDER BY description ASC") + statement?.executeUpdate("TRUNCATE TABLE broadcast_zones") + statement?.executeUpdate("INSERT INTO broadcast_zones (description, SoundChannel, Box, Relay) SELECT description, SoundChannel, Box, Relay FROM temp_broadcast_zones") + statement?.executeUpdate("DROP TABLE temp_broadcast_zones") + Logger.info("broadcast_zones table resorted by description" as Any) + // reload the local list + GetBroadcastZones() + return true + } catch (e: Exception) { + Logger.error("Error resorting broadcast_zones table by description: ${e.message}" as Any) + } + return false + } + /** * Clears all entries from the broadcast_zones in the database. */ diff --git a/src/web/WebApp.kt b/src/web/WebApp.kt index 562202e..48e9b7f 100644 --- a/src/web/WebApp.kt +++ b/src/web/WebApp.kt @@ -3,7 +3,6 @@ package web import codes.Somecodes import codes.Somecodes.Companion.ListAudioFiles import codes.Somecodes.Companion.ValiDateForLogHtml -import codes.Somecodes.Companion.ValidDate import codes.Somecodes.Companion.ValidFile import codes.Somecodes.Companion.ValidScheduleDay import codes.Somecodes.Companion.ValidScheduleTime @@ -66,13 +65,13 @@ class WebApp(val listenPort: Int, val userlist: List>, val val username = it.formParam("username") val password = it.formParam("password") if (username == null || password == null) { - it.status(400).result("Username and password are required") + 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("Invalid username or password") + it.status(401).result(objectmapper.writeValueAsString(resultMessage("Invalid username or password"))) return@post } // Set user session @@ -208,40 +207,43 @@ class WebApp(val listenPort: Int, val userlist: List>, val if (!exists) { if (ValidFile(addvalue.Path)) { if (db.Add_Soundbank(addvalue)) { - it.result(objectmapper.writeValueAsString(mapOf("message" to "OK"))) + db.Resort_Soundbank_by_Description() + it.result(objectmapper.writeValueAsString(resultMessage("OK"))) } else it.status(500) - .result("Failed to add soundbank to database") + .result(objectmapper.writeValueAsString(resultMessage("Failed to add soundbank to database"))) } else it.status(400) - .result("Invalid Path, file does not exist") + .result(objectmapper.writeValueAsString(resultMessage("Invalid Path, file does not exist"))) } else it.status(400) - .result("TAG=${addvalue.TAG} already exists for the same Language=${addvalue.Language} and Category=${addvalue.Category}") - } else it.status(400).result("Invalid Path") - } else it.status(400).result(objectmapper.writeValueAsString(mapOf("message" to "Invalid Language"))) - } else it.status(400).result(objectmapper.writeValueAsString(mapOf("message" to "Invalid Category"))) - } else it.status(400).result(objectmapper.writeValueAsString(mapOf("message" to "Invalid TAG"))) - } else it.status(400).result(objectmapper.writeValueAsString(mapOf("message" to "Invalid Description"))) + .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("Invalid Path"))) + } else it.status(400).result(objectmapper.writeValueAsString(resultMessage("Invalid Language"))) + } else it.status(400).result(objectmapper.writeValueAsString(resultMessage("Invalid Category"))) + } else it.status(400).result(objectmapper.writeValueAsString(resultMessage("Invalid TAG"))) + } else it.status(400).result(objectmapper.writeValueAsString(resultMessage("Invalid Description"))) } catch (_: Exception) { - it.status(400).result("Invalid request body") + it.status(400).result(objectmapper.writeValueAsString(resultMessage("Invalid request body"))) } } delete("List") { // truncate soundbank table if (db.Clear_Soundbank()) { - it.result(objectmapper.writeValueAsString(mapOf("message" to "OK"))) + db.Reload_Soundbank() + it.result(objectmapper.writeValueAsString(resultMessage("OK"))) } else { - it.status(500).result("Failed to truncate soundbank table") + 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(mapOf("message" to "Invalid index"))) + it.status(400).result(objectmapper.writeValueAsString(resultMessage("Invalid index"))) } else { if (db.Delete_Soundbank_by_index(index)) { - it.result(objectmapper.writeValueAsString(mapOf("message" to "OK"))) + db.Resort_Soundbank_by_Description() + it.result(objectmapper.writeValueAsString(resultMessage("OK"))) } else { - it.status(500).result("Failed to delete soundbank with index $index") + it.status(500).result(objectmapper.writeValueAsString(resultMessage("Failed to delete soundbank with index $index"))) } } } @@ -250,17 +252,17 @@ class WebApp(val listenPort: Int, val userlist: List>, val val index = it.pathParam("index").toUIntOrNull() if (index == null) { // tidak ada path param index - it.status(400).result(objectmapper.writeValueAsString(mapOf("message" to "Invalid index"))) + it.status(400).result(objectmapper.writeValueAsString(resultMessage("Invalid index"))) } else { val sb = db.SoundbankList.find { xx -> xx.index == index } if (sb == null) { // soundbank dengan index tersebut tidak ditemukan - it.status(404).result("Soundbank with index $index not found") + it.status(404).result(objectmapper.writeValueAsString(resultMessage("Soundbank with index $index not found"))) } else { // soundbank dengan index tersebut ditemukan, sekarang update val json: JsonNode = objectmapper.readTree(it.body()) if (json.isEmpty) { - it.status(400).result(objectmapper.writeValueAsString(mapOf("message" to "UpdateByIndex with index=$index has empty body"))) + it.status(400).result(objectmapper.writeValueAsString(resultMessage("UpdateByIndex with index=$index has empty body"))) } else { val _description = json.get("Description").asText() val _tag = json.get("TAG").asText() @@ -283,7 +285,7 @@ class WebApp(val listenPort: Int, val userlist: List>, val sb.Category = _category changed = true } else { - it.status(400).result(objectmapper.writeValueAsString(mapOf("message" to "Invalid Category"))) + it.status(400).result(objectmapper.writeValueAsString(resultMessage("Invalid Category"))) return@patch } } @@ -296,16 +298,17 @@ class WebApp(val listenPort: Int, val userlist: List>, val sb.Path = _path changed = true } else { - it.status(400).result("Invalid Path, file does not exist") + it.status(400).result(objectmapper.writeValueAsString(resultMessage("Invalid Path, file does not exist"))) return@patch } } if (changed) { if (db.Update_Soundbank_by_index(index, sb)) { - it.result(objectmapper.writeValueAsString(mapOf("message" to "OK"))) - } else it.status(500).result("Failed to update soundbank with index $index") + db.Resort_Soundbank_by_Description() + 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("Nothing has changed for soundbank with index $index") + .result(objectmapper.writeValueAsString(resultMessage("Nothing has changed for soundbank with index $index"))) } } } @@ -322,24 +325,25 @@ class WebApp(val listenPort: Int, val userlist: List>, val xlsxdata.write(out) } } else { - it.status(500).result("Failed to export soundbank to XLSX") + 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(mapOf("message" to "No file uploaded"))) + it.status(400).result(objectmapper.writeValueAsString(resultMessage("No file uploaded"))) return@post } try { val xlsx = XSSFWorkbook(uploaded.content()) if (db.Import_Soundbank_XLSX(xlsx)) { - it.result(objectmapper.writeValueAsString(mapOf("message" to "OK"))) + db.Resort_Soundbank_by_Description() + it.result(objectmapper.writeValueAsString(resultMessage("OK"))) } else { - it.status(500).result("Failed to import soundbank from XLSX") + it.status(500).result(objectmapper.writeValueAsString(resultMessage("Failed to import soundbank from XLSX"))) } } catch (e: Exception) { - it.status(400).result(objectmapper.writeValueAsString(mapOf("message" to "Invalid XLSX file"))) + it.status(400).result(objectmapper.writeValueAsString(resultMessage("Invalid XLSX file"))) } } } @@ -354,21 +358,23 @@ class WebApp(val listenPort: Int, val userlist: List>, val delete("List") { // truncate messagebank table if (db.Clear_Messagebank()) { - it.result(objectmapper.writeValueAsString(mapOf("message" to "OK"))) + db.Reload_Messagebank() + it.result(objectmapper.writeValueAsString(resultMessage("OK"))) } else { - it.status(500).result(objectmapper.writeValueAsString(mapOf("message" to "Failed to truncate messagebank table"))) + 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(mapOf("message" to "Invalid index"))) + it.status(400).result(objectmapper.writeValueAsString(resultMessage("Invalid index"))) } else { if (db.Delete_Messagebank_by_index(index)) { - it.result(objectmapper.writeValueAsString(mapOf("message" to "OK"))) + db.Resort_Messagebank_by_ANN_ID() + it.result(objectmapper.writeValueAsString(resultMessage("OK"))) } else { - it.status(500).result(objectmapper.writeValueAsString(mapOf("message" to "Failed to delete messagebank with index $index"))) + it.status(500).result(objectmapper.writeValueAsString(resultMessage("Failed to delete messagebank with index $index"))) } } } @@ -376,15 +382,15 @@ class WebApp(val listenPort: Int, val userlist: List>, val // update messagebank by index val index = it.pathParam("index").toUIntOrNull() if (index == null) { - it.status(400).result(objectmapper.writeValueAsString(mapOf("message" to "Invalid index"))) + it.status(400).result(objectmapper.writeValueAsString(resultMessage("Invalid index"))) } else { val mb = db.MessagebankList.find { xx -> xx.index == index } if (mb == null) { - it.status(404).result(objectmapper.writeValueAsString(mapOf("message" to "Messagebank with index $index not found"))) + 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(mapOf("message" to "UpdateByIndex with index=$index has empty body"))) + 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() @@ -411,7 +417,7 @@ class WebApp(val listenPort: Int, val userlist: List>, val mb.Voice_Type = _voice_type changed = true } else { - it.status(400).result(objectmapper.writeValueAsString(mapOf("message" to "Invalid Voice_Type"))) + it.status(400).result(objectmapper.writeValueAsString(resultMessage("Invalid Voice_Type"))) return@patch } } @@ -425,11 +431,12 @@ class WebApp(val listenPort: Int, val userlist: List>, val } if (changed) { if (db.Update_Messagebank_by_index(index, mb)) { - it.result(objectmapper.writeValueAsString(mapOf("message" to "OK"))) + db.Resort_Messagebank_by_ANN_ID() + it.result(objectmapper.writeValueAsString(resultMessage("OK"))) } else it.status(500) - .result(objectmapper.writeValueAsString(mapOf("message" to "Failed to update messagebank with index $index"))) + .result(objectmapper.writeValueAsString(resultMessage("Failed to update messagebank with index $index"))) } else it.status(400) - .result(objectmapper.writeValueAsString(mapOf("message" to "Nothing has changed for messagebank with index $index"))) + .result(objectmapper.writeValueAsString(resultMessage("Nothing has changed for messagebank with index $index"))) } } } @@ -446,24 +453,25 @@ class WebApp(val listenPort: Int, val userlist: List>, val xlsxdata.write(out) } } else { - it.status(500).result(objectmapper.writeValueAsString(mapOf("message" to "Failed to export messagebank to XLSX"))) + 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(mapOf("message" to "No file uploaded"))) + it.status(400).result(objectmapper.writeValueAsString(resultMessage("No file uploaded"))) return@post } try { val xlsx = XSSFWorkbook(uploaded.content()) if (db.Import_Messagebank_XLSX(xlsx)) { - it.result(objectmapper.writeValueAsString(mapOf("message" to "OK"))) + db.Resort_Messagebank_by_ANN_ID() + it.result(objectmapper.writeValueAsString(resultMessage("OK"))) } else { - it.status(500).result(objectmapper.writeValueAsString(mapOf("message" to "Failed to import messagebank from XLSX"))) + it.status(500).result(objectmapper.writeValueAsString(resultMessage("Failed to import messagebank from XLSX"))) } } catch (e: Exception) { - it.status(400).result(objectmapper.writeValueAsString(mapOf("message" to "Invalid XLSX file"))) + it.status(400).result(objectmapper.writeValueAsString(resultMessage("Invalid XLSX file"))) } } } @@ -477,35 +485,51 @@ class WebApp(val listenPort: Int, val userlist: List>, val val json: JsonNode = objectmapper.readTree(it.body()) val tag = json.get("tag").asText() val languages = json.get("language").asText().split(";") + println("Add Language Link, tag=$tag, languages=$languages") if (ValidString(tag)){ - if (languages.all { xx -> Language.entries.any { yy -> yy.name== xx} }){ - if (db.LanguageLinkList.any { ll -> ll.TAG==tag }){ + if (languages.all { xx -> Language.entries.any { yy -> yy.name.equals(xx,true)} }){ + if (!db.LanguageLinkList.any { ll -> ll.TAG.equals(tag,true) }) { val newvalue = LanguageLink(0u, tag, languages.joinToString(";")) if (db.Add_LanguageLink(newvalue)){ - it.result(objectmapper.writeValueAsString(mapOf("message" to "OK"))) - } else it.status(500).result(objectmapper.writeValueAsString(mapOf("message" to "Failed to add language link to database"))) - } else it.status(400).result(objectmapper.writeValueAsString(mapOf("message" to "TAG=$tag already exists"))) - } else it.status(400).result(objectmapper.writeValueAsString(mapOf("message" to "Contains unsupported language"))) - } else it.status(400).result(objectmapper.writeValueAsString(mapOf("message" to "Invalid tag or language"))) + db.Resort_LanguageLink_by_TAG() + it.result(objectmapper.writeValueAsString(resultMessage("OK"))) + } else { + it.status(500).result(objectmapper.writeValueAsString(resultMessage("Failed to add language link to database"))) + println("Failed to add language link to database") + } + } else { + it.status(400).result(objectmapper.writeValueAsString(resultMessage("TAG=$tag already exists"))) + println("TAG=$tag already exists") + } + } else { + it.status(400).result(objectmapper.writeValueAsString(resultMessage("Contains unsupported language"))) + println("Contains unsupported language") + } + } else { + it.status(400).result(objectmapper.writeValueAsString(resultMessage("Invalid tag or language"))) + println("Invalid tag") + } } delete("List") { // truncate language link table if (db.Clear_LanguageLink()) { - it.result(objectmapper.writeValueAsString(mapOf("message" to "OK"))) + db.Reload_LanguageLink() + it.result(objectmapper.writeValueAsString(resultMessage("OK"))) } else { - it.status(500).result(objectmapper.writeValueAsString(mapOf("message" to "Failed to truncate language link table"))) + 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(mapOf("message" to "Invalid index"))) + it.status(400).result(objectmapper.writeValueAsString(resultMessage("Invalid index"))) } else { if (db.Delete_LanguageLink_by_index(index)) { - it.result(objectmapper.writeValueAsString(mapOf("message" to "OK"))) + db.Resort_LanguageLink_by_TAG() + it.result(objectmapper.writeValueAsString(resultMessage("OK"))) } else { - it.status(500).result(objectmapper.writeValueAsString(mapOf("message" to "Failed to delete language link with index $index"))) + it.status(500).result(objectmapper.writeValueAsString(resultMessage("Failed to delete language link with index $index"))) } } } @@ -513,15 +537,15 @@ class WebApp(val listenPort: Int, val userlist: List>, val // update by index val index = it.pathParam("index").toUIntOrNull() if (index == null) { - it.status(400).result(objectmapper.writeValueAsString(mapOf("message" to "Invalid index"))) + it.status(400).result(objectmapper.writeValueAsString(resultMessage("Invalid index"))) } else { val ll = db.LanguageLinkList.find { xx -> xx.index == index } if (ll == null) { - it.status(404).result(objectmapper.writeValueAsString(mapOf("message" to "Language link with index $index not found"))) + 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(mapOf("message" to "UpdateByIndex with index=$index has empty body"))) + 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() @@ -536,11 +560,12 @@ class WebApp(val listenPort: Int, val userlist: List>, val } if (changed) { if (db.Update_LanguageLink_by_index(index, ll)) { - it.result(objectmapper.writeValueAsString(mapOf("message" to "OK"))) + db.Resort_LanguageLink_by_TAG() + it.result(objectmapper.writeValueAsString(resultMessage("OK"))) } else it.status(500) - .result(objectmapper.writeValueAsString(mapOf("message" to "Failed to update language link with index $index"))) + .result(objectmapper.writeValueAsString(resultMessage("Failed to update language link with index $index"))) } else it.status(400) - .result(objectmapper.writeValueAsString(mapOf("message" to "Nothing has changed for language link with index $index"))) + .result(objectmapper.writeValueAsString(resultMessage("Nothing has changed for language link with index $index"))) } } } @@ -557,24 +582,25 @@ class WebApp(val listenPort: Int, val userlist: List>, val xlsxdata.write(out) } } else { - it.status(500).result(objectmapper.writeValueAsString(mapOf("message" to "Failed to export language link to XLSX"))) + 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(mapOf("message" to "No file uploaded"))) + it.status(400).result(objectmapper.writeValueAsString(resultMessage("No file uploaded"))) return@post } try { val xlsx = XSSFWorkbook(uploaded.content()) if (db.Import_LanguageLink_XLSX(xlsx)) { - it.result(objectmapper.writeValueAsString(mapOf("message" to "OK"))) + db.Resort_LanguageLink_by_TAG() + it.result(objectmapper.writeValueAsString(resultMessage("OK"))) } else { - it.status(500).result(objectmapper.writeValueAsString(mapOf("message" to "Failed to import language link from XLSX"))) + it.status(500).result(objectmapper.writeValueAsString(resultMessage("Failed to import language link from XLSX"))) } } catch (e: Exception) { - it.status(400).result(objectmapper.writeValueAsString(mapOf("message" to "Invalid XLSX file"))) + it.status(400).result(objectmapper.writeValueAsString(resultMessage("Invalid XLSX file"))) } } } @@ -586,21 +612,23 @@ class WebApp(val listenPort: Int, val userlist: List>, val delete("List") { // truncate timer table if (db.Clear_Schedulebank()) { - it.result(objectmapper.writeValueAsString(mapOf("message" to "OK"))) + db.Reload_Schedulebank() + it.result(objectmapper.writeValueAsString(resultMessage("OK"))) } else { - it.status(500).result(objectmapper.writeValueAsString(mapOf("message" to "Failed to truncate schedulebank table"))) + it.status(500).result(objectmapper.writeValueAsString(resultMessage("Failed to truncate schedulebank table"))) } } delete("DeleteByIndex/{index}") { // delete by index val index = it.pathParam("index").toUIntOrNull() if (index == null) { - it.status(400).result(objectmapper.writeValueAsString(mapOf("message" to "Invalid index"))) + it.status(400).result(objectmapper.writeValueAsString(resultMessage("Invalid index"))) } else { if (db.Delete_Schedulebank_by_index(index)) { - it.result(objectmapper.writeValueAsString(mapOf("message" to "OK"))) + db.Resort_Schedulebank_by_Day_Time() + it.result(objectmapper.writeValueAsString(resultMessage("OK"))) } else { - it.status(500).result("Failed to delete schedule with index $index") + it.status(500).result(objectmapper.writeValueAsString(resultMessage("Failed to delete schedule with index $index"))) } } } @@ -608,15 +636,15 @@ class WebApp(val listenPort: Int, val userlist: List>, val // update by index val index = it.pathParam("index").toUIntOrNull() if (index == null) { - it.status(400).result(objectmapper.writeValueAsString(mapOf("message" to "Invalid index"))) + it.status(400).result(objectmapper.writeValueAsString(resultMessage("Invalid index"))) } else { val sb = db.SchedulebankList.find { xx -> xx.index == index } if (sb == null) { - it.status(404).result("Schedule with index $index not found") + it.status(404).result(objectmapper.writeValueAsString(resultMessage("Schedule with index $index not found"))) } else { val json: JsonNode = objectmapper.readTree(it.body()) if (json.isEmpty) { - it.status(400).result(objectmapper.writeValueAsString(mapOf("message" to "UpdateByIndex with index=$index has empty body"))) + it.status(400).result(objectmapper.writeValueAsString(resultMessage("UpdateByIndex with index=$index has empty body"))) } else { val _description = json.get("Description").asText() val _time = json.get("Time").asText() @@ -636,7 +664,7 @@ class WebApp(val listenPort: Int, val userlist: List>, val sb.Time = _time changed = true } else { - it.status(400).result("Invalid Time format, must be HH:mm") + it.status(400).result(objectmapper.writeValueAsString(resultMessage("Invalid Time format, must be HH:mm"))) return@patch } } @@ -645,7 +673,7 @@ class WebApp(val listenPort: Int, val userlist: List>, val sb.Day = _day changed = true } else { - it.status(400).result("Invalid Day format") + it.status(400).result(objectmapper.writeValueAsString(resultMessage("Invalid Day format"))) return@patch } } @@ -670,17 +698,18 @@ class WebApp(val listenPort: Int, val userlist: List>, val sb.Language = _language changed = true } else { - it.status(400).result(objectmapper.writeValueAsString(mapOf("message" to "Invalid Language"))) + it.status(400).result(objectmapper.writeValueAsString(resultMessage("Invalid Language"))) return@patch } } if (changed) { if (db.Update_Schedulebank_by_index(index, sb)) { - it.result(objectmapper.writeValueAsString(mapOf("message" to "OK"))) + db.Resort_Schedulebank_by_Day_Time() + it.result(objectmapper.writeValueAsString(resultMessage("OK"))) } else it.status(500) - .result(objectmapper.writeValueAsString(mapOf("message" to "Failed to update schedule with index $index"))) + .result(objectmapper.writeValueAsString(resultMessage("Failed to update schedule with index $index"))) } else it.status(400) - .result(objectmapper.writeValueAsString(mapOf("message" to "Nothing has changed for schedule with index $index"))) + .result(objectmapper.writeValueAsString(resultMessage("Nothing has changed for schedule with index $index"))) } } } @@ -697,24 +726,25 @@ class WebApp(val listenPort: Int, val userlist: List>, val xlsxdata.write(out) } } else { - it.status(500).result(objectmapper.writeValueAsString(mapOf("message" to "Failed to export schedulebank to XLSX"))) + 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(mapOf("message" to "No file uploaded"))) + it.status(400).result(objectmapper.writeValueAsString(resultMessage("No file uploaded"))) return@post } try { val xlsx = XSSFWorkbook(uploaded.content()) if (db.Import_Schedulebank_XLSX(xlsx)) { - it.result(objectmapper.writeValueAsString(mapOf("message" to "OK"))) + db.Resort_Schedulebank_by_Day_Time() + it.result(objectmapper.writeValueAsString(resultMessage("OK"))) } else { - it.status(500).result("Failed to import schedulebank from XLSX") + it.status(500).result(objectmapper.writeValueAsString(resultMessage("Failed to import schedulebank from XLSX"))) } } catch (e: Exception) { - it.status(400).result(objectmapper.writeValueAsString(mapOf("message" to "Invalid XLSX file"))) + it.status(400).result(objectmapper.writeValueAsString(resultMessage("Invalid XLSX file"))) } } } @@ -735,7 +765,7 @@ class WebApp(val listenPort: Int, val userlist: List>, val } } else { println("Invalid logdate=$logdate") - get1.status(400).result("Invalid logdate") + get1.status(400).result(objectmapper.writeValueAsString(resultMessage("Invalid logdate"))) } } get("ExportXLSX") { get1 -> @@ -758,11 +788,86 @@ class WebApp(val listenPort: Int, val userlist: List>, val xlsxdata.write(out) } } else { - get1.status(500).result("Failed to export log to XLSX") + get1.status(500).result(objectmapper.writeValueAsString(resultMessage("Failed to export log to XLSX"))) } - } else get1.status(400).result("Invalid logdate") + } else get1.status(400).result(objectmapper.writeValueAsString(resultMessage("Invalid logdate"))) } } + path("BroadcastZones"){ + get("List") { + // get broadcast zones list + it.result(MariaDB.ArrayListtoString(db.BroadcastZoneList)) + } + delete("List"){ + // truncate broadcast zones table + if (db.Clear_BroadcastZones()) { + db.GetBroadcastZones() + it.result(objectmapper.writeValueAsString(resultMessage("OK"))) + } else { + it.status(500).result(objectmapper.writeValueAsString(resultMessage("Failed to truncate broadcast zones table"))) + } + } + post("Add") { + // Parse JSON from request body + val json: JsonNode = objectmapper.readTree(it.body()) + val zone = json.get("zone").asText() + val description = json.get("description").asText() + println("Add Broadcast Zone, zone=$zone, description=$description") + // TODO continue tomorrow + } + 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.Delete_BroadcastZones_by_index(index)) { + db.Resort_BroadcastZones_by_description() + it.result(objectmapper.writeValueAsString(resultMessage("OK"))) + } else { + it.status(500).result(objectmapper.writeValueAsString(resultMessage("Failed to delete broadcast zone with index $index"))) + } + } + } + post("UpdateByIndex/{index}") { + // TODO continue tomorrow + + } + get("ExportXLSX") { + val xlsxdata = db.Export_BroadcastZones_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.Import_BroadcastZones_XLSX(xlsx)) { + db.Resort_BroadcastZones_by_description() + 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"))) + } + } + + } } } }.start(listenPort) diff --git a/src/web/resultMessage.kt b/src/web/resultMessage.kt new file mode 100644 index 0000000..8543017 --- /dev/null +++ b/src/web/resultMessage.kt @@ -0,0 +1,4 @@ +package web + +@Suppress("unused") +data class resultMessage(val message: String)