diff options
-rwxr-xr-x | db/rerun_dbic_loader.pl | 1 | ||||
-rw-r--r-- | perllib/FixMyStreet/App/Controller/Admin.pm | 356 | ||||
-rw-r--r-- | perllib/FixMyStreet/DB/Result/Secret.pm | 21 | ||||
-rw-r--r-- | templates/web/default/admin/council_contacts.html | 89 | ||||
-rw-r--r-- | templates/web/default/admin/council_contacts.txt | 4 | ||||
-rw-r--r-- | templates/web/default/admin/council_edit.html | 62 | ||||
-rw-r--r-- | templates/web/default/report/display.html | 2 |
7 files changed, 366 insertions, 169 deletions
diff --git a/db/rerun_dbic_loader.pl b/db/rerun_dbic_loader.pl index 4437241e8..71efa5db5 100755 --- a/db/rerun_dbic_loader.pl +++ b/db/rerun_dbic_loader.pl @@ -19,7 +19,6 @@ my @tables_to_ignore = ( 'debugdate', # 'flickr_imported', # 'partial_user', # - 'secret', # 'textmystreet', # ); my $exclude = '^(?:' . join( '|', @tables_to_ignore ) . ')$'; diff --git a/perllib/FixMyStreet/App/Controller/Admin.pm b/perllib/FixMyStreet/App/Controller/Admin.pm index fcc55cba0..d2ea69c94 100644 --- a/perllib/FixMyStreet/App/Controller/Admin.pm +++ b/perllib/FixMyStreet/App/Controller/Admin.pm @@ -5,6 +5,7 @@ use namespace::autoclean; BEGIN { extends 'Catalyst::Controller'; } use POSIX qw(strftime strcoll); +use Digest::MD5 qw(md5_hex); =head1 NAME @@ -192,9 +193,162 @@ sub council_list : Path('council_list') : Args(0) { return 1; } + +sub council_contacts : Path('council_contacts') : Args(1) { + my ( $self, $c, $area_id ) = @_; + + my $posted = $c->req->param('posted') || ''; + $c->stash->{area_id} = $area_id; + + $c->forward( 'get_token' ); + + if ( $posted ) { + $c->log->debug( 'posted' ); + $c->forward('update_contacts'); + } + + $c->forward('display_contacts'); + + return 1; +} + +sub update_contacts : Private { + my ( $self, $c ) = @_; + + my $posted = $c->req->param('posted'); + my $editor = $c->req->remote_user || _('*unknown*'); + + if ( $posted eq 'new' ) { + $c->forward('check_token'); + + my $category = $self->trim( $c->req->param( 'category' ) ); + my $email = $self->trim( $c->req->param( 'email' ) ); + + $category = 'Empty property' if $c->cobrand->moniker eq 'emptyhomes'; + + my $contact = $c->model('DB::Contact')->find_or_new( + { + area_id => $c->stash->{area_id}, + category => $category, + } + ); + + $contact->email( $email ); + $contact->confirmed( $c->req->param('confirmed') ? 1 : 0 ); + $contact->deleted( $c->req->param('deleted') ? 1 : 0 ); + $contact->note( $c->req->param('note') ); + $contact->whenedited( \'ms_current_timestamp()' ); + $contact->editor( $editor ); + + if ( $contact->in_storage ) { + $c->stash->{updated} = _('Values updated'); + + # NB: History is automatically stored by a trigger in the database + $contact->update; + } else { + $c->stash->{updated} = _('New category contact added'); + $contact->insert; + } + + } elsif ( $posted eq 'update' ) { + $c->forward('check_token'); + + my @categories = $c->req->param('confirmed'); + + my $contacts = $c->model('DB::Contact')->search( + { + area_id => $c->stash->{area_id}, + category => { -in => \@categories }, + } + ); + + $contacts->update( + { + confirmed => 1, + whenedited => \'ms_current_timestamp()', + note => 'Confirmed', + editor => $editor, + } + ); + + $c->stash->{updated} = _('Values updated'); + } +} + +sub display_contacts : Private { + my ( $self, $c ) = @_; + + $c->forward('setup_council_details'); + + my $area_id = $c->stash->{area_id}; + + my $contacts = $c->model('DB::Contact')->search( + { area_id => $area_id }, + { order_by => ['category'] } + ); + + $c->stash->{contacts} = $contacts; + + if ( $c->req->param('text') == 1 ) { + $c->stash->{template} = 'admin/council_contacts.txt'; + $c->res->content_encoding('text/plain'); + return 1; + } + + return 1; +} + +sub setup_council_details : Private { + my ( $self, $c ) = @_; + + my $area_id = $c->stash->{area_id}; + + my $mapit_data = mySociety::MaPit::call('area', $area_id); + + $c->stash->{council_name} = $mapit_data->{name}; + + my $example_postcode = mySociety::MaPit::call('area/example_postcode', $area_id); + + if ($example_postcode && ! ref $example_postcode) { + $c->stash->{example_pc} = $example_postcode; + } + + return 1; +} + +sub council_edit : Path('council_edit') : Args(2) { + my ( $self, $c, $area_id, $category ) = @_; + + $c->stash->{area_id} = $area_id; + + $c->forward( 'get_token' ); + $c->forward('setup_council_details'); + + my $contact = $c->model('DB::Contact')->search( + { + area_id => $area_id, + category => $category + } + )->first; + + $c->stash->{contact} = $contact; + + my $history = $c->model('DB::ContactsHistory')->search( + { + area_id => $area_id, + category => $category + }, + { + order_by => ['contacts_history_id'] + }, + ); + + $c->stash->{history} = $history; + + return 1; +} + # use Encode; -# use POSIX qw(strftime strcoll); -# use Digest::MD5 qw(md5_hex); # # use Page; # use mySociety::Config; @@ -203,17 +357,32 @@ sub council_list : Path('council_list') : Args(0) { # use mySociety::VotingArea; # use mySociety::Web qw(NewURL ent); # -# =item get_token Q -# -# Generate a token based on user and secret -# -# =cut -# sub get_token { -# my ($q) = @_; -# my $secret = scalar(dbh()->selectrow_array('select secret from secret')); -# my $token = md5_hex(($q->remote_user() . $secret)); -# return $token; -# } +=item get_token + +Generate a token based on user and secret + +=cut +sub get_token : Private { + my ( $self, $c ) = @_; + + my $secret = $c->model('DB::Secret')->search()->first; + + my $token = md5_hex(($c->req->remote_user() . $secret->secret)); + + $c->stash->{token} = $token; + + return 1; +} + +sub check_token : Private { + my ( $self, $c ) = @_; + + if ( $c->req->param('token' ) ne $c->stash->{token} ) { + $c->detach( '/page_error_404_not_found', [ _('The requested URL was not found on this server.') ] ); + } + + return 1; +} # # =item allowed_pages Q # @@ -271,154 +440,6 @@ sub council_list : Path('council_list') : Args(0) { # } # # -# -# # admin_council_contacts CGI AREA_ID -# sub admin_council_contacts ($$) { -# my ($q, $area_id) = @_; -# -# # Submit form -# my $updated = ''; -# my $posted = $q->param('posted') || ''; -# if ($posted eq 'new') { -# return not_found($q) if $q->param('token') ne get_token($q); -# my $email = trim($q->param('email')); -# my $category = trim($q->param('category')); -# $category = 'Empty property' if $q->{site} eq 'emptyhomes'; -# # History is automatically stored by a trigger in the database -# my $update = dbh()->do("update contacts set -# email = ?, -# confirmed = ?, -# deleted = ?, -# editor = ?, -# whenedited = ms_current_timestamp(), -# note = ? -# where area_id = ? -# and category = ? -# ", {}, -# $email, ($q->param('confirmed') ? 1 : 0), -# ($q->param('deleted') ? 1 : 0), -# ($q->remote_user() || _("*unknown*")), $q->param('note'), -# $area_id, $category -# ); -# $updated = $q->p($q->em(_("Values updated"))); -# unless ($update > 0) { -# dbh()->do('insert into contacts -# (area_id, category, email, editor, whenedited, note, confirmed, deleted) -# values -# (?, ?, ?, ?, ms_current_timestamp(), ?, ?, ?)', {}, -# $area_id, $category, $email, -# ($q->remote_user() || _('*unknown*')), $q->param('note'), -# ($q->param('confirmed') ? 1 : 0), ($q->param('deleted') ? 1 : 0) -# ); -# $updated = $q->p($q->em(_("New category contact added"))); -# } -# dbh()->commit(); -# } elsif ($posted eq 'update') { -# return not_found($q) if $q->param('token') ne get_token($q); -# my @cats = $q->param('confirmed'); -# foreach my $cat (@cats) { -# dbh()->do("update contacts set -# confirmed = 't', editor = ?, -# whenedited = ms_current_timestamp(), -# note = 'Confirmed' -# where area_id = ? -# and category = ? -# ", {}, -# ($q->remote_user() || _("*unknown*")), -# $area_id, $cat -# ); -# } -# $updated = $q->p($q->em(_("Values updated"))); -# dbh()->commit(); -# } -# -# my $bci_data = select_all("select * from contacts where area_id = ? order by category", $area_id); -# -# if ($q->param('text')) { -# print $q->header(-type => 'text/plain', -charset => 'utf-8'); -# foreach my $l (@$bci_data) { -# next if $l->{deleted} || !$l->{confirmed}; -# print $l->{category} . "\t" . $l->{email} . "\n"; -# } -# return; -# } -# -# $q->delete_all(); # No need for state! -# -# # Title -# my $mapit_data = mySociety::MaPit::call('area', $area_id); -# my $title = sprintf(_('Council contacts for %s'), $mapit_data->{name}); -# print html_head($q, $title); -# print $q->h1($title); -# print $updated; -# -# # Example postcode, link to list of problem reports -# my $links_html; -# my $example_postcode = mySociety::MaPit::call('area/example_postcode', $area_id); -# if ($example_postcode && ! ref $example_postcode) { -# $links_html .= $q->a({ href => mySociety::Config::get('BASE_URL') . '/?pc=' . $q->escape($example_postcode) }, -# "Example postcode " . $example_postcode) . " | "; -# } -# $links_html .= ' ' . -# $q->a({ href => mySociety::Config::get('BASE_URL') . "/reports?council=" . $area_id }, _(" List all reported problems")); -# $links_html .= ' ' . -# $q->a({ href => NewURL($q, area_id => $area_id, page => 'councilcontacts', text => 1) }, _('Text only version')); -# print $q->p($links_html); -# -# # Display of addresses / update statuses form -# print $q->start_form(-method => 'POST', -action => './'); -# print $q->start_table({border=>1, cellpadding=>2, cellspacing=>0}); -# print $q->Tr({}, $q->th({}, [_("Category"), _("Email"), _("Confirmed"), _("Deleted"), _("Last editor"), _("Note"), _("When edited"), _('Confirm')])); -# foreach my $l (@$bci_data) { -# print $q->Tr($q->td([ -# $q->a({ href => NewURL($q, area_id => $area_id, category => $l->{category}, page => 'counciledit') }, -# $l->{category}), $l->{email}, $l->{confirmed} ? _('Yes') : _('No'), -# $l->{deleted} ? _('Yes') : _('No'), $l->{editor}, ent($l->{note}), -# $l->{whenedited} =~ m/^(.+)\.\d+$/, -# $q->checkbox(-name => 'confirmed', -value => $l->{category}, -label => '') -# ])); -# } -# print $q->end_table(); -# # XXX -# print $q->p( -# $q->hidden('area_id', $area_id), -# $q->hidden('posted', 'update'), -# $q->hidden('token', get_token($q)), -# $q->hidden('page', 'councilcontacts'), -# $q->submit(_('Update statuses')) -# ); -# print $q->end_form(); -# -# # Display form for adding new category -# print $q->h2(_('Add new category')); -# print $q->start_form(-method => 'POST', -action => './'); -# if ($q->{site} ne 'emptyhomes') { -# print $q->p($q->strong(_("Category: ")), -# $q->textfield(-name => "category", -size => 30)); -# } -# print $q->p($q->strong(_("Email: ")), -# $q->textfield(-name => "email", -size => 30)); -# $q->autoEscape(0); -# print $q->p( -# $q->checkbox(-id => 'confirmed', -name => "confirmed", -value => 1, -label => ' ' . $q->label({-for => 'confirmed'}, _('Confirmed'))), -# ' ', -# $q->checkbox(-id => 'deleted', -name => "deleted", -value => 1, -label => ' ' . $q->label({-for => 'deleted'}, _('Deleted'))) -# ); -# $q->autoEscape(1); -# print $q->p($q->strong(_("Note: ")), -# $q->textarea(-name => "note", -rows => 3, -columns=>40)); -# print $q->p( -# $q->hidden('area_id', $area_id), -# $q->hidden('posted', 'new'), -# $q->hidden('token', get_token($q)), -# $q->hidden('page', 'councilcontacts'), -# $q->submit(_('Create category')) -# ); -# print $q->end_form(); -# -# print html_tail($q); -# } -# # # admin_council_edit CGI AREA_ID CATEGORY # sub admin_council_edit ($$$) { # my ($q, $area_id, $category) = @_; @@ -962,12 +983,13 @@ sub council_list : Path('council_list') : Args(0) { # } # Page::do_fastcgi(\&main); # -# sub trim { -# my $e = shift; -# $e =~ s/^\s+//; -# $e =~ s/\s+$//; -# return $e; -# } +sub trim { + my $self = shift; + my $e = shift; + $e =~ s/^\s+//; + $e =~ s/\s+$//; + return $e; +} =head1 AUTHOR diff --git a/perllib/FixMyStreet/DB/Result/Secret.pm b/perllib/FixMyStreet/DB/Result/Secret.pm new file mode 100644 index 000000000..399f0be18 --- /dev/null +++ b/perllib/FixMyStreet/DB/Result/Secret.pm @@ -0,0 +1,21 @@ +package FixMyStreet::DB::Result::Secret; + +# Created by DBIx::Class::Schema::Loader +# DO NOT MODIFY THE FIRST PART OF THIS FILE + +use strict; +use warnings; + +use base 'DBIx::Class::Core'; + +__PACKAGE__->load_components("FilterColumn", "InflateColumn::DateTime"); +__PACKAGE__->table("secret"); +__PACKAGE__->add_columns("secret", { data_type => "text", is_nullable => 0 }); + + +# Created by DBIx::Class::Schema::Loader v0.07010 @ 2011-06-03 12:02:18 +# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:Htl6+DHfHy9l+bjBxAbH6Q + + +# You can replace this text with custom code or comments, and it will be preserved on regeneration +1; diff --git a/templates/web/default/admin/council_contacts.html b/templates/web/default/admin/council_contacts.html new file mode 100644 index 000000000..03b487d9c --- /dev/null +++ b/templates/web/default/admin/council_contacts.html @@ -0,0 +1,89 @@ +[% INCLUDE 'admin/header.html' title=tprintf(loc('Council contacts for %s'), council_name) -%] + +<p> +<em>[% updated %]</em> +</p> + +<p> +[% IF example_pc %] +<a href="[% c.uri_for( '/around', { pc => example_pc } ) %]">[% tprintf( loc('Example postcode %s'), example_pc ) | html %]</a> | +[% END %] +<a href="[% c.uri_for( '/reports', { council => area_id } ) %]">[% loc('List all reported problems' ) %]</a> +<a href="[% c.uri_for( 'council_contacts', area_id, { text => 1 } ) %]">[% loc('Text only version') %]</a> +</p> + +<form method="post" action="[% c.uri_for('council_contacts', area_id ) %]" enctype="application/x-www-form-urlencoded" accept-charset="utf-8"> + + <table cellspacing="0" cellpadding="2" border="1"> + <tr> + <th>Category</th> + <th>Email</th> + <th>Confirmed</th> + <th>Deleted</th> + <th>Last editor</th> + <th>Note</th> + <th>When edited</th> + <th>Confirm</th> + </tr> + [% WHILE ( contact = contacts.next ) %] + <tr> + <td><a href="[% c.uri_for( 'council_edit', area_id, contact.category ) %]">[% contact.category %]</a></td> + <td>[% contact.email | html %]</td> + <td>[% IF contact.confirmed %][% loc('Yes') %][% ELSE %][% loc('No') %][% END %]</td> + <td>[% IF contact.deleted %][% loc('Yes') %][% ELSE %][% loc('No') %][% END %]</td> + <td>[% contact.editor %]</td> + <td>[% contact.note | html %]</td> + <td>[% contact.whenedited.ymd _ ' ' _ contact.whenedited.hms %]</td> + <td><input type="checkbox" name="confirmed" value="[% contact.category %]"></td> + </tr> + [% END %] + </table> + + <p> + <input type="hidden" name="area_id" value="[% area_id %]"> + <input type="hidden" name="posted" value="update"> + <input type="hidden" name="token" value="[% token %]"> + <input type="submit" name="Update statuses" value="Update statuses"> + </p> + </form> + + <h2>Add new category</h2> + + <form method="post" action="[% c.uri_for('council_contacts', area_id ) %]" enctype="application/x-www-form-urlencoded" accept-charset="utf-8"> + + [% IF c.cobrand.moniker != 'emptyhomes' %] + <p> + <strong>Category: </strong><input type="text" name="category" size="30"> + </p> + [% END %] + + <p> + <strong>Email: </strong><input type="text" name="email" size="30"> + </p> + + <p> + <input type="checkbox" name="confirmed" value="1" id="confirmed"> + <label for="confirmed">Confirmed</label> + + <input type="checkbox" name="deleted" value="1"id="deleted"> + <label for="deleted">Deleted</label> + </p> + + <p> + <strong>Note: </strong> <textarea name="note" rows="3" cols="40"></textarea> + </p> + + <p> + <input type="hidden" name="area_id" value="[% area_id %]" > + <input type="hidden" name="posted" value="new" > + <input type="hidden" name="token" value="[% token %]" > + <input type="submit" name="Create category" value="Create category" > + </p> + + <div> + <input type="hidden" name=".cgifields" value="confirmed" > + <input type="hidden" name=".cgifields" value="deleted" > + </div> + </form> + +[% INCLUDE 'admin/footer.html' %] diff --git a/templates/web/default/admin/council_contacts.txt b/templates/web/default/admin/council_contacts.txt new file mode 100644 index 000000000..2d1e04bfa --- /dev/null +++ b/templates/web/default/admin/council_contacts.txt @@ -0,0 +1,4 @@ +[% WHILE ( contact = contacts.next ) -%] +[%- NEXT IF contact.deleted || ! contact.confirmed %] +[% contact.category %] [% contact.email %] +[%- END %] diff --git a/templates/web/default/admin/council_edit.html b/templates/web/default/admin/council_edit.html new file mode 100644 index 000000000..c9ce0e602 --- /dev/null +++ b/templates/web/default/admin/council_edit.html @@ -0,0 +1,62 @@ +[% INCLUDE 'admin/header.html' title=tprintf(loc('Council contacts for %s'), council_name) -%] + +[% BLOCK highlightchanged_yesno %] +[%- output = loc('No') %] +[%- IF new.$value %][% output = loc('Yes') %][% END %] +[%- IF old && old.$value != new.$value %]<strong>[% output %]</strong>[% ELSE %][% output %][% END %] +[%- END %] + +[% BLOCK highlightchanged %] +[%- IF old && old.$value != new.$value %]<strong>[% new.$value %]</strong>[% ELSE %][% new.$value %][% END %] +[%- END %] +<p> +<em>[% updated %]</em> +</p> + +<p> +[% IF example_pc %] +<a href="[% c.uri_for( '/around', { pc => example_pc } ) %]">[% tprintf( loc('Example postcode %s'), example_pc ) | html %]</a> +[% END %] +</p> + +<form method="post" action="[% c.uri_for('council_contacts', area_id ) %]" enctype="application/x-www-form-urlencoded" accept-charset="utf-8"> + <strong>Category: </strong>test + <input type="hidden" name="category" value="[% contact.category | html %]" > + <input type="hidden" name="token" value="[% token %]" >1 + <strong> Email: </strong> + <input type="text" name="email" value="[% contact.email | html %]" size="30"> + <input type="checkbox" name="confirmed" value="1" id="confirmed"[% ' checked' IF contact.confirmed %]> <label for="confirmed">Confirmed</label> + <input type="checkbox" name="deleted" value="1" id="deleted"[% ' checked' IF contact.deleted %]> <label for="deleted">Deleted</label><br> + + <strong>Note: </strong><textarea name="note" rows="3" cols="40">[% contact.note | html %]</textarea> <br> + + <input type="hidden" name="area_id" value="[% area_id %]"> + <input type="hidden" name="posted" value="new"> + <input type="submit" name="Save changes" value="Save changes"> +</form> + +<h2>History</h2> +<table border="1"> + <tr> + <th>When edited</th> + <th>Email</th> + <th>Confirmed</th> + <th>Deleted</th> + <th>Editor</th> + <th>Note</th> + </tr> + [%- prev = '' %] + [%- WHILE ( contact = history.next ) %] + <tr> + <td>[% contact.whenedited.ymd _ ' ' _ contact.whenedited.hms %]</td> + <td>[% PROCESS highlightchanged old=prev new=contact value='email' %]</td> + <td>[% PROCESS highlightchanged_yesno old=prev new=contact value='confirmed' %]</td> + <td>[% PROCESS highlightchanged_yesno old=prev new=contact value='deleted' %]</td> + <td>[% contact.editor %]</td> + <td>[% contact.note | html %]</td> + </tr> + [%- prev = contact %] + [%- END %] +</table> + +[% INCLUDE 'admin/footer.html' %] diff --git a/templates/web/default/report/display.html b/templates/web/default/report/display.html index fdef6c775..4fa58c1db 100644 --- a/templates/web/default/report/display.html +++ b/templates/web/default/report/display.html @@ -44,7 +44,7 @@ <form action="[% c.uri_for( '/alert/subscribe' ) %]" method="post" id="email_alert_box"> <p>[% loc('Receive email when updates are left on this problem.' ) %]</p> <label class="n" for="alert_rznvy">[% loc('Email') %]</label> - <input type="text" name="rznvy" id="alert_rznvy" value="[% email %]" size="30"> + <input type="text" name="rznvy" id="alert_rznvy" value="[% email | html %]" size="30"> <input type="hidden" name="id" value="[% problem.id %]"> <input type="hidden" name="type" value="updates"> <input type="submit" value="[% loc('Subscribe') %]"> |