Require current EULA version everywhere for logged in users.
[gitorious:taladars-gitorious-saltation.git] / app / controllers / application_controller.rb
1 #--
2 #   Copyright (C) 2007, 2008 Johan Sørensen <johan@johansorensen.com>
3 #
4 #   This program is free software: you can redistribute it and/or modify
5 #   it under the terms of the GNU Affero General Public License as published by
6 #   the Free Software Foundation, either version 3 of the License, or
7 #   (at your option) any later version.
8 #
9 #   This program is distributed in the hope that it will be useful,
10 #   but WITHOUT ANY WARRANTY; without even the implied warranty of
11 #   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 #   GNU Affero General Public License for more details.
13 #
14 #   You should have received a copy of the GNU Affero General Public License
15 #   along with this program.  If not, see <http://www.gnu.org/licenses/>.
16 #++
17
18 # Filters added to this controller apply to all controllers in the application.
19 # Likewise, all the methods added will be available for all controllers.
20
21 class ApplicationController < ActionController::Base
22   include AuthenticatedSystem
23   include ExceptionNotifiable
24   
25   before_filter :public_and_logged_in
26   before_filter :require_current_eula
27   
28   layout :pick_layout_based_on_site
29   
30   rescue_from ActiveRecord::RecordNotFound, :with => :render_not_found
31   rescue_from ActionController::UnknownController, :with => :render_not_found
32   rescue_from ActionController::UnknownAction, :with => :render_not_found
33   rescue_from Grit::GitRuby::Repository::NoSuchPath, :with => :render_not_found
34   rescue_from Grit::Git::GitTimeout, :with => :render_git_timeout
35   
36   def rescue_action(exception)
37     return super if RAILS_ENV != "production"
38     
39     case exception
40       # Can't catch RoutingError with rescue_from it seems, 
41       # so do it the old-fashioned way
42     when ActionController::RoutingError
43       render_not_found
44     else
45       super
46     end
47   end
48   
49   def current_site
50     @current_site || Site.default
51   end
52   
53   protected
54     # Sets the before_filters needed to be able to render in a Site specific
55     # context. +options+ is the options for the before_filters
56     def self.renders_in_site_specific_context(options = {})
57       before_filter :find_current_site, options
58       before_filter :redirect_to_current_site_subdomain, options
59     end
60     
61     # Sets the before_filters needed to make sure the requests are rendered
62     # in the "global" (eg without any Site specific layouts + subdomains).
63     # +options+ is the options for the before_filter
64     def self.renders_in_global_context(options = {})
65       before_filter :require_global_site_context, options
66     end
67   
68     # return the url with the +repo+.owner prefixed if it's a mainline repo,
69     # otherwise return the +path_spec+
70     # if +path_spec+ is an array (and no +args+ given) it'll use that as the 
71     # polymorphic-url-style (eg [@project, @repo, @foo])
72     def repo_owner_path(repo, path_spec, *args)
73       if repo.team_repo?
74         if path_spec.is_a?(Symbol)
75           return send("group_#{path_spec}", *args.unshift(repo.owner))
76         else
77           return *unshifted_polymorphic_path(repo, path_spec)
78         end
79       elsif repo.user_repo?
80         if path_spec.is_a?(Symbol)
81           return send("user_#{path_spec}", *args.unshift(repo.owner))
82         else
83           return *unshifted_polymorphic_path(repo, path_spec)
84         end
85       else
86         if path_spec.is_a?(Symbol)
87           return send(path_spec, *args)
88         else
89           return *path_spec
90         end
91       end
92     end
93     helper_method :repo_owner_path
94   
95     def require_user_has_ssh_keys
96       unless current_user.ssh_keys.count > 0
97         flash[:error] = I18n.t "application.require_ssh_keys_error"
98         redirect_to new_user_key_path(current_user)
99         return 
100       end
101     end
102
103     def require_current_user
104       unless @user == current_user
105         flash[:error] = I18n.t "application.require_current_user", :title => current_user.title
106         redirect_to user_path(current_user)
107         return
108       end
109     end
110     
111     def require_current_eula
112       if logged_in?
113         unless current_user.current_license_agreement_accepted?
114           store_location
115           flash[:error] = I18n.t "views.license.terms_not_accepted"
116           redirect_to user_license_path(current_user)
117           return
118         end
119       end
120       return true
121     end
122     
123     def find_repository_owner
124       if params[:project_id]
125         @owner = Project.find_by_slug!(params[:project_id])
126         @project = @owner
127       elsif params[:user_id]
128         @owner = User.find_by_login!(params[:user_id])
129       elsif params[:group_id]
130         @owner = Group.find_by_name!(params[:group_id])
131       else
132         raise ActiveRecord::RecordNotFound
133       end
134     end
135     
136     def find_repository_owner_and_repository
137       find_repository_owner
138       @owner.repositories.find_by_name!(params[:id])
139     end
140     
141     def find_project
142       @project = Project.find_by_slug!(params[:project_id])
143     end
144     
145     def find_project_and_repository
146       @project = Project.find_by_slug!(params[:project_id])
147       # We want to look in all repositories that's somehow within this project
148       # realm, not just @project.repositories
149       @repository = Repository.find_by_name_and_project_id!(params[:repository_id], @project.id)
150     end
151     
152     def check_repository_for_commits
153       unless @repository.has_commits?
154         flash[:notice] = I18n.t "application.no_commits_notice"
155         redirect_to project_repository_path(@project, @repository) and return
156       end
157     end
158     
159     def render_not_found
160       render :file => "#{RAILS_ROOT}/public/404.html", :status => 404
161     end
162     
163     def render_git_timeout
164       render :partial => "/projects/git_timeout", :layout => "application" and return
165     end
166     
167     def public_and_logged_in
168       login_required unless GitoriousConfig['public_mode']
169     end
170     
171     # turns ["foo", "bar"] route globbing parameters into "foo/bar"
172     def desplat_path(*paths)
173       paths.flatten.compact.map{|p| CGI.unescape(p) }.join("/")
174     end
175     helper_method :desplat_path
176     
177     # turns "foo/bar" into ["foo", "bar"] for route globbing
178     def ensplat_path(path)
179       path.split("/").select{|p| !p.blank? }
180     end
181     helper_method :ensplat_path
182     
183     # Returns an array like [branch_ref, *tree_path]
184     def branch_with_tree(branch_ref, tree_path)
185       tree_path = tree_path.is_a?(Array) ? tree_path : ensplat_path(tree_path)
186       ensplat_path(branch_ref) + tree_path
187     end
188     helper_method :branch_with_tree
189     
190     def branch_and_path(branch_and_path, git)
191       branch_and_path = desplat_path(branch_and_path)
192       branch_ref = path = nil
193       heads = Array(git.heads).map{|h| h.name }
194       heads.each do |head|
195         if branch_and_path.starts_with?(head)
196           branch_ref = head
197           path = ensplat_path(branch_and_path.sub(head, "")) || []
198         end
199       end
200       unless path # fallback
201         path = ensplat_path(branch_and_path)[1..-1]
202         branch_ref = ensplat_path(branch_and_path)[0]
203       end
204       [branch_ref, path]
205     end
206     
207     def find_current_site
208       @current_site ||= begin
209         if @project
210           @project.site
211         else
212           if !subdomain_without_common.blank?
213             Site.find_by_subdomain(subdomain_without_common)
214           end
215         end
216       end
217     end
218     
219     def pick_layout_based_on_site
220       if current_site && current_site.subdomain
221         current_site.subdomain
222       else
223         "application"
224       end
225     end
226     
227     def subdomain_without_common
228       tld_length = GitoriousConfig["gitorious_host"].split(".").length - 1
229       request.subdomains(tld_length).select{|s| s !~ /^(ww.|secure)$/}.first
230     end
231     
232     def redirect_to_current_site_subdomain
233       return unless request.get?
234       if !current_site.subdomain.blank?
235         if subdomain_without_common != current_site.subdomain
236           redirect_to(:only_path => false, 
237             :host => "#{current_site.subdomain}.#{request.domain}#{request.port_string}")
238         end
239       elsif !subdomain_without_common.blank?
240         redirect_to_top_domain
241       end
242     end
243     
244     def require_global_site_context
245       unless subdomain_without_common.blank?
246         redirect_to_top_domain
247       end
248     end
249     
250     def redirect_to_top_domain
251       host_without_subdomain = {
252         :only_path => false, 
253         :host => "#{request.domain}"
254       }
255       if ![80, 443].include?(request.port)
256         host_without_subdomain[:host] << ":#{request.port}"
257       end
258       redirect_to host_without_subdomain
259     end
260     
261   private  
262     def unshifted_polymorphic_path(repo, path_spec)
263       if path_spec[0].is_a?(Symbol)
264         path_spec.insert(1, repo.owner)
265       else
266         path_spec.unshift(repo.owner)
267       end
268     end
269 end