- package LedgerSMB::RESTXML::Handler;
- use strict;
- use warnings;
- use Carp;
- use LedgerSMB::User;
- use LedgerSMB::Sysconfig;
- use LedgerSMB::Log;
- use Scalar::Util qw(blessed);
- use DBI;
- =head3 cgi_handle
- CGI_handle is the gateway for the RESTful lsmb API.
- =head3 NOTES
- =cut
- sub cgi_handle {
- my $self = shift;
- my $method = $ENV{REQUEST_METHOD};
- my $pathinfo = $ENV{PATH_INFO};
- #pull off the leading slash, we need it in the form document/arguments/foo
- $pathinfo =~ s#^/##;
- my $function = 'handle_' . lc($method);
- my ( $user, $module, @args ) = split '/', $pathinfo;
- $user = LedgerSMB::User->fetch_config($user);
- my $dbh = $self->connect_db($user);
- # non-word characters are forbidden, usually a sign of someone being sneaky.
- $module =~ s#\W##;
- my $document_module = $self->try_to_load($module);
- if ($document_module) {
- if ( $document_module->can($function) ) {
- my $returnValue = $document_module->$function(
- {
- dbh => $dbh,
- args => \@args,
- handler => $self,
- user => $user
- }
- );
- #return $self->return_serialized_response($returnValue);
- }
- else {
- return $self->unsupported("$module cannot handle method $method");
- }
- }
- else {
- return $self->not_found(
- "Could not find a handler for document type $module: <pre>$@</pre>"
- );
- }
- }
- sub cgi_report_error {
- my $self = shift;
- my $message = shift;
- my $code = shift || 500;
- print "Status: $code\n";
- print "Content-Type: text/html\n\n";
- print "<html><body>\n";
- print "<h1>REST API error</h1>";
- print "<blockquote>$message</blockquote>";
- print "</body></html>";
- }
- sub cgi_read_query {
- my $self = shift;
- use CGI;
- my $cgi = CGI->new();
- return $cgi;
- }
- # ------------------------------------------------------------------------------------------------------------------------
- =head3 try_to_load
- try_to_load will try to load a RESTXML document handler module. returns undef
- if it cannot load the given module for any reason. passed the type of RESTXML
- document to try to load. returns a blessed anonymous hashref if the module
- *can*, and is successfully loaded.
- =cut
- sub try_to_load {
- my $self = shift;
- my $module = shift;
- eval qq{
- use LedgerSMB::RESTXML::Document::$module;
- };
- if ($@) {
- warn "Cannot load $module: $@" unless $@ =~ /Can't locate LedgerSMB\//i;
- return undef;
- }
- else {
- return bless {}, "LedgerSMB::RESTXML::Document::$module";
- }
- }
- =head3 connect_db
- Given a user's config, returns a database connection handle.
- =cut
- sub connect_db {
- my ( $self, $myconfig ) = @_;
- my $dbh = DBI->connect( $myconfig->{dbconnect},
- $myconfig->{dbuser}, $myconfig->{dbpasswd} )
- or carp "Error connecting to the db :$DBI::errstr";
- $dbh->{pg_enable_utf8} = 1;
- return $dbh;
- }
- # lets see how far XML::Simple can take us.
- use XML::Simple;
- use Scalar::Util qw(blessed);
- sub return_serialized_response {
- my ( $self, $response ) = @_;
- print "Content-type: text/xml\n\n";
- if ( blessed $response && $response->isa('XML::Twig::Elt') ) {
- print qq{<?xml version="1.0"?>\n};
- print $response->sprint();
- }
- else {
- my $xs = XML::Simple->new(
- NoAttr => 1,
- RootName => 'LedgerSMBResponse',
- XMLDecl => 1
- );
- print $xs->XMLout($response);
- }
- return;
- }
- sub read_query {
- my ($self) = @_;
- # for now.
- return $self->cgi_read_query();
- }
- # =------------------------- POSSIBLE WAYS FOR MODULES TO RESPOND.
- sub respond {
- my ( $self, $data ) = @_;
- return $self->return_serialized_response($data);
- }
- sub not_found {
- my ( $self, $message ) = @_;
- $self->cgi_report_error( $message, 404 );
- }
- sub unsupported {
- my ( $self, $message ) = @_;
- $self->cgi_report_error( $message, 501 );
- }
- sub error {
- my ( $self, $message ) = @_;
- $self->cgi_report_error( $message, 500 );
- }
- 1;
|