From 87098bd183fcf59ba038f1cebef68356e6d57ed5 Mon Sep 17 00:00:00 2001 From: Robin Houston Date: Thu, 24 May 2012 12:57:00 +0100 Subject: Authenticated API An authenticated API for public bodies. So far just one method is implemented, which gives the details of a request in JSON format. --- app/controllers/api_controller.rb | 46 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) create mode 100644 app/controllers/api_controller.rb (limited to 'app/controllers/api_controller.rb') diff --git a/app/controllers/api_controller.rb b/app/controllers/api_controller.rb new file mode 100644 index 000000000..538dade3f --- /dev/null +++ b/app/controllers/api_controller.rb @@ -0,0 +1,46 @@ +class ApiController < ApplicationController + before_filter :check_api_key + + def create_request + + end + + def show_request + @request = InfoRequest.find(params[:id]) + raise PermissionDenied if @request.public_body_id != @public_body.id + + @request_data = { + :id => @request.id, + :url => make_url("request", @request.url_title), + :title => @request.title, + + :created_at => @request.created_at, + :updated_at => @request.updated_at, + + :status => @request.calculate_status, + + :public_body_url => make_url("body", @request.public_body.url_name), + :requestor_url => make_url("user", @request.user.url_name), + :request_email => @request.incoming_email, + + :request_text => @request.last_event_forming_initial_request.outgoing_message.body, + } + + render :json => @request_data + end + + def add_correspondence + + end + + protected + def check_api_key + @public_body = PublicBody.find_by_api_key(params[:k].gsub(' ', '+')) + raise PermissionDenied if @public_body.nil? + end + + private + def make_url(*args) + "http://" + MySociety::Config.get("DOMAIN", '127.0.0.1:3000') + "/" + args.join("/") + end +end -- cgit v1.2.3 From 67d2a6c466a1167fa0343e256d73bc89ec27ebdf Mon Sep 17 00:00:00 2001 From: Robin Houston Date: Thu, 24 May 2012 13:12:05 +0100 Subject: Reorder methods --- app/controllers/api_controller.rb | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'app/controllers/api_controller.rb') diff --git a/app/controllers/api_controller.rb b/app/controllers/api_controller.rb index 538dade3f..205ad1c3b 100644 --- a/app/controllers/api_controller.rb +++ b/app/controllers/api_controller.rb @@ -1,10 +1,6 @@ class ApiController < ApplicationController before_filter :check_api_key - def create_request - - end - def show_request @request = InfoRequest.find(params[:id]) raise PermissionDenied if @request.public_body_id != @public_body.id @@ -29,6 +25,10 @@ class ApiController < ApplicationController render :json => @request_data end + def create_request + + end + def add_correspondence end -- cgit v1.2.3 From 132dc3e9862d85109eb4a0e5946c22d3ec97d4bb Mon Sep 17 00:00:00 2001 From: Seb Bacon Date: Thu, 24 May 2012 14:05:17 +0100 Subject: Work in progress on getting new APIController test to pass. They don't, yet! --- app/controllers/api_controller.rb | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) (limited to 'app/controllers/api_controller.rb') diff --git a/app/controllers/api_controller.rb b/app/controllers/api_controller.rb index 205ad1c3b..ed567640e 100644 --- a/app/controllers/api_controller.rb +++ b/app/controllers/api_controller.rb @@ -26,7 +26,27 @@ class ApiController < ApplicationController end def create_request - + json = ActiveSupport::JSON.decode(params[:request_json]) + existing_request = InfoRequest.find_by_existing_request(json["title"], + @public_body.id, + json["body"]) + info_request = InfoRequest.new(:title => json["title"], + :public_body_id => @public_body.id, + :described_state => "awaiting_response", + :external_user_name => json["external_user_name"], + :external_url => json["external_url"]) + outgoing_message = OutgoingMessage.new(json["body"]) + info_request.outgoing_messages << outgoing_messages + outgoing_message.info_request = info_request + # See if values were valid or not + if !existing_request.nil? || !info_request.valid? + # We don't want the error "Outgoing messages is invalid", as the outgoing message + # will be valid for a specific reason which we are displaying anyway. + info_request.errors.delete("outgoing_messages") + render :json => {'errors' => :info_request.errors.to_s} + else + render :json => {'url' => 'http://goo.com'} + end end def add_correspondence -- cgit v1.2.3 From c2681d8effb64e4f49ab17d867a5616613dea4f7 Mon Sep 17 00:00:00 2001 From: Robin Houston Date: Mon, 28 May 2012 10:21:36 +0100 Subject: API create_request method is working "when using the API", it "should create a new request from a POST", AND IT DOES! --- app/controllers/api_controller.rb | 58 +++++++++++++++++++++++++++------------ 1 file changed, 40 insertions(+), 18 deletions(-) (limited to 'app/controllers/api_controller.rb') diff --git a/app/controllers/api_controller.rb b/app/controllers/api_controller.rb index ed567640e..a5b70b8d2 100644 --- a/app/controllers/api_controller.rb +++ b/app/controllers/api_controller.rb @@ -27,26 +27,48 @@ class ApiController < ApplicationController def create_request json = ActiveSupport::JSON.decode(params[:request_json]) - existing_request = InfoRequest.find_by_existing_request(json["title"], - @public_body.id, - json["body"]) - info_request = InfoRequest.new(:title => json["title"], - :public_body_id => @public_body.id, - :described_state => "awaiting_response", - :external_user_name => json["external_user_name"], - :external_url => json["external_url"]) - outgoing_message = OutgoingMessage.new(json["body"]) - info_request.outgoing_messages << outgoing_messages - outgoing_message.info_request = info_request - # See if values were valid or not - if !existing_request.nil? || !info_request.valid? - # We don't want the error "Outgoing messages is invalid", as the outgoing message - # will be valid for a specific reason which we are displaying anyway. + request = InfoRequest.new( + :title => json["title"], + :public_body_id => @public_body.id, + :described_state => "waiting_response", + :external_user_name => json["external_user_name"], + :external_url => json["external_url"] + ) + + outgoing_message = OutgoingMessage.new( + :status => 'ready', + :message_type => 'initial_request', + :body => json["body"], + :last_sent_at => Time.now(), + :what_doing => 'normal_sort', + :info_request => request + ) + request.outgoing_messages << outgoing_message + + # Return an error if the request is invalid + if !request.valid? + # We don't want the error "Outgoing messages is invalid", as in this + # case the list of errors will also contain a more specific error + # describing the reason it is invalid. info_request.errors.delete("outgoing_messages") - render :json => {'errors' => :info_request.errors.to_s} - else - render :json => {'url' => 'http://goo.com'} + + render :json => { + 'errors' => request.errors.full_messages + } + return end + + request.save! + request.log_event("sent", + :email => nil, + :outgoing_message_id => outgoing_message.id, + :smtp_message_id => nil + ) + render :json => { + 'url' => make_url("request", request.url_title), + 'id' => request.id + } + end def add_correspondence -- cgit v1.2.3 From c6b9e01f32f5e58a4abf48b6c781906cd914429f Mon Sep 17 00:00:00 2001 From: Robin Houston Date: Mon, 28 May 2012 10:28:02 +0100 Subject: Just include all the error messages MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit I can’t see any way the error could be triggered by the caller, anyway. --- app/controllers/api_controller.rb | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) (limited to 'app/controllers/api_controller.rb') diff --git a/app/controllers/api_controller.rb b/app/controllers/api_controller.rb index a5b70b8d2..a152813f0 100644 --- a/app/controllers/api_controller.rb +++ b/app/controllers/api_controller.rb @@ -46,12 +46,8 @@ class ApiController < ApplicationController request.outgoing_messages << outgoing_message # Return an error if the request is invalid + # (Can this ever happen?) if !request.valid? - # We don't want the error "Outgoing messages is invalid", as in this - # case the list of errors will also contain a more specific error - # describing the reason it is invalid. - info_request.errors.delete("outgoing_messages") - render :json => { 'errors' => request.errors.full_messages } -- cgit v1.2.3 From a9da9e604855fec18b5b7af349a0c8c0330ebfea Mon Sep 17 00:00:00 2001 From: Robin Houston Date: Mon, 28 May 2012 10:29:44 +0100 Subject: more comments --- app/controllers/api_controller.rb | 3 +++ 1 file changed, 3 insertions(+) (limited to 'app/controllers/api_controller.rb') diff --git a/app/controllers/api_controller.rb b/app/controllers/api_controller.rb index a152813f0..e5b66e7c3 100644 --- a/app/controllers/api_controller.rb +++ b/app/controllers/api_controller.rb @@ -54,12 +54,15 @@ class ApiController < ApplicationController return end + # Save the request, and add the corresponding InfoRequestEvent request.save! request.log_event("sent", :email => nil, :outgoing_message_id => outgoing_message.id, :smtp_message_id => nil ) + + # Return the URL and ID number. render :json => { 'url' => make_url("request", request.url_title), 'id' => request.id -- cgit v1.2.3 From ceefc42a75a06f693fe614d345e619ace5014d23 Mon Sep 17 00:00:00 2001 From: Robin Houston Date: Mon, 28 May 2012 14:49:40 +0100 Subject: API: we can add a response to a request --- app/controllers/api_controller.rb | 81 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 81 insertions(+) (limited to 'app/controllers/api_controller.rb') diff --git a/app/controllers/api_controller.rb b/app/controllers/api_controller.rb index e5b66e7c3..9bcd82632 100644 --- a/app/controllers/api_controller.rb +++ b/app/controllers/api_controller.rb @@ -57,6 +57,7 @@ class ApiController < ApplicationController # Save the request, and add the corresponding InfoRequestEvent request.save! request.log_event("sent", + :api => true, :email => nil, :outgoing_message_id => outgoing_message.id, :smtp_message_id => nil @@ -71,7 +72,87 @@ class ApiController < ApplicationController end def add_correspondence + request = InfoRequest.find(params[:id]) + json = ActiveSupport::JSON.decode(params[:correspondence_json]) + direction = json["direction"] + body = json["body"] + sent_at_str = json["sent_at"] + + errors = [] + + if !request.is_external? + raise ActiveRecord::RecordNotFound.new("Request #{params[:id]} cannot be updated using the API") + end + + if request.public_body_id != @public_body.id + raise ActiveRecord::RecordNotFound.new("You do not own request #{params[:id]}") + end + + if !["request", "response"].include?(direction) + errors << "The direction parameter must be 'request' or 'response'" + end + + if body.nil? + errors << "The 'body' is missing" + elsif body.empty? + errors << "The 'body' is empty" + end + + begin + sent_at = Time.iso8601(sent_at_str) + rescue ArgumentError + errors << "Failed to parse 'sent_at' field as ISO8601 time: #{sent_at_str}" + end + + if !errors.empty? + render :json => { "errors" => errors } + return + end + + if direction == "request" + # In the 'request' direction, i.e. what we (Alaveteli) regard as outgoing + + outgoing_message = OutgoingMessage.new( + :info_request => request, + :status => 'ready', + :message_type => 'followup', + :body => body, + :last_sent_at => sent_at, + :what_doing => 'normal_sort' + ) + request.outgoing_messages << outgoing_message + request.save! + request.log_event("followup_sent", + :api => true, + :email => nil, + :outgoing_message_id => outgoing_message.id, + :smtp_message_id => nil + ) + else + # In the 'response' direction, i.e. what we (Alaveteli) regard as incoming + + raw_email = RawEmail.new + incoming_message = IncomingMessage.new( + :info_request => request, + :raw_email => raw_email, + :sent_at => sent_at + ) + raw_email.incoming_message = incoming_message + raw_email.save! + raw_email.data = "From external\nFrom: \nTo: \nDate: #{sent_at.rfc2822}\nSubject: Response\n\n" + body + + request.incoming_messages << incoming_message + request.save! + request.log_event("response", + :api => true, + :email => nil, + :incoming_message_id => incoming_message.id, + :smtp_message_id => nil + ) + end + + head :no_content end protected -- cgit v1.2.3 From a72660063d1add8a7cd4bcc540496249b2a4a0aa Mon Sep 17 00:00:00 2001 From: Robin Houston Date: Mon, 28 May 2012 15:46:01 +0100 Subject: API: Some testing of show_request --- app/controllers/api_controller.rb | 1 + 1 file changed, 1 insertion(+) (limited to 'app/controllers/api_controller.rb') diff --git a/app/controllers/api_controller.rb b/app/controllers/api_controller.rb index 9bcd82632..2c7f9a4a9 100644 --- a/app/controllers/api_controller.rb +++ b/app/controllers/api_controller.rb @@ -157,6 +157,7 @@ class ApiController < ApplicationController protected def check_api_key + raise "Missing required parameter 'k'" if params[:k].nil? @public_body = PublicBody.find_by_api_key(params[:k].gsub(' ', '+')) raise PermissionDenied if @public_body.nil? end -- cgit v1.2.3 From e19238dd262e3254c0cd269f2f3b28f3cee0fd09 Mon Sep 17 00:00:00 2001 From: Robin Houston Date: Mon, 28 May 2012 17:00:34 +0100 Subject: WIP attachment uploading via API --- app/controllers/api_controller.rb | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) (limited to 'app/controllers/api_controller.rb') diff --git a/app/controllers/api_controller.rb b/app/controllers/api_controller.rb index 2c7f9a4a9..5661819b9 100644 --- a/app/controllers/api_controller.rb +++ b/app/controllers/api_controller.rb @@ -74,6 +74,7 @@ class ApiController < ApplicationController def add_correspondence request = InfoRequest.find(params[:id]) json = ActiveSupport::JSON.decode(params[:correspondence_json]) + attachments = params[:attachments] direction = json["direction"] body = json["body"] @@ -105,8 +106,12 @@ class ApiController < ApplicationController errors << "Failed to parse 'sent_at' field as ISO8601 time: #{sent_at_str}" end + if direction == "request" && !attachments.nil? + errors << "You cannot attach files to messages in the 'request' direction" + end + if !errors.empty? - render :json => { "errors" => errors } + render :json => { "errors" => errors }, :status => 500 return end @@ -144,6 +149,21 @@ class ApiController < ApplicationController request.incoming_messages << incoming_message request.save! + + attachments.each_with_index do |attachment, i| + filename = File.basename(attachment.original_filename) + body = attachment.read + content_type = AlaveteliFileTypes.filename_and_content_to_mimetype(filename, body) || 'application/octet-stream' + + a = FoiAttachment.new( + :incoming_message_id => incoming_message.id, + :filename => filename, + :content_type => content_type + ) + a.body = body + a.save! + end + request.log_event("response", :api => true, :email => nil, -- cgit v1.2.3 From 1ff635e834c004600faa445fc53e757996cde30d Mon Sep 17 00:00:00 2001 From: Robin Houston Date: Thu, 7 Jun 2012 22:04:53 +0100 Subject: WIP API --- app/controllers/api_controller.rb | 36 ++++++++---------------------------- 1 file changed, 8 insertions(+), 28 deletions(-) (limited to 'app/controllers/api_controller.rb') diff --git a/app/controllers/api_controller.rb b/app/controllers/api_controller.rb index 5661819b9..c1156845d 100644 --- a/app/controllers/api_controller.rb +++ b/app/controllers/api_controller.rb @@ -136,40 +136,20 @@ class ApiController < ApplicationController ) else # In the 'response' direction, i.e. what we (Alaveteli) regard as incoming - - raw_email = RawEmail.new - incoming_message = IncomingMessage.new( - :info_request => request, - :raw_email => raw_email, - :sent_at => sent_at - ) - raw_email.incoming_message = incoming_message - raw_email.save! - raw_email.data = "From external\nFrom: \nTo: \nDate: #{sent_at.rfc2822}\nSubject: Response\n\n" + body - - request.incoming_messages << incoming_message - request.save! - - attachments.each_with_index do |attachment, i| + attachment_hashes = [] + (attachments || []).each_with_index do |attachment, i| filename = File.basename(attachment.original_filename) body = attachment.read content_type = AlaveteliFileTypes.filename_and_content_to_mimetype(filename, body) || 'application/octet-stream' - - a = FoiAttachment.new( - :incoming_message_id => incoming_message.id, - :filename => filename, - :content_type => content_type + attachment_hashes.push( + :content_type => content_type, + :body => body, + :filename => filename ) - a.body = body - a.save! end - request.log_event("response", - :api => true, - :email => nil, - :incoming_message_id => incoming_message.id, - :smtp_message_id => nil - ) + mail = RequestMailer.create_external_response(request, body, sent_at, attachment_hashes) + request.receive(mail, mail.encoded, true) end head :no_content -- cgit v1.2.3 From 89459d3902583fa3d6dad78462d2bf2fa6f94db6 Mon Sep 17 00:00:00 2001 From: Robin Houston Date: Mon, 18 Jun 2012 12:55:11 +0100 Subject: API controller tests all pass --- app/controllers/api_controller.rb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'app/controllers/api_controller.rb') diff --git a/app/controllers/api_controller.rb b/app/controllers/api_controller.rb index c1156845d..524aa44b7 100644 --- a/app/controllers/api_controller.rb +++ b/app/controllers/api_controller.rb @@ -139,11 +139,11 @@ class ApiController < ApplicationController attachment_hashes = [] (attachments || []).each_with_index do |attachment, i| filename = File.basename(attachment.original_filename) - body = attachment.read - content_type = AlaveteliFileTypes.filename_and_content_to_mimetype(filename, body) || 'application/octet-stream' + attachment_body = attachment.read + content_type = AlaveteliFileTypes.filename_and_content_to_mimetype(filename, attachment_body) || 'application/octet-stream' attachment_hashes.push( :content_type => content_type, - :body => body, + :body => attachment_body, :filename => filename ) end -- cgit v1.2.3