]> git.openstreetmap.org Git - rails.git/blob - app/controllers/trace_controller.rb
Fix tag links.
[rails.git] / app / controllers / trace_controller.rb
1 class TraceController < ApplicationController
2   before_filter :authorize_web  
3   before_filter :authorize, :only => [:api_details, :api_data, :api_create]
4   layout 'site'
5  
6   # Counts and selects pages of GPX traces for various criteria (by user, tags, public etc.).
7   #  target_user - if set, specifies the user to fetch traces for.  if not set will fetch all traces
8   def list (target_user = nil)
9     # from display name, pick up user id if one user's traces only
10     display_name = params[:display_name]
11     if target_user.nil? and !display_name.blank?
12       @display_name = display_name
13       target_user = User.find(:first, :conditions => [ "display_name = ?", display_name])
14     end
15
16     # set title
17     if target_user.nil?
18       @title = "public GPS traces"
19     elsif target_user.id == @user.id
20       @title = "your GPS traces"
21     else
22       @title = "public GPS traces from #{target_user.display_name}"
23     end
24
25     @title += " tagged with #{params[:tag]}" if params[:tag]
26
27     opt = Hash.new
28     opt[:include] = [:user, :tags] # load users and tags from db at same time as traces
29
30     # four main cases:
31     # 1 - all traces, logged in = all public traces + all user's (i.e + all mine)
32     # 2 - all traces, not logged in = all public traces
33     # 3 - user's traces, logged in as same user = all user's traces 
34     # 4 - user's traces, not logged in as that user = all user's public traces
35     if target_user.nil? # all traces
36       if @user
37         conditions = ["(public = 1 OR user_id = ?)", @user.id] #1
38       else
39         conditions  = ["public = 1"] #2
40       end
41     else
42       if @user and @user.id == target_user.id
43         conditions = ["user_id = ?", @user.id] #3 (check vs user id, so no join + can't pick up non-public traces by changing name)
44       else
45         conditions = ["public = 1 AND user_id = ?", target_user.id] #4
46       end
47     end
48     conditions[0] += " AND users.display_name != ''" # users need to set display name before traces will be exposed
49     
50     opt[:order] = 'timestamp DESC'
51     if params[:tag]
52       @tag = params[:tag]
53       conditions[0] += " AND gpx_file_tags.tag = ?"
54       conditions << @tag;
55     end
56     
57     opt[:conditions] = conditions
58     opt[:per_page] = 20
59
60     @trace_pages, @traces = paginate(:traces, opt)
61     
62     # put together SET of tags across traces, for related links
63     tagset = Hash.new
64     if @traces
65       @traces.each do |trace|
66         trace.tags.reload if params[:tag] # if searched by tag, ActiveRecord won't bring back other tags, so do explicitly here
67         trace.tags.each do |tag|
68           tagset[tag.tag] = tag.tag
69         end
70       end
71     end
72     
73     # final helper vars for view
74     @display_name = display_name
75     @all_tags = tagset.values
76   end
77
78   def mine
79     if @user
80       list(@user) unless @user.nil?
81     else
82       redirect_to :controller => 'user', :action => 'login', :referer => request.request_uri
83     end
84   end
85
86   def view
87     @trace = Trace.find(params[:id])
88     unless @trace.public
89       if @user
90         render :nothing, :status => :forbidden if @trace.user.id != @user.id
91       end
92     end
93   rescue ActiveRecord::RecordNotFound
94     render :nothing => true, :status => :not_found
95   end
96
97   def create
98     name = params[:trace][:gpx_file].original_filename.gsub(/[^a-zA-Z0-9.]/, '_') # This makes sure filenames are sane
99
100     do_create(name, params[:trace][:tagstring], params[:trace][:description], params[:trace][:public]) do |f|
101       f.write(params[:trace][:gpx_file].read)
102     end
103
104     if @trace.id
105       logger.info("id is #{@trace.id}")
106       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."
107
108       redirect_to :action => 'mine'
109     end
110   end
111
112   def data
113     trace = Trace.find(params[:id])
114     if trace and (trace.public? or (@user and @user == trace.user))
115       send_file(trace.trace_name, :filename => "#{trace.id}#{trace.extension_name}", :type => trace.mime_type, :disposition => 'attachment')
116     else
117       render :nothing, :status => :not_found
118     end
119   end
120
121   def make_public
122     trace = Trace.find(params[:id])
123     if @user and trace.user == @user and !trace.public
124       trace.public = true
125       trace.save
126       flash[:notice] = 'Track made public'
127       redirect_to :controller => 'trace', :action => 'view', :id => params[:id]
128     end
129   end
130
131   def georss
132     traces = Trace.find(:all, :conditions => ['public = true'], :order => 'timestamp DESC', :limit => 20)
133
134     rss = OSM::GeoRSS.new
135
136     #def add(latitude=0, longitude=0, title_text='dummy title', url='http://www.example.com/', description_text='dummy description', timestamp=Time.now)
137     traces.each do |trace|
138       rss.add(trace.latitude, trace.longitude, trace.name, trace.user.display_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)
139     end
140
141     render :text => rss.to_s, :content_type => "application/rss+xml"
142   end
143
144   def picture
145     begin
146       trace = Trace.find(params[:id])
147
148       if trace.public? or (@user and @user == trace.user)
149         send_file(trace.large_picture_name, :filename => "#{trace.id}.gif", :type => 'image/gif', :disposition => 'inline')
150       else
151         render :nothing, :status => :forbidden
152       end
153     rescue ActiveRecord::RecordNotFound
154       render :nothing => true, :status => :not_found
155     rescue
156       render :nothing => true, :status => :internal_server_error
157     end
158   end
159
160   def icon
161     begin
162       trace = Trace.find(params[:id])
163
164       if trace.public? or (@user and @user == trace.user)
165         send_file(trace.icon_picture_name, :filename => "#{trace.id}_icon.gif", :type => 'image/gif', :disposition => 'inline')
166       else
167         render :nothing, :status => :forbidden
168       end
169     rescue ActiveRecord::RecordNotFound
170       render :nothing => true, :status => :not_found
171     rescue
172       render :nothing => true, :status => :internal_server_error
173     end
174   end
175
176   def api_details
177     begin
178       trace = Trace.find(params[:id])
179
180       if trace.public? or trace.user == @user
181         render :text => trace.to_xml.to_s, :content_type => "text/xml"
182       else
183         render :nothing => true, :status => :forbidden
184       end
185     rescue ActiveRecord::RecordNotFound
186       render :nothing => true, :status => :not_found
187     rescue
188       render :nothing => true, :status => :internal_server_error
189     end
190   end
191
192   def api_data
193     render :action => 'data'
194   end
195
196   def api_create
197     do_create(params[:filename], params[:tags], params[:description], true) do |f|
198       f.write(request.raw_post)
199     end
200
201     if @trace.id
202       render :nothing => true
203     else
204       render :nothing => true, :status => :internal_server_error
205     end
206   end
207
208 private
209
210   def do_create(name, tags, description, public)
211     filename = "/tmp/#{rand}"
212
213     File.open(filename, "w") { |f| yield f }
214
215     @trace = Trace.new({:name => name, :tagstring => tags,
216                         :description => description, :public => public})
217     @trace.inserted = false
218     @trace.user = @user
219     @trace.timestamp = Time.now
220
221     if @trace.save
222       File.rename(filename, @trace.trace_name)
223     else
224       FileUtils.rm_f(filename)
225     end
226   end
227
228 end