From 10cf213ffa75b12e2a493266204b0c4f6fd7f2f8 Mon Sep 17 00:00:00 2001 From: Xavier Guimard Date: Fri, 25 Dec 2015 10:46:04 +0000 Subject: [PATCH] POD documentation --- .../lib/Lemonldap/NG/Common/PSGI.pm | 223 ++++++++++++++++++ .../lib/Lemonldap/NG/Common/PSGI/Request.pm | 190 +++++++++++++++ .../lib/Lemonldap/NG/Common/PSGI/Router.pm | 207 ++++++++++++++++ 3 files changed, 620 insertions(+) diff --git a/lemonldap-ng-common/lib/Lemonldap/NG/Common/PSGI.pm b/lemonldap-ng-common/lib/Lemonldap/NG/Common/PSGI.pm index 42d866bd6..238706915 100644 --- a/lemonldap-ng-common/lib/Lemonldap/NG/Common/PSGI.pm +++ b/lemonldap-ng-common/lib/Lemonldap/NG/Common/PSGI.pm @@ -210,3 +210,226 @@ sub _run { } 1; +__END__ + +=head1 NAME + +=encoding utf8 + +Lemonldap::NG::Common::PSGI - Base library for PSGI modules of Lemonldap::NG. +Use Lemonldap::NG::Common::PSGI::Router for REST API. + +=head1 SYNOPSIS + + package My::PSGI; + + use base Lemonldap::NG::Common::PSGI; + + sub init { + my ($self,$args) = splice @_; + # Will be called 1 time during startup + + # Store debug level + $self->logLevel('info'); + # Can use syslog for user actions + $self->syslog('daemon'); + + # Return a boolean. If false, then error message has to be stored in + # $self->error + return 1; + } + + sub router { + my ( $self, $req ) = splice @_; + # Do something and return a PSGI response + # NB: $req is a Lemonldap::NG::Common::PSGI::Request object + + return [ 200, [ 'Content-Type' => 'text/plain' ], [ 'Body lines' ] ]; + } + +This package could then be called as a CGI, using FastCGI,... + + #!/usr/bin/env perl + + use My::PSGI; + use Plack::Handler::FCGI; # or Plack::Handler::CGI + + Plack::Handler::FCGI->new->run( My::PSGI->run() ); + +=head1 DESCRIPTION + +This package provides base class for Lemonldap::NG web interfaces but could be +used regardless. + +=head1 METHODS + +=head2 Running methods + +=head3 run ( $args ) + +Main method that will manage requests. It can be called using class or already +created object: + +=over + +=item Class->run($args): launch new($args), init(), then manage requests (using +private _run() method + +=item $object->run(): manage directly requests. Initialization must have be done +earlier. + +=back + +=head2 Logging + +=head3 lmLog ( $msg, $level) + +Print on STDERR messages if level > $self->{logLevel}. Defined log levels are: +debug, info, notice, warn, error. + +=head3 userLog ($msg, $level) + +If $self->syslog is configured, store message with it, else called simply lmLog(). +$self->syslog must be empty or contain syslog facility + +=head3 userError() userNotice() userInfo() + +Alias for userLog(level). + +=head2 Content sending + +Note that $req, the first argument of these functions, is a +L. See the corresponding documentation. + +=head3 sendHtml ( $req, $template ) + +This method build HTML response using HTML::Template and the template $template. +$template file must be in $self->templateDir directory. +HTML template will receive 5 variables: + +=over + +=item SCRIPT_NAME: the path to the (F)CGI + +=item STATIC_PREFIX: content of $self->staticPrefix + +=item AVAILABLE_LANGUAGES: content of $self->languages + +=item LINKS: JSON stringification of $self->links + +=item VERSION: Lemonldap::NG version + +=back + +The response is always send with a 200 code. + +=head3 sendJSONresponse ( $req, $json, %args ) + +Stringify $json object and send it to the client. $req is the +Lemonldap::NG::Common::PSGI::Request object; %args can define the HTTP error +code (200 by default). + +If client is not json compatible (`Accept` header), response is send in XML. + +Examples: + + $self->sendJSONresponse ( $req, { result => 0 }, code => 400 ); + + $self->sendJSONresponse ( $req, { result => 1 } ); + +=head3 sendError ( $req, $msg, $code ) + +Call sendJSONresponse with `{ error => $msg }` and code (default to 500) and +call lmLog() to duplicate error in logs + +=head3 abort ( $msg ) + +When an error is detected during startup (init() sub), you must not call +sendError() but call abort(). Each request received later will receive the +error (abort uses sendError() behind the scene). + +=head2 Accessors + +=head3 error + +String error. Used if init() fails or if sendError is called without argument. + +=head3 languages + +String containing list of languages (ie "fr, en'). Used by sendHtml(). + +=head3 logLevel + +See lmLog(). + +=head3 staticPrefix + +String indicating the path of static content (js, css,...). Used by sendHtml(). + +=head3 templateDir + +Directory containing template files. + +=head3 links + +Array of links to display by sendHtml(). Each element has the form: + + { target => 'http://target', title => 'string to display' } + +=head3 syslog + +Syslog facility. If empty, STDERR will be used for logging + +=head1 SEE ALSO + +L, L, L, +L, L, L, +L, L, +L, + +=head1 AUTHORS + +=over + +=item Clement Oudot, Eclem.oudot@gmail.comE + +=item François-Xavier Deltombe, Efxdeltombe@gmail.com.E + +=item Xavier Guimard, Ex.guimard@free.frE + +=item Thomas Chemineau, Ethomas.chemineau@gmail.comE + +=back + +=head1 BUG REPORT + +Use OW2 system to report bug or ask for features: +L + +=head1 DOWNLOAD + +Lemonldap::NG is available at +L + +=head1 COPYRIGHT AND LICENSE + +=over + +=item Copyright (C) 2015 by Xavier Guimard, Ex.guimard@free.frE + +=back + +This library 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, 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, see L. + +=cut diff --git a/lemonldap-ng-common/lib/Lemonldap/NG/Common/PSGI/Request.pm b/lemonldap-ng-common/lib/Lemonldap/NG/Common/PSGI/Request.pm index fbe09041f..495162728 100644 --- a/lemonldap-ng-common/lib/Lemonldap/NG/Common/PSGI/Request.pm +++ b/lemonldap-ng-common/lib/Lemonldap/NG/Common/PSGI/Request.pm @@ -139,3 +139,193 @@ sub jsonBodyToObj { } 1; +__END__ + +=head1 NAME + +=encoding utf8 + +Lemonldap::NG::Common::PSGI::Request - HTTP request object for Lemonldap::NG +PSGIs + +=head1 SYNOPSIS + + package My::PSGI; + + use base Lemonldap::NG::Common::PSGI; + + # See Lemonldap::NG::Common::PSGI + ... + + sub router { + my ( $self, $req ) = splice @_; + # Do something and return a PSGI response + # NB: $req is a Lemonldap::NG::Common::PSGI::Request object + if ( $req->accept eq 'text/plain' ) { ... } + + return [ 200, [ 'Content-Type' => 'text/plain' ], [ 'Body lines' ] ]; + } + +=head1 DESCRIPTION + +This package provides HTTP request objects used by Lemonldap::NG PSGIs. It +contains common accessors to work with request + +=head1 METHODS + +=head2 Accessors + +=head3 accept + +'Accept' header content. + +=head3 encodings + +'Accept-Encoding' header content. + +=head3 languages + +'Accept-Language header content. + +=head3 cookies + +'Cookie' header content. + +=head3 hostname + +'Host' header content. + +=head3 remote_ip + +Client IP address. + +=head3 port + +Client TCP port. + +=head3 method + +HTTP method asked by client (GET/POST/PUT/DELETE). + +=head3 scriptname + +SCRIPT_NAME environment variable provided by HTTP server. + +=head3 get_server_port + +Server port. + +=head3 path + +PATH_INFO content which has been substracted `scriptname`. So it's the relative +path_info for REST calls. + +=head3 uri + +REQUEST_URI environment variable. + +=head3 unparsed_uri + +Same as `uri` but without decoding. + +=head3 user + +REMOTE_USER environment variable. It contains username when a server authentication +is done. + +=head3 userData + +Hash reference to be used by Lemonldap::NG::Handler::PSGI. If a server authentication +is done, it contains: + + { _whatToTrace => `user()` } + +=head3 params + +GET parameters. + +=head3 body + +Content of POST requests + +=head3 error + +Set if an error occurs + +=head3 contentType + +Content type of posted datas. + +=head3 contentLength + +Length of posted datas. + +=head2 Private accessors + +=head3 _psgixBuffered + +PSGI psgix.input.buffered variable. + +=head3 _psgiInput + +PSGI psgix.input variable. + +=head2 Methods + +=head3 jsonBodyToObj() + +Get the content of a JSON POST request as Perl object. + +=head1 SEE ALSO + +L, L, L, +L, L, L, +L, L, +L, + +=head1 AUTHORS + +=over + +=item Clement Oudot, Eclem.oudot@gmail.comE + +=item François-Xavier Deltombe, Efxdeltombe@gmail.com.E + +=item Xavier Guimard, Ex.guimard@free.frE + +=item Thomas Chemineau, Ethomas.chemineau@gmail.comE + +=back + +=head1 BUG REPORT + +Use OW2 system to report bug or ask for features: +L + +=head1 DOWNLOAD + +Lemonldap::NG is available at +L + +=head1 COPYRIGHT AND LICENSE + +=over + +=item Copyright (C) 2015 by Xavier Guimard, Ex.guimard@free.frE + +=back + +This library 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, 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, see L. + +=cut diff --git a/lemonldap-ng-common/lib/Lemonldap/NG/Common/PSGI/Router.pm b/lemonldap-ng-common/lib/Lemonldap/NG/Common/PSGI/Router.pm index 2385c37ea..5d14cc6f9 100644 --- a/lemonldap-ng-common/lib/Lemonldap/NG/Common/PSGI/Router.pm +++ b/lemonldap-ng-common/lib/Lemonldap/NG/Common/PSGI/Router.pm @@ -150,3 +150,210 @@ sub followPath { } 1; +__END__ + +=head1 NAME + +=encoding utf8 + +Lemonldap::NG::Common::PSGI::Router - Base library for REST APIs of Lemonldap::NG. + +=head1 SYNOPSIS + + package My::PSGI; + + use base Lemonldap::NG::Common::PSGI::Router; + + sub init { + my ($self,$args) = splice @_; + # Will be called 1 time during startup + + # Declare REST routes (could be HTML templates or methods) + $self->addRoute ( 'index.html', undef, ['GET'] ) + ->addRoute ( books => { ':book' => 'booksMethod' }, ['GET', 'POST'] ) + ->addRoute ( properties => { '*' => 'propertiesMethod' }, ['GET', 'POST', 'PUT', 'DELETE']); + + # Default route (ie: PATH_INFO == '/') + $self->defaultRoute('index.html'); + + # See Lemonldap::NG::Common::PSGI for other options + + # Return a boolean. If false, then error message has to be stored in + # $self->error + return 1; + } + + sub booksMethod { + my ( $self, $req, @otherPathInfo ) = splice @_; + my $book = $req->params('book'); + my $method = $req->method; + ... + $self->sendJSONresponse(...); + } + + sub propertiesMethod { + my ( $self, $property, @otherPathInfo ) = splice @_; + my $method = $req->method; + ... + $self->sendJSONresponse(...); + } + +This package could then be called as a CGI, using FastCGI,... + + #!/usr/bin/env perl + + use My::PSGI; + use Plack::Handler::FCGI; # or Plack::Handler::CGI + + Plack::Handler::FCGI->new->run( My::PSGI->run() ); + +=head1 DESCRIPTION + +This package provides base class for Lemonldap::NG REST API but could be +used regardless. + +=head1 METHODS + +See L for logging methods, content sending,... + +=head2 Initialization methods + +=head3 addRoute ( $word, $dest, $methods ) + +Declare a REST route. Arguments: + +=over + +=item $word: the first word of /path/info. + +=item $dest: string, sub ref or hash ref (see "Route types" bellow) + +=item $methods: array ref containing the methods concerned by this route. + +=back + +=head4 Route types + +As seen in "SYNOPSIS", you can declare routes with variable component. $dest +can be: + +=over + +=item a word: the name of the method to call + +=item undef: $word is used as $dest + +=item a ref to code: an anonymous subroutin to call + +=item a hash ref: it's a recursive call to `{ $word => $dest }` + +=item an array ref: in this case each element of the array will be considered as +`{ $element => $element }`. So each element must be a word that makes a +correspondance between a path_info word and a subroutine + +=back + +Some special $word: + +=over + +=item ':name': the word in path_info will be stored in GET parameters + +=item '*': the subroutine will be called with the word of path_info as second argument +(after $req) + +=item 'something.html': if $word finishes with '.html', then sendHtml() will be called +with 'something.tpl' as template name. In this case, $dest is not used. + +=back + +Examples: + +=over + +=item to manage http://.../books/127 with book() where 127 is the book number, use: + + $self->addRoute( books => { ':bookId' => 'book' }, ['GET'] ); + +booId parameter will be stored in $req->params('bookId'); + +=item to manage http://.../books/127/pages/5 with page(), use: + + $self->addRoute( books => { ':bookId' => { pages => { ':pageId' => 'page' } } }, ['GET'] ); + +=item to manage simultaneously the 2 previous examples + + $self->addRoute( books => { ':bookId' => { pages => { ':pageId' => 'page' } } }, ['GET'] ) + ->addRoute( books => { ':bookId' => { '*' => 'book' } }, ['GET'] ); + +Note that book() will be called for any path_info containing /books/<$bookid>/<$other> +except if $other == 'pages'. + +=item to manage /properties/p1, /properties/p2 with p1() and p2(), use: + + $self->addRoute( properties => [ 'p1', 'p2' ] ); + +=back + +=head3 defaultRoute($path) + +This method defined which path_info to use if path_info is '/' or empty. + +=head3 Accessors + +See L for inherited accessors (error, languages, +logLevel, staticPrefix, templateDir, links, syslog). + +=head1 SEE ALSO + +L, L, L, +L, L, L, +L, L, +L, + +=head1 AUTHORS + +=over + +=item Clement Oudot, Eclem.oudot@gmail.comE + +=item François-Xavier Deltombe, Efxdeltombe@gmail.com.E + +=item Xavier Guimard, Ex.guimard@free.frE + +=item Thomas Chemineau, Ethomas.chemineau@gmail.comE + +=back + +=head1 BUG REPORT + +Use OW2 system to report bug or ask for features: +L + +=head1 DOWNLOAD + +Lemonldap::NG is available at +L + +=head1 COPYRIGHT AND LICENSE + +=over + +=item Copyright (C) 2015 by Xavier Guimard, Ex.guimard@free.frE + +=back + +This library 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, 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, see L. + +=cut