merged cont.
[opensuse:yast-rest-service.git] / webservice / app / controllers / application_controller.rb
1 #--
2 # Webyast Webservice framework
3 #
4 # Copyright (C) 2009, 2010 Novell, Inc. 
5 #   This library is free software; you can redistribute it and/or modify
6 # it only under the terms of version 2.1 of the GNU Lesser General Public
7 # License as published by the Free Software Foundation. 
8 #
9 #   This library is distributed in the hope that it will be useful, but WITHOUT
10 # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11 # FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more 
12 # details. 
13 #
14 #   You should have received a copy of the GNU Lesser General Public
15 # License along with this library; if not, write to the Free Software 
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17 #++
18
19 # Filters added to this controller apply to all controllers in the application.
20 # Likewise, all the methods added will be available for all controllers.
21
22 require 'exceptions'
23 require 'gettext_rails'
24 require 'dbus'
25
26 class ApplicationController < ActionController::Base
27   layout 'main'  
28
29   #render only pure text to simple show it on frontend
30   rescue_from Exception, :with => :report_exception
31
32   rescue_from BackendException, :with => :report_backend_exception
33
34   rescue_from NoPermissionException do |exception|
35     logger.info "No permission: #{exception.permission} for #{exception.user}"
36     render :xml => exception, :status => 403 #403-forbidden
37   end
38
39   rescue_from InvalidParameters do |exception|
40     logger.info "Raised resource Invalid exception - #{exception.inspect}"
41     render :xml => exception, :status => 422 #422-resource invalid
42   end
43
44   rescue_from DBus::Error do |exception|
45     logger.info "Raised DBus::Error exception - #{exception.message}"
46     logger.info "#{exception.inspect}"
47     report_backend_exception DBusException.new(exception.message)
48   end
49
50 #lazy load of YaST::Config library
51   rescue_from "YaST::ConfigFile::NotFoundError" do |exception|
52     #catch uncaught exception from reading yaml and report as
53     #Backend problem
54     logger.warn "Uncaught ConfigFile::NotFound exception. Reported as CorruptedFile"
55     report_backend_exception CorruptedFileException.new(exception.path)
56
57   end
58
59   include AuthenticatedSystem
60
61   include YastRoles
62
63   helper :all # include all helpers, all the time
64
65   # See ActionController::RequestForgeryProtection for details
66   # Uncomment the :secret if you're not using the cookie session store
67   # protect_from_forgery # :secret => 'b8ebfaf489f039bccb691367daf9da63'
68
69   # See ActionController::Base for details
70   # Uncomment this to filter the contents of submitted sensitive data parameters
71   # from your application log (in this case, all fields with names like "password").
72   filter_parameter_logging :password # RORSCAN_ITL
73   before_filter :init_cache
74
75   private
76
77   def init_cache
78     return unless (logged_in? && YastCache.active) #Does not make sense if no session id is available or
79                                                    #cache is not active
80     if request && request.request_method == :get
81       return unless (request.parameters["action"] == "show" || 
82                      request.parameters["action"] == "index")
83       #finding the correct cache name 
84       #(has to be the model class name and not the controller name)
85       path = YastCache.find_key(request.parameters["controller"], (request.parameters["id"] || :all))
86       if path.blank?
87         logger.info("Cache for model #{path} not found")
88         return
89       end
90       path.downcase!
91       data_cache = DataCache.find_by_path_and_session(path, self.current_account.remember_token)
92       found = false
93       data_cache.each { |cache|
94         found = true
95         if cache.picked_md5 != cache.refreshed_md5
96           cache.picked_md5 = cache.refreshed_md5
97           cache.save
98         end
99       } unless data_cache.blank?
100       DataCache.create(:path => path, :session => self.current_account.remember_token,
101                        :picked_md5 => nil, :refreshed_md5 => nil) unless found
102     end
103   end
104
105   def report_backend_exception(exception) 
106       logger.info "Backend exception: #{exception}"
107       render :xml => exception, :status => 503
108   end
109
110   def report_exception(exception)
111     def exception.to_xml
112       xml = Builder::XmlMarkup.new({})
113       xml.instruct!
114
115       xml.error do
116         xml.type "GENERIC"
117         xml.description exception.message
118         xml.tag!(:bug,true,:type=> "boolean")
119         xml.backtrace(:type => "array") do
120           exception.backtrace.each do |b|
121             xml.line b
122           end
123         end
124       end
125     end
126     logger.warn "Uncaught exception #{exception.class}: #{exception.message} \n Backtrace: #{exception.backtrace.join('\n')}"
127       
128     render :xml => exception, :status => 503
129     
130   end
131
132 protected
133
134   def ensure_login
135     unless logged_in?
136       flash[:notice] = _("Please login to continue")
137       redirect_to :controller => "session", :action => "new", :hostid => "localhost" #redirect by default to locahost appliance (bnc#602807)
138     end
139   end
140
141   def ensure_logout
142     if logged_in?
143       flash[:notice] = _("You must logout before you can login")
144       redirect_to root_url
145     end
146   end
147
148   def self.init_gettext(domainname, options = {})
149     locale_path = options[:locale_path]
150     unless locale_path
151       #If path of the translation has not been set we are trying to load
152       #vendor specific translations too
153       if Dir.glob(File.join("**", "public", "**", "#{domainname}.mo")).size > 0
154         vendor_text_path = "public/vendor/text/locale"
155         locale_path = File.join(RAILS_ROOT, vendor_text_path)
156         opt = {:locale_path => locale_path}.merge(options)
157         logger.info "Loading textdomain #{domainname} from #{vendor_text_path}"
158         ActionController::Base.init_gettext(domainname, opt)
159       else
160         #load default no vendor translation available
161         locale_path = ""
162         #searching in RAILS_ROOT
163         mo_files = Dir.glob(File.join(RAILS_ROOT, "**", "#{domainname}.mo"))
164         if mo_files.size > 0
165           locale_path = File.dirname(File.dirname(File.dirname(mo_files.first)))
166         else
167           # trying plugin directory in the git 
168           mo_files = Dir.glob(File.join(RAILS_ROOT, "..", "**", "#{domainname}.mo"))
169           locale_path = File.dirname(File.dirname(File.dirname(mo_files.first))) if mo_files.size > 0
170         end
171         unless locale_path.blank?
172           logger.info "Loading standard textdomain #{domainname} from #{locale_path}"
173           opt = {:locale_path => locale_path}.merge(options)
174           ActionController::Base.init_gettext(domainname, opt)
175         else
176           logger.error "Cannot find translation for #{domainname}"
177         end
178       end
179     else
180       #load default if the path has been given
181       logger.info "Loading textdomain #{domainname} from #{locale_path}"
182       ActionController::Base.init_gettext(domainname, options)
183     end
184   end
185
186
187
188   # Initialize GetText and Content-Type.
189   # You need to call this once a request from WWW browser.
190   # You can select the scope of the textdomain.
191   # 1. If you call init_gettext in ApplicationControler,
192   #    The textdomain apply whole your application.
193   # 2. If you call init_gettext in each controllers
194   #    (In this sample, blog_controller.rb is applicable)
195   #    The textdomains are applied to each controllers/views.
196   init_gettext "webyast-base"  # textdomain, options(:charset, :content_type)
197   I18n.supported_locales = Dir[ File.join(RAILS_ROOT, 'locale/*') ].collect{|v| File.basename(v)}
198
199 =begin
200   # You can set callback methods. These methods are called on the each WWW request.
201   def before_init_gettext(cgi)
202     p "before_init_gettext"
203   end
204   def after_init_gettext(cgi)
205     p "after_init_gettext"
206   end
207 =end
208
209
210 =begin
211   # you can redefined the title/explanation of the top of the error message.
212   ActionView::Helpers::ActiveRecordHelper::L10n.set_error_message_title(N_("An error is occured on %{record}"), N_("%{num} errors are occured on %{record}"))
213   ActionView::Helpers::ActiveRecordHelper::L10n.set_error_message_explanation(N_("The error is:"), N_("The errors are:"))
214 =end
215   # See ActionController::RequestForgeryProtection for details
216   # Uncomment the :secret if you're not using the cookie session store
217   protect_from_forgery # :secret => 'b1aeb693a1ee49ab70c6b6bf514963a3' RORSCAN_ITL
218
219   # See ActionController::Base for details
220   # Uncomment this to filter the contents of submitted sensitive data parameters
221   # from your application log (in this case, all fields with names like "password").
222   filter_parameter_logging :password # RORSCAN_ITL
223
224   # Translation mapping for ActiveResource validation errors
225   def error_mapping
226     # TODO: is it complete?
227     # ActiveRecord::Errors.default_error_messages defines more messages
228     # but it seems that they cannot be used with YaST model...
229     {
230       :blank => _("can't be blank"),
231       :inclusion => _("is out of allowed values"),
232       :empty => _("can't be empty"),
233       :invalid => _("is invalid")
234     }
235   end
236
237
238 end