tamed_beast 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (50) hide show
  1. data/Gemfile +4 -0
  2. data/README +12 -0
  3. data/Rakefile +2 -0
  4. data/app/controllers/forums_controller.rb +60 -0
  5. data/app/controllers/posts_controller.rb +98 -0
  6. data/app/controllers/topics_controller.rb +94 -0
  7. data/app/models/forum.rb +23 -0
  8. data/app/models/post.rb +26 -0
  9. data/app/models/topic.rb +97 -0
  10. data/app/views/forums/_form.html.erb +21 -0
  11. data/app/views/forums/edit.html.erb +12 -0
  12. data/app/views/forums/index.html.erb +63 -0
  13. data/app/views/forums/new.html.erb +10 -0
  14. data/app/views/forums/show.html.erb +81 -0
  15. data/app/views/posts/_edit.html.erb +38 -0
  16. data/app/views/posts/edit.html.erb +14 -0
  17. data/app/views/posts/index.html.erb +1 -0
  18. data/app/views/topics/_form.html.erb +17 -0
  19. data/app/views/topics/edit.html.erb +10 -0
  20. data/app/views/topics/index.html.erb +2 -0
  21. data/app/views/topics/new.html.erb +18 -0
  22. data/app/views/topics/show.html.erb +175 -0
  23. data/config/conf.rb +0 -0
  24. data/lib/generators/tamed_beast/install_generator.rb +56 -0
  25. data/lib/generators/tamed_beast/migration_generator.rb +26 -0
  26. data/lib/generators/tamed_beast/templates/migration.rb +57 -0
  27. data/lib/generators/tamed_beast/templates/routes.rb +9 -0
  28. data/lib/tamed_beast.rb +7 -0
  29. data/lib/tamed_beast/application_helper.rb +18 -0
  30. data/lib/tamed_beast/auth.rb +24 -0
  31. data/lib/tamed_beast/engine.rb +7 -0
  32. data/lib/tamed_beast/version.rb +3 -0
  33. data/tamed_beast.gemspec +23 -0
  34. data/test/fixtures/forums.yml +19 -0
  35. data/test/fixtures/posts.yml +34 -0
  36. data/test/fixtures/topics.yml +29 -0
  37. data/test/fixtures/users.yml +9 -0
  38. data/test/functional/forums_controller_test.rb +51 -0
  39. data/test/functional/posts_controller_test.rb +54 -0
  40. data/test/functional/topics_controller_test.rb +55 -0
  41. data/test/unit/forum_test.rb +10 -0
  42. data/test/unit/post_test.rb +32 -0
  43. data/test/unit/topic_test.rb +33 -0
  44. data/vendor/plugins/white_list/README +29 -0
  45. data/vendor/plugins/white_list/Rakefile +22 -0
  46. data/vendor/plugins/white_list/init.rb +2 -0
  47. data/vendor/plugins/white_list/lib/white_list_helper.rb +97 -0
  48. data/vendor/plugins/white_list/test/white_list_test.rb +132 -0
  49. data/vendor/plugins/white_list_formatted_content/init.rb +27 -0
  50. metadata +161 -0
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in tamed_beast.gemspec
4
+ gemspec
data/README ADDED
@@ -0,0 +1,12 @@
1
+ Welcome to Tamed Beast!
2
+
3
+ Tamed beast is an attempt to tame savage_beast under Rails3. We worked with savage_beast under rails 2.x, but we find ourselves less than comfortable using it...
4
+ And it came the day to migrate to Rails3 and - hey - how do we migrate savage_beast to Rails3? What about all our posts and forums?
5
+ Damn.
6
+ So we started writing our own bulletin board solution, trying to be compatible with the savage_beast data model.
7
+
8
+ TODO:
9
+ * Add moderators / manage moderatorship roles
10
+ * Add views
11
+ * Add search feature
12
+ * Improve tests
data/Rakefile ADDED
@@ -0,0 +1,2 @@
1
+ require 'bundler'
2
+ Bundler::GemHelper.install_tasks
@@ -0,0 +1,60 @@
1
+ class ForumsController < ApplicationController
2
+ before_filter :login_required, :except => [:index, :show]
3
+ before_filter :find_or_initialize_forum, :except => :index
4
+
5
+ #before_filter :admin?, :except => [:show, :index]
6
+
7
+ def index
8
+ @forums = Forum.order('position')
9
+ # reset the page of each forum we have visited when we go back to index
10
+ session[:forum_page] = nil
11
+ respond_to do |format|
12
+ format.html
13
+ format.xml { render :xml => @forums }
14
+ end
15
+ end
16
+
17
+ def show
18
+ respond_to do |format|
19
+ format.html do
20
+ # keep track of when we last viewed this forum for activity indicators
21
+ (session[:forums] ||= {})[@forum.id] = Time.now.utc if !current_user.nil?
22
+ (session[:forum_page] ||= Hash.new(1))[@forum.id] = params[:page].to_i if params[:page]
23
+
24
+ @topics = @forum.topics.paginate :page => params[:page]
25
+ User.find(:all, :conditions => ['id IN (?)', @topics.collect { |t| t.replied_by }.uniq]) unless @topics.blank?
26
+ end
27
+ format.xml { render :xml => @forum }
28
+ end
29
+ end
30
+
31
+ def create
32
+ @forum.attributes = params[:forum]
33
+ @forum.save!
34
+ respond_to do |format|
35
+ format.html { redirect_to @forum }
36
+ format.xml { head :created, :location => forum_url(@forum, :format => :xml) }
37
+ end
38
+ end
39
+
40
+ def update
41
+ @forum.update_attributes!(params[:forum])
42
+ respond_to do |format|
43
+ format.html { redirect_to @forum }
44
+ format.xml { head 200 }
45
+ end
46
+ end
47
+
48
+ def destroy
49
+ @forum.destroy
50
+ respond_to do |format|
51
+ format.html { redirect_to forums_path }
52
+ format.xml { head 200 }
53
+ end
54
+ end
55
+
56
+ protected
57
+ def find_or_initialize_forum
58
+ @forum = params[:id] ? Forum.find(params[:id]) : Forum.new
59
+ end
60
+ end
@@ -0,0 +1,98 @@
1
+ class PostsController < ApplicationController
2
+ before_filter :find_post, :except => [:index, :create]
3
+ before_filter :login_required, :except => [:index, :show]
4
+ #@@query_options = { :select => "#{Post.table_name}.*, #{Topic.table_name}.title as topic_title, #{Forum.table_name}.name as forum_name", :joins => "inner join #{Topic.table_name} on #{Post.table_name}.topic_id = #{Topic.table_name}.id inner join #{Forum.table_name} on #{Topic.table_name}.forum_id = #{Forum.table_name}.id" }
5
+
6
+ def index
7
+ #conditions = []
8
+ #[:user_id, :forum_id, :topic_id].each { |attr| conditions << Post.send(:sanitize_sql, ["#{Post.table_name}.#{attr} = ?", params[attr]]) if params[attr] }
9
+ #conditions = conditions.empty? ? nil : conditions.collect { |c| "(#{c})" }.join(' AND ')
10
+ #@posts = Post.paginate @@query_options.merge(:conditions => conditions, :page => params[:page], :count => {:select => "#{Post.table_name}.id"}, :order => post_order)
11
+ #@users = User.find(:all, :select => 'distinct *', :conditions => ['id in (?)', @posts.collect(&:user_id).uniq]).index_by(&:id)
12
+ #render_posts_or_xml
13
+
14
+ #@posts = Post.where(:forum_id => params[:forum_id]).where(:topic_id => params[:topic_id]).order('created_at desc').paginate(:page => params[:page])
15
+ end
16
+
17
+ def show
18
+ respond_to do |format|
19
+ format.html { redirect_to forum_topic_path(@post.forum_id, @post.topic_id) }
20
+ format.xml { render :xml => @post.to_xml }
21
+ end
22
+ end
23
+
24
+ def create
25
+ @topic = Topic.find_by_id_and_forum_id(params[:topic_id],params[:forum_id])
26
+ @forum = @topic.forum
27
+ @post = @topic.posts.build(params[:post])
28
+ @post.user = current_user
29
+ @post.save!
30
+ email_users_in_topic(@topic)
31
+ respond_to do |format|
32
+ format.html do
33
+ redirect_to forum_topic_path(:forum_id => params[:forum_id], :id => params[:topic_id], :anchor => @post.dom_id, :page => params[:page] || '1')
34
+ end
35
+ format.xml { head :created, :location => post_url(:forum_id => params[:forum_id], :topic_id => params[:topic_id], :id => @post, :format => :xml) }
36
+ end
37
+ rescue ActiveRecord::RecordInvalid
38
+ flash[:bad_reply] = 'Please post something at least...'[:post_something_message]
39
+ respond_to do |format|
40
+ format.html do
41
+ redirect_to forum_topic_path(:forum_id => params[:forum_id], :id => params[:topic_id], :anchor => 'reply-form', :page => params[:page] || '1')
42
+ end
43
+ end
44
+ end
45
+
46
+ def edit
47
+ respond_to do |format|
48
+ format.html
49
+ end
50
+ end
51
+
52
+ def update
53
+ @post.attributes = params[:post]
54
+ @post.save!
55
+ rescue ActiveRecord::RecordInvalid
56
+ flash[:bad_reply] = 'An error occurred'[:error_occured_message]
57
+ ensure
58
+ respond_to do |format|
59
+ format.html do
60
+ redirect_to forum_topic_path(:forum_id => params[:forum_id], :id => params[:topic_id], :anchor => @post.dom_id, :page => params[:page] || '1')
61
+ end
62
+ format.xml { head 200 }
63
+ end
64
+ end
65
+
66
+ def destroy
67
+ @post.destroy
68
+ #flash[:notice] = "Post of '{title}' was deleted."[:post_deleted_message, @post.topic.title]
69
+ respond_to do |format|
70
+ format.html do
71
+ redirect_to(@post.topic.frozen? ?
72
+ forum_path(params[:forum_id]) :
73
+ forum_topic_path(:forum_id => params[:forum_id], :id => params[:topic_id], :page => params[:page]))
74
+ end
75
+ format.xml { head 200 }
76
+ end
77
+ end
78
+
79
+ protected
80
+ def post_order
81
+ "#{Post.table_name}.created_at#{params[:forum_id] && params[:topic_id] ? nil : " desc"}"
82
+ end
83
+
84
+ def find_post
85
+ @post = Post.find_by_id_and_topic_id_and_forum_id(params[:id], params[:topic_id], params[:forum_id]) || raise(ActiveRecord::RecordNotFound)
86
+ end
87
+
88
+ def email_users_in_topic(topic)
89
+ sent = []
90
+ topic.posts.find(:all, :conditions => ["user_id <> ?", current_user.id]).each do |post|
91
+ unless sent.include?(post.user.id)
92
+ UserMailer.send_later(:deliver_forum_notification, post.user, topic) if post.user.notify_forum?
93
+ sent << post.user_id
94
+ end
95
+ end
96
+ UserMailer.send_later(:deliver_forum_notification_admin, topic)
97
+ end
98
+ end
@@ -0,0 +1,94 @@
1
+ class TopicsController < ApplicationController
2
+ before_filter :find_forum_and_topic, :except => :index
3
+ before_filter :login_required , :only => [:new, :create, :edit, :update, :destroy]
4
+
5
+ def index
6
+ respond_to do |format|
7
+ format.html { redirect_to forum_path(params[:forum_id]) }
8
+ format.xml do
9
+ @topics = Topic.paginate_by_forum_id(params[:forum_id], :order => 'sticky desc, replied_at desc', :page => params[:page])
10
+ render :xml => @topics.to_xml
11
+ end
12
+ end
13
+ end
14
+
15
+ def new
16
+ @topic = Topic.new
17
+ end
18
+
19
+ def show
20
+ respond_to do |format|
21
+ format.html do
22
+ # keep track of when we last viewed this topic for activity indicators
23
+ (session[:topics] ||= {})[@topic.id] = Time.now.utc if !current_user.nil?
24
+ # authors of topics don't get counted towards total hits
25
+ @topic.hit! unless current_user.nil? and @topic.user == current_user
26
+ @posts = @topic.posts.paginate :page => params[:page]
27
+ User.find(:all, :conditions => ['id IN (?)', @posts.collect { |p| p.user_id }.uniq]) unless @posts.nil?
28
+ @post = Post.new
29
+ end
30
+ format.xml do
31
+ render :xml => @topic.to_xml
32
+ end
33
+ end
34
+ end
35
+
36
+ def create
37
+ topic_save, post_save = false, false
38
+
39
+ Topic.transaction do
40
+ @topic = Topic.new(:title => params[:topic][:title])
41
+ @topic.forum_id = @forum.id
42
+ assign_protected
43
+ if @topic.save
44
+ topic_save = true
45
+ @post = Post.new(:body => params[:topic][:body])
46
+ @post.topic_id = @topic.id
47
+ @post.forum_id = @topic.forum_id
48
+ @post.user = current_user
49
+ @topic.body = @post.body
50
+ post_save = true if @post.save
51
+ end
52
+ end
53
+
54
+ if topic_save && post_save
55
+ respond_to do |format|
56
+ format.html { redirect_to forum_topic_path(@forum, @topic) }
57
+ format.xml { head :created, :location => topic_url(:forum_id => @forum, :id => @topic, :format => :xml) }
58
+ end
59
+ else
60
+ render :action => "new"
61
+ end
62
+ end
63
+
64
+ def update
65
+ @topic.attributes = params[:topic]
66
+ assign_protected
67
+ @topic.save!
68
+ respond_to do |format|
69
+ format.html { redirect_to forum_topic_path(@forum, @topic) }
70
+ format.xml { head 200 }
71
+ end
72
+ end
73
+
74
+ def destroy
75
+ @topic.destroy
76
+ respond_to do |format|
77
+ format.html { redirect_to forum_path(@forum) }
78
+ format.xml { head 200 }
79
+ end
80
+ end
81
+
82
+ protected
83
+ def assign_protected
84
+ @topic.user = current_user if @topic.new_record?
85
+ #return unless admin?
86
+ #@topic.sticky, @topic.locked = params[:topic][:sticky], params[:topic][:locked]
87
+ @topic.forum_id = params[:forum_id] if params[:forum_id]
88
+ end
89
+
90
+ def find_forum_and_topic
91
+ @forum = Forum.find(params[:forum_id])
92
+ @topic = @forum.topics.find(params[:id]) if params[:id]
93
+ end
94
+ end
@@ -0,0 +1,23 @@
1
+ class Forum < ActiveRecord::Base
2
+ acts_as_list
3
+
4
+ validates_presence_of :name
5
+
6
+ has_many :topics, :order => 'sticky desc, replied_at desc', :dependent => :delete_all
7
+ has_one :recent_topic, :class_name => 'Topic', :order => 'sticky desc, replied_at desc'
8
+
9
+ # this is used to see if a forum is "fresh"... we can't use topics because it puts
10
+ # stickies first even if they are not the most recently modified
11
+ has_many :recent_topics, :class_name => 'Topic', :order => 'replied_at DESC'
12
+ has_one :recent_topic, :class_name => 'Topic', :order => 'replied_at DESC'
13
+
14
+ has_many :posts, :order => "#{Post.table_name}.created_at DESC", :dependent => :delete_all
15
+ has_one :recent_post, :order => "#{Post.table_name}.created_at DESC", :class_name => 'Post'
16
+
17
+ format_attribute :description
18
+
19
+ # retrieves forums ordered by position
20
+ def self.find_ordered(options = {})
21
+ self.order('position')
22
+ end
23
+ end
@@ -0,0 +1,26 @@
1
+ class Post < ActiveRecord::Base
2
+ def self.per_page() 25 end
3
+
4
+ belongs_to :forum
5
+ belongs_to :user
6
+ belongs_to :topic
7
+
8
+ format_attribute :body
9
+ before_create { |r| r.forum_id = r.topic.forum_id }
10
+ after_create :update_cached_fields
11
+ after_destroy :update_cached_fields
12
+
13
+ validates_presence_of :user_id, :body, :topic_id
14
+ attr_accessible :body
15
+
16
+ def editable_by?(user)
17
+ user && (user.id == user_id)
18
+ end
19
+
20
+ protected
21
+ # using count isn't ideal but it gives us correct caches each time
22
+ def update_cached_fields
23
+ Forum.update_all ['posts_count = ?', Post.count(:id, :conditions => {:forum_id => forum_id})], ['id = ?', forum_id]
24
+ topic.update_cached_post_fields(self)
25
+ end
26
+ end
@@ -0,0 +1,97 @@
1
+ class Topic < ActiveRecord::Base
2
+ validates_presence_of :forum_id, :user_id, :title
3
+ before_create :set_default_replied_at_and_sticky
4
+ before_update :check_for_changing_forums
5
+ after_save :update_forum_counter_cache
6
+ before_destroy :update_post_user_counts
7
+ after_destroy :update_forum_counter_cache
8
+
9
+ belongs_to :forum
10
+ belongs_to :user
11
+ belongs_to :last_post, :class_name => "Post", :foreign_key => 'last_post_id'
12
+
13
+ has_many :posts, :order => "#{Post.table_name}.created_at", :dependent => :delete_all
14
+ has_one :recent_post, :order => "#{Post.table_name}.created_at DESC", :class_name => 'Post'
15
+
16
+ has_many :voices, :through => :posts, :source => :user, :uniq => true
17
+ belongs_to :replied_by_user, :foreign_key => "replied_by", :class_name => "User"
18
+
19
+ attr_accessible :title
20
+ attr_accessor :body
21
+
22
+ def hit!
23
+ self.class.increment_counter :hits, id
24
+ end
25
+
26
+ def sticky?
27
+ sticky == 1
28
+ end
29
+
30
+ def views
31
+ hits
32
+ end
33
+
34
+ def paged?
35
+ posts_count > Post.per_page
36
+ end
37
+
38
+ def last_page
39
+ [(posts_count.to_f / Post.per_page).ceil.to_i, 1].max
40
+ end
41
+
42
+ def editable_by?(user)
43
+ user && (user.id == user_id)
44
+ end
45
+
46
+ def update_cached_post_fields(post)
47
+ # these fields are not accessible to mass assignment
48
+ remaining_post = post.frozen? ? recent_post : post
49
+ if remaining_post
50
+ self.class.update_all(['replied_at = ?, replied_by = ?, last_post_id = ?, posts_count = ?',
51
+ remaining_post.created_at, remaining_post.user_id, remaining_post.id, posts.count], ['id = ?', id])
52
+ else
53
+ self.destroy
54
+ end
55
+ end
56
+
57
+ protected
58
+ def set_default_replied_at_and_sticky
59
+ self.replied_at = Time.now.utc
60
+ self.sticky ||= 0
61
+ end
62
+
63
+ def set_post_forum_id
64
+ Post.update_all ['forum_id = ?', forum_id], ['topic_id = ?', id]
65
+ end
66
+
67
+ def check_for_changing_forums
68
+ old = Topic.find(id)
69
+ @old_forum_id = old.forum_id if old.forum_id != forum_id
70
+ true
71
+ end
72
+
73
+ # using count isn't ideal but it gives us correct caches each time
74
+ def update_forum_counter_cache
75
+ forum_conditions = ['topics_count = ?', Topic.count(:id, :conditions => {:forum_id => forum_id})]
76
+ # if the topic moved forums
77
+ if !frozen? && @old_forum_id && @old_forum_id != forum_id
78
+ set_post_forum_id
79
+ Forum.update_all ['topics_count = ?, posts_count = ?',
80
+ Topic.count(:id, :conditions => {:forum_id => @old_forum_id}),
81
+ Post.count(:id, :conditions => {:forum_id => @old_forum_id})], ['id = ?', @old_forum_id]
82
+ end
83
+ # if the topic moved forums or was deleted
84
+ if frozen? || (@old_forum_id && @old_forum_id != forum_id)
85
+ forum_conditions.first << ", posts_count = ?"
86
+ forum_conditions << Post.count(:id, :conditions => {:forum_id => forum_id})
87
+ end
88
+ # User doesn't have update_posts_count method in SB2, as reported by Ryan
89
+ #@voices.each &:update_posts_count if @voices
90
+ Forum.update_all forum_conditions, ['id = ?', forum_id]
91
+ @old_forum_id = @voices = nil
92
+ end
93
+
94
+ def update_post_user_counts
95
+ @voices = voices.to_a
96
+ end
97
+ end
@@ -0,0 +1,21 @@
1
+ <p style="float:right; margin-top:0">
2
+ </p>
3
+
4
+ <p id="forum_name">
5
+
6
+ <table border="0" cellspacing="0" cellpadding="0" class="noborder nopad wide">
7
+ <td>
8
+ <label><%= 'Title'[:title_title] %></label><br />
9
+ <%= form.text_field :name, :class => "primary" %>
10
+ </td>
11
+ <td style="text-align:right">
12
+ <label><%= 'Position'[:position_title] %></label><br />
13
+ <%= form.text_field :position, :size => 5 %>
14
+
15
+ </td>
16
+ </table>
17
+
18
+ </p>
19
+ <p id="forum_descripion">
20
+ <label><%= 'Description'[:description_title] %></label><br />
21
+ <%= form.text_area :description, :rows => 7 %></p>