aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rwxr-xr-xbin/geocode50
-rwxr-xr-xbin/setup-contacts204
-rwxr-xr-xbin/update-schema2
-rw-r--r--cpanfile1
-rw-r--r--cpanfile.snapshot75
-rw-r--r--db/downgrade_0037---0036.sql1
-rw-r--r--db/downgrade_0038---0037.sql2
-rw-r--r--db/schema.sql12
-rw-r--r--db/schema_0037-response-templates.sql8
-rw-r--r--db/schema_0038-time-spent.sql2
-rw-r--r--locale/de_CH.UTF-8/LC_MESSAGES/FixMyStreet.po1227
-rw-r--r--perllib/FixMyStreet.pm5
-rw-r--r--perllib/FixMyStreet/App.pm83
-rw-r--r--perllib/FixMyStreet/App/Controller/Admin.pm169
-rw-r--r--perllib/FixMyStreet/App/Controller/Photo.pm163
-rw-r--r--perllib/FixMyStreet/App/Controller/Report.pm14
-rw-r--r--perllib/FixMyStreet/App/Controller/Report/New.pm25
-rw-r--r--perllib/FixMyStreet/App/Controller/Reports.pm1
-rw-r--r--perllib/FixMyStreet/App/Model/PhotoSet.pm306
-rw-r--r--perllib/FixMyStreet/App/View/Web.pm3
-rw-r--r--perllib/FixMyStreet/Cobrand/Default.pm44
-rw-r--r--perllib/FixMyStreet/Cobrand/Zurich.pm572
-rw-r--r--perllib/FixMyStreet/DB/Result/AdminLog.pm2
-rw-r--r--perllib/FixMyStreet/DB/Result/Body.pm22
-rw-r--r--perllib/FixMyStreet/DB/Result/Problem.pm68
-rw-r--r--perllib/FixMyStreet/DB/Result/ResponseTemplate.pm49
-rw-r--r--perllib/FixMyStreet/DB/ResultSet/Problem.pm2
-rw-r--r--perllib/FixMyStreet/Geocode/Zurich.pm11
-rw-r--r--perllib/FixMyStreet/Map.pm10
-rw-r--r--perllib/FixMyStreet/Map/Zurich.pm174
-rw-r--r--perllib/FixMyStreet/SendReport/Email.pm7
-rw-r--r--perllib/FixMyStreet/SendReport/Zurich.pm13
-rw-r--r--perllib/FixMyStreet/TestMech.pm30
-rw-r--r--t/app/controller/moderate.t10
-rw-r--r--t/app/controller/photo.t75
-rw-r--r--t/app/controller/questionnaire.t2
-rw-r--r--t/app/controller/report_display.t142
-rw-r--r--t/app/controller/report_import.t8
-rw-r--r--t/app/helpers/grey.gifbin0 -> 34 bytes
-rw-r--r--t/app/helpers/send_email.t72
-rw-r--r--t/app/helpers/send_email_sample_mime.txt57
-rw-r--r--t/app/model/photoset.t76
-rw-r--r--t/cobrand/zurich-logo_portal.x.jpgbin0 -> 365 bytes
-rw-r--r--t/cobrand/zurich.t661
-rw-r--r--t/cobrand/zurich_attachments.txt40
-rw-r--r--templates/email/default/test.txt1
-rw-r--r--templates/email/fixamingata/test.txt15
-rw-r--r--templates/email/zurich/problem-closed.txt4
-rw-r--r--templates/email/zurich/problem-confirm.txt4
-rw-r--r--templates/email/zurich/problem-external.txt8
-rw-r--r--templates/email/zurich/problem-rejected.txt16
-rw-r--r--templates/email/zurich/problem-wish.txt16
-rw-r--r--templates/email/zurich/reply-autoresponse.txt1
-rw-r--r--templates/email/zurich/submit-external-personal.txt15
-rw-r--r--templates/email/zurich/submit-external-wish.txt20
-rw-r--r--templates/email/zurich/submit-external.txt15
-rw-r--r--templates/web/base/admin/category_edit.html3
-rw-r--r--templates/web/base/auth/general.html2
-rw-r--r--templates/web/base/maps/noscript_map.html64
-rw-r--r--templates/web/base/maps/openlayers.html61
-rw-r--r--templates/web/base/report/new/category_extras.html2
-rw-r--r--templates/web/base/report/photo.html25
-rw-r--r--templates/web/zurich/admin/body-form.html1
-rw-r--r--templates/web/zurich/admin/header.html8
-rw-r--r--templates/web/zurich/admin/list_updates.html86
-rw-r--r--templates/web/zurich/admin/problem_row.html10
-rw-r--r--templates/web/zurich/admin/report_edit-sdm.html171
-rw-r--r--templates/web/zurich/admin/report_edit.html509
-rw-r--r--templates/web/zurich/admin/response_templates_select.html25
-rw-r--r--templates/web/zurich/admin/stats.html4
-rw-r--r--templates/web/zurich/admin/template_edit.html38
-rw-r--r--templates/web/zurich/admin/templates.html28
-rw-r--r--templates/web/zurich/auth/general.html2
-rw-r--r--templates/web/zurich/faq/faq-de-ch.html110
-rw-r--r--templates/web/zurich/footer.html3
-rw-r--r--templates/web/zurich/header.html7
-rw-r--r--templates/web/zurich/maps/noscript_map.html70
-rw-r--r--templates/web/zurich/report/banner.html19
-rw-r--r--templates/web/zurich/report/new/fill_in_details_form.html13
-rw-r--r--templates/web/zurich/report/updates.html6
-rw-r--r--web/cobrands/sass/_base.scss55
-rw-r--r--web/cobrands/zurich/admin-faux-columns.gifbin0 -> 107 bytes
-rw-r--r--web/cobrands/zurich/base.scss181
-rw-r--r--web/cobrands/zurich/layout.scss79
-rw-r--r--web/js/map-wmts-zurich.js171
85 files changed, 4713 insertions, 1655 deletions
diff --git a/bin/geocode b/bin/geocode
index 2559f7a3c..f6bf79149 100755
--- a/bin/geocode
+++ b/bin/geocode
@@ -12,10 +12,23 @@ geocode - commandline tool to test geocoders
$ bin/geocode --cobrand=bromley "Glebe Rd"
# ... if you want to use config that you have in conf/general.bing.yml
- $ bin/geocode --override-config=general.bing --cobrand=bromley "Glebe Rd"
+ $ bin/geocode --override-config=general.yml.bing --cobrand=bromley "Glebe Rd"
+
+ # ... if your config only has a single entry in ALLOWED_COBRANDS
+ $ bin/geocode --override-config=general.yml.zurich "Im eisernen Zeit"
## ... output from geocoder
+=head1 OPTIONS
+
+ --help|h show this help
+ --use-cache use the configured GEO_CACHE (default OFF)
+
+ # the following options take a string argument:
+ --geocoder e.g. OSM/Bing/Google/Zurich
+ --cobrand (default, bromley, zurich etc.)
+ --override-config e.g. conf/general.yml
+
=cut
use strict;
@@ -32,6 +45,7 @@ BEGIN {
use Data::Dumper;
use Pod::Usage;
use feature 'say';
+use File::Temp 'tempdir';
use Getopt::Long;
@@ -41,13 +55,12 @@ GetOptions \%options,
'geocoder=s',
'help|h',
'cobrand=s',
- 'override-config=s';
+ 'override-config=s',
+ 'use-cache';
my $s = join ' ', @ARGV
or pod2usage(0);
-pod2usage(0) unless $options{cobrand};
-
local $ENV{FMS_OVERRIDE_CONFIG} = $options{'override-config'} if $options{'override-config'};
eval 'use FixMyStreet';
@@ -63,22 +76,41 @@ my $geocoder_type = $options{geocoder} || do {
} or pod2usage(0);
my $geocoder_name = "FixMyStreet::Geocode::${geocoder_type}";
+chomp $geocoder_name;
my $code_ref = $geocoder_name->can('string')
or die "$geocoder_name is not a valid geocoder?";
-my @allowed_cobrands = FixMyStreet::Cobrand->get_allowed_cobrands();
+my @allowed_cobrands = @{ FixMyStreet::Cobrand->get_allowed_cobrands() };
+
+my $cobrand_option = $options{cobrand}
+ || do {
+ $allowed_cobrands[0]->{moniker} if scalar @allowed_cobrands == 1;
+ } or pod2usage(0);
-my $cobrand_name = FixMyStreet::Cobrand->get_class_for_moniker($options{cobrand});
+my $cobrand_name = FixMyStreet::Cobrand->get_class_for_moniker($cobrand_option);
my $cobrand = $cobrand_name->new();
say "USING COBRAND $cobrand_name";
-if ($cobrand->moniker ne lc($options{cobrand})) {
- say "!!! asked for $options{cobrand}";
+if ($cobrand->moniker ne lc($cobrand_option)) {
+ say "!!! asked for $cobrand_option";
say "!!! Check ALLOWED_COBRANDS setting in conf/general.yml (or supplied --override-config file)";
say Dumper(\@allowed_cobrands);
}
+say "USING GEOCODER $geocoder_name "
+ . ( $options{'use-cache'} ?
+ 'WITH ' . FixMyStreet->config('GEO_CACHE') :
+ 'WITHOUT cache');
+
my $c = FixMyStreet::App->new();
$c->stash->{cobrand} = $cobrand;
-say Dumper( $code_ref->( $s, $c ) );
+FixMyStreet::override_config({
+ # if we're not using cache, then set GEO_CACHE to a temporary directory
+ $options{'use-cache'} ?
+ () :
+ ( GEO_CACHE => (tempdir( CLEANUP => 1 ) . '/') ),
+}, sub {
+ my $result = $code_ref->( $s, $c );
+ say Dumper $result;
+});
diff --git a/bin/setup-contacts b/bin/setup-contacts
new file mode 100755
index 000000000..d562ae71d
--- /dev/null
+++ b/bin/setup-contacts
@@ -0,0 +1,204 @@
+#!/usr/bin/env perl
+
+use strict;
+use warnings;
+require 5.8.0;
+use feature 'say';
+
+BEGIN {
+ use File::Basename qw(dirname);
+ use File::Spec;
+ my $d = dirname(File::Spec->rel2abs($0));
+ require "$d/../setenv.pl";
+}
+
+use FixMyStreet::App;
+
+my $moniker = $ARGV[0];
+
+my $c = FixMyStreet::App->new();
+my $cobrand = FixMyStreet::Cobrand->get_class_for_moniker($moniker)->new({ c => $c });
+$c->stash->{cobrand} = $cobrand;
+
+die "Not a staging site, bailing out" unless $c->config->{STAGING_SITE}; # TODO, allow override via --force
+say "Applying contacts for $cobrand";
+
+
+ensure_bodies();
+setup_contacts();
+
+=head2 setup_contacts, ensure_bodies
+
+routines to update extra data for contacts. These can be called by
+a script:
+
+ bin/setup-contacts zurich
+
+=cut
+
+sub ensure_bodies {
+ my @bodies = $cobrand->body_details_data;
+
+ my $bodies_rs = $c->model('DB::Body');
+
+ for my $body (@bodies) {
+ # following should work (having added Unique name/parent constraint, but doesn't)
+ # $bodies_rs->find_or_create( $body, { $parent ? ( key => 'body_name_parent_key' ) : () } );
+ # let's keep it simple and just allow unique names
+ next if $bodies_rs->search({ name => $body->{name} })->count;
+ if (my $area_id = delete $body->{area_id}) {
+ $body->{body_areas} = [ { area_id => $area_id } ];
+ }
+ my $parent = $body->{parent};
+ if ($parent and ! ref $parent) {
+ $body->{parent} = { name => $parent };
+ }
+ $bodies_rs->find_or_create( $body );
+ }
+}
+
+sub setup_contacts {
+ die "Not a staging site, bailing out" unless $c->config->{STAGING_SITE}; # TODO, allow override via --force
+
+ my @contact_details = $cobrand->contact_details_data;
+
+ for my $detail (@contact_details) {
+ update_contact( $detail, $description );
+ }
+}
+
+sub update_contact {
+ my ($contact_data, $description) = @_;
+
+ my $contact_rs = $c->model('DB::Contact');
+
+ my $category = $contact_data->{category} or die "No category provided";
+ $description ||= "Update contact";
+
+ my $contact = ensure_contact($contact_data, $description)
+ or return; # e.g. nothing returned if deleted
+
+ if (my $fields = $contact_data->{fields}) {
+
+ my @fields = map { get_field_extra($_) } @$fields;
+ my $note = sprintf 'Fields edited by automated script%s', $description ? " ($description)" : '';
+ $contact->set_extra_fields(@fields);
+ $contact->set_inflated_columns({
+ confirmed => 1,
+ deleted => 0,
+ editor => 'automated script',
+ whenedited => \'NOW()',
+ note => "Updated fields $description",
+ });
+ $contact->update;
+ }
+}
+
+sub ensure_contact {
+ my ($contact_data, $description) = @_;
+
+ my $category = $contact_data->{category} or die "No category provided";
+ $description ||= "Ensure contact exists $category";
+
+ my $email = temp_email_to_update(); # will only be set if newly created
+
+ my $body = get_body_for_contact($contact_data) or die "No body found for $category";
+
+ my $contact_rs = $c->model('DB::Contact');
+
+ my $category_details = $contact_data->{category_details} || {};
+
+ if (my $old_name = delete $contact_data->{rename_from}) {
+ if (my $old_category = $contact_rs->find({
+ category => $old_name,
+ , body => $body,
+ })) {
+ $old_category->update({
+ category => $category,
+ whenedited => \'NOW()',
+ note => "Renamed $description",
+ %{ $category_details || {} },
+ });
+ return $old_category;
+ }
+ }
+
+ if ($contact_data->{delete}) {
+ my $contact = $contact_rs->search({
+ body_id => $body->id,
+ category => $category,
+ deleted => 0
+ });
+ if ($contact->count) {
+ print sprintf "Deleting: %s\n", $category;
+ $contact->update({
+ deleted => 1,
+ editor => 'automated script',
+ whenedited => \'NOW()',
+ note => "Deleted by script $description",
+ });
+ }
+ return;
+ }
+
+ return $contact_rs->find_or_create(
+ {
+ body => $body,
+ category => $category,
+
+ confirmed => 1,
+ deleted => 0,
+ email => $email,
+ editor => 'automated script',
+ note => 'created by automated script',
+ send_method => '',
+ whenedited => \'NOW()',
+ %{ $category_details || {} },
+ },
+ {
+ key => 'contacts_body_id_category_idx'
+ }
+ );
+}
+
+sub get_field_extra {
+ my ($field) = @_;
+
+ my %default = (
+ variable => 'true',
+ order => '1',
+ required => 'no',
+ datatype => 'string',
+ datatype_description => 'a string',
+ );
+
+ if (($field->{datatype} || '') eq 'boolean') {
+ %default = (
+ %default,
+ datatype => 'singlevaluelist',
+ datatype_description => 'Yes or No',
+ values => { value => [
+ { key => ['No'], name => ['No'] },
+ { key => ['Yes'], name => ['Yes'] },
+ ] },
+ );
+ }
+
+ return { %default, %$field };
+}
+
+sub temp_email_to_update { 'test@example.com' }
+
+sub get_body_for_contact {
+ my ($contact_data) = @_;
+ if (my $body_name = $contact_data->{body_name}) {
+ return $c->model('DB::Body')->find({ name => $body_name });
+ }
+ if ($cobrand->can('contact_details_data_body_default')) {
+ return $cobrand->contact_details_data_body_default;
+ }
+ return;
+ # TODO: for UK Councils use
+ # $c->model('DB::Body')->find(id => $cobrand->council_id);
+ # # NB: (or better that's the area in BodyAreas)
+}
diff --git a/bin/update-schema b/bin/update-schema
index d40df1689..1af08b002 100755
--- a/bin/update-schema
+++ b/bin/update-schema
@@ -195,6 +195,8 @@ else {
# By querying the database schema, we can see where we're currently at
# (assuming schema change files are never half-applied, which should be the case)
sub get_db_version {
+ return '0038' if column_exists('admin_log', 'time_spent');
+ return '0037' if table_exists('response_templates');
return '0036' if constraint_contains('problem_cobrand_check', 'a-z0-9_');
return '0035' if column_exists('problem', 'bodies_missing');
return '0034' if ! function_exists('ms_current_timestamp');
diff --git a/cpanfile b/cpanfile
index d7abc3315..16d431884 100644
--- a/cpanfile
+++ b/cpanfile
@@ -43,6 +43,7 @@ requires 'DBIx::Class::ResultSet';
requires 'DBIx::Class::Schema::Loader';
requires 'Digest::MD5';
requires 'Digest::SHA';
+requires 'Email::MIME';
requires 'Email::Send';
requires 'Email::Send::SMTP';
requires 'Email::Simple';
diff --git a/cpanfile.snapshot b/cpanfile.snapshot
index add5bc404..922738c24 100644
--- a/cpanfile.snapshot
+++ b/cpanfile.snapshot
@@ -2584,6 +2584,63 @@ DISTRIBUTIONS
ExtUtils::MakeMaker 0
Test::More 0.47
Time::Local 0.000
+ Email-MIME-1.929
+ pathname: R/RJ/RJBS/Email-MIME-1.929.tar.gz
+ provides:
+ Email::MIME 1.929
+ Email::MIME::Creator 1.929
+ Email::MIME::Encode 1.929
+ Email::MIME::Header 1.929
+ Email::MIME::Modifier 1.929
+ requirements:
+ Carp 0
+ Email::Address 0
+ Email::MIME::ContentType 1.016
+ Email::MIME::Encodings 1.314
+ Email::MessageID 0
+ Email::Simple 2.102
+ Email::Simple::Creator 0
+ Email::Simple::Header 0
+ Encode 1.9801
+ ExtUtils::MakeMaker 0
+ MIME::Base64 0
+ MIME::Types 1.13
+ Scalar::Util 0
+ parent 0
+ perl 5.008001
+ strict 0
+ warnings 0
+ Email-MIME-ContentType-1.018
+ pathname: R/RJ/RJBS/Email-MIME-ContentType-1.018.tar.gz
+ provides:
+ Email::MIME::ContentType 1.018
+ requirements:
+ Carp 0
+ Exporter 5.57
+ ExtUtils::MakeMaker 0
+ strict 0
+ warnings 0
+ Email-MIME-Encodings-1.315
+ pathname: R/RJ/RJBS/Email-MIME-Encodings-1.315.tar.gz
+ provides:
+ Email::MIME::Encodings 1.315
+ requirements:
+ Carp 0
+ ExtUtils::MakeMaker 6.30
+ MIME::Base64 3.05
+ MIME::QuotedPrint 3.05
+ strict 0
+ warnings 0
+ Email-MessageID-1.405
+ pathname: R/RJ/RJBS/Email-MessageID-1.405.tar.gz
+ provides:
+ Email::MessageID 1.405
+ requirements:
+ ExtUtils::MakeMaker 6.30
+ Sys::Hostname 0
+ overload 0
+ strict 0
+ warnings 0
Email-Send-2.198
pathname: R/RJ/RJBS/Email-Send-2.198.tar.gz
provides:
@@ -2670,6 +2727,9 @@ DISTRIBUTIONS
pathname: S/SH/SHLOMIF/Error-0.17019.tar.gz
provides:
Error 0.17019
+ Error::Simple 0.17019
+ Error::WarnDie undef
+ Error::subs undef
requirements:
Module::Build 0.39
Scalar::Util 0
@@ -3498,6 +3558,20 @@ DISTRIBUTIONS
ExtUtils::MakeMaker 6.52
Test::More 0.82
perl 5.00503
+ MIME-Lite-3.030
+ pathname: R/RJ/RJBS/MIME-Lite-3.030.tar.gz
+ provides:
+ MIME::Lite 3.030
+ MIME::Lite::IO_Handle 3.030
+ MIME::Lite::IO_Scalar 3.030
+ MIME::Lite::IO_ScalarArray 3.030
+ MIME::Lite::SMTP 3.030
+ MailTool undef
+ requirements:
+ Email::Date::Format 1.000
+ ExtUtils::MakeMaker 0
+ File::Basename 0
+ File::Spec 0
MIME-Types-1.38
pathname: M/MA/MARKOV/MIME-Types-1.38.tar.gz
provides:
@@ -5077,6 +5151,7 @@ DISTRIBUTIONS
IO::Socket::SSL 0
LWP::UserAgent 0
MIME::Base64 0
+ MIME::Lite 0
MIME::Parser 0
Net::POP3 0
Scalar::Util 0
diff --git a/db/downgrade_0037---0036.sql b/db/downgrade_0037---0036.sql
new file mode 100644
index 000000000..39f73b308
--- /dev/null
+++ b/db/downgrade_0037---0036.sql
@@ -0,0 +1 @@
+drop table response_templates;
diff --git a/db/downgrade_0038---0037.sql b/db/downgrade_0038---0037.sql
new file mode 100644
index 000000000..11a0d11ad
--- /dev/null
+++ b/db/downgrade_0038---0037.sql
@@ -0,0 +1,2 @@
+alter table admin_log
+ drop column time_spent;
diff --git a/db/schema.sql b/db/schema.sql
index 2db89bddb..72fccd7f3 100644
--- a/db/schema.sql
+++ b/db/schema.sql
@@ -427,7 +427,8 @@ create table admin_log (
action text not null,
whenedited timestamp not null default current_timestamp,
user_id int references users(id) null,
- reason text not null default ''
+ reason text not null default '',
+ time_spent int not null default 0
);
create table moderation_original_data (
@@ -457,3 +458,12 @@ create table user_body_permissions (
),
unique(user_id, body_id, permission_type)
);
+
+create table response_templates (
+ id serial not null primary key,
+ body_id int references body(id) not null,
+ title text not null,
+ text text not null,
+ created timestamp not null default current_timestamp,
+ unique(body_id, title)
+);
diff --git a/db/schema_0037-response-templates.sql b/db/schema_0037-response-templates.sql
new file mode 100644
index 000000000..4534e1e84
--- /dev/null
+++ b/db/schema_0037-response-templates.sql
@@ -0,0 +1,8 @@
+create table response_templates (
+ id serial not null primary key,
+ body_id int references body(id) not null,
+ title text not null,
+ text text not null,
+ created timestamp not null default current_timestamp,
+ unique(body_id, title)
+);
diff --git a/db/schema_0038-time-spent.sql b/db/schema_0038-time-spent.sql
new file mode 100644
index 000000000..093eb4086
--- /dev/null
+++ b/db/schema_0038-time-spent.sql
@@ -0,0 +1,2 @@
+alter table admin_log
+ add column time_spent int not null default 0;
diff --git a/locale/de_CH.UTF-8/LC_MESSAGES/FixMyStreet.po b/locale/de_CH.UTF-8/LC_MESSAGES/FixMyStreet.po
index c7b47b702..73b73874a 100644
--- a/locale/de_CH.UTF-8/LC_MESSAGES/FixMyStreet.po
+++ b/locale/de_CH.UTF-8/LC_MESSAGES/FixMyStreet.po
@@ -8,8 +8,8 @@ msgid ""
msgstr ""
"Project-Id-Version: fixmystreet\n"
"Report-Msgid-Bugs-To: matthew@mysociety.org\n"
-"POT-Creation-Date: 2015-07-31 14:28+0100\n"
-"PO-Revision-Date: 2015-07-10 13:29+0000\n"
+"POT-Creation-Date: 2015-05-21 15:17+0000\n"
+"PO-Revision-Date: 2015-06-02 13:18+0100\n"
"Last-Translator: mySociety <transifex@mysociety.org>\n"
"Language-Team: German (Switzerland) (http://www.transifex.com/projects/p/fixmystreet/language/de_CH/)\n"
"Language: de_CH\n"
@@ -17,16 +17,14 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
+"X-Generator: Poedit 1.7.6\n"
-#: perllib/FixMyStreet/DB/Result/Problem.pm:623
+#: perllib/FixMyStreet/DB/Result/Problem.pm:649
#: perllib/FixMyStreet/DB/ResultSet/Problem.pm:392
msgid " and "
msgstr "und"
-#: templates/web/base/report/new/councils_text_all.html:2
#: templates/web/base/report/new/councils_text_none.html:11
-#: templates/web/base/report/new/councils_text_none.html:2
-#: templates/web/base/report/new/councils_text_some.html:19
#: templates/web/base/report/new/councils_text_some.html:22
#: templates/web/base/report/new/councils_text_some.html:5
msgid " or "
@@ -57,12 +55,11 @@ msgstr ""
msgid "%d to %d of %d"
msgstr "%d bis %d von %d"
-#: templates/web/base/reports/body.html:0
#: templates/web/base/reports/body.html:23
msgid "%s - Summary reports"
msgstr "Alle Meldungen"
-#: perllib/FixMyStreet/DB/Result/Problem.pm:672
+#: perllib/FixMyStreet/DB/Result/Problem.pm:740
msgid "%s ref:&nbsp;%s"
msgstr ""
@@ -70,7 +67,7 @@ msgstr ""
msgid "%s ward, %s"
msgstr ""
-#: perllib/FixMyStreet/DB/Result/Problem.pm:559
+#: perllib/FixMyStreet/DB/Result/Problem.pm:585
msgid "%s, reported at %s"
msgstr "Gemeldet von %s um %s"
@@ -82,6 +79,10 @@ msgstr ""
msgid "&copy; <a href=\"http://www.openstreetmap.org/copyright\">OpenStreetMap</a> contributors"
msgstr ""
+#: templates/web/zurich/report/new/fill_in_details_form.html:70
+msgid "(Defect & location of defect)"
+msgstr "(Schaden & Ort des Schadens)"
+
#: templates/web/base/email_sent.html:29
msgid "(Don't worry &mdash; we'll hang on to your alert while you're checking your email.)"
msgstr ""
@@ -95,10 +96,20 @@ msgid "(Don't worry &mdash; we'll hang on to your update while you're checking y
msgstr ""
#: templates/web/base/admin/report_blocks.html:11
-#: templates/web/base/admin/users.html:31
+#: templates/web/base/admin/users.html:29
msgid "(Email in abuse table)"
msgstr ""
+#: templates/web/zurich/admin/report_edit-sdm.html:60
+#: templates/web/zurich/admin/report_edit.html:88
+msgid "(No name)"
+msgstr "Ihr Name"
+
+#: templates/web/zurich/admin/report_edit-sdm.html:67
+#: templates/web/zurich/admin/report_edit.html:95
+msgid "(No phone number)"
+msgstr "Ihre Telefonnummer"
+
#: templates/web/base/alert/_list.html:20
#: templates/web/fixmystreet/alert/_list.html:24
msgid "(a default distance which covers roughly 200,000 people)"
@@ -123,7 +134,7 @@ msgstr "(beantwortet)"
msgid "(fixed)"
msgstr "(beantwortet)"
-#: templates/web/base/index.html:8 templates/web/base/index.html:9
+#: templates/web/base/index.html:9
#: templates/web/fixmystreet/around/intro.html:2
msgid "(like graffiti, fly tipping, broken paving slabs, or street lighting)"
msgstr "(z.B. illegale Deponien, Strassensch&auml;den, Graffitis usw.)"
@@ -133,8 +144,8 @@ msgstr "(z.B. illegale Deponien, Strassensch&auml;den, Graffitis usw.)"
msgid "(not sent to council)"
msgstr ""
-#: templates/web/base/report/new/fill_in_details_form.html:199
-#: templates/web/zurich/report/new/fill_in_details_form.html:77
+#: templates/web/base/report/new/fill_in_details_form.html:218
+#: templates/web/zurich/report/new/fill_in_details_form.html:99
msgid "(optional)"
msgstr "(optional)"
@@ -147,7 +158,7 @@ msgstr ""
msgid "(sent to both)"
msgstr ""
-#: templates/web/base/report/new/fill_in_details_form.html:193
+#: templates/web/base/report/new/fill_in_details_form.html:212
msgid "(we never show your email address or phone number)"
msgstr "(Ihre E-Mail Adresse und Telefonnummer werden nie angezeigt)"
@@ -155,17 +166,16 @@ msgstr "(Ihre E-Mail Adresse und Telefonnummer werden nie angezeigt)"
msgid "(we never show your email)"
msgstr "(Ihre E-Mail Adresse wird nie angezeigt)"
-#: perllib/FixMyStreet/App/Controller/Report/New.pm:666
-#: perllib/FixMyStreet/DB/Result/Problem.pm:410
+#: perllib/FixMyStreet/App/Controller/Report/New.pm:651
+#: perllib/FixMyStreet/DB/Result/Problem.pm:418
msgid "-- Pick a category --"
msgstr "-- Wählen Sie eine Kategorie --"
-#: perllib/FixMyStreet/App/Controller/Report/New.pm:630
-#: perllib/FixMyStreet/DB/Result/Problem.pm:416
+#: perllib/FixMyStreet/App/Controller/Report/New.pm:618
+#: perllib/FixMyStreet/DB/Result/Problem.pm:424
msgid "-- Pick a property type --"
msgstr ""
-#: templates/web/base/admin/body-form.html:42
#: templates/web/base/admin/body-form.html:43
msgid ""
"<code>MAPIT_URL</code> is set (<code>%s</code>) but no <code>MAPIT_TYPES</code>.<br>\n"
@@ -173,7 +183,6 @@ msgid ""
" Maybe add some <code>MAPIT_TYPES</code> to your config file?"
msgstr ""
-#: templates/web/base/around/_report_banner.html:3
#: templates/web/base/around/_report_banner.html:5
msgid "<small>If you cannot see the map, <a href='%s' rel='nofollow'>skip this step</a>.</small>"
msgstr "Karte nicht sichtbar? <a href='%s' rel='nofollow'>&Uuml;berspringen</a>.</small>"
@@ -200,7 +209,7 @@ msgstr "Neu Registrieren"
msgid "<strong>No</strong>, I do not, let me sign in by email:"
msgstr ""
-#: templates/web/base/report/new/fill_in_details_form.html:144
+#: templates/web/base/report/new/fill_in_details_form.html:163
msgid "<strong>No</strong>, let me confirm my report by email:"
msgstr ""
@@ -209,7 +218,7 @@ msgid "<strong>No</strong>, let me confirm my update by email:"
msgstr ""
#: templates/web/base/auth/general.html:37
-#: templates/web/base/report/new/fill_in_details_form.html:122
+#: templates/web/base/report/new/fill_in_details_form.html:141
#: templates/web/base/report/update-form.html:95
#: templates/web/fixmystreet/auth/general.html:37
#: templates/web/fixmystreet/auth/general.html:39
@@ -223,16 +232,12 @@ msgstr "Passwort"
msgid "About us"
msgstr "&Uuml;ber uns"
-#: templates/web/base/admin/report_edit.html:48
-#: templates/web/base/admin/report_edit.html:52
-#: templates/web/base/report/update-form.html:30
+#: templates/web/base/admin/report_edit.html:39
#: templates/web/base/report/update-form.html:31
-#: templates/web/fixmystreet/report/update-form.html:28
#: templates/web/fixmystreet/report/update-form.html:29
msgid "Action Scheduled"
msgstr ""
-#: templates/web/base/admin/body-form.html:3
#: templates/web/base/admin/body-form.html:4
msgid ""
"Add a <strong>body</strong> for each administrative body, such as a council or department\n"
@@ -240,32 +245,36 @@ msgid ""
" categories of problem) to each body."
msgstr ""
-#: templates/web/base/admin/body.html:56
+#: templates/web/base/admin/body.html:48
msgid "Add a contact using the form below."
msgstr ""
#: templates/web/base/admin/bodies.html:74
-#: templates/web/base/admin/body-form.html:240
-#: templates/web/zurich/admin/body-form.html:51
+#: templates/web/base/admin/body-form.html:233
+#: templates/web/zurich/admin/body-form.html:52
msgid "Add body"
msgstr "Adresse hinzuf&uuml;gen"
-#: templates/web/base/admin/body.html:116
+#: templates/web/base/admin/body.html:108
#: templates/web/zurich/admin/body.html:31
msgid "Add new category"
msgstr "F&uuml;ge neue Kategorie hinzu"
-#: templates/web/base/admin/users.html:47
+#: templates/web/base/admin/users.html:45
msgid "Add user"
msgstr "User hinzuf&uuml;gen"
-#: templates/web/base/my/my.html:64 templates/web/fixmystreet/my/my.html:52
+#: templates/web/base/my/my.html:64 templates/web/fixmystreet/my/my.html:70
msgid "Added %s"
msgstr ""
+#: templates/web/base/report/new/category_extras.html:4
+msgid "Additional Information"
+msgstr "Zusätzliche Angaben"
+
#: templates/web/base/auth/change_password.html:29
msgid "Again:"
-msgstr "Nochmals:"
+msgstr "Nochmals"
#: templates/web/base/admin/timeline.html:35
msgid "Alert %d created for %s, type %s, parameters %s / %s"
@@ -281,15 +290,18 @@ msgid "Alert me to future updates"
msgstr ""
#: templates/web/base/reports/index.html:3
-#: templates/web/zurich/admin/stats.html:5
#: templates/web/zurich/reports/index.html:12
msgid "All Reports"
msgstr "Alle Meldungen"
+#: templates/web/zurich/admin/stats.html:5
+msgid "All Reports as CSV"
+msgstr "Als CSV exportieren"
+
#: templates/web/base/footer.html:11 templates/web/fixmystreet/footer.html:26
#: templates/web/zurich/admin/index-dm.html:12
#: templates/web/zurich/admin/stats.html:13
-#: templates/web/zurich/footer.html:19
+#: templates/web/zurich/footer.html:20
#: templates/web/zurich/nav_over_content.html:6
msgid "All reports"
msgstr "Alle Meldungen"
@@ -303,11 +315,8 @@ msgstr "Alle Meldungen von %s bis %s"
msgid "All the information you provide here will be sent to"
msgstr ""
-#: templates/web/base/report/new/councils_text_all.html:2
#: templates/web/base/report/new/councils_text_all.html:4
-#: templates/web/base/report/new/fill_in_details_form.html:12
#: templates/web/base/report/new/fill_in_details_form.html:14
-#: templates/web/fixmystreet/report/new/fill_in_details_form.html:10
#: templates/web/fixmystreet/report/new/fill_in_details_form.html:11
msgid "All the information you provide here will be sent to <strong>%s</strong>."
msgstr ""
@@ -322,10 +331,10 @@ msgstr ""
msgid "Anonymous"
msgstr "Anonym"
-#: templates/web/base/admin/report_edit.html:75
+#: templates/web/base/admin/report_edit.html:62
#: templates/web/base/admin/update_edit.html:23
msgid "Anonymous:"
-msgstr "Anonym:"
+msgstr "Anonym"
#: templates/web/base/footer.html:26
msgid "Are you a <strong>developer</strong>? Would you like to contribute to FixMyStreet?"
@@ -336,32 +345,33 @@ msgid "Are you a developer?"
msgstr ""
#: templates/web/base/admin/body-form.html:69
-#: templates/web/base/admin/body.html:16
#: templates/web/zurich/admin/body-form.html:24
msgid "Area covered"
msgstr "Gebiet"
#: templates/web/base/admin/bodies.html:15
-#: templates/web/base/admin/body.html:60
+#: templates/web/base/admin/body.html:52
msgid "As this is a staging site and %s is false, reports made on this site will be sent to the problem reporter, not the contact given for the report’s category."
msgstr ""
-#: templates/web/zurich/admin/report_edit.html:141
+#: templates/web/zurich/admin/report_edit.html:268
+msgid "Assign to competent body:"
+msgstr "Nachricht an zuständige Stelle:"
+
+#: templates/web/zurich/admin/report_edit.html:228
#: templates/web/zurich/admin/stats.html:36
msgid "Assign to different category:"
-msgstr "Einer anderen Kategorie (DA) zuweisen:"
+msgstr "Einer anderen Kategorie (DA) zuweisen"
-#: templates/web/zurich/admin/report_edit.html:150
+#: templates/web/zurich/admin/report_edit.html:266
msgid "Assign to external body:"
-msgstr "Einer externen Stelle zuweisen:"
+msgstr "Nachricht an zuständige Stelle"
-#: templates/web/zurich/admin/report_edit.html:130
-#: templates/web/zurich/admin/report_edit.html:187
+#: templates/web/zurich/admin/report_edit.html:245
msgid "Assign to subdivision:"
-msgstr "An Fachbereich zuweisen:"
+msgstr "An Fachbereich zuweisen"
-#: perllib/FixMyStreet/Cobrand/Zurich.pm:165
-#: templates/web/zurich/report/updates.html:11
+#: perllib/FixMyStreet/Cobrand/Zurich.pm:210
msgid "Assigned to %s"
msgstr "Besten Dank f&uuml;r Ihre Meldung. Wir haben Ihr Anliegen an %s weitergeleitet, da es nicht in den Zust&auml;ndigkeitsbereich der am Pilot beteiligten Fachbereiche f&auml;llt.<br/>Freundliche Gr&uuml;sse <br/>Ihre Stadt Z&uuml;rich"
@@ -386,8 +396,8 @@ msgstr "Zur&uuml;ck"
msgid "Ban email address"
msgstr ""
-#: perllib/FixMyStreet/App/Controller/Admin.pm:1192
-#: perllib/FixMyStreet/Cobrand/Zurich.pm:301
+#: perllib/FixMyStreet/App/Controller/Admin.pm:1285
+#: perllib/FixMyStreet/Cobrand/Zurich.pm:381
#: templates/web/base/admin/bodies.html:1 templates/web/zurich/header.html:64
msgid "Bodies"
msgstr "Externe Adressen"
@@ -398,10 +408,9 @@ msgstr "Externe Adressen"
msgid "Body"
msgstr "Organisation"
-#: templates/web/base/admin/report_edit.html:34
#: templates/web/base/admin/user-form.html:32
msgid "Body:"
-msgstr "Organisation:"
+msgstr "Organisation"
#: templates/web/base/admin/stats.html:80
msgid "By Date"
@@ -411,15 +420,16 @@ msgstr ""
msgid "Can't see the map? <em>Skip this step</em>"
msgstr "Karte nicht sichtbar? <em>&Uuml;berspringen Sie diesen Schritt</em>"
-#: templates/web/base/admin/body.html:68
+#: templates/web/base/admin/body.html:60
#: templates/web/base/admin/index.html:55
#: templates/web/base/report/new/category.html:10
-#: templates/web/base/report/new/category_wrapper.html:3
+#: templates/web/fixmystreet/report/new/fill_in_details_form.html:53
#: templates/web/zurich/admin/body.html:14
#: templates/web/zurich/admin/index-dm.html:23
#: templates/web/zurich/admin/index-sdm.html:21
#: templates/web/zurich/admin/reports.html:13
#: templates/web/zurich/admin/stats.html:50
+#: templates/web/zurich/report/new/fill_in_details_form.html:50
msgid "Category"
msgstr "Kategorie"
@@ -427,12 +437,13 @@ msgstr "Kategorie"
msgid "Category fix rate for problems > 4 weeks old"
msgstr ""
-#: templates/web/base/admin/body.html:138
+#: templates/web/base/admin/body.html:130
#: templates/web/base/admin/category_edit.html:23
-#: templates/web/base/admin/report_edit.html:74
+#: templates/web/base/admin/report_edit.html:61
+#: templates/web/base/report/new/fill_in_details_form.html:68
#: templates/web/zurich/admin/body.html:43
-#: templates/web/zurich/admin/report_edit-sdm.html:42
-#: templates/web/zurich/admin/report_edit.html:140
+#: templates/web/zurich/admin/report_edit-sdm.html:70
+#: templates/web/zurich/admin/report_edit.html:98
msgid "Category:"
msgstr "Kategorie:"
@@ -447,19 +458,19 @@ msgstr "Kategorie: %s"
msgid "Change password"
msgstr "Passwort &auml;ndern"
-#: templates/web/base/admin/body.html:160
+#: templates/web/base/admin/body.html:152
msgid ""
"Check <strong>confirmed</strong> to indicate that this contact has been confirmed as correct.\n"
" If you are not sure of the origin or validity of the contact, leave this unchecked."
msgstr ""
-#: templates/web/base/admin/body.html:171
+#: templates/web/base/admin/body.html:163
msgid ""
"Check <strong>deleted</strong> to remove the category from use. \n"
" It will not appear as an available category in the drop-down menu on the report-a-problem page."
msgstr ""
-#: templates/web/base/admin/body.html:191
+#: templates/web/base/admin/body.html:183
msgid ""
"Check <strong>private</strong> if reports in this category should <strong>never be displayed on the website</strong>.\n"
" <br>\n"
@@ -470,12 +481,16 @@ msgid ""
" at a specific address."
msgstr ""
-#: templates/web/base/admin/body.html:130
+#: templates/web/base/admin/body.html:122
msgid ""
"Choose a <strong>category</strong> name that makes sense to the public (e.g., \"Pothole\", \"Street lighting\") but is helpful\n"
" to the body too. These will appear in the drop-down menu on the report-a-problem page."
msgstr ""
+#: templates/web/zurich/admin/response_templates_select.html:6
+msgid "Choose a template"
+msgstr "Vorlage wählen"
+
#: templates/web/base/admin/stats.html:65
#: templates/web/base/admin/stats.html:71
msgid "Click here or enter as dd/mm/yyyy"
@@ -484,31 +499,25 @@ msgstr ""
#: templates/web/base/js/translation_strings.html:50
#: templates/web/fixmystreet/around/_report_banner.html:2
msgid "Click map to report a problem"
-msgstr "Mangel lokalisieren"
+msgstr "Schaden lokalisieren"
-#: perllib/FixMyStreet/Cobrand/Zurich.pm:141
-#: templates/web/base/admin/report_edit.html:48
-#: templates/web/base/admin/report_edit.html:58
-#: templates/web/base/admin/report_edit.html:60
-#: templates/web/base/dashboard/index.html:142
+#: perllib/FixMyStreet/Cobrand/Zurich.pm:185
+#: perllib/FixMyStreet/Cobrand/Zurich.pm:955
+#: templates/web/base/admin/report_edit.html:45
+#: templates/web/base/admin/report_edit.html:47
#: templates/web/base/dashboard/index.html:144
#: templates/web/fixmystreet/report/banner.html:15
-#: templates/web/zurich/admin/header.html:1
#: templates/web/zurich/admin/header.html:10
-#: templates/web/zurich/admin/header.html:12
-#: templates/web/zurich/admin/report_edit.html:95
-#: templates/web/zurich/admin/report_edit.html:97
+#: templates/web/zurich/admin/header.html:16
#: templates/web/zurich/admin/stats.html:31
-#: templates/web/zurich/report/banner.html:13
msgid "Closed"
msgstr "Beantwortet"
-#: perllib/FixMyStreet/DB/Result/Problem.pm:771
+#: perllib/FixMyStreet/DB/Result/Problem.pm:839
msgid "Closed by council"
msgstr ""
-#: templates/web/base/my/my.html:40
-#: templates/web/fixmystreet/my/_problem-list.html:12
+#: templates/web/base/my/my.html:40 templates/web/fixmystreet/my/my.html:46
msgid "Closed reports"
msgstr ""
@@ -516,41 +525,38 @@ msgstr ""
msgid "Closed:"
msgstr "Beantwortet:"
-#: templates/web/base/around/tabbed_lists.html:10
#: templates/web/base/around/tabbed_lists.html:12
msgid "Closest nearby problems <small>(within&nbsp;%skm)</small>"
msgstr ""
#: templates/web/base/admin/report_edit.html:23
-#: templates/web/zurich/admin/report_edit-sdm.html:33
-#: templates/web/zurich/admin/report_edit.html:46
msgid "Co-ordinates:"
-msgstr "Koordinaten:"
+msgstr "Koordinaten"
#: templates/web/base/admin/list_updates.html:10
msgid "Cobrand"
msgstr ""
-#: templates/web/base/admin/report_edit.html:91
+#: templates/web/base/admin/report_edit.html:75
#: templates/web/base/admin/update_edit.html:50
msgid "Cobrand data:"
msgstr ""
-#: templates/web/base/admin/report_edit.html:90
+#: templates/web/base/admin/report_edit.html:74
#: templates/web/base/admin/update_edit.html:49
msgid "Cobrand:"
msgstr ""
-#: perllib/FixMyStreet/App/Controller/Admin.pm:1199
+#: perllib/FixMyStreet/App/Controller/Admin.pm:1292
#: templates/web/base/admin/config_page.html:1
msgid "Configuration"
msgstr ""
-#: templates/web/base/admin/category_edit.html:52
+#: templates/web/base/admin/category_edit.html:50
msgid "Configure Endpoint"
msgstr ""
-#: templates/web/base/admin/body.html:72
+#: templates/web/base/admin/body.html:64
msgid "Confirm"
msgstr "Best&auml;tigen"
@@ -571,10 +577,10 @@ msgstr ""
msgid "Confirmation"
msgstr "Bestätigung"
-#: templates/web/base/admin/body.html:166
-#: templates/web/base/admin/body.html:79
-#: templates/web/base/admin/category_edit.html:37
-#: templates/web/base/admin/category_edit.html:89
+#: templates/web/base/admin/body.html:158
+#: templates/web/base/admin/body.html:71
+#: templates/web/base/admin/category_edit.html:32
+#: templates/web/base/admin/category_edit.html:87
#: templates/web/zurich/admin/stats.html:40
msgid "Confirmed"
msgstr "Best&auml;tigt"
@@ -585,7 +591,7 @@ msgstr ""
#: templates/web/base/admin/list_updates.html:39
#: templates/web/base/admin/problem_row.html:36
-#: templates/web/base/admin/report_edit.html:83
+#: templates/web/base/admin/report_edit.html:70
msgid "Confirmed:"
msgstr "Best&auml;tigt:"
@@ -593,10 +599,8 @@ msgstr "Best&auml;tigt:"
msgid "Contact FixMyStreet"
msgstr ""
-#: templates/web/base/contact/index.html:1
#: templates/web/base/contact/index.html:2
#: templates/web/base/contact/submit.html:1
-#: templates/web/fixmystreet/contact/index.html:1
#: templates/web/fixmystreet/contact/index.html:2
msgid "Contact Us"
msgstr ""
@@ -606,8 +610,13 @@ msgstr ""
msgid "Contact the team"
msgstr ""
-#: perllib/FixMyStreet/App/Controller/Admin.pm:1325
-#: perllib/FixMyStreet/App/Controller/Admin.pm:1353
+#: templates/web/zurich/admin/report_edit-sdm.html:40
+#: templates/web/zurich/admin/report_edit.html:59
+msgid "Coordinates:"
+msgstr "Koordinaten"
+
+#: perllib/FixMyStreet/App/Controller/Admin.pm:1429
+#: perllib/FixMyStreet/App/Controller/Admin.pm:1457
msgid "Could not find user"
msgstr ""
@@ -625,10 +634,6 @@ msgstr ""
msgid "Council contacts for %s"
msgstr "Kontaktdetails von %s"
-#: perllib/FixMyStreet/DB/Result/Problem.pm:670
-msgid "Council ref:&nbsp;%s"
-msgstr ""
-
#: templates/web/base/admin/stats.html:84
msgid "Council:"
msgstr ""
@@ -638,31 +643,32 @@ msgstr ""
#: templates/web/zurich/admin/stats.html:45
#: templates/web/zurich/admin/stats.html:50
msgid "Count"
-msgstr ""
+msgstr "Anzahl"
#: templates/web/base/email_sent.html:1
msgid "Create a report"
msgstr "Erfasse eine Meldung"
-#: templates/web/base/admin/body.html:208
+#: templates/web/base/admin/body.html:200
#: templates/web/zurich/admin/body.html:59
msgid "Create category"
-msgstr ""
+msgstr "Kategorie erstellen"
+
+#: templates/web/zurich/admin/template_edit.html:29
+msgid "Create template"
+msgstr "Vorlage erstellen"
#: templates/web/base/admin/problem_row.html:34
-#: templates/web/zurich/admin/list_updates.html:29
-#: templates/web/zurich/admin/list_updates.html:8
+#: templates/web/zurich/admin/templates.html:10
msgid "Created"
msgstr "Erstellt"
#: templates/web/base/admin/list_updates.html:38
-#: templates/web/base/admin/report_edit.html:82
+#: templates/web/base/admin/report_edit.html:69
#: templates/web/base/admin/update_edit.html:51
-#: templates/web/zurich/admin/report_edit-sdm.html:47
-#: templates/web/zurich/admin/report_edit.html:61
#: templates/web/zurich/admin/update_edit.html:29
msgid "Created:"
-msgstr "Erstellt:"
+msgstr "Erstellt"
#: templates/web/base/admin/stats.html:31
msgid "Current state"
@@ -673,7 +679,11 @@ msgstr "Aktueller Status"
msgid "Currently no bodies have been created."
msgstr "Bisher wurden noch keine Organisationseinheiten erfasst."
-#: templates/web/base/dashboard/index.html:5
+#: perllib/FixMyStreet/Cobrand/Zurich.pm:820
+#: templates/web/zurich/admin/report_edit-sdm.html:109
+msgid "Customer not contactable"
+msgstr "Kunde nicht kontaktierbar"
+
#: templates/web/base/dashboard/index.html:7
msgid "Dashboard"
msgstr ""
@@ -682,15 +692,20 @@ msgstr ""
msgid "Dealt with by subdivision within 5 working days"
msgstr "Innerhalb von f&uuml;nf Arbeitstagen abgeschlossen"
+#: perllib/FixMyStreet/App/Controller/Admin.pm:875
+#: templates/web/zurich/admin/template_edit.html:33
+msgid "Delete template"
+msgstr "Vorlage löschen"
+
#: templates/web/base/admin/bodies.html:27
-#: templates/web/base/admin/body.html:177
-#: templates/web/base/admin/body.html:81
-#: templates/web/base/admin/category_edit.html:42
-#: templates/web/base/admin/category_edit.html:90
+#: templates/web/base/admin/body.html:169
+#: templates/web/base/admin/body.html:73
+#: templates/web/base/admin/category_edit.html:37
+#: templates/web/base/admin/category_edit.html:88
msgid "Deleted"
msgstr "Gel&ouml;scht"
-#: templates/web/fixmystreet/report/new/fill_in_details_form.html:51
+#: templates/web/fixmystreet/report/new/fill_in_details_form.html:43
#: templates/web/zurich/admin/index-dm.html:22
#: templates/web/zurich/admin/index-sdm.html:20
#: templates/web/zurich/admin/reports.html:12
@@ -704,16 +719,21 @@ msgstr "Beschreibung"
#: templates/web/base/admin/report_edit.html:20
#: templates/web/base/report/new/fill_in_details_form.html:62
-#: templates/web/zurich/admin/report_edit-sdm.html:25
-#: templates/web/zurich/admin/report_edit.html:25
-#: templates/web/zurich/admin/report_edit.html:35
+#: templates/web/zurich/admin/report_edit-sdm.html:27
+#: templates/web/zurich/admin/report_edit.html:29
+#: templates/web/zurich/admin/report_edit.html:43
msgid "Details:"
-msgstr "Beschreibung:"
+msgstr "Beschreibung"
-#: templates/web/base/admin/body.html:87
+#: templates/web/base/admin/body.html:79
msgid "Devolved"
msgstr ""
+#: templates/web/zurich/admin/report_edit-sdm.html:50
+#: templates/web/zurich/admin/report_edit.html:69
+msgid "Didn't use map"
+msgstr "hat Karte nicht verwendet"
+
#: templates/web/base/admin/edit-league.html:8
msgid "Diligency prize league table"
msgstr "Weiss ich nicht"
@@ -738,16 +758,13 @@ msgstr ""
msgid "Don't like forms?"
msgstr ""
-#: templates/web/base/admin/report_edit.html:48
-#: templates/web/base/admin/report_edit.html:60
-#: templates/web/base/report/update-form.html:30
+#: templates/web/base/admin/report_edit.html:47
#: templates/web/base/report/update-form.html:32
-#: templates/web/fixmystreet/report/update-form.html:28
#: templates/web/fixmystreet/report/update-form.html:30
msgid "Duplicate"
msgstr ""
-#: templates/web/base/admin/body.html:106
+#: templates/web/base/admin/body.html:98
msgid ""
"Each contact for the body has a category, which is displayed to the public. \n"
" Different categories <strong>can have the same contact</strong> (email address).\n"
@@ -757,20 +774,19 @@ msgstr ""
#: templates/web/base/admin/list_updates.html:42
#: templates/web/base/admin/problem_row.html:41
-#: templates/web/base/admin/users.html:33
-#: templates/web/zurich/admin/problem_row.html:42
+#: templates/web/base/admin/users.html:31
+#: templates/web/zurich/admin/problem_row.html:48
+#: templates/web/zurich/admin/templates.html:20
msgid "Edit"
-msgstr ""
+msgstr "Anpassen"
-#: templates/web/base/admin/body.html:220
+#: templates/web/base/admin/body.html:212
#: templates/web/zurich/admin/body.html:71
msgid "Edit body details"
msgstr "Details editieren"
#: templates/web/base/admin/report_edit.html:1
-#: templates/web/zurich/admin/report_edit-sdm.html:1
-#: templates/web/zurich/admin/report_edit-sdm.html:4
-#: templates/web/zurich/admin/report_edit.html:1
+#: templates/web/zurich/admin/report_edit-sdm.html:5
#: templates/web/zurich/admin/report_edit.html:5
msgid "Editing problem %d"
msgstr "Meldung %d bearbeiten"
@@ -784,12 +800,12 @@ msgstr ""
msgid "Editing user %d"
msgstr ""
-#: templates/web/base/admin/category_edit.html:91
+#: templates/web/base/admin/category_edit.html:89
msgid "Editor"
msgstr ""
#: templates/web/base/admin/bodies.html:23
-#: templates/web/base/admin/category_edit.html:88
+#: templates/web/base/admin/category_edit.html:86
#: templates/web/base/admin/flagged.html:38
#: templates/web/base/admin/users.html:16
#: templates/web/fixmystreet/auth/general.html:21
@@ -800,23 +816,23 @@ msgstr ""
msgid "Email"
msgstr "E-Mail"
-#: perllib/FixMyStreet/App/Controller/Admin.pm:1301
+#: perllib/FixMyStreet/App/Controller/Admin.pm:1405
msgid "Email added to abuse list"
msgstr ""
-#: templates/web/base/admin/body.html:155
+#: templates/web/base/admin/body.html:147
msgid "Email address:"
msgstr ""
#: templates/web/base/tokens/confirm_alert.html:6
msgid "Email alert created"
-msgstr ""
+msgstr "E-Mail Benachrichtigung erstellt"
#: templates/web/base/tokens/confirm_alert.html:10
msgid "Email alert deleted"
-msgstr ""
+msgstr "E-Mail Benachrichtigung gel&ouml;scht"
-#: perllib/FixMyStreet/App/Controller/Admin.pm:1298
+#: perllib/FixMyStreet/App/Controller/Admin.pm:1402
msgid "Email already in abuse list"
msgstr ""
@@ -828,15 +844,13 @@ msgstr ""
msgid "Email me updates"
msgstr "Schicken Sie mir Aktualisierungen"
-#: templates/web/base/admin/category_edit.html:31
-#: templates/web/base/admin/report_edit.html:80
+#: templates/web/base/admin/category_edit.html:26
+#: templates/web/base/admin/report_edit.html:67
#: templates/web/base/admin/update_edit.html:33
#: templates/web/base/admin/user-form.html:20
#: templates/web/base/alert/updates.html:13
#: templates/web/base/report/display.html:42
#: templates/web/zurich/admin/body.html:47
-#: templates/web/zurich/admin/report_edit-sdm.html:44
-#: templates/web/zurich/admin/report_edit.html:57
msgid "Email:"
msgstr "E-mail:"
@@ -844,28 +858,27 @@ msgstr "E-mail:"
msgid "Email: %s"
msgstr "E-mail:"
-#: perllib/FixMyStreet/App/Controller/Report/New.pm:632
+#: perllib/FixMyStreet/App/Controller/Report/New.pm:620
msgid "Empty flat or maisonette"
msgstr ""
-#: perllib/FixMyStreet/App/Controller/Report/New.pm:631
+#: perllib/FixMyStreet/App/Controller/Report/New.pm:619
msgid "Empty house or bungalow"
msgstr ""
-#: perllib/FixMyStreet/App/Controller/Report/New.pm:634
+#: perllib/FixMyStreet/App/Controller/Report/New.pm:622
msgid "Empty office or other commercial"
msgstr ""
-#: perllib/FixMyStreet/App/Controller/Report/New.pm:635
+#: perllib/FixMyStreet/App/Controller/Report/New.pm:623
msgid "Empty pub or bar"
msgstr ""
-#: perllib/FixMyStreet/App/Controller/Report/New.pm:636
+#: perllib/FixMyStreet/App/Controller/Report/New.pm:624
msgid "Empty public building - school, hospital, etc."
msgstr ""
-#: templates/web/base/admin/body-form.html:162
-#: templates/web/base/admin/body-form.html:163
+#: templates/web/base/admin/body-form.html:159
msgid ""
"Enable <strong>Open311 update-sending</strong> if the endpoint will send and receive\n"
" updates to existing reports. If you're not sure, it probably does not, so leave this unchecked.\n"
@@ -873,8 +886,7 @@ msgid ""
" <a href='https://www.mysociety.org/2013/02/20/open311-extended/' class='admin-offsite-link'>this article</a>."
msgstr ""
-#: templates/web/base/admin/body-form.html:222
-#: templates/web/base/admin/body-form.html:223
+#: templates/web/base/admin/body-form.html:216
msgid ""
"Enable this <strong>can be devolved</strong> setting if one or more contacts have a \n"
" different endpoint (and send method) from the body's. For example, if reports for some categories of\n"
@@ -885,13 +897,13 @@ msgstr ""
msgid "End Date:"
msgstr ""
-#: templates/web/base/admin/body-form.html:130
+#: templates/web/base/admin/body-form.html:126
msgid "Endpoint"
msgstr ""
-#: perllib/FixMyStreet/Cobrand/Zurich.pm:73
+#: perllib/FixMyStreet/Cobrand/Zurich.pm:76
msgid "Enter a Z&uuml;rich street name"
-msgstr "Ungef&auml;hre Adresse des Mangels"
+msgstr "Ungef&auml;hre Adresse des Schadens"
#: perllib/FixMyStreet/Cobrand/UK.pm:13
msgid "Enter a nearby UK postcode, or street name and area"
@@ -900,21 +912,19 @@ msgstr "Geben Sie eine Adresse an"
#: perllib/FixMyStreet/Cobrand/FiksGataMi.pm:20
#: perllib/FixMyStreet/Cobrand/FixaMinGata.pm:21
msgid "Enter a nearby postcode, or street name and area"
-msgstr "Ungef&auml;hre Adresse des Mangels"
+msgstr "Ungef&auml;hre Adresse des Schadens"
-#: templates/web/base/around/postcode_form.html:1
#: templates/web/base/around/postcode_form.html:2
-#: templates/web/fixmystreet/around/postcode_form.html:10
#: templates/web/fixmystreet/around/postcode_form.html:11
msgid "Enter a nearby street name and area"
-msgstr "Ungef&auml;hre Adresse des Mangels"
+msgstr "Ungef&auml;hre Adresse des Schadens"
#: perllib/FixMyStreet/Cobrand/ZeroTB.pm:7
msgid "Enter a nearby street name and area, postal code or district in Delhi"
msgstr ""
#: templates/web/base/auth/general.html:64
-#: templates/web/base/report/new/fill_in_details_form.html:151
+#: templates/web/base/report/new/fill_in_details_form.html:170
#: templates/web/base/report/update-form.html:124
msgid "Enter a new password:"
msgstr ""
@@ -926,9 +936,9 @@ msgstr ""
msgid "Enter a password"
msgstr "Ihr Passwort"
-#: templates/web/base/index-steps.html:26
+#: templates/web/base/index-steps.html:33
msgid "Enter details of the problem"
-msgstr "Beschreiben Sie den Mangel"
+msgstr "Beschreiben Sie den Schaden"
#: templates/web/base/auth/token.html:5
#: templates/web/base/errors/generic.html:1
@@ -949,16 +959,17 @@ msgstr "Beispieladresse"
msgid "Examples:"
msgstr "Beispiele:"
-#: templates/web/fixmystreet/report/new/fill_in_details_form.html:55
+#: templates/web/fixmystreet/report/new/fill_in_details_form.html:47
msgid "Explain what’s wrong, exactly where it is, and how long it’s been there…"
msgstr ""
-#: templates/web/base/admin/body-form.html:81
-msgid "External URL"
+#: perllib/FixMyStreet/Cobrand/Zurich.pm:170
+#: perllib/FixMyStreet/Cobrand/Zurich.pm:908
+#: templates/web/zurich/admin/header.html:12
+msgid "Extern"
msgstr ""
-#: templates/web/base/admin/category_edit.html:27
-#: templates/web/base/admin/report_edit.html:92
+#: templates/web/base/admin/report_edit.html:76
msgid "Extra data:"
msgstr ""
@@ -976,7 +987,7 @@ msgstr "Alle Meldungen"
msgid "First time"
msgstr ""
-#: templates/web/base/admin/body.html:48
+#: templates/web/base/admin/body.html:40
msgid "Fix this by choosing an <strong>area covered</strong> in the <em>Edit body details</em> form below."
msgstr ""
@@ -1007,31 +1018,24 @@ msgid ""
msgstr ""
#: templates/web/base/admin/index.html:55
-#: templates/web/base/admin/report_edit.html:48
-#: templates/web/base/admin/report_edit.html:54
-#: templates/web/base/admin/report_edit.html:55
-#: templates/web/base/dashboard/index.html:142
+#: templates/web/base/admin/report_edit.html:41
+#: templates/web/base/admin/report_edit.html:42
#: templates/web/base/dashboard/index.html:144
-#: templates/web/base/report/update-form.html:30
#: templates/web/base/report/update-form.html:34
#: templates/web/fixmystreet/report/banner.html:12
-#: templates/web/fixmystreet/report/update-form.html:28
#: templates/web/fixmystreet/report/update-form.html:32
msgid "Fixed"
msgstr "Beantwortet"
-#: templates/web/base/admin/report_edit.html:48
-#: templates/web/base/admin/report_edit.html:56
+#: templates/web/base/admin/report_edit.html:43
msgid "Fixed - Council"
msgstr ""
-#: templates/web/base/admin/report_edit.html:48
-#: templates/web/base/admin/report_edit.html:55
+#: templates/web/base/admin/report_edit.html:42
msgid "Fixed - User"
msgstr ""
-#: templates/web/base/my/my.html:35
-#: templates/web/fixmystreet/my/_problem-list.html:7
+#: templates/web/base/my/my.html:35 templates/web/fixmystreet/my/my.html:41
msgid "Fixed reports"
msgstr ""
@@ -1039,7 +1043,7 @@ msgstr ""
msgid "Fixed:"
msgstr ""
-#: templates/web/base/admin/body-form.html:89
+#: templates/web/base/admin/body-form.html:84
#: templates/web/zurich/admin/body-form.html:36
msgid "Flag as deleted"
msgstr "Als gel&#246;scht markieren"
@@ -1048,7 +1052,7 @@ msgstr "Als gel&#246;scht markieren"
msgid "Flag user"
msgstr ""
-#: perllib/FixMyStreet/App/Controller/Admin.pm:1197
+#: perllib/FixMyStreet/App/Controller/Admin.pm:1290
#: templates/web/base/admin/users.html:19
msgid "Flagged"
msgstr ""
@@ -1057,7 +1061,7 @@ msgstr ""
msgid "Flagged reports and users"
msgstr ""
-#: templates/web/base/admin/user-form.html:46
+#: templates/web/base/admin/user-form.html:45
msgid "Flagged users are listed on the <a href='%s'>flagged</a> page."
msgstr ""
@@ -1065,8 +1069,8 @@ msgstr ""
msgid "Flagged users are not restricted in any way. This is just a list of users that have been marked for attention."
msgstr ""
-#: templates/web/base/admin/report_edit.html:94
-#: templates/web/base/admin/user-form.html:52
+#: templates/web/base/admin/report_edit.html:78
+#: templates/web/base/admin/user-form.html:51
msgid "Flagged:"
msgstr ""
@@ -1075,6 +1079,10 @@ msgstr ""
msgid "Follow a ward link to view only reports within that ward."
msgstr ""
+#: templates/web/base/admin/report_edit.html:30
+msgid "For council(s):"
+msgstr ""
+
#: templates/web/base/admin/body-form.html:65
msgid "For more information, see <a href='http://fixmystreet.org/customising/fms_and_mapit' class='admin-offsite-link'>How FixMyStreet uses Mapit</a>."
msgstr ""
@@ -1084,8 +1092,15 @@ msgstr ""
msgid "Forgotten your password?"
msgstr "Ihr Passwort"
+#: perllib/FixMyStreet/Cobrand/Zurich.pm:738
+msgid "Forwarded to external body"
+msgstr "An externe Stelle weitergeleitet"
+
+#: perllib/FixMyStreet/Cobrand/Zurich.pm:739
+msgid "Forwarded wish to external body"
+msgstr "Wunsch an externe Stelle weitergeleitet"
+
#: templates/web/base/faq/faq-en-gb.html:1
-#: templates/web/base/static/privacy.html:1
#: templates/web/base/static/privacy.html:2
msgid "Frequently Asked Questions"
msgstr "Hilfe"
@@ -1099,13 +1114,11 @@ msgstr ""
msgid "Get updates"
msgstr ""
-#: templates/web/fixmystreet/reports/_rss.html:3
#: templates/web/fixmystreet/reports/_rss.html:9
msgid "Get updates of %s problems"
-msgstr "Beschreiben Sie den Mangel"
+msgstr "Beschreiben Sie den Schaden"
#: templates/web/fixmystreet/reports/_rss.html:11
-#: templates/web/fixmystreet/reports/_rss.html:3
msgid "Get updates of problems in this %s"
msgstr ""
@@ -1125,7 +1138,7 @@ msgstr ""
msgid "Go"
msgstr "Los"
-#: templates/web/base/admin/report_edit.html:93
+#: templates/web/base/admin/report_edit.html:77
msgid "Going to send questionnaire?"
msgstr ""
@@ -1149,7 +1162,7 @@ msgstr ""
#: templates/web/base/footer.html:15 templates/web/fixmystreet/footer.html:30
#: templates/web/zurich/faq/faq-de-ch.html:1
-#: templates/web/zurich/footer.html:21
+#: templates/web/zurich/footer.html:22
#: templates/web/zurich/nav_over_content.html:8
msgid "Help"
msgstr "Hilfe"
@@ -1159,19 +1172,16 @@ msgstr "Hilfe"
msgid "Here are the types of local problem alerts for &lsquo;%s&rsquo;."
msgstr ""
-#: templates/web/fixmystreet/header.html:58
-#: templates/web/zurich/footer.html:11
+#: templates/web/fixmystreet/header.html:52
+#: templates/web/zurich/footer.html:12
msgid "Hi %s"
msgstr "Hallo %s"
-#: templates/web/base/admin/report_edit.html:48
-#: templates/web/base/admin/report_edit.html:63
-#: templates/web/base/admin/report_edit.html:64
+#: perllib/FixMyStreet/Cobrand/Zurich.pm:901
+#: templates/web/base/admin/report_edit.html:50
+#: templates/web/base/admin/report_edit.html:51
#: templates/web/base/admin/update_edit.html:28
-#: templates/web/zurich/admin/header.html:1
#: templates/web/zurich/admin/header.html:11
-#: templates/web/zurich/admin/report_edit.html:86
-#: templates/web/zurich/admin/report_edit.html:90
#: templates/web/zurich/admin/stats.html:32
#: templates/web/zurich/admin/update_edit.html:18
msgid "Hidden"
@@ -1185,7 +1195,7 @@ msgstr "Alte ausblenden"
msgid "Hide pins"
msgstr "Stecknadeln ausblenden"
-#: templates/web/base/admin/category_edit.html:84
+#: templates/web/base/admin/category_edit.html:82
msgid "History"
msgstr "History"
@@ -1201,16 +1211,14 @@ msgstr "Erfassen Sie eine neue Meldung:"
msgid "How to send successful reports"
msgstr "Anleitung"
-#: perllib/FixMyStreet/App/Controller/Admin.pm:740
+#: perllib/FixMyStreet/App/Controller/Admin.pm:757
msgid "I am afraid you cannot confirm unconfirmed reports."
msgstr ""
-#: templates/web/base/tokens/confirm_problem.html:23
#: templates/web/base/tokens/confirm_problem.html:27
msgid "I just reported a problem on @fixmystreet"
msgstr ""
-#: templates/web/base/tokens/confirm_update.html:19
#: templates/web/base/tokens/confirm_update.html:23
msgid "I just updated a problem on @fixmystreet"
msgstr ""
@@ -1219,7 +1227,11 @@ msgstr ""
msgid "I'm afraid we couldn't locate your problem in the database.\n"
msgstr ""
-#: perllib/FixMyStreet/App/Controller/Tokens.pm:327
+#: perllib/FixMyStreet/App/Controller/Tokens.pm:54
+msgid "I'm afraid we couldn't validate that token, as the report was made too long ago."
+msgstr ""
+
+#: perllib/FixMyStreet/App/Controller/Tokens.pm:282
msgid "I'm afraid we couldn't validate that token. If you've copied the URL from an email, please check that you copied it exactly.\n"
msgstr "Leider konnte Ihre URL nicht aufgel&ouml;st werden. Falls Sie die URL aus einer Mail kopiert haben, &uuml;berpr&uuml;fen Sie bitte ob Sie die gesamte URL kopiert haben.\n"
@@ -1228,20 +1240,19 @@ msgstr "Leider konnte Ihre URL nicht aufgel&ouml;st werden. Falls Sie die URL au
#: templates/web/base/admin/reports.html:11
#: templates/web/zurich/admin/index-dm.html:21
#: templates/web/zurich/admin/index-sdm.html:19
-#: templates/web/zurich/admin/list_updates.html:28
-#: templates/web/zurich/admin/list_updates.html:7
+#: templates/web/zurich/admin/list_updates.html:22
+#: templates/web/zurich/admin/list_updates.html:36
#: templates/web/zurich/admin/reports.html:11
msgid "ID"
msgstr "ID"
-#: templates/web/base/admin/body-form.html:24
#: templates/web/base/admin/body-form.html:25
msgid ""
"Identify a <strong>parent</strong> if this body is itself part of another body.\n"
" For basic installations, you don't need to join bodies in this way."
msgstr ""
-#: templates/web/base/admin/body.html:133
+#: templates/web/base/admin/body.html:125
msgid ""
"If two or more bodies serve the same location, FixMyStreet combines identical categories into a single entry in\n"
" the menu. Make sure you use the same category name in the bodies if you want this to happen."
@@ -1263,7 +1274,6 @@ msgstr ""
msgid "If you get some more information about the status of your problem, please come back to the site and leave an update."
msgstr ""
-#: templates/web/base/report/new/councils_text_none.html:2
#: templates/web/base/report/new/councils_text_none.html:8
msgid "If you submit a problem here the subject and details of the problem will be public, but the problem will <strong>not</strong> be reported to the council."
msgstr ""
@@ -1280,27 +1290,24 @@ msgid ""
"your experience of getting the problem fixed?"
msgstr ""
-#: templates/web/base/admin/body.html:149
+#: templates/web/base/admin/body.html:141
msgid "If you're using <strong>a send method that is not email</strong>, enter the service ID (Open311) or equivalent identifier here."
msgstr ""
-#: templates/web/base/admin/body-form.html:207
-#: templates/web/base/admin/body-form.html:208
+#: templates/web/base/admin/body-form.html:201
msgid ""
"If you've enabled Open311 update-sending above, Open311 usually only accepts OPEN or CLOSED status in \n"
" its updates. Enable <strong>extended Open311 stauses</strong> if you want to allow extra states to be passed.\n"
" Check that your cobrand supports this feature before switching it on."
msgstr ""
-#: templates/web/base/admin/body-form.html:194
-#: templates/web/base/admin/body-form.html:195
+#: templates/web/base/admin/body-form.html:188
msgid ""
"If you've enabled Open311 update-sending above, enable <strong>suppression of alerts</strong> \n"
" if you do <strong>not</strong> want that user to be notified whenever these updates are created."
msgstr ""
-#: templates/web/base/admin/body-form.html:177
-#: templates/web/base/admin/body-form.html:178
+#: templates/web/base/admin/body-form.html:174
msgid ""
"If you've enabled Open311 update-sending above, you must identify which \n"
" FixMyStreet <strong>user</strong> will be attributed as the creator of those updates\n"
@@ -1315,11 +1322,8 @@ msgstr "Unbekannt ID"
msgid "Illegal feed selection"
msgstr ""
-#: templates/web/base/dashboard/index.html:142
#: templates/web/base/dashboard/index.html:144
-#: templates/web/base/report/update-form.html:30
#: templates/web/base/report/update-form.html:32
-#: templates/web/fixmystreet/report/update-form.html:28
#: templates/web/fixmystreet/report/update-form.html:30
msgid "In Progress"
msgstr "In Bearbeitung"
@@ -1332,14 +1336,11 @@ msgstr ""
msgid "In addition, the following attributes that are not part of the Open311 v2 specification are returned: agency_sent_datetime, title (also returned as part of description), interface_used, comment_count, requestor_name (only present if requestor allowed the name to be shown on this site)."
msgstr ""
-#: perllib/FixMyStreet/Cobrand/Zurich.pm:144
-#: templates/web/base/admin/report_edit.html:48
-#: templates/web/base/admin/report_edit.html:51
+#: perllib/FixMyStreet/Cobrand/Zurich.pm:188
+#: perllib/FixMyStreet/Cobrand/Zurich.pm:949
+#: templates/web/base/admin/report_edit.html:38
#: templates/web/fixmystreet/report/banner.html:19
-#: templates/web/zurich/admin/header.html:1
#: templates/web/zurich/admin/header.html:8
-#: templates/web/zurich/admin/report_edit.html:99
-#: templates/web/zurich/report/banner.html:15
msgid "In progress"
msgstr "In Bearbeitung"
@@ -1347,7 +1348,7 @@ msgstr "In Bearbeitung"
msgid "Inbox zero, here we come!"
msgstr ""
-#: templates/web/zurich/admin/report_edit.html:160
+#: templates/web/zurich/admin/report_edit.html:282
msgid "Include reporter personal details"
msgstr "Pers&ouml;nliche Angaben des Meldenden mitsenden"
@@ -1359,12 +1360,11 @@ msgstr ""
msgid "Incorrect has_photo value \"%s\""
msgstr ""
-#: templates/web/zurich/admin/list_updates.html:3
+#: templates/web/zurich/admin/list_updates.html:33
msgid "Internal notes"
msgstr "Interne Notizen"
#: templates/web/base/admin/report_edit.html:48
-#: templates/web/base/admin/report_edit.html:61
msgid "Internal referral"
msgstr ""
@@ -1372,7 +1372,7 @@ msgstr ""
msgid "Invalid agency_responsible value %s"
msgstr ""
-#: perllib/FixMyStreet/App/Controller/Admin.pm:1112
+#: perllib/FixMyStreet/App/Controller/Admin.pm:1205
msgid "Invalid end date"
msgstr "Ung&ultiges Enddatum"
@@ -1380,17 +1380,13 @@ msgstr "Ung&ultiges Enddatum"
msgid "Invalid format %s specified."
msgstr ""
-#: perllib/FixMyStreet/App/Controller/Admin.pm:1108
+#: perllib/FixMyStreet/App/Controller/Admin.pm:1201
msgid "Invalid start date"
msgstr "Ung&ultiges Startdatum"
-#: templates/web/base/admin/report_edit.html:48
-#: templates/web/base/admin/report_edit.html:50
-#: templates/web/base/dashboard/index.html:142
+#: templates/web/base/admin/report_edit.html:37
#: templates/web/base/dashboard/index.html:143
-#: templates/web/base/report/update-form.html:30
#: templates/web/base/report/update-form.html:31
-#: templates/web/fixmystreet/report/update-form.html:28
#: templates/web/fixmystreet/report/update-form.html:29
msgid "Investigating"
msgstr ""
@@ -1403,8 +1399,17 @@ msgstr ""
msgid "It’s on its way to the council right now."
msgstr ""
+#: perllib/FixMyStreet/Cobrand/Zurich.pm:173
+msgid "Jurisdiction Unknown"
+msgstr "Zust&auml;ndigkeit unbekannt"
+
+#: perllib/FixMyStreet/Cobrand/Zurich.pm:913
+#: templates/web/zurich/admin/header.html:15
+msgid "Jurisdiction unknown"
+msgstr "Zust&auml;ndigkeit unbekannt"
+
#: templates/web/base/auth/general.html:44
-#: templates/web/base/report/new/fill_in_details_form.html:131
+#: templates/web/base/report/new/fill_in_details_form.html:150
#: templates/web/base/report/update-form.html:104
#: templates/web/fixmystreet/auth/general.html:47
#: templates/web/fixmystreet/report/new/form_user_loggedout.html:28
@@ -1413,12 +1418,12 @@ msgstr ""
msgid "Keep me signed in on this computer"
msgstr "Angemeldet bleiben"
-#: templates/web/base/admin/body.html:70
+#: templates/web/base/admin/body.html:62
#: templates/web/zurich/admin/body.html:16
msgid "Last editor"
msgstr "Letzter Bearbeiter"
-#: templates/web/base/admin/report_edit.html:88
+#: templates/web/base/admin/report_edit.html:72
msgid "Last update:"
msgstr "Letzte Bearbeitung"
@@ -1426,29 +1431,30 @@ msgstr "Letzte Bearbeitung"
msgid "Last&nbsp;update:"
msgstr "Letzte Bearbeitung"
-#: templates/web/base/admin/body-form.html:229
+#: templates/web/base/admin/body-form.html:222
msgid "Leave this blank if all reports to this body should be sent using the same send method (e.g., \"%s\")."
msgstr ""
-#: templates/web/base/admin/body.html:27
+#: templates/web/base/admin/body.html:17 templates/web/base/admin/body.html:19
msgid "List all reported problems"
msgstr "Liste aller Meldungen"
-#: templates/web/base/report/new/category_wrapper.html:4
+#: templates/web/base/report/new/fill_in_details_form.html:69
+#: templates/web/fixmystreet/report/new/fill_in_details_form.html:54
+#: templates/web/zurich/report/new/fill_in_details_form.html:51
msgid "Loading..."
msgstr ""
#: templates/web/base/alert/choose.html:1
#: templates/web/base/alert/choose.html:3
#: templates/web/base/alert/index.html:1 templates/web/base/alert/index.html:3
-#: templates/web/base/alert/list.html:1 templates/web/base/alert/list.html:5
+#: templates/web/base/alert/list.html:5
#: templates/web/base/alert/updates.html:1
#: templates/web/base/tokens/confirm_alert.html:1
#: templates/web/fixmystreet/alert/updates.html:1
msgid "Local RSS feeds and email alerts"
msgstr ""
-#: templates/web/base/alert/list.html:1 templates/web/base/alert/list.html:12
#: templates/web/base/alert/list.html:14 templates/web/base/alert/list.html:3
msgid "Local RSS feeds and email alerts for ‘%s’"
msgstr ""
@@ -1457,39 +1463,34 @@ msgstr ""
msgid "Local alerts"
msgstr "RSS"
-#: templates/web/base/index-steps.html:25
+#: templates/web/base/index-steps.html:31
msgid "Locate the problem on a map of the area"
-msgstr "Lokalisieren Sie den Mangel auf der Karte"
+msgstr "Lokalisieren Sie den Schaden auf der Karte"
#: templates/web/base/js/translation_strings.html:43
msgid "MAP"
msgstr ""
#: templates/web/base/js/translation_strings.html:45
-#: templates/web/base/maps/google-ol.html:13
msgid "Map"
msgstr ""
-#: templates/web/base/admin/report_edit.html:86
-msgid "Mark as sent"
-msgstr ""
-
-#: templates/web/base/admin/user-form.html:44
+#: templates/web/base/admin/user-form.html:43
msgid "Mark users whose behaviour you want to keep a check on as <strong>flagged</strong>."
msgstr ""
-#: templates/web/base/reports/index.html:24
-msgid "Marked fixed/closed in the past eight weeks"
-msgstr ""
-
-#: templates/web/base/reports/index.html:25
-msgid "Marked fixed/closed more than eight weeks ago"
-msgstr ""
-
#: templates/web/fixmystreet/contact/index.html:106
msgid "Message"
msgstr "Nachricht"
+#: templates/web/zurich/admin/report_edit.html:339
+msgid "Message to competent body:"
+msgstr "Nachricht an zuständige Stelle"
+
+#: templates/web/zurich/admin/report_edit.html:337
+msgid "Message to external body:"
+msgstr "Nachricht an zuständige Stelle"
+
#: templates/web/base/contact/index.html:97
msgid "Message:"
msgstr "Nachricht:"
@@ -1524,15 +1525,13 @@ msgstr "Meldungen in der Nähe"
#: templates/web/fixmystreet/report/update-form.html:138
#: templates/web/zurich/admin/body-form.html:4
#: templates/web/zurich/auth/general.html:60
-#: templates/web/zurich/report/new/fill_in_details_form.html:77
+#: templates/web/zurich/report/new/fill_in_details_form.html:99
msgid "Name"
msgstr "Name"
-#: templates/web/base/admin/report_edit.html:79
+#: templates/web/base/admin/report_edit.html:66
#: templates/web/base/admin/update_edit.html:32
#: templates/web/base/admin/user-form.html:18
-#: templates/web/zurich/admin/report_edit-sdm.html:43
-#: templates/web/zurich/admin/report_edit.html:56
#: templates/web/zurich/admin/stats.html:41
msgid "Name:"
msgstr "Name:"
@@ -1550,12 +1549,12 @@ msgstr ""
msgid "Nearest postcode to the pin placed on the map (automatically generated): %s (%sm away)"
msgstr ""
-#: perllib/FixMyStreet/Cobrand/Default.pm:442
-#: perllib/FixMyStreet/Cobrand/Default.pm:482
+#: perllib/FixMyStreet/Cobrand/Default.pm:424
+#: perllib/FixMyStreet/Cobrand/Default.pm:464
msgid "Nearest road to the pin placed on the map (automatically generated by Bing Maps): %s"
msgstr ""
-#: perllib/FixMyStreet/DB/ResultSet/AlertType.pm:277
+#: perllib/FixMyStreet/DB/ResultSet/AlertType.pm:278
msgid ""
"Nearest road to the pin placed on the map (automatically generated by Bing Maps): %s\n"
"\n"
@@ -1569,16 +1568,16 @@ msgstr "Fast Fertig! Bitte checken Sie Ihre Mailbox..."
msgid "New <br>problems"
msgstr "Neue <br>Meldungen"
-#: perllib/FixMyStreet/App/Controller/Admin.pm:261
+#: perllib/FixMyStreet/App/Controller/Admin.pm:265
msgid "New body added"
msgstr "Neue Organisation hinzugef&uuml;gt"
-#: perllib/FixMyStreet/App/Controller/Admin.pm:379
+#: perllib/FixMyStreet/App/Controller/Admin.pm:391
msgid "New category contact added"
msgstr ""
-#: templates/web/zurich/admin/report_edit-sdm.html:55
-#: templates/web/zurich/admin/report_edit.html:81
+#: templates/web/zurich/admin/report_edit-sdm.html:113
+#: templates/web/zurich/admin/report_edit.html:141
msgid "New internal note:"
msgstr "Neue interne Notiz"
@@ -1590,6 +1589,10 @@ msgstr ""
msgid "New local reports on reportemptyhomes.com"
msgstr ""
+#: templates/web/zurich/admin/report_edit-sdm.html:117
+msgid "New note to DM:"
+msgstr "Neue Nachricht an die Kommunikation"
+
#: db/alert_types.pl:38
msgid "New problems for {{COUNCIL}} within {{WARD}} ward on FixMyStreet"
msgstr ""
@@ -1638,23 +1641,24 @@ msgstr ""
msgid "New state"
msgstr "Neuer Status"
-#: templates/web/zurich/admin/report_edit-sdm.html:58
-msgid "New update:"
-msgstr "Neue Antwort"
+#: templates/web/zurich/admin/template_edit.html:9
+#: templates/web/zurich/admin/templates.html:26
+msgid "New template"
+msgstr "Neue Vorlage"
#: templates/web/base/pagination.html:13
msgid "Next"
msgstr "Weiter"
-#: templates/web/base/admin/body.html:80 templates/web/base/admin/body.html:82
-#: templates/web/base/admin/body.html:86 templates/web/base/admin/body.html:88
+#: templates/web/base/admin/body.html:72 templates/web/base/admin/body.html:74
+#: templates/web/base/admin/body.html:78 templates/web/base/admin/body.html:80
#: templates/web/base/admin/category_edit.html:4
#: templates/web/base/admin/list_updates.html:32
#: templates/web/base/admin/list_updates.html:34
#: templates/web/base/admin/list_updates.html:35
#: templates/web/base/admin/problem_row.html:20
+#: templates/web/base/admin/report_edit.html:64
#: templates/web/base/admin/report_edit.html:77
-#: templates/web/base/admin/report_edit.html:93
#: templates/web/base/admin/update_edit.html:25
#: templates/web/base/questionnaire/creator_fixed.html:16
#: templates/web/base/questionnaire/index.html:44
@@ -1688,7 +1692,8 @@ msgstr ""
msgid "No flagged users found."
msgstr ""
-#: templates/web/zurich/admin/report_edit-sdm.html:65
+#: templates/web/zurich/admin/report_edit-sdm.html:138
+#: templates/web/zurich/admin/report_edit.html:318
msgid "No further updates"
msgstr "Bearbeitung abschliessen"
@@ -1706,25 +1711,20 @@ msgstr "Bisher wurden noch keine Meldungen erfasst."
msgid "No result returned"
msgstr ""
-#: templates/web/base/admin/body-form.html:60
#: templates/web/base/admin/body-form.html:61
msgid ""
"No specific areas are currently available, because the <code>MAPIT_URL</code> in\n"
" your config file is not pointing to a live MapIt service."
msgstr ""
-#: templates/web/base/report/_support.html:2
#: templates/web/base/report/_support.html:4
msgid "No supporters"
msgstr ""
-#: templates/web/base/admin/report_edit.html:41
-#: templates/web/zurich/admin/report_edit-sdm.html:46
-#: templates/web/zurich/admin/report_edit.html:60
+#: templates/web/base/admin/report_edit.html:30
msgid "None"
msgstr "Keine"
-#: templates/web/base/admin/user-form.html:24
#: templates/web/base/admin/user-form.html:25
msgid ""
"Normal (public) users should not be associated with any <strong>body</strong>.<br>\n"
@@ -1733,16 +1733,19 @@ msgid ""
" activity across their body), the ability to hide reports or set special report statuses."
msgstr ""
-#: templates/web/base/admin/report_edit.html:48
-#: templates/web/base/admin/report_edit.html:59
-#: templates/web/base/report/update-form.html:30
+#: templates/web/base/admin/report_edit.html:46
#: templates/web/base/report/update-form.html:33
-#: templates/web/fixmystreet/report/update-form.html:28
#: templates/web/fixmystreet/report/update-form.html:31
msgid "Not Responsible"
msgstr ""
-#: templates/web/zurich/admin/report_edit-sdm.html:18
+#: perllib/FixMyStreet/Cobrand/Zurich.pm:177
+#: perllib/FixMyStreet/Cobrand/Zurich.pm:923
+#: templates/web/zurich/admin/header.html:13
+msgid "Not contactable"
+msgstr "Nicht kontaktierbar"
+
+#: templates/web/zurich/admin/report_edit-sdm.html:108
msgid "Not for my subdivision"
msgstr "Anderer Fachbereich zust&auml;ndig"
@@ -1750,12 +1753,12 @@ msgstr "Anderer Fachbereich zust&auml;ndig"
msgid "Not reported before"
msgstr ""
-#: templates/web/base/report/_main.html:62
+#: templates/web/base/report/_main.html:61
msgid "Not reported to council"
msgstr ""
-#: templates/web/base/admin/body.html:71
-#: templates/web/base/admin/category_edit.html:92
+#: templates/web/base/admin/body.html:63
+#: templates/web/base/admin/category_edit.html:90
#: templates/web/zurich/admin/body.html:17
msgid "Note"
msgstr ""
@@ -1764,8 +1767,8 @@ msgstr ""
msgid "Note that when including unconfirmed reports we use the date the report was created which may not be in the same month the report was confirmed so the numbers may jump about a little"
msgstr ""
-#: templates/web/base/admin/body.html:186
-#: templates/web/base/admin/category_edit.html:49
+#: templates/web/base/admin/body.html:178
+#: templates/web/base/admin/category_edit.html:47
#: templates/web/zurich/admin/body.html:53
msgid "Note:"
msgstr ""
@@ -1774,11 +1777,15 @@ msgstr ""
msgid "Note: <strong>%s</strong>"
msgstr ""
+#: templates/web/zurich/admin/list_updates.html:19
+msgid "Notes from SDM to DM"
+msgstr "Nachrichten an die Kommunikationstelle"
+
#: templates/web/fixmystreet/report/new/form_user_loggedout.html:10
msgid "Now to submit your report&hellip;"
msgstr ""
-#: templates/web/base/report/new/fill_in_details_form.html:113
+#: templates/web/base/report/new/fill_in_details_form.html:132
msgid "Now to submit your report&hellip; do you have a FixMyStreet password?"
msgstr ""
@@ -1815,40 +1822,27 @@ msgstr ""
msgid "Older <br>problems"
msgstr ""
-#: templates/web/fixmystreet/report/new/fill_in_details_form.html:45
+#: templates/web/fixmystreet/report/new/fill_in_details_form.html:37
msgid "One-line summary"
msgstr ""
-#: perllib/FixMyStreet/Cobrand/Zurich.pm:138
-#: templates/web/base/admin/report_edit.html:48
-#: templates/web/base/admin/report_edit.html:49
-#: templates/web/base/admin/report_edit.html:50
+#: perllib/FixMyStreet/Cobrand/Zurich.pm:165
+#: perllib/FixMyStreet/Cobrand/Zurich.pm:895
+#: templates/web/base/admin/report_edit.html:36
+#: templates/web/base/admin/report_edit.html:37
#: templates/web/base/admin/update_edit.html:28
#: templates/web/base/dashboard/index.html:142
#: templates/web/base/report/update-form.html:30
#: templates/web/fixmystreet/report/update-form.html:28
-#: templates/web/zurich/admin/header.html:1
#: templates/web/zurich/admin/header.html:7
-#: templates/web/zurich/admin/report_edit.html:86
-#: templates/web/zurich/admin/report_edit.html:88
#: templates/web/zurich/admin/update_edit.html:18
-#: templates/web/zurich/report/banner.html:11
msgid "Open"
msgstr "Aufgenommen"
-#: templates/web/base/reports/index.html:22
-msgid "Open for more than four weeks, with an update within the past eight weeks"
-msgstr ""
-
-#: templates/web/base/my/my.html:30
-#: templates/web/fixmystreet/my/_problem-list.html:2
+#: templates/web/base/my/my.html:30 templates/web/fixmystreet/my/my.html:36
msgid "Open reports"
msgstr "Offene Meldungen"
-#: templates/web/base/reports/index.html:23
-msgid "Open, but not had any update in eight weeks"
-msgstr ""
-
#: templates/web/base/open311/index.html:70
msgid "Open311 API for the mySociety FixMyStreet server"
msgstr ""
@@ -1871,13 +1865,13 @@ msgstr ""
msgid "Or you can subscribe to an alert based upon what ward or council you&rsquo;re in:"
msgstr ""
-#: perllib/FixMyStreet/App/Controller/Report/New.pm:1061
-#: perllib/FixMyStreet/App/Controller/Report/New.pm:666
-#: perllib/FixMyStreet/App/Controller/Report/New.pm:667
-#: perllib/FixMyStreet/DB/Result/Problem.pm:565
-#: perllib/FixMyStreet/DB/Result/Problem.pm:575
-#: perllib/FixMyStreet/DB/Result/Problem.pm:585
-#: perllib/FixMyStreet/DB/Result/Problem.pm:597
+#: perllib/FixMyStreet/App/Controller/Report/New.pm:1056
+#: perllib/FixMyStreet/App/Controller/Report/New.pm:651
+#: perllib/FixMyStreet/App/Controller/Report/New.pm:652
+#: perllib/FixMyStreet/DB/Result/Problem.pm:591
+#: perllib/FixMyStreet/DB/Result/Problem.pm:601
+#: perllib/FixMyStreet/DB/Result/Problem.pm:611
+#: perllib/FixMyStreet/DB/Result/Problem.pm:623
#: perllib/FixMyStreet/DB/ResultSet/Problem.pm:378
#: perllib/FixMyStreet/DB/ResultSet/Problem.pm:393
msgid "Other"
@@ -1901,8 +1895,7 @@ msgstr ""
msgid "Parent"
msgstr "Geh&ouml;rt zu"
-#: templates/web/base/admin/report_edit.html:48
-#: templates/web/base/admin/report_edit.html:64
+#: templates/web/base/admin/report_edit.html:51
msgid "Partial"
msgstr ""
@@ -1922,7 +1915,7 @@ msgstr ""
msgid "Permalink"
msgstr ""
-#: templates/web/zurich/report/new/fill_in_details_form.html:83
+#: templates/web/zurich/report/new/fill_in_details_form.html:105
msgid "Phone number"
msgstr "Telefonnummer"
@@ -1932,26 +1925,32 @@ msgid "Phone number (optional)"
msgstr "Telefonnummer (optional)"
#: perllib/FixMyStreet/DB/ResultSet/Problem.pm:291
-#: templates/web/base/admin/report_edit.html:81
-#: templates/web/base/report/new/fill_in_details_form.html:197
-#: templates/web/zurich/admin/report_edit-sdm.html:46
-#: templates/web/zurich/admin/report_edit.html:60
+#: templates/web/base/admin/report_edit.html:68
+#: templates/web/base/report/new/fill_in_details_form.html:216
#: templates/web/zurich/admin/stats.html:39
msgid "Phone:"
msgstr "Telefonnummer:"
-#: templates/web/fixmystreet/report/new/fill_in_details_form.html:66
+#: templates/web/fixmystreet/report/new/fill_in_details_form.html:72
#: templates/web/fixmystreet/report/update-form.html:59
#: templates/web/zurich/admin/index-dm.html:29
#: templates/web/zurich/admin/index-sdm.html:24
#: templates/web/zurich/admin/reports.html:16
#: templates/web/zurich/admin/stats.html:37
-#: templates/web/zurich/report/new/fill_in_details_form.html:51
+#: templates/web/zurich/report/new/fill_in_details_form.html:69
msgid "Photo"
msgstr "Foto"
+#: perllib/FixMyStreet/App/Controller/Photo.pm:201
+msgid "Photo is required."
+msgstr "Foto wird ben&ouml;tigt"
+
+#: templates/web/base/admin/category_edit.html:43
+msgid "Photo required"
+msgstr "Foto ben&ouml;tigt"
+
#: templates/web/base/questionnaire/index.html:71
-#: templates/web/base/report/new/fill_in_details_form.html:84
+#: templates/web/base/report/new/fill_in_details_form.html:103
#: templates/web/base/report/update-form.html:62
#: templates/web/fixmystreet/questionnaire/index.html:91
msgid "Photo:"
@@ -1965,15 +1964,12 @@ msgstr "Fotos von neuen Meldungen in der N&auml;he"
msgid "Place pin on map"
msgstr "Pin auf der Karte absetzen"
-#: templates/web/base/admin/report_edit.html:48
-#: templates/web/base/admin/report_edit.html:51
-#: templates/web/base/dashboard/index.html:142
+#: perllib/FixMyStreet/Cobrand/Zurich.pm:935
+#: perllib/FixMyStreet/Cobrand/Zurich.pm:941
+#: templates/web/base/admin/report_edit.html:38
#: templates/web/base/dashboard/index.html:143
-#: templates/web/zurich/admin/header.html:1
#: templates/web/zurich/admin/header.html:9
#: templates/web/zurich/admin/index-dm.html:9
-#: templates/web/zurich/admin/report_edit.html:86
-#: templates/web/zurich/admin/report_edit.html:89
msgid "Planned"
msgstr "Rückmeldung ausstehend"
@@ -1985,7 +1981,6 @@ msgstr ""
msgid "Please be polite, concise and to the point."
msgstr "Bitte seien Sie freundlich und pr&auml;gnant."
-#: templates/web/base/auth/change_password.html:12
#: templates/web/base/auth/change_password.html:17
msgid "Please check the passwords and try again"
msgstr ""
@@ -1995,27 +1990,24 @@ msgid "Please check your email"
msgstr "Bitte &uuml;berpr&uuml;fen Sie Ihr E-Mail"
#: templates/web/base/auth/general.html:14
-#: templates/web/base/auth/general.html:8
-#: templates/web/fixmystreet/auth/general.html:10
#: templates/web/fixmystreet/auth/general.html:16
-#: templates/web/zurich/auth/general.html:3
#: templates/web/zurich/auth/general.html:9
msgid "Please check your email address is correct"
msgstr "Bitte &uuml;berpr&uuml;fen Sie ob Ihre E-Mail Adresse korrekt ist"
-#: perllib/FixMyStreet/App/Controller/Admin.pm:343
-#: perllib/FixMyStreet/App/Controller/Report/New.pm:876
-#: perllib/FixMyStreet/App/Controller/Report/New.pm:925
-#: perllib/FixMyStreet/DB/Result/Problem.pm:412
+#: perllib/FixMyStreet/App/Controller/Admin.pm:347
+#: perllib/FixMyStreet/App/Controller/Report/New.pm:861
+#: perllib/FixMyStreet/App/Controller/Report/New.pm:920
+#: perllib/FixMyStreet/DB/Result/Problem.pm:420
#: templates/web/base/js/translation_strings.html:9
msgid "Please choose a category"
msgstr "Bitte w&auml;hlen Sie eine Kategorie"
-#: perllib/FixMyStreet/DB/Result/Problem.pm:418
+#: perllib/FixMyStreet/DB/Result/Problem.pm:426
msgid "Please choose a property type"
msgstr ""
-#: perllib/FixMyStreet/App/Controller/Admin.pm:370
+#: perllib/FixMyStreet/App/Controller/Admin.pm:382
msgid "Please correct the errors below"
msgstr ""
@@ -2031,13 +2023,12 @@ msgstr ""
msgid "Please do not be abusive&nbsp;&mdash; abusing your council devalues the service for all users."
msgstr ""
-#: perllib/FixMyStreet/App/Controller/Admin.pm:346
+#: perllib/FixMyStreet/App/Controller/Admin.pm:350
#: perllib/FixMyStreet/DB/Result/Comment.pm:125
#: templates/web/base/js/translation_strings.html:2
msgid "Please enter a message"
msgstr ""
-#: templates/web/base/auth/change_password.html:12
#: templates/web/base/auth/change_password.html:15
#: templates/web/base/js/translation_strings.html:19
msgid "Please enter a password"
@@ -2049,9 +2040,9 @@ msgstr "Obligatorisches Feld"
msgid "Please enter a subject"
msgstr ""
-#: perllib/FixMyStreet/App/Controller/Admin.pm:1048
-#: perllib/FixMyStreet/App/Controller/Admin.pm:345
-#: perllib/FixMyStreet/App/Controller/Admin.pm:995
+#: perllib/FixMyStreet/App/Controller/Admin.pm:1088
+#: perllib/FixMyStreet/App/Controller/Admin.pm:1141
+#: perllib/FixMyStreet/App/Controller/Admin.pm:349
#: perllib/FixMyStreet/DB/Result/User.pm:127
#: templates/web/base/js/translation_strings.html:12
#: templates/web/base/js/translation_strings.html:16
@@ -2071,18 +2062,15 @@ msgstr "Bitte geben Sie einige Details an"
#: perllib/FixMyStreet/App/Controller/Contact.pm:112
#: perllib/FixMyStreet/DB/Result/User.pm:124
#: templates/web/base/auth/general.html:13
-#: templates/web/base/auth/general.html:8
#: templates/web/base/js/translation_strings.html:11
#: templates/web/base/js/translation_strings.html:15
-#: templates/web/fixmystreet/auth/general.html:10
#: templates/web/fixmystreet/auth/general.html:15
-#: templates/web/zurich/auth/general.html:3
#: templates/web/zurich/auth/general.html:8
msgid "Please enter your email"
msgstr "Ihre E-Mail Adresse"
#: templates/web/fixmystreet/report/new/form_user_loggedout.html:7
-#: templates/web/zurich/report/new/fill_in_details_form.html:75
+#: templates/web/zurich/report/new/fill_in_details_form.html:97
msgid "Please enter your email address"
msgstr "Ihre E-Mail Adresse"
@@ -2090,7 +2078,7 @@ msgstr "Ihre E-Mail Adresse"
msgid "Please enter your first name"
msgstr "Bitte geben Sie Ihren Namen an"
-#: perllib/FixMyStreet/Cobrand/UK.pm:318
+#: perllib/FixMyStreet/DB/Result/Problem.pm:413
#: templates/web/base/js/translation_strings.html:7
msgid "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"
msgstr ""
@@ -2120,20 +2108,19 @@ msgstr "Bitte geben Sie Ihre E-Mail-Adresse an"
msgid "Please feel free to <a href=\"%s\">sign in again</a>, or go back to the <a href=\"/\">front page</a>."
msgstr "<a href=\"%s\">Erneut anmelden</a> oder <a href=\"/\">zur&uuml;ck zur Startseite</a>."
-#: templates/web/base/report/new/fill_in_details_text.html:1
#: templates/web/base/report/new/fill_in_details_text.html:8
msgid "Please fill in details of the problem below."
msgstr ""
#: templates/web/zurich/report/new/fill_in_details_form.html:46
msgid "Please fill in details of the problem."
-msgstr "Beschreiben Sie den Mangel."
+msgstr "Beschreiben Sie den Schaden."
#: templates/web/base/report/new/fill_in_details_form.html:28
#: templates/web/fixmystreet/report/new/sidebar.html:7
#: templates/web/zurich/report/new/fill_in_details_form.html:20
msgid "Please fill in the form below with details of the problem, and describe the location as precisely as possible in the details box."
-msgstr "F&uuml;llen Sie das Formular mit den Details des Mangels aus und beschreiben Sie den Ort des Mangels m&ouml;glichst genau."
+msgstr "F&uuml;llen Sie das Formular mit den Details des Schadens aus und beschreiben Sie den Ort des Schadens m&ouml;glichst genau."
#: perllib/FixMyStreet/App/Controller/Questionnaire.pm:251
msgid "Please indicate whether you'd like to receive another questionnaire"
@@ -2171,6 +2158,10 @@ msgstr ""
msgid "Please say whether you've ever reported a problem to your council before"
msgstr ""
+#: templates/web/zurich/admin/report_edit.html:263
+msgid "Please select a body."
+msgstr "Organisation wählen"
+
#: perllib/FixMyStreet/App/Controller/Alert.pm:80
msgid "Please select the feed you want"
msgstr ""
@@ -2187,9 +2178,9 @@ msgstr ""
msgid "Please take a look at the updates that have been left."
msgstr ""
-#: perllib/FixMyStreet/App/Controller/Photo.pm:177
-#: perllib/FixMyStreet/App/Controller/Photo.pm:187
-#: perllib/FixMyStreet/App/Controller/Photo.pm:189
+#: perllib/FixMyStreet/App/Model/PhotoSet.pm:117
+#: perllib/FixMyStreet/App/Model/PhotoSet.pm:127
+#: perllib/FixMyStreet/App/Model/PhotoSet.pm:129
msgid "Please upload a JPEG image only"
msgstr "Bitte laden Sie nur JPEG Bilder hoch."
@@ -2232,14 +2223,15 @@ msgstr "Zur&uuml;ck"
msgid "Privacy"
msgstr ""
-#: templates/web/base/admin/body.html:202
-#: templates/web/base/admin/body.html:85
-#: templates/web/base/admin/category_edit.html:45
-#: templates/web/base/admin/report_edit.html:95
+#: templates/web/base/admin/body.html:194
+#: templates/web/base/admin/body.html:77
+#: templates/web/base/admin/category_edit.html:40
+#: templates/web/base/admin/report_edit.html:79
msgid "Private"
msgstr ""
-#: templates/web/base/maps/openlayers.html:89
+#: templates/web/base/maps/noscript_map.html:59
+#: templates/web/zurich/maps/noscript_map.html:57
msgid "Problem"
msgstr "Meldung"
@@ -2260,7 +2252,7 @@ msgstr ""
msgid "Problem breakdown by state"
msgstr "Meldungen nach Status sortiert"
-#: perllib/FixMyStreet/App/Controller/Admin.pm:966
+#: perllib/FixMyStreet/App/Controller/Admin.pm:1059
msgid "Problem marked as open."
msgstr ""
@@ -2295,7 +2287,7 @@ msgstr "Meldungen, welche k&uuml;rzlich beantwortet wurden"
msgid "Problems within %.1fkm of this location"
msgstr ""
-#: perllib/FixMyStreet/Cobrand/Default.pm:650
+#: perllib/FixMyStreet/Cobrand/Default.pm:632
#: perllib/FixMyStreet/Cobrand/EmptyHomes.pm:120
#: perllib/FixMyStreet/Cobrand/FiksGataMi.pm:139
#: perllib/FixMyStreet/Cobrand/UK.pm:207
@@ -2307,7 +2299,6 @@ msgstr "Meldungen innerhalb %s"
msgid "Problems within %s ward"
msgstr ""
-#: templates/web/base/reports/body.html:0
#: templates/web/base/reports/body.html:24
msgid "Problems within %s, FixMyStreet"
msgstr ""
@@ -2321,7 +2312,7 @@ msgstr ""
msgid "Properties recently reported as put back to use on reportemptyhomes.com"
msgstr ""
-#: templates/web/base/admin/report_edit.html:45
+#: templates/web/base/admin/report_edit.html:32
msgid "Property address:"
msgstr ""
@@ -2338,32 +2329,26 @@ msgstr "Meldung aktualisieren"
msgid "Providing a name and password is optional, but doing so will allow you to more easily report problems, leave updates and manage your reports."
msgstr ""
-#: templates/web/base/report/new/fill_in_details_form.html:155
+#: templates/web/base/report/new/fill_in_details_form.html:174
#: templates/web/base/report/update-form.html:128
#: templates/web/fixmystreet/report/new/form_user_loggedout.html:71
#: templates/web/fixmystreet/report/update-form.html:119
msgid "Providing a password is optional, but doing so will allow you to more easily report problems, leave updates and manage your reports."
msgstr ""
-#: templates/web/zurich/admin/report_edit.html:195
-#: templates/web/zurich/admin/report_edit.html:211
+#: templates/web/zurich/admin/report_edit.html:300
+#: templates/web/zurich/admin/report_edit.html:327
msgid "Public response:"
-msgstr "Offizielle Antwort"
+msgstr "R&uuml;ckmeldung an User"
-#: templates/web/zurich/admin/report_edit.html:77
+#: templates/web/zurich/admin/report_edit.html:121
#: templates/web/zurich/admin/stats.html:38
msgid "Publish photo"
msgstr "Foto ver&ouml;ffentlichen"
-#: templates/web/zurich/admin/report_edit.html:219
-msgid "Publish the response"
-msgstr "Antwort ver&ouml;ffentlichen"
-
#: templates/web/base/questionnaire/completed.html:1
-#: templates/web/base/questionnaire/index.html:0
#: templates/web/base/questionnaire/index.html:14
#: templates/web/base/questionnaire/index.html:4
-#: templates/web/fixmystreet/questionnaire/index.html:0
#: templates/web/fixmystreet/questionnaire/index.html:15
#: templates/web/fixmystreet/questionnaire/index.html:33
#: templates/web/fixmystreet/questionnaire/index.html:5
@@ -2383,7 +2368,6 @@ msgid "Questionnaire filled in by problem reporter"
msgstr ""
#: templates/web/base/alert/_list.html:21
-#: templates/web/base/around/display_location.html:1
#: templates/web/base/around/display_location.html:3
#: templates/web/base/report/display.html:50
#: templates/web/base/reports/_rss.html:1
@@ -2422,7 +2406,7 @@ msgstr ""
msgid "RSS feed of problems in this %s"
msgstr ""
-#: perllib/FixMyStreet/Cobrand/Default.pm:651
+#: perllib/FixMyStreet/Cobrand/Default.pm:633
#: perllib/FixMyStreet/Cobrand/EmptyHomes.pm:121
#: perllib/FixMyStreet/Cobrand/FiksGataMi.pm:138
#: perllib/FixMyStreet/Cobrand/UK.pm:214
@@ -2434,7 +2418,6 @@ msgstr ""
msgid "RSS feed of problems within %s ward"
msgstr ""
-#: templates/web/base/around/display_location.html:1
#: templates/web/base/around/display_location.html:4
msgid "RSS feed of recent local problems"
msgstr ""
@@ -2452,7 +2435,6 @@ msgstr ""
msgid "Receive email when updates are left on this problem."
msgstr "Erhalten Sie Aktualisierungen dieser Meldung."
-#: templates/web/base/around/display_location.html:0
#: templates/web/base/around/display_location.html:33
msgid "Recent local problems, FixMyStreet"
msgstr ""
@@ -2468,25 +2450,29 @@ msgstr "K&uuml;rzlich erfasste Meldungen:"
#: templates/web/zurich/report/new/notes.html:5
msgid "Remember that FixMyStreet is primarily for reporting physical problems that can be fixed. If your problem is not appropriate for submission via this site remember that you can contact your council directly using their own website."
-msgstr "Z&uuml;ri wie neu dient dazu M&auml;ngel an der Infrastruktur zu melden. Meldungen und W&uuml;nsche bez&uuml;glich Verbesserungen an der Infrastruktur sowie Gestaltungsvorschl&auml;ge k&ouml;nnen über Z&uuml;ri wie neu nicht ber&uuml;cksichtigt werden. Notf&auml;lle m&uuml;ssen der Polizei gemeldet werden via Telefon 117."
+msgstr "&#171;Z&uuml;ri wie neu&#187; dient dazu Sch&auml;den an der Infrastruktur zu melden. Meldungen und W&uuml;nsche bez&uuml;glich Verbesserungen an der Infrastruktur sowie Gestaltungsvorschl&auml;ge k&ouml;nnen über &#171;Z&uuml;ri wie neu&#187; nicht ber&uuml;cksichtigt werden. Notf&auml;lle m&uuml;ssen der Polizei gemeldet werden via Telefon 117."
#: templates/web/base/admin/report_blocks.html:16
msgid "Remove flag"
msgstr ""
-#: templates/web/base/admin/report_edit.html:110
+#: templates/web/base/admin/report_edit.html:94
#: templates/web/base/admin/update_edit.html:62
#: templates/web/zurich/admin/update_edit.html:35
msgid "Remove photo (can't be undone!)"
msgstr ""
+#: templates/web/zurich/admin/report_edit.html:298
+msgid "Reply to user:"
+msgstr "Antwort an User"
+
#: templates/web/fixmystreet/header_logo.html:2
msgid "Report"
-msgstr ""
+msgstr "Meldung"
#: templates/web/base/footer.html:7 templates/web/fixmystreet/footer.html:22
#: templates/web/fixmystreet/header_logo.html:2
-#: templates/web/zurich/footer.html:17
+#: templates/web/zurich/footer.html:18
#: templates/web/zurich/nav_over_content.html:4
msgid "Report a problem"
msgstr "Eine Meldung erfassen"
@@ -2508,7 +2494,7 @@ msgstr ""
#: templates/web/fixmystreet/around/intro.html:1
#: templates/web/zurich/around/intro.html:1
msgid "Report, view, or discuss local problems"
-msgstr "Melden Sie M&auml;ngel an der Infrastruktur von Z&uuml;rich"
+msgstr "Melden Sie Sch&auml;den an der Infrastruktur von Z&uuml;rich"
#: templates/web/base/my/my.html:82
msgid "Reported %s"
@@ -2518,7 +2504,7 @@ msgstr ""
msgid "Reported %s, to %s"
msgstr ""
-#: perllib/FixMyStreet/DB/Result/Problem.pm:580
+#: perllib/FixMyStreet/DB/Result/Problem.pm:606
#: templates/web/base/contact/index.html:50
#: templates/web/fixmystreet/contact/index.html:65
msgid "Reported anonymously at %s"
@@ -2530,62 +2516,66 @@ msgstr "Anonym gemeldet um"
msgid "Reported before"
msgstr ""
-#: perllib/FixMyStreet/DB/Result/Problem.pm:603
+#: perllib/FixMyStreet/DB/Result/Problem.pm:629
#: templates/web/base/contact/index.html:52
#: templates/web/fixmystreet/contact/index.html:67
msgid "Reported by %s at %s"
msgstr "Gemeldet von %s um %s"
+#: templates/web/zurich/admin/report_edit-sdm.html:58
+#: templates/web/zurich/admin/report_edit.html:86
+msgid "Reported by:"
+msgstr "Gemeldet von"
+
#: templates/web/zurich/report/_main.html:2
msgid "Reported in the %s category"
msgstr "In der Kategorie %s gemeldet"
-#: perllib/FixMyStreet/DB/Result/Problem.pm:576
+#: perllib/FixMyStreet/DB/Result/Problem.pm:602
msgid "Reported in the %s category anonymously at %s"
msgstr "In der Kategorie %s um %s gemeldet"
-#: perllib/FixMyStreet/DB/Result/Problem.pm:598
+#: perllib/FixMyStreet/DB/Result/Problem.pm:624
msgid "Reported in the %s category by %s at %s"
msgstr "Gemeldet in der Kategorie %s"
-#: perllib/FixMyStreet/DB/Result/Problem.pm:572
+#: perllib/FixMyStreet/DB/Result/Problem.pm:598
msgid "Reported via %s anonymously at %s"
msgstr "Anonym gemeldet von %s um %s "
-#: perllib/FixMyStreet/DB/Result/Problem.pm:594
+#: perllib/FixMyStreet/DB/Result/Problem.pm:620
msgid "Reported via %s by %s at %s"
msgstr ""
-#: perllib/FixMyStreet/DB/Result/Problem.pm:568
+#: perllib/FixMyStreet/DB/Result/Problem.pm:594
msgid "Reported via %s in the %s category anonymously at %s"
msgstr ""
-#: perllib/FixMyStreet/DB/Result/Problem.pm:588
+#: perllib/FixMyStreet/DB/Result/Problem.pm:614
msgid "Reported via %s in the %s category by %s at %s"
msgstr ""
-#: templates/web/base/reports/index.html:21
-#, fuzzy
-msgid "Reported within the last four weeks"
-msgstr "In der Kategorie %s gemeldet"
+#: templates/web/zurich/admin/report_edit-sdm.html:36
+#: templates/web/zurich/admin/report_edit.html:55
+msgid "Reported:"
+msgstr "Gemeldet"
-#: templates/web/base/around/around_index.html:1
#: templates/web/base/around/around_index.html:3
#: templates/web/base/js/translation_strings.html:41
-#: templates/web/base/report/new/fill_in_details.html:0
#: templates/web/base/report/new/fill_in_details.html:5
#: templates/web/fixmystreet/around/around_index.html:2
#: templates/web/zurich/report/new/fill_in_details_form.html:2
msgid "Reporting a problem"
msgstr "Ihre Meldung"
-#: perllib/FixMyStreet/App/Controller/Admin.pm:1193
-#: perllib/FixMyStreet/Cobrand/Zurich.pm:294
+#: perllib/FixMyStreet/App/Controller/Admin.pm:1286
+#: perllib/FixMyStreet/Cobrand/Zurich.pm:373
#: templates/web/zurich/header.html:60
msgid "Reports"
msgstr "Meldungen"
-#: perllib/FixMyStreet/Cobrand/UK.pm:327 perllib/FixMyStreet/Cobrand/UK.pm:331
+#: perllib/FixMyStreet/DB/Result/Problem.pm:434
+#: perllib/FixMyStreet/DB/Result/Problem.pm:438
msgid "Reports are limited to %s characters in length. Please shorten your report"
msgstr ""
@@ -2601,10 +2591,17 @@ msgstr ""
msgid "Reports published"
msgstr "Beantwortet"
-#: templates/web/base/admin/report_edit.html:85
+#: templates/web/base/admin/report_edit.html:71
msgid "Resend report"
msgstr ""
+#: templates/web/zurich/admin/template_edit.html:1
+#: templates/web/zurich/admin/template_edit.html:4
+#: templates/web/zurich/admin/templates.html:1
+#: templates/web/zurich/admin/templates.html:3
+msgid "Response Templates for %s"
+msgstr "Vorlagen für %s"
+
#: templates/web/base/js/translation_strings.html:28
msgid "Right place?"
msgstr "Richtiger Ort?"
@@ -2619,26 +2616,32 @@ msgstr ""
msgid "Road operator for this named road (from OpenStreetMap): %s"
msgstr ""
-#: perllib/FixMyStreet/App/Controller/Admin.pm:1392
-#: perllib/FixMyStreet/App/Controller/Admin.pm:1403
-#: templates/web/base/admin/report_edit.html:106
-#: templates/web/zurich/admin/report_edit.html:73
+#: perllib/FixMyStreet/App/Controller/Admin.pm:1505
+#: perllib/FixMyStreet/App/Controller/Admin.pm:1510
+#: templates/web/base/admin/report_edit.html:90
+#: templates/web/zurich/admin/report_edit.html:116
msgid "Rotate Left"
msgstr "Links drehen"
-#: perllib/FixMyStreet/App/Controller/Admin.pm:1392
-#: templates/web/base/admin/report_edit.html:107
-#: templates/web/zurich/admin/report_edit.html:74
+#: perllib/FixMyStreet/App/Controller/Admin.pm:1505
+#: templates/web/base/admin/report_edit.html:91
+#: templates/web/zurich/admin/report_edit.html:117
msgid "Rotate Right"
msgstr "Rechts drehen"
+#: templates/web/zurich/admin/report_edit.html:439
+msgid "Rotating this photo will discard unsaved changes to the report."
+msgstr "Durch das Drehen des Fotos gehen nicht gespeicherte Änderungen verloren."
+
#: templates/web/base/js/translation_strings.html:46
+#: templates/web/base/maps/google-ol.html:13
msgid "Satellite"
msgstr ""
-#: templates/web/base/admin/body.html:208
-#: templates/web/base/admin/category_edit.html:81
+#: templates/web/base/admin/body.html:200
+#: templates/web/base/admin/category_edit.html:79
#: templates/web/zurich/admin/body.html:59
+#: templates/web/zurich/admin/template_edit.html:29
msgid "Save changes"
msgstr "Speichern"
@@ -2651,7 +2654,7 @@ msgstr "Meldungen suchen"
msgid "Search Users"
msgstr "User suchen"
-#: templates/web/zurich/header.html:77
+#: templates/web/zurich/header.html:82
msgid "Search reports"
msgstr "Meldungen suchen"
@@ -2665,7 +2668,7 @@ msgstr "Suchen:"
msgid "Searching found no reports."
msgstr ""
-#: templates/web/base/admin/users.html:41
+#: templates/web/base/admin/users.html:39
msgid "Searching found no users."
msgstr ""
@@ -2688,24 +2691,28 @@ msgstr "Gebiet wählen"
msgid "Select which type of alert you'd like and click the button for an RSS feed, or enter your email address to subscribe to an email alert."
msgstr ""
-#: perllib/FixMyStreet/DB/Result/Problem.pm:685
+#: perllib/FixMyStreet/Cobrand/Zurich.pm:821
+msgid "Sent report back"
+msgstr "Meldung zur&uuml;ckgewiesen"
+
+#: perllib/FixMyStreet/DB/Result/Problem.pm:753
msgid "Sent to %s %s later"
msgstr ""
-#: templates/web/base/admin/report_edit.html:84
+#: templates/web/base/admin/report_edit.html:71
msgid "Sent:"
msgstr "Gesendet:"
-#: templates/web/base/admin/report_edit.html:89
+#: templates/web/base/admin/report_edit.html:73
#: templates/web/zurich/admin/stats.html:45
msgid "Service:"
-msgstr ""
+msgstr "Gerät"
#: templates/web/fixmystreet/report/display.html:38
msgid "Share"
msgstr ""
-#: templates/web/base/report/new/fill_in_details_form.html:192
+#: templates/web/base/report/new/fill_in_details_form.html:211
#: templates/web/base/report/update-form.html:157
#: templates/web/fixmystreet/report/new/form_user_loggedin.html:23
#: templates/web/fixmystreet/report/new/form_user_loggedout.html:59
@@ -2750,12 +2757,7 @@ msgstr "Ausloggen"
msgid "Signed in as %s"
msgstr ""
-#: templates/web/base/report/new/fill_in_details_text.html:1
-msgid "Some categories may require additional information."
-msgstr ""
-
-#: templates/web/base/admin/body-form.html:149
-#: templates/web/base/admin/body-form.html:150
+#: templates/web/base/admin/body-form.html:146
msgid ""
"Some endpoints require an <strong>API key</strong> to indicate that the reports are being\n"
" sent from your FixMyStreet installation."
@@ -2778,7 +2780,7 @@ msgstr ""
msgid "Sorry, there has been an error confirming your problem."
msgstr ""
-#: perllib/FixMyStreet/App/Controller/Report/New.pm:214
+#: perllib/FixMyStreet/App/Controller/Report/New.pm:215
#: perllib/FixMyStreet/Geocode.pm:37 perllib/FixMyStreet/Geocode/Bing.pm:37
#: perllib/FixMyStreet/Geocode/FixaMinGata.pm:56
#: perllib/FixMyStreet/Geocode/Google.pm:47
@@ -2788,7 +2790,7 @@ msgstr "Diese Adresse wurde nicht gefunden."
#: perllib/FixMyStreet/Geocode/Bing.pm:34
#: perllib/FixMyStreet/Geocode/Google.pm:44
-#: perllib/FixMyStreet/Geocode/Zurich.pm:87
+#: perllib/FixMyStreet/Geocode/Zurich.pm:88
msgid "Sorry, we could not parse that location. Please try again."
msgstr "Diese Adresse wurde nicht gefunden."
@@ -2796,7 +2798,7 @@ msgstr "Diese Adresse wurde nicht gefunden."
msgid "Start Date:"
msgstr ""
-#: templates/web/base/admin/body.html:69
+#: templates/web/base/admin/body.html:61
#: templates/web/base/admin/flagged.html:18
#: templates/web/base/admin/list_updates.html:11
#: templates/web/base/admin/reports.html:15
@@ -2804,19 +2806,20 @@ msgstr ""
msgid "State"
msgstr "Status"
-#: templates/web/base/admin/report_edit.html:47
+#: templates/web/base/admin/report_edit.html:34
#: templates/web/base/admin/update_edit.html:27
#: templates/web/base/report/update-form.html:28
-#: templates/web/zurich/admin/report_edit-sdm.html:53
-#: templates/web/zurich/admin/report_edit.html:84
+#: templates/web/zurich/admin/report_edit-sdm.html:73
+#: templates/web/zurich/admin/report_edit.html:101
+#: templates/web/zurich/admin/report_edit.html:164
#: templates/web/zurich/admin/update_edit.html:17
msgid "State:"
-msgstr "Status:"
+msgstr "Status"
-#: perllib/FixMyStreet/App/Controller/Admin.pm:1198
-#: perllib/FixMyStreet/Cobrand/Zurich.pm:308
+#: perllib/FixMyStreet/App/Controller/Admin.pm:1291
+#: perllib/FixMyStreet/Cobrand/Zurich.pm:376
#: templates/web/base/admin/stats.html:1
-#: templates/web/zurich/admin/stats.html:1 templates/web/zurich/header.html:72
+#: templates/web/zurich/admin/stats.html:1 templates/web/zurich/header.html:73
msgid "Stats"
msgstr "Statistik"
@@ -2830,6 +2833,11 @@ msgstr ""
msgid "Still open, via questionnaire, %s"
msgstr ""
+#: templates/web/zurich/admin/report_edit-sdm.html:25
+#: templates/web/zurich/admin/report_edit.html:26
+msgid "Street View"
+msgstr ""
+
#: perllib/FixMyStreet/DB/ResultSet/Problem.pm:387
msgid "Subcategory: %s"
msgstr ""
@@ -2845,26 +2853,26 @@ msgstr "Titel"
#: templates/web/base/admin/report_edit.html:19
#: templates/web/base/contact/index.html:88
#: templates/web/base/report/new/fill_in_details_form.html:53
-#: templates/web/zurich/admin/report_edit.html:34
+#: templates/web/zurich/admin/report_edit.html:39
msgid "Subject:"
-msgstr "Titel:"
+msgstr "Titel"
#: templates/web/base/questionnaire/creator_fixed.html:19
-#: templates/web/base/report/new/fill_in_details_form.html:136
-#: templates/web/base/report/new/fill_in_details_form.html:158
-#: templates/web/base/report/new/fill_in_details_form.html:96
+#: templates/web/base/report/new/fill_in_details_form.html:115
+#: templates/web/base/report/new/fill_in_details_form.html:155
+#: templates/web/base/report/new/fill_in_details_form.html:177
#: templates/web/fixmystreet/report/new/form_user_loggedin.html:36
#: templates/web/fixmystreet/report/new/form_user_loggedout.html:23
#: templates/web/fixmystreet/report/new/form_user_loggedout.html:76
-#: templates/web/zurich/report/new/fill_in_details_form.html:91
+#: templates/web/zurich/report/new/fill_in_details_form.html:113
msgid "Submit"
msgstr "Abschicken"
-#: templates/web/base/admin/report_edit.html:113
+#: templates/web/base/admin/report_edit.html:97
#: templates/web/base/admin/update_edit.html:65
-#: templates/web/base/admin/user-form.html:56
-#: templates/web/zurich/admin/report_edit-sdm.html:64
-#: templates/web/zurich/admin/report_edit.html:221
+#: templates/web/base/admin/user-form.html:55
+#: templates/web/zurich/admin/report_edit-sdm.html:137
+#: templates/web/zurich/admin/report_edit.html:323
#: templates/web/zurich/admin/update_edit.html:38
msgid "Submit changes"
msgstr "Speichern"
@@ -2874,16 +2882,13 @@ msgstr "Speichern"
msgid "Submit questionnaire"
msgstr ""
-#: perllib/FixMyStreet/Cobrand/Zurich.pm:134
-#: templates/web/zurich/admin/header.html:1
+#: perllib/FixMyStreet/Cobrand/Zurich.pm:160
+#: perllib/FixMyStreet/Cobrand/Zurich.pm:888
#: templates/web/zurich/admin/header.html:6
#: templates/web/zurich/admin/index-dm.html:23
#: templates/web/zurich/admin/index-dm.html:6
#: templates/web/zurich/admin/index-sdm.html:21
-#: templates/web/zurich/admin/report_edit.html:86
-#: templates/web/zurich/admin/report_edit.html:87
#: templates/web/zurich/admin/reports.html:13
-#: templates/web/zurich/report/banner.html:9
msgid "Submitted"
msgstr "Erfasst"
@@ -2899,24 +2904,23 @@ msgstr ""
msgid "Subscribe me to an email alert"
msgstr ""
-#: perllib/FixMyStreet/App/Controller/Admin.pm:1191
-#: perllib/FixMyStreet/Cobrand/Zurich.pm:293
+#: perllib/FixMyStreet/App/Controller/Admin.pm:1284
+#: perllib/FixMyStreet/Cobrand/Zurich.pm:372
#: templates/web/base/admin/bodies.html:25
#: templates/web/base/admin/index.html:1
#: templates/web/zurich/admin/index-dm.html:1
#: templates/web/zurich/admin/index-sdm.html:1
-#: templates/web/zurich/admin/index.html:1 templates/web/zurich/footer.html:12
+#: templates/web/zurich/admin/index.html:1 templates/web/zurich/footer.html:13
#: templates/web/zurich/header.html:57
msgid "Summary"
msgstr "Zusammenfassung"
#: templates/web/base/reports/index.html:1
-#: templates/web/zurich/reports/index.html:0
#: templates/web/zurich/reports/index.html:4
msgid "Summary reports"
msgstr "Alle Meldungen"
-#: perllib/FixMyStreet/App/Controller/Admin.pm:1195
+#: perllib/FixMyStreet/App/Controller/Admin.pm:1288
msgid "Survey"
msgstr ""
@@ -2924,17 +2928,26 @@ msgstr ""
msgid "Survey Results"
msgstr ""
+#: templates/web/zurich/admin/template_edit.html:7
+msgid "Template &laquo;%s&raquo;"
+msgstr "Vorlage &laquo;%s&raquo;"
+
+#: perllib/FixMyStreet/Cobrand/Zurich.pm:383
+#: templates/web/zurich/header.html:77
+msgid "Templates"
+msgstr "Vorlagen"
+
#: templates/web/base/admin/list_updates.html:12
-#: templates/web/zurich/admin/list_updates.html:10
-#: templates/web/zurich/admin/list_updates.html:31
+#: templates/web/zurich/admin/templates.html:9
msgid "Text"
msgstr ""
-#: templates/web/base/admin/body.html:28
+#: templates/web/base/admin/body.html:21
msgid "Text only version"
msgstr ""
#: templates/web/base/admin/update_edit.html:20
+#: templates/web/zurich/admin/template_edit.html:24
#: templates/web/zurich/admin/update_edit.html:12
msgid "Text:"
msgstr ""
@@ -2964,13 +2977,13 @@ msgstr ""
msgid "Thanks, glad to hear it's been fixed! Could we just ask if you have ever reported a problem to a council before?"
msgstr ""
-#: perllib/FixMyStreet/App/Controller/Photo.pm:195
+#: perllib/FixMyStreet/App/Model/PhotoSet.pm:134
msgid "That image doesn't appear to have uploaded correctly (%s), please try again."
msgstr ""
#: perllib/FixMyStreet/App/Controller/Council.pm:97
msgid "That location does not appear to be covered by a council; perhaps it is offshore or outside the country. Please try again."
-msgstr "Sie k&ouml;nnen M&auml;ngel nur innerhalb der Stadt Z&uuml;rich melden. Verwenden Sie daf&uuml;r die Adressuche."
+msgstr "Sie k&ouml;nnen Sch&auml;den nur innerhalb der Stadt Z&uuml;rich melden. Verwenden Sie daf&uuml;r die Adressuche."
#: perllib/FixMyStreet/App/Controller/Location.pm:126
msgid "That location does not appear to be in the UK; please try again."
@@ -2982,45 +2995,37 @@ msgstr ""
msgid "That postcode was not recognised, sorry."
msgstr ""
-#: perllib/FixMyStreet/App/Controller/Admin.pm:712
-#, fuzzy
-msgid "That problem has been marked as sent."
-msgstr "Dieser Mangel wurde behoben"
-
-#: perllib/FixMyStreet/App/Controller/Admin.pm:704
+#: perllib/FixMyStreet/App/Controller/Admin.pm:728
msgid "That problem will now be resent."
msgstr ""
-#: perllib/FixMyStreet/App/Controller/Report.pm:118
+#: perllib/FixMyStreet/App/Controller/Report.pm:128
msgid "That report cannot be viewed on %s."
-msgstr "Diese Meldung wurde von Z&uuml;ri wie neu entfernt."
+msgstr "Diese Meldung wurde von &#171;Z&uuml;ri wie neu&#187; entfernt."
-#: perllib/FixMyStreet/App/Controller/Report.pm:111
+#: perllib/FixMyStreet/App/Controller/Report.pm:121
msgid "That report has been removed from FixMyStreet."
-msgstr "Diese Meldung wurde von Z&uuml;ri wie neu entfernt."
+msgstr "Diese Meldung wurde von &#171;Z&uuml;ri wie neu&#187; entfernt."
-#: templates/web/base/admin/body.html:144
+#: templates/web/base/admin/body.html:136
msgid ""
"The <strong>email address</strong> is the destination to which reports about this category will be sent. \n"
" Other categories for this body may have the same email address."
msgstr ""
-#: templates/web/base/admin/body-form.html:123
-#: templates/web/base/admin/body-form.html:124
+#: templates/web/base/admin/body-form.html:120
msgid ""
"The <strong>endpoint</strong> is the URL of the service that FixMyStreet will connect to \n"
" when sending reports to this body."
msgstr ""
-#: templates/web/base/admin/body-form.html:136
-#: templates/web/base/admin/body-form.html:137
+#: templates/web/base/admin/body-form.html:133
msgid ""
"The <strong>jurisdiction</strong> is only needed if the endpoint is serving more\n"
" than one. If the body is running its own endpoint, you can usually leave this blank."
msgstr ""
-#: templates/web/base/admin/body-form.html:94
-#: templates/web/base/admin/body-form.html:95
+#: templates/web/base/admin/body-form.html:91
msgid ""
"The <strong>send method</strong> determines how problem reports will be sent to the body.\n"
" If you leave this blank, <strong>send method defaults to email</strong>."
@@ -3030,7 +3035,6 @@ msgstr ""
msgid "The Open311 v2 attribute agency_responsible is used to list the administrations that received the problem report, which is not quite the way the attribute is defined in the Open311 v2 specification."
msgstr ""
-#: templates/web/base/admin/body-form.html:11
#: templates/web/base/admin/body-form.html:12
msgid ""
"The body's <strong>name</strong> identifies the body (for example, <em>Borsetshire District Council</em>)\n"
@@ -3041,10 +3045,9 @@ msgstr ""
msgid "The confirmation email <strong>may</strong> take a few minutes to arrive &mdash; <em>please</em> be patient."
msgstr ""
-#: templates/web/base/report/new/fill_in_details_text.html:1
#: templates/web/base/report/new/fill_in_details_text.html:3
msgid "The council won&rsquo;t be able to help unless you leave as much detail as you can. Please describe the exact location of the problem (e.g. on a wall), what it is, how long it has been there, a description (and a photo of the problem if you have one), etc."
-msgstr "Bitte machen Sie so genaue Angaben wie m&ouml;glich: Beschreiben Sie die Art des Mangels und wo er sich befindet (z.B. an der Wand). Senden Sie uns ein Foto des Mangels (inkl. Umgebung). <br/>Beschreiben Sie nur einen Mangel pro Meldung."
+msgstr "Bitte machen Sie so genaue Angaben wie m&ouml;glich: Beschreiben Sie die Art des Schadens und wo er sich befindet (z.B. an der Wand). Senden Sie uns mindestens ein Foto des Schadens (inkl. Umgebung). <br/>Beschreiben Sie <b>nur einen Schaden pro Meldung</b>."
#: templates/web/fixmystreet/questionnaire/index.html:44
msgid "The details of your problem are available from the other tab above."
@@ -3054,7 +3057,6 @@ msgstr ""
msgid "The details of your problem are available on the right hand side of this page."
msgstr ""
-#: templates/web/base/admin/edit-league.html:3
#: templates/web/base/admin/edit-league.html:4
msgid "The diligency prize league table shows editors' activity (who's been editing the most records)."
msgstr ""
@@ -3122,12 +3124,10 @@ msgstr ""
msgid "The list of available areas is being provided by the MapIt service at %s."
msgstr ""
-#: templates/web/base/auth/change_password.html:12
#: templates/web/base/auth/change_password.html:16
msgid "The passwords do not match"
msgstr ""
-#: templates/web/base/errors/page_error_404_not_found.html:10
#: templates/web/base/errors/page_error_404_not_found.html:12
msgid "The requested URL '%s' was not found on this server"
msgstr ""
@@ -3148,17 +3148,12 @@ msgstr ""
msgid "The user could not locate the problem on a map, but to see the area around the location they entered"
msgstr ""
-#: templates/web/base/admin/user-form.html:12
#: templates/web/base/admin/user-form.html:13
msgid ""
"The user's <strong>name</strong> is displayed publicly on reports that have not been marked <em>anonymous</em>.\n"
" Names are not necessarily unique."
msgstr ""
-#: templates/web/base/reports/_problem-list.html:15
-msgid "There are no reports to show."
-msgstr ""
-
#: perllib/FixMyStreet/App/Controller/Reports.pm:75
msgid "There was a problem showing the All Reports page. Please try again later."
msgstr ""
@@ -3168,7 +3163,7 @@ msgstr ""
msgid "There was a problem showing this page. Please try again later."
msgstr ""
-#: perllib/FixMyStreet/App/Controller/Report/New.pm:762
+#: perllib/FixMyStreet/App/Controller/Report/New.pm:747
#: perllib/FixMyStreet/App/Controller/Report/Update.pm:134
#: templates/web/base/auth/general.html:23
#: templates/web/fixmystreet/auth/general.html:25
@@ -3192,8 +3187,7 @@ msgstr ""
msgid "There were problems with your update. Please see below."
msgstr ""
-#: templates/web/base/admin/body-form.html:112
-#: templates/web/base/admin/body-form.html:113
+#: templates/web/base/admin/body-form.html:109
msgid ""
"These settings are for bodies that use Open311 (or other back-end integration) to receive problem reports.<br>\n"
" <strong>You don't need to set them if the Send Method is email.</strong>.\n"
@@ -3206,18 +3200,17 @@ msgstr ""
msgid "This API implementation is work in progress and not yet stabilized. It will change without warnings in the future."
msgstr ""
-#: templates/web/base/admin/body.html:44
+#: templates/web/base/admin/body.html:36
msgid ""
"This body covers no area. This means that it has no jurisdiction over problems reported <em>at any location</em>.\n"
" Consequently, none of its categories will appear in the drop-down category menu when users report problems.\n"
" Currently, users <strong>cannot report problems to this body</strong>."
msgstr ""
-#: templates/web/base/admin/body.html:54
+#: templates/web/base/admin/body.html:46
msgid "This body has no contacts. This means that currently problems reported to this body <strong>will not be sent</strong>."
msgstr ""
-#: templates/web/base/admin/body-form.html:52
#: templates/web/base/admin/body-form.html:53
msgid ""
"This body will only be sent reports for problems that are located in the <strong>area covered</strong>.\n"
@@ -3232,8 +3225,8 @@ msgstr ""
msgid "This email has been sent to several councils covering the location of the problem, as the category selected is provided for all of them; please ignore it if you're not the correct council to deal with the issue."
msgstr ""
-#: perllib/FixMyStreet/App/Controller/Report/New.pm:902
-#: perllib/FixMyStreet/App/Controller/Report/New.pm:972
+#: perllib/FixMyStreet/App/Controller/Report/New.pm:897
+#: perllib/FixMyStreet/App/Controller/Report/New.pm:967
#: perllib/FixMyStreet/Cobrand/EmptyHomes.pm:142
#: perllib/FixMyStreet/Cobrand/UK.pm:43
msgid "This information is required"
@@ -3259,23 +3252,23 @@ msgstr ""
#: templates/web/base/report/update-form.html:48
#: templates/web/fixmystreet/report/update-form.html:46
msgid "This problem has been fixed"
-msgstr "Dieser Mangel wurde behoben"
+msgstr "Dieser Schaden wurde behoben"
#: templates/web/base/report/update-form.html:43
#: templates/web/fixmystreet/report/update-form.html:40
msgid "This problem has not been fixed"
-msgstr "Dieser Mangel wurde nicht behoben"
+msgstr "Dieser Schaden wurde nicht behoben"
#: templates/web/base/report/banner.html:19
msgid "This problem is in progress"
-msgstr "Dieser Mangel ist in Bearbeitung"
+msgstr "Dieser Schaden ist in Bearbeitung"
#: templates/web/base/report/banner.html:9
msgid "This problem is old and of unknown status."
msgstr "Dieses Problem ist alt und hat einen unbekannten Status"
-#: perllib/FixMyStreet/Cobrand/Zurich.pm:131
-#: perllib/FixMyStreet/Cobrand/Zurich.pm:132
+#: perllib/FixMyStreet/Cobrand/Zurich.pm:157
+#: perllib/FixMyStreet/Cobrand/Zurich.pm:158
#: templates/web/zurich/report/_main.html:14
msgid "This report is awaiting moderation."
msgstr "&Uuml;berpr&uuml;fung ausstehend"
@@ -3300,16 +3293,28 @@ msgstr ""
msgid "This web page also contains a photo of the problem, provided by the user."
msgstr ""
-#: perllib/FixMyStreet/App/Controller/Admin.pm:1194
+#: templates/web/zurich/admin/report_edit-sdm.html:123
+#: templates/web/zurich/admin/report_edit-sdm.html:76
+#: templates/web/zurich/admin/report_edit.html:104
+#: templates/web/zurich/admin/report_edit.html:148
+msgid "Time spent (in minutes):"
+msgstr "Aufwand (in Minuten)"
+
+#: perllib/FixMyStreet/App/Controller/Admin.pm:1287
#: templates/web/base/admin/timeline.html:1
msgid "Timeline"
msgstr ""
#: templates/web/base/admin/flagged.html:15
#: templates/web/base/admin/reports.html:12
+#: templates/web/zurich/admin/templates.html:8
msgid "Title"
msgstr "Titel"
+#: templates/web/zurich/admin/template_edit.html:20
+msgid "Title:"
+msgstr "Titel"
+
#: templates/web/base/around/_report_banner.html:2
msgid "To <strong>report a problem</strong>, click on the map at the correct location."
msgstr ""
@@ -3338,20 +3343,16 @@ msgstr "Erneut versuchen"
msgid "Try emailing us directly:"
msgstr ""
-#: templates/web/base/admin/report_edit.html:48
-#: templates/web/base/admin/report_edit.html:59
-#: templates/web/base/report/update-form.html:30
+#: templates/web/base/admin/report_edit.html:46
#: templates/web/base/report/update-form.html:33
-#: templates/web/fixmystreet/report/update-form.html:28
#: templates/web/fixmystreet/report/update-form.html:31
msgid "Unable to fix"
msgstr ""
-#: templates/web/base/admin/report_edit.html:48
-#: templates/web/base/admin/report_edit.html:64
+#: templates/web/base/admin/report_edit.html:51
#: templates/web/base/admin/update_edit.html:28
-#: templates/web/zurich/admin/report_edit-sdm.html:45
-#: templates/web/zurich/admin/report_edit.html:58
+#: templates/web/zurich/admin/report_edit-sdm.html:64
+#: templates/web/zurich/admin/report_edit.html:92
#: templates/web/zurich/admin/update_edit.html:18
msgid "Unconfirmed"
msgstr "Unbest&auml;tigt"
@@ -3368,7 +3369,9 @@ msgstr ""
msgid "Unknown error"
msgstr "Unbekannter Fehler"
-#: perllib/FixMyStreet/App/Controller/Report.pm:106
+#: perllib/FixMyStreet/App/Controller/Report.pm:103
+#: perllib/FixMyStreet/App/Controller/Report.pm:111
+#: perllib/FixMyStreet/App/Controller/Report.pm:114
msgid "Unknown problem ID"
msgstr ""
@@ -3390,8 +3393,8 @@ msgstr ""
msgid "Update below added by %s at %s"
msgstr ""
-#: templates/web/base/admin/body-form.html:240
-#: templates/web/zurich/admin/body-form.html:51
+#: templates/web/base/admin/body-form.html:233
+#: templates/web/zurich/admin/body-form.html:52
msgid "Update body"
msgstr "Speichern"
@@ -3416,7 +3419,7 @@ msgstr ""
msgid "Update reopened problem"
msgstr ""
-#: templates/web/base/admin/body.html:101
+#: templates/web/base/admin/body.html:93
msgid "Update statuses"
msgstr ""
@@ -3430,19 +3433,19 @@ msgstr ""
msgid "Updated"
msgstr "Aktualisiert"
-#: perllib/FixMyStreet/App/Controller/Admin.pm:1014
-#: perllib/FixMyStreet/App/Controller/Admin.pm:1058
-#: perllib/FixMyStreet/App/Controller/Admin.pm:808
-#: perllib/FixMyStreet/App/Controller/Admin.pm:956
-#: perllib/FixMyStreet/Cobrand/Zurich.pm:556
-#: perllib/FixMyStreet/Cobrand/Zurich.pm:625
+#: perllib/FixMyStreet/App/Controller/Admin.pm:1049
+#: perllib/FixMyStreet/App/Controller/Admin.pm:1107
+#: perllib/FixMyStreet/App/Controller/Admin.pm:1151
+#: perllib/FixMyStreet/App/Controller/Admin.pm:825
+#: perllib/FixMyStreet/Cobrand/Zurich.pm:757
+#: perllib/FixMyStreet/Cobrand/Zurich.pm:782
+#: perllib/FixMyStreet/Cobrand/Zurich.pm:852
msgid "Updated!"
msgstr "Aktualisiert!"
#: templates/web/base/admin/list_updates.html:2
#: templates/web/base/report/update.html:3
#: templates/web/fixmystreet/report/update.html:5
-#: templates/web/zurich/admin/list_updates.html:24
#: templates/web/zurich/report/updates.html:2
msgid "Updates"
msgstr "Antwort"
@@ -3455,27 +3458,25 @@ msgstr ""
msgid "Updates on {{title}}"
msgstr ""
-#: templates/web/base/report/display.html:0
#: templates/web/base/report/display.html:5
-#: templates/web/fixmystreet/report/display.html:0
#: templates/web/fixmystreet/report/display.html:9
msgid "Updates to this problem, FixMyStreet"
msgstr ""
-#: templates/web/base/admin/body.html:182
+#: templates/web/base/admin/body.html:174
msgid "Use the <strong>note</strong> to record details that are only displayed in the admin. Notes are not shown publicly, and are not sent to the body."
msgstr ""
-#: templates/web/zurich/admin/list_updates.html:30
-#: templates/web/zurich/admin/list_updates.html:9
-msgid "User"
-msgstr ""
+#: templates/web/zurich/admin/report_edit-sdm.html:48
+#: templates/web/zurich/admin/report_edit.html:67
+msgid "Used map"
+msgstr "Karte verwendet"
-#: perllib/FixMyStreet/App/Controller/Admin.pm:1357
+#: perllib/FixMyStreet/App/Controller/Admin.pm:1461
msgid "User flag removed"
msgstr ""
-#: perllib/FixMyStreet/App/Controller/Admin.pm:1329
+#: perllib/FixMyStreet/App/Controller/Admin.pm:1433
msgid "User flagged"
msgstr ""
@@ -3483,23 +3484,23 @@ msgstr ""
msgid "User search finds matches in users' names and email addresses."
msgstr ""
-#: perllib/FixMyStreet/App/Controller/Admin.pm:1196
-#: perllib/FixMyStreet/Cobrand/Zurich.pm:307
+#: perllib/FixMyStreet/App/Controller/Admin.pm:1289
+#: perllib/FixMyStreet/Cobrand/Zurich.pm:388
#: templates/web/base/admin/flagged.html:29
#: templates/web/zurich/header.html:69
msgid "Users"
msgstr ""
-#: perllib/FixMyStreet/App/Controller/Admin.pm:374
-#: perllib/FixMyStreet/App/Controller/Admin.pm:404
-#: perllib/FixMyStreet/App/Controller/Admin.pm:421
+#: perllib/FixMyStreet/App/Controller/Admin.pm:386
+#: perllib/FixMyStreet/App/Controller/Admin.pm:416
+#: perllib/FixMyStreet/App/Controller/Admin.pm:436
msgid "Values updated"
msgstr ""
#: templates/web/base/admin/report_edit.html:18
#: templates/web/base/admin/update_edit.html:18
#: templates/web/zurich/admin/report_edit-sdm.html:21
-#: templates/web/zurich/admin/report_edit.html:20
+#: templates/web/zurich/admin/report_edit.html:22
#: templates/web/zurich/admin/update_edit.html:10
msgid "View report on site"
msgstr "Meldung auf der Webseite betrachten"
@@ -3508,16 +3509,10 @@ msgstr "Meldung auf der Webseite betrachten"
msgid "View reports by ward"
msgstr ""
-#: templates/web/base/around/display_location.html:0
#: templates/web/base/around/display_location.html:35
msgid "Viewing a location"
msgstr "Meldung erfassen"
-#: templates/web/base/report/display.html:0
-#: templates/web/fixmystreet/report/display.html:0
-msgid "Viewing a problem"
-msgstr "Meldung anschauen"
-
#: templates/web/base/reports/body.html:16
msgid "Wards of this council"
msgstr ""
@@ -3550,7 +3545,7 @@ msgstr "Ihre E-Mail Adresse oder Telefonnummer werden nie angezeigt"
msgid "We realise this problem might be the responsibility of %s; however, we don't currently have any contact details for them. If you know of an appropriate contact address, please do get in touch."
msgstr ""
-#: templates/web/base/index-steps.html:31
+#: templates/web/base/index-steps.html:38
msgid "We send it to the council on your behalf"
msgstr ""
@@ -3571,11 +3566,11 @@ msgstr ""
msgid "We’ll get back to you as soon as we can."
msgstr ""
-#: templates/web/fixmystreet/report/new/fill_in_details_form.html:49
+#: templates/web/fixmystreet/report/new/fill_in_details_form.html:41
msgid "What’s the issue, and where is it?"
msgstr ""
-#: templates/web/base/admin/category_edit.html:87
+#: templates/web/base/admin/category_edit.html:85
#: templates/web/zurich/admin/body.html:18
msgid "When edited"
msgstr "Wann editiert"
@@ -3584,7 +3579,7 @@ msgstr "Wann editiert"
msgid "When sent"
msgstr "Wann gesendet"
-#: perllib/FixMyStreet/App/Controller/Report/New.pm:633
+#: perllib/FixMyStreet/App/Controller/Report/New.pm:621
msgid "Whole block of empty flats"
msgstr ""
@@ -3592,6 +3587,12 @@ msgstr ""
msgid "Why stop there? <a href=\"/alert\">Set up more alerts</a> for free."
msgstr ""
+#: perllib/FixMyStreet/Cobrand/Zurich.pm:181
+#: perllib/FixMyStreet/Cobrand/Zurich.pm:918
+#: templates/web/zurich/admin/header.html:14
+msgid "Wish"
+msgstr "Wunsch"
+
#: templates/web/base/open311/index.html:92
msgid "With request searches, it is also possible to search for agency_responsible to limit the requests to those sent to a single administration. The search term is the administration ID provided by <a href=\"%s\">MaPit</a>."
msgstr ""
@@ -3619,18 +3620,18 @@ msgid "Year"
msgstr "Jahr"
#: templates/web/base/admin/bodies.html:66
-#: templates/web/base/admin/body.html:80 templates/web/base/admin/body.html:82
-#: templates/web/base/admin/body.html:86 templates/web/base/admin/body.html:88
+#: templates/web/base/admin/body.html:72 templates/web/base/admin/body.html:74
+#: templates/web/base/admin/body.html:78 templates/web/base/admin/body.html:80
#: templates/web/base/admin/category_edit.html:5
#: templates/web/base/admin/flagged.html:47
#: templates/web/base/admin/list_updates.html:32
#: templates/web/base/admin/list_updates.html:34
#: templates/web/base/admin/list_updates.html:35
#: templates/web/base/admin/problem_row.html:20
-#: templates/web/base/admin/report_edit.html:76
-#: templates/web/base/admin/report_edit.html:93
+#: templates/web/base/admin/report_edit.html:63
+#: templates/web/base/admin/report_edit.html:77
#: templates/web/base/admin/update_edit.html:24
-#: templates/web/base/admin/users.html:31
+#: templates/web/base/admin/users.html:29
#: templates/web/base/questionnaire/creator_fixed.html:14
#: templates/web/base/questionnaire/index.html:42
#: templates/web/base/questionnaire/index.html:81
@@ -3659,12 +3660,11 @@ msgstr ""
msgid "You are reporting the following update for being abusive, containing personal information, or similar:"
msgstr ""
-#: templates/web/zurich/tokens/confirm_problem.html:5
#: templates/web/zurich/tokens/confirm_problem.html:8
msgid "You can <a href=\"%s%s\">view the problem on this site</a>."
msgstr "Danke! Sie k&ouml;nnen Ihre aktualisierte Meldung <a href=\"%s%s\">auf der Webseite anschauen</a>."
-#: templates/web/base/admin/user-form.html:48
+#: templates/web/base/admin/user-form.html:47
msgid "You can add an abusive user's email to the abuse list, which automatically hides (and never sends) reports they create."
msgstr ""
@@ -3680,13 +3680,11 @@ msgid ""
msgstr ""
#: templates/web/base/report/new/councils_text_none.html:10
-#: templates/web/base/report/new/councils_text_none.html:2
-#: templates/web/base/report/new/councils_text_some.html:19
#: templates/web/base/report/new/councils_text_some.html:21
msgid "You can help us by finding a contact email address for local problems for %s and emailing it to us at <a href='mailto:%s'>%s</a>."
msgstr ""
-#: templates/web/base/admin/body-form.html:85
+#: templates/web/base/admin/body-form.html:81
msgid "You can mark a body as deleted if you do not want it to be active on the site."
msgstr ""
@@ -3699,10 +3697,9 @@ msgid "You have already answered this questionnaire. If you have a question, ple
msgstr ""
#: templates/web/base/questionnaire/index.html:68
-#: templates/web/base/report/new/fill_in_details_form.html:75
+#: templates/web/base/report/new/fill_in_details_form.html:94
#: templates/web/fixmystreet/questionnaire/index.html:88
-#: templates/web/fixmystreet/report/new/fill_in_details_form.html:73
-#: templates/web/zurich/report/new/fill_in_details_form.html:58
+#: templates/web/fixmystreet/report/new/fill_in_details_form.html:79
msgid "You have already attached a photo to this report, attaching another one will replace it."
msgstr "Sie haben bereits ein Photo angeh&auml;ngt. Laden Sie ein neues hoch um es zu ersetzen."
@@ -3711,6 +3708,10 @@ msgstr "Sie haben bereits ein Photo angeh&auml;ngt. Laden Sie ein neues hoch um
msgid "You have already attached a photo to this update, attaching another one will replace it."
msgstr ""
+#: templates/web/zurich/report/new/fill_in_details_form.html:78
+msgid "You have already attached photos to this report. Note that you can attach a maximum of 3 to this report (if you try to upload more, the oldest will be removed)."
+msgstr "Sie haben dieser Meldung bereits Fotos angehängt. Sie können maximal 3 Fotos anhängen (wenn Sie mehr anhängen, wird das Älteste entfernt)."
+
#: templates/web/base/auth/sign_out.html:4
#: templates/web/zurich/auth/sign_out.html:3
msgid "You have been signed out"
@@ -3720,7 +3721,6 @@ msgstr "Sie haben sich abgemeldet"
msgid "You have located the problem at the point marked with a green pin on the map. If this is not the correct location, simply click on the map again. "
msgstr "Der gr&uuml;ne Punkt lokalisiert Ihre Meldung auf der Karte. Falls dieser Ort nicht stimmt, kann der Pin verschoben werden."
-#: templates/web/zurich/tokens/confirm_problem.html:5
#: templates/web/zurich/tokens/confirm_problem.html:6
msgid "You have successfully confirmed your email address."
msgstr "Sie haben Ihre Meldung erfolgreich best&auml;tigt. "
@@ -3750,12 +3750,11 @@ msgid ""
" contacts (such as an email address) to which reports are sent."
msgstr ""
-#: templates/web/base/admin/report_edit.html:85
+#: templates/web/base/admin/report_edit.html:71
msgid "You really want to resend?"
msgstr ""
-#: templates/web/base/my/my.html:0 templates/web/base/my/my.html:15
-#: templates/web/base/my/my.html:4 templates/web/fixmystreet/my/my.html:0
+#: templates/web/base/my/my.html:15 templates/web/base/my/my.html:4
#: templates/web/fixmystreet/my/my.html:15
#: templates/web/fixmystreet/my/my.html:4
msgid "Your Reports"
@@ -3770,7 +3769,7 @@ msgstr "Ihre Meldungen"
#: templates/web/fixmystreet/report/new/form_user_loggedin.html:3
#: templates/web/fixmystreet/report/new/form_user_loggedout.html:1
#: templates/web/fixmystreet/report/update-form.html:76
-#: templates/web/zurich/report/new/fill_in_details_form.html:71
+#: templates/web/zurich/report/new/fill_in_details_form.html:93
msgid "Your email"
msgstr "E-Mail Adresse"
@@ -3783,13 +3782,13 @@ msgstr "Ihre E-Mail Adresse"
#: templates/web/base/auth/general.html:27
msgid "Your email address:"
-msgstr "Ihre E-Mail Adresse:"
+msgstr "Ihre E-Mail Adresse"
#: templates/web/base/alert/_list.html:92
-#: templates/web/base/report/new/fill_in_details_form.html:106
+#: templates/web/base/report/new/fill_in_details_form.html:125
#: templates/web/base/report/update-form.html:81
msgid "Your email:"
-msgstr "Ihre E-Mail:"
+msgstr "Ihre E-Mail"
#: templates/web/fixmystreet/report/updates-sidebar-notes.html:7
msgid "Your information will only be used in accordance with our <a href=\"/privacy\">privacy policy</a>"
@@ -3801,16 +3800,16 @@ msgstr "Wir verwenden Ihre pers&ouml;nlichen Daten nur entsprechend unserer <a h
#: templates/web/fixmystreet/report/new/form_user_loggedout.html:54
#: templates/web/fixmystreet/report/update-form.html:142
#: templates/web/zurich/auth/general.html:61
-#: templates/web/zurich/report/new/fill_in_details_form.html:81
+#: templates/web/zurich/report/new/fill_in_details_form.html:103
msgid "Your name"
msgstr "Ihr Name"
#: templates/web/base/auth/general.html:59
#: templates/web/base/contact/index.html:73
-#: templates/web/base/report/new/fill_in_details_form.html:185
+#: templates/web/base/report/new/fill_in_details_form.html:204
#: templates/web/base/report/update-form.html:151
msgid "Your name:"
-msgstr "Ihr Name:"
+msgstr "Ihr Name"
#: templates/web/fixmystreet/auth/general.html:42
#: templates/web/fixmystreet/report/new/form_user_loggedout.html:22
@@ -3825,7 +3824,7 @@ msgstr "Ihr Passwort wurde ge&auml;ndert"
#: templates/web/fixmystreet/report/new/form_user_loggedin.html:27
#: templates/web/fixmystreet/report/new/form_user_loggedout.html:63
-#: templates/web/zurich/report/new/fill_in_details_form.html:87
+#: templates/web/zurich/report/new/fill_in_details_form.html:109
msgid "Your phone number"
msgstr "Ihre Telefonnummer"
@@ -3837,26 +3836,27 @@ msgstr "Ihre Meldung"
msgid "Your reports"
msgstr "Ihre Meldungen"
-#: templates/web/base/my/my.html:53 templates/web/fixmystreet/my/my.html:41
+#: templates/web/base/my/my.html:53 templates/web/fixmystreet/my/my.html:59
msgid "Your updates"
msgstr ""
#: templates/web/base/contact/index.html:81
msgid "Your&nbsp;email:"
-msgstr "Ihre E-Mail Adresse:"
+msgstr "Ihre E-Mail Adresse"
#: templates/web/base/admin/timeline.html:4
msgid "by %s"
msgstr ""
-#: templates/web/base/reports/body.html:6
#: templates/web/base/reports/body.html:7
msgid "council"
msgstr ""
-#: templates/web/base/admin/report_edit.html:32
-#: templates/web/zurich/admin/report_edit-sdm.html:40
-#: templates/web/zurich/admin/report_edit.html:54
+#: perllib/FixMyStreet/DB/Result/Problem.pm:738
+msgid "council ref:&nbsp;%s"
+msgstr ""
+
+#: templates/web/base/admin/report_edit.html:28
msgid "didn't use map"
msgstr "hat Karte nicht verwendet"
@@ -3865,7 +3865,6 @@ msgstr "hat Karte nicht verwendet"
msgid "e.g. ‘%s’ or ‘%s’"
msgstr "z.B. ‘%s’ oder ‘%s’"
-#: templates/web/base/admin/body-form.html:188
#: templates/web/base/admin/flagged.html:51
msgid "edit user"
msgstr ""
@@ -3925,7 +3924,7 @@ msgstr ""
msgid "marked as unable to fix"
msgstr ""
-#: perllib/FixMyStreet/App/Controller/Admin.pm:130
+#: perllib/FixMyStreet/App/Controller/Admin.pm:131
#: templates/web/base/admin/questionnaire.html:15
#: templates/web/base/admin/questionnaire.html:16
msgid "n/a"
@@ -3940,22 +3939,16 @@ msgstr "oder"
msgid "or locate me automatically"
msgstr "oder automatisch lokalisieren"
-#: templates/web/base/admin/report_edit.html:28
-#: templates/web/base/admin/report_edit.html:30
-#: templates/web/zurich/admin/report_edit-sdm.html:27
-#: templates/web/zurich/admin/report_edit-sdm.html:29
-#: templates/web/zurich/admin/report_edit-sdm.html:36
-#: templates/web/zurich/admin/report_edit-sdm.html:38
-#: templates/web/zurich/admin/report_edit.html:27
-#: templates/web/zurich/admin/report_edit.html:29
-#: templates/web/zurich/admin/report_edit.html:38
-#: templates/web/zurich/admin/report_edit.html:40
+#: templates/web/base/admin/report_edit.html:26
+#: templates/web/zurich/admin/report_edit-sdm.html:32
+#: templates/web/zurich/admin/report_edit-sdm.html:55
+#: templates/web/zurich/admin/report_edit.html:34
#: templates/web/zurich/admin/report_edit.html:50
-#: templates/web/zurich/admin/report_edit.html:52
+#: templates/web/zurich/admin/report_edit.html:74
msgid "originally entered: &ldquo;%s&rdquo;"
msgstr "Originaltext: &ldquo;%s&rdquo;"
-#: templates/web/base/admin/report_edit.html:43
+#: templates/web/base/admin/report_edit.html:30
msgid "other areas:"
msgstr ""
@@ -3964,14 +3957,12 @@ msgstr ""
msgid "reopened"
msgstr ""
-#: templates/web/fixmystreet/header.html:59
-#: templates/web/zurich/footer.html:12
+#: templates/web/fixmystreet/header.html:53
+#: templates/web/zurich/footer.html:13
msgid "sign out"
msgstr "ausloggen"
-#: templates/web/base/report/new/fill_in_details_form.html:12
#: templates/web/base/report/new/fill_in_details_form.html:15
-#: templates/web/fixmystreet/report/new/fill_in_details_form.html:10
#: templates/web/fixmystreet/report/new/fill_in_details_form.html:12
msgid "the local council"
msgstr ""
@@ -3989,9 +3980,7 @@ msgstr ""
msgid "today"
msgstr "heute"
-#: templates/web/base/admin/report_edit.html:32
-#: templates/web/zurich/admin/report_edit-sdm.html:40
-#: templates/web/zurich/admin/report_edit.html:54
+#: templates/web/base/admin/report_edit.html:28
msgid "used map"
msgstr "Karte verwendet"
@@ -3999,11 +3988,6 @@ msgstr "Karte verwendet"
msgid "user is from same council as problem - %d"
msgstr ""
-#: templates/web/base/admin/update_edit.html:38
-msgid "user is problem owner"
-msgstr ""
-
-#: templates/web/base/reports/body.html:0
#: templates/web/base/reports/body.html:3
msgid "ward"
msgstr ""
@@ -4084,3 +4068,24 @@ msgid "We do <strong>not</strong> yet have details for the other council that co
msgid_plural "We do <strong>not</strong> yet have details for the other councils that cover this location."
msgstr[0] ""
msgstr[1] ""
+
+#~ msgid "Edit templates"
+#~ msgstr "Vorlagen editieren"
+
+#~ msgid "Publish the response"
+#~ msgstr "Antwort ver&ouml;ffentlichen"
+
+#~ msgid "Templates:"
+#~ msgstr "Vorlagen:"
+
+#~ msgid "Viewing a problem"
+#~ msgstr "Meldung anschauen"
+
+#~ msgid "New update:"
+#~ msgstr "Neue Antwort"
+
+#~ msgid "Please upload a JPEG image only\n"
+#~ msgstr "Bitte laden Sie nur JPEG Bilder hoch\n"
+
+#~ msgid "Thank you &mdash; you can <a href=\"%s\">view your updated problem</a> on the site."
+#~ msgstr "Danke &mdash; Sie k&ouml;nnen Ihre aktualisierte Meldung <a href=\"%s\">auf der Webseite anschauen</a>."
diff --git a/perllib/FixMyStreet.pm b/perllib/FixMyStreet.pm
index 76760b967..76befb96a 100644
--- a/perllib/FixMyStreet.pm
+++ b/perllib/FixMyStreet.pm
@@ -124,11 +124,14 @@ sub override_config($&) {
}
);
+ FixMyStreet::Map::reload_allowed_maps() if $config->{MAP_TYPE};
+
$code->();
$override_guard1->restore();
$override_guard2->restore();
- mySociety::MaPit::configure() if $config->{MAPIT_URL};;
+ mySociety::MaPit::configure() if $config->{MAPIT_URL};
+ FixMyStreet::Map::reload_allowed_maps() if $config->{MAP_TYPE};
}
=head2 dbic_connect_info
diff --git a/perllib/FixMyStreet/App.pm b/perllib/FixMyStreet/App.pm
index 5e0bbaf93..c9286b177 100644
--- a/perllib/FixMyStreet/App.pm
+++ b/perllib/FixMyStreet/App.pm
@@ -207,7 +207,8 @@ sub setup_request {
# XXX Put in cobrand / do properly
if ($c->cobrand->moniker eq 'zurich') {
- FixMyStreet::DB::Result::Problem->visible_states_add_unconfirmed();
+ FixMyStreet::DB::Result::Problem->visible_states_add('unconfirmed');
+ FixMyStreet::DB::Result::Problem->visible_states_remove('investigating');
}
if (FixMyStreet->test_mode) {
@@ -318,15 +319,15 @@ sub send_email {
]
};
+ return if $c->is_abuser($vars->{to});
+
# render the template
my $content = $c->view('Email')->render( $c, $template, $vars );
# create an email - will parse headers out of content
my $email = Email::Simple->new($content);
- $email->header_set( ucfirst($_), $vars->{$_} )
- for grep { $vars->{$_} } qw( to from subject Reply-To);
-
- return if $c->is_abuser( $email->header('To') );
+ $email->header_set( 'Subject', $vars->{subject} ) if $vars->{subject};
+ $email->header_set( 'Reply-To', $vars->{'Reply-To'} ) if $vars->{'Reply-To'};
$email->header_set( 'Message-ID', sprintf('<fms-%s-%s@%s>',
time(), unpack('h*', random_bytes(5, 1)), $c->config->{EMAIL_DOMAIN}
@@ -339,10 +340,16 @@ sub send_email {
_template_ => $email->body, # will get line wrapped
_parameters_ => {},
_line_indent => '',
+ From => $vars->{from},
+ To => $vars->{to},
$email->header_pairs
}
) };
+ if (my $attachments = $extra_stash_values->{attachments}) {
+ $email_text = munge_attachments($email_text, $attachments);
+ }
+
# send the email
$c->model('EmailSend')->send($email_text);
@@ -359,17 +366,7 @@ sub send_email_cron {
$params->{From} = [ $sender, _($sender_name) ];
}
- my $first_to;
- if (ref($params->{To}) eq 'ARRAY') {
- if (ref($params->{To}[0]) eq 'ARRAY') {
- $first_to = $params->{To}[0][0];
- } else {
- $first_to = $params->{To}[0];
- }
- } else {
- $first_to = $params->{To};
- }
- return 1 if $c->is_abuser($first_to);
+ return 1 if $c->is_abuser($params->{To});
$params->{'Message-ID'} = sprintf('<fms-cron-%s-%s@%s>', time(),
unpack('h*', random_bytes(5, 1)), FixMyStreet->config('EMAIL_DOMAIN')
@@ -403,8 +400,12 @@ sub send_email_cron {
$params->{_parameters_}->{site_name} = $site_name;
$params->{_line_indent} = '';
+ my $attachments = delete $params->{attachments};
+
my $email = mySociety::Locale::in_gb_locale { mySociety::Email::construct_email($params) };
+ $email = munge_attachments($email, $attachments) if $attachments;
+
if ($nomail) {
print $email;
return 1; # Failure
@@ -418,6 +419,44 @@ sub send_email_cron {
}
}
+sub munge_attachments {
+ my ($message, $attachments) = @_;
+ # $attachments should be an array_ref of things that can be parsed to Email::MIME,
+ # for example
+ # [
+ # body => $binary_data,
+ # attributes => {
+ # content_type => 'image/jpeg',
+ # encoding => 'base64',
+ # filename => '1234.1.jpeg',
+ # name => '1234.1.jpeg',
+ # },
+ # ...
+ # ]
+ #
+ # XXX: mySociety::Email::construct_email isn't using a MIME library and
+ # requires more analysis to refactor, so for now, we'll simply parse the
+ # generated MIME and add attachments.
+ #
+ # (Yes, this means that the email is constructed by Email::Simple, munged
+ # manually by custom code, turned back into Email::Simple, and then munged
+ # with Email::MIME. What's your point?)
+
+ require Email::MIME;
+ my $mime = Email::MIME->new($message);
+ $mime->parts_add([ map { Email::MIME->create(%$_)} @$attachments ]);
+ my $data = $mime->as_string;
+
+ # unsure why Email::MIME adds \r\n. Possibly mail client should handle
+ # gracefully, BUT perhaps as the segment constructed by
+ # mySociety::Email::construct_email strips to \n, they seem not to.
+ # So we re-run the same regexp here to the added part.
+ $data =~ s/\r\n/\n/gs;
+
+ return $data;
+}
+
+
=head2 uri_with
$uri = $c->uri_with( ... );
@@ -533,7 +572,17 @@ sub get_photo_params {
}
sub is_abuser {
- my ($c, $email) = @_;
+ my ($c, $to) = @_;
+ my $email;
+ if (ref($to) eq 'ARRAY') {
+ if (ref($to->[0]) eq 'ARRAY') {
+ $email = $to->[0][0];
+ } else {
+ $email = $to->[0];
+ }
+ } else {
+ $email = $to;
+ }
my ($domain) = $email =~ m{ @ (.*) \z }x;
return $c->model('DB::Abuse')->search( { email => [ $email, $domain ] } )->first;
}
diff --git a/perllib/FixMyStreet/App/Controller/Admin.pm b/perllib/FixMyStreet/App/Controller/Admin.pm
index f9ea383f8..39d6ff72f 100644
--- a/perllib/FixMyStreet/App/Controller/Admin.pm
+++ b/perllib/FixMyStreet/App/Controller/Admin.pm
@@ -10,6 +10,7 @@ use Digest::SHA qw(sha1_hex);
use mySociety::EmailUtil qw(is_valid_email);
use if !$ENV{TRAVIS}, 'Image::Magick';
use DateTime::Format::Strptime;
+use List::Util 'first';
use FixMyStreet::SendReport;
@@ -363,6 +364,14 @@ sub update_contacts : Private {
$contact->api_key( $c->get_param('api_key') );
$contact->send_method( $c->get_param('send_method') );
+ # Set the photo_required flag in extra to the appropriate value
+ if ( $c->get_param('photo_required') ) {
+ $contact->set_extra_metadata_if_undefined( photo_required => 1 );
+ }
+ else {
+ $contact->unset_extra_metadata( 'photo_required' );
+ }
+
if ( %errors ) {
$c->stash->{updated} = _('Please correct the errors below');
$c->stash->{contact} = $contact;
@@ -669,12 +678,21 @@ sub report_edit : Path('report_edit') : Args(1) {
type => 'big',
} ]
: [],
+ print_report => 1,
);
}
- if ( $c->get_param('rotate_photo') ) {
- $c->forward('rotate_photo');
- return 1;
+ if (my $rotate_photo_param = $self->_get_rotate_photo_param($c)) {
+ $self->rotate_photo($c, @$rotate_photo_param);
+ if ( $c->cobrand->moniker eq 'zurich' ) {
+ # Clicking the photo rotation buttons should do nothing
+ # except for rotating the photo, so return the user
+ # to the report screen now.
+ $c->res->redirect( $c->uri_for( 'report_edit', $problem->id ) );
+ return;
+ } else {
+ return 1;
+ }
}
if ( $c->cobrand->moniker eq 'zurich' ) {
@@ -810,6 +828,85 @@ sub report_edit : Path('report_edit') : Args(1) {
return 1;
}
+sub templates : Path('templates') : Args(0) {
+ my ( $self, $c ) = @_;
+
+ $c->detach( '/page_error_404_not_found' )
+ unless $c->cobrand->moniker eq 'zurich';
+
+ my $user = $c->user;
+
+ $self->templates_for_body($c, $user->from_body );
+}
+
+sub templates_view : Path('templates') : Args(1) {
+ my ($self, $c, $body_id) = @_;
+
+ $c->detach( '/page_error_404_not_found' )
+ unless $c->cobrand->moniker eq 'zurich';
+
+ # e.g. for admin
+
+ my $body = $c->model('DB::Body')->find($body_id)
+ or $c->detach( '/page_error_404_not_found' );
+
+ $self->templates_for_body($c, $body);
+}
+
+sub template_edit : Path('templates') : Args(2) {
+ my ( $self, $c, $body_id, $template_id ) = @_;
+
+ $c->detach( '/page_error_404_not_found' )
+ unless $c->cobrand->moniker eq 'zurich';
+
+ my $body = $c->model('DB::Body')->find($body_id)
+ or $c->detach( '/page_error_404_not_found' );
+ $c->stash->{body} = $body;
+
+ my $template;
+ if ($template_id eq 'new') {
+ $template = $body->response_templates->new({});
+ }
+ else {
+ $template = $body->response_templates->find( $template_id )
+ or $c->detach( '/page_error_404_not_found' );
+ }
+
+ if ($c->req->method eq 'POST') {
+ if ($c->get_param('delete_template') eq _("Delete template")) {
+ $template->delete;
+ } else {
+ $template->title( $c->get_param('title') );
+ $template->text ( $c->get_param('text') );
+ $template->update_or_insert;
+ }
+
+ $c->res->redirect( $c->uri_for( 'templates', $body->id ) );
+ }
+
+ $c->stash->{response_template} = $template;
+
+ $c->stash->{template} = 'admin/template_edit.html';
+}
+
+
+sub templates_for_body {
+ my ( $self, $c, $body ) = @_;
+
+ $c->stash->{body} = $body;
+
+ my @templates = $body->response_templates->search(
+ undef,
+ {
+ order_by => 'title'
+ }
+ );
+
+ $c->stash->{response_templates} = \@templates;
+
+ $c->stash->{template} = 'admin/templates.html';
+}
+
sub users: Path('users') : Args(0) {
my ( $self, $c ) = @_;
@@ -1251,13 +1348,24 @@ Adds an entry into the admin_log table using the current user.
=cut
sub log_edit : Private {
- my ( $self, $c, $id, $object_type, $action ) = @_;
+ my ( $self, $c, $id, $object_type, $action, $time_spent ) = @_;
+
+ $time_spent //= 0;
+ $time_spent = 0 if $time_spent < 0;
+
+ my $user_object = do {
+ my $auth_user = $c->user;
+ $auth_user ? $auth_user->get_object : undef;
+ };
+
$c->model('DB::AdminLog')->create(
{
admin_user => $c->forward('get_user'),
+ $user_object ? ( user => $user_object ) : (), # as (rel => undef) doesn't work
object_type => $object_type,
action => $action,
object_id => $id,
+ time_spent => $time_spent,
}
)->insert();
}
@@ -1370,36 +1478,27 @@ Rotate a photo 90 degrees left or right
=cut
+# returns index of photo to rotate, if any
+sub _get_rotate_photo_param {
+ my ($self, $c) = @_;
+ my $key = first { /^rotate_photo/ } keys %{ $c->req->params } or return;
+ my ($index) = $key =~ /(\d+)$/;
+ my $direction = $c->get_param($key);
+ return [ $index || 0, $key, $direction ];
+}
+
sub rotate_photo : Private {
- my ( $self, $c ) =@_;
+ my ( $self, $c, $index, $key, $direction ) = @_;
- my $direction = $c->get_param('rotate_photo');
return unless $direction eq _('Rotate Left') or $direction eq _('Rotate Right');
- my $photo = $c->stash->{problem}->photo;
- my $file;
-
- # If photo field contains a hash
- if ( length($photo) == 40 ) {
- $file = file( $c->config->{UPLOAD_DIR}, "$photo.jpeg" );
- $photo = $file->slurp;
- }
-
- $photo = _rotate_image( $photo, $direction eq _('Rotate Left') ? -90 : 90 );
- return unless $photo;
-
- # Write out to new location
- my $fileid = sha1_hex($photo);
- $file = file( $c->config->{UPLOAD_DIR}, "$fileid.jpeg" );
-
- my $fh = $file->open('w');
- print $fh $photo;
- close $fh;
+ my $problem = $c->stash->{problem};
+ my $fileid = $problem->get_photoset($c)->rotate_image(
+ $index,
+ $direction eq _('Rotate Left') ? -90 : 90
+ ) or return;
- unlink glob FixMyStreet->path_to( 'web', 'photo', $c->stash->{problem}->id . '.*' );
-
- $c->stash->{problem}->photo( $fileid );
- $c->stash->{problem}->update();
+ $problem->update({ photo => $fileid });
return 1;
}
@@ -1449,18 +1548,6 @@ sub trim {
return $e;
}
-sub _rotate_image {
- my ($photo, $direction) = @_;
- my $image = Image::Magick->new;
- $image->BlobToImage($photo);
- my $err = $image->Rotate($direction);
- return 0 if $err;
- my @blobs = $image->ImageToBlob();
- undef $image;
- return $blobs[0];
-}
-
-
=head1 AUTHOR
Struan Donald
diff --git a/perllib/FixMyStreet/App/Controller/Photo.pm b/perllib/FixMyStreet/App/Controller/Photo.pm
index a2ec7d4c8..bc72f4bfb 100644
--- a/perllib/FixMyStreet/App/Controller/Photo.pm
+++ b/perllib/FixMyStreet/App/Controller/Photo.pm
@@ -8,8 +8,8 @@ use DateTime::Format::HTTP;
use Digest::SHA qw(sha1_hex);
use File::Path;
use File::Slurp;
-use Image::Size;
use Path::Class;
+use FixMyStreet::App::Model::PhotoSet;
use if !$ENV{TRAVIS}, 'Image::Magick';
=head1 NAME
@@ -49,13 +49,13 @@ sub during :LocalRegex('^([0-9a-f]{40})\.(temp|fulltemp)\.jpeg$') {
$c->forward( 'output', [ $photo ] );
}
-sub index :LocalRegex('^(c/)?(\d+)(?:\.(full|tn|fp))?\.jpeg$') {
+sub index :LocalRegex('^(c/)?(\d+)(?:\.(\d+))?(?:\.(full|tn|fp))?\.jpeg$') {
my ( $self, $c ) = @_;
- my ( $is_update, $id, $size ) = @{ $c->req->captures };
+ my ( $is_update, $id, $photo_number, $size ) = @{ $c->req->captures };
- my @photo;
+ my $item;
if ( $is_update ) {
- @photo = $c->model('DB::Comment')->search( {
+ ($item) = $c->model('DB::Comment')->search( {
id => $id,
state => 'confirmed',
photo => { '!=', undef },
@@ -67,34 +67,40 @@ sub index :LocalRegex('^(c/)?(\d+)(?:\.(full|tn|fp))?\.jpeg$') {
}
$c->detach( 'no_photo' ) if $id =~ /\D/;
- @photo = $c->cobrand->problems->search( {
+ ($item) = $c->cobrand->problems->search( {
id => $id,
state => [ FixMyStreet::DB::Result::Problem->visible_states(), 'partial' ],
photo => { '!=', undef },
} );
}
- $c->detach( 'no_photo' ) unless @photo;
+ $c->detach( 'no_photo' ) unless $item;
- my $item = $photo[0];
$c->detach( 'no_photo' ) unless $c->cobrand->allow_photo_display($item); # Should only be for reports, not updates
- my $photo = $item->photo;
- # If photo field contains a hash
- if (length($photo) == 40) {
- my $file = file( $c->config->{UPLOAD_DIR}, "$photo.jpeg" );
- $photo = $file->slurp;
- }
-
- if ( $size eq 'tn' ) {
- $photo = _shrink( $photo, 'x100' );
- } elsif ( $size eq 'fp' ) {
- $photo = _crop( $photo );
- } elsif ( $size eq 'full' ) {
- } elsif ( $c->cobrand->default_photo_resize ) {
- $photo = _shrink( $photo, $c->cobrand->default_photo_resize );
+ my $photo;
+ if ($item->can('get_photoset')) {
+ $photo = $item->get_photoset( $c )
+ ->get_image_data( num => $photo_number, size => $size )
+ or $c->detach( 'no_photo' );
} else {
- $photo = _shrink( $photo, '250x250' );
+ $photo = $item->photo;
+ # If photo field contains a hash
+ if (length($photo) == 40) {
+ my $file = file( $c->config->{UPLOAD_DIR}, "$photo.jpeg" );
+ $photo = $file->slurp;
+ }
+
+ if ( $size eq 'tn' ) {
+ $photo = _shrink( $photo, 'x100' );
+ } elsif ( $size eq 'fp' ) {
+ $photo = _crop( $photo );
+ } elsif ( $size eq 'full' ) {
+ } elsif ( $c->cobrand->default_photo_resize ) {
+ $photo = _shrink( $photo, $c->cobrand->default_photo_resize );
+ } else {
+ $photo = _shrink( $photo, '250x250' );
+ }
}
$c->forward( 'output', [ $photo ] );
@@ -156,84 +162,67 @@ sub process_photo : Private {
my ( $self, $c ) = @_;
return
- $c->forward('process_photo_upload')
- || $c->forward('process_photo_cache')
+ $c->forward('process_photo_upload_or_cache')
+ || $c->forward('process_photo_required')
|| 1; # always return true
}
-sub process_photo_upload : Private {
+sub process_photo_upload_or_cache : Private {
my ( $self, $c ) = @_;
-
- # check for upload or return
- my $upload = $c->req->upload('photo')
- || return;
-
- # check that the photo is a jpeg
- my $ct = $upload->type;
- $ct =~ s/x-citrix-//; # Thanks, Citrix
- # Had a report of a JPEG from an Android 2.1 coming through as a byte stream
- unless ( $ct eq 'image/jpeg' || $ct eq 'image/pjpeg' || $ct eq 'application/octet-stream' ) {
- $c->log->info('Bad photo tried to upload, type=' . $ct);
- $c->stash->{photo_error} = _('Please upload a JPEG image only');
- return;
- }
-
- # get the photo into a variable
- my $photo_blob = eval {
- my $filename = $upload->tempname;
- my $out = `jhead -se -autorot $filename 2>&1`;
- unless (defined $out) {
- my ($w, $h, $err) = Image::Size::imgsize($filename);
- die _("Please upload a JPEG image only") . "\n" if !defined $w || $err ne 'JPG';
- }
- die _("Please upload a JPEG image only") . "\n" if $out && $out =~ /Not JPEG:/;
- my $photo = $upload->slurp;
- return $photo;
- };
- if ( my $error = $@ ) {
- my $format = _(
-"That image doesn't appear to have uploaded correctly (%s), please try again."
- );
- $c->stash->{photo_error} = sprintf( $format, $error );
- return;
- }
-
- # we have an image we can use - save it to the upload dir for storage
- my $cache_dir = dir( $c->config->{UPLOAD_DIR} );
- $cache_dir->mkpath;
- unless ( -d $cache_dir && -w $cache_dir ) {
- warn "Can't find/write to photo cache directory '$cache_dir'";
- return;
- }
-
- my $fileid = sha1_hex($photo_blob);
- $upload->copy_to( file($cache_dir, $fileid . '.jpeg') );
-
- # stick the hash on the stash, so don't have to reupload in case of error
- $c->stash->{upload_fileid} = $fileid;
-
+ my @items = (
+ ( map {
+ /^photo/ ? # photo, photo1, photo2 etc.
+ ($c->req->upload($_)) : ()
+ } sort $c->req->upload),
+ split /,/, ($c->get_param('upload_fileid') || '')
+ );
+
+ my $photoset = FixMyStreet::App::Model::PhotoSet->new({
+ c => $c,
+ data_items => \@items,
+ });
+
+ my $fileid = $photoset->data;
+
+ $c->stash->{upload_fileid} = $fileid or return;
return 1;
}
-=head2 process_photo_cache
+=head2 process_photo_required
+
+Checks that a report has a photo attached if any of its Contacts
+require it (by setting extra->photo_required == 1). Puts an error in
+photo_error on the stash if it's required and missing, otherwise returns
+true.
-Look for the upload_fileid parameter and check it matches a file on disk. If it
-does return true and put fileid on stash, otherwise false.
+(Note that as we have reached this action, we *know* that the photo
+is missing, otherwise it would have already been handled.)
=cut
-sub process_photo_cache : Private {
+sub process_photo_required : Private {
my ( $self, $c ) = @_;
- # get the fileid and make sure it is just a hex number
- my $fileid = $c->get_param('upload_fileid') || '';
- $fileid =~ s{[^0-9a-f]}{}gi;
- return unless $fileid;
-
- my $file = file( $c->config->{UPLOAD_DIR}, "$fileid.jpeg" );
- return unless -e $file;
+ # load the report
+ my $report = $c->stash->{report} or return 1; # don't check photo for updates
+ my $bodies = $c->stash->{bodies};
+
+ my @contacts = $c-> #
+ model('DB::Contact') #
+ ->not_deleted #
+ ->search(
+ {
+ body_id => [ keys %$bodies ],
+ category => $report->category
+ }
+ )->all;
+ foreach my $contact ( @contacts ) {
+ if ( $contact->get_extra_metadata('photo_required') ) {
+ $c->stash->{photo_error} = _("Photo is required.");
+ return;
+ }
+ }
- $c->stash->{upload_fileid} = $fileid;
return 1;
}
diff --git a/perllib/FixMyStreet/App/Controller/Report.pm b/perllib/FixMyStreet/App/Controller/Report.pm
index 279994e47..d7cae05d4 100644
--- a/perllib/FixMyStreet/App/Controller/Report.pm
+++ b/perllib/FixMyStreet/App/Controller/Report.pm
@@ -99,13 +99,21 @@ sub load_problem_or_display_error : Private {
my $problem
= ( !$id || $id =~ m{\D} ) # is id non-numeric?
? undef # ...don't even search
- : $c->cobrand->problems->find( { id => $id } );
+ : $c->cobrand->problems->find( { id => $id } )
+ or $c->detach( '/page_error_404_not_found', [ _('Unknown problem ID') ] );
# check that the problem is suitable to show.
- if ( !$problem || ($problem->state eq 'unconfirmed' && !$c->cobrand->show_unconfirmed_reports) || $problem->state eq 'partial' ) {
+ # hidden_states includes partial and unconfirmed, but they have specific handling,
+ # so we check for them first.
+ if ( $problem->state eq 'partial' ) {
$c->detach( '/page_error_404_not_found', [ _('Unknown problem ID') ] );
}
- elsif ( $problem->state eq 'hidden' ) {
+ elsif ( $problem->state eq 'unconfirmed' ) {
+ $c->detach( '/page_error_404_not_found', [ _('Unknown problem ID') ] )
+ unless $c->cobrand->show_unconfirmed_reports ;
+ }
+ elsif ( $problem->hidden_states->{ $problem->state } or
+ (($problem->get_extra_metadata('closure_status')||'') eq 'hidden')) {
$c->detach(
'/page_error_410_gone',
[ _('That report has been removed from FixMyStreet.') ] #
diff --git a/perllib/FixMyStreet/App/Controller/Report/New.pm b/perllib/FixMyStreet/App/Controller/Report/New.pm
index d5b84815b..246facbee 100644
--- a/perllib/FixMyStreet/App/Controller/Report/New.pm
+++ b/perllib/FixMyStreet/App/Controller/Report/New.pm
@@ -93,6 +93,7 @@ sub report_new : Path : Args(0) {
$c->forward('check_for_category');
# deal with the user and report and check both are happy
+
return unless $c->forward('check_form_submitted');
$c->forward('process_user');
$c->forward('process_report');
@@ -290,7 +291,7 @@ sub report_import : Path('/import') {
}
# handle the photo upload
- $c->forward( '/photo/process_photo_upload' );
+ $c->forward( '/photo/process_photo' );
my $fileid = $c->stash->{upload_fileid};
if ( my $error = $c->stash->{photo_error} ) {
push @errors, $error;
@@ -889,8 +890,23 @@ sub process_report : Private {
$report->bodies_str(-1);
} else {
# construct the bodies string:
- # 'x,x' - x are body IDs that have this category
- my $body_string = join( ',', map { $_->body_id } @contacts );
+ my $body_string = do {
+ if ( $c->cobrand->can('singleton_bodies_str') && $c->cobrand->singleton_bodies_str ) {
+ # Cobrands like Zurich can only ever have a single body: 'x', because some functionality
+ # relies on string comparison against bodies_str.
+ if (@contacts) {
+ $contacts[0]->body_id;
+ }
+ else {
+ '';
+ }
+ }
+ else {
+ # 'x,x' - x are body IDs that have this category
+ my $bs = join( ',', map { $_->body_id } @contacts );
+ $bs;
+ };
+ };
$report->bodies_str($body_string);
# Record any body IDs which might have meant to match, but had no contact
if ($body_string && @{ $c->stash->{missing_details_bodies} }) {
@@ -1162,6 +1178,9 @@ sub redirect_or_confirm_creation : Private {
}
} );
$c->stash->{token_url} = $c->uri_for_email( '/P', $token->token );
+ if ($c->cobrand->can('problem_confirm_email_extras')) {
+ $c->cobrand->problem_confirm_email_extras($report);
+ }
$c->send_email( $template, {
to => [ $report->name ? [ $report->user->email, $report->name ] : $report->user->email ],
} );
diff --git a/perllib/FixMyStreet/App/Controller/Reports.pm b/perllib/FixMyStreet/App/Controller/Reports.pm
index 9dc0ad6bc..3bd7e592b 100644
--- a/perllib/FixMyStreet/App/Controller/Reports.pm
+++ b/perllib/FixMyStreet/App/Controller/Reports.pm
@@ -33,6 +33,7 @@ sub index : Path : Args(0) {
# Zurich goes straight to map page, with all reports
if ( $c->cobrand->moniker eq 'zurich' ) {
+ $c->forward( 'stash_report_filter_status' );
$c->forward( 'load_and_group_problems' );
my $pins = $c->stash->{pins};
$c->stash->{page} = 'reports';
diff --git a/perllib/FixMyStreet/App/Model/PhotoSet.pm b/perllib/FixMyStreet/App/Model/PhotoSet.pm
new file mode 100644
index 000000000..b18460821
--- /dev/null
+++ b/perllib/FixMyStreet/App/Model/PhotoSet.pm
@@ -0,0 +1,306 @@
+package FixMyStreet::App::Model::PhotoSet;
+
+# TODO this isn't a Cat model, rename to something else
+
+use Moose;
+use Path::Tiny 'path';
+use if !$ENV{TRAVIS}, 'Image::Magick';
+use Scalar::Util 'openhandle', 'blessed';
+use Digest::SHA qw(sha1_hex);
+use Image::Size;
+use MIME::Base64;
+
+has c => (
+ is => 'ro',
+);
+
+has object => (
+ is => 'ro',
+);
+
+has data => ( # generic data from DB field
+ is => 'ro',
+ lazy => 1,
+ default => sub {
+ # yes, this is a little circular: data -> data_items -> items -> data
+ # e.g. if not provided, then we're presumably uploading/etc., so calculate from
+ # the stored cached fileids
+ # (obviously if you provide none of these, then you'll get an infinite loop)
+ my $self = shift;
+ my $data = join ',', map { $_->[0] } $self->all_images;
+ return $data;
+ }
+);
+
+has data_items => ( # either a) split from data or b) provided by photo upload
+ isa => 'ArrayRef',
+ is => 'rw',
+ traits => ['Array'],
+ lazy => 1,
+ handles => {
+ map_data_items => 'map',
+ },
+ default => sub {
+ my $self = shift;
+ my $data = $self->data
+ or return [];
+
+ return [$data] if (_jpeg_magic($data));
+
+ return [ split ',' => $data ];
+ },
+);
+
+has upload_dir => (
+ is => 'ro',
+ lazy => 1,
+ default => sub {
+ my $self = shift;
+ my $cache_dir = path( $self->c->config->{UPLOAD_DIR} );
+ $cache_dir->mkpath;
+ unless ( -d $cache_dir && -w $cache_dir ) {
+ warn "Can't find/write to photo cache directory '$cache_dir'";
+ return;
+ }
+ $cache_dir;
+ },
+);
+
+sub _jpeg_magic {
+ $_[0] =~ /^\x{ff}\x{d8}/; # JPEG
+ # NB: should we also handle \x{89}\x{50} (PNG, 15 results in live DB) ?
+ # and \x{49}\x{49} (Tiff, 3 results in live DB) ?
+}
+
+=head2 C<images>, C<num_images>, C<get_raw_image_data>, C<all_images>
+
+C<$photoset-E<GT>images> is an AoA containing the filed and the binary image data.
+
+ [
+ [ $fileid1, $binary_data ],
+ [ $fileid2, $binary_data ],
+ ...
+ ]
+
+Various accessors are provided onto it:
+
+ num_images: count
+ get_raw_image_data ($index): return the [$fileid, $binary_data] tuple
+ all_images: return AoA as an array (e.g. rather than arrayref)
+
+=cut
+
+has images => ( # AoA of [$fileid, $binary_data] tuples
+ isa => 'ArrayRef',
+ is => 'rw',
+ traits => ['Array'],
+ lazy => 1,
+ handles => {
+ num_images => 'count',
+ get_raw_image_data => 'get',
+ all_images => 'elements',
+ },
+ default => sub {
+ my $self = shift;
+ my @photos = $self->map_data_items( sub {
+ my $part = $_;
+
+ if (blessed $part and $part->isa('Catalyst::Request::Upload')) {
+ # check that the photo is a jpeg
+ my $upload = $part;
+ my $ct = $upload->type;
+ $ct =~ s/x-citrix-//; # Thanks, Citrix
+ # Had a report of a JPEG from an Android 2.1 coming through as a byte stream
+ unless ( $ct eq 'image/jpeg' || $ct eq 'image/pjpeg' || $ct eq 'application/octet-stream' ) {
+ my $c = $self->c;
+ $c->log->info('Bad photo tried to upload, type=' . $ct);
+ $c->stash->{photo_error} = _('Please upload a JPEG image only');
+ return ();
+ }
+
+ # base64 decode the file if it's encoded that way
+ # Catalyst::Request::Upload doesn't do this automatically
+ # unfortunately.
+ my $transfer_encoding = $upload->headers->header('Content-Transfer-Encoding');
+ if (defined $transfer_encoding && $transfer_encoding eq 'base64') {
+ my $decoded = decode_base64($upload->slurp);
+ if (open my $fh, '>', $upload->tempname) {
+ binmode $fh;
+ print $fh $decoded;
+ close $fh
+ } else {
+ my $c = $self->c;
+ $c->log->info('Couldn\'t open temp file to save base64 decoded image: ' . $!);
+ $c->stash->{photo_error} = _("Sorry, we couldn't save your image(s), please try again.");
+ return ();
+ }
+ }
+
+ # get the photo into a variable
+ my $photo_blob = eval {
+ my $filename = $upload->tempname;
+ my $out = `jhead -se -autorot $filename 2>&1`;
+ unless (defined $out) {
+ my ($w, $h, $err) = Image::Size::imgsize($filename);
+ die _("Please upload a JPEG image only") . "\n" if !defined $w || $err ne 'JPG';
+ }
+ die _("Please upload a JPEG image only") . "\n" if $out && $out =~ /Not JPEG:/;
+ my $photo = $upload->slurp;
+ };
+ if ( my $error = $@ ) {
+ my $format = _(
+ "That image doesn't appear to have uploaded correctly (%s), please try again."
+ );
+ $self->c->stash->{photo_error} = sprintf( $format, $error );
+ return ();
+ }
+
+ # we have an image we can use - save it to the upload dir for storage
+ my $fileid = $self->get_fileid($photo_blob);
+ my $file = $self->get_file($fileid);
+ $upload->copy_to( $file );
+ return [$fileid, $photo_blob];
+
+ }
+ if (_jpeg_magic($part)) {
+ my $photo_blob = $part;
+ my $fileid = $self->get_fileid($photo_blob);
+ my $file = $self->get_file($fileid);
+ $file->spew_raw($photo_blob);
+ return [$fileid, $photo_blob];
+ }
+ if (length($part) == 40) {
+ my $fileid = $part;
+ my $file = $self->get_file($fileid);
+ if ($file->exists) {
+ my $photo = $file->slurp_raw;
+ [$fileid, $photo];
+ }
+ else {
+ warn "File $fileid doesn't exist";
+ ();
+ }
+ }
+ else {
+ warn sprintf "Received bad photo hash of length %d", length($part);
+ ();
+ }
+ });
+ return \@photos;
+ },
+);
+
+sub get_fileid {
+ my ($self, $photo_blob) = @_;
+ return sha1_hex($photo_blob);
+}
+
+sub get_file {
+ my ($self, $fileid) = @_;
+ my $cache_dir = $self->upload_dir;
+ return path( $cache_dir, "$fileid.jpeg" );
+}
+
+sub get_image_data {
+ my ($self, %args) = @_;
+ my $num = $args{num} || 0;
+
+ my $data = $self->get_raw_image_data( $num )
+ or return;
+
+ my ($fileid, $photo) = @$data;
+
+ my $size = $args{size};
+ if ( $size eq 'tn' ) {
+ $photo = _shrink( $photo, 'x100' );
+ } elsif ( $size eq 'fp' ) {
+ $photo = _crop( $photo );
+ } elsif ( $size eq 'full' ) {
+ # do nothing
+ } else {
+ $photo = _shrink( $photo, $self->c->cobrand->default_photo_resize || '250x250' );
+ }
+
+ return $photo;
+}
+
+sub delete_cached {
+ my ($self) = @_;
+ my $object = $self->object or return;
+
+ unlink glob FixMyStreet->path_to(
+ 'web',
+ 'photo',
+ $object->id . '.*'
+ );
+}
+
+sub rotate_image {
+ my ($self, $index, $direction) = @_;
+
+ my @images = $self->all_images;
+ return if $index > $#images;
+
+ my @items = map $_->[0], @images;
+ $items[$index] = _rotate_image( $images[$index][1], $direction );
+
+ my $new_set = (ref $self)->new({
+ data_items => \@items,
+ c => $self->c,
+ object => $self->object,
+ });
+
+ $self->delete_cached();
+
+ return $new_set->data; # e.g. new comma-separated fileid
+}
+
+sub _rotate_image {
+ my ($photo, $direction) = @_;
+ return $photo unless $Image::Magick::VERSION;
+ my $image = Image::Magick->new;
+ $image->BlobToImage($photo);
+ my $err = $image->Rotate($direction);
+ return 0 if $err;
+ my @blobs = $image->ImageToBlob();
+ undef $image;
+ return $blobs[0];
+}
+
+
+
+
+
+# NB: These 2 subs stolen from A::C::Photo, should be purged from there!
+#
+# Shrinks a picture to the specified size, but keeping in proportion.
+sub _shrink {
+ my ($photo, $size) = @_;
+ return $photo unless $Image::Magick::VERSION;
+ my $image = Image::Magick->new;
+ $image->BlobToImage($photo);
+ my $err = $image->Scale(geometry => "$size>");
+ throw Error::Simple("resize failed: $err") if "$err";
+ $image->Strip();
+ my @blobs = $image->ImageToBlob();
+ undef $image;
+ return $blobs[0];
+}
+
+# Shrinks a picture to 90x60, cropping so that it is exactly that.
+sub _crop {
+ my ($photo) = @_;
+ return $photo unless $Image::Magick::VERSION;
+ my $image = Image::Magick->new;
+ $image->BlobToImage($photo);
+ my $err = $image->Resize( geometry => "90x60^" );
+ throw Error::Simple("resize failed: $err") if "$err";
+ $err = $image->Extent( geometry => '90x60', gravity => 'Center' );
+ throw Error::Simple("resize failed: $err") if "$err";
+ $image->Strip();
+ my @blobs = $image->ImageToBlob();
+ undef $image;
+ return $blobs[0];
+}
+
+1;
diff --git a/perllib/FixMyStreet/App/View/Web.pm b/perllib/FixMyStreet/App/View/Web.pm
index 9cc571efc..37a81e444 100644
--- a/perllib/FixMyStreet/App/View/Web.pm
+++ b/perllib/FixMyStreet/App/View/Web.pm
@@ -133,6 +133,9 @@ sub escape_js {
'>' => 'u003e',
);
$text =~ s/([\\"'<>])/\\$lookup{$1}/g;
+
+ $text =~ s/(?:\r\n|\n|\r)/\\n/g; # replace newlines
+
return $text;
}
diff --git a/perllib/FixMyStreet/Cobrand/Default.pm b/perllib/FixMyStreet/Cobrand/Default.pm
index c347d5750..9541f2601 100644
--- a/perllib/FixMyStreet/Cobrand/Default.pm
+++ b/perllib/FixMyStreet/Cobrand/Default.pm
@@ -913,4 +913,48 @@ sub jurisdiction_id_example {
return $self->moniker;
}
+=head2 body_details_data
+
+Returns a list of bodies to create with ensure_body. These
+are mostly just passed to ->find_or_create, but there is some
+pre-processing so that you can enter:
+
+ area_id => 123,
+ parent => 'Big Town',
+
+instead of
+
+ body_areas => [ { area_id => 123 } ],
+ parent => { name => 'Big Town' },
+
+For example:
+
+ return (
+ {
+ name => 'Big Town',
+ },
+ {
+ name => 'Small town',
+ parent => 'Big Town',
+ area_id => 1234,
+ },
+
+
+=cut
+
+sub body_details_data {
+ return ();
+}
+
+=head2 contact_details_data
+
+Returns a list of contact_data to create with setup_contacts.
+See Zurich for an example.
+
+=cut
+
+sub contact_details_data {
+ return ()
+}
+
1;
diff --git a/perllib/FixMyStreet/Cobrand/Zurich.pm b/perllib/FixMyStreet/Cobrand/Zurich.pm
index 9ed65c5f5..6da3e566c 100644
--- a/perllib/FixMyStreet/Cobrand/Zurich.pm
+++ b/perllib/FixMyStreet/Cobrand/Zurich.pm
@@ -5,9 +5,12 @@ use DateTime;
use POSIX qw(strcoll);
use RABX;
use Scalar::Util 'blessed';
+use DateTime::Format::Pg;
use strict;
use warnings;
+use feature 'say';
+use utf8;
=head1 NAME
@@ -105,8 +108,11 @@ sub prettify_dt {
sub zurich_closed_states {
my $states = {
'fixed - council' => 1,
- 'closed' => 1,
+ 'closed' => 1, # extern
'hidden' => 1,
+ 'investigating' => 1, # wish
+ 'unable to fix' => 1, # jurisdiction unknown
+ 'partial' => 1, # not contactable
};
return wantarray ? keys %{ $states } : $states;
@@ -117,6 +123,37 @@ sub problem_is_closed {
return exists $self->zurich_closed_states->{ $problem->state } ? 1 : 0;
}
+sub zurich_public_response_states {
+ my $states = {
+ 'fixed - council' => 1,
+ 'closed' => 1, # extern
+ 'unable to fix' => 1, # jurisdiction unknown
+ };
+
+ return wantarray ? keys %{ $states } : $states;
+}
+
+sub zurich_user_response_states {
+ my $states = {
+ 'hidden' => 1,
+ 'investigating' => 1, # wish
+ 'partial' => 1, # not contactable
+ };
+
+ return wantarray ? keys %{ $states } : $states;
+}
+
+sub problem_has_public_response {
+ my ($self, $problem) = @_;
+ return exists $self->zurich_public_response_states->{ $problem->state } ? 1 : 0;
+}
+
+sub problem_has_user_response {
+ my ($self, $problem) = @_;
+ my $state_matches = exists $self->zurich_user_response_states->{ $problem->state } ? 1 : 0;
+ return $state_matches && $problem->get_extra_metadata('public_response');
+}
+
sub problem_as_hashref {
my $self = shift;
my $problem = shift;
@@ -132,16 +169,35 @@ sub problem_as_hashref {
$hashref->{title} = _('This report is awaiting moderation.');
$hashref->{state} = 'submitted';
$hashref->{state_t} = _('Submitted');
+ $hashref->{banner_id} = 'closed';
} else {
if ( $problem->state eq 'confirmed' ) {
$hashref->{state} = 'open';
$hashref->{state_t} = _('Open');
+ $hashref->{banner_id} = 'closed';
+ } elsif ( $problem->state eq 'closed' ) {
+ $hashref->{state} = 'extern'; # is this correct?
+ $hashref->{banner_id} = 'closed';
+ $hashref->{state_t} = _('Extern');
+ } elsif ( $problem->state eq 'unable to fix' ) {
+ $hashref->{state} = 'jurisdiction unknown'; # is this correct?
+ $hashref->{state_t} = _('Jurisdiction Unknown');
+ $hashref->{banner_id} = 'fixed'; # green
+ } elsif ( $problem->state eq 'partial' ) {
+ $hashref->{state} = 'not contactable'; # is this correct?
+ $hashref->{state_t} = _('Not contactable');
+ # no banner_id as hidden
+ } elsif ( $problem->state eq 'investigating' ) {
+ $hashref->{state} = 'wish'; # is this correct?
+ $hashref->{state_t} = _('Wish');
} elsif ( $problem->is_fixed ) {
$hashref->{state} = 'closed';
+ $hashref->{banner_id} = 'fixed';
$hashref->{state_t} = _('Closed');
} elsif ( $problem->state eq 'in progress' || $problem->state eq 'planned' ) {
$hashref->{state} = 'in progress';
$hashref->{state_t} = _('In progress');
+ $hashref->{banner_id} = 'progress';
}
}
@@ -275,13 +331,46 @@ sub get_or_check_overdue {
return $self->overdue($problem);
}
+=head1 C<set_problem_state>
+
+If the state has changed, sets the state and calls C::Admin's C<log_edit> action.
+If the state hasn't changed, defers to update_admin_log (to update time_spent if any).
+
+Returns either undef or the AdminLog entry created.
+
+=cut
+
sub set_problem_state {
my ($self, $c, $problem, $new_state) = @_;
- return if $new_state eq $problem->state;
+ return $self->update_admin_log($c, $problem) if $new_state eq $problem->state;
$problem->state( $new_state );
$c->forward( 'log_edit', [ $problem->id, 'problem', "state change to $new_state" ] );
}
+=head1 C<update_admin_log>
+
+Calls C::Admin's C<log_edit> if either a) text is provided, or b) there has
+been time_spent on the task. As set_problem_state will already call log_edit
+if required, don't call this as well.
+
+Returns either undef or the AdminLog entry created.
+
+=cut
+
+sub update_admin_log {
+ my ($self, $c, $problem, $text) = @_;
+
+ my $time_spent = ( ($c->get_param('time_spent') // 0) + 0 );
+ $c->set_param('time_spent' => 0); # explicitly zero this to avoid duplicates
+
+ if (!$text) {
+ return unless $time_spent;
+ $text = "Logging time_spent";
+ }
+
+ $c->forward( 'log_edit', [ $problem->id, 'problem', $text, $time_spent ] );
+}
+
# Specific administrative displays
sub admin_pages {
@@ -289,23 +378,25 @@ sub admin_pages {
my $c = $self->{c};
my $type = $c->stash->{admin_type};
+
my $pages = {
'summary' => [_('Summary'), 0],
'reports' => [_('Reports'), 2],
'report_edit' => [undef, undef],
'update_edit' => [undef, undef],
+ 'stats' => [_('Stats'), 4],
};
return $pages if $type eq 'sdm';
$pages = { %$pages,
'bodies' => [_('Bodies'), 1],
'body' => [undef, undef],
+ 'templates' => [_('Templates'), 2],
};
return $pages if $type eq 'dm';
$pages = { %$pages,
'users' => [_('Users'), 3],
- 'stats' => [_('Stats'), 4],
'user_edit' => [undef, undef],
};
return $pages if $type eq 'super';
@@ -448,7 +539,7 @@ sub admin_report_edit {
}
- # If super or sdm check that the token is correct before proceeding
+ # If super or dm check that the token is correct before proceeding
if ( ($type eq 'super' || $type eq 'dm') && $c->get_param('submit') ) {
$c->forward('check_token');
}
@@ -468,6 +559,7 @@ sub admin_report_edit {
}
}
+
# Problem updates upon submission
if ( ($type eq 'super' || $type eq 'dm') && $c->get_param('submit') ) {
$problem->set_extra_metadata('publish_photo' => $c->get_param('publish_photo') || 0 );
@@ -488,10 +580,43 @@ sub admin_report_edit {
my $internal_note_text = "";
# Workflow things
+ #
+ # Note that 2 types of email may be sent
+ # 1) _admin_send_email() sends an email to the *user*, if their email is confirmed
+ #
+ # 2) setting $problem->whensent(undef) may make it eligible for generating an email
+ # to the body (internal or external). See DBRS::Problem->send_reports for Zurich-
+ # specific categories which are eligible for this.
+ #
+ # It looks like both of these will do:
+ # a) TT processing of [% ... %] directives, in FMS::App->send_email(_cron)
+ # b) pseudo-PHP substitution of <?=$values['name']?> which is done as
+ # naive substitution
+ # commonlib mySociety::Email
+ #
+ # So it makes sense to add new parameters as the more powerful TT (a).
+
my $redirect = 0;
- my $new_cat = $c->get_param('category');
- if ( $new_cat && $new_cat ne $problem->category ) {
- my $cat = $c->model('DB::Contact')->search( { category => $c->get_param('category') } )->first;
+ my $new_cat = $c->get_param('category') || '';
+ my $state = $c->get_param('state') || '';
+ my $oldstate = $problem->state;
+
+ my $closure_states = $self->zurich_closed_states;
+ delete $closure_states->{'fixed - council'}; # may not be needed?
+
+ my $old_closure_state = $problem->get_extra_metadata('closure_status');
+
+ # update the public update from DM
+ if (my $update = $c->get_param('status_update')) {
+ $problem->set_extra_metadata(public_response => $update);
+ }
+
+ if (
+ ($state eq 'confirmed')
+ && $new_cat
+ && $new_cat ne $problem->category
+ ) {
+ my $cat = $c->model('DB::Contact')->search({ category => $c->get_param('category') } )->first;
my $old_cat = $problem->category;
$problem->category( $new_cat );
$problem->external_body( undef );
@@ -499,7 +624,25 @@ sub admin_report_edit {
$problem->whensent( undef );
$problem->set_extra_metadata(changed_category => 1);
$internal_note_text = "Weitergeleitet von $old_cat an $new_cat";
+ $self->update_admin_log($c, $problem, "Changed category from $old_cat to $new_cat");
$redirect = 1 if $cat->body_id ne $body->id;
+ } elsif ( $closure_states->{$state} and
+ ( $oldstate ne 'planned' )
+ || (($old_closure_state ||'') ne $state))
+ {
+ # for these states
+ # - closed (Extern)
+ # - investigating (Wish)
+ # - hidden
+ # - partial (Not contactable)
+ # - unable to fix (Jurisdiction unknown)
+ # we divert to planned (Rueckmeldung ausstehend) and set closure_status to the requested state
+ # From here, the DM can reply to the user, triggering the setting of problem to correct state
+ $problem->set_extra_metadata( closure_status => $state );
+ $self->set_problem_state($c, $problem, 'planned');
+ $state = 'planned';
+ $problem->set_extra_metadata_if_undefined( moderated_overdue => $self->overdue( $problem ) );
+
} elsif ( my $subdiv = $c->get_param('body_subdivision') ) {
$problem->set_extra_metadata_if_undefined( moderated_overdue => $self->overdue( $problem ) );
$self->set_problem_state($c, $problem, 'in progress');
@@ -507,31 +650,82 @@ sub admin_report_edit {
$problem->bodies_str( $subdiv );
$problem->whensent( undef );
$redirect = 1;
- } elsif ( my $external = $c->get_param('body_external') ) {
- $problem->set_extra_metadata_if_undefined( moderated_overdue => $self->overdue( $problem ) );
- $self->set_problem_state($c, $problem, 'closed');
- $problem->set_extra_metadata_if_undefined( closed_overdue => $self->overdue( $problem ) );
- $problem->external_body( $external );
- $problem->whensent( undef );
- _admin_send_email( $c, 'problem-external.txt', $problem );
- $redirect = 1;
} else {
- if (my $state = $c->get_param('state')) {
+ if ($state) {
- if ($problem->state eq 'unconfirmed' and $state ne 'unconfirmed') {
+ if ($oldstate eq 'unconfirmed' and $state ne 'unconfirmed') {
# only set this for the first state change
$problem->set_extra_metadata_if_undefined( moderated_overdue => $self->overdue( $problem ) );
}
- $self->set_problem_state($c, $problem, $state);
+ $self->set_problem_state($c, $problem, $state)
+ unless $closure_states->{$state};
+ # we'll defer to 'planned' clause below to change the state
+ }
+ }
+
+ if ($problem->state eq 'planned') {
+ # Rueckmeldung ausstehend
+ # override $state from the metadata set above
+ $state = $problem->get_extra_metadata('closure_status') || '';
+ my ($moderated, $closed) = (0, 0);
- if ($self->problem_is_closed($problem)) {
- $problem->set_extra_metadata_if_undefined( closed_overdue => $self->overdue( $problem ) );
+ if ($state eq 'hidden' && $c->get_param('publish_response') ) {
+ _admin_send_email( $c, 'problem-rejected.txt', $problem );
+
+ $self->set_problem_state($c, $problem, $state);
+ $moderated++;
+ $closed++;
+ }
+ elsif ($state =~/^(closed|investigating)$/) { # Extern | Wish
+ $moderated++;
+ # Nested if instead of `and` because in these cases, we *don't*
+ # want to close unless we have body_external (so we don't want
+ # the final elsif clause below to kick in on publish_response)
+ if (my $external = $c->get_param('body_external')) {
+ my $external_body = $c->model('DB::Body')->find($external)
+ or die "Body $external not found";
+ $problem->external_body( $external );
+ }
+ if ($problem->external_body && $c->get_param('publish_response')) {
+ $problem->whensent( undef );
+ $self->set_problem_state($c, $problem, $state);
+ my $template = ($state eq 'investigating') ? 'problem-wish.txt' : 'problem-external.txt';
+ _admin_send_email( $c, $template, $problem );
+ $redirect = 0;
+ $closed++;
}
- if ( $state eq 'hidden' && $c->get_param('send_rejected_email') ) {
- _admin_send_email( $c, 'problem-rejected.txt', $problem );
+ # set the external_message in extra, so that it can be edited again
+ if ( my $external_message = $c->get_param('external_message') ) {
+ $problem->set_extra_metadata( external_message => $external_message );
}
+ # else should really return a message here
+ }
+ elsif ($c->get_param('publish_response')) {
+ # otherwise we only set the state if publish_response is set
+ #
+
+ # if $state wasn't set, then we are simply closing the message as fixed
+ $state ||= 'fixed - council';
+ _admin_send_email( $c, 'problem-closed.txt', $problem );
+ $redirect = 0;
+ $moderated++;
+ $closed++;
+ }
+
+ if ($moderated) {
+ $problem->set_extra_metadata_if_undefined( moderated_overdue => $self->overdue( $problem ) );
}
+
+ if ($closed) {
+ # set to either the closure_status from metadata or 'fixed - council' as above
+ $self->set_problem_state($c, $problem, $state);
+ $problem->set_extra_metadata_if_undefined( closed_overdue => $self->overdue( $problem ) );
+ $problem->unset_extra_metadata('closure_status');
+ }
+ }
+ else {
+ $problem->unset_extra_metadata('closure_status');
}
$problem->title( $c->get_param('title') ) if $c->get_param('title');
@@ -539,21 +733,42 @@ sub admin_report_edit {
$problem->latitude( $c->get_param('latitude') );
$problem->longitude( $c->get_param('longitude') );
- # Final, public, Update from DM
- if (my $update = $c->get_param('status_update')) {
- $problem->set_extra_metadata(public_response => $update);
- if ($c->get_param('publish_response')) {
- $self->set_problem_state($c, $problem, 'fixed - council');
- $problem->set_extra_metadata( closed_overdue => $self->overdue( $problem ) );
- _admin_send_email( $c, 'problem-closed.txt', $problem );
- }
+ # send external_message if provided and state is *now* Wish|Extern
+ # e.g. was already, or was set in the Rueckmeldung ausstehend clause above.
+ if ( my $external_message = $c->get_param('external_message')
+ and $problem->state =~ /^(closed|investigating)$/)
+ {
+ my $external = $problem->external_body;
+ my $external_body = $c->model('DB::Body')->find($external)
+ or die "Body $external not found";
+
+ $problem->set_extra_metadata_if_undefined( moderated_overdue => $self->overdue( $problem ) );
+ # Create a Comment on this Problem with the content of the external message.
+ # NB this isn't directly shown anywhere, but is for logging purposes.
+ $problem->add_to_comments( {
+ text => (
+ sprintf '(%s %s) %s',
+ $state eq 'closed' ?
+ _('Forwarded to external body') :
+ _('Forwarded wish to external body'),
+ $external_body->name,
+ $external_message,
+ ),
+ user => $c->user->obj,
+ state => 'hidden', # seems best fit, should not be shown publicly
+ mark_fixed => 0,
+ anonymous => 1,
+ extra => { is_internal_note => 1, is_external_message => 1 },
+ } );
+ # set the external_message in extra, so that it will be picked up
+ # later by send-reports
+ $problem->set_extra_metadata( external_message => $external_message );
}
$problem->lastupdate( \'current_timestamp' );
$problem->update;
- $c->stash->{status_message} =
- '<p><em>' . _('Updated!') . '</em></p>';
+ $c->stash->{status_message} = '<p class="message-updated">' . _('Updated!') . '</p>';
# do this here otherwise lastupdate and confirmed times
# do not display correctly (reloads problem from database, including
@@ -572,14 +787,21 @@ sub admin_report_edit {
} );
}
- if ( $redirect ) {
- $c->detach('index');
+ # Just update if time_spent still hasn't been logged
+ # (this will only happen if no other update_admin_log has already been called)
+ $self->update_admin_log($c, $problem);
+
+ if ( $redirect and $type eq 'dm' ) {
+ # only redirect for DM
+ $c->stash->{status_message} ||= '<p class="message-updated">' . _('Updated!') . '</p>';
+ $c->go('index');
}
$c->stash->{updates} = [ $c->model('DB::Comment')
->search( { problem_id => $problem->id }, { order_by => 'created' } )
->all ];
+ $self->stash_states($problem);
return 1;
}
@@ -588,15 +810,32 @@ sub admin_report_edit {
# Has cut-down edit template for adding update and sending back up only
$c->stash->{template} = 'admin/report_edit-sdm.html';
- if ($c->get_param('send_back')) {
+ if ($c->get_param('send_back') or $c->get_param('not_contactable')) {
+ # SDM can send back a report either to be assigned to a different
+ # subdivision, or because the customer was not contactable.
+ # We handle these in the same way but with different statuses.
+
$c->forward('check_token');
+ my $not_contactable = $c->get_param('not_contactable');
+
$problem->bodies_str( $body->parent->id );
- $self->set_problem_state($c, $problem, 'confirmed');
+ if ($not_contactable) {
+ # we can't directly set state, but mark the closure_status for DM to confirm.
+ $self->set_problem_state($c, $problem, 'planned');
+ $problem->set_extra_metadata( closure_status => 'partial');
+ }
+ else {
+ $self->set_problem_state($c, $problem, 'confirmed');
+ }
$problem->update;
- # log here
+ $c->forward( 'log_edit', [ $problem->id, 'problem',
+ $not_contactable ?
+ _('Customer not contactable')
+ : _('Sent report back') ] );
+ # Make sure the problem's time_spent is updated
+ $self->update_admin_log($c, $problem);
$c->res->redirect( '/admin/summary' );
-
} elsif ($c->get_param('submit')) {
$c->forward('check_token');
@@ -621,8 +860,10 @@ sub admin_report_edit {
anonymous => 1,
} );
}
+ # Make sure the problem's time_spent is updated
+ $self->update_admin_log($c, $problem);
- $c->stash->{status_message} = '<p><em>' . _('Updated!') . '</em></p>';
+ $c->stash->{status_message} = '<p class="message-updated">' . _('Updated!') . '</p>';
# If they clicked the no more updates button, we're done.
if ($c->get_param('no_more_updates')) {
@@ -639,14 +880,113 @@ sub admin_report_edit {
->search( { problem_id => $problem->id }, { order_by => 'created' } )
->all ];
+ $self->stash_states($problem);
return 1;
}
+ $self->stash_states($problem);
return 0;
}
+sub stash_states {
+ my ($self, $problem) = @_;
+ my $c = $self->{c};
+
+ # current problem state affects which states are visible in dropdowns
+ my @states = (
+ {
+ # Erfasst
+ state => 'unconfirmed',
+ trans => _('Submitted'),
+ unconfirmed => 1,
+ hidden => 1,
+ },
+ {
+ # Aufgenommen
+ state => 'confirmed',
+ trans => _('Open'),
+ unconfirmed => 1,
+ },
+ {
+ # Unsichtbar (hidden)
+ state => 'hidden',
+ trans => _('Hidden'),
+ unconfirmed => 1,
+ hidden => 1,
+ },
+ {
+ # Extern
+ state => 'closed',
+ trans => _('Extern'),
+ },
+ {
+ # Zustaendigkeit unbekannt
+ state => 'unable to fix',
+ trans => _('Jurisdiction unknown'),
+ },
+ {
+ # Wunsch (hidden)
+ state => 'investigating',
+ trans => _('Wish'),
+ },
+ {
+ # Nicht kontaktierbar (hidden)
+ state => 'partial',
+ trans => _('Not contactable'),
+ },
+ );
+ my %state_trans = map { $_->{state} => $_->{trans} } @states;
+
+ my $state = $problem->state;
+
+ # Rueckmeldung ausstehend may also indicate the status it's working towards.
+ push @states, do {
+ if ($state eq 'planned' and my $closure_status = $problem->get_extra_metadata('closure_status')) {
+ {
+ state => $closure_status,
+ trans => sprintf '%s (%s)', _('Planned'), $state_trans{$closure_status},
+ };
+ }
+ else {
+ {
+ state => 'planned',
+ trans => _('Planned'),
+ };
+ }
+ };
+
+ if ($state eq 'in progress') {
+ push @states, {
+ state => 'in progress',
+ trans => _('In progress'),
+ };
+ }
+ elsif ($state eq 'fixed - council') {
+ push @states, {
+ state => 'fixed - council',
+ trans => _('Closed'),
+ };
+ }
+ elsif ($state =~/^(hidden|unconfirmed)$/) {
+ @states = grep { $_->{$state} } @states;
+ }
+ $c->stash->{states} = \@states;
+ $c->stash->{states_trans} = { map { $_->{state} => $_->{trans} } @states }; # [% states_trans.${problem.state} %]
+
+ # stash details about the public response
+ $c->stash->{default_public_response} = "\nFreundliche Grüsse\n\nIhre Stadt Zürich\n";
+ $c->stash->{show_publish_response} =
+ ($problem->state eq 'planned');
+}
+
+=head2 _admin_send_email
+
+Send an email to the B<user> who logged the problem, if their email address is confirmed.
+
+=cut
+
sub _admin_send_email {
my ( $c, $template, $problem ) = @_;
@@ -665,9 +1005,36 @@ sub _admin_send_email {
to => [ $to ],
url => $c->uri_for_email( $problem->url ),
from => [ $sender, $sender_name ],
+ problem => $problem,
} );
}
+sub munge_sendreport_params {
+ my ($self, $c, $row, $h, $params) = @_;
+ if ($row->state =~ /^(closed|investigating)$/ && $row->get_extra_metadata('publish_photo')) {
+ # we attach images to reports sent to external bodies
+ my $photoset = $row->get_photoset($c);
+ my @images = $photoset->all_images
+ or return;
+ my $index = 0;
+ my $id = $row->id;
+ my @attachments = map {
+ my $i = $index++;
+ {
+ body => $_->[1],
+ attributes => {
+ filename => "$id.$i.jpeg",
+ content_type => 'image/jpeg',
+ encoding => 'base64',
+ # quoted-printable ends up with newlines corrupting binary data
+ name => "$id.$i.jpeg",
+ },
+ }
+ } @images;
+ $params->{attachments} = \@attachments;
+ }
+}
+
sub admin_fetch_all_bodies {
my ( $self, @bodies ) = @_;
@@ -718,7 +1085,10 @@ sub admin_stats {
if ($y && $m) {
$c->stash->{start_date} = DateTime->new( year => $y, month => $m, day => 1 );
$c->stash->{end_date} = $c->stash->{start_date} + DateTime::Duration->new( months => 1 );
- $date_params{created} = { '>=', $c->stash->{start_date}, '<', $c->stash->{end_date} };
+ $date_params{created} = {
+ '>=', DateTime::Format::Pg->format_datetime($c->stash->{start_date}),
+ '<', DateTime::Format::Pg->format_datetime($c->stash->{end_date}),
+ };
}
my %params = (
@@ -730,6 +1100,8 @@ sub admin_stats {
my $problems = $c->model('DB::Problem')->search(
{%date_params},
{
+ join => 'admin_log_entries',
+ distinct => 1,
columns => [
'id', 'created',
'latitude', 'longitude',
@@ -741,10 +1113,11 @@ sub admin_stats {
'whensent', 'lastupdate',
'service',
'extra',
- ],
+ { sum_time_spent => { sum => 'admin_log_entries.time_spent' } },
+ ]
}
);
- my $body = "Report ID,Created,Sent to Agency,Last Updated,E,N,Category,Status,UserID,External Body,Title,Detail,Media URL,Interface Used,Council Response\n";
+ my $body = "Report ID,Created,Sent to Agency,Last Updated,E,N,Category,Status,UserID,External Body,Time Spent,Title,Detail,Media URL,Interface Used,Council Response\n";
require Text::CSV;
my $csv = Text::CSV->new({ binary => 1 });
while ( my $report = $problems->next ) {
@@ -759,7 +1132,10 @@ sub admin_stats {
# replace newlines with HTML <br/> element
$detail =~ s{\r?\n}{ <br/> }g;
- $public_response =~ s{\r?\n}{ <br/> }g;
+ $public_response =~ s{\r?\n}{ <br/> }g if $public_response;
+
+ # Assemble photo URL, if report has a photo
+ my $media_url = $report->get_photo_params->{url} ? ($c->cobrand->base_url . $report->get_photo_params->{url}) : '';
my @columns = (
$report->id,
@@ -769,9 +1145,10 @@ sub admin_stats {
$report->local_coords, $report->category,
$report->state, $report->user_id,
$body_name,
+ $report->get_column('sum_time_spent') || 0,
$report->title,
$detail,
- $c->cobrand->base_url . $report->get_photo_params->{url},
+ $media_url,
$report->service || 'Web interface',
$public_response,
);
@@ -850,4 +1227,111 @@ sub admin_stats {
return 1;
}
+sub problem_confirm_email_extras {
+ my ($self, $report) = @_;
+ my $confirmed_reports = $report->user->problems->search({
+ extra => { like => '%email_confirmed%' },
+ })->count;
+
+ $self->{c}->stash->{email_confirmed} = $confirmed_reports;
+}
+
+sub body_details_data {
+ return (
+ {
+ name => 'Stadt Zurich'
+ },
+ {
+ name => 'Elektrizitäwerk Stadt Zürich',
+ parent => 'Stadt Zurich',
+ area_id => 423017,
+ },
+ {
+ name => 'ERZ Entsorgung + Recycling Zürich',
+ parent => 'Stadt Zurich',
+ area_id => 423017,
+ },
+ {
+ name => 'Fachstelle Graffiti',
+ parent => 'Stadt Zurich',
+ area_id => 423017,
+ },
+ {
+ name => 'Grün Stadt Zürich',
+ parent => 'Stadt Zurich',
+ area_id => 423017,
+ },
+ {
+ name => 'Tiefbauamt Stadt Zürich',
+ parent => 'Stadt Zurich',
+ area_id => 423017,
+ },
+ {
+ name => 'Dienstabteilung Verkehr',
+ parent => 'Stadt Zurich',
+ area_id => 423017,
+ },
+ );
+}
+
+sub contact_details_data {
+ return (
+ {
+ category => 'Beleuchtung/Uhren',
+ body_name => 'Elektrizitätswerk Stadt Zürich',
+ fields => [
+ {
+ code => 'strasse',
+ description => 'Strasse',
+ datatype => 'string',
+ required => 'yes',
+ },
+ {
+ code => 'haus_nr',
+ description => 'Haus-Nr.',
+ datatype => 'string',
+ },
+ {
+ code => 'mast_nr',
+ description => 'Mast-Nr.',
+ datatype => 'string',
+ }
+ ],
+ },
+ {
+ category => 'Brunnen/Hydranten',
+ # body_name ???
+ fields => [
+ {
+ code => 'hydranten_nr',
+ description => 'Hydranten-Nr.',
+ datatype => 'string',
+ },
+ ],
+ },
+ {
+ category => "Grünflächen/Spielplätze",
+ body_name => 'Grün Stadt Zürich',
+ rename_from => "Tiere/Grünflächen",
+ },
+ {
+ category => 'Spielplatz/Sitzbank',
+ body_name => 'Grün Stadt Zürich',
+ delete => 1,
+ },
+ );
+}
+
+sub contact_details_data_body_default {
+ my ($self) = @_;
+ # temporary measure to assign un-bodied contacts to parent
+ # (this isn't at all how things will be setup in live, but is
+ # handy during dev.)
+ return $self->{c}->model('DB::Body')->find({ name => 'Stadt Zurich' });
+}
+
+sub reports_per_page { return 20; }
+
+sub singleton_bodies_str { 1 }
+
1;
diff --git a/perllib/FixMyStreet/DB/Result/AdminLog.pm b/perllib/FixMyStreet/DB/Result/AdminLog.pm
index fcf909692..d60915cfc 100644
--- a/perllib/FixMyStreet/DB/Result/AdminLog.pm
+++ b/perllib/FixMyStreet/DB/Result/AdminLog.pm
@@ -37,6 +37,8 @@ __PACKAGE__->add_columns(
{ data_type => "integer", is_foreign_key => 1, is_nullable => 1 },
"reason",
{ data_type => "text", default_value => "", is_nullable => 0 },
+ "time_spent",
+ { data_type => "integer", default_value => "0", is_nullable => 0 },
);
__PACKAGE__->set_primary_key("id");
__PACKAGE__->belongs_to(
diff --git a/perllib/FixMyStreet/DB/Result/Body.pm b/perllib/FixMyStreet/DB/Result/Body.pm
index 0c1046cd8..a2e004c6a 100644
--- a/perllib/FixMyStreet/DB/Result/Body.pm
+++ b/perllib/FixMyStreet/DB/Result/Body.pm
@@ -18,12 +18,6 @@ __PACKAGE__->add_columns(
is_nullable => 0,
sequence => "body_id_seq",
},
- "name",
- { data_type => "text", is_nullable => 0 },
- "external_url",
- { data_type => "text", is_nullable => 1 },
- "parent",
- { data_type => "integer", is_foreign_key => 1, is_nullable => 1 },
"endpoint",
{ data_type => "text", is_nullable => 1 },
"jurisdiction",
@@ -42,8 +36,14 @@ __PACKAGE__->add_columns(
{ data_type => "boolean", default_value => \"false", is_nullable => 0 },
"send_extended_statuses",
{ data_type => "boolean", default_value => \"false", is_nullable => 0 },
+ "name",
+ { data_type => "text", is_nullable => 0 },
+ "parent",
+ { data_type => "integer", is_foreign_key => 1, is_nullable => 1 },
"deleted",
{ data_type => "boolean", default_value => \"false", is_nullable => 0 },
+ "external_url",
+ { data_type => "text", is_nullable => 1 },
);
__PACKAGE__->set_primary_key("id");
__PACKAGE__->has_many(
@@ -87,6 +87,12 @@ __PACKAGE__->belongs_to(
},
);
__PACKAGE__->has_many(
+ "response_templates",
+ "FixMyStreet::DB::Result::ResponseTemplate",
+ { "foreign.body_id" => "self.id" },
+ { cascade_copy => 0, cascade_delete => 0 },
+);
+__PACKAGE__->has_many(
"user_body_permissions",
"FixMyStreet::DB::Result::UserBodyPermission",
{ "foreign.body_id" => "self.id" },
@@ -100,8 +106,8 @@ __PACKAGE__->has_many(
);
-# Created by DBIx::Class::Schema::Loader v0.07035 @ 2014-07-29 13:54:07
-# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:PhUeFDRLSQVMk7Sts5K6MQ
+# Created by DBIx::Class::Schema::Loader v0.07035 @ 2015-02-19 16:13:43
+# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:d6GuQm8vrNmCc4NWw58srA
sub url {
my ( $self, $c, $args ) = @_;
diff --git a/perllib/FixMyStreet/DB/Result/Problem.pm b/perllib/FixMyStreet/DB/Result/Problem.pm
index 9706087aa..3b7f8bcfd 100644
--- a/perllib/FixMyStreet/DB/Result/Problem.pm
+++ b/perllib/FixMyStreet/DB/Result/Problem.pm
@@ -323,10 +323,6 @@ sub visible_states_remove {
}
}
-sub visible_states_add_unconfirmed {
- $_[0]->visible_states_add('unconfirmed')
-}
-
=head2
@states = FixMyStreet::DB::Problem::council_states();
@@ -483,11 +479,17 @@ sub url {
=head2 get_photo_params
-Returns a hashref of details of any attached photo for use in templates.
+Returns a hashref of details of the attached photo, if any, for use in templates.
+
+NB: this method doesn't currently support multiple photos gracefully.
+
+Use get_photoset($c) instead to do the right thing with reports with 0, 1, or more photos.
=cut
sub get_photo_params {
+ # use Carp 'cluck';
+ # cluck "get_photo_params called"; # TEMPORARY die to make sure I've done right thing with Zurich templates
my $self = shift;
return FixMyStreet::App::get_photo_params($self, 'id');
}
@@ -637,7 +639,28 @@ sub body {
return $body;
}
-# returns true if the external id is the council's ref, i.e., useful to publish it.
+=head2 response_templates
+
+Returns all ResponseTemplates attached to this problem's bodies, in alphabetical
+order of title.
+
+=cut
+
+sub response_templates {
+ my $problem = shift;
+ return FixMyStreet::App->model('DB::ResponseTemplate')->search(
+ {
+ body_id => $problem->bodies_str_ids
+ },
+ {
+ order_by => 'title'
+ }
+ );
+}
+
+# returns true if the external id is the council's ref, i.e., useful to publish it
+# (by way of an example, the barnet send method returns a useful reference when
+# it succeeds, so that is the ref we should show on the problem report page).
# Future: this is installation-dependent so maybe should be using the contact
# data to determine if the external id is public on a council-by-council basis.
# Note: this only makes sense when called on a problem that has been sent!
@@ -828,6 +851,27 @@ sub latest_moderation_log_entry {
return $self->admin_log_entries->search({ action => 'moderation' }, { order_by => 'id desc' })->first;
}
+=head2 get_photoset
+
+Return a PhotoSet object for all photos attached to this field
+
+ my $photoset = $obj->get_photoset( $c );
+ print $photoset->num_images;
+ return $photoset->get_image_data(num => 0, size => 'full');
+
+=cut
+
+sub get_photoset {
+ my ($self, $c) = @_;
+ my $class = 'FixMyStreet::App::Model::PhotoSet';
+ eval "use $class";
+ return $class->new({
+ c => $c,
+ data => $self->photo,
+ object => $self,
+ });
+}
+
__PACKAGE__->has_many(
"admin_log_entries",
"FixMyStreet::DB::Result::AdminLog",
@@ -838,6 +882,18 @@ __PACKAGE__->has_many(
}
);
+sub get_time_spent {
+ my $self = shift;
+ my $admin_logs = $self->admin_log_entries->search({},
+ {
+ group_by => 'object_id',
+ columns => [
+ { sum_time_spent => { sum => 'time_spent' } },
+ ]
+ })->single;
+ return $admin_logs ? $admin_logs->get_column('sum_time_spent') : 0;
+}
+
# we need the inline_constructor bit as we don't inherit from Moose
__PACKAGE__->meta->make_immutable( inline_constructor => 0 );
diff --git a/perllib/FixMyStreet/DB/Result/ResponseTemplate.pm b/perllib/FixMyStreet/DB/Result/ResponseTemplate.pm
new file mode 100644
index 000000000..48a1ab3ae
--- /dev/null
+++ b/perllib/FixMyStreet/DB/Result/ResponseTemplate.pm
@@ -0,0 +1,49 @@
+use utf8;
+package FixMyStreet::DB::Result::ResponseTemplate;
+
+# Created by DBIx::Class::Schema::Loader
+# DO NOT MODIFY THE FIRST PART OF THIS FILE
+
+use strict;
+use warnings;
+
+use base 'DBIx::Class::Core';
+__PACKAGE__->load_components("FilterColumn", "InflateColumn::DateTime", "EncodedColumn");
+__PACKAGE__->table("response_templates");
+__PACKAGE__->add_columns(
+ "id",
+ {
+ data_type => "integer",
+ is_auto_increment => 1,
+ is_nullable => 0,
+ sequence => "response_templates_id_seq",
+ },
+ "body_id",
+ { data_type => "integer", is_foreign_key => 1, is_nullable => 0 },
+ "title",
+ { data_type => "text", is_nullable => 0 },
+ "text",
+ { data_type => "text", is_nullable => 0 },
+ "created",
+ {
+ data_type => "timestamp",
+ default_value => \"current_timestamp",
+ is_nullable => 0,
+ },
+);
+__PACKAGE__->set_primary_key("id");
+__PACKAGE__->add_unique_constraint("response_templates_body_id_title_key", ["body_id", "title"]);
+__PACKAGE__->belongs_to(
+ "body",
+ "FixMyStreet::DB::Result::Body",
+ { id => "body_id" },
+ { is_deferrable => 0, on_delete => "NO ACTION", on_update => "NO ACTION" },
+);
+
+
+# Created by DBIx::Class::Schema::Loader v0.07035 @ 2015-02-19 16:13:43
+# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:xzhmxtu0taAnBMZN0HBocw
+
+
+# You can replace this text with custom code or comments, and it will be preserved on regeneration
+1;
diff --git a/perllib/FixMyStreet/DB/ResultSet/Problem.pm b/perllib/FixMyStreet/DB/ResultSet/Problem.pm
index f01ddfff1..40076d374 100644
--- a/perllib/FixMyStreet/DB/ResultSet/Problem.pm
+++ b/perllib/FixMyStreet/DB/ResultSet/Problem.pm
@@ -247,7 +247,7 @@ sub send_reports {
my $site = $site_override || CronFns::site($base_url);
my $states = [ 'confirmed', 'fixed' ];
- $states = [ 'unconfirmed', 'confirmed', 'in progress', 'planned', 'closed' ] if $site eq 'zurich';
+ $states = [ 'unconfirmed', 'confirmed', 'in progress', 'planned', 'closed', 'investigating' ] if $site eq 'zurich';
my $unsent = $rs->search( {
state => $states,
whensent => undef,
diff --git a/perllib/FixMyStreet/Geocode/Zurich.pm b/perllib/FixMyStreet/Geocode/Zurich.pm
index aad918b0e..50a7c355e 100644
--- a/perllib/FixMyStreet/Geocode/Zurich.pm
+++ b/perllib/FixMyStreet/Geocode/Zurich.pm
@@ -31,6 +31,7 @@ sub setup_soap {
my $action = "$attr/IFixMyZuerich/";
require SOAP::Lite;
+ # SOAP::Lite->import( +trace => [transport => \&log_message ] );
# Set up the SOAP handler
$security = SOAP::Header->name("Security")->attr({
@@ -109,5 +110,15 @@ sub string {
return { error => $error };
}
+sub log_message {
+ my ($in) = @_;
+ eval {
+ printf "log_message [$in]: %s\n\n", $in->content; # ...for example
+ };
+ if ($@) {
+ print "log_message [$in]: ???? \n\n";
+ }
+}
+
1;
diff --git a/perllib/FixMyStreet/Map.pm b/perllib/FixMyStreet/Map.pm
index b050592ba..81b81f656 100644
--- a/perllib/FixMyStreet/Map.pm
+++ b/perllib/FixMyStreet/Map.pm
@@ -35,6 +35,16 @@ sub allowed_maps {
return grep { $avail{$_} } @allowed;
}
+=head2 reload_allowed_maps
+
+Allows tests to override MAP_TYPE at run time.
+
+=cut
+
+sub reload_allowed_maps {
+ @ALL_MAP_CLASSES = allowed_maps();
+}
+
=head2 map_class
Set and return the appropriate class given a query parameter string.
diff --git a/perllib/FixMyStreet/Map/Zurich.pm b/perllib/FixMyStreet/Map/Zurich.pm
index 9b01f2978..3e198f820 100644
--- a/perllib/FixMyStreet/Map/Zurich.pm
+++ b/perllib/FixMyStreet/Map/Zurich.pm
@@ -11,25 +11,53 @@ use Geo::Coordinates::CH1903;
use Math::Trig;
use Utils;
-use constant ZOOM_LEVELS => 8;
+use constant ZOOM_LEVELS => 9;
use constant DEFAULT_ZOOM => 5;
use constant MIN_ZOOM_LEVEL => 0;
use constant ID_OFFSET => 2;
+use constant TILE_SIZE => 512;
sub map_tiles {
- my ( $self, %params ) = @_;
- my ( $col, $row, $z ) = ( $params{x_tile}, $params{y_tile}, $params{matrix_id} );
+ my ($self, %params) = @_;
+ my ($left_col, $top_row, $z) = @params{'x_left_tile', 'y_top_tile', 'matrix_id'};
my $tile_url = $self->base_tile_url();
+ my $cols = $params{cols};
+ my $rows = $params{rows};
+
+ my @col_offsets = (0.. ($cols-1) );
+ my @row_offsets = (0.. ($rows-1) );
+
return [
- "$tile_url/$z/" . ($row - 1) . "/" . ($col - 1) . ".jpg",
- "$tile_url/$z/" . ($row - 1) . "/$col.jpg",
- "$tile_url/$z/$row/" . ($col - 1) . ".jpg",
- "$tile_url/$z/$row/$col.jpg",
+ map {
+ my $row_offset = $_;
+ [
+ map {
+ my $col_offset = $_;
+ my $row = $top_row + $row_offset;
+ my $col = $left_col + $col_offset;
+ my $src = sprintf '%s/%d/%d/%d.jpg',
+ $tile_url, $z, $row, $col;
+ my $dotted_id = sprintf '%d.%d', $col, $row;
+
+ # return the data structure for the cell
+ +{
+ src => $src,
+ row_offset => $row_offset,
+ col_offset => $col_offset,
+ dotted_id => $dotted_id,
+ alt => "Map tile $dotted_id", # TODO "NW map tile"?
+ }
+ }
+ @col_offsets
+ ]
+ }
+ @row_offsets
];
}
sub base_tile_url {
- return '/maps/Hybrid/1.0.0/Hybrid/default/nativeTileMatrixSet';
+ # use the new 512px maps as used by Javascript
+ return 'http://www.gis.stadt-zuerich.ch/maps/rest/services/tiled/LuftbildHybrid/MapServer/WMTS/tile/1.0.0/tiled_LuftbildHybrid/default/default028mm';
}
sub copyright {
@@ -50,29 +78,77 @@ sub display_map {
$params{longitude} = Utils::truncate_coordinate($c->get_param('lon') + 0)
if defined $c->get_param('lon');
- my $zoom = defined $c->get_param('zoom')
- ? $c->get_param('zoom') + 0
- : $c->stash->{page} eq 'report'
- ? DEFAULT_ZOOM+1
- : DEFAULT_ZOOM;
- $zoom = ZOOM_LEVELS - 1 if $zoom >= ZOOM_LEVELS;
- $zoom = 0 if $zoom < 0;
+ $params{rows} //= 2; # 2x2 square is default
+ $params{cols} //= 2;
+
+ $params{zoom} = do {
+ my $zoom = defined $c->get_param('zoom')
+ ? $c->get_param('zoom') + 0
+ : $c->stash->{page} eq 'report'
+ ? DEFAULT_ZOOM+1
+ : DEFAULT_ZOOM;
+ $zoom = ZOOM_LEVELS - 1 if $zoom >= ZOOM_LEVELS;
+ $zoom = 0 if $zoom < 0;
+ $zoom;
+ };
+
+ $c->stash->{map} = $self->get_map_hash( %params );
- ($params{x_tile}, $params{y_tile}, $params{matrix_id}) = latlon_to_tile_with_adjust($params{latitude}, $params{longitude}, $zoom);
+ if ($params{print_report}) {
+ $params{zoom}++ unless $params{zoom} >= ZOOM_LEVELS;
+ $c->stash->{print_report_map}
+ = $self->get_map_hash(
+ %params,
+ img_type => 'img',
+ cols => 4, rows => 4,
+ );
+ # NB: we can passthrough img_type as literal here, as only designed for print
- foreach my $pin (@{$params{pins}}) {
- ($pin->{px}, $pin->{py}) = latlon_to_px($pin->{latitude}, $pin->{longitude}, $params{x_tile}, $params{y_tile}, $zoom);
+ # NB we can do arbitrary size, including non-squares, however we'd have
+ # to modify .square-map style with padding-bottom percentage calculated in
+ # an inline style:
+ # <zarino> in which case, the only change that'd be required is
+ # removing { padding-bottom: 100% } from .square-map__outer, putting
+ # the percentage into an inline style on the element itself, and then
+ # probably renaming .square-map__* to .fixed-aspect-map__* or something
+ # since it's no longer necessarily square
}
+}
+
+sub get_map_hash {
+ my ($self, %params) = @_;
- $c->stash->{map} = {
+ @params{'x_centre_tile', 'y_centre_tile', 'matrix_id'}
+ = latlon_to_tile_with_adjust(
+ @params{'latitude', 'longitude', 'zoom', 'rows', 'cols'});
+
+ # centre_(row|col) is either in middle, or just to right.
+ # e.g. if centre is the number in parens:
+ # 1 (2) 3 => 2 - int( 3/2 ) = 1
+ # 1 2 (3) 4 => 3 - int( 4/2 ) = 1
+ $params{x_left_tile} = $params{x_centre_tile} - int($params{cols} / 2);
+ $params{y_top_tile} = $params{y_centre_tile} - int($params{rows} / 2);
+
+ $params{pins} = [
+ map {
+ my $pin = { %$_ }; # shallow clone
+ ($pin->{px}, $pin->{py})
+ = latlon_to_px($pin->{latitude}, $pin->{longitude},
+ @params{'x_left_tile', 'y_top_tile', 'zoom'});
+ $pin;
+ } @{ $params{pins} }
+ ];
+
+ return {
%params,
type => 'zurich',
map_type => 'OpenLayers.Layer.WMTS',
tiles => $self->map_tiles( %params ),
copyright => $self->copyright(),
- zoom => $zoom,
+ zoom => $params{zoom},,
zoomOffset => MIN_ZOOM_LEVEL,
numZoomLevels => ZOOM_LEVELS,
+ tile_size => TILE_SIZE,
};
}
@@ -83,29 +159,46 @@ sub latlon_to_tile($$$) {
my ($x, $y) = Geo::Coordinates::CH1903::from_latlon($lat, $lon);
my $matrix_id = $zoom + ID_OFFSET;
- my @scales = ( '250000', '125000', '64000', '32000', '16000', '8000', '4000', '2000', '1000', '500' );
+ my @scales = (
+ '250000', '125000',
+ '64000', '32000',
+ '16000', '8000',
+ '4000', '2000',
+ '1000', '500',
+ '250'
+ );
my $tileOrigin = { lat => 30814423, lon => -29386322 };
- my $tileSize = 256;
- my $res = $scales[$matrix_id] / (39.3701 * 96); # OpenLayers.INCHES_PER_UNIT[units] * OpenLayers.DOTS_PER_INCH
+ my $res = $scales[$matrix_id] / (39.3701 * 96);
+ # OpenLayers.INCHES_PER_UNIT[units] * OpenLayers.DOTS_PER_INCH
- my $fx = ( $x - $tileOrigin->{lon} ) / ($res * $tileSize);
- my $fy = ( $tileOrigin->{lat} - $y ) / ($res * $tileSize);
+ my $fx = ( $x - $tileOrigin->{lon} ) / ($res * TILE_SIZE);
+ my $fy = ( $tileOrigin->{lat} - $y ) / ($res * TILE_SIZE);
return ( $fx, $fy, $matrix_id );
}
# Given a lat/lon, convert it to OSM tile co-ordinates (nearest actual tile,
# adjusted so the point will be near the centre of a 2x2 tiled map).
-sub latlon_to_tile_with_adjust($$$) {
- my ($lat, $lon, $zoom) = @_;
- my ($x_tile, $y_tile, $matrix_id) = latlon_to_tile($lat, $lon, $zoom);
+#
+# Takes parameter for rows/cols. For even sizes (2x2, 4x4 etc.) will
+# do adjustment, but simply returns actual for odd sizes.
+#
+sub latlon_to_tile_with_adjust {
+ my ($lat, $lon, $zoom, $rows, $cols) = @_;
+ my ($x_tile, $y_tile, $matrix_id)
+ = my @ret
+ = latlon_to_tile($lat, $lon, $zoom);
- # Try and have point near centre of map
- if ($x_tile - int($x_tile) > 0.5) {
- $x_tile += 1;
+ # Try and have point near centre of map, passing through if odd
+ unless ($cols % 2) {
+ if ($x_tile - int($x_tile) > 0.5) {
+ $x_tile += 1;
+ }
}
- if ($y_tile - int($y_tile) > 0.5) {
- $y_tile += 1;
+ unless ($rows % 2) {
+ if ($y_tile - int($y_tile) > 0.5) {
+ $y_tile += 1;
+ }
}
return ( int($x_tile), int($y_tile), $matrix_id );
@@ -115,13 +208,12 @@ sub tile_to_latlon {
my ($fx, $fy, $zoom) = @_;
my $matrix_id = $zoom + ID_OFFSET;
- my @scales = ( '250000', '125000', '64000', '32000', '16000', '8000', '4000', '2000', '1000', '500' );
+ my @scales = ( '250000', '125000', '64000', '32000', '16000', '8000', '4000', '2000', '1000', '500', '250' );
my $tileOrigin = { lat => 30814423, lon => -29386322 };
- my $tileSize = 256;
my $res = $scales[$matrix_id] / (39.3701 * 96); # OpenLayers.INCHES_PER_UNIT[units] * OpenLayers.DOTS_PER_INCH
- my $x = $fx * $res * $tileSize + $tileOrigin->{lon};
- my $y = $tileOrigin->{lat} - $fy * $res * $tileSize;
+ my $x = $fx * $res * TILE_SIZE + $tileOrigin->{lon};
+ my $y = $tileOrigin->{lat} - $fy * $res * TILE_SIZE;
my ($lat, $lon) = Geo::Coordinates::CH1903::to_latlon($x, $y);
@@ -141,16 +233,16 @@ sub latlon_to_px($$$$$) {
# C is centre tile reference of displayed map
sub tile_to_px {
my ($p, $c) = @_;
- $p = 256 * ($p - $c + 1);
+ $p = TILE_SIZE * ($p - $c);
$p = int($p + .5 * ($p <=> 0));
return $p;
}
sub click_to_tile {
my ($pin_tile, $pin) = @_;
- $pin -= 256 while $pin > 256;
- $pin += 256 while $pin < 0;
- return $pin_tile + $pin / 256;
+ $pin -= TILE_SIZE while $pin > TILE_SIZE;
+ $pin += TILE_SIZE while $pin < 0;
+ return $pin_tile + $pin / TILE_SIZE;
}
# Given some click co-ords (the tile they were on, and where in the
diff --git a/perllib/FixMyStreet/SendReport/Email.pm b/perllib/FixMyStreet/SendReport/Email.pm
index 9fec0ac9c..bac408510 100644
--- a/perllib/FixMyStreet/SendReport/Email.pm
+++ b/perllib/FixMyStreet/SendReport/Email.pm
@@ -93,6 +93,11 @@ sub send {
To => $self->to,
From => $self->send_from( $row ),
};
+
+ my $app = FixMyStreet::App->new( cobrand => $cobrand );
+
+ $cobrand->munge_sendreport_params($app, $row, $h, $params) if $cobrand->can('munge_sendreport_params');
+
$params->{Bcc} = $self->bcc if @{$self->bcc};
if (FixMyStreet::Email::test_dmarc($params->{From}[0])) {
@@ -100,7 +105,7 @@ sub send {
$params->{From} = [ mySociety::Config::get('CONTACT_EMAIL'), $params->{From}[1] ];
}
- my $result = FixMyStreet::App->send_email_cron(
+ my $result = $app->send_email_cron(
$params,
mySociety::Config::get('CONTACT_EMAIL'),
$nomail,
diff --git a/perllib/FixMyStreet/SendReport/Zurich.pm b/perllib/FixMyStreet/SendReport/Zurich.pm
index 40417b41e..2838440cb 100644
--- a/perllib/FixMyStreet/SendReport/Zurich.pm
+++ b/perllib/FixMyStreet/SendReport/Zurich.pm
@@ -9,10 +9,21 @@ sub build_recipient_list {
# Only one body ever, most of the time with an email endpoint
my $body = @{ $self->bodies }[0];
+
+ # we set external_message (but default to '' in case of race condition e.g.
+ # Wunsch set, but external_message hasn't yet been filled in. TODO should
+ # we instead be holding off sending?)
if ( $row->external_body ) {
$body = FixMyStreet::App->model("DB::Body")->find( { id => $row->external_body } );
$h->{bodies_name} = $body->name;
+ $h->{external_message} = $row->get_extra_metadata('external_message') || '';
}
+ $h->{external_message} //= '';
+
+ my ($west, $nord) = $row->local_coords;
+ $h->{west} = $west;
+ $h->{nord} = $nord;
+
my $body_email = $body->endpoint;
my $parent = $body->parent;
@@ -39,6 +50,8 @@ sub get_template {
$template = 'submit-in-progress.txt';
} elsif ( $row->state eq 'planned' ) {
$template = 'submit-feedback-pending.txt';
+ } elsif ( $row->state eq 'investigating' ) {
+ $template = 'submit-external-wish.txt';
} elsif ( $row->state eq 'closed' ) {
$template = 'submit-external.txt';
if ( $row->extra->{third_personal} ) {
diff --git a/perllib/FixMyStreet/TestMech.pm b/perllib/FixMyStreet/TestMech.pm
index bd2ca4096..1035a47ba 100644
--- a/perllib/FixMyStreet/TestMech.pm
+++ b/perllib/FixMyStreet/TestMech.pm
@@ -165,6 +165,7 @@ sub delete_user {
$a->delete;
}
$_->delete for $user->comments;
+ $_->delete for $user->admin_logs;
$user->delete;
return 1;
@@ -221,6 +222,24 @@ sub get_email {
return $emails[0];
}
+=head2 get_first_email
+
+ $email = $mech->get_first_email(@emails);
+
+Returns first email in queue as a string and fails a test if the mail doesn't have a date and epoch-containing Message-ID header.
+
+=cut
+
+sub get_first_email {
+ my $mech = shift;
+ my $email = shift or do { fail 'No email retrieved'; return };
+ my $email_as_string = $email->as_string;
+ ok $email_as_string =~ s{\s+Date:\s+\S.*?$}{}xmsg, "Found and stripped out date";
+ ok $email_as_string =~ s{\s+Message-ID:\s+\S.*?$}{}xmsg, "Found and stripped out message ID (contains epoch)";
+ return $email_as_string;
+}
+
+
=head2 page_errors
my $arrayref = $mech->page_errors;
@@ -631,7 +650,7 @@ sub create_problems_for_body {
latitude => '51.5016605453401',
longitude => '-0.142497580865087',
user_id => $user->id,
- photo => 1,
+ photo => $mech->get_photo_data,
};
my %report_params = ( %$default_params, %$params );
@@ -646,4 +665,13 @@ sub create_problems_for_body {
return @problems;
}
+sub get_photo_data {
+ my $mech = shift;
+ return $mech->{sample_photo} ||= do {
+ my $sample_file = FixMyStreet->path_to( 't/app/controller/sample.jpg' );
+ $mech->builder->ok( -f "$sample_file", "sample file $sample_file exists" );
+ $sample_file->slurp(iomode => '<:raw');
+ };
+}
+
1;
diff --git a/t/app/controller/moderate.t b/t/app/controller/moderate.t
index cd4c742bb..b79f50e73 100644
--- a/t/app/controller/moderate.t
+++ b/t/app/controller/moderate.t
@@ -42,10 +42,7 @@ sub create_report {
latitude => '51.4129',
longitude => '0.007831',
user_id => $user->id,
- photo => 'DUMMY DATA', # this obv fake data would not be
- # accepted by front-end but is
- # enough to trigger "I have a
- # photo" behaviour
+ photo => $mech->get_photo_data,
});
}
my $report = create_report();
@@ -216,7 +213,7 @@ sub create_update {
user => $user,
name => 'Test User',
anonymous => 'f',
- photo => 'DUMMY DATA', # as above
+ photo => $mech->get_photo_data,
text => 'update good good bad good',
state => 'confirmed',
mark_fixed => 0,
@@ -283,7 +280,8 @@ subtest 'updates' => sub {
$mech->get_ok($REPORT_URL);
- $mech->content_contains('Photo of this report');
+ $mech->content_contains('Photo of this report')
+ or die $mech->content;
$mech->post_ok( $MODERATE_UPDATE_URL, {
%update_prepopulated,
diff --git a/t/app/controller/photo.t b/t/app/controller/photo.t
new file mode 100644
index 000000000..6e61ebb32
--- /dev/null
+++ b/t/app/controller/photo.t
@@ -0,0 +1,75 @@
+use strict;
+use utf8; # sign in error message has &ndash; in it
+use warnings;
+use feature 'say';
+use Test::More;
+use utf8;
+
+use FixMyStreet::TestMech;
+use FixMyStreet::App;
+use Web::Scraper;
+use Path::Tiny;
+use File::Temp 'tempdir';
+
+# disable info logs for this test run
+FixMyStreet::App->log->disable('info');
+END { FixMyStreet::App->log->enable('info'); }
+
+my $mech = FixMyStreet::TestMech->new;
+
+my $sample_file = path(__FILE__)->parent->child("sample.jpg");
+ok $sample_file->exists, "sample file $sample_file exists";
+
+my $westminster = $mech->create_body_ok(2527, 'Liverpool City Council');
+
+subtest "Check multiple upload worked" => sub {
+ $mech->get_ok('/around');
+
+ my $UPLOAD_DIR = tempdir( CLEANUP => 1 );
+
+ # submit initial pc form
+ FixMyStreet::override_config {
+ ALLOWED_COBRANDS => [ { fixmystreet => '.' } ],
+ MAPIT_URL => 'http://mapit.mysociety.org/',
+ UPLOAD_DIR => $UPLOAD_DIR,
+ }, sub {
+
+ $mech->log_in_ok('test@example.com');
+
+
+ # submit the main form
+ # can't post_ok as we lose the Content_Type header
+ # (TODO rewrite with HTTP::Request::Common and request_ok)
+ $mech->post( '/report/new',
+ Content_Type => 'form-data',
+ Content =>
+ {
+ submit_problem => 1,
+ title => 'Test',
+ lat => 53.4031156, lon => -2.9840579, # in Liverpool
+ pc => 'L1 4LN',
+ detail => 'Detail',
+ photo1 => [ $sample_file, undef, Content_Type => 'application/octet-stream' ],
+ photo2 => [ $sample_file, undef, Content_Type => 'application/octet-stream' ],
+ photo3 => [ $sample_file, undef, Content_Type => 'application/octet-stream' ],
+ name => 'Bob Jones',
+ may_show_name => '1',
+ email => 'test@example.com',
+ phone => '',
+ category => 'Street lighting',
+ #password_sign_in => '',
+ #password_register => '',
+ #remember_me => undef,
+ }
+ );
+ ok $mech->success, 'Made request with multiple photo upload';
+ $mech->base_is('http://localhost/report/new');
+ $mech->content_contains(
+ 'name="upload_fileid" value="1cdd4329ceee2234bd4e89cb33b42061a0724687,1cdd4329ceee2234bd4e89cb33b42061a0724687,1cdd4329ceee2234bd4e89cb33b42061a0724687"',
+ 'Returned upload_fileid contains expected hash, 3 times');
+ my $image_file = path($UPLOAD_DIR, '1cdd4329ceee2234bd4e89cb33b42061a0724687.jpeg');
+ ok $image_file->exists, 'File uploaded to temp';
+ };
+};
+
+done_testing();
diff --git a/t/app/controller/questionnaire.t b/t/app/controller/questionnaire.t
index d4fc9c74b..2a89454d5 100644
--- a/t/app/controller/questionnaire.t
+++ b/t/app/controller/questionnaire.t
@@ -276,7 +276,7 @@ foreach my $test (
$questionnaire->discard_changes;
is $report->state, $result eq 'unknown' ? $test->{problem_state} : $result;
is $report->send_questionnaire, $another;
- ok DateTime::Format::Pg->format_datetime( $report->lastupdate) gt $report_time, 'lastupdate changed'
+ ok (DateTime::Format::Pg->format_datetime( $report->lastupdate) gt $report_time, 'lastupdate changed')
unless $test->{fields}{been_fixed} eq 'Unknown' || $test->{lastupdate_static};
is $questionnaire->old_state, $test->{problem_state};
is $questionnaire->new_state, $result;
diff --git a/t/app/controller/report_display.t b/t/app/controller/report_display.t
index 002cdc1e5..265760d86 100644
--- a/t/app/controller/report_display.t
+++ b/t/app/controller/report_display.t
@@ -96,19 +96,6 @@ subtest "change report to unconfirmed and check for 404 status" => sub {
};
-subtest "Zurich unconfirmeds are 200" => sub {
- FixMyStreet::override_config {
- ALLOWED_COBRANDS => [ 'zurich' ],
- }, sub {
- $mech->host( 'zurich.example.com' );
- ok $report->update( { state => 'unconfirmed' } ), 'unconfirm report';
- $mech->get_ok("/report/$report_id");
- $mech->content_contains( '&Uuml;berpr&uuml;fung ausstehend' );
- ok $report->update( { state => 'confirmed' } ), 'confirm report again';
- $mech->host( 'www.fixmystreet.com' );
- };
-};
-
subtest "change report to hidden and check for 410 status" => sub {
ok $report->update( { state => 'hidden' } ), 'hide report';
ok $mech->get("/report/$report_id"), "get '/report/$report_id'";
@@ -400,9 +387,72 @@ for my $test (
};
}
+my $body_westminster = $mech->create_body_ok(2504, 'Westminster City Council');
+my $body_camden = $mech->create_body_ok(2505, 'Camden Borough Council');
+
+for my $test (
+ {
+ desc => 'no state dropdown if user not from authority',
+ from_body => undef,
+ no_state => 1,
+ report_body => $body_westminster->id,
+ },
+ {
+ desc => 'state dropdown if user from authority',
+ from_body => $body_westminster->id,
+ no_state => 0,
+ report_body => $body_westminster->id,
+ },
+ {
+ desc => 'no state dropdown if user not from same body as problem',
+ from_body => $body_camden->id,
+ no_state => 1,
+ report_body => $body_westminster->id,
+ },
+ {
+ desc => 'state dropdown if user from authority and problem sent to multiple bodies',
+ from_body => $body_westminster->id,
+ no_state => 0,
+ report_body => $body_westminster->id . ',2506',
+ },
+) {
+ subtest $test->{desc} => sub {
+ $mech->log_in_ok( $user->email );
+ $user->from_body( $test->{from_body} );
+ $user->update;
+
+ $report->discard_changes;
+ $report->bodies_str( $test->{report_body} );
+ $report->update;
+
+ $mech->get_ok("/report/$report_id");
+ my $fields = $mech->visible_form_values( 'updateForm' );
+ if ( $test->{no_state} ) {
+ ok !$fields->{state};
+ } else {
+ ok $fields->{state};
+ }
+ };
+}
+
+subtest "Zurich unconfirmeds are 200" => sub {
+ FixMyStreet::override_config {
+ ALLOWED_COBRANDS => [ 'zurich' ],
+ MAP_TYPE => 'Zurich,OSM',
+ }, sub {
+ $mech->host( 'zurich.example.com' );
+ ok $report->update( { state => 'unconfirmed' } ), 'unconfirm report';
+ $mech->get_ok("/report/$report_id");
+ $mech->content_contains( '&Uuml;berpr&uuml;fung ausstehend' );
+ ok $report->update( { state => 'confirmed' } ), 'confirm report again';
+ $mech->host( 'www.fixmystreet.com' );
+ };
+};
+
subtest "Zurich banners are displayed correctly" => sub {
FixMyStreet::override_config {
ALLOWED_COBRANDS => [ 'zurich' ],
+ MAP_TYPE => 'Zurich,OSM',
}, sub {
$mech->host( 'zurich.example.com' );
@@ -428,8 +478,8 @@ subtest "Zurich banners are displayed correctly" => sub {
{
description => 'closed report',
state => 'closed',
- banner_id => 'fixed',
- banner_text => 'Beantwortet',
+ banner_id => 'closed',
+ banner_text => _('Extern'),
},
{
description => 'in progress report',
@@ -443,6 +493,21 @@ subtest "Zurich banners are displayed correctly" => sub {
banner_id => 'progress',
banner_text => 'In Bearbeitung',
},
+ {
+ description => 'planned report',
+ state => 'planned',
+ banner_id => 'progress',
+ banner_text => 'In Bearbeitung',
+ },
+ {
+ description => 'jurisdiction unknown',
+ state => 'unable to fix',
+ banner_id => 'fixed',
+ # We can't use _('Jurisdiction Unknown') here because
+ # TestMech::extract_problem_banner decodes the HTML entities before
+ # the string is passed back.
+ banner_text => 'Zust\x{e4}ndigkeit unbekannt',
+ },
) {
subtest "banner for $test->{description}" => sub {
$report->state( $test->{state} );
@@ -470,53 +535,6 @@ subtest "Zurich banners are displayed correctly" => sub {
};
};
-my $body_westminster = $mech->create_body_ok(2504, 'Westminster City Council');
-my $body_camden = $mech->create_body_ok(2505, 'Camden Borough Council');
-
-for my $test (
- {
- desc => 'no state dropdown if user not from authority',
- from_body => undef,
- no_state => 1,
- report_body => $body_westminster->id,
- },
- {
- desc => 'state dropdown if user from authority',
- from_body => $body_westminster->id,
- no_state => 0,
- report_body => $body_westminster->id,
- },
- {
- desc => 'no state dropdown if user not from same body as problem',
- from_body => $body_camden->id,
- no_state => 1,
- report_body => $body_westminster->id,
- },
- {
- desc => 'state dropdown if user from authority and problem sent to multiple bodies',
- from_body => $body_westminster->id,
- no_state => 0,
- report_body => $body_westminster->id . ',2506',
- },
-) {
- subtest $test->{desc} => sub {
- $mech->log_in_ok( $user->email );
- $user->from_body( $test->{from_body} );
- $user->update;
-
- $report->discard_changes;
- $report->bodies_str( $test->{report_body} );
- $report->update;
-
- $mech->get_ok("/report/$report_id");
- my $fields = $mech->visible_form_values( 'updateForm' );
- if ( $test->{no_state} ) {
- ok !$fields->{state};
- } else {
- ok $fields->{state};
- }
- };
-}
END {
$mech->delete_user('test@example.com');
diff --git a/t/app/controller/report_import.t b/t/app/controller/report_import.t
index 16874ac3c..4d0f6e5d1 100644
--- a/t/app/controller/report_import.t
+++ b/t/app/controller/report_import.t
@@ -321,6 +321,7 @@ subtest "Submit a correct entry (with location) to cobrand" => sub {
MAPIT_URL => 'http://global.mapit.mysociety.org/',
MAPIT_TYPES => [ 'O08' ],
MAPIT_ID_WHITELIST => [],
+ MAP_TYPE => 'Zurich,OSM',
}, sub {
ok $mech->host("zurich.example.org"), 'change host to zurich';
@@ -364,11 +365,14 @@ subtest "Submit a correct entry (with location) to cobrand" => sub {
{
name => 'Test User ll',
detail => 'This is a test report ll',
- photo => '',
+ photo1 => '',
+ photo2 => '',
+ photo3 => '',
phone => '',
email => 'test-ll@example.com',
},
- "check imported fields are shown";
+ "check imported fields are shown"
+ or diag Dumper( $mech->visible_form_values ); use Data::Dumper;
my $user =
FixMyStreet::App->model('DB::User')
diff --git a/t/app/helpers/grey.gif b/t/app/helpers/grey.gif
new file mode 100644
index 000000000..98eee7d12
--- /dev/null
+++ b/t/app/helpers/grey.gif
Binary files differ
diff --git a/t/app/helpers/send_email.t b/t/app/helpers/send_email.t
index 14c7d363b..d1609cb2f 100644
--- a/t/app/helpers/send_email.t
+++ b/t/app/helpers/send_email.t
@@ -9,12 +9,16 @@ BEGIN {
FixMyStreet->test_mode(1);
}
-use Test::More tests => 5;
+use Test::More;
+use Test::LongString;
use Catalyst::Test 'FixMyStreet::App';
use Email::Send::Test;
-use Path::Class;
+use Path::Tiny;
+
+use FixMyStreet::TestMech;
+my $mech = FixMyStreet::TestMech->new;
my $c = ctx_request("/");
@@ -33,16 +37,66 @@ my @emails = Email::Send::Test->emails;
is scalar(@emails), 1, "caught one email";
# Get the email, check it has a date and then strip it out
-my $email_as_string = $emails[0]->as_string;
-ok $email_as_string =~ s{\s+Date:\s+\S.*?$}{}xms, "Found and stripped out date";
-ok $email_as_string =~ s{\s+Message-ID:\s+\S.*?$}{}xms, "Found and stripped out message ID (contains epoch)";
+my $email_as_string = $mech->get_first_email(@emails);
-my $expected_email_content = file(__FILE__)->dir->file('send_email_sample.txt')->slurp;
+my $expected_email_content = path(__FILE__)->parent->child('send_email_sample.txt')->slurp;
my $name = FixMyStreet->config('CONTACT_NAME');
$name = "\"$name\"" if $name =~ / /;
my $sender = $name . ' <' . FixMyStreet->config('DO_NOT_REPLY_EMAIL') . '>';
$expected_email_content =~ s{CONTACT_EMAIL}{$sender};
-is $email_as_string,
-$expected_email_content,
- "email is as expected";
+is_string $email_as_string, $expected_email_content, "email is as expected";
+
+subtest 'MIME attachments' => sub {
+ my $data = path(__FILE__)->parent->child('grey.gif')->slurp_raw;
+
+ Email::Send::Test->clear;
+ my @emails = Email::Send::Test->emails;
+ is scalar(@emails), 0, "reset";
+
+ ok $c->send_email( 'test.txt',
+ { to => 'test@recipient.com',
+ attachments => [
+ {
+ body => $data,
+ attributes => {
+ filename => 'foo.gif',
+ content_type => 'image/gif',
+ encoding => 'quoted-printable',
+ name => 'foo.gif',
+ },
+ },
+ {
+ body => $data,
+ attributes => {
+ filename => 'bar.gif',
+ content_type => 'image/gif',
+ encoding => 'quoted-printable',
+ name => 'bar.gif',
+ },
+ },
+ ]
+ } ), "sent an email with MIME attachments";
+
+ @emails = $mech->get_email;
+ is scalar(@emails), 1, "caught one email";
+
+ my $email_as_string = $mech->get_first_email(@emails);
+
+ my ($boundary) = $email_as_string =~ /boundary="([A-Za-z0-9.]*)"/ms;
+ my $changes = $email_as_string =~ s{$boundary}{}g;
+ is $changes, 5, '5 boundaries'; # header + 4 around the 3x parts (text + 2 images)
+
+ my $expected_email_content = path(__FILE__)->parent->child('send_email_sample_mime.txt')->slurp;
+ $expected_email_content =~ s{CONTACT_EMAIL}{$sender}g;
+
+ is_string $email_as_string, $expected_email_content, 'MIME email text ok'
+ or do {
+ (my $test_name = $0) =~ s{/}{_}g;
+ my $path = path("test-output-$test_name.tmp");
+ $path->spew($email_as_string);
+ diag "Saved output in $path";
+ };
+};
+
+done_testing;
diff --git a/t/app/helpers/send_email_sample_mime.txt b/t/app/helpers/send_email_sample_mime.txt
new file mode 100644
index 000000000..4ce0f9520
--- /dev/null
+++ b/t/app/helpers/send_email_sample_mime.txt
@@ -0,0 +1,57 @@
+MIME-Version: 1.0
+Subject: test email =?utf-8?Q?=E2=98=BA?=
+Content-Type: multipart/mixed; boundary=""
+To: test@recipient.com
+Content-Transfer-Encoding: 7bit
+From: CONTACT_EMAIL
+
+
+--
+MIME-Version: 1.0
+Subject: test email =?utf-8?Q?=E2=98=BA?=
+Content-Type: text/plain; charset="utf-8"
+To: test@recipient.com
+Content-Transfer-Encoding: quoted-printable
+From: CONTACT_EMAIL
+
+Hello,
+
+This is a test email where foo: bar.
+
+utf8: =E6=88=91=E4=BB=AC=E5=BA=94=E8=AF=A5=E8=83=BD=E5=A4=9F=E6=97=A0=E7=BC=
+=9D=E5=A4=84=E7=90=86UTF8=E7=BC=96=E7=A0=81
+
+ indented_text
+
+long line: Lorem ipsum dolor sit amet, consectetur adipisicing elit,
+sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
+Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris
+nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in
+reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla
+pariatur. Excepteur sint occaecat cupidatat non proident, sunt in
+culpa qui officia deserunt mollit anim id est laborum.
+
+Yours,=20=20
+FixMyStreet.=20=
+
+
+
+--
+MIME-Version: 1.0
+Content-Type: image/gif; name="foo.gif"
+Content-Disposition: inline; filename="foo.gif"
+Content-Transfer-Encoding: quoted-printable
+
+GIF89a=01=00=01=00=80=00=00=00=00=00=CC=CC=CC,=00=00=00=00=01=00=01=00=00=
+=02=01L=00;=
+
+--
+MIME-Version: 1.0
+Content-Type: image/gif; name="bar.gif"
+Content-Disposition: inline; filename="bar.gif"
+Content-Transfer-Encoding: quoted-printable
+
+GIF89a=01=00=01=00=80=00=00=00=00=00=CC=CC=CC,=00=00=00=00=01=00=01=00=00=
+=02=01L=00;=
+
+----
diff --git a/t/app/model/photoset.t b/t/app/model/photoset.t
new file mode 100644
index 000000000..9e566f873
--- /dev/null
+++ b/t/app/model/photoset.t
@@ -0,0 +1,76 @@
+use strict;
+use warnings;
+use Test::More;
+use Test::Exception;
+use utf8;
+
+use FixMyStreet::App;
+use Data::Dumper;
+use DateTime;
+use Path::Tiny 'path';
+use File::Temp 'tempdir';
+
+my $dt = DateTime->now;
+
+my $c = FixMyStreet::App->new;
+my $UPLOAD_DIR = tempdir( CLEANUP => 1 );
+local $c->config->{UPLOAD_DIR} = $UPLOAD_DIR;
+
+my $user = $c->model('DB::User')->find_or_create({
+ name => 'Bob', email => 'bob@example.com',
+});
+
+my $image_path = path('t/app/controller/sample.jpg');
+
+my $db = FixMyStreet::App->model('DB')->schema;
+$db->txn_begin;
+
+sub make_report {
+ my $photo_data = shift;
+ return $db->resultset('Problem')->create({
+ postcode => 'BR1 3SB',
+ bodies_str => '',
+ areas => ",,",
+ category => 'Other',
+ title => 'test',
+ detail => 'test',
+ used_map => 't',
+ name => 'Anon',
+ anonymous => 't',
+ state => 'confirmed',
+ confirmed => $dt,
+ lang => 'en-gb',
+ service => '',
+ cobrand => 'default',
+ cobrand_data => '',
+ send_questionnaire => 't',
+ latitude => '51.4129',
+ longitude => '0.007831',
+ user => $user,
+ photo => $photo_data,
+ });
+}
+
+
+subtest 'Photoset with photo inline in DB' => sub {
+ my $report = make_report( $image_path->slurp );
+ my $photoset = $report->get_photoset($c);
+ is $photoset->num_images, 1, 'Found just 1 image';
+};
+
+$image_path->copy( path( $UPLOAD_DIR, '0123456789012345678901234567890123456789.jpeg' ) );
+subtest 'Photoset with 1 referenced photo' => sub {
+ my $report = make_report( '0123456789012345678901234567890123456789' );
+ my $photoset = $report->get_photoset($c);
+ is $photoset->num_images, 1, 'Found just 1 image';
+};
+
+subtest 'Photoset with 1 referenced photo' => sub {
+ my $report = make_report( '0123456789012345678901234567890123456789,0123456789012345678901234567890123456789,0123456789012345678901234567890123456789' );
+ my $photoset = $report->get_photoset($c);
+ is $photoset->num_images, 3, 'Found 3 images';
+};
+
+$db->txn_rollback;
+
+done_testing();
diff --git a/t/cobrand/zurich-logo_portal.x.jpg b/t/cobrand/zurich-logo_portal.x.jpg
new file mode 100644
index 000000000..c0cfef240
--- /dev/null
+++ b/t/cobrand/zurich-logo_portal.x.jpg
Binary files differ
diff --git a/t/cobrand/zurich.t b/t/cobrand/zurich.t
index 90a92fb44..721ee547c 100644
--- a/t/cobrand/zurich.t
+++ b/t/cobrand/zurich.t
@@ -5,7 +5,9 @@ use strict;
use warnings;
use DateTime;
use Test::More;
+use Test::LongString;
use JSON;
+use Path::Tiny;
# Check that you have the required locale installed - the following
# should return a line with de_CH.utf8 in. If not install that locale.
@@ -21,10 +23,19 @@ my $c = FixMyStreet::App->new();
my $cobrand = FixMyStreet::Cobrand::Zurich->new({ c => $c });
$c->stash->{cobrand} = $cobrand;
+my $sample_file = path(__FILE__)->parent->parent->child("app/controller/sample.jpg");
+ok $sample_file->exists, "sample file $sample_file exists";
+my $sample_photo = $sample_file->slurp_raw;
+
# This is a helper method that will send the reports but with the config
-# correctly set - notably SEND_REPORTS_ON_STAGING needs to be true.
+# correctly set - notably SEND_REPORTS_ON_STAGING needs to be true, and
+# zurich must be allowed cobrand if we want to be able to call cobrand
+# methods on it.
sub send_reports_for_zurich {
- FixMyStreet::override_config { SEND_REPORTS_ON_STAGING => 1 }, sub {
+ FixMyStreet::override_config {
+ SEND_REPORTS_ON_STAGING => 1,
+ ALLOWED_COBRANDS => ['zurich']
+ }, sub {
# Actually send the report
$c->model('DB::Problem')->send_reports('zurich');
};
@@ -32,15 +43,14 @@ sub send_reports_for_zurich {
sub reset_report_state {
my ($report, $created) = @_;
$report->discard_changes;
- my $extra = $report->extra;
- delete $extra->{moderated_overdue};
- delete $extra->{subdiv_overdue};
- delete $extra->{closed_overdue};
- $report->update({
- extra => { %$extra },
- state => 'unconfirmed',
- $created ? ( created => $created ) : (),
- });
+ $report->unset_extra_metadata('moderated_overdue');
+ $report->unset_extra_metadata('subdiv_overdue');
+ $report->unset_extra_metadata('closed_overdue');
+ $report->unset_extra_metadata('closure_status');
+ $report->whensent(undef);
+ $report->state('unconfirmed');
+ $report->created($created) if $created;
+ $report->update;
}
use FixMyStreet::TestMech;
@@ -64,6 +74,7 @@ $division->parent( $zurich->id );
$division->send_method( 'Zurich' );
$division->endpoint( 'division@example.org' );
$division->update;
+$division->body_areas->find_or_create({ area_id => 274456 });
my $subdivision = $mech->create_body_ok( 3, 'Subdivision A' );
$subdivision->parent( $division->id );
$subdivision->send_method( 'Zurich' );
@@ -103,15 +114,18 @@ my @reports = $mech->create_problems_for_body( 1, $division->id, 'Test', {
state => 'unconfirmed',
confirmed => undef,
cobrand => 'zurich',
+ photo => $sample_photo,
});
my $report = $reports[0];
FixMyStreet::override_config {
ALLOWED_COBRANDS => [ 'zurich' ],
+ MAP_TYPE => 'Zurich,OSM',
}, sub {
$mech->get_ok( '/report/' . $report->id );
};
-$mech->content_contains('&Uuml;berpr&uuml;fung ausstehend');
+$mech->content_contains('&Uuml;berpr&uuml;fung ausstehend')
+ or die $mech->content;
# Check logging in to deal with this report
FixMyStreet::override_config {
@@ -136,7 +150,6 @@ $mech->content_contains( 'report_edit/' . $report->id );
$mech->content_contains( DateTime->now->strftime("%d.%m.%Y") );
$mech->content_contains( 'Erfasst' );
-
subtest "changing of categories" => sub {
# create a few categories (which are actually contacts)
foreach my $name ( qw/Cat1 Cat2/ ) {
@@ -147,6 +160,9 @@ subtest "changing of categories" => sub {
);
}
+ # full Categories dropdown is hidden for unconfirmed reports
+ $report->update({ state => 'confirmed' });
+
# put report into known category
my $original_category = $report->category;
$report->update({ category => 'Cat1' });
@@ -159,6 +175,7 @@ subtest "changing of categories" => sub {
# change the category via the web interface
FixMyStreet::override_config {
ALLOWED_COBRANDS => [ 'zurich' ],
+ MAP_TYPE => 'Zurich,OSM',
}, sub {
$mech->get_ok( '/admin/report_edit/' . $report->id );
$mech->submit_form_ok( { with_fields => { category => 'Cat2' } } );
@@ -202,107 +219,112 @@ sub get_moderated_count {
subtest "report_edit" => sub {
- ok ( ! exists ${$report->extra}{moderated_overdue}, 'Report currently unmoderated' );
-
- is get_moderated_count(), 0;
-
FixMyStreet::override_config {
ALLOWED_COBRANDS => [ 'zurich' ],
+ MAP_TYPE => 'Zurich,OSM',
}, sub {
+
+ reset_report_state($report);
+ ok ( ! $report->get_extra_metadata('moderated_overdue'), 'Report currently unmoderated' );
+ is get_moderated_count(), 0;
+
$mech->get_ok( '/admin/report_edit/' . $report->id );
$mech->content_contains( 'Unbest&auml;tigt' ); # Unconfirmed email
$mech->submit_form_ok( { with_fields => { state => 'confirmed' } } );
$mech->get_ok( '/report/' . $report->id );
- };
- $mech->content_contains('Aufgenommen');
- $mech->content_contains('Test Test');
- $mech->content_lacks('photo/' . $report->id . '.jpeg');
- $mech->email_count_is(0);
+ $report->discard_changes();
- $report->discard_changes;
+ $mech->content_contains('Aufgenommen');
+ $mech->content_contains('Test Test');
+ $mech->content_lacks('photo/' . $report->id . '.0.jpeg');
+ $mech->email_count_is(0);
- is ( $report->extra->{moderated_overdue}, 0, 'Report now marked moderated' );
- is get_moderated_count(), 1;
+ $report->discard_changes;
+ is ( $report->get_extra_metadata('moderated_overdue'), 0, 'Report now marked moderated' );
+ is get_moderated_count(), 1;
- # Set state back to 10 days ago so that report is overdue
- my $created = $report->created;
- reset_report_state($report, $created->clone->subtract(days => 10));
+ # Set state back to 10 days ago so that report is overdue
+ my $created = $report->created;
+ reset_report_state($report, $created->clone->subtract(days => 10));
- is get_moderated_count(), 0;
+ is get_moderated_count(), 0;
- FixMyStreet::override_config {
- ALLOWED_COBRANDS => [ 'zurich' ],
- }, sub {
$mech->get_ok( '/admin/report_edit/' . $report->id );
$mech->submit_form_ok( { with_fields => { state => 'confirmed' } } );
$mech->get_ok( '/report/' . $report->id );
- };
- $report->discard_changes;
- is ( $report->extra->{moderated_overdue}, 1, 'moderated_overdue set correctly when overdue' );
- is get_moderated_count(), 0, 'Moderated count not increased when overdue';
- reset_report_state($report, $created);
+ $report->discard_changes;
+ is ( $report->get_extra_metadata('moderated_overdue'), 1, 'moderated_overdue set correctly when overdue' );
+ is get_moderated_count(), 0, 'Moderated count not increased when overdue';
+
+ reset_report_state($report, $created);
- FixMyStreet::override_config {
- ALLOWED_COBRANDS => [ 'zurich' ],
- }, sub {
$mech->get_ok( '/admin/report_edit/' . $report->id );
$mech->submit_form_ok( { with_fields => { state => 'confirmed' } } );
$mech->get_ok( '/report/' . $report->id );
- };
- $report->discard_changes;
- is ( $report->extra->{moderated_overdue}, 0, 'Marking confirmed sets moderated_overdue' );
- is ( $report->extra->{closed_overdue}, undef, 'Marking confirmed does NOT set closed_overdue' );
- is get_moderated_count(), 1;
+ $report->discard_changes;
+ is ( $report->get_extra_metadata('moderated_overdue'), 0, 'Marking confirmed sets moderated_overdue' );
+ is ( $report->get_extra_metadata('closed_overdue'), undef, 'Marking confirmed does NOT set closed_overdue' );
+ is get_moderated_count(), 1;
- FixMyStreet::override_config {
- ALLOWED_COBRANDS => [ 'zurich' ],
- }, sub {
$mech->get_ok( '/admin/report_edit/' . $report->id );
$mech->submit_form_ok( { with_fields => { state => 'hidden' } } );
$mech->get_ok( '/admin/report_edit/' . $report->id );
- };
- $report->discard_changes;
- is ( $report->extra->{moderated_overdue}, 0, 'Still marked moderated_overdue' );
- is ( $report->extra->{closed_overdue}, 0, 'Marking hidden also set closed_overdue' );
- is get_moderated_count(), 1, 'Check still counted moderated'
- or diag $report->get_column('extra');
- reset_report_state($report);
+ $report->discard_changes;
+ is ( $report->get_extra_metadata('moderated_overdue'), 0, 'Still marked moderated_overdue' );
+ is ( $report->get_extra_metadata('closed_overdue'), undef, "Marking hidden doesn't set closed_overdue..." );
+ is ( $report->state, 'planned', 'Marking hidden actually sets state to planned');
+ is ( $report->get_extra_metadata('closure_status'), 'hidden', 'Marking hidden sets closure_status to hidden');
+ is get_moderated_count(), 1, 'Check still counted moderated'
+ or diag $report->get_column('extra');
+
+ # publishing actually sets hidden
+ $mech->form_with_fields( 'status_update' );
+ $mech->submit_form_ok( { button => 'publish_response' } );
+ $mech->get_ok( '/admin/report_edit/' . $report->id );
+ $report->discard_changes;
- is ( $report->extra->{moderated_overdue}, undef, 'Sanity check' );
- is get_moderated_count(), 0;
+ is ( $report->get_extra_metadata('closed_overdue'), 0, "Closing as hidden sets closed_overdue..." );
+ is ( $report->state, 'hidden', 'Closing as hidden sets state to hidden');
+ is ( $report->get_extra_metadata('closure_status'), undef, 'Closing as hidden unsets closure_status');
- # Check that setting to 'hidden' also triggers moderation
- FixMyStreet::override_config {
- ALLOWED_COBRANDS => [ 'zurich' ],
- }, sub {
+
+ reset_report_state($report);
+ is ( $report->get_extra_metadata('moderated_overdue'), undef, 'Sanity check' );
+ is get_moderated_count(), 0;
+
+ # Check that setting to 'hidden' also triggers moderation
$mech->get_ok( '/admin/report_edit/' . $report->id );
$mech->submit_form_ok( { with_fields => { state => 'hidden' } } );
$mech->get_ok( '/admin/report_edit/' . $report->id );
- };
- $report->discard_changes;
- is ( $report->extra->{moderated_overdue}, 0, 'Marking hidden from scratch sets moderated_overdue' );
- is ( $report->extra->{closed_overdue}, 0, 'Marking hidden from scratch also set closed_overdue' );
- is get_moderated_count(), 1;
+ $mech->form_with_fields( 'status_update' );
+ $mech->submit_form_ok( { button => 'publish_response' } );
- is ($cobrand->get_or_check_overdue($report), 0, 'sanity check');
- $report->update({ created => $created->clone->subtract(days => 10) });
- is ($cobrand->get_or_check_overdue($report), 0, 'overdue call not increased');
+ $report->discard_changes;
+ is ( $report->get_extra_metadata('moderated_overdue'), 0, 'Marking hidden from scratch sets moderated_overdue' );
+ is ( $report->get_extra_metadata('closed_overdue'), 0, 'Marking hidden from scratch also set closed_overdue' );
+ is get_moderated_count(), 1;
- reset_report_state($report, $created);
+ is ($cobrand->get_or_check_overdue($report), 0, 'sanity check');
+ $report->update({ created => $created->clone->subtract(days => 10) });
+ is ($cobrand->get_or_check_overdue($report), 0, 'overdue call not increased');
+
+ reset_report_state($report, $created);
+ }
};
FixMyStreet::override_config {
ALLOWED_COBRANDS => [ 'zurich' ],
+ MAP_TYPE => 'Zurich,OSM',
}, sub {
# Photo publishing
$mech->get_ok( '/admin/report_edit/' . $report->id );
$mech->submit_form_ok( { with_fields => { state => 'confirmed', publish_photo => 1 } } );
$mech->get_ok( '/report/' . $report->id );
- $mech->content_contains('photo/' . $report->id . '.jpeg');
+ $mech->content_contains('photo/' . $report->id . '.0.jpeg');
# Internal notes
$mech->get_ok( '/admin/report_edit/' . $report->id );
@@ -317,7 +339,7 @@ FixMyStreet::override_config {
$mech->content_contains( 'Originaltext: &ldquo;Test Test 1 for ' . $division->id . ' Detail&rdquo;' );
$mech->get_ok( '/admin/report_edit/' . $report->id );
- $mech->submit_form_ok( { with_fields => { body_subdivision => $subdivision->id, send_rejected_email => 1 } } );
+ $mech->submit_form_ok( { with_fields => { body_subdivision => $subdivision->id } } );
$mech->get_ok( '/report/' . $report->id );
$mech->content_contains('In Bearbeitung');
@@ -332,74 +354,109 @@ $mech->clear_emails_ok;
$mech->log_out_ok;
-my $user = $mech->log_in_ok( 'sdm1@example.org') ;
-$user->update({ from_body => undef });
-FixMyStreet::override_config {
- ALLOWED_COBRANDS => [ 'zurich' ],
-}, sub {
- $mech->get_ok( '/admin' );
-};
-is $mech->uri->path, '/my', "got sent to /my";
-$user->from_body( $subdivision->id );
-$user->update;
+subtest 'SDM' => sub {
+ my $user = $mech->log_in_ok( 'sdm1@example.org') ;
+ $user->update({ from_body => undef });
+ FixMyStreet::override_config {
+ ALLOWED_COBRANDS => [ 'zurich' ],
+ }, sub {
+ $mech->get_ok( '/admin' );
+ };
+ is $mech->uri->path, '/my', "got sent to /my";
+ $user->from_body( $subdivision->id );
+ $user->update;
-FixMyStreet::override_config {
- ALLOWED_COBRANDS => [ 'zurich' ],
-}, sub {
- $mech->get_ok( '/admin' );
-};
-is $mech->uri->path, '/admin', "am logged in";
+ FixMyStreet::override_config {
+ ALLOWED_COBRANDS => [ 'zurich' ],
+ }, sub {
+ $mech->get_ok( '/admin' );
+ };
+ is $mech->uri->path, '/admin', "am logged in";
-$mech->content_contains( 'report_edit/' . $report->id );
-$mech->content_contains( DateTime->now->strftime("%d.%m.%Y") );
-$mech->content_contains( 'In Bearbeitung' );
+ $mech->content_contains( 'report_edit/' . $report->id );
+ $mech->content_contains( DateTime->now->strftime("%d.%m.%Y") );
+ $mech->content_contains( 'In Bearbeitung' );
-FixMyStreet::override_config {
- ALLOWED_COBRANDS => [ 'zurich' ],
-}, sub {
- $mech->get_ok( '/admin/report_edit/' . $report->id );
- $mech->content_contains( 'Initial internal note' );
+ FixMyStreet::override_config {
+ ALLOWED_COBRANDS => [ 'zurich' ],
+ MAP_TYPE => 'Zurich,OSM',
+ }, sub {
+ $mech->get_ok( '/admin/report_edit/' . $report->id );
+ $mech->content_contains( 'Initial internal note' );
- $mech->submit_form_ok( { with_fields => { status_update => 'This is an update.' } } );
- is $mech->uri->path, '/admin/report_edit/' . $report->id, "still on edit page";
- $mech->content_contains('This is an update');
- ok $mech->form_with_fields( 'status_update' );
- $mech->submit_form_ok( { button => 'no_more_updates' } );
- is $mech->uri->path, '/admin/summary', "redirected now finished with report.";
+ $mech->submit_form_ok( { with_fields => { status_update => 'This is an update.' } } );
+ is $mech->uri->path, '/admin/report_edit/' . $report->id, "still on edit page";
+ $mech->content_contains('This is an update');
+ ok $mech->form_with_fields( 'status_update' );
+ $mech->submit_form_ok( { button => 'no_more_updates' } );
+ is $mech->uri->path, '/admin/summary', "redirected now finished with report.";
- $mech->get_ok( '/report/' . $report->id );
- $mech->content_contains('In Bearbeitung');
- $mech->content_contains('Test Test');
-};
+ $mech->get_ok( '/report/' . $report->id );
+ $mech->content_contains('In Bearbeitung');
+ $mech->content_contains('Test Test');
+ };
-send_reports_for_zurich();
-$email = $mech->get_email;
-like $email->header('Subject'), qr/Feedback/, 'subject looks okay';
-like $email->header('To'), qr/division\@example.org/, 'to line looks correct';
-$mech->clear_emails_ok;
+ send_reports_for_zurich();
+ $email = $mech->get_email;
+ like $email->header('Subject'), qr/Feedback/, 'subject looks okay';
+ like $email->header('To'), qr/division\@example.org/, 'to line looks correct';
+ $mech->clear_emails_ok;
-$report->discard_changes;
-is $report->state, 'planned', 'Report now in planned state';
+ $report->discard_changes;
+ is $report->state, 'planned', 'Report now in planned state';
+
+ subtest 'send_back' => sub {
+ FixMyStreet::override_config {
+ ALLOWED_COBRANDS => [ 'zurich' ],
+ MAP_TYPE => 'Zurich,OSM',
+ }, sub {
+ $report->update({ bodies_str => $subdivision->id, state => 'in progress' });
+ $mech->get_ok( '/admin/report_edit/' . $report->id );
+ $mech->submit_form_ok( { form_number => 2, button => 'send_back' } );
+ $report->discard_changes;
+ is $report->state, 'confirmed', 'Report sent back to confirmed state';
+ is $report->bodies_str, $division->id, 'Report sent back to division';
+ };
+ };
-$mech->log_out_ok;
-$user = $mech->log_in_ok( 'dm1@example.org') ;
+ subtest 'not contactable' => sub {
+ FixMyStreet::override_config {
+ ALLOWED_COBRANDS => [ 'zurich' ],
+ MAP_TYPE => 'Zurich,OSM',
+ }, sub {
+ $report->update({ bodies_str => $subdivision->id, state => 'in progress' });
+ $mech->get_ok( '/admin/report_edit/' . $report->id );
+ $mech->submit_form_ok( { button => 'not_contactable', form_number => 2 } );
+ $report->discard_changes;
+ is $report->state, 'planned', 'Report sent back to Rueckmeldung ausstehend state';
+ is $report->get_extra_metadata('closure_status'), 'partial', 'Report sent back to partial (not_contactable) state';
+ is $report->bodies_str, $division->id, 'Report sent back to division';
+ };
+ };
+
+ $mech->log_out_ok;
+};
+
+my $user = $mech->log_in_ok( 'dm1@example.org') ;
FixMyStreet::override_config {
ALLOWED_COBRANDS => [ 'zurich' ],
}, sub {
$mech->get_ok( '/admin' );
};
+reset_report_state($report);
+$report->update({ state => 'planned' });
+
$mech->content_contains( 'report_edit/' . $report->id );
$mech->content_contains( DateTime->now->strftime("%d.%m.%Y") );
# User confirms their email address
-my $extra = $report->extra;
-$extra->{email_confirmed} = 1;
-$report->extra ( { %$extra } );
+$report->set_extra_metadata(email_confirmed => 1);
$report->update;
FixMyStreet::override_config {
ALLOWED_COBRANDS => [ 'zurich' ],
+ MAP_TYPE => 'Zurich,OSM',
}, sub {
$mech->get_ok( '/admin/report_edit/' . $report->id );
$mech->content_lacks( 'Unbest&auml;tigt' ); # Confirmed email
@@ -419,18 +476,22 @@ like $email->header('From'), qr/division\@example.org/, 'from line looks correct
like $email->body, qr/FINAL UPDATE/, 'body looks correct';
$mech->clear_emails_ok;
-# Assign directly to planned, don't confirm email
+# Assign planned (via confirmed), don't confirm email
@reports = $mech->create_problems_for_body( 1, $division->id, 'Second', {
state => 'unconfirmed',
confirmed => undef,
cobrand => 'zurich',
+ photo => $sample_photo,
});
$report = $reports[0];
FixMyStreet::override_config {
ALLOWED_COBRANDS => [ 'zurich' ],
+ MAP_TYPE => 'Zurich,OSM',
}, sub {
$mech->get_ok( '/admin/report_edit/' . $report->id );
+ $mech->submit_form_ok( { with_fields => { state => 'confirmed' } } );
+ $mech->get_ok( '/admin/report_edit/' . $report->id );
$mech->submit_form_ok( { with_fields => { state => 'planned' } } );
$mech->get_ok( '/report/' . $report->id );
};
@@ -439,9 +500,12 @@ $mech->content_contains('Second Test');
FixMyStreet::override_config {
ALLOWED_COBRANDS => [ 'zurich' ],
+ MAP_TYPE => 'Zurich,OSM',
}, sub {
$mech->get_ok( '/admin/report_edit/' . $report->id );
$mech->content_contains( 'Unbest&auml;tigt' );
+ $report->discard_changes;
+ $mech->form_with_fields( 'status_update' );
$mech->submit_form_ok( { button => 'publish_response', with_fields => { status_update => 'FINAL UPDATE' } } );
$mech->get_ok( '/report/' . $report->id );
@@ -458,52 +522,155 @@ $mech->email_count_is(0);
state => 'unconfirmed',
confirmed => undef,
cobrand => 'zurich',
+ photo => $sample_photo,
});
$report = $reports[0];
-FixMyStreet::override_config {
- ALLOWED_COBRANDS => [ 'zurich' ],
-}, sub {
- $mech->get_ok( '/admin/report_edit/' . $report->id );
- $mech->submit_form_ok( { with_fields => { body_external => $external_body->id } } );
- $mech->get_ok( '/report/' . $report->id );
-};
-$mech->content_contains('Beantwortet');
-$mech->content_contains('Third Test');
-$mech->content_contains('Wir haben Ihr Anliegen an External Body weitergeleitet');
-send_reports_for_zurich();
-$email = $mech->get_email;
-like $email->header('Subject'), qr/Weitergeleitete Meldung/, 'subject looks okay';
-like $email->header('To'), qr/external_body\@example.org/, 'to line looks correct';
-like $email->body, qr/External Body/, 'body has right name';
-unlike $email->body, qr/test\@example.com/, 'body does not contain email address';
-$mech->clear_emails_ok;
+subtest "external report triggers email" => sub {
+ my $EXTERNAL_MESSAGE = 'Look Ma, no hands!';
+ FixMyStreet::override_config {
+ ALLOWED_COBRANDS => [ 'zurich' ],
+ MAP_TYPE => 'Zurich,OSM',
+ }, sub {
-# Test calling back, and third_personal boolean setting
-FixMyStreet::override_config {
- ALLOWED_COBRANDS => [ 'zurich' ],
-}, sub {
- $mech->get_ok( '/admin' );
- is $mech->uri->path, '/admin', "am logged in";
- $mech->content_contains( 'report_edit/' . $report->id );
- $mech->get_ok( '/admin/report_edit/' . $report->id );
- $mech->submit_form_ok( { with_fields => { state => 'unconfirmed' } } );
- $mech->submit_form_ok( { with_fields => { body_external => $external_body->id, third_personal => 1 } } );
- $mech->get_ok( '/report/' . $report->id );
+ # required to see body_external field
+ $report->state('planned');
+ $report->set_extra_metadata('closure_status' => 'closed');
+ # Set the public_response manually here because the default one will have line breaks that get escaped as HTML, causing the comparison to fail.
+ $report->set_extra_metadata('public_response' => 'Freundliche Gruesse Ihre Stadt Zuerich');
+ $report->update;
+
+ $mech->get_ok( '/admin/report_edit/' . $report->id );
+ $mech->form_with_fields( 'publish_response' );
+ $mech->submit_form_ok( {
+ button => 'publish_response',
+ with_fields => {
+ body_external => $external_body->id,
+ external_message => $EXTERNAL_MESSAGE,
+ } });
+ $report->discard_changes;
+ $mech->get_ok( '/report/' . $report->id );
+ };
+ is ($report->state, 'closed', 'Report was closed correctly');
+ $mech->content_contains('Extern')
+ or die $mech->content;
+ $mech->content_contains('Third Test');
+ $mech->content_contains($report->get_extra_metadata('public_response')) or die $mech->content;
+ send_reports_for_zurich();
+ $email = $mech->get_email;
+ like $email->header('Subject'), qr/Weitergeleitete Meldung/, 'subject looks okay';
+ like $email->header('To'), qr/external_body\@example.org/, 'to line looks correct';
+ like $email->body, qr/External Body/, 'body has right name';
+ like $email->body, qr/$EXTERNAL_MESSAGE/, 'external_message was passed on';
+ unlike $email->body, qr/test\@example.com/, 'body does not contain email address';
+ $mech->clear_emails_ok;
+
+ subtest "Test third_personal boolean setting" => sub {
+ FixMyStreet::override_config {
+ ALLOWED_COBRANDS => [ 'zurich' ],
+ MAP_TYPE => 'Zurich,OSM',
+ }, sub {
+ $mech->get_ok( '/admin' );
+ # required to see body_external field
+ $report->state('planned');
+ $report->set_extra_metadata('closure_status' => 'closed');
+ $report->set_extra_metadata('public_response' => 'Freundliche Gruesse Ihre Stadt Zuerich');
+ $report->update;
+
+ is $mech->uri->path, '/admin', "am logged in";
+ $mech->content_contains( 'report_edit/' . $report->id );
+ $mech->get_ok( '/admin/report_edit/' . $report->id );
+ $mech->form_with_fields( 'publish_response' );
+ $mech->submit_form_ok( {
+ button => 'publish_response',
+ with_fields => {
+ body_external => $external_body->id,
+ third_personal => 1,
+ } });
+ $mech->get_ok( '/report/' . $report->id );
+ };
+ $mech->content_contains('Extern');
+ $mech->content_contains('Third Test');
+ $mech->content_contains($report->get_extra_metadata('public_response'));
+ send_reports_for_zurich();
+ $email = $mech->get_email;
+ like $email->header('Subject'), qr/Weitergeleitete Meldung/, 'subject looks okay';
+ like $email->header('To'), qr/external_body\@example.org/, 'to line looks correct';
+ like $email->body, qr/External Body/, 'body has right name';
+ like $email->body, qr/test\@example.com/, 'body does contain email address';
+ $mech->clear_emails_ok;
+ };
+
+ subtest "Test external wish sending" => sub {
+ FixMyStreet::override_config {
+ ALLOWED_COBRANDS => [ 'zurich' ],
+ MAP_TYPE => 'Zurich,OSM',
+ }, sub {
+ # set as wish
+ $report->discard_changes;
+ $report->state('planned');
+ $report->set_extra_metadata('closure_status' => 'investigating');
+ $report->update;
+ is ($report->state, 'planned', 'Sanity check') or die;
+
+ $mech->get_ok( '/admin/report_edit/' . $report->id );
+
+ $mech->form_with_fields( 'publish_response' );
+ $mech->submit_form_ok( {
+ button => 'publish_response',
+ with_fields => {
+ body_external => $external_body->id,
+ external_message => $EXTERNAL_MESSAGE,
+ } });
+ };
+ send_reports_for_zurich();
+ $email = $mech->get_email;
+ like $email->header('Subject'), qr/Weitergeleitete Meldung/, 'subject looks okay';
+ like $email->header('To'), qr/external_body\@example.org/, 'to line looks correct';
+ like $email->body, qr/External Body/, 'body has right name';
+ like $email->body, qr/$EXTERNAL_MESSAGE/, 'external_message was passed on';
+ like $email->body, qr/test\@example.com/, 'body contains email address';
+ $mech->clear_emails_ok;
+ };
+
+ subtest "Closure email includes public response" => sub {
+ my $PUBLIC_RESPONSE = "This is the public response to your report. Freundliche Gruesse.";
+ FixMyStreet::override_config {
+ ALLOWED_COBRANDS => [ 'zurich' ],
+ MAP_TYPE => 'Zurich,OSM',
+ }, sub {
+ # set as extern
+ reset_report_state($report);
+ $report->state('planned');
+ $report->set_extra_metadata('closure_status' => 'closed');
+ $report->set_extra_metadata('email_confirmed' => 1);
+ $report->unset_extra_metadata('public_response');
+ $report->update;
+ is ($report->state, 'planned', 'Sanity check') or die;
+
+ $mech->get_ok( '/admin/report_edit/' . $report->id );
+
+ $mech->form_with_fields( 'publish_response' );
+ $mech->submit_form_ok( {
+ button => 'publish_response',
+ with_fields => {
+ body_external => $external_body->id,
+ external_message => $EXTERNAL_MESSAGE,
+ status_update => $PUBLIC_RESPONSE,
+ } });
+ };
+ $email = $mech->get_email;
+ my $report_id = $report->id;
+ like $email->header('Subject'), qr/Meldung #$report_id/, 'subject looks okay';
+ like $email->header('To'), qr/test\@example.com/, 'to line looks correct';
+ like $email->body, qr/$PUBLIC_RESPONSE/, 'public_response was passed on' or die $email->body;
+ $mech->clear_emails_ok;
+ };
+ $report->comments->delete; # delete the comments, as they confuse later tests
};
-$mech->content_contains('Beantwortet');
-$mech->content_contains('Third Test');
-$mech->content_contains('Wir haben Ihr Anliegen an External Body weitergeleitet');
-send_reports_for_zurich();
-$email = $mech->get_email;
-like $email->header('Subject'), qr/Weitergeleitete Meldung/, 'subject looks okay';
-like $email->header('To'), qr/external_body\@example.org/, 'to line looks correct';
-like $email->body, qr/External Body/, 'body has right name';
-like $email->body, qr/test\@example.com/, 'body does contain email address';
-$mech->clear_emails_ok;
-$mech->log_out_ok;
-subtest "only superuser can see stats" => sub {
+subtest "superuser and dm can see stats" => sub {
+ $mech->log_out_ok;
$user = $mech->log_in_ok( 'super@example.org' );
FixMyStreet::override_config {
@@ -520,7 +687,7 @@ subtest "only superuser can see stats" => sub {
}, sub {
$mech->get( '/admin/stats' );
};
- is $mech->res->code, 404, "only superuser should be able to see stats page";
+ is $mech->res->code, 200, "dm can now also see stats page";
$mech->log_out_ok;
};
@@ -556,6 +723,7 @@ subtest "phone number is mandatory" => sub {
ALLOWED_COBRANDS => [ 'zurich' ],
MAPIT_ID_WHITELIST => [ 274456 ],
MAPIT_GENERATION => 2,
+ MAP_TYPE => 'Zurich,OSM',
}, sub {
$user = $mech->log_in_ok( 'dm1@example.org' );
$mech->get_ok( '/report/new?lat=47.381817&lon=8.529156' );
@@ -572,6 +740,7 @@ subtest "phone number is not mandatory for reports from mobile apps" => sub {
ALLOWED_COBRANDS => [ 'zurich' ],
MAPIT_ID_WHITELIST => [ 423017 ],
MAPIT_GENERATION => 4,
+ MAP_TYPE => 'Zurich,OSM',
}, sub {
$mech->post_ok( '/report/new/mobile?lat=47.381817&lon=8.529156' , {
service => 'iPhone',
@@ -602,35 +771,56 @@ subtest "problems can't be assigned to deleted bodies" => sub {
MAPIT_URL => 'http://global.mapit.mysociety.org/',
MAPIT_TYPES => [ 'O08' ],
MAPIT_ID_WHITELIST => [ 423017 ],
+ MAP_TYPE => 'Zurich,OSM',
}, sub {
$mech->get_ok( '/admin/body/' . $external_body->id );
$mech->submit_form_ok( { with_fields => { deleted => 1 } } );
$mech->get_ok( '/admin/report_edit/' . $report->id );
- $mech->content_lacks( $external_body->name );
+ $mech->content_lacks( $external_body->name )
+ or do {
+ diag $mech->content;
+ diag $external_body->name;
+ die;
+ };
};
$user->from_body( $division->id );
$user->update;
$mech->log_out_ok;
};
-subtest "hidden report email are only sent when requested" => sub {
- $user = $mech->log_in_ok( 'dm1@example.org') ;
- $extra = $report->extra;
- $extra->{email_confirmed} = 1;
- $report->extra ( { %$extra } );
- $report->update;
+subtest "photo must be supplied for categories that require it" => sub {
+ FixMyStreet::App->model('DB::Contact')->find_or_create({
+ body => $division,
+ category => "Graffiti - photo required",
+ email => "graffiti\@example.org",
+ confirmed => 1,
+ deleted => 0,
+ editor => "editor",
+ whenedited => DateTime->now(),
+ note => "note for graffiti",
+ extra => { photo_required => 1 }
+ });
FixMyStreet::override_config {
+ MAPIT_TYPES => [ 'O08' ],
+ MAPIT_URL => 'http://global.mapit.mysociety.org/',
ALLOWED_COBRANDS => [ 'zurich' ],
+ MAPIT_ID_WHITELIST => [ 274456 ],
+ MAPIT_GENERATION => 2,
+ MAP_TYPE => 'Zurich,OSM',
}, sub {
- $mech->get_ok( '/admin/report_edit/' . $report->id );
- $mech->submit_form_ok( { with_fields => { state => 'hidden', send_rejected_email => 1 } } );
- $mech->email_count_is(1);
- $mech->clear_emails_ok;
- $mech->get_ok( '/admin/report_edit/' . $report->id );
- $mech->submit_form_ok( { with_fields => { state => 'hidden', send_rejected_email => undef } } );
- $mech->email_count_is(0);
- $mech->clear_emails_ok;
- $mech->log_out_ok;
+ $mech->post_ok( '/report/new', {
+ detail => 'Problem-Bericht',
+ lat => 47.381817,
+ lon => 8.529156,
+ email => 'user@example.org',
+ pc => '',
+ name => '',
+ category => 'Graffiti - photo required',
+ photo => '',
+ submit_problem => 1,
+ });
+ is $mech->res->code, 200, "missing photo shouldn't return anything but 200";
+ $mech->content_contains(_("Photo is required."), 'response should contain photo error message');
};
};
@@ -643,7 +833,7 @@ subtest "test stats" => sub {
$mech->get_ok( '/admin/stats' );
is $mech->res->code, 200, "superuser should be able to see stats page";
- $mech->content_contains('Innerhalb eines Arbeitstages moderiert: 2'); # now including hidden
+ $mech->content_contains('Innerhalb eines Arbeitstages moderiert: 3');
$mech->content_contains('Innerhalb von f&uuml;nf Arbeitstagen abgeschlossen: 3');
# my @data = $mech->content =~ /(?:moderiert|abgeschlossen): \d+/g;
# diag Dumper(\@data); use Data::Dumper;
@@ -652,10 +842,7 @@ subtest "test stats" => sub {
if (defined $export_count) {
is $export_count - $EXISTING_REPORT_COUNT, 3, 'Correct number of reports';
$mech->content_contains('fixed - council');
- $mech->content_contains(',hidden,');
}
-
- $mech->log_out_ok;
};
};
@@ -665,10 +852,118 @@ subtest "test admin_log" => sub {
object_type => 'problem',
object_id => $report->id,
});
- is scalar @entries, 4, 'State changes logged';
- is $entries[-1]->action, 'state change to hidden', 'State change logged as expected';
+
+ # XXX: following is dependent on all of test up till now, rewrite to explicitly
+ # test which things need to be logged!
+ is scalar @entries, 4, 'State changes logged';
+ is $entries[-1]->action, 'state change to closed', 'State change logged as expected';
};
+subtest 'email images to external partners' => sub {
+ FixMyStreet::override_config {
+ ALLOWED_COBRANDS => [ 'zurich' ],
+ MAP_TYPE => 'Zurich,OSM',
+ }, sub {
+ reset_report_state($report);
+
+ my $photo = path(__FILE__)->parent->child('zurich-logo_portal.x.jpg')->slurp_raw;
+ my $photoset = FixMyStreet::App::Model::PhotoSet->new({
+ c => $c,
+ data_items => [ $photo ],
+ });
+ my $fileid = $photoset->data;
+
+ $report->set_extra_metadata('publish_photo' => 1);
+ # The below email comparison must not have an external message.
+ $report->unset_extra_metadata('external_message');
+ $report->update({
+ state => 'closed',
+ photo => $fileid,
+ external_body => $external_body->id,
+ });
+
+ $mech->clear_emails_ok;
+ send_reports_for_zurich();
+
+ my @emails = $mech->get_email;
+ my $email_as_string = $mech->get_first_email(@emails);
+ my ($boundary) = $email_as_string =~ /boundary="([A-Za-z0-9.]*)"/ms;
+ my $changes = $email_as_string =~ s{$boundary}{}g;
+ is $changes, 4, '4 boundaries'; # header + 3 around the 2x parts (text + 1 image)
+
+ my $expected_email_content = path(__FILE__)->parent->child('zurich_attachments.txt')->slurp;
+
+ my $REPORT_ID = $report->id;
+ $expected_email_content =~ s{REPORT_ID}{$REPORT_ID}g;
+
+ is_string $email_as_string, $expected_email_content, 'MIME email text ok'
+ or do {
+ (my $test_name = $0) =~ s{/}{_}g;
+ my $path = path("test-output-$test_name.tmp");
+ $path->spew($email_as_string);
+ diag "Saved output in $path";
+ };
+ };
+};
+
+subtest 'Status update shown as appropriate' => sub {
+ FixMyStreet::override_config {
+ ALLOWED_COBRANDS => [ 'zurich' ],
+ MAP_TYPE => 'Zurich,OSM',
+ }, sub {
+ # ALL closed states must hide the public_response edit, and public ones
+ # must show the answer in blue.
+ for (['planned', 1, 0, 0],
+ ['fixed - council', 0, 1, 0],
+ ['closed', 0, 1, 0],
+ ['hidden', 0, 0, 1])
+ {
+ my ($state, $update, $public, $user_response) = @$_;
+ $report->update({ state => $state });
+ $mech->get_ok( '/admin/report_edit/' . $report->id );
+ contains_or_lacks($mech, $update, "<textarea name='status_update'");
+ contains_or_lacks($mech, $public || $user_response, '<div class="admin-official-answer">');
+
+ if ($public) {
+ $mech->get_ok( '/report/' . $report->id );
+ $mech->content_contains('Antwort</h4>');
+ }
+ }
+ };
+};
+
+# TODO refactor into FixMyStreet::TestMech;
+sub contains_or_lacks {
+ my ($mech, $contains, $text) = @_;
+ if ($contains) {
+ $mech->content_contains($text);
+ }
+ else {
+ $mech->content_lacks($text);
+ }
+}
+
+subtest 'time_spent' => sub {
+ FixMyStreet::override_config {
+ ALLOWED_COBRANDS => [ 'zurich' ],
+ MAP_TYPE => 'Zurich,OSM',
+ }, sub {
+ my $report = $reports[0];
+
+ is $report->get_time_spent, 0, '0 minutes spent';
+ $report->update({ state => 'in progress' });
+ $mech->get_ok( '/admin/report_edit/' . $report->id );
+ $mech->form_with_fields( 'time_spent' );
+ $mech->submit_form_ok( {
+ with_fields => {
+ time_spent => 10,
+ } });
+ is $report->get_time_spent, 10, '10 minutes spent';
+ };
+};
+
+$mech->log_out_ok;
+
END {
$mech->delete_body($subdivision);
$mech->delete_body($division);
@@ -679,3 +974,5 @@ END {
ok $mech->host("www.fixmystreet.com"), "change host back";
done_testing();
}
+
+1;
diff --git a/t/cobrand/zurich_attachments.txt b/t/cobrand/zurich_attachments.txt
new file mode 100644
index 000000000..1c989c4d9
--- /dev/null
+++ b/t/cobrand/zurich_attachments.txt
@@ -0,0 +1,40 @@
+MIME-Version: 1.0
+Subject: =?iso-8859-1?Q?Z=FCri?= wie neu: Weitergeleitete Meldung #REPORT_ID
+Content-Type: multipart/mixed; boundary=""
+To: "External Body" <external_body@example.org>
+Content-Transfer-Encoding: 7bit
+From: FixMyStreet <division@example.org>
+
+
+--
+MIME-Version: 1.0
+Subject: =?iso-8859-1?Q?Z=FCri?= wie neu: Weitergeleitete Meldung #REPORT_ID
+Content-Type: text/plain; charset="iso-8859-1"
+To: "External Body" <external_body@example.org>
+Content-Transfer-Encoding: quoted-printable
+From: FixMyStreet <division@example.org>
+
+Gr=FCezi External Body,
+
+=D6ffentliche URL: http://www.example.org/report/REPORT_ID
+
+Bei Fragen zu "Z=FCri wie neu" wenden Sie sich bitte an
+gis-zentrum@zuerich.ch.=
+
+
+
+--
+MIME-Version: 1.0
+Content-Type: image/jpeg; name="REPORT_ID.0.jpeg"
+Content-Disposition: inline; filename="REPORT_ID.0.jpeg"
+Content-Transfer-Encoding: base64
+
+/9j/4AAQSkZJRgABAQEASABIAAD/2wBDAAUDBAQEAwUEBAQFBQUGBwwIBwcHBw8LCwkMEQ8SEhEP
+ERETFhwXExQaFRERGCEYGh0dHx8fExciJCIeJBweHx7/2wBDAQUFBQcGBw4ICA4eFBEUHh4eHh4e
+Hh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh7/wAARCABTAAEDAREA
+AhEBAxEB/8QAFwAAAwEAAAAAAAAAAAAAAAAAAAIIB//EAB8QAQAABAcAAAAAAAAAAAAAAAADBAbT
+BxcYVVaUpf/EABcBAQEBAQAAAAAAAAAAAAAAAAAFBgT/xAAgEQEAAAQHAQAAAAAAAAAAAAAAAwQV
+UgECFlNhodGx/9oADAMBAAIRAxEAPwCywAIozyxS5R58tbbujSW33j6zFRj3fGbKbjAGAgAACs9N
+FCbtUfYg2mO1BM25e/V+lQeW3ISo/9k=
+
+----
diff --git a/templates/email/default/test.txt b/templates/email/default/test.txt
index bfa2c1dd3..1acd4b6ca 100644
--- a/templates/email/default/test.txt
+++ b/templates/email/default/test.txt
@@ -1,5 +1,4 @@
Subject: test email ☺
-From: bad-sender@duff.com
Hello,
diff --git a/templates/email/fixamingata/test.txt b/templates/email/fixamingata/test.txt
deleted file mode 100644
index bfa2c1dd3..000000000
--- a/templates/email/fixamingata/test.txt
+++ /dev/null
@@ -1,15 +0,0 @@
-Subject: test email ☺
-From: bad-sender@duff.com
-
-Hello,
-
-This is a test email where foo: [% foo %].
-
-utf8: 我们应该能够无缝处理UTF8编码
-
- indented_text
-
-long line: Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
-
-Yours,
-FixMyStreet.
diff --git a/templates/email/zurich/problem-closed.txt b/templates/email/zurich/problem-closed.txt
index 392004504..b469e74c6 100644
--- a/templates/email/zurich/problem-closed.txt
+++ b/templates/email/zurich/problem-closed.txt
@@ -16,10 +16,6 @@ Ihre Meldung lautet:
-Freundliche Grüsse
-
-Ihre Stadt Zürich
-
Dieses E-Mail wurde automatisch generiert. Bitte antworten Sie nicht darauf.
diff --git a/templates/email/zurich/problem-confirm.txt b/templates/email/zurich/problem-confirm.txt
index b945c6d59..d64d54e8c 100644
--- a/templates/email/zurich/problem-confirm.txt
+++ b/templates/email/zurich/problem-confirm.txt
@@ -2,7 +2,7 @@ Subject: Züri wie neu: Meldung #[% report.id %]
Grüezi [% report.name %]
-Besten Dank für Ihre Meldung auf <<Züri wie neu>>. Klicken Sie bitte auf diesen Link, um Ihre E-Mail-Adresse zu bestätigen und über den Status der Meldung informiert zu bleiben. Falls der Link nicht funktioniert, kopieren Sie ihn in Ihren Browser:
+Besten Dank für Ihre Meldung auf <<Züri wie neu>>. Klicken Sie bitte auf diesen Link, um[% UNLESS email_confirmed %] Ihre E-Mail-Adresse zu bestätigen und[% END %] über den Status der Meldung informiert zu bleiben. Falls der Link nicht funktioniert, kopieren Sie ihn in Ihren Browser:
[% token_url %]
@@ -20,4 +20,6 @@ Freundliche Grüsse
Ihre Stadt Zürich
+
+
Dieses E-Mail wurde automatisch generiert. Bitte antworten Sie nicht darauf.
diff --git a/templates/email/zurich/problem-external.txt b/templates/email/zurich/problem-external.txt
index 09cc9c7ca..5645b0e1e 100644
--- a/templates/email/zurich/problem-external.txt
+++ b/templates/email/zurich/problem-external.txt
@@ -2,8 +2,7 @@ Subject: Züri wie neu: Meldung #[% problem.id %]
Grüezi [% problem.name %]
-Besten Dank für Ihre Meldung auf <<Züri wie neu>>. Wir haben Ihr Anliegen an [% problem.body(c).name %]
-weitergeleitet, da es nicht in den Zuständigkeitsbereich der beteiligten Fachbereiche fällt.
+[% problem.extra.public_response %]
Unter:
[% url %]
@@ -16,11 +15,6 @@ Ihre Meldung lautet:
-Freundliche Grüsse
-
-Ihre Stadt Zürich
-
-
Dieses E-Mail wurde automatisch generiert. Bitte antworten Sie nicht darauf.
diff --git a/templates/email/zurich/problem-rejected.txt b/templates/email/zurich/problem-rejected.txt
index c3d375747..ac02ea19a 100644
--- a/templates/email/zurich/problem-rejected.txt
+++ b/templates/email/zurich/problem-rejected.txt
@@ -2,16 +2,7 @@ Subject: Züri wie neu: Meldung #[% problem.id %]
Grüezi [% problem.name %]
-Ihre Meldung wurde aufgrund des Inhalts zurückgewiesen.
-Dies kann verschiedene Gründe haben wie zum Beispiel unzureichenden, nicht nachvollziehbaren oder diskriminierenden Inhalt.
-
-Bitte geben Sie die Meldung nochmals, mit möglichst detaillierten, sachlichen Informationen ein.
-
-Besten Dank für Ihr Verständnis.
-
-Freundliche Grüsse
-
-Ihre Stadt Zürich
+[% problem.extra.public_response %]
Ihre Meldung lautet:
@@ -19,11 +10,6 @@ Ihre Meldung lautet:
-Freundliche Grüsse
-
-Ihre Stadt Zürich
-
-
Dieses E-Mail wurde automatisch generiert. Bitte antworten Sie nicht darauf.
diff --git a/templates/email/zurich/problem-wish.txt b/templates/email/zurich/problem-wish.txt
new file mode 100644
index 000000000..b7508c316
--- /dev/null
+++ b/templates/email/zurich/problem-wish.txt
@@ -0,0 +1,16 @@
+Subject: Züri wie neu: Meldung #[% problem.id %]
+
+Grüezi [% problem.name %]
+
+[% problem.extra.public_response %]
+
+
+Ihre Meldung lautet:
+
+[% problem.detail %]
+
+
+
+
+Dieses E-Mail wurde automatisch generiert. Bitte antworten Sie nicht darauf.
+
diff --git a/templates/email/zurich/reply-autoresponse.txt b/templates/email/zurich/reply-autoresponse.txt
index 1e79549b3..884ea6dea 100644
--- a/templates/email/zurich/reply-autoresponse.txt
+++ b/templates/email/zurich/reply-autoresponse.txt
@@ -7,4 +7,5 @@ Dies ist eine automatische Antwort auf Ihr E-Mail. Ihr E-Mail wurde nicht überm
Falls Sie eine Meldung erfassen möchten, tun Sie das bitte über die Hauptseite:
[%# link to FMZ %]
+
Falls Sie Fragen zu <<Züri wie neu>> haben, senden Sie ein E-Mail an gis-zentrum@zuerich.ch
diff --git a/templates/email/zurich/submit-external-personal.txt b/templates/email/zurich/submit-external-personal.txt
index 5e0823871..593d047c9 100644
--- a/templates/email/zurich/submit-external-personal.txt
+++ b/templates/email/zurich/submit-external-personal.txt
@@ -2,7 +2,8 @@ Subject: Züri wie neu: Weitergeleitete Meldung #<?=$values['id']?>
Grüezi <?=$values['bodies_name']?>,
-Die folgende Meldung wurde auf http://www.stadt-zuerich.ch/zueriwieneu erfasst:
+<?=$values['external_message']?>
+
Öffentliche URL: <?=$values['url']?>
@@ -12,15 +13,5 @@ Email des Meldenden: <?=$values['email']?>
Telefonnummer des Meldenden: <?=$values['phone']?>
-"Züri wie neu" ist ein Pilotprojekt der Stadt Zürich zum Thema
-Bürgerbeteiligung. Auf dieser Plattform kann die Bevölkerung auf Schäden und
-Mängel an der städtischen Infrastruktur hinweisen. Diese Meldung wurde Ihnen
-von der Stadt Zürich gesendet, da es Ihr Zuständigkeitsgebiet betreffen könnte.
-
-Bei Fragen zum Pilotprojekt "Züri wie neu" wenden Sie sich bitte an
-gis-zentrum@zuerich.ch.
-
-
-Freundliche Grüsse
-Ihre Stadt Zürich
+Bei Fragen zu "Züri wie neu" wenden Sie sich bitte an gis-zentrum@zuerich.ch. \ No newline at end of file
diff --git a/templates/email/zurich/submit-external-wish.txt b/templates/email/zurich/submit-external-wish.txt
new file mode 100644
index 000000000..ec472f95f
--- /dev/null
+++ b/templates/email/zurich/submit-external-wish.txt
@@ -0,0 +1,20 @@
+Subject: Züri wie neu: Weitergeleitete Meldung #<?=$values['id']?>
+
+Grüezi <?=$values['bodies_name']?>,
+
+<?=$values['external_message']?>
+
+
+Name des Meldenden: <?=$values['name']?>
+
+Email des Meldenden: <?=$values['email']?>
+
+Telefonnummer des Meldenden: <?=$values['phone']?>
+
+Meldung: <?=$values['detail']?>
+
+Standort in AV-Online anzeigen:
+http://webgis.intra.stzh.ch/AV_Online/Direct.asp?Map=AV&Search=Koord&West=<?=$values['west']?>&Nord=<?=$values['nord']?>&B=300
+
+
+Bei Fragen zu "Züri wie neu" wenden Sie sich bitte an gis-zentrum@zuerich.ch.
diff --git a/templates/email/zurich/submit-external.txt b/templates/email/zurich/submit-external.txt
index bf409dccc..d85c2f84f 100644
--- a/templates/email/zurich/submit-external.txt
+++ b/templates/email/zurich/submit-external.txt
@@ -2,19 +2,10 @@ Subject: Züri wie neu: Weitergeleitete Meldung #<?=$values['id']?>
Grüezi <?=$values['bodies_name']?>,
-Die folgende Meldung wurde auf http://www.stadt-zuerich.ch/zueriwieneu erfasst:
+<?=$values['external_message']?>
-Öffentliche URL: <?=$values['url']?>
-
-"Züri wie neu" ist eine Dienstleistung der Stadt Zürich zum Thema
-Bürgerbeteiligung. Auf dieser Plattform kann die Bevölkerung auf Schäden und
-Mängel an der städtischen Infrastruktur hinweisen.
-Diese Meldung wurde Ihnen von der Stadt Zürich gesendet, da es Ihr
-Zuständigkeitsgebiet betreffen könnte.
-
-Bei Fragen zu "Züri wie neu" wenden Sie sich bitte an gis-zentrum@zuerich.ch.
+Öffentliche URL: <?=$values['url']?>
-Freundliche Grüsse
-Ihre Stadt Zürich
+Bei Fragen zu "Züri wie neu" wenden Sie sich bitte an gis-zentrum@zuerich.ch. \ No newline at end of file
diff --git a/templates/web/base/admin/category_edit.html b/templates/web/base/admin/category_edit.html
index b827a4b6d..c0bd43ef5 100644
--- a/templates/web/base/admin/category_edit.html
+++ b/templates/web/base/admin/category_edit.html
@@ -43,6 +43,9 @@
[% IF c.cobrand.moniker != 'zurich' %]
<input type="checkbox" name="non_public" value="1" id="non_public"[% ' checked' IF contact.non_public %]>
<label class="inline" for="non_public">[% loc('Private') %]</label>
+ [% ELSE %]
+ <input type="checkbox" name="photo_required" value="1" id="photo_required"[% ' checked' IF contact.get_extra_metadata('photo_required') %]>
+ <label class="inline" for="photo_required">[% loc('Photo required') %]</label>
[% END %]
</p>
diff --git a/templates/web/base/auth/general.html b/templates/web/base/auth/general.html
index 7efef4f6b..6e1db86fe 100644
--- a/templates/web/base/auth/general.html
+++ b/templates/web/base/auth/general.html
@@ -25,7 +25,7 @@
[% 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') %]">
+ <input type="email" class="required email" id="email" name="email" value="[% email | html %]" placeholder="[% loc('Your email address') %]" autofocus>
<div id="form_sign_in">
<h3>[% tprintf(loc("Do you have a %s password?", "%s is the site name"), site_name) %]</h3>
diff --git a/templates/web/base/maps/noscript_map.html b/templates/web/base/maps/noscript_map.html
new file mode 100644
index 000000000..aaaa217c9
--- /dev/null
+++ b/templates/web/base/maps/noscript_map.html
@@ -0,0 +1,64 @@
+<div class="noscript">
+ <div id="[% nsm_prefix %]drag">
+ <[% map.img_type %]
+ alt="NW map tile" id="[% nsm_prefix %]t2.2"
+ name="tile_[% map.x_tile - 1 %].[% map.y_tile - 1 %]"
+ src="[% map.tiles.0 %]"
+ style="top:0; left:0;">
+ <[% map.img_type %]
+ alt="NE map tile" id="[% nsm_prefix %]t2.3"
+ name="tile_[% map.x_tile %].[% map.y_tile - 1 %]"
+ src="[% map.tiles.1 %]"
+ style="top:0px; left:256px;">
+ <br>
+ <[% map.img_type %]
+ alt="SW map tile" id="[% nsm_prefix %]t3.2"
+ name="tile_[% map.x_tile - 1 %].[% map.y_tile %]"
+ src="[% map.tiles.2 %]"
+ style="top:256px; left:0;">
+ <[% map.img_type %]
+ alt="SE map tile" id="[% nsm_prefix %]t3.3"
+ name="tile_[% map.x_tile %].[% map.y_tile %]"
+ src="[% map.tiles.3 %]"
+ style="top:256px; left:256px;">
+ </div>
+ <div id="[% nsm_prefix %]pins">[% FOR pin IN map.pins %][% INCLUDE pin %][% END %]</div>
+ [% INCLUDE compass %]
+</div>
+
+[% BLOCK compass %]
+[%
+ north = c.uri_with( { lat = map.compass.north.0, lon = map.compass.north.1, zoom = map.zoom } )
+ south = c.uri_with( { lat = map.compass.south.0, lon = map.compass.south.1, zoom = map.zoom } )
+ east = c.uri_with( { lat = map.compass.east.0, lon = map.compass.east.1, zoom = map.zoom } )
+ west = c.uri_with( { lat = map.compass.west.0, lon = map.compass.west.1, zoom = map.zoom } )
+ world = c.uri_with( { zoom = 0 } );
+ SET zoom_in = c.uri_with( { lat = map.latitude, lon = map.longitude, zoom = map.zoom + 1 } ) IF map.zoom < map.numZoomLevels - 1;
+ SET zoom_out = c.uri_with( { lat = map.latitude, lon = map.longitude, zoom = map.zoom - 1 } ) IF map.zoom > 0;
+ SET zoom_in = '#' IF map.zoom >= map.numZoomLevels - 1;
+ SET zoom_out = '#' IF map.zoom <= 0;
+%]
+<div style="position: absolute; left: 4px; top: 4px;" class="olControlPanZoom olControlNoSelect" unselectable="on">
+ <div style="position: absolute; left: 13px; top: 4px; width: 18px; height: 18px;"><a rel="nofollow" href="[% north %]"><img style="position: relative; width: 18px; height: 18px;" src="/js/OpenLayers-2.13.1/img/north-mini.png" border="0"></a></div>
+ <div style="position: absolute; left: 4px; top: 22px; width: 18px; height: 18px;"><a rel="nofollow" href="[% west %]"><img style="position: relative; width: 18px; height: 18px;" src="/js/OpenLayers-2.13.1/img/west-mini.png" border="0"></a></div>
+ <div style="position: absolute; left: 22px; top: 22px; width: 18px; height: 18px;"><a rel="nofollow" href="[% east %]"><img style="position: relative; width: 18px; height: 18px;" src="/js/OpenLayers-2.13.1/img/east-mini.png" border="0"></a></div>
+ <div style="position: absolute; left: 13px; top: 40px; width: 18px; height: 18px;"><a rel="nofollow" href="[% south %]"><img style="position: relative; width: 18px; height: 18px;" src="/js/OpenLayers-2.13.1/img/south-mini.png" border="0"></a></div>
+ <div style="position: absolute; left: 13px; top: 63px; width: 18px; height: 18px;"><a rel="nofollow" href="[% zoom_in %]"><img style="position: relative; width: 18px; height: 18px;" src="/js/OpenLayers-2.13.1/img/zoom-plus-mini.png" border="0"></a></div>
+ <div style="position: absolute; left: 13px; top: 81px; width: 18px; height: 18px;"><a rel="nofollow" href="[% world %]"><img style="position: relative; width: 18px; height: 18px;" src="/js/OpenLayers-2.13.1/img/zoom-world-mini.png" border="0"></a></div>
+ <div style="position: absolute; left: 13px; top: 99px; width: 18px; height: 18px;"><a rel="nofollow" href="[% zoom_out %]"><img style="position: relative; width: 18px; height: 18px;" src="/js/OpenLayers-2.13.1/img/zoom-minus-mini.png" border="0"></a></div>
+</div>
+[% END %]
+
+
+[% BLOCK pin %]
+
+[% IF pin.id %]
+<a title="[% pin.title | html %]" href="[% c.uri_for('/report/' _ pin.id) %]">
+[%- END -%]
+<img border="0" class="pin" src="[% c.uri_for( c.cobrand.path_to_pin_icons _ 'pin-' _ pin.colour _ '.png') %]"
+ alt="[% loc('Problem') %]" style="top:[% pin.py - 64 %]px; left:[% pin.px - 24 %]px; position: absolute;">
+[%- IF pin.id -%]
+</a>
+[% END %]
+
+[% END %]
diff --git a/templates/web/base/maps/openlayers.html b/templates/web/base/maps/openlayers.html
index 1d0f88166..1e7ae5ce8 100644
--- a/templates/web/base/maps/openlayers.html
+++ b/templates/web/base/maps/openlayers.html
@@ -30,65 +30,10 @@ var fixmystreet = {
</script>
<div id="map_box" aria-hidden="true">
[% pre_map %]
- <div id="map"><noscript>
- <div id="drag"><[% map.img_type %]
- alt="NW map tile" id="t2.2"
- name="tile_[% map.x_tile - 1 %].[% map.y_tile - 1 %]"
- src="[% map.tiles.0 %]"
- style="top:0; left:0;"><[% map.img_type %]
- alt="NE map tile" id="t2.3"
- name="tile_[% map.x_tile %].[% map.y_tile - 1 %]"
- src="[% map.tiles.1 %]"
- style="top:0px; left:256px;"><br><[% map.img_type %]
- alt="SW map tile" id="t3.2"
- name="tile_[% map.x_tile - 1 %].[% map.y_tile %]"
- src="[% map.tiles.2 %]"
- style="top:256px; left:0;"><[% map.img_type %]
- alt="SE map tile" id="t3.3"
- name="tile_[% map.x_tile %].[% map.y_tile %]"
- src="[% map.tiles.3 %]"
- style="top:256px; left:256px;"></div>
- <div id="pins">[% FOR pin IN map.pins %][% INCLUDE pin %][% END %]</div>
- [% INCLUDE compass %]
- </noscript></div>
+ <div id="map">
+ [% INCLUDE 'maps/noscript_map.html' %]
+ </div>
[% IF map.copyright %]
<div class="olControlAttribution" style="position: absolute;">[% map.copyright %]</div>
[% END %]
-
-[% BLOCK compass %]
-[%
- north = c.uri_with( { lat = map.compass.north.0, lon = map.compass.north.1, zoom = map.zoom } )
- south = c.uri_with( { lat = map.compass.south.0, lon = map.compass.south.1, zoom = map.zoom } )
- east = c.uri_with( { lat = map.compass.east.0, lon = map.compass.east.1, zoom = map.zoom } )
- west = c.uri_with( { lat = map.compass.west.0, lon = map.compass.west.1, zoom = map.zoom } )
- world = c.uri_with( { zoom = 0 } );
- SET zoom_in = c.uri_with( { lat = map.latitude, lon = map.longitude, zoom = map.zoom + 1 } ) IF map.zoom < map.numZoomLevels - 1;
- SET zoom_out = c.uri_with( { lat = map.latitude, lon = map.longitude, zoom = map.zoom - 1 } ) IF map.zoom > 0;
- SET zoom_in = '#' IF map.zoom >= map.numZoomLevels - 1;
- SET zoom_out = '#' IF map.zoom <= 0;
-%]
-<div style="position: absolute; left: 4px; top: 4px;" class="olControlPanZoom olControlNoSelect" unselectable="on">
- <div style="position: absolute; left: 13px; top: 4px; width: 18px; height: 18px;"><a rel="nofollow" href="[% north %]"><img style="position: relative; width: 18px; height: 18px;" src="/js/OpenLayers-2.13.1/img/north-mini.png" border="0"></a></div>
- <div style="position: absolute; left: 4px; top: 22px; width: 18px; height: 18px;"><a rel="nofollow" href="[% west %]"><img style="position: relative; width: 18px; height: 18px;" src="/js/OpenLayers-2.13.1/img/west-mini.png" border="0"></a></div>
- <div style="position: absolute; left: 22px; top: 22px; width: 18px; height: 18px;"><a rel="nofollow" href="[% east %]"><img style="position: relative; width: 18px; height: 18px;" src="/js/OpenLayers-2.13.1/img/east-mini.png" border="0"></a></div>
- <div style="position: absolute; left: 13px; top: 40px; width: 18px; height: 18px;"><a rel="nofollow" href="[% south %]"><img style="position: relative; width: 18px; height: 18px;" src="/js/OpenLayers-2.13.1/img/south-mini.png" border="0"></a></div>
- <div style="position: absolute; left: 13px; top: 63px; width: 18px; height: 18px;"><a rel="nofollow" href="[% zoom_in %]"><img style="position: relative; width: 18px; height: 18px;" src="/js/OpenLayers-2.13.1/img/zoom-plus-mini.png" border="0"></a></div>
- <div style="position: absolute; left: 13px; top: 81px; width: 18px; height: 18px;"><a rel="nofollow" href="[% world %]"><img style="position: relative; width: 18px; height: 18px;" src="/js/OpenLayers-2.13.1/img/zoom-world-mini.png" border="0"></a></div>
- <div style="position: absolute; left: 13px; top: 99px; width: 18px; height: 18px;"><a rel="nofollow" href="[% zoom_out %]"><img style="position: relative; width: 18px; height: 18px;" src="/js/OpenLayers-2.13.1/img/zoom-minus-mini.png" border="0"></a></div>
-</div>
-[% END %]
-
-
-[% BLOCK pin %]
-
-[% IF pin.id %]
-<a title="[% pin.title | html %]" href="[% c.uri_for('/report/' _ pin.id) %]">
-[%- END -%]
-<img border="0" class="pin" src="[% c.uri_for( c.cobrand.path_to_pin_icons _ 'pin-' _ pin.colour _ '.png') %]"
- alt="[% loc('Problem') %]" style="top:[% pin.py - 64 %]px; left:[% pin.px - 24 %]px; position: absolute;">
-[%- IF pin.id -%]
-</a>
-[% END %]
-
-[% END %]
diff --git a/templates/web/base/report/new/category_extras.html b/templates/web/base/report/new/category_extras.html
index c0f6a7bae..12ef1486f 100644
--- a/templates/web/base/report/new/category_extras.html
+++ b/templates/web/base/report/new/category_extras.html
@@ -6,7 +6,7 @@
[%- END %]
[%- IF report_meta %]
- <h4>Additional Information</h4>
+ <h4>[% loc('Additional Information') %]</h4>
[%- FOR meta IN category_extras.$category %]
[%- meta_name = meta.code -%]
diff --git a/templates/web/base/report/photo.html b/templates/web/base/report/photo.html
index c463c34c4..094f677d8 100644
--- a/templates/web/base/report/photo.html
+++ b/templates/web/base/report/photo.html
@@ -1,8 +1,21 @@
[% IF c.cobrand.allow_photo_display(object) && object.photo %]
-[% photo = object.get_photo_params %]
-<div class="update-img">
- [% IF photo.url_full %]<a href="[% photo.url_full %]" rel="fancy">[% END
- %]<img alt="Photo of this report" [% IF photo.height %]height="[% photo.height %]" width="[% photo.width %]"[% END %] src="[% photo.url %]">
- [%- IF photo.url_full %]<span>zoom</span></a>[% END %]
-</div>
+ [% IF object.can('get_photoset') %]
+ [% FOR photo IN object.get_photoset(c).images %]
+ <div class="update-img">
+ <a href="[% c.cobrand.base_url %]/photo/[% object.id %].[% loop.index %].full.jpeg?[% photo.0 %]" rel="fancy">
+ <img alt="Photo of this report" src="[% c.cobrand.base_url %]/photo/[% object.id %].[% loop.index %].jpeg?[% photo.0 %]">
+ <span>zoom</span></a>
+ </div>
+ [% END %]
+ [% ELSE %]
+ [%# e.g. comments %]
+ [% photo = object.get_photo_params %]
+ <div class="update-img">
+ [% IF photo.url_full %]<a href="[% photo.url_full %]" rel="fancy">[% END %]
+ <img alt="Photo of this report"
+ [%- IF photo.height %]height="[% photo.height %]" width="[% photo.width %]"[% END -%]
+ src="[% photo.url %]">
+ [%- IF photo.url_full %]<span>zoom</span></a>[% END %]
+ </div>
+ [% END %]
[% END %]
diff --git a/templates/web/zurich/admin/body-form.html b/templates/web/zurich/admin/body-form.html
index a31dffe7c..ac2887159 100644
--- a/templates/web/zurich/admin/body-form.html
+++ b/templates/web/zurich/admin/body-form.html
@@ -48,6 +48,7 @@
<p>
<input type="hidden" name="posted" value="body">
<input type="hidden" name="token" value="[% token %]">
+ <p>
<input type="submit" value="[% body ? loc('Update body') : loc('Add body') %]">
</p>
</form>
diff --git a/templates/web/zurich/admin/header.html b/templates/web/zurich/admin/header.html
index 281b1de23..929df8352 100644
--- a/templates/web/zurich/admin/header.html
+++ b/templates/web/zurich/admin/header.html
@@ -9,16 +9,20 @@
'planned' = loc('Planned'),
'fixed - council' = loc('Closed'),
'hidden' = loc('Hidden'),
- 'closed' = loc('Closed'),
+ 'closed' = loc('Extern'),
+ 'partial' = loc('Not contactable'),
+ 'investigating' = loc('Wish'),
+ 'unable to fix' = loc('Jurisdiction unknown'),
+ 'fixed - council' = loc('Closed'),
}
%]
<style type="text/css">
.adminhidden { color: #666666; }
- .admininternal { background-color: #eeeeff; }
.active { background-color: #ffffee; cursor: pointer; }
.error { color: red; }
.overdue { background-color: #ffcccc; }
select { width: auto; }
+ .admin-report-edit select { max-width: 100%; }
#fms_pan_zoom { top: 13em !important; }
</style>
<script>
diff --git a/templates/web/zurich/admin/list_updates.html b/templates/web/zurich/admin/list_updates.html
index 2b575f27e..bde28567b 100644
--- a/templates/web/zurich/admin/list_updates.html
+++ b/templates/web/zurich/admin/list_updates.html
@@ -1,45 +1,49 @@
[% IF updates.size %]
-<h2>[% loc('Internal notes') %]</h3>
-
-<table cellspacing="0" cellpadding="2" border="1">
- <tr>
- <th>[% loc('ID') %]</th>
- <th>[% loc('Created') %]</th>
- <th>[% loc('User') %]</th>
- <th>[% loc('Text') %]</th>
- </tr>
-[% FOREACH update IN updates -%]
- [% IF update.extra.is_internal_note %]
- <tr class="[% 'admininternal' IF update.extra.is_internal_note %]">
- <td>[% update.id %]</td>
- <td>[% PROCESS format_date this_date=update.created %] [% update.created.hms %]</td>
- <td><a href="mailto:[% update.user.email %]">[% update.user.name || update.user.email %]</a></td>
- <td>[% update.text | html %]</td>
- </tr>
- [% END %]
-[% END -%]
-</table>
-
-<h2>[% loc('Updates') %]</h2>
-
-<table cellspacing="0" cellpadding="2" border="1">
- <tr>
- <th>[% loc('ID') %]</th>
- <th>[% loc('Created') %]</th>
- <th>[% loc('User') %]</th>
- <th>[% loc('Text') %]</th>
- </tr>
-[% FOREACH update IN updates -%]
- [% IF ! update.extra.is_internal_note %]
- <tr class="[% 'adminhidden' IF update.state == 'hidden' || update.problem.state == 'hidden' %]">
- <td>[% update.id %]</td>
- <td>[% PROCESS format_date this_date=update.created %] [% update.created.hms %]</td>
- <td><a href="mailto:[% update.user.email %]">[% update.user.name || update.user.email %]</a></td>
- <td>[% update.text | html %]</td>
- </tr>
- [% END %]
-[% END -%]
-</table>
+[%# We assume internal notes are lowest priority, and thus displayed last.
+ All other updates (eg: "I've done this work, here's what you should tell
+ the citizen") are displayed first. %]
+
+[% internal_updates=[];
+ sdm_notes=[];
+ FOREACH update IN updates;
+ IF NOT update.extra.is_external_message;
+ IF update.extra.is_internal_note;
+ internal_updates.unshift(update);
+ ELSE;
+ sdm_notes.unshift(update);
+ END;
+ END;
+ END
+%]
+
+[% IF sdm_notes.size %]
+ <h2>[% loc('Notes from SDM to DM') %]</h2>
+
+ [% FOREACH update IN sdm_notes -%]
+ <div class="admin-note [% 'adminhidden' IF update.state == 'hidden' || update.problem.state == 'hidden' %]" title="[% loc('ID') %]: [% update.id %]">
+ <p class="admin-note__text">[% update.text | html %]</p>
+ <p class="admin-note__creator">
+ <a href="mailto:[% update.user.email %]">[% update.user.name || update.user.email %]</a>
+ &middot; [% PROCESS format_date this_date=update.created %] [% update.created.hms %]
+ </p>
+ </div>
+ [% END -%]
+[% END %]
+
+[% IF internal_updates.size %]
+ <h2>[% loc('Internal notes') %]</h2>
+
+ [% FOREACH update IN internal_updates -%]
+ <div class="admin-note admininternal" title="[% loc('ID') %]: [% update.id %]">
+ <p class="admin-note__text">[% update.text | html %]</p>
+ <p class="admin-note__creator">
+ <a href="mailto:[% update.user.email %]">[% update.user.name || update.user.email %]</a>
+ &middot; [% PROCESS format_date this_date=update.created %] [% update.created.hms %]
+ </p>
+ </div>
+ [% END -%]
+
+[% END %]
[% END %]
diff --git a/templates/web/zurich/admin/problem_row.html b/templates/web/zurich/admin/problem_row.html
index 9b395a1ac..baa8d3ac7 100644
--- a/templates/web/zurich/admin/problem_row.html
+++ b/templates/web/zurich/admin/problem_row.html
@@ -18,7 +18,9 @@
<td>[% PROCESS value_or_nbsp value=problem.category %]</td>
<td>[% PROCESS format_date this_date=problem.created %]</td>
<td>[% PROCESS format_date this_date=problem.lastupdate %]</td>
- <td>[% states.${problem.state} %]</td>
+ <td> [% states.${problem.state} %][% IF problem.state == 'planned';
+ SET cs=problem.get_extra_metadata('closure_status');
+ IF cs %] ([% states.$cs %]) [% END; END %]</td>
[% IF include_subdiv %]
<td>
@@ -34,7 +36,11 @@
<td>
[% IF problem.photo %]
- <img class="img" height="60" width="90" src="[% c.cobrand.base_url %]/photo/[% problem.photo %].temp.jpeg" alt="">
+ [% FOR photo IN problem.get_photoset(c).images %]
+ <div class="update-img">
+ <img height="60" width="90" alt="" src="[% c.cobrand.base_url %]/photo/[% photo.0 %].temp.jpeg">
+ </div>
+ [% END %]
[% END %]
</td>
diff --git a/templates/web/zurich/admin/report_edit-sdm.html b/templates/web/zurich/admin/report_edit-sdm.html
index 82bbeba23..8e576a718 100644
--- a/templates/web/zurich/admin/report_edit-sdm.html
+++ b/templates/web/zurich/admin/report_edit-sdm.html
@@ -1,4 +1,5 @@
[%
+ PROCESS "report/photo-js.html";
PROCESS "maps/zurich.html";
PROCESS 'admin/header.html'
title = tprintf(loc('Editing problem %d'), problem.id ),
@@ -9,63 +10,141 @@
[% map_html %]
</div>
-[% status_message %]
-
<form method="post" action="[% c.uri_for( 'report_edit', problem.id ) %]" enctype="application/x-www-form-urlencoded" accept-charset="utf-8">
<input type="hidden" name="token" value="[% token %]" >
<input type="hidden" name="submit" value="1" >
-<p align="right"><input type="submit" name="send_back" value="[% loc('Not for my subdivision') %]"></p>
-
-<ul class="no-bullets">
-<li><a href="[% c.uri_for_email( '/report', problem.id ) %]">[% loc('View report on site' )%]</a></li>
-
-<li><a href="http://webgis.intra.stzh.ch/AV_Online/Direct.asp?Map=AV&Search=Koord&West=[% problem.local_coords.0 %]&Nord=[% problem.local_coords.1 %]&B=300" target="_blank">Standort in AV-Online anzeigen</a></li>
-
-<li><span class="mock-label">[% loc('Details:') %]</span> [% problem.detail | html %]
-[% IF problem.extra.original_detail %]
-<br>[%
- SET safe = problem.extra.original_detail | html;
- tprintf( loc('originally entered: &ldquo;%s&rdquo;'), safe )
-%]
-[% END %]
-</li>
-<li><span class="mock-label">[% loc('Co-ordinates:') %]</span> [% problem.local_coords.join(',') %]
- <input type="hidden" name="latitude" id="fixmystreet.latitude" value="[% problem.latitude %]">
- <input type="hidden" name="longitude" id="fixmystreet.longitude" value="[% problem.longitude %]">
-([%
- SET safe = problem.postcode | html;
- tprintf( loc('originally entered: &ldquo;%s&rdquo;'), safe )
-%],
-[% IF problem.used_map %][% loc('used map') %][% ELSE %][% loc("didn't use map") %][% END %])</li>
-
-<li><span class="mock-label">[% loc('Category:') %]</span> [% problem.category | html %] </li>
-<li><span class="mock-label">[% loc('Name:') %]</span> [% problem.name | html %]
-<li><span class="mock-label">[% loc('Email:') %]</span> [% problem.user.email | html %]
-[% IF NOT problem.extra.email_confirmed %]<span class="error">[% loc('Unconfirmed') %]</span>[% END %]
-<li><span class="mock-label">[% loc('Phone:') %]</span> [% IF problem.user.phone %][% problem.user.phone | html %][% ELSE %]<em>[% loc('None') %]</em>[% END %]</li>
-<li><span class="mock-label">[% loc('Created:') %]</span> [% PROCESS format_date this_date=problem.created %] [% problem.created.hms %]</li>
-
-[% IF problem.photo %]
-<li><img alt="" src="[% c.cobrand.base_url %]/photo/[% problem.photo %].temp.jpeg"></li>
-[% END %]
-
-<li><span class="mock-label">[% loc('State:') %]</span> [% states.${problem.state} %]</li>
-
-<li><label for="new_internal_note">[% loc('New internal note:') %]</label>
-<textarea name='new_internal_note' id='new_internal_note' cols=60 rows=5></textarea></li>
-
-<li><label for="status_update">[% loc('New update:') %]</label>
-<textarea name='status_update' id='status_update' cols=60 rows=5></textarea></li>
+<div class="admin-report-edit admin-report-edit--details">
+
+<dl>
+
+ <dd class="screen-only">&raquo; <a href="[% c.uri_for_email( '/report', problem.id ) %]">[% loc('View report on site' )%]</a></dd>
+
+ <dd class="screen-only">&raquo; <a href="http://webgis.intra.stzh.ch/AV_Online/Direct.asp?Map=AV&amp;Search=Koord&amp;West=[% problem.local_coords.0 %]&amp;Nord=[% problem.local_coords.1 %]&amp;B=300" target="_blank">Standort in AV-Online anzeigen</a></dd>
+
+ <dd class="screen-only">&raquo; <a href="http://webgis.intra.stzh.ch/stapo/GoogleStreetView.asp?lat=[% problem.latitude %]&amp;lon=[% problem.longitude %]" target="_blank">[% loc('Street View') %]</a></dd>
+
+ <dt><span class="mock-label">[% loc('Details:') %]</span></dt>
+ <dd>[% problem.detail | html %]</dd>
+ [% IF problem.extra.original_detail %]
+ <dd>[%
+ SET safe = problem.extra.original_detail | html;
+ tprintf( loc('originally entered: &ldquo;%s&rdquo;'), safe )
+ %]</dd>
+ [% END %]
+
+ <dt class="print-only">[% loc('Reported:') %] <!-- Meldedatum --></dt>
+ <dd class="screen-no-space-after">
+ <strong>[% PROCESS format_date this_date=problem.created %] [% problem.created.hms %]</strong>
+ </dd>
+ <dt class="print-only">[% loc('Coordinates:') %] <!-- Koordinaten --></dt>
+ <dd class="screen-no-space-after print-no-space-after">
+ [% problem.local_coords.join(',') %]
+ <input type="hidden" name="latitude" id="fixmystreet.latitude" value="[% problem.latitude %]">
+ <input type="hidden" name="longitude" id="fixmystreet.longitude" value="[% problem.longitude %]">
+ </dd>
+ <dd class="screen-no-space-after print-no-space-after">
+ [% IF problem.used_map %]
+ [% loc('Used map') %]
+ [% ELSE %]
+ [% loc("Didn't use map") %]
+ [% END %]
+ </dd>
+ <dd>[%
+ SET safe = problem.postcode | html;
+ tprintf( loc('originally entered: &ldquo;%s&rdquo;'), safe )
+ %]</dd>
+
+ <dt class="print-only">[% loc('Reported by:') %] <!-- Meldende Person --></dt>
+ <dd>
+ <strong>[% IF problem.name %][% problem.name | html %][% ELSE %][% loc('(No name)') %][% END %]</strong>
+ <input type='hidden' name='name' id='name' value='[% problem.name | html %]'>
+ <br>
+ [% problem.user.email | html %]
+ [% IF NOT problem.extra.email_confirmed %]<span class="error">[% loc('Unconfirmed') %]</span>[% END %]
+ <input type='hidden' id='email' name='email' value='[% problem.user.email | html %]'>
+ <br>
+ [% IF problem.user.phone %][% problem.user.phone | html %][% ELSE %]<em>[% loc('(No phone number)') %]</em>[% END %]
+ </dd>
+
+ <dt>[% loc('Category:') %] <!-- Kategorie --></dt>
+ <dd>[% problem.category | html %]</dd>
+
+ <dt class="print-only">[% loc('State:') %] <!-- Status --></dt>
+ <dd class="print-only">[% states.${problem.state} %]</dd>
+
+ <dt>[% loc('Time spent (in minutes):') %]</dt>
+ <dd>[% problem.get_time_spent %]</dd>
+
+ <dd>
+ [% status_message %]
+ </dd>
+
+ [% IF problem.photo %]
+ <dd>
+ [% FOR photo IN problem.get_photoset(c).images %]
+ <div class="update-img">
+ <a href="[% c.cobrand.base_url %]/photo/[% photo.0 %].fulltemp.jpeg" rel="fancy">
+ <img alt="Photo of this report" src="[% c.cobrand.base_url %]/photo/[% photo.0 %].temp.jpeg">
+ <span>zoom</span>
+ </a>
+ </div>
+ [% END %]
+ </dd>
+ [% END %]
+
+</dl>
+
+</div>
+<div class="admin-report-edit admin-report-edit--interact">
+
+<script type="text/javascript">
+ $(function(){
+ $('#map_box .noscript').clone().removeClass('noscript').addClass('map_clone print-only').prependTo('.admin-report-edit--interact');
+ });
+</script>
+
+<p align="right" class="screen-only"><input type="submit" name="send_back" value="[% loc('Not for my subdivision') %]"></p>
+<p align="right" class="screen-only"><input type="submit" name="not_contactable" value="[% loc('Customer not contactable') %]"></p>
+
+<ul class="no-bullets screen-only">
+ <li>
+ <label for="new_internal_note">[% loc('New internal note:') %]</label>
+ <textarea name='new_internal_note' id='new_internal_note' cols=60 rows=4></textarea>
+ </li>
+ <li>
+ <label for="status_update">[% loc('New note to DM:') %]</label>
+ <textarea name='status_update' id='status_update' cols=60 rows=4></textarea>
+ </li>
</ul>
-<p class="cf">
+<p class="screen-only">
+ <label for="time_spent">[% loc('Time spent (in minutes):') %]</label>
+ <input type="text" name="time_spent" id="form_time_spent" style="width: 4em" value="0">
+ <script>
+ $(function () {
+ $('#form_time_spent').spinner({
+ spin: function (e, ui) {
+ if (ui.value < 0) { return false }
+ }
+ });
+ });
+ </script>
+</p>
+
+<p class="cf screen-only">
<input style="float:left" type="submit" name="Submit changes" value="[% loc('Submit changes') %]" >
<input style="float:right" type="submit" name="no_more_updates" value="[% loc('No further updates') %]">
</p>
-</form>
[% INCLUDE 'admin/list_updates.html' %]
+</div>
+</form>
+
+<div id="print_report_map" class="print-only">
+[% INCLUDE 'maps/noscript_map.html' map=print_report_map nsm_prefix="large_" %]
+</div>
+
[% INCLUDE 'admin/footer.html' %]
diff --git a/templates/web/zurich/admin/report_edit.html b/templates/web/zurich/admin/report_edit.html
index 5376d77f4..64d0950ee 100644
--- a/templates/web/zurich/admin/report_edit.html
+++ b/templates/web/zurich/admin/report_edit.html
@@ -10,160 +10,312 @@
[% map_html %]
</div>
-[% status_message %]
+[% pstate = problem.get_extra_metadata('closure_status') || problem.state %]
-<form method="post" action="[% c.uri_for( 'report_edit', problem.id ) %]" enctype="application/x-www-form-urlencoded" accept-charset="utf-8">
+<form id="report_edit" method="post" action="[% c.uri_for( 'report_edit', problem.id ) %]" enctype="application/x-www-form-urlencoded" accept-charset="utf-8">
<input type="hidden" name="token" value="[% token %]" >
<input type="hidden" name="submit" value="1" >
-<ul class="no-bullets">
-<li><a href="[% c.uri_for_email( '/report', problem.id ) %]">[% loc('View report on site' )%]</a></li>
+<div class="admin-report-edit admin-report-edit--details">
+
+<dl>
+ <dd class="screen-only">&raquo; <a href="[% c.uri_for_email( '/report', problem.id ) %]">[% loc('View report on site' )%]</a></dd>
-<li><a href="http://webgis.intra.stzh.ch/AV_Online/Direct.asp?Map=AV&Search=Koord&West=[% problem.local_coords.0 %]&Nord=[% problem.local_coords.1 %]&B=300" target="_blank">Standort in AV-Online anzeigen</a></li>
+ <dd class="screen-only">&raquo; <a href="http://webgis.intra.stzh.ch/AV_Online/Direct.asp?Map=AV&amp;Search=Koord&amp;West=[% problem.local_coords.0 %]&amp;Nord=[% problem.local_coords.1 %]&amp;B=300" target="_blank">Standort in AV-Online anzeigen</a></dd>
-[% IF problem.state == 'fixed - council' OR problem.state == 'closed' %]
- <li><span class="mock-label">[% loc('Details:') %]</span> [% problem.detail | html %]
+ <dd class="screen-only">&raquo; <a href="http://webgis.intra.stzh.ch/stapo/GoogleStreetView.asp?lat=[% problem.latitude %]&amp;lon=[% problem.longitude %]" target="_blank">[% loc('Street View') %]</a></dd>
+
+ [% IF c.cobrand.problem_is_closed(problem) %]
+ <dt><span class="mock-label">[% loc('Details:') %]</span></dt>
+ <dd>[% problem.detail | html %]</dd>
[% IF problem.extra.original_detail %]
- <br>[%
- SET detail_safe = problem.extra.original_detail | html;
- tprintf( loc('originally entered: &ldquo;%s&rdquo;'), detail_safe )
- %]
+ <dd>[%
+ SET detail_safe = problem.extra.original_detail | html;
+ tprintf( loc('originally entered: &ldquo;%s&rdquo;'), detail_safe )
+ %]</dd>
[% END %]
- </li>
-[% ELSE %]
- <li><label for='title'>[% loc('Subject:') %]</label> <input size=60 type='text' id='title' name='title' value='[% problem.title | html %]'></li>
- <li><label for='detail'>[% loc('Details:') %]</label>
- <textarea name='detail' id='detail' cols=60 rows=5>[% problem.detail | html %]</textarea>
+ [% ELSE %]
+
+ <dt><label for='title'>[% loc('Subject:') %]</label></dt>
+ <dd class="screen-only"><input size=60 type='text' id='title' name='title' value='[% problem.title | html %]'></dd>
+ <dd class="print-only">[% problem.title | html %]</dd>
+
+ <dt><label for='detail'>[% loc('Details:') %]</label></dt>
+ <dd class="screen-only"><textarea name='detail' id='detail' cols=60 rows=4>[% problem.detail | html %]</textarea></dd>
+ <dd class="print-only">[% problem.detail | html %]</dd>
+
[% IF problem.extra.original_detail %]
- [%
- SET detail_safe = problem.extra.original_detail | html;
- tprintf( loc('originally entered: &ldquo;%s&rdquo;'), detail_safe )
- %]
+ <dd>[%
+ SET detail_safe = problem.extra.original_detail | html;
+ tprintf( loc('originally entered: &ldquo;%s&rdquo;'), detail_safe )
+ %]</dd>
[% END %]
- </li>
-[% END %]
+ [% END %]
-<li><span class="mock-label">[% loc('Co-ordinates:') %]</span> [% problem.local_coords.join(',') %]
- <input type="hidden" name="latitude" id="fixmystreet.latitude" value="[% problem.latitude %]">
- <input type="hidden" name="longitude" id="fixmystreet.longitude" value="[% problem.longitude %]">
-
-([%
- SET safe = problem.postcode | html;
- tprintf( loc('originally entered: &ldquo;%s&rdquo;'), safe )
-%],
-[% IF problem.used_map %][% loc('used map') %][% ELSE %][% loc("didn't use map") %][% END %])</li>
-
-<li><span class="mock-label">[% loc('Name:') %]</span> [% problem.name | html %] <input type='hidden' name='name' id='name' value='[% problem.name | html %]'></li>
-<li><span class="mock-label">[% loc('Email:') %]</span> [% problem.user.email | html %] <input type='hidden' id='email' name='email' value='[% problem.user.email | html %]'>
-[% IF NOT problem.extra.email_confirmed %]<span class="error">[% loc('Unconfirmed') %]</span>[% END %]
-</li>
-<li><span class="mock-label">[% loc('Phone:') %]</span> [% IF problem.user.phone %][% problem.user.phone | html %][% ELSE %]<em>[% loc('None') %]</em>[% END %]</li>
-<li><span class="mock-label">[% loc('Created:') %]</span> [% PROCESS format_date this_date=problem.created %] [% problem.created.hms %]</li>
-
-
-[% IF problem.photo %]
-<li>
-[% photo = problem.get_photo_params %]
-<div class="update-img">
- <a href="[% c.cobrand.base_url %]/photo/[% problem.photo %].fulltemp.jpeg" rel="fancy">
- <img alt="Photo of this report" src="[% c.cobrand.base_url %]/photo/[% problem.photo %].temp.jpeg">
- <span>zoom</span></a>
-</div>
-<br>
-<input type="submit" name="rotate_photo" value="[% loc('Rotate Left') %]">
-<input type="submit" name="rotate_photo" value="[% loc('Rotate Right') %]">
-<br>
-<input type="checkbox" id="publish_photo" name="publish_photo" value="1"[% ' checked' IF problem.extra.publish_photo %]>
-<label class="inline" for="publish_photo">[% loc("Publish photo") %]</label></li>
-[% END %]
-</ul>
+ <dt class="print-only">[% loc('Reported:') %] <!-- Meldedatum --></dt>
+ <dd class="screen-no-space-after">
+ <strong>[% PROCESS format_date this_date=problem.created %] [% problem.created.hms %]</strong>
+ </dd>
+ <dt class="print-only">[% loc('Coordinates:') %] <!-- Koordinaten --></dt>
+ <dd class="screen-no-space-after print-no-space-after">
+ [% problem.local_coords.join(',') %]
+ <input type="hidden" name="latitude" id="fixmystreet.latitude" value="[% problem.latitude %]">
+ <input type="hidden" name="longitude" id="fixmystreet.longitude" value="[% problem.longitude %]">
+ </dd>
+ <dd class="screen-no-space-after print-no-space-after">
+ [% IF problem.used_map %]
+ [% loc('Used map') %]
+ [% ELSE %]
+ [% loc("Didn't use map") %]
+ [% END %]
+ </dd>
+ <dd>[%
+ SET safe = problem.postcode | html;
+ tprintf( loc('originally entered: &ldquo;%s&rdquo;'), safe )
+ %]</dd>
+
+ [% SET fields = problem.get_extra_fields; IF fields.size %]
+ <dd>
+ [% FOR f IN fields %]
+ <strong>[% f.description %]</strong> [% f.value %]
+ <br>
+ [% END %]
+ </dd>
+ [% END %]
-<p><label for="new_internal_note">[% loc('New internal note:') %]</label>
-<textarea name='new_internal_note' id='new_internal_note' cols=60 rows=5>[% new_internal_note | html %]</textarea></p>
-
-<p><span class="mock-label">[% loc('State:') %]</span> <select name="state" id="state">
- <option value="">--</option>
- [% FOREACH s IN [
- ['unconfirmed', loc('Submitted')]
- ['confirmed', loc('Open')],
- ['planned', loc('Planned')],
- ['hidden', loc('Hidden')],
- ] %]
- <option [% 'selected ' IF s.0 == problem.state %] value="[% s.0 %]">[% s.1 %]</option>
- [% END %]
- [% IF problem.state == 'closed' %]
- <option selected value="closed">[% loc('Closed') %]</option>
- [% ELSIF problem.state == 'fixed - council' %]
- <option selected value="fixed - council">[% loc('Closed') %]</option>
- [% ELSIF problem.state == 'in progress' %]
- <option selected value="in progress">[% loc('In progress') %]</option>
+ <dt class="print-only">[% loc('Reported by:') %] <!-- Meldende Person --></dt>
+ <dd>
+ <strong>[% IF problem.name %][% problem.name | html %][% ELSE %][% loc('(No name)') %][% END %]</strong>
+ <input type='hidden' name='name' id='name' value='[% problem.name | html %]'>
+ <br>
+ [% problem.user.email | html %]
+ [% IF NOT problem.extra.email_confirmed %]<span class="error">[% loc('Unconfirmed') %]</span>[% END %]
+ <input type='hidden' id='email' name='email' value='[% problem.user.email | html %]'>
+ <br>
+ [% IF problem.user.phone %][% problem.user.phone | html %][% ELSE %]<em>[% loc('(No phone number)') %]</em>[% END %]
+ </dd>
+
+ <dt>[% loc('Category:') %] <!-- Kategorie --></dt>
+ <dd>[% problem.category | html %]</dd>
+
+ <dt class="print-only">[% loc('State:') %] <!-- Status --></dt>
+ <dd class="print-only">[% states_trans.${problem.state} %]</dd>
+
+ <dt>[% loc('Time spent (in minutes):') %]</dt>
+ <dd>[% problem.get_time_spent %]</dd>
+
+ [% IF problem.photo %]
+ <dd>
+ [% FOR photo IN problem.get_photoset(c).images %]
+ <div class="update-img">
+ <a href="[% c.cobrand.base_url %]/photo/[% photo.0 %].fulltemp.jpeg" rel="fancy">
+ <img alt="Photo of this report" src="[% c.cobrand.base_url %]/photo/[% photo.0 %].temp.jpeg">
+ <span>zoom</span>
+ </a>
+ </div>
+ <input type="submit" name="rotate_photo_[% loop.index %]" value="[% loc('Rotate Left') %]" class="screen-only">
+ <input type="submit" name="rotate_photo_[% loop.index %]" value="[% loc('Rotate Right') %]" class="screen-only">
+ [% END %]
+ <br>
+ <input type="checkbox" id="publish_photo" name="publish_photo" value="1"[% ' checked' IF problem.extra.publish_photo %] class="screen-only">
+ <label class="inline screen-only" for="publish_photo">[% loc("Publish photo") %]</label></li>
[% END %]
-</select></p>
-<p id="automatic-reply">
- <span class="mock-label">Automatische Antwort</span>
- <input type="checkbox" name="send_rejected_email" id="send_rejected_email" value="1" />
-</p>
+</dl>
+
+</div>
+
+<div class="admin-report-edit admin-report-edit--interact">
+
+[% status_message %]
<script type="text/javascript">
-$(function(){
- // Show or hide the automatic reply field
- $('#state').change(function(){
- if ($(this).val() === 'hidden') {
- $('#automatic-reply').show();
- } else {
- $('#automatic-reply').hide();
- }
- }).change();
-});
+ $(function(){
+ $('#map_box .noscript').clone().removeClass('noscript').addClass('map_clone print-only').prependTo('.admin-report-edit--interact');
+ });
</script>
-[% IF problem.state == 'unconfirmed' OR problem.state == 'confirmed' %]
+<dl [% IF status_message %]class="with-message"[% END %]>
+
+ <dt class="screen-only">
+ <label for="new_internal_note">[% loc('New internal note:') %]</label>
+ </dt>
+ <dd class="screen-only">
+ <textarea name='new_internal_note' id='new_internal_note' cols=60 rows=4>[% new_internal_note | html %]</textarea>
+ </dd>
+
+ <dt class="screen-only">
+ <label for="time_spent">[% loc('Time spent (in minutes):') %]</label>
+ </dt>
+ <dd class="screen-only">
+ <input type="text" name="time_spent" id="form_time_spent" style="width: 4em" value="0">
+ </dd>
+
+ <dt class="screen-only">
+ <span class="mock-label">[% loc('State:') %]</span>
+ </dt>
+ <dd class="screen-only">
+ <select name="state" id="state">
+ <option value="">--</option>
+ [% FOREACH s IN states %]
+ <option [% 'selected ' IF s.state == pstate %] value="[% s.state %]">[% s.trans %]</option>
+ [% END %]
+ </select>
+ </dd>
+
+</dl>
-<ul class="no-bullets">
-[% list = FOR body IN bodies %]
+<ul class="no-bullets screen-only">
+
+[% IF problem.state == 'confirmed' %]
+ <li class="assignation">
+ <div id="assignation__category">
+ <label for="category">[% loc('Assign to different category:') %]</label>
+ <select name="category" id="category">
+ <option value="">--</option>
+ [% FOREACH cat IN categories %]
+ <option value="[% cat %]">[% cat %]</option>
+ [% END %]
+ </select>
+ </div>
+ </li>
+
+ [% list = FOR body IN bodies %]
[%- NEXT UNLESS body.parent.id == c.user.from_body.id %]
<option value="[% body.id %]"[% IF body.id == problem.bodies_str %] selected[% END %]>[% body.name %]</option>
-[% END %]
+ [% END %]
+
[% IF admin_type != 'super' AND list %]
- <li class="assignation">
+ <li class="assignation" id="assignation__subdivision">
<label for="body_subdivision">[% loc('Assign to subdivision:') %]</label>
- <select name="body_subdivision" id="body_subdivision">
+ <select name="body_subdivision" id="body_subdivision" class="assignation__select">
<option value="">--</option>
[% list %]
</select>
</li>
[% END %]
-<li class="assignation">
-<label for="category">
-[% loc('Category:') %] [% problem.category %]<br>
-[% loc('Assign to different category:') %]</label>
- <select name="category" id="category">
- <option value="">--</option>
- [% FOREACH cat IN categories %]
- <option value="[% cat %]">[% cat %]</option>
- [% END %]
- </select></li>
-
-<li class="assignation">
-<label for="body_external">[% loc('Assign to external body:') %]</label>
- <select name="body_external" id="body_external">
- <option value="">--</option>
- [% FOR body IN bodies %]
- [% NEXT IF body.parent OR body.bodies OR body.deleted %]
- <option value="[% body.id %]"[% IF body.id == problem.bodies_str %] selected[% END %]>[% body.name %]</option>
+[% END %]
+</ul>
+
+
+[% IF problem.state == 'planned' %]
+ [%# 3rd party messages sent for Extern/Wunsch states %]
+ [% SWITCH pstate %]
+ [% CASE ['closed','investigating'] %]
+ <ul class="no-bullets screen-only">
+ <li class="assignation" id="assignation__external">
+ <span class="error hidden">[% loc('Please select a body.') %]</span>
+ <label for="body_external">
+ [% IF pstate == 'closed' %]
+ [% loc('Assign to external body:') %]
+ [% ELSE %]
+ [% loc('Assign to competent body:') %]
+ [% END %]
+ </label>
+ <select name="body_external" id="body_external">
+ <option value="">--</option>
+ [% FOR body IN bodies %]
+ [% NEXT IF body.parent OR body.bodies OR body.deleted %]
+ <option value="[% body.id %]"[% IF body.id == problem.external_body %] selected[% END %]>[% body.name %]</option>
+ [% END %]
+ </select>
+ </li>
+ <li>
+ [% IF pstate == 'closed' %]
+ <input type="checkbox" name="third_personal" id="third_personal" value="1"[% ' checked' IF problem.extra.third_personal %]>
+ <label for="third_personal" class="inline">[% loc('Include reporter personal details') %]</label>
+ [% END %]
+ </li>
+ <li>
+ [% INCLUDE 'admin/response_templates_select.html' for='external_body' %]
+ <textarea name='external_message' id='external_body' cols=60 rows=5>[% problem.get_extra_metadata('external_message') | html %]</textarea>
+ </li>
+ </ul>
[% END %]
- </select>
- <br>
- <input type="checkbox" name="third_personal" id="third_personal" value="1"[% ' checked' IF problem.extra.third_personal %]>
- <label for="third_personal" class="inline">[% loc('Include reporter personal details') %]</label>
-</ul>
+ [%# Public response field shown for Ruckmeldung ausstehend states
+ # (e.g. various pstates) %]
+ <ul class="no-bullets screen-only">
+ <li id="status_update_container"><label for="status_update">
+ [% SWITCH pstate %]
+ [% CASE ['hidden', 'investigating', 'partial'] %][%# Hidden/Wish/Not contactable %]
+ [% loc('Reply to user:') %]
+ [% CASE DEFAULT %]
+ [% loc('Public response:') %]
+ [% END %]
+ </label>
+ [% INCLUDE 'admin/response_templates_select.html' for='status_update' %]
+ <textarea name='status_update' id='status_update' cols=60 rows=5>
+ [%- problem.extra.public_response || default_public_response | html -%]
+ </textarea>
+ </li>
+ </ul>
+[% END %]
+
+<p align="right" class="screen-only">
+ [% IF show_publish_response %]
+ [%# While we call this 'publish_response', the response will not actually
+ # be "published" for these cases: Wish / Hidden / Not contactable (for these,
+ # only a private email will be sent to the user. However, in all cases,
+ # this is the end of processing, so we mark this with the same text used
+ # for 'No further updates %]
+ <input type="submit" name="publish_response" value="[% loc('No further updates') %]">
+ [% END %]
+
+ [%# This button simply saves changes, but does NOT close the report (though
+ # it may trigger other workflow %]
+ <input type="submit" name="Submit changes" value="[% loc('Submit changes') %]" >
+</p>
+
+[% IF c.cobrand.problem_has_public_response(problem) || c.cobrand.problem_has_user_response(problem) %]
+ <h2>[% loc('Public response:') %]</h2>
+ <div class="admin-official-answer">
+ [% problem.extra.public_response | html_para %]
+ </div>
+[% END %]
+
+[% SWITCH problem.state %]
+ [% CASE ['closed','investigating'] %]
+ <h2>
+ [% IF problem.state == 'closed' %]
+ [% loc('Message to external body:') %]
+ [% ELSE %]
+ [% loc('Message to competent body:') %]
+ [% END %]
+ </h2>
+ <div class="admin-external-message">
+ [% problem.extra.external_message | html_para %]
+ </div>
+[% END %]
+
+
+[% INCLUDE 'admin/list_updates.html' %]
+
+</div>
+
+</form>
<script type="text/javascript">
$(function(){
- $('.assignation select').change(function(){
+ var form_fields_changed = false;
+
+ $('#form_time_spent').spinner({
+ spin: function (e, ui) {
+ if (ui.value < 0) { return false }
+ form_fields_changed = true;
+ }
+ });
+
+ setTimeout(function(){
+ $('.message-updated').fadeOut(250, function(){
+ $(this).remove();
+ });
+ }, 5000);
+
+ // When the user changes a select box, this bit of code
+ // makes the labels for the other two select boxes grey.
+ $('.assignation__select, .assignation select').change(function(){
if (this.value == "") {
$('.assignation').css('color', '#000');
} else {
@@ -172,57 +324,82 @@ $(function(){
$('.assignation').not(a).css('color', '#999');
}
});
-});
-</script>
-
-[% ELSIF problem.state == 'planned' %]
-
-<ul class="no-bullets">
-[% list = FOR body IN bodies %]
- [%- NEXT UNLESS body.parent.id == c.user.from_body.id %]
- <option value="[% body.id %]">[% body.name %]</option>
-[% END %]
- [% IF admin_type != 'super' AND list %]
- <li class="assignation">
- <label for="body_subdivision">[% loc('Assign to subdivision:') %]</label>
- <select name="body_subdivision" id="body_subdivision">
- <option value="" selected>--</option>
- [% list %]
- </select>
- </li>
- [% END %]
-
- <li><label for="status_update">[% loc('Public response:') %]</label>
-
- <textarea name='status_update' id='status_update' cols=60 rows=5>
- [%- IF problem.extra.public_response -%]
- [%- problem.extra.public_response | html -%]
- [%- ELSE -%]
-
-Freundliche Grüsse
-
-Ihre Stadt Zürich
- [%- END %]</textarea>
- </li>
-</ul>
-[% ELSIF problem.state == 'fixed - council' %]
+ $('#state').change(function(){
+ // Show or hide the automatic reply field
+ var state = $(this).val();
+
+ // show or disable assignation, templates, public_response, publish if
+ // same or different state to the one we started on
+ if ((state === '[% pstate %]')) {
+ $('input[name=publish_response]').show();
+ $('.response_templates_select').show();
+ $('#status_update_container').show();
+
+ if (state === 'confirmed') {
+ $('#assignation__category').show();
+ $('#assignation__subdivision').show();
+ }
+ if ((state === 'closed') || (state === 'investigating')) {
+ $('#assignation__external').show();
+ } else {
+ $('#assignation__external').hide();
+ }
+ }
+ else {
+ $('input[name=publish_response]').hide();
+ $('.response_templates_select').hide();
+ $('#status_update_container').hide();
+
+ $('#assignation__category').hide();
+ $('#assignation__subdivision').hide();
+ $('#assignation__category select').val('');
+ $('#assignation__subdivision select').val('');
+
+ $('#assignation__external select').val('');
+ $('#assignation__external').hide();
+ $('#external_body').hide();
+ $('#third_personal, label[for=third_personal]').hide();
+ }
-<p><span class="mock-label">[% loc('Public response:') %]</span>
-[% problem.extra.public_response | html %]
-</p>
+ }).change();
-[% END %]
+ $("form#report_edit input[type=submit]").click(function() {
+ $("form#report_edit").data("clicked_button", $(this).attr("name"));
+ });
-<p align="right">
-[% IF problem.state == 'planned' %]
-<input type="submit" name="publish_response" value="[% loc('Publish the response') %]">
-[% END %]
-<input type="submit" name="Submit changes" value="[% loc('Submit changes') %]" >
-</p>
+ $("form#report_edit").submit(function() {
+ // Make sure the external body field has a value if it's visible
+ // and the form is submitted as a 'save' action (i.e. not a rotate
+ // photo).
+ var clicked = $(this).data("clicked_button");
+ if (clicked == "publish_response" || clicked == "Submit changes") {
+ var visible = $("select#body_external:visible").length > 0;
+ var val = parseInt($("select#body_external").val());
+ if (visible && isNaN(val)) {
+ $("#assignation__external .error").removeClass("hidden");
+ $("select#body_external").focus().get(0).scrollIntoView();
+ return false;
+ }
+ }
+ // If the user has clicked to rotate a photo and has edited other
+ // fields, ask for confirmation before submitting the form
+ if (/rotate_photo/.test(clicked) && form_fields_changed) {
+ var message = "[% loc('Rotating this photo will discard unsaved changes to the report.') %]";
+ if (!confirm(message)) {
+ return false;
+ }
+ }
+ });
-</form>
+ $("form#report_edit").find("input, select, textarea").change(function() {
+ form_fields_changed = true;
+ });
+});
+</script>
-[% INCLUDE 'admin/list_updates.html' %]
+<div id="print_report_map" class="print-only">
+[% INCLUDE 'maps/noscript_map.html' map=print_report_map nsm_prefix="large_" %]
+</div>
[% INCLUDE 'admin/footer.html' %]
diff --git a/templates/web/zurich/admin/response_templates_select.html b/templates/web/zurich/admin/response_templates_select.html
new file mode 100644
index 000000000..c0f4104c8
--- /dev/null
+++ b/templates/web/zurich/admin/response_templates_select.html
@@ -0,0 +1,25 @@
+[% template_name="templates_for_${for}" %]
+
+[% response_templates = problem.response_templates %]
+<div class="response_templates_select">
+<select id="[% template_name %]">
+ <option value="">[% loc('Choose a template') %]</option>
+[% FOR t IN response_templates %]
+ <option value="[% t.id %]"> [% t.title | html %] </option>
+[% END %]
+</select>
+</div>
+<script>
+ $(function () {
+ var response_template_texts = {
+ [% FOR t IN response_templates %]
+ [% t.id %]: '[% t.text | escape_js %]' [% loop.last ? '' : ',' %]
+ [% END %]
+ };
+ $('#[% template_name %]').change(function () {
+ var val = $(this).val();
+ var text = response_template_texts[val];
+ $('#[% for %]').val( text );
+ });
+ });
+</script>
diff --git a/templates/web/zurich/admin/stats.html b/templates/web/zurich/admin/stats.html
index 52b33ebc4..fa8104496 100644
--- a/templates/web/zurich/admin/stats.html
+++ b/templates/web/zurich/admin/stats.html
@@ -2,7 +2,7 @@
[% PROCESS 'admin/report_blocks.html' %]
[% USE date %]
-<p style="float:right"><a href="[% c.uri_with( { export=1 } ) %]">[% loc('All Reports') %]</a></p>
+<p style="float:right"><a href="[% c.uri_with( { export=1 } ) %]">[% loc('All Reports as CSV') %]</a></p>
[% IF start_date AND end_date %]
<p><strong>[% tprintf( loc( 'All reports between %s and %s' ), start_date.ymd, end_date.ymd ) | html %]</strong></p>
@@ -48,7 +48,7 @@
<table>
<tr><th>[% loc('Category') %]</th><th>[% loc('Count') %]</th></tr>
-[% WHILE ( c = per_category.next ) %]<tr><td>[% c.category %]</td><td>[% c.get_column('c') %]</td></tr>[% END %]
+[% WHILE ( cc = per_category.next ) %]<tr><td>[% cc.category %]</td><td>[% cc.get_column('c') %]</td></tr>[% END %]
</table>
[% INCLUDE 'admin/footer.html' %]
diff --git a/templates/web/zurich/admin/template_edit.html b/templates/web/zurich/admin/template_edit.html
new file mode 100644
index 000000000..1deda6a77
--- /dev/null
+++ b/templates/web/zurich/admin/template_edit.html
@@ -0,0 +1,38 @@
+[% INCLUDE 'admin/header.html' title=tprintf(loc('Response Templates for %s'), body.name) -%]
+[% rt = response_template %]
+
+<h2> [% tprintf(loc('Response Templates for %s'), body.name) %] </h2>
+
+<h3> [% IF rt.id %]
+ [% tprintf(loc('Template &laquo;%s&raquo;'), rt.title) %]
+ [% ELSE %]
+ [% loc('New template') %]
+ [% END %]
+</h3>
+
+<form method="post"
+ action="[% c.uri_for('templates', body.id, rt.id || 'new' ) %]"
+ enctype="application/x-www-form-urlencoded"
+ accept-charset="utf-8"
+ class="validate">
+
+ <p>
+ <strong>[% loc('Title:') %] </strong>
+ <input type="text" name="title" class="required" size="30" value="[% rt.title| html %]">
+ </p>
+ <p>
+ <strong>[% loc('Text:') %] </strong>
+ <textarea name="text" class="required">[% rt.text |html %]</textarea>
+ </p>
+ <p>
+ <input type="hidden" name="token" value="[% token %]" >
+ <input type="submit" name="Edit templates" value="[% rt.id ? loc('Save changes') : loc('Create template') %]" >
+ </p>
+ [% IF rt.id %]
+ <p>
+ <input class="delete" type="submit" name="delete_template" value="[% loc('Delete template') %]">
+ </p>
+ [% END %]
+</form>
+
+[% INCLUDE 'admin/footer.html' %]
diff --git a/templates/web/zurich/admin/templates.html b/templates/web/zurich/admin/templates.html
new file mode 100644
index 000000000..d3b334022
--- /dev/null
+++ b/templates/web/zurich/admin/templates.html
@@ -0,0 +1,28 @@
+[% INCLUDE 'admin/header.html' title=tprintf(loc('Response Templates for %s'), body.name) -%]
+
+<h2> [% tprintf(loc('Response Templates for %s'), body.name) %] </h2>
+
+<table>
+ <thead>
+ <tr>
+ <th> [% loc('Title') %] </th>
+ <th> [% loc('Text') %] </th>
+ <th> [% loc('Created') %] </th>
+ <th> &nbsp; </th>
+ </tr>
+ </thead>
+ <tbody>
+[% FOR t IN response_templates %]
+ <tr>
+ <td> [% t.title %] </td>
+ <td> [% t.text %] </td>
+ <td> [% t.created %] </td>
+ <td> <a href="/admin/templates/[% body.id %]/[% t.id %]" class="btn">[% loc('Edit') %]</a> </td>
+ </tr>
+[% END %]
+ </tbody>
+</table>
+
+<a href="[% c.uri_for('templates', body.id, 'new') %]" class="btn">[% loc('New template') %]</a>
+
+[% INCLUDE 'admin/footer.html' %]
diff --git a/templates/web/zurich/auth/general.html b/templates/web/zurich/auth/general.html
index 11c729fde..fd34b79f8 100644
--- a/templates/web/zurich/auth/general.html
+++ b/templates/web/zurich/auth/general.html
@@ -27,7 +27,7 @@ END %]
[% 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') %]">
+ <input type="email" class="required email" id="email" name="email" value="[% email | html %]" placeholder="[% loc('Your email address') %]" autofocus>
<label for="password_sign_in">[% loc('Password (optional)') %]</label>
<div class="form-txt-submit-box">
diff --git a/templates/web/zurich/faq/faq-de-ch.html b/templates/web/zurich/faq/faq-de-ch.html
index c7e284194..deda32a1c 100644
--- a/templates/web/zurich/faq/faq-de-ch.html
+++ b/templates/web/zurich/faq/faq-de-ch.html
@@ -2,87 +2,55 @@
<h1><a name="faq"></a>Hilfe</h1>
- <dl>
-
-<dt>Was ist «Züri wie neu»</dt>
-<dd>
-«Züri wie neu» ist eine Online-Plattform, über die die Einwohnerinnen und
-Einwohner der Stadt Zürich auf Mängel und Schäden der städtischen Infrastruktur
-hinweisen können. «Züri wie neu» wird von der Stadtverwaltung moderiert und
-transparent geführt. Die Meldungen werden innerhalb von einem Arbeitstag den zuständigen Fachstellen
-zugewiesen und innert fünf Arbeitstagen abschliessend beantwortet. Fällt eine
-Meldung nicht in den Zuständigkeitsbereich der Stadtverwaltung, wird die
-Meldung anonymisiert der zuständigen dritten Stelle per E-Mail zugestellt.
-</dd>
-
-<dt>Welche Probleme kann ich über «Züri wie neu» melden?</dt>
-<dd>
-<p>Gemeldet werden können sämtliche Schäden an der Infrastruktur der Stadt Zürich.
-Dabei kann es sich um ein Loch im Strassenbelag, ein Graffiti am Stadthaus oder
-eine durch Vandalen beschädigte Parkbank handeln.
-
-<p>Es können Probleme zu folgenden Kategorien gemeldet werden:
+<h3 id="was_ist_zri_wie_neu">Was ist «Züri wie neu»</h3>
+
+<p>«Züri wie neu» ist eine Online-Plattform, über die die Einwohnerinnen und Einwohner die Stadt Zürich auf Schäden an der städtischen Infrastruktur hinweisen können. «Züri wie neu» wird von der Stadtverwaltung moderiert und transparent geführt. Die Meldungen werden innerhalb von einem Arbeitstag den zuständigen Fachstellen zugewiesen und innert fünf Arbeitstagen abschliessend beantwortet. Fällt eine Meldung nicht in den Zuständigkeitsbereich der Stadtverwaltung, wird die Meldung anonymisiert der zuständigen dritten Stelle per E-Mail zugestellt.</p>
+
+<h3 id="welche_probleme_kann_ich_ber_zri_wie_neu_melden">Welche Probleme kann ich über «Züri wie neu» melden?</h3>
+
+<p>Gemeldet werden können sämtliche Schäden an der Infrastruktur der Stadt Zürich in folgenden Kategorien:</p>
<ul>
<li>Abfall / Sammelstellen</li>
-<li>Beleuchtung</li>
+<li>Beleuchtung / Uhren</li>
+<li>Brunnen / Hydranten</li>
<li>Graffiti</li>
-<li>Spielplatz / Sitzbank</li>
+<li>Grünflächen / Spielplätze</li>
<li>Strasse / Trottoir / Platz</li>
-<li>Tiere / Grünflächen</li>
+<li>VBZ / ÖV</li>
</ul>
-</dd>
+<h3 id="was_kann_ich_nicht_ber_zri_wie_neu_melden">Was kann ich nicht über «Züri wie neu» melden?</h3>
-<dt>Was kann ich nicht über «Züri wie neu» melden?</dt>
-<dd>
<ul>
-<li>Mängel die nicht auf Stadtgebiet liegen.</li>
-<li>Melden Sie «Züri wie neu» KEINE Notfälle. Die Notrufnummern lauten:
- <br>Medizinisch - 144 Polizei - 117 Feuer - 118 Allgemein - 112</li>
+<li>Schäden die nicht auf Stadtgebiet liegen</li>
+<li>Melden Sie «Züri wie neu» KEINE Notfälle. Die Notrufnummern lauten: <br />
+Sanität – 144, Polizei – 117, Feuerwehr – 118, Allgemein - 112</li>
<li>Allgemeine Verschönerungs- und Verbesserungsvorschläge</li>
</ul>
-</dd>
-
-<dt>Wie verwende ich die Webseite?</dt>
-<dd>
-<p>
-Geben Sie zuerst eine Adresse an oder lassen Sie Ihren Standort automatisch
-über den entsprechenden Link lokalisieren. Mittels Mausklick in die danach
-angezeigte Karte können Sie den exakten Ort des Mangels angeben. Als letzten
-Schritt füllen Sie die Felder des Formulars aus und schicken die Meldung ab.
-</p>
-<p>
-Weiter können Sie bestehende Meldungen sowie auch die Rückmeldungen der
-Verwaltung betrachten.
-</p>
-</dd>
-
-<dt>Wie werden die Probleme gelöst?</dt>
-<dd>
-Die Meldungen werden innerhalb von einem Arbeitstag den zuständigen Fachstellen
-zugewiesen und innert fünf Arbeitstagen von den dafür zuständigen
-Fachstellen bearbeitet sowie mit einer entsprechenden Rückmeldung versehen.
-</dd>
-
-<dt>Kann ich «Züri wie neu» auf meinem Smartphone nutzen?</dt>
-<dd>
-Ja, sowohl über die für mobile Geräte optimierte Webseite, als auch über die
-<a href="https://itunes.apple.com/ch/app/zuri-wie-neu/id631302236">iOS</a>- und <a href="https://play.google.com/store/apps/details?id=ch.zueriwieneu.zueriwieneu">Android-App</a>.
-</dd>
-
-<dt>Kann ich auch Probleme ausserhalb von Zürich melden?</dt>
-<dd>Nein.</dd>
-
-<dt>Werden meine E-Mail-Adresse, mein Name und meine Telefonnummer vertraulich behandelt?</dt>
-<dd>
-Die Kontaktinformationen werden nur stadtintern für Rückfragen verwendet. Sie
-werden weder im Internet publiziert noch an Dritte weitergegeben.
-</dd>
-
-<dt>Wer hat «Züri wie neu» programmiert?</dt>
-<dd>«Züri wie neu» wurde von <a href="http://www.mysociety.org/">mySociety</a> entwickelt.</dd>
-
-</dl>
+
+<h3 id="wie_melde_ich_einen_schaden">Wie melde ich einen Schaden?</h3>
+
+<p>Geben Sie zuerst eine Adresse an oder lassen Sie Ihren Standort automatisch über den entsprechenden Link lokalisieren. Mittels Mausklick in die danach angezeigte Karte können Sie den exakten Ort des Mangels angeben. Als letzten Schritt füllen Sie die Felder des Formulars aus, machen mindestens ein Foto des Schadens und schicken die Meldung ab.</p>
+
+<h3 id="wie_werden_die_schden_behoben">Wie werden die Schäden behoben?</h3>
+
+<p>Die Meldungen werden innerhalb von einem Arbeitstag den zuständigen Fachstellen zugewiesen und innert fünf Arbeitstagen von den dafür zuständigen Fachstellen bearbeitet sowie mit einer entsprechenden Rückmeldung versehen.</p>
+
+<h3 id="kann_ich_zri_wie_neu_auf_meinem_smartphone_nutzen">Kann ich «Züri wie neu» auf meinem Smartphone nutzen?</h3>
+
+<p>Ja, sowohl über die für mobile Geräte optimierte Webseite, als auch über die <a href="https://itunes.apple.com/ch/app/zuri-wie-neu/id631302236">iOS-</a> und <a href="https://play.google.com/store/apps/details?id=ch.zueriwieneu.zueriwieneu">Android-App</a>.</p>
+
+<h3 id="kann_ich_auch_schden_ausserhalb_von_zrich_melden">Kann ich auch Schäden ausserhalb von Zürich melden?</h3>
+
+<p>Nein, auf «Züri wie neu» können nur Schäden auf Stadtgebiet gemeldet werden.</p>
+
+<h3 id="werden_meine_e_mail_adresse_mein_name_und_meine_telefonnummer_vertraulich_behandelt">Werden meine E-Mail-Adresse, mein Name und meine Telefonnummer vertraulich behandelt?</h3>
+
+<p>Die Kontaktinformationen werden nur stadtintern für Rückfragen verwendet. Sie werden weder im Internet publiziert noch an Dritte weitergegeben.</p>
+
+<h3 id="wer_hat_zri_wie_neu_programmiert">Wer hat «Züri wie neu» programmiert?</h3>
+
+<p>«Züri wie neu» wurde von <a href="https://www.mysociety.org/">mySociety</a> programmiert.</p>
[% INCLUDE 'footer.html' pagefooter = 'yes' %]
diff --git a/templates/web/zurich/footer.html b/templates/web/zurich/footer.html
index f70470226..11bfa9fcb 100644
--- a/templates/web/zurich/footer.html
+++ b/templates/web/zurich/footer.html
@@ -1,3 +1,4 @@
+[% USE date %]
</div><!-- .content role=main -->
</div><!-- .container -->
</div><!-- .table-cell -->
@@ -30,7 +31,7 @@
<div id="zurich-footer-wrapper" class="desk-only">
<div id="zurich-footer">
- &copy; 2013 Stadt Z&uuml;rich
+ &copy; [% date.format(date.now, '%Y') %] Stadt Z&uuml;rich
<span class="hidden">|</span> <a href="http://www.stadt-zuerich.ch/content/portal/de/index/footer/rechtliche_hinweise.html">Rechtliche Hinweise</a>
<span class="hidden">|</span> <a href="http://www.stadt-zuerich.ch/content/portal/de/index/footer/impressum.html">Impressum</a>
</div>
diff --git a/templates/web/zurich/header.html b/templates/web/zurich/header.html
index 0d06d2c53..7e88f3f0f 100644
--- a/templates/web/zurich/header.html
+++ b/templates/web/zurich/header.html
@@ -14,7 +14,7 @@
[% 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)">
+ <link rel="stylesheet" href="[% start %][% version('/cobrands/' _ c.cobrand.moniker _ '/layout.css') %]" media="screen and (min-width:48em)">
[% extra_css %]
<!--[if (lt IE 9) & (!IEMobile)]>
<link rel="stylesheet" href="[% start %][% version('/cobrands/' _ c.cobrand.moniker _ '/layout.css') %]">
@@ -68,9 +68,14 @@
<li [% IF pagename == 'users' OR pagename == 'user_edit' %]class="current"[% END %]>
<a href="/admin/users">[% loc('Users') %]</a>
</li>
+ [% END %]
<li [% IF pagename == 'stats' %]class="current"[% END %]>
<a href="/admin/stats">[% loc('Stats') %]</a>
</li>
+ [% IF admin_type == 'dm' %]
+ <li [% IF pagename == 'templates' OR pagename == 'template' %]class="current"[% END %]>
+ <a href="/admin/templates">[% loc('Templates') %]</a>
+ </li>
[% END %]
<li class="search-box">
<form method="get" action="[% c.uri_for('reports') %]" enctype="application/x-www-form-urlencoded" accept-charset="utf-8">
diff --git a/templates/web/zurich/maps/noscript_map.html b/templates/web/zurich/maps/noscript_map.html
new file mode 100644
index 000000000..5c2a2c064
--- /dev/null
+++ b/templates/web/zurich/maps/noscript_map.html
@@ -0,0 +1,70 @@
+<div class="noscript square-map__outer">
+ <div class="square-map__inner">
+ <div id="[% nsm_prefix %]drag">
+ [%- FOR row IN map.tiles -%]
+ [%- FOR tile IN row -%]
+ [%- top_px = tile.row_offset * map.tile_size -%]
+ [%- left_px = tile.col_offset * map.tile_size %]
+ <[% map.img_type %]
+ class="square-map__tile"
+ alt="[% tile.alt %]"
+ id="[% nsm_prefix %]t[% tile.dotted_id %]"
+ name="tile_[% tile.dotted_id %]"
+ src="[% tile.src %]"
+ style="width: [% 100 / map.cols %]%; height: auto; float: left;">
+ [%- END -%]
+ [% END %]
+ </div>
+ <div id="[% nsm_prefix %]pins">[% FOR pin IN map.pins %][% INCLUDE pin %][% END %]</div>
+ [% INCLUDE compass %]
+ </div>
+</div>
+
+[% BLOCK compass %]
+[%
+ north = c.uri_with( { lat = map.compass.north.0, lon = map.compass.north.1, zoom = map.zoom } )
+ south = c.uri_with( { lat = map.compass.south.0, lon = map.compass.south.1, zoom = map.zoom } )
+ east = c.uri_with( { lat = map.compass.east.0, lon = map.compass.east.1, zoom = map.zoom } )
+ west = c.uri_with( { lat = map.compass.west.0, lon = map.compass.west.1, zoom = map.zoom } )
+ world = c.uri_with( { zoom = 0 } );
+ SET zoom_in = c.uri_with( { lat = map.latitude, lon = map.longitude, zoom = map.zoom + 1 } ) IF map.zoom < map.numZoomLevels - 1;
+ SET zoom_out = c.uri_with( { lat = map.latitude, lon = map.longitude, zoom = map.zoom - 1 } ) IF map.zoom > 0;
+ SET zoom_in = '#' IF map.zoom >= map.numZoomLevels - 1;
+ SET zoom_out = '#' IF map.zoom <= 0;
+%]
+<div style="position: absolute; left: 4px; top: 4px;" class="olControlPanZoom olControlNoSelect" unselectable="on">
+ <div style="position: absolute; left: 13px; top: 4px; width: 18px; height: 18px;"><a rel="nofollow" href="[% north %]"><img style="position: relative; width: 18px; height: 18px;" src="/js/OpenLayers-2.13.1/img/north-mini.png" border="0"></a></div>
+ <div style="position: absolute; left: 4px; top: 22px; width: 18px; height: 18px;"><a rel="nofollow" href="[% west %]"><img style="position: relative; width: 18px; height: 18px;" src="/js/OpenLayers-2.13.1/img/west-mini.png" border="0"></a></div>
+ <div style="position: absolute; left: 22px; top: 22px; width: 18px; height: 18px;"><a rel="nofollow" href="[% east %]"><img style="position: relative; width: 18px; height: 18px;" src="/js/OpenLayers-2.13.1/img/east-mini.png" border="0"></a></div>
+ <div style="position: absolute; left: 13px; top: 40px; width: 18px; height: 18px;"><a rel="nofollow" href="[% south %]"><img style="position: relative; width: 18px; height: 18px;" src="/js/OpenLayers-2.13.1/img/south-mini.png" border="0"></a></div>
+ <div style="position: absolute; left: 13px; top: 63px; width: 18px; height: 18px;"><a rel="nofollow" href="[% zoom_in %]"><img style="position: relative; width: 18px; height: 18px;" src="/js/OpenLayers-2.13.1/img/zoom-plus-mini.png" border="0"></a></div>
+ <div style="position: absolute; left: 13px; top: 81px; width: 18px; height: 18px;"><a rel="nofollow" href="[% world %]"><img style="position: relative; width: 18px; height: 18px;" src="/js/OpenLayers-2.13.1/img/zoom-world-mini.png" border="0"></a></div>
+ <div style="position: absolute; left: 13px; top: 99px; width: 18px; height: 18px;"><a rel="nofollow" href="[% zoom_out %]"><img style="position: relative; width: 18px; height: 18px;" src="/js/OpenLayers-2.13.1/img/zoom-minus-mini.png" border="0"></a></div>
+</div>
+[% END %]
+
+
+[% BLOCK pin %]
+
+[% IF pin.id %]
+<a title="[% pin.title | html %]" href="[% c.uri_for('/report/' _ pin.id) %]">
+[%- END -%]
+<img
+ data-foo="[% pin.px %],[% pin.py %]/ [% map.tile_size %]*[% map.cols %],[% map.rows %]"
+ border="0"
+ class="pin"
+ src="[% c.uri_for( c.cobrand.path_to_pin_icons _ 'pin-' _ pin.colour _ '.png') %]"
+ alt="[% loc('Problem') %]"
+ style="
+ top: [% pin.py / ( map.tile_size * map.rows ) * 100 %]%;
+ left: [% pin.px / ( map.tile_size * map.cols ) * 100 %]%;
+ position: absolute;
+ margin-left: -24px; /* Half of 48px wide image */
+ margin-top: -64px; /* All of 64px tall image */
+ "
+>
+[%- IF pin.id -%]
+</a>
+[% END %]
+
+[% END %]
diff --git a/templates/web/zurich/report/banner.html b/templates/web/zurich/report/banner.html
index eda70a0de..c10a99ef6 100644
--- a/templates/web/zurich/report/banner.html
+++ b/templates/web/zurich/report/banner.html
@@ -1,17 +1,6 @@
[% USE date %]
-[% BLOCK banner %]
- <div class="banner">
- <p id="[% id %]">[% text %]</p>
- </div>
-[% END %]
-
-[% IF problem.state == 'unconfirmed' %]
- [% INCLUDE banner, id = 'closed', text = loc('Submitted') %]
-[% ELSIF problem.state == 'confirmed' %]
- [% INCLUDE banner, id = 'closed', text = loc('Open') %]
-[% ELSIF problem.is_fixed OR problem.is_closed %]
- [% INCLUDE banner, id = 'fixed', text = loc('Closed') %]
-[% ELSIF problem.state == 'in progress' OR problem.state == 'planned' %]
- [% INCLUDE banner, id = 'progress', text = loc('In progress') %]
-[% END %]
+[% problem_hashref = c.cobrand.problem_as_hashref(problem, c) %]
+<div class="banner">
+ <p id="[% problem_hashref.banner_id %]">[% problem_hashref.state_t %]</p>
+</div>
diff --git a/templates/web/zurich/report/new/fill_in_details_form.html b/templates/web/zurich/report/new/fill_in_details_form.html
index 28d9ebe68..c8c567786 100644
--- a/templates/web/zurich/report/new/fill_in_details_form.html
+++ b/templates/web/zurich/report/new/fill_in_details_form.html
@@ -48,14 +48,17 @@
[% PROCESS "report/new/category_wrapper.html" %]
[% IF c.cobrand.allow_photo_upload %]
- <label for="form_photo">[% loc('Photo') %]</label>
+ <label for="form_photo">
+ [% loc('Photo') %]
+ [% loc('(Defect &amp; location of defect)') %]
+ </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>
+ <p>[% loc('You have already attached photos to this report. Note that you can attach a maximum of 3 to this report (if you try to upload more, the oldest will be removed).') %]</p>
[% IF report.photo %]
<img align="right" src="/photo/[% report.id %].jpeg">
@@ -65,7 +68,9 @@
[% IF field_errors.photo %]
<p class='form-error'>[% field_errors.photo %]</p>
[% END %]
- <input type="file" name="photo" id="form_photo">
+ <input type="file" name="photo1" id="form_photo">
+ <input type="file" name="photo2" id="form_photo2">
+ <input type="file" name="photo3" id="form_photo3">
[% END %]
<label for="form_email">[% loc('Your email') %]</label>
@@ -84,7 +89,7 @@
[% IF field_errors.phone %]
<p class='form-error'>[% field_errors.phone %]</p>
[% END %]
- <input type="text" value="[% report.user.phone | html %]" name="phone" id="form_phone" placeholder="[% loc('Your phone number') %]">
+ <input type="text" value="[% report.user.phone | html %]" name="phone" id="form_phone" placeholder="[% loc('Your phone number') %]" required>
<div class="form-txt-submit-box">
[%# ID of submit_sign_in so name can be option, name of submit_register so it doesn't try and sign us in %]
diff --git a/templates/web/zurich/report/updates.html b/templates/web/zurich/report/updates.html
index 786ecd582..cb7644694 100644
--- a/templates/web/zurich/report/updates.html
+++ b/templates/web/zurich/report/updates.html
@@ -5,10 +5,10 @@
<div class="update-wrap">
<div class="update-text">
<p class="meta-2">[% prettify_dt( problem.lastupdate, 'zurich' ) %]</p>
- [% IF problem.state == 'fixed - council' %]
+ [%# XXX following should honour zurich_closed_states instead? %]
+ [% IF problem.state == 'fixed - council'
+ || ( problem.external_body AND problem.state == 'closed' ) %]
[% add_links( problem.extra.public_response ) | html_para %]
- [% ELSIF problem.state == 'closed' AND problem.external_body %]
- <p>[% tprintf( loc('Assigned to %s'), problem.body(c).name ) %]</p>
[% END %]
</div>
</div>
diff --git a/web/cobrands/sass/_base.scss b/web/cobrands/sass/_base.scss
index 7bb6a96cb..0df8ad01b 100644
--- a/web/cobrands/sass/_base.scss
+++ b/web/cobrands/sass/_base.scss
@@ -945,8 +945,8 @@ input.final-submit {
// fancybox gallery images have a magnifying glass in the corner
.update-img {
a {
- @include inline-block;
- position:relative;
+ display: block;
+ position: relative;
span {
position:absolute;
top:0;
@@ -1003,6 +1003,13 @@ input.final-submit {
}
}
+// The map's static image fallback is visible by default.
+// Hide it if javascript has loaded. (We show it again when
+// the page is printed.)
+html.js #map .noscript {
+ display: none;
+}
+
// OpenLayers fix for navigation being top right
// Left and right so that zoom can be left, pan right.
#fms_pan_zoom {
@@ -1729,5 +1736,49 @@ table.nicetable {
}
+@media screen {
+ .print-only {
+ display: none !important;
+ }
+}
+
+@media print {
+ @page {
+ margin: 3em;
+ }
+
+ #main-nav,
+ #nav-link,
+ .admin-nav,
+ .olControlAttribution,
+ .olControlPanZoom,
+ #sub_map_links,
+ #fms_pan_zoom,
+ .screen-only,
+ .olMapViewport {
+ display: none !important;
+ }
+
+ #map_box {
+ position: static !important;
+ height: 256px !important;
+ width: auto !important;
+ background: #f1eee9 !important; // cream colour to match OSM image
+ }
+
+ #map {
+ -webkit-transform: scale(0.5);
+ -ms-transform: scale(0.5);
+ transform: scale(0.5);
+ -webkit-transform-origin: 0 0;
+ -ms-transform-origin: 0 0;
+ transform-origin: 0 0;
+ }
+
+ html.js #map .noscript {
+ display: block;
+ }
+}
+
@import "_admin";
@import "_fixedthead";
diff --git a/web/cobrands/zurich/admin-faux-columns.gif b/web/cobrands/zurich/admin-faux-columns.gif
new file mode 100644
index 000000000..077fea2e5
--- /dev/null
+++ b/web/cobrands/zurich/admin-faux-columns.gif
Binary files differ
diff --git a/web/cobrands/zurich/base.scss b/web/cobrands/zurich/base.scss
index 559d97a27..8f6cca96f 100644
--- a/web/cobrands/zurich/base.scss
+++ b/web/cobrands/zurich/base.scss
@@ -42,11 +42,11 @@
}
&#closed {
color: #1a1a1a;
- background: #e25436;
+ background: #e25436; // red
}
&#progress {
color: #1a1a1a;
- background: #f3d74b;
+ background: #f3d74b; //purple
}
}
}
@@ -178,3 +178,180 @@ h4.static-with-rule {
}
}
}
+
+.admin-note__text {
+ background-color: #eee;
+ padding: 0.5em 1em;
+ border-radius: 4px;
+ position: relative;
+ margin-bottom: 0.5em;
+
+ // add a little speech bubble triangle to the bottom left corner
+ &:after {
+ content: "";
+ display: block;
+ position: absolute;
+ bottom: -10px;
+ left: 10px;
+ border-top: 10px solid #eee;
+ border-left: 10px solid transparent;
+ }
+
+ .admininternal & {
+ background-color: #eef;
+
+ &:after {
+ border-top-color: #eef;
+ }
+ }
+}
+
+.admin-note__creator {
+ padding-left: 30px;
+}
+
+.admin-official-answer, .admin-external-message {
+ background-color: #1F52A3; // official Zurich blue colour
+ color: #fff;
+ padding: 0.8em 1em;
+ border-radius: 4px;
+
+ p {
+ margin-bottom: 0.5em;
+
+ &:last-child {
+ margin-bottom: 0;
+ }
+ }
+}
+
+.admin {
+ label.inline {
+ padding: 0;
+ }
+
+ input[type="checkbox"] + label.inline {
+ margin-right: 0.2em;
+ }
+}
+
+.admin-label--inline {
+ display: inline; // rather than block
+ margin-right: 0.333em; // bit of space between this and the following input
+}
+
+.ui-spinner input {
+ // stop jQuery UI spinner inputs from inheriting FMS input styles
+ padding: 1px;
+ border: none;
+ border-radius: 0;
+}
+
+.square-map__outer {
+ width: 100%;
+ height: 0;
+ padding-bottom: 100%; // 100% of parent WIDTH!! Makes a square element.
+ position: relative;
+}
+
+.square-map__inner {
+ position: absolute; // Parent must keep its 0 height, so we need to create a new container for tiles.
+ top: 0;
+ left: 0;
+ right: 0;
+ bottom: 0;
+
+ #drag .square-map__tile {
+ position: static; // override position:absolute
+ }
+}
+
+#map_box {
+ top: 0em; // the default, 3em, overlaps the content below
+}
+
+@media screen {
+ dd.screen-no-space-after {
+ margin-bottom: 0;
+ }
+
+ .admin-report-edit--interact dl.with-message {
+ margin-top: 1.5em;
+ }
+}
+
+@media print {
+ #site-header .container {
+ position: relative;
+ }
+ #site-logo {
+ top: 0;
+ }
+
+ .mappage.admin {
+ .container {
+ padding: 0;
+ position: relative;
+ }
+
+ .content {
+ overflow: auto;
+ font-size: 0.8em;
+ background: transparent url(/cobrands/zurich/admin-print-columns.gif) top center repeat-y;
+ min-height: 0 !important; // override hard-coded inline min-height style
+
+ form {
+ @include clearfix; // because .admin-report-edit children are floated
+ }
+ }
+
+ #map_box {
+ display: none; // Zurich has its own clone of the map, inside admin-report-edit--interact
+ }
+ }
+
+ .admin-report-edit {
+ margin-top: 1em;
+ width: 47%;
+
+ input[type=text],
+ textarea {
+ border: none;
+ padding: 0;
+ }
+
+ dd {
+ padding-left: 1em;
+ }
+
+ h2 {
+ font-family: inherit;
+ font-size: inherit;
+ font-weight: bold;
+ }
+ }
+
+ .admin-report-edit--details {
+ float: left;
+ border-right: 1px solid #ddd;
+ padding-right: 3%;
+ }
+
+ .admin-report-edit--interact {
+ float: right;
+ }
+
+ .map_clone {
+ -webkit-transform: none;
+ -ms-transform: none;
+ transform: none;
+ }
+
+ dd.print-no-space-after {
+ margin-bottom: 0;
+ }
+
+ #print_report_map {
+ page-break-before: always;
+ }
+}
diff --git a/web/cobrands/zurich/layout.scss b/web/cobrands/zurich/layout.scss
index d22d753ca..3a20d05c5 100644
--- a/web/cobrands/zurich/layout.scss
+++ b/web/cobrands/zurich/layout.scss
@@ -111,9 +111,6 @@ body.mappage {
padding-top: 18px;
background: #fff url(logo_portal.x.jpg) top left repeat-x;
}
- #site-logo {
- margin-left: 10px;
- }
.content {
margin-top: 1em;
}
@@ -242,10 +239,52 @@ body.fullwidthpage.admin .content {
width: 100%;
}
-body.mappage.admin .content {
- margin-top: 6em;
- margin-left: 0.5em;
+body.mappage.admin {
+ .content {
+ margin-top: 5em;
+ margin-left: 0;
+ padding: 0px;
+ width: 40em;
+ background: #fff url(/cobrands/zurich/admin-faux-columns.gif) top center repeat-y;
+ @include box-shadow(0 0 5px rgba(0,0,0,0.5));
+ }
+}
+
+.admin-report-edit {
+ padding: 1em;
+ width: 50%;
+ float: right;
+ font-size: 0.8em;
+ box-sizing: border-box;
+
+ button, input[type="submit"], .btn {
+ padding: 0.5em 0.5em 0.3em 0.5em;
+ text-transform: none;
+ }
+
+ h2 {
+ font-family: inherit;
+ font-size: inherit;
+ font-weight: bold;
+ }
+}
+
+.admin-report-edit--details {
+ label[for="title"],
+ label[for="detail"] {
+ display: none;
+ }
+
+ #title {
+ margin-top: 1em;
+ font-weight: bold;
+ }
+
+ #detail {
+ margin-bottom: 1em;
+ }
}
+
.admin {
.content {
margin: 2em 0 1em;
@@ -263,22 +302,48 @@ body.mappage.admin .content {
font-weight: bold;
padding-right: 0.333em;
}
+ :first-child > label {
+ // avoid empty space above first label in a container
+ margin-top: 0;
+ }
+ textarea {
+ min-height: 0;
+ }
+ }
+
+ button, input[type=submit], .btn {
+ &.delete {
+ font-size: 0.75em;
+ color: #933;
+ margin: 2em 0;
+
+ &:hover {
+ @include background(linear-gradient(#fcc, #daa 50%));
+ };
+ }
}
#zurich-footer {
margin: 2em auto 3em auto;
}
+
+ .message-updated {
+ color: #060;
+ font-weight: bold;
+ position: absolute;
+ }
}
.admin-nav-wrapper {
background-color: white;
padding: 1.5em 0 1em;
}
+
body.mappage .admin-nav-wrapper {
box-sizing: border-box;
padding-left: 10px;
padding-right: 10px;
position: fixed;
width: 100%;
- @include box-shadow(0 0 6px 1px #000);
+ @include box-shadow(0 0 5px rgba(0,0,0,0.5));
}
diff --git a/web/js/map-wmts-zurich.js b/web/js/map-wmts-zurich.js
index 54b932168..dc81c967f 100644
--- a/web/js/map-wmts-zurich.js
+++ b/web/js/map-wmts-zurich.js
@@ -81,37 +81,170 @@ $(function(){
OpenLayers.DOTS_PER_INCH = 96;
fixmystreet.map_options = {
- maxExtent: new OpenLayers.Bounds(676000, 241000, 690000, 255000),
+ maxExtent: new OpenLayers.Bounds(676000, 241402, 689896, 254596),
units: 'm',
- scales: [ '64000', '32000', '16000', '8000', '4000', '2000', '1000', '500' ]
+ scales: [ '64000', '32000', '16000', '8000', '4000', '2000', '1000', '500', '250' ]
};
var layer_options = {
projection: new OpenLayers.Projection("EPSG:21781"),
- name: "Hybrid",
- layer: "Hybrid",
- matrixSet: "nativeTileMatrixSet",
+ name: "tiled_LuftbildHybrid",
+ layer: "tiled_LuftbildHybrid",
+ matrixSet: "default028mm",
requestEncoding: "REST",
- url: "/maps/Hybrid/",
+ url: "http://www.gis.stadt-zuerich.ch/maps/rest/services/tiled/LuftbildHybrid/MapServer/WMTS/tile/",
style: "default",
matrixIds: [
- //{ identifier: "0", matrixHeight: 2, matrixWidth: 2, scaleDenominator: 250000, supportedCRS: "urn:ogc:def:crs:EPSG::21781", tileHeight: 256, tileWidth: 256, topLeftCorner: { lat: 30814423, lon: -29386322 } },
- //{ identifier: "1", matrixHeight: 3, matrixWidth: 3, scaleDenominator: 125000, supportedCRS: "urn:ogc:def:crs:EPSG::21781", tileHeight: 256, tileWidth: 256, topLeftCorner: { lat: 30814423, lon: -29386322 } },
- { identifier: "2", matrixHeight: 4, matrixWidth: 5, scaleDenominator: 64000, supportedCRS: "urn:ogc:def:crs:EPSG::21781", tileHeight: 256, tileWidth: 256, topLeftCorner: { lat: 30814423, lon: -29386322 } },
- { identifier: "3", matrixHeight: 7, matrixWidth: 8, scaleDenominator: 32000, supportedCRS: "urn:ogc:def:crs:EPSG::21781", tileHeight: 256, tileWidth: 256, topLeftCorner: { lat: 30814423, lon: -29386322 } },
- { identifier: "4", matrixHeight: 14, matrixWidth: 14, scaleDenominator: 16000, supportedCRS: "urn:ogc:def:crs:EPSG::21781", tileHeight: 256, tileWidth: 256, topLeftCorner: { lat: 30814423, lon: -29386322 } },
- { identifier: "5", matrixHeight: 27, matrixWidth: 27, scaleDenominator: 8000, supportedCRS: "urn:ogc:def:crs:EPSG::21781", tileHeight: 256, tileWidth: 256, topLeftCorner: { lat: 30814423, lon: -29386322 } },
- { identifier: "6", matrixHeight: 52, matrixWidth: 53, scaleDenominator: 4000, supportedCRS: "urn:ogc:def:crs:EPSG::21781", tileHeight: 256, tileWidth: 256, topLeftCorner: { lat: 30814423, lon: -29386322 } },
- { identifier: "7", matrixHeight: 104, matrixWidth: 105, scaleDenominator: 2000, supportedCRS: "urn:ogc:def:crs:EPSG::21781", tileHeight: 256, tileWidth: 256, topLeftCorner: { lat: 30814423, lon: -29386322 } },
- { identifier: "8", matrixHeight: 208, matrixWidth: 208, scaleDenominator: 1000, supportedCRS: "urn:ogc:def:crs:EPSG::21781", tileHeight: 256, tileWidth: 256, topLeftCorner: { lat: 30814423, lon: -29386322 } },
- { identifier: "9", matrixHeight: 415, matrixWidth: 414, scaleDenominator: 500, supportedCRS: "urn:ogc:def:crs:EPSG::21781", tileHeight: 256, tileWidth: 256, topLeftCorner: { lat: 30814423, lon: -29386322 } }
+ // {
+ // "identifier": "0",
+ // "matrixHeight": 903,
+ // "matrixWidth": 889,
+ // "scaleDenominator": 236235.59151877242,
+ // "supportedCRS": "urn:ogc:def:crs:EPSG::21781",
+ // "tileHeight": 512,
+ // "tileWidth": 512,
+ // "topLeftCorner": {
+ // "lat": 30814423,
+ // "lon": -29386322
+ // }
+ // },
+ // {
+ // "identifier": "1",
+ // "matrixHeight": 1806,
+ // "matrixWidth": 1777,
+ // "scaleDenominator": 118117.79575938621,
+ // "supportedCRS": "urn:ogc:def:crs:EPSG::21781",
+ // "tileHeight": 512,
+ // "tileWidth": 512,
+ // "topLeftCorner": {
+ // "lat": 30814423,
+ // "lon": -29386322
+ // }
+ // },
+ {
+ "identifier": "2",
+ "matrixHeight": 3527,
+ "matrixWidth": 3470,
+ "scaleDenominator": 60476.31142880573,
+ "supportedCRS": "urn:ogc:def:crs:EPSG::21781",
+ "tileHeight": 512,
+ "tileWidth": 512,
+ "topLeftCorner": {
+ "lat": 30814423,
+ "lon": -29386322
+ }
+ },
+ {
+ "identifier": "3",
+ "matrixHeight": 7053,
+ "matrixWidth": 6939,
+ "scaleDenominator": 30238.155714402867,
+ "supportedCRS": "urn:ogc:def:crs:EPSG::21781",
+ "tileHeight": 512,
+ "tileWidth": 512,
+ "topLeftCorner": {
+ "lat": 30814423,
+ "lon": -29386322
+ }
+ },
+ {
+ "identifier": "4",
+ "matrixHeight": 14106,
+ "matrixWidth": 13877,
+ "scaleDenominator": 15119.077857201433,
+ "supportedCRS": "urn:ogc:def:crs:EPSG::21781",
+ "tileHeight": 512,
+ "tileWidth": 512,
+ "topLeftCorner": {
+ "lat": 30814423,
+ "lon": -29386322
+ }
+ },
+ {
+ "identifier": "5",
+ "matrixHeight": 28211,
+ "matrixWidth": 27753,
+ "scaleDenominator": 7559.538928600717,
+ "supportedCRS": "urn:ogc:def:crs:EPSG::21781",
+ "tileHeight": 512,
+ "tileWidth": 512,
+ "topLeftCorner": {
+ "lat": 30814423,
+ "lon": -29386322
+ }
+ },
+ {
+ "identifier": "6",
+ "matrixHeight": 56422,
+ "matrixWidth": 55505,
+ "scaleDenominator": 3779.7694643003583,
+ "supportedCRS": "urn:ogc:def:crs:EPSG::21781",
+ "tileHeight": 512,
+ "tileWidth": 512,
+ "topLeftCorner": {
+ "lat": 30814423,
+ "lon": -29386322
+ }
+ },
+ {
+ "identifier": "7",
+ "matrixHeight": 112844,
+ "matrixWidth": 111010,
+ "scaleDenominator": 1889.8847321501792,
+ "supportedCRS": "urn:ogc:def:crs:EPSG::21781",
+ "tileHeight": 512,
+ "tileWidth": 512,
+ "topLeftCorner": {
+ "lat": 30814423,
+ "lon": -29386322
+ }
+ },
+ {
+ "identifier": "8",
+ "matrixHeight": 225687,
+ "matrixWidth": 222020,
+ "scaleDenominator": 944.9423660750896,
+ "supportedCRS": "urn:ogc:def:crs:EPSG::21781",
+ "tileHeight": 512,
+ "tileWidth": 512,
+ "topLeftCorner": {
+ "lat": 30814423,
+ "lon": -29386322
+ }
+ },
+ {
+ "identifier": "9",
+ "matrixHeight": 451374,
+ "matrixWidth": 444039,
+ "scaleDenominator": 472.4711830375448,
+ "supportedCRS": "urn:ogc:def:crs:EPSG::21781",
+ "tileHeight": 512,
+ "tileWidth": 512,
+ "topLeftCorner": {
+ "lat": 30814423,
+ "lon": -29386322
+ }
+ },
+ {
+ "identifier": "10",
+ "matrixHeight": 902748,
+ "matrixWidth": 888078,
+ "scaleDenominator": 236.2355915187724,
+ "supportedCRS": "urn:ogc:def:crs:EPSG::21781",
+ "tileHeight": 512,
+ "tileWidth": 512,
+ "topLeftCorner": {
+ "lat": 30814423,
+ "lon": -29386322
+ }
+ }
]
};
fixmystreet.layer_options = [
layer_options, OpenLayers.Util.applyDefaults({
- name: "Stadtplan",
- layer: "Stadtplan",
- url: "/maps/Stadtplan/"
+ name: "Stadtplan3D",
+ layer: "Stadtplan3D",
+ url: "http://www.gis.stadt-zuerich.ch/maps/rest/services/tiled/Stadtplan3D/MapServer/WMTS/tile/"
}, layer_options)
];