File Coverage

blib/lib/App/Dochazka/REST/ResourceDefs.pm
Criterion Covered Total %
statement 12 14 85.7
branch 0 2 0.0
condition n/a
subroutine 4 5 80.0
pod 1 1 100.0
total 17 22 77.2


line stmt bran cond sub pod time code
1             # *************************************************************************
2             # Copyright (c) 2014-2017, SUSE LLC
3             #
4             # All rights reserved.
5             #
6             # Redistribution and use in source and binary forms, with or without
7             # modification, are permitted provided that the following conditions are met:
8             #
9             # 1. Redistributions of source code must retain the above copyright notice,
10             # this list of conditions and the following disclaimer.
11             #
12             # 2. Redistributions in binary form must reproduce the above copyright
13             # notice, this list of conditions and the following disclaimer in the
14             # documentation and/or other materials provided with the distribution.
15             #
16             # 3. Neither the name of SUSE LLC nor the names of its contributors may be
17             # used to endorse or promote products derived from this software without
18             # specific prior written permission.
19             #
20             # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21             # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22             # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23             # ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
24             # LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25             # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26             # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27             # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28             # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29             # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30             # POSSIBILITY OF SUCH DAMAGE.
31             # *************************************************************************
32              
33             # ------------------------
34             # The purpose of this package is to hold all the resource definitions
35             # and provide a hook for loading them.
36             # ------------------------
37              
38             package App::Dochazka::REST::ResourceDefs;
39              
40 41     41   313 use strict;
  41         108  
  41         1203  
41 41     41   226 use warnings;
  41         110  
  41         1123  
42              
43 41     41   229 use App::CELL qw( $log );
  41         120  
  41         3418  
44 41     41   19419 use Web::MREST::InitRouter;
  41         7715293  
  41         138662  
45              
46             my $defs;
47             my $tsrange_validation = qr/^[[(].*,.*[])]$/;
48             my $ts_validation = qr/^(\"|\')?\d+-\d+-\d+( +\d+:\d+(:\d+)?)?(\"|\')?$/;
49             my $term_validation = qr/^[[:alnum:]_][[:alnum:]_-]*$/;
50             my $date_validation = qr/^\d{2,4}-\d{1,2}-\d{1,2}$/;
51             my $priv_validation = qr/^(admin)|(active)|(inactive)|(passerby)$/i;
52             my $psqlint_validation = qr/^[[:alnum:] ]+$/;
53              
54              
55              
56              
57              
58             =head1 NAME
59              
60             App::Dochazka::REST::ResourceDefs - Resource definitions
61              
62              
63              
64              
65             =head1 DESCRIPTION
66              
67             The purpose of this package is to hold all the resource definitions
68             and provide a hook for loading them.
69              
70             =cut
71              
72              
73              
74              
75             =head1 RESOURCE DEFINITIONS
76              
77             =head2 Top-level resources
78              
79             =cut
80              
81             $defs->{'top'} = {
82              
83             # root resource
84             '/' => {
85             handler => 'handler_noop',
86             acl_profile => 'passerby',
87             description => 'The root resource',
88             documentation => <<'EOH',
89             =pod
90              
91             This resource is the parent of all resources that do not specify
92             a parent in their resource definition.
93             EOH
94             },
95              
96             # bugreport
97             'bugreport' =>
98             {
99             parent => '/',
100             handler => {
101             GET => 'handler_bugreport',
102             },
103             acl_profile => 'passerby',
104             cli => 'bugreport',
105             description => 'Display instructions for reporting bugs in Web::MREST',
106             documentation => <<'EOH',
107             =pod
108              
109             Returns a JSON structure containing instructions for reporting bugs.
110             EOH
111             },
112              
113             # configinfo
114             'configinfo' =>
115             {
116             parent => '/',
117             handler => {
118             GET => 'handler_configinfo',
119             },
120             acl_profile => 'passerby',
121             cli => 'configinfo',
122             description => 'Display information about Web::MREST configuration',
123             documentation => <<'EOH',
124             =pod
125              
126             Returns a list of directories that were scanned for configuration files.
127             EOH
128             },
129              
130             # dbstatus
131             'dbstatus' => {
132             parent => '/',
133             handler => {
134             GET => 'handler_dbstatus',
135             },
136             acl_profile => 'inactive',
137             cli => 'dbstatus',
138             description => 'Display status of database connection',
139             documentation => <<'EOH',
140             =pod
141              
142             This resource checks the employee's database connection and reports on its status.
143             The result - either "UP" or "DOWN" - will be encapsulated in a payload like this:
144              
145             { "dbstatus" : "UP" }
146              
147             Each employee gets her own database connection when she logs in to Dochazka.
148             Calling this resource causes the server to execute a 'ping' on the connection.
149             If the ping test fails, the server will attempt to open a new connection. Only
150             if this, too, fails will "DOWN" be returned.
151             EOH
152             },
153              
154             # docu
155             'docu' =>
156             {
157             parent => '/',
158             handler => 'handler_noop',
159             acl_profile => 'passerby',
160             cli => 'docu',
161             description => 'Access on-line documentation (via POST to an appropriate subresource)',
162             documentation => <<'EOH',
163             =pod
164              
165             This resource provides access to on-line documentation through its
166             subresources: 'docu/pod', 'docu/html', and 'docu/text'.
167              
168             To get documentation on a resource, send a POST reqeuest for one of
169             these subresources, including the resource name in the request
170             entity as a bare JSON string (i.e. in double quotes).
171             EOH
172             },
173              
174             # docu/pod
175             'docu/pod' =>
176             {
177             parent => 'docu',
178             handler => {
179             POST => 'handler_docu',
180             },
181             acl_profile => 'passerby',
182             cli => 'docu pod $RESOURCE',
183             description => 'Display POD documentation of a resource',
184             documentation => <<'EOH',
185             =pod
186            
187             This resource provides access to on-line help documentation in POD format.
188             It expects to find a resource name (e.g. "employee/eid/:eid" including the
189             double-quotes, and without leading or trailing slash) in the request body. It
190             returns a string containing the POD source code of the resource documentation.
191             EOH
192             },
193              
194             # docu/html
195             'docu/html' =>
196             {
197             parent => 'docu',
198             handler => {
199             POST => 'handler_docu',
200             },
201             acl_profile => 'passerby',
202             cli => 'docu html $RESOURCE',
203             description => 'Display HTML documentation of a resource',
204             documentation => <<'EOH',
205             =pod
206              
207             This resource provides access to on-line help documentation. It expects to find
208             a resource name (e.g. "employee/eid/:eid" including the double-quotes, and without
209             leading or trailing slash) in the request body. It generates HTML from the
210             resource documentation's POD source code.
211             EOH
212             },
213              
214             # docu/text
215             'docu/text' =>
216             {
217             parent => 'docu',
218             handler => {
219             POST => 'handler_docu',
220             },
221             acl_profile => 'passerby',
222             cli => 'docu text $RESOURCE',
223             description => 'Display resource documentation in plain text',
224             documentation => <<'EOH',
225             =pod
226              
227             This resource provides access to on-line help documentation. It expects to find
228             a resource name (e.g. "employee/eid/:eid" including the double-quotes, and without
229             leading or trailing slash) in the request body. It returns a plain text rendering
230             of the POD source of the resource documentation.
231             EOH
232             },
233              
234             # echo
235             'echo' =>
236             {
237             parent => '/',
238             handler => {
239             POST => 'handler_echo',
240             },
241             acl_profile => 'admin',
242             cli => 'echo [$JSON]',
243             description => 'Echo the request body',
244             documentation => <<'EOH',
245             =pod
246              
247             This resource simply takes whatever content body was sent and echoes it
248             back in the response body.
249             EOH
250             },
251              
252             # forbidden
253             'forbidden' =>
254             {
255             parent => '/',
256             handler => 'handler_forbidden',
257             acl_profile => 'forbidden',
258             cli => 'forbidden',
259             description => 'A resource that is forbidden to all',
260             documentation => <<'EOH',
261             =pod
262              
263             This resource returns 403 Forbidden for all allowed methods, regardless of user.
264              
265             Implementation note: this can be accomplished for any resource by including an 'acl_profile'
266             property with the value 'undef' or any unrecognized privilege level string (like "foobar").
267             EOH
268             },
269              
270             # /holiday/:tsrange
271             'holiday/:tsrange' =>
272             {
273             parent => '/',
274             handler => {
275             'GET' => 'handler_holiday_tsrange',
276             },
277             acl_profile => 'passerby',
278             cli => 'handler $TSRANGE',
279             validations => {
280             'tsrange' => $tsrange_validation,
281             },
282             description => 'Determine holidays and weekends within a tsrange',
283             documentation => <<'EOH',
284             =pod
285              
286             Used with GET. For a given tsrange, return an object keyed on dates. The for
287             each date key is itself an object. If a date falls on a weekend, the value will
288             contain a subobject { "weekend": true }. If a date is a holiday, it will
289             contain a subobject { "holiday": true }. If a date is neither a weekend nor a
290             holiday, the value will be an empty object.
291             EOH
292             },
293              
294             # noop
295             'noop' =>
296             {
297             parent => '/',
298             handler => 'handler_noop',
299             acl_profile => 'passerby',
300             cli => 'noop',
301             description => 'A resource that does nothing',
302             documentation => <<'EOH',
303             =pod
304              
305             Regardless of anything, this resource does nothing at all.
306             EOH
307             },
308              
309             # param/:type/:param
310             'param/:type/:param' =>
311             {
312             parent => '/',
313             handler => {
314             'GET' => 'handler_param',
315             'PUT' => 'handler_param',
316             'DELETE' => 'handler_param',
317             },
318             acl_profile => 'admin',
319             cli => {
320             'GET' => 'param $TYPE $PARAM',
321             'PUT' => 'param $TYPE $PARAM $VALUE',
322             'DELETE' => 'param $TYPE $PARAM',
323             },
324             description => {
325             'GET' => 'Display value of a meta/core/site parameter',
326             'PUT' => 'Set value of a parameter (meta only)',
327             'DELETE' => 'Delete a parameter (meta only)',
328             },
329             documentation => <<'EOH',
330             =pod
331              
332             This resource can be used to look up (GET) meta, core, and site parameters,
333             as well as to set (PUT) and delete (DELETE) meta parameters.
334             EOH
335             validations => {
336             'type' => qr/^(meta)|(core)|(site)$/,
337             'param' => qr/^[[:alnum:]_][[:alnum:]_-]+$/,
338             },
339             },
340              
341             # session
342             'session' =>
343             {
344             parent => '/',
345             handler => {
346             GET => 'handler_session',
347             },
348             acl_profile => 'passerby',
349             cli => 'session',
350             description => 'Display the current session',
351             documentation => <<'EOH',
352             =pod
353              
354             Dumps the current session data (server-side).
355             EOH
356             },
357              
358             # session/terminate
359             'session/terminate' =>
360             {
361             parent => '/session',
362             handler => {
363             POST => 'handler_session_terminate',
364             },
365             acl_profile => 'passerby',
366             cli => 'session terminate',
367             description => 'Terminate the current session',
368             documentation => <<'EOH',
369             =pod
370              
371             Terminates the current session
372             EOH
373             },
374              
375             # version
376             'version' =>
377             {
378             parent => '/',
379             handler => {
380             GET => 'handler_version',
381             },
382             acl_profile => 'passerby',
383             cli => 'version',
384             description => 'Display application name and version',
385             documentation => <<'EOH',
386             =pod
387              
388             Shows the software version running on the present instance. The version displayed
389             is taken from the C<$VERSION> package variable of the package specified in the
390             C<MREST_APPLICATION_MODULE> site parameter.
391             EOH
392             },
393              
394             # /whoami
395             'whoami' => {
396             parent => '/',
397             handler => {
398             GET => 'handler_whoami',
399             },
400             acl_profile => 'passerby',
401             cli => 'whoami',
402             description => 'Display the current employee (i.e. the one we authenticated with)',
403             documentation => <<'EOH',
404             =pod
405              
406             Displays the profile of the currently logged-in employee
407             EOH
408             },
409              
410             };
411              
412             =head2 Activity resources
413              
414             =cut
415              
416             $defs->{'activity'} = {
417              
418             # /activity
419             'activity' =>
420             {
421             parent => '/',
422             handler => 'handler_noop',
423             acl_profile => 'passerby',
424             cli => 'activity',
425             description => 'Parent for activity resources',
426             documentation => <<'EOH',
427             =pod
428              
429             Parent for activity resources
430             EOH
431             },
432              
433             # /activity/aid
434             'activity/aid' =>
435             {
436             parent => 'activity',
437             handler => {
438             POST => 'handler_post_activity_aid',
439             },
440             acl_profile => 'admin',
441             cli => 'activity aid',
442             description => 'Update an existing activity object via POST request (AID must be included in request body)',
443             documentation => <<'EOH',
444             =pod
445              
446             Enables existing activity objects to be updated by sending a POST request to
447             the REST server. Along with the properties to be modified, the request body
448             must include an 'aid' property, the value of which specifies the AID to be
449             updated.
450             EOH
451             },
452              
453             # /activity/aid/:aid
454             'activity/aid/:aid' =>
455             {
456             parent => 'activity',
457             handler => {
458             GET => 'handler_activity_aid',
459             PUT => 'handler_activity_aid',
460             DELETE => 'handler_activity_aid',
461             },
462             acl_profile => {
463             GET => 'active',
464             PUT => 'admin',
465             DELETE => 'admin',
466             },
467             cli => 'activity aid $AID',
468             validations => {
469             'aid' => 'Int',
470             },
471             description => 'GET, PUT, or DELETE an activity object by its AID',
472             documentation => <<'EOH',
473             =pod
474              
475             This resource allows the user to GET, PUT, or DELETE an activity object by its
476             AID.
477              
478             =over
479              
480             =item * GET
481              
482             Retrieves an activity object by its AID.
483              
484             =item * PUT
485              
486             Updates the activity object whose AID is specified by the ':aid' URI parameter.
487             The fields to be updated and their new values should be sent in the request
488             body, e.g., like this:
489              
490             { "long_desc" : "new description", "disabled" : "f" }
491              
492             =item * DELETE
493              
494             Deletes the activity object whose AID is specified by the ':aid' URI parameter.
495             This will work only if nothing in the database refers to this activity.
496              
497             =back
498             EOH
499             },
500              
501             # /activity/all
502             'activity/all' =>
503             {
504             parent => 'activity',
505             handler => {
506             GET => 'handler_get_activity_all',
507             },
508             acl_profile => 'passerby',
509             cli => 'activity all',
510             description => 'Retrieve all activity objects (excluding disabled ones)',
511             documentation => <<'EOH',
512             =pod
513              
514             Retrieves all activity objects in the database (excluding disabled activities).
515             EOH
516             },
517              
518             # /activity/all/disabled
519             'activity/all/disabled' =>
520             {
521             parent => 'activity/all',
522             handler => {
523             GET => 'handler_get_activity_all_disabled',
524             },
525             acl_profile => 'admin',
526             cli => 'activity all disabled',
527             description => 'Retrieve all activity objects, including disabled ones',
528             documentation => <<'EOH',
529             =pod
530              
531             Retrieves all activity objects in the database (including disabled activities).
532             EOH
533             },
534              
535             # /activity/code
536             'activity/code' =>
537             {
538             parent => 'activity',
539             handler => {
540             POST => 'handler_post_activity_code',
541             },
542             acl_profile => 'admin',
543             cli => 'activity aid',
544             description => 'Update an existing activity object via POST request (activity code must be included in request body)',
545             documentation => <<'EOH',
546             =pod
547              
548             This resource enables existing activity objects to be updated, and new
549             activity objects to be inserted, by sending a POST request to the REST server.
550             Along with the properties to be modified/inserted, the request body must
551             include an 'code' property, the value of which specifies the activity to be
552             updated.
553             EOH
554             },
555              
556             # /activity/code/:code
557             'activity/code/:code' =>
558             {
559             parent => 'activity',
560             handler => {
561             GET => 'handler_get_activity_code',
562             PUT => 'handler_put_activity_code',
563             DELETE => 'handler_delete_activity_code',
564             },
565             acl_profile => {
566             GET => 'passerby',
567             PUT => 'admin',
568             DELETE => 'admin',
569             },
570             cli => 'activity code $CODE',
571             validations => {
572             'code' => qr/^[[:alnum:]_][[:alnum:]_-]+$/,
573             },
574             description => 'GET, PUT, or DELETE an activity object by its code',
575             documentation => <<'EOH',
576             =pod
577              
578             With this resource, a user can GET, PUT, or DELETE an activity object by its
579             code.
580              
581             =over
582              
583             =item * GET
584              
585             Retrieves an activity object by its code.
586              
587             =item * PUT
588              
589             Inserts new or updates existing activity object whose code is specified by the
590             ':code' URI parameter. The fields to be updated and their new values should be
591             sent in the request body, e.g., like this:
592              
593             { "long_desc" : "new description", "disabled" : "f" }
594              
595             =item * DELETE
596              
597             Deletes an activity object by its code whose code is specified by the ':code'
598             URI parameter. This will work only if nothing in the database refers to this
599             activity.
600              
601             =back
602             EOH
603             },
604              
605             };
606              
607              
608             =head2 Component resources
609              
610             =cut
611              
612             $defs->{'component'} = {
613              
614             # /component
615             'component' =>
616             {
617             parent => '/',
618             handler => 'handler_noop',
619             acl_profile => 'passerby',
620             cli => 'component',
621             description => 'Parent for component resources',
622             documentation => <<'EOH',
623             =pod
624              
625             Parent for component resources
626             EOH
627             },
628              
629             # /component/all
630             'component/all' =>
631             {
632             parent => 'component',
633             handler => {
634             GET => 'handler_get_component_all',
635             },
636             acl_profile => 'admin',
637             cli => 'component all',
638             description => 'Retrieve all component objects',
639             documentation => <<'EOH',
640             =pod
641              
642             Retrieves all component objects in the database.
643             EOH
644             },
645              
646             # /component/cid
647             'component/cid' =>
648             {
649             parent => 'component',
650             handler => {
651             POST => 'handler_post_component_cid',
652             },
653             acl_profile => 'admin',
654             cli => 'component cid',
655             description => 'Update an existing component object via POST request (cid must be included in request body)',
656             documentation => <<'EOH',
657             =pod
658              
659             Enables existing component objects to be updated by sending a POST request to
660             the REST server. Along with the properties to be modified, the request body
661             must include an 'cid' property, the value of which specifies the cid to be
662             updated.
663             EOH
664             },
665              
666             # /component/cid/:cid
667             'component/cid/:cid' =>
668             {
669             parent => 'component',
670             handler => {
671             GET => 'handler_component_cid',
672             PUT => 'handler_component_cid',
673             DELETE => 'handler_component_cid',
674             },
675             acl_profile => 'admin',
676             cli => 'component cid $cid',
677             validations => {
678             'cid' => 'Int',
679             },
680             description => 'GET, PUT, or DELETE an component object by its cid',
681             documentation => <<'EOH',
682             =pod
683              
684             This resource allows the user to GET, PUT, or DELETE an component object by its
685             cid.
686              
687             =over
688              
689             =item * GET
690              
691             Retrieves an component object by its cid.
692              
693             =item * PUT
694              
695             Updates the component object whose cid is specified by the ':cid' URI parameter.
696             The fields to be updated and their new values should be sent in the request
697             body, e.g., like this:
698              
699             { "path" : "new/path", "source" : "new source", "acl" : "inactive" }
700              
701             =item * DELETE
702              
703             Deletes the component object whose cid is specified by the ':cid' URI parameter.
704             This will work only if nothing in the database refers to this component.
705              
706             =back
707             EOH
708             },
709              
710             # /component/path
711             'component/path' =>
712             {
713             parent => 'component',
714             handler => {
715             POST => 'handler_post_component_path',
716             },
717             acl_profile => 'admin',
718             cli => 'component cid',
719             description => 'Update an existing component object via POST request (component path must be included in request body)',
720             documentation => <<'EOH',
721             =pod
722              
723             This resource enables existing component objects to be updated, and new
724             component objects to be inserted, by sending a POST request to the REST server.
725             Along with the properties to be modified/inserted, the request body must
726             include an 'path' property, the value of which specifies the component to be
727             updated.
728             EOH
729             },
730              
731             };
732              
733              
734             =head2 Employee resources
735              
736             =cut
737              
738             $defs->{'employee'} = {
739              
740             # /employee
741             'employee' =>
742             {
743             parent => '/',
744             handler => 'handler_noop',
745             acl_profile => 'passerby',
746             cli => 'employee',
747             description => 'Parent for employee resources',
748             documentation => <<'EOH',
749             =pod
750              
751             Parent for employee resources
752             EOH
753             },
754              
755             # /employee/count/?:priv
756             'employee/count/?:priv' =>
757             {
758             parent => 'employee',
759             handler => {
760             GET => 'handler_get_employee_count',
761             },
762             acl_profile => 'admin',
763             cli => 'employee count',
764             validations => {
765             'priv' => $priv_validation,
766             },
767             description => 'Display total count of employees (optionally by privlevel)',
768             documentation => <<'EOH',
769             =pod
770              
771             If ':priv' is not specified, gets the total number of employees in the
772             database. This includes employees of all privilege levels, including not only
773             administrators and active employees, but inactives and passerbies as well.
774              
775             If ':priv' is specified, gets the total number of employees with the
776             given privlevel. Valid privlevels are:
777              
778             =over
779              
780             =item * passerby
781              
782             =item * inactive
783              
784             =item * active
785              
786             =item * admin
787              
788             =back
789             EOH
790             },
791              
792             # /employee/eid
793             'employee/eid' =>
794             {
795             parent => 'employee',
796             handler => {
797             POST => 'handler_post_employee_eid',
798             },
799             acl_profile => 'inactive',
800             cli => 'employee eid $JSON',
801             description => 'Update existing employee (JSON request body with EID required)',
802             documentation => <<'EOH',
803             =pod
804              
805             This resource provides a way to update employee objects using the
806             POST method, provided the employee's EID is provided in the content body.
807             The properties to be modified should also be included, e.g.:
808              
809             { "eid" : 43, "fullname" : "Foo Bariful" }
810              
811             This would change the 'fullname' property of the employee with EID 43 to "Foo
812             Bariful" (provided such an employee exists).
813              
814             ACL note: 'inactive' and 'active' employees can use this resource to modify
815             their own employee profile. Exactly which fields can be updated may differ from
816             site to site (see the DOCHAZKA_PROFILE_EDITABLE_FIELDS site parameter).
817             EOH
818             },
819              
820             # /employee/eid/:eid
821             'employee/eid/:eid' =>
822             {
823             parent => 'employee',
824             handler => {
825             GET => 'handler_get_employee_eid',
826             PUT => 'handler_put_employee_eid',
827             DELETE => 'handler_delete_employee_eid',
828             },
829             acl_profile => {
830             GET => 'passerby',
831             PUT => 'inactive',
832             DELETE => 'admin',
833             },
834             cli => 'employee eid $EID [$JSON]',
835             validations => {
836             eid => 'Int',
837             },
838             description => 'GET: look up employee (exact match); PUT: update existing employee; DELETE: delete employee',
839             documentation => <<'EOH',
840             =pod
841              
842             With this resource, we can look up an employee by exact match (GET),
843             update an existing employee (PUT), or delete an employee (DELETE).
844              
845             =over
846              
847             =item * GET
848              
849             Retrieves an employee object by its EID.
850              
851             =item * PUT
852              
853             Updates the "employee profile" (employee object) of the employee with
854             the given EID. For example, if the request body was:
855              
856             { "fullname" : "Foo Bariful" }
857              
858             the request would change the 'fullname' property of the employee with EID 43
859             (provided such an employee exists) to "Foo Bariful". Any 'eid' property
860             provided in the content body will be ignored.
861              
862             ACL note: 'inactive' and 'active' employees can use this resource to modify
863             their own employee profile. Exactly which fields can be updated may differ from
864             site to site (see the DOCHAZKA_PROFILE_EDITABLE_FIELDS site parameter).
865              
866             =item * DELETE
867              
868             Deletes the employee with the given EID (will only work if the EID
869             exists and nothing in the database refers to it).
870              
871             =back
872             EOH
873             },
874              
875             # /employee/eid/:eid/full
876             'employee/eid/:eid/full' =>
877             {
878             parent => 'employee/eid/:eid',
879             handler => {
880             GET => 'handler_get_employee_eid_full',
881             },
882             acl_profile => 'inactive',
883             cli => 'employee eid $EID full',
884             validations => {
885             eid => 'Int',
886             },
887             description => 'Full employee profile',
888             documentation => <<'EOH',
889             =pod
890              
891             This resource enables any active employee to retrieve her own
892             full employee profile. Admins and supervisors can retrieve the
893             profiles of other employees.
894             EOH
895             },
896              
897             # /employee/eid/:eid/minimal
898             'employee/eid/:eid/minimal' =>
899             {
900             parent => 'employee/eid/:eid',
901             handler => {
902             GET => 'handler_get_employee_minimal',
903             },
904             acl_profile => 'passerby',
905             cli => 'employee eid $EID minimal',
906             validations => {
907             eid => 'Int',
908             },
909             description => 'List minimal info on an employee',
910             documentation => <<'EOH',
911             =pod
912              
913             This resource enables any employee to get minimal information
914             on any other employee. Useful for EID to nick conversion or to
915             look up another employee's email address or name.
916             EOH
917             },
918              
919             # /employee/eid/:eid/team
920             'employee/eid/:eid/team' =>
921             {
922             parent => 'employee/eid/:eid',
923             handler => {
924             GET => 'handler_get_employee_eid_team',
925             },
926             acl_profile => 'admin',
927             cli => 'employee eid $EID team',
928             validations => {
929             eid => 'Int',
930             },
931             description => 'List the nicks of an employee\'s team members',
932             documentation => <<'EOH',
933             =pod
934              
935             This resource enables administrators to list the nicks of team members
936             of an arbitrary employee - i.e. that employee\'s direct reports.
937             EOH
938             },
939              
940             # /employee/list/?:priv
941             'employee/list/?:priv' =>
942             {
943             parent => 'employee',
944             handler => {
945             GET => 'handler_get_employee_list',
946             },
947             acl_profile => 'admin',
948             cli => 'employee list [$PRIV]',
949             validations => {
950             'priv' => $priv_validation,
951             },
952             description => 'List nicks of employees',
953             documentation => <<'EOH',
954             =pod
955              
956             This resource enables the administrator to easily list the nicks of
957             employees. If priv is not given, all employees are listed.
958             EOH
959             },
960              
961             # /employee/nick
962             'employee/nick' =>
963             {
964             parent => 'employee',
965             handler => {
966             POST => 'handler_post_employee_nick',
967             },
968             acl_profile => 'inactive',
969             cli => 'employee nick $JSON',
970             description => 'Insert new/update existing employee (JSON request body with nick required)',
971             documentation => <<'EOH',
972             =pod
973              
974             This resource provides a way to insert/update employee objects using the
975             POST method, provided the employee's nick is provided in the content body.
976              
977             Consider, for example, the following request body:
978              
979             { "nick" : "foobar", "fullname" : "Foo Bariful" }
980              
981             If an employee "foobar" exists, such a request would change the 'fullname'
982             property of that employee to "Foo Bariful". On the other hand, if the employee
983             doesn't exist this HTTP request would cause a new employee 'foobar' to be
984             created.
985              
986             ACL note: 'inactive' and 'active' employees can use this resource to modify
987             their own employee profile. Exactly which fields can be updated may differ from
988             site to site (see the DOCHAZKA_PROFILE_EDITABLE_FIELDS site parameter).
989             EOH
990             },
991              
992             # /employee/nick/:nick
993             'employee/nick/:nick' =>
994             {
995             parent => 'employee',
996             handler => {
997             GET => 'handler_get_employee_nick',
998             PUT => 'handler_put_employee_nick',
999             DELETE => 'handler_delete_employee_nick',
1000             },
1001             acl_profile => {
1002             GET => 'passerby',
1003             PUT => 'inactive',
1004             DELETE => 'admin',
1005             },
1006             cli => 'employee nick $NICK [$JSON]',
1007             validations => {
1008             'nick' => $term_validation,
1009             },
1010             description => "Retrieves (GET), updates/inserts (PUT), and/or deletes (DELETE) the employee specified by the ':nick' parameter",
1011             documentation => <<'EOH',
1012             =pod
1013              
1014             Retrieves (GET), updates/inserts (PUT), and/or deletes (DELETE) the employee
1015             specified by the ':nick' parameter.
1016              
1017             =over
1018              
1019             =item * GET
1020              
1021             Retrieves employee object(s) by exact match. For example:
1022              
1023             GET employee/nick/foobar
1024              
1025             would look for an employee whose nick is 'foobar'.
1026              
1027             =item * PUT
1028              
1029             Inserts a new employee or updates an existing one (exact match only).
1030             If a 'nick' property is provided in the content body and its value is
1031             different from the nick provided in the URI, the employee's nick will be
1032             changed to the value provided in the content body.
1033              
1034             ACL note: 'inactive' and 'active' employees can use this resource to modify
1035             their own employee profile. Exactly which fields can be updated may differ from
1036             site to site (see the DOCHAZKA_PROFILE_EDITABLE_FIELDS site parameter).
1037              
1038             =item * DELETE
1039              
1040             Deletes an employee (exact match only). This will work only if the
1041             exact nick exists and nothing else in the database refers to the employee
1042             in question.
1043              
1044             =back
1045             EOH
1046             },
1047              
1048             # /employee/nick/:nick/ldap
1049             'employee/nick/:nick/ldap' =>
1050             {
1051             parent => 'employee/nick/:nick',
1052             handler => {
1053             GET => 'handler_get_employee_ldap',
1054             PUT => 'handler_put_employee_ldap',
1055             },
1056             acl_profile => {
1057             GET => 'passerby',
1058             PUT => 'active',
1059             },
1060             cli => 'employee nick $nick ldap',
1061             validations => {
1062             nick => $term_validation,
1063             },
1064             description => 'List LDAP info on an employee',
1065             documentation => <<'EOH',
1066             =pod
1067              
1068             LDAP search and sync resource
1069              
1070             =over
1071              
1072             =item * GET
1073              
1074             Enables any employee to perform an LDAP lookup on any other employee.
1075              
1076             =item * PUT
1077              
1078             Enables active employees to sync their own employee profile fields[1] from the
1079             site's LDAP database.
1080              
1081             Enables admin employees to sync/create[1] any existing employee from the LDAP
1082             database. If the employee does not exist, it will be created (just the employee
1083             object itself, without any privhistory records).
1084              
1085             =back
1086              
1087             [1] Which fields get synced depends on DOCHAZKA_LDAP_MAPPING site config
1088             parameter.
1089              
1090             EOH
1091             },
1092              
1093             # /employee/nick/:nick/full
1094             'employee/nick/:nick/full' =>
1095             {
1096             parent => 'employee/nick/:nick',
1097             handler => {
1098             GET => 'handler_get_employee_nick_full',
1099             },
1100             acl_profile => 'active',
1101             cli => 'employee nick $nick full',
1102             validations => {
1103             nick => $term_validation,
1104             },
1105             description => 'Full employee profile',
1106             documentation => <<'EOH',
1107             =pod
1108              
1109             This resource enables any active employee to retrieve her own
1110             full employee profile. Admins and supervisors can retrieve the
1111             profiles of other employees.
1112             EOH
1113             },
1114              
1115             # /employee/nick/:nick/minimal
1116             'employee/nick/:nick/minimal' =>
1117             {
1118             parent => 'employee/nick/:nick',
1119             handler => {
1120             GET => 'handler_get_employee_minimal',
1121             },
1122             acl_profile => 'passerby',
1123             cli => 'employee nick $nick minimal',
1124             validations => {
1125             nick => $term_validation,
1126             },
1127             description => 'List minimal info on an employee',
1128             documentation => <<'EOH',
1129             =pod
1130              
1131             This resource enables any employee to get minimal information
1132             on any other employee. Useful for nick to EID conversion or to
1133             look up another employee's email address or name.
1134             EOH
1135             },
1136              
1137             # /employee/nick/:nick/team
1138             'employee/nick/:nick/team' =>
1139             {
1140             parent => 'employee/nick/:nick',
1141             handler => {
1142             GET => 'handler_get_employee_nick_team',
1143             },
1144             acl_profile => 'admin',
1145             cli => 'employee nick $nick team',
1146             validations => {
1147             nick => $term_validation,
1148             },
1149             description => 'List the nicks of an employee\'s team members',
1150             documentation => <<'EOH',
1151             =pod
1152              
1153             This resource enables administrators to list the nicks of team members
1154             of an arbitrary employee - i.e. that employee\'s direct reports.
1155             EOH
1156             },
1157              
1158             # /employee/search
1159             'employee/search' =>
1160             {
1161             parent => 'employee',
1162             handler => 'handler_noop',
1163             acl_profile => 'passerby',
1164             cli => 'employee search',
1165             description => 'Employee search resources',
1166             documentation => <<'EOH',
1167             =pod
1168              
1169             See child resources.
1170             EOH
1171             },
1172              
1173             # /employee/search/nick/:key
1174             'employee/search/nick/:key' =>
1175             {
1176             parent => 'employee/search',
1177             handler => {
1178             'GET' => 'handler_get_employee_search_nick',
1179             },
1180             acl_profile => 'inactive',
1181             cli => 'employee search nick $KEY',
1182             description => 'Search employee profiles on nick (% is wild)',
1183             validations => {
1184             'key' => qr/^[%[:alnum:]_][%[:alnum:]_-]*$/,
1185             },
1186             documentation => <<'EOH',
1187             =pod
1188              
1189             Look up employee profiles using a search key, which can optionally contain
1190             a wildcard ('%'). For example:
1191              
1192             GET employee/search/nick/foo%
1193              
1194             would return a list of employees whose nick starts with 'foo', provided the '%'
1195             character in the URI is properly encoded (as '%25') by the client.
1196              
1197             Note that if the user provides no wildcard characters in the key, they will
1198             implicitly be added. Example: a search for 'foo' would be converted to
1199             '%foo%'. For a literal nick lookup, use the 'employee/nick/:nick' resource.
1200             EOH
1201             },
1202              
1203             # /employee/sec_id/:sec_id
1204             'employee/sec_id/:sec_id' =>
1205             {
1206             parent => 'employee',
1207             handler => {
1208             GET => 'handler_get_employee_sec_id',
1209             },
1210             acl_profile => {
1211             GET => 'passerby'
1212             },
1213             cli => 'employee sec_id $SEC_ID',
1214             description => 'GET an employee profile by the employee\'s secondary ID',
1215             validations => {
1216             'sec_id' => $term_validation,
1217             },
1218             documentation => <<'EOH',
1219             =pod
1220              
1221             Retrieves an employee object by the secondary ID (must be an exact match)
1222             EOH
1223             },
1224              
1225             # /employee/sec_id/:sec_id/minimal
1226             'employee/sec_id/:sec_id/minimal' =>
1227             {
1228             parent => 'employee/sec_id/:sec_id',
1229             handler => {
1230             GET => 'handler_get_employee_minimal',
1231             },
1232             acl_profile => 'passerby',
1233             cli => 'employee sec_id $sec_id minimal',
1234             validations => {
1235             'sec_id' => $term_validation,
1236             },
1237             description => 'List minimal info on an employee',
1238             documentation => <<'EOH',
1239             =pod
1240              
1241             This resource enables any employee to get minimal information
1242             on any other employee. Useful for sec_id to EID conversion or to
1243             look up another employee's email address or name.
1244             EOH
1245             },
1246              
1247             # /employee/self
1248             'employee/self' =>
1249             {
1250             parent => 'employee',
1251             handler => {
1252             GET => 'handler_whoami',
1253             POST => 'handler_post_employee_self',
1254             },
1255             acl_profile => {
1256             'GET' => 'passerby',
1257             'POST' => 'inactive',
1258             },
1259             cli => 'employee current',
1260             description => 'Retrieve (GET) and edit (POST) our own employee profile',
1261             documentation => <<'EOH',
1262             =pod
1263              
1264             With this resource, we can retrieve (GET) and/or edit (POST) our own employee
1265             profile.
1266              
1267             =over
1268              
1269             =item * GET
1270              
1271             Displays the profile of the currently logged-in employee. The information
1272             is limited to just the employee object itself.
1273              
1274             =item * POST
1275              
1276             Provides a way for an employee to update certain fields of her own employee
1277             profile. Exactly which fields can be updated may differ from site to site
1278             (see the DOCHAZKA_PROFILE_EDITABLE_FIELDS site parameter).
1279              
1280             =back
1281             EOH
1282             },
1283              
1284             # /employee/self/full
1285             'employee/self/full' =>
1286             {
1287             parent => 'employee/self',
1288             handler => {
1289             GET => 'handler_get_employee_self_full',
1290             },
1291             acl_profile => 'passerby',
1292             cli => 'employee current priv',
1293             description => 'Retrieve our own employee profile, privlevel, and schedule',
1294             documentation => <<'EOH',
1295             =pod
1296              
1297             Displays the "full profile" of the currently logged-in employee. The
1298             information includes the full employee object (taken from the 'current_emp'
1299             property) as well as the employee's current privlevel and schedule, which are
1300             looked up from the database.
1301              
1302             N.B. The value of the "schedule" property is just the SID, not the actual
1303             schedule record.
1304             EOH
1305             },
1306              
1307             # /employee/team
1308             'employee/team' =>
1309             {
1310             parent => 'employee',
1311             handler => {
1312             GET => 'handler_get_employee_team',
1313             },
1314             acl_profile => 'active',
1315             cli => 'team',
1316             description => 'List nicks of the logged-in employee\'s team members',
1317             documentation => <<'EOH',
1318             =pod
1319              
1320             This resource enables supervisors to easily list the nicks of
1321             employees in their team - i.e. their direct reports.
1322             EOH
1323             },
1324              
1325             };
1326              
1327              
1328             =head2 Genreport resources
1329              
1330             =cut
1331              
1332             $defs->{'genreport'} = {
1333              
1334             # /genreport
1335             'genreport' =>
1336             {
1337             parent => '/',
1338             handler => {
1339             GET => 'handler_noop',
1340             POST => 'handler_genreport',
1341             },
1342             acl_profile => {
1343             GET => 'passerby',
1344             POST => 'admin',
1345             },
1346             cli => 'genreport',
1347             description => 'Generate reports',
1348             documentation => <<'EOH',
1349             =pod
1350              
1351             The "POST genreport" resource generates reports from Mason templates.
1352             The resource takes a request body with one mandatory property, "path"
1353             (corresponding to the path of a Mason component relative to the component
1354             root), and one optional property, "parameters", which should be a hash
1355             of parameter names and values.
1356              
1357             The resource handler checks (1) if the component exists in the database,
1358             (2) whether current employee has sufficient permissions to generate the
1359             report (by comparing the employee's privlevel with the ACL profile of the
1360             component), and (3) validates the parameters, if any, by applying the
1361             validation rules specified in the component object. Iff all of these
1362             conditions are met, the component is called with the provided parameters.
1363             EOH
1364             },
1365              
1366             };
1367              
1368              
1369             =head2 History resources
1370              
1371             =cut
1372              
1373             $defs->{'history'} = {
1374              
1375             'priv/history' =>
1376             {
1377             parent => 'priv',
1378             handler => 'handler_noop',
1379             cli => 'priv history',
1380             description => 'Privilege history resources',
1381             documentation => <<'EOH',
1382             =pod
1383              
1384             This resource presents a list of subresources, all related to privilege histories.
1385             EOH
1386             },
1387              
1388             'schedule/history' =>
1389             {
1390             parent => 'schedule',
1391             handler => 'handler_noop',
1392             cli => 'schedule history',
1393             description => 'Schedule history resources',
1394             documentation => <<'EOH',
1395             =pod
1396              
1397             This resource presents a list of subresources, all related to schedule histories.
1398             EOH
1399             },
1400              
1401             'priv/history/eid/:eid' =>
1402             {
1403             parent => 'priv/history',
1404             handler => {
1405             GET => 'handler_history_get_multiple',
1406             POST => 'handler_history_post',
1407             },
1408             acl_profile => {
1409             GET => 'inactive',
1410             POST => 'admin',
1411             },
1412             cli => 'priv history eid $EID [$JSON]',
1413             validations => {
1414             'eid' => 'Int',
1415             },
1416             description => 'Retrieves entire history of privilege level changes for employee with the given EID (GET); or, with an appropriate content body, adds (POST) a record to employee\'s privhistory',
1417             documentation => <<'EOH',
1418             =pod
1419              
1420             Retrieves entire history of privilege level changes for employee with the given
1421             EID (GET); or, with an appropriate content body, adds (POST) a record to
1422             employee\'s privhistory.
1423              
1424             =over
1425              
1426             =item * GET
1427              
1428             Retrieves the "privhistory", or history of changes in
1429             privilege level, of the employee with the given EID.
1430              
1431             =item * POST
1432              
1433             Adds a record to the privhistory of the given employee. The content body should
1434             contain two properties: "effective" (a timestamp) and "priv" (one of
1435             "passerby", "inactive", "active", or "admin").
1436              
1437             It is assumed that schedule histories will be built up record-by-record;
1438             insertion of multiple history records in a single request is not supported.
1439              
1440             =back
1441              
1442             Update note: histories can be updated by adding new records and deleting old
1443             ones. Existing history records cannot be changed. Adds/deletes should be
1444             performed with due care - especially with regard to existing employee
1445             attendance data (if any).
1446             EOH
1447             },
1448              
1449             'schedule/history/eid/:eid' =>
1450             {
1451             parent => 'schedule/history',
1452             handler => {
1453             GET => 'handler_history_get_multiple',
1454             POST => 'handler_history_post',
1455             },
1456             acl_profile => {
1457             GET => 'inactive',
1458             POST => 'admin',
1459             },
1460             cli => 'schedule history eid $EID [$JSON]',
1461             validations => {
1462             'eid' => 'Int',
1463             },
1464             description => 'Retrieves entire history of schedule changes for employee with the given EID (GET); or, with an appropriate content body, adds (POST) a record to employee\'s schedule history',
1465             documentation => <<'EOH',
1466             =pod
1467              
1468             Retrieves entire history of schedule changes for employee with the given EID
1469             (GET); or, with an appropriate content body, adds (POST) a record to
1470             employee\'s schedule history.
1471              
1472             =over
1473              
1474             =item * GET
1475              
1476             Retrieves the full history of schedule changes of the employee with the given EID.
1477             For partial history, see 'schedule/history/eid/:eid/:tsrange'.
1478              
1479             =item * POST
1480              
1481             Adds a record to the schedule history of the given employee. The content body should
1482             contain two properties: "effective" (a timestamp) and "sid" (the ID of the schedule).
1483             Alternatively, an "scode" property (schedule code) can be sent instead of "sid".
1484              
1485             It is assumed that schedule histories will be built up record-by-record;
1486             insertion of multiple history records in a single request is not supported.
1487              
1488             =back
1489              
1490             Update note: histories can be updated by adding new records and deleting old
1491             ones. Existing history records cannot be changed. Adds/deletes should be
1492             performed with due care - especially with regard to existing employee
1493             attendance data (if any).
1494             EOH
1495             },
1496              
1497             'priv/history/eid/:eid/:tsrange' =>
1498             {
1499             parent => 'priv/history',
1500             handler => {
1501             GET => 'handler_history_get_multiple',
1502             },
1503             acl_profile => 'inactive',
1504             cli => 'priv history eid $EID $TSRANGE',
1505             description => 'Get a slice of history of privilege level changes for employee with the given EID',
1506             validations => {
1507             'eid' => 'Int',
1508             'tsrange' => $tsrange_validation,
1509             },
1510             documentation => <<'EOH',
1511             =pod
1512              
1513             Retrieves a slice (given by the tsrange argument) of the employee's
1514             "privhistory" (history of changes in privilege level).
1515             EOH
1516             },
1517              
1518             'schedule/history/eid/:eid/:tsrange' =>
1519             {
1520             parent => 'schedule/history',
1521             handler => {
1522             GET => 'handler_history_get_multiple',
1523             },
1524             acl_profile => 'inactive',
1525             cli => 'schedule history eid $EID $TSRANGE',
1526             description => 'Get a slice of history of schedule changes for employee with the given EID',
1527             validations => {
1528             'eid' => 'Int',
1529             'tsrange' => $tsrange_validation,
1530             },
1531             documentation => <<'EOH',
1532             =pod
1533              
1534             Retrieves a slice (given by the tsrange argument) of the employee's
1535             "schedule history" (history of changes in schedule).
1536             EOH
1537             },
1538              
1539             'priv/history/eid/:eid/:ts' =>
1540             {
1541             parent => 'priv/history',
1542             handler => {
1543             GET => 'handler_history_get_single',
1544             },
1545             acl_profile => 'inactive',
1546             cli => 'priv history eid $EID $TS',
1547             description => 'Get the privhistory record effective at a given timestamp',
1548             validations => {
1549             'eid' => 'Int',
1550             'ts' => $ts_validation,
1551             },
1552             documentation => <<'EOH',
1553             =pod
1554              
1555             Retrieves an employee's effective privhistory record (status change) as of a
1556             given timestamp.
1557             EOH
1558             },
1559              
1560             'schedule/history/eid/:eid/:ts' =>
1561             {
1562             parent => 'schedule/history',
1563             handler => {
1564             GET => 'handler_history_get_single',
1565             },
1566             acl_profile => 'inactive',
1567             cli => 'schedule history eid $EID $TS',
1568             description => 'Get the privhistory record effective at a given timestamp',
1569             validations => {
1570             'eid' => 'Int',
1571             'ts' => $ts_validation,
1572             },
1573             documentation => <<'EOH',
1574             =pod
1575              
1576             Retrieves an employee's effective schedhistory record (status change) as of a
1577             given timestamp.
1578             EOH
1579             },
1580              
1581             'priv/history/eid/:eid/now' =>
1582             {
1583             parent => 'priv/history',
1584             handler => {
1585             GET => 'handler_history_get_single',
1586             },
1587             acl_profile => 'inactive',
1588             cli => 'priv history eid $EID now',
1589             description => 'Get the privhistory record effective as of "now" (the current timestamp)',
1590             validations => {
1591             'eid' => 'Int',
1592             },
1593             documentation => <<'EOH',
1594             =pod
1595              
1596             Retrieves an employee's effective privhistory record (status change) as of
1597             "now" (the current timestamp).
1598             EOH
1599             },
1600              
1601             'schedule/history/eid/:eid/now' =>
1602             {
1603             parent => 'schedule/history',
1604             handler => {
1605             GET => 'handler_history_get_single',
1606             },
1607             acl_profile => 'inactive',
1608             cli => 'schedule history eid $EID now',
1609             description => 'Get the privhistory record effective as of "now" (the current timestamp)',
1610             validations => {
1611             'eid' => 'Int',
1612             },
1613             documentation => <<'EOH',
1614             =pod
1615              
1616             Retrieves an employee's effective schedhistory record (status change) as of
1617             "now" (the current timestamp).
1618             EOH
1619             },
1620              
1621             'priv/history/nick/:nick' =>
1622             {
1623             parent => 'priv/history',
1624             handler => {
1625             GET => 'handler_history_get_multiple',
1626             POST => 'handler_history_post',
1627             },
1628             acl_profile => {
1629             GET => 'inactive',
1630             POST => 'admin',
1631             },
1632             cli => 'priv history nick $NICK [$JSON]',
1633             validations => {
1634             'nick' => $term_validation,
1635             },
1636             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',
1637             documentation => <<'EOH',
1638             =pod
1639              
1640             Retrieves entire history of privilege level changes for employee with the given
1641             nick (GET); or, with an appropriate content body, adds (PUT) a record to
1642             employee\'s privhistory.
1643              
1644             =over
1645              
1646             =item * GET
1647              
1648             Retrieves the "privhistory", or history of changes in
1649             privilege level, of the employee with the given nick.
1650              
1651             =item * POST
1652              
1653             Adds a record to the privhistory of the given employee. The content body should
1654             contain two properties: "effective" (a timestamp) and "priv" (one of
1655             "passerby", "inactive", "active", or "admin").
1656              
1657             It is assumed that schedule histories will be built up record-by-record;
1658             insertion of multiple history records in a single request is not supported.
1659              
1660             =back
1661              
1662             Update note: histories can be updated by adding new records and deleting old
1663             ones. Existing history records cannot be changed. Adds/deletes should be
1664             performed with due care - especially with regard to existing employee
1665             attendance data (if any).
1666             EOH
1667             },
1668              
1669             'schedule/history/nick/:nick' =>
1670             {
1671             parent => 'schedule/history',
1672             handler => {
1673             GET => 'handler_history_get_multiple',
1674             POST => 'handler_history_post',
1675             },
1676             acl_profile => {
1677             GET => 'inactive',
1678             POST => 'admin',
1679             },
1680             cli => 'schedule history nick $NICK [$JSON]',
1681             validations => {
1682             'nick' => $term_validation,
1683             },
1684             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',
1685             documentation => <<'EOH',
1686             =pod
1687              
1688             Retrieves entire history of schedule changes for employee with the given nick
1689             (GET); or, with an appropriate content body, adds (PUT) a record to employee\'s
1690             schedule history.
1691            
1692             =over
1693              
1694             =item * GET
1695              
1696             Retrieves the full history of schedule changes of the employee with the given nick.
1697             For partial histories, see 'schedule/history/nick/:nick/:tsrange'.
1698              
1699             =item * POST
1700              
1701             Adds a record to the schedule history of the given employee. The content body should
1702             contain two properties: "effective" (a timestamp) and "sid" (the ID of the schedule).
1703             Alternatively, an "scode" property (schedule code) can be sent instead of "sid".
1704              
1705             It is assumed that schedule histories will be built up record-by-record;
1706             insertion of multiple history records in a single request is not supported.
1707              
1708             =back
1709              
1710             Update note: histories can be updated by adding new records and deleting old
1711             ones. Existing history records cannot be changed. Adds/deletes should be
1712             performed with due care - especially with regard to existing employee
1713             attendance data (if any).
1714             EOH
1715             },
1716              
1717             'priv/history/nick/:nick/:tsrange' =>
1718             {
1719             parent => 'priv/history',
1720             handler => {
1721             GET => 'handler_history_get_multiple',
1722             },
1723             acl_profile => 'inactive',
1724             cli => 'priv history nick $NICK $TSRANGE',
1725             validations => {
1726             'nick' => $term_validation,
1727             'tsrange' => $tsrange_validation,
1728             },
1729             description => 'Get partial history of privilege level changes for employee with the given nick ' .
1730             '(i.e, limit to given tsrange)',
1731             documentation => <<'EOH',
1732             =pod
1733              
1734             Retrieves a slice (given by the tsrange argument) of the employee's
1735             "privhistory" (history of changes in privilege level).
1736             EOH
1737             },
1738              
1739             'schedule/history/nick/:nick/:tsrange' =>
1740             {
1741             parent => 'schedule/history',
1742             handler => {
1743             GET => 'handler_history_get_multiple',
1744             },
1745             acl_profile => 'inactive',
1746             cli => 'schedule history nick $NICK $TSRANGE',
1747             validations => {
1748             'nick' => $term_validation,
1749             'tsrange' => $tsrange_validation,
1750             },
1751             description => 'Get partial history of schedule changes for employee with the given nick ' .
1752             '(i.e, limit to given tsrange)',
1753             documentation => <<'EOH',
1754             =pod
1755              
1756             Retrieves a slice (given by the tsrange argument) of the employee's
1757             "schedule history" (history of changes in schedule).
1758             EOH
1759             },
1760              
1761             'priv/history/phid/:phid' =>
1762             {
1763             parent => 'priv/history',
1764             handler => {
1765             GET => 'handler_history_get_phid',
1766             POST => 'handler_history_post_phid',
1767             DELETE => 'handler_history_delete_phid',
1768             },
1769             acl_profile => 'admin',
1770             cli => 'priv history phid $PHID',
1771             validations => {
1772             'phid' => 'Int',
1773             },
1774             description => 'Retrieves (GET), updates (POST), or deletes (DELETE) a single privilege history record by its PHID',
1775             documentation => <<'EOH',
1776             =pod
1777              
1778             Retrieves (GET), updates (POST), or deletes (DELETE) a single privilege history record by its
1779             PHID.
1780              
1781             =over
1782              
1783             =item * GET
1784              
1785             Retrieves a privhistory record by its PHID.
1786              
1787             =item * POST
1788              
1789             Updates a privilege history record by its PHID. The 'phid' and 'eid'
1790             properties cannot be changed in this way.
1791              
1792             =item * DELETE
1793              
1794             Deletes a privhistory record by its PHID.
1795              
1796             =back
1797              
1798             (N.B.: history records can be added using POST requests on "priv/history/eid/:eid" or
1799             "priv/history/nick/:nick")
1800             EOH
1801             },
1802              
1803             'schedule/history/shid/:shid' =>
1804             {
1805             parent => 'schedule/history',
1806             handler => {
1807             GET => 'handler_history_get_shid',
1808             POST => 'handler_history_post_shid',
1809             DELETE => 'handler_history_delete_shid',
1810             },
1811             acl_profile => 'admin',
1812             cli => 'schedule history phid $PHID',
1813             validations => {
1814             'shid' => 'Int',
1815             },
1816             description => 'Retrieves (GET), updates (POST), or deletes (DELETE) a single schedule history record by its SHID',
1817             documentation => <<'EOH',
1818             =pod
1819              
1820             Retrieves (GET), updates (POST), or deletes (DELETE) a single schedule
1821             history record by its SHID.
1822              
1823             =over
1824              
1825             =item * GET
1826              
1827             Retrieves a schedule history record by its SHID.
1828              
1829             =item * POST
1830              
1831             Updates a schedule history record by its SHID. The 'shid' and 'eid'
1832             properties cannot be changed in this way.
1833              
1834             =item * DELETE
1835              
1836             Deletes a schedule history record by its SHID.
1837              
1838             =back
1839              
1840             (N.B.: history records can be added using POST requests on "schedule/history/eid/:eid" or
1841             "schedule/history/nick/:nick")
1842             EOH
1843             },
1844              
1845             'priv/history/self/?:tsrange' =>
1846             {
1847             parent => 'priv/history',
1848             handler => {
1849             GET => 'handler_history_self',
1850             },
1851             acl_profile => 'inactive',
1852             cli => 'priv history self [$TSRANGE]',
1853             validations => {
1854             'tsrange' => $tsrange_validation,
1855             },
1856             description => 'Retrieves privhistory of present employee, with option to limit to :tsrange',
1857             documentation => <<'EOH',
1858             =pod
1859              
1860             This resource retrieves the "privhistory", or history of changes in
1861             privilege level, of the present employee. Optionally, the listing can be
1862             limited to a specific tsrange such as
1863              
1864             "[2014-01-01, 2014-12-31)"
1865              
1866             EOH
1867             },
1868              
1869             'schedule/history/self/?:tsrange' =>
1870             {
1871             parent => 'schedule/history',
1872             handler => {
1873             GET => 'handler_history_self',
1874             },
1875             acl_profile => 'inactive',
1876             cli => 'schedule history self [$TSRANGE]',
1877             validations => {
1878             'tsrange' => $tsrange_validation,
1879             },
1880             description => 'Retrieves schedule history of present employee, with option to limit to :tsrange',
1881             documentation => <<'EOH',
1882             =pod
1883              
1884             This resource retrieves the "schedule history", or history of changes in
1885             schedule, of the present employee. Optionally, the listing can be
1886             limited to a specific tsrange such as
1887              
1888             "[2014-01-01, 2014-12-31)"
1889              
1890             EOH
1891             },
1892              
1893             };
1894              
1895              
1896             =head2 Interval resources
1897              
1898             =cut
1899              
1900             $defs->{'interval'} = {
1901              
1902             # /interval
1903             'interval' =>
1904             {
1905             parent => '/',
1906             handler => 'handler_noop',
1907             acl_profile => 'passerby',
1908             cli => 'interval',
1909             description => 'Parent for interval resources',
1910             documentation => <<'EOH',
1911             =pod
1912              
1913             Parent for interval resources
1914             EOH
1915             },
1916              
1917             # /interval/eid/:eid/:tsrange
1918             'interval/eid/:eid/:tsrange' =>
1919             {
1920             parent => 'interval',
1921             handler => {
1922             GET => 'handler_interval_eid',
1923             DELETE => 'handler_interval_eid',
1924             },
1925             acl_profile => {
1926             GET => 'inactive',
1927             DELETE => 'active',
1928             },
1929             cli => 'interval eid $EID $TSRANGE',
1930             validations => {
1931             'eid' => 'Int',
1932             'tsrange' => $tsrange_validation,
1933             },
1934             description => 'Retrieve an arbitrary employee\'s intervals over the given tsrange',
1935             documentation => <<'EOH',
1936             =pod
1937              
1938             With this resource, administrators can retrieve any employee's intervals
1939             over a given tsrange, and active employees can do the same with their own intervals.
1940              
1941             Before any records are returned, the tsrange is checked to see if it overlaps with
1942             any privlevel or schedule changes - in which case an error is returned. This is so
1943             interval report-generators do not have to handle changes in employee status.
1944              
1945             By default, the number of intervals returned is limited to 500. This number
1946             can be changed via the DOCHAZKA_INTERVAL_SELECT_LIMIT site configuration
1947             parameter (set to 'undef' for no limit).
1948             EOH
1949             },
1950              
1951             # /interval/eid/:eid/:ts/:psqlint'
1952             'interval/eid/:eid/:ts/:psqlint' =>
1953             {
1954             parent => 'interval',
1955             handler => {
1956             GET => 'handler_interval_eid',
1957             DELETE => 'handler_interval_eid',
1958             },
1959             acl_profile => 'active',
1960             cli => 'interval eid $EID $TS DELTA $PSQLINT',
1961             validations => {
1962             'eid' => 'Int',
1963             'ts' => $ts_validation,
1964             'psqlint' => $psqlint_validation,
1965             },
1966             description => 'Retrieve an arbitrary employee\'s intervals falling within a time period',
1967             documentation => <<'EOH',
1968             =pod
1969              
1970             This is just like 'interval/eid/:eid/:tsrange' except that the time range is
1971             specified by giving a timestamp and a PostgreSQL time interval, e.g "1 week 3 days".
1972             EOH
1973             },
1974              
1975             # /interval/fillup
1976             'interval/fillup' =>
1977             {
1978             parent => 'interval',
1979             handler => {
1980             POST => 'handler_interval_fillup',
1981             },
1982             acl_profile => {
1983             POST => 'active',
1984             },
1985             cli => 'interval fillup',
1986             description => 'Generate intervals according to schedule',
1987             documentation => <<'EOH',
1988             =pod
1989              
1990             Used with POST to create multiple attendance intervals for an employee,
1991             according to the prevailing schedule.
1992              
1993             The request body is a JSON object with the following parameters:
1994              
1995             =over
1996              
1997             =item * C<eid> (the EID of the employee to create intervals for; alternatively, C<nick> or C<sec_id>)
1998              
1999             =item * C<tsrange> (the time span over which to create intervals)
2000              
2001             =item * C<datelist> (a list of dates to create intervals for)
2002              
2003             =item * C<dry_run> (boolean value)
2004              
2005             =item * C<aid> (the AID of the activity; alternatively, C<code>)
2006              
2007             =item * C<desc> (optional interval description)
2008              
2009             =item * C<remark> (optional remark)
2010              
2011             =back
2012              
2013             If C<tsrange> is provided, C<datelist> should be omitted - and vice versa.
2014              
2015             If C<dry_run> is true, the resource does not change the database state.
2016             EOH
2017             },
2018              
2019             # /interval/iid
2020             'interval/iid' =>
2021             {
2022             parent => 'interval',
2023             handler => {
2024             POST => 'handler_post_interval_iid',
2025             },
2026             acl_profile => 'active',
2027             cli => 'interval iid $JSON',
2028             description => 'Update an existing interval object via POST request (iid must be included in request body)',
2029             documentation => <<'EOH',
2030             =pod
2031              
2032             Enables existing interval objects to be updated by sending a POST request to
2033             the REST server. Along with the properties to be modified, the request body
2034             must include an 'iid' property, the value of which specifies the iid to be
2035             updated.
2036             EOH
2037             },
2038              
2039             # /interval/iid/:iid
2040             'interval/iid/:iid' =>
2041             {
2042             parent => 'interval',
2043             handler => {
2044             GET => 'handler_get_interval_iid',
2045             PUT => 'handler_interval_iid',
2046             DELETE => 'handler_interval_iid',
2047             },
2048             acl_profile => {
2049             GET => 'inactive',
2050             PUT => 'active',
2051             DELETE => 'active',
2052             },
2053             cli => 'interval iid $iid [$JSON]',
2054             validations => {
2055             'iid' => 'Int',
2056             },
2057             description => 'GET, PUT, or DELETE an interval object by its iid',
2058             documentation => <<'EOH',
2059             =pod
2060              
2061             This resource makes it possible to GET, PUT, or DELETE an interval object by
2062             its IID.
2063              
2064             =over
2065              
2066             =item * GET
2067              
2068             Retrieves an interval object by its IID.
2069              
2070             =item * PUT
2071              
2072             Updates the interval object whose iid is specified by the ':iid' URI parameter.
2073             The fields to be updated and their new values should be sent in the request
2074             body, e.g., like this:
2075              
2076             {
2077             "eid" : 34,
2078             "aid" : 1,
2079             "intvl" : '[ 2014-11-18 08:00, 2014-11-18 12:00 )'
2080             }
2081              
2082             =item * DELETE
2083              
2084             Deletes the interval object whose iid is specified by the ':iid' URI parameter.
2085             As long as the interval does not overlap with a lock interval, the delete operation
2086             will probably work as expected.
2087              
2088             =back
2089              
2090             ACL note: 'active' employees can update/delete only their own unlocked intervals.
2091             EOH
2092             },
2093              
2094             # /interval/new
2095             'interval/new' =>
2096             {
2097             parent => 'interval',
2098             handler => {
2099             POST => 'handler_interval_new',
2100             },
2101             acl_profile => 'active',
2102             cli => 'interval new $JSON',
2103             description => 'Add a new attendance data interval',
2104             documentation => <<'EOH',
2105             =pod
2106              
2107             This is the resource by which employees add new attendance data to the
2108             database. It takes a request body containing, at the very least, C<aid> and
2109             C<intvl> properties. Additionally, it can contain C<long_desc>, while
2110             administrators can also specify C<eid> and C<remark>.
2111             EOH
2112             },
2113              
2114             # /interval/nick/:nick/:tsrange
2115             'interval/nick/:nick/:tsrange' =>
2116             {
2117             parent => 'interval',
2118             handler => {
2119             GET => 'handler_interval_nick',
2120             DELETE => 'handler_interval_nick',
2121             },
2122             acl_profile => {
2123             GET => 'inactive',
2124             DELETE => 'active',
2125             },
2126             cli => 'interval nick $NICK $TSRANGE',
2127             validations => {
2128             'nick' => $term_validation,
2129             'tsrange' => $tsrange_validation,
2130             },
2131             description => 'Retrieve an arbitrary employee\'s intervals over the given tsrange',
2132             documentation => <<'EOH',
2133             =pod
2134              
2135             With this resource, administrators can retrieve any employee's intervals
2136             over a given tsrange, and active employees can do the same with their own intervals.
2137              
2138             Before any records are returned, the tsrange is checked to see if it overlaps with
2139             any privlevel or schedule changes - in which case an error is returned. This is so
2140             interval report-generators do not have to handle changes in employee status.
2141              
2142             By default, the number of intervals returned is limited to 500. This number
2143             can be changed via the DOCHAZKA_INTERVAL_SELECT_LIMIT site configuration
2144             parameter (set to 'undef' for no limit).
2145             EOH
2146             },
2147              
2148             # /interval/nick/:nick/:ts/:psqlint'
2149             'interval/nick/:nick/:ts/:psqlint' =>
2150             {
2151             parent => 'interval',
2152             handler => {
2153             GET => 'handler_interval_nick',
2154             DELETE => 'handler_interval_nick',
2155             },
2156             acl_profile => 'active',
2157             cli => 'interval nick $NICK $TS DELTA $PSQLINT',
2158             validations => {
2159             'nick' => $term_validation,
2160             'ts' => $ts_validation,
2161             'psqlint' => $psqlint_validation,
2162             },
2163             description => 'Retrieve an arbitrary employee\'s intervals falling within a time period',
2164             documentation => <<'EOH',
2165             =pod
2166              
2167             This is just like 'interval/nick/:nick/:tsrange' except that the time range is
2168             specified by giving a timestamp and a PostgreSQL time interval, e.g "1 week 3 days".
2169             EOH
2170             },
2171              
2172             # /interval/scheduled
2173             'interval/scheduled' =>
2174             {
2175             parent => 'interval',
2176             handler => {
2177             POST => 'handler_interval_scheduled',
2178             },
2179             acl_profile => {
2180             POST => 'inactive',
2181             },
2182             cli => 'interval scheduled',
2183             description => 'Generate intervals according to schedule',
2184             documentation => <<'EOH',
2185             =pod
2186              
2187             Used with POST to generate intervals according to an employee's schedule,
2188             without actually creating any intervals - for example, to find out what
2189             intervals are scheduled for a given day.
2190              
2191             (This resource is very similar to C<interval/fillup>. The key difference is it
2192             does not check for existing attendance intervals that might conflict. As a
2193             result, it can easily produce conflicts if used with C<<dry_run => 0>> (false).
2194             If you want a list of non-conflicting intervals, use C<interval/fillup> with
2195             C<<dry_run => 1>> (true).)
2196              
2197             The request body takes the following parameters:
2198              
2199             =over
2200              
2201             =item * C<eid> (the EID of the employee to create intervals for; alternatively, C<nick> or C<sec_id>)
2202              
2203             =item * C<tsrange> (the time span over which to create intervals)
2204              
2205             =item * C<datelist> (a list of dates to create intervals for)
2206              
2207             =back
2208              
2209             If C<tsrange> is provided, C<datelist> should be omitted - and vice versa.
2210              
2211             EOH
2212             },
2213              
2214             # /interval/self/:tsrange
2215             'interval/self/:tsrange' =>
2216             {
2217             parent => 'interval',
2218             handler => {
2219             GET => 'handler_interval_self',
2220             DELETE => 'handler_interval_self',
2221             },
2222             acl_profile => 'inactive',
2223             cli => 'interval self $TSRANGE',
2224             validations => {
2225             'tsrange' => $tsrange_validation,
2226             },
2227             description => 'Retrieve one\'s own intervals over the given tsrange',
2228             documentation => <<'EOH',
2229             =pod
2230              
2231             With this resource, employees can retrieve their own attendance intervals
2232             over a given tsrange.
2233              
2234             Before any records are returned, the tsrange is checked to see if it overlaps with
2235             any privlevel or schedule changes - in which case an error is returned. This is so
2236             interval report-generators do not have to handle changes in employee status.
2237              
2238             By default, the number of intervals returned is limited to 500. This number
2239             can be changed via the DOCHAZKA_INTERVAL_SELECT_LIMIT site configuration
2240             parameter (set to 'undef' for no limit).
2241             EOH
2242             },
2243              
2244             # /interval/self/:ts/:psqlint'
2245             'interval/:self/:ts/:psqlint' =>
2246             {
2247             parent => 'interval',
2248             handler => {
2249             GET => 'handler_interval_self',
2250             DELETE => 'handler_interval_self',
2251             },
2252             acl_profile => 'active',
2253             cli => 'INTERVAL SELF $TS DELTA $PSQLINT',
2254             validations => {
2255             'ts' => $ts_validation,
2256             'psqlint' => $psqlint_validation,
2257             },
2258             description => 'Retrieve one\'s own intervals falling within a time period',
2259             documentation => <<'EOH',
2260             =pod
2261              
2262             This is just like 'interval/self/:tsrange' except that the time range is
2263             specified by giving a timestamp and a PostgreSQL time interval, e.g "1 week 3 days".
2264             EOH
2265             },
2266              
2267             # /interval/summary/eid/:eid/:tsrange
2268             'interval/summary/eid/:eid/:tsrange' => {
2269             parent => 'interval',
2270             handler => {
2271             GET => 'handler_get_interval_summary',
2272             },
2273             acl_profile => 'inactive',
2274             cli => 'interval summary',
2275             description => 'Retrieve summary of an employee\'s intervals over a time period',
2276             documentation => <<'EOH',
2277             =pod
2278              
2279             With this resource, employees can generate summaries of their attendance intervals
2280             over a given period.
2281              
2282             EOH
2283             },
2284              
2285             };
2286              
2287              
2288             =head2 Lock resources
2289              
2290             =cut
2291              
2292             $defs->{'lock'} = {
2293              
2294             # /lock
2295             'lock' =>
2296             {
2297             parent => '/',
2298             handler => 'handler_noop',
2299             acl_profile => 'passerby',
2300             cli => 'lock',
2301             description => 'Parent for lock resources',
2302             documentation => <<'EOH',
2303             =pod
2304              
2305             Parent for lock resources
2306             EOH
2307             },
2308              
2309             # /lock/eid/:eid/:tsrange
2310             'lock/eid/:eid/:tsrange' =>
2311             {
2312             parent => 'lock',
2313             handler => {
2314             GET => 'handler_get_lock_eid',
2315             },
2316             acl_profile => 'active',
2317             cli => 'lock eid $EID $TSRANGE',
2318             validations => {
2319             'eid' => 'Int',
2320             'tsrange' => $tsrange_validation,
2321             },
2322             description => 'Retrieve an arbitrary employee\'s locks over the given tsrange',
2323             documentation => <<'EOH',
2324             =pod
2325              
2326             With this resource, administrators can retrieve any employee's locks
2327             over a given tsrange.
2328              
2329             There are no syntactical limitations on the tsrange, but if too many records would
2330             be fetched, the return status will be C<DISPATCH_TOO_MANY_RECORDS_FOUND>.
2331             EOH
2332             },
2333              
2334             # /lock/lid
2335             'lock/lid' =>
2336             {
2337             parent => 'lock',
2338             handler => {
2339             POST => 'handler_post_lock_lid',
2340             },
2341             acl_profile => 'admin',
2342             cli => 'lock lid $JSON',
2343             description => 'Update an existing lock object via POST request (lid must be included in request body)',
2344             documentation => <<'EOH',
2345             =pod
2346              
2347             Enables existing lock objects to be updated by sending a POST request to
2348             the REST server. Along with the properties to be modified, the request body
2349             must include an 'lid' property, the value of which specifies the lid to be
2350             updated.
2351             EOH
2352             },
2353              
2354             # /lock/lid/:lid
2355             'lock/lid/:lid' =>
2356             {
2357             parent => 'lock',
2358             handler => {
2359             GET => 'handler_get_lock_lid',
2360             PUT => 'handler_lock_lid',
2361             DELETE => 'handler_lock_lid',
2362             },
2363             acl_profile => {
2364             GET => 'active',
2365             PUT => 'admin',
2366             DELETE => 'admin',
2367             },
2368             cli => 'lock lid $lid [$JSON]',
2369             validations => {
2370             'lid' => 'Int',
2371             },
2372             description => 'GET, PUT, or DELETE an lock object by its LID',
2373             documentation => <<'EOH',
2374             =pod
2375              
2376             This resource makes it possible to GET, PUT, or DELETE an lock object by its
2377             LID.
2378              
2379             =over
2380              
2381             =item * GET
2382              
2383             Retrieves an lock object by its lid.
2384              
2385             =item * PUT
2386              
2387             Updates the lock object whose lid is specified by the ':lid' URI parameter.
2388             The fields to be updated and their new values should be sent in the request
2389             body, e.g., like this:
2390              
2391             {
2392             "eid" : 34,
2393             "intvl" : '[ 2014-11-18 00:00, 2014-11-18 24:00 )'
2394             }
2395              
2396             =item * DELETE
2397              
2398             Deletes the lock object whose lid is specified by the ':lid' URI parameter.
2399              
2400             =back
2401              
2402             ACL note: 'active' employees can view only their own locks, and of course
2403             admin privilege is required to modify or remove a lock.
2404             EOH
2405             },
2406             # /lock/new
2407             'lock/new' =>
2408             {
2409             parent => 'lock',
2410             handler => {
2411             POST => 'handler_lock_new',
2412             },
2413             acl_profile => 'active',
2414             cli => 'lock new $JSON',
2415             description => 'Add a new attendance data lock',
2416             documentation => <<'EOH',
2417             =pod
2418              
2419             This is the resource by which the attendance data entered by an employee
2420             for a given time period can be "locked" to prevent any subsequent
2421             modifications. It takes a request body containing, at the very least, an
2422             C<intvl> property specifying the tsrange to lock. Additionally, administrators
2423             can specify C<remark> and C<eid> properties.
2424             EOH
2425             },
2426              
2427             # /lock/nick/:nick/:tsrange
2428             'lock/nick/:nick/:tsrange' =>
2429             {
2430             parent => 'lock',
2431             handler => {
2432             GET => 'handler_get_lock_nick',
2433             },
2434             acl_profile => 'active',
2435             cli => 'lock nick $NICK $TSRANGE',
2436             validations => {
2437             'nick' => $term_validation,
2438             'tsrange' => $tsrange_validation,
2439             },
2440             description => 'Retrieve an arbitrary employee\'s locks over the given tsrange',
2441             documentation => <<'EOH',
2442             =pod
2443              
2444             With this resource, administrators can retrieve any employee's locks
2445             over a given tsrange.
2446              
2447             There are no syntactical limitations on the tsrange, but if too many records would
2448             be fetched, the return status will be C<DISPATCH_TOO_MANY_RECORDS_FOUND>.
2449             EOH
2450             },
2451              
2452             # /lock/self/:tsrange
2453             'lock/self/:tsrange' =>
2454             {
2455             parent => 'lock',
2456             handler => {
2457             GET => 'handler_get_lock_self',
2458             },
2459             acl_profile => 'inactive',
2460             cli => 'lock self $TSRANGE',
2461             validations => {
2462             'tsrange' => $tsrange_validation,
2463             },
2464             description => 'Retrieve one\'s own locks over the given tsrange',
2465             documentation => <<'EOH',
2466             =pod
2467              
2468             With this resource, employees can retrieve their own attendance locks
2469             over a given tsrange.
2470              
2471             There are no syntactical limitations on the tsrange, but if too many records would
2472             be fetched, the return status will be C<DISPATCH_TOO_MANY_RECORDS_FOUND>.
2473             EOH
2474             },
2475              
2476             };
2477              
2478              
2479             =head2 Priv (non-history) resources
2480              
2481             =cut
2482              
2483             $defs->{'priv'} = {
2484              
2485             # /priv
2486             'priv' =>
2487             {
2488             parent => '/',
2489             handler => 'handler_noop',
2490             acl_profile => 'passerby',
2491             cli => 'priv',
2492             description => 'Privilege resources',
2493             documentation => <<'EOH',
2494             =pod
2495              
2496             This resource presents a list of subresources, all related to employee privileges.
2497             EOH
2498             },
2499              
2500             # /priv/eid/:eid/?:ts
2501             'priv/eid/:eid/?:ts' =>
2502             {
2503             parent => 'priv',
2504             handler => {
2505             GET => 'handler_priv_get_eid',
2506             },
2507             acl_profile => 'passerby',
2508             cli => 'priv eid $EID [$TIMESTAMP]',
2509             validations => {
2510             'eid' => 'Int',
2511             },
2512             description => 'Get the present privlevel of arbitrary employee, or with optional timestamp, that employee\'s privlevel as of that timestamp',
2513             documentation => <<'EOH',
2514             =pod
2515              
2516             This resource retrieves the privlevel of an arbitrary employee specified by EID.
2517              
2518             If no timestamp is given, the present privlevel is retrieved. If a timestamp
2519             is present, the privlevel as of that timestamp is retrieved.
2520             EOH
2521             },
2522              
2523             # /priv/nick/:nick/?:ts
2524             'priv/nick/:nick/?:ts' =>
2525             {
2526             parent => 'priv',
2527             handler => {
2528             GET => 'handler_priv_get_nick',
2529             },
2530             acl_profile => 'passerby',
2531             cli => 'priv nick $NICK [$TIMESTAMP]',
2532             validations => {
2533             'nick' => $term_validation,
2534             },
2535             description => 'Get the present privlevel of arbitrary employee, or with optional timestamp, that employee\'s privlevel as of that timestamp',
2536             documentation => <<'EOH',
2537             =pod
2538              
2539             This resource retrieves the privlevel of an arbitrary employee specified by nick.
2540              
2541             If no timestamp is given, the present privlevel is retrieved. If a timestamp
2542             is present, the privlevel as of that timestamp is retrieved.
2543             EOH
2544             },
2545              
2546             # /priv/self/?:ts
2547             'priv/self/?:ts' =>
2548             {
2549             parent => 'priv',
2550             handler => {
2551             GET => 'handler_priv_get_self',
2552             },
2553             acl_profile => 'passerby',
2554             cli => 'priv self [$TIMESTAMP]',
2555             description => 'Get the present privlevel of the currently logged-in employee, or with optional timestamp, that employee\'s privlevel as of that timestamp',
2556             documentation => <<'EOH',
2557             =pod
2558              
2559             This resource retrieves the privlevel of the caller (currently logged-in employee).
2560              
2561             If no timestamp is given, the present privlevel is retrieved. If a timestamp
2562             is present, the privlevel as of that timestamp is retrieved.
2563             EOH
2564             },
2565              
2566             };
2567              
2568              
2569             =head2 Schedule (non-history) resources
2570              
2571             =cut
2572              
2573             $defs->{'schedule'} = {
2574              
2575             # /schedule
2576             'schedule' =>
2577             {
2578             parent => '/',
2579             handler => 'handler_noop',
2580             acl_profile => 'passerby',
2581             cli => 'schedule',
2582             description => 'Schedule resources',
2583             documentation => <<'EOH',
2584             =pod
2585              
2586             This resource presents a list of "child" resources (subresources), all of which
2587             are related to schedules.
2588             EOH
2589             },
2590              
2591             # /schedule/all
2592             'schedule/all' =>
2593             {
2594             parent => 'schedule',
2595             handler => {
2596             GET => 'handler_schedule_all',
2597             },
2598             acl_profile => 'inactive',
2599             cli => 'schedule all',
2600             description => 'Retrieves (GET) all non-disabled schedules',
2601             documentation => <<'EOH',
2602             =pod
2603              
2604             This resource returns a list (array) of all schedules for which the 'disabled' field has
2605             either not been set or has been set to 'false'.
2606             EOH
2607             },
2608              
2609             # /schedule/all/disabled
2610             'schedule/all/disabled' =>
2611             {
2612             parent => 'schedule/all',
2613             handler => {
2614             GET => 'handler_schedule_all',
2615             },
2616             acl_profile => 'admin',
2617             cli => 'schedule all disabled',
2618             description => 'Retrieves (GET) all schedules (disabled and non-disabled)',
2619             documentation => <<'EOH',
2620             =pod
2621              
2622             This resource returns a list (array) of all schedules, regardless of the contents
2623             of the 'disabled' field.
2624             EOH
2625             },
2626              
2627             # /schedule/eid/:eid/?:ts
2628             'schedule/eid/:eid/?:ts' =>
2629             {
2630             parent => 'schedule',
2631             handler => {
2632             GET => 'handler_get_schedule_eid',
2633             },
2634             acl_profile => 'passerby',
2635             cli => 'schedule eid $EID [$TIMESTAMP]',
2636             validations => {
2637             'eid' => 'Int',
2638             },
2639             description => 'Get the current schedule of arbitrary employee, or with optional timestamp, that employee\'s schedule as of that timestamp',
2640             documentation => <<'EOH',
2641             =pod
2642              
2643             This resource retrieves the schedule of an arbitrary employee specified by EID.
2644              
2645             If no timestamp is given, the current schedule is retrieved. If a timestamp
2646             is present, the schedule as of that timestamp is retrieved.
2647             EOH
2648             },
2649              
2650             # /schedule/new
2651             'schedule/new' =>
2652             {
2653             parent => 'schedule',
2654             handler => {
2655             POST => 'handler_schedule_new',
2656             },
2657             acl_profile => 'admin',
2658             cli => 'schedule new $JSON',
2659             description => 'Insert schedules',
2660             documentation => <<'EOH',
2661             =pod
2662              
2663             Given a set of intervals, all of which must fall within a single contiguous
2664             168-hour (7-day) period, this resource performs all actions necessary to either
2665             create a new schedule from those intervals or verify that an equivalent
2666             schedule already exists.
2667              
2668             Sample JSON:
2669              
2670             { "schedule" : [
2671             "[2014-09-22 08:00, 2014-09-22 12:00)",
2672             "[2014-09-22 12:30, 2014-09-22 16:30)",
2673             "[2014-09-23 08:00, 2014-09-23 12:00)",
2674             "[2014-09-23 12:30, 2014-09-23 16:30)",
2675             "[2014-09-24 08:00, 2014-09-24 12:00)",
2676             "[2014-09-24 12:30, 2014-09-24 16:30)",
2677             "[2014-09-25 08:00, 2014-09-25 12:00)",
2678             "[2014-09-25 12:30, 2014-09-25 16:30)"
2679             ] }
2680              
2681             (Optionally, an scode can be assigned by including an "scode" property.)
2682              
2683             Read on for details:
2684              
2685             First, a set of scratch intervals is created in the 'schedintvls' table.
2686             If this succeeds, an INSERT operation is used to create a new record in the
2687             'schedule' table. This operation has two possible successful outcomes
2688             depending on whether such a schedule already existed in the database, or not.
2689             The status codes for these outcomes are DISPATCH_SCHEDULE_OK and
2690             DISPATCH_SCHEDULE_INSERT_OK, respectively.
2691              
2692             In both cases, the underlying scratch intervals are deleted automatically.
2693             (All operations on the 'schedintlvs' table are supposed to be hidden from
2694             Dochazka clients.)
2695              
2696             Note that many sets of intervals can map to a single schedule (the conversion
2697             process is only interested in the day of the week), so this resource may return
2698             DISPATCH_SCHEDULE_OK more often than you think.
2699              
2700             Whether or not the exact schedule existed already, if the underlying database
2701             operation is successful the payload will contain three properties: 'sid' (the
2702             SID assigned to the schedule containing the intervals), 'intervals' (the
2703             intervals themselves), and 'schedule' (the intervals as they appear after being
2704             converted into the format suitable for insertion into the 'schedule' table).
2705              
2706             N.B. At present there is no way to just check for the existence of a schedule
2707             corresponding to a given set of intervals.
2708             EOH
2709             },
2710              
2711             # /schedule/nick/:nick/?:ts
2712             'schedule/nick/:nick/?:ts' =>
2713             {
2714             parent => 'schedule',
2715             handler => {
2716             GET => 'handler_get_schedule_nick',
2717             },
2718             acl_profile => 'admin',
2719             cli => 'schedule nick $NICK [$TIMESTAMP]',
2720             validations => {
2721             'nick' => $term_validation,
2722             },
2723             description => 'Get the current schedule of arbitrary employee, or with optional timestamp, that employee\'s schedule as of that timestamp',
2724             documentation => <<'EOH',
2725             =pod
2726              
2727             This resource retrieves the schedule of an arbitrary employee specified by nick.
2728              
2729             If no timestamp is given, the current schedule is retrieved. If a timestamp
2730             is present, the schedule as of that timestamp is retrieved.
2731             EOH
2732             },
2733              
2734             # /schedule/scode/:scode
2735             'schedule/scode/:scode' =>
2736             {
2737             parent => 'schedule',
2738             handler => {
2739             GET => 'handler_get_schedule_scode',
2740             PUT => 'handler_put_schedule_scode',
2741             DELETE => 'handler_delete_schedule_scode',
2742             },
2743             acl_profile => {
2744             GET => 'inactive',
2745             PUT => 'admin',
2746             DELETE => 'admin',
2747             },
2748             cli => 'schedule scode $scode',
2749             validations => {
2750             'scode' => qr/^[[:alnum:]_][[:alnum:]_-]*$/,
2751             },
2752             description => 'Retrieves, updates, or deletes a schedule by its scode',
2753             documentation => <<'EOH',
2754             =pod
2755              
2756             This resource makes it possible to GET, PUT, or DELETE a schedule by its scode.
2757              
2758             =over
2759              
2760             =item * GET
2761              
2762             An scode (string) must be given as a URI parameter. If a schedule with this
2763             scode is found (exact, case-sensitive match), it is returned in the payload.
2764              
2765             =item * PUT
2766              
2767             This resource/method provides a way to set (modify) the 'scode', 'remark'
2768             and/or 'disabled' fields of a schedule record. Simply provide the property (or
2769             properties) and the new value(s) in the request body, e.g.:
2770              
2771             { "scode" : "WIGWAM" }
2772              
2773             or
2774              
2775             { "remark" : "foobar", "disabled" : "t" }
2776              
2777             Properties other than these three cannot be modified using this resource.
2778              
2779             =item * DELETE
2780              
2781             The scode must be given as an URI parameter. If found, the schedule with that
2782             scode will be deleted in an atomic operation. If the operation is successful the
2783             return status will be "OK".
2784              
2785             =back
2786             EOH
2787             },
2788              
2789             # /schedule/self/?:ts
2790             'schedule/self/?:ts' =>
2791             {
2792             parent => 'schedule',
2793             handler => {
2794             GET => 'handler_get_schedule_self',
2795             },
2796             acl_profile => 'passerby',
2797             cli => 'schedule current [$TIMESTAMP]',
2798             description => 'Get the current schedule of the currently logged-in employee, or with optional timestamp, that employee\'s schedule as of that timestamp',
2799             documentation => <<'EOH',
2800             =pod
2801              
2802             This resource retrieves the schedule of the caller (currently logged-in employee).
2803              
2804             If no timestamp is given, the current schedule is retrieved. If a timestamp
2805             is present, the schedule as of that timestamp is retrieved.
2806             EOH
2807             },
2808              
2809             # /schedule/sid/:sid
2810             'schedule/sid/:sid' =>
2811             {
2812             parent => 'schedule',
2813             handler => {
2814             GET => 'handler_get_schedule_sid',
2815             PUT => 'handler_put_schedule_sid',
2816             DELETE => 'handler_delete_schedule_sid',
2817             },
2818             acl_profile => {
2819             GET => 'passerby',
2820             PUT => 'admin',
2821             DELETE => 'admin',
2822             },
2823             cli => 'schedule sid $SID',
2824             validations => {
2825             'sid' => 'Int',
2826             },
2827             description => 'Retrieves, updates, or deletes a schedule by its SID',
2828             documentation => <<'EOH',
2829             =pod
2830              
2831             This resource makes it possible to GET, PUT, or DELETE a schedule by its SID.
2832              
2833             =over
2834              
2835             =item * GET
2836              
2837             An integer SID must be given as an URI parameter. If a schedule
2838             with this SID is found, it is returned in the payload.
2839              
2840             =item * PUT
2841              
2842             This resource/method provides a way to set (modify) the 'scode', 'remark'
2843             and/or 'disabled' fields of a schedule record. Simply provide the property (or
2844             properties) and the new value(s) in the request body, e.g.:
2845              
2846             { "scode" : "WIGWAM" }
2847              
2848             or
2849              
2850             { "remark" : "foobar", "disabled" : "t" }
2851              
2852             Properties other than these three cannot be modified using this resource.
2853              
2854             =item * DELETE
2855              
2856             An integer SID must be given as an URI parameter. If found, the schedule with
2857             that SID will be deleted in an atomic operation. If the operation is successful
2858             the return status will be "OK".
2859              
2860             =back
2861             EOH
2862             },
2863              
2864             };
2865              
2866              
2867              
2868             =head1 FUNCTIONS
2869              
2870             =head2 load
2871              
2872             Load all the resource definitions into the L<Path::Router> instance.
2873              
2874             =cut
2875              
2876             sub load {
2877 0     0 1   foreach my $prop ( qw( top activity component employee genreport
2878             history interval lock priv schedule ) ) {
2879 0 0         Web::MREST::InitRouter::load_resource_defs( $defs->{$prop} ) if $defs->{$prop};
2880             }
2881             }
2882              
2883              
2884             1;