- 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";
- 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;
|