]> git.openstreetmap.org Git - rails.git/blobdiff - app/controllers/api/traces_controller.rb
Move the api trace methods into a separate controller under the api namespace
[rails.git] / app / controllers / api / traces_controller.rb
diff --git a/app/controllers/api/traces_controller.rb b/app/controllers/api/traces_controller.rb
new file mode 100644 (file)
index 0000000..8401e78
--- /dev/null
@@ -0,0 +1,169 @@
+module Api
+  class TracesController < ApplicationController
+    layout "site", :except => :georss
+
+    skip_before_action :verify_authenticity_token
+    before_action :authorize_web
+    before_action :set_locale
+    before_action :authorize
+    before_action :api_deny_access_handler
+
+    authorize_resource
+
+    before_action :check_database_readable, :except => [:api_read, :api_data]
+    before_action :check_database_writable, :only => [:api_create, :api_update, :api_delete]
+    before_action :check_api_readable, :only => [:api_read, :api_data]
+    before_action :check_api_writable, :only => [:api_create, :api_update, :api_delete]
+    before_action :offline_redirect, :only => [:api_create, :api_delete, :api_data]
+    around_action :api_call_handle_error
+
+    def api_read
+      trace = Trace.visible.find(params[:id])
+
+      if trace.public? || trace.user == current_user
+        render :xml => trace.to_xml.to_s
+      else
+        head :forbidden
+      end
+    end
+
+    def api_update
+      trace = Trace.visible.find(params[:id])
+
+      if trace.user == current_user
+        trace.update_from_xml(request.raw_post)
+        trace.save!
+
+        head :ok
+      else
+        head :forbidden
+      end
+    end
+
+    def api_delete
+      trace = Trace.visible.find(params[:id])
+
+      if trace.user == current_user
+        trace.visible = false
+        trace.save!
+
+        head :ok
+      else
+        head :forbidden
+      end
+    end
+
+    def api_data
+      trace = Trace.visible.find(params[:id])
+
+      if trace.public? || trace.user == current_user
+        if request.format == Mime[:xml]
+          send_data(trace.xml_file.read, :filename => "#{trace.id}.xml", :type => request.format.to_s, :disposition => "attachment")
+        elsif request.format == Mime[:gpx]
+          send_data(trace.xml_file.read, :filename => "#{trace.id}.gpx", :type => request.format.to_s, :disposition => "attachment")
+        else
+          send_file(trace.trace_name, :filename => "#{trace.id}#{trace.extension_name}", :type => trace.mime_type, :disposition => "attachment")
+        end
+      else
+        head :forbidden
+      end
+    end
+
+    def api_create
+      tags = params[:tags] || ""
+      description = params[:description] || ""
+      visibility = params[:visibility]
+
+      if visibility.nil?
+        visibility = if params[:public]&.to_i&.nonzero?
+                       "public"
+                     else
+                       "private"
+                     end
+      end
+
+      if params[:file].respond_to?(:read)
+        trace = do_create(params[:file], tags, description, visibility)
+
+        if trace.id
+          render :plain => trace.id.to_s
+        elsif trace.valid?
+          head :internal_server_error
+        else
+          head :bad_request
+        end
+      else
+        head :bad_request
+      end
+    end
+
+    private
+
+    def do_create(file, tags, description, visibility)
+      # Sanitise the user's filename
+      name = file.original_filename.gsub(/[^a-zA-Z0-9.]/, "_")
+
+      # Get a temporary filename...
+      filename = "/tmp/#{rand}"
+
+      # ...and save the uploaded file to that location
+      File.open(filename, "wb") { |f| f.write(file.read) }
+
+      # Create the trace object, falsely marked as already
+      # inserted to stop the import daemon trying to load it
+      trace = Trace.new(
+        :name => name,
+        :tagstring => tags,
+        :description => description,
+        :visibility => visibility,
+        :inserted => true,
+        :user => current_user,
+        :timestamp => Time.now.getutc
+      )
+
+      if trace.valid?
+        Trace.transaction do
+          begin
+            # Save the trace object
+            trace.save!
+
+            # Rename the temporary file to the final name
+            FileUtils.mv(filename, trace.trace_name)
+          rescue StandardError
+            # Remove the file as we have failed to update the database
+            FileUtils.rm_f(filename)
+
+            # Pass the exception on
+            raise
+          end
+
+          begin
+            # Clear the inserted flag to make the import daemon load the trace
+            trace.inserted = false
+            trace.save!
+          rescue StandardError
+            # Remove the file as we have failed to update the database
+            FileUtils.rm_f(trace.trace_name)
+
+            # Pass the exception on
+            raise
+          end
+        end
+      end
+
+      # Finally save the user's preferred privacy level
+      if pref = current_user.preferences.where(:k => "gps.trace.visibility").first
+        pref.v = visibility
+        pref.save
+      else
+        current_user.preferences.create(:k => "gps.trace.visibility", :v => visibility)
+      end
+
+      trace
+    end
+
+    def offline_redirect
+      redirect_to :action => :offline if STATUS == :gpx_offline
+    end
+  end
+end