]> git.openstreetmap.org Git - rails.git/blob - app/controllers/traces_controller.rb
Merge remote-tracking branch 'upstream/pull/4426'
[rails.git] / app / controllers / traces_controller.rb
1 class TracesController < ApplicationController
2   include UserMethods
3
4   layout "site", :except => :georss
5
6   before_action :authorize_web
7   before_action :set_locale
8   before_action :check_database_readable
9
10   authorize_resource
11
12   before_action :check_database_writable, :only => [:new, :create, :edit, :destroy]
13   before_action :offline_warning, :only => [:mine, :show]
14   before_action :offline_redirect, :only => [:new, :create, :edit, :destroy, :data]
15
16   # Counts and selects pages of GPX traces for various criteria (by user, tags, public etc.).
17   #  target_user - if set, specifies the user to fetch traces for.  if not set will fetch all traces
18   def index
19     # from display name, pick up user id if one user's traces only
20     display_name = params[:display_name]
21     if display_name.present?
22       target_user = User.active.find_by(:display_name => display_name)
23       if target_user.nil?
24         render_unknown_user display_name
25         return
26       end
27     end
28
29     # set title
30     @title = if target_user.nil?
31                t ".public_traces"
32              elsif current_user && current_user == target_user
33                t ".my_gps_traces"
34              else
35                t ".public_traces_from", :user => target_user.display_name
36              end
37
38     @title += t ".tagged_with", :tags => params[:tag] if params[:tag]
39
40     # four main cases:
41     # 1 - all traces, logged in = all public traces + all user's (i.e + all mine)
42     # 2 - all traces, not logged in = all public traces
43     # 3 - user's traces, logged in as same user = all user's traces
44     # 4 - user's traces, not logged in as that user = all user's public traces
45     traces = if target_user.nil? # all traces
46                if current_user
47                  Trace.visible_to(current_user) # 1
48                else
49                  Trace.visible_to_all # 2
50                end
51              elsif current_user && current_user == target_user
52                current_user.traces # 3 (check vs user id, so no join + can't pick up non-public traces by changing name)
53              else
54                target_user.traces.visible_to_all # 4
55              end
56
57     traces = traces.tagged(params[:tag]) if params[:tag]
58
59     traces = traces.visible
60
61     @params = params.permit(:display_name, :tag, :before, :after)
62
63     @traces = if params[:before]
64                 traces.where("gpx_files.id < ?", params[:before]).order(:id => :desc)
65               elsif params[:after]
66                 traces.where("gpx_files.id > ?", params[:after]).order(:id => :asc)
67               else
68                 traces.order(:id => :desc)
69               end
70
71     @traces = @traces.limit(20)
72     @traces = @traces.includes(:user, :tags)
73     @traces = @traces.sort.reverse
74
75     @newer_traces = @traces.count.positive? && traces.exists?(["gpx_files.id > ?", @traces.first.id])
76     @older_traces = @traces.count.positive? && traces.exists?(["gpx_files.id < ?", @traces.last.id])
77
78     # final helper vars for view
79     @target_user = target_user
80   end
81
82   def show
83     @trace = Trace.find(params[:id])
84
85     if @trace&.visible? &&
86        (@trace&.public? || @trace&.user == current_user)
87       @title = t ".title", :name => @trace.name
88     else
89       flash[:error] = t ".trace_not_found"
90       redirect_to :action => "index"
91     end
92   rescue ActiveRecord::RecordNotFound
93     flash[:error] = t ".trace_not_found"
94     redirect_to :action => "index"
95   end
96
97   def new
98     @title = t ".upload_trace"
99     @trace = Trace.new(:visibility => default_visibility)
100   end
101
102   def edit
103     @trace = Trace.find(params[:id])
104
105     if !@trace.visible?
106       head :not_found
107     elsif current_user.nil? || @trace.user != current_user
108       head :forbidden
109     else
110       @title = t ".title", :name => @trace.name
111     end
112   rescue ActiveRecord::RecordNotFound
113     head :not_found
114   end
115
116   def create
117     @title = t ".upload_trace"
118
119     logger.info(params[:trace][:gpx_file].class.name)
120
121     if params[:trace][:gpx_file].respond_to?(:read)
122       @trace = do_create(params[:trace][:gpx_file], params[:trace][:tagstring],
123                          params[:trace][:description], params[:trace][:visibility])
124
125       if @trace.id
126         flash[:notice] = t ".trace_uploaded"
127         flash[:warning] = t ".traces_waiting", :count => current_user.traces.where(:inserted => false).count if current_user.traces.where(:inserted => false).count > 4
128
129         TraceImporterJob.perform_later(@trace)
130         redirect_to :action => :index, :display_name => current_user.display_name
131       else
132         flash[:error] = t(".upload_failed") if @trace.valid?
133
134         render :action => "new"
135       end
136     else
137       @trace = Trace.new(:name => "Dummy",
138                          :tagstring => params[:trace][:tagstring],
139                          :description => params[:trace][:description],
140                          :visibility => params[:trace][:visibility],
141                          :inserted => false, :user => current_user,
142                          :timestamp => Time.now.utc)
143       @trace.valid?
144       @trace.errors.add(:gpx_file, "can't be blank")
145
146       render :action => "new"
147     end
148   end
149
150   def update
151     @trace = Trace.find(params[:id])
152
153     if !@trace.visible?
154       head :not_found
155     elsif current_user.nil? || @trace.user != current_user
156       head :forbidden
157     elsif @trace.update(trace_params)
158       flash[:notice] = t ".updated"
159       redirect_to :action => "show", :display_name => current_user.display_name
160     else
161       @title = t ".title", :name => @trace.name
162       render :action => "edit"
163     end
164   rescue ActiveRecord::RecordNotFound
165     head :not_found
166   end
167
168   def destroy
169     trace = Trace.find(params[:id])
170
171     if !trace.visible?
172       head :not_found
173     elsif current_user.nil? || (trace.user != current_user && !current_user.administrator? && !current_user.moderator?)
174       head :forbidden
175     else
176       trace.visible = false
177       trace.save
178       flash[:notice] = t ".scheduled_for_deletion"
179       TraceDestroyerJob.perform_later(trace)
180       redirect_to :action => :index, :display_name => trace.user.display_name
181     end
182   rescue ActiveRecord::RecordNotFound
183     head :not_found
184   end
185
186   def mine
187     redirect_to :action => :index, :display_name => current_user.display_name
188   end
189
190   def data
191     trace = Trace.find(params[:id])
192
193     if trace.visible? && (trace.public? || (current_user && current_user == trace.user))
194       if Acl.no_trace_download(request.remote_ip)
195         head :forbidden
196       elsif request.format == Mime[:xml]
197         send_data(trace.xml_file.read, :filename => "#{trace.id}.xml", :type => request.format.to_s, :disposition => "attachment")
198       elsif request.format == Mime[:gpx]
199         send_data(trace.xml_file.read, :filename => "#{trace.id}.gpx", :type => request.format.to_s, :disposition => "attachment")
200       elsif trace.file.attached?
201         redirect_to rails_blob_path(trace.file, :disposition => "attachment")
202       else
203         send_file(trace.trace_name, :filename => "#{trace.id}#{trace.extension_name}", :type => trace.mime_type, :disposition => "attachment")
204       end
205     else
206       head :not_found
207     end
208   rescue ActiveRecord::RecordNotFound
209     head :not_found
210   end
211
212   def georss
213     @traces = Trace.visible_to_all.visible
214
215     @traces = @traces.joins(:user).where(:users => { :display_name => params[:display_name] }) if params[:display_name]
216
217     @traces = @traces.tagged(params[:tag]) if params[:tag]
218     @traces = @traces.order("timestamp DESC")
219     @traces = @traces.limit(20)
220     @traces = @traces.includes(:user)
221   end
222
223   def picture
224     trace = Trace.find(params[:id])
225
226     if trace.visible? && trace.inserted?
227       if trace.public? || (current_user && current_user == trace.user)
228         if trace.icon.attached?
229           redirect_to rails_blob_path(trace.image, :disposition => "inline")
230         else
231           expires_in 7.days, :private => !trace.public?, :public => trace.public?
232           send_file(trace.large_picture_name, :filename => "#{trace.id}.gif", :type => "image/gif", :disposition => "inline")
233         end
234       else
235         head :forbidden
236       end
237     else
238       head :not_found
239     end
240   rescue ActiveRecord::RecordNotFound
241     head :not_found
242   end
243
244   def icon
245     trace = Trace.find(params[:id])
246
247     if trace.visible? && trace.inserted?
248       if trace.public? || (current_user && current_user == trace.user)
249         if trace.icon.attached?
250           redirect_to rails_blob_path(trace.icon, :disposition => "inline")
251         else
252           expires_in 7.days, :private => !trace.public?, :public => trace.public?
253           send_file(trace.icon_picture_name, :filename => "#{trace.id}_icon.gif", :type => "image/gif", :disposition => "inline")
254         end
255       else
256         head :forbidden
257       end
258     else
259       head :not_found
260     end
261   rescue ActiveRecord::RecordNotFound
262     head :not_found
263   end
264
265   private
266
267   def do_create(file, tags, description, visibility)
268     # Sanitise the user's filename
269     name = file.original_filename.gsub(/[^a-zA-Z0-9.]/, "_")
270
271     # Create the trace object
272     trace = Trace.new(
273       :name => name,
274       :tagstring => tags,
275       :description => description,
276       :visibility => visibility,
277       :inserted => false,
278       :user => current_user,
279       :timestamp => Time.now.utc,
280       :file => file
281     )
282
283     # Save the trace object
284     if trace.save
285       # Finally save the user's preferred privacy level
286       if pref = current_user.preferences.find_by(:k => "gps.trace.visibility")
287         pref.v = visibility
288         pref.save
289       else
290         current_user.preferences.create(:k => "gps.trace.visibility", :v => visibility)
291       end
292     end
293
294     trace
295   end
296
297   def offline_warning
298     flash.now[:warning] = t "traces.offline_warning.message" if Settings.status == "gpx_offline"
299   end
300
301   def offline_redirect
302     render :action => :offline if Settings.status == "gpx_offline"
303   end
304
305   def default_visibility
306     visibility = current_user.preferences.find_by(:k => "gps.trace.visibility")
307
308     if visibility
309       visibility.v
310     elsif current_user.preferences.find_by(:k => "gps.trace.public", :v => "default").nil?
311       "private"
312     else
313       "public"
314     end
315   end
316
317   def trace_params
318     params.require(:trace).permit(:description, :tagstring, :visibility)
319   end
320 end