sharee.bike/copri4/main/src/Mod/APIjsonclient.pm

274 lines
10 KiB
Perl
Executable file

package APIjsonclient;
#
# SPDX-License-Identifier: AGPL-3.0-or-later
# Copyright (c) Rainer Gümpelein, TeilRad GmbH
#
#Client for shareejson api
#
use strict;
use warnings;
use POSIX;
use CGI; # only for debugging
use JSON;
use LWP::UserAgent;
use URI::Encode;
use Config::General;
use Mod::Basework;
use Mod::DBtank;
use Data::Dumper;
sub new {
my $class = shift;
my $self = {};
bless($self,$class);
return $self;
}
my $q = new CGI;
my $netloc = $q->url(-base=>1);
my $ua = LWP::UserAgent->new;
my $uri_encode = URI::Encode->new( { encode_reserved => 1 } );
$ua->agent("APIclient $netloc");
my $bw = new Basework;
my $dbt = new DBtank;
my $json = JSON->new->allow_nonref;
sub loop_sharees {
my $self = shift;
my $q = shift || "";
my $auth = shift;
my $authraw = shift;
my $return_merchant = shift || "";
my $last_used_operator = shift || "";
my @keywords = $q->param;
#only request keys which initated by sharee primary requests to operator
my $rest_hash = {};
my $rest = "";
foreach (@keywords){
if($_ =~ /request|authcookie|system|bike|station/g){
my $val = $q->param($_);
my $encoded_val = $uri_encode->encode($val);
$rest .= "$_=$encoded_val&";
$rest_hash->{$_} = "$encoded_val";
}
}
$rest =~ s/\&$//;
my $response_in = {};
my $globalconf_file = "/var/www/copri4/shareeconf/global.cfg";
my $conf = Config::General->new($globalconf_file);
my %globalconf = $conf->getall;
my @uri_operator_array = ();
my @user_group = ();
my @user_tour = ();
my $fetch_hash = {};
my $o=0;
while (my ($key, $op_name) = each %{ $globalconf{operator} }) {
my $ret_json = "";
my %ret_json_all = ();
my %ret_json_private = ();
my %ret_json_public = ();
my %withpub = ();
#shareetool, to loop only operators who is the shareetool by usersconf enabled
my $users_serviceapp = { u_id => 0 };
if($return_merchant->{aowner} && $return_merchant->{aowner} == 187 && $op_name->{database}->{dbname} && $authraw->{txt17} =~ /$op_name->{database}->{dbname}/){
my $dbh_operator = $dbt->dbconnect_extern($op_name->{database}->{dbname});
$users_serviceapp = $dbt->select_users($dbh_operator,$authraw->{c_id},"and int09=1");
$bw->log("shareetool select_users $return_merchant->{aowner} on $op_name->{database}->{dbname} $authraw->{c_id} $authraw->{txt17}",$users_serviceapp->{u_id},"");
}
#every sharee client must have a merchant_id which associate a project
if($op_name->{operatorApp} && ($users_serviceapp->{u_id} || $return_merchant->{merchant_id} eq $globalconf{website}->{'shareeweb-sharee'}->{merchant_id} || ($return_merchant->{project_id} eq $op_name->{project}))){
$o++;
#stations_available with optional caching
if($rest_hash->{request} eq "stations_available"){
push(@uri_operator_array, $op_name->{operatorApp});
#if disabled, reads DB
if($op_name->{cache_station} == 1){
#primary authraw
if($authraw->{txt30}){
my %prim_tarif_hash = ();
if($authraw->{txt30} =~ /\w\s\w/){
%prim_tarif_hash = map { $_ => 1 } split(/\s+/,$authraw->{txt30});
}elsif($authraw->{txt30} && $authraw->{txt30} =~ /(\w+)/){
$prim_tarif_hash{$1} = 1;
}
foreach my $optarif (keys(%prim_tarif_hash)){
my $op_key = "";
my $tarif_key = "";
if($optarif =~ /([A-Z]+)(\d+)/){
$op_key = $1;
$tarif_key = $2;
}
if($op_key && $op_key eq $op_name->{oprefix}){
#print $optarif . "---" . $op_name->{oprefix} . "\n";
$ret_json_private{$optarif} = $self->fetch_operator_json("$op_name->{operatorApp}/json/stations-$optarif.json","");
eval {
$bw->log("$o $key) Test Decode json-caching, using 1: $op_name->{operatorApp}/json/stations-$optarif.json","","");
my $response_in = "";
$response_in = decode_json($ret_json_private{$optarif});
};
if ($@){
$bw->log("$o $key) Failure Test reading json-caching, using fallback 1 and generate cache just-in-time: $op_name->{operatorApp}/APIjsonserver?$rest&cachme=$tarif_key",$ret_json,"");
#$ret_json_private{$optarif} = $self->fetch_operator_json("$op_name->{operatorApp}/APIjsonserver",$rest);
$self->fetch_operator_json("$op_name->{operatorApp}/APIjsonserver","$rest&cachme=$tarif_key");
$ret_json_private{$optarif} = $self->fetch_operator_json("$op_name->{operatorApp}/json/stations-$optarif.json","");
}
}
%ret_json_all = %ret_json_private;
}
}#primary private Tarifs
$withpub{$op_name->{oprefix}} = 0;
foreach my $optarif (keys(%ret_json_all)){
my $opx = $1 if($optarif =~ /([A-Z]+)(\d+)/);
if($op_name->{oprefix} eq $opx){
eval {
$bw->log("$o $key) Test Decode json-caching, using 2: ret_json_private hash","","");
my $response_in = "";
$response_in = decode_json($ret_json_all{$optarif});
foreach my $station (keys (%{ $response_in })) {
$withpub{$op_name->{oprefix}} = $response_in->{$station}->{withpub};
}
};
if ($@){
$bw->log("$o $key) Failure Test reading json-caching, No fallback for ret_json_private hash","","");
}
}
}
#print "$op_name->{oprefix}: $withpub{$op_name->{oprefix}}\n";
if($withpub{$op_name->{oprefix}} || $op_name->{withpub}){
$ret_json_public{$op_name->{oprefix}} = $self->fetch_operator_json("$op_name->{operatorApp}/json/stations-$op_name->{oprefix}.json","");
eval {
$bw->log("$o $key) Test Decode json-caching, using 3: $op_name->{operatorApp}/json/stations-$op_name->{oprefix}.json","","");
my $response_in = "";
$response_in = decode_json($ret_json_public{$op_name->{oprefix}});
};
if ($@){
$bw->log("$o $key) Failure Test reading json-caching, using fallback 3 and generate cache just-in-time: $op_name->{operatorApp}/APIjsonserver?$rest&cachme=public",$ret_json,"");
#$ret_json_public{$op_name->{oprefix}} = $self->fetch_operator_json("$op_name->{operatorApp}/APIjsonserver",$rest);
$self->fetch_operator_json("$op_name->{operatorApp}/APIjsonserver","$rest&cachme=public");
$ret_json_public{$op_name->{oprefix}} = $self->fetch_operator_json("$op_name->{operatorApp}/json/stations-$op_name->{oprefix}.json","");
}
%ret_json_all = ( %ret_json_all, %ret_json_public );
}
foreach my $optarif (keys(%ret_json_all)){
if($ret_json_all{$optarif}){
eval {
$bw->log("$o $key) Test Decode json-caching, using 3: ret_json_all hash","","");
my $response_in = "";
$response_in = decode_json($ret_json_all{$optarif});
foreach my $result (keys (%{ $response_in })) {
$fetch_hash->{$result} = $response_in->{$result};
}
};
if ($@){
$bw->log("$o $key) Failure Test reading json-caching, No fallback for ret_json_all hash","","");
}
}
}
}#end cache_station
else{
$ret_json = $self->fetch_operator_json("$op_name->{operatorApp}/APIjsonserver",$rest);
$bw->log("$o $key) Caching disabled, No reading json-caching, taking: $op_name->{operatorApp}/APIjsonserver?$rest",$ret_json,"");
}
}#end stations_available
#user_bike_occupied by $last_used_operator
elsif($last_used_operator && $rest_hash->{request} eq "user_bikes_occupied"){
if($last_used_operator eq $op_name->{database}->{dbname}){
#$bw->log("fetch_operator_json >> user_bikes_occupied by last_used_operator:$last_used_operator ","","");
$ret_json = $self->fetch_operator_json("$op_name->{operatorApp}/APIjsonserver","$rest&withoutkey=1");
}
}
#all other operator requests
else{
$ret_json = $self->fetch_operator_json("$op_name->{operatorApp}/APIjsonserver",$rest);
}
if($ret_json){
push(@uri_operator_array, $op_name->{operatorApp});
eval {
my $response_in = "";
$response_in = decode_json($ret_json);
#print Dumper($response_in);
#collect OP user_group
if($response_in->{shareejson}->{user_group}){
push (@user_group, @{$response_in->{shareejson}->{user_group}});
}
#collect OP user_tour
if($response_in->{shareejson}->{user_tour}){
push (@user_tour, @{$response_in->{shareejson}->{user_tour}});
}
if($q->param('request') && $q->param('request') =~ /stations_all|stations_available/){
foreach my $result (keys (%{ $response_in->{shareejson}->{stations} })) {
$fetch_hash->{$result} = $response_in->{shareejson}->{stations}->{$result};
#workaround, delete contributor test stations on global sharee project Freiburg
if($return_merchant->{project_id} eq "Freiburg" && $return_merchant->{project_id} ne $op_name->{project} && $fetch_hash->{$result}->{description} =~ /Contributor/i){
#$bw->log("delete contributor-station $result: $fetch_hash->{$result}->{description}","","");
delete $fetch_hash->{$result};
}
}
}
if($q->param('request') && $q->param('request') =~ /bikes_all|bikes_available/){
foreach my $result (keys (%{ $response_in->{shareejson}->{bikes} })) {
$fetch_hash->{$result} = $response_in->{shareejson}->{bikes}->{$result};
}
}
if($q->param('request') && $q->param('request') =~ /user_bikes_occupied/){
foreach my $result (keys (%{ $response_in->{shareejson}->{bikes_occupied} })) {
$fetch_hash->{$result} = $response_in->{shareejson}->{bikes_occupied}->{$result};
}
}
};
if ($@){
$bw->log("$o $key) Failure, eval json from jsonclient",$ret_json,"");
warn $@;
}
}else{
$bw->log("$o $key) NO json from Operator:",$op_name->{operatorApp},"");
}
#$bw->log("--> LOOP-end jsonclient loop_sharees user_group:\n",\@user_group,"");
}
}
#print "ALL:" . Dumper($fetch_hash);
#
return ($fetch_hash,\@uri_operator_array,\@user_group,\@user_tour);
}
sub fetch_operator_json {
my $self = shift;
my $operator_server = shift || "";
my $rest = shift || "";
my $operator_request = "$operator_server?$rest";
#$bw->log("fetch_operator_json >> $operator_request","$operator_request","");
my $req = HTTP::Request->new(GET => "$operator_request");
$req->content_type('application/x-www-form-urlencoded');
$req->content($rest);
my $res = $ua->request($req);
if ($res->is_success) {
#print $res->content;
#return $res->content;
my $encoded = Encode::encode('utf-8', Encode::decode('iso-8859-1',$res->content));
return $encoded;
}else {
return "";
}
}
1;