Diff
Modified: branches/versions/app/controllers/workflows_controller.rb (3044 => 3045)
--- branches/versions/app/controllers/workflows_controller.rb 2012-07-25 13:58:28 UTC (rev 3044)
+++ branches/versions/app/controllers/workflows_controller.rb 2012-07-25 13:58:48 UTC (rev 3045)
@@ -445,9 +445,13 @@
if @workflow.valid?
# Save content blob first now and set it on the workflow.
# TODO: wrap this in a transaction!
- @workflow.content_blob_id = ContentBlob.create(:data ="" file.read).id
- if @workflow.save_as_new_version(params[:new_workflow][:rev_comments])
+ @workflow.content_blob = ContentBlob.create(:data ="" file.read)
+ @workflow.preview = nil
+ if @workflow.save
+
+ @workflow.versions.last.update_attribute(:revision_comments, params[:new_workflow][:rev_comments])
+
# Extract workflow metadata using a Workflow object that includes the
# newly created version.
@@ -509,7 +513,7 @@
respond_to do |format|
# Here we assume that no actual workflow metadata is being updated that affects workflow versions,
# so we need to prevent the timestamping update of workflow version objects.
- Workflow.versioned_class.record_timestamps = false
+ Workflow.record_timestamps = false
if @workflow.update_attributes(params[:workflow])
@@ -536,22 +540,24 @@
format.html { render :action ="" "edit" }
end
- Workflow.versioned_class.record_timestamps = true
+ Workflow.record_timestamps = true
end
end
# PUT /workflows/1;update_version
def update_version
+
+ wv = @workflow.find_version(params[:version])
+
workflow_title = @workflow.title
if params[:version]
# Update differently based on whether a new preview image has been specified or not:
# (But only set image if platform is not windows).
if params[:workflow][:preview].blank? || params[:workflow][:preview].size == 0
- success = @workflow.update_version(params[:version],
- :title => params[:workflow][:title],
- :body => params[:workflow][:body],
- :last_edited_by => current_user.id)
+ success = wv.update_attributes(:title => params[:workflow][:title],
+ :body => params[:workflow][:body],
+ :last_edited_by => current_user.id)
else
logger.debug("Preview image provided. Attempting to set the version's preview image.")
@@ -562,11 +568,10 @@
if RUBY_PLATFORM =~ /mswin32/
success = false
else
- success = @workflow.update_version(params[:version],
- :title => params[:workflow][:title],
- :body => params[:workflow][:body],
- :image => params[:workflow][:preview].read,
- :last_edited_by => current_user.id)
+ success = wv.update_attributes(:title => params[:workflow][:title],
+ :body => params[:workflow][:body],
+ :image => params[:workflow][:preview].read,
+ :last_edited_by => current_user.id)
end
end
else
Modified: branches/versions/app/models/topic_run.rb (3044 => 3045)
--- branches/versions/app/models/topic_run.rb 2012-07-25 13:58:28 UTC (rev 3044)
+++ branches/versions/app/models/topic_run.rb 2012-07-25 13:58:48 UTC (rev 3045)
@@ -6,7 +6,6 @@
require 'acts_as_creditable'
require 'acts_as_attributor'
require 'acts_as_attributable'
-require 'explicit_versioning'
require 'acts_as_reviewable'
require 'acts_as_runnable'
Modified: branches/versions/app/models/topic_tag_map.rb (3044 => 3045)
--- branches/versions/app/models/topic_tag_map.rb 2012-07-25 13:58:28 UTC (rev 3044)
+++ branches/versions/app/models/topic_tag_map.rb 2012-07-25 13:58:48 UTC (rev 3045)
@@ -3,7 +3,6 @@
require 'acts_as_creditable'
require 'acts_as_attributor'
require 'acts_as_attributable'
-require 'explicit_versioning'
require 'acts_as_reviewable'
require 'acts_as_runnable'
@@ -26,4 +25,4 @@
:all,
:order => 'topic_tag_map.probability DESC')
end
-end
\ No newline at end of file
+end
Modified: branches/versions/app/models/topic_workflow_map.rb (3044 => 3045)
--- branches/versions/app/models/topic_workflow_map.rb 2012-07-25 13:58:28 UTC (rev 3044)
+++ branches/versions/app/models/topic_workflow_map.rb 2012-07-25 13:58:48 UTC (rev 3045)
@@ -3,7 +3,6 @@
require 'acts_as_creditable'
require 'acts_as_attributor'
require 'acts_as_attributable'
-require 'explicit_versioning'
require 'acts_as_reviewable'
require 'acts_as_runnable'
@@ -18,4 +17,4 @@
belongs_to :workflow
validates_presence_of :workflow
-end
\ No newline at end of file
+end
Modified: branches/versions/app/models/workflow.rb (3044 => 3045)
--- branches/versions/app/models/workflow.rb 2012-07-25 13:58:28 UTC (rev 3044)
+++ branches/versions/app/models/workflow.rb 2012-07-25 13:58:48 UTC (rev 3045)
@@ -8,7 +8,6 @@
require 'acts_as_creditable'
require 'acts_as_attributor'
require 'acts_as_attributable'
-require 'explicit_versioning'
require 'acts_as_reviewable'
require 'acts_as_runnable'
require 'lib/previews'
@@ -49,47 +48,16 @@
has_previews
- explicit_versioning(:version_column => "current_version",
- :extra_attributes => ["image", "svg"],
- :white_list_columns => ["body"]) do
-
- format_attribute :body
+ has_versions :workflow_versions,
+
+ :attributes => [ :title, :unique_name, :body, :body_html, :content_blob_id,
+ :file_ext, :last_edited_by, :content_type_id ],
- belongs_to :content_blob, :dependent => :destroy
- belongs_to :content_type
+ :mutable => [ :title, :unique_name, :body, :body_html, :file_ext,
+ :last_edited_by, :content_type_id ],
- validates_presence_of :content_blob
- validates_presence_of :content_type
-
- # Update the parent contribution model buy only if this isn't the current version (because the workflow model will take care of that).
- # This is required to keep the contribution's updated_at field accurate.
- after_save { |wv| wv.workflow.contribution.save if wv.workflow.contribution && wv.version != wv.workflow.current_version }
+ :ignore_columns => [ :preview_id, :image, :svg ]
- has_previews
-
- def components
- if workflow.processor_class
- workflow.processor_class.new(content_blob.data).get_components
- else
- XML::Node.new('components')
- end
- end
-
- def processor_class
- if self.content_type
- @processor_class ||= WorkflowTypesHandler.processor_class_for_type_display_name(self.content_type.title)
- end
- end
-
- def display_data_format
- klass = self.processor_class
- @display_data_format = (klass.nil? ? self.file_ext : klass.display_data_format)
- end
-
- end
-
- non_versioned_columns.push("license_id", "tag_list", "preview_id")
-
acts_as_solr(:fields => [ :title, :body, :tag_list, :contributor_name, :kind, :get_all_search_terms ],
:boost => "rank",
:include => [ :comments ]) if Conf.solr_enable
Modified: branches/versions/app/models/workflow_sweeper.rb (3044 => 3045)
--- branches/versions/app/models/workflow_sweeper.rb 2012-07-25 13:58:28 UTC (rev 3044)
+++ branches/versions/app/models/workflow_sweeper.rb 2012-07-25 13:58:48 UTC (rev 3045)
@@ -15,7 +15,7 @@
end
def after_update(workflow)
- expire_sidebar_assets(workflow.contribution.contributor_id) if workflow.contribution.contributor_type == 'User'
+ expire_sidebar_assets(workflow.contributor_id) if workflow.contributor_type == 'User'
expire_multiple_sidebar_favourites(workflow.id, 'Workflow')
expire_listing(workflow.id, 'Workflow')
expire_home_cache
Added: branches/versions/app/models/workflow_version.rb (0 => 3045)
--- branches/versions/app/models/workflow_version.rb (rev 0)
+++ branches/versions/app/models/workflow_version.rb 2012-07-25 13:58:48 UTC (rev 3045)
@@ -0,0 +1,44 @@
+# myExperiment: app/models/workflow_version.rb
+#
+# Copyright (c) 2012 University of Manchester and the University of Southampton.
+# See license.txt for details.
+
+class WorkflowVersion < ActiveRecord::Base
+
+ is_version_of :workflow
+
+ format_attribute :body
+
+ belongs_to :content_blob, :dependent => :destroy
+ belongs_to :content_type
+
+ validates_presence_of :content_blob
+ validates_presence_of :content_type
+
+ # Update the parent contribution model buy only if this isn't the current version (because the workflow model will take care of that).
+ # This is required to keep the contribution's updated_at field accurate.
+ after_save { |wv| wv.workflow.contribution.save if wv.workflow.contribution && wv.version != wv.workflow.current_version }
+
+ has_previews
+
+ def components
+ if workflow.processor_class
+ workflow.processor_class.new(content_blob.data).get_components
+ else
+ XML::Node.new('components')
+ end
+ end
+
+ def processor_class
+ if self.content_type
+ @processor_class ||= WorkflowTypesHandler.processor_class_for_type_display_name(self.content_type.title)
+ end
+ end
+
+ def display_data_format
+ klass = self.processor_class
+ @display_data_format = (klass.nil? ? self.file_ext : klass.display_data_format)
+ end
+
+end
+
Modified: branches/versions/config/environment.rb (3044 => 3045)
--- branches/versions/config/environment.rb 2012-07-25 13:58:28 UTC (rev 3044)
+++ branches/versions/config/environment.rb 2012-07-25 13:58:48 UTC (rev 3045)
@@ -54,7 +54,8 @@
:recaptcha,
:simile_timeline,
:structured_data,
- :validates_email_veracity_of
+ :validates_email_veracity_of,
+ :versioning
]
# Skip frameworks you're not going to use. To use Rails without a database,
Modified: branches/versions/db/schema.rb (3044 => 3045)
--- branches/versions/db/schema.rb 2012-07-25 13:58:28 UTC (rev 3044)
+++ branches/versions/db/schema.rb 2012-07-25 13:58:48 UTC (rev 3045)
@@ -9,7 +9,7 @@
#
# It's strongly recommended to check this file into your version control system.
-ActiveRecord::Schema.define(:version => 94) do
+ActiveRecord::Schema.define(:version => 95) do
create_table "activity_limits", :force => true do |t|
t.string "contributor_type", :null => false
@@ -740,6 +740,7 @@
t.string "reset_password_code"
t.datetime "reset_password_code_until"
t.string "account_status"
+ t.integer "spam_score"
end
create_table "viewings", :force => true do |t|
@@ -792,6 +793,8 @@
t.integer "preview_id"
end
+ add_index "workflow_versions", ["workflow_id"], :name => "index_workflow_versions_on_workflow_id"
+
create_table "workflows", :force => true do |t|
t.integer "contributor_id"
t.string "contributor_type"
Deleted: branches/versions/lib/explicit_versioning.rb (3044 => 3045)
--- branches/versions/lib/explicit_versioning.rb 2012-07-25 13:58:28 UTC (rev 3044)
+++ branches/versions/lib/explicit_versioning.rb 2012-07-25 13:58:48 UTC (rev 3045)
@@ -1,380 +0,0 @@
-module Jits
- module Acts
- # Based heavily on the acts_as_versioned plugin
- module ExplicitVersioning
- CALLBACKS = [:sync_latest_version]
- def self.included(mod) # :nodoc:
- mod.extend(ClassMethods)
- end
-
- module ClassMethods
- def explicit_versioning(options = {}, &extension)
- # don't allow multiple calls
- return if self.included_modules.include?(Jits::Acts::ExplicitVersioning::ActMethods)
-
- send :include, Jits::Acts::ExplicitVersioning::ActMethods
-
- cattr_accessor :versioned_class_name, :versioned_foreign_key, :versioned_table_name, :versioned_inheritance_column,
- :version_column, :version_sequence_name, :non_versioned_columns, :file_columns, :extra_attributes, :white_list_columns, :revision_comments_column,
- :version_association_options, :timestamp_columns, :sync_ignore_columns
-
- self.versioned_class_name = options[:class_name] || "Version"
- self.versioned_foreign_key = options[:foreign_key] || self.to_s.foreign_key
- self.versioned_table_name = options[:table_name] || "#{table_name_prefix}#{base_class.name.demodulize.underscore}_versions#{table_name_suffix}"
- self.versioned_inheritance_column = options[:inheritance_column] || "versioned_#{inheritance_column}"
- self.version_column = options[:version_column] || 'version'
- self.non_versioned_columns = [self.primary_key, inheritance_column, 'version', 'lock_version', versioned_inheritance_column, version_column]
- self.file_columns = options[:file_columns] || []
- self.extra_attributes = options[:extra_attributes] || []
- self.white_list_columns = options[:white_list_columns] || []
- self.revision_comments_column = options[:revision_comments_column] || "revision_comments"
- self.version_association_options = {
- :class_name => "#{self.to_s}::#{versioned_class_name}",
- :foreign_key => "#{versioned_foreign_key}",
- :order => 'version',
- :dependent => :destroy
- }.merge(options[:association_options] || {})
- self.timestamp_columns = options[:timestamp_columns] || [ "created_at", "updated_at" ]
- self.sync_ignore_columns = options[:sync_ignore_columns] || []
-
- class_eval do
- has_many :versions, version_association_options
-
- before_create :set_new_version
- after_create :save_version_on_create
- after_update :sync_latest_version
- end
-
- # create the dynamic versioned model
- const_set(versioned_class_name, Class.new(ActiveRecord::Base)).class_eval do
- def self.reloadable? ; false ; end
- end
-
- versioned_resource = self.to_s.demodulize.underscore.to_sym
-
- versioned_class.set_table_name versioned_table_name
- versioned_class.belongs_to versioned_resource,
- :class_name => "::#{self.to_s}",
- :foreign_key => versioned_foreign_key
-
- versioned_class.class_eval("alias_method :versioned_resource, :#{versioned_resource}")
-
- if block_given?
- versioned_class.class_eval(&extension)
- end
-
- end
- end
-
- module ActMethods
- def self.included(base) # :nodoc:
- base.extend ClassMethods
- end
-
- # Finds a specific version of this model.
- def find_version(version)
- return version if version.is_a?(self.class.versioned_class)
- return nil if version.is_a?(ActiveRecord::Base)
- find_versions(:conditions => ['version = ?', version], :limit => 1).first
- end
-
- # Finds versions of this model. Takes an options hash like <tt>find</tt>
- def find_versions(options = {})
- versions.find(:all, options)
- end
-
- # Saves the object as a new version and also saves the original object as the new version.
- # Make sure to create (and thus save) any inner associations beforehand as these won't be saved here.
- def save_as_new_version(revision_comment=nil)
- return false unless self.valid?
- without_update_callbacks do
- set_new_version
- save_version_on_create(revision_comment)
- self.save
- end
- end
-
- def update_version(version_number_to_update, attributes)
- return false if version_number_to_update.nil? or version_number_to_update.to_i < 1
- return false if attributes.nil? or attributes.empty?
- return false unless (ver = find_version(version_number_to_update))
-
- rtn = ver.update_attributes(attributes)
-
- if rtn
- # if the latest version has been updated then update the main table as well
- if version_number_to_update.to_i == eval("#{self.class.version_column}")
- return update_main_to_version(version_number_to_update, true)
- else
- return true
- end
- else
- return false
- end
- end
-
- def destroy_version(version_number)
- if (ver = find_version(version_number))
- without_update_callbacks do
- # For fault tolerance (ie: to prevent data loss through premature deletion), first...
- # Check to see if the current (aka latest) version has to be deleted,
- # and if so update the main table with the data from the version that will become the latest
- if version_number.to_i == eval("#{self.class.version_column}")
- if versions.count > 1
- to_be_latest_version = versions[versions.count-2].version
- else
- return false
- end
- success = update_main_to_version(to_be_latest_version)
- end
-
- # Then... delete the version
- if success
- retrn ver.destroy
- else
- return false
- end
- end
- end
- end
-
- def describe_version(version_number)
- return "" if versions.count < 2
- return "(earliest)" if version_number == versions.first.version
- return "(latest)" if version_number == versions.last.version
- return ""
- end
-
- def without_update_callbacks(&block)
- self.class.without_update_callbacks(&block)
- end
-
- def empty_callback() end #:nodoc:
-
- protected
-
- def set_new_version
- self.send("#{self.class.version_column}=", self.next_version)
- end
-
- # Saves a version of the model in the versioned table. This is called in the after_create callback by default
- def save_version_on_create(revision_comment=nil)
- rev = self.class.versioned_class.new
- rev.version = send(self.class.version_column)
- rev.send("#{self.class.revision_comments_column}=", revision_comment)
- rev.send("#{self.class.versioned_foreign_key}=", self.id)
- self.clone_versioned_model(self, rev)
- saved = rev.save
-
- if saved
- # Now update timestamp columns on main model.
- # Note: main model doesnt get saved yet.
- update_timestamps(rev, self)
- end
-
- return saved
- end
-
- def update_timestamps(from, to)
- begin
- self.timestamp_columns.each do |key|
- if to.has_attribute?(key)
- logger.debug("explicit_versioning - update_timestamps method - setting timestamp_column '#{key}'")
- if eval("from.#{key}.nil?")
- to.send("#{key}=", nil)
- else
- to.send("#{key}=", eval("from.#{key}"))
- end
- end
- end
- rescue => err
- logger.error("ERROR: An error occurred in the explicit_versioning plugin during the update_timestamps method (setting timestamp columns).")
- logger.error("ERROR DETAILS: #{err}")
- end
- end
-
- # This method updates the latest version entry in the versioned table with the data
- # from the main table (since those two entries should always have the same data).
- def sync_latest_version
- ver = versions.last
- clone_versioned_model(self, ver)
- ver.save
- end
-
- # This method updates the entry in the main table with the data from the version specified,
- # and also updates the corresponding version column in the main table to reflect this.
- # Note: this method on its own should not be used to revert to previous versions as it doesn't actualy delete any versions.
- def update_main_to_version(version_number, process_file_columns=true)
- if (ver = find_version(version_number))
- clone_versioned_model(ver, self, process_file_columns)
- self.send("#{self.class.version_column}=", version_number)
-
- # Now update timestamp columns on main model.
- update_timestamps(ver, self)
-
- return self.save
- else
- return false
- end
- end
-
- # Clones a model.
- def clone_versioned_model(orig_model, new_model, process_file_columns=true)
- self.versioned_attributes.each do |key|
- # Make sure to ignore file columns, white list columns, timestamp columns and any other ignore columns
- unless self.file_columns.include?(key) ||
- self.white_list_columns.include?(key) ||
- self.timestamp_columns.include?(key) ||
- self.sync_ignore_columns.include?(key)
- new_model.send("#{key}=", eval("orig_model.#{key}")) if orig_model.respond_to?(key)
- end
- end
-
- if process_file_columns
- # Now copy over file columns
- begin
- self.file_columns.each do |key|
- if orig_model.has_attribute?(key)
- if eval("orig_model.#{key}.nil?")
- logger.debug("DEBUG: file column is nil")
- new_model.send("#{key}=", nil)
- else
- logger.debug("DEBUG: file column is not nil")
- new_model.send("#{key}=", File.open(eval("orig_model.#{key}")))
- FileUtils.cp(eval("orig_model.#{key}"), eval("new_model.#{key}"))
- end
- end
- end
- rescue => err
- logger.error("ERROR: An error occurred in the explicit_versioning plugin during the clone_versioned_model method (copying file columns).")
- logger.error("ERROR DETAILS: #{err}")
- end
- end
-
- # Now set white list columns
- begin
- self.white_list_columns.each do |key|
- if orig_model.has_attribute?(key)
- if eval("orig_model.#{key}.nil?")
- new_model.send("#{key}=", nil)
- else
- new_model.send("#{key}=", eval("orig_model.#{key}"))
- end
- end
- end
- rescue => err
- logger.error("ERROR: An error occurred in the explicit_versioning plugin during the clone_versioned_model method (setting white list columns).")
- logger.error("ERROR DETAILS: #{err}")
- end
-
- # Set version column accordingly.
- if orig_model.is_a?(self.class.versioned_class)
- new_model[new_model.class.inheritance_column] = orig_model[self.class.versioned_inheritance_column]
- elsif new_model.is_a?(self.class.versioned_class)
- new_model[self.class.versioned_inheritance_column] = orig_model[orig_model.class.inheritance_column]
- end
- end
-
- # Gets the next available version for the current record, or 1 for a new record
- def next_version
- return 1 if new_record?
- (versions.calculate(:max, :version) || 0) + 1
- end
-
- # Returns an array of attribute keys that are versioned. See non_versioned_columns
- def versioned_attributes
- self.attributes.keys.select { |k| !self.class.non_versioned_columns.include?(k) } + extra_attributes
- end
-
- module ClassMethods
- # Finds a specific version of a specific row of this model
- def find_version(id, version)
- find_versions(id,
- :conditions => ["#{versioned_foreign_key} = ? AND version = ?", id, version],
- :limit => 1).first
- end
-
- # Finds versions of a specific model. Takes an options hash like <tt>find</tt>
- def find_versions(id, options = {})
- versioned_class.find :all, {
- :conditions => ["#{versioned_foreign_key} = ?", id],
- :order => 'version' }.merge(options)
- end
-
- # Returns an array of columns that are versioned. See non_versioned_columns
- def versioned_columns
- self.columns.select { |c| !non_versioned_columns.include?(c.name) }
- end
-
- # Returns an instance of the dynamic versioned model
- def versioned_class
- const_get versioned_class_name
- end
-
- # Rake migration task to create the versioned table using options passed
- def create_versioned_table(create_table_options = {})
- # create version column in main table if it does not exist
- if !self.content_columns.find { |c| %w(version lock_version).include? c.name }
- self.connection.add_column table_name, :version, :integer
- end
-
- self.connection.create_table(versioned_table_name, create_table_options) do |t|
- t.column versioned_foreign_key, :integer
- t.column :version, :integer
- t.column revision_comments_column, :text
- end
-
- updated_col = nil
- self.versioned_columns.each do |col|
- updated_col = col if !updated_col && %(updated_at updated_on).include?(col.name)
- self.connection.add_column versioned_table_name, col.name, col.type,
- :limit => col.limit,
- :default => col.default
- end
-
- if type_col = self.columns_hash[inheritance_column]
- self.connection.add_column versioned_table_name, versioned_inheritance_column, type_col.type,
- :limit => type_col.limit,
- :default => type_col.default
- end
-
- if updated_col.nil?
- self.connection.add_column versioned_table_name, :updated_at, :timestamp
- end
- end
-
- # Rake migration task to drop the versioned table
- def drop_versioned_table
- self.connection.drop_table versioned_table_name
- end
-
- # Executes the block with the update callbacks disabled.
- #
- # Foo.without_update_callbacks do
- # @foo.save
- # end
- #
- def without_update_callbacks(&block)
- class_eval do
- CALLBACKS.each do |attr_name|
- alias_method "orig_#{attr_name}".to_sym, attr_name
- alias_method attr_name, :empty_callback
- end
- end
- block.call
- ensure
- class_eval do
- CALLBACKS.each do |attr_name|
- alias_method attr_name, "orig_#{attr_name}".to_sym
- end
- end
- end
- end
- end
- end
- end
-end
-
-ActiveRecord::Base.class_eval do
- include Jits::Acts::ExplicitVersioning
-end
Modified: branches/versions/lib/previews.rb (3044 => 3045)
--- branches/versions/lib/previews.rb 2012-07-25 13:58:28 UTC (rev 3044)
+++ branches/versions/lib/previews.rb 2012-07-25 13:58:48 UTC (rev 3045)
@@ -17,6 +17,8 @@
def image=(x)
+ x = x.read if x.respond_to?(:read)
+
self.preview = Preview.new if self.preview.nil?
self.preview.image_blob = ContentBlob.new if self.preview.image_blob.nil?
@@ -25,6 +27,8 @@
def svg=(x)
+ x = x.read if x.respond_to?(:read)
+
self.preview = Preview.new if self.preview.nil?
self.preview.svg_blob = ContentBlob.new if self.preview.svg_blob.nil?