aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Bugzilla/Bug.pm3
-rw-r--r--Bugzilla/Field/Choice.pm84
-rw-r--r--Bugzilla/Object.pm13
-rw-r--r--Bugzilla/Product.pm4
-rw-r--r--Bugzilla/Status.pm12
-rwxr-xr-xeditusers.cgi6
-rwxr-xr-xeditvalues.cgi90
-rw-r--r--template/en/default/global/messages.html.tmpl25
-rw-r--r--template/en/default/global/user-error.html.tmpl5
9 files changed, 136 insertions, 106 deletions
diff --git a/Bugzilla/Bug.pm b/Bugzilla/Bug.pm
index d620f222c..d3aa1eeec 100644
--- a/Bugzilla/Bug.pm
+++ b/Bugzilla/Bug.pm
@@ -581,8 +581,7 @@ sub update {
# inside this function.
my $delta_ts = shift || $dbh->selectrow_array("SELECT NOW()");
- my $old_bug = $self->new($self->id);
- my $changes = $self->SUPER::update(@_);
+ my ($changes, $old_bug) = $self->SUPER::update(@_);
# Certain items in $changes have to be fixed so that they hold
# a name instead of an ID.
diff --git a/Bugzilla/Field/Choice.pm b/Bugzilla/Field/Choice.pm
index 7705258eb..9db5c5efd 100644
--- a/Bugzilla/Field/Choice.pm
+++ b/Bugzilla/Field/Choice.pm
@@ -24,6 +24,7 @@ package Bugzilla::Field::Choice;
use base qw(Bugzilla::Object);
+use Bugzilla::Config qw(SetParam write_params);
use Bugzilla::Constants;
use Bugzilla::Error;
use Bugzilla::Field;
@@ -41,6 +42,11 @@ use constant DB_COLUMNS => qw(
sortkey
);
+use constant UPDATE_COLUMNS => qw(
+ value
+ sortkey
+);
+
use constant NAME_FIELD => 'value';
use constant LIST_ORDER => 'sortkey, value';
@@ -55,6 +61,13 @@ use constant CLASS_MAP => {
bug_status => 'Bugzilla::Status',
};
+use constant DEFAULT_MAP => {
+ op_sys => 'defaultopsys',
+ rep_platform => 'defaultplatform',
+ priority => 'defaultpriority',
+ bug_severity => 'defaultseverity',
+};
+
#################
# Class Factory #
#################
@@ -127,6 +140,37 @@ sub create {
return $class->SUPER::create(@_);
}
+sub update {
+ my $self = shift;
+ my $dbh = Bugzilla->dbh;
+ my $fname = $self->field->name;
+
+ $dbh->bz_start_transaction();
+
+ my ($changes, $old_self) = $self->SUPER::update(@_);
+ if (exists $changes->{value}) {
+ my ($old, $new) = @{ $changes->{value} };
+ if ($self->field->type == FIELD_TYPE_MULTI_SELECT) {
+ $dbh->do("UPDATE bug_$fname SET value = ? WHERE value = ?",
+ undef, $new, $old);
+ }
+ else {
+ $dbh->do("UPDATE bugs SET $fname = ? WHERE $fname = ?",
+ undef, $new, $old);
+ }
+
+ if ($old_self->is_default) {
+ my $param = $self->DEFAULT_MAP->{$self->field->name};
+ SetParam($param, $self->name);
+ write_params();
+ }
+ }
+
+ $dbh->bz_commit_transaction();
+ return $changes;
+}
+
+
#############
# Accessors #
#############
@@ -143,6 +187,35 @@ sub field {
return $cache->{"field_$class"};
}
+sub is_default {
+ my $self = shift;
+ my $param_value =
+ Bugzilla->params->{ $self->DEFAULT_MAP->{$self->field->name} };
+ return 0 if !defined $param_value;
+ return $self->name eq $param_value ? 1 : 0;
+}
+
+sub is_static {
+ my $self = shift;
+ # If we need to special-case Resolution for *anything* else, it should
+ # get its own subclass.
+ if ($self->field->name eq 'resolution') {
+ return grep($_ eq $self->name, ('', 'FIXED', 'MOVED', 'DUPLICATE'))
+ ? 1 : 0;
+ }
+ elsif ($self->field->custom) {
+ return $self->name eq '---' ? 1 : 0;
+ }
+ return 0;
+}
+
+############
+# Mutators #
+############
+
+sub set_name { $_[0]->set('value', $_[1]); }
+sub set_sortkey { $_[0]->set('sortkey', $_[1]); }
+
##############
# Validators #
##############
@@ -153,12 +226,21 @@ sub _check_value {
my $field = $invocant->field;
$value = trim($value);
+
+ # Make sure people don't rename static values
+ if (blessed($invocant) && $value ne $invocant->name
+ && $invocant->is_static)
+ {
+ ThrowUserError('fieldvalue_not_editable',
+ { field => $field, old_value => $invocant->name });
+ }
+
ThrowUserError('fieldvalue_undefined') if !defined $value || $value eq "";
ThrowUserError('fieldvalue_name_too_long', { value => $value })
if length($value) > MAX_FIELD_VALUE_SIZE;
my $exists = $invocant->type($field)->new({ name => $value });
- if ($exists) {
+ if ($exists && (!blessed($invocant) || $invocant->id != $exists->id)) {
ThrowUserError('fieldvalue_already_exists',
{ field => $field, value => $value });
}
diff --git a/Bugzilla/Object.pm b/Bugzilla/Object.pm
index bcd436484..cde440b95 100644
--- a/Bugzilla/Object.pm
+++ b/Bugzilla/Object.pm
@@ -283,6 +283,10 @@ sub update {
$dbh->bz_commit_transaction();
+ if (wantarray) {
+ return (\%changes, $old_self);
+ }
+
return \%changes;
}
@@ -703,6 +707,8 @@ updated, and they will only be updated if their values have changed.
=item B<Returns>
+B<In scalar context:>
+
A hashref showing what changed during the update. The keys are the column
names from L</UPDATE_COLUMNS>. If a field was not changed, it will not be
in the hash at all. If the field was changed, the key will point to an arrayref.
@@ -711,6 +717,13 @@ will be the new value.
If there were no changes, we return a reference to an empty hash.
+B<In array context:>
+
+Returns a list, where the first item is the above hashref. The second item
+is the object as it was in the database before update() was called. (This
+is mostly useful to subclasses of C<Bugzilla::Object> that are implementing
+C<update>.)
+
=back
=back
diff --git a/Bugzilla/Product.pm b/Bugzilla/Product.pm
index 235a06926..8fb7b7ca9 100644
--- a/Bugzilla/Product.pm
+++ b/Bugzilla/Product.pm
@@ -147,7 +147,7 @@ sub update {
# Don't update the DB if something goes wrong below -> transaction.
$dbh->bz_start_transaction();
- my $changes = $self->SUPER::update(@_);
+ my ($changes, $old_self) = $self->SUPER::update(@_);
# We also have to fix votes.
my @msgs; # Will store emails to send to voters.
@@ -247,7 +247,7 @@ sub update {
require Bugzilla::Bug;
import Bugzilla::Bug qw(LogActivityEntry);
- my $old_settings = $self->new($self->id)->group_controls;
+ my $old_settings = $old_self->group_controls;
my $new_settings = $self->group_controls;
my $timestamp = $dbh->selectrow_array('SELECT NOW()');
diff --git a/Bugzilla/Status.pm b/Bugzilla/Status.pm
index 5f37974e7..565433850 100644
--- a/Bugzilla/Status.pm
+++ b/Bugzilla/Status.pm
@@ -77,11 +77,19 @@ sub create {
##### Accessors ####
###############################
-sub name { return $_[0]->{'value'}; }
-sub sortkey { return $_[0]->{'sortkey'}; }
sub is_active { return $_[0]->{'isactive'}; }
sub is_open { return $_[0]->{'is_open'}; }
+sub is_static {
+ my $self = shift;
+ if ($self->name eq 'UNCONFIRMED'
+ || $self->name eq Bugzilla->params->{'duplicate_or_move_bug_status'})
+ {
+ return 1;
+ }
+ return 0;
+}
+
##############
# Validators #
##############
diff --git a/editusers.cgi b/editusers.cgi
index f133b7409..a75f42040 100755
--- a/editusers.cgi
+++ b/editusers.cgi
@@ -238,7 +238,7 @@ if ($action eq 'search') {
# Update profiles table entry; silently skip doing this if the user
# is not authorized.
- my %changes;
+ my $changes = {};
if ($editusers) {
$otherUser->set_login($cgi->param('login'));
$otherUser->set_name($cgi->param('name'));
@@ -246,7 +246,7 @@ if ($action eq 'search') {
if $cgi->param('password');
$otherUser->set_disabledtext($cgi->param('disabledtext'));
$otherUser->set_disable_mail($cgi->param('disable_mail'));
- %changes = %{$otherUser->update()};
+ $changes = $otherUser->update();
}
# Update group settings.
@@ -334,7 +334,7 @@ if ($action eq 'search') {
delete_token($token);
$vars->{'message'} = 'account_updated';
- $vars->{'changed_fields'} = [keys %changes];
+ $vars->{'changed_fields'} = [keys %$changes];
$vars->{'groups_added_to'} = \@groupsAddedTo;
$vars->{'groups_removed_from'} = \@groupsRemovedFrom;
$vars->{'groups_granted_rights_to_bless'} = \@groupsGrantedRightsToBless;
diff --git a/editvalues.cgi b/editvalues.cgi
index 4525774e1..f6a602b55 100755
--- a/editvalues.cgi
+++ b/editvalues.cgi
@@ -356,91 +356,15 @@ if ($action eq 'edit') {
#
if ($action eq 'update') {
check_token_data($token, 'edit_field_value');
- my $valueold = trim($cgi->param('valueold') || '');
- my $sortkeyold = trim($cgi->param('sortkeyold') || '0');
-
- ValueMustExist($field, $valueold);
- trick_taint($valueold);
-
- $vars->{'value'} = $value;
- # If the value cannot be renamed, throw an error.
- if (lsearch($static{$field}, $valueold) >= 0 && $value ne $valueold) {
- $vars->{'old_value'} = $valueold;
- ThrowUserError('fieldvalue_not_editable', $vars);
- }
-
- if (length($value) > 60) {
- ThrowUserError('fieldvalue_name_too_long', $vars);
- }
-
- $dbh->bz_start_transaction();
-
- # Need to store because detaint_natural() will delete this if
- # invalid
- my $stored_sortkey = $sortkey;
- if ($sortkey != $sortkeyold) {
-
- if (!detaint_natural($sortkey)) {
- ThrowUserError('fieldvalue_sortkey_invalid',
- {'name' => $field,
- 'sortkey' => $stored_sortkey});
-
- }
-
- $dbh->do("UPDATE $field SET sortkey = ? WHERE value = ?",
- undef, $sortkey, $valueold);
-
- $vars->{'updated_sortkey'} = 1;
- $vars->{'sortkey'} = $sortkey;
- }
-
- if ($value ne $valueold) {
-
- unless ($value) {
- ThrowUserError('fieldvalue_undefined');
- }
- if (ValueExists($field, $value)) {
- ThrowUserError('fieldvalue_already_exists', $vars);
- }
- if ($field eq 'bug_status'
- && (grep { lc($value) eq $_ } SPECIAL_STATUS_WORKFLOW_ACTIONS))
- {
- $vars->{'value'} = $value;
- ThrowUserError('fieldvalue_reserved_word', $vars);
- }
- trick_taint($value);
-
- if ($field_obj->type != FIELD_TYPE_MULTI_SELECT) {
- $dbh->do("UPDATE bugs SET $field = ? WHERE $field = ?",
- undef, $value, $valueold);
- }
- else {
- $dbh->do("UPDATE bug_$field SET value = ? WHERE value = ?",
- undef, $value, $valueold);
- }
-
- $dbh->do("UPDATE $field SET value = ? WHERE value = ?",
- undef, $value, $valueold);
-
- $vars->{'updated_value'} = 1;
- }
-
- $dbh->bz_commit_transaction();
-
- # If the old value was the default value for the field,
- # update data/params accordingly.
- # This update is done while tables are unlocked due to the
- # annoying calls in Bugzilla/Config/Common.pm.
- if (defined $defaults{$field}
- && $value ne $valueold
- && $valueold eq Bugzilla->params->{$defaults{$field}})
- {
- SetParam($defaults{$field}, $value);
- write_params();
- $vars->{'default_value_updated'} = 1;
- }
+ $vars->{'value'} = $cgi->param('valueold');
+ my $value_obj = Bugzilla::Field::Choice->type($field_obj)
+ ->check($cgi->param('valueold'));
+ $value_obj->set_name($value);
+ $value_obj->set_sortkey($sortkey);
+ $vars->{'changes'} = $value_obj->update();
delete_token($token);
+ $vars->{'value_obj'} = $value_obj;
$vars->{'message'} = 'field_value_updated';
display_field_values();
}
diff --git a/template/en/default/global/messages.html.tmpl b/template/en/default/global/messages.html.tmpl
index eb869a776..82a71a5a2 100644
--- a/template/en/default/global/messages.html.tmpl
+++ b/template/en/default/global/messages.html.tmpl
@@ -314,20 +314,23 @@
[% ELSIF message_tag == "field_value_updated" %]
[% title = "Field Value Updated" %]
- [% IF updated_value || updated_sortkey %]
- Changes to the <em>[% value FILTER html %]</em> value of the
+ [% IF changes.keys.size %]
+ The <em>[% value FILTER html %]</em> value of the
<em>[% field.description FILTER html %]</em>
- (<em>[% field.name FILTER html %]</em>) field have been changed:
+ (<em>[% field.name FILTER html %]</em>) field has been changed:
<ul>
- [% IF updated_value %]
- <li>Field value updated to <em>[% value FILTER html %]</em></li>
- [% IF default_value_updated %]
- (note that this value is the default for this field. All
- references to the default value will now point to this new value)
- [% END %]
+ [% IF changes.value %]
+ <li>Field value updated to
+ <em>[% changes.value.1 FILTER html %]</em>.
+ [% IF value_obj.is_default %]
+ (Note that this value is the default for this field. All
+ references to the default value will now point to this new value.)
+ [% END %]
+ </li>
[% END %]
- [% IF updated_sortkey %]
- <li>Field value sortkey updated to <em>[% sortkey FILTER html %]</em></li>
+ [% IF changes.sortkey %]
+ <li>Sortkey updated to
+ <em>[% changes.sortkey.1 FILTER html %]</em>.</li>
[% END %]
</ul>
[% ELSE %]
diff --git a/template/en/default/global/user-error.html.tmpl b/template/en/default/global/user-error.html.tmpl
index bcb6b6630..c306b692a 100644
--- a/template/en/default/global/user-error.html.tmpl
+++ b/template/en/default/global/user-error.html.tmpl
@@ -457,7 +457,8 @@
[% ELSIF error == "fieldvalue_not_editable" %]
[% title = "Field Value Not Editable" %]
The value '[% old_value FILTER html %]' cannot be renamed because
- it plays some special role for the '[% field.description FILTER html %]' field.
+ it plays some special role for the '[% field.description FILTER html %]'
+ field.
[% ELSIF error == "fieldvalue_not_deletable" %]
[% title = "Field Value Not Deletable" %]
@@ -470,7 +471,7 @@
[% ELSIF error == "fieldvalue_reserved_word" %]
[% title = "Reserved Word Not Allowed" %]
- You cannot use the '[% value FILTER html %]' value for the
+ You cannot use the value '[% value FILTER html %]' for the
'[% field.description FILTER html %]' field. This value is used internally.
Please choose another one.