From: kilian (ksmachome) Date: Sun, 29 Dec 2019 07:29:49 +0000 (+0100) Subject: v20191228 X-Git-Url: http://cloud.dks.lu/git/?a=commitdiff_plain;h=736fe7bc8cd894d75c6b327349c1659325c1a763;p=saffran_lu.git v20191228 --- diff --git a/.htaccess b/.htaccess new file mode 100755 index 0000000..4cb122b --- /dev/null +++ b/.htaccess @@ -0,0 +1,17 @@ +#RewriteEngine On +#RewriteCond %{SERVER_PORT} 80 +#RewriteRule ^(.*)$ https://www.dks.lu/$1 [R,L] +#AddType application/octet-stream .pdf +#SetEnv PERL5LIB "/home/kilian/perl5/lib/perl5" +RewriteEngine on +#dev-mode begin +DirectoryIndex index.cgi index.html +AddHandler cgi-script .cgi +#devmode end +RewriteCond %{REQUEST_FILENAME} !-f +RewriteCond %{REQUEST_FILENAME} !-d + +#RewriteCond %{REQUEST_URI} !/dks_lu/apps/.* +RewriteRule "^(.*)$" "index.cgi" [NC,L,QSA] +#RewriteCond %{REQUEST_URI} !/dks_lu/apps/api/.* +#RewriteRule "^(.*)$" "apps/index.cgi?p=" [NC,L,QSA] diff --git a/backoffice/.htaccess b/backoffice/.htaccess new file mode 100644 index 0000000..ff153d9 --- /dev/null +++ b/backoffice/.htaccess @@ -0,0 +1,9 @@ +RewriteEngine on + +DirectoryIndex index.cgi index.html +AddHandler cgi-script .cgi +#RewriteBase / +RewriteCond %{REQUEST_FILENAME} !-f +RewriteCond %{REQUEST_FILENAME} !-d + +RewriteRule "^(.*)$" "index.cgi" [NC,L,QSA] \ No newline at end of file diff --git a/backoffice/api/db.cgi b/backoffice/api/db.cgi new file mode 100755 index 0000000..5233b5c --- /dev/null +++ b/backoffice/api/db.cgi @@ -0,0 +1,108 @@ +#!/Users/kilian/perl5/perlbrew/perls/perl-5.24.1/bin/perl +use strict; +use lib ('./lib/perl5'); +use lib ('./lib'); +use CGI; +use CGI::Cookie; +# use CGI::Carp qw/fatalsToBrowser/; +use File::Basename; +use JSON::PP; + +use dksconfig qw/$sitecfg/; +use dksdb; + +use session; +#use sendemail; +my $cgi = new CGI(); +my $scriptpath = $cgi->url(-absolute => 1); +my $p = (); +my @params = $cgi->param(); +foreach my $pe (@params){ + $p->{$pe} = $cgi->param($pe); +} +my $html->{result} = (); +$p->{sid} = $cgi->cookie($sitecfg->{cookiename}); +my $se = session->new(); +my $sess = $se->getsession($p->{sid}); +print $cgi->header(-type=>"application/json", -charset => "utf-8"); +if ($sess == undef){ + $html->{error} = "No Authorisation"; + print JSON::PP::encode_json($html); + exit(0); +} +# $html->{p} = $p; +# $html->{sess} =$sess; +#my $datapath = $ENV{"DOCUMENT_ROOT"}.dirname(dirname($scriptpath)).'/data/'; +if (($cgi->request_method() eq "GET") || ($cgi->request_method() eq "POST")){ + + my @params = $cgi->param(); + foreach my $pp (@params){ + $p->{$pp} = $cgi->param($pp); + } + my $db = dksdb->new(); + if (exists($p->{get})){ + my $schema = "public"; + if (exists($p->{schemata})){ + $schema = $p->{schemata}; + } + my $sql = "select * from ".$schema.".vw_".$p->{get}; + if (exists($p->{fields}) ){ + $sql = "select ".$p->{fields}." from ".$schema.".vw_".$p->{get}; + } + if (exists($p->{filter})){ + $sql .= " WHERE ".$p->{filter}.";"; + } + $html->{result}->{sqldata} = $db->dbqueryarray($sql); + } + elsif (exists($p->{set})){ + my $type = "ins"; + foreach my $x (keys(%{$p})){ + if (($x =~ /^ident_/) && ($p->{$x} ne "")){ + $type = "upd"; + last; + } + } + my $x = $p; + delete $x->{sid}; + delete $x->{set}; + my @sql = (); + if ($type eq "ins"){ + @sql = $db->create_ddl_insert($x); + }else { + @sql = $db->create_ddl_update($x); + } + if (scalar(@sql) > 0 ){ + my $rid = $db->dbquerysorted($sql[0]); + if (keys(%{$rid}) > 0 ){ + $html->{result} = $rid->{0}; + } + } + } + elsif (exists($p->{del})){ + my $x = $p; + delete $x->{sid}; + delete $x->{del}; + my @sql = $db->create_ddl_delete($x); + if (scalar(@sql) > 0 ){ + my $rid = $db->dbexec($sql[0]); + if (keys(%{$rid}) > 0 ){ + $html->{result} = $rid->{0}; + } + } + } + elsif (exists($p->{del2})){ + my $x = $p; + my $schema = "public"; + if (exists($p->{schemata})){ + $schema = $db->securetext($p->{schemata}); + } + my $rid = $db->dbexec("DELETE FROM ".$schema.".".$db->securetext($p->{table})." WHERE id='".$db->securetext($p->{id})."';"); + if (keys(%{$rid}) > 0 ){ + $html->{result} = $rid->{0}; + } + } +} +print JSON::PP::encode_json($html); +# for my $e ( keys %ENV ) { +# print "$e: $ENV{$e}
"; +# } \ No newline at end of file diff --git a/backoffice/api/file.cgi b/backoffice/api/file.cgi new file mode 100755 index 0000000..f0af54d --- /dev/null +++ b/backoffice/api/file.cgi @@ -0,0 +1,136 @@ +#!/Users/kilian/perl5/perlbrew/perls/perl-5.24.1/bin/perl + +use strict; +use lib ('./lib/perl5'); +use lib ('./lib'); +use CGI; +use CGI::Cookie; +# use CGI::Carp qw/fatalsToBrowser/; +use File::Basename; +use File::Path qw/make_path/; +use JSON::PP; +use Image::Size; +use dksconfig qw/$sitecfg/; +use dksdb; + +use session; +#use sendemail; +my $cgi = new CGI(); +my $scriptpath = $cgi->url(-absolute => 1); +my $p = (); +my @params = $cgi->param(); +foreach my $pe (@params){ + $p->{$pe} = $cgi->param($pe); +} +# if ($sitecfg->{basepath} ne "/"){ +$sitecfg->{docroot} = $sitecfg->{docroot}.substr($sitecfg->{basepath},0,index($sitecfg->{basepath},'backoffice')-1); +# } +my $html->{result} = (); +$p->{sid} = $cgi->cookie($sitecfg->{cookiename}); +my $se = session->new(); +my $sess = $se->getsession($p->{sid}); +print $cgi->header(-type=>"application/json", -charset => "utf-8"); +if ($sess == undef){ + $html->{error} = "No Authorisation"; + print JSON::PP::encode_json($html); + exit(0); +} +$html->{docroot} = $sitecfg->{docroot}; +# $html->{basepath} = $sitecfg->{basepath}; +if (($cgi->request_method() eq "GET") || ($cgi->request_method() eq "POST")){ + + if (exists($p->{fn}) && $p->{fn} eq "list"){ + if (exists($p->{folder})){ + + $p->{folder} =~ s/\.\.\///g; + my $cpath = $sitecfg->{docroot}.'/'.$p->{folder}; + my @items = (); + my $up = (); + # if (index($p->{folder},'/') > 0){ + # $up->{type} = "dir"; + # $up->{name} = ".."; + # $up->{sitepath} = $p->{folder}; + # $up->{path} = $p->{folder}; + # $up->{mimtype} = 'directory'; + # $up->{size} = ''; + # $up->{dimension}; + # $up->{thumb} = ''; + # push (@items,$up); + # } + opendir(DIR,$cpath); + + while (my $d = readdir(DIR)){ + if ($d =~ /^\./){ next; } + if ($d eq "thb"){ next; } + my $e = (); + if (-d $cpath.'/'.$d){ + $e->{type} = "dir"; + $e->{name} = $d; + $e->{sitepath} = $p->{folder}.'/'.$d; + $e->{path} = $p->{folder}.'/'.$d; + $e->{mimtype} = 'directory'; + $e->{size} = ''; + + my $cmd = 'find "'.$cpath.'/'.$d.'" -type f | grep -v \'/thb/\' | wc -l'; + my $dim = `$cmd`; + chomp($dim); + $e->{dimension} = $dim; + + $e->{thumb} = ''; + } + if (-f $cpath.'/'.$d){ + my $cmd = 'file -i "'.$cpath.'/'.$d.'" | awk -F": " \'{ print $2 }\' | awk -F";" \'{ print $1 }\''; + my $mt = `$cmd`; + chomp($mt); + #if (($mt !~ /^image/ ) || ($mt !~ /^application\/pdf/ )) { next; } + if (($mt =~ /^image/ ) || ($mt !~ /^application\/pdf/ )) { + if (! -f $cpath.'/thb/'.$d.'.thb.png'){ + if (! -d $cpath.'/thb'){ + make_path($cpath.'/thb'); + } + system('convert -thumbnail x96 -background white -alpha remove "'.$cpath.'/'.$d.'" "'.$cpath.'/thb/'.$d.'.thb.png"'); + } + if ($mt =~ /^image/ ){ + my ($ix, $iy) = imgsize($cpath.'/'.$d); + $e->{dimension} = $ix."x".$iy; + } + } + my @st = stat($cpath.'/'.$d); + $e->{type} = "file"; + $e->{mimetype} = $mt; + my $s = $st[7]; + my $hrs =""; + if ($s > 1000000024){ + $s = $s/1024; + $s = $s/1024; + $s = $s/1024; + ($hrs) = $s =~ m/^(\d+\.\d\d).*/; + $hrs = $hrs." GB"; + } elsif ($s > 1000024){ + $s = $s/1024; + $s = $s/1024; + ($hrs) = $s =~ m/^(\d+\.\d\d).*/; + $hrs = $hrs." MB"; + } elsif ($s > 1024){ + $s = $s/1024; + ($hrs) = $s =~ m/^(\d+\.\d\d).*/; + $hrs = $hrs." KB"; + } else { + $hrs = $s." B"; + } + $e->{hrsize} = $hrs; + $e->{size} = $st[7]; + $e->{name} = $d; + $e->{sitepath} = $p->{folder}.'/'.$d; + $e->{thumb} = ''; + $e->{path} = '../../../'.$p->{folder}.'/'.$d; + } + push (@items,$e); + } + closedir(DIR); + $html->{result} = \@items; + + } + } +} +print JSON::PP::encode_json($html); diff --git a/backoffice/api/index.cgi b/backoffice/api/index.cgi new file mode 100755 index 0000000..56cf968 --- /dev/null +++ b/backoffice/api/index.cgi @@ -0,0 +1,177 @@ +#!/Users/kilian/perl5/perlbrew/perls/perl-5.24.1/bin/perl +use strict; +use lib ('./lib/perl5'); +use lib ('./lib'); +use CGI; +use CGI::Cookie; +#use CGI::Carp qw/fatalsToBrowser/; +use File::Basename; +use Business::Tax::VAT::Validation; +use JSON::PP; + +use dksconfig qw/$sitecfg/; +use dksdb; + +use session; +use sendemail; +my $cgi = new CGI(); +my $scriptpath = $cgi->url(-absolute => 1); +my $p = (); +my @params = $cgi->param(); +foreach my $pe (@params){ + $p->{$pe} = $cgi->param($pe); +} +my $html->{result} = (); +$p->{sid} = $cgi->cookie($sitecfg->{cookiename}); +my $se = session->new(); +my $sess = $se->getsession($p->{sid}); +print $cgi->header(-type=>"application/json", -charset => "utf-8"); +if ($sess == undef){ + $html->{error} = "No Authorisation"; + print JSON::PP::encode_json($html); + exit(0); +} +$html->{p} = $p; +# $html->{sess} =$sess; +#my $datapath = $ENV{"DOCUMENT_ROOT"}.dirname(dirname($scriptpath)).'/data/'; +if (($cgi->request_method() eq "GET") || ($cgi->request_method() eq "POST")){ + my @params = $cgi->param(); + foreach my $pp (@params){ + $p->{$pp} = $cgi->param($pp); + } + + if (exists($p->{fn})){ + + my $db = dksdb->new(); + # if ($p->{fn} eq "savefield"){ + # # $html->{p} = $p; + # $html->{result}->{ident} = $p->{ident}; + # delete $p->{ident}; + # delete $p->{fn}; + # delete $p->{sid}; + # my $retid=undef; + # my $type = "upd"; + # foreach my $px (keys(%{$p})){ + # $html->{result}->{datafield} = $px; + # if (($px =~ /\_id$/) && ($p->{$px} eq "")){ + # $type = "ins"; + + # } + # } + # my @sql = (); + # if ($type eq "ins"){ + # @sql = $db->create_ddl_insert($p); + # } + # else { + # @sql = $db->create_ddl_update($p); + # } + # $html->{result}->{sql} = \@sql; + # foreach my $s (@sql){ + # $retid= $db->dbquerysorted($s); + # } + # $html->{result}->{id} = $retid->{0}; + # #$p->{table},#$p->{field},$p->{value},$p->{id},$p->{type} + # } + + if ($p->{fn} eq "saveform"){ + # $html->{p} = $p; + $html->{result}->{ident} = $p->{ident}; + delete $p->{ident}; + delete $p->{fn}; + delete $p->{sid}; + my $retid=undef; + my $type = "upd"; + foreach my $px (keys(%{$p})){ + $html->{result}->{datafield} = $px; + if (($px =~ /\_id$/) && ($p->{$px} eq "")){ + $type = "ins"; + delete $p->{$px}; + } + } + my @sql = (); + if ($type eq "ins"){ + @sql = $db->create_ddl_insert($p); + } + else { + @sql = $db->create_ddl_update($p); + } + #$html->{sql} = \@sql; + foreach my $s (@sql){ + #if ($type eq "ins"){ + $retid= $db->dbquerysorted($s); + #}else { + + #} + + } + $html->{result}->{id} = $retid->{0}; + #$p->{table},#$p->{field},$p->{value},$p->{id},$p->{type} + } + if($p->{fn} eq "deleterow"){ + delete $p->{fn}; + delete $p->{sid}; + my $retid = undef; + my @sql = $db->create_ddl_delete($p); + foreach my $s (@sql){ + $retid= $db->dbexec($s); + } + $html->{result}->{id} = $retid->{0}; + } + if($p->{fn} eq "savepassword"){ + if ((length($p->{pwd}) > 7) && ($p->{pwd} =~ /\d/) && ($p->{pwd} =~ /[a-z]/) && ($p->{pwd} =~ /[A-Z]/) ){ + $se->savepassword($sess->{id},$p->{pwd}); + $html->{result} = "OK"; + }else { + $html->{result} = "NOT OK"; + } + + } + if ($p->{fn} eq "sendmailvcode"){ + my $vcode = $se->randomstring(6); + $vcode = lc($vcode); + $db->dbexec("UPDATE users set vcode='".$vcode."' where id=".$sess->{id}.";"); + my $eml = sendemail->new(); + my $mret = $eml->sendemail('user_verification',$sess->{id},$p->{mail},{vcode => $vcode},undef); + if ($mret == 0){ + $html->{result}->{vcode} = $vcode; + } else { + $html->{result}->{vcode} = $vcode; + $html->{result}->{error} = $mret; + } + } + if ($p->{fn} eq "savenewemail"){ + $db->dbexec("update users set username='".$p->{email}."' where id=".$sess->{id}." and vcode='".$p->{vcode}."';"); + $html->{result} = "OK"; + } + if($p->{fn} eq "getsitemedia"){ + my $path = dirname(dirname($0)).'/img'; + } + if ($p->{fn} eq "checkvat"){ + my $hvatn=Business::Tax::VAT::Validation->new(); + my $VAT=$p->{vatnumber}; + $VAT =~ s/\s+//g; + if ($hvatn->check($VAT)){ + $html->{result} = $hvatn->informations(); + } else { + $html->{result} = $hvatn->get_last_error; + } + } + if ($p->{fn} eq "getfreeschema"){ + my $cmpy = lc($p->{companyname}); + $cmpy =~ s///; + $cmpy =~ s/[^a-z0-9\-]/\_/g; + $cmpy =~ s/^[\_]+//; + $cmpy =~ s/[\_]+$//; + $cmpy =~ s/^[\_]+/_/; + my $schemasql = "select count(*) as cnt from information_schema.schemata where schema_name='".$db->securetext($p->{schemaname})."';"; + my $dbschema = $db->dbquery($schemasql); + my $dbsnum = ""; + if ($dbschema->{cnt} > 1){ + $dbsnum = int($dbschema->{cnt}) + 1; + } + $html->{result}->{newschema} = $cmpy.$dnsnum; + } + } + +} +print JSON::PP::encode_json($html); diff --git a/backoffice/api/lib/dksconfig.pm b/backoffice/api/lib/dksconfig.pm new file mode 100644 index 0000000..17c9ea8 --- /dev/null +++ b/backoffice/api/lib/dksconfig.pm @@ -0,0 +1,28 @@ +package dksconfig; + +use strict; +use lib ('./lib/perl5'); +use lib ('./lib'); +use lib ('./'); +use File::Basename; +use Exporter 'import'; +our @EXPORT_OK = qw($sitecfg); + +our $sitecfg ={ + cookiename => 'potlu', + dbtype => 'PgPP', + dsn => 'DBI:PgPP:dbname=potlu_db;host=DKS-LAPTOP.fritz.box', + #dsn => 'DBI:PgPP:dbname=solarch_db;host=sql629.your-server.de', + dbuser => 'potlu_user', + dbpassword => 'r2btTTRfuJz4whez', + page => 'index.tt', + pagename => 'index', + basepath => substr((exists($ENV{"SCRIPT_FILENAME"})?dirname($ENV{"SCRIPT_FILENAME"}):dirname($0)),length($ENV{"DOCUMENT_ROOT"})), + datapath => substr((exists($ENV{"SCRIPT_FILENAME"})?dirname($ENV{"SCRIPT_FILENAME"}):dirname($0)),length($ENV{"DOCUMENT_ROOT"})).'/data/', + docroot => $ENV{"DOCUMENT_ROOT"}, + registration_enabled => '0', + default_group => 'users', + sitename => 'Accès - Client' +}; + +1; \ No newline at end of file diff --git a/backoffice/api/lib/dksdb.pm b/backoffice/api/lib/dksdb.pm new file mode 100644 index 0000000..13c1d5a --- /dev/null +++ b/backoffice/api/lib/dksdb.pm @@ -0,0 +1,390 @@ +package dksdb; + +use strict; +use lib ('./lib/perl5'); +use lib ('./lib'); +use lib ('./'); +BEGIN { $ENV{DBI_PUREPERL} = 2 } +use DBI; +use File::Basename; + +use Digest::SHA::PurePerl qw(sha256_hex); +use DBD::PgPP; +use URI::Encode qw(uri_encode uri_decode); +use Encode; +use dksconfig qw($sitecfg); +use Text::Unidecode; + + +sub new { + my $class = shift; + my $p = shift; + my $self = bless {}, $class; + return $self; +} + +sub securetext(){ + my $self = shift; + my $text = shift; + $text =~ s/'/''/g; + return $text; +} + +sub dbquery(){ + my $self = shift; + my $stat = shift; + # my $vw_info = shift; + my $retdata = undef; + my $dbh = DBI->connect($sitecfg->{dsn},$sitecfg->{dbuser},$sitecfg->{dbpassword},{PrintError=>0,RaiseError=>0,AutoCommit=>1}) or return $retdata->{error} = "dbquery Connection Error!".$!; + $stat = encode("utf8", $stat); + # open FILE,">>tmp/sql.log"; + # print FILE "$stat\n"; + # close FILE; + my $sth = $dbh->prepare($stat) or return $retdata->{error} = "dbquery".$dbh->errstr. "- SQL: ".$stat;; + + + $sth->execute() or return $retdata->{error} = "dbquery: ".$sth->errstr; + + my $data = $sth->fetchrow_hashref(); + foreach my $k (keys %{$data}){ + $retdata->{$k} = decode("utf-8",$data->{$k}); + } + + $sth->finish(); + $dbh->disconnect(); + + return $retdata; +} + +sub dbquerybykey(){ + my $self = shift; + my $key = shift; + my $stat = shift; + #my $retempty = shift; + my $retdata =(); + my $dbh = DBI->connect($sitecfg->{dsn},$sitecfg->{dbuser},$sitecfg->{dbpassword},{PrintError=>0,RaiseError=>0,AutoCommit=>1}) or return $retdata->{error} = "dbquery Connection Error!".$!; + # $stat = encode("utf8", $stat); + + # open FILE,">>sql.log"; + # print FILE "$stat\n"; + # close FILE; + my $sth = $dbh->prepare($stat) or return $retdata->{error} = "dbquery: ".$stat; + $sth->execute() or return $retdata->{error} = "dbquery: ".$stat; + while(my $data = $sth->fetchrow_hashref()) + { + if (exists $data->{$key}){ + foreach my $k (keys %{$data}){ + #if ($k ne $key){ + + $retdata->{$data->{$key}}{$k} =decode("utf-8",$data->{$k}); + #} + } + } + } + if (keys(%{$retdata}) == 0){ + $retdata =(); + } + $sth->finish(); + $dbh->disconnect(); + return $retdata; +} + +sub dbquerysorted(){ + my $self = shift; + my $stat = shift; + # my $vw_info = shift; + my $retdata; + my $dbh = DBI->connect($sitecfg->{dsn},$sitecfg->{dbuser},$sitecfg->{dbpassword},{PrintError=>0,RaiseError=>0,AutoCommit=>1}) or return $retdata->{error} = "dbquery Connection Error!".$!; + # $stat = encode("utf8", $stat); + # open FILE,">>tmp/sql.log"; + # print FILE "\n==\n$stat\n==\n"; + # close FILE; + my $sth = $dbh->prepare($stat) or return $retdata->{error} = "dbquerysorted ".$dbh->errstr. "- SQL: ".$stat;; + + + $sth->execute() or return $retdata->{error} = "dbquerysorted: ".$sth->errstr; + my $count = 0; + + while(my $data = $sth->fetchrow_hashref()) + { + #$retdata->{$count} = $data; + foreach my $k (keys %{$data}){ + $retdata->{$count}->{$k} = decode("utf-8",$data->{$k}); + } + $count++; + } + + + $sth->finish(); + $dbh->disconnect(); + + return $retdata; +} + +sub dbexec(){ + my $self = shift; + my $stat = shift; + my $retdata; + my $dbh = DBI->connect($sitecfg->{dsn},$sitecfg->{dbuser},$sitecfg->{dbpassword},{PrintError=>0,RaiseError=>0,AutoCommit=>1}) or return $retdata->{error} = "dbquery Connection Error!".$!; + # $stat = decode("UTF-8", $stat); + # open FILE,">>tmp/sql.log"; + # print FILE "\n==\n$stat\n==\n"; + # close FILE; + my $sth = $dbh->prepare($stat) or return $retdata->{error} = "dbexec ".$dbh->errstr. "- SQL: ".$stat;; + $retdata->{success} = $dbh->do($stat) or return $retdata->{error} = "dbexec ".$dbh->errstr. "- SQL: ".$stat; + $dbh->disconnect(); + return $retdata; +} + +sub dbqueryarray(){ + my $self = shift; + my $stat = shift; + my @retdata = (); + my $dbh = DBI->connect($sitecfg->{dsn},$sitecfg->{dbuser},$sitecfg->{dbpassword},{PrintError=>0,RaiseError=>0,AutoCommit=>1}) or return ({"error" => "dbqueryarray Connection Error!".$!}); + #$stat = encode("utf8", $stat); + #open FILE,">>/tmp/sql.log"; + #print "$stat\n"; + # close FILE; + my $sth = $dbh->prepare($stat); + + $sth->execute() or print "dbqueryarray: ".$sth->errstr; + my $count = 0; + + while(my $data = $sth->fetchrow_hashref()) + { + my $row = (); + foreach my $k (keys %{$data}){ + $row->{$k} = decode("utf-8",$data->{$k}); + } + push @retdata,$row; + } + + $sth->finish(); + $dbh->disconnect(); + #%retdata = sort {$a <=> $b} keys %retdata; + return \@retdata; +} + + +sub create_ddl_insert(){ + my $self = shift; + my $data = shift; + my $fields = (); + my @ddl = (); + + foreach my $f (keys(%{$data})){ + if (($f =~ /\_/) && ($f !~ /^ident_/)){ + my $t = substr($f,0,index($f,"_")); + my $c = substr($f,length($t)+1); + #my ($t,$c) = $f =~ m/(.+)\_(.+)/; + $fields->{$t}->{$c} = $data->{$f}; + } elsif ($f =~ /^ident_/){ + my $f2 = $f; + $f2 =~ s/^ident_//; + + my $t = substr($f2,0,index($f2,"_")); + my $c = substr($f2,length($t)+1); + $fields->{$t}->{$c} = $data->{$f}; + } + + } + + foreach my $tb (keys(%{$fields})){ + my @sqlcol = (); + my @sqlval = (); + foreach my $c (keys(%{$fields->{$tb}})){ + my $v = $fields->{$tb}->{$c}; + $v =~ s/'/''/g; + push (@sqlcol,$c); + if ($v eq ''){ + $v = 'null'; + } else { + $v = "'".$v."'"; + } + push (@sqlval,$v); + } + my $schema = "public"; + if (exists($data->{schemata})){ + $schema = $data->{schemata}; + } + push(@ddl,"INSERT INTO ".$schema.".".$tb." (".join(",",@sqlcol).") VALUES (".join(",",@sqlval).") returning id;"); + } + return @ddl; +} + + +sub create_ddl_update(){ + my $self = shift; + my $data = shift; + my $fields = (); + my @ddl = (); + foreach my $f (keys(%{$data})){ + if ($f =~ /^ident_/){ + my $fx = substr($f,6); + my $t = substr($fx,0,index($fx,"_")); + my $c = substr($fx,length($t)+1); + #my ($t,$c) = $f =~ m/^ident_(.+)\_([a-z0-9|\_]+)/; + $fields->{$t}->{cond}->{$c} = $data->{$f}; + } elsif ( ($f !~ /^ident/) && ($f =~ /.+\_.+/) ){ + my $t = substr($f,0,index($f,"_")); + my $c = substr($f,length($t)+1); + #my ($t,$c) = $f =~ m/^(.+)\_([a-z0-9|\_]+)/; + $fields->{$t}->{fields}->{$c} = $data->{$f}; + } + } + foreach my $tb (keys(%{$fields})){ + my @sqlupd = (); + my @sqlcond = (); + foreach my $c (keys(%{$fields->{$tb}->{fields}})){ + + my $v = $fields->{$tb}->{fields}->{$c}; + $v =~ s/'/''/g; + + if ($c =~ /-/){ + my @jp = split('-',$c); + if ($v eq ''){ + $v = 'null'; + } else { + $v = '"'.$v.'"'; + } + $c = 'jsonb_set(to_jsonb('.$jp[0].'),\'{"'.$jp[1].'"}\',\''.$v.'\')::json'; + push (@sqlupd,$jp[0]."=".$c); + }else { + if ($v eq ''){ + $v = 'null'; + } else { + $v = "'".$v."'"; + } + push (@sqlupd,$c."=".$v); + } + + } + foreach my $c (keys(%{$fields->{$tb}->{cond}})){ + my $v = $fields->{$tb}->{cond}->{$c}; + $v =~ s/'/''/g; + if ($v eq ''){ + $v = 'null'; + } else { + $v = "'".$v."'"; + } + push (@sqlcond,$c."=".$v); + } + my $schema = "public"; + if (exists($data->{schemata})){ + $schema = $data->{schemata}; + } + push(@ddl,"UPDATE ".$schema.".".$tb." SET ".join(",",@sqlupd)." WHERE ".join(" AND ",@sqlcond).";"); + } + + return @ddl; +} + +sub create_cnt_statement(){ + my $self = shift; + my $data = shift; + my $fields = (); + my @ddl = (); + foreach my $f (keys(%{$data})){ + if ($f =~ /^ident_/){ + my $fx = substr($f,6); + my $t = substr($fx,0,index($fx,"_")); + my $c = substr($fx,length($t)+1); + #my ($t,$c) = $f =~ m/^ident_(.+)\_([a-z0-9|\_]+)/; + $fields->{$t}->{cond}->{$c} = $data->{$f}; + } + } + foreach my $tb (keys(%{$fields})){ + my @sqlcond = (); + foreach my $c (keys(%{$fields->{$tb}->{cond}})){ + my $v = $fields->{$tb}->{cond}->{$c}; + $v =~ s/'/''/g; + if ($v eq ''){ + $v = 'null'; + } else { + $v = "'".$v."'"; + } + push (@sqlcond,$c."=".$v); + } + my $schema = "public"; + if (exists($data->{schemata})){ + $schema = $data->{schemata}; + } + push(@ddl,"SELECT count(*) as cnt from ".$schema.".".$tb." WHERE ".join(" AND ",@sqlcond).";"); + } + # open FILE,">>tmp/sql.log"; + # print FILE "\n==\n".join("\n",@ddl)."\n==\n"; + # close FILE; + return @ddl; +} + +sub create_ddl_delete(){ + my $self = shift; + my $data = shift; + my $fields = (); + my @ddl = (); + my @refcols = (); + my $refdata = (); + foreach my $f (keys(%{$data})){ + if ($f =~ /^ident_/){ + my ($t,$c) = $f =~ m/ident_(.+)\_(.+)/; + + $fields->{$t}->{cond}->{$c} = $data->{$f}; + push(@refcols,"'".$c.'_'.$t."'"); + $refdata->{$c.'_'.$t} = $data->{$f}; + } + } + foreach my $tb (keys(%{$fields})){ + my @sqlcond = (); + foreach my $c (keys(%{$fields->{$tb}->{cond}})){ + my $v = $fields->{$tb}->{cond}->{$c}; + $v =~ s/'/''/g; + push (@sqlcond,$c."='".$v."'"); + } + my $schema = "public"; + if (exists($data->{schemata})){ + $schema = $data->{schemata}; + } + push(@ddl,"DELETE FROM ".$schema.".".$tb." WHERE ".join(" AND ",@sqlcond).";"); + } + return @ddl; +} + +sub textunidecode(){ + my $self = shift; + my $text = shift; + $text = lc(unidecode(decode("utf-8",$text))); + $text =~ s/^[a-z0-9]//g; + return $text; +} + +sub createdefinedschema(){ + my $self = shift; + my $schematype = shift; + my $schemaname = shift; + my $ddlstr = ""; + my $sc = $self->dbquerysorted("select * from information_schema.schemata where schema_name='".$schemaname."';"); + if (keys(%{$sc}) > 0){ + return; + } + my @schemaddl =(); + open(SCA,$sitecfg->{datapath}.'/schemata/'.$schematype.'.schema.sql'); + while (my $l = ){ + $l =~ s/%%NEWSCHEMA%%/$schemaname/g; + if ($l eq "\n"){ + if ($ddlstr ne ""){ + push(@schemaddl,$ddlstr); + } + $ddlstr = ""; + next; + } + $ddlstr .= $l; + } + close(SCA); + if (scalar(@schemaddl) > 0){ + for(my $d;$ddbexec($schemaddl[$d]); + } + } +} + +1; diff --git a/backoffice/api/lib/dkssavefile.pm b/backoffice/api/lib/dkssavefile.pm new file mode 100644 index 0000000..55c260f --- /dev/null +++ b/backoffice/api/lib/dkssavefile.pm @@ -0,0 +1,49 @@ +package dkssavefile; + + +use strict; +use lib ('./lib/perl5'); +use lib ('./lib'); +use lib ('./'); +use MIME::Base64; +use MIME::Types; +use URI; +use Data::Dumper; +use File::Path qw(make_path); + +sub new { + my $class = shift; + my $self = bless {}, $class; + return $self; +} + +sub saveb64toFile(){ + my $self = shift; + # my $fd = shift; + my $filename = shift; + my $sitepath = shift; + my $filepath = shift; + my $data = shift; + my $ds = URI->new($data); + my $mimetype= $ds->media_type(); + my $mt = MIME::Types->new(); + my $sfx = $mt->type($mimetype); + my $ext = $sfx->{MT_extensions}; + my $nfsfx = ""; + if (scalar(@$ext) > 0){ + $nfsfx = @$ext[0]; + } + if (! -d $sitepath.'/'.$filepath){ + make_path($sitepath.'/'.$filepath); + } + open (NF,">".$sitepath.'/'.$filepath.'/'.$filename.'.'.$nfsfx); + binmode(1); + print NF $ds->data(); + close(NF); + if (-e $sitepath.'/'.$filepath.'/'.$filename.'.'.$nfsfx){ + return $filepath.'/'.$filename.'.'.$nfsfx; + } + return ""; +} + +1; \ No newline at end of file diff --git a/backoffice/api/lib/sendemail.pm b/backoffice/api/lib/sendemail.pm new file mode 100644 index 0000000..fd53b2c --- /dev/null +++ b/backoffice/api/lib/sendemail.pm @@ -0,0 +1,127 @@ +package sendemail; + +use strict; +use lib ('./lib/perl5'); +use lib ('./lib'); +use lib ('./'); +use Data::Dumper; +use File::Basename qw/dirname basename/; +use dksdb; + +sub new { + my $class = shift; + my $self = bless {}, $class; + $self->{server} = "mail.your-server.de"; + $self->{port} = "587"; + $self->{user} = 'webmaster@solana-architecture.lu'; + $self->{password} = "FLxCtIQs720K8n79"; + $self->{from} = 'webmaster@solana-architecture.lu'; + return $self; +} + +sub sendemail(){ + my $self = shift; + my $template = shift; + my $iduser = shift; + my $sendto = shift; + my $data = shift; + my $attach = shift; + my $body = ""; + my $subject = ""; + my $maildata = (); + my $db = dksdb->new(); + my $send = -1; + my $tmpl = $db->dbquerysorted("select *,ml.mailtemplate from mailtemplates mt join maillayouts ml on (mt.id_maillayout=ml.id) where templatename='".$template."';"); + if (keys(%{$tmpl}) > 0){ + $tmpl = $tmpl->{0}; + } + # open (LOG,">>tmp/sendmail.log"); + # print LOG $ENV{SCRIPT_FILENAME}; + # print LOG "SEND EMAIL:".Dumper($data)."\n"; + # close(LOG); + my $datasql = $tmpl->{'emaildatasql'}; + $data->{id} = $iduser; + foreach my $key (keys(%{$data})){ + my $srch = '%%'.lc($key).'%%'; + my $repl = $data->{$key}; + $datasql =~ s/$srch/$repl/g; + } + # open (LOG,">>tmp/sendmail.log"); + # print LOG "TEMPLATE DATA:".$datasql."\n"; + # close(LOG); + $maildata = $db->dbquerysorted($datasql); + + $body = $tmpl->{'emailtext'}; + $subject = $tmpl->{'mailsubject'}; + foreach my $key (keys(%{$maildata->{0}})){ + $data->{$key} = $maildata->{0}->{$key}; + } + foreach my $key (keys(%{$data})){ + my $srch = '%%'.lc($key).'%%'; + my $repl = $data->{$key}; + $body =~ s/$srch/$repl/g; + $subject =~ s/$srch/$repl/g; + } + my $bodytmpl = $tmpl->{mailtemplate}; + $bodytmpl =~ s/%%BODYCONTENT%%/$body/; + my $siteurl = $ENV{'REQUEST_SCHEME'}.'://'.$ENV{"HTTP_HOST"}; + $bodytmpl =~ s/%%siteurl%%/$siteurl/g; + $bodytmpl =~ s/%%SITEURL%%/$siteurl/g; + $bodytmpl =~ s/\r//g; + #$bodytmpl =~ s/"/\\\"/g; + #PROD REPLACE all not replaced DATA + #$bodytmpl =~ s/%%\w+%%//g; + #$sendto = 'ksaffran@dks.lu'; + # open (LOG,">>tmp/sendmail.log"); + # print LOG "SUBJECT:".$subject."\n"; + # print LOG "BODY TEXT:".$bodytmpl."\n"; + # close(LOG); + if (($bodytmpl ne "") && ($subject ne "") && ($sendto =~ /.+\@.+\..+/)){ + + + my $binsemail = dirname($ENV{'SCRIPT_FILENAME'}).'/sendEmail'; + my $f = dirname($ENV{SCRIPT_FILENAME}).'/tmp/mailbody_'.$sendto.'.txt'; + $f =~ s/\@/_/g; + if (! -e $binsemail){ + $binsemail = dirname($ENV{'SCRIPT_FILENAME'}).'/api/sendEmail'; + $f = dirname($ENV{SCRIPT_FILENAME}).'/api/tmp/mailbody_'.$sendto.'.txt'; + $f =~ s/\@/_/g; + if (! -e $binsemail){ + return 256; + } + } + + my $cmd= 'perl "'.$binsemail.'" -f '.$tmpl->{mailfrom}.' '; + $cmd .= ' -s "'.$self->{server}.':'.$self->{port}.'" -xu "'.$self->{user}.'" -xp "'.$self->{password}.'" -q '; + $cmd .= '-o tls=auto '; + $cmd .= '-t "'.$sendto.'" '; + $cmd .= '-u "'.$subject.'" '; + # open (LOG,">>sendmail.log"); + # print LOG $cmd."\n"; + # # print LOG "BODY TEXT:".$bodytmpl."\n"; + # close(LOG); + open(EML,">".$f); + print EML $bodytmpl; + close(EML); + # $cmd .= '-m "'.$bodytmpl.'" '; + if ($attach != undef){ + $cmd .= " -a"; + + foreach my $a (@{$attach}){ + $cmd .= " ".$a." "; + } + } + # open (LOG,">>tmp/sendmail.log"); + # print LOG "SEND EMAIL CMD:".$cmd."\n"; + # close(LOG); + # $cmd =~ s/'/''/g; + $send = system($cmd); + # open (LOG,">>tmp/sendmail.log"); + # print LOG "CMD RETURN NUM:".$send."\n"; + # close(LOG); + unlink($f); + } + return $send; +} + +1; \ No newline at end of file diff --git a/backoffice/api/lib/session.pm b/backoffice/api/lib/session.pm new file mode 100644 index 0000000..b44184f --- /dev/null +++ b/backoffice/api/lib/session.pm @@ -0,0 +1,240 @@ +package session; + +use strict; +use lib ('./lib/perl5'); +use lib ('./lib'); +use lib ('./'); +use File::Basename; +use Digest::SHA qw(sha256_hex); +use Data::Dumper; + +use dksdb; +use sendemail; +# use Data::Dumper; + +sub new { + my $class = shift; + my $self = bless {}, $class; + $self->{db} = dksdb->new(); + return $self; +} + +sub checklogin(){ + my $self = shift; + my $login = shift; + my $password = shift; + # open FILE,">>tmp/sql.log"; + # print FILE "pwd: $password\n"; + # close(FILE); + my $pwd = sha256_hex($password); + my $ret->{messagetype} ='w3-red'; + # my $newsid = undef; + $login = lc($login); + $login =~ s/^\s+//; + $login =~ s/\s+$//; + + $ret->{message} = "Mot de passe ou Login pas inconnue!"; + $ret->{messagetype} = "w3-red"; + $ret->{sid} = undef; + my $siddata = $self->{db}->dbquerysorted("select * from checklogin('".$self->{db}->securetext($login)."','".$pwd."','".$ENV{REMOTE_ADDR}."','".$ENV{HTTP_USER_AGENT}."');"); + + if (keys(%{$siddata}) > 0){ + # open FILE,">>tmp/sql.log"; + # print FILE Dumper($siddata); + # close(FILE); + $ret->{sid} = $siddata->{0}->{checklogin}; + } + return $ret; +} + +sub savepassword(){ + my $self = shift; + my $iduser = shift; + my $newpwd = shift; + my $pwd = sha256_hex($newpwd); + $self->{db}->dbexec("UPDATE users SET userpassword = '".$pwd."' WHERE id=".$iduser.";"); + return 1; +} + +sub passwordforgotten(){ + my $self = shift; + my $email = shift; + my $ret->{messagetype} ='w3-red'; + $ret->{message} = "Onbekannt E-mail!"; + my $sql = "select id,userpassword from users where username='".$self->{db}->securetext($email)."';"; + my $ex = $self->{db}->dbquerysorted($sql); + if (keys(%{$ex}) > 0){ + my $newpwd = $self->randomstring(12); + my $pwd = sha256_hex($newpwd); + $self->{db}->dbexec("UPDATE users SET userpassword = '".$pwd."' WHERE id=".$ex->{0}->{id}.";"); + my $data->{newpassword} = $newpwd; + my $eml = sendemail->new(); + my $mret = $eml->sendemail('user_forgotpasswd',$ex->{0}->{id},$email,$data,undef); + if ($mret != 0){ + $ret->{messagetype} ='w3-red'; + $ret->{message} = "Den Moment ass et leider nët méglech d'Passwuert autmatesch zreckzesetzen,
wend dech w.e.g. via E-Mail un webmaster\@fld.lu!"; + return $ret; + } + $ret->{message} = "Mir hun dir eng E-Mail, matt engem neien Passwuert gescheckt!"; + $ret->{messagetype} = "w3-green"; + } + return $ret; +} + +sub registeruser(){ + my $self = shift; + my $data = shift; + my $ret->{messagetype} ='w3-red'; + $ret->{message} = "Une erreur c'est produite, essayer plus tard!"; + $ret->{page} = "message.tt"; + my @reqfields = ("companies_company","terms","users_email","members_phone","members_surname","members_prename","members_job"); + my $reqf = 1; + foreach my $rf (@reqfields){ + if (!exists($data->{$rf})){ + $reqf = 0; + } + } + if ($reqf == 0){ + $ret->{message} = "Rempissez tous les champs s.v.p.!"; + $ret->{page} = "register.tt"; + return $ret; + } + foreach my $d (%{$data}){ + $data->{$d} = $self->{db}->securetext($data->{$d}); + } + + my $user = $self->{db}->dbquerysorted("select id from users where username='".$data->{users_email}."';"); + if (keys(%{$user}) > 0){ + $ret->{page} = "register.tt"; + $ret->{message} = "Ily existe déjà un utilisateur avec la mème adresse e-mail!"; + return $ret; + } + + my $newcode = $self->randomstring(6); + + my $newuserid = $self->{db}->dbquerysorted("INSERT INTO users (username,vcode) VALUES ('".$data->{users_email}."','".$newcode."') returning id;"); + $self->{db}->dbexec("INSERT INTO useringroups (id_user,id_group) VALUES ('".$newuserid->{0}->{id}."',(select id from usergroups where isdefault=true));"); + my $company = $self->{db}->dbquerysorted("select id from companies where link=unaccent_string('".$data->{companies_company}."');"); + if (keys(%{$company}) == 0 ){ + $company = $self->{db}->dbquerysorted("INSERT INTO companies (company,link) VALUES ('".$data->{companies_company}."',unaccent_string('".$data->{companies_company}."')) returning id;"); + $self->{db}->dbexec("INSERT INTO useringroups (id_user,id_group) VALUES ('".$newuserid->{0}->{id}."',(select id from usergroups where usergroup='company'));"); + } + $self->{db}->dbexec("INSERT INTO members (surname, prename, phone, id_user, id_company, job) VALUES('".$data->{members_surname}."', '".$data->{members_prename}."', '".$data->{members_phone}."', ".$newuserid->{0}->{id}.", ".$company->{0}->{id}.", '".$data->{members_job}."');"); + my $maildata->{vcode} = $newcode; + my $eml = sendemail->new(); + my $mret = $eml->sendemail('user_verification',$newuserid->{0}->{id},$data->{users_email},$maildata,undef); + if ($mret == 0){ + $ret->{message} = "Merci,
nous vous avons envoyé un email,avec un code de vérification!
Entrez ce code ci dessous, pour valider votre compte!
en cas de problèmes envoyer un email à info\@solana-architecture.lu"; + $ret->{messagetype} = "w3-green"; + $ret->{page} = "validationcode.tt"; + } else { + $self->{db}->dbexec("UPDATE users set username='".$data->{users_email}."',vcode=null where id=".$newuserid->{0}->{id}." ;"); + $ret->{message} = "nous ne pouvons pas envoyer un email à '".$data->{users_email}."' ! Si cette email n'existe pas, régisterez-vous avec un email existant!
en cas de problèemes envoyer un email à info\@solana-architecture.lu"; + $ret->{messagetype} = "w3-red"; + $ret->{page} = "register.tt"; + } + #$self->{db}->dbexec("insert into appaccess (id_user) values (".$newuserid->{0}->{id}.");"); + # $ret->{messagetype} = "w3-green"; + + return $ret; +} + +sub validateaccount(){ + my $self = shift; + my $data = shift; + foreach my $d (%{$data}){ + $data->{$d} = $self->{db}->securetext($data->{$d}); + } + + my $ret->{messagetype} ='w3-red'; + my $vcodedata = $self->{db}->dbquerysorted("select id,vcode,username from users where vcode='".$data->{vcode}."';"); + if (keys(%{$vcodedata}) == 0){ + $ret->{message} = "code inconnue!"; + $ret->{page} = "validationcode.tt"; + } + my $newpwd = $self->randomstring(12); + my $pwd = sha256_hex($newpwd); + my $maildata->{password} = $newpwd; + my $eml = sendemail->new(); + my $newuserid = $self->{db}->dbquerysorted("UPDATE users set userpassword='".$pwd."',vcode=null,regcode=null where id=".$vcodedata->{0}->{id}." returning id,username;"); + my $mret = $eml->sendemail('user_registration',$vcodedata->{0}->{id},$vcodedata->{0}->{username},$maildata,undef); + if ($mret == 0){ + $ret->{message} = "Merci,
Nous vous avons envoyé un email avec les données nécessaires pour se connecter!"; + $ret->{messagetype} = "w3-green"; + $ret->{page} = "message.tt"; + } else { + $ret->{message} = "NOus n'avons pas pu vous envoyé un email à '".$newuserid->{0}->{username}."'! Si l'addresse email n'existe pas, essayer avec un email existant!"; + $ret->{page} = "message.tt"; + } + return $ret; +} + +sub getsession($){ + my $self = shift; + my $sid = shift; + my $sql ="select * from public.getsession('".$self->{db}->securetext($sid)."','".$ENV{REMOTE_ADDR}."','".$ENV{HTTP_USER_AGENT}."');"; + my $res= $self->{db}->dbquerysorted($sql); + my $ret = undef; + # open FILE,">>tmp/sql.log"; + # print FILE "GET DB Session\n"; + # print FILE Dumper($res->{0}); + # close(FILE); + if (keys(%{$res}) > 0){ + + return $res->{0}; + } + return $ret; +} + +sub deletesession(){ + my $self = shift; + my $sid = shift; + $self->{db}->dbexec("DELETE FROM sessions where idsession='".$self->{db}->securetext($sid)."';"); +} + +sub randomstring(){ + my $self = shift; + my $num = shift; + my @alphanumeric = ('a'..'z', 'A'..'Z', 0..9); + my $randstring = join '', map $alphanumeric[rand @alphanumeric], 0..$num; + return $randstring; +} + + +# sub deleteprofile(){ +# my $self = shift; +# my $data = shift; +# my $ret->{message} = "mot de passe ou profile inconnue!"; +# $ret->{messagetype} = "danger"; +# if ($data->{id_user} eq ''){ +# $ret->{sid} = undef; +# return $ret; +# } +# my $pwd = sha256_hex($data->{password}); +# my $user = $self->{db}->dbquerysorted("select id from users where id= '".$data->{id_user}."' and userpassword = '".$pwd."';"); +# if (keys(%{$user}) > 0){ +# $self->admindeleteuser($data->{id_user}); +# my $ret->{'message'} = "Votre profile a été supprimé!"; +# $ret->{'messagetype'} = "info"; +# $ret->{sid} = undef; +# } +# return $ret; + +# } + +# sub admindeleteuser(){ +# my $self = shift; +# my $id_user = shift; +# my @dl = ("DELETE FROM public.useringroups WHERE id_uset=".$id_user.";", +# "DELETE FROM public.userclients WHERE id_user=".$id_user.";", +# "DELETE FROM public.appaccess WHERE id_user=".$id_user.";", +# "DELETE FROM public.modulepreferences WHERE id_user=".$id_user.";",, +# "DELETE FROM public.sessions WHERE id_user=".$id_user.";", +# "delete from users where id=".$id_user.";"); +# foreach my $s (@dl){ +# $self->{db}->dbexec($s); +# } +# return 1; +# } + +1; \ No newline at end of file diff --git a/backoffice/api/sendEmail b/backoffice/api/sendEmail new file mode 100644 index 0000000..c639439 --- /dev/null +++ b/backoffice/api/sendEmail @@ -0,0 +1,2235 @@ +#!/usr/bin/perl -w +############################################################################## +## sendEmail +## Written by: Brandon Zehm +## +## License: +## sendEmail (hereafter referred to as "program") is free software; +## you can redistribute it and/or modify it under the terms of the GNU General +## Public License as published by the Free Software Foundation; either version +## 2 of the License, or (at your option) any later version. +## When redistributing modified versions of this source code it is recommended +## that that this disclaimer and the above coder's names are included in the +## modified code. +## +## Disclaimer: +## This program is provided with no warranty of any kind, either expressed or +## implied. It is the responsibility of the user (you) to fully research and +## comprehend the usage of this program. As with any tool, it can be misused, +## either intentionally (you're a vandal) or unintentionally (you're a moron). +## THE AUTHOR(S) IS(ARE) NOT RESPONSIBLE FOR ANYTHING YOU DO WITH THIS PROGRAM +## or anything that happens because of your use (or misuse) of this program, +## including but not limited to anything you, your lawyers, or anyone else +## can dream up. And now, a relevant quote directly from the GPL: +## +## NO WARRANTY +## +## 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +## FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +## OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +## PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +## OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +## MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +## TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +## PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +## REPAIR OR CORRECTION. +## +############################################################################## +use strict; +use IO::Socket; + + +######################## +## Global Variables ## +######################## + +my %conf = ( + ## General + "programName" => $0, ## The name of this program + "version" => '1.56', ## The version of this program + "authorName" => 'Brandon Zehm', ## Author's Name + "authorEmail" => 'caspian@dotconf.net', ## Author's Email Address + "timezone" => '+0000', ## We always use +0000 for the time zone + "hostname" => 'changeme', ## Used in printmsg() for all output (is updated later in the script). + "debug" => 0, ## Default debug level + "error" => '', ## Error messages will often be stored here + + ## Logging + "stdout" => 1, + "logging" => 0, ## If this is true the printmsg function prints to the log file + "logFile" => '', ## If this is specified (form the command line via -l) this file will be used for logging. + + ## Network + "server" => 'localhost', ## Default SMTP server + "port" => 25, ## Default port + "bindaddr" => '', ## Default local bind address + "alarm" => '', ## Default timeout for connects and reads, this gets set from $opt{'timeout'} + "tls_client" => 0, ## If TLS is supported by the client (us) + "tls_server" => 0, ## If TLS is supported by the remote SMTP server + + ## Email + "delimiter" => "----MIME delimiter for sendEmail-" ## MIME Delimiter + . rand(1000000), ## Add some randomness to the delimiter + "Message-ID" => rand(1000000) . "-sendEmail", ## Message-ID for email header + +); + + +## This hash stores the options passed on the command line via the -o option. +my %opt = ( + ## Addressing + "reply-to" => '', ## Reply-To field + + ## Message + "message-file" => '', ## File to read message body from + "message-header" => '', ## Additional email header line(s) + "message-format" => 'normal', ## If "raw" is specified the message is sent unmodified + "message-charset" => 'iso-8859-1', ## Message character-set + "message-content-type" => 'auto', ## auto, text, html or an actual string to put into the content-type header. + + ## Network + "timeout" => 60, ## Default timeout for connects and reads, this is copied to $conf{'alarm'} later. + "fqdn" => 'changeme', ## FQDN of this machine, used during SMTP communication (is updated later in the script). + + ## eSMTP + "username" => '', ## Username used in SMTP Auth + "password" => '', ## Password used in SMTP Auth + "tls" => 'auto', ## Enable or disable TLS support. Options: auto, yes, no + +); + +## More variables used later in the program +my $SERVER; +my $CRLF = "\015\012"; +my $subject = ''; +my $header = ''; +my $message = ''; +my $from = ''; +my @to = (); +my @cc = (); +my @bcc = (); +my @attachments = (); +my @attachments_names = (); + +## For printing colors to the console +my ${colorRed} = "\033[31;1m"; +my ${colorGreen} = "\033[32;1m"; +my ${colorCyan} = "\033[36;1m"; +my ${colorWhite} = "\033[37;1m"; +my ${colorNormal} = "\033[m"; +my ${colorBold} = "\033[1m"; +my ${colorNoBold} = "\033[0m"; + +## Don't use shell escape codes on Windows systems +if ($^O =~ /win/i) { + ${colorRed} = ${colorGreen} = ${colorCyan} = ${colorWhite} = ${colorNormal} = ${colorBold} = ${colorNoBold} = ""; +} + +## Load IO::Socket::SSL if it's available +eval { require IO::Socket::SSL; }; +if ($@) { $conf{'tls_client'} = 0; } +else { $conf{'tls_client'} = 1; } + + + + + + +############################# +## ## +## FUNCTIONS ## +## ## +############################# + + + + + +############################################################################################### +## Function: initialize () +## +## Does all the script startup jibberish. +## +############################################################################################### +sub initialize { + + ## Set STDOUT to flush immediatly after each print + $| = 1; + + ## Intercept signals + $SIG{'QUIT'} = sub { quit("EXITING: Received SIG$_[0]", 1); }; + $SIG{'INT'} = sub { quit("EXITING: Received SIG$_[0]", 1); }; + $SIG{'KILL'} = sub { quit("EXITING: Received SIG$_[0]", 1); }; + $SIG{'TERM'} = sub { quit("EXITING: Received SIG$_[0]", 1); }; + + ## ALARM and HUP signals are not supported in Win32 + unless ($^O =~ /win/i) { + $SIG{'HUP'} = sub { quit("EXITING: Received SIG$_[0]", 1); }; + $SIG{'ALRM'} = sub { quit("EXITING: Received SIG$_[0]", 1); }; + } + + ## Fixup $conf{'programName'} + $conf{'programName'} =~ s/(.)*[\/,\\]//; + $0 = $conf{'programName'} . " " . join(" ", @ARGV); + + ## Fixup $conf{'hostname'} and $opt{'fqdn'} + if ($opt{'fqdn'} eq 'changeme') { $opt{'fqdn'} = get_hostname(1); } + if ($conf{'hostname'} eq 'changeme') { $conf{'hostname'} = $opt{'fqdn'}; $conf{'hostname'} =~ s/\..*//; } + + return(1); +} + + + + + + + + + + + + + + + +############################################################################################### +## Function: processCommandLine () +## +## Processes command line storing important data in global vars (usually %conf) +## +############################################################################################### +sub processCommandLine { + + + ############################ + ## Process command line ## + ############################ + + my @ARGS = @ARGV; ## This is so later we can re-parse the command line args later if we need to + my $numargv = @ARGS; + help() unless ($numargv); + my $counter = 0; + + for ($counter = 0; $counter < $numargv; $counter++) { + + if ($ARGS[$counter] =~ /^-h$/i) { ## Help ## + help(); + } + + elsif ($ARGS[$counter] eq "") { ## Ignore null arguments + ## Do nothing + } + + elsif ($ARGS[$counter] =~ /^--help/) { ## Topical Help ## + $counter++; + if ($ARGS[$counter] && $ARGS[$counter] !~ /^-/) { + helpTopic($ARGS[$counter]); + } + else { + help(); + } + } + + elsif ($ARGS[$counter] =~ /^-o$/i) { ## Options specified with -o ## + $counter++; + ## Loop through each option passed after the -o + while ($ARGS[$counter] && $ARGS[$counter] !~ /^-/) { + + if ($ARGS[$counter] !~ /(\S+)=(\S.*)/) { + printmsg("WARNING => Name/Value pair [$ARGS[$counter]] is not properly formatted", 0); + printmsg("WARNING => Arguments proceeding -o should be in the form of \"name=value\"", 0); + } + else { + if (exists($opt{$1})) { + if ($1 eq 'message-header') { + $opt{$1} .= $2 . $CRLF; + } + else { + $opt{$1} = $2; + } + printmsg("DEBUG => Assigned \$opt{} key/value: $1 => $2", 3); + } + else { + printmsg("WARNING => Name/Value pair [$ARGS[$counter]] will be ignored: unknown key [$1]", 0); + printmsg("HINT => Try the --help option to find valid command line arguments", 1); + } + } + $counter++; + } $counter--; + } + + elsif ($ARGS[$counter] =~ /^-f$/) { ## From ## + $counter++; + if ($ARGS[$counter] && $ARGS[$counter] !~ /^-/) { $from = $ARGS[$counter]; } + else { printmsg("WARNING => The argument after -f was not an email address!", 0); $counter--; } + } + + elsif ($ARGS[$counter] =~ /^-t$/) { ## To ## + $counter++; + while ($ARGS[$counter] && ($ARGS[$counter] !~ /^-/)) { + if ($ARGS[$counter] =~ /[;,]/) { + push (@to, split(/[;,]/, $ARGS[$counter])); + } + else { + push (@to,$ARGS[$counter]); + } + $counter++; + } $counter--; + } + + elsif ($ARGS[$counter] =~ /^-cc$/) { ## Cc ## + $counter++; + while ($ARGS[$counter] && ($ARGS[$counter] !~ /^-/)) { + if ($ARGS[$counter] =~ /[;,]/) { + push (@cc, split(/[;,]/, $ARGS[$counter])); + } + else { + push (@cc,$ARGS[$counter]); + } + $counter++; + } $counter--; + } + + elsif ($ARGS[$counter] =~ /^-bcc$/) { ## Bcc ## + $counter++; + while ($ARGS[$counter] && ($ARGS[$counter] !~ /^-/)) { + if ($ARGS[$counter] =~ /[;,]/) { + push (@bcc, split(/[;,]/, $ARGS[$counter])); + } + else { + push (@bcc,$ARGS[$counter]); + } + $counter++; + } $counter--; + } + + elsif ($ARGS[$counter] =~ /^-m$/) { ## Message ## + $counter++; + $message = ""; + while ($ARGS[$counter] && $ARGS[$counter] !~ /^-/) { + if ($message) { $message .= " "; } + $message .= $ARGS[$counter]; + $counter++; + } $counter--; + + ## Replace '\n' with $CRLF. + ## This allows newlines with messages sent on the command line + $message =~ s/\\n/$CRLF/g; + } + + elsif ($ARGS[$counter] =~ /^-u$/) { ## Subject ## + $counter++; + $subject = ""; + while ($ARGS[$counter] && $ARGS[$counter] !~ /^-/) { + if ($subject) { $subject .= " "; } + $subject .= $ARGS[$counter]; + $counter++; + } $counter--; + } + + elsif ($ARGS[$counter] =~ /^-s$/) { ## Server ## + $counter++; + if ($ARGS[$counter] && $ARGS[$counter] !~ /^-/) { + $conf{'server'} = $ARGS[$counter]; + if ($conf{'server'} =~ /:/) { ## Port ## + ($conf{'server'},$conf{'port'}) = split(":",$conf{'server'}); + } + } + else { printmsg("WARNING - The argument after -s was not the server!", 0); $counter--; } + } + + elsif ($ARGS[$counter] =~ /^-b$/) { ## Bind Address ## + $counter++; + if ($ARGS[$counter] && $ARGS[$counter] !~ /^-/) { + $conf{'bindaddr'} = $ARGS[$counter]; + } + else { printmsg("WARNING - The argument after -b was not the bindaddr!", 0); $counter--; } + } + + elsif ($ARGS[$counter] =~ /^-a$/) { ## Attachments ## + $counter++; + while ($ARGS[$counter] && ($ARGS[$counter] !~ /^-/)) { + push (@attachments,$ARGS[$counter]); + $counter++; + } $counter--; + } + + elsif ($ARGS[$counter] =~ /^-xu$/) { ## AuthSMTP Username ## + $counter++; + if ($ARGS[$counter] && $ARGS[$counter] !~ /^-/) { + $opt{'username'} = $ARGS[$counter]; + } + else { + printmsg("WARNING => The argument after -xu was not valid username!", 0); + $counter--; + } + } + + elsif ($ARGS[$counter] =~ /^-xp$/) { ## AuthSMTP Password ## + $counter++; + if ($ARGS[$counter] && $ARGS[$counter] !~ /^-/) { + $opt{'password'} = $ARGS[$counter]; + } + else { + printmsg("WARNING => The argument after -xp was not valid password!", 0); + $counter--; + } + } + + elsif ($ARGS[$counter] =~ /^-l$/) { ## Logging ## + $counter++; + $conf{'logging'} = 1; + if ($ARGS[$counter] && $ARGS[$counter] !~ /^-/) { $conf{'logFile'} = $ARGS[$counter]; } + else { printmsg("WARNING - The argument after -l was not the log file!", 0); $counter--; } + } + + elsif ($ARGS[$counter] =~ s/^-v+//i) { ## Verbosity ## + my $tmp = (length($&) - 1); + $conf{'debug'} += $tmp; + } + + elsif ($ARGS[$counter] =~ /^-q$/) { ## Quiet ## + $conf{'stdout'} = 0; + } + + else { + printmsg("Error: \"$ARGS[$counter]\" is not a recognized option!", 0); + help(); + } + + } + + + + + + + + + ################################################### + ## Verify required variables are set correctly ## + ################################################### + + ## Make sure we have something in $conf{hostname} and $opt{fqdn} + if ($opt{'fqdn'} =~ /\./) { + $conf{'hostname'} = $opt{'fqdn'}; + $conf{'hostname'} =~ s/\..*//; + } + + if (!$conf{'server'}) { $conf{'server'} = 'localhost'; } + if (!$conf{'port'}) { $conf{'port'} = 25; } + if (!$from) { + quit("ERROR => You must specify a 'from' field! Try --help.", 1); + } + if ( ((scalar(@to)) + (scalar(@cc)) + (scalar(@bcc))) <= 0) { + quit("ERROR => You must specify at least one recipient via -t, -cc, or -bcc", 1); + } + + ## Make sure email addresses look OK. + foreach my $addr (@to, @cc, @bcc, $from, $opt{'reply-to'}) { + if ($addr) { + if (!returnAddressParts($addr)) { + printmsg("ERROR => Can't use improperly formatted email address: $addr", 0); + printmsg("HINT => Try viewing the extended help on addressing with \"--help addressing\"", 1); + quit("", 1); + } + } + } + + ## Make sure all attachments exist. + foreach my $file (@attachments) { + if ( (! -f $file) or (! -r $file) ) { + printmsg("ERROR => The attachment [$file] doesn't exist!", 0); + printmsg("HINT => Try specifying the full path to the file or reading extended help with \"--help message\"", 1); + quit("", 1); + } + } + + if ($conf{'logging'} and (!$conf{'logFile'})) { + quit("ERROR => You used -l to enable logging but didn't specify a log file!", 1); + } + + if ( $opt{'username'} ) { + if (!$opt{'password'}) { + ## Prompt for a password since one wasn't specified with the -xp option. + $SIG{'ALRM'} = sub { quit("ERROR => Timeout waiting for password inpupt", 1); }; + alarm(60) if ($^O !~ /win/i); ## alarm() doesn't work in win32 + print "Password: "; + $opt{'password'} = ; chomp $opt{'password'}; + if (!$opt{'password'}) { + quit("ERROR => A username for SMTP authentication was specified, but no password!", 1); + } + } + } + + ## Validate the TLS setting + $opt{'tls'} = lc($opt{'tls'}); + if ($opt{'tls'} !~ /^(auto|yes|no)$/) { + quit("ERROR => Invalid TLS setting ($opt{'tls'}). Must be one of auto, yes, or no.", 1); + } + + ## If TLS is set to "yes", make sure sendEmail loaded the libraries needed. + if ($opt{'tls'} eq 'yes' and $conf{'tls_client'} == 0) { + quit("ERROR => No TLS support! SendEmail can't load required libraries. (try installing Net::SSLeay and IO::Socket::SSL)", 1); + } + + ## Return 0 errors + return(0); +} + + + + + + + + + + + + + + + + +## getline($socketRef) +sub getline { + my ($socketRef) = @_; + local ($/) = "\r\n"; + return $$socketRef->getline; +} + + + + +## Receive a (multiline?) SMTP response from ($socketRef) +sub getResponse { + my ($socketRef) = @_; + my ($tmp, $reply); + local ($/) = "\r\n"; + return undef unless defined($tmp = getline($socketRef)); + return("getResponse() socket is not open") unless ($$socketRef->opened); + ## Keep reading lines if it's a multi-line response + while ($tmp =~ /^\d{3}-/o) { + $reply .= $tmp; + return undef unless defined($tmp = getline($socketRef)); + } + $reply .= $tmp; + $reply =~ s/\r?\n$//o; + return $reply; +} + + + + +############################################################################################### +## Function: SMTPchat ( [string $command] ) +## +## Description: Sends $command to the SMTP server (on SERVER) and awaits a successful +## reply form the server. If the server returns an error, or does not reply +## within $conf{'alarm'} seconds an error is generated. +## NOTE: $command is optional, if no command is specified then nothing will +## be sent to the server, but a valid response is still required from the server. +## +## Input: [$command] A (optional) valid SMTP command (ex. "HELO") +## +## +## Output: Returns zero on success, or non-zero on error. +## Error messages will be stored in $conf{'error'} +## A copy of the last SMTP response is stored in the global variable +## $conf{'SMTPchat_response'} +## +## +## Example: SMTPchat ("HELO mail.isp.net"); +############################################################################################### +sub SMTPchat { + my ($command) = @_; + + printmsg("INFO => Sending: \t$command", 1) if ($command); + + ## Send our command + print $SERVER "$command$CRLF" if ($command); + + ## Read a response from the server + $SIG{'ALRM'} = sub { $conf{'error'} = "alarm"; $SERVER->close(); }; + alarm($conf{'alarm'}) if ($^O !~ /win/i); ## alarm() doesn't work in win32; + my $result = $conf{'SMTPchat_response'} = getResponse(\$SERVER); + alarm(0) if ($^O !~ /win/i); ## alarm() doesn't work in win32; + + ## Generate an alert if we timed out + if ($conf{'error'} eq "alarm") { + $conf{'error'} = "ERROR => Timeout while reading from $conf{'server'}:$conf{'port'} There was no response after $conf{'alarm'} seconds."; + return(1); + } + + ## Make sure the server actually responded + if (!$result) { + $conf{'error'} = "ERROR => $conf{'server'}:$conf{'port'} returned a zero byte response to our query."; + return(2); + } + + ## Validate the response + if (evalSMTPresponse($result)) { + ## conf{'error'} will already be set here + return(2); + } + + ## Print the success messsage + printmsg($conf{'error'}, 1); + + ## Return Success + return(0); +} + + + + + + + + + + + + +############################################################################################### +## Function: evalSMTPresponse (string $message ) +## +## Description: Searches $message for either an SMTP success or error code, and returns +## 0 on success, and the actual error code on error. +## +## +## Input: $message Data received from a SMTP server (ex. "220 +## +## +## Output: Returns zero on success, or non-zero on error. +## Error messages will be stored in $conf{'error'} +## +## +## Example: SMTPchat ("HELO mail.isp.net"); +############################################################################################### +sub evalSMTPresponse { + my ($message) = @_; + + ## Validate input + if (!$message) { + $conf{'error'} = "ERROR => No message was passed to evalSMTPresponse(). What happened?"; + return(1) + } + + printmsg("DEBUG => evalSMTPresponse() - Checking for SMTP success or error status in the message: $message ", 3); + + ## Look for a SMTP success code + if ($message =~ /^([23]\d\d)/) { + printmsg("DEBUG => evalSMTPresponse() - Found SMTP success code: $1", 2); + $conf{'error'} = "SUCCESS => Received: \t$message"; + return(0); + } + + ## Look for a SMTP error code + if ($message =~ /^([45]\d\d)/) { + printmsg("DEBUG => evalSMTPresponse() - Found SMTP error code: $1", 2); + $conf{'error'} = "ERROR => Received: \t$message"; + return($1); + } + + ## If no SMTP codes were found return an error of 1 + $conf{'error'} = "ERROR => Received a message with no success or error code. The message received was: $message"; + return(2); + +} + + + + + + + + + + +######################################################### +# SUB: &return_month(0,1,etc) +# returns the name of the month that corrosponds +# with the number. returns 0 on error. +######################################################### +sub return_month { + my $x = $_[0]; + if ($x == 0) { return 'Jan'; } + if ($x == 1) { return 'Feb'; } + if ($x == 2) { return 'Mar'; } + if ($x == 3) { return 'Apr'; } + if ($x == 4) { return 'May'; } + if ($x == 5) { return 'Jun'; } + if ($x == 6) { return 'Jul'; } + if ($x == 7) { return 'Aug'; } + if ($x == 8) { return 'Sep'; } + if ($x == 9) { return 'Oct'; } + if ($x == 10) { return 'Nov'; } + if ($x == 11) { return 'Dec'; } + return (0); +} + + + + + + + + + + + + + + + + +######################################################### +# SUB: &return_day(0,1,etc) +# returns the name of the day that corrosponds +# with the number. returns 0 on error. +######################################################### +sub return_day { + my $x = $_[0]; + if ($x == 0) { return 'Sun'; } + if ($x == 1) { return 'Mon'; } + if ($x == 2) { return 'Tue'; } + if ($x == 3) { return 'Wed'; } + if ($x == 4) { return 'Thu'; } + if ($x == 5) { return 'Fri'; } + if ($x == 6) { return 'Sat'; } + return (0); +} + + + + + + + + + + + + + + + + +############################################################################################### +## Function: returnAddressParts(string $address) +## +## Description: Returns a two element array containing the "Name" and "Address" parts of +## an email address. +## +## Example: "Brandon Zehm " +## would return: ("Brandon Zehm", "caspian@dotconf.net"); +## +## "caspian@dotconf.net" +## would return: ("caspian@dotconf.net", "caspian@dotconf.net") +############################################################################################### +sub returnAddressParts { + my $input = $_[0]; + my $name = ""; + my $address = ""; + + ## Make sure to fail if it looks totally invalid + if ($input !~ /(\S+\@\S+)/) { + $conf{'error'} = "ERROR => The address [$input] doesn't look like a valid email address, ignoring it"; + return(undef()); + } + + ## Check 1, should find addresses like: "Brandon Zehm " + elsif ($input =~ /^\s*(\S(.*\S)?)\s*<(\S+\@\S+)>/o) { + ($name, $address) = ($1, $3); + } + + ## Otherwise if that failed, just get the address: + elsif ($input =~ /<(\S+\@\S+)>/o) { + $name = $address = $1; + } + + ## Or maybe it was formatted this way: caspian@dotconf.net + elsif ($input =~ /(\S+\@\S+)/o) { + $name = $address = $1; + } + + ## Something stupid happened, just return an error. + unless ($name and $address) { + printmsg("ERROR => Couldn't parse the address: $input", 0); + printmsg("HINT => If you think this should work, consider reporting this as a bug to $conf{'authorEmail'}", 1); + return(undef()); + } + + ## Make sure there aren't invalid characters in the address, and return it. + my $ctrl = '\000-\037'; + my $nonASCII = '\x80-\xff'; + if ($address =~ /[<> ,;:"'\[\]\\$ctrl$nonASCII]/) { + printmsg("WARNING => The address [$address] seems to contain invalid characters: continuing anyway", 0); + } + return($name, $address); +} + + + + + + + + + + + + + + + + +############################################################################################### +## Function: base64_encode(string $data, bool $chunk) +## +## Description: Returns $data as a base64 encoded string. +## If $chunk is true, the encoded data is returned in 76 character long lines +## with the final \CR\LF removed. +## +## Note: This is only used from the smtp auth section of code. +## At some point it would be nice to merge the code that encodes attachments and this. +############################################################################################### +sub base64_encode { + my $data = $_[0]; + my $chunk = $_[1]; + my $tmp = ''; + my $base64 = ''; + my $CRLF = "\r\n"; + + ################################### + ## Convert binary data to base64 ## + ################################### + while ($data =~ s/(.{45})//s) { ## Get 45 bytes from the binary string + $tmp = substr(pack('u', $&), 1); ## Convert the binary to uuencoded text + chop($tmp); + $tmp =~ tr|` -_|AA-Za-z0-9+/|; ## Translate from uuencode to base64 + $base64 .= $tmp; + } + + ########################## + ## Encode the leftovers ## + ########################## + my $padding = ""; + if ( ($data) and (length($data) > 0) ) { + $padding = (3 - length($data) % 3) % 3; ## Set flag if binary data isn't divisible by 3 + $tmp = substr(pack('u', $data), 1); ## Convert the binary to uuencoded text + chop($tmp); + $tmp =~ tr|` -_|AA-Za-z0-9+/|; ## Translate from uuencode to base64 + $base64 .= $tmp; + } + + ############################ + ## Fix padding at the end ## + ############################ + $data = ''; + $base64 =~ s/.{$padding}$/'=' x $padding/e if $padding; ## Fix the end padding if flag (from above) is set + if ($chunk) { + while ($base64 =~ s/(.{1,76})//s) { ## Put $CRLF after each 76 characters + $data .= "$1$CRLF"; + } + } + else { + $data = $base64; + } + + ## Remove any trailing CRLF's + $data =~ s/(\r|\n)*$//s; + return($data); +} + + + + + + + + + +######################################################### +# SUB: send_attachment("/path/filename") +# Sends the mime headers and base64 encoded file +# to the email server. +######################################################### +sub send_attachment { + my ($filename) = @_; ## Get filename passed + my (@fields, $y, $filename_name, $encoding, ## Local variables + @attachlines, $content_type); + my $bin = 1; + + @fields = split(/\/|\\/, $filename); ## Get the actual filename without the path + $filename_name = pop(@fields); + push @attachments_names, $filename_name; ## FIXME: This is only used later for putting in the log file + + ########################## + ## Autodetect Mime Type ## + ########################## + + @fields = split(/\./, $filename_name); + $encoding = $fields[$#fields]; + + if ($encoding =~ /txt|text|log|conf|^c$|cpp|^h$|inc|m3u/i) { $content_type = 'text/plain'; } + elsif ($encoding =~ /html|htm|shtml|shtm|asp|php|cfm/i) { $content_type = 'text/html'; } + elsif ($encoding =~ /sh$/i) { $content_type = 'application/x-sh'; } + elsif ($encoding =~ /tcl/i) { $content_type = 'application/x-tcl'; } + elsif ($encoding =~ /pl$/i) { $content_type = 'application/x-perl'; } + elsif ($encoding =~ /js$/i) { $content_type = 'application/x-javascript'; } + elsif ($encoding =~ /man/i) { $content_type = 'application/x-troff-man'; } + elsif ($encoding =~ /gif/i) { $content_type = 'image/gif'; } + elsif ($encoding =~ /jpg|jpeg|jpe|jfif|pjpeg|pjp/i) { $content_type = 'image/jpeg'; } + elsif ($encoding =~ /tif|tiff/i) { $content_type = 'image/tiff'; } + elsif ($encoding =~ /xpm/i) { $content_type = 'image/x-xpixmap'; } + elsif ($encoding =~ /bmp/i) { $content_type = 'image/x-MS-bmp'; } + elsif ($encoding =~ /pcd/i) { $content_type = 'image/x-photo-cd'; } + elsif ($encoding =~ /png/i) { $content_type = 'image/png'; } + elsif ($encoding =~ /aif|aiff/i) { $content_type = 'audio/x-aiff'; } + elsif ($encoding =~ /wav/i) { $content_type = 'audio/x-wav'; } + elsif ($encoding =~ /mp2|mp3|mpa/i) { $content_type = 'audio/x-mpeg'; } + elsif ($encoding =~ /ra$|ram/i) { $content_type = 'audio/x-pn-realaudio'; } + elsif ($encoding =~ /mpeg|mpg/i) { $content_type = 'video/mpeg'; } + elsif ($encoding =~ /mov|qt$/i) { $content_type = 'video/quicktime'; } + elsif ($encoding =~ /avi/i) { $content_type = 'video/x-msvideo'; } + elsif ($encoding =~ /zip/i) { $content_type = 'application/x-zip-compressed'; } + elsif ($encoding =~ /tar/i) { $content_type = 'application/x-tar'; } + elsif ($encoding =~ /jar/i) { $content_type = 'application/java-archive'; } + elsif ($encoding =~ /exe|bin/i) { $content_type = 'application/octet-stream'; } + elsif ($encoding =~ /ppt|pot|ppa|pps|pwz/i) { $content_type = 'application/vnd.ms-powerpoint'; } + elsif ($encoding =~ /mdb|mda|mde/i) { $content_type = 'application/vnd.ms-access'; } + elsif ($encoding =~ /xls|xlt|xlm|xld|xla|xlc|xlw|xll/i) { $content_type = 'application/vnd.ms-excel'; } + elsif ($encoding =~ /doc|dot/i) { $content_type = 'application/msword'; } + elsif ($encoding =~ /rtf/i) { $content_type = 'application/rtf'; } + elsif ($encoding =~ /pdf/i) { $content_type = 'application/pdf'; } + elsif ($encoding =~ /tex/i) { $content_type = 'application/x-tex'; } + elsif ($encoding =~ /latex/i) { $content_type = 'application/x-latex'; } + elsif ($encoding =~ /vcf/i) { $content_type = 'application/x-vcard'; } + else { $content_type = 'application/octet-stream'; } + + + ############################ + ## Process the attachment ## + ############################ + + ##################################### + ## Generate and print MIME headers ## + ##################################### + + $y = "$CRLF--$conf{'delimiter'}$CRLF"; + $y .= "Content-Type: $content_type;$CRLF"; + $y .= " name=\"$filename_name\"$CRLF"; + $y .= "Content-Transfer-Encoding: base64$CRLF"; + $y .= "Content-Disposition: attachment; filename=\"$filename_name\"$CRLF"; + $y .= "$CRLF"; + print $SERVER $y; + + + ########################################################### + ## Convert the file to base64 and print it to the server ## + ########################################################### + + open (FILETOATTACH, $filename) || do { + printmsg("ERROR => Opening the file [$filename] for attachment failed with the error: $!", 0); + return(1); + }; + binmode(FILETOATTACH); ## Hack to make Win32 work + + my $res = ""; + my $tmp = ""; + my $base64 = ""; + while () { ## Read a line from the (binary) file + $res .= $_; + + ################################### + ## Convert binary data to base64 ## + ################################### + while ($res =~ s/(.{45})//s) { ## Get 45 bytes from the binary string + $tmp = substr(pack('u', $&), 1); ## Convert the binary to uuencoded text + chop($tmp); + $tmp =~ tr|` -_|AA-Za-z0-9+/|; ## Translate from uuencode to base64 + $base64 .= $tmp; + } + + ################################ + ## Print chunks to the server ## + ################################ + while ($base64 =~ s/(.{76})//s) { + print $SERVER "$1$CRLF"; + } + + } + + ################################### + ## Encode and send the leftovers ## + ################################### + my $padding = ""; + if ( ($res) and (length($res) >= 1) ) { + $padding = (3 - length($res) % 3) % 3; ## Set flag if binary data isn't divisible by 3 + $res = substr(pack('u', $res), 1); ## Convert the binary to uuencoded text + chop($res); + $res =~ tr|` -_|AA-Za-z0-9+/|; ## Translate from uuencode to base64 + } + + ############################ + ## Fix padding at the end ## + ############################ + $res = $base64 . $res; ## Get left overs from above + $res =~ s/.{$padding}$/'=' x $padding/e if $padding; ## Fix the end padding if flag (from above) is set + if ($res) { + while ($res =~ s/(.{1,76})//s) { ## Send it to the email server. + print $SERVER "$1$CRLF"; + } + } + + close (FILETOATTACH) || do { + printmsg("ERROR - Closing the filehandle for file [$filename] failed with the error: $!", 0); + return(2); + }; + + ## Return 0 errors + return(0); + +} + + + + + + + + + +############################################################################################### +## Function: $string = get_hostname (boot $fqdn) +## +## Description: Tries really hard to returns the short (or FQDN) hostname of the current +## system. Uses techniques and code from the Sys-Hostname module. +## +## Input: $fqdn A true value (1) will cause this function to return a FQDN hostname +## rather than a short hostname. +## +## Output: Returns a string +############################################################################################### +sub get_hostname { + ## Assign incoming parameters to variables + my ( $fqdn ) = @_; + my $hostname = ""; + + ## STEP 1: Get short hostname + + ## Load Sys::Hostname if it's available + eval { require Sys::Hostname; }; + unless ($@) { + $hostname = Sys::Hostname::hostname(); + } + + ## If that didn't get us a hostname, try a few other things + else { + ## Windows systems + if ($^O !~ /win/i) { + if ($ENV{'COMPUTERNAME'}) { $hostname = $ENV{'COMPUTERNAME'}; } + if (!$hostname) { $hostname = gethostbyname('localhost'); } + if (!$hostname) { chomp($hostname = `hostname 2> NUL`) }; + } + + ## Unix systems + else { + local $ENV{PATH} = '/usr/bin:/bin:/usr/sbin:/sbin'; ## Paranoia + + ## Try the environment first (Help! What other variables could/should I be checking here?) + if ($ENV{'HOSTNAME'}) { $hostname = $ENV{'HOSTNAME'}; } + + ## Try the hostname command + eval { local $SIG{__DIE__}; local $SIG{CHLD}; $hostname = `hostname 2>/dev/null`; chomp($hostname); } || + + ## Try POSIX::uname(), which strictly can't be expected to be correct + eval { local $SIG{__DIE__}; require POSIX; $hostname = (POSIX::uname())[1]; } || + + ## Try the uname command + eval { local $SIG{__DIE__}; $hostname = `uname -n 2>/dev/null`; chomp($hostname); }; + + } + + ## If we can't find anything else, return "" + if (!$hostname) { + print "WARNING => No hostname could be determined, please specify one with -o fqdn=FQDN option!\n"; + return("unknown"); + } + } + + ## Return the short hostname + unless ($fqdn) { + $hostname =~ s/\..*//; + return(lc($hostname)); + } + + ## STEP 2: Determine the FQDN + + ## First, if we already have one return it. + if ($hostname =~ /\w\.\w/) { return(lc($hostname)); } + + ## Next try using + eval { $fqdn = (gethostbyname($hostname))[0]; }; + if ($fqdn) { return(lc($fqdn)); } + return(lc($hostname)); +} + + + + + + + + +############################################################################################### +## Function: printmsg (string $message, int $level) +## +## Description: Handles all messages - printing them to the screen only if the messages +## $level is >= the global debug level. If $conf{'logFile'} is defined it +## will also log the message to that file. +## +## Input: $message A message to be printed, logged, etc. +## $level The debug level of the message. If +## not defined 0 will be assumed. 0 is +## considered a normal message, 1 and +## higher is considered a debug message. +## +## Output: Prints to STDOUT +## +## Assumptions: $conf{'hostname'} should be the name of the computer we're running on. +## $conf{'stdout'} should be set to 1 if you want to print to stdout +## $conf{'logFile'} should be a full path to a log file if you want that +## $conf{'debug'} should be an integer between 0 and 10. +## +## Example: printmsg("WARNING: We believe in generic error messages... NOT!", 0); +############################################################################################### +sub printmsg { + ## Assign incoming parameters to variables + my ( $message, $level ) = @_; + + ## Make sure input is sane + $level = 0 if (!defined($level)); + $message =~ s/\s+$//sgo; + $message =~ s/\r?\n/, /sgo; + + ## Continue only if the debug level of the program is >= message debug level. + if ($conf{'debug'} >= $level) { + + ## Get the date in the format: Dec 3 11:14:04 + my ($sec, $min, $hour, $mday, $mon) = localtime(); + $mon = ('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec')[$mon]; + my $date = sprintf("%s %02d %02d:%02d:%02d", $mon, $mday, $hour, $min, $sec); + + ## Print to STDOUT always if debugging is enabled, or if conf{stdout} is true. + if ( ($conf{'debug'} >= 1) or ($conf{'stdout'} == 1) ) { + print "$date $conf{'hostname'} $conf{'programName'}\[$$\]: $message\n"; + } + + ## Print to the log file if $conf{'logging'} is true + if ($conf{'logFile'}) { + if (openLogFile($conf{'logFile'})) { $conf{'logFile'} = ""; printmsg("ERROR => Opening the file [$conf{'logFile'}] for appending returned the error: $!", 1); } + print LOGFILE "$date $conf{'hostname'} $conf{'programName'}\[$$\]: $message\n"; + } + + } + + ## Return 0 errors + return(0); +} + + + + + + + + + + + + +############################################################################################### +## FUNCTION: +## openLogFile ( $filename ) +## +## +## DESCRIPTION: +## Opens the file $filename and attaches it to the filehandle "LOGFILE". Returns 0 on success +## and non-zero on failure. Error codes are listed below, and the error message gets set in +## global variable $!. +## +## +## Example: +## openFile ("/var/log/sendEmail.log"); +## +############################################################################################### +sub openLogFile { + ## Get the incoming filename + my $filename = $_[0]; + + ## Make sure our file exists, and if the file doesn't exist then create it + if ( ! -f $filename ) { + print STDERR "NOTICE: The log file [$filename] does not exist. Creating it now with mode [0600].\n" if ($conf{'stdout'}); + open (LOGFILE, ">>$filename"); + close LOGFILE; + chmod (0600, $filename); + } + + ## Now open the file and attach it to a filehandle + open (LOGFILE,">>$filename") or return (1); + + ## Put the file into non-buffering mode + select LOGFILE; + $| = 1; + select STDOUT; + + ## Return success + return(0); +} + + + + + + + + +############################################################################################### +## Function: read_file (string $filename) +## +## Description: Reads the contents of a file and returns a two part array: +## ($status, $file-contents) +## $status is 0 on success, non-zero on error. +## +## Example: ($status, $file) = read_file("/etc/passwd"); +############################################################################################### +sub read_file { + my ( $filename ) = @_; + + ## If the value specified is a file, load the file's contents + if ( (-e $filename and -r $filename) ) { + my $FILE; + if(!open($FILE, ' ' . $filename)) { + return((1, "")); + } + my $file = ''; + while (<$FILE>) { + $file .= $_; + } + ## Strip an ending \r\n + $file =~ s/\r?\n$//os; + } + return((1, "")); +} + + + + + + + + + +############################################################################################### +## Function: quit (string $message, int $errorLevel) +## +## Description: Exits the program, optionally printing $message. It +## returns an exit error level of $errorLevel to the +## system (0 means no errors, and is assumed if empty.) +## +## Example: quit("Exiting program normally", 0); +############################################################################################### +sub quit { + my ( $message, $errorLevel ) = @_; + $errorLevel = 0 if (!defined($errorLevel)); + + ## Print exit message + if ($message) { + printmsg($message, 0); + } + + ## Exit + exit($errorLevel); +} + + + + + + + + + + + + +############################################################################################### +## Function: help () +## +## Description: For all those newbies ;) +## Prints a help message and exits the program. +## +############################################################################################### +sub help { +exit(1) if (!$conf{'stdout'}); +print <${colorNoBold} + +Synopsis: $conf{'programName'} -f ADDRESS [options] + + ${colorRed}Required:${colorNormal} + -f ADDRESS from (sender) email address + * At least one recipient required via -t, -cc, or -bcc + * Message body required via -m, STDIN, or -o message-file=FILE + + ${colorGreen}Common:${colorNormal} + -t ADDRESS [ADDR ...] to email address(es) + -u SUBJECT message subject + -m MESSAGE message body + -s SERVER[:PORT] smtp mail relay, default is $conf{'server'}:$conf{'port'} + + ${colorGreen}Optional:${colorNormal} + -a FILE [FILE ...] file attachment(s) + -cc ADDRESS [ADDR ...] cc email address(es) + -bcc ADDRESS [ADDR ...] bcc email address(es) + -xu USERNAME username for SMTP authentication + -xp PASSWORD password for SMTP authentication + + ${colorGreen}Paranormal:${colorNormal} + -b BINDADDR[:PORT] local host bind address + -l LOGFILE log to the specified file + -v verbosity, use multiple times for greater effect + -q be quiet (i.e. no STDOUT output) + -o NAME=VALUE advanced options, for details try: --help misc + -o message-content-type= + -o message-file=FILE -o message-format=raw + -o message-header=HEADER -o message-charset=CHARSET + -o reply-to=ADDRESS -o timeout=SECONDS + -o username=USERNAME -o password=PASSWORD + -o tls= -o fqdn=FQDN + + + ${colorGreen}Help:${colorNormal} + --help the helpful overview you're reading now + --help addressing explain addressing and related options + --help message explain message body input and related options + --help networking explain -s, -b, etc + --help output explain logging and other output options + --help misc explain -o options, TLS, SMTP auth, and more + +EOM +exit(1); +} + + + + + + + + + +############################################################################################### +## Function: helpTopic ($topic) +## +## Description: For all those newbies ;) +## Prints a help message and exits the program. +## +############################################################################################### +sub helpTopic { + exit(1) if (!$conf{'stdout'}); + my ($topic) = @_; + + CASE: { + + + + +## ADDRESSING + ($topic eq 'addressing') && do { + print <" + Just Address: "john.doe\@gmail.com" + +The "Full Name" method is useful if you want a name, rather than a plain +email address, to be displayed in the recipient's From, To, or Cc fields +when they view the message. + + +${colorGreen}Multiple Recipients${colorNormal} +The -t, -cc, and -bcc options each accept multiple addresses. They may be +specified by separating them by either a white space, comma, or semi-colon +separated list. You may also specify the -t, -cc, and -bcc options multiple +times, each occurance will append the new recipients to the respective list. + +Examples: +(I used "-t" in these examples, but it can be "-cc" or "-bcc" as well) + + * Space separated list: + -t jane.doe\@yahoo.com "John Doe " + + * Semi-colon separated list: + -t "jane.doe\@yahoo.com; John Doe " + + * Comma separated list: + -t "jane.doe\@yahoo.com, John Doe " + + * Multiple -t, -cc, or -bcc options: + -t "jane.doe\@yahoo.com" -t "John Doe " + + +EOM + last CASE; + }; + + + + + + +## MESSAGE + ($topic eq 'message') && do { + print < + -o message-header=EMAIL HEADER + -o message-charset=CHARSET + -o message-format=raw + +-u SUBJECT + This option allows you to specify the subject for your email message. + It is not required (anymore) that the subject be quoted, although it + is recommended. The subject will be read until an argument starting + with a hyphen (-) is found. + Examples: + -u "Contact information while on vacation" + -u New Microsoft vulnerability discovered + +-m MESSAGE + This option is one of three methods that allow you to specify the message + body for your email. The message may be specified on the command line + with this -m option, read from a file with the -o message-file=FILE + option, or read from STDIN if neither of these options are present. + + It is not required (anymore) that the message be quoted, although it is + recommended. The message will be read until an argument starting with a + hyphen (-) is found. + Examples: + -m "See you in South Beach, Hawaii. -Todd" + -m Please ensure that you upgrade your systems right away + + Multi-line message bodies may be specified with the -m option by putting + a "\\n" into the message. Example: + -m "This is line 1.\\nAnd this is line 2." + + HTML messages are supported, simply begin your message with "" and + sendEmail will properly label the mime header so MUAs properly render + the message. It is currently not possible without "-o message-format=raw" + to send a message with both text and html parts with sendEmail. + +-o message-file=FILE + This option is one of three methods that allow you to specify the message + body for your email. To use this option simply specify a text file + containing the body of your email message. Examples: + -o message-file=/root/message.txt + -o message-file="C:\\Program Files\\output.txt" + +-o message-content-type= + This option allows you to specify the content-type of the email. If your + email message is an html message but is being displayed as a text message + just add "-o message-content-type=html" to the command line to force it + to display as an html message. This actually just changes the Content-Type: + header. Advanced users will be happy to know that if you specify anything + other than the three options listed above it will use that as the vaule + for the Content-Type header. + +-o message-header=EMAIL HEADER + This option allows you to specify additional email headers to be included. + To add more than one message header simply use this option on the command + line more than once. If you specify a message header that sendEmail would + normally generate the one you specified will be used in it's place. + Do not use this unless you know what you are doing! + Example: + To scare a Microsoft Outlook user you may want to try this: + -o message-header="X-Message-Flag: Message contains illegal content" + Example: + To request a read-receipt try this: + -o message-header="Disposition-Notification-To: " + Example: + To set the message priority try this: + -o message-header="X-Priority: 1" + Priority reference: 1=highest, 2=high, 3=normal, 4=low, 5=lowest + +-o message-charset=CHARSET + This option allows you to specify the character-set for the message body. + The default is iso-8859-1. + +-o message-format=raw + This option instructs sendEmail to assume the message (specified with -m, + read from STDIN, or read from the file specified in -o message-file=FILE) + is already a *complete* email message. SendEmail will not generate any + headers and will transmit the message as-is to the remote SMTP server. + Due to the nature of this option the following command line options will + be ignored when this one is used: + -u SUBJECT + -o message-header=EMAIL HEADER + -o message-charset=CHARSET + -a ATTACHMENT + + +${colorGreen}The Message Body${colorNormal} +The email message body may be specified in one of three ways: + 1) Via the -m MESSAGE command line option. + Example: + -m "This is the message body" + + 2) By putting the message body in a file and using the -o message-file=FILE + command line option. + Example: + -o message-file=/root/message.txt + + 3) By piping the message body to sendEmail when nither of the above command + line options were specified. + Example: + grep "ERROR" /var/log/messages | sendEmail -t you\@domain.com ... + +If the message body begins with "" then the message will be treated as +an HTML message and the MIME headers will be written so that a HTML capable +email client will display the message in it's HTML form. +Any of the above methods may be used with the -o message-format=raw option +to deliver an already complete email message. + + +EOM + last CASE; + }; + + + + + + +## MISC + ($topic eq 'misc') && do { + print < + -o timeout=SECONDS + -o fqdn=FQDN + +-a ATTACHMENT [ATTACHMENT ...] + This option allows you to attach any number of files to your email message. + To specify more than one attachment, simply separate each filename with a + space. Example: -a file1.txt file2.txt file3.txt + +-xu USERNAME + Alias for -o username=USERNAME + +-xp PASSWORD + Alias for -o password=PASSWORD + +-o username=USERNAME (synonym for -xu) + These options allow specification of a username to be used with SMTP + servers that require authentication. If a username is specified but a + password is not, you will be prompted to enter one at runtime. + +-o password=PASSWORD (synonym for -xp) + These options allow specification of a password to be used with SMTP + servers that require authentication. If a username is specified but a + password is not, you will be prompted to enter one at runtime. + +-o tls= + This option allows you to specify if TLS (SSL for SMTP) should be enabled + or disabled. The default, auto, will use TLS automatically if your perl + installation has the IO::Socket::SSL and Net::SSLeay modules available, + and if the remote SMTP server supports TLS. To require TLS for message + delivery set this to yes. To disable TLS support set this to no. A debug + level of one or higher will reveal details about the status of TLS. + +-o timeout=SECONDS + This option sets the timeout value in seconds used for all network reads, + writes, and a few other things. + +-o fqdn=FQDN + This option sets the Fully Qualified Domain Name used during the initial + SMTP greeting. Normally this is automatically detected, but in case you + need to manually set it for some reason or get a warning about detection + failing, you can use this to override the default. + + +EOM + last CASE; + }; + + + + + + +## NETWORKING + ($topic eq 'networking') && do { + print < + -o timeout=SECONDS + +-s SERVER[:PORT] + This option allows you to specify the SMTP server sendEmail should + connect to to deliver your email message to. If this option is not + specified sendEmail will try to connect to localhost:25 to deliver + the message. THIS IS MOST LIKELY NOT WHAT YOU WANT, AND WILL LIKELY + FAIL unless you have a email server (commonly known as an MTA) running + on your computer! + Typically you will need to specify your company or ISP's email server. + For example, if you use CableOne you will need to specify: + -s mail.cableone.net + If you have your own email server running on port 300 you would + probably use an option like this: + -s myserver.mydomain.com:300 + If you're a GMail user try: + -s smtp.gmail.com:587 -xu me\@gmail.com -xp PASSWD + +-b BINDADDR[:PORT] + This option allows you to specify the local IP address (and optional + tcp port number) for sendEmail to bind to when connecting to the remote + SMTP server. This useful for people who need to send an email from a + specific network interface or source address and are running sendEmail on + a firewall or other host with several network interfaces. + +-o tls= + This option allows you to specify if TLS (SSL for SMTP) should be enabled + or disabled. The default, auto, will use TLS automatically if your perl + installation has the IO::Socket::SSL and Net::SSLeay modules available, + and if the remote SMTP server supports TLS. To require TLS for message + delivery set this to yes. To disable TLS support set this to no. A debug + level of one or higher will reveal details about the status of TLS. + +-o timeout=SECONDS + This option sets the timeout value in seconds used for all network reads, + writes, and a few other things. + + +EOM + last CASE; + }; + + + + + + +## OUTPUT + ($topic eq 'output') && do { + print < The help topic specified is not valid!", 1); + }; + +exit(1); +} + + + + + + + + + + + + + + + + + + + + + + +############################# +## ## +## MAIN PROGRAM ## +## ## +############################# + + +## Initialize +initialize(); + +## Process Command Line +processCommandLine(); +$conf{'alarm'} = $opt{'timeout'}; + +## Abort program after $conf{'alarm'} seconds to avoid infinite hangs +alarm($conf{'alarm'}) if ($^O !~ /win/i); ## alarm() doesn't work in win32 + + + + +################################################### +## Read $message from STDIN if -m was not used ## +################################################### + +if (!($message)) { + ## Read message body from a file specified with -o message-file= + if ($opt{'message-file'}) { + if (! -e $opt{'message-file'}) { + printmsg("ERROR => Message body file specified [$opt{'message-file'}] does not exist!", 0); + printmsg("HINT => 1) check spelling of your file; 2) fully qualify the path; 3) doubble quote it", 1); + quit("", 1); + } + if (! -r $opt{'message-file'}) { + printmsg("ERROR => Message body file specified can not be read due to restricted permissions!", 0); + printmsg("HINT => Check permissions on file specified to ensure it can be read", 1); + quit("", 1); + } + if (!open(MFILE, "< " . $opt{'message-file'})) { + printmsg("ERROR => Error opening message body file [$opt{'message-file'}]: $!", 0); + quit("", 1); + } + while () { + $message .= $_; + } + close(MFILE); + } + + ## Read message body from STDIN + else { + alarm($conf{'alarm'}) if ($^O !~ /win/i); ## alarm() doesn't work in win32 + if ($conf{'stdout'}) { + print "Reading message body from STDIN because the '-m' option was not used.\n"; + print "If you are manually typing in a message:\n"; + print " - First line must be received within $conf{'alarm'} seconds.\n" if ($^O !~ /win/i); + print " - End manual input with a CTRL-D on its own line.\n\n" if ($^O !~ /win/i); + print " - End manual input with a CTRL-Z on its own line.\n\n" if ($^O =~ /win/i); + } + while () { ## Read STDIN into $message + $message .= $_; + alarm(0) if ($^O !~ /win/i); ## Disable the alarm since at least one line was received + } + printmsg("Message input complete.", 0); + } +} + +## Replace bare LF's with CRLF's (\012 should always have \015 with it) +$message =~ s/(\015)?(\012|$)/\015\012/g; + +## Replace bare CR's with CRLF's (\015 should always have \012 with it) +$message =~ s/(\015)(\012|$)?/\015\012/g; + +## Check message for bare periods and encode them +$message =~ s/(^|$CRLF)(\.{1})($CRLF|$)/$1.$2$3/g; + +## Get the current date for the email header +my ($sec,$min,$hour,$mday,$mon,$year,$day) = gmtime(); +$year += 1900; $mon = return_month($mon); $day = return_day($day); +my $date = sprintf("%s, %s %s %d %.2d:%.2d:%.2d %s",$day, $mday, $mon, $year, $hour, $min, $sec, $conf{'timezone'}); + + + + +################################## +## Connect to the SMTP server ## +################################## +printmsg("DEBUG => Connecting to $conf{'server'}:$conf{'port'}", 1); +$SIG{'ALRM'} = sub { + printmsg("ERROR => Timeout while connecting to $conf{'server'}:$conf{'port'} There was no response after $conf{'alarm'} seconds.", 0); + printmsg("HINT => Try specifying a different mail relay with the -s option.", 1); + quit("", 1); +}; +alarm($conf{'alarm'}) if ($^O !~ /win/i); ## alarm() doesn't work in win32; +$SERVER = IO::Socket::INET->new( PeerAddr => $conf{'server'}, + PeerPort => $conf{'port'}, + LocalAddr => $conf{'bindaddr'}, + Proto => 'tcp', + Autoflush => 1, + timeout => $conf{'alarm'}, +); +alarm(0) if ($^O !~ /win/i); ## alarm() doesn't work in win32; + +## Make sure we got connected +if ( (!$SERVER) or (!$SERVER->opened()) ) { + printmsg("ERROR => Connection attempt to $conf{'server'}:$conf{'port'} failed: $@", 0); + printmsg("HINT => Try specifying a different mail relay with the -s option.", 1); + quit("", 1); +} + +## Save our IP address for later +$conf{'ip'} = $SERVER->sockhost(); +printmsg("DEBUG => My IP address is: $conf{'ip'}", 1); + + + + + + + +######################### +## Do the SMTP Dance ## +######################### + +## Read initial greeting to make sure we're talking to a live SMTP server +if (SMTPchat()) { quit($conf{'error'}, 1); } + +## We're about to use $opt{'fqdn'}, make sure it isn't empty +if (!$opt{'fqdn'}) { + ## Ok, that means we couldn't get a hostname, how about using the IP address for the HELO instead + $opt{'fqdn'} = "[" . $conf{'ip'} . "]"; +} + +## EHLO +if (SMTPchat('EHLO ' . $opt{'fqdn'})) { + printmsg($conf{'error'}, 0); + printmsg("NOTICE => EHLO command failed, attempting HELO instead"); + if (SMTPchat('HELO ' . $opt{'fqdn'})) { quit($conf{'error'}, 1); } + if ( $opt{'username'} and $opt{'password'} ) { + printmsg("WARNING => The mail server does not support SMTP authentication!", 0); + } +} +else { + + ## Determin if the server supports TLS + if ($conf{'SMTPchat_response'} =~ /STARTTLS/) { + $conf{'tls_server'} = 1; + printmsg("DEBUG => The remote SMTP server supports TLS :)", 2); + } + else { + $conf{'tls_server'} = 0; + printmsg("DEBUG => The remote SMTP server does NOT support TLS :(", 2); + } + + ## Start TLS if possible + if ($conf{'tls_server'} == 1 and $conf{'tls_client'} == 1 and $opt{'tls'} =~ /^(yes|auto)$/) { + printmsg("DEBUG => Starting TLS", 2); + if (SMTPchat('STARTTLS')) { quit($conf{'error'}, 1); } + if (! IO::Socket::SSL->start_SSL($SERVER, SSL_version => 'SSLv23:!SSLv3:!SSLv2', , SSL_verify_mode => 0)) { + quit("ERROR => TLS setup failed: " . IO::Socket::SSL::errstr(), 1); + } + printmsg("DEBUG => TLS: Using cipher: ". $SERVER->get_cipher(), 3); + printmsg("DEBUG => TLS session initialized :)", 1); + + ## Restart our SMTP session + if (SMTPchat('EHLO ' . $opt{'fqdn'})) { quit($conf{'error'}, 1); } + } + elsif ($opt{'tls'} eq 'yes' and $conf{'tls_server'} == 0) { + quit("ERROR => TLS not possible! Remote SMTP server, $conf{'server'}, does not support it.", 1); + } + + + ## Do SMTP Auth if required + if ( $opt{'username'} and $opt{'password'} ) { + if ($conf{'SMTPchat_response'} !~ /AUTH\s/) { + printmsg("NOTICE => Authentication not supported by the remote SMTP server!", 0); + } + else { + my $auth_succeeded = 0; + my $mutual_method = 0; + + # ## SASL CRAM-MD5 authentication method + # if ($conf{'SMTPchat_response'} =~ /\bCRAM-MD5\b/i) { + # printmsg("DEBUG => SMTP-AUTH: Using CRAM-MD5 authentication method", 1); + # if (SMTPchat('AUTH CRAM-MD5')) { quit($conf{'error'}, 1); } + # + # ## FIXME!! + # + # printmsg("DEBUG => User authentication was successful", 1); + # } + + ## SASL LOGIN authentication method + if ($auth_succeeded == 0 and $conf{'SMTPchat_response'} =~ /\bLOGIN\b/i) { + $mutual_method = 1; + printmsg("DEBUG => SMTP-AUTH: Using LOGIN authentication method", 1); + if (!SMTPchat('AUTH LOGIN')) { + if (!SMTPchat(base64_encode($opt{'username'}))) { + if (!SMTPchat(base64_encode($opt{'password'}))) { + $auth_succeeded = 1; + printmsg("DEBUG => User authentication was successful (Method: LOGIN)", 1); + } + } + } + if ($auth_succeeded == 0) { + printmsg("DEBUG => SMTP-AUTH: LOGIN authenticaion failed.", 1); + } + } + + ## SASL PLAIN authentication method + if ($auth_succeeded == 0 and $conf{'SMTPchat_response'} =~ /\bPLAIN\b/i) { + $mutual_method = 1; + printmsg("DEBUG => SMTP-AUTH: Using PLAIN authentication method", 1); + if (SMTPchat('AUTH PLAIN ' . base64_encode("$opt{'username'}\0$opt{'username'}\0$opt{'password'}"))) { + printmsg("DEBUG => SMTP-AUTH: PLAIN authenticaion failed.", 1); + } + else { + $auth_succeeded = 1; + printmsg("DEBUG => User authentication was successful (Method: PLAIN)", 1); + } + } + + ## If none of the authentication methods supported by sendEmail were supported by the server, let the user know + if ($mutual_method == 0) { + printmsg("WARNING => SMTP-AUTH: No mutually supported authentication methods available", 0); + } + + ## If we didn't get authenticated, log an error message and exit + if ($auth_succeeded == 0) { + quit("ERROR => ERROR => SMTP-AUTH: Authentication to $conf{'server'}:$conf{'port'} failed.", 1); + } + } + } +} + +## MAIL FROM +if (SMTPchat('MAIL FROM:<' .(returnAddressParts($from))[1]. '>')) { quit($conf{'error'}, 1); } + +## RCPT TO +my $oneRcptAccepted = 0; +foreach my $rcpt (@to, @cc, @bcc) { + my ($name, $address) = returnAddressParts($rcpt); + if (SMTPchat('RCPT TO:<' . $address . '>')) { + printmsg("WARNING => The recipient <$address> was rejected by the mail server, error follows:", 0); + $conf{'error'} =~ s/^ERROR/WARNING/o; + printmsg($conf{'error'}, 0); + } + elsif ($oneRcptAccepted == 0) { + $oneRcptAccepted = 1; + } +} +## If no recipients were accepted we need to exit with an error. +if ($oneRcptAccepted == 0) { + quit("ERROR => Exiting. No recipients were accepted for delivery by the mail server.", 1); +} + +## DATA +if (SMTPchat('DATA')) { quit($conf{'error'}, 1); } + + +############################### +## Build and send the body ## +############################### +printmsg("INFO => Sending message body",1); + +## If the message-format is raw just send the message as-is. +if ($opt{'message-format'} =~ /^raw$/i) { + print $SERVER $message; +} + +## If the message-format isn't raw, then build and send the message, +else { + + ## Message-ID: + if ($opt{'message-header'} !~ /^Message-ID:/iom) { + $header .= 'Message-ID: <' . $conf{'Message-ID'} . '@' . $conf{'hostname'} . '>' . $CRLF; + } + + ## From: "Name" (the pointless test below is just to keep scoping correct) + if ($from and $opt{'message-header'} !~ /^From:/iom) { + my ($name, $address) = returnAddressParts($from); + $header .= 'From: "' . $name . '" <' . $address . '>' . $CRLF; + } + + ## Reply-To: + if ($opt{'reply-to'} and $opt{'message-header'} !~ /^Reply-To:/iom) { + my ($name, $address) = returnAddressParts($opt{'reply-to'}); + $header .= 'Reply-To: "' . $name . '" <' . $address . '>' . $CRLF; + } + + ## To: "Name" + if ($opt{'message-header'} =~ /^To:/iom) { + ## The user put the To: header in via -o message-header - dont do anything + } + elsif (scalar(@to) > 0) { + $header .= "To:"; + for (my $a = 0; $a < scalar(@to); $a++) { + my $msg = ""; + + my ($name, $address) = returnAddressParts($to[$a]); + $msg = " \"$name\" <$address>"; + + ## If we're not on the last address add a comma to the end of the line. + if (($a + 1) != scalar(@to)) { + $msg .= ","; + } + + $header .= $msg . $CRLF; + } + } + ## We always want a To: line so if the only recipients were bcc'd they don't see who it was sent to + else { + $header .= "To: \"Undisclosed Recipients\" <>$CRLF"; + } + + if (scalar(@cc) > 0 and $opt{'message-header'} !~ /^Cc:/iom) { + $header .= "Cc:"; + for (my $a = 0; $a < scalar(@cc); $a++) { + my $msg = ""; + + my ($name, $address) = returnAddressParts($cc[$a]); + $msg = " \"$name\" <$address>"; + + ## If we're not on the last address add a comma to the end of the line. + if (($a + 1) != scalar(@cc)) { + $msg .= ","; + } + + $header .= $msg . $CRLF; + } + } + + if ($opt{'message-header'} !~ /^Subject:/iom) { + $header .= 'Subject: ' . $subject . $CRLF; ## Subject + } + if ($opt{'message-header'} !~ /^Date:/iom) { + $header .= 'Date: ' . $date . $CRLF; ## Date + } + if ($opt{'message-header'} !~ /^X-Mailer:/iom) { + $header .= 'X-Mailer: sendEmail-'.$conf{'version'}.$CRLF; ## X-Mailer + } + ## I wonder if I should put this in by default? + # if ($opt{'message-header'} !~ /^X-Originating-IP:/iom) { + # $header .= 'X-Originating-IP: ['.$conf{'ip'}.']'.$CRLF; ## X-Originating-IP + # } + + ## Encode all messages with MIME. + if ($opt{'message-header'} !~ /^MIME-Version:/iom) { + $header .= "MIME-Version: 1.0$CRLF"; + } + if ($opt{'message-header'} !~ /^Content-Type:/iom) { + my $content_type = 'multipart/mixed'; + if (scalar(@attachments) == 0) { $content_type = 'multipart/related'; } + $header .= "Content-Type: $content_type; boundary=\"$conf{'delimiter'}\"$CRLF"; + } + + ## Send additional message header line(s) if specified + if ($opt{'message-header'}) { + $header .= $opt{'message-header'}; + } + + ## Send the message header to the server + print $SERVER $header . $CRLF; + + ## Start sending the message body to the server + print $SERVER "This is a multi-part message in MIME format. To properly display this message you need a MIME-Version 1.0 compliant Email program.$CRLF"; + print $SERVER "$CRLF"; + + + ## Send message body + print $SERVER "--$conf{'delimiter'}$CRLF"; + ## Send a message content-type header: + ## If the message contains HTML... + if ($opt{'message-content-type'} eq 'html' or ($opt{'message-content-type'} eq 'auto' and $message =~ /^\s*( 0) { + ## Disable the alarm so people on modems can send big attachments + alarm(0) if ($^O !~ /win/i); ## alarm() doesn't work in win32 + + ## Send the attachments + foreach my $filename (@attachments) { + ## This is check 2, we already checked this above, but just in case... + if ( ! -f $filename ) { + printmsg("ERROR => The file [$filename] doesn't exist! Email will be sent, but without that attachment.", 0); + } + elsif ( ! -r $filename ) { + printmsg("ERROR => Couldn't open the file [$filename] for reading: $! Email will be sent, but without that attachment.", 0); + } + else { + printmsg("DEBUG => Sending the attachment [$filename]", 1); + send_attachment($filename); + } + } + } + + + ## End the mime encoded message + print $SERVER "$CRLF--$conf{'delimiter'}--$CRLF"; +} + + +## Tell the server we are done sending the email +print $SERVER "$CRLF.$CRLF"; +if (SMTPchat()) { quit($conf{'error'}, 1); } + + + +#################### +# We are done!!! # +#################### + +## Disconnect from the server (don't SMTPchat(), it breaks when using TLS) +print $SERVER "QUIT$CRLF"; +close $SERVER; + + + + + + +####################################### +## Generate exit message/log entry ## +####################################### + +if ($conf{'debug'} or $conf{'logging'}) { + printmsg("Generating a detailed exit message", 3); + + ## Put the message together + my $output = "Email was sent successfully! From: <" . (returnAddressParts($from))[1] . "> "; + + if (scalar(@to) > 0) { + $output .= "To: "; + for ($a = 0; $a < scalar(@to); $a++) { + $output .= "<" . (returnAddressParts($to[$a]))[1] . "> "; + } + } + if (scalar(@cc) > 0) { + $output .= "Cc: "; + for ($a = 0; $a < scalar(@cc); $a++) { + $output .= "<" . (returnAddressParts($cc[$a]))[1] . "> "; + } + } + if (scalar(@bcc) > 0) { + $output .= "Bcc: "; + for ($a = 0; $a < scalar(@bcc); $a++) { + $output .= "<" . (returnAddressParts($bcc[$a]))[1] . "> "; + } + } + $output .= "Subject: [$subject] " if ($subject); + if (scalar(@attachments_names) > 0) { + $output .= "Attachment(s): "; + foreach(@attachments_names) { + $output .= "[$_] "; + } + } + $output .= "Server: [$conf{'server'}:$conf{'port'}]"; + + +###################### +# Exit the program # +###################### + + ## Print / Log the detailed message + quit($output, 0); +} +else { + ## Or the standard message + quit("Email was sent successfully!", 0); +} + diff --git a/backoffice/api/tmp/sql.log b/backoffice/api/tmp/sql.log new file mode 100644 index 0000000..fd65884 --- /dev/null +++ b/backoffice/api/tmp/sql.log @@ -0,0 +1,20 @@ + +== +DELETE FROM portanova. WHERE id='3'; +== + +== +DELETE FROM portanova.workplans WHERE id='3'; +== + +== +DELETE FROM portanova.workplans WHERE id='2'; +== + +== +DELETE FROM portanova.workplans WHERE id='4'; +== + +== +DELETE FROM portanova.workplans WHERE id='5'; +== diff --git a/backoffice/api/upload.cgi b/backoffice/api/upload.cgi new file mode 100755 index 0000000..194fca8 --- /dev/null +++ b/backoffice/api/upload.cgi @@ -0,0 +1,242 @@ +#!/Users/kilian/perl5/perlbrew/perls/perl-5.24.1/bin/perl + +use strict; +use lib ('./lib/perl5'); +use lib ('./lib'); +use CGI; +use CGI::Cookie; +#use CGI::Carp qw/fatalsToBrowser/; +use File::Basename; +use File::Path qw/make_path/; +use JSON::PP; +use Image::Size; +use dksconfig qw/$sitecfg/; +use dksdb; + +use session; +use sendemail; +my $cgi = new CGI(); +my $scriptpath = $cgi->url(-absolute => 1); +my $p = (); +my @params = $cgi->param(); +if ($cgi->request_method() eq "POST"){ + foreach my $pe (@params){ + $p->{$pe} = $cgi->param($pe); + } +} +my $html->{result} = (); +$p->{sid} = $cgi->cookie($sitecfg->{cookiename}); +my $se = session->new(); +my $sess = $se->getsession($p->{sid}); +print $cgi->header(-type=>"application/json", -charset => "utf-8");s +if ($sess == undef){ + $html->{error} = "No Authorisation"; + print JSON::PP::encode_json($html); + exit(0); +} +my $utime = time(); +my $db = dksdb->new(); +my $basepath = dirname(dirname($ENV{SCRIPT_FILENAME})); +if ($p->{fn}){ + if ($p->{fn} eq "setsubmission"){ + select * from cdms where id_project= + #select * from vw_submission where id_project= and is_cdm= + if (exists($p->{xlsxfile}) && $p->{xlsxfile} ne ""){ + my $fh = $cgi->upload('file'); + open(NF,">".$basepath.'/'.$filepath); + binmode NF; + while (<$fh>) { + print NF; + } + close(NF); + } + if (exists($p->{pdffile}) && $p->{pdffile} ne ""){ + my $fh = $cgi->upload('file'); + open(NF,">".$basepath.'/'.$filepath); + binmode NF; + while (<$fh>) { + print NF; + } + close(NF); + } + if (exists($p->{otherfile}) && $p->{otherfile} ne ""){ + my $fh = $cgi->upload('file'); + open(NF,">".$basepath.'/'.$filepath); + binmode NF; + while (<$fh>) { + print NF; + } + close(NF); + } + + } + + # my $filepath = ""; + # my $suffix = substr($p->{file},rindex($p->{file},'.')+1); + # if ($p->{filetype} eq "download_document"){ + # $filepath = 'data/documents/'.$p->{file}; + # } + # if ($p->{filetype} eq "news_image"){ + # if ($suffix eq 'jpg' || $suffix eq 'png'){ + # $filepath = '../media/news/'.$p->{file}; + # $p->{relpath} = 'media/news/'.$p->{file}; + # } + # } + #mogrify -thumbnail x300 -background white *.png + #ls -1 members_sized/*.png | awk -F\/ '{print "composite -gravity southeast wm_fld.png members_sized/"$(NF)" members/"$(NF)}' | sh + # if ($p->{upload_filetype} eq "new_profile_photo"){ + # my $sql = "select link from members where id=".$p->{id_member}.";"; + # my $ml = $db->dbquerysorted($sql); + # $filepath = 'data/members/'.$ml->{0}->{link}.'/'.$ml->{0}->{link}.'_new.'.$suffix; + # } elsif ($p->{upload_filetype} eq "profile_photo"){ + # my $sql = "select link from members where id=".$p->{id_member}.";"; + # my $ml = $db->dbquerysorted($sql); + # $filepath = 'data/members/'.$ml->{0}->{link}.'/'.$ml->{0}->{link}.'_new.'.$suffix; + # } elsif ($p->{upload_filetype} eq "spillbou"){ + # $filepath = 'data/championnat/'.$p->{season}.'_'.$p->{playday}.'_'.$p->{team}.'.'.$suffix; + # } elsif ($p->{upload_filetype} eq "member_document"){ + # my $sql = "select link from members where id=".$p->{id_member}.";"; + # my $ml = $db->dbquerysorted($sql); + # $filepath = 'data/members/'.$ml->{0}->{link}.'/'.$p->{upload_file}.'_'.$utime.$suffix; + # } elsif ($p->{upload_filetype} eq "clublogo_new"){ + # my $sql = "select link from clubs where id=".$p->{id_club}.";"; + # my $cl = $db->dbquerysorted($sql); + # $filepath = 'data/clubs/'.$cl->{0}->{link}.'/'.$cl->{0}->{link}.'_new.'.$suffix; + # } elsif ($p->{upload_filetype} eq "clublogo"){ + # my $sql = "select link from clubs where id=".$p->{id_club}.";"; + # my $cl = $db->dbquerysorted($sql); + # $filepath = 'data/clubs/'.$cl->{0}->{link}.'/'.$cl->{0}->{link}.'.'.$suffix; + # }elsif ($p->{upload_filetype} eq "website_image"){ + # $basepath = $ENV{"DOCUMENT_ROOT"}; + # $filepath = 'images/'.$p->{folder}.'/'.$p->{upload_file}; +# if ($filepath ne ""){ +# $p->{path} = $basepath.'/'.$filepath; +# $p->{suffix} = $suffix; +# my $fh = $cgi->upload('file'); +# open(NF,">".$basepath.'/'.$filepath); +# binmode NF; +# while (<$fh>) { +# print NF; +# } +# close(NF); +# if ($p->{filetype} eq "download_document"){ +# if ($suffix eq 'png' || $suffix eq 'jpg' || $suffix eq 'pdf'){ +# system('convert -thumbnail x128 -background white -alpha remove "'.$basepath.'/'.$filepath.'" "'.$basepath.'/thumb/'.$filepath.'.thumb.png"'); +# } + +# if ($p->{row_id} eq ""){ +# my $dx = $db->dbquerysorted("select id from documents where filename='".basename($filepath)."' and folder='documents'"); +# if (keys(%{$dx}) == 0){ +# my $sql = "INSERT INTO documents (filename,folder,filetype) VALUES ('".basename($filepath)."','documents','".$suffix."');"; +# $db->dbexec($sql); +# } +# } +# } +# if ($p->{filetype} eq "news_image"){ +# my ($pwidth,$pheight) =imgsize($p->{path}); +# my $width=0; +# my $height =0; +# my $density = 72; +# if ($pwidth>700){ +# $width = 700; +# } elsif ($height > 380) { +# $height = 380; +# } +# if ($height == 0){ +# $height = ($pheight/$pwidth) * $width; +# } +# elsif ($width == 0) { +# $width = ($pwidth/$pheight) * $height; +# } +# if ($height > 380){ +# $height = 380; +# $width = ($width/$height) * $height; +# } +# system("mogrify -resize ".$width."x".$height." -density ".$density." ".$p->{path}); +# } + +# # if ($p->{upload_filetype} eq "new_profile_photo"){ +# # #convert! +# # $db->dbexec("update members set new_profile_photo='".$filepath."' where id=".$p->{id_member}.";"); +# # $html->{result}->{new_profile_photo}= $filepath; +# # } elsif ($p->{upload_filetype} eq "profile_photo"){ +# # #convert! +# # $db->dbexec("update members set profile_photo='".$filepath."' where id=".$p->{id_member}.";"); +# # $html->{result}->{new_profile_photo}= $filepath; +# # } elsif ($p->{upload_filetype} eq "spillbou"){ +# # $db->dbexec("update csresult set upload_team".$p->{team}."='".$filepath."' where id=;"); +# # } elsif ($p->{upload_filetype} eq "member_document"){ + +# # } elsif ($p->{upload_filetype} eq "clublogo_new"){ + +# # } elsif ($p->{upload_filetype} eq "clublogo"){ + +# # } elsif ($p->{upload_filetype} eq "website_image"){ + +# # } els +# } +# } +# if (exists($p->{gameresult})){ +# my $basepath = dirname(dirname($ENV{SCRIPT_FILENAME})); +# my $csdir = "data/championship/"; +# my $gmid = $p->{id}; +# my $cdata = $db->dbquerybykey("id","select * from vw_games where id=".$gmid); + +# if ($p->{result_teamhome} ne ""){ +# my $suffix = substr($p->{upload_teamhome},rindex($p->{upload_teamhome},'.')+1); +# my $fh = $cgi->upload('upload_teamhome'); +# my $filepath = $basepath.'/'.$csdir.'/'.$cdata->{$gmid}->{season}.'/'.$cdata->{$gmid}->{playday}.'_'.$cdata->{$gmid}->{link_teamhome}.'.'.$suffix; +# open(NF,">".$filepath); +# binmode NF; +# while (<$fh>) { +# print NF; +# } +# close(NF); +# $db->dbexec("UPDATE csgames set upload_teamhome='".basename($filepath)."',result_teamhome='".$p->{result_teamhome}."' WHERE id=".$gmid); + +# #transform document an make thumbnail +# } +# if ($p->{result_teamguest} ne ""){ +# my $suffix = substr($p->{upload_teamguest},rindex($p->{upload_teamguest},'.')+1); +# my $fh = $cgi->upload('upload_teamguest'); +# my $filepath = $basepath.'/'.$csdir.'/'.$cdata->{$gmid}->{season}.'/'.$cdata->{$gmid}->{playday}.'_'.$cdata->{$gmid}->{link_teamguest}.'.'.$suffix; +# open(NF,">".$filepath); +# binmode NF; +# while (<$fh>) { +# print NF; +# } +# close(NF); +# $db->dbexec("UPDATE csgames set upload_teamguest='".basename($filepath)."',result_teamguest='".$p->{result_teamguest}."' WHERE id=".$gmid); +# #transform document an make thumbnail +# } +# $cdata = $db->dbquerybykey("id","select * from vw_games where id=".$gmid); +# if ($cdata->{$gmid}->{result_teamhome} eq $cdata->{$gmid}->{result_teamguest}){ + +# my $pth = "null"; +# my $ptg = "null"; +# my @x = (); +# if (($sess->{usergroups} =~ /fld/ ) && ($p->{sets_teamhome} ne "") && ($p->{sets_teamgoust} ne "")){ +# push(@x,$p->{sets_teamhome}); +# push(@x,$p->{sets_teamguest}); +# } else { +# @x= split("-",$cdata->{$gmid}->{result_teamhome}); +# } +# if (int($x[0]) > int($x[1])){$pth = 3;$ptg=0;} else {$pth = 0;$ptg=3;} +# if (int($x[0]) == int($x[1])){$pth = 1; $ptg = 1;} +# $db->dbexec("update csgames set sets_teamhome=".$x[0].", sets_teamguest=".$x[1].",points_teamhome=".$pth.",points_teamguest=".$ptg." WHERE id=".$gmid.";"); +# if (($sess->{usergroups} =~ /fld/ ) && ($p->{validated} eq "1")) { +# $db->dbexec("update csgames set validated=true WHERE id=".$gmid.";"); +# } +# } else { +# $db->dbexec("update csgames set sets_teamhome=null, sets_teamguest=null,points_teamhome=null,points_teamguest=null,validated=null WHERE id=".$gmid.";"); +# } +# $db->dbexec("select * from setcsranking('".$cdata->{$gmid}->{id_season}."','".$cdata->{$gmid}->{id_division}."');"); +# } +my $js = JSON::PP->new(); +$js->allow_blessed(1); +# open(NF,">upload.txt"); +# print NF $js->utf8->encode($p); +# print NF $js->utf8->encode($sess); +# close(NF); +$html->{result}->{p} = $p; +print $js->utf8->encode($p); \ No newline at end of file diff --git a/backoffice/css/module.css b/backoffice/css/module.css new file mode 100644 index 0000000..ca08b42 --- /dev/null +++ b/backoffice/css/module.css @@ -0,0 +1,8 @@ +/* input::-webkit-calendar-picker-indicator{ + display: none; +} +And to hide the prompt: + +input[type="date"]::-webkit-input-placeholder{ + visibility: hidden !important; +} */ \ No newline at end of file diff --git a/backoffice/css/w3pro.css b/backoffice/css/w3pro.css new file mode 100644 index 0000000..7b4b45d --- /dev/null +++ b/backoffice/css/w3pro.css @@ -0,0 +1,379 @@ +/* W3PRO.CSS 4.13 June 2019 by Jan Egil and Borge Refsnes */ +html{box-sizing:border-box}*,*:before,*:after{box-sizing:inherit} +/* Extract from normalize.css by Nicolas Gallagher and Jonathan Neal git.io/normalize */ +html{-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%}body{margin:0} +article,aside,details,figcaption,figure,footer,header,main,menu,nav,section{display:block}summary{display:list-item} +audio,canvas,progress,video{display:inline-block}progress{vertical-align:baseline} +audio:not([controls]){display:none;height:0}[hidden],template{display:none} +a{background-color:transparent}a:active,a:hover{outline-width:0} +abbr[title]{border-bottom:none;text-decoration:underline;text-decoration:underline dotted} +b,strong{font-weight:bolder}dfn{font-style:italic}mark{background:#ff0;color:#000} +small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline} +sub{bottom:-0.25em}sup{top:-0.5em}figure{margin:1em 40px}img{border-style:none} +code,kbd,pre,samp{font-family:monospace,monospace;font-size:1em}hr{box-sizing:content-box;height:0;overflow:visible} +button,input,select,textarea,optgroup{font:inherit;margin:0}optgroup{font-weight:bold} +button,input{overflow:visible}button,select{text-transform:none} +button,[type=button],[type=reset],[type=submit]{-webkit-appearance:button} +button::-moz-focus-inner,[type=button]::-moz-focus-inner,[type=reset]::-moz-focus-inner,[type=submit]::-moz-focus-inner{border-style:none;padding:0} +button:-moz-focusring,[type=button]:-moz-focusring,[type=reset]:-moz-focusring,[type=submit]:-moz-focusring{outline:1px dotted ButtonText} +fieldset{border:1px solid #c0c0c0;margin:0 2px;padding:.35em .625em .75em} +legend{color:inherit;display:table;max-width:100%;padding:0;white-space:normal}textarea{overflow:auto} +[type=checkbox],[type=radio]{padding:0} +[type=number]::-webkit-inner-spin-button,[type=number]::-webkit-outer-spin-button{height:auto} +[type=search]{-webkit-appearance:textfield;outline-offset:-2px} +[type=search]::-webkit-search-decoration{-webkit-appearance:none} +::-webkit-file-upload-button{-webkit-appearance:button;font:inherit} +/* End extract */ +html,body{font-family:Verdana,sans-serif;font-size:15px;line-height:1.5}html{overflow-x:hidden} +h1{font-size:36px}h2{font-size:30px}h3{font-size:24px}h4{font-size:20px}h5{font-size:18px}h6{font-size:16px}.w3-serif{font-family:serif} +h1,h2,h3,h4,h5,h6{font-family:"Segoe UI",Arial,sans-serif;font-weight:400;margin: 0}.w3-wide{letter-spacing:4px} +hr{border:0;border-top:1px solid #eee;margin:20px 0} +.w3-image{max-width:100%;height:auto}img{vertical-align:middle}a{color:inherit} +.w3-table,.w3-table-all{border-collapse:collapse;border-spacing:0;width:100%;display:table}.w3-table-all{border:1px solid #ccc} +.w3-bordered tr,.w3-table-all tr{border-bottom:1px solid #ddd}.w3-striped tbody tr:nth-child(even){background-color:#f1f1f1} +.w3-table-all tr:nth-child(odd){background-color:#fff}.w3-table-all tr:nth-child(even){background-color:#f1f1f1} +.w3-hoverable tbody tr:hover,.w3-ul.w3-hoverable li:hover{background-color:#ccc}.w3-centered tr th,.w3-centered tr td{text-align:center} +.w3-table td,.w3-table th,.w3-table-all td,.w3-table-all th{padding:8px 8px;display:table-cell;text-align:left;vertical-align:top} +.w3-table th:first-child,.w3-table td:first-child,.w3-table-all th:first-child,.w3-table-all td:first-child{padding-left:16px} +.w3-btn,.w3-button{border:none;display:inline-block;padding:8px 16px;vertical-align:middle;overflow:hidden;text-decoration:none;color:inherit;background-color:inherit;text-align:center;cursor:pointer;white-space:nowrap} +.w3-btn:hover{box-shadow:0 8px 16px 0 rgba(0,0,0,0.2),0 6px 20px 0 rgba(0,0,0,0.19)} +.w3-btn,.w3-button{-webkit-touch-callout:none;-webkit-user-select:none;-khtml-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none} +.w3-disabled,.w3-btn:disabled,.w3-button:disabled{cursor:not-allowed;opacity:0.3}.w3-disabled *,:disabled *{pointer-events:none} +.w3-btn.w3-disabled:hover,.w3-btn:disabled:hover{box-shadow:none} +.w3-badge,.w3-tag{background-color:#000;color:#fff;display:inline-block;padding-left:8px;padding-right:8px;text-align:center}.w3-badge{border-radius:50%} +.w3-ul{list-style-type:none;padding:0;margin:0}.w3-ul li{padding:8px 16px;border-bottom:1px solid #ddd}.w3-ul li:last-child{border-bottom:none} +.w3-tooltip,.w3-display-container{position:relative}.w3-tooltip .w3-text{display:none}.w3-tooltip:hover .w3-text{display:inline-block} +.w3-ripple:active{opacity:0.5}.w3-ripple{transition:opacity 0s} +.w3-input{padding:4px;display:block;border:1px solid #ccc;width:100%;background-color: #e8f0fe; } +.w3-select{padding:4px 0; display:block;width:100%;border:1px solid #ccc;background-color: #e8f0fe;} +.w3-dropdown-click,.w3-dropdown-hover{position:relative;display:inline-block;cursor:pointer} +.w3-dropdown-hover:hover .w3-dropdown-content{display:block; } +.w3-dropdown-hover:first-child,.w3-dropdown-click:hover{background-color:#ccc;color:#000} +.w3-dropdown-hover:hover > .w3-button:first-child,.w3-dropdown-click:hover > .w3-button:first-child{background-color:#ccc;color:#000} +.w3-dropdown-content{cursor:auto;color:#000;background-color:#fff;display:none;position:absolute;min-width:160px;margin:0;padding:0;z-index:1} +.w3-check,.w3-radio{width:24px;height:24px;position:relative;top:6px} +.w3-sidebar{height:100%;width:200px;background-color:#fff;position:fixed!important;z-index:1;overflow:auto} +.w3-bar-block .w3-dropdown-hover,.w3-bar-block .w3-dropdown-click{width:100%} +.w3-bar-block .w3-dropdown-hover .w3-dropdown-content,.w3-bar-block .w3-dropdown-click .w3-dropdown-content{min-width:100%} +.w3-bar-block .w3-dropdown-hover .w3-button,.w3-bar-block .w3-dropdown-click .w3-button{width:100%;text-align:left;padding:8px 16px} +.w3-main,#main{transition:margin-left .4s} +.w3-modal{z-index:3;display:none;padding-top:100px;position:fixed;left:0;top:0;width:100%;height:100%;overflow:auto;background-color:rgb(0,0,0);background-color:rgba(0,0,0,0.4)} +.w3-modal-content{margin:auto;background-color:#fff;position:relative;padding:0;outline:0;width:600px} +.w3-bar{width:100%;overflow:hidden}.w3-center .w3-bar{display:inline-block;width:auto} +.w3-bar .w3-bar-item{padding:8px 16px;float:left;width:auto;border:none;display:block;outline:0} +.w3-bar .w3-dropdown-hover,.w3-bar .w3-dropdown-click{position:static;float:left} +.w3-bar .w3-button{white-space:normal} +.w3-bar-block .w3-bar-item{width:100%;display:block;padding:8px 16px;text-align:left;border:none;white-space:normal;float:none;outline:0} +.w3-bar-block.w3-center .w3-bar-item{text-align:center}.w3-block{display:block;width:100%} +.w3-responsive{display:block;overflow-x:auto} +.w3-container:after,.w3-container:before,.w3-panel:after,.w3-panel:before,.w3-row:after,.w3-row:before,.w3-row-padding:after,.w3-row-padding:before, +.w3-cell-row:before,.w3-cell-row:after,.w3-clear:after,.w3-clear:before,.w3-bar:before,.w3-bar:after{content:"";display:table;clear:both} +.w3-col,.w3-half,.w3-third,.w3-twothird,.w3-threequarter,.w3-quarter,.w3-fifth,.w3-twofifth,.w3-threefifth,.w3-fourfifth{float:left;width:100%} +.w3-col.s1{width:8.33333%}.w3-col.s2{width:16.66666%}.w3-col.s3{width:24.99999%}.w3-col.s4{width:33.33333%} +.w3-col.s5{width:41.66666%}.w3-col.s6{width:49.99999%}.w3-col.s7{width:58.33333%}.w3-col.s8{width:66.66666%} +.w3-col.s9{width:74.99999%}.w3-col.s10{width:83.33333%}.w3-col.s11{width:91.66666%}.w3-col.s12{width:99.99999%} +@media (min-width:601px){.w3-col.m1{width:8.33333%}.w3-col.m2{width:16.66666%}.w3-col.m3,.w3-quarter{width:24.99999%}.w3-col.m4,.w3-third{width:33.33333%}.w3-fifth{width:20%;min-width:100px} +.w3-col.m5{width:41.66666%}.w3-col.m6,.w3-half{width:49.99999%}.w3-col.m7{width:58.33333%}.w3-col.m8,.w3-twothird{width:66.66666%} +.w3-col.m9,.w3-threequarter{width:74.99999%}.w3-col.m10{width:83.33333%}.w3-col.m11{width:91.66666%}.w3-col.m12{width:99.99999%}.w3-twofifth{width:40%}.w3-threefifth{width:60%}.w3-fourfifth{width:80%}} +@media (min-width:993px){.w3-col.l1{width:8.33333%}.w3-col.l2{width:16.66666%}.w3-col.l3{width:24.99999%}.w3-col.l4{width:33.33333%} +.w3-col.l5{width:41.66666%}.w3-col.l6{width:49.99999%}.w3-col.l7{width:58.33333%}.w3-col.l8{width:66.66666%} +.w3-col.l9{width:74.99999%}.w3-col.l10{width:83.33333%}.w3-col.l11{width:91.66666%}.w3-col.l12{width:99.99999%}} +.w3-rest{overflow:hidden}.w3-stretch{margin-left:-16px;margin-right:-16px} +.w3-content,.w3-auto{margin-left:auto;margin-right:auto}.w3-content{max-width:980px}.w3-auto{max-width:1140px} +.w3-cell-row{display:table;width:100%}.w3-cell{display:table-cell} +.w3-cell-top{vertical-align:top}.w3-cell-middle{vertical-align:middle}.w3-cell-bottom{vertical-align:bottom} +.w3-hide{display:none!important}.w3-show-block,.w3-show{display:block!important}.w3-show-inline-block{display:inline-block!important} +@media (max-width:1205px){.w3-auto{max-width:95%}} +@media (max-width:600px){.w3-modal-content{margin:0 10px;width:auto!important}.w3-modal{padding-top:30px} +.w3-dropdown-hover.w3-mobile .w3-dropdown-content,.w3-dropdown-click.w3-mobile .w3-dropdown-content{position:relative} +.w3-hide-small{display:none!important}.w3-mobile{display:block;width:100%!important}.w3-bar-item.w3-mobile,.w3-dropdown-hover.w3-mobile,.w3-dropdown-click.w3-mobile{text-align:center} +.w3-dropdown-hover.w3-mobile,.w3-dropdown-hover.w3-mobile .w3-btn,.w3-dropdown-hover.w3-mobile .w3-button,.w3-dropdown-click.w3-mobile,.w3-dropdown-click.w3-mobile .w3-btn,.w3-dropdown-click.w3-mobile .w3-button{width:100%}} +@media (max-width:768px){.w3-modal-content{width:500px}.w3-modal{padding-top:50px}} +@media (min-width:993px){.w3-modal-content{width:900px}.w3-hide-large{display:none!important}.w3-sidebar.w3-collapse{display:block!important}} +@media (max-width:992px) and (min-width:601px){.w3-hide-medium{display:none!important}} +@media (max-width:992px){.w3-sidebar.w3-collapse{display:none}.w3-main{margin-left:0!important;margin-right:0!important}.w3-auto{max-width:100%}} +.w3-top,.w3-bottom{position:fixed;width:100%;z-index:1}.w3-top{top:0}.w3-bottom{bottom:0} +.w3-overlay{position:fixed;display:none;width:100%;height:100%;top:0;left:0;right:0;bottom:0;background-color:rgba(0,0,0,0.5);z-index:2} +.w3-display-topleft{position:absolute;left:0;top:0}.w3-display-topright{position:absolute;right:0;top:0} +.w3-display-bottomleft{position:absolute;left:0;bottom:0}.w3-display-bottomright{position:absolute;right:0;bottom:0} +.w3-display-middle{position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);-ms-transform:translate(-50%,-50%)} +.w3-display-left{position:absolute;top:50%;left:0%;transform:translate(0%,-50%);-ms-transform:translate(-0%,-50%)} +.w3-display-right{position:absolute;top:50%;right:0%;transform:translate(0%,-50%);-ms-transform:translate(0%,-50%)} +.w3-display-topmiddle{position:absolute;left:50%;top:0;transform:translate(-50%,0%);-ms-transform:translate(-50%,0%)} +.w3-display-bottommiddle{position:absolute;left:50%;bottom:0;transform:translate(-50%,0%);-ms-transform:translate(-50%,0%)} +.w3-display-container:hover .w3-display-hover{display:block}.w3-display-container:hover span.w3-display-hover{display:inline-block}.w3-display-hover{display:none} +.w3-display-position{position:absolute} +.w3-circle{border-radius:50%} +.w3-round-small{border-radius:2px}.w3-round,.w3-round-medium{border-radius:4px}.w3-round-large{border-radius:8px}.w3-round-xlarge{border-radius:16px}.w3-round-xxlarge{border-radius:32px} +.w3-row-padding,.w3-row-padding>.w3-half,.w3-row-padding>.w3-third,.w3-row-padding>.w3-twothird,.w3-row-padding>.w3-threequarter,.w3-row-padding>.w3-quarter,.w3-row-padding>.w3-col{padding:0 8px} +.w3-container,.w3-panel{padding:0.01em 8px}.w3-panel{margin-top:8px;margin-bottom:8px} +.w3-code,.w3-codespan{font-family:Consolas,"courier new";font-size:16px} +.w3-code{width:auto;background-color:#fff;padding:8px 12px;border-left:4px solid #4CAF50;word-wrap:break-word} +.w3-codespan{color:crimson;background-color:#f1f1f1;padding-left:4px;padding-right:4px;font-size:110%} +.w3-card,.w3-card-2{box-shadow:0 2px 5px 0 rgba(0,0,0,0.16)} +.w3-card-4,.w3-hover-shadow:hover{box-shadow:0 4px 10px 0 rgba(0,0,0,0.2),0 4px 20px 0 rgba(0,0,0,0.19)} +.w3-spin{animation:w3-spin 2s infinite linear}@keyframes w3-spin{0%{transform:rotate(0deg)}100%{transform:rotate(359deg)}} +.w3-animate-fading{animation:fading 10s infinite}@keyframes fading{0%{opacity:0}50%{opacity:1}100%{opacity:0}} +.w3-animate-opacity{animation:opac 0.8s}@keyframes opac{from{opacity:0} to{opacity:1}} +.w3-animate-top{position:relative;animation:animatetop 0.4s}@keyframes animatetop{from{top:-300px;opacity:0} to{top:0;opacity:1}} +.w3-animate-left{position:relative;animation:animateleft 0.4s}@keyframes animateleft{from{left:-300px;opacity:0} to{left:0;opacity:1}} +.w3-animate-right{position:relative;animation:animateright 0.4s}@keyframes animateright{from{right:-300px;opacity:0} to{right:0;opacity:1}} +.w3-animate-bottom{position:relative;animation:animatebottom 0.4s}@keyframes animatebottom{from{bottom:-300px;opacity:0} to{bottom:0;opacity:1}} +.w3-animate-zoom {animation:animatezoom 0.6s}@keyframes animatezoom{from{transform:scale(0)} to{transform:scale(1)}} +.w3-animate-input{transition:width 0.4s ease-in-out}.w3-animate-input:focus{width:100%!important} +.w3-opacity,.w3-hover-opacity:hover{opacity:0.60}.w3-opacity-off,.w3-hover-opacity-off:hover{opacity:1} +.w3-opacity-max{opacity:0.25}.w3-opacity-min{opacity:0.75} +.w3-greyscale-max,.w3-grayscale-max,.w3-hover-greyscale:hover,.w3-hover-grayscale:hover{filter:grayscale(100%)} +.w3-greyscale,.w3-grayscale{filter:grayscale(75%)}.w3-greyscale-min,.w3-grayscale-min{filter:grayscale(50%)} +.w3-sepia{filter:sepia(75%)}.w3-sepia-max,.w3-hover-sepia:hover{filter:sepia(100%)}.w3-sepia-min{filter:sepia(50%)} +.w3-tiny{font-size:10px!important}.w3-small{font-size:12px!important}.w3-medium{font-size:15px!important}.w3-large{font-size:18px!important} +.w3-xlarge{font-size:24px!important}.w3-xxlarge{font-size:36px!important}.w3-xxxlarge{font-size:48px!important}.w3-jumbo{font-size:64px!important} +.w3-left-align{text-align:left!important}.w3-right-align{text-align:right!important}.w3-justify{text-align:justify!important}.w3-center{text-align:center!important} +.w3-border-0{border:0!important}.w3-border{border:1px solid #ccc!important} +.w3-border-top{border-top:1px solid #ccc!important}.w3-border-bottom{border-bottom:1px solid #ccc!important} +.w3-border-left{border-left:1px solid #ccc!important}.w3-border-right{border-right:1px solid #ccc!important} +.w3-topbar{border-top:6px solid #ccc!important}.w3-bottombar{border-bottom:6px solid #ccc!important} +.w3-leftbar{border-left:6px solid #ccc!important}.w3-rightbar{border-right:6px solid #ccc!important} +.w3-section,.w3-code{margin-top:16px!important;margin-bottom:16px!important} +.w3-margin{margin:16px!important}.w3-margin-top{margin-top:16px!important}.w3-margin-bottom{margin-bottom:16px!important} +.w3-margin-left{margin-left:16px!important}.w3-margin-right{margin-right:16px!important} +.w3-padding-small{padding:4px 8px!important}.w3-padding{padding:8px 16px!important}.w3-padding-large{padding:12px 24px!important} +.w3-padding-16{padding-top:16px!important;padding-bottom:16px!important}.w3-padding-24{padding-top:24px!important;padding-bottom:24px!important} +.w3-padding-32{padding-top:32px!important;padding-bottom:32px!important}.w3-padding-48{padding-top:48px!important;padding-bottom:48px!important} +.w3-padding-64{padding-top:64px!important;padding-bottom:64px!important} +.w3-left{float:left!important}.w3-right{float:right!important} +.w3-button:hover{color:#000!important;background-color:#ccc!important} +.w3-transparent,.w3-hover-none:hover{background-color:transparent!important} +.w3-hover-none:hover{box-shadow:none!important} +/* DEFAULT COLORS */ +.w3-amber,.w3-hover-amber:hover{color:#000!important;background-color:#ffc107!important} +.w3-aqua,.w3-hover-aqua:hover{color:#000!important;background-color:#00ffff!important} +.w3-blue,.w3-hover-blue:hover{color:#fff!important;background-color:#2196F3!important} +.w3-light-blue,.w3-hover-light-blue:hover{color:#000!important;background-color:#87CEEB!important} +.w3-brown,.w3-hover-brown:hover{color:#fff!important;background-color:#795548!important} +.w3-cyan,.w3-hover-cyan:hover{color:#000!important;background-color:#00bcd4!important} +.w3-blue-grey,.w3-hover-blue-grey:hover{color:#fff!important;background-color:#607d8b!important} +.w3-green,.w3-hover-green:hover{color:#fff!important;background-color:#4CAF50!important} +.w3-light-green,.w3-hover-light-green:hover{color:#000!important;background-color:#8bc34a!important} +.w3-indigo,.w3-hover-indigo:hover{color:#fff!important;background-color:#3f51b5!important} +.w3-khaki,.w3-hover-khaki:hover{color:#000!important;background-color:#f0e68c!important} +.w3-lime,.w3-hover-lime:hover{color:#000!important;background-color:#cddc39!important} +.w3-orange,.w3-hover-orange:hover{color:#000!important;background-color:#ff9800!important} +.w3-deep-orange,.w3-hover-deep-orange:hover{color:#fff!important;background-color:#ff5722!important} +.w3-pink,.w3-hover-pink:hover{color:#fff!important;background-color:#e91e63!important} +.w3-purple,.w3-hover-purple:hover{color:#fff!important;background-color:#9c27b0!important} +.w3-deep-purple,.w3-hover-deep-purple:hover{color:#fff!important;background-color:#673ab7!important} +.w3-red,.w3-hover-red:hover{color:#fff!important;background-color:#f44336!important} +.w3-sand,.w3-hover-sand:hover{color:#000!important;background-color:#fdf5e6!important} +.w3-teal,.w3-hover-teal:hover{color:#fff!important;background-color:#009688!important} +.w3-yellow,.w3-hover-yellow:hover{color:#000!important;background-color:#ffeb3b!important} +.w3-white,.w3-hover-white:hover{color:#000!important;background-color:#fff!important} +.w3-black,.w3-hover-black:hover{color:#fff!important;background-color:#000!important} +.w3-grey,.w3-hover-grey:hover{color:#000!important;background-color:#9e9e9e!important} +.w3-light-grey,.w3-hover-light-grey:hover{color:#000!important;background-color:#f1f1f1!important} +.w3-dark-grey,.w3-hover-dark-grey:hover{color:#fff!important;background-color:#616161!important} +.w3-pale-red,.w3-hover-pale-red:hover{color:#000!important;background-color:#ffe7e7!important}.w3-pale-green,.w3-hover-pale-green:hover{color:#000!important;background-color:#e7ffe7!important} +.w3-pale-yellow,.w3-hover-pale-yellow:hover{color:#000!important;background-color:#ffffd7!important}.w3-pale-blue,.w3-hover-pale-blue:hover{color:#000!important;background-color:#e7ffff!important} +.w3-text-align-right { text-align: right;} +.w3-text-amber,.w3-hover-text-amber:hover{color:#ffc107!important} +.w3-text-aqua,.w3-hover-text-aqua:hover{color:#00ffff!important} +.w3-text-blue,.w3-hover-text-blue:hover{color:#2196F3!important} +.w3-text-light-blue,.w3-hover-text-light-blue:hover{color:#87CEEB!important} +.w3-text-brown,.w3-hover-text-brown:hover{color:#795548!important} +.w3-text-cyan,.w3-hover-text-cyan:hover{color:#00bcd4!important} +.w3-text-blue-grey,.w3-hover-text-blue-grey:hover{color:#607d8b!important} +.w3-text-green,.w3-hover-text-green:hover{color:#4CAF50!important} +.w3-text-light-green,.w3-hover-text-light-green:hover{color:#8bc34a!important} +.w3-text-indigo,.w3-hover-text-indigo:hover{color:#3f51b5!important} +.w3-text-khaki,.w3-hover-text-khaki:hover{color:#b4aa50!important} +.w3-text-lime,.w3-hover-text-lime:hover{color:#cddc39!important} +.w3-text-orange,.w3-hover-text-orange:hover{color:#ff9800!important} +.w3-text-deep-orange,.w3-hover-text-deep-orange:hover{color:#ff5722!important} +.w3-text-pink,.w3-hover-text-pink:hover{color:#e91e63!important} +.w3-text-purple,.w3-hover-text-purple:hover{color:#9c27b0!important} +.w3-text-deep-purple,.w3-hover-text-deep-purple:hover{color:#673ab7!important} +.w3-text-red,.w3-hover-text-red:hover{color:#f44336!important} +.w3-text-sand,.w3-hover-text-sand:hover{color:#fdf5e6!important} +.w3-text-teal,.w3-hover-text-teal:hover{color:#009688!important} +.w3-text-yellow,.w3-hover-text-yellow:hover{color:#d2be0e!important} +.w3-text-white,.w3-hover-text-white:hover{color:#fff!important} +.w3-text-black,.w3-hover-text-black:hover{color:#000!important} +.w3-text-grey,.w3-hover-text-grey:hover{color:#757575!important} +.w3-text-light-grey,.w3-hover-text-light-grey:hover{color:#f1f1f1!important} +.w3-text-dark-grey,.w3-hover-text-dark-grey:hover{color:#3a3a3a!important} +.w3-border-amber,.w3-hover-border-amber:hover{border-color:#ffc107!important} +.w3-border-aqua,.w3-hover-border-aqua:hover{border-color:#00ffff!important} +.w3-border-blue,.w3-hover-border-blue:hover{border-color:#2196F3!important} +.w3-border-light-blue,.w3-hover-border-light-blue:hover{border-color:#87CEEB!important} +.w3-border-brown,.w3-hover-border-brown:hover{border-color:#795548!important} +.w3-border-cyan,.w3-hover-border-cyan:hover{border-color:#00bcd4!important} +.w3-border-blue-grey,.w3-hover-blue-grey:hover{border-color:#607d8b!important} +.w3-border-green,.w3-hover-border-green:hover{border-color:#4CAF50!important} +.w3-border-light-green,.w3-hover-border-light-green:hover{border-color:#8bc34a!important} +.w3-border-indigo,.w3-hover-border-indigo:hover{border-color:#3f51b5!important} +.w3-border-khaki,.w3-hover-border-khaki:hover{border-color:#f0e68c!important} +.w3-border-lime,.w3-hover-border-lime:hover{border-color:#cddc39!important} +.w3-border-orange,.w3-hover-border-orange:hover{border-color:#ff9800!important} +.w3-border-deep-orange,.w3-hover-border-deep-orange:hover{border-color:#ff5722!important} +.w3-border-pink,.w3-hover-border-pink:hover{border-color:#e91e63!important} +.w3-border-purple,.w3-hover-border-purple:hover{border-color:#9c27b0!important} +.w3-border-deep-purple,.w3-hover-border-deep-purple:hover{border-color:#673ab7!important} +.w3-border-red,.w3-hover-border-red:hover{border-color:#f44336!important} +.w3-border-sand,.w3-hover-border-sand:hover{border-color:#fdf5e6!important} +.w3-border-teal,.w3-hover-border-teal:hover{border-color:#009688!important} +.w3-border-yellow,.w3-hover-border-yellow:hover{border-color:#ffeb3b!important} +.w3-border-white,.w3-hover-border-white:hover{border-color:#fff!important} +.w3-border-black,.w3-hover-border-black:hover{border-color:#000!important} +.w3-border-grey,.w3-hover-border-grey:hover{border-color:#9e9e9e!important} +.w3-border-light-grey,.w3-hover-border-light-grey:hover{border-color:#f1f1f1!important} +.w3-border-dark-grey,.w3-hover-border-dark-grey:hover{border-color:#616161!important} +.w3-border-pale-red,.w3-hover-border-pale-red:hover{border-color:#ffe7e7!important}.w3-border-pale-green,.w3-hover-border-pale-green:hover{border-color:#e7ffe7!important} +.w3-border-pale-yellow,.w3-hover-border-pale-yellow:hover{border-color:#ffffd7!important}.w3-border-pale-blue,.w3-hover-border-pale-blue:hover{border-color:#e7ffff!important} +/* DEFAULT THEME */ +.w3-theme-l5 {color:#000 !important; background-color:#f6f8fc !important} +.w3-theme-l4 {color:#000 !important; background-color:#e1e9f6 !important} +.w3-theme-l3 {color:#000 !important; background-color:#c3d3ed !important} +.w3-theme-l2 {color:#000 !important; background-color:#a5bee4 !important} +.w3-theme-l1 {color:#fff !important; background-color:#88a8db !important} +.w3-theme-d1 {color:#fff !important; background-color:#5180cb !important} +.w3-theme-d2 {color:#fff !important; background-color:#3a6fc3 !important} +.w3-theme-d3 {color:#fff !important; background-color:#3361aa !important} +.w3-theme-d4 {color:#fff !important; background-color:#2c5392 !important} +.w3-theme-d5 {color:#fff !important; background-color:#24457a !important} + +.w3-theme-light {color:#000 !important; background-color:#f6f8fc !important} +.w3-theme-dark {color:#fff !important; background-color:#24457a !important} +.w3-theme-action {color:#fff !important; background-color:#24457a !important} + +.w3-theme {color:#fff !important; background-color:#6a92d3 !important} +.w3-text-theme {color:#6a92d3 !important} +.w3-border-theme {border-color:#6a92d3 !important} + +.w3-hover-theme:hover {color:#fff !important; background-color:#6a92d3 !important} +.w3-hover-text-theme:hover {color:#6a92d3 !important} +.w3-hover-border-theme:hover {border-color:#6a92d3 !important} + +.w3-label { color: rgb(153, 150, 150);} +/* #main {margin-left: 210px;} */ +@media (max-width:768px){ + #sidebar { display: none;} + #main { margin-left: 0px;} +} + +.w3-select { + display: block; + font-size: 16px; + font-family: sans-serif; + font-weight: normal; + color: #444; + line-height: 1.3; + padding: .6em 1.4em .5em .8em; + width: 100%; + max-width: 100%; + box-sizing: border-box; + margin: 0; + border-bottom: 1px solid #aaa; + box-shadow: 0 1px 0 1px rgba(0,0,0,.04); + /* border-radius: .5em; */ + -moz-appearance: none; + -webkit-appearance: none; + appearance: none; + background-color: #e8f0fe; + background-image: url('data:image/svg+xml;charset=US-ASCII,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22292.4%22%20height%3D%22292.4%22%3E%3Cpath%20fill%3D%22%23000%22%20d%3D%22M287%2069.4a17.6%2017.6%200%200%200-13-5.4H18.4c-5%200-9.3%201.8-12.9%205.4A17.6%2017.6%200%200%200%200%2082.2c0%205%201.8%209.3%205.4%2012.9l128%20127.9c3.6%203.6%207.8%205.4%2012.8%205.4s9.2-1.8%2012.8-5.4L287%2095c3.5-3.5%205.4-7.8%205.4-12.8%200-5-1.9-9.2-5.5-12.8z%22%2F%3E%3C%2Fsvg%3E'), + linear-gradient(to bottom, #e8f0fe 0%,#e8f0fe 100%); + background-repeat: no-repeat, repeat; + background-position: right .7em top 50%, 0 0; + background-size: .65em auto, 100%; +} +.w3-select::-ms-expand { + display: none; +} +.w3-select:hover { + border-color: #888; +} +.w3-select:focus { + border-color: #aaa; + box-shadow: 0 0 1px 1px #6a92d3; + box-shadow: 0 0 0 1px -moz-mac-focusring; + color: #222; + outline: none; +} + + +.w3-select option { + font-weight:normal; +} + +.w3-table { + table-layout: fixed; +} + +.w3-text-line-through { text-decoration: line-through; } + +#snackbar { + visibility: hidden; + min-width: 250px; + margin-left: -125px; + background-color: #333; + color: #fff; + text-align: center; + border-radius: 2px; + padding: 16px; + position: fixed; + z-index: 1; + left: 50%; + bottom: 30px; + font-size: 17px; +} + +#snackbar.show { + visibility: visible; + -webkit-animation: fadein 0.5s, fadeout 0.5s 2.5s; + animation: fadein 0.5s, fadeout 0.5s 2.5s; +} + +@-webkit-keyframes fadein { + from {bottom: 0; opacity: 0;} + to {bottom: 30px; opacity: 1;} +} + +@keyframes fadein { + from {bottom: 0; opacity: 0;} + to {bottom: 30px; opacity: 1;} +} + +@-webkit-keyframes fadeout { + from {bottom: 30px; opacity: 1;} + to {bottom: 0; opacity: 0;} +} + +@keyframes fadeout { + from {bottom: 30px; opacity: 1;} + to {bottom: 0; opacity: 0;} +} + +.tabulator-header-filter > input { + background-color: #e8f0fe; + border: 1px solid #ccc; + font-weight: normal; +} + +.w3-readonly { + pointer-events:none; + padding:8px;display:block;border:0px;width:100%;background-color: #fff; +} + +.right-side-bg { + background: url("../img/bg1.jpg"); + background-size: cover; + min-height: 100vh; +} + +/* .mceContentBody { + background: #e8f0fe; + color:#000; +} */ + +/* .tabulator-row-even { + background-color: #757575; +} */ \ No newline at end of file diff --git a/backoffice/data/.htaccess b/backoffice/data/.htaccess new file mode 100644 index 0000000..b4b826d --- /dev/null +++ b/backoffice/data/.htaccess @@ -0,0 +1,5 @@ +RewriteEngine On +RewriteBase / +RewriteCond %{HTTP_COOKIE} !potlu= [NC] +RewriteRule .* "%{REQUEST_SCHEME}://%{HTTP_HOST}/backoffice/login.html" [L] +# Require all denied \ No newline at end of file diff --git a/backoffice/data/company/.htaccess b/backoffice/data/company/.htaccess new file mode 100644 index 0000000..b4b826d --- /dev/null +++ b/backoffice/data/company/.htaccess @@ -0,0 +1,5 @@ +RewriteEngine On +RewriteBase / +RewriteCond %{HTTP_COOKIE} !potlu= [NC] +RewriteRule .* "%{REQUEST_SCHEME}://%{HTTP_HOST}/backoffice/login.html" [L] +# Require all denied \ No newline at end of file diff --git a/backoffice/data/schemata/.htaccess b/backoffice/data/schemata/.htaccess new file mode 100644 index 0000000..b4b826d --- /dev/null +++ b/backoffice/data/schemata/.htaccess @@ -0,0 +1,5 @@ +RewriteEngine On +RewriteBase / +RewriteCond %{HTTP_COOKIE} !potlu= [NC] +RewriteRule .* "%{REQUEST_SCHEME}://%{HTTP_HOST}/backoffice/login.html" [L] +# Require all denied \ No newline at end of file diff --git a/backoffice/data/schemata/defaultcompany.schema.sql b/backoffice/data/schemata/defaultcompany.schema.sql new file mode 100644 index 0000000..f7db8e9 --- /dev/null +++ b/backoffice/data/schemata/defaultcompany.schema.sql @@ -0,0 +1,1193 @@ + +CREATE SCHEMA %%NEWSCHEMA%%; + +CREATE TABLE %%NEWSCHEMA%%.defaultweekworkplan ( + id integer NOT NULL, + id_staff integer, + startdate date, + mon json, + tue json, + wed json, + thu json, + fri json, + sat json, + sun json +); + +CREATE SEQUENCE %%NEWSCHEMA%%.defaultweekworkplan_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + +ALTER SEQUENCE %%NEWSCHEMA%%.defaultweekworkplan_id_seq OWNED BY %%NEWSCHEMA%%.defaultweekworkplan.id; + +CREATE TABLE %%NEWSCHEMA%%.defaultworkplan ( + id bigint NOT NULL, + id_staff integer, + daydate date, + plannedtimes json, + vacancytimes json, + presencetimes json +); + +CREATE SEQUENCE %%NEWSCHEMA%%.defaultworkplan_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + +ALTER SEQUENCE %%NEWSCHEMA%%.defaultworkplan_id_seq OWNED BY %%NEWSCHEMA%%.defaultworkplan.id; + +CREATE TABLE %%NEWSCHEMA%%.reportperiod ( + id integer NOT NULL, + periodname text, + startdate date, + enddate date +); + +CREATE SEQUENCE %%NEWSCHEMA%%.reportperiod_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + +ALTER SEQUENCE %%NEWSCHEMA%%.reportperiod_id_seq OWNED BY %%NEWSCHEMA%%.reportperiod.id; + +CREATE TABLE %%NEWSCHEMA%%.sites ( + id integer NOT NULL, + sitename text, + address text, + zip text, + city text, + country text, + id_timetracker integer, + created timestamp without time zone DEFAULT now(), + modified timestamp without time zone DEFAULT now(), + timeclockhost text +); + +CREATE SEQUENCE %%NEWSCHEMA%%.sites_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + +ALTER SEQUENCE %%NEWSCHEMA%%.sites_id_seq OWNED BY %%NEWSCHEMA%%.sites.id; + +CREATE TABLE %%NEWSCHEMA%%.staff ( + id integer NOT NULL, + staffnumber text, + surname text, + prename text, + job text, + birthdate date, + entrydate date, + leavedate date +); + +CREATE SEQUENCE %%NEWSCHEMA%%.staff_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + +ALTER SEQUENCE %%NEWSCHEMA%%.staff_id_seq OWNED BY %%NEWSCHEMA%%.staff.id; + +CREATE TABLE %%NEWSCHEMA%%.staffgroups ( + id integer NOT NULL, + groupname text, + groupcolor text +); + +CREATE SEQUENCE %%NEWSCHEMA%%.staffgroups_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + +ALTER SEQUENCE %%NEWSCHEMA%%.staffgroups_id_seq OWNED BY %%NEWSCHEMA%%.staffgroups.id; + +CREATE TABLE %%NEWSCHEMA%%.staffperiodbase ( + id integer NOT NULL, + id_staff integer, + startdate date, + monthhours numeric, + weekhours numeric +); + +CREATE SEQUENCE %%NEWSCHEMA%%.staffperiodbase_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + +ALTER SEQUENCE %%NEWSCHEMA%%.staffperiodbase_id_seq OWNED BY %%NEWSCHEMA%%.staffperiodbase.id; + +CREATE TABLE %%NEWSCHEMA%%.stafftimetracks ( + id bigint NOT NULL, + id_staff integer, + stamp_in timestamp without time zone, + stamp_out timestamp without time zone, + tracktype text, + created timestamp without time zone DEFAULT now(), + modified timestamp without time zone DEFAULT now() +); + +CREATE SEQUENCE %%NEWSCHEMA%%.stafftimetracks_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + +ALTER SEQUENCE %%NEWSCHEMA%%.stafftimetracks_id_seq OWNED BY %%NEWSCHEMA%%.stafftimetracks.id; + +CREATE TABLE %%NEWSCHEMA%%.staffvacancy ( + id integer NOT NULL, + id_staff integer, + startdate date, + enddate date, + vacancytype text, + dayhours time without time zone, + note text, + validated boolean +); + +CREATE SEQUENCE %%NEWSCHEMA%%.staffvacancy_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + +ALTER SEQUENCE %%NEWSCHEMA%%.staffvacancy_id_seq OWNED BY %%NEWSCHEMA%%.staffvacancy.id; + +CREATE TABLE %%NEWSCHEMA%%.staffvacancyyear ( + id integer NOT NULL, + id_staff integer, + vyear integer, + hours numeric, + days numeric +); + +CREATE SEQUENCE %%NEWSCHEMA%%.staffvacancyyear_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + +ALTER SEQUENCE %%NEWSCHEMA%%.staffvacancyyear_id_seq OWNED BY %%NEWSCHEMA%%.staffvacancyyear.id; + +CREATE TABLE %%NEWSCHEMA%%.staffworkplan ( + id bigint NOT NULL, + id_staff integer, + daydate date, + timestart1 time without time zone, + timeend1 time without time zone, + timestart2 time without time zone, + timeend2 time without time zone, + timepause time without time zone, + vacancyhours time without time zone, + vacancytype text +); + +CREATE SEQUENCE %%NEWSCHEMA%%.staffworkplan_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + +ALTER SEQUENCE %%NEWSCHEMA%%.staffworkplan_id_seq OWNED BY %%NEWSCHEMA%%.staffworkplan.id; + +CREATE VIEW %%NEWSCHEMA%%.vw_reportperiodlist AS + SELECT reportperiod.id, + reportperiod.periodname, + reportperiod.startdate, + reportperiod.enddate + FROM %%NEWSCHEMA%%.reportperiod; + +CREATE VIEW %%NEWSCHEMA%%.vw_stafflist AS + SELECT staff.id, + staff.staffnumber, + staff.surname, + staff.prename, + staff.job, + staff.birthdate, + staff.entrydate, + staff.leavedate, + ((staff.surname || ' '::text) || staff.prename) AS dspname + FROM %%NEWSCHEMA%%.staff; + +CREATE VIEW %%NEWSCHEMA%%.vw_staffplanned_dayweektotals AS + SELECT stw2.calweek, + stw2.caldate AS dates, + stw2.id_staff, + max( + CASE + WHEN (stw2.isodow = (1)::double precision) THEN stw2.id + ELSE NULL::bigint + END) AS mon_id, + max( + CASE + WHEN (stw2.isodow = (1)::double precision) THEN to_char((stw2.timestart1)::interval, 'HH24:MI'::text) + ELSE NULL::text + END) AS mon_start1, + max( + CASE + WHEN (stw2.isodow = (1)::double precision) THEN to_char((stw2.timeend1)::interval, 'HH24:MI'::text) + ELSE NULL::text + END) AS mon_end1, + max( + CASE + WHEN (stw2.isodow = (1)::double precision) THEN to_char((stw2.timestart2)::interval, 'HH24:MI'::text) + ELSE NULL::text + END) AS mon_start2, + max( + CASE + WHEN (stw2.isodow = (1)::double precision) THEN to_char((stw2.timeend2)::interval, 'HH24:MI'::text) + ELSE NULL::text + END) AS mon_end2, + max( + CASE + WHEN (stw2.isodow = (1)::double precision) THEN to_char((stw2.timepause)::interval, 'HH24:MI'::text) + ELSE NULL::text + END) AS mon_pause, + to_char(max( + CASE + WHEN (stw2.isodow = (1)::double precision) THEN ((stw2.time1 + stw2.time2) - (stw2.timepause)::interval) + ELSE NULL::interval + END), 'HH24:MI'::text) AS mon_timetotal, + max( + CASE + WHEN (stw2.isodow = (2)::double precision) THEN stw2.id + ELSE NULL::bigint + END) AS tue_id, + max( + CASE + WHEN (stw2.isodow = (2)::double precision) THEN to_char((stw2.timestart1)::interval, 'HH24:MI'::text) + ELSE NULL::text + END) AS tue_start1, + max( + CASE + WHEN (stw2.isodow = (2)::double precision) THEN to_char((stw2.timeend1)::interval, 'HH24:MI'::text) + ELSE NULL::text + END) AS tue_end1, + max( + CASE + WHEN (stw2.isodow = (2)::double precision) THEN to_char((stw2.timestart2)::interval, 'HH24:MI'::text) + ELSE NULL::text + END) AS tue_start2, + max( + CASE + WHEN (stw2.isodow = (2)::double precision) THEN to_char((stw2.timeend2)::interval, 'HH24:MI'::text) + ELSE NULL::text + END) AS tue_end2, + max( + CASE + WHEN (stw2.isodow = (2)::double precision) THEN to_char((stw2.timepause)::interval, 'HH24:MI'::text) + ELSE NULL::text + END) AS tue_pause, + to_char(max( + CASE + WHEN (stw2.isodow = (2)::double precision) THEN ((stw2.time1 + stw2.time2) - (stw2.timepause)::interval) + ELSE NULL::interval + END), 'HH24:MI'::text) AS tue_timetotal, + max( + CASE + WHEN (stw2.isodow = (3)::double precision) THEN stw2.id + ELSE NULL::bigint + END) AS wed_id, + max( + CASE + WHEN (stw2.isodow = (3)::double precision) THEN to_char((stw2.timestart1)::interval, 'HH24:MI'::text) + ELSE NULL::text + END) AS wed_start1, + max( + CASE + WHEN (stw2.isodow = (3)::double precision) THEN to_char((stw2.timeend1)::interval, 'HH24:MI'::text) + ELSE NULL::text + END) AS wed_end1, + max( + CASE + WHEN (stw2.isodow = (3)::double precision) THEN to_char((stw2.timestart2)::interval, 'HH24:MI'::text) + ELSE NULL::text + END) AS wed_start2, + max( + CASE + WHEN (stw2.isodow = (3)::double precision) THEN to_char((stw2.timeend2)::interval, 'HH24:MI'::text) + ELSE NULL::text + END) AS wed_end2, + max( + CASE + WHEN (stw2.isodow = (3)::double precision) THEN to_char((stw2.timepause)::interval, 'HH24:MI'::text) + ELSE NULL::text + END) AS wed_pause, + to_char(max( + CASE + WHEN (stw2.isodow = (3)::double precision) THEN ((stw2.time1 + stw2.time2) - (stw2.timepause)::interval) + ELSE NULL::interval + END), 'HH24:MI'::text) AS wed_timetotal, + max( + CASE + WHEN (stw2.isodow = (4)::double precision) THEN stw2.id + ELSE NULL::bigint + END) AS thu_id, + max( + CASE + WHEN (stw2.isodow = (4)::double precision) THEN to_char((stw2.timestart1)::interval, 'HH24:MI'::text) + ELSE NULL::text + END) AS thu_start1, + max( + CASE + WHEN (stw2.isodow = (4)::double precision) THEN to_char((stw2.timeend1)::interval, 'HH24:MI'::text) + ELSE NULL::text + END) AS thu_end1, + max( + CASE + WHEN (stw2.isodow = (4)::double precision) THEN to_char((stw2.timestart2)::interval, 'HH24:MI'::text) + ELSE NULL::text + END) AS thu_start2, + max( + CASE + WHEN (stw2.isodow = (4)::double precision) THEN to_char((stw2.timeend2)::interval, 'HH24:MI'::text) + ELSE NULL::text + END) AS thu_end2, + max( + CASE + WHEN (stw2.isodow = (4)::double precision) THEN to_char((stw2.timepause)::interval, 'HH24:MI'::text) + ELSE NULL::text + END) AS thu_pause, + to_char(max( + CASE + WHEN (stw2.isodow = (4)::double precision) THEN ((stw2.time1 + stw2.time2) - (stw2.timepause)::interval) + ELSE NULL::interval + END), 'HH24:MI'::text) AS thu_timetotal, + max( + CASE + WHEN (stw2.isodow = (5)::double precision) THEN stw2.id + ELSE NULL::bigint + END) AS fri_id, + max( + CASE + WHEN (stw2.isodow = (5)::double precision) THEN to_char((stw2.timestart1)::interval, 'HH24:MI'::text) + ELSE NULL::text + END) AS fri_start1, + max( + CASE + WHEN (stw2.isodow = (5)::double precision) THEN to_char((stw2.timeend1)::interval, 'HH24:MI'::text) + ELSE NULL::text + END) AS fri_end1, + max( + CASE + WHEN (stw2.isodow = (5)::double precision) THEN to_char((stw2.timestart2)::interval, 'HH24:MI'::text) + ELSE NULL::text + END) AS fri_start2, + max( + CASE + WHEN (stw2.isodow = (5)::double precision) THEN to_char((stw2.timeend2)::interval, 'HH24:MI'::text) + ELSE NULL::text + END) AS fri_end2, + max( + CASE + WHEN (stw2.isodow = (5)::double precision) THEN to_char((stw2.timepause)::interval, 'HH24:MI'::text) + ELSE NULL::text + END) AS fri_pause, + to_char(max( + CASE + WHEN (stw2.isodow = (5)::double precision) THEN ((stw2.time1 + stw2.time2) - (stw2.timepause)::interval) + ELSE NULL::interval + END), 'HH24:MI'::text) AS fri_timetotal, + max( + CASE + WHEN (stw2.isodow = (6)::double precision) THEN stw2.id + ELSE NULL::bigint + END) AS sat_id, + max( + CASE + WHEN (stw2.isodow = (6)::double precision) THEN to_char((stw2.timestart1)::interval, 'HH24:MI'::text) + ELSE NULL::text + END) AS sat_start1, + max( + CASE + WHEN (stw2.isodow = (6)::double precision) THEN to_char((stw2.timeend1)::interval, 'HH24:MI'::text) + ELSE NULL::text + END) AS sat_end1, + max( + CASE + WHEN (stw2.isodow = (6)::double precision) THEN to_char((stw2.timestart2)::interval, 'HH24:MI'::text) + ELSE NULL::text + END) AS sat_start2, + max( + CASE + WHEN (stw2.isodow = (6)::double precision) THEN to_char((stw2.timeend2)::interval, 'HH24:MI'::text) + ELSE NULL::text + END) AS sat_end2, + max( + CASE + WHEN (stw2.isodow = (6)::double precision) THEN to_char((stw2.timepause)::interval, 'HH24:MI'::text) + ELSE NULL::text + END) AS sat_pause, + to_char(max( + CASE + WHEN (stw2.isodow = (6)::double precision) THEN ((stw2.time1 + stw2.time2) - (stw2.timepause)::interval) + ELSE NULL::interval + END), 'HH24:MI'::text) AS sat_timetotal, + max( + CASE + WHEN (stw2.isodow = (7)::double precision) THEN stw2.id + ELSE NULL::bigint + END) AS sun_id, + max( + CASE + WHEN (stw2.isodow = (7)::double precision) THEN to_char((stw2.timestart1)::interval, 'HH24:MI'::text) + ELSE NULL::text + END) AS sun_start1, + max( + CASE + WHEN (stw2.isodow = (7)::double precision) THEN to_char((stw2.timeend1)::interval, 'HH24:MI'::text) + ELSE NULL::text + END) AS sun_end1, + max( + CASE + WHEN (stw2.isodow = (7)::double precision) THEN to_char((stw2.timestart2)::interval, 'HH24:MI'::text) + ELSE NULL::text + END) AS sun_start2, + max( + CASE + WHEN (stw2.isodow = (7)::double precision) THEN to_char((stw2.timeend2)::interval, 'HH24:MI'::text) + ELSE NULL::text + END) AS sun_end2, + max( + CASE + WHEN (stw2.isodow = (7)::double precision) THEN to_char((stw2.timepause)::interval, 'HH24:MI'::text) + ELSE NULL::text + END) AS sun_pause, + to_char(max( + CASE + WHEN (stw2.isodow = (7)::double precision) THEN ((stw2.time1 + stw2.time2) - (stw2.timepause)::interval) + ELSE NULL::interval + END), 'HH24:MI'::text) AS sun_timetotal, + to_char(sum(((stw2.time1 + stw2.time2) - (stw2.timepause)::interval)), 'HH24:MI'::text) AS week_timetotal + FROM ( SELECT staffworkplan.daydate, + date_part('week'::text, staffworkplan.daydate) AS calweek, + (date_trunc('week'::text, (staffworkplan.daydate)::timestamp with time zone))::date AS caldate, + date_part('isodow'::text, staffworkplan.daydate) AS isodow, + staffworkplan.id, + staffworkplan.id_staff, + staffworkplan.timestart1, + staffworkplan.timeend1, + CASE + WHEN (staffworkplan.timestart1 > staffworkplan.timeend1) THEN ('24:00:00'::time without time zone - ((staffworkplan.timestart1 - staffworkplan.timeend1))::time without time zone) + ELSE (staffworkplan.timeend1 - staffworkplan.timestart1) + END AS time1, + staffworkplan.timestart2, + staffworkplan.timeend2, + CASE + WHEN (staffworkplan.timestart2 > staffworkplan.timeend2) THEN ('24:00:00'::time without time zone - ((staffworkplan.timestart2 - staffworkplan.timeend2))::time without time zone) + ELSE (staffworkplan.timeend2 - staffworkplan.timestart2) + END AS time2, + staffworkplan.timepause + FROM %%NEWSCHEMA%%.staffworkplan) stw2 + GROUP BY stw2.calweek, stw2.caldate, stw2.id_staff; + +CREATE VIEW %%NEWSCHEMA%%.vw_staffworkplan_weekly AS + SELECT stw2.calweek, + to_char((stw2.caldate)::timestamp with time zone, 'YYYY'::text) AS calyear, + stw2.caldate AS weekbegin, + public.getdateslist(stw2.caldate, 7) AS dates, + stw2.id_staff, + max( + CASE + WHEN (stw2.isodow = (1)::double precision) THEN stw2.id + ELSE NULL::bigint + END) AS mon_id, + max( + CASE + WHEN (stw2.isodow = (1)::double precision) THEN to_char((stw2.timestart1)::interval, 'HH24:MI'::text) + ELSE NULL::text + END) AS mon_start1, + max( + CASE + WHEN (stw2.isodow = (1)::double precision) THEN to_char((stw2.timeend1)::interval, 'HH24:MI'::text) + ELSE NULL::text + END) AS mon_end1, + max( + CASE + WHEN (stw2.isodow = (1)::double precision) THEN to_char((stw2.timestart2)::interval, 'HH24:MI'::text) + ELSE NULL::text + END) AS mon_start2, + max( + CASE + WHEN (stw2.isodow = (1)::double precision) THEN to_char((stw2.timeend2)::interval, 'HH24:MI'::text) + ELSE NULL::text + END) AS mon_end2, + max( + CASE + WHEN (stw2.isodow = (1)::double precision) THEN to_char((stw2.timepause)::interval, 'HH24:MI'::text) + ELSE NULL::text + END) AS mon_pause, + max( + CASE + WHEN (stw2.isodow = (1)::double precision) THEN to_char((stw2.vacancyhours)::interval, 'HH24:MI'::text) + ELSE NULL::text + END) AS mon_vacancyhours, + max( + CASE + WHEN (stw2.isodow = (1)::double precision) THEN stw2.vacancytype + ELSE NULL::text + END) AS mon_vacancytype, + to_char(max( + CASE + WHEN (stw2.isodow = (1)::double precision) THEN ((stw2.time1 + stw2.time2) - (stw2.timepause)::interval) + ELSE NULL::interval + END), 'HH24:MI'::text) AS mon_timetotal, + max( + CASE + WHEN (stw2.isodow = (2)::double precision) THEN stw2.id + ELSE NULL::bigint + END) AS tue_id, + max( + CASE + WHEN (stw2.isodow = (2)::double precision) THEN to_char((stw2.timestart1)::interval, 'HH24:MI'::text) + ELSE NULL::text + END) AS tue_start1, + max( + CASE + WHEN (stw2.isodow = (2)::double precision) THEN to_char((stw2.timeend1)::interval, 'HH24:MI'::text) + ELSE NULL::text + END) AS tue_end1, + max( + CASE + WHEN (stw2.isodow = (2)::double precision) THEN to_char((stw2.timestart2)::interval, 'HH24:MI'::text) + ELSE NULL::text + END) AS tue_start2, + max( + CASE + WHEN (stw2.isodow = (2)::double precision) THEN to_char((stw2.timeend2)::interval, 'HH24:MI'::text) + ELSE NULL::text + END) AS tue_end2, + max( + CASE + WHEN (stw2.isodow = (2)::double precision) THEN to_char((stw2.timepause)::interval, 'HH24:MI'::text) + ELSE NULL::text + END) AS tue_pause, + max( + CASE + WHEN (stw2.isodow = (2)::double precision) THEN to_char((stw2.vacancyhours)::interval, 'HH24:MI'::text) + ELSE NULL::text + END) AS tue_vacancyhours, + max( + CASE + WHEN (stw2.isodow = (2)::double precision) THEN stw2.vacancytype + ELSE NULL::text + END) AS tue_vacancytype, + to_char(max( + CASE + WHEN (stw2.isodow = (2)::double precision) THEN ((stw2.time1 + stw2.time2) - (stw2.timepause)::interval) + ELSE NULL::interval + END), 'HH24:MI'::text) AS tue_timetotal, + max( + CASE + WHEN (stw2.isodow = (3)::double precision) THEN stw2.id + ELSE NULL::bigint + END) AS wed_id, + max( + CASE + WHEN (stw2.isodow = (3)::double precision) THEN to_char((stw2.timestart1)::interval, 'HH24:MI'::text) + ELSE NULL::text + END) AS wed_start1, + max( + CASE + WHEN (stw2.isodow = (3)::double precision) THEN to_char((stw2.timeend1)::interval, 'HH24:MI'::text) + ELSE NULL::text + END) AS wed_end1, + max( + CASE + WHEN (stw2.isodow = (3)::double precision) THEN to_char((stw2.timestart2)::interval, 'HH24:MI'::text) + ELSE NULL::text + END) AS wed_start2, + max( + CASE + WHEN (stw2.isodow = (3)::double precision) THEN to_char((stw2.timeend2)::interval, 'HH24:MI'::text) + ELSE NULL::text + END) AS wed_end2, + max( + CASE + WHEN (stw2.isodow = (3)::double precision) THEN to_char((stw2.timepause)::interval, 'HH24:MI'::text) + ELSE NULL::text + END) AS wed_pause, + max( + CASE + WHEN (stw2.isodow = (3)::double precision) THEN to_char((stw2.vacancyhours)::interval, 'HH24:MI'::text) + ELSE NULL::text + END) AS wed_vacancyhours, + max( + CASE + WHEN (stw2.isodow = (3)::double precision) THEN stw2.vacancytype + ELSE NULL::text + END) AS wed_vacancytype, + to_char(max( + CASE + WHEN (stw2.isodow = (3)::double precision) THEN ((stw2.time1 + stw2.time2) - (stw2.timepause)::interval) + ELSE NULL::interval + END), 'HH24:MI'::text) AS wed_timetotal, + max( + CASE + WHEN (stw2.isodow = (4)::double precision) THEN stw2.id + ELSE NULL::bigint + END) AS thu_id, + max( + CASE + WHEN (stw2.isodow = (4)::double precision) THEN to_char((stw2.timestart1)::interval, 'HH24:MI'::text) + ELSE NULL::text + END) AS thu_start1, + max( + CASE + WHEN (stw2.isodow = (4)::double precision) THEN to_char((stw2.timeend1)::interval, 'HH24:MI'::text) + ELSE NULL::text + END) AS thu_end1, + max( + CASE + WHEN (stw2.isodow = (4)::double precision) THEN to_char((stw2.timestart2)::interval, 'HH24:MI'::text) + ELSE NULL::text + END) AS thu_start2, + max( + CASE + WHEN (stw2.isodow = (4)::double precision) THEN to_char((stw2.timeend2)::interval, 'HH24:MI'::text) + ELSE NULL::text + END) AS thu_end2, + max( + CASE + WHEN (stw2.isodow = (4)::double precision) THEN to_char((stw2.timepause)::interval, 'HH24:MI'::text) + ELSE NULL::text + END) AS thu_pause, + max( + CASE + WHEN (stw2.isodow = (4)::double precision) THEN to_char((stw2.vacancyhours)::interval, 'HH24:MI'::text) + ELSE NULL::text + END) AS thu_vacancyhours, + max( + CASE + WHEN (stw2.isodow = (4)::double precision) THEN stw2.vacancytype + ELSE NULL::text + END) AS thu_vacancytype, + to_char(max( + CASE + WHEN (stw2.isodow = (4)::double precision) THEN ((stw2.time1 + stw2.time2) - (stw2.timepause)::interval) + ELSE NULL::interval + END), 'HH24:MI'::text) AS thu_timetotal, + max( + CASE + WHEN (stw2.isodow = (5)::double precision) THEN stw2.id + ELSE NULL::bigint + END) AS fri_id, + max( + CASE + WHEN (stw2.isodow = (5)::double precision) THEN to_char((stw2.timestart1)::interval, 'HH24:MI'::text) + ELSE NULL::text + END) AS fri_start1, + max( + CASE + WHEN (stw2.isodow = (5)::double precision) THEN to_char((stw2.timeend1)::interval, 'HH24:MI'::text) + ELSE NULL::text + END) AS fri_end1, + max( + CASE + WHEN (stw2.isodow = (5)::double precision) THEN to_char((stw2.timestart2)::interval, 'HH24:MI'::text) + ELSE NULL::text + END) AS fri_start2, + max( + CASE + WHEN (stw2.isodow = (5)::double precision) THEN to_char((stw2.timeend2)::interval, 'HH24:MI'::text) + ELSE NULL::text + END) AS fri_end2, + max( + CASE + WHEN (stw2.isodow = (5)::double precision) THEN to_char((stw2.timepause)::interval, 'HH24:MI'::text) + ELSE NULL::text + END) AS fri_pause, + max( + CASE + WHEN (stw2.isodow = (5)::double precision) THEN to_char((stw2.vacancyhours)::interval, 'HH24:MI'::text) + ELSE NULL::text + END) AS fri_vacancyhours, + max( + CASE + WHEN (stw2.isodow = (5)::double precision) THEN stw2.vacancytype + ELSE NULL::text + END) AS fri_vacancytype, + to_char(max( + CASE + WHEN (stw2.isodow = (5)::double precision) THEN ((stw2.time1 + stw2.time2) - (stw2.timepause)::interval) + ELSE NULL::interval + END), 'HH24:MI'::text) AS fri_timetotal, + max( + CASE + WHEN (stw2.isodow = (6)::double precision) THEN stw2.id + ELSE NULL::bigint + END) AS sat_id, + max( + CASE + WHEN (stw2.isodow = (6)::double precision) THEN to_char((stw2.timestart1)::interval, 'HH24:MI'::text) + ELSE NULL::text + END) AS sat_start1, + max( + CASE + WHEN (stw2.isodow = (6)::double precision) THEN to_char((stw2.timeend1)::interval, 'HH24:MI'::text) + ELSE NULL::text + END) AS sat_end1, + max( + CASE + WHEN (stw2.isodow = (6)::double precision) THEN to_char((stw2.timestart2)::interval, 'HH24:MI'::text) + ELSE NULL::text + END) AS sat_start2, + max( + CASE + WHEN (stw2.isodow = (6)::double precision) THEN to_char((stw2.timeend2)::interval, 'HH24:MI'::text) + ELSE NULL::text + END) AS sat_end2, + max( + CASE + WHEN (stw2.isodow = (6)::double precision) THEN to_char((stw2.timepause)::interval, 'HH24:MI'::text) + ELSE NULL::text + END) AS sat_pause, + max( + CASE + WHEN (stw2.isodow = (6)::double precision) THEN to_char((stw2.vacancyhours)::interval, 'HH24:MI'::text) + ELSE NULL::text + END) AS sat_vacancyhours, + max( + CASE + WHEN (stw2.isodow = (6)::double precision) THEN stw2.vacancytype + ELSE NULL::text + END) AS sat_vacancytype, + to_char(max( + CASE + WHEN (stw2.isodow = (6)::double precision) THEN ((stw2.time1 + stw2.time2) - (stw2.timepause)::interval) + ELSE NULL::interval + END), 'HH24:MI'::text) AS sat_timetotal, + max( + CASE + WHEN (stw2.isodow = (7)::double precision) THEN stw2.id + ELSE NULL::bigint + END) AS sun_id, + max( + CASE + WHEN (stw2.isodow = (7)::double precision) THEN to_char((stw2.timestart1)::interval, 'HH24:MI'::text) + ELSE NULL::text + END) AS sun_start1, + max( + CASE + WHEN (stw2.isodow = (7)::double precision) THEN to_char((stw2.timeend1)::interval, 'HH24:MI'::text) + ELSE NULL::text + END) AS sun_end1, + max( + CASE + WHEN (stw2.isodow = (7)::double precision) THEN to_char((stw2.timestart2)::interval, 'HH24:MI'::text) + ELSE NULL::text + END) AS sun_start2, + max( + CASE + WHEN (stw2.isodow = (7)::double precision) THEN to_char((stw2.timeend2)::interval, 'HH24:MI'::text) + ELSE NULL::text + END) AS sun_end2, + max( + CASE + WHEN (stw2.isodow = (7)::double precision) THEN to_char((stw2.timepause)::interval, 'HH24:MI'::text) + ELSE NULL::text + END) AS sun_pause, + max( + CASE + WHEN (stw2.isodow = (7)::double precision) THEN to_char((stw2.vacancyhours)::interval, 'HH24:MI'::text) + ELSE NULL::text + END) AS sun_vacancyhours, + max( + CASE + WHEN (stw2.isodow = (7)::double precision) THEN stw2.vacancytype + ELSE NULL::text + END) AS sun_vacancytype, + to_char(max( + CASE + WHEN (stw2.isodow = (7)::double precision) THEN ((stw2.time1 + stw2.time2) - (stw2.timepause)::interval) + ELSE NULL::interval + END), 'HH24:MI'::text) AS sun_timetotal, + to_char(sum(((stw2.time1 + stw2.time2) - (stw2.timepause)::interval)), 'HH24:MI'::text) AS week_timetotal + FROM ( SELECT staffworkplan.daydate, + date_part('week'::text, staffworkplan.daydate) AS calweek, + (date_trunc('week'::text, (staffworkplan.daydate)::timestamp with time zone))::date AS caldate, + date_part('isodow'::text, staffworkplan.daydate) AS isodow, + staffworkplan.id, + staffworkplan.id_staff, + staffworkplan.timestart1, + staffworkplan.timeend1, + staffworkplan.vacancyhours, + staffworkplan.vacancytype, + CASE + WHEN (staffworkplan.timestart1 > staffworkplan.timeend1) THEN ('24:00:00'::time without time zone - ((staffworkplan.timestart1 - staffworkplan.timeend1))::time without time zone) + ELSE (staffworkplan.timeend1 - staffworkplan.timestart1) + END AS time1, + staffworkplan.timestart2, + staffworkplan.timeend2, + CASE + WHEN (staffworkplan.timestart2 > staffworkplan.timeend2) THEN ('24:00:00'::time without time zone - ((staffworkplan.timestart2 - staffworkplan.timeend2))::time without time zone) + ELSE (staffworkplan.timeend2 - staffworkplan.timestart2) + END AS time2, + staffworkplan.timepause + FROM %%NEWSCHEMA%%.staffworkplan) stw2 + GROUP BY stw2.calweek, stw2.caldate, stw2.id_staff; + +CREATE VIEW %%NEWSCHEMA%%.vw_staffworkplanlist AS + SELECT st.id AS id_staff, + ((st.surname || ' '::text) || st.prename) AS staffname, + (((((('Semaine '::text || sp_dwt.calweek) || '
('::text) || to_char((sp_dwt.weekbegin)::timestamp with time zone, 'DD.MM.YYYY'::text)) || ' - '::text) || to_char((date((sp_dwt.weekbegin + '7 days'::interval)))::timestamp with time zone, 'DD.MM.YYYY'::text)) || ')'::text) AS calweek, + sp_dwt.week_timetotal, + sp_dwt.weekbegin AS weekstart, + date((sp_dwt.weekbegin + '7 days'::interval)) AS weekend, + to_char((((((( + CASE + WHEN (sp_dwt.mon_vacancytype = 'ill'::text) THEN COALESCE((sp_dwt.mon_vacancyhours)::interval, '00:00:00'::interval) + ELSE '00:00:00'::interval + END + + CASE + WHEN (sp_dwt.tue_vacancytype = 'ill'::text) THEN COALESCE((sp_dwt.tue_vacancyhours)::interval, '00:00:00'::interval) + ELSE '00:00:00'::interval + END) + + CASE + WHEN (sp_dwt.wed_vacancytype = 'ill'::text) THEN COALESCE((sp_dwt.wed_vacancyhours)::interval, '00:00:00'::interval) + ELSE '00:00:00'::interval + END) + + CASE + WHEN (sp_dwt.thu_vacancytype = 'ill'::text) THEN COALESCE((sp_dwt.thu_vacancyhours)::interval, '00:00:00'::interval) + ELSE '00:00:00'::interval + END) + + CASE + WHEN (sp_dwt.fri_vacancytype = 'ill'::text) THEN COALESCE((sp_dwt.fri_vacancyhours)::interval, '00:00:00'::interval) + ELSE '00:00:00'::interval + END) + + CASE + WHEN (sp_dwt.sat_vacancytype = 'ill'::text) THEN COALESCE((sp_dwt.sat_vacancyhours)::interval, '00:00:00'::interval) + ELSE '00:00:00'::interval + END) + + CASE + WHEN (sp_dwt.sun_vacancytype = 'ill'::text) THEN COALESCE((sp_dwt.sun_vacancyhours)::interval, '00:00:00'::interval) + ELSE '00:00:00'::interval + END), 'HH24:MI'::text) AS weekvacancy_times_ill, + to_char((((((( + CASE + WHEN (sp_dwt.mon_vacancytype <> 'ill'::text) THEN COALESCE((sp_dwt.mon_vacancyhours)::interval, '00:00:00'::interval) + ELSE '00:00:00'::interval + END + + CASE + WHEN (sp_dwt.tue_vacancytype <> 'ill'::text) THEN COALESCE((sp_dwt.tue_vacancyhours)::interval, '00:00:00'::interval) + ELSE '00:00:00'::interval + END) + + CASE + WHEN (sp_dwt.wed_vacancytype <> 'ill'::text) THEN COALESCE((sp_dwt.wed_vacancyhours)::interval, '00:00:00'::interval) + ELSE '00:00:00'::interval + END) + + CASE + WHEN (sp_dwt.thu_vacancytype <> 'ill'::text) THEN COALESCE((sp_dwt.thu_vacancyhours)::interval, '00:00:00'::interval) + ELSE '00:00:00'::interval + END) + + CASE + WHEN (sp_dwt.fri_vacancytype <> 'ill'::text) THEN COALESCE((sp_dwt.fri_vacancyhours)::interval, '00:00:00'::interval) + ELSE '00:00:00'::interval + END) + + CASE + WHEN (sp_dwt.sat_vacancytype <> 'ill'::text) THEN COALESCE((sp_dwt.sat_vacancyhours)::interval, '00:00:00'::interval) + ELSE '00:00:00'::interval + END) + + CASE + WHEN (sp_dwt.sun_vacancytype <> 'ill'::text) THEN COALESCE((sp_dwt.sun_vacancyhours)::interval, '00:00:00'::interval) + ELSE '00:00:00'::interval + END), 'HH24:MI'::text) AS weekvacancy_times, + (((((( + CASE + WHEN (sp_dwt.mon_vacancytype = 'ill'::text) THEN COALESCE(((to_number("left"(sp_dwt.mon_vacancyhours, 2), '99'::text) * (60)::numeric) + to_number("right"(sp_dwt.mon_vacancyhours, 2), '99'::text)), (0)::numeric) + ELSE (0)::numeric + END + + CASE + WHEN (sp_dwt.tue_vacancytype = 'ill'::text) THEN COALESCE(((to_number("left"(sp_dwt.tue_vacancyhours, 2), '99'::text) * (60)::numeric) + to_number("right"(sp_dwt.tue_vacancyhours, 2), '99'::text)), (0)::numeric) + ELSE (0)::numeric + END) + + CASE + WHEN (sp_dwt.wed_vacancytype = 'ill'::text) THEN COALESCE(((to_number("left"(sp_dwt.wed_vacancyhours, 2), '99'::text) * (60)::numeric) + to_number("right"(sp_dwt.wed_vacancyhours, 2), '99'::text)), (0)::numeric) + ELSE (0)::numeric + END) + + CASE + WHEN (sp_dwt.thu_vacancytype = 'ill'::text) THEN COALESCE(((to_number("left"(sp_dwt.thu_vacancyhours, 2), '99'::text) * (60)::numeric) + to_number("right"(sp_dwt.thu_vacancyhours, 2), '99'::text)), (0)::numeric) + ELSE (0)::numeric + END) + + CASE + WHEN (sp_dwt.fri_vacancytype = 'ill'::text) THEN COALESCE(((to_number("left"(sp_dwt.fri_vacancyhours, 2), '99'::text) * (60)::numeric) + to_number("right"(sp_dwt.fri_vacancyhours, 2), '99'::text)), (0)::numeric) + ELSE (0)::numeric + END) + + CASE + WHEN (sp_dwt.sat_vacancytype = 'ill'::text) THEN COALESCE(((to_number("left"(sp_dwt.sat_vacancyhours, 2), '99'::text) * (60)::numeric) + to_number("right"(sp_dwt.sat_vacancyhours, 2), '99'::text)), (0)::numeric) + ELSE (0)::numeric + END) + + CASE + WHEN (sp_dwt.sun_vacancytype = 'ill'::text) THEN COALESCE(((to_number("left"(sp_dwt.sun_vacancyhours, 2), '99'::text) * (60)::numeric) + to_number("right"(sp_dwt.sun_vacancyhours, 2), '99'::text)), (0)::numeric) + ELSE (0)::numeric + END) AS weekvacancy_minutes_ill, + (((((( + CASE + WHEN (sp_dwt.mon_vacancytype <> 'ill'::text) THEN COALESCE(((to_number("left"(sp_dwt.mon_vacancyhours, 2), '99'::text) * (60)::numeric) + to_number("right"(sp_dwt.mon_vacancyhours, 2), '99'::text)), (0)::numeric) + ELSE (0)::numeric + END + + CASE + WHEN (sp_dwt.tue_vacancytype <> 'ill'::text) THEN COALESCE(((to_number("left"(sp_dwt.tue_vacancyhours, 2), '99'::text) * (60)::numeric) + to_number("right"(sp_dwt.tue_vacancyhours, 2), '99'::text)), (0)::numeric) + ELSE (0)::numeric + END) + + CASE + WHEN (sp_dwt.wed_vacancytype <> 'ill'::text) THEN COALESCE(((to_number("left"(sp_dwt.wed_vacancyhours, 2), '99'::text) * (60)::numeric) + to_number("right"(sp_dwt.wed_vacancyhours, 2), '99'::text)), (0)::numeric) + ELSE (0)::numeric + END) + + CASE + WHEN (sp_dwt.thu_vacancytype <> 'ill'::text) THEN COALESCE(((to_number("left"(sp_dwt.thu_vacancyhours, 2), '99'::text) * (60)::numeric) + to_number("right"(sp_dwt.thu_vacancyhours, 2), '99'::text)), (0)::numeric) + ELSE (0)::numeric + END) + + CASE + WHEN (sp_dwt.fri_vacancytype <> 'ill'::text) THEN COALESCE(((to_number("left"(sp_dwt.fri_vacancyhours, 2), '99'::text) * (60)::numeric) + to_number("right"(sp_dwt.fri_vacancyhours, 2), '99'::text)), (0)::numeric) + ELSE (0)::numeric + END) + + CASE + WHEN (sp_dwt.sat_vacancytype <> 'ill'::text) THEN COALESCE(((to_number("left"(sp_dwt.sat_vacancyhours, 2), '99'::text) * (60)::numeric) + to_number("right"(sp_dwt.sat_vacancyhours, 2), '99'::text)), (0)::numeric) + ELSE (0)::numeric + END) + + CASE + WHEN (sp_dwt.sun_vacancytype <> 'ill'::text) THEN COALESCE(((to_number("left"(sp_dwt.sun_vacancyhours, 2), '99'::text) * (60)::numeric) + to_number("right"(sp_dwt.sun_vacancyhours, 2), '99'::text)), (0)::numeric) + ELSE (0)::numeric + END) AS weekvacancy_minutes, + ((to_number("left"(sp_dwt.week_timetotal, 2), '99'::text) * (60)::numeric) + to_number("right"(sp_dwt.week_timetotal, 2), '99'::text)) AS weekminutes, + sp_dwt.mon_id, + sp_dwt.weekbegin AS mon_date, + ((COALESCE(((to_char((sp_dwt.mon_start1)::interval, 'HH24:MI'::text) || ' - '::text) || to_char((sp_dwt.mon_end1)::interval, 'HH24:MI'::text)), ''::text) || COALESCE(((('
'::text || to_char((sp_dwt.mon_start2)::interval, 'HH24:MI'::text)) || ' - '::text) || to_char((sp_dwt.mon_end2)::interval, 'HH24:MI'::text)), ''::text)) || COALESCE(((('
Congé '::text || sp_dwt.mon_vacancytype) || ': '::text) || to_char((sp_dwt.mon_vacancyhours)::interval, 'HH24:MI'::text)), ''::text)) AS dspmontimes, + sp_dwt.mon_timetotal, + sp_dwt.tue_id, + date((sp_dwt.weekbegin + '1 day'::interval)) AS tue_date, + ((COALESCE(((to_char((sp_dwt.tue_start1)::interval, 'HH24:MI'::text) || ' - '::text) || to_char((sp_dwt.tue_end1)::interval, 'HH24:MI'::text)), ''::text) || COALESCE(((('
'::text || to_char((sp_dwt.tue_start2)::interval, 'HH24:MI'::text)) || ' - '::text) || to_char((sp_dwt.tue_end2)::interval, 'HH24:MI'::text)), ''::text)) || COALESCE(((('
Congé '::text || sp_dwt.tue_vacancytype) || ': '::text) || to_char((sp_dwt.tue_vacancyhours)::interval, 'HH24:MI'::text)), ''::text)) AS dsptuetimes, + sp_dwt.tue_timetotal, + sp_dwt.wed_id, + date((sp_dwt.weekbegin + '2 days'::interval)) AS wed_date, + ((COALESCE(((to_char((sp_dwt.wed_start1)::interval, 'HH24:MI'::text) || ' - '::text) || to_char((sp_dwt.wed_end1)::interval, 'HH24:MI'::text)), ''::text) || COALESCE(((('
'::text || to_char((sp_dwt.wed_start2)::interval, 'HH24:MI'::text)) || ' - '::text) || to_char((sp_dwt.wed_end2)::interval, 'HH24:MI'::text)), ''::text)) || COALESCE(((('
Congé '::text || sp_dwt.wed_vacancytype) || ': '::text) || to_char((sp_dwt.wed_vacancyhours)::interval, 'HH24:MI'::text)), ''::text)) AS dspwedtimes, + sp_dwt.wed_timetotal, + sp_dwt.thu_id, + date((sp_dwt.weekbegin + '3 days'::interval)) AS thu_date, + ((COALESCE(((to_char((sp_dwt.thu_start1)::interval, 'HH24:MI'::text) || ' - '::text) || to_char((sp_dwt.thu_end1)::interval, 'HH24:MI'::text)), ''::text) || COALESCE(((('
'::text || to_char((sp_dwt.thu_start2)::interval, 'HH24:MI'::text)) || ' - '::text) || to_char((sp_dwt.thu_end2)::interval, 'HH24:MI'::text)), ''::text)) || COALESCE(((('
Congé '::text || sp_dwt.thu_vacancytype) || ': '::text) || to_char((sp_dwt.thu_vacancyhours)::interval, 'HH24:MI'::text)), ''::text)) AS dspthutimes, + sp_dwt.thu_timetotal, + sp_dwt.fri_id, + date((sp_dwt.weekbegin + '4 days'::interval)) AS fri_date, + ((COALESCE(((to_char((sp_dwt.fri_start1)::interval, 'HH24:MI'::text) || ' -'::text) || to_char((sp_dwt.fri_end1)::interval, 'HH24:MI'::text)), ''::text) || COALESCE(((('
'::text || to_char((sp_dwt.fri_start2)::interval, 'HH24:MI'::text)) || ' - '::text) || to_char((sp_dwt.fri_end2)::interval, 'HH24:MI'::text)), ''::text)) || COALESCE(((('
Congé '::text || sp_dwt.fri_vacancytype) || ': '::text) || to_char((sp_dwt.fri_vacancyhours)::interval, 'HH24:MI'::text)), ''::text)) AS dspfritimes, + sp_dwt.fri_timetotal, + sp_dwt.sat_id, + date((sp_dwt.weekbegin + '5 days'::interval)) AS sat_date, + ((COALESCE(((to_char((sp_dwt.sat_start1)::interval, 'HH24:MI'::text) || ' - '::text) || to_char((sp_dwt.sat_end1)::interval, 'HH24:MI'::text)), ''::text) || COALESCE(((('
'::text || to_char((sp_dwt.sat_start2)::interval, 'HH24:MI'::text)) || ' - '::text) || to_char((sp_dwt.sat_end2)::interval, 'HH24:MI'::text)), ''::text)) || COALESCE(((('
Congé '::text || sp_dwt.sat_vacancytype) || ': '::text) || to_char((sp_dwt.sat_vacancyhours)::interval, 'HH24:MI'::text)), ''::text)) AS dspsattimes, + sp_dwt.sat_timetotal, + sp_dwt.sun_id, + date((sp_dwt.weekbegin + '6 days'::interval)) AS sun_date, + ((COALESCE(((to_char((sp_dwt.sun_start1)::interval, 'HH24:MI'::text) || ' - '::text) || to_char((sp_dwt.sun_end1)::interval, 'HH24:MI'::text)), ''::text) || COALESCE(((('
'::text || to_char((sp_dwt.sun_start2)::interval, 'HH24:MI'::text)) || ' - '::text) || to_char((sp_dwt.sun_end2)::interval, 'HH24:MI'::text)), ''::text)) || COALESCE(((('
Congé '::text || sp_dwt.sun_vacancytype) || ': '::text) || to_char((sp_dwt.sun_vacancyhours)::interval, 'HH24:MI'::text)), ''::text)) AS dspsuntimes, + sp_dwt.sun_timetotal + FROM (%%NEWSCHEMA%%.vw_staffworkplan_weekly sp_dwt + LEFT JOIN %%NEWSCHEMA%%.staff st ON ((sp_dwt.id_staff = st.id))) + ORDER BY sp_dwt.calweek; + +CREATE TABLE %%NEWSCHEMA%%.workplans ( + id integer NOT NULL, + workplan text, + mon_timestart1 time without time zone, + mon_timeend1 time without time zone, + mon_timestart2 time without time zone, + mon_timeend2 time without time zone, + mon_timepause time without time zone, + tue_timestart1 time without time zone, + tue_timeend1 time without time zone, + tue_timestart2 time without time zone, + tue_timeend2 time without time zone, + tue_timepause time without time zone, + wed_timestart1 time without time zone, + wed_timeend1 time without time zone, + wed_timestart2 time without time zone, + wed_timeend2 time without time zone, + wed_timepause time without time zone, + thu_timestart1 time without time zone, + thu_timeend1 time without time zone, + thu_timestart2 time without time zone, + thu_timeend2 time without time zone, + thu_timepause time without time zone, + fri_timestart1 time without time zone, + fri_timeend1 time without time zone, + fri_timestart2 time without time zone, + fri_timeend2 time without time zone, + fri_timepause time without time zone, + sat_timestart1 time without time zone, + sat_timeend1 time without time zone, + sat_timestart2 time without time zone, + sat_timeend2 time without time zone, + sat_timepause time without time zone, + sun_timestart1 time without time zone, + sun_timeend1 time without time zone, + sun_timestart2 time without time zone, + sun_timeend2 time without time zone, + sun_timepause time without time zone +); + +CREATE VIEW %%NEWSCHEMA%%.vw_workplanlist AS + SELECT workplans.id, + workplans.workplan + FROM %%NEWSCHEMA%%.workplans; + +CREATE VIEW %%NEWSCHEMA%%.vw_workplans AS + SELECT workplans.id, + workplans.workplan, + ((COALESCE(((to_char((workplans.mon_timestart1)::interval, 'HH24:MI'::text) || ' - '::text) || to_char((workplans.mon_timeend1)::interval, 'HH24:MI'::text)), ''::text) || COALESCE(((('
'::text || to_char((workplans.mon_timestart2)::interval, 'HH24:MI'::text)) || ' - '::text) || to_char((workplans.mon_timeend2)::interval, 'HH24:MI'::text)), ''::text)) || COALESCE((('
'::text || 'Pause: '::text) || to_char((workplans.mon_timepause)::interval, 'HH24:MI'::text)), ''::text)) AS dspmontimes, + ((COALESCE(((to_char((workplans.tue_timestart1)::interval, 'HH24:MI'::text) || ' - '::text) || to_char((workplans.tue_timeend1)::interval, 'HH24:MI'::text)), ''::text) || COALESCE(((('
'::text || to_char((workplans.tue_timestart2)::interval, 'HH24:MI'::text)) || ' - '::text) || to_char((workplans.tue_timeend2)::interval, 'HH24:MI'::text)), ''::text)) || COALESCE((('
'::text || 'Pause: '::text) || to_char((workplans.tue_timepause)::interval, 'HH24:MI'::text)), ''::text)) AS dsptuetimes, + ((COALESCE(((to_char((workplans.wed_timestart1)::interval, 'HH24:MI'::text) || ' - '::text) || to_char((workplans.wed_timeend1)::interval, 'HH24:MI'::text)), ''::text) || COALESCE(((('
'::text || to_char((workplans.wed_timestart2)::interval, 'HH24:MI'::text)) || ' - '::text) || to_char((workplans.wed_timeend2)::interval, 'HH24:MI'::text)), ''::text)) || COALESCE((('
'::text || 'Pause: '::text) || to_char((workplans.wed_timepause)::interval, 'HH24:MI'::text)), ''::text)) AS dspwedtimes, + ((COALESCE(((to_char((workplans.thu_timestart1)::interval, 'HH24:MI'::text) || ' - '::text) || to_char((workplans.thu_timeend1)::interval, 'HH24:MI'::text)), ''::text) || COALESCE(((('
'::text || to_char((workplans.thu_timestart2)::interval, 'HH24:MI'::text)) || ' - '::text) || to_char((workplans.thu_timeend2)::interval, 'HH24:MI'::text)), ''::text)) || COALESCE((('
'::text || 'Pause: '::text) || to_char((workplans.thu_timepause)::interval, 'HH24:MI'::text)), ''::text)) AS dspthutimes, + ((COALESCE(((to_char((workplans.fri_timestart1)::interval, 'HH24:MI'::text) || ' -'::text) || to_char((workplans.fri_timeend1)::interval, 'HH24:MI'::text)), ''::text) || COALESCE(((('
'::text || to_char((workplans.fri_timestart2)::interval, 'HH24:MI'::text)) || ' - '::text) || to_char((workplans.fri_timeend2)::interval, 'HH24:MI'::text)), ''::text)) || COALESCE((('
'::text || 'Pause: '::text) || to_char((workplans.fri_timepause)::interval, 'HH24:MI'::text)), ''::text)) AS dspfritimes, + ((COALESCE(((to_char((workplans.sat_timestart1)::interval, 'HH24:MI'::text) || ' - '::text) || to_char((workplans.sat_timeend1)::interval, 'HH24:MI'::text)), ''::text) || COALESCE(((('
'::text || to_char((workplans.sat_timestart2)::interval, 'HH24:MI'::text)) || ' - '::text) || to_char((workplans.sat_timeend2)::interval, 'HH24:MI'::text)), ''::text)) || COALESCE((('
'::text || 'Pause: '::text) || to_char((workplans.sat_timepause)::interval, 'HH24:MI'::text)), ''::text)) AS dspsattimes, + ((COALESCE(((to_char((workplans.sun_timestart1)::interval, 'HH24:MI'::text) || ' - '::text) || to_char((workplans.sun_timeend1)::interval, 'HH24:MI'::text)), ''::text) || COALESCE(((('
'::text || to_char((workplans.sun_timestart2)::interval, 'HH24:MI'::text)) || ' - '::text) || to_char((workplans.sun_timeend2)::interval, 'HH24:MI'::text)), ''::text)) || COALESCE((('
'::text || 'Pause: '::text) || to_char((workplans.sun_timepause)::interval, 'HH24:MI'::text)), ''::text)) AS dspsuntimes + FROM %%NEWSCHEMA%%.workplans; + +CREATE VIEW %%NEWSCHEMA%%.vw_workplansdata AS + SELECT workplans.id, + workplans.workplan, + to_char((workplans.mon_timestart1)::interval, 'HH24:MI'::text) AS mon_timestart1, + to_char((workplans.mon_timeend1)::interval, 'HH24:MI'::text) AS mon_timeend1, + to_char((workplans.mon_timestart2)::interval, 'HH24:MI'::text) AS mon_timestart2, + to_char((workplans.mon_timeend2)::interval, 'HH24:MI'::text) AS mon_timeend2, + to_char((workplans.mon_timepause)::interval, 'HH24:MI'::text) AS mon_timepause, + to_char((workplans.tue_timestart1)::interval, 'HH24:MI'::text) AS tue_timestart1, + to_char((workplans.tue_timeend1)::interval, 'HH24:MI'::text) AS tue_timeend1, + to_char((workplans.tue_timestart2)::interval, 'HH24:MI'::text) AS tue_timestart2, + to_char((workplans.tue_timeend2)::interval, 'HH24:MI'::text) AS tue_timeend2, + to_char((workplans.tue_timepause)::interval, 'HH24:MI'::text) AS tue_timepause, + to_char((workplans.wed_timestart1)::interval, 'HH24:MI'::text) AS wed_timestart1, + to_char((workplans.wed_timeend1)::interval, 'HH24:MI'::text) AS wed_timeend1, + to_char((workplans.wed_timestart2)::interval, 'HH24:MI'::text) AS wed_timestart2, + to_char((workplans.wed_timeend2)::interval, 'HH24:MI'::text) AS wed_timeend2, + to_char((workplans.wed_timepause)::interval, 'HH24:MI'::text) AS wed_timepause, + to_char((workplans.thu_timestart1)::interval, 'HH24:MI'::text) AS thu_timestart1, + to_char((workplans.thu_timeend1)::interval, 'HH24:MI'::text) AS thu_timeend1, + to_char((workplans.thu_timestart2)::interval, 'HH24:MI'::text) AS thu_timestart2, + to_char((workplans.thu_timeend2)::interval, 'HH24:MI'::text) AS thu_timeend2, + to_char((workplans.thu_timepause)::interval, 'HH24:MI'::text) AS thu_timepause, + to_char((workplans.fri_timestart1)::interval, 'HH24:MI'::text) AS fri_timestart1, + to_char((workplans.fri_timeend1)::interval, 'HH24:MI'::text) AS fri_timeend1, + to_char((workplans.fri_timestart2)::interval, 'HH24:MI'::text) AS fri_timestart2, + to_char((workplans.fri_timeend2)::interval, 'HH24:MI'::text) AS fri_timeend2, + to_char((workplans.fri_timepause)::interval, 'HH24:MI'::text) AS fri_timepause, + to_char((workplans.sat_timestart1)::interval, 'HH24:MI'::text) AS sat_timestart1, + to_char((workplans.sat_timeend1)::interval, 'HH24:MI'::text) AS sat_timeend1, + to_char((workplans.sat_timestart2)::interval, 'HH24:MI'::text) AS sat_timestart2, + to_char((workplans.sat_timeend2)::interval, 'HH24:MI'::text) AS sat_timeend2, + to_char((workplans.sat_timepause)::interval, 'HH24:MI'::text) AS sat_timepause, + to_char((workplans.sun_timestart1)::interval, 'HH24:MI'::text) AS sun_timestart1, + to_char((workplans.sun_timeend1)::interval, 'HH24:MI'::text) AS sun_timeend1, + to_char((workplans.sun_timestart2)::interval, 'HH24:MI'::text) AS sun_timestart2, + to_char((workplans.sun_timeend2)::interval, 'HH24:MI'::text) AS sun_timeend2, + to_char((workplans.sun_timepause)::interval, 'HH24:MI'::text) AS sun_timepause + FROM %%NEWSCHEMA%%.workplans; + +CREATE SEQUENCE %%NEWSCHEMA%%.workplans_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + +ALTER SEQUENCE %%NEWSCHEMA%%.workplans_id_seq OWNED BY %%NEWSCHEMA%%.workplans.id; + +CREATE TABLE %%NEWSCHEMA%%.worktypes ( + id integer NOT NULL, + worktype text, + isworktime boolean, + isfreetime boolean, + typecolor text +); + +CREATE SEQUENCE %%NEWSCHEMA%%.worktypes_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + +ALTER SEQUENCE %%NEWSCHEMA%%.worktypes_id_seq OWNED BY %%NEWSCHEMA%%.worktypes.id; + +ALTER TABLE ONLY %%NEWSCHEMA%%.defaultweekworkplan ALTER COLUMN id SET DEFAULT nextval('%%NEWSCHEMA%%.defaultweekworkplan_id_seq'::regclass); + +ALTER TABLE ONLY %%NEWSCHEMA%%.defaultworkplan ALTER COLUMN id SET DEFAULT nextval('%%NEWSCHEMA%%.defaultworkplan_id_seq'::regclass); + +ALTER TABLE ONLY %%NEWSCHEMA%%.reportperiod ALTER COLUMN id SET DEFAULT nextval('%%NEWSCHEMA%%.reportperiod_id_seq'::regclass); + +ALTER TABLE ONLY %%NEWSCHEMA%%.sites ALTER COLUMN id SET DEFAULT nextval('%%NEWSCHEMA%%.sites_id_seq'::regclass); + +ALTER TABLE ONLY %%NEWSCHEMA%%.staff ALTER COLUMN id SET DEFAULT nextval('%%NEWSCHEMA%%.staff_id_seq'::regclass); + +ALTER TABLE ONLY %%NEWSCHEMA%%.staffgroups ALTER COLUMN id SET DEFAULT nextval('%%NEWSCHEMA%%.staffgroups_id_seq'::regclass); + +ALTER TABLE ONLY %%NEWSCHEMA%%.staffperiodbase ALTER COLUMN id SET DEFAULT nextval('%%NEWSCHEMA%%.staffperiodbase_id_seq'::regclass); + +ALTER TABLE ONLY %%NEWSCHEMA%%.stafftimetracks ALTER COLUMN id SET DEFAULT nextval('%%NEWSCHEMA%%.stafftimetracks_id_seq'::regclass); + +ALTER TABLE ONLY %%NEWSCHEMA%%.staffvacancy ALTER COLUMN id SET DEFAULT nextval('%%NEWSCHEMA%%.staffvacancy_id_seq'::regclass); + +ALTER TABLE ONLY %%NEWSCHEMA%%.staffvacancyyear ALTER COLUMN id SET DEFAULT nextval('%%NEWSCHEMA%%.staffvacancyyear_id_seq'::regclass); + +ALTER TABLE ONLY %%NEWSCHEMA%%.staffworkplan ALTER COLUMN id SET DEFAULT nextval('%%NEWSCHEMA%%.staffworkplan_id_seq'::regclass); + +ALTER TABLE ONLY %%NEWSCHEMA%%.workplans ALTER COLUMN id SET DEFAULT nextval('%%NEWSCHEMA%%.workplans_id_seq'::regclass); + +ALTER TABLE ONLY %%NEWSCHEMA%%.worktypes ALTER COLUMN id SET DEFAULT nextval('%%NEWSCHEMA%%.worktypes_id_seq'::regclass); + +ALTER TABLE ONLY %%NEWSCHEMA%%.defaultweekworkplan + ADD CONSTRAINT defaultweekworkplan_pkey PRIMARY KEY (id); + +ALTER TABLE ONLY %%NEWSCHEMA%%.defaultworkplan + ADD CONSTRAINT defaultworkplan_pkey PRIMARY KEY (id); + +ALTER TABLE ONLY %%NEWSCHEMA%%.reportperiod + ADD CONSTRAINT reportperiod_pkey PRIMARY KEY (id); + +ALTER TABLE ONLY %%NEWSCHEMA%%.sites + ADD CONSTRAINT sites_pkey PRIMARY KEY (id); + +ALTER TABLE ONLY %%NEWSCHEMA%%.staff + ADD CONSTRAINT staff_pkey PRIMARY KEY (id); + +ALTER TABLE ONLY %%NEWSCHEMA%%.staffgroups + ADD CONSTRAINT staffgroups_pkey PRIMARY KEY (id); + +ALTER TABLE ONLY %%NEWSCHEMA%%.staffperiodbase + ADD CONSTRAINT staffperiodbase_pkey PRIMARY KEY (id); + +ALTER TABLE ONLY %%NEWSCHEMA%%.stafftimetracks + ADD CONSTRAINT stafftimetracks_pkey PRIMARY KEY (id); + +ALTER TABLE ONLY %%NEWSCHEMA%%.staffvacancy + ADD CONSTRAINT staffvacancy_pkey PRIMARY KEY (id); + +ALTER TABLE ONLY %%NEWSCHEMA%%.staffvacancyyear + ADD CONSTRAINT staffvacancyyear_pkey PRIMARY KEY (id); + +ALTER TABLE ONLY %%NEWSCHEMA%%.staffworkplan + ADD CONSTRAINT staffworkplan_pkey PRIMARY KEY (id); + +ALTER TABLE ONLY %%NEWSCHEMA%%.workplans + ADD CONSTRAINT workplans_pkey PRIMARY KEY (id); + +ALTER TABLE ONLY %%NEWSCHEMA%%.worktypes + ADD CONSTRAINT worktypes_pkey PRIMARY KEY (id); + +CREATE TRIGGER trg_upd_%%NEWSCHEMA%%_weekhours BEFORE UPDATE OF weekhours ON %%NEWSCHEMA%%.staffperiodbase FOR EACH ROW EXECUTE PROCEDURE public.trg_update_monthhours(); diff --git a/backoffice/img/bg1.jpg b/backoffice/img/bg1.jpg new file mode 100644 index 0000000..80c5326 Binary files /dev/null and b/backoffice/img/bg1.jpg differ diff --git a/backoffice/img/favicon/android-icon-144x144.png b/backoffice/img/favicon/android-icon-144x144.png new file mode 100644 index 0000000..6aa79d8 Binary files /dev/null and b/backoffice/img/favicon/android-icon-144x144.png differ diff --git a/backoffice/img/favicon/android-icon-192x192.png b/backoffice/img/favicon/android-icon-192x192.png new file mode 100644 index 0000000..f58a3e6 Binary files /dev/null and b/backoffice/img/favicon/android-icon-192x192.png differ diff --git a/backoffice/img/favicon/android-icon-36x36.png b/backoffice/img/favicon/android-icon-36x36.png new file mode 100644 index 0000000..f52eed7 Binary files /dev/null and b/backoffice/img/favicon/android-icon-36x36.png differ diff --git a/backoffice/img/favicon/android-icon-48x48.png b/backoffice/img/favicon/android-icon-48x48.png new file mode 100644 index 0000000..d5beba1 Binary files /dev/null and b/backoffice/img/favicon/android-icon-48x48.png differ diff --git a/backoffice/img/favicon/android-icon-72x72.png b/backoffice/img/favicon/android-icon-72x72.png new file mode 100644 index 0000000..7c7f324 Binary files /dev/null and b/backoffice/img/favicon/android-icon-72x72.png differ diff --git a/backoffice/img/favicon/android-icon-96x96.png b/backoffice/img/favicon/android-icon-96x96.png new file mode 100644 index 0000000..38484ee Binary files /dev/null and b/backoffice/img/favicon/android-icon-96x96.png differ diff --git a/backoffice/img/favicon/apple-icon-114x114.png b/backoffice/img/favicon/apple-icon-114x114.png new file mode 100644 index 0000000..3d448dd Binary files /dev/null and b/backoffice/img/favicon/apple-icon-114x114.png differ diff --git a/backoffice/img/favicon/apple-icon-120x120.png b/backoffice/img/favicon/apple-icon-120x120.png new file mode 100644 index 0000000..99a1a39 Binary files /dev/null and b/backoffice/img/favicon/apple-icon-120x120.png differ diff --git a/backoffice/img/favicon/apple-icon-144x144.png b/backoffice/img/favicon/apple-icon-144x144.png new file mode 100644 index 0000000..6aa79d8 Binary files /dev/null and b/backoffice/img/favicon/apple-icon-144x144.png differ diff --git a/backoffice/img/favicon/apple-icon-152x152.png b/backoffice/img/favicon/apple-icon-152x152.png new file mode 100644 index 0000000..3ee4143 Binary files /dev/null and b/backoffice/img/favicon/apple-icon-152x152.png differ diff --git a/backoffice/img/favicon/apple-icon-180x180.png b/backoffice/img/favicon/apple-icon-180x180.png new file mode 100644 index 0000000..7541cce Binary files /dev/null and b/backoffice/img/favicon/apple-icon-180x180.png differ diff --git a/backoffice/img/favicon/apple-icon-57x57.png b/backoffice/img/favicon/apple-icon-57x57.png new file mode 100644 index 0000000..58d5700 Binary files /dev/null and b/backoffice/img/favicon/apple-icon-57x57.png differ diff --git a/backoffice/img/favicon/apple-icon-60x60.png b/backoffice/img/favicon/apple-icon-60x60.png new file mode 100644 index 0000000..31a3f78 Binary files /dev/null and b/backoffice/img/favicon/apple-icon-60x60.png differ diff --git a/backoffice/img/favicon/apple-icon-72x72.png b/backoffice/img/favicon/apple-icon-72x72.png new file mode 100644 index 0000000..7c7f324 Binary files /dev/null and b/backoffice/img/favicon/apple-icon-72x72.png differ diff --git a/backoffice/img/favicon/apple-icon-76x76.png b/backoffice/img/favicon/apple-icon-76x76.png new file mode 100644 index 0000000..bd28884 Binary files /dev/null and b/backoffice/img/favicon/apple-icon-76x76.png differ diff --git a/backoffice/img/favicon/apple-icon-precomposed.png b/backoffice/img/favicon/apple-icon-precomposed.png new file mode 100644 index 0000000..cd3635a Binary files /dev/null and b/backoffice/img/favicon/apple-icon-precomposed.png differ diff --git a/backoffice/img/favicon/apple-icon.png b/backoffice/img/favicon/apple-icon.png new file mode 100644 index 0000000..cd3635a Binary files /dev/null and b/backoffice/img/favicon/apple-icon.png differ diff --git a/backoffice/img/favicon/browserconfig.xml b/backoffice/img/favicon/browserconfig.xml new file mode 100644 index 0000000..c554148 --- /dev/null +++ b/backoffice/img/favicon/browserconfig.xml @@ -0,0 +1,2 @@ + +#ffffff \ No newline at end of file diff --git a/backoffice/img/favicon/favicon-16x16.png b/backoffice/img/favicon/favicon-16x16.png new file mode 100644 index 0000000..09adf92 Binary files /dev/null and b/backoffice/img/favicon/favicon-16x16.png differ diff --git a/backoffice/img/favicon/favicon-32x32.png b/backoffice/img/favicon/favicon-32x32.png new file mode 100644 index 0000000..3281e25 Binary files /dev/null and b/backoffice/img/favicon/favicon-32x32.png differ diff --git a/backoffice/img/favicon/favicon-96x96.png b/backoffice/img/favicon/favicon-96x96.png new file mode 100644 index 0000000..38484ee Binary files /dev/null and b/backoffice/img/favicon/favicon-96x96.png differ diff --git a/backoffice/img/favicon/favicon.ico b/backoffice/img/favicon/favicon.ico new file mode 100644 index 0000000..bbf93a1 Binary files /dev/null and b/backoffice/img/favicon/favicon.ico differ diff --git a/backoffice/img/favicon/manifest.json b/backoffice/img/favicon/manifest.json new file mode 100644 index 0000000..013d4a6 --- /dev/null +++ b/backoffice/img/favicon/manifest.json @@ -0,0 +1,41 @@ +{ + "name": "App", + "icons": [ + { + "src": "\/android-icon-36x36.png", + "sizes": "36x36", + "type": "image\/png", + "density": "0.75" + }, + { + "src": "\/android-icon-48x48.png", + "sizes": "48x48", + "type": "image\/png", + "density": "1.0" + }, + { + "src": "\/android-icon-72x72.png", + "sizes": "72x72", + "type": "image\/png", + "density": "1.5" + }, + { + "src": "\/android-icon-96x96.png", + "sizes": "96x96", + "type": "image\/png", + "density": "2.0" + }, + { + "src": "\/android-icon-144x144.png", + "sizes": "144x144", + "type": "image\/png", + "density": "3.0" + }, + { + "src": "\/android-icon-192x192.png", + "sizes": "192x192", + "type": "image\/png", + "density": "4.0" + } + ] +} \ No newline at end of file diff --git a/backoffice/img/favicon/ms-icon-144x144.png b/backoffice/img/favicon/ms-icon-144x144.png new file mode 100644 index 0000000..6aa79d8 Binary files /dev/null and b/backoffice/img/favicon/ms-icon-144x144.png differ diff --git a/backoffice/img/favicon/ms-icon-150x150.png b/backoffice/img/favicon/ms-icon-150x150.png new file mode 100644 index 0000000..b08e562 Binary files /dev/null and b/backoffice/img/favicon/ms-icon-150x150.png differ diff --git a/backoffice/img/favicon/ms-icon-310x310.png b/backoffice/img/favicon/ms-icon-310x310.png new file mode 100644 index 0000000..12046d8 Binary files /dev/null and b/backoffice/img/favicon/ms-icon-310x310.png differ diff --git a/backoffice/img/favicon/ms-icon-70x70.png b/backoffice/img/favicon/ms-icon-70x70.png new file mode 100644 index 0000000..5135560 Binary files /dev/null and b/backoffice/img/favicon/ms-icon-70x70.png differ diff --git a/backoffice/img/hourtrax.png b/backoffice/img/hourtrax.png new file mode 100644 index 0000000..4f04687 Binary files /dev/null and b/backoffice/img/hourtrax.png differ diff --git a/backoffice/img/icons/Agreement_01.svg b/backoffice/img/icons/Agreement_01.svg new file mode 100644 index 0000000..27a8a06 --- /dev/null +++ b/backoffice/img/icons/Agreement_01.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/backoffice/img/icons/Bill.svg b/backoffice/img/icons/Bill.svg new file mode 100644 index 0000000..b891cd2 --- /dev/null +++ b/backoffice/img/icons/Bill.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/backoffice/img/icons/Document_Save.svg b/backoffice/img/icons/Document_Save.svg new file mode 100644 index 0000000..7262b20 --- /dev/null +++ b/backoffice/img/icons/Document_Save.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/backoffice/img/icons/Floppy.svg b/backoffice/img/icons/Floppy.svg new file mode 100644 index 0000000..d85ccd9 --- /dev/null +++ b/backoffice/img/icons/Floppy.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/backoffice/img/icons/Folder_Delete_01.svg b/backoffice/img/icons/Folder_Delete_01.svg new file mode 100644 index 0000000..c1b0566 --- /dev/null +++ b/backoffice/img/icons/Folder_Delete_01.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/backoffice/img/icons/Folder_Find_01.svg b/backoffice/img/icons/Folder_Find_01.svg new file mode 100644 index 0000000..7d4ef63 --- /dev/null +++ b/backoffice/img/icons/Folder_Find_01.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/backoffice/img/icons/Save.svg b/backoffice/img/icons/Save.svg new file mode 100644 index 0000000..ce6bfa3 --- /dev/null +++ b/backoffice/img/icons/Save.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/backoffice/img/icons/access.svg b/backoffice/img/icons/access.svg new file mode 100644 index 0000000..ca4578c --- /dev/null +++ b/backoffice/img/icons/access.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/backoffice/img/icons/access_white.svg b/backoffice/img/icons/access_white.svg new file mode 100644 index 0000000..5ecb2b8 --- /dev/null +++ b/backoffice/img/icons/access_white.svg @@ -0,0 +1,5 @@ + + + + \ No newline at end of file diff --git a/backoffice/img/icons/address.svg b/backoffice/img/icons/address.svg new file mode 100644 index 0000000..4d51035 --- /dev/null +++ b/backoffice/img/icons/address.svg @@ -0,0 +1,3 @@ + + + diff --git a/backoffice/img/icons/address_white.svg b/backoffice/img/icons/address_white.svg new file mode 100644 index 0000000..a5de7d7 --- /dev/null +++ b/backoffice/img/icons/address_white.svg @@ -0,0 +1,3 @@ + + + diff --git a/backoffice/img/icons/apps.svg b/backoffice/img/icons/apps.svg new file mode 100644 index 0000000..eef3c30 --- /dev/null +++ b/backoffice/img/icons/apps.svg @@ -0,0 +1,3 @@ + + + diff --git a/backoffice/img/icons/apps_white.svg b/backoffice/img/icons/apps_white.svg new file mode 100644 index 0000000..f37f596 --- /dev/null +++ b/backoffice/img/icons/apps_white.svg @@ -0,0 +1,3 @@ + + + diff --git a/backoffice/img/icons/archive.svg b/backoffice/img/icons/archive.svg new file mode 100644 index 0000000..5dc21ee --- /dev/null +++ b/backoffice/img/icons/archive.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/backoffice/img/icons/archive_white.svg b/backoffice/img/icons/archive_white.svg new file mode 100644 index 0000000..2cff08a --- /dev/null +++ b/backoffice/img/icons/archive_white.svg @@ -0,0 +1,5 @@ + + + + \ No newline at end of file diff --git a/backoffice/img/icons/calendar.svg b/backoffice/img/icons/calendar.svg new file mode 100644 index 0000000..6b51e03 --- /dev/null +++ b/backoffice/img/icons/calendar.svg @@ -0,0 +1,3 @@ + + + diff --git a/backoffice/img/icons/calendar_white.svg b/backoffice/img/icons/calendar_white.svg new file mode 100644 index 0000000..c738ec5 --- /dev/null +++ b/backoffice/img/icons/calendar_white.svg @@ -0,0 +1,3 @@ + + + diff --git a/backoffice/img/icons/club.svg b/backoffice/img/icons/club.svg new file mode 100644 index 0000000..8a941e3 --- /dev/null +++ b/backoffice/img/icons/club.svg @@ -0,0 +1,3 @@ + + + diff --git a/backoffice/img/icons/club_white.svg b/backoffice/img/icons/club_white.svg new file mode 100644 index 0000000..5325dc0 --- /dev/null +++ b/backoffice/img/icons/club_white.svg @@ -0,0 +1,3 @@ + + + diff --git a/backoffice/img/icons/clubs.svg b/backoffice/img/icons/clubs.svg new file mode 100644 index 0000000..0a7d497 --- /dev/null +++ b/backoffice/img/icons/clubs.svg @@ -0,0 +1,3 @@ + + + diff --git a/backoffice/img/icons/clubs_white.svg b/backoffice/img/icons/clubs_white.svg new file mode 100644 index 0000000..7184d28 --- /dev/null +++ b/backoffice/img/icons/clubs_white.svg @@ -0,0 +1,3 @@ + + + diff --git a/backoffice/img/icons/code.svg b/backoffice/img/icons/code.svg new file mode 100644 index 0000000..c3b4f28 --- /dev/null +++ b/backoffice/img/icons/code.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/backoffice/img/icons/company.svg b/backoffice/img/icons/company.svg new file mode 100644 index 0000000..4b65899 --- /dev/null +++ b/backoffice/img/icons/company.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/backoffice/img/icons/company_white.svg b/backoffice/img/icons/company_white.svg new file mode 100644 index 0000000..ed26c0f --- /dev/null +++ b/backoffice/img/icons/company_white.svg @@ -0,0 +1,5 @@ + + + + \ No newline at end of file diff --git a/backoffice/img/icons/cube.svg b/backoffice/img/icons/cube.svg new file mode 100644 index 0000000..31b3129 --- /dev/null +++ b/backoffice/img/icons/cube.svg @@ -0,0 +1,3 @@ + + + diff --git a/backoffice/img/icons/cube_white.svg b/backoffice/img/icons/cube_white.svg new file mode 100644 index 0000000..9a78edf --- /dev/null +++ b/backoffice/img/icons/cube_white.svg @@ -0,0 +1,3 @@ + + + diff --git a/backoffice/img/icons/cubelight.svg b/backoffice/img/icons/cubelight.svg new file mode 100644 index 0000000..ff786d4 --- /dev/null +++ b/backoffice/img/icons/cubelight.svg @@ -0,0 +1,3 @@ + + + diff --git a/backoffice/img/icons/cubelight_white.svg b/backoffice/img/icons/cubelight_white.svg new file mode 100644 index 0000000..c7965b6 --- /dev/null +++ b/backoffice/img/icons/cubelight_white.svg @@ -0,0 +1,3 @@ + + + diff --git a/backoffice/img/icons/dashboard.svg b/backoffice/img/icons/dashboard.svg new file mode 100644 index 0000000..c5f36cc --- /dev/null +++ b/backoffice/img/icons/dashboard.svg @@ -0,0 +1,3 @@ + + + diff --git a/backoffice/img/icons/dashboard_white.svg b/backoffice/img/icons/dashboard_white.svg new file mode 100644 index 0000000..c6a7dda --- /dev/null +++ b/backoffice/img/icons/dashboard_white.svg @@ -0,0 +1,3 @@ + + + diff --git a/backoffice/img/icons/documents.svg b/backoffice/img/icons/documents.svg new file mode 100644 index 0000000..aaec4c6 --- /dev/null +++ b/backoffice/img/icons/documents.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/backoffice/img/icons/documents_white.svg b/backoffice/img/icons/documents_white.svg new file mode 100644 index 0000000..94d71a7 --- /dev/null +++ b/backoffice/img/icons/documents_white.svg @@ -0,0 +1,5 @@ + + + + \ No newline at end of file diff --git a/backoffice/img/icons/download.svg b/backoffice/img/icons/download.svg new file mode 100644 index 0000000..eb20956 --- /dev/null +++ b/backoffice/img/icons/download.svg @@ -0,0 +1,3 @@ + + + diff --git a/backoffice/img/icons/download_white.svg b/backoffice/img/icons/download_white.svg new file mode 100644 index 0000000..100cebf --- /dev/null +++ b/backoffice/img/icons/download_white.svg @@ -0,0 +1,3 @@ + + + diff --git a/backoffice/img/icons/duplicate.svg b/backoffice/img/icons/duplicate.svg new file mode 100644 index 0000000..cebaad8 --- /dev/null +++ b/backoffice/img/icons/duplicate.svg @@ -0,0 +1,3 @@ + + + diff --git a/backoffice/img/icons/duplicate_white.svg b/backoffice/img/icons/duplicate_white.svg new file mode 100644 index 0000000..a643c74 --- /dev/null +++ b/backoffice/img/icons/duplicate_white.svg @@ -0,0 +1,3 @@ + + + diff --git a/backoffice/img/icons/edit.svg b/backoffice/img/icons/edit.svg new file mode 100644 index 0000000..c0bb9ac --- /dev/null +++ b/backoffice/img/icons/edit.svg @@ -0,0 +1,3 @@ + + + diff --git a/backoffice/img/icons/edit_white.svg b/backoffice/img/icons/edit_white.svg new file mode 100644 index 0000000..bbbe89f --- /dev/null +++ b/backoffice/img/icons/edit_white.svg @@ -0,0 +1,3 @@ + + + diff --git a/backoffice/img/icons/excel.svg b/backoffice/img/icons/excel.svg new file mode 100644 index 0000000..6c14cc2 --- /dev/null +++ b/backoffice/img/icons/excel.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/backoffice/img/icons/excel_white.svg b/backoffice/img/icons/excel_white.svg new file mode 100644 index 0000000..7693393 --- /dev/null +++ b/backoffice/img/icons/excel_white.svg @@ -0,0 +1,5 @@ + + + + \ No newline at end of file diff --git a/backoffice/img/icons/file.svg b/backoffice/img/icons/file.svg new file mode 100644 index 0000000..6df51bd --- /dev/null +++ b/backoffice/img/icons/file.svg @@ -0,0 +1,3 @@ + + + diff --git a/backoffice/img/icons/file/dir.png b/backoffice/img/icons/file/dir.png new file mode 100644 index 0000000..a2e3c0f Binary files /dev/null and b/backoffice/img/icons/file/dir.png differ diff --git a/backoffice/img/icons/file/doc.png b/backoffice/img/icons/file/doc.png new file mode 100644 index 0000000..8e43190 Binary files /dev/null and b/backoffice/img/icons/file/doc.png differ diff --git a/backoffice/img/icons/file/docx.png b/backoffice/img/icons/file/docx.png new file mode 100644 index 0000000..8e43190 Binary files /dev/null and b/backoffice/img/icons/file/docx.png differ diff --git a/backoffice/img/icons/file/file.png b/backoffice/img/icons/file/file.png new file mode 100644 index 0000000..c981a83 Binary files /dev/null and b/backoffice/img/icons/file/file.png differ diff --git a/backoffice/img/icons/file/folderup.svg b/backoffice/img/icons/file/folderup.svg new file mode 100644 index 0000000..7cb0513 --- /dev/null +++ b/backoffice/img/icons/file/folderup.svg @@ -0,0 +1,22 @@ + + + + + + + + diff --git a/backoffice/img/icons/file/folderup_white.svg b/backoffice/img/icons/file/folderup_white.svg new file mode 100644 index 0000000..74fb046 --- /dev/null +++ b/backoffice/img/icons/file/folderup_white.svg @@ -0,0 +1,22 @@ + + + + + + + + diff --git a/backoffice/img/icons/file/jpg.png b/backoffice/img/icons/file/jpg.png new file mode 100644 index 0000000..3f2999c Binary files /dev/null and b/backoffice/img/icons/file/jpg.png differ diff --git a/backoffice/img/icons/file/pdf.png b/backoffice/img/icons/file/pdf.png new file mode 100644 index 0000000..8614b6e Binary files /dev/null and b/backoffice/img/icons/file/pdf.png differ diff --git a/backoffice/img/icons/file/png.png b/backoffice/img/icons/file/png.png new file mode 100644 index 0000000..3f2999c Binary files /dev/null and b/backoffice/img/icons/file/png.png differ diff --git a/backoffice/img/icons/file/txt.png b/backoffice/img/icons/file/txt.png new file mode 100644 index 0000000..2e41cee Binary files /dev/null and b/backoffice/img/icons/file/txt.png differ diff --git a/backoffice/img/icons/file/xls.png b/backoffice/img/icons/file/xls.png new file mode 100644 index 0000000..ceabc7d Binary files /dev/null and b/backoffice/img/icons/file/xls.png differ diff --git a/backoffice/img/icons/file/xlsx.png b/backoffice/img/icons/file/xlsx.png new file mode 100644 index 0000000..ceabc7d Binary files /dev/null and b/backoffice/img/icons/file/xlsx.png differ diff --git a/backoffice/img/icons/file_white.svg b/backoffice/img/icons/file_white.svg new file mode 100644 index 0000000..3e04bda --- /dev/null +++ b/backoffice/img/icons/file_white.svg @@ -0,0 +1,3 @@ + + + diff --git a/backoffice/img/icons/folder.svg b/backoffice/img/icons/folder.svg new file mode 100644 index 0000000..f1f6e4a --- /dev/null +++ b/backoffice/img/icons/folder.svg @@ -0,0 +1,3 @@ + + + diff --git a/backoffice/img/icons/folder_add.svg b/backoffice/img/icons/folder_add.svg new file mode 100644 index 0000000..4f8b21e --- /dev/null +++ b/backoffice/img/icons/folder_add.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/backoffice/img/icons/folder_add_white.svg b/backoffice/img/icons/folder_add_white.svg new file mode 100644 index 0000000..728bbae --- /dev/null +++ b/backoffice/img/icons/folder_add_white.svg @@ -0,0 +1,5 @@ + + + + \ No newline at end of file diff --git a/backoffice/img/icons/folder_white.svg b/backoffice/img/icons/folder_white.svg new file mode 100644 index 0000000..25baa23 --- /dev/null +++ b/backoffice/img/icons/folder_white.svg @@ -0,0 +1,3 @@ + + + diff --git a/backoffice/img/icons/globe.svg b/backoffice/img/icons/globe.svg new file mode 100644 index 0000000..9af64dc --- /dev/null +++ b/backoffice/img/icons/globe.svg @@ -0,0 +1,3 @@ + + + diff --git a/backoffice/img/icons/globe_white.svg b/backoffice/img/icons/globe_white.svg new file mode 100644 index 0000000..f0c2dea --- /dev/null +++ b/backoffice/img/icons/globe_white.svg @@ -0,0 +1,3 @@ + + + diff --git a/backoffice/img/icons/group.svg b/backoffice/img/icons/group.svg new file mode 100644 index 0000000..a74f7ad --- /dev/null +++ b/backoffice/img/icons/group.svg @@ -0,0 +1,3 @@ + + + diff --git a/backoffice/img/icons/group_white.svg b/backoffice/img/icons/group_white.svg new file mode 100644 index 0000000..72dd9db --- /dev/null +++ b/backoffice/img/icons/group_white.svg @@ -0,0 +1,3 @@ + + + diff --git a/backoffice/img/icons/home.svg b/backoffice/img/icons/home.svg new file mode 100644 index 0000000..f6b8f1c --- /dev/null +++ b/backoffice/img/icons/home.svg @@ -0,0 +1,9 @@ + + + + + + + diff --git a/backoffice/img/icons/inbox.svg b/backoffice/img/icons/inbox.svg new file mode 100644 index 0000000..034e942 --- /dev/null +++ b/backoffice/img/icons/inbox.svg @@ -0,0 +1,3 @@ + + + diff --git a/backoffice/img/icons/inbox_white.svg b/backoffice/img/icons/inbox_white.svg new file mode 100644 index 0000000..1d98ae9 --- /dev/null +++ b/backoffice/img/icons/inbox_white.svg @@ -0,0 +1,3 @@ + + + diff --git a/backoffice/img/icons/library.svg b/backoffice/img/icons/library.svg new file mode 100644 index 0000000..0a917f3 --- /dev/null +++ b/backoffice/img/icons/library.svg @@ -0,0 +1,3 @@ + + + diff --git a/backoffice/img/icons/library_white.svg b/backoffice/img/icons/library_white.svg new file mode 100644 index 0000000..3928fdd --- /dev/null +++ b/backoffice/img/icons/library_white.svg @@ -0,0 +1,3 @@ + + + diff --git a/backoffice/img/icons/license.svg b/backoffice/img/icons/license.svg new file mode 100644 index 0000000..54f0fec --- /dev/null +++ b/backoffice/img/icons/license.svg @@ -0,0 +1,3 @@ + + + diff --git a/backoffice/img/icons/license_white.svg b/backoffice/img/icons/license_white.svg new file mode 100644 index 0000000..2563f36 --- /dev/null +++ b/backoffice/img/icons/license_white.svg @@ -0,0 +1,3 @@ + + + diff --git a/backoffice/img/icons/list.svg b/backoffice/img/icons/list.svg new file mode 100644 index 0000000..ea3f0e2 --- /dev/null +++ b/backoffice/img/icons/list.svg @@ -0,0 +1,3 @@ + + + diff --git a/backoffice/img/icons/list_white.svg b/backoffice/img/icons/list_white.svg new file mode 100644 index 0000000..b57b752 --- /dev/null +++ b/backoffice/img/icons/list_white.svg @@ -0,0 +1,3 @@ + + + diff --git a/backoffice/img/icons/log.svg b/backoffice/img/icons/log.svg new file mode 100644 index 0000000..886dd3d --- /dev/null +++ b/backoffice/img/icons/log.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/backoffice/img/icons/log_white.svg b/backoffice/img/icons/log_white.svg new file mode 100644 index 0000000..3e443fa --- /dev/null +++ b/backoffice/img/icons/log_white.svg @@ -0,0 +1,5 @@ + + + + \ No newline at end of file diff --git a/backoffice/img/icons/logout.svg b/backoffice/img/icons/logout.svg new file mode 100644 index 0000000..da64de0 --- /dev/null +++ b/backoffice/img/icons/logout.svg @@ -0,0 +1,3 @@ + + + diff --git a/backoffice/img/icons/logout_white.svg b/backoffice/img/icons/logout_white.svg new file mode 100644 index 0000000..3feb1b7 --- /dev/null +++ b/backoffice/img/icons/logout_white.svg @@ -0,0 +1,3 @@ + + + diff --git a/backoffice/img/icons/menu.svg b/backoffice/img/icons/menu.svg new file mode 100644 index 0000000..1a247ab --- /dev/null +++ b/backoffice/img/icons/menu.svg @@ -0,0 +1,3 @@ + + + diff --git a/backoffice/img/icons/menu_white.svg b/backoffice/img/icons/menu_white.svg new file mode 100644 index 0000000..222cc94 --- /dev/null +++ b/backoffice/img/icons/menu_white.svg @@ -0,0 +1,3 @@ + + + diff --git a/backoffice/img/icons/newspaper.svg b/backoffice/img/icons/newspaper.svg new file mode 100644 index 0000000..420b45a --- /dev/null +++ b/backoffice/img/icons/newspaper.svg @@ -0,0 +1,3 @@ + + + diff --git a/backoffice/img/icons/newspaper_white.svg b/backoffice/img/icons/newspaper_white.svg new file mode 100644 index 0000000..472b389 --- /dev/null +++ b/backoffice/img/icons/newspaper_white.svg @@ -0,0 +1,3 @@ + + + diff --git a/backoffice/img/icons/numberlist.svg b/backoffice/img/icons/numberlist.svg new file mode 100644 index 0000000..33ac90c --- /dev/null +++ b/backoffice/img/icons/numberlist.svg @@ -0,0 +1,3 @@ + + + diff --git a/backoffice/img/icons/numberlist_white.svg b/backoffice/img/icons/numberlist_white.svg new file mode 100644 index 0000000..e98d4aa --- /dev/null +++ b/backoffice/img/icons/numberlist_white.svg @@ -0,0 +1,3 @@ + + + diff --git a/backoffice/img/icons/package.svg b/backoffice/img/icons/package.svg new file mode 100644 index 0000000..0b6a94d --- /dev/null +++ b/backoffice/img/icons/package.svg @@ -0,0 +1,3 @@ + + + diff --git a/backoffice/img/icons/package_white.svg b/backoffice/img/icons/package_white.svg new file mode 100644 index 0000000..9a40a7b --- /dev/null +++ b/backoffice/img/icons/package_white.svg @@ -0,0 +1,3 @@ + + + diff --git a/backoffice/img/icons/pdf.svg b/backoffice/img/icons/pdf.svg new file mode 100644 index 0000000..43a58e1 --- /dev/null +++ b/backoffice/img/icons/pdf.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/backoffice/img/icons/pdf_white.svg b/backoffice/img/icons/pdf_white.svg new file mode 100644 index 0000000..94dbd95 --- /dev/null +++ b/backoffice/img/icons/pdf_white.svg @@ -0,0 +1,5 @@ + + + + \ No newline at end of file diff --git a/backoffice/img/icons/pdfexport.svg b/backoffice/img/icons/pdfexport.svg new file mode 100644 index 0000000..49169f9 --- /dev/null +++ b/backoffice/img/icons/pdfexport.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/backoffice/img/icons/pdfexport_white.svg b/backoffice/img/icons/pdfexport_white.svg new file mode 100644 index 0000000..49169f9 --- /dev/null +++ b/backoffice/img/icons/pdfexport_white.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/backoffice/img/icons/pictures.svg b/backoffice/img/icons/pictures.svg new file mode 100644 index 0000000..97bb690 --- /dev/null +++ b/backoffice/img/icons/pictures.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/backoffice/img/icons/pictures_white.svg b/backoffice/img/icons/pictures_white.svg new file mode 100644 index 0000000..9142d7f --- /dev/null +++ b/backoffice/img/icons/pictures_white.svg @@ -0,0 +1,5 @@ + + + + \ No newline at end of file diff --git a/backoffice/img/icons/plus.svg b/backoffice/img/icons/plus.svg new file mode 100644 index 0000000..08e85b5 --- /dev/null +++ b/backoffice/img/icons/plus.svg @@ -0,0 +1,3 @@ + + + diff --git a/backoffice/img/icons/plus_white.svg b/backoffice/img/icons/plus_white.svg new file mode 100644 index 0000000..22714fe --- /dev/null +++ b/backoffice/img/icons/plus_white.svg @@ -0,0 +1,3 @@ + + + diff --git a/backoffice/img/icons/projects.svg b/backoffice/img/icons/projects.svg new file mode 100644 index 0000000..1e8e1e7 --- /dev/null +++ b/backoffice/img/icons/projects.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/backoffice/img/icons/projects_white.svg b/backoffice/img/icons/projects_white.svg new file mode 100644 index 0000000..ddbd36c --- /dev/null +++ b/backoffice/img/icons/projects_white.svg @@ -0,0 +1,5 @@ + + + + \ No newline at end of file diff --git a/backoffice/img/icons/remove.svg b/backoffice/img/icons/remove.svg new file mode 100644 index 0000000..e459477 --- /dev/null +++ b/backoffice/img/icons/remove.svg @@ -0,0 +1,3 @@ + + + diff --git a/backoffice/img/icons/remove_white.svg b/backoffice/img/icons/remove_white.svg new file mode 100644 index 0000000..77e856e --- /dev/null +++ b/backoffice/img/icons/remove_white.svg @@ -0,0 +1,3 @@ + + + diff --git a/backoffice/img/icons/squares.svg b/backoffice/img/icons/squares.svg new file mode 100644 index 0000000..8e084a0 --- /dev/null +++ b/backoffice/img/icons/squares.svg @@ -0,0 +1,3 @@ + + + diff --git a/backoffice/img/icons/squares_white.svg b/backoffice/img/icons/squares_white.svg new file mode 100644 index 0000000..489f802 --- /dev/null +++ b/backoffice/img/icons/squares_white.svg @@ -0,0 +1,3 @@ + + + diff --git a/backoffice/img/icons/target.svg b/backoffice/img/icons/target.svg new file mode 100644 index 0000000..72b5eb0 --- /dev/null +++ b/backoffice/img/icons/target.svg @@ -0,0 +1,3 @@ + + + diff --git a/backoffice/img/icons/target_white.svg b/backoffice/img/icons/target_white.svg new file mode 100644 index 0000000..b02c6c4 --- /dev/null +++ b/backoffice/img/icons/target_white.svg @@ -0,0 +1,3 @@ + + + diff --git a/backoffice/img/icons/upload.svg b/backoffice/img/icons/upload.svg new file mode 100644 index 0000000..20dfeb0 --- /dev/null +++ b/backoffice/img/icons/upload.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/backoffice/img/icons/upload_white.svg b/backoffice/img/icons/upload_white.svg new file mode 100644 index 0000000..367855a --- /dev/null +++ b/backoffice/img/icons/upload_white.svg @@ -0,0 +1,5 @@ + + + + \ No newline at end of file diff --git a/backoffice/img/icons/user.svg b/backoffice/img/icons/user.svg new file mode 100644 index 0000000..37b4e3d --- /dev/null +++ b/backoffice/img/icons/user.svg @@ -0,0 +1,3 @@ + + + diff --git a/backoffice/img/icons/user_white.svg b/backoffice/img/icons/user_white.svg new file mode 100644 index 0000000..78d94ca --- /dev/null +++ b/backoffice/img/icons/user_white.svg @@ -0,0 +1,3 @@ + + + diff --git a/backoffice/img/logo_512.png b/backoffice/img/logo_512.png new file mode 100644 index 0000000..37e2068 Binary files /dev/null and b/backoffice/img/logo_512.png differ diff --git a/backoffice/img/logo_512_xx.png b/backoffice/img/logo_512_xx.png new file mode 100644 index 0000000..b82da90 Binary files /dev/null and b/backoffice/img/logo_512_xx.png differ diff --git a/backoffice/img/no-image-icon.png b/backoffice/img/no-image-icon.png new file mode 100644 index 0000000..1849ae7 Binary files /dev/null and b/backoffice/img/no-image-icon.png differ diff --git a/backoffice/img/no-news-img.png b/backoffice/img/no-news-img.png new file mode 100644 index 0000000..3411fda Binary files /dev/null and b/backoffice/img/no-news-img.png differ diff --git a/backoffice/img/toplogo.png b/backoffice/img/toplogo.png new file mode 100644 index 0000000..37e2068 Binary files /dev/null and b/backoffice/img/toplogo.png differ diff --git a/backoffice/index.cgi b/backoffice/index.cgi new file mode 100755 index 0000000..ecd3994 --- /dev/null +++ b/backoffice/index.cgi @@ -0,0 +1,193 @@ +#!/Users/kilian/perl5/perlbrew/perls/perl-5.24.1/bin/perl + +use strict; +use lib ('api/lib/perl5'); +use lib ('api/lib'); +use File::Basename qw/dirname basename/; +use Template; +# use Template::Constants qw( :debug ); +use CGI; +#use CGI::Carp qw(fatalsToBrowser); +use CGI::Cookie; +use Data::Dumper; +use JSON::PP; + +use dksconfig qw/$sitecfg/; +use session; + +my $skl = "skeleton/index.tt"; +my $cgi = new CGI(); +my $p=(); +my $cookie; +my $vars = $sitecfg; + +$vars->{filepath} = substr($cgi->url({-absolute=>1}),length($vars->{basepath})+1); +$vars->{baseurl} = $cgi->url({-base=>1}).$vars->{basepath}; + +if ($vars->{basepath} eq "/"){ + $vars->{siteurl} = $cgi->url({-base=>1}); +}else { + $vars->{siteurl} = $cgi->url({-base=>1}).dirname($vars->{basepath}); + $vars->{docroot} = $vars->{docroot}.dirname($vars->{basepath}); + #$vars->{sitepath} = dirname($vars->{basepath}); +} + + +if ($vars->{filepath} ne ""){ + $vars->{suffix} = substr($vars->{filepath},rindex($vars->{filepath},'.')); + $vars->{page} = $vars->{filepath}; + $vars->{page} =~ s/html$/tt/; +} +$vars->{abspath} = ""; + +my $sess = (); +my $se = session->new(); +$p->{sid} = $cgi->cookie($vars->{cookiename}); +if ($cgi->request_method() eq "GET"){ + my @params = $cgi->param(); + foreach my $pp (@params){ + $p->{$pp} = $cgi->param($pp); + } + +} + +if ($cgi->request_method() eq "POST"){ + + my @params = $cgi->param(); + foreach my $pp (@params){ + $p->{$pp} = $cgi->param($pp); + } + $vars->{hasposts} = $p; + if (exists($p->{'btnlogin'})){ + my $ret = $se->checklogin($p->{login},$p->{password}); + + if ($ret->{sid} ne ""){ + $p->{sid} = $ret->{sid}; + + $cookie = CGI::Cookie->new(-name=>$vars->{cookiename},-value=>$p->{sid},-httponly => 1); + + }else { + $vars->{message} = $ret->{message}; + $vars->{messagetype} = $ret->{messagetype}; + $vars->{page} = "message.tt"; + } + } + if (exists($p->{'btnregister'})){ + + my $ret = $se->registeruser($p); + + $vars->{message} = $ret->{message}; + $vars->{messagetype} = $ret->{messagetype}; + $vars->{page} = $ret->{page}; + } + if (exists($p->{'btnforgotpassword'})){ + my $ret = $se->passwordforgotten($p->{email}); + $vars->{message} = $ret->{message}; + $vars->{messagetype} = $ret->{messagetype}; + $vars->{page} = "message.tt"; + } + if (exists($p->{'btnvalidateemail'})){ + my $ret = $se->validateaccount($p); + $vars->{message} = $ret->{message}; + $vars->{messagetype} = $ret->{messagetype}; + $vars->{page} = "message.tt"; + } + if (exists($p->{'btnresendcode'})){ + my $ret = $se->resendcode($p->{email}); + $vars->{message} = $ret->{message}; + $vars->{messagetype} = $ret->{messagetype}; + $vars->{page} = "message.tt"; + } + + if (exists($p->{logout})){ + $se->deletesession($p->{sid}); + $p->{sid} = ""; + $cookie = CGI::Cookie->new(-name=>$vars->{cookiename},-value=>"",-httponly => 1); + } + # if (exists($p->{btndeleteprofile})){ + # my $ret = $se->deleteprofile($p->{deleteprofile}); + # $vars->{message} = $ret->{message}; + # $vars->{messagetype} = $ret->{messagetype}; + # $vars->{page} = "message.tt"; + # if (exists($ret->{sid})){ + # $p->{sid} = ""; + # } + # $cookie = CGI::Cookie->new(-name=>$vars->{cookiename},-value=>"",-httponly => 1); + # } +} +# open FILE,">>tmp/sql.log"; +# print FILE "parameter session = ".$p->{sid}."\n"; +# close(FILE); +if ($p->{sid} ne ""){ + $sess = $se->getsession($p->{sid}); +} +# open FILE,">>tmp/sql.log"; +# print FILE "Seesion GOT!\n"; +# print FILE Dumper($sess); +# close(FILE); + + +#$vars->{beforex} = $vars->{page}; +if (!exists($sess->{id}) || (!exists($p->{sid})) || $p->{sid} eq ""){ + $skl = "skeleton/login.tt"; +} +# if ($vars->{page} eq "deleteprofile.tt") { +# $skl = "skeleton/login.tt"; +# } +# my ($appname) = $ENV{REQUEST_URI} =~ /.*\/module\/(\w+)\/.*/; +if ($p->{sid} ne ""){ + $vars->{session} = $sess; +} +#SESSION - End +# #BEGIN - Browser Blocking +# if (($ENV{HTTP_USER_AGENT} !~ /Chrome/) || ($ENV{HTTP_USER_AGENT} =~ /Edge/) || ($ENV{HTTP_USER_AGENT} =~ /Firefox/)){ +# $skl = "skeleton/browser.tt"; +# } +# #END - Browser Blocking +my $ctype = 'text/html'; +if ($vars->{suffix} eq ".js"){ + $ctype= "text/javascript"; +} elsif ($vars->{suffix} eq ".css"){ + $ctype = "text/css"; +} +print $cgi->header(-type=>$ctype, -charset=>"utf-8",-cookie => $cookie); +# print dirname($ENV{"SCRIPT_FILENAME"}); + +my $template = Template->new({INCLUDE_PATH => [dirname($ENV{"SCRIPT_FILENAME"}).'/tmpl']}); +#} + +my @lv = split(/\//,$vars->{filepath}); +my $absnum = scalar(@lv)-1; + +for (my $i=0;$i<$absnum;$i++){ + $vars->{abspath} .= "../"; +} + +# $vars->{page} = $vars->{page}; +if ($vars->{page} =~ /^module/){ + $vars->{module} = basename(dirname($vars->{page})); +} +$vars->{pagename} = basename($vars->{page}); +$vars->{pagename} =~ s/\.tt$//; +# my ($appname) = $ENV{REQUEST_URI} =~ /.*\/apps\/(\w+)\/.*/; +#$vars->{requri} = $ENV{REQUEST_URI}; + +#BEGIN - iFrame - Modules + +if ($skl ne "skeleton/login.tt" && $vars->{page} =~ /^module/){ + $skl = "skeleton/module.tt"; + if ($vars->{page} !~ /\.tt$/) { + $skl = "skeleton/module_file.tt"; + } + $vars->{params}= $p; +} + +#END - iFrame - Modules + +$template->process($skl,$vars) || die "Template process failed: ", $template->error(), "\n"; + +# if ($vars->{page} =~ /\.tt/){ +# print '
'.Dumper($p)."
";
+# } 
+
+
diff --git a/backoffice/js/admin.js b/backoffice/js/admin.js
new file mode 100644
index 0000000..3cc2511
--- /dev/null
+++ b/backoffice/js/admin.js
@@ -0,0 +1,106 @@
+var choice = {"company":{"schemata":null}};
+
+var admin = {
+    loadpage: function(modulepage, modulename) {
+        //console.log(modulename);
+        //console.log("Load module:" + modulepage);
+        if (modulename) {
+            document.getElementById("modulename").innerHTML = modulename;
+        }
+        document.getElementById("moduleframe").setAttribute('src', modulepage);
+    },
+    sidebarclick: function(modulepage, modulename) {
+        admin.loadpage(modulepage, modulename);
+    },
+    getcurrentSchemata: function(){
+      //console.log("selected schemata: " + document.getElementById("schemata").value);
+      return document.getElementById("schemata").value;
+    },
+    getAllSchemata: function(){
+      var x = choice["company"]["schemata"];
+      
+      console.log(x.getValue(true));//.getValue(true));
+      return x.getValue(true);
+    },
+    logout: function() {
+        req.reqdata("POST", location.href, { "logout": "1" }, admin.reloadpage);
+
+    },
+    reloadpage(page) {
+        location.href = location.href;
+
+    }
+}
+
+function reload_page() {
+    location.href = location.href;
+}
+
+// function closeSidebar(){
+//   document.getElementById("sidebar").style.display = "none";
+//   document.getElementById("main").style.margin = "0 0 0 0";
+//   document.getElementById("modulename").style.setProperty("margin-left","0px");
+// }
+
+// function openSidebar(){
+//   document.getElementById("sidebar").style.display = "block";
+//   document.getElementById("main").style.setProperty("margin-left","210px");
+//   document.getElementById("modulename").style.setProperty("margin-left","150px");
+// }
+
+var mySidebar = document.getElementById("mySidebar");
+
+// Get the DIV with overlay effect
+var overlayBg = document.getElementById("myOverlay");
+
+// Toggle between showing and hiding the sidebar, and add overlay effect
+function w3_open() {
+    if (mySidebar.style.display === 'block') {
+        mySidebar.style.display = 'none';
+        overlayBg.style.display = "none";
+    } else {
+        mySidebar.style.display = 'block';
+        overlayBg.style.display = "block";
+    }
+}
+
+// Close the sidebar with the close button
+function w3_close() {
+    mySidebar.style.display = "none";
+    overlayBg.style.display = "none";
+}
+
+document.addEventListener("DOMContentLoaded", function() {
+  
+  choice["company"]["schemata"] = new Choices('#schemata',{
+    searchEnabled: false,
+    itemSelectText: 'x',
+    removeItemButton: false,
+    choices : []
+  });
+  getschemata();
+});
+
+function getschemata(){
+  req.reqdata("POST","db.cgi",{"get":"companylist"},fillschematalist);
+}
+
+function fillschematalist(data){
+  console.log(data);
+  fillselectlist(choice["company"]["schemata"],data.sqldata,'schemata','company');
+  
+  return false;
+}
+
+function fillselectlist(obj,data,vidcol,vvalcol){
+  var sellist = [];
+  obj.clearStore();
+  if (data){
+    for (var i in data){
+      sellist.push({value:data[i][vidcol],label:data[i][vvalcol]});
+    }
+  }
+  obj.setChoices(sellist, 'value', 'label', true);
+  obj.setChoiceByValue(sellist[0].value);
+  return false;
+}
\ No newline at end of file
diff --git a/backoffice/js/formsave.js b/backoffice/js/formsave.js
new file mode 100644
index 0000000..8611d49
--- /dev/null
+++ b/backoffice/js/formsave.js
@@ -0,0 +1,286 @@
+function saveform(frmid,aftercallback){
+  var flds=getformcontent(frmid,null);
+  flds["fn"] ="saveform";
+  flds["schemata"]=parent.admin.getcurrentSchemata();
+  console.log(flds);
+  if (aftercallback){
+    req.reqdata("POST","index.cgi",flds,aftercallback);
+    formsaved({});
+  }
+  else {
+    req.reqdata("POST","index.cgi",flds,formsaved);
+  }
+  return false;
+}
+
+function formsaved(data){
+  var sb = document.getElementById("snackbar");
+  sb.className="show w3-green";
+  sb.innerHTML = 'Les données ont été sauvegardées!';
+  setTimeout(function(){ sb.className = sb.className.replace("show w3-green", ""); }, 3000);
+  return false;
+}
+
+function showsnackbar(xclass,xmessage){
+  var sb = document.getElementById("snackbar");
+  sb.className="show " + xclass;
+  sb.innerHTML = xmessage;
+  setTimeout(function(){ sb.className = sb.className.replace(sb.className, ""); }, 3000);
+  return false;
+}
+
+function getformcontent(frmid,dataflds){
+  var frm = document.getElementById("frm_" + frmid);
+  var flds = [];
+  if (dataflds){
+    flds = dataflds;
+  } 
+ 
+  for (var i = 0; i < frm.elements.length; i++) {
+    var field = frm.elements[i];
+    //console.log("field:" + field.id + " Name:" + field.getAttribute("name"));
+    if (field.tagName == "INPUT" || field.tagName == "SELECT" || field.tagName == "TEXTAREA"){
+      if (field.classList.contains("tagedit")){
+        var fvalue=field.value.trim();
+        var ndata = null;
+        if (fvalue != ""){
+          ndata =  fvalue.split(",");  
+        }
+       
+        flds[field.getAttribute("name")] = ndata;
+      }else if (field.tagName == "TEXTAREA" ){
+        if (field.classList.contains("richeditarea")){
+          flds[field.getAttribute("name")] = tinymce.get(field.id).getContent();
+        } else {
+          flds[field.getAttribute("name")] = field.innerHTML;
+        }
+        
+      }else if (field.type == "checkbox" ){
+        if (field.checked){
+          flds[field.getAttribute("name")] = "1";
+        } else {
+          flds[field.getAttribute("name")] = "";
+        }
+        
+      }
+      else {
+        if (field.tagName == "SELECT" && field.multiple == true){
+          var opts = field.selectedOptions;
+          var vals = [];
+          for (var o in opts){
+            if (opts[o].value){
+              vals.push(opts[o].value);
+            }
+          }
+          if (vals.length > 0) {
+            flds[field.getAttribute("name")] = vals;
+          } else {
+            flds[field.getAttribute("name")] = "";
+          }
+          
+        } else {
+          flds[field.getAttribute("name")] = field.value;
+        }
+        
+      }
+      
+    }
+  }
+  return flds;
+}
+
+function cleanform(frmname){
+  //console.log("Clean Form: " + frmname);
+  var frm = document.getElementById("frm_" + frmname);
+  
+  for (var f in frm){
+    //console.log(frm[f].id);
+    if (frm[f] && frm[f].id){
+    if (frm[f].tagName == 'INPUT'){
+      //console.log("is INPUT" + frm[f].id + " type:" + frm[f].type + " class:" + frm[f].classList);
+      if (frm[f].type == "checkbox"){
+        frm[f].checked = false;
+      } else if (frm[f].classList.contains("datefield")){
+          if (frm[f]._flatpickr){ frm[f]._flatpickr.clear(); }
+      } else if (frm[f].classList.contains("choices__input")){
+        if (choice[frmname][frm[f].id]){
+          choice[frmname][frm[f].id].removeActiveItems();
+        }
+      } else {
+        frm[f].value = "";
+      }
+    }
+    if (frm[f].tagName == 'SELECT'){
+      //console.log("is INPUT" + frm[f].id + " multiple:" + frm[f].multiple + " class:" + frm[f].classList);
+      if (frm[f].multiple == true){
+        if (frm[f].classList.contains("choices__input")){
+          choice[frmname][frm[f].id].removeActiveItems();
+        }
+      } else {
+        frm[f].value = "";
+      }
+      
+    }
+    if (frm[f].tagName == 'TEXTAREA'){
+      //console.log("is INPUT" + frm[f].id +  " class:" + frm[f].classList);
+      if (frm[f].classList.contains("richeditarea")){
+        tinymce.get(frm[f].id).setContent("");
+      } else {
+        frm[f].innerHTML = "";
+      } 
+    }
+  }
+  }
+  return false;
+}
+
+function cleanform2(frmname,choices){
+  //console.log("Clean Form: " + frmname);
+  var frm = document.getElementById("frm_" + frmname);
+  
+  for (var f in frm){
+    //console.log(frm[f].id);
+    if (frm[f] && frm[f].id){
+    if (frm[f].tagName == 'INPUT'){
+      //console.log("is INPUT" + frm[f].id + " type:" + frm[f].type + " class:" + frm[f].classList);
+      if (frm[f].type == "checkbox"){
+        frm[f].checked = false;
+      } else if (frm[f].classList.contains("datefield")){
+          if (frm[f]._flatpickr){ frm[f]._flatpickr.clear(); }
+      } else if (frm[f].classList.contains("choices__input")){
+        if (choices[frm[f].id]){
+          choices[frm[f].id].removeActiveItems();
+        }
+      } else {
+        frm[f].value = "";
+      }
+    }
+    if (frm[f].tagName == 'SELECT'){
+      //console.log("is INPUT" + frm[f].id + " multiple:" + frm[f].multiple + " class:" + frm[f].classList);
+      if (frm[f].multiple == true){
+        if (frm[f].classList.contains("choices__input")){
+          choices[frm[f].id].removeActiveItems();
+        }
+      } else {
+        frm[f].value = "";
+      }
+      
+    }
+    if (frm[f].tagName == 'TEXTAREA'){
+      //console.log("is INPUT" + frm[f].id +  " class:" + frm[f].classList);
+      if (frm[f].classList.contains("richeditarea")){
+        tinymce.get(frm[f].id).setContent("");
+      } else {
+        frm[f].innerHTML = "";
+      } 
+    }
+  }
+  }
+  return false;
+}
+
+function fillformbydataclass(dataclass,data,readonly = false){
+  //console.log(data);
+  var frm = document.querySelectorAll('.data_'+ dataclass);
+  if (data){
+    for (var f in frm){
+      //console.log(frm[f]);
+      if (data[frm[f].id]){
+        //console.log(frm[f].id + " => " + data[frm[f].id]);
+        if (readonly){ frm[f].readonly = true;}
+        if (frm[f].tagName == 'INPUT'){
+          if (frm[f].type == "checkbox"){
+            if (data[frm[f].id] == "1"){
+              frm[f].checked = true;
+            } else {
+              frm[f].checked = false;
+            }
+          } else if (frm[f].classList.contains("datefield")){ 
+            frm[f]._flatpickr.setDate(data[frm[f].id]);
+          } else if (frm[f].classList.contains("timefield")){ 
+            frm[f]._flatpickr.setDate(data[frm[f].id]);
+          }else if (frm[f].classList.contains("choices__input")){  
+            if ((data[frm[f].id] != null) && (data[frm[f].id] != '[""]')){
+              choice[dataclass][frm[f].id].setValue(JSON.parse(data[frm[f].id])); 
+            }
+          } else {
+            frm[f].value=data[frm[f].id];
+          }
+        }
+        if (frm[f].tagName == 'SELECT'){
+          if (frm[f].classList.contains("choices__input")){
+            if (frm[f].multiple == true){
+              //console.log(data[frm[f].id]);
+              choice[dataclass][frm[f].id].setChoiceByValue(JSON.parse(data[frm[f].id]));
+            }else {
+              choice[dataclass][frm[f].id].setChoiceByValue(data[frm[f].id]);
+            }
+          } else {
+            frm[f].value=data[frm[f].id];
+          }
+          
+        }
+      }
+      
+    }
+  }
+}
+
+function fillformbydataclass2(dataclass,choices,data){
+  //console.log(data);
+  var frm = document.querySelectorAll('.data_'+ dataclass);
+  if (data){
+    for (var f in frm){
+      //console.log(frm[f]);
+      if (data[frm[f].id]){
+        //console.log(frm[f].id + " => " + data[frm[f].id]);
+        
+        if (frm[f].tagName == 'INPUT'){
+          if (frm[f].type == "checkbox"){
+            if (data[frm[f].id] == "1"){
+              frm[f].checked = true;
+            } else {
+              frm[f].checked = false;
+            }
+          } else if (frm[f].classList.contains("datefield")){ 
+            frm[f]._flatpickr.setDate(data[frm[f].id]);
+          } else if (frm[f].classList.contains("timefield")){ 
+            frm[f]._flatpickr.setDate(data[frm[f].id]);
+          }else if (frm[f].classList.contains("choices__input")){  
+            if ((data[frm[f].id] != null) && (data[frm[f].id] != '[""]')){
+              choices[frm[f].id].setValue(JSON.parse(data[frm[f].id])); 
+            }
+          } else {
+            frm[f].value=data[frm[f].id];
+          }
+        }
+        if (frm[f].tagName == 'SELECT'){
+          if (frm[f].classList.contains("choices__input")){
+            if (frm[f].multiple == true){
+              //console.log(data[frm[f].id]);
+              choices[frm[f].id].setChoiceByValue(JSON.parse(data[frm[f].id]));
+            }else {
+              choices[frm[f].id].setChoiceByValue(data[frm[f].id]);
+            }
+          } else {
+            frm[f].value=data[frm[f].id];
+          }
+          
+        }
+      }
+      
+    }
+  }
+}
+
+function fillselectlist(obj,data,vidcol,vvalcol){
+  var sellist = [];
+  obj.clearStore();
+  if (data){
+    for (var i in data){
+      sellist.push({value:data[i][vidcol],label:data[i][vvalcol]});
+    }
+  }
+  obj.setChoices(sellist, 'value', 'label', true);
+  return false;
+}
\ No newline at end of file
diff --git a/backoffice/js/module_global.js b/backoffice/js/module_global.js
new file mode 100644
index 0000000..8cc297b
--- /dev/null
+++ b/backoffice/js/module_global.js
@@ -0,0 +1,92 @@
+document.addEventListener("DOMContentLoaded", function() {
+  //console.log( "Iframe "+ location.pathname.substring(location.pathname.lastIndexOf("/")) +" ready!" );
+  initpage();
+});
+
+var module = {
+  viewpanel: function(pnlname){
+    console.log(pnlname);
+    var panels = document.getElementsByClassName("panel");
+    var toolbars = document.getElementsByClassName("toolbar");
+    currentview = pnlname;
+    for (var p=0;p tbody > tr:first-child").children();
+//   //   var colnum = cols.length -1;
+//   //   console.log("childnum:" + colnum);
+//   //   for (var i=1;i<=colnum;i++){
+//   //     wx = $("#tbl_"+tblmodule+" > tbody > tr:first-child > td:nth-child("+ i +")").width();
+//   //     // wx = wx +3;
+//   //     $("#tbl_"+tblmodule+"_head > thead > tr > th:nth-child("+ i +")").width(wx);
+//   //   }
+// }
+
+// function sectionload(sectionid,callback){
+//   var sec = document.querySelectorAll('section');
+//   for (var i in sec){
+//     sec[i].style.display = 'none';
+//   }
+//   if (callback){
+//     callback;
+//   }
+//   document.getElementById(sectionid).style.display = 'block';
+// }
+
+
+// function emptyform(id){
+//   // $("#" + id + "> input,select,textarea").each(
+//     // function(){
+//       // console.log("Set Empty Value On" + $(this).id);
+//     // }
+
+//   // );
+// }
\ No newline at end of file
diff --git a/backoffice/js/request.js b/backoffice/js/request.js
new file mode 100644
index 0000000..d63cf1d
--- /dev/null
+++ b/backoffice/js/request.js
@@ -0,0 +1,119 @@
+var api = location.origin + location.pathname.substring(0,location.pathname.lastIndexOf('/')) + '/api/';
+if (location.pathname.indexOf('module') > 0){
+  api = location.origin + location.pathname.substring(0, location.pathname.indexOf('module')) + 'api/';
+}
+// console.log(api);
+var req = {
+    multipartform: function(url,frmdata,callback=null){
+    var ret = null;
+    var rdata = null;
+    var async = false;
+    if (callback){
+      async=true;
+    }
+    
+    var request = new XMLHttpRequest();
+    
+    //console.log(frmdata);
+    var sendurl = api + url;
+    //console.log("sending URL: " + "POST" + " => " +sendurl);
+    request.open("POST", sendurl, true);
+    request.onload = function(){
+      if (request.status >= 200 && request.status <= 400){
+        //console.log("Status returned: " + request.status + "resp:" + request.getResponseHeader("Content-Type"));
+        if (request.getResponseHeader("Content-Type").indexOf('application/json') == 0){
+          var xparse = JSON.parse(request.responseText);
+          ret = xparse.result;
+          //console.log(ret);
+        }
+        else {
+          ret = request.responseText;
+        }
+        if (async){
+          callback(ret);
+        }
+      } else {
+        alert("ServerERROR:" + request.status + "\n" + request.responseText);
+      }
+    };
+    request.onerror = function(){
+      alert("Connection ERROR!\n" + url);
+    };
+  
+      request.setRequestHeader('Content-Type','multipart/form-data; charset=UTF-8');
+      request.send(frmdata);
+    return ret;
+  },
+  reqdata: function(method,url,data,callback=null){
+    
+    var ret = null;
+    var rdata = null;
+    var async = false;
+    if (callback){
+      async=true;
+    }
+    
+    var request = new XMLHttpRequest();
+    if (typeof data == 'object'){
+      var xdata = [];
+      for (var i in data){
+         var value = '';
+         if (typeof(data[i]) == 'object'){
+           value = encodeURIComponent(JSON.stringify(data[i]));
+         } else {
+           value = encodeURIComponent(data[i]);
+         }
+         xdata.push(i + "=" + value);
+      }
+      rdata = xdata.join("&");
+    }else {
+      rdata = data;
+    }
+    //console.log("Data to send: " + decodeURIComponent(rdata));
+    var sendurl = api + url;
+    if (method.toUpperCase() == 'GET'){
+      sendurl = sendurl + '?' + rdata;
+    }
+    //console.log("sending URL: " + method + " => " +sendurl + '?' + rdata);
+    request.open(method.toUpperCase(), sendurl, true);
+    request.onload = function(){
+      if (request.status >= 200 && request.status <= 400){
+         console.log("Status returned: " + request.status + "resp:" + request.getResponseHeader("Content-Type"));
+        if (request.getResponseHeader("Content-Type").indexOf('application/json') == 0){
+          if (request.responseText){
+            console.log(request.responseText);
+            var xparse = JSON.parse(request.responseText);
+            ret = xparse.result;
+          } else {
+            ret = null;  
+          }
+          
+        }else {
+          ret = request.responseText;
+        }
+        callback(ret);
+      } else {
+        //console.log("ServerERROR: " + request.status + "\n" + request.responseText);
+        alert("ServerERROR:" + request.status + "\n" + request.responseText);
+      }
+    };
+    request.onerror = function(){
+      //console.log("ERROR: connection ERROR\n" + url);
+      alert("Connection ERROR!\n" + url);
+    };
+    if (method.toUpperCase() == 'POST'){
+      request.setRequestHeader('Content-Type','application/x-www-form-urlencoded; charset=UTF-8');
+      request.send(rdata);
+    } else {
+      //request.withCredentials = true;
+      request.send();
+    }
+    return ret;
+  },
+  asyncNoEvent: function(data){
+    console.log("query done");
+    console.log(data);
+    console.log("done");
+  }
+  
+}
\ No newline at end of file
diff --git a/backoffice/tmp/sql.log b/backoffice/tmp/sql.log
new file mode 100644
index 0000000..e69de29
diff --git a/backoffice/tmpl/block/cgu.tt b/backoffice/tmpl/block/cgu.tt
new file mode 100644
index 0000000..51564c1
--- /dev/null
+++ b/backoffice/tmpl/block/cgu.tt
@@ -0,0 +1,216 @@
+
+

+1 : Objet

+

+Les présentes « conditions générales d'utilisation » +ont pour objet l'encadrement juridique des modalités de mise à +disposition des services du site solana-architecture.lu +et leur utilisation par « l'Utilisateur ».

+

+Les conditions générales d'utilisation doivent être acceptées par +tout Utilisateur souhaitant accéder au site. Elles constituent le +contrat entre le site et l'Utilisateur. L'accès au site par +l'Utilisateur signifie son acceptation des présentes conditions +générales d'utilisation.

+

+ En cas de non-acceptation des conditions générales d'utilisation + stipulées dans le présent contrat, l'Utilisateur se doit de + renoncer à l'accès des services proposés par le site.

+

Solana Architecture s.à r.l. se réserve le droit de modifier unilatéralement et + à tout moment le contenu des présentes conditions générales + d'utilisation.

+

+2 : Mentions légales

+

+L'édition du site solana-architecture.lu est +assurée par l'entreprise Solana Architecture s.à r.l. dont le +siège social est situé à 61, rue des Trévires - L- Luxembourg-Bonnevoie.

+

+Responsable de la publication Web est Martin Solana (Gérant).

+ + +

3 : +Définitions

+

+La présente clause a pour objet de définir les différents termes +essentiels du contrat :

+
  • + Utilisateur : ce terme désigne toute personne qui utilise le + site ou l'un des services proposés par le site.

    +
  • Contenu + utilisateur : ce sont les données transmises par l'Utilisateur + au sein du site.

    +
  • Membre : + l'Utilisateur qui est employé d'une entreprise qui aimerais transferer des soumissions proposé par Solana Architecture s.à r.l. et qui peut s'identifié au site.

    +
  • Identifiant + et mot de passe : c'est l'ensemble des informations nécessaires + à l'identification d'un Utilisateur sur le site. L'identifiant et + le mot de passe permettent à l'Utilisateur d'accéder à des + services réservés aux membres du site. Le mot de passe est + confidentiel.

    +

4 : +accès aux services

+

+Le site permet à l'Utilisateur un accès gratuit aux services +suivants :

+
  • + Modifier ses données personnelles est les données du club;

    +
  • Transférer et télécharger les documents nécessaires pour faire des soumissions;

    +
  • consulter les information et documents utiles et nécessaires pour faire des soumissions;

    +

+Le site est accessible gratuitement en tout lieu à tout Utilisateur +ayant un accès à Internet. Tous les frais supportés par +l'Utilisateur pour accéder au service (matériel informatique, +logiciels, connexion Internet, etc.) sont à sa charge.

+

+Selon le cas :

+

+L'Utilisateur non membre n'a pas accès aux services réservés aux +membres. Pour cela, il doit s'identifier à l'aide de son identifiant +et de son mot de passe.

+ +

+Le site met en œuvre tous les moyens mis à sa disposition pour +assurer un accès de qualité à ses services. L'obligation étant de +moyens, le site ne s'engage pas à atteindre ce résultat.

+

+Tout événement dû à un cas de force majeure ayant pour +conséquence un dysfonctionnement du réseau ou du serveur n'engage +pas la responsabilité de solana-architecture.lu.

+

+L'accès aux services du site peut à tout moment faire l'objet d'une +interruption, d'une suspension, d'une modification sans préavis pour +une maintenance ou pour tout autre cas. L'Utilisateur s'oblige à ne +réclamer aucune indemnisation suite à l'interruption, à la +suspension ou à la modification du présent contrat.

+

+L'Utilisateur a la possibilité de contacter le site par messagerie +électronique à l'adresse info [ at ] solana-architecture.lu. +

+

5 : +Propriété intellectuelle

+

+Les marques, logos, signes et tout autre contenu du site font l'objet +d'une protection par le Code de la propriété intellectuelle et plus +particulièrement par le droit d'auteur.

+

+L'Utilisateur sollicite l'autorisation préalable du site pour toute +reproduction, publication, copie des différents contenus.

+

+L'Utilisateur s'engage à une utilisation des contenus du site dans +un cadre strictement privé. Une utilisation des contenus à des fins +commerciales est strictement interdite.

+

+Tout contenu mis en ligne par l'Utilisateur est de sa seule +responsabilité. L'Utilisateur s'engage à ne pas mettre en ligne de +contenus pouvant porter atteinte aux intérêts de tierces personnes. +Tout recours en justice engagé par un tiers lésé contre le site +sera pris en charge par l'Utilisateur. +

+

+Le contenu de l'Utilisateur peut être à tout moment et pour +n'importe quelle raison supprimé ou modifié par le site. +L'Utilisateur ne reçoit aucune justification et notification +préalablement à la suppression ou à la modification du contenu +Utilisateur.

+

6 : +Données personnelles

+

+Les informations demandées à l'inscription au site sont +nécessaires et obligatoires pour la création du compte de +l'Utilisateur. En particulier, l'adresse électronique pourra être +utilisée par le site pour l'administration, la gestion et +l'animation du service.

+

+Le site assure à l'Utilisateur une collecte et un traitement +d'informations personnelles dans le respect de la vie privée +conformément à la loi européen des protection de données relative à +l'informatique, aux fichiers et aux libertés.

+

+L'Utilisateur dispose d'un droit d'accès, de rectification, de +suppression et d'opposition de ses données personnelles. +L'Utilisateur exerce ce droit via :

+
  • + Formulaire mis à disposition;

    + +
+

7 : +Responsabilité et force majeure

+

+Les sources des informations diffusées sur le site sont réputées +fiables. Toutefois, le site se réserve la faculté d'une +non-garantie de la fiabilité des sources. Les informations données +sur le site le sont à titre purement informatif. Ainsi, +l'Utilisateur assume seul l'entière responsabilité de l'utilisation +des informations et contenus du présent site.

+

+L'Utilisateur s'assure de garder son mot de passe secret. Toute +divulgation du mot de passe, quelle que soit sa forme, est interdite.

+

+L'Utilisateur assume les risques liés à l'utilisation de son +identifiant et mot de passe. Le site décline toute responsabilité.

+

+Tout usage du service par l'Utilisateur ayant directement ou +indirectement pour conséquence des dommages doit faire l'objet d'une +indemnisation au profit du site.

+

+Une garantie optimale de la sécurité et de la confidentialité des +données transmises n'est pas assurée par le site. Toutefois, le +site s'engage à mettre en œuvre tous les moyens nécessaires afin +de garantir au mieux la sécurité et la confidentialité des +données.

+

+La responsabilité du site ne peut être engagée en cas de force +majeure ou du fait imprévisible et insurmontable d'un tiers.

+

8 : +Liens hypertextes

+

+De nombreux liens hypertextes sortants sont présents sur le site, +cependant les pages web où mènent ces liens n'engagent en rien la +responsabilité de solana-architecture.lu qui n'a +pas le contrôle de ces liens.

+

+L'Utilisateur s'interdit donc à engager la responsabilité du site +concernant le contenu et les ressources relatives à ces liens +hypertextes sortants.

+

9 : +Évolution du contrat

+

+Le site se réserve à tout moment le droit de modifier les clauses +stipulées dans le présent contrat.

+

10 : +Durée

+

+La durée du présent contrat est indéterminée. Le contrat produit +ses effets à l'égard de l'Utilisateur à compter de l'utilisation +du service.

+

11 : +Droit applicable et juridiction compétente

+

+La législation luxembourgeoise s'applique au présent contrat. En cas +d'absence de résolution amiable d'un litige né entre les parties, +seuls les tribunaux luxembourgeoises +sont compétents.

+ +

12 : +Publication par l'Utilisateur

+

+Le site permet aux membres de télécharger des fichiers.

+

+Dans ses publications, le membre s'engage à respecter les règles +de la Netiquette et les règles de droit en vigueur.

+

+Le site exerce une modération sur les publications et se réserve le droit de +refuser leur mise en ligne, sans avoir à s'en justifier auprès du +membre.

+

+Le membre reste titulaire de l'intégralité de ses droits de +propriété intellectuelle. Mais en publiant une publication sur le +site, il cède à l' entreprise SOlana Architecture s.à r.l. le droit non exclusif et +gratuit de représenter, reproduire, adapter, modifier, diffuser et +distribuer sa publication, directement ou par un tiers autorisé, +dans le monde entier, sur tout support (numérique ou physique), pour +la durée de la propriété intellectuelle. Le Membre cède notamment +le droit d'utiliser sa publication sur internet et sur les réseaux +

+ \ No newline at end of file diff --git a/backoffice/tmpl/block/dlgdeleterow.tt b/backoffice/tmpl/block/dlgdeleterow.tt new file mode 100644 index 0000000..903ec61 --- /dev/null +++ b/backoffice/tmpl/block/dlgdeleterow.tt @@ -0,0 +1,62 @@ +
+ +
+
+ × +

Supprimer

+
+
+ êtes vous sûre de vouloir supprimer la rangé sélectionné? + [% fieldhidden("dlgdeltable","delete",'','') %] + [% fieldhidden("dlgdelrowid","delete",'','') %] +
+
+ + +
+
+
+ \ No newline at end of file diff --git a/backoffice/tmpl/block/dlguploadfile.tt b/backoffice/tmpl/block/dlguploadfile.tt new file mode 100644 index 0000000..1126d3e --- /dev/null +++ b/backoffice/tmpl/block/dlguploadfile.tt @@ -0,0 +1,91 @@ +
+ +
+
+ × +

Fichier eroplueden

+
+
+
+ [% fieldhidden("table","upload",'','') %] + [% fieldhidden("row_id","upload","ident",'') %] + [% fieldhidden("filetype","upload",'','') %] + [% fieldfile("file","upload","Fichier auswielen",'','','') %] +
+
+
+ + [% formsavefilebutton('uploadfile','eroplueden','') %] +
+
+
+ \ No newline at end of file diff --git a/backoffice/tmpl/block/head.tt b/backoffice/tmpl/block/head.tt new file mode 100644 index 0000000..bdf7408 --- /dev/null +++ b/backoffice/tmpl/block/head.tt @@ -0,0 +1,29 @@ + + + + + [% sitename %] - [% pagename %] + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/backoffice/tmpl/block/snackbar.tt b/backoffice/tmpl/block/snackbar.tt new file mode 100644 index 0000000..464a162 --- /dev/null +++ b/backoffice/tmpl/block/snackbar.tt @@ -0,0 +1 @@ +
\ No newline at end of file diff --git a/backoffice/tmpl/block/toolbars.tt b/backoffice/tmpl/block/toolbars.tt new file mode 100644 index 0000000..9c0073a --- /dev/null +++ b/backoffice/tmpl/block/toolbars.tt @@ -0,0 +1,9 @@ +[% MACRO tabletoolbar(ident) BLOCK -%] + +
+ + + + +
+[% END -%] \ No newline at end of file diff --git a/backoffice/tmpl/macro/fields.tt b/backoffice/tmpl/macro/fields.tt new file mode 100644 index 0000000..2cdc4d3 --- /dev/null +++ b/backoffice/tmpl/macro/fields.tt @@ -0,0 +1,140 @@ +[% MACRO fieldhidden(column,table,ident,value) BLOCK -%] + +[% END -%] +[% MACRO fieldeditbox(column,table,title,size,state,value,plhold) BLOCK -%] +
+ + 0 %][% state %][% END %]/> + +
+[% END -%] +[% MACRO fieldfile(column,table,title,size,state,value) BLOCK -%] +
+ + 0 %][% state %][% END %]/> + +
+[% END -%] +[% MACRO fieldpasswordbox(column,table,title,size,state,value) BLOCK -%] +
+ + 0 %][% state %][% END %]/> + +
+[% END -%] +[% MACRO fieldtagbox(column,table,title,size,state,value) BLOCK -%] +
+ + 0 %][% state %][% END %]/> + +
+[% END -%] +[% MACRO fieldcheckbox(column,table,title,size,state,value) BLOCK -%] +
+
+ 0 %][% state %][% END %]> + +
+[% END -%] + +[% MACRO fieldemailbox(column,table,title,size,state,value) BLOCK -%] +
+ + 0 %][% state %][% END %]/> +
+[% END -%] + +[% MACRO fieldselectbox(column,table,title,size,state,value,extraclass) BLOCK -%] + [% IF state.length > 0 %] + [% fieldeditbox(column,table,title,size,state,value) %] + [% ELSE %] +
+ + + +
+ [% END %] +[% END -%] +[% MACRO fieldmultiselectbox(column,table,title,size,state,value) BLOCK -%] + [% IF state.length > 0 %] + [% fieldeditbox(column,table,title,size,state,value) %] + [% ELSE %] +
+ + + +
+ [% END %] +[% END -%] +[% MACRO fielddatetimebox(column,table,title,size,state,value) BLOCK -%] +
+ + 0 %][% state %][% END %]]/> + +
+[% END -%] +[% MACRO fielddatebox(column,table,title,size,state,value) BLOCK -%] +
+ + 0 %][% state %][% END %]]/> + +
+[% END -%] +[% MACRO fieldtimebox(column,table,title,size,state,value) BLOCK -%] + [% IF state.length > 0 %] + [% fieldeditbox(column,table,title,size,state,value) %] + [% ELSE %] +
+ +
+
+ 0 %][% state %][% END %]]/> +
+ +
+
+ [% END %] +[% END -%] +[% MACRO fieldtextarea(column,table,title,size,state,height,value) BLOCK -%] +
+ + +
+[% END -%] +[% MACRO fieldrichtextarea(column,table,title,size,state,height,value) BLOCK -%] +
+ + +
+[% END -%] + +[% MACRO formsavebutton(formname,btnname) BLOCK -%] +
+ +
+[% END -%] +[% MACRO formsavetextfilebutton(formname,btnname) BLOCK -%] +
+ +
+[% END -%] +[% MACRO formdlgsavebutton(formname,btnname,clbk) BLOCK -%] + +[% END -%] +[% MACRO formsavefilebutton(formname,btnname,container) BLOCK -%] +[% IF container.length > 0 %] +
+ [% END %] + +[% IF container.length > 0 %] +
+[% END %] +[% END -%] + + diff --git a/backoffice/tmpl/module/companies/index.js b/backoffice/tmpl/module/companies/index.js new file mode 100644 index 0000000..dc07ef2 --- /dev/null +++ b/backoffice/tmpl/module/companies/index.js @@ -0,0 +1,180 @@ +var schemata = "public"; +var currentview = null; +function initpage(){ + //schemata = parent.admin.getcurrentSchemata(); + console.log("Current Schema:" + schemata); + companies.inittable(); + module.viewpanel("tbl_companies"); + //call("reportperiod","inittable"); +// flatpickr(".timefield",{ +// //altInput: true, +// //altFormat: "H:i", +// dateFormat: "H:i", +// //allowInput: true, +// defaultHour:'', +// defaultMinute:'', +// enableTime: true, +// noCalendar: true, +// time_24hr: true, +// "locale": "fr", +// }); +} + +// var tbl = null; +// [% sid = session.id %] +// [% IF(session.usergroups.search('admin') != 1) %] +// [% qcompany = dksdb.query("select id_company from vw_userlist where id=$sid;") %] +// [% company = qcompany.get_all() %] +// var idcompany = "[% company.0.id_company %]"; +// [% ELSE %] +// var idcompany = null; +// [% END %] +// //var choice = {"submissionaccess":{"projects":null,"cdm":null,"cdm_requests":null}}; + +// function initpage() { +// [% IF(session.usergroups.search('admin') == 1) %] + +// tbl = new Tabulator("#tbl_companies", { +// headerFilterPlaceholder: "filter...", +// height: "95vh", +// layout: "fitDataFill", +// selectable: 1, +// responsiveLayout: "collapse", +// columns: [{ +// title: "entreprise", +// field: "company", +// headerFilter: "input" +// }, { +// title: "address", +// field: "address", +// headerFilter: "input" +// }, { +// title: "cp", +// field: "zip", +// headerFilter: "input" +// }, { +// title: "ville", +// field: "city", +// headerFilter: "input" +// }, { +// title: "pays", +// field: "country", +// headerFilter: "input" +// }] +// }); +// gettbldata(); + +// [% ELSE %] +// getcompanydata(idcompany); +// [% END %] + + +// } +// [% IF(session.usergroups.search('admin') == 1) %] + + + +// function gettbldata() { +// req.reqdata("POST", "db.cgi", { +// "get": "companylist" +// }, loadtbldata); + +// } + +// function loadtbldata(data) { +// if (data && data.sqldata) { +// tbl.setData(data.sqldata); +// } +// } + +// function edit() { + +// var udata = tbl.getSelectedData(); +// console.log(udata[0]); +// if (udata[0]) { +// var uid = udata[0].id; +// getcompanydata(uid); + +// } + +// } + +// function add() { +// cleanform('companies'); +// viewform(); +// } + +// function remove() { +// var udata = tbl.getSelectedData(); +// if (udata[0]) { +// if (confirm("Êtes vous sûre de supprimer l'entreprise selectionné?")) { +// req.reqdata("POST", "db.cgi", { +// "del": "1", +// "ident_companies_id": udata[0].id +// }, gettbldata); +// } +// } + +// } +// [% END %] + + +// function getcompanydata(id) { +// req.reqdata("POST", "db.cgi", {"get": "companydata","filter": "id=" + id}, fillformcompany); +// } + +// function fillformcompany(data) { +// cleanform('companies'); +// var isreadonly = false; +// [% IF(session.usergroups.search('admin') != 1) %] +// if (data.sqldata[0]["validated"] == 1) { +// isreadonly = true; +// } +// [% END %] +// if (data && data.sqldata) { +// fillformbydataclass('companies', data.sqldata[0], isreadonly); +// } +// if (isreadonly == true) { +// document.getElementById("btnsave_companies").style.display = 'none'; +// } +// } + +// function viewtable() { +// gettbldata(); +// document.getElementById("pnl_table").style.display = 'block'; +// document.getElementById("pnl_company").style.display = 'none'; +// } + +// function viewform(){ +// document.getElementById("pnl_table").style.display = 'none'; +// document.getElementById("pnl_company").style.display = 'block'; +// } + +//[% IF(session.usergroups.search('admin') == 1) %] +// function getprojects(){ +// req.reqdata("POST","db.cgi",{"get":"projectlist"},fillprojectlist); +// } + +// function fillprojectlist(data){ +// console.log("fill projectlist"); +// fillselectlist(choice["submissionaccess"]["projects"],data.sqldata,'id','project'); +// return false; +// } + +//[% END %] + +// function getcdms(){ +// req.reqdata("POST","db.cgi",{"get":"cdmlist"},fillcdmlist); +// } + +// function fillcdmlist(data){ +// console.log("fill cdmlist"); +// fillselectlist(choice["submissionaccess"]["cdm_requests"],data.sqldata,'id','cdm'); +// //var cdmlist = []; +// [% IF (session.usergroups.search('admin') == 1) %] +// fillselectlist(choice["submissionaccess"]["cdm"],data.sqldata,'id','cdm'); +// //choice["submissionaccess"]["cdm"].clearStore(); +// [% END %] + +// return false; +// } \ No newline at end of file diff --git a/backoffice/tmpl/module/companies/index.tt b/backoffice/tmpl/module/companies/index.tt new file mode 100644 index 0000000..f59f8b0 --- /dev/null +++ b/backoffice/tmpl/module/companies/index.tt @@ -0,0 +1,13 @@ +
+
+
+ + + [% INCLUDE "module/$module/widgets/companies/tbar_companies.tt" %] +
+
+ [% INCLUDE "module/$module/widgets/companies/tbl_companies.tt" %] + [% INCLUDE "module/$module/widgets/companies/frm_companies.tt" %] +
+[% INCLUDE block/dlgdeleterow.tt %] + diff --git a/backoffice/tmpl/module/companies/widgets/companies/companies.js b/backoffice/tmpl/module/companies/widgets/companies/companies.js new file mode 100644 index 0000000..d3eb751 --- /dev/null +++ b/backoffice/tmpl/module/companies/widgets/companies/companies.js @@ -0,0 +1,104 @@ +//var tbl_companies = null; +//var weekdays= ["mon","tue","wed","thu","fri","sat","sun"]; +var companies ={ + tbl: null, + current_company: null, + name: "companies", + choices:{}, + initform: function(){ + + }, + inittable: function(){ + companies.initform(); + companies.tbl = new Tabulator("#tbl_" + companies.name, { + headerFilterPlaceholder: "filter...", + height: "94vh", + layout: "fitData", + selectable: 1, + rowContext:function(e, row){ + //e - the click event object + //row - row component + e.preventDefault(); // prevent the browsers default context menu form appearing. + }, + columns: [{ + title: "entreprise", + field: "company", + headerFilter: "input" + }, { + title: "address", + field: "address", + headerFilter: "input" + }, { + title: "cp", + field: "zip", + headerFilter: "input" + }, { + title: "ville", + field: "city", + headerFilter: "input" + }, { + title: "pays", + field: "country", + headerFilter: "input" + }] + }); + companies.gettbldata(); + }, + gettbldata: function(){ + req.reqdata("POST", "db.cgi", { "get": companies.name + "list","schemata":schemata}, companies.loadtbldata); + }, + loadtbldata: function(data){ + if (data && data.sqldata) { companies.tbl.setData(data.sqldata);} + }, + add: function(){ + cleanform2(companies.name,companies.choices); + module.viewpanel('frm_' + companies.name); + }, + edit: function(){ + var udata = companies.tbl.getSelectedData(); + if (udata[0]) { + cleanform2(companies.name,companies.choices); + req.reqdata("POST", "db.cgi", { "get": companies.name + "data","schemata":schemata, "filter":"id='" + udata[0].id + "'"}, companies.fillform); + module.viewpanel('frm_' +companies.name); + } + }, + fillform: function(data){ + console.log("Fill Form 1"); + if (data && data.sqldata){ + console.log("Fill Form 2"); + fillformbydataclass2(companies.name,companies.choices,data.sqldata[0]); + } + }, + remove: function(){ + var udata = companies.tbl.getSelectedData(); + if (udata[0]) { + var uid = udata[0].id; + //TODO: delete Data + module.viewpanel('tbl_' + companies.name); + } + }, + saveform: function(){ + var wpdata = getformcontent(companies.name); + //TODO: save form + console.log(wpdata); + }, + // getcompany: function(ev,id){ + // console.log(id + "=>" + ev.detail.value); + // req.reqdata("POST","db.cgi",{"get":companies.name + "data","schemata":schemata,"filter":"id='" + ev.detail.value + "'"},companies.setcompany); + // }, + // setcompany: function(data){ + // if (data && data.sqldata){ + // console.log(data.sqldata[0]); + // fillformbydataclass("companies",data.sqldata[0],false); + // } + // }, + +} + + + + + + + + diff --git a/backoffice/tmpl/module/companies/widgets/companies/frm_companies.tt b/backoffice/tmpl/module/companies/widgets/companies/frm_companies.tt new file mode 100644 index 0000000..3638f51 --- /dev/null +++ b/backoffice/tmpl/module/companies/widgets/companies/frm_companies.tt @@ -0,0 +1,35 @@ +[% PROCESS macro/fields.tt %] + + diff --git a/backoffice/tmpl/module/companies/widgets/companies/tbar_companies.tt b/backoffice/tmpl/module/companies/widgets/companies/tbar_companies.tt new file mode 100644 index 0000000..038663c --- /dev/null +++ b/backoffice/tmpl/module/companies/widgets/companies/tbar_companies.tt @@ -0,0 +1,7 @@ + + \ No newline at end of file diff --git a/backoffice/tmpl/module/companies/widgets/companies/tbl_companies.tt b/backoffice/tmpl/module/companies/widgets/companies/tbl_companies.tt new file mode 100644 index 0000000..26b61d1 --- /dev/null +++ b/backoffice/tmpl/module/companies/widgets/companies/tbl_companies.tt @@ -0,0 +1,3 @@ +
+
+
\ No newline at end of file diff --git a/backoffice/tmpl/module/dashboard/index.js b/backoffice/tmpl/module/dashboard/index.js new file mode 100644 index 0000000..c75ce58 --- /dev/null +++ b/backoffice/tmpl/module/dashboard/index.js @@ -0,0 +1,7 @@ +var schemata = null; +var allschemata = null; +function initpage(){ + schemata = parent.admin.getcurrentSchemata(); + allschemata = parent.admin.getAllSchemata(); + +} \ No newline at end of file diff --git a/backoffice/tmpl/module/dashboard/index.tt b/backoffice/tmpl/module/dashboard/index.tt new file mode 100644 index 0000000..a0c5377 --- /dev/null +++ b/backoffice/tmpl/module/dashboard/index.tt @@ -0,0 +1,19 @@ +[% appaccess = dksdb.prepare("select replace(ap.icon,'.svg','_white.svg') as icon,ap.app,ap.name,ug.usergroup from useringroups uig join apps ap on (uig.id_group=ap.id_usergroup) join usergroups ug on (uig.id_group=ug.id) where uig.id_user=? and ap.app != 'dashboard' order by ap.sort; ") %] + +
+
+
+
+
+
+ + [% FOREACH ap = appaccess.execute(session.id) %] +
+ +
+ [% END %] +
+
+
diff --git a/backoffice/tmpl/module/planning/index.js b/backoffice/tmpl/module/planning/index.js new file mode 100644 index 0000000..1e2655c --- /dev/null +++ b/backoffice/tmpl/module/planning/index.js @@ -0,0 +1,26 @@ +var schemata = null; +var currentview = null; +function initpage(){ + schemata = parent.admin.getcurrentSchemata(); + console.log("Current Schema:" + schemata); + reportperiod.inittable(); + staffworkplan.inittable(); + module.viewpanel("tbl_reportperiod"); + //call("reportperiod","inittable"); + flatpickr(".timefield",{ + //altInput: true, + //altFormat: "H:i", + dateFormat: "H:i", + //allowInput: true, + defaultHour:'', + defaultMinute:'', + enableTime: true, + noCalendar: true, + time_24hr: true, + "locale": "fr", + }); + +} + + + diff --git a/backoffice/tmpl/module/planning/index.tt b/backoffice/tmpl/module/planning/index.tt new file mode 100644 index 0000000..d797cf0 --- /dev/null +++ b/backoffice/tmpl/module/planning/index.tt @@ -0,0 +1,18 @@ + +
+
+
+ + + [% INCLUDE "module/$module/widgets/reportperiod/tbar_reportperiod.tt" %] + [% INCLUDE "module/$module/widgets/staffworkplan/tbar_staffworkplan.tt" %] +
+
+ [% INCLUDE "module/$module/widgets/reportperiod/tbl_reportperiod.tt" %] + [% INCLUDE "module/$module/widgets/staffworkplan/tbl_staffworkplan.tt" %] + [% INCLUDE "module/$module/widgets/staffworkplan/frm_staffworkplan.tt" %] +
+[% INCLUDE block/dlgdeleterow.tt %] +[% INCLUDE "module/$module/widgets/reportperiod/dlg_reportperiod.tt" %] + + diff --git a/backoffice/tmpl/module/planning/widgets/reportperiod/dlg_reportperiod.tt b/backoffice/tmpl/module/planning/widgets/reportperiod/dlg_reportperiod.tt new file mode 100644 index 0000000..f1f6508 --- /dev/null +++ b/backoffice/tmpl/module/planning/widgets/reportperiod/dlg_reportperiod.tt @@ -0,0 +1,30 @@ +[% PROCESS macro/fields.tt %] +
+ +
+
+ × +

editer/ajouter période

+
+
+
+ [% fieldhidden("id","reportperiod",'ident','') %] + [% fieldeditbox("periodname","reportperiod","Nom",'w3-third','','','') %] + [% fielddatebox("startdate","reportperiod","début",'w3-fifth','','','') %] + [% fielddatebox("enddate","reportperiod","fin",'w3-fifth','','','') %] +
+
+
+ + +
+
+
+ \ No newline at end of file diff --git a/backoffice/tmpl/module/planning/widgets/reportperiod/reportperiod.js b/backoffice/tmpl/module/planning/widgets/reportperiod/reportperiod.js new file mode 100644 index 0000000..8945cf4 --- /dev/null +++ b/backoffice/tmpl/module/planning/widgets/reportperiod/reportperiod.js @@ -0,0 +1,65 @@ +var reportperiod ={ + tbl: null, + name: "reportperiod", + initform: function(){ + + }, + inittable: function(){ + reportperiod.tbl = new Tabulator("#tbl_" + reportperiod.name, { + headerFilterPlaceholder: "filter...", + height: "94vh", + layout: "fitDataFill", + selectable: 1, + rowContext:function(e, row){ + //e - the click event object + //row - row component + //var contextMenu = CtxMenu(); + //contextMenu.addItem("Editer", edit()); + // Add our custom function to the menu + //cntextMenu.addItem("Hello World", ContextMenuExampleFunction); + + // Add a seperator + //contextMenu.addSeperator(); + e.preventDefault(); // prevent the browsers default context menu form appearing. + }, + columns: [{title: "Nom", field: "periodname",headerFilter: "input"}, + { title: "Début",field: "startdate",formatter:"datetime",formatterParams:{inputFormat:"yyyy-mm-dd",outputFormat:"DD.MM.YYYY",invalidPlaceholder:""} }, + { title: "Fin",field: "enddate",formatter:"datetime",formatterParams:{inputFormat:"yyyy-mm-dd",outputFormat:"DD.MM.YYYY",invalidPlaceholder:""} }, + ] + }); + reportperiod.initform(); + reportperiod.gettbldata(); + }, + gettbldata: function(){ + req.reqdata("POST", "db.cgi", { "get": reportperiod.name + "list","schemata":schemata}, reportperiod.loadtbldata); + }, + loadtbldata: function(data){ + if (data && data.sqldata) { reportperiod.tbl.setData(data.sqldata);} + }, + add: function(){ + cleanform(reportperiod.name); + module.viewdialog(reportperiod.name,null); + }, + remove: function(){ + var udata = tbl_reportperiod.getSelectedData(); + if (udata[0]) { + showdeletedlg(reportperiod.name,udata[0].id,null,gettbldata_workplan); + } + }, + edit: function(){ + var udata = reportperiod.tbl.getSelectedData(); + if (udata[0]) { + var uid = udata[0].id; + module.viewpanel('tbl_' + reportperiod.name); + } + }, + viewstaffplan: function(){ + var udata = reportperiod.tbl.getSelectedData(); + if (udata[0]){ + staffworkplan.datefrom = udata[0].startdate; + staffworkplan.dateto = udata[0].enddate; + staffworkplan.gettbldata(); + module.viewpanel('tbl_staffworkplan'); + } + } +} \ No newline at end of file diff --git a/backoffice/tmpl/module/planning/widgets/reportperiod/tbar_reportperiod.tt b/backoffice/tmpl/module/planning/widgets/reportperiod/tbar_reportperiod.tt new file mode 100644 index 0000000..e384dda --- /dev/null +++ b/backoffice/tmpl/module/planning/widgets/reportperiod/tbar_reportperiod.tt @@ -0,0 +1,5 @@ + \ No newline at end of file diff --git a/backoffice/tmpl/module/planning/widgets/reportperiod/tbl_reportperiod.tt b/backoffice/tmpl/module/planning/widgets/reportperiod/tbl_reportperiod.tt new file mode 100644 index 0000000..5375e5d --- /dev/null +++ b/backoffice/tmpl/module/planning/widgets/reportperiod/tbl_reportperiod.tt @@ -0,0 +1,3 @@ +
+
+
\ No newline at end of file diff --git a/backoffice/tmpl/module/planning/widgets/staffworkplan/frm_staffworkplan.tt b/backoffice/tmpl/module/planning/widgets/staffworkplan/frm_staffworkplan.tt new file mode 100644 index 0000000..2ae89c7 --- /dev/null +++ b/backoffice/tmpl/module/planning/widgets/staffworkplan/frm_staffworkplan.tt @@ -0,0 +1,59 @@ +[% PROCESS macro/fields.tt %] +[% wd = [ + {'wd' => 'mon' ,'day' => 'Lundi'}, {'wd' => 'tue','day' => 'Mardi'}, {'wd' => 'wed','day' => 'Mercredi'}, {'wd' => 'thu','day' => 'Jeudi'}, {'wd' => 'fri','day' => 'Vendredi'}, {'wd' => 'sat' ,'day' => 'Samedi'}, {'wd' => 'sun','day' =>'Dimanche'} +] +%] + diff --git a/backoffice/tmpl/module/planning/widgets/staffworkplan/staffworkplan.js b/backoffice/tmpl/module/planning/widgets/staffworkplan/staffworkplan.js new file mode 100644 index 0000000..268c458 --- /dev/null +++ b/backoffice/tmpl/module/planning/widgets/staffworkplan/staffworkplan.js @@ -0,0 +1,243 @@ +//var tbl_staffworkplan = null; +var weekdays= ["mon","tue","wed","thu","fri","sat","sun"]; +var staffworkplan ={ + tbl: null, + current_workplan: null, + datefrom: null, + dateto: null, + name: "staffworkplan", + choices:{"id_staff":null,"weekdays":null,"id_workplan":null,"dayvacancy":null}, + initform: function(){ + flatpickr("#dates",{altInput: true, + altFormat: "d.m.Y", + mode: "multiple", + dateFormat: "Y-m-d", + allowInput: false, + "locale": "fr", + }); + flatpickr("#daterange",{altInput: true, + altFormat: "d.m.Y", + mode: "range", + dateFormat: "Y-m-d", + allowInput: false, + "locale": "fr", + }); + staffworkplan.choices["id_staff"] = new Choices('#id_staff',{ + searchEnabled: false, + itemSelectText: '', + removeItemButton: true, + choices : [] + }); + staffworkplan.choices["id_workplan"] = new Choices('#id_workplan',{ + searchEnabled: false, + itemSelectText: '', + removeItemButton: true, + choices : [] + }); + staffworkplan.choices["dayvacancy"] = new Choices('.dayvacancy',{ + searchEnabled: false, + itemSelectText: '', + //removeItemButton: true, + shouldSort: false, + shouldSortItems: false, + choices : [{"value":"","label":""},{"value":"normal","label":"normal"},{"value":"extra","label":"extraordinaire"},{"value":"ill","label":"maladie"}] + }); + staffworkplan.choices["weekdays"] = new Choices('#weekdays',{ + searchEnabled: false, + itemSelectText: '', + removeItemButton: true, + shouldSort: false, + shouldSortItems: false, + choices : [{"value":"1","label":"Lundi"},{"value":"2","label":"Mardi"},{"value":"3","label":"Mecredi"},{"value":"4","label":"Jeudi"},{"value":"5","label":"Vendredi"},{"value":"6","label":"Samedi"},{"value":"7","label":"Dimanche"}] + }); + staffworkplan.getstaff(); + staffworkplan.getwptemplates(); + staffworkplan.choices["id_workplan"].passedElement.element.addEventListener('change', function(event){staffworkplan.getworkplan(event,this.id)},false); + var tfields = document.getElementsByClassName("timefield"); + for (var i=0;iSemaine", field:"week_timetotal", bottomCalc:staffworkplan.periodtimesum}, + { title: "Lundi", + columns: [ + { title: "heures",field: "dspmontimes",formatter: "html",width:120 }, + { title: "total",field: "mon_timetotal",formatter: "html" }, + ] + }, + { title: "Mardi", + columns: [ + { title: "heures",field: "dsptuetimes",formatter: "html",width:120 }, + { title: "total",field: "tue_timetotal",formatter: "html" }, + ] }, + { title: "Mercredi", + columns: [ + { title: "heures",field: "dspwedtimes",formatter: "html",width:120 }, + { title: "total",field: "wed_timetotal",formatter: "html" }, + ] }, + { title: "Jeudi",columns: [ + { title: "heures",field: "dspthutimes",formatter: "html",width:120 }, + { title: "total",field: "thu_timetotal",formatter: "html" }, + ] }, + { title: "Vendredi",columns: [ + { title: "heures",field: "dspfritimes",formatter: "html",width:120 }, + { title: "total",field: "fri_timetotal",formatter: "html" }, + ] }, + { title: "Samedi",columns: [ + { title: "heures",field: "dspsatimes",formatter: "html",width:120 }, + { title: "total",field: "sat_timetotal",formatter: "html" }, + ] }, + { title: "Dimanche",columns: [ + { title: "heures",field: "dspsuntimes",formatter: "html",width:120 }, + { title: "total",field: "sun_timetotal",formatter: "html" }, + ] } + ] + }); + staffworkplan.gettbldata(); + }, + gettbldata: function(){ + req.reqdata("POST", "db.cgi", { "get": staffworkplan.name + "list","schemata":schemata}, staffworkplan.loadtbldata); + }, + loadtbldata: function(data){ + if (data && data.sqldata) { staffworkplan.tbl.setData(data.sqldata);} + }, + add: function(){ + cleanform2(staffworkplan.name,staffworkplan.choices); + module.viewpanel('frm_' + staffworkplan.name); + }, + edit: function(){ + var udata = staffworkplan.tbl.getSelectedData(); + if (udata[0]) { + var wpdata = ""; + cleanform2(staffworkplan.name,staffworkplan.choices); + req.reqdata("POST", "db.cgi", { "get": staffworkplan.name + "_weekly","schemata":schemata, "filter":"id_staff=" + udata[0].id_staff + " and calweek='" + udata[0].calweek + "' AND calyear='"+ udata[0].calyear +"'"}, staffworkplan.fillform); + module.viewpanel('frm_' +staffworkplan.name); + } + }, + fillform: function(data){ + if (data && data.sqldata){ + fillformbydataclass2(staffworkplan.name,staffworkplan.choices,data.sqldata[0]); + } + }, + remove: function(){ + var udata = staffworkplan.tbl.getSelectedData(); + if (udata[0]) { + var uid = udata[0].id; + module.viewpanel('tbl_' + staffworkplan.name); + } + }, + saveform: function(){ + var wpdata = getformcontent(staffworkplan.name); + console.log(wpdata); + }, + getstaff: function(){ + req.reqdata("POST","db.cgi",{"get":"stafflist","schemata":schemata},staffworkplan.fillstaff); + }, + fillstaff: function(data){ + fillselectlist(staffworkplan.choices["id_staff"],data.sqldata,'id','dspname'); + }, + getwptemplates: function(){ + req.reqdata("POST","db.cgi",{"get":"workplanlist","schemata":schemata},staffworkplan.fillwptemplates); + }, + fillwptemplates: function(data){ + fillselectlist(staffworkplan.choices["id_workplan"],data.sqldata,'id','workplan'); + }, + getworkplan: function(ev,id){ + console.log(id + "=>" + ev.detail.value); + + req.reqdata("POST","db.cgi",{"get":"workplansdata","schemata":schemata,"filter":"id=" + ev.detail.value},staffworkplan.setworkplan); + }, + setworkplan: function(data){ + if (data && data.sqldata){ + console.log(data.sqldata[0]); + var wpdata = data.sqldata[0]; + delete wpdata["id"]; + fillformbydataclass("staffworkplan",data.sqldata[0],false); + for (var w in weekdays){ + //console.log() + staffworkplan.checktime(weekdays[w] + "_timestart1"); + } + } + }, + setvacancytime: function(ev,id){ + console.log("Vacancy: " + id); + wday = id.substring(0,3); + if (ev.detail.value == ""){ + document.getElementById(wday + "_vacancytime")._flatpickr.clear(); + } else if (document.getElementById(wday + "_vacancytime").value == ""){ + document.getElementById(wday + "_vacancytime")._flatpickr.setDate(document.getElementById(wday + "_timetotal").value); + } + }, + checktime: function(id){ + wday=id.substring(0,3); + console.log("timefield: " + wday +"=>" + id + " changed"); + var mt1 = 0; + var mt2 = 0; + var mtp = 0; + if ((document.getElementById(wday + "_timeend1").value != "") && (document.getElementById(wday + "_timestart1").value != "")){ + mt1 = timecalc.TimeToMinutes(document.getElementById(wday + "_timeend1").value)-timecalc.TimeToMinutes(document.getElementById(wday + "_timestart1").value); + } + if ((document.getElementById(wday + "_timeend2").value != "") && (document.getElementById(wday + "_timestart2").value != "")){ + mt2 = timecalc.TimeToMinutes(document.getElementById(wday + "_timeend2").value)-timecalc.TimeToMinutes(document.getElementById(wday + "_timestart2").value); + } + if (document.getElementById(wday + "_timepause").value != ""){ + mtp = timecalc.TimeToMinutes(document.getElementById(wday + "_timepause").value); + } + document.getElementById(wday + "_timetotal").value= timecalc.MinutesToTime(mt1+mt2-mtp); + + }, + periodtimesum: function(values, data, calcParams){ + console.log(values); + console.log(data); + calc = 0; + for (var i=0;i