From: Kilian Saffran Date: Tue, 16 Apr 2019 17:55:03 +0000 (+0200) Subject: server documents booking and drop bs-tbl X-Git-Tag: 0.7beta~27 X-Git-Url: http://cloud.dks.lu/git/?a=commitdiff_plain;h=716b335cabe84a8f9b9b0cfaed946ad0b1263001;p=invoicejournal.git server documents booking and drop bs-tbl --- diff --git a/css/app.css b/css/app.css index 207a847..f137f86 100644 --- a/css/app.css +++ b/css/app.css @@ -60,7 +60,7 @@ select.bg-primary, select.bg-primary:hover, select.bg-primary:active { } -input.right { +.right { text-align: right; } .table-hover tbody tr:hover { @@ -72,4 +72,25 @@ input.right { .card { margin: 10px; +} + +.thead-dark tr th select.form-control { + background-color: #212529; + background-image: url("data:image/svg+xml;utf8,"); + color: #fff; + margin: 0px; +} + +.table tbody tr.highlight td { + background-color: lightblue; +} + +.noselect { + -webkit-touch-callout: none; /* iOS Safari */ + -webkit-user-select: none; /* Safari */ + -khtml-user-select: none; /* Konqueror HTML */ + -moz-user-select: none; /* Firefox */ + -ms-user-select: none; /* Internet Explorer/Edge */ + user-select: none; /* Non-prefixed version, currently + supported by Chrome and Opera */ } \ No newline at end of file diff --git a/db.invoicejournal.json b/db.invoicejournal.json new file mode 100644 index 0000000..d507921 --- /dev/null +++ b/db.invoicejournal.json @@ -0,0 +1 @@ +{"name":"invoicejournal","type":"local","server":"dks-laptop","dbfile":"invoicejournal","vpn":"","vat":"0,17","currency":"€","mailserver":"","mailencryption":"","mailport":"","maillogin":"","mailpassword":""} \ No newline at end of file diff --git a/index.html b/index.html index 9382c6a..6928c2b 100644 --- a/index.html +++ b/index.html @@ -21,9 +21,11 @@ Übersicht + Buchungen Rechnungen Konten Bankkonto + Dokumente Angebote Produkte Vorlagen diff --git a/main.js b/main.js index 40e1e4e..97e77c0 100644 --- a/main.js +++ b/main.js @@ -12,10 +12,11 @@ let mainWindow function createWindow () { // Create the browser window. var executablePath = ""; - var parameters = []; + var parameters = []; + console.log(app.getAppPath()); if (os.platform() == "win32"){ executablePath = "C:\\Strawberry\\perl\\bin\\perl.exe"; - parameters = ["C:\\Users\\ksaff\\Workspace\\dks_server\\dkslocalserver.pl"]; + parameters = ["C:\\Users\\ksaff\\Workspace\\Apps\\invoicejournal\\\\server\\invoicejournalserver.pl"]; } else { //os.platform() == "darwin" executablePath = "/Users/kilian/perl5/perlbrew/perls/perl-5.28.1/bin/perl"; parameters = ["/Users/kilian/Workspace/dks_server/dkslocalserver.pl"]; diff --git a/modules/accounts/form_account.html b/modules/accounts/form_account.html new file mode 100644 index 0000000..05db2d9 --- /dev/null +++ b/modules/accounts/form_account.html @@ -0,0 +1,250 @@ + + + + + + + + + + + + Konto + + + +
+ +
+ + + + + + + + + + + + + + diff --git a/modules/accounts/form_account.js b/modules/accounts/form_account.js new file mode 100644 index 0000000..e69de29 diff --git a/modules/accounts/index.html b/modules/accounts/index.html index 2897c37..fbe2f07 100644 --- a/modules/accounts/index.html +++ b/modules/accounts/index.html @@ -4,7 +4,6 @@ - @@ -23,23 +22,37 @@ -
+
+ + + + + + + +
+ + + + + + + + + + +
Kunden-Nr.Company / NameAdresseE-mailTelefon
+
+
- - - - - - - -
Kunden-Nr.Company / NameAdresseE-mailTelefon
+
+
- diff --git a/modules/accounts/index.js b/modules/accounts/index.js index f5fa6b5..4088578 100644 --- a/modules/accounts/index.js +++ b/modules/accounts/index.js @@ -1,6 +1,7 @@ var winh = Math.max(document.documentElement.clientHeight, window.innerHeight || 0); var tblh = winh-54; - +var shiftdown = false; +var selection = []; function initpage(){ // console.log(appdb.url); @@ -13,10 +14,9 @@ function loadtable(){ var sql = 'SELECT id, company, prename,surname, address, zip, city, country, email, phone, mobile, ident FROM accounts;'; var data = appdb.dbquery(sql); - console.log(data.sqldata); + for (var i in data.sqldata){ - var row = ''+ - '' + + var row = ''+ '' + data.sqldata[i].ident+ '' + '' + data.sqldata[i].company + (( data.sqldata[i].company != null)?'
':'') + data.sqldata[i].surname + ' ' + data.sqldata[i].surname + '' + '' + data.sqldata[i].address+ ((data.sqldata[i].address != null)?'
':'') + data.sqldata[i].zip + ' ' + data.sqldata[i].city + ((data.sqldata[i].country != null)?'
':'')+ data.sqldata[i].country + '' + @@ -25,12 +25,14 @@ function loadtable(){ ''; $("#tbl_accounts").append(row.replace(/null/g,'')); } - $('#tbl_accounts').bootstrapTable({ - pagination: false, - search: false, - height: tblh, - clickToSelect: true - }); + var cols = $("#tbl_accounts > tbody > tr:first-child").children(); + var colnum = cols.length -1 + console.log("childnum:" + colnum); + for (var i=1;i<=colnum;i++){ + wx = $("#tbl_accounts > tbody > tr:first-child > td:nth-child("+ i +")").width(); + wx = wx +3; + $("#tbl_accounts_head > thead > tr > th:nth-child("+ i +")").width(wx); + } } @@ -38,9 +40,8 @@ function loadtable(){ function account_edit(){ - var id= getTableSelectionID(); - if (id){ - parent.browserapp.loadmodulepage('accounts','form_account',{"id":d}); + if (selection.length >= 1){ + parent.browserapp.loadmodulepage('accounts','form_account',{"id":selection[0]}); } } @@ -54,22 +55,29 @@ function account_duplicate(){ } -function getTableSelectionID(){ - var sel = $('#tbl_accounts').bootstrapTable('getSelections'); - var id = null; - - if (sel){ id=sel[0]._id; } - console.log("Selected ID:" + id); - return id; +function setselection(id){ + if (shiftdown === true){ + if ($("#" + id).hasClass('highlight')){ + $("#" + id).removeClass('highlight'); + selection.splice($.inArray(id, selection),1); + }else { + $("#" + id).addClass('highlight'); + selection.push(id); + } + } else { + $("#" + id).addClass('highlight').siblings().removeClass('highlight'); + selection = [id]; + } } -function getTableSelectionIDs(){ - var sel = $('#tbl_accounts').bootstrapTable('getSelections'); - var ids = []; - if (sel){ - for (var s in sel){ - ids.push(s._id); - } +$(document).on('keydown',function(evt){ + if (evt.key= "Shift"){ + shiftdown = true; + } +}); + +$(document).on('keyup',function(evt){ + if (evt.key = "Shift"){ + shiftdown = false; } - return ids; -} \ No newline at end of file +}); \ No newline at end of file diff --git a/modules/bookings/form_booking.html b/modules/bookings/form_booking.html new file mode 100644 index 0000000..09b7480 --- /dev/null +++ b/modules/bookings/form_booking.html @@ -0,0 +1,260 @@ + + + + + + + + + + + + Rechnung + + + +
+ +
+
+
+
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+ +
+
+ +
+
+
+
+
+
+
+
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+
+
+
+
+
+
+ +
+ +
+ +
+
+ +
+ +
+ +
+
+
+
+
+
+ +
+ +
+ +
+
+ +
+ +
+ +
+
+
+
+
+
+
+
+
+
+ +
+
+
+ + + + + + + + + + + + + +
DescriptionQtyUnitPriceVATDiscountSums
+
+
+
+
+
+ + + + + + + + + + + + +
DatumTypSenderEmpfängerKontoAuszugBetrag
+
+
+ + + + + + + + + +
NameTypeDate
+
+ +
+
+
+
+
+
+ + +
+
+
+
+
+
+ + +
+
+
+
+ +
+
+ + + + + + + + + + + + + + diff --git a/modules/bookings/form_booking.js b/modules/bookings/form_booking.js new file mode 100644 index 0000000..e98ccbc --- /dev/null +++ b/modules/bookings/form_booking.js @@ -0,0 +1,81 @@ +function initpage(){ + $(".datepicker").datepicker({}); + tinymce.init({ + selector: 'textarea.richtextedit', + branding: false, + menubar:false, + statusbar: false, + plugins: 'searchreplace autolink directionality visualblocks visualchars advlist lists textpattern', + toolbar: 'bold italic underline strikethrough forecolor backcolor | link | alignleft aligncenter alignright alignjustify | numlist bullist outdent indent | removeformat', + image_advtab: true, + language: 'de', + }); + getaccounts(); + if (mpref.cfg.id){ + getinvoicedata(mpref.cfg.id); + } else { + //load default new invoice data + } + console.log("invoice ID:",mpref.cfg.id); +} + +$("#status").onchange(function(data){ + + var xtest = $("#status").html(); + console.log($("#status").html()); + if ($("#status").html() == 'bezahlt'){ + $("#status").attr("class","btn btn-success"); + } else if ($("#status").html() == 'geplant'){ + $("#status").attr("class","btn btn-secondary"); + } else if ($("#status").html() == 'überfällig'){ + $("#status").attr("class","btn btn-danger"); + } else if ($("#status").html() == 'verschickt'){ + $("#status").attr("class","btn btn-warning"); + } else if ($("#status").html() == 'erhalten'){ + $("#status").attr("class","btn btn-info"); + } +}) + +function getaccounts(){ + var sql = "select id, company,case when \"type\" like '%kunde%' then 1 else 0 end as receiver,case when \"type\" like '%lieferant%' or \"type\" like '%mitarbeiter%' or \"type\" like '%behörde%' then 1 else 0 end as sender from accounts;"; + var data = appdb.dbquery(sql); + //onsole.log(data.sqldata); + for (var i in data.sqldata){ + if (data.sqldata[i].receiver == 1){ + $("#id_receipient").append(''); + } + if (data.sqldata[i].sender == 1){ + $("#id_sender").append(''); + } + } +} + +function getinvoicedata(id){ + var sql = "select ij.id_sender,ij.id_receipient,ij.id_template,ij.status,ij.reference,ij.type, " + + "ij.statement,STRFTIME(\"%d.%m.%Y\",ij.date) as date,STRFTIME(\"%d.%m.%Y\",ij.deadlinedate) as deadlinedate,ij.footertext,ij.headertext, " + + "printf(\"%.2f\",CAST(sum(pos.quantity * pos.unitamount) as real)) as netamount, " + + "printf(\"%.2f\",CAST(case when pos.taxpercent > 0 then sum(pos.taxpercent * pos.quantity * pos.unitamount) else 0.0 end AS REAL)) as vatamount, " + + "printf(\"%.2f\",CAST(sum(pos.quantity * pos.unitamount) + case when pos.taxpercent > 0 then sum(pos.taxpercent * pos.quantity * pos.unitamount) else 0.0 end AS real)) as grossamount, " + + "printf(\"%.2f\",COALESCE(ij.payedamount,0.0)) as payedamount " + + "from invoicejournal ij left join invoicepositions pos on (ij.id=pos.id_invoice) where ij.id='"+mpref.cfg.id+"' group by pos.id_invoice;"; + var data = appdb.dbquery(sql); + if (data.sqldata){ + for (var i in data.sqldata[0]){ + if ($("#" + i).prop("tagName") == "SELECT"){ + $("#" + i).val(data.sqldata[0][i]); + } else if ($("#" + i).prop("tagName") == "INPUT" ) { + console.log(i + ">=" + data.sqldata[0][i]); + $("#" + i).val(data.sqldata[0][i]); + } else { + $("#" + i).html(data.sqldata[0][i]); + } + + $("#" + i).val(data.sqldata[0][i]); + } + } +} + +function loadinvoicepositions(){ + +} + diff --git a/modules/bookings/index.html b/modules/bookings/index.html new file mode 100644 index 0000000..400fe78 --- /dev/null +++ b/modules/bookings/index.html @@ -0,0 +1,194 @@ + + + + + + + + + +Buchungen + + + +
+ + + + + + + +
+ + + + + + + + + + + +
Beschreibung + + Betrag
+
+
+ + + + +
+
+
+
+
+
+ +
+
+
+
Σ
+
+ +
+
+
+
€
+
+ +
+
+
+
+
+
+ +
+
+
+
Σ
+
+ +
+
+
+
€
+
+ +
+
+
+
+
+
+ +
+
+
+
Σ
+
+ +
+
+
+
€
+
+ +
+
+
+
+
+
+ +
+
+
+
Σ
+
+ +
+
+
+
€
+
+ +
+
+
+
+
+
+ +
+
+
+
Σ
+
+ +
+
+
+
€
+
+ +
+
+
+
+ +
+
+ + + + + + + + + + + + \ No newline at end of file diff --git a/modules/bookings/index.js b/modules/bookings/index.js new file mode 100644 index 0000000..e6f2687 --- /dev/null +++ b/modules/bookings/index.js @@ -0,0 +1,198 @@ +var winh = Math.max(document.documentElement.clientHeight, window.innerHeight || 0); +var tblh = winh-54; +var pagepref = undefined; +var selection = []; +// var cfg = { +// byear: 2018 +// } +var sums = { planned: {cnt:0,sum:0},sended: {cnt:0,sum:0},payed: {cnt:0,sum:0},delayed: {cnt:0,sum:0},total: {cnt:0,sum:0}}; +var shiftdown = false; +function initpage(){ + console.log(appdb.url); + pagepref = parent.usersystem.getPreference("bookings"); + if (pagepref === null){ + pagepref= {}; + } + console.log(pagepref); + //loadyears(); + loadtable(); + load_senders(); + load_receipients(); + load_dateranges(); +} + +$(document).on('keydown',function(evt){ + if (evt.key= "Shift"){ + shiftdown = true; + } +}); + +$(document).on('keyup',function(evt){ + if (evt.key = "Shift"){ + shiftdown = false; + } +}); + +function loadtable(){ + var where = ''; + if (pagepref && pagepref.filter && Object.keys(pagepref.filter).length > 0){ + var whfilter = []; + for (var i in pagepref.filter){ + console.log(i); + if (i == 'bookingdate'){ + if ($("#daterange :selected").text() != ''){ + whfilter.push(pagepref.filter[i] + "='" + $("#daterange :selected").text() + "'"); + } + + } else { + whfilter.push(i + "='" + pagepref.filter[i] + "'"); + } + + } + if (whfilter.length > 0){ + where = ' where ' + whfilter.join( " AND "); + } + + } + sums = { planned: {cnt:0,sum:0},sended: {cnt:0,sum:0},payed: {cnt:0,sum:0},delayed: {cnt:0,sum:0},total: {cnt:0,sum:0}}; + var sql = "select strftime('%d.%m.%Y',invoicepositions.bookingdate) as bookingdate, invoicepositions.bookingdate as datesortable,invoicepositions.id,sender.company as sender,receipient.company as receipient, invoicepositions.description,replace(printf('%.2f€',quantity * unitamount),'.',',') as amount,quantity * unitamount as sumamount , invoicejournal.status from invoicepositions left join accounts sender on (invoicepositions.id_sender=sender.id) left join invoicejournal on (invoicepositions.id_invoice=invoicejournal.id) left join accounts receipient on (invoicepositions.id_receipient=receipient.id)" + where + " order by invoicepositions.bookingdate desc;"; + console.log(sql); + //$('#tbl_bookings').bootstrapTable('destroy'); + $("#tbl_bookings > tbody").html(""); + var data = appdb.dbquery(sql); + //console.log(data.sqldata); + for (var i in data.sqldata){ + var cstatus = "secondary"; + if (data.sqldata[i].status== "geplant"){ + sums.planned.cnt = sums.planned.cnt + 1; + sums.planned.sum = sums.planned.sum + parseFloat(data.sqldata[i].sumamount); + } + if (data.sqldata[i].status== "bezahlt"){ + cstatus = "success"; + sums.payed.cnt = sums.payed.cnt + 1; + sums.payed.sum = sums.payed.sum + parseFloat(data.sqldata[i].sumamount); + } + if (data.sqldata[i].status== "überfällig"){ + cstatus = "danger"; + sums.delayed.cnt = sums.delayed.cnt + 1; + sums.delayed.sum = sums.delayed.sum + parseFloat(data.sqldata[i].sumamount); + } + if (data.sqldata[i].status== "verschickt"){ + cstatus = "warning"; + sums.sended.cnt = sums.sended.cnt + 1; + sums.sended.sum = sums.sended.sum + parseFloat(data.sqldata[i].sumamount); + } + sums.total.cnt = sums.total.cnt + 1; + sums.total.sum = sums.total.sum + parseFloat(data.sqldata[i].sumamount); + var acolor = ""; + if (data.sqldata[i].amount.startsWith("-")){ acolor = "text-danger"; } + var row = ''+ + // '' + + ''+data.sqldata[i].datesortable+' ' + data.sqldata[i].bookingdate+ '' + + '' + data.sqldata[i].receipient+ '' + + '' + data.sqldata[i].sender+ '' + + '' + data.sqldata[i].description+ '' + + '' + data.sqldata[i].status+ '' + + '' + data.sqldata[i].amount+ '' + + ''; + + $("#tbl_bookings > tbody").append(row); + } + var cols = $("#tbl_bookings > tbody > tr:first-child").children(); + var colnum = cols.length -1 + console.log("childnum:" + colnum); + for (var i=1;i<=colnum;i++){ + wx = $("#tbl_bookings > tbody > tr:first-child > td:nth-child("+ i +")").width(); + wx = wx +3; + $("#tbl_bookings_head > thead > tr > th:nth-child("+ i +")").width(wx); + } + $("#cnt_planned").val(sums.planned.cnt);$("#sum_planned").val(sums.planned.sum.toFixed(2).toString().replace('.',',')); + $("#cnt_payed").val(sums.payed.cnt);$("#sum_payed").val(sums.payed.sum.toFixed(2).toString().replace('.',',')); + $("#cnt_delayed").val(sums.delayed.cnt);$("#sum_delayed").val(sums.delayed.sum.toFixed(2).toString().replace('.',',')); + $("#cnt_total").val(sums.total.cnt);$("#sum_total").val(sums.total.sum.toFixed(2).toString().replace('.',',')); + $("#cnt_sended").val(sums.sended.cnt);$("#sum_sended").val(sums.sended.sum.toFixed(2).toString().replace('.',',')); +} + +function load_senders(){ + var sql = "select distinct (sender.company) as sender from invoicepositions left join accounts sender on (invoicepositions.id_sender=sender.id) order by sender.company;"; + $("#sender").html(''); + var data = appdb.dbquery(sql); + + for (var i in data.sqldata){ + $("#sender").append(''); + } + if (pagepref && pagepref.filter && pagepref.filter.sender && pagepref.filter.sender != ''){ + //console.log("set selection:" + pagepref.filter.sender); + $("#sender").val(pagepref.filter.sender); + } +} + +function load_receipients(){ + var sql = "select distinct (receipient.company) as receipient from invoicepositions left join accounts receipient on (invoicepositions.id_receipient=receipient.id) order by receipient.company;"; + $("#receipient").html(''); + var data = appdb.dbquery(sql); + + for (var i in data.sqldata){ + $("#receipient").append(''); + } + if (pagepref && pagepref.filter && pagepref.filter.receipient && pagepref.filter.receipient != ''){ + //console.log("set selection:" + pagepref.filter.receipient); + $("#receipient").val(pagepref.filter.receipient); + } +} + +function load_dateranges(){ + var sql = "select strftime('%Y',bookingdate) as daterange, 'strftime(''%Y'',bookingdate)' as filter from invoicepositions where bookingdate is not null group by daterange union select strftime('%Y %m',bookingdate) as daterange , 'strftime(''%Y %m'',bookingdate)' as filter from invoicepositions where bookingdate is not null group by daterange union select strftime('%Y Q',bookingdate) || (((CAST(strftime('%m',bookingdate) AS INT) -1 ) / 3) +1) as daterange ,'strftime(''%Y Q'',bookingdate) || (((CAST(strftime(''%m'',bookingdate) AS INT) -1 ) / 3) +1)' as filter from invoicepositions where bookingdate is not null group by daterange order by daterange desc;"; + $("#daterange").html(''); + var data = appdb.dbquery(sql); + + for (var i in data.sqldata){ + $("#daterange").append(''); + } +} + + +function setfilter(id,field){ + console.log("setFilter"); + if (pagepref['filter'] === undefined){ + pagepref['filter'] = {}; + } + if ($("#" + id + " :selected").val() != ""){ + pagepref['filter'][field] = $("#" + id + " :selected").val(); + } + else { + delete pagepref['filter'][field]; + $("#" + id + "").val($("#"+ id +" option:first").val()); + } + parent.usersystem.setPreference('bookings',pagepref); + loadtable(); +} + + +function booking_edit(){ + var inv_id= getTableSelectionID(); + if (inv_id){ + parent.browserapp.loadmodulepage('bookings','form_booking',{"id":inv_id}); + } + +} + +function booking_delete(){ + +} + +function booking_duplicate(){ + +} + +function setselection(id){ + if (shiftdown === true){ + if ($("#" + id).hasClass('highlight')){ + $("#" + id).removeClass('highlight'); + }else { + $("#" + id).addClass('highlight'); + } + } else { + $("#" + id).addClass('highlight').siblings().removeClass('highlight'); + } +} diff --git a/modules/bookings/lib/booking.js b/modules/bookings/lib/booking.js new file mode 100644 index 0000000..e571178 --- /dev/null +++ b/modules/bookings/lib/booking.js @@ -0,0 +1,20 @@ +var invoice = { + new: function(){ + + }, + duplicate: function(id){ + + }, + delete: function(id){ + + }, + update: function(){ + + }, + print: function(){ + + }, + createpdf: function(){ + + }, +} \ No newline at end of file diff --git a/modules/documents/index.html b/modules/documents/index.html new file mode 100644 index 0000000..107fbd9 --- /dev/null +++ b/modules/documents/index.html @@ -0,0 +1,78 @@ + + + + + + + + + +Dokumente + + + +
+ + + + + + + +
+ + + + + + + + + +
Name
+
+
+ + + + +
+
+
+
+ +
+
+ + + + + + + + + + + \ No newline at end of file diff --git a/modules/documents/index.js b/modules/documents/index.js new file mode 100644 index 0000000..fbc1465 --- /dev/null +++ b/modules/documents/index.js @@ -0,0 +1,226 @@ +var winh = Math.max(document.documentElement.clientHeight, window.innerHeight || 0); +var tblh = winh-54; +var pagepref = undefined; +var selection = []; +// var cfg = { +// byear: 2018 +// } +// var sums = { planned: {cnt:0,sum:0},sended: {cnt:0,sum:0},payed: {cnt:0,sum:0},delayed: {cnt:0,sum:0},total: {cnt:0,sum:0}}; +shiftdown = false; +function initpage(){ + console.log(appdb.url); + pagepref = parent.usersystem.getPreference("documents"); + if (pagepref === null){ + pagepref= {}; + } + console.log(pagepref); + //loadyears(); + loadtable(); + load_categories(); + load_folders(); +} + +$(document).on('keydown',function(evt){ + if (evt.key= "Shift"){ + shiftdown = true; + } + console.log("shiftdown: " + shiftdown); +}); + +$(document).on('keyup',function(evt){ + //console.log("shift up x"); + //console.log(evt.key); + if (evt.key = "Shift"){ + //console.log("shift up"); + shiftdown = false; + } + console.log("shiftdown: " + shiftdown); +}); + +function loadtable(){ + // var path = ''; + // if (pagepref && pagepref.filter && Object.keys(pagepref.filter).length > 0){ + // var whfilter = []; + // for (var i in pagepref.filter){ + // if (i == 'category' ){ + + // } + // whfilter.push(i + "='" + pagepref.filter[i] + "'"); + // } + // path = ' where ' + whfilter.join( " AND "); + // } + $("#tbl_documents > tbody").html(""); + //console.log(decodeURIComponent(mpref.cfg.serviceurl) + 'filesystem/search?type=f&relative=1'); + + $.ajax({ + encoding:"UTF-8", + url:decodeURIComponent(mpref.cfg.serviceurl) + 'filesystem/search?type=f&relative=1', + crossDomain: true, + success: function (data){ + console.log(data); + result=data.result; + for (var i in result){ + var category = result[i].substring(0,result[i].indexOf("/")); + var year = result[i].substring(result[i].indexOf("/")+1,result[i].lastIndexOf("/")); + var month = ''; + if (year.indexOf('/') > 0){ + month = year.substring(year.indexOf("/")+1); + year = result[i].substring(0,year.indexOf("/")); + } + var file = result[i].substring(result[i].lastIndexOf("/")+1); + var row = '' + + ''+file+'' + + ''+category+'' + + ''+ year +'' + + ''+ month +'' + + '' + $("#tbl_documents > tbody").append(row); + } + var cols = $("#tbl_documents > tbody > tr:first-child").children(); + var colnum = cols.length -1; + console.log("childnum:" + colnum); + for (var i=1;i<=colnum;i++){ + wx = $("#tbl_documents > tbody > tr:first-child > td:nth-child("+ i +")").width(); + wx = wx +3; + $("#tbl_documents_head > thead > tr > th:nth-child("+ i +")").width(wx); + } + }, + error: function(data){ + //alert("Error:" + JSON.stringify(data)); + console.log("Error:" + JSON.stringify(data)); + }, + async:false + }); + + +} + +function load_categories(){ + $.ajax({ + encoding:"UTF-8", + url:decodeURIComponent(mpref.cfg.serviceurl) + 'filesystem/directory/list', + crossDomain: true, + success: function (data){ + console.log(data); + result=data.result.directory; + $("#category").html(''); + for (var c in result){ + $("#category").append(''); + } + }, + error: function(data){ + //alert("Error:" + JSON.stringify(data)); + console.log("Error:" + JSON.stringify(data)); + }, + async:false + }); + +} + +function load_folders(){ + // var sql = "select distinct (receipient.company) as receipient from invoicepositions left join accounts receipient on (invoicepositions.id_receipient=receipient.id) order by receipient.company;"; + // $("#receipient").html(''); + // var data = appdb.dbquery(sql); + + // for (var i in data.sqldata){ + // $("#receipient").append(''); + // } +} + +function setfilter(id,field){ + console.log("setFilter"); + if (pagepref['filter'] === undefined){ + pagepref['filter'] = {}; + } + if ($("#" + id + " :selected").val() != ""){ + pagepref['filter'][field] = $("#" + id + " :selected").val(); + } + else { + delete pagepref['filter'][field]; + $("#" + id + "").val($("#"+ id +" option:first").val()); + } + parent.usersystem.setPreference('documents',pagepref); + loadtable(); +} + +function document_add(){ + docfilter = [ + { name: 'PDF', extensions: ['pdf'] } + ]; + + var newfile = parent.usersystem.selectfile("select file",null,docfilter); + console.log(newfile); +} + +function document_delete(){ + +} + +function document_view(){ + window.open +} + +function document_parse(){ + +} +// function loadyears(){ +// sql = "select byear from invoicejournal group by byear order by byear asc;"; +// var data = appdb.dbquery(sql); +// //onsole.log(data.sqldata); +// for (var i in data.sqldata){ +// $("#timerange").append('' + data.sqldata[i].byear+''); +// } + +// } + +// function booking_edit(){ +// var inv_id= getTableSelectionID(); +// if (inv_id){ +// parent.browserapp.loadmodulepage('bookings','form_booking',{"id":inv_id}); +// } + +// } + +// function invoice_delete(){ + +// } + +// function invoice_duplicate(){ + +// } + +function setselection(id){ + if (shiftdown === true){ + if ($("#" + id).hasClass('highlight')){ + $("#" + id).removeClass('highlight'); + }else { + $("#" + id).addClass('highlight'); + } + } else { + $("#" + id).addClass('highlight').siblings().removeClass('highlight'); + } + //console.log("selected:" +id); + + //.siblings(); +} + + +// function getTableSelectionID(){ +// var sel = $('#tbl_bookings').bootstrapTable('getSelections'); +// var id = null; + +// if (sel){ id=sel[0]._id; } +// console.log("Selected ID:" + id); +// return id; +// } + +// function getTableSelectionIDs(){ +// var sel = $('#tbl_bookings').bootstrapTable('getSelections'); +// var ids = []; +// if (sel){ +// for (var s in sel){ +// ids.push(s._id); +// } +// } +// return ids; +// } \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 1d78a78..7b1783d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -230,6 +230,12 @@ "integrity": "sha512-aUjdRFISbuFOl0EIZc+9e4FfZp0bDZgAdOOf30bJmw8VM9v84SHyVyxDfbWxpGYbdZD/9XoKxfHVNmxPkhwyGw==", "dev": true }, + "almond": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/almond/-/almond-0.3.3.tgz", + "integrity": "sha1-oOfJWsdiTWQXtElLHmi/9pMWiiA=", + "dev": true + }, "ansi-regex": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", @@ -1719,8 +1725,7 @@ "version": "2.1.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", - "dev": true, - "optional": true + "dev": true }, "aproba": { "version": "1.2.0", @@ -1744,15 +1749,13 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", - "dev": true, - "optional": true + "dev": true }, "brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", "dev": true, - "optional": true, "requires": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -1769,22 +1772,19 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=", - "dev": true, - "optional": true + "dev": true }, "concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", - "dev": true, - "optional": true + "dev": true }, "console-control-strings": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", "integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=", - "dev": true, - "optional": true + "dev": true }, "core-util-is": { "version": "1.0.2", @@ -1915,8 +1915,7 @@ "version": "2.0.3", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", - "dev": true, - "optional": true + "dev": true }, "ini": { "version": "1.3.5", @@ -1930,7 +1929,6 @@ "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", "dev": true, - "optional": true, "requires": { "number-is-nan": "^1.0.0" } @@ -1947,7 +1945,6 @@ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", "dev": true, - "optional": true, "requires": { "brace-expansion": "^1.1.7" } @@ -1956,15 +1953,13 @@ "version": "0.0.8", "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", - "dev": true, - "optional": true + "dev": true }, "minipass": { "version": "2.3.5", "resolved": "https://registry.npmjs.org/minipass/-/minipass-2.3.5.tgz", "integrity": "sha512-Gi1W4k059gyRbyVUZQ4mEqLm0YIUiGYfvxhF6SIlk3ui1WVxMTGfGdQ2SInh3PDrRTVvPKgULkpJtT4RH10+VA==", "dev": true, - "optional": true, "requires": { "safe-buffer": "^5.1.2", "yallist": "^3.0.0" @@ -1985,7 +1980,6 @@ "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", "dev": true, - "optional": true, "requires": { "minimist": "0.0.8" } @@ -2074,8 +2068,7 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=", - "dev": true, - "optional": true + "dev": true }, "object-assign": { "version": "4.1.1", @@ -2089,7 +2082,6 @@ "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", "dev": true, - "optional": true, "requires": { "wrappy": "1" } @@ -2185,8 +2177,7 @@ "version": "5.1.2", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true, - "optional": true + "dev": true }, "safer-buffer": { "version": "2.1.2", @@ -2228,7 +2219,6 @@ "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", "dev": true, - "optional": true, "requires": { "code-point-at": "^1.0.0", "is-fullwidth-code-point": "^1.0.0", @@ -2250,7 +2240,6 @@ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", "dev": true, - "optional": true, "requires": { "ansi-regex": "^2.0.0" } @@ -2299,15 +2288,13 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", - "dev": true, - "optional": true + "dev": true }, "yallist": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.0.3.tgz", "integrity": "sha512-S+Zk8DEWE6oKpV+vI3qWkaK+jSbIK86pCwe2IF/xwIpQ8jEuxpw9NyaGjmp9+BoJv5FV2piqCDcoCtStppiq2A==", - "dev": true, - "optional": true + "dev": true } } }, @@ -2720,6 +2707,12 @@ "integrity": "sha512-Ubldcmxp5np52/ENotGxlLe6aGMvmF4R8S6tZjsP6Knsaxd/xp3Zrh50cG93lR6nPXyUFwzN3ZSOQI0wRJNdGg==", "dev": true }, + "jquery-mousewheel": { + "version": "3.1.13", + "resolved": "https://registry.npmjs.org/jquery-mousewheel/-/jquery-mousewheel-3.1.13.tgz", + "integrity": "sha1-BvAzXxbjU6aV5yBr9QUDy1I6buU=", + "dev": true + }, "jsbn": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", @@ -4026,6 +4019,16 @@ "ajv-keywords": "^3.1.0" } }, + "select2": { + "version": "4.0.6-rc.1", + "resolved": "https://registry.npmjs.org/select2/-/select2-4.0.6-rc.1.tgz", + "integrity": "sha1-qmwwOKfw8ukf+t448KIcFeGBMnY=", + "dev": true, + "requires": { + "almond": "~0.3.1", + "jquery-mousewheel": "~3.1.13" + } + }, "semver": { "version": "5.6.0", "resolved": "https://registry.npmjs.org/semver/-/semver-5.6.0.tgz", diff --git a/package.json b/package.json index 8cf47cc..d91c3f1 100644 --- a/package.json +++ b/package.json @@ -17,6 +17,7 @@ "jquery": "^3.3.1", "pdfjs-dist": "^2.0.943", "popper.js": "^1.14.7", + "select2": "^4.0.6-rc.1", "tinymce": "^5.0.1", "tinymce-i18n": "^19.2.11", "webpack": "^4.29.4" diff --git a/renderer.js b/renderer.js index 25583a8..196da85 100644 --- a/renderer.js +++ b/renderer.js @@ -6,13 +6,17 @@ var usersystem = { var ppath=""; if (os.platform() == "darwin"){ ppath = os.homedir() + '/Library/Application Support/invoicejournal/'; - } else if (os.platform() == "Win32") { + } else if (os.platform() == "win32") { ppath = os.homedir() + '/AppData/Roaming/invoicejournal/'; } return ppath; }, - selectfile: function(dlgtitle,lastpath,filefilters=null){ - return dialog.showOpenDialog({title: dlgtitle,defaultPath: lastpath, filters: filefilters, properties: ['openFile'] }); + selectfile: function(dlgtitle,lastpath,filefilters=null,multiselect=false){ + var 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'] }); @@ -30,7 +34,8 @@ var usersystem = { dialog.showErrorBox(errtitle, errmsg); }, setPreference: function(key,data){ - //console.log("save preferences to: " + this.profilepath() + key + ".json"); + console.log("sset preference to: " + this.profilepath() + key + ".json"); + console.log(data); if ((typeof data == 'object') || (typeof data == 'array')){ data = JSON.stringify(data); } @@ -38,6 +43,7 @@ var usersystem = { return result; }, getPreference: function(key){ + console.log("getPreference:" + this.profilepath() + key + ".json"); var data = null; if (fs.existsSync(this.profilepath() + key + ".json")){ console.log("Read Key:" + key); @@ -51,6 +57,8 @@ var usersystem = { }, getLocalDataSets: function(){ var datasets =[]; + console.log(os.platform()); + console.log("ProfilePath:" + this.profilepath()); var files = fs.readdirSync(this.profilepath()); files.forEach(function(file) { if (file.match('db\..*\.json')){ diff --git a/server/Module/FileSystem.pm b/server/Module/FileSystem.pm new file mode 100644 index 0000000..bb3d150 --- /dev/null +++ b/server/Module/FileSystem.pm @@ -0,0 +1,315 @@ +package Module::FileSystem; + +use strict; +use warnings; +use parent qw(Plack::Component); +use Plack::Request; +use Data::Dumper; +use File::Find::Rule; +use File::Basename; +use JSON::PP; +use File::Path qw(make_path remove_tree); +use File::Copy; +use MIME::Types; +if ($^O eq "MSWin32"){ + eval('use Win32::File;'); +} + +sub call { + my($self, $env) = @_; + if (($env->{REMOTE_ADDR} =~ "^127\.0\.") && + ($env->{REMOTE_ADDR} =~ "^10\.") && + ($env->{REMOTE_ADDR} =~ "^172\.16\.") && + ($env->{REMOTE_ADDR} =~ "^192\.168\.")) { + return [ + 404, + [ 'Content-Type' => "text/html",'Cache-Control' => 'no-store, no-cache, must-revalidate' ], + [ "Sorry no remote access allowed!" ] + ]; + } + if ($env->{PATH_INFO} =~ /^\/search/){ + return $self->search($env); + } elsif ($env->{PATH_INFO} =~ /^\/directory/) { + return $self->directory($env); + } elsif ($env->{PATH_INFO} =~ /^\/file/) { + return $self->file($env); + } elsif ($env->{PATH_INFO} =~ /^\/userenv/){ + return $self->userenv($env); + } + return [ + 404, + [ 'Content-Type' => "text/html",'Cache-Control' => 'no-store, no-cache, must-revalidate' ], + [ "Unknown System Request!" ] + ]; +} + +sub search() { + my $self = shift; + my $env = shift; + my $html->{result} = (); + # $html->{docroot} = $self->{docpath}; + my $ct="application/json"; + my $status=200; + my $req = Plack::Request->new($env); + my $ff = File::Find::Rule->new; + if (exists($req->query_parameters->{name})){ + my $namesearch = $req->query_parameters->{name}; + $ff->name($req->query_parameters->{name}) + }elsif((exists($req->query_parameters->{namelist}))){ + my @nl = split(",",$req->query_parameters->{namelist}); + $ff->name(@nl); + } + if (exists($req->query_parameters->{type})){ + if ($req->query_parameters->{type} eq 'd'){ + $ff->directory; + } else { + $ff->file; + } + } + if (exists($req->query_parameters->{relative})){ + $ff->relative; + } + if (exists($req->query_parameters->{osspec})){ + $ff->canonpath; + } + my $spath = $self->{docpath}; + if (exists($req->query_parameters->{path})){ + + $spath = $self->{docpath}.'/'.$req->query_parameters->{path}; + $spath =~ s/..\///g; + } + my @data = $ff->in($spath); + if (exists($req->query_parameters->{sorted})){ + @data = sort {$a cmp $b} @data; + if ($req->query_parameters->{sorted} eq "desc"){ + @data = reverse(@data); + } + } + my $ret = undef; + # if (exists($req->query_parameters->{output}) && $req->query_parameters->{output} eq "text"){ + # $ct = "text/plain"; + # $ret = ""; + # foreach my $d (@data){ + # $ret .= $d."\n"; + # } + # } + # elsif (exists($req->query_parameters->{output}) && $req->query_parameters->{output} eq "fmlist"){ + # $ct = "text/plain"; + # $ret = ""; + # foreach my $d (@data){ + # $ret .= $d."\r"; + # } + # } + # else { + $html->{result} = \@data; + $ret = JSON::PP::encode_json($html); + # } + + return [ + 200, + [ 'Content-Type' => $ct,'Cache-Control' => 'no-store, no-cache, must-revalidate', 'Access-Control-Allow-Origin'=> '*' ], + [ $ret ] + ]; +} + +sub directory() { + my $self = shift; + my $env = shift; + my $html; + my $ct="application/json"; + my $status=200; + + my $req = Plack::Request->new($env); + if ($env->{PATH_INFO} =~ /^\/directory\/list/){ + my $mt = MIME::Types->new(); + $html->{result} = []; + my $dir=$self->{docpath}; + if (exists($req->query_parameters->{path})){ + $dir=$self->{docpath}.'/'.$req->query_parameters->{path}; + $dir =~ s/..\///g; + } + $html->{result} = {}; + if (-d $dir){ + my @dirs = (); + my @files = (); + opendir(LDIR,$dir); + while (my $f = readdir(LDIR)){ + if ($f =~ /^\./){ next; } + + if (-d $dir.'/'.$f){ + my $bok =1 ; + if ($^O eq "MSWin32"){ + eval ('my $attr; + Win32::File::GetAttributes($dir.\'/\'.$f,$attr); + if ($attr & HIDDEN){ + $bok = 0; + }'); + } + if ($bok == 1){ + push(@dirs,$f); + } + + } elsif (-f $dir.'/'.$f) { + my $bok =1 ; + if ($^O eq "MSWin32"){ + eval ('my $attr; + Win32::File::GetAttributes($dir.\'/\'.$f,$attr); + if ($attr & HIDDEN){ + $bok = 0; + }'); + } + if ($bok == 1){ + print $f."\n"; + my $fi->{name} = $f; + my $mtf = $mt->mimeTypeOf($f); + $fi->{mimetype} = (exists($mtf->{MT_simplified})?$mtf->{MT_simplified}:'unknown'); + + push(@files,$fi); + } + } + } + closedir(LDIR); + $html->{result}->{directory} = \@dirs; + $html->{result}->{file} = \@files; + } + + } + if ($env->{PATH_INFO} =~ /^\/directory\/exists/){ + $html->{result} = 0; + if (exists($req->query_parameters->{path})){ + if (-d $req->query_parameters->{path}){ + $html->{result} = 1; + } + } + } + if ($env->{PATH_INFO} =~ /^\/directory\/make/){ + make_path($req->query_parameters->{path}); + $html->{result} = 0; + if (-d $req->query_parameters->{path}){ + $html->{result} = 1; + } + } + if ($env->{PATH_INFO} =~ /^\/directory\/delete/){ + my $keep_root = 0; + if (exists($req->query_parameters->{keep_root})){ + $keep_root = 1; + } + $html->{result} = 0; + if (-d $req->query_parameters->{path}){ + remove_tree( $req->query_parameters->{path}, {keep_root => $keep_root} ); + $html->{result} = 1; + } + } + return [ + 200, + [ 'Content-Type' => $ct,'Cache-Control' => 'no-store, no-cache, must-revalidate', 'Access-Control-Allow-Origin'=> '*' ], + [ JSON::PP::encode_json($html) ] + ]; +} + +sub file() { + my $self = shift; + my $env = shift; + my $html->{result} = (); + my $ct="application/json"; + my $status=200; + + my $req = Plack::Request->new($env); + if ($env->{PATH_INFO} =~ /^\/file\/exists/){ + $html->{result} = 0; + if (exists($req->query_parameters->{path})){ + if (-f $req->query_parameters->{path}){ + $html->{result} = 1; + } + } + } +# if ($env->{PATH_INFO} =~ /^\/file\/choose/){ +# # A simple open file with graphic filers +# my ( @fss, $fss ); +# my ( @parms ); +# push @parms, +# -filter => [ 'PDF - fichiers PDF', '*.pdf' ], +# -directory => $ENV{HOME}, +# -title => 'selectionner un fichier PDF'; +# @fss = Win32::GUI::GetOpenFileName ( @parms ); +# if (scalar(@fss) > 0 ){ +# $html->{result} = \@fss; +# } +# } + if ($env->{PATH_INFO} =~ /^\/file\/write/){ + $html->{result} = 0; + if (exists($req->query_parameters->{path})){ + if (! -d (dirname($req->query_parameters->{path}))){ + make_path(dirname($req->query_parameters->{path})) + } + my $fwrite = ">"; + if (exists($req->query_parameters->{append})){ + $fwrite = ">>"; + } + my $datax = $req->body_parameters->{data}; + print $req->body_parameters->{data}."\n"; + open(WFI,$fwrite.$req->query_parameters->{path}); + print WFI $req->body_parameters->{data}; + close(WFI); + $html->{result} = 1; + } + } + if ($env->{PATH_INFO} =~ /^\/file\/read/){ + $html->{result} = ""; + if (exists($req->query_parameters->{path})){ + if (-f $req->query_parameters->{path}){ + my $rdata = ""; + open(RFI,$req->query_parameters->{path}); + while ( my $l = ){ + $rdata .= $l; + } + close(RFI); + $html->{result} = $rdata; + } + } + } + if ($env->{PATH_INFO} =~ /^\/file\/copy/){ + $html->{result} = ""; + if (exists($req->query_parameters->{src})){ + if (-f $req->query_parameters->{src}){ + my $dest = $req->query_parameters->{dest}; + if (! -d dirname($req->query_parameters->{dest})){ + make_path(dirname($req->query_parameters->{dest})) + } + if ($req->query_parameters->{src} ne $req->query_parameters->{dest}){ + my $cp = copy($req->query_parameters->{src},$req->query_parameters->{dest}); + $html->{result} = $cp; + } else { + $html->{result} = 1; + } + } + } + } + + return [ + 200, + [ 'Content-Type' => $ct,'Cache-Control' => 'no-store, no-cache, must-revalidate', 'Access-Control-Allow-Origin'=> '*' ], + [ JSON::PP::encode_json($html) ] + ]; +} + + +sub userenv() { + my $self = shift; + my $env = shift; + my $html->{result} = (); + my $ct="application/json"; + my $status=200; + + my $req = Plack::Request->new($env); + foreach my $k (keys(%ENV)){ + $html->{result}->{$k} = $ENV{$k}; + } + + return [ + 200, + [ 'Content-Type' => $ct,'Cache-Control' => 'no-store, no-cache, must-revalidate', 'Access-Control-Allow-Origin'=> '*' ], + [ JSON::PP::encode_json($html) ] + ]; +} +1; \ No newline at end of file diff --git a/server/Module/OpenVPN.pm b/server/Module/OpenVPN.pm new file mode 100644 index 0000000..4267ef6 --- /dev/null +++ b/server/Module/OpenVPN.pm @@ -0,0 +1,207 @@ +package Module::OpenVPN; + +use strict; +use warnings; +use parent qw(Plack::Component); +use Plack::Request; +use Data::Dumper; +use File::Find::Rule; +use File::Basename; +use JSON::PP; +use File::Copy; +use File::Path qw(make_path); + +sub call { + my($self, $env) = @_; + #$self->_app->($env); + if (($env->{REMOTE_ADDR} =~ "^127\.0\.") && + ($env->{REMOTE_ADDR} =~ "^10\.") && + ($env->{REMOTE_ADDR} =~ "^172\.16\.") && + ($env->{REMOTE_ADDR} =~ "^192\.168\.")) { + return [ + 404, + [ 'Content-Type' => "text/html",'Cache-Control' => 'no-store, no-cache, must-revalidate' ], + [ "Sorry no remote access allowed!" ] + ]; + } + if ($env->{PATH_INFO} =~ /^\/connect/){ + return $self->vpnconnect($env); + } elsif ($env->{PATH_INFO} =~ /^\/disconnect/){ + return $self->vpndisconnect($env); + } elsif ($env->{PATH_INFO} =~ /^\/installprofile/){ + return $self->vpninstallprofile($env); + } elsif ($env->{PATH_INFO} =~ /^\/listprofiles/){ + return $self->vpnprofilelist($env); + } + return [ + 404, + [ 'Content-Type' => "text/html",'Cache-Control' => 'no-store, no-cache, must-revalidate' ], + [ "Unknown System Request!" ] + ]; +} + +sub vpnconnect(){ + my $self = shift; + my $env = shift; + my $html->{result} = 0; + my $req = Plack::Request->new($env); + my $uprofile = ""; + #is gui or vpn running + + if (exists($req->query_parameters->{vpnprofile})){ + my $status = $self->vpnstatus(); + if (!exists($status->{active}->{$req->query_parameters->{vpnprofile}})){ + if ($^O eq "MSWin32"){ + if (exists($status->{gui})){ + system('taskkill.exe /F /IM openvpn.exe'); + system('taskkill.exe /F /IM openvpn-gui.exe'); + sleep(1); + } + my $st = system('start /b "" "C:\Program Files\OpenVPN\bin\openvpn-gui.exe" --connect '.$req->query_parameters->{vpnprofile}.'.ovpn'); + if ($st == 0){ + + my $bconn = 0; + my $i = 30; + while ($bconn == 0 || $i > 0){ + $status = $self->vpnstatus(); + if (exists($status->{active}->{$req->query_parameters->{vpnprofile}})){ + $html->{result} = $status; + $bconn = 1; + } + $i--; + sleep(1); + } + } + } + } else { + $html->{result} = $status; + } + } + return [ + 200, + [ 'Content-Type' => "application/json",'Cache-Control' => 'no-store, no-cache, must-revalidate', 'Access-Control-Allow-Origin'=> '*' ], + [ JSON::PP::encode_json($html) ] + ]; +} + +sub vpnstatus(){ + my $self = shift; + my $status = (); + if ($^O eq "MSWin32"){ + + my $tasklist = `tasklist`; + my @task = split("\n",$tasklist); + my @ovpntasks = grep(/openvpn-gui\.exe/,@task); + if (scalar(@ovpntasks) > 0){ + $status->{gui} = "running"; + } + @ovpntasks = grep(/openvpn.exe/,@task); + #$status->{active_connections} = scalar(@ovpntasks); + if (scalar(@ovpntasks) > 0){ + my $ff = File::Find::Rule->new(); + $ff->file; + $ff->name('*.log'); + my @loglist =$ff->in($ENV{USERPROFILE}.'/OpenVPN/log'); + foreach my $c (@loglist){ + open(CLOG,$c); + my @data = ; + close(CLOG); + my $laststate=$data[scalar(@data)-1]; + chomp($laststate); + if ($laststate =~ /CONNECTED/){ + my ($time,$ip,$server,$port) = $laststate =~ /.+MANAGEMENT:\s>STATE:(\d+),CONNECTED,SUCCESS,(.+),(.+),(.+),,$/; + if (!exists($status->{connection}->{$ip})){ + $status->{connection}->{$ip}->{config} = substr(basename($c),0,-4);; + $status->{connection}->{$ip}->{server} = $server; + $status->{connection}->{$ip}->{port} = $port; + $status->{connection}->{$ip}->{connected_since} = $time; + }else { + if ($time >= $status->{connection}->{$ip}->{connected_since}){ + $status->{connection}->{$ip}->{config} = substr(basename($c),0,-4); + $status->{connection}->{$ip}->{server}= $server; + $status->{connection}->{$ip}->{port} = $port; + $status->{connection}->{$ip}->{connected_since} = $time; + } + } + } + } + my @notactive = (); + my $active = (); + foreach my $c (keys(%{$status->{connection}})){ + my $routeslist = `route print -4`; + my @routes = split("\n",$routeslist); + my @activetest = grep(/$c/,@routes); + if (scalar(@activetest) == 0){ + push @notactive,$c; + } else { + $active->{$status->{connection}->{$c}->{config}} = $c; + } + } + foreach my $na (@notactive){ + delete $status->{connection}->{$na}; + } + $status->{active} = $active; + } + } + return $status; +} + +sub vpndisconnect(){ + my $self = shift; + my $env = shift; + my $html->{result} = 1; + if ($^O eq "MSWin32"){ + system('taskkill.exe /F /IM openvpn.exe'); + system('taskkill.exe /F /IM openvpn-gui.exe'); + } + return [ + 200, + [ 'Content-Type' => "application/json",'Cache-Control' => 'no-store, no-cache, must-revalidate', 'Access-Control-Allow-Origin'=> '*' ], + [ JSON::PP::encode_json($html) ] + ]; +} + +sub vpninstallprofile(){ + my $self = shift; + my $env = shift; + my $req = Plack::Request->new($env); + my $html->{result} = 0; + if ($^O eq "MSWin32"){ + if ( ! -d $ENV{USERPROFILE}.'/OpenVPN'){ + make_path($ENV{USERPROFILE}.'/OpenVPN'); + } + if (exists($req->query_parameters->{vpnprofile}) && (-e $req->query_parameters->{vpnprofile}) && ($req->query_parameters->{vpnprofile} =~ /\.ovpn$/)){ + copy(req->query_parameters->{vpnprofile},$ENV{USERPROFILE}.'/OpenVPN/'.basename($req->query_parameters->{vpnprofile})); + $html->{result} = 1; + } + } + return [ + 200, + [ 'Content-Type' => "application/json",'Cache-Control' => 'no-store, no-cache, must-revalidate', 'Access-Control-Allow-Origin'=> '*' ], + [ JSON::PP::encode_json($html) ] + ]; +} + +sub vpnprofilelist(){ + my $self = shift; + my $env = shift; + my $html->{result} = (); + if ($^O eq "MSWin32"){ + my $ff = File::Find::Rule->new(); + $ff->file; + $ff->name('*.ovpn'); + my @vpnlist =$ff->in($ENV{USERPROFILE}.'/OpenVPN'); + foreach (my $p=0;$p{result} = \@vpnlist; + } + return [ + 200, + [ 'Content-Type' => "application/json",'Cache-Control' => 'no-store, no-cache, must-revalidate', 'Access-Control-Allow-Origin'=> '*' ], + [ JSON::PP::encode_json($html) ] + ]; +} + + +1; \ No newline at end of file diff --git a/server/Module/PDFExtract.pm b/server/Module/PDFExtract.pm new file mode 100644 index 0000000..393a1f9 --- /dev/null +++ b/server/Module/PDFExtract.pm @@ -0,0 +1,264 @@ +package Module::PDFExtract; + +use strict; +use warnings; +use parent qw(Plack::Component); +use Plack::Request; +use File::Basename; +use Data::Dumper; +use PDF::API2; +use File::Path qw/make_path/; + +sub call { + my($self, $env) = @_; + #$self->_app->($env); + my $html->{result} = "unknown function"; + if (($env->{REMOTE_ADDR} =~ "^127\.0\.") && + ($env->{REMOTE_ADDR} =~ "^10\.") && + ($env->{REMOTE_ADDR} =~ "^172\.16\.") && + ($env->{REMOTE_ADDR} =~ "^192\.168\.")) { + return [ + 404, + [ 'Content-Type' => "text/html",'Cache-Control' => 'no-store, no-cache, must-revalidate' ], + [ "Sorry no remote access allowed!" ] + ]; + } + # if ($env->{PATH_INFO} =~ /^\/pdfsplit/){ + # return $self->pdfsplit($env); + # } + # if ($env->{PATH_INFO} =~ /^\/pdfpagenumbers/){ + # return $self->pdfpagesnumbers($env); + # } +# if ($env->{PATH_INFO} =~ /^\/pdfextract/){ +# return $self->pdfextract($env); +# } + if ($env->{PATH_INFO} =~ /^\/parse/){ + return $self->parsestatement($env); + } + # if ($env->{PATH_INFO} =~ /^\/parsestatement/){ + # return $self->parsestatement($env); + # } + return [ + 404, + [ 'Content-Type' => 'text/html','Cache-Control' => 'no-store, no-cache, must-revalidate' , 'Access-Control-Allow-Origin'=> '*'], + [ "unknown function" ] + ]; +} + +# sub pdfpagesnumbers(){ +# my $self = shift; +# my $env = shift; +# my $ct="application/json"; +# my $status=200; +# my $req = Plack::Request->new($env); +# my $html->{result}->{pagenumbers} = 0; +# if (exists($req->query_parameters->{file}) && ($req->query_parameters->{file} =~ /\.pdf$/)){ +# my $pdf = PDF::API2->open($req->query_parameters->{file}); +# $html->{result}->{pagenumbers} = $pdf->pages; +# } +# return [ +# 200, +# [ 'Content-Type' => $ct,'Cache-Control' => 'no-store, no-cache, must-revalidate' , 'Access-Control-Allow-Origin'=> '*'], +# [ JSON::PP::encode_json($html) ] +# ]; +# } + +# sub pdfsplit(){ +# my $self = shift; +# my $env = shift; +# my $html->{result} = (); +# my $ct="application/json"; +# my $status=200; +# my $req = Plack::Request->new($env); +# my @nfiles = (); +# my $outputdir = $ENV{TEMP}; +# if (exists($req->query_parameters->{file}) && exists($req->query_parameters->{prefix})){ +# my $basepdf = basename($req->query_parameters->{file}); +# $outputdir =~ s/\\/\//g; + +# my $oldpdf = PDF::API2->open($req->query_parameters->{file}); +# my $xx = $oldpdf->pages; +# for my $page_nb (1..$xx) { +# my $newpdf = PDF::API2->new; +# my $page = $newpdf->importpage($oldpdf, $page_nb); + +# my $npdfname = $outputdir.'/'.$req->query_parameters->{prefix}.substr($basepdf,0,-4).".".$page_nb.".pdf"; +# push @nfiles,$npdfname; +# if (-e $npdfname){ unlink($npdfname); } +# $newpdf->saveas($npdfname); +# } +# } +# foreach my $n (@nfiles){ +# my $r = $self->pdfextract($n); +# } +# $html->{result}->{files} = \@nfiles; +# return [ +# 200, +# [ 'Content-Type' => $ct,'Cache-Control' => 'no-store, no-cache, must-revalidate' , 'Access-Control-Allow-Origin'=> '*'], +# [ JSON::PP::encode_json($html) ] +# ]; +# }; + +sub pdfextract(){ + my $self = shift; + my $file = shift; +# my $html->{result} = (); +# my $ct="application/json"; +# my $status=200; +# my $req = Plack::Request->new($env); + my $pdftotext; + my $sep = "/"; + if ($^O eq "MSWin32") { + $sep = "\\"; + $pdftotext=dirname($0).$sep.'pdftotext.exe'; + }else { + $pdftotext=dirname($0).$sep.'pdftotext'; + } + if (-e $file.'.txt'){ + unlink($file.'.txt'); + } + my $cmd = 'start /b "" "'.$pdftotext.'" -q -table -eol unix "'.$file.'" "'.$file.'.txt"'; + my $st = `$cmd`;#'system(1,$cmd)' ; + #print $cmd."->".$st."\n"; + return $st; +} + + +sub parsestatement(){ + my $self = shift; + my $env = shift; + my $html->{result} = (); + my $req = Plack::Request->new($env); + my $ct="application/json"; + my $status=200; + my $file = $self->{docpath}.'/'.$req->query_parameters->{file}; + if (! -e $file){ + $html->{error}->{msg} = "file: ".$file." does not exist!"; + return [ + 200, + [ 'Content-Type' => $ct,'Cache-Control' => 'no-store, no-cache, must-revalidate' , 'Access-Control-Allow-Origin'=> '*'], + [ JSON::PP::encode_json($html) ] + ]; + } + + + + my $pxdata = (); + my @pdata = (); + my $jdata = (); + if (-e $file){ + my $st = $self->pdfextract($file); + + if (($st == 0) && (-e $file.".txt")){ + open(PDFDATA,$file.".txt"); + while (my $l = ) { + chomp($l); + if ($l ne "") {push @pdata,$l;} + } + close(PDFDATA); + } + my $caccount = ""; + my $stmtnum = ""; + my $r = 0; + my $cpos = ""; + foreach my $p (@pdata){ + if ($p =~ /^\s+Konto\s+:/ ) { + $cpos = ""; + ($caccount) = $p =~ m/.+IBAN\s+(.+)$/; + next; + }elsif ($p =~ /Kontoauszug Nr\./){ + $cpos = ""; + ($stmtnum) = $p =~ m/^Kontoauszug Nr\.\s(\d+).+$/; + next; + }elsif ($p =~ /^\d\d\.\d\d\s+[GUT|UEBER|SEPA]/){ + $cpos = ""; + $r++; + my ($type,$trdate,$trval,$trsign) = $p =~ m/\d\d\.\d\d\s+(.+)\s+(\d\d\.\d\d\.\d\d)\s+([\d|,|\.]+)\s([+|-])$/; + $type =~ s/\s//g; + $trsign =~ s/\+//; + $trval=~ s/\.//g; + $trdate = substr($trdate,0,6).'20'.substr($trdate,-2); + $jdata->{$r}->{"Account"} = $caccount; + $jdata->{$r}->{"StatementNumber"} = $stmtnum; + $jdata->{$r}->{"BookingDate"} = $trdate; + $jdata->{$r}->{"Amount"} = $trsign.$trval; + $jdata->{$r}->{"TransactionIdent"} = ""; + $jdata->{$r}->{"Message"} = ""; + $jdata->{$r}->{"ForeignAccountOwner"} = ""; + $jdata->{$r}->{"Bank"} = ""; + $jdata->{$r}->{"TransferAccount"} = ""; + $jdata->{$r}->{"TransferCosts"} = 0; + #$jdata->{$r}->{"BookingType"} = $type; + next; + }elsif ($p =~ /^\s+Unser Zeichen/){ + $cpos = "TransactionIdent"; + my ($trid) = $p =~ m/^\s+Unser Zeichen\s+(.+)$/; + $jdata->{$r}->{$cpos} =$trid; + }elsif ($p =~ /^\s+Mitteilung/){ + $cpos = "Message"; + my ($msg) = $p =~ m/^\s+Mitteilung\s+(.+)$/; + $jdata->{$r}->{$cpos} = $msg; + }elsif ($p =~ /^\s+Auftraggeber/){ + $cpos = "ForeignAccountOwner"; + my ($apl) = $p =~ /^\s+Auftraggeber\s+(.+)$/; + $apl =~ s/\s+/\ /g; + $jdata->{$r}->{$cpos} =$apl; + }elsif ($p =~ /^\s+Bank d. Auftr.gebers/){ + $cpos = ""; + }elsif ($p =~ /^\s+BIC-Code Bank d. Auftraggebers/){ + $cpos = "Bank"; + my ($trfbank) = $p =~ /^\s+BIC-Code\sBank\sd\.\sAuftraggebers\s+(.+)$/; + $jdata->{$r}->{$cpos} =$trfbank; + }elsif ($p =~ /^\s+End-to-End-Identifizierung/){ + $cpos = ""; + }elsif ($p =~ /^\s+Beg.nstigter/){ + $cpos = "ForeignAccountOwner"; + my ($recp) = $p =~ /^\s+Beg.nstigter\s+(.+)$/; + $recp =~ s/\s+/\ /g; + $jdata->{$r}->{$cpos} =$recp; + $cpos=""; + }elsif ($p =~ /^\s+Konto Nr. Beg.nst./){ + $cpos = "TransferAccount"; + + my ($trfacc) = $p =~ /^\s+Konto\sNr\.\sBeg.nst.\s+(.+)$/; + $trfacc =~ s/\///g; + $trfacc =~ s/(....)/$1 /sg; + $trfacc =~ s/\s+$//; + $jdata->{$r}->{$cpos} =$trfacc; + $cpos=""; + }elsif ($p =~ /^\s+bei/){ + $cpos = ""; + }elsif ($p =~ /^\s+Transfergeb.hr/){ + $cpos = "TransferCosts"; + my ($tramount) = $p =~ /^\s+Transfergeb.hr\s+EUR\s+(.+)$/; + $tramount =~ s/\,/\./g; + $jdata->{$r}->{$cpos} =$tramount; + }elsif ($p =~ /^\s+Durch Ihren Bonus abgedeckt/){ + $cpos = "TransferCosts"; + my ($tramount) = $p =~ /^\s+Durch Ihren Bonus abgedeckt\s+EUR\s+(.+)$/; + $tramount =~ s/\,/\./g; + $jdata->{$r}->{$cpos} = $jdata->{$r}->{$cpos} + $tramount; + }elsif ($p =~ /^\s+Zeichen/){ + $cpos = ""; + } elsif ($p =~ /^\s+Neuer Kontostand/){ + $cpos=""; + }elsif ($cpos ne "") { + my ($data) = $p =~ m/\s+(.+)$/; + $jdata->{$r}->{$cpos} .= " ".$data; + } + } + + } + if (-e $file.'.txt'){ + unlink($file.'.txt'); + } + $html->{result} = $jdata; + return [ + 200, + [ 'Content-Type' => $ct,'Cache-Control' => 'no-store, no-cache, must-revalidate' , 'Access-Control-Allow-Origin'=> '*'], + [ JSON::PP::encode_json($html) ] + ]; +} + + +1; \ No newline at end of file diff --git a/server/Module/PDFExtract_checkservice.pm b/server/Module/PDFExtract_checkservice.pm new file mode 100644 index 0000000..018361d --- /dev/null +++ b/server/Module/PDFExtract_checkservice.pm @@ -0,0 +1,409 @@ +package Module::PDFExtract; + +use strict; +use warnings; +use parent qw(Plack::Component); +use Plack::Request; +use File::Basename; +use Data::Dumper; +use PDF::API2; +use File::Path qw/make_path/; + +sub call { + my($self, $env) = @_; + #$self->_app->($env); + my $html->{result} = "unknown function"; + if (($env->{REMOTE_ADDR} =~ "^127\.0\.") && + ($env->{REMOTE_ADDR} =~ "^10\.") && + ($env->{REMOTE_ADDR} =~ "^172\.16\.") && + ($env->{REMOTE_ADDR} =~ "^192\.168\.")) { + return [ + 404, + [ 'Content-Type' => "text/html",'Cache-Control' => 'no-store, no-cache, must-revalidate' ], + [ "Sorry no remote access allowed!" ] + ]; + } + if ($env->{PATH_INFO} =~ /^\/pdfsplit/){ + return $self->pdfsplit($env); + } + if ($env->{PATH_INFO} =~ /^\/pdfpagenumbers/){ + return $self->pdfpagesnumbers($env); + } +# if ($env->{PATH_INFO} =~ /^\/pdfextract/){ +# return $self->pdfextract($env); +# } + if ($env->{PATH_INFO} =~ /^\/parsedata/){ + return $self->parsedata($env); + } + if ($env->{PATH_INFO} =~ /^\/parsestatement/){ + return $self->parsestatement($env); + } + return [ + 404, + [ 'Content-Type' => 'text/html','Cache-Control' => 'no-store, no-cache, must-revalidate' , 'Access-Control-Allow-Origin'=> '*'], + [ "unknown function" ] + ]; +} + +sub pdfpagesnumbers(){ + my $self = shift; + my $env = shift; + my $ct="application/json"; + my $status=200; + my $req = Plack::Request->new($env); + my $html->{result}->{pagenumbers} = 0; + if (exists($req->query_parameters->{file}) && ($req->query_parameters->{file} =~ /\.pdf$/)){ + my $pdf = PDF::API2->open($req->query_parameters->{file}); + $html->{result}->{pagenumbers} = $pdf->pages; + } + return [ + 200, + [ 'Content-Type' => $ct,'Cache-Control' => 'no-store, no-cache, must-revalidate' , 'Access-Control-Allow-Origin'=> '*'], + [ JSON::PP::encode_json($html) ] + ]; +} + +sub pdfsplit(){ + my $self = shift; + my $env = shift; + my $html->{result} = (); + my $ct="application/json"; + my $status=200; + my $req = Plack::Request->new($env); + my @nfiles = (); + my $outputdir = $ENV{TEMP}; + if (exists($req->query_parameters->{file}) && exists($req->query_parameters->{prefix})){ + my $basepdf = basename($req->query_parameters->{file}); + $outputdir =~ s/\\/\//g; + + my $oldpdf = PDF::API2->open($req->query_parameters->{file}); + my $xx = $oldpdf->pages; + for my $page_nb (1..$xx) { + my $newpdf = PDF::API2->new; + my $page = $newpdf->importpage($oldpdf, $page_nb); + + my $npdfname = $outputdir.'/'.$req->query_parameters->{prefix}.substr($basepdf,0,-4).".".$page_nb.".pdf"; + push @nfiles,$npdfname; + if (-e $npdfname){ unlink($npdfname); } + $newpdf->saveas($npdfname); + } + } + foreach my $n (@nfiles){ + my $r = $self->pdfextract($n); + } + $html->{result}->{files} = \@nfiles; + return [ + 200, + [ 'Content-Type' => $ct,'Cache-Control' => 'no-store, no-cache, must-revalidate' , 'Access-Control-Allow-Origin'=> '*'], + [ JSON::PP::encode_json($html) ] + ]; +}; + +sub pdfextract(){ + my $self = shift; + my $file = shift; +# my $html->{result} = (); +# my $ct="application/json"; +# my $status=200; +# my $req = Plack::Request->new($env); + my $pdftotext; + my $sep = "/"; + if ($^O eq "MSWin32") { + $sep = "\\"; + $pdftotext=dirname($0).$sep.'pdftotext.exe'; + }else { + $pdftotext=dirname($0).$sep.'pdftotext'; + } + if (-e $file.'.txt'){ + unlink($file.'.txt'); + } + my $cmd = 'start /b "" "'.$pdftotext.'" -q -table -eol unix "'.$file.'" "'.$file.'.txt"'; + my $st = `$cmd`;#'system(1,$cmd)' ; + #print $cmd."->".$st."\n"; + return $st; +} + +sub parsedata(){ + my $self = shift; + my $env = shift; + my $req = Plack::Request->new($env); + if (exists($req->query_parameters->{type}) && exists($req->query_parameters->{file})){ + if ($req->query_parameters->{type} eq "inv"){ + return $self->parseinvoice($req->query_parameters->{file}); + } elsif ($req->query_parameters->{type} eq "invold"){ + return $self->parseoldinvoice($req->query_parameters->{file}); + } elsif ($req->query_parameters->{type} eq "stmt") { + return $self->parsestatement($req->query_parameters->{file}); + } else { + return [ + 404, + [ 'Content-Type' => 'text/html','Cache-Control' => 'no-store, no-cache, must-revalidate' , 'Access-Control-Allow-Origin'=> '*'], + [ "unknown function" ] + ]; + } + } +} + +sub parseinvoice(){ + my $self = shift; + my $file = shift; + my $html->{result} = (); + my $ct="application/json"; + my $status=200; + my $pxdata = (); + if (-e $file){ + my @invoicedata = (); + open(EXT,$file); + while (my $l = ){ + chomp($l); + push(@invoicedata,$l); + } + close(EXT); + foreach my $p (@invoicedata){ + if ($p =~ /^N. Facture/) { + my ($tmp) = $p =~ m/.+\s(\d{4,}.\d{1,2}.\d{4,})\s.+$/; + $pxdata->{reference} = $tmp; + } + if ($p =~ /^Date de la facture/) { + my ($d,$m,$y) = $p =~ m/.+\s(\d{1,2}).(\d{1,2}).(\d{4,}).+$/; + if (length($d) == 1) { $d = "0".$d;} + if (length($m) == 1) { $m = "0".$m;} + $pxdata->{invoicedate} = $y.'-'.$m.'-'.$d; + } +# if (($p =~ /facture/) && ($pxdata->{invoicedate} eq "--")) { +# my ($d,$m,$y) = $p =~ m/.+\s(\d{1,2}).(\d{1,2}).(\d{4,})$/; +# if (length($d) == 1) { $d = "0".$d;} +# if (length($m) == 1) { $m = "0".$m;} +# $pxdata->{invoicedate} = $y.'-'.$m.'-'.$d; +# } + if ($p =~ /^Enfant/) { + my ($tmp) = $p =~ m/.+\s\((\d+)\).+$/; + $pxdata->{checkservice} = $tmp; + } + if (($p =~ /^\s+\(\d+\)$/) && (!defined($pxdata->{checkservice}))) { + my ($tmp) = $p =~ m/\s+\((\d+)\)$/; + $pxdata->{checkservice} = $tmp; + } + if ($p =~ /Heures.+\sh\s/) { + my ($hrs,$p1,$e1) = $p =~ m/.+Heures.+\s+([\s|\d]+,\d{1,2})\sh\s+([\s|\d]+,\d{1,2})\s+([\s|\d]+,\d{1,2}).+$/; + $p1 =~ s/,/\./; + $e1 =~ s/,/\./; + $p1 =~ s/\ //; + $e1 =~ s/\ //; + if (exists($pxdata->{hoursamount})){ + $pxdata->{hoursamount} = $pxdata->{hoursamount} + $p1 + $e1; + } else { + $pxdata->{hoursamount} = $p1 + $e1; + } + + } + if ($p =~ /Repas/) { + my ($rn,$p1,$e1) = $p =~ m/.+Repas.+\s+(\d+)\s+([\s|\d]+,\d{1,2})\s+([\s|\d]+,\d{1,2}).+$/; + $p1 =~ s/,/\./; + $e1 =~ s/,/\./; + $p1 =~ s/\ //; + $e1 =~ s/\ //; + $pxdata->{lunchnum} = $rn; + $pxdata->{lunchamount} = $p1 + $e1; + } + if ($p =~ /Participation totale de l.Etat/){ + my ($e1) = $p =~ m/.+Participation totale de l.Etat\s+([\s|\d]+,\d{1,2}).+$/; + $e1 =~ s/,/\./; + $e1 =~ s/\ //; + $pxdata->{benefitamount} = $e1; + } + if ($p =~ /Montant\s.\sr.gler/) { + my ($m1) = $p =~ m/.+Montant.+\s+([\s|\d]+,\d{1,2}).+$/; + $m1 =~ s/,/\./; + $m1 =~ s/\ //; + $pxdata->{totalamount} = $m1; + } + #print Dumper(@pdata); + } + } + $html->{result} = $pxdata; + return [ + 200, + [ 'Content-Type' => $ct,'Cache-Control' => 'no-store, no-cache, must-revalidate' , 'Access-Control-Allow-Origin'=> '*'], + [ JSON::PP::encode_json($html) ] + ]; +} + +sub parseoldinvoice(){ + my $self = shift; + my $file = shift; + my $html->{result} = (); + my $ct="application/json"; + my $status=200; + my $pxdata = (); + if (-e $file){ + my @invoicedata = (); + open(EXT,$file); + while (my $l = ){ + chomp($l); + push(@invoicedata,$l); + } + close(EXT); + foreach my $p (@invoicedata){ + if ($p =~ /N. Facture/) { + my ($tmp) = $p =~ m/.+\s(\d{4,}.\d{1,2}.\d{4,})\s.+$/; + $pxdata->{reference} = $tmp; + } + if ($p =~ /Date de la/) { + my ($d,$m,$y) = $p =~ m/.+\s(\d{1,2}).(\d{1,2}).(\d{4,})$/; + if (length($d) == 1) { $d = "0".$d;} + if (length($m) == 1) { $m = "0".$m;} + $pxdata->{invoicedate} = $y.'-'.$m.'-'.$d; + } + if (($p =~ /facture/) && ($pxdata->{invoicedate} eq "--")) { + my ($d,$m,$y) = $p =~ m/.+\s(\d{1,2}).(\d{1,2}).(\d{4,})$/; + if (length($d) == 1) { $d = "0".$d;} + if (length($m) == 1) { $m = "0".$m;} + $pxdata->{invoicedate} = $y.'-'.$m.'-'.$d; + } + if ($p =~ /Carte N./) { + my ($tmp) = $p =~ m/.+\s(\d+)$/; + $pxdata->{checkservice} = $tmp; + } + if ($p =~ /Heure/) { + my ($tmp1,$tmp2) = $p =~ m/.+\s(\d+).(\d+)+$/; + $pxdata->{hoursamount} = $tmp1.'.'.$tmp2; + } + if ($p =~ /Repas/) { + my ($tmp1,$tmp2) = $p =~ m/.+\s(\d+).(\d+)+$/; + $pxdata->{lunchamount} = $tmp1.'.'.$tmp2; + } + if ($p =~ /Montant\s.\spayer/) { + my ($tmp1,$tmp2) = $p =~ m/.+\s(\d+).(\d+)+$/; + $pxdata->{totalamount} = $tmp1.'.'.$tmp2; + } + #print Dumper(@pdata); + } + } + $html->{result} = $pxdata; + return [ + 200, + [ 'Content-Type' => $ct,'Cache-Control' => 'no-store, no-cache, must-revalidate' , 'Access-Control-Allow-Origin'=> '*'], + [ JSON::PP::encode_json($html) ] + ]; +} + +sub parsestatement(){ + my $self = shift; + my $file = shift; + my $html->{result} = (); + my $ct="application/json"; + my $status=200; + my $sxdata = (); + my $cmonth = "none"; + my $frmonth = {"Janvier" => '01',"F�vrier"=> '02',"Mars" => '03',"Avril" => '04', "Mai" => '05',"Juin" => '06',"Juillet" => '07',"Ao�t" => '08',"Septembre" => '09',"Octobre" => '10',"Novembre" => '11',"D�cembre" => '12'}; + if (-e $file){ + my @xstmtdata = (); + open(EXT,$file); + while (my $l = ){ + chomp($l); + push(@xstmtdata,$l); + } + close(EXT); + my $sxdata = (); + + foreach my $p (@xstmtdata){ + if ($p =~ /P.riode/) { + my ($m1,$y1,$m2,$y2) = $p =~ m/.+\s(.+)\s+(\d+)\s+.\s+(.+)\s+(\d+)$/; + if (($m1 eq $m2) && ($y1 eq $y2)){ + $cmonth=$y1.'-'.$frmonth->{$m1}; + } + } + if ($p =~ /\d{13,}/) { + my ($csnum,$am) = $p =~ m/.+\s+(\d{13,})\s+([\d|\ |,]+)$/; + $am =~ s/\s+//; + $am =~ s/,/./; + $sxdata->{$cmonth}->{$csnum}=$am; + } + } + } + $html->{result} = $sxdata; + return [ + 200, + [ 'Content-Type' => $ct,'Cache-Control' => 'no-store, no-cache, must-revalidate' , 'Access-Control-Allow-Origin'=> '*'], + [ JSON::PP::encode_json($html) ] + ]; +} + + +# +#sub importstatementdata(){ +# my $simpdata = shift; +# my $fname = shift; +# #print Dumper($simpdata); +# my $n=0; +# foreach my $m (keys(%{$simpdata})){ +# $n++; +# if (-e dirname($fname).$sep."prestation.".$m."-".$n.".pdf"){ +# unlink(dirname($fname).$sep."prestation.".$m."-".$n.".pdf"); +# } +# rename($fname,dirname($fname).$sep."prestation.".$m."-".$n.".pdf"); +# foreach my $csnum (keys(%{$simpdata->{$m}})){ +# $simpdata->{$m}->{fnum} = $n; +# } +# } +# foreach my $m (keys(%{$simpdata})){ +# $n++; +# if ($m =~ /\d{4,}-\d{2,}/) { +# foreach my $csnum (keys(%{$simpdata->{$m}})){ +# print "Import Check-Service no: " + $csnum + "\n"; +# if (defined($db)){ +# my $child = $db->dbquerysorted("select uuid from childs where replace(checkservicenumber,' ','') = '".$csnum."';"); +# if (keys(%{$child}) == 1) { +# my $accdata = $db->dbquerysorted("select accmonth,childuuid from accounting where childuuid='".$child->{0}->{uuid}."' and accmonth=date('".substr($m,0,4).'-'.substr($m,5,2)."-01');"); +# if (keys(%{$accdata}) == 1) { +# #make update +# my @upd = (); +# push @upd,"benefitamount='".$simpdata->{$m}->{$csnum}."'"; +# push @upd,"benefitfile='prestation.".$m."-".$simpdata->{$m}->{fnum}.".pdf'"; +# my $sql = "update accounting set ".join(',',@upd)." where childuuid='".$child->{0}->{uuid}."' and accmonth=date('".substr($m,0,4).'-'.substr($m,5,2)."-01');"; +# #print $sql."\n"; +# my $r = $db->dbexec($sql); +# if (($log ne "") && (-e $log)){ +# if (!defined($r)) { +# open(LOG,">>".$log); +# print LOG localtime().":ERROR:".$sql."\n"; +# close(LOG); +# } else { +# open(LOG,">>".$log); +# print LOG localtime().":SUCCESS:".$sql."\n"; +# close(LOG); +# } +# } +# }else { +# my @ins1 = (); +# my @ins2 = (); +# push(@ins1,"accmonth");push (@ins2,"date('".substr($m,0,4).'-'.substr($m,5,2)."-01')"); +# push(@ins1,"childuuid");push (@ins2,"'".$child->{0}->{uuid}."'"); +# push(@ins1,"benefitamount");push (@ins2,"".$simpdata->{$m}->{$csnum}.""); +# push(@ins1,"benefitfile");push (@ins2,"'prestation.".$m."-".$simpdata->{$m}->{fnum}.".pdf'"); +# +# #accmonth,childuuid,invoicedate,invoiceamount,reference +# my $sql = "insert into accounting (".join(',',@ins1).") VALUES (".join(',',@ins2).");"; +# #print $sql."\n"; +# my $r = $db->dbexec($sql); +# if (($log ne "") && (-e $log)){ +# if (!defined($r)) { +# open(LOG,">>".$log); +# print LOG localtime().":ERROR:".$sql."\n"; +# close(LOG); +# } else { +# open(LOG,">>".$log); +# print LOG localtime().":SUCCESS:".$sql."\n"; +# close(LOG); +# } +# } +# } +# } +# } +# } +# } +# } +#} + +1; \ No newline at end of file diff --git a/server/Module/SQLite.pm b/server/Module/SQLite.pm new file mode 100644 index 0000000..741743a --- /dev/null +++ b/server/Module/SQLite.pm @@ -0,0 +1,255 @@ +package Module::SQLite; + +use strict; +use warnings; +use parent qw(Plack::Component); +use Plack::Request; +use File::Basename; +#use Data::Dumper; +use DBI; +use DBD::SQLite; +use Encode; +use JSON::PP; + +sub call { + my($self, $env) = @_; + if (($env->{REMOTE_ADDR} =~ "^127\.0\.") && + ($env->{REMOTE_ADDR} =~ "^10\.") && + ($env->{REMOTE_ADDR} =~ "^172\.16\.") && + ($env->{REMOTE_ADDR} =~ "^192\.168\.")) { + return [ + 404, + [ 'Content-Type' => "text/html",'Cache-Control' => 'no-store, no-cache, must-revalidate' ], + [ "Sorry no remote access allowed!" ] + ]; + } + #$self->_app->($env); + return $self->sqlite($env); +} + +sub sqlite { + my $self = shift; + my $env = shift; + my $html->{result} = (); + my $ct="application/json"; + my $status=200; + my $req = Plack::Request->new($env); + my $res = (); + #print $req->query_parameters->{db}.":".$req->query_parameters->{type}.":".decode_base64($req->query_parameters->{sql})."\n------------------\n"; + + if ($env->{PATH_INFO} =~ /^\/\w+/){ + $self->{dbfile} = $self->{'dbpath'}.'/'.basename($env->{PATH_INFO}).'.sqlite'; + $html->{req}->{db} = $self->{'dbpath'}.'/'.basename($env->{PATH_INFO}).'.sqlite'; + }else { + if (exists($req->body_parameters->{db})){ + $self->{dbfile} = $req->body_parameters->{db}; + $html->{req}->{db} = $req->body_parameters->{db}; + } else { + return [ + 400, + [ 'Content-Type' => $ct.'; charset=utf-8','Cache-Control' => 'no-store, no-cache, must-revalidate', 'Access-Control-Allow-Origin'=> '*' ], + [ JSON::PP::encode_json($html) ] + ]; + } + } + + $html->{req}->{type} = $req->body_parameters->{type}; + $html->{req}->{sql} = $req->body_parameters->{sql}; + #$html->{req}->{sqldecoded} = $req->query_parameters->{sql}; + if (exists($req->body_parameters->{sql}) && exists($req->body_parameters->{type})) { + #$self->{dbfile} = $req->query_parameters->{db}; + #my $db = sqlite->new(); + my $q = $req->body_parameters->{sql}; + my $t = $req->body_parameters->{type}; + print $q."\n"; + if ($t eq "query"){ + $res = $self->dbquery($req->body_parameters->{key},$q); + } elsif ($t eq "querysorted"){ + $res = $self->dbquerysorted($q); + } elsif ($t eq "queryarray"){ + $res = $self->dbqueryarray($q); + } elsif ($t eq "exec"){ + $res = $self->dbexec($q); + } + $html->{result}->{sqldata} = $res; + } else { + return [ + 400, + [ 'Content-Type' => $ct.'; charset=utf-8','Cache-Control' => 'no-store, no-cache, must-revalidate', 'Access-Control-Allow-Origin'=> '*' ], + [ JSON::PP::encode_json($html) ] + ]; + } + return [ + 200, + [ 'Content-Type' => $ct.'; charset=utf-8','Cache-Control' => 'no-store, no-cache, must-revalidate', 'Access-Control-Allow-Origin'=> '*' ], + [ JSON::PP::encode_json($html) ] + ]; +}; + + + +sub strreplace(){ + my $self = shift; + my $text = shift; + $text =~ s/'/''/g; + return $text; +} + +sub dbquery(){ + my $self = shift; + my $key = shift; + my $stat = shift; + my $retdata =(); + my $dbh = DBI->connect('DBI:SQLite:dbname='.$self->{dbfile},"","",{PrintError=>1,RaiseError=>1,AutoCommit=>1}) or return $retdata->{error} = "dbquery Connection Error!".$!; + #$stat = encode("utf8", $stat); + + #open FILE,">>/tmp/sql.log"; + # print FILE "key:".$key.";$stat\n"; + # close FILE; + my $sth = $dbh->prepare($stat); + $sth->execute() or print "dbquery: ".$sth->errstr; + while(my $data = $sth->fetchrow_hashref()) + { + if (exists $data->{$key}){ + foreach my $k (keys %{$data}){ + $retdata->{$data->{$key}}{$k} = decode( "utf8", $data->{$k}); + } + } + } + if (keys(%{$retdata}) == 0){ + $retdata =(); + } + $sth->finish(); + $dbh->disconnect(); + return $retdata; +} + +sub dbquerysorted(){ + my $self = shift; + my $stat = shift; + my $retdata = (); + my $dbh = DBI->connect('DBI:SQLite:dbname='.$self->{dbfile},"","",{PrintError=>1,RaiseError=>1,AutoCommit=>1}) or return $retdata->{error} = "dbquery 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 "dbquery: ".$sth->errstr; + my $count = 0; + while(my $data = $sth->fetchrow_hashref()) + { + foreach my $k (keys %{$data}){ + $retdata->{$count}->{$k} = decode( "utf8", $data->{$k}); + } + $count++; + } + + $sth->finish(); + $dbh->disconnect(); + #%retdata = sort {$a <=> $b} keys %retdata; + return $retdata; +} + +sub dbqueryarray(){ + my $self = shift; + my $stat = shift; + my @retdata = (); + my $dbh = DBI->connect('DBI:SQLite:dbname='.$self->{dbfile},"","",{PrintError=>1,RaiseError=>1,AutoCommit=>1}) or return $retdata[0]->{error} = "dbquery 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 "dbquery: ".$sth->errstr; + my $count = 0; + + while(my $valdata = $sth->fetchrow_arrayref()) + { + if (!defined($valdata)){ last;} + my @rdata = (); + foreach my $k (@{$valdata}){ + push @rdata,decode( "utf8", $k); + } + push @retdata,\@rdata; + } + + $sth->finish(); + $dbh->disconnect(); + #%retdata = sort {$a <=> $b} keys %retdata; + return \@retdata; +} + +sub dbexec(){ + my $self = shift; + my $stat = shift; + my $dbh = DBI->connect('DBI:SQLite:dbname='.$self->{dbfile},"","",{PrintError=>1,AutoCommit=>1}) or return "dbexec Connection Error!".$!; + #$stat = encode("utf8", $stat); + #print $stat."\n"; + #open FILE,">>/Users/kilian/sql.log"; + #print FILE "$stat\n"; + #close FILE; + my $sth = $dbh->prepare($stat); + my $rv =$dbh->do($stat) or print "Failed dbexec:\n'".$stat. "'\n\n"; + $dbh->disconnect(); + return $rv; +} + + +#sub dbbackup(){ +# my $self = shift; +# my $path = shift; +# my $type = shift; +# +# my @dx = localtime(); +# $dx[5] = $dx[5] +1900; +# $dx[4] = $dx[4] +1; +# if ($dx[4] < 10){$dx[4] = '0'.$dx[4];} +# if ($dx[3] < 10){$dx[3] = '0'.$dx[3];} +# if ($dx[2] < 10){$dx[2] = '0'.$dx[2];} +# if ($dx[1] < 10){$dx[1] = '0'.$dx[1];} +# if ($dx[0] < 10){$dx[0] = '0'.$dx[0];} +# my $xdd = $dx[5].$dx[4].$dx[3].'_'.$dx[2].$dx[1].$dx[0]; +# my $bfile = ""; +# if ($type eq "binary" ) { +# $bfile = $path.'/'.basename(substr($self->{dbfile},0,rindex($self->{dbfile},'.'))).'_'.$xdd.'.sqlite'; +# my $dbh = DBI->connect('DBI:SQLite:dbname='.$self->{dbfile},"","",{PrintError=>1,RaiseError=>1,AutoCommit=>1}) or die "dbexec Connection Error!".$!; +# $dbh->sqlite_backup_to_file($bfile); +# $dbh->disconnect(); +# }elsif($type eq "sql"){ +# $bfile = $path.'/'.basename($self->{dbfile}).'_'.$xdd.'.sql'; +# my $st = system('sqlite3 "'.$self->{dbfile}.'" ".dump" > '.$bfile); +# } +# return $bfile; +#} +# +#sub dbrestore(){ +# my $self = shift; +# my $file = shift; +# my $type = shift; +# if ($type eq "binary" ) { +# my $dbh = DBI->connect('DBI:SQLite:dbname='.$self->{dbfile},"","",{PrintError=>1,RaiseError=>1,AutoCommit=>1}) or die "dbexec Connection Error!".$!; +# $dbh->sqlite_backup_from_file($file); +# $dbh->disconnect(); +# }elsif($type eq "sql"){ +# open(REST,$file) or die "cannot open restore file $file!\n"; +# my $rsql = ""; +# while (my $l = ) { +# $rsql .= $l; +# } +# close(REST); +# unlink($self->{dbfile}); +# $self->dbexec($rsql); +# } +#} +# +#sub dbrepair(){ +# my $self = shift; +# my $bfile = $self->dbbackup($ENV{'TMPDIR'},'sql'); +# $self->dbrestore($bfile,'sql'); +# unlink($bfile); +#} + + +1; \ No newline at end of file diff --git a/server/Module/Service.pm b/server/Module/Service.pm new file mode 100644 index 0000000..96caf93 --- /dev/null +++ b/server/Module/Service.pm @@ -0,0 +1,473 @@ +package Module::Service; + +use strict; +use warnings; +use File::Path qw(make_path); +use File::Basename; +use parent qw(Plack::Component); + +sub call { + my($self, $env) = @_; + if (($env->{REMOTE_ADDR} =~ "^127\.0\.") && + ($env->{REMOTE_ADDR} =~ "^10\.") && + ($env->{REMOTE_ADDR} =~ "^172\.16\.") && + ($env->{REMOTE_ADDR} =~ "^192\.168\.")) { + return [ + 404, + [ 'Content-Type' => "text/html",'Cache-Control' => 'no-store, no-cache, must-revalidate' ], + [ "Sorry no access allowed!" ] + ]; + } + return $self->service($env); +} + +sub service() { + my $self = shift; + my $env = shift; + my $html = "Unknown service!"; + my $ct="application/json"; + my $status=200; + + # if ($env->{PATH_INFO} =~ /^\/info/){ + # return $self->appinfo($env); + # } + # if ($env->{PATH_INFO} =~ /^\/preferences/){ + # return $self->preferences($env); + # } + if (($env->{PATH_INFO} =~ /^\/stop/) || ($env->{PATH_INFO} =~ /^\/unload/)){ + warn "Killing the existing server (pid:".$self->{pid}.")\n"; + kill 'TERM' => $self->{pid}; + + if (lc($^O) =~ /mswin32/) { + sleep 1; + kill 'KILL' => $self->{pid}; + } + # waitpid($self->{pid}, 0); + # warn "Successfully killed! Restarting the new server process.\n"; + + } + # if($env->{PATH_INFO} =~ /^\/getconfig/){ + # return $self->getconfig($env); + # } + + return [ + 200, + [ 'Content-Type' => 'text/html','Cache-Control' => 'no-store, no-cache, must-revalidate' , 'Access-Control-Allow-Origin'=> '*'], + [ $html ] + ]; +}; + +# sub preferences(){ +# my $self = shift; +# my $env =shift; +# my $name = basename($0); +# $name =~ s/\srv.pl$//; +# $name =~ s/\srv.exe$//; +# my $appcfgpath = $ENV{APPDATA}.'/'.$name; +# $appcfgpath =~ s/\\/\//g; +# my $pref->{result}= (); +# my $req = Plack::Request->new($env); +# if (exists($req->query_parameters->{page})){ +# if (-e $appcfgpath.'/'.$req->query_parameters->{page}.'.json'){ +# open(PREF,$appcfgpath.'/'.$req->query_parameters->{page}.'.json'); +# my $strpref = ""; +# while (my $l = ){ +# $strpref .= $l; +# } +# close(PREF); +# $pref->{result}=JSON::PP::decode_json($strpref); +# } +# if (exists($req->query_parameters->{set})){ +# my $newpref = JSON::PP::decode_json($req->query_parameters->{set}); +# foreach my $p (keys(%{$newpref})){ +# $pref->{result}->{$p} = $newpref->{$p}; +# } +# open(PREF,">".$appcfgpath.'/'.$req->query_parameters->{page}.'.json'); +# print PREF JSON::PP::encode_json($pref->{result}); +# close(PREF); +# } +# } +# return [ +# 200, +# [ 'Content-Type' => "application/json",'Cache-Control' => 'no-store, no-cache, must-revalidate', 'Access-Control-Allow-Origin'=> '*' ], +# [ JSON::PP::encode_json($pref) ] +# ]; +# } + +# sub appinfo(){ +# my $self = shift; +# my $env = shift; +# my $html->{result} = (); +# my $req = Plack::Request->new($env); +# my $name = basename($0); +# $name =~ s/\.pl$//; +# $name =~ s/\.exe$//; +# $html->{result}->{OS} = $^O; +# $html->{result}->{app} = $name; +# if ($^O eq "MSWin32"){ +# $html->{result}->{home} = $ENV{USERPROFILE}; +# $html->{result}->{user} = $ENV{USERNAME}; +# $html->{result}->{appcfgpath} = $ENV{APPDATA}.'/'.$name; +# $html->{result}->{hostname} = $ENV{COMPUTERNAME}; +# $html->{result}->{arch} = $ENV{PROCESSOR_ARCHITEW6432}; +# $html->{result}->{appcfgpath} =~ s/\\/\//g; +# $html->{result}->{home} =~ s/\\/\//g; +# } else { +# $html->{result}->{home} = $ENV{HOME}; +# $html->{result}->{user} = $ENV{USER}; +# if ($^O eq "darwin"){ +# $html->{result}->{appcfgpath} = $ENV{HOME}.'/Library/Application Support/'.$name; +# } else { +# $html->{result}->{appcfgpath} = $ENV{HOME}.'/.'.$name.'/'; +# } +# $html->{result}->{hostname} = `hostname -s`; +# chomp($html->{result}->{hostname}); +# $html->{result}->{arch} = `uname -m`; +# chomp($html->{result}->{arch}); +# } +# if (! -e $html->{result}->{appcfgpath}){ +# make_path($html->{result}->{appcfgpath}); +# } +# if (-e $html->{result}->{appcfgpath}.'/service.json'){ +# open(LCFG,$html->{result}->{appcfgpath}.'/service.json'); +# my $strljs = ""; +# while (my $l = ){ +# $strljs .= $l; +# } +# close(LCFG); +# print $strljs."\n--\n"; +# #if ($strljs =~ /^\{.*\}$/){ +# $html->{result}->{appconfig} = JSON::PP::decode_json($strljs); +# #} +# } +# return [ +# 200, +# [ 'Content-Type' => "application/json",'Cache-Control' => 'no-store, no-cache, must-revalidate', 'Access-Control-Allow-Origin'=> '*' ], +# [ JSON::PP::encode_json($html) ] +# ]; +# } + +# sub getfileconfig(){ +# my $self = shift; +# my $strcfg = ""; +# my $apppath = $self->getappconfigpath(); +# if (-e $apppath.'/'.basename($apppath).'.conf'){ +# open(AUTH,$apppath.'/'.basename($apppath).'.conf'); +# while (my $l = ){ +# chomp($l); +# $strcfg .= $l; +# } +# close(AUTH); +# } +# if ($strcfg eq ""){ +# return undef; +# } +# return JSON::decode_json($strcfg); +# } + +# sub getconfig(){ +# my $self = shift; +# my $env = shift; +# my $html->{result} = undef; +# my $req = Plack::Request->new($env); +# my @sections = ('weblogin','cablenet','wirelessnet','openvpn','extdrives','shares','shareusers'); +# if (exists($req->query_parameters->{section})){ +# @sections = split(',',$req->query_parameters->{section}); +# } +# foreach my $s (@sections){ +# if ($s eq 'weblogin') { +# $html->{result}->{$s} = $self->getweblogin(); +# } elsif ($s eq 'cablenet') { +# $html->{result}->{$s} = $self->getcablenetworkconfig(); +# } elsif ($s eq 'wirelessnet') { + +# } elsif ($s eq 'openvpn') { +# $html->{result}->{$s} = $self->getOpenVPN(); +# } elsif ($s eq 'extdrives') { +# $html->{result}->{extdrives} = $self->getdrives(); +# } elsif ($s eq 'shares') { +# $html->{result}->{shares} = $self->getshares(); +# } elsif ($s eq 'shareusers') { + +# }; +# } +# return [ +# 200, +# [ 'Content-Type' => "application/json",'Cache-Control' => 'no-store, no-cache, must-revalidate', 'Access-Control-Allow-Origin'=> '*' ], +# [ JSON::PP::encode_json($html) ] +# ]; +# } + +# sub getweblogin(){ +# my $self = shift; +# my $apppath = $self->getappconfigpath(); +# my $loginname= ""; +# if (-e $apppath.'/'.basename($apppath).'.passwd'){ +# open(AUTH,$apppath.'/'.basename($apppath).'.passwd'); +# while (my $l = ){ +# chomp($l); +# my ($loginname) = $l =~ /^(\w+)\=.*/; +# } +# close(AUTH); +# } +# return { "user" => $loginname }; +# } + +# sub setlogin(){ +# my $self = shift; +# my $env = shift; +# my $req = Plack::Request->new($env); + +# } + +# sub getwifinetworks(){ +# my $self = shift; +# my $current = `sudo grep ssid /etc/wpa_supplicant/wpa_supplicant.conf`; +# chomp($current); +# my $wifi->{ssid} = undef; +# if ($current ne ""){ +# $wifi->{ssid} = $current; +# } +# my $strlist = `sudo iw wlan0 scan | grep SSID | sed \'s/.*SSID: //g\'`; +# my @list = split("\n",$strlist); +# $wifi->{networks} = \@list; +# return $wifi; +# } + + + + +#sub getusers(){ +# my $self = shift; +# my $cmd = ""; +# if ($^O eq "linux"){ +# $cmd = 'cat /etc/passwd | grep "/bin/bash" | grep -v -e "^root" | awk -F ":" \'{ print $1 }\''; +# } elsif ($^O eq "darwin"){ +# $cmd = 'ls -1 /Users | grep -v "Shared"'; +# } elsif ($^O eq "MSWin32"){ +# +# } +# my $strdata = `$cmd`; +# my @list = split("\n",$strdata); +# return \@list; +#} + +# sub getdrives(){ +# my $self = shift; +# my $connecteddrives = $self->getconnecteddrives(); +# my $mounts = $self->getcurrentmountpoints(); +# my $cfg = $self->getfileconfig(); +# my $fstypes = { ntfs => 'ntfs-3g',exfat => 'exfat', fat32 => 'vfat'}; +# my $drivesdata = (); +# foreach my $cd (keys(%{$connecteddrives})){ +# if (exists($cfg->{drives}->{$connecteddrives->{$cd}->{serial}})){ +# $drivesdata->{$cd} = $connecteddrives->{$cd}; +# #print $cd." => ".$config->{drives}->{$connecteddrives->{$cd}->{serial}}->{path}."\n"; +# # if (! -d $config->{drives}->{$connecteddrives->{$cd}->{serial}}->{path}){ +# # mkdir($config->{drives}->{$connecteddrives->{$cd}->{serial}}->{path}); +# # } +# if (exists($mounts->{$connecteddrives->{$cd}->{dev}})){ +# $drivesdata->{$cd}->{mounpoint} = $mounts->{$connecteddrives->{$cd}->{dev}}; +# # my $cmd = "sudo mount -t ".$fstypes->{$connecteddrives->{$cd}->{fs}}." -o uid=".$config->{drives}->{$connecteddrives->{$cd}->{serial}}->{uid}.',gid='.$config->{drives}->{$connecteddrives->{$cd}->{serial}}->{gid}.','.$config->{drives}->{$connecteddrives->{$cd}->{serial}}->{type}." /dev/".$connecteddrives->{$cd}->{dev}." ".$config->{drives}->{$connecteddrives->{$cd}->{serial}}->{path}; +# #print $cmd."\n"; +# # my $res = `$cmd`; +# } +# } +# } +# return $drivesdata; +# } + +# sub mountdrives(){ +# my $self = shift; +# #mount -t ntfs-3g -o uid=1001,gid=1001,rw /dev/sdb1 /home/dks/music +# } + +# sub getshares(){ +# my $self = shift; +# my $shares =(); +# open(SMB,'/etc/samba/smb.conf'); +# my $cgrp = ""; +# while (my $l = ){ +# chomp($l); +# if ($l =~ /^\[.*\]$/){ +# $cgrp = $l; +# $cgrp =~ s /\[//; +# $cgrp =~ s /\]//; +# } elsif ($l ne ""){ +# my ($k,$v) = $l =~ m/\s*(.+)\s+\=\s+(.*)$/; +# if ($cgrp eq "global"){ +# if (($k eq "workgroup") || ($k eq "server string") || ($k eq "netbios name")){ +# $shares->{$cgrp}->{$k} =$v; +# } +# }else { +# if (($k eq "comment") || ($k eq "path") || ($k eq "vialid users")){ +# $shares->{$cgrp}->{$k} =$v; +# } +# } +# } +# } +# close(SMB); +# return $shares; +# } + +# sub setshares(){ +# my $self = shift; +# } + + +# sub getwifinetworks(){ +# my $self = shift; +# #iw wlan0 scan | grep SSID | sed 's/.*SSID: //g' +# # } + +# sub setwifinetwork(){ +# my $self = shift; +# #/etc/wpa_supplicant/wpa_supplicant.conf +# #network={ +# #ssid="testing" +# #psk="testingPassword" +# ##encrypted: +# #psk=131e1e221f6e06e3911a2d11ff2fac9182665c004de85300f9cac208a6a80531 +# #wpa_passphrase "testing" "testingPassword" +# #} +# #wpa_cli -i wlan0 reconfigure +# ##unsecurd +# # network={ +# # ssid="testing" +# # key_mgmt=NONE +# #} +# ##HIDDEN +# # network={ +# # ssid="yourHiddenSSID" +# # scan_ssid=1 +# # psk="Your_wifi_password" +# #} +# ##MULTIPLE with option apriority +# #network={ +# # ssid="HomeOneSSID" +# # psk="passwordOne" +# # priority=1 +# # id_str="homeOne" +# #} +# # +# #network={ +# # ssid="HomeTwoSSID" +# # psk="passwordTwo" +# # priority=2 +# # id_str="homeTwo" +# #} +# } + +# sub configureOpenVPN(){ +# my $self = shift; +# my $file = shift; +# } + +# sub getOpenVPN(){ +# my $self = shift; +# opendir(OVPN,'/etc/openvpn'); +# my $ovpndata = (); +# print "read OPENVPN:\n"; +# while(my $f = readdir(OVPN)){ +# print "OVPN file:".$f."\n"; +# if (($f =~ /\.ovpn$/) || ($f =~ /\.conf$/)){ +# my $name = substr($f,0,-6); +# $ovpndata->{$name} = undef; +# } +# } + +# closedir(OVPN); +# return $ovpndata; +# } + +# sub getOpenVPNstatus(){ + +# } + +# sub getcablenetworkconfig(){ +# my $self = shift; +# my $cmd = ""; +# my $ncfg->{type} = "dhcp"; +# if ($^O eq "linux"){ +# $cmd = 'cat /etc/dhcpcd.conf | grep -e "^static\|^interface"'; +# my $strdata = `$cmd`; +# my @data = split("\n",$strdata); +# foreach my $d (@data){ +# if ($d =~ /static\sip_address/){ +# $ncfg->{ip} = $d =~ /.+=(.+)\/\d{1,2}$/; +# $ncfg->{subnet} = $d =~ /.+=.+\/(\d{1,2})$/; +# #substr(Net::CIDR::addrandmask2cidr($stdata->{0}->{networkip}, $stdata->{0}->{networksubnet}),-3) +# } +# if ($d =~ /static\srouters/){ +# $ncfg->{gateway} = $d =~ /.+=(.+)$/; +# } +# if ($d =~ /static\sdomain_name_servers/){ +# $ncfg->{dns} = $d =~ /.+=(.+)$/; +# } +# } +# } elsif ($^O eq "darwin"){ +# $cmd = ''; +# } elsif ($^O eq "MSWin32"){ +# $cmd = ''; +# } +# return $ncfg; +# } + +# sub getappconfigpath(){ +# my $self = shift; +# my $name = basename($0); +# $name =~ s/\.pl$//; +# $name =~ s/\.exe$//; +# my $path = ""; +# if ($^O eq "MSWin32"){ +# $path = $ENV{APPDATA}.'/'.$name; +# } elsif ($^O eq "darwin"){ +# $path = $ENV{HOME}.'/Library/Application Support/'.$name; +# } else { +# $path = $ENV{HOME}.'/.'.$name.'/'; +# } +# return $path; +# } + +# sub getconnecteddrives(){ +# my $self = shift; +# my $cmd = 'lsblk -o name,label,size,mountpoint,fstype,SERIAL | grep -e "sd."'; +# my $strdrives = `$cmd`; +# my $drives = (); +# my @drives = split("\n",$strdrives); +# foreach my $l (@drives){ +# $l =~ tr/a-zA-Z0-9 ._-//cd; +# $l =~ s/\s+/\ /g; +# my @tmp = split(" ",$l); +# #print Dumper(@tmp); +# if ( $l =~ /^sd.\d/ ) { +# my $drv = substr($tmp[0],0,3); +# $drives->{$drv}->{dev} = $tmp[0]; +# $drives->{$drv}->{label} = $tmp[1]; +# $drives->{$drv}->{size} = $tmp[2]; +# $drives->{$drv}->{fs} = $tmp[3]; +# } else { +# #print $l."\n"; +# $drives->{$tmp[0]}->{serial} = $tmp[2]; +# } +# } + +# return $drives; +# } + +# sub getcurrentmountpoints(){ +# my $self = shift; +# my $cmd = 'mount | grep "/dev/sd"'; +# my $mpoints = (); +# my $strmounts = `$cmd`; +# #print $strmounts; +# my @mdrives = split("\n",$strmounts); +# foreach my $m (@mdrives){ +# my ($drv,$path) = $m =~ m/^\/dev\/(.+)\son\s(.*)\stype.*$/; +# $mpoints->{$drv} = $path; +# } +# return $mpoints; +# } + + +1; \ No newline at end of file diff --git a/server/Module/Test.pm b/server/Module/Test.pm new file mode 100644 index 0000000..acb92c6 --- /dev/null +++ b/server/Module/Test.pm @@ -0,0 +1,54 @@ +package Module::Test; + +use strict; +use warnings; +use parent qw(Plack::Component); +use Plack::Request; +use Data::Dumper; +use URI::Encode qw/uri_encode/; + +sub call { + my($self, $env) = @_; + #$self->_app->($env); + if (($env->{REMOTE_ADDR} =~ "^127\.0\.") && + ($env->{REMOTE_ADDR} =~ "^10\.") && + ($env->{REMOTE_ADDR} =~ "^172\.16\.") && + ($env->{REMOTE_ADDR} =~ "^192\.168\.")) { + return [ + 404, + [ 'Content-Type' => "text/html",'Cache-Control' => 'no-store, no-cache, must-revalidate' ], + [ "Sorry no remote access allowed!" ] + ]; + } + return $self->test($env); +} + +sub test(){ + my $self = shift; + my $env = shift; + my $html = {}; + my $ct="application/json"; + my $status=200; + my $request = Plack::Request->new($env); + + foreach my $k (keys(%ENV)){ + $html->{sysenv}->{$k} = $ENV{$k}; + } + + foreach my $k (keys(%{$env})){ + $html->{request}->{$k} = uri_encode($env->{$k}); + } + # $html .= "

GET PARAMETERS

"; + # $html .= Dumper($request->query_parameters); + # $html .= "

POST PARAMETERS

"; + # $html .= Dumper($request->body_parameters); + # print "Test Called!\n"; + return [ + 200, + [ 'Content-Type' => "application/json",'Cache-Control' => 'no-store, no-cache, must-revalidate', 'Access-Control-Allow-Origin'=> '*' ], + [ JSON::PP::encode_json($html) ] + ]; +}; + + +1; \ No newline at end of file diff --git a/server/Module/VPNServer.pm b/server/Module/VPNServer.pm new file mode 100644 index 0000000..ec6144d --- /dev/null +++ b/server/Module/VPNServer.pm @@ -0,0 +1,69 @@ +package Module::Test; + +use strict; +use warnings; +use parent qw(Plack::Component); +use Plack::Request; +use Data::Dumper; + +sub call { + my($self, $env) = @_; + #$self->_app->($env); + if (!exists($env->{REMOTE_USER}) ) { + return [ + 404, + [ 'Content-Type' => "text/html",'Cache-Control' => 'no-store, no-cache, must-revalidate' ], + [ "Access not allowed!" ] + ]; + } + if ($env->{PATH_INFO} =~ /^\/server/){ + return $self->server($env); + } elsif ($env->{PATH_INFO} =~ /^\/client/) { + return $self->client($env); + } else { + return $self->clientslist($env) + } + return return [ + 404, + [ 'Content-Type' => "text/html",'Cache-Control' => 'no-store, no-cache, must-revalidate' ], + [ "Access not allowed!" ] + ];; +} + +sub server(){ + my $self = shift; + my $env = shift; + my $html = ""; + my $ct="application/json"; + my $status=200; + my $request = Plack::Request->new($env); + if ($env->{PATH_INFO} =~ /^\/server\/list/){ + + } + return [ + 200, + [ 'Content-Type' => "application/json",'Cache-Control' => 'no-store, no-cache, must-revalidate' ], + [ $html ] + ]; +}; + +sub client(){ + my $self = shift; + my $env = shift; + my $html = ""; + my $ct="application/json"; + my $status=200; + my $request = Plack::Request->new($env); + if ($env->{PATH_INFO} =~ /^\/client\/add/){ + + } elsif ($env->{PATH_INFO} =~ /^\/client\/revoke/){ + + } + return [ + 200, + [ 'Content-Type' => "application/json",'Cache-Control' => 'no-store, no-cache, must-revalidate' ], + [ $html ] + ]; +}; + +1; \ No newline at end of file diff --git a/server/createpdfA4invoice.pl b/server/createpdfA4invoice.pl new file mode 100644 index 0000000..fe41671 --- /dev/null +++ b/server/createpdfA4invoice.pl @@ -0,0 +1,224 @@ +#!/usr/bin/env perl + +use strict; +use PDF::API2; +use PDF::Table; +use Image::Size; +use File::Basename; +use Getopt::Long; +use utf8; +use Encode; +use JSON::PP; +#use Data::Dumper; +my $pdf = PDF::API2->new(); +my $strpdfdata =""; +my $templatedata =(); +my $data = ""; +my $pdfout = ""; +my $lang = "fr"; +# my $datafile=dirname($0).'/pdftest.pdf'; +GetOptions ("data|d=s" => \$data, "pdfoutput|o=s" => \$pdfout, "lang|l=s" =>\$lang); +if (! -e $datafile){ + print "file $datafile does not exist!\n"; + exit(1); +} +if (-e $pdfout){ + unlink($pdfout); +} + + + +my $strtemplatedata = '{ + "section":{ + "12headerimg":{"x":50,"y":755,"width":160,"type":"image"}, + "02headerline":{"type":"line","color":"black","width":1,"start":{"x":50,"y":753},"end":{"x":285,"y":753}}, + "03dkstext":{"type":"text","align":"center","font":{"name":"Helvetica","size":9},"x":200,"y":743}, + "04dksfooter":{"type":"text","align":"center","font":{"name":"Helvetica","size":10},"x":297.5,"y":25,"lineheight":15}, + "05adrline":{"type":"line","color":"black","width":1,"start":{"x":52,"y":662},"end":{"x":280,"y":662}}, + "06header_right":{"type":"text","align":"right","font":{"name":"Helvetica","size":11},"x":550,"y":820,"lineheight":14}, + "07reporttype":{"type":"text","align":"right","font":{"name":"HelveticaBold","size":30},"x":550,"y":704,"lineheight":14}, + "08tbladdress":{"type":"table","x":"50","w":"230","font":"Helvetica","font_size":"11","start_y":"680","start_h":"620","next_y":"750","next_h":"500","padding":"2","padding_bottom":"3","padding_top":"3","padding_right":"5","column_props":[{ "min_w":"200", "max_w":"200", "justify":"left" }],"header_props":[{ "font_size":"11", "font":"HelveticaBold", "bg_color":"white", "font_color":"black", "repeat":"1", "justify":"left" }],"border":"0"}, + "09tblinvoicedata":{"type":"table","x":"390","w":"175","font":"Helvetica","font_size":"11","start_y":"680","start_h":"620","next_y":"750","next_h":"500","padding":"2","padding_bottom":"3","padding_top":"3","padding_right":"5","column_props":[ { "min_w":"70","max_w":"70","justify":"left" },{ "min_w":"90","max_w":"90","justify":"left","font":"HelveticaBold" } ],"border":"0"}, + "10tblproductdata":{"type":"table","x":"50","w":"500","font":"Helvetica","font_size":"11","start_y":"570","start_h":"300","next_y":"750","next_h":"500","padding":"2","padding_left":"5","padding_bottom":"10","padding_top":"5","padding_right":"5","header_props":[{"font_size":"11","font":"HelveticaBold","bg_color":"#e6e6e6","font_color":"black","repeat":"1","justify":"center" }],"column_props":[ { },{ "min_w":"40","max_w":"40","justify":"right" },{ "min_w":"20","max_w":"20","justify":"right" },{ "min_w":"50","max_w":"50","justify":"right","font":"Helvetica" } ],"border":"0.5"}, + "11totalsums":{"type":"table","x":"349.5","w":"201","font":"Helvetica","font_size":"11","start_y":"%%10tblproductdata:y%%","start_h":"150","next_y":"750","next_h":"500","padding":"2","padding_left":"5","padding_bottom":"10","padding_top":"5","padding_right":"5","column_props":[ { "justify":"right" },{ "min_w":"70","max_w":"70","justify":"right","font":"HelveticaBold" } ],"border":"0.5"} + }, + "data":{"fr":{ + "12headerimg":{"src":"'.dirname($0).'/dks_1000.png"}, + "03dkstext":{"text":["Database Knowledge Solutions - Simplify IT!"]}, + "04dksfooter":{"text":["DKS, Société à responsabilité limitée, RC Luxembourg,B168572 - TVA: LU 2537 5617 - No. Aut: 10024550 / 0","IBAN: LU25 0020 1100 2783 8700; BIC: BILLLULL"]}, + "06header_right":{"text":["DKS s.à r.l.","8b, rue du Moulin","6914 Roodt/Syre","Tel: +352 691 504574","info@dks.lu / www.dks.lu"]}, + "08tbladdress":{"text":[ ["À:"], ["%%RECEPIENT%%"], ["%%ADDRESS"], ["%%COUNTYSHORT%%-%%ZIP%% %%CITY%%"] ]}, + "07reporttype":{"text":["Facture"]}, + "09tblinvoicedata":{"text":[ ["NO. Facture","%%REFERENCE%%"], ["Date","%%INVOICEDATE%%"], ["Échéanche","%%REMINDERDATE%%"], ["No Client","%%CLIENTNUMBER%%"], ["Ust-Id","%%VATID%%"] ]}, + "10tblproductdata":{"text":[ ["Produit", "Qu.","Prix unitaire","Prix Net"], ["%%PRODUCT%%", "%%QUANTIY%% %%UNIT%%","%%UNITAMOUNT%% %%CURRENCY%%","%%NETAMOUNT%% %%CURRENCY%%"] ]}, + "11totalsums":{"text":[ ["Total Net :","%%SUMNETAMOUNT%% %%CURRENCY%%"], ["TVA (%%VATPERCENT%%%) :","%%SUMVATAMOUNT%% %%CURRENCY%%"], ["Total à payer:","%%SUMGROSSAMOUNT%% %%CURRENCY%%"] ]} + },"de":{ + "12headerimg":{"src":"'.dirname($0).'/dks_1000.png"}, + "03dkstext":{"text":["Database Knowledge Solutions - Simplify IT!"]}, + "04dksfooter":{"text":["DKS, Société à responsabilité limitée, RC Luxembourg,B168572 - TVA: LU 2537 5617 - No. Aut: 10024550 / 0","IBAN: LU25 0020 1100 2783 8700; BIC: BILLLULL"]}, + "06header_right":{"text":["DKS s.à r.l.","8b, rue du Moulin","6914 Roodt/Syre","Tel: +352 691 504574","info@dks.lu / www.dks.lu"]}, + "08tbladdress":{"text":[ ["An:"], ["%%RECEPIENT%%"], ["%%ADDRESS"], ["%%COUNTYSHORT%%-%%ZIP%% %%CITY%%"] ]}, + "07reporttype":{"text":["Rechnung"]}, + "09tblinvoicedata":{"text":[ ["Rechnungs-Nr.","%%REFERENCE%%"], ["Datum","%%INVOICEDATE%%"], ["Fälligkeit","%%REMINDERDATE%%"], ["Kunden-Nr.","%%CLIENTNUMBER%%"], ["Ust-Id","%%VATID%%"] ]}, + "10tblproductdata":{"text":[ ["Produkt", "Anzahl","EinzelPreis","Netto-Preis"], ["%%PRODUCT%%", "%%QUANTIY%% %%UNIT%%","%%UNITAMOUNT%% %%CURRENCY%%","%%NETAMOUNT%% %%CURRENCY%%"] ]}, + "11totalsums":{"text":[ ["Gesamt Netto :","%%SUMNETAMOUNT%% %%CURRENCY%%"], ["MwSt. (%%VATPERCENT%%%) :","%%SUMVATAMOUNT%% %%CURRENCY%%€"], ["Gesamt Brutto :","%%SUMGROSSAMOUNT%% %%CURRENCY%%"] ]} + },"en":{ + "12headerimg":{"src":"'.dirname($0).'/dks_1000.png"}, + "03dkstext":{"text":["Database Knowledge Solutions - Simplify IT!"]}, + "04dksfooter":{"text":["DKS, Société à responsabilité limitée, RC Luxembourg,B168572 - TVA: LU 2537 5617 - No. Aut: 10024550 / 0","IBAN: LU25 0020 1100 2783 8700; BIC: BILLLULL"]}, + "06header_right":{"text":["DKS s.à r.l.","8b, rue du Moulin","6914 Roodt/Syre","Tel: +352 691 504574","info@dks.lu / www.dks.lu"]}, + "08tbladdress":{"text":[ ["To:"],["%%RECEPIENT%%"], ["%%ADDRESS"], ["%%COUNTYSHORT%%-%%ZIP%% %%CITY%%"] ]}, + "07reporttype":{"text":["Invoice"]}, + "09tblinvoicedata":{"text":[ ["Reference.","%%REFERENCE%%"], ["Date","%%INVOICEDATE%%"], ["Due Date","%%REMINDERDATE%"], ["Client-Id","%%CLIENTNUMBER%%"], ["VAT-Id","%%VATID%%"] ]}, + "10tblproductdata":{"text":[ ["Product", "Quantity","Unit Amount","Net Amount"], ["%%PRODUCT%%", "%%QUANTIY%% %%UNIT%%","%%UNITAMOUNT%% %%CURRENCY%%","%%NETAMOUNT%% %%CURRENCY%%"] ]}, + "11totalsums":{"text":[ ["Net Total :","%%SUMNETAMOUNT%% %%CURRENCY%%"], ["VAT (%%VATPERCENT%%%) :","%%SUMVATAMOUNT%% %%CURRENCY%%€"], ["Total to Pay:","%%SUMGROSSAMOUNT%% %%CURRENCY%%"] ] + }, + } +}'; + + +open(DATA,$strtemplatedata); +while (my $l = ){ + $strpdfdata .= $l; +} +close(DATA); +$templatedata = JSON::PP::decode_json($strpdfdata); +my $pdfdata->{section} = $templatedata->{section}; +$pdfdata->{data} = $templatedata->{data}->{$lang}; + +$pdf->preferences({-fitwindow => 1}); + + +my $page = $pdf->page(); +$page->mediabox('A4'); + + + + +my $endpoints = (); +foreach my $s (sort keys(%{$pdfdata->{section}})){ + $endpoints->{$s} = {final_y => '', lastpage => 1,pages => 1}; + if ($pdfdata->{section}->{$s}->{type} eq "image"){ + #print "Add Image $s\n"; + + $endpoints->{$s}->{y} = &addimage($pdf,$page,$pdfdata->{section}->{$s},$pdfdata->{data}->{$s}); + } elsif ($pdfdata->{section}->{$s}->{type} eq "line"){ + #print "Add Line $s\n"; + $endpoints->{$s}->{y} = &addline($page,$pdfdata->{section}->{$s}); + } elsif ($pdfdata->{section}->{$s}->{type} eq "text"){ + #print "Add Text $s\n"; + $endpoints->{$s}->{y} = &addtext($pdf,$page,$pdfdata->{section}->{$s},$pdfdata->{data}->{$s}); + } elsif ($pdfdata->{section}->{$s}->{type} eq "table"){ + #print "Add Table $s\n"; + ($endpoints->{$s}->{lastpage}, $endpoints->{$s}->{pages}, $endpoints->{$s}->{y}) = &addtable($pdf,$page,$pdfdata->{section}->{$s},$pdfdata->{data}->{$s}); + } +} + +$pdf->saveas($pdfout); +$pdf->end; + +#Functions + +sub addimage(){ + my $pdf = shift; + my $page = shift; + my $section = shift; + my $data = shift; + my $gfx = $page->gfx(); + my ($iw, $ih) = imgsize($data->{src}); + my $nimgw = $section->{width}; + my $nimgh = ($nimgw/$iw) * $ih; + #print "New Imagesize: w:".$nimgw." h:".$nimgh."\n"; + $gfx->translate($section->{x},$section->{y}); + my $img = $pdf->image_png($data->{src}); + $gfx->image($img,0,0,$nimgw,$nimgh); + $gfx->translate(0,0); + $gfx->save; + return $nimgh + $section->{y}; +} + +sub addline(){ + my $page = shift; + my $section = shift; + my $line = $page->gfx(); + $line->translate($section->{x},$section->{y}); + $line->strokecolor($section->{color}); + $line->linewidth($section->{width}); + $line->move( $section->{start}->{x}, $section->{start}->{y} ); + $line->line( $section->{end}->{x}, $section->{end}->{y} ); + $line->stroke; + $line->save; + return $section->{end}->{y}; +} + +sub addtext(){ + my $pdf = shift; + my $page = shift; + my $section = shift; + my $data = shift; + + my $textobj = $page->text(); + + #print "X:".$section->{x}." Y:".$section->{y}."\n"; + $textobj->translate($section->{x}, $section->{y}); + $textobj->font($pdf->corefont($section->{font}->{name}),$section->{font}->{size}); + foreach my $d (@{$data->{text}}){ + if ($section->{align} eq "center"){ + $textobj->text_center($d); + } elsif ($section->{align} eq "right"){ + $textobj->text_right($d); + } else { + $textobj->text($d); + } + $section->{y} = $section->{y} - $section->{lineheight}; + $textobj->translate($section->{x}, $section->{y}); + } + $textobj->save; + return $section->{y}; +} + +sub addtable(){ + my $pdf = shift; + my $page = shift; + my $section = shift; + my $data = shift; + my $pdftbl = new PDF::Table; + delete($section->{type}); + if (exists($section->{font})){ + $section->{font} = $pdf->corefont($section->{font}); + } + if (exists($section->{start_y})){ + if ($section->{start_y} =~ /^%%.*%%$/){ + my ($sec,$k) = $section->{start_y} =~ /^%%(.+):(.+)%%$/; + $section->{start_y} = $endpoints->{$sec}->{$k}; + } + } + #print "HeadProps\n"; + if (exists($section->{header_props})){ + foreach (my $i=0;$i{header_props}});$i++){ + my $tmpdata = @{$section->{header_props}}[$i]; + if (exists($tmpdata->{font})){ + $tmpdata->{font} = $pdf->corefont($tmpdata->{font}); + } + @{$section->{header_props}}[$i] = $tmpdata; + } + } + #print "ColProps\n"; + if (exists($section->{column_props})){ + foreach (my $i=0;$i{column_props}});$i++){ + my $tmpdata = @{$section->{column_props}}[$i]; + if (exists($tmpdata->{font})){ + $tmpdata->{font} = $pdf->corefont($tmpdata->{font}); + } + @{$section->{column_props}}[$i] = $tmpdata; + } + } + #print Dumper($section); + #print ref %{$section}."\n"; + my ($lastpage, $tblpages, $final_y) = $pdftbl->table($pdf,$page, $data->{text}, %{$section}); + return ($lastpage, $tblpages, $final_y); +} + + + + diff --git a/server/fmtosqlite.pl b/server/fmtosqlite.pl new file mode 100644 index 0000000..cf8f000 --- /dev/null +++ b/server/fmtosqlite.pl @@ -0,0 +1,110 @@ +#!/usr/bin/env perl + +use strict; +use Getopt::Long; +use File::Basename; +use Data::Dumper; +use Encode; +use Getopt::Long; +my $file = ""; +my $outfile = ""; +#my $dbfile = ""; +GetOptions("infile|i=s" => \$file, "outfile|o=s" => \$outfile); + +my $fdata = ""; +open (FF,$file); +while (my $l = ){ + #chomp($l); + $l =~ s/\r//g; + $l =~ s/\n//g; + #print $l."\n\n"; + $fdata .= $l; +} +close(FF); +#print $fdata; +$fdata =~ s/
<\/TD>/<\/TD>/g; +my ($tbl) = $fdata =~ m/.*(.*)<\/TABLE>.*/; +$tbl =~ s/^//; +$tbl =~ s/<\/TR>$//; + +my @strdata = split('',$tbl); +my $strcol = shift(@strdata); +#print Dumper(@strdata); +#print Dumper($strcol); +#get cols; +my $tablename = substr(basename($file),0,rindex(basename($file),".")); + +my @cols = &getheaderarray($strcol); +my @rows = (); +foreach my $d (@strdata){ + my @rdata = &getdataarray($d); + push (@rows,\@rdata); +} +print Dumper(@rows); +#print Dumper(@cols); +open (FOUT,">".$outfile); +print FOUT &tableddl($tablename,\@cols); + +foreach my $r (@rows){ + my @nr = (); + foreach my $d (@{$r}){ + if ($d eq ""){$d = 'null';} + elsif ($d =~ /^\d\d\/\d\d\/\d\d\d\d\s+\d\d:\d\d:\d\d$/){ + my ($c,$m,$y,$h,$n,$s) = $d =~ m/(\d\d)\/(\d\d)\/(\d\d\d\d)\s+(\d\d):(\d\d):(\d\d)/; + $d = "datetime('".$y.'-'.$m.'-'.$c.' '.$h.':'.$n.':'.$s."')"; + }elsif ($d =~ /^\d+,\d+$/){ + $d =~ s/,/./; + }else { + $d =~ s/\r$//; + $d =~ s/\n$//; + $d = "'".encode('utf-8',$d)."'"; + } + push (@nr,$d); + } + my $sql = "INSERT INTO ".$tablename." (".join(',',@cols).") VALUES (".join(",",@nr).");"; + print $sql."\n"; + print FOUT $sql."\n"; +} +close(FOUT); + + +sub getheaderarray(){ + my $strdata = shift; + $strdata =~ s/^
//; + $strdata =~ s/<\/TH>$//; + $strdata = lc($strdata); + $strdata =~ s/\s+/\ /g; + $strdata =~ s/\s/\_/g; + my @data = split('',$strdata); + return @data; +} + +sub getdataarray(){ + my $strdata = shift; + + $strdata =~ s/^//; + $strdata =~ s/<\/TD>$//; + $strdata =~ s/
/\n/g; + my @data = split('
',$strdata); + return @data; +} + +sub tableddl(){ + my $tablename = shift; + my $tmpcols = shift; + my @cols = @{$tmpcols}; + my $ddl = 'CREATE TABLE "'.$tablename.'" ('."\n"; + my @dcol = (); + my $pk = ""; + foreach my $c (@cols){ + if ($c eq "id"){ + $pk = "id"; + } + push (@dcol, '"'.$c.'" TEXT'); + } + if ($pk ne ""){ + push (@dcol,"PRIMARY KEY ('".$pk."')"); + } + $ddl .= "\t".join(",\n\t",@dcol)."\n);"; + return $ddl; +} \ No newline at end of file diff --git a/server/invoicejournalserver.pl b/server/invoicejournalserver.pl new file mode 100644 index 0000000..1f1c131 --- /dev/null +++ b/server/invoicejournalserver.pl @@ -0,0 +1,95 @@ +#!C:\Strawberry\perl\bin\perl.exe +use strict; +use File::Basename; +use Getopt::Long; +use Time::HiRes; +use Data::Dumper; +use lib (dirname($0)); +#use Win32::HideConsole; +#hide_console; +if ($^O eq "MSWin32" ){ + + use lib ("C:/Users/ksaff/Workspace/Apps/invoicejournal/server"); +} +#if ($^O eq "darwin"){ +# use lib ($ENV{HOME}.'/perl5/lib/perl5'); +#} +use Plack::Builder; +use Plack::App::Directory; +use Plack::App::File; +use Plack::App::WrapCGI; +use Plack::Middleware::Auth::Basic; +use Plack::Request; +use Plack::Runner; +use Module::Service; +use Module::Test; +use Module::SQLite; +use Module::PDFExtract; +use Module::FileSystem; + + +print $^O."\n"; +print $^X."\n"; +print "Process:".$$."\n"; +print join(@INC)."\n"; + + +my @match = grep { /par-.*inc$/} @INC; + +my $basedir = dirname($0); +if (scalar(@match) > 0){ + $basedir = $match[0]; +} + +my $cfgpath = ""; +print "BASEDIR:".$basedir."\n"; +my $name = basename($0); +$name =~ s/\.pl$//; +$name =~ s/\.exe$//; + +if ($^O eq "MSWin32"){ + $cfgpath = $ENV{APPDATA}.'/dks/'; +} elsif ($^O eq "darwin"){ + $cfgpath = $ENV{HOME}.'/Library/Application Support/dks/'; +} else { + $cfgpath = $ENV{HOME}.'/.dks/'; +} +$cfgpath =~ s/\\/\//g; +print $cfgpath."\n"; +# sub version { +# require Twiggy; +# print "Twiggy $Twiggy::VERSION\n"; +# } + +# sub authen_cb { +# my($username, $password, $env) = @_; +# my $auth = 0; +# if (-e $cfgpath.'/'.$name.'.passwd'){ +# open(AUTH,$cfgpath.'/'.$name.'.passwd'); +# while (my $l = ){ +# chomp($l); +# if ($l eq $username.'='.$password){ +# $auth = 1; +# last; +# } +# } +# close(AUTH); +# } +# return $auth; +# } + +my $allapp = builder { + mount "/server" => Module::Service->new({pid => $$ }); + mount "/filesystem" => Module::FileSystem->new({docpath => $cfgpath.'invoicejournal/documents'}); + mount "/test" => Module::Test->new(); + mount "/pdfextract" => Module::PDFExtract->new({docpath => $cfgpath.'invoicejournal/documents'}); + mount "/sqlite" => Module::SQLite->new({dbpath => $cfgpath."db"}); +}; + + +my @args = ("-p","6060"); +my $runner = Plack::Runner->new(server => 'Starlight', env => 'deployment');#env => development, test +$runner->parse_options(@args); +$runner->run($allapp); + +print "Started\n"; diff --git a/server/pdfextract.pl b/server/pdfextract.pl new file mode 100644 index 0000000..26d5748 --- /dev/null +++ b/server/pdfextract.pl @@ -0,0 +1,155 @@ +#!C:\Perl\bin\perl.exe + +use strict; +use warnings; +use Getopt::Long; +use File::Basename; +my $pdffile=""; +my $toolsdir=dirname($0); +GetOptions("pdf|p=s" => \$pdffile); + +if (! -e $pdffile) { + print "incomplete input!\n"; + exit(1); +} +if (-e $pdffile.'.txt'){ + unlink($pdffile.'.txt'); +} +if (-e $pdffile.'.csv'){ + unlink($pdffile.'.csv'); +} + +my $sep = '/'; +if ($^O eq "Win32") { + $sep = "\\"; +} +if (! -e $toolsdir.$sep.'pdftotext.exe'){ + exit(2); +} + my $cmd = '"'.$toolsdir.$sep.'pdftotext.exe" -table -eol unix "'.$pdffile.'" "'.$pdffile.'.txt"'; + my $st = system($cmd); + my $jdata = (); + if (($st == 0) && (-e $pdffile.".txt")){ + my @pdata = (); + open(PDFDATA,$pdffile.".txt"); + while (my $l = ) { + chomp($l); + if ($l ne "") { + push @pdata,$l; + } + } + close(PDFDATA); + my $caccount = ""; + my $stmtnum = ""; + my $r = 0; + my $cpos = ""; + foreach my $p (@pdata){ + if ($p =~ /^\s+Konto\s+:/ ) { + $cpos = ""; + ($caccount) = $p =~ m/.+IBAN\s+(.+)$/; + next; + }elsif ($p =~ /Kontoauszug Nr\./){ + $cpos = ""; + ($stmtnum) = $p =~ m/^Kontoauszug Nr\.\s(\d+).+$/; + next; + }elsif ($p =~ /^\d\d\.\d\d\s+[GUT|UEBER|SEPA]/){ + $cpos = ""; + $r++; + my ($type,$trdate,$trval,$trsign) = $p =~ m/\d\d\.\d\d\s+(.+)\s+(\d\d\.\d\d\.\d\d)\s+([\d|,|\.]+)\s([+|-])$/; + $type =~ s/\s//g; + $trsign =~ s/\+//; + $trval=~ s/\.//g; + $trdate = substr($trdate,0,6).'20'.substr($trdate,-2); + $jdata->{$r}->{"Account"} = $caccount; + $jdata->{$r}->{"StatementNumber"} = $stmtnum; + $jdata->{$r}->{"BookingDate"} = $trdate; + $jdata->{$r}->{"Amount"} = $trsign.$trval; + $jdata->{$r}->{"TransactionIdent"} = ""; + $jdata->{$r}->{"Message"} = ""; + $jdata->{$r}->{"ForeignAccountOwner"} = ""; + $jdata->{$r}->{"Bank"} = ""; + $jdata->{$r}->{"TransferAccount"} = ""; + $jdata->{$r}->{"TransferCosts"} = 0; + #$jdata->{$r}->{"BookingType"} = $type; + next; + }elsif ($p =~ /^\s+Unser Zeichen/){ + $cpos = "TransactionIdent"; + my ($trid) = $p =~ m/^\s+Unser Zeichen\s+(.+)$/; + $jdata->{$r}->{$cpos} =$trid; + }elsif ($p =~ /^\s+Mitteilung/){ + $cpos = "Message"; + my ($msg) = $p =~ m/^\s+Mitteilung\s+(.+)$/; + $jdata->{$r}->{$cpos} = $msg; + }elsif ($p =~ /^\s+Auftraggeber/){ + $cpos = "ForeignAccountOwner"; + my ($apl) = $p =~ /^\s+Auftraggeber\s+(.+)$/; + $apl =~ s/\s+/\ /g; + $jdata->{$r}->{$cpos} =$apl; + }elsif ($p =~ /^\s+Bank d. Auftr.gebers/){ + $cpos = ""; + }elsif ($p =~ /^\s+BIC-Code Bank d. Auftraggebers/){ + $cpos = "Bank"; + my ($trfbank) = $p =~ /^\s+BIC-Code\sBank\sd\.\sAuftraggebers\s+(.+)$/; + $jdata->{$r}->{$cpos} =$trfbank; + }elsif ($p =~ /^\s+End-to-End-Identifizierung/){ + $cpos = ""; + }elsif ($p =~ /^\s+Beg.nstigter/){ + $cpos = "ForeignAccountOwner"; + my ($recp) = $p =~ /^\s+Beg.nstigter\s+(.+)$/; + $recp =~ s/\s+/\ /g; + $jdata->{$r}->{$cpos} =$recp; + $cpos=""; + }elsif ($p =~ /^\s+Konto Nr. Beg.nst./){ + $cpos = "TransferAccount"; + + my ($trfacc) = $p =~ /^\s+Konto\sNr\.\sBeg.nst.\s+(.+)$/; + $trfacc =~ s/\///g; + $trfacc =~ s/(....)/$1 /sg; + $trfacc =~ s/\s+$//; + $jdata->{$r}->{$cpos} =$trfacc; + $cpos=""; + }elsif ($p =~ /^\s+bei/){ + $cpos = ""; + }elsif ($p =~ /^\s+Transfergeb.hr/){ + $cpos = "TransferCosts"; + my ($tramount) = $p =~ /^\s+Transfergeb.hr\s+EUR\s+(.+)$/; + $tramount =~ s/\,/\./g; + $jdata->{$r}->{$cpos} =$tramount; + }elsif ($p =~ /^\s+Durch Ihren Bonus abgedeckt/){ + $cpos = "TransferCosts"; + my ($tramount) = $p =~ /^\s+Durch Ihren Bonus abgedeckt\s+EUR\s+(.+)$/; + $tramount =~ s/\,/\./g; + $jdata->{$r}->{$cpos} = $jdata->{$r}->{$cpos} + $tramount; + }elsif ($p =~ /^\s+Zeichen/){ + $cpos = ""; + } elsif ($p =~ /^\s+Neuer Kontostand/){ + $cpos=""; + }elsif ($cpos ne "") { + my ($data) = $p =~ m/\s+(.+)$/; + $jdata->{$r}->{$cpos} .= " ".$data; + } + } + + } +if (-e $pdffile.'.txt'){ + unlink($pdffile.'.txt'); +} +open(FOUT,">".$pdffile.".csv"); +print FOUT '"Account","StatementNumber","BookingDate","Amount","TransactionIdent","Message","ForeignAccountOwner","Bank","TransferAccount","TransferCosts"'."\n"; +foreach my $r (keys(%{$jdata})){ + my @data = (); + push @data, $jdata->{$r}->{"Account"}; + push @data, $jdata->{$r}->{"StatementNumber"}; + push @data, $jdata->{$r}->{"BookingDate"}; + push @data, $jdata->{$r}->{"Amount"}; + push @data, $jdata->{$r}->{"TransactionIdent"}; + $jdata->{$r}->{"Message"} =~ s/\s+/\ /g; + push @data, $jdata->{$r}->{"Message"}; + $jdata->{$r}->{"ForeignAccountOwner"} =~ s/\s+/\ /g; + push @data, $jdata->{$r}->{"ForeignAccountOwner"}; + push @data, $jdata->{$r}->{"Bank"}; + push @data, $jdata->{$r}->{"TransferAccount"}; + push @data, $jdata->{$r}->{"TransferCosts"}; + print FOUT '"'.join('","',@data).'"'."\n"; +} +close(FOUT); \ No newline at end of file diff --git a/server/pdftextblock.pl b/server/pdftextblock.pl new file mode 100644 index 0000000..c4e548b --- /dev/null +++ b/server/pdftextblock.pl @@ -0,0 +1,29 @@ +#!/usr/bin/env perl +use strict; +use PDF::API2; +use PDF::TextBlock; + +my $pdf = PDF::API2->new( -file => "40-demo.pdf" ); +my $tb = PDF::TextBlock->new({ + + pdf => $pdf, + fonts => { + b => PDF::TextBlock::Font->new({ + pdf => $pdf, + font => $pdf->corefont( 'Helvetica-Bold', -encoding => 'latin1' ), + }), + i => PDF::TextBlock::Font->new({ + pdf => $pdf, + font => $pdf->corefont('Helvetica-Oblique') + }) + }, +}); +$tb->text( + ' This fairly lengthy, rather verbose sentence is tagged to appear ' . + ' Click here to visit Omni Hotels. ' . "\n\n" . + "New paragraph.\n\n" . + "Another paragraph." +); +$tb->apply; +$pdf->save; +$pdf->end; \ No newline at end of file diff --git a/server/pdftotext.exe b/server/pdftotext.exe new file mode 100644 index 0000000..3cfe847 Binary files /dev/null and b/server/pdftotext.exe differ diff --git a/server/sqlitedumpdata.pl b/server/sqlitedumpdata.pl new file mode 100644 index 0000000..00ad087 --- /dev/null +++ b/server/sqlitedumpdata.pl @@ -0,0 +1,47 @@ +#!/usr/bin/perl +use strict; +use File::Basename; +use Getopt::Long; +use lib (dirname($0).'/cgi/lib'); +use sqlite; +use pgsql; +use localconfig; +my $sdb = ""; +my $ident = ""; +my $schema = 0; +my $data = 0; +GetOptions("database|db=s" => \$sdb,"ident|i=s" => \$ident,"schema|s" => \$schema,"data|d" => \$data); +my $db = sqlite->new($sdb); + +$db->dbbackup(dirname($0).'/cursqlitedb.sql','sql'); +my $cfgpath=dirname($0).'/conf'; +my $cfg = localconfig->new($cfgpath.'/'.$ident.'.conf'); +my $rcfg = $cfg->readconfig(); +my $pg = pgsql->new($rcfg); +if ($schema == 1){ + open(SDB,dirname($0).'/cursqlitedb.sql'); + my $ddlschema = ""; + while (my $l = ){ + #chomp($l); + if (($l !~ /^INSERT/) && ($l !~ /^UPDATE/) && ($l !~ /^DELETE/)){ + $ddlschema .= $l; + } + + } + my $r = $pg->dbexec("INSERT INTO ".$rcfg->{schema}.".ddlschema (ddlschema) VALUES ('".$pg->strreplace($ddlschema)."');"); +} +if ($data == 1){ + my @sqldata = (); + open(SDB,dirname($0).'/cursqlitedb.sql'); + while (my $l = ){ + chomp($l); + if (($l =~ /^INSERT/) || ($l =~ /^UPDATE/) || ($l =~ /^DELETE/)){ + push(@sqldata,$l); + } + } + close(SDB); + + foreach my $d (@sqldata){ + my $r = $pg->dbexec("INSERT INTO ".$rcfg->{schema}.".sqlsync (tsquery,sqlquery,client) VALUES (now(),'".$pg->strreplace($d)."','system');"); + } +} diff --git a/server/syncfolder.pl b/server/syncfolder.pl new file mode 100644 index 0000000..1bde6bf --- /dev/null +++ b/server/syncfolder.pl @@ -0,0 +1,27 @@ +#!/usr/bin/perl + +use strict; +my $homepath=$ENV{HOME}; +my $macpath='osascript -e "set mypath to POSIX path of (choose folder with prompt \"Choose Folder:\" default location \"'.$homepath.'\")"'; +my $mirror='dks@dks-backup:/home/dks/mirror/'; +my $ssh= ' -e "ssh -p 3587" '; +my $path = `$macpath`; + +#todo -> show differences + dryrun + keep newer files +#todo -> rsync with perl (Net::OpenSSH) or putty + +if ($path ne ""){ + chomp($path); + my $relpath = substr($path,length($homepath)+1); + print "Path to sync: ".$path." -> ".$relpath."\n"; + my $cmd = 'rsync -avz --progress --delete-after '.$ssh." ".$path." ".$mirror.$relpath; + my $terminalcmd = 'osascript -e "tell application \"Terminal\" + set currenttab to do script (\"rsync -avz --delete-after --progress -e \'ssh -p 3587\' '.$path.' '.$mirror.$relpath.' && exit 0\") + end tell"'; + + print $terminalcmd."\n"; + system($terminalcmd); + +} + +