]> git.openstreetmap.org Git - rails.git/blob - app/controllers/trace_controller.rb
do wot john said innit - eagerly load tags in the map call for ways
[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   #  paging_action - the action that will be linked back to from view
9   def list (target_user = nil, paging_action = 'list')
10     @traces_per_page = 20
11     page_index = params[:page] ? params[:page].to_i - 1 : 0 # nice 1-based page -> 0-based page index
12
13     # from display name, pick up user id if one user's traces only
14     display_name = params[:display_name]
15     if target_user.nil? and display_name and display_name != ''
16       target_user = User.find(:first, :conditions => [ "display_name = ?", display_name])
17     end
18
19     opt = Hash.new
20     opt[:include] = [:user, :tags] # load users and tags from db at same time as traces
21
22     # four main cases:
23     # 1 - all traces, logged in = all public traces + all user's (i.e + all mine)
24     # 2 - all traces, not logged in = all public traces
25     # 3 - user's traces, logged in as same user = all user's traces 
26     # 4 - user's traces, not logged in as that user = all user's public traces
27     if target_user.nil? # all traces
28       if @user
29         conditions = ["(public = 1 OR user_id = ?)", @user.id] #1
30       else
31         conditions  = ["public = 1"] #2
32       end
33     else
34       if @user and @user.id == target_user.id
35         conditions = ["user_id = ?", @user.id] #3 (check vs user id, so no join + can't pick up non-public traces by changing name)
36       else
37         conditions = ["public = 1 AND user_id = ?", target_user.id] #4
38       end
39     end
40     conditions[0] += " AND users.display_name != ''" # users need to set display name before traces will be exposed
41     
42     opt[:order] = 'timestamp DESC'
43     if params[:tag]
44       @tag = params[:tag]
45       conditions[0] += " AND gpx_file_tags.tag = ?"
46       conditions << @tag;
47     end
48     
49     opt[:conditions] = conditions
50
51     # count traces using all options except limit
52     @max_trace = Trace.count(opt)
53     @max_page = Integer((@max_trace + 1) / @traces_per_page) 
54     
55     # last step before fetch - add paging options
56     opt[:limit] = @traces_per_page
57     if page_index > 0
58       opt[:offset] = @traces_per_page * page_index
59     end
60
61     @traces = Trace.find(:all , 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     @paging_action = paging_action # the action that paging requests should route back to, e.g. 'list' or 'mine'
78     @page = page_index + 1 # nice 1-based external page numbers
79   end
80
81   def mine
82     if @user
83       list(@user, 'mine') unless @user.nil?
84     else
85       redirect_to :controller => 'user', :action => 'login'
86     end
87   end
88
89   def view
90     @trace = Trace.find(params[:id])
91     unless @trace.public
92       if @user
93         render :nothing, :status => 401 if @trace.user.id != @user.id
94       end
95     end
96   end
97
98   def create
99     filename = "/tmp/#{rand}"
100
101     File.open(filename, "w") { |f| f.write(@params['trace']['gpx_file'].read) }
102     @params['trace']['name'] = @params['trace']['gpx_file'].original_filename.gsub(/[^a-zA-Z0-9.]/, '_') # This makes sure filenames are sane
103     @params['trace'].delete('gpx_file') # remove the field from the hash, because there's no such field in the DB
104     @trace = Trace.new(@params['trace'])
105     @trace.inserted = false
106     @trace.user = @user
107     @trace.timestamp = Time.now
108
109     if @trace.save
110       saved_filename = "/home/osm/gpx/#{@trace.id}.gpx"
111       File.rename(filename, saved_filename)
112
113       logger.info("id is #{@trace.id}")
114       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."
115       redirect_to :action => 'mine'
116     else
117       # fixme throw an error here
118        redirect_to :action => 'mine'
119        flash[:notice] = "You haven't entered a tag or a description for yoru traces."
120     end
121   end
122
123   def data
124     trace = Trace.find(params[:id])
125     if trace.public? or (@user and @user == trace.user)
126       send_data(File.open("/home/osm/gpx/#{trace.id}.gpx",'r').read , :filename => "#{trace.id}.gpx", :type => 'text/plain', :disposition => 'inline')
127     end
128   end
129
130   def make_public
131     trace = Trace.find(params[:id])
132     if @user and trace.user == @user and !trace.public
133       trace.public = true
134       trace.save
135       flash[:notice] = 'Track made public'
136       redirect_to :controller => 'trace', :action => 'view', :id => params[:id]
137     end
138   end
139
140   def georss
141     traces = Trace.find(:all, :conditions => ['public = true'], :order => 'timestamp DESC', :limit => 20)
142
143     rss = OSM::GeoRSS.new
144
145     #def add(latitude=0, longitude=0, title_text='dummy title', url='http://www.example.com/', description_text='dummy description', timestamp=Time.now)
146     traces.each do |trace|
147       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)
148     end
149
150     response.headers["Content-Type"] = 'application/xml+rss'
151
152     render :text => rss.to_s
153   end
154
155   def picture
156     trace = Trace.find(params[:id])
157     send_data(trace.large_picture, :filename => "#{trace.id}.gif", :type => 'image/gif', :disposition => 'inline') if trace.public? or (@user and @user == trace.user)
158   end
159
160   def icon
161     trace = Trace.find(params[:id])
162     send_data(trace.icon_picture, :filename => "#{trace.id}_icon.gif", :type => 'image/gif', :disposition => 'inline') if trace.public? or (@user and @user == trace.user)
163   end
164
165   def api_details
166     trace = Trace.find(params[:id])
167     doc = OSM::API.new.get_xml_doc
168     doc.root << trace.to_xml_node() if trace.public? or trace.user == @user
169     render :text => doc.to_s
170   end
171
172   def api_data
173     render :action => 'data'
174   end
175
176   def api_create
177     #FIXME merge this code with create as they're pretty similar?
178     
179     filename = "/tmp/#{rand}"
180     File.open(filename, "w") { |f| f.write(request.raw_post) }
181     @params['trace'] = {}
182     @params['trace']['name'] = params[:filename]
183     @params['trace']['tagstring'] = params[:tags]
184     @params['trace']['description'] = params[:description]
185     @trace = Trace.new(@params['trace'])
186     @trace.inserted = false
187     @trace.user = @user
188     @trace.timestamp = Time.now
189
190     if @trace.save
191       saved_filename = "/home/osm/gpx/#{@trace.id}.gpx"
192       File.rename(filename, saved_filename)
193       logger.info("id is #{@trace.id}")
194       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."
195       render :nothing => true
196     else
197       render :nothing => true, :status => 400 # er FIXME what fricking code to return?
198     end
199
200   end
201 end