aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.gitignore3
-rwxr-xr-xbin/comment-backfill21
-rwxr-xr-xbin/fetch-comments15
-rwxr-xr-xbin/kasabi4
-rwxr-xr-xbin/make_css3
-rwxr-xr-xbin/open311-populate-service-list4
-rwxr-xr-xbin/send-comments100
-rwxr-xr-xbin/send-reports747
-rw-r--r--conf/crontab.ugly5
-rw-r--r--conf/general.yml-example3
-rw-r--r--conf/packages.debian-squeeze1
-rw-r--r--conf/packages.debian-squeeze+testing1
-rw-r--r--data/dashboard.json236
-rw-r--r--db/schema.sql16
-rw-r--r--db/schema_0013-add_external_id_to_comment.sql6
-rw-r--r--db/schema_0015-add_extra_to_comment.sql6
-rw-r--r--db/schema_0016-add_whensent_and_send_fail_to_comment.sql11
-rw-r--r--db/schema_0017-add_send_comments_to_open311conf.sql6
-rw-r--r--db/schema_0018-add_comment_user_to_open311conf.sql6
-rw-r--r--db/schema_0019-add_title_to_users.sql8
-rw-r--r--db/schema_0020-add_suppress_alerts_to_open311.sql6
-rw-r--r--perllib/FixMyStreet/App.pm18
-rw-r--r--perllib/FixMyStreet/App/Controller/Admin.pm27
-rw-r--r--perllib/FixMyStreet/App/Controller/Alert.pm9
-rw-r--r--perllib/FixMyStreet/App/Controller/Around.pm3
-rw-r--r--perllib/FixMyStreet/App/Controller/Contact.pm19
-rw-r--r--perllib/FixMyStreet/App/Controller/Dashboard.pm245
-rw-r--r--perllib/FixMyStreet/App/Controller/My.pm2
-rw-r--r--perllib/FixMyStreet/App/Controller/Photo.pm7
-rwxr-xr-xperllib/FixMyStreet/App/Controller/Questionnaire.pm2
-rw-r--r--perllib/FixMyStreet/App/Controller/Report.pm30
-rw-r--r--perllib/FixMyStreet/App/Controller/Report/New.pm40
-rw-r--r--perllib/FixMyStreet/App/Controller/Report/Update.pm37
-rwxr-xr-xperllib/FixMyStreet/App/Controller/Static.pm7
-rw-r--r--perllib/FixMyStreet/App/Controller/Tokens.pm1
-rw-r--r--perllib/FixMyStreet/App/Model/EmailSend.pm2
-rw-r--r--perllib/FixMyStreet/Cobrand.pm18
-rw-r--r--perllib/FixMyStreet/Cobrand/Barnet.pm84
-rw-r--r--perllib/FixMyStreet/Cobrand/Bromley.pm62
-rw-r--r--perllib/FixMyStreet/Cobrand/Default.pm60
-rw-r--r--perllib/FixMyStreet/Cobrand/FixMyStreet.pm49
-rw-r--r--perllib/FixMyStreet/Cobrand/LichfieldDC.pm2
-rw-r--r--perllib/FixMyStreet/Cobrand/UKCouncils.pm31
-rw-r--r--perllib/FixMyStreet/DB/Result/Comment.pm37
-rw-r--r--perllib/FixMyStreet/DB/Result/Open311conf.pm21
-rw-r--r--perllib/FixMyStreet/DB/Result/Problem.pm13
-rw-r--r--perllib/FixMyStreet/DB/Result/User.pm30
-rw-r--r--perllib/FixMyStreet/DB/ResultSet/Problem.pm215
-rw-r--r--perllib/FixMyStreet/DB/ResultSet/Questionnaire.pm3
-rw-r--r--perllib/FixMyStreet/EmailSend.pm12
-rw-r--r--perllib/FixMyStreet/Geocode/Bing.pm12
-rw-r--r--perllib/FixMyStreet/Map/Bromley.pm22
-rw-r--r--perllib/FixMyStreet/Map/FMS.pm21
-rw-r--r--perllib/FixMyStreet/Map/OSM.pm10
-rw-r--r--perllib/FixMyStreet/SendReport.pm45
-rw-r--r--perllib/FixMyStreet/SendReport/Barnet.pm229
-rw-r--r--perllib/FixMyStreet/SendReport/EastHants.pm62
-rw-r--r--perllib/FixMyStreet/SendReport/Email.pm111
-rw-r--r--perllib/FixMyStreet/SendReport/EmptyHomes.pm51
-rw-r--r--perllib/FixMyStreet/SendReport/London.pm113
-rw-r--r--perllib/FixMyStreet/SendReport/Open311.pm133
-rw-r--r--perllib/FixMyStreet/TestMech.pm1
-rw-r--r--perllib/Open311.pm257
-rw-r--r--perllib/Open311/GetServiceRequestUpdates.pm132
-rw-r--r--perllib/Open311/PopulateServiceList.pm43
-rw-r--r--t/app/controller/about.t2
-rw-r--r--t/app/controller/admin.t49
-rw-r--r--t/app/controller/alert_new.t32
-rw-r--r--t/app/controller/dashboard.t639
-rw-r--r--t/app/controller/questionnaire.t132
-rw-r--r--t/app/controller/report_import.t2
-rw-r--r--t/app/controller/report_new.t161
-rw-r--r--t/app/controller/report_updates.t20
-rw-r--r--t/app/controller/reports.t4
-rw-r--r--t/app/model/problem.t130
-rw-r--r--t/app/uri_for.t57
-rw-r--r--t/cobrand/get_council_sender.t30
-rw-r--r--t/open311.t451
-rw-r--r--t/open311/getservicerequestupdates.t537
-rw-r--r--t/open311/populate-service-list.t298
-rw-r--r--templates/email/bromley/questionnaire.txt22
-rw-r--r--templates/email/bromley/signature.txt3
-rw-r--r--templates/email/default/alert-confirm.txt7
-rw-r--r--templates/email/default/alert-problem-area.txt3
-rw-r--r--templates/email/default/alert-problem-council.txt3
-rw-r--r--templates/email/default/alert-problem-nearby.txt3
-rw-r--r--templates/email/default/alert-problem-ward.txt3
-rw-r--r--templates/email/default/alert-problem.txt3
-rw-r--r--templates/email/default/alert-update.txt3
-rw-r--r--templates/email/default/login.txt3
-rw-r--r--templates/email/default/partial.txt3
-rw-r--r--templates/email/default/problem-confirm.txt7
-rw-r--r--templates/email/default/questionnaire.txt3
-rw-r--r--templates/email/default/reply-autoresponse3
-rw-r--r--templates/email/default/signature.txt2
-rw-r--r--templates/email/default/submit-brent.txt5
-rw-r--r--templates/email/default/submit-example.txt2
-rw-r--r--templates/email/default/submit.txt5
-rw-r--r--templates/email/default/update-confirm.txt5
-rwxr-xr-xtemplates/web/barnet/faq/faq-en-gb.html103
-rw-r--r--templates/web/barnet/footer.html45
-rw-r--r--templates/web/barnet/header.html146
-rw-r--r--templates/web/barnet/index.html100
-rw-r--r--templates/web/barnet/report/new/councils_text_all.html4
-rw-r--r--templates/web/barnet/report/updates-sidebar-notes.html1
-rw-r--r--templates/web/bromley/auth/sign_out.html8
-rw-r--r--templates/web/bromley/contact/address.html (renamed from templates/web/fixmystreet/report/new/form_heading.html)0
-rw-r--r--templates/web/bromley/contact/submit.html19
-rwxr-xr-xtemplates/web/bromley/faq/faq-en-gb.html111
-rw-r--r--templates/web/bromley/footer.html43
-rw-r--r--templates/web/bromley/header.html72
-rw-r--r--templates/web/bromley/report/display.html217
-rw-r--r--templates/web/bromley/report/new/fill_in_details_form.html228
-rw-r--r--templates/web/default/admin/council_contacts.html25
-rw-r--r--templates/web/default/admin/report_edit.html1
-rw-r--r--templates/web/default/auth/sign_out.html6
-rw-r--r--templates/web/default/common_header_tags.html3
-rw-r--r--templates/web/default/dashboard/index.html152
-rwxr-xr-xtemplates/web/default/faq/faq-en-gb.html9
-rw-r--r--templates/web/default/index.html2
-rw-r--r--templates/web/default/js/validation_strings.html5
-rw-r--r--templates/web/default/report/new/councils_text_all.html2
-rw-r--r--templates/web/default/report/new/extra_name.html18
-rw-r--r--templates/web/default/report/updates.html10
-rwxr-xr-xtemplates/web/default/reports/council.html40
-rw-r--r--templates/web/default/tokens/confirm_problem.html11
-rw-r--r--templates/web/fixmystreet/alert/_list.html4
-rw-r--r--templates/web/fixmystreet/alert/index.html15
-rw-r--r--templates/web/fixmystreet/alert/list.html1
-rw-r--r--templates/web/fixmystreet/around/around_index.html45
-rwxr-xr-xtemplates/web/fixmystreet/around/display_location.html7
-rwxr-xr-xtemplates/web/fixmystreet/faq/faq-en-gb.html8
-rw-r--r--templates/web/fixmystreet/footer.html2
-rw-r--r--templates/web/fixmystreet/header.html5
-rw-r--r--templates/web/fixmystreet/index.html36
-rw-r--r--templates/web/fixmystreet/report/display.html6
-rw-r--r--templates/web/fixmystreet/report/new/category.html10
-rw-r--r--templates/web/fixmystreet/report/new/councils_text.html9
-rw-r--r--templates/web/fixmystreet/report/new/councils_text_all.html19
-rw-r--r--templates/web/fixmystreet/report/new/councils_text_none.html20
-rw-r--r--templates/web/fixmystreet/report/new/councils_text_some.html28
-rw-r--r--templates/web/fixmystreet/report/new/fill_in_details_form.html12
-rw-r--r--templates/web/fixmystreet/report/new/notes.html2
-rw-r--r--templates/web/fixmystreet/report/new/report_import.html92
-rw-r--r--templates/web/fixmystreet/report/updates-sidebar-notes.html5
-rw-r--r--templates/web/fixmystreet/static/for_councils.html44
-rw-r--r--templates/web/fixmystreet/static/for_councils_faq.html366
-rw-r--r--web/cobrands/barnet/_colours.scss9
-rw-r--r--web/cobrands/barnet/barnet.scss115
-rw-r--r--web/cobrands/barnet/base.scss39
-rw-r--r--web/cobrands/barnet/config.rb25
-rw-r--r--web/cobrands/barnet/img/barnet-footer-logo.gifbin0 -> 5262 bytes
-rw-r--r--web/cobrands/barnet/img/barnet-logo.gifbin0 -> 6372 bytes
-rw-r--r--web/cobrands/barnet/img/barnet-skipnav.pngbin0 -> 799 bytes
-rw-r--r--web/cobrands/barnet/img/bcArrow.gifbin0 -> 3741 bytes
-rw-r--r--web/cobrands/barnet/img/browsealoud.gifbin0 -> 3109 bytes
-rw-r--r--web/cobrands/barnet/img/directgov.gifbin0 -> 3316 bytes
-rw-r--r--web/cobrands/barnet/img/fms-logo.pngbin0 -> 4740 bytes
-rw-r--r--web/cobrands/barnet/img/nav-arrow-active.gifbin0 -> 3831 bytes
-rw-r--r--web/cobrands/barnet/img/nav-bg-active.gifbin0 -> 153 bytes
-rw-r--r--web/cobrands/barnet/img/social1-facebook.gifbin0 -> 499 bytes
-rw-r--r--web/cobrands/barnet/img/social2-twitter.gifbin0 -> 876 bytes
-rw-r--r--web/cobrands/barnet/img/social3-youtube.gifbin0 -> 1017 bytes
-rw-r--r--web/cobrands/barnet/img/social4-flickr.gifbin0 -> 670 bytes
-rw-r--r--web/cobrands/barnet/layout.scss260
-rw-r--r--web/cobrands/barnet/position_map.js25
-rw-r--r--web/cobrands/bromley/_colours.scss5
-rw-r--r--web/cobrands/bromley/base.scss53
-rw-r--r--web/cobrands/bromley/bromley-logo.jpgbin0 -> 20898 bytes
-rw-r--r--web/cobrands/bromley/bromley-logo.s.jpgbin0 -> 5908 bytes
-rw-r--r--web/cobrands/bromley/bromley.scss110
-rw-r--r--web/cobrands/bromley/favicon.icobin0 -> 61798 bytes
-rw-r--r--web/cobrands/bromley/favicon.pngbin0 -> 840 bytes
-rw-r--r--web/cobrands/bromley/fms-logo.pngbin0 -> 4740 bytes
-rw-r--r--web/cobrands/bromley/layout.scss148
-rw-r--r--web/cobrands/bromley/main-menu-hover-home-right.gifbin0 -> 4299 bytes
-rw-r--r--web/cobrands/bromley/main-menu1.gifbin0 -> 12809 bytes
-rw-r--r--web/cobrands/bromley/position_map.js19
-rw-r--r--web/cobrands/bromley/tab-blue.pngbin0 -> 826 bytes
-rw-r--r--web/cobrands/fixmystreet/_base.scss95
-rw-r--r--web/cobrands/fixmystreet/_colours.scss1
-rw-r--r--web/cobrands/fixmystreet/_layout.scss109
-rw-r--r--web/cobrands/fixmystreet/fixmystreet.js231
-rw-r--r--web/cobrands/fixmystreet/position_map.js21
-rw-r--r--web/css/core.scss6
-rw-r--r--web/js/fancybox/jquery.fancybox-1.3.4.js6
-rw-r--r--web/js/fancybox/jquery.fancybox-1.3.4.pack.js6
-rw-r--r--web/js/fixmystreet-old-box.js39
-rw-r--r--web/js/fixmystreet.js171
-rw-r--r--web/js/map-OpenLayers.js71
-rw-r--r--web/js/map-bing-ol.js25
-rw-r--r--web/js/modernizr.custom.76759.js4
-rw-r--r--web/js/modernizr.custom.js4
193 files changed, 7674 insertions, 2208 deletions
diff --git a/.gitignore b/.gitignore
index fca749585..dfb7c786e 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,6 +1,7 @@
*.ttc
/cities_bin
/private_locale
+*~
._*
.DS_Store
.carton
@@ -20,6 +21,8 @@ tags
/web/css/main.css
/web/cobrands/fixmystreet/*.css
/web/cobrands/bromley/*.css
+/web/photo
+/web/cobrands/barnet/*.css
/local
/web/cobrands/fixmystreet/compass_app_log.txt
diff --git a/bin/comment-backfill b/bin/comment-backfill
new file mode 100755
index 000000000..e296d7756
--- /dev/null
+++ b/bin/comment-backfill
@@ -0,0 +1,21 @@
+#!/usr/bin/env perl
+
+use strict;
+use warnings;
+require 5.8.0;
+use DateTime;
+
+use FixMyStreet::App;
+
+use Open311;
+use Open311::GetServiceRequestUpdates;
+
+my $start_time = DateTime->now->subtract( days => 1, hours => 1 );
+my $end_time = DateTime->now;
+
+my $updates = Open311::GetServiceRequestUpdates->new(
+ start_date => $start_time,
+ end_date => $end_time,
+);
+
+$updates->fetch;
diff --git a/bin/fetch-comments b/bin/fetch-comments
new file mode 100755
index 000000000..4bbcc9d21
--- /dev/null
+++ b/bin/fetch-comments
@@ -0,0 +1,15 @@
+#!/usr/bin/env perl
+
+use strict;
+use warnings;
+require 5.8.0;
+
+use FixMyStreet::App;
+
+use Open311;
+use Open311::GetServiceRequestUpdates;
+
+
+my $updates = Open311::GetServiceRequestUpdates->new;
+
+$updates->fetch;
diff --git a/bin/kasabi b/bin/kasabi
index 5b99ba4ff..456b2f4d1 100755
--- a/bin/kasabi
+++ b/bin/kasabi
@@ -63,7 +63,7 @@ def main():
report['detail'] = tidy_string(report['detail'])
report['confirmed'] = report['confirmed'].replace(microsecond=0).isoformat() # Don't want microseconds
report['lastupdate'] = report['lastupdate'].replace(microsecond=0).isoformat()
- report['council'] = sorted(re.sub('\|.*', '', report['council']).split(',')) # Remove missing councils
+ report['council'] = sorted(re.sub('\|.*', '', report['council'] or '').split(',')) # Remove missing councils
# Fetch updates to note state changes
states = [ { 'state': 'confirmed', 'time': report['confirmed'] } ]
@@ -166,6 +166,7 @@ class FixMyStreetChangeSet(object):
# Get info for the councils
council_data = { 'sentTo': '', 'areaNames': [] }
for council in report['council']:
+ if not council: continue
js = json.load(urllib.urlopen('http://mapit.mysociety.org/area/{0}'.format(council)))
os_id = int(js['codes']['unit_id']) + 7000000000000000
if report['whensent']:
@@ -173,6 +174,7 @@ class FixMyStreetChangeSet(object):
council_data['areaNames'].append(js['name'])
council_data.setdefault('firstCouncil', council)
council_data['areaNames'] = ' / '.join(council_data['areaNames'])
+ council_data.setdefault('firstCouncil', '0')
# easting/northing
diff --git a/bin/make_css b/bin/make_css
index 27cbec1b5..22ebddba2 100755
--- a/bin/make_css
+++ b/bin/make_css
@@ -16,9 +16,10 @@ DIRECTORY=$(cd `dirname $0`/../web && pwd)
# FixMyStreet uses compass
compass compile --output-style compressed $DIRECTORY/cobrands/fixmystreet
compass compile --output-style compressed $DIRECTORY/cobrands/bromley
+compass compile --output-style compressed $DIRECTORY/cobrands/barnet
# The rest are plain sass
-for scss in `find $DIRECTORY -name "*.scss" -exec dirname {} \; | uniq | grep -v "cobrands/\(fixmystreet\|bromley\)"`
+for scss in `find $DIRECTORY -name "*.scss" -exec dirname {} \; | uniq | grep -v "cobrands/\(fixmystreet\|bromley\|barnet\)"`
do
sass --scss --update --style compressed $scss
done
diff --git a/bin/open311-populate-service-list b/bin/open311-populate-service-list
index 36e04f5a6..33be61af7 100755
--- a/bin/open311-populate-service-list
+++ b/bin/open311-populate-service-list
@@ -6,7 +6,9 @@ use FixMyStreet::App;
use Open311::PopulateServiceList;
-my $council_list = FixMyStreet::App->model('DB::Open311conf');
+my $council_list = FixMyStreet::App->model('DB::Open311conf')->search( {
+ send_method => 'Open311'
+} );
my $p = Open311::PopulateServiceList->new( council_list => $council_list );
$p->process_councils;
diff --git a/bin/send-comments b/bin/send-comments
new file mode 100755
index 000000000..b1c1463ce
--- /dev/null
+++ b/bin/send-comments
@@ -0,0 +1,100 @@
+#!/usr/bin/env perl
+
+# send-reports:
+# Send new problem reports to councils
+#
+# Copyright (c) 2011 UK Citizens Online Democracy. All rights reserved.
+# Email: matthew@mysociety.org. WWW: http://www.mysociety.org
+
+use strict;
+use warnings;
+require 5.8.0;
+
+use Digest::MD5;
+use Encode;
+use Error qw(:try);
+use CronFns;
+
+use FixMyStreet::App;
+
+use Utils;
+use mySociety::Config;
+use mySociety::EmailUtil;
+
+use Open311;
+
+# maximum number of webservice attempts to send before not trying any more (XXX may be better in config?)
+use constant SEND_FAIL_RETRIES_CUTOFF => 3;
+
+# send_method config values found in by-area config data, for selecting to appropriate method
+use constant SEND_METHOD_EMAIL => 'email';
+use constant SEND_METHOD_OPEN311 => 'Open311';
+
+# Set up site, language etc.
+my ($verbose, $nomail) = CronFns::options();
+my $base_url = mySociety::Config::get('BASE_URL');
+my $site = CronFns::site($base_url);
+
+my $councils = FixMyStreet::App->model('DB::Open311Conf')->search( {
+ send_method => SEND_METHOD_OPEN311,
+ send_comments => 1,
+} );
+
+while ( my $council = $councils->next ) {
+ my $comments = FixMyStreet::App->model('DB::Comment')->search( {
+ 'me.whensent' => undef,
+ 'me.external_id' => undef,
+ 'me.state' => 'confirmed',
+ 'me.confirmed' => { '!=' => undef },
+ 'problem.whensent' => { '!=' => undef },
+ 'problem.external_id' => { '!=' => undef },
+ 'problem.council' => { -like => '%' . $council->area_id .'%' },
+ 'problem.send_method_used' => 'Open311',
+ },
+ {
+ join => 'problem',
+ }
+ );
+
+ my $o = Open311->new(
+ endpoint => $council->endpoint,
+ jurisdiction => $council->jurisdiction,
+ api_key => $council->api_key,
+ );
+
+ while ( my $comment = $comments->next ) {
+ my $cobrand = FixMyStreet::Cobrand->get_class_for_moniker($comment->cobrand)->new();
+
+ if ( $comment->send_fail_count ) {
+ next if bromley_retry_timeout( $comment );
+ }
+
+ my $id = $o->post_service_request_update( $comment );
+
+ if ( $id ) {
+ $comment->update( {
+ external_id => $id,
+ whensent => \'ms_current_timestamp()',
+ } );
+ } else {
+ $comment->update( {
+ send_fail_count => $comment->send_fail_count + 1,
+ send_fail_timestamp => \'ms_current_timestamp()',
+ send_fail_reason => 'Failed to post over Open311',
+ } );
+ }
+ }
+}
+
+sub bromley_retry_timeout {
+ my $row = shift;
+
+ my $tz = DateTime::TimeZone->new( name => 'local' );
+ my $now = DateTime->now( time_zone => $tz );
+ my $diff = $now - $row->send_fail_timestamp;
+ if ( $diff->in_units( 'minutes' ) < 30 ) {
+ return 1;
+ }
+
+ return 0;
+}
diff --git a/bin/send-reports b/bin/send-reports
index 5f3a508b7..16296dc5b 100755
--- a/bin/send-reports
+++ b/bin/send-reports
@@ -10,750 +10,13 @@ use strict;
use warnings;
require 5.8.0;
-use Digest::MD5;
-use Encode;
-use Error qw(:try);
-use JSON;
-use LWP::UserAgent;
-use LWP::Simple;
-use CGI; # Trying awkward kludge
+use CGI; # XXX
use CronFns;
-use FixMyStreet::App;
-
-use EastHantsWSDL;
-use BarnetInterfaces::service::ZLBB_SERVICE_ORDER;
-use Utils;
use mySociety::Config;
-use mySociety::EmailUtil;
-use mySociety::MaPit;
-use mySociety::Web qw(ent);
-
-use Open311;
-
-# maximum number of webservice attempts to send before not trying any more (XXX may be better in config?)
-use constant SEND_FAIL_RETRIES_CUTOFF => 3;
-
-# specific council numbers
-use constant COUNCIL_ID_BARNET => 2489;
-use constant COUNCIL_ID_EAST_HANTS => 2330;
-
-use constant MAX_LINE_LENGTH => 132;
-
-# send_method config values found in by-area config data, for selecting to appropriate method
-use constant SEND_METHOD_EMAIL => 'email';
-use constant SEND_METHOD_OPEN311 => 'open311';
-use constant SEND_METHOD_BARNET => 'barnet';
-use constant SEND_METHOD_EAST_HANTS => 'easthants';
-use constant SEND_METHOD_LONDON => 'london';
-
-# Set up site, language etc.
-my ($verbose, $nomail) = CronFns::options();
-my $base_url = mySociety::Config::get('BASE_URL');
-my $site = CronFns::site($base_url);
-
-my $unsent = FixMyStreet::App->model("DB::Problem")->search( {
- state => [ 'confirmed', 'fixed' ],
- whensent => undef,
- council => { '!=', undef },
-} );
-
-my %sending_skipped_by_method = ();
-
-my (%notgot, %note);
-while (my $row = $unsent->next) {
-
- my $cobrand = FixMyStreet::Cobrand->get_class_for_moniker($row->cobrand)->new();
-
- # Cobranded and non-cobranded messages can share a database. In this case, the conf file
- # should specify a vhost to send the reports for each cobrand, so that they don't get sent
- # more than once if there are multiple vhosts running off the same database. The email_host
- # call checks if this is the host that sends mail for this cobrand.
- next unless $cobrand->email_host();
- $cobrand->set_lang_and_domain($row->lang, 1);
- if ( $row->is_from_abuser ) {
- $row->update( { state => 'hidden' } );
- next;
- }
-
- # Due to multiple councils, it's possible to want to send both by email *and* another method
- # NB: might need to revist this if multiple councils have custom send methods
- my $send_email = 0;
- my $send_method = 0;
-
- # Template variables for the email
- my $email_base_url = $cobrand->base_url_for_emails($row->cobrand_data);
- my %h = map { $_ => $row->$_ } qw/id title detail name category latitude longitude used_map/;
- map { $h{$_} = $row->user->$_ } qw/email phone/;
- $h{confirmed} = DateTime::Format::Pg->format_datetime( $row->confirmed->truncate (to => 'second' ) );
-
- $h{query} = $row->postcode;
- $h{url} = $email_base_url . '/report/' . $row->id;
- $h{phone_line} = $h{phone} ? _('Phone:') . " $h{phone}\n\n" : '';
- if ($row->photo) {
- $h{has_photo} = _("This web page also contains a photo of the problem, provided by the user.") . "\n\n";
- $h{image_url} = $email_base_url . '/photo/' . $row->id . '.full.jpeg';
- } else {
- $h{has_photo} = '';
- $h{image_url} = '';
- }
- $h{fuzzy} = $row->used_map ? _('To view a map of the precise location of this issue')
- : _('The user could not locate the problem on a map, but to see the area around the location they entered');
- $h{closest_address} = '';
-
- # If we are in the UK include eastings and northings, and nearest stuff
- $h{easting_northing} = '';
- if ( $cobrand->country eq 'GB' ) {
-
- ( $h{easting}, $h{northing} ) = Utils::convert_latlon_to_en( $h{latitude}, $h{longitude} );
-
- # email templates don't have conditionals so we need to farmat this here
- $h{easting_northing} #
- = "Easting: $h{easting}\n\n" #
- . "Northing: $h{northing}\n\n";
-
- }
-
- if ( $row->used_map ) {
- $h{closest_address} = $cobrand->find_closest( $h{latitude}, $h{longitude}, $row );
- }
-
- my (@to, @recips, $template, $areas_info, @open311_councils);
- if ($site eq 'emptyhomes') {
-
- my $council = $row->council;
- $areas_info = mySociety::MaPit::call('areas', $council);
- my $name = $areas_info->{$council}->{name};
- my $contact = FixMyStreet::App->model("DB::Contact")->find( {
- deleted => 0,
- area_id => $council,
- category => 'Empty property',
- } );
- my ($council_email, $confirmed, $note) = ( $contact->email, $contact->confirmed, $contact->note );
- unless ($confirmed) {
- $note = 'Council ' . $council . ' deleted' unless $note;
- $council_email = 'N/A' unless $council_email;
- $notgot{$council_email}{$row->category}++;
- $note{$council_email}{$row->category} = $note;
- next;
- }
-
- push @to, [ $council_email, $name ];
- @recips = ($council_email);
- $send_method = 0;
- $send_email = 1;
- $template = Utils::read_file("$FindBin::Bin/../templates/email/emptyhomes/" . $row->lang . "/submit.txt");
-
- } else {
-
- # XXX Needs locks!
- my @all_councils = split /,|\|/, $row->council;
- my ($councils, $missing) = $row->council =~ /^([\d,]+)(?:\|([\d,]+))?/;
- my @councils = split(/,/, $councils);
- $areas_info = mySociety::MaPit::call('areas', \@all_councils);
- my (@dear, %recips);
- my $all_confirmed = 1;
- foreach my $council (@councils) {
- my $name = $areas_info->{$council}->{name};
- push @dear, $name;
-
- # look in the DB to determine if there is a special handler for this council (e.g., open311, or custom)
- my $council_config = FixMyStreet::App->model("DB::Open311conf")->search( { area_id => $council} )->first;
- $send_method = $council_config->send_method if ($council_config and $council_config->send_method);
- if ($council == COUNCIL_ID_EAST_HANTS) { # E. Hants have a web service
- $send_method = SEND_METHOD_EAST_HANTS; # TODO: delete? should be in the db
- $h{category} = 'Customer Services' if $h{category} eq 'Other';
- }
-
- # if council lookup provided no explicit send_method, maybe there's some other criterion for setting it:
- if (! $send_method) {
- if ($areas_info->{$council}->{type} eq 'LBO') { # London
- $send_method = SEND_METHOD_LONDON;
- }
- }
- $send_email = 1 unless $send_method; # default to email if nothing explicit was provided
-
- # currently: open311 or Barnet without an endpoint is useless, so check the endpoint is set
- if ($send_method eq SEND_METHOD_OPEN311 or $send_method eq SEND_METHOD_BARNET) {
- if ($council_config->endpoint) {
- if ($send_method eq SEND_METHOD_OPEN311) {
- push @open311_councils, $council_config;
- }
- } else {
- print "Warning: no endpoint specified in config data for council=$council (will try email instead)\n";
- $send_method = 0;
- $send_email = 1;
- }
- }
-
- if ($send_email) {
- my $contact = FixMyStreet::App->model("DB::Contact")->find( {
- deleted => 0,
- area_id => $council,
- category => $row->category
- } );
- my ($council_email, $confirmed, $note) = ( $contact->email, $contact->confirmed, $contact->note );
- $council_email = essex_contact($row->latitude, $row->longitude) if $council == 2225;
- $council_email = oxfordshire_contact($row->latitude, $row->longitude) if $council == 2237 && $council_email eq 'SPECIAL';
- unless ($confirmed) {
- $all_confirmed = 0;
- $note = 'Council ' . $row->council . ' deleted'
- unless $note;
- $council_email = 'N/A' unless $council_email;
- $notgot{$council_email}{$row->category}++;
- $note{$council_email}{$row->category} = $note;
- }
- push @to, [ $council_email, $name ];
- $recips{$council_email} = 1;
- }
- }
- @recips = keys %recips;
- next unless $all_confirmed;
-
- $template = 'submit.txt';
- $template = 'submit-brent.txt' if $row->council eq 2488 || $row->council eq 2237;
- my $template_path = FixMyStreet->path_to( "templates", "email", $cobrand->moniker, $template )->stringify;
- $template_path = FixMyStreet->path_to( "templates", "email", "default", $template )->stringify
- unless -e $template_path;
- $template = Utils::read_file( $template_path );
-
- if ($h{category} eq _('Other')) {
- $h{category_footer} = _('this type of local problem');
- $h{category_line} = '';
- } else {
- $h{category_footer} = "'" . $h{category} . "'";
- $h{category_line} = sprintf(_("Category: %s"), $h{category}) . "\n\n";
- }
-
- $h{councils_name} = join(_(' and '), @dear);
- if ($h{category} eq _('Other')) {
- $h{multiple} = @dear>1 ? "[ " . _("This email has been sent to both councils covering the location of the problem, as the user did not categorise it; please ignore it if you're not the correct council to deal with the issue, or let us know what category of problem this is so we can add it to our system.") . " ]\n\n"
- : '';
- } else {
- $h{multiple} = @dear>1 ? "[ " . _("This email has been sent to several councils covering the location of the problem, as the category selected is provided for all of them; please ignore it if you're not the correct council to deal with the issue.") . " ]\n\n"
- : '';
- }
- $h{missing} = '';
- if ($missing) {
- my $name = $areas_info->{$missing}->{name};
- $h{missing} = '[ '
- . sprintf(_('We realise this problem might be the responsibility of %s; however, we don\'t currently have any contact details for them. If you know of an appropriate contact address, please do get in touch.'), $name)
- . " ]\n\n";
- }
-
- }
-
- unless ($send_email || $send_method) {
- die 'Report not going anywhere for ID ' . $row->id . '!';
- }
-
- if (mySociety::Config::get('STAGING_SITE')) {
- # on a staging server send emails to ourselves rather than the councils
- # ...webservice calls will only go through if explictly allowed here:
- my @testing_councils = (COUNCIL_ID_BARNET);
- unless (grep {$row->council eq $_} @testing_councils) {
- @recips = ( mySociety::Config::get('CONTACT_EMAIL') );
- $send_method = 0;
- $send_email = 1;
- }
- } elsif ($site eq 'emptyhomes') {
- my $council = $row->council;
- my $country = $areas_info->{$council}->{country};
- if ($country eq 'W') {
- push @recips, 'shelter@' . mySociety::Config::get('EMAIL_DOMAIN');
- } else {
- push @recips, 'eha@' . mySociety::Config::get('EMAIL_DOMAIN');
- }
- }
-
- # Special case for this parish council
- # if ($address && $address =~ /Sprowston/ && $row->council == 2233 && $row->category eq 'Street lighting') {
- # $h{councils_name} = 'Sprowston Parish Council';
- # my $e = 'parishclerk' . '@' . 'sprowston-pc.gov.uk';
- # @to = ( [ $e, $h{councils_name} ] );
- # @recips = ($e);
- # }
-
- # Multiply results together, so one success counts as a success.
- my $result = -1;
-
- if ($send_email) {
- $result *= FixMyStreet::App->send_email_cron(
- {
- _template_ => $template,
- _parameters_ => \%h,
- To => \@to,
- From => [ $row->user->email, $row->name ],
- },
- mySociety::Config::get('CONTACT_EMAIL'),
- \@recips,
- $nomail
- );
- }
-
- if ($send_method eq SEND_METHOD_EAST_HANTS) {
- $h{message} = construct_easthants_message(%h);
- if (!$nomail) {
- $result *= post_easthants_message(%h);
- }
- } elsif ($send_method eq SEND_METHOD_BARNET) {
- $h{message} = construct_barnet_message(%h);
- if (!$nomail) {
- if (my $cutoff_msg = does_exceed_cutoff_limit($row, "barnet")) {
- print "$cutoff_msg\n" if $verbose;
- } else {
- my ($barnet_result, $err_msg) = post_barnet_message( $row, %h );
- update_send_fail_data($row, $err_msg) if $barnet_result;
- $result *= $barnet_result;
- }
- }
- } elsif ($send_method eq SEND_METHOD_LONDON) {
- $h{message} = construct_london_message(%h);
- if (!$nomail) {
- $result *= post_london_report( $row, %h );
- }
- } elsif ($send_method eq SEND_METHOD_OPEN311) {
- foreach my $conf ( @open311_councils ) {
- print 'posting to end point for ' . $conf->area_id . "\n" if $verbose;
-
- my $contact = FixMyStreet::App->model("DB::Contact")->find( {
- deleted => 0,
- area_id => $conf->area_id,
- category => $row->category
- } );
-
- my $open311 = Open311->new(
- jurisdiction => $conf->jurisdiction,
- endpoint => $conf->endpoint,
- api_key => $conf->api_key,
- );
-
- # non standard west berks end points
- if ( $row->council =~ /2619/ ) {
- $open311->endpoints( { services => 'Services', requests => 'Requests' } );
- }
-
- # required to get round issues with CRM constraints
- if ( $row->council =~ /2218/ ) {
- $row->user->name( $row->user->id . ' ' . $row->user->name );
- }
-
- my $resp = $open311->send_service_request( $row, \%h, $contact->email );
-
- # make sure we don't save user changes from above
- if ( $row->council =~ /2218/ ) {
- $row->discard_changes();
- }
-
- if ( $resp ) {
- $row->external_id( $resp );
- $result *= 0;
- } else {
- $result *= 1;
- # temporary fix to resolve some issues with west berks
- if ( $row->council =~ /2619/ ) {
- $result *= 0;
- }
- }
- }
- }
-
- if ($result == mySociety::EmailUtil::EMAIL_SUCCESS) {
- $row->update( {
- whensent => \'ms_current_timestamp()',
- lastupdate => \'ms_current_timestamp()',
- } );
- }
-}
-
-if ($verbose) {
- print "Council email addresses that need checking:\n" if keys %notgot;
- foreach my $e (keys %notgot) {
- foreach my $c (keys %{$notgot{$e}}) {
- print $notgot{$e}{$c} . " problem, to $e category $c (" . $note{$e}{$c}. ")\n";
- }
- }
-}
-
-if ($verbose and keys %sending_skipped_by_method) {
- my $c = 0;
- print "\nProblem reports that send-reports did not attempt to send because retries >= " . SEND_FAIL_RETRIES_CUTOFF . ":\n";
- foreach my $send_method (sort keys %sending_skipped_by_method) {
- printf " %-24s %4d\n", "$send_method:", $sending_skipped_by_method{$send_method};
- $c+=$sending_skipped_by_method{$send_method};
- }
- printf " %-24s %4d\n", "Total:", $c;
-}
-
-sub _get_district_for_contact {
- my ( $lat, $lon ) = @_;
- my $district =
- mySociety::MaPit::call( 'point', "4326/$lon,$lat", type => 'DIS' );
- ($district) = keys %$district;
- return $district;
-}
-
-# Essex has different contact addresses depending upon the district
-# Might be easier if we start storing in the db all areas covered by a point
-# Will do for now :)
-sub essex_contact {
- my $district = _get_district_for_contact(@_);
- my $email;
- $email = 'eastarea' if $district == 2315 || $district == 2312;
- $email = 'midarea' if $district == 2317 || $district == 2314 || $district == 2316;
- $email = 'southarea' if $district == 2319 || $district == 2320 || $district == 2310;
- $email = 'westarea' if $district == 2309 || $district == 2311 || $district == 2318 || $district == 2313;
- die "Returned district $district which is not in Essex!" unless $email;
- return "highways.$email\@essexcc.gov.uk";
-}
-
-# Oxfordshire has different contact addresses depending upon the district
-sub oxfordshire_contact {
- my $district = _get_district_for_contact(@_);
- my $email;
- $email = 'northernarea' if $district == 2419 || $district == 2420 || $district == 2421;
- $email = 'southernarea' if $district == 2417 || $district == 2418;
- die "Returned district $district which is not in Oxfordshire!" unless $email;
- return "$email\@oxfordshire.gov.uk";
-}
-
-# East Hampshire
-
-sub construct_easthants_message {
- my %h = @_;
- my $message = '';
- $message .= "[ This report was also sent to the district council covering the location of the problem, as the user did not categorise it; please ignore if you're not the correct council to deal with the issue. ]\n\n"
- if $h{multiple};
- $message .= <<EOF;
-Subject: $h{title}
-
-Category: $h{category}
-
-Details: $h{detail}
-
-$h{fuzzy}, or to provide an update on the problem, please visit the following link:
-
-$h{url}
-
-$h{closest_address}
-EOF
- return $message;
-}
-
-my $eh_service;
-sub post_easthants_message {
- my %h = @_;
- my $return = 1;
- $eh_service ||= EastHantsWSDL->on_fault(sub { my($soap, $res) = @_; die ref $res ? $res->faultstring : $soap->transport->status, "\n"; });
- try {
- # ServiceName, RemoteCreatedBy, Salutation, FirstName, Name, Email, Telephone, HouseNoName, Street, Town, County, Country, Postcode, Comments, FurtherInfo, ImageURL
- my $message = ent(encode_utf8($h{message}));
- my $name = ent(encode_utf8($h{name}));
- my $result = $eh_service->INPUTFEEDBACK(
- $h{category}, 'FixMyStreet', '', '', $name, $h{email}, $h{phone},
- '', '', '', '', '', '', $message, 'Yes', $h{image_url}
- );
- $return = 0 if $result eq 'Report received';
- } otherwise {
- my $e = shift;
- print "Caught an error: $e\n";
- };
- return $return;
-}
-
-# currently just blind copy of construct_easthants_message
-sub construct_barnet_message {
- my %h = @_;
- my $message = <<EOF;
-Subject: $h{title}
-
-Details: $h{detail}
-
-$h{fuzzy}, or to provide an update on the problem, please visit the following link:
-
-$h{url}
-
-$h{closest_address}
-EOF
-}
-
-sub post_barnet_message {
- my ( $problem, %h ) = @_;
- my $return = 1;
- my $err_msg = "";
-
- my $default_kbid = 14; # This is the default, "Street Scene"
- my $kbid = sprintf( "%050d", Utils::barnet_categories()->{$h{category}} || $default_kbid);
-
- my $geo_code = "$h{easting} $h{northing}";
-
- my $interface = BarnetInterfaces::service::ZLBB_SERVICE_ORDER->new();
-
- my ($nearest_postcode, $nearest_street) = ('', '');
- for ($h{closest_address}) {
- $nearest_postcode = sprintf("%-10s", $1) if /Nearest postcode [^:]+: ((\w{1,4}\s?\w+|\w+))/;
- # use partial postcode or comma as delimiter, strip leading number (possible letter 221B) off too
- # "99 Foo Street, London N11 1XX" becomes Foo Street
- # "99 Foo Street N11 1XX" becomes Foo Street
- $nearest_street = $1 if /Nearest road [^:]+: (?:\d+\w? )?(.*?)(\b[A-Z]+\d|,|$)/m;
- }
- my $postcode = mySociety::PostcodeUtil::is_valid_postcode($h{query})
- ? $h{query} : $nearest_postcode; # use given postcode if available
-
- # note: endpoint can be of form 'https://username:password@url'
- my $council_config = FixMyStreet::App->model("DB::Open311conf")->search( { area_id => COUNCIL_ID_BARNET} )->first;
- if ($council_config and $council_config->endpoint) {
- $interface->set_proxy($council_config->endpoint);
- # Barnet web service doesn't like namespaces in the elements so use a prefix
- $interface->set_prefix('urn');
- } else {
- die "Barnet webservice FAIL: looks like you're missing some config data: no endpoint (URL) found for area_id=" . COUNCIL_ID_BARNET;
- }
-
- eval {
- my $result = $interface->Z_CRM_SERVICE_ORDER_CREATE( {
- ET_RETURN => { # ignored by server
- item => {
- TYPE => "", ID => "", NUMBER => "", MESSAGE => "", LOG_NO => "", LOG_MSG_NO => "",
- MESSAGE_V1 => "", MESSAGE_V2 => "", MESSAGE_V3 => "", MESSAGE_V4 => "", PARAMETER => "",
- ROW => "", FIELD => "", SYSTEM => "",
- },
- },
- IT_PROBLEM_DESC => { # MyTypes::TABLE_OF_CRMT_SERVICE_REQUEST_TEXT
- item => [ # MyTypes::CRMT_SERVICE_REQUEST_TEXT
- map { { TEXT_LINE => $_ } } split_text_with_entities(ent(encode_utf8($h{message})), 132) # char132
- ],
- },
- IV_CUST_EMAIL => truncate_string_with_entities(ent(encode_utf8($h{email})), 241), # char241
- IV_CUST_NAME => truncate_string_with_entities(ent(encode_utf8($h{name})), 50), # char50
- IV_KBID => $kbid, # char50
- IV_PROBLEM_ID => $h{id}, # char35
- IV_PROBLEM_LOC => { # MyTypes::BAPI_TTET_ADDRESS_COM
- COUNTRY2 => 'GB', # char2
- REGION => "", # char3
- COUNTY => "", # char30
- CITY => "", # char30
- POSTALCODE => $postcode, # char10
- STREET => truncate_string_with_entities(ent(encode_utf8($nearest_street)), 30), # char30
- STREETNUMBER => "", # char5
- GEOCODE => $geo_code, # char32
- },
- IV_PROBLEM_SUB => truncate_string_with_entities(ent(encode_utf8($h{title})), 40), # char40
- },
- );
- if ($result) {
- # currently not using this: get_EV_ORDER_GUID (maybe that's the customer number in the CRM)
- if (my $barnet_id = $result->get_EV_ORDER_NO()) {
- $problem->external_id( $barnet_id );
- $problem->external_body( 'Barnet Borough Council' ); # better to use $problem->body()?
- $problem->send_method_used('barnet');
- $return = 0;
- } else {
- my @returned_items = split /<item[^>]*>/, $result->get_ET_RETURN;
- my @messages = ();
- foreach my $item (@returned_items) {
- if ($item=~/<MESSAGE [^>]*>\s*(\S.*?)<\/MESSAGE>/) { # if there's a non-null MESSAGE in there, grab it
- push @messages, $1; # best stab at extracting useful error message back from convoluted response
- }
- }
- push @messages, "service returned no external id" unless @messages;
- $err_msg = "Failed (problem id $h{id}): " . join(" \n ", @messages);
- }
- } else {
- my %fault = (
- 'code' => $result->get_faultcode(),
- 'actor' => $result->get_faultactor(),
- 'string' => $result->get_faultstring(),
- 'detail' => $result->get_detail(), # possibly only contains debug info
- );
- $fault{$_}=~s/^\s*|\s*$//g foreach keys %fault;
- $fault{actor}&&=" (actor: $fault{actor})";
- $fault{'detail'} &&= "\n" . $fault{'detail'};
- $err_msg = "Failed (problem id $h{id}): Fault $fault{code}$fault{actor}\n$fault{string}$fault{detail}";
- }
-
- };
- print "$err_msg\n" if $err_msg;
- if ($@) {
- my $e = shift;
- print "Caught an error: $@\n";
- }
- return ($return, $err_msg);
-}
-
-# London
-
-sub construct_london_message {
- my %h = @_;
- return <<EOF,
-A user of FixMyStreet has submitted the following report of a local
-problem that they believe might require your attention.
-
-Subject: $h{title}
-
-Details: $h{detail}
-
-$h{fuzzy}, or to provide an update on the problem, please visit the
-following link:
-
-$h{url}
-
-$h{closest_address}
-Yours,
-The FixMyStreet team
-EOF
-}
-
-sub post_london_report {
- my ( $problem, %h ) = @_;
- my $phone = $h{phone};
- my $mobile = '';
- if ($phone && $phone =~ /^\s*07/) {
- $mobile = $phone;
- $phone = '';
- }
- my ($first, $last) = $h{name} =~ /^(\S*)(?: (.*))?$/;
- my %params = (
- Key => mySociety::Config::get('LONDON_REPORTIT_KEY'),
- Signature => Digest::MD5::md5_hex( $h{confirmed} . mySociety::Config::get('LONDON_REPORTIT_SECRET') ),
- Type => Utils::london_categories()->{$h{category}},
- RequestDate => $h{confirmed},
- RequestMethod => 'Web',
- ExternalId => $h{url},
- 'Customer.Title' => '',
- 'Customer.FirstName' => $first,
- 'Customer.Surname' => $last,
- 'Customer.Email' => $h{email},
- 'Customer.Phone' => $phone,
- 'Customer.Mobile' => $mobile,
- 'ProblemDescription' => $h{message},
- );
- if ($h{used_map}) {
- $params{'Location.Latitude'} = $h{latitude};
- $params{'Location.Longitude'} = $h{longitude};
- } elsif (mySociety::PostcodeUtil::is_valid_postcode($h{query})) {
- # Didn't use map, and entered postcode, so use that.
- $params{'Location.Postcode'} = $h{query};
- } else {
- # Otherwise, lat/lon is all we have, even if it's wrong.
- $params{'Location.Latitude'} = $h{latitude};
- $params{'Location.Longitude'} = $h{longitude};
- }
- if ($h{has_photo}) {
- $params{'Document1.Name'} = 'Photograph';
- $params{'Document1.MimeType'} = 'image/jpeg';
- $params{'Document1.URL'} = $h{image_url};
- $params{'Document1.URLPublic'} = 'true';
- }
- my $browser = LWP::UserAgent->new;
- my $response = $browser->post( mySociety::Config::get('LONDON_REPORTIT_URL'), \%params );
- my $out = $response->content;
- if ($response->code ne 200) {
- print "Failed to post $h{id} to London API, response was " . $response->code . " $out\n";
- return 1;
- }
- my ($id) = $out =~ /<caseid>(.*?)<\/caseid>/;
- my ($org) = $out =~ /<organisation>(.*?)<\/organisation>/;
- my ($team) = $out =~ /<team>(.*?)<\/team>/;
-
- $org = london_lookup($org);
- $problem->external_id( $id );
- $problem->external_body( $org );
- $problem->external_team( $team );
- return 0;
-}
-
-# Nearest things
-
-sub london_lookup {
- my $org = shift || '';
- my $str = "Unknown ($org)";
- open(FP, "$FindBin::Bin/../data/dft.csv");
- while (<FP>) {
- /^(.*?),(.*)/;
- if ($org eq $1) {
- $str = $2;
- last;
- }
- }
- close FP;
- return $str;
-}
-
-# for barnet webservice: max-length fields require truncate and split
-
-# truncate_string_with_entities
-# args: text to truncate
-# max number of chars
-# returns: string truncated
-# Note: must not partially truncate an entity (e.g., &amp;)
-sub truncate_string_with_entities {
- my ($str, $max_len) = @_;
- my $retVal = "";
- foreach my $chunk (split /(\&(?:\#\d+|\w+);)/, $str) {
- if ($chunk=~/^\&(\#\d+|\w+);$/){
- my $next = $retVal.$chunk;
- last if length $next > $max_len;
- $retVal=$next
- } else {
- $retVal.=$chunk;
- if (length $retVal > $max_len) {
- $retVal = substr($retVal, 0, $max_len);
- last
- }
- }
- }
- return $retVal
-}
-
-# split_text_with_entities into lines
-# args: text to be broken into lines
-# max length (option: uses constant MAX_LINE_LENGTH)
-# returns: array of lines
-# Must not to split an entity (e.g., &amp;)
-# Not worrying about hyphenating here, since a word is only ever split if
-# it's longer than the whole line, which is uncommon in genuine problem reports
-sub split_text_with_entities {
- my ($text, $max_line_length) = @_;
- $max_line_length ||= MAX_LINE_LENGTH;
- my @lines;
- foreach my $line (split "\n", $text) {
- while (length $line > $max_line_length) {
- if (! ($line =~ s/^(.{1,$max_line_length})\s// # break on a space
- or $line =~ s/^(.{1,$max_line_length})(\&(\#\d+|\w+);)/$2/ # break before an entity
- or $line =~ s/(.{$max_line_length})//)) { # break the word ruthlessly
- $line =~ s/(.*)//; # otherwise gobble whole line (which is now shorter than max length)
- }
- push @lines, $1;
- }
- push @lines, $line;
- }
- return @lines;
-}
+use FixMyStreet::App;
-# tests send_fail_count agains cutoff limit
-# args: problem (row from problem db)
-# returns false if there is no cutoff, otherwise error message
-sub does_exceed_cutoff_limit {
- my ($problem, $council_name) = @_;
- my $err_msg = "";
- if ($problem->send_fail_count >= SEND_FAIL_RETRIES_CUTOFF) {
- $sending_skipped_by_method{$council_name || '?'}++;
- $council_name &&= " to $council_name";
- $err_msg = "skipped: problem id=" . $problem->id . " send$council_name has failed "
- . $problem->send_fail_count . " times, cutoff is " . SEND_FAIL_RETRIES_CUTOFF;
- }
- return $err_msg;
-}
+my $site = CronFns::site(mySociety::Config::get('BASE_URL'));
+CronFns::language($site);
-# update_send_fail_data records the failure (of a webservice send)
-# args: problem (row from problem db)
-# returns: no return value (updates record)
-sub update_send_fail_data {
- my ($problem, $err_msg) = @_;
- $problem->update( {
- send_fail_count => $problem->send_fail_count + 1,
- send_fail_timestamp => \'ms_current_timestamp()',
- send_fail_reason => $err_msg
- } );
-}
+FixMyStreet::App->model('DB::Problem')->send_reports();
diff --git a/conf/crontab.ugly b/conf/crontab.ugly
index 1a4e82cee..087021fd1 100644
--- a/conf/crontab.ugly
+++ b/conf/crontab.ugly
@@ -22,12 +22,15 @@ MAILTO=!!(*= $user *)!!@mysociety.org
#2 * * * * !!(*= $user *)!! run-with-lockfile -n /data/vhost/!!(*= $vhost *)!!/send-alerts.lock "/data/vhost/!!(*= $vhost *)!!/fixmystreet/bin/cron-wrapper send-alerts" || echo "stalled?"
0,30 * * * * !!(*= $user *)!! run-with-lockfile -n /data/vhost/!!(*= $vhost *)!!/send-questionnaires.lock "/data/vhost/!!(*= $vhost *)!!/fixmystreet/bin/cron-wrapper send-questionnaires" || echo "stalled?"
-!!(* } elsif (($vhost eq 'www.fixmystreet.com') || ($vhost eq 'matthew.fixmystreet.com') || ($vhost eq 'integration-staging.fixmystreet.com')) { *)!!
+!!(* } elsif (($vhost eq 'www.fixmystreet.com') || ($vhost eq 'bromley.test.mysociety.org') || ($vhost eq 'integration-staging.fixmystreet.com')) { *)!!
5,10,15,20,25,30,35,40,45,50,55 * * * * !!(*= $user *)!! run-with-lockfile -n /data/vhost/!!(*= $vhost *)!!/send-reports.lock "/data/vhost/!!(*= $vhost *)!!/fixmystreet/bin/cron-wrapper send-reports" || echo "stalled?"
0 0-8,10,11,13,14,16,17,19-23 * * * !!(*= $user *)!! run-with-lockfile -n /data/vhost/!!(*= $vhost *)!!/send-reports.lock "/data/vhost/!!(*= $vhost *)!!/fixmystreet/bin/cron-wrapper send-reports" || echo "stalled?"
0 9,12,15,18 * * * !!(*= $user *)!! run-with-lockfile -n /data/vhost/!!(*= $vhost *)!!/send-reports.lock "/data/vhost/!!(*= $vhost *)!!/fixmystreet/bin/cron-wrapper send-reports --verbose" || echo "stalled?"
2 * * * * !!(*= $user *)!! run-with-lockfile -n /data/vhost/!!(*= $vhost *)!!/send-alerts.lock "/data/vhost/!!(*= $vhost *)!!/fixmystreet/bin/cron-wrapper send-alerts" || echo "stalled?"
0,30 * * * * !!(*= $user *)!! run-with-lockfile -n /data/vhost/!!(*= $vhost *)!!/send-questionnaires.lock "/data/vhost/!!(*= $vhost *)!!/fixmystreet/bin/cron-wrapper send-questionnaires" || echo "stalled?"
+5,10,15,20,25,30,35,40,45,50,55 * * * * !!(*= $user *)!! run-with-lockfile -n /data/vhost/!!(*= $vhost *)!!/send-comments.lock "/data/vhost/!!(*= $vhost *)!!/fixmystreet/bin/cron-wrapper send-comments" || echo "stalled?"
+5,10,15,20,25,30,35,40,45,50,55 * * * * !!(*= $user *)!! run-with-lockfile -n /data/vhost/!!(*= $vhost *)!!/fetch-comments.lock "/data/vhost/!!(*= $vhost *)!!/fixmystreet/bin/cron-wrapper fetch-comments" || echo "stalled?"
+0,30 * * * * !!(*= $user *)!! run-with-lockfile -n /data/vhost/!!(*= $vhost *)!!/open311-populate-service-list.lock "/data/vhost/!!(*= $vhost *)!!/fixmystreet/bin/cron-wrapper open311-populate-service-list" || echo "stalled?"
!!(* } *)!!
diff --git a/conf/general.yml-example b/conf/general.yml-example
index ec77e6ba8..93b54a3e7 100644
--- a/conf/general.yml-example
+++ b/conf/general.yml-example
@@ -62,4 +62,5 @@ RSS_LIMIT: '20'
# Should problem reports link to the council summary pages?
AREA_LINKS_FROM_PROBLEMS: '0'
-
+# used to override the STAGING SERVER safety mechanism in send-reports
+TESTING_COUNCILS:
diff --git a/conf/packages.debian-squeeze b/conf/packages.debian-squeeze
index cb494157d..0efd5e469 100644
--- a/conf/packages.debian-squeeze
+++ b/conf/packages.debian-squeeze
@@ -36,3 +36,4 @@ postgresql-8.4
postgresql-server-dev-8.4
gnuplot
ttf-bitstream-vera
+libexpat1-dev
diff --git a/conf/packages.debian-squeeze+testing b/conf/packages.debian-squeeze+testing
index cec3a2624..7935ff3fe 100644
--- a/conf/packages.debian-squeeze+testing
+++ b/conf/packages.debian-squeeze+testing
@@ -36,3 +36,4 @@ postgresql-8.4
postgresql-server-dev-8.4
gnuplot
ttf-bitstream-vera
+libexpat1-dev
diff --git a/data/dashboard.json b/data/dashboard.json
new file mode 100644
index 000000000..1da667356
--- /dev/null
+++ b/data/dashboard.json
@@ -0,0 +1,236 @@
+{
+ "council": { "name": "South Borsetshire District Council" },
+ "wards": {
+ "1": { "id": 1, "name": "West Ward" },
+ "2": { "id": 2, "name": "East Ward" },
+ "3": { "id": 3, "name": "North Ward" },
+ "4": { "id": 4, "name": "South Ward" }
+ },
+ "category_options": [
+ "Abandoned vehicles",
+ "Grafitti",
+ "Potholes",
+ "Street lighting",
+ "Trees",
+ "Other"
+ ],
+ "counts_all": {
+ "wtd": {
+ "total": 10,
+ "planned": 2,
+ "in progress": 1,
+ "investigating": 1,
+ "fixed - council": 3,
+ "fixed_user": 2,
+ "time_to_fix": 2,
+ "time_to_mark": 2,
+ "not_marked": 1
+ },
+ "week": {
+ "total": 21,
+ "planned": 5,
+ "in progress": 3,
+ "investigating": 4,
+ "fixed - council": 6,
+ "fixed_user": 3,
+ "time_to_fix": 3,
+ "time_to_mark": 2,
+ "not_marked": 1
+ },
+ "weeks": {
+ "total": 57,
+ "planned": 5,
+ "in progress": 16,
+ "investigating": 4,
+ "fixed - council": 23,
+ "fixed_user": 9,
+ "time_to_fix": 2,
+ "time_to_mark": 2,
+ "not_marked": 1
+ },
+ "ytd": {
+ "total": 171,
+ "planned": 23,
+ "in progress": 34,
+ "investigating": 9,
+ "fixed - council": 72,
+ "fixed_user": 33,
+ "time_to_fix": 2,
+ "time_to_mark": 2,
+ "not_marked": 1
+ }
+ },
+ "counts_some": {
+ "wtd": {
+ "total": 5,
+ "planned": 0,
+ "in progress": 1,
+ "investigating": 1,
+ "fixed - council": 2,
+ "fixed_user": 1,
+ "time_to_fix": 2,
+ "time_to_mark": 2,
+ "not_marked": 0
+ },
+ "week": {
+ "total": 7,
+ "planned": 1,
+ "in progress": 2,
+ "investigating": 1,
+ "fixed - council": 2,
+ "fixed_user": 1,
+ "time_to_fix": 3,
+ "time_to_mark": 2,
+ "not_marked": 0
+ },
+ "weeks": {
+ "total": 57,
+ "planned": 5,
+ "in progress": 16,
+ "investigating": 4,
+ "fixed - council": 23,
+ "fixed_user": 9,
+ "time_to_fix": 2,
+ "time_to_mark": 2,
+ "not_marked": 1
+ },
+ "ytd": {
+ "total": 57,
+ "planned": 5,
+ "in progress": 16,
+ "investigating": 4,
+ "fixed - council": 23,
+ "fixed_user": 9,
+ "time_to_fix": 2,
+ "time_to_mark": 2,
+ "not_marked": 1
+ }
+ },
+ "lists": {
+ "all": {
+ "1": [
+ { "id": 0, "title": "Pothole" },
+ { "id": 0, "title": "Fallen Tree" },
+ { "id": 0, "title": "Fly tipping" },
+ { "id": 0, "title": "Loose kerb" },
+ { "id": 0, "title": "Blocked drain" },
+ { "id": 0, "title": "Pothole" },
+ { "id": 0, "title": "Abandoned car" },
+ { "id": 0, "title": "Burst pipe" },
+ { "id": 0, "title": "Pothole" },
+ { "id": 0, "title": "Uneven paving" }
+ ],
+ "2": [
+ { "id": 0, "title": "Burst pipe" },
+ { "id": 0, "title": "Blocked drain" },
+ { "id": 0, "title": "Burst pipe" },
+ { "id": 0, "title": "Pothole" },
+ { "id": 0, "title": "Fly tipping" },
+ { "id": 0, "title": "Blocked drain" },
+ { "id": 0, "title": "Burst pipe" },
+ { "id": 0, "title": "Pothole" },
+ { "id": 0, "title": "Uneven paving" },
+ { "id": 0, "title": "Blocked drain" },
+ { "id": 0, "title": "Loose kerb" },
+ { "id": 0, "title": "Blocked drain" },
+ { "id": 0, "title": "Fallen Tree" },
+ { "id": 0, "title": "Burst pipe" },
+ { "id": 0, "title": "Abandoned car" },
+ { "id": 0, "title": "Pothole" },
+ { "id": 0, "title": "Pothole" },
+ { "id": 0, "title": "Loose kerb" },
+ { "id": 0, "title": "Blocked drain" },
+ { "id": 0, "title": "Blocked drain" }
+ ],
+ "3": [
+ { "id": 0, "title": "Burst pipe" },
+ { "id": 0, "title": "Loose kerb" },
+ { "id": 0, "title": "Blocked drain" },
+ { "id": 0, "title": "Blocked drain" },
+ { "id": 0, "title": "Fly tipping" },
+ { "id": 0, "title": "Uneven paving" },
+ { "id": 0, "title": "Fallen Tree" },
+ { "id": 0, "title": "Blocked drain" },
+ { "id": 0, "title": "Pothole" },
+ { "id": 0, "title": "Pothole" },
+ { "id": 0, "title": "Burst pipe" },
+ { "id": 0, "title": "Burst pipe" },
+ { "id": 0, "title": "Loose kerb" },
+ { "id": 0, "title": "Abandoned car" },
+ { "id": 0, "title": "Pothole" },
+ { "id": 0, "title": "Blocked drain" },
+ { "id": 0, "title": "Blocked drain" },
+ { "id": 0, "title": "Fallen Tree" },
+ { "id": 0, "title": "Pothole" },
+ { "id": 0, "title": "Burst pipe" },
+ { "id": 0, "title": "Pothole" },
+ { "id": 0, "title": "Fly tipping" },
+ { "id": 0, "title": "Burst pipe" },
+ { "id": 0, "title": "Abandoned car" },
+ { "id": 0, "title": "Pothole" },
+ { "id": 0, "title": "Loose kerb" },
+ { "id": 0, "title": "Uneven paving" },
+ { "id": 0, "title": "Blocked drain" },
+ { "id": 0, "title": "Blocked drain" },
+ { "id": 0, "title": "Pothole" }
+ ]
+ },
+ "filtered": {
+ "1": [
+ { "id": 0, "title": "Pothole" },
+ { "id": 0, "title": "Fallen Tree" },
+ { "id": 0, "title": "Loose kerb" },
+ { "id": 0, "title": "Abandoned car" },
+ { "id": 0, "title": "Pothole" },
+ { "id": 0, "title": "Uneven paving" }
+ ],
+ "2": [
+ { "id": 0, "title": "Burst pipe" },
+ { "id": 0, "title": "Loose kerb" },
+ { "id": 0, "title": "Blocked drain" },
+ { "id": 0, "title": "Fly tipping" },
+ { "id": 0, "title": "Fallen Tree" },
+ { "id": 0, "title": "Blocked drain" },
+ { "id": 0, "title": "Pothole" },
+ { "id": 0, "title": "Burst pipe" },
+ { "id": 0, "title": "Burst pipe" },
+ { "id": 0, "title": "Loose kerb" },
+ { "id": 0, "title": "Blocked drain" },
+ { "id": 0, "title": "Fallen Tree" },
+ { "id": 0, "title": "Pothole" },
+ { "id": 0, "title": "Pothole" },
+ { "id": 0, "title": "Fly tipping" },
+ { "id": 0, "title": "Abandoned car" },
+ { "id": 0, "title": "Pothole" },
+ { "id": 0, "title": "Uneven paving" },
+ { "id": 0, "title": "Blocked drain" },
+ { "id": 0, "title": "Pothole" }
+ ],
+ "3": [
+ { "id": 0, "title": "Burst pipe" },
+ { "id": 0, "title": "Blocked drain" },
+ { "id": 0, "title": "Blocked drain" },
+ { "id": 0, "title": "Uneven paving" },
+ { "id": 0, "title": "Fallen Tree" },
+ { "id": 0, "title": "Pothole" },
+ { "id": 0, "title": "Pothole" },
+ { "id": 0, "title": "Burst pipe" },
+ { "id": 0, "title": "Loose kerb" },
+ { "id": 0, "title": "Abandoned car" },
+ { "id": 0, "title": "Pothole" },
+ { "id": 0, "title": "Blocked drain" },
+ { "id": 0, "title": "Fallen Tree" },
+ { "id": 0, "title": "Pothole" },
+ { "id": 0, "title": "Burst pipe" },
+ { "id": 0, "title": "Fly tipping" },
+ { "id": 0, "title": "Burst pipe" },
+ { "id": 0, "title": "Abandoned car" },
+ { "id": 0, "title": "Pothole" },
+ { "id": 0, "title": "Uneven paving" },
+ { "id": 0, "title": "Blocked drain" },
+ { "id": 0, "title": "Blocked drain" },
+ { "id": 0, "title": "Pothole" }
+ ]
+ }
+ }
+}
diff --git a/db/schema.sql b/db/schema.sql
index e1205099d..832104991 100644
--- a/db/schema.sql
+++ b/db/schema.sql
@@ -135,7 +135,8 @@ create table users (
phone text,
password text not null default '',
from_council integer, -- id of council user is from or null/0 if not
- flagged boolean not null default 'f'
+ flagged boolean not null default 'f',
+ title text
);
-- Problems reported by users of site
@@ -311,9 +312,15 @@ create table comment (
or problem_state = 'fixed'
or problem_state = 'fixed - council'
or problem_state = 'fixed - user'
- )
+ ),
-- other fields? one to indicate whether this was written by the council
-- and should be highlighted in the display?
+ external_id text,
+ extra text,
+ send_fail_count integer not null default 0,
+ send_fail_reason text,
+ send_fail_timestamp timestamp,
+ whensent timestamp
);
create index comment_user_id_idx on comment(user_id);
@@ -428,5 +435,8 @@ create table open311conf (
endpoint text not null,
jurisdiction text,
api_key text,
- send_method text
+ send_method text,
+ send_comments boolean not null default 'f',
+ comment_user_id int references users(id),
+ suppress_alerts boolean not null default 'f'
);
diff --git a/db/schema_0013-add_external_id_to_comment.sql b/db/schema_0013-add_external_id_to_comment.sql
new file mode 100644
index 000000000..a1cd11c3f
--- /dev/null
+++ b/db/schema_0013-add_external_id_to_comment.sql
@@ -0,0 +1,6 @@
+begin;
+
+ALTER TABLE comment
+ ADD COLUMN external_id TEXT;
+
+commit;
diff --git a/db/schema_0015-add_extra_to_comment.sql b/db/schema_0015-add_extra_to_comment.sql
new file mode 100644
index 000000000..5c1789ea2
--- /dev/null
+++ b/db/schema_0015-add_extra_to_comment.sql
@@ -0,0 +1,6 @@
+begin;
+
+ALTER TABLE comment
+ ADD COLUMN extra TEXT;
+
+commit;
diff --git a/db/schema_0016-add_whensent_and_send_fail_to_comment.sql b/db/schema_0016-add_whensent_and_send_fail_to_comment.sql
new file mode 100644
index 000000000..792ff2e38
--- /dev/null
+++ b/db/schema_0016-add_whensent_and_send_fail_to_comment.sql
@@ -0,0 +1,11 @@
+begin;
+
+ALTER table comment
+ ADD column send_fail_count integer not null default 0;
+ALTER table comment
+ ADD column send_fail_reason text;
+ALTER table comment
+ ADD column send_fail_timestamp timestamp;
+ALTER table comment
+ ADD column whensent timestamp;
+commit;
diff --git a/db/schema_0017-add_send_comments_to_open311conf.sql b/db/schema_0017-add_send_comments_to_open311conf.sql
new file mode 100644
index 000000000..0ee015575
--- /dev/null
+++ b/db/schema_0017-add_send_comments_to_open311conf.sql
@@ -0,0 +1,6 @@
+begin;
+
+ALTER table open311conf
+ ADD column send_comments BOOL NOT NULL DEFAULT 'f';
+
+commit;
diff --git a/db/schema_0018-add_comment_user_to_open311conf.sql b/db/schema_0018-add_comment_user_to_open311conf.sql
new file mode 100644
index 000000000..93851e2a3
--- /dev/null
+++ b/db/schema_0018-add_comment_user_to_open311conf.sql
@@ -0,0 +1,6 @@
+begin;
+
+ALTER TABLE open311conf
+ ADD COLUMN comment_user_id INT REFERENCES users(id);
+
+commit;
diff --git a/db/schema_0019-add_title_to_users.sql b/db/schema_0019-add_title_to_users.sql
new file mode 100644
index 000000000..1cc7dd16d
--- /dev/null
+++ b/db/schema_0019-add_title_to_users.sql
@@ -0,0 +1,8 @@
+-- These are changes needed to the schema to support moving over to DBIx::Class
+
+begin;
+
+AlTER TABLE users
+ ADD COLUMN title text;
+
+commit;
diff --git a/db/schema_0020-add_suppress_alerts_to_open311.sql b/db/schema_0020-add_suppress_alerts_to_open311.sql
new file mode 100644
index 000000000..26fc54617
--- /dev/null
+++ b/db/schema_0020-add_suppress_alerts_to_open311.sql
@@ -0,0 +1,6 @@
+begin;
+
+ALTER table open311conf
+ ADD column suppress_alerts BOOL NOT NULL DEFAULT 'f';
+
+commit;
diff --git a/perllib/FixMyStreet/App.pm b/perllib/FixMyStreet/App.pm
index 262379b79..6ccc801ce 100644
--- a/perllib/FixMyStreet/App.pm
+++ b/perllib/FixMyStreet/App.pm
@@ -53,6 +53,7 @@ __PACKAGE__->config(
'Plugin::Session' => { # Catalyst::Plugin::Session::Store::DBIC
dbic_class => 'DB::Session',
expires => 3600 * 24 * 7 * 4, # 4 weeks
+ cookie_secure => 2,
},
'Plugin::Authentication' => {
@@ -180,12 +181,7 @@ sub setup_request {
Memcached::set_namespace( FixMyStreet->config('FMS_DB_NAME') . ":" );
- my $map = $host =~ /^osm\./ ? 'OSM' : $c->req->param('map_override');
- #if ($c->sessionid) {
- # $map = $c->session->{map};
- # $map = undef unless $map eq 'OSM';
- #}
- FixMyStreet::Map::set_map_class( $map );
+ FixMyStreet::Map::set_map_class( $cobrand->map_type || $c->req->param('map_override') );
return $c;
}
@@ -323,6 +319,16 @@ sub send_email_cron {
unpack('h*', random_bytes(5, 1))
);
+ $params->{_parameters_}->{signature} = '';
+ #$params->{_parameters_}->{signature} = $c->view('Email')->render(
+ # $c, 'signature.txt', {
+ # additional_template_paths => [
+ # FixMyStreet->path_to( 'templates', 'email', $c->cobrand->moniker, $c->stash->{lang_code} )->stringify,
+ # FixMyStreet->path_to( 'templates', 'email', $c->cobrand->moniker )->stringify,
+ # ]
+ # }
+ #);
+
my $email = mySociety::Locale::in_gb_locale { mySociety::Email::construct_email($params) };
if ( FixMyStreet->test_mode ) {
diff --git a/perllib/FixMyStreet/App/Controller/Admin.pm b/perllib/FixMyStreet/App/Controller/Admin.pm
index 198acade6..998cb83a8 100644
--- a/perllib/FixMyStreet/App/Controller/Admin.pm
+++ b/perllib/FixMyStreet/App/Controller/Admin.pm
@@ -8,6 +8,8 @@ use POSIX qw(strftime strcoll);
use Digest::MD5 qw(md5_hex);
use mySociety::EmailUtil qw(is_valid_email);
+use FixMyStreet::SendReport;
+
=head1 NAME
FixMyStreet::App::Controller::Admin- Catalyst Controller
@@ -338,7 +340,7 @@ sub update_contacts : Private {
} elsif ( $posted eq 'open311' ) {
$c->forward('check_token');
- my %params = map { $_ => $c->req->param($_) } qw/open311_id endpoint jurisdiction api_key area_id/;
+ my %params = map { $_ => $c->req->param($_) || '' } qw/open311_id endpoint jurisdiction api_key area_id send_method send_comments suppress_alerts comment_user_id/;
if ( $params{open311_id} ) {
my $conf = $c->model('DB::Open311Conf')->find( { id => $params{open311_id} } );
@@ -346,6 +348,10 @@ sub update_contacts : Private {
$conf->endpoint( $params{endpoint} );
$conf->jurisdiction( $params{jurisdiction} );
$conf->api_key( $params{api_key} );
+ $conf->send_method( $params{send_method} );
+ $conf->send_comments( $params{send_comments} || 0);
+ $conf->suppress_alerts( $params{suppress_alerts} || 0);
+ $conf->comment_user_id( $params{comment_user_id} || undef );
$conf->update();
@@ -356,6 +362,10 @@ sub update_contacts : Private {
$conf->endpoint( $params{endpoint} );
$conf->jurisdiction( $params{jurisdiction} );
$conf->api_key( $params{api_key} );
+ $conf->send_method( $params{send_method} );
+ $conf->send_comments( $params{send_comments} || 0);
+ $conf->suppress_alerts( $params{suppress_alerts} || 0);
+ $conf->comment_user_id( $params{comment_user_id} || undef );
$conf->insert();
@@ -378,6 +388,9 @@ sub display_contacts : Private {
$c->stash->{contacts} = $contacts;
+ my @methods = map { $_ =~ s/FixMyStreet::SendReport:://; $_ } keys %{ FixMyStreet::SendReport->get_senders };
+ $c->stash->{send_methods} = \@methods;
+
my $open311 = $c->model('DB::Open311Conf')->search(
{ area_id => $area_id }
);
@@ -492,7 +505,7 @@ sub search_reports : Path('search_reports') {
'me.id' => $search_n,
'user.email' => { ilike => $like_search },
'me.name' => { ilike => $like_search },
- title => { ilike => $like_search },
+ 'me.title' => { ilike => $like_search },
detail => { ilike => $like_search },
council => { like => $like_search },
cobrand_data => { like => $like_search },
@@ -571,8 +584,7 @@ sub report_edit : Path('report_edit') : Args(1) {
}
)->first;
- $c->detach( '/page_error_404_not_found',
- [ _('The requested URL was not found on this server.') ] )
+ $c->detach( '/page_error_404_not_found' )
unless $problem;
$c->stash->{problem} = $problem;
@@ -734,8 +746,7 @@ sub update_edit : Path('update_edit') : Args(1) {
}
)->first;
- $c->detach( '/page_error_404_not_found',
- [ _('The requested URL was not found on this server.') ] )
+ $c->detach( '/page_error_404_not_found' )
unless $update;
$c->forward('get_token');
@@ -1068,7 +1079,7 @@ sub check_token : Private {
my ( $self, $c ) = @_;
if ( !$c->req->param('token') || $c->req->param('token' ) ne $c->stash->{token} ) {
- $c->detach( '/page_error_404_not_found', [ _('The requested URL was not found on this server.') ] );
+ $c->detach( '/page_error_404_not_found' );
}
return 1;
@@ -1238,7 +1249,7 @@ sub check_page_allowed : Private {
$page ||= 'summary';
if ( !grep { $_ eq $page } keys %{ $c->stash->{allowed_pages} } ) {
- $c->detach( '/page_error_404_not_found', [ _('The requested URL was not found on this server.') ] );
+ $c->detach( '/page_error_404_not_found' );
}
return 1;
diff --git a/perllib/FixMyStreet/App/Controller/Alert.pm b/perllib/FixMyStreet/App/Controller/Alert.pm
index 2698c6ac0..6e9ae819c 100644
--- a/perllib/FixMyStreet/App/Controller/Alert.pm
+++ b/perllib/FixMyStreet/App/Controller/Alert.pm
@@ -191,7 +191,11 @@ sub create_alert : Private {
$alert->insert();
}
- $alert->confirm() if $c->user && $c->user->id == $alert->user->id;
+ if ( $c->user && $c->user->id == $alert->user->id ) {
+ $alert->confirm();
+ } else {
+ $alert->confirmed(0);
+ }
$c->stash->{alert} = $alert;
}
@@ -470,6 +474,7 @@ sub add_recent_photos : Private {
{
$c->stash->{photos} = $c->cobrand->recent_photos(
+ 'alert',
$num_photos,
$c->stash->{latitude},
$c->stash->{longitude},
@@ -477,7 +482,7 @@ sub add_recent_photos : Private {
);
}
else {
- $c->stash->{photos} = $c->cobrand->recent_photos($num_photos);
+ $c->stash->{photos} = $c->cobrand->recent_photos('alert', $num_photos);
}
return 1;
diff --git a/perllib/FixMyStreet/App/Controller/Around.pm b/perllib/FixMyStreet/App/Controller/Around.pm
index e110cf8d7..3047b195c 100644
--- a/perllib/FixMyStreet/App/Controller/Around.pm
+++ b/perllib/FixMyStreet/App/Controller/Around.pm
@@ -186,10 +186,11 @@ sub display_location : Private {
@pins = map {
# Here we might have a DB::Problem or a DB::Nearby, we always want the problem.
my $p = (ref $_ eq 'FixMyStreet::App::Model::DB::Nearby') ? $_->problem : $_;
+ my $colour = $c->cobrand->pin_colour( $p, 'around' );
{
latitude => $p->latitude,
longitude => $p->longitude,
- colour => 'yellow', # $p->is_fixed ? 'green' : 'red',
+ colour => $colour,
id => $p->id,
title => $p->title,
}
diff --git a/perllib/FixMyStreet/App/Controller/Contact.pm b/perllib/FixMyStreet/App/Controller/Contact.pm
index f28d37989..c300aee9a 100644
--- a/perllib/FixMyStreet/App/Controller/Contact.pm
+++ b/perllib/FixMyStreet/App/Controller/Contact.pm
@@ -139,17 +139,17 @@ sub prepare_params_for_email : Private {
$c->stash->{message} =~ s/\r\n/\n/g;
$c->stash->{subject} =~ s/\r|\n/ /g;
- my $base_url = $c->cobrand->base_url_for_emails( $c->cobrand->extra_data );
- my $admin_base_url = $c->cobrand->admin_base_url
- || 'https://secure.mysociety.org/admin/bci/';
+ my $base_url = $c->cobrand->base_url_for_emails( $c->cobrand->extra_data );
+ my $admin_url = $c->cobrand->admin_base_url;
if ( $c->stash->{update} ) {
my $problem_url = $base_url . '/report/' . $c->stash->{update}->problem_id
. '#update_' . $c->stash->{update}->id;
- my $admin_url = $admin_base_url . 'update_edit/' . $c->stash->{update}->id;
+ my $admin_url = " - $admin_url" . 'update_edit/' . $c->stash->{update}->id
+ if $admin_url;
$c->stash->{message} .= sprintf(
- " \n\n[ Complaint about update %d on report %d - %s - %s ]",
+ " \n\n[ Complaint about update %d on report %d - %s%s ]",
$c->stash->{update}->id,
$c->stash->{update}->problem_id,
$problem_url, $admin_url
@@ -158,9 +158,10 @@ sub prepare_params_for_email : Private {
elsif ( $c->stash->{problem} ) {
my $problem_url = $base_url . '/report/' . $c->stash->{problem}->id;
- my $admin_url = $admin_base_url . 'report_edit/' . $c->stash->{problem}->id;
+ $admin_url = " - $admin_url" . 'report_edit/' . $c->stash->{problem}->id
+ if $admin_url;
$c->stash->{message} .= sprintf(
- " \n\n[ Complaint about report %d - %s - %s ]",
+ " \n\n[ Complaint about report %d - %s%s ]",
$c->stash->{problem}->id,
$problem_url, $admin_url
);
@@ -183,7 +184,7 @@ generally required to stash
sub setup_request : Private {
my ( $self, $c ) = @_;
- $c->stash->{contact_email} = $c->cobrand->contact_email;
+ $c->stash->{contact_email} = $c->cobrand->contact_email( 'contact' );
$c->stash->{contact_email} =~ s/\@/&#64;/;
for my $param (qw/em subject message/) {
@@ -205,7 +206,7 @@ Sends the email
sub send_email : Private {
my ( $self, $c ) = @_;
- my $recipient = $c->cobrand->contact_email();
+ my $recipient = $c->cobrand->contact_email( 'contact' );
my $recipient_name = $c->cobrand->contact_name();
$c->stash->{host} = $c->req->header('HOST');
diff --git a/perllib/FixMyStreet/App/Controller/Dashboard.pm b/perllib/FixMyStreet/App/Controller/Dashboard.pm
new file mode 100644
index 000000000..e4266dc64
--- /dev/null
+++ b/perllib/FixMyStreet/App/Controller/Dashboard.pm
@@ -0,0 +1,245 @@
+package FixMyStreet::App::Controller::Dashboard;
+use Moose;
+use namespace::autoclean;
+
+use DateTime;
+use File::Slurp;
+
+BEGIN { extends 'Catalyst::Controller'; }
+
+=head1 NAME
+
+FixMyStreet::App::Controller::Dashboard - Catalyst Controller
+
+=head1 DESCRIPTION
+
+Catalyst Controller.
+
+=head1 METHODS
+
+=cut
+
+sub example : Local : Args(0) {
+ my ( $self, $c ) = @_;
+ $c->stash->{template} = 'dashboard/index.html';
+
+ $c->stash->{children} = {};
+ for my $i (1..3) {
+ $c->stash->{children}{$i} = { id => $i, name => "Ward $i" };
+ }
+
+ # TODO Set up manual version of what the below would do
+ #$c->forward( '/report/new/setup_categories_and_councils' );
+
+ # See if we've had anything from the dropdowns - perhaps vary results if so
+ $c->stash->{ward} = $c->req->param('ward');
+ $c->stash->{category} = $c->req->param('category');
+ $c->stash->{q_state} = $c->req->param('state');
+
+ eval {
+ my $data = File::Slurp::read_file(
+ FixMyStreet->path_to( 'data/dashboard.json' )->stringify
+ );
+ my $j = JSON->new->utf8->decode($data);
+ if ( !$c->stash->{ward} && !$c->stash->{category} ) {
+ $c->stash->{problems} = $j->{counts_all};
+ } else {
+ $c->stash->{problems} = $j->{counts_some};
+ }
+ $c->stash->{council} = $j->{council};
+ $c->stash->{children} = $j->{wards};
+ $c->stash->{category_options} = $j->{category_options};
+ if ( lc($c->stash->{q_state}) eq 'all' or !$c->stash->{q_state} ) {
+ $c->stash->{lists} = $j->{lists}->{all};
+ } else {
+ $c->stash->{lists} = $j->{lists}->{filtered};
+ }
+ };
+ if ($@) {
+ $c->stash->{message} = _("There was a problem showing this page. Please try again later.") . ' ' .
+ sprintf(_('The error was: %s'), $@);
+ $c->stash->{template} = 'errors/generic.html';
+ }
+}
+
+=head2 check_page_allowed
+
+Checks if we can view this page, and if not redirect to 404.
+
+=cut
+
+sub check_page_allowed : Private {
+ my ( $self, $c ) = @_;
+
+ $c->detach( '/auth/redirect' ) unless $c->user_exists;
+
+ $c->detach( '/page_error_404_not_found' )
+ unless $c->user_exists && $c->user->from_council;
+
+ return $c->user->from_council;
+}
+
+=head2 index
+
+Show the dashboard table.
+
+=cut
+
+sub index : Path : Args(0) {
+ my ( $self, $c ) = @_;
+
+ my $council = $c->forward('check_page_allowed');
+
+ # Set up the data for the dropdowns
+
+ my $council_detail = mySociety::MaPit::call('area', $council );
+ $c->stash->{council} = $council_detail;
+
+ my $children = mySociety::MaPit::call('area/children', $council,
+ type => $mySociety::VotingArea::council_child_types,
+ );
+ $c->stash->{children} = $children;
+
+ $c->stash->{all_councils} = { $council => $council_detail };
+ $c->forward( '/report/new/setup_categories_and_councils' );
+
+ # See if we've had anything from the dropdowns
+
+ $c->stash->{ward} = $c->req->param('ward');
+ $c->stash->{category} = $c->req->param('category');
+
+ my %where = (
+ council => $council, # XXX This will break in a two tier council. Restriction needs looking at...
+ 'problem.state' => [ FixMyStreet::DB::Result::Problem->visible_states() ],
+ );
+ $where{areas} = { 'like', '%,' . $c->stash->{ward} . ',%' }
+ if $c->stash->{ward};
+ $where{category} = $c->stash->{category}
+ if $c->stash->{category};
+ $c->stash->{where} = \%where;
+ my $prob_where = { %where };
+ $prob_where->{state} = $prob_where->{'problem.state'};
+ delete $prob_where->{'problem.state'};
+ $c->stash->{prob_where} = $prob_where;
+
+ my %counts;
+ my $t = DateTime->today;
+ $counts{wtd} = $c->forward( 'updates_search', [ $t->subtract( days => $t->dow - 1 ) ] );
+ $counts{week} = $c->forward( 'updates_search', [ DateTime->now->subtract( weeks => 1 ) ] );
+ $counts{weeks} = $c->forward( 'updates_search', [ DateTime->now->subtract( weeks => 4 ) ] );
+ $counts{ytd} = $c->forward( 'updates_search', [ DateTime->today->set( day => 1, month => 1 ) ] );
+
+ $c->stash->{problems} = \%counts;
+
+ # List of reports underneath summary table
+
+ $c->stash->{q_state} = $c->req->param('state') || '';
+ if ( $c->stash->{q_state} eq 'fixed' ) {
+ $prob_where->{state} = [ FixMyStreet::DB::Result::Problem->fixed_states() ];
+ } elsif ( $c->stash->{q_state} ) {
+ $prob_where->{state} = $c->stash->{q_state};
+ }
+ my $params = {
+ %$prob_where,
+ 'me.confirmed' => { '>=', DateTime->now->subtract( days => 30 ) },
+ };
+ my @problems = $c->cobrand->problems->search( $params )->all;
+ my %problems;
+ foreach (@problems) {
+ if ($_->confirmed >= DateTime->now->subtract(days => 7)) {
+ push @{$problems{1}}, $_;
+ } elsif ($_->confirmed >= DateTime->now->subtract(days => 14)) {
+ push @{$problems{2}}, $_;
+ } else {
+ push @{$problems{3}}, $_;
+ }
+ }
+ $c->stash->{lists} = \%problems;
+}
+
+sub updates_search : Private {
+ my ( $self, $c, $time ) = @_;
+
+ my $params = {
+ %{$c->stash->{where}},
+ 'me.confirmed' => { '>=', $time },
+ };
+
+ my $comments = $c->model('DB::Comment')->search(
+ $params,
+ {
+ group_by => [ 'problem_state' ],
+ select => [ 'problem_state', { count => 'me.id' } ],
+ as => [ qw/state state_count/ ],
+ join => 'problem'
+ }
+ );
+
+ my %counts =
+ map { ($_->state||'-') => $_->get_column('state_count') } $comments->all;
+ %counts =
+ map { $_ => $counts{$_} || 0 }
+ ('confirmed', 'investigating', 'in progress', 'closed', 'fixed - council',
+ 'fixed - user', 'fixed', 'unconfirmed', 'hidden',
+ 'partial', 'planned');
+
+ for my $vars (
+ [ 'time_to_fix', 'fixed - council' ],
+ [ 'time_to_mark', 'in progress', 'planned', 'investigating', 'closed' ],
+ ) {
+ my $col = shift @$vars;
+ my $substmt = "select min(id) from comment where me.problem_id=comment.problem_id and problem_state in ('"
+ . join("','", @$vars) . "')";
+ $comments = $c->model('DB::Comment')->search(
+ { %$params,
+ problem_state => $vars,
+ 'me.id' => \"= ($substmt)",
+ },
+ {
+ select => [
+ { count => 'me.id' },
+ { avg => { extract => "epoch from me.confirmed-problem.confirmed" } },
+ ],
+ as => [ qw/state_count time/ ],
+ join => 'problem'
+ }
+ )->first;
+ $counts{$col} = int( ($comments->get_column('time')||0) / 60 / 60 / 24 + 0.5 );
+ }
+
+ $counts{fixed_user} = $c->model('DB::Comment')->search(
+ { %$params, mark_fixed => 1, problem_state => undef }, { join => 'problem' }
+ )->count;
+
+ $params = {
+ %{$c->stash->{prob_where}},
+ 'me.confirmed' => { '>=', $time },
+ };
+ $counts{total} = $c->cobrand->problems->search( $params )->count;
+
+ $params = {
+ %{$c->stash->{prob_where}},
+ 'me.confirmed' => { '>=', $time },
+ state => 'confirmed',
+ '(select min(id) from comment where me.id=problem_id and problem_state is not null)' => undef,
+ };
+ $counts{not_marked} = $c->cobrand->problems->search( $params )->count;
+
+ return \%counts;
+}
+
+=head1 AUTHOR
+
+Matthew Somerville
+
+=head1 LICENSE
+
+Copyright (c) 2012 UK Citizens Online Democracy. All rights reserved.
+Licensed under the Affero GPL.
+
+=cut
+
+__PACKAGE__->meta->make_immutable;
+
+1;
+
diff --git a/perllib/FixMyStreet/App/Controller/My.pm b/perllib/FixMyStreet/App/Controller/My.pm
index 3de83b265..c00264315 100644
--- a/perllib/FixMyStreet/App/Controller/My.pm
+++ b/perllib/FixMyStreet/App/Controller/My.pm
@@ -48,7 +48,7 @@ sub my : Path : Args(0) {
push @$pins, {
latitude => $problem->latitude,
longitude => $problem->longitude,
- colour => $problem->is_fixed ? 'green' : 'red',
+ colour => $c->cobrand->pin_colour( $problem, 'my' ),
id => $problem->id,
title => $problem->title,
};
diff --git a/perllib/FixMyStreet/App/Controller/Photo.pm b/perllib/FixMyStreet/App/Controller/Photo.pm
index a84c538cc..fc4c3fde7 100644
--- a/perllib/FixMyStreet/App/Controller/Photo.pm
+++ b/perllib/FixMyStreet/App/Controller/Photo.pm
@@ -6,6 +6,8 @@ BEGIN {extends 'Catalyst::Controller'; }
use DateTime::Format::HTTP;
use Digest::SHA1 qw(sha1_hex);
+use File::Path;
+use File::Slurp;
use Path::Class;
=head1 NAME
@@ -95,6 +97,10 @@ sub index :LocalRegex('^(c/)?(\d+)(?:\.(full|tn|fp))?\.jpeg$') {
sub output : Private {
my ( $self, $c, $photo ) = @_;
+ # Save to file
+ File::Path::make_path( FixMyStreet->path_to( 'web', 'photo', 'c' )->stringify );
+ File::Slurp::write_file( FixMyStreet->path_to( 'web', $c->req->path )->stringify, \$photo );
+
my $dt = DateTime->now()->add( years => 1 );
$c->res->content_type( 'image/jpeg' );
@@ -166,6 +172,7 @@ sub process_photo_upload : Private {
$ct =~ s/x-citrix-//; # Thanks, Citrix
# Had a report of a JPEG from an Android 2.1 coming through as a byte stream
unless ( $ct eq 'image/jpeg' || $ct eq 'image/pjpeg' || $ct eq 'application/octet-stream' ) {
+ $c->log->info('Bad photo tried to upload, type=' . $ct);
$c->stash->{photo_error} = _('Please upload a JPEG image only');
return;
}
diff --git a/perllib/FixMyStreet/App/Controller/Questionnaire.pm b/perllib/FixMyStreet/App/Controller/Questionnaire.pm
index fe71f3fbb..6aa4f7604 100755
--- a/perllib/FixMyStreet/App/Controller/Questionnaire.pm
+++ b/perllib/FixMyStreet/App/Controller/Questionnaire.pm
@@ -294,7 +294,7 @@ sub display : Private {
pins => [ {
latitude => $problem->latitude,
longitude => $problem->longitude,
- colour => $problem->is_fixed() ? 'green' : 'red',
+ colour => $c->cobrand->pin_colour( $problem, 'questionnaire' ),
} ],
);
}
diff --git a/perllib/FixMyStreet/App/Controller/Report.pm b/perllib/FixMyStreet/App/Controller/Report.pm
index afe180c29..cca625bd5 100644
--- a/perllib/FixMyStreet/App/Controller/Report.pm
+++ b/perllib/FixMyStreet/App/Controller/Report.pm
@@ -153,6 +153,36 @@ sub generate_map_tags : Private {
return 1;
}
+sub delete :Local :Args(1) {
+ my ( $self, $c, $id ) = @_;
+
+ $c->forward( 'load_problem_or_display_error', [ $id ] );
+ my $p = $c->stash->{problem};
+
+ my $uri = $c->uri_for( '/report', $id );
+
+ return $c->res->redirect($uri) unless $c->user_exists;
+
+ my $council = $c->user->obj->from_council;
+ return $c->res->redirect($uri) unless $council;
+
+ my %councils = map { $_ => 1 } @{$p->councils};
+ return $c->res->redirect($uri) unless $councils{$council};
+
+ $p->state('hidden');
+ $p->lastupdate( \'ms_current_timestamp()' );
+ $p->update;
+
+ $c->model('DB::AdminLog')->create( {
+ admin_user => $c->user->email,
+ object_type => 'problem',
+ action => 'state_change',
+ object_id => $id,
+ } );
+
+ return $c->res->redirect($uri);
+}
+
__PACKAGE__->meta->make_immutable;
1;
diff --git a/perllib/FixMyStreet/App/Controller/Report/New.pm b/perllib/FixMyStreet/App/Controller/Report/New.pm
index 15b5d4be5..35173816a 100644
--- a/perllib/FixMyStreet/App/Controller/Report/New.pm
+++ b/perllib/FixMyStreet/App/Controller/Report/New.pm
@@ -187,12 +187,16 @@ sub report_form_ajax : Path('ajax') : Args(0) {
my $category = $c->render_fragment( 'report/new/category.html');
my $councils_text = $c->render_fragment( 'report/new/councils_text.html');
my $has_open311 = keys %{ $c->stash->{category_extras} };
+ my $extra_name_info = $c->stash->{extra_name_info}
+ ? $c->render_fragment('report/new/extra_name.html')
+ : '';
my $body = JSON->new->utf8(1)->encode(
{
councils_text => $councils_text,
category => $category,
has_open311 => $has_open311,
+ extra_name_info => $extra_name_info,
}
);
@@ -217,7 +221,7 @@ sub category_extras_ajax : Path('category_extras') : Args(0) {
$c->forward('setup_categories_and_councils');
my $category_extra = '';
- if ( $c->stash->{category_extras}->{ $c->req->param('category') } ) {
+ if ( $c->stash->{category_extras}->{ $c->req->param('category') } && @{ $c->stash->{category_extras}->{ $c->req->param('category') } } >= 1 ) {
$c->stash->{report_meta} = {};
$c->stash->{report} = { category => $c->req->param('category') };
$c->stash->{category_extras} = { $c->req->param('category' ) => $c->stash->{category_extras}->{ $c->req->param('category') } };
@@ -457,6 +461,13 @@ sub initialize_report : Private {
}
+ if ( $c->req->param('first_name') && $c->req->param('last_name') ) {
+ $c->stash->{first_name} = $c->req->param('first_name');
+ $c->stash->{last_name} = $c->req->param('last_name');
+
+ $c->req->param( 'name', sprintf( '%s %s', $c->req->param('first_name'), $c->req->param('last_name') ) );
+ }
+
# Capture whether the map was used
$report->used_map( $c->req->param('skipped') ? 0 : 1 );
@@ -605,7 +616,7 @@ sub setup_categories_and_councils : Private {
);
$category_label = _('Property type:');
- } elsif ($first_council->{type} eq 'LBO') {
+ } elsif ($first_council->{id} != 2482 && $first_council->{type} eq 'LBO') {
$area_ids_to_list{ $first_council->{id} } = 1;
my @local_categories;
@@ -618,7 +629,7 @@ sub setup_categories_and_councils : Private {
_('-- Pick a category --'),
@local_categories
);
- $category_label = _('Category:');
+ $category_label = _('Category');
} else {
@@ -646,9 +657,10 @@ sub setup_categories_and_councils : Private {
}
if (@category_options) {
- @category_options =
- ( _('-- Pick a category --'), @category_options, _('Other') );
- $category_label = _('Category:');
+ @category_options = ( _('-- Pick a category --'), @category_options );
+ push @category_options, _('Other')
+ unless $first_council->{id} == 2482;
+ $category_label = _('Category');
}
}
@@ -658,6 +670,7 @@ sub setup_categories_and_councils : Private {
$c->stash->{category_options} = \@category_options;
$c->stash->{category_extras} = \%category_extras;
$c->stash->{category_extras_json} = encode_json \%category_extras;
+ $c->stash->{extra_name_info} = $first_council->{id} == 2482 ? 1 : 0;
my @missing_details_councils =
grep { !$area_ids_to_list{$_} } #
@@ -700,9 +713,10 @@ sub process_user : Private {
# The user is already signed in
if ( $c->user_exists ) {
my $user = $c->user->obj;
- my %params = map { $_ => scalar $c->req->param($_) } ( 'name', 'phone' );
+ my %params = map { $_ => scalar $c->req->param($_) } ( 'name', 'phone', 'fms_extra_title' );
$user->name( Utils::trim_text( $params{name} ) ) if $params{name};
$user->phone( Utils::trim_text( $params{phone} ) );
+ $user->title( Utils::trim_text( $params{fms_extra_title} ) );
$report->user( $user );
$report->name( $user->name );
return 1;
@@ -710,7 +724,7 @@ sub process_user : Private {
# Extract all the params to a hash to make them easier to work with
my %params = map { $_ => scalar $c->req->param($_) }
- ( 'email', 'name', 'phone', 'password_register' );
+ ( 'email', 'name', 'phone', 'password_register', 'fms_extra_title' );
# cleanup the email address
my $email = $params{email} ? lc $params{email} : '';
@@ -739,6 +753,7 @@ sub process_user : Private {
$report->user->phone( Utils::trim_text( $params{phone} ) );
$report->user->password( Utils::trim_text( $params{password_register} ) )
if $params{password_register};
+ $report->user->title( Utils::trim_text( $params{fms_extra_title} ) );
$report->name( Utils::trim_text( $params{name} ) );
return 1;
@@ -810,7 +825,7 @@ sub process_report : Private {
}
$report->council( $first_council->{id} );
- } elsif ( $first_council->{type} eq 'LBO') {
+ } elsif ( $first_council->{id} != 2482 && $first_council->{type} eq 'LBO') {
unless ( Utils::london_categories()->{ $report->category } ) {
$c->stash->{field_errors}->{category} = _('Please choose a category');
@@ -862,6 +877,8 @@ sub process_report : Private {
};
}
+ $c->cobrand->process_extras( $c, \@contacts, \@extra );
+
if ( @extra ) {
$c->stash->{report_meta} = \@extra;
$report->extra( \@extra );
@@ -908,6 +925,8 @@ sub check_for_errors : Private {
%{ $c->stash->{report}->check_for_errors },
);
+ # FIXME: need to check for required bromley fields here
+
# if they're got the login details wrong when signing in then
# we don't care about the name field even though it's validated
# by the user object
@@ -949,10 +968,12 @@ sub save_user_and_report : Private {
name => $report->user->name,
phone => $report->user->phone,
password => $report->user->password,
+ title => $report->user->title,
};
$report->user->name( undef );
$report->user->phone( undef );
$report->user->password( '', 1 );
+ $report->user->title( undef );
$report->user->insert();
$c->log->info($report->user->id . ' created for this report');
}
@@ -968,6 +989,7 @@ sub save_user_and_report : Private {
name => $report->user->name,
phone => $report->user->phone,
password => $report->user->password,
+ title => $report->user->title,
};
$report->user->discard_changes();
$c->log->info($report->user->id . ' exists, but is not logged in for this report');
diff --git a/perllib/FixMyStreet/App/Controller/Report/Update.pm b/perllib/FixMyStreet/App/Controller/Report/Update.pm
index 8a87fe7a2..5b0dad170 100644
--- a/perllib/FixMyStreet/App/Controller/Report/Update.pm
+++ b/perllib/FixMyStreet/App/Controller/Report/Update.pm
@@ -104,13 +104,18 @@ sub process_user : Private {
my $user = $c->user->obj;
my $name = scalar $c->req->param('name');
$user->name( Utils::trim_text( $name ) ) if $name;
+ my $title = scalar $c->req->param('fms_extra_title');
+ if ( $title ) {
+ $c->log->debug( 'user exists and title is ' . $title );
+ $user->title( Utils::trim_text( $title ) );
+ }
$update->user( $user );
return 1;
}
# Extract all the params to a hash to make them easier to work with
my %params = map { $_ => scalar $c->req->param($_) }
- ( 'rznvy', 'name', 'password_register' );
+ ( 'rznvy', 'name', 'password_register', 'fms_extra_title' );
# cleanup the email address
my $email = $params{rznvy} ? lc $params{rznvy} : '';
@@ -136,6 +141,8 @@ sub process_user : Private {
if $params{name};
$update->user->password( Utils::trim_text( $params{password_register} ) )
if $params{password_register};
+ $update->user->title( Utils::trim_text( $params{fms_extra_title} ) )
+ if $params{fms_extra_title};
return 1;
}
@@ -153,6 +160,15 @@ want to move adding these elsewhere
sub process_update : Private {
my ( $self, $c ) = @_;
+ if ( $c->req->param('first_name' ) && $c->req->param('last_name' ) ) {
+ my $first_name = $c->req->param('first_name');
+ my $last_name = $c->req->param('last_name');
+ $c->req->param('name', sprintf( '%s %s', $first_name, $last_name ) );
+
+ $c->stash->{first_name} = $first_name;
+ $c->stash->{last_name} = $last_name;
+ }
+
my %params =
map { $_ => scalar $c->req->param($_) } ( 'update', 'name', 'fixed', 'state', 'reopen' );
@@ -185,6 +201,24 @@ sub process_update : Private {
$update->problem_state( $params{state} );
}
+ if ( $c->req->param('fms_extra_title') ) {
+ my %extras = ();
+ $extras{title} = $c->req->param('fms_extra_title');
+ $extras{email_alerts_required} = $c->req->param('add_alert');
+ $update->extra( \%extras );
+
+ $c->stash->{fms_extra_title} = $c->req->param('fms_extra_title');
+ }
+
+ if ( $c->stash->{ first_name } && $c->stash->{ last_name } ) {
+ my $extra = $update->extra || {};
+ $extra->{first_name} = $c->stash->{ first_name };
+ $extra->{last_name} = $c->stash->{ last_name };
+ $update->extra( $extra );
+ }
+
+ $c->log->debug( 'name is ' . $c->req->param('name') );
+
$c->stash->{update} = $update;
$c->stash->{add_alert} = $c->req->param('add_alert');
@@ -268,6 +302,7 @@ sub save_update : Private {
}
elsif ( $c->user && $c->user->id == $update->user->id ) {
# Logged in and same user, so can confirm update straight away
+ $c->log->debug( 'user exists' );
$update->user->update;
$update->confirm;
} else {
diff --git a/perllib/FixMyStreet/App/Controller/Static.pm b/perllib/FixMyStreet/App/Controller/Static.pm
index d4b7a1b83..723f0f2e1 100755
--- a/perllib/FixMyStreet/App/Controller/Static.pm
+++ b/perllib/FixMyStreet/App/Controller/Static.pm
@@ -22,13 +22,6 @@ sub about : Global : Args(0) {
# don't need to do anything here - should just pass through.
}
-sub for_councils : Path('/for-councils') : Args(0) {
- my ( $self, $c ) = @_;
-}
-sub for_councils_faq : Path('/for-councils/faq') : Args(0) {
- my ( $self, $c ) = @_;
-}
-
sub privacy : Global : Args(0) {
my ( $self, $c ) = @_;
}
diff --git a/perllib/FixMyStreet/App/Controller/Tokens.pm b/perllib/FixMyStreet/App/Controller/Tokens.pm
index b974f94e6..1434838f2 100644
--- a/perllib/FixMyStreet/App/Controller/Tokens.pm
+++ b/perllib/FixMyStreet/App/Controller/Tokens.pm
@@ -71,6 +71,7 @@ sub confirm_problem : Path('/P') {
$problem->user->name( $data->{name} ) if $data->{name};
$problem->user->phone( $data->{phone} ) if $data->{phone};
$problem->user->password( $data->{password}, 1 ) if $data->{password};
+ $problem->user->title( $data->{title} ) if $data->{title};
$problem->user->update;
}
$c->authenticate( { email => $problem->user->email }, 'no_password' );
diff --git a/perllib/FixMyStreet/App/Model/EmailSend.pm b/perllib/FixMyStreet/App/Model/EmailSend.pm
index 73086c65f..761856bde 100644
--- a/perllib/FixMyStreet/App/Model/EmailSend.pm
+++ b/perllib/FixMyStreet/App/Model/EmailSend.pm
@@ -35,7 +35,7 @@ elsif ( my $smtp_host = FixMyStreet->config('SMTP_SMARTHOST') ) {
# Email::Send::SMTP
$args = {
- mailer => 'SMTP',
+ mailer => 'FixMyStreet::EmailSend',
mailer_args => [ Host => $smtp_host ],
};
}
diff --git a/perllib/FixMyStreet/Cobrand.pm b/perllib/FixMyStreet/Cobrand.pm
index 647261e32..b88f6facc 100644
--- a/perllib/FixMyStreet/Cobrand.pm
+++ b/perllib/FixMyStreet/Cobrand.pm
@@ -109,4 +109,22 @@ sub get_class_for_moniker {
return 'FixMyStreet::Cobrand::Default';
}
+=head2 exists
+
+ FixMyStreet::Cobrand->exists( $moniker );
+
+Given a moniker, returns true if that cobrand is available to us for use
+
+=cut
+
+sub exists {
+ my ( $class, $moniker ) = @_;
+
+ foreach my $avail ( $class->available_cobrand_classes ) {
+ return 1 if $moniker eq $avail->{moniker};
+ }
+
+ return 0;
+}
+
1;
diff --git a/perllib/FixMyStreet/Cobrand/Barnet.pm b/perllib/FixMyStreet/Cobrand/Barnet.pm
index 6f115ec63..b3876a2c6 100644
--- a/perllib/FixMyStreet/Cobrand/Barnet.pm
+++ b/perllib/FixMyStreet/Cobrand/Barnet.pm
@@ -8,16 +8,100 @@ sub council_id { return 2489; }
sub council_area { return 'Barnet'; }
sub council_name { return 'Barnet Council'; }
sub council_url { return 'barnet'; }
+sub all_reports_style { return 'detailed'; }
+
+sub path_to_web_templates {
+ my $self = shift;
+ return [
+ FixMyStreet->path_to( 'templates/web', $self->moniker )->stringify,
+ FixMyStreet->path_to( 'templates/web/fixmystreet' )->stringify
+ ];
+}
sub disambiguate_location {
my $self = shift;
return {
%{ $self->SUPER::disambiguate_location() },
+ town => 'Barnet',
centre => '51.612832,-0.218169',
span => '0.0563,0.09',
bounds => [ '51.584682,-0.263169', '51.640982,-0.173169' ],
};
}
+sub generate_problem_banner {
+ my ( $self, $problem ) = @_;
+
+ my $banner = {};
+ if ( $problem->is_open && time() - $problem->lastupdate_local->epoch > 8 * 7 * 24 * 60 * 60 )
+ {
+ $banner->{id} = 'unknown';
+ $banner->{text} = _('Unknown');
+ }
+ if ($problem->is_fixed) {
+ $banner->{id} = 'fixed';
+ $banner->{text} = _('Fixed');
+ }
+ if ($problem->is_closed) {
+ $banner->{id} = 'closed';
+ $banner->{text} = _('Closed');
+ }
+
+ if ( grep { $problem->state eq $_ } ( 'investigating', 'in progress', 'planned' ) ) {
+ $banner->{id} = 'progress';
+ $banner->{text} = _('In progress');
+ }
+
+ return $banner;
+}
+
+sub council_rss_alert_options {
+ my $self = shift;
+ my $all_councils = shift;
+ my $c = shift;
+
+ my %councils = map { $_ => 1 } $self->area_types();
+
+ my $num_councils = scalar keys %$all_councils;
+
+ my ( @options, @reported_to_options );
+ if ( $num_councils == 1 or $num_councils == 2 ) {
+ my ($council, $ward);
+ foreach (values %$all_councils) {
+ if ($councils{$_->{type}}) {
+ $council = $_;
+ $council->{short_name} = $self->short_name( $council );
+ ( $council->{id_name} = $council->{short_name} ) =~ tr/+/_/;
+ } else {
+ $ward = $_;
+ $ward->{short_name} = $self->short_name( $ward );
+ ( $ward->{id_name} = $ward->{short_name} ) =~ tr/+/_/;
+ }
+ }
+
+ push @options,
+ {
+ type => 'council',
+ id => sprintf( 'council:%s:%s', $council->{id}, $council->{id_name} ),
+ text => 'All problems within the council.',
+ rss_text => sprintf( _('RSS feed of problems within %s'), $council->{name}),
+ uri => $c->uri_for( '/rss/reports/' . $council->{short_name} ),
+ };
+ push @options,
+ {
+ type => 'ward',
+ id => sprintf( 'ward:%s:%s:%s:%s', $council->{id}, $ward->{id}, $council->{id_name}, $ward->{id_name} ),
+ rss_text => sprintf( _('RSS feed of problems within %s ward'), $ward->{name}),
+ text => sprintf( _('Problems within %s ward'), $ward->{name}),
+ uri => $c->uri_for( '/rss/reports/' . $council->{short_name} . '/' . $ward->{short_name} ),
+ } if $ward;
+ }
+
+ return ( \@options, @reported_to_options ? \@reported_to_options : undef );
+}
+
+sub example_places {
+ return [ 'N11 1NP', 'Wood St' ];
+}
1;
diff --git a/perllib/FixMyStreet/Cobrand/Bromley.pm b/perllib/FixMyStreet/Cobrand/Bromley.pm
index 75174b638..c5c6c6345 100644
--- a/perllib/FixMyStreet/Cobrand/Bromley.pm
+++ b/perllib/FixMyStreet/Cobrand/Bromley.pm
@@ -1,5 +1,7 @@
package FixMyStreet::Cobrand::Bromley;
-use base 'FixMyStreet::Cobrand::UKCouncils';
+use mro 'c3';
+use parent 'FixMyStreet::Cobrand::FixMyStreet';
+use parent 'FixMyStreet::Cobrand::UKCouncils';
use strict;
use warnings;
@@ -8,6 +10,14 @@ sub council_id { return 2482; }
sub council_area { return 'Bromley'; }
sub council_name { return 'Bromley Council'; }
sub council_url { return 'bromley'; }
+sub all_reports_style { return 'detailed'; }
+
+sub base_url {
+ return FixMyStreet->config('BASE_URL') if FixMyStreet->config('STAGING_SITE');
+ return 'https://fix.bromley.gov.uk';
+}
+
+sub admin_base_url { '' }
sub path_to_web_templates {
my $self = shift;
@@ -17,10 +27,19 @@ sub path_to_web_templates {
];
}
+sub site_title {
+ my ($self) = @_;
+ return "London Borough of Bromley - Report a problem in Bromley\x{2019}s streets or parks";
+}
+sub site_name {
+ return 'Bromley FixMyStreet';
+}
+
sub disambiguate_location {
my $self = shift;
return {
%{ $self->SUPER::disambiguate_location() },
+ town => 'Bromley',
centre => '51.366836,0.040623',
span => '0.154963,0.24347',
bounds => [ '51.289355,-0.081112', '51.444318,0.162358' ],
@@ -31,5 +50,46 @@ sub example_places {
return ( 'BR1 3UH', 'Glebe Rd, Bromley' );
}
+sub map_type {
+ 'Bromley';
+}
+
+sub on_map_default_max_pin_age {
+ return '1 month';
+}
+
+# Bromley pins always yellow
+sub pin_colour {
+ my ( $self, $p, $context ) = @_;
+ return 'yellow';
+}
+
+sub recent_photos {
+ my ( $self, $area, $num, $lat, $lon, $dist ) = @_;
+ $num = 3 if $num > 3 && $area eq 'alert';
+ return $self->problems->recent_photos( $num, $lat, $lon, $dist );
+}
+
+sub send_questionnaires {
+ return 0;
+}
+
+sub ask_ever_reported {
+ return 0;
+}
+
+sub process_extras {
+ my $self = shift;
+ $self->SUPER::process_extras( @_, [ 'first_name', 'last_name' ] );
+}
+
+sub contact_email {
+ my $self = shift;
+ my $type = shift || '';
+ return join( '@', 'info', 'bromley.gov.uk' ) if $type eq 'contact';
+ return $self->next::method();
+}
+sub contact_name { 'Bromley Council (do not reply)'; }
+
1;
diff --git a/perllib/FixMyStreet/Cobrand/Default.pm b/perllib/FixMyStreet/Cobrand/Default.pm
index c45c36b0b..b06c534ac 100644
--- a/perllib/FixMyStreet/Cobrand/Default.pm
+++ b/perllib/FixMyStreet/Cobrand/Default.pm
@@ -97,7 +97,7 @@ Base URL for the admin interface.
=cut
-sub admin_base_url { 0 }
+sub admin_base_url { '' }
=head2 writetothem_url
@@ -136,6 +136,15 @@ Parameter is QUERY
sub enter_postcode_text { '' }
+=head2 all_reports_style
+
+Return the type of problem information to display on the all reports
+pages for councils. Can be either simple or detailed.
+
+=cut
+
+sub all_reports_style { return 'simple'; }
+
=head2 set_lang_and_domain
my $set_lang = $cobrand->set_lang_and_domain( $lang, $unicode, $dir )
@@ -173,6 +182,7 @@ EASTING and NORTHING.
sub recent_photos {
my $self = shift;
+ my $area = shift;
return $self->problems->recent_photos(@_);
}
@@ -350,6 +360,27 @@ Return the title to be used in page heads.
sub site_title { 'FixMyStreet' }
+=head2 site_name
+
+Return short name for use in emails.
+
+=cut
+sub site_name {
+ my $self = shift;
+ $self->site_title;
+}
+
+=head2 map_type
+
+Return an override type of map if necessary.
+
+=cut
+sub map_type {
+ my $self = shift;
+ return 'OSM' if $self->{c}->req->uri->host =~ /^osm\./;
+ return;
+}
+
=head2 on_map_list_limit
Return the maximum number of items to be given in the list of reports on the map
@@ -576,6 +607,14 @@ first time they' ve reported a problem
sub ask_ever_reported { 1 }
+=head2 send_questionnaires
+
+Return a boolean indicating whether people should be sent questionnaire emails.
+
+=cut
+
+sub send_questionnaires { 1 }
+
=head2 admin_pages
List of names of pages to display on the admin interface
@@ -740,6 +779,8 @@ sub council_rss_alert_options {
( $ward->{id_name} = $ward->{short_name} ) =~ tr/+/_/;
}
}
+ $council->{name} = 'London Borough of Bromley'
+ if $council->{name} eq 'Bromley Council';
push @options,
{
@@ -916,9 +957,26 @@ Get stats to display on the council reports page
sub get_report_stats { return 0; }
+sub get_council_sender { return 'Email' };
+
sub example_places {
return [ 'B2 4QA', 'Tib St, Manchester' ];
}
+sub process_extras {}
+
+=head 2 pin_colour
+
+Returns the colour of pin to be used for a particular report
+(so perhaps different depending upon the age of the report).
+
+=cut
+sub pin_colour {
+ my ( $self, $p, $context ) = @_;
+ #return 'green' if time() - $p->confirmed_local->epoch < 7 * 24 * 60 * 60;
+ return 'yellow' if $context eq 'around';
+ return $p->is_fixed ? 'green' : 'red';
+}
+
1;
diff --git a/perllib/FixMyStreet/Cobrand/FixMyStreet.pm b/perllib/FixMyStreet/Cobrand/FixMyStreet.pm
index 97b4c3c8b..c2ba60786 100644
--- a/perllib/FixMyStreet/Cobrand/FixMyStreet.pm
+++ b/perllib/FixMyStreet/Cobrand/FixMyStreet.pm
@@ -6,6 +6,27 @@ sub restriction {
return {};
}
+sub admin_base_url {
+ return 'https://secure.mysociety.org/admin/bci/';
+}
+
+sub get_council_sender {
+ my ( $self, $area_id, $area_info ) = @_;
+
+ my $send_method;
+
+ my $council_config = FixMyStreet::App->model("DB::Open311conf")->search( { area_id => $area_id } )->first;
+ $send_method = $council_config->send_method if $council_config;
+
+ return $send_method if $send_method;
+
+ return 'London' if $area_info->{type} eq 'LBO';
+
+ return 'Email';
+}
+
+sub all_reports_style { return 'detailed'; }
+
sub generate_problem_banner {
my ( $self, $problem ) = @_;
@@ -32,5 +53,33 @@ sub generate_problem_banner {
return $banner;
}
+sub process_extras {
+ my $self = shift;
+ my $ctx = shift;
+ my $contacts = shift;
+ my $extra = shift;
+ my $fields = shift || [];
+
+ if ( $contacts->[0]->area_id == 2482 ) {
+ my @fields = ( 'fms_extra_title', @$fields );
+ for my $field ( @fields ) {
+ my $value = $ctx->request->param( $field );
+
+ if ( !$value ) {
+ $ctx->stash->{field_errors}->{ $field } = _('This information is required');
+ }
+ push @$extra, {
+ name => $field,
+ description => uc( $field),
+ value => $value || '',
+ };
+ }
+
+ if ( $ctx->request->param('fms_extra_title') ) {
+ $ctx->stash->{fms_extra_title} = $ctx->request->param('fms_extra_title');
+ $ctx->stash->{extra_name_info} = 1;
+ }
+ }
+}
1;
diff --git a/perllib/FixMyStreet/Cobrand/LichfieldDC.pm b/perllib/FixMyStreet/Cobrand/LichfieldDC.pm
index 4d93aaf76..804289d34 100644
--- a/perllib/FixMyStreet/Cobrand/LichfieldDC.pm
+++ b/perllib/FixMyStreet/Cobrand/LichfieldDC.pm
@@ -26,7 +26,7 @@ sub disambiguate_location {
%{ $self->SUPER::disambiguate_location() },
centre => '52.688198,-1.804966',
span => '0.1196,0.218675',
- bounds => [ '52.807793,-1.586291', '52.584891,-1.963232' ],
+ bounds => [ '52.584891,-1.963232', '52.807793,-1.586291' ],
};
}
diff --git a/perllib/FixMyStreet/Cobrand/UKCouncils.pm b/perllib/FixMyStreet/Cobrand/UKCouncils.pm
index b40f13d9d..8a6954418 100644
--- a/perllib/FixMyStreet/Cobrand/UKCouncils.pm
+++ b/perllib/FixMyStreet/Cobrand/UKCouncils.pm
@@ -7,6 +7,10 @@ use warnings;
use Carp;
use URI::Escape;
+sub is_council {
+ 1;
+}
+
sub site_restriction {
my $self = shift;
return ( "and council='" . $self->council_id . "'", $self->council_url, { council => sprintf('%d', $self->council_id) } );
@@ -56,9 +60,16 @@ sub council_check {
return 1;
}
my $url = 'http://www.fixmystreet.com/';
- $url .= 'alert' if $context eq 'alert';
+ if ($context eq 'alert') {
+ $url .= 'alert';
+ } else {
+ $url .= 'around';
+ }
$url .= '?pc=' . URI::Escape::uri_escape( $self->{c}->req->param('pc') )
if $self->{c}->req->param('pc');
+ $url .= '?latitude=' . URI::Escape::uri_escape( $self->{c}->req->param('latitude') )
+ . '&amp;longitude=' . URI::Escape::uri_escape( $self->{c}->req->param('longitude') )
+ if $self->{c}->req->param('latitude');
my $error_msg = "That location is not covered by " . $self->council_name . ".
Please visit <a href=\"$url\">the main FixMyStreet site</a>.";
return ( 0, $error_msg );
@@ -70,10 +81,24 @@ sub all_councils_report {
}
sub recent_photos {
- my ( $self, $num, $lat, $lon, $dist ) = @_;
+ my ( $self, $area, $num, $lat, $lon, $dist ) = @_;
$num = 2 if $num == 3;
return $self->problems->recent_photos( $num, $lat, $lon, $dist );
}
-1;
+sub get_council_sender {
+ my ( $self, $area_id, $area_info ) = @_;
+
+ my $send_method;
+
+ my $council_config = FixMyStreet::App->model("DB::Open311conf")->search( { area_id => $area_id } )->first;
+ $send_method = $council_config->send_method if $council_config;
+ return $send_method if $send_method;
+
+ return 'London' if $area_info->{type} eq 'LBO';
+
+ return 'Email';
+}
+
+1;
diff --git a/perllib/FixMyStreet/DB/Result/Comment.pm b/perllib/FixMyStreet/DB/Result/Comment.pm
index 5b45c63a8..91695d7d0 100644
--- a/perllib/FixMyStreet/DB/Result/Comment.pm
+++ b/perllib/FixMyStreet/DB/Result/Comment.pm
@@ -54,6 +54,18 @@ __PACKAGE__->add_columns(
{ data_type => "boolean", default_value => \"false", is_nullable => 0 },
"problem_state",
{ data_type => "text", is_nullable => 1 },
+ "external_id",
+ { data_type => "text", is_nullable => 1 },
+ "extra",
+ { data_type => "text", is_nullable => 1 },
+ "send_fail_count",
+ { data_type => "integer", default_value => 0, is_nullable => 0 },
+ "send_fail_reason",
+ { data_type => "text", is_nullable => 1 },
+ "send_fail_timestamp",
+ { data_type => "timestamp", is_nullable => 1 },
+ "whensent",
+ { data_type => "timestamp", is_nullable => 1 },
);
__PACKAGE__->set_primary_key("id");
__PACKAGE__->belongs_to(
@@ -70,13 +82,34 @@ __PACKAGE__->belongs_to(
);
-# Created by DBIx::Class::Schema::Loader v0.07017 @ 2012-03-08 17:19:55
-# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:E+96vo/AB0zz1jAEPj/OKw
+# Created by DBIx::Class::Schema::Loader v0.07017 @ 2012-03-26 15:44:18
+# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:nvkElEgSU6XcLd9znSqhmQ
+
+__PACKAGE__->filter_column(
+ extra => {
+ filter_from_storage => sub {
+ my $self = shift;
+ my $ser = shift;
+ return undef unless defined $ser;
+ my $h = new IO::String($ser);
+ return RABX::wire_rd($h);
+ },
+ filter_to_storage => sub {
+ my $self = shift;
+ my $data = shift;
+ my $ser = '';
+ my $h = new IO::String($ser);
+ RABX::wire_wr( $data, $h );
+ return $ser;
+ },
+ }
+);
use DateTime::TimeZone;
use Image::Size;
use Moose;
use namespace::clean -except => [ 'meta' ];
+use RABX;
with 'FixMyStreet::Roles::Abuser';
diff --git a/perllib/FixMyStreet/DB/Result/Open311conf.pm b/perllib/FixMyStreet/DB/Result/Open311conf.pm
index 742a12ebd..c95b0c8f2 100644
--- a/perllib/FixMyStreet/DB/Result/Open311conf.pm
+++ b/perllib/FixMyStreet/DB/Result/Open311conf.pm
@@ -28,13 +28,30 @@ __PACKAGE__->add_columns(
{ data_type => "text", is_nullable => 1 },
"send_method",
{ data_type => "text", is_nullable => 1 },
+ "send_comments",
+ { data_type => "boolean", default_value => \"false", is_nullable => 0 },
+ "comment_user_id",
+ { data_type => "integer", is_foreign_key => 1, is_nullable => 1 },
+ "suppress_alerts",
+ { data_type => "boolean", default_value => \"false", is_nullable => 0 },
);
__PACKAGE__->set_primary_key("id");
__PACKAGE__->add_unique_constraint("open311conf_area_id_key", ["area_id"]);
+__PACKAGE__->belongs_to(
+ "comment_user",
+ "FixMyStreet::DB::Result::User",
+ { id => "comment_user_id" },
+ {
+ is_deferrable => 1,
+ join_type => "LEFT",
+ on_delete => "CASCADE",
+ on_update => "CASCADE",
+ },
+);
-# Created by DBIx::Class::Schema::Loader v0.07017 @ 2012-03-08 17:19:55
-# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:ClYnPB2gsKapnfHuco5d/w
+# Created by DBIx::Class::Schema::Loader v0.07017 @ 2012-05-11 13:30:31
+# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:ByJbRe/Y/9Z1WHdG8kaIHg
# You can replace this text with custom code or comments, and it will be preserved on regeneration
diff --git a/perllib/FixMyStreet/DB/Result/Problem.pm b/perllib/FixMyStreet/DB/Result/Problem.pm
index 532c209d8..9cbaef6c2 100644
--- a/perllib/FixMyStreet/DB/Result/Problem.pm
+++ b/perllib/FixMyStreet/DB/Result/Problem.pm
@@ -85,7 +85,7 @@ __PACKAGE__->add_columns(
"geocode",
{ data_type => "bytea", is_nullable => 1 },
"send_fail_count",
- { data_type => "integer", default_value => 0, is_nullable => 0 },
+ { data_type => "integer", is_nullable => 1 },
"send_fail_reason",
{ data_type => "text", is_nullable => 1 },
"send_fail_timestamp",
@@ -704,6 +704,17 @@ sub update_from_open311_service_request {
return 1;
}
+sub update_send_failed {
+ my $self = shift;
+ my $msg = shift;
+
+ $self->update( {
+ send_fail_count => $self->send_fail_count + 1,
+ send_fail_timestamp => \'ms_current_timestamp()',
+ send_fail_reason => $msg
+ } );
+}
+
# we need the inline_constructor bit as we don't inherit from Moose
__PACKAGE__->meta->make_immutable( inline_constructor => 0 );
diff --git a/perllib/FixMyStreet/DB/Result/User.pm b/perllib/FixMyStreet/DB/Result/User.pm
index e13d88b88..7f43d1a52 100644
--- a/perllib/FixMyStreet/DB/Result/User.pm
+++ b/perllib/FixMyStreet/DB/Result/User.pm
@@ -30,6 +30,8 @@ __PACKAGE__->add_columns(
{ data_type => "integer", is_nullable => 1 },
"flagged",
{ data_type => "boolean", default_value => \"false", is_nullable => 0 },
+ "title",
+ { data_type => "text", is_nullable => 1 },
);
__PACKAGE__->set_primary_key("id");
__PACKAGE__->add_unique_constraint("users_email_key", ["email"]);
@@ -46,6 +48,12 @@ __PACKAGE__->has_many(
{ cascade_copy => 0, cascade_delete => 0 },
);
__PACKAGE__->has_many(
+ "open311confs",
+ "FixMyStreet::DB::Result::Open311conf",
+ { "foreign.comment_user_id" => "self.id" },
+ { cascade_copy => 0, cascade_delete => 0 },
+);
+__PACKAGE__->has_many(
"problems",
"FixMyStreet::DB::Result::Problem",
{ "foreign.user_id" => "self.id" },
@@ -53,8 +61,8 @@ __PACKAGE__->has_many(
);
-# Created by DBIx::Class::Schema::Loader v0.07017 @ 2012-03-08 17:19:55
-# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:tM1LUGrqDeQnF4BDgnYXGQ
+# Created by DBIx::Class::Schema::Loader v0.07017 @ 2012-05-01 16:20:29
+# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:LKi8u5IYnHW1+Mez64nvGg
__PACKAGE__->add_columns(
"password" => {
@@ -172,4 +180,22 @@ sub belongs_to_council {
return 0;
}
+=head2 split_name
+
+ $name = $user->split_name;
+ printf( 'Welcome %s %s', $name->{first}, $name->{last} );
+
+Returns a hashref with first and last keys with first name(s) and last name.
+NB: the spliting algorithm is extremely basic.
+
+=cut
+
+sub split_name {
+ my $self = shift;
+
+ my ($first, $last) = $self->name =~ /^(\S*)(?: (.*))?$/;
+
+ return { first => $first || '', last => $last || '' };
+}
+
1;
diff --git a/perllib/FixMyStreet/DB/ResultSet/Problem.pm b/perllib/FixMyStreet/DB/ResultSet/Problem.pm
index 3557e77c7..a7738becf 100644
--- a/perllib/FixMyStreet/DB/ResultSet/Problem.pm
+++ b/perllib/FixMyStreet/DB/ResultSet/Problem.pm
@@ -4,6 +4,16 @@ use base 'DBIx::Class::ResultSet';
use strict;
use warnings;
+use CronFns;
+
+use Utils;
+use mySociety::Config;
+use mySociety::EmailUtil;
+use mySociety::MaPit;
+
+use FixMyStreet::App;
+use FixMyStreet::SendReport;
+
my $site_restriction;
my $site_key;
@@ -209,4 +219,209 @@ sub categories_summary {
return \%categories;
}
+sub send_reports {
+ # Set up site, language etc.
+ my ($verbose, $nomail) = CronFns::options();
+ my $base_url = mySociety::Config::get('BASE_URL');
+ my $site = CronFns::site($base_url);
+
+ my $unsent = FixMyStreet::App->model("DB::Problem")->search( {
+ state => [ 'confirmed', 'fixed' ],
+ whensent => undef,
+ council => { '!=', undef },
+ } );
+ my (%notgot, %note);
+
+ my $send_report = FixMyStreet::SendReport->new();
+ my $senders = $send_report->get_senders;
+ my %sending_skipped_by_method;
+
+ while (my $row = $unsent->next) {
+
+ my $cobrand = FixMyStreet::Cobrand->get_class_for_moniker($row->cobrand)->new();
+
+ # Cobranded and non-cobranded messages can share a database. In this case, the conf file
+ # should specify a vhost to send the reports for each cobrand, so that they don't get sent
+ # more than once if there are multiple vhosts running off the same database. The email_host
+ # call checks if this is the host that sends mail for this cobrand.
+ next unless $cobrand->email_host();
+ $cobrand->set_lang_and_domain($row->lang, 1);
+ if ( $row->is_from_abuser ) {
+ $row->update( { state => 'hidden' } );
+ next;
+ }
+
+ # Template variables for the email
+ my $email_base_url = $cobrand->base_url_for_emails($row->cobrand_data);
+ my %h = map { $_ => $row->$_ } qw/id title detail name category latitude longitude used_map/;
+ map { $h{$_} = $row->user->$_ } qw/email phone/;
+ $h{confirmed} = DateTime::Format::Pg->format_datetime( $row->confirmed->truncate (to => 'second' ) );
+
+ $h{query} = $row->postcode;
+ $h{url} = $email_base_url . '/report/' . $row->id;
+ $h{phone_line} = $h{phone} ? _('Phone:') . " $h{phone}\n\n" : '';
+ if ($row->photo) {
+ $h{has_photo} = _("This web page also contains a photo of the problem, provided by the user.") . "\n\n";
+ $h{image_url} = $email_base_url . '/photo/' . $row->id . '.full.jpeg';
+ } else {
+ $h{has_photo} = '';
+ $h{image_url} = '';
+ }
+ $h{fuzzy} = $row->used_map ? _('To view a map of the precise location of this issue')
+ : _('The user could not locate the problem on a map, but to see the area around the location they entered');
+ $h{closest_address} = '';
+
+ # If we are in the UK include eastings and northings, and nearest stuff
+ $h{easting_northing} = '';
+ if ( $cobrand->country eq 'GB' ) {
+
+ ( $h{easting}, $h{northing} ) = Utils::convert_latlon_to_en( $h{latitude}, $h{longitude} );
+
+ # email templates don't have conditionals so we need to farmat this here
+ $h{easting_northing} #
+ = "Easting: $h{easting}\n\n" #
+ . "Northing: $h{northing}\n\n";
+
+ }
+
+ if ( $row->used_map ) {
+ $h{closest_address} = $cobrand->find_closest( $h{latitude}, $h{longitude}, $row );
+ }
+
+ my %reporters = ();
+ my (@to, @recips, $template, $areas_info, $sender_count );
+ if ($site eq 'emptyhomes') {
+
+ my $council = $row->council;
+ $areas_info = mySociety::MaPit::call('areas', $council);
+ my $name = $areas_info->{$council}->{name};
+ my $sender = "FixMyStreet::SendReport::EmptyHomes";
+ $reporters{ $sender } = $sender->new() unless $reporters{$sender};
+ $reporters{ $sender }->add_council( $council, $name );
+ $template = Utils::read_file("$FindBin::Bin/../templates/email/emptyhomes/" . $row->lang . "/submit.txt");
+
+ } else {
+
+ # XXX Needs locks!
+ my @all_councils = split /,|\|/, $row->council;
+ my ($councils, $missing) = $row->council =~ /^([\d,]+)(?:\|([\d,]+))?/;
+ my @councils = split(/,/, $councils);
+ $areas_info = mySociety::MaPit::call('areas', \@all_councils);
+ my @dear;
+
+ foreach my $council (@councils) {
+ my $name = $areas_info->{$council}->{name};
+
+ my $sender = $cobrand->get_council_sender( $council, $areas_info->{$council} );
+ $sender = "FixMyStreet::SendReport::$sender";
+
+ if ( ! exists $senders->{ $sender } ) {
+ warn "No such sender [ $sender ] for council $name ( $council )";
+ next;
+ }
+ $reporters{ $sender } ||= $sender->new();
+
+ if ( $reporters{ $sender }->should_skip( $row ) ) {
+ $sending_skipped_by_method{ $sender }++ if
+ $reporters{ $sender }->skipped;
+ } else {
+ push @dear, $name;
+ $reporters{ $sender }->add_council( $council, $name );
+ }
+ }
+
+ $template = 'submit.txt';
+ $template = 'submit-brent.txt' if $row->council eq 2488 || $row->council eq 2237;
+ my $template_path = FixMyStreet->path_to( "templates", "email", $cobrand->moniker, $template )->stringify;
+ $template_path = FixMyStreet->path_to( "templates", "email", "default", $template )->stringify
+ unless -e $template_path;
+ $template = Utils::read_file( $template_path );
+
+ if ($h{category} eq _('Other')) {
+ $h{category_footer} = _('this type of local problem');
+ $h{category_line} = '';
+ } else {
+ $h{category_footer} = "'" . $h{category} . "'";
+ $h{category_line} = sprintf(_("Category: %s"), $h{category}) . "\n\n";
+ }
+
+ $h{councils_name} = join(_(' and '), @dear);
+ if ($h{category} eq _('Other')) {
+ $h{multiple} = @dear>1 ? "[ " . _("This email has been sent to both councils covering the location of the problem, as the user did not categorise it; please ignore it if you're not the correct council to deal with the issue, or let us know what category of problem this is so we can add it to our system.") . " ]\n\n"
+ : '';
+ } else {
+ $h{multiple} = @dear>1 ? "[ " . _("This email has been sent to several councils covering the location of the problem, as the category selected is provided for all of them; please ignore it if you're not the correct council to deal with the issue.") . " ]\n\n"
+ : '';
+ }
+ $h{missing} = '';
+ if ($missing) {
+ my $name = $areas_info->{$missing}->{name};
+ $h{missing} = '[ '
+ . sprintf(_('We realise this problem might be the responsibility of %s; however, we don\'t currently have any contact details for them. If you know of an appropriate contact address, please do get in touch.'), $name)
+ . " ]\n\n";
+ }
+
+ $sender_count = scalar @dear;
+ }
+
+ unless ( keys %reporters ) {
+ die 'Report not going anywhere for ID ' . $row->id . '!';
+ }
+
+ next unless $sender_count;
+
+ if (mySociety::Config::get('STAGING_SITE')) {
+ # on a staging server send emails to ourselves rather than the councils
+ my @testing_councils = split( '\|', mySociety::Config::get('TESTING_COUNCILS') );
+ unless ( grep { $row->council eq $_ } @testing_councils ) {
+ %reporters = (
+ 'FixMyStreet::SendReport::Email' => $reporters{ 'FixMyStreet::SendReport::Email' } || FixMyStreet::SendReport::Email->new()
+ );
+ }
+ }
+
+ # Multiply results together, so one success counts as a success.
+ my $result = -1;
+
+ for my $sender ( keys %reporters ) {
+ $result *= $reporters{ $sender }->send(
+ $row, \%h, \@to, $template, \@recips, $nomail, $areas_info
+ );
+ }
+
+ if ($result == mySociety::EmailUtil::EMAIL_SUCCESS) {
+ $row->update( {
+ whensent => \'ms_current_timestamp()',
+ lastupdate => \'ms_current_timestamp()',
+ } );
+ } else {
+ my @errors;
+ for my $sender ( keys %reporters ) {
+ unless ( $reporters{ $sender }->success ) {
+ push @errors, $reporters{ $sender }->error;
+ }
+ }
+ $row->update_send_failed( join( '|', @errors ) );
+ }
+ }
+
+ if ($verbose) {
+ print "Council email addresses that need checking:\n" if keys %notgot;
+ foreach my $e (keys %notgot) {
+ foreach my $c (keys %{$notgot{$e}}) {
+ print $notgot{$e}{$c} . " problem, to $e category $c (" . $note{$e}{$c}. ")\n";
+ }
+ }
+ if (keys %sending_skipped_by_method) {
+ my $c = 0;
+ print "\nProblem reports that send-reports did not attempt to send the following:\n";
+ foreach my $send_method (sort keys %sending_skipped_by_method) {
+ printf " %-24s %4d\n", "$send_method:", $sending_skipped_by_method{$send_method};
+ $c+=$sending_skipped_by_method{$send_method};
+ }
+ printf " %-24s %4d\n", "Total:", $c;
+ }
+ }
+}
+
1;
diff --git a/perllib/FixMyStreet/DB/ResultSet/Questionnaire.pm b/perllib/FixMyStreet/DB/ResultSet/Questionnaire.pm
index 0cf01b6d1..753eb2084 100644
--- a/perllib/FixMyStreet/DB/ResultSet/Questionnaire.pm
+++ b/perllib/FixMyStreet/DB/ResultSet/Questionnaire.pm
@@ -48,6 +48,9 @@ sub send_questionnaires_period {
my $cobrand = FixMyStreet::Cobrand->get_class_for_moniker($row->cobrand)->new();
$cobrand->set_lang_and_domain($row->lang, 1);
+ # Not all cobrands send questionnaires
+ next unless $cobrand->send_questionnaires;
+
# Cobranded and non-cobranded messages can share a database. In this case, the conf file
# should specify a vhost to send the reports for each cobrand, so that they don't get sent
# more than once if there are multiple vhosts running off the same database. The email_host
diff --git a/perllib/FixMyStreet/EmailSend.pm b/perllib/FixMyStreet/EmailSend.pm
new file mode 100644
index 000000000..61d8a70c2
--- /dev/null
+++ b/perllib/FixMyStreet/EmailSend.pm
@@ -0,0 +1,12 @@
+package FixMyStreet::EmailSend;
+use base Email::Send::SMTP;
+
+sub get_env_sender {
+ # Should really use cobrand's contact_email function, but not sure how
+ # best to access that from in here.
+ my $sender = FixMyStreet->config('CONTACT_EMAIL');
+ $sender =~ s/team/fms-DO-NOT-REPLY/;
+ return $sender;
+}
+
+1;
diff --git a/perllib/FixMyStreet/Geocode/Bing.pm b/perllib/FixMyStreet/Geocode/Bing.pm
index a24f7c102..3bbb9dcdc 100644
--- a/perllib/FixMyStreet/Geocode/Bing.pm
+++ b/perllib/FixMyStreet/Geocode/Bing.pm
@@ -44,8 +44,6 @@ sub string {
if (!$js) {
return { error => _('Sorry, we could not parse that location. Please try again.') };
- } elsif ($js =~ /BT\d/ && $params->{bing_country} eq 'United Kingdom') {
- return { error => _("We do not currently cover Northern Ireland, I'm afraid.") };
}
$js = JSON->new->utf8->allow_nonref->decode($js);
@@ -54,11 +52,15 @@ sub string {
}
my $results = $js->{resourceSets}->[0]->{resources};
- my ( $error, @valid_locations, $latitude, $longitude );
+ my ( $error, @valid_locations, $latitude, $longitude, $ni );
foreach (@$results) {
my $address = $_->{name};
next unless $_->{address}->{countryRegion} eq $params->{bing_country};
+ if ($params->{bing_country} eq 'United Kingdom' && $_->{address}{adminDistrict} eq 'Northern Ireland') {
+ $ni = 1;
+ next;
+ }
# Getting duplicate, yet different, results from Bing sometimes
next if @valid_locations
@@ -80,6 +82,10 @@ sub string {
push (@valid_locations, $_);
}
+ if ($ni && !scalar @valid_locations) {
+ return { error => _("We do not currently cover Northern Ireland, I'm afraid.") };
+ }
+
return { latitude => $latitude, longitude => $longitude } if scalar @valid_locations == 1;
return { error => $error };
}
diff --git a/perllib/FixMyStreet/Map/Bromley.pm b/perllib/FixMyStreet/Map/Bromley.pm
new file mode 100644
index 000000000..20821236f
--- /dev/null
+++ b/perllib/FixMyStreet/Map/Bromley.pm
@@ -0,0 +1,22 @@
+#!/usr/bin/perl
+#
+# FixMyStreet:Map::Bromley
+# Bromley have slightly different tiles, with trees etc.
+#
+# Copyright (c) 2012 UK Citizens Online Democracy. All rights reserved.
+# Email: matthew@mysociety.org; WWW: http://www.mysociety.org/
+
+package FixMyStreet::Map::Bromley;
+use base 'FixMyStreet::Map::FMS';
+
+use strict;
+
+sub map_type {
+ return '[ [ "", "a-" ], "https://{S}fix.bromley.gov.uk/tilma" ]';
+}
+
+sub map_tile_base {
+ '-', "https://%sfix.bromley.gov.uk/tilma/%d/%d/%d.png";
+}
+
+1;
diff --git a/perllib/FixMyStreet/Map/FMS.pm b/perllib/FixMyStreet/Map/FMS.pm
index 24842c861..b1dd29002 100644
--- a/perllib/FixMyStreet/Map/FMS.pm
+++ b/perllib/FixMyStreet/Map/FMS.pm
@@ -37,23 +37,28 @@ sub get_quadkey {
return $key;
}
+sub map_tile_base {
+ '.', "http://%stilma.mysociety.org/sv/%d/%d/%d.png";
+}
+
sub map_tiles {
my ($self, $x, $y, $z) = @_;
if ($z >= 16) {
+ my ($tile_sep, $tile_base) = $self->map_tile_base;
return [
- "http://a.tilma.mysociety.org/sv/$z/" . ($x-1) . "/" . ($y-1) . ".png",
- "http://b.tilma.mysociety.org/sv/$z/$x/" . ($y-1) . ".png",
- "http://c.tilma.mysociety.org/sv/$z/" . ($x-1) . "/$y.png",
- "http://tilma.mysociety.org/sv/$z/$x/$y.png",
+ sprintf($tile_base, 'a' . $tile_sep, $z, $x-1, $y-1),
+ sprintf($tile_base, 'b' . $tile_sep, $z, $x, $y-1),
+ sprintf($tile_base, 'c' . $tile_sep, $z, $x-1, $y),
+ sprintf($tile_base, '', $z, $x, $y),
];
} else {
my $url = "g=701";
$url .= "&productSet=mmOS" if $z > 10;
return [
- "http://ecn.t0.tiles.virtualearth.net/tiles/r" . get_quadkey($x-1, $y-1, $z) . ".png?$url",
- "http://ecn.t1.tiles.virtualearth.net/tiles/r" . get_quadkey($x, $y-1, $z) . ".png?$url",
- "http://ecn.t2.tiles.virtualearth.net/tiles/r" . get_quadkey($x-1, $y, $z) . ".png?$url",
- "http://ecn.t3.tiles.virtualearth.net/tiles/r" . get_quadkey($x, $y, $z) . ".png?$url",
+ "//ecn.t0.tiles.virtualearth.net/tiles/r" . get_quadkey($x-1, $y-1, $z) . ".png?$url",
+ "//ecn.t1.tiles.virtualearth.net/tiles/r" . get_quadkey($x, $y-1, $z) . ".png?$url",
+ "//ecn.t2.tiles.virtualearth.net/tiles/r" . get_quadkey($x-1, $y, $z) . ".png?$url",
+ "//ecn.t3.tiles.virtualearth.net/tiles/r" . get_quadkey($x, $y, $z) . ".png?$url",
];
}
}
diff --git a/perllib/FixMyStreet/Map/OSM.pm b/perllib/FixMyStreet/Map/OSM.pm
index 8ca5949d8..119337e37 100644
--- a/perllib/FixMyStreet/Map/OSM.pm
+++ b/perllib/FixMyStreet/Map/OSM.pm
@@ -109,15 +109,9 @@ sub map_pins {
my @pins = map {
# Here we might have a DB::Problem or a DB::Nearby, we always want the problem.
my $p = (ref $_ eq 'FixMyStreet::App::Model::DB::Nearby') ? $_->problem : $_;
- #{
- # latitude => $p->latitude,
- # longitude => $p->longitude,
- # colour => $p->state eq 'fixed' ? 'green' : 'red',
- # id => $p->id,
- # title => $p->title,
- #}
+ my $colour = $c->cobrand->pin_colour( $p, 'around' );
[ $p->latitude, $p->longitude,
- 'yellow', # $p->is_fixed ? 'green' : 'red',
+ $colour,
$p->id, $p->title
]
} @$around_map, @$nearby;
diff --git a/perllib/FixMyStreet/SendReport.pm b/perllib/FixMyStreet/SendReport.pm
new file mode 100644
index 000000000..915fe4a20
--- /dev/null
+++ b/perllib/FixMyStreet/SendReport.pm
@@ -0,0 +1,45 @@
+package FixMyStreet::SendReport;
+
+use Moose;
+
+use Module::Pluggable
+ sub_name => 'senders',
+ search_path => __PACKAGE__,
+ require => 1;
+
+has 'councils' => ( is => 'rw', isa => 'HashRef', default => sub { {} } );
+has 'to' => ( is => 'rw', isa => 'ArrayRef', default => sub { [] } );
+has 'success' => ( is => 'rw', isa => 'Bool', default => 0 );
+has 'error' => ( is => 'rw', isa => 'Str', default => '' );
+has 'skipped' => ( 'is' => 'rw', isa => 'Str', default => '' );
+
+
+sub should_skip {
+ return 0;
+}
+
+sub get_senders {
+ my $self = shift;
+
+ my %senders = map { $_ => 1 } $self->senders;
+
+ return \%senders;
+}
+
+sub reset {
+ my $self = shift;
+
+ $self->councils( {} );
+ $self->to( [] );
+}
+
+sub add_council {
+ my $self = shift;
+ my $council = shift;
+ my $name = shift;
+
+ $self->councils->{ $council } = $name;
+}
+
+
+1;
diff --git a/perllib/FixMyStreet/SendReport/Barnet.pm b/perllib/FixMyStreet/SendReport/Barnet.pm
new file mode 100644
index 000000000..ecbe82872
--- /dev/null
+++ b/perllib/FixMyStreet/SendReport/Barnet.pm
@@ -0,0 +1,229 @@
+package FixMyStreet::SendReport::Barnet;
+
+use Moose;
+
+BEGIN { extends 'FixMyStreet::SendReport'; }
+
+use BarnetInterfaces::service::ZLBB_SERVICE_ORDER;
+use Encode;
+use Utils;
+use mySociety::Config;
+use mySociety::Web qw(ent);
+
+# maximum number of webservice attempts to send before not trying any more (XXX may be better in config?)
+use constant SEND_FAIL_RETRIES_CUTOFF => 3;
+
+# specific council numbers
+use constant COUNCIL_ID_BARNET => 2489;
+use constant MAX_LINE_LENGTH => 132;
+
+sub should_skip {
+ my $self = shift;
+ my $problem = shift;
+
+ my $council_name = 'Barnet';
+ my $err_msg = "";
+
+ if ($problem->send_fail_count >= SEND_FAIL_RETRIES_CUTOFF) {
+ $council_name &&= " to $council_name";
+ $err_msg = "skipped: problem id=" . $problem->id . " send$council_name has failed "
+ . $problem->send_fail_count . " times, cutoff is " . SEND_FAIL_RETRIES_CUTOFF;
+
+ $self->skipped( $err_msg );
+
+ return 1;
+ }
+}
+
+sub construct_message {
+ my %h = @_;
+ my $message = <<EOF;
+Subject: $h{title}
+
+Details: $h{detail}
+
+$h{fuzzy}, or to provide an update on the problem, please visit the following link:
+
+$h{url}
+
+$h{closest_address}
+EOF
+}
+
+
+sub send {
+ my ( $self, $problem, $h, $to, $template, $recips, $nomail ) = @_;
+
+ my %h = %$h;
+
+ $h{message} = construct_message(%h);
+
+ my $return = 1;
+ my $err_msg = "";
+
+ my $default_kbid = 14; # This is the default, "Street Scene"
+ my $kbid = sprintf( "%050d", Utils::barnet_categories()->{$h{category}} || $default_kbid);
+
+ my $geo_code = "$h{easting} $h{northing}";
+
+ my $interface = BarnetInterfaces::service::ZLBB_SERVICE_ORDER->new();
+
+ my ($nearest_postcode, $nearest_street) = ('', '');
+ for ($h{closest_address}) {
+ $nearest_postcode = sprintf("%-10s", $1) if /Nearest postcode [^:]+: ((\w{1,4}\s?\w+|\w+))/;
+ # use partial postcode or comma as delimiter, strip leading number (possible letter 221B) off too
+ # "99 Foo Street, London N11 1XX" becomes Foo Street
+ # "99 Foo Street N11 1XX" becomes Foo Street
+ $nearest_street = $1 if /Nearest road [^:]+: (?:\d+\w? )?(.*?)(\b[A-Z]+\d|,|$)/m;
+ }
+ my $postcode = mySociety::PostcodeUtil::is_valid_postcode($h{query})
+ ? $h{query} : $nearest_postcode; # use given postcode if available
+
+ # note: endpoint can be of form 'https://username:password@url'
+ my $council_config = FixMyStreet::App->model("DB::Open311conf")->search( { area_id => COUNCIL_ID_BARNET} )->first;
+ if ($council_config and $council_config->endpoint) {
+ $interface->set_proxy($council_config->endpoint);
+ # Barnet web service doesn't like namespaces in the elements so use a prefix
+ $interface->set_prefix('urn');
+ # uncomment these lines to print XML that will be sent rather
+ # than connecting to the endpoint
+ #$interface->outputxml(1);
+ #$interface->no_dispatch(1);
+ } else {
+ die "Barnet webservice FAIL: looks like you're missing some config data: no endpoint (URL) found for area_id=" . COUNCIL_ID_BARNET;
+ }
+
+ eval {
+ my $result = $interface->Z_CRM_SERVICE_ORDER_CREATE( {
+ ET_RETURN => { # ignored by server
+ item => {
+ TYPE => "", ID => "", NUMBER => "", MESSAGE => "", LOG_NO => "", LOG_MSG_NO => "",
+ MESSAGE_V1 => "", MESSAGE_V2 => "", MESSAGE_V3 => "", MESSAGE_V4 => "", PARAMETER => "",
+ ROW => "", FIELD => "", SYSTEM => "",
+ },
+ },
+ IT_PROBLEM_DESC => { # MyTypes::TABLE_OF_CRMT_SERVICE_REQUEST_TEXT
+ item => [ # MyTypes::CRMT_SERVICE_REQUEST_TEXT
+ map { { TEXT_LINE => $_ } } split_text_with_entities(ent(encode_utf8($h{message})), 132) # char132
+ ],
+ },
+ IV_CUST_EMAIL => truncate_string_with_entities(ent(encode_utf8($h{email})), 241), # char241
+ IV_CUST_NAME => truncate_string_with_entities(ent(encode_utf8($h{name})), 50), # char50
+ IV_KBID => $kbid, # char50
+ IV_PROBLEM_ID => $h{id}, # char35
+ IV_PROBLEM_LOC => { # MyTypes::BAPI_TTET_ADDRESS_COM
+ COUNTRY2 => 'GB', # char2
+ REGION => "", # char3
+ COUNTY => "", # char30
+ CITY => "", # char30
+ POSTALCODE => $postcode, # char10
+ STREET => truncate_string_with_entities(ent(encode_utf8($nearest_street)), 30), # char30
+ STREETNUMBER => "", # char5
+ GEOCODE => $geo_code, # char32
+ },
+ IV_PROBLEM_SUB => truncate_string_with_entities(ent(encode_utf8($h{title})), 40), # char40
+ },
+ );
+ if ($result) {
+ # currently not using this: get_EV_ORDER_GUID (maybe that's the customer number in the CRM)
+ if (my $barnet_id = $result->get_EV_ORDER_NO()) {
+ $problem->external_id( $barnet_id );
+ $problem->external_body( 'Barnet Borough Council' ); # better to use $problem->body()?
+ $problem->send_method_used('barnet');
+ $return = 0;
+ } else {
+ my @returned_items = split /<item[^>]*>/, $result->get_ET_RETURN;
+ my @messages = ();
+ foreach my $item (@returned_items) {
+ if ($item=~/<MESSAGE [^>]*>\s*(\S.*?)<\/MESSAGE>/) { # if there's a non-null MESSAGE in there, grab it
+ push @messages, $1; # best stab at extracting useful error message back from convoluted response
+ }
+ }
+ push @messages, "service returned no external id" unless @messages;
+ $err_msg = "Failed (problem id $h{id}): " . join(" \n ", @messages);
+ }
+ } else {
+ my %fault = (
+ 'code' => $result->get_faultcode(),
+ 'actor' => $result->get_faultactor(),
+ 'string' => $result->get_faultstring(),
+ 'detail' => $result->get_detail(), # possibly only contains debug info
+ );
+ foreach (keys %fault) {
+ $fault{$_}="" unless defined $fault{$_};
+ $fault{$_}=~s/^\s*|\s*$//g;
+ }
+ $fault{actor}&&=" (actor: $fault{actor})";
+ $fault{'detail'} &&= "\n" . $fault{'detail'};
+ $err_msg = "Failed (problem id $h{id}): Fault $fault{code}$fault{actor}\n$fault{string}$fault{detail}";
+ }
+
+ };
+ if ($err_msg) {
+ # for timeouts, we can tidy the message a wee bit (i.e. strip the 'error deserializing...' message)
+ $err_msg=~s/(?:Error deserializing message:.*)(Can't connect to [a-zA-Z0-9.:]+\s*\(Connection timed out\)).*/$1/s;
+ print "$err_msg\n";
+ }
+ if ($@) {
+ my $e = shift;
+ print "Caught an error: $@\n";
+ }
+ if ( $return ) {
+ $self->error( "Error sending to Barnet: $err_msg" );
+ }
+ $self->success( !$return );
+ return $return;
+}
+
+# for barnet webservice: max-length fields require truncate and split
+
+# truncate_string_with_entities
+# args: text to truncate
+# max number of chars
+# returns: string truncated
+# Note: must not partially truncate an entity (e.g., &amp;)
+sub truncate_string_with_entities {
+ my ($str, $max_len) = @_;
+ my $retVal = "";
+ foreach my $chunk (split /(\&(?:\#\d+|\w+);)/, $str) {
+ if ($chunk=~/^\&(\#\d+|\w+);$/){
+ my $next = $retVal.$chunk;
+ last if length $next > $max_len;
+ $retVal=$next
+ } else {
+ $retVal.=$chunk;
+ if (length $retVal > $max_len) {
+ $retVal = substr($retVal, 0, $max_len);
+ last
+ }
+ }
+ }
+ return $retVal
+}
+
+# split_text_with_entities into lines
+# args: text to be broken into lines
+# max length (option: uses constant MAX_LINE_LENGTH)
+# returns: array of lines
+# Must not to split an entity (e.g., &amp;)
+# Not worrying about hyphenating here, since a word is only ever split if
+# it's longer than the whole line, which is uncommon in genuine problem reports
+sub split_text_with_entities {
+ my ($text, $max_line_length) = @_;
+ $max_line_length ||= MAX_LINE_LENGTH;
+ my @lines;
+ foreach my $line (split "\n", $text) {
+ while (length $line > $max_line_length) {
+ if (! ($line =~ s/^(.{1,$max_line_length})\s// # break on a space
+ or $line =~ s/^(.{1,$max_line_length})(\&(\#\d+|\w+);)/$2/ # break before an entity
+ or $line =~ s/(.{$max_line_length})//)) { # break the word ruthlessly
+ $line =~ s/(.*)//; # otherwise gobble whole line (which is now shorter than max length)
+ }
+ push @lines, $1;
+ }
+ push @lines, $line;
+ }
+ return @lines;
+}
+
+1;
diff --git a/perllib/FixMyStreet/SendReport/EastHants.pm b/perllib/FixMyStreet/SendReport/EastHants.pm
new file mode 100644
index 000000000..681a9d4c4
--- /dev/null
+++ b/perllib/FixMyStreet/SendReport/EastHants.pm
@@ -0,0 +1,62 @@
+package FixMyStreet::SendReport::EastHants;
+
+use Moose;
+
+BEGIN { extends 'FixMyStreet::SendReport'; }
+
+# export just what we need as error if we use :try
+use Error qw(try otherwise);
+use Encode;
+use mySociety::Web qw(ent);
+use EastHantsWSDL;
+
+sub construct_message {
+ my %h = @_;
+ my $message = '';
+ $message .= "[ This report was also sent to the district council covering the location of the problem, as the user did not categorise it; please ignore if you're not the correct council to deal with the issue. ]\n\n"
+ if $h{multiple};
+ $message .= <<EOF;
+Subject: $h{title}
+
+Details: $h{detail}
+
+$h{fuzzy}, or to provide an update on the problem, please visit the following link:
+
+$h{url}
+
+$h{closest_address}
+EOF
+ return $message;
+}
+
+sub send {
+ return if mySociety::Config::get('STAGING_SITE');
+
+ my ( $self, $row, $h, $to, $template, $recips, $nomail ) = @_;
+
+ # FIXME: should not recreate this each time
+ my $eh_service;
+
+ $h->{category} = 'Customer Services' if $h->{category} eq 'Other';
+ $h->{message} = construct_message( %$h );
+ my $return = 1;
+ $eh_service ||= EastHantsWSDL->on_fault(sub { my($soap, $res) = @_; die ref $res ? $res->faultstring : $soap->transport->status, "\n"; });
+ try {
+ # ServiceName, RemoteCreatedBy, Salutation, FirstName, Name, Email, Telephone, HouseNoName, Street, Town, County, Country, Postcode, Comments, FurtherInfo, ImageURL
+ my $message = ent(encode_utf8($h->{message}));
+ my $name = ent(encode_utf8($h->{name}));
+ my $result = $eh_service->INPUTFEEDBACK(
+ $h->{category}, 'FixMyStreet', '', '', $name, $h->{email}, $h->{phone},
+ '', '', '', '', '', '', $message, 'Yes', $h->{image_url}
+ );
+ $return = 0 if $result eq 'Report received';
+ } otherwise {
+ my $e = shift;
+ print "Caught an error: $e\n";
+ $self->error( "Error sending to East Hants: $e" );
+ };
+ $self->success( !$return );
+ return $return;
+}
+
+1;
diff --git a/perllib/FixMyStreet/SendReport/Email.pm b/perllib/FixMyStreet/SendReport/Email.pm
new file mode 100644
index 000000000..239bee715
--- /dev/null
+++ b/perllib/FixMyStreet/SendReport/Email.pm
@@ -0,0 +1,111 @@
+package FixMyStreet::SendReport::Email;
+
+use Moose;
+
+BEGIN { extends 'FixMyStreet::SendReport'; }
+
+use mySociety::EmailUtil;
+
+sub build_recipient_list {
+ my $self = shift;
+ my $row = shift;
+ my %recips;
+
+ my $all_confirmed = 1;
+ foreach my $council ( keys %{ $self->councils } ) {
+ my $contact = FixMyStreet::App->model("DB::Contact")->find( {
+ deleted => 0,
+ area_id => $council,
+ category => $row->category
+ } );
+
+ my ($council_email, $confirmed, $note) = ( $contact->email, $contact->confirmed, $contact->note );
+
+ $council_email = essex_contact($row->latitude, $row->longitude) if $council == 2225;
+ $council_email = oxfordshire_contact($row->latitude, $row->longitude) if $council == 2237 && $council_email eq 'SPECIAL';
+
+ unless ($confirmed) {
+ $all_confirmed = 0;
+ #$note = 'Council ' . $row->council . ' deleted'
+ #unless $note;
+ $council_email = 'N/A' unless $council_email;
+ #$notgot{$council_email}{$row->category}++;
+ #$note{$council_email}{$row->category} = $note;
+ }
+
+ push @{ $self->to }, [ $council_email, $self->councils->{ $council } ];
+ $recips{$council_email} = 1;
+ }
+
+ return () unless $all_confirmed;
+ return keys %recips;
+}
+
+sub send {
+ my $self = shift;
+ my ( $row, $h, $to, $template, $recips, $nomail, $areas_info ) = @_;
+
+ my @recips;
+
+ @recips = $self->build_recipient_list( $row, $areas_info );
+
+ # on a staging server send emails to ourselves rather than the councils
+ if (mySociety::Config::get('STAGING_SITE')) {
+ @recips = ( mySociety::Config::get('CONTACT_EMAIL') );
+ }
+
+ return unless @recips;
+
+ my $result = FixMyStreet::App->send_email_cron(
+ {
+ _template_ => $template,
+ _parameters_ => $h,
+ To => $self->to,
+ From => [ $row->user->email, $row->name ],
+ },
+ mySociety::Config::get('CONTACT_EMAIL'),
+ \@recips,
+ $nomail
+ );
+
+ if ( $result == mySociety::EmailUtil::EMAIL_SUCCESS ) {
+ $self->success(1);
+ } else {
+ $self->error( 'Failed to send email' );
+ }
+
+ return $result;
+}
+
+# Essex has different contact addresses depending upon the district
+# Might be easier if we start storing in the db all areas covered by a point
+# Will do for now :)
+sub essex_contact {
+ my $district = _get_district_for_contact(@_);
+ my $email;
+ $email = 'eastarea' if $district == 2315 || $district == 2312;
+ $email = 'midarea' if $district == 2317 || $district == 2314 || $district == 2316;
+ $email = 'southarea' if $district == 2319 || $district == 2320 || $district == 2310;
+ $email = 'westarea' if $district == 2309 || $district == 2311 || $district == 2318 || $district == 2313;
+ die "Returned district $district which is not in Essex!" unless $email;
+ return "highways.$email\@essexcc.gov.uk";
+}
+
+# Oxfordshire has different contact addresses depending upon the district
+sub oxfordshire_contact {
+ my $district = _get_district_for_contact(@_);
+ my $email;
+ $email = 'northernarea' if $district == 2419 || $district == 2420 || $district == 2421;
+ $email = 'southernarea' if $district == 2417 || $district == 2418;
+ die "Returned district $district which is not in Oxfordshire!" unless $email;
+ return "$email\@oxfordshire.gov.uk";
+}
+
+sub _get_district_for_contact {
+ my ( $lat, $lon ) = @_;
+ my $district =
+ mySociety::MaPit::call( 'point', "4326/$lon,$lat", type => 'DIS' );
+ ($district) = keys %$district;
+ return $district;
+}
+1;
diff --git a/perllib/FixMyStreet/SendReport/EmptyHomes.pm b/perllib/FixMyStreet/SendReport/EmptyHomes.pm
new file mode 100644
index 000000000..9453b4ca5
--- /dev/null
+++ b/perllib/FixMyStreet/SendReport/EmptyHomes.pm
@@ -0,0 +1,51 @@
+package FixMyStreet::SendReport::EmptyHomes;
+
+use Moose;
+use namespace::autoclean;
+
+BEGIN { extends 'FixMyStreet::SendReport::Email'; }
+
+sub build_recipient_list {
+ my $self = shift;
+ my $row = shift;
+ my $areas_info = shift;
+ my %recips;
+
+ my $all_confirmed = 1;
+ foreach my $council ( keys %{ $self->councils } ) {
+ my $contact = FixMyStreet::App->model("DB::Contact")->find( {
+ deleted => 0,
+ area_id => $council,
+ category => 'Empty property',
+ } );
+
+ my ($council_email, $confirmed, $note) = ( $contact->email, $contact->confirmed, $contact->note );
+
+ $council_email = essex_contact($row->latitude, $row->longitude) if $council == 2225;
+ $council_email = oxfordshire_contact($row->latitude, $row->longitude) if $council == 2237 && $council_email eq 'SPECIAL';
+
+ unless ($confirmed) {
+ $all_confirmed = 0;
+ #$note = 'Council ' . $row->council . ' deleted'
+ #unless $note;
+ $council_email = 'N/A' unless $council_email;
+ #$notgot{$council_email}{$row->category}++;
+ #$note{$council_email}{$row->category} = $note;
+ }
+
+ push @{ $self->to }, [ $council_email, $self->councils->{ $council } ];
+ $recips{$council_email} = 1;
+
+ my $country = $areas_info->{$council}->{country};
+ if ($country eq 'W') {
+ $recips{ 'shelter@' . mySociety::Config::get('EMAIL_DOMAIN') } = 1;
+ } else {
+ $recips{ 'eha@' . mySociety::Config::get('EMAIL_DOMAIN') } = 1;
+ }
+ }
+
+ return () unless $all_confirmed;
+ return keys %recips;
+}
+
+1;
diff --git a/perllib/FixMyStreet/SendReport/London.pm b/perllib/FixMyStreet/SendReport/London.pm
new file mode 100644
index 000000000..58ecb2375
--- /dev/null
+++ b/perllib/FixMyStreet/SendReport/London.pm
@@ -0,0 +1,113 @@
+package FixMyStreet::SendReport::London;
+
+use Moose;
+
+BEGIN { extends 'FixMyStreet::SendReport'; }
+
+use Digest::MD5;
+use LWP::UserAgent;
+use LWP::Simple;
+
+use Utils;
+
+sub construct_message {
+ my %h = @_;
+ return <<EOF,
+A user of FixMyStreet has submitted the following report of a local
+problem that they believe might require your attention.
+
+Subject: $h{title}
+
+Details: $h{detail}
+
+$h{fuzzy}, or to provide an update on the problem, please visit the
+following link:
+
+$h{url}
+
+$h{closest_address}
+Yours,
+The FixMyStreet team
+EOF
+}
+
+sub send {
+ return if mySociety::Config::get('STAGING_SITE');
+ my ( $self, $row, $h, $to, $template, $recips, $nomail ) = @_;
+
+ $h->{message} = construct_message( %$h );
+ my $phone = $h->{phone};
+ my $mobile = '';
+ if ($phone && $phone =~ /^\s*07/) {
+ $mobile = $phone;
+ $phone = '';
+ }
+ my ($first, $last) = $h->{name} =~ /^(\S*)(?: (.*))?$/;
+ my %params = (
+ Key => mySociety::Config::get('LONDON_REPORTIT_KEY'),
+ Signature => Digest::MD5::md5_hex( $h->{confirmed} . mySociety::Config::get('LONDON_REPORTIT_SECRET') ),
+ Type => Utils::london_categories()->{$h->{category}},
+ RequestDate => $h->{confirmed},
+ RequestMethod => 'Web',
+ ExternalId => $h->{url},
+ 'Customer.Title' => '',
+ 'Customer.FirstName' => $first,
+ 'Customer.Surname' => $last,
+ 'Customer.Email' => $h->{email},
+ 'Customer.Phone' => $phone,
+ 'Customer.Mobile' => $mobile,
+ 'ProblemDescription' => $h->{message},
+ );
+ if ($h->{used_map}) {
+ $params{'Location.Latitude'} = $h->{latitude};
+ $params{'Location.Longitude'} = $h->{longitude};
+ } elsif (mySociety::PostcodeUtil::is_valid_postcode($h->{query})) {
+ # Didn't use map, and entered postcode, so use that.
+ $params{'Location.Postcode'} = $h->{query};
+ } else {
+ # Otherwise, lat/lon is all we have, even if it's wrong.
+ $params{'Location.Latitude'} = $h->{latitude};
+ $params{'Location.Longitude'} = $h->{longitude};
+ }
+ if ($h->{has_photo}) {
+ $params{'Document1.Name'} = 'Photograph';
+ $params{'Document1.MimeType'} = 'image/jpeg';
+ $params{'Document1.URL'} = $h->{image_url};
+ $params{'Document1.URLPublic'} = 'true';
+ }
+ my $browser = LWP::UserAgent->new;
+ my $response = $browser->post( mySociety::Config::get('LONDON_REPORTIT_URL'), \%params );
+ my $out = $response->content;
+ if ($response->code ne 200) {
+ print "Failed to post $h->{id} to London API, response was " . $response->code . " $out\n";
+ $self->error( "Failed to post $h->{id} to London API, response was " . $response->code . " $out" );
+ return 1;
+ }
+ my ($id) = $out =~ /<caseid>(.*?)<\/caseid>/;
+ my ($org) = $out =~ /<organisation>(.*?)<\/organisation>/;
+ my ($team) = $out =~ /<team>(.*?)<\/team>/;
+
+ $org = london_lookup($org);
+ $row->external_id( $id );
+ $row->external_body( $org );
+ $row->external_team( $team );
+ $self->success(1);
+ return 0;
+}
+
+sub london_lookup {
+ my $org = shift || '';
+ my $str = "Unknown ($org)";
+ open(FP, "$FindBin::Bin/../data/dft.csv");
+ while (<FP>) {
+ /^(.*?),(.*)/;
+ if ($org eq $1) {
+ $str = $2;
+ last;
+ }
+ }
+ close FP;
+ return $str;
+}
+
+1;
diff --git a/perllib/FixMyStreet/SendReport/Open311.pm b/perllib/FixMyStreet/SendReport/Open311.pm
new file mode 100644
index 000000000..52268fd91
--- /dev/null
+++ b/perllib/FixMyStreet/SendReport/Open311.pm
@@ -0,0 +1,133 @@
+package FixMyStreet::SendReport::Open311;
+
+use Moose;
+use namespace::autoclean;
+
+BEGIN { extends 'FixMyStreet::SendReport'; }
+
+use FixMyStreet::App;
+use mySociety::Config;
+use DateTime::Format::W3CDTF;
+use Open311;
+
+sub should_skip {
+ my $self = shift;
+ my $row = shift;
+
+ if ( $row->send_fail_count > 0 ) {
+ if ( bromley_retry_timeout($row) ) {
+ return 1;
+ }
+ }
+}
+
+sub send {
+ my $self = shift;
+ my ( $row, $h, $to, $template, $recips, $nomail ) = @_;
+
+ my $result = -1;
+
+ foreach my $council ( keys %{ $self->councils } ) {
+ my $conf = FixMyStreet::App->model("DB::Open311conf")->search( { area_id => $council, endpoint => { '!=', '' } } )->first;
+
+ my $always_send_latlong = 1;
+ my $send_notpinpointed = 0;
+
+ my $basic_desc = 0;
+
+ # Extra bromley fields
+ if ( $row->council =~ /2482/ ) {
+
+ my $extra = $row->extra;
+ if ( $row->used_map || ( !$row->used_map && !$row->postcode ) ) {
+ push @$extra, { name => 'northing', value => $h->{northing} };
+ push @$extra, { name => 'easting', value => $h->{easting} };
+ }
+ push @$extra, { name => 'report_url', value => $h->{url} };
+ push @$extra, { name => 'service_request_id_ext', value => $row->id };
+ push @$extra, { name => 'report_title', value => $row->title };
+ push @$extra, { name => 'public_anonymity_required', value => $row->anonymous ? 'TRUE' : 'FALSE' };
+ push @$extra, { name => 'email_alerts_requested', value => 'FALSE' }; # always false as can never request them
+ push @$extra, { name => 'requested_datetime', value => DateTime::Format::W3CDTF->format_datetime($row->confirmed_local->set_nanosecond(0)) };
+ push @$extra, { name => 'email', value => $row->user->email };
+ $row->extra( $extra );
+
+ $always_send_latlong = 0;
+ $send_notpinpointed = 1;
+
+ # make sure we have first_name and last_name attributes
+ if ( $row->cobrand ne 'bromley' ) {
+ my ( $firstname, $lastname ) = ( $row->user->name =~ /(\w+)\s+(.+)/ );
+ push @$extra, { name => 'first_name', value => $firstname };
+ push @$extra, { name => 'last_name', value => $lastname };
+ }
+
+ $basic_desc = 1;
+ }
+
+ # FIXME: we've already looked this up before
+ my $contact = FixMyStreet::App->model("DB::Contact")->find( {
+ deleted => 0,
+ area_id => $conf->area_id,
+ category => $row->category
+ } );
+
+ my $open311 = Open311->new(
+ jurisdiction => $conf->jurisdiction,
+ endpoint => $conf->endpoint,
+ api_key => $conf->api_key,
+ always_send_latlong => $always_send_latlong,
+ send_notpinpointed => $send_notpinpointed,
+ basic_description => $basic_desc,
+ );
+
+ # non standard west berks end points
+ if ( $row->council =~ /2619/ ) {
+ $open311->endpoints( { services => 'Services', requests => 'Requests' } );
+ }
+
+ # required to get round issues with CRM constraints
+ if ( $row->council =~ /2218/ ) {
+ $row->user->name( $row->user->id . ' ' . $row->user->name );
+ }
+
+ my $resp = $open311->send_service_request( $row, $h, $contact->email );
+
+ # make sure we don't save user changes from above
+ if ( $row->council =~ /2218/ || $row->council =~ /2482/ ) {
+ $row->discard_changes();
+ }
+
+ if ( $resp ) {
+ $row->external_id( $resp );
+ $row->send_method_used('Open311');
+ $result *= 0;
+ $self->success( 1 );
+ } else {
+ $result *= 1;
+ # temporary fix to resolve some issues with west berks
+ if ( $row->council =~ /2619/ ) {
+ $result *= 0;
+ }
+ }
+ }
+
+ $self->error( 'Failed to send over Open311' ) unless $self->success;
+
+ return $result;
+}
+
+sub bromley_retry_timeout {
+ my $row = shift;
+
+ my $tz = DateTime::TimeZone->new( name => 'local' );
+ my $now = DateTime->now( time_zone => $tz );
+ my $diff = $now - $row->send_fail_timestamp;
+ if ( $diff->in_units( 'minutes' ) < 30 ) {
+ return 1;
+ }
+
+ return 0;
+}
+
+1;
diff --git a/perllib/FixMyStreet/TestMech.pm b/perllib/FixMyStreet/TestMech.pm
index 7daf01f56..dc42c1aba 100644
--- a/perllib/FixMyStreet/TestMech.pm
+++ b/perllib/FixMyStreet/TestMech.pm
@@ -225,6 +225,7 @@ sub form_errors {
my $result = scraper {
process 'div.form-error', 'errors[]', 'TEXT';
process 'p.form-error', 'errors[]', 'TEXT';
+ process 'p.error', 'errors[]', 'TEXT';
}
->scrape( $mech->response );
return $result->{errors} || [];
diff --git a/perllib/Open311.pm b/perllib/Open311.pm
index e26e3e4c6..fd6a67706 100644
--- a/perllib/Open311.pm
+++ b/perllib/Open311.pm
@@ -5,6 +5,7 @@ use Moose;
use XML::Simple;
use LWP::Simple;
use LWP::UserAgent;
+use DateTime::Format::W3CDTF;
use HTTP::Request::Common qw(POST);
has jurisdiction => ( is => 'ro', isa => 'Str' );;
@@ -12,10 +13,23 @@ has api_key => ( is => 'ro', isa => 'Str' );
has endpoint => ( is => 'ro', isa => 'Str' );
has test_mode => ( is => 'ro', isa => 'Bool' );
has test_uri_used => ( is => 'rw', 'isa' => 'Str' );
+has test_req_used => ( is => 'rw' );
has test_get_returns => ( is => 'rw' );
-has endpoints => ( is => 'rw', default => sub { { services => 'services.xml', requests => 'requests.xml' } } );
+has endpoints => ( is => 'rw', default => sub { { services => 'services.xml', requests => 'requests.xml', service_request_updates => 'update.xml', update => 'update.xml' } } );
has debug => ( is => 'ro', isa => 'Bool', default => 0 );
has debug_details => ( is => 'rw', 'isa' => 'Str', default => '' );
+has success => ( is => 'rw', 'isa' => 'Bool', default => 0 );
+has error => ( is => 'rw', 'isa' => 'Str', default => '' );
+has always_send_latlong => ( is => 'ro', isa => 'Bool', default => 1 );
+has send_notpinpointed => ( is => 'ro', isa => 'Bool', default => 0 );
+has basic_description => ( is => 'ro', isa => 'Bool', default => 0 );
+
+before [
+ qw/get_service_list get_service_meta_info get_service_requests get_service_request_updates
+ send_service_request post_service_request_update/
+ ] => sub {
+ shift->debug_details('');
+ };
sub get_service_list {
my $self = shift;
@@ -39,22 +53,49 @@ sub send_service_request {
my $extra = shift;
my $service_code = shift;
- my $description = <<EOT;
-title: @{[$problem->title()]}
+ my $params = $self->_populate_service_request_params(
+ $problem, $extra, $service_code
+ );
-detail: @{[$problem->detail()]}
+ my $response = $self->_post( $self->endpoints->{requests}, $params );
-url: $extra->{url}
+ if ( $response ) {
+ my $obj = $self->_get_xml_object( $response );
-Submitted via FixMyStreet
-EOT
-;
+ if ( $obj ) {
+ if ( $obj->{ request }->{ service_request_id } ) {
+ return $obj->{ request }->{ service_request_id };
+ } else {
+ my $token = $obj->{ request }->{ token };
+ if ( $token ) {
+ return $self->get_service_request_id_from_token( $token );
+ }
+ }
+ }
+
+ warn sprintf( "Failed to submit problem %s over Open311, response\n: %s\n%s", $problem->id, $response, $self->debug_details );
+ return 0;
+ }
+}
+
+sub _populate_service_request_params {
+ my $self = shift;
+ my $problem = shift;
+ my $extra = shift;
+ my $service_code = shift;
+
+ my $description;
+ if ( $self->basic_description ) {
+ $description = $problem->detail;
+ } else {
+ $description = $self->_generate_service_request_description(
+ $problem, $extra
+ );
+ }
my ( $firstname, $lastname ) = ( $problem->user->name =~ /(\w+)\s+(.+)/ );
my $params = {
- lat => $problem->latitude,
- long => $problem->longitude,
email => $problem->user->email,
description => $description,
service_code => $service_code,
@@ -62,6 +103,25 @@ EOT
last_name => $lastname || '',
};
+ # if you click nearby reports > skip map then it's possible
+ # to end up with used_map = f and nothing in postcode
+ if ( $problem->used_map || $self->always_send_latlong
+ || ( !$self->send_notpinpointed && !$problem->used_map
+ && !$problem->postcode ) )
+ {
+ $params->{lat} = $problem->latitude;
+ $params->{long} = $problem->longitude;
+ # this is a special case for sending to Bromley so they can
+ # report accuracy levels correctly. We include easting and
+ # northing as attributes elsewhere.
+ } elsif ( $self->send_notpinpointed && !$problem->used_map
+ && !$problem->postcode )
+ {
+ $params->{address_id} = '#NOTPINPOINTED#';
+ } else {
+ $params->{address_string} = $problem->postcode;
+ }
+
if ( $problem->user->phone ) {
$params->{ phone } = $problem->user->phone;
}
@@ -74,30 +134,37 @@ EOT
my $extras = $problem->extra;
for my $attr ( @$extras ) {
- my $name = sprintf( 'attribute[%s]', $attr->{name} );
+ my $attr_name = $attr->{name};
+ if ( $attr_name eq 'first_name' || $attr_name eq 'last_name' ) {
+ $params->{$attr_name} = $attr->{value} if $attr->{value};
+ next if $attr_name eq 'first_name';
+ }
+ $attr_name =~ s/fms_extra_//;
+ my $name = sprintf( 'attribute[%s]', $attr_name );
$params->{ $name } = $attr->{value};
}
}
- my $response = $self->_post( $self->endpoints->{requests}, $params );
+ return $params;
+}
- if ( $response ) {
- my $obj = $self->_get_xml_object( $response );
+sub _generate_service_request_description {
+ my $self = shift;
+ my $problem = shift;
+ my $extra = shift;
- if ( $obj ) {
- if ( $obj->{ request }->{ service_request_id } ) {
- return $obj->{ request }->{ service_request_id };
- } else {
- my $token = $obj->{ request }->{ token };
- if ( $token ) {
- return $self->get_service_request_id_from_token( $token );
- }
- }
- }
+ my $description = <<EOT;
+title: @{[$problem->title()]}
- warn sprintf( "Failed to submit problem %s over Open311, response\n: %s\n%s", $problem->id, $response, $self->debug_details );
- return 0;
- }
+detail: @{[$problem->detail()]}
+
+url: $extra->{url}
+
+Submitted via FixMyStreet
+EOT
+;
+
+ return $description;
}
sub get_service_requests {
@@ -129,6 +196,107 @@ sub get_service_request_id_from_token {
}
}
+sub get_service_request_updates {
+ my $self = shift;
+ my $start_date = shift;
+ my $end_date = shift;
+
+ my $params = {
+ api_key => $self->api_key,
+ jurisdiction => $self->jurisdiction,
+ };
+
+ if ( $start_date || $end_date ) {
+ return 0 unless $start_date && $end_date;
+
+ $params->{start_date} = $start_date;
+ $params->{end_date} = $end_date;
+ }
+
+ my $xml = $self->_get( $self->endpoints->{service_request_updates}, $params || undef );
+ my $service_requests = $self->_get_xml_object( $xml );
+ my $requests;
+ if ( ref $service_requests->{request_update } eq 'ARRAY' ) {
+ $requests = $service_requests->{request_update};
+ }
+ else {
+ $requests = [ $service_requests->{request_update} ];
+ }
+
+ return $requests;
+}
+
+sub post_service_request_update {
+ my $self = shift;
+ my $comment = shift;
+
+ my $params = $self->_populate_service_request_update_params( $comment );
+
+ my $response = $self->_post( $self->endpoints->{update}, $params );
+
+ if ( $response ) {
+ my $obj = $self->_get_xml_object( $response );
+
+ if ( $obj ) {
+ if ( $obj->{ request_update }->{ update_id } ) {
+ my $update_id = $obj->{request_update}->{update_id};
+
+ # if there's nothing in the update_id element we get a HASHREF back
+ unless ( ref $update_id ) {
+ return $obj->{ request_update }->{ update_id };
+ }
+ } else {
+ my $token = $obj->{ request_update }->{ token };
+ if ( $token ) {
+ return $self->get_service_request_id_from_token( $token );
+ }
+ }
+ }
+
+ warn sprintf( "Failed to submit comment %s over Open311, response - %s\n%s\n", $comment->id, $response, $self->debug_details );
+ return 0;
+ }
+}
+
+sub _populate_service_request_update_params {
+ my $self = shift;
+ my $comment = shift;
+
+ my $name = $comment->name || $comment->user->name;
+ my ( $firstname, $lastname ) = ( $name =~ /(\w+)\s+(.+)/ );
+
+ my $params = {
+ update_id_ext => $comment->id,
+ updated_datetime => DateTime::Format::W3CDTF->format_datetime($comment->confirmed_local->set_nanosecond(0)),
+ service_request_id => $comment->problem->external_id,
+ service_request_id_ext => $comment->problem->id,
+ status => $comment->problem->is_open ? 'OPEN' : 'CLOSED',
+ email => $comment->user->email,
+ description => $comment->text,
+ public_anonymity_required => $comment->anonymous ? 'TRUE' : 'FALSE',
+ last_name => $lastname,
+ first_name => $firstname,
+ };
+
+ if ( $comment->photo ) {
+ my $cobrand = FixMyStreet::Cobrand->get_class_for_moniker($comment->cobrand)->new();
+ my $email_base_url = $cobrand->base_url_for_emails($comment->cobrand_data);
+ my $url = $email_base_url . '/photo/c/' . $comment->id . '.full.jpeg';
+ $params->{media_url} = $url;
+ }
+
+ if ( $comment->extra ) {
+ $params->{'email_alerts_requested'}
+ = $comment->extra->{email_alerts_requested} ? 'TRUE' : 'FALSE';
+ $params->{'title'} = $comment->extra->{title};
+
+ $params->{first_name} = $comment->extra->{first_name} if $comment->extra->{first_name};
+ $params->{last_name} = $comment->extra->{last_name} if $comment->extra->{last_name};
+ }
+
+ return $params;
+}
+
sub _get {
my $self = shift;
my $path = shift;
@@ -144,10 +312,25 @@ sub _get {
my $content;
if ( $self->test_mode ) {
+ $self->success(1);
$content = $self->test_get_returns->{ $path };
$self->test_uri_used( $uri->as_string );
} else {
- $content = get( $uri->as_string );
+ my $ua = LWP::UserAgent->new;
+
+ my $req = HTTP::Request->new(
+ GET => $uri->as_string
+ );
+
+ my $res = $ua->request( $req );
+
+ if ( $res->is_success ) {
+ $content = $res->decoded_content;
+ $self->success(1);
+ } else {
+ $self->success(0);
+ $self->error( $res->status_line );
+ }
}
return $content;
@@ -171,17 +354,27 @@ sub _post {
$self->debug_details( $self->debug_details . "\nrequest:" . $req->as_string );
my $ua = LWP::UserAgent->new();
- my $res = $ua->request( $req );
+ my $res;
+
+ if ( $self->test_mode ) {
+ $res = $self->test_get_returns->{ $path };
+ $self->test_req_used( $req );
+ } else {
+ $res = $ua->request( $req );
+ }
if ( $res->is_success ) {
+ $self->success(1);
return $res->decoded_content;
} else {
- warn sprintf(
- "request failed: %s\nerror: %s\n%s",
+ $self->success(0);
+ $self->error( sprintf(
+ "request failed: %s\nerror: %s\n%s\n",
$res->status_line,
$self->_process_error( $res->decoded_content ),
$self->debug_details
- );
+ ) );
+ warn $self->error;
return 0;
}
}
diff --git a/perllib/Open311/GetServiceRequestUpdates.pm b/perllib/Open311/GetServiceRequestUpdates.pm
new file mode 100644
index 000000000..c30d05b22
--- /dev/null
+++ b/perllib/Open311/GetServiceRequestUpdates.pm
@@ -0,0 +1,132 @@
+package Open311::GetServiceRequestUpdates;
+
+use Moose;
+use Open311;
+use FixMyStreet::App;
+use DateTime::Format::W3CDTF;
+
+has council_list => ( is => 'ro' );
+has system_user => ( is => 'rw' );
+has start_date => ( is => 'ro', default => undef );
+has end_date => ( is => 'ro', default => undef );
+has suppress_alerts => ( is => 'rw', default => 0 );
+
+sub fetch {
+ my $self = shift;
+
+ my $councils = FixMyStreet::App->model('DB::Open311Conf')->search(
+ {
+ send_method => 'Open311',
+ send_comments => 1,
+ comment_user_id => { '!=', undef },
+ endpoint => { '!=', '' },
+ }
+ );
+
+ while ( my $council = $councils->next ) {
+
+ my $o = Open311->new(
+ endpoint => $council->endpoint,
+ api_key => $council->api_key,
+ jurisdiction => $council->jurisdiction,
+ );
+
+ $self->suppress_alerts( $council->suppress_alerts );
+ $self->system_user( $council->comment_user );
+ $self->update_comments( $o, { areaid => $council->area_id }, );
+ }
+}
+
+sub update_comments {
+ my ( $self, $open311, $council_details ) = @_;
+
+ my @args = ();
+
+ if ( $self->start_date || $self->end_date ) {
+ return 0 unless $self->start_date && $self->end_date;
+
+ push @args, $self->start_date;
+ push @args, $self->end_date;
+ }
+
+ my $requests = $open311->get_service_request_updates( @args );
+
+ unless ( $open311->success ) {
+ warn "Failed to fetch ServiceRequest Updates: " . $open311->error;
+ return 0;
+ }
+
+ for my $request (@$requests) {
+ my $request_id = $request->{service_request_id};
+
+ # If there's no request id then we can't work out
+ # what problem it belongs to so just skip
+ next unless $request_id;
+
+ my $problem =
+ FixMyStreet::App->model('DB::Problem')
+ ->search( {
+ external_id => $request_id,
+ council => { like => '%' . $council_details->{areaid} . '%' },
+ } );
+
+ if (my $p = $problem->first) {
+ my $c = $p->comments->search( { external_id => $request->{update_id} } );
+
+ if ( !$c->first ) {
+ my $comment_time = DateTime::Format::W3CDTF->parse_datetime( $request->{updated_datetime} );
+
+ my $comment = FixMyStreet::App->model('DB::Comment')->new(
+ {
+ problem => $p,
+ user => $self->system_user,
+ external_id => $request->{update_id},
+ text => $request->{description},
+ mark_fixed => 0,
+ mark_open => 0,
+ anonymous => 0,
+ name => $self->system_user->name,
+ confirmed => $comment_time,
+ created => $comment_time,
+ state => 'confirmed',
+ }
+ );
+
+ # if the comment is older than the last update
+ # do not change the status of the problem as it's
+ # tricky to determine the right thing to do.
+ if ( $comment->created_local > $p->lastupdate_local ) {
+ if ( $p->is_open and lc($request->{status}) eq 'closed' ) {
+ $p->state( 'fixed - council' );
+ $comment->problem_state( 'fixed - council' );
+ } elsif ( ( $p->is_closed || $p->is_fixed ) and lc($request->{status}) eq 'open' ) {
+ $p->state( 'confirmed' );
+ $comment->problem_state( 'confirmed' );
+ }
+ }
+
+ $p->lastupdate( $comment->created );
+ $p->update;
+ $comment->insert();
+
+ if ( $self->suppress_alerts ) {
+ my $alert = FixMyStreet::App->model('DB::Alert')->find( {
+ alert_type => 'new_updates',
+ parameter => $p->id,
+ confirmed => 1,
+ user_id => $p->user->id,
+ } );
+
+ my $alerts_sent = FixMyStreet::App->model('DB::AlertSent')->find_or_create( {
+ alert_id => $alert->id,
+ parameter => $comment->id,
+ } );
+ }
+ }
+ }
+ }
+
+ return 1;
+}
+
+1;
diff --git a/perllib/Open311/PopulateServiceList.pm b/perllib/Open311/PopulateServiceList.pm
index cfec9005d..7b5f4c7fe 100644
--- a/perllib/Open311/PopulateServiceList.pm
+++ b/perllib/Open311/PopulateServiceList.pm
@@ -8,6 +8,7 @@ use Open311;
has council_list => ( is => 'ro' );
has found_contacts => ( is => 'rw', default => sub { [] } );
+has verbose => ( is => 'ro', default => 0 );
has _current_council => ( is => 'rw' );
has _current_open311 => ( is => 'rw' );
@@ -81,7 +82,7 @@ sub process_service {
$self->_current_service->{description} :
$self->_current_service->{service_name};
- print $self->_current_service->{service_code} . ': ' . $category . "\n";
+ print $self->_current_service->{service_code} . ': ' . $category . "\n" if $self->verbose;
my $contacts = FixMyStreet::App->model( 'DB::Contact')->search(
{
area_id => $self->_current_council->area_id,
@@ -121,7 +122,7 @@ sub _handle_existing_contact {
my $service_name = $self->_normalize_service_name;
- print $self->_current_council->area_id . " already has a contact for service code " . $self->_current_service->{service_code} . "\n";
+ print $self->_current_council->area_id . " already has a contact for service code " . $self->_current_service->{service_code} . "\n" if $self->verbose;
if ( $contact->deleted || $service_name ne $contact->category || $self->_current_service->{service_code} ne $contact->email ) {
eval {
@@ -179,16 +180,22 @@ sub _create_contact {
if ( $contact ) {
push @{ $self->found_contacts }, $self->_current_service->{service_code};
- print "created contact for service code " . $self->_current_service->{service_code} . " for council @{[$self->_current_council->area_id]}\n";
+ print "created contact for service code " . $self->_current_service->{service_code} . " for council @{[$self->_current_council->area_id]}\n" if $self->verbose;
}
}
-sub _add_contact_to_meta {
+sub _add_meta_to_contact {
my ( $self, $contact ) = @_;
- print "Fetching meta data for $self->_current_service->{service_code}\n";
+ print "Fetching meta data for $self->_current_service->{service_code}\n" if $self->verbose;
my $meta_data = $self->_current_open311->get_service_meta_info( $self->_current_service->{service_code} );
+ if ( ref $meta_data->{ attributes }->{ attribute } eq 'HASH' ) {
+ $meta_data->{ attributes }->{ attribute } = [
+ $meta_data->{ attributes }->{ attribute }
+ ];
+ }
+
# turn the data into something a bit more friendly to use
my @meta =
# remove trailing colon as we add this when we display so we don't want 2
@@ -197,7 +204,31 @@ sub _add_contact_to_meta {
sort { $a->{order} <=> $b->{order} }
@{ $meta_data->{attributes}->{attribute} };
- $contact->extra( \@meta );
+ # we add these later on from bromley so don't list them here
+ # as we don't want to display them
+ if ( $self->_current_council->area_id == 2482 ) {
+ my %ignore = map { $_ => 1 } qw/
+ service_request_id_ext
+ requested_datetime
+ report_url
+ title
+ last_name
+ email
+ easting
+ northing
+ report_title
+ public_anonymity_required
+ email_alerts_requested
+ /;
+
+ @meta = grep { ! $ignore{ $_->{ code } } } @meta;
+ }
+
+ if ( @meta ) {
+ $contact->extra( \@meta );
+ } else {
+ $contact->extra( undef );
+ }
$contact->update;
}
diff --git a/t/app/controller/about.t b/t/app/controller/about.t
index ea7b1af20..4e49cdac9 100644
--- a/t/app/controller/about.t
+++ b/t/app/controller/about.t
@@ -13,7 +13,7 @@ $mech->content_contains('html class="no-js" lang="en-gb"');
SKIP: {
skip( "Need 'emptyhomes' in ALLOWED_COBRANDS config", 8 )
- unless FixMyStreet::App->config->{ALLOWED_COBRANDS} =~ m{emptyhomes};
+ unless FixMyStreet::Cobrand->exists('emptyhomes');
# check that geting the page as EHA produces a different page
ok $mech->host("reportemptyhomes.co.uk"), 'change host to reportemptyhomes';
diff --git a/t/app/controller/admin.t b/t/app/controller/admin.t
index d8a1c24a1..09d99cfdf 100644
--- a/t/app/controller/admin.t
+++ b/t/app/controller/admin.t
@@ -105,34 +105,39 @@ subtest 'check summary counts' => sub {
$mech->content_contains( "$q_count questionnaires sent" );
- ok $mech->host('barnet.fixmystreet.com');
+ SKIP: {
+ skip( "Need 'barnet' in ALLOWED_COBRANDS config", 7 )
+ unless FixMyStreet::Cobrand->exists('barnet');
- $mech->get_ok('/admin');
- $mech->title_like(qr/Summary/);
+ ok $mech->host('barnet.fixmystreet.com');
- my ($num_live) = $mech->content =~ /(\d+)<\/strong> live problems/;
- my ($num_alerts) = $mech->content =~ /(\d+) confirmed alerts/;
- my ($num_qs) = $mech->content =~ /(\d+) questionnaires sent/;
+ $mech->get_ok('/admin');
+ $mech->title_like(qr/Summary/);
- $report->council(2489);
- $report->cobrand('barnet');
- $report->update;
+ my ($num_live) = $mech->content =~ /(\d+)<\/strong> live problems/;
+ my ($num_alerts) = $mech->content =~ /(\d+) confirmed alerts/;
+ my ($num_qs) = $mech->content =~ /(\d+) questionnaires sent/;
- $alert->cobrand('barnet');
- $alert->update;
+ $report->council(2489);
+ $report->cobrand('barnet');
+ $report->update;
- $mech->get_ok('/admin');
+ $alert->cobrand('barnet');
+ $alert->update;
- $mech->content_contains( ($num_live+1) . "</strong> live problems" );
- $mech->content_contains( ($num_alerts+1) . " confirmed alerts" );
- $mech->content_contains( ($num_qs+1) . " questionnaires sent" );
+ $mech->get_ok('/admin');
- $report->council(2504);
- $report->cobrand('');
- $report->update;
+ $mech->content_contains( ($num_live+1) . "</strong> live problems" );
+ $mech->content_contains( ($num_alerts+1) . " confirmed alerts" );
+ $mech->content_contains( ($num_qs+1) . " questionnaires sent" );
+
+ $report->council(2504);
+ $report->cobrand('');
+ $report->update;
- $alert->cobrand('');
- $alert->update;
+ $alert->cobrand('');
+ $alert->update;
+ }
FixMyStreet::App->model('DB::Problem')->search( { council => 1 } )->update( { council => 2489 } );
ok $mech->host('fixmystreet.com');
@@ -222,6 +227,8 @@ subtest 'check open311 configuring' => sub {
api_key => 'api key',
endpoint => 'http://example.com/open311',
jurisdiction => 'mySociety',
+ send_comments => 0,
+ send_method => 'Open311',
}
}
);
@@ -244,6 +251,8 @@ subtest 'check open311 configuring' => sub {
api_key => 'new api key',
endpoint => 'http://example.org/open311',
jurisdiction => 'open311',
+ send_comments => 0,
+ send_method => 'Open311',
}
}
);
diff --git a/t/app/controller/alert_new.t b/t/app/controller/alert_new.t
index 3a4c2ef81..7ba887824 100644
--- a/t/app/controller/alert_new.t
+++ b/t/app/controller/alert_new.t
@@ -142,25 +142,18 @@ foreach my $test (
}
foreach my $test (
- {
- email => 'test-new@example.com',
- type => 'area',
- content => 'your alert will not be activated',
- email_text => 'confirm the alert',
- uri =>
-'/alert/subscribe?type=local&rznvy=test-new@example.com&feed=area:1000:A_Location',
- param1 => 1000
- }
+ { exist => 0 },
+ { exist => 1 },
)
{
- subtest "use existing unlogged in user in a alert" => sub {
+ subtest "use existing unlogged in user in a alert ($test->{exist})" => sub {
$mech->log_out_ok();
- my $type = $test->{type} . '_problems';
+ my $type = 'area_problems';
my $user =
FixMyStreet::App->model('DB::User')
- ->find_or_create( { email => $test->{email} } );
+ ->find_or_create( { email => 'test-new@example.com' } );
my $alert = FixMyStreet::App->model('DB::Alert')->find(
{
@@ -169,24 +162,26 @@ foreach my $test (
}
);
# clear existing data so we can be sure we're creating it
- ok $alert->delete() if $alert;
+ ok $alert->delete() if $alert && !$test->{exist};
- $mech->get_ok( $test->{uri} );
+ $mech->get_ok( '/alert/subscribe?type=local&rznvy=test-new@example.com&feed=area:1000:A_Location' );
$alert = FixMyStreet::App->model('DB::Alert')->find(
{
user => $user,
alert_type => $type,
- parameter => $test->{param1},
- parameter2 => $test->{param2},
- confirmed => 0,
+ parameter => 1000,
+ parameter2 => undef,
+ confirmed => $test->{exist},
}
);
$mech->content_contains( 'Now check your email' );
+ $alert->confirm();
ok $alert, 'New alert created with existing user';
- $mech->delete_user($user);
+
+ $mech->delete_user($user) if $test->{exist};
};
}
@@ -445,6 +440,7 @@ subtest "Test normal alert signups and that alerts are sent" => sub {
ok $update, "created test update - $update_id";
FixMyStreet::App->model('DB::AlertType')->email_alerts();
+ # TODO Note the below will fail if the db has an existing alert that matches
$mech->email_count_is(3);
my @emails = $mech->get_email;
my $count;
diff --git a/t/app/controller/dashboard.t b/t/app/controller/dashboard.t
new file mode 100644
index 000000000..7033fa02c
--- /dev/null
+++ b/t/app/controller/dashboard.t
@@ -0,0 +1,639 @@
+use strict;
+use warnings;
+use Test::More;
+
+use FixMyStreet::TestMech;
+use Web::Scraper;
+
+my $mech = FixMyStreet::TestMech->new;
+
+my $test_user = 'council_user@example.com';
+my $test_pass = 'password';
+my $test_council = 2651;
+my $test_ward = 20723;
+
+$mech->delete_user( $test_user );
+my $user = FixMyStreet::App->model('DB::User')->create( {
+ email => $test_user,
+ password => $test_pass,
+} );
+
+my $p_user = FixMyStreet::App->model('DB::User')->find_or_create( {
+ email => 'p_user@example.com'
+} );
+
+$mech->not_logged_in_ok;
+$mech->get_ok('/dashboard');
+
+$mech->content_contains( 'sign in' );
+
+$mech->submit_form(
+ with_fields => { email => $test_user, password_sign_in => $test_pass }
+);
+
+is $mech->status, '404', 'If not council user get 404';
+
+$user->from_council( $test_council );
+$user->update;
+
+$mech->log_out_ok;
+$mech->get_ok('/dashboard');
+$mech->submit_form_ok( {
+ with_fields => { email => $test_user, password_sign_in => $test_pass }
+} );
+
+$mech->content_contains( 'Summary Statistics for City of Edinburgh' );
+
+FixMyStreet::App->model('DB::Contact')->search( { area_id => $test_council } )
+ ->delete;
+
+delete_problems();
+
+my @cats = qw( Grafitti Litter Potholes );
+for my $contact ( @cats ) {
+ FixMyStreet::App->model('DB::Contact')->create(
+ {
+ area_id => $test_council,
+ category => $contact,
+ email => "$contact\@example.org",
+ confirmed => 1,
+ whenedited => DateTime->now,
+ deleted => 0,
+ editor => 'test',
+ note => 'test',
+ }
+ );
+}
+
+$mech->get_ok('/dashboard');
+
+my $categories = scraper {
+ process "select[name=category] > option", 'cats[]' => 'TEXT',
+ process "select[name=ward] > option", 'wards[]' => 'TEXT',
+ process "table[id=overview] > tr", 'rows[]' => scraper {
+ process 'td', 'cols[]' => 'TEXT'
+ },
+ process "tr[id=total] > td", 'totals[]' => 'TEXT',
+ process "tr[id=fixed_council] > td", 'council[]' => 'TEXT',
+ process "tr[id=fixed_user] > td", 'user[]' => 'TEXT',
+ process "tr[id=total_fixed] > td", 'total_fixed[]' => 'TEXT',
+ process "tr[id=in_progress] > td", 'in_progress[]' => 'TEXT',
+ process "tr[id=planned] > td", 'planned[]' => 'TEXT',
+ process "tr[id=investigating] > td", 'investigating[]' => 'TEXT',
+ process "tr[id=marked] > td", 'marked[]' => 'TEXT',
+ process "tr[id=avg_marked] > td", 'avg_marked[]' => 'TEXT',
+ process "tr[id=avg_fixed] > td", 'avg_fixed[]' => 'TEXT',
+ process "tr[id=not_marked] > td", 'not_marked[]' => 'TEXT',
+ process "tr[id=closed] > td", 'closed[]' => 'TEXT',
+ process "table[id=reports] > tr > td", 'report_lists[]' => scraper {
+ process 'ul > li', 'reports[]' => 'TEXT'
+ },
+};
+
+my $expected_cats = [ 'All', '-- Pick a category --', @cats, 'Other' ];
+my $res = $categories->scrape( $mech->content );
+is_deeply( $res->{cats}, $expected_cats, 'correct list of categories' );
+
+foreach my $row ( @{ $res->{rows} }[1 .. 11] ) {
+ foreach my $col ( @{ $row->{cols} } ) {
+ is $col, 0;
+ }
+}
+
+for my $reports ( @{ $res->{report_lists} } ) {
+ is_deeply $reports, {}, 'No reports';
+}
+
+foreach my $test (
+ {
+ desc => 'confirmed today with no state',
+ dt => DateTime->now,
+ counts => [1,1,1,1],
+ report_counts => [1, 0, 0],
+ },
+ {
+ desc => 'confirmed last 7 days with no state',
+ dt => DateTime->now->subtract( days => 6, hours => 23 ),
+ counts => [1,2,2,2],
+ report_counts => [2, 0, 0],
+ },
+ {
+ desc => 'confirmed last 8 days with no state',
+ dt => DateTime->now->subtract( days => 8 ),
+ counts => [1,2,3,3],
+ report_counts => [2, 1, 0],
+ },
+ {
+ desc => 'confirmed last 4 weeks with no state',
+ dt => DateTime->now->subtract( weeks => 2 ),
+ counts => [1,2,4,4],
+ report_counts => [2, 1, 1],
+ },
+ {
+ desc => 'confirmed this year with no state',
+ dt => DateTime->now->subtract( weeks => 7 ),
+ counts => [1,2,4,5],
+ report_counts => [2, 1, 1],
+ },
+) {
+ subtest $test->{desc} => sub {
+ make_problem( { state => 'confirmed', conf_dt => $test->{dt} } );
+
+ $mech->get_ok('/dashboard');
+ $res = $categories->scrape( $mech->content );
+
+ check_row( $res, 'totals', $test->{counts} );
+ check_row( $res, 'not_marked', $test->{counts} );
+
+ check_report_counts( $res, $test->{report_counts} );
+ };
+}
+
+delete_problems();
+
+foreach my $test (
+ {
+ desc => 'user fixed today',
+ confirm_dt => DateTime->now->subtract( days => 1 ),
+ mark_dt => DateTime->now,
+ state => 'fixed - user',
+ counts => {
+ totals => [1,1,1,1],
+ user => [1,1,1,1],
+ council => [0,0,0,0],
+ avg_fixed => [0,0,0,0],
+ total_fixed => [1,1,1,1],
+ }
+ },
+ {
+ desc => 'council fixed today',
+ confirm_dt => DateTime->now->subtract( days => 1 ),
+ mark_dt => DateTime->now,
+ state => 'fixed - council',
+ counts => {
+ totals => [2,2,2,2],
+ user => [1,1,1,1],
+ council => [1,1,1,1],
+ avg_fixed => [1,1,1,1],
+ total_fixed => [2,2,2,2],
+ }
+ },
+ {
+ desc => 'marked investigating today',
+ confirm_dt => DateTime->now->subtract( days => 1 ),
+ mark_dt => DateTime->now,
+ state => 'investigating',
+ counts => {
+ totals => [3,3,3,3],
+ user => [1,1,1,1],
+ council => [1,1,1,1],
+ total_fixed => [2,2,2,2],
+ avg_marked => [1,1,1,1],
+ investigating => [1,1,1,1],
+ marked => [1,1,1,1]
+ }
+ },
+ {
+ desc => 'marked in progress today',
+ confirm_dt => DateTime->now->subtract( days => 1 ),
+ mark_dt => DateTime->now,
+ state => 'in progress',
+ counts => {
+ totals => [4,4,4,4],
+ user => [1,1,1,1],
+ council => [1,1,1,1],
+ total_fixed => [2,2,2,2],
+ avg_marked => [1,1,1,1],
+ investigating => [1,1,1,1],
+ in_progress => [1,1,1,1],
+ marked => [2,2,2,2]
+ }
+ },
+ {
+ desc => 'marked as planned today',
+ confirm_dt => DateTime->now->subtract( days => 1 ),
+ mark_dt => DateTime->now,
+ state => 'planned',
+ counts => {
+ totals => [5,5,5,5],
+ user => [1,1,1,1],
+ council => [1,1,1,1],
+ total_fixed => [2,2,2,2],
+ avg_marked => [1,1,1,1],
+ investigating => [1,1,1,1],
+ in_progress => [1,1,1,1],
+ planned => [1,1,1,1],
+ marked => [3,3,3,3]
+ }
+ },
+ {
+ desc => 'marked as planned today, confirmed a week ago',
+ confirm_dt => DateTime->now->subtract( days => 8 ),
+ mark_dt => DateTime->now,
+ state => 'planned',
+ counts => {
+ totals => [5,5,6,6],
+ user => [1,1,1,1],
+ council => [1,1,1,1],
+ total_fixed => [2,2,2,2],
+ avg_marked => [3,3,3,3],
+ investigating => [1,1,1,1],
+ in_progress => [1,1,1,1],
+ planned => [2,2,2,2],
+ marked => [4,4,4,4]
+ }
+ },
+ {
+ desc => 'marked as council fixed today, confirmed a week ago',
+ confirm_dt => DateTime->now->subtract( days => 8 ),
+ mark_dt => DateTime->now,
+ state => 'fixed - council',
+ counts => {
+ totals => [5,5,7,7],
+ user => [1,1,1,1],
+ council => [2,2,2,2],
+ total_fixed => [3,3,3,3],
+ avg_fixed => [5,5,5,5],
+ avg_marked => [3,3,3,3],
+ investigating => [1,1,1,1],
+ in_progress => [1,1,1,1],
+ planned => [2,2,2,2],
+ marked => [4,4,4,4]
+ }
+ },
+ {
+ desc => 'marked as council fixed a week ago, confirmed 3 weeks ago',
+ confirm_dt => DateTime->now->subtract( days => 21),
+ mark_dt => DateTime->now->subtract( days => 8 ),
+ state => 'fixed - council',
+ counts => {
+ totals => [5,5,8,8],
+ user => [1,1,1,1],
+ council => [2,2,3,3],
+ total_fixed => [3,3,4,4],
+ avg_fixed => [5,5,7,7],
+ avg_marked => [3,3,3,3],
+ investigating => [1,1,1,1],
+ in_progress => [1,1,1,1],
+ planned => [2,2,2,2],
+ marked => [4,4,4,4]
+ }
+ },
+ {
+ desc => 'marked as user fixed 6 weeks ago, confirmed 7 weeks ago',
+ confirm_dt => DateTime->now->subtract( weeks => 6 ),
+ mark_dt => DateTime->now->subtract( weeks => 7 ),
+ state => 'fixed - user',
+ counts => {
+ totals => [5,5,8,9],
+ user => [1,1,1,2],
+ council => [2,2,3,3],
+ total_fixed => [3,3,4,5],
+ avg_fixed => [5,5,7,7],
+ avg_marked => [3,3,3,3],
+ investigating => [1,1,1,1],
+ in_progress => [1,1,1,1],
+ planned => [2,2,2,2],
+ marked => [4,4,4,4]
+ }
+ },
+ {
+ desc => 'marked as closed',
+ confirm_dt => DateTime->now->subtract( days => 1 ),
+ mark_dt => DateTime->now,
+ state => 'closed',
+ counts => {
+ totals => [6,6,9,10],
+ user => [1,1,1,2],
+ council => [2,2,3,3],
+ total_fixed => [3,3,4,5],
+ avg_fixed => [5,5,7,7],
+ avg_marked => [2,2,2,2],
+ investigating => [1,1,1,1],
+ in_progress => [1,1,1,1],
+ planned => [2,2,2,2],
+ closed => [1,1,1,1],
+ marked => [5,5,5,5]
+ }
+ },
+) {
+ subtest $test->{desc} => sub {
+ make_problem(
+ {
+ state => $test->{state},
+ conf_dt => $test->{confirm_dt},
+ mark_dt => $test->{mark_dt},
+ }
+ );
+
+ $mech->get_ok('/dashboard');
+ $res = $categories->scrape( $mech->content );
+
+ foreach my $row ( keys %{ $test->{counts} } ) {
+ check_row( $res, $row, $test->{counts}->{$row} );
+ }
+ };
+}
+
+delete_problems();
+
+for my $test (
+ {
+ desc => 'Selecting no category does nothing',
+ p1 => {
+ state => 'confirmed',
+ conf_dt => DateTime->now(),
+ category => 'Potholes',
+ },
+ p2 => {
+ state => 'confirmed',
+ conf_dt => DateTime->now(),
+ category => 'Litter',
+ },
+ category => '',
+ counts => {
+ totals => [2,2,2,2],
+ },
+ counts_after => {
+ totals => [2,2,2,2],
+ },
+ report_counts => [2,0,0],
+ report_counts_after => [2,0,0],
+ },
+ {
+ desc => 'Limit display by category',
+ category => 'Potholes',
+ counts => {
+ totals => [2,2,2,2],
+ },
+ counts_after => {
+ totals => [1,1,1,1],
+ },
+ report_counts => [2,0,0],
+ report_counts_after => [1,0,0],
+ },
+ {
+ desc => 'Limit display for category with no entries',
+ category => 'Grafitti',
+ counts => {
+ totals => [2,2,2,2],
+ },
+ counts_after => {
+ totals => [0,0,0,0],
+ },
+ report_counts => [2,0,0],
+ report_counts_after => [0,0,0],
+ },
+ {
+ desc => 'Limit display by category for council fixed',
+ p1 => {
+ state => 'fixed - council',
+ conf_dt => DateTime->now()->subtract( weeks => 1 ),
+ mark_dt => DateTime->now()->subtract( weeks => 1 ),
+ category => 'Potholes',
+ },
+ p2 => {
+ state => 'fixed - council',
+ conf_dt => DateTime->now()->subtract( weeks => 1 ),
+ mark_dt => DateTime->now()->subtract( weeks => 1 ),
+ category => 'Litter',
+ },
+ category => 'Potholes',
+ counts => {
+ council => [0,0,2,2],
+ totals => [2,2,4,4],
+ },
+ counts_after => {
+ council => [0,0,1,1],
+ totals => [1,1,2,2],
+ },
+ report_counts => [2,2,0],
+ report_counts_after => [1,1,0],
+ },
+ {
+ desc => 'Limit display by category for user fixed',
+ p1 => {
+ state => 'fixed - user',
+ conf_dt => DateTime->now()->subtract( weeks => 1 ),
+ mark_dt => DateTime->now()->subtract( weeks => 1 ),
+ category => 'Potholes',
+ },
+ p2 => {
+ state => 'fixed - user',
+ conf_dt => DateTime->now()->subtract( weeks => 1 ),
+ mark_dt => DateTime->now()->subtract( weeks => 1 ),
+ category => 'Litter',
+ },
+ category => 'Potholes',
+ counts => {
+ user => [0,0,2,2],
+ council => [0,0,2,2],
+ totals => [2,2,6,6],
+ },
+ counts_after => {
+ user => [0,0,1,1],
+ council => [0,0,1,1],
+ totals => [1,1,3,3],
+ },
+ report_counts => [2,4,0],
+ report_counts_after => [1,2,0],
+ },
+ {
+ desc => 'Limit display by ward',
+ p1 => {
+ state => 'confirmed',
+ conf_dt => DateTime->now()->subtract( weeks => 1 ),
+ category => 'Potholes',
+ # in real life it has commas around it and the search
+ # uses them
+ areas => ',20720,',
+ },
+ p2 => {
+ state => 'fixed - council',
+ conf_dt => DateTime->now()->subtract( weeks => 1 ),
+ mark_dt => DateTime->now()->subtract( weeks => 1 ),
+ category => 'Litter',
+ areas => ',20720,',
+ },
+ ward => 20720,
+ counts => {
+ user => [0,0,2,2],
+ council => [0,0,3,3],
+ totals => [2,2,8,8],
+ },
+ counts_after => {
+ user => [0,0,0,0],
+ council => [0,0,1,1],
+ totals => [0,0,2,2],
+ },
+ report_counts => [2,6,0],
+ report_counts_after => [0,2,0],
+ },
+) {
+ subtest $test->{desc} => sub {
+ make_problem( $test->{p1} ) if $test->{p1};
+ make_problem( $test->{p2} ) if $test->{p2};
+
+ $mech->get_ok('/dashboard');
+
+ $res = $categories->scrape( $mech->content );
+
+ foreach my $row ( keys %{ $test->{counts} } ) {
+ check_row( $res, $row, $test->{counts}->{$row} );
+ }
+
+ check_report_counts( $res, $test->{report_counts} );
+
+ $mech->submit_form_ok( {
+ with_fields => {
+ category => $test->{category},
+ ward => $test->{ward},
+ }
+ } );
+
+ $res = $categories->scrape( $mech->content );
+
+ foreach my $row ( keys %{ $test->{counts_after} } ) {
+ check_row( $res, $row, $test->{counts_after}->{$row} );
+ }
+ check_report_counts( $res, $test->{report_counts_after} );
+ };
+}
+
+delete_problems();
+
+for my $test (
+ {
+ desc => 'Selecting no state does nothing',
+ p1 => {
+ state => 'fixed - user',
+ conf_dt => DateTime->now(),
+ category => 'Potholes',
+ },
+ p2 => {
+ state => 'confirmed',
+ conf_dt => DateTime->now(),
+ category => 'Litter',
+ },
+ state => '',
+ report_counts => [2,0,0],
+ report_counts_after => [2,0,0],
+ },
+ {
+ desc => 'limit by state works',
+ state => 'fixed',
+ report_counts => [2,0,0],
+ report_counts_after => [1,0,0],
+ },
+ {
+ desc => 'All fixed states count as fixed',
+ p1 => {
+ state => 'fixed - council',
+ conf_dt => DateTime->now(),
+ category => 'Potholes',
+ },
+ p2 => {
+ state => 'fixed',
+ conf_dt => DateTime->now(),
+ category => 'Potholes',
+ },
+ state => 'fixed',
+ report_counts => [4,0,0],
+ report_counts_after => [3,0,0],
+ },
+) {
+ subtest $test->{desc} => sub {
+ make_problem( $test->{p1} ) if $test->{p1};
+ make_problem( $test->{p2} ) if $test->{p2};
+
+ $mech->get_ok('/dashboard');
+
+ $res = $categories->scrape( $mech->content );
+
+ check_report_counts( $res, $test->{report_counts} );
+
+ $mech->submit_form_ok( {
+ with_fields => {
+ state => $test->{state},
+ }
+ } );
+
+ $res = $categories->scrape( $mech->content );
+
+ check_report_counts( $res, $test->{report_counts_after} );
+ };
+}
+
+sub make_problem {
+ my $args = shift;
+
+ my $p = FixMyStreet::App->model('DB::Problem')->create( {
+ title => 'a problem',
+ name => 'a user',
+ anonymous => 1,
+ detail => 'some detail',
+ state => $args->{state},
+ confirmed => $args->{conf_dt},
+ whensent => $args->{conf_dt},
+ lastupdate => $args->{mark_dt} || $args->{conf_dt},
+ council => $test_council,
+ postcode => 'EH99 1SP',
+ latitude => '51',
+ longitude => '1',
+ areas => $args->{areas} || $test_ward,
+ used_map => 0,
+ user_id => $p_user->id,
+ category => $args->{category} || 'Other',
+ } );
+
+ if ( $args->{state} ne 'confirmed' ) {
+ my $c = FixMyStreet::App->model('DB::Comment')->create( {
+ problem => $p,
+ user_id => $p_user->id,
+ state => 'confirmed',
+ problem_state => $args->{state} =~ /^fixed - user|fixed$/ ? undef : $args->{state},
+ confirmed => $args->{mark_dt},
+ text => 'an update',
+ mark_fixed => $args->{state} =~ /fixed/ ? 1 : 0,
+ anonymous => 1,
+ } );
+ }
+}
+
+sub check_row {
+ my $res = shift;
+ my $row = shift;
+ my $totals = shift;
+
+ is $res->{ $row }->[0], $totals->[0], "Correct count in $row for WTD";
+ is $res->{ $row }->[1], $totals->[1], "Correct count in $row for last 7 days";
+ is $res->{ $row }->[2], $totals->[2], "Correct count in $row for last 4 weeks";
+ is $res->{ $row }->[3], $totals->[3], "Correct count in $row for YTD";
+}
+
+sub check_report_counts {
+ my $res = shift;
+ my $counts = shift;
+
+ for my $i ( 0 .. 2 ) {
+ if ( $counts->[$i] == 0 ) {
+ is_deeply $res->{report_lists}->[$i], {}, "No reports for column $i";
+ } else {
+ if ( ref( $res->{report_lists}->[$i]->{reports} ) eq 'ARRAY' ) {
+ is scalar @{ $res->{report_lists}->[$i]->{reports} }, $counts->[$i], "Correct report count for column $i";
+ } else {
+ fail "Correct report count for column $i ( no reports )";
+ }
+ }
+ }
+}
+
+sub delete_problems {
+ FixMyStreet::App->model('DB::Comment')
+ ->search( { 'problem.council' => $test_council }, { join => 'problem' } )
+ ->delete;
+ FixMyStreet::App->model('DB::Problem')
+ ->search( { council => $test_council } )->delete();
+}
+
+done_testing;
diff --git a/t/app/controller/questionnaire.t b/t/app/controller/questionnaire.t
index 0e2a71184..2d4fdb711 100644
--- a/t/app/controller/questionnaire.t
+++ b/t/app/controller/questionnaire.t
@@ -322,67 +322,79 @@ for my $test (
};
}
-# EHA extra checking
-ok $mech->host("reportemptyhomes.com"), 'change host to reportemptyhomes';
-
-# Reset, and all the questionaire sending function - FIXME should it detect site itself somehow?
-$report->send_questionnaire( 1 );
-$report->update;
-$questionnaire->delete;
-FixMyStreet::App->model('DB::Questionnaire')->send_questionnaires( {
- site => 'emptyhomes'
-} );
-$email = $mech->get_email;
-ok $email, "got an email";
-$mech->clear_emails_ok;
-
-like $email->body, qr/fill in this short questionnaire/i, "got questionnaire email";
-($token) = $email->body =~ m{http://.*?/Q/(\S+)};
-ok $token, "extracted questionnaire token '$token'";
-
-$mech->get_ok("/Q/" . $token);
-$mech->content_contains( 'should have reported what they have done' );
-
-# Test already answered the ever reported question, so not shown again
-$dt = $dt->add( weeks => 4 );
-my $questionnaire2 = FixMyStreet::App->model('DB::Questionnaire')->find_or_create(
- {
- problem_id => $report->id,
- whensent => $dt->ymd . ' ' . $dt->hms,
- ever_reported => 1,
- }
-);
-ok $questionnaire2, 'added another questionnaire';
-ok $mech->host("fixmystreet.com"), 'change host to fixmystreet';
-$mech->get_ok("/Q/" . $token);
-$mech->title_like( qr/Questionnaire/ );
-$mech->content_contains( 'Has this problem been fixed?' );
-$mech->content_lacks( 'ever reported' );
-
-# EHA extra checking
-ok $mech->host("reportemptyhomes.com"), 'change host to reportemptyhomes';
-$mech->get_ok("/Q/" . $token);
-$mech->content_contains( 'made a lot of progress' );
-
-$token = FixMyStreet::App->model("DB::Token")->find( { scope => 'questionnaire', token => $token } );
-ok $token, 'found token for questionnaire';
-$questionnaire = FixMyStreet::App->model('DB::Questionnaire')->find( { id => $token->data } );
-ok $questionnaire, 'found questionnaire';
-
-# I18N Unicode extra testing using FiksGataMi
-$report->send_questionnaire( 1 );
-$report->cobrand( 'fiksgatami' );
-$report->update;
-$questionnaire->delete;
-$questionnaire2->delete;
-FixMyStreet::App->model('DB::Questionnaire')->send_questionnaires( { site => 'fixmystreet' } ); # It's either fixmystreet or emptyhomes
-$email = $mech->get_email;
-ok $email, "got an email";
-$mech->clear_emails_ok;
+SKIP: {
+ skip( "Need 'emptyhomes' in ALLOWED_COBRANDS config", 18 )
+ unless FixMyStreet::Cobrand->exists('emptyhomes');
+
+ # EHA extra checking
+ ok $mech->host("reportemptyhomes.com"), 'change host to reportemptyhomes';
+
+ # Reset, and all the questionaire sending function - FIXME should it detect site itself somehow?
+ $report->send_questionnaire( 1 );
+ $report->update;
+ $questionnaire->delete;
+
+ FixMyStreet::App->model('DB::Questionnaire')->send_questionnaires( {
+ site => 'emptyhomes'
+ } );
+ $email = $mech->get_email;
+ ok $email, "got an email";
+ $mech->clear_emails_ok;
+
+ like $email->body, qr/fill in this short questionnaire/i, "got questionnaire email";
+ ($token) = $email->body =~ m{http://.*?/Q/(\S+)};
+ ok $token, "extracted questionnaire token '$token'";
+
+ $mech->get_ok("/Q/" . $token);
+ $mech->content_contains( 'should have reported what they have done' );
+
+ # Test already answered the ever reported question, so not shown again
+ $dt = $dt->add( weeks => 4 );
+ my $questionnaire2 = FixMyStreet::App->model('DB::Questionnaire')->find_or_create(
+ {
+ problem_id => $report->id,
+ whensent => $dt->ymd . ' ' . $dt->hms,
+ ever_reported => 1,
+ }
+ );
+ ok $questionnaire2, 'added another questionnaire';
+ ok $mech->host("fixmystreet.com"), 'change host to fixmystreet';
+ $mech->get_ok("/Q/" . $token);
+ $mech->title_like( qr/Questionnaire/ );
+ $mech->content_contains( 'Has this problem been fixed?' );
+ $mech->content_lacks( 'ever reported' );
+
+ # EHA extra checking
+ ok $mech->host("reportemptyhomes.com"), 'change host to reportemptyhomes';
+ $mech->get_ok("/Q/" . $token);
+ $mech->content_contains( 'made a lot of progress' );
+
+ $token = FixMyStreet::App->model("DB::Token")->find( { scope => 'questionnaire', token => $token } );
+ ok $token, 'found token for questionnaire';
+ $questionnaire = FixMyStreet::App->model('DB::Questionnaire')->find( { id => $token->data } );
+ ok $questionnaire, 'found questionnaire';
+
+ $questionnaire2->delete;
+}
-like $email->body, qr/Testing =96 Detail/, 'email contains encoded character from user';
-like $email->body, qr/sak p=E5 FiksGataMi/, 'email contains encoded character from template';
-is $email->header('Content-Type'), 'text/plain; charset="windows-1252"', 'email is in right encoding';
+SKIP: {
+ skip( "Need 'fiksgatami' in ALLOWED_COBRANDS config", 5 )
+ unless FixMyStreet::Cobrand->exists('fiksgatami');
+
+ # I18N Unicode extra testing using FiksGataMi
+ $report->send_questionnaire( 1 );
+ $report->cobrand( 'fiksgatami' );
+ $report->update;
+ $questionnaire->delete;
+ FixMyStreet::App->model('DB::Questionnaire')->send_questionnaires( { site => 'fixmystreet' } ); # It's either fixmystreet or emptyhomes
+ $email = $mech->get_email;
+ ok $email, "got an email";
+ $mech->clear_emails_ok;
+
+ like $email->body, qr/Testing =96 Detail/, 'email contains encoded character from user';
+ like $email->body, qr/sak p=E5 FiksGataMi/, 'email contains encoded character from template';
+ is $email->header('Content-Type'), 'text/plain; charset="windows-1252"', 'email is in right encoding';
+}
$mech->delete_user('test@example.com');
done_testing();
diff --git a/t/app/controller/report_import.t b/t/app/controller/report_import.t
index 934bf0346..eb686b44e 100644
--- a/t/app/controller/report_import.t
+++ b/t/app/controller/report_import.t
@@ -266,7 +266,7 @@ subtest "Submit a correct entry (with location) to cobrand" => sub {
SKIP: {
skip( "Need 'fiksgatami' in ALLOWED_COBRANDS config", 20 )
- unless FixMyStreet::App->config->{ALLOWED_COBRANDS} =~ m{fiksgatami};
+ unless FixMyStreet::Cobrand->exists('fiksgatami');
mySociety::MaPit::configure('http://mapit.nuug.no/');
ok $mech->host("fiksgatami.no"), 'change host to fiksgatami';
diff --git a/t/app/controller/report_new.t b/t/app/controller/report_new.t
index c16befd37..29fb650e5 100644
--- a/t/app/controller/report_new.t
+++ b/t/app/controller/report_new.t
@@ -52,9 +52,23 @@ my $contact3 = FixMyStreet::App->model('DB::Contact')->find_or_create( {
category => 'Trees',
email => 'trees@example.com',
} );
+my $contact4 = FixMyStreet::App->model('DB::Contact')->find_or_create( {
+ %contact_params,
+ area_id => 2482, # Bromley
+ category => 'Trees',
+ email => 'trees@example.com',
+} );
+my $contact5 = FixMyStreet::App->model('DB::Contact')->find_or_create( {
+ %contact_params,
+ area_id => 2651, # Edinburgh
+ category => 'Trees',
+ email => 'trees@example.com',
+} );
ok $contact1, "created test contact 1";
ok $contact2, "created test contact 2";
ok $contact3, "created test contact 3";
+ok $contact4, "created test contact 4";
+ok $contact5, "created test contact 5";
# test that the various bit of form get filled in and errors correctly
# generated.
@@ -360,7 +374,7 @@ foreach my $test (
is_deeply $mech->form_errors, [], "no errors for pc '$test->{pc}'";
# click through to the report page
- $mech->follow_link_ok( { text => 'skip this step', },
+ $mech->follow_link_ok( { text_regex => qr/skip this step/i, },
"follow 'skip this step' link" );
# submit the main form
@@ -540,7 +554,7 @@ subtest "test password errors for a user who is signing in as they report" => su
"submit location" );
# click through to the report page
- $mech->follow_link_ok( { text => 'Skip this step', },
+ $mech->follow_link_ok( { text_regex => qr/skip this step/i, },
"follow 'skip this step' link" );
$mech->submit_form_ok(
@@ -587,7 +601,7 @@ subtest "test report creation for a user who is signing in as they report" => su
"submit location" );
# click through to the report page
- $mech->follow_link_ok( { text => 'Skip this step', },
+ $mech->follow_link_ok( { text_regex => qr/skip this step/i, },
"follow 'skip this step' link" );
$mech->submit_form_ok(
@@ -681,7 +695,7 @@ foreach my $test (
"submit location" );
# click through to the report page
- $mech->follow_link_ok( { text => 'Skip this step', },
+ $mech->follow_link_ok( { text_regex => qr/skip this step/i, },
"follow 'skip this step' link" );
# check that the fields are correctly prefilled
@@ -784,7 +798,7 @@ subtest "check that a lat/lon off coast leads to /around" => sub {
is $mech->uri->path, '/around', "redirected to '/around'";
is_deeply #
- $mech->page_errors,
+ $mech->form_errors,
[ 'That spot does not appear to be covered by a council. If you have'
. ' tried to report an issue past the shoreline, for example, please'
. ' specify the closest point on land.' ], #
@@ -792,8 +806,145 @@ subtest "check that a lat/lon off coast leads to /around" => sub {
};
+for my $test (
+ {
+ desc => 'user title not set if not bromley problem',
+ host => 'http://www.fixmystreet.com',
+ postcode => 'EH99 1SP',
+ fms_extra_title => '',
+ extra => undef,
+ user_title => undef,
+ },
+ {
+ desc => 'title shown for bromley problem on main site',
+ host => 'http://www.fixmystreet.com',
+ postcode => 'BR1 3UH',
+ fms_extra_title => 'MR',
+ extra => [
+ {
+ name => 'fms_extra_title',
+ value => 'MR',
+ description => 'FMS_EXTRA_TITLE',
+ },
+ ],
+ user_title => 'MR',
+ },
+ {
+ desc =>
+ 'title, first and last name shown for bromley problem on cobrand',
+ host => 'http://bromley.fixmystreet.com',
+ postcode => 'BR1 3UH',
+ first_name => 'Test',
+ last_name => 'User',
+ fms_extra_title => 'MR',
+ extra => [
+ {
+ name => 'fms_extra_title',
+ value => 'MR',
+ description => 'FMS_EXTRA_TITLE',
+ },
+ {
+ name => 'first_name',
+ value => 'Test',
+ description => 'FIRST_NAME',
+ },
+ {
+ name => 'last_name',
+ value => 'User',
+ description => 'LAST_NAME',
+ },
+ ],
+ user_title => 'MR',
+ },
+ )
+{
+ subtest $test->{desc} => sub {
+ $mech->host( $test->{host} );
+
+ $mech->log_out_ok;
+ $mech->clear_emails_ok;
+
+ $mech->get_ok('/');
+ $mech->submit_form_ok( { with_fields => { pc => $test->{postcode}, } },
+ "submit location" );
+ $mech->follow_link_ok(
+ { text_regex => qr/skip this step/i, },
+ "follow 'skip this step' link"
+ );
+
+ my $fields = $mech->visible_form_values('mapSkippedForm');
+ if ( $test->{fms_extra_title} ) {
+ ok exists( $fields->{fms_extra_title} ), 'user title field displayed';
+ } else {
+ ok !exists( $fields->{fms_extra_title} ), 'user title field not displayed';
+ }
+ if ( $test->{first_name} ) {
+ ok exists( $fields->{first_name} ), 'first name field displayed';
+ ok exists( $fields->{last_name} ), 'last name field displayed';
+ ok !exists( $fields->{name} ), 'no name field displayed';
+ }
+ else {
+ ok !exists( $fields->{first_name} ),
+ 'first name field not displayed';
+ ok !exists( $fields->{last_name} ), 'last name field not displayed';
+ ok exists( $fields->{name} ), 'name field displayed';
+ }
+
+ my $submission_fields = {
+ title => "Test Report",
+ detail => 'Test report details.',
+ photo => '',
+ email => 'firstlast@example.com',
+ may_show_name => '1',
+ phone => '07903 123 456',
+ category => 'Trees',
+ password_register => '',
+ };
+
+ $submission_fields->{fms_extra_title} = $test->{fms_extra_title}
+ if $test->{fms_extra_title};
+
+ if ( $test->{first_name} ) {
+ $submission_fields->{first_name} = $test->{first_name};
+ $submission_fields->{last_name} = $test->{last_name};
+ }
+ else {
+ $submission_fields->{name} = 'Test User';
+ }
+
+ $mech->submit_form_ok( { with_fields => $submission_fields },
+ "submit good details" );
+
+ my $email = $mech->get_email;
+ ok $email, "got an email";
+ like $email->body, qr/confirm the problem/i, "confirm the problem";
+
+ my ($url) = $email->body =~ m{(https?://\S+)};
+ ok $url, "extracted confirm url '$url'";
+
+ # confirm token in order to update the user details
+ $mech->get_ok($url);
+
+ my $user =
+ FixMyStreet::App->model('DB::User')
+ ->find( { email => 'firstlast@example.com' } );
+
+ my $report = $user->problems->first;
+ ok $report, "Found the report";
+ my $extras = $report->extra;
+ is $user->title, $test->{'user_title'}, 'user title correct';
+ is_deeply $extras, $test->{extra}, 'extra contains correct values';
+
+ $user->problems->delete;
+ $user->alerts->delete;
+ $user->delete;
+ };
+}
+
$contact1->delete;
$contact2->delete;
$contact3->delete;
+$contact4->delete;
+$contact5->delete;
done_testing();
diff --git a/t/app/controller/report_updates.t b/t/app/controller/report_updates.t
index 9c2b0861b..0337a881b 100644
--- a/t/app/controller/report_updates.t
+++ b/t/app/controller/report_updates.t
@@ -872,7 +872,11 @@ for my $test (
is_deeply $values, $test->{initial_values}, 'initial form values';
- is $mech->extract_problem_banner->{text}, $test->{initial_banner}, 'initial banner';
+ if ( !defined( $test->{initial_banner} ) ) {
+ is $mech->extract_problem_banner->{text}, undef, 'initial banner';
+ } else {
+ like $mech->extract_problem_banner->{text}, qr/@{[ $test->{initial_banner} ]}/i, 'initial banner';
+ }
$mech->submit_form_ok(
{
@@ -883,7 +887,11 @@ for my $test (
is $mech->uri->path, "/report/" . $report_id, "redirected to report page";
- is $mech->extract_problem_banner->{text}, $test->{endstate_banner}, 'submitted banner';
+ if ( !defined( $test->{endstate_banner} ) ) {
+ is $mech->extract_problem_banner->{text}, undef, 'endstate banner';
+ } else {
+ like $mech->extract_problem_banner->{text}, qr/@{[ $test->{endstate_banner} ]}/i, 'endstate banner';
+ }
$mech->email_count_is(0);
@@ -1029,8 +1037,12 @@ foreach my $test (
is_deeply $values, $test->{initial_values}, 'initial form values';
- is $mech->extract_problem_banner->{text}, $test->{initial_banner},
- 'initial banner';
+ if ( !defined( $test->{initial_banner} ) ) {
+ is $mech->extract_problem_banner->{text}, undef, 'initial banner';
+ } else {
+ like $mech->extract_problem_banner->{text}, qr/@{[ $test->{initial_banner} ]}/i,
+ 'initial banner';
+ }
$mech->submit_form_ok( { with_fields => $test->{fields}, },
'submit update' );
diff --git a/t/app/controller/reports.t b/t/app/controller/reports.t
index 58803d778..801dbeddb 100644
--- a/t/app/controller/reports.t
+++ b/t/app/controller/reports.t
@@ -17,14 +17,14 @@ $mech->follow_link_ok( { text_regex => qr/Birmingham/ } );
SKIP: {
skip( "Need 'emptyhomes' in ALLOWED_COBRANDS config", 8 )
- unless FixMyStreet::App->config->{ALLOWED_COBRANDS} =~ m{emptyhomes};
+ unless FixMyStreet::Cobrand->exists('emptyhomes');
ok $mech->host("reportemptyhomes.com"), 'change host to reportemptyhomes';
$mech->get_ok('/reports');
# EHA lacks one column the others have
$mech->content_lacks('state unknown');
skip( "Need 'fiksgatami' in ALLOWED_COBRANDS config", 8 )
- unless FixMyStreet::App->config->{ALLOWED_COBRANDS} =~ m{fiksgatami};
+ unless FixMyStreet::Cobrand->exists('fiksgatami');
mySociety::MaPit::configure('http://mapit.nuug.no/');
ok $mech->host("fiksgatami.no"), 'change host to fiksgatami';
$mech->get_ok('/reports');
diff --git a/t/app/model/problem.t b/t/app/model/problem.t
index 638e89200..a7415851b 100644
--- a/t/app/model/problem.t
+++ b/t/app/model/problem.t
@@ -7,6 +7,7 @@ use Test::More;
use FixMyStreet;
use FixMyStreet::App;
+use FixMyStreet::TestMech;
use mySociety::Locale;
mySociety::Locale::gettext_domain('FixMyStreet');
@@ -16,8 +17,8 @@ my $problem_rs = FixMyStreet::App->model('DB::Problem');
my $problem = $problem_rs->new(
{
postcode => 'EH99 1SP',
- latitude => 1,
- longitude => 1,
+ latitude => '51.5016605453401',
+ longitude => '-0.142497580865087',
areas => 1,
title => '',
detail => '',
@@ -345,6 +346,131 @@ for my $test (
};
}
+my $mech = FixMyStreet::TestMech->new();
+
+FixMyStreet::App->model('DB::Contact')->find_or_create(
+ {
+ area_id => 2651,
+ category => 'potholes',
+ email => 'test@example.org',
+ confirmed => 1,
+ deleted => 0,
+ editor => 'test',
+ whenedited => \'ms_current_timestamp()',
+ note => '',
+ }
+);
+
+FixMyStreet::App->model('DB::Contact')->find_or_create(
+ {
+ area_id => 2226,
+ category => 'potholes',
+ email => '2226@example.org',
+ confirmed => 1,
+ deleted => 0,
+ editor => 'test',
+ whenedited => \'ms_current_timestamp()',
+ note => '',
+ }
+);
+
+FixMyStreet::App->model('DB::Contact')->find_or_create(
+ {
+ area_id => 2326,
+ category => 'potholes',
+ email => '2326@example.org',
+ confirmed => 1,
+ deleted => 0,
+ editor => 'test',
+ whenedited => \'ms_current_timestamp()',
+ note => '',
+ }
+);
+
+foreach my $test ( {
+ desc => 'sends an email',
+ unset_whendef => 1,
+ email_count => 1,
+ email => 'system_user@example.com',
+ name => 'Andrew Smith',
+ dear => qr'Dear City of Edinburgh Council',
+ to => qr'City of Edinburgh Council',
+ council => 2651,
+ },
+ {
+ desc => 'no email sent if no unsent problems',
+ unset_whendef => 0,
+ email_count => 0,
+ email => 'system_user@example.com',
+ name => 'Andrew Smith',
+ council => 2651,
+ },
+ {
+ desc => 'email to two tier council',
+ unset_whendef => 1,
+ email_count => 1,
+ email => 'system_user@example.com',
+ name => 'Andrew Smith',
+ to => qr'Gloucestershire County Council.*Cheltenham Borough Council',
+ dear => qr'Dear Gloucestershire County Council and Cheltenham Borough',
+ council => '2226,2326',
+ multiple => 1,
+ },
+ {
+ desc => 'email to two tier council with one missing details',
+ unset_whendef => 1,
+ email_count => 1,
+ email => 'system_user@example.com',
+ name => 'Andrew Smith',
+ to => qr'Gloucestershire County Council',
+ dear => qr'Dear Gloucestershire County Council,',
+ council => '2226|2649',
+ missing => qr'problem might be the responsibility of Fife.*Council'ms,
+ },
+) {
+ subtest $test->{ desc } => sub {
+ $mech->clear_emails_ok;
+
+ FixMyStreet::App->model('DB::Problem')->search(
+ {
+ whensent => undef
+ }
+ )->update( { whensent => \'ms_current_timestamp()' } );
+
+ $problem->discard_changes;
+ $problem->update( {
+ council => $test->{ council },
+ state => 'confirmed',
+ confirmed => \'ms_current_timestamp()',
+ whensent => $test->{ unset_whendef } ? undef : \'ms_current_timestamp()',
+ category => 'potholes',
+ name => $test->{ name },
+ } );
+
+ FixMyStreet::App->model('DB::Problem')->send_reports();
+
+ $mech->email_count_is( $test->{ email_count } );
+ if ( $test->{ email_count } ) {
+ my $email = $mech->get_email;
+ like $email->header('To'), $test->{ to }, 'to line looks correct';
+ is $email->header('From'), sprintf('"%s" <%s>', $test->{ name }, $test->{ email } ), 'from line looks correct';
+ like $email->header('Subject'), qr/A Title/, 'subject line looks correct';
+ like $email->body, qr/A user of FixMyStreet/, 'email body looks a bit like a report';
+ like $email->body, qr/Subject: A Title/, 'more email body checking';
+ like $email->body, $test->{ dear }, 'Salutation looks correct';
+
+ if ( $test->{multiple} ) {
+ like $email->body, qr/This email has been sent to several councils /, 'multiple council text correct';
+ } elsif ( $test->{ missing } ) {
+ like $email->body, $test->{ missing }, 'missing council information correct';
+ }
+
+ $problem->discard_changes;
+ ok defined( $problem->whensent ), 'whensent set';
+ }
+ };
+}
+
$problem->comments->delete;
$problem->delete;
$user->delete;
diff --git a/t/app/uri_for.t b/t/app/uri_for.t
index 51a6e8a0e..eecf30e32 100644
--- a/t/app/uri_for.t
+++ b/t/app/uri_for.t
@@ -78,31 +78,36 @@ is(
'FiksGataMi url with lat not zoom'
);
-like(
- $reh_en_c->uri_for_email( '/foo' ),
- qr{^http://en.},
- 'adds en to retain language'
-);
-
-# instantiate this here otherwise sets locale to cy and breaks test
-# above
-my $reh_cy_c = FixMyStreet::App->new(
- {
- request => Catalyst::Request->new(
- {
- base => URI->new('http://cy.reportemptyhomes.com/'),
- uri => URI->new('http://cy.reportemptyhomes.com/test_namespace')
- }
- ),
- namespace => 'test_namespace',
- }
-);
-$reh_cy_c->setup_request();
-
-like(
- $reh_cy_c->uri_for_email( '/foo' ),
- qr{^http://cy.},
- 'retains language'
-);
+SKIP: {
+ skip( "Need 'emptyhomes' in ALLOWED_COBRANDS config", 2 )
+ unless FixMyStreet::Cobrand->exists('emptyhomes');
+
+ like(
+ $reh_en_c->uri_for_email( '/foo' ),
+ qr{^http://en.},
+ 'adds en to retain language'
+ );
+
+ # instantiate this here otherwise sets locale to cy and breaks test
+ # above
+ my $reh_cy_c = FixMyStreet::App->new(
+ {
+ request => Catalyst::Request->new(
+ {
+ base => URI->new('http://cy.reportemptyhomes.com/'),
+ uri => URI->new('http://cy.reportemptyhomes.com/test_namespace')
+ }
+ ),
+ namespace => 'test_namespace',
+ }
+ );
+ $reh_cy_c->setup_request();
+
+ like(
+ $reh_cy_c->uri_for_email( '/foo' ),
+ qr{^http://cy.},
+ 'retains language'
+ );
+}
done_testing();
diff --git a/t/cobrand/get_council_sender.t b/t/cobrand/get_council_sender.t
new file mode 100644
index 000000000..9004a47f5
--- /dev/null
+++ b/t/cobrand/get_council_sender.t
@@ -0,0 +1,30 @@
+use strict;
+use warnings;
+
+use Test::More;
+
+use mySociety::Locale;
+use FixMyStreet::App;
+
+use_ok 'FixMyStreet::Cobrand';
+
+mySociety::Locale::gettext_domain( 'FixMyStreet' );
+
+my $c = FixMyStreet::Cobrand::FixMyStreet->new();
+
+
+is $c->get_council_sender( '1000', { type => 'DIS' } ), 'Email', 'defaults to email';
+is $c->get_council_sender( '1000', { type => 'LBO' } ), 'London', 'returns london report it if London borough';
+
+my $conf = FixMyStreet::App->model('DB::Open311Conf')->find_or_create(
+ area_id => 1000,
+ endpoint => '',
+ send_method => 'TestMethod'
+);
+
+is $c->get_council_sender( '1000', { type => 'LBO' } ), 'TestMethod', 'uses send_method in preference to London';
+is $c->get_council_sender( '1000', { type => 'DIS' } ), 'TestMethod', 'uses send_method in preference to Email';
+
+$conf->delete;
+
+done_testing();
diff --git a/t/open311.t b/t/open311.t
index 30de330b6..814b11f82 100644
--- a/t/open311.t
+++ b/t/open311.t
@@ -5,6 +5,10 @@ use warnings;
use Test::More;
use Test::Warn;
use FixMyStreet::App;
+use CGI::Simple;
+use HTTP::Response;
+use DateTime;
+use DateTime::Format::W3CDTF;
use FindBin;
use lib "$FindBin::Bin/../perllib";
@@ -39,4 +43,451 @@ my $expected_error = qr{.*request failed: 500 Can.t connect to 192.168.50.1:80 \
warning_like {$o2->send_service_request( $p, { url => 'http://example.com/' }, 1 )} $expected_error, 'warning generated on failed call';
+my $dt = DateTime->now();
+
+my $user = FixMyStreet::App->model('DB::User')->new( {
+ name => 'Test User',
+ email => 'test@example.com',
+} );
+
+my $problem = FixMyStreet::App->model('DB::Problem')->new( {
+ id => 80,
+ external_id => 81,
+ state => 'confirmed',
+ title => 'a problem',
+ detail => 'problem detail',
+ category => 'pothole',
+ latitude => 1,
+ longitude => 2,
+ user => $user,
+} );
+
+subtest 'posting service request' => sub {
+ my $extra = {
+ url => 'http://example.com/report/1',
+ };
+
+ my $results = make_service_req( $problem, $extra, $problem->category, '<?xml version="1.0" encoding="utf-8"?><service_requests><request><service_request_id>248</service_request_id></request></service_requests>' );
+
+ is $results->{ res }, 248, 'got request id';
+
+ my $req = $o->test_req_used;
+
+ my $description = <<EOT;
+title: a problem
+
+detail: problem detail
+
+url: http://example.com/report/1
+
+Submitted via FixMyStreet
+EOT
+;
+
+ my $c = CGI::Simple->new( $results->{ req }->content );
+
+ is $c->param('email'), $user->email, 'correct email';
+ is $c->param('first_name'), 'Test', 'correct first name';
+ is $c->param('last_name'), 'User', 'correct last name';
+ is $c->param('lat'), 1, 'latitide correct';
+ is $c->param('long'), 2, 'longitude correct';
+ is $c->param('description'), $description, 'description correct';
+ is $c->param('service_code'), 'pothole', 'service code correct';
+};
+
+subtest 'posting service request with basic_description' => sub {
+ my $extra = {
+ url => 'http://example.com/report/1',
+ };
+
+ my $results = make_service_req(
+ $problem,
+ $extra,
+ $problem->category,
+ '<?xml version="1.0" encoding="utf-8"?><service_requests><request><service_request_id>248</service_request_id></request></service_requests>',
+ { basic_description => 1 },
+ );
+
+ is $results->{ res }, 248, 'got request id';
+
+ my $req = $o->test_req_used;
+
+ my $c = CGI::Simple->new( $results->{ req }->content );
+
+ is $c->param('description'), $problem->detail, 'description correct';
+};
+
+for my $test (
+ {
+ desc => 'extra values in service request',
+ extra => [
+ {
+ name => 'title',
+ value => 'A title',
+ }
+ ],
+ params => [
+ [ 'attribute[title]', 'A title', 'extra paramater used correctly' ]
+ ]
+ },
+ {
+ desc => 'first and last names in extra used correctly',
+ extra => [
+ {
+ name => 'first_name',
+ value => 'First',
+ },
+ {
+ name => 'last_name',
+ value => 'Last',
+ },
+ ],
+ params => [
+ [ 'first_name', 'First', 'first name correct' ],
+ [ 'last_name', 'Last', 'last name correct' ],
+ [ 'attribute[first_name]', undef, 'no first_name attribute param' ],
+ [ 'attribute[last_name]', 'Last', 'last_name attribute param correct' ],
+ ],
+ },
+ {
+ title => 'magic fms_extra parameters handled correctly',
+ extra => [
+ {
+ name => 'fms_extra_title',
+ value => 'Extra title',
+ }
+ ],
+ params => [
+ [
+ 'attribute[title]',
+ 'Extra title',
+ 'fms_extra extra param used correctly'
+ ]
+ ],
+ },
+ )
+{
+ subtest $test->{desc} => sub {
+ $problem->extra( $test->{extra} );
+
+ my $extra = { url => 'http://example.com/report/1', };
+
+ my $results = make_service_req( $problem, $extra, $problem->category,
+'<?xml version="1.0" encoding="utf-8"?><service_requests><request><service_request_id>248</service_request_id></request></service_requests>'
+ );
+ my $req = $o->test_req_used;
+ my $c = CGI::Simple->new( $results->{req}->content );
+
+ for my $param ( @{ $test->{params} } ) {
+ is $c->param( $param->[0] ), $param->[1], $param->[2];
+ }
+ };
+}
+
+my $comment = FixMyStreet::App->model('DB::Comment')->new( {
+ id => 38362,
+ user => $user,
+ problem => $problem,
+ anonymous => 0,
+ text => 'this is a comment',
+ confirmed => $dt,
+ extra => { title => 'Mr', email_alerts_requested => 0 },
+} );
+
+subtest 'basic request update post parameters' => sub {
+ my $results = make_update_req( $comment, '<?xml version="1.0" encoding="utf-8"?><service_request_updates><request_update><update_id>248</update_id></request_update></service_request_updates>' );
+
+ is $results->{ res }, 248, 'got update id';
+
+ my $req = $o->test_req_used;
+
+ my $c = CGI::Simple->new( $results->{ req }->content );
+
+ is $c->param('description'), 'this is a comment', 'email correct';
+ is $c->param('email'), 'test@example.com', 'email correct';
+ is $c->param('status'), 'OPEN', 'status correct';
+ is $c->param('service_request_id_ext'), 80, 'external request id correct';
+ is $c->param('service_request_id'), 81, 'request id correct';
+ is $c->param('public_anonymity_required'), 'FALSE', 'anon status correct';
+ is $c->param('updated_datetime'), DateTime::Format::W3CDTF->format_datetime($dt), 'correct date';
+ is $c->param('title'), 'Mr', 'correct title';
+ is $c->param('last_name'), 'User', 'correct first name';
+ is $c->param('first_name'), 'Test', 'correct second name';
+ is $c->param('email_alerts_requested'), 'FALSE', 'email alerts flag correct';
+ is $c->param('media_url'), undef, 'no media url';
+};
+
+subtest 'check media url set' => sub {
+ $comment->photo(1);
+ $comment->cobrand('fixmystreet');
+
+ my $results = make_update_req( $comment, '<?xml version="1.0" encoding="utf-8"?><service_request_updates><request_update><update_id>248</update_id></request_update></service_request_updates>' );
+
+ is $results->{ res }, 248, 'got update id';
+
+ my $req = $o->test_req_used;
+
+ my $c = CGI::Simple->new( $results->{ req }->content );
+ my $expected_path = '/c/' . $comment->id . '.full.jpeg';
+ like $c->param('media_url'), qr/$expected_path/, 'image url included';
+};
+
+foreach my $test (
+ {
+ desc => 'comment with fixed state sends status of CLOSED',
+ state => 'fixed',
+ anon => 0,
+ status => 'CLOSED',
+ },
+ {
+ desc => 'comment with fixed - user state sends status of CLOSED',
+ state => 'fixed - user',
+ anon => 0,
+ status => 'CLOSED',
+ },
+ {
+ desc => 'comment with fixed - council state sends status of CLOSED',
+ state => 'fixed - council',
+ anon => 0,
+ status => 'CLOSED',
+ },
+ {
+ desc => 'comment with closed state sends status of CLOSED',
+ state => 'closed',
+ anon => 0,
+ status => 'CLOSED',
+ },
+ {
+ desc => 'comment with investigating state sends status of OPEN',
+ state => 'investigating',
+ anon => 0,
+ status => 'OPEN',
+ },
+ {
+ desc => 'comment with planned state sends status of OPEN',
+ state => 'planned',
+ anon => 0,
+ status => 'OPEN',
+ },
+ {
+ desc => 'comment with in progress state sends status of OPEN',
+ state => 'in progress',
+ anon => 0,
+ status => 'OPEN',
+ },
+ {
+ desc => 'anonymous commment sets public_anonymity_required to true',
+ state => 'confirmed',
+ anon => 1,
+ status => 'OPEN',
+ },
+) {
+ subtest $test->{desc} => sub {
+ $comment->problem->state( $test->{state} );
+ $comment->anonymous( $test->{anon} );
+
+ my $results = make_update_req( $comment, '<?xml version="1.0" encoding="utf-8"?><service_request_updates><request_update><update_id>248</update_id></request_update></service_request_updates>' );
+
+ my $c = CGI::Simple->new( $results->{ req }->content );
+ is $c->param('status'), $test->{status}, 'correct status';
+ is $c->param('public_anonymity_required'), $test->{anon} ? 'TRUE' : 'FALSE', 'correct anonymity';
+ };
+}
+
+
+for my $test (
+ {
+ desc => 'update name name taken from comment over user',
+ comment_name => 'First Last',
+ user_name => 'Personal Family',
+ extra => undef,
+ first_name => 'First',
+ last_name => 'Last'
+ },
+ {
+ desc => 'update name name taken from user if no comment name',
+ comment_name => '',
+ user_name => 'Personal Family',
+ extra => undef,
+ first_name => 'Personal',
+ last_name => 'Family'
+ },
+ {
+ desc => 'update name taken from extra if available',
+ comment_name => 'First Last',
+ user_name => 'Personal Family',
+ extra => { first_name => 'Forename', last_name => 'Surname' },
+ first_name => 'Forename',
+ last_name => 'Surname'
+ },
+ )
+{
+ subtest $test->{desc} => sub {
+ $comment->name( $test->{comment_name} );
+ $user->name( $test->{user_name} );
+ $comment->extra( $test->{ extra } );
+
+ my $results = make_update_req( $comment,
+'<?xml version="1.0" encoding="utf-8"?><service_request_updates><request_update><update_id>248</update_id></request_update></service_request_updates>'
+ );
+
+ my $c = CGI::Simple->new( $results->{req}->content );
+ is $c->param('first_name'), $test->{first_name}, 'first name correct';
+ is $c->param('last_name'), $test->{last_name}, 'last name correct';
+ };
+}
+
+for my $test (
+ {
+ desc => 'use lat long forces lat long even if map not used',
+ use_latlong => 1,
+ postcode => 'EH99 1SP',
+ used_map => 0,
+ includes_latlong => 1,
+ },
+ {
+ desc => 'no use lat long and no map sends address instead of lat long',
+ use_latlong => 0,
+ postcode => 'EH99 1SP',
+ used_map => 0,
+ includes_latlong => 0,
+ },
+ {
+ desc => 'no use lat long but used map sends lat long',
+ use_latlong => 0,
+ postcode => 'EH99 1SP',
+ used_map => 1,
+ includes_latlong => 1,
+ },
+ {
+ desc => 'no use lat long, no map and no postcode sends lat long',
+ use_latlong => 0,
+ postcode => '',
+ used_map => 0,
+ includes_latlong => 1,
+ },
+ {
+ desc => 'no use lat long, no map and no postcode sends lat long',
+ use_latlong => 0,
+ notpinpoint => 1,
+ postcode => '',
+ used_map => 0,
+ includes_latlong => 0,
+ }
+) {
+ subtest $test->{desc} => sub {
+ my $extra = { url => 'http://example.com/report/1', };
+ $problem->used_map( $test->{used_map} );
+ $problem->postcode( $test->{postcode} );
+
+ my $results = make_service_req(
+ $problem,
+ $extra,
+ $problem->category,
+ '<?xml version="1.0" encoding="utf-8"?><service_requests><request><service_request_id>248</service_request_id></request></service_requests>',
+ { always_send_latlong => $test->{use_latlong},
+ send_notpinpointed => $test->{notpinpoint} },
+ );
+
+ is $results->{ res }, 248, 'got request id';
+
+ my $c = CGI::Simple->new( $results->{ req }->content );
+
+ if ( $test->{notpinpoint} ) {
+ is $c->param('lat'), undef, 'no latitude';
+ is $c->param('long'), undef, 'no longitude';
+ is $c->param('address_string'), undef, 'no address';
+ is $c->param('address_id'), '#NOTPINPOINTED#', 'has not pinpointed';
+ } elsif ( $test->{includes_latlong} ) {
+ ok $c->param('lat'), 'has latitude';
+ ok $c->param('long'), 'has longitude';
+ is $c->param('address_string'), undef, 'no address';
+ } else {
+ is $c->param('lat'), undef, 'no latitude';
+ is $c->param('long'), undef, 'no latitude';
+ is $c->param('address_string'), $test->{postcode}, 'has address';
+ }
+ };
+}
+
+subtest 'No update id in reponse' => sub {
+ my $results;
+ warning_like {
+ $results = make_update_req( $comment, '<?xml version="1.0" encoding="utf-8"?><service_request_updates><request_update><update_id></update_id></request_update></service_request_updates>' )
+ } qr/Failed to submit comment \d+ over Open311/, 'correct error message';
+
+ is $results->{ res }, 0, 'No update_id is a failure';
+};
+
+subtest 'error reponse' => sub {
+ my $results;
+ warning_like {
+ $results = make_update_req( $comment, '<?xml version="1.0" encoding="utf-8"?><errors><error><code>400</code><description>There was an error</description</error></errors>' )
+ } qr/Failed to submit comment \d+ over Open311.*There was an error/, 'correct error messages';
+
+ is $results->{ res }, 0, 'error in response is a failure';
+};
+
done_testing();
+
+sub make_update_req {
+ my $comment = shift;
+ my $xml = shift;
+
+ return make_req(
+ {
+ object => $comment,
+ xml => $xml,
+ method => 'post_service_request_update',
+ path => 'update.xml',
+ }
+ );
+}
+
+sub make_service_req {
+ my $problem = shift;
+ my $extra = shift;
+ my $service_code = shift;
+ my $xml = shift;
+ my $open311_args = shift || {};
+
+ return make_req(
+ {
+ object => $problem,
+ xml => $xml,
+ method => 'send_service_request',
+ path => 'requests.xml',
+ method_args => [ $extra, $service_code ],
+ open311_conf => $open311_args,
+ }
+ );
+}
+
+sub make_req {
+ my $args = shift;
+
+ my $object = $args->{object};
+ my $xml = $args->{xml};
+ my $method = $args->{method};
+ my $path = $args->{path};
+ my %open311_conf = %{ $args->{open311_conf} || {} };
+ my @args = @{ $args->{method_args} || [] };
+
+ $open311_conf{'test_mode'} = 1;
+ $open311_conf{'end_point'} = 'http://localhost/o311';
+ my $o =
+ Open311->new( %open311_conf );
+
+ my $test_res = HTTP::Response->new();
+ $test_res->code(200);
+ $test_res->message('OK');
+ $test_res->content($xml);
+
+ $o->test_get_returns( { $path => $test_res } );
+
+ my $res = $o->$method($object, @args);
+
+ my $req = $o->test_req_used;
+
+ return { res => $res, req => $req };
+}
diff --git a/t/open311/getservicerequestupdates.t b/t/open311/getservicerequestupdates.t
new file mode 100644
index 000000000..7ec8d5ae0
--- /dev/null
+++ b/t/open311/getservicerequestupdates.t
@@ -0,0 +1,537 @@
+#!/usr/bin/env perl
+
+use strict;
+use warnings;
+use Test::More;
+use CGI::Simple;
+
+use FindBin;
+use lib "$FindBin::Bin/../perllib";
+use lib "$FindBin::Bin/../commonlib/perllib";
+
+use_ok( 'Open311' );
+
+use_ok( 'Open311::GetServiceRequestUpdates' );
+use DateTime;
+use FixMyStreet::App;
+
+my $user = FixMyStreet::App->model('DB::User')->find_or_create(
+ {
+ email => 'system_user@example.com'
+ }
+);
+
+my $requests_xml = qq{<?xml version="1.0" encoding="utf-8"?>
+<service_requests_updates>
+<request_update>
+<update_id>638344</update_id>
+<service_request_id>1</service_request_id>
+<service_request_id_ext>1</service_request_id_ext>
+<status>open</status>
+<description>This is a note</description>
+UPDATED_DATETIME
+</request_update>
+</service_requests_updates>
+};
+
+
+my $dt = DateTime->now;
+
+# basic xml -> perl object tests
+for my $test (
+ {
+ desc => 'basic parsing - element missing',
+ updated_datetime => '',
+ res => { update_id => 638344, service_request_id => 1, service_request_id_ext => 1,
+ status => 'open', description => 'This is a note' },
+ },
+ {
+ desc => 'basic parsing - empty element',
+ updated_datetime => '<updated_datetime />',
+ res => { update_id => 638344, service_request_id => 1, service_request_id_ext => 1,
+ status => 'open', description => 'This is a note', updated_datetime => {} } ,
+ },
+ {
+ desc => 'basic parsing - element with no content',
+ updated_datetime => '<updated_datetime></updated_datetime>',
+ res => { update_id => 638344, service_request_id => 1, service_request_id_ext => 1,
+ status => 'open', description => 'This is a note', updated_datetime => {} } ,
+ },
+ {
+ desc => 'basic parsing - element with content',
+ updated_datetime => sprintf( '<updated_datetime>%s</updated_datetime>', $dt ),
+ res => { update_id => 638344, service_request_id => 1, service_request_id_ext => 1,
+ status => 'open', description => 'This is a note', updated_datetime => $dt } ,
+ },
+) {
+ subtest $test->{desc} => sub {
+ my $local_requests_xml = $requests_xml;
+ $local_requests_xml =~ s/UPDATED_DATETIME/$test->{updated_datetime}/;
+
+ my $o = Open311->new( jurisdiction => 'mysociety', endpoint => 'http://example.com', test_mode => 1, test_get_returns => { 'update.xml' => $local_requests_xml } );
+
+ my $res = $o->get_service_request_updates;
+ is_deeply $res->[0], $test->{ res }, 'result looks correct';
+
+ };
+}
+
+my $problem_rs = FixMyStreet::App->model('DB::Problem');
+my $problem = $problem_rs->new(
+ {
+ postcode => 'EH99 1SP',
+ latitude => 1,
+ longitude => 1,
+ areas => 1,
+ title => '',
+ detail => '',
+ used_map => 1,
+ user_id => 1,
+ name => '',
+ state => 'confirmed',
+ service => '',
+ cobrand => 'default',
+ cobrand_data => '',
+ user => $user,
+ created => DateTime->now()->subtract( days => 1 ),
+ lastupdate => DateTime->now()->subtract( days => 1 ),
+ anonymous => 1,
+ external_id => time(),
+ council => 2482,
+ }
+);
+
+$problem->insert;
+
+for my $test (
+ {
+ desc => 'element with content',
+ updated_datetime => sprintf( '<updated_datetime>%s</updated_datetime>', $dt ),
+ description => 'This is a note',
+ external_id => 638344,
+ start_state => 'confirmed',
+ close_comment => 0,
+ mark_fixed=> 0,
+ mark_open => 0,
+ problem_state => undef,
+ end_state => 'confirmed',
+ },
+ {
+ desc => 'comment closes report',
+ updated_datetime => sprintf( '<updated_datetime>%s</updated_datetime>', $dt ),
+ description => 'This is a note',
+ external_id => 638344,
+ start_state => 'confirmed',
+ close_comment => 1,
+ mark_fixed=> 0,
+ mark_open => 0,
+ problem_state => 'fixed - council',
+ end_state => 'fixed - council',
+ },
+ {
+ desc => 'comment re-opens fixed report',
+ updated_datetime => sprintf( '<updated_datetime>%s</updated_datetime>', $dt ),
+ description => 'This is a note',
+ external_id => 638344,
+ start_state => 'fixed - user',
+ close_comment => 0,
+ mark_fixed => 0,
+ mark_open => 0,
+ problem_state => 'confirmed',
+ end_state => 'confirmed',
+ },
+ {
+ desc => 'comment re-opens closed report',
+ updated_datetime => sprintf( '<updated_datetime>%s</updated_datetime>', $dt ),
+ description => 'This is a note',
+ external_id => 638344,
+ start_state => 'closed',
+ close_comment => 0,
+ mark_fixed => 0,
+ mark_open => 0,
+ problem_state => 'confirmed',
+ end_state => 'confirmed',
+ },
+ {
+ desc => 'comment leaves report closed',
+ updated_datetime => sprintf( '<updated_datetime>%s</updated_datetime>', $dt ),
+ description => 'This is a note',
+ external_id => 638344,
+ start_state => 'closed',
+ close_comment => 1,
+ mark_fixed => 0,
+ mark_open => 0,
+ end_state => 'closed',
+ },
+) {
+ subtest $test->{desc} => sub {
+ my $local_requests_xml = $requests_xml;
+ $local_requests_xml =~ s/UPDATED_DATETIME/$test->{updated_datetime}/;
+ $local_requests_xml =~ s#<service_request_id>\d+</service_request_id>#<service_request_id>@{[$problem->external_id]}</service_request_id>#;
+ $local_requests_xml =~ s#<service_request_id_ext>\d+</service_request_id_ext>#<service_request_id_ext>@{[$problem->id]}</service_request_id_ext>#;
+ $local_requests_xml =~ s#<status>\w+</status>#<status>closed</status># if $test->{close_comment};
+
+ my $o = Open311->new( jurisdiction => 'mysociety', endpoint => 'http://example.com', test_mode => 1, test_get_returns => { 'update.xml' => $local_requests_xml } );
+
+ $problem->comments->delete;
+ $problem->lastupdate( DateTime->now()->subtract( days => 1 ) );
+ $problem->state( $test->{start_state} );
+ $problem->update;
+
+ my $council_details = { areaid => 2482 };
+ my $update = Open311::GetServiceRequestUpdates->new( system_user => $user );
+ $update->update_comments( $o, $council_details );
+
+ is $problem->comments->count, 1, 'comment count';
+ $problem->discard_changes;
+
+ my $c = FixMyStreet::App->model('DB::Comment')->search( { external_id => $test->{external_id} } )->first;
+ ok $c, 'comment exists';
+ is $c->text, $test->{description}, 'text correct';
+ is $c->mark_fixed, $test->{mark_fixed}, 'mark_closed correct';
+ is $c->problem_state, $test->{problem_state}, 'problem_state correct';
+ is $c->mark_open, $test->{mark_open}, 'mark_open correct';
+ is $problem->state, $test->{end_state}, 'correct problem state';
+ };
+}
+
+
+foreach my $test (
+ {
+ desc => 'date for comment correct',
+ updated_datetime => sprintf( '<updated_datetime>%s</updated_datetime>', $dt ),
+ external_id => 638344,
+ },
+) {
+ subtest $test->{desc} => sub {
+ my $dt = DateTime->now();
+ $dt->subtract( minutes => 10 );
+ my $local_requests_xml = $requests_xml;
+
+ my $updated = sprintf( '<updated_datetime>%s</updated_datetime>', $dt );
+ $local_requests_xml =~ s/UPDATED_DATETIME/$updated/;
+ $local_requests_xml =~ s#<service_request_id>\d+</service_request_id>#<service_request_id>@{[$problem->external_id]}</service_request_id>#;
+ $local_requests_xml =~ s#<service_request_id_ext>\d+</service_request_id_ext>#<service_request_id_ext>@{[$problem->id]}</service_request_id_ext>#;
+
+ my $o = Open311->new( jurisdiction => 'mysociety', endpoint => 'http://example.com', test_mode => 1, test_get_returns => { 'update.xml' => $local_requests_xml } );
+
+ $problem->comments->delete;
+
+ my $council_details = { areaid => 2482 };
+ my $update = Open311::GetServiceRequestUpdates->new( system_user => $user );
+ $update->update_comments( $o, $council_details );
+
+ my $comment = $problem->comments->first;
+ is $comment->created, $dt, 'created date set to date from XML';
+ is $comment->confirmed, $dt, 'confirmed date set to date from XML';
+ };
+}
+
+my $problem2 = $problem_rs->new(
+ {
+ postcode => 'EH99 1SP',
+ latitude => 1,
+ longitude => 1,
+ areas => 1,
+ title => '',
+ detail => '',
+ used_map => 1,
+ user_id => 1,
+ name => '',
+ state => 'confirmed',
+ service => '',
+ cobrand => 'default',
+ cobrand_data => '',
+ user => $user,
+ created => DateTime->now(),
+ lastupdate => DateTime->now(),
+ anonymous => 1,
+ external_id => $problem->external_id,
+ council => 2651,
+ }
+);
+
+$problem2->insert();
+$problem->comments->delete;
+$problem2->comments->delete;
+
+for my $test (
+ {
+ desc => 'identical external_ids on problem resolved using council',
+ updated_datetime => sprintf( '<updated_datetime>%s</updated_datetime>', $dt ),
+ external_id => 638344,
+ area_id => 2651,
+ request_id => $problem2->external_id,
+ request_id_ext => $problem2->id,
+ p1_comments => 0,
+ p2_comments => 1,
+ },
+ {
+ desc => 'identical external_ids on comments resolved',
+ updated_datetime => sprintf( '<updated_datetime>%s</updated_datetime>', $dt ),
+ external_id => 638344,
+ area_id => 2482,
+ request_id => $problem->external_id,
+ request_id_ext => $problem->id,
+ p1_comments => 1,
+ p2_comments => 1,
+ },
+) {
+ subtest $test->{desc} => sub {
+ my $local_requests_xml = $requests_xml;
+ $local_requests_xml =~ s/UPDATED_DATETIME/$test->{updated_datetime}/;
+ $local_requests_xml =~ s#<service_request_id>\d+</service_request_id>#<service_request_id>$test->{request_id}</service_request_id>#;
+ $local_requests_xml =~ s#<service_request_id_ext>\d+</service_request_id_ext>#<service_request_id_ext>$test->{request_id_ext}</service_request_id_ext>#;
+
+ my $o = Open311->new( jurisdiction => 'mysociety', endpoint => 'http://example.com', test_mode => 1, test_get_returns => { 'update.xml' => $local_requests_xml } );
+
+
+ my $council_details = { areaid => $test->{area_id} };
+ my $update = Open311::GetServiceRequestUpdates->new( system_user => $user );
+ $update->update_comments( $o, $council_details );
+
+ is $problem->comments->count, $test->{p1_comments}, 'comment count for first problem';
+ is $problem2->comments->count, $test->{p2_comments}, 'comment count for second problem';
+ };
+}
+
+subtest 'using start and end date' => sub {
+ my $local_requests_xml = $requests_xml;
+ my $o = Open311->new( jurisdiction => 'mysociety', endpoint => 'http://example.com', test_mode => 1, test_get_returns => { 'update.xml' => $local_requests_xml } );
+
+ my $start_dt = DateTime->now();
+ $start_dt->subtract( days => 1 );
+ my $end_dt = DateTime->now();
+
+
+ my $update = Open311::GetServiceRequestUpdates->new(
+ system_user => $user,
+ start_date => $start_dt,
+ );
+
+ my $res = $update->update_comments( $o );
+ is $res, 0, 'returns 0 if start but no end date';
+
+ $update = Open311::GetServiceRequestUpdates->new(
+ system_user => $user,
+ end_date => $end_dt,
+ );
+
+ $res = $update->update_comments( $o );
+ is $res, 0, 'returns 0 if end but no start date';
+
+ $update = Open311::GetServiceRequestUpdates->new(
+ system_user => $user,
+ start_date => $start_dt,
+ end_date => $end_dt,
+ );
+
+ my $council_details = { areaid => 2482 };
+ $update->update_comments( $o, $council_details );
+
+ my $start = $start_dt . '';
+ my $end = $end_dt . '';
+
+ my $uri = URI->new( $o->test_uri_used );
+ my $c = CGI::Simple->new( $uri->query );
+
+ is $c->param('start_date'), $start, 'start date used';
+ is $c->param('end_date'), $end, 'end date used';
+};
+
+subtest 'check that existing comments are not duplicated' => sub {
+ my $requests_xml = qq{<?xml version="1.0" encoding="utf-8"?>
+ <service_requests_updates>
+ <request_update>
+ <update_id>638344</update_id>
+ <service_request_id>@{[ $problem->external_id ]}</service_request_id>
+ <service_request_id_ext>@{[ $problem->id ]}</service_request_id_ext>
+ <status>open</status>
+ <description>This is a note</description>
+ <updated_datetime>UPDATED_DATETIME</updated_datetime>
+ </request_update>
+ <request_update>
+ <update_id>638354</update_id>
+ <service_request_id>@{[ $problem->external_id ]}</service_request_id>
+ <service_request_id_ext>@{[ $problem->id ]}</service_request_id_ext>
+ <status>open</status>
+ <description>This is a different note</description>
+ <updated_datetime>UPDATED_DATETIME2</updated_datetime>
+ </request_update>
+ </service_requests_updates>
+ };
+
+ $problem->comments->delete;
+
+ my $comment = FixMyStreet::App->model('DB::Comment')->new(
+ {
+ problem => $problem,
+ external_id => 638344,
+ text => 'This is a note',
+ user => $user,
+ state => 'confirmed',
+ mark_fixed => 0,
+ anonymous => 0,
+ confirmed => $dt,
+ }
+ );
+ $comment->insert;
+
+ is $problem->comments->count, 1, 'one comment before fetching updates';
+
+ $requests_xml =~ s/UPDATED_DATETIME2/$dt/;
+ $requests_xml =~ s/UPDATED_DATETIME/@{[ $comment->confirmed ]}/;
+
+ my $o = Open311->new( jurisdiction => 'mysociety', endpoint => 'http://example.com', test_mode => 1, test_get_returns => { 'update.xml' => $requests_xml } );
+
+ my $update = Open311::GetServiceRequestUpdates->new(
+ system_user => $user,
+ );
+
+ my $council_details = { areaid => 2482 };
+ $update->update_comments( $o, $council_details );
+
+ $problem->discard_changes;
+ is $problem->comments->count, 2, 'two comments after fetching updates';
+
+ $update->update_comments( $o, $council_details );
+ $problem->discard_changes;
+ is $problem->comments->count, 2, 're-fetching updates does not add comments';
+
+ $problem->comments->delete;
+ $update->update_comments( $o, $council_details );
+ $problem->discard_changes;
+ is $problem->comments->count, 2, 'if comments are deleted then they are added';
+};
+
+foreach my $test ( {
+ desc => 'check that closed and then open comment results in correct state',
+ dt1 => $dt->subtract( hours => 1 ),
+ dt2 => $dt,
+ },
+ {
+ desc => 'check that old comments do not change problem status',
+ dt1 => $dt->subtract( hours => 2 ),
+ dt2 => $dt,
+ }
+) {
+ subtest $test->{desc} => sub {
+ my $requests_xml = qq{<?xml version="1.0" encoding="utf-8"?>
+ <service_requests_updates>
+ <request_update>
+ <update_id>638344</update_id>
+ <service_request_id>@{[ $problem->external_id ]}</service_request_id>
+ <service_request_id_ext>@{[ $problem->id ]}</service_request_id_ext>
+ <status>closed</status>
+ <description>This is a note</description>
+ <updated_datetime>UPDATED_DATETIME</updated_datetime>
+ </request_update>
+ <request_update>
+ <update_id>638354</update_id>
+ <service_request_id>@{[ $problem->external_id ]}</service_request_id>
+ <service_request_id_ext>@{[ $problem->id ]}</service_request_id_ext>
+ <status>open</status>
+ <description>This is a different note</description>
+ <updated_datetime>UPDATED_DATETIME2</updated_datetime>
+ </request_update>
+ </service_requests_updates>
+ };
+
+ $problem->comments->delete;
+ $problem->state( 'confirmed' );
+ $problem->lastupdate( $dt->subtract( hours => 3 ) );
+ $problem->update;
+
+ $requests_xml =~ s/UPDATED_DATETIME/$test->{dt1}/;
+ $requests_xml =~ s/UPDATED_DATETIME2/$test->{dt2}/;
+
+ my $o = Open311->new( jurisdiction => 'mysociety', endpoint => 'http://example.com', test_mode => 1, test_get_returns => { 'update.xml' => $requests_xml } );
+
+ my $update = Open311::GetServiceRequestUpdates->new(
+ system_user => $user,
+ );
+
+ my $council_details = { areaid => 2482 };
+ $update->update_comments( $o, $council_details );
+
+ $problem->discard_changes;
+ is $problem->comments->count, 2, 'two comments after fetching updates';
+ is $problem->state, 'confirmed', 'correct problem status';
+ };
+}
+
+foreach my $test ( {
+ desc => 'normally alerts are not suppressed',
+ suppress_alerts => 0,
+ },
+ {
+ desc => 'alerts suppressed if suppress_alerts set',
+ suppress_alerts => 1,
+ }
+) {
+ subtest $test->{desc} => sub {
+ my $requests_xml = qq{<?xml version="1.0" encoding="utf-8"?>
+ <service_requests_updates>
+ <request_update>
+ <update_id>638344</update_id>
+ <service_request_id>@{[ $problem->external_id ]}</service_request_id>
+ <service_request_id_ext>@{[ $problem->id ]}</service_request_id_ext>
+ <status>closed</status>
+ <description>This is a note</description>
+ <updated_datetime>UPDATED_DATETIME</updated_datetime>
+ </request_update>
+ </service_requests_updates>
+ };
+
+ $problem->comments->delete;
+ $problem->state( 'confirmed' );
+ $problem->lastupdate( $dt->subtract( hours => 3 ) );
+ $problem->update;
+
+ my $alert = FixMyStreet::App->model('DB::Alert')->find_or_create( {
+ alert_type => 'new_updates',
+ parameter => $problem->id,
+ confirmed => 1,
+ user_id => $problem->user->id,
+ } );
+
+ $requests_xml =~ s/UPDATED_DATETIME/$dt/;
+
+ my $o = Open311->new( jurisdiction => 'mysociety', endpoint => 'http://example.com', test_mode => 1, test_get_returns => { 'update.xml' => $requests_xml } );
+
+ my $update = Open311::GetServiceRequestUpdates->new(
+ system_user => $user,
+ suppress_alerts => $test->{suppress_alerts},
+ );
+
+ my $council_details = { areaid => 2482 };
+ $update->update_comments( $o, $council_details );
+ $problem->discard_changes;
+
+ my $alerts_sent = FixMyStreet::App->model('DB::AlertSent')->search(
+ {
+ alert_id => $alert->id,
+ parameter => $problem->comments->first->id,
+ }
+ );
+
+ if ( $test->{suppress_alerts} ) {
+ ok $alerts_sent->count(), 'alerts suppressed';
+ } else {
+ is $alerts_sent->count(), 0, 'alerts not suppressed';
+ }
+
+ $alerts_sent->delete;
+ $alert->delete;
+ }
+}
+
+$problem2->comments->delete();
+$problem->comments->delete();
+$problem2->delete;
+$problem->delete;
+$user->comments->delete;
+$user->problems->delete;
+$user->delete;
+
+done_testing();
diff --git a/t/open311/populate-service-list.t b/t/open311/populate-service-list.t
index bdb7404f9..fbd729f3a 100644
--- a/t/open311/populate-service-list.t
+++ b/t/open311/populate-service-list.t
@@ -203,6 +203,304 @@ subtest 'check conflicting contacts not changed' => sub {
is $contact_count, 4, 'correct number of contacts';
};
+subtest 'check meta data population' => sub {
+ my $processor = Open311::PopulateServiceList->new( council_list => [] );
+
+ my $meta_xml = '<?xml version="1.0" encoding="utf-8"?>
+<service_definition>
+ <service_code>100</service_code>
+ <attributes>
+ <attribute>
+ <variable>true</variable>
+ <code>type</code>
+ <datatype>string</datatype>
+ <required>true</required>
+ <datatype_description>Type of bin</datatype_description>
+ <order>1</order>
+ <description>Type of bin</description>
+ </attribute>
+ </attributes>
+</service_definition>
+ ';
+
+ my $contact = FixMyStreet::App->model('DB::Contact')->find_or_create(
+ {
+ area_id => 1,
+ email => '001',
+ category => 'Bins left out 24x7',
+ confirmed => 1,
+ deleted => 0,
+ editor => $0,
+ whenedited => \'ms_current_timestamp()',
+ note => 'test contact',
+ }
+ );
+
+ my $o = Open311->new(
+ jurisdiction => 'mysociety',
+ endpoint => 'http://example.com',
+ test_mode => 1,
+ test_get_returns => { 'services/100.xml' => $meta_xml }
+ );
+
+ my $council = FixMyStreet::App->model('DB::Open311conf')->new( {
+ area_id => 2482
+ } );
+
+ $processor->_current_open311( $o );
+ $processor->_current_council( $council );
+ $processor->_current_service( { service_code => 100 } );
+
+ $processor->_add_meta_to_contact( $contact );
+
+ my $extra = [ {
+ variable => 'true',
+ code => 'type',
+ datatype => 'string',
+ required => 'true',
+ datatype_description => 'Type of bin',
+ order => 1,
+ description => 'Type of bin'
+
+ } ];
+
+ $contact->discard_changes;
+
+ is_deeply $contact->extra, $extra, 'meta data saved';
+};
+
+subtest 'check attribute ordering' => sub {
+ my $processor = Open311::PopulateServiceList->new( council_list => [] );
+
+ my $meta_xml = '<?xml version="1.0" encoding="utf-8"?>
+<service_definition>
+ <service_code>100</service_code>
+ <attributes>
+ <attribute>
+ <variable>true</variable>
+ <code>type</code>
+ <datatype>string</datatype>
+ <required>true</required>
+ <datatype_description>Type of bin</datatype_description>
+ <order>1</order>
+ <description>Type of bin</description>
+ </attribute>
+ <attribute>
+ <variable>true</variable>
+ <code>colour</code>
+ <datatype>string</datatype>
+ <required>true</required>
+ <datatype_description>Colour of bin</datatype_description>
+ <order>3</order>
+ <description>Colour of bin</description>
+ </attribute>
+ <attribute>
+ <variable>true</variable>
+ <code>size</code>
+ <datatype>string</datatype>
+ <required>true</required>
+ <datatype_description>Size of bin</datatype_description>
+ <order>2</order>
+ <description>Size of bin</description>
+ </attribute>
+ </attributes>
+</service_definition>
+ ';
+
+ my $contact = FixMyStreet::App->model('DB::Contact')->find_or_create(
+ {
+ area_id => 1,
+ email => '001',
+ category => 'Bins left out 24x7',
+ confirmed => 1,
+ deleted => 0,
+ editor => $0,
+ whenedited => \'ms_current_timestamp()',
+ note => 'test contact',
+ }
+ );
+
+ my $o = Open311->new(
+ jurisdiction => 'mysociety',
+ endpoint => 'http://example.com',
+ test_mode => 1,
+ test_get_returns => { 'services/100.xml' => $meta_xml }
+ );
+
+ my $council = FixMyStreet::App->model('DB::Open311conf')->new( {
+ area_id => 1
+ } );
+
+ $processor->_current_open311( $o );
+ $processor->_current_council( $council );
+ $processor->_current_service( { service_code => 100 } );
+
+ $processor->_add_meta_to_contact( $contact );
+
+ my $extra = [
+ {
+ variable => 'true',
+ code => 'type',
+ datatype => 'string',
+ required => 'true',
+ datatype_description => 'Type of bin',
+ order => 1,
+ description => 'Type of bin'
+
+ },
+ {
+ variable => 'true',
+ code => 'size',
+ datatype => 'string',
+ required => 'true',
+ datatype_description => 'Size of bin',
+ order => 2,
+ description => 'Size of bin'
+
+ },
+ {
+ variable => 'true',
+ code => 'colour',
+ datatype => 'string',
+ required => 'true',
+ datatype_description => 'Colour of bin',
+ order => 3,
+ description => 'Colour of bin'
+
+ },
+ ];
+
+ $contact->discard_changes;
+
+ is_deeply $contact->extra, $extra, 'meta data re-ordered correctly';
+};
+
+subtest 'check bromely skip code' => sub {
+ my $processor = Open311::PopulateServiceList->new( council_list => [] );
+
+ my $meta_xml = '<?xml version="1.0" encoding="utf-8"?>
+<service_definition>
+ <service_code>100</service_code>
+ <attributes>
+ <attribute>
+ <variable>true</variable>
+ <code>type</code>
+ <datatype>string</datatype>
+ <required>true</required>
+ <datatype_description>Type of bin</datatype_description>
+ <order>1</order>
+ <description>Type of bin</description>
+ </attribute>
+ <attribute>
+ <variable>true</variable>
+ <code>title</code>
+ <datatype>string</datatype>
+ <required>true</required>
+ <datatype_description>Type of bin</datatype_description>
+ <order>1</order>
+ <description>Type of bin</description>
+ </attribute>
+ <attribute>
+ <variable>true</variable>
+ <code>report_url</code>
+ <datatype>string</datatype>
+ <required>true</required>
+ <datatype_description>Type of bin</datatype_description>
+ <order>1</order>
+ <description>Type of bin</description>
+ </attribute>
+ </attributes>
+</service_definition>
+ ';
+
+ my $contact = FixMyStreet::App->model('DB::Contact')->find_or_create(
+ {
+ area_id => 1,
+ email => '001',
+ category => 'Bins left out 24x7',
+ confirmed => 1,
+ deleted => 0,
+ editor => $0,
+ whenedited => \'ms_current_timestamp()',
+ note => 'test contact',
+ }
+ );
+
+ my $o = Open311->new(
+ jurisdiction => 'mysociety',
+ endpoint => 'http://example.com',
+ test_mode => 1,
+ test_get_returns => { 'services/100.xml' => $meta_xml }
+ );
+
+ my $council = FixMyStreet::App->model('DB::Open311conf')->new( {
+ area_id => 2482
+ } );
+
+ $processor->_current_open311( $o );
+ $processor->_current_council( $council );
+ $processor->_current_service( { service_code => 100 } );
+
+ $processor->_add_meta_to_contact( $contact );
+
+ my $extra = [ {
+ variable => 'true',
+ code => 'type',
+ datatype => 'string',
+ required => 'true',
+ datatype_description => 'Type of bin',
+ order => 1,
+ description => 'Type of bin'
+
+ } ];
+
+ $contact->discard_changes;
+
+ is_deeply $contact->extra, $extra, 'only non std bromley meta data saved';
+
+ $council->area_id(1);
+
+ $processor->_current_council( $council );
+ $processor->_add_meta_to_contact( $contact );
+
+ $extra = [
+ {
+ variable => 'true',
+ code => 'type',
+ datatype => 'string',
+ required => 'true',
+ datatype_description => 'Type of bin',
+ order => 1,
+ description => 'Type of bin'
+
+ },
+ {
+ variable => 'true',
+ code => 'title',
+ datatype => 'string',
+ required => 'true',
+ datatype_description => 'Type of bin',
+ order => 1,
+ description => 'Type of bin'
+
+ },
+ {
+ variable => 'true',
+ code => 'report_url',
+ datatype => 'string',
+ required => 'true',
+ datatype_description => 'Type of bin',
+ order => 1,
+ description => 'Type of bin'
+
+ },
+ ];
+
+ $contact->discard_changes;
+
+ is_deeply $contact->extra, $extra, 'all meta data saved for non bromley';
+};
+
sub get_standard_xml {
return qq{<?xml version="1.0" encoding="utf-8"?>
<services>
diff --git a/templates/email/bromley/questionnaire.txt b/templates/email/bromley/questionnaire.txt
new file mode 100644
index 000000000..4328479e1
--- /dev/null
+++ b/templates/email/bromley/questionnaire.txt
@@ -0,0 +1,22 @@
+Subject: Questionnaire about '<?=$values['title']?>'
+
+Hi <?=$values['name']?>,
+
+<?=$values['created']?> ago, you reported a problem. To keep the
+site up to date and relevant, please fill in a short questionnaire
+updating the status of your problem:
+
+ <?=$values['url']?>
+
+This email has been sent automatically from an unmonitored
+mailbox, please do not reply.
+
+[% INCLUDE 'signature.txt' %]
+
+
+Your problem was as follows:
+
+<?=$values['title']?>
+
+<?=$values['detail']?>
+
diff --git a/templates/email/bromley/signature.txt b/templates/email/bromley/signature.txt
new file mode 100644
index 000000000..776ba3527
--- /dev/null
+++ b/templates/email/bromley/signature.txt
@@ -0,0 +1,3 @@
+Customer Service Centre
+London Borough of Bromley
+Email: csc@bromley.gov.uk
diff --git a/templates/email/default/alert-confirm.txt b/templates/email/default/alert-confirm.txt
index fae3f2963..abf7801f5 100644
--- a/templates/email/default/alert-confirm.txt
+++ b/templates/email/default/alert-confirm.txt
@@ -1,14 +1,13 @@
-Subject: Confirm your alert on FixMyStreet
+Subject: Confirm your alert on [% c.cobrand.site_name %]
Hi,
Please click on the link below to confirm the alert you just
-asked to subscribe to on FixMyStreet:
+asked to subscribe to on [% c.cobrand.site_name %]:
[% token_url %]
If you can't click the link, please copy and paste it to the
address bar of your web browser.
-Yours,
-The FixMyStreet team
+[% INCLUDE 'signature.txt' %]
diff --git a/templates/email/default/alert-problem-area.txt b/templates/email/default/alert-problem-area.txt
index 8c41aaf5e..3696c87d4 100644
--- a/templates/email/default/alert-problem-area.txt
+++ b/templates/email/default/alert-problem-area.txt
@@ -5,8 +5,7 @@ The following new problems have been added within
<?=$values['data']?>
-Yours,
-The FixMyStreet team
+<?=$values['signature']?>
To stop receiving emails when there are new problems in
<?=$values['area_name']?>, please follow this link:
diff --git a/templates/email/default/alert-problem-council.txt b/templates/email/default/alert-problem-council.txt
index 572e057a6..5544a2043 100644
--- a/templates/email/default/alert-problem-council.txt
+++ b/templates/email/default/alert-problem-council.txt
@@ -4,8 +4,7 @@ The following new problems have been reported to <?=$values['area_name']?>:
<?=$values['data']?>
-Yours,
-The FixMyStreet team
+<?=$values['signature']?>
To stop receiving emails when there are new problems reported to
<?=$values['area_name']?>, please follow this link:
diff --git a/templates/email/default/alert-problem-nearby.txt b/templates/email/default/alert-problem-nearby.txt
index 0bf8483a7..0c88dab5a 100644
--- a/templates/email/default/alert-problem-nearby.txt
+++ b/templates/email/default/alert-problem-nearby.txt
@@ -4,8 +4,7 @@ The following nearby problems have been added:
<?=$values['data']?>
-Yours,
-The FixMyStreet team
+<?=$values['signature']?>
To stop receiving emails when there are nearby problems,
please follow this link: <?=$values['unsubscribe_url']?>
diff --git a/templates/email/default/alert-problem-ward.txt b/templates/email/default/alert-problem-ward.txt
index efcf15993..9793bcdac 100644
--- a/templates/email/default/alert-problem-ward.txt
+++ b/templates/email/default/alert-problem-ward.txt
@@ -5,8 +5,7 @@ within <?=$values['ward_name']?>:
<?=$values['data']?>
-Yours,
-The FixMyStreet team
+<?=$values['signature']?>
To stop receiving emails when there are new problems reported to
<?=$values['area_name']?> within <?=$values['ward_name']?>,
diff --git a/templates/email/default/alert-problem.txt b/templates/email/default/alert-problem.txt
index 8369b8e28..01e184e0a 100644
--- a/templates/email/default/alert-problem.txt
+++ b/templates/email/default/alert-problem.txt
@@ -4,8 +4,7 @@ The following new problems have been added:
<?=$values['data']?>
-Yours,
-The FixMyStreet team
+<?=$values['signature']?>
To stop receiving emails when there are new problems,
please follow this link: <?=$values['unsubscribe_url']?>
diff --git a/templates/email/default/alert-update.txt b/templates/email/default/alert-update.txt
index ac0ddd50a..1140de1fa 100644
--- a/templates/email/default/alert-update.txt
+++ b/templates/email/default/alert-update.txt
@@ -11,8 +11,7 @@ To view or reply to these updates, please visit the following URL:
You cannot contact anyone by replying to this email.
-Yours,
-The FixMyStreet team
+<?=$values['signature']?>
To stop receiving emails when there are new updates on this problem,
please follow this link: <?=$values['unsubscribe_url']?>
diff --git a/templates/email/default/login.txt b/templates/email/default/login.txt
index d24f1cc4f..608d99ee9 100644
--- a/templates/email/default/login.txt
+++ b/templates/email/default/login.txt
@@ -5,6 +5,5 @@ able to view your problem reports and manage them more easily.
[% c.uri_for_action( 'auth/token', token ) %]
-Yours,
-The FixMyStreet.com team
+[% INCLUDE 'signature.txt' %]
diff --git a/templates/email/default/partial.txt b/templates/email/default/partial.txt
index 279d76ea0..82bc0cf0e 100644
--- a/templates/email/default/partial.txt
+++ b/templates/email/default/partial.txt
@@ -10,5 +10,4 @@ please visit the following URL:
Thanks!
-Yours,
-The FixMyStreet team
+[% INCLUDE 'signature.txt' %]
diff --git a/templates/email/default/problem-confirm.txt b/templates/email/default/problem-confirm.txt
index 58c1c75d1..5f5bd511a 100644
--- a/templates/email/default/problem-confirm.txt
+++ b/templates/email/default/problem-confirm.txt
@@ -1,9 +1,9 @@
-Subject: Confirm your problem on FixMyStreet
+Subject: Confirm your problem on [% c.cobrand.site_name %]
Hi [% report.name %],
Please click on the link below to confirm the problem you just
-added to FixMyStreet:
+added to [% c.cobrand.site_name %]:
[% token_url %]
@@ -16,5 +16,4 @@ Your problem had the title:
And details:
[% report.detail %]
-Yours,
-The FixMyStreet team
+[% INCLUDE 'signature.txt' %]
diff --git a/templates/email/default/questionnaire.txt b/templates/email/default/questionnaire.txt
index 7ff184c41..88d4cc1b5 100644
--- a/templates/email/default/questionnaire.txt
+++ b/templates/email/default/questionnaire.txt
@@ -13,8 +13,7 @@ updating the status of your problem:
Please do not reply to this email; there is a public comment
box on the questionnaire.
-Yours,
-The FixMyStreet team
+<?=$values['signature']?>
Your problem was as follows:
diff --git a/templates/email/default/reply-autoresponse b/templates/email/default/reply-autoresponse
index 672c1f3c9..cdd7288ed 100644
--- a/templates/email/default/reply-autoresponse
+++ b/templates/email/default/reply-autoresponse
@@ -19,5 +19,4 @@ unsubscribe link at the bottom of the email.
If you have a question or comment about the site, please send your
email to team@fixmystreet.com
-Yours,
-The FixMyStreet team
+[% INCLUDE 'signature.txt' %]
diff --git a/templates/email/default/signature.txt b/templates/email/default/signature.txt
new file mode 100644
index 000000000..69ee38767
--- /dev/null
+++ b/templates/email/default/signature.txt
@@ -0,0 +1,2 @@
+Yours,
+The FixMyStreet team
diff --git a/templates/email/default/submit-brent.txt b/templates/email/default/submit-brent.txt
index 4b3e20968..c94e6e1e4 100644
--- a/templates/email/default/submit-brent.txt
+++ b/templates/email/default/submit-brent.txt
@@ -29,8 +29,7 @@ Longitude: <?=$values['longitude']?>
Replies to this email will go to the user who submitted the problem.
-Yours,
-The FixMyStreet team
+<?=$values['signature']?>
This message was sent via FixMyStreet, a project of UKCOD, registered charity
number 1076346. If there is a more appropriate email address for messages about
@@ -40,5 +39,5 @@ also welcome any other feedback you may have.
FixMyStreet is now available for full integration into council
websites, making life easier for both you and your residents.
-Read more here: http://www.fixmystreet.com/for-councils
+Read more here: http://www.mysociety.org/for-councils/fixmystreet/
diff --git a/templates/email/default/submit-example.txt b/templates/email/default/submit-example.txt
index 6d1815cd1..4956a7a93 100644
--- a/templates/email/default/submit-example.txt
+++ b/templates/email/default/submit-example.txt
@@ -57,5 +57,5 @@ feedback you may have.
FixMyStreet is now available for full integration into council
websites, making life easier for both you and your residents.
-Read more here: http://www.fixmystreet.com/for-councils
+Read more here: http://www.mysociety.org/for-councils/fixmystreet/
diff --git a/templates/email/default/submit.txt b/templates/email/default/submit.txt
index 20fa17096..a956b4add 100644
--- a/templates/email/default/submit.txt
+++ b/templates/email/default/submit.txt
@@ -29,8 +29,7 @@ Longitude: <?=$values['longitude']?>
Replies to this email will go to the user who submitted the problem.
-Yours,
-The FixMyStreet team
+<?=$values['signature']?>
This message was sent via FixMyStreet, a project of UKCOD, registered charity
number 1076346. If there is a more appropriate email address for messages about
@@ -40,5 +39,5 @@ also welcome any other feedback you may have.
FixMyStreet is now available for full integration into council
websites, making life easier for both you and your residents.
-Read more here: http://www.fixmystreet.com/for-councils
+Read more here: http://www.mysociety.org/for-councils/fixmystreet/
diff --git a/templates/email/default/update-confirm.txt b/templates/email/default/update-confirm.txt
index c7571e76c..fdcd68edb 100644
--- a/templates/email/default/update-confirm.txt
+++ b/templates/email/default/update-confirm.txt
@@ -1,4 +1,4 @@
-Subject: Confirm your update on FixMyStreet
+Subject: Confirm your update on [% c.cobrand.site_name %]
Hi [% update.name %],
@@ -14,5 +14,4 @@ Your update reads:
[% update.text %]
-Yours,
-The FixMyStreet team
+[% INCLUDE 'signature.txt' %]
diff --git a/templates/web/barnet/faq/faq-en-gb.html b/templates/web/barnet/faq/faq-en-gb.html
new file mode 100755
index 000000000..126a03314
--- /dev/null
+++ b/templates/web/barnet/faq/faq-en-gb.html
@@ -0,0 +1,103 @@
+[% INCLUDE 'header.html', title = 'Help', bodyclass = 'twothirdswidthpage' %]
+
+<h1>Frequently Asked Questions</h1>
+
+<p>These pages are for reporting things which are broken or dirty or damaged or dumped, and need fixing, cleaning or clearing, such as:</p>
+ <ul><li>abandoned vehicles
+ <li>flyposting or graffiti
+ <li>flytipping or litter
+ <li>streetcleaning, such as broken glass in a cycle lane
+ <li>unlit lamposts
+ <li>broken playground equipment
+ <li>potholes
+ </ul>
+
+<dl>
+ <dt>What issues can&rsquo;t be reported here?</dt>
+ <dd><p>It is not a way of reporting all issues. Problems such as:</p>
+ <ul>
+ <li>missed rubbish or recycling collections
+ <li>anti-social behaviour
+ <li>noise pollution or barking dogs
+ <li>fires and smoke/smell pollution
+ <li>proposals for speed bumps/ CCTV/ pedestrian crossings/ new road layouts/ etc.
+ <li>complaining about your neighbours
+ <li>complaining or commenting about the council
+ </ul>
+ </dd>
+
+ <dt>How do I report a problem here?</dt>
+ <dd>After entering a postcode or location, you are shown
+a map of that area. You can view problems already reported in that area,
+or report ones of your own by clicking on the map at the location of
+the problem.</dd>
+ <dt>How are the problems solved?</dt>
+ <dd>They are reported directly to us so we can then resolve the problem.
+ You can also discuss the problem on the website with others if you wish.</dd>
+
+ <dt>Do you remove silly or illegal content?</dt>
+ <dd>Barnet Council and FixMyStreet are not responsible for the content and accuracy
+of material submitted by their users. We reserve the right to edit or remove any
+problems or updates which we consider to be inappropriate upon being informed
+by a user of the site.</dd>
+
+ <dt>Can I use FixMyStreet on my mobile?</dt>
+ <dd>Yes a special mobile friendly version is available to report problem in Barnet’s streets or parks.
+ </dd>
+
+ <dt>Can I use these pages to report problems outside of the London Borough of Barnet?</dd>
+ <dd>No, please visit the main FixMyStreet site at <a href="http://www.fixmystreet.com/">http://www.fixmystreet.com/</a> to report problem outside the borough.</dd>
+
+ <dt>Who built FixMyStreet?</dt>
+ <dd>FixMyStreet was built by <a href="http://www.mysociety.org/">mySociety</a>, in conjunction with the <a href="http://www.youngfoundation.org.uk/">Young Foundation</a>.
+mySociety is the project of a registered charity which has grown out of the community of
+volunteers who built sites like <a href="http://www.theyworkforyou.com/">TheyWorkForYou</a>.
+mySociety&rsquo;s primary mission is to build Internet projects which give people simple, tangible
+benefits in the civic and community aspects of their lives. Our first project
+was <a href="http://www.writetothem.com/">WriteToThem</a>, where you can write to any of your
+elected representatives, for free. The charity is called UK Citizens Online Democracy and is charity number 1076346. mySociety
+can be contacted by email at <a href="mailto:hello&#64;mysociety.org">hello&#64;mysociety.org</a>,
+or by post at: mySociety, 483 Green Lanes, London, N13 4BS, UK.</dd>
+
+ <dt>Why does the site use kilometres for measurements?</dt>
+ <dd>The British national
+ grid reference system, devised by Ordnance Survey (the British national
+ mapping agency) around the time of the second world war, uses eastings and
+ northings measured in metres and kilometres; the maps we use are from
+ Ordnance Survey and so this is what we use to display distances.
+ There you have it: not everything British is in miles!</dd>
+
+ <dt>Why can&rsquo;t I zoom out more on the reporting map?</dt>
+ <dd>We want to keep reports locally focused, so we restrict the ability to
+ move radically between areas. The map on <a href="/my">Your Reports</a> will let you see all
+ the reports you&rsquo;ve made, wherever they are.</dd>
+
+ <dt>Who gets to see my email address?</dt>
+ <dd>If you submit a problem, your details, and details
+ of the problem, will be submitted to Barnet Council.
+Other than the council, only people we authorise to view the FixMyStreet administration interface
+will be able to see your email address and they will never use it for anything other than
+to help administer FixMyStreet. We will never give or sell your email address to anyone else,
+unless we are obliged to by law. Your name will not be published anywhere unless you let us.</dd>
+
+ <dt>What emails will you send to me?</dt>
+ <dd>We will email you if someone leaves an update on a
+problem you&rsquo;ve reported, and send you a questionnaire email four weeks
+after you submit a problem, asking for a status update; we&rsquo;ll only ever
+send you emails in relation to your problem.</dd>
+
+ <dt>I&rsquo;d like a site like this for my own location/ where&rsquo;s the "source code" to this site?</dt>
+ <dd>
+The software behind this site is open source, and available
+to you mainly under the GNU Affero GPL software license. You can <a
+href="http://github.com/mysociety/fixmystreet">download the
+source code</a> and help us develop it.
+You&rsquo;re welcome to use it in your own projects, although you must also
+make available the source code to any such projects.
+<a href="http://www.fiksgatami.no/">Fiksgatami</a> is an example of our code
+being used in a Norwegian version of this site.
+</dd>
+
+ </dl>
+
+[% INCLUDE 'footer.html' pagefooter = 'yes' %]
diff --git a/templates/web/barnet/footer.html b/templates/web/barnet/footer.html
index 32c6b5f7b..7982ad530 100644
--- a/templates/web/barnet/footer.html
+++ b/templates/web/barnet/footer.html
@@ -1,7 +1,37 @@
- </div>
- <!-- end of content, start of footer -->
- </div>
- </div>
+ <p id="barnet-powered-by" class="desk-only">
+ <a href="http://www.fixmystreet.com/">Powered by <img src="/cobrands/barnet/img/fms-logo.png" style="height:20px;"></a>
+ </p>
+ </div><!-- .content role=main -->
+ </div><!-- .container -->
+ </div><!-- .table-cell -->
+
+ <div class="nav-wrapper">
+ <div class="nav-wrapper-2">
+ <div id="main-nav" role="navigation">
+ <ul id="mysoc-menu">
+ <li><a href="http://www.fixmystreet.com/">Powered by <img src="/cobrands/barnet/img/fms-logo.png" style="height:20px;"></a></li>
+ </ul>
+ <ul id="main-menu">
+ <li><[% IF c.req.uri.path == '/' %]span[% ELSE %]a href="/"[% END %] class="report-a-problem-btn"
+ >[% loc("Report a problem") %]</[% c.req.uri.path == '/' ? 'span' : 'a' %]></li>[%
+ %]<li><[% IF c.req.uri.path == '/my' %]span[% ELSE %]a href="/my"[% END
+ %]>[% loc("Your reports") %]</[% c.req.uri.path == '/my' ? 'span' : 'a' %]></li>[%
+ %]<li><[% IF c.req.uri.path == '/reports/Barnet' %]span[% ELSE %]a href="/reports/Barnet"[% END
+ %]>[% loc("All reports") %]</[% c.req.uri.path == '/reports' ? 'span' : 'a' %]></li>[%
+ %]<li><[% IF c.req.uri.path == '/alert' %]span[% ELSE %]a href="/alert[% pc ? '/list?pc=' : '' %][% pc | uri %]"[% END
+ %]>[% loc("Local alerts") %]</[% c.req.uri.path == '/alert' ? 'span' : 'a' %]></li>[%
+ %]<li><[% IF c.req.uri.path == '/faq' %]span[% ELSE %]a href="/faq"[% END
+ %]>[% loc("Help") %]</[% c.req.uri.path == '/faq' ? 'span' : 'a' %]></li>
+ </ul>
+ </div>
+ </div>
+ </div>
+
+ </div> <!-- .wrapper -->
+</div>
+</div>
+</div>
+
<!-- googleoff: index -->
<div id="column_nav">
<div class="navigation active">
@@ -44,8 +74,7 @@
</div>
</div>
<!-- googleon: index -->
- </div>
- </div>
- </div>
+</div>
+</div>
</body>
-</html> \ No newline at end of file
+</html>
diff --git a/templates/web/barnet/header.html b/templates/web/barnet/header.html
index 955473090..5c6a19d89 100644
--- a/templates/web/barnet/header.html
+++ b/templates/web/barnet/header.html
@@ -1,60 +1,94 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
-<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
- <head>
- <link rel="stylesheet" type="text/css" href="http://pledgebank.barnet.gov.uk/microsites/barnet/site/styles/standard.css" media="screen" />
-<!--[if lte IE 6]>
- <link rel="stylesheet" type="text/css" href="http://pledgebank.barnet.gov.uk/microsites/barnet/site/styles/generic/ie-six.css" media="screen" />
- <link rel="stylesheet" type="text/css" href="http://pledgebank.barnet.gov.uk/microsites/barnet/site/styles/generic/ie-six-print.css" media="print" />
-<![endif]-->
-<!--[if IE 7]>
- <link rel="stylesheet" type="text/css" href="http://pledgebank.barnet.gov.uk/microsites/barnet/site/styles/generic/ie-seven.css" media="screen" />
-<![endif]-->
-<!--[if IE 8]>
- <link rel="stylesheet" type="text/css" href="http://pledgebank.barnet.gov.uk/microsites/barnet/site/styles/generic/ie-eight.css" media="screen" />
-<![endif]-->
- <link rel="stylesheet" type="text/css" href="http://pledgebank.barnet.gov.uk/microsites/barnet/site/styles/generic/print.css" media="print" />
- <link rel="stylesheet" type="text/css" href="http://pledgebank.barnet.gov.uk/microsites/barnet/site/styles/generic/handheld.css" media="handheld" />
- <link rel="Shortcut Icon" type="image/x-icon" href="http://pledgebank.barnet.gov.uk/microsites/barnet/site/favicon.ico" />
+<!doctype html>
+<!--[if lt IE 7]><html class="no-js ie6 oldie" lang="[% lang_code %]"><![endif]-->
+<!--[if IE 7]> <html class="no-js ie7 oldie" lang="[% lang_code %]"><![endif]-->
+<!--[if IE 8]> <html class="no-js ie8 oldie" lang="[% lang_code %]"><![endif]-->
+<!--[if IE 9]> <html class="no-js ie9 oldie" lang="[% lang_code %]"><![endif]-->
+<!--[if gt IE 9]><!--><html class="no-js" lang="[% lang_code %]"><!--<![endif]-->
+ <head>
+ <meta name="viewport" content="initial-scale=1.0">
+
+ <meta http-equiv="X-UA-Compatible" content="IE=Edge,chrome=1">
+ <meta name="HandHeldFriendly" content="true">
+ <meta name="mobileoptimized" content="0">
+
<link rel="ToC" href="http://www.barnet.gov.uk/site_map" />
<meta name="Keywords" content="fixmystreet barnet pothole streetlights report street problem" />
<meta name="Description" content="FixMyStreet Barnet: report problems in Barnet like graffiti, fly tipping, broken paving slabs, or street lighting" />
- <link rel="stylesheet" type="text/css" href="[% version('/css/core.css') %]">
- <link rel="stylesheet" type="text/css" href="/cobrands/barnet/css/layout.css">
-
- [% INCLUDE 'common_header_tags.html' %]
-
- </head>
- <body>
- <div id="wrapper">
- <div id="ie_wrapper">
-<!-- googleoff: index -->
- <div id="mobile_name">London Borough of Barnet</div>
- <div id="mast">
- <div class="pseudoH1">
- <a href="http://www.barnet.gov.uk/"><span>London Borough of Barnet</span> <img src="http://pledgebank.barnet.gov.uk/microsites/barnet/site/images/blank.gif" alt="London Borough of Barnet logo" /></a>
- </div>
- <ul id="skip" class="hidden">
- <li><a href="#content" rel="nofollow">Skip to content</a></li>
- <li><a href="#column_nav" rel="nofollow">Skip to main navigation</a></li>
- </ul>
- <div class="mast_links"></div>
- <span class="clear"></span>
- <div id="search"></div>
- <div class="clear"></div>
- </div>
-<!-- googleon: index -->
- <div id="page_wrap">
- <div id="page">
- <div id="breadcrumb">
-<!-- googleoff:all -->
- <ul>
- <li><a href="/">FixMyStreet Home</a></li>
- <li class="bc_end"><span>[% c.req.uri.path == '/'? 'Report a problem' : "$title" | html %]</span></li>
- </ul>
-<!-- googleon:all -->
- </div>
- <div id="content" class="withWidth fullWidth">
- <div id="mysociety">
-
- <!-- end of header --> \ No newline at end of file
+ <link rel="Shortcut Icon" type="image/x-icon" href="http://pledgebank.barnet.gov.uk/microsites/barnet/site/favicon.ico" />
+
+ <link rel="stylesheet" href="[% version('/cobrands/barnet/base.css') %]">
+ <link rel="stylesheet" href="[% version('/cobrands/barnet/layout.css') %]" media="(min-width:48em)">
+ <link rel="stylesheet" href="[% version('/js/fancybox/jquery.fancybox-1.3.4.css') %]">
+ <!--[if (lt IE 9) & (!IEMobile)]>
+ <link rel="stylesheet" href="[% version('/cobrands/barnet/layout.css') %]">
+ <![endif]-->
+ <link rel="stylesheet" href="[% version('/cobrands/barnet/barnet.css') %]" media="(min-width:48em)">
+ <!--[if (lt IE 9) & (!IEMobile)]>
+ <link rel="stylesheet" href="[% version('/cobrands/barnet/barnet.css') %]">
+ <![endif]-->
+
+ <script src="[% version('/js/modernizr.custom.js') %]" charset="utf-8"></script>
+ <script src="[% version('/cobrands/barnet/position_map.js') %]" charset="utf-8"></script>
+ [% INCLUDE 'common_header_tags.html', js_override = '/cobrands/fixmystreet/fixmystreet.js' %]
+ <script src="[% version('/js/fancybox/jquery.fancybox-1.3.4.pack.js') %]" charset="utf-8"></script>
+
+ </head>
+ <body class="[% bodyclass | html IF bodyclass %]">
+ <div id="barnet-wrapper">
+ <div id="ie_wrapper">
+ <div id="mast">
+ <div class="pseudoH1">
+ <a href="http://www.barnet.gov.uk/"><span>London Borough of Barnet</span> <img src="http://pledgebank.barnet.gov.uk/microsites/barnet/site/images/blank.gif" alt="London Borough of Barnet logo" /></a>
+ </div>
+ <ul id="skip" class="hidden">
+ <li><a href="#content" rel="nofollow">Skip to content</a></li>
+ <li><a href="#column_nav" rel="nofollow">Skip to main navigation</a></li>
+ </ul>
+ <div class="mast_links"></div>
+ <span class="clear"></span>
+ <div id="search"></div>
+ <div class="clear"></div>
+ </div>
+ <div id="page_wrap">
+ <div id="page">
+ <div id="breadcrumb">
+ <!-- googleoff:all -->
+ <ul>
+ <li><a href="http://www.barnet.gov.uk/">Home</a></li>
+ <li><a href="/">FixMyStreet</a></li>
+ <li class="bc_end"><span>
+ [% IF c.req.uri.path == '/' %]Report a problem[% ELSE %][% title %][% END %]
+ </span></li>
+ </ul>
+ <!-- googleon:all -->
+ </div>
+ <div id="content" class="withWidth fullWidth">
+ <div id="user-meta">
+ [% IF c.user_exists %]
+ <p>
+ [% tprintf(loc('Hi %s'), c.user.name || c.user.email) %]
+ <a href="/auth/sign_out">[% loc('sign out') %]</a>
+ </p>
+ [% END %]
+ </div>
+
+ <h1 id="page-title">
+ <span>FixMyStreet</span>
+ </h1>
+
+ <div class="wrapper">
+ <div class="table-cell">
+ <header id="site-header" role="banner">
+ <div class="container">
+ <a href="/" id="site-logo">FixMyStreet</a>
+ <a href="#main-nav" id="nav-link">Main Navigation</a>
+ </div>
+ </header>
+
+ [% pre_container_extra %]
+
+ <div class="container">
+ <div class="content[% " $mainclass" | html IF mainclass %]" role="main">
+
+ <!-- end of header -->
diff --git a/templates/web/barnet/index.html b/templates/web/barnet/index.html
new file mode 100644
index 000000000..82600625e
--- /dev/null
+++ b/templates/web/barnet/index.html
@@ -0,0 +1,100 @@
+[%# Assumes fixmystreet cobrand is using FMS map template - for bonus points preload all the right map elements. %]
+[% map_js = BLOCK %]
+<script>
+yepnope.addPrefix( 'preload', function ( resource ) {
+ resource.noexec = true;
+ return resource;
+});
+Modernizr.load({
+ load: [
+ "preload![% version('/js/OpenLayers.fixmystreet.js') %]",
+ "preload![% version('/js/map-OpenLayers.js') %]",
+ "preload![% version('/js/map-bing-ol.js') %]",
+ "preload![% version('/js/jquery.ba-hashchange.min.js') %]"
+ ]
+});
+</script>
+[% END %]
+
+[% pre_container_extra = BLOCK %]
+<div id="front-main">
+ <div id="front-main-container">
+ <h1>[% loc('Report, view, or discuss local problems') %]</h1>
+
+ <h2>[% loc('(like graffiti, fly tipping, broken paving slabs, or street lighting)') %]</h2>
+
+ [%
+ question
+ = c.cobrand.enter_postcode_text()
+ || loc("Enter a nearby GB postcode, or street name and area");
+ %]
+
+ <form action="[% c.uri_for('/around') %]" method="get" name="postcodeForm" id="postcodeForm">
+ <label for="pc">[% question %]:</label>
+ <div>
+ <input type="text" name="pc" value="" id="pc" size="10" maxlength="200" placeholder="[% tprintf(loc('e.g. ‘%s’ or ‘%s’'), c.cobrand.example_places) %]">
+ <input type="submit" value="[% loc('Go') %]" id="submit">
+ </div>
+ </form>
+ </div>
+</div>
+[% END %]
+
+[% INCLUDE 'header.html', title => '' , bodyclass => 'frontpage fullwidthpage' %]
+
+[% IF error %]
+ <p class="error">[% error %]</p>
+[% END %]
+
+<div class="tablewrapper">
+ <div id="front-howto">
+ <h2>[% loc('How to report a problem') %]</h2>
+
+ <ol class="big-numbers">
+ <li>[% question %]</li>
+ <li>[% loc('Locate the problem on a map of the area') %]</li>
+ <li>[% loc('Enter details of the problem') %]</li>
+ </ol>
+
+ <section class="full-width">
+ [% INCLUDE "front/stats.html" %]
+ [% TRY %][% INCLUDE "front/tips.html" %][% CATCH file %][% END %]
+ </section>
+ </div>
+
+
+ [%
+ recent_photos = c.cobrand.recent_photos('front', 5);
+ %]
+
+ [% IF recent_photos.size %]
+ <div id="front-recently">
+ <h2>[% loc('Recently reported problems') %]</h2>
+
+ <section class="full-width">
+ <ul class="issue-list-a">
+ [% FOREACH p IN recent_photos %]
+ <li>
+ <a href="/report/[% p.id %]">
+ <div class="text">
+ <h4>[% p.title | html %]</h4>
+ <small>[% prettify_epoch( p.confirmed_local.epoch, 1 ) %]</small>
+ </div>
+ <div class="img">
+ <img alt="[% p.title | html %]" title="[% p.title | html %]" height="60" width="90" src="/photo/[% p.id %].fp.jpeg">
+ </div>
+ </a>
+ </li>
+ [% END %]
+ </ul>
+ </section>
+
+ </div>
+ [% END %]
+</div>
+
+
+<!-- [% TRY %][% INCLUDE 'front/news.html' %][% CATCH file %][% END %] -->
+
+
+[% INCLUDE 'footer.html' pagefooter = 'yes' %]
diff --git a/templates/web/barnet/report/new/councils_text_all.html b/templates/web/barnet/report/new/councils_text_all.html
new file mode 100644
index 000000000..20152928b
--- /dev/null
+++ b/templates/web/barnet/report/new/councils_text_all.html
@@ -0,0 +1,4 @@
+<p>
+All the information you provide here will be sent to the <strong>relevant department</strong>.
+[% loc('The subject and details of the problem will be public, plus your name if you give us permission.') %]
+</p>
diff --git a/templates/web/barnet/report/updates-sidebar-notes.html b/templates/web/barnet/report/updates-sidebar-notes.html
new file mode 100644
index 000000000..9fff322a1
--- /dev/null
+++ b/templates/web/barnet/report/updates-sidebar-notes.html
@@ -0,0 +1 @@
+ <p>[% loc( 'Please note that updates are not sent to the relevant department. If you leave your name it will be public. Your information will only be used in accordance with our <a href="/faq#privacy">privacy policy</a>' ) %]</p>
diff --git a/templates/web/bromley/auth/sign_out.html b/templates/web/bromley/auth/sign_out.html
new file mode 100644
index 000000000..63749b233
--- /dev/null
+++ b/templates/web/bromley/auth/sign_out.html
@@ -0,0 +1,8 @@
+[% INCLUDE 'header.html', title = loc('Sign out'), bodyclass = 'fullwidthpage' %]
+
+<p>You have been signed out of Bromley’s street and parks problem reporting system.</p>
+
+<p>Please feel free to <a href="[% c.uri_for('/auth') %]">sign in again</a>, or
+go back to the <a href="/">main street and parks reporting page</a>.</p>
+
+[% INCLUDE 'footer.html' %]
diff --git a/templates/web/fixmystreet/report/new/form_heading.html b/templates/web/bromley/contact/address.html
index e69de29bb..e69de29bb 100644
--- a/templates/web/fixmystreet/report/new/form_heading.html
+++ b/templates/web/bromley/contact/address.html
diff --git a/templates/web/bromley/contact/submit.html b/templates/web/bromley/contact/submit.html
new file mode 100644
index 000000000..781862866
--- /dev/null
+++ b/templates/web/bromley/contact/submit.html
@@ -0,0 +1,19 @@
+[% INCLUDE 'header.html', title = loc('Contact Us') %]
+
+<h1>[% loc('Contact the team') %]</h1>
+
+[% IF success %]
+
+<p>Thank you for letting us know about this report. We will review, and if
+necessary, edit the report, or remove it from the site. You can contact us at
+<a href="mailto:[% contact_email %]">[% contact_email %]</a>.
+
+[% ELSE %]
+
+ <p>
+ [% tprintf( loc('Failed to send message. Please try again, or <a href="mailto:%s">email us</a>.'), contact_email ) %]
+ </p>
+
+[% END %]
+
+[% INCLUDE 'footer.html' %]
diff --git a/templates/web/bromley/faq/faq-en-gb.html b/templates/web/bromley/faq/faq-en-gb.html
new file mode 100755
index 000000000..ae418de37
--- /dev/null
+++ b/templates/web/bromley/faq/faq-en-gb.html
@@ -0,0 +1,111 @@
+[% INCLUDE 'header.html', title = 'Help', bodyclass = 'fullwidthpage' %]
+
+<p>These pages are for reporting things which are broken, dirty, damaged or dumped, and need fixing, cleaning or clearing, such as:</p>
+ <ul><li>abandoned vehicles
+ <li>graffiti
+ <li>flytipping and dumped rubbish
+ <li>street cleaning, such as dog fouling and street sweeping
+ <li>unlit lamp posts
+ <li>park repairs, such as broken fences or playground equipment
+ <li>potholes
+ </ul>
+
+<dl>
+ <dt>What issues can&rsquo;t be reported here?</dt>
+ <dd><p>The following problems should be reported via
+ <a href="http://www.bromley.gov.uk/report">http://www.bromley.gov.uk/report</a>:</p>
+ <ul>
+ <li>missed rubbish or recycling collections
+ <li>anti-social behaviour
+ <li>noise pollution or barking dogs
+ <li>fires and smoke/smell pollution
+ <li>proposals for speed bumps/ CCTV/ pedestrian crossings/ new road layouts/ etc.
+ <li>complaining about your neighbours
+ <li>complaining or commenting about the council
+ </ul>
+ <p>Do not use this to report urgent or emergency problems because reports are not always dealt with immediately outside of working hours.</p>
+ <p>Note, the council does not maintain responsibility for problems on private land or TFL roads (A21 and part of the A232, West Wickham to Locksbottom). TFL road enquiries should be directed to <a href="http://reportit.tfl.gov.uk/">http://reportit.tfl.gov.uk/</a>.
+
+ </dd>
+
+ <dt>How do I report a problem here?</dt>
+ <dd>After entering a postcode or location, you are shown
+a map of that area. You can view problems already reported in that area,
+or report ones of your own by clicking on the map at the location of
+the problem.</dd>
+ <dt>How are the problems solved?</dt>
+ <dd>They are reported directly to us so we can then resolve the problem.
+ You can also discuss the problem on the website with others if you wish.</dd>
+
+ <dt>Do you remove silly or illegal content?</dt>
+ <dd>Bromley Council and FixMyStreet are not responsible for the content and accuracy
+of material submitted by its users. We reserve the right to edit or remove any
+problems or updates which we consider to be inappropriate upon being informed
+by a user of the site.</dd>
+
+ <dt>Can I use FixMyStreet on my mobile?</dt>
+ <dd>Yes a special mobile friendly version is available to report problem in Bromley’s streets or parks.
+ </dd>
+
+ <dt>Can I use these pages to report problems outside of the London Borough of Bromley?</dd>
+ <dd>Yes, if you enter a postcode or address outside the borough you will be re-directed to the main FixMyStreet site that will enable you to report problems elsewhere. FixMyStreet will forward these on to the relevant council.</dd>
+
+ <dt>The site is powered by FixMyStreet, who are they?</dt>
+ <dd>FixMyStreet was built by <a href="http://www.mysociety.org/">mySociety</a>, in conjunction with the <a href="http://www.youngfoundation.org.uk/">Young Foundation</a>.
+mySociety is the project of a registered charity which has grown out of the community of
+volunteers who built sites like <a href="http://www.theyworkforyou.com/">TheyWorkForYou</a>.
+mySociety&rsquo;s primary mission is to build Internet projects which give people simple, tangible
+benefits in the civic and community aspects of their lives.
+The charity is called UK Citizens Online Democracy and is charity number 1076346. mySociety
+can be contacted by email at <a href="mailto:hello&#64;mysociety.org">hello&#64;mysociety.org</a>,
+or by post at mySociety, 483 Green Lanes, London, N13 4BS.</dd>
+
+ <dt>Why does the site use kilometres for measurements?</dt>
+ <dd>The British national
+ grid reference system, devised by Ordnance Survey (the British national
+ mapping agency) around the time of the second world war, uses eastings and
+ northings measured in metres and kilometres; the maps we use are from
+ Ordnance Survey and so this is what we use to display distances.
+ There you have it: not everything British is in miles!</dd>
+
+ <dt>Why can&rsquo;t I zoom out more on the reporting map?</dt>
+ <dd>We want to keep reports locally focused, so we restrict the ability to
+ move radically between areas. The map on <a href="/my">Your Reports</a> will let you see all
+ the reports you&rsquo;ve made, wherever they are.</dd>
+
+ <dt>I&rsquo;d like a site like this for my own location/ where&rsquo;s the "source code" to this site?</dt>
+ <dd>
+The mySociety software behind this site is open source, and available
+under the GNU Affero GPL software license. You can <a
+href="http://github.com/mysociety/fixmystreet">download the
+source code</a> and help mySociety develop it.
+You&rsquo;re welcome to use it in your own projects, although you must also
+make available the source code to any such projects.
+<a href="http://www.fiksgatami.no/">Fiksgatami</a> is an example of our code
+being used in a Norwegian version of this site.
+</dd>
+
+</dl>
+
+ <h2>Privacy Questions</h2>
+
+ <dl>
+ <dt>Who gets to see my email address?</dt>
+ <dd>
+<p>If you submit a problem, your details, and details of the problem, will be
+submitted to Bromley Council. Other than the council, only people we authorise
+to view the FixMyStreet administration interface will be able to see your email
+address and they will never use it for anything other than to help administer
+FixMyStreet.</p>
+<p>We will never give or sell your email address to anyone else, unless we are
+obliged to by law. Your name will not be published anywhere unless you let us.</p>
+</dd>
+
+ <dt>What emails will you send to me?</dt>
+ <dd>We will email you when we have received your report, and when it has
+ been investigated and actioned. We will only send you emails that
+ relate to an issue you have reported.</dd>
+
+ </dl>
+
+[% INCLUDE 'footer.html' pagefooter = 'yes' %]
diff --git a/templates/web/bromley/footer.html b/templates/web/bromley/footer.html
index 9be0741bf..d60854daa 100644
--- a/templates/web/bromley/footer.html
+++ b/templates/web/bromley/footer.html
@@ -1,23 +1,8 @@
- [% IF pagefooter %]
- <footer role="content-info">
- <div class="tablewrapper bordered">
- <div id="footer-mobileapps">
- <h4>Mobile apps</h4>
-
- <ul>
- <li><a class="m-app-iphone" href="http://itunes.apple.com/gb/app/fixmystreet/id297456545">iPhone</a></li>
- <li><a class="m-app-droid" href="https://market.android.com/details?id=com.android.fixmystreet">Android</a></li>
- <li><a class="m-app-nokia" href="http://store.ovi.com/content/107557">Nokia</a></li>
- <li><a class="m-app-iphone-streetreport" href="http://itunes.apple.com/gb/app/streetreport/id371891859">iPhone Street Report</a></li>
- </ul>
- </div>
-
- <div id="footer-help">
- </div>
- </div>
- </footer>
- [% END %]
</div><!-- .content role=main -->
+ <p id="bromley-powered-by" class="desk-only">
+ <a href="http://www.fixmystreet.com/">Powered by <img src="/cobrands/bromley/fms-logo.png" alt="FixMyStreet" style="height:20px;"></a>
+ </p>
+
</div><!-- .container -->
</div><!-- .table-cell -->
@@ -25,9 +10,8 @@
<div class="nav-wrapper-2">
<div id="main-nav" role="navigation">
<ul id="mysoc-menu">
- <li><a href="http://www.fixmystreet.com/">Powered by FixMyStreet</a></li>
+ <li><a href="http://www.fixmystreet.com/">Powered by <img src="/cobrands/bromley/fms-logo.png" alt="FixMyStreet" style="height:20px;"></a></li>
</ul>
-
<ul id="main-menu">
<li><[% IF c.req.uri.path == '/' %]span[% ELSE %]a href="/"[% END %] class="report-a-problem-btn"
>[% loc("Report a problem") %]</[% c.req.uri.path == '/' ? 'span' : 'a' %]></li>[%
@@ -44,7 +28,22 @@
</div>
</div>
-<!-- [% INCLUDE 'debug_footer.html' %] -->
</div> <!-- .wrapper -->
+
+<div id="bromley-footer" class="desk-only">
+ <p class="copy">&copy; 2012 London Borough of Bromley</p>
+
+ <a href="http://www.direct.gov.uk/"><img src="https://www.bromley.gov.uk/site/images/directgov.jpg" alt="Directgov website link - Public services all in one place" /></a>
+
+ <ul class="footer-nav">
+ <li><a href="#bromley-header">To the top</a></li>
+ <li><a href="http://www.bromley.gov.uk/terms">Disclaimer</a></li>
+ <li><a href="http://www.bromley.gov.uk/privacy" rel="nofollow">Privacy and cookies</a></li>
+ <li><a href="http://www.bromley.gov.uk/accesstoinfo">Access to information</a></li>
+ </ul>
+
+</div>
+
+ </div></div>
</body>
</html>
diff --git a/templates/web/bromley/header.html b/templates/web/bromley/header.html
index f7beabd8c..69a595923 100644
--- a/templates/web/bromley/header.html
+++ b/templates/web/bromley/header.html
@@ -6,39 +6,77 @@
<!--[if gt IE 9]><!--><html class="no-js" lang="[% lang_code %]"><!--<![endif]-->
<head>
<meta name="viewport" content="initial-scale=1.0">
-
<meta http-equiv="X-UA-Compatible" content="IE=Edge,chrome=1">
<meta name="HandHeldFriendly" content="true">
<meta name="mobileoptimized" content="0">
<link rel="stylesheet" href="[% version('/cobrands/bromley/base.css') %]">
- <!-- <link rel="stylesheet" href="[% version('/cobrands/fixmystreet/layout.css') %]" media="(min-width:48em)"> -->
- <link rel="stylesheet" href="[% version('/js/fancybox/jquery.fancybox-1.3.4.css') %]">
+ <link rel="stylesheet" href="[% version('/cobrands/bromley/layout.css') %]" media="(min-width:48em)">
+ <link rel="stylesheet" href="[% version('/cobrands/bromley/bromley.css') %]">
+ [% extra_css %]
<!--[if (lt IE 9) & (!IEMobile)]>
- <!-- <link rel="stylesheet" href="[% version('/cobrands/fixmystreet/layout.css') %]"> -->
+ <link rel="stylesheet" href="[% version('/cobrands/bromley/layout.css') %]">
<![endif]-->
- <script src="[% version('/js/modernizr.custom.76759.js') %]" charset="utf-8"></script>
+ <script src="[% version('/js/modernizr.custom.js') %]" charset="utf-8"></script>
+ <script src="[% version('/cobrands/bromley/position_map.js') %]" charset="utf-8"></script>
[% INCLUDE 'common_header_tags.html', js_override = '/cobrands/fixmystreet/fixmystreet.js' %]
- <script src="[% version('/js/fancybox/jquery.fancybox-1.3.4.pack.js') %]" charset="utf-8"></script>
+ [% extra_js %]
- [% IF c.req.uri.host == 'osm.fixmystreet.com' %]
- <link rel="canonical" href="http://www.fixmystreet.com[% c.req.uri.path_query %]">
- [% END %]
-
- [% INCLUDE 'tracking_code.html' %]
+ <link rel="Shortcut Icon" type="image/x-icon" href="/cobrands/bromley/favicon.ico">
</head>
<body class="[% bodyclass | html IF bodyclass %]">
+ [%# ie_wrapper is to prevent a horizontal scrollbar in IE7, it appears (from Bromley site) %]
+ <div id="bromley-wrapper"><div id="bromley-ie_wrapper">
+
+<div id="bromley-header" class="desk-only">
+ <ul class="header-nav">
+ <li><a href="http://www.bromley.gov.uk/accessibility">Accessibility</a></li>
+ <li><a class="skiplink" href="http://www.bromley.gov.uk/#user-meta" rel="nofollow">Skip to content</a></li>
+ <!-- <li><a rel="nofollow" href="http://www.bromley.gov.uk/a_to_z?previewstyle=generic/print.css">Printer friendly</a></li> -->
+ <!-- <li><a href="http://www.bromley.gov.uk/accessibility/settings">Text size: AAA</a></li> -->
+ <li><div id="google_translate_element"></div></li>
+ </ul>
+
+ <div class="logo">
+ <a href="http://www.bromley.gov.uk"><img src="/cobrands/bromley/bromley-logo.jpg" alt="London Borough of Bromley logo" width="159" height="114" style="width:159px; height:114px;" /></a>
+ </div>
+
+ <div class="sign-in">
+ [% IF c.user_exists %]
+ <p>
+ [% tprintf(loc('Hi %s'), c.user.name || c.user.email) %]
+ <a href="/auth/sign_out">[% loc('sign out') %]</a>
+ </p>
+ [% END %]
+ </div>
+
+ <div class="main-menu">
+ <ul>
+ <li class="home"><[% IF c.req.uri.path == '/' %]span[% ELSE %]a href="/"[% END %] class="report-a-problem-btn"
+ >[% "Report" %]</[% c.req.uri.path == '/' ? 'span' : 'a' %]></li>[%
+ %]<li><[% IF c.req.uri.path == '/my' OR ( c.req.uri.path == '/auth' AND c.req.params.r == 'my' ) %]span[% ELSE %]a href="/my"[% END
+ %]>[% loc("Your reports") %]</[% ( c.req.uri.path == '/my' OR ( c.req.uri.path == '/auth' AND c.req.params.r == 'my' ) ) ? 'span' : 'a' %]></li>[%
+ %]<li><[% IF c.req.uri.path == '/reports/Bromley' %]span[% ELSE %]a href="/reports/Bromley"[% END
+ %]>[% loc("All reports") %]</[% c.req.uri.path == '/reports' ? 'span' : 'a' %]></li>[%
+ %]<li><[% IF c.req.uri.path == '/alert' %]span[% ELSE %]a href="/alert[% pc ? '/list?pc=' : '' %][% pc | uri %]"[% END
+ %]>[% loc("Local alerts") %]</[% c.req.uri.path == '/alert' ? 'span' : 'a' %]></li>[%
+ %]<li class="last"><[% IF c.req.uri.path == '/faq' %]span[% ELSE %]a href="/faq"[% END
+ %]>[% loc("Help") %]</[% c.req.uri.path == '/faq' ? 'span' : 'a' %]></li>
+ </ul>
+ </div>
+</div>
+
<div class="wrapper">
<div class="table-cell">
- <header id="site-header" role="banner">
+ <div id="site-header" role="banner">
<div class="container">
<a href="/" id="site-logo">FixMyStreet</a>
<a href="#main-nav" id="nav-link">Main Navigation</a>
</div>
- </header>
+ </div>
<div id="user-meta">
[% IF c.user_exists %]
@@ -46,12 +84,14 @@
[% tprintf(loc('Hi %s'), c.user.name || c.user.email) %]
<a href="/auth/sign_out">[% loc('sign out') %]</a>
</p>
- [% ELSE %]
- <!-- <a href="/auth">[% loc('Sign in') %]</a> -->
[% END %]
</div>
+ <h1 class="main desk-only">Reporting a problem in Bromley&rsquo;s streets or parks</h1>
+
+ [% pre_container_extra %]
+
<div class="container">
<div class="content[% " $mainclass" | html IF mainclass %]" role="main">
- <!-- [% INCLUDE 'debug_header.html' %] -->
+
diff --git a/templates/web/bromley/report/display.html b/templates/web/bromley/report/display.html
new file mode 100644
index 000000000..071f9b3ca
--- /dev/null
+++ b/templates/web/bromley/report/display.html
@@ -0,0 +1,217 @@
+[%
+ PROCESS "report/photo-js.html";
+ PROCESS "maps/${map.type}.html";
+
+ problem_title = problem.title _ ' - ' _ loc('Viewing a problem');
+ INCLUDE 'header.html'
+ title = problem_title
+ rss = [ loc('Updates to this problem, FixMyStreet'), "/rss/$problem.id" ]
+ robots = 'index, nofollow'
+ bodyclass = 'mappage'
+%]
+
+[% map_html %]
+
+</div>
+
+
+[% IF banner.id %]
+ <div class="banner">
+ <p id="[% banner.id %]">[% banner.text %]</p>
+ </div>
+[% END %]
+
+[% INCLUDE 'report/_main.html' %]
+
+<div class="shadow-wrap">
+ <ul id="key-tools">
+ [% IF c.user_exists AND c.user.council == 'Bromley Council' %]
+ <li><form method="post" action="/report/delete/[% problem.id %]">
+ <input type="submit" class="abuse" value="Remove from site">
+ </form></li>
+ [% ELSE %]
+ <li><a rel="nofollow" id="key-tool-report-abuse" class="abuse" href="[% c.uri_for( '/contact', { id => problem.id } ) %]">[% loc('Report abuse') %]</a></li>
+ [% END %]
+ <li><a rel="nofollow" id="key-tool-report-updates" class="feed" href="[% c.uri_for( '/alert/subscribe', { id => problem.id } ) %]">[% loc('Get updates' ) %]</a></li>
+ <li><a class="chevron" id="key-tool-problems-nearby" href="[% c.uri_for( '/around', { lat => short_latitude, lon => short_longitude } ) %]">[% loc( 'Problems nearby' ) %]</a></li>
+ </ul>
+
+<div id="report-updates-data" class="hidden-js">
+ <form action="[% c.uri_for( '/alert/subscribe' ) %]" method="post">
+ <p><a href="[% c.uri_for( '/rss', problem.id ) %]">
+ <img src="/i/feed.png" width="16" height="16" title="[% loc('RSS feed') %]" alt="[% loc('RSS feed of updates to this problem' ) %]" border="0" style="float: right">
+ </a></p>
+ <p>[% loc('Receive email when updates are left on this problem.' ) %]</p>
+ <fieldset>
+ <label class="hidden n" for="alert_rznvy">[% loc('Your email') %]</label>
+ <div class="form-txt-submit-box">
+ <input type="email" name="rznvy" id="alert_rznvy" value="[% email | html %]" size="30" placeholder="[% loc('Your email') %]">
+ <input class="green-btn" type="submit" value="[% loc('Subscribe') %]">
+ </div>
+ <input type="hidden" name="id" value="[% problem.id %]">
+ <input type="hidden" name="type" value="updates">
+ </fieldset>
+ </form>
+</div>
+
+</div>
+
+[% INCLUDE 'report/updates.html' %]
+
+<div id="update_form">
+ <h2>[% loc( 'Provide an update') %]</h2>
+
+ [% INCLUDE 'errors.html' %]
+
+ <form method="post" action="[% c.uri_for( '/report/update' ) %]" name="updateForm" class="validate"[% IF c.cobrand.allow_photo_upload %] enctype="multipart/form-data"[% END %]>
+ <fieldset>
+ <input type="hidden" name="submit_update" value="1">
+ <input type="hidden" name="id" value="[% problem.id | html %]">
+
+ <label for="form_update">[% loc( 'Update' ) %]</label>
+ [% IF field_errors.update %]
+ <div class='form-error'>[% field_errors.update %]</div>
+ [% END %]
+ <textarea rows="7" cols="30" name="update" id="form_update" placeholder="[% loc('Please write your update here') %]" required>[% update.text | html %]</textarea>
+
+ <div class="general-sidebar-notes">
+ <p>Please note this comments box can only be used for this report.
+ <br><a href="http://www.bromley.gov.uk/report">Report a different issue</a>
+ </div>
+
+ [% IF c.user && c.user.belongs_to_council( problem.council ) %]
+ <label for="form_state">[% loc( 'State' ) %]</label>
+ <select name="state" id="form_state">
+ [% FOREACH state IN [ ['confirmed', loc('Open')], ['investigating',
+ loc('Investigating')], ['planned', loc('Planned')], ['in progress',
+ loc('In Progress')], ['closed', loc('Closed')], ['fixed', loc('Fixed')] ] %]
+ <option [% 'selected ' IF state.0 == problem.state %] value="[% state.0 %]">[% state.1 %]</option>
+ [% END %]
+ </select>
+ [% ELSE %]
+ [% IF problem.is_fixed AND c.user_exists AND c.user.id == problem.user_id %]
+
+ <input type="checkbox" name="reopen" id="form_reopen" value="1"[% ' checked' IF update.mark_open %]>
+ <label class="inline" for="form_reopen">[% loc('This problem has not been fixed') %]</label>
+
+ [% ELSIF !problem.is_fixed %]
+
+ <div class="checkbox-group">
+ <input type="checkbox" name="fixed" id="form_fixed" value="1"[% ' checked' IF update.mark_fixed %]>
+ <label class="inline" for="form_fixed">[% loc('This problem has been fixed') %]</label>
+ </div>
+
+ [% END %]
+ [% END %]
+
+ [% IF c.cobrand.allow_photo_upload %]
+ <div id="fileupload_normalUI">
+ [% IF upload_fileid %]
+ <img align="right" src="/photo/[% upload_fileid %].temp.jpeg" alt="">
+ <p>[% loc('You have already attached a photo to this update, attaching another one will replace it.') %]</p>
+ <input type="hidden" name="upload_fileid" value="[% upload_fileid %]">
+ [% END %]
+ <label for="form_photo">[% loc('Photo') %]</label>
+ [% IF field_errors.photo %]
+ <p class='form-error'>[% field_errors.photo %]</p>
+ [% END %]
+ <input type="file" name="photo" id="form_photo">
+ </div>
+ [% END %]
+
+ [% IF c.user_exists %]
+
+ [% INCLUDE name %]
+
+ <input class="final-submit green-btn" type="submit" id="update_post" value="[% loc('Post') %]">
+
+
+ [% ELSE %]
+
+ <label for="form_rznvy">[% loc('Email' ) %]</label>
+ [% IF field_errors.email %]
+ <p class='form-error'>[% field_errors.email %]</p>
+ [% END %]
+ <input type="email" name="rznvy" id="form_rznvy" value="[% update.user.email | html %]" placeholder="[% loc('Your email address' ) %]" required>
+
+ <div id="form_sign_in">
+ <p>To submit your update you now need to confirm it either by email or by using a FixMyStreet password.</p>
+
+ <div id="form_sign_in_no" class="form-box">
+ <h5>Confirm my report by email</h5>
+
+ [% INCLUDE name %]
+
+ <div class="general-sidebar-notes">
+ <p class="dark">[% loc('We never show your email') %]</p>
+ <p>[% loc('Providing a password is optional, but doing so will allow you to more easily report problems, leave updates and manage your reports.') %]</p>
+ </div>
+
+ <label for="password_register">[% loc('Password (optional)') %]</label>
+
+ <div class="form-txt-submit-box">
+ <input type="password" name="password_register" id="password_register" value="" placeholder="[% loc('Enter a password') %]">
+ <input class="green-btn" type="submit" name="submit_register" id="submit_register" value="[% loc('Post') %]">
+ </div>
+ </div>
+ <div id="form_sign_in_yes" class="form-box">
+ <h5>Confirm my report with my FixMyStreet password</h5>
+
+ <label class="hidden-js n" for="password_sign_in">[% loc('Yes I have a password') %]</label>
+ [% IF field_errors.password %]
+ <p class='form-error'>[% field_errors.password %]</p>
+ [% END %]
+ <div class="form-txt-submit-box">
+ <input type="password" name="password_sign_in" id="password_sign_in" value="" placeholder="[% loc('Your password') %]">
+ <input class="green-btn" type="submit" name="submit_sign_in" id="submit_sign_in" value="[% loc('Post') %]">
+ </div>
+
+ <div class="checkbox-group">
+ <input type="checkbox" id="remember_me" name="remember_me" value='1'[% ' checked' IF remember_me %]>
+ <label class="inline n" for="remember_me">[% loc('Keep me signed in on this computer') %]</label>
+ </div>
+ </div>
+ </div>
+
+ [% END %]
+
+ <p>Your information will only be used in accordance with our <a href="/faq#privacy">privacy policy</a>.</p>
+
+ </fieldset>
+ </form>
+</div>
+
+
+
+[% INCLUDE 'footer.html' %]
+
+[% BLOCK name %]
+ [% IF problem.council == '2482' %]
+ [% extra_name_info = 1 %]
+ [% INCLUDE 'report/new/extra_name.html' %]
+ [% END %]
+
+ [% IF c.user_exists %]
+ [% names = c.user.split_name %]
+ [% END %]
+ <label for="form_first_name">[% loc('First Name') %]</label>
+ [% IF field_errors.first_name %]
+ <p class='form-error'>[% field_errors.first_name %]</p>
+ [% END %]
+ <input type="text" value="[% names.first || first_name | html %]" name="first_name" id="form_first_name" placeholder="[% loc('Your first name') %]">
+
+ <label for="form_last_name">[% loc('Last Name') %]</label>
+ [% IF field_errors.last_name %]
+ <p class='form-error'>[% field_errors.last_name %]</p>
+ [% END %]
+ <input type="text" value="[% names.last || last_name | html %]" name="last_name" id="form_last_name" placeholder="[% loc('Your last name') %]">
+
+ <div class="checkbox-group">
+ <input type="checkbox" name="may_show_name" id="form_may_show_name" value="1"[% ' checked' IF update AND NOT update.anonymous %]>
+ <label class="inline" for="form_may_show_name">[% loc('Show my name publicly') %]</label>
+ </div>
+ <div class="checkbox-group">
+ <input type="checkbox" name="add_alert" id="form_add_alert" value="1"[% ' checked' IF add_alert %]>
+ <label class="inline" for="form_add_alert">[% loc( 'Alert me to future updates' ) %]</label>
+ </div>
+[% END %]
diff --git a/templates/web/bromley/report/new/fill_in_details_form.html b/templates/web/bromley/report/new/fill_in_details_form.html
new file mode 100644
index 000000000..1ceb0ac10
--- /dev/null
+++ b/templates/web/bromley/report/new/fill_in_details_form.html
@@ -0,0 +1,228 @@
+<div id="report-a-problem-main">
+ [% IF js %]
+ <p id="councils_text">
+ [%
+ tprintf(
+ loc('All the information you provide here will be sent to <strong>%s</strong>.'),
+ loc('the local council')
+ );
+ %]
+ Details of the problem will be public, plus your name if you give us permission.
+ </p>
+ [% ELSE %]
+ [% PROCESS 'report/new/councils_text.html' %]
+ [% END %]
+
+ <div id="report-a-problem-sidebar">
+ <!--
+ The text for this section needs checking, but I can't work out which bit comes from where
+ -->
+ <div class="sidebar-tips">
+ [% IF report.used_map %]
+ [% IF partial_token %]
+ <p id="unknown">[% loc('Please note your report has <strong>not yet been sent</strong>. Choose a category and add further information below, then submit.') %]</p>
+ [% END %]
+ <p>[% loc('You have located the problem at the point marked with a green pin on the map. If this is not the correct location, simply click on the map again. ') %]</p>
+ [% ELSE %]
+ <p>
+ [% loc('Please fill in the form below with details of the problem, and describe the location as precisely as possible in the details box.') %]
+ </p>
+ [% END %]
+ </div>
+
+ </div>
+
+ [% INCLUDE 'errors.html' %]
+ <fieldset>
+ <div id="problem_form">
+
+ [% INCLUDE 'report/new/form_heading.html' %]
+
+
+ [% IF field_errors.council %]
+ <p class='form-error'>[% field_errors.council %]</p>
+ [% END %]
+
+
+
+ <label for="form_title">[% loc('Subject') %]</label>
+ [% IF field_errors.title %]
+ <p class='form-error'>[% field_errors.title %]</p>
+ [% END %]
+ <input type="text" value="[% report.title | html %]" name="title" id="form_title" placeholder="[% loc('Provide a title') %]" required>
+
+ <label for="form_detail">[% loc('Details') %]</label>
+ [% IF report.used_map %]
+ <p>
+ We won&rsquo;t be able to help unless you leave as much
+detail as you can. Please describe the exact location of the problem (e.g. on a
+wall).
+ </p>
+ [% END %]
+ [% IF field_errors.detail %]
+ <p class='form-error'>[% field_errors.detail %]</p>
+ [% END %]
+ <textarea rows="7" cols="26" name="detail" id="form_detail" placeholder="[% loc('Please fill in details of the problem.') %]" required>[% report.detail | html %]</textarea>
+
+ [% IF js %]
+ <div id="form_category_row">
+ <label for="form_category">[% loc('Category') %]</label>
+ <select name="category" id="form_category" required><option>[% loc('Loading...') %]</option></select>
+ </div>
+ [% ELSE %]
+ [% IF category_options.size %]
+ [% IF field_errors.category %]
+ <p class='form-error'>[% field_errors.category %]</p>
+ [% END %]
+
+ [% PROCESS "report/new/category.html" %]
+ [% END %]
+ [% END %]
+
+ [%- IF category_extras %]
+ [% PROCESS "report/new/category_extras.html" %]
+ [%- END %]
+
+ [% IF c.cobrand.allow_photo_upload %]
+ [% IF field_errors.photo %]
+ <p class='form-error'>[% field_errors.photo %]</p>
+ [% END %]
+
+
+ [% IF upload_fileid || report.photo %]
+ [% IF upload_fileid %]
+ <img align="right" src="/photo/[% upload_fileid %].temp.jpeg" alt="">
+ <input type="hidden" name="upload_fileid" value="[% upload_fileid %]">
+ [% END %]
+
+ <p>[% loc('You have already attached a photo to this report, attaching another one will replace it.') %]</p>
+
+ [% IF report.photo %]
+ <img align="right" src="/photo/[% report.id %].jpeg">
+ [% END %]
+ [% END %]
+
+ <label for="form_photo">[% loc('Photo') %]</label>
+ <input type="file" name="photo" id="form_photo">
+ [% END %]
+
+ [% IF c.user_exists %]
+ <div class="form-box">
+ [% INCLUDE 'report/new/extra_name.html' %]
+
+ [% names = c.user.split_name %]
+ <label for="form_first_name">[% loc('First Name') %]</label>
+ [% IF field_errors.first_name %]
+ <p class='form-error'>[% field_errors.first_name %]</p>
+ [% END %]
+ <input type="text" value="[% ( first_name || names.first ) | html %]" name="first_name" id="form_first_name" placeholder="[% loc('Your first name') %]">
+
+ <label for="form_last_name">[% loc('Last Name') %]</label>
+ [% IF field_errors.last_name %]
+ <p class='form-error'>[% field_errors.last_name %]</p>
+ [% END %]
+ <input type="text" value="[% ( last_name || names.last ) | html %]" name="last_name" id="form_last_name" placeholder="[% loc('Your last name') %]">
+
+
+ [%# if there is nothing in the name field then set check box as default on form %]
+ <div class="checkbox-group">
+ <input type="checkbox" name="may_show_name" id="form_may_show_name" value="1"[% ' checked' IF !report.anonymous %]>
+ <label class="inline" for="form_may_show_name">[% loc('Show my name publicly') %]</label>
+ </div>
+
+ <div class="general-sidebar-notes">
+ <p>[% loc('We never show your email address or phone number.') %]</p>
+ </div>
+
+ <label for="form_phone">[% loc('Phone number (optional)') %]</label>
+ <input class="" type="text" value="[% report.user.phone | html %]" name="phone" id="form_phone" placeholder="[% loc('Your phone number') %]">
+
+ <div class="form-txt-submit-box">
+ <input class="green-btn" type="submit" id="submit_register" name="submit_register" value="[% loc('Submit') %]">
+ </div>
+ </div>
+ [% ELSE %]
+
+ <label for="form_email">[% loc('Your email') %]</label>
+ [% IF field_errors.email %]
+ <p class='form-error'>[% field_errors.email %]</p>
+ [% END %]
+ <input type="email" value="[% report.user.email | html %]" name="email" id="form_email" placeholder="[% loc('Please enter your email address') %]" required>
+
+ <div id="form_sign_in">
+
+ <p>To submit your report you now need to confirm it either by email or by using a FixMyStreet password.</p>
+
+ <div id="form_sign_in_no" class="form-box">
+ <h5>Confirm my report by email</h5>
+
+ [% INCLUDE 'report/new/extra_name.html' %]
+
+ <label for="form_first_name">[% loc('First Name') %]</label>
+ [% IF field_errors.first_name %]
+ <p class='form-error'>[% field_errors.first_name %]</p>
+ [% END %]
+ <input type="text" class="form-focus-trigger" value="[% first_name | html %]" name="first_name" id="form_first_name" placeholder="[% loc('Your first name') %]">
+
+ <label for="form_last_name">[% loc('Last Name') %]</label>
+ [% IF field_errors.last_name %]
+ <p class='form-error'>[% field_errors.last_name %]</p>
+ [% END %]
+ <input type="text" class="form-focus-trigger" value="[% last_name | html %]" name="last_name" id="form_last_name" placeholder="[% loc('Your last name') %]">
+
+ [%# if there is nothing in the name field then set check box as default on form %]
+ <div class="checkbox-group">
+ <input type="checkbox" name="may_show_name" id="form_may_show_name" value="1"[% ' checked' IF !report.anonymous %]>
+ <label class="inline" for="form_may_show_name">[% loc('Show my name publicly') %]</label>
+ </div>
+
+ <div class="general-sidebar-notes form-focus-hidden">
+ <p class="dark">[% loc('We never show your email address or phone number.') %]</p>
+ <p>[% loc('Providing a password is optional, but doing so will allow you to more easily report future problems, leave updates and manage your reports.') %]</p>
+ </div>
+
+ <label class="form-focus-hidden" for="form_phone">[% loc('Phone number (optional)') %]</label>
+ <input class="form-focus-hidden" type="text" value="[% report.user.phone | html %]" name="phone" id="form_phone" placeholder="[% loc('Your phone number') %]">
+
+ <label class="form-focus-hidden" for="password_register">[% loc('Password (optional)') %]</label>
+
+ <div class="form-txt-submit-box form-focus-hidden">
+ <input type="password" name="password_register" id="password_register" value="" placeholder="[% loc('Enter a password') %]">
+ <input class="green-btn" type="submit" id="submit_register" name="submit_register" value="[% loc('Submit') %]">
+ </div>
+ </div>
+
+ <div id="form_sign_in_yes" class="form-box">
+
+ <h5>Confirm my report with my FixMyStreet password</h5>
+
+ <label class="hidden-js n" for="password_sign_in">[% loc('Yes I have a password') %]</label>
+ <div class="form-txt-submit-box">
+ [% IF field_errors.password %]
+ <p class='form-error'>[% field_errors.password %]</p>
+ [% END %]
+ <input type="password" name="password_sign_in" id="password_sign_in" placeholder="[% loc('Your password') %]" value="">
+ <input class="green-btn" type="submit" id="submit_sign_in" name="submit_sign_in" value="[% loc('Submit') %]">
+ </div>
+
+ <div class="checkbox-group">
+ <input type="checkbox" id="remember_me" name="remember_me" value='1'[% ' checked' IF remember_me %]>
+ <label class="n inline" for="remember_me">[% loc('Keep me signed in on this computer') %]</label>
+ </div>
+ </div>
+
+ </div>
+
+ [% END %]
+
+ <p>[% loc("We will only use your personal information in accordance with our <a href=\"/faq#privacy\">privacy policy.</a>") %]</p>
+
+ </div>
+ </fieldset>
+
+ [% IF partial_token %]
+ <input type="hidden" name="partial" value="[% partial_token.token %]">
+ [% END %]
+
+ <input type="hidden" name="submit_problem" value="1">
+</div>
diff --git a/templates/web/default/admin/council_contacts.html b/templates/web/default/admin/council_contacts.html
index da7223aa6..e35c8cda2 100644
--- a/templates/web/default/admin/council_contacts.html
+++ b/templates/web/default/admin/council_contacts.html
@@ -121,6 +121,31 @@
</p>
<p>
+ <label for="send_method">Send Method</label>:
+ <select name="send_method">
+ <option value=""> -- Select a method -- </option>
+ [% FOR method IN send_methods %]
+ <option value="[% method %]"[% ' selected' IF conf.send_method == method %]>[% method %]</option>
+ [% END %]
+ </select>
+ </p>
+
+ <p>
+ <label for="send_comments">Use Open311 comment sending extension</label>:
+ <input type="checkbox" name="send_comments"[% ' checked' IF conf.send_comments %]>
+ </p>
+
+ <p>
+ <label for"comment_user_id">User to attribute fetched comments to</label>:
+ <input type="text" name="comment_user_id" value="[% conf.comment_user_id %]">
+ </p>
+
+ <p>
+ <label for="suppress_alerts">Do not send email alerts on fetched comments to problem creator</label>:
+ <input type="checkbox" name="suppress_alerts"[% ' checked' IF conf.suppress_alerts %]>
+ </p>
+
+ <p>
<input type="hidden" name="open311_id" value="[% conf.id %]">
<input type="hidden" name="area_id" value="[% area_id %]">
<input type="hidden" name="posted" value="open311">
diff --git a/templates/web/default/admin/report_edit.html b/templates/web/default/admin/report_edit.html
index cbba1b3b0..9ef7e8248 100644
--- a/templates/web/default/admin/report_edit.html
+++ b/templates/web/default/admin/report_edit.html
@@ -37,6 +37,7 @@
<li>[% loc('Service:') %] [% problem.service %]</li>
<li>[% loc('Cobrand:') %] [% problem.cobrand %]</li>
<li>[% loc('Cobrand data:') %] [% problem.cobrand_data %]</li>
+<li>[% loc('Extra data:') %] [% problem.extra ? 'Yes' : 'No' %]</li>
<li>[% loc('Going to send questionnaire?') %] [% IF problem.send_questionnaire %][% loc('Yes') %][% ELSE %][% loc('No') %][% END %]</li>
<li><label for="flagged">[% loc('Flagged:') %]</label> <input type="checkbox" name="flagged"[% ' checked' IF problem.flagged %]></li>
diff --git a/templates/web/default/auth/sign_out.html b/templates/web/default/auth/sign_out.html
index 3d8df60e4..23d39aa2d 100644
--- a/templates/web/default/auth/sign_out.html
+++ b/templates/web/default/auth/sign_out.html
@@ -1,8 +1,8 @@
-[% INCLUDE 'header.html', title => loc('Sign out') %]
+[% INCLUDE 'header.html', title = loc('Sign out'), bodyclass = 'fullwidthpage' %]
<h1>[% loc('You have been signed out') %]</h1>
-<p>Please feel free to <a href="[% c.uri_for('/auth') %]">sign in again</a>.</p>
-
+<p>Please feel free to <a href="[% c.uri_for('/auth') %]">sign in again</a>, or
+go back to the <a href="/">FixMyStreet front page</a>.</p>
[% INCLUDE 'footer.html' %]
diff --git a/templates/web/default/common_header_tags.html b/templates/web/default/common_header_tags.html
index c87f93994..582afd422 100644
--- a/templates/web/default/common_header_tags.html
+++ b/templates/web/default/common_header_tags.html
@@ -7,7 +7,8 @@
<script src="[% version('/js/jquery.validate.min.js') %]" type="text/javascript" charset="utf-8"></script>
<script type="text/javascript" src="[% version('/js/geo.min.js') %]"></script>
-<script type="text/javascript" src="[% version(js_override || '/js/fixmystreet.js') %]"></script>
+<script type="text/javascript" src="[% version('/js/fixmystreet.js') %]"></script>
+<script type="text/javascript" src="[% version(js_override || '/js/fixmystreet-old-box.js') %]"></script>
[% map_js %]
diff --git a/templates/web/default/dashboard/index.html b/templates/web/default/dashboard/index.html
new file mode 100644
index 000000000..308042d0d
--- /dev/null
+++ b/templates/web/default/dashboard/index.html
@@ -0,0 +1,152 @@
+[%
+ INCLUDE 'header.html'
+ title = loc('Dashboard')
+ robots = 'noindex, nofollow'
+ bodyclass = 'fullwidthpage'
+%]
+
+<style>
+ th[scope=row] { text-align: left; }
+ tr.subtotal { background-color: #eee; }
+ #overview tr:nth-child(2) { background-color: #fee; }
+ select { width: auto; }
+</style>
+
+<form>
+
+<p>Ward: <select name="ward"><option value=''>All</option>
+ [% FOR w IN children.values.sort('name') %]
+ <option value="[% w.id %]"[% ' selected' IF w.id == ward %]>[% w.name %]</option>
+ [% END %]
+</select>
+
+<p>Report category: <select name="category"><option value=''>All</option>
+ [% FOR cat_op IN category_options %]
+ <option value='[% cat_op | html %]'[% ' selected' IF category == cat_op %]>[% cat_op | html %]</option>
+ [% END %]
+ </select>
+
+<p><input type="submit" value="Look up">
+
+<h2>Summary Statistics for [% council.name %]</h2>
+
+<table width="100%" id="overview">
+ <tr>
+ <td>&nbsp;</td>
+ <th scope="col">WTD</th>
+ <th scope="col">Last 7 days</th>
+ <th scope="col">Last 4 weeks</th>
+ <th scope="col">YTD</th>
+ </tr>
+
+ [%
+ rows = {
+ '0' => [ "total", "Total reports received" ]
+ '1' => [ "fixed - council", "Council has marked as fixed" ]
+ '2' => [ "fixed_user", "User has marked as fixed" ]
+ };
+ FOR row IN rows %]
+ <tr id="[% row.value.0.replace('[^\w]+', '_' ) %]">
+ <th scope="row">[% row.value.1 %]</th>
+ <td>[% problems.wtd.${row.value.0} %]</td>
+ <td>[% problems.week.${row.value.0} %]</td>
+ <td>[% problems.weeks.${row.value.0} %]</td>
+ <td>[% problems.ytd.${row.value.0} %]</td>
+ </tr>
+ [% END %]
+
+ <tr class='subtotal' id="total_fixed">
+ <th scope="row">Total marked as fixed</th>
+ <td>[% problems.wtd.${"fixed - council"} + problems.wtd.fixed_user %]</td>
+ <td>[% problems.week.${"fixed - council"} + problems.week.fixed_user %]</td>
+ <td>[% problems.weeks.${"fixed - council"} + problems.weeks.fixed_user %]</td>
+ <td>[% problems.ytd.${"fixed - council"} + problems.ytd.fixed_user %]</td>
+ </tr>
+
+ [%
+ rows = {
+ '0' => [ "in progress", "Council has marked as in progress" ]
+ '1' => [ "planned", "Council has marked as planned" ]
+ '2' => [ "investigating", "Council has marked as investigating" ]
+ '3' => [ "closed", "Council has marked as closed" ]
+ };
+ wtd = 0, week = 0, weeks = 0, ytd = 0;
+ FOR row IN rows %]
+ <tr id="[% row.value.0.replace('[^\w]+', '_' ) %]">
+ <th scope="row">[% row.value.1 %]</th>
+ <td>[% problems.wtd.${row.value.0} %]</td>
+ <td>[% problems.week.${row.value.0} %]</td>
+ <td>[% problems.weeks.${row.value.0} %]</td>
+ <td>[% problems.ytd.${row.value.0} %]</td>
+ </tr>
+ [% END %]
+
+ <tr class='subtotal' id="marked">
+ <th scope="row">Total marked</th>
+ <td>[% problems.wtd.${"in progress"} + problems.wtd.planned + problems.wtd.investigating + problems.wtd.closed %]</td>
+ <td>[% problems.week.${"in progress"} + problems.week.planned + problems.week.investigating + problems.wtd.closed %]</td>
+ <td>[% problems.weeks.${"in progress"} + problems.weeks.planned + problems.weeks.investigating + problems.wtd.closed %]</td>
+ <td>[% problems.ytd.${"in progress"} + problems.ytd.planned + problems.ytd.investigating + problems.wtd.closed %]</td>
+ </tr>
+
+ <tr id="avg_fixed">
+ <th scope="row">Average time to council marking fixed (days)</th>
+ <td>[% problems.wtd.time_to_fix %]</td>
+ <td>[% problems.week.time_to_fix %]</td>
+ <td>[% problems.weeks.time_to_fix %]</td>
+ <td>[% problems.ytd.time_to_fix %]</td>
+ </tr>
+
+ <tr id="avg_marked">
+ <th scope="row">Average time to first council state change (days)</th>
+ <td>[% problems.wtd.time_to_mark %]</td>
+ <td>[% problems.week.time_to_mark %]</td>
+ <td>[% problems.weeks.time_to_mark %]</td>
+ <td>[% problems.ytd.time_to_mark %]</td>
+ </tr>
+
+ <tr class='subtotal' id="not_marked">
+ <th scope="row">Total not marked</th>
+ <td>[% problems.wtd.not_marked %]</td>
+ <td>[% problems.week.not_marked %]</td>
+ <td>[% problems.weeks.not_marked %]</td>
+ <td>[% problems.ytd.not_marked %]</td>
+ </tr>
+
+</table>
+
+<h2>Reports</h2>
+
+ </select>
+<p>Report state: <select name="state">
+<option value=''>All</option>
+ [% FOREACH state IN [ ['confirmed', loc('Open')], ['investigating',
+ loc('Investigating')], ['planned', loc('Planned')], ['in progress',
+ loc('In Progress')], ['closed', loc('Closed')], ['fixed', loc('Fixed')] ] %]
+ <option [% 'selected ' IF state.0 == q_state %] value="[% state.0 %]">[% state.1 %]</option>
+ [% END %]
+</select>
+<input type="submit" value="Look up">
+
+<table width="100%" id="reports">
+ <tr>
+ <th scope="col">Less than 7 days old</th>
+ <th scope="col">7-14 days old</th>
+ <th scope="col">14-30 days old</th>
+ </tr>
+ <tr>
+ <td width="34%"><ul>[% INCLUDE list, list = lists.1 %]</ul></td>
+ <td width="33%"><ul>[% INCLUDE list, list = lists.2 %]</ul></td>
+ <td width="33%"><ul>[% INCLUDE list, list = lists.3 %]</ul></td>
+ </tr>
+</table>
+
+</form>
+
+[% INCLUDE 'footer.html' %]
+
+[% BLOCK list %]
+[% FOR p IN list %]
+<li><a href="/report/[% p.id %]">[% p.title | html %]</a></li>
+[% END %]
+[% END %]
diff --git a/templates/web/default/faq/faq-en-gb.html b/templates/web/default/faq/faq-en-gb.html
index 290be5564..1e52cc3b0 100755
--- a/templates/web/default/faq/faq-en-gb.html
+++ b/templates/web/default/faq/faq-en-gb.html
@@ -25,11 +25,11 @@ or clearing</strong>, such as:
</dd>
<dt>What isn&rsquo;t FixMyStreet for?</dt>
- <dd>FixMyStreet is not a way of getting in touch with [% c.cobrand.moniker == 'southampton' ? 'the' : 'your' %] council for all
+ <dd>FixMyStreet is not a way of getting in touch with [% c.cobrand.is_council ? 'the' : 'your' %] council for all
issues &ndash; please use FixMyStreet only for problems such as the above. We
often route problem reports via cleansing services or highways and so using
FixMyStreet for other matters may result in a delay in your report getting
- to the right department. <strong>You will need to contact [% c.cobrand.moniker == 'southampton' ? 'the' : 'your' %] council
+ to the right department. <strong>You will need to contact [% c.cobrand.is_council ? 'the' : 'your' %] council
directly for problems such as</strong>:
<ul><li>Anti-social behaviour
@@ -51,7 +51,7 @@ with a map of that area. You can view problems already reported in that area,
or report ones of your own simply by clicking on the map at the location of
the problem.</dd>
<dt>How are the problems solved?</dt>
- <dd>They are reported to the [% IF c.cobrand.moniker != 'southampton' %]relevant[% END %] council by email. The
+ <dd>They are reported to the [% IF !c.cobrand.is_council %]relevant[% END %] council by email. The
council can then resolve the problem the way they normally would.
Alternatively, you can discuss the problem on the website with others[% IF c.cobrand.moniker != 'southampton' %], and
then together lobby the council to fix it, or fix it directly yourselves[% END %].</dd>
@@ -91,7 +91,8 @@ href="https://secure.mysociety.org/donate/">please do</a>.</dd>
to find out where reports go at the moment. Also <a href="/contact">contact us</a>
to update the address or addresses we use.</dd>
<dt>I&rsquo;m from a council, can we have FixMyStreet on our website?</dt>
- <dd>Yes you can! We offer branded, hosted versions of FixMyStreet for local council websites. <a href="/for-councils">Full details</a>.</dd>
+ <dd>Yes you can! We offer branded, hosted versions of FixMyStreet for local council websites.
+ <a href="http://www.mysociety.org/for-councils/fixmystreet/">Full details</a>.</dd>
<dt>Do you remove silly or illegal content?</dt>
<dd>FixMyStreet is not responsible for the content and accuracy
of material submitted by its users. We reserve the right to edit or remove any
diff --git a/templates/web/default/index.html b/templates/web/default/index.html
index e5f98b0c5..4d178d192 100644
--- a/templates/web/default/index.html
+++ b/templates/web/default/index.html
@@ -51,7 +51,7 @@
</div>
[%
- recent_photos = c.cobrand.recent_photos(3);
+ recent_photos = c.cobrand.recent_photos('front', 3);
probs = c.cobrand.recent();
%]
diff --git a/templates/web/default/js/validation_strings.html b/templates/web/default/js/validation_strings.html
index 718d10d56..3148d1993 100644
--- a/templates/web/default/js/validation_strings.html
+++ b/templates/web/default/js/validation_strings.html
@@ -14,5 +14,8 @@
email: {
required: '[% loc('Please enter your email') | replace("'", "\\'") %]',
email: '[% loc('Please enter a valid email') | replace("'", "\\'") %]'
- }
+ },
+ fms_extra_title: '[% loc('Please enter your title') | replace("'", "\\'") %]',
+ first_name: '[% loc('Please enter your first name') | replace("'", "\\'") %]',
+ last_name: '[% loc('Please enter your second name') | replace("'", "\\'") %]'
};
diff --git a/templates/web/default/report/new/councils_text_all.html b/templates/web/default/report/new/councils_text_all.html
index 8514e0b0a..df3388bf3 100644
--- a/templates/web/default/report/new/councils_text_all.html
+++ b/templates/web/default/report/new/councils_text_all.html
@@ -1,5 +1,5 @@
<p>
-[% IF all_councils.${area_ids_to_list.0}.type == 'LBO' %]
+[% IF area_ids_to_list.0 != 2489 && area_ids_to_list.0 != 2482 && all_councils.${area_ids_to_list.0}.type == 'LBO' %]
[%
tprintf(
loc('All the information you provide here will be sent to <strong>%s</strong> or a relevant local body such as <strong>TfL</strong>, via the London Report-It system.'),
diff --git a/templates/web/default/report/new/extra_name.html b/templates/web/default/report/new/extra_name.html
new file mode 100644
index 000000000..e8c2cadaf
--- /dev/null
+++ b/templates/web/default/report/new/extra_name.html
@@ -0,0 +1,18 @@
+[% IF extra_name_info %]
+<label for="form_fms_extra_title">Title</label>
+[% IF field_errors.fms_extra_title %]
+ <p class='form-error'>[% field_errors.fms_extra_title %]</p>
+[% END %]
+[% title = '' %]
+[% IF fms_extra_title %][% title = fms_extra_title | upper %]
+[% ELSIF c.user && c.user.title %][% title = c.user.title | upper %][% END %]
+<select class="form-focus-trigger" id="form_fms_extra_title"
+ name="fms_extra_title">
+ <option></option>
+ <option value="MR"[% ' selected' IF title == 'MR' %]>Mr</option>
+ <option value="MISS"[% ' selected' IF title == 'MISS' %]>Miss</option>
+ <option value="MRS"[% ' selected' IF title == 'MRS' %]>Mrs</option>
+ <option value="MS"[% ' selected' IF title == 'MS' %]>Ms</option>
+ <option value="DR"[% ' selected' IF title == 'DR' %]>Dr</option>
+</select>
+[% END %]
diff --git a/templates/web/default/report/updates.html b/templates/web/default/report/updates.html
index 374a7c570..2a65a3e3e 100644
--- a/templates/web/default/report/updates.html
+++ b/templates/web/default/report/updates.html
@@ -12,9 +12,13 @@
[% IF update.anonymous || update.name == '' %]
[% tprintf( loc( 'Posted anonymously at %s' ), prettify_epoch( update.confirmed_local.epoch ) ) -%]
- [%- ELSIF update.user.from_council %]
- [% user_name = update.user.name | html %]
- [% tprintf( loc( 'Posted by %s (<strong>%s</strong>) at %s' ), user_name, update.user.council, prettify_epoch( update.confirmed_local.epoch ) ) -%]
+ [%- ELSIF update.user.from_council;
+ user_name = update.user.name | html;
+ council = update.user.council;
+ IF council == 'Bromley Council';
+ council = "$council <img src='/cobrands/bromley/favicon.png' alt=''>";
+ END %]
+ [% tprintf( loc( 'Posted by %s (<strong>%s</strong>) at %s' ), user_name, council, prettify_epoch( update.confirmed_local.epoch ) ) -%]
[%- ELSE %]
[% tprintf( loc( 'Posted by %s at %s' ), update.name, prettify_epoch( update.confirmed_local.epoch ) ) | html -%]
[%- END -%]
diff --git a/templates/web/default/reports/council.html b/templates/web/default/reports/council.html
index 0d3d43d82..b837bcee9 100755
--- a/templates/web/default/reports/council.html
+++ b/templates/web/default/reports/council.html
@@ -1,3 +1,9 @@
+[% IF c.cobrand.moniker == 'fixmystreet' OR c.cobrand.moniker == 'bromley';
+ style = 'new';
+ ELSE;
+ style = 'old';
+ END;
+%]
[% IF ward %]
[% name = "$ward.name, $council.name"
thing = loc('ward')
@@ -8,6 +14,12 @@
%]
[% END %]
+[% IF c.cobrand.is_council %]
+ [% ward_text = loc( 'View reports by ward' ) %]
+[% ELSE %]
+ [% ward_text = loc( 'Wards of this council' ) %]
+[% END %]
+
[%
PROCESS "maps/${map.type}.html";
INCLUDE 'header.html',
@@ -19,8 +31,8 @@
[% map_html %]
-[% IF c.cobrand.moniker != 'fixmystreet' AND children.size %]
-<h2 style="clear:right">[% loc('Wards of this council') %]</h2>
+[% IF c.cobrand.all_reports_style != 'detailed' AND children.size %]
+<h2 style="clear:right">[% ward_text %]</h2>
<p>[% loc('Follow a ward link to view only reports within that ward.') %]</p>
<ul>
[% FOR child IN children.values.sort('name') %]
@@ -66,12 +78,22 @@ Its area is now covered by <a href="/reports/Bedford">Bedford Borough Council</a
<a href="/reports/Central+Bedfordshire">Central Bedfordshire Council</a>.
[% END %]
</p>
-[% ELSIF c.cobrand.moniker == 'fixmystreet' %]
+[% ELSIF c.cobrand.all_reports_style == 'detailed' %]
<div class="shadow-wrap">
<ul id="key-tools"[% IF NOT children.size %] class="singleton"[% END %]>
- <li><a rel="nofollow" id="key-tool-updates-area" class="feed" href="[% rss_url %]">[% tprintf(loc('Get updates of problems in this %s'), thing) %]</a></li>
+ <li><a rel="nofollow" id="key-tool-updates-area" class="feed" href="[% rss_url %]">[%
+ IF c.cobrand.moniker == 'bromley' AND thing == 'council';
+ 'Get updates of reports in Bromley';
+ ELSIF c.cobrand.moniker == 'bromley';
+ 'Get updates of reports in this ward';
+ ELSIF c.cobrand.is_council;
+ tprintf(loc('Get updates of %s problems'), thing);
+ ELSE;
+ tprintf(loc('Get updates of problems in this %s'), thing);
+ END
+ %]</a></li>
[% IF children.size %]
- <li><a href="#council_wards" id="key-tool-wards" class="chevron">[% loc('Wards of this council') %]</a></li>
+ <li><a href="#council_wards" id="key-tool-wards" class="chevron">[% ward_text %]</a></li>
[% END %]
</ul>
</div>
@@ -81,9 +103,9 @@ Its area is now covered by <a href="/reports/Bedford">Bedford Borough Council</a
[% TRY %][% INCLUDE 'reports/cobrand_stats.html' %][% CATCH file %][% END %]
-[% IF c.cobrand.moniker == 'fixmystreet' AND children.size %]
+[% IF c.cobrand.all_reports_style == 'detailed' AND children.size %]
<section id="council_wards" class="hidden-js">
- <h2>[% loc('Wards of this council') %]</h2>
+<h2>[% ward_text %]</h2>
<p>[% loc('Follow a ward link to view only reports within that ward.') %]</p>
<ul class="issue-list-a full-width">
[% FOR child IN children.values.sort('name') %]
@@ -96,7 +118,7 @@ Its area is now covered by <a href="/reports/Bedford">Bedford Borough Council</a
[% IF c.cobrand.moniker == 'fixmystreet' %]
<p class="promo">
FixMyStreet is now available for local council websites.
- <a href="/for-councils">Find&nbsp;out&nbsp;more</a>.
+ <a href="http://www.mysociety.org/for-councils/fixmystreet/">Find&nbsp;out&nbsp;more</a>.
</p>
[% END %]
@@ -117,7 +139,7 @@ Its area is now covered by <a href="/reports/Bedford">Bedford Borough Council</a
[% IF problems %]
<ul class="issue-list-a">
-[% IF c.cobrand.moniker == 'fixmystreet' %]
+[% IF c.cobrand.all_reports_style == 'detailed' %]
[% FOREACH problem IN problems %]
<li>
diff --git a/templates/web/default/tokens/confirm_problem.html b/templates/web/default/tokens/confirm_problem.html
index 756958380..1e3c6c535 100644
--- a/templates/web/default/tokens/confirm_problem.html
+++ b/templates/web/default/tokens/confirm_problem.html
@@ -1,8 +1,16 @@
-[% INCLUDE 'header.html', title => loc('Confirmation') %]
+[% INCLUDE 'header.html', title = loc('Confirmation') %]
<h1>[% loc('Confirmation') %]</h1>
<p class="confirmed">
+[% IF c.cobrand.is_council %]
+Thank you. You have successfully confirmed your report
+and this will now be investigated by the council.
+You can <a href="[% c.uri_for( '/report', problem.id ) %]">view the problem on this site</a>.
+</p>
+
+<p>Your reference for this problem is [% problem.id %], please quote it in any enquiries.
+[% ELSE %]
[%
loc('You have successfully confirmed your problem');
@@ -15,6 +23,7 @@
c.uri_for( '/report', problem.id )
);
%]
+[% END %]
</p>
[% display_crosssell_advert( problem.user.email, problem.name ) %]
diff --git a/templates/web/fixmystreet/alert/_list.html b/templates/web/fixmystreet/alert/_list.html
index e9f877466..e14d394f2 100644
--- a/templates/web/fixmystreet/alert/_list.html
+++ b/templates/web/fixmystreet/alert/_list.html
@@ -30,7 +30,11 @@
</p>
<p>
+ [% IF c.cobrand.is_council %]
+ Or you can subscribe to an alert for all council problems or one based upon what ward you&rsquo;re in:
+ [% ELSE %]
[% loc("Or you can subscribe to an alert based upon what ward or council you&rsquo;re in:") %]
+ [% END %]
</p>
[% IF reported_to_options %]
diff --git a/templates/web/fixmystreet/alert/index.html b/templates/web/fixmystreet/alert/index.html
index 8d4459c01..03d9843f6 100644
--- a/templates/web/fixmystreet/alert/index.html
+++ b/templates/web/fixmystreet/alert/index.html
@@ -3,9 +3,15 @@
<h1>[% loc('Local RSS feeds and email alerts') %]</h1>
<p>
+[% IF c.cobrand.is_council %]
+FixMyStreet has a variety of RSS feeds and email alerts for local problems, including
+alerts for all problems within a particular ward, or all problems
+within a certain distance of a particular location.
+[% ELSE %]
[% loc('FixMyStreet has a variety of RSS feeds and email alerts for local problems, including
alerts for all problems within a particular ward or council, or all problems
within a certain distance of a particular location.') %]
+[% END %]
</p>
[% IF location_offshore %]
@@ -16,8 +22,13 @@ within a certain distance of a particular location.') %]
[% INCLUDE 'errors.html' %]
[% END %]
-<p>[% loc('To find out what local alerts we have for you, please enter your GB
- postcode or street name and area' ) %]</p>
+<p>
+[% IF c.cobrand.is_council %]
+To find out what local alerts we have for you, please enter your [% c.cobrand.council_area %] postcode or street name and area:
+[% ELSE %]
+[% loc('To find out what local alerts we have for you, please enter your GB postcode or street name and area' ) %]
+[% END %]
+</p>
<form method="get" action="/alert/list" class="full-width">
<fieldset>
<div class="form-txt-submit-box">
diff --git a/templates/web/fixmystreet/alert/list.html b/templates/web/fixmystreet/alert/list.html
index 8305fff6f..84899d457 100644
--- a/templates/web/fixmystreet/alert/list.html
+++ b/templates/web/fixmystreet/alert/list.html
@@ -20,7 +20,6 @@
<form id="alerts" name="alerts" method="post" action="/alert/subscribe">
-[%# XXX These photos should perhaps be in a vertical column on the right hand side, as currently. %]
[% IF photos.size %]
<div class="sticky-sidebar">
<aside>
diff --git a/templates/web/fixmystreet/around/around_index.html b/templates/web/fixmystreet/around/around_index.html
index 331f34325..d91ba928a 100644
--- a/templates/web/fixmystreet/around/around_index.html
+++ b/templates/web/fixmystreet/around/around_index.html
@@ -1,34 +1,37 @@
-[% INCLUDE 'header.html', title => loc('Reporting a problem'), bodyclass => 'mappage' %]
-
-[%
- # NOTE ON PARTIAL REPORTS:
- #
- # partial reports get a bit of extra text added, the form goes to
- # '/report/new' and the partial hidden field is added to the form.
-%]
-
+[% pre_container_extra = BLOCK %]
+<div id="front-main"><div id="front-main-container">
[%
question
= c.cobrand.enter_postcode_text()
|| loc("Enter a nearby GB postcode, or street name and area");
%]
-
<form action="[% c.uri_for('/around') %]" method="get" name="postcodeForm" id="postcodeForm">
- <fieldset>
- <label for="pc">[% question %]:</label>
+ <label for="pc">[% question %]:</label>
+ <div>
<input type="text" name="pc" value="[% pc | html %]" id="pc" size="10" maxlength="200">
- <input class="green-btn final-submit" type="submit" value="[% loc('Go') %]" id="submit">
+ <input type="submit" value="[% loc('Go') %]" id="submit">
+ </div>
- [% IF partial_token %]
- <input type="hidden" name="partial" value="[% partial_token.token %]">
- [% END %]
- </fieldset>
+ [% IF partial_token %]
+ <input type="hidden" name="partial" value="[% partial_token.token %]">
+ [% END %]
</form>
+</div></div>
+[% END %]
+
+[% INCLUDE 'header.html', title = loc('Reporting a problem'), bodyclass = 'frontpage fullwidthpage' %]
+
+[%
+ # NOTE ON PARTIAL REPORTS:
+ #
+ # partial reports get a bit of extra text added, the form goes to
+ # '/report/new' and the partial hidden field is added to the form.
+%]
[% IF location_offshore %]
- <p class="error">[% loc('That spot does not appear to be covered by a council. If you have tried to report an issue past the shoreline, for example, please specify the closest point on land.') %]</p>
+ <p class="form-error">[% loc('That spot does not appear to be covered by a council. If you have tried to report an issue past the shoreline, for example, please specify the closest point on land.') %]</p>
[% ELSIF location_error %]
- <p class="error">[% location_error %]</p>
+ <p class="form-error">[% location_error %]</p>
[% END %]
[% IF possible_location_matches %]
@@ -43,10 +46,8 @@
[% IF partial_token %]
<p style="margin-top: 0; color: #cc0000;">
<img align="right" src="/photo/[% partial_report.id %].jpeg" hspace="5">
- [% loc("Thanks for uploading your photo. We now need to locate your problem, so please enter a nearby street name or postcode in the box below&nbsp;:") %]
+ [% loc("Thanks for uploading your photo. We now need to locate your problem, so please enter a nearby street name or postcode in the box above&nbsp;:") %]
</p>
[% END %]
-
-
[% INCLUDE 'footer.html' %]
diff --git a/templates/web/fixmystreet/around/display_location.html b/templates/web/fixmystreet/around/display_location.html
index c98982a60..a7240688f 100755
--- a/templates/web/fixmystreet/around/display_location.html
+++ b/templates/web/fixmystreet/around/display_location.html
@@ -69,7 +69,12 @@
<div id="side">
- <h1 class="big-green-banner">[% loc( 'Click map to report a problem' ) %]</h1>
+ <h1 class="big-green-banner">[%
+ loc( 'Click map to report a problem' );
+ IF c.cobrand.moniker == 'bromley';
+ '<span>Yellow pins show existing reports</span>';
+ END
+ %]</h1>
<p id="skip-this-step">
[%
diff --git a/templates/web/fixmystreet/faq/faq-en-gb.html b/templates/web/fixmystreet/faq/faq-en-gb.html
index 1e676d9f2..123de7c37 100755
--- a/templates/web/fixmystreet/faq/faq-en-gb.html
+++ b/templates/web/fixmystreet/faq/faq-en-gb.html
@@ -36,11 +36,11 @@ or clearing</strong>, such as:
</dd>
<dt>What isn&rsquo;t FixMyStreet for?</dt>
- <dd>FixMyStreet is not a way of getting in touch with [% c.cobrand.moniker == 'southampton' ? 'the' : 'your' %] council for all
+ <dd>FixMyStreet is not a way of getting in touch with [% c.cobrand.is_council ? 'the' : 'your' %] council for all
issues &ndash; please use FixMyStreet only for problems such as the above. We
often route problem reports via cleansing services or highways and so using
FixMyStreet for other matters may result in a delay in your report getting
- to the right department. <strong>You will need to contact [% c.cobrand.moniker == 'southampton' ? 'the' : 'your' %] council
+ to the right department. <strong>You will need to contact [% c.cobrand.is_council ? 'the' : 'your' %] council
directly for problems such as</strong>:
<ul><li>Anti-social behaviour
@@ -62,7 +62,7 @@ with a map of that area. You can view problems already reported in that area,
or report ones of your own simply by clicking on the map at the location of
the problem.</dd>
<dt>How are the problems solved?</dt>
- <dd>They are reported to the [% IF c.cobrand.moniker != 'southampton' %]relevant[% END %] council by email. The
+ <dd>They are reported to the [% IF !c.cobrand.is_council %]relevant[% END %] council by email. The
council can then resolve the problem the way they normally would.
Alternatively, you can discuss the problem on the website with others[% IF c.cobrand.moniker != 'southampton' %], and
then together lobby the council to fix it, or fix it directly yourselves[% END %].</dd>
@@ -102,7 +102,7 @@ href="https://secure.mysociety.org/donate/">please do</a>.</dd>
to find out where reports go at the moment. Also <a href="/contact">contact us</a>
to update the address or addresses we use.</dd>
<dt>I&rsquo;m from a council, can we have FixMyStreet on our website?</dt>
- <dd>Yes you can! We offer branded, hosted versions of FixMyStreet for local council websites. <a href="/for-councils">Full details</a>.</dd>
+ <dd>Yes you can! We offer branded, hosted versions of FixMyStreet for local council websites. <a href="http://www.mysociety.org/for-councils/fixmystreet/">Full details</a>.</dd>
<dt>Do you remove silly or illegal content?</dt>
<dd>FixMyStreet is not responsible for the content and accuracy
of material submitted by its users. We reserve the right to edit or remove any
diff --git a/templates/web/fixmystreet/footer.html b/templates/web/fixmystreet/footer.html
index 903d8c73d..c45c3c536 100644
--- a/templates/web/fixmystreet/footer.html
+++ b/templates/web/fixmystreet/footer.html
@@ -19,7 +19,7 @@
</li>
<li>
<h4>[% loc('Are you from a council?') %]</h4>
- <p>[% loc('Would you like better integration with FixMyStreet? <a href="/for-councils">Find out about FixMyStreet for councils</a>.') %]</p>
+ <p>[% loc('Would you like better integration with FixMyStreet? <a href="http://www.mysociety.org/for-councils/fixmystreet/">Find out about FixMyStreet for councils</a>.') %]</p>
</li>
</ul>
</div>
diff --git a/templates/web/fixmystreet/header.html b/templates/web/fixmystreet/header.html
index f5d510922..731af797a 100644
--- a/templates/web/fixmystreet/header.html
+++ b/templates/web/fixmystreet/header.html
@@ -18,7 +18,8 @@
<link rel="stylesheet" href="[% version('/cobrands/fixmystreet/layout.css') %]">
<![endif]-->
- <script src="[% version('/js/modernizr.custom.76759.js') %]" charset="utf-8"></script>
+ <script src="[% version('/js/modernizr.custom.js') %]" charset="utf-8"></script>
+ <script src="[% version('/cobrands/fixmystreet/position_map.js') %]" charset="utf-8"></script>
[% INCLUDE 'common_header_tags.html', js_override = '/cobrands/fixmystreet/fixmystreet.js' %]
[% extra_js %]
@@ -51,6 +52,8 @@
[% END %]
</div>
+ [% pre_container_extra %]
+
<div class="container">
<div class="content[% " $mainclass" | html IF mainclass %]" role="main">
diff --git a/templates/web/fixmystreet/index.html b/templates/web/fixmystreet/index.html
index 04b23ca7f..476c426b0 100644
--- a/templates/web/fixmystreet/index.html
+++ b/templates/web/fixmystreet/index.html
@@ -16,18 +16,15 @@ Modernizr.load({
</script>
[% END %]
-[% INCLUDE 'header.html', title => '' , bodyclass => 'frontpage fullwidthpage' %]
-
-[% IF error %]
- <p class="error">[% error %]</p>
-[% END %]
-
-
+[% pre_container_extra = BLOCK %]
<div id="front-main">
<div id="front-main-container">
- <h1>[% loc('Report, view, or discuss local problems') %]</h1>
-
- <h2>[% loc('(like graffiti, fly tipping, broken paving slabs, or street lighting)') %]</h2>
+ [% IF c.cobrand.moniker == 'bromley' %]
+ <h1 class="main mob-only">Reporting a problem in Bromley&rsquo;s streets or parks</h1>
+ [% ELSE %]
+ <h1>[% loc('Report, view, or discuss local problems') %]</h1>
+ <h2>[% loc('(like graffiti, fly tipping, broken paving slabs, or street lighting)') %]</h2>
+ [% END %]
[%
question
@@ -44,6 +41,17 @@ Modernizr.load({
</form>
</div>
</div>
+[% END %]
+
+[% INCLUDE 'header.html', title = '', bodyclass = 'frontpage fullwidthpage' %]
+
+[% IF c.cobrand.moniker == 'bromley' %]
+<p>This is primarily for reporting physical problems that can be fixed
+like graffiti, cleansing issues or road defects. To report other
+kinds of problems like missed bins use our
+<a href="http://www.bromley.gov.uk/report">online report it forms</a>.
+</p>
+[% END %]
<div class="tablewrapper">
<div id="front-howto">
@@ -53,7 +61,11 @@ Modernizr.load({
<li>[% question %]</li>
<li>[% loc('Locate the problem on a map of the area') %]</li>
<li>[% loc('Enter details of the problem') %]</li>
- <li>[% loc('We send it to the council on your behalf') %]</li>
+ [% IF c.cobrand.is_council %]
+ <li>Confirm the report and [% c.cobrand.council_name %] will investigate</li>
+ [% ELSE %]
+ <li>[% loc('We send it to the council on your behalf') %]</li>
+ [% END %]
</ol>
<section class="full-width">
@@ -64,7 +76,7 @@ Modernizr.load({
[%
- recent_photos = c.cobrand.recent_photos(5);
+ recent_photos = c.cobrand.recent_photos('front', 5);
%]
[% IF recent_photos.size %]
diff --git a/templates/web/fixmystreet/report/display.html b/templates/web/fixmystreet/report/display.html
index 0bb13fa67..26e041d61 100644
--- a/templates/web/fixmystreet/report/display.html
+++ b/templates/web/fixmystreet/report/display.html
@@ -57,7 +57,7 @@
[% IF c.cobrand.moniker != 'emptyhomes' %]
<div class="general-sidebar-notes">
- <p>[% loc( 'Please note that updates are not sent to the council. If you leave your name it will be public. Your information will only be used in accordance with our <a href="/faq#privacy">privacy policy</a>' ) %]</p>
+ [% INCLUDE 'report/updates-sidebar-notes.html' %]
</div>
[% END %]
@@ -179,6 +179,10 @@
[% INCLUDE 'footer.html' %]
[% BLOCK name %]
+ [% IF problem.council == '2482' %]
+ [% extra_name_info = 1 %]
+ [% INCLUDE 'report/new/extra_name.html' %]
+ [% END %]
<label for="form_name">[% loc('Name') %]</label>
[% IF field_errors.name %]
<p class='form-error'>[% field_errors.name %]</p>
diff --git a/templates/web/fixmystreet/report/new/category.html b/templates/web/fixmystreet/report/new/category.html
deleted file mode 100644
index 095cd7c2e..000000000
--- a/templates/web/fixmystreet/report/new/category.html
+++ /dev/null
@@ -1,10 +0,0 @@
-[% FILTER collapse %]
-[% IF category_options.size %]
- <label for='form_category'>[% category_label | html %]</label>
- <select name='category' id='form_category'[% ' onchange="form_category_onchange()"' IF category_extras.size %]>
- [% FOREACH cat_op IN category_options %]
- <option value='[% cat_op | html %]'[% ' selected' IF report.category == cat_op %]>[% cat_op | html %]</option>
- [% END %]
- </select>
-[% END %]
-[% END -%]
diff --git a/templates/web/fixmystreet/report/new/councils_text.html b/templates/web/fixmystreet/report/new/councils_text.html
deleted file mode 100644
index 1da5746c1..000000000
--- a/templates/web/fixmystreet/report/new/councils_text.html
+++ /dev/null
@@ -1,9 +0,0 @@
-[% FILTER collapse %]
-[% IF area_ids_to_list.size == 0 %]
- [% PROCESS 'report/new/councils_text_none.html' %]
-[% ELSIF area_ids_to_list.size == all_councils.size %]
- [% PROCESS 'report/new/councils_text_all.html' %]
-[% ELSE %]
- [% PROCESS 'report/new/councils_text_some.html' %]
-[% END %]
-[% END -%]
diff --git a/templates/web/fixmystreet/report/new/councils_text_all.html b/templates/web/fixmystreet/report/new/councils_text_all.html
deleted file mode 100644
index fe2d5be12..000000000
--- a/templates/web/fixmystreet/report/new/councils_text_all.html
+++ /dev/null
@@ -1,19 +0,0 @@
-<p>
-[% IF area_ids_to_list.0 != 2489 && all_councils.${area_ids_to_list.0}.type == 'LBO' %]
-[%
- tprintf(
- loc('All the information you provide here will be sent to <strong>%s</strong> or a relevant local body such as <strong>TfL</strong>, via the London Report-It system.'),
- all_council_names.join( '</strong>' _ loc(' or ') _ '<strong>' )
- );
-%]
-[% ELSE %]
-[%
- tprintf(
- loc('All the information you provide here will be sent to <strong>%s</strong>.'),
- all_council_names.join( '</strong>' _ loc(' or ') _ '<strong>' )
- );
-%]
-[% END %]
-
-[% loc('The subject and details of the problem will be public, plus your name if you give us permission.') %]
-</p>
diff --git a/templates/web/fixmystreet/report/new/councils_text_none.html b/templates/web/fixmystreet/report/new/councils_text_none.html
deleted file mode 100644
index 992d030c0..000000000
--- a/templates/web/fixmystreet/report/new/councils_text_none.html
+++ /dev/null
@@ -1,20 +0,0 @@
-<p>[%
-
- nget(
- "We do not yet have details for the council that covers this location.",
- "We do not yet have details for the councils that cover this location.",
- all_councils.size
- );
-%]
-[%
- loc("If you submit a problem here the subject and details of the problem will be public, but the problem will <strong>not</strong> be reported to the council.");
-%]
-[%
- tprintf(
- loc("You can help us by finding a contact email address for local problems for %s and emailing it to us at <a href='mailto:%s'>%s</a>."),
- all_council_names.join( loc(' or ') ),
- c.cobrand.contact_email,
- c.cobrand.contact_email
- );
-
-%]</p> \ No newline at end of file
diff --git a/templates/web/fixmystreet/report/new/councils_text_some.html b/templates/web/fixmystreet/report/new/councils_text_some.html
deleted file mode 100644
index 9f123fb9a..000000000
--- a/templates/web/fixmystreet/report/new/councils_text_some.html
+++ /dev/null
@@ -1,28 +0,0 @@
-<p>
-[% loc('All the information you provide here will be sent to') %]
-
-[% FOREACH council_id IN area_ids_to_list %]
- [% loc( ' or ') IF ! loop.first %]
- <strong>[% all_councils.$council_id.name %]</strong>
- [%- '.' IF loop.last %]
-[% END %]
-
-[%
- loc('The subject and details of the problem will be public, plus your name if you give us permission.');
-%]
-[%
- nget(
- "We do <strong>not</strong> yet have details for the other council that covers this location.",
- "We do <strong>not</strong> yet have details for the other councils that cover this location.",
- missing_details_councils.size
- );
-%]
-[%
- tprintf(
- loc("You can help us by finding a contact email address for local problems for %s and emailing it to us at <a href='mailto:%s'>%s</a>."),
- missing_details_council_names.join( loc(' or ') ),
- c.cobrand.contact_email,
- c.cobrand.contact_email
- );
-%]
-</p> \ No newline at end of file
diff --git a/templates/web/fixmystreet/report/new/fill_in_details_form.html b/templates/web/fixmystreet/report/new/fill_in_details_form.html
index 283f748ba..237533657 100644
--- a/templates/web/fixmystreet/report/new/fill_in_details_form.html
+++ b/templates/web/fixmystreet/report/new/fill_in_details_form.html
@@ -69,7 +69,7 @@
[% IF js %]
<div id="form_category_row">
- <label class="inline" for="form_category">[% loc('Category') %]</label>
+ <label for="form_category">[% loc('Category') %]</label>
<select name="category" id="form_category" required><option>[% loc('Loading...') %]</option></select>
</div>
[% ELSE %]
@@ -111,7 +111,10 @@
[% IF c.user_exists %]
<div class="form-box">
- <label for="form_may_show_nameme">[% loc('Name') %]</label>
+
+ [% INCLUDE 'report/new/extra_name.html' %]
+
+ <label for="form_name">[% loc('Name') %]</label>
[% IF field_errors.name %]
<p class='form-error'>[% field_errors.name %]</p>
[% END %]
@@ -168,10 +171,13 @@
<div id="form_sign_in_no" class="form-box">
<h5>[% loc('<strong>No</strong> Let me confirm my report by email') %]</h5>
- <label for="form_may_show_nameme">[% loc('Name') %]</label>
+ [% INCLUDE 'report/new/extra_name.html' %]
+
+ <label for="form_name">[% loc('Name') %]</label>
[% IF field_errors.name %]
<p class='form-error'>[% field_errors.name %]</p>
[% END %]
+
<input type="text" class="form-focus-trigger validName" value="[% report.name | html %]" name="name" id="form_name" placeholder="[% loc('Your name') %]">
[%# if there is nothing in the name field then set check box as default on form %]
diff --git a/templates/web/fixmystreet/report/new/notes.html b/templates/web/fixmystreet/report/new/notes.html
index 5a885abd0..289520be3 100644
--- a/templates/web/fixmystreet/report/new/notes.html
+++ b/templates/web/fixmystreet/report/new/notes.html
@@ -6,4 +6,4 @@
<li>[% loc("Please do not be abusive &mdash; abusing your council devalues the service for all users.") %]</li>
<li>[% loc("Writing your message entirely in block capitals makes it hard to read, as does a lack of punctuation.") %]</li>
<li>[% loc("Remember that FixMyStreet is primarily for reporting physical problems that can be fixed. If your problem is not appropriate for submission via this site remember that you can contact your council directly using their own website.") %]</li>
-</ul> \ No newline at end of file
+</ul>
diff --git a/templates/web/fixmystreet/report/new/report_import.html b/templates/web/fixmystreet/report/new/report_import.html
deleted file mode 100644
index 7aa105afe..000000000
--- a/templates/web/fixmystreet/report/new/report_import.html
+++ /dev/null
@@ -1,92 +0,0 @@
-[% INCLUDE 'header.html', title => 'External import' %]
-
-<h1>External import</h1>
-
-<p>You may inject problem reports into FixMyStreet programatically using this
-simple interface. Upon receipt, an email will be sent to the address given,
-with a link the user must click in order to check the details of their report,
-add any other information they wish, and then submit to the council.
-
-<p>This interface returns a plain text response; either <samp>SUCCESS</samp> if
-the report has been successfully received, or if not, a list of errors, one per
-line each starting with <samp>ERROR:</samp>.
-
-<p>You may submit the following information by POST to this URL
-(i.e. <samp>[% c.uri_for('/import') %]</samp> ):</p>
-
-<style type="text/css" media="screen">
- input {
- /* Hide the form elements - they are just here for simpler testing */
- display: none;
- }
-</style>
-
-<form method="POST" action="/import" enctype="multipart/form-data">
-
-<dl>
- <dt>service</dt>
- <dd>
- <em>Required</em>.
- Name of application/service using this interface.
- <input type="text" name="service" />
- </dd>
-
- <dt>id</dt>
- <dd>
- Unique ID of a user/device, for possible future use.<br>
- <small>(e.g. used by Flickr import to know which accounts to look at)</small>
- <input type="text" name="id" />
- </dd>
-
- <dt>subject</dt>
- <dd>
- <em>Required</em>. Subject of problem report.
- <input type="text" name="subject" />
- </dd>
-
- <dt>detail</dt>
- <dd>
- Main body and details of problem report.
- <input type="text" name="detail" />
- </dd>
-
- <dt>name</dt>
- <dd>
- <em>Required</em>. Name of problem reporter.
- <input type="text" name="name" />
- </dd>
-
- <dt>email</dt>
- <dd>
- <em>Required</em>. Email address of problem reporter.
- <input type="text" name="email" />
- </dd>
-
- <dt>phone</dt>
- <dd>
- Telephone number of problem reporter.
- <input type="text" name="phone" />
- </dd>
-
- <dt>easting / northing</dt>
- <dt>lat / lon</dt>
- <dd>
- Location of problem report. You can either supply eastings/northings, or WGS84 latitude/longitude.
- <input type="text" name="easting" />
- <input type="text" name="northing" />
- <input type="text" name="lat" />
- <input type="text" name="lon" />
- </dd>
-
- <dt>photo</dt>
- <dd>
- Photo of problem (JPEG only).
- <input type="file" name="photo" />
- </dd>
-</dl>
-
-<input type="submit" />
-
-</form>
-
-[% INCLUDE 'footer.html' %] \ No newline at end of file
diff --git a/templates/web/fixmystreet/report/updates-sidebar-notes.html b/templates/web/fixmystreet/report/updates-sidebar-notes.html
new file mode 100644
index 000000000..7dd6a235c
--- /dev/null
+++ b/templates/web/fixmystreet/report/updates-sidebar-notes.html
@@ -0,0 +1,5 @@
+ <p>
+ [% IF problem.council != '2482' OR problem.send_method_used != 'Open311' %]
+ [% loc( 'Please note that updates are not sent to the council.' ) %]
+ [% END %]
+ [% loc( 'Your information will only be used in accordance with our <a href="/faq#privacy">privacy policy</a>' ) %]</p>
diff --git a/templates/web/fixmystreet/static/for_councils.html b/templates/web/fixmystreet/static/for_councils.html
deleted file mode 100644
index 1e1789df7..000000000
--- a/templates/web/fixmystreet/static/for_councils.html
+++ /dev/null
@@ -1,44 +0,0 @@
-[% INCLUDE 'header.html', title = loc('FixMyStreet for Councils'), bodyclass = 'twothirdswidthpage' %]
-
-<div class="sticky-sidebar">
- <aside>
- <ul class="plain-list">
- <li><strong>FixMyStreet for Councils</strong></li>
- <li>Summary</li>
- <li><a href="/for-councils/faq">Questions and Answers</a></li>
- <li><i>Email us at <a href="mailto:hello&#64;mysociety.org">hello&#64;mysociety.org</a></i></li>
- </ul>
- </aside>
-</div>
-
-<h1>Shift your problem reporting online: FixMyStreet for Councils</h1>
-
-<p>Councils everywhere are looking to move street issue reporting online, to make
-savings and improve services for their residents. <strong>FixMyStreet for
-Councils</strong> is explicitly designed to support the shift to digital.
-
-<p>FixMyStreet is the most popular online street issue reporting application in
-the UK. It’s known for prioritising usability and accessibility &ndash; and people
-love to use it. With very little cost and effort, your staff and your website’s
-users can enjoy its simple yet powerful features.
-
-<p>Embedding FixMyStreet in your council’s website is simple. As a cloud-based
-service, it requires no development work from your team. We will match your
-site’s look and feel seamlessly, and provide robust technical support and free
-training to council users. We also offer a mobile web version of the product
-as well as iPhone and Android apps branded for councils.
-
-<p>We can also integrate FixMyStreet with your CRM or customer management system,
-to ensure automatic two-way updates, saving you even more time and money.
-
-<img src="/cobrands/fixmystreet/barnet.png" alt="" style="float: right; padding: 0.25em; border: solid 1px #ccc; margin: 1em;">
-
-<p>mySociety, the non-profit behind FixMyStreet, is a software provider to over
-forty local authorities in the UK. We understand the challenges that councils
-face in channel shift, and will bring our passion and expertise to support your
-journey.
-
-<p>Have questions? Read our <a href="/for-councils/faq">Questions and Answers for Councils</a>
-or get in touch at <a href="mailto:hello&#64;mysociety.org">hello&#64;mysociety.org</a>.
-
-[% INCLUDE 'footer.html' pagefooter = 'yes' %]
diff --git a/templates/web/fixmystreet/static/for_councils_faq.html b/templates/web/fixmystreet/static/for_councils_faq.html
deleted file mode 100644
index d45166ed1..000000000
--- a/templates/web/fixmystreet/static/for_councils_faq.html
+++ /dev/null
@@ -1,366 +0,0 @@
-[% INCLUDE 'header.html', title = loc('Questions and Answers :: FixMyStreet for Councils'), bodyclass = 'twothirdswidthpage' %]
-
-<div class="sticky-sidebar">
- <aside>
- <ul class="plain-list">
- <li><strong>FixMyStreet for Councils</strong></li>
- <li><a href="/for-councils">Summary</a></li>
- <li>Questions and Answers <ul>
- <li><a href="#general">General information</a></li>
- <li><a href="#implementing">Implementing FixMyStreet for Councils</a></li>
- <li><a href="#reporting">Problem reporting</a></li>
- <li><a href="#best">Getting the best out of FixMyStreet</a></li>
- </ul> </li>
- <li><i>Email us at <a href="mailto:hello&#64;mysociety.org">hello&#64;mysociety.org</a></i></li>
- </ul>
- </aside>
-</div>
-
-<h1>Questions about FixMyStreet for Councils</h1>
-
-<h2 id="general">General information</h2>
-
-<dl>
-
-<dt>What is FixMyStreet For Councils?</dt>
-
-<dd>
-<p>FixMyStreet is a street issue-reporting and mapping application
-designed specifically for local authority websites.
-
-<p>It integrates seamlessly with council websites, fully reflecting their look
-and feel. All copy, categories, information, reporting fields and links can be
-customised to the specific needs of the council. FixMyStreet can also be
-connected to a CRM or fault management system for automatic two-way updates.
-
-<p>The software is open source and is based on mySociety’s award-winning
-FixMyStreet.com platform, which has been operating for five years. It is the
-most widely-used street issue web application in the UK, sending over 5,000
-reports to local authorities each month.
-</dd>
-
-<dt>Who built it?</dt>
-
-<dd>
-FixMyStreet for Councils was built by mySociety Ltd, a company registered in
-England and Wales, company number 03277032. mySociety Ltd is wholly owned by
-the charity UK Citizens Online Democracy (charity number 1076346). All profits
-are returned to the charity.
-</dd>
-
-<dt>What are the benefits for councils?</dt>
-
-<dd>
-<p>FixMyStreet for Councils will save you and your residents time. It will reduce duplicate reports and encourage the shift of street issue reporting to the web.
-
-<p>It also places a highly usable, attractive application on your website, and a very simple channel for responding to your residents if you wish to do so.
-
-<p>Most councils get a high volume of telephone calls to report street issues - by moving even a small proportion of that online, you can make significant savings over time.
-</dd>
-
-<dt>Why is FixMyStreet more effective than standard reporting forms?</dt>
-
-<dd>
-<p>As a rule, people do not enjoy filling in onerous forms on the web. They
-often span several pages and require a lot of personal information &ndash; so many
-people resort to calling instead.
-
-<p>Reporting on FixMyStreet is extremely simple and quick. The user pinpoints
-the location of the problem on a map, provides a description and a photo if
-they have one, and their email address. You’ll receive the email address with
-the problem report, so your officers can get in touch if they need to.
-
-<p>Using a map as a way to locate an issue is very useful &ndash; people often don’t
-know the exact nearest address, but they can show where it is on a map.
-
-<p>Finally, FixMyStreet allows you to comment on a report or update its status
-&ndash; your update will be available for everyone interested to see on the website,
-further reducing avoidable contact.
-</dd>
-
-<dt>What is the difference between FixMyStreet.com and FixMyStreet for Councils?</dt>
-
-<dd>
-<p>FixMyStreet.com is a national street issue reporting website that enables
-anyone anywhere in Great Britain to report a problem to their council. The
-reports are delivered to councils by email.
-
-<p>FixMyStreet for Councils is a product for council websites to enable their
-residents to report issues to them. It becomes a natural part of the council’s
-site, can be included in the list of top tasks, integrates council-relevant
-information, and can be linked with council’s backoffice.
-
-<p>It uses the same software platform as the FixMyStreet.com site; issues
-reported to a council on its own website are also shown on FixMyStreet.com, and
-vice-versa. Read the Implementation FAQ above to learn why this approach really
-works.
-
-</dd>
-
-<dt>Which councils already have FixMyStreet?</dt>
-
-<dd>
-The London Borough of Bromley will soon be launching our upgraded FixMyStreet
-for Councils product. For existing implementations, have a look at the
-<a href="http://barnet.fixmystreet.com/">London Borough of Barnet’s website</a>
-or <a href="http://southampton.fixmystreet.com/">Southampton City Council’s
-website</a>. Meanwhile, West Berkshire Council is an example of a back-office
-integration - they receive problems reported on FixMyStreet directly into their
-CRM.
-</dd>
-
-<dt>Is there a mobile version of the FixMyStreet for Councils product?</dt>
-
-<dd>
-<p>As more and more people use their smartphones for online tasks, we make it
-easy for councils to enable mobile street issue reporting. We offer two
-products:
-<ul>
-<li>A mobile web version of FixMyStreet &ndash; this presents users with a
-mobile-optimised version of a council FixMyStreet web app, and enables mobile
-reporting by simply entering a URL of the council’s web reporting page in their
-mobile browser
-<li>Mobile Apps - some users do prefer to use downlodable apps, so we are
-currently developing iPhone and Android Apps with the capability to include
-council branding. If you are interested, <a
-href="mailto:hello&#64;mysociety.org">let us know</a>.
-</ul>
-</dd>
-
-<dt>What is the cost to councils?</dt>
-
-<dd>
-<ul>
-<li>The front end product costs £3,500 in year one, reducing to £2,000 per annum in future years.
-<li>Web and mobile-optimised site together cost £5,500 in year one and £3,000 per annum subsequently.
-<li>Web, mobile-optimised site, and iPhone and Android apps cost £9,500 in year one, then £4,000 per annum.
-</ul>
-
-<p>We also offer fixed price for integration with Microsoft, Oracle and
-Lagan CRM systems, at £5,500 in year one, then £2,000 per annum
-thereafter. Integration with other CRM or back-office systems costs
-£6,500 in year one,
-
-<p>These prices exclude VAT and assume standard FixMyStreet for councils
-product - if you need further customisations please get in touch with
-us for a quote.
-
-<p>The prices are all-inclusive, covering installation, updates, unlimited
-problem reports and user training. There are no hidden fees.
-
-<p>There’s no commitment beyond the first 12 months, so you won’t be locked
-into a lengthy contract.
-
-</dl>
-<h2 id="implementing">Implementing FixMyStreet for Councils</h2>
-<dl>
-
-<dt>How easy is it to implement FixMyStreet on a council website?</dt>
-
-<dd>
-Extremely easy. Because we run FixMyStreet as a cloud service, all you need to do is to provide details of your website’s colour scheme, fonts, and any customised links or information you’d like to include. We will do all the work in setting up your issue reporting application. The implementation can take as little as a week, and requires minimal work from your web team.
-</dd>
-
-<dt>Can we integrate FixMyStreet with the council’s CRM or fault management system?</dt>
-
-<dd>
-<p>Absolutely. Integrating with your back-office system ensures maximum efficiencies - all reports go straight into your database. When their status changes, updates can be automatically pushed out onto your website as well as to FixMyStreet.com. We are able to integrate with any back-office system.
-
-<p>We understand that each council has its own processes which have evolved over time. We will work with you to find the best integration solution to ensure minimum disruption to your work, while helping make your processes simpler and more streamlined.
-
-<p>If you’d like us to advise on the best integration options for you, get in touch. Our advice is completely free - we are always keen to talk to councils and learn about your needs.
-</dd>
-
-<dt>What is the technical architecture of FixMyStreet?</dt>
-
-<dd>
-<p>FixMyStreet for councils uses the same <a
-href="https://github.com/mysociety/fixmystreet">open source code base</a> and
-runs on the same servers as the national FixMyStreet site. At the same time it
-has been designed to allow customisation of both design and functionality.
-Using the URL of the site visited the code determines which version of
-FixMyStreet to display and loads the appropriate design and customisations.
-
-<p>If you have back end integration then new reports to your council will be
-sent to your CRM through the agreed mechanism ( e.g. Open311 ). If we cannot
-send a report to you then it will be put back on the queue and we will try
-again later so you won’t miss any reports.
-</dd>
-
-<dt>Why is linking FixMyStreet for Councils with the national FixMyStreet.com website a good idea?</dt>
-
-<dd>
-
-<p>There are three key benefits. First, by using the same underlying platform we can spread the cost of maintaining and hosting the system across the national site and different council users. This helps to keep prices low. Plus, we carry out all the technical maintenance and support, so you don’t need to.
-
-<p>Second, issues reported on FixMyStreet.com are also shown on your Council’s website, avoiding duplicate reports by different residents.
-
-<p>Third, the customised features on your own FixMyStreet (such as categories, information you gather from customers, additional details on issues the council is not responsible for, etc) will also be reflected on FixMyStreet.com. So wherever your residents report issues, they will get the right features and information from the council.
-</dd>
-
-<dt>Do you offer training?</dt>
-
-<dd>
-Yes. We offer a free two-hour remote training session to your users. If your location is within two hours’ travel from one of our FixMyStreet team members, we will provide training in person.
-</dd>
-
-<dt>What level of support do you provide after implementation?</dt>
-
-<dd>
-<p>We will provide technical support, address any questions, and make tweaks to your system if required. We will also go out of our way to help you with non-technical issues based on our significant experience with online problem reporting.
-
-<p>Throughout our contract with you, we will always be available by email or on the phone, and will get back to you quickly.
-
-</dl>
-<h2 id="reporting">Problem reporting</h2>
-<dl>
-
-<dt>Can we customise report categories and information requested?</dt>
-
-<dd>
-<p>Yes. You can add the categories most relevant to your council, and remove ones that are not. Your customised categories will appear on both your website’s FixMyStreet implementation, and on the national FixMystreet.com website.
-
-<p>You can also customise information requested for each issue type - for example, Southampton council asks its customers to report the approximate pothole size, to help prioritise its work.
-</dd>
-
-<dt>How can we deal with issues that the council is not responsible for?</dt>
-
-<dd>
-Most councils already get residents phoning up or emailing them about problems not within their remit. FixMyStreet can help reduce this in two ways:
-We can include the most commonly misreported issues in the categories list so when a users selects these, we can give them alternative contact information. If there are known geographical areas that council is not responsible for, we can alert users to that when they click on the map, provided you have given us this information.
-Alternatively, if you have contact details in relevant organisations, we can instead email reports to them, while telling the user that these are not the council’s responsibility.
-</dd>
-
-<dt>How are reports delivered to the council?</dt>
-
-<dd>
-<p>If your FixMyStreet is not integrated with your CRM or back-office system, you will receive reports by email to email addresses that you specify. Different type of problems can be sent to different addresses if you wish.
-
-<p>With back-office integration, reports will go straight into your CRM or fault management system.
-</dd>
-
-<dt>What information is provided in a problem report?</dt>
-
-<dd>
-<p>You will receive the following information:
-<ul>
-<li>Issue category
-<li>Precise location reported (in both latitude/longitude and easting/northing)
-<li>Subject and issue description (we encourage users to give as much detail as possible)
-<li>Link to a photo of the problem if the user has added one (we don’t send the actual photos so that we don’t clog your system)
-<li>The user’s verified email address and phone number if given, so you can contact them directly if you wish
-<li>A link to the issue on FixMyStreet for you to update the issue if required.
-</ul>
-</dd>
-
-<dt>How precise is location information provided in FixMyStreet?</dt>
-
-<dd>
-<p>Very. The user clicks on a map that includes useful information for
-reporting, such as building positions and footpaths, so they can tell you the
-location as precisely as they can.
-
-<p>This approach also helps capture superior location data even when the user
-does not know the exact address.
-
-<p>We will send you the co-ordinates for the point clicked on the map, as well
-as the nearest street address as an additional data point. You can also view
-the map directly on the issue report page.
-</dd>
-
-<dt>Can we reflect more granular report statuses than just open and fixed?</dt>
-
-<dd>
-Yes. As a client council you get a selection of problem statuses, including:
-Investigating, Planned, In Progress, Fixed and Closed.
-</dd>
-
-</dl>
-<h2 id="best">Getting the best out of FixMyStreet</h2>
-<dl>
-
-<dt>Can we add photos showing that council has dealt with an issue?</dt>
-
-<dd>
-Yes - you can easily post a photo as an update to a report on your website. These will also be shown on the national FixMyStreet.com site.
-</dd>
-
-<dt>What can we do to help shift users to online reporting instead of calling us up?</dt>
-
-<dd>
-Online reporting is better for you and your residents, as it’s quick, effective and cheap. Good technology will certainly encourage the shift, but to make it fully effective you could do a a few things to help.
-Direct residents to report issues on your website when they are in the telephone queue
-When someone reports an issue to your call centre, tell them that next time they can do it much quicker online
-Encourage council employees or other relevant organisations to report issues online
-Respond to problem reports online, so that your residents know you engage well through this channel.
-</dd>
-
-<dt>How can a council respond to issue reports?</dt>
-
-<dd>
-<p>If you choose the back-office integration option, when an issue status
-changes in your CRM or fault management system, it can also automatically
-update on both your website and the national FixMyStreet website. This assumes
-that your system can support automatic updates (most systems can).
-
-<p>If your back-office is not integrated, you can still easily respond by
-changing the status manually on the website, or adding a few words of
-commentary. This simple process is much quicker than a telephone call or email.
-</dd>
-
-<dt>How can we contact the person submitting the report if we need more information?</dt>
-
-<dd>
-Our software encourages users to submit as much information as possible, along with photographs. If you do need additional details, you can either post your question as an update to the issue online, or email the user directly (you will get their email address with the issue report).
-</dd>
-
-<dt>We are unable to fix every problem, in particular in the current budget environment. How do we deal with this?</dt>
-
-<dd>
-<p>Whether reported online or not, there are some issues that a council will
-decide not to fix because it needs to prioritise more important problems.
-
-<p>Our online reporting application gives you a direct channel to explain to
-your residents why certain problems cannot be addressed. This will lead to a
-more open, constructive relationship. This may be a big culture change - we are
-happy to support you with our experience in this area.
-
-<p>When deciding not to deal with a problem, you can close it so that it does
-not show as an open problem.
-</dd>
-
-<dt>We are worried about being swamped with high volume of online reports. What can we do?</dt>
-
-<dd>
-While the volume of online reporting is likely to increase (a good thing, as it
-replaces phone calls and alerts you to issues you didn’t know about), it
-usually happens gradually, giving you plenty of time to adjust. We can stage
-the introduction of your new reporting app to make the process even smoother.
-</dd>
-
-<dt>Does FixMyStreet for Councils offer reporting functionality?</dt>
-
-<dd>
-<p>We are currently working on a new reporting dashboard for councils,
-accessible through a separate council log-in. This will have detailed reporting
-on issue categories, timelines, statuses and help you identify emerging
-hotspots.
-
-<p>Any new council implementation from April 2012 will have this new
-functionality. Please get in touch if you’d like more detail.
-</dd>
-
-<dt>I’d like to discuss options for my council. What do I do?</dt>
-
-<dd>
-<p>Just drop us a line to <a
-href="mailto:hello&#64;mysociety.org">hello&#64;mysociety.org</a> and we will get back
-to you as soon as possible.
-
-<p>We will be happy to advise you on the options, and recommend an
-implementation approach to fit your needs based on our experience.
-</dd>
-
-</dl>
-
-[% INCLUDE 'footer.html' pagefooter = 'yes' %]
diff --git a/web/cobrands/barnet/_colours.scss b/web/cobrands/barnet/_colours.scss
new file mode 100644
index 000000000..2f5ccc42b
--- /dev/null
+++ b/web/cobrands/barnet/_colours.scss
@@ -0,0 +1,9 @@
+/* COLOURS */
+
+$primary: #E9E9EA;
+$primary_b: #000000;
+$primary_text: #3E3D44;
+
+$contrast1: #E1E3E4;
+$contrast1_dark: darken(#E1E3E4, 10%);
+$contrast2: #AA8D11;
diff --git a/web/cobrands/barnet/barnet.scss b/web/cobrands/barnet/barnet.scss
new file mode 100644
index 000000000..a6feb018f
--- /dev/null
+++ b/web/cobrands/barnet/barnet.scss
@@ -0,0 +1,115 @@
+/* Parts of barnet's main CSS needed for its header/footer and adjusted (see
+ * bottom) to not be affected by main FixMyStreet CSS. Not very sustainable;
+ * perhaps we should wrap all council CSS within a SCSS #council ID? Hmm.
+ */
+
+@import "compass";
+
+#column_nav li { list-style: none ;}
+
+#content ol.big-numbers li {
+ padding: 0 0 0 2.5em;
+}
+
+#barnet-wrapper {
+ width: 100%;
+ display: table;
+ caption-side: bottom;
+}
+
+#barnet-powered-by {
+ clear: both;
+}
+
+body {font-size: 75%; font-family: Arial, Helvetica, sans-serif; color: #3e3d44; padding: 0; margin: 0; line-height: 1.5; background: #e9e9ea;}
+body > html {font-size: 12px;}
+
+#barnet-wrapper {padding: 0; margin: 20px auto; width: 960px; background: #fff;}
+#ie_wrapper {display: block; padding: 20px 25px 25px;}
+#page {float: left; width: 100%;}
+
+#mast {clear: both;}
+
+#mast .pseudoH1 {margin: 0 0 0 -3px; padding: 0; background: url(img/barnet-logo.gif) no-repeat top left; width: 240px; height: 38px; float: left;}
+#mast .pseudoH1 a, #mast .pseudoH1 a:link, #mast .pseudoH1 a:visited, #mast .pseudoH1 a:hover, #mast .pseudoH1 a:active {display: block; width: 240px; height: 38px; padding: 0; background: url(img/barnet-logo.gif) no-repeat top left;}
+#mast .pseudoH1 span {position: absolute; margin-top: -13000px; top: -13000px;}
+
+#mast .mast_links {float: right; display: inline; margin: 0; padding: 10px 0 0; list-style: none; overflow: hidden;}
+
+#mast #search {clear: both; float: right; margin: 8px 0 0; background: #e1e3e4; border-top: 6px solid #bddadc; border-bottom: 2px solid #c8cacb; width: 100%; padding: 3px 0 2px; height: 21px;}
+
+/* ############################################################## */
+
+#content {margin: 0; width: 910px; overflow: hidden; min-height: 350px;}
+#content.withWidth {margin: 0 0 0 232px; width: 446px; overflow: hidden; float: left; display: inline;}
+#content.fullWidth {width: 678px;}
+#content.home {margin-top: 18px;}
+
+.mappage {
+ #content.withWidth {margin: 0 0 0 0px; width: auto; overflow: hidden; float: left; display: inline;}
+ #content.fullWidth {width: 900px;}
+}
+
+/* IE6 ignore the second #foo.bar rule so we have to fudge it another way */
+.ie6 {
+ .mappage {
+ #content {
+ margin: 0 0 0 0px;
+ overflow: hidden;
+ float: left;
+ display: inline;
+ width: 900px;
+ }
+ }
+}
+
+#breadcrumb {font-size: .9em; color: #5c6267; padding: 6px 0; margin: 0 0 0 232px;}
+#breadcrumb.full {margin: 0;}
+#breadcrumb ul {margin: 0; padding: 0; list-style: none;}
+#breadcrumb ul li {margin: 0; padding: 0 4px 0 0; display: inline;}
+#breadcrumb ul li a:link, #breadcrumb ul li a:visited, #breadcrumb ul li a:hover, #breadcrumb ul li a:active {color: #5c6267; background: url(img/bcArrow.gif) no-repeat right center; padding: 0 10px 0 0; font-weight: normal;}
+#breadcrumb ul li span {font-weight: normal; color: #5c6267;}
+
+/* ############################################################## */
+
+#column_nav {width: 214px; float: left; display: inline; padding: 0; margin: -35px 0 0 -910px; border-right: 3px solid #fff;}
+
+.ie6 #column_nav {
+ float: none;
+ position: absolute;
+ top: 85px;
+ margin: 0 0 0 0px;
+}
+
+body.mappage #column_nav { display: none; }
+
+#content h1 {margin: 0 0 20px; font-size: 1.8em; border-bottom: 6px solid #bed9dd; font-family: Georgia, Times, 'Times New Roman', serif; color: #5d6167;}
+#content h1 span {padding: 6px 7px 3px; border: 1px solid #eff1f2; border-bottom: 0 none; display: block;}
+#content h1#reports_heading span { display: none; }
+
+#column_nav .navigation {background: #fff; margin: 0 0 4px;}
+#column_nav h2 {font-size: 1.2em; padding: 0; height: 29px; margin: 0; border-radius: 0 0 3px 3px; background: url(img/nav-bg-active.gif) left bottom repeat-x; border-top: 6px solid #bddadc;}
+#column_nav #nav1 h2 {border-radius: 0 0 0 3px;}
+#column_nav h2 a {color: #fff; padding: 3px 10px 0 26px; display: block; background: url(img/nav-arrow.gif) 8px 7px no-repeat;}
+#column_nav .active h2 a {background: url(img/nav-arrow-active.gif) 8px 8px no-repeat;}
+#column_nav ul {margin: 0 0 0 4px; padding: 8px 7px 4px; border-width: 0 1px 1px; border-color: #e1e1e1; border-style: solid; border-radius: 3px; list-style: none; background: #fff; background: -moz-linear-gradient(top, #ffffff 0%, #f7f9f8 100%); background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#ffffff), color-stop(100%,#f7f9f8)); background: -webkit-linear-gradient(top, #ffffff 0%,#f7f9f8 100%); background: -o-linear-gradient(top, #ffffff 0%,#f7f9f8 100%); background: -ms-linear-gradient(top, #ffffff 0%,#f7f9f8 100%); background: linear-gradient(top, #ffffff 0%,#f7f9f8 100%); filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#f7f9f8',GradientType=0);}
+#column_nav ul li {margin: 0; padding: 2px 4px; border-bottom: 1px solid #bfc0c1; color: #333; font-size: .9em;}
+#column_nav ul li.lastItem {border-bottom: none;}
+#column_nav ul li a:link, #column_nav ul li a:visited, #column_nav ul li a:hover, #column_nav ul li a:active {display: block; color: #333; font-weight: normal;}
+#column_nav ul li a:hover, #column_nav ul li a:active {text-decoration: none; color: #0090a2;}
+
+/* ############################################################## */
+
+#footer {clear: both; margin: 10px 0 0; padding: 15px 0 0; text-align: left;}
+#footer p {border-top: 1px solid #dadadb; border-bottom: 1px solid #dadadb; margin: 0 0 5px; color: #5d6167; float: left; display: inline; height: 24px; padding: 8px 0 2px; width: 551px;}
+#footer p a {color: #5d6167; font-weight: normal; padding: 0 2px;}
+#footer p.assocLinks {float: right; display: inline; padding: 5px 0; width: 359px;}
+#footer p.assocLinks a {float: left; display: inline; margin: 0 0 0 8px; padding: 0; background-position: center top; background-repeat: no-repeat; width: 24px; height: 24px;}
+#footer p.assocLinks a:active, #footer p.assocLinks a:hover, #footer p.assocLinks a:focus {background-position: center bottom;}
+#footer a#goto_browsealoud {background-image: url(img/browsealoud.gif); width: 95px; height: 25px; margin-top: 1px;}
+#footer a#goto_directgov {background-image: url(img/directgov.gif); width: 90px; margin: 0 0 0 22px;}
+#footer a#share_facebook {background-image: url(img/social1-facebook.gif); margin: 0 0 0 24px;}
+#footer a#share_twitter {background-image: url(img/social2-twitter.gif);}
+#footer a#share_youtube {background-image: url(img/social3-youtube.gif);}
+#footer a#share_flickr {background-image: url(img/social4-flickr.gif);}
+#bottomBar {background: url(img/barnet-footer-logo.gif) 771px 12px no-repeat #21aaaa; display: block; width: 100%; height: 56px; border-top: 6px solid #bddadc;}
diff --git a/web/cobrands/barnet/base.scss b/web/cobrands/barnet/base.scss
new file mode 100644
index 000000000..0447c6779
--- /dev/null
+++ b/web/cobrands/barnet/base.scss
@@ -0,0 +1,39 @@
+@import "../fixmystreet/_h5bp";
+@import "./_colours";
+@import "../fixmystreet/_mixins";
+@import "compass";
+
+@import "../fixmystreet/_base";
+
+#mast,
+#breadcrumb,
+#page-title,
+#column_nav,
+#footer,
+#bottomBar
+{ display: none }
+
+#site-header{
+ @include background(none);
+ background-color: white;
+}
+#site-logo {
+ width: 235px;
+ background: url('/cobrands/barnet/img/barnet-logo.gif') -3px -3px no-repeat;
+}
+#nav-link {
+ right: 1em;
+ background: url('/cobrands/barnet/img/barnet-skipnav.png') no-repeat;
+}
+
+#front-main #postcodeForm div input#submit,
+.green-btn,
+button.green-btn,
+input.green-btn,
+.red-btn,
+button.red-btn,
+input.red-btn{
+ @include button-reset;
+ background: #5D6167;
+ color: white;
+}
diff --git a/web/cobrands/barnet/config.rb b/web/cobrands/barnet/config.rb
new file mode 100644
index 000000000..cab97b18f
--- /dev/null
+++ b/web/cobrands/barnet/config.rb
@@ -0,0 +1,25 @@
+# Require any additional compass plugins here.
+
+# Set this to the root of your project when deployed:
+http_path = "/"
+css_dir = ""
+sass_dir = ""
+images_dir = ""
+javascripts_dir = ""
+
+# You can select your preferred output style here (can be overridden via the command line):
+# output_style = :expanded or :nested or :compact or :compressed
+
+# To enable relative paths to assets via compass helper functions. Uncomment:
+# relative_assets = true
+
+# To disable debugging comments that display the original location of your selectors. Uncomment:
+# line_comments = false
+
+# If you prefer the indented syntax, you might want to regenerate this
+# project again passing --syntax sass, or you can uncomment this:
+# preferred_syntax = :sass
+# and then run:
+# sass-convert -R --from scss --to sass sass scss && rm -rf sass && mv scss sass
+
+line_comments = false # by Compass.app
diff --git a/web/cobrands/barnet/img/barnet-footer-logo.gif b/web/cobrands/barnet/img/barnet-footer-logo.gif
new file mode 100644
index 000000000..afba1cca2
--- /dev/null
+++ b/web/cobrands/barnet/img/barnet-footer-logo.gif
Binary files differ
diff --git a/web/cobrands/barnet/img/barnet-logo.gif b/web/cobrands/barnet/img/barnet-logo.gif
new file mode 100644
index 000000000..86e0f4ee8
--- /dev/null
+++ b/web/cobrands/barnet/img/barnet-logo.gif
Binary files differ
diff --git a/web/cobrands/barnet/img/barnet-skipnav.png b/web/cobrands/barnet/img/barnet-skipnav.png
new file mode 100644
index 000000000..21efe0f67
--- /dev/null
+++ b/web/cobrands/barnet/img/barnet-skipnav.png
Binary files differ
diff --git a/web/cobrands/barnet/img/bcArrow.gif b/web/cobrands/barnet/img/bcArrow.gif
new file mode 100644
index 000000000..4e7c1848e
--- /dev/null
+++ b/web/cobrands/barnet/img/bcArrow.gif
Binary files differ
diff --git a/web/cobrands/barnet/img/browsealoud.gif b/web/cobrands/barnet/img/browsealoud.gif
new file mode 100644
index 000000000..4fbb3eded
--- /dev/null
+++ b/web/cobrands/barnet/img/browsealoud.gif
Binary files differ
diff --git a/web/cobrands/barnet/img/directgov.gif b/web/cobrands/barnet/img/directgov.gif
new file mode 100644
index 000000000..1c9dd22e2
--- /dev/null
+++ b/web/cobrands/barnet/img/directgov.gif
Binary files differ
diff --git a/web/cobrands/barnet/img/fms-logo.png b/web/cobrands/barnet/img/fms-logo.png
new file mode 100644
index 000000000..23bea6b0f
--- /dev/null
+++ b/web/cobrands/barnet/img/fms-logo.png
Binary files differ
diff --git a/web/cobrands/barnet/img/nav-arrow-active.gif b/web/cobrands/barnet/img/nav-arrow-active.gif
new file mode 100644
index 000000000..89ff9d0b3
--- /dev/null
+++ b/web/cobrands/barnet/img/nav-arrow-active.gif
Binary files differ
diff --git a/web/cobrands/barnet/img/nav-bg-active.gif b/web/cobrands/barnet/img/nav-bg-active.gif
new file mode 100644
index 000000000..0d2ec9873
--- /dev/null
+++ b/web/cobrands/barnet/img/nav-bg-active.gif
Binary files differ
diff --git a/web/cobrands/barnet/img/social1-facebook.gif b/web/cobrands/barnet/img/social1-facebook.gif
new file mode 100644
index 000000000..41b404df0
--- /dev/null
+++ b/web/cobrands/barnet/img/social1-facebook.gif
Binary files differ
diff --git a/web/cobrands/barnet/img/social2-twitter.gif b/web/cobrands/barnet/img/social2-twitter.gif
new file mode 100644
index 000000000..17f368536
--- /dev/null
+++ b/web/cobrands/barnet/img/social2-twitter.gif
Binary files differ
diff --git a/web/cobrands/barnet/img/social3-youtube.gif b/web/cobrands/barnet/img/social3-youtube.gif
new file mode 100644
index 000000000..eeb6ba356
--- /dev/null
+++ b/web/cobrands/barnet/img/social3-youtube.gif
Binary files differ
diff --git a/web/cobrands/barnet/img/social4-flickr.gif b/web/cobrands/barnet/img/social4-flickr.gif
new file mode 100644
index 000000000..300e75da0
--- /dev/null
+++ b/web/cobrands/barnet/img/social4-flickr.gif
Binary files differ
diff --git a/web/cobrands/barnet/layout.scss b/web/cobrands/barnet/layout.scss
new file mode 100644
index 000000000..97b27cfff
--- /dev/null
+++ b/web/cobrands/barnet/layout.scss
@@ -0,0 +1,260 @@
+@import "_colours";
+@import "../fixmystreet/_layout";
+
+#mast,
+#breadcrumb,
+#page-title,
+#column_nav,
+#footer,
+#bottomBar {
+ display: block;
+}
+
+// So that map appears underneath the header
+.wrapper {
+ position: relative;
+}
+.ie6, .ie7 {
+ .wrapper {
+ padding-top: 1em;
+ }
+}
+
+#front-main {
+ background: $primary;
+ @include border-radius(1em 1em 0 0);
+ margin-bottom: 1em;
+ padding-top: 0;
+ width: 678px;
+ // layout sets this because base has it slightly lighter
+ h2 {
+ color: $primary_text;
+ }
+ #front-main-container {
+ padding: 1em;
+ }
+}
+
+#front_intro {
+ float: left;
+ margin-right: 3em;
+}
+
+#front_recent {
+ margin-left: 3em;
+}
+
+body.fullwidthpage {
+ .content {
+ width: 52em;
+ }
+}
+.ie6 {
+ body.fullwidthpage {
+ #front-main {
+ margin-top: -4em;
+ }
+ #front-howto,
+ #front-recently {
+ width: 26em;
+ }
+ .container {
+ padding: 0;
+ }
+ .content {
+ margin-left: 0px;
+ width: 55em;
+ }
+ div.img {
+ margin-top: -3.3em;
+ }
+ }
+}
+
+body.twothirdswidthpage {
+ .content {
+ @include box-shadow(none);
+ width: 640px;
+ margin-top: 0;
+ .sticky-sidebar {
+ display: none;
+ aside {
+ top: 25em;
+ }
+ }
+ }
+}
+
+.nav-wrapper {
+ display: none;
+}
+
+.mappage {
+ #breadcrumb {
+ margin-left: 0px;
+ }
+}
+
+.frontpage .content {
+ margin: 0;
+ @include box-shadow(none);
+}
+.ie6, .ie7, .ie8 {
+ .frontpage .content {
+ border: none;
+ }
+}
+
+#content .container h1 {
+ border-bottom: none;
+ font-size: 2em;
+ margin-bottom: 0.5em;
+}
+
+.shadow-wrap {
+ position: static;
+ padding-top: 0;
+ margin-bottom: 1em;
+ ul#key-tools {
+ border-top: none;
+ border-bottom: 1px solid $primary;
+ li {
+ a.chevron {
+ background-position: right -3230px;
+ }
+ a.feed {
+ background-position: right -3080px;
+ }
+ a.abuse {
+ background-position: right -2940px;
+ }
+ }
+ }
+ ul#key-tools.singleton {
+ li a {
+ padding-right: 4em;
+ }
+ }
+}
+
+#content h1.big-green-banner {
+ font-size: 1.4em;
+ margin-left: -2em;
+ background: #e1e3e4 url(/cobrands/fixmystreet/images/sprite.png) right -2192px no-repeat
+}
+
+body.frontpage {
+ #user-meta {
+ p {
+ top: 1em;
+ color: $primary_text;
+ a {
+ background: none;
+ }
+ }
+ }
+}
+#user-meta {
+ float: right;
+ p {
+ @include box-shadow(none);
+ color: $primary_text;
+ position: relative;
+ background: none;
+ a {
+ color: $primary_text;
+ background: none;
+ }
+ a:hover {
+ background: $primary;
+ }
+ }
+}
+.ie6 {
+ #user-meta {
+ float: none;
+ p {
+ position: absolute;
+ margin-top: 35px;
+ margin-right: 20px;
+ right: 0px;
+ left: auto;
+ }
+
+ }
+ .mappage {
+ #user-meta {
+ p {
+ margin-right: -100px;
+ }
+ }
+ }
+}
+
+/* barnet styles */
+
+.clear {
+ clear: both;
+}
+
+.container {
+ padding: 0 1em;
+}
+
+#site-header,
+#site-logo {
+ display: none !important;
+}
+
+
+#report-a-problem-sidebar {
+ left: 30em;
+ top: 4em;
+ width: 17em;
+ .sidebar-tips,
+ .sidebar-notes {
+ font-size: 0.9em;
+ }
+}
+.ie6 {
+ #report-a-problem-sidebar {
+ margin-top: -4em;
+ left: 30em;
+ .sidebar-notes {
+ padding-bottom: 0.5em;
+ }
+ p {
+ margin-bottom: 0.4em;
+ }
+ }
+}
+
+
+.general-sidebar-notes {
+ left: 25em;
+ width: 14em;
+ font-size: 1.2em;
+ p {
+ margin-bottom: 0 !important;
+ }
+}
+
+#front-howto #front_stats div big,
+ol.big-numbers > li::before {
+ color: #C0E8E8;
+}
+
+.banner {
+ p {
+ top: -2em;
+ }
+ p#fixed {
+ padding-top: 4em;
+ background: #00BD08;
+ }
+}
+
+
+#map_box {
+ border: 1px solid black;
+}
diff --git a/web/cobrands/barnet/position_map.js b/web/cobrands/barnet/position_map.js
new file mode 100644
index 000000000..465d852ec
--- /dev/null
+++ b/web/cobrands/barnet/position_map.js
@@ -0,0 +1,25 @@
+function position_map_box() {
+ var map_pos = 'absolute', map_height = $('.wrapper').height();
+ // on the all reports page the height of the wrapper leads to a very
+ // large map so we set a maximum size
+ if ( map_height > 600 ) {
+ map_height = 600;
+ }
+ $('#map_box').prependTo('.wrapper').css({
+ zIndex: 0, position: map_pos,
+ top: 1, left: $('.wrapper').left,
+ right: 0, bottom: $('.wrapper').bottom + 1,
+ width: '898px', height: map_height,
+ margin: 0
+ });
+}
+
+function map_fix() {
+ var height = $('.wrapper').height() - 3;
+ if ( height > 600 ) {
+ height = 600;
+ }
+ $('#map_box').height(height);
+}
+
+var slide_wards_down = 1;
diff --git a/web/cobrands/bromley/_colours.scss b/web/cobrands/bromley/_colours.scss
index c0376274e..e178c9db2 100644
--- a/web/cobrands/bromley/_colours.scss
+++ b/web/cobrands/bromley/_colours.scss
@@ -1,8 +1,9 @@
/* COLOURS */
-$primary: rgb(76,120,168);
+$primary: rgb(91,120,147);
$primary_b: #000000;
$primary_text: #ffffff;
-$contrast1: #00BD08;
+$contrast1: rgb(91,120,147);
+$contrast1_dark: darken(rgb(91,120,147), 10%);
$contrast2: #AA8D11;
diff --git a/web/cobrands/bromley/base.scss b/web/cobrands/bromley/base.scss
index 4594f832f..9c5ff2b0f 100644
--- a/web/cobrands/bromley/base.scss
+++ b/web/cobrands/bromley/base.scss
@@ -5,3 +5,56 @@
@import "../fixmystreet/_base";
+a, a:visited {
+ color: #369;
+ &:hover, &:active {
+ color: #369;
+ }
+}
+
+h1.main {
+ color: $primary;
+ text-align: center;
+ margin: 0.5em 0;
+}
+
+// Want a white header, and logo is slightly bigger
+#site-header {
+ @include background(linear-gradient(#ddd, #fff 10%, #fff));
+ height: 4em;
+}
+
+// Colour tab to match colour scheme
+#nav-link {
+ width: 50px;
+ height: 48px;
+ background: url('/cobrands/bromley/tab-blue.png') 0 0 no-repeat;
+}
+
+// Change logo to logo of council
+#site-logo {
+ display: block;
+ width: 80px;
+ height: 44px;
+ top: 0.9em;
+ background: url('/cobrands/bromley/bromley-logo.s.jpg') 0 0 no-repeat;
+}
+
+#problems-nav {
+ border-bottom:0.25em solid $primary;
+ ul li a {
+ text-transform: none;
+ &.active {
+ background: $primary;
+ color: #fff;
+ }
+ }
+}
+
+.big-green-banner {
+ text-transform: none;
+}
+
+#form_sign_in {
+ margin-top: 1em;
+}
diff --git a/web/cobrands/bromley/bromley-logo.jpg b/web/cobrands/bromley/bromley-logo.jpg
new file mode 100644
index 000000000..28da8b7ea
--- /dev/null
+++ b/web/cobrands/bromley/bromley-logo.jpg
Binary files differ
diff --git a/web/cobrands/bromley/bromley-logo.s.jpg b/web/cobrands/bromley/bromley-logo.s.jpg
new file mode 100644
index 000000000..16f632848
--- /dev/null
+++ b/web/cobrands/bromley/bromley-logo.s.jpg
Binary files differ
diff --git a/web/cobrands/bromley/bromley.scss b/web/cobrands/bromley/bromley.scss
new file mode 100644
index 000000000..91ec75fea
--- /dev/null
+++ b/web/cobrands/bromley/bromley.scss
@@ -0,0 +1,110 @@
+/* Parts of Bromley's main CSS needed for its header/footer and adjusted (see
+ * bottom) to not be affected by main FixMyStreet CSS. Not very sustainable;
+ * perhaps we should wrap all council CSS within a SCSS #council ID? Hmm.
+ */
+
+@import "compass";
+
+// Bits of Bromley's forms.css, adjusted
+input[type=text],
+input[type=password],
+input[type=email],
+input[type=file],
+textarea,
+select { background: #fff; border: 1px solid #768b9a; border-color: #768b9a #d1dee8 #d1dee8 #768b9a; color: #333; font-family: Arial, 'Helvetica Neue', Helvetica, sans-serif; padding: 8px;
+@include border-radius(0); }
+
+.green-btn, button.green-btn, input.green-btn {
+ background: #5b7189 url("https://www.bromley.gov.uk/site/styles/css_img/button.gif") repeat-x 0 -1px; border: 1px solid #8e9eb0; color: #fff; font-family: 'Gill Sans', 'Trebuchet MS', Calibri, sans-serif; font-weight: normal; margin: 0; min-height: 23px; outline: 1px solid #405062; padding: 4px 8px; text-transform: uppercase; }
+.green-btn:hover, button.green-btn:hover, input.green-btn:hover { background: #5b7189; border: 1px solid #8e9eb0; }
+.form-txt-submit-box input[type=submit] {
+ padding-top: 0; padding-bottom: 0; width: auto;
+}
+
+
+h1, h2, h3, h4, h5, h6, legend { font-family: 'Gill Sans', 'Trebuchet MS', Calibri, sans-serif; }
+body { color: #333; font-family: Arial, 'Helvetica Neue', Helvetica, sans-serif; line-height: 1.4; }
+
+// #header renamed to #bromley-header
+#bromley-header { padding: 0 18px 0 25px; }
+
+.header-nav {float:right; background:url('https://www.bromley.gov.uk/site/styles/css_img/header-nav.gif') no-repeat; overflow:hidden; width:651px; height:34px; line-height:34px; padding:0 20px;}
+.header-nav li {float:left; width:130px; text-align:center; background:url('https://www.bromley.gov.uk/site/styles/css_img/header-nav-divider.gif') top right no-repeat;}
+.header-nav li:last-child {background:none;}
+.header-nav a:link, .header-nav a:visited {color:#fff; text-decoration:none;}
+.header-nav a:hover, .header-nav a:active {text-decoration:underline;}
+
+/* -------- For Google translate select box only */
+.header-nav div#google_translate_element .goog-te-gadget { font-family: Arial, 'Helvetica Neue', Helvetica, sans-serif; }
+.header-nav div#google_translate_element .goog-te-gadget .goog-te-combo { margin:5px 0 0 5px; padding:0 0 0 2px; background: #9b9b9b; color: #fff; border: 1px solid #606060; font-size: 12px; width: 138px;}
+.header-nav div#google_translate_element .goog-te-gadget .goog-te-combo option { background:#fff; color: #666; padding: 1px 0; margin: 0; }
+/* --- */
+
+.logo {padding:10px 0;}
+
+.sign-in {float:right; margin-top:-87px; width: 650px; text-align: right;}
+.sign-in a:link, .sign-in a:visited {color:#333; font-weight:bold; text-decoration:none;}
+.sign-in a:hover, .sign-in a:active {text-decoration:underline;}
+
+.main-menu {background:url('https://www.bromley.gov.uk/site/styles/css_img/main-menu.gif') no-repeat; width:689px; height:45px; margin-top:-60px; float:right; clear:right;}
+.main-menu li {float:left; width:126px; padding-right:2px; text-align:center; font:150%/45px 'Gill Sans', 'Trebuchet MS', Calibri, sans-serif;}
+.main-menu li a:link, .main-menu li a:visited {color:#fff; display:block; text-decoration:none;}
+.main-menu li a:hover, .main-menu li a:active {background:url('https://www.bromley.gov.uk/site/styles/css_img/main-menu-hover.gif') repeat-x;}
+.main-menu li.home a:hover, .main-menu li.home a:active {background:url('https://www.bromley.gov.uk/site/styles/css_img/main-menu-hover-home.gif') repeat-x;}
+
+//#search { float: right; padding: 10px 17px; width: 270px; }
+//#search label {display:none;}
+//#search input { background: #ececec; border: 1px solid #768b9a; border-color: #768b9a #d1dee8 #d1dee8 #768b9a; line-height: 9px; padding: 6px 5px 4px; width: 184px; }
+//#search input.button { background: #fff; border: 1px solid #8596a8; color: #333; font-family: 'Gill Sans', 'Trebuchet MS', Calibri, sans-serif; font-size:133%; height: 27px; line-height: 27px; padding: 0; vertical-align: top; width: 70px; }
+
+// #footer renamed to #bromley-footer, fixed font size.
+#bromley-footer { background: #666 url('https://www.bromley.gov.uk/site/styles/css_img/footer.gif') top center no-repeat; clear: both; width:100%; padding:30px 15px 50px; margin-left:-15px; color:#fff; font-size:92%;}
+#bromley-footer a:link,
+#bromley-footer a:visited { color: #fff; text-decoration: none; }
+#bromley-footer a:hover,
+#bromley-footer a:active { text-decoration: underline;}
+#bromley-footer img { float: right; margin-top: -18px; }
+#bromley-footer .footer-nav { float: right; height:35px; margin-top: -15px; }
+#bromley-footer .footer-nav li { border-right:1px solid #fff; float: left; line-height: 1; padding: 0 20px; }
+#bromley-footer .footer-nav li:last-child { border: none; }
+
+// Bromley IE specific CSS
+.ie6 {
+ div { zoom: 1; }
+ #bromley-wrapper { padding: 0; }
+ #bromley-footer { margin: 0; }
+ //#search input { padding: 8px 5px 2px; }
+ //#search input.button { padding: 0; width: 68px; line-height: 24px; }
+ input.button { overflow: visible; width: 1%; }
+}
+.ie7 {
+ div { zoom: 1; }
+ //#search input { padding: 8px 5px 2px; }
+ //#search input.button { padding: 0; width: 68px; line-height: 24px; }
+ input.button { overflow: visible; }
+}
+.ie8 {
+ //#search input { padding: 8px 5px 2px; }
+ //#search input.button { padding: 0; line-height: 24px; }
+}
+
+// mySociety additions
+#bromley-header { font-size: 12px; }
+.header-nav ul { margin: 0; }
+.header-nav li { list-style-type: none; }
+// Width is actually 637, but that causes wrap-around, need to ask for fixes and corner image
+.main-menu { background: url('/cobrands/bromley/main-menu1.gif') no-repeat; width: 638px; }
+.main-menu ul { margin: 0; }
+.main-menu li { list-style-type: none; color: #ccf; }
+.main-menu li.last { padding-right: 0; }
+.main-menu li.last a:hover, .main-menu li.last a:active {background:url('/cobrands/bromley/main-menu-hover-home-right.gif') repeat-x;}
+//#search input { display: inline; margin: 0; @include border-radius(0em); }
+//#search input.button { font-weight: normal; text-transform: none; }
+#bromley-footer { padding-bottom: 60px; }
+#bromley-footer .footer-nav li { list-style-type: none; }
+#bromley-footer p { margin: 0; }
+
+#bromley-powered-by {
+ clear: both;
+}
+
diff --git a/web/cobrands/bromley/favicon.ico b/web/cobrands/bromley/favicon.ico
new file mode 100644
index 000000000..cf0577755
--- /dev/null
+++ b/web/cobrands/bromley/favicon.ico
Binary files differ
diff --git a/web/cobrands/bromley/favicon.png b/web/cobrands/bromley/favicon.png
new file mode 100644
index 000000000..0acd804e7
--- /dev/null
+++ b/web/cobrands/bromley/favicon.png
Binary files differ
diff --git a/web/cobrands/bromley/fms-logo.png b/web/cobrands/bromley/fms-logo.png
new file mode 100644
index 000000000..23bea6b0f
--- /dev/null
+++ b/web/cobrands/bromley/fms-logo.png
Binary files differ
diff --git a/web/cobrands/bromley/layout.scss b/web/cobrands/bromley/layout.scss
index 3dc34c6c7..eef0ee679 100644
--- a/web/cobrands/bromley/layout.scss
+++ b/web/cobrands/bromley/layout.scss
@@ -1,11 +1,155 @@
@import "_colours";
@import "../fixmystreet/_layout";
-body {
- background: #fff;
+body { background: #9b9b9b url('https://www.bromley.gov.uk/site/styles/css_img/repeater.gif') repeat-x; }
+#bromley-wrapper { background: #fff url('https://www.bromley.gov.uk/site/styles/css_img/header-corners.gif') center 110px no-repeat; margin: 1px auto 0; padding: 0 15px; width: 955px;}
+.offline #bromley-wrapper { padding: 0 15px 20px; }
+
+// So that map appears underneath the header
+.wrapper {
+ position: relative;
+}
+.ie6, .ie7 {
+ .wrapper {
+ padding-top: 1em;
+ }
+}
+
+// To prevent font size larger interfering with the fixed Bromley layout
+.container { width: auto; }
+.full-width { width: 464px; }
+.shadow-wrap { width: 464px; }
+#map_box { width: 464px; }
+.content { width: 432px; }
+body.fullwidthpage .content { width: auto; }
+body.twothirdswidthpage .content {
+ width: 640px;
+ aside {
+ left: 672px;
+ width: 208px;
+ padding: 16px;
+ }
+ .sticky-sidebar {
+ left: 672px;
+ aside {
+ top:7em;
+ }
+ }
+}
+.ie6, .ie7 {
+ body.mappage .container {
+ width: 464px;
+ margin-left: 0;
+ }
}
#front-main {
background: $primary;
+ @include border-radius(1em 1em 0 0);
+ margin: 2em 1em 0;
+ padding-top: 0;
+ // layout sets this because base has it slightly lighter
+ h2 {
+ color: $primary_text;
+ }
+ a#geolocate_link {
+ color: $primary_text;
+ }
+}
+
+// Don't want gap that normal site has
+body.frontpage {
+ .table-cell {
+ .content {
+ margin-top: 0;
+ }
+ }
+}
+
+// Don't want FixMyStreet logo on desktop, and we have a skip to content in
+// Bromley header
+#site-header {
+ display: none;
+}
+
+#user-meta {
+ display: none;
+}
+
+// Currently hiding, but do want some internal navigation somewhere at the end
+.nav-wrapper {
+ display: none;
+}
+
+// White background, so no shadow or margin needed.
+.content {
+ margin: 0;
+ @include box-shadow(none);
+}
+.ie6, .ie7, .ie8 {
+ .content {
+ margin: 0;
+ border: none;
+ }
+}
+
+// As map can scroll and isn't at the top, give it an edge
+#map_box {
+ border: solid 1px #999;
+ top: 1em;
+ right: 0em;
+ margin: 0;
+}
+
+// Perhaps fix map location (should be in central?)
+.ie6 #map_box, .ie7 #map_box {
+ right: -480px;
+}
+
+.general-sidebar-notes,
+#report-a-problem-sidebar {
+ position: static;
+ width: auto;
+ @include box-shadow(rgba(0, 0, 0, 0), 0, 0, 0);
+ .sidebar-tips,
+ .sidebar-notes {
+ font-size:1em;
+ }
+}
+
+.ie7 .big-green-banner {
+ right: 0;
+}
+
+// Pull OpenLayers navigation down a bit
+#fms_pan_zoom {
+ top: 0.5em !important;
+}
+
+// Fix location of aside sidebar
+body.twothirdswidthpage {
+ .content {
+ aside {
+ @include box-shadow(none);
+ }
+ .sticky-sidebar {
+ top: 1em;
+ aside {
+ position: absolute;
+ top: 0;
+ }
+ }
+ }
+}
+
+// So as not to interfere with the Bromley footer, make the fixed nav static.
+.shadow-wrap {
+ position: static;
+ padding-top: 0;
+ margin-bottom: 1em;
+ ul#key-tools {
+ border-top: none;
+ border-bottom: 1px solid $primary;
+ }
}
diff --git a/web/cobrands/bromley/main-menu-hover-home-right.gif b/web/cobrands/bromley/main-menu-hover-home-right.gif
new file mode 100644
index 000000000..80c11c782
--- /dev/null
+++ b/web/cobrands/bromley/main-menu-hover-home-right.gif
Binary files differ
diff --git a/web/cobrands/bromley/main-menu1.gif b/web/cobrands/bromley/main-menu1.gif
new file mode 100644
index 000000000..21ab45668
--- /dev/null
+++ b/web/cobrands/bromley/main-menu1.gif
Binary files differ
diff --git a/web/cobrands/bromley/position_map.js b/web/cobrands/bromley/position_map.js
new file mode 100644
index 000000000..dddef3def
--- /dev/null
+++ b/web/cobrands/bromley/position_map.js
@@ -0,0 +1,19 @@
+function position_map_box() {
+ var $html = $('html');
+ var bromley_right;
+ if ($html.hasClass('ie6') || $html.hasClass('ie7')) {
+ bromley_right = '-480px';
+ } else {
+ bromley_right = '0em';
+ }
+ // Do the same as CSS (in case resized from mobile).
+ $('#map_box').prependTo('.content').css({
+ zIndex: 1, position: 'absolute',
+ top: '1em', left: '', right: bromley_right, bottom: '',
+ width: '464px', height: '464px',
+ margin: 0
+ });
+}
+
+function map_fix() {}
+var slide_wards_down = 1;
diff --git a/web/cobrands/bromley/tab-blue.png b/web/cobrands/bromley/tab-blue.png
new file mode 100644
index 000000000..62e6285b7
--- /dev/null
+++ b/web/cobrands/bromley/tab-blue.png
Binary files differ
diff --git a/web/cobrands/fixmystreet/_base.scss b/web/cobrands/fixmystreet/_base.scss
index 644b015b5..4d3b36888 100644
--- a/web/cobrands/fixmystreet/_base.scss
+++ b/web/cobrands/fixmystreet/_base.scss
@@ -31,9 +31,6 @@ h1 {
margin-top: 0.5em;
margin-bottom: 0.5em;
}
-#front-main h1 {
- margin-top: 0.7em;
-}
h1#reports_heading span {
display: none;
}
@@ -145,12 +142,23 @@ img {
//do this otherwise IE will just not display
//any img without a height defined
height:auto;
+ max-width: 100%;
+}
+// So that map popups display correctly
+#popup img {
+ max-width: none;
}
select, input, textarea {
font-size: 99%;
max-width: 95%;
}
+.ie7 {
+ select, input, textarea {
+ max-width: none;
+ }
+}
+
// To deal with bug from drop-down being wider than holder
select {
width: 100%;
@@ -247,10 +255,27 @@ input[type=password],
input[type=email],
input[type=file],
textarea {
+ @include box-sizing(border-box);
width: 100%;
// adjust so the sides line up
padding: 0.5em;
- margin: 0 0 0 -0.5em;
+}
+.ie7 {
+ input[type=text],
+ input[type=password],
+ input[type=email],
+ input[type=file],
+ textarea {
+ max-width: 95%;
+ }
+ // In order to work around the IE7 specific issue of inheriting left margins
+ // http://techblog.willshouse.com/2009/07/12/ie6ie7-form-element-margin-inheritance-bug/
+ fieldset > input[type=text],
+ fieldset > input[type=password],
+ fieldset > input[type=email],
+ fieldset > textarea {
+ margin-left: -1em;
+ }
}
textarea {
@@ -294,7 +319,6 @@ label{
margin: 0 -2em 0.25em -2em;
background:#eeeeee;
padding:1em 2em 1em 2em;
- max-width:26em;
>input[type=text] {
margin-bottom:1em;
}
@@ -303,7 +327,7 @@ label{
margin:0.5em 0;
}
h5 {
- margin:0;
+ margin:0 0 1em;
font: {
size:1.125em;
weight:normal;
@@ -319,6 +343,14 @@ label{
// it looks okay.
.ie6 .form-box {
margin: 0 0 0.25em 0;
+ padding: 1em;
+}
+// Prevent grey displaying oddly by giving it a width, and stop odd left margin issue
+.ie7 .form-box {
+ width: 100%;
+ > input[type=text] {
+ margin-left: 2em;
+ }
}
.form-txt-submit-box {
@@ -350,8 +382,14 @@ p.form-error {
background:#ff0000;
color:#fff;
padding:0 0.5em;
- margin:0 0 0 -0.5em;
@include border-radius(0.25em 0.25em 0 0);
+ a {
+ color: white;
+ text-decoration: underline;
+ }
+ a:hover {
+ text-decoration: none;
+ }
}
input.form-error,
@@ -364,7 +402,6 @@ ul.error {
background:#ff0000;
color:#fff;
padding:0 0.5em;
- margin:0 0 0 -0.5em;
@include border-radius(0.25em);
}
@@ -457,7 +494,8 @@ p.label-valid {
&#mysoc-menu{
li {
a {
- background:$primary;
+ color: $primary_text;
+ background: $primary;
&#mysoc-logo {
background-image:url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAIkAAAAyCAMAAABf9whNAAAACW9GRnMAAADwAAAAJgAMZizzAAAACXBIWXMAAABIAAAASABGyWs+AAAACXZwQWcAAAF5AAAQZgCwCYXlAAAANlBMVEUAAAAiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiL///90WH2CAAAAEHRSTlMADx8vP09fb3+Pn6+/z9/v+t8hjgAAAAFiS0dEEeK1PboAAAGqSURBVFjD7ZbNjtwgEAY/oIE2YKj3f9ocPDOZ3eN6FCUKdWsJQ+H+saXNZrPZbDabzf/GovwdIhH8LUzHn/PqI32Jcw1v0fjidQf30EZPqmMURXeT5F5kbYwqSQbeWpAU6xg961pT+mgm+WR4Ke6SzG9JwQRWB6iaTClCzQBLknT0AibZAnCBSx2ALACGQ5JOznsmq1TA82LKIalC6Jwh5seaMGdUWKxiJQpclWVqLNlJsxThUIB6z8Qft3FQgEODrs4qUuj9qoljpAr2euKkmxVIjzrpTBUI90xMGgzJQGrMAEUGrGKQn6c7/HbngT1MMqRO1wdNDA6WpNgW5Ld38s1kuLt7fPbO5Lg7Z76ZaLJoV3WAa6wsxbmiyrMMruyMVxc3SaqvAv+YSQWS1Fs9oAi8jQKmsGB4zwJXgdO9VWnAkaUAHJ81CTAkLYAm5ZbB/QhSmm9d7Ff7Splr5jaI90zMgpQsScHsGmRFUsheH6O1jecR5m5BZlFSzF5NkpJ7lMJ85etDlPWjHdMJ6aMiFdYPdgzw6Q90Yvwo2+fM+3dps9lsNpvNP8gvi7UYry9B6TcAAAAldEVYdGRhdGU6Y3JlYXRlADIwMTItMDUtMDJUMTk6NDY6NTErMDE6MDAcdbR4AAAAJXRFWHRkYXRlOm1vZGlmeQAyMDEyLTA1LTAyVDE5OjQ2OjUxKzAxOjAwbSgMxAAAABl0RVh0U29mdHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAAAASUVORK5CYII=');
background-repeat:no-repeat;
@@ -485,7 +523,8 @@ p.label-valid {
#user-meta {
p {
position: relative;
- background:$primary;
+ color: $primary_text;
+ background: $primary;
padding:1em 6em 1em 1em;
a {
position: absolute;
@@ -518,7 +557,11 @@ p.label-valid {
&:last-child {
border-right:none;
}
- a {
+ input[type=submit] {
+ width: 100%;
+ border: none;
+ }
+ a, input[type=submit] {
display: block;
background-color: #f5f5f5;
background-repeat: no-repeat;
@@ -529,7 +572,7 @@ p.label-valid {
size:0.6875em;
family: Helmet, Freesans, sans-serif;
}
- &:hover, &.hover, &.active {
+ &:hover, &.hover {
text-decoration:none;
background-color:#333;
color:#fff;
@@ -546,7 +589,7 @@ p.label-valid {
background-image:url('/cobrands/fixmystreet/images/sprite.png');
background-position:center -2716px;
}
- &.hover, &.active {
+ &.hover {
background-image:url('/cobrands/fixmystreet/images/sprite.png');
background-position:center -2064px;
}
@@ -717,7 +760,7 @@ a:hover.button-left {
width: 0;
height: 0;
border-left: 0.5em solid transparent;
- border-bottom: 0.5em solid #4B8304;
+ border-bottom: 0.5em solid $contrast1_dark;
}
}
@@ -753,7 +796,7 @@ a:hover.button-left {
color:#fff;
background: $contrast1;
&:before {
- border-bottom: 0.5em solid #4B8304;
+ border-bottom: 0.5em solid $contrast1_dark;
}
}
}
@@ -838,6 +881,7 @@ a:hover.button-left {
}
.img {
text-align:right;
+ width: 90px;
img {
height:auto;
}
@@ -906,7 +950,7 @@ a:hover.button-left {
width:20px;
height:20px;
opacity: 0.5;
- background:#fff url(images/sprite.png) -16px -1098px no-repeat;
+ background:#fff url(/cobrands/fixmystreet/images/sprite.png) -16px -1098px no-repeat;
//hide text - http://nicolasgallagher.com/another-css-image-replacement-technique/
font: 0/0 a;
color: transparent;
@@ -1286,7 +1330,8 @@ table.nicetable {
.promo {
@extend .full-width;
- background:$primary;
+ color: $primary_text;
+ background: $primary;
padding:1em;
margin-bottom:1em;
overflow:hidden;
@@ -1299,10 +1344,10 @@ table.nicetable {
width:16px;
height:16px;
text-indent:-999999px;
- background:url(images/sprite.png) -341px -263px no-repeat;
+ background:url(/cobrands/fixmystreet/images/sprite.png) -341px -263px no-repeat;
@include border-radius(4px);
&:hover {
- background:#222 url(images/sprite.png) -341px -223px no-repeat;
+ background:#222 url(/cobrands/fixmystreet/images/sprite.png) -341px -223px no-repeat;
}
}
}
@@ -1333,7 +1378,8 @@ table.nicetable {
}
a {
@include inline-block;
- background:$primary;
+ color: $primary_text;
+ background: $primary;
padding-left:0.5em;
padding-right:0.5em;
color:#1a1a1a;
@@ -1347,7 +1393,7 @@ table.nicetable {
// this is a bit of a hack to get some differentation between desk and mobile
.desk-only {
- display:none !important;
+ display:none;
}
// hide anything with this class if js is working
@@ -1366,6 +1412,7 @@ table.nicetable {
/* Front page */
#front-main {
text-align:center;
+ margin: 1em;
h2 {
font: {
style:italic;
@@ -1374,6 +1421,9 @@ table.nicetable {
}
color:#4d4d4d;
}
+ p {
+ margin: 0.5em 0 0;
+ }
#postcodeForm {
@extend .full-width;
padding:1em;
@@ -1392,7 +1442,7 @@ table.nicetable {
display:table-cell;
margin:0;
padding:0.25em 2%;
- width:82%;
+ width:86%;
border:none;
background:none;
line-height:1.5em;
@@ -1460,7 +1510,6 @@ table.nicetable {
#front-recently {
.issue-list-a {
border-bottom:none;
- margin-bottom:0;
}
}
diff --git a/web/cobrands/fixmystreet/_colours.scss b/web/cobrands/fixmystreet/_colours.scss
index 2463cdeeb..1a62d0282 100644
--- a/web/cobrands/fixmystreet/_colours.scss
+++ b/web/cobrands/fixmystreet/_colours.scss
@@ -5,4 +5,5 @@ $primary_b: #F3B11E;
$primary_text: #222;
$contrast1: #00BD08;
+$contrast1_dark: #4B8304;
$contrast2: #AA8D11;
diff --git a/web/cobrands/fixmystreet/_layout.scss b/web/cobrands/fixmystreet/_layout.scss
index 6a32ea010..56b2f41d5 100644
--- a/web/cobrands/fixmystreet/_layout.scss
+++ b/web/cobrands/fixmystreet/_layout.scss
@@ -3,10 +3,10 @@
//hacks for desk/mob only stuff
.desk-only {
- display:block !important;
+ display: block;
}
.mob-only {
- display:none !important;
+ display: none;
}
body {
@@ -147,7 +147,8 @@ h1 {
@include background(linear-gradient(#000, #444 10%, #444 95%, #111));
}
a.report-a-problem-btn {
- background:$primary;
+ color: $primary_text;
+ background: $primary;
padding:0.25em;
margin:0.5em;
color:#333;
@@ -197,28 +198,23 @@ h1 {
// .content Is the white box
// The narrow single column box
-.content{
+.content {
width: 27em;
margin-top: 3em;
- background: #fff;
- padding: 1em;
- padding-bottom: 3em;
- margin-left: 0.5em;
margin-bottom: -1em;
+ margin-left: 0.5em;
+ padding: 1em 1em 3em;
+ background: #fff;
@include box-shadow(0px 0px 6px 1px #000);
}
.ie6, .ie7, .ie8 {
.content {
// If no box-shadow, just want a boring black border to stand it out from the map.
- border: 1px solid black;
+ border: 1px solid #666;
//take off margins so we line up properly
- margin: 0;
+ margin: 0 0 0 0.5em;
}
}
-//weird margining thing for ie8
-.ie8 .content {
- margin-top:3em;
-}
// map page - has fixed header and different styling
body.mappage {
@@ -253,7 +249,7 @@ body.mappage {
.container {
float: left;
width: 27em;
- margin-left: 1.4em;
+ margin-left: 0.7em;
}
.nav-wrapper{
z-index:1;
@@ -266,13 +262,6 @@ body.mappage {
}
}
}
-.ie6 {
- body.mappage {
- .container {
- margin-left: 0.7em;
- }
- }
-}
//ie8 needs different stuff on .nav-wrapper so we
//have to define all the rest of it again as this resets
//the z-index base yet again :S
@@ -304,7 +293,6 @@ body.fullwidthpage {
}
// two thirds width page, also has option for a sidebar which can be sticky or not
body.twothirdswidthpage {
- @extend .fullwidthpage;
.content {
width:40em;
position: relative;
@@ -588,7 +576,7 @@ body.twothirdswidthpage {
@include box-shadow(-0em 0px 1em 1em #fff);
li {
border:none;
- a {
+ a, input[type=submit] {
font-size: 0.75em;
color:#666;
padding: 0.5em 1.5em 0.5em 0;
@@ -644,9 +632,14 @@ body.twothirdswidthpage {
top:-0.5em;
position: absolute;
border-top: 0.5em solid transparent;
- border-left: 0.5em solid #4B8304;
+ border-left: 0.5em solid $contrast1_dark;
border-bottom:none;
}
+ span {
+ display: block;
+ font-size: 80%;
+ padding-top: 0.5em;
+ }
}
.ie6 .big-green-banner {
background: $contrast1 url(/cobrands/fixmystreet/images/ie_green_chevron.gif) right center no-repeat;
@@ -668,7 +661,7 @@ body.twothirdswidthpage {
background-position:-324px -326px;
background-repeat:no-repeat;
&:before {
- border-bottom: 0.75em solid #4B8304;
+ border-bottom: 0.75em solid $contrast1_dark;
}
}
}
@@ -694,18 +687,13 @@ input[type=text],
input[type=password],
input[type=email],
textarea{
- width: 25em;
-}
-.form-box {
- max-width:25em;
+ max-width: 25em;
}
-
/* form errors */
div.form-error,
p.form-error {
display:block;
- width:24.7em;
}
input.form-error,
@@ -735,7 +723,7 @@ textarea.form-error {
}
}
.ie6, .ie7 {
- #report-a-problem-sidebar {
+ #report-a-problem-sidebar, .general-sidebar-notes {
left: 29em; // 0.5em left margin gone on .content in IE6/7, so reduce this accordingly.
}
}
@@ -774,19 +762,15 @@ textarea.form-error {
body.frontpage {
.table-cell {
- // we do this so we can have full screen width elements
- >.container {
- width:100%;
- }
.content {
- margin:14em auto 0 auto;
+ margin: 1em auto 0;
}
}
.nav-wrapper-2{
height:6em;
}
#site-header{
- height:9em;
+ height:8em;
}
#site-logo{
top:3em;
@@ -799,7 +783,7 @@ body.frontpage {
p {
top:-4em;
right:0;
- color:#FFD000;
+ color:$primary;
background:none;
@include box-shadow(rgba(0, 0, 0, 0) 0 0 0);
a {
@@ -825,7 +809,7 @@ body.frontpage {
.ie6, .ie7 {
body.frontpage {
#site-header {
- height:3em;
+ height:4em;
}
#site-logo {
top:-1em;
@@ -838,24 +822,13 @@ body.frontpage {
.ie6 body.frontpage #site-logo {
background:url(/cobrands/fixmystreet/images/ie_front_logo.gif) 0 0 no-repeat;
}
-//weird margining thing for ie8
-.ie8 body.frontpage {
- #front-main {
- top:-12em;
- }
- .table-cell .content {
- margin-top:12em;
- }
-}
// big yellow bit full screen width
#front-main {
color: $primary_text;
background: $primary url(/cobrands/fixmystreet/images/tile-y.jpg);
- position:absolute;
- width:100%;
- left:0;
- top:-15em;
+ margin: 0;
+ padding: 1em;
#front-main-container {
max-width: 57em;
margin:0 auto;
@@ -868,6 +841,7 @@ body.frontpage {
#postcodeForm {
background:none;
overflow:hidden;
+ padding-bottom: 0;
margin-right:0.5em;
label {
margin:0.5em 0;
@@ -881,8 +855,8 @@ body.frontpage {
display:block;
float:left;
padding:0.25em 0.5em;
- height:1.5em;
- width:16em;
+ height:2em;
+ width:17em;
}
input#submit {
display:block;
@@ -893,27 +867,40 @@ body.frontpage {
}
}
}
+ a {
+ color: $primary_text;
+ text-decoration: underline;
+ &:hover {
+ text-decoration: none;
+ }
+ }
a#geolocate_link {
background:none;
color:#222;
- margin:-1em 0 0.5em 0;
+ text-decoration: none;
+ padding-bottom: 0;
&:hover {
text-decoration:underline;
background:none;
}
}
}
-.ie6, .ie7 {
- #front-main {
- top:2em;
+.ie7 #front-main {
+ #postcodeForm {
+ div {
+ input#pc {
+ height:1.5em;
+ width:16em;
+ }
+ }
}
}
-
#front-howto {
border-right:1em solid #fff;
#front_stats {
background:none;
+ color: #222;
border-top:0.25em solid $primary;
padding-top:1em;
div {
diff --git a/web/cobrands/fixmystreet/fixmystreet.js b/web/cobrands/fixmystreet/fixmystreet.js
index 9d5151189..c8ed8ae51 100644
--- a/web/cobrands/fixmystreet/fixmystreet.js
+++ b/web/cobrands/fixmystreet/fixmystreet.js
@@ -3,33 +3,6 @@
* FixMyStreet JavaScript
*/
-function form_category_onchange() {
- var cat = $('#form_category');
- var args = {
- category: cat.val()
- };
-
- if ( typeof fixmystreet !== 'undefined' ) {
- args.latitude = fixmystreet.latitude;
- args.longitude = fixmystreet.longitude;
- } else {
- args.latitude = $('input[name="latitude"]').val();
- args.longitude = $('input[name="longitude"]').val();
- }
-
- $.getJSON('/report/new/category_extras', args, function(data) {
- if ( data.category_extra ) {
- if ( $('#category_meta').size() ) {
- $('#category_meta').html( data.category_extra);
- } else {
- $('#form_category_row').after( data.category_extra );
- }
- } else {
- $('#category_meta').empty();
- }
- });
-}
-
/*
* general height fixing function
*
@@ -80,12 +53,12 @@ function tabs(elem, indirect) {
$(function(){
var $html = $('html');
- $html.removeClass('no-js').addClass('js');
-
-
- // Preload the new report pin
- document.createElement('img').src = '/i/pin-green.png';
+ var cobrand;
+ if (window.location.href.indexOf('bromley') != -1) {
+ cobrand = 'bromley';
+ }
+ // Deal with switching between mobile and desktop versions on resize
var last_type;
$(window).resize(function(){
var type = $('#site-header').css('borderTopWidth');
@@ -106,7 +79,9 @@ $(function(){
}
if (typeof fixmystreet !== 'undefined' && fixmystreet.page == 'around') {
// Immediately go full screen map if on around page
- $('#site-header').hide();
+ if (cobrand != 'bromley') {
+ $('#site-header').hide();
+ }
$('#map_box').prependTo('.wrapper').css({
position: 'absolute',
top: 0, left: 0, right: 0, bottom: 0,
@@ -128,167 +103,33 @@ $(function(){
} else {
// Make map full screen on non-mobile sizes.
$html.removeClass('mobile');
- var map_pos = 'fixed', map_height = '100%';
- if ($html.hasClass('ie6')) {
- map_pos = 'absolute';
- map_height = $(window).height();
- }
- $('#map_box').prependTo('.wrapper').css({
- zIndex: 0, position: map_pos,
- top: 0, left: 0, right: 0, bottom: 0,
- width: '100%', height: map_height,
- margin: 0
- });
+ position_map_box();
if (typeof fixmystreet !== 'undefined') {
- fixmystreet.state_map = 'full';
+ if (cobrand == 'bromley') {
+ //$('#bromley-footer').hide();
+ } else {
+ fixmystreet.state_map = 'full';
+ }
}
if (typeof fixmystreet !== 'undefined' && fixmystreet.page == 'around') {
// Remove full-screen-ness
- $('#site-header').show();
+ var banner_text;
+ if (cobrand == 'bromley') {
+ banner_text = 'Click map to report a problem<span>Yellow pins show existing reports</span>';
+ } else {
+ $('#site-header').show();
+ banner_text = 'Click map to report a problem';
+ }
$('#fms_pan_zoom').css({ top: '4.75em !important' });
$('.big-green-banner')
.removeClass('mobile-map-banner')
.prependTo('#side')
- .text('Click map to report a problem');
+ .html(banner_text);
}
$('span.report-a-problem-btn').css({ cursor:'' }).off('.reportBtn');
}
last_type = type;
- });
-
- //add mobile class if small screen
- $(window).resize();
-
- $('#pc').focus();
-
- $('input[type=submit]').removeAttr('disabled');
- /*
- $('#mapForm').submit(function() {
- if (this.submit_problem) {
- $('input[type=submit]', this).prop("disabled", true);
- }
- return true;
- });
- */
-
- if (!$('#been_fixed_no').prop('checked') && !$('#been_fixed_unknown').prop('checked')) {
- $('#another_qn').hide();
- }
- $('#been_fixed_no').click(function() {
- $('#another_qn').show('fast');
- });
- $('#been_fixed_unknown').click(function() {
- $('#another_qn').show('fast');
- });
- $('#been_fixed_yes').click(function() {
- $('#another_qn').hide('fast');
- });
-
- // FIXME - needs to use translated string
- jQuery.validator.addMethod('validCategory', function(value, element) {
- return this.optional(element) || value != '-- Pick a category --'; }, validation_strings.category );
-
- jQuery.validator.addMethod('validName', function(value, element) {
- var validNamePat = /\ba\s*n+on+((y|o)mo?u?s)?(ly)?\b/i;
- return this.optional(element) || value.length > 5 && value.match( /\S/ ) && !value.match( validNamePat ); }, validation_strings.category );
-
- var form_submitted = 0;
- var submitted = false;
-
- $("form.validate").validate({
- rules: {
- title: { required: true },
- detail: { required: true },
- email: { required: true },
- update: { required: true },
- rznvy: { required: true }
- },
- messages: validation_strings,
- onkeyup: false,
- onfocusout: false,
- errorElement: 'div',
- errorClass: 'form-error',
- // we do this to stop things jumping around on blur
- success: function (err) { if ( form_submitted ) { err.addClass('label-valid').removeClass('label-valid-hidden').html( '&nbsp;' ); } else { err.addClass('label-valid-hidden'); } },
- errorPlacement: function( error, element ) {
- element.before( error );
- },
- submitHandler: function(form) {
- if (form.submit_problem) {
- $('input[type=submit]', form).prop("disabled", true);
- }
-
- form.submit();
- },
- // make sure we can see the error message when we focus on invalid elements
- showErrors: function( errorMap, errorList ) {
- if ( submitted && errorList.length ) {
- $(window).scrollTop( $(errorList[0].element).offset().top - 120 );
- }
- this.defaultShowErrors();
- submitted = false;
- },
- invalidHandler: function(form, validator) { submitted = true; }
- });
-
- $('input[type=submit]').click( function(e) { form_submitted = 1; } );
-
- /* set correct required status depending on what we submit
- * NB: need to add things to form_category as the JS updating
- * of this we do after a map click removes them */
- $('#submit_sign_in').click( function(e) {
- $('#form_category').addClass('required validCategory').removeClass('valid');
- $('#form_name').removeClass();
- } );
-
- $('#submit_register').click( function(e) {
- $('#form_category').addClass('required validCategory').removeClass('valid');
- $('#form_name').addClass('required validName');
- } );
-
- $('#problem_submit > input[type="submit"]').click( function(e) {
- $('#form_category').addClass('required validCategory').removeClass('valid');
- $('#form_name').addClass('required validName');
- } );
-
- $('#update_post').click( function(e) {
- $('#form_name').addClass('required').removeClass('valid');
- } );
-
- $('#form_category').change( form_category_onchange );
-
- // Geolocation
- if (geo_position_js.init()) {
- $('#postcodeForm').after('<a href="#" id="geolocate_link">&hellip; or locate me automatically</a>');
- $('#geolocate_link').click(function(e) {
- e.preventDefault();
- // Spinny thing!
- if($('.mobile').length){
- $(this).append(' <img src="/cobrands/fixmystreet/images/spinner-black.gif" alt="" align="bottom">');
- }else{
- $(this).append(' <img src="/cobrands/fixmystreet/images/spinner-yellow.gif" alt="" align="bottom">');
- }
- geo_position_js.getCurrentPosition(function(pos) {
- $('img', this).remove();
- var latitude = pos.coords.latitude;
- var longitude = pos.coords.longitude;
- location.href = '/around?latitude=' + latitude + ';longitude=' + longitude;
- }, function(err) {
- $('img', this).remove();
- if (err.code == 1) { // User said no
- } else if (err.code == 2) { // No position
- $(this).html("Could not look up location");
- } else if (err.code == 3) { // Too long
- $('this').html("No result returned");
- } else { // Unknown
- $('this').html("Unknown error");
- }
- }, {
- enableHighAccuracy: true,
- timeout: 10000
- });
- });
- }
+ }).resize();
/*
* Report a problem page
@@ -361,10 +202,15 @@ $(function(){
/*
* Show stuff on input focus
*/
- $('.form-focus-hidden').hide();
- $('.form-focus-trigger').on('focus', function(){
- $('.form-focus-hidden').fadeIn(500);
- });
+ var form_focus_data = $('.form-focus-trigger').map(function() {
+ return $(this).val();
+ }).get().join('');
+ if (!form_focus_data) {
+ $('.form-focus-hidden').hide();
+ $('.form-focus-trigger').on('focus', function(){
+ $('.form-focus-hidden').fadeIn(500);
+ });
+ }
/*
* Show on click - pretty generic
@@ -479,12 +325,12 @@ $.fn.drawer = function(id, ajax) {
});
};
- if ($('html.mobile').length) {
+ if ($('html.mobile').length || slide_wards_down ) {
$('#council_wards').hide().removeClass('hidden-js').find('h2').hide();
$('#key-tool-wards').click(function(e){
e.preventDefault();
$('#council_wards').slideToggle('800', function(){
- $('#key-tool-wards').toggleClass('active');
+ $('#key-tool-wards').toggleClass('hover');
});
});
} else {
@@ -508,6 +354,7 @@ $.fn.drawer = function(id, ajax) {
var $v = $(this);
$('<input/>').attr({ name:$v.attr('name'), value:$v.val(), type:'hidden' }).appendTo(form);
});
+ $('body').append(form);
form.submit();
});
@@ -575,7 +422,13 @@ $.fn.drawer = function(id, ajax) {
*/
if (!$('html.mobile').length) {
if (!($('body').hasClass('frontpage'))){
- heightFix(window, '.content', -176);
+ var offset = -176;
+ if (cobrand == 'bromley') {
+ offset = -110;
+ }
+ heightFix(window, '.content', offset);
+ // in case we have a map that isn't full screen
+ map_fix();
}
}
diff --git a/web/cobrands/fixmystreet/position_map.js b/web/cobrands/fixmystreet/position_map.js
new file mode 100644
index 000000000..4a18d9f9a
--- /dev/null
+++ b/web/cobrands/fixmystreet/position_map.js
@@ -0,0 +1,21 @@
+function position_map_box() {
+ var $html = $('html');
+ if ($html.hasClass('ie6')) {
+ $('#map_box').prependTo('.wrapper').css({
+ zIndex: 0, position: 'absolute',
+ top: 0, left: 0, right: 0, bottom: 0,
+ width: '100%', height: $(window).height(),
+ margin: 0
+ });
+ } else {
+ $('#map_box').prependTo('.wrapper').css({
+ zIndex: 0, position: 'fixed',
+ top: 0, left: 0, right: 0, bottom: 0,
+ width: '100%', height: '100%',
+ margin: 0
+ });
+ }
+}
+
+function map_fix() {}
+var slide_wards_down = 0;
diff --git a/web/css/core.scss b/web/css/core.scss
index a38a188ce..72e483dfa 100644
--- a/web/css/core.scss
+++ b/web/css/core.scss
@@ -114,7 +114,9 @@ $map_width: 500px;
}
}
- #geolocate_para {
+ #geolocate_link {
+ display: block;
+ border: none;
font-size: 70%;
margin: 2px 0 0 0;
text-align: right;
@@ -609,7 +611,7 @@ $map_width: 500px;
}
}
- #geolocate_para {
+ #geolocate_link {
font-size: 100%;
}
diff --git a/web/js/fancybox/jquery.fancybox-1.3.4.js b/web/js/fancybox/jquery.fancybox-1.3.4.js
index be7727537..728aa6a51 100644
--- a/web/js/fancybox/jquery.fancybox-1.3.4.js
+++ b/web/js/fancybox/jquery.fancybox-1.3.4.js
@@ -943,7 +943,7 @@
$(window).unbind("resize.fb scroll.fb");
$(document).unbind('keydown.fb');
- content.find('iframe').attr('src', isIE6 && /^https/i.test(window.location.href || '') ? 'javascript:void(false)' : 'about:blank');
+ content.find('iframe').attr('src', isIE6 && /^https/i.test(window.location.href || '') ? '/js/fancybox/blank.gif' : 'about:blank');
if (currentOpts.titlePosition !== 'inside') {
title.empty();
@@ -1090,7 +1090,7 @@
loading.addClass('fancybox-ie6');
wrap.addClass('fancybox-ie6');
- $('<iframe id="fancybox-hide-sel-frame" src="' + (/^https/i.test(window.location.href || '') ? 'javascript:void(false)' : 'about:blank' ) + '" scrolling="no" border="0" frameborder="0" tabindex="-1"></iframe>').prependTo(outer);
+ $('<iframe id="fancybox-hide-sel-frame" src="' + (/^https/i.test(window.location.href || '') ? '/js/fancybox/blank.gif' : 'about:blank' ) + '" scrolling="no" border="0" frameborder="0" tabindex="-1"></iframe>').prependTo(outer);
}
};
@@ -1153,4 +1153,4 @@
$.fancybox.init();
});
-})(jQuery); \ No newline at end of file
+})(jQuery);
diff --git a/web/js/fancybox/jquery.fancybox-1.3.4.pack.js b/web/js/fancybox/jquery.fancybox-1.3.4.pack.js
index 1373ed083..d5bd61fe9 100644
--- a/web/js/fancybox/jquery.fancybox-1.3.4.pack.js
+++ b/web/js/fancybox/jquery.fancybox-1.3.4.pack.js
@@ -37,10 +37,10 @@ j.css({width:c.width-d.padding*2,height:c.height-y*a-d.padding*2})},U=function()
b.fn.fancybox=function(a){if(!b(this).length)return this;b(this).data("fancybox",b.extend({},a,b.metadata?b(this).metadata():{})).unbind("click.fb").bind("click.fb",function(c){c.preventDefault();if(!h){h=true;b(this).blur();o=[];q=0;c=b(this).attr("rel")||"";if(!c||c==""||c==="nofollow")o.push(this);else{o=b("a[rel="+c+"], area[rel="+c+"]");q=o.index(this)}I()}});return this};b.fancybox=function(a,c){var g;if(!h){h=true;g=typeof c!=="undefined"?c:{};o=[];q=parseInt(g.index,10)||0;if(b.isArray(a)){for(var k=
0,C=a.length;k<C;k++)if(typeof a[k]=="object")b(a[k]).data("fancybox",b.extend({},g,a[k]));else a[k]=b({}).data("fancybox",b.extend({content:a[k]},g));o=jQuery.merge(o,a)}else{if(typeof a=="object")b(a).data("fancybox",b.extend({},g,a));else a=b({}).data("fancybox",b.extend({content:a},g));o.push(a)}if(q>o.length||q<0)q=0;I()}};b.fancybox.showActivity=function(){clearInterval(K);t.show();K=setInterval(Z,66)};b.fancybox.hideActivity=function(){t.hide()};b.fancybox.next=function(){return b.fancybox.pos(p+
1)};b.fancybox.prev=function(){return b.fancybox.pos(p-1)};b.fancybox.pos=function(a){if(!h){a=parseInt(a);o=l;if(a>-1&&a<l.length){q=a;I()}else if(d.cyclic&&l.length>1){q=a>=l.length?0:l.length-1;I()}}};b.fancybox.cancel=function(){if(!h){h=true;b.event.trigger("fancybox-cancel");N();e.onCancel(o,q,e);h=false}};b.fancybox.close=function(){function a(){u.fadeOut("fast");n.empty().hide();f.hide();b.event.trigger("fancybox-cleanup");j.empty();d.onClosed(l,p,d);l=e=[];p=q=0;d=e={};h=false}if(!(h||f.is(":hidden"))){h=
-true;if(d&&false===d.onCleanup(l,p,d))h=false;else{N();b(E.add(z).add(A)).hide();b(j.add(u)).unbind();b(window).unbind("resize.fb scroll.fb");b(document).unbind("keydown.fb");j.find("iframe").attr("src",M&&/^https/i.test(window.location.href||"")?"javascript:void(false)":"about:blank");d.titlePosition!=="inside"&&n.empty();f.stop();if(d.transitionOut=="elastic"){r=V();var c=f.position();i={top:c.top,left:c.left,width:f.width(),height:f.height()};if(d.opacity)i.opacity=1;n.empty().hide();B.prop=1;
+true;if(d&&false===d.onCleanup(l,p,d))h=false;else{N();b(E.add(z).add(A)).hide();b(j.add(u)).unbind();b(window).unbind("resize.fb scroll.fb");b(document).unbind("keydown.fb");j.find("iframe").attr("src",M&&/^https/i.test(window.location.href||"")?"/js/fancybox/blank.gif":"about:blank");d.titlePosition!=="inside"&&n.empty();f.stop();if(d.transitionOut=="elastic"){r=V();var c=f.position();i={top:c.top,left:c.left,width:f.width(),height:f.height()};if(d.opacity)i.opacity=1;n.empty().hide();B.prop=1;
b(B).animate({prop:0},{duration:d.speedOut,easing:d.easingOut,step:T,complete:a})}else f.fadeOut(d.transitionOut=="none"?0:d.speedOut,a)}}};b.fancybox.resize=function(){u.is(":visible")&&u.css("height",b(document).height());b.fancybox.center(true)};b.fancybox.center=function(a){var c,g;if(!h){g=a===true?1:0;c=U();!g&&(f.width()>c[0]||f.height()>c[1])||f.stop().animate({top:parseInt(Math.max(c[3]-20,c[3]+(c[1]-j.height()-40)*0.5-d.padding)),left:parseInt(Math.max(c[2]-20,c[2]+(c[0]-j.width()-40)*0.5-
d.padding))},typeof a=="number"?a:200)}};b.fancybox.init=function(){if(!b("#fancybox-wrap").length){b("body").append(m=b('<div id="fancybox-tmp"></div>'),t=b('<div id="fancybox-loading"><div></div></div>'),u=b('<div id="fancybox-overlay"></div>'),f=b('<div id="fancybox-wrap"></div>'));D=b('<div id="fancybox-outer"></div>').append('<div class="fancybox-bg" id="fancybox-bg-n"></div><div class="fancybox-bg" id="fancybox-bg-ne"></div><div class="fancybox-bg" id="fancybox-bg-e"></div><div class="fancybox-bg" id="fancybox-bg-se"></div><div class="fancybox-bg" id="fancybox-bg-s"></div><div class="fancybox-bg" id="fancybox-bg-sw"></div><div class="fancybox-bg" id="fancybox-bg-w"></div><div class="fancybox-bg" id="fancybox-bg-nw"></div>').appendTo(f);
D.append(j=b('<div id="fancybox-content"></div>'),E=b('<a id="fancybox-close"></a>'),n=b('<div id="fancybox-title"></div>'),z=b('<a href="javascript:;" id="fancybox-left"><span class="fancy-ico" id="fancybox-left-ico"></span></a>'),A=b('<a href="javascript:;" id="fancybox-right"><span class="fancy-ico" id="fancybox-right-ico"></span></a>'));E.click(b.fancybox.close);t.click(b.fancybox.cancel);z.click(function(a){a.preventDefault();b.fancybox.prev()});A.click(function(a){a.preventDefault();b.fancybox.next()});
-b.fn.mousewheel&&f.bind("mousewheel.fb",function(a,c){if(h)a.preventDefault();else if(b(a.target).get(0).clientHeight==0||b(a.target).get(0).scrollHeight===b(a.target).get(0).clientHeight){a.preventDefault();b.fancybox[c>0?"prev":"next"]()}});b.support.opacity||f.addClass("fancybox-ie");if(M){t.addClass("fancybox-ie6");f.addClass("fancybox-ie6");b('<iframe id="fancybox-hide-sel-frame" src="'+(/^https/i.test(window.location.href||"")?"javascript:void(false)":"about:blank")+'" scrolling="no" border="0" frameborder="0" tabindex="-1"></iframe>').prependTo(D)}}};
+b.fn.mousewheel&&f.bind("mousewheel.fb",function(a,c){if(h)a.preventDefault();else if(b(a.target).get(0).clientHeight==0||b(a.target).get(0).scrollHeight===b(a.target).get(0).clientHeight){a.preventDefault();b.fancybox[c>0?"prev":"next"]()}});b.support.opacity||f.addClass("fancybox-ie");if(M){t.addClass("fancybox-ie6");f.addClass("fancybox-ie6");b('<iframe id="fancybox-hide-sel-frame" src="'+(/^https/i.test(window.location.href||"")?"/js/fancybox/blank.gif":"about:blank")+'" scrolling="no" border="0" frameborder="0" tabindex="-1"></iframe>').prependTo(D)}}};
b.fn.fancybox.defaults={padding:10,margin:40,opacity:false,modal:false,cyclic:false,scrolling:"auto",width:560,height:340,autoScale:true,autoDimensions:true,centerOnScroll:false,ajax:{},swf:{wmode:"transparent"},hideOnOverlayClick:true,hideOnContentClick:false,overlayShow:true,overlayOpacity:0.7,overlayColor:"#777",titleShow:true,titlePosition:"float",titleFormat:null,titleFromAlt:false,transitionIn:"fade",transitionOut:"fade",speedIn:300,speedOut:300,changeSpeed:300,changeFade:"fast",easingIn:"swing",
-easingOut:"swing",showCloseButton:true,showNavArrows:true,enableEscapeButton:true,enableKeyboardNav:true,onStart:function(){},onCancel:function(){},onComplete:function(){},onCleanup:function(){},onClosed:function(){},onError:function(){}};b(document).ready(function(){b.fancybox.init()})})(jQuery); \ No newline at end of file
+easingOut:"swing",showCloseButton:true,showNavArrows:true,enableEscapeButton:true,enableKeyboardNav:true,onStart:function(){},onCancel:function(){},onComplete:function(){},onCleanup:function(){},onClosed:function(){},onError:function(){}};b(document).ready(function(){b.fancybox.init()})})(jQuery);
diff --git a/web/js/fixmystreet-old-box.js b/web/js/fixmystreet-old-box.js
new file mode 100644
index 000000000..72eeafb4d
--- /dev/null
+++ b/web/js/fixmystreet-old-box.js
@@ -0,0 +1,39 @@
+/*
+ * fixmystreet-old-box.js
+ * Create the 'email me updates' pop up box on old-style report display pages.
+ */
+
+$(function(){
+
+ if (!$('#email_alert_box').length) {
+ return;
+ }
+
+ var timer;
+ function email_alert_close() {
+ $('#email_alert_box').hide('fast');
+ }
+
+ $('#email_alert').click(function(e) {
+ e.preventDefault();
+ if ($('#email_alert_box').is(':visible')) {
+ email_alert_close();
+ } else {
+ var pos = $(this).position();
+ $('#email_alert_box').css( { 'left': ( pos.left - 20 ) + 'px', 'top': ( pos.top + 20 ) + 'px' } );
+ $('#email_alert_box').show('fast');
+ $('#alert_rznvy').focus();
+ }
+ }).hover(function() {
+ window.clearTimeout(timer);
+ }, function() {
+ timer = window.setTimeout(email_alert_close, 2000);
+ });
+
+ $('#email_alert_box').hover(function() {
+ window.clearTimeout(timer);
+ }, function() {
+ timer = window.setTimeout(email_alert_close, 2000);
+ });
+
+});
diff --git a/web/js/fixmystreet.js b/web/js/fixmystreet.js
index 834aa4ed3..36d47b5b2 100644
--- a/web/js/fixmystreet.js
+++ b/web/js/fixmystreet.js
@@ -1,51 +1,31 @@
/*
* fixmystreet.js
- * FixMyStreet JavaScript
+ * FixMyStreet JavaScript used by all cobrands.
+ * With the JavaScript written more proper like.
*/
-function form_category_onchange() {
- var cat = $('#form_category');
- var args = {
- category: cat.val()
- };
-
- if ( typeof fixmystreet !== 'undefined' ) {
- args.latitude = fixmystreet.latitude;
- args.longitude = fixmystreet.longitude;
- } else {
- args.latitude = $('input[name="latitude"]').val();
- args.longitude = $('input[name="longitude"]').val();
- }
-
- $.getJSON('/report/new/category_extras', args, function(data) {
- if ( data.category_extra ) {
- if ( $('#category_meta').size() ) {
- $('#category_meta').html( data.category_extra);
- } else {
- $('#form_category_row').after( data.category_extra );
- }
- } else {
- $('#category_meta').empty();
- }
- });
-}
+(function($){
+/*
+ Deal with changes to category by asking for details from the server.
+ */
$(function(){
- $('html').removeClass('no-js').addClass('js');
+ var $html = $('html');
+
+ // Add a class to the whole page saying JavaScript is enabled (for CSS and so on)
+ $html.removeClass('no-js').addClass('js');
+ // Preload the new report pin
+ document.createElement('img').src = '/i/pin-green.png';
+
+ // Focus on postcode box on front page
$('#pc').focus();
+ // In case we've come here by clicking back to a form that disabled a submit button
$('input[type=submit]').removeAttr('disabled');
- /*
- $('#mapForm').submit(function() {
- if (this.submit_problem) {
- $('input[type=submit]', this).prop("disabled", true);
- }
- return true;
- });
- */
+ // Questionnaire hide/showings
if (!$('#been_fixed_no').prop('checked') && !$('#been_fixed_unknown').prop('checked')) {
$('#another_qn').hide();
}
@@ -59,10 +39,7 @@ $(function(){
$('#another_qn').hide('fast');
});
- var timer;
- function email_alert_close() {
- $('#email_alert_box').hide('fast');
- }
+ // Form validation
// FIXME - needs to use translated string
jQuery.validator.addMethod('validCategory', function(value, element) {
@@ -85,12 +62,18 @@ $(function(){
},
messages: validation_strings,
onkeyup: false,
+ onfocusout: false,
errorElement: 'div',
errorClass: 'form-error',
// we do this to stop things jumping around on blur
success: function (err) { if ( form_submitted ) { err.addClass('label-valid').removeClass('label-valid-hidden').html( '&nbsp;' ); } else { err.addClass('label-valid-hidden'); } },
errorPlacement: function( error, element ) {
- element.parent('div').before( error );
+ // Different for old/new style design
+ if ($('.form-field').length) {
+ element.parent('div.form-field').before( error );
+ } else {
+ element.before( error );
+ }
},
submitHandler: function(form) {
if (form.submit_problem) {
@@ -102,7 +85,7 @@ $(function(){
// make sure we can see the error message when we focus on invalid elements
showErrors: function( errorMap, errorList ) {
if ( submitted && errorList.length ) {
- $(window).scrollTop( $(errorList[0].element).offset().top - 40 );
+ $(window).scrollTop( $(errorList[0].element).offset().top - 120 );
}
this.defaultShowErrors();
submitted = false;
@@ -112,83 +95,105 @@ $(function(){
$('input[type=submit]').click( function(e) { form_submitted = 1; } );
- /* set correct required status depending on what we submit
- * NB: need to add things to form_category as the JS updating
+ /* set correct required status depending on what we submit
+ * NB: need to add things to form_category as the JS updating
* of this we do after a map click removes them */
$('#submit_sign_in').click( function(e) {
$('#form_category').addClass('required validCategory').removeClass('valid');
$('#form_name').removeClass();
+ $('#form_first_name').removeClass();
+ $('#form_last_name').removeClass();
+ $('#form_fms_extra_title').removeClass();
} );
- $('#submit_register').click( function(e) {
+ $('#submit_register').click( function(e) {
$('#form_category').addClass('required validCategory').removeClass('valid');
$('#form_name').addClass('required validName');
+ $('#form_first_name').addClass('required');
+ $('#form_last_name').addClass('required');
+ $('#form_fms_extra_title').addClass('required');
} );
- $('#problem_submit > input[type="submit"]').click( function(e) {
+ $('#problem_submit > input[type="submit"]').click( function(e) {
$('#form_category').addClass('required validCategory').removeClass('valid');
$('#form_name').addClass('required validName');
+ $('#form_first_name').addClass('required');
+ $('#form_last_name').addClass('required');
+ $('#form_fms_extra_title').addClass('required');
} );
- $('#update_post').click( function(e) {
+ $('#update_post').click( function(e) {
$('#form_name').addClass('required').removeClass('valid');
} );
- $('#email_alert').click(function(e) {
- if (!$('#email_alert_box').length) {
- return true;
- }
- e.preventDefault();
- if ($('#email_alert_box').is(':visible')) {
- email_alert_close();
- } else {
- var pos = $(this).position();
- $('#email_alert_box').css( { 'left': ( pos.left - 20 ) + 'px', 'top': ( pos.top + 20 ) + 'px' } );
- $('#email_alert_box').show('fast');
- $('#alert_rznvy').focus();
- }
- }).hover(function() {
- window.clearTimeout(timer);
- }, function() {
- timer = window.setTimeout(email_alert_close, 2000);
- });
-
- $('#email_alert_box').hover(function() {
- window.clearTimeout(timer);
- }, function() {
- timer = window.setTimeout(email_alert_close, 2000);
- });
-
- // Using delegate here because we *might* be running under a cobrand which isn't jQuery 1.7+
- // Delegation is necessary because #form_category may be replaced during the lifetime of the page
- $("#problem_form").delegate("select#form_category", "change", form_category_onchange );
-
// Geolocation
if (geo_position_js.init()) {
- $('#postcodeForm').append('<p id="geolocate_para">Or <a href="#" id="geolocate_link">locate me automatically</a>').css({ "padding-bottom": "0.5em" });
+ if ($('body.frontpage').length) {
+ $('#postcodeForm').after('<a href="#" id="geolocate_link">&hellip; or locate me automatically</a>');
+ } else{
+ $('#postcodeForm').append('<a href="#" id="geolocate_link">&hellip; or locate me automatically</a>');
+ }
$('#geolocate_link').click(function(e) {
+ var $link = $(this);
e.preventDefault();
// Spinny thing!
- $('#geolocate_para').append(' <img src="/i/flower.gif" alt="" align="bottom">');
+ if($('.mobile').length){
+ $link.append(' <img src="/cobrands/fixmystreet/images/spinner-black.gif" alt="" align="bottom">');
+ }else{
+ $link.append(' <img src="/cobrands/fixmystreet/images/spinner-yellow.gif" alt="" align="bottom">');
+ }
geo_position_js.getCurrentPosition(function(pos) {
- $('#geolocate_para img').remove();
+ $link.find('img').remove();
var latitude = pos.coords.latitude;
var longitude = pos.coords.longitude;
location.href = '/around?latitude=' + latitude + ';longitude=' + longitude;
}, function(err) {
- $('#geolocate_para img').remove();
+ $link.find('img').remove();
if (err.code == 1) { // User said no
+ $link.html("You declined; please fill in the box above");
} else if (err.code == 2) { // No position
- $('#geolocate_para').html("Could not look up location");
+ $link.html("Could not look up location");
} else if (err.code == 3) { // Too long
- $('#geolocate_para').html("No result returned");
+ $link.html("No result returned");
} else { // Unknown
- $('#geolocate_para').html("Unknown error");
+ $link.html("Unknown error");
}
}, {
+ enableHighAccuracy: true,
timeout: 10000
});
});
}
+ // Delegation is necessary because #form_category may be replaced during the lifetime of the page
+ $("#problem_form").on("change.category", "select#form_category", function(){
+ var args = {
+ category: $(this).val()
+ };
+
+ if ( typeof fixmystreet !== 'undefined' ) {
+ args.latitude = fixmystreet.latitude;
+ args.longitude = fixmystreet.longitude;
+ } else {
+ args.latitude = $('input[name="latitude"]').val();
+ args.longitude = $('input[name="longitude"]').val();
+ }
+
+ $.getJSON('/report/new/category_extras', args, function(data) {
+ var $category_meta = $('#category_meta');
+ if ( data.category_extra ) {
+ if ( $category_meta.length ) {
+ $category_meta.html( data.category_extra );
+ } else {
+ $('#form_category_row').after( data.category_extra );
+ }
+ } else {
+ $category_meta.empty();
+ }
+ });
+ });
+
});
+
+})(jQuery);
+
diff --git a/web/js/map-OpenLayers.js b/web/js/map-OpenLayers.js
index d73e2bfc8..d98994d84 100644
--- a/web/js/map-OpenLayers.js
+++ b/web/js/map-OpenLayers.js
@@ -7,6 +7,33 @@ function fixmystreet_update_pin(lonlat) {
);
document.getElementById('fixmystreet.latitude').value = lonlat.lat || lonlat.y;
document.getElementById('fixmystreet.longitude').value = lonlat.lon || lonlat.x;
+
+ $.getJSON('/report/new/ajax', {
+ latitude: $('#fixmystreet\\.latitude').val(),
+ longitude: $('#fixmystreet\\.longitude').val()
+ }, function(data) {
+ if (data.error) {
+ if (!$('#side-form-error').length) {
+ $('<div id="side-form-error"/>').insertAfter($('#side-form'));
+ }
+ $('#side-form-error').html('<h1>Reporting a problem</h1><p>' + data.error + '</p>').show();
+ $('#side-form').hide();
+ return;
+ }
+ $('#side-form, #site-logo').show();
+ $('#councils_text').html(data.councils_text);
+ $('#form_category_row').html(data.category);
+ if ( data.extra_name_info && !$('#form_fms_extra_title').length ) {
+ // there might be a first name field on some cobrands
+ var lb = $('#form_first_name').prev();
+ if ( lb.length == 0 ) { lb = $('#form_name').prev(); }
+ lb.before(data.extra_name_info);
+ }
+ });
+
+ if (!$('#side-form-error').is(':visible')) {
+ $('#side-form, #site-logo').show();
+ }
}
function fixmystreet_activate_drag() {
@@ -56,7 +83,11 @@ function fixmystreet_onload() {
var bounds = area.getDataExtent();
if (bounds) {
var center = bounds.getCenterLonLat();
- fixmystreet.map.setCenter(center, fixmystreet.map.getZoomForExtent(bounds), false, true);
+ var z = fixmystreet.map.getZoomForExtent(bounds);
+ if ( z < 13 && $('html').hasClass('mobile') ) {
+ z = 13;
+ }
+ fixmystreet.map.setCenter(center, z, false, true);
}
});
}
@@ -151,7 +182,14 @@ function fixmystreet_onload() {
if ( fixmystreet.zoomToBounds ) {
var bounds = fixmystreet.markers.getDataExtent();
- if (bounds) { fixmystreet.map.zoomToExtent( bounds ); }
+ if (bounds) {
+ var center = bounds.getCenterLonLat();
+ var z = fixmystreet.map.getZoomForExtent(bounds);
+ if ( z < 13 && $('html').hasClass('mobile') ) {
+ z = 13;
+ }
+ fixmystreet.map.setCenter(center, z);
+ }
}
$('#hide_pins_link').click(function(e) {
@@ -238,8 +276,9 @@ $(function(){
if (fixmystreet.state_map && fixmystreet.state_map == 'full') {
// TODO Work better with window resizing, this is pretty 'set up' only at present
- var $content = $('.content'),
- q = ( $content.offset().left + $content.width() ) / 2;
+ var $content = $('.content'), mb = $('#map_box'),
+ q = ( $content.offset().left - mb.offset().left + $content.width() ) / 2;
+ if (q < 0) { q = 0; }
// Need to try and fake the 'centre' being 75% from the left
fixmystreet.map.pan(-q, -25, { animate: false });
fixmystreet.map.events.register("movestart", null, function(e){
@@ -421,7 +460,7 @@ OpenLayers.Control.Click = OpenLayers.Class(OpenLayers.Control, {
fixmystreet.markers.addFeatures( markers );
fixmystreet_activate_drag();
}
- fixmystreet_update_pin(lonlat);
+
// check to see if markers are visible. We click the
// link so that it updates the text in case they go
// back
@@ -429,23 +468,15 @@ OpenLayers.Control.Click = OpenLayers.Class(OpenLayers.Control, {
fixmystreet.state_pins_were_hidden = true;
$('#hide_pins_link').click();
}
+
+ // Store pin location in form fields, and check coverage of point
+ fixmystreet_update_pin(lonlat);
+
+ // Already did this first time map was clicked, so no need to do it again.
if (fixmystreet.page == 'new') {
return;
}
- $.getJSON('/report/new/ajax', {
- latitude: $('#fixmystreet\\.latitude').val(),
- longitude: $('#fixmystreet\\.longitude').val()
- }, function(data) {
- if (data.error) {
- // XXX If they then click back and click somewhere in the area, this error will still show.
- $('#side-form').html('<h1>Reporting a problem</h1><p>' + data.error + '</p>');
- return;
- }
- $('#councils_text').html(data.councils_text);
- $('#form_category_row').html(data.category);
- });
- $('#side-form, #site-logo').show();
fixmystreet.map.updateSize(); // might have done, and otherwise Firefox gets confused.
/* For some reason on IOS5 if you use the jQuery show method it
* doesn't display the JS validation error messages unless you do this
@@ -468,6 +499,8 @@ OpenLayers.Control.Click = OpenLayers.Class(OpenLayers.Control, {
// e.xy is relative to top left of map, which might not be top left of page
e.xy.x += bo.left;
e.xy.y += bo.top;
+
+ // 24 and 64 is the width and height of the marker pin
if (e.xy.y <= o.top || (e.xy.x >= o.left && e.xy.x <= o.left + w + 24 && e.xy.y >= o.top && e.xy.y <= o.top + h + 64)) {
// top of the page, pin hidden by header;
// or underneath where the new sidebar will appear
@@ -476,7 +509,7 @@ OpenLayers.Control.Click = OpenLayers.Class(OpenLayers.Control, {
fixmystreet.map.getProjectionObject()
);
var p = fixmystreet.map.getViewPortPxFromLonLat(lonlat);
- p.x -= ( o.left + w ) / 2;
+ p.x -= ( o.left - bo.left + w ) / 2;
lonlat = fixmystreet.map.getLonLatFromViewPortPx(p);
fixmystreet.map.panTo(lonlat);
}
diff --git a/web/js/map-bing-ol.js b/web/js/map-bing-ol.js
index 89b274b18..7d40f8afc 100644
--- a/web/js/map-bing-ol.js
+++ b/web/js/map-bing-ol.js
@@ -1,3 +1,5 @@
+var tile_base = [ [ '', 'a.', 'b.', 'c.' ], 'http://{S}tilma.mysociety.org/sv' ];
+
function set_map_config(perm) {
var permalink_id;
if ($('#map_permalink').length) {
@@ -17,6 +19,9 @@ function set_map_config(perm) {
new OpenLayers.Control.Permalink(permalink_id),
new OpenLayers.Control.PanZoomFMS({id: 'fms_pan_zoom' })
];
+ if (fixmystreet.map_type) {
+ tile_base = fixmystreet.map_type;
+ }
fixmystreet.map_type = OpenLayers.Layer.Bing;
}
@@ -36,7 +41,7 @@ OpenLayers.Layer.Bing = OpenLayers.Class(OpenLayers.Layer.XYZ, {
if (z >= 16) {
copyrights = 'Contains Ordnance Survey data &copy; Crown copyright and database right 2010';
} else {
- logo = '<a href="http://www.bing.com/maps/"><img border=0 src="http://dev.virtualearth.net/Branding/logo_powered_by.png"></a>';
+ logo = '<a href="http://www.bing.com/maps/"><img border=0 src="//dev.virtualearth.net/Branding/logo_powered_by.png"></a>';
copyrights = '&copy; 2011 <a href="http://www.bing.com/maps/">Microsoft</a>. &copy; AND, Navteq, Ordnance Survey';
}
this.attribution = OpenLayers.String.format(this.attributionTemplate, {
@@ -94,20 +99,18 @@ OpenLayers.Layer.Bing = OpenLayers.Class(OpenLayers.Layer.XYZ, {
var url;
if (z >= 16) {
- url = [
- "http://tilma.mysociety.org/sv/${z}/${x}/${y}.png",
- "http://a.tilma.mysociety.org/sv/${z}/${x}/${y}.png",
- "http://b.tilma.mysociety.org/sv/${z}/${x}/${y}.png",
- "http://c.tilma.mysociety.org/sv/${z}/${x}/${y}.png"
- ];
+ url = [];
+ for (var i=0; i< tile_base[0].length; i++) {
+ url.push( tile_base[1].replace('{S}', tile_base[0][i]) + "/${z}/${x}/${y}.png" );
+ }
} else {
var type = '';
if (z > 10) { type = '&productSet=mmOS'; }
url = [
- "http://ecn.t0.tiles.virtualearth.net/tiles/r${id}.png?g=701" + type,
- "http://ecn.t1.tiles.virtualearth.net/tiles/r${id}.png?g=701" + type,
- "http://ecn.t2.tiles.virtualearth.net/tiles/r${id}.png?g=701" + type,
- "http://ecn.t3.tiles.virtualearth.net/tiles/r${id}.png?g=701" + type
+ "//ecn.t0.tiles.virtualearth.net/tiles/r${id}.png?g=701" + type,
+ "//ecn.t1.tiles.virtualearth.net/tiles/r${id}.png?g=701" + type,
+ "//ecn.t2.tiles.virtualearth.net/tiles/r${id}.png?g=701" + type,
+ "//ecn.t3.tiles.virtualearth.net/tiles/r${id}.png?g=701" + type
];
}
var s = '' + x + y + z;
diff --git a/web/js/modernizr.custom.76759.js b/web/js/modernizr.custom.76759.js
deleted file mode 100644
index 20a22d8fa..000000000
--- a/web/js/modernizr.custom.76759.js
+++ /dev/null
@@ -1,4 +0,0 @@
-/* Modernizr 2.5.3 (Custom Build) | MIT & BSD
- * Build: http://www.modernizr.com/download/#-input-shiv-mq-teststyles-load
- */
-;window.Modernizr=function(a,b,c){function v(a){i.cssText=a}function w(a,b){return v(prefixes.join(a+";")+(b||""))}function x(a,b){return typeof a===b}function y(a,b){return!!~(""+a).indexOf(b)}function z(a,b,d){for(var e in a){var f=b[a[e]];if(f!==c)return d===!1?a[e]:x(f,"function")?f.bind(d||b):f}return!1}function A(){e.input=function(c){for(var d=0,e=c.length;d<e;d++)n[c[d]]=c[d]in j;return n.list&&(n.list=!!b.createElement("datalist")&&!!a.HTMLDataListElement),n}("autocomplete autofocus list placeholder max min multiple pattern required step".split(" "))}var d="2.5.3",e={},f=b.documentElement,g="modernizr",h=b.createElement(g),i=h.style,j=b.createElement("input"),k={}.toString,l={},m={},n={},o=[],p=o.slice,q,r=function(a,c,d,e){var h,i,j,k=b.createElement("div"),l=b.body,m=l?l:b.createElement("body");if(parseInt(d,10))while(d--)j=b.createElement("div"),j.id=e?e[d]:g+(d+1),k.appendChild(j);return h=["&#173;","<style>",a,"</style>"].join(""),k.id=g,m.innerHTML+=h,m.appendChild(k),l||(m.style.background="",f.appendChild(m)),i=c(k,a),l?k.parentNode.removeChild(k):m.parentNode.removeChild(m),!!i},s=function(b){var c=a.matchMedia||a.msMatchMedia;if(c)return c(b).matches;var d;return r("@media "+b+" { #"+g+" { position: absolute; } }",function(b){d=(a.getComputedStyle?getComputedStyle(b,null):b.currentStyle)["position"]=="absolute"}),d},t={}.hasOwnProperty,u;!x(t,"undefined")&&!x(t.call,"undefined")?u=function(a,b){return t.call(a,b)}:u=function(a,b){return b in a&&x(a.constructor.prototype[b],"undefined")},Function.prototype.bind||(Function.prototype.bind=function(b){var c=this;if(typeof c!="function")throw new TypeError;var d=p.call(arguments,1),e=function(){if(this instanceof e){var a=function(){};a.prototype=c.prototype;var f=new a,g=c.apply(f,d.concat(p.call(arguments)));return Object(g)===g?g:f}return c.apply(b,d.concat(p.call(arguments)))};return e});for(var B in l)u(l,B)&&(q=B.toLowerCase(),e[q]=l[B](),o.push((e[q]?"":"no-")+q));return e.input||A(),v(""),h=j=null,function(a,b){function g(a,b){var c=a.createElement("p"),d=a.getElementsByTagName("head")[0]||a.documentElement;return c.innerHTML="x<style>"+b+"</style>",d.insertBefore(c.lastChild,d.firstChild)}function h(){var a=k.elements;return typeof a=="string"?a.split(" "):a}function i(a){var b={},c=a.createElement,e=a.createDocumentFragment,f=e();a.createElement=function(a){var e=(b[a]||(b[a]=c(a))).cloneNode();return k.shivMethods&&e.canHaveChildren&&!d.test(a)?f.appendChild(e):e},a.createDocumentFragment=Function("h,f","return function(){var n=f.cloneNode(),c=n.createElement;h.shivMethods&&("+h().join().replace(/\w+/g,function(a){return b[a]=c(a),f.createElement(a),'c("'+a+'")'})+");return n}")(k,f)}function j(a){var b;return a.documentShived?a:(k.shivCSS&&!e&&(b=!!g(a,"article,aside,details,figcaption,figure,footer,header,hgroup,nav,section{display:block}audio{display:none}canvas,video{display:inline-block;*display:inline;*zoom:1}[hidden]{display:none}audio[controls]{display:inline-block;*display:inline;*zoom:1}mark{background:#FF0;color:#000}")),f||(b=!i(a)),b&&(a.documentShived=b),a)}var c=a.html5||{},d=/^<|^(?:button|form|map|select|textarea)$/i,e,f;(function(){var a=b.createElement("a");a.innerHTML="<xyz></xyz>",e="hidden"in a,f=a.childNodes.length==1||function(){try{b.createElement("a")}catch(a){return!0}var c=b.createDocumentFragment();return typeof c.cloneNode=="undefined"||typeof c.createDocumentFragment=="undefined"||typeof c.createElement=="undefined"}()})();var k={elements:c.elements||"abbr article aside audio bdi canvas data datalist details figcaption figure footer header hgroup mark meter nav output progress section summary time video",shivCSS:c.shivCSS!==!1,shivMethods:c.shivMethods!==!1,type:"default",shivDocument:j};a.html5=k,j(b)}(this,b),e._version=d,e.mq=s,e.testStyles=r,e}(this,this.document),function(a,b,c){function d(a){return o.call(a)=="[object Function]"}function e(a){return typeof a=="string"}function f(){}function g(a){return!a||a=="loaded"||a=="complete"||a=="uninitialized"}function h(){var a=p.shift();q=1,a?a.t?m(function(){(a.t=="c"?B.injectCss:B.injectJs)(a.s,0,a.a,a.x,a.e,1)},0):(a(),h()):q=0}function i(a,c,d,e,f,i,j){function k(b){if(!o&&g(l.readyState)&&(u.r=o=1,!q&&h(),l.onload=l.onreadystatechange=null,b)){a!="img"&&m(function(){t.removeChild(l)},50);for(var d in y[c])y[c].hasOwnProperty(d)&&y[c][d].onload()}}var j=j||B.errorTimeout,l={},o=0,r=0,u={t:d,s:c,e:f,a:i,x:j};y[c]===1&&(r=1,y[c]=[],l=b.createElement(a)),a=="object"?l.data=c:(l.src=c,l.type=a),l.width=l.height="0",l.onerror=l.onload=l.onreadystatechange=function(){k.call(this,r)},p.splice(e,0,u),a!="img"&&(r||y[c]===2?(t.insertBefore(l,s?null:n),m(k,j)):y[c].push(l))}function j(a,b,c,d,f){return q=0,b=b||"j",e(a)?i(b=="c"?v:u,a,b,this.i++,c,d,f):(p.splice(this.i++,0,a),p.length==1&&h()),this}function k(){var a=B;return a.loader={load:j,i:0},a}var l=b.documentElement,m=a.setTimeout,n=b.getElementsByTagName("script")[0],o={}.toString,p=[],q=0,r="MozAppearance"in l.style,s=r&&!!b.createRange().compareNode,t=s?l:n.parentNode,l=a.opera&&o.call(a.opera)=="[object Opera]",l=!!b.attachEvent&&!l,u=r?"object":l?"script":"img",v=l?"script":u,w=Array.isArray||function(a){return o.call(a)=="[object Array]"},x=[],y={},z={timeout:function(a,b){return b.length&&(a.timeout=b[0]),a}},A,B;B=function(a){function b(a){var a=a.split("!"),b=x.length,c=a.pop(),d=a.length,c={url:c,origUrl:c,prefixes:a},e,f,g;for(f=0;f<d;f++)g=a[f].split("="),(e=z[g.shift()])&&(c=e(c,g));for(f=0;f<b;f++)c=x[f](c);return c}function g(a,e,f,g,i){var j=b(a),l=j.autoCallback;j.url.split(".").pop().split("?").shift(),j.bypass||(e&&(e=d(e)?e:e[a]||e[g]||e[a.split("/").pop().split("?")[0]]||h),j.instead?j.instead(a,e,f,g,i):(y[j.url]?j.noexec=!0:y[j.url]=1,f.load(j.url,j.forceCSS||!j.forceJS&&"css"==j.url.split(".").pop().split("?").shift()?"c":c,j.noexec,j.attrs,j.timeout),(d(e)||d(l))&&f.load(function(){k(),e&&e(j.origUrl,i,g),l&&l(j.origUrl,i,g),y[j.url]=2})))}function i(a,b){function c(a,c){if(a){if(e(a))c||(j=function(){var a=[].slice.call(arguments);k.apply(this,a),l()}),g(a,j,b,0,h);else if(Object(a)===a)for(n in m=function(){var b=0,c;for(c in a)a.hasOwnProperty(c)&&b++;return b}(),a)a.hasOwnProperty(n)&&(!c&&!--m&&(d(j)?j=function(){var a=[].slice.call(arguments);k.apply(this,a),l()}:j[n]=function(a){return function(){var b=[].slice.call(arguments);a&&a.apply(this,b),l()}}(k[n])),g(a[n],j,b,n,h))}else!c&&l()}var h=!!a.test,i=a.load||a.both,j=a.callback||f,k=j,l=a.complete||f,m,n;c(h?a.yep:a.nope,!!i),i&&c(i)}var j,l,m=this.yepnope.loader;if(e(a))g(a,0,m,0);else if(w(a))for(j=0;j<a.length;j++)l=a[j],e(l)?g(l,0,m,0):w(l)?B(l):Object(l)===l&&i(l,m);else Object(a)===a&&i(a,m)},B.addPrefix=function(a,b){z[a]=b},B.addFilter=function(a){x.push(a)},B.errorTimeout=1e4,b.readyState==null&&b.addEventListener&&(b.readyState="loading",b.addEventListener("DOMContentLoaded",A=function(){b.removeEventListener("DOMContentLoaded",A,0),b.readyState="complete"},0)),a.yepnope=k(),a.yepnope.executeStack=h,a.yepnope.injectJs=function(a,c,d,e,i,j){var k=b.createElement("script"),l,o,e=e||B.errorTimeout;k.src=a;for(o in d)k.setAttribute(o,d[o]);c=j?h:c||f,k.onreadystatechange=k.onload=function(){!l&&g(k.readyState)&&(l=1,c(),k.onload=k.onreadystatechange=null)},m(function(){l||(l=1,c(1))},e),i?k.onload():n.parentNode.insertBefore(k,n)},a.yepnope.injectCss=function(a,c,d,e,g,i){var e=b.createElement("link"),j,c=i?h:c||f;e.href=a,e.rel="stylesheet",e.type="text/css";for(j in d)e.setAttribute(j,d[j]);g||(n.parentNode.insertBefore(e,n),m(c,0))}}(this,document),Modernizr.load=function(){yepnope.apply(window,[].slice.call(arguments,0))}; \ No newline at end of file
diff --git a/web/js/modernizr.custom.js b/web/js/modernizr.custom.js
new file mode 100644
index 000000000..c4d6ffdfc
--- /dev/null
+++ b/web/js/modernizr.custom.js
@@ -0,0 +1,4 @@
+/* Modernizr 2.5.3 (Custom Build) | MIT & BSD
+ * Build: http://www.modernizr.com/download/#-shiv-load
+ */
+;window.Modernizr=function(a,b,c){function t(a){i.cssText=a}function u(a,b){return t(prefixes.join(a+";")+(b||""))}function v(a,b){return typeof a===b}function w(a,b){return!!~(""+a).indexOf(b)}function x(a,b,d){for(var e in a){var f=b[a[e]];if(f!==c)return d===!1?a[e]:v(f,"function")?f.bind(d||b):f}return!1}var d="2.5.3",e={},f=b.documentElement,g="modernizr",h=b.createElement(g),i=h.style,j,k={}.toString,l={},m={},n={},o=[],p=o.slice,q,r={}.hasOwnProperty,s;!v(r,"undefined")&&!v(r.call,"undefined")?s=function(a,b){return r.call(a,b)}:s=function(a,b){return b in a&&v(a.constructor.prototype[b],"undefined")},Function.prototype.bind||(Function.prototype.bind=function(b){var c=this;if(typeof c!="function")throw new TypeError;var d=p.call(arguments,1),e=function(){if(this instanceof e){var a=function(){};a.prototype=c.prototype;var f=new a,g=c.apply(f,d.concat(p.call(arguments)));return Object(g)===g?g:f}return c.apply(b,d.concat(p.call(arguments)))};return e});for(var y in l)s(l,y)&&(q=y.toLowerCase(),e[q]=l[y](),o.push((e[q]?"":"no-")+q));return t(""),h=j=null,function(a,b){function g(a,b){var c=a.createElement("p"),d=a.getElementsByTagName("head")[0]||a.documentElement;return c.innerHTML="x<style>"+b+"</style>",d.insertBefore(c.lastChild,d.firstChild)}function h(){var a=k.elements;return typeof a=="string"?a.split(" "):a}function i(a){var b={},c=a.createElement,e=a.createDocumentFragment,f=e();a.createElement=function(a){var e=(b[a]||(b[a]=c(a))).cloneNode();return k.shivMethods&&e.canHaveChildren&&!d.test(a)?f.appendChild(e):e},a.createDocumentFragment=Function("h,f","return function(){var n=f.cloneNode(),c=n.createElement;h.shivMethods&&("+h().join().replace(/\w+/g,function(a){return b[a]=c(a),f.createElement(a),'c("'+a+'")'})+");return n}")(k,f)}function j(a){var b;return a.documentShived?a:(k.shivCSS&&!e&&(b=!!g(a,"article,aside,details,figcaption,figure,footer,header,hgroup,nav,section{display:block}audio{display:none}canvas,video{display:inline-block;*display:inline;*zoom:1}[hidden]{display:none}audio[controls]{display:inline-block;*display:inline;*zoom:1}mark{background:#FF0;color:#000}")),f||(b=!i(a)),b&&(a.documentShived=b),a)}var c=a.html5||{},d=/^<|^(?:button|form|map|select|textarea)$/i,e,f;(function(){var a=b.createElement("a");a.innerHTML="<xyz></xyz>",e="hidden"in a,f=a.childNodes.length==1||function(){try{b.createElement("a")}catch(a){return!0}var c=b.createDocumentFragment();return typeof c.cloneNode=="undefined"||typeof c.createDocumentFragment=="undefined"||typeof c.createElement=="undefined"}()})();var k={elements:c.elements||"abbr article aside audio bdi canvas data datalist details figcaption figure footer header hgroup mark meter nav output progress section summary time video",shivCSS:c.shivCSS!==!1,shivMethods:c.shivMethods!==!1,type:"default",shivDocument:j};a.html5=k,j(b)}(this,b),e._version=d,e}(this,this.document),function(a,b,c){function d(a){return o.call(a)=="[object Function]"}function e(a){return typeof a=="string"}function f(){}function g(a){return!a||a=="loaded"||a=="complete"||a=="uninitialized"}function h(){var a=p.shift();q=1,a?a.t?m(function(){(a.t=="c"?B.injectCss:B.injectJs)(a.s,0,a.a,a.x,a.e,1)},0):(a(),h()):q=0}function i(a,c,d,e,f,i,j){function k(b){if(!o&&g(l.readyState)&&(u.r=o=1,!q&&h(),l.onload=l.onreadystatechange=null,b)){a!="img"&&m(function(){t.removeChild(l)},50);for(var d in y[c])y[c].hasOwnProperty(d)&&y[c][d].onload()}}var j=j||B.errorTimeout,l={},o=0,r=0,u={t:d,s:c,e:f,a:i,x:j};y[c]===1&&(r=1,y[c]=[],l=b.createElement(a)),a=="object"?l.data=c:(l.src=c,l.type=a),l.width=l.height="0",l.onerror=l.onload=l.onreadystatechange=function(){k.call(this,r)},p.splice(e,0,u),a!="img"&&(r||y[c]===2?(t.insertBefore(l,s?null:n),m(k,j)):y[c].push(l))}function j(a,b,c,d,f){return q=0,b=b||"j",e(a)?i(b=="c"?v:u,a,b,this.i++,c,d,f):(p.splice(this.i++,0,a),p.length==1&&h()),this}function k(){var a=B;return a.loader={load:j,i:0},a}var l=b.documentElement,m=a.setTimeout,n=b.getElementsByTagName("script")[0],o={}.toString,p=[],q=0,r="MozAppearance"in l.style,s=r&&!!b.createRange().compareNode,t=s?l:n.parentNode,l=a.opera&&o.call(a.opera)=="[object Opera]",l=!!b.attachEvent&&!l,u=r?"object":l?"script":"img",v=l?"script":u,w=Array.isArray||function(a){return o.call(a)=="[object Array]"},x=[],y={},z={timeout:function(a,b){return b.length&&(a.timeout=b[0]),a}},A,B;B=function(a){function b(a){var a=a.split("!"),b=x.length,c=a.pop(),d=a.length,c={url:c,origUrl:c,prefixes:a},e,f,g;for(f=0;f<d;f++)g=a[f].split("="),(e=z[g.shift()])&&(c=e(c,g));for(f=0;f<b;f++)c=x[f](c);return c}function g(a,e,f,g,i){var j=b(a),l=j.autoCallback;j.url.split(".").pop().split("?").shift(),j.bypass||(e&&(e=d(e)?e:e[a]||e[g]||e[a.split("/").pop().split("?")[0]]||h),j.instead?j.instead(a,e,f,g,i):(y[j.url]?j.noexec=!0:y[j.url]=1,f.load(j.url,j.forceCSS||!j.forceJS&&"css"==j.url.split(".").pop().split("?").shift()?"c":c,j.noexec,j.attrs,j.timeout),(d(e)||d(l))&&f.load(function(){k(),e&&e(j.origUrl,i,g),l&&l(j.origUrl,i,g),y[j.url]=2})))}function i(a,b){function c(a,c){if(a){if(e(a))c||(j=function(){var a=[].slice.call(arguments);k.apply(this,a),l()}),g(a,j,b,0,h);else if(Object(a)===a)for(n in m=function(){var b=0,c;for(c in a)a.hasOwnProperty(c)&&b++;return b}(),a)a.hasOwnProperty(n)&&(!c&&!--m&&(d(j)?j=function(){var a=[].slice.call(arguments);k.apply(this,a),l()}:j[n]=function(a){return function(){var b=[].slice.call(arguments);a&&a.apply(this,b),l()}}(k[n])),g(a[n],j,b,n,h))}else!c&&l()}var h=!!a.test,i=a.load||a.both,j=a.callback||f,k=j,l=a.complete||f,m,n;c(h?a.yep:a.nope,!!i),i&&c(i)}var j,l,m=this.yepnope.loader;if(e(a))g(a,0,m,0);else if(w(a))for(j=0;j<a.length;j++)l=a[j],e(l)?g(l,0,m,0):w(l)?B(l):Object(l)===l&&i(l,m);else Object(a)===a&&i(a,m)},B.addPrefix=function(a,b){z[a]=b},B.addFilter=function(a){x.push(a)},B.errorTimeout=1e4,b.readyState==null&&b.addEventListener&&(b.readyState="loading",b.addEventListener("DOMContentLoaded",A=function(){b.removeEventListener("DOMContentLoaded",A,0),b.readyState="complete"},0)),a.yepnope=k(),a.yepnope.executeStack=h,a.yepnope.injectJs=function(a,c,d,e,i,j){var k=b.createElement("script"),l,o,e=e||B.errorTimeout;k.src=a;for(o in d)k.setAttribute(o,d[o]);c=j?h:c||f,k.onreadystatechange=k.onload=function(){!l&&g(k.readyState)&&(l=1,c(),k.onload=k.onreadystatechange=null)},m(function(){l||(l=1,c(1))},e),i?k.onload():n.parentNode.insertBefore(k,n)},a.yepnope.injectCss=function(a,c,d,e,g,i){var e=b.createElement("link"),j,c=i?h:c||f;e.href=a,e.rel="stylesheet",e.type="text/css";for(j in d)e.setAttribute(j,d[j]);g||(n.parentNode.insertBefore(e,n),m(c,0))}}(this,document),Modernizr.load=function(){yepnope.apply(window,[].slice.call(arguments,0))}; \ No newline at end of file