line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package RapidApp::TableSpec; |
2
|
5
|
|
|
5
|
|
522
|
use strict; |
|
5
|
|
|
|
|
11
|
|
|
5
|
|
|
|
|
129
|
|
3
|
5
|
|
|
5
|
|
23
|
use Moose; |
|
5
|
|
|
|
|
9
|
|
|
5
|
|
|
|
|
31
|
|
4
|
|
|
|
|
|
|
with 'MooseX::Traits'; |
5
|
|
|
|
|
|
|
|
6
|
|
|
|
|
|
|
# This configuration class defines behaviors of tables and |
7
|
|
|
|
|
|
|
# columns in a general way that can be used in different places |
8
|
|
|
|
|
|
|
|
9
|
5
|
|
|
5
|
|
27959
|
use RapidApp::Util qw(:all); |
|
5
|
|
|
|
|
12
|
|
|
5
|
|
|
|
|
1746
|
|
10
|
5
|
|
|
5
|
|
2049
|
use RapidApp::TableSpec::Column; |
|
5
|
|
|
|
|
17
|
|
|
5
|
|
|
|
|
13401
|
|
11
|
|
|
|
|
|
|
|
12
|
|
|
|
|
|
|
our $VERSION = '0.1'; |
13
|
|
|
|
|
|
|
|
14
|
|
|
|
|
|
|
sub BUILD { |
15
|
230
|
|
|
230
|
0
|
521
|
my $self = shift; |
16
|
230
|
|
|
|
|
6087
|
$self->add_onrequest_columns_mungers( $self->column_permissions_roles_munger ); |
17
|
|
|
|
|
|
|
} |
18
|
|
|
|
|
|
|
|
19
|
|
|
|
|
|
|
around BUILDARGS => sub { |
20
|
|
|
|
|
|
|
my $orig = shift; |
21
|
|
|
|
|
|
|
my $class = shift; |
22
|
|
|
|
|
|
|
my %params = (ref($_[0]) eq 'HASH') ? %{ $_[0] } : @_; # <-- arg as hash or hashref |
23
|
|
|
|
|
|
|
|
24
|
|
|
|
|
|
|
# -- New: handle rogue name values, like ScalarRefs which DBIC sometimes uses |
25
|
|
|
|
|
|
|
# for the ->table attr of Result classes, and also normalize values |
26
|
|
|
|
|
|
|
# ** note: this should no longer be needed since we added _table_name_safe() |
27
|
|
|
|
|
|
|
if(my $table = $params{name}) { |
28
|
|
|
|
|
|
|
$table = $$table if (ref($table)||'' eq 'SCALAR'); |
29
|
|
|
|
|
|
|
$table =~ s/("|')//g; |
30
|
|
|
|
|
|
|
$table = (split(/\./,$table,2))[1] || $table; #<-- get 'table' for both 'db.table' and 'table' format |
31
|
|
|
|
|
|
|
$params{name} = $table; |
32
|
|
|
|
|
|
|
} |
33
|
|
|
|
|
|
|
# -- |
34
|
|
|
|
|
|
|
|
35
|
|
|
|
|
|
|
return $class->$orig(%params); |
36
|
|
|
|
|
|
|
}; |
37
|
|
|
|
|
|
|
|
38
|
|
|
|
|
|
|
|
39
|
|
|
|
|
|
|
|
40
|
|
|
|
|
|
|
has 'ResultClass' => ( is => 'ro', isa => 'Str' ); |
41
|
|
|
|
|
|
|
|
42
|
|
|
|
|
|
|
has 'name' => ( is => 'ro', isa => 'Str', required => 1 ); |
43
|
|
|
|
|
|
|
has 'title' => ( is => 'ro', isa => 'Maybe[Str]', default => undef ); |
44
|
|
|
|
|
|
|
has 'iconCls' => ( is => 'ro', isa => 'Maybe[Str]', default => undef ); |
45
|
|
|
|
|
|
|
|
46
|
|
|
|
|
|
|
|
47
|
|
|
|
|
|
|
has 'header_prefix' => ( is => 'ro', isa => 'Maybe[Str]', default => undef ); |
48
|
|
|
|
|
|
|
|
49
|
|
|
|
|
|
|
# Hash of CodeRefs to programatically change Column properties |
50
|
|
|
|
|
|
|
has 'column_property_transforms' => ( is => 'ro', isa => 'Maybe[HashRef[CodeRef]]', default => undef ); |
51
|
|
|
|
|
|
|
|
52
|
|
|
|
|
|
|
# Hash of static changes to apply to named properties of all Columns |
53
|
|
|
|
|
|
|
has 'column_properties' => ( is => 'ro', isa => 'Maybe[HashRef]', default => undef ); |
54
|
|
|
|
|
|
|
|
55
|
|
|
|
|
|
|
# Hash of static properties initially applied to all Columns (if not already set) |
56
|
|
|
|
|
|
|
has 'default_column_properties' => ( is => 'ro', isa => 'Maybe[HashRef]', default => undef ); |
57
|
|
|
|
|
|
|
|
58
|
|
|
|
|
|
|
has 'profile_definitions' => ( is => 'ro', isa => 'Maybe[HashRef]', default => undef ); |
59
|
|
|
|
|
|
|
|
60
|
|
|
|
|
|
|
has 'column_order' => ( is => 'ro', isa => 'ArrayRef[Str]', default => sub {[]} ); |
61
|
|
|
|
|
|
|
|
62
|
|
|
|
|
|
|
has 'columns' => ( |
63
|
|
|
|
|
|
|
traits => ['Hash'], |
64
|
|
|
|
|
|
|
is => 'ro', |
65
|
|
|
|
|
|
|
isa => 'HashRef[RapidApp::TableSpec::Column]', |
66
|
|
|
|
|
|
|
default => sub { {} }, |
67
|
|
|
|
|
|
|
handles => { |
68
|
|
|
|
|
|
|
apply_columns => 'set', |
69
|
|
|
|
|
|
|
get_column => 'get', |
70
|
|
|
|
|
|
|
has_column => 'exists', |
71
|
|
|
|
|
|
|
column_list => 'values', |
72
|
|
|
|
|
|
|
num_columns => 'count', |
73
|
|
|
|
|
|
|
delete_column => 'delete' |
74
|
|
|
|
|
|
|
} |
75
|
|
|
|
|
|
|
); |
76
|
|
|
|
|
|
|
around 'apply_columns' => sub { |
77
|
|
|
|
|
|
|
my $orig = shift; |
78
|
|
|
|
|
|
|
my $self = shift; |
79
|
|
|
|
|
|
|
my %cols = (ref($_[0]) eq 'HASH') ? %{ $_[0] } : @_; # <-- arg as hash or hashref |
80
|
|
|
|
|
|
|
|
81
|
|
|
|
|
|
|
my $def = $self->default_column_properties; |
82
|
|
|
|
|
|
|
if ($def) { |
83
|
|
|
|
|
|
|
foreach my $Column (values %cols) { |
84
|
|
|
|
|
|
|
$Column->set_properties_If($def); |
85
|
|
|
|
|
|
|
} |
86
|
|
|
|
|
|
|
} |
87
|
|
|
|
|
|
|
|
88
|
|
|
|
|
|
|
push @{$self->column_order}, grep { ! $self->columns->{$_} } keys %cols; |
89
|
|
|
|
|
|
|
|
90
|
|
|
|
|
|
|
$self->$orig(%cols); |
91
|
|
|
|
|
|
|
$self->prune_invalid_columns; |
92
|
|
|
|
|
|
|
}; |
93
|
|
|
|
|
|
|
around 'column_list' => sub { |
94
|
|
|
|
|
|
|
my $orig = shift; |
95
|
|
|
|
|
|
|
my $self = shift; |
96
|
|
|
|
|
|
|
# Force column_list to go through get_column so its logic gets called: |
97
|
|
|
|
|
|
|
return grep { $_ = $self->get_column($_) } $self->updated_column_order; |
98
|
|
|
|
|
|
|
}; |
99
|
|
|
|
|
|
|
around 'get_column' => sub { |
100
|
|
|
|
|
|
|
my $orig = shift; |
101
|
|
|
|
|
|
|
my $self = shift; |
102
|
|
|
|
|
|
|
my $name = shift; |
103
|
|
|
|
|
|
|
my $Column = $self->$orig($name) || return undef; |
104
|
|
|
|
|
|
|
|
105
|
|
|
|
|
|
|
return $Column unless ( |
106
|
|
|
|
|
|
|
defined $self->column_property_transforms or ( |
107
|
|
|
|
|
|
|
defined $self->column_properties and |
108
|
|
|
|
|
|
|
defined $self->column_properties->{$Column->name} |
109
|
|
|
|
|
|
|
) |
110
|
|
|
|
|
|
|
); |
111
|
|
|
|
|
|
|
|
112
|
|
|
|
|
|
|
my $trans = $self->column_property_transforms; |
113
|
|
|
|
|
|
|
my $cur_props = $Column->all_properties_hash; |
114
|
|
|
|
|
|
|
my %change_props = (); |
115
|
|
|
|
|
|
|
|
116
|
|
|
|
|
|
|
foreach my $prop (keys %$trans) { |
117
|
|
|
|
|
|
|
local $_ = $cur_props->{$prop}; |
118
|
|
|
|
|
|
|
$change_props{$prop} = $trans->{$prop}->($cur_props); |
119
|
|
|
|
|
|
|
delete $change_props{$prop} unless (defined $change_props{$prop}); |
120
|
|
|
|
|
|
|
} |
121
|
|
|
|
|
|
|
|
122
|
|
|
|
|
|
|
%change_props = ( %change_props, %{ $self->column_properties->{$Column->name} } ) if ( |
123
|
|
|
|
|
|
|
defined $self->column_properties and |
124
|
|
|
|
|
|
|
defined $self->column_properties->{$Column->name} |
125
|
|
|
|
|
|
|
); |
126
|
|
|
|
|
|
|
|
127
|
|
|
|
|
|
|
return $Column->copy(%change_props); |
128
|
|
|
|
|
|
|
}; |
129
|
|
|
|
|
|
|
|
130
|
|
|
|
|
|
|
|
131
|
|
|
|
|
|
|
|
132
|
|
|
|
|
|
|
has 'limit_columns' => ( is => 'rw', isa => 'Maybe[ArrayRef[Str]]', default => undef, trigger => \&prune_invalid_columns ); |
133
|
|
|
|
|
|
|
has 'exclude_columns' => ( is => 'rw', isa => 'Maybe[ArrayRef[Str]]', default => undef, trigger => \&prune_invalid_columns ); |
134
|
|
|
|
|
|
|
|
135
|
|
|
|
|
|
|
sub prune_invalid_columns { |
136
|
1094
|
|
|
1094
|
0
|
1536
|
my $self = shift; |
137
|
|
|
|
|
|
|
|
138
|
1094
|
|
|
|
|
1712
|
my @remove_cols = (); |
139
|
|
|
|
|
|
|
|
140
|
1094
|
50
|
33
|
|
|
26171
|
if (defined $self->limit_columns and scalar @{ $self->limit_columns } > 0) { |
|
0
|
|
|
|
|
0
|
|
141
|
0
|
|
|
|
|
0
|
my %map = map { $_ => 1 } @{ $self->limit_columns }; |
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
142
|
0
|
|
|
|
|
0
|
push @remove_cols, grep { not defined $map{$_} } keys %{ $self->columns }; |
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
143
|
|
|
|
|
|
|
} |
144
|
|
|
|
|
|
|
|
145
|
1094
|
50
|
33
|
|
|
23659
|
if (defined $self->exclude_columns and scalar @{ $self->exclude_columns } > 0) { |
|
0
|
|
|
|
|
0
|
|
146
|
0
|
|
|
|
|
0
|
my %map = map { $_ => 1 } @{ $self->exclude_columns }; |
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
147
|
0
|
|
|
|
|
0
|
push @remove_cols, grep { defined $map{$_} } keys %{ $self->columns }; |
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
148
|
|
|
|
|
|
|
} |
149
|
|
|
|
|
|
|
|
150
|
1094
|
|
|
|
|
2107
|
foreach my $remove (@remove_cols) { |
151
|
0
|
|
|
|
|
0
|
delete $self->columns->{$remove}; |
152
|
|
|
|
|
|
|
} |
153
|
|
|
|
|
|
|
|
154
|
1094
|
|
|
|
|
2952
|
$self->updated_column_order; |
155
|
|
|
|
|
|
|
} |
156
|
|
|
|
|
|
|
|
157
|
|
|
|
|
|
|
sub updated_column_order { |
158
|
3292
|
|
|
3292
|
0
|
4575
|
my $self = shift; |
159
|
3292
|
|
|
|
|
4296
|
my %seen = (); |
160
|
|
|
|
|
|
|
# Prune out duplciates and columns not in $self->columns |
161
|
3292
|
50
|
|
|
|
4329
|
@{$self->column_order} = grep { !$seen{$_}++ and $self->columns->{$_} } @{$self->column_order}; |
|
3292
|
|
|
|
|
67216
|
|
|
15113
|
|
|
|
|
310057
|
|
|
3292
|
|
|
|
|
68873
|
|
162
|
|
|
|
|
|
|
# Append any missing columns to the end (shouldn't be any) |
163
|
3292
|
|
|
|
|
4948
|
push @{$self->column_order}, grep { !$seen{$_} } keys %{$self->columns}; |
|
3292
|
|
|
|
|
65511
|
|
|
12599
|
|
|
|
|
19158
|
|
|
3292
|
|
|
|
|
65049
|
|
164
|
3292
|
|
|
|
|
4748
|
return @{$self->column_order}; |
|
3292
|
|
|
|
|
66766
|
|
165
|
|
|
|
|
|
|
} |
166
|
|
|
|
|
|
|
|
167
|
|
|
|
|
|
|
|
168
|
|
|
|
|
|
|
sub get_column_order_index { |
169
|
0
|
|
|
0
|
0
|
0
|
my $self = shift; |
170
|
0
|
|
|
|
|
0
|
my $column = shift; |
171
|
0
|
|
|
|
|
0
|
my $i = 0; |
172
|
0
|
|
|
|
|
0
|
for my $col ($self->updated_column_order) { |
173
|
0
|
0
|
|
|
|
0
|
return $i if ($col eq $column); |
174
|
0
|
|
|
|
|
0
|
$i++; |
175
|
|
|
|
|
|
|
} |
176
|
0
|
|
|
|
|
0
|
die "get_column_order_index(): column name '$column' not found"; |
177
|
|
|
|
|
|
|
} |
178
|
|
|
|
|
|
|
|
179
|
|
|
|
|
|
|
sub set_column_order_before { |
180
|
0
|
|
|
0
|
0
|
0
|
my $self = shift; |
181
|
0
|
|
|
|
|
0
|
my $colname = shift; |
182
|
0
|
|
|
|
|
0
|
my @cols = @_; |
183
|
0
|
|
|
|
|
0
|
my $offset = $self->get_column_order_index($colname); |
184
|
0
|
|
|
|
|
0
|
return $self->set_column_order($offset,@cols); |
185
|
|
|
|
|
|
|
} |
186
|
|
|
|
|
|
|
|
187
|
|
|
|
|
|
|
sub set_column_order_after { |
188
|
0
|
|
|
0
|
0
|
0
|
my $self = shift; |
189
|
0
|
|
|
|
|
0
|
my $colname = shift; |
190
|
0
|
|
|
|
|
0
|
my @cols = @_; |
191
|
0
|
|
|
|
|
0
|
my $offset = $self->get_column_order_index($colname); |
192
|
0
|
|
|
|
|
0
|
return $self->set_column_order(++$offset,@cols); |
193
|
|
|
|
|
|
|
} |
194
|
|
|
|
|
|
|
|
195
|
|
|
|
|
|
|
sub set_column_orderIf { |
196
|
0
|
|
|
0
|
0
|
0
|
my $self = shift; |
197
|
0
|
|
|
|
|
0
|
my $offset = shift; |
198
|
0
|
|
|
|
|
0
|
my @cols = @_; |
199
|
0
|
0
|
0
|
|
|
0
|
@cols = @{$_[0]} if (scalar @_ == 1 and ref($_[0]) eq 'ARRAY'); |
|
0
|
|
|
|
|
0
|
|
200
|
0
|
|
|
|
|
0
|
return $self->set_column_order($offset, grep { exists $self->columns->{$_} } @cols); |
|
0
|
|
|
|
|
0
|
|
201
|
|
|
|
|
|
|
} |
202
|
|
|
|
|
|
|
|
203
|
|
|
|
|
|
|
sub set_column_order { |
204
|
0
|
|
|
0
|
0
|
0
|
my $self = shift; |
205
|
0
|
|
|
|
|
0
|
my $offset = shift; |
206
|
0
|
0
|
|
|
|
0
|
die "First argument to set_column_order must be an index/offset" unless ($offset =~ /^\d+$/); |
207
|
0
|
|
|
|
|
0
|
my @cols = @_; |
208
|
0
|
0
|
0
|
|
|
0
|
@cols = @{$_[0]} if (scalar @_ == 1 and ref($_[0]) eq 'ARRAY'); |
|
0
|
|
|
|
|
0
|
|
209
|
|
|
|
|
|
|
|
210
|
0
|
|
|
|
|
0
|
my %seen = (); |
211
|
0
|
|
0
|
|
|
0
|
!$seen{$_}++ or die "set_column_order(): column name specified more than once ($_)" for (@cols); |
212
|
0
|
|
0
|
|
|
0
|
$self->has_column($_) or die "set_column_order(): cannot set the order of non-existant columns ($_)" for (@cols); |
213
|
|
|
|
|
|
|
|
214
|
0
|
|
|
|
|
0
|
my %cols_map = map { $_ => 1 } @cols; |
|
0
|
|
|
|
|
0
|
|
215
|
|
|
|
|
|
|
|
216
|
|
|
|
|
|
|
#prune out the new columns from the current order: |
217
|
0
|
|
|
|
|
0
|
@{$self->column_order} = grep { !$cols_map{$_} } @{$self->column_order}; |
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
218
|
|
|
|
|
|
|
|
219
|
0
|
0
|
|
|
|
0
|
if ($offset < scalar @{$self->column_order}) { |
|
0
|
|
|
|
|
0
|
|
220
|
|
|
|
|
|
|
# Add them back in at the new offset/index: |
221
|
0
|
|
|
|
|
0
|
splice(@{$self->column_order},$offset,0,@cols); |
|
0
|
|
|
|
|
0
|
|
222
|
|
|
|
|
|
|
} |
223
|
|
|
|
|
|
|
else { |
224
|
|
|
|
|
|
|
# offset is at or past the end of the array, ignore it and just append: |
225
|
0
|
|
|
|
|
0
|
push @{$self->column_order}, @cols; |
|
0
|
|
|
|
|
0
|
|
226
|
|
|
|
|
|
|
} |
227
|
|
|
|
|
|
|
|
228
|
|
|
|
|
|
|
# Just to be safe: |
229
|
0
|
|
|
|
|
0
|
$self->updated_column_order; |
230
|
|
|
|
|
|
|
} |
231
|
|
|
|
|
|
|
|
232
|
0
|
|
|
0
|
0
|
0
|
sub column_names { (shift)->column_names_ordered } |
233
|
|
|
|
|
|
|
sub column_names_ordered { |
234
|
92
|
|
|
92
|
0
|
191
|
my $self = shift; |
235
|
92
|
|
|
|
|
360
|
return map { $_->name } $self->column_list; |
|
781
|
|
|
|
|
16286
|
|
236
|
|
|
|
|
|
|
} |
237
|
|
|
|
|
|
|
|
238
|
|
|
|
|
|
|
|
239
|
|
|
|
|
|
|
sub columns_properties_limited { |
240
|
92
|
|
|
92
|
0
|
200
|
my $self = shift; |
241
|
92
|
|
|
|
|
213
|
my @props = @_; |
242
|
92
|
|
|
|
|
448
|
$self->updated_column_order; |
243
|
92
|
|
|
|
|
441
|
return { map { $_->name => $_->properties_limited(@props) } $self->column_list }; |
|
781
|
|
|
|
|
21429
|
|
244
|
|
|
|
|
|
|
} |
245
|
|
|
|
|
|
|
|
246
|
|
|
|
|
|
|
|
247
|
|
|
|
|
|
|
sub add_columns { |
248
|
1094
|
|
|
1094
|
0
|
1747
|
my $self = shift; |
249
|
1094
|
|
|
|
|
2060
|
my @cols = (@_); |
250
|
|
|
|
|
|
|
|
251
|
1094
|
|
|
|
|
1648
|
my @added = (); |
252
|
|
|
|
|
|
|
|
253
|
1094
|
|
|
|
|
1858
|
foreach my $col (@cols) { |
254
|
1094
|
|
|
|
|
1393
|
my $Column; |
255
|
1094
|
50
|
|
|
|
2456
|
$Column = $col if (ref($col) eq 'RapidApp::TableSpec::Column'); |
256
|
1094
|
50
|
|
|
|
1983
|
unless ($Column) { |
257
|
1094
|
50
|
|
|
|
29987
|
$col->{profile_definitions} = $self->profile_definitions if ($self->profile_definitions); |
258
|
1094
|
|
|
|
|
28306
|
$Column = RapidApp::TableSpec::Column->new($col); |
259
|
1094
|
|
|
|
|
3256
|
$Column->set_properties($col); |
260
|
|
|
|
|
|
|
} |
261
|
|
|
|
|
|
|
|
262
|
|
|
|
|
|
|
#die "A column named " . $Column->name . ' already exists.' if (defined $self->has_column($Column->name)); |
263
|
|
|
|
|
|
|
|
264
|
1094
|
|
|
|
|
25070
|
$self->apply_columns( $Column->name => $Column ); |
265
|
1094
|
|
|
|
|
2390
|
push @added, $Column; |
266
|
|
|
|
|
|
|
} |
267
|
|
|
|
|
|
|
|
268
|
1094
|
|
|
|
|
2882
|
$self->update_column_permissions_roles_code; |
269
|
1094
|
|
|
|
|
20045
|
return @added; |
270
|
|
|
|
|
|
|
} |
271
|
|
|
|
|
|
|
|
272
|
|
|
|
|
|
|
|
273
|
|
|
|
|
|
|
sub applyIf_column_properties { |
274
|
0
|
|
|
0
|
0
|
0
|
my $self = shift; |
275
|
0
|
0
|
|
|
|
0
|
my %new = (ref($_[0]) eq 'HASH') ? %{ $_[0] } : @_; # <-- arg as hash or hashref |
|
0
|
|
|
|
|
0
|
|
276
|
0
|
|
|
|
|
0
|
my $hash = \%new; |
277
|
|
|
|
|
|
|
|
278
|
0
|
|
|
|
|
0
|
my $pruned = { map { $_ => $hash->{$_} } grep { $self->get_column($_) } keys %$hash }; |
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
279
|
|
|
|
|
|
|
|
280
|
0
|
|
|
|
|
0
|
return $self->apply_column_properties($pruned); |
281
|
|
|
|
|
|
|
} |
282
|
|
|
|
|
|
|
|
283
|
|
|
|
|
|
|
sub apply_column_properties { |
284
|
0
|
|
|
0
|
0
|
0
|
my $self = shift; |
285
|
|
|
|
|
|
|
|
286
|
0
|
0
|
|
|
|
0
|
my %new = (ref($_[0]) eq 'HASH') ? %{ $_[0] } : @_; # <-- arg as hash or hashref |
|
0
|
|
|
|
|
0
|
|
287
|
0
|
|
|
|
|
0
|
my $hash = \%new; |
288
|
|
|
|
|
|
|
|
289
|
0
|
|
|
|
|
0
|
foreach my $col (keys %$hash) { |
290
|
0
|
0
|
|
|
|
0
|
my $Column = $self->get_column($col) or die "apply_column_properties failed - no such column '$col'"; |
291
|
0
|
|
|
|
|
0
|
$Column->set_properties($hash->{$col}); |
292
|
|
|
|
|
|
|
} |
293
|
|
|
|
|
|
|
|
294
|
0
|
|
|
|
|
0
|
$self->update_column_permissions_roles_code; |
295
|
|
|
|
|
|
|
} |
296
|
|
|
|
|
|
|
|
297
|
|
|
|
|
|
|
|
298
|
|
|
|
|
|
|
|
299
|
|
|
|
|
|
|
sub copy { |
300
|
0
|
|
|
0
|
0
|
0
|
my $self = shift; |
301
|
0
|
0
|
|
|
|
0
|
my %opts = (ref($_[0]) eq 'HASH') ? %{ $_[0] } : @_; # <-- arg as hash or hashref |
|
0
|
|
|
|
|
0
|
|
302
|
|
|
|
|
|
|
|
303
|
0
|
|
|
|
|
0
|
my %attr = (); |
304
|
0
|
|
|
|
|
0
|
my %other = (); |
305
|
|
|
|
|
|
|
|
306
|
0
|
|
|
|
|
0
|
foreach my $opt (keys %opts) { |
307
|
0
|
0
|
|
|
|
0
|
if ($self->meta->find_attribute_by_name($opt)) { |
308
|
0
|
|
|
|
|
0
|
$attr{$opt} = $opts{$opt}; |
309
|
|
|
|
|
|
|
} |
310
|
|
|
|
|
|
|
else { |
311
|
0
|
|
|
|
|
0
|
$other{$opt} = $opts{$opt}; |
312
|
|
|
|
|
|
|
} |
313
|
|
|
|
|
|
|
} |
314
|
|
|
|
|
|
|
|
315
|
|
|
|
|
|
|
# Need to use Clone::clone to ensure a deep copy. Discovered that with |
316
|
|
|
|
|
|
|
# clone_object alone, deeper data scructures, such as 'columns' attribute, |
317
|
|
|
|
|
|
|
# were only copied by reference, and not be deep data |
318
|
0
|
|
|
|
|
0
|
my $Copy = $self->meta->clone_object(Clone::clone($self),%attr); |
319
|
|
|
|
|
|
|
|
320
|
0
|
|
|
|
|
0
|
foreach my $key (keys %other) { |
321
|
0
|
0
|
|
|
|
0
|
$Copy->$key($other{$key}) if ($Copy->can($key)); |
322
|
|
|
|
|
|
|
} |
323
|
|
|
|
|
|
|
|
324
|
|
|
|
|
|
|
# If column property transforms (name) was supplied, use it to transform |
325
|
|
|
|
|
|
|
# limit/exclude columns: |
326
|
0
|
0
|
0
|
|
|
0
|
if($opts{column_property_transforms} and $opts{column_property_transforms}{name}) { |
327
|
0
|
|
|
|
|
0
|
my $sub = $opts{column_property_transforms}{name}; |
328
|
|
|
|
|
|
|
|
329
|
0
|
0
|
|
|
|
0
|
if($Copy->limit_columns) { |
330
|
0
|
|
|
|
|
0
|
my @limit = map { $sub->() } @{ $Copy->limit_columns }; |
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
331
|
0
|
0
|
|
|
|
0
|
$Copy->limit_columns(\@limit) if (scalar @limit > 0); |
332
|
|
|
|
|
|
|
} |
333
|
|
|
|
|
|
|
|
334
|
0
|
0
|
|
|
|
0
|
if ($Copy->exclude_columns) { |
335
|
0
|
|
|
|
|
0
|
my @exclude = map { $sub->() } @{ $Copy->exclude_columns }; |
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
336
|
0
|
0
|
|
|
|
0
|
$Copy->exclude_columns(\@exclude) if (scalar @exclude > 0); |
337
|
|
|
|
|
|
|
} |
338
|
|
|
|
|
|
|
} |
339
|
|
|
|
|
|
|
|
340
|
0
|
|
|
|
|
0
|
return $Copy; |
341
|
|
|
|
|
|
|
} |
342
|
|
|
|
|
|
|
|
343
|
|
|
|
|
|
|
sub add_columns_from_TableSpec { |
344
|
0
|
|
|
0
|
0
|
0
|
my $self = shift; |
345
|
0
|
|
|
|
|
0
|
my $TableSpec = shift; |
346
|
|
|
|
|
|
|
|
347
|
0
|
|
|
|
|
0
|
my @added = (); |
348
|
0
|
|
|
|
|
0
|
push @added, $self->add_columns($_) for ($TableSpec->column_list); |
349
|
|
|
|
|
|
|
|
350
|
|
|
|
|
|
|
# Apply foreign TableSpec's limit/exclude columns: |
351
|
0
|
|
|
|
|
0
|
my %seen = (); |
352
|
0
|
|
|
|
|
0
|
my @limit = (); |
353
|
0
|
0
|
|
|
|
0
|
push @limit, @{ $self->limit_columns } if ($self->limit_columns); |
|
0
|
|
|
|
|
0
|
|
354
|
0
|
0
|
|
|
|
0
|
push @limit, @{ $TableSpec->limit_columns } if ($TableSpec->limit_columns); |
|
0
|
|
|
|
|
0
|
|
355
|
0
|
|
|
|
|
0
|
@limit = grep { not $seen{$_}++ } @limit; |
|
0
|
|
|
|
|
0
|
|
356
|
0
|
0
|
|
|
|
0
|
$self->limit_columns(\@limit) if (scalar @limit > 0); |
357
|
|
|
|
|
|
|
|
358
|
0
|
|
|
|
|
0
|
%seen = (); |
359
|
0
|
|
|
|
|
0
|
my @exclude = (); |
360
|
0
|
0
|
|
|
|
0
|
push @exclude, @{ $self->exclude_columns } if ($self->exclude_columns); |
|
0
|
|
|
|
|
0
|
|
361
|
0
|
0
|
|
|
|
0
|
push @exclude, @{ $TableSpec->exclude_columns } if ($TableSpec->exclude_columns); |
|
0
|
|
|
|
|
0
|
|
362
|
0
|
|
|
|
|
0
|
@exclude = grep { not $seen{$_}++ } @exclude; |
|
0
|
|
|
|
|
0
|
|
363
|
0
|
0
|
|
|
|
0
|
$self->exclude_columns(\@exclude) if (scalar @exclude > 0); |
364
|
|
|
|
|
|
|
|
365
|
0
|
|
|
|
|
0
|
$self->updated_column_order; |
366
|
0
|
|
|
|
|
0
|
return @added; |
367
|
|
|
|
|
|
|
} |
368
|
|
|
|
|
|
|
|
369
|
|
|
|
|
|
|
|
370
|
|
|
|
|
|
|
# Designed to work with DataStore2: if defined, gets added as an |
371
|
|
|
|
|
|
|
# onrequest_columns_munger to DataStore2-based modules that are |
372
|
|
|
|
|
|
|
# configured to use this TableSpec: |
373
|
|
|
|
|
|
|
has 'onrequest_columns_mungers' => ( |
374
|
|
|
|
|
|
|
traits => [ 'Array' ], |
375
|
|
|
|
|
|
|
is => 'ro', |
376
|
|
|
|
|
|
|
isa => 'ArrayRef[RapidApp::Handler]', |
377
|
|
|
|
|
|
|
default => sub { [] }, |
378
|
|
|
|
|
|
|
handles => { |
379
|
|
|
|
|
|
|
all_onrequest_columns_mungers => 'uniq', |
380
|
|
|
|
|
|
|
add_onrequest_columns_mungers => 'push', |
381
|
|
|
|
|
|
|
insert_onrequest_columns_mungers => 'unshift', |
382
|
|
|
|
|
|
|
has_no_onrequest_columns_mungers => 'is_empty', |
383
|
|
|
|
|
|
|
} |
384
|
|
|
|
|
|
|
); |
385
|
|
|
|
|
|
|
|
386
|
|
|
|
|
|
|
|
387
|
|
|
|
|
|
|
has 'column_permissions_roles_munger' => ( |
388
|
|
|
|
|
|
|
is => 'ro', |
389
|
|
|
|
|
|
|
isa => 'RapidApp::Handler', |
390
|
|
|
|
|
|
|
default => sub { RapidApp::Handler->new( code => sub {} ) } |
391
|
|
|
|
|
|
|
); |
392
|
|
|
|
|
|
|
|
393
|
|
|
|
|
|
|
|
394
|
|
|
|
|
|
|
has 'roles_permissions_columns_map' => ( is => 'rw', isa => 'HashRef', default => sub {{}} ); |
395
|
|
|
|
|
|
|
|
396
|
|
|
|
|
|
|
sub update_column_permissions_roles_code { |
397
|
1094
|
|
|
1094
|
0
|
1494
|
my $self = shift; |
398
|
|
|
|
|
|
|
|
399
|
|
|
|
|
|
|
# NOT IN USE |
400
|
1094
|
|
|
|
|
1421
|
return; |
401
|
|
|
|
|
|
|
|
402
|
0
|
|
|
|
|
|
my $roles = {}; |
403
|
|
|
|
|
|
|
|
404
|
0
|
|
|
|
|
|
foreach my $Column ($self->column_list) { |
405
|
0
|
0
|
|
|
|
|
$Column->permission_roles or next; |
406
|
|
|
|
|
|
|
|
407
|
0
|
|
|
|
|
|
foreach my $perm ( keys %{ $Column->permission_roles } ) { |
|
0
|
|
|
|
|
|
|
408
|
0
|
|
|
|
|
|
foreach my $role ( @{ $Column->permission_roles->{$perm} } ) { |
|
0
|
|
|
|
|
|
|
409
|
0
|
0
|
0
|
|
|
|
die "Role names cannot contain spaces ('$role')" if (not ref($role) and $role =~ /\s+/); |
410
|
0
|
|
|
|
|
|
my $rolespec = $role; |
411
|
0
|
0
|
|
|
|
|
$rolespec = join(' ',@$role) if (ref($role) eq 'ARRAY'); |
412
|
0
|
0
|
|
|
|
|
$roles->{$rolespec} = {} unless ($roles->{$rolespec}); |
413
|
0
|
0
|
|
|
|
|
$roles->{$rolespec}{$perm} = [] unless ($roles->{$rolespec}{$perm}); |
414
|
0
|
|
|
|
|
|
push @{ $roles->{$rolespec}{$perm} }, $Column->name; |
|
0
|
|
|
|
|
|
|
415
|
|
|
|
|
|
|
} |
416
|
|
|
|
|
|
|
} |
417
|
|
|
|
|
|
|
} |
418
|
|
|
|
|
|
|
|
419
|
0
|
|
|
|
|
|
$self->roles_permissions_columns_map($roles); |
420
|
|
|
|
|
|
|
|
421
|
0
|
0
|
|
0
|
|
|
return $self->column_permissions_roles_munger->code(sub {}) unless (scalar(keys %$roles) > 0); |
422
|
|
|
|
|
|
|
return $self->column_permissions_roles_munger->code(sub { |
423
|
0
|
|
|
0
|
|
|
my $columns = shift; |
424
|
0
|
|
|
|
|
|
return $self->apply_permission_roles_to_datastore_columns($columns); |
425
|
0
|
|
|
|
|
|
}); |
426
|
|
|
|
|
|
|
} |
427
|
|
|
|
|
|
|
|
428
|
|
|
|
|
|
|
|
429
|
|
|
|
|
|
|
# This code not in use - |
430
|
|
|
|
|
|
|
sub apply_permission_roles_to_datastore_columns { |
431
|
0
|
|
|
0
|
0
|
|
my $self = shift; |
432
|
0
|
|
|
|
|
|
my $columns = shift; |
433
|
|
|
|
|
|
|
|
434
|
0
|
|
|
|
|
|
my $c = RapidApp->active_request_context; |
435
|
|
|
|
|
|
|
#delete $columns->{creator}->{editor} unless ($c->check_user_roles('admin')); |
436
|
|
|
|
|
|
|
|
437
|
0
|
|
|
|
|
|
my $map = $self->roles_permissions_columns_map; |
438
|
|
|
|
|
|
|
|
439
|
0
|
|
|
|
|
|
foreach my $role (keys %$map) { |
440
|
0
|
0
|
|
|
|
|
if ($c->check_user_roles(split(/\s+/,$role))) { |
441
|
|
|
|
|
|
|
# Any code that would need to be called for the positive condition would go here |
442
|
|
|
|
|
|
|
|
443
|
|
|
|
|
|
|
} |
444
|
|
|
|
|
|
|
else { |
445
|
|
|
|
|
|
|
|
446
|
|
|
|
|
|
|
#CREATE: |
447
|
0
|
0
|
|
|
|
|
if ($map->{$role}->{create}) { |
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
448
|
|
|
|
|
|
|
|
449
|
|
|
|
|
|
|
|
450
|
|
|
|
|
|
|
} |
451
|
|
|
|
|
|
|
#READ: |
452
|
|
|
|
|
|
|
elsif ($map->{$role}->{read}) { |
453
|
|
|
|
|
|
|
|
454
|
|
|
|
|
|
|
|
455
|
|
|
|
|
|
|
} |
456
|
|
|
|
|
|
|
#UPDATE: |
457
|
|
|
|
|
|
|
elsif ($map->{$role}->{update}) { |
458
|
0
|
|
|
|
|
|
my $list = $map->{$role}->{update}; |
459
|
0
|
0
|
|
|
|
|
$list = [ $list ] unless (ref($list)); |
460
|
0
|
|
|
|
|
|
foreach my $colname (@$list) { |
461
|
0
|
|
|
|
|
|
delete $columns->{$colname}->{editor}; |
462
|
|
|
|
|
|
|
} |
463
|
|
|
|
|
|
|
} |
464
|
|
|
|
|
|
|
#DESTROY |
465
|
|
|
|
|
|
|
elsif ($map->{$role}->{destroy}) { |
466
|
|
|
|
|
|
|
|
467
|
|
|
|
|
|
|
|
468
|
|
|
|
|
|
|
} |
469
|
|
|
|
|
|
|
|
470
|
|
|
|
|
|
|
|
471
|
|
|
|
|
|
|
} |
472
|
|
|
|
|
|
|
|
473
|
|
|
|
|
|
|
|
474
|
|
|
|
|
|
|
} |
475
|
|
|
|
|
|
|
|
476
|
|
|
|
|
|
|
# TODO |
477
|
|
|
|
|
|
|
|
478
|
|
|
|
|
|
|
#scream($self->roles_permissions_columns_map); |
479
|
|
|
|
|
|
|
} |
480
|
|
|
|
|
|
|
|
481
|
|
|
|
|
|
|
# If TableSpec should be cached, then here we need a Cache::Cache |
482
|
|
|
|
|
|
|
# object, which is given on DbicLnk if use_cache is on. |
483
|
|
|
|
|
|
|
has 'cache' => ( is => 'ro', predicate => 'has_cache' ); |
484
|
|
|
|
|
|
|
|
485
|
5
|
|
|
5
|
|
49
|
no Moose; |
|
5
|
|
|
|
|
11
|
|
|
5
|
|
|
|
|
41
|
|
486
|
|
|
|
|
|
|
__PACKAGE__->meta->make_immutable; |
487
|
|
|
|
|
|
|
1; |