instiki/app/models/page.rb
Jacques Distler d786e95a77 Ruby 1.9 + MySQL Hack
The default encoding in MySQL is latin1. Ruby 1.9
is a stickler about the encoding of a sequence of bytes.
In this case, a utf8 page name stored in the database comes
back as "ASCII-8BIT" (ie, binary). Coerce that back to utf8.

This doesn't affect SQLite3, and it doesn't affect Ruby 1.8.
It doesn't even affect MySQL databases with "utf8" encoding
(though that has other issues, since MySQL's utf8 support is
broken).
There are probably other, similar problems lurking.
2010-01-04 06:41:04 -06:00

127 lines
3.8 KiB
Ruby

class Page < ActiveRecord::Base
belongs_to :web
has_many :revisions, :order => 'id', :dependent => :destroy
has_many :wiki_references, :order => 'referenced_name'
has_one :current_revision, :class_name => 'Revision', :order => 'id DESC'
def revise(content, name, time, author, renderer)
revisions_size = new_record? ? 0 : revisions.size
if (revisions_size > 0) and content == current_revision.content and name == self.name
raise Instiki::ValidationError.new(
"You have tried to save page '#{name}' without changing its content")
end
self.name = name
author = Author.new(author.to_s) unless author.is_a?(Author)
# Try to render content to make sure that markup engine can take it,
renderer.revision = Revision.new(
:page => self, :content => content, :author => author, :revised_at => time)
renderer.display_content(update_references = true)
# A user may change a page, look at it and make some more changes - several times.
# Not to record every such iteration as a new revision, if the previous revision was done
# by the same author, not more than 30 minutes ago, then update the last revision instead of
# creating a new one
if (revisions_size > 0) && continous_revision?(time, author)
current_revision.update_attributes(:content => content, :revised_at => time)
else
revisions.build(:content => content, :author => author, :revised_at => time)
end
save
self
end
def rollback(revision_number, time, author_ip, renderer)
roll_back_revision = self.revisions[revision_number]
if roll_back_revision.nil?
raise Instiki::ValidationError.new("Revision #{revision_number} not found")
end
author = Author.new(roll_back_revision.author.name, author_ip)
revise(roll_back_revision.content, self.name, time, author, renderer)
end
def revisions?
revisions.size > 1
end
def previous_revision(revision)
revision_index = revisions.each_with_index do |rev, index|
if rev.id == revision.id
break index
else
nil
end
end
if revision_index.nil? or revision_index == 0
nil
else
revisions[revision_index - 1]
end
end
def references
web.select.pages_that_reference(name)
end
def wiki_words
wiki_references.select { |ref| ref.wiki_word? }.map { |ref| ref.referenced_name }
end
def linked_from
web.select.pages_that_link_to(name)
end
def redirects
wiki_references.select { |ref| ref.redirected_page? }.map { |ref| ref.referenced_name }
end
def included_from
web.select.pages_that_include(name)
end
# Returns the original wiki-word name as separate words, so "MyPage" becomes "My Page".
def plain_name
web.brackets_only? ? CGI.escapeHTML(name).as_utf8 : CGI.escapeHTML(WikiWords.separate(name)).as_utf8
end
LOCKING_PERIOD = 30.minutes
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_attribute(:locked_at, nil)
end
def locked?(comparison_time)
locked_at + LOCKING_PERIOD > comparison_time unless locked_at.nil?
end
def to_param
name
end
private
def continous_revision?(time, author)
(current_revision.author == author) && (revised_at + 30.minutes > time)
end
# Forward method calls to the current revision, so the page responds to all revision calls
def method_missing(method_id, *args, &block)
method_name = method_id.to_s
# Perform a hand-off to AR::Base#method_missing
if @attributes.include?(method_name) or md = /(=|\?|_before_type_cast)$/.match(method_name)
super(method_id, *args, &block)
else
current_revision.send(method_id)
end
end
end