savage-beast 0.1.0

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 (265) hide show
  1. data/.gitignore +2 -0
  2. data/README.rdoc +42 -0
  3. data/Rakefile +25 -0
  4. data/VERSION +1 -0
  5. data/app/controllers/application.rb +6 -0
  6. data/app/controllers/beast_application_controller.rb +3 -0
  7. data/app/controllers/forums_controller.rb +64 -0
  8. data/app/controllers/moderators_controller.rb +10 -0
  9. data/app/controllers/monitorships_controller.rb +22 -0
  10. data/app/controllers/posts_controller.rb +134 -0
  11. data/app/controllers/topics_controller.rb +110 -0
  12. data/app/helpers/count_helper.rb +13 -0
  13. data/app/helpers/forums_helper.rb +15 -0
  14. data/app/helpers/moderators_helper.rb +2 -0
  15. data/app/helpers/monitorships_helper.rb +2 -0
  16. data/app/helpers/posts_helper.rb +3 -0
  17. data/app/helpers/topics_helper.rb +3 -0
  18. data/app/models/forum.rb +26 -0
  19. data/app/models/moderatorship.rb +6 -0
  20. data/app/models/monitorship.rb +5 -0
  21. data/app/models/monitorships_sweeper.rb +9 -0
  22. data/app/models/post.rb +33 -0
  23. data/app/models/posts_sweeper.rb +12 -0
  24. data/app/models/topic.rb +94 -0
  25. data/app/views/forums/_form.html.erb +21 -0
  26. data/app/views/forums/edit.html.erb +12 -0
  27. data/app/views/forums/index.html.erb +77 -0
  28. data/app/views/forums/new.html.erb +10 -0
  29. data/app/views/forums/show.html.erb +94 -0
  30. data/app/views/layouts/_head.html.erb +34 -0
  31. data/app/views/layouts/_post.rss.builder +9 -0
  32. data/app/views/layouts/application.html.erb +29 -0
  33. data/app/views/layouts/beast.html.erb +29 -0
  34. data/app/views/monitorships/create.js.rjs +4 -0
  35. data/app/views/monitorships/destroy.js.rjs +4 -0
  36. data/app/views/posts/_edit.html.erb +38 -0
  37. data/app/views/posts/edit.html.erb +14 -0
  38. data/app/views/posts/edit.js.rjs +6 -0
  39. data/app/views/posts/index.html.erb +53 -0
  40. data/app/views/posts/index.rss.builder +20 -0
  41. data/app/views/posts/monitored.html.erb +55 -0
  42. data/app/views/posts/monitored.rss.builder +15 -0
  43. data/app/views/posts/update.js.rjs +3 -0
  44. data/app/views/topics/_form.html.erb +28 -0
  45. data/app/views/topics/edit.html.erb +10 -0
  46. data/app/views/topics/index.html.erb +2 -0
  47. data/app/views/topics/new.html.erb +18 -0
  48. data/app/views/topics/show.html.erb +183 -0
  49. data/app/views/topics/show.rss.builder +16 -0
  50. data/config/routes.rb +18 -0
  51. data/generators/beast/beast_generator.rb +88 -0
  52. data/generators/beast/templates/migrations/create_savage_tables.rb +73 -0
  53. data/generators/beast/templates/public/images/clearbits/_readme.txt +12 -0
  54. data/generators/beast/templates/public/images/clearbits/add.gif +0 -0
  55. data/generators/beast/templates/public/images/clearbits/addressbook.gif +0 -0
  56. data/generators/beast/templates/public/images/clearbits/alert.gif +0 -0
  57. data/generators/beast/templates/public/images/clearbits/apple.gif +0 -0
  58. data/generators/beast/templates/public/images/clearbits/arrow1_e.gif +0 -0
  59. data/generators/beast/templates/public/images/clearbits/arrow1_n.gif +0 -0
  60. data/generators/beast/templates/public/images/clearbits/arrow1_ne.gif +0 -0
  61. data/generators/beast/templates/public/images/clearbits/arrow1_nw.gif +0 -0
  62. data/generators/beast/templates/public/images/clearbits/arrow1_s.gif +0 -0
  63. data/generators/beast/templates/public/images/clearbits/arrow1_se.gif +0 -0
  64. data/generators/beast/templates/public/images/clearbits/arrow1_sw.gif +0 -0
  65. data/generators/beast/templates/public/images/clearbits/arrow1_w.gif +0 -0
  66. data/generators/beast/templates/public/images/clearbits/arrow2_e.gif +0 -0
  67. data/generators/beast/templates/public/images/clearbits/arrow2_n.gif +0 -0
  68. data/generators/beast/templates/public/images/clearbits/arrow2_ne.gif +0 -0
  69. data/generators/beast/templates/public/images/clearbits/arrow2_nw.gif +0 -0
  70. data/generators/beast/templates/public/images/clearbits/arrow2_s.gif +0 -0
  71. data/generators/beast/templates/public/images/clearbits/arrow2_se.gif +0 -0
  72. data/generators/beast/templates/public/images/clearbits/arrow2_sw.gif +0 -0
  73. data/generators/beast/templates/public/images/clearbits/arrow2_w.gif +0 -0
  74. data/generators/beast/templates/public/images/clearbits/arrow3_e.gif +0 -0
  75. data/generators/beast/templates/public/images/clearbits/arrow3_n.gif +0 -0
  76. data/generators/beast/templates/public/images/clearbits/arrow3_ne.gif +0 -0
  77. data/generators/beast/templates/public/images/clearbits/arrow3_nw.gif +0 -0
  78. data/generators/beast/templates/public/images/clearbits/arrow3_s.gif +0 -0
  79. data/generators/beast/templates/public/images/clearbits/arrow3_se.gif +0 -0
  80. data/generators/beast/templates/public/images/clearbits/arrow3_sw.gif +0 -0
  81. data/generators/beast/templates/public/images/clearbits/arrow3_w.gif +0 -0
  82. data/generators/beast/templates/public/images/clearbits/ascii.gif +0 -0
  83. data/generators/beast/templates/public/images/clearbits/back.gif +0 -0
  84. data/generators/beast/templates/public/images/clearbits/bg_blank.gif +0 -0
  85. data/generators/beast/templates/public/images/clearbits/bg_circle.gif +0 -0
  86. data/generators/beast/templates/public/images/clearbits/bg_rounded.gif +0 -0
  87. data/generators/beast/templates/public/images/clearbits/bg_rounded_ne.gif +0 -0
  88. data/generators/beast/templates/public/images/clearbits/bg_rounded_nw.gif +0 -0
  89. data/generators/beast/templates/public/images/clearbits/bg_rounded_se.gif +0 -0
  90. data/generators/beast/templates/public/images/clearbits/bg_rounded_sw.gif +0 -0
  91. data/generators/beast/templates/public/images/clearbits/bigsmile.gif +0 -0
  92. data/generators/beast/templates/public/images/clearbits/binary.gif +0 -0
  93. data/generators/beast/templates/public/images/clearbits/blah.gif +0 -0
  94. data/generators/beast/templates/public/images/clearbits/bstop.gif +0 -0
  95. data/generators/beast/templates/public/images/clearbits/buy.gif +0 -0
  96. data/generators/beast/templates/public/images/clearbits/calday.gif +0 -0
  97. data/generators/beast/templates/public/images/clearbits/calendar.gif +0 -0
  98. data/generators/beast/templates/public/images/clearbits/camera.gif +0 -0
  99. data/generators/beast/templates/public/images/clearbits/cart.gif +0 -0
  100. data/generators/beast/templates/public/images/clearbits/cd.gif +0 -0
  101. data/generators/beast/templates/public/images/clearbits/cellphone.gif +0 -0
  102. data/generators/beast/templates/public/images/clearbits/chat.gif +0 -0
  103. data/generators/beast/templates/public/images/clearbits/check.gif +0 -0
  104. data/generators/beast/templates/public/images/clearbits/close.gif +0 -0
  105. data/generators/beast/templates/public/images/clearbits/comment.gif +0 -0
  106. data/generators/beast/templates/public/images/clearbits/cube.gif +0 -0
  107. data/generators/beast/templates/public/images/clearbits/day.gif +0 -0
  108. data/generators/beast/templates/public/images/clearbits/denied.gif +0 -0
  109. data/generators/beast/templates/public/images/clearbits/document.gif +0 -0
  110. data/generators/beast/templates/public/images/clearbits/download.gif +0 -0
  111. data/generators/beast/templates/public/images/clearbits/edit.gif +0 -0
  112. data/generators/beast/templates/public/images/clearbits/eject.gif +0 -0
  113. data/generators/beast/templates/public/images/clearbits/equalizer.gif +0 -0
  114. data/generators/beast/templates/public/images/clearbits/first.gif +0 -0
  115. data/generators/beast/templates/public/images/clearbits/flag.gif +0 -0
  116. data/generators/beast/templates/public/images/clearbits/flash.gif +0 -0
  117. data/generators/beast/templates/public/images/clearbits/folder.gif +0 -0
  118. data/generators/beast/templates/public/images/clearbits/forward.gif +0 -0
  119. data/generators/beast/templates/public/images/clearbits/frown.gif +0 -0
  120. data/generators/beast/templates/public/images/clearbits/ftp.gif +0 -0
  121. data/generators/beast/templates/public/images/clearbits/graph.gif +0 -0
  122. data/generators/beast/templates/public/images/clearbits/heart.gif +0 -0
  123. data/generators/beast/templates/public/images/clearbits/home.gif +0 -0
  124. data/generators/beast/templates/public/images/clearbits/html.gif +0 -0
  125. data/generators/beast/templates/public/images/clearbits/ipod.gif +0 -0
  126. data/generators/beast/templates/public/images/clearbits/last.gif +0 -0
  127. data/generators/beast/templates/public/images/clearbits/lock.gif +0 -0
  128. data/generators/beast/templates/public/images/clearbits/loop.gif +0 -0
  129. data/generators/beast/templates/public/images/clearbits/mail.gif +0 -0
  130. data/generators/beast/templates/public/images/clearbits/man.gif +0 -0
  131. data/generators/beast/templates/public/images/clearbits/manman.gif +0 -0
  132. data/generators/beast/templates/public/images/clearbits/music.gif +0 -0
  133. data/generators/beast/templates/public/images/clearbits/mute.gif +0 -0
  134. data/generators/beast/templates/public/images/clearbits/mute_centered.gif +0 -0
  135. data/generators/beast/templates/public/images/clearbits/newwindow.gif +0 -0
  136. data/generators/beast/templates/public/images/clearbits/next.gif +0 -0
  137. data/generators/beast/templates/public/images/clearbits/night.gif +0 -0
  138. data/generators/beast/templates/public/images/clearbits/open.gif +0 -0
  139. data/generators/beast/templates/public/images/clearbits/pause.gif +0 -0
  140. data/generators/beast/templates/public/images/clearbits/phone.gif +0 -0
  141. data/generators/beast/templates/public/images/clearbits/play.gif +0 -0
  142. data/generators/beast/templates/public/images/clearbits/previous.gif +0 -0
  143. data/generators/beast/templates/public/images/clearbits/quicktime.gif +0 -0
  144. data/generators/beast/templates/public/images/clearbits/redo.gif +0 -0
  145. data/generators/beast/templates/public/images/clearbits/reload.gif +0 -0
  146. data/generators/beast/templates/public/images/clearbits/sad.gif +0 -0
  147. data/generators/beast/templates/public/images/clearbits/save.gif +0 -0
  148. data/generators/beast/templates/public/images/clearbits/scream.gif +0 -0
  149. data/generators/beast/templates/public/images/clearbits/search.gif +0 -0
  150. data/generators/beast/templates/public/images/clearbits/seconds.gif +0 -0
  151. data/generators/beast/templates/public/images/clearbits/smile.gif +0 -0
  152. data/generators/beast/templates/public/images/clearbits/smirk.gif +0 -0
  153. data/generators/beast/templates/public/images/clearbits/star.gif +0 -0
  154. data/generators/beast/templates/public/images/clearbits/stop.gif +0 -0
  155. data/generators/beast/templates/public/images/clearbits/subtract.gif +0 -0
  156. data/generators/beast/templates/public/images/clearbits/switch.gif +0 -0
  157. data/generators/beast/templates/public/images/clearbits/target.gif +0 -0
  158. data/generators/beast/templates/public/images/clearbits/tcp.gif +0 -0
  159. data/generators/beast/templates/public/images/clearbits/time.gif +0 -0
  160. data/generators/beast/templates/public/images/clearbits/toggle.gif +0 -0
  161. data/generators/beast/templates/public/images/clearbits/tongue.gif +0 -0
  162. data/generators/beast/templates/public/images/clearbits/tools.gif +0 -0
  163. data/generators/beast/templates/public/images/clearbits/trackback.gif +0 -0
  164. data/generators/beast/templates/public/images/clearbits/trash.gif +0 -0
  165. data/generators/beast/templates/public/images/clearbits/tv.gif +0 -0
  166. data/generators/beast/templates/public/images/clearbits/type.gif +0 -0
  167. data/generators/beast/templates/public/images/clearbits/undo.gif +0 -0
  168. data/generators/beast/templates/public/images/clearbits/unlock.gif +0 -0
  169. data/generators/beast/templates/public/images/clearbits/upload.gif +0 -0
  170. data/generators/beast/templates/public/images/clearbits/user.gif +0 -0
  171. data/generators/beast/templates/public/images/clearbits/video.gif +0 -0
  172. data/generators/beast/templates/public/images/clearbits/volume_high.gif +0 -0
  173. data/generators/beast/templates/public/images/clearbits/volume_low.gif +0 -0
  174. data/generators/beast/templates/public/images/clearbits/wifi.gif +0 -0
  175. data/generators/beast/templates/public/images/clearbits/window.gif +0 -0
  176. data/generators/beast/templates/public/images/clearbits/woman.gif +0 -0
  177. data/generators/beast/templates/public/images/clearbits/womanman.gif +0 -0
  178. data/generators/beast/templates/public/images/clearbits/work.gif +0 -0
  179. data/generators/beast/templates/public/images/clearbits/zoomin.gif +0 -0
  180. data/generators/beast/templates/public/images/clearbits/zoomout.gif +0 -0
  181. data/generators/beast/templates/public/images/feed-icon.png +0 -0
  182. data/generators/beast/templates/public/images/rails.png +0 -0
  183. data/generators/beast/templates/public/images/reply_background.png +0 -0
  184. data/generators/beast/templates/public/images/small_circle.gif +0 -0
  185. data/generators/beast/templates/public/images/spinner.gif +0 -0
  186. data/generators/beast/templates/public/images/spinner_black.gif +0 -0
  187. data/generators/beast/templates/public/images/spinner_bounce.gif +0 -0
  188. data/generators/beast/templates/public/javascripts/beast.js +80 -0
  189. data/generators/beast/templates/public/stylesheets/display.css +941 -0
  190. data/lang/en.yml +206 -0
  191. data/lib/beast.rb +79 -0
  192. data/lib/savage_beast/application_helper.rb +91 -0
  193. data/lib/savage_beast/authentication_system.rb +47 -0
  194. data/lib/savage_beast/user_init.rb +79 -0
  195. data/lib/tasks/capistrano.rake +90 -0
  196. data/lib/tasks/deploy_edge.rake +44 -0
  197. data/lib/tasks/savage_beast.rake +133 -0
  198. data/po/beast.pot +712 -0
  199. data/po/nl/beast.po +700 -0
  200. data/tested_plugins/acts_as_list/README +23 -0
  201. data/tested_plugins/acts_as_list/init.rb +3 -0
  202. data/tested_plugins/acts_as_list/lib/active_record/acts/list.rb +256 -0
  203. data/tested_plugins/acts_as_list/test/list_test.rb +332 -0
  204. data/tested_plugins/gibberish/LICENSE +18 -0
  205. data/tested_plugins/gibberish/README +118 -0
  206. data/tested_plugins/gibberish/Rakefile +14 -0
  207. data/tested_plugins/gibberish/init.rb +3 -0
  208. data/tested_plugins/gibberish/lang/es.yml +3 -0
  209. data/tested_plugins/gibberish/lang/fr.yml +3 -0
  210. data/tested_plugins/gibberish/lib/gibberish.rb +8 -0
  211. data/tested_plugins/gibberish/lib/gibberish/localize.rb +88 -0
  212. data/tested_plugins/gibberish/lib/gibberish/string_ext.rb +17 -0
  213. data/tested_plugins/gibberish/test/gibberish_test.rb +203 -0
  214. data/tested_plugins/gibberish/test/lang/es.yml +1 -0
  215. data/tested_plugins/gibberish/test/lang/fr.yml +1 -0
  216. data/tested_plugins/mislav-will_paginate/CHANGELOG.rdoc +110 -0
  217. data/tested_plugins/mislav-will_paginate/LICENSE +18 -0
  218. data/tested_plugins/mislav-will_paginate/README.rdoc +107 -0
  219. data/tested_plugins/mislav-will_paginate/Rakefile +53 -0
  220. data/tested_plugins/mislav-will_paginate/examples/apple-circle.gif +0 -0
  221. data/tested_plugins/mislav-will_paginate/examples/index.haml +69 -0
  222. data/tested_plugins/mislav-will_paginate/examples/index.html +92 -0
  223. data/tested_plugins/mislav-will_paginate/examples/pagination.css +90 -0
  224. data/tested_plugins/mislav-will_paginate/examples/pagination.sass +91 -0
  225. data/tested_plugins/mislav-will_paginate/init.rb +1 -0
  226. data/tested_plugins/mislav-will_paginate/lib/will_paginate.rb +78 -0
  227. data/tested_plugins/mislav-will_paginate/lib/will_paginate/array.rb +16 -0
  228. data/tested_plugins/mislav-will_paginate/lib/will_paginate/collection.rb +146 -0
  229. data/tested_plugins/mislav-will_paginate/lib/will_paginate/core_ext.rb +32 -0
  230. data/tested_plugins/mislav-will_paginate/lib/will_paginate/finder.rb +264 -0
  231. data/tested_plugins/mislav-will_paginate/lib/will_paginate/named_scope.rb +170 -0
  232. data/tested_plugins/mislav-will_paginate/lib/will_paginate/named_scope_patch.rb +37 -0
  233. data/tested_plugins/mislav-will_paginate/lib/will_paginate/version.rb +9 -0
  234. data/tested_plugins/mislav-will_paginate/lib/will_paginate/view_helpers.rb +402 -0
  235. data/tested_plugins/mislav-will_paginate/test/boot.rb +21 -0
  236. data/tested_plugins/mislav-will_paginate/test/collection_test.rb +143 -0
  237. data/tested_plugins/mislav-will_paginate/test/console +8 -0
  238. data/tested_plugins/mislav-will_paginate/test/database.yml +22 -0
  239. data/tested_plugins/mislav-will_paginate/test/finder_test.rb +476 -0
  240. data/tested_plugins/mislav-will_paginate/test/fixtures/admin.rb +3 -0
  241. data/tested_plugins/mislav-will_paginate/test/fixtures/developer.rb +14 -0
  242. data/tested_plugins/mislav-will_paginate/test/fixtures/developers_projects.yml +13 -0
  243. data/tested_plugins/mislav-will_paginate/test/fixtures/project.rb +15 -0
  244. data/tested_plugins/mislav-will_paginate/test/fixtures/projects.yml +6 -0
  245. data/tested_plugins/mislav-will_paginate/test/fixtures/replies.yml +29 -0
  246. data/tested_plugins/mislav-will_paginate/test/fixtures/reply.rb +7 -0
  247. data/tested_plugins/mislav-will_paginate/test/fixtures/schema.rb +38 -0
  248. data/tested_plugins/mislav-will_paginate/test/fixtures/topic.rb +10 -0
  249. data/tested_plugins/mislav-will_paginate/test/fixtures/topics.yml +30 -0
  250. data/tested_plugins/mislav-will_paginate/test/fixtures/user.rb +2 -0
  251. data/tested_plugins/mislav-will_paginate/test/fixtures/users.yml +35 -0
  252. data/tested_plugins/mislav-will_paginate/test/helper.rb +40 -0
  253. data/tested_plugins/mislav-will_paginate/test/lib/activerecord_test_case.rb +43 -0
  254. data/tested_plugins/mislav-will_paginate/test/lib/activerecord_test_connector.rb +75 -0
  255. data/tested_plugins/mislav-will_paginate/test/lib/load_fixtures.rb +11 -0
  256. data/tested_plugins/mislav-will_paginate/test/lib/view_test_process.rb +178 -0
  257. data/tested_plugins/mislav-will_paginate/test/tasks.rake +59 -0
  258. data/tested_plugins/mislav-will_paginate/test/view_test.rb +365 -0
  259. data/tested_plugins/white_list/README +29 -0
  260. data/tested_plugins/white_list/Rakefile +22 -0
  261. data/tested_plugins/white_list/init.rb +2 -0
  262. data/tested_plugins/white_list/lib/white_list_helper.rb +97 -0
  263. data/tested_plugins/white_list/test/white_list_test.rb +132 -0
  264. data/tested_plugins/white_list_formatted_content/init.rb +27 -0
  265. metadata +322 -0
@@ -0,0 +1,15 @@
1
+ module ForumsHelper
2
+
3
+ # used to know if a topic has changed since we read it last
4
+ def recent_topic_activity(topic)
5
+ return false if not logged_in?
6
+ return topic.replied_at > ((session[:topics] && session[:topics][topic.id]) || 3.days.ago) # was: last_active. TODO: Could implement something to look at the user
7
+ end
8
+
9
+ # used to know if a forum has changed since we read it last
10
+ def recent_forum_activity(forum)
11
+ return false unless logged_in? && forum.recent_topic
12
+ return forum.recent_topic.replied_at > ((session[:forums] && session[:forums][forum.id]) || 3.days.ago) # was: last_active. TODO: Could implement something to look at the user
13
+ end
14
+
15
+ end
@@ -0,0 +1,2 @@
1
+ module ModeratorsHelper
2
+ end
@@ -0,0 +1,2 @@
1
+ module MonitorshipsHelper
2
+ end
@@ -0,0 +1,3 @@
1
+ module PostsHelper
2
+ include CountHelper
3
+ end
@@ -0,0 +1,3 @@
1
+ module TopicsHelper
2
+ include CountHelper
3
+ end
@@ -0,0 +1,26 @@
1
+ class Forum < ActiveRecord::Base
2
+ acts_as_list
3
+
4
+ validates_presence_of :name
5
+
6
+ has_many :moderatorships, :dependent => :delete_all
7
+ has_many :moderators, :through => :moderatorships, :source => :user
8
+
9
+ has_many :topics, :order => 'sticky desc, replied_at desc', :dependent => :delete_all
10
+ has_one :recent_topic, :class_name => 'Topic', :order => 'sticky desc, replied_at desc'
11
+
12
+ # this is used to see if a forum is "fresh"... we can't use topics because it puts
13
+ # stickies first even if they are not the most recently modified
14
+ has_many :recent_topics, :class_name => 'Topic', :order => 'replied_at DESC'
15
+ has_one :recent_topic, :class_name => 'Topic', :order => 'replied_at DESC'
16
+
17
+ has_many :posts, :order => "#{Post.table_name}.created_at DESC", :dependent => :delete_all
18
+ has_one :recent_post, :order => "#{Post.table_name}.created_at DESC", :class_name => 'Post'
19
+
20
+ format_attribute :description
21
+
22
+ # retrieves forums ordered by position
23
+ def self.find_ordered(options = {})
24
+ find :all, options.update(:order => 'position')
25
+ end
26
+ end
@@ -0,0 +1,6 @@
1
+ class Moderatorship < ActiveRecord::Base
2
+ belongs_to :forum
3
+ belongs_to :user
4
+ before_create { |r| count(:id, :conditions => ['forum_id = ? and user_id = ?', r.forum_id, r.user_id]).zero? }
5
+
6
+ end
@@ -0,0 +1,5 @@
1
+ class Monitorship < ActiveRecord::Base
2
+ belongs_to :user
3
+ belongs_to :topic
4
+
5
+ end
@@ -0,0 +1,9 @@
1
+ class MonitorshipsSweeper < ActionController::Caching::Sweeper
2
+ observe Monitorship
3
+
4
+ def after_save(monitorship)
5
+ FileUtils.rm_rf File.join(RAILS_ROOT, 'public', 'users', monitorship.user_id.to_s)
6
+ end
7
+
8
+ alias_method :after_destroy, :after_save
9
+ end
@@ -0,0 +1,33 @@
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
14
+ attr_accessible :body
15
+
16
+ def editable_by?(user)
17
+ user && (user.id == user_id || user.admin? || user.moderator_of?(forum_id))
18
+ end
19
+
20
+ def to_xml(options = {})
21
+ options[:except] ||= []
22
+ options[:except] << :topic_title << :forum_name
23
+ super
24
+ end
25
+
26
+ protected
27
+ # using count isn't ideal but it gives us correct caches each time
28
+ def update_cached_fields
29
+ Forum.update_all ['posts_count = ?', Post.count(:id, :conditions => {:forum_id => forum_id})], ['id = ?', forum_id]
30
+ User.update_posts_count(user_id)
31
+ topic.update_cached_post_fields(self)
32
+ end
33
+ end
@@ -0,0 +1,12 @@
1
+ class PostsSweeper < ActionController::Caching::Sweeper
2
+ observe Post
3
+
4
+ def after_save(post)
5
+ FileUtils.rm_rf File.join(RAILS_ROOT, 'public', 'forums', post.forum_id.to_s, 'posts.rss')
6
+ FileUtils.rm_rf File.join(RAILS_ROOT, 'public', 'forums', post.forum_id.to_s, 'topics', "#{post.topic_id}.rss")
7
+ FileUtils.rm_rf File.join(RAILS_ROOT, 'public', 'users')
8
+ FileUtils.rm_rf File.join(RAILS_ROOT, 'public', 'posts.rss')
9
+ end
10
+
11
+ alias_method :after_destroy, :after_save
12
+ end
@@ -0,0 +1,94 @@
1
+ class Topic < ActiveRecord::Base
2
+ validates_presence_of :forum, :user, :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
+ has_many :monitorships
13
+ has_many :monitors, :through => :monitorships, :conditions => ["#{Monitorship.table_name}.active = ?", true], :source => :user
14
+
15
+ has_many :posts, :order => "#{Post.table_name}.created_at", :dependent => :delete_all
16
+ has_one :recent_post, :order => "#{Post.table_name}.created_at DESC", :class_name => 'Post'
17
+
18
+ has_many :voices, :through => :posts, :source => :user, :uniq => true
19
+ belongs_to :replied_by_user, :foreign_key => "replied_by", :class_name => "User"
20
+
21
+ attr_accessible :title
22
+ # to help with the create form
23
+ attr_accessor :body
24
+
25
+ def hit!
26
+ self.class.increment_counter :hits, id
27
+ end
28
+
29
+ def sticky?() sticky == 1 end
30
+
31
+ def views() hits end
32
+
33
+ def paged?() posts_count > Post.per_page end
34
+
35
+ def last_page
36
+ [(posts_count.to_f / Post.per_page).ceil.to_i, 1].max
37
+ end
38
+
39
+ def editable_by?(user)
40
+ user && (user.id == user_id || user.admin? || user.moderator_of?(forum_id))
41
+ end
42
+
43
+ def update_cached_post_fields(post)
44
+ # these fields are not accessible to mass assignment
45
+ remaining_post = post.frozen? ? recent_post : post
46
+ if remaining_post
47
+ self.class.update_all(['replied_at = ?, replied_by = ?, last_post_id = ?, posts_count = ?',
48
+ remaining_post.created_at, remaining_post.user_id, remaining_post.id, posts.count], ['id = ?', id])
49
+ else
50
+ self.destroy
51
+ end
52
+ end
53
+
54
+ protected
55
+ def set_default_replied_at_and_sticky
56
+ self.replied_at = Time.now.utc
57
+ self.sticky ||= 0
58
+ end
59
+
60
+ def set_post_forum_id
61
+ Post.update_all ['forum_id = ?', forum_id], ['topic_id = ?', id]
62
+ end
63
+
64
+ def check_for_changing_forums
65
+ old = Topic.find(id)
66
+ @old_forum_id = old.forum_id if old.forum_id != forum_id
67
+ true
68
+ end
69
+
70
+ # using count isn't ideal but it gives us correct caches each time
71
+ def update_forum_counter_cache
72
+ forum_conditions = ['topics_count = ?', Topic.count(:id, :conditions => {:forum_id => forum_id})]
73
+ # if the topic moved forums
74
+ if !frozen? && @old_forum_id && @old_forum_id != forum_id
75
+ set_post_forum_id
76
+ Forum.update_all ['topics_count = ?, posts_count = ?',
77
+ Topic.count(:id, :conditions => {:forum_id => @old_forum_id}),
78
+ Post.count(:id, :conditions => {:forum_id => @old_forum_id})], ['id = ?', @old_forum_id]
79
+ end
80
+ # if the topic moved forums or was deleted
81
+ if frozen? || (@old_forum_id && @old_forum_id != forum_id)
82
+ forum_conditions.first << ", posts_count = ?"
83
+ forum_conditions << Post.count(:id, :conditions => {:forum_id => forum_id})
84
+ end
85
+ # User doesn't have update_posts_count method in SB2, as reported by Ryan
86
+ #@voices.each &:update_posts_count if @voices
87
+ Forum.update_all forum_conditions, ['id = ?', forum_id]
88
+ @old_forum_id = @voices = nil
89
+ end
90
+
91
+ def update_post_user_counts
92
+ @voices = voices.to_a
93
+ end
94
+ 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
+ <%= form.label :name %><br />
9
+ <%= form.text_field :name, :class => "primary" %>
10
+ </td>
11
+ <td style="text-align:right">
12
+ <%=form.label :position %><br />
13
+ <%= form.text_field :position, :size => 5 %>
14
+
15
+ </td>
16
+ </table>
17
+
18
+ </p>
19
+ <p id="forum_descripion">
20
+ <%= form.label(:description) %><br />
21
+ <%= form.text_area :description, :rows => 7 %></p>
@@ -0,0 +1,12 @@
1
+ <div class="crumbs">
2
+ <%= link_to 'Forums'[:forums_title], forums_path %> <span class="arrow">&rarr;</span>
3
+ </div>
4
+
5
+ <h1><%= 'Edit Forum'[:edit_forum] %></h1>
6
+
7
+ <% form_for :forum,
8
+ :url => forum_path(@forum),
9
+ :html => { :method => :put } do |f| -%>
10
+ <%= render :partial => "form", :object => f %>
11
+ <%= submit_tag 'Save Forum'[:save_forum] -%> or <%= link_to('Cancel'[:cancel], forums_path) %>
12
+ <% end -%>
@@ -0,0 +1,77 @@
1
+ <% content_for :right do %>
2
+
3
+ <% if admin? %>
4
+ <h6><%=t(:admin_title) %></h6>
5
+ <p><%= link_to t(:create_new_forum), new_forum_path, :class => "utility" %></p>
6
+ <% end %>
7
+
8
+ <% end %>
9
+
10
+ <h1 style="margin-top:0;"><%= t(:forums_title) %></h1>
11
+ <p class="subtitle">
12
+ <%= feed_icon_tag t(:recent_posts), all_posts_path(:format => 'rss') %>
13
+ <%= t(:topics_count, :count => Topic.count, :n => number_with_delimiter(Topic.count)) %>,
14
+ <%= t(:posts_count, :count => Post.count, :n => number_with_delimiter(Post.count)) %>,
15
+ <% users_count = User.count(:conditions => "posts_count > 0") %>
16
+ <%= t(:voices_count, :count => users_count, :n => number_with_delimiter(users_count)) %>
17
+
18
+ </p>
19
+
20
+ <table border="0" cellspacing="0" cellpadding="0" class="wide forums">
21
+ <tr>
22
+ <th class="la" width="70%" colspan="3"><%= t(:forum_title) %></th>
23
+ <!--
24
+ <th width="5%">Topics</th>
25
+ <th width="5%">Posts</th>
26
+ -->
27
+ <th class="la" width="30%" colspan="1"><%= t(:last_post) %></th>
28
+ </tr>
29
+ <% for forum in @forums do %>
30
+ <tr>
31
+ <td class="vat c1">
32
+
33
+ <% if recent_forum_activity(forum) %>
34
+ <%= image_tag "savage_beast/clearbits/comment.gif", :class => "icon green", :title => 'Recent activity'[:recent_activity] %>
35
+ <% else %>
36
+ <%= image_tag "savage_beast/clearbits/comment.gif", :class => "icon grey", :title => 'No recent activity'[:no_recent_activity] %>
37
+ <% end %>
38
+ </td>
39
+ <td class="c2 vat">
40
+ <%= link_to h(forum.name), forum_path(forum), :class => "title" %>
41
+ <div class="posts">
42
+ <%= t(:topics_count, :count => forum.topics.size, :n => number_with_delimiter(forum.topics.size)) %>,
43
+ <%= t(:posts_count, :count => forum.posts.size, :n => number_with_delimiter(forum.posts.size)) %>
44
+ </div>
45
+ <p class="desc"><%= forum.description_html %>
46
+ </p>
47
+ </td>
48
+ <td class="c3">
49
+ <%= link_to t(:edit_title), edit_forum_path(forum), :class => "tiny", :rel => "directory", :style => "float:right" if admin? %>
50
+ </td>
51
+
52
+ <td class="inv lp">
53
+ <% if forum.recent_post %>
54
+ <%= time_ago_in_words(forum.recent_post.created_at) %><br />
55
+ <%= t(:by_user, :user => "<strong>#{h(forum.recent_post.user.display_name)}</strong>") %>
56
+ <span>(<%= link_to t(:view), forum_topic_path(:forum_id => forum, :id => forum.recent_post.topic_id, :page => forum.recent_post.topic.last_page, :anchor => forum.recent_post.dom_id) %>)</span>
57
+ <% end %>
58
+ </td>
59
+ </tr>
60
+ <% end %>
61
+ </table>
62
+
63
+ <p>
64
+ <%= link_to t(:recent_posts), all_posts_path %>
65
+ </p>
66
+
67
+ <% online_users = User.currently_online -%>
68
+ <% unless !online_users || online_users.empty? %>
69
+ <div class="stats">
70
+ <div class="users">
71
+ <% unless !online_users || online_users.empty? %>
72
+ <%= t(:users_online) %> <%= online_users.map { |u| link_to "<strong>#{h u.display_name}</strong>", user_path(u) } * ", " %><br />
73
+ <% end %>
74
+ </div>
75
+ </div>
76
+ <% end %>
77
+
@@ -0,0 +1,10 @@
1
+ <div class="crumbs">
2
+ <%= link_to "Forums"[:forums_title], forums_path %> <span class="arrow">&rarr;</span>
3
+ </div>
4
+
5
+ <h1><%= t(:new_forum) %></h1>
6
+
7
+ <% form_for :forum, :url => forums_path do |f| -%>
8
+ <%= render :partial => "form", :object => f %>
9
+ <%= submit_tag t(:create) -%> <%= t(:or) %> <%= link_to(t(:cancel), forums_path) -%>
10
+ <% end -%>
@@ -0,0 +1,94 @@
1
+ <% content_for :right do %>
2
+
3
+ <% unless @forum.description.blank? %>
4
+ <%= @forum.description_html %>
5
+ <hr />
6
+ <% end %>
7
+
8
+ <h5 style="margin-bottom:1.0em;"><%= t(:moderators_title) %></h5>
9
+
10
+ <% unless @forum.moderators.empty? -%>
11
+ <ul class="flat" style="margin-top:1em;">
12
+ <% @forum.moderators.each do |user| -%>
13
+ <li><%= link_to user.display_name, user_path(user) %></li>
14
+ <% end -%>
15
+ </ul>
16
+ <% else -%>
17
+ <p><%= t(:forum_is_unmoderated) %></p>
18
+ <p><%= t(:please_be_courteous) %></p>
19
+ <% end -%>
20
+
21
+ <% end %>
22
+
23
+ <% @page_title = @forum.name %>
24
+
25
+ <div class="crumbs">
26
+ <%= link_to t(:forums_title), forums_path %> <span class="arrow">&rarr;</span>
27
+ </div>
28
+ <h1 style="margin-top:0.5em">
29
+ <%= h @forum.name %>
30
+ </h1>
31
+
32
+ <p class="subtitle">
33
+ <%= feed_icon_tag @forum.name, forum_posts_path(@forum, :format => :rss) %>
34
+ <%= t(:topics_count, :count => @forum.topics.size, :n => number_with_delimiter(@forum.topics.size)) %>,
35
+ <%= t(:posts_count, :count => @forum.posts.size, :n => number_with_delimiter(@forum.posts.size)) %>
36
+ </p>
37
+
38
+ <% if @topics.total_pages > 1 -%>
39
+ <% if logged_in? %>
40
+ <p style="float:right; margin-top:0;"><%= link_to t(:new_topic), new_forum_topic_path(@forum), :class => "utility" %></p>
41
+ <% end %>
42
+ <%= will_paginate @topics %>
43
+ <% end -%>
44
+
45
+ <table border="0" cellspacing="0" cellpadding="0" class="wide topics">
46
+ <tr>
47
+ <th class="la" colspan="2"><%= t(:topic_title) %></th>
48
+ <th width="1%"><%= t(:posts_title) %></th>
49
+ <th width="1%"><%= t(:views_title) %></th>
50
+ <th class="la"><%= t(:last_post) %></th>
51
+ </tr>
52
+ <% for topic in @topics %>
53
+ <tr class="hentry">
54
+ <td style="padding:5px; width:16px;" class="c1">
55
+ <%
56
+ icon = "comment"
57
+ color = ""
58
+ if topic.locked?
59
+ icon = "lock"
60
+ post = ", this topic is locked."[:comma_locked_topic]
61
+ color = "darkgrey"
62
+ end
63
+ %>
64
+ <% if recent_topic_activity(topic) %>
65
+ <%= image_tag "savage_beast/clearbits/#{icon}.gif", :class => "icon green", :title => "Recent activity"[]+"#{post}" %>
66
+ <% else %>
67
+ <%= image_tag "savage_beast/clearbits/#{icon}.gif", :class => "icon grey #{color}", :title => "No recent activity"[]+"#{post}" %>
68
+ <% end %>
69
+ </td>
70
+ <td class="c2">
71
+ <%= "Sticky"[:sticky_title]+": <strong>" if topic.sticky? %>
72
+ <%= topic_title_link (topic), :class => "entry-title", :rel => "bookmark" %>
73
+ <%#= link_to h(topic.title), topic_path(@forum, topic), :class => "entry-title", :rel => "bookmark" %>
74
+ <%= "</strong>" if topic.sticky? %>
75
+ <% if topic.paged? -%>
76
+ <small><%= link_to 'last'[], forum_topic_path(:forum_id => @forum, :id => topic, :page => topic.last_page) %></small>
77
+ <% end -%>
78
+ </td>
79
+ <td class="ca inv stat"><%= topic.posts.size %></td>
80
+ <td class="ca inv stat"><%= number_with_delimiter(topic.views) %></td>
81
+ <td class="lp">
82
+ <abbr class="updated" title="<%= topic.replied_at.xmlschema %>"><%= time_ago_in_words(topic.replied_at) %></abbr>
83
+ <%= 'by {user}'[:by_user, "<span class=\"author\"><strong class=\"fn\">#{h(topic.replied_by_user.display_name)}</strong></span>"] %>
84
+ <span><%= link_to 'view'[], forum_topic_path(:forum_id => @forum, :id => topic, :page => topic.last_page, :anchor => "posts-#{topic.last_post_id}") %></span>
85
+ </td>
86
+ </tr>
87
+ <% end %>
88
+ </table>
89
+
90
+ <%= will_paginate @topics %>
91
+
92
+ <% if logged_in? %>
93
+ <p><%= link_to t(:new_topic), new_forum_topic_path(@forum), :class => "utility" %></p>
94
+ <% end%>