#!/usr/bin/perl package Ernad::Chungju; use strict; use warnings; use File::Copy; use Data::Dumper; use File::Basename; use XML::LibXML; ## fixme!!! This should come from the configuration my $allport='nep-all'; my $ernad_ns='http://ernad.openlib.org'; my $xhtml_ns='http://www.w3.org/1999/xhtml'; my $dom=XML::LibXML->new(); my $home_dir=$ENV{'HOME'} // '' ; if(not $home_dir) { $home_dir='/home/ernad'; } my $orders_outstanding_dir="$home_dir/opt/chungju/orders"; my $orders_accepted_dir="$home_dir/var/chungju/orders/accepted"; my $orders_refused_dir="$home_dir/var/chungju/orders/refused"; my $orders_fullfilled_dir="$home_dir/var/chungju/orders/fullfilled"; my $adverts_dir="$home_dir/var/chungju/adverts"; my $adverts_fullfilled_dir="$home_dir/var/chungju/adverts/fullfilled"; my $previous_report_file="$home_dir/var/chungju/last_order_report.txt"; my $accepted_orders_file="$home_dir/var/chungju/accepted_orders.txt"; sub inject_advert_into_rif { my $advert_element=shift; my $rif_file=shift; if(not -f $rif_file) { warn "no such file $rif_file"; exit; } my $rif_doc = $dom->parse_file($rif_file); my $xc = XML::LibXML::XPathContext->new($rif_doc); $xc->registerNs('h', 'http://www.w3.org/1999/xhtml'); $xc->registerNs('a', 'http://amf.openlib.org'); $xc->registerNs('e', 'http://ernad.openlib.org'); ## clears existing ad_elemnet foreach my $existing_advert_element ($xc->findnodes('//e:advert')) { ## fixme. This will not remove adverts with a if($existing_advert_element->hasAttribute('report')) { next; } $existing_advert_element->parentNode->removeChild($existing_advert_element); } ## let's place the advert next to the issuedate my $issuedate_element=$xc->findnodes('//e:issuedate')->[0]; if(not defined($issuedate_element)) { die "no issuedate in rif $rif_file"; } my $collection_element=$xc->findnodes('/a:amf/a:collection')->[0]; $collection_element->insertAfter($advert_element,$issuedate_element); $rif_doc->toFile($rif_file,2); return $rif_doc; } sub transform_order_to_advert { my $order_file=shift; my $report=shift; ## find order file from that my $order_file_name=basename($order_file); my $order_date=&order_file_to_order_date($order_file); my $order_doc = $dom->parse_file($order_file); my $order_element=$order_doc->documentElement(); my $report_id_text_upper = XML::LibXML::Text->new(uc($report)); my $report_id_text_lower = XML::LibXML::Text->new(lc($report)); my $advert_element = $order_doc->createElement('advert'); $advert_element->setNamespace($ernad_ns,'e'); my $xc = XML::LibXML::XPathContext->new($order_doc); $xc->registerNs('h', 'http://www.w3.org/1999/xhtml'); $xc->registerNs('e', 'http://ernad.openlib.org'); foreach my $report_id_element ($xc->findnodes('//e:report_id')) { my $case=$report_id_element->getAttribute('case') // ''; ## use lower case by default my $replace_text=$report_id_text_lower->cloneNode; if($case eq 'upper') { $replace_text=$report_id_text_upper->cloneNode; } $report_id_element->parentNode->replaceChild($replace_text,$report_id_element); } my $text_element=$xc->findnodes('/e:order/e:text')->[0]; my $html_element=$xc->findnodes('/e:order/e:html')->[0]; $advert_element->appendChild($text_element); $advert_element->appendChild($html_element); return $advert_element; } ### Find the advert file when the report is the allport. ### Copy into the curent file for the other report #sub find_and_organize_order_file_allport { # my $orders_outstanding_dir="$home_dir/opt/chungju/orders"; # my $orders_fullfilled_dir="$home_dir/var/chungju/orders"; # my $to_do_dates=&get_dates_from_dir($orders_outstanding_dir); # my $done_dates=&get_dates_from_dir($orders_fullfilled_dir); # foreach my $done_date (keys %{$done_dates}) { # if(defined($to_do_dates->{$done_date})) { # delete $to_do_dates->{$done_date}; # } # } # my @orders_to_do=sort keys $to_do_dates; # my $date=$orders_to_do[0]; # if(not defined($date)) { # return 0; # } # my $order_file="$orders_outstanding_dir/$date.xml"; # my $current_file="$orders_fullfilled_dir/$date"."_current.xml"; # my $fullfilled_file="$orders_fullfilled_dir/$date.xml"; # ## copy to the current file # copy($order_file,$current_file); # copy($order_file,$fullfilled_file); # return $fullfilled_file; #} # ### Find the file if the report is not the allport simply use the file ### marked as current. If there are serveral report the last and warn. #sub find_and_organize_order_file_non_allport { # my $orders_fullfilled_dir="$home_dir/var/chungju/orders"; # my $count_current_files=0; # my $current_file=''; # foreach $current_file (`ls $orders_fullfilled_dir`) { # if(not $current_file=~m|^(\d{4}-\d{2}-\d{2})_current\.xml$|) { # next; # } # $count_current_files++; # } # if($count_current_files>1) { # warn "more than one current file"; # } # if(not $count_current_files) { # warn "no current files found"; # exit; # } # return $current_file; #} # sub get_dates_from_dir { my $dir=shift; my $o; if(not -d $dir) { warn "no such directory: $dir"; exit; } foreach my $file (`ls $dir`) { chomp $file; if(not $file=~m|^(\d{4}-\d{2}-\d{2})\.xml$|) { next; } my $date=$1; my $size=`stat -c %s $dir/$file`; chomp $size; $o->{$date}=$size; } return $o; } sub report_on_state_of_order_file { my $order_file=shift; ## optional arguments, required for monitoring ## to avoid repeating reports ## these will not be defined in a more detailed report my $accepted_orders=shift; ## output structure my $out; ## default is that we need to take action my $action=1; ## the report my $report=''; if(not $order_file=~m|^\d{4}-\d{2}-\d{2}\.xml$|) { return; } my $result=''; my $accepted_file="$orders_accepted_dir/$order_file"; my $refused_file="$orders_refused_dir/$order_file"; my $fullfilled_file="$orders_fullfilled_dir/$order_file"; my $fullfilled_file_exists=0; my $order_file_age=-M "$orders_outstanding_dir/$order_file"; my $accepted_file_age=-M $accepted_file; my $refused_file_age=-M $refused_file; if(-f $fullfilled_file) { $fullfilled_file_exists=1; } ## status is 'new', 'changed' or 'old'. my $status_accepted=&find_status($order_file,$orders_accepted_dir); my $status_refused=&find_status($order_file,$orders_refused_dir); ## just to prettyprint the order my $order=substr($order_file,0,length($order_file)-4); ## new order if($status_accepted eq 'new' and $status_refused eq 'new') { $result="A new order $order is available.\n"; if($fullfilled_file_exists) { $result.="But there is an advert file for it. Something is wrong.\n"; } } if($status_accepted eq 'new' and $status_refused eq 'changed') { $result="A new version of refused order $order is available.\n"; if($fullfilled_file_exists) { $result.="But there is an advert file for it. Something is wrong.\n"; } } if($status_accepted eq 'new' and $status_refused eq 'old') { $result="The order $order is still refused, no new decision.\n"; $action=0; if($fullfilled_file_exists) { $result.="But there is an advert file for it. Something is wrong.\n"; } } if($status_accepted eq 'old' and $status_refused eq 'new') { $result="The order $order is accepted.\n"; $action=0; ## this was not known, and we check for it if(defined($accepted_orders) and not defined($accepted_orders->{$order})) { $action=1; $accepted_orders->{$order}=1; } } if($status_accepted eq 'changed' and $status_refused eq 'new') { $result="A new version of an accepted order $order is available.\n"; if($fullfilled_file_exists) { $result.="But there is an advert file it. Something is wrong.\n"; } if(defined($accepted_orders)) { delete $accepted_orders->{$order}; } } if($status_accepted eq 'changed' and $status_refused eq 'old') { if($accepted_file_age > $refused_file_age) { $result="The order $order is refused but an earlier version was accepted.\n"; $result.="I am deleting the earlier accepted version\n"; unlink($accepted_file); } if($accepted_file_age < $refused_file_age) { $result="The current order is refused but a different, more recent version was accepted.\n"; $result.="I am deleting the more recent accepted version\n"; unlink($accepted_file); } if(defined($accepted_orders)) { delete $accepted_orders->{$order}; } } if($status_accepted eq 'changed' and $status_refused eq 'changed') { $result="Yikes. The order $order_file has been changed that has been accepted and refused.\n"; $result.="I treat it as as new order. I will remove the accepted and refused order.\n"; unlink($accepted_file); unlink($refused_file); if(defined($accepted_orders)) { delete $accepted_orders->{$order}; } } if($status_accepted eq 'old' and $status_refused eq 'old') { $result="Yikes. The same order $order is both accepted and refused\n."; if($accepted_file_age > $refused_file_age) { $result.="I am deleting the earlier accepted version\n"; unlink($accepted_file); if(defined($accepted_orders)) { delete $accepted_orders->{$order}; } } if($accepted_file_age < $refused_file_age) { $result="The current add is refused but a different, more recent version was accepted.\n"; $result.="I am deleting the earlier refused version\n"; unlink($refused_file); } } if($status_accepted eq 'old' and $status_refused eq 'changed') { if($order_file_age < $refused_file_age) { $result="An earlier order that was refused has been accepted.\n"; ## no more action on this required $action=0; ## if this was not known, if(defined($accepted_orders) and not defined($accepted_orders->{$order})) { $accepted_orders->{$order}=1; } } if($order_file_age > $refused_file_age) { $result="A version of the order was recently refused by the order accepted."; $result.="Somehing is wrong\n"; } } $out->{'result'}=$result; $out->{'action'}=$action; $out->{'accepted'}=$status_accepted; return $out; } sub order_file_to_order_date { my $order_file_name=shift; my $order_date=substr($order_file_name,0,length($order_file_name)-4); return $order_date; } ## sub find_status { my $file=shift; my $dir=shift; my $order_file="$orders_outstanding_dir/$file"; my $dir_file="$dir/$file"; if(not -f $dir_file) { return 'new'; } if(`diff -w $dir_file $order_file`) { return 'changed'; } return 'old'; } sub fullfill_order { my $order_file=shift; my $fullfill_date=shift; if(not $order_file=~m|^(\d{4}-\d{2}-\d{2})\.xml$|) { die; } if(not $fullfill_date=~m|^\d{4}-\d{2}-\d{2}$|) { die; } my $order_date=&order_file_to_order_date($order_file); my $fullfilled_file="$orders_fullfilled_dir/$order_file"; if(-f $fullfilled_file) { return "order $order_date already fullfilled\n"; } my $advert_file="$adverts_fullfilled_dir/$order_date.xml"; if(-f $advert_file) { return "There is already an avert file for $fullfill_date\n"; } my $parser = XML::LibXML->new; my $order_doc=$parser->parse_file("$orders_accepted_dir/$order_file"); $order_doc->setEncoding('utf-8'); my $root_element=$order_doc->documentElement; $root_element->setAttribute('fullfill_date',$fullfill_date); $order_doc->toFile("$fullfilled_file",2); print "writing $advert_file\n"; $order_doc->toFile("$advert_file",2); ## return 0 on success return 0; } ## finds an order to fullfill sub find_order_to_fullfill { foreach my $order_file (`ls $orders_outstanding_dir`) { chomp $order_file; if(not $order_file=~m|^\d{4}-\d{2}-\d{2}\.xml$|) { next; } #print "order_file is $order_file\n"; my $order_fullfilled_file="$orders_fullfilled_dir/$order_file"; my $order_date=&Ernad::Chungju::order_file_to_order_date($order_file); my $out=&Ernad::Chungju::report_on_state_of_order_file($order_file); my $action=$out->{'action'}; if($action) { print "order of $order_date needs work\n"; next; } if(-f $order_fullfilled_file) { print "order $order_date is fullfilled\n"; next; } return $order_file; } return ''; } sub find_advert_to_put_in_subject_report { my $current_date=shift; foreach my $file (`ls -t $adverts_fullfilled_dir`) { chomp $file; my $fufi="$adverts_fullfilled_dir/$file"; print "found advert fullfilled file $fufi\n"; open my $fh, '<', "$fufi"; binmode $fh; # drop all PerlIO layers possibly created by a use open pragma my $doc = XML::LibXML->load_xml(IO => $fh) or die; my $date=$doc->documentElement->getAttribute('fullfill_date') // ''; if(not $date) { print "no fullfill date in $fufi\n"; next; } if($date eq $current_date) { print "found advert $fufi\n"; return $fufi; } print "fullfill_date on advert in file $file is $date, not $current_date\n"; } return ''; } 1;