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