diff options
-rwxr-xr-x | perllib/FixMyStreet/App/Controller/About.pm | 1 | ||||
-rw-r--r-- | perllib/FixMyStreet/App/Controller/Reports.pm | 34 | ||||
-rw-r--r-- | perllib/FixMyStreet/Cobrand/FixMyStreet.pm | 98 | ||||
-rw-r--r-- | t/cobrand/fixmystreet.t | 47 | ||||
-rw-r--r-- | templates/web/fixmystreet.com/about/council-dashboard.html | 60 | ||||
-rw-r--r-- | web/cobrands/fixmystreet.com/fmsforcouncils.scss | 2 |
6 files changed, 231 insertions, 11 deletions
diff --git a/perllib/FixMyStreet/App/Controller/About.pm b/perllib/FixMyStreet/App/Controller/About.pm index 233da25d3..48a5dfffd 100755 --- a/perllib/FixMyStreet/App/Controller/About.pm +++ b/perllib/FixMyStreet/App/Controller/About.pm @@ -23,6 +23,7 @@ sub page : Path("/about") : Args(1) { my $template = $c->forward('find_template'); $c->detach('/page_error_404_not_found', []) unless $template; $c->stash->{template} = $template; + $c->cobrand->call_hook('about_hook'); } sub index : Path("/about") : Args(0) { diff --git a/perllib/FixMyStreet/App/Controller/Reports.pm b/perllib/FixMyStreet/App/Controller/Reports.pm index e19c7628f..b0015acc5 100644 --- a/perllib/FixMyStreet/App/Controller/Reports.pm +++ b/perllib/FixMyStreet/App/Controller/Reports.pm @@ -71,6 +71,7 @@ sub index : Path : Args(0) { my $dashboard = eval { my $data = FixMyStreet->config('TEST_DASHBOARD_DATA'); + # uncoverable branch true unless ($data) { my $fn = '../data/all-reports-dashboard'; if ($c->stash->{body}) { @@ -155,6 +156,7 @@ sub ward : Path : Args(2) { $c->res->redirect($ward); $c->detach; } + $c->cobrand->call_hook('council_dashboard_hook'); $c->go('index'); } @@ -330,17 +332,35 @@ sub body_check : Private { # Oslo/ kommunes sharing a name in Norway return if $c->cobrand->reports_body_check( $c, $q_body ); + my $body = $c->forward('body_find', [ $q_body ]); + if ($body) { + $c->stash->{body} = $body; + return; + } + + # No result, bad body name. + $c->detach( 'redirect_index' ); +} + +=head2 + +Given a string, try and find a body starting with/matching that string. +Returns the matching body object if found. + +=cut + +sub body_find : Private { + my ($self, $c, $q_body) = @_; + # We must now have a string to check my @bodies = $c->model('DB::Body')->search( { name => { -like => "$q_body%" } } )->all; if (@bodies == 1) { - $c->stash->{body} = $bodies[0]; - return; + return $bodies[0]; } else { foreach (@bodies) { if (lc($_->name) eq lc($q_body) || $_->name =~ /^\Q$q_body\E (Borough|City|District|County) Council$/i) { - $c->stash->{body} = $_; - return; + return $_; } } } @@ -353,13 +373,9 @@ sub body_check : Private { if (@translations == 1) { if ( my $body = $c->model('DB::Body')->find( { id => $translations[0]->object_id } ) ) { - $c->stash->{body} = $body; - return; + return $body; } } - - # No result, bad body name. - $c->detach( 'redirect_index' ); } =head2 ward_check diff --git a/perllib/FixMyStreet/Cobrand/FixMyStreet.pm b/perllib/FixMyStreet/Cobrand/FixMyStreet.pm index c50721334..a50a22ff9 100644 --- a/perllib/FixMyStreet/Cobrand/FixMyStreet.pm +++ b/perllib/FixMyStreet/Cobrand/FixMyStreet.pm @@ -1,6 +1,9 @@ package FixMyStreet::Cobrand::FixMyStreet; use base 'FixMyStreet::Cobrand::UK'; +use strict; +use warnings; + use mySociety::Random; use constant COUNCIL_ID_BROMLEY => 2482; @@ -62,5 +65,98 @@ sub extra_contact_validation { return %errors; } -1; +=head2 council_dashboard_hook + +This is for council-specific dashboard pages, which can only be seen by +superusers and logged-in users with an email domain matching a body name. + +=cut + +sub council_dashboard_hook { + my $self = shift; + my $c = $self->{c}; + + unless ( $c->user_exists ) { + $c->res->redirect('/about/council-dashboard'); + $c->detach; + } + + return if $c->user->is_superuser; + + my $body = $c->user->from_body || _user_to_body($c); + if ($body) { + # Matching URL and user's email body + return if $body->id eq $c->stash->{body}->id; + + # Matched /a/ body, redirect to its summary page + $c->stash->{body} = $body; + $c->stash->{wards} = [ { name => 'summary' } ]; + $c->detach('/reports/redirect_body'); + } + + $c->res->redirect('/about/council-dashboard'); +} +sub _user_to_body { + my $c = shift; + my $email = lc $c->user->email; + return _email_to_body($c, $email); +} + +sub _email_to_body { + my ($c, $email) = @_; + my ($domain) = $email =~ m{ @ (.*) \z }x; + + my @data = eval { FixMyStreet->path_to('../data/fixmystreet-councils.csv')->slurp }; + my $body; + foreach (@data) { + chomp; + my ($d, $b) = split /\|/; + if ($d eq $domain) { + $body = $b; + last; + } + } + # If we didn't find a lookup entry, default to the first part of the domain + unless ($body) { + $domain =~ s/\.gov\.uk$//; + $body = ucfirst $domain; + } + + $body = $c->forward('/reports/body_find', [ $body ]); + return $body; +} + +sub about_hook { + my $self = shift; + my $c = $self->{c}; + + if ($c->stash->{template} eq 'about/council-dashboard.html') { + $c->stash->{form_name} = $c->get_param('name') || ''; + $c->stash->{email} = $c->get_param('username') || ''; + if ($c->user_exists) { + my $body = _user_to_body($c); + if ($body) { + $c->stash->{body} = $body; + $c->stash->{wards} = [ { name => 'summary' } ]; + $c->detach('/reports/redirect_body'); + } + } + if (my $email = $c->get_param('username')) { + $email = lc $email; + $email =~ s/\s+//g; + my $body = _email_to_body($c, $email); + if ($body) { + # Send confirmation email (hopefully) + $c->stash->{template} = 'auth/general.html'; + $c->detach('/auth/general'); + } else { + $c->stash->{no_body_found} = 1; + $c->set_param('em', $email); # What the contact form wants + $c->detach('/contact/submit'); + } + } + } +} + +1; diff --git a/t/cobrand/fixmystreet.t b/t/cobrand/fixmystreet.t new file mode 100644 index 000000000..eda93e187 --- /dev/null +++ b/t/cobrand/fixmystreet.t @@ -0,0 +1,47 @@ +use FixMyStreet::Script::UpdateAllReports; + +use FixMyStreet::TestMech; +my $mech = FixMyStreet::TestMech->new; + +my $body = $mech->create_body_ok( 2514, 'Birmingham' ); + +my $data; +FixMyStreet::override_config { + MAPIT_URL => 'http://mapit.uk/', +}, sub { + $data = FixMyStreet::Script::UpdateAllReports::generate_dashboard($body); +}; + +FixMyStreet::override_config { + MAPIT_URL => 'http://mapit.uk/', + TEST_DASHBOARD_DATA => $data, + ALLOWED_COBRANDS => 'fixmystreet', +}, sub { + # Not logged in, redirected + $mech->get_ok('/reports/Birmingham/summary'); + is $mech->uri->path, '/about/council-dashboard'; + + $mech->submit_form_ok({ with_fields => { username => 'someone@somewhere.example.org' }}); + $mech->content_contains('We will be in touch'); + # XXX Check email arrives + + $mech->log_in_ok('someone@somewhere.example.org'); + $mech->get_ok('/reports/Birmingham/summary'); + is $mech->uri->path, '/about/council-dashboard'; + $mech->content_contains('Ending in .gov.uk'); + + $mech->submit_form_ok({ with_fields => { name => 'Someone', username => 'someone@birmingham.gov.uk' }}); + $mech->content_contains('Now check your email'); + # XXX Check email arrives, click link + + $mech->log_in_ok('someone@birmingham.gov.uk'); + # Logged in, redirects + $mech->get_ok('/about/council-dashboard'); + is $mech->uri->path, '/reports/Birmingham/summary'; + $mech->content_contains('Top 5 wards'); + +}; + +END { + done_testing(); +} diff --git a/templates/web/fixmystreet.com/about/council-dashboard.html b/templates/web/fixmystreet.com/about/council-dashboard.html new file mode 100644 index 000000000..7acaee207 --- /dev/null +++ b/templates/web/fixmystreet.com/about/council-dashboard.html @@ -0,0 +1,60 @@ +[% extra_css = BLOCK %] + <link rel="stylesheet" href="[% version('/cobrands/fixmystreet.com/fmsforcouncils.css') %]"> + <link href="https://fonts.googleapis.com/css?family=Rubik:400,500" rel="stylesheet"> +[% END %] + +[% IF no_body_found %] + +[% INCLUDE header.html + title = 'FixMyStreet Professional', bodyclass = 'fullwidthpage' +%] + +<div class="confirmation-header confirmation-header--inbox"> + <h1>Thanks!</h1> + <p>We will be in touch with a confirmation link soon.</p> +</div> + +[% ELSE %] + +[% INCLUDE header.html + title = 'FixMyStreet Professional', bodyclass = 'fms-for-councils fullwidthpage' +%] + +<div class="fixed-container"> + <div class="council-header"> + <h1 class="councils-logo">FixMyStreet Professional</h1> + </div> + <div class="councils-hero"> + <div class="councils-hero__demo-access"> + <p>To access a council-specific version of our main dashboard page, + please provide your name and email below and we'll send you a link.</p> + <form method="post" class="councils-hero__demo-access__form"> + <div class="form-group"> + <label for="demo-name">Name</label> + <span class="required">required</span> + <input type="text" name="name" id="demo-name" required value="[% form_name | html %]"> + </div> + <div class="form-group"> + <label for="demo-email">Contact email</label> + <span class="required">required</span> + <input type="email" name="username" id="demo-email" required value="[% email | html %]"> + <p class="form-note">Ending in .gov.uk, or other official council domain</p> + </div> + <div class="form-group submit-group"> + <input type="hidden" name="r" value="about/council-dashboard"> + <input type="hidden" name="extra.referer" value="[% c.req.headers.referer | html %]"> + <input type="hidden" name="subject" value="Council dashboard request"> + <input type="hidden" name="message" value="Filled in the council dashboard form"> + <input type="hidden" name="recipient" value="bettercities"> + <input type="hidden" name="dest" value="from_council"> + <input type="submit" value="Let me in" class="btn"> + </div> + </form> + </div> + </div> + +</div> + +[% END %] + +[% INCLUDE footer.html %] diff --git a/web/cobrands/fixmystreet.com/fmsforcouncils.scss b/web/cobrands/fixmystreet.com/fmsforcouncils.scss index ee166b8fd..0e7c6a281 100644 --- a/web/cobrands/fixmystreet.com/fmsforcouncils.scss +++ b/web/cobrands/fixmystreet.com/fmsforcouncils.scss @@ -147,7 +147,7 @@ $fms-pink: #E65376; border-radius: 3px; color: #fff; padding: 2em; - margin: 4em auto -4em auto; + margin: 4em auto 4em auto; max-width: 26em; position: relative; z-index: 1; |