tamed_beast 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
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>