line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
# ************************************************************************* |
2
|
|
|
|
|
|
|
# Copyright (c) 2014-2015, 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
|
|
|
|
|
|
|
package App::Dochazka::REST; |
34
|
|
|
|
|
|
|
|
35
|
42
|
|
|
42
|
|
125130
|
use 5.012; |
|
42
|
|
|
|
|
157
|
|
36
|
42
|
|
|
42
|
|
193
|
use strict; |
|
42
|
|
|
|
|
81
|
|
|
42
|
|
|
|
|
752
|
|
37
|
42
|
|
|
42
|
|
180
|
use warnings; |
|
42
|
|
|
|
|
87
|
|
|
42
|
|
|
|
|
1085
|
|
38
|
|
|
|
|
|
|
|
39
|
42
|
|
|
42
|
|
188
|
use App::CELL qw( $CELL $log $meta $core $site ); |
|
42
|
|
|
|
|
83
|
|
|
42
|
|
|
|
|
3967
|
|
40
|
42
|
|
|
42
|
|
3634
|
use App::Dochazka::REST::ConnBank qw( $dbix_conn conn_status ); |
|
42
|
|
|
|
|
85
|
|
|
42
|
|
|
|
|
3397
|
|
41
|
42
|
|
|
42
|
|
256
|
use Data::Dumper; |
|
42
|
|
|
|
|
89
|
|
|
42
|
|
|
|
|
1566
|
|
42
|
42
|
|
|
42
|
|
228
|
use File::Path; |
|
42
|
|
|
|
|
81
|
|
|
42
|
|
|
|
|
1834
|
|
43
|
42
|
|
|
42
|
|
235
|
use File::ShareDir; |
|
42
|
|
|
|
|
71
|
|
|
42
|
|
|
|
|
1234
|
|
44
|
42
|
|
|
42
|
|
240
|
use File::Spec; |
|
42
|
|
|
|
|
74
|
|
|
42
|
|
|
|
|
791
|
|
45
|
42
|
|
|
42
|
|
11846
|
use Log::Any::Adapter; |
|
42
|
|
|
|
|
11022
|
|
|
42
|
|
|
|
|
432
|
|
46
|
42
|
|
|
42
|
|
1130
|
use Params::Validate qw( :all ); |
|
42
|
|
|
|
|
80
|
|
|
42
|
|
|
|
|
5568
|
|
47
|
42
|
|
|
42
|
|
255
|
use Try::Tiny; |
|
42
|
|
|
|
|
81
|
|
|
42
|
|
|
|
|
1703
|
|
48
|
42
|
|
|
42
|
|
10858
|
use Web::Machine; |
|
42
|
|
|
|
|
3336462
|
|
|
42
|
|
|
|
|
1237
|
|
49
|
42
|
|
|
42
|
|
17613
|
use Web::MREST; |
|
42
|
|
|
|
|
42714
|
|
|
42
|
|
|
|
|
2918
|
|
50
|
42
|
|
|
42
|
|
10680
|
use Web::MREST::CLI qw( normalize_filespec ); |
|
42
|
|
|
|
|
4010556
|
|
|
42
|
|
|
|
|
3762
|
|
51
|
|
|
|
|
|
|
|
52
|
|
|
|
|
|
|
|
53
|
|
|
|
|
|
|
|
54
|
|
|
|
|
|
|
=head1 NAME |
55
|
|
|
|
|
|
|
|
56
|
|
|
|
|
|
|
App::Dochazka::REST - Dochazka REST server |
57
|
|
|
|
|
|
|
|
58
|
|
|
|
|
|
|
|
59
|
|
|
|
|
|
|
|
60
|
|
|
|
|
|
|
=head1 VERSION |
61
|
|
|
|
|
|
|
|
62
|
|
|
|
|
|
|
Version 0.557 |
63
|
|
|
|
|
|
|
|
64
|
|
|
|
|
|
|
=cut |
65
|
|
|
|
|
|
|
|
66
|
|
|
|
|
|
|
our $VERSION = '0.557'; |
67
|
|
|
|
|
|
|
|
68
|
|
|
|
|
|
|
|
69
|
|
|
|
|
|
|
=head2 Development status |
70
|
|
|
|
|
|
|
|
71
|
|
|
|
|
|
|
Alpha. |
72
|
|
|
|
|
|
|
|
73
|
|
|
|
|
|
|
|
74
|
|
|
|
|
|
|
|
75
|
|
|
|
|
|
|
=head1 SYNOPSIS |
76
|
|
|
|
|
|
|
|
77
|
|
|
|
|
|
|
Start the server with default settings: |
78
|
|
|
|
|
|
|
|
79
|
|
|
|
|
|
|
$ dochazka-rest |
80
|
|
|
|
|
|
|
|
81
|
|
|
|
|
|
|
Point browser to: |
82
|
|
|
|
|
|
|
|
83
|
|
|
|
|
|
|
http://localhost:5000/ |
84
|
|
|
|
|
|
|
|
85
|
|
|
|
|
|
|
Use L<App::Dochazka::CLI> command-line interface to access full functionality: |
86
|
|
|
|
|
|
|
|
87
|
|
|
|
|
|
|
$ dochazka-cli |
88
|
|
|
|
|
|
|
|
89
|
|
|
|
|
|
|
|
90
|
|
|
|
|
|
|
|
91
|
|
|
|
|
|
|
=head1 DESCRIPTION |
92
|
|
|
|
|
|
|
|
93
|
|
|
|
|
|
|
This distribution, L<App::Dochazka::REST>, including all the modules in C<lib/>, |
94
|
|
|
|
|
|
|
the scripts in C<bin/>, and the configuration files in C<config/>, |
95
|
|
|
|
|
|
|
constitutes the REST server (API) component of Dochazka, the open-source |
96
|
|
|
|
|
|
|
Attendance/Time Tracking (ATT) system. |
97
|
|
|
|
|
|
|
|
98
|
|
|
|
|
|
|
Dochazka as a whole aims to be a convenient, open-source ATT solution. |
99
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
101
|
|
|
|
|
|
|
|
102
|
|
|
|
|
|
|
=head1 ARCHITECTURE |
103
|
|
|
|
|
|
|
|
104
|
|
|
|
|
|
|
Dochazka consists of four main components: |
105
|
|
|
|
|
|
|
|
106
|
|
|
|
|
|
|
=over |
107
|
|
|
|
|
|
|
|
108
|
|
|
|
|
|
|
=item * Dochazka clients |
109
|
|
|
|
|
|
|
|
110
|
|
|
|
|
|
|
=item * REST server (this module) |
111
|
|
|
|
|
|
|
|
112
|
|
|
|
|
|
|
=item * PostgreSQL database |
113
|
|
|
|
|
|
|
|
114
|
|
|
|
|
|
|
=item * Data model |
115
|
|
|
|
|
|
|
|
116
|
|
|
|
|
|
|
=back |
117
|
|
|
|
|
|
|
|
118
|
|
|
|
|
|
|
In a nutshell, clients attempt to translate user intent into REST API |
119
|
|
|
|
|
|
|
calls, which are transmitted over a network (using the HTTP protocol) to |
120
|
|
|
|
|
|
|
the server. The server processes incoming HTTP requests. Requests for |
121
|
|
|
|
|
|
|
valid REST resources are passed to the API for processing and errors are |
122
|
|
|
|
|
|
|
generated for invalid requests. The result is returned to the client in |
123
|
|
|
|
|
|
|
an HTTP response. The REST API uses the PostgreSQL server to save state. |
124
|
|
|
|
|
|
|
The clients and the REST API use the data model to represent and manipulate |
125
|
|
|
|
|
|
|
objects. |
126
|
|
|
|
|
|
|
|
127
|
|
|
|
|
|
|
|
128
|
|
|
|
|
|
|
|
129
|
|
|
|
|
|
|
=head1 DOCUMENTATION |
130
|
|
|
|
|
|
|
|
131
|
|
|
|
|
|
|
=over |
132
|
|
|
|
|
|
|
|
133
|
|
|
|
|
|
|
=item * L<App::Dochazka::REST::Guide> |
134
|
|
|
|
|
|
|
|
135
|
|
|
|
|
|
|
A detailed guide to the REST server. |
136
|
|
|
|
|
|
|
|
137
|
|
|
|
|
|
|
=item * L<App::Dochazka::REST::Docs::Resources> |
138
|
|
|
|
|
|
|
|
139
|
|
|
|
|
|
|
Dochazka REST API documentation. |
140
|
|
|
|
|
|
|
|
141
|
|
|
|
|
|
|
=item * L<App::Dochazka::Common> |
142
|
|
|
|
|
|
|
|
143
|
|
|
|
|
|
|
Dochazka data model and other bits used by all Dochazka components. |
144
|
|
|
|
|
|
|
|
145
|
|
|
|
|
|
|
=item * L<App::Dochazka::CLI> and L<App::Dochazka::CLI::Guide> |
146
|
|
|
|
|
|
|
|
147
|
|
|
|
|
|
|
Reference Dochazka command-line client. |
148
|
|
|
|
|
|
|
|
149
|
|
|
|
|
|
|
=item * L<App::Dochazka::WWW> |
150
|
|
|
|
|
|
|
|
151
|
|
|
|
|
|
|
Reference Dochazka WWW client. |
152
|
|
|
|
|
|
|
|
153
|
|
|
|
|
|
|
=over |
154
|
|
|
|
|
|
|
|
155
|
|
|
|
|
|
|
|
156
|
|
|
|
|
|
|
|
157
|
|
|
|
|
|
|
|
158
|
|
|
|
|
|
|
=head1 EXPORTS |
159
|
|
|
|
|
|
|
|
160
|
|
|
|
|
|
|
=cut |
161
|
|
|
|
|
|
|
|
162
|
42
|
|
|
42
|
|
413
|
use Exporter qw( import ); |
|
42
|
|
|
|
|
136
|
|
|
42
|
|
|
|
|
62115
|
|
163
|
|
|
|
|
|
|
our @EXPORT_OK = qw( init_arbitrary_script $faux_context ); |
164
|
|
|
|
|
|
|
our $faux_context; |
165
|
|
|
|
|
|
|
|
166
|
|
|
|
|
|
|
|
167
|
|
|
|
|
|
|
|
168
|
|
|
|
|
|
|
=head1 FUNCTIONS |
169
|
|
|
|
|
|
|
|
170
|
|
|
|
|
|
|
|
171
|
|
|
|
|
|
|
=head2 run_sql |
172
|
|
|
|
|
|
|
|
173
|
|
|
|
|
|
|
Takes a L<DBIx::Connector> object and an array of SQL statements. Runs them |
174
|
|
|
|
|
|
|
one by one until an exception is thrown or the last statement completes |
175
|
|
|
|
|
|
|
successfully. Returns a status object which will be either OK or ERR. |
176
|
|
|
|
|
|
|
If NOT_OK, the error text will be in C<< $status->text >>. |
177
|
|
|
|
|
|
|
|
178
|
|
|
|
|
|
|
=cut |
179
|
|
|
|
|
|
|
|
180
|
|
|
|
|
|
|
sub run_sql { |
181
|
0
|
|
|
0
|
1
|
0
|
my ( $conn, @stmts ) = @_; |
182
|
0
|
|
|
|
|
0
|
my $status; |
183
|
|
|
|
|
|
|
try { |
184
|
0
|
|
|
0
|
|
0
|
foreach my $stmt ( @stmts ) { |
185
|
0
|
|
|
|
|
0
|
$log->debug( "Running SQL statement $stmt" ); |
186
|
0
|
|
|
|
|
0
|
$conn->run( fixup => sub { $_->do( $stmt ); } ); |
|
0
|
|
|
|
|
0
|
|
187
|
|
|
|
|
|
|
} |
188
|
|
|
|
|
|
|
} catch { |
189
|
0
|
|
|
0
|
|
0
|
$status = $CELL->status_err( 'DOCHAZKA_DBI_ERR', args => [ $_ ] ); |
190
|
0
|
|
|
|
|
0
|
}; |
191
|
0
|
0
|
|
|
|
0
|
return $status if $status; |
192
|
0
|
|
|
|
|
0
|
return $CELL->status_ok; |
193
|
|
|
|
|
|
|
} |
194
|
|
|
|
|
|
|
|
195
|
|
|
|
|
|
|
|
196
|
|
|
|
|
|
|
sub _do_audit_triggers { |
197
|
0
|
|
|
0
|
|
0
|
my ( $mode, $conn ) = @_; |
198
|
|
|
|
|
|
|
|
199
|
0
|
|
|
|
|
0
|
my $sql; |
200
|
0
|
0
|
|
|
|
0
|
if ( $mode eq 'create' ) { |
|
|
0
|
|
|
|
|
|
201
|
0
|
|
|
|
|
0
|
$sql = $site->DBINIT_CREATE_AUDIT_TRIGGERS; |
202
|
|
|
|
|
|
|
} elsif ( $mode eq 'delete' ) { |
203
|
0
|
|
|
|
|
0
|
$sql = $site->DBINIT_DELETE_AUDIT_TRIGGERS; |
204
|
|
|
|
|
|
|
} else { |
205
|
0
|
|
|
|
|
0
|
die "AAADFDGGGGGGAAAAAAAHHH! " . __PACKAGE__ . "::_do_audit_triggers"; |
206
|
|
|
|
|
|
|
} |
207
|
|
|
|
|
|
|
|
208
|
0
|
|
|
|
|
0
|
my @prepped_sql; |
209
|
0
|
|
|
|
|
0
|
foreach my $table ( @{ $site->DOCHAZKA_AUDIT_TABLES } ) { |
|
0
|
|
|
|
|
0
|
|
210
|
0
|
|
|
|
|
0
|
my $sql_copy = $sql; |
211
|
0
|
|
|
|
|
0
|
my $question_mark = quotemeta('?'); |
212
|
0
|
|
|
|
|
0
|
$log->debug( "Replacing question mark with $table" ); |
213
|
0
|
|
|
|
|
0
|
$sql_copy =~ s{$question_mark}{$table}; |
214
|
0
|
|
|
|
|
0
|
push( @prepped_sql, $sql_copy ); |
215
|
|
|
|
|
|
|
} |
216
|
0
|
|
|
|
|
0
|
my $status = run_sql( |
217
|
|
|
|
|
|
|
$conn, |
218
|
|
|
|
|
|
|
@prepped_sql, |
219
|
|
|
|
|
|
|
); |
220
|
0
|
|
|
|
|
0
|
return $status; |
221
|
|
|
|
|
|
|
} |
222
|
|
|
|
|
|
|
|
223
|
|
|
|
|
|
|
|
224
|
|
|
|
|
|
|
=head2 create_audit_triggers |
225
|
|
|
|
|
|
|
|
226
|
|
|
|
|
|
|
Create the audit triggers. Wrapper for _do_audit_triggers |
227
|
|
|
|
|
|
|
|
228
|
|
|
|
|
|
|
=cut |
229
|
|
|
|
|
|
|
|
230
|
|
|
|
|
|
|
sub create_audit_triggers { |
231
|
0
|
|
|
0
|
1
|
0
|
my $conn = shift; |
232
|
0
|
|
|
|
|
0
|
return _do_audit_triggers( 'create', $conn ); |
233
|
|
|
|
|
|
|
} |
234
|
|
|
|
|
|
|
|
235
|
|
|
|
|
|
|
|
236
|
|
|
|
|
|
|
=head2 delete_audit_triggers |
237
|
|
|
|
|
|
|
|
238
|
|
|
|
|
|
|
Delete the audit triggers. Wrapper for _do_audit_triggers |
239
|
|
|
|
|
|
|
|
240
|
|
|
|
|
|
|
=cut |
241
|
|
|
|
|
|
|
|
242
|
|
|
|
|
|
|
sub delete_audit_triggers { |
243
|
0
|
|
|
0
|
1
|
0
|
my $conn = shift; |
244
|
0
|
|
|
|
|
0
|
return _do_audit_triggers( 'delete', $conn ); |
245
|
|
|
|
|
|
|
} |
246
|
|
|
|
|
|
|
|
247
|
|
|
|
|
|
|
|
248
|
|
|
|
|
|
|
=head2 reset_mason_dir |
249
|
|
|
|
|
|
|
|
250
|
|
|
|
|
|
|
Wipe out and re-create the Mason state directory. Returns status object. |
251
|
|
|
|
|
|
|
Upon success, level will be 'OK' and payload will contain the full path |
252
|
|
|
|
|
|
|
to the Mason component root. |
253
|
|
|
|
|
|
|
|
254
|
|
|
|
|
|
|
=cut |
255
|
|
|
|
|
|
|
|
256
|
|
|
|
|
|
|
sub reset_mason_dir { |
257
|
39
|
|
|
39
|
1
|
77
|
my $status; |
258
|
|
|
|
|
|
|
|
259
|
39
|
|
|
|
|
226
|
$log->info( "Checking permissions of Mason directory (DOCHAZKA_STATE_DIR)" ); |
260
|
39
|
|
|
|
|
3188
|
my $statedir = $site->DOCHAZKA_STATE_DIR; |
261
|
39
|
50
|
|
|
|
940
|
die "OUCH!!! DOCHAZKA_STATE_DIR site parameter not defined!" unless $statedir; |
262
|
39
|
50
|
|
|
|
912
|
die "OUCH!!! DOCHAZKA_STATE_DIR $statedir is not readable by me!" unless -r $statedir; |
263
|
0
|
0
|
|
|
|
|
die "OUCH!!! DOCHAZKA_STATE_DIR $statedir is not writable by me!" unless -w $statedir; |
264
|
0
|
0
|
|
|
|
|
die "OUCH!!! DOCHAZKA_STATE_DIR $statedir is not executable by me!" unless -x $statedir; |
265
|
0
|
|
|
|
|
|
my $masondir = File::Spec->catfile( $statedir, 'Mason' ); |
266
|
0
|
|
|
|
|
|
$log->debug( "Mason directory is $masondir" ); |
267
|
0
|
|
|
|
|
|
rmtree( $masondir ); |
268
|
0
|
|
|
|
|
|
mkpath( $masondir, 0, 0750 ); |
269
|
|
|
|
|
|
|
|
270
|
|
|
|
|
|
|
# re-create |
271
|
0
|
|
|
|
|
|
my $comp_root = File::Spec->catfile( $masondir, 'comp_root' ); |
272
|
0
|
|
|
|
|
|
mkpath( $comp_root, 0, 0750 ); |
273
|
0
|
|
|
|
|
|
my $data_dir = File::Spec->catfile( $masondir, 'data_dir' ); |
274
|
0
|
|
|
|
|
|
mkpath( $data_dir, 0, 0750 ); |
275
|
0
|
|
|
|
|
|
$status = App::Dochazka::REST::Mason::init_singleton( |
276
|
|
|
|
|
|
|
comp_root => $comp_root, |
277
|
|
|
|
|
|
|
data_dir => $data_dir |
278
|
|
|
|
|
|
|
); |
279
|
0
|
0
|
|
|
|
|
return $status unless $status->ok; |
280
|
0
|
|
|
|
|
|
$status->payload( $comp_root ); |
281
|
0
|
|
|
|
|
|
return $status; |
282
|
|
|
|
|
|
|
} |
283
|
|
|
|
|
|
|
|
284
|
|
|
|
|
|
|
|
285
|
|
|
|
|
|
|
=head2 initialize_activities_table |
286
|
|
|
|
|
|
|
|
287
|
|
|
|
|
|
|
Create the activities defined in the site parameter |
288
|
|
|
|
|
|
|
DOCHAZKA_ACTIVITY_DEFINITIONS |
289
|
|
|
|
|
|
|
|
290
|
|
|
|
|
|
|
=cut |
291
|
|
|
|
|
|
|
|
292
|
|
|
|
|
|
|
sub initialize_activities_table { |
293
|
0
|
|
|
0
|
1
|
|
my $conn = shift; |
294
|
0
|
|
|
|
|
|
my $status = $CELL->status_ok; |
295
|
|
|
|
|
|
|
try { |
296
|
|
|
|
|
|
|
$conn->txn( fixup => sub { |
297
|
0
|
|
|
|
|
|
my $sth = $_->prepare( $site->SQL_ACTIVITY_INSERT ); |
298
|
0
|
|
|
|
|
|
foreach my $actdef ( @{ $site->DOCHAZKA_ACTIVITY_DEFINITIONS } ) { |
|
0
|
|
|
|
|
|
|
299
|
0
|
|
|
|
|
|
$sth->bind_param( 1, $actdef->{code} ); |
300
|
0
|
|
|
|
|
|
$sth->bind_param( 2, $actdef->{long_desc} ); |
301
|
0
|
|
|
|
|
|
$sth->bind_param( 3, 'dbinit' ); |
302
|
0
|
|
|
|
|
|
$sth->execute; |
303
|
|
|
|
|
|
|
} |
304
|
0
|
|
|
0
|
|
|
} ); |
305
|
|
|
|
|
|
|
} catch { |
306
|
0
|
|
|
0
|
|
|
$status = $CELL->status_err( 'DOCHAZKA_DBI_ERR', args => [ $_ ] ); |
307
|
0
|
|
|
|
|
|
}; |
308
|
0
|
|
|
|
|
|
return $status; |
309
|
|
|
|
|
|
|
} |
310
|
|
|
|
|
|
|
|
311
|
|
|
|
|
|
|
|
312
|
|
|
|
|
|
|
=head2 reset_db |
313
|
|
|
|
|
|
|
|
314
|
|
|
|
|
|
|
Drop and re-create a Dochazka database. Takes superuser credentials as |
315
|
|
|
|
|
|
|
arguments. |
316
|
|
|
|
|
|
|
|
317
|
|
|
|
|
|
|
Be very, _very_, _VERY_ careful with this function. |
318
|
|
|
|
|
|
|
|
319
|
|
|
|
|
|
|
=cut |
320
|
|
|
|
|
|
|
|
321
|
|
|
|
|
|
|
sub reset_db { |
322
|
|
|
|
|
|
|
|
323
|
0
|
|
|
0
|
1
|
|
my $status; |
324
|
0
|
|
|
|
|
|
my $dbname = $site->DOCHAZKA_DBNAME; |
325
|
0
|
|
|
|
|
|
my $dbuser = $site->DOCHAZKA_DBUSER; |
326
|
0
|
|
|
|
|
|
my $dbpass = $site->DOCHAZKA_DBPASS; |
327
|
0
|
|
|
|
|
|
$log->debug( "Entering " . __PACKAGE__ . "::reset_db to initialize database $dbname with credentials $dbuser / $dbpass" ); |
328
|
|
|
|
|
|
|
|
329
|
|
|
|
|
|
|
# PGTZ *must* be set |
330
|
0
|
|
|
|
|
|
$ENV{'PGTZ'} = $site->DOCHAZKA_TIMEZONE; |
331
|
|
|
|
|
|
|
|
332
|
|
|
|
|
|
|
# create: |
333
|
|
|
|
|
|
|
# - audit schema (see config/sql/audit_Config.pm) |
334
|
|
|
|
|
|
|
# - public schema (all application-specific tables, functions, triggers, etc.) |
335
|
|
|
|
|
|
|
# - the 'root' and 'demo' employees |
336
|
|
|
|
|
|
|
# - privhistory record for root |
337
|
0
|
|
|
|
|
|
print "Getting database connection..."; |
338
|
0
|
|
|
|
|
|
my $conn = App::Dochazka::REST::ConnBank::get_arbitrary_dbix_conn( |
339
|
|
|
|
|
|
|
$dbname, $dbuser, $dbpass |
340
|
|
|
|
|
|
|
); |
341
|
0
|
|
|
|
|
|
print "done\n"; |
342
|
|
|
|
|
|
|
|
343
|
0
|
|
|
|
|
|
print "Initializing audit schema..."; |
344
|
|
|
|
|
|
|
$status = run_sql( |
345
|
|
|
|
|
|
|
$conn, |
346
|
0
|
|
|
|
|
|
@{ $site->DBINIT_AUDIT }, |
|
0
|
|
|
|
|
|
|
347
|
|
|
|
|
|
|
); |
348
|
0
|
0
|
|
|
|
|
if ( $status->not_ok ) { |
349
|
0
|
|
|
|
|
|
print Dumper( $status ), "\n"; |
350
|
0
|
|
|
|
|
|
return $status; |
351
|
|
|
|
|
|
|
} |
352
|
0
|
|
|
|
|
|
print "done\n"; |
353
|
|
|
|
|
|
|
|
354
|
0
|
|
|
|
|
|
print "Initializing public schema..."; |
355
|
|
|
|
|
|
|
$status = run_sql( |
356
|
|
|
|
|
|
|
$conn, |
357
|
0
|
|
|
|
|
|
@{ $site->DBINIT_CREATE }, |
|
0
|
|
|
|
|
|
|
358
|
|
|
|
|
|
|
); |
359
|
0
|
0
|
|
|
|
|
if ( $status->not_ok ) { |
360
|
0
|
|
|
|
|
|
print Dumper( $status ), "\n"; |
361
|
0
|
|
|
|
|
|
return $status; |
362
|
|
|
|
|
|
|
} |
363
|
0
|
|
|
|
|
|
print "done\n"; |
364
|
|
|
|
|
|
|
|
365
|
|
|
|
|
|
|
# get EID of root employee that was just created, since |
366
|
|
|
|
|
|
|
# we will need it in the second round of SQL statements |
367
|
0
|
|
|
|
|
|
my $eids = get_eid_of( $conn, "root", "demo" ); |
368
|
0
|
|
|
|
|
|
$site->set( 'DOCHAZKA_EID_OF_ROOT', $eids->{'root'} ); |
369
|
0
|
|
|
|
|
|
$site->set( 'DOCHAZKA_EID_OF_DEMO', $eids->{'demo'} ); |
370
|
|
|
|
|
|
|
|
371
|
|
|
|
|
|
|
# the second round of SQL statements to make root employee immutable |
372
|
|
|
|
|
|
|
# is taken from DBINIT_MAKE_ROOT_IMMUTABLE site param |
373
|
|
|
|
|
|
|
|
374
|
|
|
|
|
|
|
# prep DBINIT_MAKE_ROOT_IMMUTABLE |
375
|
|
|
|
|
|
|
# (replace ? with EID of root employee in all the statements |
376
|
|
|
|
|
|
|
# N.B.: we avoid the /r modifier here because we might be using Perl # 5.012) |
377
|
|
|
|
|
|
|
my @root_immutable_statements = map { |
378
|
0
|
|
|
|
|
|
local $_ = $_; s/\?/$eids->{'root'}/g; $_; |
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
379
|
0
|
|
|
|
|
|
} @{ $site->DBINIT_MAKE_ROOT_IMMUTABLE }; |
|
0
|
|
|
|
|
|
|
380
|
|
|
|
|
|
|
|
381
|
|
|
|
|
|
|
# run the modified statements |
382
|
0
|
|
|
|
|
|
$status = run_sql( |
383
|
|
|
|
|
|
|
$conn, |
384
|
|
|
|
|
|
|
@root_immutable_statements, |
385
|
|
|
|
|
|
|
); |
386
|
0
|
0
|
|
|
|
|
return $status unless $status->ok; |
387
|
|
|
|
|
|
|
|
388
|
|
|
|
|
|
|
# insert initial set of activities |
389
|
0
|
|
|
|
|
|
$status = initialize_activities_table( $conn ); |
390
|
|
|
|
|
|
|
|
391
|
|
|
|
|
|
|
# insert initial set of components |
392
|
|
|
|
|
|
|
try { |
393
|
|
|
|
|
|
|
$conn->txn( fixup => sub { |
394
|
0
|
|
|
|
|
|
my $sth = $_->prepare( $site->SQL_COMPONENT_INSERT ); |
395
|
0
|
|
|
|
|
|
foreach my $actdef ( @{ $site->DOCHAZKA_COMPONENT_DEFINITIONS } ) { |
|
0
|
|
|
|
|
|
|
396
|
0
|
0
|
|
|
|
|
$actdef->{'validations'} = undef unless exists( $actdef->{'validations'} ); |
397
|
0
|
|
|
|
|
|
$sth->bind_param( 1, $actdef->{path} ); |
398
|
0
|
|
|
|
|
|
$sth->bind_param( 2, $actdef->{source} ); |
399
|
0
|
|
|
|
|
|
$sth->bind_param( 3, $actdef->{acl} ); |
400
|
0
|
|
|
|
|
|
$sth->bind_param( 4, $actdef->{validations} ); |
401
|
0
|
|
|
|
|
|
$sth->execute; |
402
|
|
|
|
|
|
|
} |
403
|
0
|
|
|
0
|
|
|
} ); |
404
|
|
|
|
|
|
|
} catch { |
405
|
0
|
|
|
0
|
|
|
$status = $CELL->status_err( 'DOCHAZKA_DBI_ERR', args => [ $_ ] ); |
406
|
0
|
|
|
|
|
|
}; |
407
|
0
|
0
|
|
|
|
|
return $status unless $status->ok; |
408
|
|
|
|
|
|
|
|
409
|
|
|
|
|
|
|
# if auditing is enabled, create the audit triggers |
410
|
0
|
0
|
|
|
|
|
if ( $site->DOCHAZKA_AUDITING ) { |
411
|
0
|
|
|
|
|
|
$status = create_audit_triggers( $conn ); |
412
|
0
|
0
|
|
|
|
|
return $status unless $status->ok; |
413
|
|
|
|
|
|
|
} |
414
|
|
|
|
|
|
|
|
415
|
0
|
|
|
|
|
|
$log->notice( "Database $dbname successfully (re-)initialized" ); |
416
|
0
|
|
|
|
|
|
return $status; |
417
|
|
|
|
|
|
|
} |
418
|
|
|
|
|
|
|
|
419
|
|
|
|
|
|
|
|
420
|
|
|
|
|
|
|
=head2 get_eid_of |
421
|
|
|
|
|
|
|
|
422
|
|
|
|
|
|
|
Obtain the EIDs of a list of employee nicks. Returns a reference to a hash |
423
|
|
|
|
|
|
|
where the keys are the nicks and the values are the corresponding EIDs. |
424
|
|
|
|
|
|
|
|
425
|
|
|
|
|
|
|
NOTE 1: This routine expects to receive a L<DBIx::Connector> object as its |
426
|
|
|
|
|
|
|
first argument. It does not use the C<$dbix_conn> singleton. |
427
|
|
|
|
|
|
|
|
428
|
|
|
|
|
|
|
NOTE 2: The nicks are expected to exist and no provision (other than logging a |
429
|
|
|
|
|
|
|
DOCHAZKA_DBI_ERR) is made for their non-existence. |
430
|
|
|
|
|
|
|
|
431
|
|
|
|
|
|
|
=cut |
432
|
|
|
|
|
|
|
|
433
|
|
|
|
|
|
|
sub get_eid_of { |
434
|
0
|
|
|
0
|
1
|
|
my ( $conn, @nicks ) = @_; |
435
|
0
|
|
|
|
|
|
$log->debug( "Entering " . __PACKAGE__ . "::get_eid_of" ); |
436
|
0
|
|
|
|
|
|
my ( %eids, $status ); |
437
|
0
|
|
|
|
|
|
$status = $CELL->status_ok; |
438
|
|
|
|
|
|
|
try { |
439
|
|
|
|
|
|
|
$conn->run( fixup => sub { |
440
|
0
|
|
|
|
|
|
my $sth = $_->prepare( $site->DBINIT_SELECT_EID_OF ); |
441
|
0
|
|
|
|
|
|
foreach my $nick ( @nicks ) { |
442
|
0
|
|
|
|
|
|
$sth->bind_param( 1, $nick ); |
443
|
0
|
|
|
|
|
|
$sth->execute; |
444
|
0
|
|
|
|
|
|
( $eids{$nick} ) = $sth->fetchrow_array(); |
445
|
0
|
|
|
|
|
|
$log->debug( "EID of $nick is $eids{$nick}" ); |
446
|
|
|
|
|
|
|
} |
447
|
0
|
|
|
0
|
|
|
} ); |
448
|
|
|
|
|
|
|
} catch { |
449
|
0
|
|
|
0
|
|
|
$status = $CELL->status_err( 'DOCHAZKA_DBI_ERR', args => [ $_ ] ); |
450
|
0
|
|
|
|
|
|
}; |
451
|
0
|
0
|
|
|
|
|
die $status->text unless $status->ok; |
452
|
0
|
|
|
|
|
|
return \%eids; |
453
|
|
|
|
|
|
|
} |
454
|
|
|
|
|
|
|
|
455
|
|
|
|
|
|
|
|
456
|
|
|
|
|
|
|
=head2 version |
457
|
|
|
|
|
|
|
|
458
|
|
|
|
|
|
|
Accessor method (to be called like a constructor) providing access to C<$VERSION> variable |
459
|
|
|
|
|
|
|
|
460
|
|
|
|
|
|
|
=cut |
461
|
|
|
|
|
|
|
|
462
|
0
|
|
|
0
|
1
|
|
sub version { $VERSION; } |
463
|
|
|
|
|
|
|
|
464
|
|
|
|
|
|
|
|
465
|
|
|
|
|
|
|
|
466
|
|
|
|
|
|
|
=head2 init_arbitrary_script |
467
|
|
|
|
|
|
|
|
468
|
|
|
|
|
|
|
For scripts that need to manipulate the database directly (i.e. via the data |
469
|
|
|
|
|
|
|
model). |
470
|
|
|
|
|
|
|
|
471
|
|
|
|
|
|
|
=cut |
472
|
|
|
|
|
|
|
|
473
|
|
|
|
|
|
|
sub init_arbitrary_script { |
474
|
0
|
|
|
0
|
1
|
|
my ( $ARGS ) = @_; |
475
|
0
|
|
|
|
|
|
my $quiet = 0; |
476
|
0
|
0
|
0
|
|
|
|
if ( ref( $ARGS ) eq 'HASH' and exists( $ARGS->{quiet} ) ) { |
477
|
0
|
|
|
|
|
|
$quiet = $ARGS->{quiet}; |
478
|
|
|
|
|
|
|
} |
479
|
0
|
|
|
|
|
|
my $app_distro = 'App-Dochazka-REST'; |
480
|
0
|
|
|
|
|
|
my $sitedir = '/etc/dochazka-rest'; |
481
|
0
|
0
|
|
|
|
|
print "Loading configuration parameters from $sitedir\n" unless $quiet; |
482
|
0
|
|
|
|
|
|
my $status = Web::MREST::init( |
483
|
|
|
|
|
|
|
distro => $app_distro, |
484
|
|
|
|
|
|
|
sitedir => $sitedir, |
485
|
|
|
|
|
|
|
); |
486
|
0
|
0
|
|
|
|
|
die $status->text unless $status->ok; |
487
|
|
|
|
|
|
|
|
488
|
0
|
0
|
|
|
|
|
print "Setting up logging\n" unless $quiet; |
489
|
0
|
|
|
|
|
|
my $log_file = normalize_filespec( $site->MREST_LOG_FILE ); |
490
|
0
|
|
|
|
|
|
my $should_reset = $site->MREST_LOG_FILE_RESET; |
491
|
0
|
0
|
|
|
|
|
unlink $log_file if $should_reset; |
492
|
0
|
|
|
|
|
|
Log::Any::Adapter->set( 'File', $log_file ); |
493
|
0
|
|
|
|
|
|
my $message = "Logging to $log_file"; |
494
|
0
|
0
|
|
|
|
|
print "$message\n" unless $quiet; |
495
|
0
|
|
|
|
|
|
$log->info( $message ); |
496
|
0
|
0
|
|
|
|
|
if ( ! $site->MREST_APPNAME ) { |
497
|
0
|
|
|
|
|
|
die "Site parameter MREST_APPNAME is undefined - please investigate!"; |
498
|
|
|
|
|
|
|
} |
499
|
|
|
|
|
|
|
$log->init( |
500
|
0
|
|
0
|
|
|
|
ident => $site->MREST_APPNAME, |
501
|
|
|
|
|
|
|
debug_mode => ( $site->MREST_DEBUG_MODE || 0 ), |
502
|
|
|
|
|
|
|
); |
503
|
|
|
|
|
|
|
|
504
|
0
|
0
|
|
|
|
|
print "Connecting to database\n" unless $quiet; |
505
|
0
|
|
|
|
|
|
App::Dochazka::REST::ConnBank::init_singleton(); |
506
|
0
|
0
|
|
|
|
|
print "Database is " . conn_status() . "\n" unless $quiet; |
507
|
|
|
|
|
|
|
|
508
|
0
|
|
|
|
|
|
$faux_context = { 'dbix_conn' => $dbix_conn, 'current' => { 'eid' => 1 } }; |
509
|
|
|
|
|
|
|
} |
510
|
|
|
|
|
|
|
|
511
|
|
|
|
|
|
|
|
512
|
|
|
|
|
|
|
|
513
|
|
|
|
|
|
|
=head1 GLOSSARY OF TERMS |
514
|
|
|
|
|
|
|
|
515
|
|
|
|
|
|
|
In Dochazka, some commonly-used terms have special meanings: |
516
|
|
|
|
|
|
|
|
517
|
|
|
|
|
|
|
=over |
518
|
|
|
|
|
|
|
|
519
|
|
|
|
|
|
|
=item * B<employee> -- |
520
|
|
|
|
|
|
|
Regardless of whether they are employees in reality, for the |
521
|
|
|
|
|
|
|
purposes of Dochazka employees are the folks whose attendance/time is being |
522
|
|
|
|
|
|
|
tracked. Employees are expected to interact with Dochazka using the |
523
|
|
|
|
|
|
|
following functions and commands. |
524
|
|
|
|
|
|
|
|
525
|
|
|
|
|
|
|
=item * B<administrator> -- |
526
|
|
|
|
|
|
|
In Dochazka, administrators are employees with special powers. Certain |
527
|
|
|
|
|
|
|
REST/CLI functions are available only to administrators. |
528
|
|
|
|
|
|
|
|
529
|
|
|
|
|
|
|
=item * B<CLI client> -- |
530
|
|
|
|
|
|
|
CLI stands for Command-Line Interface. The CLI client is the Perl script |
531
|
|
|
|
|
|
|
that is run when an employee types C<dochazka> at the bash prompt. |
532
|
|
|
|
|
|
|
|
533
|
|
|
|
|
|
|
=item * B<REST server> -- |
534
|
|
|
|
|
|
|
REST stands for ... . The REST server is a collection of Perl modules |
535
|
|
|
|
|
|
|
running on a server at the site. |
536
|
|
|
|
|
|
|
|
537
|
|
|
|
|
|
|
=item * B<site> -- |
538
|
|
|
|
|
|
|
In a general sense, the "site" is the company, organization, or place that |
539
|
|
|
|
|
|
|
has implemented (installed, configured) Dochazka for attendance/time |
540
|
|
|
|
|
|
|
tracking. In a technical sense, a site is a specific instance of the |
541
|
|
|
|
|
|
|
Dochazka REST server that CLI clients connect to. |
542
|
|
|
|
|
|
|
|
543
|
|
|
|
|
|
|
=back |
544
|
|
|
|
|
|
|
|
545
|
|
|
|
|
|
|
|
546
|
|
|
|
|
|
|
|
547
|
|
|
|
|
|
|
=head1 AUTHOR |
548
|
|
|
|
|
|
|
|
549
|
|
|
|
|
|
|
Nathan Cutler, C<< <ncutler@suse.cz> >> |
550
|
|
|
|
|
|
|
|
551
|
|
|
|
|
|
|
|
552
|
|
|
|
|
|
|
|
553
|
|
|
|
|
|
|
|
554
|
|
|
|
|
|
|
=head1 BUGS |
555
|
|
|
|
|
|
|
|
556
|
|
|
|
|
|
|
To report bugs or request features, use the GitHub issue tracker at |
557
|
|
|
|
|
|
|
L<https://github.com/smithfarm/dochazka-rest/issues>. |
558
|
|
|
|
|
|
|
|
559
|
|
|
|
|
|
|
|
560
|
|
|
|
|
|
|
|
561
|
|
|
|
|
|
|
|
562
|
|
|
|
|
|
|
=head1 SUPPORT |
563
|
|
|
|
|
|
|
|
564
|
|
|
|
|
|
|
The full documentation comes with the distro, and can be comfortable |
565
|
|
|
|
|
|
|
perused at metacpan.org: |
566
|
|
|
|
|
|
|
|
567
|
|
|
|
|
|
|
https://metacpan.org/pod/App::Dochazka::REST |
568
|
|
|
|
|
|
|
|
569
|
|
|
|
|
|
|
You can also read the documentation for individual modules using the |
570
|
|
|
|
|
|
|
perldoc command, e.g.: |
571
|
|
|
|
|
|
|
|
572
|
|
|
|
|
|
|
perldoc App::Dochazka::REST |
573
|
|
|
|
|
|
|
perldoc App::Dochazka::REST::Model::Activity |
574
|
|
|
|
|
|
|
|
575
|
|
|
|
|
|
|
Other resources: |
576
|
|
|
|
|
|
|
|
577
|
|
|
|
|
|
|
=over 4 |
578
|
|
|
|
|
|
|
|
579
|
|
|
|
|
|
|
=item * GitHub issue tracker (report bugs here) |
580
|
|
|
|
|
|
|
|
581
|
|
|
|
|
|
|
L<https://github.com/smithfarm/dochazka-rest> |
582
|
|
|
|
|
|
|
|
583
|
|
|
|
|
|
|
=item * AnnoCPAN: Annotated CPAN documentation |
584
|
|
|
|
|
|
|
|
585
|
|
|
|
|
|
|
L<http://annocpan.org/dist/App-Dochazka-REST> |
586
|
|
|
|
|
|
|
|
587
|
|
|
|
|
|
|
=back |
588
|
|
|
|
|
|
|
|
589
|
|
|
|
|
|
|
|
590
|
|
|
|
|
|
|
|
591
|
|
|
|
|
|
|
|
592
|
|
|
|
|
|
|
=head1 LICENSE AND COPYRIGHT |
593
|
|
|
|
|
|
|
|
594
|
|
|
|
|
|
|
Copyright (c) 2014-2015, SUSE LLC |
595
|
|
|
|
|
|
|
All rights reserved. |
596
|
|
|
|
|
|
|
|
597
|
|
|
|
|
|
|
Redistribution and use in source and binary forms, with or without |
598
|
|
|
|
|
|
|
modification, are permitted provided that the following conditions are met: |
599
|
|
|
|
|
|
|
|
600
|
|
|
|
|
|
|
1. Redistributions of source code must retain the above copyright notice, this |
601
|
|
|
|
|
|
|
list of conditions and the following disclaimer. |
602
|
|
|
|
|
|
|
|
603
|
|
|
|
|
|
|
2. Redistributions in binary form must reproduce the above copyright notice, |
604
|
|
|
|
|
|
|
this list of conditions and the following disclaimer in the documentation |
605
|
|
|
|
|
|
|
and/or other materials provided with the distribution. |
606
|
|
|
|
|
|
|
|
607
|
|
|
|
|
|
|
3. Neither the name of SUSE LLC nor the names of its contributors |
608
|
|
|
|
|
|
|
may be used to endorse or promote products derived from this software without |
609
|
|
|
|
|
|
|
specific prior written permission. |
610
|
|
|
|
|
|
|
|
611
|
|
|
|
|
|
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND |
612
|
|
|
|
|
|
|
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
613
|
|
|
|
|
|
|
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
614
|
|
|
|
|
|
|
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE |
615
|
|
|
|
|
|
|
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
616
|
|
|
|
|
|
|
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR |
617
|
|
|
|
|
|
|
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER |
618
|
|
|
|
|
|
|
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, |
619
|
|
|
|
|
|
|
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
620
|
|
|
|
|
|
|
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
621
|
|
|
|
|
|
|
|
622
|
|
|
|
|
|
|
|
623
|
|
|
|
|
|
|
=cut |
624
|
|
|
|
|
|
|
|
625
|
|
|
|
|
|
|
1; # End of App::Dochazka::REST |