aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'Bugzilla/WebService/User.pm')
-rw-r--r--Bugzilla/WebService/User.pm595
1 files changed, 296 insertions, 299 deletions
diff --git a/Bugzilla/WebService/User.pm b/Bugzilla/WebService/User.pm
index 0ae76d70f..3fcc929ce 100644
--- a/Bugzilla/WebService/User.pm
+++ b/Bugzilla/WebService/User.pm
@@ -18,40 +18,35 @@ use Bugzilla::Error;
use Bugzilla::Group;
use Bugzilla::User;
use Bugzilla::Util qw(trim detaint_natural);
-use Bugzilla::WebService::Util qw(filter filter_wants validate translate params_to_objects);
+use Bugzilla::WebService::Util
+ qw(filter filter_wants validate translate params_to_objects);
use List::Util qw(first min);
# Don't need auth to login
-use constant LOGIN_EXEMPT => {
- login => 1,
- offer_account_by_email => 1,
-};
+use constant LOGIN_EXEMPT => {login => 1, offer_account_by_email => 1,};
use constant READ_ONLY => qw(
- get
+ get
);
use constant PUBLIC_METHODS => qw(
- create
- get
- login
- logout
- offer_account_by_email
- update
- valid_login
+ create
+ get
+ login
+ logout
+ offer_account_by_email
+ update
+ valid_login
);
-use constant MAPPED_FIELDS => {
- email => 'login',
- full_name => 'name',
- login_denied_text => 'disabledtext',
-};
+use constant MAPPED_FIELDS =>
+ {email => 'login', full_name => 'name', login_denied_text => 'disabledtext',};
use constant MAPPED_RETURNS => {
- login_name => 'email',
- realname => 'full_name',
- disabledtext => 'login_denied_text',
+ login_name => 'email',
+ realname => 'full_name',
+ disabledtext => 'login_denied_text',
};
##############
@@ -59,38 +54,38 @@ use constant MAPPED_RETURNS => {
##############
sub login {
- my ($self, $params) = @_;
+ my ($self, $params) = @_;
- # Check to see if we are already logged in
- my $user = Bugzilla->user;
- if ($user->id) {
- return $self->_login_to_hash($user);
- }
+ # Check to see if we are already logged in
+ my $user = Bugzilla->user;
+ if ($user->id) {
+ return $self->_login_to_hash($user);
+ }
- # Username and password params are required
- foreach my $param ("login", "password") {
- (defined $params->{$param} || defined $params->{'Bugzilla_' . $param})
- || ThrowCodeError('param_required', { param => $param });
- }
+ # Username and password params are required
+ foreach my $param ("login", "password") {
+ (defined $params->{$param} || defined $params->{'Bugzilla_' . $param})
+ || ThrowCodeError('param_required', {param => $param});
+ }
- $user = Bugzilla->login();
- return $self->_login_to_hash($user);
+ $user = Bugzilla->login();
+ return $self->_login_to_hash($user);
}
sub logout {
- my $self = shift;
- Bugzilla->logout;
+ my $self = shift;
+ Bugzilla->logout;
}
sub valid_login {
- my ($self, $params) = @_;
- defined $params->{login}
- || ThrowCodeError('param_required', { param => 'login' });
- Bugzilla->login();
- if (Bugzilla->user->id && Bugzilla->user->login eq $params->{login}) {
- return $self->type('boolean', 1);
- }
- return $self->type('boolean', 0);
+ my ($self, $params) = @_;
+ defined $params->{login}
+ || ThrowCodeError('param_required', {param => 'login'});
+ Bugzilla->login();
+ if (Bugzilla->user->id && Bugzilla->user->login eq $params->{login}) {
+ return $self->type('boolean', 1);
+ }
+ return $self->type('boolean', 0);
}
#################
@@ -98,168 +93,169 @@ sub valid_login {
#################
sub offer_account_by_email {
- my $self = shift;
- my ($params) = @_;
- my $email = trim($params->{email})
- || ThrowCodeError('param_required', { param => 'email' });
-
- Bugzilla->user->check_account_creation_enabled;
- Bugzilla->user->check_and_send_account_creation_confirmation($email);
- return undef;
+ my $self = shift;
+ my ($params) = @_;
+ my $email = trim($params->{email})
+ || ThrowCodeError('param_required', {param => 'email'});
+
+ Bugzilla->user->check_account_creation_enabled;
+ Bugzilla->user->check_and_send_account_creation_confirmation($email);
+ return undef;
}
sub create {
- my $self = shift;
- my ($params) = @_;
-
- Bugzilla->user->in_group('editusers')
- || ThrowUserError("auth_failure", { group => "editusers",
- action => "add",
- object => "users"});
-
- my $email = trim($params->{email})
- || ThrowCodeError('param_required', { param => 'email' });
- my $realname = trim($params->{full_name});
- my $password = trim($params->{password}) || '*';
-
- my $user = Bugzilla::User->create({
- login_name => $email,
- realname => $realname,
- cryptpassword => $password
- });
-
- return { id => $self->type('int', $user->id) };
+ my $self = shift;
+ my ($params) = @_;
+
+ Bugzilla->user->in_group('editusers')
+ || ThrowUserError("auth_failure",
+ {group => "editusers", action => "add", object => "users"});
+
+ my $email = trim($params->{email})
+ || ThrowCodeError('param_required', {param => 'email'});
+ my $realname = trim($params->{full_name});
+ my $password = trim($params->{password}) || '*';
+
+ my $user = Bugzilla::User->create(
+ {login_name => $email, realname => $realname, cryptpassword => $password});
+
+ return {id => $self->type('int', $user->id)};
}
-# function to return user information by passing either user ids or
+# function to return user information by passing either user ids or
# login names or both together:
-# $call = $rpc->call( 'User.get', { ids => [1,2,3],
+# $call = $rpc->call( 'User.get', { ids => [1,2,3],
# names => ['testusera@redhat.com', 'testuserb@redhat.com'] });
sub get {
- my ($self, $params) = validate(@_, 'names', 'ids', 'match', 'group_ids', 'groups');
-
- Bugzilla->switch_to_shadow_db();
-
- defined($params->{names}) || defined($params->{ids})
- || defined($params->{match})
- || ThrowCodeError('params_required',
- { function => 'User.get', params => ['ids', 'names', 'match'] });
-
- my @user_objects;
- @user_objects = map { Bugzilla::User->check($_) } @{ $params->{names} }
- if $params->{names};
-
- # start filtering to remove duplicate user ids
- my %unique_users = map { $_->id => $_ } @user_objects;
- @user_objects = values %unique_users;
-
- my @users;
-
- # If the user is not logged in: Return an error if they passed any user ids.
- # Otherwise, return a limited amount of information based on login names.
- if (!Bugzilla->user->id){
- if ($params->{ids}){
- ThrowUserError("user_access_by_id_denied");
- }
- if ($params->{match}) {
- ThrowUserError('user_access_by_match_denied');
- }
- my $in_group = $self->_filter_users_by_group(
- \@user_objects, $params);
- @users = map { filter $params, {
- id => $self->type('int', $_->id),
- real_name => $self->type('string', $_->name),
- name => $self->type('email', $_->login),
- } } @$in_group;
-
- return { users => \@users };
- }
+ my ($self, $params)
+ = validate(@_, 'names', 'ids', 'match', 'group_ids', 'groups');
- my $obj_by_ids;
- $obj_by_ids = Bugzilla::User->new_from_list($params->{ids}) if $params->{ids};
-
- # obj_by_ids are only visible to the user if they can see
- # the otheruser, for non visible otheruser throw an error
- foreach my $obj (@$obj_by_ids) {
- if (Bugzilla->user->can_see_user($obj)){
- if (!$unique_users{$obj->id}) {
- push (@user_objects, $obj);
- $unique_users{$obj->id} = $obj;
- }
- }
- else {
- ThrowUserError('auth_failure', {reason => "not_visible",
- action => "access",
- object => "user",
- userid => $obj->id});
- }
- }
+ Bugzilla->switch_to_shadow_db();
- # User Matching
- my $limit = Bugzilla->params->{maxusermatches};
- if ($params->{limit}) {
- detaint_natural($params->{limit})
- || ThrowCodeError('param_must_be_numeric',
- { function => 'Bugzilla::WebService::User::match',
- param => 'limit' });
- $limit = $limit ? min($params->{limit}, $limit) : $params->{limit};
- }
+ defined($params->{names})
+ || defined($params->{ids})
+ || defined($params->{match})
+ || ThrowCodeError('params_required',
+ {function => 'User.get', params => ['ids', 'names', 'match']});
- my $exclude_disabled = $params->{'include_disabled'} ? 0 : 1;
- foreach my $match_string (@{ $params->{'match'} || [] }) {
- my $matched = Bugzilla::User::match($match_string, $limit, $exclude_disabled);
- foreach my $user (@$matched) {
- if (!$unique_users{$user->id}) {
- push(@user_objects, $user);
- $unique_users{$user->id} = $user;
- }
- }
- }
+ my @user_objects;
+ @user_objects = map { Bugzilla::User->check($_) } @{$params->{names}}
+ if $params->{names};
+
+ # start filtering to remove duplicate user ids
+ my %unique_users = map { $_->id => $_ } @user_objects;
+ @user_objects = values %unique_users;
+ my @users;
+
+ # If the user is not logged in: Return an error if they passed any user ids.
+ # Otherwise, return a limited amount of information based on login names.
+ if (!Bugzilla->user->id) {
+ if ($params->{ids}) {
+ ThrowUserError("user_access_by_id_denied");
+ }
+ if ($params->{match}) {
+ ThrowUserError('user_access_by_match_denied');
+ }
my $in_group = $self->_filter_users_by_group(\@user_objects, $params);
- foreach my $user (@$in_group) {
- my $user_info = filter $params, {
- id => $self->type('int', $user->id),
- real_name => $self->type('string', $user->name),
- name => $self->type('email', $user->login),
- email => $self->type('email', $user->email),
- can_login => $self->type('boolean', $user->is_enabled ? 1 : 0),
- };
-
- if (Bugzilla->user->in_group('editusers')) {
- $user_info->{email_enabled} = $self->type('boolean', $user->email_enabled);
- $user_info->{login_denied_text} = $self->type('string', $user->disabledtext);
+ @users = map {
+ filter $params,
+ {
+ id => $self->type('int', $_->id),
+ real_name => $self->type('string', $_->name),
+ name => $self->type('email', $_->login),
}
-
- if (Bugzilla->user->id == $user->id) {
- if (filter_wants($params, 'saved_searches')) {
- $user_info->{saved_searches} = [
- map { $self->_query_to_hash($_) } @{ $user->queries }
- ];
- }
- if (filter_wants($params, 'saved_reports')) {
- $user_info->{saved_reports} = [
- map { $self->_report_to_hash($_) } @{ $user->reports }
- ];
- }
+ } @$in_group;
+
+ return {users => \@users};
+ }
+
+ my $obj_by_ids;
+ $obj_by_ids = Bugzilla::User->new_from_list($params->{ids}) if $params->{ids};
+
+ # obj_by_ids are only visible to the user if they can see
+ # the otheruser, for non visible otheruser throw an error
+ foreach my $obj (@$obj_by_ids) {
+ if (Bugzilla->user->can_see_user($obj)) {
+ if (!$unique_users{$obj->id}) {
+ push(@user_objects, $obj);
+ $unique_users{$obj->id} = $obj;
+ }
+ }
+ else {
+ ThrowUserError(
+ 'auth_failure',
+ {
+ reason => "not_visible",
+ action => "access",
+ object => "user",
+ userid => $obj->id
}
+ );
+ }
+ }
+
+ # User Matching
+ my $limit = Bugzilla->params->{maxusermatches};
+ if ($params->{limit}) {
+ detaint_natural($params->{limit})
+ || ThrowCodeError('param_must_be_numeric',
+ {function => 'Bugzilla::WebService::User::match', param => 'limit'});
+ $limit = $limit ? min($params->{limit}, $limit) : $params->{limit};
+ }
+
+ my $exclude_disabled = $params->{'include_disabled'} ? 0 : 1;
+ foreach my $match_string (@{$params->{'match'} || []}) {
+ my $matched = Bugzilla::User::match($match_string, $limit, $exclude_disabled);
+ foreach my $user (@$matched) {
+ if (!$unique_users{$user->id}) {
+ push(@user_objects, $user);
+ $unique_users{$user->id} = $user;
+ }
+ }
+ }
+
+ my $in_group = $self->_filter_users_by_group(\@user_objects, $params);
+ foreach my $user (@$in_group) {
+ my $user_info = filter $params,
+ {
+ id => $self->type('int', $user->id),
+ real_name => $self->type('string', $user->name),
+ name => $self->type('email', $user->login),
+ email => $self->type('email', $user->email),
+ can_login => $self->type('boolean', $user->is_enabled ? 1 : 0),
+ };
+
+ if (Bugzilla->user->in_group('editusers')) {
+ $user_info->{email_enabled} = $self->type('boolean', $user->email_enabled);
+ $user_info->{login_denied_text} = $self->type('string', $user->disabledtext);
+ }
- if (filter_wants($params, 'groups')) {
- if (Bugzilla->user->id == $user->id || Bugzilla->user->in_group('editusers')) {
- $user_info->{groups} = [
- map { $self->_group_to_hash($_) } @{ $user->groups }
- ];
- }
- else {
- $user_info->{groups} = $self->_filter_bless_groups($user->groups);
- }
- }
+ if (Bugzilla->user->id == $user->id) {
+ if (filter_wants($params, 'saved_searches')) {
+ $user_info->{saved_searches}
+ = [map { $self->_query_to_hash($_) } @{$user->queries}];
+ }
+ if (filter_wants($params, 'saved_reports')) {
+ $user_info->{saved_reports}
+ = [map { $self->_report_to_hash($_) } @{$user->reports}];
+ }
+ }
- push(@users, $user_info);
+ if (filter_wants($params, 'groups')) {
+ if (Bugzilla->user->id == $user->id || Bugzilla->user->in_group('editusers')) {
+ $user_info->{groups} = [map { $self->_group_to_hash($_) } @{$user->groups}];
+ }
+ else {
+ $user_info->{groups} = $self->_filter_bless_groups($user->groups);
+ }
}
- return { users => \@users };
+ push(@users, $user_info);
+ }
+
+ return {users => \@users};
}
###############
@@ -267,156 +263,157 @@ sub get {
###############
sub update {
- my ($self, $params) = @_;
-
- my $dbh = Bugzilla->dbh;
+ my ($self, $params) = @_;
- my $user = Bugzilla->login(LOGIN_REQUIRED);
+ my $dbh = Bugzilla->dbh;
- # Reject access if there is no sense in continuing.
- $user->in_group('editusers')
- || ThrowUserError("auth_failure", {group => "editusers",
- action => "edit",
- object => "users"});
+ my $user = Bugzilla->login(LOGIN_REQUIRED);
- defined($params->{names}) || defined($params->{ids})
- || ThrowCodeError('params_required',
- { function => 'User.update', params => ['ids', 'names'] });
+ # Reject access if there is no sense in continuing.
+ $user->in_group('editusers')
+ || ThrowUserError("auth_failure",
+ {group => "editusers", action => "edit", object => "users"});
- my $user_objects = params_to_objects($params, 'Bugzilla::User');
+ defined($params->{names})
+ || defined($params->{ids})
+ || ThrowCodeError('params_required',
+ {function => 'User.update', params => ['ids', 'names']});
- my $values = translate($params, MAPPED_FIELDS);
+ my $user_objects = params_to_objects($params, 'Bugzilla::User');
- # We delete names and ids to keep only new values to set.
- delete $values->{names};
- delete $values->{ids};
+ my $values = translate($params, MAPPED_FIELDS);
- $dbh->bz_start_transaction();
- foreach my $user (@$user_objects){
- $user->set_all($values);
- }
+ # We delete names and ids to keep only new values to set.
+ delete $values->{names};
+ delete $values->{ids};
- my %changes;
- foreach my $user (@$user_objects){
- my $returned_changes = $user->update();
- $changes{$user->id} = translate($returned_changes, MAPPED_RETURNS);
- }
- $dbh->bz_commit_transaction();
-
- my @result;
- foreach my $user (@$user_objects) {
- my %hash = (
- id => $user->id,
- changes => {},
- );
-
- foreach my $field (keys %{ $changes{$user->id} }) {
- my $change = $changes{$user->id}->{$field};
- # We normalize undef to an empty string, so that the API
- # stays consistent for things that can become empty.
- $change->[0] = '' if !defined $change->[0];
- $change->[1] = '' if !defined $change->[1];
- # We also flatten arrays (used by groups and blessed_groups)
- $change->[0] = join(',', @{$change->[0]}) if ref $change->[0];
- $change->[1] = join(',', @{$change->[1]}) if ref $change->[1];
-
- $hash{changes}{$field} = {
- removed => $self->type('string', $change->[0]),
- added => $self->type('string', $change->[1])
- };
- }
+ $dbh->bz_start_transaction();
+ foreach my $user (@$user_objects) {
+ $user->set_all($values);
+ }
- push(@result, \%hash);
- }
+ my %changes;
+ foreach my $user (@$user_objects) {
+ my $returned_changes = $user->update();
+ $changes{$user->id} = translate($returned_changes, MAPPED_RETURNS);
+ }
+ $dbh->bz_commit_transaction();
- return { users => \@result };
-}
+ my @result;
+ foreach my $user (@$user_objects) {
+ my %hash = (id => $user->id, changes => {},);
-sub _filter_users_by_group {
- my ($self, $users, $params) = @_;
- my ($group_ids, $group_names) = @$params{qw(group_ids groups)};
+ foreach my $field (keys %{$changes{$user->id}}) {
+ my $change = $changes{$user->id}->{$field};
- # If no groups are specified, we return all users.
- return $users if (!$group_ids and !$group_names);
+ # We normalize undef to an empty string, so that the API
+ # stays consistent for things that can become empty.
+ $change->[0] = '' if !defined $change->[0];
+ $change->[1] = '' if !defined $change->[1];
- my $user = Bugzilla->user;
- my (@groups, %groups);
+ # We also flatten arrays (used by groups and blessed_groups)
+ $change->[0] = join(',', @{$change->[0]}) if ref $change->[0];
+ $change->[1] = join(',', @{$change->[1]}) if ref $change->[1];
- if ($group_ids) {
- @groups = map { Bugzilla::Group->check({ id => $_ }) } @$group_ids;
- $groups{$_->id} = $_ foreach @groups;
+ $hash{changes}{$field} = {
+ removed => $self->type('string', $change->[0]),
+ added => $self->type('string', $change->[1])
+ };
}
- if ($group_names) {
- foreach my $name (@$group_names) {
- my $group = Bugzilla::Group->check({ name => $name, _error => 'invalid_group_name' });
- $user->in_group($group) || ThrowUserError('invalid_group_name', { name => $name });
- $groups{$group->id} = $group;
- }
+
+ push(@result, \%hash);
+ }
+
+ return {users => \@result};
+}
+
+sub _filter_users_by_group {
+ my ($self, $users, $params) = @_;
+ my ($group_ids, $group_names) = @$params{qw(group_ids groups)};
+
+ # If no groups are specified, we return all users.
+ return $users if (!$group_ids and !$group_names);
+
+ my $user = Bugzilla->user;
+ my (@groups, %groups);
+
+ if ($group_ids) {
+ @groups = map { Bugzilla::Group->check({id => $_}) } @$group_ids;
+ $groups{$_->id} = $_ foreach @groups;
+ }
+ if ($group_names) {
+ foreach my $name (@$group_names) {
+ my $group
+ = Bugzilla::Group->check({name => $name, _error => 'invalid_group_name'});
+ $user->in_group($group)
+ || ThrowUserError('invalid_group_name', {name => $name});
+ $groups{$group->id} = $group;
}
- @groups = values %groups;
+ }
+ @groups = values %groups;
- my @in_group = grep { $self->_user_in_any_group($_, \@groups) } @$users;
- return \@in_group;
+ my @in_group = grep { $self->_user_in_any_group($_, \@groups) } @$users;
+ return \@in_group;
}
sub _user_in_any_group {
- my ($self, $user, $groups) = @_;
- foreach my $group (@$groups) {
- return 1 if $user->in_group($group);
- }
- return 0;
+ my ($self, $user, $groups) = @_;
+ foreach my $group (@$groups) {
+ return 1 if $user->in_group($group);
+ }
+ return 0;
}
sub _filter_bless_groups {
- my ($self, $groups) = @_;
- my $user = Bugzilla->user;
+ my ($self, $groups) = @_;
+ my $user = Bugzilla->user;
- my @filtered_groups;
- foreach my $group (@$groups) {
- next unless $user->can_bless($group->id);
- push(@filtered_groups, $self->_group_to_hash($group));
- }
+ my @filtered_groups;
+ foreach my $group (@$groups) {
+ next unless $user->can_bless($group->id);
+ push(@filtered_groups, $self->_group_to_hash($group));
+ }
- return \@filtered_groups;
+ return \@filtered_groups;
}
sub _group_to_hash {
- my ($self, $group) = @_;
- my $item = {
- id => $self->type('int', $group->id),
- name => $self->type('string', $group->name),
- description => $self->type('string', $group->description),
- };
- return $item;
+ my ($self, $group) = @_;
+ my $item = {
+ id => $self->type('int', $group->id),
+ name => $self->type('string', $group->name),
+ description => $self->type('string', $group->description),
+ };
+ return $item;
}
sub _query_to_hash {
- my ($self, $query) = @_;
- my $item = {
- id => $self->type('int', $query->id),
- name => $self->type('string', $query->name),
- query => $self->type('string', $query->url),
- };
- return $item;
+ my ($self, $query) = @_;
+ my $item = {
+ id => $self->type('int', $query->id),
+ name => $self->type('string', $query->name),
+ query => $self->type('string', $query->url),
+ };
+ return $item;
}
sub _report_to_hash {
- my ($self, $report) = @_;
- my $item = {
- id => $self->type('int', $report->id),
- name => $self->type('string', $report->name),
- query => $self->type('string', $report->query),
- };
- return $item;
+ my ($self, $report) = @_;
+ my $item = {
+ id => $self->type('int', $report->id),
+ name => $self->type('string', $report->name),
+ query => $self->type('string', $report->query),
+ };
+ return $item;
}
sub _login_to_hash {
- my ($self, $user) = @_;
- my $item = { id => $self->type('int', $user->id) };
- if ($user->{_login_token}) {
- $item->{'token'} = $user->id . "-" . $user->{_login_token};
- }
- return $item;
+ my ($self, $user) = @_;
+ my $item = {id => $self->type('int', $user->id)};
+ if ($user->{_login_token}) {
+ $item->{'token'} = $user->id . "-" . $user->{_login_token};
+ }
+ return $item;
}
1;