| 97 | | @section = @node.section |
|---|
| 98 | | @date ||= params[:date] ? parse_date(params[:date]) : Time.now |
|---|
| 99 | | render :file => template_url(opts), :layout=>false |
|---|
| 100 | | |
|---|
| 101 | | cache_page if opts[:cache] |
|---|
| 102 | | end |
|---|
| 103 | | |
|---|
| 104 | | # Cache page content into a static file in the current sites directory : SITES_ROOT/test.host/public |
|---|
| 105 | | def cache_page(opts={}) |
|---|
| 106 | | return unless perform_caching && caching_allowed |
|---|
| 107 | | opts = {:expire_after => nil, |
|---|
| 108 | | :path => (visitor.site.public_path + page_cache_file), |
|---|
| 109 | | :content_data => response.body |
|---|
| 110 | | }.merge(opts) |
|---|
| 111 | | secure(CachedPage) { CachedPage.create(opts) } |
|---|
| 112 | | end |
|---|
| 113 | | |
|---|
| 114 | | # Return true if we can cache the current page |
|---|
| 115 | | def caching_allowed |
|---|
| 116 | | visitor.is_anon? |
|---|
| 117 | | end |
|---|
| 118 | | |
|---|
| 119 | | # Cache file path that reflects the called url |
|---|
| 120 | | def page_cache_file |
|---|
| 121 | | path = url_for(:only_path => true, :skip_relative_url_root => true) |
|---|
| 122 | | path = ((path.empty? || path == "/") ? "/index" : URI.unescape(path)) |
|---|
| 123 | | path << ".#{params[:format] || 'html'}" unless path =~ /\.#{params[:format]}$/ |
|---|
| 124 | | path |
|---|
| 125 | | end |
|---|
| 126 | | |
|---|
| 127 | | # Find the best template for the current node's skin, node's class, format and mode. The template |
|---|
| 128 | | # files are searched first into 'sites/shared/views/templates/fixed'. If the templates are not found |
|---|
| 129 | | # there, they are searched in the database and compiled into 'app/views/templates/compiled'. |
|---|
| 130 | | def template_url(opts={}) |
|---|
| 131 | | skin_name = opts[:skin] || (@node ? @node[:skin] : nil) || 'default' |
|---|
| 132 | | skin_name = skin_name.gsub(/[^a-zA-Z]/,'') # security |
|---|
| 133 | | mode = opts[:mode] || params[:mode] |
|---|
| 134 | | format = opts[:format] || params[:format] || 'html' |
|---|
| 135 | | klass = @node.class |
|---|
| 136 | | # FIXME: rescue_template = opts[:rescue_template] || '/templates/fixed/default/any' |
|---|
| 137 | | # FIXME: @skin_obj = nil |
|---|
| 138 | | # classes : |
|---|
| 139 | | klasses = [] |
|---|
| 140 | | klass.kpath.split(//).each_index { |i| klasses << klass.kpath[0..i] } |
|---|
| 141 | | |
|---|
| 142 | | best_match = { |
|---|
| 143 | | :conditions => ["tkpath IN (?) AND format = ? AND mode #{mode ? '=' : 'IS'} ?", klasses, format, mode], |
|---|
| 144 | | :select => "*, (template_contents.skin_name = '#{skin_name}') AS skin_ok", |
|---|
| 145 | | :order => "length(tkpath) DESC, skin_ok DESC" |
|---|
| 146 | | } |
|---|
| 147 | | |
|---|
| 148 | | if skin_name == 'default' |
|---|
| 149 | | template = TemplateContent.find(:first, best_match) |
|---|
| 150 | | skin_root = "#{SITES_ROOT}/shared" |
|---|
| 151 | | else |
|---|
| 152 | | best_match[:conditions][0] += " AND template_contents.node_id = nodes.id" |
|---|
| 153 | | best_match[:from] = "nodes, template_contents" |
|---|
| 154 | | best_match[:select] = "nodes.*, template_contents.*, (template_contents.skin_name = #{skin_name}) AS skin_ok", |
|---|
| 155 | | template = secure(Template) { Template.find(:first, best_match) } |
|---|
| 156 | | skin_root = "#{SITES_ROOT}/#{visitor.site.host}" |
|---|
| 157 | | end |
|---|
| 158 | | |
|---|
| 159 | | raise ActiveRecord::RecordNotFound unless template |
|---|
| 160 | | mode = "_#{mode}" if mode |
|---|
| 161 | | skin_path = "/#{template.skin_name}/#{template.klass}#{mode}.#{format}" |
|---|
| 162 | | main_path = "/#{visitor.lang}/main.erb" |
|---|
| 163 | | url = "#{skin_root}/zafu.compiled#{skin_path}#{main_path}" |
|---|
| 164 | | |
|---|
| 165 | | if File.exists?(url) |
|---|
| 166 | | if skin_name == 'default' && (File.stat(url).mtime < File.stat("#{skin_root}/zafu#{skin_path}").mtime || RAILS_ENV == 'development') |
|---|
| 167 | | FileUtils.rmtree("#{skin_root}/zafu.compiled#{skin_path}") |
|---|
| 168 | | elsif skin_name != 'default' && (File.stat(url).mtime < template.v_updated_at || RAILS_ENV == 'development') |
|---|
| 169 | | FileUtils.rmtree("#{skin_root}/zafu.compiled#{skin_path}") |
|---|
| 170 | | else |
|---|
| 171 | | # we can use the cached version |
|---|
| 172 | | return url |
|---|
| 173 | | end |
|---|
| 174 | | end |
|---|
| 175 | | |
|---|
| 176 | | # render zafu |
|---|
| 177 | | response.template.instance_variable_set(:@session, session) |
|---|
| 178 | | skin_helper = response.template |
|---|
| 179 | | res = ZafuParser.new_with_url(skin_path, :helper => skin_helper).render |
|---|
| 180 | | FileUtils::mkpath(File.dirname(url)) unless File.exists?(File.dirname(url)) |
|---|
| 181 | | File.open(url, "wb") { |f| f.syswrite(res) } |
|---|
| 182 | | |
|---|
| 183 | | return url |
|---|
| 184 | | end |
|---|
| 185 | | |
|---|
| 186 | | # tested in MainControllerTest |
|---|
| 187 | | def template_text_for_url(url) |
|---|
| 188 | | url = url[1..-1] # strip leading '/' |
|---|
| 189 | | url = url.split('/') |
|---|
| 190 | | skin_name = url.shift |
|---|
| 191 | | if skin_name == 'default' |
|---|
| 192 | | path = File.join(SITES_ROOT, 'shared', 'zafu', 'default', *url) |
|---|
| 193 | | if File.exists?(path) |
|---|
| 194 | | File.read(path) |
|---|
| | 97 | @section = @node.section |
|---|
| | 98 | @date ||= params[:date] ? parse_date(params[:date]) : Time.now |
|---|
| | 99 | render :file => template_url(opts), :layout=>false |
|---|
| | 100 | |
|---|
| | 101 | cache_page if opts[:cache] |
|---|
| | 102 | end |
|---|
| | 103 | |
|---|
| | 104 | # Cache page content into a static file in the current sites directory : SITES_ROOT/test.host/public |
|---|
| | 105 | def cache_page(opts={}) |
|---|
| | 106 | return unless perform_caching && caching_allowed |
|---|
| | 107 | opts = {:expire_after => nil, |
|---|
| | 108 | :path => (visitor.site.public_path + page_cache_file), |
|---|
| | 109 | :content_data => response.body |
|---|
| | 110 | }.merge(opts) |
|---|
| | 111 | secure(CachedPage) { CachedPage.create(opts) } |
|---|
| | 112 | end |
|---|
| | 113 | |
|---|
| | 114 | # Return true if we can cache the current page |
|---|
| | 115 | def caching_allowed |
|---|
| | 116 | visitor.is_anon? |
|---|
| | 117 | end |
|---|
| | 118 | |
|---|
| | 119 | # Cache file path that reflects the called url |
|---|
| | 120 | def page_cache_file |
|---|
| | 121 | path = url_for(:only_path => true, :skip_relative_url_root => true) |
|---|
| | 122 | path = ((path.empty? || path == "/") ? "/index" : URI.unescape(path)) |
|---|
| | 123 | path << ".#{params[:format] || 'html'}" unless path =~ /\.#{params[:format]}$/ |
|---|
| | 124 | path |
|---|
| | 125 | end |
|---|
| | 126 | |
|---|
| | 127 | # Find the best template for the current node's skin, node's class, format and mode. The template |
|---|
| | 128 | # files are searched first into 'sites/shared/views/templates/fixed'. If the templates are not found |
|---|
| | 129 | # there, they are searched in the database and compiled into 'app/views/templates/compiled'. |
|---|
| | 130 | def template_url(opts={}) |
|---|
| | 131 | skin_name = opts[:skin] || (@node ? @node[:skin] : nil) || 'default' |
|---|
| | 132 | skin_name = skin_name.gsub(/[^a-zA-Z]/,'') # security |
|---|
| | 133 | mode = opts[:mode] || params[:mode] |
|---|
| | 134 | format = opts[:format] || params[:format] || 'html' |
|---|
| | 135 | klass = @node.class |
|---|
| | 136 | # FIXME: rescue_template = opts[:rescue_template] || '/templates/fixed/default/any' |
|---|
| | 137 | # FIXME: @skin_obj = nil |
|---|
| | 138 | # classes : |
|---|
| | 139 | klasses = [] |
|---|
| | 140 | klass.kpath.split(//).each_index { |i| klasses << klass.kpath[0..i] } |
|---|
| | 141 | |
|---|
| | 142 | best_match = { |
|---|
| | 143 | :conditions => ["tkpath IN (?) AND format = ? AND mode #{mode ? '=' : 'IS'} ?", klasses, format, mode], |
|---|
| | 144 | :select => "*, (template_contents.skin_name = '#{skin_name}') AS skin_ok", |
|---|
| | 145 | :order => "length(tkpath) DESC, skin_ok DESC" |
|---|
| | 146 | } |
|---|
| | 147 | |
|---|
| | 148 | if skin_name == 'default' |
|---|
| | 149 | template = TemplateContent.find(:first, best_match) |
|---|
| | 150 | skin_root = "#{SITES_ROOT}/shared" |
|---|
| | 151 | else |
|---|
| | 152 | best_match[:conditions][0] += " AND template_contents.node_id = nodes.id" |
|---|
| | 153 | best_match[:from] = "nodes, template_contents" |
|---|
| | 154 | best_match[:select] = "nodes.*, template_contents.*, (template_contents.skin_name = #{skin_name}) AS skin_ok", |
|---|
| | 155 | template = secure(Template) { Template.find(:first, best_match) } |
|---|
| | 156 | skin_root = "#{SITES_ROOT}/#{visitor.site.host}" |
|---|
| | 157 | end |
|---|
| | 158 | |
|---|
| | 159 | raise ActiveRecord::RecordNotFound unless template |
|---|
| | 160 | mode = "_#{mode}" if mode |
|---|
| | 161 | skin_path = "/#{template.skin_name}/#{template.klass}#{mode}.#{format}" |
|---|
| | 162 | main_path = "/#{visitor.lang}/main.erb" |
|---|
| | 163 | url = "#{skin_root}/zafu.compiled#{skin_path}#{main_path}" |
|---|
| | 164 | |
|---|
| | 165 | if File.exists?(url) |
|---|
| | 166 | if skin_name == 'default' && (File.stat(url).mtime < File.stat("#{skin_root}/zafu#{skin_path}").mtime || RAILS_ENV == 'development') |
|---|
| | 167 | FileUtils.rmtree("#{skin_root}/zafu.compiled#{skin_path}") |
|---|
| | 168 | elsif skin_name != 'default' && (File.stat(url).mtime < template.v_updated_at || RAILS_ENV == 'development') |
|---|
| | 169 | FileUtils.rmtree("#{skin_root}/zafu.compiled#{skin_path}") |
|---|
| | 170 | else |
|---|
| | 171 | # we can use the cached version |
|---|
| | 172 | return url |
|---|
| | 173 | end |
|---|
| | 174 | end |
|---|
| | 175 | |
|---|
| | 176 | # render zafu |
|---|
| | 177 | response.template.instance_variable_set(:@session, session) |
|---|
| | 178 | skin_helper = response.template |
|---|
| | 179 | res = ZafuParser.new_with_url(skin_path, :helper => skin_helper).render |
|---|
| | 180 | FileUtils::mkpath(File.dirname(url)) unless File.exists?(File.dirname(url)) |
|---|
| | 181 | File.open(url, "wb") { |f| f.syswrite(res) } |
|---|
| | 182 | |
|---|
| | 183 | return url |
|---|
| | 184 | end |
|---|
| | 185 | |
|---|
| | 186 | # tested in MainControllerTest |
|---|
| | 187 | def template_text_for_url(url) |
|---|
| | 188 | url = url[1..-1] # strip leading '/' |
|---|
| | 189 | url = url.split('/') |
|---|
| | 190 | skin_name = url.shift |
|---|
| | 191 | if skin_name == 'default' |
|---|
| | 192 | path = File.join(SITES_ROOT, 'shared', 'zafu', 'default', *url) |
|---|
| | 193 | if File.exists?(path) |
|---|
| | 194 | File.read(path) |
|---|
| | 195 | else |
|---|
| | 196 | nil |
|---|
| | 197 | end |
|---|
| | 198 | else |
|---|
| | 199 | if @skin_obj[:name] == skin_name |
|---|
| | 200 | skin = @skin_obj |
|---|
| | 201 | end |
|---|
| | 202 | skin ||= secure(Skin) { Skin.find_by_name(skin_name) } |
|---|
| | 203 | template = skin.template_for_path(url.join('/')) |
|---|
| | 204 | template ? template.version.text : nil |
|---|
| | 205 | end |
|---|
| | 206 | rescue ActiveRecord::RecordNotFound |
|---|
| | 207 | return nil |
|---|
| | 208 | end |
|---|
| | 209 | |
|---|
| | 210 | # TODO: implement |
|---|
| | 211 | def template_url_for_asset(opts) |
|---|
| | 212 | |
|---|
| | 213 | # 1. find in current skin ? |
|---|
| | 214 | url = opts[:current_template][1..-1].split('/') + opts[:src].split('/') |
|---|
| | 215 | url.compact! |
|---|
| | 216 | skin_name = url.shift |
|---|
| | 217 | if @skin_obj && @skin_obj[:name] == skin_name |
|---|
| | 218 | skin = @skin_obj |
|---|
| | 219 | end |
|---|
| | 220 | skin ||= secure(Skin) { Skin.find_by_name(skin_name) } |
|---|
| | 221 | asset = skin.asset_for_path(url.join('/'), Document) |
|---|
| | 222 | asset ? node_url(asset) : nil |
|---|
| | 223 | rescue ActiveRecord::RecordNotFound |
|---|
| | 224 | return nil |
|---|
| | 225 | end |
|---|
| | 226 | |
|---|
| | 227 | # TODO: test |
|---|
| | 228 | def save_erb_to_url(template, template_url) |
|---|
| | 229 | path = fullpath_from_template_url(template_url) + ".erb" |
|---|
| | 230 | FileUtils.mkpath(File.dirname(path)) unless File.exists?(File.dirname(path)) |
|---|
| | 231 | File.open(path, "wb") { |f| f.syswrite(template) } |
|---|
| | 232 | "" |
|---|
| | 233 | end |
|---|
| | 234 | |
|---|
| | 235 | # TODO: test |
|---|
| | 236 | def fullpath_from_template_url(template_url=params[:template_url]) |
|---|
| | 237 | if template_url =~ /\.\.|[^\w\._\/]/ |
|---|
| | 238 | raise Zena::AccessViolation.new("'template_url' contains illegal characters : #{template_url.inspect}") |
|---|
| | 239 | end |
|---|
| | 240 | |
|---|
| | 241 | template_url = template_url[1..-1].split('/') |
|---|
| | 242 | path = "/#{template_url[0]}/#{template_url[1]}/#{visitor.lang}/#{template_url[2..-1].join('/')}" |
|---|
| | 243 | |
|---|
| | 244 | if template_url[0] == 'default' |
|---|
| | 245 | "#{SITES_ROOT}/shared/zafu.compiled#{path}" |
|---|
| | 246 | else |
|---|
| | 247 | "#{SITES_ROOT}/#{visitor.site.host}/zafu.compiled#{path}" |
|---|
| | 248 | end |
|---|
| | 249 | end |
|---|
| | 250 | |
|---|
| | 251 | # Verify that only logged in users access to some protected resources. This can be used to remove public access to an |
|---|
| | 252 | # entire site. +authorize+ is called before any action in any controller. |
|---|
| | 253 | def authorize |
|---|
| | 254 | if (visitor.site[:authorize] || params[:prefix] == AUTHENTICATED_PREFIX) && ! session[:user] |
|---|
| | 255 | flash[:notice] = trans "Please log in" |
|---|
| | 256 | session[:after_login_url] = request.parameters |
|---|
| | 257 | redirect_to :controller =>'login', :action=>'login' and return false |
|---|
| | 258 | end |
|---|
| | 259 | end |
|---|
| | 260 | |
|---|
| | 261 | # Make sure everything is in sync, change current language, set @su warning color (tested in MainControllerTest) |
|---|
| | 262 | def check_env |
|---|
| | 263 | # Set connection charset. MySQL 4.0 doesn't support this so it |
|---|
| | 264 | # will throw an error, MySQL 4.1 needs this |
|---|
| | 265 | suppress(ActiveRecord::StatementInvalid) do |
|---|
| | 266 | ActiveRecord::Base.connection.execute 'SET NAMES UTF8' |
|---|
| | 267 | end |
|---|
| | 268 | |
|---|
| | 269 | redirect_to not_found_path if params[:id] && params[:path] # make sure we do not mix 'pretty urls' with resources. |
|---|
| | 270 | |
|---|
| | 271 | new_lang = nil |
|---|
| | 272 | if params[:lang] |
|---|
| | 273 | if visitor.site.lang_list.include?(params[:lang]) |
|---|
| | 274 | new_lang = params[:lang] |
|---|
| | 275 | else |
|---|
| | 276 | new_lang = :bad_language |
|---|
| | 277 | end |
|---|
| | 278 | elsif params[:prefix] && params[:prefix] != AUTHENTICATED_PREFIX |
|---|
| | 279 | if visitor.site.lang_list.include?(params[:prefix]) |
|---|
| | 280 | session[:lang] = params[:prefix] |
|---|
| | 281 | else |
|---|
| | 282 | new_lang = :bad_language |
|---|
| | 283 | end |
|---|
| | 284 | end |
|---|
| | 285 | |
|---|
| | 286 | if new_lang |
|---|
| | 287 | if new_lang == :bad_language |
|---|
| | 288 | flash[:notice] = trans "The requested language is not available." |
|---|
| | 289 | session[:lang] ||= visitor.site[:default_lang] |
|---|
| | 290 | else |
|---|
| | 291 | session[:lang] = new_lang |
|---|
| | 292 | end |
|---|
| | 293 | req = request.parameters |
|---|
| | 294 | req.delete(:lang) |
|---|
| | 295 | req[:prefix] = session[:user] ? AUTHENTICATED_PREFIX : session[:lang] |
|---|
| | 296 | redirect_to req and return false |
|---|
| | 297 | end |
|---|
| | 298 | # If the current user is su, make the CSS ugly so the user does not stay logged in as su. |
|---|
| | 299 | if visitor.is_su? |
|---|
| | 300 | @su=' style="background:#060;" ' |
|---|
| | 301 | else |
|---|
| | 302 | @su='' |
|---|
| | 303 | end |
|---|
| | 304 | |
|---|
| | 305 | # turn translation on/off |
|---|
| | 306 | if params[:translate] |
|---|
| | 307 | if visitor.group_ids.include?(visitor.site[:trans_group_id]) |
|---|
| | 308 | if params[:translate] == 'on' |
|---|
| | 309 | session[:translate] = true |
|---|
| | 310 | else |
|---|
| | 311 | session[:translate] = nil |
|---|
| | 312 | end |
|---|
| | 313 | end |
|---|
| | 314 | req = request.parameters |
|---|
| | 315 | req.delete(:translate) |
|---|
| | 316 | redirect_to req and return false |
|---|
| | 317 | end |
|---|
| | 318 | visitor.lang = session[:lang] ||= (visitor.lang || visitor.site[:default_lang]) |
|---|
| | 319 | true |
|---|
| | 320 | end |
|---|
| | 321 | |
|---|
| | 322 | # "Translate" static text into the current lang |
|---|
| | 323 | def trans(keyword, edit=true) |
|---|
| | 324 | TransPhrase[keyword][lang] |
|---|
| | 325 | end |
|---|
| | 326 | |
|---|
| | 327 | def set_encoding |
|---|
| | 328 | headers['Content-Type'] ||= 'text/html' |
|---|
| | 329 | if headers['Content-Type'].starts_with?('text/') and !headers['Content-Type'].include?('charset=') |
|---|
| | 330 | headers['Content-Type'] += '; charset=utf-8' |
|---|
| | 331 | end |
|---|
| | 332 | end |
|---|
| | 333 | |
|---|
| | 334 | # Parse date : return a date from a string |
|---|
| | 335 | # TODO: test time_zone.. |
|---|
| | 336 | def parse_date(datestr, fmt=trans('datetime')) |
|---|
| | 337 | elements = datestr.split(/(\.|\-|\/|\s|:)+/) |
|---|
| | 338 | format = fmt.split(/(\.|\-|\/|\s|:)+/) |
|---|
| | 339 | if elements |
|---|
| | 340 | hash = {} |
|---|
| | 341 | elements.each_index do |i| |
|---|
| | 342 | hash[format[i]] = elements[i] |
|---|
| | 343 | end |
|---|
| | 344 | hash['%Y'] ||= hash['%y'] ? (hash['%y'].to_i + 2000) : Time.now.year |
|---|
| | 345 | hash['%H'] ||= 0 |
|---|
| | 346 | hash['%M'] ||= 0 |
|---|
| | 347 | hash['%S'] ||= 0 |
|---|
| | 348 | if hash['%Y'] && hash['%m'] && hash['%d'] |
|---|
| | 349 | visitor.tz.unadjust(Time.gm(hash['%Y'], hash['%m'], hash['%d'], hash['%H'], hash['%M'], hash['%S'])) |
|---|
| | 350 | else |
|---|
| | 351 | nil |
|---|
| | 352 | end |
|---|
| 210 | | # TODO: implement |
|---|
| 211 | | def template_url_for_asset(opts) |
|---|
| 212 | | |
|---|
| 213 | | # 1. find in current skin ? |
|---|
| 214 | | url = opts[:current_template][1..-1].split('/') + opts[:src].split('/') |
|---|
| 215 | | url.compact! |
|---|
| 216 | | skin_name = url.shift |
|---|
| 217 | | if @skin_obj && @skin_obj[:name] == skin_name |
|---|
| 218 | | skin = @skin_obj |
|---|
| 219 | | end |
|---|
| 220 | | skin ||= secure(Skin) { Skin.find_by_name(skin_name) } |
|---|
| 221 | | asset = skin.asset_for_path(url.join('/'), Document) |
|---|
| 222 | | asset ? node_url(asset) : nil |
|---|
| 223 | | rescue ActiveRecord::RecordNotFound |
|---|
| 224 | | return nil |
|---|
| 225 | | end |
|---|
| 226 | | |
|---|
| 227 | | # TODO: test |
|---|
| 228 | | def save_erb_to_url(template, template_url) |
|---|
| 229 | | path = fullpath_from_template_url(template_url) + ".erb" |
|---|
| 230 | | FileUtils.mkpath(File.dirname(path)) unless File.exists?(File.dirname(path)) |
|---|
| 231 | | File.open(path, "wb") { |f| f.syswrite(template) } |
|---|
| 232 | | "" |
|---|
| 233 | | end |
|---|
| 234 | | |
|---|
| 235 | | # TODO: test |
|---|
| 236 | | def fullpath_from_template_url(template_url=params[:template_url]) |
|---|
| 237 | | if template_url =~ /\.\.|[^\w\._\/]/ |
|---|
| 238 | | raise Zena::AccessViolation.new("'template_url' contains illegal characters : #{template_url.inspect}") |
|---|
| 239 | | end |
|---|
| 240 | | |
|---|
| 241 | | template_url = template_url[1..-1].split('/') |
|---|
| 242 | | path = "/#{template_url[0]}/#{template_url[1]}/#{visitor.lang}/#{template_url[2..-1].join('/')}" |
|---|
| 243 | | |
|---|
| 244 | | if template_url[0] == 'default' |
|---|
| 245 | | "#{SITES_ROOT}/shared/zafu.compiled#{path}" |
|---|
| 246 | | else |
|---|
| 247 | | "#{SITES_ROOT}/#{visitor.site.host}/zafu.compiled#{path}" |
|---|
| 248 | | end |
|---|
| 249 | | end |
|---|
| 250 | | |
|---|
| 251 | | # Verify that only logged in users access to some protected resources. This can be used to remove public access to an |
|---|
| 252 | | # entire site. +authorize+ is called before any action in any controller. |
|---|
| 253 | | def authorize |
|---|
| 254 | | if (visitor.site[:authorize] || params[:prefix] == AUTHENTICATED_PREFIX) && ! session[:user] |
|---|
| 255 | | flash[:notice] = trans "Please log in" |
|---|
| 256 | | session[:after_login_url] = request.parameters |
|---|
| 257 | | redirect_to :controller =>'login', :action=>'login' and return false |
|---|
| 258 | | end |
|---|
| 259 | | end |
|---|
| 260 | | |
|---|
| 261 | | # Make sure everything is in sync, change current language, set @su warning color (tested in MainControllerTest) |
|---|
| 262 | | def check_env |
|---|
| 263 | | # Set connection charset. MySQL 4.0 doesn't support this so it |
|---|
| 264 | | # will throw an error, MySQL 4.1 needs this |
|---|
| 265 | | suppress(ActiveRecord::StatementInvalid) do |
|---|
| 266 | | ActiveRecord::Base.connection.execute 'SET NAMES UTF8' |
|---|
| 267 | | end |
|---|
| 268 | | |
|---|
| 269 | | redirect_to not_found_path if params[:id] && params[:path] # make sure we do not mix 'pretty urls' with resources. |
|---|
| 270 | | |
|---|
| 271 | | new_lang = nil |
|---|
| 272 | | if params[:lang] |
|---|
| 273 | | if visitor.site.lang_list.include?(params[:lang]) |
|---|
| 274 | | new_lang = params[:lang] |
|---|
| 275 | | else |
|---|
| 276 | | new_lang = :bad_language |
|---|
| 277 | | end |
|---|
| 278 | | elsif params[:prefix] && params[:prefix] != AUTHENTICATED_PREFIX |
|---|
| 279 | | if visitor.site.lang_list.include?(params[:prefix]) |
|---|
| 280 | | session[:lang] = params[:prefix] |
|---|
| 281 | | else |
|---|
| 282 | | new_lang = :bad_language |
|---|
| 283 | | end |
|---|
| 284 | | end |
|---|
| 285 | | |
|---|
| 286 | | if new_lang |
|---|
| 287 | | if new_lang == :bad_language |
|---|
| 288 | | flash[:notice] = trans "The requested language is not available." |
|---|
| 289 | | session[:lang] ||= visitor.site[:default_lang] |
|---|
| 290 | | else |
|---|
| 291 | | session[:lang] = new_lang |
|---|
| 292 | | end |
|---|
| 293 | | req = request.parameters |
|---|
| 294 | | req.delete(:lang) |
|---|
| 295 | | req[:prefix] = session[:user] ? AUTHENTICATED_PREFIX : session[:lang] |
|---|
| 296 | | redirect_to req and return false |
|---|
| 297 | | end |
|---|
| 298 | | # If the current user is su, make the CSS ugly so the user does not stay logged in as su. |
|---|
| 299 | | if visitor.is_su? |
|---|
| 300 | | @su=' style="background:#060;" ' |
|---|
| 301 | | else |
|---|
| 302 | | @su='' |
|---|
| 303 | | end |
|---|
| 304 | | |
|---|
| 305 | | # turn translation on/off |
|---|
| 306 | | if params[:translate] |
|---|
| 307 | | if visitor.group_ids.include?(visitor.site[:trans_group_id]) |
|---|
| 308 | | if params[:translate] == 'on' |
|---|
| 309 | | session[:translate] = true |
|---|
| 310 | | else |
|---|
| 311 | | session[:translate] = nil |
|---|
| 312 | | end |
|---|
| 313 | | end |
|---|
| 314 | | req = request.parameters |
|---|
| 315 | | req.delete(:translate) |
|---|
| 316 | | redirect_to req and return false |
|---|
| 317 | | end |
|---|
| 318 | | visitor.lang = session[:lang] ||= (visitor.lang || visitor.site[:default_lang]) |
|---|
| 319 | | true |
|---|
| 320 | | end |
|---|
| 321 | | |
|---|
| 322 | | # "Translate" static text into the current lang |
|---|
| 323 | | def trans(keyword, edit=true) |
|---|
| 324 | | TransPhrase[keyword][lang] |
|---|
| 325 | | end |
|---|
| 326 | | |
|---|
| 327 | | def set_encoding |
|---|
| 328 | | headers['Content-Type'] ||= 'text/html' |
|---|
| 329 | | if headers['Content-Type'].starts_with?('text/') and !headers['Content-Type'].include?('charset=') |
|---|
| 330 | | headers['Content-Type'] += '; charset=utf-8' |
|---|
| 331 | | end |
|---|
| 332 | | end |
|---|
| 333 | | |
|---|
| 334 | | # Parse date : return a date from a string |
|---|
| 335 | | # TODO: test time_zone.. |
|---|
| 336 | | def parse_date(datestr, fmt=trans('datetime')) |
|---|
| 337 | | elements = datestr.split(/(\.|\-|\/|\s|:)+/) |
|---|
| 338 | | format = fmt.split(/(\.|\-|\/|\s|:)+/) |
|---|
| 339 | | if elements |
|---|
| 340 | | hash = {} |
|---|
| 341 | | elements.each_index do |i| |
|---|
| 342 | | hash[format[i]] = elements[i] |
|---|
| 343 | | end |
|---|
| 344 | | hash['%Y'] ||= hash['%y'] ? (hash['%y'].to_i + 2000) : Time.now.year |
|---|
| 345 | | hash['%H'] ||= 0 |
|---|
| 346 | | hash['%M'] ||= 0 |
|---|
| 347 | | hash['%S'] ||= 0 |
|---|
| 348 | | if hash['%Y'] && hash['%m'] && hash['%d'] |
|---|
| 349 | | visitor.tz.unadjust(Time.gm(hash['%Y'], hash['%m'], hash['%d'], hash['%H'], hash['%M'], hash['%S'])) |
|---|
| 350 | | else |
|---|
| 351 | | nil |
|---|
| 352 | | end |
|---|
| 353 | | else |
|---|
| 354 | | nil |
|---|
| 355 | | end |
|---|
| 356 | | end |
|---|
| 357 | | |
|---|
| 358 | | def parse_dates(hash, fmt=trans('datetime')) |
|---|
| 359 | | [:v_publish_from, :log_at, :event_at].each do |sym| |
|---|
| 360 | | hash[sym] = parse_date(hash[sym], fmt) if hash[sym] && hash[sym].kind_of?(String) |
|---|
| 361 | | end |
|---|
| 362 | | end |
|---|
| 363 | | |
|---|
| 364 | | # /////// The following methods are common to controllers and views //////////// # |
|---|
| 365 | | |
|---|
| 366 | | def data_path(obj) |
|---|
| 367 | | zen_path(obj, :format => obj.c_ext) |
|---|
| 368 | | end |
|---|
| 369 | | |
|---|
| 370 | | # Path for the node (as string). Options can be :format and :mode. |
|---|
| 371 | | def zen_path(obj, opts={}) |
|---|
| 372 | | opts = {:format => params[:format], :prefix => prefix}.merge(opts) |
|---|
| 373 | | opts[:format] = 'html' if opts[:format].nil? || opts[:format] == '' |
|---|
| 374 | | if obj[:id] == visitor.site[:root_id] && opts[:mode].nil? |
|---|
| 375 | | "/#{opts[:prefix]}" # index page |
|---|
| 376 | | elsif obj[:custom_base] |
|---|
| 377 | | "/#{opts[:prefix]}/" + |
|---|
| 378 | | obj.basepath + |
|---|
| 379 | | (opts[:mode] ? "_#{opts[:mode]}" : '') + |
|---|
| 380 | | ".#{opts[:format]}" |
|---|
| 381 | | else |
|---|
| 382 | | "/#{opts[:prefix]}/" + |
|---|
| 383 | | (obj.basepath != '' ? "#{obj.basepath}/" : '') + |
|---|
| 384 | | (obj.class.to_s.downcase ) + |
|---|
| 385 | | (obj[:zip].to_s ) + |
|---|
| 386 | | (opts[:mode] ? "_#{opts[:mode]}" : '') + |
|---|
| 387 | | ".#{opts[:format]}" |
|---|
| 388 | | end |
|---|
| 389 | | end |
|---|
| 390 | | |
|---|
| 391 | | def zen_url(obj, opts={}) |
|---|
| 392 | | path = zen_path(obj,opts) |
|---|
| 393 | | url_for(:url => path) |
|---|
| 394 | | end |
|---|
| 395 | | |
|---|
| 396 | | def prefix |
|---|
| 397 | | if visitor.is_anon? |
|---|
| 398 | | if visitor.site[:monolingual] |
|---|
| 399 | | '' |
|---|
| 400 | | else |
|---|
| 401 | | lang |
|---|
| 402 | | end |
|---|
| 403 | | else |
|---|
| 404 | | AUTHENTICATED_PREFIX |
|---|
| 405 | | end |
|---|
| 406 | | end |
|---|
| 407 | | |
|---|
| 408 | | # Restrict access some actions to administrators (used as a before_filter) |
|---|
| 409 | | def check_is_admin |
|---|
| 410 | | render_404(ActiveRecord::RecordNotFound) unless visitor.is_admin? |
|---|
| 411 | | @admin = true |
|---|
| 412 | | end |
|---|
| 413 | | |
|---|
| 414 | | # Notes finder options are |
|---|
| 415 | | # [from] node providing the notes. If omitted, <code>@project</code> or <code>@node.project</code> is used. |
|---|
| 416 | | # [find] method called on the source. Default is 'notes'. For example, <code>:from=>@node.project, :find=>:notes</code> finds all notes from the project of the current node. |
|---|
| 417 | | # [date] only find notes for the given date |
|---|
| 418 | | # [using] specify the field used to sort and filter by date. By default, 'log_at' is used |
|---|
| 419 | | # [order] sort order. By default "#{using} ASC" is used. |
|---|
| 420 | | # [] |
|---|
| 421 | | def notes(options={}) |
|---|
| 422 | | source = options[:from] || (@project ||= (@node ? @node.project : nil)) |
|---|
| 423 | | return [] unless source |
|---|
| 424 | | |
|---|
| 425 | | options.delete(:from) |
|---|
| | 396 | def prefix |
|---|
| | 397 | if visitor.is_anon? |
|---|
| | 398 | if visitor.site[:monolingual] |
|---|
| | 399 | '' |
|---|
| | 400 | else |
|---|
| | 401 | lang |
|---|
| | 402 | end |
|---|
| | 403 | else |
|---|
| | 404 | AUTHENTICATED_PREFIX |
|---|
| | 405 | end |
|---|
| | 406 | end |
|---|
| | 407 | |
|---|
| | 408 | # Restrict access some actions to administrators (used as a before_filter) |
|---|
| | 409 | def check_is_admin |
|---|
| | 410 | render_404(ActiveRecord::RecordNotFound) unless visitor.is_admin? |
|---|
| | 411 | @admin = true |
|---|
| | 412 | end |
|---|
| | 413 | |
|---|
| | 414 | # Notes finder options are |
|---|
| | 415 | # [from] node providing the notes. If omitted, <code>@project</code> or <code>@node.project</code> is used. |
|---|
| | 416 | # [find] method called on the source. Default is 'notes'. For example, <code>:from=>@node.project, :find=>:notes</code> finds all notes from the project of the current node. |
|---|
| | 417 | # [date] only find notes for the given date |
|---|
| | 418 | # [using] specify the field used to sort and filter by date. By default, 'log_at' is used |
|---|
| | 419 | # [order] sort order. By default "#{using} ASC" is used. |
|---|
| | 420 | # [] |
|---|
| | 421 | def notes(options={}) |
|---|
| | 422 | source = options[:from] || (@project ||= (@node ? @node.project : nil)) |
|---|
| | 423 | return [] unless source |
|---|
| | 424 | |
|---|
| | 425 | options.delete(:from) |
|---|