summaryrefslogtreecommitdiff
path: root/LedgerSMB/RESTXML/Handler.pm
blob: 006c2ead3746fa1a9628d092f1894de6e27dca7c (plain)
  1. package LedgerSMB::RESTXML::Handler;
  2. use strict;
  3. use warnings;
  4. use Carp;
  5. use LedgerSMB::User;
  6. use LedgerSMB::Sysconfig;
  7. use LedgerSMB::Log;
  8. use Scalar::Util qw(blessed);
  9. use DBI;
  10. =head3 cgi_handle
  11. CGI_handle is the gateway for the RESTful lsmb API.
  12. =head3 NOTES
  13. =cut
  14. sub cgi_handle {
  15. my $self = shift;
  16. my $method = $ENV{REQUEST_METHOD};
  17. my $pathinfo = $ENV{PATH_INFO};
  18. #pull off the leading slash, we need it in the form document/arguments/foo
  19. $pathinfo =~ s#^/##;
  20. my $function = 'handle_'.lc($method);
  21. my ($user, $module, @args) = split '/',$pathinfo;
  22. $user = LedgerSMB::User->fetch_config($user);
  23. my $dbh = $self->connect_db($user);
  24. # non-word characters are forbidden, usually a sign of someone being sneaky.
  25. $module =~ s#\W##;
  26. my $document_module = $self->try_to_load($module);
  27. if($document_module) {
  28. if($document_module->can($function)) {
  29. my $returnValue = $document_module->$function({dbh=>$dbh, args=>\@args, handler=>$self, user=>$user});
  30. #return $self->return_serialized_response($returnValue);
  31. } else {
  32. return $self->unsupported("$module cannot handle method $method");
  33. }
  34. } else {
  35. return $self->not_found("Could not find a handler for document type $module: <pre>$@</pre>");
  36. }
  37. }
  38. sub cgi_report_error {
  39. my $self = shift;
  40. my $message = shift;
  41. my $code = shift||500;
  42. print "Status: $code\n";
  43. print "Content-Type: text/html\n\n";
  44. print "<html><body>\n";
  45. print "<h1>REST API error</h1>";
  46. print "<blockquote>$message</blockquote>";
  47. print "</body></html>";
  48. }
  49. sub cgi_read_query {
  50. my $self = shift;
  51. use CGI;
  52. my $cgi = CGI->new();
  53. return $cgi;
  54. }
  55. # ------------------------------------------------------------------------------------------------------------------------
  56. =head3 try_to_load
  57. try_to_load will try to load a RESTXML document handler module. returns undef
  58. if it cannot load the given module for any reason. passed the type of RESTXML
  59. document to try to load. returns a blessed anonymous hashref if the module
  60. *can*, and is successfully loaded.
  61. =cut
  62. sub try_to_load {
  63. my $self = shift;
  64. my $module = shift;
  65. eval qq{
  66. use LedgerSMB::RESTXML::Document::$module;
  67. };
  68. if($@) {
  69. warn "Cannot load $module: $@" unless $@ =~ /Can't locate LedgerSMB\//i;
  70. return undef;
  71. } else {
  72. return bless {}, "LedgerSMB::RESTXML::Document::$module";
  73. }
  74. }
  75. =head3 connect_db
  76. Given a user's config, returns a database connection handle.
  77. =cut
  78. sub connect_db {
  79. my ($self, $myconfig) = @_;
  80. my $dbh = DBI->connect(
  81. $myconfig->{dbconnect}, $myconfig->{dbuser},
  82. $myconfig->{dbpasswd})
  83. or carp "Error connecting to the db :$DBI::errstr";
  84. return $dbh;
  85. }
  86. # lets see how far XML::Simple can take us.
  87. use XML::Simple;
  88. use Scalar::Util qw(blessed);
  89. sub return_serialized_response {
  90. my ($self, $response) = @_;
  91. print "Content-type: text/xml\n\n";
  92. if(blessed $response && $response->isa('XML::Twig::Elt')) {
  93. print qq{<?xml version="1.0"?>\n};
  94. print $response->sprint();
  95. } else {
  96. my $xs = XML::Simple->new(NoAttr=>1,RootName=>'LedgerSMBResponse',XMLDecl=>1);
  97. print $xs->XMLout($response);
  98. }
  99. return;
  100. }
  101. sub read_query {
  102. my ($self) = @_;
  103. # for now.
  104. return $self->cgi_read_query();
  105. }
  106. # =------------------------- POSSIBLE WAYS FOR MODULES TO RESPOND.
  107. sub respond {
  108. my ($self, $data) = @_;
  109. return $self->return_serialized_response($data);
  110. }
  111. sub not_found {
  112. my ($self, $message) = @_;
  113. $self->cgi_report_error($message,404);
  114. }
  115. sub unsupported {
  116. my ($self, $message) = @_;
  117. $self->cgi_report_error($message, 501)
  118. }
  119. sub error {
  120. my ($self, $message) = @_;
  121. $self->cgi_report_error($message,500);
  122. }
  123. 1;