commit 09/02/2026

This commit is contained in:
2026-02-10 17:05:39 +07:00
parent e18976ace3
commit 546f2e27af
24 changed files with 1205 additions and 384 deletions

View File

@@ -0,0 +1,431 @@
/* !
*
* ../css/litepicker.css
* Litepicker v2.0.12 (https://github.com/wakirin/Litepicker)
* Package: litepicker (https://www.npmjs.com/package/litepicker)
* License: MIT (https://github.com/wakirin/Litepicker/blob/master/LICENCE.md)
* Copyright 2019-2021 Rinat G.
*
* Hash: 2f11f1f0300ea13b17b5
* */
:root {
--litepicker-container-months-color-bg: #fff;
--litepicker-container-months-box-shadow-color: #ddd;
--litepicker-footer-color-bg: #fafafa;
--litepicker-footer-box-shadow-color: #ddd;
--litepicker-tooltip-color-bg: #fff;
--litepicker-month-header-color: #333;
--litepicker-button-prev-month-color: #9e9e9e;
--litepicker-button-next-month-color: #9e9e9e;
--litepicker-button-prev-month-color-hover: #2196f3;
--litepicker-button-next-month-color-hover: #2196f3;
--litepicker-month-width: calc(var(--litepicker-day-width) * 7);
--litepicker-month-weekday-color: #9e9e9e;
--litepicker-month-week-number-color: #9e9e9e;
--litepicker-day-width: 38px;
--litepicker-day-color: #333;
--litepicker-day-color-hover: #2196f3;
--litepicker-is-today-color: #f44336;
--litepicker-is-in-range-color: #bbdefb;
--litepicker-is-locked-color: #9e9e9e;
--litepicker-is-start-color: #fff;
--litepicker-is-start-color-bg: #2196f3;
--litepicker-is-end-color: #fff;
--litepicker-is-end-color-bg: #2196f3;
--litepicker-button-cancel-color: #fff;
--litepicker-button-cancel-color-bg: #9e9e9e;
--litepicker-button-apply-color: #fff;
--litepicker-button-apply-color-bg: #2196f3;
--litepicker-button-reset-color: #909090;
--litepicker-button-reset-color-hover: #2196f3;
--litepicker-highlighted-day-color: #333;
--litepicker-highlighted-day-color-bg: #ffeb3b;
}
.show-week-numbers {
--litepicker-month-width: calc(var(--litepicker-day-width) * 8);
}
.litepicker {
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
font-size: 0.8em;
display: none;
}
.litepicker button {
border: none;
background: none;
}
.litepicker .container__main {
display: -webkit-box;
display: -ms-flexbox;
display: flex;
}
.litepicker .container__months {
display: -webkit-box;
display: -ms-flexbox;
display: flex;
-ms-flex-wrap: wrap;
flex-wrap: wrap;
background-color: var(--litepicker-container-months-color-bg);
border-radius: 5px;
-webkit-box-shadow: 0 0 5px var(--litepicker-container-months-box-shadow-color);
box-shadow: 0 0 5px var(--litepicker-container-months-box-shadow-color);
width: calc(var(--litepicker-month-width) + 10px);
-webkit-box-sizing: content-box;
box-sizing: content-box;
}
.litepicker .container__months.columns-2 {
width: calc((var(--litepicker-month-width) * 2) + 20px);
}
.litepicker .container__months.columns-3 {
width: calc((var(--litepicker-month-width) * 3) + 30px);
}
.litepicker .container__months.columns-4 {
width: calc((var(--litepicker-month-width) * 4) + 40px);
}
.litepicker .container__months.split-view .month-item-header .button-previous-month, .litepicker .container__months.split-view .month-item-header .button-next-month {
visibility: visible;
}
.litepicker .container__months .month-item {
padding: 5px;
width: var(--litepicker-month-width);
-webkit-box-sizing: content-box;
box-sizing: content-box;
}
.litepicker .container__months .month-item-header {
display: -webkit-box;
display: -ms-flexbox;
display: flex;
-webkit-box-pack: justify;
-ms-flex-pack: justify;
justify-content: space-between;
font-weight: 500;
padding: 10px 5px;
text-align: center;
-webkit-box-align: center;
-ms-flex-align: center;
align-items: center;
color: var(--litepicker-month-header-color);
}
.litepicker .container__months .month-item-header div {
-webkit-box-flex: 1;
-ms-flex: 1;
flex: 1;
}
.litepicker .container__months .month-item-header div > .month-item-name {
margin-right: 5px;
}
.litepicker .container__months .month-item-header div > .month-item-year {
padding: 0;
}
.litepicker .container__months .month-item-header .reset-button {
color: var(--litepicker-button-reset-color);
}
.litepicker .container__months .month-item-header .reset-button > svg {
fill: var(--litepicker-button-reset-color);
}
.litepicker .container__months .month-item-header .reset-button * {
pointer-events: none;
}
.litepicker .container__months .month-item-header .reset-button:hover {
color: var(--litepicker-button-reset-color-hover);
}
.litepicker .container__months .month-item-header .reset-button:hover > svg {
fill: var(--litepicker-button-reset-color-hover);
}
.litepicker .container__months .month-item-header .button-previous-month, .litepicker .container__months .month-item-header .button-next-month {
visibility: hidden;
text-decoration: none;
padding: 3px 5px;
border-radius: 3px;
-webkit-transition: color 0.3s, border 0.3s;
transition: color 0.3s, border 0.3s;
cursor: default;
}
.litepicker .container__months .month-item-header .button-previous-month *, .litepicker .container__months .month-item-header .button-next-month * {
pointer-events: none;
}
.litepicker .container__months .month-item-header .button-previous-month {
color: var(--litepicker-button-prev-month-color);
}
.litepicker .container__months .month-item-header .button-previous-month > svg, .litepicker .container__months .month-item-header .button-previous-month > img {
fill: var(--litepicker-button-prev-month-color);
}
.litepicker .container__months .month-item-header .button-previous-month:hover {
color: var(--litepicker-button-prev-month-color-hover);
}
.litepicker .container__months .month-item-header .button-previous-month:hover > svg {
fill: var(--litepicker-button-prev-month-color-hover);
}
.litepicker .container__months .month-item-header .button-next-month {
color: var(--litepicker-button-next-month-color);
}
.litepicker .container__months .month-item-header .button-next-month > svg, .litepicker .container__months .month-item-header .button-next-month > img {
fill: var(--litepicker-button-next-month-color);
}
.litepicker .container__months .month-item-header .button-next-month:hover {
color: var(--litepicker-button-next-month-color-hover);
}
.litepicker .container__months .month-item-header .button-next-month:hover > svg {
fill: var(--litepicker-button-next-month-color-hover);
}
.litepicker .container__months .month-item-weekdays-row {
display: -webkit-box;
display: -ms-flexbox;
display: flex;
justify-self: center;
-webkit-box-pack: start;
-ms-flex-pack: start;
justify-content: flex-start;
color: var(--litepicker-month-weekday-color);
}
.litepicker .container__months .month-item-weekdays-row > div {
padding: 5px 0;
font-size: 85%;
-webkit-box-flex: 1;
-ms-flex: 1;
flex: 1;
width: var(--litepicker-day-width);
text-align: center;
}
.litepicker .container__months .month-item:first-child .button-previous-month {
visibility: visible;
}
.litepicker .container__months .month-item:last-child .button-next-month {
visibility: visible;
}
.litepicker .container__months .month-item.no-previous-month .button-previous-month {
visibility: hidden;
}
.litepicker .container__months .month-item.no-next-month .button-next-month {
visibility: hidden;
}
.litepicker .container__days {
display: -webkit-box;
display: -ms-flexbox;
display: flex;
-ms-flex-wrap: wrap;
flex-wrap: wrap;
justify-self: center;
-webkit-box-pack: start;
-ms-flex-pack: start;
justify-content: flex-start;
text-align: center;
-webkit-box-sizing: content-box;
box-sizing: content-box;
}
.litepicker .container__days > div, .litepicker .container__days > a {
padding: 5px 0;
width: var(--litepicker-day-width);
}
.litepicker .container__days .day-item {
color: var(--litepicker-day-color);
text-align: center;
text-decoration: none;
border-radius: 3px;
-webkit-transition: color 0.3s, border 0.3s;
transition: color 0.3s, border 0.3s;
cursor: default;
}
.litepicker .container__days .day-item:hover {
color: var(--litepicker-day-color-hover);
-webkit-box-shadow: inset 0 0 0 1px var(--litepicker-day-color-hover);
box-shadow: inset 0 0 0 1px var(--litepicker-day-color-hover);
}
.litepicker .container__days .day-item.is-today {
color: var(--litepicker-is-today-color);
}
.litepicker .container__days .day-item.is-locked {
color: var(--litepicker-is-locked-color);
}
.litepicker .container__days .day-item.is-locked:hover {
color: var(--litepicker-is-locked-color);
-webkit-box-shadow: none;
box-shadow: none;
cursor: default;
}
.litepicker .container__days .day-item.is-in-range {
background-color: var(--litepicker-is-in-range-color);
border-radius: 0;
}
.litepicker .container__days .day-item.is-start-date {
color: var(--litepicker-is-start-color);
background-color: var(--litepicker-is-start-color-bg);
border-top-left-radius: 5px;
border-bottom-left-radius: 5px;
border-top-right-radius: 0;
border-bottom-right-radius: 0;
}
.litepicker .container__days .day-item.is-start-date.is-flipped {
border-top-left-radius: 0;
border-bottom-left-radius: 0;
border-top-right-radius: 5px;
border-bottom-right-radius: 5px;
}
.litepicker .container__days .day-item.is-end-date {
color: var(--litepicker-is-end-color);
background-color: var(--litepicker-is-end-color-bg);
border-top-left-radius: 0;
border-bottom-left-radius: 0;
border-top-right-radius: 5px;
border-bottom-right-radius: 5px;
}
.litepicker .container__days .day-item.is-end-date.is-flipped {
border-top-left-radius: 5px;
border-bottom-left-radius: 5px;
border-top-right-radius: 0;
border-bottom-right-radius: 0;
}
.litepicker .container__days .day-item.is-start-date.is-end-date {
border-top-left-radius: 5px;
border-bottom-left-radius: 5px;
border-top-right-radius: 5px;
border-bottom-right-radius: 5px;
}
.litepicker .container__days .day-item.is-highlighted {
color: var(--litepicker-highlighted-day-color);
background-color: var(--litepicker-highlighted-day-color-bg);
}
.litepicker .container__days .week-number {
display: -webkit-box;
display: -ms-flexbox;
display: flex;
-webkit-box-align: center;
-ms-flex-align: center;
align-items: center;
-webkit-box-pack: center;
-ms-flex-pack: center;
justify-content: center;
color: var(--litepicker-month-week-number-color);
font-size: 85%;
}
.litepicker .container__footer {
text-align: right;
padding: 10px 5px;
margin: 0 5px;
background-color: var(--litepicker-footer-color-bg);
-webkit-box-shadow: inset 0px 3px 3px 0px var(--litepicker-footer-box-shadow-color);
box-shadow: inset 0px 3px 3px 0px var(--litepicker-footer-box-shadow-color);
border-bottom-left-radius: 5px;
border-bottom-right-radius: 5px;
}
.litepicker .container__footer .preview-date-range {
margin-right: 10px;
font-size: 90%;
}
.litepicker .container__footer .button-cancel {
background-color: var(--litepicker-button-cancel-color-bg);
color: var(--litepicker-button-cancel-color);
border: 0;
padding: 3px 7px 4px;
border-radius: 3px;
}
.litepicker .container__footer .button-cancel * {
pointer-events: none;
}
.litepicker .container__footer .button-apply {
background-color: var(--litepicker-button-apply-color-bg);
color: var(--litepicker-button-apply-color);
border: 0;
padding: 3px 7px 4px;
border-radius: 3px;
margin-left: 10px;
margin-right: 10px;
}
.litepicker .container__footer .button-apply:disabled {
opacity: 0.7;
}
.litepicker .container__footer .button-apply * {
pointer-events: none;
}
.litepicker .container__tooltip {
position: absolute;
margin-top: -4px;
padding: 4px 8px;
border-radius: 4px;
background-color: var(--litepicker-tooltip-color-bg);
-webkit-box-shadow: 0 1px 3px rgba(0,0,0,0.25);
box-shadow: 0 1px 3px rgba(0,0,0,0.25);
white-space: nowrap;
font-size: 11px;
pointer-events: none;
visibility: hidden;
}
.litepicker .container__tooltip:before {
position: absolute;
bottom: -5px;
left: calc(50% - 5px);
border-top: 5px solid rgba(0,0,0,0.12);
border-right: 5px solid transparent;
border-left: 5px solid transparent;
content: "";
}
.litepicker .container__tooltip:after {
position: absolute;
bottom: -4px;
left: calc(50% - 4px);
border-top: 4px solid var(--litepicker-tooltip-color-bg);
border-right: 4px solid transparent;
border-left: 4px solid transparent;
content: "";
}

File diff suppressed because one or more lines are too long

View File

@@ -21,7 +21,7 @@ dtLog = null;
function fill_logtablebody(vv) { function fill_logtablebody(vv) {
dtLog.clear(); dtLog.clear();
if (!Array.isArray(vv) || vv.length === 0) { if (!Array.isArray(vv) || vv.length === 0) {
$('#btnExport').prop('disabled', true); //$('#btnExport').prop('disabled', true);
return; return;
} }
dtLog.rows.add(vv); dtLog.rows.add(vv);
@@ -29,7 +29,7 @@ function fill_logtablebody(vv) {
$('#tablesize').text("Table Size: " + vv.length); $('#tablesize').text("Table Size: " + vv.length);
$('#btnExport').prop('disabled', false); //$('#btnExport').prop('disabled', false);
} }
/** /**
@@ -43,8 +43,10 @@ function reloadLogs(APIURL = "Log/", date, filter) {
date: date, date: date,
filter: filter filter: filter
}) })
console.log("Loading logs with params: " + params.toString());
window.logdata = []; window.logdata = [];
fetchAPI(APIURL + "List?" + params.toString(), "GET", {}, null, (okdata) => { fetchAPI(APIURL + "List?" + params.toString(), "GET", {}, null, (okdata) => {
console.log("Logs loaded: " + okdata.length);
if (Array.isArray(okdata)) { if (Array.isArray(okdata)) {
window.logdata.push(...okdata); window.logdata.push(...okdata);
fill_logtablebody(window.logdata); fill_logtablebody(window.logdata);
@@ -54,16 +56,33 @@ function reloadLogs(APIURL = "Log/", date, filter) {
}); });
} }
datepicker = null;
$btnGet = null;
$(document).ready(function () { $(document).ready(function () {
console.log("log.js ready"); console.log("log.js ready");
let selectedlogdate = ""; let selectedlogdate = "";
let logfilter = ""; let logfilter = "";
let APIURL = "Log/"; let APIURL = "Log/";
$btnGet = $('#btnGet');
datepicker = new Litepicker({
element: document.getElementById('logdate'),
format: 'DD/MM/YYYY',
lang: 'en-US',
autoApply: true,
singleMode: true,
startDate: new Date(),
onSelect: (date) => {
selectedlogdate = date.format('DD/MM/YYYY');
console.log("Selected date: " + selectedlogdate);
}
})
if (dtLog === null) { if (dtLog === null) {
dtLog = new DataTable('#logtable', { dtLog = new DataTable('#logtable', {
dom: 'Bfrtip',
data: [], data: [],
pageLength: 25, pageLength: 25,
columns: [ columns: [
@@ -72,36 +91,42 @@ $(document).ready(function () {
{ title: "Time", data: "timenya" }, { title: "Time", data: "timenya" },
{ title: "Machine", data: "machine" }, { title: "Machine", data: "machine" },
{ title: "Description", data: "description" } { title: "Description", data: "description" }
] ],
buttons: ['print', 'pdf', 'excel']
}); });
} }
// findalldate is checkbox, if checked will disable datepicker
if (!$('#logdate').val()) { $('#findalldate').off('change').on('change', function () {
const today = new Date(); if ($(this).is(':checked')) {
const dd = String(today.getDate()).padStart(2, '0'); datepicker.disabled = true;
const mm = String(today.getMonth() + 1).padStart(2, '0'); selectedlogdate = "alldate";
const yyyy = today.getFullYear(); console.log("Find all date checked, omitting date filter");
$('#logdate').val(`${yyyy}-${mm}-${dd}`); } else {
selectedlogdate = `${dd}-${mm}-${yyyy}`; datepicker.disabled = false;
reloadLogs(APIURL, selectedlogdate, logfilter); const date = datepicker.getDate();
} selectedlogdate = date.format('DD/MM/YYYY');
$('#logdate').off('change').on('change', function () { console.log("Find all date unchecked, selected date: " + selectedlogdate);
const selected = $(this).val();
if (selected) {
const [year, month, day] = selected.split('-');
selectedlogdate = `${day}-${month}-${year}`;
reloadLogs(APIURL, selectedlogdate, logfilter);
} }
}); });
$('#searchfilter').off('input').on('input', function () { $('#searchfilter').off('input').on('input', function () {
logfilter = $(this).val(); logfilter = $(this).val();
//reloadLogs(APIURL, selectedlogdate, logfilter);
});
$btnGet.click(function () {
let checked = $('#findalldate').is(':checked');
if (checked && logfilter.trim() === "") {
alert("Please enter a filter when 'Find All Date' is checked to avoid large data load.");
return;
}
//$(this).data('selectedlogdate', selectedlogdate);
//$(this).data('logfilter', logfilter);
reloadLogs(APIURL, selectedlogdate, logfilter); reloadLogs(APIURL, selectedlogdate, logfilter);
}); });
$('#btnExport').off('click').on('click', function () {
DoExport(APIURL, "log.xlsx", { date: selectedlogdate, filter: logfilter });
});
selectedlogdate = datepicker.getDate().format('DD/MM/YYYY');
console.log("Initial selected date: " + selectedlogdate);
$btnGet.trigger('click'); // load logs on page load
}); });

View File

@@ -22,6 +22,15 @@ window.schedulebankdata = [];
window.selectedschedulerow = null; window.selectedschedulerow = null;
dtScheduleBank = null; dtScheduleBank = null;
dtTodaySchedule = null;
function fill_todayscheduletablebody(vv) {
dtTodaySchedule.clear();
if (!Array.isArray(vv) || vv.length === 0) return;
dtTodaySchedule.rows.add(vv);
dtTodaySchedule.draw();
}
/** /**
* Fill schedulebank table body with values * Fill schedulebank table body with values
@@ -117,7 +126,19 @@ function reloadTimerBank(APIURL = "ScheduleBank/") {
}); });
} }
function reloadTodaySchedule(APIURL = "ScheduleBank/") {
fetchAPI(APIURL + "TodaySchedule", "GET", {}, null, (okdata) => {
if (Array.isArray(okdata)) {
console.log("Today's Schedule: ", okdata);
fill_todayscheduletablebody(okdata);
}
}, (errdata) => {
alert("Error loading today's schedule : " + errdata.message);
});
}
dayViewMode = 'all'; // all, everyday, monday, tuesday, wednesday, thursday, friday, saturday, sunday dayViewMode = 'all'; // all, everyday, monday, tuesday, wednesday, thursday, friday, saturday, sunday
scheduledate = null; // Litepicker instance for schedule date selection
$(document).ready(function () { $(document).ready(function () {
console.log("schedulebank.js loaded successfully"); console.log("schedulebank.js loaded successfully");
@@ -169,6 +190,26 @@ $(document).ready(function () {
}); });
} }
if (dtTodaySchedule === null) {
dtTodaySchedule = new DataTable('#todaytable', {
dom: 'Bfrtip',
data: [],
pageLength: 25,
columns: [
{ title: "No", data: "index" },
{ title: "Description", data: "description" },
{ title: "Day", data: "day" },
{ title: "Time", data: "time" },
{ title: "Message", data: "soundpath" },
{ title: "Repeat", data: "repeat" },
{ title: "Enable", data: "enable" },
{ title: "Broadcast Zones", data: "broadcastZones" },
{ title: "Language", data: "language" }
],
buttons: ['print', 'pdf']
});
}
$.fn.dataTable.ext.search.push(function (settings, data, dataIndex, rowData) { $.fn.dataTable.ext.search.push(function (settings, data, dataIndex, rowData) {
if (settings.nTable.id !== 'schedulebanktable') return true; if (settings.nTable.id !== 'schedulebanktable') return true;
switch (dayViewMode) { switch (dayViewMode) {
@@ -223,16 +264,30 @@ $(document).ready(function () {
let $weeklyselect = $schedulemodal.find('#weeklyselect'); let $weeklyselect = $schedulemodal.find('#weeklyselect');
// radio button for specific date // radio button for specific date
let $schedulespecialdate = $schedulemodal.find('#schedulespecialdate'); let $schedulespecialdate = $schedulemodal.find('#schedulespecialdate');
scheduledate = new Litepicker({
element: document.getElementById('scheduledate'),
format: 'DD/MM/YYYY',
lang: 'en-US',
autoApply: true,
singleMode: true,
startDate: new Date(),
onSelect: (date) => {
console.log("Selected special date: " + date.format('DD/MM/YYYY'));
}
})
// date input // date input
let $scheduledate = $schedulemodal.find('#scheduledate'); //let $scheduledate = $schedulemodal.find('#scheduledate');
// select2 for language // select2 for language
let $languageselect = $schedulemodal.find('#languageselect'); let $languageselect = $schedulemodal.find('#languageselect');
$schedulespecialdate.off('change').on('change', function () { $schedulespecialdate.off('change').on('change', function () {
if ($(this).is(':checked')) { if ($(this).is(':checked')) {
$scheduledate.prop('disabled', false); //$scheduledate.prop('disabled', false);
scheduledate.disabled = false
} else { } else {
$scheduledate.prop('disabled', true); //$scheduledate.prop('disabled', true);
scheduledate.disabled = true
} }
}); });
@@ -261,7 +316,8 @@ $(document).ready(function () {
dropdownParent: $('#schedulemodal') dropdownParent: $('#schedulemodal')
}); });
$scheduledate.prop('disabled', true).val(''); //$scheduledate.prop('disabled', true).val('');
scheduledate.disabled = true;
$schedulezones.empty().select2({ $schedulezones.empty().select2({
data: window.BroadcastZoneList.map(zone => ({ id: zone.description, text: zone.description })), data: window.BroadcastZoneList.map(zone => ({ id: zone.description, text: zone.description })),
placeholder: 'Select broadcast zones', placeholder: 'Select broadcast zones',
@@ -284,24 +340,28 @@ $(document).ready(function () {
$scheduleeveryday.off('change').on('change', function () { $scheduleeveryday.off('change').on('change', function () {
if ($(this).is(':checked')) { if ($(this).is(':checked')) {
$weeklyselect.prop('disabled', true); $weeklyselect.prop('disabled', true);
$scheduledate.prop('disabled', true); //$scheduledate.prop('disabled', true);
scheduledate.disabled = true;
} }
}); });
$scheduleweekly.off('change').on('change', function () { $scheduleweekly.off('change').on('change', function () {
if ($(this).is(':checked')) { if ($(this).is(':checked')) {
$weeklyselect.prop('disabled', false); $weeklyselect.prop('disabled', false);
$scheduledate.prop('disabled', true); //$scheduledate.prop('disabled', true);
scheduledate.disabled = true;
} }
}); });
$schedulespecialdate.off('change').on('change', function () { $schedulespecialdate.off('change').on('change', function () {
if ($(this).is(':checked')) { if ($(this).is(':checked')) {
$weeklyselect.prop('disabled', true); $weeklyselect.prop('disabled', true);
$scheduledate.prop('disabled', false); //$scheduledate.prop('disabled', false);
scheduledate.disabled = false;
} }
}); });
} }
reloadTimerBank(APIURL); reloadTimerBank(APIURL);
reloadTodaySchedule(APIURL);
reloadBroadcastZones(); reloadBroadcastZones();
getLanguages(); getLanguages();
getScheduledDays(); getScheduledDays();
@@ -309,6 +369,7 @@ $(document).ready(function () {
$btnClear.click(() => { $btnClear.click(() => {
DoClear(APIURL, "Timerbank", (okdata) => { DoClear(APIURL, "Timerbank", (okdata) => {
reloadTimerBank(APIURL); reloadTimerBank(APIURL);
reloadTodaySchedule(APIURL);
alert("Success clear schedulebank : " + okdata.message); alert("Success clear schedulebank : " + okdata.message);
}, (errdata) => { }, (errdata) => {
alert("Error clear schedulebank : " + errdata.message); alert("Error clear schedulebank : " + errdata.message);
@@ -317,7 +378,9 @@ $(document).ready(function () {
}); });
$btnAdd.click(() => { $btnAdd.click(() => {
$schedulemodal.modal('show'); $schedulemodal.modal('show');
clearScheduleModal(); clearScheduleModal();
$scheduleeveryday.prop('checked', true).trigger('click');
$schedulemodal.off('click.scheduleclose').on('click.scheduleclose', '#scheduleclose', function () { $schedulemodal.off('click.scheduleclose').on('click.scheduleclose', '#scheduleclose', function () {
$schedulemodal.modal('hide'); $schedulemodal.modal('hide');
@@ -333,7 +396,7 @@ $(document).ready(function () {
if ($scheduleeveryday.is(':checked')) { if ($scheduleeveryday.is(':checked')) {
_Day = "Everyday"; _Day = "Everyday";
} else if ($schedulespecialdate.is(':checked')) { } else if ($schedulespecialdate.is(':checked')) {
_Day = Convert_input_date_to_string($scheduledate.val()); _Day = Convert_input_date_to_string(scheduledate.getDate().format('DD/MM/YYYY'));
} else if ($scheduleweekly.is(':checked')) { } else if ($scheduleweekly.is(':checked')) {
_Day = $weeklyselect.val(); _Day = $weeklyselect.val();
} }
@@ -363,6 +426,7 @@ $(document).ready(function () {
fetchAPI(APIURL + "Add", "POST", {}, scheduleObj, (okdata) => { fetchAPI(APIURL + "Add", "POST", {}, scheduleObj, (okdata) => {
reloadTimerBank(APIURL); reloadTimerBank(APIURL);
reloadTodaySchedule(APIURL);
alert("Success add schedule: " + okdata.message); alert("Success add schedule: " + okdata.message);
}, (errdata) => { }, (errdata) => {
alert("Error add schedule: " + errdata.message); alert("Error add schedule: " + errdata.message);
@@ -393,6 +457,7 @@ $(document).ready(function () {
if (confirm(`Are you sure to delete schedule [${sr.index}] Description=${sr.description}?`)) { if (confirm(`Are you sure to delete schedule [${sr.index}] Description=${sr.description}?`)) {
fetchAPI(APIURL + "DeleteByIndex/" + sr.index, "DELETE", {}, null, (okdata) => { fetchAPI(APIURL + "DeleteByIndex/" + sr.index, "DELETE", {}, null, (okdata) => {
reloadTimerBank(APIURL); reloadTimerBank(APIURL);
reloadTodaySchedule(APIURL);
alert("Success delete schedule : " + okdata.message); alert("Success delete schedule : " + okdata.message);
}, (errdata) => { }, (errdata) => {
alert("Error delete schedule : " + errdata.message); alert("Error delete schedule : " + errdata.message);
@@ -438,7 +503,8 @@ $(document).ready(function () {
$weeklyselect.val(null).trigger('change'); $weeklyselect.val(null).trigger('change');
$weeklyselect.prop('disabled', true); $weeklyselect.prop('disabled', true);
$scheduledate.prop('disabled', true); //$scheduledate.prop('disabled', true);
scheduledate.disabled = true;
break; break;
case 'Sunday': case 'Sunday':
case 'Monday': case 'Monday':
@@ -452,7 +518,8 @@ $(document).ready(function () {
$weeklyselect.val(sr.Day).trigger('change'); $weeklyselect.val(sr.Day).trigger('change');
$weeklyselect.prop('disabled', false); $weeklyselect.prop('disabled', false);
$scheduledate.prop('disabled', true); //$scheduledate.prop('disabled', true);
scheduledate.disabled = true;
break; break;
default: default:
console.log("Assuming special date for Day: ", sr.Day); console.log("Assuming special date for Day: ", sr.Day);
@@ -461,8 +528,10 @@ $(document).ready(function () {
if (/^\d{2}\/\d{2}\/\d{4}$/.test(sr.Day)) { if (/^\d{2}\/\d{2}\/\d{4}$/.test(sr.Day)) {
$schedulespecialdate.prop('checked', true); $schedulespecialdate.prop('checked', true);
$scheduledate.val(Convert_string_to_input_date(sr.Day)); //$scheduledate.val(Convert_string_to_input_date(sr.Day));
$scheduledate.prop('disabled', false); // $scheduledate.prop('disabled', false);
scheduledate.setDate(dayjs(sr.Day,'DD/MM/YYYY'));
scheduledate.disabled = false;
$weeklyselect.val(null).trigger('change'); $weeklyselect.val(null).trigger('change');
$weeklyselect.prop('disabled', true); $weeklyselect.prop('disabled', true);
@@ -484,7 +553,8 @@ $(document).ready(function () {
Day = "Everyday"; Day = "Everyday";
} else if ($schedulespecialdate.is(':checked')) { } else if ($schedulespecialdate.is(':checked')) {
// convert date from yyyy-mm-dd to dd/mm/yyyy // convert date from yyyy-mm-dd to dd/mm/yyyy
Day = Convert_input_date_to_string($scheduledate.val()); //Day = Convert_input_date_to_string($scheduledate.val());
Day = scheduledate.getDate().format('DD/MM/YYYY');
} else if ($scheduleweekly.is(':checked')) { } else if ($scheduleweekly.is(':checked')) {
Day = $weeklyselect.val(); Day = $weeklyselect.val();
} }
@@ -516,6 +586,7 @@ $(document).ready(function () {
fetchAPI(APIURL + "UpdateByIndex/" + sr.index, "PATCH", {}, scheduleObj, (okdata) => { fetchAPI(APIURL + "UpdateByIndex/" + sr.index, "PATCH", {}, scheduleObj, (okdata) => {
alert("Success edit schedule: " + okdata.message); alert("Success edit schedule: " + okdata.message);
reloadTimerBank(APIURL); reloadTimerBank(APIURL);
reloadTodaySchedule(APIURL);
}, (errdata) => { }, (errdata) => {
alert("Error edit schedule: " + errdata.message); alert("Error edit schedule: " + errdata.message);
}); });
@@ -537,6 +608,7 @@ $(document).ready(function () {
$btnImport.click(() => { $btnImport.click(() => {
DoImport(APIURL, (okdata) => { DoImport(APIURL, (okdata) => {
reloadTimerBank(APIURL); reloadTimerBank(APIURL);
reloadTodaySchedule(APIURL);
alert("Success import schedulebank from XLSX : " + okdata.message); alert("Success import schedulebank from XLSX : " + okdata.message);
}, (errdata) => { }, (errdata) => {
alert("Error importing schedulebank from XLSX : " + errdata.message); alert("Error importing schedulebank from XLSX : " + errdata.message);

View File

@@ -292,9 +292,9 @@
</div> </div>
<script src="assets/bootstrap/js/bootstrap.min.js"></script> <script src="assets/bootstrap/js/bootstrap.min.js"></script>
<script src="assets/js/bs-init.js"></script> <script src="assets/js/bs-init.js"></script>
<script src="assets/js/datatables.js"></script>
<script src="assets/js/soundchannel.js"></script> <script src="assets/js/soundchannel.js"></script>
<script src="assets/js/broadcastzones.js"></script> <script src="assets/js/broadcastzones.js"></script>
<script src="assets/js/datatables.js"></script>
</body> </body>
</html> </html>

View File

@@ -159,10 +159,10 @@
<script src="assets/bootstrap/js/bootstrap.min.js"></script> <script src="assets/bootstrap/js/bootstrap.min.js"></script>
<script src="assets/js/bs-init.js"></script> <script src="assets/js/bs-init.js"></script>
<script src="assets/js/jquery-3.7.1.min.js"></script> <script src="assets/js/jquery-3.7.1.min.js"></script>
<script src="assets/js/script.js"></script>
<script src="assets/js/all.min.js"></script>
<script src="assets/js/datatables.js"></script>
<script src="assets/js/select2.min.js"></script> <script src="assets/js/select2.min.js"></script>
<script src="assets/js/datatables.js"></script>
<script src="assets/js/all.min.js"></script>
<script src="assets/js/script.js"></script>
</body> </body>
</html> </html>

View File

@@ -119,10 +119,10 @@
<script src="assets/bootstrap/js/bootstrap.min.js"></script> <script src="assets/bootstrap/js/bootstrap.min.js"></script>
<script src="assets/js/bs-init.js"></script> <script src="assets/js/bs-init.js"></script>
<script src="assets/js/jquery-3.7.1.min.js"></script> <script src="assets/js/jquery-3.7.1.min.js"></script>
<script src="assets/js/script.js"></script>
<script src="assets/js/all.min.js"></script>
<script src="assets/js/datatables.js"></script>
<script src="assets/js/select2.min.js"></script> <script src="assets/js/select2.min.js"></script>
<script src="assets/js/datatables.js"></script>
<script src="assets/js/all.min.js"></script>
<script src="assets/js/script.js"></script>
</body> </body>
</html> </html>

View File

@@ -99,8 +99,8 @@
</div> </div>
<script src="assets/bootstrap/js/bootstrap.min.js"></script> <script src="assets/bootstrap/js/bootstrap.min.js"></script>
<script src="assets/js/bs-init.js"></script> <script src="assets/js/bs-init.js"></script>
<script src="assets/js/languagelink.js"></script>
<script src="assets/js/datatables.js"></script> <script src="assets/js/datatables.js"></script>
<script src="assets/js/languagelink.js"></script>
</body> </body>
</html> </html>

View File

@@ -15,6 +15,7 @@
<link rel="stylesheet" href="assets/css/FontAwesome.css"> <link rel="stylesheet" href="assets/css/FontAwesome.css">
<link rel="stylesheet" href="assets/css/bss-overrides.css"> <link rel="stylesheet" href="assets/css/bss-overrides.css">
<link rel="stylesheet" href="assets/css/datatables.css"> <link rel="stylesheet" href="assets/css/datatables.css">
<link rel="stylesheet" href="assets/css/litepicker.css">
<link rel="stylesheet" href="assets/css/Login-Form-Basic-icons.css"> <link rel="stylesheet" href="assets/css/Login-Form-Basic-icons.css">
<link rel="stylesheet" href="assets/css/styles.css"> <link rel="stylesheet" href="assets/css/styles.css">
</head> </head>
@@ -26,16 +27,26 @@
</div> </div>
</div> </div>
<div class="row"> <div class="row">
<div class="col-4 col-sm-4 col-md-2 col-lg-2 col-xl-2"> <div class="col-5 ms-1 me-1">
<div class="row">
<div class="col-auto">
<p class="text-add">Select Log Date</p> <p class="text-add">Select Log Date</p>
</div> </div>
<div class="col-4 col-sm-4 col-md-2 col-lg-2 col-xl-2"><input id="logdate" class="form-control" type="date"></div> <div class="col-auto"><input type="text" id="logdate" class="form-control"></div>
<div class="col-4 col-sm-4 col-md-2 col-lg-2 col-xl-2"><button class="btn w-100 pad-button btn-round-basic color-import" id="btnExport" type="button">Export</button></div> <div class="col">
<div class="col-md-2 col-lg-2 col-xl-2"></div> <div class="form-check w-100 h-100 align-content-center"><input class="form-check-input" type="checkbox" id="findalldate"><label class="form-check-label" for="formCheck-1">All Date</label></div>
<div class="col-4 col-sm-4 col-md-2 col-lg-2 col-xl-2 d-none"> </div>
</div>
</div>
<div class="col-5 ms-1 me-1">
<div class="row">
<div class="col-auto">
<p class="text-add">Search</p> <p class="text-add">Search</p>
</div> </div>
<div class="col-4 col-sm-4 col-md-2 col-lg-2 col-xl-2 d-none"><input type="text" id="searchfilter" class="form-control" placeholder="Search Filter"></div> <div class="col"><input type="text" id="searchfilter" class="form-control" placeholder="Search Filter"></div>
</div>
</div>
<div class="col ms-1 me-1"><button class="btn w-100 pad-button btn-round-basic color-import" id="btnGet" type="button">Get</button></div>
</div> </div>
<div class="row"> <div class="row">
<div class="col"> <div class="col">
@@ -60,8 +71,9 @@
</div> </div>
<script src="assets/bootstrap/js/bootstrap.min.js"></script> <script src="assets/bootstrap/js/bootstrap.min.js"></script>
<script src="assets/js/bs-init.js"></script> <script src="assets/js/bs-init.js"></script>
<script src="assets/js/log.js"></script> <script src="assets/js/litepicker.js"></script>
<script src="assets/js/datatables.js"></script> <script src="assets/js/datatables.js"></script>
<script src="assets/js/log.js"></script>
</body> </body>
</html> </html>

View File

@@ -136,8 +136,8 @@
</div> </div>
<script src="assets/bootstrap/js/bootstrap.min.js"></script> <script src="assets/bootstrap/js/bootstrap.min.js"></script>
<script src="assets/js/bs-init.js"></script> <script src="assets/js/bs-init.js"></script>
<script src="assets/js/messagebank.js"></script>
<script src="assets/js/datatables.js"></script> <script src="assets/js/datatables.js"></script>
<script src="assets/js/messagebank.js"></script>
</body> </body>
</html> </html>

View File

@@ -120,8 +120,8 @@
</div> </div>
<script src="assets/bootstrap/js/bootstrap.min.js"></script> <script src="assets/bootstrap/js/bootstrap.min.js"></script>
<script src="assets/js/bs-init.js"></script> <script src="assets/js/bs-init.js"></script>
<script src="assets/js/soundbank.js"></script>
<script src="assets/js/datatables.js"></script> <script src="assets/js/datatables.js"></script>
<script src="assets/js/soundbank.js"></script>
</body> </body>
</html> </html>

View File

@@ -15,6 +15,7 @@
<link rel="stylesheet" href="assets/css/FontAwesome.css"> <link rel="stylesheet" href="assets/css/FontAwesome.css">
<link rel="stylesheet" href="assets/css/bss-overrides.css"> <link rel="stylesheet" href="assets/css/bss-overrides.css">
<link rel="stylesheet" href="assets/css/datatables.css"> <link rel="stylesheet" href="assets/css/datatables.css">
<link rel="stylesheet" href="assets/css/litepicker.css">
<link rel="stylesheet" href="assets/css/Login-Form-Basic-icons.css"> <link rel="stylesheet" href="assets/css/Login-Form-Basic-icons.css">
<link rel="stylesheet" href="assets/css/styles.css"> <link rel="stylesheet" href="assets/css/styles.css">
</head> </head>
@@ -25,46 +26,6 @@
<h2 style="text-align: center;">Schedule Bank</h2> <h2 style="text-align: center;">Schedule Bank</h2>
</div> </div>
</div> </div>
<div class="row d-none pad-row-search">
<div class="col-md-7 col-lg-7 col-xl-7"></div>
<div class="col-2 col-sm-2 col-md-2 col-lg-2 col-xl-2 search">
<p class="text-add">Search</p>
</div>
<div class="col-10 col-sm-10 col-md-3 col-lg-3 col-xl-3"><input class="w-100 form-control" type="text" id="findschedule" placeholder="Search keyword" name="findsoundbank"></div>
</div>
<div class="row">
<div class="col-3 col-sm-3 col-md-3 col-lg-2 col-xl-2"><button class="btn w-100 pad-button btn-round-basic color-add" id="btnClear" type="button">Clear</button></div>
<div class="col-3 col-sm-3 col-md-3 col-lg-2 col-xl-2"><button class="btn w-100 pad-button btn-round-basic color-add" id="btnAdd" type="button">Add</button></div>
<div class="col-3 col-sm-3 col-md-3 col-lg-2 col-xl-2"><button class="btn w-100 pad-button btn-round-basic color-remove" id="btnRemove" type="button">Remove</button></div>
<div class="col-3 col-sm-3 col-md-3 col-lg-2 col-xl-2"><button class="btn w-100 pad-button btn-round-basic color-edit" id="btnEdit" type="button">Edit</button></div>
<div class="col-6 col-sm-6 col-md-6 col-lg-2 col-xl-2"><button class="btn w-100 pad-button btn-round-basic color-import" id="btnExport" type="button">Export</button></div>
<div class="col-6 col-sm-6 col-md-6 col-lg-2 col-xl-2"><button class="btn w-100 pad-button btn-round-basic color-import" id="btnImport" type="button">Import</button></div>
</div>
<div class="row">
<div class="col">
<p id="tablesize" class="text-add" style="text-align: center;">Table Length : N/A</p>
</div>
</div>
<div class="row">
<div class="table-responsive">
<table class="table" id="schedulebanktable">
<thead>
<tr>
<th class="class05">No</th>
<th class="class15">Description</th>
<th class="class15">Day</th>
<th class="class10">Time</th>
<th class="class15">Sound Path</th>
<th class="class10">Repeat</th>
<th class="class05">Enable</th>
<th class="class15">Broadcast Zones</th>
<th class="class10">Language</th>
</tr>
</thead>
<tbody id="schedulebanktablebody"></tbody>
</table>
</div>
</div>
<div class="modal fade" role="dialog" tabindex="-1" id="schedulemodal"> <div class="modal fade" role="dialog" tabindex="-1" id="schedulemodal">
<div class="modal-dialog" role="document"> <div class="modal-dialog" role="document">
<div class="modal-content"> <div class="modal-content">
@@ -106,10 +67,10 @@
</div> </div>
</div> </div>
<div class="row py-2"> <div class="row py-2">
<div class="col-7 col-sm-7 col-md-7 col-lg-6 col-xl-6 pad-day"> <div class="col-auto pad-day">
<div class="form-check"><input class="form-check-input" type="radio" id="schedulespecialdate" name="dayselect"><label class="form-check-label" for="schedulespecialdate">Special Date</label></div> <div class="form-check"><input class="form-check-input" type="radio" id="schedulespecialdate" name="dayselect"><label class="form-check-label" for="schedulespecialdate">Special Date</label></div>
</div> </div>
<div class="col-sm-5 col-md-5 col-lg-6 col-xl-6"><input id="scheduledate" class="form-control" type="date"></div> <div class="col"><input type="text" id="scheduledate" class="form-control"></div>
</div> </div>
</div> </div>
</div> </div>
@@ -181,10 +142,80 @@
</div> </div>
</div> </div>
</div> </div>
<div class="accordion" role="tablist" id="accordion-1">
<div class="accordion-item">
<h2 class="accordion-header" role="tab"><button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#accordion-1 .item-1" aria-expanded="false" aria-controls="accordion-1 .item-1">Schedule Table</button></h2>
<div class="accordion-collapse collapse item-1" role="tabpanel" data-bs-parent="#accordion-1">
<div class="accordion-body">
<div class="row">
<div class="col-3 col-sm-3 col-md-3 col-lg-2 col-xl-2"><button class="btn w-100 pad-button btn-round-basic color-add" id="btnClear" type="button">Clear</button></div>
<div class="col-3 col-sm-3 col-md-3 col-lg-2 col-xl-2"><button class="btn w-100 pad-button btn-round-basic color-add" id="btnAdd" type="button">Add</button></div>
<div class="col-3 col-sm-3 col-md-3 col-lg-2 col-xl-2"><button class="btn w-100 pad-button btn-round-basic color-remove" id="btnRemove" type="button">Remove</button></div>
<div class="col-3 col-sm-3 col-md-3 col-lg-2 col-xl-2"><button class="btn w-100 pad-button btn-round-basic color-edit" id="btnEdit" type="button">Edit</button></div>
<div class="col-6 col-sm-6 col-md-6 col-lg-2 col-xl-2"><button class="btn w-100 pad-button btn-round-basic color-import" id="btnExport" type="button">Export</button></div>
<div class="col-6 col-sm-6 col-md-6 col-lg-2 col-xl-2"><button class="btn w-100 pad-button btn-round-basic color-import" id="btnImport" type="button">Import</button></div>
</div>
<div class="row">
<div class="col">
<p id="tablesize" class="text-add" style="text-align: center;">Table Length : N/A</p>
</div>
</div>
<div class="row">
<div class="table-responsive">
<table class="table" id="schedulebanktable">
<thead>
<tr>
<th class="class05">No</th>
<th class="class15">Description</th>
<th class="class15">Day</th>
<th class="class10">Time</th>
<th class="class15">Sound Path</th>
<th class="class10">Repeat</th>
<th class="class05">Enable</th>
<th class="class15">Broadcast Zones</th>
<th class="class10">Language</th>
</tr>
</thead>
<tbody id="schedulebanktablebody"></tbody>
</table>
</div>
</div>
</div>
</div>
</div>
<div class="accordion-item">
<h2 class="accordion-header" role="tab"><button class="accordion-button" type="button" data-bs-toggle="collapse" data-bs-target="#accordion-1 .item-2" aria-expanded="true" aria-controls="accordion-1 .item-2">Today's Schedule</button></h2>
<div class="accordion-collapse collapse show item-2" role="tabpanel" data-bs-parent="#accordion-1">
<div class="accordion-body">
<div class="row">
<div class="table-responsive">
<table class="table" id="todaytable">
<thead>
<tr>
<th class="class05">No</th>
<th class="class15">Description</th>
<th class="class15">Day</th>
<th class="class10">Time</th>
<th class="class15">Sound Path</th>
<th class="class10">Repeat</th>
<th class="class05">Enable</th>
<th class="class15">Broadcast Zones</th>
<th class="class10">Language</th>
</tr>
</thead>
<tbody id="schedulebanktablebody-1"></tbody>
</table>
</div>
</div>
</div>
</div>
</div>
</div>
<script src="assets/bootstrap/js/bootstrap.min.js"></script> <script src="assets/bootstrap/js/bootstrap.min.js"></script>
<script src="assets/js/bs-init.js"></script> <script src="assets/js/bs-init.js"></script>
<script src="assets/js/schedulebank.js"></script> <script src="assets/js/litepicker.js"></script>
<script src="assets/js/datatables.js"></script> <script src="assets/js/datatables.js"></script>
<script src="assets/js/schedulebank.js"></script>
</body> </body>
</html> </html>

View File

@@ -16,6 +16,10 @@ import content.Language
import content.VoiceType import content.VoiceType
import database.data.Log import database.data.Log
import database.MariaDB import database.MariaDB
import database.table.Table_BroadcastZones
import database.table.Table_Logs
import database.table.Table_Messagebank
import database.table.Table_SoundChannel
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.delay import kotlinx.coroutines.delay
@@ -44,8 +48,12 @@ const val version = "0.0.29 (09/02/2026)"
const val max_channel = 64 const val max_channel = 64
val apptick : Long = System.currentTimeMillis() val apptick : Long = System.currentTimeMillis()
// dipakai untuk ambil messagebank berdasarkan id
// 4 tabel utama , kepakai dimana-mana, ditaruh di root biar gampang aksesnya
lateinit var broadcastDB: Table_BroadcastZones
lateinit var soundchannelDB: Table_SoundChannel
lateinit var messageDB: Table_Messagebank
lateinit var logDB: Table_Logs
val contentCache = ContentCache() val contentCache = ContentCache()
@@ -235,14 +243,14 @@ fun main(args: Array<String>) {
val androidserver = TCP_Android_Command_Server() val androidserver = TCP_Android_Command_Server()
androidserver.StartTcpServer(5003){ androidserver.StartTcpServer(5003){
Logger.info { it } Logger.info { it }
db.logDB.Add(Log.NewLog("ANDROID", it)) logDB.Add(Log.NewLog("ANDROID", it))
} }
val barixserver = TCP_Barix_Command_Server() val barixserver = TCP_Barix_Command_Server()
barixserver.StartTcpServer { cmd -> barixserver.StartTcpServer { cmd ->
val _tcp = barixserver.getSocket(cmd.ipaddress) val _tcp = barixserver.getSocket(cmd.ipaddress)
val _streamer = StreamerOutputs[cmd.ipaddress] val _streamer = StreamerOutputs[cmd.ipaddress]
val _sc = db.soundchannelDB.List.find { it.ip == cmd.ipaddress } val _sc = soundchannelDB.List.find { it.ip == cmd.ipaddress }
if (_streamer == null) { if (_streamer == null) {
// belum create BarixConnection untuk ipaddress ini // belum create BarixConnection untuk ipaddress ini
@@ -297,13 +305,13 @@ fun main(args: Array<String>) {
} }
db.logDB.Add("AAS"," Application started") logDB.Add("AAS"," Application started")
// shutdown hook // shutdown hook
Runtime.getRuntime().addShutdownHook(Thread ({ Runtime.getRuntime().addShutdownHook(Thread ({
db.logDB.Add("AAS"," Application stopping") logDB.Add("AAS"," Application stopping")
Logger.info { "Shutdown hook called, stopping services..." } Logger.info { "Shutdown hook called, stopping services..." }
barixserver.StopTcpCommand() barixserver.StopTcpCommand()
androidserver.StopTcpCommand() androidserver.StopTcpCommand()

View File

@@ -7,7 +7,6 @@ import codes.Somecodes.Companion.IsNumber
import codes.Somecodes.Companion.Make_WAV_FileName import codes.Somecodes.Companion.Make_WAV_FileName
import codes.Somecodes.Companion.SoundbankResult_directory import codes.Somecodes.Companion.SoundbankResult_directory
import codes.Somecodes.Companion.ValidFile import codes.Somecodes.Companion.ValidFile
import codes.Somecodes.Companion.ValidIPV4
import codes.Somecodes.Companion.ValidString import codes.Somecodes.Companion.ValidString
import codes.Somecodes.Companion.dateformat1 import codes.Somecodes.Companion.dateformat1
import codes.Somecodes.Companion.datetimeformat1 import codes.Somecodes.Companion.datetimeformat1
@@ -20,7 +19,6 @@ import content.VoiceType
import database.data.Messagebank import database.data.Messagebank
import database.data.QueueTable import database.data.QueueTable
import database.data.Soundbank import database.data.Soundbank
import org.tinylog.Logger import org.tinylog.Logger
import java.time.DayOfWeek import java.time.DayOfWeek
import java.time.LocalDate import java.time.LocalDate
@@ -37,93 +35,7 @@ import java.time.LocalTime
*/ */
class MainExtension01 { class MainExtension01 {
data class InvalidZoneDetail(val zonename: String, val reason: String)
data class ValidZoneDetail(
val zonename: String,
val soundchanel: String,
val ip: String,
val boxid: String,
val contacts: String
)
class CheckBroadcastZoneResult {
var allvalid: Boolean = false
var message: String? = null
var validzones = mutableListOf<ValidZoneDetail>()
var invalidzones = mutableListOf<InvalidZoneDetail>()
}
/**
* Fungsi untuk cek apakah semua broadcast zone valid
* Valid berarti nama broadcast zone ada di tabel BroadcastZones, dan SoundChannel-nya ada di tabel SoundChannel, dan IP-nya valid
* @param bz List of broadcast zone (SoundChannel)
* @return CheckBroadcastZoneResult object containing allvalid flag and list of invalid zones
*/
fun AllBroadcastZonesValid(bz: List<String>): CheckBroadcastZoneResult {
val result = CheckBroadcastZoneResult()
if (bz.isNotEmpty()) {
bz.forEach { zz ->
if (ValidString(zz)) { // string tidak kosong
val findzone = db.broadcastDB.List.find {
ValidString(it.description) && ValidString(it.SoundChannel) && zz.equals(
it.description,
true
)
}
if (findzone != null) { // ketemu zona dengan deskripsi sesuai
val findsc = db.soundchannelDB.List.find {
findzone.SoundChannel.equals(
it.channel,
true
) && ValidIPV4(it.ip)
}
if (findsc != null) { // ketemu soundchannel dengan channel sesuai dan IP valid
// check apakah offline atau online
if (StreamerOutputs.containsKey(findsc.ip)) {
val bc = StreamerOutputs[findsc.ip]
if (bc != null && bc.isOnline()) {
result.validzones.add(
ValidZoneDetail(
zz,
findzone.SoundChannel,
findsc.ip,
findzone.id,
findzone.bp
)
)
} else result.invalidzones.add(
InvalidZoneDetail(
zz,
"SoundChannel ${findzone.SoundChannel} with IP ${findsc.ip} is offline"
)
)
} else result.invalidzones.add(
InvalidZoneDetail(
zz,
"SoundChannel ${findzone.SoundChannel} with IP ${findsc.ip} is not connected in StreamerOutputs"
)
)
} else result.invalidzones.add(
InvalidZoneDetail(
zz,
"SoundChannel ${findzone.SoundChannel} not found or has invalid IP in SoundChannel table"
)
)
} else result.invalidzones.add(InvalidZoneDetail(zz, "Zone $zz not found in BroadcastZones table"))
} else result.invalidzones.add(InvalidZoneDetail(zz, "Invalid broadcast zone string"))
}
if (result.validzones.size == bz.size) {
result.allvalid = true
result.message = "All requested broadcast zones are valid"
} else {
result.message = "Some requested broadcast zones are not registered in BroadcastZone table"
}
} else {
result.message = "No Broadcast Zones checked for validity"
}
return result
}
/** /**
@@ -168,7 +80,7 @@ class MainExtension01 {
var selected_voice = config.Get(configKeys.DEFAULT_VOICE_TYPE.key) var selected_voice = config.Get(configKeys.DEFAULT_VOICE_TYPE.key)
if (selected_voice.isEmpty()) selected_voice = VoiceType.VOICE_1.name if (selected_voice.isEmpty()) selected_voice = VoiceType.VOICE_1.name
languages.forEach { lang -> languages.forEach { lang ->
db.messageDB.List messageDB.List
.find { mb -> .find { mb ->
mb.ANN_ID == id.toUInt() && mb.Language.equals(lang, true) && mb.Voice_Type.equals( mb.ANN_ID == id.toUInt() && mb.Language.equals(lang, true) && mb.Voice_Type.equals(
selected_voice, selected_voice,
@@ -771,7 +683,7 @@ class MainExtension01 {
if (!ValidFile(qp.Message)) throw Exception("Invalid audio file ${qp.Message}") if (!ValidFile(qp.Message)) throw Exception("Invalid audio file ${qp.Message}")
if (qp.BroadcastZones.isEmpty()) throw Exception("Empty broadcast zones") if (qp.BroadcastZones.isEmpty()) throw Exception("Empty broadcast zones")
val zz = qp.BroadcastZones.split(";", ",").map { it.trim() }.filter { ValidString(it) } val zz = qp.BroadcastZones.split(";", ",").map { it.trim() }.filter { ValidString(it) }
AllBroadcastZonesValid(zz).let { checkresult -> broadcastDB.AllBroadcastZonesValid(zz).let { checkresult ->
if (!checkresult.allvalid) { if (!checkresult.allvalid) {
val reasons = val reasons =
checkresult.invalidzones.joinToString("; ") { iz -> "Zone '${iz.zonename}': ${iz.reason}" } checkresult.invalidzones.joinToString("; ") { iz -> "Zone '${iz.zonename}': ${iz.reason}" }
@@ -793,10 +705,10 @@ class MainExtension01 {
so.ActivateRelay(relays) so.ActivateRelay(relays)
so.SendData(afi.bytes, cbOK = { so.SendData(afi.bytes, cbOK = {
so.SetAudioFileInfo(null) so.SetAudioFileInfo(null)
db.logDB.Add("AAS", it) logDB.Add("AAS", it)
}, cbFail = { }, cbFail = {
so.SetAudioFileInfo(null) so.SetAudioFileInfo(null)
db.logDB.Add("AAS", it) logDB.Add("AAS", it)
}, cbPlaying = { isplaying -> }, cbPlaying = { isplaying ->
if (!isplaying) { if (!isplaying) {
so.ClearUsedByBroadcastZones() so.ClearUsedByBroadcastZones()
@@ -809,7 +721,7 @@ class MainExtension01 {
val logmessage = val logmessage =
"Broadcast started PAGING with Filename '${qp.Message}' to zones: ${qp.BroadcastZones}" "Broadcast started PAGING with Filename '${qp.Message}' to zones: ${qp.BroadcastZones}"
Logger.info { logmessage } Logger.info { logmessage }
db.logDB.Add("AAS", logmessage) logDB.Add("AAS", logmessage)
db.queuepagingDB.DeleteByIndex(qp.index.toInt()) db.queuepagingDB.DeleteByIndex(qp.index.toInt())
db.queuepagingDB.Resort() db.queuepagingDB.Resort()
return true return true
@@ -819,7 +731,7 @@ class MainExtension01 {
db.queuepagingDB.DeleteByIndex(qp.index.toInt()) db.queuepagingDB.DeleteByIndex(qp.index.toInt())
db.queuepagingDB.Resort() db.queuepagingDB.Resort()
val msg = "Canceled paging message $qp due to exception: ${e.message}" val msg = "Canceled paging message $qp due to exception: ${e.message}"
db.logDB.Add("AAS", msg) logDB.Add("AAS", msg)
Logger.error { msg } Logger.error { msg }
} }
return false return false
@@ -840,7 +752,7 @@ class MainExtension01 {
if (mblist.isEmpty()) throw Exception("ANN_ID $ann_id not found in Messagebank") if (mblist.isEmpty()) throw Exception("ANN_ID $ann_id not found in Messagebank")
if (qp.BroadcastZones.isEmpty()) throw Exception("Empty broadcast zones") if (qp.BroadcastZones.isEmpty()) throw Exception("Empty broadcast zones")
val zz = qp.BroadcastZones.split(";", ",").map { it.trim() }.filter { ValidString(it) } val zz = qp.BroadcastZones.split(";", ",").map { it.trim() }.filter { ValidString(it) }
AllBroadcastZonesValid(zz).let { checkresult -> broadcastDB.AllBroadcastZonesValid(zz).let { checkresult ->
if (!checkresult.allvalid) { if (!checkresult.allvalid) {
val reasons = val reasons =
checkresult.invalidzones.joinToString("; ") { iz -> "Zone '${iz.zonename}': ${iz.reason}" } checkresult.invalidzones.joinToString("; ") { iz -> "Zone '${iz.zonename}': ${iz.reason}" }
@@ -880,7 +792,7 @@ class MainExtension01 {
listafi, listafi,
targetfile, true, targetfile, true,
) )
db.logDB.Add("AAS", result.message) logDB.Add("AAS", result.message)
if (!result.success) { if (!result.success) {
throw Exception(result.message) throw Exception(result.message)
} }
@@ -899,11 +811,11 @@ class MainExtension01 {
targetafi.bytes, targetafi.bytes,
{ {
so.SetAudioFileInfo(null) so.SetAudioFileInfo(null)
db.logDB.Add("AAS", it) logDB.Add("AAS", it)
}, },
{ {
so.SetAudioFileInfo(null) so.SetAudioFileInfo(null)
db.logDB.Add("AAS", it) logDB.Add("AAS", it)
}, cbPlaying = { isplaying -> }, cbPlaying = { isplaying ->
if (!isplaying) { if (!isplaying) {
so.ClearUsedByBroadcastZones() so.ClearUsedByBroadcastZones()
@@ -916,7 +828,7 @@ class MainExtension01 {
val logmsg = val logmsg =
"Broadcast started SHALAT message with generated file '$targetfile' to zones: ${qp.BroadcastZones}" "Broadcast started SHALAT message with generated file '$targetfile' to zones: ${qp.BroadcastZones}"
Logger.info { logmsg } Logger.info { logmsg }
db.logDB.Add("AAS", logmsg) logDB.Add("AAS", logmsg)
db.queuepagingDB.DeleteByIndex(qp.index.toInt()) db.queuepagingDB.DeleteByIndex(qp.index.toInt())
db.queuepagingDB.Resort() db.queuepagingDB.Resort()
return true return true
@@ -926,7 +838,7 @@ class MainExtension01 {
db.queuepagingDB.DeleteByIndex(qp.index.toInt()) db.queuepagingDB.DeleteByIndex(qp.index.toInt())
db.queuepagingDB.Resort() db.queuepagingDB.Resort()
val msg = "Canceled shalat message $qp due to exception: ${e.message}" val msg = "Canceled shalat message $qp due to exception: ${e.message}"
db.logDB.Add("AAS", msg) logDB.Add("AAS", msg)
Logger.error { msg } Logger.error { msg }
} }
return false return false
@@ -947,7 +859,7 @@ class MainExtension01 {
if (mblist.isEmpty()) throw Exception("ANN_ID $ann_id not found in Messagebank") if (mblist.isEmpty()) throw Exception("ANN_ID $ann_id not found in Messagebank")
if (qa.BroadcastZones.isEmpty()) throw Exception("Empty broadcast zones") if (qa.BroadcastZones.isEmpty()) throw Exception("Empty broadcast zones")
val zz = qa.BroadcastZones.split(";") val zz = qa.BroadcastZones.split(";")
AllBroadcastZonesValid(zz).let { checkresult -> broadcastDB.AllBroadcastZonesValid(zz).let { checkresult ->
if (!checkresult.allvalid) { if (!checkresult.allvalid) {
val reasons = val reasons =
checkresult.invalidzones.joinToString("; ") { iz -> "Zone '${iz.zonename}': ${iz.reason}" } checkresult.invalidzones.joinToString("; ") { iz -> "Zone '${iz.zonename}': ${iz.reason}" }
@@ -997,13 +909,13 @@ class MainExtension01 {
so.SetAudioFileInfo(null) so.SetAudioFileInfo(null)
so.ClearUsedByBroadcastZones() so.ClearUsedByBroadcastZones()
so.DeactivateRelay() so.DeactivateRelay()
db.logDB.Add("AAS", it) logDB.Add("AAS", it)
}, },
{ {
so.SetAudioFileInfo(null) so.SetAudioFileInfo(null)
so.ClearUsedByBroadcastZones() so.ClearUsedByBroadcastZones()
so.DeactivateRelay() so.DeactivateRelay()
db.logDB.Add("AAS", it) logDB.Add("AAS", it)
}, cbPlaying = { isplaying -> }, cbPlaying = { isplaying ->
if (!isplaying) { if (!isplaying) {
so.ClearUsedByBroadcastZones() so.ClearUsedByBroadcastZones()
@@ -1015,7 +927,7 @@ class MainExtension01 {
val logmsg = val logmsg =
"Broadcast started TIMER message with generated file '$targetfile' to zones: ${qa.BroadcastZones}" "Broadcast started TIMER message with generated file '$targetfile' to zones: ${qa.BroadcastZones}"
Logger.info { logmsg } Logger.info { logmsg }
db.logDB.Add("AAS", logmsg) logDB.Add("AAS", logmsg)
db.queuetableDB.DeleteByIndex(qa.index.toInt()) db.queuetableDB.DeleteByIndex(qa.index.toInt())
db.queuetableDB.Resort() db.queuetableDB.Resort()
return true return true
@@ -1025,7 +937,7 @@ class MainExtension01 {
db.queuetableDB.DeleteByIndex(qa.index.toInt()) db.queuetableDB.DeleteByIndex(qa.index.toInt())
db.queuetableDB.Resort() db.queuetableDB.Resort()
val msg = "Canceled TIMER message $qa due to exception: ${e.message}" val msg = "Canceled TIMER message $qa due to exception: ${e.message}"
db.logDB.Add("AAS", msg) logDB.Add("AAS", msg)
Logger.error { msg } Logger.error { msg }
} }
return false return false
@@ -1045,7 +957,7 @@ class MainExtension01 {
if (qa.BroadcastZones.isEmpty()) throw Exception("Empty broadcast zones") if (qa.BroadcastZones.isEmpty()) throw Exception("Empty broadcast zones")
val zz = qa.BroadcastZones.split(";") val zz = qa.BroadcastZones.split(";")
AllBroadcastZonesValid(zz).let { checkresult -> broadcastDB.AllBroadcastZonesValid(zz).let { checkresult ->
if (!checkresult.allvalid) { if (!checkresult.allvalid) {
val reasons = val reasons =
checkresult.invalidzones.joinToString("; ") { iz -> "Zone '${iz.zonename}': ${iz.reason}" } checkresult.invalidzones.joinToString("; ") { iz -> "Zone '${iz.zonename}': ${iz.reason}" }
@@ -1071,7 +983,7 @@ class MainExtension01 {
// not available from variables, try to get from Message column // not available from variables, try to get from Message column
// ada ini, karena protokol FIS dulu tidak ada ANN_ID tapi pake Remark // ada ini, karena protokol FIS dulu tidak ada ANN_ID tapi pake Remark
val remark = variables?.get("REMARK").orEmpty() val remark = variables?.get("REMARK").orEmpty()
db.logDB.Add("AAS", "Trying to get ANN_ID from REMARK field: $remark") logDB.Add("AAS", "Trying to get ANN_ID from REMARK field: $remark")
Logger.info { "Trying to get ANN_ID from REMARK field: $remark" } Logger.info { "Trying to get ANN_ID from REMARK field: $remark" }
when (remark) { when (remark) {
"GOP" -> { "GOP" -> {
@@ -1099,9 +1011,9 @@ class MainExtension01 {
} }
} }
Logger.info { "Found ANN_ID from REMARK field: $ann_id" } Logger.info { "Found ANN_ID from REMARK field: $ann_id" }
db.logDB.Add("AAS", "Found ANN_ID from REMARK field: $ann_id") logDB.Add("AAS", "Found ANN_ID from REMARK field: $ann_id")
} else { } else {
db.logDB.Add("AAS", "Found ANN_ID from SB_TAGS variables: $ann_id") logDB.Add("AAS", "Found ANN_ID from SB_TAGS variables: $ann_id")
Logger.info { "Found ANN_ID from SB_TAGS variables: $ann_id" } Logger.info { "Found ANN_ID from SB_TAGS variables: $ann_id" }
} }
@@ -1152,13 +1064,13 @@ class MainExtension01 {
so.SetAudioFileInfo(null) so.SetAudioFileInfo(null)
so.ClearUsedByBroadcastZones() so.ClearUsedByBroadcastZones()
so.DeactivateRelay() so.DeactivateRelay()
db.logDB.Add("AAS", it) logDB.Add("AAS", it)
}, },
{ {
so.SetAudioFileInfo(null) so.SetAudioFileInfo(null)
so.ClearUsedByBroadcastZones() so.ClearUsedByBroadcastZones()
so.DeactivateRelay() so.DeactivateRelay()
db.logDB.Add("AAS", it) logDB.Add("AAS", it)
}, cbPlaying = { isplaying -> }, cbPlaying = { isplaying ->
if (!isplaying) { if (!isplaying) {
so.ClearUsedByBroadcastZones() so.ClearUsedByBroadcastZones()
@@ -1171,7 +1083,7 @@ class MainExtension01 {
val logmsg = val logmsg =
"Broadcast started SOUNDBANK message with generated file '$targetfile' to zones: ${qa.BroadcastZones}" "Broadcast started SOUNDBANK message with generated file '$targetfile' to zones: ${qa.BroadcastZones}"
Logger.info { logmsg } Logger.info { logmsg }
db.logDB.Add("AAS", logmsg) logDB.Add("AAS", logmsg)
db.queuetableDB.DeleteByIndex(qa.index.toInt()) db.queuetableDB.DeleteByIndex(qa.index.toInt())
db.queuetableDB.Resort() db.queuetableDB.Resort()
return true return true
@@ -1180,7 +1092,7 @@ class MainExtension01 {
} catch (e: Exception) { } catch (e: Exception) {
val msg = "Canceled SOUNDBANK message $qa due to exception: ${e.message}" val msg = "Canceled SOUNDBANK message $qa due to exception: ${e.message}"
db.logDB.Add("AAS", msg) logDB.Add("AAS", msg)
Logger.error { msg } Logger.error { msg }
db.queuetableDB.DeleteByIndex(qa.index.toInt()) db.queuetableDB.DeleteByIndex(qa.index.toInt())
db.queuetableDB.Resort() db.queuetableDB.Resort()

View File

@@ -664,6 +664,14 @@ class Somecodes {
} }
} }
/**
* Get today's date as a string in the format "dd/MM/yyyy".
* @return A string representing today's date.
*/
fun Today_to_DateString() : String {
return dateformat1.format(LocalDateTime.now())
}
/** /**
* Check if a string is a valid time in the format "hh:mm:ss". * Check if a string is a valid time in the format "hh:mm:ss".
* @param value The string to check. * @param value The string to check.
@@ -709,6 +717,21 @@ class Somecodes {
return sd?.name return sd?.name
} }
/**
* Check if a string is a valid language code.
* A valid language code is one that matches any of the Language enum values.
* @param value The string to check.
* @return True if the string is a valid language code, false otherwise.
*/
fun ValidLanguage(value: String) : Boolean{
value.split(";",",").forEach { ll ->
Language.entries.forEach { l ->
if (l.value.equals(ll,true)) return true
}
}
return false
}
/** /**
* Check if a string is a valid schedule day or a valid date. * Check if a string is a valid schedule day or a valid date.
* A valid schedule day is either one of the ScheduleDay enum names or a date in the format "dd/MM/yyyy". * A valid schedule day is either one of the ScheduleDay enum names or a date in the format "dd/MM/yyyy".

View File

@@ -15,6 +15,7 @@ import kotlinx.coroutines.Job
import kotlinx.coroutines.isActive import kotlinx.coroutines.isActive
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking import kotlinx.coroutines.runBlocking
import messageDB
import org.tinylog.Logger import org.tinylog.Logger
import tcpreceiver import tcpreceiver
import udpreceiver import udpreceiver
@@ -347,7 +348,7 @@ class TCP_Android_Command_Server {
// iterasi setiap ANN_ID // iterasi setiap ANN_ID
.forEach { annid -> .forEach { annid ->
// masukin ke VARMESSAGES yang unik secara ANN_ID dan Language // masukin ke VARMESSAGES yang unik secara ANN_ID dan Language
val xx = db.messageDB.List val xx = messageDB.List
.asSequence() .asSequence()
.filter{it.ANN_ID == annid.toUInt()} .filter{it.ANN_ID == annid.toUInt()}
.distinctBy { it.ANN_ID } .distinctBy { it.ANN_ID }
@@ -447,13 +448,13 @@ class TCP_Android_Command_Server {
VARMESSAGES.forEachIndexed { index, msg -> VARMESSAGES.forEachIndexed { index, msg ->
val ann_id = msg.ANN_ID val ann_id = msg.ANN_ID
val msg_indo = db.messageDB.List.find { val msg_indo = messageDB.List.find {
it.ANN_ID == ann_id && it.Language.equals( it.ANN_ID == ann_id && it.Language.equals(
Language.INDONESIA.name, Language.INDONESIA.name,
true true
) )
} }
val msg_eng = db.messageDB.List.find { val msg_eng = messageDB.List.find {
it.ANN_ID == ann_id && it.Language.equals( it.ANN_ID == ann_id && it.Language.equals(
Language.ENGLISH.name, Language.ENGLISH.name,
true true

View File

@@ -1,5 +1,7 @@
package content package content
import java.time.DayOfWeek
@Suppress("unused") @Suppress("unused")
enum class ScheduleDay(val day: String) { enum class ScheduleDay(val day: String) {
Sunday("Sunday"), Sunday("Sunday"),
@@ -9,5 +11,22 @@ enum class ScheduleDay(val day: String) {
Thursday("Thursday"), Thursday("Thursday"),
Friday("Friday"), Friday("Friday"),
Saturday("Saturday"), Saturday("Saturday"),
Everyday("Everyday") Everyday("Everyday");
companion object {
/**
* Converts a DayOfWeek to a ScheduleDay
*/
fun from_LocalDate_DOW(value : DayOfWeek) : ScheduleDay{
return when(value){
DayOfWeek.SUNDAY -> Sunday
DayOfWeek.MONDAY -> Monday
DayOfWeek.TUESDAY -> Tuesday
DayOfWeek.WEDNESDAY -> Wednesday
DayOfWeek.THURSDAY -> Thursday
DayOfWeek.FRIDAY -> Friday
DayOfWeek.SATURDAY -> Saturday
}}
}
} }

View File

@@ -21,34 +21,21 @@ import database.table.Table_SoundChannel
import database.table.Table_Soundbank import database.table.Table_Soundbank
import database.table.Table_Users import database.table.Table_Users
import messageDB
import broadcastDB
import logDB
import soundchannelDB
/** class MariaDB {
* A class to manage a connection to a MariaDB database.
*
* @property address The address of the MariaDB server.
* @property port The port number of the MariaDB server.
* @property dbName The name of the database to connect to.
* @property username The username for the database connection.
* @property password The password for the database connection.
*/
class MariaDB(
address: String = config.Get(configKeys.DATABASE_HOST.key),
port: Int = config.Get(configKeys.DATABASE_PORT.key).toInt(),
dbName: String = config.Get(configKeys.DATABASE_NAME.key),
username: String = config.Get(configKeys.DATABASE_USER.key),
password: String = config.Get(configKeys.DATABASE_PASSWORD.key)
) {
var connected: Boolean = false var connected: Boolean = false
lateinit var connection: Connection var connection: Connection? = null
lateinit var soundDB: Table_Soundbank lateinit var soundDB: Table_Soundbank
lateinit var messageDB: Table_Messagebank
lateinit var languageDB: Table_LanguageLink lateinit var languageDB: Table_LanguageLink
lateinit var scheduleDB: Table_Schedule lateinit var scheduleDB: Table_Schedule
lateinit var broadcastDB: Table_BroadcastZones
lateinit var queuetableDB: Table_QueueSoundbank lateinit var queuetableDB: Table_QueueSoundbank
lateinit var queuepagingDB: Table_QueuePaging lateinit var queuepagingDB: Table_QueuePaging
lateinit var soundchannelDB: Table_SoundChannel
lateinit var logDB: Table_Logs
lateinit var userDB: Table_Users lateinit var userDB: Table_Users
lateinit var logSemiAuto: Table_LogSemiAuto lateinit var logSemiAuto: Table_LogSemiAuto
@@ -79,20 +66,10 @@ class MariaDB(
} }
init { init {
try { CreateConnection()?.let { connection ->
connection = this.connection = connection
DriverManager.getConnection( Logger.info { "Connected to MariaDB successfully"}
"jdbc:mysql://$address:$port/$dbName?sslMode=REQUIRED", CreateDatabase(connection)
username,
password
) as Connection
Logger.info("Connected to MySQL" as Any)
connected = true
// create databas 'aas' if not exists
val statement = connection.createStatement()
statement.executeUpdate("CREATE DATABASE IF NOT EXISTS aas")
statement.executeUpdate("USE aas")
soundDB = Table_Soundbank(connection) soundDB = Table_Soundbank(connection)
messageDB = Table_Messagebank(connection) messageDB = Table_Messagebank(connection)
@@ -123,9 +100,10 @@ class MariaDB(
messageDB.Get() messageDB.Get()
soundDB.Get() soundDB.Get()
languageDB.Get() languageDB.Get()
scheduleDB.Get()
broadcastDB.Get() broadcastDB.Get()
soundchannelDB.Get() soundchannelDB.Get()
scheduleDB.Get()
userDB.Get() userDB.Get()
} }
} }
@@ -140,10 +118,6 @@ class MariaDB(
Logger.info { "BroadcastZones count: ${broadcastDB.List.size}" } Logger.info { "BroadcastZones count: ${broadcastDB.List.size}" }
Logger.info { "SoundChannel count: ${soundchannelDB.List.size}" } Logger.info { "SoundChannel count: ${soundchannelDB.List.size}" }
Logger.info { "User count: ${userDB.List.size}" } Logger.info { "User count: ${userDB.List.size}" }
} catch (e: Exception) {
Logger.error("Failed to connect to MariaDB: ${e.message}" as Any)
} }
} }
@@ -152,14 +126,59 @@ class MariaDB(
*/ */
fun close() { fun close() {
try { try {
connection.close() this.connection?.close()
Logger.info("Connection to MariaDB closed" as Any) Logger.info("Connection to MariaDB closed" as Any)
} catch (e: Exception) { } catch (e: Exception) {
Logger.error("Error closing MariaDB connection: ${e.message}" as Any) Logger.error("Error closing MariaDB connection: ${e.message}" as Any)
} } finally {
this.connection = null
connected = false connected = false
} }
}
/**
* Creates a new connection to the MariaDB database.
* @return A Connection object if successful, null otherwise.
*/
fun CreateConnection(): Connection? {
val address: String = config.Get(configKeys.DATABASE_HOST.key)
val port: Int = config.Get(configKeys.DATABASE_PORT.key).toInt()
val dbName: String = config.Get(configKeys.DATABASE_NAME.key)
val username: String = config.Get(configKeys.DATABASE_USER.key)
val password: String = config.Get(configKeys.DATABASE_PASSWORD.key)
connected = false
try{
val cc = DriverManager.getConnection(
"jdbc:mysql://$address:$port/$dbName?sslMode=REQUIRED",
username,
password
)
connected = true
return cc
} catch (e : Exception){
Logger.error("Failed to create connection to MariaDB: ${e.message}" as Any)
return null
}
}
/**
* Creates the database if it does not exist.
* @param connection The Connection object to use for creating the database.
* @return True if the database was created or already exists, false otherwise.
*/
fun CreateDatabase(connection: Connection) : Boolean{
try {
// create databas 'aas' if not exists
val statement = connection.createStatement()
statement.executeUpdate("CREATE DATABASE IF NOT EXISTS aas")
statement.executeUpdate("USE aas")
return true
} catch (e : Exception){
Logger.error { "Error creating database: ${e.message}" }
}
return false
}
} }

View File

@@ -6,8 +6,30 @@ import java.sql.Connection
import java.util.function.Consumer import java.util.function.Consumer
@Suppress("unused", "SqlDialectInspection", "SqlSourceToSinkFlow") @Suppress("unused", "SqlDialectInspection", "SqlSourceToSinkFlow")
abstract class dbFunctions<T>(val dbName: String, val connection: Connection, requiredcolumns: List<String>) { abstract class dbFunctions<T>(val dbName: String, conn: Connection, requiredcolumns: List<String>) {
var List : ArrayList<T> = ArrayList() var List : ArrayList<T> = ArrayList()
var connection = conn
/**
* Check if the database connection is valid
* @return true if valid, false otherwise
*/
fun IsConnected() : Boolean{
return try {
connection.isValid(2)
} catch (e: Exception) {
Logger.error("Database connection is not valid: ${e.message}" as Any)
false
}
}
/**
* Change the database connection
* @param newcon The new Connection object
*/
fun ChangeConnection(newcon: Connection){
connection = newcon
}
init{ init{
val columns = GetColumnInfo() val columns = GetColumnInfo()

View File

@@ -1,9 +1,14 @@
package database.table package database.table
import StreamerOutputs
import broadcastDB
import codes.Somecodes.Companion.ValidIPV4
import codes.Somecodes.Companion.ValidString
import database.data.BroadcastZones import database.data.BroadcastZones
import database.dbFunctions import database.dbFunctions
import org.apache.poi.xssf.usermodel.XSSFWorkbook import org.apache.poi.xssf.usermodel.XSSFWorkbook
import org.tinylog.Logger import org.tinylog.Logger
import soundchannelDB
import java.sql.Connection import java.sql.Connection
import java.util.function.Consumer import java.util.function.Consumer
@@ -200,4 +205,129 @@ class Table_BroadcastZones(connection: Connection) : dbFunctions<BroadcastZones>
.map { it.description } .map { it.description }
.sorted() .sorted()
} }
data class InvalidZoneDetail(val zonename: String, val reason: String)
data class ValidZoneDetail(
val zonename: String,
val soundchanel: String,
val ip: String,
val boxid: String,
val contacts: String
)
class CheckBroadcastZoneResult {
var allvalid: Boolean = false
var message: String? = null
var validzones = mutableListOf<ValidZoneDetail>()
var invalidzones = mutableListOf<InvalidZoneDetail>()
}
/**
* Check if all broadcast zones in a comma-separated string are valid
* Valid means the broadcast zone name exists in the BroadcastZones table, its SoundChannel exists in the SoundChannel table, and its IP is valid
* @param zones Comma-separated string of broadcast zones
* @param checkOnline Whether to check if the sound channel is really online, recorded in StreamerOutputs map
* @return true if all broadcast zones are valid, false otherwise
*/
fun AllBroadcastZonesValid(zones: String, checkOnline: Boolean = true) : Boolean{
val bzlist = zones.split(",",";").map { it.trim() }.filter { it.isNotEmpty() }
//println("Checking all broadcast zones validity for: $bzlist")
AllBroadcastZonesValid(bzlist, checkOnline).let { result ->
if (result.allvalid) {
//Logger.info("All broadcast zones are valid: ${bzlist.joinToString(", ")}" as Any)
return true
} else {
//Logger.warn("Some broadcast zones are invalid:" as Any)
result.invalidzones.forEach { iz ->
Logger.warn(" - Zone '${iz.zonename}' is invalid: ${iz.reason}" as Any)
}
return false
}
}
//return AllBroadcastZonesValid(bzlist).allvalid
}
/**
* Fungsi untuk cek apakah semua broadcast zone valid
* Valid berarti nama broadcast zone ada di tabel BroadcastZones, dan SoundChannel-nya ada di tabel SoundChannel, dan IP-nya valid
* @param bz List of broadcast zone (SoundChannel)
* @param checkOnline Whether to check if the sound channel is really online, recorded in StreamerOutputs map
* @return CheckBroadcastZoneResult object containing allvalid flag and list of invalid zones
*/
fun AllBroadcastZonesValid(bz: List<String>, checkOnline: Boolean = true): CheckBroadcastZoneResult {
val result = CheckBroadcastZoneResult()
if (bz.isNotEmpty()) {
bz.forEach { zz ->
if (ValidString(zz)) { // string tidak kosong
val findzone = List.find{
ValidString(it.description) && ValidString(it.SoundChannel) && it.description.equals(zz,true)
}
if (findzone != null) { // ketemu zona dengan deskripsi sesuai
val findsc = soundchannelDB.List.find {
findzone.SoundChannel.equals(
it.channel,
true
) && ValidIPV4(it.ip)
}
if (findsc != null) { // ketemu soundchannel dengan channel sesuai dan IP valid
// check apakah offline atau online
if (checkOnline){
if (StreamerOutputs.containsKey(findsc.ip)) {
val bc = StreamerOutputs[findsc.ip]
if (bc != null && bc.isOnline()) {
result.validzones.add(
ValidZoneDetail(
zz,
findzone.SoundChannel,
findsc.ip,
findzone.id,
findzone.bp
)
)
} else result.invalidzones.add(
InvalidZoneDetail(
zz,
"SoundChannel ${findzone.SoundChannel} with IP ${findsc.ip} is offline"
)
)
} else result.invalidzones.add(
InvalidZoneDetail(
zz,
"SoundChannel ${findzone.SoundChannel} with IP ${findsc.ip} is not connected in StreamerOutputs"
)
)
} else {
result.validzones.add(
ValidZoneDetail(
zz,
findzone.SoundChannel,
findsc.ip,
findzone.id,
findzone.bp
)
)
}
} else result.invalidzones.add(
InvalidZoneDetail(
zz,
"SoundChannel ${findzone.SoundChannel} not found or has invalid IP in SoundChannel table"
)
)
} else result.invalidzones.add(InvalidZoneDetail(zz, "Zone $zz not found in BroadcastZones table"))
} else result.invalidzones.add(InvalidZoneDetail(zz, "Invalid broadcast zone string"))
}
if (result.validzones.size == bz.size) {
result.allvalid = true
result.message = "All requested broadcast zones are valid"
} else {
result.message = "Some requested broadcast zones are not registered in BroadcastZone table"
}
} else {
result.message = "No Broadcast Zones checked for validity"
}
return result
}
} }

View File

@@ -2,10 +2,14 @@ package database.table
import database.data.Log import database.data.Log
import database.dbFunctions import database.dbFunctions
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import org.apache.poi.xssf.usermodel.XSSFWorkbook import org.apache.poi.xssf.usermodel.XSSFWorkbook
import org.tinylog.Logger import org.tinylog.Logger
import java.sql.Connection import java.sql.Connection
import java.sql.Date import java.sql.Date
import java.sql.Statement
import java.time.LocalDate import java.time.LocalDate
import java.time.format.DateTimeFormatter import java.time.format.DateTimeFormatter
import java.util.function.Consumer import java.util.function.Consumer
@@ -47,6 +51,12 @@ class Table_Logs(connection: Connection) : dbFunctions<Log>("logs", connection,l
fun GetLogForHtml(date: String, filter: String?, cbOK: Consumer<ArrayList<Log>>?, cbFail: Consumer<String>?){ fun GetLogForHtml(date: String, filter: String?, cbOK: Consumer<ArrayList<Log>>?, cbFail: Consumer<String>?){
try{ try{
var statement : Statement?
if ("alldate" == date){
if (filter.isNullOrEmpty()) throw Exception("Filter is required when date is 'alldate'")
statement = connection.prepareStatement("SELECT * FROM ${super.dbName} WHERE description LIKE ?")
statement?.setString(1, "%$filter%")
} else {
val valid_date : Date? = when{ val valid_date : Date? = when{
dateformat1.matches(date) -> { dateformat1.matches(date) -> {
Date.valueOf(LocalDate.parse(date, DateTimeFormatter.ofPattern("dd/MM/yyyy"))) Date.valueOf(LocalDate.parse(date, DateTimeFormatter.ofPattern("dd/MM/yyyy")))
@@ -64,7 +74,7 @@ class Table_Logs(connection: Connection) : dbFunctions<Log>("logs", connection,l
} }
if (valid_date!=null){ if (valid_date!=null){
// use coalescing for different datenya formats // use coalescing for different datenya formats
val statement = if (filter.isNullOrEmpty()){ statement = if (filter.isNullOrEmpty()){
connection.prepareStatement("SELECT * FROM ${super.dbName} WHERE COALESCE(STR_TO_DATE(datenya,'%d/%m/%Y'), STR_TO_DATE(datenya,'%d-%m-%Y'), STR_TO_DATE(datenya,'%Y/%m/%d'), STR_TO_DATE(datenya,'%Y-%m-%d')) = ?") connection.prepareStatement("SELECT * FROM ${super.dbName} WHERE COALESCE(STR_TO_DATE(datenya,'%d/%m/%Y'), STR_TO_DATE(datenya,'%d-%m-%Y'), STR_TO_DATE(datenya,'%Y/%m/%d'), STR_TO_DATE(datenya,'%Y-%m-%d')) = ?")
} else { } else {
connection.prepareStatement("SELECT * FROM ${super.dbName} WHERE COALESCE(STR_TO_DATE(datenya,'%d/%m/%Y'), STR_TO_DATE(datenya,'%d-%m-%Y'), STR_TO_DATE(datenya,'%Y/%m/%d'), STR_TO_DATE(datenya,'%Y-%m-%d')) = ? AND description LIKE ?") connection.prepareStatement("SELECT * FROM ${super.dbName} WHERE COALESCE(STR_TO_DATE(datenya,'%d/%m/%Y'), STR_TO_DATE(datenya,'%d-%m-%Y'), STR_TO_DATE(datenya,'%Y/%m/%d'), STR_TO_DATE(datenya,'%Y-%m-%d')) = ? AND description LIKE ?")
@@ -73,7 +83,10 @@ class Table_Logs(connection: Connection) : dbFunctions<Log>("logs", connection,l
if (!filter.isNullOrEmpty()){ if (!filter.isNullOrEmpty()){
statement?.setString(2, "%$filter%") statement?.setString(2, "%$filter%")
} }
val resultSet = statement?.executeQuery() } else throw Exception("Invalid date")
}
if (statement!=null){
val resultSet = statement.executeQuery()
val tempList = ArrayList<Log>() val tempList = ArrayList<Log>()
while (resultSet?.next() == true) { while (resultSet?.next() == true) {
val log = Log( val log = Log(
@@ -86,7 +99,7 @@ class Table_Logs(connection: Connection) : dbFunctions<Log>("logs", connection,l
tempList.add(log) tempList.add(log)
} }
cbOK?.accept(tempList) cbOK?.accept(tempList)
} else throw Exception("Invalid date") } else throw Exception("Failed to prepare statement")
} catch (e : Exception){ } catch (e : Exception){
if (filter.isNullOrEmpty()){ if (filter.isNullOrEmpty()){
cbFail?.accept("Failed to Get logs for date $date: ${e.message}") cbFail?.accept("Failed to Get logs for date $date: ${e.message}")
@@ -94,9 +107,16 @@ class Table_Logs(connection: Connection) : dbFunctions<Log>("logs", connection,l
cbFail?.accept("Failed to Get logs for date $date with filter $filter: ${e.message}") cbFail?.accept("Failed to Get logs for date $date with filter $filter: ${e.message}")
} }
} }
} }
/****
* Fetches all log entries from the database and populates the local List.
* @param cbOK Optional callback invoked upon successful retrieval.
* @param cbFail Optional callback invoked upon failure with an error message.
*/
override fun Get(cbOK: Consumer<Unit>?, cbFail: Consumer<String>?) { override fun Get(cbOK: Consumer<Unit>?, cbFail: Consumer<String>?) {
CoroutineScope(Dispatchers.IO).launch {
List.clear() List.clear()
try { try {
val statement = connection.createStatement() val statement = connection.createStatement()
@@ -119,6 +139,8 @@ class Table_Logs(connection: Connection) : dbFunctions<Log>("logs", connection,l
} }
} }
}
fun Add(machine: String, description: String): Boolean { fun Add(machine: String, description: String): Boolean {
val log = Log.NewLog(machine, description) val log = Log.NewLog(machine, description)
return Add(log) return Add(log)

View File

@@ -236,4 +236,26 @@ class Table_Messagebank(connection: Connection) : dbFunctions<Messagebank>("mess
.map { it.ANN_ID } .map { it.ANN_ID }
.sorted() .sorted()
} }
// valid messagedetail is message_name [ann_id]
// so we need regex to check if messagedetail matches that format
private val messageDetailRegex = """^(.*?)\s*\[(\d+)]$""".toRegex()
/**
* Check if a messagebank entry exists based on messagedetail and languages
* @param messagedetail the messagedetail in format "message_name [ann_id]"
* @param languages a comma or semicolon separated string of languages to check
* @return true if the messagebank entry exists for all specified languages, false otherwise
*/
fun Messagebank_Exists(messagedetail: String, languages: String) : Boolean{
val match = messageDetailRegex.find(messagedetail)
val ll = languages.split(",",";").map { it.trim() }
if (match != null){
val msg = match.groupValues[1].trim()
val annid = match.groupValues[2].toUIntOrNull() ?: return false // kalau bukan number, return false
val ff = List.filter{ it.ANN_ID == annid && it.Description == msg }
return ll.all{ lang -> ff.any{ it.Language.equals(lang, ignoreCase = true) } }
}
return false
}
} }

View File

@@ -1,6 +1,9 @@
package database.table package database.table
import codes.Somecodes.Companion.ValidLanguage
import codes.Somecodes.Companion.ValidScheduleDay import codes.Somecodes.Companion.ValidScheduleDay
import codes.Somecodes.Companion.ValidScheduleTime
import content.ScheduleDay
import database.MariaDB.Companion.ValidTime import database.MariaDB.Companion.ValidTime
import database.data.ScheduleBank import database.data.ScheduleBank
import database.dbFunctions import database.dbFunctions
@@ -9,7 +12,54 @@ import org.tinylog.Logger
import java.sql.Connection import java.sql.Connection
import java.util.function.Consumer import java.util.function.Consumer
import broadcastDB
import codes.Somecodes
import messageDB
import java.time.LocalDate
class Table_Schedule(connection: Connection) : dbFunctions<ScheduleBank>("schedulebank", connection, listOf("index", "Description", "Day", "Time", "Soundpath", "Repeat", "Enable", "BroadcastZones", "Language")) { class Table_Schedule(connection: Connection) : dbFunctions<ScheduleBank>("schedulebank", connection, listOf("index", "Description", "Day", "Time", "Soundpath", "Repeat", "Enable", "BroadcastZones", "Language")) {
/**
* A list to hold today's schedule entries.
*/
val todaySchedule = ArrayList<ScheduleBank>()
/**
* Update today's schedule
*/
fun UpdateTodaySchedule(){
todaySchedule.clear()
fun Find_Enabled_Schedules() : List<ScheduleBank>{
return List
.filter{it.Enable} // yang enabled saja
.filter{ValidScheduleTime(it.Time)} // yang timenya dalam format HH:MM
.filter{ValidLanguage(it.Language)} // yang bahasanya valid
.filter{broadcastDB.AllBroadcastZonesValid(it.BroadcastZones, false)} // yang broadcastzonesnya valid
// Soundpath ini coding typo, aslinya Messagebank description
.filter{messageDB.Messagebank_Exists(it.Soundpath, it.Language)}
}
val eligibleSchedule = Find_Enabled_Schedules()
val tempMap = mutableMapOf<String, ScheduleBank>()
// prioritas paling rendah adalah everyday
eligibleSchedule.filter { it.Day == ScheduleDay.Everyday.day }.forEach { tempMap[it.Time] = it }
// lebih tinggi adalah weekly, akan replace everyday jika time nya sama
val today_DOW = ScheduleDay.from_LocalDate_DOW(LocalDate.now().dayOfWeek)
eligibleSchedule.filter { it.Day == today_DOW.day }.forEach { tempMap[it.Time] = it }
// paling tinggi adalah specific date, akan replace yang lain jika time nya sama
val today = Somecodes.Today_to_DateString()
eligibleSchedule.filter { it.Day == today }.forEach { tempMap[it.Time] = it }
// masukin ke todaySchedule yang sudah di sort by Time
todaySchedule.addAll(tempMap.values.sortedBy { it.Time })
println("Todays schedule : $todaySchedule")
}
override fun Create() { override fun Create() {
val tabledefinition = "CREATE TABLE IF NOT EXISTS ${super.dbName} (" + val tabledefinition = "CREATE TABLE IF NOT EXISTS ${super.dbName} (" +
"`index` INT AUTO_INCREMENT PRIMARY KEY," + "`index` INT AUTO_INCREMENT PRIMARY KEY," +
@@ -44,6 +94,7 @@ class Table_Schedule(connection: Connection) : dbFunctions<ScheduleBank>("schedu
) )
List.add(schedulebank) List.add(schedulebank)
} }
UpdateTodaySchedule()
cbOK?.accept(Unit) cbOK?.accept(Unit)
} catch (e: Exception) { } catch (e: Exception) {
Logger.error("Error fetching ${super.dbName}: ${e.message}" as Any) Logger.error("Error fetching ${super.dbName}: ${e.message}" as Any)

View File

@@ -2,6 +2,7 @@ package web
import StreamerOutputs import StreamerOutputs
import barix.BarixConnection import barix.BarixConnection
import broadcastDB
import codes.Somecodes import codes.Somecodes
import codes.Somecodes.Companion.GetAppUpTime import codes.Somecodes.Companion.GetAppUpTime
import codes.Somecodes.Companion.GetSensorsInfo import codes.Somecodes.Companion.GetSensorsInfo
@@ -49,7 +50,10 @@ import google.GoogleTTS
import google.autoadd import google.autoadd
import google.fileoperation import google.fileoperation
import io.javalin.websocket.WsCloseStatus import io.javalin.websocket.WsCloseStatus
import logDB
import messageDB
import org.tinylog.Logger import org.tinylog.Logger
import soundchannelDB
import version import version
import java.io.File import java.io.File
import java.nio.ByteBuffer import java.nio.ByteBuffer
@@ -730,7 +734,7 @@ class WebApp(val listenPort: Int, var userlist: List<Pair<String, String>>, val
db.soundDB.Resort() db.soundDB.Resort()
it.result(objectmapper.writeValueAsString(resultMessage("OK"))) it.result(objectmapper.writeValueAsString(resultMessage("OK")))
db.logDB.Add("AAS", "Deleted sound bank with index $index") logDB.Add("AAS", "Deleted sound bank with index $index")
} else { } else {
it.status(500) it.status(500)
.result(objectmapper.writeValueAsString(resultMessage("Failed to delete soundbank with index $index"))) .result(objectmapper.writeValueAsString(resultMessage("Failed to delete soundbank with index $index")))
@@ -863,15 +867,15 @@ class WebApp(val listenPort: Int, var userlist: List<Pair<String, String>>, val
path("MessageBank") { path("MessageBank") {
get("List") { ctx -> get("List") { ctx ->
// get messagebank list // get messagebank list
db.messageDB.Get({ messageDB.Get({
ctx.result(MariaDB.ArrayListtoString(db.messageDB.List)) ctx.result(MariaDB.ArrayListtoString(messageDB.List))
}, { msgFail -> }, { msgFail ->
ctx.status(500).result(objectmapper.writeValueAsString(resultMessage(msgFail))) ctx.status(500).result(objectmapper.writeValueAsString(resultMessage(msgFail)))
}) })
} }
get("MessageIDs") { ctx -> get("MessageIDs") { ctx ->
val value = db.messageDB.List val value = messageDB.List
.distinctBy { it.ANN_ID } .distinctBy { it.ANN_ID }
.sortedBy { it.ANN_ID } .sortedBy { it.ANN_ID }
.map { KeyValueMessage(it.ANN_ID.toString(), it.Description) } .map { KeyValueMessage(it.ANN_ID.toString(), it.Description) }
@@ -902,10 +906,10 @@ class WebApp(val listenPort: Int, var userlist: List<Pair<String, String>>, val
message_tags message_tags
) )
val existed = val existed =
db.messageDB.List.any { it.ANN_ID == mb.ANN_ID && it.Language == mb.Language && it.Voice_Type == mb.Voice_Type } messageDB.List.any { it.ANN_ID == mb.ANN_ID && it.Language == mb.Language && it.Voice_Type == mb.Voice_Type }
if (!existed) { if (!existed) {
if (db.messageDB.Add(mb)) { if (messageDB.Add(mb)) {
db.messageDB.Resort() messageDB.Resort()
it.result(objectmapper.writeValueAsString(resultMessage("OK"))) it.result(objectmapper.writeValueAsString(resultMessage("OK")))
} else it.status(500) } else it.status(500)
.result(objectmapper.writeValueAsString(resultMessage("Failed to add messagebank to database"))) .result(objectmapper.writeValueAsString(resultMessage("Failed to add messagebank to database")))
@@ -926,8 +930,8 @@ class WebApp(val listenPort: Int, var userlist: List<Pair<String, String>>, val
} }
delete("List") { delete("List") {
// truncate messagebank table // truncate messagebank table
if (db.messageDB.Clear()) { if (messageDB.Clear()) {
db.messageDB.Get() messageDB.Get()
it.result(objectmapper.writeValueAsString(resultMessage("OK"))) it.result(objectmapper.writeValueAsString(resultMessage("OK")))
} else { } else {
it.status(500) it.status(500)
@@ -941,10 +945,10 @@ class WebApp(val listenPort: Int, var userlist: List<Pair<String, String>>, val
it.status(400) it.status(400)
.result(objectmapper.writeValueAsString(resultMessage("Invalid index"))) .result(objectmapper.writeValueAsString(resultMessage("Invalid index")))
} else { } else {
if (db.messageDB.DeleteByIndex(index.toInt())) { if (messageDB.DeleteByIndex(index.toInt())) {
db.messageDB.Resort() messageDB.Resort()
it.result(objectmapper.writeValueAsString(resultMessage("OK"))) it.result(objectmapper.writeValueAsString(resultMessage("OK")))
db.logDB.Add("AAS", "Deleted message bank with index $index") logDB.Add("AAS", "Deleted message bank with index $index")
} else { } else {
it.status(500) it.status(500)
.result(objectmapper.writeValueAsString(resultMessage("Failed to delete messagebank with index $index"))) .result(objectmapper.writeValueAsString(resultMessage("Failed to delete messagebank with index $index")))
@@ -958,7 +962,7 @@ class WebApp(val listenPort: Int, var userlist: List<Pair<String, String>>, val
it.status(400) it.status(400)
.result(objectmapper.writeValueAsString(resultMessage("Invalid index"))) .result(objectmapper.writeValueAsString(resultMessage("Invalid index")))
} else { } else {
val mb = db.messageDB.List.find { xx -> xx.index == index } val mb = messageDB.List.find { xx -> xx.index == index }
if (mb == null) { if (mb == null) {
it.status(404) it.status(404)
.result(objectmapper.writeValueAsString(resultMessage("Messagebank with index $index not found"))) .result(objectmapper.writeValueAsString(resultMessage("Messagebank with index $index not found")))
@@ -1007,8 +1011,8 @@ class WebApp(val listenPort: Int, var userlist: List<Pair<String, String>>, val
changed = true changed = true
} }
if (changed) { if (changed) {
if (db.messageDB.UpdateByIndex(index.toInt(), mb)) { if (messageDB.UpdateByIndex(index.toInt(), mb)) {
db.messageDB.Resort() messageDB.Resort()
it.result(objectmapper.writeValueAsString(resultMessage("OK"))) it.result(objectmapper.writeValueAsString(resultMessage("OK")))
} else it.status(500) } else it.status(500)
.result(objectmapper.writeValueAsString(resultMessage("Failed to update messagebank with index $index"))) .result(objectmapper.writeValueAsString(resultMessage("Failed to update messagebank with index $index")))
@@ -1019,7 +1023,7 @@ class WebApp(val listenPort: Int, var userlist: List<Pair<String, String>>, val
} }
} }
get("ExportXLSX") { get("ExportXLSX") {
val xlsxdata = db.messageDB.Export_XLSX() val xlsxdata = messageDB.Export_XLSX()
if (xlsxdata != null) { if (xlsxdata != null) {
it.header( it.header(
"Content-Type", "Content-Type",
@@ -1043,8 +1047,8 @@ class WebApp(val listenPort: Int, var userlist: List<Pair<String, String>>, val
} }
try { try {
val xlsx = XSSFWorkbook(uploaded.content()) val xlsx = XSSFWorkbook(uploaded.content())
if (db.messageDB.Import_XLSX(xlsx)) { if (messageDB.Import_XLSX(xlsx)) {
db.messageDB.Resort() messageDB.Resort()
it.result(objectmapper.writeValueAsString(resultMessage("OK"))) it.result(objectmapper.writeValueAsString(resultMessage("OK")))
} else { } else {
it.status(500) it.status(500)
@@ -1133,7 +1137,7 @@ class WebApp(val listenPort: Int, var userlist: List<Pair<String, String>>, val
if (db.languageDB.DeleteByIndex(index.toInt())) { if (db.languageDB.DeleteByIndex(index.toInt())) {
db.languageDB.Resort() db.languageDB.Resort()
it.result(objectmapper.writeValueAsString(resultMessage("OK"))) it.result(objectmapper.writeValueAsString(resultMessage("OK")))
db.logDB.Add("AAS", "Deleted language link with index $index") logDB.Add("AAS", "Deleted language link with index $index")
} else { } else {
it.status(500) it.status(500)
.result(objectmapper.writeValueAsString(resultMessage("Failed to delete language link with index $index"))) .result(objectmapper.writeValueAsString(resultMessage("Failed to delete language link with index $index")))
@@ -1219,11 +1223,14 @@ class WebApp(val listenPort: Int, var userlist: List<Pair<String, String>>, val
} }
} }
path("ScheduleBank") { path("ScheduleBank") {
get("TodaySchedule"){ ctx ->
ctx.json(db.scheduleDB.todaySchedule)
}
get("List") { ctx -> get("List") { ctx ->
db.scheduleDB.Get({ db.scheduleDB.Get({
// get timer list // get timer list
ctx.result(MariaDB.ArrayListtoString(db.scheduleDB.List)) ctx.json(db.scheduleDB.List)
}, { msgFail -> }, { msgFail ->
ctx.status(500).result(objectmapper.writeValueAsString(resultMessage(msgFail))) ctx.status(500).result(objectmapper.writeValueAsString(resultMessage(msgFail)))
}) })
@@ -1257,7 +1264,7 @@ class WebApp(val listenPort: Int, var userlist: List<Pair<String, String>>, val
if (ValidString(broadcast_zones)) { if (ValidString(broadcast_zones)) {
val zones = broadcast_zones.split(";") val zones = broadcast_zones.split(";")
if (zones.all { zz -> if (zones.all { zz ->
db.broadcastDB.List.any { xx -> broadcastDB.List.any { xx ->
xx.description.equals( xx.description.equals(
zz, zz,
true true
@@ -1318,7 +1325,7 @@ class WebApp(val listenPort: Int, var userlist: List<Pair<String, String>>, val
if (db.scheduleDB.DeleteByIndex(index.toInt())) { if (db.scheduleDB.DeleteByIndex(index.toInt())) {
db.scheduleDB.Resort() db.scheduleDB.Resort()
it.result(objectmapper.writeValueAsString(resultMessage("OK"))) it.result(objectmapper.writeValueAsString(resultMessage("OK")))
db.logDB.Add("AAS", "Deleted schedule bank with index $index") logDB.Add("AAS", "Deleted schedule bank with index $index")
} else { } else {
it.status(500) it.status(500)
.result(objectmapper.writeValueAsString(resultMessage("Failed to delete schedule with index $index"))) .result(objectmapper.writeValueAsString(resultMessage("Failed to delete schedule with index $index")))
@@ -1407,21 +1414,21 @@ class WebApp(val listenPort: Int, var userlist: List<Pair<String, String>>, val
} }
get("GetMessageAndBroadcastZones") { get("GetMessageAndBroadcastZones") {
val result = object { val result = object {
val messages = db.messageDB.List val messages = messageDB.List
.filter { mb -> .filter { mb ->
!mb.Message_Detail.contains("[") && !mb.Message_Detail.contains( !mb.Message_Detail.contains("[") && !mb.Message_Detail.contains(
"]" "]"
) )
} }
.map { mb -> "${mb.Description} [${mb.ANN_ID}]" } .map { mb -> "${mb.Description} [${mb.ANN_ID}]" }
val broadcastzones = db.broadcastDB.List val broadcastzones = broadcastDB.List
} }
it.result(objectmapper.writeValueAsString(result)) it.result(objectmapper.writeValueAsString(result))
} }
// Kirim list language dari Messagebank berdasarkan ANN_ID // Kirim list language dari Messagebank berdasarkan ANN_ID
get("GetLanguageList/{ANN_ID}") { get1 -> get("GetLanguageList/{ANN_ID}") { get1 ->
val langlist = db.messageDB.List val langlist = messageDB.List
.filter { it.ANN_ID == get1.pathParam("ANN_ID").toInt().toUInt() } .filter { it.ANN_ID == get1.pathParam("ANN_ID").toInt().toUInt() }
.map { it.Language }.distinct() .map { it.Language }.distinct()
get1.result(objectmapper.writeValueAsString(langlist)) get1.result(objectmapper.writeValueAsString(langlist))
@@ -1525,7 +1532,7 @@ class WebApp(val listenPort: Int, var userlist: List<Pair<String, String>>, val
.map { it.trim() } .map { it.trim() }
.filter { it.isNotEmpty() }.distinct() .filter { it.isNotEmpty() }.distinct()
.mapNotNull { it.toUIntOrNull() } .mapNotNull { it.toUIntOrNull() }
val mbankids = db.messageDB.Get_MessageID_List() val mbankids = messageDB.Get_MessageID_List()
if (!mbids.all { id -> mbankids.any { it == id } }) { if (!mbids.all { id -> mbankids.any { it == id } }) {
ctx.status(400) ctx.status(400)
.result(objectmapper.writeValueAsString(resultMessage("Some ANN_ID not found in Messagebank"))) .result(objectmapper.writeValueAsString(resultMessage("Some ANN_ID not found in Messagebank")))
@@ -1537,7 +1544,7 @@ class WebApp(val listenPort: Int, var userlist: List<Pair<String, String>>, val
val bzdesc = val bzdesc =
broadcastzones.split(";").map { it.trim() } broadcastzones.split(";").map { it.trim() }
.filter { it.isNotEmpty() }.distinct() .filter { it.isNotEmpty() }.distinct()
val bzlist = db.broadcastDB.Get_BroadcastZone_List() val bzlist = broadcastDB.Get_BroadcastZone_List()
val missing_broadcastzones = ArrayList<String>() val missing_broadcastzones = ArrayList<String>()
bzdesc.forEach { bz -> bzdesc.forEach { bz ->
if (!bzlist.any { it.equals(bz, true) }) { if (!bzlist.any { it.equals(bz, true) }) {
@@ -1594,7 +1601,7 @@ class WebApp(val listenPort: Int, var userlist: List<Pair<String, String>>, val
if (db.userDB.DeleteByIndex(index.toInt())) { if (db.userDB.DeleteByIndex(index.toInt())) {
db.userDB.Resort() db.userDB.Resort()
it.result(objectmapper.writeValueAsString(resultMessage("OK"))) it.result(objectmapper.writeValueAsString(resultMessage("OK")))
db.logDB.Add("AAS", "Deleted user with index $index") logDB.Add("AAS", "Deleted user with index $index")
} else it.status(500) } else it.status(500)
.result(objectmapper.writeValueAsString(resultMessage("Failed to delete user with index $index"))) .result(objectmapper.writeValueAsString(resultMessage("Failed to delete user with index $index")))
} }
@@ -1700,7 +1707,7 @@ class WebApp(val listenPort: Int, var userlist: List<Pair<String, String>>, val
.map { it.trim() } .map { it.trim() }
.filter { it.isNotEmpty() }.distinct() .filter { it.isNotEmpty() }.distinct()
.mapNotNull { it.toUIntOrNull() } .mapNotNull { it.toUIntOrNull() }
val mbankids = db.messageDB.Get_MessageID_List() val mbankids = messageDB.Get_MessageID_List()
val missing_broadcastids = ArrayList<UInt>() val missing_broadcastids = ArrayList<UInt>()
mbids.forEach { mbid -> mbids.forEach { mbid ->
if (!mbankids.any { it == mbid }) { if (!mbankids.any { it == mbid }) {
@@ -1727,7 +1734,7 @@ class WebApp(val listenPort: Int, var userlist: List<Pair<String, String>>, val
val bzdesc = _broadcastzones.split(";").map { it.trim() } val bzdesc = _broadcastzones.split(";").map { it.trim() }
.filter { it.isNotEmpty() }.distinct() .filter { it.isNotEmpty() }.distinct()
val bzlist = db.broadcastDB.Get_BroadcastZone_List() val bzlist = broadcastDB.Get_BroadcastZone_List()
val missing_broadcastzones = ArrayList<String>() val missing_broadcastzones = ArrayList<String>()
bzdesc.forEach { bz -> bzdesc.forEach { bz ->
if (!bzlist.any { it.equals(bz, true) }) { if (!bzlist.any { it.equals(bz, true) }) {
@@ -1832,8 +1839,8 @@ class WebApp(val listenPort: Int, var userlist: List<Pair<String, String>>, val
get("GetMessageAndBroadcastZones") { get("GetMessageAndBroadcastZones") {
val result = object { val result = object {
val messages = db.messageDB.List val messages = messageDB.List
val broadcastzones = db.broadcastDB.List val broadcastzones = broadcastDB.List
} }
it.result(objectmapper.writeValueAsString(result)) it.result(objectmapper.writeValueAsString(result))
} }
@@ -1842,8 +1849,10 @@ class WebApp(val listenPort: Int, var userlist: List<Pair<String, String>>, val
get("List") { get1 -> get("List") { get1 ->
val logdate = get1.queryParam("date") ?: "" val logdate = get1.queryParam("date") ?: ""
val logfilter = get1.queryParam("filter") val logfilter = get1.queryParam("filter")
db.logDB.GetLogForHtml(logdate, logfilter, { loglist -> Logger.info{"Client ${get1.ip()} requested log list for date $logdate with filter $logfilter"}
get1.result(objectmapper.writeValueAsString(loglist)) logDB.GetLogForHtml(logdate, logfilter, { loglist ->
get1.contentType("application/json")
get1.json(loglist)
}, { msgFail -> }, { msgFail ->
get1.status(500).result(objectmapper.writeValueAsString(resultMessage(msgFail))) get1.status(500).result(objectmapper.writeValueAsString(resultMessage(msgFail)))
}) })
@@ -1853,9 +1862,9 @@ class WebApp(val listenPort: Int, var userlist: List<Pair<String, String>>, val
val logfilter = get1.queryParam("filter") ?: "" val logfilter = get1.queryParam("filter") ?: ""
if (ValiDateForLogHtml(logdate)) { if (ValiDateForLogHtml(logdate)) {
val xlsxdata = if (ValidString(logfilter)) { val xlsxdata = if (ValidString(logfilter)) {
db.logDB.Export_Log_XLSX(logdate.replace('-', '/'), logfilter) logDB.Export_Log_XLSX(logdate.replace('-', '/'), logfilter)
} else { } else {
db.logDB.Export_Log_XLSX(logdate.replace('-', '/'), "") logDB.Export_Log_XLSX(logdate.replace('-', '/'), "")
} }
if (xlsxdata != null) { if (xlsxdata != null) {
get1.header( get1.header(
@@ -1876,22 +1885,22 @@ class WebApp(val listenPort: Int, var userlist: List<Pair<String, String>>, val
} }
path("BroadcastZones") { path("BroadcastZones") {
get("List") { ctx -> get("List") { ctx ->
db.broadcastDB.Get({ broadcastDB.Get({
ctx.result(MariaDB.ArrayListtoString(db.broadcastDB.List)) ctx.json(broadcastDB.List)
}, { msgFail -> }, { msgFail ->
ctx.status(500).result(objectmapper.writeValueAsString(resultMessage(msgFail))) ctx.status(500).result(objectmapper.writeValueAsString(resultMessage(msgFail)))
}) })
} }
get("BroadcastZoneDescriptions") { ctx -> get("BroadcastZoneDescriptions") { ctx ->
val value = db.broadcastDB.List val value = broadcastDB.List
.distinctBy { it.description } .distinctBy { it.description }
.map { it.description } .map { it.description }
ctx.result(objectmapper.writeValueAsString(value)) ctx.result(objectmapper.writeValueAsString(value))
} }
delete("List") { delete("List") {
// truncate broadcast zones table // truncate broadcast zones table
if (db.broadcastDB.Clear()) { if (broadcastDB.Clear()) {
db.broadcastDB.Get() broadcastDB.Get()
it.result(objectmapper.writeValueAsString(resultMessage("OK"))) it.result(objectmapper.writeValueAsString(resultMessage("OK")))
} else { } else {
it.status(500) it.status(500)
@@ -1910,8 +1919,8 @@ class WebApp(val listenPort: Int, var userlist: List<Pair<String, String>>, val
if (ValidString(_relay)) { if (ValidString(_relay)) {
val newbp = val newbp =
BroadcastZones(0u, _description, _soundchannel, _box, _relay) BroadcastZones(0u, _description, _soundchannel, _box, _relay)
if (db.broadcastDB.Add(newbp)) { if (broadcastDB.Add(newbp)) {
db.broadcastDB.Resort() broadcastDB.Resort()
it.result(objectmapper.writeValueAsString(resultMessage("OK"))) it.result(objectmapper.writeValueAsString(resultMessage("OK")))
} else it.status(500) } else it.status(500)
.result(objectmapper.writeValueAsString(resultMessage("Failed to add broadcast zone to database"))) .result(objectmapper.writeValueAsString(resultMessage("Failed to add broadcast zone to database")))
@@ -1931,10 +1940,10 @@ class WebApp(val listenPort: Int, var userlist: List<Pair<String, String>>, val
it.status(400) it.status(400)
.result(objectmapper.writeValueAsString(resultMessage("Invalid index"))) .result(objectmapper.writeValueAsString(resultMessage("Invalid index")))
} else { } else {
if (db.broadcastDB.DeleteByIndex(index.toInt())) { if (broadcastDB.DeleteByIndex(index.toInt())) {
db.broadcastDB.Resort() broadcastDB.Resort()
it.result(objectmapper.writeValueAsString(resultMessage("OK"))) it.result(objectmapper.writeValueAsString(resultMessage("OK")))
db.logDB.Add("AAS", "Deleted broadcast zone with index $index") logDB.Add("AAS", "Deleted broadcast zone with index $index")
} else { } else {
it.status(500) it.status(500)
.result(objectmapper.writeValueAsString(resultMessage("Failed to delete broadcast zone with index $index"))) .result(objectmapper.writeValueAsString(resultMessage("Failed to delete broadcast zone with index $index")))
@@ -1948,7 +1957,7 @@ class WebApp(val listenPort: Int, var userlist: List<Pair<String, String>>, val
it.status(400) it.status(400)
.result(objectmapper.writeValueAsString(resultMessage("Invalid index"))) .result(objectmapper.writeValueAsString(resultMessage("Invalid index")))
} else { } else {
val bz = db.broadcastDB.List.find { xx -> xx.index == index } val bz = broadcastDB.List.find { xx -> xx.index == index }
if (bz == null) { if (bz == null) {
it.status(404) it.status(404)
.result(objectmapper.writeValueAsString(resultMessage("Broadcast zone with index $index not found"))) .result(objectmapper.writeValueAsString(resultMessage("Broadcast zone with index $index not found")))
@@ -1980,8 +1989,8 @@ class WebApp(val listenPort: Int, var userlist: List<Pair<String, String>>, val
changed = true changed = true
} }
if (changed) { if (changed) {
if (db.broadcastDB.UpdateByIndex(index.toInt(), bz)) { if (broadcastDB.UpdateByIndex(index.toInt(), bz)) {
db.broadcastDB.Resort() broadcastDB.Resort()
it.result(objectmapper.writeValueAsString(resultMessage("OK"))) it.result(objectmapper.writeValueAsString(resultMessage("OK")))
} else it.status(500) } else it.status(500)
.result(objectmapper.writeValueAsString(resultMessage("Failed to update broadcast zone with index $index"))) .result(objectmapper.writeValueAsString(resultMessage("Failed to update broadcast zone with index $index")))
@@ -1993,7 +2002,7 @@ class WebApp(val listenPort: Int, var userlist: List<Pair<String, String>>, val
} }
get("ExportXLSX") { get("ExportXLSX") {
val xlsxdata = db.broadcastDB.Export_XLSX() val xlsxdata = broadcastDB.Export_XLSX()
if (xlsxdata != null) { if (xlsxdata != null) {
it.header( it.header(
"Content-Type", "Content-Type",
@@ -2017,8 +2026,8 @@ class WebApp(val listenPort: Int, var userlist: List<Pair<String, String>>, val
} }
try { try {
val xlsx = XSSFWorkbook(uploaded.content()) val xlsx = XSSFWorkbook(uploaded.content())
if (db.broadcastDB.Import_XLSX(xlsx)) { if (broadcastDB.Import_XLSX(xlsx)) {
db.broadcastDB.Resort() broadcastDB.Resort()
it.result(objectmapper.writeValueAsString(resultMessage("OK"))) it.result(objectmapper.writeValueAsString(resultMessage("OK")))
} else { } else {
it.status(500) it.status(500)
@@ -2033,20 +2042,20 @@ class WebApp(val listenPort: Int, var userlist: List<Pair<String, String>>, val
} }
path("SoundChannel") { path("SoundChannel") {
get("List") { ctx -> get("List") { ctx ->
db.soundchannelDB.Get({ soundchannelDB.Get({
ctx.result(MariaDB.ArrayListtoString(db.soundchannelDB.List)) ctx.json(soundchannelDB.List)
}, { msgFail -> }, { msgFail ->
ctx.status(500).result(objectmapper.writeValueAsString(resultMessage(msgFail))) ctx.status(500).result(objectmapper.writeValueAsString(resultMessage(msgFail)))
}) })
} }
get("SoundChannelDescriptions") { get("SoundChannelDescriptions") {
it.result(objectmapper.writeValueAsString(db.soundchannelDB.Get_SoundChannel_List())) it.result(objectmapper.writeValueAsString(soundchannelDB.Get_SoundChannel_List()))
} }
delete("List") { delete("List") {
// truncate sound channel table // truncate sound channel table
if (db.soundchannelDB.Clear()) { if (soundchannelDB.Clear()) {
db.soundchannelDB.Get() soundchannelDB.Get()
it.result(objectmapper.writeValueAsString(resultMessage("OK"))) it.result(objectmapper.writeValueAsString(resultMessage("OK")))
} else { } else {
it.status(500) it.status(500)
@@ -2060,7 +2069,7 @@ class WebApp(val listenPort: Int, var userlist: List<Pair<String, String>>, val
it.status(400) it.status(400)
.result(objectmapper.writeValueAsString(resultMessage("Invalid index"))) .result(objectmapper.writeValueAsString(resultMessage("Invalid index")))
} else { } else {
val sc = db.soundchannelDB.List.find { xx -> xx.index == index } val sc = soundchannelDB.List.find { xx -> xx.index == index }
if (sc == null) { if (sc == null) {
it.status(404) it.status(404)
.result(objectmapper.writeValueAsString(resultMessage("Sound channel with index $index not found"))) .result(objectmapper.writeValueAsString(resultMessage("Sound channel with index $index not found")))
@@ -2082,7 +2091,7 @@ class WebApp(val listenPort: Int, var userlist: List<Pair<String, String>>, val
// cek apakah ada soundchannel lain yang pakai ip dan channel yang sama // cek apakah ada soundchannel lain yang pakai ip dan channel yang sama
val othersc = val othersc =
db.soundchannelDB.List.filter { sc -> sc.ip == _ip } soundchannelDB.List.filter { sc -> sc.ip == _ip }
.filter { sc -> sc.index != index } .filter { sc -> sc.index != index }
if (othersc.isNotEmpty()) { if (othersc.isNotEmpty()) {
it.status(400) it.status(400)
@@ -2090,8 +2099,8 @@ class WebApp(val listenPort: Int, var userlist: List<Pair<String, String>>, val
} else { } else {
// ada sesuatu yang ganti // ada sesuatu yang ganti
val newsc = SoundChannel(0u, _channel, _ip) val newsc = SoundChannel(0u, _channel, _ip)
if (db.soundchannelDB.UpdateByIndex(index.toInt(), newsc)) { if (soundchannelDB.UpdateByIndex(index.toInt(), newsc)) {
db.soundchannelDB.Resort() soundchannelDB.Resort()
it.result( it.result(
objectmapper.writeValueAsString( objectmapper.writeValueAsString(
resultMessage( resultMessage(
@@ -2128,7 +2137,7 @@ class WebApp(val listenPort: Int, var userlist: List<Pair<String, String>>, val
} }
get("ExportXLSX") { get("ExportXLSX") {
val xlsxdata = db.soundchannelDB.Export_XLSX() val xlsxdata = soundchannelDB.Export_XLSX()
if (xlsxdata != null) { if (xlsxdata != null) {
it.header( it.header(
"Content-Type", "Content-Type",
@@ -2152,8 +2161,8 @@ class WebApp(val listenPort: Int, var userlist: List<Pair<String, String>>, val
} }
try { try {
val xlsx = XSSFWorkbook(uploaded.content()) val xlsx = XSSFWorkbook(uploaded.content())
if (db.soundchannelDB.Import_XLSX(xlsx)) { if (soundchannelDB.Import_XLSX(xlsx)) {
db.soundchannelDB.Resort() soundchannelDB.Resort()
it.result(objectmapper.writeValueAsString(resultMessage("OK"))) it.result(objectmapper.writeValueAsString(resultMessage("OK")))
} else { } else {
it.status(500) it.status(500)
@@ -2169,7 +2178,7 @@ class WebApp(val listenPort: Int, var userlist: List<Pair<String, String>>, val
path("QueuePaging") { path("QueuePaging") {
get("List") { ctx -> get("List") { ctx ->
db.queuepagingDB.Get({ db.queuepagingDB.Get({
ctx.result(MariaDB.ArrayListtoString(db.queuepagingDB.List)) ctx.json(db.queuepagingDB.List)
}, { msgFail -> }, { msgFail ->
ctx.status(500).result(objectmapper.writeValueAsString(resultMessage(msgFail))) ctx.status(500).result(objectmapper.writeValueAsString(resultMessage(msgFail)))
}) })
@@ -2195,7 +2204,7 @@ class WebApp(val listenPort: Int, var userlist: List<Pair<String, String>>, val
if (db.queuepagingDB.DeleteByIndex(index.toInt())) { if (db.queuepagingDB.DeleteByIndex(index.toInt())) {
db.queuepagingDB.Resort() db.queuepagingDB.Resort()
it.result(objectmapper.writeValueAsString(resultMessage("OK"))) it.result(objectmapper.writeValueAsString(resultMessage("OK")))
db.logDB.Add("AAS", "Deleted queue paging with index $index") logDB.Add("AAS", "Deleted queue paging with index $index")
} else { } else {
it.status(500) it.status(500)
.result(objectmapper.writeValueAsString(resultMessage("Failed to delete queue paging with index $index"))) .result(objectmapper.writeValueAsString(resultMessage("Failed to delete queue paging with index $index")))
@@ -2207,7 +2216,7 @@ class WebApp(val listenPort: Int, var userlist: List<Pair<String, String>>, val
path("QueueTable") { path("QueueTable") {
get("List") { ctx -> get("List") { ctx ->
db.queuetableDB.Get({ db.queuetableDB.Get({
ctx.result(MariaDB.ArrayListtoString(db.queuetableDB.List)) ctx.json(db.queuetableDB.List)
}, { msgFail -> }, { msgFail ->
ctx.status(500).result(objectmapper.writeValueAsString(resultMessage(msgFail))) ctx.status(500).result(objectmapper.writeValueAsString(resultMessage(msgFail)))
}) })
@@ -2233,7 +2242,7 @@ class WebApp(val listenPort: Int, var userlist: List<Pair<String, String>>, val
if (db.queuetableDB.DeleteByIndex(index.toInt())) { if (db.queuetableDB.DeleteByIndex(index.toInt())) {
db.queuetableDB.Resort() db.queuetableDB.Resort()
it.result(objectmapper.writeValueAsString(resultMessage("OK"))) it.result(objectmapper.writeValueAsString(resultMessage("OK")))
db.logDB.Add("AAS", "Deleted queue sound with index $index") logDB.Add("AAS", "Deleted queue sound with index $index")
} else { } else {
it.status(500) it.status(500)
@@ -2521,7 +2530,7 @@ class WebApp(val listenPort: Int, var userlist: List<Pair<String, String>>, val
_config.Set(configKeys.DEFAULT_VOICE_TYPE.key, defaultvoice) _config.Set(configKeys.DEFAULT_VOICE_TYPE.key, defaultvoice)
_config.Save() _config.Save()
Logger.info { "Changed FIS Codes" } Logger.info { "Changed FIS Codes" }
db.logDB.Add( logDB.Add(
"AAS", "AAS",
"Save FIS Codes Message: GOP=$_gop, GBD=$_gbd, GFC=$_gfc, FLD=$_fld, DefaultVoice=$defaultvoice" "Save FIS Codes Message: GOP=$_gop, GBD=$_gbd, GFC=$_gfc, FLD=$_fld, DefaultVoice=$defaultvoice"
) )
@@ -2636,7 +2645,7 @@ class WebApp(val listenPort: Int, var userlist: List<Pair<String, String>>, val
// messages // messages
String_To_List(user.messagebank_ann_id).forEach { msg -> String_To_List(user.messagebank_ann_id).forEach { msg ->
//println("Looking for message ANN_ID: $msg") //println("Looking for message ANN_ID: $msg")
db.messageDB.List.filter { it.ANN_ID == msg.toUInt() }.forEach { xx -> messageDB.List.filter { it.ANN_ID == msg.toUInt() }.forEach { xx ->
//println("Adding message: ${xx.ANN_ID};${xx.Description};${xx.Language};${xx.Message_Detail}") //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}") result.messages.add("${xx.ANN_ID};${xx.Description};${xx.Language};${xx.Message_Detail}")
} }
@@ -2755,9 +2764,9 @@ class WebApp(val listenPort: Int, var userlist: List<Pair<String, String>>, val
val logfilter = get1.queryParam("filter") ?: "" val logfilter = get1.queryParam("filter") ?: ""
if (ValiDateForLogHtml(logdate)) { if (ValiDateForLogHtml(logdate)) {
val xlsxdata = if (ValidString(logfilter)) { val xlsxdata = if (ValidString(logfilter)) {
db.logDB.Export_Log_XLSX(logdate.replace('-', '/'), logfilter) logDB.Export_Log_XLSX(logdate.replace('-', '/'), logfilter)
} else { } else {
db.logDB.Export_Log_XLSX(logdate.replace('-', '/'), "") logDB.Export_Log_XLSX(logdate.replace('-', '/'), "")
} }
if (xlsxdata != null) { if (xlsxdata != null) {
get1.header( get1.header(
@@ -2780,7 +2789,7 @@ class WebApp(val listenPort: Int, var userlist: List<Pair<String, String>>, val
val datelog = ctx.pathParam("datelog") val datelog = ctx.pathParam("datelog")
println("Request log for date: $datelog") println("Request log for date: $datelog")
db.logSemiAuto.GetLogSemiAutoForHtml(datelog, null, { db.logSemiAuto.GetLogSemiAutoForHtml(datelog, null, {
ctx.result(MariaDB.ArrayListtoString(it)) ctx.json(it)
}, { err -> }, { err ->
ctx.status(500).result(objectmapper.writeValueAsString(resultMessage(err))) ctx.status(500).result(objectmapper.writeValueAsString(resultMessage(err)))
}) })
@@ -2829,8 +2838,8 @@ class WebApp(val listenPort: Int, var userlist: List<Pair<String, String>>, val
fun Get_Barix_Connection_by_ZoneName(zonename: String): BarixConnection? { fun Get_Barix_Connection_by_ZoneName(zonename: String): BarixConnection? {
if (ValidString(zonename)) { if (ValidString(zonename)) {
val bz = db.broadcastDB.List.find { it.description == zonename } val bz = broadcastDB.List.find { it.description == zonename }
val sc = if (bz != null) db.soundchannelDB.List.find { it.channel == bz.SoundChannel } else null val sc = if (bz != null) soundchannelDB.List.find { it.channel == bz.SoundChannel } else null
val ip = sc?.ip ?: "" val ip = sc?.ip ?: ""
if (ValidIPV4(ip)) { if (ValidIPV4(ip)) {
// ketemu ip-nya // ketemu ip-nya