From: Kilian Saffran Date: Thu, 15 Apr 2021 09:00:19 +0000 (+0200) Subject: v20210415 X-Git-Url: http://cloud.dks.lu/git/?a=commitdiff_plain;h=5a972c24b3022a4bc71706c27ed27db3c82ce70d;p=hourtrax.git v20210415 --- diff --git a/.hourtrax/hourtrax.sqlite b/.hourtrax/hourtrax.sqlite index 5556614..4759d31 100644 Binary files a/.hourtrax/hourtrax.sqlite and b/.hourtrax/hourtrax.sqlite differ diff --git a/.hourtrax/potsync.conf b/.hourtrax/potsync.conf new file mode 100644 index 0000000..7267af7 --- /dev/null +++ b/.hourtrax/potsync.conf @@ -0,0 +1,6 @@ +USERAGENT=POT Hourtrax +POTAPIKEY=6b9c80d2-9153-11eb-8558-efa3f9982293 +POTAPIURL=http://app.pot.lan/potapp/api.php +POTSCHEMA=alicehartmann +POTLASTSYNCFROMSERVER= +POTLASTSYNCTOSERVER= diff --git a/install/install02.sh b/.hourtrax/staff.json similarity index 100% rename from install/install02.sh rename to .hourtrax/staff.json diff --git a/.hourtrax/sync.conf b/.hourtrax/sync.conf new file mode 100644 index 0000000..f5daa36 --- /dev/null +++ b/.hourtrax/sync.conf @@ -0,0 +1,5 @@ +htxuser="htx" +htxpwd="Aib5aevo" +htxurl="https://htx.plandutravail.lu/htx/api.php" +htxschema="alicehartmann" +htxstation="dhart-pot03" \ No newline at end of file diff --git a/.vscode/sftp.json b/.vscode/sftp.json new file mode 100644 index 0000000..8d5f6a8 --- /dev/null +++ b/.vscode/sftp.json @@ -0,0 +1,11 @@ + +{ + "name": "htx-test", + "scheme": "sftp", + "context": "bin/", + "host": "dhart-pot02", + "username": "pot", + "password": "sai4seip", + "port":3587, + "remotePath": "/home/pot/bin/" +} diff --git a/bin/clearfingerprint.sh b/bin/clearfingerprint.sh new file mode 100644 index 0000000..ffdcd77 --- /dev/null +++ b/bin/clearfingerprint.sh @@ -0,0 +1,19 @@ +#!/bin/bash +CALLDIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" +if [[ $# -eq 0 ]] +then + echo "No args!" + exit 0 +fi +IDSTAFF=$1 +db=${HOME}"/.hourtrax/hourtrax.sqlite" +HASHDATA=(`sqlite3 $db "select fingerhash from fingerprints where id_staff='"${IDSTAFF}"';"`) +#echo ${HASHDATA} +sqlite3 $db "delete from fingerprints where id_staff='"${IDSTAFF}"';" +for h in "${!HASHDATA[@]}" + do + #echo ${HASHDATA[$h]} + TEST=(`echo "${HASHDATA[$h]}" | tr -d [] | awk -F"," '{ print $1" "$2}'`) + #echo "${CALLDIR}/fp.py deleteuser 30 ${TEST[0]} ${TEST[1]}" + ${CALLDIR}/fp.py deleteuser 30 ${TEST[0]} ${TEST[1]} +done \ No newline at end of file diff --git a/bin/fp.py b/bin/fp.py index 09797f6..2bc90ff 100644 --- a/bin/fp.py +++ b/bin/fp.py @@ -66,8 +66,8 @@ Finger_RST_Pin = 24 GPIO.setmode(GPIO.BCM) GPIO.setwarnings(False) -GPIO.setup(Finger_WAKE_Pin, GPIO.IN) -GPIO.setup(Finger_RST_Pin, GPIO.OUT) +GPIO.setup(Finger_WAKE_Pin, GPIO.IN) +GPIO.setup(Finger_RST_Pin, GPIO.OUT) GPIO.setup(Finger_RST_Pin, GPIO.OUT, initial=GPIO.HIGH) g_rx_buf = [] @@ -82,28 +82,28 @@ def TxAndRxCmd(command_buf, rx_bytes_need, timeout): CheckSum = 0 tx_buf = [] tx = "" - - tx_buf.append(CMD_HEAD) + + tx_buf.append(CMD_HEAD) for byte in command_buf: - tx_buf.append(byte) + tx_buf.append(byte) CheckSum ^= byte - - tx_buf.append(CheckSum) - tx_buf.append(CMD_TAIL) - + + tx_buf.append(CheckSum) + tx_buf.append(CMD_TAIL) + for i in tx_buf: tx += chr(i) - + ser.flushInput() ser.write(tx) - - g_rx_buf = [] + + g_rx_buf = [] time_before = time.time() time_after = time.time() while time_after - time_before < timeout and len(g_rx_buf) < rx_bytes_need: # Waiting for response bytes_can_recv = ser.inWaiting() if bytes_can_recv != 0: - g_rx_buf += ser.read(bytes_can_recv) + g_rx_buf += ser.read(bytes_can_recv) time_after = time.time() for i in range(len(g_rx_buf)): @@ -111,11 +111,11 @@ def TxAndRxCmd(command_buf, rx_bytes_need, timeout): if len(g_rx_buf) != rx_bytes_need: return ACK_TIMEOUT * -1 - if g_rx_buf[0] != CMD_HEAD: + if g_rx_buf[0] != CMD_HEAD: return ACK_FAIL * -1 if g_rx_buf[rx_bytes_need - 1] != CMD_TAIL: return ACK_FAIL * -1 - if g_rx_buf[1] != tx_buf[1]: + if g_rx_buf[1] != tx_buf[1]: return ACK_FAIL * -1 CheckSum = 0 @@ -125,10 +125,10 @@ def TxAndRxCmd(command_buf, rx_bytes_need, timeout): if index == 6: if CheckSum != byte: return ACK_FAIL * -1 - CheckSum ^= byte - return ACK_SUCCESS; + CheckSum ^= byte + return ACK_SUCCESS + - def GetCompareLevel(): global g_rx_buf command_buf = [CMD_COM_LEV, 0, 0, 1, 0] @@ -139,16 +139,16 @@ def GetCompareLevel(): return g_rx_buf[3] else: return 0xFF - + def SetCompareLevel(level): global g_rx_buf command_buf = [CMD_COM_LEV, 0, level, 0, 0] - r = TxAndRxCmd(command_buf, 8, 0.1) - + r = TxAndRxCmd(command_buf, 8, 0.1) + if r == ACK_TIMEOUT: return ACK_TIMEOUT * -1 - if r == ACK_SUCCESS and g_rx_buf[4] == ACK_SUCCESS: + if r == ACK_SUCCESS and g_rx_buf[4] == ACK_SUCCESS: return g_rx_buf[3] else: return 0xFF @@ -164,7 +164,7 @@ def GetUserCount(): return g_rx_buf[3] else: return 0xFF - + def GetTimeOut(): global g_rx_buf command_buf = [CMD_TIMEOUT, 0, 0, 1, 0] @@ -174,7 +174,7 @@ def GetTimeOut(): if r == ACK_SUCCESS and g_rx_buf[4] == ACK_SUCCESS: return g_rx_buf[3] else: - return 0xFF + return 0xFF def AddUser(perm): @@ -182,8 +182,8 @@ def AddUser(perm): r = GetUserCount() #sys.stdout.write ("users" + str(r)) if r >= USER_MAX_CNT: - return ACK_FULL * -1 - + return ACK_FULL * -1 + command_buf = [CMD_ADD_1, 0, r+1, perm, 0] r = TxAndRxCmd(command_buf, 8, MYTIMEOUT) #sys.stdout.write("1:" + str(g_rx_buf)) @@ -211,7 +211,7 @@ def ReplaceUser(highbit,lowbit): r = AddUser(MYPERM) return r -def DeleteUser(highnit,lowbit): +def DeleteUser(highbit,lowbit): global g_rx_buf,MYTIMEOUT if highbit == -1: return ACK_GO_OUT * -1 @@ -223,7 +223,7 @@ def DeleteUser(highnit,lowbit): #print(g_rx_buf) if r == ACK_FAIL: return ACK_FAIL * -1 - if r == ACK_SUCCESS: + if r == ACK_SUCCESS: return ACK_SUCCESS def ClearAllUser(): @@ -232,7 +232,7 @@ def ClearAllUser(): r = TxAndRxCmd(command_buf, 8, 5) if r == ACK_TIMEOUT: return ACK_TIMEOUT * -1 - if r == ACK_SUCCESS and g_rx_buf[4] == ACK_SUCCESS: + if r == ACK_SUCCESS and g_rx_buf[4] == ACK_SUCCESS: return ACK_SUCCESS else: return ACK_FAIL * -1 @@ -244,20 +244,20 @@ def GetAllUsers(): print(g_rx_buf) if r == ACK_TIMEOUT: return ACK_TIMEOUT * -1 - if r == ACK_SUCCESS: + if r == ACK_SUCCESS: return ACK_SUCCESS else: return ACK_FAIL * -1 - + #*************************************************************************** # @brief Check if user ID is between 1 and 3 -#***************************************************************************/ +#***************************************************************************/ def IsMasterUser(user_id): - if user_id == 1 or user_id == 2 or user_id == 3: + if user_id == 1 or user_id == 2 or user_id == 3: return TRUE - else: + else: return FALSE - + def VerifyUser(): global g_rx_buf,MYTIMEOUT command_buf = [CMD_MATCH, 0, 0, 0, 0] @@ -267,7 +267,7 @@ def VerifyUser(): return str(ACK_TIMEOUT * -1) if r == ACK_SUCCESS and IsMasterUser(g_rx_buf[4]) == TRUE: #ACK_SUCCESS - return "u["+ str(g_rx_buf[2])+',' + str(g_rx_buf[3])+',' + str(g_rx_buf[4])+',' + str(g_rx_buf[6]) +"]" + return "u["+ str(g_rx_buf[2])+',' + str(g_rx_buf[3])+',' + str(g_rx_buf[4])+',' + str(g_rx_buf[6]) +"]" else: return "-" + str(ACK_NO_USER) # The center of the fingersys.stdout.write is out of alignment with sensor @@ -276,16 +276,16 @@ def ExitApp(reason): ser.close() GPIO.cleanup() sys.stdout.write(reason) - sys.exit() - + sys.exit() + def Analysis_PC_Command(command): global Finger_SleepFlag - exitmsg = "-50" + #exitmsg = "-50" if command == "count": ExitApp(str(GetUserCount())) elif command == "write": r = AddUser(MYPERM) - ExitApp(str(r)) + ExitApp(str(r)) elif command == "read": r = VerifyUser() ExitApp(str(r)) @@ -305,22 +305,22 @@ def Analysis_PC_Command(command): r = ReplaceUser(MYHIGH,MYLOW) ExitApp(str(r)) else: - exitmsg = "I" + ExitApp("-99") ExitApp("-100") - - + + def main(): - + GPIO.output(Finger_RST_Pin, GPIO.LOW) - time.sleep(0.25) + time.sleep(0.25) GPIO.output(Finger_RST_Pin, GPIO.HIGH) time.sleep(0.25) # Wait for module to start - if SetCompareLevel(MYLEVEL) != MYLEVEL: + if SetCompareLevel(MYLEVEL) != MYLEVEL: ExitApp("-20") Analysis_PC_Command(MYCMD) - + if __name__ == '__main__': try: main() except KeyboardInterrupt: - ExitApp("-30") + ExitApp("-30") \ No newline at end of file diff --git a/bin/fp.sh b/bin/fp.sh deleted file mode 100644 index cb832ce..0000000 --- a/bin/fp.sh +++ /dev/null @@ -1,5 +0,0 @@ -#!/bin/bash -CALLDIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" -DATADIR=`dirname ${CALLDIR}`; -DATADIR=${DATADIR}'/.hourtrax' -sqlite3 ${DATADIR}'/hourtrax.sqlite' "select 'u' || fingerhash from fingerprints where id_staff='1';" \ No newline at end of file diff --git a/bin/fpread.sh b/bin/fpread.sh new file mode 100644 index 0000000..7ac06f0 --- /dev/null +++ b/bin/fpread.sh @@ -0,0 +1,2 @@ +#!/bin/bash +echo -n "u[1,1,1,1]" \ No newline at end of file diff --git a/bin/fpunload.sh b/bin/fpunload.sh index 0aca85d..50d003e 100644 --- a/bin/fpunload.sh +++ b/bin/fpunload.sh @@ -1,5 +1,5 @@ #!/bin/bash -echo "Virtual unload!" +echo "" # MYPID=`ps ax | grep fp.py | grep -v "grep" | head -n 1 | awk '{ print $1 }'` # if [ "${MYPID}" != "" ] # then diff --git a/bin/fpwrite.sh b/bin/fpwrite.sh new file mode 100644 index 0000000..ad0ea7e --- /dev/null +++ b/bin/fpwrite.sh @@ -0,0 +1,2 @@ +#!/bin/bash +echo -n "au[1,1,1,1]" \ No newline at end of file diff --git a/bin/getdataupdates.sh b/bin/getdataupdates.sh new file mode 100644 index 0000000..de74e5d --- /dev/null +++ b/bin/getdataupdates.sh @@ -0,0 +1,9 @@ +#!/bin/bash +CALLDIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" +. ${HOME}/.hourtrax/sync.conf +if [[ $# -eq 0 ]] +then + echo "No args!" + exit 0 +fi +NEWTSTP=`sqlite3 .hourtrax/hourtrax.sqlite "Select datetime('now','localtime');` diff --git a/bin/getstaffdata.sh b/bin/getstaffdata.sh new file mode 100644 index 0000000..936b1c1 --- /dev/null +++ b/bin/getstaffdata.sh @@ -0,0 +1,8 @@ +#!/bin/bash +CALLDIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" +. ${HOME}/.hourtrax/sync.conf +if [[ $# -eq 0 ]] +then + echo "No args!" + exit 0 +fi \ No newline at end of file diff --git a/bin/sendtrack.sh b/bin/sendtrack.sh new file mode 100644 index 0000000..820845b --- /dev/null +++ b/bin/sendtrack.sh @@ -0,0 +1,19 @@ +#!/bin/bash +CALLDIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" +. ${HOME}/.hourtrax/sync.conf +if [[ $# -eq 0 ]] +then + echo "No args!" + exit 0 +fi +TRACKID=$1 + +# DATABYID=`/usr/local/bin/sqlite3 -json ${HOME}/.hourtrax/hourtrax.sqlite "Select id,id_staff,daydate,stamp_in,stamp_out,created,modified from timetracks where id='"${TRACKID}"';"`; +# #echo "Data to send: "${DATABYID} +# HNAME=`hostname` +# curl -k -A "${USERAGENT}" -H "pot-tracker: ${HNAME}" \ +# -H "pot-schema: ${POTSCHEMA}" \ +# -H "pot-api-key: ${POTAPIKEY}" \ +# --request POST \ +# --data "cl=TimeTracker&fn=setTracker&schema=${POTSCHEMA}&tracker=${HNAME}&data=${DATABYID}" \ +# ${POTAPIURL} \ No newline at end of file diff --git a/bin/setstaff.sh b/bin/setstaff.sh new file mode 100644 index 0000000..819f601 --- /dev/null +++ b/bin/setstaff.sh @@ -0,0 +1,44 @@ +#!/bin/bash +CALLDIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" +if [[ $# -eq 0 ]] +then + echo "No args!" + exit 0 +fi + +#$db="/mnt/c/Users/ksaff/Workspace/hourtrax/.hourtrax/hourtrax.sqlite" +db=${HOME}"/.hourtrax/hourtrax.sqlite" +params=$1 +params=${params//[\[|\$|\]|\{|\}|\']} + +#eval ${params} +IFS=';' +stdata=(`echo "$params"`) +HASID="0" +declare -a acol +declare -a aval +for s in "${stdata[@]}" +do + IFS='=' + cold=(`echo "$s"`) + acol=(${acol[@]} ${cold[0]}) + if [ "${cold[0]}" == "id" ]; then + HASID="1" + fi + if [ "${cold[1]}" == "" ]; then + val='null' + else + val="'"${cold[1]}"'" + fi + aval=(${aval[@]} $val) +done +scol=$(IFS=, ; echo "${acol[*]}") +sval=$(IFS=, ; echo "${aval[*]}") +sql="REPLACE INTO staff ("$scol") VALUES ("$sval");" +if [[ "$HASID" == "1" ]]; then + sqlite3 $db "$sql" + echo $sql +else + echo "no ID!" +fi + diff --git a/bin/syncdown.pl b/bin/syncdown.pl new file mode 100644 index 0000000..b2e6735 --- /dev/null +++ b/bin/syncdown.pl @@ -0,0 +1,26 @@ +#!/usr/bin/env perl + +use strict; +use JSON::PP; +my $cfg = &readconfig($ENV{HOME}.'/.hourtrax/sync.conf'); + +my $cmd = 'curl -H "Content-type: application/json" --user "'.$cfg->{htxuser}.':'.$cfg->{htxpwd}.'" -X POST --data \'{"fn":"queryarray","cl":"data","sql":"select id,prename,surname,isdeleted, + case when istimetrackenabled is null or timetrackers::text not like \'%'.$cfg->{htxstation}.'%\' then true else null end as isdisabled, timetrackerlang as lang,timetrackerfixtime as fixtime,timetrackerpin as pin, timetrackerrestriction as restriction from '.$cfg->{htxschema}.'.staff"}\' '.$cfg->{htxurl}; +print $cmd."\n"; +my $res = `$cmd`; + +print $res."\n"; + +sub readconfig($file){ + my $file = shift; + my $ncfg = (); + open(CFG,$file); + while (my $l = ){ + chomp($l); + if (($l =~ /^#/ ) || ($l eq "")) { next;} + my ($k,$v) = $l =~ m/^(.+)="(.+)"/; + $ncfg->{$k} = $v; + } + close(CFG); + return $ncfg; +} \ No newline at end of file diff --git a/bin/syncup.pl b/bin/syncup.pl new file mode 100644 index 0000000..fe1c430 --- /dev/null +++ b/bin/syncup.pl @@ -0,0 +1,126 @@ +#!/usr/bin/env perl +use strict; +use Getopt::Long; +use Data::Dumper; +use File::Basename; +use FindBin qw($RealBin); +use JSON::PP; +use lib (dirname($RealBin).'/lib'); +use DB::PgSQL; +use ConfigFile; +use SSH; +use POSIX qw/strftime/; +# check if running +#print "PID:".$$."\n"; +my $cmd = 'ps ax | grep '.basename($0).' | grep -v "grep" | awk \'{ print $1 }\''; +my $cfgpath = dirname($RealBin).'/conf'; +my $logpath = dirname($RealBin).'/log'; +my $cfgdata = ConfigFile->new({logfile => $logpath.'/'.strftime('%Y-%m-%d',localtime()).'.log'}); +#print $cmd."\n"; +my $isrunning = `$cmd`; +chomp($isrunning); +#print "Result:".$isrunning."\n"; +if ($isrunning ne "$$"){ + $cfgdata->writelog("script","params","start","script already running on PID:$$!"); + print basename($0)." already runs!\n"; + exit(1); +} + + + +my $timetracker = ""; +my $system = ""; +GetOptions( "timetracker|t=s" => \$timetracker); +print "start htx(up) sync timetracker $timetracker to pot\n"; + +if (($timetracker eq "") || (! -e $cfgpath.'/'.$timetracker.'.conf')){ + $cfgdata->writelog("script","params","start","no timetracker in params!"); + print "no timetracker!\n"; + exit(2); +} +my $ttcfgfile = dirname($RealBin).'/conf/'.$timetracker.'.conf'; +my $ttcfg = $cfgdata->read_conf($ttcfgfile); +#print Dumper($ttcfg); +if (exists($ttcfg->{syncdb}) && exists($ttcfg->{syncschema}) && ($ttcfg->{syncdb} ne "") && ($ttcfg->{syncschema} ne "") && -f $cfgpath.'/'.$ttcfg->{syncdb}.'.conf'){ + my $ttssh = SSH->new({host => $ttcfg->{sshhost},opts => {user => $ttcfg->{sshuser}, password => $ttcfg->{sshpwd}, port => $ttcfg->{sshport}, strict_mode => 0}}); + my $syscfgfile = dirname($RealBin).'/conf/'.$ttcfg->{syncdb}.'.conf'; + my $syscfg = $cfgdata->read_conf($syscfgfile); + #print Dumper($syscfg); + my $sysdb = DB::PgSQL->new({dbname => $syscfg->{dbname},dbhost => $syscfg->{dbhost},dbuser=>$syscfg->{dbuser}, dbpasswd => $syscfg->{dbpasswd}}); + my $newts = $sysdb->query("select to_char(now(),'YYYY-MM-DD HH24:MI:SS') as newts;"); + my $ttsql = "select id,id_staff,stamp_in,stamp_out from timetracks "; + if (exists($ttcfg->{lastsyncup}) && ($ttcfg->{lastsyncup} =~ /\d\d\d\d-\d\d-\d\d \d\d:\d\d:\d\d/)){ + $ttsql .= " where stamp_in >= '".$ttcfg->{lastsyncup}."' or stamp_out >= '".$ttcfg->{lastsyncup}."'"; + } + $ttsql .= ";"; + my $cmd = 'sqlite3 "'.$ttcfg->{datapath}.'/'.$ttcfg->{dbfile}.'" "'.$ttsql.'"'; + + $cfgdata->writelog("ssh","syncup","sqlite",$cmd); + my $out = $ttssh->piperemote($cmd); + #print "->$out<-\n"; + if ($out eq ""){ + print $ttcfg->{sshhost}.": nothing to update or Connection Time Out!\n"; + exit(3); + } + #print $out; + my @ttdata = split("\n",$out); + #print Dumper(@ttdata); + foreach my $tt (@ttdata){ + #print $tt."\n"; + chomp($tt); + my @cols = split(/\|/,$tt); + #print Dumper(@cols); + my $sysrowsql = "INSERT INTO ".$ttcfg->{syncschema}.".timetracker (id,id_staff,daydate,stamp_in) VALUES ('".$cols[0]."','".$cols[1]."',date('".substr($cols[2],0,10)."'),'".$cols[2]."') on conflict on constraint timetracker_pkey do nothing;"; + if ($cols[3] ne ""){ + $sysrowsql .= "UPDATE ".$ttcfg->{syncschema}.".timetracker set stamp_out='".$cols[3]."' where stamp_out is null and id='".$cols[0]."';"; + } + #print $sysrowsql."\n--\n"; + $cfgdata->writelog("pot","syncup","sql",$sysrowsql); + my $st = $sysdb->exec($sysrowsql); + } + print "New TS: ".$newts->{newts}."\n"; + # + my $replts = "sed -i 's/^lastsyncup=.*/lastsyncup=".$newts->{newts}."/' ".$ttcfgfile; + $out = `$replts`; + if ($out ne ""){ + $cfgdata->writelog("config","sed","errror","error writing timetamp to config ".$timetracker.".conf!".$out); + } + +} else { + $cfgdata->writelog("script","params","start","no System DB or schema found!"); + print "no System DB or schema found!\n"; + exit(2); +} +# if (($system eq "") || (! -e $cfgpath.'/'.$system.'.conf')){ +# $cfgdata->writelog("script","params","start","no system in params!"); +# print "no system\n"; +# exit(3); +# } + +#$sysdb-> +#if (! -e $cfg->{datapath}.'/'.$cfg->{dbfile}){ +# print "no database ".$cfg->{datapath}.'/'.$cfg->{dbfile}." found!\n"; +# exit(1); +#} + +#my $jdata = &readdatafile(); +#my $db = DB::SQLite->new({dbfile => $cfg->{datapath}.'/'.$cfg->{dbfile}}); +#my @k = keys(%{$jdata->{result}}); +#foreach my $fn (keys(%{$jdata->{result}})){ +# foreach my $j (keys(%{$jdata->{$fn}->{data}})){ +# my $data = $jdata->{result}->{$fn}->{$j}; + #print Dumper($user); +# if ($fn eq "getusers"){ +# my $sql = "REPLACE INTO staff (id,prename,surname,isdisabled,isdeleted) VALUES (".$db->value($data->{id}).",".$db->value($data->{prename}).",".$db->value($data->{surname}).",".(($data->{istimetrackenabled} eq "1")?'null':"'1'").",".$db->value($data->{isdeleted}).");"; +# print $sql."\n"; +# $db->exec($sql); +# } elsif ($fn eq "getpotdata"){ +# my $sql = "REPLACE INTO staffworktimes (id,id_staff,starttime1,endtime1,starttime2,endtime2) VALUES (".$db->value($data->{id}).",".$db->value($data->{id_staff}).",".$db->value($data->{timestart1}).",".$db->value($data->{timeend1}).",".$db->value($data->{timestart2}).",".$db->value($data->{timeend2}).");"; +# print $sql."\n"; +# $db->exec($sql); +# } + +# } +#} + +#unlink($datafile); diff --git a/desktopapp/css/theme.css b/desktopapp/css/theme.css index efad5ec..ddf8483 100644 --- a/desktopapp/css/theme.css +++ b/desktopapp/css/theme.css @@ -146,7 +146,7 @@ hr{border:0;border-top:1px solid #eee;margin:20px 0} .padding-32{padding-top:32px!important;padding-bottom:32px!important}.padding-48{padding-top:48px!important;padding-bottom:48px!important} .padding-64{padding-top:64px!important;padding-bottom:64px!important} .left{float:left!important}.right{float:right!important} -.button:hover{color:#fff!important;background-color:#343434!important} +/* .button:hover{color:#fff!important;background-color:#343434!important} */ .transparent,.hover-none:hover{background-color:transparent!important} .hover-none:hover{box-shadow:none!important} /* DEFAULT COLORS */ diff --git a/desktopapp/img/touch.svg b/desktopapp/img/touch.svg new file mode 100644 index 0000000..33b7615 --- /dev/null +++ b/desktopapp/img/touch.svg @@ -0,0 +1,5 @@ + + + + \ No newline at end of file diff --git a/desktopapp/index.fingerprint.html b/desktopapp/index.fingerprint.html deleted file mode 100644 index a44ec38..0000000 --- a/desktopapp/index.fingerprint.html +++ /dev/null @@ -1,156 +0,0 @@ - - - - - - - - - -Time Clock - - -
- -
- -

Tappez sur l'écran pour commencer
Tippen Sie auf den Bildschirm, um zu starten

-
- - - - - - - - - - - - - -
- -
-
- - - - - - - - - - - \ No newline at end of file diff --git a/desktopapp/index.html b/desktopapp/index.html new file mode 100644 index 0000000..be3747c --- /dev/null +++ b/desktopapp/index.html @@ -0,0 +1,141 @@ + + + + + + + + + Time Clock + + +
+ +

+
+ + + + + + + + + + +
+
+
+ + + + + + + + + + diff --git a/desktopapp/js/admin.js b/desktopapp/js/admin.js deleted file mode 100644 index 5c0f99f..0000000 --- a/desktopapp/js/admin.js +++ /dev/null @@ -1,106 +0,0 @@ -Date.prototype.addDays = function(days) { - this.setDate(this.getDate() + parseInt(days)); - return this; -}; - -var admin = { - globaldata: {filter:{datefrom:null,dateto:null}}, - current_dataset: {}, - loadapp: function(appident){ - //console.log(appident); - //console.log(location.origin + '/app/' + appident + '/index.html'); - location.href=location.origin + '/app/' + appident + '/index.html'; - }, - loadpage: function(modulepage,modulename){ - //console.log(admin.current_dataset); - //console.log("Load module:" + modulepage); - if (modulename){ - document.getElementById("modulename").innerHTML = modulename; - } - var pm = []; - for (var i in admin.current_dataset){ - pm.push(i + "=" + encodeURIComponent(admin.current_dataset[i])); - } - if (pm.length > 0){ - modulepage = modulepage + "?" + pm.join("&"); - } - //console.log(modulepage); - document.getElementById("moduleframe").setAttribute('src',modulepage); - }, - sidebarclick: function(modulepage,modulename){ - admin.ladpage(modulepage,modulename); - }, - logout: function(){ - req.reqdata("POST",location.href,{"logout":"1"},admin.reloadpage); - - }, - setheader: function(htext){ - if (htext){ - document.getElementById("modulename").innerHTML = htext; - } - }, - reloadpage(page){ - location.href=location.href; - - }, - getdatasets: function(){ - req.reqdata("POST","db.cgi",{"db":app,"type":"array","sql":"select * from datastores;"},admin.loaddatasets); - }, - loaddatasets: function(data){ - //console.log(data); - var gdt = document.getElementById('globaldatasets'); - gdt.innerHTML = ''; - if (data && data.sqldata){ - var opts = ';' - for (var i in data.sqldata){ - opts += ''; - } - gdt.innerHTML = opts; - } - if (admin.current_dataset.db){ - - }else { - admin.current_dataset["db"]=gdt.value; - } - //console.log(admin.current_dataset); - } -} - -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"); -} - -function getMonday(d) { - d = new Date(d); - var day = d.getDay(), - diff = d.getDate() - day + (day == 0 ? -6:1); // adjust when day is sunday - return new Date(d.setDate(diff)); -} - -document.addEventListener("DOMContentLoaded", function() { - var mxdate = getMonday(new Date()); - mxdate = mxdate.addDays(-28) - //console.log(mxdate); - admin.globaldata.filter.datefrom = mxdate.toJSON().substring(0,10); - admin.globaldata.filter.dateto= new Date().toJSON().substring(0,10); - //console.log(admin.globaldata.filter); - if (app && app != ""){ - //initpage() - - - - - } -}); \ No newline at end of file diff --git a/desktopapp/js/app.js b/desktopapp/js/app.js index 85e0638..dd3feb8 100644 --- a/desktopapp/js/app.js +++ b/desktopapp/js/app.js @@ -7,7 +7,7 @@ let binpath = os.homedir() + '/bin/'; let preferences= {}; if (debug == 1){ cfgpath = path.dirname(__dirname)+ '/.hourtrax/'; - binpath = path.dirname(__dirname)+ '/bin/'; + binpath = '/mnt/c/Users/ksaff/Workspace/hourtrax/bin/'; } let app = { currentview: null, @@ -44,6 +44,15 @@ let app = { } return data; }, + setlanguage: function(nlang){ + if (nlang != 'fr' && nlang != 'de'){ nlang='de';} + var lbldata = document.getElementsByClassName("lbl"); + for (var l=0;lZugriff gewährt!", -"-1":"Erreur/Fehler! Veuillez essayer de placer le centre de l'empreinte digitale à plat sur le capteur, ou cette empreinte existe déjà!
Versuchen Sie bitte, die Mitte des Fingerabdrucks flach auf den Sensor zu legen, sonst ist der Fingerabdruck bereits vorhanden.", -"2":"l'empreinte digitale a été sauvegardée!
Der Fingerabdruck wurde gespeichert!", - - "-4": "Erreur/Fehler! La bibliothèque d'empreintes digitales est pleine! Prière de contacter le Support!
Die Fingerabdruck-Bibliothek ist voll! Bitte kontaktieren Sie den Support!", -"-5":"Erreur/Fehler! Utilisateur non verifé! Veuillez essayer de placer le centre de l'empreinte digitale à plat sur le capteur!
Nicht verifizierter Benutzer! Bitte versuchen Sie, die Mitte des Fingerabdrucks flach auf den Sensor zu legen!", -"-8":"Timed Out!" - -} - let fingerprint ={ unload: function(){ - console.log(binpath +'bin/fpunload.sh'); - const fpunload = spawn('bash', [binpath +'bin/fpunload.sh','']); + //console.log(binpath +'fpunload.sh'); + if (preferences.type != "fingerprint"){ return;} + const fpunload = spawn('bash', ['/home/pot/bin/fpunload.sh','']); + //const fpunload = spawn('bash', ["-c",binpath +'/fpunload.sh','']); fpunload.stdout.on('data', (data) => { console.log(`fpunload stdout: ${data}`); }); @@ -27,10 +19,12 @@ let fingerprint ={ }); }, read: function(){ + if (preferences.type != "fingerprint"){ return;} console.log("Read Start",moment(new Date()).format('hh:mm:ss')); timeclock.startCheckIdle(); - console.log("execute",binpath + 'bin/fp.sh'); - const fpread = spawn('bash', [binpath + 'bin/fp.sh', 'read',preferences.timeout]); + console.log("execute",binpath + 'fpread.sh'); + const fpread = spawn('python', ['/home/pot/bin/fp.py', 'read',preferences.timeout]); + //const fpread = spawn('bash', ['-c',binpath + '/fpread.sh', 'read',preferences.timeout]); fpread.stdout.on('data', (data) => { console.log(`fpread stdout: ${data}`); console.log("Read OUT End",moment(new Date()).format('hh:mm:ss')); @@ -39,24 +33,25 @@ let fingerprint ={ //var user=data.toString(); var user = data.toString().replace(/^u/,''); console.log("fp user",user); - console.log("sql","select id_staff,fingerhash,fingertype from fingerprints where fingerhash='"+user+"' and id_staff='"+timeclock.currentuser.id+"';"); - db.query("select id_staff,fingerhash,fingertype from fingerprints where fingerhash='"+user+"' and id_staff='"+timeclock.currentuser.id+"';").then(fpdata => { + var rsql = "select id_staff,fingerhash,fingertype from fingerprints where fingerhash='"+user+"' and id_staff='"+timeclock.userdata[timeclock.current_index].id+"';"; + console.log("rsql",rsql); + db.query(rsql).then(fpdata => { console.log("fpdata",fpdata); if (fpdata){ console.log("data compared",fpdata) timeclock.loadtimetrack(); - app.snackbar(fpmsg["0"],'green'); + app.snackbar(lang["de"]["fp_ok"],'green'); } else { fingerprint.read(); - app.snackbar(fpmsg["-5"],'red'); + app.snackbar(lang["de"]["fp_notok"],'red'); } }).catch(e => { console.log("db error",e); fingerprint.read(); - app.snackbar(fpmsg["-5"],'red'); + app.snackbar(lang["de"]["fp_notok"],'red'); }) } else { - app.snackbar(fpmsg["-5"],'red'); + app.snackbar(lang["de"]["fp_notok"],'red'); fingerprint.read(); } @@ -82,8 +77,10 @@ let fingerprint ={ }); }, write: function(){ + if (preferences.type != "fingerprint"){ return;} console.log("Write Start",moment(new Date()).format('hh:mm:ss')); - const fpwrite = spawn('python', [binpath + 'bin/fp.py', 'write',preferences.timeout]); + //const fpwrite = spawn('bash', ["-c",binpath + '/fp.py', 'write',preferences.timeout]); + const fpwrite = spawn('python', ['/home/pot/bin/fp.py', 'write',preferences.timeout]); timeclock.startCheckIdle(); fpwrite.stdout.on('data', (data) => { console.log("Write OUT End",moment(new Date()).format('hh:mm:ss')); @@ -91,22 +88,22 @@ let fingerprint ={ console.log(data.toString()); if (data.toString().startsWith("au")){ var newuser = data.toString().replace(/^au/,''); - console.log("write FP to User:",timeclock.currentuser,timeclock.writefinger,newuser); - db.exec("REPLACE INTO fingerprints (id_staff,fingerhash,fingertype) VALUES ('"+ timeclock.currentuser.id +"','"+ newuser +"','"+ timeclock.writefinger +"');").then(dbdata => { + console.log("write FP to User:",timeclock.current_index,timeclock.writefinger,newuser); + db.exec("REPLACE INTO fingerprints (id_staff,fingerhash,fingertype) VALUES ('"+ timeclock.userdata[timeclock.current_index].id +"','"+ newuser +"','"+ timeclock.writefinger +"');").then(dbdata => { console.log("newfinger db sql",dbdata); document.getElementById("regfinger"+ timeclock.writefinger).classList.add("orange"); - app.snackbar(fpmsg["2"],'green'); + app.snackbar(lang["de"]["fp_saved"],'green'); document.getElementById("btnwritefinger").classList.remove("green"); //fingerprint.write(); } ).catch(e =>{ console.log("errordb",e); - app.snackbar(fpmsg["-1"],'red'); + app.snackbar(lang["de"]["fp_notok"],'red'); document.getElementById("btnwritefinger").classList.remove("green"); //fingerprint.write(); }); } else { - app.snackbar(fpmsg["-1"],'red'); + app.snackbar(lang["de"]["fp_notok"],'red'); document.getElementById("btnwritefinger").classList.remove("green"); //fingerprint.write(); } diff --git a/desktopapp/js/lang.js b/desktopapp/js/lang.js index 79aaf67..2c89dd8 100644 --- a/desktopapp/js/lang.js +++ b/desktopapp/js/lang.js @@ -1,8 +1,113 @@ -let lang = {"de": -{"pinerrormsg":"Pin-Code nicht korrekt!" + +let lang = {"de": +{"pinerrormsg":"Pin-Code nicht korrekt!", +"msgplacefinger":"Legen Sie einen Ihrer registrierten Finger auf den Fingerabdruck-Sensor", +"cancel":"abbrechen", +"msgchoosename":"Wählen Sie Ihren Namen!", +"msgnotinworktime":"Sie können sich erst ab Uhr einloggen!", +"enterpincode":"Pincode eingeben:", +"registerfinger":"Registrierung", +"close":"schließen", +"selectfinger":"einen Finger auswählen", +"msgstartregister":"klicken Sie unten, um die Registrierung zu starten, dann legen Sie Ihren Finger auf den Fingerabdruck-Sensor", +"tracking":"Stechuhr", +"trackin":"Einloggen", +"trackout":"Ausloggen", +"endpause":"Ende Pause", +"startpause":"Start Pause", +"weekview":"Wochenübersicht", +"msgtrackregistered":"Danke,
der Vorgang wurde gespeichert!", +"fp_ok":"Zugriff gewährt!", +"fp_notok":"Fingerabdruck nicht erkannt!", +"fp_saved":"Der Fingerabdruck wurde gespeichert", +"fplib_full":"Die Fingerabdruck-Bibliothek ist voll! Bitte kontaktieren Sie den Support!", +"timeout":"Timed Out!", +"lasttrack":"Letzter Eintrag", +"statusoutsidetime":"Sie können sich an einem %%WEEKDAY%% nur zwischen %%STARTIME%% Uhr und %%ENDTIME%% Uhr ein- resp. ausloggen
Aktuelle Zeit:
%%CURRENT_TIME%%", +"mon":"Montag", +"tue":"Dienstag", +"wed":"Mittwoch", +"thu":"Donnerstag", +"fri":"Freitag", +"sat":"Samstag", +"sun":"Sonntag" }}; lang["fr"] = { - "pinerrormsg":"Code-Pin incorrecte!" + "pinerrormsg":"Code-Pin incorrecte!", + "msgplacefinger":"Mettez un de vos doigts enregistrés sur l'emprinte digitale", +"cancel":"abandonner", +"msgchoosename":"Sélectionner votre nom!", +"msgnotinworktime":"Vous pouvez pointer à partir de heure!", +"enterpincode":"entrer Code-Pin:", +"registerfinger":"Enregistrement", +"close":"fermer", +"selectfinger":"sélectionner un doigt", +"msgstartregister":"cliquer ci-dessous pour commencer l'enreigistrement, puis mettez le doigt sur l'emprinte digitale", +"tracking":"pointage", +"trackin":"Entrée", +"trackout":"Sortie", +"endpause":"Fin Pause", +"startpause":"Début Pause", +"weekview":"Semaine courrante", +"msgtrackregistered":"Merci,
le pointage a été sauvegardé!", +"fp_ok":"Accès authorisé!", +"fp_notok":"empr. digitale pas reconue!", +"fp_saved":"empr. digitale a été sauvegardée", +"fplib_full":"la Biblio des empr. digitale est plein! contactez le Support!", +"timeout":"Timed Out!", +"lasttrack":"Dernier Pointage", +"statusoutsidetime":"vous pouvez pointer le %%WEEKDAY%% seulement entre %%STARTTIME%% et %%ENDTIME%%
Heure actuelle:
%%CURRENT_TIME%%", +"mon":"Montag", +"tue":"Dienstag", +"wed":"Mittwoch", +"thu":"Donnerstag", +"fri":"Freitag", +"sat":"Samstag", +"sun":"Sonntag" }; + +lang["en"] = { + "pinerrormsg":"false pincode!", + "msgplacefinger":"put one of your registered finger on the fingerprint-sensor", +"cancel":"cancel", +"msgchoosename":"Select your name!", +"msgnotinworktime":"Vous pouvez pointer à partir de heure!", +"enterpincode":"enter pincode", +"registerfinger":"Register", +"close":"close", +"selectfinger":"select finger", +"msgstartregister":"click down here the start registration and put your finger on the sensor", +"tracking":"tracking", +"trackin":"Entry", +"trackout":"Leave", +"endpause":"End Pause", +"startpause":"Start Pause", +"weekview":"Current Week", +"msgtrackregistered":"Thank you,
the time has been saved!", +"fp_ok":"Access granted!", +"fp_notok":"unknown fingerprint!", +"fp_saved":"fingerprint has been saved", +"fplib_full":"la Biblio des empr. digitale est plein! contactez le Support!", +"timeout":"Timed Out!", +"lasttrack":"Last Track", +"statusoutsidetime":"on %%WEEKDAY%% you can only checkin/checkout between %%STARTTIME%% and %%ENDTIME%%
Current Time:
%%CURRENT_TIME%%", +"mon":"Monday", +"tue":"Tuesday", +"wed":"Wednesday", +"thu":"Thursday", +"fri":"Friday", +"sat":"Saturday", +"sun":"Sunday" +}; + +// let fpmsg={ "0": "Accès autorisé!
!", +// "-1":"Erreur/Fehler! Veuillez essayer de placer le centre de l'empreinte digitale à plat sur le capteur, ou cette empreinte existe déjà!
Versuchen Sie bitte, die Mitte des Fingerabdrucks flach auf den Sensor zu legen, sonst ist der Fingerabdruck bereits vorhanden.", +// "2":"l'empreinte digitale a été sauvegardée!
!", + +// "-4": "Erreur/Fehler! La bibliothèque d'empreintes digitales est pleine! Prière de contacter le Support!
", +// "-5":"Erreur/Fehler! Utilisateur non verifé! Veuillez essayer de placer le centre de l'empreinte digitale à plat sur le capteur!
Nicht verifizierter Benutzer! Bitte versuchen Sie, die Mitte des Fingerabdrucks flach auf den Sensor zu legen!", +// "-8":"Timed Out!" + +// } diff --git a/desktopapp/js/moduleglobal.js b/desktopapp/js/moduleglobal.js deleted file mode 100644 index 4b0991c..0000000 --- a/desktopapp/js/moduleglobal.js +++ /dev/null @@ -1,24 +0,0 @@ -// document.addEventListener("DOMContentLoaded", function() { -// //console.log( "Iframe "+ location.pathname.substring(location.pathname.lastIndexOf("/")) +" ready!" ); -// mpref.loadconfig(); -// initpage(); -// }); - -// var mpref ={ -// cfg: null, -// getSearchParams: function (k){ -// //alert(location.href); -// var p={}; -// //console.log("params =>" + location.search); -// location.search.replace(/[?&]+([^=&]+)=([^&]*)/gi,function(s,k,v){p[k]=v}); -// return k?p[k]:p; -// }, -// loadconfig: function(){ -// this.cfg = this.getSearchParams(); -// //var page = location.pathname.substring(location.pathname.lastIndexOf("/")); -// //page = page.replace(/\.html/,''); -// //apppref.getpreference(page); -// //appdb.dbfile = this.cfg.dbfile; -// //appdb.url = decodeURIComponent(this.cfg.serviceurl) + 'sqlite/' + decodeURIComponent(this.cfg.dbfile); -// } -// } diff --git a/desktopapp/js/renderer.js b/desktopapp/js/renderer.js deleted file mode 100644 index f33e58e..0000000 --- a/desktopapp/js/renderer.js +++ /dev/null @@ -1,83 +0,0 @@ -const { dialog } = require('electron'); -const fs = require('fs'); -const os = require('os'); -const path = require('path'); -let debug = 0; -let usersystem = { - profilepath: function(){ - cfgpath = os.homedir() + '/.hourtrax/'; - if (debug == 1){ - cfgpath = path.dirname(__dirname)+ '/.hourtrax/'; - } - return cfgpath; - }, - setPreference: function(key,data){ - console.log("set preference to: " + this.profilepath() + key + ".json"); - console.log(data); - if ((typeof data == 'object') || (typeof data == 'array')){ - data = JSON.stringify(data); - } - let result = fs.writeFileSync(this.profilepath() + key + ".json", data); - return result; - }, - getPreference: function(key){ - console.log("getPreference:" + this.profilepath() + key + ".json"); - let data = null; - if (fs.existsSync(this.profilepath() + key + ".json")){ - console.log("Read Key:" + key); - let data = fs.readFileSync(this.profilepath() + key + ".json", 'utf-8'); - if (data.startsWith("{") || data.startsWith("[")){ - data = JSON.parse(data); - } - return data; - } - return data; - }, - // selectfile: function(dlgtitle,lastpath,filefilters=null,multiselect=false){ - // let props = ['openFile']; - // if (multiselect == true){ - // props.push('multiSelections'); - // } - // return dialog.showOpenDialog({title: dlgtitle,defaultPath: lastpath, filters: filefilters, properties: props }); - // }, - // selectdir: function(dlgtitle,lastpath){ - // return dialog.showOpenDialog({title: dlgtitle,defaultPath: lastpath, filters: filefilters, properties: ['openDirectory'] }); - // }, - // showMessage: function(msgTitle,msg,msgdetail,msgtype,msgButtons=["OK"],defautlbtnid=0,cancelbtnid){ - // return dialog.showMessageBox({type: msgtype, // - // title: msgTitle, - // buttons:msgButtons, - // message: msg, - // detail: msgdetail, - // defaultId: defautlbtnid, - // cancelId: cancelbtnid}); - // }, - // showError: function(errtitle,errmsg){ - // dialog.showErrorBox(errtitle, errmsg); - // }, - - // getDataSets: function(){ - // let datasets =[]; - // //console.log(os.platform()); - // //console.log("ProfilePath:" + this.profilepath()); - // let files = fs.readdirSync(this.profilepath()); - // files.forEach(function(file) { - // if (file.match('.*\.json')){ - // if (file != 'invoicejournal.json'){ - // datasets.push({"label":file.replace('.json',''),"value":file}); - // } - - // } - // }); - // //console.log(datasets); - // return datasets; - // }, - // getsysinfo: function(){ - // return { - // "hostname": os.hostname(), - // "userdir": os.homedir(), - // "platform": os.platform(), - // "userinfo":os.userInfo() - // } - // } -} \ No newline at end of file diff --git a/desktopapp/js/request.js b/desktopapp/js/request.js deleted file mode 100644 index aff471f..0000000 --- a/desktopapp/js/request.js +++ /dev/null @@ -1,125 +0,0 @@ -//var api = 'http://localhost:8080/'; -// if (location.pathname.indexOf('module') > 0){ -// api = location.origin + location.pathname.substring(0, location.pathname.indexOf('module')) + '/'; -// } - -// async function postData(url = '', data = {}) { -// const response = await fetch(api + url, { -// method: 'POST', -// //mode: 'same-origin', -// cache: 'no-cache', -// //credentials: 'same-origin', -// headers: { -// 'Content-Type': 'application/json' - -// }, -// redirect: 'follow', -// //referrerPolicy: 'strict-origin', -// body: JSON.stringify(data) -// }); - -// return response.json(); -// } - - - -// var req = { -// multipartform: function(url,frmdata,callback){ -// var ret = null; -// // var rdata = null; -// if (!callback) { -// callback = req.asyncNoEvent; -// } -// var request = new XMLHttpRequest(); -// var sendurl = api + url; -// request.open("POST", sendurl, true); -// request.onload = function(){ -// if (request.status >= 200 && request.status <= 400){ -// if (request.getResponseHeader("Content-Type").indexOf('application/json') == 0){ -// var xparse = JSON.parse(request.responseText); -// ret = xparse.result; -// } -// else { -// ret = request.responseText; -// } -// callback(ret); -// } else { -// alert("Server ERROR:" + 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(url,data,callback){ -// var ret = null; -// var rdata = null; -// if (!callback) { callback = req.asyncNoEvent; } -// 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 Request for " + url); -// //console.log(rdata); -// var sendurl = api + url; -// console.log(sendurl + '?' + rdata); -// request.open("POST", sendurl, true); -// request.onload = function(){ -// if (request.status >= 200 && request.status <= 400){ -// if (request.getResponseHeader("Content-Type").indexOf('application/json') == 0){ -// if (request.responseText){ -// var xparse = JSON.parse(request.responseText); -// ret = xparse.result; -// } else { -// ret = null; -// } -// }else { -// ret = request.responseText; -// } -// callback(ret); -// } else { -// console.log("Server ERROR: " + request.status + "\n" + request.responseText); -// } -// }; -// request.onerror = function(){ -// console.log("ERROR: connection ERROR\n" + url); -// }; -// request.setRequestHeader('Content-Type','application/x-www-form-urlencoded; charset=UTF-8'); -// request.send(rdata); -// return ret; -// }, -// asyncNoEvent: function(data){ -// console.log("NoEvent Called!"); -// console.log(data); -// } - -// } - -// var report ={ -// generate: function(repname,filename,data){ -// showdataloaddlg("Création PDF encours","Attendez s.v.p."); -// postData("report.cgi",{"generate":repname,"file": filename + ".pdf","data":data}).then (data => {closedataloaddlg();report.openreport(data);}); -// return false; -// }, -// openreport(data){ -// if (data && data.file){ -// window.open(api + "report.cgi?open=" + encodeURIComponent(data.file)); -// } -// } -// } \ No newline at end of file diff --git a/desktopapp/js/sqlite.js b/desktopapp/js/sqlite.js index c39df24..ebad837 100644 --- a/desktopapp/js/sqlite.js +++ b/desktopapp/js/sqlite.js @@ -23,13 +23,16 @@ let db = { queryarray: function(sql){ return new Promise((resolve, reject) => { let queries = []; + console.log("Query array",sql); db.dbh.each(`${sql}`, (err, row) => { + console.log("XXOK");; if (err) { reject(err); // optional: you might choose to swallow errors. } else { queries.push(row); // accumulate the data } }, (err, n) => { + console.log("XXNO",err,n); if (err) { reject(err); // optional: again, you might choose to swallow this error. } else { diff --git a/desktopapp/js/sync.js b/desktopapp/js/sync.js new file mode 100644 index 0000000..f8981e1 --- /dev/null +++ b/desktopapp/js/sync.js @@ -0,0 +1,22 @@ +let syncdata ={ + track: function(id){ + if (debug == 1){ + console.log("DEBUG Execute sendtrack.sh!"); + return; + } else { + const synctrack = spawn('bash', ['/home/pot/bin/sendtrack.sh',id]); + synctrack.stdout.on('data', (data) => { + console.log(`synctrack stdout: ${data}`); + }); + + synctrack.stderr.on('data', (data) => { + console.error(`synctrack stderr: ${data}`); + }); + + synctrack.on('close', (code) => { + console.log(`synctrack child process exited with code ${code}`); + }); + } + + } +} \ No newline at end of file diff --git a/desktopapp/js/timeclock.js b/desktopapp/js/timeclock.js index 7734009..ab2b8bd 100644 --- a/desktopapp/js/timeclock.js +++ b/desktopapp/js/timeclock.js @@ -3,143 +3,207 @@ let timeclock = { current_index: null, currentuser: null, currentpanel: null, - tbl: null, + current_lang: "fr", + //tbl: null, + today: null, + weekday: null, lasttrack: null, interval: null, userdata: [], + currentuserlist: 1, intervaltime: preferences.timeout, writefinger: null, loadscreensaver: function(){ - console.log("Load screemsaver"); + console.log("Load screensaver"); timeclock.currentpanel = 'screensaver'; timeclock.currentuser= null; fingerprint.unload(); timeclock.stopCheckIdle(); app.viewpanel('screensaver'); - + return false; }, checkuserpin: function(){ + timeclock.stopCheckIdle(); let pcode = document.getElementById("pincode").value; + //console.log(pcode +" = " + timeclock.userdata[timeclock.current_index].pin); if (pcode == timeclock.userdata[timeclock.current_index].pin){ console.log("goto fingerprint registration"); - timeclock.loadfingerwriter(); + if (preferences.type == "fingerprint"){ + timeclock.loadfingerwriter(); + } else { + timeclock.loadtimetrack(); + } + } else { document.getElementById("pincode").value = ""; timeclock.startCheckIdle(); app.snackbar(lang['de'].pinerrormsg,'red'); } - }, - set_currentUser: function(uindex){ - return new Promise((resolve, reject) => { - let sql = "select st.*,fp.fingertypes,wt.daydate,wt.starttime1,wt.endtime1,wt.starttime2,wt.endtime2 from staff st " + - " left join staffworktimes wt on (st.id=wt.id_staff and daydate=current_date) " + - " LEFT join (select '[' ||group_concat(fingertype,',') || ']' as fingertypes,id_staff from fingerprints fp group by id_staff order by id_staff) fp on (fp.id_staff=st.id) " + - " where st.id='" + timeclock.userdata[uindex].id+"';" - db.query(sql).then( stdata => { - if (stdata && stdata.id==timeclock.userdata[uindex].id){ - resolve(uindex); - } else { - reject(null); - } - timeclock.currentuser = stdata; - - }).catch(err => {reject(null)}); - }); + return false; }, loadstatus: function(msg){ - //document.getElementById("statusmsg").innerHTML=msg; - console.log("Load status"); + if (msg == null){ + msg = ''; + } + document.getElementById("statusmsg").innerHTML=msg; + //console.log("Load status"); //timeclock.currentpanel = 'status'; //timeclock.currentuser= null; fingerprint.unload(); //timeclock.tbl.clearData(); app.viewpanel('status'); - setTimeout('timeclock.loadusers()',4000); + setTimeout('timeclock.loadusers()',3000); }, loadusers: function(){ console.log("Load users"); timeclock.currentpanel = 'users'; timeclock.currentuser= null; fingerprint.unload(); - timeclock.tbl.clearData(); - db.queryarray("select st.id,coalesce(st.prename,'') as prename,coalesce(st.surname,'') as surname, st.pin, count(fp.fingerhash) as fingercount from staff st left join fingerprints fp on (st.id=fp.id_staff) where st.isdisabled is null and st.isblocked is null and st.isdeleted is null group by st.id order by st.surname,st.prename;").then(data => { - let ulist = ""; - console.log(data); + + //timeclock.tbl.clearData(); + db.queryarray("select * from (select st.id,coalesce(st.prename,'') as prename,coalesce(st.surname,'') as surname, st.pin, count(fp.fingerhash) as fingercount,lang,,monstart,monend,tuestart,tueend,wedstart,wedend,thustart,thuend,fristart,friend,satstart,satend,sunstart,sunend from staff st left join fingerprints fp on (st.id=fp.id_staff) where st.isenabled=true group by st.id order by st.surname,st.prename) where LENGTH(pin) > 3 or fingercount > 0 order by surname,prename;").then(data => { + let ulist = '
'; + //console.log(data); timeclock.userdata = data; - for (let i in timeclock.userdata){ - if (timeclock.userdata[i].fingercount == 0 && timeclock.userdata[i].pin != ""){ - ulist += ''; - } else if (timeclock.userdata[i].fingercount > 0) { - ulist += ''; - } + if (timeclock.userdata.length > 24){ + document.getElementById("mnubtn_usersprev").style.display = 'block'; + document.getElementById("mnubtn_usersnext").style.display = 'block'; } - document.getElementById('userlist').innerHTML=ulist; + ulistnum = 1; + for (i=0; i < timeclock.userdata.length;i++){ + //style="padding: 8px 12px!important;" + //if (timeclock.userdata[i].fingercount == 0 && timeclock.userdata[i].pin != ""){ + ulist += ''; + if (i == 23) {ulistnum++;ulist += '
'; + document.getElementById('userlists').innerHTML=ulist; }); app.viewpanel('users'); timeclock.startCheckIdle(); + return false; + }, + userselected: function(i){ + console.log("user selected!"); + let weekday = moment().format('ddd').toLowerCase(); + let ctime = moment().format('HH:MM'); + let cantrack = false; + if (timeclock.userdata[i].lang) { timeclock.current_lang=timeclock.userdata[i].lang;app.setlanguage(timeclock.userdata[i].lang); } + else { app.setlanguage("fr");timeclock.current_lang="fr"; } + + if (timeclock.userdata[i][weekday +"start"] != null){ + if (ctime >= timeclock.userdata[i][weekday +"start"]){ + cantrack=true; + } + } + if (timeclock.userdata[i][weekday +"end"] != null){ + if (ctime <= timeclock.userdata[i][weekday +"end"]){ + cantrack=true; + } + } + if (cantrack == true){ + if (preferences.type != "fingerprint" && timeclock.userdata[i].pin != ""){ + timeclock.loadpincode(i); + } + else if (timeclock.userdata[i].fingercount == 0 && timeclock.userdata[i].pin != ""){ + timeclock.loadpincode(i); + } else if (timeclock.userdata[i].fingercount > 0) { + timeclock.loadfingerprint(i); + } + } else { + let smsg = lang[nlang]["statusoutsidetime"]; + smsg = smsg.replace(/%%STARTTIME%%/,timeclock.userdata[i][weekday +"start"]); + smsg = smsg.replace(/%%ENDTIME%%/,timeclock.userdata[i][weekday +"end"]); + smsg = smsg.replace(/%%WEEKDAY%%/,lang[weekday]); + smsg = smsg.replace(/%%CURRENT_TIME%%/,moment().format("HH:MM")); + timeclock.loadstatus(smsg); + + } + + return false; + }, + prevusers: function(){ + let ulx = document.getElementsByClassName("userlistdata"); + console.log(ulx); + if (timeclock.currentuserlist == 1 ){ return false;} + for (u=0;u { - - // } - // ).catch(err => { timeclock.loadusers();}) - + return false; }, loadfingerwriter: function(){ - + timeclock.stopCheckIdle(); for (var d=1;d<=5;d++){ console.log("clean finger " + d); document.getElementById("regfinger"+ d).classList.remove("orange"); document.getElementById("regfinger"+ d).classList.remove("green"); } console.log("get fingertypes" + timeclock.userdata[timeclock.current_index].id); - db.queryarray("select fingertype from fingerprints WHERE id_staff='"+ timeclock.userdata[timeclock.current_index].id +"';").then( fng => { - console.log("fingerdata",fng); - for (var d in fng){ - document.getElementById("regfinger"+ fng[d].fingertype).classList.add("orange"); - } - console.log("appview wf"); - app.viewpanel('writefinger'); - timeclock.startCheckIdle(); - }).catch(e => { console.log(e);}); - + app.viewpanel('writefinger'); + timeclock.startCheckIdle(); + // db.queryarray("select fingertype from fingerprints WHERE id_staff='"+ timeclock.userdata[timeclock.current_index].id +"';").then( fng => { + // console.log("fingerdata",fng); + // for (var d in fng){ + // document.getElementById("regfinger"+ fng[d].fingertype).classList.add("orange"); + // } + // console.log("appview wf"); + + // }).catch(e => { console.log(e);}); + return false; }, loadfingerprint: function (uindex){ timeclock.stopCheckIdle(); - timeclock.currentuser= uindex; + timeclock.current_index= uindex; var allgr = document.getElementsByClassName("username"); for (var i in allgr){ allgr[i].innerHTML = timeclock.userdata[uindex].prename + ' ' + timeclock.userdata[uindex].surname; } - console.log("Fingers:" + timeclock.userdata[uindex].fingercount); - if (timeclock.userdata[uindex].fingercount == 0){ - for (var d=1;d<=5;d++){ - console.log("clean finger " + d); - document.getElementById("regfinger"+ d).classList.remove("orange"); - document.getElementById("regfinger"+ d).classList.remove("green"); - } - app.viewpanel('writefinger'); - timeclock.startCheckIdle(); - } else { + + //console.log("set view readfinger!",timeclock.userdata[uindex].id); for (var d=1;d<=5;d++){ document.getElementById("finger"+ d).style.display = 'none'; } - db.queryarray("select fingertype from fingerprints where id_staff='"+ timeclock.currentuser.id +"';").then(data => { + //console.log("XXOK","select fingertype from fingerprints where id_staff='"+ timeclock.userdata[uindex].id +"';"); + + db.queryarray("select fingertype from fingerprints where id_staff='"+ timeclock.userdata[uindex].id +"';").then(data => { + console.log("fingertype got!",data); for (var d in data){ document.getElementById("finger"+ data[d].fingertype).style.display = 'block'; } + fingerprint.read(); + app.viewpanel('readfinger'); timeclock.startCheckIdle(); }).catch(e => { - + console.log("fingerprints error!"); }); - - } + return false; }, registerfinger: function(obj,finger){ timeclock.writefinger = finger; @@ -165,7 +229,7 @@ let timeclock = { document.getElementById("btntrackout").disabled = true; document.getElementById("btntrackinpause").disabled = true; document.getElementById("btntrackoutpause").disabled = true; - db.query("select id,id_staff,daydate,strftime('%d/%m/%Y',daydate) as dspdaydate ,strftime('%Y-%m-%d %H:%M:00',stamp_in) as stamp_in,strftime('%Y-%m-%d %H:%M:00',stamp_out) as stamp_out,strftime('%H:%M',stamp_in) as dspstamp_in,strftime('%H:%M',stamp_out) as dspstamp_out from timetracks where stamp_in=(select max(stamp_in) from timetracks where id_staff='" + timeclock.currentuser.id + "') and id_staff='" + timeclock.currentuser.id + "';").then(trdata => { + db.query("select id,id_staff,daydate,strftime('%d/%m/%Y',daydate) as dspdaydate ,strftime('%Y-%m-%d %H:%M:00',stamp_in) as stamp_in,strftime('%Y-%m-%d %H:%M:00',stamp_out) as stamp_out,strftime('%H:%M',stamp_in) as dspstamp_in,strftime('%H:%M',stamp_out) as dspstamp_out from timetracks where stamp_in=(select max(stamp_in) from timetracks where id_staff='" + timeclock.userdata[timeclock.current_index].id + "') and id_staff='" + timeclock.userdata[timeclock.current_index].id + "';").then(trdata => { timeclock.gettabledata(); if (trdata){ timeclock.lasttrack = trdata; @@ -199,23 +263,31 @@ let timeclock = { setTrack:function (direction){ let sql = ""; db.newuuid().then(newid => { + var syncid=newid.id; if (direction == 'in'){ - sql = "INSERT INTO timetracks (id,id_staff,daydate, stamp_in) VALUES ('"+ newid.id+"','"+timeclock.currentuser.id+"',date('now','localtime'),datetime('now','localtime'));"; + sql = "INSERT INTO timetracks (id,id_staff,daydate, stamp_in) VALUES ('"+ newid.id+"','"+timeclock.userdata[timeclock.current_index].id+"',date('now','localtime'),datetime('now','localtime'));"; } else if (direction == 'out'){ - sql = "UPDATE timetracks SET stamp_out=datetime('now','localtime') where id_staff='"+ timeclock.currentuser.id+"' and id='"+timeclock.lasttrack.id+"';"; + syncid=timeclock.lasttrack.id; + sql = "UPDATE timetracks SET stamp_out=datetime('now','localtime') where id_staff='"+ timeclock.userdata[timeclock.current_index].id+"' and id='"+timeclock.lasttrack.id+"';"; } + console.log("SET TrackSQL",sql); db.exec(sql).then(data => { + var msgreg = lang["fr"].msgtrackregistered; + if (timeclock.userdata[timeclock.current_index].lang){ + msgreg = lang[timeclock.userdata[timeclock.current_index].lang].msgtrackregistered; + } //app.snackbar('le pointage a été enregistré!','green'); + timeclock.loadstatus(msgreg); + syncdata.track(syncid); - timeclock.loadstatus(''); //timeclock.loadusers(); }).catch(e => { - app.snackbar('erreur d\'enregistrement du pointage!','red'); + app.snackbar(e + ' erreur 1 d\'enregistrement du pointage!','red'); }); }).catch(e => { - app.snackbar('erreur d\'enregistrement du pointage!','red'); + app.snackbar('erreur 2 d\'enregistrement du pointage!','red'); }); @@ -246,19 +318,19 @@ stopCheckIdle: function (){ document.getElementById("timer").style.display = 'none'; window.clearInterval(timeclock.interval); }, -inittable: function (){ - timeclock.tbl = new Tabulator("#tbl_weektracks", { - headerSort:false, - height: "370px", - layout:"fitColumns", - locale:"fr", - columns: [ - {title:"Date", field:"dspdaydate",align: "center"}, - {title:"Entrée",align: "right",field:"dspstamp_in"}, - {title:"Sortie",align: "right",field:"dspstamp_out"} -] -}); -}, +// inittable: function (){ +// // timeclock.tbl = new Tabulator("#tbl_weektracks", { +// // headerSort:false, +// // height: "370px", +// // layout:"fitColumns", +// // locale:"fr", +// // columns: [ +// // {title:"Date", field:"dspdaydate",align: "center"}, +// // {title:"Entrée",align: "right",field:"dspstamp_in"}, +// // {title:"Sortie",align: "right",field:"dspstamp_out"} +// // ] +// // }); +// }, setPinValue: function(key){ var cobj = document.getElementById("pincode"); var cpin = cobj.value; @@ -270,8 +342,8 @@ clearUserPin: function(){ return false; }, gettabledata: function(){ - db.queryarray("select id,id_staff,strftime('%d/%m/%Y',daydate) as dspdaydate,strftime('%H:%M',stamp_in) as dspstamp_in,strftime('%H:%M',stamp_out) as dspstamp_out from timetracks where strftime('%W',daydate) = strftime('%W',date('now','localtime')) and id_staff='" + timeclock.currentuser.id +"' order by daydate,stamp_in,stamp_out;").then(tbldata => { - timeclock.tbl.setData(tbldata); + db.queryarray("select id,id_staff,strftime('%d/%m/%Y',daydate) as dspdaydate,strftime('%H:%M',stamp_in) as dspstamp_in,strftime('%H:%M',stamp_out) as dspstamp_out from timetracks where strftime('%W',daydate) = strftime('%W',date('now','localtime')) and id_staff='" + timeclock.userdata[timeclock.current_index].id +"' order by daydate,stamp_in,stamp_out;").then(tbldata => { + //timeclock.tbl.setData(tbldata); }); } diff --git a/desktopapp/main.js b/desktopapp/main.js index 4947461..74ffb51 100644 --- a/desktopapp/main.js +++ b/desktopapp/main.js @@ -9,7 +9,7 @@ const {ipcMain} = require('electron') //var child = require('child_process').execFile; app.disableHardwareAcceleration() -let debug = 1 +let debug = 0 // Keep a global reference of the window object, if you don't, the window will // be closed automatically when the JavaScript object is garbage collected. let ua = app.getName() + '/' + app.getVersion() + '-' + os.type() + '/' + os.release() + '/' + os.arch @@ -44,7 +44,7 @@ function createWindow () { // } // if (os.platform() == "win32"){ // const glshort = globalShortcut.register('CommandOrControl+Shift+I', () => { - mainWindow.webContents.openDevTools({detached: true}); + mainWindow.webContents.openDevTools(); // }) // } mainWindow.setMenu(null) @@ -55,7 +55,7 @@ function createWindow () { } console.log("Path:" + __dirname); - mainWindow.loadFile("index."+ appcfg.type +".html") + mainWindow.loadFile("index.html") mainWindow.show() mainWindow.on('closed', () => { mainWindow = null diff --git a/install/.hourtrax/hourtrax.json b/install/.hourtrax/hourtrax.json index 97891f2..9efa9d1 100644 --- a/install/.hourtrax/hourtrax.json +++ b/install/.hourtrax/hourtrax.json @@ -2,7 +2,5 @@ "type":"fingerprint", "db": "hourtrax.sqlite", "timeout":30, - "flextime":-1, - "adminpwd":"htrax2021", - "wlan":{"ssid":"","psk":"","prority":1,"id_str":"client"} + "flextime":-1 } \ No newline at end of file diff --git a/install/.hourtrax/hourtrax.sqlite b/install/.hourtrax/hourtrax.sqlite index 672b5a7..e69de29 100644 Binary files a/install/.hourtrax/hourtrax.sqlite and b/install/.hourtrax/hourtrax.sqlite differ diff --git a/install/.hourtrax/ht.sql b/install/.hourtrax/ht.sql index bd8cbe8..28530c5 100644 --- a/install/.hourtrax/ht.sql +++ b/install/.hourtrax/ht.sql @@ -8,6 +8,10 @@ CREATE TABLE staff ( isblocked BOOLEAN, isdisabled BOOLEAN, isdeleted BOOLEAN, + fixtime integer, + lang text, + timetrackers text, + restriction text, modified DATETIME DEFAULT (datetime('now','localtime')), created DATETIME DEFAULT (datetime('now','localtime')), PRIMARY KEY (id) @@ -43,6 +47,20 @@ CREATE TABLE staffworktimes ( created DATETIME DEFAULT (datetime('now','localtime')), primary key (id) ); +CREATE Table stations ( + id text not null, + name text, + vpnname text, + timeout text, + primary key(id), + schema text, + modified DATETIME DEFAULT (datetime('now','localtime')), + created DATETIME DEFAULT (datetime('now','localtime')), +); +CREATE TRIGGER trg_stations_upd UPDATE ON stations + BEGIN + UPDATE stations SET modified=datetime('now','localtime') WHERE id = NEW.id; + END; CREATE TRIGGER trg_staff_upd UPDATE ON staff BEGIN UPDATE staff SET modified=datetime('now','localtime') WHERE id = NEW.id; diff --git a/install/bin/electron/resources/app/img/touch.svg b/install/bin/electron/resources/app/img/touch.svg new file mode 100644 index 0000000..33b7615 --- /dev/null +++ b/install/bin/electron/resources/app/img/touch.svg @@ -0,0 +1,5 @@ + + + + \ No newline at end of file diff --git a/install/bin/electron/resources/app/index.fingerprint.html b/install/bin/electron/resources/app/index.fingerprint.html index 3162782..ed00fff 100644 --- a/install/bin/electron/resources/app/index.fingerprint.html +++ b/install/bin/electron/resources/app/index.fingerprint.html @@ -13,7 +13,7 @@
-

Tappez sur l'écran pour commencer
Tippen Sie auf den Bildschirm, um zu starten

+