-
Notifications
You must be signed in to change notification settings - Fork 1
/
User.pm
350 lines (247 loc) · 8.01 KB
/
User.pm
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
use utf8;
package Rapi::Blog::DB::Result::User;
# Created by DBIx::Class::Schema::Loader
# DO NOT MODIFY THE FIRST PART OF THIS FILE
use strict;
use warnings;
use Moose;
use MooseX::NonMoose;
use MooseX::MarkAsMethods autoclean => 1;
extends 'DBIx::Class::Core';
__PACKAGE__->load_components("InflateColumn::DateTime");
__PACKAGE__->table("user");
__PACKAGE__->add_columns(
"id",
{ data_type => "integer", is_auto_increment => 1, is_nullable => 0 },
"username",
{ data_type => "varchar", is_nullable => 0, size => 32 },
"full_name",
{
data_type => "varchar",
default_value => \"null",
is_nullable => 1,
size => 64,
},
"image",
{
data_type => "varchar",
default_value => \"null",
is_nullable => 1,
size => 255,
},
"email",
{
data_type => "varchar",
default_value => \"null",
is_nullable => 1,
size => 255,
},
"admin",
{ data_type => "boolean", default_value => 0, is_nullable => 0 },
"author",
{ data_type => "boolean", default_value => 0, is_nullable => 0 },
"comment",
{ data_type => "boolean", default_value => 1, is_nullable => 0 },
"disabled",
{ data_type => "boolean", default_value => 0, is_nullable => 0 },
);
__PACKAGE__->set_primary_key("id");
__PACKAGE__->add_unique_constraint("full_name_unique", ["full_name"]);
__PACKAGE__->add_unique_constraint("username_unique", ["username"]);
__PACKAGE__->has_many(
"comments",
"Rapi::Blog::DB::Result::Comment",
{ "foreign.user_id" => "self.id" },
{ cascade_copy => 0, cascade_delete => 0 },
);
__PACKAGE__->has_many(
"post_authors",
"Rapi::Blog::DB::Result::Post",
{ "foreign.author_id" => "self.id" },
{ cascade_copy => 0, cascade_delete => 0 },
);
__PACKAGE__->has_many(
"post_creators",
"Rapi::Blog::DB::Result::Post",
{ "foreign.creator_id" => "self.id" },
{ cascade_copy => 0, cascade_delete => 0 },
);
__PACKAGE__->has_many(
"post_updaters",
"Rapi::Blog::DB::Result::Post",
{ "foreign.updater_id" => "self.id" },
{ cascade_copy => 0, cascade_delete => 0 },
);
__PACKAGE__->has_many(
"preauth_actions",
"Rapi::Blog::DB::Result::PreauthAction",
{ "foreign.user_id" => "self.id" },
{ cascade_copy => 0, cascade_delete => 0 },
);
# Created by DBIx::Class::Schema::Loader v0.07049 @ 2018-10-27 23:38:05
# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:2klRAJnak1zgM9iKuGRQCQ
use RapidApp::Util ':all';
__PACKAGE__->load_components('+RapidApp::DBIC::Component::TableSpec');
__PACKAGE__->load_components('+Rapi::Blog::DB::Component::SafeResult');
__PACKAGE__->add_virtual_columns( set_pw => {
data_type => "varchar",
is_nullable => 1,
sql => "SELECT NULL",
set_function => sub {} # This is a dummy designed to hook via AuthCore/linked_user_model
});
__PACKAGE__->apply_TableSpec;
sub insert {
my $self = shift;
# Fix GitHub Issue #1 - we want to do this perm check, however, if this insert is being
# generated via automatic inflation from the CoreSchema LinkedRow, this will result in
# a deep recursion (i.e. the current user *is* being inserted). For this case, we bail
# out of the perm check if we detect that a linkedRow sync is already in-progress
unless($self->{_pulling_linkedRow}) {
my $User = Rapi::Blog::Util->get_User;
die usererr "Create User: PERMISSION DENIED" if ($User && $User->id && !$User->admin);
}
$self->next::method(@_);
$self->_role_perm_sync;
$self
}
sub update {
my $self = shift;
my $User = Rapi::Blog::Util->get_User;
die usererr "Update User: PERMISSION DENIED" if (
$User && $User->id &&
!($User->admin || $self->id == $User->id)
);
$self->next::method(@_);
$self->_role_perm_sync;
$self
}
sub delete {
my $self = shift;
my $User = Rapi::Blog::Util->get_User;
die usererr "Delete User: PERMISSION DENIED" if ($User && $User->id && !$User->admin);
$self->next::method(@_)
}
# return the username if full_name is not set
around 'full_name' => sub {
my ($orig,$self,@args) = @_;
$self->$orig(@args) || $self->username
};
sub image_url {
my $self = shift;
$self->{_image_url} //= $self->image
? join('/','_ra-rel-mnt_','simplecas','fetch_content',$self->image)
: undef
}
sub _role_perm_sync {
my $self = shift;
if($self->{_pulling_linkedRow}) {
$self->_apply_from_CoreUser($self->{_pulling_linkedRow});
}
else {
if($self->can('_find_linkedRow')) {
# This is ugly but needed to hook both sides correctly across all CRUD ops
my $Row = $self->_find_linkedRow || $self->_create_linkedRow;
$self->_apply_to_CoreUser( $Row );
}
}
}
# change originated from CoreSchema::User:
sub _apply_from_CoreUser {
my ($self, $CoreUser) = @_;
my $cur_admin = $self->admin || 0;
$CoreUser = $CoreUser->get_from_storage if ($CoreUser->in_storage); # needed in case the username has changed
my $LinkRs = $CoreUser->user_to_roles;
my $admin_cond = { username => $CoreUser->username, role => 'administrator' };
if($LinkRs->search_rs($admin_cond)->first) {
$self->admin(1);
}
else {
$self->admin(0);
}
$self->update unless ($cur_admin == $self->admin);
}
# change originated locally:
sub _apply_to_CoreUser {
my ($self, $CoreUser) = @_;
my $LinkRs = $CoreUser->user_to_roles;
my $admin_cond = { username => $CoreUser->username, role => 'administrator' };
if($self->admin) {
$LinkRs->find_or_create($admin_cond);
}
else {
if(my $Link = $LinkRs->search_rs($admin_cond)->first) {
$Link->delete;
}
}
}
sub can_post {
my $self = shift;
$self->admin || $self->author
}
sub can_comment {
my $self = shift;
$self->admin || $self->comment
}
# You can replace this text with custom code or comments, and it will be preserved on regeneration
__PACKAGE__->meta->make_immutable;
1;
__END__
=head1 NAME
Rapi::Blog::DB::Result::User - User row object
=head1 DESCRIPTION
This is the default User Result class/row object for L<Rapi::Blog>. The C<list_users()> template directive
returns an array of these objects (in the sub property C<rows>)
This is a L<DBIx::Class::Row>.
=head1 COLUMNS
=head2 id
Auto-increment user id. Read-only.
=head2 username
The unique username used to login to the system. This links with the RapidApp AuthCore user object with
the same username and the system automatically keeps these objects in sync.
=head2 full_name
Friendly display name.
=head2 image
CAS image column (C<'cas_img'>). Contains the sha1 of a file within the SimpleCAS.
=head2 email
User's E-Mail address
=head2 admin
True/false permission flag if the user is an admin or not. Setting this value automatically adds or
removes the C<administrators> role in AuthCore user object.
=head2 author
True/false permission flag which determines whether or not a user is allowed to add new posts.
=head2 comment
True/false permission flag which determines whether or not a user is allowed to add comments.
=head2 set_pw
Virtual column can be set with a plaintext value that on insert/update will store the hashed
password in the AuthCore user row.
=head1 METHODS
=head2 image_url
URL which can be used to access the user's C<image> (i.e. avatar) for the active site/scaffold.
=head2 can_post
Util method returns true if the user can post. Will be true if the user is either an admin or
an author.
=head2 can_post
Util method returns true if the user can comment. Will be true if the user is either an admin or
has the comment permission.
=head2 comments
Multi-relationship to all the Comments this user has created.
=head2 post_authors
Multi-relationship to all the Posts this user is the author of.
=head2 post_creators
Multi-relationship to all the Posts this user has created.
=head2 post_updaters
Multi-relationship to all the Posts this user is the last updater of.
=head1 SEE ALSO
=over
=item *
L<Rapi::Blog>
=item *
L<http://rapi.io/blog>
=back
=head1 AUTHOR
Henry Van Styn <vanstyn@cpan.org>
=head1 COPYRIGHT AND LICENSE
This software is copyright (c) 2017 by IntelliTree Solutions llc.
This is free software; you can redistribute it and/or modify it under
the same terms as the Perl 5 programming language system itself.
=cut