Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Big spike of refactoring.

Signed-off-by: Andrea Franz <andrea@gravityblast.com>
  • Loading branch information...
commit c12feaadbe7981c2c590904da5533fd8889dfacf 1 parent 6e33a95
Sean Cribbs seancribbs authored committed
19 app/helpers/copy_move_helper.rb
View
@@ -4,17 +4,16 @@ def page_parent_select_tag
list = homes.inject([]) do |l, home|
l.concat build_tree(home, [])
end
- options = options_for_select list, (@page.parent ? @page.parent.id : nil)
- select_tag 'parent', options
+ select_tag 'parent_id', options, options_for_select(list)
end
- def build_tree page, list, level = 0
- label = "#{'-'*level}#{page.title}"
- id = page.id
- list << [label, id]
- page.children.each do |p|
- build_tree p, list, level + 1
- end
- list
+ def build_tree(page, list, level = 0)
+ label = "#{'-'*level}#{page.title}"
+ id = page.id
+ list << [label, id]
+ page.children.each do |p|
+ build_tree p, list, level + 1
+ end
+ list
end
end
21 copy_move_extension.rb
View
@@ -1,27 +1,26 @@
require_dependency 'application_controller'
class CopyMoveExtension < Radiant::Extension
- version "1.9.1"
+ version "2.0.0"
description "Adds the ability to copy and move a page and all of its children"
url "http://gravityblast.com/projects/radiant-copymove-extension/"
define_routes do |map|
- map.copy_move_index 'admin/pages/copy_move/:id', :controller => 'copy_move', :action => 'index'
- map.copy_move_copy_move 'admin/pages/copy_move/:id/copy_move', :controller => 'copy_move', :action => 'copy_move'
+ map.with_options(:controller => "admin/pages") do |cm|
+ cm.copy_admin_page 'admin/pages/:id/copy', :action => 'copy'
+ cm.copy_children_admin_page 'admin/pages/:id/copy_children', :action => 'copy_children'
+ cm.copy_tree_admin_page 'admin/pages/:id/copy_tree', :action => 'copy_tree'
+ cm.move_admin_page 'admin/pages/:id/move', :action => 'move'
+ end
end
def activate
Admin::PagesController.class_eval do
- before_filter do |c|
- c.include_stylesheet 'admin/copy_move'
- end
+ include CopyMove::Controller
+ helper :copy_move
end
-
+ Page.class_eval { include CopyMove }
admin.page.index.add :sitemap_head, 'copy_move_extra_th'
admin.page.index.add :node, 'copy_move_extra_td', :after => "add_child_column"
end
-
- def deactivate
- end
-
end
51 lib/copy_move.rb
View
@@ -0,0 +1,51 @@
+module CopyMove
+ class CircularHierarchy < ActiveRecord::ActiveRecordError
+ def initialize(record)
+ @record = record
+ super("Page #{record.title} cannot be made a descendant of itself.")
+ end
+ end
+
+ def new_slug_and_title_under(parent)
+ test_page = self.clone
+ test_page.parent = parent
+ until test_page.valid?
+ index = (index || 0) + 1
+ test_page.title = "#{title} (Copy#{' '+index if index > 1})"
+ test_page.slug = "#{slug}-#{index}"
+ end
+ {:slug => test_page.slug, :title => test_page.title}
+ end
+
+ def move_under(parent)
+ raise CircularHierarchy.new(self) if parent == self || parent.ancestors.include?(self)
+ update_attributes!(:parent_id => parent.id)
+ end
+
+ def copy_to(parent, status = nil)
+ parent.children.build(copiable_attributes.symbolize_keys.merge(new_slug_and_title_under(parent))).tap do |new_page|
+ self.parts.each do |part|
+ new_page.parts << part.clone
+ end
+ new_page.status_id = status || new_page.status_id
+ new_page.save!
+ end
+ end
+
+ def copy_with_children_to(parent, status = nil)
+ copy_to(parent, status).tap do |new_page|
+ children.each {|child| child.copy_to(new_page, status) }
+ end
+ end
+
+ def copy_tree_to(parent, status = nil)
+ copy_to(parent, status).tap do |new_page|
+ children.each {|child| child.copy_tree_to(new_page, status) }
+ end
+ end
+
+ private
+ def copiable_attributes
+ self.attributes.dup.delete_if {|k,v| [:id, :parent_id].include?(k.to_sym) }
+ end
+end
91 lib/copy_move/controller.rb
View
@@ -0,0 +1,91 @@
+module CopyMove
+ module Controller
+ def self.included(base)
+ base.class_eval do
+ before_filter do |c|
+ c.include_stylesheet 'admin/copy_move'
+ end
+ before_filter :load_model, :only => [:copy, :copy_children, :copy_tree, :move]
+ before_filter :load_parent, :only => [:copy, :copy_children, :copy_tree, :move]
+ end
+ end
+
+ def copy
+ @new_page = @page.copy_to(@parent)
+ respond_to do |wants|
+ wants.html do
+ flash[:notice] = "A copy of <strong>#{@page.title}</strong> was created under <strong>#{@parent.title}</strong>."
+ redirect_to admin_pages_url
+ end
+ wants.xml do
+ render :xml => @new_page, :status => :created, :location => admin_page_url(@new_page, :format => params[:format])
+ end
+ wants.json do
+ render :json => @new_page, :status => :created, :location => admin_page_url(@new_page, :format => params[:format])
+ end
+ end
+ end
+
+ def copy_children
+ @new_page = @page.copy_with_children_to(@parent)
+ respond_to do |wants|
+ wants.html do
+ flash[:notice] = "Copies of <strong>#{@page.title}</strong> and its immediate children were created under <strong>#{@parent.title}</strong>."
+ redirect_to admin_pages_url
+ end
+ wants.xml do
+ render :xml => @new_page, :status => :created, :location => admin_page_url(@new_page, :format => params[:format])
+ end
+ wants.json do
+ render :json => @new_page, :status => :created, :location => admin_page_url(@new_page, :format => params[:format])
+ end
+ end
+ end
+
+ def copy_tree
+ @new_page = @page.copy_tree_to(@parent)
+ respond_to do |wants|
+ wants.html do
+ flash[:notice] = "Copies of <strong>#{@page.title}</strong> and all its descendants were created under <strong>#{@parent.title}</strong>."
+ redirect_to admin_pages_url
+ end
+ wants.xml do
+ render :xml => @new_page, :status => :created, :location => admin_page_url(@new_page, :format => params[:format])
+ end
+ wants.json do
+ render :json => @new_page, :status => :created, :location => admin_page_url(@new_page, :format => params[:format])
+ end
+ end
+ end
+
+ def move
+ @page.move_under(@parent)
+ respond_to do |wants|
+ wants.html do
+ flash[:notice] = "Page <strong>#{@page.title}</strong> and all its descendants were moved under <strong>#{@parent.title}</strong>."
+ redirect_to admin_pages_url
+ end
+ wants.xml do
+ render :xml => @page
+ end
+ wants.json do
+ render :json => @page
+ end
+ end
+ rescue CopyMove::CircularHierarchy => e
+ respond_to do |wants|
+ wants.html do
+ flash[:error] = e.message
+ redirect_to admin_pages_url
+ end
+ wants.xml { render :xml => e, :status => :conflict }
+ wants.json { render :json => e, :status => :conflict }
+ end
+ end
+
+ private
+ def load_parent
+ @parent = Page.find(params[:parent_id])
+ end
+ end
+end
19 lib/tasks/copy_move_extension_tasks.rake
View
@@ -2,7 +2,7 @@ namespace :radiant do
namespace :extensions do
namespace :copy_move do
- desc "Runs the migration of the CopyMove extension"
+ desc "Runs the migration of the Copy Move extension"
task :migrate => :environment do
require 'radiant/extension_migrator'
if ENV["VERSION"]
@@ -12,22 +12,17 @@ namespace :radiant do
end
end
- desc "Copies public assets of the CopyMove extension to the instance public/ directory."
+ desc "Copies public assets of the Copy Move to the instance public/ directory."
task :update => :environment do
is_svn_or_dir = proc {|path| path =~ /\.svn/ || File.directory?(path) }
+ puts "Copying assets from CopyMoveExtension"
Dir[CopyMoveExtension.root + "/public/**/*"].reject(&is_svn_or_dir).each do |file|
path = file.sub(CopyMoveExtension.root, '')
directory = File.dirname(path)
- puts "Copying #{path}..."
- mkdir_p RAILS_ROOT + directory
- cp file, RAILS_ROOT + path
+ mkdir_p RAILS_ROOT + directory, :verbose => false
+ cp file, RAILS_ROOT + path, :verbose => false
end
- end
-
- desc "Migrates and copies files in public/admin"
- task :install => [:environment, :migrate, :update] do
- end
-
+ end
end
end
-end
+end
162 spec/controllers/copy_move_controller_spec.rb
View
@@ -0,0 +1,162 @@
+require File.dirname(__FILE__) + '/../spec_helper'
+
+describe Admin::PagesController do
+ dataset :users_and_pages
+ before :each do
+ login_as :existing
+ end
+
+ describe "routes" do
+ it "should route URLs to the copy action" do
+ route_for(:controller => "admin/pages", :action => "copy", :id => "1").should == "/admin/pages/1/copy"
+ params_from(:post, "/admin/pages/1/copy").should == {:controller => "admin/pages", :action => "copy", :id => "1"}
+ end
+
+ it "should route URLs to the copy_children action" do
+ route_for(:controller => "admin/pages", :action => "copy_children", :id => "1").should == "/admin/pages/1/copy_children"
+ params_from(:post, "/admin/pages/1/copy_children").should == {:controller => "admin/pages", :action => "copy_children", :id => "1"}
+ end
+
+ it "should route URLs to the copy_tree action" do
+ route_for(:controller => "admin/pages", :action => "copy_tree", :id => "1").should == "/admin/pages/1/copy_tree"
+ params_from(:post, "/admin/pages/1/copy_tree").should == {:controller => "admin/pages", :action => "copy_tree", :id => "1"}
+ end
+ end
+
+ describe "POST to /admin/pages/:id/copy" do
+ before :each do
+ post :copy, :id => page_id(:first), :parent_id => page_id(:another)
+ end
+
+ it "should load the page" do
+ assigns[:page].should == pages(:first)
+ end
+
+ it "should load the parent page" do
+ assigns[:parent].should == pages(:another)
+ end
+
+ it "should create a new page" do
+ assigns[:new_page].should be
+ end
+
+ it "should write a flash notice" do
+ flash[:notice].should be
+ end
+
+ it "should redirect to the sitemap" do
+ response.should redirect_to(admin_pages_url)
+ end
+ end
+
+ describe "POST to /admin/pages/:id/copy_children" do
+ before :each do
+ post :copy_children, :id => page_id(:assorted), :parent_id => page_id(:another)
+ end
+
+ it "should load the page" do
+ assigns[:page].should == pages(:assorted)
+ end
+
+ it "should load the parent page" do
+ assigns[:parent].should == pages(:another)
+ end
+
+ it "should create a new page" do
+ assigns[:new_page].should be
+ end
+
+ it "should have copied the children" do
+ assigns[:new_page].should have(12).children
+ end
+
+ it "should write a flash notice" do
+ flash[:notice].should be
+ end
+
+ it "should redirect to the sitemap" do
+ response.should redirect_to(admin_pages_url)
+ end
+ end
+
+ describe "POST to /admin/pages/:id/copy_tree" do
+ before :each do
+ post :copy_tree, :id => page_id(:parent), :parent_id => page_id(:another)
+ end
+
+ it "should load the page" do
+ assigns[:page].should == pages(:parent)
+ end
+
+ it "should load the parent page" do
+ assigns[:parent].should == pages(:another)
+ end
+
+ it "should create a new page" do
+ assigns[:new_page].should be
+ end
+
+ it "should have copied the descendants" do
+ assigns[:new_page].should have(3).children
+ assigns[:new_page].children.first.should have(1).child
+ end
+
+ it "should write a flash notice" do
+ flash[:notice].should be
+ end
+
+ it "should redirect to the sitemap" do
+ response.should redirect_to(admin_pages_url)
+ end
+ end
+
+ describe "POST to /admin/pages/:id/move" do
+ describe "when moving to a valid parent" do
+ before :each do
+ post :move, :id => page_id(:first), :parent_id => page_id(:another)
+ end
+
+ it "should load the page" do
+ assigns[:page].should == pages(:first)
+ end
+
+ it "should load the parent page" do
+ assigns[:parent].should == pages(:another)
+ end
+
+ it "should have moved the page to its new parent" do
+ assigns[:page].parent.should == assigns[:parent]
+ end
+
+ it "should write a flash notice" do
+ flash[:notice].should be
+ end
+
+ it "should redirect to the sitemap" do
+ response.should redirect_to(admin_pages_url)
+ end
+ end
+
+ describe "when moving to an invalid parent" do
+ before :each do
+ post :move, :id => page_id(:parent), :parent_id => page_id(:child)
+ end
+
+ it "should load the page" do
+ assigns[:page].should == pages(:parent)
+ end
+
+ it "should load the parent page" do
+ assigns[:parent].should == pages(:child)
+ end
+
+ it "should write a flash error" do
+ flash[:error].should be
+ end
+
+ it "should redirect to the sitemap" do
+ response.should redirect_to(admin_pages_url)
+ end
+ end
+ end
+end
108 spec/models/copy_move_spec.rb
View
@@ -0,0 +1,108 @@
+require File.dirname(__FILE__) + '/../spec_helper'
+
+describe CopyMove do
+ dataset :pages
+
+ describe "suggesting a new slug and title" do
+ it "should use the same slug and title when there is not a child page of the new parent that has the same slug or title" do
+ pages(:first).new_slug_and_title_under(pages(:parent)).should == {:slug => "first", :title => "First"}
+ end
+
+ it "should use a different slug and title when there is a conflicting child page of the new parent" do
+ pages(:first).new_slug_and_title_under(pages(:home)).should_not == {:slug => "first", :title => "First"}
+ pages(:first).new_slug_and_title_under(pages(:home)).should == {:slug => "first-1", :title => "First (Copy)"}
+ end
+ end
+
+ describe "moving under a new parent" do
+ it "should refuse to move under itself" do
+ lambda { pages(:first).move_under(pages(:first)) }.should raise_error(CopyMove::CircularHierarchy)
+ end
+
+ it "should refuse to move under a descendant of itself" do
+ lambda { pages(:parent).move_under(pages(:child)) }.should raise_error(CopyMove::CircularHierarchy)
+ end
+
+ it "should move to a new parent" do
+ @page = pages(:first)
+ lambda { @page.move_under(pages(:another)) }.should_not raise_error
+ @page.reload.parent.should == pages(:another)
+ end
+ end
+
+ describe "copying the page" do
+ before :each do
+ @page = pages(:first)
+ end
+
+ it "should duplicate the page" do
+ @new_page = @page.copy_to(pages(:another))
+ @page.attributes.delete_if {|k,v| [:id, :parent_id].include?(k.to_sym) }.each do |key,value|
+ @new_page[key].should == value
+ end
+ @page.parts.each do |part|
+ @new_page.part(part.name).should_not be_nil
+ end
+ end
+
+ it "should use a new slug and title if a similar page exists under the new parent" do
+ @new_page = @page.copy_to(pages(:home))
+ @new_page.slug.should_not == @page.slug
+ @new_page.title.should_not == @page.title
+ end
+
+ it "should override the status when given" do
+ @new_page = @page.copy_to(pages(:another), Status[:draft].id)
+ @new_page.status.should == Status[:draft]
+ end
+ end
+
+ describe "copying the page with first-level children" do
+ it "should copy the page and its children" do
+ @page = pages(:assorted)
+ @new_page = @page.copy_with_children_to(pages(:first))
+ @new_page.parent.should == pages(:first)
+ @new_page.should have(12).children
+ end
+
+ it "should not copy grandchild pages" do
+ @page = pages(:parent)
+ @new_page = @page.copy_with_children_to(pages(:childless))
+ @new_page.children.count.should == 3
+ @new_page.children.first.children.count.should == 0
+ end
+
+ it "should override the status when given" do
+ @page = pages(:assorted)
+ @new_page = @page.copy_with_children_to(pages(:first), Status[:hidden].id)
+ @new_page.status.should == Status[:hidden]
+ @new_page.children.each do |child|
+ child.status.should == Status[:hidden]
+ end
+ end
+ end
+
+ describe "copying the page with all descendants" do
+ before :each do
+ @page = pages(:parent)
+ end
+
+ it "should copy the page and all descendants" do
+ @new_page = @page.copy_tree_to(pages(:first))
+ @new_page.parent.should == pages(:first)
+ @new_page.should have(3).children
+ @new_page.children.first.should have(1).child
+ @new_page.children.first.children.first.should have(1).child
+ end
+
+ it "should override the status when given" do
+ @new_page = @page.copy_tree_to(pages(:first), Status[:hidden].id)
+ @new_page.status.should == Status[:hidden]
+ @new_page.children.each do |child|
+ child.status.should == Status[:hidden]
+ end
+ @new_page.children.first.children.first.status.should == Status[:hidden]
+ @new_page.children.first.children.first.children.first.status.should == Status[:hidden]
+ end
+ end
+end
6 spec/spec.opts
View
@@ -0,0 +1,6 @@
+--colour
+--format
+progress
+--loadby
+mtime
+--reverse
36 spec/spec_helper.rb
View
@@ -0,0 +1,36 @@
+unless defined? RADIANT_ROOT
+ ENV["RAILS_ENV"] = "test"
+ case
+ when ENV["RADIANT_ENV_FILE"]
+ require ENV["RADIANT_ENV_FILE"]
+ when File.dirname(__FILE__) =~ %r{vendor/radiant/vendor/extensions}
+ require "#{File.expand_path(File.dirname(__FILE__) + "/../../../../../../")}/config/environment"
+ else
+ require "#{File.expand_path(File.dirname(__FILE__) + "/../../../../")}/config/environment"
+ end
+end
+require "#{RADIANT_ROOT}/spec/spec_helper"
+
+Dataset::Resolver.default << (File.dirname(__FILE__) + "/datasets")
+
+if File.directory?(File.dirname(__FILE__) + "/matchers")
+ Dir[File.dirname(__FILE__) + "/matchers/*.rb"].each {|file| require file }
+end
+
+Spec::Runner.configure do |config|
+ # config.use_transactional_fixtures = true
+ # config.use_instantiated_fixtures = false
+ # config.fixture_path = RAILS_ROOT + '/spec/fixtures'
+
+ # You can declare fixtures for each behaviour like this:
+ # describe "...." do
+ # fixtures :table_a, :table_b
+ #
+ # Alternatively, if you prefer to declare them only once, you can
+ # do so here, like so ...
+ #
+ # config.global_fixtures = :table_a, :table_b
+ #
+ # If you declare global fixtures, be aware that they will be declared
+ # for all of your examples, even those that don't use them.
+end
Please sign in to comment.
Something went wrong with that request. Please try again.