openstreetmap-website/app/controllers/trace_controller.rb
Tom Hughes dcad29dad0 Split the rest action into sparate read, update and delete actions thus
allowing authorization to be done on a per-action basis without worring
about the method. This should make the user API work.

Also do a lot of cleanup of the controllers.
2007-06-27 17:27:10 +00:00

232 lines
8.2 KiB
Ruby

class TraceController < ApplicationController
before_filter :authorize_web
before_filter :authorize, :only => [:api_details, :api_data, :api_create]
layout 'site'
# Counts and selects pages of GPX traces for various criteria (by user, tags, public etc.).
# target_user - if set, specifies the user to fetch traces for. if not set will fetch all traces
# paging_action - the action that will be linked back to from view
def list (target_user = nil, paging_action = 'list')
@title = 'public GPS traces'
@title += " tagged with #{params[:tag]}" if params[:tag]
@traces_per_page = 20
page_index = params[:page] ? params[:page].to_i - 1 : 0 # nice 1-based page -> 0-based page index
# from display name, pick up user id if one user's traces only
display_name = params[:display_name]
if target_user.nil? and display_name and display_name != ''
@paging_action = 'view'
@display_name = display_name
@title += " from #{@display_name}"
target_user = User.find(:first, :conditions => [ "display_name = ?", display_name])
end
opt = Hash.new
opt[:include] = [:user, :tags] # load users and tags from db at same time as traces
# four main cases:
# 1 - all traces, logged in = all public traces + all user's (i.e + all mine)
# 2 - all traces, not logged in = all public traces
# 3 - user's traces, logged in as same user = all user's traces
# 4 - user's traces, not logged in as that user = all user's public traces
if target_user.nil? # all traces
if @user
conditions = ["(public = 1 OR user_id = ?)", @user.id] #1
else
conditions = ["public = 1"] #2
end
else
if @user and @user.id == target_user.id
conditions = ["user_id = ?", @user.id] #3 (check vs user id, so no join + can't pick up non-public traces by changing name)
else
conditions = ["public = 1 AND user_id = ?", target_user.id] #4
end
end
conditions[0] += " AND users.display_name != ''" # users need to set display name before traces will be exposed
opt[:order] = 'timestamp DESC'
if params[:tag]
@tag = params[:tag]
conditions[0] += " AND gpx_file_tags.tag = ?"
conditions << @tag;
end
opt[:conditions] = conditions
# count traces using all options except limit
@max_trace = Trace.count(opt)
@max_page = Integer((@max_trace + 1) / @traces_per_page)
# last step before fetch - add paging options
opt[:limit] = @traces_per_page
if page_index > 0
opt[:offset] = @traces_per_page * page_index
end
@traces = Trace.find(:all , opt)
# put together SET of tags across traces, for related links
tagset = Hash.new
if @traces
@traces.each do |trace|
trace.tags.reload if params[:tag] # if searched by tag, ActiveRecord won't bring back other tags, so do explicitly here
trace.tags.each do |tag|
tagset[tag.tag] = tag.tag
end
end
end
# final helper vars for view
@display_name = display_name
@all_tags = tagset.values
@paging_action = paging_action # the action that paging requests should route back to, e.g. 'list' or 'mine'
@page = page_index + 1 # nice 1-based external page numbers
end
def mine
if @user
list(@user, 'mine') unless @user.nil?
else
redirect_to :controller => 'user', :action => 'login', :referer => request.request_uri
end
end
def view
@trace = Trace.find(params[:id])
unless @trace.public
if @user
render :nothing, :status => :forbidden if @trace.user.id != @user.id
end
end
end
def create
filename = "/tmp/#{rand}"
File.open(filename, "w") { |f| f.write(params[:trace][:gpx_file].read) }
params[:trace][:name] = params[:trace][:gpx_file].original_filename.gsub(/[^a-zA-Z0-9.]/, '_') # This makes sure filenames are sane
params[:trace].delete('gpx_file') # remove the field from the hash, because there's no such field in the DB
@trace = Trace.new(params[:trace])
@trace.inserted = false
@trace.user = @user
@trace.timestamp = Time.now
if @trace.save
saved_filename = "/home/osm/gpx/#{@trace.id}.gpx"
File.rename(filename, saved_filename)
logger.info("id is #{@trace.id}")
flash[:notice] = "Your GPX file has been uploaded and is awaiting insertion in to the database. This will usually happen within half an hour, and an email will be sent to you on completion."
redirect_to :action => 'mine'
end
end
def data
trace = Trace.find(params[:id])
if trace and (trace.public? or (@user and @user == trace.user))
send_file(trace.trace_name, :filename => "#{trace.id}.gpx", :type => trace.mime_type, :disposition => 'attachment')
else
render :nothing, :status => :not_found
end
end
def make_public
trace = Trace.find(params[:id])
if @user and trace.user == @user and !trace.public
trace.public = true
trace.save
flash[:notice] = 'Track made public'
redirect_to :controller => 'trace', :action => 'view', :id => params[:id]
end
end
def georss
traces = Trace.find(:all, :conditions => ['public = true'], :order => 'timestamp DESC', :limit => 20)
rss = OSM::GeoRSS.new
#def add(latitude=0, longitude=0, title_text='dummy title', url='http://www.example.com/', description_text='dummy description', timestamp=Time.now)
traces.each do |trace|
rss.add(trace.latitude, trace.longitude, trace.name, url_for({:controller => 'trace', :action => 'view', :id => trace.id, :display_name => trace.user.display_name}), "<img src='#{url_for({:controller => 'trace', :action => 'icon', :id => trace.id, :user_login => trace.user.display_name})}'> GPX file with #{trace.size} points from #{trace.user.display_name}", trace.timestamp)
end
render :text => rss.to_s, :content_type => "application/rss+xml"
end
def picture
begin
trace = Trace.find(params[:id])
if trace.public? or (@user and @user == trace.user)
send_file(trace.large_picture_name, :filename => "#{trace.id}.gif", :type => 'image/gif', :disposition => 'inline')
else
render :nothing, :status => :forbidden
end
rescue ActiveRecord::RecordNotFound
render :nothing => true, :status => :not_found
rescue
render :nothing => true, :status => :internal_server_error
end
end
def icon
begin
trace = Trace.find(params[:id])
if trace.public? or (@user and @user == trace.user)
send_file(trace.icon_picture_name, :filename => "#{trace.id}_icon.gif", :type => 'image/gif', :disposition => 'inline')
else
render :nothing, :status => :forbidden
end
rescue ActiveRecord::RecordNotFound
render :nothing => true, :status => :not_found
rescue
render :nothing => true, :status => :internal_server_error
end
end
def api_details
begin
trace = Trace.find(params[:id])
if trace.public? or trace.user == @user
render :text => trace.to_xml.to_s, :content_type => "text/xml"
else
render :nothing => true, :status => :forbidden
end
rescue ActiveRecord::RecordNotFound
render :nothing => true, :status => :not_found
rescue
render :nothing => true, :status => :internal_server_error
end
end
def api_data
render :action => 'data'
end
def api_create
#FIXME merge this code with create as they're pretty similar?
filename = "/tmp/#{rand}"
File.open(filename, "w") { |f| f.write(request.raw_post) }
params[:trace] = {}
params[:trace][:name] = params[:filename]
params[:trace][:tagstring] = params[:tags]
params[:trace][:description] = params[:description]
@trace = Trace.new(params[:trace])
@trace.inserted = false
@trace.user = @user
@trace.timestamp = Time.now
if @trace.save
saved_filename = "/home/osm/gpx/#{@trace.id}.gpx"
File.rename(filename, saved_filename)
logger.info("id is #{@trace.id}")
flash[:notice] = "Your GPX file has been uploaded and is awaiting insertion in to the database. This will usually happen within half an hour, and an email will be sent to you on completion."
render :nothing => true
else
render :nothing => true, :status => :internal_server_error
end
end
end