zena 1.0.0.beta2 → 1.0.0.beta3
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +2 -0
- data/History.txt +12 -0
- data/app/controllers/application_controller.rb +0 -1
- data/app/controllers/columns_controller.rb +11 -1
- data/app/controllers/nodes_controller.rb +79 -19
- data/app/controllers/versions_controller.rb +0 -2
- data/app/controllers/virtual_classes_controller.rb +19 -6
- data/app/models/column.rb +5 -1
- data/app/models/comment.rb +1 -6
- data/app/models/node.rb +21 -3
- data/app/models/role.rb +21 -0
- data/app/models/site.rb +7 -2
- data/app/models/template.rb +3 -3
- data/app/models/text_document.rb +4 -4
- data/app/models/user.rb +21 -8
- data/app/views/columns/_li.html.erb +1 -0
- data/app/views/nodes/_groups.rhtml +1 -1
- data/app/views/sites/_form.erb +3 -1
- data/app/views/sites/_li.erb +1 -0
- data/app/views/sites/index.erb +1 -1
- data/app/views/virtual_classes/_form.erb +11 -2
- data/app/views/virtual_classes/_li.erb +5 -2
- data/bin/zena +1 -1
- data/bricks/math/lib/bricks/math.rb +1 -1
- data/bricks/mongrel/README +3 -0
- data/bricks/mongrel/zena/deploy.rb +56 -0
- data/bricks/passenger/README +3 -0
- data/bricks/passenger/zena/deploy.rb +49 -0
- data/config/bricks.yml +6 -0
- data/config/deploy.rb +24 -18
- data/config/gems.yml +3 -3
- data/db/migrate/20100915062903_add_api_group_id_to_site.rb +9 -0
- data/lib/tasks/zena.rake +39 -35
- data/lib/zena.rb +5 -6
- data/lib/zena/acts/enrollable.rb +37 -6
- data/lib/zena/app.rb +4 -2
- data/lib/zena/deploy.rb +110 -150
- data/lib/zena/deploy/awstats.conf.rhtml +4 -4
- data/lib/zena/deploy/httpd.rhtml +2 -1
- data/lib/zena/deploy/stats.vhost.rhtml +7 -7
- data/lib/zena/deploy/vhost.rhtml +1 -1
- data/lib/zena/deploy/vhost_www.rhtml +4 -4
- data/lib/zena/foxy_parser.rb +6 -5
- data/lib/zena/info.rb +1 -1
- data/lib/zena/integration/test_case.rb +8 -3
- data/lib/zena/parser.rb +11 -11
- data/lib/zena/parser/zafu_tags.rb +2 -2
- data/lib/zena/remote.rb +16 -0
- data/lib/zena/remote/connection.rb +67 -0
- data/lib/zena/remote/interface.rb +405 -0
- data/lib/zena/remote/klass.rb +14 -0
- data/lib/zena/remote/mock.rb +58 -0
- data/lib/zena/remote/node.rb +76 -0
- data/lib/zena/routes.rb +2 -1
- data/lib/zena/use.rb +9 -4
- data/lib/zena/use/ajax.rb +3 -3
- data/lib/zena/use/authlogic.rb +8 -1
- data/lib/zena/use/context.rb +22 -21
- data/lib/zena/use/dates.rb +26 -3
- data/lib/zena/use/display.rb +33 -5
- data/lib/zena/use/forms.rb +90 -12
- data/lib/zena/use/fulltext.rb +1 -1
- data/lib/zena/use/i18n.rb +118 -31
- data/lib/zena/use/query_builder.rb +7 -5
- data/lib/zena/use/query_node.rb +30 -4
- data/lib/zena/use/rendering.rb +1 -1
- data/lib/zena/use/search.rb +10 -7
- data/lib/zena/use/urls.rb +3 -3
- data/lib/zena/use/zafu_attributes.rb +2 -2
- data/lib/zena/use/zafu_eval.rb +1 -1
- data/lib/zena/use/zafu_safe_definitions.rb +1 -0
- data/lib/zena/use/zafu_templates.rb +1 -1
- data/lib/zena/zafu_compiler.rb +5 -1
- data/public/javascripts/zena.js +4 -4
- data/public/stylesheets/admin.css +1 -0
- data/test/custom_queries/complex.host.yml +3 -3
- data/test/fixtures/files/translations_fr.yml +4 -1
- data/test/functional/application_controller_test.rb +2 -2
- data/test/functional/nodes_controller_test.rb +57 -5
- data/test/functional/users_controller_test.rb +10 -9
- data/test/functional/virtual_classes_controller_test.rb +48 -0
- data/test/integration/navigation_test.rb +13 -1
- data/test/integration/query_node/filters.yml +5 -0
- data/test/integration/query_node_test.rb +1 -1
- data/test/integration/zafu_compiler/ajax.yml +13 -19
- data/test/integration/zafu_compiler/basic.yml +0 -72
- data/test/integration/zafu_compiler/complex.yml +1 -1
- data/test/integration/zafu_compiler/complex_ok.yml +19 -0
- data/test/integration/zafu_compiler/dates.yml +62 -1
- data/test/integration/zafu_compiler/display.yml +4 -4
- data/test/integration/zafu_compiler/forms.yml +19 -7
- data/test/integration/zafu_compiler/i18n.yml +56 -1
- data/test/integration/zafu_compiler/later.yml +23 -1
- data/test/integration/zafu_compiler/relations.yml +1 -1
- data/test/integration/zafu_compiler/roles.yml +29 -1
- data/test/integration/zafu_compiler/safe_definitions.yml +1 -1
- data/test/integration/zafu_compiler/zafu_attributes.yml +2 -1
- data/test/integration/zafu_compiler_test.rb +5 -3
- data/test/sites/zena/columns.yml +3 -0
- data/test/sites/zena/roles.yml +0 -1
- data/test/sites/zena/sites.yml +1 -0
- data/test/sites/zena/versions.yml +2 -0
- data/test/unit/node_test.rb +27 -9
- data/test/unit/relation_proxy_test.rb +7 -4
- data/test/unit/remote_test.rb +379 -0
- data/test/unit/user_test.rb +47 -0
- data/test/unit/zena/acts/enrollable_test.rb +36 -7
- data/test/unit/zena/acts/serializable_test.rb +14 -2
- data/test/unit/zena/use/i18n_test.rb +32 -5
- data/test/unit/zena/use/query_node_test.rb +13 -1
- data/zena.gemspec +25 -11
- metadata +24 -10
data/.gitignore
CHANGED
data/History.txt
CHANGED
@@ -1,3 +1,15 @@
|
|
1
|
+
== 1.0.0.beta3 2010-09-17
|
2
|
+
|
3
|
+
* major changes
|
4
|
+
* created Zena::Remote API
|
5
|
+
* fixed Ajax operations and tests
|
6
|
+
* fixed forms to create/update new objects
|
7
|
+
* added dynamic translations
|
8
|
+
* better querybuilder integration relative to SELECT clauses
|
9
|
+
* fixed date parsing
|
10
|
+
* added safe 'send' method
|
11
|
+
* added support to create and update Roles
|
12
|
+
|
1
13
|
== 1.0.0.beta2 2010-07-24
|
2
14
|
|
3
15
|
* major changes
|
@@ -7,8 +7,18 @@ class ColumnsController < ApplicationController
|
|
7
7
|
# GET /columns
|
8
8
|
# GET /columns.xml
|
9
9
|
def index
|
10
|
+
roles = {}
|
10
11
|
secure(Column) do
|
11
|
-
@columns = Column.paginate(:all, :order => 'name', :per_page => 20, :page => params[:page])
|
12
|
+
@columns = Column.paginate(:all, :order => 'role_id ASC, name ASC', :per_page => 20, :page => params[:page]).sort! do |a, b|
|
13
|
+
role_a = (roles[a.role_id] ||= a.role).name
|
14
|
+
role_b = (roles[b.role_id] ||= b.role).name
|
15
|
+
|
16
|
+
if role_a == role_b
|
17
|
+
a.name <=> b.name
|
18
|
+
else
|
19
|
+
role_a <=> role_b
|
20
|
+
end
|
21
|
+
end
|
12
22
|
end
|
13
23
|
|
14
24
|
@column = Column.new
|
@@ -3,22 +3,23 @@
|
|
3
3
|
|
4
4
|
basepath class and zip optional mode format
|
5
5
|
|
6
|
-
/projects/art/ project24
|
6
|
+
/projects/art/ project24 _print .html
|
7
7
|
|
8
8
|
Examples:
|
9
9
|
/current/art/project24.html << a project inside the 'art' page
|
10
10
|
/note24.html << a Note's page
|
11
11
|
/note24_print.html << a Note in 'print' mode
|
12
|
-
/current/art.html << 'art' page (this page has custom base set
|
13
|
-
/current/
|
12
|
+
/current/art.html << 'art' page (this page has custom base set, this means no class or zip shown)
|
13
|
+
/current/art_print.html << 'art' page in 'print' mode
|
14
14
|
/current/art/project24/image28.html << image page (for comments, etc)
|
15
|
-
/current/art/project24/image28.jpg << full image
|
16
|
-
/current/art/project24/image28_pv.jpg << image in the 'pv' format
|
17
|
-
/current/art/project24/
|
15
|
+
/current/art/project24/image28.jpg << full image data
|
16
|
+
/current/art/project24/image28_pv.jpg << image in the 'pv' image format
|
17
|
+
/current/art/project24/image28_print.html << image page in 'print' mode
|
18
18
|
|
19
19
|
=end
|
20
20
|
class NodesController < ApplicationController
|
21
21
|
before_filter :check_is_admin, :only => [:export]
|
22
|
+
before_filter :check_api_group
|
22
23
|
before_filter :find_node, :except => [:index, :create, :not_found, :catch_all, :search]
|
23
24
|
before_filter :check_can_drive, :only => [:edit]
|
24
25
|
before_filter :check_path, :only => [:index, :show]
|
@@ -50,15 +51,46 @@ class NodesController < ApplicationController
|
|
50
51
|
raise ActiveRecord::RecordNotFound
|
51
52
|
end
|
52
53
|
|
54
|
+
# Find nodes starting from root node
|
53
55
|
def search
|
54
|
-
do_search
|
55
56
|
respond_to do |format|
|
56
|
-
format.html
|
57
|
-
|
58
|
-
|
57
|
+
format.html do
|
58
|
+
begin
|
59
|
+
do_search
|
60
|
+
rescue QueryBuilder::Error => err
|
61
|
+
flash[:error] = err.message
|
62
|
+
end
|
63
|
+
render_and_cache :mode => '+search', :cache => false
|
64
|
+
end
|
65
|
+
|
66
|
+
format.xml do
|
67
|
+
begin
|
68
|
+
do_search
|
69
|
+
if @nodes.kind_of?(Fixnum)
|
70
|
+
# count
|
71
|
+
render :xml => "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<count type=\"integer\">#{@nodes}</count>\n"
|
72
|
+
elsif @nodes
|
73
|
+
render :xml => Array(@nodes).to_xml(:root => 'nodes')
|
74
|
+
else
|
75
|
+
render :xml => [].to_xml(:root => 'nodes')
|
76
|
+
end
|
77
|
+
rescue QueryBuilder::Error => err
|
78
|
+
render :xml => [{:message => err.message}].to_xml(:root => 'errors'), :status => 401
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
format.js do
|
83
|
+
do_search
|
84
|
+
render :action => 'search'
|
85
|
+
end
|
59
86
|
end
|
60
87
|
end
|
61
88
|
|
89
|
+
# Find nodes starting from a given node
|
90
|
+
def find
|
91
|
+
search
|
92
|
+
end
|
93
|
+
|
62
94
|
# this should not be needed.... but format.js never gets called otherwize.
|
63
95
|
def asearch
|
64
96
|
do_search
|
@@ -180,7 +212,7 @@ class NodesController < ApplicationController
|
|
180
212
|
flash[:notice] = 'Node was successfully created.'
|
181
213
|
format.html { redirect_to zen_path(@node) }
|
182
214
|
format.js
|
183
|
-
format.xml { render :xml => @node, :status => :created, :location => node_url(@node) }
|
215
|
+
format.xml { render :xml => @node.to_xml(:root => 'node'), :status => :created, :location => node_url(@node) }
|
184
216
|
else
|
185
217
|
format.html { render :action => "new" }
|
186
218
|
format.js
|
@@ -312,13 +344,19 @@ class NodesController < ApplicationController
|
|
312
344
|
end
|
313
345
|
end
|
314
346
|
end # parent iframe (upload)
|
315
|
-
|
347
|
+
else
|
316
348
|
respond_to do |format|
|
317
349
|
format.html do
|
318
|
-
if
|
319
|
-
|
350
|
+
if @node.errors.empty?
|
351
|
+
if params[:edit] == 'popup'
|
352
|
+
redirect_to edit_node_version_path(:node_id => @node[:zip], :id => 0, :close => (params[:validate] ? true : nil))
|
353
|
+
else
|
354
|
+
redirect_to zen_path(@node, :mode => params[:mode])
|
355
|
+
end
|
320
356
|
else
|
321
|
-
|
357
|
+
# FIXME: Render referring page would be better
|
358
|
+
# Get mode and details from request.referer
|
359
|
+
render_and_cache :mode => 'edit', :cache => false
|
322
360
|
end
|
323
361
|
end # html
|
324
362
|
|
@@ -564,6 +602,13 @@ class NodesController < ApplicationController
|
|
564
602
|
end
|
565
603
|
|
566
604
|
def do_search
|
605
|
+
if @node
|
606
|
+
default_scope = 'self'
|
607
|
+
else
|
608
|
+
@node = current_site.root_node
|
609
|
+
default_scope = 'site'
|
610
|
+
end
|
611
|
+
|
567
612
|
unless query_params = params[:q]
|
568
613
|
query_params = params.dup
|
569
614
|
%w{controller action format}.each do |key|
|
@@ -571,10 +616,18 @@ class NodesController < ApplicationController
|
|
571
616
|
end
|
572
617
|
end
|
573
618
|
|
574
|
-
|
575
|
-
|
576
|
-
|
577
|
-
|
619
|
+
if request.format != Mime::XML || params[:page] || params[:per_page]
|
620
|
+
@search_per_page = params[:per_page] ? params[:per_page].to_i : 20
|
621
|
+
@nodes = secure(Node) { Node.search_records(query_params, :node => @node, :default => {:scope => default_scope}, :page => params[:page], :per_page => @search_per_page) }
|
622
|
+
@search_count = 100 # FIXME: @nodes ? @nodes.total_entries : 0
|
623
|
+
else
|
624
|
+
# XML without pagination
|
625
|
+
@nodes = secure(Node) { Node.search_records(query_params, :node => @node, :default => {:scope => default_scope}) }
|
626
|
+
end
|
627
|
+
|
628
|
+
if @nodes.kind_of?(Node)
|
629
|
+
@nodes = [@nodes]
|
630
|
+
end
|
578
631
|
end
|
579
632
|
|
580
633
|
# Document data do not change session[:lang] and can point at cached content (no nee to redirect to AUTHENTICATED_PREFIX).
|
@@ -608,5 +661,12 @@ class NodesController < ApplicationController
|
|
608
661
|
def check_can_drive
|
609
662
|
raise ActiveRecord::RecordNotFound unless @node.can_drive?
|
610
663
|
end
|
664
|
+
|
665
|
+
def check_api_group
|
666
|
+
return true if request.format != Mime::XML || visitor.api_authorized?
|
667
|
+
|
668
|
+
render :xml => [{:message => 'Not in API group.'}].to_xml(:root => 'errors'), :status => 401
|
669
|
+
false
|
670
|
+
end
|
611
671
|
end
|
612
672
|
|
@@ -6,7 +6,7 @@ class VirtualClassesController < ApplicationController
|
|
6
6
|
|
7
7
|
def index
|
8
8
|
secure(VirtualClass) do
|
9
|
-
@virtual_classes =
|
9
|
+
@virtual_classes = Role.paginate(:all, :order => 'kpath', :per_page => 20, :page => params[:page])
|
10
10
|
end
|
11
11
|
|
12
12
|
last_kpath = @virtual_classes.last.kpath
|
@@ -16,7 +16,17 @@ class VirtualClassesController < ApplicationController
|
|
16
16
|
end
|
17
17
|
end
|
18
18
|
|
19
|
-
@virtual_classes.sort!
|
19
|
+
@virtual_classes.sort! do |a, b|
|
20
|
+
if a.kpath == b.kpath
|
21
|
+
# Order VirtualClass first
|
22
|
+
b_type = b.kind_of?(Role) ? b.class.to_s : 'V' # sort real classes like VirtualClass
|
23
|
+
a_type = a.kind_of?(Role) ? a.class.to_s : 'V'
|
24
|
+
|
25
|
+
b_type <=> a_type
|
26
|
+
else
|
27
|
+
a.kpath <=> b.kpath
|
28
|
+
end
|
29
|
+
end
|
20
30
|
|
21
31
|
@virtual_class = VirtualClass.new('')
|
22
32
|
|
@@ -80,7 +90,12 @@ class VirtualClassesController < ApplicationController
|
|
80
90
|
end
|
81
91
|
|
82
92
|
def create
|
83
|
-
|
93
|
+
type = params[:virtual_class].delete(:type)
|
94
|
+
if type == 'Role'
|
95
|
+
@virtual_class = Role.new(params[:virtual_class])
|
96
|
+
else
|
97
|
+
@virtual_class = VirtualClass.new(params[:virtual_class])
|
98
|
+
end
|
84
99
|
|
85
100
|
respond_to do |format|
|
86
101
|
if @virtual_class.save
|
@@ -97,8 +112,6 @@ class VirtualClassesController < ApplicationController
|
|
97
112
|
end
|
98
113
|
|
99
114
|
def update
|
100
|
-
@virtual_class = VirtualClass.find(params[:id])
|
101
|
-
|
102
115
|
respond_to do |format|
|
103
116
|
if @virtual_class.update_attributes(params[:virtual_class])
|
104
117
|
flash[:notice] = 'VirtualClass was successfully updated.'
|
@@ -125,6 +138,6 @@ class VirtualClassesController < ApplicationController
|
|
125
138
|
|
126
139
|
protected
|
127
140
|
def find_virtual_class
|
128
|
-
@virtual_class = secure!(VirtualClass) {
|
141
|
+
@virtual_class = secure!(VirtualClass) { Role.find(params[:id])}
|
129
142
|
end
|
130
143
|
end
|
data/app/models/column.rb
CHANGED
@@ -12,11 +12,15 @@ class Column < ActiveRecord::Base
|
|
12
12
|
validates_uniqueness_of :name, :scope => :site_id
|
13
13
|
validate :name_not_in_models
|
14
14
|
|
15
|
+
safe_method :name => String
|
16
|
+
|
15
17
|
class << self
|
16
18
|
include Zena::Acts::Secure
|
17
19
|
|
18
20
|
def roles_for_form
|
19
|
-
secure(Role) { Role.all(:order => '
|
21
|
+
secure(Role) { Role.all(:order => 'name ASC') }.map do |role|
|
22
|
+
[role.name, role.id]
|
23
|
+
end
|
20
24
|
end
|
21
25
|
|
22
26
|
# Import a hash of virtual class definitions and try to build the virtual classes.
|
data/app/models/comment.rb
CHANGED
@@ -10,7 +10,7 @@ class Comment < ActiveRecord::Base
|
|
10
10
|
|
11
11
|
safe_attribute :title, :created_at, :updated_at, :status
|
12
12
|
safe_method :text => String, :author_name => {:class => String, :nil => true},
|
13
|
-
:
|
13
|
+
:discussion_id => Number
|
14
14
|
|
15
15
|
safe_context :replies => ['Comment'], :node => 'Node'
|
16
16
|
|
@@ -64,11 +64,6 @@ class Comment < ActiveRecord::Base
|
|
64
64
|
self[:id]
|
65
65
|
end
|
66
66
|
|
67
|
-
# needed by zafu to group
|
68
|
-
def discussion_zip
|
69
|
-
self[:discussion_id]
|
70
|
-
end
|
71
|
-
|
72
67
|
# TODO: test
|
73
68
|
def can_write?
|
74
69
|
is_author? && discussion.open?
|
data/app/models/node.rb
CHANGED
@@ -162,7 +162,6 @@ class Node < ActiveRecord::Base
|
|
162
162
|
:score => Number, :comments_count => Number,
|
163
163
|
:custom_a => Number, :custom_b => Number
|
164
164
|
|
165
|
-
# FIXME: remove 'zip' and use :id => {:class => Number, :method => 'zip'}
|
166
165
|
# same with parent_zip, section_zip, etc...
|
167
166
|
|
168
167
|
|
@@ -808,7 +807,7 @@ class Node < ActiveRecord::Base
|
|
808
807
|
transform_attributes(attributes, base_node)
|
809
808
|
end
|
810
809
|
|
811
|
-
def safe_method_type(signature)
|
810
|
+
def safe_method_type(signature, receiver = nil)
|
812
811
|
if signature.size > 1
|
813
812
|
RubyLess::SafeClass.safe_method_type_for(self, signature)
|
814
813
|
else
|
@@ -818,6 +817,13 @@ class Node < ActiveRecord::Base
|
|
818
817
|
elsif method =~ /^(.+)_((id|zip|status|comment)(s?))\Z/ && !instance_methods.include?(method)
|
819
818
|
key = $3 == 'id' ? "zip#{$4}" : $2
|
820
819
|
{:method => "rel[#{$1.inspect}].try(:other_#{key})", :nil => true, :class => ($4.blank? ? Number : [Number])}
|
820
|
+
elsif receiver && query = receiver.opts[:query]
|
821
|
+
# Resolve by using information in the SELECT part of the query that found this node
|
822
|
+
if query.select_keys.include?(method)
|
823
|
+
{:class => String, :method => "attributes[#{method.inspect}]", :nil => true}
|
824
|
+
else
|
825
|
+
nil
|
826
|
+
end
|
821
827
|
else
|
822
828
|
nil
|
823
829
|
end
|
@@ -1395,6 +1401,19 @@ class Node < ActiveRecord::Base
|
|
1395
1401
|
secure(Node) { Node.find_node_by_pseudo(string, base_node || self) }
|
1396
1402
|
end
|
1397
1403
|
|
1404
|
+
safe_method [:send, String] => {:class => String, :nil => true, :method => 'safe_send'}
|
1405
|
+
|
1406
|
+
# Safe dynamic method dispatching when the method is not known during compile time. Currently this
|
1407
|
+
# only works for methods without arguments.
|
1408
|
+
def safe_send(method)
|
1409
|
+
# We need to load roles or all properties will be ignored
|
1410
|
+
load_roles!
|
1411
|
+
|
1412
|
+
return nil unless type = safe_method_type([method])
|
1413
|
+
res = eval(type[:method])
|
1414
|
+
res ? res.to_s : nil
|
1415
|
+
end
|
1416
|
+
|
1398
1417
|
protected
|
1399
1418
|
|
1400
1419
|
# after node is saved, make sure it's children have the correct section set
|
@@ -1721,7 +1740,6 @@ class Node < ActiveRecord::Base
|
|
1721
1740
|
end
|
1722
1741
|
end
|
1723
1742
|
end
|
1724
|
-
|
1725
1743
|
end
|
1726
1744
|
|
1727
1745
|
Bricks.apply_patches
|
data/app/models/role.rb
CHANGED
@@ -8,6 +8,27 @@ class Role < ActiveRecord::Base
|
|
8
8
|
before_validation :set_defaults
|
9
9
|
validate :check_can_save
|
10
10
|
|
11
|
+
include RubyLess
|
12
|
+
safe_method :columns => {:class => ['Column'], :method => 'columns.values', :nil => false}
|
13
|
+
safe_method :name => String
|
14
|
+
|
15
|
+
def superclass
|
16
|
+
if new_record?
|
17
|
+
Node
|
18
|
+
else
|
19
|
+
Node.get_class_from_kpath(kpath)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def superclass=(klass)
|
24
|
+
if k = Node.get_class(klass)
|
25
|
+
self.kpath = k.kpath
|
26
|
+
else
|
27
|
+
errors.add('superclass', 'invalid')
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
|
11
32
|
private
|
12
33
|
def set_defaults
|
13
34
|
self.site_id = visitor.site.id
|
data/app/models/site.rb
CHANGED
@@ -19,11 +19,11 @@ The #Site model holds configuration information for a site:
|
|
19
19
|
class Site < ActiveRecord::Base
|
20
20
|
include RubyLess
|
21
21
|
safe_method :host => String, :lang_list => [String]
|
22
|
-
safe_context :root => {:class => Node, :method => 'root_node'}
|
22
|
+
safe_context :root => {:class => 'Node', :method => 'root_node'}
|
23
23
|
|
24
24
|
validate :valid_site
|
25
25
|
validates_uniqueness_of :host
|
26
|
-
attr_accessible :name, :languages, :default_lang, :authentication, :http_auth, :auto_publish, :redit_time
|
26
|
+
attr_accessible :name, :languages, :default_lang, :authentication, :http_auth, :auto_publish, :redit_time, :api_group_id
|
27
27
|
has_many :groups, :order => "name"
|
28
28
|
has_many :nodes
|
29
29
|
has_many :users
|
@@ -229,6 +229,11 @@ class Site < ActiveRecord::Base
|
|
229
229
|
@site_group ||= Group.find(self[:site_group_id])
|
230
230
|
end
|
231
231
|
|
232
|
+
# Return the API group: the one in which API visitors must be to use the API.
|
233
|
+
def api_group
|
234
|
+
@api_group ||= Group.find_by_id(self[:api_group_id])
|
235
|
+
end
|
236
|
+
|
232
237
|
# Return true if the given user is an administrator for this site.
|
233
238
|
def is_admin?(user)
|
234
239
|
admin_user_ids.include?(user[:id])
|
data/app/models/template.rb
CHANGED
@@ -93,14 +93,14 @@ class Template < TextDocument
|
|
93
93
|
self.text = <<END_TXT
|
94
94
|
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
|
95
95
|
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
|
96
|
-
<html xmlns=
|
96
|
+
<html xmlns='http://www.w3.org/1999/xhtml' do='void' lang='\#{v.lang}' xml:lang='en'>
|
97
97
|
<head do='void' name='head'>
|
98
98
|
<title do='title_for_layout' do='show' attr='title' name='page_title'>page title</title>
|
99
99
|
<!-- link href='favicon.png' rel='shortcut icon' type='image/png' / -->
|
100
|
-
<meta http-equiv=
|
100
|
+
<meta http-equiv='Content-type' content='text/html; charset=utf-8' />
|
101
101
|
<r:void name='stylesheets'>
|
102
102
|
<r:stylesheets/>
|
103
|
-
<link href=
|
103
|
+
<link href='style.css' rel='Stylesheet' type='text/css'/>
|
104
104
|
</r:void>
|
105
105
|
|
106
106
|
<r:javascripts/>
|