view release on metacpan or search on metacpan
0.003 2014-08-12 16:57 CEST
- bring in Resource.pm from App-Dochazka-REST and start adapting it
0.004 2014-08-13 03:37 CEST
- bin/dochazka-www: bring in server startup script from App-Dochazka-REST
and adapt to our needs
- config/WWW_Config.pm: add some config params
- WWW.pm: bring in initialization routine from App-Dochazka-REST, adapt it, and
call it from dochazka-www
- Resource.pm: eliminate large chunks of App-Dochazka-REST code that we don't
need here; add debug messages; think through how requests will be validated
by writing comments
- looking good overall -- the server starts and displays placeholder
credentials dialog
0.005 2014-08-13 08:36 CEST
- change distro sharedir from 'config/' to 'share/', move config/ into it
- make a new 'comp/' subdir under share/, for Mason components
- make a new 'auth.mc' top-level Mason component for the credentials dialog
- WWW.pm: instantiate Mason interpreter and export it as $Mason singleton;
load our distro sharedir instead of App-Dochazka-REST's; replace
server with LWP::UserAgent object in session data
- current state: login dialog displays and user can enter credentials; each
time the form is submitted, the credentials are authenticated to the REST
server and the REST server's response is displayed
0.018 2014-08-18 10:06 CEST
- fix bug "messages not getting loaded properly due to typo in name of
WWW_Message_en.conf file"
- rename 'auth.mi' to more descriptive 'login_dialog.mi'
- WWW.pm: add some POD detailing the request-response cycle
- Resource.pm: eliminate resource_exists and integrate _validate_session into
is_authorized; improve session recognition; clarify that all POST requests
are treated as form submits and handled in 'process_post', which will not
be reached if session not authorized
- dhandler.mc: clarify what dhandler.mc's job is
- 02auth.js: rename to login_dialog.js and refactor to work with new
generalized JSON structure for form submits
0.019 2014-08-18 10:43 CEST
- fix bug: "exception in Resource.pm->is_authorized"
- login_dialog.js: display reassuring message before attempting to
- 013simpleForm2.js: fix bug "form submit broken when clicking on submit
button"
0.059 2014-08-29 17:20 CEST
- Resource.pm->_login_dialog: improve error displayed on login failure
- 007directAction.js: constructor gives dA objects a default start method
if one is not provided in the argument object; add 'insertEmployee' dA
- 100login.js: refactor MFILE.loginDialogFormSubmit, improve error message
displayed on login failure
- 110empProfile.js: refactor MFILE.directAction.newEmployee.start so it
properly validates the nick before attempting the insert, which is
implemented by calling the new 'insertEmployee' dA target
0.060 2014-08-29 22:36 CEST
- implement "Masquerade as different employee" feature
- js/: add 'masqEmployee' target; rename 003targets.js to 003prototypes.js
after adding MFILE.empProfile prototype to it; minor cleanup
- 011simpleMenu2.pm: check MFILE.currentEmployee's heritage each time we enter
a menu, and fix it if necessary (it loses its heritage on each page reload,
but each page reload takes us to the main menu, where we restore the heritage)
- HTML.pm: give 'userbox' an id so we can refer to it
lib/App/MFILE/WWW.pm view on Meta::CPAN
Initialization routine - run from C<bin/mfile-www>, the server startup script.
This routine loads configuration parameters from files in the distro and site
configuration directories, and sets up logging.
FIXME: This code could be moved into the startup script.
=cut
sub init {
my %ARGS = validate( @_, {
mode => { type => SCALAR, optional => 1 }, # 'STANDALONE' or 'DDIST', defaults to 'STANDALONE'
ddist_sharedir => { type => SCALAR, optional => 1 },
sitedir => { type => SCALAR, optional => 1 },
debug_mode => { type => SCALAR, optional => 1 },
} );
# * determine mode
my $mode = $ARGS{'mode'} || 'STANDALONE';
if ( $mode =~ m/^(standalone|ddist)$/i ) {
if ( $mode =~ m/^ddist$/i ) {
lib/App/MFILE/WWW/Dispatch.pm view on Meta::CPAN
if ( ! $method or ! $path or ! $body ) {
$log->crit( 'POST request received, but missing mandatory attribute(s) - ' .
'here is the entire request body: ' . Dumper( $ajax ) );
return 0;
}
# POST is used only for login/logout ATM
if ( $method =~ m/^LOGIN/i ) {
$log->debug( "Incoming login/logout attempt" );
if ( $path =~ m/^login/i ) {
return $self->validate_user_credentials( $body );
} else {
return $self->_logout( $body );
}
}
$log->crit( "Asked to perform an AJAX call, but feature is not implemented!" );
return 0;
}
=head2 validate_user_credentials
Called from C<process_post> to process login requests (special AJAX requests)
originating from the JavaScript side (i.e. the login screen in
login-dialog.js, via login.js).
Returns a status object - OK means the login was successful; all other statuses
mean unsuccessful.
=cut
sub validate_user_credentials {
my ( $self, $body ) = @_;
$log->debug( "Entering " . __PACKAGE__ . "::validate_user_credentials()" );
my $r = $self->request;
my $session = $r->{'env'}->{'psgix.session'};
my $nick = $body->{'nam'};
my $password = $body->{'pwd'};
my $standalone = $meta->META_WWW_STANDALONE_MODE;
$log->debug( "Employee $nick login attempt" );
my ( $code, $message, $body_json );
lib/App/MFILE/WWW/Resource.pm view on Meta::CPAN
( length $uri > $site->MFILE_URI_MAX_LENGTH )
? 1
: 0;
}
=head2 is_authorized
Since all requests go through this function at a fairly early stage, we
leverage it to validate the session.
=cut
sub is_authorized {
my ( $self ) = @_;
$log->debug( "Entering " . __PACKAGE__ . "::is_authorized()" );
my $r = $self->request;
my $session = $self->session;
lib/App/MFILE/WWW/Resource.pm view on Meta::CPAN
$log->warn( "Bypassing login dialog! Using default credentials" );
#
# since the credentials are set in the configuration file, we only
# need to check them once - the result of this check is placed in
# META_LOGIN_BYPASS_STATE
#
if ( not defined $meta->META_LOGIN_BYPASS_STATE ) {
$meta->set('META_LOGIN_BYPASS_STATE', 0);
$session->{'ip_addr'} = $remote_addr;
$session->{'last_seen'} = time;
my $bypass_status = $self->validate_user_credentials( {
'nam' => $site->MFILE_WWW_DEFAULT_LOGIN_CREDENTIALS->{'nam'},
'pwd' => $site->MFILE_WWW_DEFAULT_LOGIN_CREDENTIALS->{'pwd'},
} );
if ( $bypass_status->level() eq 'OK' ) {
$meta->set('META_LOGIN_BYPASS_STATE', 1);
}
}
return $meta->META_LOGIN_BYPASS_STATE;
}
lib/App/MFILE/WWW/Resource.pm view on Meta::CPAN
=head2 _is_fresh
Takes a single argument, the PSGI session, which is assumed to contain a
C<last_seen> attribute containing the number of seconds since epoch when the
session was last seen.
=cut
sub _is_fresh {
my ( $session ) = validate_pos( @_, { type => HASHREF } );
return 0 unless my $last_seen = $session->{'last_seen'};
return ( time - $last_seen > $site->MFILE_WWW_SESSION_EXPIRATION_TIME )
? 0
: 1;
}
=head2 known_content_type
lib/App/MFILE/WWW/Resource.pm view on Meta::CPAN
$log->debug( "Entering " . __PACKAGE__ . "::main_html" );
$cepriv = '' unless defined( $cepriv );
$log->debug( "Entering " . __PACKAGE__ . "::main_html() with \$ce " .
Dumper($ce) . " and \$cepriv " . $cepriv );
my $r = '<!DOCTYPE html>';
$r .= '<html>';
$r .= '<head>';
$r .= '<meta charset="utf-8">';
# $r .= '<meta http-equiv="Cache-Control" content="no-cache, no-store, must-revalidate">';
# $r .= '<meta http-equiv="Pragma" content="no-cache">';
# $r .= '<meta http-equiv="Expires" content="0">';
$r .= "<title>App::MFILE::WWW " . $meta->META_MFILE_APPVERSION . "</title>";
$r .= '<link rel="stylesheet" type="text/css" href="/css/start.css" />';
# Bring in RequireJS with testing == 0 (false)
$r .= $self->_require_js(0, $ce, $cepriv);
$r .= '</head>';
$r .= '<body>';
lib/App/MFILE/WWW/Resource.pm view on Meta::CPAN
sub test_html {
my ( $self ) = @_;
$log->debug( "Entering " . __PACKAGE__ . "::test_html" );
my $r = '';
$r = '<!DOCTYPE html>';
$r .= '<html>';
$r .= '<head>';
$r .= '<meta charset="utf-8">';
$r .= '<meta http-equiv="Cache-Control" content="no-cache, no-store, must-revalidate">';
$r .= '<meta http-equiv="Pragma" content="no-cache">';
$r .= '<meta http-equiv="Expires" content="0">';
$r .= "<title>App::MFILE::WWW " . $meta->META_MFILE_APPVERSION . " (Unit testing)</title>";
$r .= '<link rel="stylesheet" type="text/css" href="/css/qunit.css" />';
# Bring in RequireJS with testing == 1 (true)
$r .= $self->_require_js(1);
$r .= '</head><body>';
$r .= '<div id="myLoadProgress" class="loadProgress">Loading RequireJS...</div>';
lib/App/MFILE/WWW/Resource.pm view on Meta::CPAN
$r .= '</script>';
return $r;
}
=head2 login_status
Once the username and password are known (either from C<process_post> via the
login AJAX request generated by the login dialog, or from the site
configuration via the MFILE_WWW_BYPASS_LOGIN_DIALOG mechanism), the
C<validate_user_credentials> method is called. That method is implemented by
the derived application, so it can validate user credentials however it likes.
The C<validate_user_credentials> method is then expected to call this method -
C<login_status> - to generate a status object from the results of the user
credentials validation.
Now, C<App::MFILE::WWW> does expect the C<validate_user_credentials> method to
provide the results of user credentials validation in a peculiar format,
hinging on the argument C<$code>, where a value of 200 indicates successful
validation and any other value indicates a failure.
=cut
sub login_status {
my ( $self, $code, $message, $body_json ) = @_;
my $status;
lib/App/MFILE/WWW/Resource.pm view on Meta::CPAN
body => [BODY OF HTTP RESPONSE, IF ANY]
=cut
sub rest_req {
my $self = shift;
# process arguments
my $ua = $self->ua();
die "Bad user agent object" unless ref( $ua ) eq 'LWP::UserAgent';
my %ARGS = validate( @_, {
server => { type => SCALAR, default => 'http://localhost:5000' },
method => { type => SCALAR, default => 'GET', regex => qr/^(GET|POST|PUT|DELETE)$/ },
nick => { type => SCALAR, optional => 1 },
password => { type => SCALAR, default => '' },
path => { type => SCALAR, default => '/' },
req_body => { type => HASHREF, optional => 1 },
} );
$ARGS{'path'} =~ s/^\/*/\//;
my $r;
share/js/core/qunit-2.4.0.js view on Meta::CPAN
try {
block.call(currentTest.testEnvironment);
} catch (e) {
actual = e;
}
currentTest.ignoreGlobalErrors = false;
if (actual) {
var expectedType = objectType(expected);
// We don't want to validate thrown error
if (!expected) {
result = true;
expected = null;
// Expected is a regexp
} else if (expectedType === "regexp") {
result = expected.test(errorString(actual));
// Expected is a constructor, maybe an Error constructor
} else if (expectedType === "function" && actual instanceof expected) {
share/js/core/qunit.js view on Meta::CPAN
try {
block.call(currentTest.testEnvironment);
} catch (e) {
actual = e;
}
currentTest.ignoreGlobalErrors = false;
if (actual) {
var expectedType = objectType(expected);
// We don't want to validate thrown error
if (!expected) {
result = true;
expected = null;
// Expected is a regexp
} else if (expectedType === "regexp") {
result = expected.test(errorString(actual));
// Expected is a constructor, maybe an Error constructor
} else if (expectedType === "function" && actual instanceof expected) {