require_dependency 'revision' class Page < ActiveRecord::Base # Page usage areas WIKI = 'wiki' BLIKI = 'bliki' TASK = 'task' TEMPLATE = 'template' SYSTEM = 'system' belongs_to :web, :dependent => true has_many :revisions, :order => 'id', :dependent => true has_one :current_revision, :class_name => 'Revision', :conditions => ['current = ?', true] has_and_belongs_to_many :tags validates_uniqueness_of :name, :scope => :web_id # Add a new revision to the page. Must supply the following keys: # * :contents - the new markup contents # * :author - author of change # Other optional keys are: # * :force - true: forces creation of a new revision, false: forces update of current revision def revise options = {} @error = nil crev = current_revision Revision.transaction do begin if crev && ( (options.has_key?(:force) && options[:force] == false) || (!options.has_key?(:force) && crev.updated_at + 30.minutes > Time.now && crev.author == options[:author])) # This is a continuous change - reuse existing revision crev.markup_content = options[:content] crev.save crev.current! else # create new revision crev.not_current! if crev crev = Revision.create :page => self, :markup_content => options[:content] || options[:markup_content], :author => options[:author], :number => revisions.size+1 crev.current! end rescue Exception => detail @error = detail raise end end raise @error if @error revisions.reload current_revision(true) end def plain_name WikiWords.separate name end # Forward method calls to the current revision, so the page responds to all revision calls def method_missing(method_symbol, *args, &block) if Revision.instance_methods.include? method_symbol.to_s revisions.last.send(method_symbol, *args, &block) else super end end # Page locking - prevent simultaneous edits without explicit break def lock(time, locked_by) update_attributes(:locked_at => time, :locked_by => locked_by) end def lock_duration(time) ((time - locked_at) / 60).to_i unless locked_at.nil? end def unlock update_attributes(:locked_at => nil, :locked_by => nil) end # Before the lock horizon, the page has "just been locked", after it the page # is considered to have been locked for some time. This is purely for display # purposes. LOCK_HORIZON = 30.minutes def locked?(comparison_time) locked_at + LOCK_HORIZON > comparison_time unless locked_at.nil? end end