diff options
Diffstat (limited to 'torrus/perllib/Torrus/Renderer/HTML.pm')
-rw-r--r-- | torrus/perllib/Torrus/Renderer/HTML.pm | 597 |
1 files changed, 597 insertions, 0 deletions
diff --git a/torrus/perllib/Torrus/Renderer/HTML.pm b/torrus/perllib/Torrus/Renderer/HTML.pm new file mode 100644 index 000000000..6eec86d21 --- /dev/null +++ b/torrus/perllib/Torrus/Renderer/HTML.pm @@ -0,0 +1,597 @@ +# Copyright (C) 2002 Stanislav Sinyagin +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. + +# $Id: HTML.pm,v 1.14 2011-03-01 00:09:39 ivan Exp $ +# Stanislav Sinyagin <ssinyagin@yahoo.com> + +package Torrus::Renderer::HTML; + +use strict; + +use Torrus::ConfigTree; +use Torrus::Search; +use Torrus::Log; + +use URI::Escape; +use Template; +use POSIX qw(abs log floor pow); +use Date::Parse; +use Date::Format; + +Torrus::SiteConfig::loadStyling(); + +# All our methods are imported by Torrus::Renderer; + +sub render_html +{ + my $self = shift; + my $config_tree = shift; + my $token = shift; + my $view = shift; + my $outfile = shift; + + my $tmplfile = $config_tree->getParam($view, 'html-template'); + + my $expires = $config_tree->getParam($view, 'expires'); + + # Create the Template Toolkit processor once, and reuse + # it in subsequent render() calls + + if( not defined( $self->{'tt'} ) ) + { + $self->{'tt'} = + new Template(INCLUDE_PATH => $Torrus::Global::templateDirs, + TRIM => 1); + } + my $ttvars = + { + 'treeName' => $config_tree->treeName(), + 'token' => $token, + 'view' => $view, + 'expires' => $expires, + 'path' => sub { return $config_tree->path($_[0]); }, + 'pathToken' => sub { return $config_tree->token($_[0]); }, + 'nodeExists' => sub { return $config_tree->nodeExists($_[0]); }, + 'children' => sub { return $config_tree->getChildren($_[0]); }, + 'isLeaf' => sub { return $config_tree->isLeaf($_[0]); }, + 'isAlias' => sub { return $config_tree->isAlias($_[0]); }, + 'sortTokens' => sub { return $self->sortTokens($config_tree, + $_[0]); }, + 'nodeName' => sub { return $self->nodeName($config_tree, $_[0]); }, + 'parent' => sub { return $config_tree->getParent($_[0]); }, + 'nodeParam' => sub { return $config_tree->getNodeParam(@_); }, + 'param' => sub { return $config_tree->getParam(@_); }, + 'url' => sub { return $self->makeURL($config_tree, 0, @_); }, + 'persistentUrl' => sub { return $self->makeURL($config_tree, 1, @_); }, + 'clearVar' => sub { delete $self->{'options'}{'variables'}{$_[0]}; + return undef;}, + 'plainURL' => $Torrus::Renderer::plainURL, + 'splitUrls' => sub { return $self->makeSplitURLs($config_tree, + $_[0], $_[1]); }, + 'topURL' => ($Torrus::Renderer::rendererURL ne '' ? + $Torrus::Renderer::rendererURL : '/'), + 'rrprint' => sub { return $self->rrPrint($config_tree, + $_[0], $_[1]); }, + 'scale' => sub { return $self->scale($_[0], $_[1]); }, + 'tsetMembers' => sub { $config_tree->tsetMembers($_[0]); }, + 'tsetList' => sub { $config_tree->getTsets(); }, + 'style' => sub { return $self->style($_[0]); }, + 'companyName'=> $Torrus::Renderer::companyName, + 'companyLogo'=> $Torrus::Renderer::companyLogo, + 'companyURL' => $Torrus::Renderer::companyURL, + 'siteInfo' => $Torrus::Renderer::siteInfo, + 'treeInfo' => sub { return $Torrus::Global::treeConfig{ + $config_tree->treeName()}{'info'}; }, + 'version' => $Torrus::Global::version, + 'xmlnorm' => \&Torrus::Renderer::xmlnormalize, + 'userAuth' => $Torrus::CGI::authorizeUsers, + 'uid' => $self->{'options'}->{'uid'}, + 'userAttr' => sub { return $self->userAttribute( $_[0] ) }, + 'mayDisplayAdmInfo' => sub { + return $self->may_display_adminfo( $config_tree, $_[0] ) }, + 'adminfo' => $self->{'adminfo'}, + 'mayDisplayReports' => sub { + return $self->may_display_reports($config_tree) }, + 'reportsUrl' => sub { + return $self->reportsUrl($config_tree); }, + 'timestamp' => sub { return time2str($Torrus::Renderer::timeFormat, + time()); }, + 'verifyDate' => sub { return verifyDate($_[0]); }, + 'markup' => sub{ return $self->translateMarkup( @_ ); }, + 'searchEnabled' => $Torrus::Renderer::searchEnabled, + 'searchResults' => sub { return $self->doSearch($config_tree, $_[0]); }, + + #Freeside + 'freesideHeader' => sub { return $self->freesideHeader(@_); }, + 'freesideFooter' => sub { return $self->freesideFooter(); }, + 'freesideComponent' => sub { return $self->freesideComponent(@_); }, + 'uri_escape' => sub { return uri_escape(@_); }, + 'matches' => sub { return $_[0] =~ $_[1]; }, + 'iface_underscore' => sub { $_[0] =~ s/[\/\.]/_/g; return $_[0]; }, + 'load_nms' => sub { return $self->load_nms; }, + 'get_serviceids' => sub { my $nms = shift; + my $router = shift; + return $nms->get_router_serviceids($router); + }, + 'popup_link' => sub { + my $type = shift; + + if($type eq 'nms-add_iface.html') { + my $host = shift; + my $iface = shift; + my $nms = shift; + my $serviceids = shift; + + if ( $serviceids && $serviceids->{$iface} ) { + + my $svc_port = $nms->find_svc($serviceids->{$iface}); + + if ($svc_port) { + my $url = $Torrus::Freeside::FSURL. + "/view/svc_port.cgi?". $svc_port->svcnum; + return "<A HREF='$url'>View Service</A>"; + } else { + my $component = + $nms->find_torrus_srvderive_component($serviceids->{$iface}); + + if ($component) { + return $serviceids->{$iface}. ' combined into '. + $component->torrus_srvderive->serviceid; + } else { + return 'Monitored as '. $serviceids->{$iface}. + '; not yet provisioned or combined'; + } + } + + } else { + + return + $self->freesideComponent('/elements/popup_link.html', + 'action' => "/freeside/misc/". + $type."?host=$host;iface=$iface", + 'label' => 'Monitor for billing', + 'actionlabel' => 'Monitor interface', + ); + + } + + } elsif ($type eq 'nms-add_router.html') { + return + $self->freesideComponent('/elements/popup_link.html', + 'action' => "/freeside/misc/$type", + 'label' => 'Add Router', + 'actionlabel' => 'Add Router', + ); + } + + ''; + }, + + }; + + + # Pass the options from Torrus::Renderer::render() to Template + while( my( $opt, $val ) = each( %{$self->{'options'}} ) ) + { + $ttvars->{$opt} = $val; + } + + my $result = $self->{'tt'}->process( $tmplfile, $ttvars, $outfile ); + + undef $ttvars; + + if( not $result ) + { + if( $config_tree->isTset( $token ) ) + { + Error("Error while rendering tokenset $token: " . + $self->{'tt'}->error()); + } + else + { + my $path = $config_tree->path($token); + Error("Error while rendering $path: " . + $self->{'tt'}->error()); + } + return undef; + } + + return ($expires+time(), 'text/html; charset=UTF-8'); +} + + +sub nodeName +{ + my $self = shift; + my $config_tree = shift; + my $token = shift; + + my $n = $config_tree->getNodeParam($token, 'node-display-name', 1); + if( defined( $n ) and length( $n ) > 0 ) + { + return $n; + } + + return $config_tree->nodeName($config_tree->path($token)); +} + + +sub sortTokens +{ + my $self = shift; + my $config_tree = shift; + my $tokenlist = shift; + + my @sorted = (); + if( ref($tokenlist) and scalar(@{$tokenlist}) > 0 ) + { + @sorted = sort + { + my $p_a = $config_tree->getNodeParam($a, 'precedence', 1); + $p_a = 0 unless defined $p_a; + my $p_b = $config_tree->getNodeParam($b, 'precedence', 1); + $p_b = 0 unless defined $p_b; + if( $p_a == $p_b ) + { + my $n_a = $config_tree->path($a); + my $n_b = $config_tree->path($b); + return $n_a cmp $n_b; + } + else + { + return $p_b <=> $p_a; + } + } @{$tokenlist}; + } + else + { + push(@sorted, $tokenlist); + } + return @sorted; +} + + +# compose an URL for a node. +# $persistent defines if the link should be persistent +# Persistent link is done with nodeid if available, or with path + +sub makeURL +{ + my $self = shift; + my $config_tree = shift; + my $persistent = shift; + my $token = shift; + my $view = shift; + my @add_vars = @_; + + my $ret = $Torrus::Renderer::rendererURL . '/' . $config_tree->treeName(); + + if( $persistent ) + { + my $nodeid = $config_tree->getNodeParam($token, 'nodeid', 1); + if( defined( $nodeid ) ) + { + $ret .= '?nodeid=' . + uri_escape($nodeid, $Torrus::Renderer::uriEscapeExceptions); + } + else + { + $ret .= '?path=' . + uri_escape($config_tree->path($token), + $Torrus::Renderer::uriEscapeExceptions); + } + } + else + { + $ret .= '?token=' . uri_escape($token); + } + + if( $view ) + { + $ret .= '&view=' . uri_escape($view); + } + + my %vars = (); + # This could be array or a reference to array + my $add_vars_size = scalar( @add_vars ); + if( $add_vars_size == 1 and ref( $add_vars[0] ) ) + { + %vars = @{$add_vars[0]}; + } + elsif( $add_vars_size > 0 and ($add_vars_size % 2 == 0) ) + { + %vars = @add_vars; + } + + if( ref( $self->{'options'}->{'variables'} ) ) + { + foreach my $name ( sort keys %{$self->{'options'}->{'variables'}} ) + { + my $val = $self->{'options'}->{'variables'}->{$name}; + if( not defined( $vars{$name} ) ) + { + $vars{$name} = $val; + } + } + } + + foreach my $name ( sort keys %vars ) + { + if( $vars{$name} ne '' ) + { + $ret .= '&' . $name . '=' . + uri_escape( $vars{$name}, + $Torrus::Renderer::uriEscapeExceptions ); + } + } + + return $ret; +} + +sub makeSplitURLs +{ + my $self = shift; + my $config_tree = shift; + my $token = shift; + my $view = shift; + + my $ret = ''; + while( defined( $token ) ) + { + my $path = $config_tree->path($token); + + my $str = '<SPAN CLASS="PathElement">'; + $str .= + sprintf('<A HREF="%s">%s%s</A>', + $self->makeURL($config_tree, 0, $token, $view), + $config_tree->nodeName($path), + ( $config_tree->isSubtree($token) and + $path ne '/') ? '/':'' ); + $str .= "</SPAN>\n"; + + $ret = $str . $ret; + + $token = $config_tree->getParent( $token ); + } + + return $ret; +} + + +sub rrPrint +{ + my $self = shift; + my $config_tree = shift; + my $token = shift; + my $view = shift; + + my @ret = (); + my($fname, $mimetype) = $self->render( $config_tree, $token, $view ); + + if( $mimetype ne 'text/plain' ) + { + Error("View $view does not produce text/plain for token $token"); + } + else + { + if( not open(IN, $fname) ) + { + Error("Cannot open $fname for reading: $!"); + } + else + { + chomp(my $values = <IN>); + @ret = split(':', $values); + close IN; + } + } + return @ret; +} + +# This subroutine is taken from Dave Plonka's Flowscan + +sub scale +{ + my $self = shift; + # This is based somewhat on Tobi Oetiker's code in rrd_graph.c: + my $fmt = shift; + my $value = shift; + my @symbols = ("a", # 10e-18 Ato + "f", # 10e-15 Femto + "p", # 10e-12 Pico + "n", # 10e-9 Nano + "u", # 10e-6 Micro + "m", # 10e-3 Milli + " ", # Base + "k", # 10e3 Kilo + "M", # 10e6 Mega + "G", # 10e9 Giga + "T", # 10e12 Terra + "P", # 10e15 Peta + "E"); # 10e18 Exa + + my $symbcenter = 6; + my $digits = (0 == $value)? 0 : floor(log(abs($value))/log(1000)); + return sprintf( $fmt . " %s", $value/pow(1000, $digits), + $symbols[ $symbcenter+$digits ] ); +} + +sub style +{ + my $self = shift; + my $object = shift; + + my $media; + if( not defined( $media = $self->{'options'}->{'variables'}->{'MEDIA'} ) ) + { + $media = 'default'; + } + return $Torrus::Renderer::styling{$media}{$object}; +} + + + +sub userAttribute +{ + my $self = shift; + my $attr = shift; + + if( $self->{'options'}->{'uid'} and $self->{'options'}->{'acl'} ) + { + $self->{'options'}->{'acl'}-> + userAttribute( $self->{'options'}->{'uid'}, $attr ); + } + else + { + return ''; + } +} + +sub hasPrivilege +{ + my $self = shift; + my $object = shift; + my $privilege = shift; + + if( $self->{'options'}->{'uid'} and $self->{'options'}->{'acl'} ) + { + $self->{'options'}->{'acl'}-> + hasPrivilege( $self->{'options'}->{'uid'}, $object, $privilege ); + } + else + { + return undef; + } +} + + +sub translateMarkup +{ + my $self = shift; + my @strings = @_; + + my $tt = new Template( TRIM => 1 ); + + my $ttvars = + { + 'em' => sub { return '<em>' . $_[0] . '</em>'; }, + 'strong' => sub { return '<strong>' . $_[0] . '</strong>'; } + }; + + my $ret = ''; + + foreach my $str ( @strings ) + { + my $output = ''; + my $result = $tt->process( \$str, $ttvars, \$output ); + + if( not $result ) + { + Error('Error translating markup: ' . $tt->error()); + } + else + { + $ret .= $output; + } + } + + undef $tt; + + return $ret; +} + + +sub verifyDate +{ + my $input = shift; + + my $time = str2time( $input ); + # rrdtool does not understand dates prior to 1980 (315529200) + if( defined( $time ) and $time > 315529200 ) + { + # Present the time in format understood by rrdtool + return time2str('%H:%M %Y%m%d', $time); + } + else + { + return ''; + } +} + + +sub may_display_reports +{ + my $self = shift; + my $config_tree = shift; + + if( $Torrus::Renderer::displayReports ) + { + if( not $Torrus::CGI::authorizeUsers ) + { + return 1; + } + + my $tree = $config_tree->treeName(); + if( $self->hasPrivilege( $tree, 'DisplayReports' ) and + -r $Torrus::Global::reportsDir . '/' . $tree . + '/html/index.html' ) + { + return 1; + } + } + return 0; +} + + +sub reportsUrl +{ + my $self = shift; + my $config_tree = shift; + + return $Torrus::Renderer::rendererURL . '/' . + $config_tree->treeName() . '?htmlreport=index.html'; +} + + +sub doSearch +{ + my $self = shift; + my $config_tree = shift; + my $string = shift; + + + my $tree = $config_tree->treeName(); + + my $sr = new Torrus::Search; + $sr->openTree( $tree ); + my $result = $sr->searchPrefix( $string, $tree ); + $sr->closeTree( $tree ); + + my $ret = []; + push( @{$ret}, sort {$a->[0] cmp $b->[0]} @{$result} ); + + return $ret; +} + + +1; + + +# Local Variables: +# mode: perl +# indent-tabs-mode: nil +# perl-indent-level: 4 +# End: |