package Mod::APIjsonserver; # # SPDX-License-Identifier: AGPL-3.0-or-later # Copyright (c) Rainer Gümpelein, TeilRad GmbH # #Server for sharee json api # ##In DB context $q->escapeHTML must always done by API # use warnings; use strict; use Exporter; our @ISA = qw (Exporter); use POSIX; use CGI; use Apache2::Const -compile => qw(OK ); use JSON; use Scalar::Util qw(looks_like_number); use Config::General; use Time::Piece; use Lib::Config; use Mod::DBtank; use Mod::Basework; use Mod::Shareework; use Mod::APIfunc; use Mod::APIjsonclient; use Mod::APIsigclient; use Data::Dumper; sub handler { my ($r) = @_; my $q = new CGI; $q->import_names('R'); my $json = JSON->new->allow_nonref; my $cf = new Config; my $dbt = new DBtank; my $bw = new Basework; my $tk = new Shareework; my $apif = new APIfunc; my $jsc = new APIjsonclient; my $si = new APIsigclient; my $dbh = ""; my %varenv = $cf->envonline(); my $oprefix = $dbt->{operator}->{$varenv{dbname}}->{oprefix}; my $now_dt = strftime "%Y-%m-%d %H:%M:%S", localtime; my $lang="de"; my @keywords = $q->param; my $debug=1; my $user_agent = $q->user_agent(); #my %headers = map { $_ => $q->http($_) } $q->http(); #$bw->log("headers:",\%headers,""); $bw->log("APIjsonserver request:\n--> user-agent '$user_agent' ",$q,""); print $q->header(-type => "application/json", -charset => "utf-8", -'Access-Control-Allow-Origin' => "*"); #for my $header ( keys %headers ) { # print "$header: $headers{$header}\n"; #} my $respreq = $q->param('request') || ""; my $apiserver = $q->url(-base=>1) || ""; my $response = { apiserver => "$apiserver", response => "$respreq", uri_primary => "$dbt->{primary}->{sharee_primary}->{primaryApp}", copri_version => "4.1.23.03", user_id => "", authcookie => "", new_authcoo => "0", clearing_cache => "0", agb_checked => "0", user_group => [], user_tour => [], response_state => "OK, nothing todo", agb_html => "$dbt->{project_conf}->{Freiburg}->{agb_html}", privacy_html => "$dbt->{project_conf}->{Freiburg}->{privacy_html}", impress_html => "$dbt->{project_conf}->{Freiburg}->{impress_html}", tariff_info_html => "$dbt->{project_conf}->{Freiburg}->{tariff_info_html}", bike_info_html => "$dbt->{project_conf}->{Freiburg}->{bike_info_html}", lang => "de", last_used_operator => { operator_name => "sharee.bike | TeilRad GmbH", operator_email => "hotline\@sharee.bike", operator_phone => "+49 761 45370097", operator_hours => "Bürozeiten: Montag, Mittwoch, Freitag 9-12 Uhr", }, init_map => { center => { latitude => "", longitude => "" }, radius => "" } }; my $aowner = 0; my $coo = $q->param('authcookie') || $q->param('sessionid') || ""; if(!$coo && !$q->param('merchant_id')){ $response->{response_state} = "Failure 9900: no authcookie or merchant_id defined"; $response->{response_text} = "Authentifizierung fehlgeschlagen."; $bw->log("Failure 9900: NO authcookie or merchant_id defined",$q,""); my $jrout = $json->pretty->encode({shareejson => $response}); print $jrout; return Apache2::Const::OK; exit 0; }else{ my $return_merchant = { project_id => "" }; ($aowner, $return_merchant) = $apif->fetch_merchant($q,\%varenv,$coo,$q->param('merchant_id')); #if($aowner && ($aowner == 195 || $aowner == 185 || $aowner == 176)){ if($return_merchant->{project_id} eq "Konstanz"){ $response->{agb_html} = "$dbt->{project_conf}->{Konstanz}->{agb_html}"; $response->{bike_info_html} = "$dbt->{project_conf}->{Konstanz}->{bike_info_html}"; } if($return_merchant->{project_id} eq "Bayern"){ $response->{agb_html} = "$dbt->{project_conf}->{Bayern}->{agb_html}"; $response->{privacy_html} = "$dbt->{project_conf}->{Bayern}->{privacy_html}"; $response->{tariff_info_html} = "$dbt->{project_conf}->{Bayern}->{tariff_info_html}"; $response->{bike_info_html} = "$dbt->{project_conf}->{Bayern}->{bike_info_html}"; } } #If param>40 || value > 400 then exit foreach(@keywords){ if($_ ne "app_debug"){ if(length($_) > 40 || length($q->param($_)) > 400){ $response->{response_state} = "Failure 9000: amount of characters in $_ exceeds"; $bw->log("Failure 9000: amount of characters in $_ exceeds",$q,""); my $jrout = $json->pretty->encode({shareejson => $response}); print $jrout; return Apache2::Const::OK; exit 0; } } } #RESTful bikeAPP ------------------------------------------------------------------ if($q->param('user_device_manufacturer') || $q->param('user_device_manufaturer') || $q->param('user_device_model') || $q->param('user_device_platform') || $q->param('user_device_version') || $q->param('user_device_id')){ #tipo fix my $user_device_manufacturer = $q->param('user_device_manufacturer') || $q->param('user_device_manufaturer') || ""; my $user_device = $user_device_manufacturer . ";" . $q->param('user_device_model') . ";" . $q->param('user_device_platform') . ";" . $q->param('user_device_version') . ";" . $q->param('user_device_id'); $q->param(-name=>'user_device',-value=>"$user_device"); $bw->log("user_device",$q->param('user_device'),""); } #just auth_verify if($q->param('request') eq "auth_verify"){ ($aowner,my $return_merchant) = $apif->fetch_merchant($q,\%varenv,$coo,$q->param('merchant_id')); $varenv{merchant_id} = $return_merchant->{merchant_id}; $response = { %$response, %$return_merchant }; my ($auth,$authraw) = $apif->auth_verify($q); $response = { %$response, %$auth }; if(ref($auth) eq "HASH" && $auth->{authcookie}){ $response = { %$response, %$auth }; }else{ $response->{response_state} = "Failure 1001: authcookie not defined"; $response->{response_text} = "Entschuldigung, die Sitzung wurde unterbrochen"; } } #authout elsif($q->param('request') eq "authout"){ ($aowner,my $return_merchant) = $apif->fetch_merchant($q,\%varenv,$coo,$q->param('merchant_id')); $varenv{merchant_id} = $return_merchant->{merchant_id}; $response = { %$response, %$return_merchant }; my ($auth,$authraw) = $apif->authout($q); $response = { %$response, %$auth }; if(ref($auth) eq "HASH" && $auth->{authcookie}){ $response->{authcookie} = "$auth->{authcookie}"; $response->{response_state} = "OK, logout"; $response->{response_text} = "Auf Wiedersehen."; }else{ $response->{response_state} = "Failure 1001: authcookie not defined"; $response->{response_text} = "Entschuldigung, die Sitzung wurde unterbrochen"; } } #authorization elsif($q->param('request') eq "authorization"){ ($aowner,my $return_merchant) = $apif->fetch_merchant($q,\%varenv,$coo,$q->param('merchant_id')); $varenv{merchant_id} = $return_merchant->{merchant_id}; $response = { %$response, %$return_merchant }; my ($auth,$authraw) = $apif->authorization($q,"","",$aowner); if(ref($auth) eq "HASH" && $auth->{authcookie}){ $response = { %$response, %$auth }; $response->{response_text} = "Herzlich willkommen im Fahrradmietsystem"; }else{ $response->{response_state} = "Failure: cannot generate authcookie"; $response->{response_text} = "Entschuldigung, die Anmeldung schlug fehl"; } } #booking request elsif($q->param('request') eq "booking_request"){ ($aowner,my $return_merchant) = $apif->fetch_merchant($q,\%varenv,$coo,$q->param('merchant_id')); $varenv{merchant_id} = $return_merchant->{merchant_id}; my $rows = 0; $response = { %$response, %$return_merchant }; my ($auth,$authraw) = $apif->auth_verify($q); $response = { %$response, %$auth }; if(ref($auth) eq "HASH" && $auth->{authcookie}){ my $bike = $q->escapeHTML($q->param('bike')) || ""; if($bike){ my $bike_id = $bike; $bike_id =~ s/S[1-9]X/SX/; $bike_id = $1 if($bike_id =~ /(\d+)/); #check count of occcupied/requested bikes my $record = $apif->user_bikes_occupied($dbh,$authraw,""); my $count=0; my $still_requested = 0; foreach my $id (keys(%$record)){ $count++; if($bike_id && $bike_id == $record->{$id}->{barcode}){ $still_requested = 1; $response->{response_state} = "OK, bike " . $bike . " already requested or occupied"; $response->{response_text} = "Fahrrad Nr. " . $bike . " ist bereits reserviert"; } } if(!$still_requested){ #only if not App debuglevel defined if(!$authraw->{int11} && $count >= 3){ $response->{response_state} = "Failure: booking_request declined. max count of 3 occupied bikes has been reached"; $response->{response_text} = "Die maximale Anzahl von 3 Reservierungen wurde erreicht"; }else{ my $gps = ""; my $latitude = ""; my $longitude = ""; #old if($q->param('gps')){ my $gps_input = $q->param('gps'); $gps_input =~ s/\s//g if($gps_input); $latitude = $q->escapeHTML($1) if($gps_input =~ /^(\d+\.\d+),\d+/); $longitude = $q->escapeHTML($1) if($gps_input =~ /\d+,(\d+\.\d+)$/); $gps = "$latitude,$longitude" if($latitude && $longitude); } #new if($q->param('latitude') && $q->param('longitude')){ my $latitude_in = $q->param('latitude'); my $longitude_in = $q->param('longitude'); $latitude = $1 if($latitude_in =~ /(\d+\.\d+)/); $longitude = $1 if($longitude_in =~ /(\d+\.\d+)/); $gps = "$latitude,$longitude" if($latitude && $longitude); } my $response_book = {}; my $ct_bike = {}; my $ct_tariff = {}; ($ct_bike,$ct_tariff) = $apif->fetch_bike_tariff(\%varenv,$authraw,$bike,$aowner); #sig booking_request my $sig_book = { bikeId => "", rentalId => "", }; if(!$ct_bike->{barcode} || !$ct_bike->{int10} || $ct_bike->{int10} != 1){ $response->{response_state} = "Failure 2001: booking bike $bike fails, bike not available"; $response->{response_text} = "Mietrad $bike ist nicht verfügbar. Ist das Mietrad für sie freigeschaltet? Bitte überprüfen Sie Ihre Profildaten auf Vollständigkeit"; }elsif(!$ct_tariff->{barcode}){#ist will not happen, because of prios tariff select in fetch_bike_tariff $response->{response_state} = "Failure 2089: booking bike $bike fails, no user tariff available"; $response->{response_text} = "Reservierung Mietrad $bike nicht möglich. Ist die Mietrad Flotte für sie freigeschaltet? Bitte überprüfen Sie Ihre Profildaten auf Vollständigkeit"; }elsif($ct_bike->{barcode} && $ct_tariff->{barcode}){ #sig reservation. not mandatory, disabled because sig seems to get confused if((!$q->param('state') || $q->param('state') ne "occupied") && $ct_bike->{int11} == 3){ $sig_book = $si->sig_booking(\%varenv,"reserve",$authraw,$ct_bike,""); $sig_book->{bikeId} = "$ct_bike->{txt22}"; $sig_book->{rentalId} = "$R::rentalId" if($R::rentalId);#only for cmd tests } $response_book = $apif->booking_request($q,\%varenv,$authraw,$bike,$ct_bike,$ct_tariff,$aowner,$gps,$sig_book); } #just in time booking if(ref($response_book) eq "HASH" && $response_book->{response_state} =~ /OK/ && $q->param('state') && $q->param('state') =~ /occupied/){ my $booking_values = {}; my $ctpos = {}; my $booking_pos = { table => "contenttranspos", fetch => "one", barcode => "$bike_id", int10 => "2", ca_id => "$authraw->{c_id}", }; my $dbh = ""; $ctpos = $dbt->fetch_tablerecord($dbh,$booking_pos); #sig booking if($ctpos->{int11} == 3){ #$sig_book = $si->sig_booking(\%varenv,"rental",$authraw,$ct_bike,$ctpos); #we have to use $ct_bike->{txt22} because we doesn't using sig reserve in this case system("$varenv{basedir}/src/scripts/sig_client.pl '$varenv{syshost}' 'rental' '$authraw->{c_id}' '$ct_bike->{txt22}' '$ctpos->{c_id}' &"); $sig_book->{bikeId} = "$ct_bike->{txt22}"; $sig_book->{rentalId} = "$R::rentalId" if($R::rentalId);#only for cmd tests ($rows, $booking_values) = $apif->booking_update($q,\%varenv,$authraw,$aowner,$sig_book); $response = {%$response, %$booking_values}; }else{ ($rows, $booking_values) = $apif->booking_update($q,\%varenv,$authraw,$aowner,$sig_book); $response = {%$response, %$booking_values}; } }else{ $response = {%$response, %$response_book}; } } #return list of occupied/requested bikes $record = $apif->user_bikes_occupied($dbh,$authraw,""); $response->{bikes_occupied} = $apif->rentals($record,$authraw,"1");#returns JSON rental values }#end still_requested }else{ $response->{response_state} = "Failure: no bike defined"; $response->{response_text} = "Abbruch, es wurde kein Fahrrad ausgewählt"; } }else{ $response->{response_state} = "Failure 1001: authcookie not defined"; $response->{response_text} = "Entschuldigung, die Sitzung wurde unterbrochen"; } }#end booking request #booking cancel/update elsif($q->param('request') eq "booking_cancel" || $q->param('request') eq "booking_update"){ if($q->param('request') eq "booking_cancel"){ $q->param(-name=>'request',-value=>"booking_update"); $q->param(-name=>'state',-value=>"canceled"); } ($aowner,my $return_merchant) = $apif->fetch_merchant($q,\%varenv,$coo,$q->param('merchant_id')); $varenv{merchant_id} = $return_merchant->{merchant_id}; $response = { %$response, %$return_merchant }; my ($auth,$authraw) = $apif->auth_verify($q); my $rows = 0; $response = { %$response, %$auth }; if(ref($auth) eq "HASH" && $auth->{authcookie}){ my $bike = $q->escapeHTML($q->param('bike')) || ""; if($bike){ my $bike_id = $bike; $bike_id =~ s/S[1-9]X/SX/; $bike_id = $1 if($bike_id =~ /(\d+)/); my $ctpos = {}; my $booking_pos = { table => "contenttranspos", fetch => "one", barcode => "$bike_id", int10 => "IN::('2','3')", ca_id => "$authraw->{c_id}", }; $ctpos = $dbt->fetch_tablerecord($dbh,$booking_pos); my $sig_book = { bikeId => $ctpos->{txt22}, rentalId => $ctpos->{txt11}, }; if($q->param('request') eq "booking_update" && $q->param('state') && $q->param('state') =~ /canceled/){ my $booking_values = {}; if($ctpos->{int11} == 3){ $sig_book = $si->sig_booking(\%varenv,"reserve_end",$authraw,"",$ctpos); ($rows, $booking_values) = $apif->booking_update($q,\%varenv,$authraw,$aowner,$sig_book); }else{ ($rows, $booking_values) = $apif->booking_update($q,\%varenv,$authraw,$aowner,""); } $response = {%$response, %$booking_values}; } elsif($q->param('request') eq "booking_update" && (($q->param('state') && $q->param('state') =~ /occupied|available/) || ($q->param('lock_state') && $q->param('lock_state') =~ /locking|locked|unlocking|unlocked/))){ my $booking_values = {}; #update on sig if($ctpos->{int11} == 3){ if($q->param('state') eq "occupied"){ system("$varenv{basedir}/src/scripts/sig_client.pl '$varenv{syshost}' 'rental' '$authraw->{c_id}' '$ctpos->{txt22}' '$ctpos->{c_id}' &"); } #rental/end will be done by sig push-notification # if($q->param('lock_state') eq "unlocking" && !$q->param('state')){ system("$varenv{basedir}/src/scripts/sig_client.pl '$varenv{syshost}' 'unlock' '$authraw->{c_id}' '$ctpos->{txt22}' '$ctpos->{c_id}' &"); } #TODO, check if booking_values in both cases: push-notify and/or app trigger works $sig_book->{rentalId} = "$R::rentalId" if($R::rentalId);#only for cmd tests ($rows, $booking_values) = $apif->booking_update($q,\%varenv,$authraw,$aowner,$sig_book); $response = {%$response, %$booking_values}; my $record = $apif->user_bikes_occupied($dbh,$authraw,"show_dialog"); $response->{bikes_occupied} = $apif->rentals($record,$authraw,"1"); #update on Ilockit }else{ ($rows, $booking_values) = $apif->booking_update($q,\%varenv,$authraw,$aowner,$sig_book); $response = {%$response, %$booking_values}; my $record = $apif->user_bikes_occupied($dbh,$authraw,""); $response->{bikes_occupied} = $apif->rentals($record,$authraw,"1"); } }#end occupied|available else{ my $record = $apif->user_bikes_occupied($dbh,$authraw,""); $response->{bikes_occupied} = $apif->rentals($record,$authraw,"1"); } }else{ $response->{response_state} = "Failure: no bike defined"; $response->{response_text} = "Abbruch, es wurde keine Fahrrad Nummer angegeben"; } }else{ $response->{response_state} = "Failure 1001: authcookie not defined"; $response->{response_text} = "Entschuldigung, die Sitzung wurde unterbrochen"; } }#end booking cancel/update #user_bikes_occupied elsif($q->param('request') eq "user_bikes_occupied"){ if($varenv{syshost} eq "shareeapp-primary"){ ($aowner,my $return_merchant) = $apif->fetch_merchant($q,\%varenv,$coo,$q->param('merchant_id')); $varenv{merchant_id} = $return_merchant->{merchant_id}; $response = { %$response, %$return_merchant }; my ($auth,$authraw) = $apif->auth_verify($q); if(ref($auth) eq "HASH" && $auth->{authcookie}){ $response = { %$response, %$auth }; ($response->{bikes_occupied},$response->{uri_operator_array},$response->{user_group},$response->{user_tour}) = $jsc->loop_sharees($q,$auth,$authraw,$return_merchant); }else{ $response->{response_state} = "Failure 1001: authcookie not defined"; $response->{response_text} = "Entschuldigung, die Sitzung wurde unterbrochen"; } }else{ my ($auth,$authraw) = $apif->auth_verify($q); if(ref($auth) eq "HASH" && $auth->{authcookie}){ $response = { %$response, %$auth }; my $record = $apif->user_bikes_occupied($dbh,$authraw,"show_dialog"); $response->{bikes_occupied} = $apif->rentals($record,$authraw,"1"); }else{ $response->{response_state} = "Failure 1001: authcookie not defined"; $response->{response_text} = "Entschuldigung, die Sitzung wurde unterbrochen"; } } } #bikes_available elsif($q->param('request') eq "bikes_available"){ if($varenv{syshost} eq "shareeapp-primary"){ ($aowner,my $return_merchant) = $apif->fetch_merchant($q,\%varenv,$coo,$q->param('merchant_id')); $varenv{merchant_id} = $return_merchant->{merchant_id}; $response = { %$response, %$return_merchant }; my $auth = {}; my $authraw = {}; ($auth,$authraw) = $apif->auth_verify($q); $response = { %$response, %$auth }; ($response->{bikes},$response->{uri_operator_array},$response->{user_group},$response->{user_tour}) = $jsc->loop_sharees($q,$auth,$authraw,$return_merchant); #$bw->log("X bikes_available $varenv{syshost} $stamp: $response->{user_group}",$response,""); }else{ ($aowner,my $return_merchant) = $apif->fetch_merchant($q,\%varenv,$coo,$q->param('merchant_id')); $varenv{merchant_id} = $return_merchant->{merchant_id}; #on operator loop select, operator adr must be select to get user_group my $auth = {}; my $authraw = {}; ($auth,$authraw) = $apif->auth_verify($q,"","",1); $response = { %$response, %$auth }; #$bw->log("Y bikes_available by c_id $authraw->{c_id}, Tarif:",$authraw->{txt30},""); if($varenv{syshost} eq "shareeapp-sx"){ ($response->{bikes},my $return2copri->{bikes}) = $si->sig_available($q,\%varenv,$authraw); $tk->sigbike_cupdate($return2copri->{bikes}); }else{ $response->{bikes} = $apif->bikes_available($q,\%varenv,$authraw); } } if(ref($response->{bikes}) ne "HASH"){ $response->{response_state} = "Failure 5003: cannot find any user defined bike tariff"; $response->{response_text} = "Abbruch, es konnte kein gültiger Tarif gefunden werden"; } } #bikes_all with service_state calculater #cronjob for maintenance update runs at ~ 7:00 elsif($q->param('request') eq "bikes_all"){ if($varenv{syshost} eq "shareeapp-primary"){ ($aowner,my $return_merchant) = $apif->fetch_merchant($q,\%varenv,$coo,$q->param('merchant_id')); $varenv{merchant_id} = $return_merchant->{merchant_id}; $response = { %$response, %$return_merchant }; my ($auth,$authraw) = $apif->auth_verify($q); $response = { %$response, %$auth }; ($response->{bikes},$response->{uri_operator_array},$response->{user_group},$response->{user_tour}) = $jsc->loop_sharees($q,$auth,$authraw,$return_merchant); }else{ ($aowner,my $return_merchant) = $apif->fetch_merchant($q,\%varenv,$coo,$q->param('merchant_id')); $varenv{merchant_id} = $return_merchant->{merchant_id}; my $auth = {}; my $authraw = {}; ($auth,$authraw) = $apif->auth_verify($q,"","",1); $response = { %$response, %$auth }; $response->{response_text} = "Vorsicht, das ist die Liste aller Leihräder unabhängig von der Verfügbarkeit"; #on shareetool only stations on user_tour my $stations_allraw = {}; (my $stations_not_used,$stations_allraw) = $apif->stations_all($q,\%varenv,"",$authraw) if($aowner && $aowner eq "187");#shareetool my ($bikes_all,$bikes_allraw,$bikes_on_station) = $apif->bikes_all($q,\%varenv,$authraw,$stations_allraw); my $bike = "all"; my $interval = $q->param('interval') || "31"; my $service_state_debug = "\n"; my $pos_record = {}; my $response_work = {}; my $node = {}; #shareetool if($aowner && $aowner eq "187"){ (my $xresponse, $pos_record, my $node_template, my $crecord) = $apif->service_select($q,$authraw,"",$interval); ($response_work, $node) = $apif->service_work($pos_record,$bikes_allraw,"",$node_template); #Pseudocode -- Calculate service_state: #if (state == "defekt") -> service_state=1-rot #else if (1 harte Wartung fällig und ( mind. 1 weiche Wartung fällig -oder- Aufgabe Text eingetragen )) -> service_state=2-Blau #else if ( mind. 1 harte Wartung fällig ) -> service_state=3-grün #else service_state=4-grau } my $i=0; foreach my $bid (sort { $bikes_allraw->{$a}->{mtime} cmp $bikes_allraw->{$b}->{mtime} } keys (%$bikes_allraw)){ my $biselect = $bikes_allraw->{$bid}->{barcode}; $i++; #service_state Calculator $bikes_all->{$oprefix . $bid}->{todo_info} = "0"; $bikes_all->{$oprefix . $bid}->{service_state} = "0"; $bikes_allraw->{$bid}->{service_state_blue} = 0; $bikes_allraw->{$bid}->{service_state_green} = 0; if(ref($response_work->{$biselect}) eq "HASH" && $aowner && $aowner eq "187"){#shareetool foreach my $id (keys(%{$response_work->{$biselect}})){ $bikes_all->{$oprefix . $bid}->{service_template} = $node->{template_id}; #$bw->log("response_work:$biselect|$id|$response_work->{$biselect}->{$id}->{mtime}|$response_work->{$biselect}->{$id}->{service_type}|$response_work->{$biselect}->{$id}->{time_over}|$response_work->{$biselect}->{$id}->{work_val}","",""); #time_over && (service_type || Aufgaben) if(($response_work->{$biselect}->{$id}->{time_over} == 1 && $response_work->{$biselect}->{$id}->{service_type} >= 1) || ($id eq "txt01" && $response_work->{$biselect}->{$id}->{work_val})){ #print $id . ":" . $response_work->{$biselect}->{$id}->{work_val} . "\n"; if($id eq "txt01" && $response_work->{$biselect}->{$id}->{work_val} && $response_work->{$biselect}->{$id}->{work_val} ne "NaN" && $response_work->{$biselect}->{$id}->{work_val} !~ /::erledigt::/){ $bikes_all->{$oprefix . $bid}->{todo_info} = "1"; } if(($response_work->{$biselect}->{$id}->{time_over} == 1 && $response_work->{$biselect}->{$id}->{service_type} == 1) || ($id eq "txt01" && $response_work->{$biselect}->{$id}->{work_val} && $response_work->{$biselect}->{$id}->{work_val} ne "NaN" && $response_work->{$biselect}->{$id}->{work_val} !~ /::erledigt::/)){ $bikes_allraw->{$bid}->{service_state_blue}++; } if($response_work->{$biselect}->{$id}->{time_over} == 1 && $response_work->{$biselect}->{$id}->{service_type} == 2){ $bikes_allraw->{$bid}->{service_state_green}++; } } }#end response_work service_state calc if($bikes_all->{$oprefix . $bid}->{state} eq "defect"){ $bikes_all->{$oprefix . $bid}->{service_state} = "1"; $service_state_debug .= "$bid: service_state 1\n"; #$bw->log("defect service_state bike: $bid:",$bikes_all->{$oprefix . $bid}->{service_state},""); } elsif($bikes_allraw->{$bid}->{service_state_blue} >= 1 && $bikes_allraw->{$bid}->{service_state_green} >= 1){ #print "$bikes_allraw->{$bid}->{service_state_blue}|$bikes_allraw->{$bid}->{service_state_green}" if($bid eq "5"); #$bikes_all->{$oprefix . $bid}->{service_state} = "$bikes_allraw->{$bid}->{service_state_blue}"; $bikes_all->{$oprefix . $bid}->{service_state} = "2"; $bikes_all->{$oprefix . $bid}->{state} = "maintenance"; #if($bikes_allraw->{$bid}->{txt10} && $bikes_allraw->{$bid}->{txt10} !~ /defect|maintenance|requested|occupied/) if($bikes_allraw->{$bid}->{int10} && ($bikes_allraw->{$bid}->{int10} == 1 || $bikes_allraw->{$bid}->{int10} == 6)){ $service_state_debug .= "$bid: service_state 2\n"; #$bw->log("maintenance service_state bike: $bid:",$bikes_all->{$oprefix . $bid}->{service_state},""); #4 = "maintenance" $apif->bikestate_update($authraw,$bikes_allraw->{$bid}->{c_id},"4"); } } elsif($bikes_allraw->{$bid}->{service_state_green} >= 1){ #$bikes_all->{$oprefix . $bid}->{service_state} = "$bikes_allraw->{$bid}->{service_state_green}"; $bikes_all->{$oprefix . $bid}->{service_state} = "3"; $bikes_all->{$oprefix . $bid}->{state} = "maintenance"; #if($bikes_allraw->{$bid}->{txt10} && $bikes_allraw->{$bid}->{txt10} !~ /defect|maintenance|requested|occupied/){ if($bikes_allraw->{$bid}->{int10} && ($bikes_allraw->{$bid}->{int10} == 1 || $bikes_allraw->{$bid}->{int10} == 6)){ $service_state_debug .= "$bid: service_state 3\n"; #$bw->log("maintenance service_state bike: $bid:",$bikes_all->{$oprefix . $bid}->{service_state},""); #4 = "maintenance" $apif->bikestate_update($authraw,$bikes_allraw->{$bid}->{c_id},"4"); } }else{ #if($bikes_allraw->{$bid}->{txt10} && $bikes_allraw->{$bid}->{txt10} =~ /maintenance/) if($bikes_allraw->{$bid}->{int10} && $bikes_allraw->{$bid}->{int10} == 4){ $service_state_debug .= "$bid: 0\n"; #$bw->log("maintenance TO available service_state bike: $bid:",$bikes_all->{$oprefix . $bid}->{service_state},""); #1 = "available" $apif->bikestate_update($authraw,$bikes_allraw->{$bid}->{c_id},"1"); } } #workaround to get todo_info on defect #else NOT if(ref($response_work->{$biselect}) eq "HASH" && $response_work->{$biselect}->{int01}->{c_id}) ---> because 31 day select } if($bikes_all->{$oprefix . $bid}->{state} eq "defect"){ $bikes_all->{$oprefix . $bid}->{service_state} = "1"; my $search = { key => "txt01", val => "%", }; my $pos_record_bi = $apif->service_work_search($biselect,"","",$search); if($pos_record_bi->{txt01} && $pos_record_bi->{txt01} ne "NaN" && $pos_record_bi->{txt01} !~ /::erledigt::/){ #$bikes_all->{$oprefix . $bid}->{todo_info} = "$pos_record_bi->{txt01}"; $bikes_all->{$oprefix . $bid}->{todo_info} = "1"; } $service_state_debug .= "$bid: service_state 1\n"; } } $bw->log("service_state_debug",$service_state_debug,""); $response->{bikes} = $bikes_all; } } #stations_all elsif($q->param('request') eq "stations_all"){ if($varenv{syshost} eq "shareeapp-primary"){ ($aowner,my $return_merchant) = $apif->fetch_merchant($q,\%varenv,$coo,$q->param('merchant_id')); $varenv{merchant_id} = $return_merchant->{merchant_id}; $response = { %$response, %$return_merchant }; my ($auth,$authraw) = $apif->auth_verify($q); $response = { %$response, %$auth }; ($response->{stations},$response->{uri_operator_array},$response->{user_group},$response->{user_tour}) = $jsc->loop_sharees($q,$auth,$authraw,$return_merchant); }else{ ($aowner,my $return_merchant) = $apif->fetch_merchant($q,\%varenv,$coo,$q->param('merchant_id')); $varenv{merchant_id} = $return_merchant->{merchant_id}; my $auth = {}; my $authraw = {}; ($auth,$authraw) = $apif->auth_verify($q,"","",1); $response = { %$response, %$auth }; my ($bikes_all,$bikes_allraw,$bikes_on_station) = $apif->bikes_all($q,\%varenv,$authraw,""); ($response->{stations},my $stations_allraw) = $apif->stations_all($q,\%varenv,$bikes_on_station,$authraw); } } #stations_available elsif($q->param('request') eq "stations_available"){ if($varenv{syshost} eq "shareeapp-primary"){ ($aowner,my $return_merchant) = $apif->fetch_merchant($q,\%varenv,$coo,$q->param('merchant_id')); $varenv{merchant_id} = $return_merchant->{merchant_id}; $response = { %$response, %$return_merchant }; my ($auth,$authraw) = $apif->auth_verify($q); my $user_agent_subversion = 1000; #$user_agent = "3.0.348";#test $user_agent_subversion = $1 if($user_agent =~ /3\.0\.(\d+)/); #merchant_message timerange my $lnow = strftime("%Y-%m-%d %H:%M:%S", localtime(time)); my $localtime = Time::Piece->strptime($lnow, "%Y-%m-%d %H:%M:%S"); my $epoch_now = $localtime->epoch; my $maintanance_start = Time::Piece->strptime("2023-03-06 00:00:00", "%Y-%m-%d %H:%M:%S"); my $maintanance_end = Time::Piece->strptime("2023-04-01 01:00:00", "%Y-%m-%d %H:%M:%S"); my $epoch_start = $maintanance_start->epoch; my $epoch_end = $maintanance_end->epoch; #App update message if($user_agent_subversion <= 348){ if($epoch_now >= $epoch_start && $epoch_now <= $epoch_end){ my $pref_ctu = { table => "contentuser", fetch => "one", ct_name => "App-update-message", }; my $uadr = { c_id => 0 }; $uadr = $dbt->fetch_tablerecord($dbh,$pref_ctu); $response->{merchant_message} = $uadr->{txt01} . $user_agent; $response->{merchant_message} = $uadr->{txt02} if($q->param('lang') eq "en"); }else{ $apif->authout($q,$coo); } } #user_rental $response->{user_rental} = {}; if($authraw->{txt19} && $authraw->{txt19} =~ /sharee_/){ my $last_used_operator = $authraw->{txt19}; my $dbh_operator = $dbt->dbconnect_extern("$last_used_operator"); my $record_rentals = {}; $record_rentals = $apif->user_bikes_occupied($dbh_operator,$authraw,""); foreach my $r_id (keys (%$record_rentals)){ if($record_rentals->{$r_id}->{c_id}){ my $prefix = $record_rentals->{$r_id}->{txt12}; my $station_type = "A-B"; $station_type = "A-A" if($record_rentals->{$r_id}->{int41}); $response->{user_rental} = { $record_rentals->{$r_id}->{c_id} => { bike_id => "$prefix$record_rentals->{$r_id}->{barcode}", station_id => "$prefix$record_rentals->{$r_id}->{int06}", station_group => "$prefix$record_rentals->{$r_id}->{int29}", station_type => "$station_type", }}; } } } $response = { %$response, %$auth }; ($response->{stations},$response->{uri_operator_array},$response->{user_group},$response->{user_tour}) = $jsc->loop_sharees($q,$auth,$authraw,$return_merchant); }else{ ($aowner,my $return_merchant) = $apif->fetch_merchant($q,\%varenv,$coo,$q->param('merchant_id')); $varenv{merchant_id} = $return_merchant->{merchant_id}; my $auth = {}; my $authraw = {}; ($auth,$authraw) = $apif->auth_verify($q,"","",1); $response = { %$response, %$auth }; #sig first save if($varenv{syshost} eq "shareeapp-sx"){ ($response->{stations},my $return2copri->{stations}) = $si->sig_available($q,\%varenv,$authraw); $tk->sigstation_cupdate($return2copri->{stations}); }else{ ($response->{stations}, my $response_raw) = $apif->stations_available($q,\%varenv,$authraw,""); } } } #user_feedback / user_minianswer of user_miniquery elsif($q->param('request') eq "user_feedback" || $q->param('request') eq "user_minianswer"){ ($aowner,my $return_merchant) = $apif->fetch_merchant($q,\%varenv,$coo,$q->param('merchant_id')); $varenv{merchant_id} = $return_merchant->{merchant_id}; $response = { %$response, %$return_merchant }; my ($auth,$authraw) = $apif->auth_verify($q); $response = { %$response, %$auth }; $response->{uri_operator} = "$varenv{wwwhost}"; if(ref($auth) eq "HASH" && $auth->{authcookie}){ my $customer = $auth->{c_id}; #print Dumper($auth); (my $xresponse->{$customer}, my $responseraw, my $node_template, my $crecord) = $apif->service_select($q,$authraw,"","1"); #$bw->log("c_id: $crecord->{c_id} |user_feedback OR user_minianswer node_template",$node_template,""); my $back_id = ""; my $rows=0; #if(!$back_id)#disabled because of every feedback have to be saved if(1==1){ #INSERT just dadaset $back_id = $apif->service_insert($q,$authraw,$node_template,$crecord,$aowner); $rows = $apif->service_update($q,$authraw,$node_template,$back_id); if($rows && $rows > 0){ $response->{response_state} = "OK, feedback insert and update"; $response->{response_text} = "Danke für die Nachricht."; }else{ $response->{response_state} = "Failure 3606, feedback_update"; $response->{response_text} = "Die Nachricht konnte leider nicht gespeichert werden."; } } #($xresponse->{$customer}, $responseraw, $node_template, $crecord) = $apif->service_select($q,$authraw,$back_id,"") if($back_id); #my $response_work = {}; #$response_work->{feedback} = $apif->feedback_response($responseraw,$node_template); #$response = { %$response, %$response_work }; } } #service_done #insert and/or update elsif($q->param('request') eq "service_done"){ ($aowner,my $return_merchant) = $apif->fetch_merchant($q,\%varenv,$coo,$q->param('merchant_id')); $varenv{merchant_id} = $return_merchant->{merchant_id}; $response = { %$response, %$return_merchant }; my ($auth,$authraw) = $apif->auth_verify($q); my $station_id = $1 if($q->param('station') =~ /(\d+)/); #my $bike_id = $1 if($q->param('bike') =~ /(\d+)/); my $bike = $q->escapeHTML($q->param('bike')) || ""; my $bike_id = $bike; $bike_id =~ s/S[1-9]X/SX/; $bike_id = $1 if($bike_id =~ /(\d+)/); $response->{uri_operator} = "$varenv{wwwhost}"; if(ref($auth) eq "HASH" && $auth->{authcookie}){ if(looks_like_number($bike_id) || looks_like_number($station_id)){ my $article = looks_like_number($bike_id) || looks_like_number($station_id); #select services with max work_duration of 1 day and service_worker alias contentadr.c_id = contenttranspo.owner match (my $xresponse->{$article}, my $responseraw, my $node_template, my $crecord) = $apif->service_select($q,$authraw,"","1"); #$bw->log("service_done OOO: node",$node_template,""); if(ref($xresponse->{$article}) eq "HASH"){ #$bw->log("service_done xresponse",$xresponse->{$article},""); #if no new_task then select last service_id with work_duration < 1 day my $service_id = ""; if(!$q->param('new_task') && $q->param('work_val') ne "::new_task::"){ foreach my $id (sort { $xresponse->{$article}->{$a}->{mtime} cmp $xresponse->{$article}->{$b}->{mtime} } keys (%{$xresponse->{$article}})){ $service_id = $id if($id > 1); } } my $rows=0; $service_id = $1 if($q->param('service_id') =~ /(\d+)/); if(!$service_id){ #INSERT just dadaset (without work values) ($response->{service_id}) = $apif->service_insert($q,$authraw,$node_template,$crecord); $bw->log("service insert ",$response,""); #once again to get node_record template ($xresponse->{$article}, $responseraw, $node_template, $crecord) = $apif->service_select($q,$authraw,"","1"); #UPDATE $service_id = $response->{service_id}; $rows = $apif->service_update($q,$authraw,$node_template,$response->{service_id}); $response->{response_state} = "OK" if($rows > 0); $response->{response_text} = "OK, service_insert and update" if($rows > 0); }else{ #UPDATE $rows = $apif->service_update($q,$authraw,$node_template,$service_id); $response->{response_state} = "OK" if($rows > 0); $response->{response_text} = "OK, service_update" if($rows > 0); } #UPDATE bike content state if($q->param('work_id') eq "state" && looks_like_number($bike_id) && $q->param('work_val') =~ /available|maintenance|defect/){ #once again to get node_record template ($xresponse->{$article}, $responseraw, $node_template, $crecord) = $apif->service_select($q,$authraw,"","1"); while (my ($key, $value) = each %{ $dbt->{copri_conf}->{bike_state} }) { if($q->param('work_val') eq $value){ $rows = $apif->bikestate_update($authraw,$responseraw->{$service_id}->{cc_id},$key); $response->{response_state} = "OK"; $response->{response_text} = "OK, bikestate_update to state=$value"; } } } #UPDATE bike battery charge if($q->param('work_id') =~ /smartlock_battery_charge|bike_battery_charge/ && looks_like_number($bike_id) && looks_like_number($q->param('work_val'))){ #once again to get node_record template ($xresponse->{$article}, $responseraw, $node_template, $crecord) = $apif->service_select($q,$authraw,"","1"); my ($bikes_all,$bikes_allraw,$bikes_on_station) = $apif->bikes_all($q,\%varenv,$authraw,""); if($q->param('work_id') eq "smartlock_battery_charge"){ my $update_hash = { int14 => $q->param('work_val') }; $rows = $apif->bikestate_update($authraw,$responseraw->{$service_id}->{cc_id},"",$update_hash); $response->{response_state} = "OK"; $response->{response_text} = "OK, bikestate_update " . $q->param('work_id') . " to " . $q->param('work_val'); #add-on to log my $action = "txt11=" . $bikes_allraw->{$bike_id}->{int14} . " - " . $q->param('work_val'); $apif->service_update($q,$authraw,$node_template,$service_id,$action); } if($q->param('work_id') eq "bike_battery_charge"){ my $update_hash = { int19 => $q->param('work_val') }; $rows = $apif->bikestate_update($authraw,$responseraw->{$service_id}->{cc_id},"",$update_hash); $response->{response_state} = "OK"; $response->{response_text} = "OK, bikestate_update " . $q->param('work_id') . " to " . $q->param('work_val'); #add-on to log my $action = "txt12=" . $bikes_allraw->{$bike_id}->{int19} . " - " . $q->param('work_val'); $apif->service_update($q,$authraw,$node_template,$service_id,$action); } } #redistribution if(($q->param('work_id') eq "int04" || $q->param('work_id') eq "station") && looks_like_number($bike_id) && ($q->param('work_val') || looks_like_number($q->param('work_val')))){ $q->param(-name=>'work_id',-value=>"int04") if($q->param('work_id') eq "station");#station db-field is int04 my $to_station_id = $1 if($q->param('work_val') =~ /(\d+)/); my ($bikes_all,$bikes_allraw,$bikes_on_station) = $apif->bikes_all($q,\%varenv,$authraw,""); #add-on to log redistribute my $action = "txt10=" . $bikes_allraw->{$bike_id}->{int04} . " - " . $q->param('work_val'); $apif->service_update($q,$authraw,$node_template,$service_id,$action); my ($stations_all,$stations_allraw) = $apif->stations_all($q,\%varenv,$bikes_on_station,$authraw); if(looks_like_number($stations_allraw->{$to_station_id}->{int04})){ ($xresponse->{$article}, $responseraw, $node_template, $crecord) = $apif->service_select($q,$authraw,"","1"); my $update_hash = { int04 => "$to_station_id" }; $rows = $apif->bikestate_update($authraw,$responseraw->{$service_id}->{cc_id},"",$update_hash); $response->{response_state} = "OK" if($rows > 0); $response->{response_text} = "OK, bikestate_update to_station_id $to_station_id" if($rows > 0); }elsif($to_station_id == 0){#werkstatt ($xresponse->{$article}, $responseraw, $node_template, $crecord) = $apif->service_select($q,$authraw,"","1"); my $update_hash = { int04 => "$to_station_id" }; #5 = "defect" $rows = $apif->bikestate_update($authraw,$responseraw->{$service_id}->{cc_id},"5",$update_hash); $response->{response_state} = "OK" if($rows > 0); $response->{response_text} = "OK, bikestate_update to Werkstatt $to_station_id" if($rows > 0); }else{ $bw->log("service_update fails to_station_id: $to_station_id",$stations_allraw->{$to_station_id}->{int04},""); $response->{response_state} = "Failure 3003: service_update fails"; } } if($rows != 1){ $response->{response_state} = "Failure 3004: service_update fails"; } $response->{service_id_done} = $service_id; }else{ $response->{response_state} = "Failure 3009: service_update fails because of can not find bike or station"; $response->{response_text} = "Fehler, angefragte Artikel konnte nicht gefunden werden!"; } my $response_work = {}; my $node = {}; my ($bikes_all,$bikes_allraw,$bikes_on_station) = $apif->bikes_all($q,\%varenv,$authraw,""); if(looks_like_number($bike_id)){ (my $xresponse, my $pos_record, my $node_template, my $crecord) = $apif->service_select($q,$authraw,"","100");#check interval ($response_work, $node) = $apif->service_work($pos_record,$bikes_allraw,"",$node_template); } elsif(looks_like_number($station_id)){ my ($stations_all,$stations_allraw) = $apif->stations_all($q,\%varenv,$bikes_on_station,$authraw); (my $xresponse, my $pos_record, my $node_template, my $crecord) = $apif->service_select($q,$authraw,"","100");#check interval ($response_work, $node) = $apif->service_work($pos_record,$stations_allraw,"",$node_template); } #inject oprefix my $op_response_work = {}; foreach my $key (keys %$response_work){ $op_response_work->{$oprefix . $key} = $response_work->{$key}; } $response = { %$response, %$op_response_work, %$auth }; my $node_template_id = 0; $node_template_id = $node_template->{template_id} if(ref($node_template) eq "HASH" && $node_template->{template_id}); $response->{service_template} = "$node_template_id"; }else{ $response->{response_state} = "Failure 3002: no bike OR station ID defined"; } }else{ $response->{response_state} = "Failure 1001: authcookie not defined"; } }#end service_done #service_work #service_work. select last service by bike-id elsif($q->param('request') eq "service_work"){ ($aowner,my $return_merchant) = $apif->fetch_merchant($q,\%varenv,$coo,$q->param('merchant_id')); $varenv{merchant_id} = $return_merchant->{merchant_id}; $response = { %$response, %$return_merchant }; my ($auth,$authraw) = $apif->auth_verify($q); my $station_id = ""; $station_id = $1 if($q->param('station') =~ /(\d+)/); #$bike_id = $1 if($q->param('bike') =~ /(\d+)/); my $bike = $q->escapeHTML($q->param('bike')) || ""; my $bike_id = $bike; $bike_id =~ s/S[1-9]X/SX/; $bike_id = $1 if($bike_id =~ /(\d+)/); $response->{uri_operator} = "$varenv{wwwhost}"; my $node = {}; my $response_work = {}; my $history = 0; $history = $q->param('history') if(looks_like_number($q->param('history'))); if(ref($auth) eq "HASH" && $auth->{authcookie}){ if(looks_like_number($bike_id)){ my ($bikes_all,$bikes_allraw,$bikes_on_station) = $apif->bikes_all($q,\%varenv,$authraw,""); (my $xresponse, my $pos_record, my $node_template, my $crecord) = $apif->service_select($q,$authraw,"",$history); #$bw->log("service_work bike_id $bike_id pos_record",$pos_record,""); ($response_work, $node) = $apif->service_work($pos_record,$bikes_allraw,$history,$node_template); #$bw->log("service_work bike_id $bike_id response_work",$response_work,""); if(ref($response_work) ne "HASH"){#if fails $response->{response_state} = "Failure 4010: no service found"; } my $op_response_work = {}; foreach my $key (keys %$response_work){ $op_response_work->{$oprefix . $key} = $response_work->{$key}; } $response = { %$response, %$op_response_work, %$auth }; }elsif($q->param('bike') && $q->param('bike') eq "all"){ my ($bikes_all,$bikes_allraw,$bikes_on_station) = $apif->bikes_all($q,\%varenv,$authraw,""); my $bike = $q->param('bike'); (my $xresponse, my $pos_record, my $node_template, my $crecord) = $apif->service_select($q,$authraw,"",$history); ($response_work, $node) = $apif->service_work($pos_record,$bikes_allraw,$history,$node_template); if(ref($response_work) ne "HASH"){#if fails $response->{response_state} = "Failure 4011: no service found"; } my $op_response_work = {}; foreach my $key (keys %$response_work){ $op_response_work->{$oprefix . $key} = $response_work->{$key}; } $response = { %$response, %$op_response_work, %$auth }; }elsif(looks_like_number($station_id)){ my ($bikes_all,$bikes_allraw,$bikes_on_station) = $apif->bikes_all($q,\%varenv,$authraw,""); my ($stations_all,$stations_allraw) = $apif->stations_all($q,\%varenv,$bikes_on_station,$authraw); (my $xresponse, my $pos_record, my $node_template, my $crecord) = $apif->service_select($q,$authraw,"",$history); ($response_work, $node) = $apif->service_work($pos_record,$stations_allraw,$history,$node_template); if(ref($response_work) ne "HASH"){#if fails $response->{response_state} = "Failure 4013: no service found"; } my $op_response_work = {}; foreach my $key (keys %$response_work){ $op_response_work->{$oprefix . $key} = $response_work->{$key}; } $response = { %$response, %$op_response_work, %$auth }; }elsif($q->param('station') && $q->param('station') eq "all"){ my ($bikes_all,$bikes_allraw,$bikes_on_station) = $apif->bikes_all($q,\%varenv,$authraw,""); my ($stations_all,$stations_allraw) = $apif->stations_all($q,\%varenv,$bikes_on_station,$authraw); my $station = $q->param('station'); (my $xresponse, my $pos_record, my $node_template, my $crecord) = $apif->service_select($q,$authraw,"",$history); ($response_work, $node) = $apif->service_work($pos_record,$stations_allraw,$history,$node_template); if(ref($response_work) ne "HASH"){#if fails $response->{response_state} = "Failure 4014: no service found"; } my $op_response_work = {}; foreach my $key (keys %$response_work){ $op_response_work->{$oprefix . $key} = $response_work->{$key}; } $response = { %$response, %$op_response_work, %$auth }; }else{ $response->{response_state} = "Failure 3002: no bike OR station ID defined"; } }else{ $response->{response_state} = "Failure 1001: authcookie not defined"; } $response->{service_template} = "$node->{template_id}"; }#end service_work #last if request not defined else{ ($aowner,my $return_merchant) = $apif->fetch_merchant($q,\%varenv,$coo,$q->param('merchant_id')); $varenv{merchant_id} = $return_merchant->{merchant_id}; $response = { %$response, %$return_merchant }; $response->{'response_state'} = "Failure: request not defined"; } #end RESTful ------------------------------------------------------------ #FINAL JSON response OUTPUT ---------------------------------------------------------- my $jrout = $json->pretty->encode({shareejson => $response}); print $jrout; $bw->log("APIjsonserver response by $user_agent mapped aowner:$aowner",$jrout,"") if($user_agent !~ /APIclient/); #end JSON ---------------------------------------------------------------------------- return Apache2::Const::OK; }#end handler 1;