Changeset 928

Show
Ignore:
Timestamp:
03/10/07 23:49:39 (21 months ago)
Author:
kake
Message:

Write tests for and fix bugs #48 and #173; in the process, move preview_node() and edit_node() from wiki.cgi into OpenGuides.pm, and add more functionality to OpenGuides::Test.

Location:
trunk
Files:
9 modified

Legend:

Unmodified
Added
Removed
  • trunk/Build.PL

    r918 r928  
    322322                      "differences.tt", 
    323323                      "display_metadata.tt", 
    324                       "edit_conflict.tt", 
    325324                      "edit_form.tt", 
    326325                      "error.tt", 
  • trunk/Changes

    r919 r928  
    33More detailed changelogs can be found at 
    44http://dev.openguides.org/log/trunk 
     5 
     60.59     
     7        Move preview_node() and edit_node() from wiki.cgi into OpenGuides.pm 
     8        Remove edit_conflict.tt - use edit_form.tt instead to reduce 
     9          duplication. 
     10        Make sure to always pass the config object into the templates. 
     11        Add some extra test utilities to OpenGuides::Test 
     12        Write tests for and fix: 
     13          #48 (Edit conflict page erroneously converts lat/lon to os_x, os_y). 
     14          #173 (edit conflict form doesn't let you edit everything). 
    515 
    6160.58    21 December 2006 
  • trunk/MANIFEST

    r927 r928  
    3939templates/differences.tt 
    4040templates/display_metadata.tt 
    41 templates/edit_conflict.tt 
    4241templates/edit_form.tt 
    4342templates/error.tt 
     
    9594t/40_search_as_feed.t 
    9695t/41_deletion.t 
     96t/42_edit_conflict.t 
    9797t/51_display_node.t 
    9898t/52_display_diffs.t 
  • trunk/README.CSS

    r895 r928  
    2626 
    2727div.warning_text 
    28     Used in: edit_conflict.tt 
     28    Used in: edit_form.tt 
    2929    Purpose: Warns the user that there is an edit conflict 
    3030 
     
    6161span.node_name 
    6262    Used in: backlink_results.tt delete_confirm.tt delete_done.tt 
    63              differences.tt node_history.tt, edit_conflict.tt 
     63             differences.tt node_history.tt 
    6464    Purpose: Inlines a node name in a snippet of explanatory text, 
    6565             without linking to it. 
    6666 
    6767td.label 
    68     Used in: edit_conflict.tt, edit_form.tt 
     68    Used in: edit_form.tt 
    6969    Purpose: Defines a label for a field 
    7070 
     
    9999div#maincontent 
    100100    Used in: backlink_results.tt, delete_confirm.tt, delete_done.tt, 
    101              delete_password_wrong.tt, edit_conflict.tt, edit_form.tt, 
     101             delete_password_wrong.tt, edit_form.tt, 
    102102             home_node.tt, newpage.tt, node.tt, node_history.tt, preferences.tt, 
    103103             recent_changes.tt, search_results.tt, site_index.tt, 
     
    195195 
    196196input#address 
    197     Used in: edit_conflict.tt, edit_form.tt 
     197    Used in: edit_form.tt 
    198198    Purpose: An input field for the address of the node 
    199199 
     
    203203 
    204204input#fax 
    205     Used in: edit_conflict.tt, edit_form.tt 
     205    Used in: edit_form.tt 
    206206    Purpose: An input field for the fax number of the node 
    207207 
     
    216216 
    217217input#hours 
    218     Used in: edit_conflit.tt, edit_form.tt 
     218    Used in: edit_form.tt 
    219219    Purpose: An input field for the opening hours of a node 
    220220     
     
    225225 
    226226input#map_link 
    227     Used in: edit_conflict.tt, edit_form.tt 
     227    Used in: edit_form.tt 
    228228    Purpose: An input field for the map link of the node 
    229229 
     
    238238 
    239239input#os_x 
    240     Used in: edit_conflict.tt, edit_form.tt 
     240    Used in: edit_form.tt 
    241241    Purpose: An input field for the OS X coordinate of the node 
    242242 
    243243input#os_y 
    244     Used in: edit_conflict.tt, edit_form.tt 
     244    Used in: edit_form.tt 
    245245    Purpose: An input field for the OS Y coordinate of the node 
    246246 
     
    250250 
    251251input#phone 
    252     Used in: edit_conflict.tt, edit_form.tt 
     252    Used in: edit_form.tt 
    253253    Purpose: An input field for the telephone number of the node 
    254254 
    255255input#postcode 
    256     Used in: edit_conflict.tt, edit_form.tt 
     256    Used in: edit_form.tt 
    257257    Purpose: An input field for the postcode of the node 
    258258         
     
    284284 
    285285input#website 
    286     Used in: edit_conflict.tt, edit_form.tt 
     286    Used in: edit_form.tt 
    287287    Purpose: An input field for the web site of the node 
    288288 
     
    301301 
    302302textarea#categories 
    303     Used in: edit_conflict.tt, edit_form.tt 
     303    Used in: edit_form.tt 
    304304    Purpose: An box to enter the categories of the node 
    305305 
    306306textarea#content_textarea 
    307     Used in: edit_conflict.tt, edit_form.tt 
     307    Used in: edit_form.tt 
    308308    Purpose: A box to enter the main conent of the node 
    309309    Note: ID doesn't match class, as IDs have to be globally unique, and we 
     
    311311 
    312312textarea#locales 
    313     Used in: edit_conflict.tt, edit_form.tt 
     313    Used in: edit_form.tt 
    314314    Purpose: A box to enter the locales of the node 
    315315 
  • trunk/lib/OpenGuides.pm

    r927 r928  
    318318        return $output if $return_output; 
    319319        print $output; 
     320    } 
     321} 
     322 
     323=item B<display_edit_form> 
     324 
     325  $guide->display_edit_form( 
     326                             id => "Vivat Bacchus", 
     327                           ); 
     328 
     329Display an edit form for the specified node.  As with other methods, the 
     330C<return_output> parameter can be used to return the output instead of 
     331printing it to STDOUT. 
     332 
     333=cut 
     334 
     335sub display_edit_form { 
     336    my ($self, %args) = @_; 
     337    my $return_output = $args{return_output} || 0; 
     338    my $config = $self->config; 
     339    my $wiki = $self->wiki; 
     340    my $node = $args{id}; 
     341    my %node_data = $wiki->retrieve_node($node); 
     342    my ($content, $checksum) = @node_data{ qw( content checksum ) }; 
     343    my %cookie_data = OpenGuides::CGI->get_prefs_from_cookie(config=>$config); 
     344 
     345    my $username = $self->get_cookie( "username" ); 
     346    my $edit_type = $self->get_cookie( "default_edit_type" ) eq "normal" 
     347                        ? "Normal edit" 
     348                        : "Minor tidying"; 
     349 
     350    my %metadata_vars = OpenGuides::Template->extract_metadata_vars( 
     351                             wiki     => $wiki, 
     352                             config   => $config, 
     353                 metadata => $node_data{metadata} ); 
     354 
     355    $metadata_vars{website} ||= 'http://'; 
     356    my $moderate = $wiki->node_required_moderation($node); 
     357 
     358    my %tt_vars = ( content         => CGI->escapeHTML($content), 
     359                    checksum        => CGI->escapeHTML($checksum), 
     360                    %metadata_vars, 
     361                    config          => $config, 
     362                    username        => $username, 
     363                    edit_type       => $edit_type, 
     364                    moderate        => $moderate, 
     365                    deter_robots    => 1, 
     366    ); 
     367 
     368    my $output = $self->process_template( 
     369                                          id            => $node, 
     370                                          template      => "edit_form.tt", 
     371                                          tt_vars       => \%tt_vars, 
     372                                        ); 
     373    return $output if $return_output; 
     374    print $output; 
     375} 
     376 
     377=item B<preview_edit> 
     378 
     379  $guide->display_edit_form( 
     380                             id      => "Vivat Bacchus", 
     381                             cgi_obj => $q, 
     382                           ); 
     383 
     384Preview the edited version of the specified node.  As with other methods, the 
     385C<return_output> parameter can be used to return the output instead of 
     386printing it to STDOUT. 
     387 
     388=cut 
     389 
     390sub preview_edit { 
     391    my ($self, %args) = @_; 
     392    my $node = $args{id}; 
     393    my $q = $args{cgi_obj}; 
     394    my $return_output = $args{return_output}; 
     395    my $wiki = $self->wiki; 
     396    my $config = $self->config; 
     397 
     398    my $content  = $q->param('content'); 
     399    $content     =~ s/\r\n/\n/gs; 
     400    my $checksum = $q->param('checksum'); 
     401 
     402    my %new_metadata = OpenGuides::Template->extract_metadata_vars( 
     403                                               wiki                 => $wiki, 
     404                                               config               => $config, 
     405                                               cgi_obj              => $q, 
     406                                               set_coord_field_vars => 1, 
     407    ); 
     408    foreach my $var ( qw( username comment edit_type ) ) { 
     409        $new_metadata{$var} = $q->escapeHTML($q->param($var)); 
     410    } 
     411 
     412    if ($wiki->verify_checksum($node, $checksum)) { 
     413        my $moderate = $wiki->node_required_moderation($node); 
     414        my %tt_vars = ( 
     415            %new_metadata, 
     416            config                 => $config, 
     417            content                => $q->escapeHTML($content), 
     418            preview_html           => $wiki->format($content), 
     419            preview_above_edit_box => $self->get_cookie( 
     420                                                   "preview_above_edit_box" ), 
     421            checksum               => $q->escapeHTML($checksum), 
     422            moderate               => $moderate 
     423        ); 
     424        my $output = process_template( 
     425                                       id => $node, 
     426                                       template => "edit_form.tt", 
     427                                       tt_vars => \%tt_vars, 
     428                                     ); 
     429        return $output if $args{return_output}; 
     430        print $output; 
     431    } else { 
     432        return $self->_handle_edit_conflict( 
     433                                             id            => $node, 
     434                                             content       => $content, 
     435                                             new_metadata  => \%new_metadata, 
     436                                             return_output => $return_output, 
     437                                           ); 
    320438    } 
    321439} 
     
    10401158    my $checksum = $q->param("checksum"); 
    10411159 
    1042     my %metadata = OpenGuides::Template->extract_metadata_vars( 
     1160    my %new_metadata = OpenGuides::Template->extract_metadata_vars( 
    10431161        wiki    => $wiki, 
    10441162        config  => $config, 
     
    10461164    ); 
    10471165 
    1048     delete $metadata{website} if $metadata{website} eq 'http://'; 
    1049  
    1050     $metadata{opening_hours_text} = $q->param("hours_text") || ""; 
     1166    delete $new_metadata{website} if $new_metadata{website} eq 'http://'; 
     1167 
     1168    $new_metadata{opening_hours_text} = $q->param("hours_text") || ""; 
    10511169 
    10521170    # Pick out the unmunged versions of lat/long if they're set. 
    10531171    # (If they're not, it means they weren't munged in the first place.) 
    1054     $metadata{latitude} = delete $metadata{latitude_unmunged} 
    1055         if $metadata{latitude_unmunged}; 
    1056     $metadata{longitude} = delete $metadata{longitude_unmunged} 
    1057         if $metadata{longitude_unmunged}; 
     1172    $new_metadata{latitude} = delete $new_metadata{latitude_unmunged} 
     1173        if $new_metadata{latitude_unmunged}; 
     1174    $new_metadata{longitude} = delete $new_metadata{longitude_unmunged} 
     1175        if $new_metadata{longitude_unmunged}; 
    10581176 
    10591177    # Check to make sure all the indexable nodes are created 
     
    10631181        $self->_autoCreateCategoryLocale( 
    10641182                                          id       => $node, 
    1065                                           metadata => \%metadata 
     1183                                          metadata => \%new_metadata 
    10661184        ); 
    10671185    } 
    10681186     
    10691187    foreach my $var ( qw( summary username comment edit_type ) ) { 
    1070         $metadata{$var} = $q->param($var) || ""; 
    1071     } 
    1072     $metadata{host} = $ENV{REMOTE_ADDR}; 
     1188        $new_metadata{$var} = $q->param($var) || ""; 
     1189    } 
     1190    $new_metadata{host} = $ENV{REMOTE_ADDR}; 
    10731191 
    10741192    # Wiki::Toolkit::Plugin::RSS::ModWiki wants "major_change" to be set. 
    1075     $metadata{major_change} = ( $metadata{edit_type} eq "Normal edit" ) 
    1076                             ? 1 
    1077                             : 0; 
    1078  
    1079     my $written = $wiki->write_node($node, $content, $checksum, \%metadata ); 
     1193    $new_metadata{major_change} = ( $new_metadata{edit_type} eq "Normal edit" ) 
     1194                                    ? 1 
     1195                                    : 0; 
     1196 
     1197    my $written = $wiki->write_node( $node, $content, $checksum, 
     1198                                     \%new_metadata ); 
    10801199 
    10811200    if ($written) { 
     
    10841203        print $output; 
    10851204    } else { 
    1086         my %node_data = $wiki->retrieve_node($node); 
    1087         my %tt_vars = ( checksum       => $node_data{checksum}, 
    1088                         new_content    => $content, 
    1089                         stored_content => $node_data{content} ); 
    1090         foreach my $mdvar ( keys %metadata ) { 
    1091             if ($mdvar eq "locales") { 
    1092                 $tt_vars{"stored_$mdvar"} = $node_data{metadata}{locale}; 
    1093                 $tt_vars{"new_$mdvar"}    = $metadata{locale}; 
    1094             } elsif ($mdvar eq "categories") { 
    1095                 $tt_vars{"stored_$mdvar"} = $node_data{metadata}{category}; 
    1096                 $tt_vars{"new_$mdvar"}    = $metadata{category}; 
    1097             } elsif ($mdvar eq "username" or $mdvar eq "comment" 
    1098                       or $mdvar eq "edit_type" ) { 
    1099                 $tt_vars{$mdvar} = $metadata{$mdvar}; 
    1100             } else { 
    1101                 $tt_vars{"stored_$mdvar"} = $node_data{metadata}{$mdvar}[0]; 
    1102                 $tt_vars{"new_$mdvar"}    = $metadata{$mdvar}; 
    1103             } 
    1104         } 
    1105         return %tt_vars if $args{return_tt_vars}; 
    1106         my $output = $self->process_template( 
    1107                                               id       => $node, 
    1108                                               template => "edit_conflict.tt", 
    1109                                               tt_vars  => \%tt_vars, 
    1110                                             ); 
    1111         return $output if $args{return_output}; 
    1112         print $output; 
    1113     } 
     1205        return $self->_handle_edit_conflict( 
     1206                                             id            => $node, 
     1207                                             content       => $content, 
     1208                                             new_metadata  => \%new_metadata, 
     1209                                             return_output => $return_output, 
     1210                                           ); 
     1211    } 
     1212} 
     1213 
     1214sub _handle_edit_conflict { 
     1215    my ($self, %args) = @_; 
     1216    my $return_output = $args{return_output} || 0; 
     1217    my $config = $self->config; 
     1218    my $wiki = $self->wiki; 
     1219    my $node = $args{id}; 
     1220    my $content = $args{content}; 
     1221    my %new_metadata = %{$args{new_metadata}}; 
     1222 
     1223    my %node_data = $wiki->retrieve_node($node); 
     1224    my %tt_vars = ( checksum       => $node_data{checksum}, 
     1225                    new_content    => $content, 
     1226                    content        => $node_data{content} ); 
     1227    my %old_metadata = OpenGuides::Template->extract_metadata_vars( 
     1228                                           wiki     => $wiki, 
     1229                                           config   => $config, 
     1230                                           metadata => $node_data{metadata} ); 
     1231    # Make sure we look at all variables. 
     1232    my @tmp = (keys %new_metadata, keys %old_metadata ); 
     1233    my %tmp_hash = map { $_ => 1; } @tmp; 
     1234    my @all_vars = keys %tmp_hash; 
     1235 
     1236    foreach my $mdvar ( keys %new_metadata ) { 
     1237        if ($mdvar eq "locales") { 
     1238            $tt_vars{$mdvar} = $old_metadata{locales}; 
     1239            $tt_vars{"new_$mdvar"} = $new_metadata{locale}; 
     1240        } elsif ($mdvar eq "categories") { 
     1241            $tt_vars{$mdvar} = $old_metadata{categories}; 
     1242            $tt_vars{"new_$mdvar"} = $new_metadata{category}; 
     1243        } elsif ($mdvar eq "username" or $mdvar eq "comment" 
     1244                  or $mdvar eq "edit_type" ) { 
     1245            $tt_vars{$mdvar} = $new_metadata{$mdvar}; 
     1246        } else { 
     1247            $tt_vars{$mdvar} = $old_metadata{$mdvar}; 
     1248            $tt_vars{"new_$mdvar"} = $new_metadata{$mdvar}; 
     1249        } 
     1250    } 
     1251 
     1252    $tt_vars{coord_field_1} = $old_metadata{coord_field_1}; 
     1253    $tt_vars{coord_field_2} = $old_metadata{coord_field_2}; 
     1254    $tt_vars{coord_field_1_value} = $old_metadata{coord_field_1_value}; 
     1255    $tt_vars{coord_field_2_value} = $old_metadata{coord_field_2_value}; 
     1256    $tt_vars{"new_coord_field_1_value"} 
     1257                                = $new_metadata{$old_metadata{coord_field_1}}; 
     1258    $tt_vars{"new_coord_field_2_value"} 
     1259                                = $new_metadata{$old_metadata{coord_field_2}}; 
     1260 
     1261    $tt_vars{conflict} = 1; 
     1262    return %tt_vars if $args{return_tt_vars}; 
     1263    my $output = $self->process_template( 
     1264                                          id       => $node, 
     1265                                          template => "edit_form.tt", 
     1266                                          tt_vars  => \%tt_vars, 
     1267                                        ); 
     1268    return $output if $args{return_output}; 
     1269    print $output; 
    11141270} 
    11151271 
  • trunk/lib/OpenGuides/Template.pm

    r888 r928  
    147147 
    148148    my $tt_vars = { 
     149        config                => $config, 
    149150        site_name             => $config->site_name, 
    150151        cgi_url               => $script_name, 
  • trunk/lib/OpenGuides/Test.pm

    r888 r928  
    9393would come from a CGI form, eg lines in a textarea are separated by C<\r\n>. 
    9494 
     95This method will automatically grab the checksum from the database, so 
     96even if the node already exists your data will still be written.  If you 
     97don't want this behaviour (for example, if you're testing edit conflicts) 
     98then pass in a true value to the C<omit_checksum> parameter: 
     99 
     100  OpenGuides::Test->write_data( 
     101                                guide         => $guide, 
     102                                node          => "Crabtree Tavern", 
     103                                omit_checksum => 1, 
     104                              ); 
     105 
     106If you want to grab the output, pass a true value to C<return_output>: 
     107 
     108  my $output = OpenGuides::Test->write_data( 
     109                                             guide        => $guide, 
     110                                             node         => "Crabtree Tavern", 
     111                                             return_output => 1, 
     112                                           ); 
     113 
     114Similarly, if you pass a true value to C<return_tt_vars>, the return value 
     115will be the variables which would have been passed to the template for output: 
     116 
     117  my %vars = OpenGuides::Test->write_data( 
     118                                             guide        => $guide, 
     119                                             node         => "Crabtree Tavern", 
     120                                             return_tt_vars => 1, 
     121                                           ); 
     122 
    95123=cut 
    96124 
     
    123151     
    124152    # Get the checksum of the current contents if necessary. 
    125     my $wiki = $args{guide}->wiki; 
    126     if ( $wiki->node_exists( $args{node} ) ) { 
    127         my %data = $wiki->retrieve_node( $args{node} ); 
    128         $q->param( -name => "checksum", -value => $data{checksum} ); 
     153    unless ( $args{omit_checksum} ) { 
     154        my $wiki = $args{guide}->wiki; 
     155        if ( $wiki->node_exists( $args{node} ) ) { 
     156            my %data = $wiki->retrieve_node( $args{node} ); 
     157            $q->param( -name => "checksum", -value => $data{checksum} ); 
     158        } 
    129159    } 
    130  
    131     $args{guide}->commit_node( 
    132                                return_output => 1, 
    133                                id => $args{node}, 
    134                                cgi_obj => $q, 
    135                              ); 
     160  
     161    if ( $args{return_output} ) { 
     162        return $args{guide}->commit_node( 
     163                                          return_output => 1, 
     164                                          id => $args{node}, 
     165                                          cgi_obj => $q, 
     166                                        ); 
     167    } elsif ( $args{return_tt_vars} ) { 
     168        return $args{guide}->commit_node( 
     169                                          return_tt_vars => 1, 
     170                                          id => $args{node}, 
     171                                          cgi_obj => $q, 
     172                                        ); 
     173    } else { 
     174        $args{guide}->commit_node( 
     175                                   id => $args{node}, 
     176                                   cgi_obj => $q, 
     177                                 ); 
     178    } 
    136179} 
    137180 
  • trunk/templates/edit_form.tt

    r859 r928  
     1[% USE CGI %] 
    12[% INCLUDE header.tt page_title = "Edit $node_name - $site_name" %] 
    23<div id="content"> 
     
    45<div id="maincontent"> 
    56<h1 align="center">Edit &quot;[% node_name %]&quot;</h1> 
     7 
     8[% IF conflict %] 
     9  <div class="warning_text"> 
     10    Someone has committed changes to this node since you began editing. 
     11    You will need to manually merge your changes into the new version. 
     12  </div> 
     13[% END %] 
    614 
    715[% IF preview_html AND preview_above_edit_box %] 
     
    1523  <table summary="Form for editing page attributes"> 
    1624    <tr> 
    17       <td colspan="2"> 
     25      <td colspan="[% IF conflict %]3[% ELSE %]2[% END %]"> 
    1826        [%# Put the td outside the TRY-CATCH because TT will print everything 
    1927            up to where it gets the error - avoid mismatched tags. %] 
     
    3947    </tr> 
    4048    <tr> 
    41       <td colspan="2" align="center"><a href="[% cgi_url %]?[% node_param %]">(cancel edit)</a></td> 
     49      <td colspan="[% IF conflict %]3[% ELSE %]2[% END %]" align="center"><a href="[% cgi_url %]?[% node_param %]">(cancel edit)</a></td> 
    4250    </tr> 
    4351    <tr> 
    44       <td colspan="2"> 
     52      <td colspan="[% IF conflict %]3[% ELSE %]2[% END %]"> 
    4553        <fieldset> 
    4654          <legend>Main information (required)</legend> 
     
    4957              <td class="label"><label for="content">Content:</label></td> 
    5058              <td><textarea name="content" id="content_textarea" rows="21" cols="70" wrap="virtual">[% content %]</textarea></td> 
     59              [% IF conflict %] 
     60                <td><small>[% CGI.escapeHTML(new_content) %]</small></td> 
     61              [% END %] 
    5162            </tr> 
    5263            <tr> 
     
    5768              <td><textarea name="locales" id="locales" rows="5" cols="70">[% FOREACH locale = locales %][% locale.name %] 
    5869[% END %]</textarea></td> 
     70              [% IF conflict %] 
     71                <td>[% FOREACH locale = new_locales %][% CGI.escapeHTML(locale) %]<br/>[% END %]</td> 
     72              [% END %] 
    5973            </tr> 
    6074            <tr> 
     
    6276              <td><textarea name="categories" id="categories" rows="5" cols="70">[% FOREACH category = categories %][% category.name %] 
    6377[% END %]</textarea></td> 
     78              [% IF conflict %] 
     79                <td>[% FOREACH category = new_categories %][% CGI.escapeHTML(category) %]<br/>[% END %]</td> 
     80              [% END %] 
    6481            </tr> 
    6582          </table> 
     
    7693                [% INCLUDE node_photo_notes.tt %] 
    7794              </td> 
     95              [% IF conflict %] 
     96                <td>[% CGI.escapeHTML(new_node_image) %]</td> 
     97              [% END %] 
    7898            </tr> 
    7999[% END %]