zena 1.2.5 → 1.2.6

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,3 +1,11 @@
1
+ == 1.2.6
2
+
3
+ * Major changes
4
+ * Support for multiple domains (site alias) for a single site.
5
+
6
+ * Minor changes
7
+ * Added 'cmd' option for pdf brick. <== TODO: Document
8
+ * Added 'local_ips' option to bricks.yml (used when pdf engine cannot render non-public assets). <== TODO: Document
1
9
  == 1.2.5 2013-07-15
2
10
 
3
11
  * Major changes
@@ -6,6 +14,7 @@
6
14
  * WARN: Properties in list context do not resolve with first element anymore. "first" prefix needed.
7
15
  * Enable VirtualClass on native classes !
8
16
  * Added 'activity' brick which records visitor's last "seen_at" date. <== TODO: Document
17
+ * Support for site alias (other domain pointing to same data) "rake mkalias". <== TODO: Document
9
18
 
10
19
  * Minor changes
11
20
  * Fixed encode_params in Ajax requests.
@@ -30,7 +30,7 @@ class NodesController < ApplicationController
30
30
  layout :popup_layout, :only => [:edit, :import]
31
31
 
32
32
  def index
33
- if @node = secure(Node) { Node.find(current_site.root_id) }
33
+ if @node = secure(Node) { Node.find(current_site.home_id) }
34
34
  respond_to do |format|
35
35
  format.html { render_and_cache :mode => '+index' }
36
36
  format.xml { render :xml => @node.to_xml }
@@ -8,7 +8,7 @@ class VersionsController < ApplicationController
8
8
  respond_to do |format|
9
9
 
10
10
  format.html {
11
- if @node.id == current_site.root_id
11
+ if @node.id == current_site.home_id
12
12
  render_and_cache :cache => false, :mode => '+index'
13
13
  insert_warning
14
14
  else
@@ -1280,64 +1280,6 @@ class Node < ActiveRecord::Base
1280
1280
  # Id to zip mapping for user_id. Used by zafu and forms.
1281
1281
  def user_zip; self[:user_id]; end
1282
1282
 
1283
- # transform to another class
1284
- # def vclass=(new_class)
1285
- # if new_class.kind_of?(String)
1286
- # klass = Module.const_get(new_class)
1287
- # else
1288
- # klass = new_class
1289
- # end
1290
- # raise NameError if !klass.ancestors.include?(Node) || klass.version_class != self.class.content_class
1291
- #
1292
- #
1293
- #
1294
- # rescue NameError
1295
- # errors.add('klass', 'invalid')
1296
- # end
1297
-
1298
- # transform an Node into another Object. This is a two step operation :
1299
- # 1. create a new object with the attributes from the old one
1300
- # 2. move old object out of the way (setting parent_id and section_id to -1)
1301
- # 3. try to save new object
1302
- # 4. delete old and set new object id to old
1303
- # THIS IS DANGEROUS !! NEEDS TESTING
1304
- # def change_to(klass)
1305
- # return nil if self[:id] == current_site[:root_id]
1306
- # # ==> Check for class specific information (file to remove, participations, tags, etc) ... should we leave these things and
1307
- # # not care ?
1308
- # # ==> When changing into something else : update version type and data !!!
1309
- # my_id = self[:id].to_i
1310
- # my_parent = self[:parent_id].to_i
1311
- # my_project = self[:section_id].to_i
1312
- # connection = self.class.connection
1313
- # # 1. create a new object with the attributes from the old one
1314
- # new_obj = secure!(klass) { klass.new(self.attributes) }
1315
- # # 2. move old object out of the way (setting parent_id and section_id to -1)
1316
- # self.class.connection.execute "UPDATE #{self.class.table_name} SET parent_id='0', section_id='0' WHERE id=#{my_id}"
1317
- # # 3. try to save new object
1318
- # if new_obj.save
1319
- # tmp_id = new_obj[:id]
1320
- # # 4. delete old and set new object id to old. Delete tmp Version.
1321
- # self.class.connection.execute "DELETE FROM #{self.class.table_name} WHERE id=#{my_id}"
1322
- # self.class.connection.execute "DELETE FROM #{Version.table_name} WHERE node_id=#{tmp_id}"
1323
- # self.class.connection.execute "UPDATE #{self.class.table_name} SET id='#{my_id}' WHERE id=#{tmp_id}"
1324
- # self.class.connection.execute "UPDATE #{self.class.table_name} SET section_id=id WHERE id=#{my_id}" if new_obj.kind_of?(Section)
1325
- # self.class.logger.info "[#{self[:id]}] #{self.class} --> #{klass}"
1326
- # if new_obj.kind_of?(Section)
1327
- # # update section_id for children
1328
- # sync_section(my_id)
1329
- # elsif self.kind_of?(Section)
1330
- # # update section_id for children
1331
- # sync_section(parent[:section_id])
1332
- # end
1333
- # secure ( klass ) { klass.find(my_id) }
1334
- # else
1335
- # # set object back
1336
- # self.class.connection.execute "UPDATE #{self.class.table_name} SET parent_id='#{my_parent}', section_id='#{my_project}' WHERE id=#{my_id}"
1337
- # self
1338
- # end
1339
- # end
1340
-
1341
1283
  # Find the discussion for the current context (v_status and v_lang). This automatically creates a new #Discussion if there is
1342
1284
  # no closed or open discussion for the current lang and Node#can_auto_create_discussion? is true
1343
1285
  def discussion
@@ -6,8 +6,8 @@ A zena installation supports many sites. Each site is uniquely identified by it'
6
6
  The #Site model holds configuration information for a site:
7
7
 
8
8
  +host+:: Unique host name. (teti.ch, zenadmin.org, dev.example.org, ...)
9
- +orphan_id+:: Site seed node id. This is the only node in the site without a parent.
10
- +root_id+:: This is the apparent root of the site.
9
+ +root_id+:: Site seed node id. This is the only node in the site without a parent.
10
+ +home_id+:: This is the apparent root of the site (home page).
11
11
  +anon_id+:: Anonymous user id. This user is the 'public' user of the site. Even if +authorize+ is set to true, this user is needed to configure the defaults for all newly created users.
12
12
  +public_group_id+:: Id of the 'public' group. Every user of the site (with 'anonymous user') belongs to this group.
13
13
  +site_group_id+:: Id of the 'site' group. Every user except anonymous are part of this group. This group can be seen as the 'logged in users' group.
@@ -57,12 +57,12 @@ class Site < ActiveRecord::Base
57
57
 
58
58
  include RubyLess
59
59
  safe_method :host => String, :lang_list => [String], :default_lang => String, :master_host => String
60
- safe_method :root => Proc.new {|h, r, s| {:method => 'root_node', :class => VirtualClass['Project'], :nil => true}}
61
- safe_method :orphan => Proc.new {|h, r, s| {:method => 'orphan_node', :class => VirtualClass['Project'], :nil => true}}
60
+ safe_method :root => Proc.new {|h, r, s| {:method => 'root_node', :class => current_site.root_node.vclass, :nil => true}}
61
+ safe_method :home => Proc.new {|h, r, s| {:method => 'home_node', :class => current_site.home_node.vclass, :nil => true}}
62
62
 
63
63
  validate :valid_site
64
64
  validates_uniqueness_of :host
65
- attr_accessible :name, :languages, :default_lang, :authentication, :http_auth, :ssl_on_auth, :auto_publish, :redit_time, :api_group_id, :root_zip
65
+ attr_accessible :name, :languages, :default_lang, :authentication, :http_auth, :ssl_on_auth, :auto_publish, :redit_time, :api_group_id, :home_zip
66
66
  has_many :groups, :order => "name"
67
67
  has_many :nodes
68
68
  has_many :users
@@ -181,8 +181,8 @@ class Site < ActiveRecord::Base
181
181
 
182
182
  raise Exception.new("Could not publish root node for site [#{host}] (site#{site[:id]})\n#{root.errors.map{|k,v| "[#{k}] #{v}"}.join("\n")}") unless (root.v_status == Zena::Status::Pub || root.publish)
183
183
 
184
+ site.home_id = root[:id]
184
185
  site.root_id = root[:id]
185
- site.orphan_id = root[:id]
186
186
 
187
187
  # Make sure safe definitions on Time/Array/String are available on prop_eval validation.
188
188
  Zena::Use::ZafuSafeDefinitions
@@ -228,14 +228,21 @@ class Site < ActiveRecord::Base
228
228
  def find_by_host(host)
229
229
  host = $1 if host =~ /^(.*)\.$/
230
230
  if site = self.find(:first, :conditions => ['host = ?', host]) rescue nil
231
- if id = site.master_id
232
- # The loaded site is an alias, load master site.
233
- master = self.find(:first, :conditions => ['id = ?', id])
234
- master.alias = site
235
- site = master
236
- end
231
+ setup_master(site)
232
+ else
233
+ nil
234
+ end
235
+ end
236
+
237
+ def setup_master(site)
238
+ if id = site.master_id
239
+ # The loaded site is an alias, load master site.
240
+ master = self.find(:first, :conditions => ['id = ?', id])
241
+ master.alias = site
242
+ master
243
+ else
244
+ site
237
245
  end
238
- site
239
246
  end
240
247
 
241
248
  # List of attributes that can be configured in the admin form
@@ -293,9 +300,9 @@ class Site < ActiveRecord::Base
293
300
  @root ||= secure(Node) { Node.find(root_id) } || Node.new(:title => host)
294
301
  end
295
302
 
296
- # Return the orphan node.
297
- def orphan_node
298
- @orphan ||= secure(Node) { Node.find(orphan_id) } || Node.new(:title => host)
303
+ # Return the home node.
304
+ def home_node
305
+ @home ||= secure(Node) { Node.find(home_id) } || Node.new(:title => host)
299
306
  end
300
307
 
301
308
  # Return the public group: the one in which every visitor belongs.
@@ -383,19 +390,19 @@ class Site < ActiveRecord::Base
383
390
  @alias && @alias[:authentication] || self[:authentication]
384
391
  end
385
392
 
386
- def root_id
387
- @root_id ||= @alias && @alias[:root_id] || self[:root_id]
393
+ def home_id
394
+ @home_id ||= @alias && @alias[:home_id] || self[:home_id] || self[:root_id]
388
395
  end
389
396
 
390
- def root_zip
391
- root_node.zip
397
+ def home_zip
398
+ home_node.zip
392
399
  end
393
400
 
394
- def root_zip=(zip)
401
+ def home_zip=(zip)
395
402
  if id = secure(Node) { Node.translate_pseudo_id(zip) }
396
- self[:root_id] = id
403
+ self[:home_id] = id
397
404
  else
398
- @root_zip_error = _('could not be found')
405
+ @home_zip_error = _('could not be found')
399
406
  end
400
407
  end
401
408
 
@@ -404,8 +411,8 @@ class Site < ActiveRecord::Base
404
411
  ali = Site.new(self.attributes)
405
412
  ali.host = hostname
406
413
  ali.master_id = self.id
407
- ali.orphan_id = self.orphan_id
408
414
  ali.root_id = self.root_id
415
+ ali.home_id = self.home_id
409
416
  ali.prop = self.prop
410
417
  ali.save
411
418
  ali
@@ -605,9 +612,9 @@ class Site < ActiveRecord::Base
605
612
  self[:default_lang] = nil
606
613
  end
607
614
 
608
- if @root_zip_error
609
- errors.add('root_id', @root_zip_error)
610
- @root_zip_error = nil
615
+ if @home_zip_error
616
+ errors.add('root_id', @home_zip_error)
617
+ @home_zip_error = nil
611
618
  end
612
619
  end
613
620
 
@@ -405,7 +405,7 @@ class User < ActiveRecord::Base
405
405
 
406
406
  if !is_admin?
407
407
  # Make sure we remove dev_skin settings if user is not an admin.
408
- self[:dev_skin_id] = nil
408
+ self.dev_skin_id = nil
409
409
  end
410
410
  end
411
411
 
@@ -14,7 +14,7 @@
14
14
  <% end %>
15
15
  <table cellspacing='0' class='edit_site'>
16
16
  <tr><td class='label'><%= _('host') %></td><td><%= @site[:host] %></td></tr>
17
- <tr><td class='label'><%= _('root') %></td><td><%= text_field('site', :root_zip, :size=>15, :value => @site.root_zip) %></td></tr>
17
+ <tr><td class='label'><%= _('home') %></td><td><%= text_field('site', :home_zip, :size=>15, :value => @site.home_zip) %></td></tr>
18
18
  <% Site.attributes_for_form(@site.is_alias?)[:text].each do |name| -%>
19
19
  <tr><td class='label'><%= _(name) %></td><td><%= text_field('site', name, :size=>nil) %></td></tr>
20
20
  <% end -%>
@@ -5,7 +5,7 @@
5
5
  :method => :get) %></td>
6
6
  <td class="name"><%= li.host %></td>
7
7
  <% if !li.master_id %>
8
- <td class='root'><%= li.root_node.title.limit(10) %></td>
8
+ <td class='home'><%= li.home_node.title.limit(10) %></td>
9
9
  <% [:languages, :default_lang].each do |sym| -%>
10
10
  <td class="<%= sym %>"><%= li[sym] %></td>
11
11
  <% end -%>
@@ -15,6 +15,6 @@
15
15
  <td class='redit_time' ><%= li.redit_time %></td>
16
16
  <td class='options'><%= Site.attributes_for_form(li.is_alias?)[:bool].reject{|sym| !li.send(sym)}.join(', ') %></td>
17
17
  <% else %>
18
- <td colspan='8' class='root'><%= li.root_node.title %></td>
18
+ <td colspan='8' class='root'><%= li.home_node.title %></td>
19
19
  <% end -%>
20
20
  </tr>
@@ -15,12 +15,12 @@
15
15
  </head>
16
16
 
17
17
  <body do='void' name='body'>
18
- <div id='top' do='root' do='link'/>
18
+ <div id='top' do='home' do='link'/>
19
19
  <div id='header'>
20
20
  <div id='login' do='login_link'/>
21
21
  <div id='visitor'><r:visitor_link/> <r:if test='can_edit?' do='link' mode='admin' do='t'>btn_edit</r:if></div>
22
22
  <div id='search' do='search_box' type='search'/>
23
- <ol id='menu' do='root' do='pages'>
23
+ <ol id='menu' do='home' do='pages'>
24
24
  <li do='each' on_if='is_ancestor?(main)' do='link'/>
25
25
  </ol>
26
26
  </div>
@@ -3,7 +3,8 @@
3
3
 
4
4
  Examples:
5
5
 
6
- Bricks::Pdf.engine = 'Xhtml2pdf'
6
+ Bricks::Pdf.engine = 'prince'
7
+ Bricks::Pdf.cmd = '/usr/local/bin/prince'
7
8
 
8
9
  Bricks::Pdf.render_file "myfile.html" => STDOUT (strings)
9
10
  Bricks::Pdf.render_file "myfile.html", "out.pdf" => out.pdf (file)
@@ -2,8 +2,9 @@ module Bricks
2
2
  module Pdf
3
3
  module Engine
4
4
  module Prince
5
+ CMD = Bricks::CONFIG['pdf']['cmd'] || 'prince'
5
6
  def command(opts)
6
- cmd = ['prince']
7
+ cmd = [CMD]
7
8
  {
8
9
  :http_user => '--http-user=',
9
10
  :http_password => '--http-password=',
@@ -0,0 +1,11 @@
1
+ class RenameOrphanAndRootInSite < ActiveRecord::Migration
2
+ def self.up
3
+ rename_column :sites, :root_id, :home_id
4
+ rename_column :sites, :orphan_id, :root_id
5
+ end
6
+
7
+ def self.down
8
+ rename_column :sites, :root_id, :orphan_id
9
+ rename_column :sites, :home_id, :root_id
10
+ end
11
+ end
@@ -54,7 +54,12 @@ development:
54
54
  production:
55
55
  # Port used only to provide assets during custom rendering (pdf).
56
56
  # We need this to avoid deadlocks with round-robin based serving.
57
+ # Do not use with Passenger.
57
58
  # asset_port: 7999
59
+ #
60
+ # When external rendering engines (pdf) cannot get non-public assets, add the server ip to
61
+ # what Zena considers 'local'
62
+ # local_ips: 123.45.67.89, 127.0.0.1
58
63
  activity: ON
59
64
  cache_path: '/public/cache'
60
65
  mongrel: OFF
@@ -22,7 +22,7 @@ querybuilder: '= 1.2.2'
22
22
  yamltest: '= 0.7.0'
23
23
  safe_yaml: '= 0.8.0'
24
24
  rubyless: '= 0.8.10'
25
- property: '= 2.3.2'
25
+ property: '= 2.3.3'
26
26
  versions: '= 0.3.1'
27
27
 
28
28
  jeweler:
@@ -15,12 +15,12 @@
15
15
  </head>
16
16
 
17
17
  <body do='void' name='body'>
18
- <div id='top' do='root' do='link'/>
18
+ <div id='top' do='home' do='link'/>
19
19
  <div id='header'>
20
20
  <div id='login' do='login_link'/>
21
21
  <div id='visitor'><r:visitor_link/> <r:if test='can_edit?' do='link' mode='admin' do='t'>btn_edit</r:if></div>
22
22
  <div id='search' do='search_box' type='search'/>
23
- <ol id='menu' do='root' do='pages'>
23
+ <ol id='menu' do='home' do='pages'>
24
24
  <li do='each' on_if='is_ancestor?(main)' do='link'/>
25
25
  </ol>
26
26
  </div>
@@ -21,6 +21,8 @@ module Zena
21
21
  end
22
22
 
23
23
  ASSET_PORT = Bricks.raw_config['asset_port'].to_i
24
+ LOCAL_IPS = ((Bricks.raw_config['local_ips'] || '').split(',').map(&:strip) + %w{127.0.0.1 ::1}).uniq
25
+
24
26
 
25
27
  ENABLE_LATEX = true && has_executable('pdflatex') # enable LateX post-rendering
26
28
  ENABLE_FOP = true && has_executable('fop', 'xsltproc') # enable xsl-fo post-rendering
@@ -10,7 +10,7 @@ module Zena
10
10
  activate_authlogic
11
11
  end
12
12
 
13
- def login(fixture)
13
+ def login(fixture, site_name = nil)
14
14
  super
15
15
  if defined?(@controller)
16
16
  @controller.class_eval do
@@ -1,4 +1,4 @@
1
1
  module Zena
2
- VERSION = '1.2.5'
2
+ VERSION = '1.2.6'
3
3
  ROOT = File.expand_path(File.join(File.dirname(__FILE__), '..', '..'))
4
4
  end
@@ -10,7 +10,7 @@ module Zena
10
10
  TITLE_ML_JOIN = %Q{INNER JOIN idx_nodes_ml_strings AS id1 ON id1.node_id = nodes.id AND id1.key = 'title'}
11
11
 
12
12
  # (slow). Find a node by it's path. This is used during node importation when stored as zml files or to resolve custom_base url until we have an "alias" table.
13
- def find_by_path(path, parent_id = current_site.orphan_id, multilingual = false)
13
+ def find_by_path(path, parent_id = current_site.root_id, multilingual = false)
14
14
  res = nil
15
15
  path = path.split('/') unless path.kind_of?(Array)
16
16
  last = path.size - 1
@@ -86,11 +86,11 @@ module Zena
86
86
  User.find_by_single_access_token(user_token)
87
87
  end
88
88
  end
89
-
89
+
90
90
  # Create a fake cookie based on HTTP_AUTH using session_id and render_token. This is
91
91
  # only used for requests from localhost (asset host).
92
92
  def forge_cookie_with_http_auth
93
- if (request.headers['REMOTE_ADDR'] == '127.0.0.1' || request.headers['REMOTE_ADDR'] == '::1') &&
93
+ if Zena::LOCAL_IPS.include?(request.headers['REMOTE_ADDR']) &&
94
94
  (Zena::ASSET_PORT.to_i == 0 || request.port.to_i == Zena::ASSET_PORT)
95
95
  authenticate_with_http_basic do |login, password|
96
96
  # login = visitor.id
@@ -546,9 +546,15 @@ module Zena
546
546
  when 'root'
547
547
  # Special pseudo-context
548
548
  add_table(main_table)
549
- set_main_class(VirtualClass['Project'])
549
+ set_main_class(current_site.root_node.vclass)
550
550
  add_filter "#{table}.id = #{current_site.root_id}"
551
551
  return true
552
+ when 'home'
553
+ # Special pseudo-context
554
+ add_table(main_table)
555
+ set_main_class(current_site.home_node.vclass)
556
+ add_filter "#{table}.id = #{current_site.home_id}"
557
+ return true
552
558
  #when 'author', 'traductions', 'versions'
553
559
  # # TODO: not implemented yet...
554
560
  # return nil
@@ -7,11 +7,17 @@ module Zena
7
7
  include Zena::Use::Upload::UploadedFile
8
8
 
9
9
  # Set visitor for unit testing
10
- def login(fixture)
10
+ def login(fixture, site_name = nil)
11
11
  user = users(fixture)
12
- setup_visitor(user, user.site)
12
+ if site_name
13
+ site = Site.setup_master(Site.find_by_name(site_name))
14
+ else
15
+ # Not an alias
16
+ site = user.site
17
+ end
18
+ setup_visitor(user, site)
13
19
  user.ip = '10.0.0.44'
14
- $_test_site = user.site.name
20
+ $_test_site = site.name
15
21
  ::I18n.locale = user.lang
16
22
  end
17
23