]> git.imager.perl.org - bse.git/blame - site/cgi-bin/modules/BSE/AdminSiteUsers.pm
remove BSE::ProductImportXLS, it's no longer used
[bse.git] / site / cgi-bin / modules / BSE / AdminSiteUsers.pm
CommitLineData
9063386f
TC
1package BSE::AdminSiteUsers;
2use strict;
2076966c 3use base qw(BSE::UI::AdminDispatch BSE::UI::SiteuserCommon);
9063386f 4use BSE::Util::Tags qw(tag_error_img tag_hash);
3f9c8a96 5use BSE::Util::HTML qw(:default popup_menu);
b7cadc84 6use BSE::TB::SiteUsers;
9063386f 7use BSE::Util::Iterate;
505456b1 8use BSE::Util::DynSort qw(sorter tag_sorthelp);
9063386f 9use BSE::Util::SQL qw/now_datetime/;
220c179a 10use BSE::SubscriptionTypes;
00dd8d82 11use BSE::CfgInfo qw(custom_class);
efcc5a30 12use constant SITEUSER_GROUP_SECT => 'BSE Siteuser groups validation';
4d764c34 13use BSE::Template;
32696f84 14use DevHelp::Date qw(dh_parse_date_sql dh_parse_time_sql);
9063386f 15
b7cadc84 16our $VERSION = "1.015";
cb7fd78d 17
9063386f
TC
18my %actions =
19 (
2076966c
TC
20 list => 'bse_members_user_list',
21 edit => 'bse_members_user_edit',
22 save => 'bse_members_user_edit',
23 addform => 'bse_members_user_add',
24 add => 'bse_members_user_add',
a0edb02e
TC
25 deleteform => 'bse_members_user_delete',
26 delete => 'bse_members_user_delete',
2076966c 27 view => 'bse_members_user_view',
74b3689a 28 unlock => 'bse_members_user_unlock',
2076966c
TC
29 grouplist => 'bse_members_group_list',
30 addgroupform => 'bse_members_group_add',
31 addgroup => 'bse_members_group_add',
32 editgroup => 'bse_members_group_edit',
33 savegroup => 'bse_members_group_edit',
34 deletegroupform => 'bse_members_group_delete',
35 deletegroup => 'bse_members_group_delete',
36 groupmemberform => 'bse_members_user_edit',
37 savegroupmembers => 'bse_members_user_edit',
6555857d 38 confirm => 'bse_members_confirm',
32696f84
TC
39 adduserfile => 'bse_members_user_add_file',
40 adduserfileform => 'bse_members_user_add_file',
41 edituserfile => 'bse_members_user_edit_file',
42 saveuserfile => 'bse_members_user_edit_file',
43 deluserfileform => 'bse_members_user_del_file',
44 deluserfile => 'bse_members_user_del_file',
45
46 addgroupfile => 'bse_members_group_add_file',
47 addgroupfileform => 'bse_members_group_add_file',
48 editgroupfile => 'bse_members_group_edit_file',
49 savegroupfile => 'bse_members_group_edit_file',
50 delgroupfileform => 'bse_members_group_del_file',
51 delgroupfile => 'bse_members_group_del_file',
52 fileaccesslog => 'bse_members_file_log',
9063386f
TC
53 );
54
829c9ed9 55my @donttouch = qw(id userId password email confirmed confirmSecret waitingForConfirmation flags affiliate_name previousLogon); # flags is saved separately
9063386f
TC
56my %donttouch = map { $_, $_ } @donttouch;
57
2076966c 58sub default_action { 'list' }
9063386f 59
2076966c
TC
60sub actions {
61 \%actions
62}
9063386f 63
2076966c
TC
64sub rights {
65 \%actions
9063386f
TC
66}
67
d49f56a6
TC
68sub flags {
69 my ($cfg) = @_;
70
71 my %flags = $cfg->entriesCS('site user flags');
72
73 my @valid = grep /^\w+$/, keys %flags;
74
75 return map +{ id => $_, desc => $flags{$_} },
76 sort { lc($flags{$a}) cmp lc($flags{$b}) } @valid;
77}
78
758a29cd
TC
79my %nosearch = map { $_ => 1 } qw/id password confirmSecret/;
80
9063386f
TC
81sub req_list {
82 my ($class, $req, $msg) = @_;
83
84 my $cgi = $req->cgi;
495114d1
TC
85 $msg = $req->message($msg);
86
b7cadc84 87 my @users = BSE::TB::SiteUsers->all;
758a29cd
TC
88 my $id = $cgi->param('id');
89 defined $id or $id = '';
511df710
TC
90 my $search_done = 0;
91 my %search_fields;
758a29cd 92 if ($id =~ /^\d+$/) {
511df710 93 $search_fields{id} = $id;
758a29cd 94 @users = grep $_->{id} == $id, @users;
511df710 95 ++$search_done;
758a29cd
TC
96 }
97 else {
98 my %fields;
b7cadc84 99 my @cols = grep !$nosearch{$_}, BSE::TB::SiteUser->columns;
758a29cd
TC
100 for my $col (@cols, 'name') {
101 my $value = $cgi->param($col);
102 if (defined $value && $value =~ /\S/) {
103 $fields{$col} = $value;
104 }
105 }
106 if (keys %fields) {
511df710
TC
107 %search_fields = %fields;
108 ++$search_done;
758a29cd
TC
109 my $name = delete $fields{name};
110 if (defined $name) {
111 @users = grep "$_->{name1} $_->{name2}" =~ /\Q$name/i, @users;
112 }
113 for my $col (keys %fields) {
114 my $value_re = qr/\Q$fields{$col}/i;
115 @users = grep $_->{$col} =~ /$value_re/, @users;
116 }
117 }
118 }
9063386f 119 my ($sortby, $reverse) =
505456b1 120 sorter(data=>\@users, cgi=>$cgi, sortby=>'userId', session=>$req->session,
00dd8d82 121 name=>'siteusers', fields=> { id => {numeric => 1 } });
74b3689a 122 my $it = BSE::Util::Iterate::Objects->new;
511df710
TC
123
124 my $search_param =
125 join('&', map { "$_=".escape_uri($search_fields{$_}) } keys %search_fields);
a0edb02e 126
74b3689a
TC
127 $req->set_variable(siteusers => \@users);
128
9063386f
TC
129 my %acts;
130 %acts =
131 (
d5a6b1ee 132 $req->admin_tags,
9063386f
TC
133 message => $msg,
134 $it->make_paged_iterator('siteuser', 'siteusers', \@users, undef,
505456b1
TC
135 $cgi, undef, 'pp=20', $req->session,
136 'siteusers'),
9063386f
TC
137 sortby=>$sortby,
138 reverse=>$reverse,
139 sorthelp => [ \&tag_sorthelp, $sortby, $reverse ],
511df710
TC
140 ifSearchDone => $search_done,
141 search_param => $search_param,
9063386f
TC
142 );
143
758a29cd 144 return $req->dyn_response('admin/users/list', \%acts);
9063386f
TC
145}
146
147sub tag_if_required {
148 my ($cfg, $args) = @_;
149
150 return $cfg->entryBool('site users', "require_$args", 0);
151}
152
d49f56a6
TC
153sub iter_flags {
154 my ($cfg) = @_;
155
156 flags($cfg);
157}
158
159sub tag_if_flag_set {
160 my ($flags, $arg, $acts, $funcname, $templater) = @_;
161
162 my @args = DevHelp::Tags->get_parms($arg, $acts, $templater);
163 @args or return;
164
165 return index($flags, $args[0]) >= 0;
166}
167
220c179a
TC
168sub tag_if_subscribed_register {
169 my ($cgi, $cfg, $subs, $rsub_index) = @_;
170
171 return 0 if $$rsub_index < 0 or $$rsub_index >= @$subs;
172 my $sub = $subs->[$$rsub_index];
173 if ($cgi->param('checkedsubs')) {
174 my @checked = $cgi->param('subscription');
175 return grep($sub->{id} == $_, @checked) != 0;
176 }
177 else {
178 my $def = $cfg->entryBool('site users', 'subscribe_all', 0);
179
180 return $cfg->entryBool('site users', "subscribe_$sub->{id}", $def);
181 }
182}
183
184sub tag_if_subscribed {
185 my ($cgi, $subs, $rsub_index, $usersubs) = @_;
186
187 $$rsub_index >= 0 && $$rsub_index < @$subs
188 or return;
189
190 my $sub = $subs->[$$rsub_index];
191 if ($cgi->param('checkedsubs')) {
192 my @checked = $cgi->param('subscription');
193 return grep($sub->{id} == $_, @checked) != 0;
194 }
195
196 $usersubs->{$sub->{id}};
197}
198
6a8a205a
TC
199sub iter_orders {
200 my ($siteuser) = @_;
201
202 return $siteuser->orders;
203}
204
efcc5a30
TC
205sub iter_groups {
206 require BSE::TB::SiteUserGroups;
207
208 BSE::TB::SiteUserGroups->all;
209}
210
211sub tag_ifUserMember {
212 my ($user, $rgroup) = @_;
213
214 $$rgroup or return 0;
215
216 $user->is_member_of($$rgroup);
217}
218
9063386f
TC
219sub req_edit {
220 my ($class, $req, $msg, $errors) = @_;
221
2076966c
TC
222 $class->_display_user($req, $msg, $errors, 'admin/users/edit');
223}
224
a0edb02e
TC
225sub req_deleteform {
226 my ($class, $req, $msg, $errors) = @_;
227
228 $class->_display_user($req, $msg, $errors, 'admin/users/delete');
229}
230
2076966c
TC
231sub req_view {
232 my ($class, $req, $msg, $errors) = @_;
233
234 $class->_display_user($req, $msg, $errors, 'admin/users/view');
235}
236
237sub _display_user {
238 my ($class, $req, $msg, $errors, $template) = @_;
239
9063386f
TC
240 my $cgi = $req->cgi;
241 my $id = $cgi->param('id');
49cca15d
TC
242 my $userId = $cgi->param('userId');
243 my $siteuser;
244 if (defined $id) {
b7cadc84 245 $siteuser = BSE::TB::SiteUsers->getByPkey($id)
49cca15d
TC
246 or return $class->req_list($req, "No site user id '$id' found");
247 }
248 elsif (defined $userId) {
b7cadc84 249 ($siteuser) = BSE::TB::SiteUsers->getBy(userId => $userId)
49cca15d
TC
250 or return $class->req_list($req, "No site user logon '$userId' found");
251 }
252 else {
253 return $class->req_list($req, "No site user id supplied");
254 }
9063386f 255
d49f56a6
TC
256 my $it = BSE::Util::Iterate->new;
257
74b3689a
TC
258 $msg = $req->message($msg || $errors);
259
260 $req->set_variable(siteuser => $siteuser);
9063386f 261
32696f84
TC
262 require BSE::TB::OwnedFiles;
263 my @file_cats = BSE::TB::OwnedFiles->categories($req->cfg);
264 my %subbed = map { $_ => 1 } $siteuser->subscribed_file_categories;
265 for my $cat (@file_cats) {
266 $cat->{subscribed} = exists $subbed{$cat->{id}} ? 1 : 0;
267 }
268
220c179a
TC
269 my @subs = grep $_->{visible}, BSE::SubscriptionTypes->all;
270 my $sub_index;
271 require BSE::SubscribedUsers;
272 my @usersubs = BSE::SubscribedUsers->getBy(userId=>$siteuser->{id});
273 my %usersubs = map { $_->{subId}, $_ } @usersubs;
efcc5a30 274 my $current_group;
32696f84 275 my $current_file;
9063386f
TC
276 my %acts;
277 %acts =
278 (
32696f84 279 $req->admin_tags,
9063386f
TC
280 message => $msg,
281 siteuser => [ \&tag_hash, $siteuser ],
282 error_img => [ \&tag_error_img, $req->cfg, $errors ],
283 ifRequired => [ \&tag_if_required, $req->cfg ],
d49f56a6
TC
284 $it->make_iterator([ \&iter_flags, $req->cfg], 'flag', 'flags'),
285 ifFlagSet => [ \&tag_if_flag_set, $siteuser->{flags} ],
220c179a
TC
286 $it->make_iterator(undef, 'subscription', 'subscriptions', \@subs,
287 \$sub_index),
288 ifSubscribed =>
289 [ \&tag_if_subscribed, $cgi, \@subs, \$sub_index, \%usersubs ],
6a8a205a
TC
290 $it->make_iterator([ \&iter_orders, $siteuser ],
291 'userorder', 'userorders' ),
3c32512d 292 $class->_edit_tags($siteuser, $req->cfg),
efcc5a30
TC
293 $it->make_iterator(\&iter_groups, 'group', 'groups',
294 undef, undef, undef, \$current_group),
295 ifMember => [ \&tag_ifUserMember, $siteuser, \$current_group ],
2076966c
TC
296 $it->make_iterator([ \&iter_seminar_bookings, $siteuser],
297 'booking', 'bookings'),
32696f84
TC
298 $it->make
299 (
300 code => [ files => $siteuser ],
301 single => "userfile",
302 plural => "userfiles",
303 store => \$current_file,
304 ),
305 userfile_category => [ tag_userfile_category => $class, $req, \$current_file ],
306 $it->make
307 (
308 data => \@file_cats,
309 single => "filecat",
310 plural => "filecats"
311 ),
9063386f
TC
312 );
313
4d764c34 314 return $req->dyn_response($template, \%acts);
9063386f
TC
315}
316
32696f84
TC
317sub tag_userfile_category {
318 my ($self, $req, $rfile) = @_;
319
320 my ($current) = $req->cgi->param("category");
321 unless (defined $current) {
322 if ($rfile && $$rfile) {
323 $current = $$rfile->category;
324 }
325 }
326 defined $current
327 or $current = "";
328
329 require BSE::TB::OwnedFiles;
330 my @all = BSE::TB::OwnedFiles->categories($req->cfg);
331 return popup_menu
332 (
333 -name => "category",
334 -default => $current,
335 -values => [ map $_->{id}, @all ],
336 -labels => { map { $_->{id} => $_->{name} } @all },
337 );
338}
339
2076966c
TC
340sub iter_seminar_bookings {
341 my ($siteuser) = @_;
342
343 return $siteuser->seminar_bookings_detail;
344}
345
9063386f
TC
346sub req_save {
347 my ($class, $req) = @_;
348
349 my $cgi = $req->cgi;
350 my $cfg = $req->cfg;
351
352 my $id = $cgi->param('id');
353 $id && $id =~ /^\d+$/
354 or return $class->req_list($req, "No user id supplied");
355
b7cadc84 356 my $user = BSE::TB::SiteUsers->getByPkey($id)
9063386f
TC
357 or return $class->req_list($req, "No user $id found");
358
359 my %errors;
360 my $nopassword = $req->cfg->entry('site users', 'nopassword', 0);
b7cadc84 361 my @cols = grep !$donttouch{$_}, BSE::TB::SiteUser->columns;
288ef5b8
TC
362 my $custom = custom_class($cfg);
363 my @required = $custom->siteuser_edit_required($req, $user);
364 for my $col (@required) {
9063386f 365 my $value = $cgi->param($col);
288ef5b8
TC
366 if (defined $value && $value eq '') {
367 my $disp = $cfg->entry('site users', "display_$col", "\u$col");
368 $errors{$col} = "$disp is a required field";
9063386f
TC
369 }
370 }
371
372 my $saveemail;
373 my $email = $cgi->param('email');
6aa67dd9 374 $email =~ s/^\s+|\s+$//g;
288ef5b8
TC
375 if (defined $email && $email ne $user->{email} && $email ne '') {
376 if ($email !~ /.\@./) {
505456b1
TC
377 $errors{email} = "Email is invalid";
378 }
379 unless ($errors{email}) {
380 if ($nopassword) {
381 my $conf_email = $cgi->param('confirmemail');
6aa67dd9 382 $conf_email =~ s/^\s+|\s+$//g;
505456b1
TC
383 if ($conf_email) {
384 if ($conf_email eq $email) {
b7cadc84 385 my $other = BSE::TB::SiteUsers->getBy(userId=>$email);
505456b1
TC
386 if ($other) {
387 $errors{email} = "That email address is already in use";
388 }
389 else {
390 ++$saveemail;
391 }
9063386f
TC
392 }
393 else {
505456b1
TC
394 $errors{confirmemail} =
395 "Confirmation email address doesn't match email address";
9063386f 396 }
505456b1 397 }
9063386f 398 else {
505456b1 399 $errors{confirmemail} = "Please enter a confirmation email address";
9063386f
TC
400 }
401 }
402 else {
505456b1 403 ++$saveemail;
9063386f
TC
404 }
405 }
505456b1 406 unless ($errors{email}) {
b7cadc84 407 my $checkemail = BSE::TB::SiteUser->generic_email($email);
505456b1
TC
408 require BSE::EmailBlacklist;
409 my $blackentry = BSE::EmailBlacklist->getEntry($checkemail);
410 if ($blackentry) {
411 $errors{email} = "Email $email is blacklisted: $blackentry->{why}";
412 }
9063386f
TC
413 }
414 }
415
416 my $newpass;
417 unless ($nopassword) {
418 $newpass = $cgi->param('password');
419 my $confirm = $cgi->param('confirm_password');
420
421 if (defined $newpass && length $newpass) {
77f53961 422 my @errors;
b7cadc84
AO
423 my %other = map { $_ => $user->$_() } BSE::TB::SiteUser->password_check_fields;
424 if (!BSE::TB::SiteUser->check_password_rules
77f53961
TC
425 (
426 password => $newpass,
427 username => $user->userId,
428 other => \%other,
429 errors => \@errors,
430 )) {
431 $errors{password} = \@errors;
9063386f
TC
432 }
433 elsif (!defined $confirm || length $confirm == 0) {
434 $errors{confirm_password} = "Please enter a confirmation password";
435 }
436 elsif ($newpass ne $confirm) {
437 $errors{confirm_password} = "The confirmation password is different from the password";
438 }
439 }
440 }
441
dfdeb4fe 442 my $aff_name = $cgi->param('affiliate_name');
3c32512d
TC
443 $aff_name = _validate_affiliate_name($req, $aff_name, \%errors, $user);
444
445 $class->_save_images($req->cfg, $req->cgi, $user, \%errors);
dfdeb4fe 446
0f09d542
TC
447 if ($cfg->entry('custom', 'admin_saveopts') &&
448 $custom->can("admin_siteuser_saveopts_validate")) {
449 $custom->admin_siteuser_saveopts_validate($user, $req, \%errors);
450 }
451
9063386f
TC
452 keys %errors
453 and return $class->req_edit($req, undef, \%errors);
454
455 my $newemail;
456 if ($saveemail && $email ne $user->{email}) {
457 $user->{confirmed} = 0;
458 $user->{confirmSecret} = '';
459 $user->{email} = $email;
460 $user->{userId} = $email if $nopassword;
461 ++$newemail;
462 }
5899bc52
TC
463 if (!$nopassword && $newpass) {
464 $user->changepw($newpass, $req->user || "U");
465 }
9063386f 466
dfdeb4fe
TC
467 $user->{affiliate_name} = $aff_name if defined $aff_name;
468
9063386f
TC
469 for my $col (@cols) {
470 my $value = $cgi->param($col);
471 if (defined $value) {
472 $user->{$col} = $value;
473 }
474 }
475
0f09d542
TC
476 if ($cfg->entry('custom', 'admin_saveopts')) {
477 $custom->admin_siteuser_saveopts($user, $req);
478 }
479
d49f56a6
TC
480 my @flags = flags($cfg);
481 my %flags = map { $_->{id} => 1 } @flags;
482 $user->{flags} = join('', grep exists $flags{$_}, $cgi->param('flags'))
483 if $cgi->param('saveFlags');
484
9063386f
TC
485 $user->{textOnlyMail} = 0
486 if $cgi->param('saveTextOnlyMail') && !defined $cgi->param('textOnlyMail');
9063386f
TC
487 $user->{disabled} = 0
488 if $cgi->param('saveDisabled') && !defined $cgi->param('disabled');
489 $user->save;
490
efcc5a30
TC
491 # save group membership
492 my @save_ids = $cgi->param('set_group_id');
493 if (@save_ids) {
494 my %member_of = map { $_ => 1 } $user->group_ids;
495 my %new_ids = map { $_ => 1 } $cgi->param('group_id');
496 require BSE::TB::SiteUserGroups;
497 my %all_groups = map { $_->{id} => $_ } BSE::TB::SiteUserGroups->all;
498
499 for my $id (@save_ids) {
500 my $group = $all_groups{$id}
501 or next;
502 if ($member_of{$id} and !$new_ids{$id}) {
503 $group->remove_member($user->{id});
ad34a019
TC
504 $custom->can('group_remove_member')
505 and $custom->group_remove_member($group, $user->{id}, $cfg);
efcc5a30
TC
506 }
507 elsif (!$member_of{$id} and $new_ids{$id}) {
508 $group->add_member($user->{id});
ad34a019
TC
509 $custom->can('group_add_member')
510 and $custom->group_add_member($group, $user->{id}, $cfg);
efcc5a30
TC
511 }
512 }
513 }
514
220c179a
TC
515 if ($cgi->param('checkedsubs')) {
516 $class->save_subs($req, $user);
517 }
518
32696f84
TC
519 if ($cgi->param('save_file_subs')) {
520 my @new_subs = $cgi->param("file_subscriptions");
521 $user->set_subscribed_file_categories($cfg, @new_subs);
522 }
523
505456b1 524 $custom->siteusers_changed($cfg);
ad34a019
TC
525 $custom->can('siteuser_edit')
526 and $custom->siteuser_edit($user, 'admin', $cfg);
505456b1
TC
527
528 my @msgs;
9063386f
TC
529
530 my $sent_ok = 1; # no error handling if true
531 my $code;
532 my $msg;
533 if ($nopassword) {
534 $sent_ok = $user->send_conf_request($req->cgi, $req->cfg, \$code, \$msg)
535 if $newemail;
536 }
537 else {
538 my @subs = $user->subscriptions;
220c179a 539 if (@subs && !$user->{confirmed}) {
9063386f
TC
540 $sent_ok = $user->send_conf_request($req->cgi, $req->cfg, \$code, \$msg);
541 }
542 }
543
544 unless ($sent_ok) {
545 if ($code eq 'blacklist') {
546 push @msgs, "Could not send confirmation: Email address blacklisted: $msg";
547 }
548 elsif ($code eq 'mail') {
549 push @msgs, "Could not send confirmation: Error sending email: $msg";
550 }
551 else {
552 push @msgs, "Could not send confirmation: $msg";
553 }
554 }
555
556 my $r = $cgi->param('r');
495114d1 557 $req->flash("msg:bse/admin/siteusers/usersaved", [ $user ]);
9063386f 558 unless ($r) {
495114d1 559 $r = $req->cfg->admin_url2('siteusers', 'list');
9063386f
TC
560 }
561 $r .= "&m=".escape_uri($_) for @msgs;
562
563 return BSE::Template->get_refresh($r, $req->cfg);
564}
565
a0edb02e
TC
566sub req_delete {
567 my ($class, $req) = @_;
568
569 my $cgi = $req->cgi;
570 my $cfg = $req->cfg;
571
572 $req->check_csrf("admin_siteuser_delete")
573 or return $class->csrf_error($req, "admin_siteuser_delete", "Delete Member");
574
575 my $id = $cgi->param('id');
576 $id && $id =~ /^\d+$/
577 or return $class->req_list($req, "No user id supplied");
578
b7cadc84 579 my $user = BSE::TB::SiteUsers->getByPkey($id)
a0edb02e
TC
580 or return $class->req_list($req, "No user $id found");
581
ac1f5536
TC
582 $req->audit
583 (
584 component => "members::delete",
585 object => $user,
87a74ac9 586 level => "notice",
68d44fe0 587 msg => "Site User '" . $user->userId . "' deleted",
ac1f5536 588 );
a0edb02e 589
495114d1 590 my $logon = $user->userId;
a0edb02e
TC
591
592 $user->remove($req->cfg);
593
495114d1 594 $req->flash("msg:bse/admin/siteusers/userdeleted", [ $logon ]);
a0edb02e
TC
595 my $r = $cgi->param('r');
596 unless ($r) {
495114d1 597 $r = $req->cfg->admin_url2('siteusers', 'list');
a0edb02e 598 }
a0edb02e
TC
599
600 return $req->get_refresh($r);
601}
602
9063386f
TC
603sub req_addform {
604 my ($class, $req, $msg, $errors) = @_;
605
606 my $cgi = $req->cgi;
607
04329a85 608 $msg = $req->message($msg || $errors);
9063386f 609
220c179a
TC
610 my $it = BSE::Util::Iterate->new;
611
612 my @subs = grep $_->{visible}, BSE::SubscriptionTypes->all;
613 my $sub_index;
9063386f
TC
614 my %acts;
615 %acts =
616 (
d5a6b1ee 617 $req->admin_tags,
9063386f
TC
618 message => $msg,
619 error_img => [ \&tag_error_img, $req->cfg, $errors ],
620 ifRequired => [ \&tag_if_required, $req->cfg ],
220c179a
TC
621 $it->make_iterator([ \&iter_flags, $req->cfg], 'flag', 'flags'),
622 ifFlagSet => 0,
623 $it->make_iterator(undef, 'subscription', 'subscriptions', \@subs,
624 \$sub_index),
625 ifSubscribed =>
626 [ \&tag_if_subscribed_register, $cgi, $req->cfg, \@subs, \$sub_index ],
9063386f
TC
627 );
628
4d764c34 629 return $req->dyn_response('admin/users/add', \%acts);
9063386f
TC
630}
631
632sub req_add {
633 my ($class, $req) = @_;
634
635 my $cgi = $req->cgi;
636 my $cfg = $req->cfg;
637
638 my %user;
b7cadc84 639 my @cols = BSE::TB::SiteUser->columns;
9063386f 640 shift @cols;
9063386f 641
288ef5b8
TC
642 my $custom = custom_class($cfg);
643 my @required = $custom->siteuser_add_required($req);
644
9063386f
TC
645 my $nopassword = $cfg->entryBool('site users', 'nopassword', 0);
646 my %errors;
647 my $email = $cgi->param('email');
6aa67dd9 648 $email =~ s/^\s+|\s+$//g;
4c4d3c3f 649 if (!defined $email) { # required check done later
9063386f
TC
650 $email = ''; # prevent undefined value warnings later
651 }
652 elsif ($email !~ /.\@./) {
653 $errors{email} = "Please enter a valid email address";
654 }
655 if ($nopassword) {
656 my $confemail = $cgi->param('confirmemail');
657 if (!defined $confemail or !length $confemail) {
658 $errors{confirmemail} = "Please enter a confirmation email address";
659 }
660 elsif ($email ne $confemail) {
661 $errors{confirmemail} = "Confirmation email should match the Email Address";
662 }
b7cadc84 663 my $user = BSE::TB::SiteUsers->getBy(userId=>$email);
9063386f
TC
664 if ($user) {
665 $errors{email} = "Sorry, email $email already exists as a user";
666 }
667 $user{userId} = $email;
668 $user{password} = '';
669 }
670 else {
9063386f
TC
671 my $userid = $cgi->param('userId');
672 if (!defined $userid || length $userid == 0) {
673 $errors{userId} = "Please enter a userid";
674 }
675 my $pass = $cgi->param('password');
77f53961 676 $pass =~ s/\A\s+//, $pass =~ s/\s+\z// if defined $pass;
9063386f 677 my $pass2 = $cgi->param('confirm_password');
77f53961
TC
678 $pass2 =~ s/\A\s+//, $pass2 =~ s/\s+\z// if defined $pass2;
679 my %other = map { $_ => scalar $cgi->param($_) }
b7cadc84 680 BSE::TB::SiteUser->password_check_fields;
77f53961 681 my @errors;
9063386f
TC
682 if (!defined $pass || length $pass == 0) {
683 $errors{password} = "Please enter a password";
684 }
b7cadc84 685 elsif (!BSE::TB::SiteUser->check_password_rules
77f53961
TC
686 (
687 password => $pass,
688 username => $userid,
689 other => \%other,
690 errors => \@errors,
691 )) {
692 $errors{password} = \@errors;
9063386f
TC
693 }
694 elsif (!defined $pass2 || length $pass2 == 0) {
695 $errors{confirm_password} = "Please enter a confirmation password";
696 }
697 elsif ($pass ne $pass2) {
698 $errors{confirm_password} =
699 "The confirmation password is different from the password";
700 }
b7cadc84 701 my $user = BSE::TB::SiteUsers->getBy(userId=>$userid);
9063386f
TC
702 if ($user) {
703 # give the user a suggestion
704 my $workuser = $userid;
705 $workuser =~ s/\d+$//;
706 my $suffix = 1;
707 for my $suffix (1..100) {
b7cadc84 708 unless (BSE::TB::SiteUsers->getBy(userId=>"$workuser$suffix")) {
9063386f
TC
709 $cgi->param(userid=>"$workuser$suffix");
710 last;
711 }
712 }
713 $errors{userId} = "Sorry, user $userid already exists";
714 }
715 $user{userId} = $userid;
716 $user{password} = $pass;
717 }
718
719 unless ($errors{email}) {
b7cadc84 720 my $checkemail = BSE::TB::SiteUser->generic_email($email);
9063386f
TC
721 require 'BSE/EmailBlacklist.pm';
722 my $blackentry = BSE::EmailBlacklist->getEntry($checkemail);
723 if ($blackentry) {
724 $errors{email} = "Email $email is blacklisted: $blackentry->{why}";
725 }
726 }
727
728 my @mod_cols = grep !$donttouch{$_}, @cols;
729 for my $col (@mod_cols) {
730 my $value = $cgi->param($col);
731 if ($cfg->entryBool('site users', "require_$col")) {
732 unless (defined $value && $value ne '') {
733 my $disp = $cfg->entry('site users', "display_$col", "\u$col");
734
735 $errors{$col} = "$disp is a required field";
736 }
737 }
738 if (defined $value) {
739 $user{$col} = $value;
740 }
741 }
3c32512d
TC
742
743 my $aff_name = $cgi->param('affiliate_name');
744 $aff_name = _validate_affiliate_name($req, $aff_name, \%errors);
745 defined $aff_name or $aff_name = '';
746
9063386f
TC
747 if (keys %errors) {
748 return $class->req_addform($req, undef, \%errors);
749 }
750
751 $user{email} = $email;
3c32512d 752 $user{affiliate_name} = $aff_name;
9063386f
TC
753 if ($nopassword) {
754 use BSE::Util::Secure qw/make_secret/;
755 $user{password} = make_secret($cfg);
756 }
d49f56a6
TC
757 my @flags = flags($cfg);
758 my %flags = map { $_->{id} => 1 } @flags;
759 $user{flags} = join('', grep exists $flags{$_}, $cgi->param('flags'));
9063386f
TC
760
761 my $user;
762 eval {
b7cadc84 763 $user = BSE::TB::SiteUsers->make(%user);
9063386f
TC
764 };
765 if ($user) {
220c179a 766 my $subs = $class->save_subs($req, $user);
45408d74
TC
767
768 $req->audit
769 (
770 actor => $req->user || "U",
771 object => $user,
772 component => "members::add",
68d44fe0 773 msg => "Site User '" . $user->userId . "' created",
87a74ac9 774 level => "notice",
45408d74
TC
775 );
776
495114d1
TC
777 $req->flash("msg:bse/admin/siteusers/usercreated", [ $user ]);
778
9063386f
TC
779 my $msg;
780 if ($nopassword) {
781 my $code;
782 my $sent_ok = $user->send_conf_request($cgi, $cfg, \$code, \$msg);
783 }
220c179a
TC
784 else {
785 if ($subs) {
786 my $code;
787 my $sent_ok = $user->send_conf_request($cgi, $cfg, \$code, \$msg);
788 }
f197f061
TC
789 else {
790 if ($cfg->entry
791 ('site users', 'notify_register_customer_admin',
792 $cfg->entry('site users', 'notify_register_customer'))) {
793 $user->send_registration_notify
794 (
795 remote_addr => $req->ip_address
796 );
797 }
798 }
220c179a 799 }
505456b1 800
505456b1 801 $custom->siteusers_changed($cfg);
ad34a019
TC
802 $custom->can('siteuser_add')
803 and $custom->siteuser_add($user, 'admin', $cfg);
505456b1 804
9063386f
TC
805 my $r = $cgi->param('r');
806 unless ($r) {
495114d1 807 $r = $req->cfg->admin_url2('siteusers', 'list');
9063386f 808 }
e3d242f7 809 $r .= "&m=".escape_uri($msg) if $msg;
9063386f
TC
810 return BSE::Template->get_refresh($r, $cfg);
811 }
812 else {
b27af108 813 $class->req_addform($req, "Database error $@");
9063386f
TC
814 }
815}
816
220c179a
TC
817sub save_subs {
818 my ($class, $req, $user) = @_;
819
820 my @subs = grep $_->{visible}, BSE::SubscriptionTypes->all;
821 my %subs = map { $_->{id} => $_ } @subs;
822 my @subids = $req->cgi->param('subscription');
823 $user->removeSubscriptions;
824 require BSE::SubscribedUsers;
825 my @cols = BSE::SubscribedUser->columns;
826 shift @cols;
827 my $found = 0;
828 for my $id (@subids) {
829 if ($subs{$id}) {
830 my %usersub;
831 $usersub{subId} = $id;
832 $usersub{userId} = $user->{id};
833
834 BSE::SubscribedUsers->add(@usersub{@cols});
835 ++$found;
836 }
837 }
838
839 $found;
840}
841
74b3689a
TC
842sub req_unlock {
843 my ($class, $req) = @_;
844
845 my $cgi = $req->cgi;
846 my $cfg = $req->cfg;
847
848 my $id = $cgi->param('id');
849 $id && $id =~ /^\d+$/
850 or return $class->req_list($req, "No user id supplied");
851
b7cadc84 852 my $user = BSE::TB::SiteUsers->getByPkey($id)
74b3689a
TC
853 or return $class->req_list($req, "No user $id found");
854
855 $user->unlock(request => $req);
856 $req->flash_notice("msg:bse/user/unlocked", [ $user ]);
857
858 my $uri = $cgi->param("r") || $cfg->admin_url2("siteusers", "list");
859
860 return $req->get_refresh($uri);
861}
862
3c32512d
TC
863sub _validate_affiliate_name {
864 my ($req, $aff_name, $errors, $user) = @_;
865
866 my $display = $req->cfg->entry('site users', 'display_affiliate_name',
867 "Affiliate name");
868 my $required = $req->cfg->entry('site users', 'require_affiliate_name', 0);
869
870 if (defined $aff_name) {
871 $aff_name =~ s/^\s+|\s+$//g;
872 if (length $aff_name) {
873 if ($aff_name =~ /^\w+$/) {
b7cadc84 874 my $other = BSE::TB::SiteUsers->getBy(affiliate_name => $aff_name);
3c32512d
TC
875 if ($other && (!$user || $other->{id} != $user->{id})) {
876 $errors->{affiliate_name} = "$display $aff_name is already in use";
877 }
878 else {
879 return $aff_name;
880 }
881 }
882 else {
883 $errors->{affiliate_name} = "invalid $display, no spaces or special characters are allowed";
884 }
885 }
886 elsif ($required) {
887 $errors->{affiliate_name} = "$display is a required field";
888 }
889 else {
890 return '';
891 }
892 }
893
894 # always required if making a new user
895 if (!$errors->{affiliate_name} && $required && !$user) {
896 $errors->{affiliate_name} = "$display is a required field";
897 }
898
899 return;
900}
220c179a 901
efcc5a30
TC
902sub _get_group {
903 my ($req, $msg) = @_;
904
905 my $id = $req->cgi->param('id');
32696f84 906 defined $id && $id =~ /^-?\d+$/
efcc5a30 907 or do { $$msg = "Missing or invalid group id"; return };
32696f84
TC
908
909 my $group;
efcc5a30 910 require BSE::TB::SiteUserGroups;
32696f84
TC
911 if ($id < 0) {
912 $group = BSE::TB::SiteUserGroups->getQueryGroup($req->cfg, $id);
913 }
914 else {
915 $group = BSE::TB::SiteUserGroups->getByPkey($id);
916 }
efcc5a30
TC
917 $group
918 or do { $$msg = "Unknown group id"; return };
919
920 $group;
921}
922
923sub req_grouplist {
924 my ($class, $req, $errors) = @_;
925
926 require BSE::TB::SiteUserGroups;
32696f84 927 my @groups = BSE::TB::SiteUserGroups->admin_and_query_groups($req->cfg);
efcc5a30
TC
928
929 my $msg = $req->message($errors);
930
931 my $it = BSE::Util::Iterate->new;
932 my %acts;
933 %acts =
934 (
d5a6b1ee 935 $req->admin_tags,
efcc5a30
TC
936 msg=>$msg,
937 message=>$msg,
938 $it->make_iterator(undef, 'group', 'groups', \@groups),
939 );
940
4d764c34 941 return $req->dyn_response('admin/users/grouplist', \%acts);
efcc5a30
TC
942}
943
944sub req_addgroupform {
945 my ($class, $req, $errors) = @_;
946
947 my $msg = $req->message($errors);
948
949 my %acts;
950 %acts =
951 (
d5a6b1ee 952 $req->admin_tags,
efcc5a30
TC
953 msg=>$msg,
954 message=>$msg,
495114d1 955 ifError => 1,
efcc5a30
TC
956 error_img => [ \&tag_error_img, $req->cfg, $errors ],
957 );
958
4d764c34 959 return $req->dyn_response('admin/users/groupadd', \%acts);
efcc5a30
TC
960}
961
962sub req_addgroup {
963 my ($class, $req) = @_;
964
965 require BSE::TB::SiteUserGroups;
966 my %fields = BSE::TB::SiteUserGroup->valid_fields;
967 my %rules = BSE::TB::SiteUserGroup->valid_rules;
968
969 my %errors;
970 $req->validate(errors=>\%errors,
971 fields=>\%fields,
972 rules=>\%rules,
495114d1 973 section=>SITEUSER_GROUP_SECT);
c2096d67
TC
974 my $cgi = $req->cgi;
975 my $name = $cgi->param('name');
495114d1
TC
976 unless ($errors{name}) {
977 my ($other) = BSE::TB::SiteUserGroups->getBy(name => $name);
978 $other and $errors{name} = "Group '$name' already exists";
979 }
980 keys %errors
981 and return $class->req_addgroupform($req, \%errors);
982
efcc5a30
TC
983 my $group = BSE::TB::SiteUserGroups->add($name);
984
495114d1 985 $req->flash("msg:bse/admin/siteusers/groupcreated", [ $group ]);
c2096d67
TC
986 my $r = $cgi->param('r');
987 unless ($r) {
495114d1 988 $r = $req->cfg->admin_url2('siteusers', "grouplist");
c2096d67
TC
989 }
990 return BSE::Template->get_refresh($r, $req->cfg);
efcc5a30
TC
991}
992
993sub req_editgroup {
994 my ($class, $req, $errors) = @_;
995
996 return $class->_common_group($req, $errors, 'admin/users/groupedit');
997}
998
999sub req_savegroup {
1000 my ($class, $req) = @_;
1001
1002 my $msg;
1003 my $group = _get_group($req, \$msg)
1004 or return $class->req_grouplist($req, { id => $msg });
1005
1006 my %fields = BSE::TB::SiteUserGroup->valid_fields;
1007 my %rules = BSE::TB::SiteUserGroup->valid_rules;
1008
1009 my %errors;
1010 $req->validate(errors=>\%errors,
1011 fields=>\%fields,
1012 rules=>\%rules,
1013 section=>SITEUSER_GROUP_SECT)
1014 or return $class->req_editgroup($req, \%errors);
c2096d67
TC
1015
1016 my $cgi = $req->cgi;
1017 $group->{name} = $cgi->param('name');
efcc5a30
TC
1018 $group->save;
1019
495114d1 1020 $req->flash("msg:bse/admin/siteusers/groupsaved", [ $group ]);
c2096d67
TC
1021 my $r = $cgi->param('r');
1022 unless ($r) {
495114d1 1023 $r = $req->cfg->admin_url2('siteusers', 'grouplist');
c2096d67
TC
1024 }
1025 return BSE::Template->get_refresh($r, $req->cfg);
efcc5a30
TC
1026}
1027
1028sub _common_group {
1029 my ($class, $req, $errors, $template) = @_;
1030
1031 my $msg;
1032 my $group = _get_group($req, \$msg)
1033 or return $class->req_grouplist($req, { id=> $msg });
1034
1035 $msg = $req->message($errors);
32696f84
TC
1036 my $it = BSE::Util::Iterate->new;
1037 my $current_file;
efcc5a30
TC
1038 my %acts;
1039 %acts =
1040 (
d5a6b1ee 1041 $req->admin_tags,
efcc5a30
TC
1042 msg=>$msg,
1043 message=>$msg,
1044 error_img => [ \&tag_error_img, $req->cfg, $errors ],
1045 group => [ \&tag_hash, $group ],
32696f84
TC
1046 $it->make
1047 (
1048 code => [ files => $group ],
1049 single => "groupfile",
1050 plural => "groupfiles",
1051 store => \$current_file,
1052 ),
efcc5a30
TC
1053 );
1054
4d764c34 1055 return $req->dyn_response($template, \%acts);
efcc5a30
TC
1056}
1057
1058sub req_deletegroupform {
1059 my ($class, $req, $errors) = @_;
1060
1061 return $class->_common_group($req, $errors, 'admin/users/groupdelete');
1062}
1063
1064sub req_deletegroup {
1065 my ($class, $req) = @_;
1066
1067 my $msg;
1068 my $group = _get_group($req, \$msg)
1069 or return $class->req_grouplist($req, { id=>$msg });
1070
495114d1 1071 my $name = $group->name;
efcc5a30
TC
1072 $group->remove;
1073
c2096d67 1074 my $r = $req->cgi->param('r');
495114d1 1075 $req->flash("msg:bse/admin/siteusers/groupdeleted", [ $name ]);
c2096d67 1076 unless ($r) {
495114d1 1077 $r = $req->cfg->admin_url2('siteusers', "grouplist");
c2096d67
TC
1078 }
1079 return BSE::Template->get_refresh($r, $req->cfg);
efcc5a30
TC
1080}
1081
1082sub tag_ifMember {
1083 my ($ruser, $members) = @_;
1084
1085 $$ruser or return 0;
1086 exists $members->{$$ruser->{id}};
1087}
1088
1089sub req_groupmemberform {
1090 my ($class, $req, $errors) = @_;
1091
1092 my $msg;
1093 my $group = _get_group($req, \$msg)
1094 or return $class->req_grouplist($req, { id=>$msg });
1095
1096 $msg = $req->message($errors);
1097
1098 my %members = map { $_=> 1 } $group->member_ids;
b7cadc84 1099 my @siteusers = BSE::TB::SiteUsers->all;
efcc5a30
TC
1100
1101 my $user;
1102
1103 my $it = BSE::Util::Iterate->new;
1104 my %acts;
1105 %acts =
1106 (
d5a6b1ee 1107 $req->admin_tags,
efcc5a30
TC
1108 msg=>$msg,
1109 message=>$msg,
1110 error_img => [ \&tag_error_img, $req->cfg, $errors ],
1111 group => [ \&tag_hash, $group ],
1112 $it->make_iterator(undef, 'siteuser', 'siteusers', \@siteusers,
1113 undef, undef, \$user),
1114 ifMember => [ \&tag_ifMember, \$user, \%members ],
1115 );
1116
4d764c34 1117 return $req->dyn_response('admin/users/groupmembers', \%acts);
efcc5a30
TC
1118}
1119
1120sub req_savegroupmembers {
1121 my ($class, $req) = @_;
1122
1123 my $msg;
1124 my $group = _get_group($req, \$msg)
1125 or return $class->req_grouplist($req, { id=>$msg });
1126
1127 my $cgi = $req->cgi;
1128 my %current_ids = map { $_ => 1 } $group->member_ids;
1129 my @to_be_set = $cgi->param('set_is_member');
1130 my %set_ids = map { $_ => 1 } $cgi->param('is_member');
b7cadc84 1131 my %all_ids = map { $_ => 1 } BSE::TB::SiteUsers->all_ids;
efcc5a30 1132
ad34a019
TC
1133 my $custom = custom_class($req->cfg);
1134
efcc5a30
TC
1135 for my $id (@to_be_set) {
1136 next unless $all_ids{$id};
1137
1138 if ($set_ids{$id} && !$current_ids{$id}) {
1139 $group->add_member($id);
ad34a019
TC
1140 $custom->can('group_add_member')
1141 and $custom->group_add_member($group, $id, $req->cfg);
efcc5a30
TC
1142 }
1143 elsif (!$set_ids{$id} && $current_ids{$id}) {
1144 $group->remove_member($id);
ad34a019
TC
1145 $custom->can('group_remove_member')
1146 and $custom->group_remove_member($group, $id, $req->cfg);
efcc5a30
TC
1147 }
1148 }
1149
495114d1 1150 $req->flash("msg:bse/admin/siteusers/membershipsaved", [ $group ]);
c2096d67
TC
1151 my $r = $cgi->param('r');
1152 unless ($r) {
495114d1 1153 $r = $req->cfg->admin_url2('siteusers', 'grouplist');
c2096d67
TC
1154 }
1155 return BSE::Template->get_refresh($r, $req->cfg);
efcc5a30
TC
1156}
1157
6555857d
TC
1158sub req_confirm {
1159 my ($class, $req) = @_;
1160
1161 $ENV{REMOTE_USER} || $req->getuser
1162 or return $class->error($req,
1163 { error => "You must be authenticated to use this function. Either enable access control or setup .htpasswd." });
1164
1165 my $cgi = $req->cgi;
1166 my $id = $cgi->param('id');
1167 defined $id
1168 or return $class->req_list($req, "No site user id supplied");
b7cadc84 1169 my $siteuser = BSE::TB::SiteUsers->getByPkey($id)
6555857d
TC
1170 or return $class->req_list($req, "No such site user found");
1171
1172 $siteuser->{confirmed} = 1;
1173 $siteuser->save;
1174
495114d1 1175 $req->flash("msg:bse/admin/siteusers/confirmed", [ $siteuser ]);
6555857d
TC
1176 my $r = $cgi->param('r');
1177 unless ($r) {
495114d1 1178 $r = $req->cfg->admin_url2('siteusers', 'list');
6555857d
TC
1179 }
1180
1181 return BSE::Template->get_refresh($r, $req->cfg);
1182}
1183
32696f84
TC
1184my %file_fields =
1185 (
1186 content_type =>
1187 {
1188 description => "Content type",
1189 rules => "dh_one_line",
1190 },
1191 category =>
1192 {
1193 description => "Category",
1194 rules => "dh_one_line",
1195 },
1196 modwhen_date =>
1197 {
1198 description => "Last Modified date",
1199 rules => "date",
6450bbad 1200 required_if => "modwhen_time",
32696f84
TC
1201 },
1202 modwhen_time =>
1203 {
1204 description => "Last Modified time",
1205 rules => "time",
1206 required_if => "modwhen_date",
1207 },
1208 title =>
1209 {
1210 description => "Title",
1211 rules => "dh_one_line",
1212 },
1213 body =>
1214 {
1215 description => "Body",
1216 },
1217 );
1218
1219my %save_file_fields =
1220 (
1221 content_type =>
1222 {
1223 description => "Content type",
1224 rules => "dh_one_line",
1225 },
1226 category =>
1227 {
1228 description => "Category",
1229 rules => "dh_one_line",
1230 },
1231 modwhen_date =>
1232 {
1233 description => "Last Modified date",
1234 rules => "date",
6450bbad 1235 required => 1,
32696f84
TC
1236 },
1237 modwhen_time =>
1238 {
1239 description => "Last Modified time",
1240 rules => "time",
1241 required => 1,
1242 },
1243 title =>
1244 {
1245 description => "Title",
1246 rules => "dh_one_line",
1247 required => 1,
1248 },
1249 body =>
1250 {
1251 description => "Body",
1252 },
1253 );
1254
1255sub req_adduserfileform {
1256 my ($self, $req, $errors) = @_;
1257
1258 my $msg;
1259 my $siteuser = _get_user($req, \$msg)
1260 or return $self->req_list($req, $msg);
1261
4ae3f7d7
TC
1262 $msg = $req->message($errors);
1263
32696f84
TC
1264 my %acts =
1265 (
1266 $req->admin_tags,
1267 message => $msg,
1268 siteuser => [ \&tag_hash, $siteuser ],
1269 error_img => [ \&tag_error_img, $req->cfg, $errors ],
4ae3f7d7 1270 ifError => 1,
32696f84
TC
1271 userfile_category => [ tag_userfile_category => $self, $req, undef ],
1272 );
1273
1274 return $req->dyn_response("admin/users/add_user_file", \%acts);
1275}
1276
1277sub req_adduserfile {
1278 my ($self, $req) = @_;
1279
1280 my $msg;
1281 my $user = _get_user($req, \$msg)
1282 or return $self->req_list($req, $msg);
1283
1284 my $cgi = $req->cgi;
1285
1286 $req->check_csrf("admin_user_add_file")
1287 or return $self->csrf_error($req, "admin_user_add_file", "Add Member File");
1288
1289 my %errors;
1290 $req->validate(fields => \%file_fields,
1291 errors => \%errors);
1292
1293 my $file = $cgi->param("file");
1294 my $file_fh = $cgi->upload("file");
1295 unless ($file) {
1296 $errors{file} = "Please select a file";
1297 }
1298 if ($file && -z $file) {
1299 $errors{file} = "File is empty";
1300 }
1301 if (!$errors{$file} && !$file_fh) {
1302 $errors{file} = "Something is wrong with the upload form or your file wasn't found";
1303 }
1304
1305 keys %errors
4ae3f7d7 1306 and return $self->req_adduserfileform($req, \%errors);
32696f84
TC
1307
1308 require BSE::API;
1309 BSE::API->import("bse_add_owned_file");
1310
1311 my %file;
1312 $file{file} = $file_fh;
1313 for my $field (qw/content_type category title body/) {
1314 my ($value) = $cgi->param($field);
1315 defined $value or $value = "";
1316 $file{$field} = $value;
1317 }
1318 $file{download} = $cgi->param('download') ? 1 : 0;
1319 my $mod_date = $cgi->param("modwhen_date");
1320 my $mod_time = $cgi->param("modwhen_time");
1321 if ($mod_date && $mod_time) {
1322 $file{modwhen} = dh_parse_date_sql($mod_date) . " "
1323 . dh_parse_time_sql($mod_time);
1324 }
1325 $file{display_name} = $file . "";
1326 my $upload_info = $cgi->uploadInfo($file);
1327# some content types come through strangely
1328# if (!$file{content_type} && $upload_info->{"Content-Type"}) {
1329# $file{content_type} = $upload_info->{"Content-Type"}
1330# }
1331 for my $key (keys %$upload_info) {
1332 print STDERR "uploadinfo: $key: $upload_info->{$key}\n";
1333 }
1334 local $SIG{__DIE__};
1335 my $owned_file = eval { bse_add_owned_file($req->cfg, $user, %file) };
1336 unless ($owned_file) {
1337 $errors{file} = $@;
1338 return $self->req_edit($req, undef, \%errors);
1339 }
1340
1341 my $r = $cgi->param('r');
495114d1 1342 $req->flash("msg:bse/admin/siteusers/userfilecreated", [ $user, $owned_file ]);
32696f84 1343 unless ($r) {
495114d1 1344 $r = $req->cfg->admin_url2('siteusers', 'edit', { _t => "files", id => $user->id });
32696f84
TC
1345 }
1346
1347 return BSE::Template->get_refresh($r, $req->cfg);
1348}
1349
1350sub _get_user_file {
1351 my ($req, $user, $msg) = @_;
1352
1353 my $file_id = $req->cgi->param("file_id");
1354 unless (defined $file_id && $file_id =~ /^\d+$/) {
1355 $$msg = "Missing or invalid file id";
1356 return;
1357 }
1358 require BSE::TB::OwnedFiles;
1359 my ($file) = BSE::TB::OwnedFiles->getBy
1360 (
1361 owner_type => $user->file_owner_type,
1362 owner_id => $user->id,
1363 id => $file_id
1364 );
1365 unless ($file) {
1366 $$msg = "No such file found";
1367 return;
1368 }
1369
1370 return $file;
1371}
1372
1373sub _show_userfile {
1374 my ($self, $req, $template, $siteuser, $file, $errors) = @_;
1375
1376 my $message = $req->message($errors);
1377
1378 my %acts =
1379 (
1380 $req->admin_tags,
1381 userfile => [ \&tag_hash, $file ],
1382 message => $message,
1383 siteuser => [ \&tag_hash, $siteuser ],
1384 error_img => [ \&tag_error_img, $req->cfg, $errors ],
1385 userfile_category => [ tag_userfile_category => $self, $req, \$file ],
1386 );
1387
1388 return $req->dyn_response($template, \%acts);
1389}
1390
1391sub req_edituserfile {
1392 my ($self, $req, $errors) = @_;
1393
1394 my $msg;
1395 my $siteuser = _get_user($req, \$msg)
1396 or return $self->req_list($req, $msg);
1397
1398 my $file = _get_user_file($req, $siteuser, \$msg)
1399 or return $self->req_list($req, $msg);
1400
1401 return $self->_show_userfile($req, "admin/users/edit_user_file", $siteuser, $file, $errors);
1402}
1403
1404sub req_deluserfileform {
1405 my ($self, $req, $errors) = @_;
1406
1407 my $msg;
1408 my $siteuser = _get_user($req, \$msg)
1409 or return $self->req_list($req, $msg);
1410
1411 my $file = _get_user_file($req, $siteuser, \$msg)
1412 or return $self->req_list($req, $msg);
1413
1414 return $self->_show_userfile($req, "admin/users/delete_user_file", $siteuser, $file, $errors);
1415}
1416
1417sub req_saveuserfile {
1418 my ($self, $req) = @_;
1419
1420 $req->check_csrf("admin_user_edit_file")
1421 or return $self->csrf_error($req, "admin_user_edit_file", "Edit Member File");
1422
1423 my $msg;
1424 my $siteuser = _get_user($req, \$msg)
1425 or return $self->req_list($req, $msg);
1426
1427 my $file = _get_user_file($req, $siteuser, \$msg)
1428 or return $self->req_list($req, $msg);
1429
1430 my %errors;
1431 $req->validate(fields => \%file_fields,
1432 errors => \%errors);
1433
1434 my %changes;
1435 my $cgi = $req->cgi;
1436 my $new_file = $cgi->param("file");
1437 my $new_fh = $cgi->upload("file");
1438
1439 if ($new_file) {
1440 if (!$new_fh) {
1441 $errors{file} = "Something is wrong with the upload form or your file wasn't found";
1442 }
1443 }
1444 unless ($errors{file}) {
1445 -z $new_file
1446 and $errors{file} = "File is empty";
1447 }
1448
1449 keys %errors
1450 and return $self->req_edituserfile($req, \%errors);
1451
1452 for my $field (qw/content_type category title body/) {
1453 my ($value) = $cgi->param($field);
1454 defined $value
1455 and $changes{$field} = $value;
1456 }
1457 if ($new_file && $new_fh) {
1458 $changes{file} = $new_fh;
1459 $changes{display_name} = $new_file;
1460 my $upload_info = $cgi->uploadInfo($new_file);
1461# some content types come through strangely
1462# if (!$changes{content_type} && $upload_info->{"Content-Type"}) {
1463# $changes{content_type} = $upload_info->{"Content-Type"}
1464# }
1465 }
1466 if (defined $changes{content_type} && !$changes{content_type} =~ /\S/) {
1467 $errors{content_type} = "Content type must be set";
1468 }
1469 $changes{download} = $cgi->param('download') ? 1 : 0;
1470 my $mod_date = $cgi->param("modwhen_date");
1471 my $mod_time = $cgi->param("modwhen_time");
1472 if ($mod_date && $mod_time) {
1473 $changes{modwhen} = dh_parse_date_sql($mod_date) . " "
1474 . dh_parse_time_sql($mod_time);
1475 }
1476
1477 require BSE::API;
1478 BSE::API->import("bse_replace_owned_file");
1479 my $good = eval { bse_replace_owned_file($req->cfg, $file, %changes); };
1480
1481 $good
1482 or return $self->req_edituserfile($req, { _ => $@ });
1483
495114d1 1484 $req->flash("msg:bse/admin/siteusers/userfilesaved", [ $siteuser, $file ]);
32696f84
TC
1485 my $r = $cgi->param('r');
1486 unless ($r) {
495114d1 1487 $r = $req->cfg->admin_url2('siteusers', 'edit', { _t => "files", id => $siteuser->id });
32696f84
TC
1488 }
1489
1490 return BSE::Template->get_refresh($r, $req->cfg);
1491}
1492
1493sub req_deluserfile {
1494 my ($self, $req) = @_;
1495
1496 $req->check_csrf("admin_user_del_file")
1497 or return $self->csrf_error($req, "admin_user_del_file", "Delete Member File");
1498
1499 my $msg;
1500 my $siteuser = _get_user($req, \$msg)
1501 or return $self->req_list($req, $msg);
1502
1503 my $file = _get_user_file($req, $siteuser, \$msg)
1504 or return $self->req_list($req, $msg);
1505
495114d1 1506 my $display_name = $file->display_name;
32696f84
TC
1507 require BSE::API;
1508 BSE::API->import("bse_delete_owned_file");
1509 my $good = eval { bse_delete_owned_file($req->cfg, $file); };
1510
1511 $good
1512 or return $self->req_deluserfileform($req, { _ => $@ });
1513
495114d1 1514 $req->flash("msg:bse/admin/siteusers/userfiledeleted", [ $siteuser, $display_name ]);
32696f84
TC
1515 my $r = $req->cgi->param('r');
1516 unless ($r) {
495114d1 1517 $r = $req->cfg->admin_url2('siteusers', 'edit', { _t => "files", id => $siteuser->id });
32696f84
TC
1518 }
1519
1520 return BSE::Template->get_refresh($r, $req->cfg);
1521}
1522
1523sub req_addgroupfileform {
1524 my ($self, $req, $errors) = @_;
1525
1526 my $msg;
1527 my $group = _get_group($req, \$msg)
1528 or return $self->req_list($req, $msg);
1529
4ae3f7d7
TC
1530 $msg = $req->message($errors);
1531
32696f84
TC
1532 my %acts =
1533 (
1534 $req->admin_tags,
1535 message => $msg,
1536 group => [ \&tag_hash, $group ],
1537 error_img => [ \&tag_error_img, $req->cfg, $errors ],
4ae3f7d7 1538 ifError => 1,
32696f84
TC
1539 userfile_category => [ tag_userfile_category => $self, $req, undef ],
1540 );
1541
1542 return $req->dyn_response("admin/users/add_group_file", \%acts);
1543}
1544
1545sub req_addgroupfile {
1546 my ($self, $req) = @_;
1547
1548 my $msg;
1549 my $group = _get_group($req, \$msg)
1550 or return $self->req_list($req, $msg);
1551
1552 my $cgi = $req->cgi;
1553
1554 $req->check_csrf("admin_group_add_file")
1555 or return $self->csrf_error($req, "admin_group_add_file", "Add Member File");
1556
1557 my %errors;
1558 $req->validate(fields => \%file_fields,
1559 errors => \%errors);
1560
1561 my $file = $cgi->param("file");
1562 my $file_fh = $cgi->upload("file");
1563 unless ($file) {
1564 $errors{file} = "Please select a file";
1565 }
1566 if ($file && -z $file) {
1567 $errors{file} = "File is empty";
1568 }
1569 if (!$errors{$file} && !$file_fh) {
1570 $errors{file} = "Something is wrong with the upload form or your file wasn't found";
1571 }
1572
1573 keys %errors
4ae3f7d7 1574 and return $self->req_addgroupfileform($req, \%errors);
32696f84
TC
1575
1576 require BSE::API;
1577 BSE::API->import("bse_add_owned_file");
1578
1579 my %file;
1580 $file{file} = $file_fh;
1581 for my $field (qw/content_type category title body/) {
1582 my ($value) = $cgi->param($field);
1583 defined $value or $value = "";
1584 $file{$field} = $value;
1585 }
1586 $file{download} = $cgi->param('download') ? 1 : 0;
1587 my $mod_date = $cgi->param("modwhen_date");
1588 my $mod_time = $cgi->param("modwhen_time");
1589 if ($mod_date && $mod_time) {
1590 $file{modwhen} = dh_parse_date_sql($mod_date) . " "
1591 . dh_parse_time_sql($mod_time);
1592 }
1593 $file{display_name} = $file . "";
1594 my $upload_info = $cgi->uploadInfo($file);
1595# some content types come through strangely
1596# if (!$file{content_type} && $upload_info->{"Content-Type"}) {
1597# $file{content_type} = $upload_info->{"Content-Type"}
1598# }
1599 for my $key (keys %$upload_info) {
1600 print STDERR "uploadinfo: $key: $upload_info->{$key}\n";
1601 }
1602 local $SIG{__DIE__};
1603 my $owned_file = eval { bse_add_owned_file($req->cfg, $group, %file) };
1604 unless ($owned_file) {
1605 $errors{file} = $@;
1606 return $self->req_edit($req, undef, \%errors);
1607 }
1608
1609 my $r = $cgi->param('r');
495114d1 1610 $req->flash("msg:bse/admin/siteusers/groupfilecreated", [ $group, $owned_file ]);
32696f84 1611 unless ($r) {
495114d1 1612 $r = $req->cfg->admin_url2('siteusers', 'editgroup', { _t => "files", id => $group->id });
32696f84
TC
1613 }
1614
1615 return BSE::Template->get_refresh($r, $req->cfg);
1616}
1617
1618sub _get_group_file {
1619 my ($req, $group, $msg) = @_;
1620
1621 my $file_id = $req->cgi->param("file_id");
1622 unless (defined $file_id && $file_id =~ /^\d+$/) {
1623 $$msg = "Missing or invalid file id";
1624 return;
1625 }
1626 require BSE::TB::OwnedFiles;
1627 my ($file) = BSE::TB::OwnedFiles->getBy
1628 (
1629 owner_type => $group->file_owner_type,
1630 owner_id => $group->id,
1631 id => $file_id
1632 );
1633 unless ($file) {
1634 $$msg = "No such file found";
1635 return;
1636 }
1637
1638 return $file;
1639}
1640
1641sub _show_groupfile {
1642 my ($self, $req, $template, $group, $file, $errors) = @_;
1643
1644 my $message = $req->message($errors);
1645
1646 my %acts =
1647 (
1648 $req->admin_tags,
1649 groupfile => [ \&tag_hash, $file ],
1650 message => $message,
1651 group => [ \&tag_hash, $group ],
1652 error_img => [ \&tag_error_img, $req->cfg, $errors ],
1653 userfile_category => [ tag_userfile_category => $self, $req, \$file ],
1654 );
1655
1656 return $req->dyn_response($template, \%acts);
1657}
1658
1659sub req_editgroupfile {
1660 my ($self, $req, $errors) = @_;
1661
1662 my $msg;
1663 my $group = _get_group($req, \$msg)
1664 or return $self->req_list($req, $msg);
1665
1666 my $file = _get_group_file($req, $group, \$msg)
1667 or return $self->req_list($req, $msg);
1668
1669 return $self->_show_groupfile($req, "admin/users/edit_group_file", $group, $file, $errors);
1670}
1671
1672sub req_delgroupfileform {
1673 my ($self, $req, $errors) = @_;
1674
1675 my $msg;
1676 my $group = _get_group($req, \$msg)
1677 or return $self->req_list($req, $msg);
1678
1679 my $file = _get_group_file($req, $group, \$msg)
1680 or return $self->req_list($req, $msg);
1681
1682 return $self->_show_groupfile($req, "admin/users/delete_group_file", $group, $file, $errors);
1683}
1684
1685sub req_savegroupfile {
1686 my ($self, $req) = @_;
1687
1688 $req->check_csrf("admin_group_edit_file")
1689 or return $self->csrf_error($req, "admin_group_edit_file", "Edit Member File");
1690
1691 my $msg;
1692 my $group = _get_group($req, \$msg)
1693 or return $self->req_list($req, $msg);
1694
1695 my $file = _get_group_file($req, $group, \$msg)
1696 or return $self->req_list($req, $msg);
1697
1698 my %errors;
1699 $req->validate(fields => \%file_fields,
1700 errors => \%errors);
1701
1702 my %changes;
1703 my $cgi = $req->cgi;
1704 my $new_file = $cgi->param("file");
1705 my $new_fh = $cgi->upload("file");
1706
1707 if ($new_file) {
1708 if (!$new_fh) {
1709 $errors{file} = "Something is wrong with the upload form or your file wasn't found";
1710 }
1711 }
1712 unless ($errors{file}) {
1713 -z $new_file
1714 and $errors{file} = "File is empty";
1715 }
1716
1717 keys %errors
1718 and return $self->req_editgroupfile($req, \%errors);
1719
1720 for my $field (qw/content_type category title body/) {
1721 my ($value) = $cgi->param($field);
1722 defined $value
1723 and $changes{$field} = $value;
1724 }
1725 if ($new_file && $new_fh) {
1726 $changes{file} = $new_fh;
1727 $changes{display_name} = $new_file;
1728 my $upload_info = $cgi->uploadInfo($new_file);
1729# some content types come through strangely
1730# if (!$changes{content_type} && $upload_info->{"Content-Type"}) {
1731# $changes{content_type} = $upload_info->{"Content-Type"}
1732# }
1733 }
1734 if (defined $changes{content_type} && !$changes{content_type} =~ /\S/) {
1735 $errors{content_type} = "Content type must be set";
1736 }
1737 $changes{download} = $cgi->param('download') ? 1 : 0;
1738 my $mod_date = $cgi->param("modwhen_date");
1739 my $mod_time = $cgi->param("modwhen_time");
1740 if ($mod_date && $mod_time) {
1741 $changes{modwhen} = dh_parse_date_sql($mod_date) . " "
1742 . dh_parse_time_sql($mod_time);
1743 }
1744
1745 require BSE::API;
1746 BSE::API->import("bse_replace_owned_file");
1747 my $good = eval { bse_replace_owned_file($req->cfg, $file, %changes); };
1748
1749 $good
1750 or return $self->req_editgroupfile($req, { _ => $@ });
1751
495114d1 1752 $req->flash("msg:bse/admin/siteusers/groupfilesaved", [ $group, $file ]);
32696f84
TC
1753 my $r = $cgi->param('r');
1754 unless ($r) {
495114d1 1755 $r = $req->cfg->admin_url2('siteusers', 'editgroup', { _t => "files", id => $group->id });
32696f84
TC
1756 }
1757
1758 return BSE::Template->get_refresh($r, $req->cfg);
1759}
1760
1761sub req_delgroupfile {
1762 my ($self, $req) = @_;
1763
1764 $req->check_csrf("admin_group_del_file")
1765 or return $self->csrf_error($req, "admin_group_del_file", "Delete Member File");
1766
1767 my $msg;
1768 my $group = _get_group($req, \$msg)
1769 or return $self->req_list($req, $msg);
1770
1771 my $file = _get_group_file($req, $group, \$msg)
1772 or return $self->req_list($req, $msg);
1773
495114d1
TC
1774 my $display_name = $file->display_name;
1775
32696f84
TC
1776 require BSE::API;
1777 BSE::API->import("bse_delete_owned_file");
1778 my $good = eval { bse_delete_owned_file($req->cfg, $file); };
1779
1780 $good
1781 or return $self->req_delgroupfileform($req, { _ => $@ });
1782
495114d1 1783 $req->flash("msg:bse/admin/siteusers/groupfiledeleted", [ $group, $display_name ]);
32696f84
TC
1784 my $r = $req->cgi->param('r');
1785 unless ($r) {
495114d1 1786 $r = $req->cfg->admin_url2('siteusers', 'editgroup', { _t => "files", id => $group->id });
32696f84
TC
1787 }
1788
1789 return BSE::Template->get_refresh($r, $req->cfg);
1790}
1791
1792sub _get_user {
1793 my ($req, $msg) = @_;
1794
1795 my $id = $req->cgi->param('id');
1796 defined $id && $id =~ /^\d+$/
1797 or do { $$msg = "Missing or invalid user id"; return };
1798 require BSE::TB::SiteUserGroups;
b7cadc84 1799 my $group = BSE::TB::SiteUsers->getByPkey($id);
32696f84
TC
1800 $group
1801 or do { $$msg = "Unknown user id"; return };
1802
1803 $group;
1804}
1805
1806sub csrf_error {
1807 my ($self, $req, $name, $description) = @_;
1808
1809 my %errors;
1810 my $msg = $req->csrf_error;
1811 $errors{_csrfp} = $msg;
1812 return $self->req_list($req, "$description: $msg ($name)");
1813}
1814
1815sub tag_page_args {
1816 my ($self, $page_args, $args) = @_;
1817
1818 my %args = %$page_args;
1819 if ($args) {
1820 delete @args{split ' ', $args};
1821 }
1822
1823 return join "&amp;", map { "$_=" . escape_uri($args{$_}) } keys %args;
1824}
1825
1826sub tag_page_argsh {
1827 my ($self, $page_args, $args) = @_;
1828
1829 my %args = %$page_args;
1830 if ($args) {
1831 delete @args{split ' ', $args};
1832 }
1833
1834 return join "", map
1835 {
1836 my $value = escape_html($args{$_});
1837 qq(<input type="hidden" name="$_" value="$value" />);
1838 } keys %args;
1839}
1840
1841sub tag_fileaccess_user {
1842 my ($rcurrent, $cache) = @_;
1843
1844 $$rcurrent
1845 or return '';
1846 my $id = $$rcurrent->siteuser_id;
1847 exists $cache->{$id}
b7cadc84 1848 or $cache->{$id} = BSE::TB::SiteUsers->getByPkey($id);
32696f84
TC
1849
1850 $cache->{$id}
1851 or return "** No user $id";
1852
1853 return escape_html($cache->{$id}->userId);
1854}
1855
1856sub tag_ifFileuser {
1857 my ($rcurrent, $cache) = @_;
1858
1859 $$rcurrent
1860 or return '';
1861 my $id = $$rcurrent->siteuser_id;
1862 exists $cache->{$id}
b7cadc84 1863 or $cache->{$id} = BSE::TB::SiteUsers->getByPkey($id);
32696f84
TC
1864
1865 return defined $cache->{$id};
1866}
1867
1868sub _find_file_owner {
1869 my ($owner_type, $owner_id, $cfg, $cache) = @_;
1870
1871 require BSE::TB::SiteUserGroups;
1872 my $owner;
b7cadc84
AO
1873 if ($owner_type eq BSE::TB::SiteUser->file_owner_type) {
1874 if ($cache->{$owner_id} ||= BSE::TB::SiteUsers->getByPkey($owner_id)) {
32696f84
TC
1875 $owner = $cache->{$owner_id}->data_only;
1876 $owner->{desc} = "User: " . $owner->{userId};
1877 }
1878 else {
1879 return;
1880 }
1881 }
1882 elsif ($owner_type eq BSE::TB::SiteUserGroup->file_owner_type) {
1883 my $group;
1884 if ($owner_id < 0) {
1885 $group = BSE::TB::SiteUserGroups->getQueryGroup($cfg, $owner_id);
1886 }
1887 else {
1888 $group = BSE::TB::SiteUserGroups->getByPkey($owner_id);
1889 }
1890 $group
1891 or return;
1892 $owner = $group->data_only;
1893 $owner->{desc} = "Group: " . $group->{name};
1894 }
1895 else {
1896 print STDERR "** Unknown file owner type $owner_type\n";
1897 return;
1898 }
1899
1900 return $owner;
1901}
1902
1903sub tag_fileowner {
1904 my ($rcurrent, $cache, $cfg, $args) = @_;
1905
1906 $$rcurrent or return "";
1907
1908 my $owner = _find_file_owner($$rcurrent->{owner_type}, $$rcurrent->{owner_id}, $cfg, $cache)
1909 or return "Unknown";
1910
1911 return tag_hash($owner, $args);
1912}
1913
1914sub tag_filecat {
1915 my ($rcurrent, $cats) = @_;
1916
1917 $$rcurrent
1918 or return '';
1919
1920 $cats->{$$rcurrent->{category}};
1921}
1922
1923sub req_fileaccesslog {
1924 my ($self, $req) = @_;
1925
1926 my @filters;
1927 my $cgi = $req->cgi;
1928 my %page_args;
1929 my $file_id = $cgi->param("file_id");
1930 my $file;
1931 if ($file_id && $file_id =~ /^\d+$/) {
1932 require BSE::TB::OwnedFiles;
1933 $file = BSE::TB::OwnedFiles->getByPkey($file_id);
1934 if ($file) {
1935 push @filters, [ '=', file_id => $file_id ];
1936 $page_args{file_id} = $file_id;
1937 }
1938 }
1939 my $siteuser_id = $cgi->param('siteuser_id');
1940 my $user;
1941 if ($siteuser_id && $siteuser_id =~ /^\d+$/) {
b7cadc84 1942 $user = BSE::TB::SiteUsers->getByPkey($siteuser_id);
32696f84
TC
1943 if ($user) {
1944 push @filters, [ '=', siteuser_id => $siteuser_id ];
1945 $page_args{siteuser_id} = $siteuser_id;
1946 }
1947 }
1948 my $owner_id = $cgi->param("owner_id");
1949 my $owner_type = $cgi->param("owner_type") || "U";
1950 my $owner;
1951 my $owner_desc = '';
1952 my %user_cache;
1953 if (defined $owner_id) {
1954 push @filters,
1955 (
1956 [ '=', owner_id => $owner_id ],
1957 [ '=', owner_type => $owner_type ],
1958 );
1959 $owner = _find_file_owner($owner_type, $owner_id, $req->cfg, \%user_cache);
1960 if ($owner) {
1961 $owner_desc = $owner->{desc};
1962 }
1963 if ($owner) {
1964 $page_args{owner_type} = $owner_type;
1965 $page_args{owner_id} = $owner_id;
1966 }
1967 }
1968
1969 require BSE::TB::OwnedFiles;
1970 my %categories = map { $_->{id} => escape_html($_->{name}) }
1971 BSE::TB::OwnedFiles->categories($req->cfg);
1972
1973 my $category_id = $cgi->param("category");
1974 my $category;
1975 if (defined $category_id && $categories{$category_id}) {
1976 $category = $categories{$category_id};
1977 push @filters,
1978 [ "=", category => $category_id ];
1979 $page_args{category} = $category_id;
1980 }
1981 use POSIX qw(strftime);
1982 my %errors;
1983 my $from = $cgi->param("from") || strftime("%d/%m/%Y", localtime(time()-30*86400));
1984 my $to = $cgi->param("to") || strftime("%d/%m/%Y", localtime);
1985 my $from_sql = dh_parse_date_sql($from)
1986 or $errors{from_sql} = "Invalid from date";
1987 my $to_sql = dh_parse_date_sql($to)
1988 or $errors{to_sql} = "Invalid to date";
1989
1990 require BSE::TB::FileAccessLog;
1991 my @entries;
1992 unless (keys %errors) {
3334157f 1993 push @filters, [ between => when_at => $from_sql, "$to_sql 23:59:59" ];
32696f84
TC
1994 $cgi->param(from => $from);
1995 $cgi->param(to => $to);
1996 $page_args{from} = $from;
1997 $page_args{to} = $to;
1998 @entries = map $_->{id}, BSE::TB::FileAccessLog->query
1999 (
2000 [ qw/id/ ],
2001 \@filters,
2002 {
2003 order => 'when_at desc'
2004 },
2005 );
2006 }
2007
2008 my $it = BSE::Util::Iterate->new;
2009 my $current_access;
2010 my %acts =
2011 (
2012 $req->admin_tags,
2013 $it->make_paged
2014 (
2015 data => \@entries,
2016 fetch => [ getByPkey => 'BSE::TB::FileAccessLog' ],
2017 cgi => $req->cgi,
2018 single => "fileaccess",
2019 plural => "fileaccesses",
2020 store => \$current_access,
2021 name => "fileaccesses",
2022 session => $req->session,
2023 perpage_parm => "pp=100",
2024 ),
2025 ifOwner => defined $owner,
2026 owner => [ \&tag_hash, $owner ],
2027 owner_type => (defined $owner_type ? $owner_type : ''),
2028 owner_desc => escape_html($owner_desc),
2029 ifSiteuser => defined $user,
2030 siteuser => [ \&tag_hash, $user ],
2031 ifFile => defined $file,
2032 file => [ \&tag_hash, $file ],
2033 page_args => [ tag_page_args => $self, \%page_args ],
2034 page_argsh => [ tag_page_argsh => $self, \%page_args ],
2035 user => [ \&tag_fileaccess_user, \$current_access, \%user_cache ],
2036 ifFileuser => [ \&tag_ifFileuser, \$current_access, \%user_cache ],
2037 fileowner => [ \&tag_fileowner, \$current_access, \%user_cache, $req->cfg ],
2038 filecat => [ \&tag_filecat, \$current_access, \%categories ],
2039 error_img =>[ \&tag_error_img, $req->cfg, \%errors ],
2040 ifCategory => $category,
2041 category => escape_html($category),
2042 );
2043
2044 return $req->dyn_response("admin/users/fileaccess", \%acts);
2045}
2046
9063386f 20471;