diff options
Diffstat (limited to 'perllib/FixMyStreet/App')
-rw-r--r-- | perllib/FixMyStreet/App/Controller/Admin.pm | 12 | ||||
-rw-r--r-- | perllib/FixMyStreet/App/Controller/Around.pm | 4 | ||||
-rw-r--r-- | perllib/FixMyStreet/App/Controller/Auth.pm | 109 | ||||
-rw-r--r-- | perllib/FixMyStreet/App/Controller/Contact.pm | 3 | ||||
-rw-r--r-- | perllib/FixMyStreet/App/Controller/Location.pm | 16 | ||||
-rw-r--r-- | perllib/FixMyStreet/App/Controller/Open311.pm | 2 | ||||
-rw-r--r-- | perllib/FixMyStreet/App/Controller/Photo.pm | 16 | ||||
-rwxr-xr-x | perllib/FixMyStreet/App/Controller/Questionnaire.pm | 13 | ||||
-rw-r--r-- | perllib/FixMyStreet/App/Controller/Report.pm | 2 | ||||
-rw-r--r-- | perllib/FixMyStreet/App/Controller/Report/New.pm | 86 | ||||
-rw-r--r-- | perllib/FixMyStreet/App/Controller/Report/Update.pm | 2 | ||||
-rw-r--r-- | perllib/FixMyStreet/App/Controller/Reports.pm | 30 | ||||
-rwxr-xr-x | perllib/FixMyStreet/App/Controller/Rss.pm | 10 | ||||
-rw-r--r-- | perllib/FixMyStreet/App/Controller/Tokens.pm | 2 | ||||
-rw-r--r-- | perllib/FixMyStreet/App/Model/PhotoSet.pm | 92 |
15 files changed, 215 insertions, 184 deletions
diff --git a/perllib/FixMyStreet/App/Controller/Admin.pm b/perllib/FixMyStreet/App/Controller/Admin.pm index 2bf215c56..f54a862ab 100644 --- a/perllib/FixMyStreet/App/Controller/Admin.pm +++ b/perllib/FixMyStreet/App/Controller/Admin.pm @@ -345,8 +345,6 @@ sub update_contacts : Private { $errors{email} = _('Please enter a valid email') unless is_valid_email($email) || $email eq 'REFUSED'; $errors{note} = _('Please enter a message') unless $c->get_param('note'); - $category = 'Empty property' if $c->cobrand->moniker eq 'emptyhomes'; - my $contact = $c->model('DB::Contact')->find_or_new( { body_id => $c->stash->{body_id}, @@ -743,16 +741,6 @@ sub report_edit : Path('report_edit') : Args(1) { my $new_state = $c->get_param('state'); my $old_state = $problem->state; - if ( $new_state eq 'confirmed' - && $problem->state eq 'unconfirmed' - && $c->cobrand->moniker eq 'emptyhomes' ) - { - $c->stash->{status_message} = - '<p><em>' - . _('I am afraid you cannot confirm unconfirmed reports.') - . '</em></p>'; - $done = 1; - } my $flagged = $c->get_param('flagged') ? 1 : 0; my $non_public = $c->get_param('non_public') ? 1 : 0; diff --git a/perllib/FixMyStreet/App/Controller/Around.pm b/perllib/FixMyStreet/App/Controller/Around.pm index 1e6d9ec9e..b0340204a 100644 --- a/perllib/FixMyStreet/App/Controller/Around.pm +++ b/perllib/FixMyStreet/App/Controller/Around.pm @@ -47,7 +47,7 @@ sub index : Path : Args(0) { } # Check to see if the spot is covered by a area - if not show an error. - return unless $c->cobrand->moniker eq 'fixmybarangay' || $c->forward('check_location_is_acceptable'); + return unless $c->forward('check_location_is_acceptable'); # If we have a partial - redirect to /report/new so that it can be # completed. @@ -182,7 +182,7 @@ sub display_location : Private { # create a list of all the pins my @pins; - unless ($c->get_param('no_pins') || $c->cobrand->moniker eq 'emptyhomes') { + unless ($c->get_param('no_pins')) { @pins = map { # Here we might have a DB::Problem or a DB::Nearby, we always want the problem. my $p = (ref $_ eq 'FixMyStreet::App::Model::DB::Nearby') ? $_->problem : $_; diff --git a/perllib/FixMyStreet/App/Controller/Auth.pm b/perllib/FixMyStreet/App/Controller/Auth.pm index 9e8fb29aa..c5a6cf9bf 100644 --- a/perllib/FixMyStreet/App/Controller/Auth.pm +++ b/perllib/FixMyStreet/App/Controller/Auth.pm @@ -9,6 +9,7 @@ use Net::Domain::TLD; use mySociety::AuthToken; use JSON::MaybeXS; use Net::Facebook::Oauth2; +use Net::Twitter::Lite::WithAPIv1_1; =head1 NAME @@ -38,6 +39,7 @@ sub general : Path : Args(0) { # 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'); @@ -133,6 +135,8 @@ sub email_sign_in : Private { }; $token_data->{facebook_id} = $c->session->{oauth}{facebook_id} if $c->get_param('oauth_need_email') && $c->session->{oauth}{facebook_id}; + $token_data->{twitter_id} = $c->session->{oauth}{twitter_id} + if $c->get_param('oauth_need_email') && $c->session->{oauth}{twitter_id}; my $token_obj = $c->model('DB::Token')->create({ scope => 'email_sign_in', @@ -180,6 +184,7 @@ sub token : Path('/M') : Args(1) { $user->name( $data->{name} ) if $data->{name}; $user->password( $data->{password}, 1 ) if $data->{password}; $user->facebook_id( $data->{facebook_id} ) if $data->{facebook_id}; + $user->twitter_id( $data->{twitter_id} ) if $data->{twitter_id}; $user->update; $c->authenticate( { email => $user->email }, 'no_password' ); @@ -203,7 +208,7 @@ sub fb : Private { } sub facebook_sign_in : Private { - my( $self, $c ) = @_; + my ( $self, $c ) = @_; my $fb = $c->forward('/auth/fb'); my $url = $fb->get_authorization_url(scope => ['email']); @@ -223,17 +228,9 @@ Handles the Facebook callback request and completes the authentication sequence. =cut sub facebook_callback: Path('/auth/Facebook') : Args(0) { - my( $self, $c ) = @_; + my ( $self, $c ) = @_; - if ( $c->get_param('error_code') ) { - $c->stash->{oauth_failure} = 1; - if ($c->session->{oauth}{detach_to}) { - $c->detach($c->session->{oauth}{detach_to}, $c->session->{oauth}{detach_args}); - } else { - $c->stash->{template} = 'auth/general.html'; - $c->detach; - } - } + $c->detach('oauth_failure') if $c->get_param('error_code'); my $fb = $c->forward('/auth/fb'); my $access_token; @@ -250,12 +247,92 @@ sub facebook_callback: Path('/auth/Facebook') : Args(0) { $c->session->{oauth}{token} = $access_token; my $info = $fb->get('https://graph.facebook.com/me?fields=name,email')->as_hash(); - my $name = $info->{name}; my $email = lc ($info->{email} || ""); - my $uid = $info->{id}; + $c->forward('oauth_success', [ 'facebook', $info->{id}, $info->{name}, $email ]); +} + +=head2 twitter_sign_in + +Starts the Twitter authentication sequence. + +=cut + +sub tw : Private { + my ($self, $c) = @_; + Net::Twitter::Lite::WithAPIv1_1->new( + ssl => 1, + consumer_key => $c->config->{TWITTER_KEY}, + consumer_secret => $c->config->{TWITTER_SECRET}, + ); +} + +sub twitter_sign_in : Private { + my ( $self, $c ) = @_; + + my $twitter = $c->forward('/auth/tw'); + my $url = $twitter->get_authentication_url(callback => $c->uri_for('/auth/Twitter')); + + my %oauth; + $oauth{return_url} = $c->get_param('r'); + $oauth{detach_to} = $c->stash->{detach_to}; + $oauth{detach_args} = $c->stash->{detach_args}; + $oauth{token} = $twitter->request_token; + $oauth{token_secret} = $twitter->request_token_secret; + $c->session->{oauth} = \%oauth; + $c->res->redirect($url); +} + +=head2 twitter_callback + +Handles the Twitter callback request and completes the authentication sequence. + +=cut + +sub twitter_callback: Path('/auth/Twitter') : Args(0) { + my ( $self, $c ) = @_; + + my $request_token = $c->req->param('oauth_token'); + my $verifier = $c->req->param('oauth_verifier'); + my $oauth = $c->session->{oauth}; + + $c->detach('oauth_failure') if $c->get_param('denied') || $request_token ne $oauth->{token}; + + my $twitter = $c->forward('/auth/tw'); + $twitter->request_token($oauth->{token}); + $twitter->request_token_secret($oauth->{token_secret}); + + eval { + # request_access_token no longer returns UID or name + $twitter->request_access_token(verifier => $verifier); + }; + if ($@) { + ($c->stash->{message} = $@) =~ s/at [^ ]*Auth.pm.*//; + $c->stash->{template} = 'errors/generic.html'; + $c->detach; + } + + my $info = $twitter->verify_credentials(); + $c->forward('oauth_success', [ 'twitter', $info->{id}, $info->{name} ]); +} + +sub oauth_failure : Private { + my ( $self, $c ) = @_; + + $c->stash->{oauth_failure} = 1; + if ($c->session->{oauth}{detach_to}) { + $c->detach($c->session->{oauth}{detach_to}, $c->session->{oauth}{detach_args}); + } else { + $c->stash->{template} = 'auth/general.html'; + $c->detach; + } +} + +sub oauth_success : Private { + my ($self, $c, $type, $uid, $name, $email) = @_; my $user; if ($email) { + # Only Facebook gets here # We've got an ID and an email address # Remove any existing mention of this ID my $existing = $c->model('DB::User')->find( { facebook_id => $uid } ); @@ -267,14 +344,14 @@ sub facebook_callback: Path('/auth/Facebook') : Args(0) { $user->in_storage() ? $user->update : $user->insert; } else { # We've got an ID, but no email - $user = $c->model('DB::User')->find( { facebook_id => $uid } ); + $user = $c->model('DB::User')->find( { $type . '_id' => $uid } ); if ($user) { - # Matching Facebook ID in our database + # Matching ID in our database $user->name($name); $user->update; } else { # No matching ID, store ID for use later - $c->session->{oauth}{facebook_id} = $uid; + $c->session->{oauth}{$type . '_id'} = $uid; $c->stash->{oauth_need_email} = 1; } } diff --git a/perllib/FixMyStreet/App/Controller/Contact.pm b/perllib/FixMyStreet/App/Controller/Contact.pm index 115f4e3d2..e20011471 100644 --- a/perllib/FixMyStreet/App/Controller/Contact.pm +++ b/perllib/FixMyStreet/App/Controller/Contact.pm @@ -242,8 +242,7 @@ sub send_email : Private { my $from = [ $c->stash->{em}, $c->stash->{form_name} ]; my $params = { - to => [ [ $recipient, _($recipient_name) ] ], - subject => 'FMS message: ' . $c->stash->{subject}, + to => [ [ $recipient, _($recipient_name) ] ], }; if (FixMyStreet::Email::test_dmarc($c->stash->{em})) { $params->{'Reply-To'} = [ $from ]; diff --git a/perllib/FixMyStreet/App/Controller/Location.pm b/perllib/FixMyStreet/App/Controller/Location.pm index 6def423ce..c457c8fce 100644 --- a/perllib/FixMyStreet/App/Controller/Location.pm +++ b/perllib/FixMyStreet/App/Controller/Location.pm @@ -134,22 +134,6 @@ sub check_location : Private { return 1; } -=head2 country_message - -Displays the country_message template, used for displaying a message to -people using the site from outside the host country. - -=cut - -sub country_message : Path('/country_message') : Args(0) { - my ( $self, $c ) = @_; - - # we do not want to cache this as we always want to check if displaying this - # is the right thing to do. - $c->res->header( 'Cache_Control' => 'max-age=0' ); - $c->stash->{template} = 'front/international_banner.html'; -} - # Utility function for if someone (rarely) enters a grid reference sub gridref_to_latlon { my ( $a, $b, $num ) = @_; diff --git a/perllib/FixMyStreet/App/Controller/Open311.pm b/perllib/FixMyStreet/App/Controller/Open311.pm index f35dc64a5..4f1727b1a 100644 --- a/perllib/FixMyStreet/App/Controller/Open311.pm +++ b/perllib/FixMyStreet/App/Controller/Open311.pm @@ -284,7 +284,7 @@ sub output_requests : Private { my $display_photos = $c->cobrand->allow_photo_display($problem); if ($display_photos && $problem->photo) { my $url = $c->cobrand->base_url(); - my $imgurl = $url . "/photo/$id.full.jpeg"; + my $imgurl = $url . $problem->photos->[0]->{url_full}; $request->{'media_url'} = [ $imgurl ]; } push(@problemlist, $request); diff --git a/perllib/FixMyStreet/App/Controller/Photo.pm b/perllib/FixMyStreet/App/Controller/Photo.pm index bfb1c5535..d24d3ff71 100644 --- a/perllib/FixMyStreet/App/Controller/Photo.pm +++ b/perllib/FixMyStreet/App/Controller/Photo.pm @@ -29,12 +29,12 @@ Display a photo =cut -sub during :LocalRegex('^([0-9a-f]{40})\.(temp|fulltemp)\.jpeg$') { +sub during :LocalRegex('^(temp|fulltemp)\.([0-9a-f]{40}\.(?:jpeg|png|gif|tiff))$') { my ( $self, $c ) = @_; - my ( $hash, $size ) = @{ $c->req->captures }; + my ( $size, $filename ) = @{ $c->req->captures }; my $photoset = FixMyStreet::App::Model::PhotoSet->new({ - data_items => [ $hash ] + data_items => [ $filename ] }); $size = $size eq 'temp' ? 'default' : 'full'; @@ -43,7 +43,7 @@ sub during :LocalRegex('^([0-9a-f]{40})\.(temp|fulltemp)\.jpeg$') { $c->forward( 'output', [ $photo ] ); } -sub index :LocalRegex('^(c/)?(\d+)(?:\.(\d+))?(?:\.(full|tn|fp))?\.jpeg$') { +sub index :LocalRegex('^(c/)?(\d+)(?:\.(\d+))?(?:\.(full|tn|fp))?\.(?:jpeg|png|gif|tiff)$') { my ( $self, $c ) = @_; my ( $is_update, $id, $photo_number, $size ) = @{ $c->req->captures }; @@ -79,10 +79,10 @@ sub output : Private { # Save to file File::Path::make_path( FixMyStreet->path_to( 'web', 'photo', 'c' )->stringify ); - File::Slurp::write_file( FixMyStreet->path_to( 'web', $c->req->path )->stringify, \$photo ); + File::Slurp::write_file( FixMyStreet->path_to( 'web', $c->req->path )->stringify, \$photo->{data} ); - $c->res->content_type( 'image/jpeg' ); - $c->res->body( $photo ); + $c->res->content_type( $photo->{content_type} ); + $c->res->body( $photo->{data} ); } sub no_photo : Private { @@ -140,7 +140,7 @@ sub process_photo_upload_or_cache : Private { /^photo/ ? # photo, photo1, photo2 etc. ($c->req->upload($_)) : () } sort $c->req->upload), - split /,/, ($c->get_param('upload_fileid') || '') + grep { $_ } split /,/, ($c->get_param('upload_fileid') || '') ); my $photoset = FixMyStreet::App::Model::PhotoSet->new({ diff --git a/perllib/FixMyStreet/App/Controller/Questionnaire.pm b/perllib/FixMyStreet/App/Controller/Questionnaire.pm index 8fe2514c0..017a552db 100755 --- a/perllib/FixMyStreet/App/Controller/Questionnaire.pm +++ b/perllib/FixMyStreet/App/Controller/Questionnaire.pm @@ -47,14 +47,6 @@ sub check_questionnaire : Private { $c->stash->{problem} = $problem; $c->stash->{answered_ever_reported} = $problem->user->answered_ever_reported; - - # EHA needs to know how many to alter display, and whether to send another or not - if ($c->cobrand->moniker eq 'emptyhomes') { - $c->stash->{num_questionnaire} = $c->model('DB::Questionnaire')->count( - { problem_id => $problem->id } - ); - } - } =head2 submit @@ -236,11 +228,6 @@ sub process_questionnaire : Private { $c->stash->{update} = Utils::cleanup_text($c->stash->{update}, { allow_multiline => 1 }); - # EHA questionnaires done for you - if ($c->cobrand->moniker eq 'emptyhomes') { - $c->stash->{another} = $c->stash->{num_questionnaire}==1 ? 'Yes' : 'No'; - } - my @errors; push @errors, _('Please state whether or not the problem has been fixed') unless $c->stash->{been_fixed}; diff --git a/perllib/FixMyStreet/App/Controller/Report.pm b/perllib/FixMyStreet/App/Controller/Report.pm index 5cc44bb8f..475a29fb5 100644 --- a/perllib/FixMyStreet/App/Controller/Report.pm +++ b/perllib/FixMyStreet/App/Controller/Report.pm @@ -230,7 +230,7 @@ to moderation, however we'd need to inform all the other users too about this change, at which point we can delete: - this method - - the call to it in templates/web/fixmystreet/report/display.html + - the call to it in templates/web/base/report/display_tools.html - the users_can_hide cobrand method, in favour of user->has_permission_to =cut diff --git a/perllib/FixMyStreet/App/Controller/Report/New.pm b/perllib/FixMyStreet/App/Controller/Report/New.pm index 66dc20a3a..5df182506 100644 --- a/perllib/FixMyStreet/App/Controller/Report/New.pm +++ b/perllib/FixMyStreet/App/Controller/Report/New.pm @@ -221,7 +221,7 @@ sub category_extras_ajax : Path('category_extras') : Args(0) { $c->forward('setup_categories_and_bodies'); $c->forward('check_for_category'); - my $category = $c->stash->{category}; + my $category = $c->stash->{category} || ""; my $category_extra = ''; my $generate; if ( $c->stash->{category_extras}->{$category} && @{ $c->stash->{category_extras}->{$category} } >= 1 ) { @@ -616,58 +616,47 @@ sub setup_categories_and_bodies : Private { $c->stash->{unresponsive} = {}; if (keys %bodies == 1 && $first_body->send_method && $first_body->send_method eq 'Refused') { - $c->stash->{unresponsive}{ALL} = $first_body->id; - } - - # FIXME - implement in cobrand - if ( $c->cobrand->moniker eq 'emptyhomes' ) { - - # add all bodies found to the list - foreach (@contacts) { - $bodies_to_list{ $_->body_id } = 1; + # If there's only one body, and it's set to refused, we can show the + # message immediately, before they select a category. + if ($c->action->name eq 'category_extras_ajax' && $c->req->method eq 'POST') { + # The mobile app doesn't currently use this, in which case make + # sure the message is output, either below with a category, or when + # a blank category call is made. + $c->stash->{unresponsive}{""} = $first_body->id; + } else { + $c->stash->{unresponsive}{ALL} = $first_body->id; } + } - # set our own categories - @category_options = ( - _('-- Pick a property type --'), - _('Empty house or bungalow'), - _('Empty flat or maisonette'), - _('Whole block of empty flats'), - _('Empty office or other commercial'), - _('Empty pub or bar'), - _('Empty public building - school, hospital, etc.') - ); - - } else { - - # keysort does not appear to obey locale so use strcoll (see i18n.t) - @contacts = sort { strcoll( $a->category, $b->category ) } @contacts; + # keysort does not appear to obey locale so use strcoll (see i18n.t) + @contacts = sort { strcoll( $a->category, $b->category ) } @contacts; - my %seen; - foreach my $contact (@contacts) { + my %seen; + foreach my $contact (@contacts) { - $bodies_to_list{ $contact->body_id } = 1; + $bodies_to_list{ $contact->body_id } = 1; - unless ( $seen{$contact->category} ) { - push @category_options, $contact->category; + unless ( $seen{$contact->category} ) { + push @category_options, $contact->category; - my $metas = $contact->get_extra_fields; - $category_extras{ $contact->category } = $metas - if scalar @$metas; + my $metas = $contact->get_extra_fields; + $category_extras{ $contact->category } = $metas + if scalar @$metas; - $c->stash->{unresponsive}{$contact->category} = $contact->body_id - if $contact->email =~ /^REFUSED$/i; + my $body_send_method = $bodies{$contact->body_id}->send_method || ''; + $c->stash->{unresponsive}{$contact->category} = $contact->body_id + if !$c->stash->{unresponsive}{ALL} && + ($contact->email =~ /^REFUSED$/i || $body_send_method eq 'Refused'); - $non_public_categories{ $contact->category } = 1 if $contact->non_public; - } - $seen{$contact->category} = 1; + $non_public_categories{ $contact->category } = 1 if $contact->non_public; } + $seen{$contact->category} = 1; + } - if (@category_options) { - # If there's an Other category present, put it at the bottom - @category_options = ( _('-- Pick a category --'), grep { $_ ne _('Other') } @category_options ); - push @category_options, _('Other') if $seen{_('Other')}; - } + if (@category_options) { + # If there's an Other category present, put it at the bottom + @category_options = ( _('-- Pick a category --'), grep { $_ ne _('Other') } @category_options ); + push @category_options, _('Other') if $seen{_('Other')}; } $c->cobrand->munge_category_list(\@category_options, \@contacts, \%category_extras) @@ -849,12 +838,7 @@ sub process_report : Private { my $first_area = ( values %$areas )[0]; my $first_body = ( values %$bodies )[0]; - if ( $c->cobrand->moniker eq 'emptyhomes' ) { - - $bodies = join( ',', @{ $c->stash->{bodies_to_list} } ) || -1; - $report->bodies_str( $bodies ); - - } elsif ( $report->category ) { + if ( $report->category ) { # FIXME All contacts were fetched in setup_categories_and_bodies, # so can this DB call also be avoided? @@ -1034,6 +1018,8 @@ sub tokenize_user : Private { }; $c->stash->{token_data}{facebook_id} = $c->session->{oauth}{facebook_id} if $c->get_param('oauth_need_email') && $c->session->{oauth}{facebook_id}; + $c->stash->{token_data}{twitter_id} = $c->session->{oauth}{twitter_id} + if $c->get_param('oauth_need_email') && $c->session->{oauth}{twitter_id}; } =head2 save_user_and_report @@ -1061,7 +1047,7 @@ sub save_user_and_report : Private { $report->bodies_str( undef ) if $report->bodies_str eq '-1'; # if there is a Message Manager message ID, pass it back to the client view - if ($c->cobrand->moniker eq 'fixmybarangay' && $c->get_param('external_source_id') =~ /^\d+$/) { + if (($c->get_param('external_source_id') || "") =~ /^\d+$/) { $c->stash->{external_source_id} = $c->get_param('external_source_id'); $report->external_source_id( $c->get_param('external_source_id') ); $report->external_source( $c->config->{MESSAGE_MANAGER_URL} ) ; diff --git a/perllib/FixMyStreet/App/Controller/Report/Update.pm b/perllib/FixMyStreet/App/Controller/Report/Update.pm index 8d6bc2019..af4ccff03 100644 --- a/perllib/FixMyStreet/App/Controller/Report/Update.pm +++ b/perllib/FixMyStreet/App/Controller/Report/Update.pm @@ -382,6 +382,8 @@ sub tokenize_user : Private { }; $c->stash->{token_data}{facebook_id} = $c->session->{oauth}{facebook_id} if $c->get_param('oauth_need_email') && $c->session->{oauth}{facebook_id}; + $c->stash->{token_data}{twitter_id} = $c->session->{oauth}{twitter_id} + if $c->get_param('oauth_need_email') && $c->session->{oauth}{twitter_id}; } =head2 save_update diff --git a/perllib/FixMyStreet/App/Controller/Reports.pm b/perllib/FixMyStreet/App/Controller/Reports.pm index 027b0d5a4..5bcbb3dc4 100644 --- a/perllib/FixMyStreet/App/Controller/Reports.pm +++ b/perllib/FixMyStreet/App/Controller/Reports.pm @@ -141,15 +141,9 @@ sub ward : Path : Args(2) { area => $c->stash->{ward} ? $c->stash->{ward}->{id} : [ keys %{$c->stash->{body}->areas} ], any_zoom => 1, ); - if ( $c->cobrand->moniker eq 'emptyhomes' ) { - FixMyStreet::Map::display_map( - $c, %map_params, latitude => 0, longitude => 0, - ); - } else { - FixMyStreet::Map::display_map( - $c, %map_params, pins => $pins, - ); - } + FixMyStreet::Map::display_map( + $c, %map_params, pins => $pins, + ); $c->cobrand->tweak_all_reports_map( $c ); @@ -188,15 +182,6 @@ sub rss_area_ward : Path('/rss/area') : Args(2) { # We're checking an area here, but this function is currently doing that. return if $c->cobrand->reports_body_check( $c, $area ); - # If we're passed an ID number (don't think this is used anywhere, it - # certainly shouldn't be), just look that up on mapit and redirect - if ($area =~ /^\d+$/) { - my $council = mySociety::MaPit::call('area', $area); - $c->detach( 'redirect_index') if $council->{error}; - $c->stash->{body} = $council; - $c->detach( 'redirect_body' ); - } - # We must now have a string to check on mapit my $areas = mySociety::MaPit::call( 'areas', $area, type => $c->cobrand->area_types, @@ -296,15 +281,6 @@ sub body_check : Private { # Oslo/ kommunes sharing a name in Norway return if $c->cobrand->reports_body_check( $c, $q_body ); - # If we're passed an ID number (don't think this is used anywhere, it - # certainly shouldn't be), just look that up on MaPit and redirect - if ($q_body =~ /^\d+$/) { - my $area = mySociety::MaPit::call('area', $q_body); - $c->detach( 'redirect_index') if $area->{error}; - $c->stash->{body} = $area; - $c->detach( 'redirect_body' ); - } - # We must now have a string to check my @bodies = $c->model('DB::Body')->search( { name => { -like => "$q_body%" } } )->all; diff --git a/perllib/FixMyStreet/App/Controller/Rss.pm b/perllib/FixMyStreet/App/Controller/Rss.pm index 6047f063b..8d4f8313c 100755 --- a/perllib/FixMyStreet/App/Controller/Rss.pm +++ b/perllib/FixMyStreet/App/Controller/Rss.pm @@ -6,6 +6,8 @@ use POSIX qw(strftime); use URI::Escape; use XML::RSS; +use FixMyStreet::App::Model::PhotoSet; + use mySociety::Gaze; use mySociety::Locale; use mySociety::MaPit; @@ -160,7 +162,6 @@ sub local_problems_ll : Private { sub output : Private { my ( $self, $c ) = @_; - $c->detach( '/page_error_404_not_found', [ 'Feed not found' ] ) if $c->cobrand->moniker eq 'emptyhomes'; $c->forward( 'lookup_type' ); $c->forward( 'query_main' ); $c->forward( 'generate' ); @@ -277,8 +278,13 @@ sub add_row : Private { $item{category} = ent($row->{category}) if $row->{category}; if ($c->cobrand->allow_photo_display($row) && $row->{photo}) { + # Bit yucky as we don't have full objects here + my $photoset = FixMyStreet::App::Model::PhotoSet->new({ db_data => $row->{photo} }); + my $first_fn = $photoset->get_id(0); + my ($hash, $format) = split /\./, $first_fn; + my $cachebust = substr($hash, 0, 8); my $key = $alert_type->item_table eq 'comment' ? 'c/' : ''; - $item{description} .= ent("\n<br><img src=\"". $base_url . "/photo/$key$row->{id}.jpeg\">"); + $item{description} .= ent("\n<br><img src=\"". $base_url . "/photo/$key$row->{id}.0.$format?$cachebust\">"); } if ( $row->{used_map} ) { diff --git a/perllib/FixMyStreet/App/Controller/Tokens.pm b/perllib/FixMyStreet/App/Controller/Tokens.pm index eb35fd152..38f344250 100644 --- a/perllib/FixMyStreet/App/Controller/Tokens.pm +++ b/perllib/FixMyStreet/App/Controller/Tokens.pm @@ -106,6 +106,7 @@ sub confirm_problem : Path('/P') { $problem->user->password( $data->{password}, 1 ) if $data->{password}; $problem->user->title( $data->{title} ) if $data->{title}; $problem->user->facebook_id( $data->{facebook_id} ) if $data->{facebook_id}; + $problem->user->twitter_id( $data->{twitter_id} ) if $data->{twitter_id}; $problem->user->update; } $c->authenticate( { email => $problem->user->email }, 'no_password' ); @@ -232,6 +233,7 @@ sub confirm_update : Path('/C') { $comment->user->name( $data->{name} ) if $data->{name}; $comment->user->password( $data->{password}, 1 ) if $data->{password}; $comment->user->facebook_id( $data->{facebook_id} ) if $data->{facebook_id}; + $comment->user->twitter_id( $data->{twitter_id} ) if $data->{twitter_id}; $comment->user->update; } diff --git a/perllib/FixMyStreet/App/Model/PhotoSet.pm b/perllib/FixMyStreet/App/Model/PhotoSet.pm index 54457bae9..b44bf4b38 100644 --- a/perllib/FixMyStreet/App/Model/PhotoSet.pm +++ b/perllib/FixMyStreet/App/Model/PhotoSet.pm @@ -8,6 +8,8 @@ use if !$ENV{TRAVIS}, 'Image::Magick'; use Scalar::Util 'openhandle', 'blessed'; use Digest::SHA qw(sha1_hex); use Image::Size; +use IPC::Cmd qw(can_run); +use IPC::Open3; use MIME::Base64; has c => ( @@ -49,7 +51,7 @@ has data_items => ( # either a) split from db_data or b) provided by photo uploa my $self = shift; my $data = $self->db_data or return []; - return [$data] if (_jpeg_magic($data)); + return [$data] if (detect_type($data)); return [ split ',' => $data ]; }, @@ -70,10 +72,12 @@ has upload_dir => ( }, ); -sub _jpeg_magic { - $_[0] =~ /^\x{ff}\x{d8}/; # JPEG - # NB: should we also handle \x{89}\x{50} (PNG, 15 results in live DB) ? - # and \x{49}\x{49} (Tiff, 3 results in live DB) ? +sub detect_type { + return 'jpeg' if $_[0] =~ /^\x{ff}\x{d8}/; + return 'png' if $_[0] =~ /^\x{89}\x{50}/; + return 'tiff' if $_[0] =~ /^II/; + return 'gif' if $_[0] =~ /^GIF/; + return ''; } =head2 C<ids>, C<num_images>, C<get_id>, C<all_ids> @@ -106,15 +110,17 @@ has ids => ( # Arrayref of $fileid tuples (always, so post upload/raw data proc my $part = $_; if (blessed $part and $part->isa('Catalyst::Request::Upload')) { - # check that the photo is a jpeg my $upload = $part; my $ct = $upload->type; $ct =~ s/x-citrix-//; # Thanks, Citrix + my ($type) = $ct =~ m{image/(jpeg|pjpeg|gif|tiff|png)}; + $type = 'jpeg' if $type && $type eq 'pjpeg'; # Had a report of a JPEG from an Android 2.1 coming through as a byte stream - unless ( $ct eq 'image/jpeg' || $ct eq 'image/pjpeg' || $ct eq 'application/octet-stream' ) { + $type = 'jpeg' if !$type && $ct eq 'application/octet-stream'; + unless ( $type ) { my $c = $self->c; $c->log->info('Bad photo tried to upload, type=' . $ct); - $c->stash->{photo_error} = _('Please upload a JPEG image only'); + $c->stash->{photo_error} = _('Please upload an image only'); return (); } @@ -139,12 +145,18 @@ has ids => ( # Arrayref of $fileid tuples (always, so post upload/raw data proc # get the photo into a variable my $photo_blob = eval { my $filename = $upload->tempname; - my $out = `jhead -se -autorot $filename 2>&1`; + my $out; + if ($type eq 'jpeg' && can_run('jhead')) { + my $pid = open3(undef, my $stdout, undef, 'jhead', '-se', '-autorot', $filename); + $out = join('', <$stdout>); + waitpid($pid, 0); + close $stdout; + } unless (defined $out) { my ($w, $h, $err) = Image::Size::imgsize($filename); - die _("Please upload a JPEG image only") . "\n" if !defined $w || $err ne 'JPG'; + die _("Please upload an image only") . "\n" if !defined $w || $err !~ /JPG|GIF|PNG|TIF/; } - die _("Please upload a JPEG image only") . "\n" if $out && $out =~ /Not JPEG:/; + die _("Please upload an image only") . "\n" if $out && $out =~ /Not JPEG:/; my $photo = $upload->slurp; }; if ( my $error = $@ ) { @@ -157,29 +169,30 @@ has ids => ( # Arrayref of $fileid tuples (always, so post upload/raw data proc # we have an image we can use - save it to the upload dir for storage my $fileid = $self->get_fileid($photo_blob); - my $file = $self->get_file($fileid); + my $file = $self->get_file($fileid, $type); $upload->copy_to( $file ); - return $fileid; + return $file->basename; } - if (_jpeg_magic($part)) { + if (my $type = detect_type($part)) { my $photo_blob = $part; my $fileid = $self->get_fileid($photo_blob); - my $file = $self->get_file($fileid); + my $file = $self->get_file($fileid, $type); $file->spew_raw($photo_blob); - return $fileid; + return $file->basename; } - if (length($part) == 40) { - my $fileid = $part; - my $file = $self->get_file($fileid); + my ($fileid, $type) = split /\./, $part; + $type ||= 'jpeg'; + if ($fileid && length($fileid) == 40) { + my $file = $self->get_file($fileid, $type); if ($file->exists) { - $fileid; + $file->basename; } else { - warn "File $fileid doesn't exist"; + warn "File $part doesn't exist"; (); } } else { - warn sprintf "Received bad photo hash of length %d", length($part); + # A bad hash, probably a bot spamming with bad data. (); } }); @@ -193,18 +206,23 @@ sub get_fileid { } sub get_file { - my ($self, $fileid) = @_; + my ($self, $fileid, $type) = @_; my $cache_dir = $self->upload_dir; - return path( $cache_dir, "$fileid.jpeg" ); + return path( $cache_dir, "$fileid.$type" ); } -sub get_raw_image_data { +sub get_raw_image { my ($self, $index) = @_; - my $fileid = $self->get_id($index); - my $file = $self->get_file($fileid); + my $filename = $self->get_id($index); + my ($fileid, $type) = split /\./, $filename; + my $file = $self->get_file($fileid, $type); if ($file->exists) { my $photo = $file->slurp_raw; - return $photo; + return { + data => $photo, + content_type => "image/$type", + extension => $type, + }; } } @@ -212,8 +230,9 @@ sub get_image_data { my ($self, %args) = @_; my $num = $args{num} || 0; - my $photo = $self->get_raw_image_data( $num ) + my $image = $self->get_raw_image( $num ) or return; + my $photo = $image->{data}; my $size = $args{size}; if ( $size eq 'tn' ) { @@ -226,7 +245,10 @@ sub get_image_data { $photo = _shrink( $photo, $args{default} || '250x250' ); } - return $photo; + return { + data => $photo, + content_type => $image->{content_type}, + }; } sub delete_cached { @@ -250,13 +272,15 @@ sub remove_images { --$dec; } + $self->delete_cached(); + + return undef if !@images; + my $new_set = (ref $self)->new({ data_items => \@images, object => $self->object, }); - $self->delete_cached(); - return $new_set->data; # e.g. new comma-separated fileid } @@ -266,8 +290,8 @@ sub rotate_image { my @images = $self->all_ids; return if $index > $#images; - my $image_data = $self->get_raw_image_data($index); - $images[$index] = _rotate_image( $image_data, $direction ); + my $image = $self->get_raw_image($index); + $images[$index] = _rotate_image( $image->{data}, $direction ); my $new_set = (ref $self)->new({ data_items => \@images, |