Skip to content

Commit

Permalink
Fixed all tests and bugs (multilingual indexing, prop eval, etc).
Browse files Browse the repository at this point in the history
  • Loading branch information
gaspard committed Apr 15, 2011
1 parent b8c4011 commit b9a2944
Show file tree
Hide file tree
Showing 29 changed files with 232 additions and 215 deletions.
1 change: 0 additions & 1 deletion app/controllers/virtual_classes_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -198,7 +198,6 @@ def get_roles(definitions, res = {})
def current_compared_to(definitions)
current = ::Role.export
roles = get_roles(definitions)
puts roles.inspect
filter_keys(current, definitions, roles)
current
end
Expand Down
67 changes: 42 additions & 25 deletions app/models/role.rb
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ class Role < ActiveRecord::Base
has_and_belongs_to_many :nodes

before_validation :set_defaults
validate :check_can_save
validate :validate_role
attr_accessible :name, :superclass, :icon

after_save :expire_vclass_cache
Expand Down Expand Up @@ -62,21 +62,29 @@ def import_all(superclass, definitions, post_import)
definitions.each do |name, sub|
next unless name =~ /\A[A-Z]/

klass = VirtualClass[name]
if klass && klass.real_class?
res += import_all(klass, sub, post_import)
elsif sub['type'] == 'Role'
case sub['type']
when 'Class'
klass = VirtualClass[name]
if klass && klass.real_class?
res += import_all(klass, sub, post_import)
else
raise Exception.new("Unknown real class '#{name}'.")
end
when 'Role'
res << import_role(superclass, name, sub)
elsif sub['type'] == 'Class'
# real class
raise Exception.new("Unknown real class '#{name}'.")
elsif sub['type'] == 'VirtualClass' || sub['type'].nil?
when 'VirtualClass'
# VirtualClass
res += import_vclass(superclass, name, sub, post_import)
when nil
klass = VirtualClass[name]
if klass && klass.real_class?
res += import_all(klass, sub, post_import)
else
res += import_vclass(superclass, name, sub, post_import)
end
else
# Invalid type
raise Exception.new("Cannot create '#{name}': invalid type '#{sub['type']}'.")
res << tmp
end
end
res
Expand Down Expand Up @@ -156,8 +164,8 @@ def superclass
end

def superclass=(klass)
if k = Node.get_class(klass)
self.kpath = k.kpath
if klass.kind_of?(VirtualClass) || klass = VirtualClass[klass]
@superclass = klass
else
errors.add('superclass', 'invalid')
end
Expand All @@ -178,19 +186,21 @@ def export
end

def import_columns(columns)
columns.each do |name, definition|
column = secure(::Column) { ::Column.find_by_name(name) }
if !column
# create
column = ::Column.new(:name => name)
elsif column.role_id != self.id
# error (do not move a column)
raise Exception.new("Cannot set property '#{name}' in '#{self.name}': already defined in '#{column.role.name}'.")
transaction do
columns.each do |name, definition|
column = secure(::Column) { ::Column.find_by_name(name) }
if !column
# create
column = ::Column.new(:name => name)
elsif column.role_id != self.id
# error (do not move a column)
raise Exception.new("Cannot set property '#{name}' in '#{self.name}': already defined in '#{column.role.name}'.")
end
column.role_id = self.id
column.ptype = definition['ptype']
column.index = definition['index']
column.save!
end
column.role_id = self.id
column.ptype = definition['ptype']
column.index = definition['index']
column.save!
end
end

Expand Down Expand Up @@ -221,8 +231,15 @@ def set_defaults
self.site_id = visitor.site.id
end

def check_can_save
def validate_role
errors.add('base', 'You do not have the rights to change roles.') unless visitor.is_admin?
if new_record?
errors.add('superclass', 'invalid') unless @superclass.kind_of?(VirtualClass) && @superclass.kpath
end

if @superclass && self.class == ::Role
self.kpath = @superclass.kpath
end
end

def expire_vclass_cache
Expand Down
8 changes: 0 additions & 8 deletions app/models/virtual_class.rb
Original file line number Diff line number Diff line change
Expand Up @@ -447,14 +447,6 @@ def do_find(*args)
real_class.do_find(*args)
end

def superclass=(klass)
if klass.kind_of?(VirtualClass) || klass = VirtualClass[klass]
@superclass = klass
else
errors.add('superclass', 'invalid')
end
end

# Build new nodes instances of this VirtualClass
def new_instance(hash={})
real_class.new(hash, self)
Expand Down
23 changes: 15 additions & 8 deletions app/views/virtual_classes/index.erb
Original file line number Diff line number Diff line change
Expand Up @@ -9,20 +9,27 @@
</table>

<div class='admin_group'>
<h3><%= link_to(_('export'), :action => 'export') %></h3>
<h3><%= _('import') %></h3>
<% if @roles_backup -%>
<h3><%= _('import') %></h3>
<%= form_tag({ :controller => 'virtual_classes', :action => 'import'}) %>
<p>
<%= hidden_field_tag(:roles, @roles_backup) %>
<%#= hidden_field_tag(:delete_roles, '1') %>
</p>
<p class="btn_validate"><input type="submit" value='<%= _('revert') %>'/></p>
<p>
<%= hidden_field_tag(:roles, @roles_backup) %>
<%#= hidden_field_tag(:delete_roles, '1') %>
</p>
<p class="btn_validate">
<%= link_to(_('back'), :action => 'index')%> &nbsp;
<input type="submit" value='<%= _('revert') %>'/>
</p>
</form>
<% else -%>
<h3><%= link_to(_('export'), :action => 'export') %></h3>
<h3><%= _('import') %></h3>
<%= form_tag({ :controller => 'virtual_classes', :action => 'import_prepare'}, {:multipart => true} ) %>
<p><input style='line-height:1.5em;' name="attachment" class='file' type="file" /></p>
<p class="btn_validate"><input type="submit" value='<%= _('diff') %>'/></p>
<p class="btn_validate">
<%= link_to(_('cancel'), :action => 'index')%> &nbsp;
<input type="submit" value='<%= _('diff') %>'/>
</p>
</form>
<% end -%>
</div>
2 changes: 1 addition & 1 deletion config/bricks.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ test:
tags: ON
captcha: ON
sphinx: OFF
worker: ON
worker: OFF

development:
asset_port: 7999
Expand Down
39 changes: 15 additions & 24 deletions lib/zena/use/fulltext.rb
Original file line number Diff line number Diff line change
Expand Up @@ -45,38 +45,29 @@ module ModelMethods

def self.included(base)
base.before_validation :build_fulltext_indices
base.alias_method_chain :rebuild_index!, :fulltext
base.alias_method_chain :rebuild_index_for_version, :fulltext
end

def rebuild_index_with_fulltext!
visible_versions.each do |version|
build_fulltext_indices(version)
fields_to_set = []
FULLTEXT_FIELDS.each do |idx_group|
next unless version.changes[idx_group]
fields_to_set << "#{idx_group}=#{Zena::Db.quote(version[idx_group])}"
end
def rebuild_index_for_version_with_fulltext(version)
# Call PropEval or other modules inserted before
rebuild_index_for_version_without_fulltext(version)

unless fields_to_set.empty?
Version.connection.execute "UPDATE versions SET #{fields_to_set.join(',')} WHERE id=#{version.id}"
end
build_fulltext_indices(true)
fields_to_set = []
FULLTEXT_FIELDS.each do |idx_group|
next unless version.changes[idx_group]
fields_to_set << "#{idx_group}=#{Zena::Db.quote(version[idx_group])}"
end

unless fields_to_set.empty?
Version.connection.execute "UPDATE versions SET #{fields_to_set.join(',')} WHERE id=#{version.id}"
end
rebuild_index_without_fulltext!
end

private
# Prepare roles to add/remove to object.
def build_fulltext_indices(rebuild_version = nil)
# Make sure roles are loaded because we compile RubyLess.

if rebuild_version
version = rebuild_version
# make sure prop corresponds to the correct version content
@properties = version.prop
else
return unless prop.changed?
version = self.version
end
def build_fulltext_indices(force_rebuild = false)
return if !force_rebuild && !prop.changed?

if vclass = self.virtual_class
vclass_prop = vclass.prop
Expand Down
4 changes: 2 additions & 2 deletions lib/zena/use/html_tags.rb
Original file line number Diff line number Diff line change
Expand Up @@ -168,12 +168,12 @@ def flash_messages(opts={})
type = opts[:show] || 'both'
"<div class='flash_messages'>" +
if (type == 'notice' || type == 'both') && flash[:notice]
"<div id='flash_notice' class='auto_fade' onclick='new Effect.Fade(this)'>#{flash[:notice]}</div>"
"<div class='auto_fade notice' onclick='new Effect.Fade(this)'>#{flash[:notice]}</div>"
else
''
end +
if (type == 'error' || type == 'both') && flash[:error ]
"<div id='flash_error' onclick='new Effect.Fade(this)'>#{flash[:error]}</div>"
"<div class='error' onclick='new Effect.Fade(this)'>#{flash[:error]}</div>"
else
''
end +
Expand Down
30 changes: 13 additions & 17 deletions lib/zena/use/ml_index.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,38 +7,34 @@ def self.included(base)
end

def rebuild_index_with_multi_lingual!
# We call rebuild_index_without_multi_lingual first with our hack
# to avoid inclusion order problems with fulltext index.

# Skip multi lingual indices
@index_langs = []

# Build std index
rebuild_index_without_multi_lingual!

# Skip std index
@skip_std_index = true

visible_versions.each do |version|
# 1. for each visible version
self.version = version
@properties = version.prop
@index_langs = nil # force rebuild
# Build ml index for each version
# rebuild for each lang
@index_langs = nil
# Forces a to skip multi lingual indices
# @index_langs = []

# Build std index
rebuild_index_for_version(version)
rebuild_index_without_multi_lingual!
# 2. PropEval::rebuild_index!
# 3. Fulltext::rebuild_index!
# 4. Properties::rebuild_index!
end
end

def rebuild_index_for_version(v)
rebuild_index_without_multi_lingual!
# noop (method chaining in PropEval, Fulltext, etc)
end


# Hash used to read current values
def index_reader(group_name)
if group_name =~ /^ml_/
return nil if index_langs.empty?
super.merge(:with => {'lang' => index_langs})
elsif @skip_std_index
nil
else
super
end
Expand Down
7 changes: 4 additions & 3 deletions lib/zena/use/prop_eval.rb
Original file line number Diff line number Diff line change
Expand Up @@ -45,11 +45,12 @@ def self.included(base)
base.alias_method_chain :rebuild_index_for_version, :prop_eval
end

def rebuild_index_for_version_with_prop_eval(v)
def rebuild_index_for_version_with_prop_eval(version)
# Call other modules inserted before
rebuild_index_for_version_without_prop_eval(version)
merge_prop_eval(true)
# Only save properties, without changing updated_at date or other callbacks
Zena::Db.set_attribute(v, 'properties', encode_properties(@properties)) if v.changed?
rebuild_index_for_version_without_prop_eval(v)
Zena::Db.set_attribute(version, 'properties', encode_properties(@properties)) if version.changed?
end

def need_set__id
Expand Down
2 changes: 1 addition & 1 deletion lib/zena/use/scope_index.rb
Original file line number Diff line number Diff line change
Expand Up @@ -247,10 +247,10 @@ def update_scope_indices_on_prop_change(deleted=false)
models_to_update = [self]
else
models_to_update = find(:all, query, :skip_rubyless => true) || []
raise if !models_to_update.empty? && title == models_to_update.first.title
end

models_to_update.each do |m|
next if m.destroyed? # on destroy, self can be in this list
if idx_model = m.scope_index
if deleted
# Clear obsolete content
Expand Down
5 changes: 3 additions & 2 deletions lib/zena/use/urls.rb
Original file line number Diff line number Diff line change
Expand Up @@ -224,8 +224,9 @@ module ControllerMethods
module ViewMethods
include Common
include RubyLess
safe_method [:url, Node] => {:class => String, :method => 'zen_url'}
safe_method [:path, Node] => {:class => String, :method => 'zen_path'}
safe_method [:url, Node] => {:class => String, :method => 'zen_url'}
safe_method [:url, Node, Hash] => {:class => String, :method => 'zen_url'}
safe_method [:path, Node] => {:class => String, :method => 'zen_path'}

safe_method [:zen_path, Node, Hash] => {:class => String, :accept_nil => true}
safe_method [:zen_path, Node] => {:class => String, :accept_nil => true}
Expand Down
2 changes: 1 addition & 1 deletion public/stylesheets/admin.css
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ table.admin td:first-child { border-left: 1px solid #999; }
.role_diff del.differ { display:block;}
.role_diff ins.differ { display:block;}

.flash_messages #flash_error { background:#DDC8C8; padding:1.5em;}
.flash_messages .error { background:#DDC8C8; padding:1.5em;}

/* status */
.u40 { background:#B7CC87;}
Expand Down
24 changes: 18 additions & 6 deletions test/functional/virtual_classes_controller_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -197,12 +197,25 @@ class VirtualClassesControllerTest < Zena::Controller::TestCase

context 'importing virtual class definitions' do
subject do
{:action => :import, :attachment => uploaded_fixture('vclasses.yml', 'text/yaml')}
{:action => :import, :roles => {
'Node' => {
'Note' => {
'Foo' => {
'type' => 'VirtualClass',
},
'Bar' => {
'type' => 'Role',
}
}
}
}.to_yaml}
end

should 'create virtual classes' do
assert_difference('VirtualClass.count', 3) do
post_subject
assert_difference('VirtualClass.count', 1) do
assert_difference('Role.count', 2) do
post_subject
end
end
end
end # importing virtual class definitions
Expand All @@ -215,9 +228,8 @@ class VirtualClassesControllerTest < Zena::Controller::TestCase
should 'dump virtual classes to yaml' do
get_subject
res = YAML.load @response.body
puts @response.body
assert_equal %w{Blog Contact Letter Original Post Reference Tag Task Tracker}, res.keys.sort
assert_equal res['Original'], roles(:Original).export
assert_equal 'VirtualClass', res['Node']['Page']['Project']['Blog']['type']
assert_equal res['Node']['Original'], roles(:Original).export
end
end # importing virtual class definitions
end # that is an admin
Expand Down
2 changes: 1 addition & 1 deletion test/integration/zafu_compiler/ajax.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ add_each_no_form:
res: "/<ul><li.*id='things_add'.*li.*class='form' id='things_form'.*form.*I <p><input id=.things_title. name=.node\[title\]. .*type=.text..*hidden/"

add_each_no_form_date:
src: "<ul do='children' id='things'><li do='each'>I <p do='show' date='event_at' tformat='short_date'>blah</p></li><li do='add'/></ul>"
src: "<ul do='children' id='things'><li do='each'>I <p do='show' attr='event_at' tformat='short_date'>blah</p></li><li do='add'/></ul>"
res: "/<ul><li.*id='things_add'.*li.*id='things_form'.*form.*I <p>.*date_box.*name='node\[event_at\]' type='text' value.*hidden/"

add_each_no_form_focus:
Expand Down

0 comments on commit b9a2944

Please sign in to comment.