zena 1.2.5 → 1.2.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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