1 #!/usr/bin/env perl -wT
2 # -*- Mode: perl; indent-tabs-mode: nil -*-
4 # The contents of this file are subject to the Mozilla Public
5 # License Version 1.1 (the "License"); you may not use this file
6 # except in compliance with the License. You may obtain a copy of
7 # the License at http://www.mozilla.org/MPL/
9 # Software distributed under the License is distributed on an "AS
10 # IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
11 # implied. See the License for the specific language governing
12 # rights and limitations under the License.
14 # The Original Code is the Bugzilla Bug Tracking System.
16 # Contributor(s): Marc Schumann <wurblzap@gmail.com>
17 # Lance Larsh <lance.larsh@oracle.com>
18 # Frédéric Buclin <LpSolit@gmail.com>
19 # David Lawrence <dkl@redhat.com>
20 # Vlad Dascalu <jocuri@softhome.net>
21 # Gavin Shelley <bugzilla@chimpychompy.org>
27 use Bugzilla
::Constants
;
32 use Bugzilla
::BugMail
;
38 my $user = Bugzilla
->login(LOGIN_REQUIRED
);
40 my $cgi = Bugzilla
->cgi;
41 my $template = Bugzilla
->template;
42 my $dbh = Bugzilla
->dbh;
43 my $userid = $user->id;
44 my $editusers = $user->in_group('editusers');
47 # Reject access if there is no sense in continuing.
50 || ThrowUserError
("auth_failure", {group
=> "editusers",
51 reason
=> "cant_bless",
58 my $action = $cgi->param('action') || 'search';
59 my $otherUserID = $cgi->param('userid');
60 my $otherUserLogin = $cgi->param('user');
61 my $token = $cgi->param('token');
63 # Prefill template vars with data used in all or nearly all templates
64 $vars->{'editusers'} = $editusers;
65 mirrorListSelectionValues
();
67 ###########################################################################
68 if ($action eq 'search') {
69 # Allow to restrict the search to any group the user is allowed to bless.
70 $vars->{'restrictablegroups'} = $user->bless_groups();
71 $template->process('admin/users/search.html.tmpl', $vars)
72 || ThrowTemplateError
($template->error());
74 ###########################################################################
75 } elsif ($action eq 'list') {
76 my $matchvalue = $cgi->param('matchvalue') || '';
77 my $matchstr = $cgi->param('matchstr');
78 my $matchtype = $cgi->param('matchtype');
79 my $grouprestrict = $cgi->param('grouprestrict') || '0';
80 my $query = 'SELECT DISTINCT userid, login_name, realname, disabledtext ' .
86 # If a group ID is given, make sure it is a valid one.
89 $group = new Bugzilla
::Group
(scalar $cgi->param('groupid'));
90 $group || ThrowUserError
('invalid_group_ID');
93 if (!$editusers && Bugzilla
->params->{'usevisibilitygroups'}) {
94 # Show only users in visible groups.
95 $visibleGroups = $user->visible_groups_as_string();
98 $query .= qq{, user_group_map AS ugm
99 WHERE ugm
.user_id
= profiles
.userid
101 AND ugm
.group_id IN
($visibleGroups)
103 $nextCondition = 'AND';
107 if ($grouprestrict eq '1') {
108 $query .= qq{, user_group_map AS ugm
109 WHERE ugm
.user_id
= profiles
.userid
112 $nextCondition = 'AND';
115 $nextCondition = 'WHERE';
119 if (!$visibleGroups) {
120 $vars->{'users'} = {};
123 # Handle selection by login name, real name, or userid.
124 if (defined($matchtype)) {
125 $query .= " $nextCondition ";
127 if ($matchvalue eq 'userid') {
129 my $stored_matchstr = $matchstr;
130 detaint_natural
($matchstr)
131 || ThrowUserError
('illegal_user_id', {userid
=> $stored_matchstr});
133 $expr = "profiles.userid";
134 } elsif ($matchvalue eq 'realname') {
135 $expr = "profiles.realname";
137 $expr = "profiles.login_name";
139 if ($matchtype eq 'regexp') {
140 $query .= $dbh->sql_regexp($expr, '?');
141 $matchstr = '.' unless $matchstr;
142 } elsif ($matchtype eq 'notregexp') {
143 $query .= $dbh->sql_not_regexp($expr, '?');
144 $matchstr = '.' unless $matchstr;
145 } elsif ($matchtype eq 'exact') {
146 $query .= $expr . ' = ?';
147 $matchstr = '.' unless $matchstr;
148 } else { # substr or unknown
149 $query .= $dbh->sql_istrcmp($expr, '?', 'LIKE');
150 $matchstr = "%$matchstr%";
152 $nextCondition = 'AND';
153 # We can trick_taint because we use the value in a SELECT only,
154 # using a placeholder.
155 trick_taint
($matchstr);
156 push(@bindValues, $matchstr);
159 # Handle selection by group.
160 if ($grouprestrict eq '1') {
161 my $grouplist = join(',',
162 @
{Bugzilla
::User
->flatten_group_membership($group->id)});
163 $query .= " $nextCondition ugm.group_id IN($grouplist) ";
165 $query .= ' ORDER BY profiles.login_name';
167 $vars->{'users'} = $dbh->selectall_arrayref($query,
173 if ($matchtype && $matchtype eq 'exact' && scalar(@
{$vars->{'users'}}) == 1) {
174 my $match_user_id = $vars->{'users'}[0]->{'userid'};
175 my $match_user = check_user
($match_user_id);
176 edit_processing
($match_user);
178 $template->process('admin/users/list.html.tmpl', $vars)
179 || ThrowTemplateError
($template->error());
182 ###########################################################################
183 } elsif ($action eq 'add') {
184 $editusers || ThrowUserError
("auth_failure", {group
=> "editusers",
188 $vars->{'token'} = issue_session_token
('add_user');
190 $template->process('admin/users/create.html.tmpl', $vars)
191 || ThrowTemplateError
($template->error());
193 ###########################################################################
194 } elsif ($action eq 'new') {
195 $editusers || ThrowUserError
("auth_failure", {group
=> "editusers",
199 check_token_data
($token, 'add_user');
201 my $new_user = Bugzilla
::User
->create({
202 login_name
=> scalar $cgi->param('login'),
203 cryptpassword
=> scalar $cgi->param('password'),
204 realname
=> scalar $cgi->param('name'),
205 disabledtext
=> scalar $cgi->param('disabledtext'),
206 disable_mail
=> scalar $cgi->param('disable_mail')});
208 userDataToVars
($new_user->id);
210 delete_token
($token);
212 # We already display the updated page. We have to recreate a token now.
213 $vars->{'token'} = issue_session_token
('edit_user');
214 $vars->{'message'} = 'account_created';
215 $template->process('admin/users/edit.html.tmpl', $vars)
216 || ThrowTemplateError
($template->error());
218 ###########################################################################
219 } elsif ($action eq 'edit') {
220 my $otherUser = check_user
($otherUserID, $otherUserLogin);
221 edit_processing
($otherUser);
223 ###########################################################################
224 } elsif ($action eq 'update') {
225 check_token_data
($token, 'edit_user');
226 my $otherUser = check_user
($otherUserID, $otherUserLogin);
227 $otherUserID = $otherUser->id;
229 # Lock tables during the check+update session.
230 $dbh->bz_start_transaction();
232 $editusers || $user->can_see_user($otherUser)
233 || ThrowUserError
('auth_failure', {reason
=> "not_visible",
237 $vars->{'loginold'} = $otherUser->login;
239 # Update profiles table entry; silently skip doing this if the user
243 $otherUser->set_login($cgi->param('login'));
244 $otherUser->set_name($cgi->param('name'));
245 $otherUser->set_password($cgi->param('password'))
246 if $cgi->param('password');
247 $otherUser->set_disabledtext($cgi->param('disabledtext'));
248 $otherUser->set_disable_mail($cgi->param('disable_mail'));
249 %changes = %{$otherUser->update()};
252 # Update group settings.
253 my $sth_add_mapping = $dbh->prepare(
254 qq{INSERT INTO user_group_map
(
255 user_id
, group_id
, isbless
, grant_type
260 my $sth_remove_mapping = $dbh->prepare(
261 qq{DELETE FROM user_group_map
269 my @groupsRemovedFrom;
270 my @groupsGrantedRightsToBless;
271 my @groupsDeniedRightsToBless;
273 # Regard only groups the user is allowed to bless and skip all others
275 # XXX: checking for existence of each user_group_map entry
276 # would allow to display a friendlier error message on page reloads.
277 userDataToVars
($otherUserID);
278 my $permissions = $vars->{'permissions'};
279 foreach (@
{$user->bless_groups()}) {
281 my $name = $$_{'name'};
283 # Change memberships.
284 my $groupid = $cgi->param("group_$id") || 0;
285 if ($groupid != $permissions->{$id}->{'directmember'}) {
287 $sth_remove_mapping->execute(
288 $otherUserID, $id, 0, GRANT_DIRECT
);
289 push(@groupsRemovedFrom, $name);
291 $sth_add_mapping->execute(
292 $otherUserID, $id, 0, GRANT_DIRECT
);
293 push(@groupsAddedTo, $name);
297 # Only members of the editusers group may change bless grants.
298 # Skip silently if this is not the case.
300 my $groupid = $cgi->param("bless_$id") || 0;
301 if ($groupid != $permissions->{$id}->{'directbless'}) {
303 $sth_remove_mapping->execute(
304 $otherUserID, $id, 1, GRANT_DIRECT
);
305 push(@groupsDeniedRightsToBless, $name);
307 $sth_add_mapping->execute(
308 $otherUserID, $id, 1, GRANT_DIRECT
);
309 push(@groupsGrantedRightsToBless, $name);
314 if (@groupsAddedTo || @groupsRemovedFrom) {
315 $dbh->do(qq{INSERT INTO profiles_activity
(
317 profiles_when
, fieldid
,
324 ($otherUserID, $userid,
325 get_field_id
('bug_group'),
326 join(', ', @groupsRemovedFrom), join(', ', @groupsAddedTo)));
328 # XXX: should create profiles_activity entries for blesser changes.
330 $dbh->bz_commit_transaction();
332 # XXX: userDataToVars may be off when editing ourselves.
333 userDataToVars
($otherUserID);
334 delete_token
($token);
336 $vars->{'message'} = 'account_updated';
337 $vars->{'changed_fields'} = [keys %changes];
338 $vars->{'groups_added_to'} = \
@groupsAddedTo;
339 $vars->{'groups_removed_from'} = \
@groupsRemovedFrom;
340 $vars->{'groups_granted_rights_to_bless'} = \
@groupsGrantedRightsToBless;
341 $vars->{'groups_denied_rights_to_bless'} = \
@groupsDeniedRightsToBless;
342 # We already display the updated page. We have to recreate a token now.
343 $vars->{'token'} = issue_session_token
('edit_user');
345 $template->process('admin/users/edit.html.tmpl', $vars)
346 || ThrowTemplateError
($template->error());
348 ###########################################################################
349 } elsif ($action eq 'del') {
350 my $otherUser = check_user
($otherUserID, $otherUserLogin);
351 $otherUserID = $otherUser->id;
353 Bugzilla
->params->{'allowuserdeletion'}
354 || ThrowUserError
('users_deletion_disabled');
355 $editusers || ThrowUserError
('auth_failure', {group
=> "editusers",
358 $vars->{'otheruser'} = $otherUser;
360 # Find other cross references.
361 $vars->{'attachments'} = $dbh->selectrow_array(
362 'SELECT COUNT(*) FROM attachments WHERE submitter_id = ?',
363 undef, $otherUserID);
364 $vars->{'assignee_or_qa'} = $dbh->selectrow_array(
367 WHERE assigned_to
= ? OR qa_contact
= ?
},
368 undef, ($otherUserID, $otherUserID));
369 $vars->{'reporter'} = $dbh->selectrow_array(
370 'SELECT COUNT(*) FROM bugs WHERE reporter = ?',
371 undef, $otherUserID);
372 $vars->{'cc'} = $dbh->selectrow_array(
373 'SELECT COUNT(*) FROM cc WHERE who = ?',
374 undef, $otherUserID);
375 $vars->{'bugs_activity'} = $dbh->selectrow_array(
376 'SELECT COUNT(*) FROM bugs_activity WHERE who = ?',
377 undef, $otherUserID);
378 $vars->{'component_cc'} = $dbh->selectrow_array(
379 'SELECT COUNT(*) FROM component_cc WHERE user_id = ?',
380 undef, $otherUserID);
381 $vars->{'email_setting'} = $dbh->selectrow_array(
382 'SELECT COUNT(*) FROM email_setting WHERE user_id = ?',
383 undef, $otherUserID);
384 $vars->{'flags'}{'requestee'} = $dbh->selectrow_array(
385 'SELECT COUNT(*) FROM flags WHERE requestee_id = ?',
386 undef, $otherUserID);
387 $vars->{'flags'}{'setter'} = $dbh->selectrow_array(
388 'SELECT COUNT(*) FROM flags WHERE setter_id = ?',
389 undef, $otherUserID);
390 $vars->{'longdescs'} = $dbh->selectrow_array(
391 'SELECT COUNT(*) FROM longdescs WHERE who = ?',
392 undef, $otherUserID);
393 my $namedquery_ids = $dbh->selectcol_arrayref(
394 'SELECT id FROM namedqueries WHERE userid = ?',
395 undef, $otherUserID);
396 $vars->{'namedqueries'} = scalar(@
$namedquery_ids);
397 if (scalar(@
$namedquery_ids)) {
398 $vars->{'namedquery_group_map'} = $dbh->selectrow_array(
399 'SELECT COUNT(*) FROM namedquery_group_map WHERE namedquery_id IN' .
400 ' (' . join(', ', @
$namedquery_ids) . ')');
403 $vars->{'namedquery_group_map'} = 0;
405 $vars->{'profile_setting'} = $dbh->selectrow_array(
406 'SELECT COUNT(*) FROM profile_setting WHERE user_id = ?',
407 undef, $otherUserID);
408 $vars->{'profiles_activity'} = $dbh->selectrow_array(
409 'SELECT COUNT(*) FROM profiles_activity WHERE who = ? AND userid != ?',
410 undef, ($otherUserID, $otherUserID));
411 $vars->{'quips'} = $dbh->selectrow_array(
412 'SELECT COUNT(*) FROM quips WHERE userid = ?',
413 undef, $otherUserID);
414 $vars->{'series'} = $dbh->selectrow_array(
415 'SELECT COUNT(*) FROM series WHERE creator = ?',
416 undef, $otherUserID);
417 $vars->{'votes'} = $dbh->selectrow_array(
418 'SELECT COUNT(*) FROM votes WHERE who = ?',
419 undef, $otherUserID);
420 $vars->{'watch'}{'watched'} = $dbh->selectrow_array(
421 'SELECT COUNT(*) FROM watch WHERE watched = ?',
422 undef, $otherUserID);
423 $vars->{'watch'}{'watcher'} = $dbh->selectrow_array(
424 'SELECT COUNT(*) FROM watch WHERE watcher = ?',
425 undef, $otherUserID);
426 $vars->{'whine_events'} = $dbh->selectrow_array(
427 'SELECT COUNT(*) FROM whine_events WHERE owner_userid = ?',
428 undef, $otherUserID);
429 $vars->{'whine_schedules'} = $dbh->selectrow_array(
430 qq{SELECT COUNT
(distinct eventid
)
435 undef, ($otherUserID, MAILTO_USER
));
436 $vars->{'token'} = issue_session_token
('delete_user');
438 $template->process('admin/users/confirm-delete.html.tmpl', $vars)
439 || ThrowTemplateError
($template->error());
441 ###########################################################################
442 } elsif ($action eq 'delete') {
443 check_token_data
($token, 'delete_user');
444 my $otherUser = check_user
($otherUserID, $otherUserLogin);
445 $otherUserID = $otherUser->id;
447 # Cache for user accounts.
448 my %usercache = (0 => new Bugzilla
::User
());
451 # Lock tables during the check+removal session.
452 # XXX: if there was some change on these tables after the deletion
453 # confirmation checks, we may do something here we haven't warned
455 $dbh->bz_start_transaction();
457 Bugzilla
->params->{'allowuserdeletion'}
458 || ThrowUserError
('users_deletion_disabled');
459 $editusers || ThrowUserError
('auth_failure',
460 {group
=> "editusers",
463 @
{$otherUser->product_responsibilities()}
464 && ThrowUserError
('user_has_responsibility');
466 Bugzilla
->logout_user($otherUser);
468 # Get the named query list so we can delete namedquery_group_map entries.
469 my $namedqueries_as_string = join(', ', @
{$dbh->selectcol_arrayref(
470 'SELECT id FROM namedqueries WHERE userid = ?', undef, $otherUserID)});
472 # Get the timestamp for LogActivityEntry.
473 my $timestamp = $dbh->selectrow_array('SELECT NOW()');
475 # When we update a bug_activity entry, we update the bug timestamp, too.
476 my $sth_set_bug_timestamp =
477 $dbh->prepare('UPDATE bugs SET delta_ts = ? WHERE bug_id = ?');
479 # Reference removals which need LogActivityEntry.
480 my $statement_flagupdate = 'UPDATE flags set requestee_id = NULL
483 AND requestee_id = ?';
484 my $sth_flagupdate_attachment =
485 $dbh->prepare(sprintf($statement_flagupdate, '= ?'));
486 my $sth_flagupdate_bug =
487 $dbh->prepare(sprintf($statement_flagupdate, 'IS NULL'));
489 my $buglist = $dbh->selectall_arrayref('SELECT DISTINCT bug_id, attach_id
491 WHERE requestee_id = ?',
492 undef, $otherUserID);
494 foreach (@
$buglist) {
495 my ($bug_id, $attach_id) = @
$_;
496 my @old_summaries = Bugzilla
::Flag
->snapshot($bug_id, $attach_id);
498 $sth_flagupdate_attachment->execute($bug_id, $attach_id, $otherUserID);
501 $sth_flagupdate_bug->execute($bug_id, $otherUserID);
503 my @new_summaries = Bugzilla
::Flag
->snapshot($bug_id, $attach_id);
504 # Let update_activity do all the dirty work, including setting
506 Bugzilla
::Flag
::update_activity
($bug_id, $attach_id, $timestamp,
507 \
@old_summaries, \
@new_summaries);
508 $updatedbugs{$bug_id} = 1;
511 # Simple deletions in referred tables.
512 $dbh->do('DELETE FROM email_setting WHERE user_id = ?', undef,
514 $dbh->do('DELETE FROM logincookies WHERE userid = ?', undef, $otherUserID);
515 $dbh->do('DELETE FROM namedqueries WHERE userid = ?', undef, $otherUserID);
516 $dbh->do('DELETE FROM namedqueries_link_in_footer WHERE user_id = ?', undef,
518 if ($namedqueries_as_string) {
519 $dbh->do('DELETE FROM namedquery_group_map WHERE namedquery_id IN ' .
520 "($namedqueries_as_string)");
522 $dbh->do('DELETE FROM profile_setting WHERE user_id = ?', undef,
524 $dbh->do('DELETE FROM profiles_activity WHERE userid = ? OR who = ?', undef,
525 ($otherUserID, $otherUserID));
526 $dbh->do('UPDATE quips SET userid = NULL where userid = ?', undef, $otherUserID);
527 $dbh->do('DELETE FROM tokens WHERE userid = ?', undef, $otherUserID);
528 $dbh->do('DELETE FROM user_group_map WHERE user_id = ?', undef,
530 $dbh->do('DELETE FROM votes WHERE who = ?', undef, $otherUserID);
531 $dbh->do('DELETE FROM watch WHERE watcher = ? OR watched = ?', undef,
532 ($otherUserID, $otherUserID));
534 # Deletions in referred tables which need LogActivityEntry.
535 $buglist = $dbh->selectcol_arrayref('SELECT bug_id FROM cc
537 undef, $otherUserID);
538 $dbh->do('DELETE FROM cc WHERE who = ?', undef, $otherUserID);
539 foreach my $bug_id (@
$buglist) {
540 LogActivityEntry
($bug_id, 'cc', $otherUser->login, '', $userid,
542 $sth_set_bug_timestamp->execute($timestamp, $bug_id);
543 $updatedbugs{$bug_id} = 1;
546 # Even more complex deletions in referred tables.
550 my $sth_seriesid = $dbh->prepare(
551 'SELECT series_id FROM series WHERE creator = ?');
552 my $sth_deleteSeries = $dbh->prepare(
553 'DELETE FROM series WHERE series_id = ?');
554 my $sth_deleteSeriesData = $dbh->prepare(
555 'DELETE FROM series_data WHERE series_id = ?');
557 $sth_seriesid->execute($otherUserID);
558 while ($id = $sth_seriesid->fetchrow_array()) {
559 $sth_deleteSeriesData->execute($id);
560 $sth_deleteSeries->execute($id);
564 my $sth_whineidFromEvents = $dbh->prepare(
565 'SELECT id FROM whine_events WHERE owner_userid = ?');
566 my $sth_deleteWhineEvent = $dbh->prepare(
567 'DELETE FROM whine_events WHERE id = ?');
568 my $sth_deleteWhineQuery = $dbh->prepare(
569 'DELETE FROM whine_queries WHERE eventid = ?');
570 my $sth_deleteWhineSchedule = $dbh->prepare(
571 'DELETE FROM whine_schedules WHERE eventid = ?');
573 $dbh->do('DELETE FROM whine_schedules WHERE mailto = ? AND mailto_type = ?',
574 undef, ($otherUserID, MAILTO_USER
));
576 $sth_whineidFromEvents->execute($otherUserID);
577 while ($id = $sth_whineidFromEvents->fetchrow_array()) {
578 $sth_deleteWhineQuery->execute($id);
579 $sth_deleteWhineSchedule->execute($id);
580 $sth_deleteWhineEvent->execute($id);
584 # 3.1) fall back to the default assignee
585 $buglist = $dbh->selectall_arrayref(
586 'SELECT bug_id, initialowner
588 INNER JOIN components ON components.id = bugs.component_id
589 WHERE assigned_to = ?', undef, $otherUserID);
591 my $sth_updateAssignee = $dbh->prepare(
592 'UPDATE bugs SET assigned_to = ?, delta_ts = ? WHERE bug_id = ?');
594 foreach my $bug (@
$buglist) {
595 my ($bug_id, $default_assignee_id) = @
$bug;
596 $sth_updateAssignee->execute($default_assignee_id,
597 $timestamp, $bug_id);
598 $updatedbugs{$bug_id} = 1;
599 $default_assignee_id ||= 0;
600 $usercache{$default_assignee_id} ||=
601 new Bugzilla
::User
($default_assignee_id);
602 LogActivityEntry
($bug_id, 'assigned_to', $otherUser->login,
603 $usercache{$default_assignee_id}->login,
604 $userid, $timestamp);
607 # 3.2) fall back to the default QA contact
608 $buglist = $dbh->selectall_arrayref(
609 'SELECT bug_id, initialqacontact
611 INNER JOIN components ON components.id = bugs.component_id
612 WHERE qa_contact = ?', undef, $otherUserID);
614 my $sth_updateQAcontact = $dbh->prepare(
615 'UPDATE bugs SET qa_contact = ?, delta_ts = ? WHERE bug_id = ?');
617 foreach my $bug (@
$buglist) {
618 my ($bug_id, $default_qa_contact_id) = @
$bug;
619 $sth_updateQAcontact->execute($default_qa_contact_id,
620 $timestamp, $bug_id);
621 $updatedbugs{$bug_id} = 1;
622 $default_qa_contact_id ||= 0;
623 $usercache{$default_qa_contact_id} ||=
624 new Bugzilla
::User
($default_qa_contact_id);
625 LogActivityEntry
($bug_id, 'qa_contact', $otherUser->login,
626 $usercache{$default_qa_contact_id}->login,
627 $userid, $timestamp);
630 # Finally, remove the user account itself.
631 $dbh->do('DELETE FROM profiles WHERE userid = ?', undef, $otherUserID);
633 $dbh->bz_commit_transaction();
634 delete_token
($token);
636 $vars->{'message'} = 'account_deleted';
637 $vars->{'otheruser'}{'login'} = $otherUser->login;
638 $vars->{'restrictablegroups'} = $user->bless_groups();
639 $template->process('admin/users/search.html.tmpl', $vars)
640 || ThrowTemplateError
($template->error());
642 # Send mail about what we've done to bugs.
643 # The deleted user is not notified of the changes.
644 foreach (keys(%updatedbugs)) {
645 Bugzilla
::BugMail
::Send
($_, {'changer' => $user->login} );
648 ###########################################################################
649 } elsif ($action eq 'activity') {
650 my $otherUser = check_user
($otherUserID, $otherUserLogin);
652 $vars->{'profile_changes'} = $dbh->selectall_arrayref(
653 "SELECT profiles.login_name AS who, " .
654 $dbh->sql_date_format('profiles_activity.profiles_when') . " AS activity_when,
655 fielddefs.description AS what,
656 profiles_activity.oldvalue AS removed,
657 profiles_activity.newvalue AS added
658 FROM profiles_activity
659 INNER JOIN profiles ON profiles_activity.who = profiles.userid
660 INNER JOIN fielddefs ON fielddefs.id = profiles_activity.fieldid
661 WHERE profiles_activity.userid = ?
662 ORDER BY profiles_activity.profiles_when",
666 $vars->{'otheruser'} = $otherUser;
668 $template->process("account/profile-activity.html.tmpl", $vars)
669 || ThrowTemplateError
($template->error());
671 ###########################################################################
673 $vars->{'action'} = $action;
674 ThrowCodeError
('action_unrecognized', $vars);
679 ###########################################################################
681 ###########################################################################
683 # Try to build a user object using its ID, else its login name, and throw
684 # an error if the user does not exist.
686 my ($otherUserID, $otherUserLogin) = @_;
692 $otherUser = Bugzilla
::User
->new($otherUserID);
693 $vars->{'user_id'} = $otherUserID;
695 elsif ($otherUserLogin) {
696 $otherUser = new Bugzilla
::User
({ name
=> $otherUserLogin });
697 $vars->{'user_login'} = $otherUserLogin;
699 ($otherUser && $otherUser->id) || ThrowCodeError
('invalid_user', $vars);
704 # Copy incoming list selection values from CGI params to template variables.
705 sub mirrorListSelectionValues
{
706 my $cgi = Bugzilla
->cgi;
707 if (defined($cgi->param('matchtype'))) {
708 foreach ('matchvalue', 'matchstr', 'matchtype', 'grouprestrict', 'groupid') {
709 $vars->{'listselectionvalues'}{$_} = $cgi->param($_);
714 # Retrieve user data for the user editing form. User creation and user
715 # editing code rely on this to call derive_groups().
717 my $otheruserid = shift;
718 my $otheruser = new Bugzilla
::User
($otheruserid);
720 my $user = Bugzilla
->user;
721 my $dbh = Bugzilla
->dbh;
723 my $grouplist = $otheruser->groups_as_string;
725 $vars->{'otheruser'} = $otheruser;
726 $vars->{'groups'} = $user->bless_groups();
728 $vars->{'permissions'} = $dbh->selectall_hashref(
730 COUNT
(directmember
.group_id
) AS directmember
,
731 COUNT
(regexpmember
.group_id
) AS regexpmember
,
732 (CASE WHEN
(groups
.id IN
($grouplist)
733 AND COUNT
(directmember
.group_id
) = 0
734 AND COUNT
(regexpmember
.group_id
) = 0
737 COUNT
(directbless
.group_id
) AS directbless
739 LEFT JOIN user_group_map AS directmember
740 ON directmember
.group_id
= id
741 AND directmember
.user_id
= ?
742 AND directmember
.isbless
= 0
743 AND directmember
.grant_type
= ?
744 LEFT JOIN user_group_map AS regexpmember
745 ON regexpmember
.group_id
= id
746 AND regexpmember
.user_id
= ?
747 AND regexpmember
.isbless
= 0
748 AND regexpmember
.grant_type
= ?
749 LEFT JOIN user_group_map AS directbless
750 ON directbless
.group_id
= id
751 AND directbless
.user_id
= ?
752 AND directbless
.isbless
= 1
753 AND directbless
.grant_type
= ?
754 } . $dbh->sql_group_by('id'),
756 ($otheruserid, GRANT_DIRECT
,
757 $otheruserid, GRANT_REGEXP
,
758 $otheruserid, GRANT_DIRECT
));
760 # Find indirect bless permission.
761 $query = qq{SELECT groups
.id
762 FROM groups
, group_group_map AS ggm
763 WHERE groups
.id
= ggm
.grantor_id
764 AND ggm
.member_id IN
($grouplist)
765 AND ggm
.grant_type
= ?
766 } . $dbh->sql_group_by('id');
767 foreach (@
{$dbh->selectall_arrayref($query, undef,
769 # Merge indirect bless permissions into permission variable.
770 $vars->{'permissions'}{${$_}[0]}{'indirectbless'} = 1;
774 sub edit_processing
{
775 my $otherUser = shift;
776 my $user = Bugzilla
->user;
777 my $template = Bugzilla
->template;
779 $user->in_group('editusers') || $user->can_see_user($otherUser)
780 || ThrowUserError
('auth_failure', {reason
=> "not_visible",
784 userDataToVars
($otherUser->id);
785 $vars->{'token'} = issue_session_token
('edit_user');
787 $template->process('admin/users/edit.html.tmpl', $vars)
788 || ThrowTemplateError
($template->error());