source: subversion/sites/rails_port/app/controllers/trace_controller.rb @ 6792

Revision 6792, 10.2 KB checked in by tomhughes, 6 years ago (diff)

Use FileUtils?.mv instead of File.rename as it will do a copy+delete when
the source and target are not on the same filesystem. Closes #670.

Line 
1class 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, action = "list")
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      target_user = User.find(:first, :conditions => [ "display_name = ?", display_name])
13    end
14
15    # set title
16    if target_user.nil?
17      @title = "Public GPS traces"
18    elsif @user and @user.id == target_user.id
19      @title = "Your GPS traces"
20    else
21      @title = "Public GPS traces from #{target_user.display_name}"
22    end
23
24    @title += " tagged with #{params[:tag]}" if params[:tag]
25
26    # four main cases:
27    # 1 - all traces, logged in = all public traces + all user's (i.e + all mine)
28    # 2 - all traces, not logged in = all public traces
29    # 3 - user's traces, logged in as same user = all user's traces
30    # 4 - user's traces, not logged in as that user = all user's public traces
31    if target_user.nil? # all traces
32      if @user
33        conditions = ["(gpx_files.public = 1 OR gpx_files.user_id = ?)", @user.id] #1
34      else
35        conditions  = ["gpx_files.public = 1"] #2
36      end
37    else
38      if @user and @user.id == target_user.id
39        conditions = ["gpx_files.user_id = ?", @user.id] #3 (check vs user id, so no join + can't pick up non-public traces by changing name)
40      else
41        conditions = ["gpx_files.public = 1 AND gpx_files.user_id = ?", target_user.id] #4
42      end
43    end
44   
45    if params[:tag]
46      @tag = params[:tag]
47      conditions[0] += " AND EXISTS (SELECT * FROM gpx_file_tags AS gft WHERE gft.gpx_id = gpx_files.id AND gft.tag = ?)"
48      conditions << @tag
49    end
50   
51    conditions[0] += " AND gpx_files.visible = 1"
52
53    @trace_pages, @traces = paginate(:traces,
54                                     :include => [:user, :tags],
55                                     :conditions => conditions,
56                                     :order => "gpx_files.timestamp DESC",
57                                     :per_page => 20)
58
59    # put together SET of tags across traces, for related links
60    tagset = Hash.new
61    if @traces
62      @traces.each do |trace|
63        trace.tags.reload if params[:tag] # if searched by tag, ActiveRecord won't bring back other tags, so do explicitly here
64        trace.tags.each do |tag|
65          tagset[tag.tag] = tag.tag
66        end
67      end
68    end
69   
70    # final helper vars for view
71    @action = action
72    @display_name = target_user.display_name if target_user
73    @all_tags = tagset.values
74  end
75
76  def mine
77    if @user
78      list(@user, "mine") unless @user.nil?
79    else
80      redirect_to :controller => 'user', :action => 'login', :referer => request.request_uri
81    end
82  end
83
84  def view
85    @trace = Trace.find(params[:id])
86    @title = "Viewing trace #{@trace.name}"
87    if !@trace.visible?
88      render :nothing => true, :status => :not_found
89    elsif !@trace.public? and @trace.user.id != @user.id
90      render :nothing => true, :status => :forbidden
91    end
92  rescue ActiveRecord::RecordNotFound
93    render :nothing => true, :status => :not_found
94  end
95
96  def create
97    logger.info(params[:trace][:gpx_file].class.name)
98    if params[:trace][:gpx_file].respond_to?(:read)
99      do_create(params[:trace][:gpx_file], params[:trace][:tagstring],
100                params[:trace][:description], params[:trace][:public])
101
102      if @trace.id
103        logger.info("id is #{@trace.id}")
104        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."
105
106        redirect_to :action => 'mine'
107      end
108    else
109      @trace = Trace.new({:name => "Dummy",
110                          :tagstring => params[:trace][:tagstring],
111                          :description => params[:trace][:description],
112                          :public => params[:trace][:public],
113                          :inserted => false, :user => @user,
114                          :timestamp => Time.now})
115      @trace.valid?
116      @trace.errors.add(:gpx_file, "can't be blank")
117    end
118  end
119
120  def data
121    trace = Trace.find(params[:id])
122
123    if trace.visible? and (trace.public? or (@user and @user == trace.user))
124      if request.format == Mime::XML
125        send_file(trace.xml_file, :filename => "#{trace.id}.xml", :type => Mime::XML.to_s, :disposition => 'attachment')
126      else
127        send_file(trace.trace_name, :filename => "#{trace.id}#{trace.extension_name}", :type => trace.mime_type, :disposition => 'attachment')
128      end
129    else
130      render :nothing, :status => :not_found
131    end
132  rescue ActiveRecord::RecordNotFound
133    render :nothing => true, :status => :not_found
134  end
135
136  def edit
137    @trace = Trace.find(params[:id])
138
139    if @user and @trace.user == @user
140      if params[:trace]
141        @trace.description = params[:trace][:description]
142        @trace.tagstring = params[:trace][:tagstring]
143        if @trace.save
144          redirect_to :action => 'view'
145        end       
146      end
147    else
148      render :nothing, :status => :forbidden
149    end
150  rescue ActiveRecord::RecordNotFound
151    render :nothing => true, :status => :not_found
152  end
153
154  def delete
155    trace = Trace.find(params[:id])
156
157    if @user and trace.user == @user
158      if request.post? and trace.visible?
159        trace.visible = false
160        trace.save
161        flash[:notice] = 'Track scheduled for deletion'
162        redirect_to :controller => 'traces', :action => 'mine'
163      else
164        render :nothing, :status => :bad_request
165      end
166    else
167      render :nothing, :status => :forbidden
168    end
169  rescue ActiveRecord::RecordNotFound
170    render :nothing => true, :status => :not_found
171  end
172
173  def make_public
174    trace = Trace.find(params[:id])
175
176    if @user and trace.user == @user
177      if request.post? and !trace.public?
178        trace.public = true
179        trace.save
180        flash[:notice] = 'Track made public'
181        redirect_to :controller => 'trace', :action => 'view', :id => params[:id]
182      else
183        render :nothing, :status => :bad_request
184      end
185    else
186      render :nothing, :status => :forbidden
187    end
188  rescue ActiveRecord::RecordNotFound
189    render :nothing => true, :status => :not_found
190  end
191
192  def georss
193    conditions = ["gpx_files.public = 1"]
194
195    if params[:display_name]
196      conditions[0] += " AND users.display_name = ?"
197      conditions << params[:display_name]
198    end
199   
200    if params[:tag]
201      conditions[0] += " AND EXISTS (SELECT * FROM gpx_file_tags AS gft WHERE gft.gpx_id = gpx_files.id AND gft.tag = ?)"
202      conditions << params[:tag]
203    end
204
205    traces = Trace.find(:all, :include => :user, :conditions => conditions, 
206                        :order => "timestamp DESC", :limit => 20)
207
208    rss = OSM::GeoRSS.new
209
210    traces.each do |trace|
211      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)
212    end
213
214    render :text => rss.to_s, :content_type => "application/rss+xml"
215  end
216
217  def picture
218    trace = Trace.find(params[:id])
219
220    if trace.inserted?
221      if trace.public? or (@user and @user == trace.user)
222        send_file(trace.large_picture_name, :filename => "#{trace.id}.gif", :type => 'image/gif', :disposition => 'inline')
223      else
224        render :nothing, :status => :forbidden
225      end
226    else
227      render :nothing => true, :status => :not_found
228    end
229  rescue ActiveRecord::RecordNotFound
230    render :nothing => true, :status => :not_found
231  end
232
233  def icon
234    trace = Trace.find(params[:id])
235
236    if trace.inserted?
237      if trace.public? or (@user and @user == trace.user)
238        send_file(trace.icon_picture_name, :filename => "#{trace.id}_icon.gif", :type => 'image/gif', :disposition => 'inline')
239      else
240        render :nothing, :status => :forbidden
241      end
242    else
243      render :nothing => true, :status => :not_found
244    end
245  rescue ActiveRecord::RecordNotFound
246    render :nothing => true, :status => :not_found
247  end
248
249  def api_details
250    trace = Trace.find(params[:id])
251
252    if trace.public? or trace.user == @user
253      render :text => trace.to_xml.to_s, :content_type => "text/xml"
254    else
255      render :nothing => true, :status => :forbidden
256    end
257  rescue ActiveRecord::RecordNotFound
258    render :nothing => true, :status => :not_found
259  end
260
261  def api_data
262    trace = Trace.find(params[:id])
263
264    if trace.public? or trace.user == @user
265      send_file(trace.trace_name, :filename => "#{trace.id}#{trace.extension_name}", :type => trace.mime_type, :disposition => 'attachment')
266    else
267      render :nothing => true, :status => :forbidden
268    end
269  rescue ActiveRecord::RecordNotFound
270    render :nothing => true, :status => :not_found
271  end
272
273  def api_create
274    if request.post?
275      do_create(params[:file], params[:tags], params[:description], params[:public])
276
277      if @trace.id
278        render :text => @trace.id.to_s, :content_type => "text/plain"
279      elsif @trace.valid?
280        render :nothing => true, :status => :internal_server_error
281      else
282        render :nothing => true, :status => :bad_request
283      end
284    else
285      render :nothing => true, :status => :method_not_allowed
286    end
287  end
288
289private
290
291  def do_create(file, tags, description, public)
292    name = file.original_filename.gsub(/[^a-zA-Z0-9.]/, '_')
293    filename = "/tmp/#{rand}"
294
295    File.open(filename, "w") { |f| f.write(file.read) }
296
297    @trace = Trace.new({:name => name, :tagstring => tags,
298                        :description => description, :public => public})
299    @trace.inserted = false
300    @trace.user = @user
301    @trace.timestamp = Time.now
302
303    if @trace.save
304      FileUtils.mv(filename, @trace.trace_name)
305    else
306      FileUtils.rm_f(filename)
307    end
308  end
309
310end
Note: See TracBrowser for help on using the repository browser.