Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
bugzilla
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
etersoft
bugzilla
Commits
620caf68
Commit
620caf68
authored
Jan 18, 2008
by
mkanat%bugzilla.org
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Bug 402791: Move status and resolution updating from process_bug.cgi into Bugzilla::Bug
Patch By Max Kanat-Alexander <mkanat@bugzilla.org> r=LpSolit, a=LpSolit
parent
f39fc76d
Show whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
480 additions
and
433 deletions
+480
-433
Bug.pm
Bugzilla/Bug.pm
+288
-237
Status.pm
Bugzilla/Status.pm
+98
-0
process_bug.cgi
process_bug.cgi
+66
-185
code-error.html.tmpl
template/en/default/global/code-error.html.tmpl
+4
-0
user-error.html.tmpl
template/en/default/global/user-error.html.tmpl
+24
-11
No files found.
Bugzilla/Bug.pm
View file @
620caf68
...
@@ -164,6 +164,7 @@ use constant UPDATE_VALIDATORS => {
...
@@ -164,6 +164,7 @@ use constant UPDATE_VALIDATORS => {
assigned_to
=>
\&
_check_assigned_to
,
assigned_to
=>
\&
_check_assigned_to
,
bug_status
=>
\&
_check_bug_status
,
bug_status
=>
\&
_check_bug_status
,
cclist_accessible
=>
\&
Bugzilla::Object::
check_boolean
,
cclist_accessible
=>
\&
Bugzilla::Object::
check_boolean
,
dup_id
=>
\&
_check_dup_id
,
qa_contact
=>
\&
_check_qa_contact
,
qa_contact
=>
\&
_check_qa_contact
,
reporter_accessible
=>
\&
Bugzilla::Object::
check_boolean
,
reporter_accessible
=>
\&
Bugzilla::Object::
check_boolean
,
resolution
=>
\&
_check_resolution
,
resolution
=>
\&
_check_resolution
,
...
@@ -178,14 +179,14 @@ sub UPDATE_COLUMNS {
...
@@ -178,14 +179,14 @@ sub UPDATE_COLUMNS {
my
@columns
=
qw(
my
@columns
=
qw(
alias
alias
assigned_to
assigned_to
bug_file_loc
bug_severity
bug_status
cclist_accessible
cclist_accessible
component_id
component_id
deadline
deadline
estimated_time
estimated_time
everconfirmed
everconfirmed
bug_file_loc
bug_severity
bug_status
op_sys
op_sys
priority
priority
product_id
product_id
...
@@ -437,12 +438,8 @@ sub run_create_validators {
...
@@ -437,12 +438,8 @@ sub run_create_validators {
delete
$params
->
{
product
};
delete
$params
->
{
product
};
(
$params
->
{
bug_status
},
$params
->
{
everconfirmed
})
(
$params
->
{
bug_status
},
$params
->
{
everconfirmed
})
=
$class
->
_check_bug_status
(
$params
->
{
bug_status
},
$product
);
=
$class
->
_check_bug_status
(
$params
->
{
bug_status
},
$product
,
$params
->
{
comment
});
# Check whether a comment is required on bug creation.
my
$vars
=
{};
$vars
->
{
comment_exists
}
=
(
$params
->
{
comment
}
=~
/\S+/
)
?
1
:
0
;
Bugzilla::
Bug
->
check_status_change_triggers
(
$params
->
{
bug_status
},
[]
,
$vars
);
$params
->
{
target_milestone
}
=
$class
->
_check_target_milestone
(
$params
->
{
target_milestone
}
=
$class
->
_check_target_milestone
(
$params
->
{
target_milestone
},
$product
);
$params
->
{
target_milestone
},
$product
);
...
@@ -582,14 +579,19 @@ sub update {
...
@@ -582,14 +579,19 @@ sub update {
$delta_ts
);
$delta_ts
);
}
}
# If this bug is no longer a duplicate, it no longer belongs in the
# Check if we have to update the duplicates table and the other bug.
# dup table.
my
(
$old_dup
,
$cur_dup
)
=
(
$old_bug
->
dup_id
||
0
,
$self
->
dup_id
||
0
);
if
(
exists
$changes
->
{
'resolution'
}
if
(
$old_dup
!=
$cur_dup
)
{
&&
$changes
->
{
'resolution'
}
->
[
0
]
eq
'DUPLICATE'
)
{
my
$dup_id
=
$self
->
dup_id
;
$dbh
->
do
(
"DELETE FROM duplicates WHERE dupe = ?"
,
undef
,
$self
->
id
);
$dbh
->
do
(
"DELETE FROM duplicates WHERE dupe = ?"
,
undef
,
$self
->
id
);
$changes
->
{
'dupe_of'
}
=
[
$dup_id
,
undef
];
if
(
$cur_dup
)
{
$dbh
->
do
(
'INSERT INTO duplicates (dupe, dupe_of) VALUES (?,?)'
,
undef
,
$self
->
id
,
$cur_dup
);
if
(
my
$update_dup
=
delete
$self
->
{
_dup_for_update
})
{
$update_dup
->
update
();
}
}
$changes
->
{
'dup_id'
}
=
[
$old_dup
||
undef
,
$cur_dup
||
undef
];
}
}
# If any change occurred, refresh the timestamp of the bug.
# If any change occurred, refresh the timestamp of the bug.
...
@@ -893,41 +895,62 @@ sub _check_bug_severity {
...
@@ -893,41 +895,62 @@ sub _check_bug_severity {
}
}
sub
_check_bug_status
{
sub
_check_bug_status
{
my
(
$invocant
,
$status
,
$product
)
=
@_
;
my
(
$invocant
,
$status
,
$product
,
$comment
)
=
@_
;
my
$user
=
Bugzilla
->
user
;
my
$user
=
Bugzilla
->
user
;
my
@valid_statuses
;
# Make sure this is a valid status.
my
$new_status
=
ref
$status
?
$status
:
Bugzilla::
Status
->
check
(
$status
);
my
$old_status
;
# Note that this is undef for new bugs.
if
(
ref
$invocant
)
{
if
(
ref
$invocant
)
{
$product
=
$invocant
->
product_obj
;
$product
=
$invocant
->
product_obj
;
@valid_statuses
=
map
{
$_
->
name
}
@
{
$invocant
->
status
->
can_change_to
};
$old_status
=
$invocant
->
status
;
}
my
$comments
=
$invocant
->
{
added_comments
}
||
[]
;
else
{
$comment
=
$comments
->
[
-
1
];
@valid_statuses
=
map
{
$_
->
name
}
@
{
Bugzilla::
Status
->
can_change_to
()};
}
}
if
(
!
$product
->
votes_to_confirm
)
{
# Check permissions for users filing new bugs.
# UNCONFIRMED becomes an invalid status if votes_to_confirm is 0,
if
(
!
ref
$invocant
)
{
# even if you are in editbugs.
my
$default_status
=
Bugzilla::
Status
->
can_change_to
->
[
0
];
@valid_statuses
=
grep
{
$_
ne
'UNCONFIRMED'
}
@valid_statuses
;
}
if
(
!
ref
(
$invocant
))
{
if
(
$user
->
in_group
(
'editbugs'
,
$product
->
id
)
if
(
$user
->
in_group
(
'editbugs'
,
$product
->
id
)
||
$user
->
in_group
(
'canconfirm'
,
$product
->
id
))
{
||
$user
->
in_group
(
'canconfirm'
,
$product
->
id
))
{
# If the user with privs hasn't selected another status,
# If the user with privs hasn't selected another status,
# select the first one of the list.
# select the first one of the list.
$
status
||=
$valid_statuses
[
0
]
;
$
new_status
||=
$default_status
;
}
}
else
{
else
{
# A user with no privs cannot choose the initial status.
# A user with no privs cannot choose the initial status.
$
status
=
$valid_statuses
[
0
]
;
$
new_status
=
$default_status
;
}
}
}
}
# This check already takes the workflow into account.
# Make sure this is a valid transition.
check_field
(
'bug_status'
,
$status
,
\
@valid_statuses
);
if
(
!
$new_status
->
allow_change_from
(
$old_status
,
$product
))
{
ThrowUserError
(
'illegal_bug_status_transition'
,
{
old
=>
$old_status
,
new
=>
$new_status
});
}
return
$status
if
ref
$invocant
;
# Check if a comment is required for this change.
if
(
$new_status
->
comment_required_on_change_from
(
$old_status
)
&&
!
$comment
)
{
ThrowUserError
(
'comment_required'
,
{
old
=>
$old_status
,
new
=>
$new_status
});
}
if
(
ref
$invocant
&&
$new_status
->
name
eq
'ASSIGNED'
&&
Bugzilla
->
params
->
{
"usetargetmilestone"
}
&&
Bugzilla
->
params
->
{
"musthavemilestoneonaccept"
}
# musthavemilestoneonaccept applies only if at least two
# target milestones are defined for the product.
&&
scalar
(
@
{
$product
->
milestones
})
>
1
&&
$invocant
->
target_milestone
eq
$product
->
default_milestone
)
{
ThrowUserError
(
"milestone_required"
,
{
bug
=>
$invocant
});
}
return
$new_status
->
name
if
ref
$invocant
;
return
(
$status
,
$status
eq
'UNCONFIRMED'
?
0
:
1
);
return
(
$status
,
$status
eq
'UNCONFIRMED'
?
0
:
1
);
}
}
...
@@ -1073,6 +1096,85 @@ sub _check_dependencies {
...
@@ -1073,6 +1096,85 @@ sub _check_dependencies {
return
(
$deps
{
'dependson'
},
$deps
{
'blocked'
});
return
(
$deps
{
'dependson'
},
$deps
{
'blocked'
});
}
}
sub
_check_dup_id
{
my
(
$self
,
$dupe_of
)
=
@_
;
my
$dbh
=
Bugzilla
->
dbh
;
$dupe_of
=
trim
(
$dupe_of
);
$dupe_of
||
ThrowCodeError
(
'undefined_field'
,
{
field
=>
'dup_id'
});
# Make sure we can change the original bug (issue A on bug 96085)
ValidateBugID
(
$dupe_of
,
'dup_id'
);
# Make sure a loop isn't created when marking this bug
# as duplicate.
my
%
dupes
;
my
$this_dup
=
$dupe_of
;
my
$sth
=
$dbh
->
prepare
(
'SELECT dupe_of FROM duplicates WHERE dupe = ?'
);
while
(
$this_dup
)
{
if
(
$this_dup
==
$self
->
id
)
{
ThrowUserError
(
'dupe_loop_detected'
,
{
bug_id
=>
$self
->
id
,
dupe_of
=>
$dupe_of
});
}
# If $dupes{$this_dup} is already set to 1, then a loop
# already exists which does not involve this bug.
# As the user is not responsible for this loop, do not
# prevent him from marking this bug as a duplicate.
last
if
exists
$dupes
{
$this_dup
};
$dupes
{
$this_dup
}
=
1
;
$this_dup
=
$dbh
->
selectrow_array
(
$sth
,
undef
,
$this_dup
);
}
my
$cur_dup
=
$self
->
dup_id
||
0
;
if
(
$cur_dup
!=
$dupe_of
&&
Bugzilla
->
params
->
{
'commentonduplicate'
}
&&
!
$self
->
{
added_comments
})
{
ThrowUserError
(
'comment_required'
);
}
# Should we add the reporter to the CC list of the new bug?
# If he can see the bug...
if
(
$self
->
reporter
->
can_see_bug
(
$dupe_of
))
{
my
$dupe_of_bug
=
new
Bugzilla::
Bug
(
$dupe_of
);
# We only add him if he's not the reporter of the other bug.
$self
->
{
_add_dup_cc
}
=
1
if
$dupe_of_bug
->
reporter
->
id
!=
$self
->
reporter
->
id
;
}
# What if the reporter currently can't see the new bug? In the browser
# interface, we prompt the user. In other interfaces, we default to
# not adding the user, as the safest option.
elsif
(
Bugzilla
->
params
->
usage_mode
==
USAGE_MODE_BROWSER
)
{
# If we've already confirmed whether the user should be added...
my
$cgi
=
Bugzilla
->
cgi
;
my
$add_confirmed
=
$cgi
->
param
(
'confirm_add_duplicate'
);
if
(
defined
$add_confirmed
)
{
$self
->
{
_add_dup_cc
}
=
$add_confirmed
;
}
else
{
# Note that here we don't check if he user is already the reporter
# of the dupe_of bug, since we already checked if he can *see*
# the bug, above. People might have reporter_accessible turned
# off, but cclist_accessible turned on, so they might want to
# add the reporter even though he's already the reporter of the
# dup_of bug.
my
$vars
=
{};
my
$template
=
Bugzilla
->
template
;
# Ask the user what they want to do about the reporter.
$vars
->
{
'cclist_accessible'
}
=
$dbh
->
selectrow_array
(
q{SELECT cclist_accessible FROM bugs WHERE bug_id = ?}
,
undef
,
$dupe_of
);
$vars
->
{
'original_bug_id'
}
=
$dupe_of
;
$vars
->
{
'duplicate_bug_id'
}
=
$self
->
id
;
print
$cgi
->
header
();
$template
->
process
(
"bug/process/confirm-duplicate.html.tmpl"
,
$vars
)
||
ThrowTemplateError
(
$template
->
error
());
exit
;
}
}
return
$dupe_of
;
}
sub
_check_estimated_time
{
sub
_check_estimated_time
{
return
$_
[
0
]
->
_check_time
(
$_
[
1
],
'estimated_time'
);
return
$_
[
0
]
->
_check_time
(
$_
[
1
],
'estimated_time'
);
}
}
...
@@ -1221,9 +1323,45 @@ sub _check_rep_platform {
...
@@ -1221,9 +1323,45 @@ sub _check_rep_platform {
}
}
sub
_check_resolution
{
sub
_check_resolution
{
my
(
$
invocant
,
$resolution
)
=
@_
;
my
(
$
self
,
$resolution
)
=
@_
;
$resolution
=
trim
(
$resolution
);
$resolution
=
trim
(
$resolution
);
# Throw a special error for resolving bugs without a resolution
# (or trying to change the resolution to '' on a closed bug without
# using clear_resolution).
ThrowUserError
(
'missing_resolution'
,
{
status
=>
$self
->
status
->
name
})
if
!
$resolution
&&
!
$self
->
status
->
is_open
;
# Make sure this is a valid resolution.
check_field
(
'resolution'
,
$resolution
);
check_field
(
'resolution'
,
$resolution
);
# The moving code doesn't use set_resolution. This check prevents
# people from hacking the URL variables (or using some other interface)
# and setting a bug to MOVED without moving it.
ThrowCodeError
(
'no_manual_moved'
)
if
$resolution
eq
'MOVED'
;
# Don't allow open bugs to have resolutions.
ThrowUserError
(
'resolution_not_allowed'
)
if
$self
->
status
->
is_open
;
# Check noresolveonopenblockers.
if
(
Bugzilla
->
params
->
{
"noresolveonopenblockers"
}
&&
$resolution
eq
'FIXED'
)
{
my
@dependencies
=
CountOpenDependencies
(
$self
->
id
);
if
(
@dependencies
)
{
ThrowUserError
(
"still_unresolved_bugs"
,
{
dependencies
=>
\
@dependencies
,
dependency_count
=>
scalar
@dependencies
});
}
}
# Check if they're changing the resolution and need to comment.
if
(
Bugzilla
->
params
->
{
'commentonchange_resolution'
}
&&
$self
->
resolution
&&
$resolution
ne
$self
->
resolution
&&
!
$self
->
{
added_comments
})
{
ThrowUserError
(
'comment_required'
);
}
return
$resolution
;
return
$resolution
;
}
}
...
@@ -1476,6 +1614,11 @@ sub set_assigned_to {
...
@@ -1476,6 +1614,11 @@ sub set_assigned_to {
}
}
sub
reset_assigned_to
{
sub
reset_assigned_to
{
my
$self
=
shift
;
my
$self
=
shift
;
if
(
Bugzilla
->
params
->
{
'commentonreassignbycomponent'
}
&&
!
$self
->
{
added_comments
})
{
ThrowUserError
(
'comment_required'
);
}
my
$comp
=
$self
->
component_obj
;
my
$comp
=
$self
->
component_obj
;
$self
->
set_assigned_to
(
$comp
->
default_assignee
);
$self
->
set_assigned_to
(
$comp
->
default_assignee
);
}
}
...
@@ -1528,6 +1671,38 @@ sub set_dependencies {
...
@@ -1528,6 +1671,38 @@ sub set_dependencies {
$self
->
{
'dependson'
}
=
$dependson
;
$self
->
{
'dependson'
}
=
$dependson
;
$self
->
{
'blocked'
}
=
$blocked
;
$self
->
{
'blocked'
}
=
$blocked
;
}
}
sub
_clear_dup_id
{
$_
[
0
]
->
{
dup_id
}
=
undef
;
}
sub
set_dup_id
{
my
(
$self
,
$dup_id
)
=
@_
;
my
$old
=
$self
->
dup_id
||
0
;
$self
->
set
(
'dup_id'
,
$dup_id
);
my
$new
=
$self
->
dup_id
||
0
;
return
if
$old
==
$new
;
# Update the other bug.
my
$dupe_of
=
new
Bugzilla::
Bug
(
$self
->
dup_id
);
if
(
delete
$self
->
{
_add_dup_cc
})
{
$dupe_of
->
add_cc
(
$self
->
reporter
);
}
$dupe_of
->
add_comment
(
""
,
{
type
=>
CMT_HAS_DUPE
,
extra_data
=>
$self
->
id
});
$self
->
{
_dup_for_update
}
=
$dupe_of
;
# Now make sure that we add a duplicate comment on *this* bug.
# (Change an existing comment into a dup comment, if there is one,
# or add an empty dup comment.)
if
(
$self
->
{
added_comments
})
{
my
@normal
=
grep
{
!
defined
$_
->
{
type
}
||
$_
->
{
type
}
==
CMT_NORMAL
}
@
{
$self
->
{
added_comments
}
};
# Turn the last one into a dup comment.
$normal
[
-
1
]
->
{
type
}
=
CMT_DUPE_OF
;
$normal
[
-
1
]
->
{
extra_data
}
=
$self
->
dup_id
;
}
else
{
$self
->
add_comment
(
''
,
{
type
=>
CMT_DUPE_OF
,
extra_data
=>
$self
->
dup_id
});
}
}
sub
set_estimated_time
{
$_
[
0
]
->
set
(
'estimated_time'
,
$_
[
1
]);
}
sub
set_estimated_time
{
$_
[
0
]
->
set
(
'estimated_time'
,
$_
[
1
]);
}
sub
_set_everconfirmed
{
$_
[
0
]
->
set
(
'everconfirmed'
,
$_
[
1
]);
}
sub
_set_everconfirmed
{
$_
[
0
]
->
set
(
'everconfirmed'
,
$_
[
1
]);
}
sub
set_op_sys
{
$_
[
0
]
->
set
(
'op_sys'
,
$_
[
1
]);
}
sub
set_op_sys
{
$_
[
0
]
->
set
(
'op_sys'
,
$_
[
1
]);
}
...
@@ -1665,6 +1840,11 @@ sub set_qa_contact {
...
@@ -1665,6 +1840,11 @@ sub set_qa_contact {
}
}
sub
reset_qa_contact
{
sub
reset_qa_contact
{
my
$self
=
shift
;
my
$self
=
shift
;
if
(
Bugzilla
->
params
->
{
'commentonreassignbycomponent'
}
&&
!
$self
->
{
added_comments
})
{
ThrowUserError
(
'comment_required'
);
}
my
$comp
=
$self
->
component_obj
;
my
$comp
=
$self
->
component_obj
;
$self
->
set_qa_contact
(
$comp
->
default_qa_contact
);
$self
->
set_qa_contact
(
$comp
->
default_qa_contact
);
}
}
...
@@ -1672,14 +1852,73 @@ sub set_remaining_time { $_[0]->set('remaining_time', $_[1]); }
...
@@ -1672,14 +1852,73 @@ sub set_remaining_time { $_[0]->set('remaining_time', $_[1]); }
# Used only when closing a bug or moving between closed states.
# Used only when closing a bug or moving between closed states.
sub
_zero_remaining_time
{
$_
[
0
]
->
{
'remaining_time'
}
=
0
;
}
sub
_zero_remaining_time
{
$_
[
0
]
->
{
'remaining_time'
}
=
0
;
}
sub
set_reporter_accessible
{
$_
[
0
]
->
set
(
'reporter_accessible'
,
$_
[
1
]);
}
sub
set_reporter_accessible
{
$_
[
0
]
->
set
(
'reporter_accessible'
,
$_
[
1
]);
}
sub
set_resolution
{
$_
[
0
]
->
set
(
'resolution'
,
$_
[
1
]);
}
sub
set_resolution
{
sub
clear_resolution
{
$_
[
0
]
->
{
'resolution'
}
=
''
}
my
(
$self
,
$value
,
$dupe_of
)
=
@_
;
my
$old_res
=
$self
->
resolution
;
$self
->
set
(
'resolution'
,
$value
);
my
$new_res
=
$self
->
resolution
;
if
(
$new_res
ne
$old_res
)
{
# Clear the dup_id if we're leaving the dup resolution.
if
(
$old_res
eq
'DUPLICATE'
)
{
$self
->
_clear_dup_id
();
}
# Duplicates should have no remaining time left.
elsif
(
$new_res
eq
'DUPLICATE'
&&
$self
->
remaining_time
!=
0
)
{
$self
->
_zero_remaining_time
();
}
}
# We don't check if we're entering or leaving the dup resolution here,
# because we could be moving from being a dup of one bug to being a dup
# of another, theoretically. Note that this code block will also run
# when going between different closed states.
if
(
$self
->
resolution
eq
'DUPLICATE'
)
{
if
(
$dupe_of
)
{
$self
->
set_dup_id
(
$dupe_of
);
}
elsif
(
!
$self
->
dup_id
)
{
ThrowUserError
(
'dupe_id_required'
);
}
}
}
sub
clear_resolution
{
my
$self
=
shift
;
if
(
!
$self
->
status
->
is_open
)
{
ThrowUserError
(
'resolution_cant_clear'
,
{
bug_id
=>
$self
->
id
});
}
if
(
Bugzilla
->
params
->
{
'commentonclearresolution'
}
&&
$self
->
resolution
&&
!
$self
->
{
added_comments
})
{
ThrowUserError
(
'comment_required'
);
}
$self
->
{
'resolution'
}
=
''
;
$self
->
_clear_dup_id
;
}
sub
set_severity
{
$_
[
0
]
->
set
(
'bug_severity'
,
$_
[
1
]);
}
sub
set_severity
{
$_
[
0
]
->
set
(
'bug_severity'
,
$_
[
1
]);
}
sub
set_status
{
sub
set_status
{
my
(
$self
,
$status
)
=
@_
;
my
(
$self
,
$status
,
$resolution
,
$dupe_of
)
=
@_
;
my
$old_status
=
$self
->
status
;
$self
->
set
(
'bug_status'
,
$status
);
$self
->
set
(
'bug_status'
,
$status
);
delete
$self
->
{
'status'
};
my
$new_status
=
$self
->
status
;
if
(
$new_status
->
is_open
)
{
# Check for the everconfirmed transition
# Check for the everconfirmed transition
$self
->
_set_everconfirmed
(
1
)
if
(
is_open_state
(
$status
)
&&
$status
ne
'UNCONFIRMED'
);
$self
->
_set_everconfirmed
(
1
)
if
$new_status
->
name
ne
'UNCONFIRMED'
;
$self
->
clear_resolution
();
}
else
{
# We do this here so that we can make sure closed statuses have
# resolutions.
$self
->
set_resolution
(
$resolution
||
$self
->
resolution
,
$dupe_of
);
# Changing between closed statuses zeros the remaining time.
if
(
$new_status
->
id
!=
$old_status
->
id
&&
$self
->
remaining_time
!=
0
)
{
$self
->
_zero_remaining_time
();
}
}
}
}
sub
set_status_whiteboard
{
$_
[
0
]
->
set
(
'status_whiteboard'
,
$_
[
1
]);
}
sub
set_status_whiteboard
{
$_
[
0
]
->
set
(
'status_whiteboard'
,
$_
[
1
]);
}
sub
set_summary
{
$_
[
0
]
->
set
(
'short_desc'
,
$_
[
1
]);
}
sub
set_summary
{
$_
[
0
]
->
set
(
'short_desc'
,
$_
[
1
]);
}
...
@@ -2389,217 +2628,29 @@ sub bug_alias_to_id {
...
@@ -2389,217 +2628,29 @@ sub bug_alias_to_id {
# Workflow Control routines
# Workflow Control routines
#####################################################################
#####################################################################
# Make sure that the new status is allowed by the status workflow.
sub
process_knob
{
sub
check_status_transition
{
my
(
$self
,
$action
,
$to_resolution
,
$dupe_of
)
=
@_
;
my
(
$self
,
$new_status
)
=
@_
;
if
(
!
grep
{
$_
->
name
eq
$self
->
bug_status
}
@
{
$new_status
->
can_change_from
})
{
ThrowUserError
(
'illegal_bug_status_transition'
,
{
old
=>
$self
->
bug_status
,
new
=>
$new_status
->
name
})
}
}
# Make sure all checks triggered by the workflow are successful.
# Some are hardcoded and come from older versions of Bugzilla.
sub
check_status_change_triggers
{
my
(
$self
,
$action
,
$bugs
,
$vars
)
=
@_
;
my
$dbh
=
Bugzilla
->
dbh
;
my
$dbh
=
Bugzilla
->
dbh
;
$vars
||=
{};
my
@bug_ids
=
map
{
$_
->
id
}
@$bugs
;
# First, make sure no comment is required if there is none.
# If a comment is given, then this check is useless.
if
(
!
$vars
->
{
comment_exists
})
{
if
(
grep
{
$action
eq
$_
}
SPECIAL_STATUS_WORKFLOW_ACTIONS
)
{
# 'commentonnone' doesn't exist, so this is safe.
ThrowUserError
(
'comment_required'
)
if
Bugzilla
->
params
->
{
"commenton$action"
};
}
elsif
(
!
scalar
@bug_ids
)
{
# The bug is being created; that's why @bug_ids is undefined.
my
$comment_required
=
$dbh
->
selectrow_array
(
'SELECT require_comment
FROM status_workflow
INNER JOIN bug_status
ON id = new_status
WHERE old_status IS NULL
AND value = ?'
,
undef
,
$action
);
ThrowUserError
(
'description_required'
)
if
$comment_required
;
}
else
{
my
$required_for_transitions
=
$dbh
->
selectcol_arrayref
(
'SELECT DISTINCT bug_status.value
FROM bug_status
INNER JOIN bugs
ON bugs.bug_status = bug_status.value
INNER JOIN status_workflow
ON bug_status.id = old_status
INNER JOIN bug_status b_s
ON b_s.id = new_status
WHERE bug_id IN ('
.
join
(
','
,
@bug_ids
)
.
')
AND b_s.value = ?
AND require_comment = 1'
,
undef
,
$action
);
if
(
scalar
(
@$required_for_transitions
))
{
ThrowUserError
(
'comment_required'
,
{
old
=>
$required_for_transitions
,
new
=>
$action
});
}
}
}
# Now run hardcoded checks.
return
if
$action
eq
'none'
;
# There is no checks for these actions.
return
if
(
$action
eq
'none'
||
$action
eq
'clearresolution'
);
# Also leave now if we are creating a new bug (we only want to check
# if a comment is required on bug creation).
return
unless
scalar
@bug_ids
;
if
(
$action
eq
'duplicate'
)
{
if
(
$action
eq
'duplicate'
)
{
# You cannot mark bugs as duplicates when changing
$self
->
set_status
(
Bugzilla
->
params
->
{
'duplicate_or_move_bug_status'
},
# several bugs at once.
'DUPLICATE'
,
$dupe_of
);
$vars
->
{
bug_id
}
||
ThrowUserError
(
'dupe_not_allowed'
);
# Make sure we can change the original bug (issue A on bug 96085)
$vars
->
{
dup_id
}
||
ThrowCodeError
(
'undefined_field'
,
{
field
=>
'dup_id'
});
ValidateBugID
(
$vars
->
{
dup_id
},
'dup_id'
);
# Make sure a loop isn't created when marking this bug
# as duplicate.
my
%
dupes
;
my
$dupe_of
=
$vars
->
{
dup_id
};
my
$sth
=
$dbh
->
prepare
(
'SELECT dupe_of FROM duplicates
WHERE dupe = ?'
);
while
(
$dupe_of
)
{
if
(
$dupe_of
==
$vars
->
{
bug_id
})
{
ThrowUserError
(
'dupe_loop_detected'
,
{
bug_id
=>
$vars
->
{
bug_id
},
dupe_of
=>
$vars
->
{
dup_id
}
});
}
# If $dupes{$dupe_of} is already set to 1, then a loop
# already exists which does not involve this bug.
# As the user is not responsible for this loop, do not
# prevent him from marking this bug as a duplicate.
last
if
exists
$dupes
{
"$dupe_of"
};
$dupes
{
"$dupe_of"
}
=
1
;
$sth
->
execute
(
$dupe_of
);
$dupe_of
=
$sth
->
fetchrow_array
;
}
}
elsif
(
$action
eq
'move'
)
{
# Also, let's see if the reporter has authorization to see
$self
->
set_status
(
Bugzilla
->
params
->
{
'duplicate_or_move_bug_status'
},
# the bug to which we are duping. If not we need to prompt.
'MOVED'
);
$vars
->
{
DuplicateUserConfirm
}
=
1
;
# DUPLICATE bugs should have no time remaining.
foreach
my
$bug
(
@$bugs
)
{
# Note that 0.00 is *true* for Perl!
next
unless
(
$bug
->
remaining_time
>
0
);
$bug
->
_zero_remaining_time
;
$vars
->
{
'message'
}
=
"remaining_time_zeroed"
if
Bugzilla
->
user
->
in_group
(
Bugzilla
->
params
->
{
'timetrackinggroup'
});
}
}
elsif
(
$action
eq
'change_resolution'
||
!
is_open_state
(
$action
))
{
# don't resolve as fixed while still unresolved blocking bugs
if
(
Bugzilla
->
params
->
{
"noresolveonopenblockers"
}
&&
$vars
->
{
resolution
}
eq
'FIXED'
)
{
my
@dependencies
=
Bugzilla::Bug::
CountOpenDependencies
(
@bug_ids
);
if
(
scalar
@dependencies
>
0
)
{
ThrowUserError
(
"still_unresolved_bugs"
,
{
dependencies
=>
\
@dependencies
,
dependency_count
=>
scalar
@dependencies
});
}
}
# You cannot use change_resolution if there is at least one open bug
# nor can you close open bugs if no resolution is given.
my
$open_states
=
join
(
','
,
map
{
$dbh
->
quote
(
$_
)}
BUG_STATE_OPEN
);
my
$idlist
=
join
(
','
,
@bug_ids
);
my
$is_open
=
$dbh
->
selectrow_array
(
"SELECT 1 FROM bugs WHERE bug_id IN ($idlist)
AND bug_status IN ($open_states)"
);
if
(
$is_open
)
{
ThrowUserError
(
'resolution_not_allowed'
)
if
(
$action
eq
'change_resolution'
);
ThrowUserError
(
'missing_resolution'
,
{
status
=>
$action
})
if
!
$vars
->
{
resolution
};
}
# Now is good time to validate the resolution, if any.
check_field
(
'resolution'
,
$vars
->
{
resolution
},
Bugzilla::
Bug
->
settable_resolutions
)
if
$vars
->
{
resolution
};
if
(
$action
ne
'change_resolution'
)
{
foreach
my
$b
(
@$bugs
)
{
if
(
$b
->
bug_status
ne
$action
)
{
# Note that 0.00 is *true* for Perl!
next
unless
(
$b
->
remaining_time
>
0
);
$b
->
_zero_remaining_time
;
$vars
->
{
'message'
}
=
"remaining_time_zeroed"
if
Bugzilla
->
user
->
in_group
(
Bugzilla
->
params
->
{
'timetrackinggroup'
});
}
}
}
}
elsif
(
$action
eq
'ASSIGNED'
&&
Bugzilla
->
params
->
{
"usetargetmilestone"
}
&&
Bugzilla
->
params
->
{
"musthavemilestoneonaccept"
})
{
$vars
->
{
requiremilestone
}
=
1
;
}
}
sub
get_new_status_and_resolution
{
my
(
$self
,
$action
,
$resolution
)
=
@_
;
my
$dbh
=
Bugzilla
->
dbh
;
my
$status
;
my
$everconfirmed
=
$self
->
everconfirmed
;
if
(
$action
eq
'none'
)
{
# Leaving the status unchanged doesn't need more investigation.
return
(
$self
->
bug_status
,
$self
->
resolution
,
$self
->
everconfirmed
);
}
elsif
(
$action
eq
'duplicate'
||
$action
eq
'move'
)
{
# Always change the bug status, even if the bug was already "closed".
$status
=
Bugzilla
->
params
->
{
'duplicate_or_move_bug_status'
};
$resolution
=
(
$action
eq
'duplicate'
)
?
'DUPLICATE'
:
'MOVED'
;
}
}
elsif
(
$action
eq
'change_resolution'
)
{
elsif
(
$action
eq
'change_resolution'
)
{
$status
=
$self
->
bug_status
;
$self
->
set_resolution
(
$to_resolution
);
# You cannot change the resolution of an open bug.
ThrowUserError
(
'resolution_not_allowed'
)
if
is_open_state
(
$status
);
$resolution
||
ThrowUserError
(
'missing_resolution'
,
{
status
=>
$status
});
}
}
elsif
(
$action
eq
'clearresolution'
)
{
elsif
(
$action
eq
'clearresolution'
)
{
$status
=
$self
->
bug_status
;
$self
->
clear_resolution
();
is_open_state
(
$status
)
||
ThrowUserError
(
'missing_resolution'
,
{
status
=>
$status
});
$resolution
=
''
;
}
}
else
{
else
{
$status
=
$action
;
$self
->
set_status
(
$action
,
$to_resolution
);
if
(
is_open_state
(
$status
))
{
# Open bugs have no resolution.
$resolution
=
''
;
$everconfirmed
=
(
$status
eq
'UNCONFIRMED'
)
?
0
:
1
;
}
elsif
(
is_open_state
(
$self
->
bug_status
))
{
# A resolution is required to close bugs.
$resolution
||
ThrowUserError
(
'missing_resolution'
,
{
status
=>
$status
});
}
}
else
{
# Already closed bugs can only change their resolution
# using the change_resolution action.
$resolution
=
$self
->
resolution
}
}
# Now it's time to validate the bug resolution.
# Bug resolutions have no workflow specific rules, so any valid
# resolution will do it.
check_field
(
'resolution'
,
$resolution
)
if
(
$resolution
ne
''
);
trick_taint
(
$resolution
);
return
(
$status
,
$resolution
,
$everconfirmed
);
}
}
#####################################################################
#####################################################################
...
...
Bugzilla/Status.pm
View file @
620caf68
...
@@ -106,6 +106,24 @@ sub can_change_to {
...
@@ -106,6 +106,24 @@ sub can_change_to {
return
$self
->
{
'can_change_to'
};
return
$self
->
{
'can_change_to'
};
}
}
sub
allow_change_from
{
my
(
$self
,
$old_status
,
$product
)
=
@_
;
# Always allow transitions from a status to itself.
return
1
if
(
$old_status
&&
$old_status
->
id
==
$self
->
id
);
if
(
$self
->
name
eq
'UNCONFIRMED'
&&
!
$product
->
votes_to_confirm
)
{
# UNCONFIRMED is an invalid status transition if votes_to_confirm is 0
# in this product.
return
0
;
}
my
(
$cond
,
$values
)
=
$self
->
_status_condition
(
$old_status
);
my
(
$transition_allowed
)
=
Bugzilla
->
dbh
->
selectrow_array
(
"SELECT 1 FROM status_workflow WHERE $cond"
,
undef
,
@$values
);
return
$transition_allowed
?
1
:
0
;
}
sub
can_change_from
{
sub
can_change_from
{
my
$self
=
shift
;
my
$self
=
shift
;
my
$dbh
=
Bugzilla
->
dbh
;
my
$dbh
=
Bugzilla
->
dbh
;
...
@@ -128,6 +146,32 @@ sub can_change_from {
...
@@ -128,6 +146,32 @@ sub can_change_from {
return
$self
->
{
'can_change_from'
};
return
$self
->
{
'can_change_from'
};
}
}
sub
comment_required_on_change_from
{
my
(
$self
,
$old_status
)
=
@_
;
my
(
$cond
,
$values
)
=
$self
->
_status_condition
(
$old_status
);
my
(
$require_comment
)
=
Bugzilla
->
dbh
->
selectrow_array
(
"SELECT require_comment FROM status_workflow
WHERE $cond"
,
undef
,
@$values
);
return
$require_comment
;
}
# Used as a helper for various functions that have to deal with old_status
# sometimes being NULL and sometimes having a value.
sub
_status_condition
{
my
(
$self
,
$old_status
)
=
@_
;
my
@values
;
my
$cond
=
'old_status IS NULL'
;
# For newly-filed bugs
if
(
$old_status
)
{
$cond
=
'old_status = ?'
;
push
(
@values
,
$old_status
->
id
);
}
$cond
.=
" AND new_status = ?"
;
push
(
@values
,
$self
->
id
);
return
(
$cond
,
\
@values
);
}
sub
add_missing_bug_status_transitions
{
sub
add_missing_bug_status_transitions
{
my
$bug_status
=
shift
||
Bugzilla
->
params
->
{
'duplicate_or_move_bug_status'
};
my
$bug_status
=
shift
||
Bugzilla
->
params
->
{
'duplicate_or_move_bug_status'
};
my
$dbh
=
Bugzilla
->
dbh
;
my
$dbh
=
Bugzilla
->
dbh
;
...
@@ -215,6 +259,60 @@ below.
...
@@ -215,6 +259,60 @@ below.
Returns: A list of Bugzilla::Status objects.
Returns: A list of Bugzilla::Status objects.
=item C<allow_change_from>
=over
=item B<Description>
Tells you whether or not a change to this status from another status is
allowed.
=item B<Params>
=over
=item C<$old_status> - The Bugzilla::Status you're changing from.
=item C<$product> - A L<Bugzilla::Product> representing the product of
the bug you're changing. Needed to check product-specific workflow
issues (such as whether or not the C<UNCONFIRMED> status is enabled
in this product).
=back
=item B<Returns>
C<1> if you are allowed to change to this status from that status, or
C<0> if you aren't allowed.
Note that changing from a status to itself is always allowed.
=back
=item C<comment_required_on_change_from>
=over
=item B<Description>
Checks if a comment is required to change to this status from another
status, according to the current settings in the workflow.
Note that this doesn't implement the checks enforced by the various
C<commenton> parameters--those are checked by internal checks in
L<Bugzilla::Bug>.
=item B<Params>
C<$old_status> - The status you're changing from.
=item B<Returns>
C<1> if a comment is required on this change, C<0> if not.
=back
=item C<add_missing_bug_status_transitions>
=item C<add_missing_bug_status_transitions>
Description: Insert all missing transitions to a given bug status.
Description: Insert all missing transitions to a given bug status.
...
...
process_bug.cgi
View file @
620caf68
...
@@ -75,7 +75,6 @@ $vars->{'use_keywords'} = 1 if Bugzilla::Keyword::keyword_count();
...
@@ -75,7 +75,6 @@ $vars->{'use_keywords'} = 1 if Bugzilla::Keyword::keyword_count();
my
@editable_bug_fields
=
editable_bug_fields
();
my
@editable_bug_fields
=
editable_bug_fields
();
my
$requiremilestone
=
0
;
local
our
$PrivilegesRequired
=
0
;
local
our
$PrivilegesRequired
=
0
;
######################################################################
######################################################################
...
@@ -268,48 +267,9 @@ if (should_set('product')) {
...
@@ -268,48 +267,9 @@ if (should_set('product')) {
}
}
}
}
# Confirm that the reporter of the current bug can access the bug we are duping to.
# Component, target_milestone, and version are in here just in case
sub
DuplicateUserConfirm
{
# the 'product' field wasn't defined in the CGI. It doesn't hurt to set
my
(
$dupe
,
$original
)
=
@_
;
# them twice.
my
$cgi
=
Bugzilla
->
cgi
;
my
$dbh
=
Bugzilla
->
dbh
;
my
$template
=
Bugzilla
->
template
;
# if we've already been through here, then exit
if
(
defined
$cgi
->
param
(
'confirm_add_duplicate'
))
{
return
;
}
if
(
$dupe
->
reporter
->
can_see_bug
(
$original
))
{
$cgi
->
param
(
'confirm_add_duplicate'
,
'1'
);
return
;
}
elsif
(
Bugzilla
->
usage_mode
==
USAGE_MODE_EMAIL
)
{
# The email interface defaults to the safe alternative, which is
# not CC'ing the user.
$cgi
->
param
(
'confirm_add_duplicate'
,
0
);
return
;
}
$vars
->
{
'cclist_accessible'
}
=
$dbh
->
selectrow_array
(
q{SELECT cclist_accessible FROM bugs WHERE bug_id = ?}
,
undef
,
$original
);
# Once in this part of the subroutine, the user has not been auto-validated
# and the duper has not chosen whether or not to add to CC list, so let's
# ask the duper what he/she wants to do.
$vars
->
{
'original_bug_id'
}
=
$original
;
$vars
->
{
'duplicate_bug_id'
}
=
$dupe
->
bug_id
;
# Confirm whether or not to add the reporter to the cc: list
# of the original bug (the one this bug is being duped against).
print
Bugzilla
->
cgi
->
header
();
$template
->
process
(
"bug/process/confirm-duplicate.html.tmpl"
,
$vars
)
||
ThrowTemplateError
(
$template
->
error
());
exit
;
}
my
@set_fields
=
qw(op_sys rep_platform priority bug_severity
my
@set_fields
=
qw(op_sys rep_platform priority bug_severity
component target_milestone version
component target_milestone version
bug_file_loc status_whiteboard short_desc
bug_file_loc status_whiteboard short_desc
...
@@ -324,9 +284,13 @@ my %methods = (
...
@@ -324,9 +284,13 @@ my %methods = (
bug_file_loc
=>
'set_url'
,
bug_file_loc
=>
'set_url'
,
);
);
foreach
my
$b
(
@bug_objects
)
{
foreach
my
$b
(
@bug_objects
)
{
# Component, target_milestone, and version are in here just in case
if
(
should_set
(
'comment'
)
||
$cgi
->
param
(
'work_time'
))
{
# the 'product' field wasn't defined in the CGI. It doesn't hurt to set
# Add a comment as needed to each bug. This is done early because
# them twice.
# there are lots of things that want to check if we added a comment.
$b
->
add_comment
(
scalar
(
$cgi
->
param
(
'comment'
)),
{
isprivate
=>
scalar
$cgi
->
param
(
'commentprivacy'
),
work_time
=>
scalar
$cgi
->
param
(
'work_time'
)
});
}
foreach
my
$field_name
(
@set_fields
)
{
foreach
my
$field_name
(
@set_fields
)
{
if
(
should_set
(
$field_name
))
{
if
(
should_set
(
$field_name
))
{
my
$method
=
$methods
{
$field_name
};
my
$method
=
$methods
{
$field_name
};
...
@@ -480,7 +444,13 @@ if ($action eq Bugzilla->params->{'move-button-text'}) {
...
@@ -480,7 +444,13 @@ if ($action eq Bugzilla->params->{'move-button-text'}) {
foreach
my
$bug
(
@bug_objects
)
{
foreach
my
$bug
(
@bug_objects
)
{
my
(
$status
,
$resolution
)
=
$bug
->
get_new_status_and_resolution
(
'move'
);
my
(
$status
,
$resolution
)
=
$bug
->
get_new_status_and_resolution
(
'move'
);
$bug
->
set_status
(
$status
);
$bug
->
set_status
(
$status
);
$bug
->
set_resolution
(
$resolution
);
# We don't use set_resolution here because the MOVED resolution is
# special and is normally rejected by set_resolution.
$bug
->
{
resolution
}
=
$resolution
;
# That means that we need to clear dups manually. Eventually this
# bug-moving code will all be inside Bugzilla::Bug, so it's OK
# to call an internal function here.
$bug
->
_clear_dup_id
;
}
}
$_
->
update
()
foreach
@bug_objects
;
$_
->
update
()
foreach
@bug_objects
;
$dbh
->
bz_unlock_tables
();
$dbh
->
bz_unlock_tables
();
...
@@ -527,56 +497,34 @@ if ($action eq Bugzilla->params->{'move-button-text'}) {
...
@@ -527,56 +497,34 @@ if ($action eq Bugzilla->params->{'move-button-text'}) {
}
}
if
((
$cgi
->
param
(
'set_default_assignee'
)
||
$cgi
->
param
(
'set_default_qa_contact'
))
# You cannot mark bugs as duplicates when changing several bugs at once
&&
Bugzilla
->
params
->
{
'commentonreassignbycomponent'
}
&&
!
comment_exists
())
# (because currently there is no way to check for duplicate loops in that
{
# situation).
ThrowUserError
(
'comment_required'
);
if
(
!
$cgi
->
param
(
'id'
)
&&
$cgi
->
param
(
'dup_id'
))
{
ThrowUserError
(
'dupe_not_allowed'
);
}
}
my
$duplicate
;
# It will store the ID of the bug we are pointing to, if any.
# Set the status, resolution, and dupe_of (if needed). This has to be done
# down here, because the validity of status changes depends on other fields,
# Make sure the bug status transition is legal for all bugs.
# such as Target Milestone.
my
$knob
=
scalar
$cgi
->
param
(
'knob'
);
foreach
my
$b
(
@bug_objects
)
{
# Special actions (duplicate, change_resolution and clearresolution) are outside
if
(
should_set
(
'knob'
))
{
# the workflow.
# First, get the correct resolution <select>, in case there is more
if
(
!
grep
{
$knob
eq
$_
}
SPECIAL_STATUS_WORKFLOW_ACTIONS
)
{
# than one open -> closed transition allowed.
# Make sure the bug status exists and is active.
my
$knob
=
$cgi
->
param
(
'knob'
);
check_field
(
'bug_status'
,
$knob
);
my
$status
=
new
Bugzilla::
Status
({
name
=>
$knob
});
my
$bug_status
=
new
Bugzilla::
Status
({
name
=>
$knob
});
my
$resolution
;
$_
->
check_status_transition
(
$bug_status
)
foreach
@bug_objects
;
if
(
$status
)
{
$resolution
=
$cgi
->
param
(
'resolution_knob_'
.
$status
->
id
);
# Fill the resolution field with the correct value (e.g. in case the
# workflow allows several open -> closed transitions).
if
(
$bug_status
->
is_open
)
{
$cgi
->
delete
(
'resolution'
);
}
}
else
{
else
{
$cgi
->
param
(
'resolution'
,
$cgi
->
param
(
'resolution_knob_'
.
$bug_status
->
id
)
);
$resolution
=
$cgi
->
param
(
'resolution_knob_change_resolution'
);
}
}
}
elsif
(
$knob
eq
'change_resolution'
)
{
# Fill the resolution field with the correct value.
$cgi
->
param
(
'resolution'
,
$cgi
->
param
(
'resolution_knob_change_resolution'
));
}
else
{
# The resolution field is not in use.
$cgi
->
delete
(
'resolution'
);
}
# The action is a valid one.
# Translate the knob values into new status and resolution values.
trick_taint
(
$knob
);
$b
->
process_knob
(
$knob
,
$resolution
,
scalar
$cgi
->
param
(
'dup_id'
));
# Some information is required for checks.
}
$vars
->
{
comment_exists
}
=
comment_exists
();
}
$vars
->
{
bug_id
}
=
$cgi
->
param
(
'id'
);
$vars
->
{
dup_id
}
=
$cgi
->
param
(
'dup_id'
);
$vars
->
{
resolution
}
=
$cgi
->
param
(
'resolution'
)
||
''
;
Bugzilla::
Bug
->
check_status_change_triggers
(
$knob
,
\
@bug_objects
,
$vars
);
# Some triggers require extra actions.
$duplicate
=
$vars
->
{
dup_id
}
if
(
$knob
eq
'duplicate'
);
$requiremilestone
=
$vars
->
{
requiremilestone
};
# $vars->{DuplicateUserConfirm} is true only if a single bug is being edited.
DuplicateUserConfirm
(
$bug
,
$duplicate
)
if
$vars
->
{
DuplicateUserConfirm
};
my
$any_keyword_changes
;
my
$any_keyword_changes
;
if
(
defined
$cgi
->
param
(
'keywords'
))
{
if
(
defined
$cgi
->
param
(
'keywords'
))
{
...
@@ -627,32 +575,6 @@ foreach my $id (@idlist) {
...
@@ -627,32 +575,6 @@ foreach my $id (@idlist) {
my
$comma
=
$::comma
;
my
$comma
=
$::comma
;
my
$old_bug_obj
=
new
Bugzilla::
Bug
(
$id
);
my
$old_bug_obj
=
new
Bugzilla::
Bug
(
$id
);
my
(
$status
,
$everconfirmed
);
my
$resolution
=
$old_bug_obj
->
resolution
;
# We only care about the resolution field if the user explicitly edits it
# or if he closes the bug.
if
(
$knob
eq
'change_resolution'
||
$cgi
->
param
(
'resolution'
))
{
$resolution
=
$cgi
->
param
(
'resolution'
);
}
(
$status
,
$resolution
,
$everconfirmed
)
=
$old_bug_obj
->
get_new_status_and_resolution
(
$knob
,
$resolution
);
if
(
$status
ne
$old_bug_obj
->
bug_status
)
{
$query
.=
"$comma bug_status = ?"
;
push
(
@bug_values
,
$status
);
$comma
=
','
;
}
if
(
$resolution
ne
$old_bug_obj
->
resolution
)
{
$query
.=
"$comma resolution = ?"
;
push
(
@bug_values
,
$resolution
);
$comma
=
','
;
}
if
(
$everconfirmed
ne
$old_bug_obj
->
everconfirmed
)
{
$query
.=
"$comma everconfirmed = ?"
;
push
(
@bug_values
,
$everconfirmed
);
$comma
=
','
;
}
my
$bug_changed
=
0
;
my
$bug_changed
=
0
;
my
$write
=
"WRITE"
;
# Might want to make a param to control
my
$write
=
"WRITE"
;
# Might want to make a param to control
# whether we do LOW_PRIORITY ...
# whether we do LOW_PRIORITY ...
...
@@ -695,9 +617,6 @@ foreach my $id (@idlist) {
...
@@ -695,9 +617,6 @@ foreach my $id (@idlist) {
$formhash
{
$col
}
=
$cgi
->
param
(
$col
)
if
defined
$cgi
->
param
(
$col
);
$formhash
{
$col
}
=
$cgi
->
param
(
$col
)
if
defined
$cgi
->
param
(
$col
);
$i
++
;
$i
++
;
}
}
# The status and resolution are defined by the workflow.
$formhash
{
'bug_status'
}
=
$status
;
$formhash
{
'resolution'
}
=
$resolution
;
# This hash is required by Bug::check_can_change_field().
# This hash is required by Bug::check_can_change_field().
my
$cgi_hash
=
{
'dontchange'
=>
scalar
$cgi
->
param
(
'dontchange'
)};
my
$cgi_hash
=
{
'dontchange'
=>
scalar
$cgi
->
param
(
'dontchange'
)};
...
@@ -731,15 +650,7 @@ foreach my $id (@idlist) {
...
@@ -731,15 +650,7 @@ foreach my $id (@idlist) {
}
}
my
$new_product
=
$bug_objects
{
$id
}
->
product_obj
;
my
$new_product
=
$bug_objects
{
$id
}
->
product_obj
;
# musthavemilestoneonaccept applies only if at least two
# target milestones are defined for the product.
if
(
$requiremilestone
&&
scalar
(
@
{
$new_product
->
milestones
})
>
1
&&
$bug_objects
{
$id
}
->
target_milestone
eq
$new_product
->
default_milestone
)
{
ThrowUserError
(
"milestone_required"
,
{
bug_id
=>
$id
});
}
if
(
defined
$cgi
->
param
(
'delta_ts'
)
&&
$cgi
->
param
(
'delta_ts'
)
ne
$delta_ts
)
if
(
defined
$cgi
->
param
(
'delta_ts'
)
&&
$cgi
->
param
(
'delta_ts'
)
ne
$delta_ts
)
{
{
(
$vars
->
{
'operations'
})
=
(
$vars
->
{
'operations'
})
=
...
@@ -763,15 +674,6 @@ foreach my $id (@idlist) {
...
@@ -763,15 +674,6 @@ foreach my $id (@idlist) {
exit
;
exit
;
}
}
if
(
$cgi
->
param
(
'comment'
)
||
$cgi
->
param
(
'work_time'
)
||
$duplicate
)
{
my
$type
=
$duplicate
?
CMT_DUPE_OF
:
CMT_NORMAL
;
$bug_objects
{
$id
}
->
add_comment
(
scalar
(
$cgi
->
param
(
'comment'
)),
{
isprivate
=>
scalar
(
$cgi
->
param
(
'commentprivacy'
)),
work_time
=>
scalar
$cgi
->
param
(
'work_time'
),
type
=>
$type
,
extra_data
=>
$duplicate
});
$bug_changed
=
1
;
}
#################################
#################################
# Start Actual Database Updates #
# Start Actual Database Updates #
...
@@ -779,7 +681,25 @@ foreach my $id (@idlist) {
...
@@ -779,7 +681,25 @@ foreach my $id (@idlist) {
$timestamp
=
$dbh
->
selectrow_array
(
q{SELECT NOW()}
);
$timestamp
=
$dbh
->
selectrow_array
(
q{SELECT NOW()}
);
$bug_objects
{
$id
}
->
update
(
$timestamp
);
my
$changes
=
$bug_objects
{
$id
}
->
update
(
$timestamp
);
my
%
notify_deps
;
if
(
$changes
->
{
'bug_status'
})
{
my
(
$old_status
,
$new_status
)
=
@
{
$changes
->
{
'bug_status'
}
};
# If this bug has changed from opened to closed or vice-versa,
# then all of the bugs we block need to be notified.
if
(
is_open_state
(
$old_status
)
ne
is_open_state
(
$new_status
))
{
$notify_deps
{
$_
}
=
1
foreach
(
@
{
$bug_objects
{
$id
}
->
blocked
});
}
# We may have zeroed the remaining time, if we moved into a closed
# status, so we should inform the user about that.
if
(
!
is_open_state
(
$new_status
)
&&
$changes
->
{
'remaining_time'
})
{
$vars
->
{
'message'
}
=
"remaining_time_zeroed"
if
Bugzilla
->
user
->
in_group
(
Bugzilla
->
params
->
{
'timetrackinggroup'
});
}
}
$bug_objects
{
$id
}
->
update_keywords
(
$timestamp
);
$bug_objects
{
$id
}
->
update_keywords
(
$timestamp
);
...
@@ -790,11 +710,6 @@ foreach my $id (@idlist) {
...
@@ -790,11 +710,6 @@ foreach my $id (@idlist) {
$dbh
->
do
(
$query
,
undef
,
@bug_values
);
$dbh
->
do
(
$query
,
undef
,
@bug_values
);
}
}
# Check for duplicates if the bug is [re]open or its resolution is changed.
if
(
$resolution
ne
'DUPLICATE'
)
{
$dbh
->
do
(
q{DELETE FROM duplicates WHERE dupe = ?}
,
undef
,
$id
);
}
my
(
$cc_removed
)
=
$bug_objects
{
$id
}
->
update_cc
(
$timestamp
);
my
(
$cc_removed
)
=
$bug_objects
{
$id
}
->
update_cc
(
$timestamp
);
$cc_removed
=
[
map
{
$_
->
login
}
@$cc_removed
];
$cc_removed
=
[
map
{
$_
->
login
}
@$cc_removed
];
...
@@ -828,7 +743,6 @@ foreach my $id (@idlist) {
...
@@ -828,7 +743,6 @@ foreach my $id (@idlist) {
# $msgs will store emails which have to be sent to voters, if any.
# $msgs will store emails which have to be sent to voters, if any.
my
$msgs
;
my
$msgs
;
my
%
notify_deps
;
foreach
my
$c
(
@editable_bug_fields
)
{
foreach
my
$c
(
@editable_bug_fields
)
{
my
$col
=
$c
;
# We modify it, don't want to modify array
my
$col
=
$c
;
# We modify it, don't want to modify array
...
@@ -844,6 +758,7 @@ foreach my $id (@idlist) {
...
@@ -844,6 +758,7 @@ foreach my $id (@idlist) {
bug_severity short_desc alias
bug_severity short_desc alias
deadline estimated_time remaining_time
deadline estimated_time remaining_time
reporter_accessible cclist_accessible
reporter_accessible cclist_accessible
bug_status resolution
status_whiteboard bug_file_loc)
,
status_whiteboard bug_file_loc)
,
Bugzilla
->
custom_field_names
);
Bugzilla
->
custom_field_names
);
...
@@ -857,14 +772,6 @@ foreach my $id (@idlist) {
...
@@ -857,14 +772,6 @@ foreach my $id (@idlist) {
CheckIfVotedConfirmed
(
$id
,
$whoid
);
CheckIfVotedConfirmed
(
$id
,
$whoid
);
}
}
# If this bug has changed from opened to closed or vice-versa,
# then all of the bugs we block need to be notified.
if
(
$col
eq
'bug_status'
&&
is_open_state
(
$old
)
ne
is_open_state
(
$new
))
{
$notify_deps
{
$_
}
=
1
foreach
(
@
{
$bug_objects
{
$id
}
->
blocked
});
}
LogActivityEntry
(
$id
,
$col
,
$old
,
$new
,
$whoid
,
$timestamp
);
LogActivityEntry
(
$id
,
$col
,
$old
,
$new
,
$whoid
,
$timestamp
);
$bug_changed
=
1
;
$bug_changed
=
1
;
}
}
...
@@ -883,35 +790,6 @@ foreach my $id (@idlist) {
...
@@ -883,35 +790,6 @@ foreach my $id (@idlist) {
MessageToMTA
(
$msg
);
MessageToMTA
(
$msg
);
}
}
if
(
$duplicate
)
{
# If the bug was already marked as a duplicate, remove
# the existing entry.
$dbh
->
do
(
'DELETE FROM duplicates WHERE dupe = ?'
,
undef
,
$cgi
->
param
(
'id'
));
my
$dup
=
new
Bugzilla::
Bug
(
$duplicate
);
my
$reporter
=
$new_bug_obj
->
reporter
;
my
$isoncc
=
$dbh
->
selectrow_array
(
q{SELECT who FROM cc
WHERE bug_id = ? AND who = ?}
,
undef
,
$duplicate
,
$reporter
->
id
);
unless
((
$reporter
->
id
==
$dup
->
reporter
->
id
)
||
$isoncc
||
!
$cgi
->
param
(
'confirm_add_duplicate'
))
{
# The reporter is oblivious to the existence of the original bug
# and is permitted access. Add him to the cc (and record activity).
LogActivityEntry
(
$duplicate
,
"cc"
,
""
,
$reporter
->
name
,
$whoid
,
$timestamp
);
$dbh
->
do
(
q{INSERT INTO cc (who, bug_id) VALUES (?, ?)}
,
undef
,
$reporter
->
id
,
$duplicate
);
}
# Bug 171639 - Duplicate notifications do not need to be private.
$dup
->
add_comment
(
""
,
{
type
=>
CMT_HAS_DUPE
,
extra_data
=>
$new_bug_obj
->
bug_id
});
$dup
->
update
(
$timestamp
);
$dbh
->
do
(
q{INSERT INTO duplicates VALUES (?, ?)}
,
undef
,
$duplicate
,
$cgi
->
param
(
'id'
));
}
# Now all changes to the DB have been made. It's time to email
# Now all changes to the DB have been made. It's time to email
# all concerned users, including the bug itself, but also the
# all concerned users, including the bug itself, but also the
# duplicated bug and dependent bugs, if any.
# duplicated bug and dependent bugs, if any.
...
@@ -930,15 +808,18 @@ foreach my $id (@idlist) {
...
@@ -930,15 +808,18 @@ foreach my $id (@idlist) {
# receive email about the change.
# receive email about the change.
send_results
(
$id
,
$vars
);
send_results
(
$id
,
$vars
);
if
(
$duplicate
)
{
# If the bug was marked as a duplicate, we need to notify users on the
# other bug of any changes to that bug.
my
$new_dup_id
=
$changes
->
{
'dup_id'
}
?
$changes
->
{
'dup_id'
}
->
[
1
]
:
undef
;
if
(
$new_dup_id
)
{
$vars
->
{
'mailrecipients'
}
=
{
'changer'
=>
Bugzilla
->
user
->
login
};
$vars
->
{
'mailrecipients'
}
=
{
'changer'
=>
Bugzilla
->
user
->
login
};
$vars
->
{
'id'
}
=
$
duplicate
;
$vars
->
{
'id'
}
=
$
new_dup_id
;
$vars
->
{
'type'
}
=
"dupe"
;
$vars
->
{
'type'
}
=
"dupe"
;
# Let the user know a duplication notation was added to the
# Let the user know a duplication notation was added to the
# original bug.
# original bug.
send_results
(
$
duplicate
,
$vars
);
send_results
(
$
new_dup_id
,
$vars
);
}
}
my
%
all_dep_changes
=
(
%
notify_deps
,
%
changed_deps
);
my
%
all_dep_changes
=
(
%
notify_deps
,
%
changed_deps
);
...
...
template/en/default/global/code-error.html.tmpl
View file @
620caf68
...
@@ -309,6 +309,10 @@
...
@@ -309,6 +309,10 @@
[% ELSIF error == "need_quipid" %]
[% ELSIF error == "need_quipid" %]
A valid quipid is needed.
A valid quipid is needed.
[% ELSIF error == "no_manual_moved" %]
You cannot set the resolution of [% terms.abug %] to MOVED without
moving the [% terms.bug %].
[% ELSIF error == "param_must_be_numeric" %]
[% ELSIF error == "param_must_be_numeric" %]
[% title = "Invalid Parameter" %]
[% title = "Invalid Parameter" %]
Invalid parameter passed to [% function FILTER html %].
Invalid parameter passed to [% function FILTER html %].
...
...
template/en/default/global/user-error.html.tmpl
View file @
620caf68
...
@@ -252,14 +252,15 @@
...
@@ -252,14 +252,15 @@
[% ELSIF error == "comment_required" %]
[% ELSIF error == "comment_required" %]
[% title = "Comment Required" %]
[% title = "Comment Required" %]
You have to specify a <b>comment</b>
You have to specify a
[% IF old.size && new %]
[% IF old && new %]
to change the [% terms.bug %] status from [% old.join(", ") FILTER html %]
<b>comment</b> when changing the status of [% terms.abug %] from
to [% new FILTER html %].
[%+ old.name FILTER html %] to [% new.name FILTER html %].
[% ELSIF new %]
description for this [% terms.bug %].
[% ELSE %]
[% ELSE %]
on this change.
<b>comment</b>
on this change.
[% END %]
[% END %]
Please explain your change.
[% ELSIF error == "comment_too_long" %]
[% ELSIF error == "comment_too_long" %]
[% title = "Comment Too Long" %]
[% title = "Comment Too Long" %]
...
@@ -346,9 +347,10 @@
...
@@ -346,9 +347,10 @@
[% title = "Dependency Loop Detected" %]
[% title = "Dependency Loop Detected" %]
You can't make [% terms.abug %] block itself or depend on itself.
You can't make [% terms.abug %] block itself or depend on itself.
[% ELSIF error == "description_required" %]
[% ELSIF error == "dupe_id_required" %]
[% title = "Description Required" %]
[% title = "Duplicate Bug Id Required" %]
You must provide a description of the [% terms.bug %].
You must specify [% terms.abug %] id to mark this [% terms.bug %]
as a duplicate of.
[% ELSIF error == "dupe_not_allowed" %]
[% ELSIF error == "dupe_not_allowed" %]
[% title = "Cannot mark $terms.bugs as duplicates" %]
[% title = "Cannot mark $terms.bugs as duplicates" %]
...
@@ -679,8 +681,13 @@
...
@@ -679,8 +681,13 @@
[% ELSIF error == "illegal_bug_status_transition" %]
[% ELSIF error == "illegal_bug_status_transition" %]
[% title = "Illegal $terms.Bug Status Change" %]
[% title = "Illegal $terms.Bug Status Change" %]
[% IF old.defined %]
You are not allowed to change the [% terms.bug %] status from
You are not allowed to change the [% terms.bug %] status from
[%+ old FILTER html %] to [% new FILTER html %].
[%+ old.name FILTER html %] to [% new.name FILTER html %].
[% ELSE %]
You are not allowed to file new [% terms.bugs %] with the
[%+ new.name FILTER html %] status.
[% END %]
[% ELSIF error == "illegal_change" %]
[% ELSIF error == "illegal_change" %]
[% title = "Not allowed" %]
[% title = "Not allowed" %]
...
@@ -940,7 +947,7 @@
...
@@ -940,7 +947,7 @@
[% ELSIF error == "milestone_required" %]
[% ELSIF error == "milestone_required" %]
[% title = "Milestone Required" %]
[% title = "Milestone Required" %]
You must determine a target milestone for [% terms.bug %]
You must determine a target milestone for [% terms.bug %]
[%+ bug
_
id FILTER html %]
[%+ bug
.
id FILTER html %]
if you are going to accept it. Part of accepting
if you are going to accept it. Part of accepting
[%+ terms.abug %] is giving an estimate of when it will be fixed.
[%+ terms.abug %] is giving an estimate of when it will be fixed.
...
@@ -1379,6 +1386,10 @@
...
@@ -1379,6 +1386,10 @@
[% title = "Summary Needed" %]
[% title = "Summary Needed" %]
You must enter a summary for this [% terms.bug %].
You must enter a summary for this [% terms.bug %].
[% ELSIF error == "resolution_cant_clear" %]
[% terms.Bug %] [% bug_id FILTER bug_link(bug_id) FILTER none %] is
closed, so you cannot clear its resolution.
[% ELSIF error == "resolution_not_allowed" %]
[% ELSIF error == "resolution_not_allowed" %]
[% title = "Resolution Not Allowed" %]
[% title = "Resolution Not Allowed" %]
You cannot set a resolution for open [% terms.bugs %].
You cannot set a resolution for open [% terms.bugs %].
...
@@ -1659,5 +1670,7 @@
...
@@ -1659,5 +1670,7 @@
version
version
[% ELSIF class == "Bugzilla::Milestone" %]
[% ELSIF class == "Bugzilla::Milestone" %]
milestone
milestone
[% ELSIF class == "Bugzilla::Status" %]
status
[% END %]
[% END %]
[% END %]
[% END %]
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment