aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.gitignore2
-rw-r--r--.travis.yml1
-rwxr-xr-xbin/install-as-user1
-rwxr-xr-xbin/make_css2
-rwxr-xr-xbin/open311-populate-service-list1
-rwxr-xr-xbin/oxfordshire/open311_service_request.cgi427
-rwxr-xr-xbin/oxfordshire/open311_service_request_update.cgi126
-rw-r--r--bin/oxfordshire/open311_services.pm150
-rwxr-xr-xbin/send-comments28
m---------commonlib0
-rw-r--r--conf/crontab.ugly10
-rw-r--r--conf/general.yml-example4
-rw-r--r--db/schema.sql18
-rw-r--r--db/schema_0025-add_more_statuses_to_problem.sql83
-rw-r--r--db/schema_0026-add_send_extended_comments_to_open311conf.sql6
-rw-r--r--db/schema_0027-add_sub_category_to_problem.sql6
-rw-r--r--perllib/FixMyStreet/App.pm3
-rw-r--r--perllib/FixMyStreet/App/Controller/Admin.pm17
-rw-r--r--perllib/FixMyStreet/App/Controller/Contact.pm7
-rw-r--r--perllib/FixMyStreet/App/Controller/Dashboard.pm8
-rwxr-xr-xperllib/FixMyStreet/App/Controller/JS.pm2
-rw-r--r--perllib/FixMyStreet/App/Controller/Open311.pm2
-rw-r--r--perllib/FixMyStreet/App/Controller/Report.pm2
-rw-r--r--perllib/FixMyStreet/App/Controller/Report/New.pm35
-rw-r--r--perllib/FixMyStreet/App/Controller/Report/Update.pm18
-rw-r--r--perllib/FixMyStreet/App/Controller/Reports.pm13
-rw-r--r--perllib/FixMyStreet/Cobrand/Bromley.pm4
-rw-r--r--perllib/FixMyStreet/Cobrand/Default.pm70
-rw-r--r--perllib/FixMyStreet/Cobrand/FixMyBarangay.pm12
-rw-r--r--perllib/FixMyStreet/Cobrand/LichfieldDC.pm13
-rw-r--r--perllib/FixMyStreet/Cobrand/Oxfordshire.pm55
-rw-r--r--perllib/FixMyStreet/Cobrand/SeeSomething.pm148
-rw-r--r--perllib/FixMyStreet/Cobrand/Stevenage.pm1
-rw-r--r--perllib/FixMyStreet/Cobrand/UKCouncils.pm16
-rw-r--r--perllib/FixMyStreet/DB/Result/Body.pm2
-rw-r--r--perllib/FixMyStreet/DB/Result/Comment.pm9
-rw-r--r--perllib/FixMyStreet/DB/Result/Problem.pm113
-rw-r--r--perllib/FixMyStreet/DB/ResultSet/AlertType.pm5
-rw-r--r--perllib/FixMyStreet/DB/ResultSet/Problem.pm52
-rw-r--r--perllib/FixMyStreet/DB/ResultSet/Questionnaire.pm3
-rw-r--r--perllib/FixMyStreet/EmailSend.pm5
-rw-r--r--perllib/FixMyStreet/SendReport/Email.pm8
-rw-r--r--perllib/FixMyStreet/SendReport/Open311.pm46
-rw-r--r--perllib/Open311.pm54
-rw-r--r--perllib/Open311/GetServiceRequestUpdates.pm60
-rw-r--r--perllib/Open311/PopulateServiceList.pm2
-rw-r--r--t/app/controller/dashboard.t54
-rw-r--r--t/app/controller/questionnaire.t16
-rw-r--r--t/app/controller/report_display.t42
-rw-r--r--t/app/controller/report_new.t272
-rw-r--r--t/app/controller/report_updates.t491
-rw-r--r--t/app/controller/rss.t5
-rw-r--r--t/app/helpers/send_email.t2
-rw-r--r--t/app/model/problem.t77
-rw-r--r--t/app/model/questionnaire.t16
-rw-r--r--t/app/sendreport/email.t1
-rw-r--r--t/map/tilma/original.t16
-rw-r--r--t/open311.t125
-rw-r--r--t/open311/getservicerequestupdates.t174
-rw-r--r--templates/email/default/confirm_report_sent.txt9
-rw-r--r--templates/email/seesomething/confirm_report_sent.txt10
-rw-r--r--templates/email/seesomething/submit.txt25
-rw-r--r--templates/web/bromley/report/display.html8
-rw-r--r--templates/web/default/admin/body-form.html5
-rw-r--r--templates/web/default/around/around_index.html54
-rwxr-xr-xtemplates/web/default/around/display_location.html6
-rw-r--r--templates/web/default/common_header_tags.html1
-rw-r--r--templates/web/default/dashboard/index.html18
-rw-r--r--templates/web/default/front/stats.html2
-rw-r--r--templates/web/default/index-steps.html19
-rw-r--r--templates/web/default/index.html6
-rw-r--r--templates/web/default/js/validation_rules.html7
-rw-r--r--templates/web/default/questionnaire/index.html4
-rw-r--r--templates/web/default/report/_main.html2
-rw-r--r--templates/web/default/report/banner.html2
-rw-r--r--templates/web/default/report/display.html13
-rw-r--r--templates/web/default/report/new/category.html2
-rw-r--r--templates/web/default/report/new/fill_in_details_form.html2
-rw-r--r--templates/web/default/report/update-form.html8
-rw-r--r--templates/web/default/report/updates.html21
-rw-r--r--templates/web/default/report_created.html9
-rwxr-xr-xtemplates/web/default/reports/body.html7
-rwxr-xr-xtemplates/web/emptyhomes/around/display_location.html56
-rw-r--r--templates/web/emptyhomes/front/stats.html27
-rw-r--r--templates/web/emptyhomes/header.html1
-rw-r--r--templates/web/emptyhomes/index.html68
-rw-r--r--templates/web/emptyhomes/report/banner.html6
-rw-r--r--templates/web/emptyhomes/report/display.html32
-rw-r--r--templates/web/emptyhomes/report/new/councils_text_all.html2
-rwxr-xr-xtemplates/web/emptyhomes/reports/_ward-list.html0
-rwxr-xr-xtemplates/web/emptyhomes/reports/body.html73
-rwxr-xr-xtemplates/web/emptyhomes/reports/index.html9
-rw-r--r--templates/web/emptyhomes/tracking_code.html12
-rw-r--r--templates/web/fixmybarangay/faq/faq-en-gb.html54
-rw-r--r--templates/web/fixmybarangay/footer.html38
-rw-r--r--templates/web/fixmybarangay/report/_message_manager.html25
-rw-r--r--templates/web/fixmybarangay/report/new/councils_text.html4
-rwxr-xr-xtemplates/web/fixmybarangay/reports/index.html21
-rw-r--r--templates/web/fixmystreet/header.html5
-rw-r--r--templates/web/fixmystreet/report/banner.html6
-rw-r--r--templates/web/fixmystreet/report/new/fill_in_details_form.html14
-rw-r--r--templates/web/fixmystreet/report/update-form.html8
-rw-r--r--templates/web/oxfordshire/around/intro.html1
-rwxr-xr-xtemplates/web/oxfordshire/faq/faq-en-gb.html232
-rw-r--r--templates/web/oxfordshire/footer.html51
-rw-r--r--templates/web/oxfordshire/header.html94
-rw-r--r--templates/web/oxfordshire/report/new/councils_text_all.html18
-rw-r--r--templates/web/oxfordshire/report/new/fill_in_details_text.html6
-rw-r--r--templates/web/oxfordshire/report/new/notes.html10
-rw-r--r--templates/web/seesomething/admin/footer.html7
-rw-r--r--templates/web/seesomething/admin/header.html2
-rw-r--r--templates/web/seesomething/admin/stats.html63
-rw-r--r--templates/web/seesomething/around/around_index.html24
-rw-r--r--templates/web/seesomething/around/display_location.html49
-rw-r--r--templates/web/seesomething/around/postcode_form.html17
-rw-r--r--templates/web/seesomething/auth/general.html46
-rw-r--r--templates/web/seesomething/auth/sign_out.html7
-rw-r--r--templates/web/seesomething/footer.html22
-rw-r--r--templates/web/seesomething/front/stats.html0
-rw-r--r--templates/web/seesomething/front/tips.html3
-rw-r--r--templates/web/seesomething/index.html43
-rw-r--r--templates/web/seesomething/js/translation_strings.html15
-rw-r--r--templates/web/seesomething/js/validation_rules.html13
-rw-r--r--templates/web/seesomething/report/display.html9
-rw-r--r--templates/web/seesomething/report/new/category.html14
-rw-r--r--templates/web/seesomething/report/new/fill_in_details_form.html104
-rw-r--r--templates/web/seesomething/report_created.html29
-rw-r--r--templates/web/seesomething/set_body_class.html1
-rw-r--r--templates/web/southampton/front/news.html9
-rw-r--r--templates/web/stevenage/around/intro.html2
-rw-r--r--web/cobrands/fixmybarangay/_colours.scss4
-rw-r--r--web/cobrands/fixmybarangay/base.scss36
-rw-r--r--web/cobrands/fixmybarangay/images/city6.pngbin227275 -> 0 bytes
-rw-r--r--web/cobrands/fixmybarangay/images/city7.pngbin126124 -> 0 bytes
-rw-r--r--web/cobrands/fixmybarangay/images/fmb-header.pngbin0 -> 44269 bytes
-rw-r--r--web/cobrands/fixmybarangay/layout.scss11
-rw-r--r--web/cobrands/fixmybarangay/message_manager.scss35
-rw-r--r--web/cobrands/fixmybarangay/message_manager_client.js87
-rw-r--r--web/cobrands/fixmystreet/_layout.scss9
-rw-r--r--web/cobrands/fixmystreet/fixmystreet.js14
-rw-r--r--web/cobrands/oxfordshire/_colours.scss16
-rw-r--r--web/cobrands/oxfordshire/base.scss40
-rw-r--r--web/cobrands/oxfordshire/config.rb25
-rwxr-xr-xweb/cobrands/oxfordshire/images/bg-y.jpgbin0 -> 1287 bytes
-rwxr-xr-xweb/cobrands/oxfordshire/images/bg.jpgbin0 -> 1590 bytes
-rw-r--r--web/cobrands/oxfordshire/images/divider1x32.pngbin0 -> 167 bytes
-rwxr-xr-xweb/cobrands/oxfordshire/images/dot6x6.jpgbin0 -> 1145 bytes
-rw-r--r--web/cobrands/oxfordshire/images/fms-logo-105x20.pngbin0 -> 2348 bytes
-rw-r--r--web/cobrands/oxfordshire/images/fms-logo-inverse.pngbin0 -> 1299 bytes
-rwxr-xr-xweb/cobrands/oxfordshire/images/footer.jpgbin0 -> 16093 bytes
-rwxr-xr-xweb/cobrands/oxfordshire/images/header.jpgbin0 -> 112470 bytes
-rwxr-xr-xweb/cobrands/oxfordshire/images/logo.jpgbin0 -> 12774 bytes
-rw-r--r--web/cobrands/oxfordshire/images/tab-green.pngbin0 -> 819 bytes
-rw-r--r--web/cobrands/oxfordshire/images/tabs-featured-on.pngbin0 -> 162 bytes
-rw-r--r--web/cobrands/oxfordshire/images/tabs-featured.pngbin0 -> 175 bytes
-rw-r--r--web/cobrands/oxfordshire/layout.scss154
-rw-r--r--web/cobrands/oxfordshire/oxfordshire.scss184
-rw-r--r--web/cobrands/oxfordshire/position_map.js19
-rw-r--r--web/cobrands/southampton/css.scss4
-rw-r--r--web/js/fixmystreet.js8
160 files changed, 4527 insertions, 652 deletions
diff --git a/.gitignore b/.gitignore
index 27d7ced66..862e1b7b3 100644
--- a/.gitignore
+++ b/.gitignore
@@ -28,9 +28,11 @@ FixMyBarangay.po
/web/cobrands/fixmystreet/*.css
/web/cobrands/bromley/*.css
/web/cobrands/fixmybarangay/*.css
+/web/cobrands/oxfordshire/*.css
/web/cobrands/stevenage/*.css
/web/cobrands/barnet/*.css
/web/cobrands/zurich/*.css
+/web/cobrands/seesomething
/web/photo
/local
diff --git a/.travis.yml b/.travis.yml
index dcf35ab60..542ffd816 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -33,7 +33,6 @@ before_script:
-e "s,cobrand_two: 'hostname_substring2',fixmystreet: 'localhost',"
-e "s,(BASE_URL:) 'http://www.example.org',\\1 'http://localhost',"
-e "s,(MAPIT_URL:) '',\\1 'http://mapit.mysociety.org/',"
- -e "s,(CONTACT_EMAIL:) 'team,\\1 'person,"
conf/general.yml-example > conf/general.yml
- ./bin/cron-wrapper ./bin/make_po FixMyStreet-EmptyHomes
- ./bin/cron-wrapper ./bin/make_emptyhomes_welsh_po
diff --git a/bin/install-as-user b/bin/install-as-user
index 2656195f4..2e0816966 100755
--- a/bin/install-as-user
+++ b/bin/install-as-user
@@ -86,6 +86,7 @@ sed -r \
-e "s,^( *BASE_URL:).*,\\1 'http://$HOST'," \
-e "s,^( *EMAIL_DOMAIN:).*,\\1 '$HOST'," \
-e "s,^( *CONTACT_EMAIL:).*,\\1 'help@$HOST'," \
+ -e "s,^( *DO_NOT_REPLY_EMAIL:).*,\\1 'help@$HOST'," \
conf/general.yml-example > conf/general.yml
# Create the database if it doesn't exist:
diff --git a/bin/make_css b/bin/make_css
index a86fd4f0d..cd78e7f13 100755
--- a/bin/make_css
+++ b/bin/make_css
@@ -14,7 +14,7 @@
DIRECTORY=$(cd `dirname $0`/../web && pwd)
# FixMyStreet uses compass
-NEWSTYLE=${1:-"fixmystreet bromley fixmybarangay barnet zurich default stevenage"}
+NEWSTYLE=${1:-"fixmystreet bromley fixmybarangay barnet zurich default stevenage oxfordshire"}
NEWSTYLE_REGEX=${NEWSTYLE// /\\|}
for site in $NEWSTYLE; do
compass compile --output-style compressed $DIRECTORY/cobrands/$site
diff --git a/bin/open311-populate-service-list b/bin/open311-populate-service-list
index c72c04e65..be1ace3b9 100755
--- a/bin/open311-populate-service-list
+++ b/bin/open311-populate-service-list
@@ -15,6 +15,7 @@ my ($opt, $usage) = describe_options(
print($usage->text), exit if $opt->help;
my $bodies = FixMyStreet::App->model('DB::Body')->search( {
+ id => { '!=', 2237 }, # XXX Until Oxfordshire does do so
send_method => 'Open311'
} );
my $verbose = 0;
diff --git a/bin/oxfordshire/open311_service_request.cgi b/bin/oxfordshire/open311_service_request.cgi
new file mode 100755
index 000000000..af0c35ca0
--- /dev/null
+++ b/bin/oxfordshire/open311_service_request.cgi
@@ -0,0 +1,427 @@
+#!/usr/bin/perl
+
+# script for absobring incoming Open311 service request POSTs and
+# passing them into Bentley EXOR backend via create_enquiry stored
+# procedure.
+#
+# mySociety: http://code.fixmystreet.com/
+#-----------------------------------------------------------------
+
+require 'open311_services.pm';
+use DBD::Oracle qw(:ora_types);
+### for local testing (no Oracle):
+### use constant { ORA_VARCHAR2=>1, ORA_DATE=>1, ORA_NUMBER=>1};
+
+my %PEM_BOUND_VAR_TYPES = get_pem_field_types();
+
+my $ERR_MSG = 'error'; # unique key in data hash
+
+# incoming (Open311, from FMS) field names
+# note: attribute[*] are being sent by FMS explicitly as attributes for Oxfordshire
+my %F = (
+ 'ACCOUNT_ID' => 'account_id',
+ 'ADDRESS_ID' => 'address_id',
+ 'ADDRESS_STRING' => 'address_string',
+ 'API_KEY' => 'api_key',
+ 'CLOSEST_ADDRESS' => 'attribute[closest_address]',
+ 'DESCRIPTION' => 'description',
+ 'DEVICE_ID' => 'device_id',
+ 'EASTING' => 'attribute[easting]',
+ 'EMAIL' => 'email',
+ 'FIRST_NAME' => 'first_name',
+ 'FMS_ID' => 'attribute[external_id]',
+ 'LAST_NAME' => 'last_name',
+ 'LAT' => 'lat',
+ 'LONG' => 'long',
+ 'MEDIA_URL' => 'media_url',
+ 'NORTHING' => 'attribute[northing]',
+ 'PHONE' => 'phone',
+ 'REQUESTED_DATETIME' => 'requested_datetime',
+ 'SERVICE_CODE' => 'service_code',
+ 'STATUS' => 'status',
+
+);
+
+my $req = new CGI;
+
+# normally, POST requests are inserting service requests
+# and GET requests are for returning service requests, although OCC aren't planning on
+# using that (it's part of the Open311 spec).
+# So actually the service discovery is more useful, so send in a 'services' param
+# to see that.
+#
+# But for testing the db connection, set $TEST_SERVICE_DISCOVERY so that
+# *all* requests simply do a service discovery by setting (possibly via the config file)
+
+if ($TEST_SERVICE_DISCOVERY) {
+ get_service_discovery($req); # to test
+}elsif ($ENV{'REQUEST_METHOD'} eq "POST") {
+ post_service_request($req);
+} elsif ($req -> param('services')) {
+ get_service_discovery($req);
+} elsif ($RUN_FAKE_INSERT_TEST) {
+ # allow a GET to make an insert, for testing (from the commandnd line!)
+ print "Running fake insert test... returned: " . get_FAKE_INSERT();
+ print "\nSee $OUT_FILENAME for data" if $TESTING_WRITE_TO_FILE;
+ print "\n";
+} else {
+ get_service_requests($req);
+}
+
+#----------------------------------------------------
+# post_service_request
+# accepts an incoming service request
+# If everything goes well, it puts it in the database and
+# returns the PEM ID to the caller
+#----------------------------------------------------
+sub post_service_request {
+ my $req = shift;
+ my %data;
+ my $pem_id = 0;
+
+ foreach (values %F) {
+ $data{$_} = $req -> param($_);
+ $data{$_} =~ s/^\s+|\s+$//g; # trim
+ }
+
+ error_and_exit(CODE_OR_ID_NOT_PROVIDED, "missing service code (Open311 requires one)")
+ unless $data{$F{SERVICE_CODE}};
+ error_and_exit(GENERAL_SERVICE_ERROR, "the service code you provided ($data{$F{SERVICE_CODE}}) was not recognised by this server")
+ unless service_exists($data{$F{SERVICE_CODE}});
+ error_and_exit(GENERAL_SERVICE_ERROR, "no address or long-lat provided")
+ unless ( (is_longlat($data{$F{LONG}}) && is_longlat($data{$F{LAT}})) || $data{$F{ADDRESS_STRING}} );
+
+ $pem_id = insert_into_pem(\%data);
+
+ if (! $pem_id) {
+ error_and_exit(FATAL_ERROR, $data{$ERR_MSG} || "failed to get PEM ID");
+ } else {
+ print <<XML;
+Content-type: text/xml
+
+<?xml version="1.0" encoding="utf-8"?>
+<service_requests>
+ <request>
+ <service_request_id>$pem_id</service_request_id>
+ </request>
+</service_requests>
+XML
+ }
+}
+
+#------------------------------------------------------------------
+# is_longlat
+# returns true if this looks like a long/lat value
+#------------------------------------------------------------------
+sub is_longlat {
+ return $_[0] =~ /^-?\d+\.\d+$/o? 1 : 0;
+}
+
+#------------------------------------------------------------------
+# service_exists
+# lookup the service code, to check that it exists
+# SELECT det_code, det_name FROM higatlas.doc_enquiry_types WHERE
+# det_dtp_code = 'REQS' AND det_dcl_code ='SERV' AND det_con_id=1
+# Actually, FMS is expected to be sending good codes because they
+# come from here anyway, and are expected to be stable. But could
+# cache and check... probably overkill since DB insert will probably
+# throw the error anyway.
+#------------------------------------------------------------------
+sub service_exists {
+ my $service_code = shift;
+ return 1;
+}
+
+#------------------------------------------------------------------
+# dump_to_file
+# args: ref to hash of data
+# for testing, log the incoming data into a local file
+# NB throws a fatal error
+#------------------------------------------------------------------
+sub dump_to_file {
+ my $h = shift; # href to data hash
+ if (open (OUTFILE, ">$OUT_FILENAME")) {
+ print OUTFILE "Data dump: " . gmtime() . "\n" . '-' x 64 . "\n\n";
+ foreach (sort keys %$h) {
+ print OUTFILE "$_ => " . $$h{$_} . "\n";
+ }
+ print OUTFILE "\n\n" . '-' x 64 . "\n[end]\n";
+ close OUTFILE;
+ $$h{$ERR_MSG} = "NB did not write to DB (see $OUT_FILENAME instead: switch off \$TESTING_WRITE_TO_FILE to stop this)";
+ } else {
+ $$h{$ERR_MSG} = "failed to write to outfile ($!)";
+ }
+ return 0; # test always throws an error so no risk of production confusion!
+}
+
+#------------------------------------------------------------------
+# insert_into_pem
+# args: hashref to data hash
+# returns PEM id of the new record (or passes an error message
+# into the data hash if no id is available)
+#------------------------------------------------------------------
+sub insert_into_pem {
+ my $h = shift; # href to data hash
+
+ my $pem_id;
+ my $error_value;
+ my $error_product;
+
+ # set specifc vars up where further processing on them might be needed:
+ my $undef = undef;
+ my $status = $$h{$F{STATUS}};
+ my $service_code = $$h{$F{SERVICE_CODE}};
+ my $description = $$h{$F{DESCRIPTION}};
+ my $media_url = $$h{$F{MEDIA_URL}};
+ if ($media_url) {
+ # don't put URL for full images into the database (because they're too big to see on a Blackberry)
+ $media_url =~ s/\.full(\.jpe?g)$/$1/;
+ $description .= ($STRIP_CONTROL_CHARS ne 'ruthless'? "\n\n":" ") . "Photo: $media_url";
+ }
+ my $location = $$h{$F{CLOSEST_ADDRESS}};
+ if ($location) {
+ # strip out everything apart from "Nearest" preamble
+ $location=~s/(Nearest road)[^:]+:/$1:/;
+ $location=~s/(Nearest postcode)[^:]+:(.*?)(\(\w+ away\))?\s*(\n|$)/$1: $2/;
+ }
+
+ my %bindings;
+ # comments here are suggested values
+ # field lengths are from OCC's Java portlet
+ # fixed values
+ $bindings{":ce_cat"} = 'REQS'; # or REQS ?
+ $bindings{":ce_class"} = 'SERV'; # 'FRML' ?
+ $bindings{":ce_contact_type"} = 'ENQUIRER'; # 'ENQUIRER'
+ $bindings{":ce_status_code"} = 'RE'; # RE=received (?)
+ $bindings{":ce_compl_user_type"}= 'USER'; # 'USER'
+
+ # ce_incident_datetime is *not* an optional param, but FMS isn't sending it at the moment
+ $bindings{":ce_incident_datetime"}=$$h{$F{REQUESTED_DATETIME}} || Time::Piece->new->strftime('%Y-%m-%d %H:%M');
+
+ # especially FMS-specific:
+ $bindings{":ce_source"} = "FMS"; # important, and specific to this script!
+ $bindings{":ce_doc_reference"} = $$h{$F{FMS_ID}}; # FMS id
+ $bindings{":ce_enquiry_type"} = $service_code;
+
+ # incoming data
+ $bindings{":ce_x"} = $$h{$F{EASTING}};
+ $bindings{":ce_y"} = $$h{$F{NORTHING}};
+ $bindings{":ce_forename"} = strip($$h{$F{FIRST_NAME}}, 30); # 'CLIFF'
+ $bindings{":ce_surname"} = strip($$h{$F{LAST_NAME}}, 30); # 'STEWART'
+ $bindings{":ce_work_phone"} = strip($$h{$F{PHONE}}, 25); # '0117 600 4200'
+ $bindings{":ce_email"} = strip($$h{$F{EMAIL}}, 50); # 'info@exor.co.uk'
+ $bindings{":ce_description"} = strip($description, 2000, $F{DESCRIPTION}); # 'Large Pothole'
+
+ # nearest address guesstimate
+ $bindings{":ce_location"} = strip($location, 254);
+
+ if ($TESTING_WRITE_TO_FILE) {
+ return dump_to_file(\%bindings);
+ }
+
+ # everything ready: now put it into the database
+ my $dbh = get_db_connection();
+
+ my $sth = $dbh->prepare(q#
+ BEGIN
+ PEM.create_enquiry(
+ ce_cat => :ce_cat,
+ ce_class => :ce_class,
+ ce_forename => :ce_forename,
+ ce_surname => :ce_surname,
+ ce_contact_type => :ce_contact_type,
+ ce_location => :ce_location,
+ ce_work_phone => :ce_work_phone,
+ ce_email => :ce_email,
+ ce_description => :ce_description,
+ ce_enquiry_type => :ce_enquiry_type,
+ ce_source => :ce_source,
+ ce_incident_datetime => to_Date(:ce_incident_datetime,'YYYY-MM-DD HH24:MI'),
+ ce_x => :ce_x,
+ ce_y => :ce_y,
+ ce_doc_reference => :ce_doc_reference,
+ ce_status_code => :ce_status_code,
+ ce_compl_user_type => :ce_compl_user_type,
+ error_value => :error_value,
+ error_product => :error_product,
+ ce_doc_id => :ce_doc_id);
+ END;
+#);
+
+ foreach my $name (sort keys %bindings) {
+ next if grep {$name eq $_} (':error_value', ':error_product', ':ce_doc_id'); # return values (see below)
+ $sth->bind_param(
+ $name,
+ $bindings{$name},
+ $PEM_BOUND_VAR_TYPES{$name} || ORA_VARCHAR2
+ );
+ }
+ # return values are bound explicitly here:
+ $sth->bind_param_inout(":error_value", \$error_value, 12); #> l_ERROR_VALUE # number
+ $sth->bind_param_inout(":error_product", \$error_product, 10); #> l_ERROR_PRODUCT (will always be 'DOC')
+ $sth->bind_param_inout(":ce_doc_id", \$pem_id, 12); #> l_ce_doc_id # number
+
+ # not used, but from the example docs, for reference
+ # $sth->bind_param(":ce_contact_title", $undef); # 'MR'
+ # $sth->bind_param(":ce_postcode", $undef); # 'BS11EJ' NB no spaces, upper case
+ # $sth->bind_param(":ce_building_no", $undef); # '1'
+ # $sth->bind_param(":ce_building_name", $undef); # 'CLIFTON HEIGHTS'
+ # $sth->bind_param(":ce_street", $undef); # 'HIGH STREET'
+ # $sth->bind_param(":ce_town", $undef); # 'BRSITOL'
+ # $sth->bind_param(":ce_enquiry_type", $undef); # 'CD' , ce_source => 'T'
+ # $sth->bind_param(":ce_cpr_id", $undef); # '5' (priority)
+ # $sth->bind_param(":ce_rse_he_id", $undef); #> nm3net.get_ne_id('1200D90970/09001','L')
+ # $sth->bind_param(":ce_compl_target", $undef); # '08-JAN-2004'
+ # $sth->bind_param(":ce_compl_corresp_date",$undef); # '02-JAN-2004'
+ # $sth->bind_param(":ce_compl_corresp_deliv_date", $undef); # '02-JAN-2004'
+ # $sth->bind_param(":ce_resp_of", $undef); # 'GBOWLER'
+ # $sth->bind_param(":ce_hct_vip", $undef); # 'CO'
+ # $sth->bind_param(":ce_hct_home_phone", $undef); # '0117 900 6201'
+ # $sth->bind_param(":ce_hct_mobile_phone", $undef); # '07111 1111111'
+ # $sth->bind_param(":ce_compl_remarks", $undef); # remarks (notes) max 254 char
+
+ $sth->execute();
+ $dbh->disconnect;
+
+ # if error, maybe need to look it up:
+ # error_value is the index HER_NO in table HIG_ERRORS, which has messages
+ # actually err_product not helpful (wil always be "DOC")
+ $$h{$ERR_MSG} = "$error_value $error_product" if ($error_value || $error_product);
+
+ return $pem_id;
+}
+
+#------------------------------------------------------------------
+# strip
+# args: data, max-length, field-name
+# Trims, strips control chars, truncates to max-length
+# Field-name only matters for description field
+#------------------------------------------------------------------
+sub strip {
+ my ($s, $max_len, $field_name) = @_;
+ if ($STRIP_CONTROL_CHARS) {
+ if ($STRIP_CONTROL_CHARS eq 'ruthless') {
+ $s =~ s/[[:cntrl:]]/ /g; # strip all control chars, simples
+ } elsif ($STRIP_CONTROL_CHARS eq 'desc') {
+ if ($field_name eq $F{DESCRIPTION}) {
+ $s =~ s/[^\t\n[:^cntrl:]]/ /g; # leave tabs and newlines
+ } else {
+ $s =~ s/[[:cntrl:]]/ /g; # strip all control chars, simples
+ }
+ } else {
+ $s =~ s/[^\t\n[:^cntrl:]]/ /g; # leave tabs and newlines
+ }
+ }
+ from_to($s, 'utf8', 'Windows-1252') if $ENCODE_TO_WIN1252;
+ return $max_len? substr($s, 0, 2000) : $s;
+}
+
+#------------------------------------------------------------------
+# get_service_requests
+# Strictly speaking, Open311 would expect the GET request for service
+# requests to respond with all service requests (within a specified
+# period). But as we're not using that, do a service discovery
+# instead.
+#------------------------------------------------------------------
+sub get_service_requests {
+ # error_and_exit(BAD_METHOD, "sorry, currently only handling incoming Open311 service requests: use POST method");
+ get_service_discovery(); # for now
+}
+
+#------------------------------------------------------------------
+# get_FAKE_INSERT
+# for testing off command line, force the data
+#------------------------------------------------------------------
+sub get_FAKE_INSERT {
+ my %fake_data = (
+ $F{'DESCRIPTION'} => 'Testing, description: A acute (requires Latin-1): [á] '
+ . ' pound sign (requires WinLatin-1): [£] omega tonos (requires UTF-8): [ώ]',
+ $F{'EASTING'} => '45119',
+ $F{'EMAIL'} => 'email@example.com',
+ $F{'FIRST_NAME'} => 'Dave',
+ $F{'FMS_ID'} => '1012',
+ $F{'LAST_NAME'} => 'Test',
+ $F{'LAT'} => '51.756741605999',
+ $F{'LONG'} => '-1.2596387532192',
+ $F{'NORTHING'} => '206709',
+ $F{'SERVICE_CODE'} => 'OT',
+ $F{'MEDIA_URL'} => 'http://www.example.com/pothole.jpg',
+ $F{'CLOSEST_ADDRESS'} => <<TEXT
+Nearest road to the pin placed on the map (automatically generated by Bing Maps): St Giles, Oxford, OX1 3
+
+Nearest postcode to the pin placed on the map (automatically generated): OX1 2LA (46m away)
+TEXT
+ );
+ return insert_into_pem(\%fake_data)
+}
+
+#------------------------------------------------------------------
+# get_service_discovery
+# Although not really implementing this, use it as a test to read the
+# db and confirm connectivity.
+#------------------------------------------------------------------
+sub get_service_discovery {
+ my $dbh = get_db_connection();
+ my $ary_ref = $dbh->selectall_arrayref(qq(select det_code, det_name from higatlas.doc_enquiry_types where det_dtp_code = 'REQS' AND det_dcl_code='SERV' and det_con_id=1));
+ # rough and ready XML dump now (should use XML Simple to build/escape properly!)
+ my $xml = "";
+ foreach my $row(@{$ary_ref}) {
+ if (defined $row) {
+ my ($code, $name) = @$row;
+ $xml.= <<XML;
+ <service>
+ <service_code>$code</service_code>
+ <metadata>false</metadata>
+ <type>realtime</type>
+ <keywords/>
+ <group/>
+ <service_name>$name</service_name>
+ <description/>
+ </service>
+XML
+ }
+ }
+ print <<XML;
+Content-type: text/xml
+
+<?xml version="1.0" encoding="utf-8"?>
+<services>
+$xml
+</services>
+XML
+}
+
+#------------------------------------------------------------------
+# get_pem_field_types
+# return hash of types by field name: any not explicitly set here
+# can be defaulted to VARCHAR2
+#------------------------------------------------------------------
+sub get_pem_field_types {
+ return (
+ ':ce_incident_datetime' => ORA_DATE,
+ ':ce_x' => ORA_NUMBER,
+ ':ce_y' => ORA_NUMBER,
+ ':ce_date_expires' => ORA_DATE,
+ ':ce_issue_number' => ORA_NUMBER,
+ ':ce_status_date' => ORA_DATE,
+ ':ce_compl_ack_date' => ORA_DATE,
+ ':ce_compl_peo_date' => ORA_DATE,
+ ':ce_compl_target' => ORA_DATE,
+ ':ce_compl_complete' => ORA_DATE,
+ ':ce_compl_from' => ORA_DATE,
+ ':ce_compl_to' => ORA_DATE,
+ ':ce_compl_corresp_date' => ORA_DATE,
+ ':ce_compl_corresp_deliv_date' => ORA_DATE,
+ ':ce_compl_no_of_petitioners' => ORA_NUMBER,
+ ':ce_compl_est_cost' => ORA_NUMBER,
+ ':ce_compl_adv_cost' => ORA_NUMBER,
+ ':ce_compl_act_cost' => ORA_NUMBER,
+ ':ce_compl_follow_up1' => ORA_DATE,
+ ':ce_compl_follow_up2' => ORA_DATE,
+ ':ce_compl_follow_uo3' => ORA_DATE,
+ ':ce_date_time_arrived' => ORA_DATE,
+ ':error_value' => ORA_NUMBER,
+ ':ce_doc_id' => ORA_NUMBER,
+ )
+}
+
diff --git a/bin/oxfordshire/open311_service_request_update.cgi b/bin/oxfordshire/open311_service_request_update.cgi
new file mode 100755
index 000000000..cfceffcc8
--- /dev/null
+++ b/bin/oxfordshire/open311_service_request_update.cgi
@@ -0,0 +1,126 @@
+#!/usr/bin/perl
+
+# script for querying the higatlas.fms_update table provided by
+# Bentley and offering them up as XML service request updates.
+# https://github.com/mysociety/fixmystreet/wiki/Open311-FMS---Proposed-differences-to-Open311
+#
+# mySociety: http://code.fixmystreet.com/
+#-----------------------------------------------------------------
+
+require 'open311_services.pm';
+
+# incoming query params
+my $CGI_VAR_START_DATE = 'start_date';
+my $CGI_VAR_END_DATE = 'end_date';
+my $CGI_VAR_NO_DEFAULT_DATE = 'force_no_default_date'; # for testing scratchy Oracle date stuff
+my $CGI_VAR_LIMIT = 'limit'; # for testing
+my $CGI_VAR_ANY_STATUS = 'any_status'; # for testing
+
+my $USE_ONLY_DATES = 0; # dates not times
+my $MAX_LIMIT = 1000;
+my $STATUS_CRITERIA = "(status='OPEN' OR status='CLOSED')";
+my $req = new CGI;
+
+get_service_request_updates($req);
+
+sub prepare_for_xml {
+ my $s = shift;
+ foreach ($s) {
+ from_to($_, 'utf8', 'Windows-1252') if $DECODE_FROM_WIN1252;
+ s/</&lt;/g; # numpty escaping pending XML Simple?
+ s/>/&gt;/g;
+ s/&/&amp;/g;
+ }
+ return $s;
+}
+
+#------------------------------------------------------------------
+# get_service_discovery
+# Although not really implementing this, use it as a test to read the
+# db and confirm connectivity.
+#
+# TABLE "HIGATLAS"."FMS_UPDATE"
+#
+# "ROW_ID" NUMBER(9,0) NOT NULL ENABLE,
+# "SERVICE_REQUEST_ID" NUMBER(9,0) NOT NULL ENABLE,
+# "UPDATED_TIMEDATE" DATE DEFAULT SYSDATE NOT NULL ENABLE,
+# "STATUS" VARCHAR2(10 BYTE) NOT NULL ENABLE,
+# "DESCRIPTION" VARCHAR2(254 BYTE) NOT NULL ENABLE,
+#
+# CONSTRAINT "FMS_UPDATE_PK" PRIMARY KEY ("ROW_ID")
+#------------------------------------------------------------------
+sub get_service_request_updates {
+ # by default, we only want last 24 hours
+ # also, limit to 1000 records
+
+ my $raw_start_date = $req -> param($CGI_VAR_START_DATE);
+ my $raw_end_date = $req -> param($CGI_VAR_END_DATE);
+ my $start_date = get_date_or_nothing( $raw_start_date, $USE_ONLY_DATES );
+ my $end_date = get_date_or_nothing( $raw_end_date, $USE_ONLY_DATES );
+
+ if (! $req -> param($CGI_VAR_NO_DEFAULT_DATE)) {
+ $start_date = get_date_or_nothing( $YESTERDAY, $USE_ONLY_DATES ) unless ($start_date or $end_date);
+ }
+
+ my $date_format = 'YYYY-MM-DD HH24:MI:SS'; # NB: hh24 (not hh)
+
+ $start_date = "updated_timedate >= to_date('$start_date', '$date_format')" if $start_date;
+ $end_date = "updated_timedate <= to_date('$end_date', '$date_format')" if $end_date;
+
+ my $where_clause = '';
+ my @criteria = ($start_date, $end_date);
+ push @criteria, $STATUS_CRITERIA unless $req -> param($CGI_VAR_ANY_STATUS);
+ $where_clause = join(' AND ', grep {$_} @criteria);
+ $where_clause = "WHERE $where_clause" if $where_clause;
+
+ my $sql = qq(SELECT row_id, service_request_id, to_char(updated_timedate, '$date_format'), status, description FROM higatlas.fms_update $where_clause ORDER BY updated_timedate DESC);
+
+ my $limit = $req -> param($CGI_VAR_LIMIT) =~ /^(\d{1,3})$/? $1 : $MAX_LIMIT;
+ $sql = "SELECT * FROM ($sql) WHERE ROWNUM <= $limit" if $limit;
+
+ my $debug_str;
+ my $ary_ref;
+
+ if ($TESTING_WRITE_TO_FILE) {
+ $ary_ref = [
+ [97, 1000, '2013-01-05', 'OPEN', 'report was opened'],
+ [99, 1000, '2013-01-06', 'CLOSED', 'report was closed']
+ ];
+ # only add debug now if config says we're testing
+ $debug_str = <<XML;
+ <!-- DEBUG: from: $raw_start_date => $start_date -->
+ <!-- DEBUG: to: $raw_end_date => $end_date -->
+ <!-- DEBUG: sql: $sql -->
+XML
+ } else {
+ my $dbh = get_db_connection();
+ $ary_ref = $dbh->selectall_arrayref($sql);
+ }
+
+ # rough and ready XML dump now (should use XML Simple to build/escape properly!)
+ my $xml = "";
+ foreach my $row(@{$ary_ref}) {
+ if (defined $row) {
+ my ($id, $service_req_id, $updated_at, $status, $desc) = map { prepare_for_xml($_) } @$row;
+ $updated_at=~s/(\d{4}-\d\d-\d\d) (\d\d:\d\d:\d\d)/${1}T${2}Z/; # for now assume OCC in Zulu time
+ $xml.= <<XML;
+ <request_update>
+ <update_id>$id</update_id>
+ <service_request_id>$service_req_id</service_request_id>
+ <status>$status</status>
+ <updated_datetime>$updated_at</updated_datetime>
+ <description>$desc</description>
+ </request_update>
+XML
+ }
+ }
+ print <<XML;
+Content-type: text/xml
+
+<?xml version="1.0" encoding="utf-8"?>
+<service_request_updates>
+$xml
+</service_request_updates>
+$debug_str
+XML
+}
diff --git a/bin/oxfordshire/open311_services.pm b/bin/oxfordshire/open311_services.pm
new file mode 100644
index 000000000..0b73cdfe6
--- /dev/null
+++ b/bin/oxfordshire/open311_services.pm
@@ -0,0 +1,150 @@
+#!/usr/bin/perl
+#
+# common stuff used by Oxfordshire Open311 glue scripts
+#
+# mySociety: http://code.fixmystreet.com/
+#-----------------------------------------------------------------
+
+use strict;
+use CGI;
+use Encode qw(from_to);
+use DBI;
+use Time::Piece;
+
+
+###################################################################
+# Config file: values in the config file override any values set
+# in the code below for the following things:
+#
+# host: SXX-SAN-FOO_BAR
+# sid: FOOBAR
+# port: 1531
+# username: foo
+# password: FooBar
+# testing: 0
+# encode-to-win1252: 1
+#
+# Absence of the config file fails silently in case you really are
+# using values directly set in this script.
+#------------------------------------------------------------------
+our $CONFIG_FILENAME = "/usr/local/etc/fixmystreet.config";
+
+use constant {
+ GENERAL_SERVICE_ERROR => 400,
+ CODE_OR_ID_NOT_FOUND => 404,
+ CODE_OR_ID_NOT_PROVIDED => 400,
+ BAD_METHOD => 405,
+ FATAL_ERROR => 500
+};
+
+our $DB_SERVER_NAME = 'FOO';
+our $DB_HOST = $DB_SERVER_NAME; # did this just in case we need to add more to the name (e.g, domain)
+our $DB_PORT = '1531';
+our $ORACLE_SID = 'FOOBAR';
+our $USERNAME = 'FIXMYSTREET';
+our $PASSWORD = 'XXX';
+our $STORED_PROC_NAME = 'PEM.create_enquiry';
+
+# NB can override these settings in the config file!
+
+# Strip control chars:
+# 'ruthless' removes everything (i.e. all POSIX control chars)
+# 'desc' removes everything, but keeps tabs and newlines in the 'description' field, where they matter
+# 'normal' keeps tabs and newlines
+our $STRIP_CONTROL_CHARS = 'ruthless';
+
+our $ENCODE_TO_WIN1252 = 1; # force encoding to Win-1252 for PEM data
+our $DECODE_FROM_WIN1252 = 1; # force encoding from Win-1252 for PEM data
+
+our $TESTING_WRITE_TO_FILE = 0; # write to file instead of DB or (get_service_request_update) don't really read the db
+our $OUT_FILENAME = "fms-test.txt"; # dump data here if TESTING_WRITE_TO_FILE is true
+our $TEST_SERVICE_DISCOVERY = 0; # switch to 1 to run service discovery, which confirms the DB connection at least
+our $RUN_FAKE_INSERT_TEST = 0; # command-line execution attempts insert with fake data (mimics a POST request)
+
+# Config file overrides existing values for these, if present:
+if ($CONFIG_FILENAME && open(CONF, $CONFIG_FILENAME)) {
+ while (<CONF>) {
+ next if /^#/;
+ if (/^\s*password:\s*(\S+)\s*$/i) {
+ $PASSWORD = $1;
+ } elsif (/^\s*sid:\s*(\S+)\s*$/i) {
+ $ORACLE_SID = $1;
+ } elsif (/^\s*username:\s*(\S+)\s*$/i) {
+ $USERNAME = $1;
+ } elsif (/^\s*port:\s*(\S+)\s*$/i) {
+ $DB_PORT = $1;
+ } elsif (/^\s*host:\s*(\S+)\s*$/i) {
+ $DB_HOST = $1;
+ } elsif (/^\s*testing:\s*(\S+)\s*$/i) {
+ $TESTING_WRITE_TO_FILE = $1;
+ } elsif (/^\s*test-service-discovery:\s*(\S+)\s*$/i) {
+ $TEST_SERVICE_DISCOVERY = $1;
+ } elsif (/^\s*strip-control-chars:\s*(\S+)\s*$/i) {
+ $STRIP_CONTROL_CHARS = lc $1;
+ } elsif (/^\s*encode-to-win1252:\s*(\S+)\s*$/i) {
+ $ENCODE_TO_WIN1252 = $1;
+ } elsif (/^\s*decode-from-win1252:\s*(\S+)\s*$/i) {
+ $DECODE_FROM_WIN1252 = $1;
+ } elsif (/^\s*run-fake-insert-test:\s*(\S+)\s*$/i) {
+ $RUN_FAKE_INSERT_TEST = $1;
+ }
+ }
+}
+
+our $YESTERDAY = localtime() - Time::Seconds::ONE_DAY; # yesterday
+$YESTERDAY = $YESTERDAY->strftime('%Y-%m-%d');
+
+#------------------------------------------------------------------
+# error_and_exit
+# args: HTTP status code, error message
+# Sends out the HTTP status code and message
+# and temrinates execution
+#------------------------------------------------------------------
+sub error_and_exit {
+ my ($status, $msg) = @_;
+ print "Status: $status $msg\n\n$msg\n";
+ exit;
+}
+
+
+#------------------------------------------------------------------
+# get_db_connection
+# no args: uses globals, possibly read from config
+# returns handle for the connection (otherwise terminates)
+#------------------------------------------------------------------
+sub get_db_connection {
+ return DBI->connect( "dbi:Oracle:host=$DB_HOST;sid=$ORACLE_SID;port=$DB_PORT", $USERNAME, $PASSWORD )
+ or error_and_exit(FATAL_ERROR, "failed to connect to database: " . $DBI::errstr, "");
+}
+
+#------------------------------------------------------------------
+# get_date_or_nothing {
+# parse date from incoming request, fail silently
+# expected format: 2003-02-15T13:50:05
+# These are coming from FMS for Oxford so don't expect to need
+# need to parse anyway
+#------------------------------------------------------------------
+sub get_date_or_nothing {
+ my $d = shift;
+ my $want_date_only = shift;
+ if ($d=~s/^(\d{4}-\d\d-\d\d)(T\d\d:\d\d(:\d\d)?)?.*/$1$2/) {
+ return $1 if $want_date_only;
+ $d="$1 00:00" unless $2; # no time provided
+ $d.=":00" unless $3; # no seconds
+ $d=~s/[TZ]/ /g;
+ # no point doing any parsing if regexp has done the work
+ # eval {
+ # $d=~s/(\d\d:\d\d).*/$1/; # bodge if we can't get DateTime installed
+ # $d = Time::Piece->strptime( $d, '%Y-%m-%dT%H:%M:%S');
+ # $d = $d->strftime('%Y-%m-%d %H:%M:%S');
+ # };
+ # return '' if $@;
+ } else {
+ return '';
+ }
+ return $d;
+}
+
+
+
+1;
diff --git a/bin/send-comments b/bin/send-comments
index 1a12fa684..850a57758 100755
--- a/bin/send-comments
+++ b/bin/send-comments
@@ -1,7 +1,10 @@
#!/usr/bin/env perl
-# send-reports:
-# Send new problem reports to bodies
+# send-comments:
+# Send comments/updates on reports to bodies
+# In Open311 parlance these are 'service request udpates' and are sent using
+# mySociety's proposed extension to the Open311 Georeport v2 spec:
+# https://github.com/mysociety/fixmystreet/wiki/Open311-FMS---Proposed-differences-to-Open311
#
# Copyright (c) 2011 UK Citizens Online Democracy. All rights reserved.
# Email: matthew@mysociety.org. WWW: http://www.mysociety.org
@@ -61,13 +64,20 @@ while ( my $body = $bodies->next ) {
$use_extended = 1;
}
- my $o = Open311->new(
+ my %open311_conf = (
endpoint => $body->endpoint,
jurisdiction => $body->jurisdiction,
api_key => $body->api_key,
use_extended_updates => $use_extended,
);
+
+ if ( $body->send_extended_statuses ) {
+ $open311_conf{extended_statuses} = 1;
+ }
+
+ my $o = Open311->new( %open311_conf );
+
if ( $body->areas->{2482} ) {
my $endpoints = $o->endpoints;
$endpoints->{update} = 'update.xml';
@@ -78,6 +88,18 @@ while ( my $body = $bodies->next ) {
while ( my $comment = $comments->next ) {
my $cobrand = FixMyStreet::Cobrand->get_class_for_moniker($comment->cobrand)->new();
+ # actually this should be OK for any devolved endpoint if original Open311->can_be_devolved, presumably
+ if ( $cobrand->moniker eq "fixmybarangay") {
+ my $sender = $cobrand->get_body_sender( $body, $comment->problem->category );
+ my $config = $sender->{config};
+ $o = Open311->new(
+ endpoint => $config->endpoint,
+ jurisdiction => $config->jurisdiction,
+ api_key => $config->api_key,
+ use_extended_updates => 1, # FMB uses extended updates
+ );
+ }
+
if ( $comment->send_fail_count ) {
next if bromley_retry_timeout( $comment );
}
diff --git a/commonlib b/commonlib
-Subproject e832140e07bba7697726cae50ec0da26fb54788
+Subproject 98ea3736edb949184eef7d575c9caa12748b35b
diff --git a/conf/crontab.ugly b/conf/crontab.ugly
index 9330b43f3..4eb6d5a26 100644
--- a/conf/crontab.ugly
+++ b/conf/crontab.ugly
@@ -20,13 +20,20 @@ my @sending = qw(
bromley.test.mysociety.org
stevenage.test.mysociety.org
barnet.fixmystreet.staging.mysociety.org
+ oxfordshire.fixmystreet.staging.mysociety.org
fixmybarangay.test.mysociety.org
demo.fixmybarangay.com
www.fixmybarangay.com
zurich.fixmystreet.staging.mysociety.org
+ seesomething.mysociety.org
);
my @no_alerts = qw(
zurich.fixmystreet.staging.mysociety.org
+ seesomething.mysociety.org
+);
+my @no_open311 = qw(
+ zurich.fixmystreet.staging.mysociety.org
+ seesomething.mysociety.org
);
my %sending = map { $_ => 1 } @sending;
my %no_alerts = map { $_ => 1 } @no_alerts;
@@ -45,6 +52,7 @@ my %no_alerts = map { $_ => 1 } @no_alerts;
0,30 * * * * !!(*= $user *)!! run-with-lockfile -n /data/vhost/!!(*= $vhost *)!!/send-questionnaires.lock "/data/vhost/!!(*= $vhost *)!!/fixmystreet/bin/cron-wrapper send-questionnaires" || echo "stalled?"
!!(* } *)!!
+!!(* if (!$no_open311{$vhost}) { *)!!
# Open311 sending and fetching of updates
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?"
@@ -57,6 +65,8 @@ my %no_alerts = map { $_ => 1 } @no_alerts;
0 8 * * * !!(*= $user *)!! run-with-lockfile -n /data/vhost/!!(*= $vhost *)!!/open311-populate-service-list.lock "/data/vhost/!!(*= $vhost *)!!/fixmystreet/bin/cron-wrapper open311-populate-service-list --warn" || echo "stalled?"
!!(* } *)!!
+!!(* } *)!!
+
# Once an hour, update the all reports stats
13 * * * * !!(*= $user *)!! /data/vhost/!!(*= $vhost *)!!/fixmystreet/bin/cron-wrapper update-all-reports
diff --git a/conf/general.yml-example b/conf/general.yml-example
index 175b342a4..4a06a2aff 100644
--- a/conf/general.yml-example
+++ b/conf/general.yml-example
@@ -22,6 +22,10 @@ BASE_URL: 'http://www.example.org'
EMAIL_DOMAIN: 'example.org'
CONTACT_EMAIL: 'team@example.org'
CONTACT_NAME: 'FixMyStreet'
+# Address used for emails you don't expect a reply to (e.g. confirmation
+# emails); can be same as CONTACT_EMAIL above, of course, if you don't have a
+# special address.
+DO_NOT_REPLY_EMAIL: 'do-not-reply@example.org'
# Whether this is a development site or not. It will mean e.g. templates/
# CSS modified times aren't cached
diff --git a/db/schema.sql b/db/schema.sql
index d8cc0675a..5e4bc4a3e 100644
--- a/db/schema.sql
+++ b/db/schema.sql
@@ -63,7 +63,8 @@ create table body (
send_comments boolean not null default 'f',
comment_user_id int references users(id),
suppress_alerts boolean not null default 'f',
- can_be_devolved boolean not null default 'f'
+ can_be_devolved boolean not null default 'f',
+ send_extended_statuses boolean not null default 'f'
);
create table body_areas (
@@ -176,12 +177,17 @@ create table problem (
or state = 'investigating'
or state = 'planned'
or state = 'in progress'
+ or state = 'action scheduled'
or state = 'closed'
or state = 'fixed'
or state = 'fixed - council'
or state = 'fixed - user'
or state = 'hidden'
or state = 'partial'
+ or state = 'unable to fix'
+ or state = 'not responsible'
+ or state = 'duplicate'
+ or state = 'internal referral'
),
lang text not null default 'en-gb',
service text not null default '',
@@ -210,7 +216,10 @@ create table problem (
external_source_id text,
-- number of me toos
- interest_count integer default 0
+ interest_count integer default 0,
+
+ -- subcategory to enable filtering in reporting --
+ subcategory text
);
create index problem_state_latitude_longitude_idx on problem(state, latitude, longitude);
create index problem_user_id_idx on problem ( user_id );
@@ -321,10 +330,15 @@ create table comment (
or problem_state = 'investigating'
or problem_state = 'planned'
or problem_state = 'in progress'
+ or problem_state = 'action scheduled'
or problem_state = 'closed'
or problem_state = 'fixed'
or problem_state = 'fixed - council'
or problem_state = 'fixed - user'
+ or problem_state = 'unable to fix'
+ or problem_state = 'not responsible'
+ or problem_state = 'duplicate'
+ or problem_state = 'internal referral'
),
-- other fields? one to indicate whether this was written by the council
-- and should be highlighted in the display?
diff --git a/db/schema_0025-add_more_statuses_to_problem.sql b/db/schema_0025-add_more_statuses_to_problem.sql
new file mode 100644
index 000000000..14d1b3195
--- /dev/null
+++ b/db/schema_0025-add_more_statuses_to_problem.sql
@@ -0,0 +1,83 @@
+BEGIN;
+
+ ALTER TABLE problem DROP CONSTRAINT problem_state_check;
+
+ ALTER TABLE problem ADD CONSTRAINT problem_state_check CHECK (
+ state = 'unconfirmed'
+ or state = 'confirmed'
+ or state = 'investigating'
+ or state = 'planned'
+ or state = 'in progress'
+ or state = 'action scheduled'
+ or state = 'closed'
+ or state = 'fixed'
+ or state = 'fixed - council'
+ or state = 'fixed - user'
+ or state = 'hidden'
+ or state = 'partial'
+ or state = 'unable to fix'
+ or state = 'not responsible'
+ or state = 'duplicate'
+ or state = 'internal referral'
+ );
+
+
+ ALTER TABLE comment DROP CONSTRAINT comment_problem_state_check;
+
+ ALTER TABLE comment ADD CONSTRAINT comment_problem_state_check CHECK (
+ problem_state = 'confirmed'
+ or problem_state = 'investigating'
+ or problem_state = 'planned'
+ or problem_state = 'in progress'
+ or problem_state = 'action scheduled'
+ or problem_state = 'closed'
+ or problem_state = 'fixed'
+ or problem_state = 'fixed - council'
+ or problem_state = 'fixed - user'
+ or problem_state = 'unable to fix'
+ or problem_state = 'not responsible'
+ or problem_state = 'duplicate'
+ or problem_state = 'internal referral'
+ );
+
+ UPDATE alert_type set item_where = 'nearby.problem_id = problem.id and problem.state in
+ (''confirmed'', ''investigating'', ''planned'', ''in progress'',
+ ''fixed'', ''fixed - council'', ''fixed - user'', ''closed'',
+ ''action scheduled'', ''not responsible'', ''duplicate'', ''unable to fix'',
+ ''internal referral'')'
+ WHERE ref = 'postcode_local_problems';
+ UPDATE alert_type set item_where = 'problem.state in
+ (''confirmed'', ''investigating'', ''planned'', ''in progress'',
+ ''fixed'', ''fixed - council'', ''fixed - user'', ''closed''
+ ''action scheduled'', ''not responsible'', ''duplicate'', ''unable to fix'',
+ ''internal referral'' )'
+ WHERE ref = 'new_problems';
+ UPDATE alert_type set item_where = 'problem.state in (''fixed'', ''fixed - user'', ''fixed - council'')' WHERE ref = 'new_fixed_problems';
+ UPDATE alert_type set item_where = 'nearby.problem_id = problem.id and problem.state in
+ (''confirmed'', ''investigating'', ''planned'', ''in progress'',
+ ''fixed'', ''fixed - council'', ''fixed - user'', ''closed'',
+ ''action scheduled'', ''not responsible'', ''duplicate'', ''unable to fix'',
+ ''internal referral'')'
+ WHERE ref = 'local_problems';
+ UPDATE alert_type set item_where = 'problem.state in
+ (''confirmed'', ''investigating'', ''planned'', ''in progress'',
+ ''fixed'', ''fixed - council'', ''fixed - user'', ''closed'',
+ ''action scheduled'', ''not responsible'', ''duplicate'', ''unable to fix'',
+ ''internal referral'' ) AND
+ (council like ''%''||?||''%'' or council is null) and
+ areas like ''%,''||?||'',%''' WHERE ref = 'council_problems';
+ UPDATE alert_type set item_where = 'problem.state in
+ (''confirmed'', ''investigating'', ''planned'', ''in progress'',
+ ''fixed'', ''fixed - council'', ''fixed - user'', ''closed'',
+ ''action scheduled'', ''not responsible'', ''duplicate'', ''unable to fix'',
+ ''internal referral'' ) AND
+ (council like ''%''||?||''%'' or council is null) and
+ areas like ''%,''||?||'',%''' WHERE ref = 'ward_problems';
+ UPDATE alert_type set item_where = 'problem.state in
+ (''confirmed'', ''investigating'', ''planned'', ''in progress'',
+ ''fixed'', ''fixed - council'', ''fixed - user'', ''closed'',
+ ''action scheduled'', ''not responsible'', ''duplicate'', ''unable to fix'',
+ ''internal referral'' ) AND
+ areas like ''%,''||?||'',%''' WHERE ref = 'area_problems';
+
+COMMIT;
diff --git a/db/schema_0026-add_send_extended_comments_to_open311conf.sql b/db/schema_0026-add_send_extended_comments_to_open311conf.sql
new file mode 100644
index 000000000..ee7b44b75
--- /dev/null
+++ b/db/schema_0026-add_send_extended_comments_to_open311conf.sql
@@ -0,0 +1,6 @@
+begin;
+
+ALTER table open311conf
+ ADD column send_extended_statuses BOOL NOT NULL DEFAULT 'f';
+
+commit;
diff --git a/db/schema_0027-add_sub_category_to_problem.sql b/db/schema_0027-add_sub_category_to_problem.sql
new file mode 100644
index 000000000..6787bd371
--- /dev/null
+++ b/db/schema_0027-add_sub_category_to_problem.sql
@@ -0,0 +1,6 @@
+begin;
+
+ALTER TABLE problem
+ ADD COLUMN subcategory TEXT;
+
+commit;
diff --git a/perllib/FixMyStreet/App.pm b/perllib/FixMyStreet/App.pm
index f253575c8..b76f4d3ba 100644
--- a/perllib/FixMyStreet/App.pm
+++ b/perllib/FixMyStreet/App.pm
@@ -283,9 +283,8 @@ sub send_email {
my $template = shift;
my $extra_stash_values = shift || {};
- my $sender = $c->cobrand->contact_email;
+ my $sender = $c->config->{DO_NOT_REPLY_EMAIL};
my $sender_name = $c->cobrand->contact_name;
- $sender =~ s/team/fms-DO-NOT-REPLY/;
# create the vars to pass to the email template
my $vars = {
diff --git a/perllib/FixMyStreet/App/Controller/Admin.pm b/perllib/FixMyStreet/App/Controller/Admin.pm
index 17bc3ca76..a3a241590 100644
--- a/perllib/FixMyStreet/App/Controller/Admin.pm
+++ b/perllib/FixMyStreet/App/Controller/Admin.pm
@@ -29,9 +29,11 @@ sub begin : Private {
$c->uri_disposition('relative');
- if ($c->cobrand->moniker eq 'zurich') {
+ if ( $c->cobrand->moniker eq 'zurich' || $c->cobrand->moniker eq 'seesomething' ) {
$c->detach( '/auth/redirect' ) unless $c->user_exists;
$c->detach( '/auth/redirect' ) unless $c->user->from_body;
+ }
+ if ( $c->cobrand->moniker eq 'zurich' ) {
$c->cobrand->admin_type();
}
}
@@ -75,11 +77,9 @@ sub index : Path : Args(0) {
%prob_counts =
map { $_ => $prob_counts{$_} || 0 }
- ('confirmed', 'investigating', 'in progress', 'closed', 'fixed - council',
- 'fixed - user', 'fixed', 'unconfirmed', 'hidden',
- 'partial', 'planned');
+ ( FixMyStreet::DB::Result::Problem->all_states() );
$c->stash->{problems} = \%prob_counts;
- $c->stash->{total_problems_live} += $prob_counts{$_}
+ $c->stash->{total_problems_live} += $prob_counts{$_} ? $prob_counts{$_} : 0
for ( FixMyStreet::DB::Result::Problem->visible_states() );
$c->stash->{total_problems_users} = $c->cobrand->problems->unique_users;
@@ -399,12 +399,13 @@ sub update_contacts : Private {
sub body_params : Private {
my ( $self, $c ) = @_;
- my @fields = qw/name endpoint jurisdiction api_key send_method send_comments suppress_alerts comment_user_id can_be_devolved parent/;
+ my @fields = qw/name endpoint jurisdiction api_key send_method send_comments suppress_alerts send_extended_statuses comment_user_id can_be_devolved parent/;
my %defaults = map { $_ => '' } @fields;
%defaults = ( %defaults,
send_comments => 0,
suppress_alerts => 0,
comment_user_id => undef,
+ send_extended_statuses => 0,
can_be_devolved => 0,
parent => undef,
);
@@ -981,6 +982,10 @@ sub stats : Path('stats') : Args(0) {
$c->forward('fetch_all_bodies');
+ if ( $c->cobrand->moniker eq 'seesomething' ) {
+ return $c->cobrand->admin_stats();
+ }
+
if ( $c->req->param('getcounts') ) {
my ( $start_date, $end_date, @errors );
diff --git a/perllib/FixMyStreet/App/Controller/Contact.pm b/perllib/FixMyStreet/App/Controller/Contact.pm
index 926a3f2a5..04360301e 100644
--- a/perllib/FixMyStreet/App/Controller/Contact.pm
+++ b/perllib/FixMyStreet/App/Controller/Contact.pm
@@ -113,6 +113,9 @@ sub validate : Private {
or $c->req->param('update_id')
&& $c->req->param('update_id') !~ /^[1-9]\d*$/;
+ push @errors, _('There was a problem showing this page. Please try again later.')
+ if $c->req->params->{message} && $c->req->params->{message} =~ /\[url=/;
+
unshift @errors,
_('There were problems with your report. Please see below.')
if scalar keys %field_errors;
@@ -184,7 +187,7 @@ generally required to stash
sub setup_request : Private {
my ( $self, $c ) = @_;
- $c->stash->{contact_email} = $c->cobrand->contact_email( 'contact' );
+ $c->stash->{contact_email} = $c->cobrand->contact_email;
$c->stash->{contact_email} =~ s/\@/&#64;/;
for my $param (qw/em subject message/) {
@@ -206,7 +209,7 @@ Sends the email
sub send_email : Private {
my ( $self, $c ) = @_;
- my $recipient = $c->cobrand->contact_email( 'contact' );
+ my $recipient = $c->cobrand->contact_email;
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
index 657751e5c..028b9aadd 100644
--- a/perllib/FixMyStreet/App/Controller/Dashboard.pm
+++ b/perllib/FixMyStreet/App/Controller/Dashboard.pm
@@ -141,6 +141,8 @@ sub index : Path : Args(0) {
$prob_where->{state} = [ FixMyStreet::DB::Result::Problem->fixed_states() ];
} elsif ( $c->stash->{q_state} ) {
$prob_where->{state} = $c->stash->{q_state};
+ $prob_where->{state} = { IN => [ 'planned', 'action scheduled' ] }
+ if $prob_where->{state} eq 'action scheduled';
}
my $params = {
%$prob_where,
@@ -184,11 +186,13 @@ sub updates_search : Private {
map { $_ => $counts{$_} || 0 }
('confirmed', 'investigating', 'in progress', 'closed', 'fixed - council',
'fixed - user', 'fixed', 'unconfirmed', 'hidden',
- 'partial', 'planned');
+ 'partial', 'action scheduled', 'planned');
+
+ $counts{'action scheduled'} += $counts{planned} || 0;
for my $vars (
[ 'time_to_fix', 'fixed - council' ],
- [ 'time_to_mark', 'in progress', 'planned', 'investigating', 'closed' ],
+ [ 'time_to_mark', 'in progress', 'action scheduled', 'investigating', 'closed' ],
) {
my $col = shift @$vars;
my $substmt = "select min(id) from comment where me.problem_id=comment.problem_id and problem_state in ('"
diff --git a/perllib/FixMyStreet/App/Controller/JS.pm b/perllib/FixMyStreet/App/Controller/JS.pm
index 1ced9d43b..483c3c2cc 100755
--- a/perllib/FixMyStreet/App/Controller/JS.pm
+++ b/perllib/FixMyStreet/App/Controller/JS.pm
@@ -24,6 +24,8 @@ sub translation_strings : LocalRegex('^translation_strings\.(.*?)\.js$') : Args(
$c->res->content_type( 'application/javascript' );
}
+sub validation_rules : Path('validation_rules.js') : Args(0) { }
+
__PACKAGE__->meta->make_immutable;
1;
diff --git a/perllib/FixMyStreet/App/Controller/Open311.pm b/perllib/FixMyStreet/App/Controller/Open311.pm
index 3a6794325..7b8cb649f 100644
--- a/perllib/FixMyStreet/App/Controller/Open311.pm
+++ b/perllib/FixMyStreet/App/Controller/Open311.pm
@@ -100,7 +100,7 @@ sub error : Private {
sub get_discovery : Private {
my ( $self, $c ) = @_;
- my $contact_email = $c->config->{CONTACT_EMAIL};
+ my $contact_email = $c->cobrand->contact_email;
my $prod_url = 'http://www.fiksgatami.no/open311';
my $test_url = 'http://fiksgatami-dev.nuug.no/open311';
my $prod_changeset = '2011-04-08T00:00:00Z';
diff --git a/perllib/FixMyStreet/App/Controller/Report.pm b/perllib/FixMyStreet/App/Controller/Report.pm
index 39d750562..460ccaec5 100644
--- a/perllib/FixMyStreet/App/Controller/Report.pm
+++ b/perllib/FixMyStreet/App/Controller/Report.pm
@@ -114,7 +114,7 @@ sub load_problem_or_display_error : Private {
if ( !$c->user || $c->user->id != $problem->user->id ) {
$c->detach(
'/page_error_403_access_denied',
- [ _('That report cannot be viewed on FixMyStreet.') ] #
+ [ sprintf(_('That report cannot be viewed on %s.'), $c->cobrand->site_title) ] #
);
}
}
diff --git a/perllib/FixMyStreet/App/Controller/Report/New.pm b/perllib/FixMyStreet/App/Controller/Report/New.pm
index 0ba8c5f71..687e54fbe 100644
--- a/perllib/FixMyStreet/App/Controller/Report/New.pm
+++ b/perllib/FixMyStreet/App/Controller/Report/New.pm
@@ -194,6 +194,7 @@ sub report_form_ajax : Path('ajax') : Args(0) {
councils_text => $councils_text,
category => $category,
extra_name_info => $extra_name_info,
+ categories => $c->stash->{category_options},
}
);
@@ -716,6 +717,14 @@ sub process_user : Private {
my $user_title = Utils::trim_text( $params{fms_extra_title} );
+ if ( $c->cobrand->allow_anonymous_reports ) {
+ my $anon_details = $c->cobrand->anonymous_account;
+
+ for my $key ( qw( email name ) ) {
+ $params{ $key } ||= $anon_details->{ $key };
+ }
+ }
+
# The user is already signed in
if ( $c->user_exists ) {
my $user = $c->user->obj;
@@ -780,7 +789,9 @@ sub process_report : Private {
'detail_offensive',
'may_show_name', #
'category', #
+ 'subcategory', #
'partial', #
+ 'service', #
);
# load the report
@@ -805,9 +816,14 @@ sub process_report : Private {
}
$report->detail( $detail );
+ # mobile device type
+ $report->service( $params{service} ) if $params{service};
+
# set these straight from the params
$report->category( _ $params{category} ) if $params{category};
+ $report->subcategory( $params{subcategory} );
+
my $areas = $c->stash->{all_areas_mapit};
$report->areas( ',' . join( ',', sort keys %$areas ) . ',' );
@@ -927,11 +943,7 @@ sub check_for_errors : Private {
# let the model check for errors
$c->stash->{field_errors} ||= {};
- my %field_errors = (
- %{ $c->stash->{field_errors} },
- %{ $c->stash->{report}->user->check_for_errors },
- %{ $c->stash->{report}->check_for_errors },
- );
+ my %field_errors = $c->cobrand->report_check_for_errors( $c );
# Zurich, we don't care about title or name
# There is no title, and name is optional
@@ -978,7 +990,14 @@ sub save_user_and_report : Private {
my $report = $c->stash->{report};
# Save or update the user if appropriate
- if ( !$report->user->in_storage ) {
+ if ( $c->cobrand->never_confirm_reports ) {
+ if ( $report->user->in_storage() ) {
+ $report->user->update();
+ } else {
+ $report->user->insert();
+ }
+ $report->confirm();
+ } elsif ( !$report->user->in_storage ) {
# User does not exist.
# Store changes in token for when token is validated.
$c->stash->{token_data} = {
@@ -1106,6 +1125,10 @@ sub redirect_or_confirm_creation : Private {
if ( $c->cobrand->moniker eq 'fixmybarangay' && $c->user->from_body && $c->stash->{external_source_id}) {
$report_uri = $c->uri_for( '/report', $report->id, undef, { external_source_id => $c->stash->{external_source_id} } );
+ } elsif ( $c->cobrand->never_confirm_reports && $report->non_public ) {
+ $c->log->info( 'cobrand was set to always confirm reports and report was non public, success page showed');
+ $c->stash->{template} = 'report_created.html';
+ return 1;
} else {
$report_uri = $c->cobrand->base_url_for_report( $report ) . $report->url;
}
diff --git a/perllib/FixMyStreet/App/Controller/Report/Update.pm b/perllib/FixMyStreet/App/Controller/Report/Update.pm
index 4467a7036..dbfd57e78 100644
--- a/perllib/FixMyStreet/App/Controller/Report/Update.pm
+++ b/perllib/FixMyStreet/App/Controller/Report/Update.pm
@@ -203,8 +203,23 @@ sub process_update : Private {
$params{state} = 'fixed - council'
if $params{state} eq 'fixed' && $c->user && $c->user->belongs_to_body( $update->problem->bodies_str );
$update->problem_state( $params{state} );
+ } else {
+ # we do this so we have a record of the state of the problem at this point
+ # for use when sending updates to external parties
+ if ( $update->mark_fixed ) {
+ $update->problem_state( 'fixed - user' );
+ } elsif ( $update->mark_open ) {
+ $update->problem_state( 'confirmed' );
+ # if there is not state param and neither of the above conditions apply
+ # then we are not changing the state of the problem so can use the current
+ # problem state
+ } else {
+ my $problem = $c->stash->{problem} || $update->problem;
+ $update->problem_state( $problem->state );
+ }
}
+
my @extra; # Next function fills this, but we don't need it here.
# This is just so that the error checkign for these extra fields runs.
# TODO Use extra here as it is used on reports.
@@ -249,7 +264,8 @@ sub check_for_errors : Private {
$error = 1 unless $c->user && $c->user->belongs_to_body( $c->stash->{update}->problem->bodies_str );
my $state = $c->req->param('state');
- $error = 1 unless ( grep { $state eq $_ } ( qw/confirmed closed fixed investigating planned/, 'in progress', 'fixed', 'fixed - user', 'fixed - council' ) );
+ $state = 'fixed - council' if $state eq 'fixed';
+ $error = 1 unless ( grep { $state eq $_ } ( FixMyStreet::DB::Result::Problem->council_states() ) );
if ( $error ) {
$c->stash->{errors} ||= [];
diff --git a/perllib/FixMyStreet/App/Controller/Reports.pm b/perllib/FixMyStreet/App/Controller/Reports.pm
index fc7eb522f..781dee698 100644
--- a/perllib/FixMyStreet/App/Controller/Reports.pm
+++ b/perllib/FixMyStreet/App/Controller/Reports.pm
@@ -112,14 +112,21 @@ sub ward : Path : Args(2) {
my $pins = $c->stash->{pins};
$c->stash->{page} = 'reports'; # So the map knows to make clickable pins
- FixMyStreet::Map::display_map(
- $c,
+ my %map_params = (
latitude => @$pins ? $pins->[0]{latitude} : 0,
longitude => @$pins ? $pins->[0]{longitude} : 0,
area => $c->stash->{ward} ? $c->stash->{ward}->{id} : [ keys %{$c->stash->{body}->areas} ],
- pins => $pins,
any_zoom => 1,
);
+ if ( $c->cobrand->moniker eq 'emptyhomes' ) {
+ FixMyStreet::Map::display_map(
+ $c, %map_params, latitude => 0, longitude => 0,
+ );
+ } else {
+ FixMyStreet::Map::display_map(
+ $c, %map_params, pins => $pins,
+ );
+ }
$c->cobrand->tweak_all_reports_map( $c );
diff --git a/perllib/FixMyStreet/Cobrand/Bromley.pm b/perllib/FixMyStreet/Cobrand/Bromley.pm
index a4c4f4ffc..0d4894aa8 100644
--- a/perllib/FixMyStreet/Cobrand/Bromley.pm
+++ b/perllib/FixMyStreet/Cobrand/Bromley.pm
@@ -80,9 +80,7 @@ sub process_extras {
sub contact_email {
my $self = shift;
- my $type = shift || '';
- return join( '@', 'info', 'bromley.gov.uk' ) if $type eq 'contact';
- return $self->next::method();
+ return join( '@', 'info', 'bromley.gov.uk' );
}
sub contact_name { 'Bromley Council (do not reply)'; }
diff --git a/perllib/FixMyStreet/Cobrand/Default.pm b/perllib/FixMyStreet/Cobrand/Default.pm
index 998f287a1..963c8a6ad 100644
--- a/perllib/FixMyStreet/Cobrand/Default.pm
+++ b/perllib/FixMyStreet/Cobrand/Default.pm
@@ -145,6 +145,14 @@ Can be specified in template.
sub enter_postcode_text { }
+=head2 site_title
+
+The name of the site
+
+=cut
+
+sub site_title { return 'FixMyStreet'; }
+
=head2 set_lang_and_domain
my $set_lang = $cobrand->set_lang_and_domain( $lang, $unicode, $dir )
@@ -581,6 +589,13 @@ For UK sub-cobrands, to specify various alternations needed for them.
=cut
sub is_council { 0; }
+=item is_two_tier
+
+For UK sub-cobrands, to specify various alternations needed for them.
+
+=cut
+sub is_two_tier { 0; }
+
=item council_rss_alert_options
Generate a set of options for council rss alerts.
@@ -723,6 +738,61 @@ until the contacts/area/body handling is rewritten to be better.
sub reports_by_body { 0; }
+=head2 default_show_name
+
+Returns true if the show name checkbox should be ticked by default.
+
+=cut
+
+sub default_show_name {
+ 1;
+}
+
+=head2 report_check_for_errors
+
+Perform validation for new reports. Takes Catalyst context object as an argument
+
+=cut
+
+sub report_check_for_errors {
+ my $self = shift;
+ my $c = shift;
+
+ return (
+ %{ $c->stash->{field_errors} },
+ %{ $c->stash->{report}->user->check_for_errors },
+ %{ $c->stash->{report}->check_for_errors },
+ );
+}
+
+sub report_sent_confirmation_email { 0; }
+
+=head2 never_confirm_reports
+
+If true then we never send an email to confirm a report
+
+=cut
+
+sub never_confirm_reports { 0; }
+
+=head2 allow_anonymous_reports
+
+If true then can have reports that are truely anonymous - i.e with no email or name. You
+need to also put details in the anonymous_account function too.
+
+=cut
+
+sub allow_anonymous_reports { 0; }
+
+=head2 anonymous_account
+
+Details to use for anonymous reports. This should return a hashref with an email and
+a name key
+
+=cut
+
+sub anonymous_account { undef; }
+
=head2 show_unconfirmed_reports
Whether reports in state 'unconfirmed' should still be shown on the public site.
diff --git a/perllib/FixMyStreet/Cobrand/FixMyBarangay.pm b/perllib/FixMyStreet/Cobrand/FixMyBarangay.pm
index c53b8e971..53bf9f3b4 100644
--- a/perllib/FixMyStreet/Cobrand/FixMyBarangay.pm
+++ b/perllib/FixMyStreet/Cobrand/FixMyBarangay.pm
@@ -43,5 +43,17 @@ sub can_support_problems {
sub reports_by_body { 1 }
+sub default_show_name {
+ my $self = shift;
+
+ return 0 if $self->{c}->user->from_council;
+ return 1;
+}
+
+# makes no sense to send questionnaires since FMB's reporters are mostly staff
+sub send_questionnaires {
+ return 0;
+}
+
1;
diff --git a/perllib/FixMyStreet/Cobrand/LichfieldDC.pm b/perllib/FixMyStreet/Cobrand/LichfieldDC.pm
index 99797f9c9..6a534fc18 100644
--- a/perllib/FixMyStreet/Cobrand/LichfieldDC.pm
+++ b/perllib/FixMyStreet/Cobrand/LichfieldDC.pm
@@ -8,6 +8,7 @@ sub council_id { return 2434; }
sub council_area { return 'Lichfield district'; }
sub council_name { return 'Lichfield District Council'; }
sub council_url { return 'lichfielddc'; }
+sub is_two_tier { return 1; }
# Different to councils parent due to this being a two-tier council. If we get
# more, this can be genericised in the parent.
@@ -26,18 +27,6 @@ sub disambiguate_location {
};
}
-# If we ever link to a county problem report, needs to be to main FixMyStreet
-sub base_url_for_report {
- my ( $self, $report ) = @_;
- my $bodies = $report->bodies;
- my %areas = map { %{$_->areas} } values %$bodies;
- if ( $areas{2434} ) {
- return $self->base_url;
- } else {
- return FixMyStreet->config('BASE_URL');
- }
-}
-
sub map_type {
return 'OSM';
}
diff --git a/perllib/FixMyStreet/Cobrand/Oxfordshire.pm b/perllib/FixMyStreet/Cobrand/Oxfordshire.pm
new file mode 100644
index 000000000..62550e626
--- /dev/null
+++ b/perllib/FixMyStreet/Cobrand/Oxfordshire.pm
@@ -0,0 +1,55 @@
+package FixMyStreet::Cobrand::Oxfordshire;
+use base 'FixMyStreet::Cobrand::UKCouncils';
+
+use strict;
+use warnings;
+
+sub council_id { return 2237; }
+sub council_area { return 'Oxfordshire'; }
+sub council_name { return 'Oxfordshire County Council'; }
+sub council_url { return 'oxfordshire'; }
+sub is_two_tier { return 1; }
+
+sub base_url {
+ return FixMyStreet->config('BASE_URL') if FixMyStreet->config('STAGING_SITE');
+ return 'http://fixmystreet.oxfordshire.gov.uk';
+}
+
+# Different to councils parent due to this being a two-tier council. If we get
+# more, this can be genericised in the parent.
+sub problems_clause {
+ return { bodies_str => { like => '%2237%' } };
+}
+
+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 enter_postcode_text {
+ my ($self) = @_;
+ return 'Enter an Oxfordshire postcode, or street name and area';
+}
+
+sub disambiguate_location {
+ my $self = shift;
+ my $string = shift;
+ return {
+ %{ $self->SUPER::disambiguate_location() },
+ centre => '51.765765,-1.322324',
+ span => '0.154963,0.24347', # NB span is not correct
+ bounds => [ 51.459413, -1.719500, 52.168471, -0.870066 ],
+ };
+}
+
+sub example_places {
+ return ( 'OX20 1SZ', 'Park St, Woodstock' );
+}
+
+sub default_show_name { 0 }
+
+1;
+
diff --git a/perllib/FixMyStreet/Cobrand/SeeSomething.pm b/perllib/FixMyStreet/Cobrand/SeeSomething.pm
new file mode 100644
index 000000000..88d5f6b78
--- /dev/null
+++ b/perllib/FixMyStreet/Cobrand/SeeSomething.pm
@@ -0,0 +1,148 @@
+package FixMyStreet::Cobrand::SeeSomething;
+use parent 'FixMyStreet::Cobrand::UKCouncils';
+
+use strict;
+use warnings;
+
+sub council_id { return [ 2520, 2522, 2514, 2546, 2519, 2538, 2535 ]; }
+sub council_area { return 'West Midlands'; }
+sub council_name { return 'See Something Say Something'; }
+sub council_url { return 'seesomething'; }
+sub area_types { [ 'MTD' ] }
+sub site_title { return 'See Something, Say Something'; }
+
+
+sub site_restriction {
+ my $self = shift;
+ return { bodies_str => { IN => $self->council_id } };
+}
+
+sub problems_clause {
+ my $self = shift;
+ return { bodies_str => { IN => $self->council_id } };
+}
+
+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 area_check {
+ my ( $self, $params, $context ) = @_;
+
+ my $councils = $params->{all_areas};
+ my $council_match = grep { $councils->{$_} } @{ $self->council_id };
+
+ if ($council_match) {
+ return 1;
+ }
+
+ return ( 0, "That location is not covered by See Something, Say Something" );
+}
+
+sub disambiguate_location {
+ my $self = shift;
+ my $string = shift;
+
+ my $town = 'West Midlands';
+
+ return {
+ %{ $self->SUPER::disambiguate_location() },
+ town => $town,
+ centre => '52.4803101685267,-2.2708272758854',
+ span => '1.4002794815887,2.06340043925997',
+ bounds => [ 51.8259444771676, -3.23554082684068, 53.2262239587563, -1.17214038758071 ],
+ };
+}
+
+sub example_places {
+ return ( 'WS1 4NH', 'Austin Drive, Coventry' );
+}
+
+sub send_questionnaires {
+ return 0;
+}
+
+sub ask_ever_reported {
+ return 0;
+}
+
+sub report_sent_confirmation_email { 1; }
+
+sub report_check_for_errors { return (); }
+
+sub never_confirm_reports { 1; }
+
+sub allow_anonymous_reports { 1; }
+
+sub anonymous_account { return { name => 'Anonymous Submission', email => FixMyStreet->config('DO_NOT_REPLY_EMAIL') }; }
+
+sub admin_pages {
+ my $self = shift;
+
+ return {
+ 'stats' => ['Reports', 0],
+ };
+};
+
+sub admin_stats {
+ my $self = shift;
+ my $c = $self->{c};
+
+ my %filters = ();
+
+ my %councils =
+ map {
+ $c->stash->{council_details}->{$_}->{name} =~ s/(?:Borough|City) Council//;
+ $_ => $c->stash->{council_details}->{$_}
+ }
+ @{ $self->council_id };
+
+ $c->stash->{council_details} = \%councils;
+
+ if ( !$c->user_exists || !grep { $_ == $c->user->from_council } @{ $self->council_id } ) {
+ $c->detach( '/page_error_404_not_found' );
+ }
+
+ if ( $c->req->param('category') ) {
+ $filters{category} = $c->req->param('category');
+ $c->stash->{category} = $c->req->param('category');
+ }
+
+ if ( $c->req->param('subcategory') ) {
+ $filters{subcategory} = $c->req->param('subcategory');
+ $c->stash->{subcategory} = $c->req->param('subcategory');
+ }
+
+ if ( $c->req->param('service') ) {
+ $filters{service} = { -ilike => $c->req->param('service') };
+ $c->stash->{service} = $c->req->param('service');
+ }
+
+ my $page = $c->req->params->{p} || 1;
+
+ my $p = $c->model('DB::Problem')->search(
+ {
+ confirmed => { not => undef },
+ %filters
+ },
+ {
+ columns => [ qw(
+ service category subcategory council confirmed
+ ) ],
+ order_by => { -desc=> [ 'confirmed' ] },
+ rows => 20,
+ }
+ )->page( $page );
+
+ $c->stash->{reports} = $p;
+ $c->stash->{pager} = $p->pager;
+
+ return 1;
+}
+
+1;
+
diff --git a/perllib/FixMyStreet/Cobrand/Stevenage.pm b/perllib/FixMyStreet/Cobrand/Stevenage.pm
index f7a9ccd84..560baba37 100644
--- a/perllib/FixMyStreet/Cobrand/Stevenage.pm
+++ b/perllib/FixMyStreet/Cobrand/Stevenage.pm
@@ -8,6 +8,7 @@ sub council_id { return 2347; }
sub council_area { return 'Stevenage'; }
sub council_name { return 'Stevenage Council'; }
sub council_url { return 'stevenage'; }
+sub is_two_tier { return 1; }
sub path_to_web_templates {
my $self = shift;
diff --git a/perllib/FixMyStreet/Cobrand/UKCouncils.pm b/perllib/FixMyStreet/Cobrand/UKCouncils.pm
index 2b4385a98..354b1b72a 100644
--- a/perllib/FixMyStreet/Cobrand/UKCouncils.pm
+++ b/perllib/FixMyStreet/Cobrand/UKCouncils.pm
@@ -86,4 +86,20 @@ sub recent_photos {
return $self->problems->recent_photos( $num, $lat, $lon, $dist );
}
+# If we ever link to a county problem report, needs to be to main FixMyStreet
+sub base_url_for_report {
+ my ( $self, $report ) = @_;
+ if ( $self->is_two_tier ) {
+ my $bodies = $report->bodies;
+ my %areas = map { %{$_->areas} } values %$bodies;
+ if ( $areas{$self->council_id} ) {
+ return $self->base_url;
+ } else {
+ return FixMyStreet->config('BASE_URL');
+ }
+ } else {
+ return $self->base_url;
+ }
+}
+
1;
diff --git a/perllib/FixMyStreet/DB/Result/Body.pm b/perllib/FixMyStreet/DB/Result/Body.pm
index 27ea1897e..83704563a 100644
--- a/perllib/FixMyStreet/DB/Result/Body.pm
+++ b/perllib/FixMyStreet/DB/Result/Body.pm
@@ -36,6 +36,8 @@ __PACKAGE__->add_columns(
{ data_type => "boolean", default_value => \"false", is_nullable => 0 },
"can_be_devolved",
{ data_type => "boolean", default_value => \"false", is_nullable => 0 },
+ "send_extended_statuses",
+ { data_type => "boolean", default_value => \"false", is_nullable => 0 },
"parent",
{ data_type => "integer", is_foreign_key => 1, is_nullable => 1 },
);
diff --git a/perllib/FixMyStreet/DB/Result/Comment.pm b/perllib/FixMyStreet/DB/Result/Comment.pm
index 2098a6495..33fbb9356 100644
--- a/perllib/FixMyStreet/DB/Result/Comment.pm
+++ b/perllib/FixMyStreet/DB/Result/Comment.pm
@@ -147,6 +147,11 @@ sub check_for_errors {
$errors{update} = _('Please enter a message')
unless $self->text =~ m/\S/;
+ if ( $self->text && $self->problem && $self->problem->bodies_str
+ && $self->problem->bodies_str eq '2482' && length($self->text) > 2000 ) {
+ $errors{update} = _('Updates are limited to 2000 characters in length. Please shorten your update');
+ }
+
return \%errors;
}
@@ -187,6 +192,10 @@ sub meta_problem_state {
my $state = $self->problem_state;
$state =~ s/ -.*$//;
+ $state = _("not the council's responsibility")
+ if $state eq 'not responsible';
+ $state = _('duplicate report') if $state eq 'duplicate';
+
return $state;
}
diff --git a/perllib/FixMyStreet/DB/Result/Problem.pm b/perllib/FixMyStreet/DB/Result/Problem.pm
index f43e31173..d9a2a0273 100644
--- a/perllib/FixMyStreet/DB/Result/Problem.pm
+++ b/perllib/FixMyStreet/DB/Result/Problem.pm
@@ -100,6 +100,8 @@ __PACKAGE__->add_columns(
{ data_type => "text", is_nullable => 1 },
"interest_count",
{ data_type => "integer", default_value => 0, is_nullable => 1 },
+ "subcategory",
+ { data_type => "text", is_nullable => 1 },
);
__PACKAGE__->set_primary_key("id");
__PACKAGE__->has_many(
@@ -196,10 +198,11 @@ HASHREF.
sub open_states {
my $states = {
- 'confirmed' => 1,
- 'investigating' => 1,
- 'planned' => 1,
- 'in progress' => 1,
+ 'confirmed' => 1,
+ 'investigating' => 1,
+ 'in progress' => 1,
+ 'planned' => 1,
+ 'action scheduled' => 1,
};
return wantarray ? keys %{$states} : $states;
@@ -237,7 +240,11 @@ HASHREF.
sub closed_states {
my $states = {
- 'closed' => 1,
+ 'closed' => 1,
+ 'unable to fix' => 1,
+ 'not responsible' => 1,
+ 'duplicate' => 1,
+ 'internal referral' => 1,
};
return wantarray ? keys %{$states} : $states;
@@ -248,21 +255,26 @@ sub closed_states {
@states = FixMyStreet::DB::Problem::visible_states();
-Get a list or states that should be visible on the site. If called in
+Get a list of states that should be visible on the site. If called in
array context then returns an array of names, otherwise returns a
HASHREF.
=cut
my $visible_states = {
- 'confirmed' => 1,
- 'planned' => 1,
- 'investigating' => 1,
- 'in progress' => 1,
- 'fixed' => 1,
- 'fixed - council' => 1,
- 'fixed - user' => 1,
- 'closed' => 1,
+ 'confirmed' => 1,
+ 'investigating' => 1,
+ 'in progress' => 1,
+ 'planned' => 1,
+ 'action scheduled' => 1,
+ 'fixed' => 1,
+ 'fixed - council' => 1,
+ 'fixed - user' => 1,
+ 'unable to fix' => 1,
+ 'not responsible' => 1,
+ 'duplicate' => 1,
+ 'closed' => 1,
+ 'internal referral' => 1,
};
sub visible_states {
return wantarray ? keys %{$visible_states} : $visible_states;
@@ -271,6 +283,63 @@ sub visible_states_add_unconfirmed {
$visible_states->{unconfirmed} = 1;
}
+=head2
+
+ @states = FixMyStreet::DB::Problem::all_states();
+
+Get a list of all states that a problem can have. If called in
+array context then returns an array of names, otherwise returns a
+HASHREF.
+
+=cut
+
+sub all_states {
+ my $states = {
+ 'hidden' => 1,
+ 'partial' => 1,
+ 'unconfirmed' => 1,
+ 'confirmed' => 1,
+ 'investigating' => 1,
+ 'in progress' => 1,
+ 'action scheduled' => 1,
+ 'fixed' => 1,
+ 'fixed - council' => 1,
+ 'fixed - user' => 1,
+ 'unable to fix' => 1,
+ 'not responsible' => 1,
+ 'duplicate' => 1,
+ 'closed' => 1,
+ 'internal referral' => 1,
+ };
+
+ return wantarray ? keys %{$states} : $states;
+}
+
+=head2
+
+ @states = FixMyStreet::DB::Problem::council_states();
+
+Get a list of states that are availble to council users. If called in
+array context then returns an array of names, otherwise returns a
+HASHREF.
+
+=cut
+sub council_states {
+ my $states = {
+ 'confirmed' => 1,
+ 'investigating' => 1,
+ 'action scheduled' => 1,
+ 'in progress' => 1,
+ 'fixed - council' => 1,
+ 'unable to fix' => 1,
+ 'not responsible' => 1,
+ 'duplicate' => 1,
+ 'internal referral' => 1,
+ };
+
+ return wantarray ? keys %{$states} : $states;
+}
+
my $tz = DateTime::TimeZone->new( name => "local" );
sub confirmed_local {
@@ -371,6 +440,11 @@ sub check_for_errors {
$self->category(undef);
}
+ if ( $self->bodies_str && $self->detail &&
+ $self->bodies_str eq '2482' && length($self->detail) > 2000 ) {
+ $errors{detail} = _('Reports are limited to 2000 characters in length. Please shorten your report');
+ }
+
return \%errors;
}
@@ -508,11 +582,7 @@ sub meta_line {
my $category = _($problem->category);
utf8::decode($category);
- if ($problem->anonymous) {
- $meta = sprintf(_('%s, reported anonymously at %s'), $category, $date_time);
- } else {
- $meta = sprintf(_('%s, reported by %s at %s'), $category, $problem->name, $date_time);
- }
+ $meta = sprintf(_('%s, reported at %s'), $category, $date_time);
} else {
@@ -598,7 +668,8 @@ sub body {
# Note: this only makes sense when called on a problem that has been sent!
sub can_display_external_id {
my $self = shift;
- if ($self->external_id && $self->send_method_used && $self->send_method_used eq 'barnet') {
+ if ($self->external_id && $self->send_method_used &&
+ ($self->send_method_used eq 'barnet' || $self->council =~ /2237/)) {
return 1;
}
return 0;
@@ -618,7 +689,7 @@ sub processed_summary_string {
my ( $problem, $c ) = @_;
my ($duration_clause, $external_ref_clause);
if ($problem->whensent) {
- $duration_clause = $problem->duration_string($c)
+ $duration_clause = $problem->duration_string($c);
}
if ($problem->can_display_external_id) {
if ($duration_clause) {
diff --git a/perllib/FixMyStreet/DB/ResultSet/AlertType.pm b/perllib/FixMyStreet/DB/ResultSet/AlertType.pm
index 5b6b33d94..8e9b3d17e 100644
--- a/perllib/FixMyStreet/DB/ResultSet/AlertType.pm
+++ b/perllib/FixMyStreet/DB/ResultSet/AlertType.pm
@@ -231,13 +231,12 @@ sub _send_aggregated_alert_email(%) {
unless -e $template;
$template = Utils::read_file($template);
- my $sender = $cobrand->contact_email;
- (my $from = $sender) =~ s/team/fms-DO-NOT-REPLY/; # XXX
+ my $sender = FixMyStreet->config('DO_NOT_REPLY_EMAIL');
my $result = FixMyStreet::App->send_email_cron(
{
_template_ => $template,
_parameters_ => \%data,
- From => [ $from, _($cobrand->contact_name) ],
+ From => [ $sender, _($cobrand->contact_name) ],
To => $data{alert_email},
},
$sender,
diff --git a/perllib/FixMyStreet/DB/ResultSet/Problem.pm b/perllib/FixMyStreet/DB/ResultSet/Problem.pm
index dc4643673..078c78d0e 100644
--- a/perllib/FixMyStreet/DB/ResultSet/Problem.pm
+++ b/perllib/FixMyStreet/DB/ResultSet/Problem.pm
@@ -291,6 +291,16 @@ sub send_reports {
$h{closest_address} = $cobrand->find_closest( $h{latitude}, $h{longitude}, $row );
}
+ if ( $cobrand->allow_anonymous_reports &&
+ $row->user->email eq $cobrand->anonymous_account->{'email'}
+ ) {
+ $h{anonymous_report} = 1;
+ $h{user_details} = _('This report was submitted anonymously');
+ } else {
+ $h{user_details} = sprintf(_('Name: %s'), $row->name) . "\n\n";
+ $h{user_details} .= sprintf(_('Email: %s'), $row->user->email) . "\n\n";
+ }
+
my %reporters = ();
my ( $sender_count );
if ($site eq 'emptyhomes') {
@@ -338,6 +348,10 @@ sub send_reports {
$h{category_line} = sprintf(_("Category: %s"), $h{category}) . "\n\n";
}
+ if ( $row->subcategory ) {
+ $h{subcategory_line} = sprintf(_("Subcategory: %s"), $row->subcategory) . "\n\n";
+ }
+
$h{bodies_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"
@@ -364,12 +378,9 @@ sub send_reports {
if (mySociety::Config::get('STAGING_SITE') && !mySociety::Config::get('SEND_REPORTS_ON_STAGING')) {
# on a staging server send emails to ourselves rather than the bodies
- my @testing_bodies = split( '\|', mySociety::Config::get('TESTING_COUNCILS') );
- unless ( grep { $row->bodies_str eq $_ } @testing_bodies ) {
- %reporters = map { $_ => $reporters{$_} } grep { /FixMyStreet::SendReport::(Email|NI)/ } keys %reporters;
- unless (%reporters) {
- %reporters = ( 'FixMyStreet::SendReport::Email' => FixMyStreet::SendReport::Email->new() );
- }
+ %reporters = map { $_ => $reporters{$_} } grep { /FixMyStreet::SendReport::(Email|NI)/ } keys %reporters;
+ unless (%reporters) {
+ %reporters = ( 'FixMyStreet::SendReport::Email' => FixMyStreet::SendReport::Email->new() );
}
}
@@ -396,6 +407,9 @@ sub send_reports {
whensent => \'ms_current_timestamp()',
lastupdate => \'ms_current_timestamp()',
} );
+ if ( $cobrand->report_sent_confirmation_email && !$h{anonymous_report}) {
+ _send_report_sent_email( $row, \%h, $nomail );
+ }
} else {
my @errors;
for my $sender ( keys %reporters ) {
@@ -441,4 +455,30 @@ sub send_reports {
}
}
+sub _send_report_sent_email {
+ my $row = shift;
+ my $h = shift;
+ my $nomail = shift;
+
+ my $template = 'confirm_report_sent.txt';
+ my $template_path = FixMyStreet->path_to( "templates", "email", $row->cobrand, $row->lang, $template )->stringify;
+ $template_path = FixMyStreet->path_to( "templates", "email", $row->cobrand, $template )->stringify
+ unless -e $template_path;
+ $template_path = FixMyStreet->path_to( "templates", "email", "default", $template )->stringify
+ unless -e $template_path;
+ $template = Utils::read_file( $template_path );
+
+ my $result = FixMyStreet::App->send_email_cron(
+ {
+ _template_ => $template,
+ _parameters_ => $h,
+ To => $row->user->email,
+ From => mySociety::Config::get('CONTACT_EMAIL'),
+ },
+ mySociety::Config::get('CONTACT_EMAIL'),
+ [ $row->user->email ],
+ $nomail
+ );
+}
+
1;
diff --git a/perllib/FixMyStreet/DB/ResultSet/Questionnaire.pm b/perllib/FixMyStreet/DB/ResultSet/Questionnaire.pm
index d6b3eb5cb..1b9521a9f 100644
--- a/perllib/FixMyStreet/DB/ResultSet/Questionnaire.pm
+++ b/perllib/FixMyStreet/DB/ResultSet/Questionnaire.pm
@@ -89,9 +89,8 @@ sub send_questionnaires_period {
} );
$h{url} = $cobrand->base_url($row->cobrand_data) . '/Q/' . $token->token;
- my $sender = $cobrand->contact_email;
+ my $sender = FixMyStreet->config('DO_NOT_REPLY_EMAIL');
my $sender_name = _($cobrand->contact_name);
- $sender =~ s/team/fms-DO-NOT-REPLY/;
print "Sending questionnaire " . $questionnaire->id . ", problem "
. $row->id . ", token " . $token->token . " to "
diff --git a/perllib/FixMyStreet/EmailSend.pm b/perllib/FixMyStreet/EmailSend.pm
index 61d8a70c2..8b6eed462 100644
--- a/perllib/FixMyStreet/EmailSend.pm
+++ b/perllib/FixMyStreet/EmailSend.pm
@@ -2,10 +2,7 @@ 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/;
+ my $sender = FixMyStreet->config('DO_NOT_REPLY_EMAIL');
return $sender;
}
diff --git a/perllib/FixMyStreet/SendReport/Email.pm b/perllib/FixMyStreet/SendReport/Email.pm
index 182c47d56..1ff476da3 100644
--- a/perllib/FixMyStreet/SendReport/Email.pm
+++ b/perllib/FixMyStreet/SendReport/Email.pm
@@ -33,7 +33,13 @@ sub build_recipient_list {
$self->unconfirmed_notes->{$body_email}{$row->category} = $note;
}
- push @{ $self->to }, [ $body_email, $body->name ];
+ # see something uses council areas but doesn't send to councils so just use a
+ # generic name here to minimise confusion
+ if ( $row->cobrand eq 'seesomething' ) {
+ push @{ $self->to }, [ $body_email, 'See Something, Say Something' ];
+ } else {
+ push @{ $self->to }, [ $body_email, $body->name ];
+ }
$recips{$body_email} = 1;
}
diff --git a/perllib/FixMyStreet/SendReport/Open311.pm b/perllib/FixMyStreet/SendReport/Open311.pm
index c6d838998..1b79bcc99 100644
--- a/perllib/FixMyStreet/SendReport/Open311.pm
+++ b/perllib/FixMyStreet/SendReport/Open311.pm
@@ -9,6 +9,9 @@ use FixMyStreet::App;
use mySociety::Config;
use DateTime::Format::W3CDTF;
use Open311;
+use Readonly;
+
+Readonly::Scalar my $COUNCIL_ID_OXFORDSHIRE => 2237;
sub should_skip {
my $self = shift;
@@ -34,7 +37,7 @@ sub send {
my $send_notpinpointed = 0;
my $use_service_as_deviceid = 0;
- my $basic_desc = 0;
+ my $extended_desc = 1;
# To rollback temporary changes made by this function
my $revert = 0;
@@ -69,7 +72,22 @@ sub send {
push @$extra, { name => 'last_name', value => $lastname };
}
- $basic_desc = 1;
+ $extended_desc = 0;
+ }
+
+ # extra Oxfordshire fields: send nearest street, postcode, northing and easting, and the FMS id
+ if ( $row->council =~ /$COUNCIL_ID_OXFORDSHIRE/ ) {
+
+ my $extra = $row->extra;
+ push @$extra, { name => 'external_id', value => $row->id };
+ push @$extra, { name => 'closest_address', value => $h->{closest_address} } if $h->{closest_address};
+ if ( $row->used_map || ( !$row->used_map && !$row->postcode ) ) {
+ push @$extra, { name => 'northing', value => $h->{northing} };
+ push @$extra, { name => 'easting', value => $h->{easting} };
+ }
+ $row->extra( $extra );
+
+ $extended_desc = 'oxfordshire';
}
# FIXME: we've already looked this up before
@@ -86,7 +104,7 @@ sub send {
always_send_latlong => $always_send_latlong,
send_notpinpointed => $send_notpinpointed,
use_service_as_deviceid => $use_service_as_deviceid,
- basic_description => $basic_desc,
+ extended_description => $extended_desc,
);
# non standard west berks end points
@@ -94,6 +112,12 @@ sub send {
$open311->endpoints( { services => 'Services', requests => 'Requests' } );
}
+ # non-standard Oxfordshire endpoint (because it's just a script, not a full Open311 service)
+ if ( $row->council =~ /$COUNCIL_ID_OXFORDSHIRE/ ) {
+ $open311->endpoints( { requests => 'open311_service_request.cgi' } );
+ $revert = 1;
+ }
+
# required to get round issues with CRM constraints
if ( $row->bodies_str =~ /2218/ ) {
$row->user->name( $row->user->id . ' ' . $row->user->name );
@@ -101,7 +125,7 @@ sub send {
}
if ($row->cobrand eq 'fixmybarangay') {
- # FixMyBarangay endpoints expect external_id as an attribute
+ # FixMyBarangay endpoints expect external_id as an attribute, as do Oxfordshire
$row->extra( [ { 'name' => 'external_id', 'value' => $row->id } ] );
$revert = 1;
}
@@ -115,9 +139,17 @@ sub send {
$row->external_id( $resp );
$row->send_method_used('Open311');
if ($row->cobrand eq 'fixmybarangay') {
- # currently the only external body using Open311 is DPS
- # (this will change when we have 'body' logic in place, meanwhile: hardcoded)
- $row->external_body("DPS");
+ # FixMyBarangay: currently the external bodies using Open311 are DPS, DEPW, DPWH
+ # for now identify the latter two by their name in the service_code ($contact->email)
+ # So: this works because we are anticipating the service codes for (e.g., potholes) look
+ # like this:
+ # POTDEPW or POTDPWH
+ # (TODO: this will change when we have 'body' logic in place, meanwhile: hardcoded)
+ if ($contact->email =~ /(DEPW|DPWH)$/i) {
+ $row->external_body(uc $1); # body is DEPW (city roads) or DPWH (national roads)
+ } else {
+ $row->external_body("DPS"); # only other open311 dept is DPS
+ }
}
$result *= 0;
$self->success( 1 );
diff --git a/perllib/Open311.pm b/perllib/Open311.pm
index 52e17e99d..efa0ac64f 100644
--- a/perllib/Open311.pm
+++ b/perllib/Open311.pm
@@ -22,9 +22,10 @@ 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 );
+has extended_description => ( is => 'ro', isa => 'Str', default => 1 );
has use_service_as_deviceid => ( is => 'ro', isa => 'Bool', default => 0 );
has use_extended_updates => ( is => 'ro', isa => 'Bool', default => 0 );
+has extended_statuses => ( is => 'ro', isa => 'Bool', default => 0 );
before [
qw/get_service_list get_service_meta_info get_service_requests get_service_request_updates
@@ -38,7 +39,11 @@ sub get_service_list {
my $service_list_xml = $self->_get( $self->endpoints->{services} );
- return $self->_get_xml_object( $service_list_xml );
+ if ( $service_list_xml ) {
+ return $self->_get_xml_object( $service_list_xml );
+ } else {
+ return undef;
+ }
}
sub get_service_meta_info {
@@ -95,12 +100,12 @@ sub _populate_service_request_params {
my $service_code = shift;
my $description;
- if ( $self->basic_description ) {
- $description = $problem->detail;
- } else {
+ if ( $self->extended_description ) {
$description = $self->_generate_service_request_description(
$problem, $extra
);
+ } else {
+ $description = $problem->detail;
}
my ( $firstname, $lastname ) = ( $problem->user->name =~ /(\w+)\.?\s+(.+)/ );
@@ -168,8 +173,6 @@ sub _generate_service_request_description {
my $extra = shift;
my $description = <<EOT;
-title: @{[$problem->title()]}
-
detail: @{[$problem->detail()]}
url: $extra->{url}
@@ -177,6 +180,12 @@ url: $extra->{url}
Submitted via FixMyStreet
EOT
;
+ if ($self->extended_description ne 'oxfordshire') {
+ $description = <<EOT . $description;
+title: @{[$problem->title()]}
+
+EOT
+ }
return $description;
}
@@ -283,10 +292,39 @@ sub _populate_service_request_update_params {
my $name = $comment->name || $comment->user->name;
my ( $firstname, $lastname ) = ( $name =~ /(\w+)\.?\s+(.+)/ );
+ # fall back to problem state as it's probably correct
+ my $state = $comment->problem_state || $comment->problem->state;
+
+ my $status = 'OPEN';
+ if ( $self->extended_statuses ) {
+ if ( FixMyStreet::DB::Result::Problem->fixed_states()->{$state} ) {
+ $status = 'FIXED';
+ } elsif ( $state eq 'in progress' ) {
+ $status = 'IN_PROGRESS';
+ } elsif ($state eq 'action scheduled'
+ || $state eq 'planned' ) {
+ $status = 'ACTION_SCHEDULED';
+ } elsif ( $state eq 'investigating' ) {
+ $status = 'INVESTIGATING';
+ } elsif ( $state eq 'duplicate' ) {
+ $status = 'DUPLICATE';
+ } elsif ( $state eq 'not responsible' ) {
+ $status = 'NOT_COUNCILS_RESPONSIBILITY';
+ } elsif ( $state eq 'unable to fix' ) {
+ $status = 'NO_FURTHER_ACTION';
+ } elsif ( $state eq 'internal referral' ) {
+ $status = 'INTERNAL_REFERRAL';
+ }
+ } else {
+ if ( !FixMyStreet::DB::Result::Problem->open_states()->{$state} ) {
+ $status = 'CLOSED';
+ }
+ }
+
my $params = {
updated_datetime => DateTime::Format::W3CDTF->format_datetime($comment->confirmed_local->set_nanosecond(0)),
service_request_id => $comment->problem->external_id,
- status => $comment->problem->is_open ? 'OPEN' : 'CLOSED',
+ status => $status,
email => $comment->user->email,
description => $comment->text,
last_name => $lastname,
diff --git a/perllib/Open311/GetServiceRequestUpdates.pm b/perllib/Open311/GetServiceRequestUpdates.pm
index 27cb21c3a..e4416f792 100644
--- a/perllib/Open311/GetServiceRequestUpdates.pm
+++ b/perllib/Open311/GetServiceRequestUpdates.pm
@@ -11,6 +11,9 @@ has end_date => ( is => 'ro', default => undef );
has suppress_alerts => ( is => 'rw', default => 0 );
has verbose => ( is => 'ro', default => 0 );
+Readonly::Scalar my $AREA_ID_BROMLEY => 2482;
+Readonly::Scalar my $AREA_ID_OXFORDSHIRE => 2237;
+
sub fetch {
my $self = shift;
@@ -31,11 +34,16 @@ sub fetch {
jurisdiction => $body->jurisdiction,
);
- if ( $body->areas->{2482} ) {
+ # custom endpoint URLs because these councils have non-standard paths
+ if ( $body->areas->{$AREA_ID_BROMLEY} ) {
my $endpoints = $o->endpoints;
$endpoints->{update} = 'update.xml';
$endpoints->{service_request_updates} = 'update.xml';
$o->endpoints( $endpoints );
+ } elsif ( $body->areas->{$AREA_ID_OXFORDSHIRE} ) {
+ my $endpoints = $o->endpoints;
+ $endpoints->{service_request_updates} = 'open311_service_request_update.cgi';
+ $o->endpoints( $endpoints );
}
$self->suppress_alerts( $body->suppress_alerts );
@@ -55,7 +63,7 @@ sub update_comments {
push @args, $self->start_date;
push @args, $self->end_date;
# default to asking for last 2 hours worth if not Bromley
- } elsif ( ! $body_details->{areas}->{2482} ) {
+ } elsif ( ! $body_details->{areas}->{$AREA_ID_BROMLEY} ) {
my $end_dt = DateTime->now();
my $start_dt = $end_dt->clone;
$start_dt->add( hours => -2 );
@@ -79,13 +87,15 @@ sub update_comments {
# what problem it belongs to so just skip
next unless $request_id;
- my $problem =
- FixMyStreet::App->model('DB::Problem')
- ->search( {
- external_id => $request_id,
- # XXX This assumes that areas will actually only be one area.
- bodies_str => { like => '%' . join(",", keys %{$body_details->{areas}}) . '%' },
- } );
+ my $problem;
+ my $criteria = { external_id => $request_id };
+ if ($open311->jurisdiction =~ /^fixmybarangay_(dps|dpwh|depw)$/i) { # use jurisdiction (not area_id) for FMB bodies
+ $criteria->{ external_body } = uc $1;
+ } else {
+ # XXX This assumes that areas will actually only be one area.
+ $criteria->{ bodies_str } = { like => '%' . join(",", keys %{$body_details->{areas}}) . '%' };
+ }
+ $problem = FixMyStreet::App->model('DB::Problem')->search( $criteria );
if (my $p = $problem->first) {
my $c = $p->comments->search( { external_id => $request->{update_id} } );
@@ -113,12 +123,14 @@ sub update_comments {
# 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' );
+ my $state = $self->map_state( $request->{status} );
+
+ # don't update state unless it's an allowed state and it's
+ # actually changing the state of the problem
+ if ( FixMyStreet::DB::Result::Problem->council_states()->{$state} && $p->state ne $state &&
+ !( $p->is_fixed && FixMyStreet::DB::Result::Problem->fixed_states()->{$state} ) ) {
+ $p->state($state);
+ $comment->problem_state($state);
}
}
@@ -146,4 +158,22 @@ sub update_comments {
return 1;
}
+sub map_state {
+ my $self = shift;
+ my $incoming_state = shift;
+
+ $incoming_state = lc($incoming_state);
+ $incoming_state =~ s/_/ /g;
+
+ my %state_map = (
+ fixed => 'fixed - council',
+ 'not councils responsibility' => 'not responsible',
+ 'no further action' => 'unable to fix',
+ open => 'confirmed',
+ closed => 'fixed - council'
+ );
+
+ return $state_map{$incoming_state} || $incoming_state;
+}
+
1;
diff --git a/perllib/Open311/PopulateServiceList.pm b/perllib/Open311/PopulateServiceList.pm
index bd90e10e9..57ef90ecb 100644
--- a/perllib/Open311/PopulateServiceList.pm
+++ b/perllib/Open311/PopulateServiceList.pm
@@ -22,6 +22,7 @@ sub process_bodies {
while ( my $body = $self->bodies->next ) {
next unless $body->endpoint;
next unless lc($body->send_method) eq 'open311';
+ next if $body->jurisdiction =~ /^fixmybarangay_\w+$/; # FMB depts. not using service discovery yet
$self->_current_body( $body );
$self->process_body;
}
@@ -29,7 +30,6 @@ sub process_bodies {
sub process_body {
my $self = shift;
-
my $open311 = Open311->new(
endpoint => $self->_current_body->endpoint,
jurisdiction => $self->_current_body->jurisdiction,
diff --git a/t/app/controller/dashboard.t b/t/app/controller/dashboard.t
index 5a8465edc..091335040 100644
--- a/t/app/controller/dashboard.t
+++ b/t/app/controller/dashboard.t
@@ -80,7 +80,7 @@ my $categories = scraper {
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=action_scheduled] > td", 'action_scheduled[]' => 'TEXT',
process "tr[id=investigating] > td", 'investigating[]' => 'TEXT',
process "tr[id=marked] > td", 'marked[]' => 'TEXT',
process "tr[id=avg_marked] > td", 'avg_marked[]' => 'TEXT',
@@ -214,10 +214,10 @@ foreach my $test (
}
},
{
- desc => 'marked as planned today',
+ desc => 'marked as action scheduled today',
confirm_dt => DateTime->now->subtract( days => 1 ),
mark_dt => DateTime->now,
- state => 'planned',
+ state => 'action scheduled',
counts => {
totals => $is_monday ? [ 0,5,5,5] : [5,5,5,5],
user => [1,1,1,1],
@@ -226,15 +226,15 @@ foreach my $test (
avg_marked => [1,1,1,1],
investigating => [1,1,1,1],
in_progress => [1,1,1,1],
- planned => [1,1,1,1],
+ action_scheduled => [1,1,1,1],
marked => [3,3,3,3]
}
},
{
- desc => 'marked as planned today, confirmed a week ago',
+ desc => 'marked as action scheduled today, confirmed a week ago',
confirm_dt => DateTime->now->subtract( days => 8 ),
mark_dt => DateTime->now,
- state => 'planned',
+ state => 'action scheduled',
counts => {
totals => $is_monday ? [0,5,6,6] : [5,5,6,6],
user => [1,1,1,1],
@@ -243,7 +243,7 @@ foreach my $test (
avg_marked => [3,3,3,3],
investigating => [1,1,1,1],
in_progress => [1,1,1,1],
- planned => [2,2,2,2],
+ action_scheduled => [2,2,2,2],
marked => [4,4,4,4]
}
},
@@ -261,7 +261,7 @@ foreach my $test (
avg_marked => [3,3,3,3],
investigating => [1,1,1,1],
in_progress => [1,1,1,1],
- planned => [2,2,2,2],
+ action_scheduled => [2,2,2,2],
marked => [4,4,4,4]
}
},
@@ -279,7 +279,7 @@ foreach my $test (
avg_marked => [3,3,3,3],
investigating => [1,1,1,1],
in_progress => [1,1,1,1],
- planned => [2,2,2,2],
+ action_scheduled => [2,2,2,2],
marked => [4,4,4,4]
}
},
@@ -297,7 +297,7 @@ foreach my $test (
avg_marked => [3,3,3,3],
investigating => [1,1,1,1],
in_progress => [1,1,1,1],
- planned => [2,2,2,2],
+ action_scheduled => [2,2,2,2],
marked => [4,4,4,4]
}
},
@@ -315,11 +315,30 @@ foreach my $test (
avg_marked => [2,2,2,2],
investigating => [1,1,1,1],
in_progress => [1,1,1,1],
- planned => [2,2,2,2],
+ action_scheduled => [2,2,2,2],
closed => [1,1,1,1],
marked => [5,5,5,5]
}
},
+ {
+ desc => 'marked as planned',
+ confirm_dt => DateTime->now->subtract( days => 1 ),
+ mark_dt => DateTime->now,
+ state => 'planned',
+ counts => {
+ totals => $is_monday ? [0,7,10,11] : [7,7,10,11],
+ 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],
+ action_scheduled => [3,3,3,3],
+ closed => [1,1,1,1],
+ marked => [6,6,6,6]
+ }
+ },
) {
subtest $test->{desc} => sub {
make_problem(
@@ -530,6 +549,17 @@ for my $test (
report_counts_after => [1,0,0],
},
{
+ desc => 'planned counted as action scheduled',
+ p1 => {
+ state => 'planned',
+ conf_dt => DateTime->now(),
+ category => 'Potholes',
+ },
+ state => 'action scheduled',
+ report_counts => [3,0,0],
+ report_counts_after => [1,0,0],
+ },
+ {
desc => 'All fixed states count as fixed',
p1 => {
state => 'fixed - council',
@@ -542,7 +572,7 @@ for my $test (
category => 'Potholes',
},
state => 'fixed',
- report_counts => [4,0,0],
+ report_counts => [5,0,0],
report_counts_after => [3,0,0],
},
) {
diff --git a/t/app/controller/questionnaire.t b/t/app/controller/questionnaire.t
index a99f4c645..5c81a43d1 100644
--- a/t/app/controller/questionnaire.t
+++ b/t/app/controller/questionnaire.t
@@ -329,6 +329,10 @@ for my $test (
fixed => 0
},
{
+ state => 'action scheduled',
+ fixed => 0
+ },
+ {
state => 'in progress',
fixed => 0
},
@@ -337,6 +341,18 @@ for my $test (
fixed => 0
},
{
+ state => 'duplicate',
+ fixed => 0
+ },
+ {
+ state => 'not responsible',
+ fixed => 0
+ },
+ {
+ state => 'unable to fix',
+ fixed => 0
+ },
+ {
state => 'closed',
fixed => 0
},
diff --git a/t/app/controller/report_display.t b/t/app/controller/report_display.t
index 10ef3dfd9..a3c4edfc7 100644
--- a/t/app/controller/report_display.t
+++ b/t/app/controller/report_display.t
@@ -297,6 +297,38 @@ for my $test (
fixed => 1
},
{
+ description => 'duplicate report',
+ date => DateTime->now,
+ state => 'duplicate',
+ banner_id => 'closed',
+ banner_text => 'closed',
+ fixed => 0
+ },
+ {
+ description => 'not responsible report',
+ date => DateTime->now,
+ state => 'not responsible',
+ banner_id => 'closed',
+ banner_text => 'closed',
+ fixed => 0
+ },
+ {
+ description => 'unable to fix report',
+ date => DateTime->now,
+ state => 'unable to fix',
+ banner_id => 'closed',
+ banner_text => 'closed',
+ fixed => 0
+ },
+ {
+ description => 'internal referral report',
+ date => DateTime->now,
+ state => 'internal referral',
+ banner_id => 'closed',
+ banner_text => 'closed',
+ fixed => 0
+ },
+ {
description => 'closed report',
date => DateTime->now,
state => 'closed',
@@ -313,6 +345,14 @@ for my $test (
fixed => 0
},
{
+ description => 'action scheduled report',
+ date => DateTime->now,
+ state => 'action scheduled',
+ banner_id => 'progress',
+ banner_text => 'progress',
+ fixed => 0
+ },
+ {
description => 'planned report',
date => DateTime->now,
state => 'planned',
@@ -321,7 +361,7 @@ for my $test (
fixed => 0
},
{
- description => 'in progressreport',
+ description => 'in progress report',
date => DateTime->now,
state => 'in progress',
banner_id => 'progress',
diff --git a/t/app/controller/report_new.t b/t/app/controller/report_new.t
index 783f3fb01..868977953 100644
--- a/t/app/controller/report_new.t
+++ b/t/app/controller/report_new.t
@@ -1142,67 +1142,239 @@ SKIP: {
skip( "Need 'lichfielddc' in ALLOWED_COBRANDS config", 100 )
unless FixMyStreet::Cobrand->exists('lichfielddc');
- my $test_email = 'test-22@example.com';
- $mech->host( 'http://lichfielddc.fixmystreet.com/' );
- $mech->clear_emails_ok;
- $mech->log_out_ok;
-
- $mech->get_ok('/around');
- $mech->content_contains( "Lichfield District Council FixMyStreet" );
- $mech->submit_form_ok( { with_fields => { pc => 'WS13 7RD' } }, "submit location" );
- $mech->follow_link_ok( { text_regex => qr/skip this step/i, }, "follow 'skip this step' link" );
- $mech->submit_form_ok(
+ for my $test (
{
- button => 'submit_register',
- with_fields => {
- title => 'Test Report',
- detail => 'Test report details.',
- photo => '',
- name => 'Joe Bloggs',
- may_show_name => '1',
- email => $test_email,
- phone => '07903 123 456',
- category => 'Street lighting',
- }
+ desc => 'confirm link for cobrand council in two tier cobrand links to cobrand site',
+ category => 'Trees',
+ council => 2434,
+ national => 0,
+ button => 'submit_register',
},
- "submit good details"
- );
- is_deeply $mech->page_errors, [], "check there were no errors";
+ {
+ desc => 'confirm link for non cobrand council in two tier cobrand links to national site',
+ category => 'Street Lighting',
+ council => 2240,
+ national => 1,
+ button => 'submit_register',
+ },
+ {
+ desc => 'confirm redirect for cobrand council in two tier cobrand redirects to cobrand site',
+ category => 'Trees',
+ council => 2434,
+ national => 0,
+ redirect => 1,
+ },
+ {
+ desc => 'confirm redirect for non cobrand council in two tier cobrand redirect to national site',
+ category => 'Street Lighting',
+ council => 2240,
+ national => 1,
+ redirect => 1,
+ },
+ ) {
+ subtest $test->{ desc } => sub {
+ my $test_email = 'test-22@example.com';
+ $mech->host( 'http://lichfielddc.fixmystreet.com/' );
+ $mech->clear_emails_ok;
+ $mech->log_out_ok;
+
+ my $user = $mech->log_in_ok($test_email) if $test->{redirect};
+
+ $mech->get_ok('/around');
+ $mech->content_contains( "Lichfield District Council FixMyStreet" );
+ $mech->submit_form_ok( { with_fields => { pc => 'WS13 7RD' } }, "submit location" );
+ $mech->follow_link_ok( { text_regex => qr/skip this step/i, }, "follow 'skip this step' link" );
+ my %optional_fields = $test->{redirect} ? () :
+ ( email => $test_email, phone => '07903 123 456' );
+
+ # we do this as otherwise test::www::mechanize::catalyst
+ # goes to the value set in ->host above irregardless and
+ # that is a 404. It works but it is not pleasant.
+ $mech->clear_host if $test->{redirect} && $test->{national};
+ $mech->submit_form_ok(
+ {
+ button => $test->{button},
+ with_fields => {
+ title => 'Test Report',
+ detail => 'Test report details.',
+ photo => '',
+ name => 'Joe Bloggs',
+ may_show_name => '1',
+ category => $test->{category},
+ %optional_fields
+ }
+ },
+ "submit good details"
+ );
+ is_deeply $mech->page_errors, [], "check there were no errors";
+
+ # check that the user has been created/ not changed
+ $user =
+ FixMyStreet::App->model('DB::User')->find( { email => $test_email } );
+ ok $user, "user found";
+
+ # find the report
+ my $report = $user->problems->first;
+ ok $report, "Found the report";
+
+ # Check the report has been assigned appropriately
+ is $report->bodies_str, $test->{council};
+
+ if ( $test->{redirect} ) {
+ is $mech->uri->path, "/report/" . $report->id, "redirected to report page";
+ my $base = FixMyStreet->config('BASE_URL');
+ $base =~ s{http://}{};
+ $base = "lichfielddc.$base" unless $test->{national};
+ is $mech->uri->host, $base, 'redirected to correct site';
+ } else {
+ # receive token
+ 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{(http://\S+)};
+ ok $url, "extracted confirm url '$url'";
+
+ # confirm token
+ $mech->get_ok($url);
+
+ my $base = FixMyStreet->config('BASE_URL');
+ $base =~ s{http://}{http://lichfielddc.} unless $test->{national};
+ $mech->content_contains( $base . '/report/' .
+ $report->id, 'confirm page links to correct site' );
+
+ if ( $test->{national} ) {
+ # Shouldn't be found, as it was a county problem
+ is $mech->get( '/report/' . $report->id )->code, 404, "report not found";
+
+ # But should be on the main site
+ $mech->host( 'www.fixmystreet.com' );
+ }
+ $mech->get_ok( '/report/' . $report->id );
+ }
- # check that the user has been created/ not changed
- my $user =
- FixMyStreet::App->model('DB::User')->find( { email => $test_email } );
- ok $user, "user found";
+ $report->discard_changes;
+ is $report->state, 'confirmed', "Report is now confirmed";
- # find the report
- my $report = $user->problems->first;
- ok $report, "Found the report";
+ is $report->name, 'Joe Bloggs', 'name updated correctly';
- # Check the report has been assigned appropriately
- is $report->bodies_str, 2240;
+ $mech->delete_user($user);
+ };
+ }
+}
- # receive token
- my $email = $mech->get_email;
- ok $email, "got an email";
- like $email->body, qr/confirm the problem/i, "confirm the problem";
+SKIP: {
+ skip( "Need 'seesomething' in ALLOWED_COBRANDS config", 100 )
+ unless FixMyStreet::Cobrand->exists('seesomething');
- my ($url) = $email->body =~ m{(http://\S+)};
- ok $url, "extracted confirm url '$url'";
+ $mech->host('seesomething.fixmystreet.com');
+ $mech->clear_emails_ok;
+ $mech->log_out_ok;
- # confirm token
- $mech->get_ok($url);
- $report->discard_changes;
- is $report->state, 'confirmed', "Report is now confirmed";
+ my $cobrand = FixMyStreet::Cobrand::SeeSomething->new();
- # Shouldn't be found, as it was a county problem
- is $mech->get( '/report/' . $report->id )->code, 404, "report not found";
+ $mech->create_body_ok(2535, 'Sandwell Borough Council');
+ my $bus_contact = FixMyStreet::App->model('DB::Contact')->find_or_create( {
+ %contact_params,
+ body_id => 2535,
+ category => 'Bus',
+ email => 'bus@example.com',
+ non_public => 1,
+ } );
- # But should be on the main site
- $mech->host( 'www.fixmystreet.com' );
- $mech->get_ok( '/report/' . $report->id );
- is $report->name, 'Joe Bloggs', 'name updated correctly';
+ for my $test ( {
+ desc => 'report with no user details works',
+ pc => 'WS1 4NH',
+ fields => {
+ detail => 'Test report details',
+ category => 'Bus',
+ subcategory => 'Smoking',
+ },
+ email => $cobrand->anonymous_account->{email},
+ },
+ {
+ desc => 'report with user details works',
+ pc => 'WS1 4NH',
+ fields => {
+ detail => 'Test report details',
+ category => 'Bus',
+ subcategory => 'Smoking',
+ email => 'non_anon_user@example.com',
+ name => 'Non Anon',
+ },
+ email => 'non_anon_user@example.com',
+ },
+ {
+ desc => 'report with public category',
+ pc => 'WS1 4NH',
+ fields => {
+ detail => 'Test report details',
+ category => 'Bus',
+ subcategory => 'Smoking',
+ },
+ email => $cobrand->anonymous_account->{email},
+ public => 1,
+ }
+ ) {
+ subtest $test->{desc} => sub {
+ $mech->clear_emails_ok;
+ my $user =
+ FixMyStreet::App->model('DB::User')->find( { email => $test->{email} } );
+
+ if ( $user ) {
+ $user->alerts->delete;
+ $user->problems->delete;
+ $user->delete;
+ }
- $mech->delete_user($user);
+ if ( $test->{public} ) {
+ $bus_contact->non_public(0);
+ $bus_contact->update;
+ } else {
+ $bus_contact->non_public(1);
+ $bus_contact->update;
+ }
+
+ $mech->get_ok( '/around' );
+ $mech->submit_form_ok(
+ {
+ with_fields => {
+ pc => $test->{pc},
+ },
+ },
+ 'submit around form',
+ );
+ $mech->follow_link_ok( { text_regex => qr/skip this step/i, }, "follow 'skip this step' link" );
+
+ $mech->submit_form_ok(
+ {
+ with_fields => $test->{fields},
+ },
+ 'Submit form details with no user details',
+ );
+ is_deeply $mech->page_errors, [], "check there were no errors";
+
+ $user =
+ FixMyStreet::App->model('DB::User')->find( { email => $test->{email} } );
+ ok $user, "user found";
+
+ my $report = $user->problems->first;
+ ok $report, "Found the report";
+
+ $mech->email_count_is(0);
+
+ ok $report->confirmed, 'Report is confirmed automatically';
+
+ if ( $test->{public} ) {
+ is $mech->uri->path, '/report/' . $report->id, 'redirects to report page';
+ } else {
+ is $mech->uri->path, '/report/new', 'stays on report/new page';
+ $mech->content_contains( 'Your report has been sent', 'use report created template' );
+ }
+ };
+ }
+
+ $bus_contact->delete;
}
$contact1->delete;
diff --git a/t/app/controller/report_updates.t b/t/app/controller/report_updates.t
index 5accb9ce4..2765ed246 100644
--- a/t/app/controller/report_updates.t
+++ b/t/app/controller/report_updates.t
@@ -479,64 +479,103 @@ for my $test (
state => 'investigating',
},
{
- desc => 'from authority user marks report as planned',
+ desc => 'from authority user marks report as in progress',
fields => {
name => $user->name,
may_show_name => 1,
add_alert => undef,
photo => '',
- update => 'Set state to planned',
- state => 'planned',
+ update => 'Set state to in progress',
+ state => 'in progress',
},
- state => 'planned',
+ state => 'in progress',
},
{
- desc => 'from authority user marks report as in progress',
+ desc => 'from authority user marks report as fixed',
fields => {
name => $user->name,
may_show_name => 1,
add_alert => undef,
photo => '',
- update => 'Set state to in progress',
- state => 'in progress',
+ update => 'Set state to fixed',
+ state => 'fixed',
},
- state => 'in progress',
+ state => 'fixed - council',
},
{
- desc => 'from authority user marks report as closed',
+ desc => 'from authority user marks report as action scheduled',
fields => {
name => $user->name,
may_show_name => 1,
add_alert => undef,
photo => '',
- update => 'Set state to closed',
- state => 'closed',
+ update => 'Set state to action scheduled',
+ state => 'action scheduled',
},
- state => 'closed',
+ state => 'action scheduled',
},
{
- desc => 'from authority user marks report as fixed',
+ desc => 'from authority user marks report as unable to fix',
fields => {
name => $user->name,
may_show_name => 1,
add_alert => undef,
photo => '',
- update => 'Set state to fixed',
- state => 'fixed',
+ update => 'Set state to unable to fix',
+ state => 'unable to fix',
},
- state => 'fixed - council',
+ state => 'unable to fix',
+ },
+ {
+ desc => 'from authority user marks report as internal referral',
+ fields => {
+ name => $user->name,
+ may_show_name => 1,
+ add_alert => undef,
+ photo => '',
+ update => 'Set state to internal referral',
+ state => 'internal referral',
+ },
+ state => 'internal referral',
+ },
+ {
+ desc => 'from authority user marks report as not responsible',
+ fields => {
+ name => $user->name,
+ may_show_name => 1,
+ add_alert => undef,
+ photo => '',
+ update => 'Set state to not responsible',
+ state => 'not responsible',
+ },
+ state => 'not responsible',
+ meta => "not the council's responsibility"
+ },
+ {
+ desc => 'from authority user marks report as duplicate',
+ fields => {
+ name => $user->name,
+ may_show_name => 1,
+ add_alert => undef,
+ photo => '',
+ update => 'Set state to duplicate',
+ state => 'duplicate',
+ },
+ state => 'duplicate',
+ meta => 'duplicate report',
},
{
- desc => 'from authority user marks report as confirmed',
+ desc => 'from authority user marks report as internal referral',
fields => {
name => $user->name,
may_show_name => 1,
add_alert => undef,
photo => '',
- update => 'Set state to confirmed',
- state => 'confirmed',
+ update => 'Set state to internal referral',
+ state => 'internal referral',
},
- state => 'confirmed',
+ state => 'internal referral',
+ meta => 'internal referral',
},
{
desc => 'from authority user marks report sent to two councils as fixed',
@@ -579,11 +618,11 @@ for my $test (
is $update->problem_state, $test->{state}, 'problem state set';
my $update_meta = $mech->extract_update_metas;
- # setting it to confirmed shouldn't say anything
- if ( $test->{fields}->{state} ne 'confirmed' ) {
- like $update_meta->[0], qr/marked as $test->{fields}->{state}$/, 'update meta includes state change';
+ my $meta_state = $test->{meta} || $test->{fields}->{state};
+ if ( $test->{reopened} ) {
+ like $update_meta->[0], qr/reopened$/, 'update meta says reopened';
} else {
- like $update_meta->[0], qr/reopened$/, 'update meta includes state change';
+ like $update_meta->[0], qr/marked as $meta_state$/, 'update meta includes state change';
}
like $update_meta->[0], qr{Test User \(Westminster City Council\)}, 'update meta includes council name';
$mech->content_contains( 'Test User (<strong>Westminster City Council</strong>)', 'council name in bold');
@@ -611,7 +650,7 @@ subtest 'check meta correct for comments marked confirmed but not marked open' =
$mech->get_ok( "/report/" . $report->id );
my $update_meta = $mech->extract_update_metas;
- like $update_meta->[0], qr/reopened$/,
+ unlike $update_meta->[0], qr/reopened$/,
'update meta does not say reopened';
$comment->update( { mark_open => 1, problem_state => undef } );
@@ -629,7 +668,159 @@ subtest 'check meta correct for comments marked confirmed but not marked open' =
unlike $update_meta->[0], qr/marked as open$/,
'update meta does not says marked as open';
unlike $update_meta->[0], qr/reopened$/, 'update meta does not say reopened';
- };
+};
+
+subtest "check first comment with no status change has no status in meta" => sub {
+ $mech->log_in_ok( $user->email );
+ $user->from_body( undef );
+ $user->update;
+
+ my $comment = $report->comments->first;
+ $comment->update( { mark_fixed => 0, problem_state => 'confirmed' } );
+
+ $mech->get_ok("/report/$report_id");
+
+ my $update_meta = $mech->extract_update_metas;
+ unlike $update_meta->[0], qr/marked as|reopened/, 'update meta does not include state change';
+};
+
+subtest "check comment with no status change has not status in meta" => sub {
+ $mech->log_in_ok( $user->email );
+ $user->from_body( undef );
+ $user->update;
+
+ my $comment = $report->comments->first;
+ $comment->update( { mark_fixed => 1, problem_state => 'fixed - council' } );
+
+ $mech->get_ok("/report/$report_id");
+
+ $mech->submit_form_ok(
+ {
+ with_fields => {
+ name => $user->name,
+ may_show_name => 1,
+ add_alert => undef,
+ photo => '',
+ update => 'Comment that does not change state',
+ },
+ },
+ 'submit update'
+ );
+
+ $report->discard_changes;
+ my @updates = $report->comments->all;
+ is scalar @updates, 2, 'correct number of updates';
+
+ warn $updates[0]->problem_state;
+ warn $updates[1]->problem_state;
+ my $update = pop @updates;
+
+ is $report->state, 'fixed - council', 'correct report state';
+ is $update->problem_state, 'fixed - council', 'corect update state';
+ my $update_meta = $mech->extract_update_metas;
+ unlike $update_meta->[1], qr/marked as/, 'update meta does not include state change';
+
+ $user->from_body( 2504 );
+ $user->update;
+
+ $mech->get_ok("/report/$report_id");
+
+ $mech->submit_form_ok(
+ {
+ with_fields => {
+ name => $user->name,
+ may_show_name => 1,
+ add_alert => undef,
+ photo => '',
+ update => 'Comment that sets state to investigating',
+ state => 'investigating',
+ },
+ },
+ 'submit update'
+ );
+
+ $report->discard_changes;
+ @updates = $report->comments->all;
+ is scalar @updates, 3, 'correct number of updates';
+
+ $update = pop @updates;
+
+ is $report->state, 'investigating', 'correct report state';
+ is $update->problem_state, 'investigating', 'corect update state';
+ $update_meta = $mech->extract_update_metas;
+ like $update_meta->[0], qr/marked as fixed/, 'first update meta says fixed';
+ unlike $update_meta->[1], qr/marked as/, 'second update meta does not include state change';
+ like $update_meta->[2], qr/marked as investigating/, 'third update meta says investigating';
+
+ my $dt = DateTime->now->add( seconds => 1 );
+ $comment = FixMyStreet::App->model('DB::Comment')->find_or_create(
+ {
+ problem_id => $report_id,
+ user_id => $user->id,
+ name => 'Other User',
+ mark_fixed => 'false',
+ text => 'This is some update text',
+ state => 'confirmed',
+ confirmed => $dt->ymd . ' ' . $dt->hms,
+ anonymous => 'f',
+ }
+ );
+
+ $mech->get_ok("/report/$report_id");
+
+ $report->discard_changes;
+ @updates = $report->comments->all;
+ is scalar @updates, 4, 'correct number of updates';
+
+ $update = pop @updates;
+
+ is $report->state, 'investigating', 'correct report state';
+ is $update->problem_state, undef, 'no update state';
+ $update_meta = $mech->extract_update_metas;
+ like $update_meta->[0], qr/marked as fixed/, 'first update meta says fixed';
+ unlike $update_meta->[1], qr/marked as/, 'second update meta does not include state change';
+ like $update_meta->[2], qr/marked as investigating/, 'third update meta says investigating';
+ unlike $update_meta->[3], qr/marked as/, 'fourth update meta has no state change';
+};
+
+subtest 'check meta correct for second comment marking as reopened' => sub {
+ $report->comments->delete;
+ my $comment = FixMyStreet::App->model('DB::Comment')->create(
+ {
+ user => $user,
+ problem_id => $report->id,
+ text => 'update text',
+ confirmed => DateTime->now,
+ problem_state => 'fixed - user',
+ anonymous => 0,
+ mark_open => 0,
+ mark_fixed => 1,
+ state => 'confirmed',
+ }
+ );
+
+ $mech->get_ok( "/report/" . $report->id );
+ my $update_meta = $mech->extract_update_metas;
+ like $update_meta->[0], qr/fixed$/, 'update meta says fixed';
+
+ $comment = FixMyStreet::App->model('DB::Comment')->create(
+ {
+ user => $user,
+ problem_id => $report->id,
+ text => 'update text',
+ confirmed => DateTime->now,
+ problem_state => 'confirmed',
+ anonymous => 0,
+ mark_open => 0,
+ mark_fixed => 0,
+ state => 'confirmed',
+ }
+ );
+
+ $mech->get_ok( "/report/" . $report->id );
+ $update_meta = $mech->extract_update_metas;
+ like $update_meta->[1], qr/reopened$/, 'update meta says reopened';
+};
$user->from_body(undef);
$user->update;
@@ -1288,6 +1479,254 @@ for my $test (
};
}
+for my $test (
+ {
+ desc => 'update confirmed without marking as fixed leaves state unchanged',
+ initial_state => 'confirmed',
+ expected_form_fields => {
+ fixed => undef,
+ },
+ submitted_form_fields => {
+ fixed => 0,
+ },
+ end_state => 'confirmed',
+ },
+ {
+ desc => 'update investigating without marking as fixed leaves state unchanged',
+ initial_state => 'investigating',
+ expected_form_fields => {
+ fixed => undef,
+ },
+ submitted_form_fields => {
+ fixed => 0,
+ },
+ end_state => 'investigating',
+ },
+ {
+ desc => 'update in progress without marking as fixed leaves state unchanged',
+ initial_state => 'in progress',
+ expected_form_fields => {
+ fixed => undef,
+ },
+ submitted_form_fields => {
+ fixed => 0,
+ },
+ end_state => 'in progress',
+ },
+ {
+ desc => 'update action scheduled without marking as fixed leaves state unchanged',
+ initial_state => 'action scheduled',
+ expected_form_fields => {
+ fixed => undef,
+ },
+ submitted_form_fields => {
+ fixed => 0,
+ },
+ end_state => 'action scheduled',
+ },
+ {
+ desc => 'update fixed without marking as open leaves state unchanged',
+ initial_state => 'fixed',
+ expected_form_fields => {
+ reopen => undef,
+ },
+ submitted_form_fields => {
+ reopen => 0,
+ },
+ end_state => 'fixed',
+ },
+ {
+ desc => 'update unable to fix without marking as fixed leaves state unchanged',
+ initial_state => 'unable to fix',
+ expected_form_fields => {
+ fixed => undef,
+ },
+ submitted_form_fields => {
+ fixed => 0,
+ },
+ end_state => 'unable to fix',
+ },
+ {
+ desc => 'update internal referral without marking as fixed leaves state unchanged',
+ initial_state => 'internal referral',
+ expected_form_fields => {
+ fixed => undef,
+ },
+ submitted_form_fields => {
+ fixed => 0,
+ },
+ end_state => 'internal referral',
+ },
+ {
+ desc => 'update not responsible without marking as fixed leaves state unchanged',
+ initial_state => 'not responsible',
+ expected_form_fields => {
+ fixed => undef,
+ },
+ submitted_form_fields => {
+ fixed => 0,
+ },
+ end_state => 'not responsible',
+ },
+ {
+ desc => 'update duplicate without marking as fixed leaves state unchanged',
+ initial_state => 'duplicate',
+ expected_form_fields => {
+ fixed => undef,
+ },
+ submitted_form_fields => {
+ fixed => 0,
+ },
+ end_state => 'duplicate',
+ },
+ {
+ desc => 'can mark confirmed as fixed',
+ initial_state => 'confirmed',
+ expected_form_fields => {
+ fixed => undef,
+ },
+ submitted_form_fields => {
+ fixed => 1,
+ },
+ end_state => 'fixed - user',
+ },
+ {
+ desc => 'can mark investigating as fixed',
+ initial_state => 'investigating',
+ expected_form_fields => {
+ fixed => undef,
+ },
+ submitted_form_fields => {
+ fixed => 1,
+ },
+ end_state => 'fixed - user',
+ },
+ {
+ desc => 'can mark in progress as fixed',
+ initial_state => 'in progress',
+ expected_form_fields => {
+ fixed => undef,
+ },
+ submitted_form_fields => {
+ fixed => 1,
+ },
+ end_state => 'fixed - user',
+ },
+ {
+ desc => 'can mark action scheduled as fixed',
+ initial_state => 'action scheduled',
+ expected_form_fields => {
+ fixed => undef,
+ },
+ submitted_form_fields => {
+ fixed => 1,
+ },
+ end_state => 'fixed - user',
+ },
+ {
+ desc => 'cannot mark fixed as fixed, can mark as not fixed',
+ initial_state => 'fixed',
+ expected_form_fields => {
+ reopen => undef,
+ },
+ submitted_form_fields => {
+ reopen => 1,
+ },
+ end_state => 'confirmed',
+ },
+ {
+ desc => 'can mark unable to fix as fixed, cannot mark not closed',
+ initial_state => 'unable to fix',
+ expected_form_fields => {
+ fixed => undef,
+ },
+ submitted_form_fields => {
+ fixed => 1,
+ },
+ end_state => 'fixed - user',
+ },
+ {
+ desc => 'can mark internal referral as fixed, cannot mark not closed',
+ initial_state => 'internal referral',
+ expected_form_fields => {
+ fixed => undef,
+ },
+ submitted_form_fields => {
+ fixed => 1,
+ },
+ end_state => 'fixed - user',
+ },
+ {
+ desc => 'can mark not responsible as fixed, cannot mark not closed',
+ initial_state => 'not responsible',
+ expected_form_fields => {
+ fixed => undef,
+ },
+ submitted_form_fields => {
+ fixed => 1,
+ },
+ end_state => 'fixed - user',
+ },
+ {
+ desc => 'can mark duplicate as fixed, cannot mark not closed',
+ initial_state => 'duplicate',
+ expected_form_fields => {
+ fixed => undef,
+ },
+ submitted_form_fields => {
+ fixed => 1,
+ },
+ end_state => 'fixed - user',
+ },
+) {
+ subtest $test->{desc} => sub {
+ $mech->log_in_ok( $report->user->email );
+
+ my %standard_fields = (
+ name => $report->user->name,
+ update => 'update text',
+ photo => '',
+ may_show_name => 1,
+ add_alert => 1,
+ );
+
+ my %expected_fields = (
+ %standard_fields,
+ %{ $test->{expected_form_fields} },
+ update => '',
+ );
+
+ my %submitted_fields = (
+ %standard_fields,
+ %{ $test->{submitted_form_fields} },
+ );
+
+ # clear out comments for this problem to make
+ # checking details easier later
+ ok( $_->delete, 'deleted comment ' . $_->id ) for $report->comments;
+
+ $report->discard_changes;
+ $report->state($test->{initial_state});
+ $report->update;
+
+ $mech->get_ok("/report/$report_id");
+
+ my $values = $mech->visible_form_values('updateForm');
+ is_deeply $values, \%expected_fields, 'correct form fields present';
+
+ if ( $test->{submitted_form_fields} ) {
+ $mech->submit_form_ok( {
+ with_fields => \%submitted_fields
+ },
+ 'submit update'
+ );
+
+ $report->discard_changes;
+ is $report->state, $test->{end_state}, 'update sets correct report state';
+ }
+ };
+}
+
subtest 'check have to be logged in for creator fixed questionnaire' => sub {
$mech->log_out_ok();
diff --git a/t/app/controller/rss.t b/t/app/controller/rss.t
index 002d63d67..f04a17151 100644
--- a/t/app/controller/rss.t
+++ b/t/app/controller/rss.t
@@ -13,7 +13,7 @@ my $dt = DateTime->new(
);
my $user1 = FixMyStreet::App->model('DB::User')
- ->find_or_create( { email => 'reporter@example.com', name => 'Reporter User' } );
+ ->find_or_create( { email => 'reporter-rss@example.com', name => 'Reporter User' } );
my $report = FixMyStreet::App->model('DB::Problem')->find_or_create( {
postcode => 'eh1 1BB',
@@ -175,7 +175,6 @@ subtest "check RSS feeds on cobrand have correct URLs for non-cobrand reports" =
$mech->content_contains($expected2, 'cobrand area report point to cobrand url');
};
-$user1->problems->delete();
-$user1->delete();
+$mech->delete_user( $user1 );
done_testing();
diff --git a/t/app/helpers/send_email.t b/t/app/helpers/send_email.t
index 8c043f701..3067d90f3 100644
--- a/t/app/helpers/send_email.t
+++ b/t/app/helpers/send_email.t
@@ -49,7 +49,7 @@ ok $email_as_string =~ s{\s+Message-ID:\s+\S.*?$}{}xms, "Found and stripped out
my $expected_email_content = file(__FILE__)->dir->file('send_email_sample.txt')->slurp;
my $name = FixMyStreet->config('CONTACT_NAME');
$name = "\"$name\"" if $name =~ / /;
-my $sender = $name . ' <' . FixMyStreet->config('CONTACT_EMAIL') . '>';
+my $sender = $name . ' <' . FixMyStreet->config('DO_NOT_REPLY_EMAIL') . '>';
$expected_email_content =~ s{CONTACT_EMAIL}{$sender};
is $email_as_string,
diff --git a/t/app/model/problem.t b/t/app/model/problem.t
index b2243fcf5..a92e3b079 100644
--- a/t/app/model/problem.t
+++ b/t/app/model/problem.t
@@ -302,6 +302,13 @@ for my $test (
is_closed => 0,
},
{
+ state => 'action scheduled',
+ is_visible => 1,
+ is_fixed => 0,
+ is_open => 1,
+ is_closed => 0,
+ },
+ {
state => 'in progress',
is_visible => 1,
is_fixed => 0,
@@ -309,6 +316,27 @@ for my $test (
is_closed => 0,
},
{
+ state => 'duplicate',
+ is_visible => 1,
+ is_fixed => 0,
+ is_open => 0,
+ is_closed => 1,
+ },
+ {
+ state => 'not responsible',
+ is_visible => 1,
+ is_fixed => 0,
+ is_open => 0,
+ is_closed => 1,
+ },
+ {
+ state => 'unable to fix',
+ is_visible => 1,
+ is_fixed => 0,
+ is_open => 0,
+ is_closed => 1,
+ },
+ {
state => 'fixed',
is_visible => 1,
is_fixed => 1,
@@ -554,9 +582,56 @@ foreach my $test ( {
};
}
+subtest 'check can turn on report sent email alerts' => sub {
+ eval 'use Test::MockModule; 1' or
+ plan skip_all => 'Skipping tests that rely on Test::MockModule';
+
+ $mech->clear_emails_ok;
+
+ FixMyStreet::App->model('DB::Problem')->search(
+ {
+ whensent => undef
+ }
+ )->update( { whensent => \'ms_current_timestamp()' } );
+
+ $problem->discard_changes;
+ $problem->update( {
+ council => 2651,
+ state => 'confirmed',
+ confirmed => \'ms_current_timestamp()',
+ whensent => undef,
+ category => 'potholes',
+ name => 'Test User',
+ cobrand => 'fixmystreet',
+ } );
+
+ my $m = new Test::MockModule(
+ 'FixMyStreet::Cobrand::FixMyStreet' );
+ $m->mock( report_sent_confirmation_email => 1 );
+ FixMyStreet::App->model('DB::Problem')->send_reports();
+
+ $mech->email_count_is( 2 );
+ my @emails = $mech->get_email;
+ my $email = $emails[0];
+
+ like $email->header('To'),qr/City of Edinburgh Council/, 'to line looks correct';
+ is $email->header('From'), '"Test User" <system_user@example.com>', '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, qr/Dear City of Edinburgh Council/, 'Salutation looks correct';
+
+ $problem->discard_changes;
+ ok defined( $problem->whensent ), 'whensent set';
+
+ $email = $emails[1];
+ like $email->header('Subject'), qr/Problem Report Sent/, 'report sent email title correct';
+ like $email->body, qr/Your report about/, 'report sent body correct';
+};
+
$problem->comments->delete;
$problem->delete;
-$user->delete;
+$mech->delete_user( $user );
foreach (@contacts) {
$_->delete;
diff --git a/t/app/model/questionnaire.t b/t/app/model/questionnaire.t
index 60b52043a..86af51c42 100644
--- a/t/app/model/questionnaire.t
+++ b/t/app/model/questionnaire.t
@@ -62,6 +62,10 @@ for my $test (
send_email => 1,
},
{
+ state => 'action scheduled',
+ send_email => 1,
+ },
+ {
state => 'in progress',
send_email => 1,
},
@@ -78,6 +82,18 @@ for my $test (
send_email => 1,
},
{
+ state => 'duplicate',
+ send_email => 1,
+ },
+ {
+ state => 'unable to fix',
+ send_email => 1,
+ },
+ {
+ state => 'not responsible',
+ send_email => 1,
+ },
+ {
state => 'closed',
send_email => 1,
},
diff --git a/t/app/sendreport/email.t b/t/app/sendreport/email.t
index 106a31c42..8063c928f 100644
--- a/t/app/sendreport/email.t
+++ b/t/app/sendreport/email.t
@@ -33,6 +33,7 @@ my $contact = FixMyStreet::App->model('DB::Contact')->find_or_create(
my $row = FixMyStreet::App->model('DB::Problem')->new( {
bodies_str => '1000',
category => 'category',
+ cobrand => '',
} );
ok $e;
diff --git a/t/map/tilma/original.t b/t/map/tilma/original.t
index cd3bc623e..72cde5f9f 100644
--- a/t/map/tilma/original.t
+++ b/t/map/tilma/original.t
@@ -71,10 +71,26 @@ for my $test (
colour => 'yellow',
},
{
+ state => 'duplicate',
+ colour => 'yellow',
+ },
+ {
+ state => 'unable to fix',
+ colour => 'yellow',
+ },
+ {
+ state => 'not responsible',
+ colour => 'yellow',
+ },
+ {
state => 'investigating',
colour => 'yellow',
},
{
+ state => 'action scheduled',
+ colour => 'yellow',
+ },
+ {
state => 'planned',
colour => 'yellow',
},
diff --git a/t/open311.t b/t/open311.t
index 2371c53bc..71a87325c 100644
--- a/t/open311.t
+++ b/t/open311.t
@@ -106,7 +106,7 @@ subtest 'posting service request with basic_description' => sub {
$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 },
+ { extended_description => 0 },
);
is $results->{ res }, 248, 'got request id';
@@ -192,6 +192,7 @@ my $comment = FixMyStreet::App->model('DB::Comment')->new( {
anonymous => 0,
text => 'this is a comment',
confirmed => $dt,
+ problem_state => 'confirmed',
extra => { title => 'Mr', email_alerts_requested => 0 },
} );
@@ -216,7 +217,7 @@ subtest 'basic request update post parameters' => sub {
};
subtest 'extended 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>', 1 );
+ 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>', { use_extended_updates => 1 } );
is $results->{ res }, 248, 'got update id';
@@ -258,16 +259,47 @@ foreach my $test (
desc => 'comment with fixed state sends status of CLOSED',
state => 'fixed',
status => 'CLOSED',
+ extended => 'FIXED',
},
{
desc => 'comment with fixed - user state sends status of CLOSED',
state => 'fixed - user',
status => 'CLOSED',
+ extended => 'FIXED',
},
{
desc => 'comment with fixed - council state sends status of CLOSED',
state => 'fixed - council',
status => 'CLOSED',
+ extended => 'FIXED',
+ },
+ {
+ desc => 'comment with duplicate state sends status of CLOSED',
+ state => 'duplicate',
+ anon => 0,
+ status => 'CLOSED',
+ extended => 'DUPLICATE',
+ },
+ {
+ desc => 'comment with not reponsible state sends status of CLOSED',
+ state => 'not responsible',
+ anon => 0,
+ status => 'CLOSED',
+ extended => 'NOT_COUNCILS_RESPONSIBILITY',
+ },
+ {
+ desc => 'comment with unable to fix state sends status of CLOSED',
+ state => 'unable to fix',
+ anon => 0,
+ status => 'CLOSED',
+ extended => 'NO_FURTHER_ACTION',
+ },
+ {
+ desc => 'comment with internal referral state sends status of CLOSED',
+ state => 'internal referral',
+ anon => 0,
+ status => 'CLOSED',
+ extended => 'INTERNAL_REFERRAL',
},
{
desc => 'comment with closed state sends status of CLOSED',
@@ -278,29 +310,42 @@ foreach my $test (
desc => 'comment with investigating state sends status of OPEN',
state => 'investigating',
status => 'OPEN',
+ extended => 'INVESTIGATING',
},
{
desc => 'comment with planned state sends status of OPEN',
state => 'planned',
status => 'OPEN',
+ extended => 'ACTION_SCHEDULED',
},
{
- desc => 'comment with in progress state sends status of OPEN',
- state => 'in progress',
+ desc => 'comment with action scheduled state sends status of OPEN',
+ state => 'action scheduled',
+ anon => 0,
status => 'OPEN',
+ extended => 'ACTION_SCHEDULED',
},
{
- state => 'confirmed',
+ desc => 'comment with in progress state sends status of OPEN',
+ state => 'in progress',
status => 'OPEN',
+ extended => 'IN_PROGRESS',
},
) {
subtest $test->{desc} => sub {
+ $comment->problem_state( $test->{state} );
$comment->problem->state( $test->{state} );
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';
+
+ if ( $test->{extended} ) {
+ 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>', { extended_statuses => 1 } );
+ my $c = CGI::Simple->new( $results->{ req }->content );
+ is $c->param('status'), $test->{extended}, 'correct extended status';
+ }
};
}
@@ -319,16 +364,70 @@ for my $test (
},
) {
subtest $test->{desc} => sub {
+ $comment->problem_state( $test->{state} );
$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>', 1 );
+ 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>', { use_extended_updates => 1 } );
my $c = CGI::Simple->new( $results->{ req }->content );
is $c->param('public_anonymity_required'), $test->{anon} ? 'TRUE' : 'FALSE', 'correct anonymity';
};
}
+my $dt2 = $dt->clone;
+$dt2->add( 'minutes' => 1 );
+
+my $comment2 = FixMyStreet::App->model('DB::Comment')->new( {
+ id => 38363,
+ user => $user,
+ problem => $problem,
+ anonymous => 0,
+ text => 'this is a comment',
+ confirmed => $dt,
+ problem_state => 'confirmed',
+ extra => { title => 'Mr', email_alerts_requested => 0 },
+} );
+
+for my $test (
+ {
+ desc => 'comment with fixed - council state sends status of CLOSED even if problem is open',
+ state => 'fixed - council',
+ problem_state => 'confirmed',
+ status => 'CLOSED',
+ extended => 'FIXED',
+ },
+ {
+ desc => 'comment marked open sends status of OPEN even if problem is closed',
+ state => 'confirmed',
+ problem_state => 'fixed - council',
+ status => 'OPEN',
+ extended => 'OPEN',
+ },
+ {
+ desc => 'comment with no problem state falls back to report state',
+ state => '',
+ problem_state => 'fixed - council',
+ status => 'CLOSED',
+ extended => 'FIXED',
+ },
+) {
+ subtest $test->{desc} => sub {
+ $comment->problem_state( $test->{state} );
+ $comment->problem->state( $test->{problem_state} );
+ 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';
+
+ if ( $test->{extended} ) {
+ 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>', { extended_statuses => 1 } );
+ my $c = CGI::Simple->new( $results->{ req }->content );
+ is $c->param('status'), $test->{extended}, 'correct extended status';
+ }
+ };
+}
+
for my $test (
{
@@ -539,18 +638,16 @@ done_testing();
sub make_update_req {
my $comment = shift;
my $xml = shift;
- my $extended = shift;
+ my $open311_args = shift || {};
my $params = {
- object => $comment,
- xml => $xml,
- method => 'post_service_request_update',
- path => 'servicerequestupdates.xml',
+ object => $comment,
+ xml => $xml,
+ method => 'post_service_request_update',
+ path => 'servicerequestupdates.xml',
+ open311_conf => $open311_args,
};
- if ( $extended ) {
- $params->{ open311_conf } = { use_extended_updates => 1 };
- }
return make_req( $params );
}
diff --git a/t/open311/getservicerequestupdates.t b/t/open311/getservicerequestupdates.t
index da23c944e..36ed13615 100644
--- a/t/open311/getservicerequestupdates.t
+++ b/t/open311/getservicerequestupdates.t
@@ -131,63 +131,209 @@ $problem->insert;
for my $test (
{
- desc => 'element with content',
+ desc => 'OPEN status for confirmed problem does not change state',
updated_datetime => sprintf( '<updated_datetime>%s</updated_datetime>', $dt ),
description => 'This is a note',
external_id => 638344,
start_state => 'confirmed',
- close_comment => 0,
+ comment_status => 'OPEN',
mark_fixed=> 0,
mark_open => 0,
problem_state => undef,
end_state => 'confirmed',
},
{
- desc => 'comment closes report',
+ desc => 'bad state does not update states but does create update',
updated_datetime => sprintf( '<updated_datetime>%s</updated_datetime>', $dt ),
description => 'This is a note',
external_id => 638344,
start_state => 'confirmed',
- close_comment => 1,
+ comment_status => 'INVALID_STATE',
+ mark_fixed=> 0,
+ mark_open => 0,
+ problem_state => undef,
+ end_state => 'confirmed',
+ },
+
+ {
+ desc => 'investigating status changes problem status',
+ updated_datetime => sprintf( '<updated_datetime>%s</updated_datetime>', $dt ),
+ description => 'This is a note',
+ external_id => 638344,
+ start_state => 'confirmed',
+ comment_status => 'INVESTIGATING',
+ mark_fixed=> 0,
+ mark_open => 0,
+ problem_state => 'investigating',
+ end_state => 'investigating',
+ },
+ {
+ desc => 'in progress status changes problem status',
+ updated_datetime => sprintf( '<updated_datetime>%s</updated_datetime>', $dt ),
+ description => 'This is a note',
+ external_id => 638344,
+ start_state => 'confirmed',
+ comment_status => 'IN_PROGRESS',
+ mark_fixed=> 0,
+ mark_open => 0,
+ problem_state => 'in progress',
+ end_state => 'in progress',
+ },
+ {
+ desc => 'action scheduled status changes problem status',
+ updated_datetime => sprintf( '<updated_datetime>%s</updated_datetime>', $dt ),
+ description => 'This is a note',
+ external_id => 638344,
+ start_state => 'confirmed',
+ comment_status => 'ACTION_SCHEDULED',
+ mark_fixed=> 0,
+ mark_open => 0,
+ problem_state => 'action scheduled',
+ end_state => 'action scheduled',
+ },
+ {
+ desc => 'not responsible status changes problem status',
+ updated_datetime => sprintf( '<updated_datetime>%s</updated_datetime>', $dt ),
+ description => 'This is a note',
+ external_id => 638344,
+ start_state => 'confirmed',
+ comment_status => 'NOT_COUNCILS_RESPONSIBILITY',
+ mark_fixed=> 0,
+ mark_open => 0,
+ problem_state => 'not responsible',
+ end_state => 'not responsible',
+ },
+ {
+ desc => 'internal referral status changes problem status',
+ updated_datetime => sprintf( '<updated_datetime>%s</updated_datetime>', $dt ),
+ description => 'This is a note',
+ external_id => 638344,
+ start_state => 'confirmed',
+ comment_status => 'INTERNAL_REFERRAL',
+ mark_fixed=> 0,
+ mark_open => 0,
+ problem_state => 'internal referral',
+ end_state => 'internal referral',
+ },
+ {
+ desc => 'duplicate status changes problem status',
+ updated_datetime => sprintf( '<updated_datetime>%s</updated_datetime>', $dt ),
+ description => 'This is a note',
+ external_id => 638344,
+ start_state => 'confirmed',
+ comment_status => 'DUPLICATE',
+ mark_fixed=> 0,
+ mark_open => 0,
+ problem_state => 'duplicate',
+ end_state => 'duplicate',
+ },
+ {
+ desc => 'fixed status marks report as fixed - council',
+ updated_datetime => sprintf( '<updated_datetime>%s</updated_datetime>', $dt ),
+ description => 'This is a note',
+ external_id => 638344,
+ start_state => 'confirmed',
+ comment_status => 'FIXED',
+ mark_fixed=> 0,
+ mark_open => 0,
+ problem_state => 'fixed - council',
+ end_state => 'fixed - council',
+ },
+ {
+ desc => 'status of CLOSED marks report as fixed - council',
+ updated_datetime => sprintf( '<updated_datetime>%s</updated_datetime>', $dt ),
+ description => 'This is a note',
+ external_id => 638344,
+ start_state => 'confirmed',
+ comment_status => 'CLOSED',
mark_fixed=> 0,
mark_open => 0,
problem_state => 'fixed - council',
end_state => 'fixed - council',
},
{
- desc => 'comment re-opens fixed report',
+ desc => 'status of OPEN 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,
+ comment_status => 'OPEN',
mark_fixed => 0,
mark_open => 0,
problem_state => 'confirmed',
end_state => 'confirmed',
},
{
- desc => 'comment re-opens closed report',
+ desc => 'action sheduled re-opens fixed report as action scheduled',
updated_datetime => sprintf( '<updated_datetime>%s</updated_datetime>', $dt ),
description => 'This is a note',
external_id => 638344,
- start_state => 'closed',
- close_comment => 0,
+ start_state => 'fixed - user',
+ comment_status => 'ACTION_SCHEDULED',
+ mark_fixed => 0,
+ mark_open => 0,
+ problem_state => 'action scheduled',
+ end_state => 'action scheduled',
+ },
+ {
+ desc => 'open status re-opens closed report',
+ updated_datetime => sprintf( '<updated_datetime>%s</updated_datetime>', $dt ),
+ description => 'This is a note',
+ external_id => 638344,
+ start_state => 'not responsible',
+ comment_status => 'OPEN',
mark_fixed => 0,
mark_open => 0,
problem_state => 'confirmed',
end_state => 'confirmed',
},
{
- desc => 'comment leaves report closed',
+ desc => 'fixed status leaves fixed - user report as fixed - user',
+ updated_datetime => sprintf( '<updated_datetime>%s</updated_datetime>', $dt ),
+ description => 'This is a note',
+ external_id => 638344,
+ start_state => 'fixed - user',
+ comment_status => 'FIXED',
+ mark_fixed => 0,
+ mark_open => 0,
+ problem_state => undef,
+ end_state => 'fixed - user',
+ },
+ {
+ desc => 'closed status updates fixed report',
+ updated_datetime => sprintf( '<updated_datetime>%s</updated_datetime>', $dt ),
+ description => 'This is a note',
+ external_id => 638344,
+ start_state => 'fixed - user',
+ comment_status => 'NO_FURTHER_ACTION',
+ mark_fixed => 0,
+ mark_open => 0,
+ problem_state => 'unable to fix',
+ end_state => 'unable to fix',
+ },
+ {
+ desc => 'no futher action status closes report',
updated_datetime => sprintf( '<updated_datetime>%s</updated_datetime>', $dt ),
description => 'This is a note',
external_id => 638344,
- start_state => 'closed',
- close_comment => 1,
+ start_state => 'confirmed',
+ comment_status => 'NO_FURTHER_ACTION',
mark_fixed => 0,
mark_open => 0,
- end_state => 'closed',
+ problem_state => 'unable to fix',
+ end_state => 'unable to fix',
+ },
+ {
+ desc => 'fixed status sets closed report as fixed',
+ updated_datetime => sprintf( '<updated_datetime>%s</updated_datetime>', $dt ),
+ description => 'This is a note',
+ external_id => 638344,
+ start_state => 'unable to fix',
+ comment_status => 'FIXED',
+ mark_fixed => 0,
+ mark_open => 0,
+ problem_state => 'fixed - council',
+ end_state => 'fixed - council',
},
) {
subtest $test->{desc} => sub {
@@ -195,7 +341,7 @@ for my $test (
$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};
+ $local_requests_xml =~ s#<status>\w+</status>#<status>$test->{comment_status}</status># if $test->{comment_status};
my $o = Open311->new( jurisdiction => 'mysociety', endpoint => 'http://example.com', test_mode => 1, test_get_returns => { 'servicerequestupdates.xml' => $local_requests_xml } );
diff --git a/templates/email/default/confirm_report_sent.txt b/templates/email/default/confirm_report_sent.txt
new file mode 100644
index 000000000..42f200213
--- /dev/null
+++ b/templates/email/default/confirm_report_sent.txt
@@ -0,0 +1,9 @@
+Subject: Problem Report Sent: <?=$values['title']?>
+
+Hi,
+
+Your report about "<?=$values['title']?>" has been sent to <?=$values['councils_name']?>.
+
+Thanks
+
+<?=$values['signature']?>
diff --git a/templates/email/seesomething/confirm_report_sent.txt b/templates/email/seesomething/confirm_report_sent.txt
new file mode 100644
index 000000000..d62a50c49
--- /dev/null
+++ b/templates/email/seesomething/confirm_report_sent.txt
@@ -0,0 +1,10 @@
+Subject: See Something, Say Something report sent
+
+Thank you for your report. It will help us to direct our policing activity to make public transport even safer. Find out more of what we are doing at:
+
+Safer Travel Partnership
+
+http://www.safertravel.info
+
+Follow us on Twitter: https://www.twitter.com/ST_Police
+or on Facebook: http://www.facebook.com/safertravelpolice
diff --git a/templates/email/seesomething/submit.txt b/templates/email/seesomething/submit.txt
new file mode 100644
index 000000000..0682425fe
--- /dev/null
+++ b/templates/email/seesomething/submit.txt
@@ -0,0 +1,25 @@
+Subject: Report on See Something, Say Something
+
+A user of
+See Something, Say Something has submitted the following report
+of a problem that they believe might require your attention.
+
+<?=$values['image_url']?>
+----------
+
+<?=$values['user_details']?>
+
+<?=$values['phone_line']?><?=$values['category_line']?><?=$values['subcategory_line']?>
+
+Details: <?=$values['detail']?>
+
+<?=$values['easting_northing']?>Latitude: <?=$values['latitude']?>
+
+Longitude: <?=$values['longitude']?>
+
+<?=$values['closest_address']?>----------
+
+Replies to this email will go to the user who submitted the problem
+unless it is an anonymous report in which case they will be discarded.
+
+<?=$values['signature']?>
diff --git a/templates/web/bromley/report/display.html b/templates/web/bromley/report/display.html
index be5fd1ed4..329d7ace9 100644
--- a/templates/web/bromley/report/display.html
+++ b/templates/web/bromley/report/display.html
@@ -77,9 +77,11 @@
[% IF c.user && c.user.belongs_to_body( problem.bodies_str ) %]
<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')] ] %]
+ [% FOREACH state IN [ ['confirmed', loc('Open')], ['investigating',
+ loc('Investigating')], ['action scheduled', loc('Action Scheduled')],
+ ['in progress', loc('In Progress')], ['duplicate', loc('Duplicate')],
+ ['unable to fix', loc('Unable to fix')], ['not responsible', loc('Not Responsible')],
+ ['fixed', loc('Fixed')] ] %]
<option [% 'selected ' IF state.0 == problem.state %] value="[% state.0 %]">[% state.1 %]</option>
[% END %]
</select>
diff --git a/templates/web/default/admin/body-form.html b/templates/web/default/admin/body-form.html
index 7653f2884..039d83ae2 100644
--- a/templates/web/default/admin/body-form.html
+++ b/templates/web/default/admin/body-form.html
@@ -72,6 +72,11 @@
</p>
<p>
+ <label for="send_extended_statuses">Send extended open311 statuses with service request updates</label>:
+ <input type="checkbox" id="send_extended_statuses" name="send_extended_statuses"[% ' checked' IF conf.send_extended_statuses %]>
+ </p>
+
+ <p>
<input type="hidden" name="posted" value="body">
<input type="hidden" name="token" value="[% token %]">
<input type="submit" value="[% body ? loc('Update body') : loc('Add body') %]">
diff --git a/templates/web/default/around/around_index.html b/templates/web/default/around/around_index.html
index f58d13d80..a143e90a2 100644
--- a/templates/web/default/around/around_index.html
+++ b/templates/web/default/around/around_index.html
@@ -1,34 +1,24 @@
-[% INCLUDE 'header.html', title => loc('Reporting a problem') %]
-
-[%
- # 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.
-%]
-
-[% INCLUDE 'around/postcode_form.html' %]
-
-[% IF location_error %]
- <p class="error">[% location_error %]</p>
-[% END %]
-
-[% IF possible_location_matches %]
- <p>[% loc('We found more than one match for that location. We show up to ten matches, please try a different search if yours is not here.') %]</p>
- <ul class="pc_alternatives">
- [% FOREACH match IN possible_location_matches %]
- <li><a href="/around?latitude=[% match.latitude | uri %];longitude=[% match.longitude | uri %]">[% match.address | html %]</a></li>
- [% END %]
- </ul>
-[% END %]
-
-[% IF partial_token %]
- <p style="margin-top: 0; color: #cc0000;">
- <img align="right" src="/photo/[% 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;:") %]
- </p>
-[% END %]
-
-
+[% INCLUDE 'header.html', title => loc('Reporting a problem'), bodyclass = 'mappage' %]
+
+<form action="[% c.uri_for('/around') %]" method="get" name="mapForm" id="mapForm">
+ <div id="side-form">
+ <div id="report-a-problem-main">
+ [% INCLUDE 'around/postcode_form.html' %]
+
+ [% IF location_error %]
+ <p class="error">[% location_error %]</p>
+ [% END %]
+
+ [% IF possible_location_matches %]
+ <p>[% loc('We found more than one match for that location. We show up to ten matches, please try a different search if yours is not here.') %]</p>
+ <ul class="pc_alternatives">
+ [% FOREACH match IN possible_location_matches %]
+ <li><a href="/around?latitude=[% match.latitude | uri %];longitude=[% match.longitude | uri %]">[% match.address | html %]</a></li>
+ [% END %]
+ </ul>
+ [% END %]
+ </div>
+ </div>
+</form>
[% INCLUDE 'footer.html' %]
diff --git a/templates/web/default/around/display_location.html b/templates/web/default/around/display_location.html
index c9586c393..c8c6935de 100755
--- a/templates/web/default/around/display_location.html
+++ b/templates/web/default/around/display_location.html
@@ -29,9 +29,9 @@
PROCESS "maps/${map.type}.html";
+ SET rss = [ loc('Recent local problems, FixMyStreet'), rss_url ] IF c.cobrand.moniker != 'emptyhomes';
INCLUDE 'header.html',
title => loc('Viewing a location')
- rss => [ loc('Recent local problems, FixMyStreet'), rss_url ],
bodyclass => 'mappage',
robots => 'noindex,nofollow';
@@ -51,6 +51,7 @@
[% map_html %]
+ [% IF c.cobrand.moniker != 'emptyhomes' %]
<p id='sub_map_links'>
[% IF c.cobrand.moniker == 'zurich' %]
<a class="hidden-nojs" id="map_layer_toggle" href="">Stadtplan</a>
@@ -69,6 +70,7 @@
[% END %]
[% END %]
</p>
+ [% END %]
</div>
@@ -82,11 +84,13 @@
[% TRY %][% INCLUDE 'around/extra_text.html' %][% CATCH file %][% END %]
[% END %]
+ [% IF c.cobrand.moniker != 'emptyhomes' %]
[% INCLUDE 'around/_updates.html' %]
<section class="full-width">
[% INCLUDE "around/tabbed_lists.html" %]
</section>
+ [% END %]
</div>
[% IF allow_creation %]
diff --git a/templates/web/default/common_header_tags.html b/templates/web/default/common_header_tags.html
index 6582c19cc..346d53693 100644
--- a/templates/web/default/common_header_tags.html
+++ b/templates/web/default/common_header_tags.html
@@ -1,6 +1,7 @@
[% USE date %][% USE Math %]
<meta http-equiv="content-type" content="text/html; charset=utf-8">
+<script type="text/javascript" src="/js/validation_rules.js?[% Math.int( date.now / 3600 ) %]"></script>
<script type="text/javascript" src="/js/translation_strings.[% lang_code %].js?[% Math.int( date.now / 3600 ) %]"></script>
<script type="text/javascript" src="/jslib/jquery-1.7.2.min.js"></script>
diff --git a/templates/web/default/dashboard/index.html b/templates/web/default/dashboard/index.html
index b26bd48cd..f5a3cfba3 100644
--- a/templates/web/default/dashboard/index.html
+++ b/templates/web/default/dashboard/index.html
@@ -81,7 +81,7 @@
[%
rows = {
'0' => [ "in progress", "Council has marked as in progress" ]
- '1' => [ "planned", "Council has marked as planned" ]
+ '1' => [ "action scheduled", "Council has marked as planned" ]
'2' => [ "investigating", "Council has marked as investigating" ]
'3' => [ "closed", "Council has marked as closed" ]
};
@@ -98,10 +98,14 @@
<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>
+ <td>[% problems.wtd.${"in progress"} + problems.wtd.${"action scheduled"} +
+ problems.wtd.investigating + problems.wtd.closed %]</td>
+ <td>[% problems.week.${"in progress"} + problems.week.${"action scheduled"} +
+ problems.week.investigating + problems.wtd.closed %]</td>
+ <td>[% problems.weeks.${"in progress"} + problems.weeks.${"action scheduled"} +
+ problems.weeks.investigating + problems.wtd.closed %]</td>
+ <td>[% problems.ytd.${"in progress"} + problems.ytd.${"action scheduled"} +
+ problems.ytd.investigating + problems.wtd.closed %]</td>
</tr>
<tr id="avg_fixed">
@@ -136,8 +140,8 @@
<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')] ] %]
+ loc('Investigating')], ['action scheduled', 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>
diff --git a/templates/web/default/front/stats.html b/templates/web/default/front/stats.html
index 927ae4eb1..eae66018b 100644
--- a/templates/web/default/front/stats.html
+++ b/templates/web/default/front/stats.html
@@ -38,8 +38,8 @@
<div>[% tprintf( new_text, stats.new ) | comma %]</div>
[% IF c.cobrand.moniker != 'emptyhomes' %]
<div>[% tprintf( fixed_text, stats.fixed ) | comma %]</div>
- [% END %]
[% IF c.cobrand.moniker != 'zurich' %]
<div>[% tprintf( updates_text, stats.updates ) | comma %]</div>
[% END %]
+ [% END %]
</div>
diff --git a/templates/web/default/index-steps.html b/templates/web/default/index-steps.html
index 8a83abf07..6fae921b7 100644
--- a/templates/web/default/index-steps.html
+++ b/templates/web/default/index-steps.html
@@ -2,8 +2,23 @@
<ol class="big-numbers">
[% IF c.cobrand.moniker == 'fixmybarangay' %]
- <li>Text LUZ or BSN followed by your report to 12345</li>
- <li>Visit the Barangay Center in person</li>
+ <li>Text <span class="promo-big">FMB LUZ</span> or <span class="promo-big">FMB BSN</span> followed by your report to
+ <ul id="promo-list">
+ <li>
+ <span class="promo-bigger">391-FMB</span> (391362) SMART short code
+ </li>
+ <li>
+ <span class="promo-bigger">0908&nbsp;896&nbsp;8278</span> for all networks
+ </li>
+ </ul>
+ <div class="promo-example">
+ For example:<br/>
+ <div>
+ FMB LUZ Busted streetlamp, P. Cabantan St., Pole # 12345, near Sto. Antonio Chapel
+ </div>
+ </div>
+ </li>
+ <li>Or visit the Barangay Center in person</li>
<li>Staff? <a href="/auth">Sign in</a> and click on the map!
[% ELSE %]
<li>[% question %]</li>
diff --git a/templates/web/default/index.html b/templates/web/default/index.html
index 3cfc07591..beaeefb20 100644
--- a/templates/web/default/index.html
+++ b/templates/web/default/index.html
@@ -5,10 +5,13 @@
[% END %]
<p id="expl">
+ [% IF c.cobrand.moniker == 'emptyhomes' %]
+ <strong>[% loc('Report empty properties') %]</strong>
+ [% ELSE %]
[%
subhead
= c.cobrand.moniker == 'southampton'
- ? '(like graffiti, fly tipping, or broken paving slabs)'
+ ? ''
: loc('(like graffiti, fly tipping, broken paving slabs, or street lighting)');
%]
@@ -17,6 +20,7 @@
[% IF subhead != ' ' %]
<small>[% subhead %]</small>
[% END %]
+ [% END %]
</p>
[% TRY %][% INCLUDE 'front/news.html' %][% CATCH file %][% END %]
diff --git a/templates/web/default/js/validation_rules.html b/templates/web/default/js/validation_rules.html
new file mode 100644
index 000000000..409d0971f
--- /dev/null
+++ b/templates/web/default/js/validation_rules.html
@@ -0,0 +1,7 @@
+ validation_rules = {
+ title: { required: true },
+ detail: { required: true },
+ email: { required: true },
+ update: { required: true },
+ rznvy: { required: true }
+ };
diff --git a/templates/web/default/questionnaire/index.html b/templates/web/default/questionnaire/index.html
index 5b48f8915..6783bca57 100644
--- a/templates/web/default/questionnaire/index.html
+++ b/templates/web/default/questionnaire/index.html
@@ -80,9 +80,13 @@ href="http://www.emptyhomes.com/getinvolved/campaign.html">http://www.emptyhomes
</p>
[% END %]
+[% IF c.cobrand.moniker == 'southampton' %]
+<p>Add a public update (please note it will not be sent to the council)</p>
+[% ELSE %]
<p>[% loc('If you wish to leave a public update on the problem, please enter it here
(please note it will not be sent to the council). For example, what was
your experience of getting the problem fixed?') %]</p>
+[% END %]
<p><textarea name="update" style="max-width:90%" rows="7" cols="30">[% update | html %]</textarea></p>
diff --git a/templates/web/default/report/_main.html b/templates/web/default/report/_main.html
index 9b637b83c..789f8e43e 100644
--- a/templates/web/default/report/_main.html
+++ b/templates/web/default/report/_main.html
@@ -3,7 +3,7 @@
<p><em>
[% problem.meta_line(c) | html %]
- [%- IF !problem.used_map %]; <strong>[% loc('there is no pin shown as the user did not use the map') %]</strong>[% END %]
+ [%- IF !problem.used_map AND c.cobrand.moniker != 'emptyhomes' %]; <strong>[% loc('there is no pin shown as the user did not use the map') %]</strong>[% END %]
[% IF problem.bodies_str %]
[% IF problem.whensent || problem.can_display_external_id %]
<small class="council_sent_info"><br>
diff --git a/templates/web/default/report/banner.html b/templates/web/default/report/banner.html
index 85aaed82d..52bfa6e67 100644
--- a/templates/web/default/report/banner.html
+++ b/templates/web/default/report/banner.html
@@ -14,7 +14,7 @@
[% IF problem.is_closed %]
[% INCLUDE banner, id = 'closed', text = loc('This problem has been closed') %]
[% END %]
-[% states = [ 'investigating', 'in progress', 'planned' ];
+[% states = [ 'investigating', 'in progress', 'planned', 'action scheduled' ];
IF states.grep(problem.state).size %]
[% INCLUDE banner, id = 'progress', text = loc('This problem is in progress') %]
[% END %]
diff --git a/templates/web/default/report/display.html b/templates/web/default/report/display.html
index 18b4bf51a..2ade45a8a 100644
--- a/templates/web/default/report/display.html
+++ b/templates/web/default/report/display.html
@@ -2,15 +2,18 @@
PROCESS "maps/${map.type}.html";
problem_title = problem.title _ ' - ' _ loc('Viewing a problem');
+ SET rss = [ loc('Updates to this problem, FixMyStreet'), "/rss/$problem.id" ] IF c.cobrand.moniker != 'emptyhomes';
+ SET robots = 'index, nofollow';
+ SET robots = 'noindex, nofollow' IF c.cobrand.moniker == 'emptyhomes';
INCLUDE 'header.html'
title = problem_title
- rss = [ loc('Updates to this problem, FixMyStreet'), "/rss/$problem.id" ]
- robots = 'index, nofollow'
%]
-[% map_html %]
+[% IF c.cobrand.moniker != 'emptyhomes' %]
+ [% map_html %]
+ </div>
+[% END %]
-</div>
<div id="side">
[% INCLUDE 'report/banner.html' %]
@@ -22,6 +25,7 @@
</small>
</p>
+[% IF c.cobrand.moniker != 'emptyhomes' %]
<p style="padding-bottom: 0.5em; border-bottom: dotted 1px #999999;" align="right">
<a href="[% c.uri_for( '/around', { lat => short_latitude, lon => short_longitude } ) %]">[% loc( 'More problems nearby' ) %]</a>
</p>
@@ -45,6 +49,7 @@
[% INCLUDE 'report/updates.html' %]
[% INCLUDE 'report/update-form.html' %]
+[% END %]
</div>
diff --git a/templates/web/default/report/new/category.html b/templates/web/default/report/new/category.html
index f2ef529f2..a701e0851 100644
--- a/templates/web/default/report/new/category.html
+++ b/templates/web/default/report/new/category.html
@@ -3,7 +3,7 @@
[% IF category;
category = category | lower;
END; %]
- <label for='form_category'>[% category_label | html %]</label>
+ <label for='form_category' id="form_category_label">[% category_label | html %]</label>
<select name='category' id='form_category'[% ' onchange="form_category_onchange()"' IF category_extras.size %]>
[% FOREACH cat_op IN category_options %]
[% cat_op_lc = cat_op | lower %]
diff --git a/templates/web/default/report/new/fill_in_details_form.html b/templates/web/default/report/new/fill_in_details_form.html
index 4af0baccd..5eff4e147 100644
--- a/templates/web/default/report/new/fill_in_details_form.html
+++ b/templates/web/default/report/new/fill_in_details_form.html
@@ -206,7 +206,7 @@
<div class="checkbox">
[%# if there is nothing in the name field then set check box as default on form %]
- <input type="checkbox" name="may_show_name" id="form_may_show_name" value="1"[% ' checked' IF !report.anonymous %]>
+ <input type="checkbox" name="may_show_name" id="form_may_show_name" value="1"[% ' checked' IF report.anonymous==0 OR (c.cobrand.default_show_name AND report.anonymous=='') %]>
<label for="form_may_show_name">[% loc('Show my name publicly') %]</label>
<br><small>[% loc('(we never show your email address or phone number)') %]</small>
</div>
diff --git a/templates/web/default/report/update-form.html b/templates/web/default/report/update-form.html
index eeaec7915..50bc2906c 100644
--- a/templates/web/default/report/update-form.html
+++ b/templates/web/default/report/update-form.html
@@ -28,8 +28,10 @@
<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')] ] %]
+ loc('Investigating')], ['action scheduled', loc('Action Scheduled')],
+ ['in progress', loc('In Progress')], ['duplicate', loc('Duplicate')],
+ ['unable to fix', loc('Unable to fix')], ['not responsible', loc('Not Responsible')],
+ ['fixed', loc('Fixed')] ] %]
<option [% 'selected ' IF state.0 == problem.state %] value="[% state.0 %]">[% state.1 %]</option>
[% END %]
</select>
@@ -151,7 +153,7 @@
</div>
<div class="checkbox">
- <input type="checkbox" name="may_show_name" id="form_may_show_name" value="1"[% ' checked' UNLESS update.anonymous %]>
+ <input type="checkbox" name="may_show_name" id="form_may_show_name" value="1"[% ' checked' IF update.anonymous==0 OR (c.cobrand.default_show_name AND update.anonymous=='') %]>
<label for="form_may_show_name">[% loc('Show my name publicly') %]</label>
<small>[% loc('(we never show your email)') %]</small>
</div>
diff --git a/templates/web/default/report/updates.html b/templates/web/default/report/updates.html
index a892e0e69..04a8bec33 100644
--- a/templates/web/default/report/updates.html
+++ b/templates/web/default/report/updates.html
@@ -1,3 +1,4 @@
+[% global.last_state = '' %]
[% FOREACH update IN updates %]
[% INCLUDE 'report/update.html' %]
[% END %]
@@ -22,8 +23,20 @@
[%- ELSE %]
[% tprintf( loc( 'Posted by %s at %s' ), update.name, prettify_dt( update.confirmed_local ) ) | html -%]
[%- END -%]
- [%- ", " _ loc( 'marked as fixed' ) IF update.mark_fixed %]
- [%- ", " _ loc( 'reopened' ) IF update.mark_open OR update.problem_state == 'confirmed' %]
- [%- ", " _ tprintf(loc( 'marked as %s' ), update.meta_problem_state) IF update.problem_state AND update.problem_state != 'confirmed' %]
+ [%- update_state = '' %]
+ [%- IF update.mark_fixed %][% update_state = ", " _ loc( 'marked as fixed' ) %][% END %]
+ [%- IF update.mark_open %][% update_state = ", " _ loc( 'reopened' ) %][% END %]
+ [%- IF !update_state && update.problem_state %]
+ [%- state = update.meta_problem_state %]
+ [%- IF ( c.cobrand.moniker == 'bromley' OR update.user.council == 'Bromley Council' ) AND update.problem_state == 'unable to fix' %]
+ [%- state = loc('no further action') %]
+ [% END %]
+ [%- IF update.problem_state == 'confirmed' AND global.last_state != '' %]
+ [%- update_state = ", " _ loc('reopened') %]
+ [%- ELSIF update.problem_state != 'confirmed' %]
+ [%- update_state = ", " _ tprintf(loc( 'marked as %s' ), state ) %]
+ [% END %]
+ [%- END %]
+ [%- update_state IF update_state != global.last_state %]
+ [%- global.last_state = update_state %]
[% END %]
-
diff --git a/templates/web/default/report_created.html b/templates/web/default/report_created.html
new file mode 100644
index 000000000..81083654b
--- /dev/null
+++ b/templates/web/default/report_created.html
@@ -0,0 +1,9 @@
+[% INCLUDE 'header.html', title => loc('Report created') %]
+
+<h1>[% loc("Report created") %]</h1>
+
+<p>
+[% loc('Your report has been created and will shortly be sent.') %]
+</p>
+
+[% INCLUDE 'footer.html' %]
diff --git a/templates/web/default/reports/body.html b/templates/web/default/reports/body.html
index 284915571..da184c6e9 100755
--- a/templates/web/default/reports/body.html
+++ b/templates/web/default/reports/body.html
@@ -1,9 +1,3 @@
-[% IF c.cobrand.moniker == 'fixmystreet' OR c.cobrand.moniker == 'bromley';
- style = 'new';
- ELSE;
- style = 'old';
- END;
-%]
[% IF ward %]
[% name = "$ward.name, $body.name"
thing = loc('ward')
@@ -24,7 +18,6 @@
PROCESS "maps/${map.type}.html";
INCLUDE 'header.html',
title = tprintf(loc('%s - Summary reports'), name)
- context = 'reports'
bodyclass = 'mappage'
rss = [ tprintf(loc('Problems within %s, FixMyStreet'), name), rss_url ]
%]
diff --git a/templates/web/emptyhomes/around/display_location.html b/templates/web/emptyhomes/around/display_location.html
deleted file mode 100755
index 888c8717e..000000000
--- a/templates/web/emptyhomes/around/display_location.html
+++ /dev/null
@@ -1,56 +0,0 @@
-[%
-
- url_skip = c.uri_for(
- '/report/new',
- {
- pc => pc
- latitude => short_latitude,
- longitude => short_longitude,
- skipped => 1,
- }
- );
-
- PROCESS "maps/${map.type}.html";
-
- INCLUDE 'header.html',
- title => loc('Viewing a location')
- robots => 'noindex,nofollow';
-%]
-
-<form action="[% c.uri_for('/report/new') %]" method="post" name="mapForm" id="mapForm" enctype="multipart/form-data">
-[% IF c.req.params.map_override %]
-<input type="hidden" name="map_override" value="[% c.req.params.map_override | html %]">
-[% END %]
-<input type="hidden" name="pc" value="[% pc | html %]">
-
-<input type="hidden" name="latitude" id="fixmystreet.latitude" value="[% short_latitude | html %]">
-<input type="hidden" name="longitude" id="fixmystreet.longitude" value="[% short_longitude | html %]">
-
-[% map_html %]
-
-</div>
-<div id="side">
-
-<p id="text_map" class="banner">
- [% loc( 'To <strong>report a problem</strong>, simply click on the map at the correct location.' ) %]
- [%
- tprintf(
- loc("<small>If you cannot see the map, <a href='%s' rel='nofollow'>skip this step</a>.</small>"),
- url_skip
- )
- %]
- <span id="text_map_arrow"></span>
-</p>
-
-</div>
-
-<div style="display:none" id="side-form">
-[% INCLUDE "report/new/fill_in_details_form.html"
- js = 1,
- report.used_map = 1
-%]
-</div>
-
-</form>
-
-[% INCLUDE 'footer.html' %]
diff --git a/templates/web/emptyhomes/front/stats.html b/templates/web/emptyhomes/front/stats.html
deleted file mode 100644
index cbb26fee1..000000000
--- a/templates/web/emptyhomes/front/stats.html
+++ /dev/null
@@ -1,27 +0,0 @@
-[%
- USE Comma;
- # Note - if we want to i18n the commas we should try
- # 'Template::Plugin::Number::Format'
-%]
-
-[%
- stats = c.cobrand.front_stats_data();
-
- new_text =
- stats.recency == '1 week'
- ? nget(
- "<big>%s</big> report in past week",
- "<big>%s</big> reports in past week",
- stats.new
- )
- : nget(
- "<big>%s</big> report recently",
- "<big>%s</big> reports recently",
- stats.new
- );
-
-%]
-
-<div id="front_stats">
- <div>[% tprintf( new_text, stats.new ) | comma %]</div>
-</div>
diff --git a/templates/web/emptyhomes/header.html b/templates/web/emptyhomes/header.html
index 96ad1040c..cc2f68ac0 100644
--- a/templates/web/emptyhomes/header.html
+++ b/templates/web/emptyhomes/header.html
@@ -25,6 +25,7 @@
<div id="navigation">
<ul>
<li><a href="/">[% loc("Report a problem") %]</a></li>
+ <li><a href="/reports">[% loc("All reports") %]</a></li>
<li><a href="/faq">[% loc("Help") %]</a></li>
<li><a href="/about">[% loc('About us') %]</a></li>
[% IF lang_code == 'en-gb' %]
diff --git a/templates/web/emptyhomes/index.html b/templates/web/emptyhomes/index.html
deleted file mode 100644
index 9ca771fc0..000000000
--- a/templates/web/emptyhomes/index.html
+++ /dev/null
@@ -1,68 +0,0 @@
-[% INCLUDE 'header.html', title => '' %]
-
-[% IF c.req.uri.host == 'reportemptyhomes.com' or c.req.uri.host == 'emptyhomes.matthew.fixmystreet.com' %]
-
-<h2>Channel 4: The Great British Property Scandal</h2>
-
-<div class="video"><object id="flashObj" width="480" height="270" classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=9,0,47,0"><param name="movie" value="http://c.brightcove.com/services/viewer/federated_f9?isVid=1&isUI=1" /><param name="bgcolor" value="#FFFFFF" /><param name="flashVars" value="@videoPlayer=1293919404001&playerID=1242807532001&playerKey=AQ~~,AAABIWs5YNk~,K8Yb_Dc0PlMA8gCUiCBbnEcXR1bU7HRm&domain=embed&dynamicStreaming=true" /><param name="base" value="http://admin.brightcove.com" /><param name="seamlesstabbing" value="false" /><param name="allowFullScreen" value="true" /><param name="swLiveConnect" value="true" /><param name="allowScriptAccess" value="always" /><embed src="http://c.brightcove.com/services/viewer/federated_f9?isVid=1&isUI=1" bgcolor="#FFFFFF" flashVars="@videoPlayer=1293919404001&playerID=1242807532001&playerKey=AQ~~,AAABIWs5YNk~,K8Yb_Dc0PlMA8gCUiCBbnEcXR1bU7HRm&domain=embed&dynamicStreaming=true" base="http://admin.brightcove.com" name="flashObj" width="480" height="270" seamlesstabbing="false" type="application/x-shockwave-flash" allowFullScreen="true" allowScriptAccess="always" swLiveConnect="true" pluginspage="http://www.macromedia.com/shockwave/download/index.cgi?P1_Prod_Version=ShockwaveFlash"></embed></object></div>
-
-<p>
-Empty Homes were offical advisors to the recent empty homes TV series <strong>The Great British Property Scandal</strong>!
-</p>
-
-<p>
-The series highlighted the nearly two million British families who don’t have adequate housing, and the million-odd homes lying empty across the UK.
-</p>
-
-<p>
-The TV series launched a campaign for action and while this is running, our <a href="[% uri => '/' %]">www.reportemptyhomes.com</a> website has been merged with the campaign's reporting system so that all reports are gathered together and sent on to the local councils. Please use these links to report empty properties which you know of:
-</p>
-
-<ul class="channel4">
-
-<li><a href="http://www.channel4.com/programmes/the-great-british-property-scandal/articles/report-an-empty">Report an empty property</a></li>
-<li><a href="http://cy.reportemptyhomes.com/">Rhoi gwybod am eiddo gwag</a></li>
-
-<li><a href="http://itunes.apple.com/gb/app/empty-homes-spotter/id482550587?mt=8"><img src="/i/appstore.png" hspace="5" alt="" align="right">Download the iPhone app</a> from the App Store.</li>
-
-</ul>
-
-[% ELSE %]
-
-[% IF error %]
- <p class="error">[% error %]</p>
-[% END %]
-
-<p id="expl">
- <strong>[% loc('Report empty properties') %]</strong>
-</p>
-
-[%
- question = 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>
- <span><input type="text" name="pc" value="" id="pc" size="10" maxlength="200">
- <input type="submit" value="[% loc('Go') %]" id="sub">
- </span>
-</form>
-
-<div id="front_intro">
-
- <h2>[% loc('How to report a problem') %]</h2>
-
- <ol>
- <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>
- </ol>
-
- [% INCLUDE "front/stats.html" %]
-
-</div>
-
-[% END %]
-
-[% INCLUDE 'footer.html' %]
diff --git a/templates/web/emptyhomes/report/banner.html b/templates/web/emptyhomes/report/banner.html
new file mode 100644
index 000000000..d473a777e
--- /dev/null
+++ b/templates/web/emptyhomes/report/banner.html
@@ -0,0 +1,6 @@
+[% IF problem.is_fixed %]
+<p class="banner" id="fixed">
+ [% loc('This problem has been fixed') %].
+</p>
+[% END %]
+
diff --git a/templates/web/emptyhomes/report/display.html b/templates/web/emptyhomes/report/display.html
deleted file mode 100644
index 911908d2b..000000000
--- a/templates/web/emptyhomes/report/display.html
+++ /dev/null
@@ -1,32 +0,0 @@
-[%
- problem_title = loc('Viewing a problem');
- INCLUDE 'header.html'
- title = problem_title
- robots = 'noindex, nofollow'
-%]
-
-<div id="side">
-
-[% IF problem.is_fixed %]
-<p class="banner" id="fixed">
- [% loc('This problem has been fixed') %].
-</p>
-[% END %]
-
-<h1>Empty property report</h1>
-
-<p><em>[% problem.meta_line(c) | html %]
-[% IF problem.bodies_str %]
- [% IF problem.whensent %]
- <small class="council_sent_info"><br>[% problem.duration_string(c) %]</small>
- [% END %]
-[% ELSE %]
-<br><small>[% loc('Not reported to council') %]</small>
-[% END %]
-
-</em></p>
-
-</div>
-
-[% INCLUDE 'footer.html' %]
-
diff --git a/templates/web/emptyhomes/report/new/councils_text_all.html b/templates/web/emptyhomes/report/new/councils_text_all.html
index cd892212c..5769e6cd5 100644
--- a/templates/web/emptyhomes/report/new/councils_text_all.html
+++ b/templates/web/emptyhomes/report/new/councils_text_all.html
@@ -1,7 +1,7 @@
<p>
[%
tprintf(
- loc('All the information you provide here will be sent to <strong>%s</strong>. On the site, we will show the subject and details of the problem, plus your name if you give us permission.'),
+ loc('All the information you provide here will be sent to <strong>%s</strong>. On the site, we will show the subject and details of the problem.'),
all_body_names.join( '</strong>' _ loc(' or ') _ '<strong>' )
);
%]
diff --git a/templates/web/emptyhomes/reports/_ward-list.html b/templates/web/emptyhomes/reports/_ward-list.html
new file mode 100755
index 000000000..e69de29bb
--- /dev/null
+++ b/templates/web/emptyhomes/reports/_ward-list.html
diff --git a/templates/web/emptyhomes/reports/body.html b/templates/web/emptyhomes/reports/body.html
deleted file mode 100755
index eff87d823..000000000
--- a/templates/web/emptyhomes/reports/body.html
+++ /dev/null
@@ -1,73 +0,0 @@
-[% IF ward %]
- [% name = "$ward.name, $council.name"
- thing = loc('ward')
- %]
-[% ELSE %]
- [% name = council.name
- thing = loc('council')
- %]
-[% END %]
-
-[%
- INCLUDE 'header.html',
- title = tprintf(loc('%s - Summary reports'), name)
- context = 'reports'
-%]
-
-[% IF children.size %]
-<h2 style="clear:right">[% loc('Wards of this council') %]</h2>
-<p>[% loc('Follow a ward link to view only reports within that ward.') %]</p>
-<ul>
-[% FOR child IN children.values.sort('name') %]
-<li><a href="[% child.url %]">[% child.name %]</a></li>
-[% END %]
-</ul>
-[% END %]
-
-<div id="side">
-
-[% IF NOT body.areas AND c.cobrand.country == 'GB' %]
-<p id="unknown">This council no longer exists.
-[% IF council.name.match('Penwith|Kerrier|Carrick|Restormel|Caradon|North Cornwall') %]
-Its area is now covered by <a href="/reports/Cornwall">Cornwall Council</a>.
-[% ELSIF council.name.match('Durham|Easington|Sedgefield|Teesdale|Wear Valley|Derwentside|Chester le Street') %]
-Its area is now covered by <a href="/reports/Durham+County">Durham County Council</a>.
-[% ELSIF council.name.match('Blyth Valley|Wansbeck|Castle Morpeth|Tynedale|Alnwick|Berwick upon Tweed') %]
-Its area is now covered by <a href="/reports/Northumberland">Northumberland County Council</a>.
-[% ELSIF council.name.match('North Shropshire|Oswestry|Shrewsbury and Atcham|South Shropshire|Bridgnorth') %]
-Its area is now covered by <a href="/reports/Shropshire">Shropshire Council</a>.
-[% ELSIF council.name.match('Salisbury|West Wiltshire|Kennet|North Wiltshire') %]
-Its area is now covered by <a href="/reports/Wiltshire">Wiltshire Council</a>.
-[% ELSIF council.name.match('Ellesmere Port and Neston|Vale Royal|Chester') %]
-Its area is now covered by <a href="/reports/Cheshire+West+and+Chester">Cheshire West and Chester Council</a>.
-[% ELSIF council.name.match('Macclesfield|Congleton|Crewe and Nantwich') %]
-Its area is now covered by <a href="/reports/Cheshire+East">Cheshire East Council</a>.
-[% ELSIF council.name.match('Mid Bedfordshire|South Bedfordshire') %]
-Its area is now covered by <a href="/reports/Central+Bedfordshire">Central Bedfordshire Council</a>.
-[% ELSIF council.name.match('Cheshire') %]
-Its area is now covered by <a href="/reports/Cheshire+West+and+Chester">Cheshire West and Chester Council</a> or
-<a href="/reports/Cheshire+East">Cheshire East Council</a>.
-[% ELSIF council.name.match('Bedfordshire') %]
-Its area is now covered by <a href="/reports/Bedford">Bedford Borough Council</a> or
-<a href="/reports/Central+Bedfordshire">Central Bedfordshire Council</a>.
-[% END %]
-</p>
-[% END %]
-
-[% IF c.cobrand.all_councils_report %]
- [% tprintf( loc('This is a summary of all reports for one %s.'), thing ) %]
-[% ELSE %]
- [% tprintf( loc('This is a summary of all reports for this %s.'), thing ) %]
-[% END %]
-
-[% IF ward %]
-[% tprintf( loc('You can <a href="%s">view all reports for the council</a> or <a href="/reports">show all councils</a>.'), council_url ) %]
-[% ELSE %]
-[% loc('You can <a href="/reports">show all councils</a>.') %]
-[% END %]
-
-<h2>[% name %]</h2>
-
-</div>
-[% INCLUDE 'footer.html' %]
-
diff --git a/templates/web/emptyhomes/reports/index.html b/templates/web/emptyhomes/reports/index.html
index 9ce2b66ca..3029bcd1c 100755
--- a/templates/web/emptyhomes/reports/index.html
+++ b/templates/web/emptyhomes/reports/index.html
@@ -10,8 +10,6 @@
<th>[% loc('Name') %]</th>
<th>[% loc('New problems') %]</th>
<th>[% loc('Older problems') %]</th>
-<th>[% loc('Recently fixed') %]</th>
-<th>[% loc('Older fixed') %]</th>
</tr>
[% FOREACH body IN bodies %]
@@ -20,12 +18,11 @@
[%- ELSIF loop.count % 2 %] class="a"
[%- END -%]
>
-<td align="left">[% body.name %]</td>
+<td align="left"><a href="[% body.url(c) %]">[% body.name %]</a></td>
<td>[% open.${body.id}.new or 0 %]</td>
-<td>[% (open.${body.id}.older or 0) + (open.${body.id}.unknown or 0) %]</td>
-<td>[% fixed.${body.id}.new or 0 %]</td>
-<td>[% fixed.${body.id}.old or 0 %]</td>
+<td>[% (open.${body.id}.older or 0) + (open.${body.id}.unknown or 0) + (fixed.${body.id}.new or 0) + (fixed.${body.id}.old or 0) %]</td>
</tr>
+
[% END %]
</table>
diff --git a/templates/web/emptyhomes/tracking_code.html b/templates/web/emptyhomes/tracking_code.html
deleted file mode 100644
index 73526d3bd..000000000
--- a/templates/web/emptyhomes/tracking_code.html
+++ /dev/null
@@ -1,12 +0,0 @@
-<!-- Piwik -->
-<script type="text/javascript">
-var pkBaseURL = (("https:" == document.location.protocol) ? "https://piwik.mysociety.org/" : "http://piwik.mysociety.org/");
-document.write(unescape("%3Cscript src='" + pkBaseURL + "piwik.js' type='text/javascript'%3E%3C/script%3E"));
-</script><script type="text/javascript">
-try {
-var piwikTracker = Piwik.getTracker(pkBaseURL + "piwik.php", 12);
-piwikTracker.trackPageView();
-piwikTracker.enableLinkTracking();
-} catch( err ) {}
-</script><noscript><img width=1 height=1 src="http://piwik.mysociety.org/piwik.php?idsite=12" style="border:0" alt=""></noscript>
-<!-- End Piwik Tag -->
diff --git a/templates/web/fixmybarangay/faq/faq-en-gb.html b/templates/web/fixmybarangay/faq/faq-en-gb.html
index 320a7528e..771569e23 100644
--- a/templates/web/fixmybarangay/faq/faq-en-gb.html
+++ b/templates/web/fixmybarangay/faq/faq-en-gb.html
@@ -54,7 +54,8 @@ the problem.</dd>
<dd>
You can use your email address and set a password right away, but your
account won't be enabled as a <em>staff account</em> until one of the
- system administrators has checked it. TODO: contact details.
+ system administrators has checked it. If you're not sure who to contact, try
+ <a href="mailto:[% c.config.CONTACT_EMAIL %]">[% c.config.CONTACT_EMAIL %]</a>.
</dd>
<dt>I've forgotten my password, what do I do?</dt>
<dd>
@@ -68,10 +69,32 @@ the problem.</dd>
or quit the browser (just closing the window without quitting the browser is not enough).
</dd>
<dt>Reporting</dt>
- <dd>TODO</dd>
+ <dd><p>
+ To make a new report, start by clicking on the button for either barangay <em>BSN</em> or <em>Luz</em>.
+ </p>
+ <ul>
+ <li>
+ <strong>To create a standalone report</strong> simply click on the map where the problem is.
+ </li>
+ <li>
+ <strong>To create a report from a text message</strong> log into Message Manager (see below),
+ then select the message you want to use (click on the radio button). When the message has gone
+ green, you can click on the map and the message will automatically be used to create the report.
+ You can edit the text, but that report will be associated with that incoming message.
+ </li>
+ </ul>
+ <p>
+ Once you've placed the pin, but before you press <em>Submit</em>, you can drag or reposition the pin
+ if you want to change its position.
+ </p>
+ <p>
+ Choose the category for this report &dash; obviously, this helps FixMyBarangay decide to which
+ department the report will be sent.
+ </p>
+ </dd>
<dt>How do I see the SMS messages people have sent?</dt>
- <dd>When you look at the barangay problems, click on "Problems via text"
- (or, if you're viewing a specific report, click "Show messages") to see the
+ <dd>When you look at the barangay problems, click on <em>Problems via text</em>
+ (or, if you're viewing a specific report, click <em>Show messages</em>) to see the
currently available messages. You'll need a username and password
for the Message Manager (your manager will have told you what these
are). Note that you can only see messages that have not yet been used to
@@ -82,31 +105,40 @@ the problem.</dd>
No, it's a separate account (some FMB users don't have any access to the SMS messages).
Your manager will tell you what your login for Message Manager system is, if you have one.
</dd>
- <dt>I tried to work with a message but it said "lock not granted". What's up?</dt>
+ <dt>I tried to work with a message but it said "Someone is working with that message right now!" What's up?</dt>
<dd>
- This means another staff member is working on the message. To prevent you both creating
+ This means another staff member has a "lock" on the message. To prevent you both creating
a report, or sending a reply, we use a first-come-first-serve locking mechanism.
Collisions like this are rare, but if they do happen, try again a few minutes later
because the lock may have expired by then.
</dd>
<dt>Can I delete a message?</dt>
<dd>
- Yes. Click on the red cross when you hover over it (although really you're only hiding it).
- You need an <em>administrator</em> account in the Message Manager to be able to see the
+ Yes. Click on the red cross when you hover over it (although really you're only hiding it so
+ it never gets shown within FixMyBarangay).
+ You need a manager's account in the Message Manager to be able to see any
messages that have been hidden, so hiding them is as good as deleting them.
</dd>
<dt>It looks like an incoming message is wrongly shown as a reply. Can I fix it?</dt>
<dd>
FixMyBarangay tries to recognise SMS replies, and automatically matches them to the right thread. If it
- gets this wrong, the reply may appear as a new "available" message, or a new message might be
- mistaken for a reply. You need to ask an administrator to log into Message Manager to sort this out for you.
+ gets this wrong you can click on the <em>detach</em> button. The message will then be a new "available"
+ message. If Message Manager got it wrong the other way round, and missed a reply, you can fix this too
+ but you need to log into Message Manager with a manager's account to do it.
</dd>
<dt>How do the replies get back to the original sender?</dt>
<dd>
Although you're replying from within FixMyBarangay, the replies are sent by SMS.
- There may be a delay of a few minutes between the moment you press <strong>reply</strong>
+ There may be a delay of a several minutes between the moment you press <strong>reply</strong>
and the message's arrival.
</dd>
+ <dt>How can I tell the original sender their problem has been fixed?</dt>
+ <dd>
+ Go to the report. If the report is marked "this report was submitted by SMS", you can send a reply.
+ Click on <em>Show Messages</em>. When the messages appear, click on <em>Show messages for
+ <strong>this</strong> report</em>. Hover over the message you want to send the message to, and
+ click <em>Reply</em>.
+ </dd>
<h2><a name="organisation"></a>Organisation Questions</h2>
<dl>
diff --git a/templates/web/fixmybarangay/footer.html b/templates/web/fixmybarangay/footer.html
index 88f18db4b..5bac32e98 100644
--- a/templates/web/fixmybarangay/footer.html
+++ b/templates/web/fixmybarangay/footer.html
@@ -75,6 +75,29 @@
</div>
</div>
<div style="display:none">
+ <div id="detach-form-container" class="fancybox-popup">
+ <p>
+ Are you sure you want to detach this message?
+ </p>
+ <p>
+ Message Manager probably thinks this message is a reply because
+ it came in from a number to which we'd recently sent an outward reply.
+ </p>
+ <p>
+ If you detach the message, it will appear as a new, available message (instead of being a reply).
+ </p>
+ <form action="/dummy" id="detach-form" onsubmit="event.returnValue = false; return false;" method="post" accept-charset="utf-8">
+ <div style="display:none;">
+ <input type="hidden" name="_method" value="POST">
+ </div>
+ <input type="hidden" name="msg_id" id="detach_msg_id">
+ <div class="submit">
+ <input id="detach-submit" type="submit" value="Detach Message">
+ </div>
+ </form>
+ </div>
+ </div>
+ <div style="display:none">
<div id="mm-help" style="font-size:90%;">
<h2> Accessing Message Manager from FixMyBarangay (FMB)</h2>
<h3>
@@ -125,14 +148,23 @@
</p>
[% END %]
<h3>
- Replying to a message
+ <span class="demo_detach_btn">detach</span> Detaching a message ("not a reply")
+ </h3>
+ <p>
+ Message Manager tries to notice when an incoming message is a reply. Sometimes it guesses wrong. To detach a
+ message from its parent &mdash; that is, to mark it as <em>not a reply</em>, hover over the message and click
+ <span class="demo_detach_btn">detach</span>.
+ </p>
+
+ <h3>
+ <span class="demo_reply_btn">reply</span> Replying to a message
</h3>
<p>
You can send an SMS back to the original sender: just hover over the message and click <span class="demo_reply_btn">reply</span>. It will usually
take a few minutes for the message to arrive.
</p>
<h3>
- Getting message info
+ <span class="demo_info_btn">i</span> Getting message info
</h3>
<p>
Hover over a message and click on its <span class="demo_info_btn">i</span> button to see when it was sent.
@@ -140,7 +172,7 @@
actual number (instead the number is scrambled, but will be the <em>same scrambled number</em> on other messages they've sent).
</p>
<h3>
- Hiding a message
+ <span class="demo_hide_btn">X</span> Hiding a message
</h3>
<p>
If a message can't be used to create a report, you can hide it by hovering over it and clicking its <span class="demo_hide_btn">X</span> button. If you're not
diff --git a/templates/web/fixmybarangay/report/_message_manager.html b/templates/web/fixmybarangay/report/_message_manager.html
index 08f333cad..2860689be 100644
--- a/templates/web/fixmybarangay/report/_message_manager.html
+++ b/templates/web/fixmybarangay/report/_message_manager.html
@@ -109,19 +109,25 @@ $(document).ready(function() {
$('#external_source_id').val(service_id);
}
- var dummy_reply_cleanup = function(data) {
+ var reply_cleanup = function(data) {
reset_timeout();
$('#reply_text').val('');
dummy_busy = false;
mm_refresh_messages();
}
- var dummy_hide_cleanup = function(data) {
+ var hide_cleanup = function(data) {
reset_timeout();
$('#reason_text').val('');
dummy_busy = false;
}
+ var detach_cleanup = function(data) {
+ reset_timeout();
+ dummy_busy = false;
+ mm_refresh_messages(); // refresh because detached message now appears in the list
+ }
+
var custom_tooltips;
if (problem_id) { // this page is viewing, not creating
custom_tooltips = {tt_radio: "Select before clicking 'Copy to Update' to add this message as an update"};
@@ -180,7 +186,7 @@ $(document).ready(function() {
message_manager.reply(
$('#reply_to_msg_id').val(),
$('#reply_text').val(),
- {callback:dummy_reply_cleanup});
+ {callback:reply_cleanup});
}
});
@@ -195,9 +201,20 @@ $(document).ready(function() {
message_manager.hide(
$('#hide_msg_id').val(),
$('#reason_text').val(),
- {callback:dummy_hide_cleanup});
+ {callback:hide_cleanup});
}
});
+
+ $('#detach-submit').click(function(e) {
+ e.preventDefault();
+ if (! dummy_busy) {
+ dummy_busy = true;
+ message_manager.mark_as_not_a_reply(
+ $('#detach_msg_id').val(),
+ {callback:detach_cleanup});
+ }
+ });
+
$("a#reply").fancybox({onClosed: function(){dummy_busy=false;}});
// only show on problem display page
diff --git a/templates/web/fixmybarangay/report/new/councils_text.html b/templates/web/fixmybarangay/report/new/councils_text.html
index 24c54ea50..0001b0e68 100644
--- a/templates/web/fixmybarangay/report/new/councils_text.html
+++ b/templates/web/fixmybarangay/report/new/councils_text.html
@@ -1,5 +1,5 @@
<p>
The information provided here will be displayed publicly on the site as well as being sent to the
-relevant authority (DPWH, DEPW, or DPS). If you select the Fix Locally category then the
-information will not be sent anywhere.
+relevant authority (DPWH, DEPW, or DPS).
+If you select a "bgy. will fix" category, then your report will be emailed to the barangay team.
</p>
diff --git a/templates/web/fixmybarangay/reports/index.html b/templates/web/fixmybarangay/reports/index.html
index a99878c27..cda1fd6fd 100755
--- a/templates/web/fixmybarangay/reports/index.html
+++ b/templates/web/fixmybarangay/reports/index.html
@@ -7,10 +7,6 @@
[% loc('This is a summary of all reports on this site; select a particular barangay to see the reports sent there.') %]
</p>
-<p>
- [%# (this will change when we have 'body' logic in place, meanwhile: hardcoded) %]
- See also the <a href="/reports/dps">map of DPS reports</a>.
-</p>
</div>
<table cellpadding="3" cellspacing="1" border="0" class="nicetable">
@@ -42,4 +38,21 @@
</tbody>
</table>
+
+<p>
+[%# (this will change when we have 'body' logic in place, meanwhile: hardcoded) %]
+See also the maps of reports submitted to these departments:
+</p>
+<ul>
+<li>
+<a href="/reports/depw" title="Department of Engineering and Public Works">DEPW</a> &mdash; city road maintenance
+</li>
+<li>
+<a href="/reports/dps" title="Department of Public Services">DPS</a> &mdash; streetlight maintenance
+</li>
+<li>
+<a href="/reports/dpwh" title="Department of Public Works and Highways">DPWH</a> &mdash; national road maintenance
+</li>
+</ul>
+</p>
[% INCLUDE 'footer.html', pagefooter = 'yes' %]
diff --git a/templates/web/fixmystreet/header.html b/templates/web/fixmystreet/header.html
index f9c146bc0..85ed2c0e1 100644
--- a/templates/web/fixmystreet/header.html
+++ b/templates/web/fixmystreet/header.html
@@ -22,7 +22,7 @@
<script src="[% start %][% version('/js/modernizr.custom.js') %]" charset="utf-8"></script>
<script src="[% start %][% version('/cobrands/fixmystreet/position_map.js') %]" charset="utf-8"></script>
- [% INCLUDE 'common_header_tags.html', js_override = '/cobrands/fixmystreet/fixmystreet.js', site_title = 'FixMyStreet' %]
+ [% INCLUDE 'common_header_tags.html', js_override = '/cobrands/fixmystreet/fixmystreet.js', site_title = c.cobrand.site_title %]
[% extra_js %]
[% IF c.req.uri.host == 'osm.fixmystreet.com' %]
@@ -32,13 +32,14 @@
[% INCLUDE 'tracking_code.html' %]
</head>
+ [% TRY %][% PROCESS 'set_body_class.html' %][% CATCH file %][% END %]
<body class="[% bodyclass | html IF bodyclass %]">
<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="/" id="site-logo">[% c.cobrand.site_title | html %]</a>
<a href="#main-nav" id="nav-link">Main Navigation</a>
</div>
</header>
diff --git a/templates/web/fixmystreet/report/banner.html b/templates/web/fixmystreet/report/banner.html
index 58712604e..25c9db424 100644
--- a/templates/web/fixmystreet/report/banner.html
+++ b/templates/web/fixmystreet/report/banner.html
@@ -5,7 +5,7 @@
</div>
[% END %]
-[% IF problem.is_open AND date.now - problem.lastupdate_local.epoch > 8 * 7 * 24 * 60 * 60 %]
+[% IF c.cobrand.moniker != 'bromley' AND problem.council != '2482' AND problem.is_open AND date.now - problem.lastupdate_local.epoch > 8 * 7 * 24 * 60 * 60 %]
[% INCLUDE banner, id = 'unknown', text = loc('Unknown') %]
[% END %]
[% IF problem.is_fixed %]
@@ -14,8 +14,8 @@
[% IF problem.is_closed %]
[% INCLUDE banner, id = 'closed', text = loc('Closed') %]
[% END %]
-[% states = [ 'investigating', 'in progress', 'planned' ];
- IF states.grep(problem.state).size %]
+[% states = [ 'investigating', 'in progress', 'planned', 'action scheduled' ];
+ IF c.cobrand.moniker != 'bromley' && states.grep(problem.state).size %]
[% INCLUDE banner, id = 'progress', text = loc('In progress') %]
[% END %]
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 ceba7a6ba..e2e091460 100644
--- a/templates/web/fixmystreet/report/new/fill_in_details_form.html
+++ b/templates/web/fixmystreet/report/new/fill_in_details_form.html
@@ -125,17 +125,7 @@
[%# 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"
- [% IF c.cobrand.moniker == 'fixmybarangay' && c.user.from_body %]
- [%#
- FMB staff reports are anonymous by default; so may_show_name is checked only if explicitly set to 0.
- If the user has not set it (that is, it is null) TemplateToolkit sees an empty string.
- %]
- [% 'checked' IF report.anonymous==0 %]
- [% ELSE %]
- [% 'checked' IF !report.anonymous %]
- [% END %]
- >
+ <input type="checkbox" name="may_show_name" id="form_may_show_name" value="1"[% ' checked' IF report.anonymous==0 OR (c.cobrand.default_show_name AND report.anonymous=='') %]>
<label class="inline" for="form_may_show_name">[% loc('Show my name publicly') %] </label>
</div>
@@ -203,7 +193,7 @@
[%# 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 %]>
+ <input type="checkbox" name="may_show_name" id="form_may_show_name" value="1"[% ' checked' IF report.anonymous==0 OR (c.cobrand.default_show_name AND report.anonymous=='') %]>
<label class="inline" for="form_may_show_name">[% loc('Show my name publicly') %]</label>
</div>
diff --git a/templates/web/fixmystreet/report/update-form.html b/templates/web/fixmystreet/report/update-form.html
index e8115ee00..add176549 100644
--- a/templates/web/fixmystreet/report/update-form.html
+++ b/templates/web/fixmystreet/report/update-form.html
@@ -26,8 +26,10 @@
<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')] ] %]
+ loc('Investigating')], ['action scheduled', loc('Action Scheduled')],
+ ['in progress', loc('In Progress')], ['duplicate', loc('Duplicate')],
+ ['unable to fix', loc('Unable to fix')], ['not responsible', loc('Not Responsible')],
+ ['fixed', loc('Fixed')] ] %]
<option [% 'selected ' IF state.0 == problem.state %] value="[% state.0 %]">[% state.1 %]</option>
[% END %]
</select>
@@ -138,7 +140,7 @@
<input type="text" [% IF problem.bodies_str == '2482' %]class="validName" [% END %]name="name" id="form_name" value="[% update.name || c.user.name | html %]" placeholder="[% loc('Your name') %]">
<div class="checkbox-group">
- <input type="checkbox" name="may_show_name" id="form_may_show_name" value="1"[% ' checked' UNLESS update.anonymous %]>
+ <input type="checkbox" name="may_show_name" id="form_may_show_name" value="1"[% ' checked' IF update.anonymous==0 OR (c.cobrand.default_show_name AND update.anonymous=='') %]>
<label class="inline" for="form_may_show_name">[% loc('Show my name publicly') %]</label>
</div>
<div class="checkbox-group">
diff --git a/templates/web/oxfordshire/around/intro.html b/templates/web/oxfordshire/around/intro.html
new file mode 100644
index 000000000..81b2569f6
--- /dev/null
+++ b/templates/web/oxfordshire/around/intro.html
@@ -0,0 +1 @@
+ <h1 class="main">Reporting a problem in Oxfordshire</h1>
diff --git a/templates/web/oxfordshire/faq/faq-en-gb.html b/templates/web/oxfordshire/faq/faq-en-gb.html
new file mode 100755
index 000000000..9361d5647
--- /dev/null
+++ b/templates/web/oxfordshire/faq/faq-en-gb.html
@@ -0,0 +1,232 @@
+[% INCLUDE 'header.html', title => loc('Frequently Asked Questions'), bodyclass => 'twothirdswidthpage' %]
+
+<div class="sticky-sidebar">
+ <aside>
+ <ul class="plain-list">
+ <li><a href="#faq">Frequently Asked Questions</a></li>
+ <li><a href="#practical">Practical Questions</a></li>
+ <li><a href="#organisation">Organisation Questions</a></li>
+ <li><a href="/privacy">Privacy and cookies</a></li>
+ <li><a href="/contact">Contact FixMyStreet</a></li>
+ </ul>
+ </aside>
+</div>
+
+<h1><a name="faq"></a>Frequently Asked Questions</h1>
+ <dl>
+ <dt>What is FixMyStreet?</dt>
+ <dd>
+ <p>
+ FixMyStreet is a site to help people report, view,
+or discuss local problems they&rsquo;ve found to their local council by
+simply locating them on a map. It launched in early February
+2007.
+ </p>
+ <p>
+ We have now integrated with the Oxfordshire County Council website
+ to make it easier to report highways faults.
+ </p>
+ </dd>
+
+ <dt>What sort of problems should I report with FixMyStreet?</dt>
+ <dd>
+ <p>
+ FixMyStreet is primarily for reporting things which are
+<strong>broken or dirty or damaged or dumped, and need fixing, cleaning
+or clearing</strong>, such as:
+ </p>
+
+ <ul><li>Abandoned vehicles
+ <li>Dog Fouling
+ <li>Flyposting or graffiti
+ <li>Flytipping or litter
+ <li>Streetcleaning, such as broken glass in a cycle lane
+ <li>Unlit lamposts
+ <li>Potholes
+ </ul>
+ </dd>
+
+ <dt>What isn&rsquo;t FixMyStreet for?</dt>
+ <dd>
+ <p>
+ FixMyStreet is not a way of getting in touch with the 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.
+ </p>
+ <div style="margin-left:1.5em;">
+ <p>
+ <strong>You will need to contact the county council directly for</strong>:
+ </p>
+ <ul>
+ <li>Any urgent or emergency problems
+ <li>Complaining about the council
+ <li>Proposals for speed bumps/ CCTV/ pedestrian crossings/ new road layouts/ etc.
+ </ul>
+ <p>
+ <strong>You will need to contact your district council directly for problems such as:</strong>:
+ </p>
+ <ul>
+ <li>Anti-social behaviour
+ <li>Noise pollution or barking dogs
+ <li>Fires and smoke/smell pollution
+ <li>Missing wheelie bins or recycling boxes or missed rubbish collections
+ <li>Proposals for speed bumps/ CCTV/ pedestrian crossings/ new road layouts/ etc.
+ <li>Complaining about your neighbours
+ <li>Joy riding, drug taking, animal cruelty, or other criminal activity
+ </ul>
+ </div>
+ </dd>
+ <dt><a name="pothole"></a>Should I report a pothole on this site, or call?</dt>
+ <dd>
+ <p><strong>You must call us on 0845&nbsp;310&nbsp;1111 to report the pothole if it is:</strong></p>
+ <ul>
+ <li>The depth of a milk bottle
+ <li>The size of a dustbin lid
+ <li>The depth of a tennis ball, size of a dinner plate <strong>and</strong> on a busy carriageway
+ <li>The depth of a coke can on a pathway or busy carriageway
+ <li>The depth of a coke can <strong>and</strong> size of a dinner plate on a quiet carriageway
+ </ul>
+ </dd>
+
+ <dt>How do I use the site?</dt>
+ <dd>After entering a postcode or location, you are presented
+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 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, and
+then together lobby the council to fix it, or fix it directly yourselves.</dd>
+
+ <dt>What updates will I receive?</dt>
+ <dd>If you sign up to receive updates you will receive an email to acknowledge the report, an email when the problem is assigned to a representative to be inspected, one if the problem is either referred to the appropriate organisation and one when it is fixed.</dd>
+
+ <dt>Is it free?</dt>
+ <dd>The site is free to use, yes. FixMyStreet is run
+by a registered charity, though, so if you want to make a contribution, <a
+href="https://secure.mysociety.org/donate/">please do</a>.</dd>
+
+ <dt>Can I use FixMyStreet on my mobile?</dt>
+ <dd>
+ <p>The FixMyStreet website should work on your mobile phone, adapting to
+ the size of your screen automatically. We plan to release updated native
+ apps in the near future.
+ <ul>
+ <li><em>iPhone:</em> Our basic app from 2008 is available for download
+ on the App Store:
+ <a href="http://itunes.apple.com/gb/app/fixmystreet/id297456545">FixMyStreet</a>,
+ <li><em>Android:</em> A volunteer, Anna Powell-Smith, has written an app
+ available from the
+ <a href="https://market.android.com/details?id=com.android.fixmystreet">Android Market</a>.
+ <li><em>Nokia:</em> A volunteer, Thomas Forth, has written an app available from the
+ <a href="http://store.ovi.com/content/107557">Ovi Store</a>.
+ </ul>
+ </dd>
+
+ </dl>
+
+ <h2><a name="practical"></a>Practical Questions</h2>
+ <p>
+ <em>Taken from the national website <a href="http://www.fixmystreet.com">www.fixmystreet.com</a></em>
+ </p>
+ <dl>
+ <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
+problems or updates which we consider to be inappropriate upon being informed
+by a user of the site.</dd>
+
+ <dt>Why does the site use kilometres for measurements?</dt>
+ <dd>Thanks for asking politely &ndash; we never quite understand why some of the rudest
+ emails we receive are on this topic. 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 FixMyStreet locally focused, so restrict the ability to
+ move radically between areas. The map on Your Reports will let you see all
+ the reports you&rsquo;ve made, wherever they are. If you&rsquo;re from the
+ council then the emailed version of the problem report also contains the
+ closest road and postcode to the pin on the map.</dd>
+
+ <dt>This site is great – why aren&rsquo;t you better publicised?</dt>
+ <dd>As a tiny charity we simply don&rsquo;t have a publicity budget, and we
+ rely on word of mouth to advertise the site. We have a whole <a
+ href="posters/">array of posters, flyers and badges</a> if you&rsquo;d like
+ to publicise us on the web or in your local area, and why not write to your
+ local paper to let them know about us?</dd> </dl>
+
+ <h2><a name="organisation"></a>Organisation Questions</h2>
+ <p>
+ <em>Taken from the national website <a href="http://www.fixmystreet.com">www.fixmystreet.com</a></em>
+ </p>
+ <dl>
+ <dt>Who built FixMyStreet?</dt>
+ <dd>This site 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.com</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><img src="/i/moj.png" align="right" alt="Ministry of Justice" hspace="10">Who pays for it?</dt>
+ <dd>FixMyStreet was originally paid for via the Department for
+ Constitutional Affairs Innovations Fund. It is now funded by a variety of means, from commercial
+ work to <a href="http://www.mysociety.org/donate/">donations</a>.</dd>
+ <dt><a name="nfi"></a>Wasn&rsquo;t this site called Neighbourhood Fix-It?</dt>
+ <dd>Yes, we changed the name mid June 2007. We decided
+Neighbourhood Fix-It was a bit of a mouthful, hard to spell, and hard to publicise (does the URL have a dash in it or not?). The domain FixMyStreet became available, and everyone liked the name.</dd>
+ <dt>Do you need any help with the project?</dt>
+ <dd>Yes, we can use help in all sorts of ways, technical or
+non-technical. Please see our <a
+href="http://www.mysociety.org/helpus/">Get Involved page</a>.</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>
+<dt>I&rsquo;d prefer code in a different language?</dt>
+<dd>
+VisibleGovernment.ca wrote their own code for
+<a href="http://www.fixmystreet.ca/">http://www.fixmystreet.ca/</a>, which is
+written in GeoDjango and available under an MIT licence at <a
+href="http://github.com/visiblegovernment/django-fixmystreet/tree/master">github</a>.
+Or <a href="http://www.fixmystreet.org.nz/">FixMyStreet.org.nz</a> is written in
+Drupal.
+</p>
+</dd>
+ <dt>People build things, not organisations. Who <em>actually</em> built it?</dt>
+ <dd>Matthew Somerville and Francis Irving wrote the site,
+Chris Lightfoot wrote the tileserver and map cutter, Richard Pope created
+our pins, Deborah Kerr keeps things up-to-date and does user support,
+Ayesha Garrett designed our posters, and Tom Steinberg managed it all.
+
+Thanks also to
+<a href="http://www.ordnancesurvey.co.uk">Ordnance Survey</a> (for the maps,
+UK postcodes, and UK addresses &ndash; data &copy; Crown copyright, all
+rights reserved, Ministry of Justice 100037819&nbsp;2008),
+Yahoo! for their BSD-licensed JavaScript libraries, the entire free software
+community (this particular project was brought to you by Perl, PostgreSQL,
+and the number 161.290) and <a
+href="http://www.bytemark.co.uk/">Bytemark</a> (who kindly host all
+our servers).
+
+Let us know if we&rsquo;ve missed anyone.</dd>
+ </dl>
+[% INCLUDE 'footer.html' pagefooter = 'yes' %]
diff --git a/templates/web/oxfordshire/footer.html b/templates/web/oxfordshire/footer.html
new file mode 100644
index 000000000..cfca706c8
--- /dev/null
+++ b/templates/web/oxfordshire/footer.html
@@ -0,0 +1,51 @@
+ [% IF pagefooter %]
+ <footer role="content-info">
+ <p><a href="/privacy">Privacy and cookies</a></p>
+ </footer>
+ [% END %]
+ </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 id="mysoc-logo" href="http://www.fixmystreet.com/">Powered by <img src="/cobrands/oxfordshire/images/fms-logo-105x20.png" alt="FixMyStreet"></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' %]span[% ELSE %]a href="/reports"[% 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>
+
+<!-- [% INCLUDE 'debug_footer.html' %] -->
+ </div> <!-- .wrapper -->
+ <div id="oxford-footer" class="desk-only">
+ <address>
+ <strong>Oxfordshire County Council</strong><br>
+ <a href="http://www.oxfordshire.gov.uk/cms/public-site/contact-oxfordshire-county-council" title="Contac the council">Contact the council</a>
+ </address>
+ <ul><!-- use | between items -->
+ <li>
+ <a href="/contact" title="Contact the FixMyStreet team">Contact</a> |
+ </li>
+ <li class="powered-by-fms">
+ <a href="http://www.fixmystreet.com/">Powered&nbsp;by&nbsp;<img src="/cobrands/oxfordshire/images/fms-logo-inverse.png" alt="FixMyStreet"></a>
+ </li>
+ </ul>
+ </div>
+</div> <!-- oxford-wrapper -->
+</body>
+</html>
diff --git a/templates/web/oxfordshire/header.html b/templates/web/oxfordshire/header.html
new file mode 100644
index 000000000..6c338452a
--- /dev/null
+++ b/templates/web/oxfordshire/header.html
@@ -0,0 +1,94 @@
+<!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">
+
+[% SET start = c.config.ADMIN_BASE_URL IF admin %]
+
+ <link rel="stylesheet" href="[% start %][% version('/cobrands/' _ c.cobrand.moniker _ '/base.css') %]">
+ <link rel="stylesheet" href="[% start %][% version('/cobrands/' _ c.cobrand.moniker _ '/layout.css') %]" media="(min-width:48em)">
+ [% extra_css %]
+ <!--[if (lt IE 9) & (!IEMobile)]>
+ <link rel="stylesheet" href="[% start %][% version('/cobrands/' _ c.cobrand.moniker _ '/layout.css') %]">
+ <![endif]-->
+
+ <script src="[% start %][% version('/js/modernizr.custom.js') %]" charset="utf-8"></script>
+ <script src="[% start %][% version('/cobrands/oxfordshire/position_map.js') %]" charset="utf-8"></script>
+ [% INCLUDE 'common_header_tags.html', js_override = '/cobrands/fixmystreet/fixmystreet.js', site_title = 'FixMyStreet' %]
+ [% 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' %]
+
+ </head>
+ <body class="[% bodyclass | html IF bodyclass %]">
+<div id="oxford-wrapper">
+ <div id="oxford-header" class="desk-only">
+ <a href="http://www.oxfordshire.gov.uk/" title="Home" class="logo">Oxfordshire County Council<span></span></a>
+ <span id="oxford-links">
+ <a href="http://www.oxfordshire.gov.uk/" title="">Oxfordshire County Council home</a>|<a href="/" title="">FixMyStreet</a>
+ </span>
+ <div style="clear:both"></div>
+ <span class="header"><a href="/">FixMyStreet</a></span>
+ <div class="oxford-user">
+ <p>
+ [% IF c.user_exists %]
+ [% tprintf(loc('Hi %s'), c.user.name || c.user.email) %]
+ <a href="/auth/sign_out">[% loc('sign out') %]</a>
+ [% END %]
+ </p>
+ </div>
+ </div> <!-- end of oxford header -->
+ <div id="oxford-main-menu" class="desk-only">
+ <ul class="tabs">
+ <li class="home first"><[% 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/Oxfordshire' %]span[% ELSE %]a href="/reports/Oxfordshire"[% 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 class="wrapper">
+
+ <div class="table-cell">
+ <header id="site-header" role="banner">
+ <div class="container">
+ <a href="/" id="site-logo">Oxfordshire FixMyStreet</a>
+ <a href="#main-nav" id="nav-link">Main Navigation</a>
+ </div>
+ </header>
+
+ <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>
+ [% ELSE %]
+ <!-- <a href="/auth">[% loc('Sign in') %]</a> -->
+ [% END %]
+ </div>
+
+ [% pre_container_extra %]
+
+ <div class="container">
+ <div class="content[% " $mainclass" | html IF mainclass %]" role="main">
+
+ <!-- [% INCLUDE 'debug_header.html' %] -->
diff --git a/templates/web/oxfordshire/report/new/councils_text_all.html b/templates/web/oxfordshire/report/new/councils_text_all.html
new file mode 100644
index 000000000..e71a400ac
--- /dev/null
+++ b/templates/web/oxfordshire/report/new/councils_text_all.html
@@ -0,0 +1,18 @@
+<p>You can use this form to report a problem or to make an enquiry about roads
+and pavements in your area. All the information you provide here will be sent
+to <strong>[% all_council_names.join( '</strong> or <strong>' ) %]</strong>.
+The subject and details of the problem will be public, plus your name if you
+give us permission. If you report a fault on a road that is not owned by
+Oxfordshire County Council we will pass the report on to the relevant body.
+
+<p>Our opening hours are 8.30 to 5, Monday to Thursday and 8.30 to 4 on
+Fridays. Please <strong>do not</strong> use this form for reporting
+<strong>emergencies and urgent</strong> problems. You should report these by
+contacting 0845 310 11 11. If your enquiry is related to Highways and is
+outside of our opening hours and cannot wait, please contact Thames Valley
+Police on 101.</p>
+
+<p>Please use <a href="/faq#pothole" target="_blank">our chart</a> to determine
+the size of any pot holes being reported and whether to submit a report using
+this online form or by telephone.</p>
+
diff --git a/templates/web/oxfordshire/report/new/fill_in_details_text.html b/templates/web/oxfordshire/report/new/fill_in_details_text.html
new file mode 100644
index 000000000..065005956
--- /dev/null
+++ b/templates/web/oxfordshire/report/new/fill_in_details_text.html
@@ -0,0 +1,6 @@
+Oxfordshire County Council won’t be able to help unless you leave as much
+detail as you can. Please describe the exact location of the problem (e.g. in
+the carriageway), what it is, how long it has been there, a description and a
+photo of the problem if you have one. Please be aware that you can only attach
+one picture so ensure that you provide a picture that clearly shows the
+location not just the fault.
diff --git a/templates/web/oxfordshire/report/new/notes.html b/templates/web/oxfordshire/report/new/notes.html
new file mode 100644
index 000000000..e03fd8644
--- /dev/null
+++ b/templates/web/oxfordshire/report/new/notes.html
@@ -0,0 +1,10 @@
+<p>[% loc("Please note:") %]</p>
+
+<ul class="plain-list">
+ <li>[% loc("We will only use your personal information in accordance with our <a href=\"/privacy\">privacy policy.</a>") %]</li>
+ <li>[% loc("Please be polite, concise and to the point.") %]</li>
+ <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>Remember that FixMyStreet is primarily for reporting physical problems that can be fixed. Remember that you can contact Oxfordshire County Council for additional issues that are not covered on this reporting facility.</li>
+</ul>
+
diff --git a/templates/web/seesomething/admin/footer.html b/templates/web/seesomething/admin/footer.html
new file mode 100644
index 000000000..bdd42e2e4
--- /dev/null
+++ b/templates/web/seesomething/admin/footer.html
@@ -0,0 +1,7 @@
+ </div><!-- .content role=main -->
+ </div><!-- .container -->
+ </div><!-- .table-cell -->
+<!-- [% INCLUDE 'debug_footer.html' %] -->
+ </div> <!-- .wrapper -->
+</body>
+</html>
diff --git a/templates/web/seesomething/admin/header.html b/templates/web/seesomething/admin/header.html
new file mode 100644
index 000000000..40bea25bf
--- /dev/null
+++ b/templates/web/seesomething/admin/header.html
@@ -0,0 +1,2 @@
+[% INCLUDE 'header.html' admin = 1, bodyclass = 'admin fullwidthpage' %]
+ <h1>[% title %]</h1>
diff --git a/templates/web/seesomething/admin/stats.html b/templates/web/seesomething/admin/stats.html
new file mode 100644
index 000000000..713c3fb6d
--- /dev/null
+++ b/templates/web/seesomething/admin/stats.html
@@ -0,0 +1,63 @@
+[% INCLUDE 'admin/header.html' title=loc('Reports') %]
+[% PROCESS 'admin/report_blocks.html' %]
+
+[% BLOCK options %]
+ [% FOR option IN option_list %]
+ <option value="[% option %]"[% ' selected' IF selected == option %]>[% option %]</opytion>
+ [% END %]
+[% END %]
+
+<form method="post" action="[% c.uri_for('stats') %]" enctype="application/x-www-form-urlencoded" accept-charset="utf-8" id="filter-form">
+ <label for="form_category">Transport Type: </label>
+ <select name="category" id="form_category">
+ <option value="">Select</option>
+ [% PROCESS options, option_list = [ 'Bus', 'Metro', 'Train' ], selected = category %]
+ </select>
+
+ <label for="form_subcategory">Incident Type: </label>
+ <select name="subcategory" id="form_subcategory">
+ <option value="">Select</option>
+ [% PROCESS options, option_list = ['Smoking', 'Drugs', 'Anti-social Behaviour', 'Loud Music', 'Damage', 'Feet on Seats', 'Other'], selected = subcategory %]
+ </select>
+
+ <label for="form_service">Device: </label>
+ <select name="service" id="form_service">
+ <option value="">Select</option>
+ [% PROCESS options, option_list = [ 'Android', 'iPhone' ], selected = service %]
+ </select>
+
+ <input type="submit" name="getcounts" size="30" id="getcounts" value="Look Up" />
+</form>
+
+[% IF pager.total_entries == 0 %]
+<p align="center">
+No Results found
+</p>
+[% ELSE %]
+<table class="admin-report">
+ <thead>
+ <tr>
+ <th>Device</th>
+ <th>Transport Category</th>
+ <th>Incident Category</th>
+ <th>Area</th>
+ <th>Submitted</th>
+ </tr>
+ </thead>
+ <tbody>
+ [%- WHILE (report = reports.next) %]
+ <tr>
+ <td>[% report.service || 'Other' %]</td>
+ <td>[% report.category %]</td>
+ <td class="nowrap">[% report.subcategory %]</td>
+ <td class="nowrap">[% council_details.${report.council}.name %]</td>
+ <td class="nowrap">[% PROCESS format_time time=report.confirmed %]</td>
+ </tr>
+ [%- END %]
+ </tbody>
+</table>
+[% END %]
+
+[% INCLUDE 'pagination.html', param = 'p' %]
+
+[% INCLUDE 'admin/footer.html' %]
diff --git a/templates/web/seesomething/around/around_index.html b/templates/web/seesomething/around/around_index.html
new file mode 100644
index 000000000..a143e90a2
--- /dev/null
+++ b/templates/web/seesomething/around/around_index.html
@@ -0,0 +1,24 @@
+[% INCLUDE 'header.html', title => loc('Reporting a problem'), bodyclass = 'mappage' %]
+
+<form action="[% c.uri_for('/around') %]" method="get" name="mapForm" id="mapForm">
+ <div id="side-form">
+ <div id="report-a-problem-main">
+ [% INCLUDE 'around/postcode_form.html' %]
+
+ [% IF location_error %]
+ <p class="error">[% location_error %]</p>
+ [% END %]
+
+ [% IF possible_location_matches %]
+ <p>[% loc('We found more than one match for that location. We show up to ten matches, please try a different search if yours is not here.') %]</p>
+ <ul class="pc_alternatives">
+ [% FOREACH match IN possible_location_matches %]
+ <li><a href="/around?latitude=[% match.latitude | uri %];longitude=[% match.longitude | uri %]">[% match.address | html %]</a></li>
+ [% END %]
+ </ul>
+ [% END %]
+ </div>
+ </div>
+</form>
+
+[% INCLUDE 'footer.html' %]
diff --git a/templates/web/seesomething/around/display_location.html b/templates/web/seesomething/around/display_location.html
new file mode 100644
index 000000000..e90d1aa0e
--- /dev/null
+++ b/templates/web/seesomething/around/display_location.html
@@ -0,0 +1,49 @@
+[%
+
+ url_skip = c.uri_for(
+ '/report/new',
+ {
+ pc => pc
+ latitude => short_latitude,
+ longitude => short_longitude,
+ skipped => 1,
+ }
+ );
+
+ PROCESS "maps/${map.type}.html";
+
+ INCLUDE 'header.html',
+ title => loc('Viewing a location')
+ bodyclass => 'mappage',
+ robots => 'noindex,nofollow';
+
+%]
+
+<form action="[% c.uri_for('/report/new') %]" method="post" name="mapForm" id="mapForm" enctype="multipart/form-data" class="validate">
+ [% IF c.req.params.map_override %]
+ <input type="hidden" name="map_override" value="[% c.req.params.map_override | html %]">
+ [% END %]
+ <input type="hidden" name="pc" value="[% pc | html %]">
+
+ <input type="hidden" name="latitude" id="fixmystreet.latitude" value="[% short_latitude | html %]">
+ <input type="hidden" name="longitude" id="fixmystreet.longitude" value="[% short_longitude | html %]">
+
+ [% map_html %]
+
+ </div>
+
+ <div id="side">
+ [% INCLUDE 'around/_report_banner.html' %]
+ </div>
+
+ <div style="display:none" id="side-form">
+ [% INCLUDE "report/new/fill_in_details_form.html"
+ js = 1,
+ report.used_map = 1
+ report.name = c.user.name
+ %]
+ </div>
+
+</form>
+
+[% INCLUDE 'footer.html' %]
diff --git a/templates/web/seesomething/around/postcode_form.html b/templates/web/seesomething/around/postcode_form.html
new file mode 100644
index 000000000..56fcdca97
--- /dev/null
+++ b/templates/web/seesomething/around/postcode_form.html
@@ -0,0 +1,17 @@
+<div id="front-main">
+ <div id="front-main-container">
+ [%
+ question = c.cobrand.enter_postcode_text || loc('Enter a nearby street name and area');
+ %]
+
+ <label for="pc">[% question %]:</label>
+ <div>
+ <input type="text" name="pc" value="[% pc | html %]" 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>
+
+ [% IF partial_token %]
+ <input type="hidden" name="partial" value="[% partial_token.token %]">
+ [% END %]
+ </div>
+</div>
diff --git a/templates/web/seesomething/auth/general.html b/templates/web/seesomething/auth/general.html
new file mode 100644
index 000000000..4fe2829d3
--- /dev/null
+++ b/templates/web/seesomething/auth/general.html
@@ -0,0 +1,46 @@
+[% INCLUDE 'header.html', title = loc('Sign in or create an account') %]
+
+<h1>[% loc('Sign in') %]</h1>
+
+<form action="[% c.uri_for() %]" method="post" name="general_auth" class="validate">
+ <fieldset>
+ <input type="hidden" name="r" value="[% c.req.params.r | html %]">
+
+ [% IF email_error;
+
+ # other keys include fqdn, mxcheck if you'd like to write a custom error message
+
+ errors = {
+ missing => loc('Please enter your email'),
+ other => loc('Please check your email address is correct')
+ };
+
+ loc_email_error = errors.$email_error || errors.other;
+ END %]
+ <label class="n" for="email">[% loc('Email') %]</label>
+ [% IF loc_email_error %]
+ <div class="form-error">[% loc_email_error %]</div>
+ [% ELSIF sign_in_error %]
+ <div class="form-error">[% loc('There was a problem with your email/password combination. If you cannot remember your password, or do not have one, please fill in the &lsquo;sign in by email&rsquo; section of the form.') %]</div>
+ [% END %]
+ <input type="email" class="required email" id="email" name="email" value="[% email | html %]" placeholder="[% loc('Your email address') %]">
+
+ <div class="form-txt-submit-box">
+ <label class="n" for="password_sign_in">Password</label>
+ <input type="password" name="password_sign_in" id="password_sign_in" value="" placeholder="[% loc('Your password') %]">
+ </div>
+
+ <div class="form-txt-submit-box">
+ <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 class="form-txt-submit-box">
+ <input class="green-btn" type="submit" name="sign_in" value="[% loc('Sign in') %]">
+ </div>
+
+ </fieldset>
+</form>
+
+
+[% INCLUDE 'footer.html' %]
diff --git a/templates/web/seesomething/auth/sign_out.html b/templates/web/seesomething/auth/sign_out.html
new file mode 100644
index 000000000..ef1d11b58
--- /dev/null
+++ b/templates/web/seesomething/auth/sign_out.html
@@ -0,0 +1,7 @@
+[% 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', { r => 'admin/stats' } ) %]">sign in again</a></p>
+
+[% INCLUDE 'footer.html' %]
diff --git a/templates/web/seesomething/footer.html b/templates/web/seesomething/footer.html
new file mode 100644
index 000000000..95297f33d
--- /dev/null
+++ b/templates/web/seesomething/footer.html
@@ -0,0 +1,22 @@
+ </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="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 == '/faq' %]span[% ELSE %]a href="/faq"[% END
+ %]>[% loc("Help") %]</[% c.req.uri.path == '/faq' ? 'span' : 'a' %]></li>
+ </ul>
+ </div>
+ </div>
+ </div>
+
+<!-- [% INCLUDE 'debug_footer.html' %] -->
+ </div> <!-- .wrapper -->
+</body>
+</html>
diff --git a/templates/web/seesomething/front/stats.html b/templates/web/seesomething/front/stats.html
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/templates/web/seesomething/front/stats.html
diff --git a/templates/web/seesomething/front/tips.html b/templates/web/seesomething/front/tips.html
new file mode 100644
index 000000000..34712656d
--- /dev/null
+++ b/templates/web/seesomething/front/tips.html
@@ -0,0 +1,3 @@
+ <p>
+ If you are unsure about where the incident took place as you where on a moving train or bus then use the location of the start of your journey and mention which bus or train you where on in your report.
+ </p>
diff --git a/templates/web/seesomething/index.html b/templates/web/seesomething/index.html
new file mode 100644
index 000000000..cccd15709
--- /dev/null
+++ b/templates/web/seesomething/index.html
@@ -0,0 +1,43 @@
+[%# Assumes fixmystreet cobrand is using FMS map template - for bonus points preload all the right map elements. %]
+
+[% PROCESS "maps/fms.html" %]
+[% INCLUDE 'header.html', title = '', bodyclass = 'mappage' %]
+
+<form action="[% c.uri_for('/around') %]" method="get" name="mapForm" id="mapForm">
+<script type="text/javascript">
+var fixmystreet = {
+ 'page': '',
+ 'latitude': 52.505241,
+ 'longitude': -1.815285,
+ 'zoom': 3,
+ 'numZoomLevels': 5,
+ 'zoomOffset': 13,
+ 'map_type': ""
+
+}
+</script>
+<div id="map_box">
+ <div id="map"></div>
+ </div>
+
+ <div id="side-form">
+ <div id="report-a-problem-main">
+ [% form = PROCESS 'around/postcode_form.html' %]
+ [% form %]
+
+ [% IF error %]
+ <p class="form-error">[% error %]</p>
+ [% END %]
+
+ <div class="tablewrapper">
+ <div id="front-howto">
+ [% INCLUDE 'index-steps.html' %]
+ </div>
+
+ </div>
+
+ </div>
+ </div>
+</form>
+
+[% INCLUDE 'footer.html' pagefooter = 'yes' %]
diff --git a/templates/web/seesomething/js/translation_strings.html b/templates/web/seesomething/js/translation_strings.html
new file mode 100644
index 000000000..0ae40bf97
--- /dev/null
+++ b/templates/web/seesomething/js/translation_strings.html
@@ -0,0 +1,15 @@
+ translation_strings = {
+ detail: '[% loc('Please enter some details') | replace("'", "\\'") %]',
+ name: {
+ validName: '[% loc('Please enter your full name, councils need this information – if you do not wish your name to be shown on the site, untick the box below') | replace("'", "\\'") %]'
+ },
+ category: '[% loc('Please choose a transport category') | replace("'", "\\'") %]',
+ subcategory: '[% loc('Please choose an incident category') | replace("'", "\\'") %]',
+ rznvy: {
+ required: '[% loc('Please enter your email') | replace("'", "\\'") %]',
+ email: '[% loc('Please enter a valid email') | replace("'", "\\'") %]'
+ },
+ email: {
+ email: '[% loc('Please enter a valid email') | replace("'", "\\'") %]'
+ }
+ };
diff --git a/templates/web/seesomething/js/validation_rules.html b/templates/web/seesomething/js/validation_rules.html
new file mode 100644
index 000000000..cef5fce7e
--- /dev/null
+++ b/templates/web/seesomething/js/validation_rules.html
@@ -0,0 +1,13 @@
+ validation_rules = {
+ detail: { required: true },
+ category: { required: true },
+ subcategory: { required: true }
+ };
+
+ $(function(){
+ $('#submit_noname').click( function(e) {
+ $('#form_category').addClass('required validCategory').removeClass('valid');
+ $('#form_subcategory').addClass('required validCategory').removeClass('valid');
+ });
+ });
+
diff --git a/templates/web/seesomething/report/display.html b/templates/web/seesomething/report/display.html
new file mode 100644
index 000000000..93b0048a2
--- /dev/null
+++ b/templates/web/seesomething/report/display.html
@@ -0,0 +1,9 @@
+[%
+ INCLUDE 'header.html'
+ robots = 'index, nofollow',
+ bobyclass = 'mappage';
+%]
+
+Reports to this site are private
+
+[% INCLUDE 'footer.html' %]
diff --git a/templates/web/seesomething/report/new/category.html b/templates/web/seesomething/report/new/category.html
new file mode 100644
index 000000000..26d750b52
--- /dev/null
+++ b/templates/web/seesomething/report/new/category.html
@@ -0,0 +1,14 @@
+[% FILTER collapse %]
+[% IF category_options.size %]
+ [% IF category;
+ category = category | lower;
+ END; %]
+ <label for='form_category' class="select">[% category_label | html %]</label>
+ <select name='category' data-theme="c" id='form_category'[% ' onchange="form_category_onchange()"' IF category_extras.size %]>
+ [% FOREACH cat_op IN category_options %]
+ [% cat_op_lc = cat_op | lower %]
+ <option value='[% cat_op | html %]'[% ' selected' IF report.category == cat_op || category == cat_op_lc %]>[% cat_op | html %]</option>
+ [% END %]
+ </select>
+[% END %]
+[% END -%]
diff --git a/templates/web/seesomething/report/new/fill_in_details_form.html b/templates/web/seesomething/report/new/fill_in_details_form.html
new file mode 100644
index 000000000..659fadd04
--- /dev/null
+++ b/templates/web/seesomething/report/new/fill_in_details_form.html
@@ -0,0 +1,104 @@
+<div id="report-a-problem-main">
+ <p>Click and drag on the map to reposition the pin.</p>
+ <h1>[% loc('Reporting a problem') %]</h1>
+
+
+ [% 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_detail">[% loc('Details') %]</label>
+ [% 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('Transport 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 %]
+
+ <div id="form_subcategory_row">
+ <label for="form_subcategory">[% loc('Incident Category') %]</label>
+ <select name="subcategory" id="form_subcategory" required>
+ <option value="">-- Pick a category --</option>
+ <option value="Smoking/other drugs">Smoking/other drugs</option>
+ <option value="Drugs">Drugs</option>
+ <option value="Anti-social behaviour">Anti-social behaviour</option>
+ <option value="Loud music">Loud music</option>
+ <option value="Damage">Damage</option>
+ <option value="Feet on seats">Feet on seats</option>
+ <option value="Other">Other</option>
+ </select>
+ </div>
+
+ [% IF c.cobrand.allow_photo_upload %]
+ <label for="form_photo">[% loc('Photo') %]</label>
+ [% 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 %]
+
+ [% IF field_errors.photo %]
+ <p class='form-error'>[% field_errors.photo %]</p>
+ [% END %]
+ <input type="file" name="photo" id="form_photo">
+ [% END %]
+
+ <h2>Personal Details:</h2>
+
+ <label for="form_name">[% loc('Name (optional)') %]</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') %]">
+
+ <label for="form_email">[% loc('Your email (optional)') %]</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') %]">
+
+
+
+ <label class="" 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_noname" name="submit_noname" value="[% loc('Submit') %]">
+ </div>
+
+ </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/seesomething/report_created.html b/templates/web/seesomething/report_created.html
new file mode 100644
index 000000000..4a11d14b4
--- /dev/null
+++ b/templates/web/seesomething/report_created.html
@@ -0,0 +1,29 @@
+[%
+
+ IF report.used_map;
+ PROCESS "maps/${map.type}.html";
+ END;
+
+ INCLUDE 'header.html',
+ title => loc('Report created')
+ bodyclass => 'mappage',
+ robots => 'noindex,nofollow';
+%]
+
+
+ [% IF report.used_map %]
+ [% map_html %]
+
+ </div>
+ [% END %]
+
+ <div id="side">
+<div id="report-a-problem-main">
+ <h1>Complete</h1>
+ <p>Your report has been sent. If you included contact details we may be in touch to follow up or request more details.</p>
+ <p>Thank you for saying something and making our transport safer.</p>
+ <p><img src="../cobrands/seesomething/images/btp-wmp-logos.png" alt="British Transport Police and the West Midlands Police" width="271" height="116"></p>
+</div>
+ </div>
+
+[% INCLUDE 'footer.html' %]
diff --git a/templates/web/seesomething/set_body_class.html b/templates/web/seesomething/set_body_class.html
new file mode 100644
index 000000000..b613706f2
--- /dev/null
+++ b/templates/web/seesomething/set_body_class.html
@@ -0,0 +1 @@
+[% bodyclass = ( bodyclass ? bodyclass : 'mappage' ) %]
diff --git a/templates/web/southampton/front/news.html b/templates/web/southampton/front/news.html
new file mode 100644
index 000000000..79d51542c
--- /dev/null
+++ b/templates/web/southampton/front/news.html
@@ -0,0 +1,9 @@
+<div class="news">
+<p>Fix My Street is for reporting non-urgent, local problems like graffiti, fly
+tipping, or broken paving slabs; reports will be reviewed within 48 working
+hours.</p>
+
+<p>If you are reporting an urgent or dangerous matter, for example a fallen
+tree or a very deep pot hole that may cause damage, please contact us
+directly on 023 8083 3008</p>
+</div>
diff --git a/templates/web/stevenage/around/intro.html b/templates/web/stevenage/around/intro.html
index 488b587da..0298ee6e6 100644
--- a/templates/web/stevenage/around/intro.html
+++ b/templates/web/stevenage/around/intro.html
@@ -1,2 +1,2 @@
<h1>[% loc('Report, view, or discuss local problems') %]</h1>
- <h2>(like Graffiti, Fly Tipping and Abandoned Vehicles)</h2>
+ <h2>(Like Graffiti, Fly Tipping, Refuse &amp; Recycling and Abandoned Vehicles)</h2>
diff --git a/web/cobrands/fixmybarangay/_colours.scss b/web/cobrands/fixmybarangay/_colours.scss
index 2e9b1affa..bbf419bca 100644
--- a/web/cobrands/fixmybarangay/_colours.scss
+++ b/web/cobrands/fixmybarangay/_colours.scss
@@ -8,3 +8,7 @@ $col_click_map: #00BD08;
$col_click_map_dark: #4B8304;
$col_fixed_label: #00BD08;
$col_fixed_label_dark: #4B8304;
+
+$fmb_base_blue: #046AAA;
+$fmb_dark_blue: #084E7A;
+$fmb_tab_yellow: #FFD000; \ No newline at end of file
diff --git a/web/cobrands/fixmybarangay/base.scss b/web/cobrands/fixmybarangay/base.scss
index 7257f63cd..6f31f223d 100644
--- a/web/cobrands/fixmybarangay/base.scss
+++ b/web/cobrands/fixmybarangay/base.scss
@@ -27,9 +27,10 @@ input.yellow-btn{
}
body.mappage .nav-wrapper div.nav-wrapper-2 {
- background: url('images/city6.png') 30% 0% repeat-x;
+ background: url('images/fmb-header.png') 30% 0% repeat-x;
border-bottom: 2px solid #333;
}
+
#main-nav ul#main-menu li a.report-a-problem-btn:hover {
background: #fff;
}
@@ -38,3 +39,36 @@ body.mappage .nav-wrapper div.nav-wrapper-2 {
background-image: url('images/ie_logo.png');
}
+// #site-header creates grey bar in mobile
+// .nav-wrapper-2 is used on desktop
+#site-header{
+ border-top: 0.25em solid $fmb_tab_yellow;
+ @include background(linear-gradient($fmb_dark_blue, $fmb_base_blue 10%, $fmb_base_blue 90%, $fmb_dark_blue));
+}
+
+ul#promo-list {
+ margin: 0.5em;
+ li {
+ list-style:none;
+ }
+}
+.promo-big, .promo-bigger {
+ font-size: 130%;
+ font-weight: bold;
+ padding: 0 0.2em;
+}
+.promo-bigger {
+ font-size: 150%;
+}
+.promo-example {
+ font-size: 90%;
+ font-style: italic;
+ border: 1px solid #aaa;
+ background-color:#f0ebe8; // pale tone of background image
+ padding: 0.666em;
+ margin: 1em 1em 1em 0;
+ div {
+ font-style: normal;
+ font-family: monospace;
+ }
+}
diff --git a/web/cobrands/fixmybarangay/images/city6.png b/web/cobrands/fixmybarangay/images/city6.png
deleted file mode 100644
index 63d7e674c..000000000
--- a/web/cobrands/fixmybarangay/images/city6.png
+++ /dev/null
Binary files differ
diff --git a/web/cobrands/fixmybarangay/images/city7.png b/web/cobrands/fixmybarangay/images/city7.png
deleted file mode 100644
index cea65cb82..000000000
--- a/web/cobrands/fixmybarangay/images/city7.png
+++ /dev/null
Binary files differ
diff --git a/web/cobrands/fixmybarangay/images/fmb-header.png b/web/cobrands/fixmybarangay/images/fmb-header.png
new file mode 100644
index 000000000..c3c45e009
--- /dev/null
+++ b/web/cobrands/fixmybarangay/images/fmb-header.png
Binary files differ
diff --git a/web/cobrands/fixmybarangay/layout.scss b/web/cobrands/fixmybarangay/layout.scss
index 4676f8486..ec35c0f0c 100644
--- a/web/cobrands/fixmybarangay/layout.scss
+++ b/web/cobrands/fixmybarangay/layout.scss
@@ -18,7 +18,10 @@ body {
color: $primary_text;
.wrapper{
- background: url('images/city7.png') 30% 0% repeat-x;
+ background: url('images/fmb-header.png') 30% 0% repeat-x;
+ }
+ #site-logo {
+ left:8px;
}
}
@@ -27,11 +30,13 @@ body.frontpage {
#site-logo {
width: 370px !important;
height: 70px;
- background: url('images/sprite.png') -3px -106px no-repeat;
+ background: url('images/sprite.png') -3px -106px no-repeat;
+ top: 2em;
+ left: 1em;
}
.wrapper {
- background: url('images/city7.png') 30% 0% repeat-x;
+ background: url('images/fmb-header.png') 30% 0% repeat-x;
}
}
diff --git a/web/cobrands/fixmybarangay/message_manager.scss b/web/cobrands/fixmybarangay/message_manager.scss
index 120bea4ba..9af6c80ee 100644
--- a/web/cobrands/fixmybarangay/message_manager.scss
+++ b/web/cobrands/fixmybarangay/message_manager.scss
@@ -16,12 +16,10 @@ $color_bg_mm_list: #F6F6F6;
$color_bg_btn_hide: #ff0000;
$color_bg_btn_reply: #008000;
$color_bg_btn_info: #0000ff;
-
+$color_bg_btn_detach: #FFA500;
$weak_text_color: #666;
-
-
p.mm-submitted-by-sms {
color: $weak_text_color;
font-style: italic;
@@ -42,7 +40,7 @@ p.mm-submitted-by-sms {
margin: -0.5em 0 0 0;
text-align: right;
font-size:80%;
- padding:4px 8px 4px 0;
+ padding:4px 0;
a {
padding: 0.25em 0.5em;
border:1px solid $mm_border_color;
@@ -53,8 +51,15 @@ p.mm-submitted-by-sms {
&:hover {
background-color: #fff;
}
+ #mm-link-to-toggle-archive {
+ border-color: green;
+ }
}
#message-control {
+ background-color: #fff;
+ &:hover {
+ background-color: #fff;
+ }
#mm-username-container {
display: none; // hidden during dev
padding: 8px;
@@ -188,6 +193,11 @@ p.mm-submitted-by-sms {
background-color: $color_bg_btn_reply;
cursor: pointer;
}
+ .mm-detach {
+ right:5.65em;
+ background-color: $color_bg_btn_detach;
+ cursor: pointer;
+ }
}
&.mm-archive {
display: none; // archive only shown on interaction
@@ -211,10 +221,13 @@ p.mm-submitted-by-sms {
width: 11em; // hack to stop adjacent button hopping when button message changes
}
+#detach-form-container,
#reply-form-container,
#hide-form-container {
p {
color: #000;
+ max-width: 25em;
+ margin: 1em;
}
#hide-form,
#reply-form{
@@ -228,9 +241,13 @@ p.mm-submitted-by-sms {
overflow: hidden;
display: none;
}
+ select {
+ width: 100%;
+ max-width: 25em;
+ }
}
#mm-help {
- .demo_hide_btn, .demo_reply_btn, .demo_info_btn {
+ .demo_hide_btn, .demo_reply_btn, .demo_info_btn, .demo_detach_btn {
color: #fff;
font-weight: bold;
padding: 0.2em 0.4em;
@@ -238,4 +255,12 @@ p.mm-submitted-by-sms {
.demo_hide_btn { background-color: $color_bg_btn_hide; }
.demo_reply_btn { background-color: $color_bg_btn_reply; }
.demo_info_btn { background-color: $color_bg_btn_info; }
+ .demo_detach_btn{ background-color: $color_bg_btn_detach; }
+ h3 {
+ border-top: 1px solid $color_reply_bg;
+ padding-top: 0.8em;
+ }
+ p {
+ margin: 1em;
+ }
}
diff --git a/web/cobrands/fixmybarangay/message_manager_client.js b/web/cobrands/fixmybarangay/message_manager_client.js
index 11f9c1264..06ea7a909 100644
--- a/web/cobrands/fixmybarangay/message_manager_client.js
+++ b/web/cobrands/fixmybarangay/message_manager_client.js
@@ -76,7 +76,8 @@ var message_manager = (function() {
tt_hide : "Hide message",
tt_info : "Get info",
tt_reply : "Send SMS reply",
- tt_radio : "Select message before clicking on map to create report"
+ tt_radio : "Select message before clicking on map to create report",
+ tt_detach: "Detach this message because it is not a reply"
};
// cached jQuery elements, populated by the (mandatory) call to config()
@@ -226,7 +227,7 @@ var message_manager = (function() {
$login_element.stop(true,true).slideDown();
};
- var say_status = function (msg, show_spinner) {
+ var say_status = function (msg, show_spinner, allow_html) {
if ($status_element) {
if (show_spinner) {
// slow fade in so that spinner only appears if there's a long delay
@@ -234,7 +235,12 @@ var message_manager = (function() {
} else {
$status_element.find('#mm-spinner').stop(true,true).hide();
}
- $status_element.stop(true,true).show().find('p').text(msg);
+ $status_element.stop(true,true).show();
+ if (allow_html) {
+ $status_element.find('p').html(msg);
+ } else {
+ $status_element.find('p').text(msg);
+ }
}
};
@@ -257,10 +263,12 @@ var message_manager = (function() {
var $hide_button = $('<a class="mm-msg-action mm-hide" id="mm-hide-' + msg.id + '" href="#hide-form-container" title="' + _tooltips.tt_hide + '">X</a>');
var $info_button = $('<span class="mm-msg-action mm-info" id="mm-info-' + msg.id + '" title="' + _tooltips.tt_info + '">i</span>');
var $reply_button = $('<a class="mm-msg-action mm-rep" id="mm-rep-' + msg.id + '" href="#reply-form-container" title="' + _tooltips.tt_reply + '">reply</a>');
+ var $detach_button = $('<a class="mm-msg-action mm-detach" id="mm-rep-' + msg.id + '" href="#detach-form-container" title="' + _tooltips.tt_detach + '">detach</a>');
var is_radio_btn = _want_radio_btns && depth === 0 && ! is_archive;
if (_use_fancybox) {
$reply_button.fancybox();
$hide_button.fancybox();
+ $detach_button.fancybox();
}
if (depth === 0) {
var tag = (!msg.tag || msg.tag === 'null')? '&nbsp;' : msg.tag;
@@ -286,6 +294,9 @@ var message_manager = (function() {
$p.text(escaped_text).addClass('mm-reply mm-reply-' + depth);
}
var $litem = $('<li id="' + _msg_prefix + msg.id + '" class="mm-msg">').append($p).append($hide_button).append($info_button);
+ if (depth > 0 && depth % 2 === 0) { // only even-numbered depths are incoming replies that can be detached
+ $litem.append($detach_button);
+ }
if (msg.is_outbound != 1) {
$litem.append($reply_button);
}
@@ -379,6 +390,10 @@ var message_manager = (function() {
$('#hide_msg_id').val($(this).closest('li').attr('id').replace(_msg_prefix, ''));
// $('#hide-form-message-text').val(TODO);
});
+ // clicking the detach button loads the id into the (modal/fancybox) detach form
+ $message_list_element.on('click', '.mm-detach', function(event) {
+ $('#detach_msg_id').val($(this).closest('li').attr('id').replace(_msg_prefix, ''));
+ });
};
// gets messages or else requests login
@@ -440,7 +455,8 @@ var message_manager = (function() {
}
},
error: function(jqXHR, textStatus, errorThrown) {
- var st = jqXHR.status;
+ var st = jqXHR.status;
+ var msg_is_html = false;
if (st == 401 || st == 403) {
var msg = (st == 401 ? "Invalid username or password for" : "Access denied: please log in to") + " " + _mm_name;
say_status(msg);
@@ -448,11 +464,17 @@ var message_manager = (function() {
} else {
var err_msg = "Unable to load messages: ";
if (st === 0 && textStatus === 'error') { // x-domain hard to detect, sometimes intermittent?
- err_msg += "maybe try refreshing page?";
+ if (_url_root.indexOf('https')===0 && ! location.protocol != 'https:') {
+ var surl = location.href.replace(/^http:/, 'https:');
+ err_msg += 'this is an insecure URL.<br/><a href="' + surl + '">Try from HTTPS instead?</a>';
+ msg_is_html = true;
+ } else {
+ err_msg += "maybe try refreshing page?";
+ }
} else {
err_msg += textStatus + " (" + st + ")";
}
- say_status(err_msg);
+ say_status(err_msg, false, msg_is_html);
}
}
});
@@ -677,6 +699,56 @@ var message_manager = (function() {
}
};
+ var mark_as_not_a_reply = function(msg_id, options) {
+ if (_use_fancybox){
+ $.fancybox.close();
+ }
+ var callback = null;
+ var check_li_exists = false;
+ if (options) {
+ if (typeof(options.callback) === 'function') {
+ callback = options.callback;
+ }
+ if (typeof(options.check_li_exists) !== undefined && options.check_li_exists !== undefined) {
+ check_li_exists = true; // MM dummy
+ }
+ }
+ var $li = $('#' + _msg_prefix + msg_id);
+ if (check_li_exists) {
+ if ($li.size() === 0) {
+ say_status("Couldn't find message with ID " + msg_id);
+ return;
+ }
+ }
+ $li.addClass('msg-is-busy');
+ $.ajax({
+ dataType:"json",
+ type:"post",
+ data: {},
+ url: _url_root +"messages/mark_as_not_a_reply/" + msg_id + ".json",
+ beforeSend: function (xhr){
+ xhr.setRequestHeader('Authorization', get_current_auth_credentials());
+ xhr.withCredentials = true;
+ },
+ success:function(data, textStatus) {
+ if (data.success) {
+ $li.removeClass('msg-is-busy msg-is-locked').addClass('msg-is-owned').fadeOut('slow'); // no longer available
+ say_status("Message no longer marked as a reply");
+ if (typeof(callback) === "function") {
+ callback.call($(this), data.data);
+ }
+ } else {
+ $li.removeClass('msg-is-busy').addClass('msg-is-locked');
+ say_status("Hide failed: " + data.error);
+ }
+ },
+ error: function(jqXHR, textStatus, errorThrown) {
+ say_status("Detach error: " + textStatus + ": " + errorThrown);
+ $li.removeClass('msg-is-busy');
+ }
+ });
+ };
+
// if boilerplate is not already in local storage, make ajax call and load them
// otherwise, populate the boilerplate select lists: these are currently the
// reasons for hiding a message, and pre-loaded replies.message-manager.dev.mysociety.org
@@ -772,6 +844,7 @@ var message_manager = (function() {
show_info: show_info,
sign_out: sign_out,
populate_boilerplate_strings: populate_boilerplate_strings,
- say_status: say_status
+ say_status: say_status,
+ mark_as_not_a_reply: mark_as_not_a_reply
};
})();
diff --git a/web/cobrands/fixmystreet/_layout.scss b/web/cobrands/fixmystreet/_layout.scss
index 63d4ef32e..825686a75 100644
--- a/web/cobrands/fixmystreet/_layout.scss
+++ b/web/cobrands/fixmystreet/_layout.scss
@@ -681,6 +681,15 @@ body.twothirdswidthpage {
border-bottom: 0.75em solid $col_fixed_label_dark;
}
}
+ &#closed {
+ padding-top:5em;
+ background-image:url(/cobrands/fixmystreet/images/sprite.png);
+ background-position:-318px -326px;
+ background-repeat:no-repeat;
+ &:before {
+ border-bottom: 0.75em solid #666;
+ }
+ }
}
}
.ie6 .banner p {
diff --git a/web/cobrands/fixmystreet/fixmystreet.js b/web/cobrands/fixmystreet/fixmystreet.js
index c512ab530..d9360d0e2 100644
--- a/web/cobrands/fixmystreet/fixmystreet.js
+++ b/web/cobrands/fixmystreet/fixmystreet.js
@@ -54,8 +54,13 @@ $(function(){
var $html = $('html');
var cobrand;
+ var is_small_map = false;
if (window.location.href.indexOf('bromley') != -1) {
cobrand = 'bromley';
+ is_small_map = true;
+ } else if (window.location.href.indexOf('oxfordshire') != -1) {
+ cobrand = 'oxfordshire';
+ is_small_map = true;
} else if (window.location.href.indexOf('zurich') != -1) {
cobrand = 'zurich';
}
@@ -106,7 +111,7 @@ $(function(){
$html.removeClass('mobile');
position_map_box();
if (typeof fixmystreet !== 'undefined') {
- if (cobrand == 'bromley') {
+ if (is_small_map) {
//$('#bromley-footer').hide();
} else {
fixmystreet.state_map = 'full';
@@ -114,10 +119,11 @@ $(function(){
}
if (typeof fixmystreet !== 'undefined' && fixmystreet.page == 'around') {
// Remove full-screen-ness
- var banner_text;
+ var banner_text = translation_strings.report_problem_heading;
if (cobrand == 'bromley') {
- banner_text = 'Click map to report a problem<span>Yellow pins show existing reports</span>';
- } else {
+ banner_text += '<span>Yellow pins show existing reports</span>';
+ }
+ if (! is_small_map) {
$('#site-header').show();
banner_text = translation_strings.report_problem_heading;
}
diff --git a/web/cobrands/oxfordshire/_colours.scss b/web/cobrands/oxfordshire/_colours.scss
new file mode 100644
index 000000000..0179bdbe4
--- /dev/null
+++ b/web/cobrands/oxfordshire/_colours.scss
@@ -0,0 +1,16 @@
+/* COLOURS */
+
+$oxfordshire_dk_green: #114500;
+$oxfordshire_lt_green: #339E00;
+
+$primary: $oxfordshire_lt_green;
+$primary_b: $oxfordshire_dk_green;
+$primary_text: #fff;
+
+$col_click_map: $oxfordshire_lt_green;
+$col_click_map_dark: $primary_text;
+
+$col_fixed_label: $oxfordshire_lt_green;
+$col_fixed_label_dark: $primary_text;
+
+
diff --git a/web/cobrands/oxfordshire/base.scss b/web/cobrands/oxfordshire/base.scss
new file mode 100644
index 000000000..10e5c5711
--- /dev/null
+++ b/web/cobrands/oxfordshire/base.scss
@@ -0,0 +1,40 @@
+@import "../fixmystreet/_h5bp";
+@import "./_colours";
+@import "../fixmystreet/_mixins";
+@import "compass";
+
+@import "../fixmystreet/_base";
+
+
+// Colour tab to match colour scheme
+#nav-link {
+ width: 50px;
+ height: 48px;
+ background: url('/cobrands/oxfordshire/images/tab-green.png') 0 0 no-repeat;
+}
+
+#site-header {
+ background: none;
+ background-color: $oxfordshire_dk_green;
+ height: 60px;
+}
+
+#site-logo {
+ margin-top:4px;
+ background-image: url('/cobrands/oxfordshire/images/logo.jpg');
+ background-repeat: no-repeat;
+ background-position: 0px 0px;
+ border: 4px solid $oxfordshire_dk_green;
+ width: 173px;
+ height: 38px;
+}
+
+#main-nav ul#mysoc-menu li a#mysoc-logo {
+ background-image: none;
+ text-indent: 0;
+ img {
+ display: inline;
+ height: 20px;
+ width: 105px;
+ }
+} \ No newline at end of file
diff --git a/web/cobrands/oxfordshire/config.rb b/web/cobrands/oxfordshire/config.rb
new file mode 100644
index 000000000..471b4b008
--- /dev/null
+++ b/web/cobrands/oxfordshire/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 \ No newline at end of file
diff --git a/web/cobrands/oxfordshire/images/bg-y.jpg b/web/cobrands/oxfordshire/images/bg-y.jpg
new file mode 100755
index 000000000..b623bc784
--- /dev/null
+++ b/web/cobrands/oxfordshire/images/bg-y.jpg
Binary files differ
diff --git a/web/cobrands/oxfordshire/images/bg.jpg b/web/cobrands/oxfordshire/images/bg.jpg
new file mode 100755
index 000000000..e670c0f7d
--- /dev/null
+++ b/web/cobrands/oxfordshire/images/bg.jpg
Binary files differ
diff --git a/web/cobrands/oxfordshire/images/divider1x32.png b/web/cobrands/oxfordshire/images/divider1x32.png
new file mode 100644
index 000000000..fffea7e24
--- /dev/null
+++ b/web/cobrands/oxfordshire/images/divider1x32.png
Binary files differ
diff --git a/web/cobrands/oxfordshire/images/dot6x6.jpg b/web/cobrands/oxfordshire/images/dot6x6.jpg
new file mode 100755
index 000000000..73a9c72f4
--- /dev/null
+++ b/web/cobrands/oxfordshire/images/dot6x6.jpg
Binary files differ
diff --git a/web/cobrands/oxfordshire/images/fms-logo-105x20.png b/web/cobrands/oxfordshire/images/fms-logo-105x20.png
new file mode 100644
index 000000000..286f22ded
--- /dev/null
+++ b/web/cobrands/oxfordshire/images/fms-logo-105x20.png
Binary files differ
diff --git a/web/cobrands/oxfordshire/images/fms-logo-inverse.png b/web/cobrands/oxfordshire/images/fms-logo-inverse.png
new file mode 100644
index 000000000..77417c3e9
--- /dev/null
+++ b/web/cobrands/oxfordshire/images/fms-logo-inverse.png
Binary files differ
diff --git a/web/cobrands/oxfordshire/images/footer.jpg b/web/cobrands/oxfordshire/images/footer.jpg
new file mode 100755
index 000000000..8bd0758eb
--- /dev/null
+++ b/web/cobrands/oxfordshire/images/footer.jpg
Binary files differ
diff --git a/web/cobrands/oxfordshire/images/header.jpg b/web/cobrands/oxfordshire/images/header.jpg
new file mode 100755
index 000000000..f642adfc4
--- /dev/null
+++ b/web/cobrands/oxfordshire/images/header.jpg
Binary files differ
diff --git a/web/cobrands/oxfordshire/images/logo.jpg b/web/cobrands/oxfordshire/images/logo.jpg
new file mode 100755
index 000000000..9ab24d2c4
--- /dev/null
+++ b/web/cobrands/oxfordshire/images/logo.jpg
Binary files differ
diff --git a/web/cobrands/oxfordshire/images/tab-green.png b/web/cobrands/oxfordshire/images/tab-green.png
new file mode 100644
index 000000000..7837fed00
--- /dev/null
+++ b/web/cobrands/oxfordshire/images/tab-green.png
Binary files differ
diff --git a/web/cobrands/oxfordshire/images/tabs-featured-on.png b/web/cobrands/oxfordshire/images/tabs-featured-on.png
new file mode 100644
index 000000000..94fe089c6
--- /dev/null
+++ b/web/cobrands/oxfordshire/images/tabs-featured-on.png
Binary files differ
diff --git a/web/cobrands/oxfordshire/images/tabs-featured.png b/web/cobrands/oxfordshire/images/tabs-featured.png
new file mode 100644
index 000000000..99b823faf
--- /dev/null
+++ b/web/cobrands/oxfordshire/images/tabs-featured.png
Binary files differ
diff --git a/web/cobrands/oxfordshire/layout.scss b/web/cobrands/oxfordshire/layout.scss
new file mode 100644
index 000000000..8d5710158
--- /dev/null
+++ b/web/cobrands/oxfordshire/layout.scss
@@ -0,0 +1,154 @@
+@import "_colours";
+@import "../fixmystreet/_layout";
+
+body {
+ background-color: #fff;
+ background-image: none;
+}
+
+#front-main {
+ background-color: $primary;
+ background-image: none;
+ @include border-radius(1em 1em 0 0);
+ margin: 2em 1em 0;
+ padding-top: 1em;
+ h1 {
+ margin: 0 auto 0 auto;
+ }
+ h2 {
+ color: $primary_text;
+ }
+ a#geolocate_link {
+ color: $primary_text;
+ }
+}
+
+// Currently hide the nav-wrapper, because it's in going into Oxfordshire's own nav
+// likewise with user-meta
+.nav-wrapper, #user-meta {
+ display: none;
+}
+
+// hide the site-header, currently has council logo at top of page
+#site-header {
+ 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;
+ }
+}
+
+// Fix location of aside sidebar
+body.twothirdswidthpage {
+ .content {
+ aside {
+ @include box-shadow(none);
+ }
+ .sticky-sidebar {
+ aside {
+ position: fixed;
+ top: 10em;
+ li { // from occ website
+ padding-left: 19px;
+ font: 0.813em "Trebuchet MS";
+ background: url("/cobrands/oxfordshire/images/dot6x6.jpg") no-repeat 0 5px;
+ }
+ }
+ }
+ }
+}
+
+//-------------------------------------------------
+// following declarations concern the map display:
+//-------------------------------------------------
+// So that map appears underneath the header
+.wrapper {
+ position: relative;
+ .table-cell {
+ padding-left: 13px; // added 13px to match Oxfordshire's normal look
+ padding-right: 13px;
+ }
+}
+.ie6, .ie7 {
+ .wrapper {
+ padding-top: 1em;
+ }
+}
+
+// show the sidebar tips and notices in the document flow, i.e., in the
+// left-hand column, rather than in smaller text above the map
+.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;
+ }
+}
+
+// To prevent font size larger interfering with the fixed Oxfordshire 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:10em;
+ }
+ }
+}
+.ie6, .ie7 {
+ body.mappage .container {
+ width: 464px;
+ margin-left: 0;
+ }
+}
+
+// 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;
+}
+
+// So as not to interfere with the Oxfordshire footer, make the fixed nav ("get updates" etc) static.
+.shadow-wrap {
+ position: static;
+ padding-top: 0;
+ margin-bottom: 1em;
+ ul#key-tools {
+ border-top: none;
+ border-bottom: 1px solid $primary;
+ }
+}
+
+
+@import "oxfordshire";
diff --git a/web/cobrands/oxfordshire/oxfordshire.scss b/web/cobrands/oxfordshire/oxfordshire.scss
new file mode 100644
index 000000000..0429a622b
--- /dev/null
+++ b/web/cobrands/oxfordshire/oxfordshire.scss
@@ -0,0 +1,184 @@
+/* Parts of oxfordshire'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 "_colours";
+
+
+body {
+ font-family:"Trebuchet MS",Arial, Helvetica, sans-serif;
+ line-height:18px;
+ a {text-decoration:none; outline:0; font-family:Arial, Helvetica, sans-serif; font-size:0.75em; color:#0c62ba}
+ a { font-size: 1em; } // mySociety
+ a:hover {text-decoration:underline}
+ margin:0;
+ background:#E0E0E0 url("/cobrands/oxfordshire/images/bg.jpg") repeat-y top center;
+
+ #oxford-wrapper {
+ background: url("/cobrands/oxfordshire/images/bg-y.jpg") repeat-y scroll 0 0 #FFFFFF;
+ clear: both;
+ display: block;
+ margin: 0 auto;
+ padding: 0 8px;
+ width: 990px;
+ }
+
+}
+
+#oxford-header
+ {
+ padding:0 16px 7px 16px;
+ clear:both;
+ overflow:hidden;
+ position:relative;
+ width:958px;
+ height:84px;
+ height:auto !important;
+ min-height:84px;
+ background: $oxfordshire_lt_green url("/cobrands/oxfordshire/images/header.jpg") no-repeat 0 0;
+
+ a.logo:hover {cursor:pointer;cursor:hand}
+ a.logo {float:left; display:inline; margin:3px 0 6px 10px; position:relative; overflow:hidden}
+ a.logo span {display:block; position:absolute; top:0; left:0; z-index:10}
+ a.logo, a.logo span {width:173px; height:38px; background: url("/cobrands/oxfordshire/images/logo.jpg") no-repeat 0 0;}
+
+ h1 {float:left; padding:8px 0 0 10px; margin:0; font-size:1.25em; line-height:normal; font-weight:bold; color:#ffffff; white-space:nowrap;font-family:"Trebuchet MS",Tahoma,Arial,sans-serif;}
+ span.header {float:left; padding:8px 0 0 10px; margin:0; font-size:1.25em; line-height:normal; font-weight:bold; color:#ffffff; white-space:nowrap}
+ a {color:#ffffff;}
+
+ #oxford-links {
+ padding: 10px 3px 0px 0px; float:right;color:#ffffff;
+ a{
+ font-size:0.75em; // mySociety putting this back (switched off in body)
+ margin: 0px 5px 0px 5px
+ }
+
+ }
+ .oxford-user {
+ float: right;
+ p {
+ padding: 0.25em;
+ margin: 0.5em 0;
+ a {
+ margin: 0 0.5em;
+ }
+ }
+ }
+}
+
+
+
+#oxford-main-menu {
+ clear: both;
+ margin: 0;
+ padding: 0;
+ font-size: 1em;
+ position: relative;
+ ul {
+ margin: 0 0 0 330px;
+ position: relative;
+ li {
+ margin: 0;
+ list-style-type: none;
+ float:left;
+ width:126px;
+ text-align:center;
+ background: #e0e0e0;
+ padding: 8px 0;
+ margin: 0 0 0 2px;
+ }
+ }
+ // from occ.css (client site): #main .view-features-for-homepage ul.tabs
+ ul.tabs {
+ float:left;
+ position:relative;
+ padding:0;
+ margin:0.5em 0 0 0;
+ z-index:10;
+ width: 990px;
+ //width:635px;
+ min-height:32px;
+ overflow:hidden;
+ clear:both;
+ background: #939393 url("/cobrands/oxfordshire/images/tabs-featured.png") repeat 0 0;
+ li {
+ float:left;
+ padding:0 0 0px 1px;
+ margin:0;
+ font:0.813em/27px "Trebuchet MS";
+ color:#ffffff;
+ height:32px;
+ background: #666 url("/cobrands/oxfordshire/images/divider1x32.png") no-repeat 0 0;
+ }
+ li.first {padding:0; background:none}
+ span, // mySociety
+ a {
+ display:block;
+ position:relative;
+ padding:8px 0 0 0;
+ font:bold 1em "Trebuchet MS";
+ height:24px;
+ color:#ffffff;
+ text-align:center;
+ background: #939393 url("/cobrands/oxfordshire/images/tabs-featured.png") repeat-x 0 0;
+ white-space:nowrap;
+ }
+ a:hover,
+ a:focus {
+ background: none #EA6C18;
+ background:-moz-linear-gradient(100% 100% 90deg, #ff4401, #EA6C18);
+ background:-webkit-gradient(linear, 0% 0%, 0% 100%, from(#EA6C18), to(#ff4401));
+ color: #ffffff;
+ }
+ li span, // mySociety
+ li.active a {
+ text-decoration:none;
+ background: #4c4c4c url("/cobrands/oxfordshire/images/tabs-featured-on.png") repeat-x 0 0;
+ }
+ li.active a:hover,
+ li.active a:focus {color: #ffffff;}
+ li.first a {}
+ li.last a {border-right:1px solid #666;}
+ a {padding:8px 0 0 0;}
+ }
+
+}
+
+
+#oxford-footer {
+ float:left;
+ display:inline;
+ margin:0 -8px 0 -8px;
+ padding:10px 25px 30px 21px;
+ clear:both;
+ overflow:hidden;
+ width:960px;
+ background:#000000 url(/cobrands/oxfordshire/images/footer.jpg) no-repeat bottom left;
+ address {float:left; padding:11px 0 0 0; margin:0; color:#989898; font:0.813em arial}
+ a {font:1em arial; color:#ffffff; margin:0px 5px 0px 5px}
+ address a {font:1em arial; color:#ffffff; margin:0px 0px 0px 0px}
+ ul {float:right; padding:5px 0 0 55px; margin:0}
+ ul li {float:left; padding:0; font:0.813em/27px arial; color:#ffffff; overflow:hidden}
+ /* contact-the-team */
+ li {
+ margin-left: 0.5em;
+ padding: 6px;
+ &.powered-by-fms {
+ // @include border-radius(6px);
+ min-width: 200px;
+ img {
+ display: inline;
+ height:20px;
+ width: 105px;
+ }
+ &:hover {
+ background-color:#2c2c2c;
+ }
+ a:hover {
+ text-decoration: none;
+ }
+ }
+ }
+}
+
diff --git a/web/cobrands/oxfordshire/position_map.js b/web/cobrands/oxfordshire/position_map.js
new file mode 100644
index 000000000..9c88d0980
--- /dev/null
+++ b/web/cobrands/oxfordshire/position_map.js
@@ -0,0 +1,19 @@
+function position_map_box() {
+ var $html = $('html');
+ var oxfordshire_right;
+ if ($html.hasClass('ie6') || $html.hasClass('ie7')) {
+ oxfordshire_right = '-480px';
+ } else {
+ oxfordshire_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: oxfordshire_right, bottom: '',
+ width: '464px', height: '464px',
+ margin: 0
+ });
+}
+
+function map_fix() {}
+var slide_wards_down = 1;
diff --git a/web/cobrands/southampton/css.scss b/web/cobrands/southampton/css.scss
index 592e72f2b..2fc569190 100644
--- a/web/cobrands/southampton/css.scss
+++ b/web/cobrands/southampton/css.scss
@@ -68,4 +68,8 @@ $darker: #768EB5;
.update-img {
text-align: left;
}
+
+ .news {
+ padding: 1em 1em 0em 1em;
+ }
}
diff --git a/web/js/fixmystreet.js b/web/js/fixmystreet.js
index fda019b1d..e25c2a571 100644
--- a/web/js/fixmystreet.js
+++ b/web/js/fixmystreet.js
@@ -53,13 +53,7 @@ $(function(){
var submitted = false;
$("form.validate").validate({
- rules: {
- title: { required: true },
- detail: { required: true },
- email: { required: true },
- update: { required: true },
- rznvy: { required: true }
- },
+ rules: validation_rules,
messages: translation_strings,
onkeyup: false,
onfocusout: false,