### v.2.1 SUN STABLE New Features in Works
* ✔ Config. page set session expires times has to be validated not to be under 2 minutes.
-* Implement mapped provision of named timezones via main.inf, for towns not available in global list.
+* ✔ Implement mapped provision of named timezones via main.inf, for cities not available in global zone list.
* Javascript also needs to be updated to translate this properly.
* ✔ PostgreSQL to be further tested. Implement server managed database.
* On errors sessions appear not to be closed by driver, maybe this is required and they expire?
* ✔ System configuration variables should be sorted and listed by name and grouped by type. Anons presented at the bottom.
* ✔ Provide office share public link for main.inf linked categories, No login required but no log creation or search is possible.
* ✔ main.inf - Make the dbname uniform across all source types with Settings, as backups use the file format, not the database name.
-* Static pages setting for the pages directory.
-* Search on multiple words should rank by encounter of words specified and display first. (That one is difficult)
-* Provide markdown text functionality to html pages. For quick vanilla plain documentation.
-* Auto collapse/expand on multi line logs by 0-none as default. Setting to 1 or more shows only that number of lines. (That one is difficult)
* ✔ Edit button to show if hidden is the log entry section.
* ✔ Implement title bolding on logs using markdown, so tags can be avoided, for multiline logs.
* ✔ Multi db driver type support. Earth stage requires same SQL related code to work on at least one more DBMS type other than SQLight.
* PostgreSQL is the candidate as MySQL is not easy to install and bulky for all systems.
* Developing and adopting to MySQL or any other system is not prerogative, as it works well as it is with inbuilt simplicity.
+* Static pages setting for the pages directory.
+* Search on multiple words should rank by encounter of words specified and display first. (That one is difficult)
+* Provide markdown text functionality to html pages. For quick vanilla plain documentation.
+* Auto collapse/expand on multi line logs by 0-none as default. Setting to 1 or more shows only that number of lines. (That one is difficult)
### v.2.0 SUN RC2 Encountered
my $db;
my $alias = $cgi->param('alias');
my $passw = $cgi->param('passw');
-my ($debug,$frm) = "";
+my ($DBG,$frm) = "";
#Codebase release version. Release in the created db or existing one can be different, through time.
my $SCRIPT_RELEASE = Settings::release();
#anons - Are parsed end obtained only here, to be transfered to the DB config.
my $BACKUP_ENABLED = 0;
my $AUTO_SET_TIMEZONE = 0;
+my $TIME_ZONE_MAP = 0;
try{
checkAutologinSet();
<a href="https://github.com/wbudic/LifeLog" target="_blank">Get latest version of this application here!</a><br>
</center><div>);
- Settings::printDebugHTML($debug) if (Settings::debug());
+ Settings::printDebugHTML($DBG) if Settings::debug();
print $cgi->end_html;
}
my $dbg = "" ;
my $pwd = `pwd`;
$pwd =~ s/\s*$//;
- $dbg = "--DEBUG OUTPUT--\n$debug" if $debug;
+ $dbg = "--DEBUG OUTPUT--\n$DBG" if Settings::debug();
print $cgi->header,
"<hr><font color=red><b>SERVER ERROR</b></font> on ".DateTime->now().
- "<pre>".$pwd."/$0 -> &".caller." -> [\n$err]","\n$dbg</pre>",
+ "<pre>".$pwd."/$0 -> [\n$err]","\n$dbg</pre>",
$cgi->end_html;
};
exit;
# We don't need to slurp whole file as next are expected settings in begining of the config file.
open(my $fh, '<', Settings::logPath().'main.cnf' ) or LifeLogException->throw("Can't open main.cnf: $!");
while (my $line = <$fh>) {
+ chomp $line;
+ $v = Settings::parseAutonom('AUTO_LOGIN',$line);
+ if($v){@cre = split '/', $v; next}
+ $v = Settings::parseAutonom('BACKUP_ENABLED',$line);
+ if($v){$BACKUP_ENABLED = $v; next}
+ $v = Settings::parseAutonom('DBI_SOURCE',$line);
+ if($v){Settings::dbSrc($v); next}
+ $v = Settings::parseAutonom('AUTO_SET_TIMEZONE',$line);
+ if($v){$AUTO_SET_TIMEZONE = $v; next}
+ $v = Settings::parseAutonom('DBI_LOG_VAR_SIZE',$line);
+ if($v){Settings::dbVLSZ($v); next}
+ if($line =~ /<<TIME_ZONE_MAP</){
+ $TIME_ZONE_MAP = substr($line,16);
+ while ($line = <$fh>) {
chomp $line;
- $v = Settings::parseAutonom('AUTO_LOGIN',$line);
- if($v){@cre = split '/', $v; next}
- $v = Settings::parseAutonom('BACKUP_ENABLED',$line);
- if($v){$BACKUP_ENABLED = $v; next}
- $v = Settings::parseAutonom('DBI_SOURCE',$line);
- if($v){Settings::dbSrc($v); next}
- $v = Settings::parseAutonom('AUTO_SET_TIMEZONE',$line);
- if($v){$AUTO_SET_TIMEZONE = $v; next}
- $v = Settings::parseAutonom('DBI_LOG_VAR_SIZE',$line);
- if($v){Settings::dbVLSZ($v); next}
- last if Settings::parseAutonom('CONFIG',$line); #By specs the config tag, is not an autonom, if found we stop reading. So better be last one spec. in file.
+ last if($line =~ />$/);
+ $TIME_ZONE_MAP .= $line . "\n";
+ }
+ next;
+ }
+ last if Settings::parseAutonom('CONFIG',$line); #By specs the config tag, is not an autonom, if found we stop reading. So better be last one spec. in file.
}
close $fh;
if(@cre &&scalar(@cre)>1){
sub checkCreateTables {
- my $today = Settings::today();
+try{
my ($pst, $sql,$rv, $changed) = 0;
# We live check database for available tables now only once.
# Now we got a db with CONFIG, lets get settings from there.
# Default version is the scripted current one, which could have been updated.
# We need to maybe update further, if these versions differ.
- # Source default and the one from the CONFIG table in the (present) database.
- Settings::getConfiguration($db,{backup_enabled=>$BACKUP_ENABLED,auto_set_timezone=>$AUTO_SET_TIMEZONE, db_log_var_limit=>Settings::dbVLSZ()});
+ # Source default and the one from the CONFIG table in the (present) database.
+ Settings::getConfiguration($db,{
+ backup_enabled=>$BACKUP_ENABLED,auto_set_timezone=>$AUTO_SET_TIMEZONE,TIME_ZONE_MAP=>$TIME_ZONE_MAP, db_log_var_limit=>Settings::dbVLSZ()
+ });
my $DB_VERSION = Settings::release();
my $hasLogTbl = $curr_tables{'LOG'};
my $hasNotesTbl = $curr_tables{'NOTES'};
foreach my $ana(@annons){$sql .= " NAME LIKE '$ana' OR";};$sql =~ s/OR$//; $sql .=';';
$pst = Settings::selectRecords($db, $sql);
while(my @row = $pst->fetchrow_array()) {
- my ($vid,$n,$sv, $dv) = ($row[0], $row[1], Settings::anon($row[1]), $row[2]);
- $db->do("UPDATE CONFIG SET VALUE='$sv' WHERE ID=$vid;") if($dv ne $sv);
+ my ($sup,$vid,$n,$sv, $dv) = ("",$row[0], $row[1], Settings::anon($row[1]), $row[2]);
+ try{
+ if($dv ne $sv){
+ $sup = "UPDATE CONFIG SET VALUE='$sv' WHERE ID=$vid;";
+ $db->do($sup);
+ }
+ }catch{$@.="\n$sup"; die "Failed[$@]"}
}
#
# From v.1.8 Log has changed, to have LOG to NOTES relation.
$db->do(Settings::createLOGStmt());
- my $st = $db->prepare('INSERT INTO LOG(ID_CAT,DATE,LOG) VALUES (?,?,?)');
- $st->execute( 3, $today, "DB Created!");
+ my $st = $db->prepare('INSERT INTO LOG(ID_CAT,DATE,LOG) VALUES (?,?,?)');
+ $st->execute( 3, Settings::today(), "DB Created!");
$session->param("cdb", "1");
}
my $did = $r[0];
my $dnm = $r[1];
my $cmp = $dnm eq $SCRIPT_RELEASE;
- $debug .= "Upgrade cmp(RELESE_VER:'$dnm' eq Settings::release:'$SCRIPT_RELEASE') == $cmp";
+ $DBG .= "Upgrade cmp(RELESE_VER:'$dnm' eq Settings::release:'$SCRIPT_RELEASE') == $cmp";
#Settings::debug(1);
if(!$cmp){
Settings::renumerate($db);
else{
$pv = 0;
}
- &Settings::configProperty($db, 200, '^REL_RENUM',$pv);
- &Settings::configProperty($db, $did>0?$did:0, 'RELEASE_VER', $SCRIPT_RELEASE);
- &Settings::toLog($db, "Upgraded Life Log from v.$dnm to v.$SCRIPT_RELEASE version, this is the $pv upgrade.") if $pv;
+ Settings::configProperty($db, 200, '^REL_RENUM',$pv);
+ Settings::configProperty($db, $did>0?$did:0, 'RELEASE_VER', $SCRIPT_RELEASE);
+ Settings::toLog($db, "Upgraded Life Log from v.$dnm to v.$SCRIPT_RELEASE version, this is the $pv upgrade.") if $pv;
}
&populate($db);
}
#Then we check if we are login in intereactively back. Interective, logout should bring us to the login screen.
#Bypassing auto login. So to start maybe working on another database, and a new session.
return $cgi->param('autologoff') == 1;
-
+}catch{
+ LifeLogException -> throw(error=>$@,show_trace=>1);
+}
}
my @arr = Settings::selectRecords($db,"SELECT ID FROM CONFIG WHERE NAME LIKE '$name';")->fetchrow_array();
$inData = 1;
if(!@arr) {
- $debug .= "conf.ins->".$name.",".$value.",".$tick[1]."\n";
+ $DBG .= "conf.ins->".$name.",".$value.",".$tick[1]."\n";
if(Settings::isProgressDB()) {$insCnf->execute($name,$value,$tick[1])}
else{$insCnf->execute($id,$name,$value,$tick[1])}
}
# Then check if the ID is available. If not just skip, the import. Reseting can fix that latter.
if(!Settings::selectRecords($db, "SELECT ID FROM CAT WHERE NAME LIKE '$pair[1]';")->fetchrow_array()) {
if(!Settings::selectRecords($db, "SELECT ID FROM CAT WHERE ID = $pair[0];")->fetchrow_array()){
- $debug .= "cat.ins->".$pair[0].",".$pair[1].",".$tick[1]."\n";
+ $DBG .= "cat.ins->".$pair[0].",".$pair[1].",".$tick[1]."\n";
$insCat->execute($pair[0],$pair[1],$tick[1]);
}
}
my $dbg = "" ;
my $pwd = `pwd`;
$pwd =~ s/\s*$//;
- $dbg = "--DEBUG OUTPUT--\n$debug" if $debug;
+ $dbg = "--DEBUG OUTPUT--\n$DBG" if Settings::debug();
print $cgi->header,
"<font color=red><b>SERVER ERROR</b></font> on ".DateTime->now().
"<pre>".$pwd."/$0 -> &".caller." -> [$err]","\n$dbg</pre>",
}
}
- if ( $aw_cnt > &Settings::autoWordLimit ) {
+ if ( $aw_cnt > Settings::autoWordLimit() ) {
last;
}
}
$BUFFER = $cgi->start_html(
-title => "Personal Log",
-BGCOLOR => $BGCOL,
- -onload => "onBodyLoad('$toggle','".&Settings::timezone."','$today','".&Settings::sessionExprs."','$rs_cur',".&Settings::dbVLSZ.");",
+ -onload => "onBodyLoad('$toggle','".&Settings::language."','".&Settings::timezone."','$today','".&Settings::sessionExprs."','$rs_cur',".&Settings::dbVLSZ.");",
-style => [
{ -type => 'text/css', -src => "wsrc/$TH_CSS" },
{ -type => 'text/css', -src => 'wsrc/jquery-ui.css' },
#201 -> '^EXCLUDES' : 0 (Used in main.cgi)
our $SQL_PUB = undef;
+our $TIME_ZONE_MAP ="";
sub anons {my @ret=sort(keys %anons); return @ret;}
#Check call with defined(Settings::anon('my_anon'))
return $DBI_SOURCE}
sub dbVLSZ {my $r = shift; if(!$r){$r = $DBI_LVAR_SZ}else{$r=128 if($r<128);$DBI_LVAR_SZ=$r} return $r}
sub dbFile {my $r = shift; if($r) {$DBFILE=$r} return $DBFILE}
-sub dbName {return $dbname;}
+sub dbName {return $dbname}
sub dsn {return $DSN}
sub isProgressDB {return $IS_PG_DB}
sub sqlPubors {return $SQL_PUB}
}
sub today {
- my $ret = DateTime->now();
- if(!$anons{'auto_set_timezone'}){
- setTimezone($ret);
- }
+ my $ret = setTimezone();
return $ret;
}
+#Call after getConfig subroutine. Returns DateTime->now() set to timezone.
sub setTimezone {
- my $ret = shift;
- my $to = shift; #optional for testing purposes.
- my $v= $anons{'TIME_ZONE_MAP'};
- if($v){
- if(!%tz_map){
- %tz_map={}; chomp($v);
- foreach (split('\n',$v)){
- my @p = split('=', $_);
- $tz_map{trim($p[0])} = trim($p[1]);
- }
- }
- if($to){$v = $tz_map{$to};}else{$v = $tz_map{$TIME_ZONE};}
- if($v){$TIME_ZONE=$v}
+ my $to = shift; #optional for testing purposes.
+ my $ret = DateTime->now();
+ if(!$anons{'auto_set_timezone'}){
+ if($TIME_ZONE_MAP){
+ if(!%tz_map){
+ %tz_map={}; chomp($TIME_ZONE_MAP);
+ foreach (split('\n',$TIME_ZONE_MAP)){
+ my @p = split('=', $_);
+ $tz_map{trim($p[0])} = trim($p[1]);
+ }
+ }
+ my $try = $tz_map{$TIME_ZONE};
+ $try = $tz_map{$to} if(!$try);
+ if($try){
+ $TIME_ZONE = $try; #translated to mapped lib. provided zone.
+ $ret -> set_time_zone($try);
+ }
+ else{
+ try{#maybe current setting is valid and the actual one?
+ $ret -> set_time_zone($TIME_ZONE);
+ }catch{
+ SettingsException->throw(error=>"Zone not mapped:$TIME_ZONE\n<b>Available zones:</b>\n$TIME_ZONE_MAP\n", show_trace=>$DEBUG);
+ }
+ }
+ }
+ }else{
+ $ret -> set_time_zone($TIME_ZONE);
}
- $ret = DateTime->now() if(!$ret);
- $ret -> set_time_zone($TIME_ZONE);
return $ret;
}
CREATE TABLE CONFIG(
ID INT NOT NULL UNIQUE GENERATED BY DEFAULT AS IDENTITY ( INCREMENT 1 START 1 MINVALUE 1 MAXVALUE 2147483647 CACHE 1 ),
NAME VARCHAR(28) UNIQUE,
- VALUE VARCHAR(28),
+ VALUE VARCHAR(128),
DESCRIPTION VARCHAR(128),
PRIMARY KEY(ID)
);
CREATE TABLE CONFIG(
ID INT PRIMARY KEY NOT NULL,
NAME VCHAR(16) UNIQUE,
- VALUE VCHAR(28),
+ VALUE VCHAR(128),
DESCRIPTION VCHAR(128)
);
CREATE INDEX idx_config_name ON CONFIG (NAME);
sub getConfiguration {
my ($db, $hsh) = @_;
+ my $fh;
+ my $ftzmap = $ENV{'PWD'}.'tz.map';
try {
my $st = $db->prepare("SELECT ID, NAME, VALUE FROM CONFIG;");
$st->execute();
when ("SESSN_EXPR") {$SESSN_EXPR = $r[2]}
when ("DATE_UNI") {$DATE_UNI = $r[2]}
when ("LANGUAGE") {$LANGUAGE = $r[2]}
- when ("LOG_PATH") {} #ommited and code static can't change for now.
+ when ("LOG_PATH") {} # Ommited and code static can't change for now.
when ("IMG_W_H") {$IMG_W_H = $r[2]}
when ("REC_LIMIT") {$REC_LIMIT = $r[2]}
when ("AUTO_WRD_LMT"){$AUTO_WRD_LMT = $r[2]}
default {$anons{$r[1]} = $r[2]}
}
}
- #Anons are murky grounds. -- @bud
+ #Anons are murky grounds. -- @bud
if($hsh){
+ my %m = %{$hsh};
+ $TIME_ZONE_MAP = $m{'TIME_ZONE_MAP'}; #This can be a large mapping we file it to tz.map, rather then keep in db.
+ delete($m{'TIME_ZONE_MAP'});
+ if($TIME_ZONE_MAP && !(-e $ftzmap)) {
+ open($fh, '>', $ftzmap) or LifeLogException->throw( "Can't write to $ftzmap: $!");
+ print $fh $TIME_ZONE_MAP;
+ close $fh;
+ }#else{
+ # SettingsException -> throw(error=>"Missing anon TIME_ZONE_MAP! $TIME_ZONE_MAP ",show_trace=>1);
+ # }
my $stIns = $db->prepare("INSERT INTO CONFIG (ID, NAME, VALUE, DESCRIPTION) VALUES(?,?,?,?)");
- foreach my $key (keys %{$hsh}){
+ foreach my $key (keys %m){
if(index($key,'$')!=0){#per spec. anons are not prefixed with an '$' as signifier.
- my $val = %{$hsh}{$key};
+ my $val = $m{$key};
my $existing = $anons{$key};
#exists? Overwrite for $self config but not in DB! (dynamic code base set anon)
$anons{$key} = $val;
}
}
}
+
}
+ elsif #At times not passing in the hash of expected anons we read in the custom tz map file if it exists.
+ (-e $ftzmap){ open($fh, "<:perlio", $ftzmap) or LifeLogException->throw( "Can't open $ftzmap: $!");
+ read $fh, $TIME_ZONE_MAP, -s $fh;
+ close $fh;
+ }
+ &setTimezone;
}
catch {
SettingsException->throw(error=>$@, show_trace=>$DEBUG);
};
}
-
sub getTheme {
given ($THEME){
when ("Sun") { $BGCOL = '#D4AF37'; $TH_CSS = "main_sun.css"; }
}
try{
return DBI->connect($DSN, $a, $p, {AutoCommit => 1, RaiseError => 1, PrintError => 0, show_trace=>1});
- }catch{
- LifeLogException->throw(error=>"<p>Error->$@</p>", show_trace=>1);
+ }catch{
+ LifeLogException->throw(error=>"<p>Error->$@</p>", show_trace=>1);
}
}
use lib $ENV{'PWD'}.'/htdocs/cgi-bin/system/modules';
require CNFParser;
+
+# my $TIME_ZONE_MAP ="";
+# open(my $fh, '<',$ENV{'PWD'}.'/dbLifeLog/main.cnf') or LifeLogException->throw("Can't open main.cnf: $!");
+# while (my $line = <$fh>) {
+# chomp $line;
+# if($line =~ /<<TIME_ZONE_MAP</){
+# $TIME_ZONE_MAP = substr($line,16);
+# while ($line = <$fh>) {
+# chomp $line;
+# last if($line =~ />$/);
+# $TIME_ZONE_MAP .= $line . "\n";
+# }
+# }
+
+# last if Settings::parseAutonom('CONFIG',$line); #By specs the config tag, is not an autonom, if found we stop reading. So better be last one spec. in file.
+# }
+# close $fh;
+
+
+# print "$TIME_ZONE_MAP\n";
+
+
# Settings obtains from file escalated for anons to database configuration
# Currently we don't have an database set, and don't need it for this tester script.
# So we read and process the main.cnf file in via parser and transfer into Settings;
#TODO
-my %countries = {};
-my @states;
+my %regions = {};
+my @cities;
foreach my $zone (sort @zones){
$zone =~ s/\"//g;
my @p = split /\//, $zone;
- my $country = $p[0];
- my $city = $p[1];
- my $region = $p[2];
-
- if(length($country)==0){next;}
-
- if($region){
- $city = "$region/$city";
+ #America/Argentina/Rio_Gallegos
+ my $region = $p[0];
+ my $country = $p[1];
+ my $city = $p[2];
+ if(!$city){
+ $city = $country;
+ $country = $region;
}
- my $def = "$country/$city";
-
- if(exists($countries{$country})){
- $states = $countries{$country};
+
+ if(exists($regions{$region})){
+ @cities =@{ $regions{$region} };
}else{
- $states = ();
- push (@{$countries{$country}}, $states);
- # print "[$country] created list!\n";
+ @cities = ();
+ $regions{$region} = \@cities;
}
- push @{$states}, "$country/$city";
- #print "$zone<br>\n";
+ push @cities, "$country/$city";
}
+sub trim {my $r=shift; $r=~s/^\s+|\s+$//g; return $r}
print "<center>";
-print "<h2 class='rz' style='text-align:center;border-bottom: 0px cornflowerblue;'>World Time Zone Strings</h2>\n";
-foreach my $key (sort keys %countries){
- $states = $countries{$key};
- if( length($states)>0 ){
+print "<h2 class='rz' style='text-align:center;'>World Time Zone Strings</h2><br>\n";
+my $ftzmap = $ENV{'PWD'}.'tz.map';
+if(-e $ftzmap){
+ my $TIME_ZONE_MAP = "";
+ open($fh, "<:perlio", $ftzmap) or LifeLogException->throw( "Can't open $ftzmap: $!");
+ read $fh, $TIME_ZONE_MAP, -s $fh;
+ close $fh;
+ print "<div class='rz' style='text-align:left;border-bottom: 0px cornflowerblue;'><b>Custom Mapped in $ftzmap</b></div>\n";
+ print "<div class='rz' style='text-align:left;'><ul>\n";
+ foreach (split('\n',$TIME_ZONE_MAP)){
+ my @p = split('=', $_);
+ if($p[0]){
+ my $mapped = trim($p[0]);
+ print "<li><a href=\"config.cgi?tz=$mapped\">$mapped</a></li>";
+ }
+ }
+ print "</ul></div>\n";
+ print "</div><br>\n";
+}
+foreach my $key (sort keys %regions){ if(!$key){next}
+ my @country = @{$regions{$key}};
+ if( @country>0 ){
print "<div class='rz' style='text-align:left;border-bottom: 0px cornflowerblue;'><b>$key</b></div>\n";
print "<div class='rz' style='text-align:left;'><ul>\n";
- foreach $entry (sort @{$states}){
+ foreach my $entry (sort @country){
if(!$entry){next}
- foreach $city ($entry){
+ foreach my $city ($entry){
if($city){
print "<li><a href=\"config.cgi?tz=$city\">$city</a></li>";
}
var RTF_DOC_RESIZED = false;
var RTF_DOC_ORIG;
var TIME_STAMP;
+var LOCALE;
var TIMEZONE;
var DBI_LVAR_SZ;
function onBodyLoadGeneric() {
$("input[type=submit], input[type=reset], .ui-widget-content, button, .a_").button();
$("#btn_save_doc").button();
+ if(!LOCALE || LOCALE==="English"){
+ LOCALE = "en-US";
+ }
}
-function onBodyLoad(toggle, tz, today, expires, rs_cur, log_limit) {
+function onBodyLoad(toggle, locale, tz, today, expires, rs_cur, log_limit) {
- TIMEZONE = tz;
+ LOCALE = locale;
+ TIMEZONE = tz;
TIME_STAMP = new Date(today);
DBI_LVAR_SZ = parseInt(log_limit);
onBodyLoadGeneric();
var date = document.getElementById("frm_entry").date;
var dt = new Date();
- var mm = fix0(dt.getMonth() + 1);
- var dd = fix0(dt.getDate());
- date.value = dt.getFullYear() + "-" + mm + "-" + dd + " " +
- fix0(dt.getHours()) + ":" + fix0(dt.getMinutes()) + ":" + fix0(dt.getSeconds());
+ let options = {timeZone: TIMEZONE};
+ let [month, day, year] = dt.toLocaleDateString(LOCALE, options).split("/")
+ let [hour, minute, seconds] = dt.toLocaleTimeString(LOCALE, options).split(/:| /);
+ month = fix0(month); day = fix0(day);
+ hour = fix0(hour); minute = fix0(minute); seconds = fix0(seconds);
+
+ date.value = year + "-" + month + "-" + day + " " + hour + ":" + minute + ":" + seconds;
$("#submit_is_edit").val("0");
toggleDoc(true);
return false;
}
function fix0(v) {
+ v = parseInt(v);
if (v < 10) {
return "0" + v;
}