zena 1.2.4 → 1.2.5
Sign up to get free protection for your applications and to get access to all the features.
- data/History.txt +18 -0
- data/app/controllers/nodes_controller.rb +11 -6
- data/app/controllers/sites_controller.rb +3 -2
- data/app/controllers/user_sessions_controller.rb +1 -1
- data/app/controllers/virtual_classes_controller.rb +3 -2
- data/app/models/document.rb +2 -2
- data/app/models/node.rb +6 -1
- data/app/models/note.rb +3 -27
- data/app/models/role.rb +11 -5
- data/app/models/site.rb +140 -43
- data/app/models/string_hash.rb +2 -0
- data/app/models/user.rb +9 -4
- data/app/models/user_session.rb +1 -1
- data/app/models/virtual_class.rb +49 -18
- data/app/views/sites/_form.erb +7 -4
- data/app/views/sites/_li.erb +15 -9
- data/app/views/users/_li.rhtml +3 -0
- data/app/views/users/index.rhtml +1 -1
- data/app/views/virtual_classes/_form.erb +1 -1
- data/bricks/acls/zena/init.rb +1 -2
- data/bricks/acls/zena/test/sites/erebus/roles.yml +4 -0
- data/bricks/activity/lib/bricks/activity.rb +24 -0
- data/bricks/activity/zena/migrate/20130711135905_add_activity_to_user.rb +9 -0
- data/bricks/activity/zena/test/integration/activity_integration_test.rb +29 -0
- data/bricks/captcha/zena/init.rb +0 -3
- data/bricks/fs_skin/lib/bricks/fs_skin.rb +3 -3
- data/bricks/fs_skin/zena/skins/blog/Node.zafu +1 -1
- data/bricks/fs_skin/zena/tasks.rb +2 -2
- data/bricks/fs_skin/zena/test/integration/fs_skin_integration_test.rb +2 -2
- data/bricks/fs_skin/zena/test/unit/fs_skin_test.rb +1 -1
- data/bricks/math/zena/init.rb +0 -3
- data/bricks/pdf/zena/init.rb +1 -5
- data/bricks/worker/zena/init.rb +0 -2
- data/bricks/zena/zena/migrate/20130617164527_add_master_id_to_site.rb +13 -0
- data/bricks/zena/zena/migrate/20130712081512_alter_login_users.rb +9 -0
- data/config/bricks.yml +4 -1
- data/lib/bricks/loader.rb +17 -9
- data/lib/tasks/zena.rake +40 -5
- data/lib/zafu/process/ruby_less_processing.rb +3 -5
- data/lib/zena.rb +2 -0
- data/lib/zena/acts/secure.rb +11 -2
- data/lib/zena/console.rb +5 -4
- data/lib/zena/core_ext/string.rb +2 -2
- data/lib/zena/deploy.rb +22 -6
- data/lib/zena/deploy/logrotate_app.rhtml +10 -7
- data/lib/zena/deploy/logrotate_host.rhtml +21 -26
- data/lib/zena/deploy/vhost.rhtml +3 -3
- data/lib/zena/foxy_parser.rb +1 -1
- data/lib/zena/info.rb +1 -1
- data/lib/zena/site_worker.rb +2 -2
- data/lib/zena/use.rb +0 -1
- data/lib/zena/use/ancestry.rb +1 -1
- data/lib/zena/use/authlogic.rb +2 -1
- data/lib/zena/use/display.rb +6 -0
- data/lib/zena/use/query_builder.rb +1 -1
- data/lib/zena/use/query_node.rb +3 -3
- data/lib/zena/use/rendering.rb +47 -13
- data/lib/zena/use/test_helper.rb +1 -1
- data/lib/zena/use/urls.rb +6 -104
- data/lib/zena/use/zafu_safe_definitions.rb +9 -4
- data/lib/zena/use/zafu_templates.rb +1 -0
- data/locale/app.pot +4 -0
- data/locale/de/LC_MESSAGES/zena.mo +0 -0
- data/locale/de/zena.po +6 -2
- data/locale/en/LC_MESSAGES/zena.mo +0 -0
- data/locale/en/zena.po +6 -2
- data/locale/fr/LC_MESSAGES/zena.mo +0 -0
- data/locale/fr/zena.po +5 -1
- data/locale/it/LC_MESSAGES/zena.mo +0 -0
- data/locale/it/zena.po +6 -2
- data/locale/zena.pot +4 -0
- data/test/functional/nodes_controller_test.rb +2 -133
- data/test/functional/sites_controller_test.rb +1 -1
- data/test/integration/multiple_hosts_test.rb +2 -1
- data/test/integration/navigation_test.rb +37 -0
- data/test/integration/query_node/basic.yml +1 -1
- data/test/integration/zafu_compiler/ajax.yml +7 -0
- data/test/integration/zafu_compiler/comments.yml +2 -2
- data/test/integration/zafu_compiler/context.yml +6 -2
- data/test/integration/zafu_compiler/display.yml +16 -4
- data/test/integration/zafu_compiler/forms.yml +1 -0
- data/test/integration/zafu_compiler/query.yml +7 -1
- data/test/integration/zafu_compiler/relations.yml +12 -7
- data/test/integration/zafu_compiler/roles.yml +3 -3
- data/test/integration/zafu_compiler/rubyless.yml +1 -2
- data/test/integration/zafu_compiler/safe_definitions.yml +5 -0
- data/test/sites/complex/roles.yml +1 -1
- data/test/sites/ocean/roles.yml +4 -0
- data/test/sites/zena/columns.yml +3 -1
- data/test/sites/zena/roles.yml +5 -1
- data/test/sites/zena/sites.yml +22 -0
- data/test/unit/document_test.rb +14 -0
- data/test/unit/node_test.rb +14 -0
- data/test/unit/role_test.rb +19 -4
- data/test/unit/site_test.rb +67 -0
- data/test/unit/user_test.rb +20 -0
- data/test/unit/virtual_class_test.rb +116 -11
- data/test/unit/zena/use/rendering_test.rb +1 -1
- data/zena.gemspec +67 -66
- metadata +126 -125
- data/bricks/fs_skin/zena/init.rb +0 -1
- data/bricks/grid/zena/init.rb +0 -4
- data/bricks/single/zena/init.rb +0 -1
- data/bricks/spreadsheet/zena/init.rb +0 -3
data/History.txt
CHANGED
@@ -1,3 +1,21 @@
|
|
1
|
+
== 1.2.5 2013-07-15
|
2
|
+
|
3
|
+
* Major changes
|
4
|
+
* To support video streaming: redirect on first document cache. WARNING: This
|
5
|
+
implies changes to vhost files !
|
6
|
+
* WARN: Properties in list context do not resolve with first element anymore. "first" prefix needed.
|
7
|
+
* Enable VirtualClass on native classes !
|
8
|
+
* Added 'activity' brick which records visitor's last "seen_at" date. <== TODO: Document
|
9
|
+
|
10
|
+
* Minor changes
|
11
|
+
* Fixed encode_params in Ajax requests.
|
12
|
+
* Fixed cached path in vhost file.
|
13
|
+
* Added "uuid" method (generates a unique id). <== TODO: Document
|
14
|
+
* Added support for JSON String in [string_hash] <== TODO: Document
|
15
|
+
* Added 'login_info' to Node.
|
16
|
+
* Added 'group_names' to User class.
|
17
|
+
* Fixed [headers] when 'Status' is set (change to redirect on 300).
|
18
|
+
|
1
19
|
== 1.2.4 2013-06-13
|
2
20
|
|
3
21
|
* Major changes
|
@@ -203,14 +203,19 @@ class NodesController < ApplicationController
|
|
203
203
|
else
|
204
204
|
content_path = @node.filepath
|
205
205
|
end
|
206
|
-
|
206
|
+
|
207
|
+
# content_path is used to cache by creating a symlink
|
208
|
+
cache_ok = cache_page(:content_path => content_path, :authenticated => @node.v_public?)
|
209
|
+
|
207
210
|
if content_path
|
208
|
-
|
209
|
-
|
211
|
+
if @node.v_public? && cache_ok
|
212
|
+
# This is the simplest working solution to save cached version and use apache for serving (all xsendfile and such do not work with video streaming).
|
213
|
+
redirect_to data_path(@node, :mode => params[:mode]) + "?1"
|
214
|
+
else
|
215
|
+
# FIXME RAILS: remove 'stream => false' when rails streaming is fixed
|
216
|
+
send_file(content_path, :filename => @node.filename, :type => @node.content_type, :disposition => 'inline', :stream => false, :x_sendfile => ENABLE_XSENDFILE)
|
217
|
+
end
|
210
218
|
end
|
211
|
-
|
212
|
-
# content_path is used to cache by creating a symlink
|
213
|
-
cache_page(:content_path => content_path, :authenticated => @node.v_public?)
|
214
219
|
else
|
215
220
|
render_and_cache
|
216
221
|
# FIXME: redirect to document format should occur in render_and_cache
|
@@ -58,7 +58,7 @@ class UserSessionsController < ApplicationController
|
|
58
58
|
raise ActiveRecord::RecordNotFound.new("host not found #{request.host}")
|
59
59
|
end
|
60
60
|
|
61
|
-
|
61
|
+
setup_visitor(anonymous_visitor(site), site)
|
62
62
|
end
|
63
63
|
|
64
64
|
def redirect_after_login
|
@@ -10,11 +10,12 @@ class VirtualClassesController < ApplicationController
|
|
10
10
|
secure(::Role) do
|
11
11
|
@virtual_classes = ::Role.paginate(:all, :order => 'kpath', :per_page => 200, :page => params[:page])
|
12
12
|
end
|
13
|
-
|
13
|
+
|
14
|
+
list = @virtual_classes.map(&:name)
|
14
15
|
if last = @virtual_classes.last
|
15
16
|
last_kpath = last.kpath
|
16
17
|
Node.native_classes.each do |kpath, klass|
|
17
|
-
if kpath < last_kpath
|
18
|
+
if kpath < last_kpath && !list.include?(klass.name)
|
18
19
|
@virtual_classes << klass
|
19
20
|
end
|
20
21
|
end
|
data/app/models/document.rb
CHANGED
@@ -124,7 +124,7 @@ class Document < Node
|
|
124
124
|
# Try to find a virtual sub-class accepting the content type
|
125
125
|
vclass = nil
|
126
126
|
VirtualClass[base.to_s].sub_classes.each do |v|
|
127
|
-
next if v.real_class
|
127
|
+
next if v.real_class != base
|
128
128
|
|
129
129
|
if content_type =~ v.content_type_re
|
130
130
|
vclass = v
|
@@ -207,7 +207,7 @@ class Document < Node
|
|
207
207
|
end
|
208
208
|
end
|
209
209
|
|
210
|
-
# Make sure the new file
|
210
|
+
# Make sure the new file is OK with current class.
|
211
211
|
def valid_content_type
|
212
212
|
return true unless prop.content_type_changed?
|
213
213
|
|
data/app/models/node.rb
CHANGED
@@ -225,7 +225,8 @@ class Node < ActiveRecord::Base
|
|
225
225
|
:data_b => {:class => ['DataEntry'], :zafu => {:data_root => 'node_b'}},
|
226
226
|
:data_c => {:class => ['DataEntry'], :zafu => {:data_root => 'node_c'}},
|
227
227
|
:data_d => {:class => ['DataEntry'], :zafu => {:data_root => 'node_d'}},
|
228
|
-
:traductions => ['Version'], :discussion => 'Discussion'
|
228
|
+
:traductions => ['Version'], :discussion => 'Discussion',
|
229
|
+
:login_info => 'User'
|
229
230
|
|
230
231
|
# we use safe_method because the columns can be null, but the values are never null
|
231
232
|
safe_method :kpath => String, :user_zip => Number, :user_id => Number,
|
@@ -1205,6 +1206,10 @@ class Node < ActiveRecord::Base
|
|
1205
1206
|
def user
|
1206
1207
|
secure!(User) { o_user }
|
1207
1208
|
end
|
1209
|
+
|
1210
|
+
def login_info
|
1211
|
+
secure(User) { User.find(:first, :conditions => {:node_id => self.id})}
|
1212
|
+
end
|
1208
1213
|
|
1209
1214
|
# Find all data entries linked to the current node
|
1210
1215
|
def data
|
data/app/models/note.rb
CHANGED
@@ -1,33 +1,9 @@
|
|
1
1
|
=begin rdoc
|
2
|
-
|
3
|
-
|
4
|
-
=== dates
|
5
|
-
|
6
|
-
On top of the Node's dates (+created_at+, +updated_at+, +publish_from+), a note uses the following:
|
7
|
-
|
8
|
-
log_at:: used to sort/display blog entries
|
9
|
-
event_at:: used in calendars
|
10
|
-
|
11
|
-
These two dates enable you to announce an event in the blog list a couple of days before it actually occurs (event_at). All dates are stored internally as 'utc' and are converted to/from the visitor's current timezone.
|
12
|
-
|
13
|
-
=== links
|
14
|
-
|
15
|
-
Default links for Notes are:
|
16
|
-
|
17
|
-
calendars:: make this note appear in the given calendar (there is one calendar per project). By default the note is not included in its project's calendar.
|
18
|
-
projects:: make this note appear in the blog of the given project. A note always appear in its project.
|
19
|
-
|
20
|
-
=== subclasses
|
21
|
-
|
22
|
-
|
23
|
-
=== subclasses to implement before 1.0
|
24
|
-
Task:: manage things to be done (parent = Note = Todo). The parent provides the 'due date'.
|
25
|
-
Letter:: like the name says...
|
26
|
-
Request:: subclass of Todo. Manage user/client requests.
|
27
|
-
Bug:: (the class we most need!). subclass of Request.
|
28
|
-
Milestone:: special event used when choosing a Request/Bug's parent.
|
2
|
+
This class is not really useful anymore since 'event_at' and 'log_at' are obsolete. This class is really used for
|
3
|
+
testing having a virtual class 'Note' with a real ruby class of the same Name.
|
29
4
|
=end
|
30
5
|
class Note < Node
|
6
|
+
|
31
7
|
class << self
|
32
8
|
|
33
9
|
def select_classes
|
data/app/models/role.rb
CHANGED
@@ -271,12 +271,18 @@ class Role < ActiveRecord::Base
|
|
271
271
|
|
272
272
|
def validate_role
|
273
273
|
errors.add('base', 'You do not have the rights to change roles.') unless visitor.is_admin?
|
274
|
-
if new_record?
|
275
|
-
errors.add('superclass', 'invalid') unless @superclass.kind_of?(VirtualClass) && @superclass.kpath
|
276
|
-
end
|
277
274
|
|
278
|
-
if
|
279
|
-
self.kpath =
|
275
|
+
if name == 'Node'
|
276
|
+
self.kpath = 'N'
|
277
|
+
errors.add('base', 'cannot create role of name "Node"') if self.class == ::Role
|
278
|
+
else
|
279
|
+
if new_record?
|
280
|
+
errors.add('superclass', 'invalid') unless @superclass.kind_of?(VirtualClass) && @superclass.kpath
|
281
|
+
end
|
282
|
+
|
283
|
+
if @superclass && self.class == ::Role
|
284
|
+
self.kpath = @superclass.kpath
|
285
|
+
end
|
280
286
|
end
|
281
287
|
end
|
282
288
|
|
data/app/models/site.rb
CHANGED
@@ -6,7 +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
|
-
+
|
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.
|
10
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.
|
11
12
|
+public_group_id+:: Id of the 'public' group. Every user of the site (with 'anonymous user') belongs to this group.
|
12
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.
|
@@ -16,6 +17,7 @@ The #Site model holds configuration information for a site:
|
|
16
17
|
+default_lang+:: The default language of the site.
|
17
18
|
=end
|
18
19
|
class Site < ActiveRecord::Base
|
20
|
+
attr_accessor :alias # = site alias (different settings + domain)
|
19
21
|
CLEANUP_SQL = [
|
20
22
|
['attachments' , 'site_id = ?'],
|
21
23
|
['cached_pages' , 'site_id = ?'],
|
@@ -54,12 +56,13 @@ class Site < ActiveRecord::Base
|
|
54
56
|
CACHE_PATH = Bricks.raw_config['cache_path'] || '/public'
|
55
57
|
|
56
58
|
include RubyLess
|
57
|
-
safe_method :host
|
58
|
-
safe_method :root
|
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}}
|
59
62
|
|
60
63
|
validate :valid_site
|
61
64
|
validates_uniqueness_of :host
|
62
|
-
attr_accessible :name, :languages, :default_lang, :authentication, :http_auth, :ssl_on_auth, :auto_publish, :redit_time, :api_group_id
|
65
|
+
attr_accessible :name, :languages, :default_lang, :authentication, :http_auth, :ssl_on_auth, :auto_publish, :redit_time, :api_group_id, :root_zip
|
63
66
|
has_many :groups, :order => "name"
|
64
67
|
has_many :nodes
|
65
68
|
has_many :users
|
@@ -74,7 +77,12 @@ class Site < ActiveRecord::Base
|
|
74
77
|
|
75
78
|
@@attributes_for_form = {
|
76
79
|
:bool => %w{authentication http_auth auto_publish ssl_on_auth},
|
77
|
-
:text => %w{
|
80
|
+
:text => %w{languages default_lang},
|
81
|
+
}
|
82
|
+
|
83
|
+
@@alias_attributes_for_form = {
|
84
|
+
:bool => %w{authentication auto_publish ssl_on_auth},
|
85
|
+
:text => %w{},
|
78
86
|
}
|
79
87
|
|
80
88
|
class << self
|
@@ -117,7 +125,7 @@ class Site < ActiveRecord::Base
|
|
117
125
|
:lang => site.default_lang, :status => User::Status[:admin])
|
118
126
|
admin_user.site = site
|
119
127
|
|
120
|
-
|
128
|
+
setup_visitor(admin_user, site)
|
121
129
|
|
122
130
|
unless admin_user.save
|
123
131
|
# rollback
|
@@ -174,6 +182,8 @@ class Site < ActiveRecord::Base
|
|
174
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)
|
175
183
|
|
176
184
|
site.root_id = root[:id]
|
185
|
+
site.orphan_id = root[:id]
|
186
|
+
|
177
187
|
# Make sure safe definitions on Time/Array/String are available on prop_eval validation.
|
178
188
|
Zena::Use::ZafuSafeDefinitions
|
179
189
|
# Should not be needed since we load PropEval in Node, but it does not work
|
@@ -210,15 +220,27 @@ class Site < ActiveRecord::Base
|
|
210
220
|
site.instance_variable_set(:@being_created, false)
|
211
221
|
site
|
212
222
|
end
|
223
|
+
|
224
|
+
def master_sites
|
225
|
+
Site.all(:conditions => ['master_id is NULL'])
|
226
|
+
end
|
213
227
|
|
214
228
|
def find_by_host(host)
|
215
229
|
host = $1 if host =~ /^(.*)\.$/
|
216
|
-
self.find(:first, :conditions => ['host = ?', host]) rescue nil
|
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
|
237
|
+
end
|
238
|
+
site
|
217
239
|
end
|
218
240
|
|
219
241
|
# List of attributes that can be configured in the admin form
|
220
|
-
def attributes_for_form
|
221
|
-
@@attributes_for_form
|
242
|
+
def attributes_for_form(is_alias = false)
|
243
|
+
is_alias ? @@alias_attributes_for_form : @@attributes_for_form
|
222
244
|
end
|
223
245
|
end
|
224
246
|
|
@@ -229,31 +251,31 @@ class Site < ActiveRecord::Base
|
|
229
251
|
Site.attributes_for_form[:text] << 'usr_prototype_attributes'
|
230
252
|
Site.attributes_for_form[:bool] << 'expire_in_dev'
|
231
253
|
attr_accessible :usr_prototype_attributes, :expire_in_dev
|
232
|
-
|
254
|
+
|
233
255
|
# Return path for static/cached content served by proxy: RAILS_ROOT/sites/_host_/public
|
234
256
|
# If you need to serve from another directory, we do not store the path into the sites table
|
235
257
|
# for security reasons. The easiest way around this limitation is to symlink the 'public' directory.
|
236
258
|
def public_path
|
237
|
-
"/#{
|
259
|
+
"/#{host}#{PUBLIC_PATH}"
|
238
260
|
end
|
239
261
|
|
240
262
|
# This is the place where cached files should be stored in case we do not want
|
241
263
|
# to store the cached file inside the public directory.
|
242
264
|
def cache_path
|
243
|
-
"/#{
|
265
|
+
"/#{host}#{CACHE_PATH}"
|
244
266
|
end
|
245
267
|
|
246
268
|
# Return path for documents data: RAILS_ROOT/sites/_host_/data
|
247
269
|
# You can symlink the 'data' directory if you need to keep the data in some other place.
|
248
270
|
def data_path
|
249
|
-
"/#{
|
271
|
+
"/#{master_host}/data"
|
250
272
|
end
|
251
273
|
|
252
274
|
# Return the path for zafu rendered templates: RAILS_ROOT/sites/_host_/zafu
|
253
275
|
def zafu_path
|
254
|
-
"/#{
|
276
|
+
"/#{master_host}/zafu"
|
255
277
|
end
|
256
|
-
|
278
|
+
|
257
279
|
# Return the anonymous user, the one used by anonymous visitors to visit the public part
|
258
280
|
# of the site.
|
259
281
|
def anon
|
@@ -268,8 +290,12 @@ class Site < ActiveRecord::Base
|
|
268
290
|
# Return the root node or a dummy if the visitor cannot view root
|
269
291
|
# node (such as during a 404 or login rendering).
|
270
292
|
def root_node
|
271
|
-
@root ||= secure(Node) { Node.find(
|
272
|
-
|
293
|
+
@root ||= secure(Node) { Node.find(root_id) } || Node.new(:title => host)
|
294
|
+
end
|
295
|
+
|
296
|
+
# Return the orphan node.
|
297
|
+
def orphan_node
|
298
|
+
@orphan ||= secure(Node) { Node.find(orphan_id) } || Node.new(:title => host)
|
273
299
|
end
|
274
300
|
|
275
301
|
# Return the public group: the one in which every visitor belongs.
|
@@ -298,16 +324,6 @@ class Site < ActiveRecord::Base
|
|
298
324
|
@admin_user_ids ||= secure!(User) { User.find(:all, :conditions => "status >= #{User::Status[:admin]}") }.map {|r| r[:id]}
|
299
325
|
end
|
300
326
|
|
301
|
-
# Return true if the site is configured to force authentication
|
302
|
-
def authentication?
|
303
|
-
self[:authentication]
|
304
|
-
end
|
305
|
-
|
306
|
-
# Return true if the site is configured to automatically publish redactions
|
307
|
-
def auto_publish?
|
308
|
-
self[:auto_publish]
|
309
|
-
end
|
310
|
-
|
311
327
|
# Set redit time from a string of the form "1d 4h 5s" or "4 days"
|
312
328
|
def redit_time=(val)
|
313
329
|
if val.kind_of?(String)
|
@@ -337,6 +353,64 @@ class Site < ActiveRecord::Base
|
|
337
353
|
def lang_list
|
338
354
|
(self[:languages] || "").split(',').map(&:strip)
|
339
355
|
end
|
356
|
+
|
357
|
+
###### Alias handling
|
358
|
+
def is_alias?
|
359
|
+
!self[:master_id].blank?
|
360
|
+
end
|
361
|
+
|
362
|
+
# This is the host of the master site.
|
363
|
+
def master_host
|
364
|
+
self[:host]
|
365
|
+
end
|
366
|
+
|
367
|
+
# Host with aliasing (returns alias host if alias is loaded)
|
368
|
+
def host
|
369
|
+
@alias && @alias.host || master_host
|
370
|
+
end
|
371
|
+
|
372
|
+
def ssl_on_auth
|
373
|
+
@alias && @alias.prop['ssl_on_auth'] || self.prop['ssl_on_auth']
|
374
|
+
end
|
375
|
+
|
376
|
+
# Return true if the site is configured to automatically publish redactions
|
377
|
+
def auto_publish?
|
378
|
+
@alias && @alias[:auto_publish] || self[:auto_publish]
|
379
|
+
end
|
380
|
+
|
381
|
+
# Return true if the site is configured to force authentication
|
382
|
+
def authentication?
|
383
|
+
@alias && @alias[:authentication] || self[:authentication]
|
384
|
+
end
|
385
|
+
|
386
|
+
def root_id
|
387
|
+
@root_id ||= @alias && @alias[:root_id] || self[:root_id]
|
388
|
+
end
|
389
|
+
|
390
|
+
def root_zip
|
391
|
+
root_node.zip
|
392
|
+
end
|
393
|
+
|
394
|
+
def root_zip=(zip)
|
395
|
+
if id = secure(Node) { Node.translate_pseudo_id(zip) }
|
396
|
+
self[:root_id] = id
|
397
|
+
else
|
398
|
+
@root_zip_error = _('could not be found')
|
399
|
+
end
|
400
|
+
end
|
401
|
+
|
402
|
+
def create_alias(hostname)
|
403
|
+
raise "Hostname '#{hostname}' already exists" if Site.find_by_host(hostname)
|
404
|
+
ali = Site.new(self.attributes)
|
405
|
+
ali.host = hostname
|
406
|
+
ali.master_id = self.id
|
407
|
+
ali.orphan_id = self.orphan_id
|
408
|
+
ali.root_id = self.root_id
|
409
|
+
ali.prop = self.prop
|
410
|
+
ali.save
|
411
|
+
ali
|
412
|
+
end
|
413
|
+
######
|
340
414
|
|
341
415
|
def being_created?
|
342
416
|
@being_created
|
@@ -383,24 +457,36 @@ class Site < ActiveRecord::Base
|
|
383
457
|
end
|
384
458
|
|
385
459
|
def clear_cache(clear_zafu = true)
|
386
|
-
|
387
|
-
Site.
|
460
|
+
paths = ["#{SITES_ROOT}#{self.cache_path}"]
|
461
|
+
aliases = Site.all(:conditions => {:master_id => self.id})
|
462
|
+
aliases.each do |site|
|
463
|
+
paths << "#{SITES_ROOT}#{site.cache_path}"
|
464
|
+
end
|
465
|
+
Site.logger.error("\n-----------------\nCLEAR CACHE FOR SITE #{host} (#{aliases.map(&:host).join(', ')})\n-----------------\n")
|
388
466
|
|
389
|
-
|
390
|
-
|
391
|
-
|
392
|
-
|
393
|
-
|
467
|
+
paths.each do |path|
|
468
|
+
if File.exist?(path)
|
469
|
+
Dir.foreach(path) do |elem|
|
470
|
+
next unless elem =~ /^(\w\w\.html|\w\w|login\.html)$/
|
471
|
+
FileUtils.rmtree(File.join(path, elem))
|
472
|
+
end
|
394
473
|
|
395
|
-
|
396
|
-
|
397
|
-
|
474
|
+
Zena::Db.execute "DELETE FROM caches WHERE site_id = #{self[:id]}"
|
475
|
+
Zena::Db.execute "DELETE FROM cached_pages_nodes WHERE cached_pages_nodes.node_id IN (SELECT nodes.id FROM nodes WHERE nodes.site_id = #{self[:id]})"
|
476
|
+
Zena::Db.execute "DELETE FROM cached_pages WHERE site_id = #{self[:id]}"
|
477
|
+
end
|
398
478
|
end
|
399
|
-
|
479
|
+
|
480
|
+
# Clear zafu
|
400
481
|
if clear_zafu
|
401
|
-
|
402
|
-
|
403
|
-
|
482
|
+
paths = ["#{SITES_ROOT}#{self.zafu_path}"]
|
483
|
+
aliases.each do |site|
|
484
|
+
paths << "#{SITES_ROOT}#{site.cache_path}"
|
485
|
+
end
|
486
|
+
paths.each do |path|
|
487
|
+
if File.exist?(path)
|
488
|
+
FileUtils.rmtree(path)
|
489
|
+
end
|
404
490
|
end
|
405
491
|
end
|
406
492
|
|
@@ -510,8 +596,19 @@ class Site < ActiveRecord::Base
|
|
510
596
|
private
|
511
597
|
def valid_site
|
512
598
|
errors.add(:host, 'invalid') if self[:host].nil? || (self[:host] =~ /^\./) || (self[:host] =~ /[^\w\.\-]/)
|
513
|
-
|
514
|
-
|
599
|
+
|
600
|
+
if !is_alias?
|
601
|
+
errors.add(:languages, 'invalid') unless self[:languages].split(',').inject(true){|i,l| (i && l =~ /^\w\w$/)}
|
602
|
+
errors.add(:default_lang, 'invalid') unless self[:languages].split(',').include?(self[:default_lang])
|
603
|
+
else
|
604
|
+
self[:languages] = nil
|
605
|
+
self[:default_lang] = nil
|
606
|
+
end
|
607
|
+
|
608
|
+
if @root_zip_error
|
609
|
+
errors.add('root_id', @root_zip_error)
|
610
|
+
@root_zip_error = nil
|
611
|
+
end
|
515
612
|
end
|
516
613
|
|
517
614
|
end
|