app/models/wiki_service.rb in instiki-0.10.0 vs app/models/wiki_service.rb in instiki-0.10.1
- old
+ new
@@ -1,233 +1,233 @@
-require 'open-uri'
-require 'yaml'
-require 'madeleine'
-require 'madeleine/automatic'
-require 'madeleine/zmarshal'
-
-require 'web'
-require 'page'
-require 'author'
-require 'file_yard'
-require 'instiki_errors'
-
-module AbstractWikiService
-
- attr_reader :webs, :system
-
- def authenticate(password)
- # system['password'] variant is for compatibility with storages from older versions
- password == (@system[:password] || @system['password'] || 'instiki')
- end
-
- def create_web(name, address, password = nil)
- @webs[address] = Web.new(self, name, address, password) unless @webs[address]
- end
-
- def delete_web(address)
- @webs[address] = nil
- end
-
- def file_yard(web)
- raise "Web #{@web.name} does not belong to this wiki service" unless @webs.values.include?(web)
- # TODO cache FileYards
- FileYard.new("#{self.storage_path}/#{web.address}", web.max_upload_size)
- end
-
- def init_wiki_service
- @webs = {}
- @system = {}
- end
-
- def read_page(web_address, page_name)
- ApplicationController.logger.debug "Reading page '#{page_name}' from web '#{web_address}'"
- web = @webs[web_address]
- if web.nil?
- ApplicationController.logger.debug "Web '#{web_address}' not found"
- return nil
- else
- page = web.pages[page_name]
- ApplicationController.logger.debug "Page '#{page_name}' #{page.nil? ? 'not' : ''} found"
- return page
- end
- end
-
- def remove_orphaned_pages(web_address)
- @webs[web_address].remove_pages(@webs[web_address].select.orphaned_pages)
- end
-
- def revise_page(web_address, page_name, content, revised_on, author)
- page = read_page(web_address, page_name)
- page.revise(content, revised_on, author)
- page
- end
-
- def rollback_page(web_address, page_name, revision_number, created_at, author_id = nil)
- page = read_page(web_address, page_name)
- page.rollback(revision_number, created_at, author_id)
- page
- end
-
- def setup(password, web_name, web_address)
- @system[:password] = password
- create_web(web_name, web_address)
- end
-
- def setup?
- not (@webs.empty?)
- end
-
- def edit_web(old_address, new_address, name, markup, color, additional_style, safe_mode = false,
- password = nil, published = false, brackets_only = false, count_pages = false,
- allow_uploads = true, max_upload_size = nil)
-
- if not @webs.key? old_address
- raise Instiki::ValidationError.new("Web with address '#{old_address}' does not exist")
- end
-
- if old_address != new_address
- if @webs.key? new_address
- raise Instiki::ValidationError.new("There is already a web with address '#{new_address}'")
- end
- @webs[new_address] = @webs[old_address]
- @webs.delete(old_address)
- @webs[new_address].address = new_address
- end
-
- web = @webs[new_address]
- web.refresh_revisions if settings_changed?(web, markup, safe_mode, brackets_only)
-
- web.name, web.markup, web.color, web.additional_style, web.safe_mode =
- name, markup, color, additional_style, safe_mode
-
- web.password, web.published, web.brackets_only, web.count_pages =
- password, published, brackets_only, count_pages, allow_uploads
- web.allow_uploads, web.max_upload_size = allow_uploads, max_upload_size.to_i
- end
-
- def write_page(web_address, page_name, content, written_on, author)
- page = Page.new(@webs[web_address], page_name, content, written_on, author)
- @webs[web_address].add_page(page)
- page
- end
-
- def storage_path
- self.class.storage_path
- end
-
- private
- def settings_changed?(web, markup, safe_mode, brackets_only)
- web.markup != markup ||
- web.safe_mode != safe_mode ||
- web.brackets_only != brackets_only
- end
-end
-
-class WikiService
-
- include AbstractWikiService
- include Madeleine::Automatic::Interceptor
-
- # These methods do not change the state of persistent objects, and
- # should not be ogged by Madeleine
- automatic_read_only :authenticate, :read_page, :setup?, :webs, :storage_path, :file_yard
-
- @@storage_path = './storage/'
-
- class << self
-
- def storage_path=(storage_path)
- @@storage_path = storage_path
- end
-
- def storage_path
- @@storage_path
- end
-
- def clean_storage
- MadeleineServer.clean_storage(self)
- end
-
- def instance
- @madeleine ||= MadeleineServer.new(self)
- @system = @madeleine.system
- return @system
- end
-
- def snapshot
- @madeleine.snapshot
- end
-
- end
-
- def initialize
- init_wiki_service
- end
-
-end
-
-class MadeleineServer
-
- attr_reader :storage_path
-
- # Clears all the command_log and snapshot files located in the storage directory, so the
- # database is essentially dropped and recreated as blank
- def self.clean_storage(service)
- begin
- Dir.foreach(service.storage_path) do |file|
- if file =~ /(command_log|snapshot)$/
- File.delete(File.join(service.storage_path, file))
- end
- end
- rescue
- Dir.mkdir(service.storage_path)
- end
- end
-
- def initialize(service)
- @storage_path = service.storage_path
- @server = Madeleine::Automatic::AutomaticSnapshotMadeleine.new(service.storage_path,
- Madeleine::ZMarshal.new) {
- service.new
- }
- start_snapshot_thread
- end
-
- def command_log_present?
- not Dir[storage_path + '/*.command_log'].empty?
- end
-
- def snapshot
- @server.take_snapshot
- end
-
- def start_snapshot_thread
- Thread.new(@server) {
- hours_since_last_snapshot = 0
- while true
- begin
- hours_since_last_snapshot += 1
- # Take a snapshot if there is a command log, or 24 hours
- # have passed since the last snapshot
- if command_log_present? or hours_since_last_snapshot >= 24
- ActionController::Base.logger.info "[#{Time.now.strftime('%Y-%m-%d %H:%M:%S')}] " +
- 'Taking a Madeleine snapshot'
- snapshot
- hours_since_last_snapshot = 0
- end
- sleep(1.hour)
- rescue => e
- ActionController::Base.logger.error(e)
- # wait for a minute (not to spoof the log with the same error)
- # and go back into the loop, to keep trying
- sleep(1.minute)
- ActionController::Base.logger.info("Retrying to save a snapshot")
- end
- end
- }
- end
-
- def system
- @server.system
- end
-
-end
+require 'open-uri'
+require 'yaml'
+require 'madeleine'
+require 'madeleine/automatic'
+require 'madeleine/zmarshal'
+
+require 'web'
+require 'page'
+require 'author'
+require 'file_yard'
+require 'instiki_errors'
+
+module AbstractWikiService
+
+ attr_reader :webs, :system
+
+ def authenticate(password)
+ # system['password'] variant is for compatibility with storages from older versions
+ password == (@system[:password] || @system['password'] || 'instiki')
+ end
+
+ def create_web(name, address, password = nil)
+ @webs[address] = Web.new(self, name, address, password) unless @webs[address]
+ end
+
+ def delete_web(address)
+ @webs[address] = nil
+ end
+
+ def file_yard(web)
+ raise "Web #{@web.name} does not belong to this wiki service" unless @webs.values.include?(web)
+ # TODO cache FileYards
+ FileYard.new("#{self.storage_path}/#{web.address}", web.max_upload_size)
+ end
+
+ def init_wiki_service
+ @webs = {}
+ @system = {}
+ end
+
+ def read_page(web_address, page_name)
+ ApplicationController.logger.debug "Reading page '#{page_name}' from web '#{web_address}'"
+ web = @webs[web_address]
+ if web.nil?
+ ApplicationController.logger.debug "Web '#{web_address}' not found"
+ return nil
+ else
+ page = web.pages[page_name]
+ ApplicationController.logger.debug "Page '#{page_name}' #{page.nil? ? 'not' : ''} found"
+ return page
+ end
+ end
+
+ def remove_orphaned_pages(web_address)
+ @webs[web_address].remove_pages(@webs[web_address].select.orphaned_pages)
+ end
+
+ def revise_page(web_address, page_name, content, revised_on, author)
+ page = read_page(web_address, page_name)
+ page.revise(content, revised_on, author)
+ page
+ end
+
+ def rollback_page(web_address, page_name, revision_number, created_at, author_id = nil)
+ page = read_page(web_address, page_name)
+ page.rollback(revision_number, created_at, author_id)
+ page
+ end
+
+ def setup(password, web_name, web_address)
+ @system[:password] = password
+ create_web(web_name, web_address)
+ end
+
+ def setup?
+ not (@webs.empty?)
+ end
+
+ def edit_web(old_address, new_address, name, markup, color, additional_style, safe_mode = false,
+ password = nil, published = false, brackets_only = false, count_pages = false,
+ allow_uploads = true, max_upload_size = nil)
+
+ if not @webs.key? old_address
+ raise Instiki::ValidationError.new("Web with address '#{old_address}' does not exist")
+ end
+
+ if old_address != new_address
+ if @webs.key? new_address
+ raise Instiki::ValidationError.new("There is already a web with address '#{new_address}'")
+ end
+ @webs[new_address] = @webs[old_address]
+ @webs.delete(old_address)
+ @webs[new_address].address = new_address
+ end
+
+ web = @webs[new_address]
+ web.refresh_revisions if settings_changed?(web, markup, safe_mode, brackets_only)
+
+ web.name, web.markup, web.color, web.additional_style, web.safe_mode =
+ name, markup, color, additional_style, safe_mode
+
+ web.password, web.published, web.brackets_only, web.count_pages =
+ password, published, brackets_only, count_pages, allow_uploads
+ web.allow_uploads, web.max_upload_size = allow_uploads, max_upload_size.to_i
+ end
+
+ def write_page(web_address, page_name, content, written_on, author)
+ page = Page.new(@webs[web_address], page_name, content, written_on, author)
+ @webs[web_address].add_page(page)
+ page
+ end
+
+ def storage_path
+ self.class.storage_path
+ end
+
+ private
+ def settings_changed?(web, markup, safe_mode, brackets_only)
+ web.markup != markup ||
+ web.safe_mode != safe_mode ||
+ web.brackets_only != brackets_only
+ end
+end
+
+class WikiService
+
+ include AbstractWikiService
+ include Madeleine::Automatic::Interceptor
+
+ # These methods do not change the state of persistent objects, and
+ # should not be logged by Madeleine
+ automatic_read_only :authenticate, :read_page, :setup?, :webs, :storage_path, :file_yard
+
+ @@storage_path = './storage/'
+
+ class << self
+
+ def storage_path=(storage_path)
+ @@storage_path = storage_path
+ end
+
+ def storage_path
+ @@storage_path
+ end
+
+ def clean_storage
+ MadeleineServer.clean_storage(self)
+ end
+
+ def instance
+ @madeleine ||= MadeleineServer.new(self)
+ @system = @madeleine.system
+ return @system
+ end
+
+ def snapshot
+ @madeleine.snapshot
+ end
+
+ end
+
+ def initialize
+ init_wiki_service
+ end
+
+end
+
+class MadeleineServer
+
+ attr_reader :storage_path
+
+ # Clears all the command_log and snapshot files located in the storage directory, so the
+ # database is essentially dropped and recreated as blank
+ def self.clean_storage(service)
+ begin
+ Dir.foreach(service.storage_path) do |file|
+ if file =~ /(command_log|snapshot)$/
+ File.delete(File.join(service.storage_path, file))
+ end
+ end
+ rescue
+ Dir.mkdir(service.storage_path)
+ end
+ end
+
+ def initialize(service)
+ @storage_path = service.storage_path
+ @server = Madeleine::Automatic::AutomaticSnapshotMadeleine.new(service.storage_path,
+ Madeleine::ZMarshal.new) {
+ service.new
+ }
+ start_snapshot_thread
+ end
+
+ def command_log_present?
+ not Dir[storage_path + '/*.command_log'].empty?
+ end
+
+ def snapshot
+ @server.take_snapshot
+ end
+
+ def start_snapshot_thread
+ Thread.new(@server) {
+ hours_since_last_snapshot = 0
+ while true
+ begin
+ hours_since_last_snapshot += 1
+ # Take a snapshot if there is a command log, or 24 hours
+ # have passed since the last snapshot
+ if command_log_present? or hours_since_last_snapshot >= 24
+ ActionController::Base.logger.info "[#{Time.now.strftime('%Y-%m-%d %H:%M:%S')}] " +
+ 'Taking a Madeleine snapshot'
+ snapshot
+ hours_since_last_snapshot = 0
+ end
+ sleep(1.hour)
+ rescue => e
+ ActionController::Base.logger.error(e)
+ # wait for a minute (not to spoof the log with the same error)
+ # and go back into the loop, to keep trying
+ sleep(1.minute)
+ ActionController::Base.logger.info("Retrying to save a snapshot")
+ end
+ end
+ }
+ end
+
+ def system
+ @server.system
+ end
+
+end