diff options
author | Edmund von der Burg <evdb@mysociety.org> | 2011-03-31 17:54:14 +0100 |
---|---|---|
committer | Edmund von der Burg <evdb@mysociety.org> | 2011-03-31 17:54:14 +0100 |
commit | 53fbccab8e7471fa9e06496a56f136b1edb43351 (patch) | |
tree | d55e62c6729093f4532876010b91cf04705cd535 | |
parent | aee7bf19d25be738df0ca94e12452de33dcf42f9 (diff) |
Ported import.cgi to catalyst
-rw-r--r-- | conf/httpd.conf | 2 | ||||
-rw-r--r-- | notes/catalyst-master-merge-todos.txt | 14 | ||||
-rw-r--r-- | perllib/FixMyStreet/App/Controller/Reports/New.pm | 207 | ||||
-rw-r--r-- | perllib/FixMyStreet/App/Controller/Tokens.pm | 17 | ||||
-rw-r--r-- | perllib/FixMyStreet/TestMech.pm | 18 | ||||
-rw-r--r-- | t/app/controller/reports_import.t | 158 | ||||
-rw-r--r-- | t/app/controller/reports_new.t | 6 | ||||
-rw-r--r-- | t/app/controller/sample.jpg | bin | 0 -> 22588 bytes | |||
-rw-r--r-- | templates/email/default/partial.txt (renamed from templates/emails/partial) | 6 | ||||
-rw-r--r-- | templates/web/default/reports/new/fill_in_details.html | 7 | ||||
-rw-r--r-- | templates/web/default/reports/new/report_import.html | 92 | ||||
-rw-r--r-- | templates/web/default/reports/new/report_new.html | 16 | ||||
-rwxr-xr-x | web/import.cgi | 181 |
13 files changed, 519 insertions, 205 deletions
diff --git a/conf/httpd.conf b/conf/httpd.conf index 066d2bd08..56b363b71 100644 --- a/conf/httpd.conf +++ b/conf/httpd.conf @@ -56,7 +56,6 @@ RewriteRule ^/[Aa]/([0-9A-Za-z]{16,18}).*$ /alert.cgi?token=$1 [Q RewriteRule ^/[Cc]/([0-9A-Za-z]{16,18}).*$ /confirm.cgi?type=update;token=$1 [QSA,L] RewriteRule ^/[Qq]/([0-9A-Za-z]{16,18}).*$ /questionnaire.cgi?token=$1 [QSA,L] RewriteRule ^/[Ff]/([0-9A-Za-z]{16,18}).*$ /flickr.cgi?token=$1 [L] -RewriteRule ^/[Ll]/([0-9A-Za-z]{16,18}).*$ /index.cgi?partial_token=$1 [L] RewriteRule ^/[Tt]/([0-9A-Za-z]{16,18}).*$ /tms-signup.cgi?token=$1 [L] # RSS feeds for updates on a problem @@ -112,7 +111,6 @@ RewriteRule /confirm(.*) /confirm.cgi$1 [L] RewriteRule /contact(.*) /contact.cgi$1 [L] RewriteRule /flickr(.*) /flickr.cgi$1 [L] RewriteRule /fun(.*) /fun.cgi$1 [L] -RewriteRule /import(.*) /import.cgi$1 [L] RewriteRule /$ /index.cgi [L] RewriteRule /index(.*) /index.cgi$1 [L] RewriteRule /json(.*) /json.cgi$1 [L] diff --git a/notes/catalyst-master-merge-todos.txt b/notes/catalyst-master-merge-todos.txt new file mode 100644 index 000000000..5f87cbc5a --- /dev/null +++ b/notes/catalyst-master-merge-todos.txt @@ -0,0 +1,14 @@ +fix reports/123 to report/123 + +test creation of partial reports + +scan through code for all fixmes + +make email sending respect STAGING + +convert templates for new micro sites (or switch old code to use new headers and footers) + +should we ditch flickr import? (does not seem to be getting huge usage and those using it would probably report using another method: http://www.flickr.com/search/?w=all&q=fixmystreet&m=tags) + +add js to maps + diff --git a/perllib/FixMyStreet/App/Controller/Reports/New.pm b/perllib/FixMyStreet/App/Controller/Reports/New.pm index 0a29614c6..3f0b949a6 100644 --- a/perllib/FixMyStreet/App/Controller/Reports/New.pm +++ b/perllib/FixMyStreet/App/Controller/Reports/New.pm @@ -11,6 +11,8 @@ use List::MoreUtils qw(uniq); use HTML::Entities; use mySociety::MaPit; use Path::Class; +use Utils; +use mySociety::EmailUtil; =head1 NAME @@ -101,6 +103,173 @@ sub report_new : Path : Args(0) { && $c->forward('redirect_or_confirm_creation'); } +=head2 report_import + +Action to accept report creations from iPhones and other mobile apps. URL is +'/import' to be compatible with existing apps. + +=cut + +sub report_import : Path('/import') { + my ( $self, $c ) = @_; + + # If this is not a POST then just print out instructions for using page + return unless $c->req->method eq 'POST'; + + # anything else we return is plain text + $c->res->content_type('text/plain; charset=utf-8'); + + # use strict; + # use Standard; + # use mySociety::AuthToken; + # use mySociety::Config; + # use mySociety::EvEl; + # use mySociety::Locale; + + my %input = + map { $_ => $c->req->param($_) || '' } ( + 'service', 'subject', 'detail', 'name', 'email', 'phone', + 'easting', 'northing', 'lat', 'lon', 'id', 'phone_id', + ); + + my @errors; + + # Get our location + my $latitude = $input{lat} ||= 0; + my $longitude = $input{lon} ||= 0; + if ( + !( $latitude || $longitude ) # have not been given lat or lon + && ( $input{easting} && $input{northing} ) # but do have e and n + ) + { + ( $latitude, $longitude ) = + Utils::convert_en_to_latlon( $input{easting}, $input{northing} ); + } + + # handle the photo upload + $c->forward( 'process_photo_upload', [ { rotate_photo => 1 } ] ); + my $photo = $c->stash->{upload_fileid}; + if ( my $error = $c->stash->{photo_error} ) { + push @errors, $error; + } + + push @errors, 'You must supply a service' unless $input{service}; + push @errors, 'Please enter a subject' unless $input{subject} =~ /\S/; + push @errors, 'Please enter your name' unless $input{name} =~ /\S/; + + if ( $input{email} !~ /\S/ ) { + push @errors, 'Please enter your email'; + } + elsif ( !mySociety::EmailUtil::is_valid_email( $input{email} ) ) { + push @errors, 'Please enter a valid email'; + } + + if ( $latitude && $c->config->{COUNTRY} eq 'GB' ) { + eval { Utils::convert_latlon_to_en( $latitude, $longitude ); }; + push @errors, + "We had a problem with the supplied co-ordinates - outside the UK?" + if $@; + } + + unless ( $photo || ( $latitude || $longitude ) ) { + push @errors, 'Either a location or a photo must be provided.'; + } + + # if we have errors then we should bail out + if (@errors) { + my $body = join '', map { "ERROR:$_\n" } @errors; + $c->res->body($body); + return; + } + +### leaving commented out for now as the values stored here never appear to +### get used and the new user accounts might make them redundant anyway. + # + # # Store for possible future use + # if ( $input{id} || $input{phone_id} ) { + # my $id = $input{id} || $input{phone_id}; + # my $already = + # dbh() + # ->selectrow_array( + # 'select id from partial_user where service=? and nsid=?', + # {}, $input{service}, $id ); + # unless ($already) { + # dbh()->do( + # 'insert into partial_user (service, nsid, name, email, phone)' + # . ' values (?, ?, ?, ?, ?)', + # {}, + # $input{service}, + # $id, + # $input{name}, + # $input{email}, + # $input{phone} + # ); + # } + # } + + # find or create the user + my $report_user = $c->model('DB::User')->find_or_create( + { + email => $input{email}, + name => $input{name}, + phone => $input{phone} + } + ); + + # create a new report (don't save it yet) + my $report = $c->model('DB::Problem')->new( + { + user => $report_user, + postcode => '', + latitude => $latitude, + longitude => $longitude, + title => $input{subject}, + detail => $input{detail}, + name => $input{name}, + service => $input{service}, + state => 'partial', + used_map => 1, + anonymous => 0, + category => '', + areas => '', + + } + ); + + # If there was a photo add that too + if ( my $fileid = $c->stash->{upload_fileid} ) { + my $file = file( $c->config->{UPLOAD_CACHE}, "$fileid.jpg" ); + my $blob = $file->slurp; + $file->remove; + $report->photo($blob); + } + + # save the report; + $report->insert(); + + my $token = + $c->model("DB::Token") + ->create( { scope => 'partial', data => $report->id } ); + + $c->stash->{report} = $report; + $c->stash->{token_url} = $c->uri_for( '/L', $token->token ); + + my $sender = mySociety::Config::get('CONTACT_EMAIL'); + $sender =~ s/team/fms-DO-NOT-REPLY/; + + # TODO - used to be sent using EvEl + $c->send_email( + 'partial.txt', + { + to => $report->user->email, + from => $sender + } + ); + + $c->res->body('SUCCESS'); + return 1; +} + =head2 initialize_report Create the report and set up some basics in it. If there is a partial report @@ -140,12 +309,21 @@ sub initialize_report : Private { ->search( { id => $id, state => 'partial' } ) # ->first; - # no point keeping it if it is done. - $token->delete unless $report; + if ($report) { - # save the token to delete at the end - $c->stash->{partial_token} = $token if $report; + # log the problem creation user in to the site + $c->authenticate( { email => $report->user->email }, + 'no_password' ); + # save the token to delete at the end + $c->stash->{partial_token} = $token if $report; + + } + else { + + # no point keeping it if it is done. + $token->delete; + } } # If we didn't find a partial then create a new one @@ -185,7 +363,7 @@ sub determine_location : Private { # If in UK and we have a lat,lon coocdinate check it is in UK # FIXME - is this a redundant check as we already see if report has a body # to handle it? - if ( !$error_msg && $c->config->{COUNTRY} eq 'GB' ) { + if ( !$error_msg && $lat && $c->config->{COUNTRY} eq 'GB' ) { eval { Utils::convert_latlon_to_en( $lat, $lon ); }; $error_msg = _( "We had a problem with the supplied co-ordinates - outside the UK?" @@ -531,7 +709,10 @@ sub process_user : Private { my $email = lc $params{email}; $email =~ s{\s+}{}g; - my $report_user = $c->model('DB::User')->find_or_new( { email => $email } ); + my $report = $c->stash->{report}; + my $report_user # + = ( $report ? $report->user : undef ) + || $c->model('DB::User')->find_or_new( { email => $email } ); # set the user's name and phone (if given) $report_user->name( _trim_text( $params{name} ) ); @@ -603,7 +784,7 @@ sub process_report : Private { 'title', 'detail', 'pc', # 'name', 'may_show_name', # 'category', # - 'partial', 'skipped', # + 'partial', 'skipped', 'submit_problem' # ); # load the report @@ -614,6 +795,9 @@ sub process_report : Private { $report->latitude( $c->stash->{latitude} ); $report->longitude( $c->stash->{longitude} ); + # Short circuit unless the form has been submitted + return 1 unless $params{submit_problem}; + # set some simple bool values (note they get inverted) $report->anonymous( $params{may_show_name} ? 0 : 1 ); $report->used_map( $params{skipped} ? 0 : 1 ); @@ -715,7 +899,11 @@ sub process_photo : Private { } sub process_photo_upload : Private { - my ( $self, $c ) = @_; + my ( $self, $c, $args ) = @_; + + # setup args and set defaults + $args ||= {}; + $args->{rotate_photo} ||= 0; # check for upload or return my $upload = $c->req->upload('photo') @@ -729,7 +917,8 @@ sub process_photo_upload : Private { } # convert the photo into a blob (also resize etc) - my $photo_blob = eval { Page::process_photo( $upload->fh ) }; + my $photo_blob = + eval { Page::process_photo( $upload->fh, $args->{rotate_photo} ) }; if ( my $error = $@ ) { my $format = _( "That image doesn't appear to have uploaded correctly (%s), please try again." diff --git a/perllib/FixMyStreet/App/Controller/Tokens.pm b/perllib/FixMyStreet/App/Controller/Tokens.pm index 6feae9e9c..9a719a59d 100644 --- a/perllib/FixMyStreet/App/Controller/Tokens.pm +++ b/perllib/FixMyStreet/App/Controller/Tokens.pm @@ -20,7 +20,7 @@ Act on the various tokens that can be submitted. =head2 confirm_problem - /[Pp]/([0-9A-Za-z]{16,18}).*$ + /P/([0-9A-Za-z]{16,18}).*$ Confirm a problem - url appears in emails sent to users after they create the problem but are not logged in. @@ -68,6 +68,21 @@ sub confirm_problem : Path('/P') { return 1; } +=head2 redirect_to_partial_problem + + /P/... + +Redirect user to continue filling in a partial problem. + +=cut + +sub redirect_to_partial_problem : Path('/L') { + my ( $self, $c, $token_code ) = @_; + + my $url = $c->uri_for( "/reports/new", { partial => $token_code } ); + return $c->res->redirect( $url ); +} + =head2 load_auth_token my $auth_token = diff --git a/perllib/FixMyStreet/TestMech.pm b/perllib/FixMyStreet/TestMech.pm index 750a78305..04d825da7 100644 --- a/perllib/FixMyStreet/TestMech.pm +++ b/perllib/FixMyStreet/TestMech.pm @@ -182,6 +182,24 @@ sub form_errors { return $result->{errors} || []; } +=head2 import_errors + + my $arrayref = $mech->import_errors; + +Takes the text output from the import post result and returns all the errors as +an arrayref. + +=cut + +sub import_errors { + my $mech = shift; + my @errors = # + grep { $_ } # + map { s{^ERROR:\s*(.*)$}{$1}g ? $_ : undef; } # + split m/\n+/, $mech->response->content; + return \@errors; +} + =head2 pc_alternatives my $arrayref = $mech->pc_alternatives; diff --git a/t/app/controller/reports_import.t b/t/app/controller/reports_import.t new file mode 100644 index 000000000..5c16324d3 --- /dev/null +++ b/t/app/controller/reports_import.t @@ -0,0 +1,158 @@ +use strict; +use warnings; +use Test::More; + +use FixMyStreet::TestMech; +use Web::Scraper; +use Path::Class; + +my $mech = FixMyStreet::TestMech->new; +$mech->get_ok('/import'); + +my $sample_file = file(__FILE__)->parent->file("sample.jpg")->stringify; +ok -e $sample_file, "sample file $sample_file exists"; + +# submit an empty report to import - check we get all errors +subtest "Test creating bad partial entries" => sub { + + foreach my $test ( + { + fields => { email => 'bob', }, + errors => [ + 'You must supply a service', + 'Please enter a subject', + 'Please enter your name', + 'Please enter a valid email', + 'Either a location or a photo must be provided.', + ], + }, + { + fields => { email => 'bob@example.com' }, + errors => [ + 'You must supply a service', + 'Please enter a subject', + 'Please enter your name', + 'Either a location or a photo must be provided.', + ], + }, + { + fields => { lat => 1, lon => 1, }, + errors => [ + 'You must supply a service', + 'Please enter a subject', + 'Please enter your name', + 'Please enter your email', +'We had a problem with the supplied co-ordinates - outside the UK?', + ], + }, + { + fields => { photo => $sample_file, }, + errors => [ + 'You must supply a service', + 'Please enter a subject', + 'Please enter your name', + 'Please enter your email', + ], + }, + ) + { + $mech->get_ok('/import'); + + $mech->submit_form_ok( # + { with_fields => $test->{fields} }, + "fill in form" + ); + + is_deeply( $mech->import_errors, $test->{errors}, "expected errors" ); + } + +}; + +# submit an empty report to import - check we get all errors +subtest "Submit a correct entry" => sub { + + $mech->get_ok('/import'); + + $mech->submit_form_ok( # + { + with_fields => { + service => 'test-script', + name => 'Test User', + email => 'test@example.com', + subject => 'Test report', + detail => 'This is a test report', + photo => $sample_file, + } + }, + "fill in form" + ); + + is_deeply( $mech->import_errors, [], "got no errors" ); + is $mech->content, 'SUCCESS', "Got success response"; + + # check that we have received the email + $mech->email_count_is(1); + my $email = $mech->get_email; + $mech->clear_emails_ok; + + my ($token_url) = $email->body =~ m{(http://\S+)}; + ok $token_url, "Found a token url $token_url"; + + # go to the token url + $mech->get_ok($token_url); + + # check that we are not shown anything as we don't have a location yet + is_deeply $mech->visible_form_values, { pc => '' }, + "check only pc field is shown"; + + $mech->submit_form_ok( # + { with_fields => { pc => 'SW1A 1AA' } }, + "fill in postcode" + ); + + # check that we are not shown anything as we don't have a location yet + is_deeply $mech->visible_form_values, + { + name => 'Test User', + email => 'test@example.com', + title => 'Test report', + detail => 'This is a test report', + photo => '', + phone => '', + may_show_name => '1', + }, + "check imported fields are shown"; + + TODO: { + local $TODO = "'/report/123' urls not srved by catalyst yet"; + + # change the details + $mech->submit_form_ok( # + { + with_fields => { + name => 'New Test User', + email => 'test@example.com', + title => 'New Test report', + detail => 'This is a test report', + phone => '01234 567 890', + may_show_name => '1', + } + }, + "Update details and save" + ); + } + + # check that report has been created + my $user = + FixMyStreet::App->model('DB::User') + ->find( { email => 'test@example.com' } ); + ok $user, "Found a user"; + + my $report = $user->problems->first; + is $report->state, 'confirmed', 'is confirmed'; + is $report->title, 'New Test report', 'title is correct'; + + $mech->delete_user($user); +}; + +done_testing(); diff --git a/t/app/controller/reports_new.t b/t/app/controller/reports_new.t index 7ee125592..c87571a9d 100644 --- a/t/app/controller/reports_new.t +++ b/t/app/controller/reports_new.t @@ -30,12 +30,6 @@ foreach my $test ( pc_alternatives => [], }, { - pc => 'ZZ9 9ZZ', - errors => - ['We had a problem with the supplied co-ordinates - outside the UK?'], - pc_alternatives => [], - }, - { pc => 'glenthorpe', errors => [], pc_alternatives => [ # TODO - should filter out these non-UK addresses diff --git a/t/app/controller/sample.jpg b/t/app/controller/sample.jpg Binary files differnew file mode 100644 index 000000000..23198cb83 --- /dev/null +++ b/t/app/controller/sample.jpg diff --git a/templates/emails/partial b/templates/email/default/partial.txt index d754744b5..279d76ea0 100644 --- a/templates/emails/partial +++ b/templates/email/default/partial.txt @@ -1,12 +1,12 @@ Subject: Confirm your report on FixMyStreet -Hi<?=$values['name']?>, +Hi [% report.name || report.email %], To confirm the report you have uploaded to FixMyStreet via -<?=$values['service']?>, and to check or add any details, +[% report.service %], and to check or add any details, please visit the following URL: -<?=$values['url']?> +[% token_url %] Thanks! diff --git a/templates/web/default/reports/new/fill_in_details.html b/templates/web/default/reports/new/fill_in_details.html index a6c7bf047..b58d0b827 100644 --- a/templates/web/default/reports/new/fill_in_details.html +++ b/templates/web/default/reports/new/fill_in_details.html @@ -87,7 +87,12 @@ [% IF upload_fileid || report.photo %] <p>[% loc('You have already attached a photo to this report, attaching another one will replace it.') %]</p> + [% IF upload_fileid %] <input type="hidden" name="upload_fileid" value="[% upload_fileid %]" /> + [% END %] + [% IF report.photo %] + <img align="right" src="/photo?id=[% report.id %]" hspace="5"> + [% END %] [% END %] <div class='form-field'> @@ -102,7 +107,7 @@ <div class='form-field'> <label for="form_name">[% loc('Name:') %]</label> - <input type="text" value="[% report_user.name | html %]" name="name" id="form_name" size="25"> + <input type="text" value="[% report.name || report_user.name | html %]" name="name" id="form_name" size="25"> </div> diff --git a/templates/web/default/reports/new/report_import.html b/templates/web/default/reports/new/report_import.html new file mode 100644 index 000000000..7aa105afe --- /dev/null +++ b/templates/web/default/reports/new/report_import.html @@ -0,0 +1,92 @@ +[% INCLUDE 'header.html', title => 'External import' %] + +<h1>External import</h1> + +<p>You may inject problem reports into FixMyStreet programatically using this +simple interface. Upon receipt, an email will be sent to the address given, +with a link the user must click in order to check the details of their report, +add any other information they wish, and then submit to the council. + +<p>This interface returns a plain text response; either <samp>SUCCESS</samp> if +the report has been successfully received, or if not, a list of errors, one per +line each starting with <samp>ERROR:</samp>. + +<p>You may submit the following information by POST to this URL +(i.e. <samp>[% c.uri_for('/import') %]</samp> ):</p> + +<style type="text/css" media="screen"> + input { + /* Hide the form elements - they are just here for simpler testing */ + display: none; + } +</style> + +<form method="POST" action="/import" enctype="multipart/form-data"> + +<dl> + <dt>service</dt> + <dd> + <em>Required</em>. + Name of application/service using this interface. + <input type="text" name="service" /> + </dd> + + <dt>id</dt> + <dd> + Unique ID of a user/device, for possible future use.<br> + <small>(e.g. used by Flickr import to know which accounts to look at)</small> + <input type="text" name="id" /> + </dd> + + <dt>subject</dt> + <dd> + <em>Required</em>. Subject of problem report. + <input type="text" name="subject" /> + </dd> + + <dt>detail</dt> + <dd> + Main body and details of problem report. + <input type="text" name="detail" /> + </dd> + + <dt>name</dt> + <dd> + <em>Required</em>. Name of problem reporter. + <input type="text" name="name" /> + </dd> + + <dt>email</dt> + <dd> + <em>Required</em>. Email address of problem reporter. + <input type="text" name="email" /> + </dd> + + <dt>phone</dt> + <dd> + Telephone number of problem reporter. + <input type="text" name="phone" /> + </dd> + + <dt>easting / northing</dt> + <dt>lat / lon</dt> + <dd> + Location of problem report. You can either supply eastings/northings, or WGS84 latitude/longitude. + <input type="text" name="easting" /> + <input type="text" name="northing" /> + <input type="text" name="lat" /> + <input type="text" name="lon" /> + </dd> + + <dt>photo</dt> + <dd> + Photo of problem (JPEG only). + <input type="file" name="photo" /> + </dd> +</dl> + +<input type="submit" /> + +</form> + +[% INCLUDE 'footer.html' %]
\ No newline at end of file diff --git a/templates/web/default/reports/new/report_new.html b/templates/web/default/reports/new/report_new.html index 34e0c981b..14d68b029 100644 --- a/templates/web/default/reports/new/report_new.html +++ b/templates/web/default/reports/new/report_new.html @@ -6,9 +6,20 @@ <div class="error">[% location_error %]</div> [% END %] -Please select where to create this report: +[% IF partial_token %] -<form action="[% c.uri_for() %]" method="POST"> + <p style="margin-top: 0; color: #cc0000;"> + <img align="right" src="/photo?id=[% report.id %]" hspace="5"> + [% loc("Thanks for uploading your photo. We now need to locate your problem, so please enter a nearby street name or postcode in the box below :") %] + </p> + + <input type="hidden" name="partial" value="[% partial_token.token %]"> + +[% ELSE %] + Please select where to create this report: +[% END %] + +<form action="/reports/new" method="POST"> [% IF pc_error %] <div class='form-error'>[% pc_error %]</div> @@ -20,6 +31,7 @@ Please select where to create this report: </div> <p> + <input type="hidden" name="partial" value="[% partial_token.token %]"> <input type="submit" value="[% loc('Search') %]"> </p> diff --git a/web/import.cgi b/web/import.cgi deleted file mode 100755 index ac36b2ee5..000000000 --- a/web/import.cgi +++ /dev/null @@ -1,181 +0,0 @@ -#!/usr/bin/perl -w -I../perllib - -# import.cgi -# Script to which things like iPhones can POST new data -# -# Copyright (c) 2008 UK Citizens Online Democracy. All rights reserved. -# Email: matthew@mysociety.org. WWW: http://www.mysociety.org -# -# $Id: import.cgi,v 1.11 2009-12-10 16:22:49 matthew Exp $ - -use strict; -use Error qw(:try); -use Standard; -use Utils; -use mySociety::AuthToken; -use mySociety::Config; -use mySociety::EmailUtil; -use mySociety::EvEl; -use mySociety::Locale; - -sub main { - my $q = shift; - - my @vars = qw(service subject detail name email phone easting northing lat lon id phone_id); - my %input = map { $_ => $q->param($_) || '' } @vars; - my @errors; - - unless ($ENV{REQUEST_METHOD} eq 'POST') { - print Page::header($q, title=>'External import'); - docs(); - print Page::footer($q); - return; - } - - # If we were given easting, northing convert to lat lon now - my $latitude = $input{lat} ||= 0; - my $longitude = $input{lon} ||= 0; - if ( - !( $latitude || $longitude ) # have not been given lat or lon - && ( $input{easting} && $input{northing} ) # but do have e and n - ) - { - ( $latitude, $longitude ) = - Utils::convert_en_to_latlon( $input{easting}, $input{northing}); - } - - my $fh = $q->upload('photo'); # MUST come before $q->header, don't know why! - print $q->header(-charset => 'utf-8', -content_type => 'text/plain'); - - if ($fh) { - my $err = Page::check_photo($q, $fh); - push @errors, $err if $err; - } - - push @errors, 'You must supply a service' unless $input{service}; - push @errors, 'Please enter a subject' unless $input{subject} && $input{subject} =~ /\S/; - push @errors, 'Please enter your name' unless $input{name} && $input{name} =~ /\S/; - - if (!$input{email} || $input{email} !~ /\S/) { - push @errors, 'Please enter your email'; - } elsif (!mySociety::EmailUtil::is_valid_email($input{email})) { - push @errors, 'Please enter a valid email'; - } - - if ( $latitude && mySociety::Config::get('COUNTRY') eq 'GB' ) { - try { - Utils::convert_latlon_to_en( $latitude, $longitude ); - } catch Error::Simple with { - my $e = shift; - push @errors, "We had a problem with the supplied co-ordinates - outside the UK?"; - }; - } - - # TODO: Get location from photo if present in EXIF data? - - my $photo; - if ($fh) { - try { - $photo = Page::process_photo($fh, 1); - } catch Error::Simple with { - my $e = shift; - push @errors, "That photo doesn't appear to have uploaded correctly ($e), please try again."; - }; - } - - unless ( $photo || ( $latitude || $longitude ) ) { - push @errors, 'Either a location or a photo must be provided.'; - } - - if (@errors) { - print map { "ERROR:$_\n" } @errors; - return; - } - - # Store for possible future use - if ($input{id} || $input{phone_id}) { - my $id = $input{id} || $input{phone_id}; - my $already = dbh()->selectrow_array('select id from partial_user where service=? and nsid=?', {}, $input{service}, $id); - unless ($already) { - dbh()->do('insert into partial_user (service, nsid, name, email, phone) values (?, ?, ?, ?, ?)', - {}, $input{service}, $id, $input{name}, $input{email}, $input{phone}); - } - } - - # Store what we have so far in the database - my $id = dbh()->selectrow_array("select nextval('problem_id_seq')"); - Utils::workaround_pg_bytea("insert into problem - (id, postcode, latitude, longitude, title, detail, name, service, - email, phone, photo, state, used_map, anonymous, category, areas) - values - (?, '', ?, ?, ?, ?, ?, ?, ?, ?, ?, 'partial', 't', 'f', '', '')", 10, - $id, $latitude, $longitude, $input{subject}, - $input{detail}, $input{name}, $input{service}, $input{email}, $input{phone}, $photo); - - # Send checking email - my $template = File::Slurp::read_file("$FindBin::Bin/../templates/emails/partial"); - my $token = mySociety::AuthToken::store('partial', $id); - my %h = ( - name => $input{name} ? ' ' . $input{name} : '', - url => mySociety::Config::get('BASE_URL') . '/L/' . $token, - service => $input{service}, - ); - - my $sender = mySociety::Config::get('CONTACT_EMAIL'); - $sender =~ s/team/fms-DO-NOT-REPLY/; - mySociety::EvEl::send({ - _template_ => $template, - _parameters_ => \%h, - To => $input{name} ? [ [ $input{email}, $input{name} ] ] : $input{email}, - From => [ $sender, 'FixMyStreet' ], - }, $input{email}); - - dbh()->commit(); - print 'SUCCESS'; -} - -Page::do_fastcgi(\&main); - -sub docs { - print <<EOF; -<p>You may inject problem reports into FixMyStreet programatically using this -simple interface. Upon receipt, an email will be sent to the address given, -with a link the user must click in order to check the details of their report, -add any other information they wish, and then submit to the council. - -<p>This interface returns a plain text response; either <samp>SUCCESS</samp> if -the report has been successfully received, or if not, a list of errors, one per -line each starting with <samp>ERROR:</samp>. - -<p>You may submit the following information by POST to this URL -(i.e. <samp>http://www.fixmystreet.com/import</samp> ):</p> -<dl> -<dt>service -<dd> -<em>Required</em>. -Name of application/service using this interface. -<dt>id -<dd>Unique ID of a user/device, for possible future use. -<br><small>(e.g. used by Flickr import to know which accounts to look at)</small> -<dt>subject -<dd> -<em>Required</em>. Subject of problem report. -<dt>detail -<dd>Main body and details of problem report. -<dt>name -<dd> -<em>Required</em>. Name of problem reporter. -<dt>email -<dd> -<em>Required</em>. Email address of problem reporter. -<dt>phone -<dd>Telephone number of problem reporter. -<dt>easting / northing -<dt>lat / lon -<dd>Location of problem report. You can either supply eastings/northings, or WGS84 latitude/longitude. -<dt>photo -<dd>Photo of problem (JPEG only). -</dl> -EOF -} - |