view release on metacpan or search on metacpan
0.140 2014-08-05 12:39 CEST
- REST.pm: work on POD
- Dispatch.pm: fix bug in 'echo' POST resource (wasn't handling empty
requests)
- Resource.pm: implement 'known_content_type' and 'malformed_request'
routines - requests with body containing anything other than legal JSON will
be rejected
0.141 2014-08-05 15:52 CEST
- implement basic handling of PUT requests
0.142 2014-08-05 21:46 CEST
- implement 'employee' and 'employee/:nick' (INSERT/UPDATE) PUT resources
(ATM without unit tests)
- Model/Employee.pm: fix bug "'update' routine doesn't work at all"
- Resource.pm: in 'malformed_request', push JSON from request body onto
context _after_ decoding it into a Perl hashref
- minor cleanup/fixup
0.143 2014-08-06 10:19 CEST
- working on employee PUT resources: refactor targets, add 'eid' resources
- Model/Shared.pm: make 'cud' return RETURNING values in payload
- Model/Employee.pm: make 'insert' and 'update' return payload received from
'cud'
0.144 2014-08-06 13:55 CEST
- Model/Employee.pm: fix bug "'update' returns OK status when called with
undefined EID -- should be ERR"
- config/: rename SQL_EMPLOYEE_UPDATE to SQL_EMPLOYEE_UPDATE_BY_EID to
emphasize that EID is required
- t/317-dispatch-put-employee.t: add lots of unit tests
0.145 2014-08-06 15:08 CEST
- Dispatch/Employee.pm: GET resource 'employee/nick/:nick' now returns
only a single employee record unless nick parameter contains a '%',
in which case it returns a result set (JSON array of employee records)
- t/: adapt tests
0.146 2014-08-07 09:42 CEST
- config/dispatch/: improve resource descriptions by including method
- REST.pm: write some POD about POST and PUT
- staging/: get rid of old ballast, add some new ballast (CLI scripts)
- minor cleanup
0.147 2014-08-07 11:05 CEST
- t/317-dispatch-put-employee.t: fix 'keys on reference' oversight
that caused build to fail with Perl 5.20
- staging/cli.plx: work on CLI script
- split off "pure" data model functions into App::Dochazka so they can
be shared with App::Dochazka::CLI
- try to fix UTF-8 bug, but only make it worse
0.175 2014-09-25 09:29 CEST
- Resource.pm: encode response body in UTF-8 before sending it out on the line
0.176 2014-10-14 17:31 CEST
- Dispatch/: add some comments
- Resource.pm: add debug message; add allow_nonref; find bug #57
0.177 2014-10-15 10:33 CEST
- start revamping path dispatch code in light of bug #57 (PUT request to
non-existent resource returns HTTP code 200 and null entity body)
- realize that it makes no sense to return 404 on a PUT request, since the
whole idea of PUT is to create a new resource
- the principal change is in Resource.pm->allowed_methods:
- the definition of each resource (in config/dispatch) should contain list of allowed methods
- when path is recognized, return the allowed methods from the resource definition
- when the path is not recognized _AND_ the method is PUT, return 405 Method Not Allowed
0.178 2014-10-15 16:41 CEST
- the design change in 0.177 caused a lot of breakage: put the pieces back together (WIP)
0.179 2014-10-15 22:54 CEST
- Build.PL: require App::CELL 0.197 (for 'get_param')
- continue fixing brokenness following the design change in 0.177
0.180 2014-10-16 08:40 CEST
- massage Changes file
- config/dispatch: make 'help' resources for all four HTTP methods we support
(GET, POST, PUT, DELETE)
- t/: fix or disable all broken tests - test suite running clean again, but
many tests are missing
0.181 2014-10-16 10:35 CEST
- make 'employee/nick' and 'employee/eid' be POST requests (instead of PUT) -
we will reserve PUT for unique resources like 'employee/nick/joedavis'
0.182 2014-10-16 10:56 CEST
- Dispatch.pm: add POD for "" and "help" resources
0.183 2014-10-16 11:12 CEST
- LDAP.pm: use EXPORT_OK instead of EXPORT
- Resource.pm: import routines from LDAP.pm explicitly
0.184 2014-10-16 12:59 CEST
- Resource.pm: implement basic handling of DELETE requests
0.188 2014-10-16 22:46 CEST
- t/: add a bunch of tests; refine siteparam and metaparam tests; find
App::CELL bug ($meta can be used to access site parameters)
0.189 2014-10-17 11:10 CEST
- Resource.pm: provide hash to keys, instead of hash reference
0.190 2014-10-17 17:48 CEST
- Build.PL: require latest App::CELL to avoid bug
- implement 'bugreport' resource
- implement PUT method for 'metaparam/:param' resource
- Dispatch.pm: add POD for more resources
- t/310-dispatch-top-get.t: add test case for 'bugreport' resource
- t/312-dispatch-top-put.t: add test case "set meta parameter via REST
call"
0.191 2014-10-20 16:53 CEST
- Hackweek Day 1
- Build.PL: depend on latest version of App::Dochazka
- config/dispatch/dispatch_Employee_Config.pm: use refactored employee
targets
- config/sql/employee_Config.pm: do not include 'priv' and 'schedule' in
employee objects
- Dispatch/Employee.pm: refactor employee PUT and POST targets
- Model/Employee.pm: add 'overlay' method
- Resource.pm: instead of having 'priv' property directly in the current
employee hash, we make a separate 'current_priv' property for it;
push the HTTP method onto the context hash ASAP (in service_available)
- t/316-dispatch-employee-post.t: add some "real" tests involving inserting
and update employee objects
- t/317-dispatch-employee-put.t: fix broken tests
0.192 2014-10-20 22:15 CEST
- dispatch/dispatch_Employee_Config.pm: resources into alphabetical order; add
0.195 2014-10-21 10:51 CEST
- Model/Employee.pm->noof_employees_by_priv: if $priv is not a valid
privlevel, return 'OK' status + status code DISPATCH_NO_RECORDS_FOUND
to trigger a 404 Not Found response; also, put 'count' property in the
payload where it belongs
- t/315-dispatch-employee-get.t: adapt existing test case
0.196 2014-10-21 11:38 CEST
- config/dispatch_Top_Config.pm: make "echo" work with POST only; put
resources in alphabetical order
- t/: remove 'echo' tests from top-level PUT and DELETE units
0.197 2014-10-21 11:47 CEST
- work on development-checklist
- t/: standardize method order (GET, PUT, POST, DELETE); adapt units
0.198 2014-10-21 12:10 CEST
- Dispatch.pm: document all target subroutines; put into alphabetical order
by resource name/path
0.199 2014-10-21 16:31 CEST
- Hackweek Day 2
- dispatch_Message_en.conf: add DISPATCH_RESOURCE_NOT_IMPLEMENTED
- dispatch_Top_Config.pm: implement 'not_implemented' resource
- Dispatch.pm: implement 'not_implemented' resource, alphabetical order
resource-implementation workflow
0.200 2014-10-21 22:29 CEST
- ../development-checklist: finish implementing top-level resources
- Dispatch.pm: when getting site and meta params, show file and line
number along with other metadata; tweak resource documentation
- t/: some tests failing due to bug in App::CELL::Config->get_param_meta
0.201 2014-10-22 08:30 CEST
- Build.PL: require App::CELL 0.200 for bug fix
- t/: adjust two tests now that PUT metaparam/:param and PUT siteparam/:param
are assigning the request body to the parameter directly
0.202 2014-10-22 16:47 CEST
- Hackweek Day 3
- lots of refinements to (plus documentation and test cases for) employee
resources
- implement DELETE support for employee resources
- eliminate problematic "short-cut" 'employee/:nick' and 'employee/:eid'
resources
- make it possible to update an employee property to null
0.210 2014-10-24 15:33 CEST
- Hackweek Day 5
- implement privhistory resources using new development workflow
- merge 'privhistory/current' and 'privhistory/current/:tsrange' into a
single resource 'privhistory/current/?:tsrange'
- dispatch/dispatch_Privhistory_Config.pm: put resources in alphabetical
order; document resources; add more supported methods
- t/dispatch/privhistory: add privhistory tests in new structure
- Dispatch/Privhistory.pm: put targets in order according to their
corresponding resources; rename _get_nick and _get_eid to _nick and _eid,
respectively, and expand them to support PUT and DELETE
- Model/Privhistory.pm: add some debug messages
0.211 2014-10-24 22:40 CEST
- Hackweek Day 5, continued
- config/sql/dbinit_Config.pm: add UNIQUE (eid, effective) constraint to
privhistory table to avoid duplicate entries in a given employee's
privhistory listing
- dispatch_Message_en.conf: add DISPATCH_PRIVHISTORY_COULD_NOT_SPAWN
- Dispatch/Privhistory.pm: implement support for PUT and DELETE requests in
_eid and _nick targets
- Model/Employee.pm: fix bug "get 500 Server Error when I send a request for
bogus resource 'privhistory/eid/asdf'"
- t/dispatch/privhistory/: add quite a few tests
0.212 2014-10-25 23:23 CEST
- update MANIFEST to current state
- change 'privhistory' to 'priv'
- add new 'priv/current/?:ts' resource
- t/: start adapting tests
- dispatch/activity_Config.pm: add 'activity/aid/:aid' resource definition
- t/dispatch/activity.t: add initial tests for 'activity/aid/:aid'
0.226 2014-10-29 10:34 CET
- Build.PL: require 0.172 of App::Dochazka (for 'disabled' field)
- config/sql/activity_Config.pm: make SELECTs return disabled field
- t/dispatch/activity.t: add some tests for 'activity/aid/:aid' resource (GET)
- Dispatch/Activity.pm: implement 'activity/aid/:aid' resource for GET requests
0.227 2014-10-29 13:54 CET
- Dispatch/{Employee,Activity}.pm: fix bug where PUT request with request body
consisting of just a number or just a string (e.g. '9', or '"asdf"') was
causing the server to vomit 500
- activity_Config.pm: support PUT and DELETE requests for 'activity/aid/:aid';
add resource definition for 'activity/code/:code'
- dispatch_Message_en.conf: add DISPATCH_CODE_DOES_NOT_EXIST
- Dispatch/Activity.pm: support PUT and DELETE requests for 'activity/aid/:aid';
add support for 'activity/code/:code'
- Model/Activity.pm: fix 'update' routine to support the new 'disabled' field
- Model/Shared.pm: make a note in 'cud' routine that order of attrs must match
the '?' characters in the SQL statement
- Test.pm: add 'create_testing_activity' and 'delete_testing_activity'
- t/dispatch/activity.t: add a bunch of tests
0.228 2014-10-29 16:43 CET
- Dispatch/Activity.pm: trying to get _insert_activity to deal gracefully with
bogus JSON
- t/dispatch/employee.t: label some tests; add tests for some edge cases
- t/dispatch/activity.t: add tests for some edge cases
0.232 2014-10-30 22:07 CET
- activity_Config.pm: activate 'activity/code' dispatch target
- Dispatch/Activity.pm: adapt '_code' dispatch target to handle POST
- t/dispatch/activity.t: add tests
0.233 2014-10-31 13:30 CET
- realize that there are resources where the GET method needs ACL profile of,
e.g., "active" but the remaining methods (PUT, POST, DELETE) need to be
available only to administrators
- Resource.pm: modify 'forbidden' method to handle resources with ACL profiles
defined for each HTTP method separately
- config/dispatch/activity_Config.pm: define per-method ACL profiles where needed
- Model/Privhistory.pm: improve documentation of 'get_privhistory' routine
- Test.pm: add 'req_active', 'req_json_active', 'create_active_employee', and
'delete_active_employee' routines
- t/dispatch/activity.t: adapt tests to use the new routines in Test.pm and to
test the per-method ACL profile definitions
0.279 2014-11-14 10:39 CET
- Dispatch/Employee.pm: add _post_current (dispatch target for POST
'employee/{current, self}'
- t/dispatch/employee.t: ACL checks are not working for resources with
fine-grained ACL profile definition: add a test case for this
0.280 2014-11-14 11:29 CET
- employee_Config.pm: fix 'employee/self' acl_profile property
- Dispatch/Employee.pm: request body needs to be a hashref - check for that
where we really care about it - in _put_post_delete_employee_by_eid
- Dispatch/Shared.pm: pre_update_comparison was causing DOCHAZKA_BAD_INPUT to
be returned if no fields would actually change on update, but this might be
confusing - change it to allow updates in such cases
- t/dispatch/employee.t: add test cases for POST employee/{current,self} by
inactive and active employees; adapt tests to current state
0.281 2014-11-14 16:42 CET
- finish implementation (including test cases) of POST dispatch
target for 'employee/{current,self}' resource
0.282 2014-11-14 21:36 CET
0.285 2014-11-18 11:53 CET
- dbinit_Config.pm, t/sql/immutable_id.t: finish making '*id' fields immutable
0.286 2014-11-18 12:49 CET
- dispatch_Config.pm, interval_Config.pm: add basic set of 'intervals'
resources
0.287 2014-11-18 15:33 CET
- config/dispatch/HTTP_Message_en.conf: make a separate message file for codes
that map directly to an HTTP error code
- config/, lib/: transform DOCHAZKA_BAD_INPUT and DOCHAZKA_INSUFFICENT_PRIV into
special status codes that map directly to HTTP error codes
- Resource.pm: when target returns certain status codes (see package variable
%status_http_map), translate them directly into HTTP error codes
- t/: adapt to current state
0.288 2014-11-19 10:05 CET
- Dispatch/Lock.pm: lay groundwork for locks
- t/dispatch/interval.t: new tests
- interval_Config.pm, dispatch_Message_en.conf: minor fixes
- Dispatch/Interval.pm: add special ACL handling
0.315 2014-11-28 16:23 CET
- got Path::Router validations to work!!!
- config/dispatch/activity_Config.pm: added validations clauses
- config/dispatch/employee_Config.pm: added validations clauses
- config/dispatch_Message_en.conf: delete DISPATCH_AID_DOES_NOT_EXIST and
DISPATCH_CODE_DOES_NOT_EXIST
- dbinit_Config.pm: change 'kosher_code' constraint on 'activities' table to
match the validations clause
- Dispatch/Activity.pm: noticed that we were still returning custom codes (e.g.
DISPATCH_AID_DOES_NOT_EXIST) instead of a simple 404 (405 on PUT) -- fixed
- t/dispatch/activity.t: fix tests broken by the above changes
0.316 2014-11-28 16:48 CET
- dispatch/employee_Config.pm: add validations clause to the
'employee/count/:priv' resource definition
- Dispatch/Employee.pm: handle upper/mixed case priv strings gracefully
- Model/Employee.pm: noof_employees_by_priv was written long ago - update it to
use best practices
- t/dispatch/employee.t: add 'employee/count/:priv' test cases
but is not compatible with Web::MREST
0.379 2015-02-10 17:29 CET
- massive reorganization: move handler routines to Dispatch.pm
0.380 2015-02-10 18:27 CET
- Dispatch.pm: merge 'current' into 'handler_get_privsched'; fix _update_schedule
- t/dispatch/schedule.t: migrate unit tests - unit runs cleanly again
0.381 2015-02-11 10:42 CET
- work on employee handlers (PUT employee/eid/:eid and PUT employee/nick/:nick)
with two-pass additional ACL check for updates; insert is working, too
- TODO: migrate rest of employee resources and t/dispatch/employee.t
0.382 2015-02-11 14:41 CET
- ResourceDefs.pm: new module; move all migrated resource defs into it;
add missing acl_profile properties to top-level resource defs;
- Test.pm: include location header in return status (a-la Web::MREST)
- t/dispatch/top.t: migrate unit
0.383 2015-02-11 16:43 CET
- LDAP.pm: make ldap_search() look up a property; implement populate_employee()
- Dispatch.pm: add handler_get_employee_ldap() for GET employee/nick/:nick/ldap
- Auth.pm: populate certain employee attributes from LDAP upon successful LDAP autocreate
- REST_Config.pm: default value for DOCHAZKA_LDAP_POPULATE_MATRIX
- Build.PL: require App::Dochazka::Common 0.191 for "set()" method
- Dispatch.pm: increase granularity of employee/.../minimal ACL check
- No longer auto-generate Makefile.PL
0.471 2015-07-23 16:55 CEST
- t/201-LDAP.t: add simple test cases for GET employee/nick/:nick/ldap
- ResourceDefs.pm: enable PUT on employee/nick/:nick/ldap
- LDAP.pm: fix populate_employee() so it returns not_ok if nick is not in LDAP
- Dispatch.pm: implement handler_get_employee_ldap and handler_put_employee_ldap
- Auth.pm: fix DOCHAZKA_LDAP_AUTOCREATE_AS code path
0.472 2015-07-24 17:06 CEST
- doc: config/REST_Config.pm: tell users to not add a nick property to
DOCHAZKA_LDAP_POPULATE_MATRIX
- t/: test POST employee/nick without required nick property
- Dispatch.pm: return 400 if POST employee/nick without nick property
(fixes github issue #2)
bin/dochazka-ldap-sync-all view on Meta::CPAN
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
# *************************************************************************
#
# dochazka-ldap-sync-all
#
# Does the equivalent of "PUT employee/nick/:nick/ldap" on all employees whose
# sync property is true.
#
#!perl
use 5.012;
use strict;
use warnings;
#use App::CELL qw( $CELL $site $log );
use App::Dochazka::REST qw( init_arbitrary_script $faux_context );
lib/App/Dochazka/REST/Dispatch.pm view on Meta::CPAN
# first pass
if ( $pass == 1 ) {
$bool = $param_obj->exists( $param );
$bool = $bool ? 1 : 0;
$self->context->{'stash'}->{'param_value'} = $param_obj->get( $param ) if $bool;
return $bool;
}
# second pass
if ( $type ne 'meta' and $method =~ m/^(PUT)|(DELETE)$/ ) {
$self->mrest_declare_status( code => 400, explanation =>
'PUT and DELETE can be used with meta parameters only' );
return $fail;
}
if ( $method eq 'GET' ) {
return $CELL->status_ok( 'MREST_PARAMETER_VALUE', payload => {
$param => $self->context->{'stash'}->{'param_value'},
} );
} elsif ( $method eq 'PUT' ) {
$log->debug( "Request entity: " . Dumper( $self->context->{'request_entity'} ) );
return $param_obj->set( $param, $self->context->{'request_entity'} );
} elsif ( $method eq 'DELETE' ) {
delete $param_obj->{$param};
return $CELL->status_ok( 'MREST_PARAMETER_DELETED', payload => {
'type' => $type,
'param' => $param,
} );
}
}
lib/App/Dochazka/REST/Dispatch.pm view on Meta::CPAN
return 0 unless $act;
$context->{'stashed_activity_object'} = $act;
return 1;
}
# second pass
if ( $context->{'method'} eq 'GET' ) {
return $CELL->status_ok( 'DISPATCH_ACTIVITY_FOUND',
payload => $context->{'stashed_activity_object'}
);
} elsif ( $context->{'method'} eq 'PUT' ) {
return shared_update_activity(
$self,
$context->{'stashed_activity_object'},
$context->{'request_entity'}
);
} elsif ( $context->{'method'} eq 'DELETE' ) {
return $context->{'stashed_activity_object'}->delete( $context );
}
return $CELL->status_crit("Aaaaaaaaaaahhh! Swallowed by the abyss" );
}
lib/App/Dochazka/REST/Dispatch.pm view on Meta::CPAN
return 1;
}
# second pass
return $context->{'stashed_activity_object'}->delete( $context );
}
=head3 handler_put_activity_code
Handler for the 'PUT activity/code/:code' resource.
=cut
sub handler_put_activity_code {
my ( $self, $pass ) = @_;
$log->debug( "Entering " . __PACKAGE__ . "::handler_put_activity_code" );
my $context = $self->context;
# first pass
lib/App/Dochazka/REST/Dispatch.pm view on Meta::CPAN
return 0 unless $comp;
$context->{'stashed_component_object'} = $comp;
return 1;
}
# second pass
if ( $context->{'method'} eq 'GET' ) {
return $CELL->status_ok( 'DISPATCH_COMPONENT_FOUND',
payload => $context->{'stashed_component_object'}
);
} elsif ( $context->{'method'} eq 'PUT' ) {
return shared_update_component(
$self,
$context->{'stashed_component_object'},
$context->{'request_entity'}
);
} elsif ( $context->{'method'} eq 'DELETE' ) {
return $context->{'stashed_component_object'}->delete( $context );
}
return $CELL->status_crit("Aaaabllaaaaaaahhh Component! Swallowed by the abyss" );
}
lib/App/Dochazka/REST/Dispatch.pm view on Meta::CPAN
return shared_get_employee_pass1( $self, $pass, 'nick', $self->context->{'mapping'}->{'nick'} );
}
# second pass
return $self->_handler_get_employee_full_pass2();
}
=head3 handler_put_employee_eid
Handler for 'PUT employee/eid/:eid' - can only be update.
=cut
sub handler_put_employee_eid {
my ( $self, $pass ) = @_;
$log->debug( "Entering " . __PACKAGE__ . "::handler_put_employee_eid" );
my $context = $self->context;
# first pass
lib/App/Dochazka/REST/Dispatch.pm view on Meta::CPAN
return shared_update_employee(
$self,
$emp,
$context->{'request_entity'}
);
}
=head3 handler_put_employee_nick
Handler for 'PUT employee/nick/:nick' - a little complicated because it can
be insert or update, depending on whether or not the employee exists.
=cut
sub handler_put_employee_nick {
my ( $self, $pass ) = @_;
$log->debug( "Entering " . __PACKAGE__ . "::handler_put_employee_nick" );
my $context = $self->context;
lib/App/Dochazka/REST/Dispatch.pm view on Meta::CPAN
$context->{'put_employee_func'} = 'insert_employee';
}
return 0 unless shared_employee_acl_part1( $self, $emp ); # additional ACL checks
$context->{'stashed_employee_object'} = $emp;
$self->nullify_declared_status;
return 1;
}
# second pass
my $func = $context->{'put_employee_func'};
$log->debug( "PUT employee function is $func - " );
if ( $func eq 'update_employee' ) {
return $fail unless shared_employee_acl_part2( $self );
} elsif ( $func eq 'insert_employee' ) {
$context->{'request_entity'}->{'nick'} = $context->{'mapping'}->{'nick'};
} else {
die "AAAAAAAAAAAAGAGGGGGGGGAAAHAHAAHHHH!";
}
return $iue_dispatch{$func}->(
$self,
$context->{'stashed_employee_object'},
lib/App/Dochazka/REST/Dispatch.pm view on Meta::CPAN
);
return $self->_ldap_sync_pass1( $emp );
}
return $CELL->status_ok( 'DOCHAZKA_LDAP_LOOKUP', payload => $context->{'stashed_employee_object'} );
}
=head3 handler_put_employee_ldap
Handler for 'PUT employee/nick/:nick/ldap' resource.
=cut
sub handler_put_employee_ldap {
my ( $self, $pass ) = @_;
$log->debug( "Entering " . __PACKAGE__ . "::handler_put_employee_ldap" );
my $context = $self->context;
$log->debug( "mapping " . Dumper( $context->{'mapping'} ) );
my $nick = $context->{'mapping'}->{'nick'};
lib/App/Dochazka/REST/Dispatch.pm view on Meta::CPAN
return 0;
}
$context->{'stashed_interval_object'} = $int;
return 1;
}
# second pass
my $int = $context->{'stashed_interval_object'};
my $method = $context->{'method'};
if ( $method =~ m/^(PUT)|(POST)$/ ) {
return shared_update_intlock( $self, $int, $context->{'request_entity'} );
} elsif ( $method eq 'DELETE' ) {
return $int->delete( $context );
}
die "AAGAGAGGGGGGGGGGHHGHGHKD! method is " . ( $method || "undef" );
}
=head3 handler_get_interval_summary
lib/App/Dochazka/REST/Dispatch.pm view on Meta::CPAN
return 0;
}
$context->{'stashed_lock_object'} = $lock;
return 1;
}
# second pass
my $lock = $context->{'stashed_lock_object'};
my $method = $context->{'method'};
if ( $method =~ m/^(PUT)|(POST)$/ ) {
return shared_update_intlock( $self, $lock, $context->{'request_entity'} );
} elsif ( $method eq 'DELETE' ) {
return $lock->delete( $context );
}
die "AAGAGAGGGGGGGGGGHHGHGHKD! method is " . ( $method || "undef" );
}
=head2 Priv handlers
lib/App/Dochazka/REST/Dispatch.pm view on Meta::CPAN
# second pass
return $CELL->status_ok(
'DISPATCH_SCHEDULE_FOUND',
payload => $self->context->{'stashed_schedule_object'},
);
}
=head3 handler_put_schedule_sid
Handler for 'PUT schedule/sid/:sid'
=cut
sub handler_put_schedule_sid {
my ( $self, $pass ) = @_;
$log->debug( "Entering " . __PACKAGE__ . ":handler_put_schedule_sid" );
my $context = $self->context;
my $sid = $context->{'mapping'}->{'sid'};
lib/App/Dochazka/REST/Dispatch.pm view on Meta::CPAN
# second pass
return $CELL->status_ok(
'DISPATCH_SCHEDULE_FOUND',
payload => $self->context->{'stashed_schedule_object'},
);
}
=head3 handler_put_schedule_scode
Handler for 'PUT schedule/scode/:scode'
=cut
sub handler_put_schedule_scode {
my ( $self, $pass ) = @_;
$log->debug( "Entering " . __PACKAGE__ . ":handler_put_schedule_scode" );
my $context = $self->context;
my $scode = $context->{'mapping'}->{'scode'};
lib/App/Dochazka/REST/Docs/Resources.pm view on Meta::CPAN
=head1 RESOURCES
=head2 C<< / >>
=over
Allowed methods: CONNECT, DELETE, GET, OPTIONS, POST, PUT, TRACE
This resource is the parent of all resources that do not specify
a parent in their resource definition.
=back
=head2 C<< activity >>
=over
Allowed methods: CONNECT, DELETE, GET, OPTIONS, POST, PUT, TRACE
Parent for activity resources
=back
=head2 C<< activity/aid >>
=over
lib/App/Dochazka/REST/Docs/Resources.pm view on Meta::CPAN
updated.
=back
=head2 C<< activity/aid/:aid >>
=over
Allowed methods: DELETE, GET, PUT
This resource allows the user to GET, PUT, or DELETE an activity object by its
AID.
=over
=item * GET
Retrieves an activity object by its AID.
=item * PUT
Updates the activity object whose AID is specified by the ':aid' URI parameter.
The fields to be updated and their new values should be sent in the request
body, e.g., like this:
{ "long_desc" : "new description", "disabled" : "f" }
=item * DELETE
Deletes the activity object whose AID is specified by the ':aid' URI parameter.
lib/App/Dochazka/REST/Docs/Resources.pm view on Meta::CPAN
updated.
=back
=head2 C<< activity/code/:code >>
=over
Allowed methods: DELETE, GET, PUT
With this resource, a user can GET, PUT, or DELETE an activity object by its
code.
=over
=item * GET
Retrieves an activity object by its code.
=item * PUT
Inserts new or updates existing activity object whose code is specified by the
':code' URI parameter. The fields to be updated and their new values should be
sent in the request body, e.g., like this:
{ "long_desc" : "new description", "disabled" : "f" }
=item * DELETE
Deletes an activity object by its code whose code is specified by the ':code'
lib/App/Dochazka/REST/Docs/Resources.pm view on Meta::CPAN
Returns a JSON structure containing instructions for reporting bugs.
=back
=head2 C<< component >>
=over
Allowed methods: CONNECT, DELETE, GET, OPTIONS, POST, PUT, TRACE
Parent for component resources
=back
=head2 C<< component/all >>
=over
lib/App/Dochazka/REST/Docs/Resources.pm view on Meta::CPAN
updated.
=back
=head2 C<< component/cid/:cid >>
=over
Allowed methods: DELETE, GET, PUT
This resource allows the user to GET, PUT, or DELETE an component object by its
cid.
=over
=item * GET
Retrieves an component object by its cid.
=item * PUT
Updates the component object whose cid is specified by the ':cid' URI parameter.
The fields to be updated and their new values should be sent in the request
body, e.g., like this:
{ "path" : "new/path", "source" : "new source", "acl" : "inactive" }
=item * DELETE
Deletes the component object whose cid is specified by the ':cid' URI parameter.
lib/App/Dochazka/REST/Docs/Resources.pm view on Meta::CPAN
if this, too, fails will "DOWN" be returned.
=back
=head2 C<< docu >>
=over
Allowed methods: CONNECT, DELETE, GET, OPTIONS, POST, PUT, TRACE
This resource provides access to on-line documentation through its
subresources: 'docu/pod', 'docu/html', and 'docu/text'.
To get documentation on a resource, send a POST reqeuest for one of
these subresources, including the resource name in the request
entity as a bare JSON string (i.e. in double quotes).
=back
lib/App/Dochazka/REST/Docs/Resources.pm view on Meta::CPAN
back in the response body.
=back
=head2 C<< employee >>
=over
Allowed methods: CONNECT, DELETE, GET, OPTIONS, POST, PUT, TRACE
Parent for employee resources
=back
=head2 C<< employee/count/?:priv >>
=over
lib/App/Dochazka/REST/Docs/Resources.pm view on Meta::CPAN
site to site (see the DOCHAZKA_PROFILE_EDITABLE_FIELDS site parameter).
=back
=head2 C<< employee/eid/:eid >>
=over
Allowed methods: DELETE, GET, PUT
With this resource, we can look up an employee by exact match (GET),
update an existing employee (PUT), or delete an employee (DELETE).
=over
=item * GET
Retrieves an employee object by its EID.
=item * PUT
Updates the "employee profile" (employee object) of the employee with
the given EID. For example, if the request body was:
{ "fullname" : "Foo Bariful" }
the request would change the 'fullname' property of the employee with EID 43
(provided such an employee exists) to "Foo Bariful". Any 'eid' property
provided in the content body will be ignored.
lib/App/Dochazka/REST/Docs/Resources.pm view on Meta::CPAN
site to site (see the DOCHAZKA_PROFILE_EDITABLE_FIELDS site parameter).
=back
=head2 C<< employee/nick/:nick >>
=over
Allowed methods: DELETE, GET, PUT
Retrieves (GET), updates/inserts (PUT), and/or deletes (DELETE) the employee
specified by the ':nick' parameter.
=over
=item * GET
Retrieves employee object(s) by exact match. For example:
GET employee/nick/foobar
would look for an employee whose nick is 'foobar'.
=item * PUT
Inserts a new employee or updates an existing one (exact match only).
If a 'nick' property is provided in the content body and its value is
different from the nick provided in the URI, the employee's nick will be
changed to the value provided in the content body.
ACL note: 'inactive' and 'active' employees can use this resource to modify
their own employee profile. Exactly which fields can be updated may differ from
site to site (see the DOCHAZKA_PROFILE_EDITABLE_FIELDS site parameter).
lib/App/Dochazka/REST/Docs/Resources.pm view on Meta::CPAN
=back
=back
=head2 C<< employee/nick/:nick/ldap >>
=over
Allowed methods: GET, PUT
This resource enables any employee to perform an LDAP lookup on
any other employee.
=back
=head2 C<< employee/nick/:nick/minimal >>
lib/App/Dochazka/REST/Docs/Resources.pm view on Meta::CPAN
of an arbitrary employee - i.e. that employee\'s direct reports.
=back
=head2 C<< employee/search >>
=over
Allowed methods: CONNECT, DELETE, GET, OPTIONS, POST, PUT, TRACE
See child resources.
=back
=head2 C<< employee/search/nick/:key >>
=over
lib/App/Dochazka/REST/Docs/Resources.pm view on Meta::CPAN
employees in their team - i.e. their direct reports.
=back
=head2 C<< forbidden >>
=over
Allowed methods: CONNECT, DELETE, GET, OPTIONS, POST, PUT, TRACE
This resource returns 403 Forbidden for all allowed methods, regardless of user.
Implementation note: this can be accomplished for any resource by including an 'acl_profile'
property with the value 'undef' or any unrecognized privilege level string (like "foobar").
=back
=head2 C<< genreport >>
lib/App/Dochazka/REST/Docs/Resources.pm view on Meta::CPAN
fall within that tsrange.
=back
=head2 C<< interval >>
=over
Allowed methods: CONNECT, DELETE, GET, OPTIONS, POST, PUT, TRACE
Parent for interval resources
=back
=head2 C<< interval/:self/:ts/:psqlint >>
=over
lib/App/Dochazka/REST/Docs/Resources.pm view on Meta::CPAN
updated.
=back
=head2 C<< interval/iid/:iid >>
=over
Allowed methods: DELETE, GET, PUT
This resource makes it possible to GET, PUT, or DELETE an interval object by
its IID.
=over
=item * GET
Retrieves an interval object by its IID.
=item * PUT
Updates the interval object whose iid is specified by the ':iid' URI parameter.
The fields to be updated and their new values should be sent in the request
body, e.g., like this:
{
"eid" : 34,
"aid" : 1,
"intvl" : '[ 2014-11-18 08:00, 2014-11-18 12:00 )'
}
lib/App/Dochazka/REST/Docs/Resources.pm view on Meta::CPAN
Parent for interval fillup resources
=back
=head2 C<< lock >>
=over
Allowed methods: CONNECT, DELETE, GET, OPTIONS, POST, PUT, TRACE
Parent for lock resources
=back
=head2 C<< lock/eid/:eid/:tsrange >>
=over
lib/App/Dochazka/REST/Docs/Resources.pm view on Meta::CPAN
updated.
=back
=head2 C<< lock/lid/:lid >>
=over
Allowed methods: DELETE, GET, PUT
This resource makes it possible to GET, PUT, or DELETE an lock object by its
LID.
=over
=item * GET
Retrieves an lock object by its lid.
=item * PUT
Updates the lock object whose lid is specified by the ':lid' URI parameter.
The fields to be updated and their new values should be sent in the request
body, e.g., like this:
{
"eid" : 34,
"intvl" : '[ 2014-11-18 00:00, 2014-11-18 24:00 )'
}
lib/App/Dochazka/REST/Docs/Resources.pm view on Meta::CPAN
be fetched, the return status will be C<DISPATCH_TOO_MANY_RECORDS_FOUND>.
=back
=head2 C<< noop >>
=over
Allowed methods: CONNECT, DELETE, GET, OPTIONS, POST, PUT, TRACE
Regardless of anything, this resource does nothing at all.
=back
=head2 C<< param/:type/:param >>
=over
Allowed methods: DELETE, GET, PUT
This resource can be used to look up (GET) meta, core, and site parameters,
as well as to set (PUT) and delete (DELETE) meta parameters.
=back
=head2 C<< priv >>
=over
Allowed methods: CONNECT, DELETE, GET, OPTIONS, POST, PUT, TRACE
This resource presents a list of subresources, all related to employee privileges.
=back
=head2 C<< priv/eid/:eid/?:ts >>
=over
lib/App/Dochazka/REST/Docs/Resources.pm view on Meta::CPAN
is present, the privlevel as of that timestamp is retrieved.
=back
=head2 C<< priv/history >>
=over
Allowed methods: CONNECT, DELETE, GET, OPTIONS, POST, PUT, TRACE
This resource presents a list of subresources, all related to privilege histories.
=back
=head2 C<< priv/history/eid/:eid >>
=over
lib/App/Dochazka/REST/Docs/Resources.pm view on Meta::CPAN
=back
=head2 C<< priv/history/nick/:nick >>
=over
Allowed methods: GET, POST
Retrieves entire history of privilege level changes for employee with the given
nick (GET); or, with an appropriate content body, adds (PUT) a record to
employee\'s privhistory.
=over
=item * GET
Retrieves the "privhistory", or history of changes in
privilege level, of the employee with the given nick.
=item * POST
lib/App/Dochazka/REST/Docs/Resources.pm view on Meta::CPAN
is present, the privlevel as of that timestamp is retrieved.
=back
=head2 C<< schedule >>
=over
Allowed methods: CONNECT, DELETE, GET, OPTIONS, POST, PUT, TRACE
This resource presents a list of "child" resources (subresources), all of which
are related to schedules.
=back
=head2 C<< schedule/all >>
lib/App/Dochazka/REST/Docs/Resources.pm view on Meta::CPAN
is present, the schedule as of that timestamp is retrieved.
=back
=head2 C<< schedule/history >>
=over
Allowed methods: CONNECT, DELETE, GET, OPTIONS, POST, PUT, TRACE
This resource presents a list of subresources, all related to schedule histories.
=back
=head2 C<< schedule/history/eid/:eid >>
=over
lib/App/Dochazka/REST/Docs/Resources.pm view on Meta::CPAN
=back
=head2 C<< schedule/history/nick/:nick >>
=over
Allowed methods: GET, POST
Retrieves entire history of schedule changes for employee with the given nick
(GET); or, with an appropriate content body, adds (PUT) a record to employee\'s
schedule history.
=over
=item * GET
Retrieves the full history of schedule changes of the employee with the given nick.
For partial histories, see 'schedule/history/nick/:nick/:tsrange'.
=item * POST
lib/App/Dochazka/REST/Docs/Resources.pm view on Meta::CPAN
is present, the schedule as of that timestamp is retrieved.
=back
=head2 C<< schedule/scode/:scode >>
=over
Allowed methods: DELETE, GET, PUT
This resource makes it possible to GET, PUT, or DELETE a schedule by its scode.
=over
=item * GET
An integer scode must be given as an URI parameter. If a schedule
with this scode is found, it is returned in the payload.
=item * PUT
This resource/method provides a way to set (modify) the 'scode', 'remark'
and/or 'disabled' fields of a schedule record. Simply provide the property (or
properties) and the new value(s) in the request body, e.g.:
{ "scode" : "WIGWAM" }
or
{ "remark" : "foobar", "disabled" : "t" }
lib/App/Dochazka/REST/Docs/Resources.pm view on Meta::CPAN
is present, the schedule as of that timestamp is retrieved.
=back
=head2 C<< schedule/sid/:sid >>
=over
Allowed methods: DELETE, GET, PUT
This resource makes it possible to GET, PUT, or DELETE a schedule by its SID.
=over
=item * GET
An integer SID must be given as an URI parameter. If a schedule
with this SID is found, it is returned in the payload.
=item * PUT
This resource/method provides a way to set (modify) the 'scode', 'remark'
and/or 'disabled' fields of a schedule record. Simply provide the property (or
properties) and the new value(s) in the request body, e.g.:
{ "scode" : "WIGWAM" }
or
{ "remark" : "foobar", "disabled" : "t" }
lib/App/Dochazka/REST/Docs/Workflow.pm view on Meta::CPAN
If LDAP authentication is enabled and C<DOCHAZKA_LDAP_AUTOCREATE> is set, a new
passerby employee will be created whenever an as-yet unseen employee logs in
(authenticates herself to the REST server). Otherwise, a passerby employee can
log in only if an administrator has created the corresponding employee profile.
=head3 Explore available resources
Any logged-in employee is free to explore available resources. The starting
point for such exploration can be C<GET /> (i.e. a GET request for the
top-level resource), which is the same as C<GET /help>. The information
returned is specific to the HTTP method used, so for PUT resources one needs to
use C<PUT /> (or C<PUT /help>), etc.
Only accessible resources are displayed. For example, a passerby employee will
not see admin resources. A few resources (e.g. C<activity/aid/:aid>), have
different ACL profiles depending on which HTTP method is used.
=head3 Retrieve one's own employee profile
Using C<GET employee/self>, any employee can view her own employee profile.
The payload is a valid employee object.
lib/App/Dochazka/REST/Guide.pm view on Meta::CPAN
Dochazka consists of three main components:
=over
=item * REST server (this module)
The REST server listens for and processes incoming HTTP requests. Processing includes
authentication and authorization. The server attempts to map the request URI to a
Dochazka resource. The resource handler takes action on the request, depending on the
HTTP method (GET, PUT, POST, DELETE). Typically, this action will culminate in
one or more SQL statements which are sent to the PostgreSQL database for
execution. The results are sent back to the client in the HTTP reponse.
=item * PostgreSQL database
The PostgreSQL database is configured to listen for incoming SQL statements
from the REST server. Based on these statements, it creates, retrieves,
updates, and deletes (CRUD) employee attendance records and related data in the
Dochazka database.
lib/App/Dochazka/REST/Guide.pm view on Meta::CPAN
To start exploring, fire up a standard web browser and point it to the base URI
of your L<App::Dochazka::REST> installation:
http://dochazka.site
and entering one's credentials in the Basic Authentication dialog.
=head2 With a command-line HTTP client
To access all the resources, you will need a client that is capable of
generating POST, PUT, and DELETE requests as well as GET requests. Also, since
some of the information L<App::Dochazka::REST> provides is in the response
headers, the client needs to be capable of displaying those as well.
One such client is Daniel Stenberg's B<curl>.
In the HTTP request, the client may provide an C<Accept:> header specifying
either HTML (C<text/html>) or JSON (C<application/json>). For the convenience
of those using a web browser, HTML is the default.
Here are some examples of how to use B<curl> (or a web browser) to explore
lib/App/Dochazka/REST/Guide.pm view on Meta::CPAN
see all the available resources, we can authenticate as 'root':
$ curl http://root:immutable@dochazka.site/employee -H 'Accept: application/json'
=item * POST resources
With the GET method, we could only access resources for finding and displaying
information: we could not add, change, or delete information. For that we will
need to turn to some other client than the web browser -- a client like B<curl>
that is capable of generating HTTP requests with methods like POST (as well as
PUT and DELETE).
Here is an example of how we would use B<curl> to display the top-level POST
resources:
curl -v http://root:immutable@dochazka.site -X POST -H "Content-Type: application/json"
The "Content-Type: application/json" header is necessary because the server
only accepts JSON in the POST request body -- even though in this case we
did not send a request body, most POST requests will have one. For best
results, the request body should be a legal JSON string represented as a
sequence of bytes encoded in UTF-8.
=item * PUT resources
The PUT method is used to add new resources and update existing ones. Since
the resources are derived from the underlying database, this implies executing
INSERT and UPDATE statements on tables in the database.
PUT resources can be explored using a B<curl> command analogous to the one
given for the POST method.
=item * DELETE resources
Any time we need to delete information -- i.e., completely wipe it from
the database, we will need to use the DELETE method.
DELETE resources can be explored using a B<curl> command analogous to the one
given for the POST method.
lib/App/Dochazka/REST/Guide.pm view on Meta::CPAN
After the request is authenticated (associated with a known employee), the
server examines the ACL profile of the resource being requested and compares it
with the employee's privilege level. If the privilege level is too low for the
requested operation, a "403 Forbidden" response is sent.
The ACL profile is part of the resource definition. It can be specified either
as a single value for all HTTP methods, or as a hash, e.g.:
{
GET => 'passerby',
PUT => 'admin',
DELETE => 'admin',
}
In certain operations (i.e., combinations of HTTP method and resource), the
full range of functionality may be available only to administrators. See These
operations are special cases. Their ACL profile is either 'inactive' or
'active', but a non-administrator employee may still get a 403 Forbidden error
on the operation if they are trying to do something, such as update an interval
belonging to a different employee, that is reserved for administrators.
=item * B<Test for resource existence>
The next test a request undergoes on its quest to become a response is the
test of resource existence. If the request is asking for a non-existent resource,
e.g. L<http://dochazka.site/employee/curent>, it cannot be fulfilled and a "404
Not Found" response will be sent.
For GET requests, this is ordinarily the last cog in the state machine: if the
test passes, a "200 OK" response is typically sent, along with a response body.
(There are exceptions to this rule, however - see L<the AUTHORIZATION
chapter|"AUTHORIZATION">.) Requests using other methods (POST, PUT, DELETE) are
subject to further processing as described below.
=back
=head2 Additional processing (POST and PUT)
Because they are expected to have a request body, incoming POST and PUT
requests are subject to the following additional test:
=over
=item * B<malformed_request>
This test examines the request body. If it is non-existent, the test
passes. If the body exists and is valid JSON, the test passes. Otherwise,
it fails.
=item * B<known_content_type>
Test the request for the 'Content-Type' header. POST and PUT requests
should have a header that says:
Content-Type: application/json
If this header is not present, a "415 Unsupported Media Type" response is
sent.
=back
=head2 Additional processing (POST)
lib/App/Dochazka/REST/Guide.pm view on Meta::CPAN
=head2 HTTP request
An HTTP request has the following basic components:
=over
=item * Method
Dochazka supports GET, PUT, POST, and DELETE
=item * URI
Universal Resource Indicator specifying a Dochazka resource
=item * Headers
More on these below
=item * Request entity
Data accompanying the request - may or may not be present
=back
=head3 Method
The Dochazka REST server accepts the following HTTP methods:
C<GET>, C<PUT>, C<POST>, and C<DELETE>.
=over
=item C<GET>
A C<GET> request on a resource is a request for information - in other words,
it is "read-only": C<GET> requests never change the underlying data. In
Dochazka, C<GET> requests frequently map to C<SELECT> statements.
=item C<PUT>
C<PUT> requests always refer to a concrete data entity, or chunk of data.
In simple cases, this will be a single record in the underlying database. If
the record already exists, the C<PUT> request is interpreted to mean
modification (or C<UPDATE> in SQL). If the record does not exist, then the
request will map to an C<INSERT> statement to create the resource. In both
cases, upon success the response status will be C<200 OK>.
=item C<POST>
Sometimes, especially for create operations, the exact specification of the
resource is not known beforehand. To address these cases, some resources accept
C<POST> requests. If the request causes a new resource to be created, the HTTP
response status will be C<201 Created> and there will be a C<Location> header
lib/App/Dochazka/REST/Guide.pm view on Meta::CPAN
=head3 Headers
HTTP headers are somewhat obscure because they are often hidden by the
client. Nevertheless, they are an important part of the HTTP protocol. The
Dochazka REST server only accepts certain headers in the request.
#FIXME: describe the more common response headers
=head3 Body
C<PUT> and C<POST> requests may take a request body. If a request body is
expected or accepted, it must be a valid JSON string. (JSON is a simple way of
"stringifying" a data structure.)
=head2 HTTP response
The HTTP response returned by the REST server consists of:
=over
=item * Status code (e.g. 200, 400, 404, etc.)
lib/App/Dochazka/REST/Holiday.pm view on Meta::CPAN
my ( %ARGS ) = validate( @_, {
begin => { type => SCALAR },
end => { type => SCALAR },
} );
my $begin_year = _extract_year( $ARGS{begin} );
my $end_year = _extract_year( $ARGS{end} );
# transform daterange into an array of hashes containing "begin", "end"
# in other words:
# INPUT: { begin => '1901-06-30', end => '1903-03-15' }
# becomes
# OUTPUT: [
# { begin => '1901-06-30', end => '1901-12-31' },
# { begin => '1902-01-01', end => '1902-12-31' },
# { begin => '1903-01-01', end => '1903-03-15' },
# ]
my $daterange_by_year = _daterange_by_year(
begin_year => $begin_year,
end_year => $end_year,
begin_date => $ARGS{begin},
end_date => $ARGS{end},
);
lib/App/Dochazka/REST/ResourceDefs.pm view on Meta::CPAN
Regardless of anything, this resource does nothing at all.
EOH
},
# param/:type/:param
'param/:type/:param' =>
{
parent => '/',
handler => {
'GET' => 'handler_param',
'PUT' => 'handler_param',
'DELETE' => 'handler_param',
},
acl_profile => 'admin',
cli => {
'GET' => 'param $TYPE $PARAM',
'PUT' => 'param $TYPE $PARAM $VALUE',
'DELETE' => 'param $TYPE $PARAM',
},
description => {
'GET' => 'Display value of a meta/core/site parameter',
'PUT' => 'Set value of a parameter (meta only)',
'DELETE' => 'Delete a parameter (meta only)',
},
documentation => <<'EOH',
=pod
This resource can be used to look up (GET) meta, core, and site parameters,
as well as to set (PUT) and delete (DELETE) meta parameters.
EOH
validations => {
'type' => qr/^(meta)|(core)|(site)$/,
'param' => qr/^[[:alnum:]_][[:alnum:]_-]+$/,
},
},
# session
'session' =>
{
lib/App/Dochazka/REST/ResourceDefs.pm view on Meta::CPAN
updated.
EOH
},
# /activity/aid/:aid
'activity/aid/:aid' =>
{
parent => 'activity',
handler => {
GET => 'handler_activity_aid',
PUT => 'handler_activity_aid',
DELETE => 'handler_activity_aid',
},
acl_profile => {
GET => 'active',
PUT => 'admin',
DELETE => 'admin',
},
cli => 'activity aid $AID',
validations => {
'aid' => 'Int',
},
description => 'GET, PUT, or DELETE an activity object by its AID',
documentation => <<'EOH',
=pod
This resource allows the user to GET, PUT, or DELETE an activity object by its
AID.
=over
=item * GET
Retrieves an activity object by its AID.
=item * PUT
Updates the activity object whose AID is specified by the ':aid' URI parameter.
The fields to be updated and their new values should be sent in the request
body, e.g., like this:
{ "long_desc" : "new description", "disabled" : "f" }
=item * DELETE
Deletes the activity object whose AID is specified by the ':aid' URI parameter.
lib/App/Dochazka/REST/ResourceDefs.pm view on Meta::CPAN
updated.
EOH
},
# /activity/code/:code
'activity/code/:code' =>
{
parent => 'activity',
handler => {
GET => 'handler_get_activity_code',
PUT => 'handler_put_activity_code',
DELETE => 'handler_delete_activity_code',
},
acl_profile => {
GET => 'passerby',
PUT => 'admin',
DELETE => 'admin',
},
cli => 'activity code $CODE',
validations => {
'code' => qr/^[[:alnum:]_][[:alnum:]_-]+$/,
},
description => 'GET, PUT, or DELETE an activity object by its code',
documentation => <<'EOH',
=pod
With this resource, a user can GET, PUT, or DELETE an activity object by its
code.
=over
=item * GET
Retrieves an activity object by its code.
=item * PUT
Inserts new or updates existing activity object whose code is specified by the
':code' URI parameter. The fields to be updated and their new values should be
sent in the request body, e.g., like this:
{ "long_desc" : "new description", "disabled" : "f" }
=item * DELETE
Deletes an activity object by its code whose code is specified by the ':code'
lib/App/Dochazka/REST/ResourceDefs.pm view on Meta::CPAN
updated.
EOH
},
# /component/cid/:cid
'component/cid/:cid' =>
{
parent => 'component',
handler => {
GET => 'handler_component_cid',
PUT => 'handler_component_cid',
DELETE => 'handler_component_cid',
},
acl_profile => 'admin',
cli => 'component cid $cid',
validations => {
'cid' => 'Int',
},
description => 'GET, PUT, or DELETE an component object by its cid',
documentation => <<'EOH',
=pod
This resource allows the user to GET, PUT, or DELETE an component object by its
cid.
=over
=item * GET
Retrieves an component object by its cid.
=item * PUT
Updates the component object whose cid is specified by the ':cid' URI parameter.
The fields to be updated and their new values should be sent in the request
body, e.g., like this:
{ "path" : "new/path", "source" : "new source", "acl" : "inactive" }
=item * DELETE
Deletes the component object whose cid is specified by the ':cid' URI parameter.
lib/App/Dochazka/REST/ResourceDefs.pm view on Meta::CPAN
site to site (see the DOCHAZKA_PROFILE_EDITABLE_FIELDS site parameter).
EOH
},
# /employee/eid/:eid
'employee/eid/:eid' =>
{
parent => 'employee',
handler => {
GET => 'handler_get_employee_eid',
PUT => 'handler_put_employee_eid',
DELETE => 'handler_delete_employee_eid',
},
acl_profile => {
GET => 'passerby',
PUT => 'inactive',
DELETE => 'admin',
},
cli => 'employee eid $EID [$JSON]',
validations => {
eid => 'Int',
},
description => 'GET: look up employee (exact match); PUT: update existing employee; DELETE: delete employee',
documentation => <<'EOH',
=pod
With this resource, we can look up an employee by exact match (GET),
update an existing employee (PUT), or delete an employee (DELETE).
=over
=item * GET
Retrieves an employee object by its EID.
=item * PUT
Updates the "employee profile" (employee object) of the employee with
the given EID. For example, if the request body was:
{ "fullname" : "Foo Bariful" }
the request would change the 'fullname' property of the employee with EID 43
(provided such an employee exists) to "Foo Bariful". Any 'eid' property
provided in the content body will be ignored.
lib/App/Dochazka/REST/ResourceDefs.pm view on Meta::CPAN
site to site (see the DOCHAZKA_PROFILE_EDITABLE_FIELDS site parameter).
EOH
},
# /employee/nick/:nick
'employee/nick/:nick' =>
{
parent => 'employee',
handler => {
GET => 'handler_get_employee_nick',
PUT => 'handler_put_employee_nick',
DELETE => 'handler_delete_employee_nick',
},
acl_profile => {
GET => 'passerby',
PUT => 'inactive',
DELETE => 'admin',
},
cli => 'employee nick $NICK [$JSON]',
validations => {
'nick' => $term_validation,
},
description => "Retrieves (GET), updates/inserts (PUT), and/or deletes (DELETE) the employee specified by the ':nick' parameter",
documentation => <<'EOH',
=pod
Retrieves (GET), updates/inserts (PUT), and/or deletes (DELETE) the employee
specified by the ':nick' parameter.
=over
=item * GET
Retrieves employee object(s) by exact match. For example:
GET employee/nick/foobar
would look for an employee whose nick is 'foobar'.
=item * PUT
Inserts a new employee or updates an existing one (exact match only).
If a 'nick' property is provided in the content body and its value is
different from the nick provided in the URI, the employee's nick will be
changed to the value provided in the content body.
ACL note: 'inactive' and 'active' employees can use this resource to modify
their own employee profile. Exactly which fields can be updated may differ from
site to site (see the DOCHAZKA_PROFILE_EDITABLE_FIELDS site parameter).
lib/App/Dochazka/REST/ResourceDefs.pm view on Meta::CPAN
=back
EOH
},
# /employee/nick/:nick/ldap
'employee/nick/:nick/ldap' =>
{
parent => 'employee/nick/:nick',
handler => {
GET => 'handler_get_employee_ldap',
PUT => 'handler_put_employee_ldap',
},
acl_profile => {
GET => 'passerby',
PUT => 'active',
},
cli => 'employee nick $nick ldap',
validations => {
nick => $term_validation,
},
description => 'List LDAP info on an employee',
documentation => <<'EOH',
=pod
LDAP search and sync resource
=over
=item * GET
Enables any employee to perform an LDAP lookup on any other employee.
=item * PUT
Enables active employees to sync their own employee profile fields[1] from the
site's LDAP database.
Enables admin employees to sync/create[1] any existing employee from the LDAP
database. If the employee does not exist, it will be created (just the employee
object itself, without any privhistory records).
=back
lib/App/Dochazka/REST/ResourceDefs.pm view on Meta::CPAN
POST => 'handler_history_post',
},
acl_profile => {
GET => 'inactive',
POST => 'admin',
},
cli => 'priv history nick $NICK [$JSON]',
validations => {
'nick' => $term_validation,
},
description => 'Retrieves entire history of privilege level changes for employee with the given nick (GET); or, with an appropriate content body, adds (PUT) a record to employee\'s privhistory',
documentation => <<'EOH',
=pod
Retrieves entire history of privilege level changes for employee with the given
nick (GET); or, with an appropriate content body, adds (PUT) a record to
employee\'s privhistory.
=over
=item * GET
Retrieves the "privhistory", or history of changes in
privilege level, of the employee with the given nick.
=item * POST
lib/App/Dochazka/REST/ResourceDefs.pm view on Meta::CPAN
POST => 'handler_history_post',
},
acl_profile => {
GET => 'inactive',
POST => 'admin',
},
cli => 'schedule history nick $NICK [$JSON]',
validations => {
'nick' => $term_validation,
},
description => 'Retrieves entire history of schedule changes for employee with the given nick (GET); or, with an appropriate content body, adds (PUT) a record to employee\'s schedule history',
documentation => <<'EOH',
=pod
Retrieves entire history of schedule changes for employee with the given nick
(GET); or, with an appropriate content body, adds (PUT) a record to employee\'s
schedule history.
=over
=item * GET
Retrieves the full history of schedule changes of the employee with the given nick.
For partial histories, see 'schedule/history/nick/:nick/:tsrange'.
=item * POST
lib/App/Dochazka/REST/ResourceDefs.pm view on Meta::CPAN
updated.
EOH
},
# /interval/iid/:iid
'interval/iid/:iid' =>
{
parent => 'interval',
handler => {
GET => 'handler_get_interval_iid',
PUT => 'handler_interval_iid',
DELETE => 'handler_interval_iid',
},
acl_profile => {
GET => 'inactive',
PUT => 'active',
DELETE => 'active',
},
cli => 'interval iid $iid [$JSON]',
validations => {
'iid' => 'Int',
},
description => 'GET, PUT, or DELETE an interval object by its iid',
documentation => <<'EOH',
=pod
This resource makes it possible to GET, PUT, or DELETE an interval object by
its IID.
=over
=item * GET
Retrieves an interval object by its IID.
=item * PUT
Updates the interval object whose iid is specified by the ':iid' URI parameter.
The fields to be updated and their new values should be sent in the request
body, e.g., like this:
{
"eid" : 34,
"aid" : 1,
"intvl" : '[ 2014-11-18 08:00, 2014-11-18 12:00 )'
}
lib/App/Dochazka/REST/ResourceDefs.pm view on Meta::CPAN
updated.
EOH
},
# /lock/lid/:lid
'lock/lid/:lid' =>
{
parent => 'lock',
handler => {
GET => 'handler_get_lock_lid',
PUT => 'handler_lock_lid',
DELETE => 'handler_lock_lid',
},
acl_profile => {
GET => 'active',
PUT => 'admin',
DELETE => 'admin',
},
cli => 'lock lid $lid [$JSON]',
validations => {
'lid' => 'Int',
},
description => 'GET, PUT, or DELETE an lock object by its LID',
documentation => <<'EOH',
=pod
This resource makes it possible to GET, PUT, or DELETE an lock object by its
LID.
=over
=item * GET
Retrieves an lock object by its lid.
=item * PUT
Updates the lock object whose lid is specified by the ':lid' URI parameter.
The fields to be updated and their new values should be sent in the request
body, e.g., like this:
{
"eid" : 34,
"intvl" : '[ 2014-11-18 00:00, 2014-11-18 24:00 )'
}
lib/App/Dochazka/REST/ResourceDefs.pm view on Meta::CPAN
is present, the schedule as of that timestamp is retrieved.
EOH
},
# /schedule/scode/:scode
'schedule/scode/:scode' =>
{
parent => 'schedule',
handler => {
GET => 'handler_get_schedule_scode',
PUT => 'handler_put_schedule_scode',
DELETE => 'handler_delete_schedule_scode',
},
acl_profile => {
GET => 'inactive',
PUT => 'admin',
DELETE => 'admin',
},
cli => 'schedule scode $scode',
validations => {
'scode' => qr/^[[:alnum:]_][[:alnum:]_-]*$/,
},
description => 'Retrieves, updates, or deletes a schedule by its scode',
documentation => <<'EOH',
=pod
This resource makes it possible to GET, PUT, or DELETE a schedule by its scode.
=over
=item * GET
An scode (string) must be given as a URI parameter. If a schedule with this
scode is found (exact, case-sensitive match), it is returned in the payload.
=item * PUT
This resource/method provides a way to set (modify) the 'scode', 'remark'
and/or 'disabled' fields of a schedule record. Simply provide the property (or
properties) and the new value(s) in the request body, e.g.:
{ "scode" : "WIGWAM" }
or
{ "remark" : "foobar", "disabled" : "t" }
lib/App/Dochazka/REST/ResourceDefs.pm view on Meta::CPAN
is present, the schedule as of that timestamp is retrieved.
EOH
},
# /schedule/sid/:sid
'schedule/sid/:sid' =>
{
parent => 'schedule',
handler => {
GET => 'handler_get_schedule_sid',
PUT => 'handler_put_schedule_sid',
DELETE => 'handler_delete_schedule_sid',
},
acl_profile => {
GET => 'passerby',
PUT => 'admin',
DELETE => 'admin',
},
cli => 'schedule sid $SID',
validations => {
'sid' => 'Int',
},
description => 'Retrieves, updates, or deletes a schedule by its SID',
documentation => <<'EOH',
=pod
This resource makes it possible to GET, PUT, or DELETE a schedule by its SID.
=over
=item * GET
An integer SID must be given as an URI parameter. If a schedule
with this SID is found, it is returned in the payload.
=item * PUT
This resource/method provides a way to set (modify) the 'scode', 'remark'
and/or 'disabled' fields of a schedule record. Simply provide the property (or
properties) and the new value(s) in the request body, e.g.:
{ "scode" : "WIGWAM" }
or
{ "remark" : "foobar", "disabled" : "t" }
lib/App/Dochazka/REST/Test.pm view on Meta::CPAN
use App::Dochazka::REST::Dispatch;
use App::Dochazka::REST::ConnBank qw( $dbix_conn conn_up );
use App::Dochazka::REST::Util qw( hash_the_password );
use App::Dochazka::REST::Model::Activity;
use App::Dochazka::REST::Model::Component;
use App::Dochazka::REST::Model::Privhistory qw( get_privhistory );
use App::Dochazka::REST::Model::Schedhistory qw( get_schedhistory );
use App::Dochazka::REST::Model::Shared qw( cud_generic noof select_single );
use Authen::Passphrase::SaltedDigest;
use Data::Dumper;
use HTTP::Request::Common qw( GET PUT POST DELETE );
use JSON;
use Params::Validate qw( :all );
use Test::JSON;
use Test::More;
use Try::Tiny;
use Web::MREST;
=head1 NAME
lib/App/Dochazka/REST/Test.pm view on Meta::CPAN
=head1 PACKAGE VARIABLES
=cut
# faux context
our $faux_context;
# dispatch table with references to HTTP::Request::Common functions
my %methods = (
GET => \&GET,
PUT => \&PUT,
POST => \&POST,
DELETE => \&DELETE,
);
=head1 FUNCTIONS
=cut
t/dispatch/001-resource.t view on Meta::CPAN
#!perl
use 5.012;
use strict;
use warnings;
#use App::CELL::Test::LogToFile;
use App::CELL qw( $log $meta $site );
use App::CELL::Status;
use App::Dochazka::REST::Test;
use Data::Dumper;
use HTTP::Request::Common qw( GET PUT POST DELETE );
use JSON;
use Plack::Test;
use Scalar::Util qw( blessed );
use Test::Fatal;
use Test::JSON;
use Test::More;
use Test::Warnings;
use Web::MREST::Resource;
note( 'initialize, connect to database, and set up a testing plan' );
t/dispatch/001-resource.t view on Meta::CPAN
note( 'request with bad credentials (401)' );
req( $test, 401, 'fandango', 'GET', '/' );
note( 'request that doesn\'t pass ACL check (403)' );
req( $test, 403, 'demo', 'GET', '/forbidden' );
note( 'GET request for non-existent resource (400)' );
req( $test, 400, 'demo', 'GET', '/HEE HAW!!!/non-existent/resource' );
note( 'PUT request for non-existent resource (400)' );
req( $test, 400, 'demo', 'PUT', '/HEE HAW!!!/non-existent/resource' );
note( 'POST request for non-existent resource (400)' );
req( $test, 400, 'demo', 'POST', '/HEE HAW!!!/non-existent/resource' );
note( 'DELETE request on non-existent resource (400)' );
req( $test, 400, 'demo', 'DELETE', '/HEE HAW!!!/non-existent/resource' );
note( 'test argument validation in \'push_onto_context\' method' );
like( exception { Web::MREST::Resource::push_onto_context( undef, 'DUMMY2' ); },
qr/not one of the allowed types: hashref/ );
t/dispatch/activity.t view on Meta::CPAN
# takes PARAMHASH with either 'aid => ...' or 'code => ...'
sub disable_testing_activity {
my %PH = @_;
my $resource;
if ( $PH{aid} ) {
$resource = "activity/aid/$PH{aid}";
} elsif ( $PH{code} ) {
$resource = "activity/code/$PH{code}";
}
my $status = req( $test, 200, 'root', 'PUT', $resource, '{ "disabled" : true }' );
is( $status->level, 'OK', "Disable Testing Activity 2" );
is( $status->code, 'DOCHAZKA_CUD_OK', "Disable Testing Activity 3" );
is( ref( $status->payload ), 'HASH', "Disable Testing Activity 4" );
my $act = $status->payload;
ok( $act->{aid} > 8, "Disable Testing Activity 5" );
ok( $act->{disabled}, "Disable Testing Activity 6" );
return App::Dochazka::REST::Model::Activity->spawn( $act );
}
note( "create testing employees with 'active' and 'inactive' privlevels" );
create_active_employee( $test );
create_inactive_employee( $test );
note( '=======================' );
note( '"activity/aid" resource' );
note( '=======================' );
my $base = 'activity/aid';
docu_check($test, "$base");
note( "GET, PUT on $base" );
foreach my $method ( 'GET', 'PUT' ) {
foreach my $user ( 'demo', 'active', 'root', 'WOMBAT5', 'WAMBLE owdkmdf 5**' ) {
req( $test, 405, $user, $method, $base );
}
}
note( "POST on $base" );
my $foowop = create_testing_activity( code => 'FOOWOP' );
my $aid_of_foowop = $foowop->aid;
note( 'test if expected behavior behaves as expected (update)' );
t/dispatch/activity.t view on Meta::CPAN
is( $status->level, 'OK', "GET $base/:aid 13" );
is( $status->code, 'DISPATCH_ACTIVITY_FOUND', "GET $base/:aid 14" );
is_deeply( $status->payload, {
aid => $aid_of_foobar,
code => 'FOOBAR',
long_desc => undef,
remark => undef,
disabled => 1,
}, "GET $base/:aid 15" );
note( "PUT on $base/:aid" );
$activity_obj = '{ "code" : "FOOBAR", "long_desc" : "The bar of foo", "remark" : "Change is good" }';
# - test with demo fail 405
req( $test, 403, 'active', 'PUT', "$base/$aid_of_foobar", $activity_obj );
note( 'test with root success' );
$status = req( $test, 200, 'root', 'PUT', "$base/$aid_of_foobar", $activity_obj );
is( $status->level, 'OK', "PUT $base/:aid 3" );
is( $status->code, 'DOCHAZKA_CUD_OK', "PUT $base/:aid 4" );
is( ref( $status->payload ), 'HASH', "PUT $base/:aid 5" );
note( 'make an Activity object out of the payload' );
$foobar = App::Dochazka::REST::Model::Activity->spawn( $status->payload );
is( $foobar->long_desc, "The bar of foo", "PUT $base/:aid 5" );
is( $foobar->remark, "Change is good", "PUT $base/:aid 6" );
ok( $foobar->disabled, "PUT $base/:aid 7" );
note( 'test with root no request body' );
$status = req( $test, 200, 'root', 'PUT', "$base/$aid_of_foobar" );
is( $status->level, 'OK', "PUT $base/:aid 8" );
is( $status->code, 'DISPATCH_UPDATE_NO_CHANGE_OK', "PUT $base/:aid 9" );
note( 'test with root fail invalid JSON' );
req( $test, 400, 'root', 'PUT', "$base/$aid_of_foobar", '{ asdf' );
note( 'test with root fail invalid AID' );
req( $test, 400, 'root', 'PUT', "$base/asdf", '{ "legal":"json" }' );
note( 'with valid JSON that is not what we are expecting' );
$status = req( $test, 200, 'root', 'PUT', "$base/$aid_of_foobar", '0' );
is( $status->level, 'OK', "PUT $base/:aid 10" );
is( $status->code, 'DISPATCH_UPDATE_NO_CHANGE_OK', "PUT $base/:aid 11" );
note( 'with valid JSON that has some bogus properties' );
$status = req( $test, 200, 'root', 'PUT', "$base/$aid_of_foobar", '{ "legal":"json" }' );
is( $status->level, 'OK', "PUT $base/:aid 12" );
is( $status->code, 'DISPATCH_UPDATE_NO_CHANGE_OK', "PUT $base/:aid 13" );
note( "POST on $base/:aid" );
req( $test, 405, 'demo', 'POST', "$base/1" );
req( $test, 405, 'active', 'POST', "$base/1" );
req( $test, 405, 'root', 'POST', "$base/1" );
note( "DELETE on $base/:aid" );
note( 'demo fail 403' );
req( $test, 403, 'demo', 'DELETE', "$base/1" );
t/dispatch/activity.t view on Meta::CPAN
$status = req( $test, 200, 'root', 'GET', $base );
is( $status->level, 'OK' );
is( $status->code, 'DISPATCH_RECORDS_FOUND' );
is( $status->{count}, 8 );
ok( exists $status->{payload} );
is( scalar @{ $status->payload }, 8 );
note( 'and testing activity is absent' );
ok( ! scalar( grep { $_->{code} eq 'FOOBAR'; } @{ $status->payload } ), "GET $base 7" );
note( "PUT, POST, DELETE on $base" );
req( $test, 405, 'demo', 'PUT', $base );
req( $test, 405, 'active', 'PUT', $base );
req( $test, 405, 'root', 'PUT', $base );
req( $test, 405, 'demo', 'POST', $base );
req( $test, 405, 'active', 'POST', $base );
req( $test, 405, 'root', 'POST', $base );
req( $test, 405, 'demo', 'DELETE', $base );
req( $test, 405, 'active', 'DELETE', $base );
req( $test, 405, 'root', 'DELETE', $base );
note( '=============================' );
note( '"activity/all/disabled" resource' );
t/dispatch/activity.t view on Meta::CPAN
note( "count is 9 with disabled FOOBAR activity" );
is( $status->{count}, 9, "GET $base 4" );
ok( exists $status->{payload}, "GET $base 5" );
is( scalar @{ $status->payload }, 9, "GET $base 6" );
note( "get the disabled activity" );
ok( scalar( grep { $_->{code} eq 'FOOBAR'; } @{ $status->payload } ), "GET $base 7" );
note( "PUT, POST, DELETE on $base" );
req( $test, 405, 'demo', 'PUT', $base );
req( $test, 405, 'active', 'PUT', $base );
req( $test, 405, 'root', 'PUT', $base );
req( $test, 405, 'demo', 'POST', $base );
req( $test, 405, 'active', 'POST', $base );
req( $test, 405, 'root', 'POST', $base );
req( $test, 405, 'demo', 'DELETE', $base );
req( $test, 405, 'active', 'DELETE', $base );
req( $test, 405, 'root', 'DELETE', $base );
note( "delete the disabled testing activity" );
delete_testing_activity( $aid_of_foobar );
note( "=============================" );
note( "'activity/code' resource" );
note( "=============================" );
$base = 'activity/code';
docu_check($test, "$base");
note( "GET, PUT on $base" );
req( $test, 405, 'demo', 'GET', $base );
req( $test, 405, 'active', 'GET', $base );
req( $test, 405, 'root', 'GET', $base );
req( $test, 405, 'demo', 'PUT', $base );
req( $test, 405, 'active', 'PUT', $base );
req( $test, 405, 'root', 'PUT', $base );
note( "POST on $base" );
note( "insert: expected behavior" );
$activity_obj = '{ "code" : "FOOWANG", "long_desc" : "wang wang wazoo", "disabled" : "f" }';
req( $test, 403, 'demo', 'POST', $base, $activity_obj );
req( $test, 403, 'active', 'POST', $base, $activity_obj );
$status = req( $test, 200, 'root', 'POST', $base, $activity_obj );
is( $status->level, 'OK', "POST $base 4" );
is( $status->code, 'DOCHAZKA_CUD_OK', "POST $base 5" );
t/dispatch/activity.t view on Meta::CPAN
'!!!! !134@@',
'whiner*44',
'@=1337',
'/ninety/nine/luftbalons//',
) {
foreach my $user ( qw( root demo ) ) {
req( $test, 400, $user, 'GET', "$base/$invalid_code" );
}
}
note( "PUT on $base/:code" );
$activity_obj = '{ "code" : "FOOBAR", "long_desc" : "baz waz wazoo", "remark" : "Full of it", "disabled" : "f" }';
note( 'demo fail 403' );
req( $test, 403, 'demo', 'PUT', "$base/FOOBAR", $activity_obj );
req( $test, 403, 'active', 'PUT', "$base/FOOBAR", $activity_obj );
note( 'root success' );
$status = req( $test, 200, 'root', 'PUT', "$base/FOOBAR", $activity_obj );
is( $status->level, "OK", "PUT $base/:code 3" );
is( $status->code, 'DOCHAZKA_CUD_OK', "PUT $base/:code 4" );
note( 'demo: no content body' );
req( $test, 403, 'demo', 'PUT', "$base/FOOBAR" );
note( 'active: no content body' );
req( $test, 403, 'active', 'PUT', "$base/FOOBAR" );
note( 'root: no content body' );
req( $test, 400, 'root', 'PUT', "$base/FOOBAR" );
req( $test, 400, 'root', 'PUT', "$base/FOOBAR_NEW" );
note( 'root: invalid JSON' );
req( $test, 400, 'root', 'PUT', "$base/FOOBAR", '{ asdf' );
note( 'root: invalid code' );
req( $test, 400, 'root', 'PUT', "$base/!!!!", '{ "legal":"json" }' );
note( 'root: valid JSON that is not what we are expecting' );
req( $test, 400, 'root', 'PUT', "$base/FOOBAR", '0' );
req( $test, 400, 'root', 'PUT', "$base/FOOBAR_NEW", '0' );
note( 'root: update with combination of valid and invalid properties' );
$status = req( $test, 200, 'root', 'PUT', "$base/FOOBAR",
'{ "nick":"FOOBAR", "remark":"Nothing much", "sister":"willy\'s" }' );
is( $status->level, 'OK', "PUT $base/FOOBAR 21" );
is( $status->code, 'DOCHAZKA_CUD_OK', "PUT $base/FOOBAR 22" );
is( $status->payload->{'remark'}, "Nothing much", "PUT $base/FOOBAR 23" );
ok( ! exists( $status->payload->{'nick'} ), "PUT $base/FOOBAR 24" );
ok( ! exists( $status->payload->{'sister'} ), "PUT $base/FOOBAR 25" );
note( 'root: insert with combination of valid and invalid properties' );
$status = req( $test, 200, 'root', 'PUT', "$base/FOOBARPUS",
'{ "nick":"FOOBAR", "remark":"Nothing much", "sister":"willy\'s" }' );
is( $status->level, 'OK', "PUT $base/FOOBAR 27" );
is( $status->code, 'DOCHAZKA_CUD_OK', "PUT $base/FOOBAR 28" );
is( $status->payload->{'remark'}, "Nothing much", "PUT $base/FOOBAR 29" );
ok( ! exists( $status->payload->{'nick'} ), "PUT $base/FOOBAR 30" );
ok( ! exists( $status->payload->{'sister'} ), "PUT $base/FOOBAR 31" );
note( "POST on $base/:code" );
req( $test, 405, 'demo', 'POST', "$base/WORK" );
req( $test, 405, 'active', 'POST', "$base/WORK" );
req( $test, 405, 'root', 'POST', "$base/WORK" );
note( "DELETE on $base/:code" );
note( 'demo fail 403 once' );
req( $test, 403, 'demo', 'DELETE', "$base/FOOBAR1" );
t/dispatch/component.t view on Meta::CPAN
ok( scalar @{ $status->payload } );
note( 'testing component is present' );
ok( scalar( grep { $_->{path} eq 'FOOBAR'; } @{ $status->payload } ), "GET $base 7" );
note( 'delete the testing component' );
delete_testing_component( $cid_of_foobar );
ok( ! path_exists_by_dispatch( "FOOBAR" ) );
ok( ! path_exists( $dbix_conn, "FOOBAR" ) );
note( "PUT, POST, DELETE on $base" );
foreach my $method ( 'PUT', 'POST', 'DELETE' ) {
foreach my $user ( 'demo', 'active', 'piggy', 'root' ) {
req( $test, 405, $user, $method, $base );
}
}
note( '========================' );
note( '"component/cid" resource' );
note( '========================' );
$base = 'component/cid';
docu_check($test, "$base");
note( "GET, PUT on $base" );
foreach my $method ( 'GET', 'PUT' ) {
foreach my $user ( 'demo', 'active', 'root', 'WOMBAT5', 'WAMBLE owdkmdf 5**' ) {
req( $test, 405, $user, $method, $base );
}
}
note( "POST on $base" );
my $foowop = create_testing_component( path => 'FOOWOP', source => 'nada', acl => 'passerby' );
my $cid_of_foowop = $foowop->cid;
my $full_path_of_foowop = File::Spec->catfile( $comp_root, $foowop->path );
ok( -o $full_path_of_foowop );
t/dispatch/component.t view on Meta::CPAN
acl => 'passerby',
validations => undef,
}, "GET $base/:cid 4" );
note( "fail invalid (non-integer) cid" );
req( $test, 400, 'root', 'GET', "$base/jj" );
note( "fail non-existent cid" );
req( $test, 404, 'root', 'GET', "$base/444" );
note( "PUT on $base/:cid" );
$component_obj = '{ "path" : "FOOBAR", "source" : "The bar of foo", "acl" : "inactive" }';
# - test with demo fail 403
req( $test, 403, 'demo', 'PUT', "$base/$cid_of_foobar", $component_obj );
note( 'test with root (successful update)' );
$status = req( $test, 200, 'root', 'PUT', "$base/$cid_of_foobar", $component_obj );
is( $status->level, 'OK', "PUT $base/:cid 3" );
is( $status->code, 'DOCHAZKA_CUD_OK', "PUT $base/:cid 4" );
is( ref( $status->payload ), 'HASH', "PUT $base/:cid 5" );
is( $status->payload->{path}, 'FOOBAR' );
is( $status->payload->{source}, 'The bar of foo' );
is( $status->payload->{acl}, 'inactive' );
is( "The bar of foo", read_file( $full_path_of_foobar ) );
note( 'change ACL to active' );
$status = req( $test, 200, 'root', 'PUT', "$base/$cid_of_foobar", '{ "acl":"active" }' );
is( $status->level, 'OK' );
is( $status->code, 'DOCHAZKA_CUD_OK' );
is( ref( $status->payload ), 'HASH' );
is( $status->payload->{path}, 'FOOBAR' );
is( $status->payload->{source}, 'The bar of foo' );
is( $status->payload->{acl}, 'active' );
is( "The bar of foo", read_file( $full_path_of_foobar ) );
note( 'attempt ot change ACL to an illegal value' );
req( $test, 400, 'root', 'PUT', "$base/$cid_of_foobar", '{ "acl":"puppy" }' );
note( 'make an component object out of the payload' );
$foobar = App::Dochazka::REST::Model::Component->spawn( $status->payload );
is( $foobar->source, "The bar of foo", "PUT $base/:cid 5" );
is( $foobar->acl, "active", "PUT $base/:cid 6" );
note( 'test with root no request body' );
req( $test, 400, 'root', 'PUT', "$base/$cid_of_foobar" );
note( 'test with root fail invalid JSON' );
req( $test, 400, 'root', 'PUT', "$base/$cid_of_foobar", '{ asdf' );
note( 'test with root fail invalid cid' );
req( $test, 400, 'root', 'PUT', "$base/asdf", '{ "legal":"json" }' );
note( 'with valid JSON that is not what we are expecting' );
req( $test, 400, 'root', 'PUT', "$base/$cid_of_foobar", '0' );
note( 'with valid JSON that has some bogus properties' );
req( $test, 400, 'root', 'PUT', "$base/$cid_of_foobar", '{ "legal":"json" }' );
req( $test, 400, 'root', 'PUT', "$base/$cid_of_foobar", '{ "aid":"json" }' );
note( "POST on $base/:cid" );
req( $test, 405, 'demo', 'POST', "$base/$cid_of_foobar" );
req( $test, 405, 'root', 'POST', "$base/$cid_of_foobar" );
note( "DELETE on $base/:cid" );
note( 'demo fail 403' );
req( $test, 403, 'demo', 'DELETE', "$base/$cid_of_foobar" );
t/dispatch/component.t view on Meta::CPAN
note( 'root fail invalid cid' );
req( $test, 400, 'root', 'DELETE', "$base/asd" );
note( "=============================" );
note( "'component/path' resource" );
note( "=============================" );
$base = 'component/path';
docu_check($test, "$base");
note( "GET, PUT on $base" );
foreach my $method ( 'GET', 'PUT' ) {
foreach my $user ( 'demo', 'active', 'puppy', 'root' ) {
req( $test, 405, $user, $method, $base );
}
}
note( "POST on $base" );
note( "insert: expected behavior" );
$component_obj = '{ "path" : "library/foowang.mc", "source" : "wang wang wazoo", "acl" : "passerby" }';
req( $test, 403, 'demo', 'POST', $base, $component_obj );
t/dispatch/employee.t view on Meta::CPAN
'%^%#$#',
# 'ŽluÅ¥oucký kÇÅ',
' dfdf fifty-five sixty-five',
'passerbies',
'///adfd/asdf/asdf',
) {
req( $test, 400, 'root', 'GET', "$base/$priv" );
req( $test, 400, 'demo', 'GET', "$base/$priv" );
}
note( "PUT, POST, DELETE $base" );
note( 'fail 405 as demo, active, root, WOMBAT' );
$status = req( $test, 405, 'demo', 'PUT', $base );
$status = req( $test, 405, 'active', 'PUT', $base );
$status = req( $test, 405, 'WOMBAT', 'PUT', $base );
$status = req( $test, 405, 'root', 'PUT', $base );
$status = req( $test, 405, 'demo', 'POST', $base );
$status = req( $test, 405, 'active', 'POST', $base );
$status = req( $test, 405, 'root', 'POST', $base );
$status = req( $test, 405, 'demo', 'DELETE', $base );
$status = req( $test, 405, 'active', 'DELETE', $base );
$status = req( $test, 405, 'root', 'DELETE', $base );
$base .= '/admin';
note( "PUT, POST, DELETE $base" );
note( 'fail 405 for demo, active, root' );
$status = req( $test, 405, 'demo', 'PUT', $base );
$status = req( $test, 405, 'active', 'PUT', $base );
$status = req( $test, 405, 'root', 'PUT', $base );
$status = req( $test, 405, 'demo', 'POST', $base );
$status = req( $test, 405, 'active', 'POST', $base );
$status = req( $test, 405, 'root', 'POST', $base );
$status = req( $test, 405, 'demo', 'DELETE', $base );
$status = req( $test, 405, 'active', 'DELETE', $base );
$status = req( $test, 405, 'root', 'DELETE', $base );
note( '=============================' );
note( '"employee/self" resource' );
t/dispatch/employee.t view on Meta::CPAN
'eid' => 1,
'sec_id' => undef,
'nick' => 'root',
'fullname' => 'Root Immutable',
'email' => 'root@site.org',
'supervisor' => undef,
'remark' => 'dbinit',
'sync' => 0,
}, "GET $base 10" );
note( "looping: PUT $base" );
$status = req( $test, 405, 'demo', 'PUT', $base );
$status = req( $test, 405, 'active', 'PUT', $base );
$status = req( $test, 405, 'root', 'PUT', $base );
note( "looping: POST $base" );
note( "- default configuration is that 'active' and 'inactive' can modify" );
note( ' their own passhash and salt fields; demo should *not* be ' );
note( ' authorized to do this' );
req( $test, 403, 'demo', 'POST', $base, '{ "password":"saltine" }' );
foreach my $user ( "active", "inactive" ) {
#
#diag( "$user $base " . '{ "password" : "saltine" }' );
$status = req( $test, 200, $user, 'POST', $base, '{ "password" : "saltine" }' );
if ( $status->not_ok ) {
diag( Dumper $status );
BAIL_OUT(0);
}
is( $status->level, 'OK' );
is( $status->code, 'DOCHAZKA_CUD_OK' );
note( '- use root to change it back, otherwise the user won\'t be able' );
note( ' to log in and next tests will fail' );
$status = req( $test, 200, 'root', 'PUT', "employee/nick/$user", "{ \"password\" : \"$user\" }" );
is( $status->level, 'OK' );
is( $status->code, 'DOCHAZKA_CUD_OK' );
note( '- legal but bogus JSON in body' );
$status = req( $test, 200, $user, 'POST', $base, 0 );
is( $status->level, 'OK' );
is( $status->code, 'DISPATCH_UPDATE_NO_CHANGE_OK' );
note( "- 'salt' is a permitted field, but 'inactive'/$user employees" );
note( " should not, for example, be allowed to change 'nick'" );
t/dispatch/employee.t view on Meta::CPAN
is( $status->payload->{'priv'}, 'admin' );
is( ref( $status->payload->{'privhistory'} ), 'HASH' );
ok( exists $status->payload->{'privhistory'}->{'phid'} );
} else {
diag( "bad \$originator ($originator) in test loop" );
BAIL_OUT(0);
}
is( $status->payload->{'schedule'}, undef );
is( $status->payload->{'schedhistory'}, undef );
note( "PUT, POST, DELETE $resource" );
$status = req( $test, 405, $originator, 'PUT', $uri );
$status = req( $test, 405, $originator, 'POST', $uri );
$status = req( $test, 405, $originator, 'DELETE', $uri );
}
note( '=============================' );
note( '"employee/eid/:eid/full" resource' );
note( '"employee/nick/:nick/full" resource' );
note( '=============================' );
t/dispatch/employee.t view on Meta::CPAN
'inactive' => $ts_eid_inactive,
'active' => $ts_eid_active,
'root' => $site->DOCHAZKA_EID_OF_ROOT,
);
foreach my $nick ( 'demo' ) {
my $eid = $eid_map{$nick};
foreach my $uri ( "employee/eid/$eid/full", "employee/nick/$nick/full" ) {
note( "$nick tries and fails to use $uri resource" );
req( $test, 403, $nick, 'GET', $uri );
req( $test, 405, $nick, 'PUT', $uri );
req( $test, 405, $nick, 'POST', $uri );
req( $test, 405, $nick, 'DELETE', $uri );
}
}
foreach my $nick ( 'demo', 'inactive', 'active' ) {
foreach my $uri ( "employee/eid/1/full", "employee/nick/root/full" ) {
note( "$nick tries and fails to use $uri resource" );
req( $test, 403, $nick, 'GET', $uri );
req( $test, 405, $nick, 'PUT', $uri );
req( $test, 405, $nick, 'POST', $uri );
req( $test, 405, $nick, 'DELETE', $uri );
}
}
sub _employee_full_success {
my ( $originator, $nick, $uri ) = @_;
note( "$nick tries and succeeds to use $uri resource" );
$status = req( $test, 200, $originator, 'GET', $uri );
t/dispatch/employee.t view on Meta::CPAN
is( $status->payload->{'schedule'}, undef );
is( $status->payload->{'schedhistory'}, undef );
}
foreach my $nick ( 'active', 'root' ) {
my $eid = $eid_map{$nick};
foreach my $uri ( "employee/eid/$eid/full", "employee/nick/$nick/full" ) {
_employee_full_success( $nick, $nick, $uri );
note( "PUT, POST, DELETE $resource" );
req( $test, 405, $nick, 'PUT', $uri );
req( $test, 405, $nick, 'POST', $uri );
req( $test, 405, $nick, 'DELETE', $uri );
}
}
foreach my $uri ( "employee/eid/$ts_eid_inactive/full", "employee/nick/inactive/full" ) {
_employee_full_success( 'root', 'inactive', $uri );
}
note( '=============================' );
note( '"employee/eid" resource' );
note( '=============================' );
$base = "employee/eid";
note( "docu_check on $base" );
docu_check($test, "employee/eid");
note( "GET, PUT: $base" );
req( $test, 405, 'demo', 'GET', $base );
req( $test, 405, 'active', 'GET', $base );
req( $test, 405, 'root', 'GET', $base );
req( $test, 405, 'demo', 'PUT', $base );
req( $test, 405, 'active', 'PUT', $base );
req( $test, 405, 'root', 'PUT', $base );
note( "POST: $base" );
note( "create a 'mrfu' employee" );
my $mrfu = create_bare_employee( { nick => 'mrfu', password => 'mrfu' } );
my $eid_of_mrfu = $mrfu->eid;
# these tests break when 'email' is added to DOCHAZKA_PROFILE_EDITABLE_FIELDS
## - give Mr. Fu an email address
##req( $test, 403, 'demo', 'POST', $base, '{ "eid": ' . $mrfu->eid . ', "email" : "shake it" }' );
t/dispatch/employee.t view on Meta::CPAN
is( $status->code, 'DISPATCH_EMPLOYEE_FOUND' );
note( 'unknown user gets 401' );
req( $test, 401, 'unknown', 'GET', "$base/2" ); # EID 2 is 'demo'
note( 'non-administrators cannot use this resource to look at other employees' );
foreach my $user ( qw( active inactive demo ) ) {
my $status = req( $test, 403, $user, 'GET', "$base/1" );
}
note( "PUT $base/:eid" );
note( "create a testing employee 'brotherchen'" );
my $emp = create_bare_employee( {
nick => 'brotherchen',
email => 'goodbrother@orient.cn',
fullname => 'Good Brother Chen',
} );
my $eid_of_brchen = $emp->{eid};
is( $eid_of_brchen, $emp->eid );
note( "insufficient priv" );
req( $test, 403, 'demo', 'PUT', "$base/$eid_of_brchen",
'{ "eid": ' . $eid_of_brchen . ', "fullname":"Chen Update Again" }' );
note( "be nice" );
req( $test, 403, 'demo', 'PUT', "$base/$eid_of_brchen",
'{ "fullname":"Chen Update Again", "salt":"tasty" }' );
$status = req( $test, 200, 'root', 'PUT', "$base/$eid_of_brchen",
'{ "fullname":"Chen Update Again", "salt":"tasty" }' );
is( $status->level, 'OK' );
is( $status->code, 'DOCHAZKA_CUD_OK' );
my $brchen = App::Dochazka::REST::Model::Employee->spawn( %{ $status->payload } );
is( $brchen->eid, $eid_of_brchen );
my $brchenprime = App::Dochazka::REST::Model::Employee->spawn( eid => $eid_of_brchen,
nick => 'brotherchen', email => 'goodbrother@orient.cn', fullname =>
'Chen Update Again', salt => 'tasty', sync => 0 );
is_deeply( $brchen, $brchenprime );
note( "provide invalid EID in request body -> it will be ignored" );
$status = req( $test, 200, 'root', 'PUT', "$base/$eid_of_brchen",
'{ "eid": 99999, "fullname":"Chen Update Again 2" }' );
is( $status->level, 'OK' );
is( $status->code, 'DOCHAZKA_CUD_OK' );
$brchen = App::Dochazka::REST::Model::Employee->spawn( %{ $status->payload } );
isnt( $brchen->eid, 99999 );
is( $brchen->eid, $eid_of_brchen );
$brchenprime = App::Dochazka::REST::Model::Employee->spawn( eid => $eid_of_brchen,
nick => 'brotherchen', email => 'goodbrother@orient.cn', fullname =>
'Chen Update Again 2', salt => 'tasty', sync => 0 );
is_deeply( $brchen, $brchenprime );
note( 'change the nick' );
req( $test, 403, 'demo', 'PUT', "$base/$eid_of_brchen", '{' );
req( $test, 400, 'root', 'PUT', "$base/$eid_of_brchen", '{' );
req( $test, 403, 'demo', 'PUT', "$base/$eid_of_brchen", '{ "nick": "mrfu", "fullname":"Lizard Scale" }' );
$status = req( $test, 200, 'root', 'PUT', "$base/$eid_of_brchen",
'{ "nick": "mrfu", "fullname":"Lizard Scale", "email":"mrfu@dragon.cn" }' );
is( $status->level, 'OK' );
is( $status->code, 'DOCHAZKA_CUD_OK' );
$mrfu = App::Dochazka::REST::Model::Employee->spawn( %{ $status->payload } );
isnt( $mrfu->nick, 'brotherchen' );
is( $mrfu->nick, 'mrfu' );
my $mrfuprime = App::Dochazka::REST::Model::Employee->spawn( eid => $eid_of_brchen,
nick => 'mrfu', fullname => 'Lizard Scale', email => 'mrfu@dragon.cn',
salt => 'tasty', sync => 0 );
is_deeply( $mrfu, $mrfuprime );
$eid_of_mrfu = $mrfu->eid;
is( $eid_of_mrfu, $eid_of_brchen );
note( 'provide non-existent EID' );
req( $test, 403, 'demo', 'PUT', "$base/5633", '{' );
req( $test, 404, 'root', 'PUT', "$base/5633", '{' );
req( $test, 403, 'demo', 'PUT', "$base/5633",
'{ "nick": "mrfu", "fullname":"Lizard Scale" }' );
req( $test, 404, 'root', 'PUT', "$base/5633",
'{ "eid": 534, "nick": "mrfu", "fullname":"Lizard Scale" }' );
note( 'with valid JSON that is not what we are expecting' );
req( $test, 400, 'root', 'PUT', "$base/2", 0 );
note( 'another kind of bogus JSON' );
$status = req( $test, 200, 'root', 'PUT', "$base/2", '{ "legal" : "json" }' );
is( $status->level, 'OK' );
is( $status->code, 'DISPATCH_UPDATE_NO_CHANGE_OK' );
note( 'invalid EIDs caught by Path::Router validations clause' );
foreach my $eid ( @invalid_eids ) {
foreach my $user ( qw( root demo ) ) {
req( $test, 400, $user, 'PUT', "$base/$eid" );
}
}
note( 'inactive and active users get a little piece of the action, too:' );
note( 'they can operate on themselves (certain fields), but not on, e.g., Mr. Fu' );
foreach my $user ( qw( demo inactive active ) ) {
req( $test, 403, $user, 'PUT', "$base/$eid_of_mrfu", <<"EOH" );
{ "passhash" : "HAHAHAHA" }
EOH
}
foreach my $user ( qw( demo inactive active ) ) {
$status = req( $test, 200, 'root', 'GET', "employee/nick/$user" );
is( $status->level, 'OK' );
is( $status->code, 'DISPATCH_EMPLOYEE_FOUND' );
is( ref( $status->payload ), 'HASH' );
my $eid = $status->payload->{'eid'};
req( $test, 403, $user, 'PUT', "$base/$eid", <<"EOH" );
{ "nick" : "tHE gREAT fABULATOR" }
EOH
}
foreach my $user ( qw( inactive active ) ) {
$status = req( $test, 200, 'root', 'GET', "employee/nick/$user" );
is( $status->level, 'OK' );
is( $status->code, 'DISPATCH_EMPLOYEE_FOUND' );
is( ref( $status->payload ), 'HASH' );
my $eid = $status->payload->{'eid'};
$status = req( $test, 200, $user, 'PUT', "$base/$eid", <<"EOH" );
{ "password" : "tHE gREAT fABULATOR" }
EOH
is( $status->level, 'OK' );
is( $status->code, 'DOCHAZKA_CUD_OK' );
note( "so far so good, but now we can\'t log in because Test.pm assumes password is $user" );
req( $test, 401, $user, 'GET', "$base/$eid" );
note( 'change it back' );
$status = req( $test, 200, 'root', 'PUT', "$base/$eid", "{ \"password\" : \"$user\" }" );
is( $status->level, 'OK' );
is( $status->code, 'DOCHAZKA_CUD_OK' );
note( 'working again' );
$status = req( $test, 200, 'root', 'GET', "employee/nick/$user" );
is( $status->level, 'OK' );
is( $status->code, 'DISPATCH_EMPLOYEE_FOUND' );
is( ref( $status->payload ), 'HASH' );
}
t/dispatch/employee.t view on Meta::CPAN
test_employee_list( $status, [ 'active', 'demo', 'inactive', 'root' ] );
$status = req( $test, 200, 'root', 'GET', "$base/admin" );
test_employee_list( $status, [ 'root' ] );
$status = req( $test, 200, 'root', 'GET', "$base/active" );
test_employee_list( $status, [ 'active' ] );
$status = req( $test, 200, 'root', 'GET', "$base/inactive" );
test_employee_list( $status, [ 'inactive' ] );
$status = req( $test, 200, 'root', 'GET', "$base/passerby" );
test_employee_list( $status, [ 'demo' ] );
note( 'PUT, POST, DELETE employee/list/?:priv' );
req( $test, 405, 'demo', 'PUT', $base );
req( $test, 405, 'root', 'PUT', $base );
req( $test, 405, 'demo', 'POST', $base );
req( $test, 405, 'root', 'POST', $base );
req( $test, 405, 'demo', 'DELETE', $base );
req( $test, 405, 'root', 'DELETE', $base );
note( "=============================" );
note( '"employee/nick" resource' );
note( "=============================" );
$base = "employee/nick";
docu_check($test, "employee/nick");
note( 'GET, PUT employee/nick' );
req( $test, 405, 'demo', 'GET', $base );
req( $test, 405, 'root', 'GET', $base );
req( $test, 405, 'demo', 'PUT', $base );
req( $test, 405, 'root', 'PUT', $base );
note( 'POST employee/nick' );
note( 'create a \'mrfu\' employee' );
$mrfu = create_bare_employee( { nick => 'mrfu' } );
my $nick_of_mrfu = $mrfu->nick;
$eid_of_mrfu = $mrfu->eid;
note( 'give Mr. Fu an email address' );
my $j = '{ "nick": "' . $nick_of_mrfu . '", "email" : "mrsfu@dragon.cn" }';
t/dispatch/employee.t view on Meta::CPAN
req( $test, 403, 'demo', 'GET', "$base/53432" );
req( $test, 404, 'root', 'GET', "$base/heathledger" );
# this one triggers "wide character in print" warnings
#req( $test, 404, 'root', 'GET', "$base/" . uri_escape_utf8('/employee/nick//////áÄÄoÄÅ¡ÄqwšášÄšýš..-...-...-..-.00') );
note( 'single-character nicks' );
$status = req( $test, 404, 'root', 'GET', "$base/4" );
note( "PUT employee/nick/:nick" );
note( 'demo cannot PUT no matter what' );
req( $test, 403, 'demo', 'PUT', "$base/mrsfu", '{' );
note( 'root can PUT, but JSON entity is invalid' );
req( $test, 400, 'root', 'PUT', "$base/mrsfu", '{' );
note( 'demo cannot PUT no matter what' );
req( $test, 403, 'demo', 'PUT', "$base/mrsfu",
'{ "fullname":"Dragonness" }' );
note( 'insert happy path' );
$status = req( $test, 200, 'root', 'PUT', "$base/mrsfu",
'{ "fullname":"Dragonness" }' );
is( $status->level, 'OK' );
is( $status->code, 'DOCHAZKA_CUD_OK' );
$mrsfu = App::Dochazka::REST::Model::Employee->spawn( %{ $status->payload } );
$mrsfuprime = App::Dochazka::REST::Model::Employee->spawn( eid => $mrsfu->eid,
nick => 'mrsfu', fullname => 'Dragonness', sync => 0 );
is_deeply( $mrsfu, $mrsfuprime );
my $eid_of_mrsfu = $mrsfu->eid;
note( 'insert pathological paths' );
note( 'provide conflicting \'nick\' property in the content body' );
req( $test, 403, 'demo', 'PUT', "$base/hapless", '{' );
req( $test, 400, 'root', 'PUT', "$base/hapless", '{' );
req( $test, 403, 'demo', 'PUT', "$base/hapless",
'{ "nick":"INVALID", "fullname":"Anders Chen" }' );
$status = req( $test, 200, 'root', 'PUT', "$base/hapless",
'{ "nick":"INVALID", "fullname":"Anders Chen" }' );
is( $status->level, 'OK' );
is( $status->code, 'DOCHAZKA_CUD_OK' );
my $hapless = App::Dochazka::REST::Model::Employee->spawn( %{ $status->payload } );
isnt( $hapless->nick, 'INVALID' );
is( $hapless->nick, 'hapless' );
my $haplessprime = App::Dochazka::REST::Model::Employee->spawn( eid => $hapless->eid,
nick => 'hapless', fullname => 'Anders Chen', sync => 0 );
is_deeply( $hapless, $haplessprime );
my $eid_of_hapless = $hapless->eid;
note( "update happy path" );
$status = req( $test, 200, 'root', 'PUT', "$base/hapless",
'{ "fullname":"Chen Update", "salt":"none, please" }' );
is( $status->level, 'OK' );
is( $status->code, 'DOCHAZKA_CUD_OK' );
$hapless = App::Dochazka::REST::Model::Employee->spawn( %{ $status->payload } );
is( $hapless->nick, "hapless" );
is( $hapless->fullname, "Chen Update" );
is( $hapless->salt, "none, please" );
$haplessprime = App::Dochazka::REST::Model::Employee->spawn( eid => $eid_of_hapless,
nick => 'hapless', fullname => 'Chen Update', salt => "none, please",
sync => 0 );
is_deeply( $hapless, $haplessprime );
note( "update: change salt to null" );
$status = req( $test, 200, 'root', 'PUT', "$base/hapless",
'{ "fullname":"Chen Update", "salt":null }' );
is( $status->level, 'OK' );
is( $status->code, 'DOCHAZKA_CUD_OK' );
$hapless = App::Dochazka::REST::Model::Employee->spawn( %{ $status->payload } );
is( $hapless->nick, "hapless" );
is( $hapless->fullname, "Chen Update" );
is( $hapless->salt, undef );
$haplessprime = App::Dochazka::REST::Model::Employee->spawn( eid => $eid_of_hapless,
nick => 'hapless', fullname => 'Chen Update', sync => 0 );
is_deeply( $hapless, $haplessprime );
note( "update: pathological paths" );
note( 'attempt to set a bogus EID' );
$status = req( $test, 200, 'root', 'PUT', "$base/hapless",
'{ "eid": 534, "fullname":"Good Brother Chen", "salt":"" }' );
is( $status->level, 'OK' );
is( $status->code, 'DOCHAZKA_CUD_OK' );
$hapless = App::Dochazka::REST::Model::Employee->spawn( %{ $status->payload } );
is( $hapless->fullname, "Good Brother Chen" );
is( $hapless->eid, $eid_of_hapless );
isnt( $hapless->eid, 534 );
$haplessprime = App::Dochazka::REST::Model::Employee->spawn( eid => $eid_of_hapless,
nick => 'hapless', fullname => 'Good Brother Chen', salt => '', sync => 0 );
is_deeply( $hapless, $haplessprime );
note( 'attempt to change nick to null' );
dbi_err( $test, 500, 'root', 'PUT', "$base/hapless",
'{ "nick":null }', qr/violates not-null constraint/ );
note( 'feed it some random bogusness' );
$status = req( $test, 200, 'root', 'PUT', "$base/hapless", '{ "legal" : "json" }' );
is( $status->level, 'OK' );
is( $status->code, 'DISPATCH_UPDATE_NO_CHANGE_OK' );
note( 'inactive and active users can not change passwords of other users' );
foreach my $user ( qw( demo inactive active ) ) {
foreach my $target ( qw( mrsfu hapless ) ) {
req( $test, 403, $user, 'PUT', "$base/$target", <<"EOH" );
{ "passhash" : "HAHAHAHA" }
EOH
}
}
note( 'clean up testing employees' );
delete_bare_employee( $eid_of_mrsfu );
delete_bare_employee( $eid_of_hapless );
note( 'POST employee/nick:nick' );
t/dispatch/employee.t view on Meta::CPAN
#ok( ref( $status->payload->{'result_set'} ) eq 'ARRAY' );
#is( $status->payload->{'result_set'}->[0]->{'nick'}, 'root' );
note( '=============================' );
note( '"employee/sec_id/:sec_id" resource' );
note( '=============================' );
$base = "employee/sec_id";
docu_check($test, "$base/:sec_id");
note( "give 'inactive' employee a sec_id" );
$status = req( $test, 200, 'root', 'PUT', "employee/nick/inactive",
'{ "sec_id" : 1024 }' );
is( $status->level, "OK" );
is( $status->code, 'DOCHAZKA_CUD_OK' );
note( 'read it back' );
$status = req( $test, 200, 'root', 'GET', "employee/nick/inactive" );
is( $status->level, "OK" );
is( $status->code, 'DISPATCH_EMPLOYEE_FOUND' );
is( $status->payload->{'sec_id'}, 1024 );
my $mustr = $status->payload;
t/dispatch/history.t view on Meta::CPAN
'0',
'whinger',
'[,',
) {
req( $test, 400, 'root', 'GET', "$base/$inv_tsr" );
}
dbi_err( $test, 500, 'root', 'GET', "$base/[,sdf)", undef, qr/invalid input syntax for type timestamp/ );
dbi_err( $test, 500, 'root', 'GET', "$base/[\"2014-01-01 00:00\",\"2013-01-01 00:00\")", undef,
qr/range lower bound must be less than or equal to range upper bound/ );
note( 'PUT, POST, DELETE' );
req( $test, 405, 'demo', 'PUT', $base );
req( $test, 405, 'demo', 'POST', $base );
req( $test, 405, 'demo', 'DELETE', $base );
req( $test, 405, 'demo', 'PUT', "$base/[,)" );
req( $test, 405, 'demo', 'POST', "$base/[,)" );
req( $test, 405, 'demo', 'DELETE', "$base/[,)" );
}
note( '===========================================' );
note( '"{priv,schedule}/history/eid/:eid" resource' );
note( '===========================================' );
foreach $base ( "priv/history/eid", "schedule/history/eid" ) {
t/dispatch/history.t view on Meta::CPAN
req( $test, 404, 'root', 'GET', "$base/$inv_eid" );
}
foreach my $inv_eid ( '3443/plus/several/bogus/levels/of/subresources' ) {
# - as demo (entire resource is invalid, so ACL check is not reached)
req( $test, 400, 'demo', 'GET', "$base/$inv_eid" );
# - as root
req( $test, 400, 'root', 'GET', "$base/$inv_eid" );
}
note( 'PUT' );
req( $test, 405, 'demo', 'PUT', "$base/2" );
req( $test, 405, 'active', 'PUT', "$base/2" );
req( $test, 405, 'root', 'PUT', "$base/2" );
note( 'POST' );
note( 'dates before 1892-01-01 will not make it through the trigger' );
foreach my $ts (
'1869-04-28 19:15',
'1891-01-01 00:00',
'1891-12-31 23:55',
'1000-01-01 00:05',
'1500-12-20',
t/dispatch/history.t view on Meta::CPAN
note( 'non-existent EID');
my $tsr = '[1999-12-31 23:59, 2000-01-01 00:01)';
req( $test, 403, 'demo', 'GET', "$base/4534/$tsr" );
req( $test, 404, 'root', 'GET', "$base/4534/$tsr" );
note( 'invalid EID (caught by Path::Router validations)' );
foreach my $user ( qw( demo root ) ) {
req( $test, 400, $user, 'GET', "$base/asas/$tsr" );
}
note( 'PUT, POST, DELETE' );
foreach my $user ( qw( demo root ) ) {
foreach my $method ( qw( PUT POST DELETE ) ) {
req( $test, 405, $user, $method, "$base/23/[,)" );
}
}
}
note( '===========================================' );
note( '"{priv,schedule}/history/eid/:eid/:ts" resource' );
note( '===========================================' );
t/dispatch/history.t view on Meta::CPAN
note( 'non-existent EID');
my $ts = '\'2015-01-06 14:55\'';
req( $test, 403, 'demo', 'GET', "$base/4534/$ts" );
req( $test, 404, 'root', 'GET', "$base/4534/$ts" );
note( 'invalid EID (caught by Path::Router validations)' );
foreach my $user ( qw( demo root ) ) {
req( $test, 400, $user, 'GET', "$base/asas/$ts" );
}
note( 'PUT, POST, DELETE' );
foreach my $user ( qw( demo root ) ) {
foreach my $method ( qw( PUT POST DELETE ) ) {
req( $test, 405, $user, $method, "$base/23/1966-09-28 00:00" );
}
}
}
note( '===========================================' );
note( '"{priv,schedule}/history/eid/:eid/now" resource' );
note( '===========================================' );
t/dispatch/history.t view on Meta::CPAN
note( 'non-existent EID');
my $ts = '\'2015-01-06 14:55\'';
req( $test, 403, 'demo', 'GET', "$base/4534/now" );
req( $test, 404, 'root', 'GET', "$base/4534/now" );
note( 'invalid EID (caught by Path::Router validations)' );
foreach my $user ( qw( demo root ) ) {
req( $test, 400, $user, 'GET', "$base/asas/now" );
}
note( 'PUT, POST, DELETE' );
foreach my $user ( qw( demo root ) ) {
foreach my $method ( qw( PUT POST DELETE ) ) {
req( $test, 405, $user, $method, "$base/23/now" );
}
}
}
#===========================================
# "{priv,schedule}/history/nick/:nick" resource
#===========================================
foreach $base ( "priv/history/nick", "schedule/history/nick" ) {
t/dispatch/history.t view on Meta::CPAN
is( $status->payload->{'nick'}, 'root' );
ok( exists $status->payload->{'history'} );
is( scalar @{ $status->payload->{'history'} }, 1 );
is( $status->payload->{'history'}->[0]->{'eid'}, 1 );
ok( exists $status->payload->{'history'}->[0]->{'effective'} );
note( 'non-existent employee' );
req( $test, 403, 'demo', 'GET', "$base/rotoroot" );
req( $test, 404, 'root', 'GET', "$base/rotoroot" );
note( 'PUT' );
req( $test, 405, 'demo', 'PUT', "$base/asdf" );
req( $test, 405, 'root', 'PUT', "$base/asdf" );
note( "POST" );
$j = ( $base =~ m/^priv/ )
? '{ "effective":"1969-04-27 9:45", "priv":"inactive" }'
: '{ "effective":"1969-04-27 9:45", "sid":' . $ts_sid . ' }';
req( $test, 403, 'demo', 'POST', "$base/demo", $j );
$status = req( $test, 201, 'root', 'POST', "$base/demo", $j );
if ( $status->not_ok ) {
diag( $status->code . ' ' . $status->text );
}
t/dispatch/history.t view on Meta::CPAN
note( 'non-existent employee' );
my $tsr = '[1891-12-30, 1892-01-02)';
req( $test, 403, 'demo', 'GET', "$base/humphreybogart/$tsr" );
req( $test, 404, 'root', 'GET', "$base/humphreybogart/$tsr" );
note( 'root employee, with tsrange but no records found' );
req( $test, 403, 'demo', 'GET', "$base/root/[1999-12-31 23:59, 2000-01-01 00:01)" );
req( $test, 404, 'root', 'GET', "$base/root/[1999-12-31 23:59, 2000-01-01 00:01)" );
note( 'PUT, POST, DELETE' );
foreach my $user ( qw( demo root ) ) {
foreach my $method ( qw( PUT POST DELETE ) ) {
req( $test, 405, $user, $method, "$base/root/[1999-12-31 23:59, 2000-01-01 00:01)" );
}
}
}
note( '===========================================' );
note( '"{priv,schedule}/history/phid/:phid" resource' );
note( '===========================================' );
t/dispatch/history.t view on Meta::CPAN
$status = req( $test, 200, 'root', 'GET', "$base/$tphid" );
is( $status->level, 'OK' );
is( $status->code, 'DISPATCH_HISTORY_RECORD_FOUND' );
is( $status->payload->{'remark'}, undef );
is( $status->payload->{ ( ( $base =~ m/^priv/ ) ? 'priv' : 'sid' ) },
( ( $base =~ m/^priv/ ) ? 'inactive' : $ts_sid ) );
is( $status->payload->{'eid'}, 2 );
is( $status->payload->{$prop}, $tphid );
like( $status->payload->{'effective'}, qr/1977-04-27 15:30:00/ );
note( 'PUT' );
note( "PUT operations on $base/$tphid will fail with 405" );
foreach my $user ( qw( demo root ) ) {
req( $test, 405, $user, 'PUT', "$base/$tphid" );
}
note( 'POST' );
note( "Update the history record inserted above" );
$status = req( $test, 200, 'root', 'POST', "$base/$tphid", <<"EOS" );
{ "remark" : "I am foo!" }
EOS
is( $status->level, 'OK' );
is( $status->code, 'DOCHAZKA_CUD_OK' );
t/dispatch/interval_lock.t view on Meta::CPAN
EOH
is( $status->level, "OK" );
is( $status->code, "DOCHAZKA_CUD_OK" );
$status = req( $test, 200, 'root', 'GET', 'priv/nick/bubba' );
is( $status->level, "OK" );
is( $status->code, "DISPATCH_EMPLOYEE_PRIV" );
ok( $status->{'payload'} );
is( $status->{'payload'}->{'priv'}, 'active' );
note( 'let super be active\'s supervisor' );
$status = req( $test, 200, 'root', 'PUT', 'employee/nick/active', <<"EOH" );
{ "supervisor" : $eid_of_super }
EOH
is( $status->level, "OK" );
is( $status->code, "DOCHAZKA_CUD_OK" );
sub test_interval_new {
my ( $test ) = @_;
# get AID of WORK
my $aid_of_work = get_aid_by_code( $test, 'WORK' );
t/dispatch/interval_lock.t view on Meta::CPAN
is( $status->level, 'OK' );
is( $status->code, 'DISPATCH_RECORDS_FOUND' );
is( $status->{'count'}, 1 );
foreach my $tsr ( @failing_tsranges ) {
note( 'tsranges that fail validations clause' );
foreach my $user ( qw( demo inactive active root ) ) {
req( $test, 400, $user, 'GET', "$base/1/$tsr" );
}
}
note( 'PUT, POST' );
foreach my $method ( qw( PUT POST ) ) {
note( 'Testing method: $method' );
foreach my $user ( 'demo', 'root', 'WAMBLE owdkmdf 5**' ) {
req( $test, 405, $user, $method, "$base/2/[,)" );
}
}
#note( 'DELETE' );
#foreach my $user ( 'demo', 'root', 'WAMBLE owdkmdf 5**' ) {
# req( $test, 403, $user, 'DELETE', "$base/2/[,)" );
#}
t/dispatch/interval_lock.t view on Meta::CPAN
is( $status->{'DBI_return_value'}, 2 );
note( '=============================' );
note( 'interval/iid" resource' );
note( '"lock/lid" resource' );
note( '=============================' );
foreach my $il ( qw( interval lock ) ) {
my $base = "$il/$idmap{$il}";
docu_check($test, "$base");
note( 'GET, PUT' );
foreach my $method ( 'GET', 'PUT' ) {
note( 'Testing method: $method' );
foreach my $user ( 'demo', 'active', 'root', 'WOMBAT5', 'WAMBLE owdkmdf 5**' ) {
req( $test, 405, $user, $method, $base );
}
}
note( 'POST' );
my $test_id = ( $il eq 'interval' ) ? $test_iid : $test_lid;
#
note( 'test if expected behavior behaves as expected (update)' );
t/dispatch/interval_lock.t view on Meta::CPAN
ok( $status->payload->{'remark'} );
ok( ! defined $status->payload->{'long_desc'} );
}
note( 'fail invalid ID' );
req( $test, 400, 'active', 'GET', "$base/jj" );
note( 'fail non-existent IID' );
req( $test, 404, 'active', 'GET', "$base/444" );
note( 'PUT' );
my $int_obj = '{ "remark" : "Change is good" }';
note( 'test with demo fail 405' );
req( $test, 403, 'demo', 'PUT', "$base/$test_id", $int_obj );
note( 'test with root no request body' );
$status = req( $test, 200, 'root', 'PUT', "$base/$test_id" );
is( $status->level, 'OK' );
is( $status->code, 'DISPATCH_UPDATE_NO_CHANGE_OK' );
note( 'test with root fail invalid JSON' );
req( $test, 400, 'root', 'PUT', "$base/$test_id", '{ asdf' );
note( 'test with root fail invalid IID' );
req( $test, 400, 'root', 'PUT', "$base/asdf", '{ "legal":"json" }' );
note( 'with valid JSON that is not what we are expecting (valid IID)' );
$status = req( $test, 200, 'root', 'PUT', "$base/$test_id", '0' );
is( $status->level, 'OK' );
is( $status->code, 'DISPATCH_UPDATE_NO_CHANGE_OK' );
note( 'with valid JSON that has some bogus properties' );
$status = req( $test, 200, 'root', 'PUT', "$base/$test_id", '{ "legal":"json" }' );
is( $status->level, 'OK' );
is( $status->code, 'DISPATCH_UPDATE_NO_CHANGE_OK' );
note( 'POST' );
req( $test, 405, 'demo', 'POST', "$base/1" );
req( $test, 405, 'active', 'POST', "$base/1" );
req( $test, 405, 'root', 'POST', "$base/1" );
note( 'DELETE' );
note( 'first make sure there is something to delete' );
t/dispatch/interval_lock.t view on Meta::CPAN
$test_iid = test_interval_new( $test );
$test_lid = create_testing_lock( $test );
note( '=============================' );
note( 'The "interval/new" resource ( see below for tests common to both "interval/new" and "lock/new" )' );
note( '=============================' );
my $base = 'interval/new';
docu_check($test, $base);
note( 'GET, PUT' );
foreach my $method ( 'GET', 'PUT' ) {
note( "Testing method: $method" );
foreach my $user ( 'demo', 'active', 'root', 'WOMBAT5', 'WAMBLE owdkmdf 5**' ) {
req( $test, 405, $user, $method, $base );
}
}
note( 'POST' );
note( '- instigate a "403 Forbidden"' );
foreach my $user ( qw( demo inactive ) ) {
t/dispatch/interval_lock.t view on Meta::CPAN
req( $test, 405, 'root', 'DELETE', $base );
req( $test, 405, 'WOMBAT5', 'DELETE', $base );
note( '=============================' );
note( '"lock/new" resource (see below for tests common to both "interval/new" and "lock/new" )' );
note( '=============================' );
$base = 'lock/new';
docu_check($test, $base);
note( 'GET, PUT -> 405' );
foreach my $method ( 'GET', 'PUT' ) {
foreach my $user ( 'demo', 'active', 'root', 'WOMBAT5', 'WAMBLE owdkmdf 5**' ) {
req( $test, 405, $user, $method, $base );
}
}
note( 'POST' );
note ('instigate a "403 Forbidden"' );
foreach my $user ( qw( demo inactive ) ) {
req( $test, 403, $user, 'POST', $base, <<"EOH" );
{ "intvl" : "[1957-01-02 00:00, 1957-01-03 24:00)" }
t/dispatch/interval_lock.t view on Meta::CPAN
note( '- lock it' );
$status = req( $test, 201, 'root', 'POST', 'lock/new', <<"EOH" );
{ "intvl" : "[1957-01-01 00:00, 1957-02-01 00:00)" }
EOH
is( $status->level, 'OK' );
is( $status->code, 'DOCHAZKA_CUD_OK' );
my $tl = $status->payload->{'lid'};
note( '- try to update it' );
dbi_err( $test, 500, 'root', 'PUT', "interval/iid/$ti",
'{ "long_desc" : "I\'m changing this interval even though it\'s locked!" }',
qr/interval is locked/ );
note( '- try to delete it' );
dbi_err( $test, 500, 'root', 'DELETE', "interval/iid/$ti", undef,
qr/interval is locked/ );
note( '- remove the lock' );
$status = req( $test, 200, 'root', 'DELETE', "lock/lid/$tl" );
is( $status->level, 'OK' );
t/dispatch/interval_lock.t view on Meta::CPAN
'"[,today)"',
'"[today,)"',
'"[now,)"',
'"[ 1958-05-27 08:00, 1958-05-27 08:00 )"',
'"( 1977-10-22 08:00, 1977-10-23 08:00 )"',
'"[ 1977-10-22 08:00, 1977-10-23 08:00 ]"',
'"( 1977-10-22 08:00, 1977-10-23 08:00 ]"',
) {
#diag( "$insert_part1$i }" );
dbi_err( $test, 500, 'root', 'POST', $insert_base, "$insert_part1$i }", $illegal );
dbi_err( $test, 500, 'root', 'PUT', $update_base, "$update_part1$i }", $illegal );
}
note( 'intervals that trigger DOCHAZKA_DBI_ERR "No dates earlier than 1892-01-01 please"' );
foreach my $i (
'"[1865-10-01 00:00, 1865-11-01 00:00)"',
'"[1891-10-01 00:00, 1892-11-01 00:00)"',
'"[1891-12-31 23:59, 1892-11-01 00:00)"',
) {
#diag( "$insert_part1$i }" );
dbi_err( $test, 500, 'root', 'POST', $insert_base, "$insert_part1$i }",
t/dispatch/interval_lock.t view on Meta::CPAN
'"[ 1958-05-27 08:00, 1958-05-27 08:03 )"',
'"[ 1958-05-27 08:00, 1958-05-27 08:04 )"',
'"[ 1958-05-27 08:01, 1958-05-27 08:05 )"',
'"[ 1958-05-27 08:02, 1958-05-27 08:05 )"',
'"[ 1958-05-27 08:03, 1958-05-27 08:05 )"',
'"[ 1958-05-27 08:04, 1958-05-27 08:05 )"',
) {
#diag( "$insert_part1$i }" );
dbi_err( $test, 500, 'root', 'POST', $insert_base, "$insert_part1$i }",
qr/upper and lower bounds of interval must be evenly divisible by 5 minutes/ );
dbi_err( $test, 500, 'root', 'PUT', $update_base, "$update_part1$i }",
qr/upper and lower bounds of interval must be evenly divisible by 5 minutes/ );
}
}
note( '=============================' );
note( '"interval/nick/:nick/:tsrange" resource' );
note( '"lock/nick/:nick/:tsrange" resource' );
note( '=============================' );
t/dispatch/interval_lock.t view on Meta::CPAN
is( $status->{'count'}, 1 );
note( "- tsranges that fail validations clause" );
foreach my $tsr ( @failing_tsranges ) {
foreach my $user ( qw( demo inactive active root ) ) {
req( $test, 400, $user, 'GET', "$base/$user/$tsr" );
}
}
}
note( 'PUT, POST' );
foreach my $method ( qw( PUT POST DELETE ) ) {
note( "Testing the $method method" );
foreach my $user ( 'demo', 'root', 'WAMBLE owdkmdf 5**' ) {
req( $test, 405, $user, $method, "$base/demo/[,)" );
}
}
#note( 'DELETE' );
#foreach my $user ( 'demo', 'root', 'WAMBLE owdkmdf 5**' ) {
# req( $test, 403, $user, 'DELETE', "$base/demo/[,)" );
#}
t/dispatch/interval_lock.t view on Meta::CPAN
is( $status->code, 'DISPATCH_RECORDS_FOUND' );
is( $status->{'count'}, 1 );
note( 'tsranges that fail validations clause' );
foreach my $tsr ( @failing_tsranges ) {
foreach my $user ( qw( demo inactive active root ) ) {
req( $test, 400, $user, 'GET', "$base/$tsr" );
}
}
note( 'PUT, POST' );
foreach my $method ( qw( PUT POST ) ) {
note( 'Testing method: $method' );
foreach my $user ( 'demo', 'root', 'WAMBLE owdkmdf 5**' ) {
req( $test, 405, $user, $method, "$base/[,)" );
}
}
#note( 'DELETE' );
#foreach my $user ( 'demo', 'root', 'WAMBLE owdkmdf 5**' ) {
# req( $test, 403, $user, 'DELETE', "$base/2/[,)" );
#}
t/dispatch/interval_lock.t view on Meta::CPAN
is( $status->code, 'DOCHAZKA_CUD_OK' );
note( '=============================' );
note( '"interval/summary/eid/:eid/:tsrange" resource' );
note( '=============================' );
$base = "interval/summary/eid";
docu_check($test, "$base/:eid/:tsrange");
note( 'PUT, POST, DELETE -> 405' );
foreach my $method ( qw( PUT POST DELETE ) ) {
foreach my $user ( qw( demo inactive active root ) ) {
req( $test, 405, $user, $method, "$base/1/[,)" );
}
}
note( "GET interval summary" );
$status = req( $test, 200, 'active', 'GET', "$base/$eid_active/[1980-01-01,1980-1-31)" );
is( $status->level, 'OK' );
is_deeply( $status->payload, {
'1980-01-15' => {},
t/dispatch/priv.t view on Meta::CPAN
$status = req( $test, 200, 'root', 'GET', "$base/1892-01-01 00:01" );
is( $status->level, 'OK' );
is( $status->code, "DISPATCH_EMPLOYEE_PRIV_AS_AT" );
is_deeply( $status->payload, {
timestamp => "1892-01-01 00:01",
nick => "root",
priv => "admin",
eid => "1"
} );
note( 'PUT, POST, DELETE -> 405' );
foreach my $base ( '/priv/self', '/priv/self/1892-01-01' ) {
req( $test, 405, 'demo', 'PUT', $base );
req( $test, 405, 'demo', 'POST', $base );
req( $test, 405, 'demo', 'DELETE', $base );
#
req( $test, 405, 'root', 'PUT', $base );
req( $test, 405, 'root', 'POST', $base );
req( $test, 405, 'root', 'DELETE', $base );
}
note( '===========================================' );
note( '"priv/eid/:eid/?:ts" resource' );
note( '===========================================' );
$base = "priv/eid";
docu_check($test, "$base/:eid/?:ts");
t/dispatch/priv.t view on Meta::CPAN
$status = req( $test, 200, 'root', 'GET', "$base/1/1892-01-01 00:01" );
is( $status->level, 'OK' );
is( $status->code, "DISPATCH_EMPLOYEE_PRIV_AS_AT" );
is_deeply( $status->payload, {
timestamp => "1892-01-01 00:01",
nick => "root",
priv => "admin",
eid => "1"
} );
note( 'PUT, POST, DELETE -> 405' );
foreach my $base ( '/priv/eid/1', '/priv/eid/1/1892-01-01' ) {
req( $test, 405, 'demo', 'PUT', $base );
req( $test, 405, 'demo', 'POST', $base );
req( $test, 405, 'demo', 'DELETE', $base );
#
req( $test, 405, 'root', 'PUT', $base );
req( $test, 405, 'root', 'POST', $base );
req( $test, 405, 'root', 'DELETE', $base );
}
note( '===========================================' );
note( '"priv/nick/:nick/?:ts" resource' );
note( '===========================================' );
$base = "priv/nick";
docu_check($test, "$base/:nick/?:ts");
t/dispatch/priv.t view on Meta::CPAN
$status = req( $test, 200, 'root', 'GET', "$base/root/1892-01-01 00:01" );
is( $status->level, 'OK' );
is( $status->code, "DISPATCH_EMPLOYEE_PRIV_AS_AT" );
is_deeply( $status->payload, {
timestamp => "1892-01-01 00:01",
nick => "root",
priv => "admin",
eid => "1"
} );
note( 'PUT, POST, DELETE -> 405' );
foreach my $user ( qw( demo root ) ) {
foreach my $method ( qw( PUT POST DELETE ) ) {
foreach my $uri ( "$base/root", "$base/root/1892-01-01" ) {
req( $test, 405, $user, $method, $uri );
}
}
}
note( 'tear down' );
$status = delete_all_attendance_data();
BAIL_OUT(0) unless $status->ok;
t/dispatch/schedule.t view on Meta::CPAN
note( 'test a non-existent SID' );
ok( ! sid_exists( $dbix_conn, 53434 ), "non-existent SID" );
note( 'now we have seven active (i.e., non-disabled) schedules' );
my $status = req( $test, 200, 'root', 'GET', $base );
is( $status->level, 'OK' );
is( $status->code, "DISPATCH_RECORDS_FOUND" );
is( $status->{'count'}, 8 );
note( 'disable one at random' );
$status = req( $test, 200, 'root', 'PUT', "schedule/sid/" . $sid_range[3], '{ "disabled":true }' );
is( $status->level, 'OK' );
is( $status->code, 'DOCHAZKA_CUD_OK' );
note( 'now we have six active (i.e., non-disabled) schedules' );
$status = req( $test, 200, 'root', 'GET', $base );
is( $status->level, 'OK' );
is( $status->code, "DISPATCH_RECORDS_FOUND" );
is( $status->{'count'}, 7 );
note( 'PUT, POST, DELETE -> 405' );
foreach my $user ( qw( demo root ) ) {
foreach my $method ( qw( PUT POST DELETE ) ) {
req( $test, 405, $user, $method, $base );
}
}
note( '===========================================' );
note( '"schedule/all/disabled" resource' );
note( '===========================================' );
$base = "schedule/all/disabled";
docu_check($test, $base);
t/dispatch/schedule.t view on Meta::CPAN
is( $status->level, 'OK' );
is( $status->code, 'DISPATCH_SCHEDULE_FOUND' );
is( $status->payload->{'scode'}, 'DEFAULT' );
note( 'count should now be one' );
$status = req( $test, 200, 'root', 'GET', 'schedule/all/disabled' );
is( $status->level, 'OK' );
is( $status->code, "DISPATCH_RECORDS_FOUND" );
is( $status->{'count'}, 1 );
note( 'PUT, POST, DELETE -> 405' );
foreach my $user ( qw( demo root ) ) {
foreach my $method ( qw( PUT POST DELETE ) ) {
req( $test, 405, $user, $method, $base );
}
}
#delete_testing_schedule( $ts_sid );
note( '===========================================' );
note( '"schedule/eid/:eid/?:ts" resource' );
note( '===========================================' );
t/dispatch/schedule.t view on Meta::CPAN
note( "GET $base/1/2999-01-33 00:-1 (valid EID, valid timestamp)" );
dbi_err( $test, 500, 'root', 'GET', "$base/1/2999-01-33 00:-1", undef,
qr#date/time field value out of range# );
note( "GET $base/1/wanger (wanger)" );
dbi_err( $test, 500, 'root', 'GET', "$base/1/wanger", undef,
qr/invalid input syntax for type timestamp/ );
note( 'PUT, POST, DELETE -> 405' );
foreach my $user ( qw( demo root ) ) {
foreach my $method ( qw( PUT POST DELETE ) ) {
foreach my $baz ( "$base/1", "$base/1/1892-01-01" ) {
req( $test, 405, $user, $method, $baz );
}
}
}
note( "delete inactive's schedule history record" );
$status = req( $test, 200, 'root', 'DELETE', "/schedule/history/shid/$ts_shid" );
is( $status->level, 'OK' );
is( $status->code, 'DOCHAZKA_CUD_OK' );
note( "delete the testing schedule itself" );
delete_testing_schedule( $ts_sid );
note( '===========================================' );
note( '"schedule/new" resource' );
note( '===========================================' );
$base = "schedule/new";
docu_check( $test, $base );
note( 'GET, PUT -> 405' );
req( $test, 405, 'demo', 'GET', $base );
req( $test, 405, 'root', 'GET', $base );
req( $test, 405, 'demo', 'PUT', $base );
req( $test, 405, 'root', 'PUT', $base );
note( "test typical workflow for this resource, $base" );
note( '- set up an array of schedule intervals for testing' );
my $intvls = { "schedule" => [
"[$tomorrow 12:30, $tomorrow 16:30)",
"[$tomorrow 08:00, $tomorrow 12:00)",
"[$today 12:30, $today 16:30)",
"[$today 08:00, $today 12:00)",
"[$yesterday 12:30, $yesterday 16:30)",
"[$yesterday 08:00, $yesterday 12:00)",
t/dispatch/schedule.t view on Meta::CPAN
$intvls = { "schedule" => [
"[$today 12:30, $today 16:30)",
"[$today 08:00, $today 12:00)",
], "scode" => 'DIFFERENT_WANGER' };
$intvls_json = JSON->new->utf8->canonical(1)->encode( $intvls );
$status = req( $test, 201, 'root', 'POST', $base, $intvls_json );
is( $status->payload->{'sid'}, $sid );
is( $status->payload->{'scode'}, 'WANGERFETZ' );
note( 'update WANGERFETZ, replacing WANGERFETZ with NULL' );
$status = req( $test, 200, 'root', 'PUT', "schedule/scode/WANGERFETZ", '{ "scode" : null }' );
is( $status->level, 'OK' );
is( $status->code, 'DOCHAZKA_CUD_OK' );
ok( exists $status->{'payload'} );
ok( exists $status->payload->{'sid'} );
ok( exists $status->payload->{'scode'} );
is( $status->payload->{'sid'}, $sid );
is( $status->payload->{'scode'}, undef );
note( 'delete WANGERFETZ, so it doesn\'t trip us up later' );
$status = req( $test, 200, 'root', 'DELETE', "schedule/sid/$sid" );
t/dispatch/schedule.t view on Meta::CPAN
note( 'valid nick, valid timestamp' );
dbi_err( $test, 500, 'root', 'GET', "$base/root/2999-01-33 00:-1", undef,
qr#date/time field value out of range# );
note( 'wanger' );
#req( $test, 404, 'root', 'GET', "$base/root/wanger" );
dbi_err( $test, 500, 'root', 'GET', "$base/root/wanger", undef,
qr/invalid input syntax for type timestamp/ );
note( 'PUT, POST, DELETE -> 405' );
foreach my $user ( qw( demo root ) ) {
foreach my $method ( qw( PUT POST DELETE ) ) {
foreach my $baz ( "$base/root", "$base/root/1892-01-01" ) {
req( $test, 405, $user, $method, $baz );
}
}
}
note( '=============================' );
note( '"schedule/self/?:ts" resource' );
note( '=============================' );
t/dispatch/schedule.t view on Meta::CPAN
qr/invalid input syntax for type timestamp/ );
note( "stupid ts" );
dbi_err( $test, 500, 'root', 'GET', "$base/ 12341 12 jjj", undef,
qr/invalid input syntax for type timestamp/ );
note( "valid nick, valid timestamp" );
dbi_err( $test, 500, 'root', 'GET', "$base/2999-01-33 00:-1", undef,
qr#date/time field value out of range# );
note( 'PUT, POST, DELETE -> 405' );
foreach my $user ( qw( demo root ) ) {
foreach my $method ( qw( PUT POST DELETE ) ) {
foreach my $baz ( $base, "$base/1892-01-01" ) {
req( $test, 405, $user, $method, $baz );
}
}
}
note( '===========================================' );
note( '"schedule/sid/:sid" resource' );
note( '===========================================' );
t/dispatch/schedule.t view on Meta::CPAN
is( $status->payload->{'disabled'}, 0 );
is( $status->payload->{'remark'}, undef );
is( $status->payload->{'schedule'}, '[{"high_dow":"FRI","high_time":"12:00","low_dow":"FRI","low_time":"08:00"},{"high_dow":"FRI","high_time":"16:30","low_dow":"FRI","low_time":"12:30"},{"high_dow":"SAT","high_time":"12:00","low_dow":"SAT","low_time"...
ok( $status->payload->{'sid'} > 0 );
is( $status->payload->{'sid'}, $sid );
note( 'POST -> 405' );
req( $test, 405, 'demo', 'POST', "$base/1" );
req( $test, 405, 'root', 'POST', "$base/1" );
note( 'PUT' );
note( 'add a remark to the schedule' );
req( $test, 403, 'demo', 'PUT', "$base/$sid" );
$status = req( $test, 200, 'root', 'PUT', "$base/$sid", '{ "remark" : "foobar" }' );
is( $status->level, 'OK' );
is( $status->code, 'DOCHAZKA_CUD_OK' );
ok( exists( $status->{'payload'} ) );
ok( defined( $status->payload ) );
ok( exists( $status->{'payload'}->{'remark'} ) );
ok( defined( $status->{'payload'}->{'remark'} ) );
is( $status->{'payload'}->{'remark'}, "foobar" );
note( 'verify with GET' );
$status = req( $test, 200, 'root', 'GET', "$base/$sid" );
is( $status->level, 'OK' );
is( $status->code, 'DISPATCH_SCHEDULE_FOUND' );
is( $status->payload->{'remark'}, 'foobar' );
note( 'disable the schedule in the wrong way' );
dbi_err( $test, 500, 'root', 'PUT', "$base/$sid", '{ "pebble" : [1,2,3], "disabled":"hoogar" }',
qr/invalid input syntax for type boolean/ );
note( 'disable the schedule in the right way' );
$status = req( $test, 200, 'root', 'PUT', "$base/$sid", '{ "pebble" : [1,2,3], "disabled":true }' );
is( $status->level, 'OK' );
is( $status->code, 'DOCHAZKA_CUD_OK' );
note( 'add an scode' );
req( $test, 403, 'demo', 'PUT', "$base/$sid" );
$status = req( $test, 200, 'root', 'PUT', "$base/$sid", '{ "scode" : "bazblare" }' );
is( $status->level, 'OK' );
is( $status->code, 'DOCHAZKA_CUD_OK' );
ok( exists( $status->{'payload'} ) );
ok( defined( $status->payload ) );
ok( exists( $status->{'payload'}->{'scode'} ) );
ok( defined( $status->{'payload'}->{'scode'} ) );
is( $status->{'payload'}->{'scode'}, "bazblare" );
note( 'verify with GET' );
$status = req( $test, 200, 'root', 'GET', "$base/$sid" );
t/dispatch/schedule.t view on Meta::CPAN
is( $status->code, 'DISPATCH_SCHEDULE_FOUND' );
is( $status->payload->{'disabled'}, 0 );
is( $status->payload->{'remark'}, undef );
is( $status->payload->{'schedule'}, '[{"high_dow":"FRI","high_time":"12:00","low_dow":"FRI","low_time":"08:00"},{"high_dow":"FRI","high_time":"16:30","low_dow":"FRI","low_time":"12:30"},{"high_dow":"SAT","high_time":"12:00","low_dow":"SAT","low_time"...
is( $status->payload->{'scode'}, $scode );
note( 'POST -> 405' );
req( $test, 405, 'demo', 'POST', "$base/1" );
req( $test, 405, 'root', 'POST', "$base/1" );
note( 'PUT' );
note( 'add a remark to the schedule' );
req( $test, 403, 'demo', 'PUT', "$base/$scode" );
$status = req( $test, 200, 'root', 'PUT', "$base/$scode", '{ "remark" : "foobar" }' );
is( $status->level, 'OK' );
is( $status->code, 'DOCHAZKA_CUD_OK' );
ok( exists( $status->{'payload'} ) );
ok( defined( $status->payload ) );
ok( exists( $status->{'payload'}->{'remark'} ) );
ok( defined( $status->{'payload'}->{'remark'} ) );
is( $status->{'payload'}->{'remark'}, "foobar" );
note( 'verify with GET' );
$status = req( $test, 200, 'root', 'GET', "$base/$scode" );
is( $status->level, 'OK' );
is( $status->code, 'DISPATCH_SCHEDULE_FOUND' );
is( $status->payload->{'remark'}, 'foobar' );
note( 'disable the schedule in the wrong way' );
dbi_err( $test, 500, 'root', 'PUT', "$base/$scode", '{ "pebble" : [1,2,3], "disabled":"hoogar" }',
qr/invalid input syntax for type boolean/ );
note( 'disable the schedule in the right way' );
$status = req( $test, 200, 'root', 'PUT', "$base/$scode", '{ "pebble" : [1,2,3], "disabled":true }' );
is( $status->level, 'OK' );
is( $status->code, 'DOCHAZKA_CUD_OK' );
note( 'change the scode' );
req( $test, 403, 'demo', 'PUT', "$base/$scode" );
$status = req( $test, 200, 'root', 'PUT', "$base/$scode", '{ "scode" : "bazblare" }' );
is( $status->level, 'OK' );
is( $status->code, 'DOCHAZKA_CUD_OK' );
ok( exists( $status->{'payload'} ) );
ok( defined( $status->payload ) );
ok( exists( $status->{'payload'}->{'scode'} ) );
ok( defined( $status->{'payload'}->{'scode'} ) );
is( $status->{'payload'}->{'scode'}, "bazblare" );
note( 'verify with GET' );
$status = req( $test, 200, 'root', 'GET', "$base/bazblare" );
t/dispatch/supervisor.t view on Meta::CPAN
my $app = initialize_regression_test();
note( 'instantiate Plack::Test object');
my $test = Plack::Test->create( $app );
note( 'create a testing schedule' );
my $sid = create_testing_schedule( $test );
note( 'create testing user boss' );
my $boss_eid = create_active_employee( $test );
req( $test, 200, 'root', 'PUT', "employee/eid/$boss_eid", "{ \"nick\" : \"boss\" }" );
req( $test, 200, 'root', 'PUT', "employee/eid/$boss_eid", "{ \"password\" : \"boss\" }" );
note( 'create testing user peon' );
my $peon_eid = create_active_employee( $test );
req( $test, 200, 'root', 'PUT', "employee/eid/$peon_eid", "{ \"nick\" : \"peon\" }" );
req( $test, 200, 'root', 'PUT', "employee/eid/$peon_eid", "{ \"supervisor\" : $boss_eid }" );
req( $test, 200, 'root', 'PUT', "employee/eid/$peon_eid", "{ \"password\" : \"peon\" }" );
note( 'create testing user active' );
my $active_eid = create_active_employee( $test );
note( 'give \'peon\' a schedule as of 1957-01-01 00:00 so he can enter some attendance intervals' );
my @shid_for_deletion;
my $status = req( $test, 201, 'root', 'POST', "schedule/history/nick/peon", <<"EOH" );
{ "sid" : $sid, "effective" : "1957-01-01 00:00" }
EOH
is( $status->level, "OK" );
t/dispatch/top.t view on Meta::CPAN
note( '- as demo' );
my $status = req( $test, 200, 'demo', 'GET', '/' );
is( $status->level, 'OK' );
is( $status->code, 'DISPATCH_NOOP' );
note( '- as root' );
$status = req( $test, 200, 'root', 'GET', '/' );
is( $status->level, 'OK' );
is( $status->code, 'DISPATCH_NOOP' );
note( 'PUT ""' );
note( '- as demo' );
$status = req( $test, 200, 'demo', 'PUT', '/' );
is( $status->level, 'OK' );
is( $status->code, 'DISPATCH_NOOP' );
note( 'PUT ""' );
note( '- as root' );
$status = req( $test, 200, 'root', 'PUT', '/' );
is( $status->level, 'OK' );
is( $status->code, 'DISPATCH_NOOP' );
note( 'POST ""' );
note( '- as demo' );
$status = req( $test, 200, 'demo', 'POST', '/' );
is( $status->level, 'OK' );
is( $status->code, 'DISPATCH_NOOP' );
note( 'POST ""' );
t/dispatch/top.t view on Meta::CPAN
is( $status->level, 'OK' );
is( $status->code, 'DISPATCH_BUGREPORT' );
ok( exists $status->payload->{'report_bugs_to'} );
note( '- as root' );
$status = req( $test, 200, 'root', 'GET', 'bugreport' );
is( $status->level, 'OK' );
is( $status->code, 'DISPATCH_BUGREPORT' );
ok( exists $status->payload->{'report_bugs_to'} );
note( 'PUT bugreport -> 405' );
req( $test, 405, 'demo', 'PUT', 'bugreport' );
req( $test, 405, 'root', 'PUT', 'bugreport' );
note( 'POST bugreport -> 405');
req( $test, 405, 'demo', 'PUT', 'bugreport' );
req( $test, 405, 'root', 'PUT', 'bugreport' );
note( 'DELETE bugreport -> 405' );
req( $test, 405, 'demo', 'DELETE', 'bugreport' );
req( $test, 405, 'root', 'DELETE', 'bugreport' );
my $eid_of_inactive = create_inactive_employee( $test );
my $eid_of_active = create_active_employee( $test );
t/dispatch/top.t view on Meta::CPAN
note( '- as demo' );
req( $test, 403, 'demo', 'GET', $base );
note( '- as inactive, active, and root' );
foreach my $user ( 'inactive', 'active', 'root' ) {
$status = req( $test, 200, $user, 'GET', $base );
is( $status->level, 'OK' );
is( $status->code, 'DOCHAZKA_DBSTATUS' );
}
note( 'PUT, POST, DELETE -> 405' );
foreach my $method ( 'PUT', 'POST', 'DELETE' ) {
foreach my $user ( qw( demo inactive active root ) ) {
req( $test, 405, $user, $method, $base );
}
}
note( '=============================' );
note( '"docu" resource' );
note( '=============================' );
t/dispatch/top.t view on Meta::CPAN
note( '"docu/html" resource' );
note( '=============================' );
$base = 'docu/html';
docu_check($test, $base);
note( 'GET docu -> 405' );
req( $test, 405, 'demo', 'GET', $base );
req( $test, 405, 'root', 'GET', $base );
note( 'PUT docu -> 405' );
req( $test, 405, 'demo', 'PUT', $base );
req( $test, 405, 'root', 'PUT', $base );
note( 'POST docu' );
note( '- be nice' );
$status = req( $test, 200, 'demo', 'POST', $base, '"echo"' );
is( $status->level, 'OK' );
is( $status->code, 'DISPATCH_ONLINE_DOCUMENTATION' );
ok( exists $status->payload->{'resource'} );
is( $status->payload->{'resource'}, 'echo' );
ok( exists $status->payload->{'documentation'} );
my $docustr = $status->payload->{'documentation'};
t/dispatch/top.t view on Meta::CPAN
note( '=============================' );
note( '"echo" resource' );
note( '=============================' );
docu_check($test, "echo");
note( 'GET echo -> 405' );
$status = req( $test, 405, 'demo', 'GET', 'echo' );
$status = req( $test, 405, 'root', 'GET', 'echo' );
note( 'PUT echo -> 405' );
$status = req( $test, 405, 'demo', 'PUT', 'echo' );
$status = req( $test, 405, 'root', 'PUT', 'echo' );
note( 'POST echo' );
note( '- as root, with legal JSON' );
$status = req( $test, 200, 'root', 'POST', 'echo', '{ "username": "foo", "password": "bar" }' );
is( $status->level, 'OK' );
is( $status->code, 'ECHO_REQUEST_ENTITY' );
ok( exists $status->payload->{'username'} );
is( $status->payload->{'username'}, 'foo' );
ok( exists $status->payload->{'password'} );
is( $status->payload->{'password'}, 'bar' );
t/dispatch/top.t view on Meta::CPAN
note( 'DELETE echo -> 405' );
$status = req( $test, 405, 'demo', 'DELETE', 'echo' );
$status = req( $test, 405, 'root', 'DELETE', 'echo' );
note( '=============================' );
note( '"forbidden" resource' );
note( '=============================' );
docu_check($test, "forbidden");
foreach my $user ( qw( demo root ) ) {
foreach my $method ( qw( GET PUT POST DELETE ) ) {
$status = req( $test, 403, 'demo', 'GET', 'forbidden' );
}
}
note( '=============================' );
note( '"param/:type/:param" resource' );
note( '=============================' );
$base = "param";
docu_check($test, "param/:type/:param");
note( 'POST' );
is( $meta->META_DOCHAZKA_UNIT_TESTING, 1 );
$status = req( $test, 200, 'root', 'PUT', "$base/meta/META_DOCHAZKA_UNIT_TESTING", '"foobar"' );
is( $status->level, 'OK' );
is( $status->code, 'CELL_OVERWRITE_META_PARAM' );
is( $meta->META_DOCHAZKA_UNIT_TESTING, 'foobar' );
$status = req( $test, 200, 'root', 'PUT', "$base/meta/META_DOCHAZKA_UNIT_TESTING", '1' );
is( $status->level, 'OK' );
is( $status->code, 'CELL_OVERWRITE_META_PARAM' );
is( $meta->META_DOCHAZKA_UNIT_TESTING, 1 );
note( 'GET' );
note( 'non-existent and otherwise bogus parameters' );
foreach my $base ( "$base/meta", "$base/site" ) {
foreach my $user ( qw( demo root ) ) {
# these are bogus in that the resource does not exist
t/dispatch/top.t view on Meta::CPAN
$status = req( $test, 200, 'demo', 'GET', 'session' );
is( $status->level, 'OK' );
is( $status->code, 'DISPATCH_SESSION_DATA' );
ok( exists $status->payload->{'session'} );
note( 'N.B.: no session data when running via Plack::Test' );
#ok( exists $status->payload->{'session'}->{'ip_addr'} );
#ok( exists $status->payload->{'session'}->{'last_seen'} );
#ok( exists $status->payload->{'session'}->{'eid'} );
note( 'PUT, POST, DELETE -> 405' );
foreach my $user ( qw( demo root ) ) {
foreach my $method ( qw( PUT POST DELETE ) ) {
$status = req( $test, 405, $user, $method, 'session' );
}
}
note( '=============================' );
note( '"version" resource' );
note( '=============================' );
docu_check($test, "version");
t/dispatch/top.t view on Meta::CPAN
$status = req( $test, 200, 'demo', 'GET', 'version' );
is( $status->level, 'OK' );
is( $status->code, 'DISPATCH_VERSION' );
ok( exists $status->payload->{'version'} );
$status = req( $test, 200, 'root', 'GET', 'version' );
is( $status->level, 'OK' );
is( $status->code, 'DISPATCH_VERSION' );
ok( exists $status->payload->{'version'} );
note( 'PUT, POST, DELETE version -> 405' );
foreach my $user ( qw( demo root ) ) {
foreach my $method ( qw( PUT POST DELETE ) ) {
$status = req( $test, 405, $user, $method, 'version' );
}
}
note( '=============================' );
note( '"whoami" resource' );
note( '=============================' );
docu_check($test, "whoami");
t/dispatch/top.t view on Meta::CPAN
$status = req( $test, 200, 'root', 'GET', 'whoami' );
is( $status->level, 'OK' );
ok( $status->code, 'DISPATCH_RECORDS_FOUND' );
ok( defined $status->payload );
ok( exists $status->payload->{'eid'} );
ok( exists $status->payload->{'nick'} );
ok( not exists $status->payload->{'priv'} );
is( $status->payload->{'nick'}, 'root' );
note( 'PUT, POST, DELETE whoami -> 405' );
foreach my $user ( qw( demo root ) ) {
foreach my $method ( qw( PUT POST DELETE ) ) {
$status = req( $test, 405, $user, $method, 'whoami' );
}
}
delete_employee_by_nick( $test, 'active' );
delete_employee_by_nick( $test, 'inactive' );
done_testing;
ok( $status->not_ok );
note( '####################################################' );
note( 'DISPATCH TESTS' );
note( '####################################################' );
note( "GET employee/nick/$noex/ldap returns 404" );
req( $test, 404, 'root', 'GET', "employee/nick/$noex/ldap" );
note( "PUT employee/nick/$noex/ldap returns 404" );
req( $test, 404, 'root', 'PUT', "employee/nick/$noex/ldap" );
note( "GET employee/nick/$ex/ldap returns 200" );
$status = req( $test, 200, 'root', 'GET', "employee/nick/$ex/ldap" );
is( $status->level, 'OK' );
ok( $status->payload, "There is a payload" );
map {
my $value = $status->payload->{$_};
ok( $value, "$_ property has value $value" );
} @props;
$emp->delete( $faux_context ) if $status->ok;
note( 'Assert that LDAP user does not exist in Dochazka database' );
$status = App::Dochazka::REST::Model::Employee->load_by_nick( $dbix_conn, $ex );
is( $status->level, 'NOTICE' );
is( $status->code, 'DISPATCH_NO_RECORDS_FOUND', "nick doesn't exist" );
is( $status->{'count'}, 0, "nick doesn't exist" );
ok( ! exists $status->{'payload'} );
ok( ! defined( $status->payload ) );
note( "PUT employee/nick/$ex/ldap" );
$status = req( $test, 200, 'root', 'PUT', "employee/nick/$ex/ldap" );
is( $status->level, 'OK' );
is( $status->code, 'DOCHAZKA_CUD_OK' );
note( "Assert that $ex employee exists in Dochazka database" );
$status = App::Dochazka::REST::Model::Employee->load_by_nick( $dbix_conn, $ex );
is( $status->code, 'DISPATCH_RECORDS_FOUND', "Nick $ex exists" );
$emp = $status->payload;
is( $emp->nick, $ex, "Nick is the right string" );
note( "Assert that mapped properties have values" );
is( $emp->fullname, undef );
$status = $emp->update( $faux_context );
ok( $status->ok );
note( "Assert that fullname field is empty" );
$status = req( $test, 200, 'root', 'GET', "employee/nick/$ex" );
is( $status->level, 'OK' );
is( $status->payload->{fullname}, undef );
note( "Set password of employee $ex to \"$ex\"" );
$status = req( $test, 200, 'root', 'PUT', "employee/nick/$ex",
"{\"password\":\"$ex\"}" );
is( $status->level, 'OK' );
note( "PUT employee/nick/$ex/ldap" );
$status = req( $test, 200, $ex, 'PUT', "employee/nick/$ex/ldap" );
is( $status->level, 'OK' );
note( "Assert that fullname field is populated as expected" );
$status = req( $test, 200, 'root', 'GET', "employee/nick/$ex" );
is( $status->level, 'OK' );
is( $status->payload->{fullname}, $saved_fullname );
note( "Cleanup" );
$status = delete_all_attendance_data();
BAIL_OUT(0) unless $status->ok;