From bb9ccbe08bc39f7a37aa8d9054b95f977d8629bb Mon Sep 17 00:00:00 2001 From: Matthew Somerville Date: Tue, 7 Jun 2016 12:32:26 +0100 Subject: Fix annoying jump when "Get updates" drawer opened --- templates/web/base/report/display_tools.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/templates/web/base/report/display_tools.html b/templates/web/base/report/display_tools.html index 004ae29e5..c1413d9c7 100644 --- a/templates/web/base/report/display_tools.html +++ b/templates/web/base/report/display_tools.html @@ -30,10 +30,10 @@
- +

[% loc('RSS feed of updates to this problem' ) %] -

[% loc('Receive email when updates are left on this problem.' ) %]

+ [% loc('Receive email when updates are left on this problem.' ) %]

-- cgit v1.2.3 From f48f6862dd45c2bbf8ea8a9c7a1762d0242d7195 Mon Sep 17 00:00:00 2001 From: Matthew Somerville Date: Tue, 7 Jun 2016 13:16:51 +0100 Subject: Stop using Text::Wrap to wrap email bodies. If we don't do this, the default quoted-printable encoding will make sure the lines are physically wrapped anyway. format=flowed could be an alternative, but I think "=" acting as a quasi-hyphen is somewhat nicer than every line ending with "=20". A better solution could be quoted-printable doing soft wrapping only at word breaks, making each line be readable though end with a " =", but that didn't seem worth the effort involved. --- perllib/FixMyStreet/Email.pm | 8 -------- t/app/helpers/send_email_sample.txt | 14 +++++++------- t/app/helpers/send_email_sample_mime.txt | 14 +++++++------- t/cobrand/zurich_attachments.txt | 2 +- 4 files changed, 15 insertions(+), 23 deletions(-) diff --git a/perllib/FixMyStreet/Email.pm b/perllib/FixMyStreet/Email.pm index d4bfee14e..3d363f80d 100644 --- a/perllib/FixMyStreet/Email.pm +++ b/perllib/FixMyStreet/Email.pm @@ -11,7 +11,6 @@ use Encode; use POSIX qw(); use Template; use Digest::HMAC_SHA1 qw(hmac_sha1_hex); -use Text::Wrap; use mySociety::Locale; use mySociety::Random qw(random_bytes); use Utils::Email; @@ -189,13 +188,6 @@ sub construct_email ($) { # nor followed (?!\n) by a blank line with a single space". $body =~ s#(?{Subject} = $subject if defined($subject); if (!exists($p->{Subject})) { diff --git a/t/app/helpers/send_email_sample.txt b/t/app/helpers/send_email_sample.txt index 87604008c..05303f4b4 100644 --- a/t/app/helpers/send_email_sample.txt +++ b/t/app/helpers/send_email_sample.txt @@ -14,13 +14,13 @@ utf8: =E6=88=91=E4=BB=AC=E5=BA=94=E8=AF=A5=E8=83=BD=E5=A4=9F=E6=97=A0=E7=BC= 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. +long line: Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do= + eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad min= +im veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea = +commodo consequat. Duis aute irure dolor in reprehenderit in voluptate veli= +t esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupi= +datat non proident, sunt in culpa qui officia deserunt mollit anim id est l= +aborum. Yours,=20=20 FixMyStreet.= diff --git a/t/app/helpers/send_email_sample_mime.txt b/t/app/helpers/send_email_sample_mime.txt index 1747204f7..cbfe12b29 100644 --- a/t/app/helpers/send_email_sample_mime.txt +++ b/t/app/helpers/send_email_sample_mime.txt @@ -19,13 +19,13 @@ utf8: =E6=88=91=E4=BB=AC=E5=BA=94=E8=AF=A5=E8=83=BD=E5=A4=9F=E6=97=A0=E7=BC= 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. +long line: Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do= + eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad min= +im veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea = +commodo consequat. Duis aute irure dolor in reprehenderit in voluptate veli= +t esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupi= +datat non proident, sunt in culpa qui officia deserunt mollit anim id est l= +aborum. Yours,=20=20 FixMyStreet.= diff --git a/t/cobrand/zurich_attachments.txt b/t/cobrand/zurich_attachments.txt index bdc4333bf..bf8d6872b 100644 --- a/t/cobrand/zurich_attachments.txt +++ b/t/cobrand/zurich_attachments.txt @@ -14,7 +14,7 @@ Gr=C3=BCezi External Body, =C3=96ffentliche URL: http://www.example.org/report/REPORT_ID -Bei Fragen zu "Z=C3=BCri wie neu" wenden Sie sich bitte an +Bei Fragen zu "Z=C3=BCri wie neu" wenden Sie sich bitte an = gis-zentrum@zuerich.ch.= --BOUNDARY -- cgit v1.2.3 From 525c7f29761a158748cd068e3432115cd25b9f4c Mon Sep 17 00:00:00 2001 From: Matthew Somerville Date: Tue, 7 Jun 2016 14:05:58 +0100 Subject: Strip line end spaces in emails. --- perllib/FixMyStreet/Email.pm | 1 + t/app/helpers/send_email_sample.txt | 2 +- t/app/helpers/send_email_sample_mime.txt | 2 +- templates/email/fixmystreet/signature.txt | 2 +- 4 files changed, 4 insertions(+), 3 deletions(-) diff --git a/perllib/FixMyStreet/Email.pm b/perllib/FixMyStreet/Email.pm index 3d363f80d..ce7dad47a 100644 --- a/perllib/FixMyStreet/Email.pm +++ b/perllib/FixMyStreet/Email.pm @@ -187,6 +187,7 @@ sub construct_email ($) { # regex means, "replace any line ending that is neither preceded (?{Subject} = $subject if defined($subject); diff --git a/t/app/helpers/send_email_sample.txt b/t/app/helpers/send_email_sample.txt index 05303f4b4..68fe61f0e 100644 --- a/t/app/helpers/send_email_sample.txt +++ b/t/app/helpers/send_email_sample.txt @@ -22,5 +22,5 @@ t esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupi= datat non proident, sunt in culpa qui officia deserunt mollit anim id est l= aborum. -Yours,=20=20 +Yours, FixMyStreet.= diff --git a/t/app/helpers/send_email_sample_mime.txt b/t/app/helpers/send_email_sample_mime.txt index cbfe12b29..7b4ce91f6 100644 --- a/t/app/helpers/send_email_sample_mime.txt +++ b/t/app/helpers/send_email_sample_mime.txt @@ -27,7 +27,7 @@ t esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupi= datat non proident, sunt in culpa qui officia deserunt mollit anim id est l= aborum. -Yours,=20=20 +Yours, FixMyStreet.= --BOUNDARY diff --git a/templates/email/fixmystreet/signature.txt b/templates/email/fixmystreet/signature.txt index 14b7d83e7..834e69b9d 100644 --- a/templates/email/fixmystreet/signature.txt +++ b/templates/email/fixmystreet/signature.txt @@ -2,7 +2,7 @@ All the best, The FixMyStreet team -https://www.FixMyStreet.com +https://www.FixMyStreet.com Twitter: https://twitter.com/FixMyStreet Facebook: http://www.facebook.com/fixmystreet -- cgit v1.2.3 From 49782c333a340a667009eed261d0ef0ceb419f88 Mon Sep 17 00:00:00 2001 From: Matthew Somerville Date: Wed, 8 Jun 2016 12:31:46 +0100 Subject: Redirect correctly if filter used sans JavaScript. It was being treated as a new report and showing errors, rather than showing you the same page with updated filters. Fixes #1422. --- perllib/FixMyStreet/App/Controller/Report/New.pm | 7 +++++-- templates/web/base/reports/_list-filters.html | 2 +- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/perllib/FixMyStreet/App/Controller/Report/New.pm b/perllib/FixMyStreet/App/Controller/Report/New.pm index 76098c119..696234d32 100644 --- a/perllib/FixMyStreet/App/Controller/Report/New.pm +++ b/perllib/FixMyStreet/App/Controller/Report/New.pm @@ -83,8 +83,9 @@ sub report_new : Path : Args(0) { $c->forward('initialize_report'); # work out the location for this report and do some checks + # Also show map if we're just updating the filters return $c->forward('redirect_to_around') - unless $c->forward('determine_location'); + if $c->get_param('filter_update') || !$c->forward('determine_location'); # create a problem from the submitted details $c->stash->{template} = "report/new/fill_in_details.html"; @@ -1229,10 +1230,12 @@ sub redirect_to_around : Private { my ( $self, $c ) = @_; my $params = { - pc => ( $c->stash->{pc} || $c->get_param('pc') || '' ), lat => $c->stash->{latitude}, lon => $c->stash->{longitude}, }; + foreach (qw(pc zoom status filter_category)) { + $params->{$_} = $c->get_param($_); + } # delete empty values for ( keys %$params ) { diff --git a/templates/web/base/reports/_list-filters.html b/templates/web/base/reports/_list-filters.html index 4dd270dc6..d6f091aaa 100644 --- a/templates/web/base/reports/_list-filters.html +++ b/templates/web/base/reports/_list-filters.html @@ -25,7 +25,7 @@

[% tprintf(loc(' ', 'The first %s is a dropdown of all/fixed/etc, the second is a dropdown of categories'), select_status, select_category) %] - +

[% IF use_section_wrapper %] -- cgit v1.2.3 From 25adf6e4187085bd48d96c808483a6a4fcfc6ebc Mon Sep 17 00:00:00 2001 From: Matthew Somerville Date: Fri, 17 Jun 2016 11:08:18 +0100 Subject: Don't update the map pins if a new report started. --- web/js/map-OpenLayers.js | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/web/js/map-OpenLayers.js b/web/js/map-OpenLayers.js index 267643898..d1dba631e 100644 --- a/web/js/map-OpenLayers.js +++ b/web/js/map-OpenLayers.js @@ -646,6 +646,17 @@ OpenLayers.Protocol.FixMyStreet = OpenLayers.Class(OpenLayers.Protocol.HTTP, { /* Pan data handler */ OpenLayers.Format.FixMyStreet = OpenLayers.Class(OpenLayers.Format.JSON, { read: function(json, filter) { + // Check we haven't received the data after the map has been clicked. + if (fixmystreet.page == 'new') { + // If we have, we want to do nothing, which means returning an + // array of the back-projected version of the current pin + var pin = fixmystreet.markers.features[0].clone(); + pin.geometry.transform( + fixmystreet.map.getProjectionObject(), + new OpenLayers.Projection("EPSG:4326") + ); + return [ pin ]; + } if (typeof json == 'string') { obj = OpenLayers.Format.JSON.prototype.read.apply(this, [json, filter]); } else { -- cgit v1.2.3 From 5aaf27a430686748c6ec1f672ff3c1124cfab793 Mon Sep 17 00:00:00 2001 From: Matthew Somerville Date: Wed, 15 Jun 2016 18:02:02 +0100 Subject: Fix display in IE7, including front page text. .tablewrapper was sometimes losing its background, it needs to be given hasLayout. --- web/cobrands/sass/_layout.scss | 1 + 1 file changed, 1 insertion(+) diff --git a/web/cobrands/sass/_layout.scss b/web/cobrands/sass/_layout.scss index 02dab82d8..5ed4ddb97 100644 --- a/web/cobrands/sass/_layout.scss +++ b/web/cobrands/sass/_layout.scss @@ -532,6 +532,7 @@ body.authpage { //fix table to be a block for ie, float the children .ie6, .ie7 { .tablewrapper { + *zoom: 1; display:block; div {//ie6 doesn't support '>div', so we'll go with the somewhat risker 'div' width:48%; -- cgit v1.2.3 From e0f1d53bb7aed17dd3a932cca6b933b94a6d1e5b Mon Sep 17 00:00:00 2001 From: Matthew Somerville Date: Fri, 17 Jun 2016 10:47:18 +0100 Subject: Add forgotten password help to general auth page. Match the help given in new report/update form. --- templates/web/base/auth/general.html | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/templates/web/base/auth/general.html b/templates/web/base/auth/general.html index 253dc26a1..a8bf8f1e0 100644 --- a/templates/web/base/auth/general.html +++ b/templates/web/base/auth/general.html @@ -86,8 +86,15 @@
- - +
+ + +
+ +
+

[% loc('Forgotten your password?') %] + [% loc('Sign in by email instead, providing a new password. When you click the link in your email, your password will be updated.') %]

+
[% END %] -- cgit v1.2.3 From f0911da291b55801e69132a4d6f0a312089fdc18 Mon Sep 17 00:00:00 2001 From: Matthew Somerville Date: Wed, 15 Jun 2016 20:15:40 +0100 Subject: Improve auth flow taken when return key used. --- perllib/FixMyStreet/App/Controller/Auth.pm | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/perllib/FixMyStreet/App/Controller/Auth.pm b/perllib/FixMyStreet/App/Controller/Auth.pm index c5a6cf9bf..203479253 100644 --- a/perllib/FixMyStreet/App/Controller/Auth.pm +++ b/perllib/FixMyStreet/App/Controller/Auth.pm @@ -37,16 +37,17 @@ sub general : Path : Args(0) { # all done unless we have a form posted to us return unless $c->req->method eq 'POST'; - # decide which action to take - $c->detach('facebook_sign_in') if $c->get_param('facebook_sign_in'); - $c->detach('twitter_sign_in') if $c->get_param('twitter_sign_in'); - - my $clicked_password = $c->get_param('sign_in'); my $clicked_email = $c->get_param('email_sign_in'); + my $data_address = $c->get_param('email'); my $data_password = $c->get_param('password_sign_in'); my $data_email = $c->get_param('name') || $c->get_param('password_register'); + # decide which action to take $c->detach('email_sign_in') if $clicked_email || ($data_email && !$data_password); + if (!$data_address && !$data_password && !$data_email) { + $c->detach('facebook_sign_in') if $c->get_param('facebook_sign_in'); + $c->detach('twitter_sign_in') if $c->get_param('twitter_sign_in'); + } $c->forward( 'sign_in' ) && $c->detach( 'redirect_on_signin', [ $c->get_param('r') ] ); -- cgit v1.2.3 From 9d8ae07980bccd58e11acbc82e60b651ed20c181 Mon Sep 17 00:00:00 2001 From: Matthew Somerville Date: Wed, 15 Jun 2016 20:14:51 +0100 Subject: Improve CSRF tokens and add to more forms. --- perllib/FixMyStreet/App/Controller/Admin.pm | 70 +++++-------------- perllib/FixMyStreet/App/Controller/Alert.pm | 6 ++ perllib/FixMyStreet/App/Controller/Around.pm | 2 + perllib/FixMyStreet/App/Controller/Auth.pm | 40 ++++++++++- perllib/FixMyStreet/App/Controller/Moderate.pm | 2 + perllib/FixMyStreet/App/Controller/Report.pm | 3 + perllib/FixMyStreet/App/Controller/Report/New.pm | 2 + .../FixMyStreet/App/Controller/Report/Update.pm | 1 + perllib/FixMyStreet/Cobrand/Zurich.pm | 6 +- t/app/controller/alert_new.t | 12 ++-- t/app/controller/auth.t | 2 +- t/app/controller/moderate.t | 76 ++++++++++---------- t/app/controller/photo.t | 7 +- t/app/controller/report_updates.t | 80 ++++------------------ t/cobrand/zurich.t | 11 +-- templates/web/base/admin/body-form.html | 2 +- templates/web/base/admin/body.html | 4 +- templates/web/base/admin/category_edit.html | 2 +- templates/web/base/admin/report_edit.html | 2 +- templates/web/base/admin/update_edit.html | 2 +- templates/web/base/admin/user-form.html | 2 +- templates/web/base/alert/_list.html | 1 + templates/web/base/alert/updates.html | 1 + templates/web/base/around/display_location.html | 1 + templates/web/base/auth/change_password.html | 3 +- templates/web/base/report/_main.html | 1 + templates/web/base/report/display_tools.html | 2 + templates/web/base/report/new/fill_in_details.html | 5 +- templates/web/base/report/update-form.html | 1 + templates/web/base/report/update.html | 1 + templates/web/bromley/report/display.html | 1 + templates/web/eastsussex/report/update-form.html | 2 + .../web/seesomething/around/display_location.html | 1 + templates/web/zurich/admin/body-form.html | 2 +- templates/web/zurich/admin/body.html | 2 +- templates/web/zurich/admin/report_edit-sdm.html | 2 +- templates/web/zurich/admin/report_edit.html | 2 +- templates/web/zurich/admin/template_edit.html | 2 +- templates/web/zurich/admin/update_edit.html | 2 +- 39 files changed, 172 insertions(+), 194 deletions(-) diff --git a/perllib/FixMyStreet/App/Controller/Admin.pm b/perllib/FixMyStreet/App/Controller/Admin.pm index 4e288556f..72c6baad3 100644 --- a/perllib/FixMyStreet/App/Controller/Admin.pm +++ b/perllib/FixMyStreet/App/Controller/Admin.pm @@ -215,7 +215,7 @@ sub bodies : Path('bodies') : Args(0) { return; } - $c->forward( 'get_token' ); + $c->forward( '/auth/get_csrf_token' ); my $edit_activity = $c->model('DB::ContactsHistory')->search( undef, @@ -232,7 +232,7 @@ sub bodies : Path('bodies') : Args(0) { my $posted = $c->get_param('posted') || ''; if ( $posted eq 'body' ) { $c->forward('check_for_super_user'); - $c->forward('check_token'); + $c->forward('/auth/check_csrf_token'); my $params = $c->forward('body_params'); my $body = $c->model('DB::Body')->create( $params ); @@ -289,7 +289,7 @@ sub body : Path('body') : Args(1) { $c->stash->{body_id} = $body_id; $c->forward( 'check_for_super_user' ); - $c->forward( 'get_token' ); + $c->forward( '/auth/get_csrf_token' ); $c->forward( 'lookup_body' ); $c->forward( 'fetch_all_bodies' ); $c->forward( 'body_form_dropdowns' ); @@ -318,7 +318,7 @@ sub update_contacts : Private { my $editor = $c->forward('get_user'); if ( $posted eq 'new' ) { - $c->forward('check_token'); + $c->forward('/auth/check_csrf_token'); my %errors; @@ -370,7 +370,7 @@ sub update_contacts : Private { } } elsif ( $posted eq 'update' ) { - $c->forward('check_token'); + $c->forward('/auth/check_csrf_token'); my @categories = $c->get_param_list('confirmed'); @@ -393,7 +393,7 @@ sub update_contacts : Private { $c->stash->{updated} = _('Values updated'); } elsif ( $posted eq 'body' ) { $c->forward('check_for_super_user'); - $c->forward('check_token'); + $c->forward('/auth/check_csrf_token'); my $params = $c->forward( 'body_params' ); $c->stash->{body}->update( $params ); @@ -476,7 +476,7 @@ sub category_edit : Path('body') : Args(2) { $c->stash->{body_id} = $body_id; - $c->forward( 'get_token' ); + $c->forward( '/auth/get_csrf_token' ); $c->forward( 'lookup_body' ); my $contact = $c->stash->{body}->contacts->search( { category => $category } )->first; @@ -643,7 +643,7 @@ sub report_edit : Path('report_edit') : Args(1) { $c->stash->{problem} = $problem; - $c->forward('get_token'); + $c->forward('/auth/get_csrf_token'); if ( $c->cobrand->moniker eq 'zurich' ) { $c->stash->{page} = 'admin'; @@ -689,7 +689,7 @@ sub report_edit : Path('report_edit') : Args(1) { ->all ]; if ( $c->get_param('resend') ) { - $c->forward('check_token'); + $c->forward('/auth/check_csrf_token'); $problem->whensent(undef); $problem->update(); @@ -699,7 +699,7 @@ sub report_edit : Path('report_edit') : Args(1) { $c->forward( 'log_edit', [ $id, 'problem', 'resend' ] ); } elsif ( $c->get_param('mark_sent') ) { - $c->forward('check_token'); + $c->forward('/auth/check_csrf_token'); $problem->whensent(\'current_timestamp'); $problem->update(); $c->stash->{status_message} = '

' . _('That problem has been marked as sent.') . '

'; @@ -717,7 +717,7 @@ sub report_edit : Path('report_edit') : Args(1) { $c->forward('ban_user'); } elsif ( $c->get_param('submit') ) { - $c->forward('check_token'); + $c->forward('/auth/check_csrf_token'); my $done = 0; my $edited = 0; @@ -917,7 +917,7 @@ sub users: Path('users') : Args(0) { } } else { - $c->forward('get_token'); + $c->forward('/auth/get_csrf_token'); $c->forward('fetch_all_bodies'); # Admin users by default @@ -942,7 +942,7 @@ sub update_edit : Path('update_edit') : Args(1) { $c->detach( '/page_error_404_not_found' ) unless $update; - $c->forward('get_token'); + $c->forward('/auth/get_csrf_token'); $c->stash->{update} = $update; @@ -965,7 +965,7 @@ sub update_edit : Path('update_edit') : Args(1) { $c->stash->{update}->discard_changes; } elsif ( $c->get_param('submit') ) { - $c->forward('check_token'); + $c->forward('/auth/check_csrf_token'); my $old_state = $update->state; my $new_state = $c->get_param('state'); @@ -1047,12 +1047,12 @@ sub user_add : Path('user_edit') : Args(0) { my ( $self, $c ) = @_; $c->stash->{template} = 'admin/user_edit.html'; - $c->forward('get_token'); + $c->forward('/auth/get_csrf_token'); $c->forward('fetch_all_bodies'); return unless $c->get_param('submit'); - $c->forward('check_token'); + $c->forward('/auth/check_csrf_token'); unless ($c->get_param('email')) { $c->stash->{field_errors}->{email} = _('Please enter a valid email'); @@ -1084,7 +1084,7 @@ sub user_add : Path('user_edit') : Args(0) { sub user_edit : Path('user_edit') : Args(1) { my ( $self, $c, $id ) = @_; - $c->forward('get_token'); + $c->forward('/auth/get_csrf_token'); my $user = $c->model('DB::User')->find( { id => $id } ); $c->stash->{user} = $user; @@ -1092,7 +1092,7 @@ sub user_edit : Path('user_edit') : Args(1) { $c->forward('fetch_all_bodies'); if ( $c->get_param('submit') ) { - $c->forward('check_token'); + $c->forward('/auth/check_csrf_token'); my $edited = 0; @@ -1328,40 +1328,6 @@ sub get_user : Private { return $user; } -=item get_token - -Generate a token based on user and secret - -=cut - -sub get_token : Private { - my ( $self, $c ) = @_; - - my $secret = $c->model('DB::Secret')->get; - my $user = $c->forward('get_user'); - my $token = sha1_hex($user . $secret); - $c->stash->{token} = $token; - - return 1; -} - -=item check_token - -Check that a token has been set on a request and it's the correct token. If -not then display 404 page - -=cut - -sub check_token : Private { - my ( $self, $c ) = @_; - - if ( !$c->get_param('token') || $c->get_param('token') ne $c->stash->{token} ) { - $c->detach( '/page_error_404_not_found' ); - } - - return 1; -} - =item log_edit $c->forward( 'log_edit', [ $object_id, $object_type, $action_performed ] ); diff --git a/perllib/FixMyStreet/App/Controller/Alert.pm b/perllib/FixMyStreet/App/Controller/Alert.pm index ddda02abd..b578fbbcc 100644 --- a/perllib/FixMyStreet/App/Controller/Alert.pm +++ b/perllib/FixMyStreet/App/Controller/Alert.pm @@ -36,6 +36,8 @@ sub index : Path('') : Args(0) { sub list : Path('list') : Args(0) { my ( $self, $c ) = @_; + $c->forward('/auth/get_csrf_token'); + return unless $c->forward('setup_request') && $c->forward('prettify_pc') @@ -112,6 +114,8 @@ Sign up to email alerts sub subscribe_email : Private { my ( $self, $c ) = @_; + $c->forward('/auth/check_csrf_token'); + $c->stash->{errors} = []; $c->forward('process_user'); @@ -146,6 +150,8 @@ sub subscribe_email : Private { sub updates : Path('updates') : Args(0) { my ( $self, $c ) = @_; + $c->forward('/auth/get_csrf_token'); + $c->stash->{email} = $c->get_param('rznvy'); $c->stash->{problem_id} = $c->get_param('id'); } diff --git a/perllib/FixMyStreet/App/Controller/Around.pm b/perllib/FixMyStreet/App/Controller/Around.pm index b0340204a..b8f038ce3 100644 --- a/perllib/FixMyStreet/App/Controller/Around.pm +++ b/perllib/FixMyStreet/App/Controller/Around.pm @@ -156,6 +156,8 @@ sub display_location : Private { # set the template to use $c->stash->{template} = 'around/display_location.html'; + $c->forward('/auth/get_csrf_token'); + # get the lat,lng my $latitude = $c->stash->{latitude}; my $longitude = $c->stash->{longitude}; diff --git a/perllib/FixMyStreet/App/Controller/Auth.pm b/perllib/FixMyStreet/App/Controller/Auth.pm index 203479253..65533b1d2 100644 --- a/perllib/FixMyStreet/App/Controller/Auth.pm +++ b/perllib/FixMyStreet/App/Controller/Auth.pm @@ -6,8 +6,9 @@ BEGIN { extends 'Catalyst::Controller'; } use Email::Valid; use Net::Domain::TLD; -use mySociety::AuthToken; +use Digest::HMAC_SHA1 qw(hmac_sha1); use JSON::MaybeXS; +use MIME::Base64; use Net::Facebook::Oauth2; use Net::Twitter::Lite::WithAPIv1_1; @@ -415,12 +416,13 @@ sub change_password : Local { $c->detach( 'redirect' ) unless $c->user; - # FIXME - CSRF check here - # FIXME - minimum criteria for passwords (length, contain number, etc) + $c->forward('get_csrf_token'); # If not a post then no submission return unless $c->req->method eq 'POST'; + $c->forward('check_csrf_token'); + # get the passwords my $new = $c->get_param('new_password') // ''; my $confirm = $c->get_param('confirm') // ''; @@ -444,6 +446,38 @@ sub change_password : Local { } +sub get_csrf_token : Private { + my ( $self, $c ) = @_; + + my $time = $c->stash->{csrf_time} || time(); + my $hash = hmac_sha1("$time-" . ($c->sessionid || ""), $c->model('DB::Secret')->get); + $hash = encode_base64($hash, ""); + $hash =~ s/=$//; + my $token = "$time-$hash"; + $c->stash->{csrf_token} = $token unless $c->stash->{csrf_time}; + return $token; +} + +sub check_csrf_token : Private { + my ( $self, $c ) = @_; + + my $token = $c->get_param('token') || ""; + $token =~ s/ /+/g; + my ($time) = $token =~ /^(\d+)-[0-9a-zA-Z+\/]+$/; + $c->stash->{csrf_time} = $time; + $c->detach('no_csrf_token') + unless $time + && $time > time() - 3600 + && $token eq $c->forward('get_csrf_token'); + delete $c->stash->{csrf_time}; +} + +sub no_csrf_token : Private { + my ($self, $c) = @_; + $c->stash->{message} = _('Unknown error'); + $c->stash->{template} = 'errors/generic.html'; +} + =head2 sign_out Log the user out. Tell them we've done so. diff --git a/perllib/FixMyStreet/App/Controller/Moderate.pm b/perllib/FixMyStreet/App/Controller/Moderate.pm index 77a3346dc..2d23417b9 100644 --- a/perllib/FixMyStreet/App/Controller/Moderate.pm +++ b/perllib/FixMyStreet/App/Controller/Moderate.pm @@ -57,6 +57,8 @@ sub report : Chained('moderate') : PathPart('report') : CaptureArgs(1) { $c->detach unless $c->user_exists; $c->detach unless $c->user->has_permission_to(moderate => $problem->bodies_str); + $c->forward('/auth/check_csrf_token'); + my $original = $problem->find_or_new_related( moderation_original_data => { title => $problem->title, detail => $problem->detail, diff --git a/perllib/FixMyStreet/App/Controller/Report.pm b/perllib/FixMyStreet/App/Controller/Report.pm index b3e546c2c..89df4a52d 100644 --- a/perllib/FixMyStreet/App/Controller/Report.pm +++ b/perllib/FixMyStreet/App/Controller/Report.pm @@ -72,6 +72,7 @@ sub ajax : Path('ajax') : Args(1) { sub _display : Private { my ( $self, $c, $id ) = @_; + $c->forward('/auth/get_csrf_token'); $c->forward( 'load_problem_or_display_error', [ $id ] ); $c->forward( 'load_updates' ); $c->forward( 'format_problem_for_display' ); @@ -249,6 +250,8 @@ users too about this change, at which point we can delete: sub delete :Local :Args(1) { my ( $self, $c, $id ) = @_; + $c->forward('/auth/check_csrf_token'); + $c->forward( 'load_problem_or_display_error', [ $id ] ); my $p = $c->stash->{problem}; diff --git a/perllib/FixMyStreet/App/Controller/Report/New.pm b/perllib/FixMyStreet/App/Controller/Report/New.pm index 696234d32..b5d4cba3f 100644 --- a/perllib/FixMyStreet/App/Controller/Report/New.pm +++ b/perllib/FixMyStreet/App/Controller/Report/New.pm @@ -81,6 +81,7 @@ sub report_new : Path : Args(0) { # create the report - loading a partial if available $c->forward('initialize_report'); + $c->forward('/auth/get_csrf_token'); # work out the location for this report and do some checks # Also show map if we're just updating the filters @@ -96,6 +97,7 @@ sub report_new : Path : Args(0) { # deal with the user and report and check both are happy return unless $c->forward('check_form_submitted'); + $c->forward('/auth/check_csrf_token'); $c->forward('process_user'); $c->forward('process_report'); $c->forward('/photo/process_photo'); diff --git a/perllib/FixMyStreet/App/Controller/Report/Update.pm b/perllib/FixMyStreet/App/Controller/Report/Update.pm index 275a300bd..d03797f56 100644 --- a/perllib/FixMyStreet/App/Controller/Report/Update.pm +++ b/perllib/FixMyStreet/App/Controller/Report/Update.pm @@ -25,6 +25,7 @@ sub report_update : Path : Args(0) { $c->forward('check_form_submitted') or $c->go( '/report/display', [ $c->stash->{problem}->id ] ); + $c->forward('/auth/check_csrf_token'); $c->forward('process_update'); $c->forward('process_user'); $c->forward('/photo/process_photo'); diff --git a/perllib/FixMyStreet/Cobrand/Zurich.pm b/perllib/FixMyStreet/Cobrand/Zurich.pm index 987f0bb67..2e4a167db 100644 --- a/perllib/FixMyStreet/Cobrand/Zurich.pm +++ b/perllib/FixMyStreet/Cobrand/Zurich.pm @@ -541,7 +541,7 @@ sub admin_report_edit { # 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'); + $c->forward('/auth/check_csrf_token'); } # All types of users can add internal notes @@ -807,7 +807,7 @@ sub admin_report_edit { # subdivision, or because the customer was not contactable. # We handle these in the same way but with different statuses. - $c->forward('check_token'); + $c->forward('/auth/check_csrf_token'); my $not_contactable = $c->get_param('not_contactable'); @@ -829,7 +829,7 @@ sub admin_report_edit { $self->update_admin_log($c, $problem); $c->res->redirect( '/admin/summary' ); } elsif ($c->get_param('submit')) { - $c->forward('check_token'); + $c->forward('/auth/check_csrf_token'); my $db_update = 0; if ( $c->get_param('latitude') != $problem->latitude || $c->get_param('longitude') != $problem->longitude ) { diff --git a/t/app/controller/alert_new.t b/t/app/controller/alert_new.t index 777d733e2..06932f70a 100644 --- a/t/app/controller/alert_new.t +++ b/t/app/controller/alert_new.t @@ -7,6 +7,10 @@ use FixMyStreet::App; my $mech = FixMyStreet::TestMech->new; +$mech->log_in_ok('test@example.com'); +$mech->get_ok('/alert/subscribe?id=1'); +my ($csrf) = $mech->content =~ /name="token" value="([^"]*)"/; + foreach my $test ( { email => 'test@example.com', @@ -71,7 +75,7 @@ foreach my $test ( $mech->delete_user($user); } - $mech->get_ok( $test->{uri} ); + $mech->get_ok( $test->{uri} . "&token=$csrf" ); $mech->content_contains( $test->{content} ); $user = @@ -113,7 +117,7 @@ foreach my $test ( my $existing_id = $alert->id; my $existing_token = $url_token; - $mech->get_ok( $test->{uri} ); + $mech->get_ok( $test->{uri} . "&token=$csrf" ); $email = $mech->get_email; ok $email, 'got a second email'; @@ -165,7 +169,7 @@ foreach my $test ( # clear existing data so we can be sure we're creating it ok $alert->delete() if $alert && !$test->{exist}; - $mech->get_ok( '/alert/subscribe?type=local&rznvy=test-new@example.com&feed=area:1000:A_Location' ); + $mech->get_ok( '/alert/subscribe?type=local&rznvy=test-new@example.com&feed=area:1000:A_Location&token=' . $csrf ); $alert = FixMyStreet::App->model('DB::Alert')->find( { @@ -262,7 +266,7 @@ for my $test ( FixMyStreet::App->model('DB::Abuse') ->find_or_create( { email => $test->{email} } ); - $mech->get_ok( $test->{uri} ); + $mech->get_ok( $test->{uri} . "&token=$csrf" ); $mech->content_contains( $test->{content} ); $user = diff --git a/t/app/controller/auth.t b/t/app/controller/auth.t index 235a3af7e..9b3d9468a 100644 --- a/t/app/controller/auth.t +++ b/t/app/controller/auth.t @@ -128,7 +128,7 @@ $mech->not_logged_in_ok; ok my $form = $mech->form_name('change_password'), "found change password form"; is_deeply [ sort grep { $_ } map { $_->name } $form->inputs ], # - [ 'confirm', 'new_password' ], + [ 'confirm', 'new_password', 'token' ], "check we got expected fields (ie not old_password)"; # check the various ways the form can be wrong diff --git a/t/app/controller/moderate.t b/t/app/controller/moderate.t index b79f50e73..38216c708 100644 --- a/t/app/controller/moderate.t +++ b/t/app/controller/moderate.t @@ -8,6 +8,7 @@ use FixMyStreet::App; use Data::Dumper; my $mech = FixMyStreet::TestMech->new; +$mech->host('www.example.org'); my $BROMLEY_ID = 2482; my $body = $mech->create_body_ok( $BROMLEY_ID, 'Bromley Council' ); @@ -92,11 +93,12 @@ my %problem_prepopulated = ( subtest 'Problem moderation' => sub { subtest 'Post modify title and text' => sub { - $mech->post_ok('/moderate/report/' . $report->id, { + $mech->get_ok($REPORT_URL); + $mech->submit_form_ok({ with_fields => { %problem_prepopulated, problem_title => 'Good good', problem_detail => 'Good good improved', - }); + }}); $mech->base_like( qr{\Q$REPORT_URL\E} ); $report->discard_changes; @@ -105,11 +107,11 @@ subtest 'Problem moderation' => sub { }; subtest 'Revert title and text' => sub { - $mech->post_ok('/moderate/report/' . $report->id, { + $mech->submit_form_ok({ with_fields => { %problem_prepopulated, problem_revert_title => 1, problem_revert_detail => 1, - }); + }}); $mech->base_like( qr{\Q$REPORT_URL\E} ); $report->discard_changes; @@ -120,18 +122,18 @@ subtest 'Problem moderation' => sub { subtest 'Make anonymous' => sub { $mech->content_lacks('Reported anonymously'); - $mech->post_ok('/moderate/report/' . $report->id, { + $mech->submit_form_ok({ with_fields => { %problem_prepopulated, problem_show_name => 0, - }); + }}); $mech->base_like( qr{\Q$REPORT_URL\E} ); $mech->content_contains('Reported anonymously'); - $mech->post_ok('/moderate/report/' . $report->id, { + $mech->submit_form_ok({ with_fields => { %problem_prepopulated, problem_show_name => 1, - }); + }}); $mech->base_like( qr{\Q$REPORT_URL\E} ); $mech->content_lacks('Reported anonymously'); @@ -140,18 +142,18 @@ subtest 'Problem moderation' => sub { subtest 'Hide photo' => sub { $mech->content_contains('Photo of this report'); - $mech->post_ok('/moderate/report/' . $report->id, { + $mech->submit_form_ok({ with_fields => { %problem_prepopulated, problem_show_photo => 0, - }); + }}); $mech->base_like( qr{\Q$REPORT_URL\E} ); $mech->content_lacks('Photo of this report'); - $mech->post_ok('/moderate/report/' . $report->id, { + $mech->submit_form_ok({ with_fields => { %problem_prepopulated, problem_show_photo => 1, - }); + }}); $mech->base_like( qr{\Q$REPORT_URL\E} ); $mech->content_contains('Photo of this report'); @@ -160,10 +162,10 @@ subtest 'Problem moderation' => sub { subtest 'Hide report' => sub { $mech->clear_emails_ok; - my $resp = $mech->post('/moderate/report/' . $report->id, { + $mech->submit_form_ok({ with_fields => { %problem_prepopulated, problem_hide => 1, - }); + }}); $mech->base_unlike( qr{/report/}, 'redirected to front page' ); $report->discard_changes; @@ -185,22 +187,23 @@ $mech->content_lacks('Posted anonymously', 'sanity check'); subtest 'Problem 2' => sub { my $REPORT2_URL = '/report/' . $report2->id ; - $mech->post_ok('/moderate/report/' . $report2->id, { + $mech->get_ok($REPORT2_URL); + $mech->submit_form_ok({ with_fields => { %problem_prepopulated, problem_title => 'Good good', problem_detail => 'Good good improved', - }); + }}); $mech->base_like( qr{\Q$REPORT2_URL\E} ); $report2->discard_changes; is $report2->title, 'Good [...] good'; is $report2->detail, 'Good [...] good [...]improved'; - $mech->post_ok('/moderate/report/' . $report2->id, { + $mech->submit_form_ok({ with_fields => { %problem_prepopulated, problem_revert_title => 1, problem_revert_detail => 1, - }); + }}); $mech->base_like( qr{\Q$REPORT2_URL\E} ); $report2->discard_changes; @@ -229,13 +232,12 @@ my $update = create_update(); subtest 'updates' => sub { - my $MODERATE_UPDATE_URL = sprintf '/moderate/report/%d/update/%d', $report->id, $update->id; - subtest 'Update modify text' => sub { - $mech->post_ok( $MODERATE_UPDATE_URL, { + $mech->get_ok($REPORT_URL); + $mech->submit_form_ok({ with_fields => { %update_prepopulated, update_detail => 'update good good good', - }) or die $mech->content; + }}) or die $mech->content; $mech->base_like( qr{\Q$REPORT_URL\E} ); $update->discard_changes; @@ -243,10 +245,10 @@ subtest 'updates' => sub { }; subtest 'Revert text' => sub { - $mech->post_ok( $MODERATE_UPDATE_URL, { + $mech->submit_form_ok({ with_fields => { %update_prepopulated, update_revert_detail => 1, - }); + }}); $mech->base_like( qr{\Q$REPORT_URL\E} ); $update->discard_changes; @@ -258,18 +260,18 @@ subtest 'updates' => sub { $mech->content_lacks('Posted anonymously') or die sprintf '%d (%d)', $update->id, $report->comments->count; - $mech->post_ok( $MODERATE_UPDATE_URL, { + $mech->submit_form_ok({ with_fields => { %update_prepopulated, update_show_name => 0, - }); + }}); $mech->base_like( qr{\Q$REPORT_URL\E} ); $mech->content_contains('Posted anonymously'); - $mech->post_ok( $MODERATE_UPDATE_URL, { + $mech->submit_form_ok({ with_fields => { %update_prepopulated, update_show_name => 1, - }); + }}); $mech->base_like( qr{\Q$REPORT_URL\E} ); $mech->content_lacks('Posted anonymously'); @@ -283,18 +285,18 @@ subtest 'updates' => sub { $mech->content_contains('Photo of this report') or die $mech->content; - $mech->post_ok( $MODERATE_UPDATE_URL, { + $mech->submit_form_ok({ with_fields => { %update_prepopulated, update_show_photo => 0, - }); + }}); $mech->base_like( qr{\Q$REPORT_URL\E} ); $mech->content_lacks('Photo of this report'); - $mech->post_ok( $MODERATE_UPDATE_URL, { + $mech->submit_form_ok({ with_fields => { %update_prepopulated, update_show_photo => 1, - }); + }}); $mech->base_like( qr{\Q$REPORT_URL\E} ); $mech->content_contains('Photo of this report'); @@ -303,10 +305,10 @@ subtest 'updates' => sub { subtest 'Hide comment' => sub { $mech->content_contains('update good good bad good'); - $mech->post_ok( $MODERATE_UPDATE_URL, { + $mech->submit_form_ok({ with_fields => { %update_prepopulated, update_hide => 1, - }); + }}); $mech->content_lacks('update good good bad good'); }; @@ -316,11 +318,11 @@ subtest 'updates' => sub { my $update2 = create_update(); subtest 'Update 2' => sub { - my $MODERATE_UPDATE2_URL = sprintf '/moderate/report/%d/update/%d', $report->id, $update2->id; - $mech->post_ok( $MODERATE_UPDATE2_URL, { + $mech->get_ok($REPORT_URL); + $mech->submit_form_ok({ with_fields => { %update_prepopulated, update_detail => 'update good good good', - }) or die $mech->content; + }}) or die $mech->content; $update2->discard_changes; is $update2->text, 'update good good [...] good', diff --git a/t/app/controller/photo.t b/t/app/controller/photo.t index 425e3c4df..4cec82c44 100644 --- a/t/app/controller/photo.t +++ b/t/app/controller/photo.t @@ -40,11 +40,15 @@ subtest "Check multiple upload worked" => sub { # 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->get_ok('/report/new?lat=53.4031156&lon=-2.9840579'); + my ($csrf) = $mech->content =~ /name="token" value="([^"]*)"/; + $mech->post( '/report/new', Content_Type => 'form-data', Content => { submit_problem => 1, + token => $csrf, title => 'Test', lat => 53.4031156, lon => -2.9840579, # in Liverpool pc => 'L1 4LN', @@ -57,9 +61,6 @@ subtest "Check multiple upload worked" => sub { 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'; diff --git a/t/app/controller/report_updates.t b/t/app/controller/report_updates.t index 7b4bf7854..2a3c7c0b3 100644 --- a/t/app/controller/report_updates.t +++ b/t/app/controller/report_updates.t @@ -510,20 +510,14 @@ subtest 'check non authority user cannot change set state' => sub { $user->update; $mech->get_ok("/report/$report_id"); - $mech->post_ok( "/report/update", { - submit_update => 1, - id => $report_id, - name => $user->name, - may_show_name => 1, - add_alert => undef, - photo1 => '', - photo2 => '', - photo3 => '', - update => 'this is a forbidden update', - state => 'fixed - council', + $mech->submit_form_ok( { + form_id => 'form_update_form', + fields => { + may_show_name => 1, + update => 'this is a forbidden update', + state => 'fixed - council', }, - 'submitted with state', - ); + }, 'submitted with state'); is $mech->uri->path, "/report/update", "at /report/update"; @@ -540,20 +534,14 @@ for my $state ( qw/unconfirmed hidden partial/ ) { $user->update; $mech->get_ok("/report/$report_id"); - $mech->post_ok( "/report/update", { - submit_update => 1, - id => $report_id, - name => $user->name, - may_show_name => 1, - add_alert => undef, - photo1 => '', - photo2 => '', - photo3 => '', - update => 'this is a forbidden update', - state => $state, + $mech->submit_form_ok( { + form_id => 'form_update_form', + fields => { + may_show_name => 1, + update => 'this is a forbidden update', + state => $state, }, - 'submitted with state', - ); + }, 'submitted with state'); is $mech->uri->path, "/report/update", "at /report/update"; @@ -570,10 +558,6 @@ for my $test ( fields => { name => $user->name, may_show_name => 1, - add_alert => undef, - photo1 => '', - photo2 => '', - photo3 => '', update => 'Set state to investigating', state => 'investigating', }, @@ -584,10 +568,6 @@ for my $test ( fields => { name => $user->name, may_show_name => 1, - add_alert => undef, - photo1 => '', - photo2 => '', - photo3 => '', update => 'Set state to in progress', state => 'in progress', }, @@ -598,10 +578,6 @@ for my $test ( fields => { name => $user->name, may_show_name => 1, - add_alert => undef, - photo1 => '', - photo2 => '', - photo3 => '', update => 'Set state to fixed', state => 'fixed', }, @@ -612,10 +588,6 @@ for my $test ( fields => { name => $user->name, may_show_name => 1, - add_alert => undef, - photo1 => '', - photo2 => '', - photo3 => '', update => 'Set state to action scheduled', state => 'action scheduled', }, @@ -626,10 +598,6 @@ for my $test ( fields => { name => $user->name, may_show_name => 1, - add_alert => undef, - photo1 => '', - photo2 => '', - photo3 => '', update => 'Set state to unable to fix', state => 'unable to fix', }, @@ -640,10 +608,6 @@ for my $test ( fields => { name => $user->name, may_show_name => 1, - add_alert => undef, - photo1 => '', - photo2 => '', - photo3 => '', update => 'Set state to internal referral', state => 'internal referral', }, @@ -655,10 +619,6 @@ for my $test ( fields => { name => $user->name, may_show_name => 1, - add_alert => undef, - photo1 => '', - photo2 => '', - photo3 => '', update => 'Set state to not responsible', state => 'not responsible', }, @@ -670,10 +630,6 @@ for my $test ( fields => { name => $user->name, may_show_name => 1, - add_alert => undef, - photo1 => '', - photo2 => '', - photo3 => '', update => 'Set state to duplicate', state => 'duplicate', }, @@ -685,10 +641,6 @@ for my $test ( fields => { name => $user->name, may_show_name => 1, - add_alert => undef, - photo1 => '', - photo2 => '', - photo3 => '', update => 'Set state to internal referral', state => 'internal referral', }, @@ -700,10 +652,6 @@ for my $test ( fields => { name => $user->name, may_show_name => 1, - add_alert => undef, - photo1 => '', - photo2 => '', - photo3 => '', update => 'Set state to fixed', state => 'fixed', }, diff --git a/t/cobrand/zurich.t b/t/cobrand/zurich.t index cf66136e5..a595f48c9 100644 --- a/t/cobrand/zurich.t +++ b/t/cobrand/zurich.t @@ -810,17 +810,12 @@ subtest "photo must be supplied for categories that require it" => sub { MAPIT_ID_WHITELIST => [ 423017 ], MAP_TYPE => 'Zurich,OSM', }, sub { - $mech->post_ok( '/report/new', { + $mech->get_ok('/report/new?lat=47.381817&lon=8.529156'); + $mech->submit_form_ok({ with_fields => { 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'); }; diff --git a/templates/web/base/admin/body-form.html b/templates/web/base/admin/body-form.html index 7acfbfdd5..8c4956f7f 100644 --- a/templates/web/base/admin/body-form.html +++ b/templates/web/base/admin/body-form.html @@ -236,7 +236,7 @@

- +

diff --git a/templates/web/base/admin/body.html b/templates/web/base/admin/body.html index d5e575666..15802fc44 100644 --- a/templates/web/base/admin/body.html +++ b/templates/web/base/admin/body.html @@ -97,7 +97,7 @@

- +

@@ -202,7 +202,7 @@

- +

diff --git a/templates/web/base/admin/category_edit.html b/templates/web/base/admin/category_edit.html index c0bd43ef5..6537fe028 100644 --- a/templates/web/base/admin/category_edit.html +++ b/templates/web/base/admin/category_edit.html @@ -22,7 +22,7 @@

[% loc('Category:') %] [% contact.category | html %] - + [% IF contact.extra %]

[% loc('Extra data:') %] [% USE Dumper %] diff --git a/templates/web/base/admin/report_edit.html b/templates/web/base/admin/report_edit.html index c0cdead84..065c6c2ce 100644 --- a/templates/web/base/admin/report_edit.html +++ b/templates/web/base/admin/report_edit.html @@ -4,7 +4,7 @@ [% status_message %] - +

    [%- cobrand_data = problem.cobrand_data; diff --git a/templates/web/base/admin/update_edit.html b/templates/web/base/admin/update_edit.html index a956bb2cb..06bee6010 100644 --- a/templates/web/base/admin/update_edit.html +++ b/templates/web/base/admin/update_edit.html @@ -4,7 +4,7 @@ [% status_message %] - +
      [%- cobrand_data = update.cobrand_data; diff --git a/templates/web/base/admin/user-form.html b/templates/web/base/admin/user-form.html index 3956e8533..b863bf96a 100644 --- a/templates/web/base/admin/user-form.html +++ b/templates/web/base/admin/user-form.html @@ -1,5 +1,5 @@ - + [% IF c.cobrand.moniker == 'zurich' AND field_errors.email %] diff --git a/templates/web/base/alert/_list.html b/templates/web/base/alert/_list.html index 395948248..65bba2fed 100644 --- a/templates/web/base/alert/_list.html +++ b/templates/web/base/alert/_list.html @@ -1,3 +1,4 @@ + diff --git a/templates/web/base/alert/updates.html b/templates/web/base/alert/updates.html index 104bfa55a..ecaed37ca 100644 --- a/templates/web/base/alert/updates.html +++ b/templates/web/base/alert/updates.html @@ -23,6 +23,7 @@ + diff --git a/templates/web/base/around/display_location.html b/templates/web/base/around/display_location.html index 7bf62e528..7c54f4b76 100755 --- a/templates/web/base/around/display_location.html +++ b/templates/web/base/around/display_location.html @@ -40,6 +40,7 @@ [% IF allow_creation %] + [% IF c.req.params.map_override %] [% END %] diff --git a/templates/web/base/auth/change_password.html b/templates/web/base/auth/change_password.html index b4170c23e..be0dc69b4 100644 --- a/templates/web/base/auth/change_password.html +++ b/templates/web/base/auth/change_password.html @@ -3,11 +3,12 @@

      [% loc('Change password') %]

      [% IF password_changed %] -

      [% loc('Your password has been changed') %]

      +

      [% loc('Your password has been changed') %]

      [% END %] + [% IF password_error; diff --git a/templates/web/base/report/_main.html b/templates/web/base/report/_main.html index aaa167108..4821b3fa0 100644 --- a/templates/web/base/report/_main.html +++ b/templates/web/base/report/_main.html @@ -5,6 +5,7 @@ [% IF moderating %] [% original = problem_original %] +

      diff --git a/templates/web/base/report/display_tools.html b/templates/web/base/report/display_tools.html index c1413d9c7..58e450c84 100644 --- a/templates/web/base/report/display_tools.html +++ b/templates/web/base/report/display_tools.html @@ -2,6 +2,7 @@
        [% IF c.user_exists AND c.cobrand.users_can_hide AND c.user.belongs_to_body( c.cobrand.council_id ) %]
      • +
      • [% ELSIF c.cobrand.moniker != 'zurich' %] @@ -40,6 +41,7 @@ + diff --git a/templates/web/base/report/new/fill_in_details.html b/templates/web/base/report/new/fill_in_details.html index 55b3a5207..d7e2f1d3a 100644 --- a/templates/web/base/report/new/fill_in_details.html +++ b/templates/web/base/report/new/fill_in_details.html @@ -12,16 +12,15 @@ [% END %] - - [% ELSE %]
        - [% END %] + + diff --git a/templates/web/base/report/update-form.html b/templates/web/base/report/update-form.html index f6ce265bf..97e0df779 100644 --- a/templates/web/base/report/update-form.html +++ b/templates/web/base/report/update-form.html @@ -15,6 +15,7 @@ [% INCLUDE 'errors.html' %] +
        [% IF NOT login_success AND NOT oauth_need_email %] [% INCLUDE 'report/update/form_update.html' %] diff --git a/templates/web/base/report/update.html b/templates/web/base/report/update.html index a09913d39..aaad33b7a 100644 --- a/templates/web/base/report/update.html +++ b/templates/web/base/report/update.html @@ -8,6 +8,7 @@
      • [% IF moderating; original_update = update.moderation_original_data %] +
        diff --git a/templates/web/bromley/report/display.html b/templates/web/bromley/report/display.html index da83e005f..27e1e64a9 100644 --- a/templates/web/bromley/report/display.html +++ b/templates/web/bromley/report/display.html @@ -56,6 +56,7 @@ [% INCLUDE 'errors.html' %] +
        diff --git a/templates/web/eastsussex/report/update-form.html b/templates/web/eastsussex/report/update-form.html index e4fb47a45..b2c67890f 100644 --- a/templates/web/eastsussex/report/update-form.html +++ b/templates/web/eastsussex/report/update-form.html @@ -24,6 +24,7 @@

        + @@ -56,6 +57,7 @@ [% INCLUDE 'errors.html' %] +
        diff --git a/templates/web/seesomething/around/display_location.html b/templates/web/seesomething/around/display_location.html index b54311264..692ea22ee 100644 --- a/templates/web/seesomething/around/display_location.html +++ b/templates/web/seesomething/around/display_location.html @@ -20,6 +20,7 @@ %] + [% IF c.req.params.map_override %] [% END %] diff --git a/templates/web/zurich/admin/body-form.html b/templates/web/zurich/admin/body-form.html index ac2887159..966bdf799 100644 --- a/templates/web/zurich/admin/body-form.html +++ b/templates/web/zurich/admin/body-form.html @@ -47,7 +47,7 @@

        - +

        diff --git a/templates/web/zurich/admin/body.html b/templates/web/zurich/admin/body.html index 771f1e537..1a156773d 100644 --- a/templates/web/zurich/admin/body.html +++ b/templates/web/zurich/admin/body.html @@ -55,7 +55,7 @@

        - +

        diff --git a/templates/web/zurich/admin/report_edit-sdm.html b/templates/web/zurich/admin/report_edit-sdm.html index 63c6b5e6f..e7602b659 100644 --- a/templates/web/zurich/admin/report_edit-sdm.html +++ b/templates/web/zurich/admin/report_edit-sdm.html @@ -11,7 +11,7 @@
        - +
        diff --git a/templates/web/zurich/admin/report_edit.html b/templates/web/zurich/admin/report_edit.html index dd876935c..f1ee7a846 100644 --- a/templates/web/zurich/admin/report_edit.html +++ b/templates/web/zurich/admin/report_edit.html @@ -13,7 +13,7 @@ [% pstate = problem.get_extra_metadata('closure_status') || problem.state %] - +
        diff --git a/templates/web/zurich/admin/template_edit.html b/templates/web/zurich/admin/template_edit.html index 1deda6a77..dbad55f08 100644 --- a/templates/web/zurich/admin/template_edit.html +++ b/templates/web/zurich/admin/template_edit.html @@ -25,7 +25,7 @@

        - +

        [% IF rt.id %] diff --git a/templates/web/zurich/admin/update_edit.html b/templates/web/zurich/admin/update_edit.html index fbd96f3a5..adafff3a8 100644 --- a/templates/web/zurich/admin/update_edit.html +++ b/templates/web/zurich/admin/update_edit.html @@ -4,7 +4,7 @@ [% status_message %] - +
        • [% loc('View report on site' )%]
        • -- cgit v1.2.3 From f74c7910b72f41f4a72d8b6b1a683fcf9fbb244e Mon Sep 17 00:00:00 2001 From: Matthew Somerville Date: Tue, 5 Jul 2016 13:09:18 +0100 Subject: Fix CSRF issue with new login during process. If you had no session cookie, started reporting a problem, logged in through that process, you would then get a CSRF error as the token had been created before the session was. --- perllib/FixMyStreet/App/Controller/Auth.pm | 3 +++ t/app/controller/report_new.t | 1 + 2 files changed, 4 insertions(+) diff --git a/perllib/FixMyStreet/App/Controller/Auth.pm b/perllib/FixMyStreet/App/Controller/Auth.pm index 65533b1d2..be95040e1 100644 --- a/perllib/FixMyStreet/App/Controller/Auth.pm +++ b/perllib/FixMyStreet/App/Controller/Auth.pm @@ -85,6 +85,9 @@ sub sign_in : Private { $c->set_session_cookie_expire(0) unless $remember_me; + # Regenerate CSRF token as session ID changed + $c->forward('get_csrf_token'); + return 1; } diff --git a/t/app/controller/report_new.t b/t/app/controller/report_new.t index eb29d37da..ba550193e 100644 --- a/t/app/controller/report_new.t +++ b/t/app/controller/report_new.t @@ -701,6 +701,7 @@ subtest "test password errors for a user who is signing in as they report" => su subtest "test report creation for a user who is signing in as they report" => sub { $mech->log_out_ok; + $mech->cookie_jar({}); $mech->clear_emails_ok; # check that the user does not exist -- cgit v1.2.3 From e591e68dae22695c688590d4b866f3158f4f2604 Mon Sep 17 00:00:00 2001 From: Matthew Somerville Date: Mon, 20 Jun 2016 11:45:35 +0100 Subject: Patch Dropzone to correctly orient preview images. Include a patch file, applied to Dropzone as of version e524e03c, that also includes our previous Opera patch from 445e9a3d. The new minified file is our cut-down exif.js plus the patched dropzone.js. --- web/js/dropzone.js.patch | 36 +++++++++++++++++++ web/js/dropzone.min.js | 62 ++++++++++++++++++++++++++++++-- web/js/src/exif.js | 94 ++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 190 insertions(+), 2 deletions(-) create mode 100644 web/js/dropzone.js.patch mode change 100755 => 100644 web/js/dropzone.min.js create mode 100644 web/js/src/exif.js diff --git a/web/js/dropzone.js.patch b/web/js/dropzone.js.patch new file mode 100644 index 000000000..030b56a6a --- /dev/null +++ b/web/js/dropzone.js.patch @@ -0,0 +1,36 @@ +--- web/js/src/dropzone.orig.js 2016-06-17 21:29:47.000000000 +0100 ++++ web/js/src/dropzone.js 2016-06-20 11:40:55.000000000 +0100 +@@ -1469,7 +1469,7 @@ + return _results; + }; + +- Dropzone.blacklistedBrowsers = [/opera.*Macintosh.*version\/12/i]; ++ Dropzone.blacklistedBrowsers = [/opera.*(Windows Phone|Macintosh).*version\/12/i]; + + Dropzone.isBrowserSupported = function() { + var capableBrowser, regex, _i, _len, _ref; +@@ -1679,7 +1679,23 @@ + drawImageIOSFix = function(ctx, img, sx, sy, sw, sh, dx, dy, dw, dh) { + var vertSquashRatio; + vertSquashRatio = detectVerticalSquash(img); +- return ctx.drawImage(img, sx, sy, sw, sh, dx, dy, dw, dh / vertSquashRatio); ++ dh = dh / vertSquashRatio; ++ ++ /* An improved version of http://stackoverflow.com/a/28356942/669631 */ ++ var orientation = 0; ++ switch (EXIF.getData(img)) { ++ case 3: orientation = 2; break; ++ case 6: orientation = 1; break; ++ case 8: orientation = -1; break; ++ } ++ if (orientation) { ++ ctx.translate(dx + dw/2, dy + dh/2); ++ ctx.rotate(orientation * Math.PI / 2); ++ dx = -dw/2; ++ dy = -dh/2; ++ } ++ ++ return ctx.drawImage(img, sx, sy, sw, sh, dx, dy, dw, dh); + }; + + diff --git a/web/js/dropzone.min.js b/web/js/dropzone.min.js old mode 100755 new mode 100644 index f460b6c50..ff19898e9 --- a/web/js/dropzone.min.js +++ b/web/js/dropzone.min.js @@ -1,2 +1,60 @@ -(function(){var a,b,c,d,e,f,g,h,i=[].slice,j={}.hasOwnProperty,k=function(a,b){function c(){this.constructor=a}for(var d in b)j.call(b,d)&&(a[d]=b[d]);return c.prototype=b.prototype,a.prototype=new c,a.__super__=b.prototype,a};g=function(){},b=function(){function a(){}return a.prototype.addEventListener=a.prototype.on,a.prototype.on=function(a,b){return this._callbacks=this._callbacks||{},this._callbacks[a]||(this._callbacks[a]=[]),this._callbacks[a].push(b),this},a.prototype.emit=function(){var a,b,c,d,e,f;if(d=arguments[0],a=2<=arguments.length?i.call(arguments,1):[],this._callbacks=this._callbacks||{},c=this._callbacks[d])for(e=0,f=c.length;f>e;e++)b=c[e],b.apply(this,a);return this},a.prototype.removeListener=a.prototype.off,a.prototype.removeAllListeners=a.prototype.off,a.prototype.removeEventListener=a.prototype.off,a.prototype.off=function(a,b){var c,d,e,f,g;if(!this._callbacks||0===arguments.length)return this._callbacks={},this;if(d=this._callbacks[a],!d)return this;if(1===arguments.length)return delete this._callbacks[a],this;for(e=f=0,g=d.length;g>f;e=++f)if(c=d[e],c===b){d.splice(e,1);break}return this},a}(),a=function(a){function c(a,b){var e,f,g;if(this.element=a,this.version=c.version,this.defaultOptions.previewTemplate=this.defaultOptions.previewTemplate.replace(/\n*/g,""),this.clickableElements=[],this.listeners=[],this.files=[],"string"==typeof this.element&&(this.element=document.querySelector(this.element)),!this.element||null==this.element.nodeType)throw new Error("Invalid dropzone element.");if(this.element.dropzone)throw new Error("Dropzone already attached.");if(c.instances.push(this),this.element.dropzone=this,e=null!=(g=c.optionsForElement(this.element))?g:{},this.options=d({},this.defaultOptions,e,null!=b?b:{}),this.options.forceFallback||!c.isBrowserSupported())return this.options.fallback.call(this);if(null==this.options.url&&(this.options.url=this.element.getAttribute("action")),!this.options.url)throw new Error("No URL provided.");if(this.options.acceptedFiles&&this.options.acceptedMimeTypes)throw new Error("You can't provide both 'acceptedFiles' and 'acceptedMimeTypes'. 'acceptedMimeTypes' is deprecated.");this.options.acceptedMimeTypes&&(this.options.acceptedFiles=this.options.acceptedMimeTypes,delete this.options.acceptedMimeTypes),this.options.method=this.options.method.toUpperCase(),(f=this.getExistingFallback())&&f.parentNode&&f.parentNode.removeChild(f),this.options.previewsContainer!==!1&&(this.previewsContainer=this.options.previewsContainer?c.getElement(this.options.previewsContainer,"previewsContainer"):this.element),this.options.clickable&&(this.clickableElements=this.options.clickable===!0?[this.element]:c.getElements(this.options.clickable,"clickable")),this.init()}var d,e;return k(c,a),c.prototype.Emitter=b,c.prototype.events=["drop","dragstart","dragend","dragenter","dragover","dragleave","addedfile","addedfiles","removedfile","thumbnail","error","errormultiple","processing","processingmultiple","uploadprogress","totaluploadprogress","sending","sendingmultiple","success","successmultiple","canceled","canceledmultiple","complete","completemultiple","reset","maxfilesexceeded","maxfilesreached","queuecomplete"],c.prototype.defaultOptions={url:null,method:"post",withCredentials:!1,parallelUploads:2,uploadMultiple:!1,maxFilesize:256,paramName:"file",createImageThumbnails:!0,maxThumbnailFilesize:10,thumbnailWidth:120,thumbnailHeight:120,filesizeBase:1e3,maxFiles:null,params:{},clickable:!0,ignoreHiddenFiles:!0,acceptedFiles:null,acceptedMimeTypes:null,autoProcessQueue:!0,autoQueue:!0,addRemoveLinks:!1,previewsContainer:null,hiddenInputContainer:"body",capture:null,dictDefaultMessage:"Drop files here to upload",dictFallbackMessage:"Your browser does not support drag'n'drop file uploads.",dictFallbackText:"Please use the fallback form below to upload your files like in the olden days.",dictFileTooBig:"File is too big ({{filesize}}MiB). Max filesize: {{maxFilesize}}MiB.",dictInvalidFileType:"You can't upload files of this type.",dictResponseError:"Server responded with {{statusCode}} code.",dictCancelUpload:"Cancel upload",dictCancelUploadConfirmation:"Are you sure you want to cancel this upload?",dictRemoveFile:"Remove file",dictRemoveFileConfirmation:null,dictMaxFilesExceeded:"You can not upload any more files.",accept:function(a,b){return b()},init:function(){return g},forceFallback:!1,fallback:function(){var a,b,d,e,f,g;for(this.element.className=""+this.element.className+" dz-browser-not-supported",g=this.element.getElementsByTagName("div"),e=0,f=g.length;f>e;e++)a=g[e],/(^| )dz-message($| )/.test(a.className)&&(b=a,a.className="dz-message");return b||(b=c.createElement('
          '),this.element.appendChild(b)),d=b.getElementsByTagName("span")[0],d&&(null!=d.textContent?d.textContent=this.options.dictFallbackMessage:null!=d.innerText&&(d.innerText=this.options.dictFallbackMessage)),this.element.appendChild(this.getFallbackForm())},resize:function(a){var b,c,d;return b={srcX:0,srcY:0,srcWidth:a.width,srcHeight:a.height},c=a.width/a.height,b.optWidth=this.options.thumbnailWidth,b.optHeight=this.options.thumbnailHeight,null==b.optWidth&&null==b.optHeight?(b.optWidth=b.srcWidth,b.optHeight=b.srcHeight):null==b.optWidth?b.optWidth=c*b.optHeight:null==b.optHeight&&(b.optHeight=1/c*b.optWidth),d=b.optWidth/b.optHeight,a.heightd?(b.srcHeight=a.height,b.srcWidth=b.srcHeight*d):(b.srcWidth=a.width,b.srcHeight=b.srcWidth/d),b.srcX=(a.width-b.srcWidth)/2,b.srcY=(a.height-b.srcHeight)/2,b},drop:function(){return this.element.classList.remove("dz-drag-hover")},dragstart:g,dragend:function(){return this.element.classList.remove("dz-drag-hover")},dragenter:function(){return this.element.classList.add("dz-drag-hover")},dragover:function(){return this.element.classList.add("dz-drag-hover")},dragleave:function(){return this.element.classList.remove("dz-drag-hover")},paste:g,reset:function(){return this.element.classList.remove("dz-started")},addedfile:function(a){var b,d,e,f,g,h,i,j,k,l,m,n,o;if(this.element===this.previewsContainer&&this.element.classList.add("dz-started"),this.previewsContainer){for(a.previewElement=c.createElement(this.options.previewTemplate.trim()),a.previewTemplate=a.previewElement,this.previewsContainer.appendChild(a.previewElement),l=a.previewElement.querySelectorAll("[data-dz-name]"),f=0,i=l.length;i>f;f++)b=l[f],b.textContent=a.name;for(m=a.previewElement.querySelectorAll("[data-dz-size]"),g=0,j=m.length;j>g;g++)b=m[g],b.innerHTML=this.filesize(a.size);for(this.options.addRemoveLinks&&(a._removeLink=c.createElement(''+this.options.dictRemoveFile+""),a.previewElement.appendChild(a._removeLink)),d=function(b){return function(d){return d.preventDefault(),d.stopPropagation(),a.status===c.UPLOADING?c.confirm(b.options.dictCancelUploadConfirmation,function(){return b.removeFile(a)}):b.options.dictRemoveFileConfirmation?c.confirm(b.options.dictRemoveFileConfirmation,function(){return b.removeFile(a)}):b.removeFile(a)}}(this),n=a.previewElement.querySelectorAll("[data-dz-remove]"),o=[],h=0,k=n.length;k>h;h++)e=n[h],o.push(e.addEventListener("click",d));return o}},removedfile:function(a){var b;return a.previewElement&&null!=(b=a.previewElement)&&b.parentNode.removeChild(a.previewElement),this._updateMaxFilesReachedClass()},thumbnail:function(a,b){var c,d,e,f;if(a.previewElement){for(a.previewElement.classList.remove("dz-file-preview"),f=a.previewElement.querySelectorAll("[data-dz-thumbnail]"),d=0,e=f.length;e>d;d++)c=f[d],c.alt=a.name,c.src=b;return setTimeout(function(){return function(){return a.previewElement.classList.add("dz-image-preview")}}(this),1)}},error:function(a,b){var c,d,e,f,g;if(a.previewElement){for(a.previewElement.classList.add("dz-error"),"String"!=typeof b&&b.error&&(b=b.error),f=a.previewElement.querySelectorAll("[data-dz-errormessage]"),g=[],d=0,e=f.length;e>d;d++)c=f[d],g.push(c.textContent=b);return g}},errormultiple:g,processing:function(a){return a.previewElement&&(a.previewElement.classList.add("dz-processing"),a._removeLink)?a._removeLink.textContent=this.options.dictCancelUpload:void 0},processingmultiple:g,uploadprogress:function(a,b){var c,d,e,f,g;if(a.previewElement){for(f=a.previewElement.querySelectorAll("[data-dz-uploadprogress]"),g=[],d=0,e=f.length;e>d;d++)c=f[d],g.push("PROGRESS"===c.nodeName?c.value=b:c.style.width=""+b+"%");return g}},totaluploadprogress:g,sending:g,sendingmultiple:g,success:function(a){return a.previewElement?a.previewElement.classList.add("dz-success"):void 0},successmultiple:g,canceled:function(a){return this.emit("error",a,"Upload canceled.")},canceledmultiple:g,complete:function(a){return a._removeLink&&(a._removeLink.textContent=this.options.dictRemoveFile),a.previewElement?a.previewElement.classList.add("dz-complete"):void 0},completemultiple:g,maxfilesexceeded:g,maxfilesreached:g,queuecomplete:g,addedfiles:g,previewTemplate:'
          \n
          \n
          \n
          \n
          \n
          \n
          \n
          \n
          \n \n Check\n \n \n \n \n \n
          \n
          \n \n Error\n \n \n \n \n \n \n \n
          \n
          '},d=function(){var a,b,c,d,e,f,g;for(d=arguments[0],c=2<=arguments.length?i.call(arguments,1):[],f=0,g=c.length;g>f;f++){b=c[f];for(a in b)e=b[a],d[a]=e}return d},c.prototype.getAcceptedFiles=function(){var a,b,c,d,e;for(d=this.files,e=[],b=0,c=d.length;c>b;b++)a=d[b],a.accepted&&e.push(a);return e},c.prototype.getRejectedFiles=function(){var a,b,c,d,e;for(d=this.files,e=[],b=0,c=d.length;c>b;b++)a=d[b],a.accepted||e.push(a);return e},c.prototype.getFilesWithStatus=function(a){var b,c,d,e,f;for(e=this.files,f=[],c=0,d=e.length;d>c;c++)b=e[c],b.status===a&&f.push(b);return f},c.prototype.getQueuedFiles=function(){return this.getFilesWithStatus(c.QUEUED)},c.prototype.getUploadingFiles=function(){return this.getFilesWithStatus(c.UPLOADING)},c.prototype.getAddedFiles=function(){return this.getFilesWithStatus(c.ADDED)},c.prototype.getActiveFiles=function(){var a,b,d,e,f;for(e=this.files,f=[],b=0,d=e.length;d>b;b++)a=e[b],(a.status===c.UPLOADING||a.status===c.QUEUED)&&f.push(a);return f},c.prototype.init=function(){var a,b,d,e,f,g,h;for("form"===this.element.tagName&&this.element.setAttribute("enctype","multipart/form-data"),this.element.classList.contains("dropzone")&&!this.element.querySelector(".dz-message")&&this.element.appendChild(c.createElement('
          '+this.options.dictDefaultMessage+"
          ")),this.clickableElements.length&&(d=function(a){return function(){return a.hiddenFileInput&&a.hiddenFileInput.parentNode.removeChild(a.hiddenFileInput),a.hiddenFileInput=document.createElement("input"),a.hiddenFileInput.setAttribute("type","file"),(null==a.options.maxFiles||a.options.maxFiles>1)&&a.hiddenFileInput.setAttribute("multiple","multiple"),a.hiddenFileInput.className="dz-hidden-input",null!=a.options.acceptedFiles&&a.hiddenFileInput.setAttribute("accept",a.options.acceptedFiles),null!=a.options.capture&&a.hiddenFileInput.setAttribute("capture",a.options.capture),a.hiddenFileInput.style.visibility="hidden",a.hiddenFileInput.style.position="absolute",a.hiddenFileInput.style.top="0",a.hiddenFileInput.style.left="0",a.hiddenFileInput.style.height="0",a.hiddenFileInput.style.width="0",document.querySelector(a.options.hiddenInputContainer).appendChild(a.hiddenFileInput),a.hiddenFileInput.addEventListener("change",function(){var b,c,e,f;if(c=a.hiddenFileInput.files,c.length)for(e=0,f=c.length;f>e;e++)b=c[e],a.addFile(b);return a.emit("addedfiles",c),d()})}}(this))(),this.URL=null!=(g=window.URL)?g:window.webkitURL,h=this.events,e=0,f=h.length;f>e;e++)a=h[e],this.on(a,this.options[a]);return this.on("uploadprogress",function(a){return function(){return a.updateTotalUploadProgress()}}(this)),this.on("removedfile",function(a){return function(){return a.updateTotalUploadProgress()}}(this)),this.on("canceled",function(a){return function(b){return a.emit("complete",b)}}(this)),this.on("complete",function(a){return function(){return 0===a.getAddedFiles().length&&0===a.getUploadingFiles().length&&0===a.getQueuedFiles().length?setTimeout(function(){return a.emit("queuecomplete")},0):void 0}}(this)),b=function(a){return a.stopPropagation(),a.preventDefault?a.preventDefault():a.returnValue=!1},this.listeners=[{element:this.element,events:{dragstart:function(a){return function(b){return a.emit("dragstart",b)}}(this),dragenter:function(a){return function(c){return b(c),a.emit("dragenter",c)}}(this),dragover:function(a){return function(c){var d;try{d=c.dataTransfer.effectAllowed}catch(e){}return c.dataTransfer.dropEffect="move"===d||"linkMove"===d?"move":"copy",b(c),a.emit("dragover",c)}}(this),dragleave:function(a){return function(b){return a.emit("dragleave",b)}}(this),drop:function(a){return function(c){return b(c),a.drop(c)}}(this),dragend:function(a){return function(b){return a.emit("dragend",b)}}(this)}}],this.clickableElements.forEach(function(a){return function(b){return a.listeners.push({element:b,events:{click:function(d){return(b!==a.element||d.target===a.element||c.elementInside(d.target,a.element.querySelector(".dz-message")))&&a.hiddenFileInput.click(),!0}}})}}(this)),this.enable(),this.options.init.call(this)},c.prototype.destroy=function(){var a;return this.disable(),this.removeAllFiles(!0),(null!=(a=this.hiddenFileInput)?a.parentNode:void 0)&&(this.hiddenFileInput.parentNode.removeChild(this.hiddenFileInput),this.hiddenFileInput=null),delete this.element.dropzone,c.instances.splice(c.instances.indexOf(this),1)},c.prototype.updateTotalUploadProgress=function(){var a,b,c,d,e,f,g,h;if(d=0,c=0,a=this.getActiveFiles(),a.length){for(h=this.getActiveFiles(),f=0,g=h.length;g>f;f++)b=h[f],d+=b.upload.bytesSent,c+=b.upload.total;e=100*d/c}else e=100;return this.emit("totaluploadprogress",e,c,d)},c.prototype._getParamName=function(a){return"function"==typeof this.options.paramName?this.options.paramName(a):""+this.options.paramName+(this.options.uploadMultiple?"["+a+"]":"")},c.prototype.getFallbackForm=function(){var a,b,d,e;return(a=this.getExistingFallback())?a:(d='
          ',this.options.dictFallbackText&&(d+="

          "+this.options.dictFallbackText+"

          "),d+='
          ',b=c.createElement(d),"FORM"!==this.element.tagName?(e=c.createElement(''),e.appendChild(b)):(this.element.setAttribute("enctype","multipart/form-data"),this.element.setAttribute("method",this.options.method)),null!=e?e:b)},c.prototype.getExistingFallback=function(){var a,b,c,d,e,f;for(b=function(a){var b,c,d;for(c=0,d=a.length;d>c;c++)if(b=a[c],/(^| )fallback($| )/.test(b.className))return b},f=["div","form"],d=0,e=f.length;e>d;d++)if(c=f[d],a=b(this.element.getElementsByTagName(c)))return a},c.prototype.setupEventListeners=function(){var a,b,c,d,e,f,g;for(f=this.listeners,g=[],d=0,e=f.length;e>d;d++)a=f[d],g.push(function(){var d,e;d=a.events,e=[];for(b in d)c=d[b],e.push(a.element.addEventListener(b,c,!1));return e}());return g},c.prototype.removeEventListeners=function(){var a,b,c,d,e,f,g;for(f=this.listeners,g=[],d=0,e=f.length;e>d;d++)a=f[d],g.push(function(){var d,e;d=a.events,e=[];for(b in d)c=d[b],e.push(a.element.removeEventListener(b,c,!1));return e}());return g},c.prototype.disable=function(){var a,b,c,d,e;for(this.clickableElements.forEach(function(a){return a.classList.remove("dz-clickable")}),this.removeEventListeners(),d=this.files,e=[],b=0,c=d.length;c>b;b++)a=d[b],e.push(this.cancelUpload(a));return e},c.prototype.enable=function(){return this.clickableElements.forEach(function(a){return a.classList.add("dz-clickable")}),this.setupEventListeners()},c.prototype.filesize=function(a){var b,c,d,e,f,g,h,i;if(d=0,e="b",a>0){for(g=["TB","GB","MB","KB","b"],c=h=0,i=g.length;i>h;c=++h)if(f=g[c],b=Math.pow(this.options.filesizeBase,4-c)/10,a>=b){d=a/Math.pow(this.options.filesizeBase,4-c),e=f;break}d=Math.round(10*d)/10}return""+d+" "+e},c.prototype._updateMaxFilesReachedClass=function(){return null!=this.options.maxFiles&&this.getAcceptedFiles().length>=this.options.maxFiles?(this.getAcceptedFiles().length===this.options.maxFiles&&this.emit("maxfilesreached",this.files),this.element.classList.add("dz-max-files-reached")):this.element.classList.remove("dz-max-files-reached")},c.prototype.drop=function(a){var b,c;a.dataTransfer&&(this.emit("drop",a),b=a.dataTransfer.files,this.emit("addedfiles",b),b.length&&(c=a.dataTransfer.items,c&&c.length&&null!=c[0].webkitGetAsEntry?this._addFilesFromItems(c):this.handleFiles(b)))},c.prototype.paste=function(a){var b,c;if(null!=(null!=a&&null!=(c=a.clipboardData)?c.items:void 0))return this.emit("paste",a),b=a.clipboardData.items,b.length?this._addFilesFromItems(b):void 0},c.prototype.handleFiles=function(a){var b,c,d,e;for(e=[],c=0,d=a.length;d>c;c++)b=a[c],e.push(this.addFile(b));return e},c.prototype._addFilesFromItems=function(a){var b,c,d,e,f;for(f=[],d=0,e=a.length;e>d;d++)c=a[d],f.push(null!=c.webkitGetAsEntry&&(b=c.webkitGetAsEntry())?b.isFile?this.addFile(c.getAsFile()):b.isDirectory?this._addFilesFromDirectory(b,b.name):void 0:null!=c.getAsFile?null==c.kind||"file"===c.kind?this.addFile(c.getAsFile()):void 0:void 0);return f},c.prototype._addFilesFromDirectory=function(a,b){var c,d;return c=a.createReader(),d=function(a){return function(c){var d,e,f;for(e=0,f=c.length;f>e;e++)d=c[e],d.isFile?d.file(function(c){return a.options.ignoreHiddenFiles&&"."===c.name.substring(0,1)?void 0:(c.fullPath=""+b+"/"+c.name,a.addFile(c))}):d.isDirectory&&a._addFilesFromDirectory(d,""+b+"/"+d.name)}}(this),c.readEntries(d,function(a){return"undefined"!=typeof console&&null!==console&&"function"==typeof console.log?console.log(a):void 0})},c.prototype.accept=function(a,b){return a.size>1024*this.options.maxFilesize*1024?b(this.options.dictFileTooBig.replace("{{filesize}}",Math.round(a.size/1024/10.24)/100).replace("{{maxFilesize}}",this.options.maxFilesize)):c.isValidFile(a,this.options.acceptedFiles)?null!=this.options.maxFiles&&this.getAcceptedFiles().length>=this.options.maxFiles?(b(this.options.dictMaxFilesExceeded.replace("{{maxFiles}}",this.options.maxFiles)),this.emit("maxfilesexceeded",a)):this.options.accept.call(this,a,b):b(this.options.dictInvalidFileType)},c.prototype.addFile=function(a){return a.upload={progress:0,total:a.size,bytesSent:0},this.files.push(a),a.status=c.ADDED,this.emit("addedfile",a),this._enqueueThumbnail(a),this.accept(a,function(b){return function(c){return c?(a.accepted=!1,b._errorProcessing([a],c)):(a.accepted=!0,b.options.autoQueue&&b.enqueueFile(a)),b._updateMaxFilesReachedClass()}}(this))},c.prototype.enqueueFiles=function(a){var b,c,d;for(c=0,d=a.length;d>c;c++)b=a[c],this.enqueueFile(b);return null},c.prototype.enqueueFile=function(a){if(a.status!==c.ADDED||a.accepted!==!0)throw new Error("This file can't be queued because it has already been processed or was rejected.");return a.status=c.QUEUED,this.options.autoProcessQueue?setTimeout(function(a){return function(){return a.processQueue()}}(this),0):void 0},c.prototype._thumbnailQueue=[],c.prototype._processingThumbnail=!1,c.prototype._enqueueThumbnail=function(a){return this.options.createImageThumbnails&&a.type.match(/image.*/)&&a.size<=1024*this.options.maxThumbnailFilesize*1024?(this._thumbnailQueue.push(a),setTimeout(function(a){return function(){return a._processThumbnailQueue()}}(this),0)):void 0},c.prototype._processThumbnailQueue=function(){return this._processingThumbnail||0===this._thumbnailQueue.length?void 0:(this._processingThumbnail=!0,this.createThumbnail(this._thumbnailQueue.shift(),function(a){return function(){return a._processingThumbnail=!1,a._processThumbnailQueue()}}(this)))},c.prototype.removeFile=function(a){return a.status===c.UPLOADING&&this.cancelUpload(a),this.files=h(this.files,a),this.emit("removedfile",a),0===this.files.length?this.emit("reset"):void 0},c.prototype.removeAllFiles=function(a){var b,d,e,f;for(null==a&&(a=!1),f=this.files.slice(),d=0,e=f.length;e>d;d++)b=f[d],(b.status!==c.UPLOADING||a)&&this.removeFile(b);return null},c.prototype.createThumbnail=function(a,b){var c;return c=new FileReader,c.onload=function(d){return function(){return"image/svg+xml"===a.type?(d.emit("thumbnail",a,c.result),void(null!=b&&b())):d.createThumbnailFromUrl(a,c.result,b)}}(this),c.readAsDataURL(a)},c.prototype.createThumbnailFromUrl=function(a,b,c,d){var e;return e=document.createElement("img"),d&&(e.crossOrigin=d),e.onload=function(b){return function(){var d,g,h,i,j,k,l,m;return a.width=e.width,a.height=e.height,h=b.options.resize.call(b,a),null==h.trgWidth&&(h.trgWidth=h.optWidth),null==h.trgHeight&&(h.trgHeight=h.optHeight),d=document.createElement("canvas"),g=d.getContext("2d"),d.width=h.trgWidth,d.height=h.trgHeight,f(g,e,null!=(j=h.srcX)?j:0,null!=(k=h.srcY)?k:0,h.srcWidth,h.srcHeight,null!=(l=h.trgX)?l:0,null!=(m=h.trgY)?m:0,h.trgWidth,h.trgHeight),i=d.toDataURL("image/png"),b.emit("thumbnail",a,i),null!=c?c():void 0}}(this),null!=c&&(e.onerror=c),e.src=b},c.prototype.processQueue=function(){var a,b,c,d;if(b=this.options.parallelUploads,c=this.getUploadingFiles().length,a=c,!(c>=b)&&(d=this.getQueuedFiles(),d.length>0)){if(this.options.uploadMultiple)return this.processFiles(d.slice(0,b-c));for(;b>a;){if(!d.length)return;this.processFile(d.shift()),a++}}},c.prototype.processFile=function(a){return this.processFiles([a])},c.prototype.processFiles=function(a){var b,d,e;for(d=0,e=a.length;e>d;d++)b=a[d],b.processing=!0,b.status=c.UPLOADING,this.emit("processing",b);return this.options.uploadMultiple&&this.emit("processingmultiple",a),this.uploadFiles(a)},c.prototype._getFilesWithXhr=function(a){var b,c;return c=function(){var c,d,e,f;for(e=this.files,f=[],c=0,d=e.length;d>c;c++)b=e[c],b.xhr===a&&f.push(b);return f}.call(this)},c.prototype.cancelUpload=function(a){var b,d,e,f,g,h,i;if(a.status===c.UPLOADING){for(d=this._getFilesWithXhr(a.xhr),e=0,g=d.length;g>e;e++)b=d[e],b.status=c.CANCELED;for(a.xhr.abort(),f=0,h=d.length;h>f;f++)b=d[f],this.emit("canceled",b);this.options.uploadMultiple&&this.emit("canceledmultiple",d)}else((i=a.status)===c.ADDED||i===c.QUEUED)&&(a.status=c.CANCELED,this.emit("canceled",a),this.options.uploadMultiple&&this.emit("canceledmultiple",[a]));return this.options.autoProcessQueue?this.processQueue():void 0},e=function(){var a,b;return b=arguments[0],a=2<=arguments.length?i.call(arguments,1):[],"function"==typeof b?b.apply(this,a):b},c.prototype.uploadFile=function(a){return this.uploadFiles([a])},c.prototype.uploadFiles=function(a){var b,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z,A,B,C,D,E,F,G,H,I,J,K,L;for(w=new XMLHttpRequest,x=0,B=a.length;B>x;x++)b=a[x],b.xhr=w;p=e(this.options.method,a),u=e(this.options.url,a),w.open(p,u,!0),w.withCredentials=!!this.options.withCredentials,s=null,g=function(c){return function(){var d,e,f;for(f=[],d=0,e=a.length;e>d;d++)b=a[d],f.push(c._errorProcessing(a,s||c.options.dictResponseError.replace("{{statusCode}}",w.status),w));return f}}(this),t=function(c){return function(d){var e,f,g,h,i,j,k,l,m;if(null!=d)for(f=100*d.loaded/d.total,g=0,j=a.length;j>g;g++)b=a[g],b.upload={progress:f,total:d.total,bytesSent:d.loaded};else{for(e=!0,f=100,h=0,k=a.length;k>h;h++)b=a[h],(100!==b.upload.progress||b.upload.bytesSent!==b.upload.total)&&(e=!1),b.upload.progress=f,b.upload.bytesSent=b.upload.total;if(e)return}for(m=[],i=0,l=a.length;l>i;i++)b=a[i],m.push(c.emit("uploadprogress",b,f,b.upload.bytesSent));return m}}(this),w.onload=function(b){return function(d){var e;if(a[0].status!==c.CANCELED&&4===w.readyState){if(s=w.responseText,w.getResponseHeader("content-type")&&~w.getResponseHeader("content-type").indexOf("application/json"))try{s=JSON.parse(s)}catch(f){d=f,s="Invalid JSON response from server."}return t(),200<=(e=w.status)&&300>e?b._finished(a,s,d):g()}}}(this),w.onerror=function(){return function(){return a[0].status!==c.CANCELED?g():void 0}}(this),r=null!=(G=w.upload)?G:w,r.onprogress=t,j={Accept:"application/json","Cache-Control":"no-cache","X-Requested-With":"XMLHttpRequest"},this.options.headers&&d(j,this.options.headers);for(h in j)i=j[h],i&&w.setRequestHeader(h,i);if(f=new FormData,this.options.params){H=this.options.params;for(o in H)v=H[o],f.append(o,v)}for(y=0,C=a.length;C>y;y++)b=a[y],this.emit("sending",b,w,f);if(this.options.uploadMultiple&&this.emit("sendingmultiple",a,w,f),"FORM"===this.element.tagName)for(I=this.element.querySelectorAll("input, textarea, select, button"),z=0,D=I.length;D>z;z++)if(l=I[z],m=l.getAttribute("name"),n=l.getAttribute("type"),"SELECT"===l.tagName&&l.hasAttribute("multiple"))for(J=l.options,A=0,E=J.length;E>A;A++)q=J[A],q.selected&&f.append(m,q.value);else(!n||"checkbox"!==(K=n.toLowerCase())&&"radio"!==K||l.checked)&&f.append(m,l.value);for(k=F=0,L=a.length-1;L>=0?L>=F:F>=L;k=L>=0?++F:--F)f.append(this._getParamName(k),a[k],a[k].name);return this.submitRequest(w,f,a)},c.prototype.submitRequest=function(a,b){return a.send(b)},c.prototype._finished=function(a,b,d){var e,f,g;for(f=0,g=a.length;g>f;f++)e=a[f],e.status=c.SUCCESS,this.emit("success",e,b,d),this.emit("complete",e);return this.options.uploadMultiple&&(this.emit("successmultiple",a,b,d),this.emit("completemultiple",a)),this.options.autoProcessQueue?this.processQueue():void 0},c.prototype._errorProcessing=function(a,b,d){var e,f,g;for(f=0,g=a.length;g>f;f++)e=a[f],e.status=c.ERROR,this.emit("error",e,b,d),this.emit("complete",e);return this.options.uploadMultiple&&(this.emit("errormultiple",a,b,d),this.emit("completemultiple",a)),this.options.autoProcessQueue?this.processQueue():void 0},c}(b),a.version="4.2.0",a.options={},a.optionsForElement=function(b){return b.getAttribute("id")?a.options[c(b.getAttribute("id"))]:void 0},a.instances=[],a.forElement=function(a){if("string"==typeof a&&(a=document.querySelector(a)),null==(null!=a?a.dropzone:void 0))throw new Error("No Dropzone found for given element. This is probably because you're trying to access it before Dropzone had the time to initialize. Use the `init` option to setup any additional observers on your Dropzone.");return a.dropzone},a.autoDiscover=!0,a.discover=function(){var b,c,d,e,f,g;for(document.querySelectorAll?d=document.querySelectorAll(".dropzone"):(d=[],b=function(a){var b,c,e,f;for(f=[],c=0,e=a.length;e>c;c++)b=a[c],f.push(/(^| )dropzone($| )/.test(b.className)?d.push(b):void 0);return f},b(document.getElementsByTagName("div")),b(document.getElementsByTagName("form"))),g=[],e=0,f=d.length;f>e;e++)c=d[e],g.push(a.optionsForElement(c)!==!1?new a(c):void 0);return g},a.blacklistedBrowsers=[/opera.*(Windows Phone|Macintosh).*version\/12/i],a.isBrowserSupported=function(){var b,c,d,e,f;if(b=!0,window.File&&window.FileReader&&window.FileList&&window.Blob&&window.FormData&&document.querySelector)if("classList"in document.createElement("a"))for(f=a.blacklistedBrowsers,d=0,e=f.length;e>d;d++)c=f[d],c.test(navigator.userAgent)&&(b=!1);else b=!1;else b=!1;return b},h=function(a,b){var c,d,e,f;for(f=[],d=0,e=a.length;e>d;d++)c=a[d],c!==b&&f.push(c);return f},c=function(a){return a.replace(/[\-_](\w)/g,function(a){return a.charAt(1).toUpperCase()})},a.createElement=function(a){var b;return b=document.createElement("div"),b.innerHTML=a,b.childNodes[0]},a.elementInside=function(a,b){if(a===b)return!0;for(;a=a.parentNode;)if(a===b)return!0;return!1},a.getElement=function(a,b){var c;if("string"==typeof a?c=document.querySelector(a):null!=a.nodeType&&(c=a),null==c)throw new Error("Invalid `"+b+"` option provided. Please provide a CSS selector or a plain HTML element.");return c},a.getElements=function(a,b){var c,d,e,f,g,h,i,j;if(a instanceof Array){e=[];try{for(f=0,h=a.length;h>f;f++)d=a[f],e.push(this.getElement(d,b))}catch(k){c=k,e=null}}else if("string"==typeof a)for(e=[],j=document.querySelectorAll(a),g=0,i=j.length;i>g;g++)d=j[g],e.push(d);else null!=a.nodeType&&(e=[a]);if(null==e||!e.length)throw new Error("Invalid `"+b+"` option provided. Please provide a CSS selector, a plain HTML element or a list of those.");return e},a.confirm=function(a,b,c){return window.confirm(a)?b():null!=c?c():void 0},a.isValidFile=function(a,b){var c,d,e,f,g;if(!b)return!0;for(b=b.split(","),d=a.type,c=d.replace(/\/.*$/,""),f=0,g=b.length;g>f;f++)if(e=b[f],e=e.trim(),"."===e.charAt(0)){if(-1!==a.name.toLowerCase().indexOf(e.toLowerCase(),a.name.length-e.length))return!0}else if(/\/\*$/.test(e)){if(c===e.replace(/\/.*$/,""))return!0}else if(d===e)return!0;return!1},"undefined"!=typeof jQuery&&null!==jQuery&&(jQuery.fn.dropzone=function(b){return this.each(function(){return new a(this,b)})}),"undefined"!=typeof module&&null!==module?module.exports=a:window.Dropzone=a,a.ADDED="added",a.QUEUED="queued",a.ACCEPTED=a.QUEUED,a.UPLOADING="uploading",a.PROCESSING=a.UPLOADING,a.CANCELED="canceled",a.ERROR="error",a.SUCCESS="success",e=function(a){var b,c,d,e,f,g,h,i,j,k; -for(h=a.naturalWidth,g=a.naturalHeight,c=document.createElement("canvas"),c.width=1,c.height=g,d=c.getContext("2d"),d.drawImage(a,0,0),e=d.getImageData(0,0,1,g).data,k=0,f=g,i=g;i>k;)b=e[4*(i-1)+3],0===b?f=i:k=i,i=f+k>>1;return j=i/g,0===j?1:j},f=function(a,b,c,d,f,g,h,i,j,k){var l;return l=e(b),a.drawImage(b,c,d,f,g,h,i,j,k/l)},d=function(a,b){var c,d,e,f,g,h,i,j,k;if(e=!1,k=!0,d=a.document,j=d.documentElement,c=d.addEventListener?"addEventListener":"attachEvent",i=d.addEventListener?"removeEventListener":"detachEvent",h=d.addEventListener?"":"on",f=function(c){return"readystatechange"!==c.type||"complete"===d.readyState?(("load"===c.type?a:d)[i](h+c.type,f,!1),!e&&(e=!0)?b.call(a,c.type||c):void 0):void 0},g=function(){var a;try{j.doScroll("left")}catch(b){return a=b,void setTimeout(g,50)}return f("poll")},"complete"!==d.readyState){if(d.createEventObject&&j.doScroll){try{k=!a.frameElement}catch(l){}k&&g()}return d[c](h+"DOMContentLoaded",f,!1),d[c](h+"readystatechange",f,!1),a[c](h+"load",f,!1)}},a._autoDiscoverFunction=function(){return a.autoDiscover?a.discover():void 0},d(window,a._autoDiscoverFunction)}).call(this); +(function(){function k(k,n){for(var p="",l=n;lr)return!1;var l=l+r,r=k.getUint16(l,!p),v,w;for(w=0;w
        '),this.element.appendChild(b));if(a=b.getElementsByTagName("span")[0])null!=a.textContent?a.textContent= +this.options.dictFallbackMessage:null!=a.innerText&&(a.innerText=this.options.dictFallbackMessage);return this.element.appendChild(this.getFallbackForm())},resize:function(a){var b,d,f;b={srcX:0,srcY:0,srcWidth:a.width,srcHeight:a.height};d=a.width/a.height;b.optWidth=this.options.thumbnailWidth;b.optHeight=this.options.thumbnailHeight;null==b.optWidth&&null==b.optHeight?(b.optWidth=b.srcWidth,b.optHeight=b.srcHeight):null==b.optWidth?b.optWidth=d*b.optHeight:null==b.optHeight&&(b.optHeight=1/d*b.optWidth); +f=b.optWidth/b.optHeight;a.heightf?(b.srcHeight=a.height,b.srcWidth=b.srcHeight*f):(b.srcWidth=a.width,b.srcHeight=b.srcWidth/f);b.srcX=(a.width-b.srcWidth)/2;b.srcY=(a.height-b.srcHeight)/2;return b},drop:function(a){return this.element.classList.remove("dz-drag-hover")},dragstart:l,dragend:function(a){return this.element.classList.remove("dz-drag-hover")},dragenter:function(a){return this.element.classList.add("dz-drag-hover")}, +dragover:function(a){return this.element.classList.add("dz-drag-hover")},dragleave:function(a){return this.element.classList.remove("dz-drag-hover")},paste:l,reset:function(){return this.element.classList.remove("dz-started")},addedfile:function(a){var b,d,f,g,m,x;this.element===this.previewsContainer&&this.element.classList.add("dz-started");if(this.previewsContainer){a.previewElement=c.createElement(this.options.previewTemplate.trim());a.previewTemplate=a.previewElement;this.previewsContainer.appendChild(a.previewElement); +g=a.previewElement.querySelectorAll("[data-dz-name]");d=0;for(f=g.length;d'+this.options.dictRemoveFile+""),a.previewElement.appendChild(a._removeLink));b=function(b){return function(d){d.preventDefault();d.stopPropagation(); +return a.status===c.UPLOADING?c.confirm(b.options.dictCancelUploadConfirmation,function(){return b.removeFile(a)}):b.options.dictRemoveFileConfirmation?c.confirm(b.options.dictRemoveFileConfirmation,function(){return b.removeFile(a)}):b.removeFile(a)}}(this);m=a.previewElement.querySelectorAll("[data-dz-remove]");x=[];f=0;for(g=m.length;f\n
        \n
        \n
        \n
        \n
        \n
        \n
        \n
        \n \n Check\n \n \n \n \n \n
        \n
        \n \n Error\n \n \n \n \n \n \n \n
        \n
        '}; +k=function(){var a,b,d,c,g,m,x;c=arguments[0];d=2<=arguments.length?v.call(arguments,1):[];m=0;for(x=d.length;m'+this.options.dictDefaultMessage+""));this.clickableElements.length&&(d=function(a){return function(){a.hiddenFileInput&&a.hiddenFileInput.parentNode.removeChild(a.hiddenFileInput);a.hiddenFileInput= +document.createElement("input");a.hiddenFileInput.setAttribute("type","file");(null==a.options.maxFiles||1"); +a+='';a=c.createElement(a);"FORM"!==this.element.tagName?(b=c.createElement('
        '),b.appendChild(a)):(this.element.setAttribute("enctype","multipart/form-data"),this.element.setAttribute("method",this.options.method));return null!=b?b:a}; +c.prototype.getExistingFallback=function(){var a,b,d,c,g;b=function(a){var b,d,c;d=0;for(c=a.length;d=b){f=a/Math.pow(this.options.filesizeBase,4-c);g=e;break}f=Math.round(10*f)/10}return""+f+" "+g};c.prototype._updateMaxFilesReachedClass=function(){return null!= +this.options.maxFiles&&this.getAcceptedFiles().length>=this.options.maxFiles?(this.getAcceptedFiles().length===this.options.maxFiles&&this.emit("maxfilesreached",this.files),this.element.classList.add("dz-max-files-reached")):this.element.classList.remove("dz-max-files-reached")};c.prototype.drop=function(a){var b;a.dataTransfer&&(this.emit("drop",a),b=a.dataTransfer.files,this.emit("addedfiles",b),b.length&&((a=a.dataTransfer.items)&&a.length&&null!=a[0].webkitGetAsEntry?this._addFilesFromItems(a): +this.handleFiles(b)))};c.prototype.paste=function(a){var b;if(null!=(null!=a?null!=(b=a.clipboardData)?b.items:void 0:void 0)&&(this.emit("paste",a),a=a.clipboardData.items,a.length))return this._addFilesFromItems(a)};c.prototype.handleFiles=function(a){var b,c,f,g;g=[];c=0;for(f=a.length;c1048576*this.options.maxFilesize?b(this.options.dictFileTooBig.replace("{{filesize}}",Math.round(a.size/1024/10.24)/100).replace("{{maxFilesize}}",this.options.maxFilesize)):c.isValidFile(a,this.options.acceptedFiles)?null!=this.options.maxFiles&&this.getAcceptedFiles().length>= +this.options.maxFiles?(b(this.options.dictMaxFilesExceeded.replace("{{maxFiles}}",this.options.maxFiles)),this.emit("maxfilesexceeded",a)):this.options.accept.call(this,a,b):b(this.options.dictInvalidFileType)};c.prototype.addFile=function(a){a.upload={progress:0,total:a.size,bytesSent:0};this.files.push(a);a.status=c.ADDED;this.emit("addedfile",a);this._enqueueThumbnail(a);return this.accept(a,function(b){return function(c){c?(a.accepted=!1,b._errorProcessing([a],c)):(a.accepted=!0,b.options.autoQueue&& +b.enqueueFile(a));return b._updateMaxFilesReachedClass()}}(this))};c.prototype.enqueueFiles=function(a){var b,c,f;c=0;for(f=a.length;c=b)&&(f=this.getQueuedFiles(),0 +e?b._finished(a,r,d):f()}}}(this);t.onerror=function(b){return function(){if(a[0].status!==c.CANCELED)return f()}}(this);(null!=(g=t.upload)?g:t).onprogress=w;e={Accept:"application/json","Cache-Control":"no-cache","X-Requested-With":"XMLHttpRequest"};this.options.headers&&k(e,this.options.headers);for(d in e)(g=e[d])&&t.setRequestHeader(d,g);d=new FormData;if(this.options.params)for(n in e=this.options.params,e)g=e[n],d.append(n,g);n=0;for(g=a.length;n=g;l=0<=g?++n:--n)d.append(this._getParamName(l), +a[l],a[l].name);return this.submitRequest(t,d,a)};c.prototype.submitRequest=function(a,b,c){return a.send(b)};c.prototype._finished=function(a,b,d){var f,e,h;e=0;for(h=a.length;eb;)e=c[4*(a-1)+3],0===e?k=a:b=a,a=k+b>>1;h=a/h;return 0===h?1:h};p=function(e,c,k,h,a,b,d,f,g,m){var l; +l=n(c);m/=l;l=0;switch(EXIF.getData(c)){case 3:l=2;break;case 6:l=1;break;case 8:l=-1}l&&(e.translate(d+g/2,f+m/2),e.rotate(l*Math.PI/2),d=-g/2,f=-m/2);return e.drawImage(c,k,h,a,b,d,f,g,m)};k._autoDiscoverFunction=function(){if(k.autoDiscover)return k.discover()};(function(e,c){var k,h,a,b,d,f,g,l,n;a=!1;n=!0;h=e.document;l=h.documentElement;k=h.addEventListener?"addEventListener":"attachEvent";g=h.addEventListener?"removeEventListener":"detachEvent";f=h.addEventListener?"":"on";b=function(d){if("readystatechange"!== +d.type||"complete"===h.readyState)if(("load"===d.type?e:h)[g](f+d.type,b,!1),!a&&(a=!0))return c.call(e,d.type||d)};d=function(){try{l.doScroll("left")}catch(a){setTimeout(d,50);return}return b("poll")};if("complete"!==h.readyState){if(h.createEventObject&&l.doScroll){try{n=!e.frameElement}catch(p){}n&&d()}h[k](f+"DOMContentLoaded",b,!1);h[k](f+"readystatechange",b,!1);return e[k](f+"load",b,!1)}})(window,k._autoDiscoverFunction)}).call(this); diff --git a/web/js/src/exif.js b/web/js/src/exif.js new file mode 100644 index 000000000..3a2c7e1c3 --- /dev/null +++ b/web/js/src/exif.js @@ -0,0 +1,94 @@ +/* Cut down version of https://github.com/exif-js/exif-js + * only looking for orientation EXIF data. MIT. */ + +(function() { + var EXIF = {}; + window.EXIF = EXIF; + + function readEXIFData(file, start) { + var str = ""; + for (var n = start; n < start+4; n++) { + str += String.fromCharCode(file.getUint8(n)); + } + if (str != "Exif") { + return false; + } + + var bigEnd, + tiffOffset = start + 6; + + // test for TIFF validity and endianness + if (file.getUint16(tiffOffset) == 0x4949) { + bigEnd = false; + } else if (file.getUint16(tiffOffset) == 0x4D4D) { + bigEnd = true; + } else { + return false; + } + + if (file.getUint16(tiffOffset+2, !bigEnd) != 0x002A) { + return false; + } + + var firstIFDOffset = file.getUint32(tiffOffset+4, !bigEnd); + if (firstIFDOffset < 0x00000008) { + return false; + } + + var dirStart = tiffOffset + firstIFDOffset, + entries = file.getUint16(dirStart, !bigEnd), + tags = {}, + entryOffset, + i; + + for (i=0;i Date: Tue, 21 Jun 2016 09:24:56 +0100 Subject: Remove default box-shadow from .content and aside Fixes #1419. We also standardize on using `@include box-shadow()` where possible, and clearing out lots of now unnecessary box-shadow resets. --- web/cobrands/eastsussex/layout.scss | 4 ---- web/cobrands/fixmystreet.com/posters.scss | 1 - web/cobrands/harrogate/layout.scss | 1 - web/cobrands/hart/layout.scss | 5 ----- web/cobrands/oxfordshire/layout.scss | 28 +++++++++------------------- web/cobrands/sass/_layout.scss | 13 +------------ web/cobrands/sass/_mixins.scss | 14 +++++++------- web/cobrands/stevenage/layout.scss | 1 - web/cobrands/zurich/layout.scss | 29 ++++++++--------------------- 9 files changed, 25 insertions(+), 71 deletions(-) diff --git a/web/cobrands/eastsussex/layout.scss b/web/cobrands/eastsussex/layout.scss index 20be807a6..1f7c3bbb3 100644 --- a/web/cobrands/eastsussex/layout.scss +++ b/web/cobrands/eastsussex/layout.scss @@ -191,10 +191,6 @@ body.frontpage { width: auto; } -body.twothirdswidthpage .content aside { - box-shadow: 0 0 12px 0 #dae1e5; -} - .banner p#fixed { background-position: -328px -333px; } diff --git a/web/cobrands/fixmystreet.com/posters.scss b/web/cobrands/fixmystreet.com/posters.scss index ee8da9d32..518462539 100644 --- a/web/cobrands/fixmystreet.com/posters.scss +++ b/web/cobrands/fixmystreet.com/posters.scss @@ -129,7 +129,6 @@ body.goodies { padding: 0; aside { - box-shadow: none; background-color: inherit; } } diff --git a/web/cobrands/harrogate/layout.scss b/web/cobrands/harrogate/layout.scss index 417eff539..d8cc3b441 100644 --- a/web/cobrands/harrogate/layout.scss +++ b/web/cobrands/harrogate/layout.scss @@ -77,7 +77,6 @@ body.twothirdswidthpage .container .content { body.twothirdswidthpage .content aside { margin-top: 2em; - @include box-shadow(none); } diff --git a/web/cobrands/hart/layout.scss b/web/cobrands/hart/layout.scss index 99f8bdfcf..7799fa3fd 100644 --- a/web/cobrands/hart/layout.scss +++ b/web/cobrands/hart/layout.scss @@ -33,7 +33,6 @@ body.twothirdswidthpage .content { left: 672px; width: 208px; padding: 16px; - @include box-shadow(none); } .sticky-sidebar { left: 672px; @@ -43,7 +42,3 @@ body.twothirdswidthpage .content { } } } - -.content { - @include box-shadow(none); -} diff --git a/web/cobrands/oxfordshire/layout.scss b/web/cobrands/oxfordshire/layout.scss index 0bd37b95f..bc5c6c93a 100644 --- a/web/cobrands/oxfordshire/layout.scss +++ b/web/cobrands/oxfordshire/layout.scss @@ -34,24 +34,15 @@ body, body a { display: none; } -// White background, so no shadow or margin needed. -.content { +// White background, so no margin needed. +.content, +.iel8 .content { margin: 0; - @include box-shadow(none); -} -.iel8 { - .content { - margin: 0; - border: none; - } } // Fix location of aside sidebar body.twothirdswidthpage { .content { - aside { - @include box-shadow(none); - } .sticky-sidebar { aside { position: fixed; @@ -114,7 +105,7 @@ body.mappage { background-color: #069b01; // picked from header.jpg background-position: 100% 40%; overflow: auto; - box-shadow: 0 0 5px rgba(0,0,0,0.3); + @include box-shadow(0 0 5px rgba(0,0,0,0.3)); & > * { display: none; @@ -309,9 +300,7 @@ h4.static-with-rule { width: 432px; ul#key-tools { - -webkit-box-shadow: 0em 0px 1em 1em $oxfordshire_very_light_green; - -moz-box-shadow: 0em 0px 1em 1em $oxfordshire_very_light_green; - box-shadow: 0em 0px 1em 1em $oxfordshire_very_light_green; + @include box-shadow(0 0 1em 1em $oxfordshire_very_light_green); border-top-width: 2px; } } @@ -345,9 +334,10 @@ input.green-btn{ -webkit-border-radius: 4px; -moz-border-radius: 4px; border-radius: 4px; - -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); - -moz-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); - box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); + @include box-shadow( + inset 0 1px 0 rgba(255, 255, 255, 0.2), + 0 1px 2px rgba(0, 0, 0, 0.05) + ); text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); font-weight: normal; cursor: pointer; diff --git a/web/cobrands/sass/_layout.scss b/web/cobrands/sass/_layout.scss index 5ed4ddb97..bdb8e90a7 100644 --- a/web/cobrands/sass/_layout.scss +++ b/web/cobrands/sass/_layout.scss @@ -222,12 +222,9 @@ h1 { padding: 1em 1em 3em; background: #fff; color: #222; - @include box-shadow(0 0 10px rgba(0,0,0,0.5)); } .iel8 { .content { - // If no box-shadow, just want a boring black border to stand it out from the map. - border: 1px solid #666; //take off margins so we line up properly margin: 0 0.5em; } @@ -392,7 +389,6 @@ body.twothirdswidthpage, body.fullwidthpage { .container { .content { - box-shadow: none; padding: 1em; margin-bottom: 0em; footer { @@ -438,10 +434,6 @@ body.fullwidthpage { .iel8 { body.twothirdswidthpage, body.fullwidthpage { - .content { - border: 0px; - } - .container .content footer a.platform-logo { color: #ffffff; background: none; @@ -470,7 +462,6 @@ body.twothirdswidthpage { z-index: -1; width:13em; padding:1em; - @include box-shadow(0px 0px 6px 1px #000); h2 { margin-top: 0; } @@ -507,7 +498,6 @@ body.authpage { margin-#{$left}: auto; margin-#{$right}: auto; margin-bottom: 0; - box-shadow: none; padding: 1em; // same as .twothirdswidthpage .content } } @@ -556,7 +546,6 @@ body.authpage { border-#{$right}: 1em solid transparent; background:none; padding:0; - @include box-shadow(inset rgba(0, 0, 0, 0) 0 0 0); h2 { color:#222; margin-top:0; @@ -720,7 +709,7 @@ body.authpage { ul#key-tools { border-top: 0.25em solid $primary; margin: 0; - @include box-shadow(-0em 0px 1em 1em #fff); + @include box-shadow(0 0 1em 1em #fff); li { border:none; a, input[type=submit] { diff --git a/web/cobrands/sass/_mixins.scss b/web/cobrands/sass/_mixins.scss index 71f9b95a3..5bbbc19eb 100644 --- a/web/cobrands/sass/_mixins.scss +++ b/web/cobrands/sass/_mixins.scss @@ -71,16 +71,16 @@ $right: right; @include experimental(border-radius, $radius, -moz, -webkit, not -o, not -ms, official); } -@mixin box-shadow($shadow) { - @include experimental(box-shadow, $shadow, -moz, -webkit, not -o, not -ms, official); +@mixin box-shadow($shadows...) { + @include experimental(box-shadow, $shadows, -moz, -webkit, not -o, not -ms, official); } @mixin experimental($property, $value, $moz: true, $webkit: true, $o: true, $ms: true, $official: true) { - @if $webkit { -webkit-#{$property} : $value; } - @if $moz { -moz-#{$property} : $value; } - @if $ms { -ms-#{$property} : $value; } - @if $o { -o-#{$property} : $value; } - @if $official { #{$property} : $value; } + @if $webkit { -webkit-#{$property} : #{$value}; } + @if $moz { -moz-#{$property} : #{$value}; } + @if $ms { -ms-#{$property} : #{$value}; } + @if $o { -o-#{$property} : #{$value}; } + @if $official { #{$property} : #{$value}; } } @mixin inline-block($alignment: middle) { diff --git a/web/cobrands/stevenage/layout.scss b/web/cobrands/stevenage/layout.scss index f55ac0d15..901f3fb3e 100644 --- a/web/cobrands/stevenage/layout.scss +++ b/web/cobrands/stevenage/layout.scss @@ -80,7 +80,6 @@ // d523b431 body.fullwidthpage { .content { - @include box-shadow(none); background: none; } } diff --git a/web/cobrands/zurich/layout.scss b/web/cobrands/zurich/layout.scss index 3f24b3685..57cae97e9 100644 --- a/web/cobrands/zurich/layout.scss +++ b/web/cobrands/zurich/layout.scss @@ -4,35 +4,25 @@ // Things to override from parent stylesheet -// White background, so no shadow or margin needed. .content { color: #3c3c3c; - @include box-shadow(none); -} -.iel8 { - .content { - border: none; - } } -// Except on map pages (which includes the front page) -body.mappage .content, body.frontpage .content { + +// Front page content needs a shadow. +// (Purely decorative: No need for border fallback for IE8) +body.frontpage .content { @include box-shadow(0 0 6px 1px #000); } -.iel8 { - body.mappage .content, body.frontpage .content { - border: 1px solid #666; - } -} -/* The header on a map page needs a shadow too */ -body.mappage .nav-wrapper-2 { +// The header on a map page needs a shadow too +body.mappage .nav-wrapper .nav-wrapper-2 { @include box-shadow(0 0 6px 1px #000); } -/* Except on admin pages where there's an admin nav directly underneath it */ +// Except on admin pages where there's an admin nav directly underneath it body.mappage.admin .nav-wrapper-2 { @include box-shadow(none); } -/* Fix positioning of images in the admin */ +// Fix positioning of images in the admin body.admin .admin-nav-wrapper { z-index: 1; } @@ -191,9 +181,6 @@ body.mappage { body.twothirdswidthpage { .content { - aside { - @include box-shadow(none); - } .sticky-sidebar aside { top: 14em; // overrides default value, due to Zurich nav at top of content } -- cgit v1.2.3 From cb6e7350bdc42e4d329ed1dcc05c074bca697384 Mon Sep 17 00:00:00 2001 From: Zarino Zappia Date: Tue, 21 Jun 2016 09:52:48 +0100 Subject: Reinstate missing margin before reporting form email input MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `.form-box--logged-in-name` has no preceding heading, which meant the grey box background was colliding with whatever content happened to go before it. We add some margin, and while we’re at it, remove the extra margin-top on first-child labels (unnecessary, since .form-boxes have their own padding) and tidy up the syntax of the .form-box rule set. Fixes #1418. --- web/cobrands/sass/_base.scss | 35 +++++++++++++++++++++++++---------- 1 file changed, 25 insertions(+), 10 deletions(-) diff --git a/web/cobrands/sass/_base.scss b/web/cobrands/sass/_base.scss index 2c8c90c6f..754e9f75d 100644 --- a/web/cobrands/sass/_base.scss +++ b/web/cobrands/sass/_base.scss @@ -313,24 +313,32 @@ label{ margin: 0 -1em 0.25em; background: #eee; padding: 1em; - > input[type=text], input[type=email] { - margin-bottom:1em; + + & > input[type=text], + & > input[type=email] { + margin-bottom: 1em; + } + + & > label:first-child { + margin-top: 0; } + .title { - font-size:1.25em; - margin:0.5em 0; + font-size: 1.25em; + margin: 0.5em 0; } + h2 { margin: 0 0 0.5em; } + h5 { - margin:0 0 1em; - font: { - size:1.125em; - weight:normal; - } + margin: 0 0 1em; + font-size: 1.125em; + font-weight: normal; + strong { - font-size:2em; + font-size: 2em; margin-#{$right}: 0.25em; } } @@ -342,6 +350,13 @@ label{ margin: 0 0 0.25em; padding: 1em; } + +// When the user is logged in, we show a shorter form-box, +// without a heading before it. So add some space before. +#form-box--logged-in-name { + margin-top: 1.25em; +} + // Prevent grey displaying oddly by giving it a width, and stop odd left margin issue .ie7 .form-box { width: 100%; -- cgit v1.2.3 From a060d03f36275f1fae1c041cca813bddeef6287c Mon Sep 17 00:00:00 2001 From: Dave Arter Date: Mon, 27 Jun 2016 12:42:31 +0100 Subject: Use valid orientation flag for test image jhead 3.00 considers 0 an invalid value for EXIF orientation and will replace it with 1 when run with the -autorot flag. This was causing a test failure as the SHA hash of the sample image was being changed. --- t/app/controller/photo.t | 6 +++--- t/app/controller/sample.jpg | Bin 22588 -> 22570 bytes t/app/model/photoset.t | 2 +- t/open311/getservicerequestupdates.t | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/t/app/controller/photo.t b/t/app/controller/photo.t index 4cec82c44..a065c7732 100644 --- a/t/app/controller/photo.t +++ b/t/app/controller/photo.t @@ -66,12 +66,12 @@ subtest "Check multiple upload worked" => sub { ok $mech->success, 'Made request with multiple photo upload'; $mech->base_is('http://localhost/report/new'); $mech->content_like( - qr[(\s*){3}], + qr[(\s*){3}], 'Three uploaded pictures are all shown, safe'); $mech->content_contains( - 'name="upload_fileid" value="1cdd4329ceee2234bd4e89cb33b42061a0724687.jpeg,1cdd4329ceee2234bd4e89cb33b42061a0724687.jpeg,1cdd4329ceee2234bd4e89cb33b42061a0724687.jpeg"', + 'name="upload_fileid" value="7f09ef2c3933731d47121fee1b8038b3fdd3bc77.jpeg,7f09ef2c3933731d47121fee1b8038b3fdd3bc77.jpeg,7f09ef2c3933731d47121fee1b8038b3fdd3bc77.jpeg"', 'Returned upload_fileid contains expected hash, 3 times'); - my $image_file = path($UPLOAD_DIR, '1cdd4329ceee2234bd4e89cb33b42061a0724687.jpeg'); + my $image_file = path($UPLOAD_DIR, '7f09ef2c3933731d47121fee1b8038b3fdd3bc77.jpeg'); ok $image_file->exists, 'File uploaded to temp'; }; }; diff --git a/t/app/controller/sample.jpg b/t/app/controller/sample.jpg index 23198cb83..4930821c4 100644 Binary files a/t/app/controller/sample.jpg and b/t/app/controller/sample.jpg differ diff --git a/t/app/model/photoset.t b/t/app/model/photoset.t index 577e39eb1..f0fc601e2 100644 --- a/t/app/model/photoset.t +++ b/t/app/model/photoset.t @@ -58,7 +58,7 @@ subtest 'Photoset with photo inline in DB' => sub { my $report = make_report( $image_path->slurp ); my $photoset = $report->get_photoset(); is $photoset->num_images, 1, 'Found just 1 image'; - is $photoset->data, '1cdd4329ceee2234bd4e89cb33b42061a0724687.jpeg'; + is $photoset->data, '7f09ef2c3933731d47121fee1b8038b3fdd3bc77.jpeg'; }; $image_path->copy( path( $UPLOAD_DIR, '0123456789012345678901234567890123456789.jpeg' ) ); diff --git a/t/open311/getservicerequestupdates.t b/t/open311/getservicerequestupdates.t index 134d5422e..4afac7182 100644 --- a/t/open311/getservicerequestupdates.t +++ b/t/open311/getservicerequestupdates.t @@ -388,7 +388,7 @@ subtest 'Update with media_url includes image in update' => sub { is $problem->comments->count, 1, 'comment count'; my $c = $problem->comments->first; is $c->external_id, 638344; - is $c->photo, '1cdd4329ceee2234bd4e89cb33b42061a0724687.jpeg', 'photo exists'; + is $c->photo, '7f09ef2c3933731d47121fee1b8038b3fdd3bc77.jpeg', 'photo exists'; }; foreach my $test ( -- cgit v1.2.3 From c9dc13d3c966abc11203bfb18404d8a40e795b3b Mon Sep 17 00:00:00 2001 From: Matthew Somerville Date: Wed, 6 Jul 2016 12:16:33 +0100 Subject: Fix two XSS vulnerabilities. The title in the OpenGraph header was not being properly escaped, and the hide pins/all pins links were using single quotes which were able to be broken out of. Also remove the single quotes around rss_feed_uri, though this is not a vulnerability as its contents were sanitised (postcode or co-ords). --- templates/web/base/alert/_list.html | 2 +- templates/web/base/around/display_location.html | 8 ++++---- templates/web/base/header_opengraph.html | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/templates/web/base/alert/_list.html b/templates/web/base/alert/_list.html index 65bba2fed..f94ce84f8 100644 --- a/templates/web/base/alert/_list.html +++ b/templates/web/base/alert/_list.html @@ -20,7 +20,7 @@

        - [% loc( + [% loc(
        [% loc('(a default distance which covers roughly 200,000 people)') %]

        diff --git a/templates/web/base/around/display_location.html b/templates/web/base/around/display_location.html index 7c54f4b76..b2e578d3f 100755 --- a/templates/web/base/around/display_location.html +++ b/templates/web/base/around/display_location.html @@ -55,16 +55,16 @@ diff --git a/templates/web/base/header_opengraph.html b/templates/web/base/header_opengraph.html index f728d083f..6b2c8ff46 100644 --- a/templates/web/base/header_opengraph.html +++ b/templates/web/base/header_opengraph.html @@ -1,5 +1,5 @@ - + [% IF c.req.uri.path == '/' %][% END %] -- cgit v1.2.3 From 370067141211acde05766fcaa3bfad0f8b232750 Mon Sep 17 00:00:00 2001 From: Matthew Somerville Date: Wed, 6 Jul 2016 13:08:21 +0100 Subject: Version 1.8.4. --- README.md | 16 ++++++++++++++++ bin/site-specific-install.sh | 2 +- 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 036ea11de..ef1394d5d 100644 --- a/README.md +++ b/README.md @@ -45,6 +45,22 @@ web-based cross-browser testing tools for this project. ## Releases +* v1.8.4 (6th July 2016) + - Security: + - Fix XSS vulnerability in OpenGraph header and hide/all pins links. + - Front end improvements: + - Wrap emails better for differing screen sizes. #1393 + - Fix annoying jump when "Get updates" drawer opened. #1425 + - Improve auth flow taken when return key used. #1433 + - Add and improve more CSRF tokens. #1433 + - Remove default box-shadow. #1419 + - Fix missing margin before reporting form email input. #1418 + - Bugfixes: + - Redirect correctly if filter used without JavaScript. #1422 + - Remove race condition when starting new report. #1434 + - Fix a couple of display bugs in IE7. #1356 + - Correctly orient preview images. #1378 + * v1.8.3 (3rd June 2016) - Admin improvements - Add search boxes to admin index page, and move stats. #1295 diff --git a/bin/site-specific-install.sh b/bin/site-specific-install.sh index 71bfc11ff..039434d03 100644 --- a/bin/site-specific-install.sh +++ b/bin/site-specific-install.sh @@ -1,7 +1,7 @@ #!/bin/sh # Set this to the version we want to check out -VERSION=${VERSION_OVERRIDE:-v1.8.3} +VERSION=${VERSION_OVERRIDE:-v1.8.4} PARENT_SCRIPT_URL=https://github.com/mysociety/commonlib/blob/master/bin/install-site.sh -- cgit v1.2.3