Permalink
Browse files

reimporting o2 from svn

  • Loading branch information...
1 parent 7a9a2ff commit f36de8fc151605686daceb115b1c91df6ce77847 @danielw committed Sep 1, 2009
Showing with 19,693 additions and 0 deletions.
  1. +17 −0 .gitignore
  2. +3 −0 Capfile
  3. +20 −0 MIT-LICENSE
  4. +10 −0 Rakefile
  5. +99 −0 app/controllers/accounts_controller.rb
  6. +28 −0 app/controllers/admin_controller.rb
  7. +52 −0 app/controllers/application.rb
  8. +55 −0 app/controllers/categories_controller.rb
  9. +21 −0 app/controllers/dashboard_controller.rb
  10. +55 −0 app/controllers/forums_controller.rb
  11. +23 −0 app/controllers/images_controller.rb
  12. +17 −0 app/controllers/legacy_routes_controller.rb
  13. +128 −0 app/controllers/posts_controller.rb
  14. +14 −0 app/controllers/search_controller.rb
  15. +8 −0 app/controllers/tools_controller.rb
  16. +69 −0 app/controllers/users_controller.rb
  17. +3 −0 app/helpers/accounts_helper.rb
  18. +2 −0 app/helpers/admin_accounts_helper.rb
  19. +7 −0 app/helpers/admin_helper.rb
  20. +127 −0 app/helpers/application_helper.rb
  21. +3 −0 app/helpers/categories_helper.rb
  22. +3 −0 app/helpers/dashboard_helper.rb
  23. +2 −0 app/helpers/feeds_helper.rb
  24. +2 −0 app/helpers/forums_helper.rb
  25. +2 −0 app/helpers/images_helper.rb
  26. +2 −0 app/helpers/legacy_routes_helper.rb
  27. +2 −0 app/helpers/opinion_helper.rb
  28. +10 −0 app/helpers/posts_helper.rb
  29. +14 −0 app/helpers/search_helper.rb
  30. +2 −0 app/helpers/tools_helper.rb
  31. +2 −0 app/helpers/users_helper.rb
  32. +34 −0 app/models/category.rb
  33. +50 −0 app/models/comment.rb
  34. +20 −0 app/models/forum.rb
  35. +26 −0 app/models/image.rb
  36. +61 −0 app/models/post.rb
  37. +36 −0 app/models/sql_like_query.rb
  38. +62 −0 app/models/topic.rb
  39. +78 −0 app/models/user.rb
  40. +14 −0 app/models/user_mailer.rb
  41. +8 −0 app/services/search.rb
  42. +2 −0 app/views/accounts/destroy.rjs
  43. +24 −0 app/views/accounts/index.rhtml
  44. +41 −0 app/views/accounts/new.rhtml
  45. +14 −0 app/views/accounts/password_recovery.rhtml
  46. +50 −0 app/views/admin/_new_user.rhtml
  47. +12 −0 app/views/admin/_user_li.rhtml
  48. +20 −0 app/views/admin/create_user.rjs
  49. +69 −0 app/views/admin/index.rhtml
  50. +46 −0 app/views/categories/_categories_table.rhtml
  51. +6 −0 app/views/categories/_edit.rhtml
  52. +9 −0 app/views/categories/create.rjs
  53. +2 −0 app/views/categories/destroy.rjs
  54. +8 −0 app/views/categories/rename.rjs
  55. +57 −0 app/views/categories/show.rhtml
  56. +20 −0 app/views/categories/show.rxml
  57. +5 −0 app/views/categories/update.rjs
  58. +20 −0 app/views/dashboard/feed.rxml
  59. +72 −0 app/views/dashboard/index.rhtml
  60. +22 −0 app/views/forums/_forum.rhtml
  61. +3 −0 app/views/forums/_forum_li.rhtml
  62. +10 −0 app/views/forums/create.rjs
  63. +2 −0 app/views/forums/destroy.rjs
  64. +57 −0 app/views/forums/show.rhtml
  65. +20 −0 app/views/forums/show.rxml
  66. +9 −0 app/views/forums/update.rjs
  67. +73 −0 app/views/layouts/accounts.rhtml
  68. +98 −0 app/views/layouts/application.rhtml
  69. +48 −0 app/views/posts/_comment.rhtml
  70. +7 −0 app/views/posts/_comments_table.rhtml
  71. +24 −0 app/views/posts/_formatting_guide.rhtml
  72. +19 −0 app/views/posts/_recent_activity.rhtml
  73. +31 −0 app/views/posts/_topic.rhtml
  74. +58 −0 app/views/posts/edit.rhtml
  75. +61 −0 app/views/posts/new.rhtml
  76. +150 −0 app/views/posts/show.rhtml
  77. +29 −0 app/views/posts/show.rxml
  78. +6 −0 app/views/posts/update.rjs
  79. +50 −0 app/views/search/results.rhtml
  80. +8 −0 app/views/user_mailer/recover.rhtml
  81. +6 −0 app/views/users/_user_li.rhtml
  82. +10 −0 app/views/users/create_user.rjs
  83. +20 −0 app/views/users/gravatar.rhtml
  84. +27 −0 app/views/users/list.rhtml
  85. +2 −0 app/views/users/remove_user.rjs
  86. +119 −0 app/views/users/show.rhtml
  87. +14 −0 config/amazon_s3.yml
  88. +36 −0 config/boot.rb
  89. +88 −0 config/database.example.yml
  90. +71 −0 config/environment.rb
  91. +19 −0 config/environments/development.rb
  92. +20 −0 config/environments/production.rb
  93. +19 −0 config/environments/test.rb
  94. +53 −0 config/lighttpd.conf
  95. +11 −0 config/recaptcha.example.yml
  96. +32 −0 config/routes.rb
  97. +34 −0 db/development_structure.sql
  98. +32 −0 db/migrate/001_new_initial_tables.rb
  99. +9 −0 db/migrate/002_add_parent_id_to_posts.rb
  100. +9 −0 db/migrate/003_remove_obsolete_gravatar_link.rb
  101. +9 −0 db/migrate/004_remove_login_from_users.rb
  102. +24 −0 db/migrate/005_add_area.rb
  103. +24 −0 db/migrate/006_add_user_type.rb
  104. +9 −0 db/migrate/007_add_area_id_to_remote_sites.rb
  105. +9 −0 db/migrate/008_add_updated_at_to_posts.rb
  106. +9 −0 db/migrate/009_add_status_to_posts.rb
  107. +9 −0 db/migrate/010_add_title_dashed_to_categories.rb
  108. +11 −0 db/migrate/011_add_index.rb
  109. +14 −0 db/migrate/012_add_token_to_users.rb
  110. +15 −0 db/migrate/013_add_inspirations.rb
  111. +8 −0 db/migrate/014_add_null_posts_default.rb
  112. +9 −0 db/migrate/015_add_anon_posts_for_areas.rb
  113. +13 −0 db/migrate/016_add_entries_for_files.rb
  114. +9 −0 db/migrate/017_rename_entries_to_attachments.rb
  115. +9 −0 db/migrate/018_rename_post_to_topic_id.rb
  116. +12 −0 db/migrate/019_drop_attachments.rb
  117. +13 −0 db/migrate/020_add_category_id_to_comments.rb
  118. +26 −0 db/migrate/021_cleanup.rb
  119. +20 −0 db/migrate/022_areas_to_forums.rb
  120. +13 −0 db/migrate/023_remove_title_dashed.rb
  121. +9 −0 db/migrate/024_remove_post_count.rb
  122. +11 −0 db/migrate/025_add_description_for_categories.rb
  123. +11 −0 db/migrate/026_add_user_desc.rb
  124. +9 −0 db/migrate/027_add_edited_at_to_posts.rb
  125. +11 −0 db/migrate/028_add_forum_body_and_category_subtitles.rb
  126. +13 −0 db/migrate/029_change_category_description_from_string_to_text.rb
  127. +9 −0 db/migrate/030_change_signature_to_text.rb
  128. +21 −0 db/migrate/031_create_images.rb
  129. +9 −0 db/migrate/032_add_access_level_to_category.rb
  130. +14 −0 db/migrate/033_delete_accounts_with_zero_posts.rb
  131. +71 −0 db/schema.rb
  132. +2 −0 doc/README_FOR_APP
  133. +18 −0 lib/dash_string.rb
  134. +62 −0 lib/tasks/backup.rake
  135. +90 −0 lib/tasks/capistrano.rake
  136. +40 −0 public/.htaccess
  137. +22 −0 public/404.html
  138. +77 −0 public/500.html
  139. +10 −0 public/dispatch.cgi
  140. +24 −0 public/dispatch.fcgi
  141. +10 −0 public/dispatch.rb
  142. 0 public/favicon.ico
  143. BIN public/files/0000/0013/2.jpg
  144. BIN public/files/0000/0013/2_thumb.jpg
  145. BIN public/files/15/2.jpg
  146. BIN public/files/15/2_thumb.jpg
  147. BIN public/images/admin-no-gravatar.jpg
  148. BIN public/images/bg.gif
  149. BIN public/images/blank.gif
  150. BIN public/images/breadcrumb-bg.gif
  151. BIN public/images/close.gif
  152. BIN public/images/closed.gif
  153. BIN public/images/closelabel.gif
  154. BIN public/images/comment-details-tr.gif
  155. BIN public/images/comment-details.gif
  156. BIN public/images/comment-shade.gif
  157. BIN public/images/loading.gif
  158. BIN public/images/next.gif
  159. BIN public/images/nextlabel.gif
  160. BIN public/images/no-gravatar.jpg
  161. BIN public/images/prev.gif
  162. BIN public/images/prevlabel.gif
  163. BIN public/images/rails.png
  164. BIN public/images/rss.png
  165. BIN public/images/spinner.gif
  166. BIN public/images/star.png
  167. BIN public/images/sticky.gif
  168. BIN public/images/trash.gif
  169. 0 public/javascripts/application.js
  170. +873 −0 public/javascripts/controls.js
  171. +968 −0 public/javascripts/dragdrop.js
  172. +1,092 −0 public/javascripts/effects.js
  173. +29 −0 public/javascripts/flash.js
  174. +689 −0 public/javascripts/lightbox.js
  175. +128 −0 public/javascripts/opinion.js
  176. +3,271 −0 public/javascripts/prototype.js
  177. +27 −0 public/javascripts/routing_navigator.js
  178. +1 −0 public/robots.txt
  179. +120 −0 public/stylesheets/ie.css
  180. +104 −0 public/stylesheets/lightbox.css
  181. +804 −0 public/stylesheets/opinion.css
  182. +48 −0 public/stylesheets/routing_navigator.css
  183. +3 −0 script/about
  184. +3 −0 script/breakpointer
  185. +3 −0 script/console
  186. +3 −0 script/destroy
  187. +3 −0 script/generate
  188. +3 −0 script/performance/benchmarker
  189. +3 −0 script/performance/profiler
  190. +3 −0 script/plugin
  191. +3 −0 script/process/inspector
  192. +3 −0 script/process/reaper
  193. +3 −0 script/process/spawner
  194. +3 −0 script/process/spinner
  195. +3 −0 script/runner
  196. +3 −0 script/server
  197. +36 −0 test/fixtures/categories.yml
  198. +15 −0 test/fixtures/forums.yml
  199. +21 −0 test/fixtures/images.yml
  200. +74 −0 test/fixtures/posts.yml
  201. +34 −0 test/fixtures/users.yml
  202. +89 −0 test/functional/accounts_controller_test.rb
  203. +20 −0 test/functional/admin_controller_test.rb
  204. +73 −0 test/functional/categories_controller_test.rb
  205. +68 −0 test/functional/forums_controller_test.rb
  206. +18 −0 test/functional/images_controller_test.rb
  207. +18 −0 test/functional/legacy_routes_controller_test.rb
  208. +127 −0 test/functional/posts_controller_test.rb
  209. +22 −0 test/functional/search_controller_test.rb
  210. +21 −0 test/functional/tools_controller_test.rb
  211. +31 −0 test/functional/users_controller_test.rb
  212. +11 −0 test/mocks/test/remote_login_site.rb
  213. +39 −0 test/test_helper.rb
  214. +10 −0 test/unit/category_test.rb
  215. +10 −0 test/unit/forum_test.rb
  216. +10 −0 test/unit/image_test.rb
  217. +44 −0 test/unit/post_test.rb
  218. +31 −0 test/unit/user_mailer_test.rb
  219. +10 −0 test/unit/user_test.rb
  220. +3 −0 vendor/RedCloth-3.0.3/bin/redcloth
  221. +1,113 −0 vendor/RedCloth-3.0.3/lib/redcloth.rb
  222. +26 −0 vendor/RedCloth-3.0.3/run-tests.rb
  223. +105 −0 vendor/RedCloth-3.0.3/tests/code.yml
  224. +171 −0 vendor/RedCloth-3.0.3/tests/images.yml
  225. +39 −0 vendor/RedCloth-3.0.3/tests/instiki.yml
  226. +155 −0 vendor/RedCloth-3.0.3/tests/links.yml
  227. +77 −0 vendor/RedCloth-3.0.3/tests/lists.yml
  228. +218 −0 vendor/RedCloth-3.0.3/tests/markdown.yml
  229. +64 −0 vendor/RedCloth-3.0.3/tests/poignant.yml
  230. +198 −0 vendor/RedCloth-3.0.3/tests/table.yml
  231. +397 −0 vendor/RedCloth-3.0.3/tests/textism.yml
  232. +46 −0 vendor/plugins/annotate_models/ChangeLog
  233. +31 −0 vendor/plugins/annotate_models/README
  234. +127 −0 vendor/plugins/annotate_models/lib/annotate_models.rb
  235. +6 −0 vendor/plugins/annotate_models/tasks/annotate_models_tasks.rake
  236. +4 −0 vendor/plugins/attachment_fu/README
  237. +22 −0 vendor/plugins/attachment_fu/Rakefile
  238. +14 −0 vendor/plugins/attachment_fu/amazon_s3.yml.tpl
  239. +14 −0 vendor/plugins/attachment_fu/init.rb
  240. +5 −0 vendor/plugins/attachment_fu/install.rb
  241. +93 −0 vendor/plugins/attachment_fu/lib/geometry.rb
  242. +419 −0 vendor/plugins/attachment_fu/lib/technoweenie/attachment_fu.rb
  243. +39 −0 vendor/plugins/attachment_fu/lib/technoweenie/attachment_fu/backends/db_file_backend.rb
  244. +91 −0 vendor/plugins/attachment_fu/lib/technoweenie/attachment_fu/backends/file_system_backend.rb
  245. +304 −0 vendor/plugins/attachment_fu/lib/technoweenie/attachment_fu/backends/s3_backend.rb
  246. +50 −0 vendor/plugins/attachment_fu/lib/technoweenie/attachment_fu/processors/image_science_processor.rb
  247. +56 −0 vendor/plugins/attachment_fu/lib/technoweenie/attachment_fu/processors/mini_magick_processor.rb
  248. +53 −0 vendor/plugins/attachment_fu/lib/technoweenie/attachment_fu/processors/rmagick_processor.rb
  249. +16 −0 vendor/plugins/attachment_fu/test/backends/db_file_test.rb
  250. +80 −0 vendor/plugins/attachment_fu/test/backends/file_system_test.rb
  251. +103 −0 vendor/plugins/attachment_fu/test/backends/remote/s3_test.rb
  252. +57 −0 vendor/plugins/attachment_fu/test/base_attachment_tests.rb
  253. +57 −0 vendor/plugins/attachment_fu/test/basic_test.rb
  254. +57 −0 vendor/plugins/attachment_fu/test/extra_attachment_test.rb
  255. +126 −0 vendor/plugins/attachment_fu/test/fixtures/attachment.rb
  256. BIN vendor/plugins/attachment_fu/test/fixtures/files/fake/rails.png
  257. +1 −0 vendor/plugins/attachment_fu/test/fixtures/files/foo.txt
  258. BIN vendor/plugins/attachment_fu/test/fixtures/files/rails.png
  259. +101 −0 vendor/plugins/attachment_fu/test/geometry_test.rb
  260. +31 −0 vendor/plugins/attachment_fu/test/processors/image_science_test.rb
  261. +31 −0 vendor/plugins/attachment_fu/test/processors/mini_magick_test.rb
  262. +240 −0 vendor/plugins/attachment_fu/test/processors/rmagick_test.rb
  263. +86 −0 vendor/plugins/attachment_fu/test/schema.rb
  264. +121 −0 vendor/plugins/attachment_fu/test/test_helper.rb
  265. +55 −0 vendor/plugins/attachment_fu/test/validation_test.rb
  266. +152 −0 vendor/plugins/classic_pagination/CHANGELOG
  267. +18 −0 vendor/plugins/classic_pagination/README
  268. +22 −0 vendor/plugins/classic_pagination/Rakefile
  269. +33 −0 vendor/plugins/classic_pagination/init.rb
  270. +1 −0 vendor/plugins/classic_pagination/install.rb
  271. +405 −0 vendor/plugins/classic_pagination/lib/pagination.rb
  272. +135 −0 vendor/plugins/classic_pagination/lib/pagination_helper.rb
  273. +24 −0 vendor/plugins/classic_pagination/test/fixtures/companies.yml
  274. +9 −0 vendor/plugins/classic_pagination/test/fixtures/company.rb
  275. +7 −0 vendor/plugins/classic_pagination/test/fixtures/developer.rb
  276. +21 −0 vendor/plugins/classic_pagination/test/fixtures/developers.yml
  277. +13 −0 vendor/plugins/classic_pagination/test/fixtures/developers_projects.yml
  278. +3 −0 vendor/plugins/classic_pagination/test/fixtures/project.rb
  279. +7 −0 vendor/plugins/classic_pagination/test/fixtures/projects.yml
  280. +13 −0 vendor/plugins/classic_pagination/test/fixtures/replies.yml
  281. +5 −0 vendor/plugins/classic_pagination/test/fixtures/reply.rb
  282. +42 −0 vendor/plugins/classic_pagination/test/fixtures/schema.sql
  283. +3 −0 vendor/plugins/classic_pagination/test/fixtures/topic.rb
  284. +22 −0 vendor/plugins/classic_pagination/test/fixtures/topics.yml
  285. +117 −0 vendor/plugins/classic_pagination/test/helper.rb
  286. +38 −0 vendor/plugins/classic_pagination/test/pagination_helper_test.rb
  287. +177 −0 vendor/plugins/classic_pagination/test/pagination_test.rb
  288. +22 −0 vendor/plugins/html_engine/Rakefile
  289. +42 −0 vendor/plugins/html_engine/init.rb
  290. +48 −0 vendor/plugins/html_engine/lib/html_engine.rb
  291. +24 −0 vendor/plugins/html_engine/lib/html_engine_ext.rb
  292. +38 −0 vendor/plugins/html_engine/lib/red_cloth_patches.rb
  293. +44 −0 vendor/plugins/html_engine/test/engine_test.rb
  294. +8 −0 vendor/plugins/html_engine/test/test_helper.rb
  295. +22 −0 vendor/plugins/identifications/Rakefile
  296. +5 −0 vendor/plugins/identifications/init.rb
  297. +102 −0 vendor/plugins/identifications/lib/handle.rb
  298. +45 −0 vendor/plugins/identifications/lib/token.rb
  299. +4 −0 vendor/plugins/identifications/test/fixtures/article.rb
  300. 0 vendor/plugins/identifications/test/fixtures/articles.yml
Sorry, we could not display the entire diff because too many files (1,550) changed.
View
17 .gitignore
@@ -0,0 +1,17 @@
+*.log
+
+# We ignore all subversion directories underneath test and vendor
+.svn
+vendor/*/.svn
+test/*/.svn
+
+# ignore osx dsstore files
+.DS_Store
+
+tmp/*
+
+*.db
+
+database.yml
+recaptcha.yml
+deploy.rb
View
3 Capfile
@@ -0,0 +1,3 @@
+require 'capistrano/version'
+#load 'deploy' if respond_to?(:namespace) # cap2 differentiator
+load 'config/deploy'
View
20 MIT-LICENSE
@@ -0,0 +1,20 @@
+Copyright (c) 2005-2006 Daniel Weinand
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
View
10 Rakefile
@@ -0,0 +1,10 @@
+# Add your own tasks in files placed in lib/tasks ending in .rake,
+# for example lib/tasks/switchtower.rake, and they will automatically be available to Rake.
+
+require(File.join(File.dirname(__FILE__), 'config', 'boot'))
+
+require 'rake'
+require 'rake/testtask'
+require 'rake/rdoctask'
+
+require 'tasks/rails'
View
99 app/controllers/accounts_controller.rb
@@ -0,0 +1,99 @@
+class AccountsController < ApplicationController
+ before_filter :require_admin, :only => [:destroy]
+
+
+ def index
+ @user = User.new(params[:user])
+
+ if request.post?
+
+ if user = User.find_by_email_and_password(@user.email,@user.password)
+
+ if params[:remember] == 'on'
+ cookies[:token] = { :value => user.token, :expires => 3.months.from_now }
+ end
+
+ session[:user] = user
+ flash[:notice] = "Welcome #{user.name}"
+ redirect_to params[:return_to] || index_url
+ return
+ end
+
+ flash[:notice] = "Invalid login."
+ end
+ end
+
+ def new
+ # Add condition here if you want to disable or restrict the registration of new users
+ if false
+ redirect_to index_url and return
+ end
+
+ @user = User.new(params[:user])
+ end
+
+ def create
+ @user = User.new(params[:user])
+
+ # First user created is a superuser
+ @user.level = User.count > 0 ? 0 : 1024
+
+ if verify_recaptcha and @user.save
+ flash[:notice] = "Successfully created user #{@user.name}&hellip;"
+ session[:user] = @user
+
+ redirect_to index_url
+ else
+ render :action => 'new'
+ end
+ end
+
+ def update
+ @user.attributes = params[:user]
+
+ if @user.save
+ flash[:notice] = "Successfully updated user #{@user.name}&hellip;"
+ session[:user] = @user
+
+ redirect_to index_url
+ else
+ flash[:error] = "Could not save user: #{@user.errors.full_messages}"
+ redirect_to :action => 'edit'
+ end
+ end
+
+ def logout
+ session[:user] = nil
+ cookies[:token] = { :value => '', :expires => Time.at(0) }
+ redirect_to index_url
+ end
+
+ def password_recovery
+
+ if request.post?
+
+ if user = User.find_by_email(params[:user][:email])
+ UserMailer.deliver_recover(user, request.host)
+ render :update do |page|
+ page.call 'Flash.notice', "The password has been sent to <u>#{user.email}</u>&hellip;"
+ end
+ else
+ render :update do |page|
+ page.call 'Flash.error', "The email address you specified is not registered!"
+ end
+ end
+ end
+
+ end
+
+ def destroy
+ @deleted_user = User.find(params[:id])
+ @deleted_user.destroy
+ respond_to do |accepts|
+ accepts.html { flash[:notice] = "Removed user #{@deleted_user.name}&hellip;"; redirect_to index_url }
+ accepts.js
+ end
+ end
+
+
+end
View
28 app/controllers/admin_controller.rb
@@ -0,0 +1,28 @@
+class AdminController < ApplicationController
+ before_filter :require_super_user
+
+ def index
+ @superusers = User.find(:all, :conditions => "level = 1024")
+ @admins = User.find(:all, :conditions => "level = 128")
+ @moderators = User.find(:all, :conditions => "level = 64")
+ end
+
+ def new_user
+ render :partial => 'new_user'
+ end
+
+ def create_user
+ @newuser = User.new(params[:newuser])
+ @newuser.level = params[:newuser][:level]
+ @newuser.save
+ end
+
+ protected
+
+ def access_denied
+ session[:return_to] = { :controller => controller_name, :action => action_name }
+ redirect_to :controller => "accounts"
+ return false
+ end
+
+end
View
52 app/controllers/application.rb
@@ -0,0 +1,52 @@
+# Filters added to this controller will be run for all controllers in the application.
+# Likewise, all the methods added will be available for all controllers.
+class ApplicationController < ActionController::Base
+ before_filter :login
+
+ protected
+
+ def load_forum
+ @forum = Forum.find(params[:forum])
+ if not @forum
+ raise StandardError, "unknown forum"
+ end
+ end
+
+ def access_denied
+ flash[:error] = "You do not have the required user level to perform the action #{controller_name}::#{action_name}"
+ redirect_to '/'
+ return false
+ end
+
+ def login
+ user = session[:user] || login_from_cookie
+
+ if user
+ @user = User.auth(user.email, user.password)
+ end
+ end
+
+ def login_from_cookie
+ if cookies[:token]
+ return session[:user] = User.find_by_token(cookies[:token])
+ end
+ nil
+ end
+
+ def access_conditions
+ 'access_level <= ' << (@user.nil? ? 0 : @user.level).to_i.to_s
+ end
+
+ def require_super_user
+ access_denied unless @user and @user.level >= 1024
+ end
+
+ def require_admin
+ access_denied unless @user and @user.level >= 128
+ end
+
+ def require_moderator
+ access_denied unless @user and @user.level >= 64
+ end
+
+end
View
55 app/controllers/categories_controller.rb
@@ -0,0 +1,55 @@
+class CategoriesController < ApplicationController
+ before_filter :require_admin, :except => [:show]
+
+ def show
+ @category = Category.find(params[:id], :conditions => access_conditions)
+ @topic_pages = Paginator.new(self, @category.topics.count, 20, params[:page])
+ @topics = @category.topics.find(:all, :limit => 20, :offset => @topic_pages.current.offset, :order => "(status = 'sticky') DESC, updated_at DESC")
+ @recent_posts = @category.posts.find(:all, :limit => 20, :order => 'id DESC')
+ @rss = formatted_category_url(@category, 'xml')
+
+ respond_to do |accepts|
+ accepts.html
+ accepts.xml { render :action => 'show.rxml', :layout => false}
+ end
+ end
+
+ def create
+ forum = Forum.find(params[:forum_id])
+ @categories = forum.categories
+ @category = Category.new
+ @category.forum_id = forum.id
+ @category.attributes = params[:category]
+ @category.save
+
+ respond_to do |accepts|
+ accepts.js
+ end
+ end
+
+ def edit
+ @category = Category.find(params[:id])
+ render :partial => 'edit'
+ end
+
+ def destroy
+ @category = Category.find(params[:id])
+ @category.destroy
+ end
+
+ def rename
+ update
+ @categories = @category.forum.categories
+ end
+
+ def update
+ @category = Category.find(params[:id])
+ @category.attributes = params[:category]
+ @category.save
+ end
+
+ private
+
+
+
+end
View
21 app/controllers/dashboard_controller.rb
@@ -0,0 +1,21 @@
+class DashboardController < ApplicationController
+
+ def index
+ @topic_count = Topic.count
+ @comment_count = Comment.count
+ @user_count = User.count
+ @forums = Forum.find(:all)
+ @rss = url_for(:action => 'feed', :only_path => false)
+
+ today, yesterday = Time.now.to_date, Time.now.yesterday.to_date
+ @recent_posts = Post.find(:all, :limit => 10, :conditions => ["category_id in (?)", Category.ids_matching(access_conditions)], :order => 'id DESC')
+ end
+
+ def feed
+ @recent_posts = Post.find(:all, :conditions => ["category_id in (?)", Category.ids_matching(access_conditions)], :limit => 10, :order => 'id DESC')
+ respond_to do |accepts|
+ accepts.xml { render :action => 'feed.rxml', :layout => false}
+ end
+ end
+
+end
View
55 app/controllers/forums_controller.rb
@@ -0,0 +1,55 @@
+class ForumsController < ApplicationController
+ before_filter :require_super_user, :except => [:show]
+
+
+ def show
+ @forum = Forum.find(params[:id])
+ @category_pages = Paginator.new(self, @forum.categories.count(:all, :conditions => access_conditions), 20, params[:page])
+ @categories = @forum.categories.find(:all, :limit => 20, :conditions => access_conditions, :offset => @category_pages.current.offset, :order => 'id ASC')
+
+ @rss = formatted_forum_url(@forum, 'xml')
+
+ today, yesterday = Time.now.to_date, Time.now.yesterday.to_date
+ @recent_posts = @forum.posts.find(:all, :limit => 20, :conditions => ['category_id in (?)', Category.ids_matching(access_conditions)], :order => 'id DESC')
+
+ respond_to do |accepts|
+ accepts.html
+ accepts.xml { render :action => 'show.rxml', :layout => false}
+ end
+ end
+
+
+ def create
+ @forum = Forum.new
+ @forum.attributes = params[:forum]
+ @forum.save
+
+ respond_to do |accepts|
+ accepts.html { flash[:notice] = "Successfully created..."; redirect_to forum_url(@forum) }
+ accepts.js
+ end
+ end
+
+ def destroy
+ @forum = Forum.find(params[:id])
+ @forum.destroy
+
+ respond_to do |accepts|
+ accepts.html { flash[:notice] = "Successfully removed..."; redirect_to index_url }
+ accepts.js
+ end
+ end
+
+ def update
+ @forum = Forum.find(params[:id])
+ @forum.attributes = params[:forum]
+ @forum.save
+
+ respond_to do |accepts|
+ accepts.html { flash[:notice] = "Successfully updated..."; redirect_to forum_url(@forum) }
+ accepts.js
+ end
+ end
+
+
+end
View
23 app/controllers/images_controller.rb
@@ -0,0 +1,23 @@
+class ImagesController < ApplicationController
+ before_filter :fetch_post
+
+ def create
+ if @post.editable? and @post.owner?(@user)
+ image = @post.images.build(params[:image])
+
+ if image.save
+ flash[:notice] = "Successfully uploaded #{image.filename}..."
+ else
+ flash[:error] = "Uploaded image was too large."
+ end
+ end
+
+ params[:return_to] ? redirect_to(params[:return_to]) : redirect_to(:back)
+ end
+
+ private
+
+ def fetch_post
+ @post = Category.find(params[:category_id], :conditions => access_conditions).posts.find(params[:post_id])
+ end
+end
View
17 app/controllers/legacy_routes_controller.rb
@@ -0,0 +1,17 @@
+class LegacyRoutesController < ApplicationController
+
+ def area
+ area = Forum.find(params[:id])
+ redirect_to forum_url(area)
+ end
+
+ def category
+ cat = Category.find(params[:id])
+ redirect_to category_url(cat)
+ end
+
+ def post
+ post = Post.find(params[:id])
+ redirect_to category_post_url(post.category_id, post.id)
+ end
+end
View
128 app/controllers/posts_controller.rb
@@ -0,0 +1,128 @@
+class PostsController < ApplicationController
+ before_filter :fetch_category
+ before_filter :require_moderator, :except => [:show, :edit, :update, :create, :new]
+
+ def show
+ @topic = @post = Topic.find(params[:id])
+ @rss = formatted_category_post_url(@topic.category, @topic, 'xml')
+
+ respond_to do |accepts|
+ accepts.html
+ accepts.xml { render :action => 'show.rxml', :layout => false}
+ end
+
+ end
+
+ def new
+ @topic = @category.topics.create(params[:topic])
+ end
+
+ def create
+ # If post is a comment, find its parent topic
+ if params[:comment]
+ @topic = Topic.find(params[:topic])
+
+ unless @topic.closed?
+ @post = @topic.comments.build(params[:comment])
+ @post.forum = @topic.forum
+ @post.category_id = @topic.category_id
+
+ end
+
+ # if post is a topic, create a new topic
+ else
+ @post = @category.topics.create(params[:topic])
+
+ @post.forum = @category.forum
+ @post.status = "normal"
+ end
+
+ if @user
+ @post.user = @user
+ else
+ if spam?
+ render :status => 403, :text => 'I am afraid I did not save your comment due to you are suspicously resembling a spambot being!'
+ return
+ end
+ end
+
+ if @post.save
+
+ if params[:image]
+ @post.images << Image.create(params[:image])
+ end
+
+
+ if @post.is_topic?
+ flash[:notice] = "Created topic #{@post.title}"
+ redirect_to category_post_url(@post.category, @post)
+ else
+ # saving topic to set updated_at to a proper value
+ @topic.save if @topic
+ flash[:notice] = "Commented on #{@topic.title}"
+ redirect_to :controller => 'posts', :action => 'show', :category_id => @post.category_id, :id => @topic, :anchor => "comment-#{@post.id}"
+ end
+
+ else
+
+ if @post.is_topic?
+ flash[:error] = "Could not create topic..."
+ @topic = @post;
+ render :action => 'new'
+ else
+ flash[:error] = "Could not save topic..."
+ redirect_to :controller => 'posts', :action => 'show', :category_id => @post.category_id, :id => @topic, :anchor => "comments"
+ end
+ end
+
+ end
+
+ def edit
+ @post = Post.find(params[:id])
+
+ # if current user does not have privileges to edit the post:
+ redirect_to category_post_url(@post.category, @post) if @post.user != @user
+ end
+
+ def update
+ @post = Post.find(params[:id])
+ @post.attributes = params[:post]
+ @post.edited_at = Time.now.utc
+ #@post.status = params[:status]
+
+ if @post.save
+ respond_to do |accepts|
+ accepts.html { flash[:notice] = "Successfully updated&hellip;"; redirect_to @post.is_topic? ? category_post_url(@post.category, @post) : category_post_url(:category_id => @post.category, :id => @post.topic, :anchor => "comment-#{@post.id}") }
+ accepts.js
+ end
+ else
+ respond_to do |accepts|
+ accepts.html { flash[:notice] = "Could not save your post&hellip;"; render :action => 'edit' }
+ accepts.js
+ end
+ end
+ end
+
+ def destroy
+ post = Post.find(params[:id])
+ post.destroy
+
+ if post.is_a? Topic
+ redirect_to category_url(post.category)
+ else
+ redirect_to category_post_url(post.category, post.topic)
+ end
+ end
+
+ private
+
+ def fetch_category
+ @category = Category.find(params[:category_id], :conditions => access_conditions)
+ end
+
+ def spam?
+ params[:verify][:nospam] != "on" or params[:verify][:spam] == "on"
+ end
+
+
+end
View
14 app/controllers/search_controller.rb
@@ -0,0 +1,14 @@
+class SearchController < ApplicationController
+
+ def posts
+
+ category_ids = Category.ids_matching(access_conditions)
+
+ @count = Post.connection.select_value("SELECT COUNT(*) FROM posts WHERE category_id IN (#{category_ids.join(",")}) AND title LIKE '%#{params[:q]}%' OR body LIKE '%#{params[:q]}%'").to_i
+
+ @result_pages = Paginator.new(self, @count, 15, params[:page])
+
+ @results = Search.query(params[:q], :categories => category_ids, :limit => 15, :page => params[:page])
+ render :action => 'results'
+ end
+end
View
8 app/controllers/tools_controller.rb
@@ -0,0 +1,8 @@
+class ToolsController < ApplicationController
+ skip_before_filter :login
+
+ def preview_textile
+ render :text => request.raw_post.to_html
+ end
+
+end
View
69 app/controllers/users_controller.rb
@@ -0,0 +1,69 @@
+class UsersController < ApplicationController
+ before_filter :require_admin, :only => [:create_user]
+
+ def show
+ @user_details = User.find(params[:id])
+ end
+
+ def list
+
+ conditions = nil
+ if params[:access]
+ conditions = ["level >= ?", params[:access].to_i]
+ end
+
+ @user_pages = Paginator.new(self, User.count(:all, :conditions => conditions), 50, params[:page])
+ @users = User.find(:all, :limit => 50, :offset => @user_pages.current.offset, :conditions => conditions, :order => "name ASC")
+ end
+
+
+ def update
+ @user_details = User.find(params[:id])
+
+ if params[:user][:level]
+ require_super_user
+ @user_details.level = params[:user][:level]
+ @user_details.save
+ render :update do |page|
+ page.call 'Flash.notice', "User <u>#{@user_details.name}</u> updated&hellip;"
+ end
+ elsif params[:user][:title]
+ require_super_user
+ @user_details.title = params[:user][:title]
+ @user_details.save
+ render :update do |page|
+ page.call 'Flash.notice', "User <u>#{@user_details.name}</u> updated&hellip;"
+ page.replace_html 'user-title-name', @user_details.title
+ page.call 'Opinion.togglePair', 'user-title', 'user-title-edit'
+ page.visual_effect :highlight, "user-title"
+ end
+ else
+ @user_details.attributes = params[:user]
+ if @user_details.save
+ flash[:notice] = "Updated your profile&hellip;"
+ redirect_to index_url
+ else
+ flash[:notice] = "Could not update your profile&hellip;"
+ render :action => 'show', :id => @user_details
+ end
+ end
+ end
+
+ def create_user
+ @newuser = User.build(params[:newuser])
+ case(params[:level])
+ when 'Moderator':
+ @newuser.level = 64
+ when 'Administrator':
+ @newuser.level = 128
+ else
+ @newuser.level = 0
+ end
+ @newuser.save
+ end
+
+ def gravatar
+ end
+
+
+end
View
3 app/helpers/accounts_helper.rb
@@ -0,0 +1,3 @@
+module AccountsHelper
+
+end
View
2 app/helpers/admin_accounts_helper.rb
@@ -0,0 +1,2 @@
+module AdminAccountsHelper
+end
View
7 app/helpers/admin_helper.rb
@@ -0,0 +1,7 @@
+module AdminHelper
+
+ def admin_levels
+ [["Superuser", 1024], ["Administrator", 128], ["Moderator", 64]]
+ end
+
+end
View
127 app/helpers/application_helper.rb
@@ -0,0 +1,127 @@
+# Methods added to this helper will be available to all templates in the application.
+module ApplicationHelper
+
+ def recent_date(date)
+ today = z(Time.now.utc)
+ date = z(date)
+
+ day = if date.to_date == today.to_date
+ '<span class="event-today">Today</span>'
+ elsif date.to_date == today.to_date - 1
+ '<span class="event-yesterday">Yesterday</span>'
+ else
+ date.strftime("%d. %b")
+ end
+
+ day
+ end
+
+ def ifchanged(item)
+ if item != @most_recent
+ @most_recent = item
+ item
+ end
+ end
+
+ def title(new_value = nil)
+ @title = new_value if new_value
+ @title
+ end
+
+ def crumb(title, link, options = nil)
+ @crumbs ||= []
+ @crumbs << link_to(title, link, options)
+ end
+
+ def breadcrumbs
+ @crumbs ||= []
+ @crumbs.join(" &raquo; ")
+ end
+
+ def gravatar_img(email, level)
+ require 'digest/md5'
+
+ "http://www.gravatar.com/avatar.php?gravatar_id=#{Digest::MD5.hexdigest(email)}&size=40"
+ end
+
+ def js_flash_notices
+ "Flash.notice('#{flash[:notice]}')" if flash[:notice]
+ end
+
+ def js_error_notices
+ "Flash.error('#{flash[:error]}')" if flash[:error]
+ end
+
+ def superuser?
+ @user and @user.level >= 1024
+ end
+
+ def admin?
+ @user and @user.level >= 128
+ end
+
+ def moderator?
+ @user and @user.level >= 64
+ end
+
+ def formatted_date(datetime)
+ now = z(Time.now.utc)
+ datetime = z(datetime)
+
+
+ if (time_diff = now - datetime) < 86400
+ return "Today, #{datetime.strftime('%I:%M%p')}"
+ elsif (time_diff = now - datetime) < 172800
+ return "Yesterday, #{datetime.strftime('%I:%M%p')}"
+ else
+ return datetime.strftime("%I:%M%p, %b %d, %G")
+ end
+ end
+
+ def datetime(date)
+ return "unknown" if date.nil?
+ date.strftime("%Y-%m-%d %I:%M%p")
+ end
+
+ def pagination_links(paginator, options={}, html_options={})
+ html = []
+
+ html << if paginator.current.previous
+ content_tag(:span, link_to("&laquo; Previous", params.update(:page => paginator.current.previous) ), :class => 'prev')
+ end
+
+ html << pagination_links_each(paginator, options) do |page|
+ html_options[:title] = "Go to Page #{page}"
+
+ link_to(page.to_s, params.update(:page => page), html_options)
+ end
+
+ html << if paginator.current.next
+ content_tag(:span, link_to("Next &raquo;", params.update(:page => paginator.current.next) ), :class => 'next')
+ end
+
+ content_tag :div, html.join, :id => 'pagination'
+ end
+
+ def row_class(name = 'generic')
+ variable_name = "@#{name.to_s.downcase.underscore.gsub(/\s/,"_")}_counter"
+ counter = instance_variable_get(variable_name)
+ counter ||= 0
+ counter += 1
+ instance_variable_set(variable_name, counter)
+ counter.even? ? "even" : "odd"
+ end
+
+ def sig(user)
+ "---<br /><p>#{h(user.signature).to_html}</p>" unless user.signature.blank?
+ end
+
+ def rss_feed_for_page
+ if @rss
+ "<link rel='alternate' type='application/rss+xml' title='RSS' href='#{@rss}' />"
+ else
+ ""
+ end
+ end
+
+end
View
3 app/helpers/categories_helper.rb
@@ -0,0 +1,3 @@
+module CategoriesHelper
+
+end
View
3 app/helpers/dashboard_helper.rb
@@ -0,0 +1,3 @@
+module DashboardHelper
+
+end
View
2 app/helpers/feeds_helper.rb
@@ -0,0 +1,2 @@
+module FeedsHelper
+end
View
2 app/helpers/forums_helper.rb
@@ -0,0 +1,2 @@
+module ForumsHelper
+end
View
2 app/helpers/images_helper.rb
@@ -0,0 +1,2 @@
+module ImagesHelper
+end
View
2 app/helpers/legacy_routes_helper.rb
@@ -0,0 +1,2 @@
+module LegacyRoutesHelper
+end
View
2 app/helpers/opinion_helper.rb
@@ -0,0 +1,2 @@
+module OpinionHelper
+end
View
10 app/helpers/posts_helper.rb
@@ -0,0 +1,10 @@
+module PostsHelper
+
+ def allowed_to_post?
+ if !@user and !@topic.forum.anonymous_posts
+ return false
+ end
+ true
+ end
+
+end
View
14 app/helpers/search_helper.rb
@@ -0,0 +1,14 @@
+module SearchHelper
+
+ def highlight_search_result(result)
+ highlight(excerpt(h(result.body), params[:q]), params[:q])
+ rescue ArgumentError
+ truncate(result.body, 100) rescue ''
+ end
+
+ def forum_link(forum)
+ return link_to forum.title, forum_url(forum) unless forum.nil?
+ "unknown forum"
+ end
+
+end
View
2 app/helpers/tools_helper.rb
@@ -0,0 +1,2 @@
+module ToolsHelper
+end
View
2 app/helpers/users_helper.rb
@@ -0,0 +1,2 @@
+module UsersHelper
+end
View
34 app/models/category.rb
@@ -0,0 +1,34 @@
+# == Schema Information
+# Schema version: 32
+#
+# Table name: categories
+#
+# id :integer(11) not null, primary key
+# title :string(255)
+# forum_id :integer(11)
+# body :text
+# body_html :text
+# subtitle :string(255)
+# access_level :integer(11) default(0)
+#
+
+class Category < ActiveRecord::Base
+ belongs_to :forum
+ before_save :transform_text
+ attr_protected :forum
+ has_many :topics, :dependent => :destroy
+ has_many :posts
+
+ def self.ids_matching(conditions)
+ Category.find(:all, :conditions => conditions, :select => 'id' ).collect(&:id)
+ end
+
+ # This will transform the original text to html output with tags using a filter
+ # like Redcloth
+ def transform_text
+ self.body_html = body.to_html if self.body
+ end
+
+ validates_uniqueness_of :title, :scope => :forum_id
+ validates_presence_of :title
+end
View
50 app/models/comment.rb
@@ -0,0 +1,50 @@
+# == Schema Information
+# Schema version: 32
+#
+# Table name: posts
+#
+# id :integer(11) not null, primary key
+# category_id :integer(11)
+# title :string(255)
+# body :text
+# body_html :text
+# user_id :integer(11)
+# created_at :datetime
+# type :string(255)
+# parent_id :integer(11)
+# forum_id :integer(11)
+# updated_at :datetime
+# status :string(255) default("normal")
+# edited_at :datetime
+#
+
+class Comment < Post
+ belongs_to :topic, :foreign_key => 'parent_id'
+
+ def feed_title
+ "#{author_name} commented on #{topic.title}"
+ end
+
+ def editable?
+ return false if self.topic.closed?
+ self.created_at > 3.days.ago
+ end
+
+ def topic_id
+ parent_id
+ end
+
+ def topic_title
+ topic.title
+ end
+
+ def author_name
+ user ? user.name : "Unknown User"
+ end
+
+ def anchor_name
+ "comment-#{id}"
+ end
+
+ validates_presence_of :body
+end
View
20 app/models/forum.rb
@@ -0,0 +1,20 @@
+# == Schema Information
+# Schema version: 32
+#
+# Table name: forums
+#
+# id :integer(11) not null, primary key
+# title :string(255)
+# anonymous_posts :boolean(1)
+# body :text
+#
+
+class Forum < ActiveRecord::Base
+ has_many :categories, :dependent => :destroy
+ has_many :posts
+
+ protected
+
+ validates_presence_of :title
+ validates_uniqueness_of :title
+end
View
26 app/models/image.rb
@@ -0,0 +1,26 @@
+# == Schema Information
+# Schema version: 32
+#
+# Table name: images
+#
+# id :integer(11) not null, primary key
+# parent_id :integer(11)
+# post_id :integer(11)
+# content_type :string(255)
+# filename :string(255)
+# thumbnail :string(255)
+# size :integer(11)
+# width :integer(11)
+# height :integer(11)
+#
+
+class Image < ActiveRecord::Base
+ has_attachment :content_type => :image,
+ :storage => :file_system,
+ :size => 0..1.megabyte,
+ :resize_to => '640x480>',
+ :path_prefix => 'public/files',
+ :thumbnails => { :thumb => '150x150>' }
+
+ validates_as_attachment
+end
View
61 app/models/post.rb
@@ -0,0 +1,61 @@
+# == Schema Information
+# Schema version: 32
+#
+# Table name: posts
+#
+# id :integer(11) not null, primary key
+# category_id :integer(11)
+# title :string(255)
+# body :text
+# body_html :text
+# user_id :integer(11)
+# created_at :datetime
+# type :string(255)
+# parent_id :integer(11)
+# forum_id :integer(11)
+# updated_at :datetime
+# status :string(255) default("normal")
+# edited_at :datetime
+#
+
+class Post < ActiveRecord::Base
+ before_save :transform_text, :replace_empty_title
+ belongs_to :user
+ belongs_to :forum
+ belongs_to :category
+ has_many :images, :conditions => 'parent_id IS NULL'
+
+ attr_protected :forum
+
+ def topic_title
+ title
+ end
+
+ def owner?(current_user)
+ self.user != nil and self.user == current_user
+ end
+
+ def is_topic?
+ self.class == Topic
+ end
+
+ def is_comment?
+ self.class == Comment
+ end
+
+ private
+
+ # Replaces an empty title with 'untitled'
+ def replace_empty_title
+ if self.title == ''
+ self.title = "untitled"
+ end
+ end
+
+ # This will transform the original text to html output with tags using a filter
+ # like Redcloth
+ def transform_text
+ self.body_html = body.to_html
+ end
+
+end
View
36 app/models/sql_like_query.rb
@@ -0,0 +1,36 @@
+class SqlLikeQuery
+
+ def query(q, options = {})
+ query = "%#{q}%"
+
+ page = options[:page] || 0
+ limit = options[:limit] || 20
+
+ sql = "(title LIKE ? OR body LIKE ?)"
+ params = [query, query]
+
+ if categories = options[:categories]
+ sql << " AND category_id IN (#{categories.join(",")}) "
+ end
+
+ if forum = options[:forum]
+ forum_id = forum.is_a?(ActiveRecord::Base) ? forum.id : forum.to_i
+ sql << " AND forum_id = #{forum_id}"
+ end
+
+ offset = options[:page] ? (page.to_i - 1) * limit.to_i : 0
+
+ Post.find(:all,
+ :conditions => [sql, *params],
+ :order => 'created_at DESC',
+ :limit => limit,
+ :offset => offset)
+ end
+
+ def rebuild_index
+ end
+
+ def index_post(post)
+ end
+
+end
View
62 app/models/topic.rb
@@ -0,0 +1,62 @@
+# == Schema Information
+# Schema version: 32
+#
+# Table name: posts
+#
+# id :integer(11) not null, primary key
+# category_id :integer(11)
+# title :string(255)
+# body :text
+# body_html :text
+# user_id :integer(11)
+# created_at :datetime
+# type :string(255)
+# parent_id :integer(11)
+# forum_id :integer(11)
+# updated_at :datetime
+# status :string(255) default("normal")
+# edited_at :datetime
+#
+
+class Topic < Post
+ belongs_to :user
+
+ has_many :comments, :foreign_key => 'parent_id', :order => 'created_at ASC', :dependent => :destroy
+
+ def feed_title
+ "#{title} by #{user.name}"
+ end
+
+ def topic_id
+ id
+ end
+
+ def author_name
+ user.name
+ end
+
+ def anchor_name
+ nil
+ end
+
+ def editable?
+ not closed?
+ end
+
+ def closed?
+ self.status == 'closed'
+ end
+
+ def has_admin_post?
+ admin_post_id
+ end
+
+ def admin_post_id
+ @admin_post_id ||= connection.select_value(
+ "SELECT posts.id FROM posts JOIN users ON users.level >= 128 AND users.id = posts.user_id WHERE posts.parent_id = #{id} OR posts.id = #{id}"
+ )
+ end
+
+ validates_presence_of :user, :message => "Only registered users are allowed to create new topics!"
+ validates_presence_of :body
+end
View
78 app/models/user.rb
@@ -0,0 +1,78 @@
+# == Schema Information
+# Schema version: 32
+#
+# Table name: users
+#
+# id :integer(11) not null, primary key
+# password :string(255)
+# name :string(255)
+# email :string(255)
+# url :string(255)
+# level :integer(11)
+# token :string(32)
+# title :string(255)
+# signature :text
+#
+
+class User < ActiveRecord::Base
+ has_many :posts, :dependent => :destroy
+ has_token :token
+
+ attr_protected :level, :title
+
+
+ cattr_accessor :levels
+ self.levels = {
+ 1024 => "Super User",
+ 128 => "Administrator",
+ 64 => "Moderator",
+ 0 => "Member"
+ }
+
+ def self.auth(email, password)
+ find_by_email_and_password(email, password)
+ end
+
+ def level_title
+ levels[level] || 'Member'
+ end
+
+ def moderator?
+ self.level >= 64
+ end
+
+ def admin?
+ self.level >= 128
+ end
+
+ def superuser?
+ self.level >= 1024
+ end
+
+ def url=(value)
+ case value
+ when nil, (value.empty?), /^(http|ssh|ed2k|feed|https|ftp|telnet|sftp)\:\/\//
+ super
+ else
+ super('http://' +value)
+ end
+ end
+
+ def post_count
+ connection.select_value("SELECT COUNT(*) FROM posts WHERE user_id = #{self.id}").to_i
+ end
+
+ def title
+ self[:title].blank? ? level_title : self[:title]
+ end
+
+ private
+
+ validates_uniqueness_of :email, :name
+ validates_presence_of :name
+ validates_presence_of :email
+ validates_presence_of :password
+ validates_format_of :email, :with => /.*?\@.*\..{2,4}/
+ validates_length_of :password, :minimum => 5, :message => "is too short (min 5 characters)"
+ validates_confirmation_of :password, :message => "password and confirmed password do not match!"
+end
View
14 app/models/user_mailer.rb
@@ -0,0 +1,14 @@
+class UserMailer < ActionMailer::Base
+
+ def recover(user, hostname, sent_at = Time.now)
+ @from = "Opinion Forum <opinion@#{hostname}>"
+ @subject = "Password retrieval"
+ @recipients = user.email
+ @headers = {}
+ @sent_on = sent_at
+
+ @body['user'] = user
+ end
+
+
+end
View
8 app/services/search.rb
@@ -0,0 +1,8 @@
+module Search
+ mattr_accessor :engine
+ @@engine = SqlLikeQuery.new
+
+ def self.query(string, options = {})
+ Search.engine.query(string, options)
+ end
+end
View
2 app/views/accounts/destroy.rjs
@@ -0,0 +1,2 @@
+page.call 'Flash.notice', "User <u>#{h @deleted_user.name}</u> removed&hellip;"
+page.visual_effect :puff, "user-#{@deleted_user.id}"
View
24 app/views/accounts/index.rhtml
@@ -0,0 +1,24 @@
+<% title "Login" %>
+
+<div class="account">
+ <%= form_tag accounts_url %>
+ <input type="hidden" name="return_to" value="<%= params[:return_to] %>" />
+ <dl style="margin: 15px 0">
+ <dt>
+ <label for="user_email">Email</label>
+ </dt>
+ <dd><%= text_field 'user', 'email' %></dd>
+
+ <dt>
+ <label for="user_password">Password</label>
+ <span class="hint"></span>
+ </dt>
+ <dd><%= password_field 'user', 'password' %></dd>
+ <dt></dt>
+ <dd><input type="checkbox" name="remember" id="remember" style="padding:0;margin:0"/> <label for="remember">Remember me on this computer!</label></dd>
+ </dl>
+ <input name="submit" type="submit" value="Login" /> or <%= link_to 'Cancel', index_url %>
+ </form>
+ <p>Don't have an account? <%= link_to 'Register here', accounts_url(:action => 'new') %> to get one!</p>
+ <div class="small" style="margin-top:15px"><%= link_to '(I forgot my password! Duh!)', :action => 'password_recovery' %></div>
+</div>
View
41 app/views/accounts/new.rhtml
@@ -0,0 +1,41 @@
+<% title "Register" %>
+
+<div class="account">
+ <%= error_messages_for :user %>
+ <% form_tag accounts_url(:action => 'create') do %>
+ <dl>
+ <dt>
+ <label for="user_email">Email address</label>
+ <span class="hint">please make sure that the address is valid and spelled right. This will be your login</span>
+ </dt>
+ <dd><%= text_field 'user', 'email' %></dd>
+
+ <dt>
+ <label for="user_name">Name</label>
+ <span class="hint">your name/nickname</span>
+ </dt>
+ <dd><%= text_field 'user', 'name' %></dd>
+
+ <dt>
+ <label for="user_url">Homepage</label>
+ <span class="hint">url of your webpage (optional)</span>
+ </dt>
+ <dd><%= text_field 'user', 'url' %></dd>
+
+ <dt>
+ <label for="user_password">Password</label>
+ <span class="hint"></span>
+ </dt>
+ <dd><%= password_field 'user', 'password' %></dd>
+
+ <dt>
+ <label for="user_password_confirmation">Confirmation</label>
+ <span class="hint">please enter your password again</span>
+ </dt>
+ <dd><%= password_field 'user', 'password_confirmation' %></dd>
+
+ <dd><%= recaptcha_tags %></dd>
+ </dl>
+ <%= submit_tag 'Create account', :disable_with => 'Creating account&hellip;' %> or <%= link_to 'Cancel', index_url %>
+ <% end %>
+</div>
View
14 app/views/accounts/password_recovery.rhtml
@@ -0,0 +1,14 @@
+<% title "Lost your password?" %>
+
+<div class="account">
+ <%= form_remote_tag :url => (accounts_url(:action => 'password_recovery')) %>
+ <dl style="margin: 15px 0">
+ <dt>
+ <label for="user_email">Please give us your email address</label>
+ <span class="hint"></span>
+ </dt>
+ <dd><%= text_field 'user', 'email' %></dd>
+ </dl>
+ <input name="submit" type="submit" value="Send" /> or <%= link_to 'Cancel', index_url %>
+ </form>
+</div>
View
50 app/views/admin/_new_user.rhtml
@@ -0,0 +1,50 @@
+<div id="create-user">
+
+ <h1>Create a new User</h1>
+ <p>Create a new &hellip;</p>
+
+ <% form_remote_for :newuser, :url => { :action => 'create_user' } do |user| %>
+ <dl>
+
+ <dt>
+ <label for="user_email">User Type</label>
+ <span class="hint">(Superuser, Administrator or Moderator)</span>
+ </dt>
+ <dd><%= user.select 'level', admin_levels %></dd>
+
+ <dt>
+ <label for="user_email">Email address</label>
+ <span class="hint">This will be the login</span>
+ </dt>
+ <dd><%= user.text_field :email %></dd>
+
+ <dt>
+ <label for="user_name">Name</label>
+ <span class="hint">name/screenname/nickname</span>
+ </dt>
+ <dd><%= user.text_field :name %></dd>
+
+ <dt>
+ <label for="user_url">Homepage</label>
+ <span class="hint">url of that user's webpage (optional)</span>
+ </dt>
+ <dd><%= user.text_field :url %></dd>
+
+ <dt>
+ <label for="user_password">Password</label>
+ <span class="hint"></span>
+ </dt>
+ <dd><%= user.password_field :password %></dd>
+
+ <dt>
+ <label for="user_password_confirmation">Confirmation</label>
+ <span class="hint">please enter the password again</span>
+ </dt>
+ <dd><%= user.password_field :password_confirmation %></dd>
+ </dl>
+
+ <%= submit_tag 'Create' %> or <%= link_to_function 'Cancel', "Dialog.close()" %>
+
+ <% end %>
+
+</div>
View
12 app/views/admin/_user_li.rhtml
@@ -0,0 +1,12 @@
+<li id="user-<%= user_li.id %>" class="user">
+
+ <div class="user-img">
+ <img src="<%= gravatar_img(user_li.email,user_li.level) %>" />
+ </div>
+
+ <div class="user-info">
+ <p><%= h user_li.name %></p>
+ <p class="small"><%= h user_li.email %></p>
+ <p class="right-float"><%= link_to_remote image_tag('/images/trash.gif'), :url => {:controller => 'accounts', :action => 'destroy', :id => user_li.id}, :confirm => "Do you want to remove the user \"#{h user_li.name}\"?" %></p>
+ </div>
+</li>
View
20 app/views/admin/create_user.rjs
@@ -0,0 +1,20 @@
+if @newuser.valid?
+ page.call "Dialog.close"
+
+ case @newuser.level
+ when 1024:
+ page.insert_html :bottom, 'superuser-list', :partial => 'user_li', :object => @newuser
+ when 128:
+ page.insert_html :bottom, 'administrator-list', :partial => 'user_li', :object => @newuser
+ when 64:
+ page.insert_html :bottom, 'moderator-list', :partial => 'user_li', :object => @newuser
+ end
+
+
+ page.visual_effect :highlight, "user-#{@newuser.id}", :duration => 5
+ page << "$('user_email').value = '';$('user_name').value = '';$('user_url').value = '';$('user_password').value = '';$('user_password_confirmation').value = '';"
+ page.call 'Flash.notice', "Successfully created Admin: <u>#{h @newuser.name}</u>"
+else
+ page.visual_effect :shake, 'create-user'
+ page.call 'Flash.error', "Can't create user: <u>#{@newuser.errors.full_messages.first}</u>"
+end
View
69 app/views/admin/index.rhtml
@@ -0,0 +1,69 @@
+<% title "Administration" %>
+
+<% crumb "Home", index_url %>
+
+<div class="wrapper">
+
+ <h2>Super User</h2>
+
+ <ul id="superuser-list" class="user-list">
+ <% @superusers.each do |user| %>
+ <li id="user-<%= user.id %>" class="user">
+ <div class="user-img">
+ <img src="<%= gravatar_img(user.email,user.level) %>" />
+ </div>
+
+ <div class="user-info">
+ <p class="fr sr"><%= link_to_remote image_tag('/images/trash.gif'), :url => {:controller => 'accounts', :action => 'destroy', :id => user.id}, :confirm => "Do you want to remove the user \"#{h user.name}\"?" if user != session[:user] %></p>
+ <h3><%= link_to h(user.name), :controller => 'users', :action => 'show', :id => user.id %></h3>
+ <p class="small"><%= h user.email %></p>
+ </div>
+ </li>
+ <% end %>
+ </ul>
+
+ <h2 class="clear admin-heading">Administrators</h2>
+
+ <ul id="administrator-list" class="user-list">
+ <% @admins.each do |user| %>
+ <li id="user-<%= user.id %>" class="user">
+ <div class="user-img">
+ <img src="<%= gravatar_img(user.email,user.level) %>" />
+ </div>
+
+ <div class="user-info">
+ <p class="fr sr"><%= link_to_remote image_tag('/images/trash.gif'), :url => {:controller => 'accounts', :action => 'destroy', :id => user.id}, :confirm => "Do you want to remove the user \"#{h user.name}\"?" %></p>
+ <h3><%= link_to h(user.name), :controller => 'users', :action => 'show', :id => user.id %></h3>
+ <p class="small"><%= h user.email %></p>
+
+ </div>
+ </li>
+ <% end %>
+ </ul>
+
+
+ <h2 class="clear admin-heading">Moderators</h2>
+
+ <ul id="moderator-list" class="user-list">
+ <% @moderators.each do |user| %>
+ <li id="user-<%= user.id %>" class="user">
+ <div class="user-img">
+ <img src="<%= gravatar_img(user.email,user.level) %>" />
+ </div>
+
+ <div class="user-info">
+ <p class="fr sr"><%= link_to_remote image_tag('/images/trash.gif'), :url => {:controller => 'accounts', :action => 'destroy', :id => user.id}, :confirm => "Do you want to remove the user \"#{h user.name}\"?" %></p>
+ <h3><%= link_to h(user.name), :controller => 'users', :action => 'show', :id => user.id %></h3>
+ <p class="small"><%= h user.email %></p>
+ </div>
+ </li>
+ <% end %>
+ </ul>
+
+
+ <p class="clear"><%= link_to_function "Create new", "new Dialog('create-user', '/admin/new_user/')" %></p>
+</div>
+
+
+<div id="create-user" style="display:none">
+</div>
View
46 app/views/categories/_categories_table.rhtml
@@ -0,0 +1,46 @@
+<table id="category-list" class="data" cellpadding="0" cellspacing="0">
+ <tr>
+ <th class="l">Title</th>
+ <th>Topics</th>
+ <th>Posts</th>
+ <th>&nbsp;</th>
+ </tr>
+
+ <% @categories.each do |category| %>
+ <tr id="category-<%= category.id %>" class="category <%= row_class %>">
+ <td id="category-name-<%= category.id %>">
+
+ <h4><%= link_to category.title, category_url(category) %></h4>
+ <div class="subtitle">
+ <%= category.subtitle %>
+ </div>
+ </td>
+
+ <td id="rename-category-form-<%= category.id %>" style="display:none">
+ <% form_remote_for :category, category, :url => rename_category_url(category), :html => {:method => :put} do |c| %>
+
+ <%= c.text_field 'title', :size => 12 %> Title <br />
+ <%= c.text_field 'subtitle' %> Subtitle <br />
+ <%= c.text_field 'access_level', :size => 4 %> Access Level <br />
+
+ <input name="submit" type="submit" value="Submit" /> or <%= link_to_function 'Cancel', "Opinion.cancelRenameElement(#{category.id}, 'category')" %>
+ <% end %>
+ </td>
+
+
+ <td class="c"><%= category.topics.count %></td>
+ <td class="c"><%= category.posts.count %></td>
+
+ <td class="r">
+ <% if admin? %>
+ <span class="orange-link">
+ <%= link_to_function 'edit', "Opinion.renameElement(#{category.id}, 'category')" %>
+ |
+ <%= link_to_remote image_tag('trash.gif'), :url => category_url(category), :method => :delete, :confirm => "Do you want to remove the category \"#{category.title}\"?" %>
+ </span>
+ <% end %>
+ </td>
+ </tr>
+
+ <% end %>
+</table>
View
6 app/views/categories/_edit.rhtml
@@ -0,0 +1,6 @@
+<h4>Edit category description</h4>
+<% form_remote_for :category, @category, :url => category_url(@category), :html => {:method => :put} do |category| %>
+ <%= category.text_area 'body' %>
+ <%= submit_tag 'Save' %> or <%= link_to_function 'Cancel', "Dialog.close()" %>
+<% end %>
+
View
9 app/views/categories/create.rjs
@@ -0,0 +1,9 @@
+if @category.valid?
+ page.replace 'category-list', :partial => 'categories_table', :object => @categories
+ page.visual_effect :highlight, "category-#{@category.id}", :duration => 5
+ page.hide 'add-category'
+ page.call 'Flash.notice', "New category <u>#{@category.title}</u> created&hellip;"
+else
+ page.visual_effect :shake, 'add-category'
+ page.call 'Flash.error', "Can't save category: <u>#{@category.errors.full_messages.first}</u>"
+end
View
2 app/views/categories/destroy.rjs
@@ -0,0 +1,2 @@
+page.call 'Flash.notice', "Category <u>#{@category.title}</u> deleted&hellip;"
+page.visual_effect :puff, "category-#{@category.id}"
View
8 app/views/categories/rename.rjs
@@ -0,0 +1,8 @@
+if @category.valid?
+ page.replace 'category-list', :partial => 'categories_table', :object => @categories
+ page.visual_effect :highlight, "category-#{@category.id}", :duration => 1
+ page.call 'Flash.notice', "Category title renamed to <u>#{@category.title}</u>&hellip;"
+else
+ page.visual_effect :shake, "rename-category-form-#{@category.id}"
+ page.call 'Flash.error', "Can't save category: <u>#{@category.errors.full_messages.first}</u>"
+end
View
57 app/views/categories/show.rhtml
@@ -0,0 +1,57 @@
+<% title @category.title %>
+
+<% crumb "Home", index_url %>
+<% crumb @category.forum.title, forum_url(@category.forum) %>
+<% crumb @category.title, category_url(@category), :class => 'active' %>
+
+<div class="wrapper fl">
+
+ <h2><span class="feed-link"><%= link_to image_tag('/images/rss.png'), formatted_category_url(@category, 'xml') %></span> Topics</h2>
+
+
+ <% if @user %>
+ <div class="orange-link">
+ <p><%= link_to "Create a new topic", new_category_post_url(@category) %></p>
+ </div>
+ <% end %>
+
+ <table id="topic-list" class="data" cellpadding="0" cellspacing="0">
+ <tr>
+ <th class="l">Title</th>
+ <th class="l">Author</th>