move to AR
This commit is contained in:
parent
c4b7b2d9f2
commit
26c046cdfa
51 changed files with 2345 additions and 516 deletions
|
@ -46,7 +46,6 @@ class AdminController < ApplicationController
|
|||
end
|
||||
|
||||
def edit_web
|
||||
|
||||
system_password = @params['system_password']
|
||||
if system_password
|
||||
# form submitted
|
||||
|
@ -67,6 +66,7 @@ class AdminController < ApplicationController
|
|||
flash[:info] = "Web '#{@params['address']}' was successfully updated"
|
||||
redirect_home(@params['address'])
|
||||
rescue Instiki::ValidationError => e
|
||||
logger.warn e.message
|
||||
@error = e.message
|
||||
# and re-render the same template again
|
||||
end
|
||||
|
|
|
@ -10,12 +10,12 @@ class ApplicationController < ActionController::Base
|
|||
# a global variable is used here because Rails reloads controller and model classes in the
|
||||
# development environment; therefore, storing it as a class variable does not work
|
||||
# class variable is, anyway, not much different from a global variable
|
||||
$instiki_wiki_service = the_wiki
|
||||
#$instiki_wiki_service = the_wiki
|
||||
logger.debug("Wiki service: #{the_wiki.to_s}")
|
||||
end
|
||||
|
||||
def self.wiki
|
||||
$instiki_wiki_service
|
||||
Wiki.new
|
||||
end
|
||||
|
||||
protected
|
||||
|
@ -146,7 +146,7 @@ class ApplicationController < ActionController::Base
|
|||
end
|
||||
|
||||
def wiki
|
||||
$instiki_wiki_service
|
||||
self.class.wiki
|
||||
end
|
||||
|
||||
def needs_authorization?(action)
|
||||
|
|
|
@ -78,7 +78,7 @@ class FileController < ApplicationController
|
|||
return false
|
||||
end
|
||||
|
||||
unless @web.allow_uploads
|
||||
unless @web.allow_uploads?
|
||||
render_text 'File uploads are blocked by the webmaster', '403 Forbidden'
|
||||
return false
|
||||
end
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
require 'application'
|
||||
require 'fileutils'
|
||||
require 'redcloth_for_tex'
|
||||
require 'parsedate'
|
||||
|
@ -156,7 +155,7 @@ class WikiController < ApplicationController
|
|||
end
|
||||
|
||||
def published
|
||||
if @web.published
|
||||
if @web.published?
|
||||
@page = wiki.read_page(@web_name, @page_name || 'HomePage')
|
||||
else
|
||||
redirect_home
|
||||
|
@ -270,7 +269,7 @@ class WikiController < ApplicationController
|
|||
end
|
||||
|
||||
def export_web_to_tex(file_path)
|
||||
@tex_content = table_of_contents(@web.pages['HomePage'].content, render_tex_web)
|
||||
@tex_content = table_of_contents(@web.page('HomePage').content, render_tex_web)
|
||||
File.open(file_path, 'w') { |f| f.write(render_to_string('wiki/tex_web')) }
|
||||
end
|
||||
|
||||
|
@ -342,7 +341,7 @@ class WikiController < ApplicationController
|
|||
end
|
||||
|
||||
def rss_with_content_allowed?
|
||||
@web.password.nil? or @web.published
|
||||
@web.password.nil? or @web.published?
|
||||
end
|
||||
|
||||
def truncate(text, length = 30, truncate_string = '...')
|
||||
|
|
|
@ -1,4 +1,125 @@
|
|||
class Page < ActiveRecord::Base
|
||||
belongs_to :web
|
||||
has_many :pages
|
||||
end
|
||||
has_many :revisions, :order => 'number'
|
||||
has_one :current_revision, :class_name => 'Revision', :order => 'number DESC'
|
||||
|
||||
def revise(content, created_at, author)
|
||||
revisions_size = new_record? ? 0 : revisions.size
|
||||
if (revisions_size > 0) and content == current_revision.content
|
||||
raise Instiki::ValidationError.new(
|
||||
"You have tried to save page '#{name}' without changing its content")
|
||||
end
|
||||
|
||||
author = Author.new(author.to_s) unless author.is_a?(Author)
|
||||
|
||||
# Try to render content to make sure that markup engine can take it,
|
||||
# before addin a revision to the page
|
||||
Revision.new(:page => self, :content => content, :created_at => created_at, :author => author).force_rendering
|
||||
|
||||
# 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?(created_at, author)
|
||||
current_revision.update_attributes(:created_at => created_at, :content => content)
|
||||
else
|
||||
Revision.create(:page => self, :content => content, :created_at => created_at, :author => author)
|
||||
end
|
||||
|
||||
self.created_at = created_at
|
||||
save
|
||||
web.refresh_pages_with_references(name) if revisions_size == 0
|
||||
|
||||
self
|
||||
end
|
||||
|
||||
def rollback(revision_number, created_at, author_ip = nil)
|
||||
roll_back_revision = Revision.find(:first, :conditions => ['page_id = ? AND number = ?', id, revision_number])
|
||||
revise(roll_back_revision.content, created_at, Author.new(roll_back_revision.author, author_ip))
|
||||
end
|
||||
|
||||
def revisions?
|
||||
revisions.size > 1
|
||||
end
|
||||
|
||||
def revised_on
|
||||
created_on
|
||||
end
|
||||
|
||||
def in_category?(cat)
|
||||
cat.nil? || cat.empty? || categories.include?(cat)
|
||||
end
|
||||
|
||||
def categories
|
||||
display_content.find_chunks(Category).map { |cat| cat.list }.flatten
|
||||
end
|
||||
|
||||
def authors
|
||||
revisions.collect { |rev| rev.author }
|
||||
end
|
||||
|
||||
def references
|
||||
web.select.pages_that_reference(name)
|
||||
end
|
||||
|
||||
def linked_from
|
||||
web.select.pages_that_link_to(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? ? name : WikiWords.separate(name)
|
||||
end
|
||||
|
||||
# used to build chunk ids.
|
||||
#def id
|
||||
# @id ||= name.unpack('H*').first
|
||||
#end
|
||||
|
||||
def link(options = {})
|
||||
web.make_link(name, nil, options)
|
||||
end
|
||||
|
||||
def author_link(options = {})
|
||||
web.make_link(author, nil, options)
|
||||
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
|
||||
|
||||
private
|
||||
|
||||
def continous_revision?(created_at, author)
|
||||
current_revision.author == author && current_revision.created_at + 30.minutes > created_at
|
||||
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
|
||||
|
|
|
@ -1,3 +1,122 @@
|
|||
require 'diff'
|
||||
class Revision < ActiveRecord::Base
|
||||
belongs_to :page
|
||||
end
|
||||
composed_of :author, :mapping => [ %w(author name), %w(ip ip) ]
|
||||
|
||||
def created_on
|
||||
created_at.to_date
|
||||
end
|
||||
|
||||
def pretty_created_at
|
||||
# Must use DateTime because Time doesn't support %e on at least some platforms
|
||||
DateTime.new(
|
||||
created_at.year, created_at.mon, created_at.day, created_at.hour, created_at.min
|
||||
).strftime "%B %e, %Y %H:%M"
|
||||
end
|
||||
|
||||
# todo: drop next_revision, previuous_revision and number from here - unused code
|
||||
def next_revision
|
||||
Revision.find_by_number_and_page_id(number+1, page_id)
|
||||
end
|
||||
|
||||
def previous_revision
|
||||
@previous_revions ||= number > 0 ? Revision.find_by_number_and_page_id(number-1, page_id) : nil
|
||||
end
|
||||
|
||||
# Returns an array of all the WikiIncludes present in the content of this revision.
|
||||
def wiki_includes
|
||||
unless @wiki_includes_cache
|
||||
chunks = display_content.find_chunks(Include)
|
||||
@wiki_includes_cache = chunks.map { |c| ( c.escaped? ? nil : c.page_name ) }.compact.uniq
|
||||
end
|
||||
@wiki_includes_cache
|
||||
end
|
||||
|
||||
# Returns an array of all the WikiReferences present in the content of this revision.
|
||||
def wiki_references
|
||||
unless @wiki_references_cache
|
||||
chunks = display_content.find_chunks(WikiChunk::WikiReference)
|
||||
@wiki_references_cache = chunks.map { |c| ( c.escaped? ? nil : c.page_name ) }.compact.uniq
|
||||
end
|
||||
@wiki_references_cache
|
||||
end
|
||||
|
||||
# Returns an array of all the WikiWords present in the content of this revision.
|
||||
def wiki_words
|
||||
unless @wiki_words_cache
|
||||
wiki_chunks = display_content.find_chunks(WikiChunk::WikiLink)
|
||||
@wiki_words_cache = wiki_chunks.map { |c| ( c.escaped? ? nil : c.page_name ) }.compact.uniq
|
||||
end
|
||||
@wiki_words_cache
|
||||
end
|
||||
|
||||
# Returns an array of all the WikiWords present in the content of this revision.
|
||||
# that already exists as a page in the web.
|
||||
def existing_pages
|
||||
wiki_words.select { |wiki_word| page.web.page(wiki_word) }
|
||||
end
|
||||
|
||||
# Returns an array of all the WikiWords present in the content of this revision
|
||||
# that *doesn't* already exists as a page in the web.
|
||||
def unexisting_pages
|
||||
wiki_words - existing_pages
|
||||
end
|
||||
|
||||
# Explicit check for new type of display cache with chunks_by_type method.
|
||||
# Ensures new version works with older snapshots.
|
||||
def display_content
|
||||
unless @display_cache && @display_cache.respond_to?(:chunks_by_type)
|
||||
@display_cache = WikiContent.new(self)
|
||||
@display_cache.render!
|
||||
end
|
||||
@display_cache
|
||||
end
|
||||
|
||||
def display_diff
|
||||
previous_revision ? HTMLDiff.diff(previous_revision.display_content, display_content) : display_content
|
||||
end
|
||||
|
||||
def clear_display_cache
|
||||
@wiki_words_cache = @published_cache = @display_cache = @wiki_includes_cache =
|
||||
@wiki_references_cache = nil
|
||||
end
|
||||
|
||||
def display_published
|
||||
unless @published_cache && @published_cache.respond_to?(:chunks_by_type)
|
||||
@published_cache = WikiContent.new(self, {:mode => :publish})
|
||||
@published_cache.render!
|
||||
end
|
||||
@published_cache
|
||||
end
|
||||
|
||||
def display_content_for_export
|
||||
WikiContent.new(self, {:mode => :export} ).render!
|
||||
end
|
||||
|
||||
def force_rendering
|
||||
begin
|
||||
display_content.render!
|
||||
rescue => e
|
||||
logger.error "Failed rendering page #{@name}"
|
||||
logger.error e
|
||||
message = e.message
|
||||
# substitute content with an error message
|
||||
self.content = <<-EOL
|
||||
<p>Markup engine has failed to render this page, raising the following error:</p>
|
||||
<p>#{message}</p>
|
||||
<pre>#{self.content}</pre>
|
||||
EOL
|
||||
clear_display_cache
|
||||
raise e
|
||||
end
|
||||
end
|
||||
|
||||
protected
|
||||
before_create :set_revision_number
|
||||
after_create :force_rendering
|
||||
after_save :clear_display_cache
|
||||
|
||||
def set_revision_number
|
||||
self.number = self.class.count(['page_id = ?', page_id]) + 1
|
||||
end
|
||||
end
|
||||
|
|
4
app/models/system.rb
Normal file
4
app/models/system.rb
Normal file
|
@ -0,0 +1,4 @@
|
|||
class System < ActiveRecord::Base
|
||||
set_table_name 'system'
|
||||
validates_presence_of :password
|
||||
end
|
|
@ -1,3 +1,173 @@
|
|||
require 'cgi'
|
||||
|
||||
class Web < ActiveRecord::Base
|
||||
has_many :pages
|
||||
end
|
||||
has_many :pages#, :include => [:current_revision, :web]
|
||||
|
||||
def wiki
|
||||
Wiki.new
|
||||
end
|
||||
|
||||
def file_yard
|
||||
@file_yard ||= FileYard.new("#{Wiki.storage_path}/#{address}", max_upload_size)
|
||||
end
|
||||
|
||||
def settings_changed?(markup, safe_mode, brackets_only)
|
||||
self.markup != markup ||
|
||||
self.safe_mode != safe_mode ||
|
||||
self.brackets_only != brackets_only
|
||||
end
|
||||
|
||||
def add_page(name, content, created_at, author)
|
||||
page = page(name) || Page.new(:web => self, :name => name)
|
||||
page.revise(content, created_at, author)
|
||||
end
|
||||
|
||||
def authors
|
||||
select.authors
|
||||
end
|
||||
|
||||
def categories
|
||||
select.map { |page| page.categories }.flatten.uniq.sort
|
||||
end
|
||||
|
||||
def page(name)
|
||||
pages.find(:first, :conditions => ['name = ?', name])
|
||||
end
|
||||
|
||||
def has_page?(name)
|
||||
Page.count(['web_id = ? AND name = ?', id, name]) > 0
|
||||
end
|
||||
|
||||
def has_file?(name)
|
||||
wiki.file_yard(self).has_file?(name)
|
||||
end
|
||||
|
||||
def markup
|
||||
read_attribute('markup').to_sym
|
||||
end
|
||||
|
||||
def make_file_link(mode, name, text, base_url)
|
||||
link = CGI.escape(name)
|
||||
case mode
|
||||
when :export
|
||||
if has_file?(name) then "<a class=\"existingWikiWord\" href=\"#{link}.html\">#{text}</a>"
|
||||
else "<span class=\"newWikiWord\">#{text}</span>" end
|
||||
when :publish
|
||||
if has_file?(name) then "<a class=\"existingWikiWord\" href=\"#{base_url}/published/#{link}\">#{text}</a>"
|
||||
else "<span class=\"newWikiWord\">#{text}</span>" end
|
||||
else
|
||||
if has_file?(name)
|
||||
"<a class=\"existingWikiWord\" href=\"#{base_url}/file/#{link}\">#{text}</a>"
|
||||
else
|
||||
"<span class=\"newWikiWord\">#{text}<a href=\"#{base_url}/file/#{link}\">?</a></span>"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Create a link for the given page name and link text based
|
||||
# on the render mode in options and whether the page exists
|
||||
# in the this web.
|
||||
# The links a relative, and will work only if displayed on another WikiPage.
|
||||
# It should not be used in menus, templates and such - instead, use link_to_page helper
|
||||
def make_link(name, text = nil, options = {})
|
||||
text = CGI.escapeHTML(text || WikiWords.separate(name))
|
||||
mode = options[:mode] || :show
|
||||
base_url = options[:base_url] || '..'
|
||||
link_type = options[:link_type] || :show
|
||||
case link_type.to_sym
|
||||
when :show
|
||||
make_page_link(mode, name, text, base_url)
|
||||
when :file
|
||||
make_file_link(mode, name, text, base_url)
|
||||
when :pic
|
||||
make_pic_link(mode, name, text, base_url)
|
||||
else
|
||||
raise "Unknown link type: #{link_type}"
|
||||
end
|
||||
end
|
||||
|
||||
def make_page_link(mode, name, text, base_url)
|
||||
link = CGI.escape(name)
|
||||
case mode.to_sym
|
||||
when :export
|
||||
if has_page?(name) then %{<a class="existingWikiWord" href="#{link}.html">#{text}</a>}
|
||||
else %{<span class="newWikiWord">#{text}</span>} end
|
||||
when :publish
|
||||
if has_page?(name) then %{<a class="existingWikiWord" href="#{base_url}/published/#{link}">#{text}</a>}
|
||||
else %{<span class="newWikiWord">#{text}</span>} end
|
||||
else
|
||||
if has_page?(name)
|
||||
%{<a class="existingWikiWord" href="#{base_url}/show/#{link}">#{text}</a>}
|
||||
else
|
||||
%{<span class="newWikiWord">#{text}<a href="#{base_url}/show/#{link}">?</a></span>}
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def make_pic_link(mode, name, text, base_url)
|
||||
link = CGI.escape(name)
|
||||
case mode.to_sym
|
||||
when :export
|
||||
if has_file?(name) then %{<img alt="#{text}" src="#{link}" />}
|
||||
else %{<img alt="#{text}" src="no image" />} end
|
||||
when :publish
|
||||
if has_file?(name) then %{<img alt="#{text}" src="#{link}" />}
|
||||
else %{<span class="newWikiWord">#{text}</span>} end
|
||||
else
|
||||
if has_file?(name) then %{<img alt="#{text}" src="#{base_url}/pic/#{link}" />}
|
||||
else %{<span class="newWikiWord">#{text}<a href="#{base_url}/pic/#{link}">?</a></span>} end
|
||||
end
|
||||
end
|
||||
|
||||
# Clears the display cache for all the pages with references to
|
||||
def refresh_pages_with_references(page_name)
|
||||
#select.pages_that_reference(page_name).each { |page|
|
||||
# page.revisions.each { |revision| revision.clear_display_cache }
|
||||
#}
|
||||
end
|
||||
|
||||
def refresh_revisions
|
||||
select.each { |page| page.revisions.each { |revision| revision.clear_display_cache } }
|
||||
end
|
||||
|
||||
def remove_pages(pages_to_be_removed)
|
||||
pages_to_be_removed.each { |p| p.destroy }
|
||||
end
|
||||
|
||||
def revised_on
|
||||
select.most_recent_revision
|
||||
end
|
||||
|
||||
def select(&condition)
|
||||
PageSet.new(self, pages, condition)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
# Returns an array of all the wiki words in any current revision
|
||||
def wiki_words
|
||||
pages.inject([]) { |wiki_words, page| wiki_words << page.wiki_words }.flatten.uniq
|
||||
end
|
||||
|
||||
# Returns an array of all the page names on this web
|
||||
def page_names
|
||||
pages.map { |p| p.name }
|
||||
end
|
||||
|
||||
protected
|
||||
before_save :sanitize_markup
|
||||
before_validation :validate_address
|
||||
validates_uniqueness_of :address
|
||||
validates_length_of :color, :in => 3..6
|
||||
|
||||
def sanitize_markup
|
||||
self.markup = markup.to_s
|
||||
end
|
||||
|
||||
def validate_address
|
||||
unless address == CGI.escape(address)
|
||||
self.errors.add(:address, 'should contain only valid URI characters')
|
||||
raise Instiki::ValidationError.new("#{self.class.human_attribute_name('address')} #{errors.on(:address)}")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
</li>
|
||||
<% end %></ul>
|
||||
|
||||
<% if @web.count_pages %>
|
||||
<% if @web.count_pages? %>
|
||||
<% total_chars = @pages_in_category.characters %>
|
||||
<p><small>All content: <%= total_chars %> chars / <%= sprintf("%-.1f", (total_chars / 2275 )) %> pages</small></p>
|
||||
<% end %>
|
||||
|
|
|
@ -25,7 +25,7 @@
|
|||
<%= @page.revisions? ? "Revised" : "Created" %> on <%= @page.pretty_created_at %>
|
||||
by <%= @page.author_link %>
|
||||
<%= "(#{@page.author.ip})" if @page.author.respond_to?(:ip) %>
|
||||
<% if @web.count_pages %>
|
||||
<% if @web.count_pages? %>
|
||||
<% total_chars = @page.content.length %>
|
||||
(<%= total_chars %> characters / <%= sprintf("%-.1f", (total_chars / 2275 rescue 0)) %> pages)
|
||||
<% end %>
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue