diff options
-rwxr-xr-x | bin/update-schema | 1 | ||||
-rw-r--r-- | db/downgrade_0037---0036.sql | 1 | ||||
-rw-r--r-- | db/schema.sql | 9 | ||||
-rw-r--r-- | db/schema_0037-response-templates.sql | 8 | ||||
-rw-r--r-- | perllib/FixMyStreet/App/Controller/Admin.pm | 79 | ||||
-rw-r--r-- | perllib/FixMyStreet/App/View/Web.pm | 3 | ||||
-rw-r--r-- | perllib/FixMyStreet/Cobrand/Zurich.pm | 4 | ||||
-rw-r--r-- | perllib/FixMyStreet/DB/Result/Body.pm | 22 | ||||
-rw-r--r-- | perllib/FixMyStreet/DB/Result/Problem.pm | 23 | ||||
-rw-r--r-- | perllib/FixMyStreet/DB/Result/ResponseTemplate.pm | 49 | ||||
-rw-r--r-- | templates/web/zurich/admin/body-form.html | 1 | ||||
-rw-r--r-- | templates/web/zurich/admin/header.html | 1 | ||||
-rw-r--r-- | templates/web/zurich/admin/report_edit.html | 2 | ||||
-rw-r--r-- | templates/web/zurich/admin/response_templates_select.html | 25 | ||||
-rw-r--r-- | templates/web/zurich/admin/template_edit.html | 38 | ||||
-rw-r--r-- | templates/web/zurich/admin/templates.html | 28 | ||||
-rw-r--r-- | templates/web/zurich/header.html | 5 | ||||
-rw-r--r-- | web/cobrands/zurich/layout.scss | 12 |
18 files changed, 300 insertions, 11 deletions
diff --git a/bin/update-schema b/bin/update-schema index d40df1689..d98fe6e9c 100755 --- a/bin/update-schema +++ b/bin/update-schema @@ -195,6 +195,7 @@ 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 '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/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/schema.sql b/db/schema.sql index 2db89bddb..e87a2aafe 100644 --- a/db/schema.sql +++ b/db/schema.sql @@ -457,3 +457,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/perllib/FixMyStreet/App/Controller/Admin.pm b/perllib/FixMyStreet/App/Controller/Admin.pm index 7ead7db16..be705110b 100644 --- a/perllib/FixMyStreet/App/Controller/Admin.pm +++ b/perllib/FixMyStreet/App/Controller/Admin.pm @@ -819,6 +819,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->req->param('delete_template') eq _("Delete template")) { + $template->delete; + } else { + $template->title( $c->req->param('title') ); + $template->text ( $c->req->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 ) = @_; 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/Zurich.pm b/perllib/FixMyStreet/Cobrand/Zurich.pm index 3c1baaa48..46d57158b 100644 --- a/perllib/FixMyStreet/Cobrand/Zurich.pm +++ b/perllib/FixMyStreet/Cobrand/Zurich.pm @@ -9,6 +9,7 @@ use Scalar::Util 'blessed'; use strict; use warnings; use feature 'say'; +use utf8; =head1 NAME @@ -303,6 +304,7 @@ sub admin_pages { $pages = { %$pages, 'bodies' => [_('Bodies'), 1], 'body' => [undef, undef], + 'templates' => [_('Templates'), 2], }; return $pages if $type eq 'dm'; @@ -450,7 +452,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'); } 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 635c41382..d3a30db4e 100644 --- a/perllib/FixMyStreet/DB/Result/Problem.pm +++ b/perllib/FixMyStreet/DB/Result/Problem.pm @@ -643,7 +643,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! 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/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..a7ae7fb56 100644 --- a/templates/web/zurich/admin/header.html +++ b/templates/web/zurich/admin/header.html @@ -19,6 +19,7 @@ .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/report_edit.html b/templates/web/zurich/admin/report_edit.html index 02c396e1f..d2c1760ff 100644 --- a/templates/web/zurich/admin/report_edit.html +++ b/templates/web/zurich/admin/report_edit.html @@ -194,7 +194,7 @@ $(function(){ [% END %] <li><label for="status_update">[% loc('Public response:') %]</label> - + [% INCLUDE 'admin/response_templates_select.html' for='status_update' %] <textarea name='status_update' id='status_update' cols=60 rows=5> [%- IF problem.extra.public_response -%] [%- problem.extra.public_response | 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..a16032790 --- /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="">Choose a template</option> +[% FOR t IN response_templates %] + <option value="[% t.id %]"> [% t.title | html %] </option> +[% END %] +</select> +</p> +<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/template_edit.html b/templates/web/zurich/admin/template_edit.html new file mode 100644 index 000000000..e3e4fe190 --- /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 %] + Template «[% rt.title %]» + [% ELSE %] + 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> </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/header.html b/templates/web/zurich/header.html index 78ed678f6..7e88f3f0f 100644 --- a/templates/web/zurich/header.html +++ b/templates/web/zurich/header.html @@ -72,6 +72,11 @@ <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"> <input type="text" name="search" size="20" id="search" placeholder="[% loc('Search reports') %]"> diff --git a/web/cobrands/zurich/layout.scss b/web/cobrands/zurich/layout.scss index d0b24b49c..c753e2081 100644 --- a/web/cobrands/zurich/layout.scss +++ b/web/cobrands/zurich/layout.scss @@ -262,6 +262,18 @@ body.mappage.admin .content { } } + 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; } |