formol 0.0.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (226) hide show
  1. data/MIT-LICENSE +20 -0
  2. data/README.md +147 -0
  3. data/Rakefile +29 -0
  4. data/app/assets/images/formol/read.png +0 -0
  5. data/app/assets/images/formol/unread.png +0 -0
  6. data/app/assets/javascripts/formol/admin/categories.js.coffee +55 -0
  7. data/app/assets/javascripts/formol/admin/forums.js +2 -0
  8. data/app/assets/javascripts/formol/application.js +9 -0
  9. data/app/assets/javascripts/formol/categories.js +2 -0
  10. data/app/assets/javascripts/formol/forums.js +2 -0
  11. data/app/assets/javascripts/formol/poll_votes.js +2 -0
  12. data/app/assets/javascripts/formol/posts.js.coffee +9 -0
  13. data/app/assets/javascripts/formol/preferences.js +2 -0
  14. data/app/assets/javascripts/formol/subscriptions.js.coffee +13 -0
  15. data/app/assets/javascripts/formol/topics.js.coffee +54 -0
  16. data/app/assets/javascripts/lib/jquery.prevent_double_submit.js.coffee +11 -0
  17. data/app/assets/javascripts/markitup/jquery.markitup.js +593 -0
  18. data/app/assets/javascripts/markitup/sets/markdown/set.js +53 -0
  19. data/app/assets/stylesheets/form_struct.css.scss +39 -0
  20. data/app/assets/stylesheets/formol/admin/categories.css.scss +30 -0
  21. data/app/assets/stylesheets/formol/admin/forums.css +4 -0
  22. data/app/assets/stylesheets/formol/categories.css.scss +3 -0
  23. data/app/assets/stylesheets/formol/development.css +4 -0
  24. data/app/assets/stylesheets/formol/forums.css.scss +3 -0
  25. data/app/assets/stylesheets/formol/mixins/after_clear.css.scss +7 -0
  26. data/app/assets/stylesheets/formol/partials/breadcrumb.css.scss +9 -0
  27. data/app/assets/stylesheets/formol/partials/categories/list.css.scss +101 -0
  28. data/app/assets/stylesheets/formol/partials/formol_lists.css.scss +6 -0
  29. data/app/assets/stylesheets/formol/partials/forums/list.css.scss +97 -0
  30. data/app/assets/stylesheets/formol/partials/polls/poll.css.scss +9 -0
  31. data/app/assets/stylesheets/formol/partials/posts/post.css.scss +116 -0
  32. data/app/assets/stylesheets/formol/posts.css.scss +8 -0
  33. data/app/assets/stylesheets/formol/topics.css.scss +42 -0
  34. data/app/assets/stylesheets/markitup/sets/markdown/images/block_code.png +0 -0
  35. data/app/assets/stylesheets/markitup/sets/markdown/images/bold.png +0 -0
  36. data/app/assets/stylesheets/markitup/sets/markdown/images/code.png +0 -0
  37. data/app/assets/stylesheets/markitup/sets/markdown/images/h1.png +0 -0
  38. data/app/assets/stylesheets/markitup/sets/markdown/images/h2.png +0 -0
  39. data/app/assets/stylesheets/markitup/sets/markdown/images/h3.png +0 -0
  40. data/app/assets/stylesheets/markitup/sets/markdown/images/h4.png +0 -0
  41. data/app/assets/stylesheets/markitup/sets/markdown/images/h5.png +0 -0
  42. data/app/assets/stylesheets/markitup/sets/markdown/images/h6.png +0 -0
  43. data/app/assets/stylesheets/markitup/sets/markdown/images/italic.png +0 -0
  44. data/app/assets/stylesheets/markitup/sets/markdown/images/link.png +0 -0
  45. data/app/assets/stylesheets/markitup/sets/markdown/images/list-bullet.png +0 -0
  46. data/app/assets/stylesheets/markitup/sets/markdown/images/list-numeric.png +0 -0
  47. data/app/assets/stylesheets/markitup/sets/markdown/images/picture.png +0 -0
  48. data/app/assets/stylesheets/markitup/sets/markdown/images/preview.png +0 -0
  49. data/app/assets/stylesheets/markitup/sets/markdown/images/quotes.png +0 -0
  50. data/app/assets/stylesheets/markitup/sets/markdown/style.css +57 -0
  51. data/app/assets/stylesheets/markitup/skins/markitup/images/bg-container.png +0 -0
  52. data/app/assets/stylesheets/markitup/skins/markitup/images/bg-editor-bbcode.png +0 -0
  53. data/app/assets/stylesheets/markitup/skins/markitup/images/bg-editor-dotclear.png +0 -0
  54. data/app/assets/stylesheets/markitup/skins/markitup/images/bg-editor-html.png +0 -0
  55. data/app/assets/stylesheets/markitup/skins/markitup/images/bg-editor-json.png +0 -0
  56. data/app/assets/stylesheets/markitup/skins/markitup/images/bg-editor-markdown.png +0 -0
  57. data/app/assets/stylesheets/markitup/skins/markitup/images/bg-editor-textile.png +0 -0
  58. data/app/assets/stylesheets/markitup/skins/markitup/images/bg-editor-wiki.png +0 -0
  59. data/app/assets/stylesheets/markitup/skins/markitup/images/bg-editor-xml.png +0 -0
  60. data/app/assets/stylesheets/markitup/skins/markitup/images/bg-editor.png +0 -0
  61. data/app/assets/stylesheets/markitup/skins/markitup/images/handle.png +0 -0
  62. data/app/assets/stylesheets/markitup/skins/markitup/images/menu.png +0 -0
  63. data/app/assets/stylesheets/markitup/skins/markitup/images/submenu.png +0 -0
  64. data/app/assets/stylesheets/markitup/skins/markitup/style.css +147 -0
  65. data/app/assets/stylesheets/markitup/skins/simple/images/handle.png +0 -0
  66. data/app/assets/stylesheets/markitup/skins/simple/images/menu.png +0 -0
  67. data/app/assets/stylesheets/markitup/skins/simple/images/submenu.png +0 -0
  68. data/app/assets/stylesheets/markitup/skins/simple/style.css +118 -0
  69. data/app/assets/stylesheets/pygments/autumn.css +58 -0
  70. data/app/assets/stylesheets/pygments/borland.css +46 -0
  71. data/app/assets/stylesheets/pygments/bw.css +34 -0
  72. data/app/assets/stylesheets/pygments/colorful.css +61 -0
  73. data/app/assets/stylesheets/pygments/default.css +62 -0
  74. data/app/assets/stylesheets/pygments/emacs.css +61 -0
  75. data/app/assets/stylesheets/pygments/friendly.css +61 -0
  76. data/app/assets/stylesheets/pygments/fruity.css +70 -0
  77. data/app/assets/stylesheets/pygments/manni.css +61 -0
  78. data/app/assets/stylesheets/pygments/murphy.css +61 -0
  79. data/app/assets/stylesheets/pygments/native.css +70 -0
  80. data/app/assets/stylesheets/pygments/pastie.css +60 -0
  81. data/app/assets/stylesheets/pygments/perldoc.css +58 -0
  82. data/app/assets/stylesheets/pygments/tango.css +69 -0
  83. data/app/assets/stylesheets/pygments/trac.css +59 -0
  84. data/app/assets/stylesheets/pygments/vim.css +70 -0
  85. data/app/assets/stylesheets/pygments/vs.css +33 -0
  86. data/app/controllers/formol/admin/admin_controller.rb +11 -0
  87. data/app/controllers/formol/admin/categories_controller.rb +60 -0
  88. data/app/controllers/formol/admin/forums_controller.rb +56 -0
  89. data/app/controllers/formol/application_controller.rb +47 -0
  90. data/app/controllers/formol/categories_controller.rb +21 -0
  91. data/app/controllers/formol/forums_controller.rb +19 -0
  92. data/app/controllers/formol/poll_votes_controller.rb +23 -0
  93. data/app/controllers/formol/posts_controller.rb +71 -0
  94. data/app/controllers/formol/preferences_controller.rb +32 -0
  95. data/app/controllers/formol/subscriptions_controller.rb +29 -0
  96. data/app/controllers/formol/topics_controller.rb +91 -0
  97. data/app/helpers/formol/admin/categories_helper.rb +4 -0
  98. data/app/helpers/formol/admin/forums_helper.rb +4 -0
  99. data/app/helpers/formol/application_helper.rb +35 -0
  100. data/app/helpers/formol/categories_helper.rb +15 -0
  101. data/app/helpers/formol/forums_helper.rb +19 -0
  102. data/app/helpers/formol/poll_votes_helper.rb +4 -0
  103. data/app/helpers/formol/posts_helper.rb +27 -0
  104. data/app/helpers/formol/preferences_helper.rb +4 -0
  105. data/app/helpers/formol/subscriptions_helper.rb +4 -0
  106. data/app/helpers/formol/topics_helper.rb +27 -0
  107. data/app/mailers/formol/subscription_mailer.rb +13 -0
  108. data/app/models/formol/category.rb +42 -0
  109. data/app/models/formol/forum.rb +77 -0
  110. data/app/models/formol/poll/option.rb +20 -0
  111. data/app/models/formol/poll/vote.rb +32 -0
  112. data/app/models/formol/poll.rb +107 -0
  113. data/app/models/formol/post.rb +162 -0
  114. data/app/models/formol/post_observer.rb +9 -0
  115. data/app/models/formol/topic/subscription.rb +16 -0
  116. data/app/models/formol/topic/track.rb +57 -0
  117. data/app/models/formol/topic.rb +185 -0
  118. data/app/models/formol/tracking.rb +45 -0
  119. data/app/models/formol/user_preference.rb +18 -0
  120. data/app/views/formol/admin/categories/_category.html.erb +9 -0
  121. data/app/views/formol/admin/categories/_form.html.erb +8 -0
  122. data/app/views/formol/admin/categories/edit.html.erb +3 -0
  123. data/app/views/formol/admin/categories/index.html.erb +3 -0
  124. data/app/views/formol/admin/categories/new.html.erb +3 -0
  125. data/app/views/formol/admin/forums/_form.html.erb +9 -0
  126. data/app/views/formol/admin/forums/_forum.html.erb +12 -0
  127. data/app/views/formol/admin/forums/edit.html.erb +3 -0
  128. data/app/views/formol/admin/forums/new.html.erb +3 -0
  129. data/app/views/formol/categories/_category.html.erb +5 -0
  130. data/app/views/formol/categories/index.html.erb +5 -0
  131. data/app/views/formol/categories/show.html.erb +3 -0
  132. data/app/views/formol/forums/_forum.html.erb +13 -0
  133. data/app/views/formol/forums/_list.html.erb +16 -0
  134. data/app/views/formol/forums/show.html.erb +18 -0
  135. data/app/views/formol/poll/options/_form.html.erb +1 -0
  136. data/app/views/formol/poll_votes/_form.html.erb +8 -0
  137. data/app/views/formol/polls/_form.html.erb +14 -0
  138. data/app/views/formol/polls/_poll.html.erb +24 -0
  139. data/app/views/formol/posts/_form.html.erb +7 -0
  140. data/app/views/formol/posts/_last_post.html.erb +9 -0
  141. data/app/views/formol/posts/_list.html.erb +3 -0
  142. data/app/views/formol/posts/_post.html.erb +47 -0
  143. data/app/views/formol/posts/edit.html.erb +10 -0
  144. data/app/views/formol/posts/new.html.erb +14 -0
  145. data/app/views/formol/preferences/show.html.erb +11 -0
  146. data/app/views/formol/subscription_mailer/topic_reply.en.html.erb +8 -0
  147. data/app/views/formol/subscription_mailer/topic_reply.fr.html.erb +8 -0
  148. data/app/views/formol/topics/_form.html.erb +20 -0
  149. data/app/views/formol/topics/_list.html.erb +16 -0
  150. data/app/views/formol/topics/_topic.html.erb +13 -0
  151. data/app/views/formol/topics/edit.html.erb +5 -0
  152. data/app/views/formol/topics/new.html.erb +5 -0
  153. data/app/views/formol/topics/show.html.erb +25 -0
  154. data/app/views/layouts/formol/mail.html.erb +9 -0
  155. data/config/locales/en.yml +3 -0
  156. data/config/locales/formol/views/forums/en.yml +13 -0
  157. data/config/locales/formol/views/forums/fr.yml +13 -0
  158. data/config/locales/formol/views/poll_votes/en.yml +5 -0
  159. data/config/locales/formol/views/polls/en.yml.yml +5 -0
  160. data/config/locales/formol/views/posts/en.yml +23 -0
  161. data/config/locales/formol/views/posts/fr.yml +20 -0
  162. data/config/locales/formol/views/topics/en.yml +23 -0
  163. data/config/locales/formol/views/topics/fr.yml +20 -0
  164. data/config/routes.rb +31 -0
  165. data/db/migrate/20111221101158_create_formol_categories.rb +7 -0
  166. data/db/migrate/20111221111417_create_formol_forums.rb +10 -0
  167. data/db/migrate/20111221121010_create_formol_topics.rb +9 -0
  168. data/db/migrate/20111221123515_create_formol_posts.rb +9 -0
  169. data/db/migrate/20111221151653_add_index_on_tables.rb +15 -0
  170. data/db/migrate/20120103163438_add_user_to_models.rb +13 -0
  171. data/db/migrate/20120104132631_add_counter_cache_to_models.rb +12 -0
  172. data/db/migrate/20120104163741_add_pinned_to_topics.rb +7 -0
  173. data/db/migrate/20120105133522_add_position_to_categories.rb +7 -0
  174. data/db/migrate/20120105190708_add_position_to_forums.rb +7 -0
  175. data/db/migrate/20120105212559_add_lock_to_topics.rb +7 -0
  176. data/db/migrate/20120106130944_add_first_post_and_last_post_to_topics.rb +8 -0
  177. data/db/migrate/20120106192951_change_forum_description_to_string.rb +9 -0
  178. data/db/migrate/20120107012517_add_last_post_to_forum.rb +7 -0
  179. data/db/migrate/20120107122921_add_missing_indexes.rb +12 -0
  180. data/db/migrate/20120107123654_add_default_on_forum_counters.rb +10 -0
  181. data/db/migrate/20120108114030_add_views_to_topics.rb +7 -0
  182. data/db/migrate/20120108131533_create_formol_topic_tracks.rb +13 -0
  183. data/db/migrate/20120109115141_create_formol_topic_subscriptions.rb +10 -0
  184. data/db/migrate/20120109220633_create_formol_user_preferences.rb +11 -0
  185. data/db/migrate/20120109223624_add_display_signature_to_posts.rb +7 -0
  186. data/db/migrate/20120109233054_add_display_signatures_and_avatars_to_user_preferences.rb +8 -0
  187. data/db/migrate/20120110152548_create_formol_polls.rb +14 -0
  188. data/db/migrate/20120110152618_create_formol_poll_options.rb +11 -0
  189. data/db/migrate/20120110152632_create_formol_poll_votes.rb +12 -0
  190. data/lib/formol/config.rb +12 -0
  191. data/lib/formol/controllers/auth.rb +9 -0
  192. data/lib/formol/controllers/nested/has_parent_category.rb +11 -0
  193. data/lib/formol/controllers/nested/has_parent_forum.rb +11 -0
  194. data/lib/formol/controllers/nested/has_parent_topic.rb +11 -0
  195. data/lib/formol/controllers.rb +5 -0
  196. data/lib/formol/engine.rb +18 -0
  197. data/lib/formol/formatters/redcarpet/formatter.rb +36 -0
  198. data/lib/formol/formatters/redcarpet/syntax_highlighter.rb +23 -0
  199. data/lib/formol/formatters.rb +2 -0
  200. data/lib/formol/generators/install/install_generator.rb +94 -0
  201. data/lib/formol/generators/install/templates/config/formol.yml +29 -0
  202. data/lib/formol/generators/install/templates/initializer/formol.rb.erb +21 -0
  203. data/lib/formol/generators/install/templates/lib/permissions/special_rights.rb +24 -0
  204. data/lib/formol/generators/install/templates/migrations/add_formol_profile_to_users.rb.erb +7 -0
  205. data/lib/formol/generators/install/templates/migrations/add_posts_count_to_user.rb.erb +7 -0
  206. data/lib/formol/generators.rb +1 -0
  207. data/lib/formol/integration/user.rb +76 -0
  208. data/lib/formol/integration.rb +1 -0
  209. data/lib/formol/permissions/controllers.rb +30 -0
  210. data/lib/formol/permissions/manager.rb +29 -0
  211. data/lib/formol/permissions/profile.rb +24 -0
  212. data/lib/formol/permissions/profiles.rb +44 -0
  213. data/lib/formol/permissions/user.rb +29 -0
  214. data/lib/formol/permissions.rb +5 -0
  215. data/lib/formol/rails/engine.rb +81 -0
  216. data/lib/formol/rails.rb +1 -0
  217. data/lib/formol/version.rb +10 -0
  218. data/lib/formol/view_helpers/assets_helper.rb +11 -0
  219. data/lib/formol/view_helpers/format_helper.rb +12 -0
  220. data/lib/formol/view_helpers.rb +2 -0
  221. data/lib/formol/will_paginate/list_link_renderer.rb +29 -0
  222. data/lib/formol/will_paginate.rb +1 -0
  223. data/lib/formol.rb +61 -0
  224. data/lib/formol_.rb +13 -0
  225. data/lib/tasks/formol_tasks.rake +0 -0
  226. metadata +348 -0
@@ -0,0 +1,60 @@
1
+ module Formol
2
+ class Admin::CategoriesController < Admin::AdminController
3
+ respond_to :html, :except => [:sort]
4
+ respond_to :js, :only => [:sort]
5
+
6
+ def index
7
+ categories
8
+ end
9
+
10
+ def new
11
+ category
12
+ end
13
+
14
+ def create
15
+ if category.save
16
+ respond_with(category, :status => :created, :location => admin_categories_path)
17
+ else
18
+ respond_with(category, :status => :unprocessable_entity) do |format|
19
+ format.html { render :new }
20
+ end
21
+ end
22
+ end
23
+
24
+ def edit
25
+ category
26
+ end
27
+
28
+ def update
29
+ if category.update_attributes(params[:category])
30
+ respond_with(category, :location => admin_categories_path)
31
+ else
32
+ respond_with(category) do |format|
33
+ format.html { render :edit }
34
+ end
35
+ end
36
+ end
37
+
38
+ def destroy
39
+ category.destroy
40
+
41
+ respond_with(category, :location => admin_categories_path)
42
+ end
43
+
44
+ def sort
45
+ Formol::Category.sort(params[:categories])
46
+
47
+ render :nothing => true, :status => :ok
48
+ end
49
+
50
+ protected
51
+
52
+ def categories
53
+ @categories ||= Formol::Category.ready_for_listing.all
54
+ end
55
+
56
+ def category
57
+ @category ||= (params[:id].present? ? Formol::Category.find(params[:id]) : Formol::Category.new(params[:category]))
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,56 @@
1
+ module Formol
2
+ class Admin::ForumsController < Admin::AdminController
3
+ include Controllers::Nested::HasParentCategory
4
+
5
+ respond_to :html, :except => [:reorganize]
6
+ respond_to :js, :only => [:reorganize]
7
+
8
+ def new
9
+ forum
10
+
11
+ respond_with(forum)
12
+ end
13
+
14
+ def create
15
+ if forum.save
16
+ respond_with(forum, :status => :created, :location => admin_categories_path)
17
+ else
18
+ respond_with(forum, :status => :unprocessable_entity) do |format|
19
+ format.html { render :new }
20
+ end
21
+ end
22
+ end
23
+
24
+ def edit
25
+ forum
26
+ end
27
+
28
+ def update
29
+ if forum.update_attributes(params[:forum])
30
+ respond_with(forum, :location => admin_categories_path)
31
+ else
32
+ respond_with(forum) do |format|
33
+ format.html { render :edit }
34
+ end
35
+ end
36
+ end
37
+
38
+ def destroy
39
+ forum.destroy
40
+
41
+ respond_with(forum, :location => admin_categories_path)
42
+ end
43
+
44
+ def reorganize
45
+ Formol::Forum.reorganize(params[:forums], params[:category_id])
46
+
47
+ render :nothing => true, :status => :ok
48
+ end
49
+
50
+ protected
51
+
52
+ def forum
53
+ @forum ||= (params[:id].present? ? category.forums.find(params[:id]) : category.forums.new(params[:forum]))
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,47 @@
1
+ module Formol
2
+ class ApplicationController < ::ApplicationController
3
+ def per_page
4
+ 25
5
+ end
6
+
7
+ helper_method :per_page
8
+ helper_method :current_formol_user
9
+
10
+ def topic_post_page_number(topic, post)
11
+ #topic.posts.index is maybe not the most optimized
12
+ ((topic.posts(true).index(post) + 1).to_f / per_page.to_f).ceil
13
+ end
14
+
15
+ def paginated_forum_topic_post_path(forum, topic, post)
16
+ opts = {
17
+ :anchor => "formol_post_#{post.id}"
18
+ }
19
+
20
+ page = topic_post_page_number(topic, post)
21
+
22
+ opts[:page] = page if page > 1
23
+
24
+ forum_topic_path(forum, topic, opts)
25
+ end
26
+
27
+ helper_method :paginated_forum_topic_post_path
28
+
29
+ def topic_last_page_number(topic)
30
+ (topic.posts_count.to_f / per_page.to_f).ceil
31
+ end
32
+
33
+ def last_page_forum_topic_path(forum, topic, post)
34
+ opts = {
35
+ :anchor => "formol_post_#{post.id}"
36
+ }
37
+
38
+ page = topic_last_page_number(topic)
39
+
40
+ opts[:page] = page if page > 1
41
+
42
+ forum_topic_path(forum, topic, opts)
43
+ end
44
+
45
+ helper_method :last_page_forum_topic_path
46
+ end
47
+ end
@@ -0,0 +1,21 @@
1
+ module Formol
2
+ class CategoriesController < ApplicationController
3
+ respond_to :html
4
+
5
+ def index
6
+ formol_authorize!(current_formol_user, :read_category)
7
+
8
+ @categories = Formol::Category.ready_for_listing
9
+
10
+ respond_with(@categories)
11
+ end
12
+
13
+ def show
14
+ formol_authorize!(current_formol_user, :read_category)
15
+
16
+ @category = Formol::Category.find(params[:id])
17
+
18
+ respond_with(@category)
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,19 @@
1
+ module Formol
2
+ class ForumsController < ApplicationController
3
+ respond_to :html
4
+
5
+ def show
6
+ formol_authorize!(current_formol_user, :read_forum)
7
+
8
+ @topics = forum.topics.ready_for_listing.page(params[:page]).per_page(per_page)
9
+
10
+ respond_with(forum)
11
+ end
12
+
13
+ protected
14
+
15
+ def forum
16
+ @forum ||= Formol::Forum.find(params[:id])
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,23 @@
1
+ module Formol
2
+ class PollVotesController < ApplicationController
3
+ include Controllers::Nested::HasParentTopic
4
+
5
+ def create
6
+ formol_authorize!(current_formol_user, :vote_poll, topic)
7
+
8
+ poll.vote(current_formol_user, params['poll']['poll_vote_ids'])
9
+ rescue Formol::Poll::PollException => e
10
+ flash[:error] = t(e.message)
11
+ ensure
12
+ respond_to do |format|
13
+ format.html { redirect_to [topic.forum, topic] }
14
+ end
15
+ end
16
+
17
+ protected
18
+
19
+ def poll
20
+ @poll ||= topic.poll
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,71 @@
1
+ module Formol
2
+ class PostsController < ApplicationController
3
+ include Controllers::Nested::HasParentTopic
4
+
5
+ respond_to :html
6
+
7
+ def show
8
+ formol_authorize!(current_formol_user, :read_topic)
9
+
10
+ post
11
+
12
+ #respond_with location doesn't work here :/
13
+ respond_with(post) do |format|
14
+ format.html { redirect_to paginated_forum_topic_post_path(post.topic.forum, post.topic, post) }
15
+ end
16
+ end
17
+
18
+ def new
19
+ formol_authorize!(current_formol_user, :create_post, topic)
20
+
21
+ post(:quote_id => params[:quote], :user => current_formol_user)
22
+ end
23
+
24
+ def create
25
+ formol_authorize!(current_formol_user, :create_post, topic)
26
+
27
+ post(:user => current_formol_user)
28
+
29
+ if post.save
30
+ #post.topic(true) needed to handle counter increment
31
+ respond_with(post, :status => :created, :location => last_page_forum_topic_path(topic.forum, post.topic(true), post))
32
+ else
33
+ respond_with(post, :status => :unprocessable_entity) do |format|
34
+ format.html { render :new }
35
+ end
36
+ end
37
+ end
38
+
39
+ def edit
40
+ formol_authorize!(current_formol_user, :edit_post, post)
41
+
42
+ post
43
+ end
44
+
45
+ def update
46
+ formol_authorize!(current_formol_user, :edit_post, post)
47
+
48
+ if post.update_attributes(params[:post])
49
+ respond_with(post, :location => paginated_forum_topic_post_path(topic.forum, topic, post))
50
+ else
51
+ respond_with(post) do |format|
52
+ format.html { render :edit }
53
+ end
54
+ end
55
+ end
56
+
57
+ def destroy
58
+ formol_authorize!(current_formol_user, :destroy_post)
59
+
60
+ post.destroy
61
+
62
+ respond_with(post, :location => [topic.forum, topic])
63
+ end
64
+
65
+ protected
66
+
67
+ def post(attrs = {})
68
+ @post ||= (params[:id].present? ? topic.posts.find(params[:id]) : topic.posts.new(attrs.merge(params[:post] || {})))
69
+ end
70
+ end
71
+ end
@@ -0,0 +1,32 @@
1
+ module Formol
2
+ class PreferencesController < ApplicationController
3
+ respond_to :html
4
+
5
+ def show
6
+ preference
7
+
8
+ respond_with(preference)
9
+ end
10
+
11
+ def update
12
+ if preference.update_attributes(params[:user_preference])
13
+ respond_with(preference) do |format|
14
+ format.html { redirect_to preference_path }
15
+ end
16
+ # No wrong case to test for now
17
+ # just lower coverage
18
+ #
19
+ #else
20
+ # respond_with(preference) do |format|
21
+ # format.html { render :show }
22
+ # end
23
+ end
24
+ end
25
+
26
+ protected
27
+
28
+ def preference
29
+ @preference ||= current_formol_user.preference
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,29 @@
1
+ module Formol
2
+ class SubscriptionsController < ApplicationController
3
+ include Formol::Controllers::Nested::HasParentTopic
4
+
5
+ def create
6
+ formol_authorize!(current_formol_user, :subscribe_topic)
7
+
8
+ topic.register_subscriber(current_formol_user)
9
+
10
+ respond_to do |format|
11
+ format.js { render :nothing => true, :status => :ok }
12
+ end
13
+ rescue ActiveRecord::RecordInvalid
14
+ respond_to do |format|
15
+ format.js { render :nothing => true, :status => :unprocessable_entity }
16
+ end
17
+ end
18
+
19
+ def destroy
20
+ formol_authorize!(current_formol_user, :subscribe_topic)
21
+
22
+ topic.unregister_subscriber(current_formol_user)
23
+
24
+ respond_to do |format|
25
+ format.js { render :nothing => true, :status => :ok }
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,91 @@
1
+ module Formol
2
+ class TopicsController < ApplicationController
3
+ include Controllers::Nested::HasParentForum
4
+
5
+ respond_to :html
6
+
7
+ def show
8
+ formol_authorize!(current_formol_user, :read_topic)
9
+
10
+ topic.view!
11
+ topic.track_for_user!(current_formol_user)
12
+
13
+ @posts = topic.posts.ready_for_listing.page(params[:page]).per_page(per_page)
14
+
15
+ respond_with(topic)
16
+ end
17
+
18
+ def new
19
+ formol_authorize!(current_formol_user, :create_topic)
20
+
21
+ topic.posts.build(:register_user_as_subscriber => true)
22
+
23
+ unless topic.poll
24
+ topic.build_poll
25
+ topic.poll.options.build
26
+ end
27
+
28
+ respond_with(topic)
29
+ end
30
+
31
+ def create
32
+ formol_authorize!(current_formol_user, :create_topic)
33
+
34
+ topic.user = current_formol_user
35
+
36
+ if topic.save
37
+ respond_with(topic, :location => [forum, topic])
38
+ else
39
+ unless topic.poll
40
+ topic.build_poll
41
+ topic.poll.options.build
42
+ end
43
+
44
+ respond_with(topic, :status => :unprocessable_entity) do |format|
45
+ format.html { render :new }
46
+ end
47
+ end
48
+ end
49
+
50
+ def edit
51
+ formol_authorize!(current_formol_user, :edit_topic, topic)
52
+
53
+ respond_with(topic)
54
+ end
55
+
56
+ def update
57
+ formol_authorize!(current_formol_user, :edit_topic, topic)
58
+
59
+ if topic.update_attributes(params[:topic])
60
+ respond_with(topic, :location => [forum, topic])
61
+ else
62
+ respond_with(topic) do |format|
63
+ format.html { render :edit }
64
+ end
65
+ end
66
+ end
67
+
68
+ def destroy
69
+ formol_authorize!(current_formol_user, :destroy_topic)
70
+
71
+ topic.destroy
72
+
73
+ respond_with(topic, :location => forum)
74
+ end
75
+
76
+ protected
77
+
78
+ def topic
79
+ @topic ||= if params[:id].present?
80
+ if request.get?
81
+ forum.topics.ready_for_breadcrumb.includes(:poll => { :options => :votes }).find(params[:id])
82
+ else
83
+ # never eager load anything for update (brokes validates on associations)
84
+ forum.topics.find(params[:id])
85
+ end
86
+ else
87
+ forum.topics.new(params[:topic])
88
+ end
89
+ end
90
+ end
91
+ end
@@ -0,0 +1,4 @@
1
+ module Formol
2
+ module Admin::CategoriesHelper
3
+ end
4
+ end
@@ -0,0 +1,4 @@
1
+ module Formol
2
+ module Admin::ForumsHelper
3
+ end
4
+ end
@@ -0,0 +1,35 @@
1
+ module Formol
2
+ module ApplicationHelper
3
+ def breadcrumb_for(record)
4
+ items = [[t('home'), root_path]]
5
+
6
+ klass = record.class.to_s
7
+
8
+ case klass
9
+ when 'Formol::Category'
10
+ items << [record.label, category_path(record)]
11
+ when 'Formol::Forum'
12
+ items << [record.category.label, category_path(record.category)]
13
+ items << [record.label, forum_path(record)]
14
+ when 'Formol::Topic'
15
+ items << [record.forum.category.label, category_path(record.forum.category)]
16
+ items << [record.forum.label, forum_path(record.forum)]
17
+ items << [record.title, forum_topic_path(record.forum, record)]
18
+ end
19
+
20
+ content_tag(:ul, :class => 'breadcrumb') do
21
+ items.each do |(text, path)|
22
+ concat(content_tag(:li, :class => 'item'){ link_to(text, path) })
23
+ end
24
+ end
25
+ end
26
+
27
+ # When you want to link to last post, you don't need to calculate position
28
+ # of last post (wich need to load all topic's posts).
29
+ # Last post is obviously on last page, you can rely then on posts_count in
30
+ # topic object
31
+ def link_to_last_post(forum, topic, post, text = nil)
32
+ link_to (text || '>'), last_page_forum_topic_path(forum, topic, post), :title => t('formol.posts.last_post.go_to_last')
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,15 @@
1
+ module Formol
2
+ module CategoriesHelper
3
+ def formol_forum_klass(forum, user)
4
+ klasses = []
5
+
6
+ if user.present?
7
+ klasses << (user.has_read_forum?(forum) ? 'read' : 'unread')
8
+ else
9
+ klasses << 'read'
10
+ end
11
+
12
+ klasses.join(' ')
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,19 @@
1
+ module Formol
2
+ module ForumsHelper
3
+ def formol_topic_klass(topic, user)
4
+ klasses = []
5
+
6
+ klasses << 'pinned' if topic.pinned
7
+ klasses << 'locked' if topic.locked
8
+
9
+ unless user.blank?
10
+ klasses << (user.has_read_topic?(topic) ? 'read' : 'unread')
11
+ else
12
+ klasses << 'read'
13
+ end
14
+
15
+
16
+ klasses.join(' ')
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,4 @@
1
+ module Formol
2
+ module PollVotesHelper
3
+ end
4
+ end
@@ -0,0 +1,27 @@
1
+ module Formol
2
+ module PostsHelper
3
+ def link_to_post_position(post, index)
4
+ idx = ((params[:page] || 1) - 1) * per_page + index + 1
5
+
6
+ return link_to "##{idx}", "#formol_post_#{post.id}"
7
+ end
8
+
9
+ def link_to_last_fives_post_position(post, topic, index)
10
+ idx = topic.posts_count - index
11
+
12
+ return link_to "##{idx}", "#formol_post_#{post.id}"
13
+ end
14
+
15
+ def display_avatars?(user)
16
+ return true unless user
17
+
18
+ user.preference.display_avatars?
19
+ end
20
+
21
+ def display_signatures?(user, post)
22
+ s = post.display_signature? && !post.user.preference.signature.blank?
23
+
24
+ (s && user ? user.preference.display_signatures? : s)
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,4 @@
1
+ module Formol
2
+ module PreferencesHelper
3
+ end
4
+ end
@@ -0,0 +1,4 @@
1
+ module Formol
2
+ module SubscriptionsHelper
3
+ end
4
+ end
@@ -0,0 +1,27 @@
1
+ module Formol
2
+ module TopicsHelper
3
+ include PostsHelper
4
+
5
+ def link_to_subscription(topic, user)
6
+ subscriber = topic.subscriber?(user)
7
+ method = subscriber ? :delete : :post
8
+ text = t('formol.topics.show.' + (subscriber ? 'unsubscribe' : 'subscribe'))
9
+ switch_text = t('formol.topics.show.' + (subscriber ? 'subscribe' : 'unsubscribe'))
10
+
11
+ link_to text, topic_subscriptions_path(topic), :method => method,
12
+ :remote => true,
13
+ :'data-switch-text' => switch_text
14
+ end
15
+
16
+ def attach_poll_checkbox(topic)
17
+ %{<input type="checkbox" name="topic[attach_poll]" id="topic_attach_poll" value="1" #{'checked="checked"' if topic.attach_poll} />}.html_safe
18
+ end
19
+
20
+ def display_poll_form?(poll, topic, user)
21
+ !poll.expired? &&
22
+ !topic.locked? &&
23
+ formol_authorized?(user, :vote_poll, topic) &&
24
+ !poll.voted?(user)
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,13 @@
1
+ module Formol
2
+ class SubscriptionMailer < ActionMailer::Base
3
+ default :from => Formol.config.email_from
4
+
5
+ def topic_reply(post, subscriber)
6
+ @post = post
7
+
8
+ mail( :to => subscriber.email,
9
+ :subject => "New reply: #{post.topic.title}",
10
+ :layout => 'formol/mail')
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,42 @@
1
+ module Formol
2
+ class Category < ActiveRecord::Base
3
+ #Modules
4
+ include RankedModel
5
+
6
+ #Associations
7
+ has_many :forums, :dependent => :destroy,
8
+ :order => 'formol_forums.position'
9
+
10
+ #Validations
11
+ validates :label, :presence => true,
12
+ :length => { :in => 3..32,
13
+ :allow_blank => true },
14
+ :uniqueness => { :case_sensitive => false,
15
+ :allow_blank => true }
16
+
17
+ #Normalization
18
+ normalize_attributes :label, :with => [:squish, :blank]
19
+
20
+ #Sorting
21
+ ranks :position
22
+
23
+ #Scopes
24
+ class << self
25
+ # return categories conveniently ordered and eager-loaded for listing
26
+ def ready_for_listing
27
+ includes(:forums => { :last_post => [:user, :topic] }).rank(:position)
28
+ end
29
+ end
30
+
31
+ #Business
32
+ class << self
33
+ # Sorts categories from an array of ids
34
+ def sort(category_ids)
35
+ #TODO: should maybe optimize this?
36
+ (category_ids || []).each_with_index do |category_id, index|
37
+ find(category_id).update_attribute(:position, index)
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end