* Sun Jun 15 2025 Brian Read <brianr@koozali.org> 11.0.0-92.sme

- rework datetime panel [SME: 13020]
- Fix errors in error messages for local networks panel [SME: 13044]
- Add in Config Db open in Proxy.pm needed after  UTF8 change [SME: 13046]
This commit is contained in:
Brian Read 2025-06-18 11:17:51 +01:00
parent 0733537064
commit d1f2013375
11 changed files with 850 additions and 490 deletions

View File

@ -37,7 +37,7 @@ use esmith::NavigationDB; # no UTF8 raw is ok for ASCII only flat file
use SrvMngr_Auth qw(check_admin_access);
#this is overwrittrn with the "release" by the spec file - release can be "99.el8.sme"
our $VERSION = '78.el8.sme';
our $VERSION = '91.el8.sme';
#Extract the release value
if ($VERSION =~ /^(\d+)/) {
$VERSION = $1; # $1 contains the matched numeric digits
@ -325,8 +325,8 @@ sub setup_routing {
$if_admin->get('/clamav')->to('clamav#main')->name('clamav');
$if_admin->post('/clamav')->to('clamav#do_update')->name('clamav2');
$if_admin->get('/datetime')->to('datetime#main')->name('datetime');
$if_admin->post('/datetime')->to('datetime#do_update')->name('datetime2');
#$if_admin->get('/datetime')->to('datetime#main')->name('datetime');
#$if_admin->post('/datetime')->to('datetime#do_update')->name('datetime2');
$if_admin->get('/directory')->to('directory#main')->name('directory');
$if_admin->post('/directory')->to('directory#do_update')->name('directory2');

View File

@ -0,0 +1,383 @@
#
# Generated by SM2Gen version:0.9(20Jan2025) Chameleon version:4.5.4 On Python:3.12.3 at 2025-06-15 12:45:47
#
#
# Routines to be edited by the developer to provide content and validation for parameters
# and provison of the control data for table(s)
#
use esmith::util;
use esmith::util::network;
use esmith::ConfigDB::UTF8;
use esmith::AccountsDB;
use esmith::NetworksDB::UTF8;
use esmith::HostsDB;
use esmith::DomainsDB::UTF8;
use constant FALSE => 0;
use constant TRUE => 1;
#The most common ones - open DB when required.
my $cdb;
my $adb;
my $ndb;
my $hdb;
my $ddb;
#The most common ones - you might want to use these if you need to make sure that the DB is refreshed.
#$cdb = esmith::ConfigDB::UTF8->open() || die("Couldn't open config db");
#$adb = esmith::AccountsDB->open() || die("Couldn't open Accounts db");
#$ndb = esmith::NetworksDB->open() || die("Couldn't open Network db");
#$hdb = esmith::HostsDB::UTF8->open() || die("Couldn't open Hosts db");
#$ddb = esmith::DomainsDB::UTF8->open() || die("Couldn't open Domains db");
# Validation routines - parameters for each panel
sub validate_PARAMS {
my $c = shift;
my $dat_data = shift; #Data hash as parameter
# Validation for each field
my $ret = '';
if (! TRUE) #validate $c->param('time_mode')
{$ret .= 'Validation for time_mode failed';}
if (! TRUE) #validate $c->param('ntpserver')
{$ret .= 'Validation for ntpserver failed';}
if (! TRUE) #validate $c->param('year')
{$ret .= 'Validation for year failed';}
if (! TRUE) #validate $c->param('month')
{$ret .= 'Validation for month failed';}
if (! TRUE) #validate $c->param('day')
{$ret .= 'Validation for day failed';}
if (! TRUE) #validate $c->param('hour')
{$ret .= 'Validation for hour failed';}
if (! TRUE) #validate $c->param('minute')
{$ret .= 'Validation for minute failed';}
if (! TRUE) #validate $c->param('second')
{$ret .= 'Validation for second failed';}
if ($ret eq '') {$ret = 'ok';}
return $ret;
}
# Get singleton data for each panel
sub get_data_for_panel_PARAMS {
# Return a hash with the fields required which will be loaded into the shared data
my $c = shift;
$cdb = esmith::ConfigDB::UTF8->open() || die("Couldn't open config db");
# --- Setup options ---
# Get today's date and time
my ($today_sec, $today_min, $today_hour, $today_mday, $today_mon, $today_year) = localtime;
$today_year += 1900;
$today_mon += 1;
my $today_mon = sprintf('%02d', $today_mon);
my $today_mday = sprintf('%02d', $today_mday);
my $now_hour = sprintf('%02d', $today_hour);
my $now_min = sprintf('%02d', $today_min);
my $now_sec = sprintf('%02d', $today_sec);
my $current_year = $today_year;
my $ntpserverurl = $cdb->get_prop('ntpd','NTPServer');
my %ret = (
# fields from Inputs
'time_mode'=>($ntpserverurl eq '' ? 'dat_manually_set' : 'dat_ntp_server'),
'ntpserver'=>"$ntpserverurl",
'year'=>"$today_year",
'month'=>"$today_mon",
'day'=>"$today_mday",,
'hour'=>"$now_hour",
'minute'=>"$now_min",
'second'=>"$now_sec",
'ntpstatus' => $cdb->get_prop('ntpd','status') || 'disabled',
);
return %ret;
}
# Get control data for table(s)
# Return hash with values from row in which link clicked on table
sub get_selected_PARAMS {
my $c = shift;
my $selected = shift; #Parameter is name of selected row.
my $is_new_record = shift; #Indicates new record required (defaults)
my %ret = ();
#gather the values here
return %ret;
}
#after sucessful modify or create or whatever and submit then perfom (if the params validate)
sub perform_PARAMS {
my $c = shift;
my $dat_data = shift; #Data hash as parameter
my $ret = '';
$cdb = esmith::ConfigDB::UTF8->open() || die("Couldn't open config db");
my $db = $cdb; #maybe one of the others
my $dbkey = 'ntpd';
# To make it write to DB as comment, delete this (regex) string in each if statement "TRUE\) \#copy or perform with value: .* e.g."
#$ntpserverurl = ( $c->param('time_mode') eq 'dat_manually_set' ? '' : $c->param('ntpserver'));
#if (!$db->set_prop($dbkey,'NTPServer',$ntpserverurl,type=>'service'))
#{$ret .= 'Perform/save failed for NTPServer';}
#if (! TRUE) #copy or perform with value: year e.g. $db->set_prop($dbkey,'year',$c->param('year'),type=>'service'))
#{$ret .= 'Perform/save failed for year';}
#if (! TRUE) #copy or perform with value: month e.g. $db->set_prop($dbkey,'month',$c->param('month'),type=>'service'))
#{$ret .= 'Perform/save failed for month';}
#if (! TRUE) #copy or perform with value: day e.g. $db->set_prop($dbkey,'day',$c->param('day'),type=>'service'))
#{$ret .= 'Perform/save failed for day';}
#if (! TRUE) #copy or perform with value: hour e.g. $db->set_prop($dbkey,'hour',$c->param('hour'),type=>'service'))
#{$ret .= 'Perform/save failed for hour';}
#if (! TRUE) #copy or perform with value: minute e.g. $db->set_prop($dbkey,'minute',$c->param('minute'),type=>'service'))
#{$ret .= 'Perform/save failed for minute';}
#if (! TRUE) #copy or perform with value: second e.g. $db->set_prop($dbkey,'second',$c->param('second'),type=>'service'))
#{$ret .= 'Perform/save failed for second';}
if ($c->param('time_mode') eq 'dat_manually_set'){
# Time and date set manually
$ret .= $c->disable_ntp();
$ret .= $c->validate_change_datetime()
} else {
# Time set by ntp server - set up parameters to it
$ret = $c->update_ntpserver($c->param('ntpserver'))
}
if ($ret eq '') {$ret = 'ok';}
return $ret;
}
sub create_link{
# WIP
my ($c,$route, $panel, $index) = @_;
my $link = "$route?trt=$panel&Selected=$index";
return $link;
}
sub getZone_list {
my $c = shift;
#--------------------------------------------------
# Get a sorted list of time zones
#--------------------------------------------------
$ENV{BASH_ENV} = '';
if (!open(ZONES, "cd /usr/share/zoneinfo; /usr/bin/find . -type f -or -type l | /bin/grep '^./[A-Z]' |")) {
warn($c->l('COULD_NOT_OPEN_TZ_FILE') . $! . '.');
return undef;
}
my $zone;
my @zones = ();
while (defined($zone = <ZONES>)) {
chop($zone);
$zone =~ s/^.\///;
push @zones, $zone;
} ## end while (defined($zone = <ZONES>...))
close ZONES;
my @zt = sort @zones;
return \@zt;
} ## end sub getZone_list
sub getTimezone {
#--------------------------------------------------
# Figure out time zone by looking first looking at
# the configuration database value of TimeZone.
# If that is not defined, try and get it from /etc/localtime.
# If that doesn't work, default to US/Eastern.
#--------------------------------------------------
my $localtime;
my $timezonedefault = "US/Eastern";
if (defined $cdb->get('TimeZone')) {
$timezonedefault = $cdb->get('TimeZone')->value;
} else {
if (defined($localtime = readlink '/etc/localtime')) {
my $pos = index $localtime, 'zoneinfo/';
if ($pos > -1) {
$timezonedefault = substr $localtime, ($pos + 9);
}
} ## end if (defined($localtime...))
} ## end else [ if (defined $cdb->get(...))]
return $timezonedefault;
} ## end sub getTimezone
sub validate_change_datetime {
my $c = shift;
$cdb = esmith::ConfigDB::UTF8->open() || die "Couldn't open config db";
#--------------------------------------------------
# Untaint parameters and check for validity
#--------------------------------------------------
my $timezone = $c->param('Timezone');
if ($timezone =~ /^([\w\-]+\/?[\w\-+]*)$/) {
$timezone = $1;
} else {
$timezone = "US/Eastern";
}
my $month = $c->param('month');
if ($month =~ /^(\d{1,2})$/) {
$month = $1;
} else {
$month = "1";
}
if (($month < 1) || ($month > 12)) {
return $c->l('dat_INVALID_MONTH') . " $month. " . $c->l('dat_MONTH_BETWEEN_1_AND_12');
}
my $day = $c->param('day');
if ($day =~ /^(\d{1,2})$/) {
$day = $1;
} else {
$day = "1";
}
if (($day < 1) || ($day > 31)) {
return $c->l('dat_INVALID_DAY') . " $day. " . $c->l('dat_BETWEEN_1_AND_31');
}
my $year = $c->param('year');
if ($year =~ /^(\d{4})$/) {
$year = $1;
} else {
$year = "2000";
}
if (($year < 1900) || ($year > 2200)) {
return $c->l('dat_INVALID_YEAR') . " $year. " . $c->l('dat_FOUR_DIGIT_YEAR');
}
my $hour = $c->param('hour');
if ($hour =~ /^(\d{1,2})$/) {
$hour = $1;
} else {
$hour = "12";
}
if (($hour < 1) || ($hour > 23)) {
return $c->l('dat_INVALID_HOUR') . " $hour. " . $c->l('dat_BETWEEN_0_AND_23');
}
my $minute = $c->param('minute');
if ($minute =~ /^(\d{1,2})$/) {
$minute = $1;
} else {
$minute = "0";
}
if (($minute < 0) || ($minute > 59)) {
return $c->l('datINVALID_MINUTE') . " $minute. " . $c->l('dat_BETWEEN_0_AND_59');
}
my $second = $c->param('second');
if ($second =~ /^(\d{1,2})$/) {
$second = $1;
} else {
$second = "0";
}
if (($second < 0) || ($second > 59)) {
return $c->l('dat_INVALID_SECOND') . " $second. " . $c->l('dat_BETWEEN_0_AND_59');
}
#my $ampm = $c->param('Ampm');
#Move to 24 hours clock - not using AM/PM.
#if ($ampm =~ /^(AM|PM)$/) {
#$ampm = $1;
#} else {
#$ampm = "AM";
#}
# force AM so that it actually works on 24hr clock.
#$ampm = "AM";
# convert to 24 hour time
#$hour = $hour % 12;
#if ($ampm eq "PM") {
# $hour = $hour + 12;
#}
#--------------------------------------------------
# Store time zone in configuration database
#--------------------------------------------------
my $old = $cdb->get('UnsavedChanges')->value;
my $rec = $cdb->get('TimeZone');
unless ($rec) {
$rec = $cdb->new_record('TimeZone', undef);
}
$rec->set_value($timezone);
$cdb->get('UnsavedChanges')->set_value($old);
#--------------------------------------------------
# Signal event to change time zone, system time
# and hardware clock
#--------------------------------------------------
my $newdate = sprintf "%02d%02d%02d%02d%04d.%02d", $month, $day, $hour, $minute, $year, $second;
esmith::util::backgroundCommand(2, "/sbin/e-smith/signal-event", "timezone-update", $newdate);
return '';
} ## end sub validate_change_datetime
sub update_ntpserver {
my $c = shift;
my $ntpserver = shift;
my $msg = '';
$cdb = esmith::ConfigDB::UTF8->open() || die "Couldn't open config db";
#------------------------------------------------------------
# Looks good; go ahead and change the parameters.
#------------------------------------------------------------
my $old = $cdb->get('UnsavedChanges')->value;
my $rec = $cdb->get('ntpd');
if ($rec) {
$rec->set_prop('status', 'enabled');
$rec->set_prop('NTPServer', $ntpserver);
} else {
$rec = $cdb->new_record('ntpd',
{ type => 'service', status => 'enabled', SyncToHWClockSupported => 'yes', NTPServer => $ntpserver });
}
$cdb->get('UnsavedChanges')->set_value($old);
$msg = ''; #$c->l('dat_SETTINGS_CHANGED');
if ($ntpserver =~ /^\s*$/) {
$rec->set_prop('status', ($rec->prop('SyncToHWClockSupported') || 'yes') eq 'yes' ? 'enabled' : 'disabled');
$rec->set_prop('NTPServer', '');
$msg = $c->l('dat_INVALID_NTP_SERVER') if ($rec->prop('SyncToHWClockSupported') || 'yes') ne 'yes';
} ## end if ($ntpserver =~ /^\s*$/)
esmith::util::backgroundCommand(2, "/sbin/e-smith/signal-event", "timeserver-update");
return $msg;
} ## end sub update_ntpserver
sub disable_ntp {
# make sure that the parameters are set for disabled
my $old = $cdb->get('UnsavedChanges')->value;
$cdb = esmith::ConfigDB::UTF8->open() || die "Couldn't open config db";
my $rec = $cdb->get('ntpd');
if ($rec) {
$rec->set_prop('status', ($rec->prop('SyncToHWClockSupported') || 'yes') eq 'yes' ? 'enabled' : 'disabled');
$rec->set_prop('NTPServer', '');
} else {
$rec = $cdb->new_record('ntpd',
{ type => 'service', status => 'enabled', SyncToHWClockSupported => 'yes', NTPServer => '' });
}
$cdb->get('UnsavedChanges')->set_value($old);
return '';
} ## end sub disable_ntp
1;

View File

@ -1,375 +1,283 @@
package SrvMngr::Controller::Datetime;
#
# Generated by SM2Gen version:0.9(20Jan2025) Chameleon version:4.5.4 On Python:3.12.3 at 2025-06-15 12:45:47
# Remember that each route must be unique (else they just overwrite each other).
# you cannot have get and post on the same name and url.
#
#----------------------------------------------------------------------
# heading : System
# description : Date and time
# navigation : 4000 300
# routes : end
#------------------------------
#
# Documentation: https://wiki.contribs.org/Datetime
#----------------------------------------------------------------------
#
# Scheme of things:
#
# TBA!!
use strict;
use warnings;
use Mojo::Base 'Mojolicious::Controller';
use constant FALSE => 0;
use constant TRUE => 1;
use Locale::gettext;
use SrvMngr::I18N;
use SrvMngr qw(theme_list init_session);
use Data::Dumper;
use esmith::util;
use SrvMngr qw( gen_locale_date_string );
use esmith::util::network;
use esmith::ConfigDB::UTF8;
our $cdb ;
use esmith::AccountsDB;
use esmith::NetworksDB;
use esmith::HostsDB::UTF8;
use esmith::DomainsDB::UTF8;
my $cdb;
my $adb;
my $ndb;
my $hdb;
my $ddb;
my %dat_data;
require '/usr/share/smanager/lib/SrvMngr/Controller/Datetime-Custom.pm'; #The code that is to be added by the developer
sub main {
#
# Initial entry - route is "/<whatever>"
#
#set initial panel
#for initial panel:
#Specifiy panel to enter
#load up _data hash with DB fields
#load up stash with pointer(s) to control fields hash(= get-))
#and a pointer to the prefix_data hash
#render initial panel
my $c = shift;
$c->app->log->info( $c->log_req );
#The most common ones - you might want to delete some of these if they are not used.
$cdb = esmith::ConfigDB::UTF8->open() || die("Couldn't open config db");
$adb = esmith::AccountsDB->open() || die("Couldn't open Accounts db");
$ndb = esmith::NetworksDB->open() || die("Couldn't open Network db");
$hdb = esmith::HostsDB::UTF8->open() || die("Couldn't open Hosts db");
$ddb = esmith::DomainsDB::UTF8->open() || die("Couldn't open Domains db");
%dat_data = ();
my $title = $c->l('dat_FORM_TITLE');
my $modul = $c->l('dat_INITIAL_DESC');
$dat_data{'trt'} = 'PARAMS';
#Load any DB entries into the <prefix>_data area so as they are preset in the form
# which DB - this only really works if the initial panel is a PARAMS type panel and not a TABLE
my $db = $cdb; #pickup local or global db or Default to config
$c->do_display($dat_data{'trt'});
}
# Post request with params - submit from the form
sub do_update {
#
# Return after submit pushed on panel (this is a post) - route is "/<whatever>u"
# parameters in the params hash.
#
#load up all params into prefix_data hash:
#By panel (series of if statements - only one executed):
#call validate-PANEL() - return ret = ok or error message
#if validation not ok:
#render back to current panel with error message in stash
#otherwise:
#By panel (series of if statements - only one executed):
#do whatever is required: call perform-PANEL() - return 'ok' or Error Message
#call signal-event for any global actions specified (check it exists - error and continue?)
#if action smeserver-<whatever>-update exists
#signal_event smeserver-<whatever>-update
#call signal-event for any specific actions for thids panel (check it exists first - error and continue)
#set success in stash
#if no "nextpanel" entry:
#set firstpanel
#else
#set nextpanel
#call render
my $c = shift;
$c->app->log->info($c->log_req);
my %dat_datas = ();
$c->app->log->info($c->param('month'));
#The most common ones - you might want to delete some of these if they are not used.
$cdb = esmith::ConfigDB::UTF8->open() || die("Couldn't open config db");
$adb = esmith::AccountsDB->open() || die("Couldn't open Accounts db");
$ndb = esmith::NetworksDB->open() || die("Couldn't open Network db");
$hdb = esmith::HostsDB::UTF8->open() || die("Couldn't open Hosts db");
$ddb = esmith::DomainsDB::UTF8->open() || die("Couldn't open Domains db");
my $title = $c->l('dat_FORM_TITLE');
my $modul = $c->l('dat_INITIAL_DESC');
$dat_datas{ntpstatus} = 'disabled';
$cdb = esmith::ConfigDB::UTF8->open() || die "Couldn't open config db";
my $rec = $cdb->get('ntpd');
if ($rec) {
$dat_datas{'ntpserver'} = $rec->prop('NTPServer') || '';
# Accessing all POST/GET parameters
#my $params = $c->req->params->to_hash;
if ($rec->prop('status') eq 'enabled') {
$dat_datas{ntpstatus} = 'enabled'
unless ($rec->prop('SyncToHWClockSupported') || 'yes') eq 'yes' and $dat_datas{ntpserver} =~ m#^\s*$#;
}
} ## end if ($rec)
( $dat_datas{weekday}, $dat_datas{monthname}, $dat_datas{month}, $dat_datas{day}, $dat_datas{year},
$dat_datas{hour}, $dat_datas{minute}, $dat_datas{second}, $dat_datas{ampm}
)
= split /\|/,
`/bin/date '+%A|%B|%-m|%-d|%Y|%-I|%M|%S|%p'`;
# Get number of POST parameters
#my $num_params = keys scaler %$params;
# get rid of trailing carriage return on last field
chop($dat_datas{ampm});
$dat_datas{'now_string'} = gen_locale_date_string;
$c->stash(title => $title, modul => $modul, dat_datas => \%dat_datas);
$c->render('datetime');
} ## end sub main
#Params are available in the hash "params" - copy to the prefix_data hash
#while (my ($key, $value) = each %{$c->req->params->to_hash}) {
# $dat_data{$key} = $value;
#}
# the value of trt will tell you which panel has returned
my $trt = $c->param('trt') || 'PARAMS'; #hidden control on every form.
my $ret = 'ok';
#Validate the parameters in a custom sub one for each panel (although only one of these will be executed)
my $thispanel;
if ($trt eq 'PARAMS'){
#Validate form parameters for panel PARAMS
$ret = $c->validate_PARAMS(\%dat_data);
$thispanel = 'PARAMS';
}
if ($ret ne 'ok'){
$c->stash(error => $c->l($ret));
$c->do_display($thispanel);
} else {
#Do whatever is needed, including writing values to the DB
if ($trt eq 'PARAMS'){
#do whatever is required ...
$ret = $c->perform_PARAMS(\%dat_data);
if ($ret ne 'ok') {
# return to the panel with error message
$c->stash(error => $c->l($ret));
$c->stash(
title => $title,
modul => $modul,
dat_data => \%dat_data
);
$c->render(template => "datetime");
return
} else {
if ($c->param('time_mode') eq 'data_manually_set') {
$c->stash( success => $c->l('dat_UPDATING_CLOCK'));
} else {
$c->stash( success => $c->l('dat_SETTINGS_CHANGED'));
}
}
}
# and call any signal-events needed
#TBD
# Setup shared data and call panel
if ('none' eq 'none') {
$dat_data{'trt'} = 'PARAMS';
} else {
$dat_data{'trt'} = 'none';
}
$c->do_display($dat_data{'trt'});
}
}
sub do_display {
#
# Return after link clicked in table (this is a get) - route is "/<whatever>d"
# Expects ?trt=PANEL&selected="TableRowName" plus any other required
#
# OR it maybe a post from the main panel to add a new record
#
#load up all supplied params into prefix_data hash
#call get-selected-PANEL() - returns hash of all relevent parameters
#load up returned hash into prefix_data
#render - to called panel
my ($c,$trt) = @_;
$c->app->log->info($c->log_req);
#The most common ones - you might want to delete some of these if they are not used.
$cdb = esmith::ConfigDB::UTF8->open() || die("Couldn't open config db");
$adb = esmith::AccountsDB->open() || die("Couldn't open Accounts db");
$ndb = esmith::NetworksDB->open() || die("Couldn't open Network db");
$hdb = esmith::HostsDB::UTF8->open() || die("Couldn't open Hosts db");
$ddb = esmith::DomainsDB::UTF8->open() || die("Couldn't open Domains db");
sub do_update {
my $c = shift;
my %dat_datas = ();
my $title = $c->l('dat_FORM_TITLE');
my $modul = $c->l('dat_INITIAL_DESC');
my $result;
my $success;
my $old_ntpstatus = $c->param('Old_ntpstatus');
$cdb = esmith::ConfigDB::UTF8->open() || die "Couldn't open config db";
$dat_datas{ntpstatus} = $c->param('Ntpstatus');
if ($dat_datas{ntpstatus} ne $old_ntpstatus) {
if ($dat_datas{ntpstatus} eq 'disabled') {
( $dat_datas{weekday}, $dat_datas{monthname}, $dat_datas{month},
$dat_datas{day}, $dat_datas{year}, $dat_datas{hour},
$dat_datas{minute}, $dat_datas{second}, $dat_datas{ampm}
)
= split /\|/,
`/bin/date '+%A|%B|%-m|%-d|%Y|%-I|%M|%S|%p'`;
# Accessing all parameters
#my $params = $c->req->params->to_hash;
# get rid of trailing carriage return on last field
chop($dat_datas{ampm});
} else {
$dat_datas{ntpserver} = ($cdb->get_prop('ntpd', 'NTPServer')) || '';
}
$dat_datas{now_string} = gen_locale_date_string();
$c->stash(title => $title, modul => $modul, dat_datas => \%dat_datas);
return $c->render('datetime');
} ## end if ($dat_datas{ntpstatus...})
# Get number of parameters
#my $num_params = keys %$params;
if ($dat_datas{ntpstatus} eq 'enabled') {
#Tag as Post or Get (ie. create new entry or edit existing one
my $is_new_record = ($c->req->method() eq 'POST');
# update ntpserver
$dat_datas{ntpserver} = $c->param('Ntpserver') || '';
#Params are available in the hash "params" - copy to the prefix_data hash
#while (my ($key, $value) = each %{$c->req->params->to_hash}) {
# $dat_data{$key} = $value;
#}
if ($dat_datas{ntpserver} eq "pool.ntp.org") {
$result .= $c->l('dat_INVALID_NTP_ADDR');
} elsif ($dat_datas{ntpserver} =~ /^([a-zA-Z0-9\.\-]+)$/) {
$dat_datas{ntpserver} = $1;
# the value of trt will tell you which panel has returned
if (! $trt){
$trt = $c->param('trt') || 'PARAMS'; #Indicates where to go now
}
# } elsif ( $dat_datas{ntpserver} =~ /^\s*$/ ) {
# $dat_datas{ntpserver} = "";
} else {
$result .= $c->l('dat_INVALID_NTP_ADDR');
}
# Now add in the params from the selected row from the table
if (!$result) {
$success = update_ntpserver($c, $dat_datas{ntpserver});
}
} else {
my %selectedrow;
# set Locale time & clean ntpserver
#my $servername = ($c->param('ServerName') || 'WS');
if (!$result) {
$result = validate_change_datetime($c);
if ($trt eq 'PARAMS'){
#Validate Get selected row (if applicable) PARAMS
%selectedrow = $c->get_selected_PARAMS($dat_data{'Selected'},$is_new_record);
}
if ($result eq 'OK') {
$success = $c->l('dat_UPDATING_CLOCK');
$result = '';
disable_ntp();
$success .= '<br>' . $c->l('dat_SERVER_DISABLED_DESC');
} ## end if ($result eq 'OK')
} ## end if (!$result)
} ## end else [ if ($dat_datas{ntpstatus...})]
if ($result) {
$c->stash(error => $result);
$c->stash(title => $title, modul => $modul, dat_datas => \%dat_datas);
return $c->render('datetime');
} ## end if ($result)
#$result = $c->l('dat_SUCCESS');
my $message = "'Datetime' update DONE";
$c->app->log->info($message);
$c->flash(success => $success);
$c->redirect_to('/datetime');
} ## end sub do_update
sub validate_change_datetime {
my $c = shift;
$cdb = esmith::ConfigDB::UTF8->open() || die "Couldn't open config db";
#--------------------------------------------------
# Untaint parameters and check for validity
#--------------------------------------------------
my $timezone = $c->param('Timezone');
if ($timezone =~ /^([\w\-]+\/?[\w\-+]*)$/) {
$timezone = $1;
} else {
$timezone = "US/Eastern";
#Copy in the selected row params to the prefix_data hash to pass to the panel
while (my ($key, $value) = each %selectedrow){
$dat_data{$key} = $value;
}
my $month = $c->param('Month');
# Where to go now
$dat_data{'trt'} = $trt;
if ($month =~ /^(\d{1,2})$/) {
$month = $1;
} else {
$month = "1";
}
# Set up other shared data according to the panel to go to
if (($month < 1) || ($month > 12)) {
return $c->l('dat_INVALID_MONTH') . " $month. " . $c->l('dat_MONTH_BETWEEN_1_AND_12');
}
my $day = $c->param('Day');
if ($trt eq 'PARAMS'){
# pickup any other contents needed and load them into hash shared with panel
my %returned_hash;
# subroutine returns a hash directly
%returned_hash = $c->get_data_for_panel_PARAMS();
# Copy each key-value pair from the returned hash to the prefix data hash
while (my ($key, $value) = each %returned_hash) {
$dat_data{$key} = $value;
}
}
if ($day =~ /^(\d{1,2})$/) {
$day = $1;
} else {
$day = "1";
}
if (($day < 1) || ($day > 31)) {
return $c->l('dat_INVALID_DAY') . " $day. " . $c->l('dat_BETWEEN_1_AND_31');
}
my $year = $c->param('Year');
# and table control fields
if ($year =~ /^(\d{4})$/) {
$year = $1;
} else {
$year = "2000";
}
if (($year < 1900) || ($year > 2200)) {
return $c->l('dat_INVALID_YEAR') . " $year. " . $c->l('dat_FOUR_DIGIT_YEAR');
}
my $hour = $c->param('Hour');
if ($hour =~ /^(\d{1,2})$/) {
$hour = $1;
} else {
$hour = "12";
}
if (($hour < 1) || ($hour > 12)) {
return $c->l('dat_INVALID_HOUR') . " $hour. " . $c->l('dat_BETWEEN_1_AND_12');
}
my $minute = $c->param('Minute');
if ($minute =~ /^(\d{1,2})$/) {
$minute = $1;
} else {
$minute = "0";
}
if (($minute < 0) || ($minute > 59)) {
return $c->l('datINVALID_MINUTE') . " $minute. " . $c->l('dat_BETWEEN_0_AND_59');
}
my $second = $c->param('Second');
if ($second =~ /^(\d{1,2})$/) {
$second = $1;
} else {
$second = "0";
}
if (($second < 0) || ($second > 59)) {
return $c->l('dat_INVALID_SECOND') . " $second. " . $c->l('dat_BETWEEN_0_AND_59');
}
my $ampm = $c->param('Ampm');
if ($ampm =~ /^(AM|PM)$/) {
$ampm = $1;
} else {
$ampm = "AM";
}
# convert to 24 hour time
$hour = $hour % 12;
if ($ampm eq "PM") {
$hour = $hour + 12;
}
#--------------------------------------------------
# Store time zone in configuration database
#--------------------------------------------------
my $old = $cdb->get('UnsavedChanges')->value;
my $rec = $cdb->get('TimeZone');
unless ($rec) {
$rec = $cdb->new_record('TimeZone', undef);
}
$rec->set_value($timezone);
$cdb->get('UnsavedChanges')->set_value($old);
#--------------------------------------------------
# Signal event to change time zone, system time
# and hardware clock
#--------------------------------------------------
my $newdate = sprintf "%02d%02d%02d%02d%04d.%02d", $month, $day, $hour, $minute, $year, $second;
esmith::util::backgroundCommand(2, "/sbin/e-smith/signal-event", "timezone-update", $newdate);
return 'OK';
} ## end sub validate_change_datetime
sub update_ntpserver {
my $c = shift;
my $ntpserver = shift;
my $msg;
#------------------------------------------------------------
# Looks good; go ahead and change the parameters.
#------------------------------------------------------------
my $old = $cdb->get('UnsavedChanges')->value;
my $rec = $cdb->get('ntpd');
if ($rec) {
$rec->set_prop('status', 'enabled');
$rec->set_prop('NTPServer', $ntpserver);
} else {
$rec = $cdb->new_record('ntpd',
{ type => 'service', status => 'enabled', SyncToHWClockSupported => 'yes', NTPServer => $ntpserver });
}
$cdb->get('UnsavedChanges')->set_value($old);
$msg = $c->l('dat_SETTINGS_CHANGED');
if ($ntpserver =~ /^\s*$/) {
$rec->set_prop('status', ($rec->prop('SyncToHWClockSupported') || 'yes') eq 'yes' ? 'enabled' : 'disabled');
$rec->set_prop('NTPServer', '');
$msg = $c->l('dat_INVALID_NTP_SERVER') if ($rec->prop('SyncToHWClockSupported') || 'yes') ne 'yes';
} ## end if ($ntpserver =~ /^\s*$/)
esmith::util::backgroundCommand(2, "/sbin/e-smith/signal-event", "timeserver-update");
return $msg;
} ## end sub update_ntpserver
sub disable_ntp {
# make sure that the parameters are set for disabled
my $old = $cdb->get('UnsavedChanges')->value;
my $rec = $cdb->get('ntpd');
if ($rec) {
$rec->set_prop('status', ($rec->prop('SyncToHWClockSupported') || 'yes') eq 'yes' ? 'enabled' : 'disabled');
$rec->set_prop('NTPServer', '');
} else {
$rec = $cdb->new_record('ntpd',
{ type => 'service', status => 'enabled', SyncToHWClockSupported => 'yes', NTPServer => '' });
}
$cdb->get('UnsavedChanges')->set_value($old);
} ## end sub disable_ntp
sub getTimezone {
#--------------------------------------------------
# Figure out time zone by looking first looking at
# the configuration database value of TimeZone.
# If that is not defined, try and get it from /etc/localtime.
# If that doesn't work, default to US/Eastern.
#--------------------------------------------------
my $localtime;
my $timezonedefault = "US/Eastern";
if (defined $cdb->get('TimeZone')) {
$timezonedefault = $cdb->get('TimeZone')->value;
} else {
if (defined($localtime = readlink '/etc/localtime')) {
my $pos = index $localtime, 'zoneinfo/';
if ($pos > -1) {
$timezonedefault = substr $localtime, ($pos + 9);
}
} ## end if (defined($localtime...))
} ## end else [ if (defined $cdb->get(...))]
return $timezonedefault;
} ## end sub getTimezone
sub getZone_list {
my $c = shift;
#--------------------------------------------------
# Get a sorted list of time zones
#--------------------------------------------------
$ENV{BASH_ENV} = '';
if (!open(ZONES, "cd /usr/share/zoneinfo; /usr/bin/find . -type f -or -type l | /bin/grep '^./[A-Z]' |")) {
warn($c->l('COULD_NOT_OPEN_TZ_FILE') . $! . '.');
return undef;
}
my $zone;
my @zones = ();
while (defined($zone = <ZONES>)) {
chop($zone);
$zone =~ s/^.\///;
push @zones, $zone;
} ## end while (defined($zone = <ZONES>...))
close ZONES;
my @zt = sort @zones;
return \@zt;
} ## end sub getZone_list
sub getMonth_list {
my $c = shift;
return [
[ $c->l('dat_JANUARY') => '1' ],
[ $c->l('dat_FEBRUARY') => '2' ],
[ $c->l('dat_MARCH') => '3' ],
[ $c->l('dat_APRIL') => '4' ],
[ $c->l('dat_MAY') => '5' ],
[ $c->l('dat_JUNE') => '6' ],
[ $c->l('dat_JULY') => '7' ],
[ $c->l('dat_AUGUST') => '8' ],
[ $c->l('dat_SEPTEMBER') => '9' ],
[ $c->l('dat_OCTOBER') => '10' ],
[ $c->l('dat_NOVEMBER') => '11' ],
[ $c->l('dat_DECEMBER') => '12' ]
];
} ## end sub getMonth_list
sub getYear_list {
my $c= shift;
my @yearArray;
# could use also `/bin/date '+%Y'`
my $start=2025-40; my $max=2025+40;
for ( my $i = $start; $i <= $max; $i++ ) {
push @yearArray,$i;
}
my @yearList = sort @yearArray;
return \@yearList;
} ## end sub getYear_list
# Data for panel
$c->stash(
title => $title,
modul => $modul,
dat_data => \%dat_data
);
$c->render(template => "datetime");
}
1;

View File

@ -73,7 +73,6 @@ sub do_display {
if ((index($ret{ret}, "SUCCESS") != -1)) {
$trt = "LIST";
} else {
#Error - return to Add page
$trt = "ADD";
}
@ -222,17 +221,18 @@ sub add_network {
# in the form itself, but it just seemed too fiddly to do that
# at the moment. -- Skud 2002-04-11
# I agree --bjr 2020-04-18
if ($routerNetwork ne $localNetwork) {
return (ret => 'ln_NOT_ACCESSIBLE_FROM_LOCAL_NETWORK');
}
my ($network, $broadcast) = esmith::util::computeNetworkAndBroadcast($networkAddress, $networkMask);
if ($routerNetwork ne $localNetwork) {
return (ret => 'ln_NOT_ACCESSIBLE_FROM_LOCAL_NETWORK', vars => "$network,$networkMask,$networkRouter");
}
if ($network eq $localNetwork) {
return (ret => 'ln_NETWORK_ALREADY_LOCAL');
return (ret => 'ln_NETWORK_ALREADY_LOCAL', vars => "$network,$networkMask,$networkRouter");
}
if ($network_db->get($network)) {
return (ret => 'ln_NETWORK_ALREADY_ADDED');
return (ret => 'ln_NETWORK_ALREADY_ADDED', vars => "$network,$networkMask,$networkRouter");
}
$network_db->new_record(
$network,
@ -246,7 +246,7 @@ sub add_network {
$network =~ /(.+)/;
$network = $1;
system("/sbin/e-smith/signal-event", "network-create", $network) == 0
or (return (ret => 'ln_ERROR_CREATING_NETWORK'));
or (return (ret => 'ln_ERROR_CREATING_NETWORK', vars => "$network,$networkMask,$networkRouter"));
my ($totalHosts, $firstAddr, $lastAddr) = esmith::util::computeHostRange($network, $networkMask);
my $msg;

View File

@ -43,6 +43,7 @@ sub do_update {
my $http_proxy_status = $c->param('http_proxy_status') || 'disabled';
my $smtp_proxy_status = $c->param('smtp_proxy_status') || '';
my $result = "";
$db = esmith::ConfigDB::UTF8->open || die "Couldn't open config db";
my $squid = $db->get('squid') or $result = $c->l('prx_ERR_NO_SQUID_REC');
# smtpd is allowed to not exist, as the relevant packages may not be

View File

@ -18,7 +18,7 @@ manually set the date and time for your time zone.',
'dat_DECEMBER' => 'December',
'dat_NEW_M/D/Y' => 'New month/day/year:',
'dat_NEW_H/M/S' => 'New hour/min/sec:',
'dat_AM/PM_AND_TZ' => 'AM/PM and time zone:',
'dat_TZ' => 'Time zone:',
'dat_NTP_ENABLE_DESC' => 'The server can periodically synchronize the system clock to a network time protocol (NTP) server. If you select this option, enter the hostname or IP address of the NTP server below.',
'dat_NTP_CONFIGURE_DESC' => 'The server is periodically synchronizing the system clock to the network time protocol (NTP) server specified below. To synchronize to a different NTP server, enter a different hostname or IP address in the field below.',
'dat_NTP_DISABLE_DESC' => 'Choose this option to stop syncronizing the system clock to the NTP
@ -38,9 +38,7 @@ server.When the NTP service is disabled, you can set the system date and time ma
'dat_INVALID_SECOND' => 'Error: invalid second',
'dat_MONTH_BETWEEN_1_AND_12' => 'Please choose a month value between 1 and 12.',
'dat_INVALID_MONTH' => 'Error: invalid month',
'dat_UPDATING_CLOCK' => 'System clock is being updated. Please wait for a few seconds,
then click <A HREF="datetime?page=1&wherenext=Verify" TARGET="main">here</A>
to verify changes.',
'dat_UPDATING_CLOCK' => 'System clock is being updated',
'dat_ERR_SETTING_CLOCK' => 'Error occurred while setting system time and hardware clock.',
'dat_SERVER_DISABLED' => 'Network time server disabled successfully',
'dat_SERVER_DISABLED_DESC' => 'You have disabled this service: The server will rely on its internal
@ -57,3 +55,7 @@ clock, and <b>will not</b> try to synchronize from a time server.',
'dat_NTP_DISABLE_TITLE' => 'Disable Network Time Server',
'dat_CURRENT_SETTING' => 'Current setting',
'Date and time' => 'Date and time',
'dat_ntp_server' => 'NTP server',
'dat_manually_set' => 'Set manually',
'dat_NTP_Server_URL' =>'NTP Server URL:',
'dat_set_manually' =>'Set Date and Time:',

View File

@ -12,13 +12,13 @@
'ln_REMOVE_CONFIRM' => 'Are you sure you wish to remove this network?',
'ln_DEFAULT' => 'default',
'ln_NUMBER_OF_HOSTS' => 'Number of hosts',
'ln_NOT_ACCESSIBLE_FROM_LOCAL_NETWORK' => 'Error: router address {$networkRouter} is not accessible from local network. Did not add network.',
'ln_NOT_ACCESSIBLE_FROM_LOCAL_NETWORK' => 'Error: router address [_3] is not accessible from local network. Did not add network.',
'ln_LOCALNETWORK_ADD'=>'Add network',
'ln_NETWORK_ALREADY_LOCAL' => ' Error: network {$network} (derived from network {$networkAddress} and subnet mask {$networkMask}) is already considered local. Did not add new network. ',
'ln_NETWORK_ALREADY_ADDED' => 'Error: network {$network} (derived from network {$networkAddress} and subnet mask {$networkMask}) has already been added. Did not add new network.',
'ln_NETWORK_ALREADY_LOCAL' => ' Error: network [_1] (derived from network [_1] and subnet mask [_2]) is already considered local. Did not add new network. ',
'ln_NETWORK_ALREADY_ADDED' => 'Error: network [_1] (derived from network [_1] and subnet mask [_2]) has already been added. Did not add new network.',
'ln_ERROR_CREATING_NETWORK' => 'Error occurred while creating network.',
'ln_SUCCESS' =>'Successfully added network [_1]/[_2] via router [_3].',
'ln_SUCCESS_SINGLE_ADDRESS' =>'Successfully added network {$network}/{$networkMask} via router {$networkRouter}. Your server will grant local access privileges to the single IP address {$network}. ',
'ln_SUCCESS_SINGLE_ADDRESS' =>'Successfully added network [_1]/[_2] via router [_3]. Your server will grant local access privileges to the single IP address [_1]. ',
'ln_SUCCESS_NETWORK_RANGE' =>'Successfully added network [_1]/[_2] via router [_3]. Your server will grant local access privileges to [_4] IP addresses in the range [_5] to [_6]. ',
'ln_NO_SUCH_NETWORK' =>'Network not found in network db',
'ln_SUCCESS_REMOVED_NETWORK' =>'Successfully removed network [_1]/[_2] via router [_3].',
@ -26,5 +26,5 @@
'ln_NO_ADDITIONAL_NETWORKS' => 'No additional networks',
'ln_REMOVE_HOSTS_DESC' => 'Local hosts configured on the network you are about to remove have been detected. By default, they will also be removed. Uncheck this box if, for some reason, you do not wish this to happen. Note that they will not be treated as local, and may not even be reachable, after this network is removed. ',
'ln_REMOVE_HOSTS_LABEL' => 'Remove hosts on network',
'ln_extra' => '{$network}/{$networkMask} via router $networkRouter}.',
'ln_extra' => '[_1]/[_2] via router $networkRouter}.',
'ln_SUCCESS_NONSTANDARD_RANGE' =>'<p>Successfully added network [_1]/[_2] via router [_3].</p><p> Your server will grant local access privileges to [_4] IP addresses in the range [_5] to [_6].</p><p> Warning: the ProFTPd FTP server cannot handle this nonstandard subnet mask. The simpler specification <b>[_7]</b> will be used instead.</p>',

View File

@ -0,0 +1,29 @@
.datetime-config-row {
display: flex;
align-items: stretch;
margin-bottom: 1em;
}
.datetime-label-col {
background: #e8f3e2; /* light green */
padding: 1em 0em 0em 0em;
min-width: 192px;
display: flex;
align-items: flex-start;
justify-content: flex-end;
font-weight: bold;
border-radius: 4px 0 0 4px;
}
.datetime-label {
display: block;
}
.datetime-fields-col {
background: #fff;
padding: 1em;
flex: 1;
border: 1px solid #ccc;
border-left: none;
border-radius: 0 4px 4px 0;
}

View File

@ -0,0 +1,18 @@
document.addEventListener('DOMContentLoaded', function() {
var select = document.getElementById('time_mode_select');
var ntpSection = document.getElementById('ntp_section');
var manualSection = document.getElementById('manual_section');
function toggleSections() {
if (select.value === 'dat_manually_set') {
ntpSection.style.display = 'none';
manualSection.style.display = 'block';
} else {
ntpSection.style.display = 'block';
manualSection.style.display = 'none';
}
}
select.addEventListener('change', toggleSections);
toggleSections(); // Set initial state
});

View File

@ -1,125 +1,139 @@
% layout 'default', title => "Sme server 2 - datetime";
% layout 'default', title => 'Sme server 2 - datetime';
% content_for 'module' => begin
<div id='module' class='module datetime-panel'>
% if (config->{debug} == 1) {
<p>
%= dumper $c->current_route
%= dumper $dat_datas
</p>
% }
% if ( stash 'error' ) {
<br><div class=sme-error>
%= $c->render_to_string(inline => stash 'error')
</div>
%}
<h1><%= $title %></h1><br>
%= $modul
<% my $btn = l('SAVE'); %>
%= form_for '/datetime' => (method => 'POST') => begin
<p>
%= hidden_field 'Old_ntpstatus' => $dat_datas->{ntpstatus};
% param 'Ntpstatus' => $dat_datas->{ntpstatus} unless param 'Ntpstatus';
%= radio_button Ntpstatus => 'enabled'
<span class=label>
%=l 'dat_NTP_CONFIGURE_TITLE'
</span>
<br>
% if ($dat_datas->{ntpstatus} eq 'disabled') {
<div class='datetime-set-ntp'>
%=l 'dat_NTP_ENABLE_DESC'
<br>
</div>
% } else {
<div class='datetime-set-ntp'>
%=l 'dat_NTP_CONFIGURE_DESC'
<br><br>
%= javascript 'js/datetime.js'
%= stylesheet 'css/datetime.css'
<div id='module' class='module datetime-panel'>
% if (config->{debug} == 1) {
<p>
%=l 'dat_CURRENT_SETTING'
<b>
%= $dat_datas->{now_string}
</b>
%= dumper $c->current_route
%= dumper $dat_data
</p>
% }
%if ($c->stash('first')) {
<br><p>
%=$c->render_to_string(inline =>$c->l($c->stash('first')))
</p>
%} elsif ($c->stash('success')) {
<div class='success '>
%= $c->l($c->stash('success'));
</div>
%} elsif ($c->stash('error')) {
<div class='sme-error'>
%= $c->l($c->stash('error'));
</div>
%}
<h1><%= $title %></h1><br>
%= $modul
<% my $btn = l('SAVE'); %>
<p>
<br>
<span class=label>
%=l 'dat_NTP_SERVER'
</span><span class=data2>
%= text_field 'Ntpserver' => $dat_datas->{ntpserver}, class => 'input'
</span>
</p>
% if ($dat_data->{ntpstatus} eq 'disabled') {
<div class='datetime-set-ntp'>
%=l 'dat_NTP_ENABLE_DESC'
<br>
</div>
% } else {
% my $current_year = $dat_data->{year};
% my $year_options = [ map { [ $_, $_ ] } ($current_year..($current_year+30)) ];
% my $month_options = [ map { [ sprintf('%02d', $_), sprintf('%02d', $_) ] } (1..12) ];
% my $hour_options = [ map { [ sprintf('%02d', $_), sprintf('%02d', $_) ] } (0..23) ];
% my $mode_options = [
% [ $c->l('dat_ntp_server'), 'dat_ntp_server' ],
% [ $c->l('dat_manually_set'), 'dat_manually_set' ]
% ];
<h2><%= $c->l('Time Configuration') %></h2>
%= form_for "datetimeu" => (method => 'post') => begin
%= hidden_field 'Old_ntpstatus' => $dat_data->{ntpstatus};
%= hidden_field 'trt' => $dat_data->{trt};
<span class=label>
%= label_for time_mode => $c->l('Time Setting Mode:')
</span><span class=data2>
% param 'time_mode' => $dat_data->{time_mode} unless param 'time_mode';
%= select_field time_mode => ($mode_options, id => 'time_mode_select')
</span>
<div id='ntp_section'>
<p>
%= $c->l('dat_NTP_CONFIGURE_DESC')
</p>
<div class='datetime-config-row'>
<div class='datetime-label-col'>
<span class='datetime-label'>
%= label_for ntpserver => $c->l('dat_NTP_Server_URL')
</span>
</div>
<div class=datetime-fields-col>
% my $server_check = '^([a-zA-Z0-9][a-zA-Z0-9\.\-]{0,253}[a-zA-Z0-9]|(\d{1,3}\.){3}\d{1,3})$';
% param 'ntpserver' => $dat_data->{ntpserver} unless param 'ntpserver';
%= text_field ntpserver => placeholder => 'e.g. smeserver.pool.ntp.org',id => 'ntpserver', pattern => $server_check, title => 'Enter a valid hostname or IPv4 address',required => 'required'
</div>
</div>
</div>
<div id='manual_section'>
<p>
%= $c->l('dat_NTP_DISABLE_DESC')
</p>
<div class='datetime-config-row'>
<div class='datetime-label-col'>
<span class='datetime-label'>
%= label_for 'datetime_manual' => $c->l('dat_set_manually')
</span>
</div>
<div class='datetime-fields-col' id='datetime_manual'>
<fieldset>
<legend><%= $c->l('Date') %></legend>
%= label_for year => $c->l('Year:')
% param 'year' => ($dat_data->{year}) unless param 'year';
%= select_field year => ($year_options, id => 'year'), required => 'required'
&nbsp;
%= label_for month => $c->l('Month:')
% param 'month' => ($dat_data->{month}) unless param 'month';
%= select_field month => ($month_options, id => 'month'), required => 'required'
&nbsp;
%= label_for day => $c->l('Day:')
% param 'day' => ($dat_data->{day}) unless param 'day';
%= text_field day => id => 'day', size => 2, maxlength => 2, placeholder => 'DD', pattern => '^(0[1-9]|[12][0-9]|3[01])$', title => 'Day (01-31)', required => 'required', inputmode => 'numeric', autocomplete => 'off'
</fieldset>
<fieldset>
<legend><%= $c->l('Time') %></legend>
%= label_for hour => $c->l('Hour:')
% param 'hour' => ($dat_data->{hour}) unless param 'hour';
%= select_field hour => ($hour_options, id => 'hour'), required => 'required'
&nbsp;
%= label_for minute => $c->l('Minute:')
% param 'minute' => ($dat_data->{minute}) unless param 'minute';
%= text_field minute => id => 'minute', size => 2, maxlength => 2, placeholder => 'MM', pattern => '^[0-5][0-9]$', title => 'Minute (00-59)', required => 'required', inputmode => 'numeric', autocomplete => 'off'
&nbsp;
%= label_for second => $c->l('Second:')
% param 'second' => ($dat_data->{second}) unless param 'second';
%= text_field second => id => 'second', size => 2, maxlength => 2, placeholder => 'SS', pattern => '^[0-5][0-9]$', title => 'Second (00-59)', required => 'required', inputmode => 'numeric', autocomplete => 'off'
</fieldset>
</div>
</div>
<div class='datetime-config-row'>
<div class='datetime-label-col'>
<span class='datetime-label'>
%=l 'dat_TZ'
</span>
</div>
<div class='datetime-fields-col' id='datetime_manual'>
% param 'Timezone' => $c->getTimezone() unless param 'Timezone';
%= select_field 'Timezone' => $c->getZone_list(), class => 'input'
</div>
</div>
</div>
%= submit_button $btn, class => 'action'
% end
% }
</div>
% }
%= radio_button Ntpstatus => 'disabled'
<span class=label datetime-set-ntp>
%=l 'dat_NTP_DISABLE_TITLE'
</span>
% if ($dat_datas->{ntpstatus} eq 'enabled') {
<br><BR>
<div class='datetime-set-ntp'>
%=l 'dat_NTP_DISABLE_DESC'
</div>
% } else {
<div class='datetime-set-ntp'>
<br>
</p>
<p>
%=l 'dat_CURRENT_SETTING'
<b>
%= $dat_datas->{now_string}
</b>
<br>
<span class=label>
%=l 'dat_NEW_M/D/Y'
</span><span class=data2>
% param 'Month' => $dat_datas->{month} unless param 'Month';
%= select_field 'Month' => $c->getMonth_list(), class => 'input'
</span><span class=data2>
% param 'Day' => $dat_datas->{day} unless param 'Day';
%= text_field 'Day', size => '2', class => 'input'
</span><span class=data2>
% param 'Year' => $dat_datas->{year} unless param 'Year';
%= text_field 'Year', size => '4', class => 'input'
</span>
<br>
<span class=label>
%=l 'dat_NEW_H/M/S'
</span><span class=data2>
% param 'Hour' => $dat_datas->{hour} unless param 'Hour';
%= text_field 'Hour', size => '2', class => 'input'
</span><span class=data2>
% param 'Minute' => $dat_datas->{minute} unless param 'Minute';
%= text_field 'Minute', size => '2', class => 'input'
</span><span class=data2>
% param 'Second' => $dat_datas->{second} unless param 'Second';
%= text_field 'Second', size => '2', class => 'input'
</span>
<br>
<span class=label>
%=l 'dat_AM/PM_AND_TZ'
</span><span class=data2>
% param 'Ampm' => $dat_datas->{ampm} unless param 'Ampm';
%= select_field 'Ampm' => ['AM', 'PM'], class => 'input'
</span><span class=data2>
% param 'Timezone' => $c->getTimezone() unless param 'Timezone';
%= select_field 'Timezone' => $c->getZone_list(), class => 'input'
</span>
</p>
</div>
% }
<p>
<br>
%= submit_button "$btn", class => 'action'
</p>
% end
</div>
%end
% end
1;

View File

@ -2,7 +2,7 @@ Summary: Sme server navigation module : manager 2
%define name smeserver-manager
Name: %{name}
%define version 11.0.0
%define release 91
%define release 92
Version: %{version}
Release: %{release}%{?dist}
License: GPL
@ -144,6 +144,11 @@ true
%defattr(-,root,root)
%changelog
* Sun Jun 15 2025 Brian Read <brianr@koozali.org> 11.0.0-92.sme
- rework datetime panel [SME: 13020]
- Fix errors in error messages for local networks panel [SME: 13044]
- Add in Config Db open in Proxy.pm needed after UTF8 change [SME: 13046]
* Fri Jun 13 2025 Brian Read <brianr@koozali.org> 11.0.0-91.sme
- Port Forwarding - Same error as in local networking [SME: 13043]