Allow trace descriptions and tags to be edited.
[rails.git] / app / controllers / trace_controller.rb
index 94a7415f0de559022991f18bcec3d7a6535a513c..3eb7f5c7ece1eb0a247e2748c07117f06d79e409 100644 (file)
@@ -5,28 +5,24 @@ class TraceController < ApplicationController
  
   # 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
-  def list (target_user = nil)
+  def list(target_user = nil, action = "list")
     # 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.blank?
-      @display_name = display_name
       target_user = User.find(:first, :conditions => [ "display_name = ?", display_name])
     end
 
     # set title
     if target_user.nil?
-      @title = "public GPS traces"
-    elsif target_user.id == @user.id
-      @title = "your GPS traces"
+      @title = "Public GPS traces"
+    elsif @user and @user.id == target_user.id
+      @title = "Your GPS traces"
     else
-      @title = "public GPS traces from #{target_user.display_name}"
+      @title = "Public GPS traces from #{target_user.display_name}"
     end
 
     @title += " tagged with #{params[:tag]}" if params[:tag]
 
-    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
@@ -34,31 +30,32 @@ class TraceController < ApplicationController
     # 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
+        conditions = ["(gpx_files.public = 1 OR gpx_files.user_id = ?)", @user.id] #1
       else
-        conditions  = ["public = 1"] #2
+        conditions  = ["gpx_files.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)
+        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)
       else
-        conditions = ["public = 1 AND user_id = ?", target_user.id] #4
+        conditions = ["gpx_files.public = 1 AND gpx_files.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;
+      conditions[0] += " AND EXISTS (SELECT * FROM gpx_file_tags AS gft WHERE gft.gpx_id = gpx_files.id AND gft.tag = ?)"
+      conditions << @tag
     end
     
-    opt[:conditions] = conditions
-    opt[:per_page] = 20
+    conditions[0] += " AND gpx_files.visible = 1"
+
+    @trace_pages, @traces = paginate(:traces,
+                                     :include => [:user, :tags],
+                                     :conditions => conditions,
+                                     :order => "gpx_files.timestamp DESC",
+                                     :per_page => 20)
 
-    @trace_pages, @traces = paginate(:traces, opt)
-    
     # put together SET of tags across traces, for related links
     tagset = Hash.new
     if @traces
@@ -71,13 +68,14 @@ class TraceController < ApplicationController
     end
     
     # final helper vars for view
-    @display_name = display_name
+    @action = action
+    @display_name = target_user.display_name if target_user
     @all_tags = tagset.values
   end
 
   def mine
     if @user
-      list(@user) unless @user.nil?
+      list(@user, "mine") unless @user.nil?
     else
       redirect_to :controller => 'user', :action => 'login', :referer => request.request_uri
     end
@@ -85,10 +83,11 @@ class TraceController < ApplicationController
 
   def view
     @trace = Trace.find(params[:id])
-    unless @trace.public
-      if @user
-        render :nothing, :status => :forbidden if @trace.user.id != @user.id
-      end
+    @title = "Viewing trace #{@trace.name}"
+    if !@trace.visible?
+      render :nothing => true, :status => :not_found
+    elsif !@trace.public? and @trace.user.id != @user.id
+      render :nothing => true, :status => :forbidden
     end
   rescue ActiveRecord::RecordNotFound
     render :nothing => true, :status => :not_found
@@ -111,97 +110,170 @@ class TraceController < ApplicationController
 
   def data
     trace = Trace.find(params[:id])
-    if trace and (trace.public? or (@user and @user == trace.user))
+
+    if trace.visible? and (trace.public? or (@user and @user == trace.user))
       send_file(trace.trace_name, :filename => "#{trace.id}#{trace.extension_name}", :type => trace.mime_type, :disposition => 'attachment')
     else
       render :nothing, :status => :not_found
     end
+  rescue ActiveRecord::RecordNotFound
+    render :nothing => true, :status => :not_found
+  end
+
+  def edit
+    @trace = Trace.find(params[:id])
+
+    if @user and @trace.user == @user
+      if params[:trace]
+        @trace.description = params[:trace][:description]
+        @trace.tagstring = params[:trace][:tagstring]
+        if @trace.save
+          redirect_to :action => 'view'
+        end        
+      end
+    else
+      render :nothing, :status => :forbidden
+    end
+  rescue ActiveRecord::RecordNotFound
+    render :nothing => true, :status => :not_found
+  end
+
+  def delete
+    trace = Trace.find(params[:id])
+
+    if @user and trace.user == @user
+      if request.post? and trace.visible?
+        trace.visible = false
+        trace.save
+        flash[:notice] = 'Track scheduled for deletion'
+        redirect_to :controller => 'traces', :action => 'mine'
+      else
+        render :nothing, :status => :bad_request
+      end
+    else
+      render :nothing, :status => :forbidden
+    end
+  rescue ActiveRecord::RecordNotFound
+    render :nothing => true, :status => :not_found
   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]
+
+    if @user and trace.user == @user
+      if request.post? and !trace.public?
+        trace.public = true
+        trace.save
+        flash[:notice] = 'Track made public'
+        redirect_to :controller => 'trace', :action => 'view', :id => params[:id]
+      else
+        render :nothing, :status => :bad_request
+      end
+    else
+      render :nothing, :status => :forbidden
     end
+  rescue ActiveRecord::RecordNotFound
+    render :nothing => true, :status => :not_found
   end
 
   def georss
-    traces = Trace.find(:all, :conditions => ['public = true'], :order => 'timestamp DESC', :limit => 20)
+    conditions = ["gpx_files.public = 1"]
+
+    if params[:display_name]
+      conditions[0] += " AND users.display_name = ?"
+      conditions << params[:display_name]
+    end
+    
+    if params[:tag]
+      conditions[0] += " AND EXISTS (SELECT * FROM gpx_file_tags AS gft WHERE gft.gpx_id = gpx_files.id AND gft.tag = ?)"
+      conditions << params[:tag]
+    end
+
+    traces = Trace.find(:all, :include => :user, :conditions => conditions, 
+                        :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)
+      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)
     end
 
     render :text => rss.to_s, :content_type => "application/rss+xml"
   end
 
   def picture
-    begin
-      trace = Trace.find(params[:id])
+    trace = Trace.find(params[:id])
 
+    if trace.inserted?
       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
+    else
       render :nothing => true, :status => :not_found
-    rescue
-      render :nothing => true, :status => :internal_server_error
     end
+  rescue ActiveRecord::RecordNotFound
+    render :nothing => true, :status => :not_found
   end
 
   def icon
-    begin
-      trace = Trace.find(params[:id])
+    trace = Trace.find(params[:id])
 
+    if trace.inserted?
       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
+    else
       render :nothing => true, :status => :not_found
-    rescue
-      render :nothing => true, :status => :internal_server_error
     end
+  rescue ActiveRecord::RecordNotFound
+    render :nothing => true, :status => :not_found
   end
 
   def api_details
-    begin
-      trace = Trace.find(params[:id])
+    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
+    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
   end
 
   def api_data
-    render :action => 'data'
+    trace = Trace.find(params[:id])
+
+    if trace.public? or trace.user == @user
+      send_file(trace.trace_name, :filename => "#{trace.id}#{trace.extension_name}", :type => trace.mime_type, :disposition => 'attachment')
+    else
+      render :nothing => true, :status => :forbidden
+    end
+  rescue ActiveRecord::RecordNotFound
+    render :nothing => true, :status => :not_found
   end
 
   def api_create
-    do_create(params[:filename], params[:tags], params[:description], true) do |f|
-      f.write(request.raw_post)
-    end
+    if request.post?
+      name = params[:file].original_filename.gsub(/[^a-zA-Z0-9.]/, '_') # This makes sure filenames are sane
 
-    if @trace.id
-      render :nothing => true
+      do_create(name, params[:tags], params[:description], params[:public]) do |f|
+        f.write(params[:file].read)
+      end
+
+      if @trace.id
+        render :text => @trace.id.to_s, :content_type => "text/plain"
+      elsif @trace.valid?
+        render :nothing => true, :status => :internal_server_error
+      else
+        render :nothing => true, :status => :bad_request
+      end
     else
-      render :nothing => true, :status => :internal_server_error
+      render :nothing => true, :status => :method_not_allowed
     end
   end