Version 3.5.5 and 3.5.6
0. Go to demo, and login as a guest:
http://ifdefined.com/btnet/
1. Create new bug:
Description: TEST change history
Project: DemoProject
Sample custom field: 1
(enter '1' into 'Sample custom field')
Click 'Create' button
2. Now edit bug:
Enter '2' into 'Sample custom field:'
Delete Description, so the validation can work
[NOTE: If you have custom validation, the result will be the same.]
c) Click 'Update' button
Bug is not being saved. Short Description is required.
3. Fix bug edition, so the changes can be saved:
Enter 'TEST change history' into 'Description' field.
Enter '3' into 'Sample custom field:'
Press 'Update' button.
BUG: An untrue entry shows in the change history:
changed Sample custom field from "2" to "3"
Should be: from "1" to "3"
Example:
http://ifdefined.com/btnet/edit_bug.aspx?id=16599
-=====================-
Here is a comment by Piotr Owsiak - The Best .NET Developer (Thanks Piotr!) :-)
Standard fields are saved only during the first request to the site (!IsPostBack) with this code:
// save current values in previous, so that later we can write the audit trail when things change
prev\_short\_desc.Value = \(string\) dr\["short\_desc"\];
prev\_tags.Value = \(string\) dr\["bg\_tags"\];
prev\_project.Value = Convert.ToString\(\(int\)dr\["project"\]\);
prev\_project\_name.Value = Convert.ToString\(dr\["current\_project"\]\);
prev\_org.Value = Convert.ToString\(\(int\)dr\["organization"\]\);
prev\_org\_name.Value = Convert.ToString\(dr\["og\_name"\]\);
prev\_category.Value = Convert.ToString\(\(int\)dr\["category"\]\);
prev\_priority.Value = Convert.ToString\(\(int\)dr\["priority"\]\);
prev\_assigned\_to.Value = Convert.ToString\(\(int\)dr\["assigned\_to\_user"\]\);
prev\_assigned\_to\_username.Value = Convert.ToString\(dr\["assigned\_to\_username"\]\);
prev\_status.Value = Convert.ToString\(\(int\)dr\["status"\]\);
prev\_udf.Value = Convert.ToString\(\(int\)dr\["udf"\]\);
prev\_pcd1.Value = \(string\) dr\["bg\_project\_custom\_dropdown\_value1"\];
prev\_pcd2.Value = \(string\) dr\["bg\_project\_custom\_dropdown\_value2"\];
prev\_pcd3.Value = \(string\) dr\["bg\_project\_custom\_dropdown\_value3"\];
while custom fields are save with this code only on the first requst (!IsPostBack):
foreach \(DataRow drcc in ds\_custom\_cols.Tables\[0\].Rows\)
\{
string column\_name = \(string\)drcc\["name"\];
if \(security.user.dict\_custom\_field\_permission\_level\[column\_name\] \!= Security.PERMISSION\_NONE\)
\{
string val = btnet.Util.format\_db\_value\(dr\[column\_name\]\);
hash\_custom\_cols.Add\(column\_name, val\);
hash\_prev\_custom\_cols.Add\(column\_name, val\);
\}
\}
and with this code on each post back:
// Fetch the values of the custom columns from the Request and stash them in a hash table.
foreach \(DataRow drcc in ds\_custom\_cols.Tables\[0\].Rows\)
\{
string column\_name = \(string\)drcc\["name"\];
if \(security.user.dict\_custom\_field\_permission\_level\[column\_name\] \!= Security.PERMISSION\_NONE\)
\{
if \(permission\_level == Security.PERMISSION\_ALL || id == 0\)
\{
hash\_custom\_cols.Add\(column\_name, Request\[column\_name\]\);
\}
else
\{
hash\_custom\_cols.Add\(column\_name, Request\["prev\_" + column\_name\]\);
\}
hash\_prev\_custom\_cols.Add\(column\_name, Request\["prev\_" + column\_name\]\);
\}
\}
this is possible because hash_custom_cols is stored in inputs on every response with this code:
// create the "Prev" fields for the custom columns so that we
// can create an audit trail of their changes.
foreach \(string column\_name in hash\_custom\_cols.Keys\)
\{
Response.Write \("<input type=hidden name=\"prev\_"\);
Response.Write\(column\_name\);
Response.Write \("\""\);
// output a date field according to the specified format
Response.Write \(" value=\""\);
//modified by CJU on jan 9 2008
Response.Write\(HttpUtility.HtmlEncode\(hash\_custom\_cols\[column\_name\]\)\);
//modified by CJU on jan 9 2008
Response.Write \("\">\n"\);
\}
The problem is that hash_custom_cols is filled in from the last Request when permission_level == Security.PERMISSION_ALL or id == 0
and on the response input with prev_MyCustomField1 will contain not what was in the DB but what has been selected on the pager before request to the server.
This means that in case of validation errors there's a window for this bug to manifest itself via incorrect comments:
"field XXX changed from YYY to ZZZ"
cause YYY is not what was in the DB but what was on the page.
This code saves the "changed from..." message:
do\_update = true;
sql += base\_sql.Replace\(
"$3",
"changed " + column\_name + " from \"" + before.Trim\(\).Replace\("'", "''"\) + "\" to \"" + after.Trim\(\).Replace\("'", "''"\) + "\""\);
hash\_prev\_custom\_cols\[column\_name\] = hash\_custom\_cols\[column\_name\];
I'll look at this tonight. Thanks again guys.
Thanks so much. What direction should the fix take? What do you recommend?
Fixed in version 3.6.1, but there are big changes in edit_bug.aspx, so I might have broken other things....