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