Closed
Bug 302370
Opened 19 years ago
Closed 19 years ago
remove the EmitFormElements routine from editproducts.cgi and templatize that code
Categories
(Bugzilla :: Administration, task)
Bugzilla
Administration
Tracking
()
RESOLVED
FIXED
Bugzilla 2.22
People
(Reporter: timello, Assigned: gabriel.sales)
References
Details
Attachments
(1 file, 5 obsolete files)
25.60 KB,
patch
|
LpSolit
:
review+
|
Details | Diff | Splinter Review |
User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.6) Gecko/20050524 Firefox/1.0 (Ubuntu package 1.0.2 MFSA2005-44) Build Identifier: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.6) Gecko/20050524 Firefox/1.0 (Ubuntu package 1.0.2 MFSA2005-44) This routine is used to action add and edit. We could create a common template file for both. Reproducible: Always Steps to Reproduce:
Updated•19 years ago
|
Assignee: administration → gabriel
Status: UNCONFIRMED → NEW
Ever confirmed: true
Assignee | ||
Comment 1•19 years ago
|
||
Template create-edit.html.tmpl created for add and edit a product. In the edit action, i called a product object and send it to the template.
Attachment #191406 -
Flags: review?(LpSolit)
Comment 2•19 years ago
|
||
Comment on attachment 191406 [details] [diff] [review] v1-emit_form_elements no longer exists The goal of this bug is to remove EmitFormElements from editproducts.cgi *only*. This means: - don't replace $product by $product_name (among others). There is no relation with what we are doing now. We can do that later when moving the code to use Product.pm - adding and editing a product really need two separate templates. The "Block for update fields" section is bigger than the rest of the file, meaning than more than 50% of the script is useless in one case!! This will also give us more flexibility.
Attachment #191406 -
Flags: review?(LpSolit) → review-
Comment 3•19 years ago
|
||
Looking at editproducts.cgi a bit closer, here is what should be done: 1) move EmitFormElements() in its own template, let's say admin/products/edit-common.html.tmpl. 2) create admin/products/create.html.tmpl which contains the code specific to new products. The common template above is called using [% PROCESS "admin/products/edit-common.html.tmpl" %] somewhere from admin/products/create.html.tmpl. 3) create admin/products/edit.html.tmpl which contains the code specific to existing products. The common template is called as above.
Status: NEW → ASSIGNED
Target Milestone: --- → Bugzilla 2.22
Assignee | ||
Comment 4•19 years ago
|
||
I made the templates structure a little bit different, is that good? :-?
Attachment #191406 -
Attachment is obsolete: true
Attachment #193965 -
Flags: review?(LpSolit)
Comment 5•19 years ago
|
||
Comment on attachment 193965 [details] [diff] [review] v2-A different propose >Index: editproducts.cgi >+use Bugzilla::Product; Templatizing EmitFormElements() doesn't require to convert old code to use Product.pm. > if ($action eq 'add') { >+ $vars->{'classification'} = $classification; >+ $vars->{'action'} = 'new'; >+ $template->process("admin/products/edit-common.html.tmpl", >+ $vars) >+ || ThrowTemplateError($template->error()); > exit; > } This is not the right way to go. As I said in my previous comment, admin/products/create.html.tmpl should be called from here, and this template will call admin/products/edit-common.html.tmpl internally. $vars->{'action'} = 'new' really doesn't make sense! Reread my previous comment if required. > if ($action eq 'new') { >- if ($existing_product) { >- >- # Check for exact case sensitive match: >- if ($existing_product eq $product) { >- print "The product '$product' already exists. Please press\n"; >- print "<b>Back</b> and try again.\n"; >- PutTrailer($localtrailer); >- exit; >- } >- >- # Next check for a case-insensitive match: >- if (lc($existing_product) eq lc($product)) { >- print "The new product '$product' differs from existing product "; >- print "'$existing_product' only in case. Please press\n"; >- print "<b>Back</b> and try again.\n"; >- PutTrailer($localtrailer); >- exit; >- } >- } >- >+ # Check for exact case sensitive match: >+ if (lc($existing_product) eq lc($product)) { >+ ThrowUserError('product_already_exists', {'product' => $existing_product}); >+ } There is a good reason to have two separate tests here. So please leave them both! >+ $vars->{'product'} = $product; >+ $vars->{'classhtmlvar'} = $classhtmlvar; >+ $template->process("admin/products/created.html.tmpl", $vars) >+ || ThrowTemplateError($template->error()); 'classhtmlvar' should be banned! Use the existing admin/products/footer.html.tmpl instead (called internally by admin/products/created.html.tmpl). > if ($action eq 'edit' || (!$action && $product)) { >- $template->put_header("Edit product"); >- CheckProduct($product); >- my $classification_id=1; >- if (Param('useclassification')) { The goal if this bug, as already said several times, is to templatize EmitFormElements! Moving old code to new code is definitely *not* the goal of this patch!! Doing so decreases your chances to get a r+ due to the additional bugs or regressions you may introduce. So please leave this code alone for now. >+ $template->process("admin/products/edit-common.html.tmpl", $vars) >+ || ThrowTemplateError($template->error()); > exit; Note that you call the same template as before for two different actions! Re-re-read my previous comment and call admin/products/edit.html.tmpl from here. >Index: template/en/default/admin/products/create.html.tmpl The common part of the code should be in admin/products/edit-common.html.tmpl! >+ [% IF action == 'update' %] >+ [% PROCESS "admin/products/edit.html.tmpl" %] >+ [% END %] >+ >+ [% IF action == 'new' %] This is the kind of tests which doesn't make sense if your templates are correctly written. In other words, remove them. >Index: template/en/default/admin/products/created.html.tmpl >+ <a href="editproducts.cgi?action=add">add</a> a new product, >+ <a href="editcomponents.cgi?action=add&product=[% product FILTER url_quote %][% classhtmlvar FILTER url_quote %]"> As I said, 'classhtmlvar' should die and this template should call admin/products/footer.html.tmpl instead. >Index: template/en/default/admin/products/edit-common.html.tmpl >+[% IF action == 'new' %] >+ [% title = BLOCK %]Add Product[% END %] >+[% ELSE %] >+ [% title = BLOCK %]Edit Product[% END %] >+[% END %] Same comment as above about this kind of tests. >+[% PROCESS "admin/products/create.html.tmpl" %] You use these templates in the wrong way. admin/products/edit-common.html.tmpl should contain the common code for both admin/products/create.html.tmpl and admin/products/edit.html.tmpl and should be called from them. This answer your question: no, your template structure is not good. >Index: template/en/default/admin/products/edit.html.tmpl Previous comments apply here too.
Attachment #193965 -
Flags: review?(LpSolit) → review-
Assignee | ||
Comment 6•19 years ago
|
||
EmitFormElements move to template and ($action edit) database queries changed.
Attachment #193965 -
Attachment is obsolete: true
Attachment #194335 -
Flags: review?(LpSolit)
Comment 7•19 years ago
|
||
Comment on attachment 194335 [details] [diff] [review] v3-changes >Index: editproducts.cgi > if ($action eq 'edit' || (!$action && $product)) { > # get data of product >+ trick_taint($product); Move this detaint right after CheckProduct($product). This way, you don't need to have it twice, once in the "if (Param('useclassification'))" block and a second time here. >+ my $product_data = $dbh->selectrow_hashref(qq{ >+ SELECT products.id, products.name, >+ products.classification_id, products.description, >+ products.milestoneurl, products.disallownew, >+ products.votesperuser, products.maxvotesperbug, >+ products.votestoconfirm, products.defaultmilestone >+ FROM products >+ WHERE name = ?}, undef, $product); Nit: As only the 'products' table is involved, you don't need to repeat it everywhere. Remove these useless 'product.'; this will make the query lighter and easier to read. >+ $vars->{'product'} = $product_data; Also, instead of using an intermediate variable, you could directly write: $vars->{'product'} = $dbh->selectrow_hashref(...); Do the same for other variables. >+ my $components = $dbh->selectall_hashref(qq{ >+ SELECT name, id, description >+ FROM components >+ WHERE product_id = ?}, 'id', undef, ($product_id)); > >+ $vars->{'components'} = [values %$components]; selectall_hashref() is not recommended per the DBI doc itself. Easier is to use selectall_arrayref() and {'Slice' => {}} as %argument: $vars->{'components'} = $dbh->selectall_arrayref('SELECT name, description FROM components WHERE product_id = ?', {'Slice' => {}}, $product_id); This way, you get exactly the same result as what you did, but in a more elegant and maybe more efficient way. ;) >+ my $milestones = $dbh->selectcol_arrayref(q{ >+ SELECT value FROM milestones >+ WHERE product_id = ?}, undef, $product_id); Only check for milestones if Param('usetargetmilestone') is turned on. >+ my $query = qq{SELECT >+ groups.id, groups.name, groups.isactive, >+ group_control_map.entry, >+ group_control_map.membercontrol, >+ group_control_map.othercontrol, >+ group_control_map.canedit >+ FROM groups >+ LEFT JOIN group_control_map >+ ON groups.id = group_control_map.group_id >+ WHERE group_control_map.product_id = ? >+ AND groups.isbuggroup != 0 >+ ORDER BY groups.name}; >+ my $groups = $dbh->selectall_hashref($query, 'id', undef, >+ ($product_id)); Same remark here as for components: use selectall_arrayref() and {'Slice' => {}}. >+ my $constants = { >+ &::CONTROLMAPNA => 'NA', >+ &::CONTROLMAPSHOWN => 'Shown', >+ &::CONTROLMAPDEFAULT => 'Default', >+ &::CONTROLMAPMANDATORY => 'Mandatory'}; &:: is not required anymore as constants have been moved into Constants.pm. >+ >+ foreach my $group (values %$groups) { >+ $group->{'membercontrol'} = >+ $constants->{$group->{'membercontrol'}}; >+ $group->{'othercontrol'} = >+ $constants->{$group->{'othercontrol'}}; > } Hum... I'm not sure this is the right place to do it. You should move it in templates. >+ my $bug_count = $dbh->selectrow_array(qq{ >+ SELECT COUNT(bug_id) FROM bugs >+ WHERE product_id = ?}, undef, $product_id); >+ >+ $vars->{'bug_count'} = $bug_count; Use COUNT(*) instead; this makes the query in the DB faster. And again, don't use this useless intermediate variable. >Index: template/en/default/admin/products/create.html.tmpl >+[%# INTERFACE: >+ # action: string; The page action {new|update}. >+ # classification: string; name of classification. >+ # product: Bugzilla::Product object. >+ # components: array; Bugzilla::Component object(s) >+ # related to product. >+ # groups: array; Bugzilla::Group object(s) related to >+ # product. >+ #%] The only param which is passed to create.html.tmpl is 'classification'. Also, be more explicit: "classification: string; name of the classification in which the new product is created" or something like that. >+[% title = BLOCK %]Add Product[% END %] >+ >+[% PROCESS global/header.html.tmpl >+ title = title >+ h2 = h2 >+%] No need to mention 'h2' as it is not defined. >+<form method="post" action="editproducts.cgi"> >+ <table border="0" cellpadding="4" cellspacing="0"> >+ >+ [% PROCESS "admin/products/edit-common.html.tmpl" %] >+ >+ <tr> >+ <th align="right">Version:</th> >+ <td><input size="64" maxlength="255" name="version" >+ value="[% version FILTER html %]"></td> >+ </tr> Please respect the indentation: <form <table [% PROCESS <tr> <th Also, align (vertically) </td> with <td> when you need more than one line to write it. >+ <th align="right">Create chart datasets for this product:</th> >+ <td><input type="checkbox" name="createseries" value="1"></td> This needs to be enclose in <tr> </tr> tags. >+ <input type="hidden" name="subcategory" value="-All-"> >+ <input type="hidden" name="open_name" value="All Open"> >+ </table> Hidden fields should be moved out of the table, but before </form>. >Index: template/en/default/admin/products/edit-common.html.tmpl >+[%# INTERFACE: >+ # action: string; The page action {new|update}. >+ # classification: string; name of classification. >+ # product: Bugzilla::Product object. >+ # components: array; Bugzilla::Component object(s) >+ # related to product. >+ # groups: array; Bugzilla::Group object(s) related to >+ # product. >+ #%] Please don't say "Bugzilla::Foo object(s)" but "an array of foo objects". Also, only 'classification' and 'product' exist here; remove the other ones. >+[% IF Param('useclassification') %] >+ <tr> >+ <td align="right"><b>Classification:</b></th> Oops... you have a <td> </th> pair instead of <th> </th>. >+ <td><textarea rows="4" cols="64" wrap="virtual" >+ name="description">[% product.description FILTER html >+%]</textarea></td> Let %] on the previous line. >+[% IF Param('usetargetmilestone') -%] >+ <tr> >+ <th align="right">URL describing milestones for this product:</th> >+ <td><input type="text" size="64" maxlength="255" name="milestoneurl" >+ value="[% product.milestoneurl FILTER html %]"></td> >+ </tr> >+ <tr> >+ <th align="right">Default milestone:</th> >+ <td><input type="text" size="20" maxlength="20" name="defaultmilestone" >+ value="[% product.defaultmilestone FILTER html %]"></td> >+ </tr> >+[% END %] Incorrect indentation among <tr> </tr> tags. >+ <th align="right"> >+ Number of votes a [% terms.bug %] in this product needs to "a [% terms.bug %]" has to be "[% terms.abug %]". >Index: template/en/default/admin/products/edit.html.tmpl >+[%# INTERFACE: >+ # action: string; The page action {new|update}. >+ # classification: string; name of classification. >+ # product: Bugzilla::Product object. >+ # components: array; Bugzilla::Component object(s) >+ # related to product. >+ # groups: array; Bugzilla::Group object(s) related to >+ # product. >+ #%] Same comments as before. 'action' doesn't not exist. >+[% title = BLOCK %]Edit Product[% END %] >+ >+[% PROCESS global/header.html.tmpl >+ title = title >+ h2 = h2 >+%] Again, 'h2' is not defined. >+<form method="post" action="editproducts.cgi"> >+ <table border="0" cellpadding="4" cellspacing="0"> >+ >+ [% PROCESS "admin/products/edit-common.html.tmpl" %] >+ >+ <tr> Same problems as before about the indentation. >+ [% IF components.size -%] >+ [% FOREACH component = components %] >+ [% UNLESS loop.first %]<br />[% END %] Wouldn't it be easier to have <br> at the end of the FOREACH loop? This way, you don't need this test (a final <br> is fine). >+ [%- IF versions.size -%] >+ [% FOREACH v = versions %] >+ [% UNLESS loop.first %]<br />[% END %][% v FILTER none %] Same remark here. >+ [%- IF milestones.size -%] >+ [%- FOREACH m = milestones -%] >+ [% UNLESS loop.first %]<br />[% END %][% m FILTER none %] Here again. >+ [% IF groups.size %] >+ [% FOREACH g = groups %] >+ [% UNLESS loop.first %]<br />[% END %] Here again. >+ <input type="hidden" name="productold" value="[% product.name FILTER html >+%]"> >+ <input type="hidden" name="descriptionold" >+ value="[% product.description FILTER html %]"> >+ <input type="hidden" name="milestoneurlold" >+ value="[% product.milestoneurl FILTER html %]"> >+ <input type="hidden" name="disallownewold" >+ value="[% product.disallownew FILTER html %]"> >+ <input type="hidden" name="votesperuserold" >+ value="[% product.votesperuser FILTER html %]"> >+ <input type="hidden" name="maxvotesperbugold" >+ value="[% product.maxvotesperbug FILTER html %]"> >+ <input type="hidden" name="votestoconfirmold" >+ value="[% product.votestoconfirm FILTER html %]"> >+ <input type="hidden" name="defaultmilestoneold" >+ value="[% product.defaultmilestone FILTER html %]"> >+ </table> Move all these hidden fields out of the table, but before </form>. I haven't applied your patch yet, so I may find other bugs. But what I have seen so far looks very good. :)
Attachment #194335 -
Flags: review?(LpSolit) → review-
Assignee | ||
Comment 8•19 years ago
|
||
Fixed version.
Attachment #194335 -
Attachment is obsolete: true
Attachment #194449 -
Flags: review?(LpSolit)
Comment 9•19 years ago
|
||
Comment on attachment 194449 [details] [diff] [review] v3-fix >Index: editproducts.cgi > if ($action eq 'edit' || (!$action && $product)) { >+ $vars->{'product'} = $dbh->selectrow_hashref(qq{ >+ SELECT id, name, classification_id, description, >+ milestoneurl, disallownew, votesperuser, >+ maxvotesperbug, votestoconfirm, defaultmilestone >+ FROM products >+ WHERE name = ?}, undef, $product); Nit: as you already have the product ID, you could query the DB using it instead of its name (that's the way Product.pm will be used here). >+ $vars->{'components'} = $dbh->selectall_arrayref(qq{ >+ SELECT name, description >+ FROM components >+ WHERE product_id = ?}, {'Slice' => {}},$product_id); Please sort components by name => ORDER BY name. >+ $vars->{'versions'} = $dbh->selectcol_arrayref(q{ >+ SELECT value FROM versions >+ WHERE product_id = ?}, undef, $product_id); Sort versions by value. >+ $vars->{'milestones'} = $dbh->selectcol_arrayref(q{ >+ SELECT value >+ FROM milestones >+ WHERE product_id = ?}, >+ undef, $product_id); Sort milestones by sortkey and value. >+ my $query = qq{SELECT >+ groups.id, groups.name, groups.isactive, >+ group_control_map.entry, >+ group_control_map.membercontrol, >+ group_control_map.othercontrol, >+ group_control_map.canedit >+ FROM groups >+ LEFT JOIN group_control_map Should be INNER JOIN. >+ my $constants = { >+ (CONTROLMAPNA) => 'NA', >+ (CONTROLMAPSHOWN) => 'Shown', >+ (CONTROLMAPDEFAULT) => 'Default', >+ (CONTROLMAPMANDATORY) => 'Mandatory'}; $constants is useless if you don't use it. ;) >Index: template/en/default/admin/products/create.html.tmpl >+ Back to the <a href="query.cgi">query page</a> or >+ <a href="editproducts.cgi">edit</a> other products. >+ >+[% PROCESS global/footer.html.tmpl %] Instead of "Back to ....", you should insert [% PROCESS admin/products/footer.html.tmpl %]. >Index: template/en/default/admin/products/edit-common.html.tmpl >+[%# INTERFACE: >+ # classification: string; name of classification product is in. >+ # product: array; an array of objects. >+ #%] An array of which objects?? please be more precise: "an array of product objects". >+ <th align="right"> >+ Number of votes a [% terms.abug %] in this product needs to >+ automatically get out of the "a [% terms.abug %]" will give you "a a bug" :( Moreover, remove this useless >Index: template/en/default/admin/products/edit.html.tmpl >+[%# INTERFACE: >+ # classification: string; name of classification product is in. >+ # product: an array of objects. >+ # components: array; an array of object(s) related to product. >+ # groups: array; an array of objects related to product. >+ #%] Again, describe more precisely what kinds of objects we have: we have product objects, component objects, etc... . Moreover, you forgot to mention version objects, milestone objects as well as bug_count (integer; number of bugs in this product). >+ [% IF Param('usetargetmilestone') %] >+ <tr> >+ <th align="right" valign="top"> >+ <a href="editmilestones.cgi?product=[% product.name FILTER url_quote%]"> Nit: add a whitespace between url_quote and %] >+ [%- FOREACH m = milestones -%] >+ [% m FILTER none %] I'm a bit surprised that we allow unfiltered versions and milestones, but this was already here so don't change it (I just wanted to mention it ;) ). >+ <a href="editproducts.cgi?action=editgroupcontrols&product=[% >+product.name FILTER url_quote%]"> Nit: add a whitespace between url_quote and %] >+ [% FOREACH g = groups %] >+ <b>[% g.name FILTER html %]:</b> >+ [% g.membercontrol FILTER html %]/ >+ [% g.othercontrol FILTER html %] >+ [% IF g.entry %], ENTRY[% END %] >+ [% IF g.canedit %], CANEDIT[% END %] >+ <br> >+ [% END %] Are you sure g.membercontrol and g.othercontrol will be correctly displayed? Moreover, you have to test whether the group is active or not, and display DISABLED if required. >+ <th align="right" valign="top">[% terms.Bugs %]:</th> >+ <td>[% bug_count FILTER html %]</td> Nit: valign="top" is not required here. >+ Back to the <a href="query.cgi">query page</a> or >+ <a href="editproducts.cgi">edit</a> other products. >+ >+[% PROCESS global/footer.html.tmpl %] Here again, you should use admin/products/footer.html.tmpl instead of "Back to...". Your patch is now good enough to be tested. I will test it in a few minutes/hours and I may add some additional comments if I find new bugs. Feel free to update your patch meanwhile. :)
Attachment #194449 -
Flags: review?(LpSolit) → review-
Comment 10•19 years ago
|
||
(In reply to comment #9) > >+ [%- FOREACH m = milestones -%] > >+ [% m FILTER none %] > > I'm a bit surprised that we allow unfiltered versions and milestones, but this > was already here so don't change it (I just wanted to mention it ;) ). One of the fixes we are doing during templatisation is to fix some of the places where we don't currently filter, but we should be, so I think that the version and milestones should be filtered. Basically, the only field which is not filtered is the description (same for component description, keyword description, group description etc.)
Assignee | ||
Comment 11•19 years ago
|
||
New version.
Attachment #194449 -
Attachment is obsolete: true
Attachment #194550 -
Flags: review?(LpSolit)
Assignee | ||
Comment 12•19 years ago
|
||
Some nits fixed
Attachment #194550 -
Attachment is obsolete: true
Attachment #194562 -
Flags: review?(LpSolit)
Updated•19 years ago
|
Attachment #194550 -
Flags: review?(LpSolit)
Comment 13•19 years ago
|
||
Comment on attachment 194562 [details] [diff] [review] v4-fix >Index: template/en/default/admin/products/edit-common.html.tmpl >+ <th align="right">Description:</th> >+ <td><textarea rows="4" cols="64" wrap="virtual" >+ name="description">[% product.description FILTER none %] >+ </textarea></td> Nit: </textarea> should be on the previous line to avoid two leading whitespaces. I will fix that on checkin. Your patch works fine, the code looks good. r=LpSolit
Attachment #194562 -
Flags: review?(LpSolit) → review+
Updated•19 years ago
|
Flags: approval?
Updated•19 years ago
|
Flags: approval? → approval+
Comment 14•19 years ago
|
||
Checking in editproducts.cgi; /cvsroot/mozilla/webtools/bugzilla/editproducts.cgi,v <-- editproducts.cgi new revision: 1.95; previous revision: 1.94 done RCS file: /cvsroot/mozilla/webtools/bugzilla/template/en/default/admin/products/create.html.tmpl,v done Checking in template/en/default/admin/products/create.html.tmpl; /cvsroot/mozilla/webtools/bugzilla/template/en/default/admin/products/create.html.tmpl,v <-- create.html.tmpl initial revision: 1.1 done RCS file: /cvsroot/mozilla/webtools/bugzilla/template/en/default/admin/products/edit-common.html.tmpl,v done Checking in template/en/default/admin/products/edit-common.html.tmpl; /cvsroot/mozilla/webtools/bugzilla/template/en/default/admin/products/edit-common.html.tmpl,v <-- edit-common.html.tmpl initial revision: 1.1 done RCS file: /cvsroot/mozilla/webtools/bugzilla/template/en/default/admin/products/edit.html.tmpl,v done Checking in template/en/default/admin/products/edit.html.tmpl; /cvsroot/mozilla/webtools/bugzilla/template/en/default/admin/products/edit.html.tmpl,v <-- edit.html.tmpl initial revision: 1.1 done
Status: ASSIGNED → RESOLVED
Closed: 19 years ago
Resolution: --- → FIXED
You need to log in
before you can comment on or make changes to this bug.
Description
•