From 80f033f25394e78f4745f8ca05b4b0a89dcc2c35 Mon Sep 17 00:00:00 2001 From: albert Date: Mon, 15 Feb 2010 17:32:32 -0500 Subject: [PATCH] added wiki page --- app/models/artist.rb | 2 +- app/models/pool.rb | 1 + app/models/wiki_page.rb | 58 +++++++++++++++++ app/models/wiki_page_version.rb | 12 ++++ app/presenters/wiki_page_presenter.rb | 53 ++++++++++++++++ db/development_structure.sql | 62 ++++++++++++++++++- ...0100215213756_create_wiki_page_versions.rb | 19 ++++++ test/factories/wiki_page.rb | 7 +++ test/unit/wiki_page_test.rb | 39 ++++++++++-- 9 files changed, 247 insertions(+), 6 deletions(-) create mode 100644 app/models/wiki_page_version.rb create mode 100644 app/presenters/wiki_page_presenter.rb create mode 100644 db/migrate/20100215213756_create_wiki_page_versions.rb create mode 100644 test/factories/wiki_page.rb diff --git a/app/models/artist.rb b/app/models/artist.rb index ed972fd9b..64186345d 100644 --- a/app/models/artist.rb +++ b/app/models/artist.rb @@ -11,7 +11,7 @@ class Artist < ActiveRecord::Base has_one :wiki_page, :foreign_key => "title", :primary_key => "name" has_one :tag_alias, :foreign_key => "antecedent_name", :primary_key => "name" accepts_nested_attributes_for :wiki_page - attr_accessible :url_string, :other_names, :group_name, :wiki_page_attributes + attr_accessible :name, :url_string, :other_names, :group_name, :wiki_page_attributes module UrlMethods module ClassMethods diff --git a/app/models/pool.rb b/app/models/pool.rb index 58155b9f2..9dff10c0b 100644 --- a/app/models/pool.rb +++ b/app/models/pool.rb @@ -7,6 +7,7 @@ class Pool < ActiveRecord::Base belongs_to :updater, :class_name => "User" has_many :versions, :class_name => "PoolVersion", :dependent => :destroy after_save :create_version + attr_accessible :name, :description, :post_ids, :is_public, :is_active def self.create_anonymous(creator, creator_ip_addr) pool = Pool.create(:name => "TEMP:#{Time.now.to_f}.#{rand(1_000_000)}", :creator => creator, :updater_id => creator.id, :updater_ip_addr => creator_ip_addr) diff --git a/app/models/wiki_page.rb b/app/models/wiki_page.rb index e48fc246c..f27031fbe 100644 --- a/app/models/wiki_page.rb +++ b/app/models/wiki_page.rb @@ -1,3 +1,61 @@ class WikiPage < ActiveRecord::Base attr_accessor :updater_id, :updater_ip_addr + before_save :normalize_title + after_save :create_version + belongs_to :creator, :class_name => "User" + belongs_to :updater, :class_name => "User" + validates_uniqueness_of :title, :case_sensitive => false + validates_presence_of :body, :updater_id, :updater_ip_addr + attr_protected :text_search_index, :is_locked, :version + scope :titled, lambda {|title| where(["title = ?", title.downcase.tr(" ", "_")])} + has_one :tag, :foreign_key => "name", :primary_key => "title" + has_one :artist, :foreign_key => "name", :primary_key => "title" + has_many :versions, :class_name => "WikiPageVersion" + + def self.build_relation(options = {}) + relation = where() + + if options[:title] + relation = relation.where(["title LIKE ? ESCAPE E'\\\\'", options[:title].downcase.tr(" ", "_").to_escaped_for_sql_like]) + end + + if options[:creator_id] + relation = relation.where(["creator_id = ?", options[:creator_id]]) + end + + relation + end + + def revert_to(version) + self.title = version.title + self.body = version.body + self.is_locked = version.is_locked + end + + def revert_to!(version) + revert_to(version) + save! + end + + def normalize_title + self.title = title.downcase.tr(" ", "_") + end + + def creator_name + User.find_name(user_id).tr("_", " ") + end + + def pretty_title + title.tr("_", " ") + end + + def create_version + versions.create( + :updater_id => updater_id, + :updater_ip_addr => updater_ip_addr, + :title => title, + :body => body, + :is_locked => is_locked + ) + end end diff --git a/app/models/wiki_page_version.rb b/app/models/wiki_page_version.rb new file mode 100644 index 000000000..43bea5863 --- /dev/null +++ b/app/models/wiki_page_version.rb @@ -0,0 +1,12 @@ +class WikiPageVersion < ActiveRecord::Base + belongs_to :wiki_page + belongs_to :updater + + def updater_name + User.find_name(updater_id) + end + + def pretty_title + title.tr("_", " ") + end +end diff --git a/app/presenters/wiki_page_presenter.rb b/app/presenters/wiki_page_presenter.rb new file mode 100644 index 000000000..dee7b05fd --- /dev/null +++ b/app/presenters/wiki_page_presenter.rb @@ -0,0 +1,53 @@ +class WikiPagePresenter + + # Produce a formatted page that shows the difference between two versions of a page. + def diff(other_version) + pattern = Regexp.new('(?:<.+?>)|(?:[0-9_A-Za-z\x80-\xff]+[\x09\x20]?)|(?:[ \t]+)|(?:\r?\n)|(?:.+?)') + + thisarr = self.body.scan(pattern) + otharr = other_version.body.scan(pattern) + + cbo = Diff::LCS::ContextDiffCallbacks.new + diffs = thisarr.diff(otharr, cbo) + + escape_html = lambda {|str| str.gsub(/&/,'&').gsub(//,'>')} + + output = thisarr; + output.each { |q| q.replace(CGI.escape_html(q)) } + + diffs.reverse_each do |hunk| + newchange = hunk.max{|a,b| a.old_position <=> b.old_position} + newstart = newchange.old_position + oldstart = hunk.min{|a,b| a.old_position <=> b.old_position}.old_position + + if newchange.action == '+' + output.insert(newstart, "") + end + + hunk.reverse_each do |chg| + case chg.action + when '-' + oldstart = chg.old_position + output[chg.old_position] = "" if chg.old_element.match(/^\r?\n$/) + when '+' + if chg.new_element.match(/^\r?\n$/) + output.insert(chg.old_position, "[nl]") + else + output.insert(chg.old_position, "#{escape_html[chg.new_element]}") + end + end + end + + if newchange.action == '+' + output.insert(newstart, "") + end + + if hunk[0].action == '-' + output.insert((newstart == oldstart || newchange.action != '+') ? newstart+1 : newstart, "") + output.insert(oldstart, "") + end + end + + output.join.gsub(/\r?\n/, "[nl]") + end +end diff --git a/db/development_structure.sql b/db/development_structure.sql index 0a731eeab..d19a9ad16 100644 --- a/db/development_structure.sql +++ b/db/development_structure.sql @@ -948,6 +948,42 @@ CREATE SEQUENCE users_id_seq ALTER SEQUENCE users_id_seq OWNED BY users.id; +-- +-- Name: wiki_page_versions; Type: TABLE; Schema: public; Owner: -; Tablespace: +-- + +CREATE TABLE wiki_page_versions ( + id integer NOT NULL, + wiki_page_id integer NOT NULL, + updater_id integer NOT NULL, + updater_ip_addr inet NOT NULL, + title character varying(255) NOT NULL, + body text NOT NULL, + is_locked boolean NOT NULL, + created_at timestamp without time zone, + updated_at timestamp without time zone +); + + +-- +-- Name: wiki_page_versions_id_seq; Type: SEQUENCE; Schema: public; Owner: - +-- + +CREATE SEQUENCE wiki_page_versions_id_seq + START WITH 1 + INCREMENT BY 1 + NO MAXVALUE + NO MINVALUE + CACHE 1; + + +-- +-- Name: wiki_page_versions_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: - +-- + +ALTER SEQUENCE wiki_page_versions_id_seq OWNED BY wiki_page_versions.id; + + -- -- Name: wiki_pages; Type: TABLE; Schema: public; Owner: -; Tablespace: -- @@ -1158,6 +1194,13 @@ ALTER TABLE uploads ALTER COLUMN id SET DEFAULT nextval('uploads_id_seq'::regcla ALTER TABLE users ALTER COLUMN id SET DEFAULT nextval('users_id_seq'::regclass); +-- +-- Name: id; Type: DEFAULT; Schema: public; Owner: - +-- + +ALTER TABLE wiki_page_versions ALTER COLUMN id SET DEFAULT nextval('wiki_page_versions_id_seq'::regclass); + + -- -- Name: id; Type: DEFAULT; Schema: public; Owner: - -- @@ -1365,6 +1408,14 @@ ALTER TABLE ONLY users ADD CONSTRAINT users_pkey PRIMARY KEY (id); +-- +-- Name: wiki_page_versions_pkey; Type: CONSTRAINT; Schema: public; Owner: -; Tablespace: +-- + +ALTER TABLE ONLY wiki_page_versions + ADD CONSTRAINT wiki_page_versions_pkey PRIMARY KEY (id); + + -- -- Name: wiki_pages_pkey; Type: CONSTRAINT; Schema: public; Owner: -; Tablespace: -- @@ -1758,6 +1809,13 @@ CREATE UNIQUE INDEX index_users_on_email ON users USING btree (email); CREATE UNIQUE INDEX index_users_on_name ON users USING btree (lower((name)::text)); +-- +-- Name: index_wiki_page_versions_on_wiki_page_id; Type: INDEX; Schema: public; Owner: -; Tablespace: +-- + +CREATE INDEX index_wiki_page_versions_on_wiki_page_id ON wiki_page_versions USING btree (wiki_page_id); + + -- -- Name: index_wiki_pages_on_body_index_index; Type: INDEX; Schema: public; Owner: -; Tablespace: -- @@ -1853,4 +1911,6 @@ INSERT INTO schema_migrations (version) VALUES ('20100214080557'); INSERT INTO schema_migrations (version) VALUES ('20100214080605'); -INSERT INTO schema_migrations (version) VALUES ('20100215182234'); \ No newline at end of file +INSERT INTO schema_migrations (version) VALUES ('20100215182234'); + +INSERT INTO schema_migrations (version) VALUES ('20100215213756'); \ No newline at end of file diff --git a/db/migrate/20100215213756_create_wiki_page_versions.rb b/db/migrate/20100215213756_create_wiki_page_versions.rb new file mode 100644 index 000000000..a6e0ea2ca --- /dev/null +++ b/db/migrate/20100215213756_create_wiki_page_versions.rb @@ -0,0 +1,19 @@ +class CreateWikiPageVersions < ActiveRecord::Migration + def self.up + create_table :wiki_page_versions do |t| + t.column :wiki_page_id, :integer, :null => false + t.column :updater_id, :integer, :null => false + t.column :updater_ip_addr, "inet", :null => false + t.column :title, :string, :null => false + t.column :body, :text, :null => false + t.column :is_locked, :boolean, :null => false + t.timestamps + end + + add_index :wiki_page_versions, :wiki_page_id + end + + def self.down + drop_table :wiki_page_versions + end +end diff --git a/test/factories/wiki_page.rb b/test/factories/wiki_page.rb new file mode 100644 index 000000000..aa8308047 --- /dev/null +++ b/test/factories/wiki_page.rb @@ -0,0 +1,7 @@ +Factory.define(:wiki_page) do |f| + f.creator {|x| x.association(:user)} + f.title {|x| Faker::Lorem.words} + f.body {Faker::Lorem.sentences} + f.updater_id {|x| x.creator_id} + f.updater_ip_addr "127.0.0.1" +end diff --git a/test/unit/wiki_page_test.rb b/test/unit/wiki_page_test.rb index f97bcdc0c..483488ba5 100644 --- a/test/unit/wiki_page_test.rb +++ b/test/unit/wiki_page_test.rb @@ -1,8 +1,39 @@ -require 'test_helper' +require File.dirname(__FILE__) + '/../test_helper' class WikiPageTest < ActiveSupport::TestCase - # Replace this with your real tests. - test "the truth" do - assert true + context "A wiki page" do + setup do + MEMCACHE.flush_all + end + + should "normalize its title" do + wp = Factory.create(:wiki_page, :title => "HOT POTATO") + assert_equal("hot_potato", wp.title) + end + + should "search by title" do + Factory.create(:wiki_page, :title => "HOT POTATO") + matches = WikiPage.titled("hot potato") + assert_equal(1, matches.count) + assert_equal("hot_potato", matches.first.title) + end + + should "create versions" do + wp = nil + user = Factory.create(:user) + + assert_difference("WikiPageVersion.count") do + wp = Factory.create(:wiki_page, :title => "xxx") + end + + assert_difference("WikiPageVersion.count") do + wp.update_attributes(:title => "yyy", :updater_id => user.id, :updater_ip_addr => "127.0.0.1") + end + + version = WikiPageVersion.first + wp.revert_to!(version) + + assert_equal("xxx", wp.title) + end end end