Skip to content
Browse files

Initial Open N2 commit

  • Loading branch information...
0 parents commit 7753c3a72a57930d1ca797dc664acfc2a0f93716 Russell committed
Showing with 8,246 additions and 0 deletions.
  1. +37 −0 .gitignore
  2. +3 −0 Capfile
  3. +251 −0 README
  4. +10 −0 Rakefile
  5. +68 −0 app/controllers/admin/featured_items_controller.rb
  6. +48 −0 app/controllers/admin/idea_boards_controller.rb
  7. +49 −0 app/controllers/admin/ideas_controller.rb
  8. +48 −0 app/controllers/admin/users_controller.rb
  9. +36 −0 app/controllers/admin/widgets_controller.rb
  10. +29 −0 app/controllers/admin_controller.rb
  11. +106 −0 app/controllers/application_controller.rb
  12. +33 −0 app/controllers/articles_controller.rb
  13. +32 −0 app/controllers/comments_controller.rb
  14. +2 −0 app/controllers/events_controller.rb
  15. +82 −0 app/controllers/home_controller.rb
  16. +29 −0 app/controllers/idea_boards_controller.rb
  17. +83 −0 app/controllers/ideas_controller.rb
  18. +8 −0 app/controllers/mobile/comments_controller.rb
  19. +15 −0 app/controllers/mobile/home_controller.rb
  20. +50 −0 app/controllers/mobile/stories_controller.rb
  21. +39 −0 app/controllers/newswires_controller.rb
  22. +73 −0 app/controllers/resources_controller.rb
  23. +39 −0 app/controllers/sessions_controller.rb
  24. +86 −0 app/controllers/stories_controller.rb
  25. +77 −0 app/controllers/users_controller.rb
  26. +107 −0 app/helpers/admin_helper.rb
  27. +206 −0 app/helpers/application_helper.rb
  28. +2 −0 app/helpers/articles_helper.rb
  29. +2 −0 app/helpers/comments_helper.rb
  30. +2 −0 app/helpers/events_helper.rb
  31. +2 −0 app/helpers/home_helper.rb
  32. +2 −0 app/helpers/idea_boards_helper.rb
  33. +2 −0 app/helpers/ideas_helper.rb
  34. +2 −0 app/helpers/newswires_helper.rb
  35. +2 −0 app/helpers/resources_helper.rb
  36. +2 −0 app/helpers/sessions_helper.rb
  37. +2 −0 app/helpers/stories_helper.rb
  38. +93 −0 app/helpers/users_helper.rb
  39. +8 −0 app/models/article.rb
  40. +6 −0 app/models/comment.rb
  41. +49 −0 app/models/content.rb
  42. +3 −0 app/models/content_image.rb
  43. +17 −0 app/models/event.rb
  44. +16 −0 app/models/featured_item.rb
  45. +3 −0 app/models/feed.rb
  46. +19 −0 app/models/idea.rb
  47. +13 −0 app/models/idea_board.rb
  48. +7 −0 app/models/message.rb
  49. +5 −0 app/models/message_observer.rb
  50. +3 −0 app/models/newswire.rb
  51. +12 −0 app/models/notifier.rb
  52. +17 −0 app/models/resource.rb
  53. +174 −0 app/models/user.rb
  54. +3 −0 app/models/user_info.rb
  55. +29 −0 app/models/vote.rb
  56. +11 −0 app/models/vote_observer.rb
  57. +5 −0 app/models/widget.rb
  58. +21 −0 app/models/widget_page.rb
  59. +39 −0 app/sweepers/story_sweeper.rb
  60. +13 −0 app/views/admin/featured_items/_load_items.html.haml
  61. +208 −0 app/views/admin/featured_items/index.html.haml
  62. +1 −0 app/views/admin/featured_items/load_items.html.haml
  63. +2 −0 app/views/admin/featured_items/load_items.js.haml
  64. +45 −0 app/views/admin/featured_items/load_template.html.haml
  65. +5 −0 app/views/admin/idea_boards/_idea_board_form.html.haml
  66. +5 −0 app/views/admin/idea_boards/edit.html.haml
  67. +2 −0 app/views/admin/idea_boards/index.html.haml
  68. +6 −0 app/views/admin/idea_boards/new.html.haml
  69. +4 −0 app/views/admin/idea_boards/show.html.haml
  70. +6 −0 app/views/admin/ideas/_idea_form.html.haml
  71. +5 −0 app/views/admin/ideas/edit.html.haml
  72. +1 −0 app/views/admin/ideas/index.html.haml
  73. +6 −0 app/views/admin/ideas/new.html.haml
  74. +1 −0 app/views/admin/ideas/show.html.haml
  75. +1 −0 app/views/admin/index.html.haml
  76. +8 −0 app/views/admin/users/_user_form.html.haml
  77. +6 −0 app/views/admin/users/edit.html.haml
  78. +1 −0 app/views/admin/users/index.html.haml
  79. +6 −0 app/views/admin/users/new.html.haml
  80. +18 −0 app/views/admin/users/show.html.haml
  81. +174 −0 app/views/admin/widgets/index.html.haml
  82. +7 −0 app/views/articles/_article_form.fbml.haml
  83. +7 −0 app/views/articles/_article_form.html.haml
  84. +12 −0 app/views/articles/new.fbml.haml
  85. +12 −0 app/views/articles/new.html.haml
  86. +2 −0 app/views/home/about.fbml.haml
  87. +2 −0 app/views/home/about.html.haml
  88. +7 −0 app/views/home/app_tab.fbml.haml
  89. +9 −0 app/views/home/contact_us.fbml.haml
  90. +9 −0 app/views/home/contact_us.html.haml
  91. +2 −0 app/views/home/faq.fbml.haml
  92. +2 −0 app/views/home/faq.html.haml
  93. +10 −0 app/views/home/index.fbml.haml
  94. +10 −0 app/views/home/index.html.haml
  95. +2 −0 app/views/home/terms.fbml.haml
  96. +2 −0 app/views/home/terms.html.haml
  97. +12 −0 app/views/home/test_widgets.html.haml
  98. +9 −0 app/views/idea_boards/index.fbml.haml
  99. +9 −0 app/views/idea_boards/index.html.haml
  100. +27 −0 app/views/idea_boards/show.fbml.haml
  101. +27 −0 app/views/idea_boards/show.html.haml
  102. +10 −0 app/views/ideas/index.fbml.haml
  103. +10 −0 app/views/ideas/index.html.haml
  104. +9 −0 app/views/ideas/my_ideas.fbml.haml
  105. +9 −0 app/views/ideas/my_ideas.html.haml
  106. +28 −0 app/views/ideas/new.fbml.haml
  107. +28 −0 app/views/ideas/new.html.haml
  108. +37 −0 app/views/ideas/show.fbml.haml
  109. +37 −0 app/views/ideas/show.html.haml
  110. +48 −0 app/views/layouts/admin.html.haml
  111. +23 −0 app/views/layouts/application.fbml.haml
  112. +29 −0 app/views/layouts/application.html.haml
  113. +55 −0 app/views/layouts/mobile.html.haml
  114. +73 −0 app/views/layouts/new_admin.html.haml
  115. +11 −0 app/views/mobile/comments/show.html.haml
  116. +44 −0 app/views/mobile/home/index.html.haml
  117. +20 −0 app/views/mobile/stories/_story_form.html.haml
  118. +9 −0 app/views/mobile/stories/index.html.haml
  119. +9 −0 app/views/mobile/stories/new.html.haml
  120. +10 −0 app/views/mobile/stories/show.html.haml
  121. +14 −0 app/views/newswires/index.fbml.haml
  122. +14 −0 app/views/newswires/index.html.haml
  123. +6 −0 app/views/notifier/contact_us_message.haml
  124. +10 −0 app/views/resources/_subnav.fbml.haml
  125. +10 −0 app/views/resources/_subnav.html.haml
  126. +10 −0 app/views/resources/index.fbml.haml
  127. +10 −0 app/views/resources/index.html.haml
  128. +9 −0 app/views/resources/my_resources.fbml.haml
  129. +9 −0 app/views/resources/my_resources.html.haml
  130. +19 −0 app/views/resources/new.fbml.haml
  131. +20 −0 app/views/resources/new.html.haml
  132. +32 −0 app/views/resources/show.fbml.haml
  133. +32 −0 app/views/resources/show.html.haml
  134. +12 −0 app/views/sessions/new.fbml.erb
  135. +19 −0 app/views/sessions/new.html.erb
  136. +3 −0 app/views/shared/_ads_banner.fbml.haml
  137. +3 −0 app/views/shared/_ads_banner.html.haml
  138. +9 −0 app/views/shared/_comment.fbml.haml
  139. +9 −0 app/views/shared/_comment.html.haml
  140. +15 −0 app/views/shared/_comment_form.fbml.haml
  141. +15 −0 app/views/shared/_comment_form.html.haml
  142. +11 −0 app/views/shared/_comments.fbml.haml
  143. +11 −0 app/views/shared/_comments.html.haml
  144. +1 −0 app/views/shared/_fb_strings.fbml.haml
  145. +28 −0 app/views/shared/_featured_items.fbml.haml
  146. +28 −0 app/views/shared/_featured_items.html.haml
  147. +22 −0 app/views/shared/_footer.fbml.haml
  148. +22 −0 app/views/shared/_footer.html.haml
  149. +17 −0 app/views/shared/_google_ads.fbml.haml
  150. +16 −0 app/views/shared/_google_ads.html.haml
  151. +11 −0 app/views/shared/_google_analytics.html.haml
  152. +23 −0 app/views/shared/_header.fbml.haml
  153. +24 −0 app/views/shared/_header.html.haml
  154. +18 −0 app/views/shared/_idea_boards.fbml.haml
  155. +18 −0 app/views/shared/_idea_boards.html.haml
  156. +18 −0 app/views/shared/_ideas.fbml.haml
  157. +18 −0 app/views/shared/_ideas.html.haml
  158. +3 −0 app/views/shared/_login_req_dialog.fbml.haml
  159. +13 −0 app/views/shared/_page_tabs.fbml.haml
  160. +15 −0 app/views/shared/_page_tabs.html.haml
  161. +17 −0 app/views/shared/_resources.fbml.haml
  162. +18 −0 app/views/shared/_resources.html.haml
  163. +27 −0 app/views/shared/_stories.fbml.haml
  164. +27 −0 app/views/shared/_stories.html.haml
  165. +13 −0 app/views/shared/feed_items/_article.fbml.haml
  166. +13 −0 app/views/shared/feed_items/_article.html.haml
  167. +12 −0 app/views/shared/feed_items/_comment.fbml.haml
  168. +12 −0 app/views/shared/feed_items/_comment.html.haml
  169. +13 −0 app/views/shared/feed_items/_story.fbml.haml
  170. +13 −0 app/views/shared/feed_items/_story.html.haml
  171. +9 −0 app/views/shared/feed_items/_vote.fbml.haml
  172. +9 −0 app/views/shared/feed_items/_vote.html.haml
  173. +10 −0 app/views/shared/sidebar/_bio.fbml.haml
  174. +10 −0 app/views/shared/sidebar/_bio.html.haml
  175. +12 −0 app/views/shared/sidebar/_ideas_list.fbml.haml
  176. +12 −0 app/views/shared/sidebar/_ideas_list.html.haml
  177. +6 −0 app/views/shared/sidebar/_ideas_whatisthis.fbml.haml
  178. +6 −0 app/views/shared/sidebar/_ideas_whatisthis.html.haml
  179. +13 −0 app/views/shared/sidebar/_newest_users.fbml.haml
  180. +13 −0 app/views/shared/sidebar/_newest_users.html.haml
  181. +9 −0 app/views/shared/sidebar/_other_posts.fbml.haml
  182. +9 −0 app/views/shared/sidebar/_other_posts.html.haml
  183. +3 −0 app/views/shared/sidebar/_resources_ads_banner.fbml.haml
  184. +3 −0 app/views/shared/sidebar/_resources_ads_banner.html.haml
  185. +12 −0 app/views/shared/sidebar/_resources_list.fbml.haml
  186. +12 −0 app/views/shared/sidebar/_resources_list.html.haml
  187. +2 −0 app/views/shared/sidebar/_resources_search.fbml.haml
  188. +7 −0 app/views/shared/sidebar/_resources_search.html.haml
  189. +6 −0 app/views/shared/sidebar/_resources_whatisthis.fbml.haml
  190. +6 −0 app/views/shared/sidebar/_resources_whatisthis.html.haml
  191. +12 −0 app/views/shared/sidebar/_top_discussed_stories.fbml.haml
  192. +12 −0 app/views/shared/sidebar/_top_discussed_stories.html.haml
  193. +12 −0 app/views/shared/sidebar/_top_stories.fbml.haml
  194. +12 −0 app/views/shared/sidebar/_top_stories.html.haml
  195. +14 −0 app/views/shared/sidebar/_top_users.fbml.haml
  196. +14 −0 app/views/shared/sidebar/_top_users.html.haml
  197. +12 −0 app/views/shared/subnav/_idea_boards_subnav.fbml.haml
  198. +12 −0 app/views/shared/subnav/_idea_boards_subnav.html.haml
  199. +9 −0 app/views/shared/subnav/_ideas_subnav.fbml.haml
  200. +9 −0 app/views/shared/subnav/_ideas_subnav.html.haml
  201. +6 −0 app/views/shared/tags
  202. +6 −0 app/views/stories/_story_form.fbml.haml
  203. +7 −0 app/views/stories/_story_form.html.haml
  204. +12 −0 app/views/stories/index.atom.builder
  205. +6 −0 app/views/stories/index.fbml.haml
  206. +8 −0 app/views/stories/index.html.haml
  207. +12 −0 app/views/stories/new.fbml.haml
  208. +12 −0 app/views/stories/new.html.haml
  209. +35 −0 app/views/stories/show.fbml.haml
  210. +35 −0 app/views/stories/show.html.haml
  211. +8 −0 app/views/stories/tags.fbml.haml
  212. +8 −0 app/views/stories/tags.html.haml
  213. +9 −0 app/views/users/invite.fbml.haml
  214. +9 −0 app/views/users/invite.html.haml
  215. +25 −0 app/views/users/new.fbml.erb
  216. +25 −0 app/views/users/new.html.erb
  217. +12 −0 app/views/users/show.atom.builder
  218. +98 −0 app/views/users/show.fbml.haml
  219. +98 −0 app/views/users/show.html.haml
  220. +59 −0 config/application.god.sample
  221. +50 −0 config/application_settings.yml.sample
  222. +110 −0 config/boot.rb
  223. +7 −0 config/cucumber.yml
  224. +62 −0 config/database.yml.sample
  225. +63 −0 config/deploy.rb
  226. +6 −0 config/deploy/sample.rb
  227. +74 −0 config/environment.rb
  228. +30 −0 config/environments/cucumber.rb
  229. +17 −0 config/environments/development.rb
  230. +28 −0 config/environments/production.rb
  231. +17 −0 config/environments/staging.rb
  232. +30 −0 config/environments/test.rb
  233. +49 −0 config/facebooker.yml.sample
  234. +4 −0 config/initializers/001_application_settings.rb
  235. +7 −0 config/initializers/backtrace_silencers.rb
  236. +51 −0 config/initializers/formtastic.rb
  237. +5 −0 config/initializers/hoptoad.rb
  238. +10 −0 config/initializers/inflections.rb
  239. +4 −0 config/initializers/locale.rb
  240. +5 −0 config/initializers/mime_types.rb
  241. +21 −0 config/initializers/new_rails_defaults.rb
  242. +15 −0 config/initializers/session_store.rb
  243. +38 −0 config/initializers/site_keys.rb
  244. +5 −0 config/locales/defaults/en.yml
  245. +138 −0 config/locales/defaults/fr.yml
  246. +6 −0 config/locales/en.yml
  247. +35 −0 config/locales/forms/en.yml
  248. +28 −0 config/locales/forms/fr.yml
  249. +4 −0 config/locales/views/articles/en.yml
  250. +4 −0 config/locales/views/articles/fr.yml
  251. +24 −0 config/locales/views/idea_boards/en.yml
  252. +25 −0 config/locales/views/ideas/en.yml
  253. +7 −0 config/locales/views/newswires/en.yml
  254. +7 −0 config/locales/views/newswires/fr.yml
  255. +26 −0 config/locales/views/resources/en.yml
  256. +8 −0 config/locales/views/sessions/en.yml
  257. +8 −0 config/locales/views/sessions/fr.yml
  258. +70 −0 config/locales/views/shared/en.yml
  259. +18 −0 config/locales/views/shared/feed_items/en.yml
  260. +18 −0 config/locales/views/shared/feed_items/fr.yml
  261. +48 −0 config/locales/views/shared/fr.yml
  262. +34 −0 config/locales/views/shared/sidebar/en.yml
  263. +14 −0 config/locales/views/shared/sidebar/fr.yml
  264. +12 −0 config/locales/views/shared/subnav/en.yml
  265. +12 −0 config/locales/views/stories/en.yml
  266. +12 −0 config/locales/views/stories/fr.yml
  267. +22 −0 config/locales/views/users/en.yml
  268. +22 −0 config/locales/views/users/fr.yml
  269. +10 −0 config/mongrel_cluster.yml.sample
  270. +212 −0 config/newrelic.yml.sample
  271. +101 −0 config/routes.rb
  272. +35 −0 config/smtp.yml.sample
  273. +78 −0 config/unicorn.conf.rb
  274. +29 −0 config/widgets.yml
  275. +1,103 −0 db/development_structure.sql
  276. +31 −0 db/migrate/20091124161003_convert_user_table.rb
  277. +27 −0 db/migrate/20091124162312_add_users_table_columns.rb
  278. +15 −0 db/migrate/20091124182343_convert_content_table.rb
  279. +11 −0 db/migrate/20091124190738_convert_content_images_table.rb
  280. +19 −0 db/migrate/20091124204325_convert_user_info_table.rb
  281. +19 −0 db/migrate/20091124231957_convert_comments_table.rb
  282. +21 −0 db/migrate/20091201224354_vote_fu_migration.rb
  283. +11 −0 db/migrate/20091202012039_add_timestamps_to_comments.rb
  284. +16 −0 db/migrate/20091202064956_create_sessions.rb
  285. +11 −0 db/migrate/20091203014546_switch_content_timestamps.rb
  286. +17 −0 db/migrate/20091203204959_update_feeds_table.rb
  287. +12 −0 db/migrate/20091203210908_update_newswire_table.rb
  288. +14 −0 db/migrate/20091208012226_create_articles.rb
  289. +9 −0 db/migrate/20091208013109_add_article_id_to_contents.rb
  290. +15 −0 db/migrate/20091222010834_add_messages_table.rb
  291. +18 −0 db/migrate/20100103205822_create_slugs.rb
  292. +11 −0 db/migrate/20100103215300_delete_blank_users.rb
  293. +9 −0 db/migrate/20100103220246_add_cached_slug_to_users.rb
  294. +9 −0 db/migrate/20100103220337_add_cached_slug_to_contents.rb
  295. +23 −0 db/migrate/20100107182956_convert_ideas_table.rb
  296. +19 −0 db/migrate/20100109003023_create_resources.rb
  297. +9 −0 db/migrate/20100111222056_add_karma_score_to_users.rb
  298. +11 −0 db/migrate/20100112011238_update_user_timestamps.rb
  299. +30 −0 db/migrate/20100113182120_acts_as_taggable_on_migration.rb
  300. +21 −0 db/migrate/20100114002308_create_widgets.rb
Sorry, we could not display the entire diff because too many files (3,590) changed.
37 .gitignore
@@ -0,0 +1,37 @@
+public/uploads
+public/cache/*
+tmp
+.DS_Store
+public/system
+public/javascripts/cache
+public/stylesheets/cache
+coverage
+*.log
+*.bak
+script/pids
+.*.swp
+.*.swo
+config/*.yml
+config/application.god
+!config/newrelic.yml
+!config/widgets.yml
+!config/cucumber.yml
+config/deploy/*.rb
+!config/deploy/sample.rb
+*.pid
+ical
+db/*.db
+db/*.sqlite3
+config/initializers/your_site_host.rb
+config/initializers/google_analytics.rb
+coverage.data
+spec/controllers
+spec/views
+spec/helpers
+._*
+.sass-cache
+config/s3.yml
+*.sql
+!db/development_structure.sql
+spec/fixtures
+*.tmproj
3 Capfile
@@ -0,0 +1,3 @@
+load 'deploy' if respond_to?(:namespace) # cap2 differentiator
+Dir['vendor/plugins/*/recipes/*.rb'].each { |plugin| load(plugin) }
+load 'config/deploy' # remove this line to skip loading any of the default tasks
251 README
@@ -0,0 +1,251 @@
+== Welcome to N2
+
+N2 is the latest and greatest iteration of the Newscloud framework.
+
+
+== Getting Started
+
+1. Clone this application to your machine
+2. copy config/database.yml.sample to config/database.yml and configure your db.
+3. copy config/facebooker.yml.sample to config/facebook.yml and configure your facebook app.
+4. copy config/application_settings.yml.sample to config/application_settings.yml.
+This is your base config file where you set your site specific options related to the framework.
+4.b (optional)
+If you wish to configure outgoing email, copy config/smtp.yml.sample to config/smtp.yml
+and configure your outgoing mail settings. Google hosted email is supported!
+4.c (optional) There are also a number of *.yml.sample files in the config directory for advanced use.
+5. Next check that the gems are setup properly by running
+ rake gems
+If you don't see any error messages then you are good to go. You might have to run:
+ sudo rake gems:build
+ or
+ sudo rake gems:install
+to build the native extensions for some of the gems.
+6. Build the database
+If you have an existing newscloud application you would like to port over, run:
+rake n2:db:convert_and_create_database
+This will prompt you for the old database info and will migrate to the new database.
+This will _not_ harm your existing database, it will create a new database for rails
+and perform the conversions there, leaving your existing application intact.
+If you do not have an existing application you want to convert, simply run:
+rake db:setup
+and this will build the database for you.
+7. Now start the server with:
+ ruby script/server
+and you should be up and running
+8. Next you need to configure the admin interface.
+If you are converting an existing newscloud framework, and you already have
+an admin user account, you can login and access the admin interface just fine.
+As long as there are no existing admin users, there will be a default login account for you to use, which is configurable in your application_settings.yml file.
+By default the admin user is 'admin' and the password is 'n2adminpassword' and you will be prompted for that login when you reach the admin interface.
+First, you need to create a normal account, and then login into the admin interface with the default credentials. From there you can edit your user account and set the is_admin field to true, and then you will have direct access.
+(Optional): You may also now goto the featured items section of the admin interface and select featured items for the home page.
+
+
+== Web Servers
+
+By default, Rails will try to use Mongrel if it's are installed when started with script/server, otherwise Rails will use WEBrick, the webserver that ships with Ruby. But you can also use Rails
+with a variety of other web servers.
+
+Mongrel is a Ruby-based webserver with a C component (which requires compilation) that is
+suitable for development and deployment of Rails applications. If you have Ruby Gems installed,
+getting up and running with mongrel is as easy as: <tt>gem install mongrel</tt>.
+More info at: http://mongrel.rubyforge.org
+
+Say other Ruby web servers like Thin and Ebb or regular web servers like Apache or LiteSpeed or
+Lighttpd or IIS. The Ruby web servers are run through Rack and the latter can either be setup to use
+FCGI or proxy to a pack of Mongrels/Thin/Ebb servers.
+
+== Apache .htaccess example for FCGI/CGI
+
+# General Apache options
+AddHandler fastcgi-script .fcgi
+AddHandler cgi-script .cgi
+Options +FollowSymLinks +ExecCGI
+
+# If you don't want Rails to look in certain directories,
+# use the following rewrite rules so that Apache won't rewrite certain requests
+#
+# Example:
+# RewriteCond %{REQUEST_URI} ^/notrails.*
+# RewriteRule .* - [L]
+
+# Redirect all requests not available on the filesystem to Rails
+# By default the cgi dispatcher is used which is very slow
+#
+# For better performance replace the dispatcher with the fastcgi one
+#
+# Example:
+# RewriteRule ^(.*)$ dispatch.fcgi [QSA,L]
+RewriteEngine On
+
+# If your Rails application is accessed via an Alias directive,
+# then you MUST also set the RewriteBase in this htaccess file.
+#
+# Example:
+# Alias /myrailsapp /path/to/myrailsapp/public
+# RewriteBase /myrailsapp
+
+RewriteRule ^$ index.html [QSA]
+RewriteRule ^([^.]+)$ $1.html [QSA]
+RewriteCond %{REQUEST_FILENAME} !-f
+RewriteRule ^(.*)$ dispatch.cgi [QSA,L]
+
+# In case Rails experiences terminal errors
+# Instead of displaying this message you can supply a file here which will be rendered instead
+#
+# Example:
+# ErrorDocument 500 /500.html
+
+ErrorDocument 500 "<h2>Application error</h2>Rails application failed to start properly"
+
+
+== Debugging Rails
+
+Sometimes your application goes wrong. Fortunately there are a lot of tools that
+will help you debug it and get it back on the rails.
+
+First area to check is the application log files. Have "tail -f" commands running
+on the server.log and development.log. Rails will automatically display debugging
+and runtime information to these files. Debugging info will also be shown in the
+browser on requests from 127.0.0.1.
+
+You can also log your own messages directly into the log file from your code using
+the Ruby logger class from inside your controllers. Example:
+
+ class WeblogController < ActionController::Base
+ def destroy
+ @weblog = Weblog.find(params[:id])
+ @weblog.destroy
+ logger.info("#{Time.now} Destroyed Weblog ID ##{@weblog.id}!")
+ end
+ end
+
+The result will be a message in your log file along the lines of:
+
+ Mon Oct 08 14:22:29 +1000 2007 Destroyed Weblog ID #1
+
+More information on how to use the logger is at http://www.ruby-doc.org/core/
+
+Also, Ruby documentation can be found at http://www.ruby-lang.org/ including:
+
+* The Learning Ruby (Pickaxe) Book: http://www.ruby-doc.org/docs/ProgrammingRuby/
+* Learn to Program: http://pine.fm/LearnToProgram/ (a beginners guide)
+
+These two online (and free) books will bring you up to speed on the Ruby language
+and also on programming in general.
+
+
+== Debugger
+
+Debugger support is available through the debugger command when you start your Mongrel or
+Webrick server with --debugger. This means that you can break out of execution at any point
+in the code, investigate and change the model, AND then resume execution!
+You need to install ruby-debug to run the server in debugging mode. With gems, use 'gem install ruby-debug'
+Example:
+
+ class WeblogController < ActionController::Base
+ def index
+ @posts = Post.find(:all)
+ debugger
+ end
+ end
+
+So the controller will accept the action, run the first line, then present you
+with a IRB prompt in the server window. Here you can do things like:
+
+ >> @posts.inspect
+ => "[#<Post:0x14a6be8 @attributes={\"title\"=>nil, \"body\"=>nil, \"id\"=>\"1\"}>,
+ #<Post:0x14a6620 @attributes={\"title\"=>\"Rails you know!\", \"body\"=>\"Only ten..\", \"id\"=>\"2\"}>]"
+ >> @posts.first.title = "hello from a debugger"
+ => "hello from a debugger"
+
+...and even better is that you can examine how your runtime objects actually work:
+
+ >> f = @posts.first
+ => #<Post:0x13630c4 @attributes={"title"=>nil, "body"=>nil, "id"=>"1"}>
+ >> f.
+ Display all 152 possibilities? (y or n)
+
+Finally, when you're ready to resume execution, you enter "cont"
+
+
+== Console
+
+You can interact with the domain model by starting the console through <tt>script/console</tt>.
+Here you'll have all parts of the application configured, just like it is when the
+application is running. You can inspect domain models, change values, and save to the
+database. Starting the script without arguments will launch it in the development environment.
+Passing an argument will specify a different environment, like <tt>script/console production</tt>.
+
+To reload your controllers and models after launching the console run <tt>reload!</tt>
+
+== dbconsole
+
+You can go to the command line of your database directly through <tt>script/dbconsole</tt>.
+You would be connected to the database with the credentials defined in database.yml.
+Starting the script without arguments will connect you to the development database. Passing an
+argument will connect you to a different database, like <tt>script/dbconsole production</tt>.
+Currently works for mysql, postgresql and sqlite.
+
+== Description of Contents
+
+app
+ Holds all the code that's specific to this particular application.
+
+app/controllers
+ Holds controllers that should be named like weblogs_controller.rb for
+ automated URL mapping. All controllers should descend from ApplicationController
+ which itself descends from ActionController::Base.
+
+app/models
+ Holds models that should be named like post.rb.
+ Most models will descend from ActiveRecord::Base.
+
+app/views
+ Holds the template files for the view that should be named like
+ weblogs/index.html.erb for the WeblogsController#index action. All views use eRuby
+ syntax.
+
+app/views/layouts
+ Holds the template files for layouts to be used with views. This models the common
+ header/footer method of wrapping views. In your views, define a layout using the
+ <tt>layout :default</tt> and create a file named default.html.erb. Inside default.html.erb,
+ call <% yield %> to render the view using this layout.
+
+app/helpers
+ Holds view helpers that should be named like weblogs_helper.rb. These are generated
+ for you automatically when using script/generate for controllers. Helpers can be used to
+ wrap functionality for your views into methods.
+
+config
+ Configuration files for the Rails environment, the routing map, the database, and other dependencies.
+
+db
+ Contains the database schema in schema.rb. db/migrate contains all
+ the sequence of Migrations for your schema.
+
+doc
+ This directory is where your application documentation will be stored when generated
+ using <tt>rake doc:app</tt>
+
+lib
+ Application specific libraries. Basically, any kind of custom code that doesn't
+ belong under controllers, models, or helpers. This directory is in the load path.
+
+public
+ The directory available for the web server. Contains subdirectories for images, stylesheets,
+ and javascripts. Also contains the dispatchers and the default HTML files. This should be
+ set as the DOCUMENT_ROOT of your web server.
+
+script
+ Helper scripts for automation and generation.
+
+test
+ Unit and functional tests along with fixtures. When using the script/generate scripts, template
+ test files will be generated for you and placed in this directory.
+
+vendor
+ External libraries that the application depends on. Also includes the plugins subdirectory.
+ If the app has frozen rails, those gems also go here, under vendor/rails/.
+ This directory is in the load path.
10 Rakefile
@@ -0,0 +1,10 @@
+# Add your own tasks in files placed in lib/tasks ending in .rake,
+# for example lib/tasks/capistrano.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'
68 app/controllers/admin/featured_items_controller.rb
@@ -0,0 +1,68 @@
+class Admin::FeaturedItemsController < AdminController
+ skip_before_filter :admin_user_required
+ layout proc {|c| c.request.xhr? ? false : "new_admin" }
+ before_filter :set_featured_types, :only => :load_template
+
+ def index
+ end
+
+ def load_template
+ return false unless params[:id] =~ /^template_[0-9]+$/
+
+ @template_id = params[:id]
+ end
+
+ def load_items
+ case params[:id]
+ when Content.name.tableize
+ @items = Content.paginate :page => params[:page], :per_page => 12, :order => "created_at desc"
+ when Idea.name.tableize
+ @items = Idea.paginate :page => params[:page], :per_page => 12, :order => "created_at desc"
+ else
+ return false
+ end
+ end
+
+ def save
+ FeaturedItem.all.each {|fi| fi.destroy}
+
+ data = ActiveSupport::JSON.decode(params['featured_items'])
+ @template_name = FeaturedItem.create({:name => 'featured_template', :featured_type => data['template']})
+ @section1 = @template_name.children.create({:name => "section1", :featured_type => "section1"})
+ @section2 = @template_name.children.create({:name => "section2", :featured_type => "section2"})
+ ['section1', 'section2'].each do |section|
+ section_data = instance_variable_get("@#{section}")
+ ['primary', 'secondary1', 'secondary2'].each do |box|
+ item_id = data[section][box]
+ next unless item = get_item(item_id)
+ item = get_item item_id
+ section_data.children.create({:name => "item_#{item_id}", :featured_type => "featured_item", :featurable => item})
+ end
+ end
+
+ render :json => {:success => "Success!"}.to_json and return
+ end
+
+ private
+
+ def get_item item
+ return false unless item and item =~ /^([^_]+)_([0-9]+)$/
+ case $1
+ when 'content'
+ return Content.find_by_id($2)
+ when 'idea'
+ return Idea.find_by_id($2)
+ else
+ return false
+ end
+ end
+
+ def set_featured_types
+ @featurables ||= [['Stories', 'contents'], ['Ideas', 'ideas']]
+ end
+
+ def set_current_tab
+ @current_tab = 'featured-items';
+ end
+
+end
48 app/controllers/admin/idea_boards_controller.rb
@@ -0,0 +1,48 @@
+class Admin::IdeaBoardsController < AdminController
+ skip_before_filter :admin_user_required
+
+ def index
+ @idea_boards = IdeaBoard.paginate :page => params[:page], :per_page => 20, :order => "created_at desc"
+ end
+
+ def new
+ @idea_board = IdeaBoard.new
+ end
+
+ def edit
+ @idea_board = IdeaBoard.find(params[:id])
+ end
+
+ def update
+ @idea_board = IdeaBoard.find(params[:id])
+ if @idea_board.update_attributes(params[:idea_board])
+ flash[:success] = "Successfully updated your Idea Board."
+ redirect_to [:admin, @idea_board]
+ else
+ flash[:error] = "Could not update your Idea Board as requested. Please try again."
+ render :edit
+ end
+ end
+
+ def show
+ @idea_board = IdeaBoard.find(params[:id])
+ end
+
+ def create
+ @idea_board = IdeaBoard.new(params[:idea_board])
+ if @idea_board.save
+ flash[:success] = "Successfully created your new Idea Board!"
+ redirect_to [:admin, @idea_board]
+ else
+ flash[:error] = "Could not create your Idea Board, please try again"
+ render :new
+ end
+ end
+
+ private
+
+ def set_current_tab
+ @current_tab = 'idea-boards';
+ end
+
+end
49 app/controllers/admin/ideas_controller.rb
@@ -0,0 +1,49 @@
+class Admin::IdeasController < AdminController
+ skip_before_filter :admin_user_required
+
+ def index
+ @ideas = Idea.paginate :page => params[:page], :per_page => 20, :order => "created_at desc"
+ end
+
+ def new
+ @idea = Idea.new
+ end
+
+ def edit
+ @idea = Idea.find(params[:id])
+ end
+
+ def update
+ @idea = Idea.find(params[:id])
+ if @idea.update_attributes(params[:idea])
+ flash[:success] = "Successfully updated your Idea ."
+ redirect_to [:admin, @idea]
+ else
+ flash[:error] = "Could not update your Idea as requested. Please try again."
+ render :edit
+ end
+ end
+
+ def show
+ @idea = Idea.find(params[:id])
+ end
+
+ def create
+ @idea = Idea.new(params[:idea])
+ @idea.user = current_user
+ if @idea.save
+ flash[:success] = "Successfully created your new Idea !"
+ redirect_to [:admin, @idea]
+ else
+ flash[:error] = "Could not create your Idea , please try again"
+ render :new
+ end
+ end
+
+ private
+
+ def set_current_tab
+ @current_tab = 'ideas';
+ end
+
+end
48 app/controllers/admin/users_controller.rb
@@ -0,0 +1,48 @@
+class Admin::UsersController < AdminController
+ skip_before_filter :admin_user_required
+
+ def index
+ @users = User.paginate :page => params[:page], :per_page => 20, :order => "created_at desc"
+ end
+
+ def new
+ @user = User.new
+ end
+
+ def edit
+ @user = User.find(params[:id])
+ end
+
+ def update
+ @user = User.find(params[:id])
+ if @user.update_attributes(params[:user])
+ flash[:success] = "Successfully updated your User."
+ redirect_to [:admin, @user]
+ else
+ flash[:error] = "Could not update your User as requested. Please try again."
+ render :edit
+ end
+ end
+
+ def show
+ @user = User.find(params[:id])
+ end
+
+ def create
+ @user = User.new(params[:user])
+ if @user.save
+ flash[:success] = "Successfully created your new User!"
+ redirect_to [:admin, @user]
+ else
+ flash[:error] = "Could not create your User, please try again"
+ render :new
+ end
+ end
+
+ private
+
+ def set_current_tab
+ @current_tab = 'users';
+ end
+
+end
36 app/controllers/admin/widgets_controller.rb
@@ -0,0 +1,36 @@
+class Admin::WidgetsController < AdminController
+ skip_before_filter :admin_user_required
+
+ def index
+ @main = Widget.main
+ @sidebar = Widget.sidebar
+ end
+
+ def save
+ # TODO:: Switch to updating instead of deleting
+ WidgetPage.all.each {|w| w.destroy}
+ @main = params[:main].split /,/
+ @sidebar = params[:sidebar].split /,/
+
+ @home_page = WidgetPage.create({:name => 'home'})
+ @main_content = @home_page.children.create({:name => "home_main_content", :widget_type => "main_content"})
+ @sidebar_content = @home_page.children.create({:name => "home_sidebar_content", :widget_type => "sidebar_content"})
+ @main.each do |widget_id|
+ widget = Widget.find_by_id(widget_id)
+ @main_content.children.create({:name => "home_#{widget.name}_widget", :widget => widget, :widget_type => "widget"})
+ end
+ @sidebar.each do |widget_id|
+ widget = Widget.find_by_id(widget_id)
+ @sidebar_content.children.create({:name => "home_#{widget.name}_widget", :widget => widget, :widget_type => "widget"})
+ end
+
+ render :json => {:success => "Success!"}.to_json and return
+ end
+
+ private
+
+ def set_current_tab
+ @current_tab = 'widgets';
+ end
+
+end
29 app/controllers/admin_controller.rb
@@ -0,0 +1,29 @@
+class AdminController < ApplicationController
+ layout proc {|c| c.request.xhr? ? false : "new_admin" }
+
+ before_filter :check_admin_or_default_status
+ before_filter :set_current_tab
+
+ def index
+ #redirect_to admin_contents_path
+ end
+
+ private
+
+ def set_current_tab
+ @current_tab = 'dashboard'
+ end
+
+ def check_admin_or_default_status
+ return true if current_user and current_user.is_admin?
+
+ if User.find_admin_users.empty?
+ authenticate_or_request_with_http_basic do |username, password|
+ username == APP_CONFIG['default_admin_user'] and password == APP_CONFIG['default_admin_password']
+ end
+ else
+ redirect_to home_index_path and return false
+ end
+ end
+
+end
106 app/controllers/application_controller.rb
@@ -0,0 +1,106 @@
+class ApplicationController < ActionController::Base
+
+ include AuthenticatedSystem
+
+ helper :all # include all helpers, all the time
+ #protect_from_forgery # See ActionController::RequestForgeryProtection for details
+
+ before_filter :set_current_tab
+ before_filter :set_current_sub_tab
+ before_filter :set_locale
+
+ #facebook settings
+ # TODO:: get this working
+ #ensure_application_is_installed_by_facebook_user
+ #ensure_authenticated_to_facebook
+ #To prevent a violation of Facebook Terms of Service while reducing log bloat, you should also add
+ filter_parameter_logging :fb_sig_friends
+
+
+ # Scrub sensitive parameters from your log
+ filter_parameter_logging :password
+
+ before_filter :set_facebook_session
+ helper_method :facebook_session
+
+ def set_current_tab
+ @current_tab = false
+ end
+
+ def set_current_sub_tab
+ @current_sub_tab = false
+ end
+
+ def load_top_stories
+ @top_stories ||= Content.tally({
+ :at_least => 1,
+ :limit => 5,
+ :order => "votes.count desc"
+ })
+ end
+
+ def load_top_users
+ @top_users ||= User.top
+ end
+
+ def load_contents
+ @contents ||= Content.find(:all, :limit => 10, :order => "created_at desc")
+ end
+
+ def load_newest_users
+ @newest_users ||= User.newest
+ end
+
+ def load_top_discussed_stories
+ @most_discussed_stories ||= Content.find( :all,
+ :limit => 5,
+ :order => "comments_count desc"
+ )
+ end
+
+ def load_top_ideas
+ @top_ideas ||= Idea.tally({
+ :at_least => 1,
+ :limit => 5,
+ :order => "votes.count desc"
+ })
+ end
+
+ def load_featured_items
+ @featured_items ||= FeaturedItem.find_root_by_item_name('featured_template')
+ end
+
+ def load_newest_ideas
+ @newest_ideas ||= Idea.newest 5
+ end
+
+ def load_top_resources
+ @top_resources ||= Resource.tally({
+ :at_least => 1,
+ :limit => 5,
+ :order => "votes.count desc"
+ })
+ end
+
+ def load_newest_resources
+ @newest_resources ||= Resource.newest 5
+ end
+
+ def set_locale
+ locale = params[:locale] || cookies[:locale] || I18n.default_locale
+ I18n.locale = locale.to_s
+ cookies[:locale] = locale unless (cookies[:locale] && cookies[:locale] == locale)
+ end
+
+ def default_url_options(options={})
+ format = options[:format] || request.format.to_sym
+ { :locale => I18n.locale,
+ :format => format
+ }
+ end
+
+ def tag_cloud(item)
+ @tags = item.tag_counts_on(:tags)
+ end
+
+end
33 app/controllers/articles_controller.rb
@@ -0,0 +1,33 @@
+class ArticlesController < ApplicationController
+ before_filter :set_current_tab
+ before_filter :login_required, :only => [:new, :create]
+ before_filter :load_top_stories, :only => [:index]
+ before_filter :load_top_discussed_stories, :only => [:index]
+
+ def new
+ @article = Article.new
+ @article.build_content
+ end
+
+ def create
+ @article = Article.new(params[:article])
+ @article.content = Content.new(params[:article][:content_attributes].merge(:article => @article))
+ @article.content.caption = @article.body
+ @article.author = current_user
+ @article.content.user = current_user
+ if @article.save
+ flash[:success] = "Successfully posted your story!"
+ redirect_to story_path(@article.content)
+ else
+ flash[:error] = "Could not create your article. Please fix the errors and try again."
+ render :new
+ end
+ end
+
+ private
+
+ def set_current_tab
+ @current_tab = 'stories'
+ end
+
+end
32 app/controllers/comments_controller.rb
@@ -0,0 +1,32 @@
+class CommentsController < ApplicationController
+ before_filter :login_required, :only => [:create]
+ cache_sweeper :story_sweeper, :only => [:create, :update, :destroy]
+
+ def create
+ @commentable = find_commentable
+ @comment = @commentable.comments.build(params[:comment])
+ @comment.user = current_user
+ if @comment.save
+ # TODO:: change this to work with polymorphic associations, switch to using touch
+ #expire_page :controller => 'stories', :action => 'show', :id => @story
+ redirect_to @commentable
+ else
+ redirect_to @commentable
+ end
+ end
+
+ private
+
+ def find_commentable
+ params.each do |name, value|
+ next if name =~ /^fb/
+ if name =~ /(.+)_id$/
+ # switch story requests to use the content model
+ klass = $1 == 'story' ? 'content' : $1
+ return klass.classify.constantize.find(value)
+ end
+ end
+ nil
+ end
+
+end
2 app/controllers/events_controller.rb
@@ -0,0 +1,2 @@
+class EventsController < ApplicationController
+end
82 app/controllers/home_controller.rb
@@ -0,0 +1,82 @@
+class HomeController < ApplicationController
+ caches_page :index, :google_ads
+
+ before_filter :set_current_tab
+ before_filter :load_top_stories, :only => [:index, :app_tab]
+ before_filter :load_featured_items, :only => [:index, :app_tab]
+ before_filter :load_top_discussed_stories, :only => [:index, :app_tab]
+ before_filter :load_top_users, :only => [:index, :app_tab]
+ before_filter :load_newest_users, :only => [:index, :app_tab]
+
+ def index
+ expires_in 1.minutes, :private => false, :public => true
+ @no_paginate = true
+ @contents = Content.paginate :page => params[:page], :per_page => 10, :order => "created_at desc"
+ respond_to do |format|
+ format.html
+ format.fbml
+ end
+ end
+
+ def app_tab
+ @no_paginate = true
+ @contents = Content.find(:all, :limit => 10, :order => "created_at desc")
+ end
+
+ def google_ads
+ render :partial => 'shared/google_ads.html.haml', :layout => false
+ end
+
+ def about
+ end
+
+ def faq
+ end
+
+ def terms
+ end
+
+ def contact_us
+ if request.post?
+ @message = Message.new(params[:message])
+ @message.user = current_user if current_user.present?
+
+ if @message.save
+ flash[:notice] = "Thank you for contacting us, your input is appreciated."
+ redirect_to root_path
+ else
+ flash[:error] = "There was an error while processing your request. Please try again."
+ end
+ else
+ @message = Message.new
+ @message.email = current_user.email if current_user.present? and current_user.email.present?
+ end
+ end
+
+ def test_widgets
+ @featured_items = FeaturedItem.find_root_by_item_name('featured_template')
+ controller = self
+ @page = WidgetPage.find_root_by_page_name('home')
+ @main = @page.children.first.children
+ @sidebar = @page.children.second.children
+ @main.each {|w| controller.send(w.widget.load_functions) if w.widget.load_functions.present? }
+ @sidebar.each {|w| controller.send(w.widget.load_functions) if w.widget.load_functions.present? }
+ end
+
+ def render_widget
+ @no_paginate = true
+ controller = self
+ @widget = Widget.find_by_id(params[:id])
+ controller.send @widget.load_functions if @widget.load_functions.present?
+ locals = @widget.locals.present? ? { @widget.locals.to_sym => instance_variable_get("@#{@widget.locals}") } : {}
+
+ render :partial => @widget.partial, :locals => locals and return
+ end
+
+ private
+
+ def set_current_tab
+ @current_tab = 'home'
+ end
+
+end
29 app/controllers/idea_boards_controller.rb
@@ -0,0 +1,29 @@
+class IdeaBoardsController < ApplicationController
+ before_filter :set_current_tab
+ before_filter :login_required, :only => [:new, :create, :update]
+ before_filter :load_top_ideas, :only => :index
+ before_filter :load_newest_ideas, :only => :index
+
+ def index
+ @current_sub_tab = 'Browse Idea Boards'
+ @idea_boards = IdeaBoard.paginate :page => params[:page], :per_page => 10, :order => "created_at desc"
+ end
+
+ def show
+ @current_sub_tab = 'Browse Board Ideas'
+ @idea_board = IdeaBoard.find(params[:id])
+ @top_ideas = @idea_board.ideas.tally({
+ :at_least => 1,
+ :limit => 5,
+ :order => "votes.count desc"
+ })
+ @newest_ideas = @idea_board.ideas.newest 5
+ end
+
+ private
+
+ def set_current_tab
+ @current_tab = 'ideas'
+ end
+
+end
83 app/controllers/ideas_controller.rb
@@ -0,0 +1,83 @@
+class IdeasController < ApplicationController
+ before_filter :set_current_tab
+ before_filter :login_required, :only => [:new, :create, :update]
+ before_filter :load_top_ideas
+ before_filter :load_newest_ideas
+ before_filter :set_idea_board
+
+ def index
+ @current_sub_tab = 'Browse Ideas'
+ @ideas = Idea.newest
+ end
+
+ def new
+ @current_sub_tab = 'Suggest Idea'
+ @idea = Idea.new
+ @idea.idea_board = @idea_board if @idea_board.present?
+ @ideas = Idea.newest
+ end
+
+ def create
+ @idea = Idea.new(params[:idea])
+ @idea.user = current_user
+ @idea.tag_list = params[:idea][:tags_string]
+ if params[:idea][:idea_board_id].present?
+ @idea_board = IdeaBoard.find_by_id(params[:idea][:idea_board_id])
+ @idea.section_list = @idea_board.section unless @idea_board.nil?
+ end
+
+ if @idea.save
+ flash[:success] = "Thank you for your idea!"
+ redirect_to @idea_board.present? ? [@idea_board, @idea] : @idea
+ else
+ @ideas = Idea.newest
+ render :new
+ end
+ end
+
+ def show
+ @idea = Idea.find(params[:id])
+ tag_cloud @idea
+ end
+
+ # TODO:: fb comments method
+ def commented
+ render :text => "Commented" and return
+ end
+
+ def my_ideas
+ @current_sub_tab = 'My Ideas'
+ @user = User.find(params[:id])
+ @ideas = @user.ideas
+ end
+
+ def like
+ @idea = Idea.find_by_id(params[:id])
+ respond_to do |format|
+ if current_user and @idea.present? and current_user.vote_for(@idea)
+ success = "Thanks for your vote!"
+ format.html { flash[:success] = success; redirect_to params[:return_to] || ideas_path }
+ format.fbml { flash[:success] = success; redirect_to params[:return_to] || ideas_path }
+ format.json { render :json => { :msg => "#{@idea.votes.size} likes" }.to_json }
+ format.fbjs { render :json => { :msg => "#{@idea.votes.size} likes" }.to_json }
+ else
+ error = "Vote failed"
+ format.html { flash[:error] = error; redirect_to params[:return_to] || ideas_path }
+ format.fbml { flash[:error] = error; redirect_to params[:return_to] || ideas_path }
+ format.json { render :json => { :msg => error }.to_json }
+ format.fbjs { render :text => { :msg => error }.to_json }
+ end
+ end
+ end
+
+ private
+
+ def set_idea_board
+ @idea_board = params[:idea_board_id].present? ? IdeaBoard.find(params[:idea_board_id]) : nil
+ end
+
+ def set_current_tab
+ @current_tab = 'ideas'
+ end
+
+end
8 app/controllers/mobile/comments_controller.rb
@@ -0,0 +1,8 @@
+class Mobile::CommentsController < ApplicationController
+ layout proc{ |c| c.request.xhr? ? false : "mobile" }
+
+ def show
+ @comment = Comment.find(params[:id])
+ end
+
+end
15 app/controllers/mobile/home_controller.rb
@@ -0,0 +1,15 @@
+class Mobile::HomeController < ApplicationController
+ layout proc{ |c| c.request.xhr? ? false : "mobile" }
+
+ def index
+ @stories = Content.find(:all, :limit => 10, :order => "created_at desc")
+ @top_stories = Content.tally({
+ :at_least => 1,
+ :limit => 10,
+ :order => "votes.count desc"
+ })
+ @comments = Comment.newest(10)
+ @likes = Vote.newest(10)
+ end
+
+end
50 app/controllers/mobile/stories_controller.rb
@@ -0,0 +1,50 @@
+class Mobile::StoriesController < ApplicationController
+ layout proc{ |c| c.request.xhr? ? false : "mobile" }
+
+ before_filter :set_current_tab
+ #before_filter :login_required, :only => [:like, :new, :create]
+ #before_filter :load_top_stories, :only => [:index]
+
+ def index
+ @contents = Content.find(:all, :limit => 10, :order => "created_at desc")
+ end
+
+ def show
+ @story = Content.find(params[:id])
+ end
+
+ def new
+ @story = Content.new
+ end
+
+ def create
+ @story = Content.new(params[:content])
+ @story.user = current_user
+ if params[:content][:image_url].present?
+ @story.build_content_image({:url => params[:content][:image_url]})
+ end
+ if @story.save
+ flash[:success] = "Successfully posted your story!"
+ redirect_to story_path(@story)
+ else
+ flash[:error] = @story.errors.full_messages
+ render :new
+ end
+ end
+
+ def like
+ @story = Content.find(params[:id])
+ if current_user and @story.present?
+ current_user.vote_for(@story)
+ end
+
+ redirect_to params[:return_to] || stories_path
+ end
+
+ private
+
+ def set_current_tab
+ @current_tab = 'stories'
+ end
+
+end
39 app/controllers/newswires_controller.rb
@@ -0,0 +1,39 @@
+class NewswiresController < ApplicationController
+ before_filter :set_current_tab
+ before_filter :login_required, :only => [:publish]
+ before_filter :load_top_stories, :only => [:index]
+
+ def index
+ @newswires = Newswire.find(:all, :order => "updated_at desc", :limit => 20)
+ end
+
+ def publish
+ @newswire = Newswire.find_by_id(params[:id])
+ redirect_to newswire_path and return if @newswire.nil?
+
+ @content = Content.new({
+ :title => @newswire.title,
+ :caption => @newswire.caption,
+ :url => @newswire.url,
+ :source => @newswire.feed.title,
+ :user => current_user
+ })
+ unless @newswire.imageUrl.nil? or @newswire.imageUrl.empty?
+ @content.build_content_image({ :url => @newswire.imageUrl })
+ end
+ if @content.save
+ flash[:success] = "Thanks for posting a story!"
+ redirect_to story_path(@content)
+ else
+ flash[:error] = "Could not publish your story. Please try again."
+ redirect_to newswire_path
+ end
+ end
+
+ private
+
+ def set_current_tab
+ @current_tab = 'newswire'
+ end
+
+end
73 app/controllers/resources_controller.rb
@@ -0,0 +1,73 @@
+class ResourcesController < ApplicationController
+ before_filter :set_current_tab
+ before_filter :login_required, :only => [:new, :create, :update]
+ before_filter :load_top_resources
+ before_filter :load_newest_resources
+
+ def index
+ @current_sub_tab = 'Browse Resources'
+ @resources = Resource.top
+ end
+
+ def new
+ @current_sub_tab = 'Suggest Resource'
+ @resource = Resource.new
+ @resources = Resource.newest
+ end
+
+ def create
+ @resource = Resource.new(params[:resource])
+ @resource.user = current_user
+ @resource.tag_list = params[:resource][:tags_string]
+
+ if @resource.save
+ flash[:success] = "Thank you for adding to our directory!"
+ redirect_to resource_path(@resource)
+ else
+ @resources = Resource.newest
+ render :new
+ end
+ end
+
+ def show
+ @resource = Resource.find(params[:id])
+ tag_cloud @resource
+ end
+
+ def commented
+ #raise params.inspect
+ render :text => "Commented" and return
+ end
+
+ def my_resources
+ @current_sub_tab = 'My Resources'
+ @user = User.find(params[:id])
+ @resources = @user.resources
+ end
+
+ def like
+ @resource = Resource.find_by_id(params[:id])
+ respond_to do |format|
+ if current_user and @resource.present? and current_user.vote_for(@resource)
+ success = "Thanks for your vote!"
+ format.html { flash[:success] = success; redirect_to params[:return_to] || resources_path }
+ format.fbml { flash[:success] = success; redirect_to params[:return_to] || resources_path }
+ format.json { render :json => { :msg => "#{@resource.votes.size} likes" }.to_json }
+ format.fbjs { render :json => { :msg => "#{@resource.votes.size} likes" }.to_json }
+ else
+ error = "Vote failed"
+ format.html { flash[:error] = error; redirect_to params[:return_to] || resources_path }
+ format.fbml { flash[:error] = error; redirect_to params[:return_to] || resources_path }
+ format.json { render :json => { :msg => error }.to_json }
+ format.fbjs { render :text => { :msg => error }.to_json }
+ end
+ end
+ end
+
+ private
+
+ def set_current_tab
+ @current_tab = 'resources'
+ end
+
+end
39 app/controllers/sessions_controller.rb
@@ -0,0 +1,39 @@
+class SessionsController < ApplicationController
+
+ def new
+ end
+
+ def create
+ logout_keeping_session!
+ user = User.authenticate(params[:login], params[:password])
+ if user
+ # Protects against session fixation attacks, causes request forgery
+ # protection if user resubmits an earlier form using back
+ # button. Uncomment if you understand the tradeoffs.
+ # reset_session
+ self.current_user = user
+ new_cookie_flag = (params[:remember_me] == "1")
+ handle_remember_cookie! new_cookie_flag
+ redirect_back_or_default(root_path)
+ flash[:notice] = "Logged in successfully"
+ else
+ note_failed_signin
+ @login = params[:login]
+ @remember_me = params[:remember_me]
+ render :action => 'new'
+ end
+ end
+
+ def destroy
+ logout_killing_session!
+ flash[:notice] = "You have been logged out."
+ redirect_back_or_default(root_path)
+ end
+
+protected
+ # Track failed login attempts
+ def note_failed_signin
+ flash[:error] = "Couldn't log you in as '#{params[:login]}'"
+ logger.warn "Failed login for '#{params[:login]}' from #{request.remote_ip} at #{Time.now.utc}"
+ end
+end
86 app/controllers/stories_controller.rb
@@ -0,0 +1,86 @@
+class StoriesController < ApplicationController
+ caches_page :show, :index
+ cache_sweeper :story_sweeper, :only => [:create, :update, :destroy, :like]
+
+ before_filter :set_current_tab
+ before_filter :login_required, :only => [:like, :new, :create]
+ before_filter :load_top_stories, :only => [:index, :tags]
+ before_filter :load_top_discussed_stories, :only => [:index, :tags]
+ before_filter :load_top_users, :only => [:index, :app_tab, :tags]
+ before_filter :load_newest_users, :only => [:index, :app_tab, :tags]
+
+ def index
+ @contents = Content.paginate :page => params[:page], :per_page => Content.per_page, :order => "created_at desc"
+ respond_to do |format|
+ format.html
+ format.fbml
+ format.atom
+ end
+ end
+
+ def show
+ @story = Content.find(params[:id])
+ tag_cloud @story
+ end
+
+ def new
+ @story = Content.new
+ end
+
+ def create
+ @story = Content.new(params[:content])
+ @story.user = current_user
+ @story.tag_list = params[:content][:tags_string]
+ if params[:content][:image_url].present?
+ @story.build_content_image({:url => params[:content][:image_url]})
+ end
+ if @story.save
+ flash[:success] = "Successfully posted your story!"
+ redirect_to story_path(@story)
+ else
+ flash[:error] = "Could not create your story. Please clear the errors and try again."
+ render :new
+ end
+ end
+
+ def like
+ @story = Content.find_by_id(params[:id])
+ respond_to do |format|
+ if current_user and @story.present? and current_user.vote_for(@story)
+ success = "Thanks for your vote!"
+ format.html { flash[:success] = success; redirect_to params[:return_to] || stories_path }
+ format.fbml { flash[:success] = success; redirect_to params[:return_to] || stories_path }
+ format.json { render :json => { :msg => "#{@story.votes.size} likes" }.to_json }
+ format.fbjs { render :json => { :msg => "#{@story.votes.size} likes" }.to_json }
+ else
+ error = "Vote failed"
+ format.html { flash[:error] = error; redirect_to params[:return_to] || stories_path }
+ format.fbml { flash[:error] = error; redirect_to params[:return_to] || stories_path }
+ format.json { render :json => { :msg => error }.to_json }
+ format.fbjs { render :text => { :msg => error }.to_json }
+ end
+ end
+ end
+
+ def parse_page
+ @url = params[:url]
+ @page_data = Parse::Page.parse_page(@url) unless @url.empty?
+ respond_to do |format|
+ format.html { render :text => @page_data }
+ format.json { render :json => @page_data.to_json }
+ end
+ end
+
+ def tags
+ @paginate = true
+ @contents = Content.tagged_with(params[:tag], :on => 'tags').paginate :page => params[:page], :per_page => 20, :order => "created_at desc"
+
+ end
+
+ private
+
+ def set_current_tab
+ @current_tab = 'stories'
+ end
+
+end
77 app/controllers/users_controller.rb
@@ -0,0 +1,77 @@
+class UsersController < ApplicationController
+ before_filter :load_top_stories, :only => [:show]
+
+ # render new.rhtml
+ def new
+ @user = User.new
+ end
+
+ def create
+ unless params[:user].present?
+ @user = User.new
+ render :new
+ return false
+ end
+ logout_keeping_session!
+ @user = User.new(params[:user])
+ success = @user && @user.save
+ if success && @user.errors.empty?
+ # Protects against session fixation attacks, causes request forgery
+ # protection if visitor resubmits an earlier form using back
+ # button. Uncomment if you understand the tradeoffs.
+ # reset session
+ self.current_user = @user # !! now logged in
+ redirect_back_or_default('/')
+ flash[:notice] = "Thanks for signing up! We're sending you an email with your activation code."
+ else
+ flash[:error] = "We couldn't set up that account, sorry. Please try again, or contact an admin (link is above)."
+ render :action => 'new'
+ end
+ end
+
+ def link_user_accounts
+ if self.current_user.nil?
+ #register with fb
+ set_facebook_session unless facebook_session.present?
+ User.create_from_fb_connect(facebook_session.user)
+ else
+ #connect accounts
+ self.current_user.link_fb_connect(facebook_session.user.id) unless self.current_user.fb_user_id == facebook_session.user.id
+ end
+ redirect_to root_path
+ end
+
+ def show
+ @user = User.find(params[:id])
+ @is_owner = current_user && (@user.id == current_user.id)
+ @curr_action = params[:curr_action] || 'stories'
+ if @curr_action == 'stories'
+ @actions = @user.contents.newest_stories
+ elsif @curr_action == 'articles'
+ @actions = @user.contents.newest_articles
+ elsif @curr_action == 'comments'
+ @actions = @user.comments.newest
+ elsif @curr_action == 'likes'
+ @actions = @user.votes.newest
+ else
+ @actions = false
+ end
+ respond_to do |format|
+ format.html
+ format.fbml
+ format.atom { @actions = @user.newest_actions }
+ end
+ end
+
+ def invite
+ @success = false
+ if request.post?
+ if params['action'] == 'invite' and params['ids'].present?
+ flash[:notice] = "Successfully invited your friends."
+ @fb_user_ids = params['ids']
+ @success = true
+ end
+ end
+ end
+
+end
107 app/helpers/admin_helper.rb
@@ -0,0 +1,107 @@
+# Methods added to this helper will be available to all templates in the application.
+module AdminHelper
+
+ def gen_index_page(collection, model, fields, options = {})
+ set_model_vars model
+
+ html = []
+ html << "<h1>#{@model_list_name} List</h1"
+ html << "<br />"
+
+ html << "<h2>#{gen_new_link model}</h2>"
+
+ html << gen_table(collection, model, fields, options)
+ html.join
+ end
+
+ def gen_show_page(item, fields, options = {})
+ set_model_vars item.class
+
+ html = []
+ html << "<h1>#{@model_name} Details</h1>"
+ html << "<hr />"
+ fields.each do |field|
+ html << "<p>#{field.to_s.titleize}: #{field_value item, field, options[:associations]}</p>"
+ end
+ html << "<br />"
+ html << "<p>Actions: #{admin_links item}</p>"
+ html << "<br />"
+
+ html.join
+ end
+
+ def gen_new_link model
+ set_model_vars model
+ link_to "New #{@model_name}", new_polymorphic_path([:admin, model])
+ end
+
+ def gen_table(collection, model, fields, options = {})
+ set_model_vars model
+
+ html = []
+ model_list_name = @model_list_name
+ model_id = @model_id
+
+ if collection.empty?
+ html << "<p>No items found</p>"
+ else
+ html << will_paginate(collection) if options[:paginate]
+ html << "<table id='#{model_id}-table' class='admin-table'>"
+ html << "<thead>"
+ html << "<tr>"
+ fields.each {|field| html << "<th>#{field.to_s.titleize}</th>" }
+ html << "<th>Actions</th>"
+ html << "</tr>"
+ html << "</thead>"
+ html << "<tbody>"
+ collection.each do |item|
+ html << "<tr>"
+ fields.each do |field|
+ html << "<td>#{field_value item, field, options[:associations]}</td"
+ end
+ html << "<td>#{admin_links item}</td>"
+ html << "</tr>"
+ end
+ html << "</tbody>"
+ html << "</table>"
+ html << will_paginate(collection) if options[:paginate]
+ end
+
+ html.join
+ end
+
+ def admin_links item
+ [
+ link_to_unless_current('View', [:admin, item]) {link_to "Back", :back },
+ link_to('Edit', edit_polymorphic_path([:admin, item]))
+ ].join ' | '
+ end
+
+ def set_model_vars model
+ @model_list_name ||= model.name.tableize.titleize
+ @model_name ||= model.name.titleize
+ @model_id ||= model.name.tableize.dasherize
+ end
+
+ def association_exists? field, associations
+ [:belongs_to, :has_one].each do |association|
+ if associations[association].present?
+ associations[association].each do |name, field_name|
+ return name if field_name == field
+ end
+ end
+ end
+ return false
+ end
+
+ def field_value item, field, associations = nil
+ return item.send(field).to_s unless associations.present?
+ association = association_exists? field, associations
+ if association and item.send(association).present?
+ "#{link_to h(item.send(association).to_s), [:admin, item.send(association)]}"
+ else
+ item.send(field).to_s
+ end
+ end
+
+end
206 app/helpers/application_helper.rb
@@ -0,0 +1,206 @@
+# Methods added to this helper will be available to all templates in the application.
+module ApplicationHelper
+ include TagsHelper
+
+ def pipe_spacer
+ '<span class="pipe">|</span>'
+ end
+
+ def tab_selected?(current_tab, tab_name)
+ current_tab == tab_name ? "selected" : ''
+ end
+
+ def sub_tab_selected?(current_sub_tab, sub_tab_name)
+ current_sub_tab == sub_tab_name ? "selected" : ''
+ end
+
+ def default_bio(user)
+ "Hi my name is #{local_linked_profile_name user} and I forgot to add my bio. Next time you see me remind me to update my bio information."
+ end
+
+ def build_feed_link(action)
+ action_type = action.class.name
+ if action_type == 'Content'
+ base_url(story_path(action, :canvas => false))
+ elsif action_type == 'Comment'
+ base_url(story_path(action.content, :canvas => false))
+ elsif action_type == 'Vote'
+ base_url(story_path(action.voteable, :canvas => false))
+ else
+ ''
+ end
+ end
+
+ def build_feed_title(action, user)
+ action_type = action.class.name
+ if action_type == 'Content'
+ "#{user.name} posted #{action.title}"
+ elsif action_type == 'Comment'
+ "#{user.name} just commented on #{action.content.title}"
+ elsif action_type == 'Vote'
+ "#{user.name} liked #{action.voteable.title}"
+ else
+ ''
+ end
+ end
+
+ def build_feed_blurb(action, user)
+ action_type = action.class.name
+ if action_type == 'Content'
+ "#{user.name} posted #{linked_story_caption(action, 150, build_feed_link(action))}"
+ elsif action_type == 'Comment'
+ "#{user.name} just commented on #{action.content.title}: #{action.comments}"
+ elsif action_type == 'Vote'
+ "#{user.name} liked #{action.voteable.title}"
+ else
+ ''
+ end
+ end
+
+ def build_feed_item(action, action_type)
+ if action_type == 'Content'
+ if action.is_article?
+ render :partial => 'shared/feed_items/article', :locals => { :article => action }
+ else
+ render :partial => 'shared/feed_items/story', :locals => { :story => action }
+ end
+ elsif action_type == 'Comment'
+ render :partial => 'shared/feed_items/comment', :locals => { :comment => action }
+ elsif action_type == 'Vote'
+ render :partial => 'shared/feed_items/vote', :locals => { :vote => action }
+ end
+ end
+
+ def linked_story_caption(story, length = 150, url = false)
+ caption = caption(story.caption, length)
+ "#{caption} #{link_to 'More', (url ? url : story_path(story))}"
+ end
+
+ def linked_newswire_caption(newswire, length = 150)
+ caption = caption(newswire.caption, length)
+ "#{caption} #{link_to 'More', newswire.url, :target => "_cts"}"
+ end
+
+ def linked_comment_caption(comment, length = 150)
+ caption = caption(comment.comments, length)
+ "#{caption} #{link_to 'More', story_path(comment.content, :anchor => 'commentsListTop')}"
+ end
+
+ def caption(text, length = 150)
+ text.length <= length ? text : text[0, length] + '...'
+ end
+
+ def voteable_type_name(vote)
+ type = vote.voteable.class.name
+ if type == 'Content'
+ vote.voteable.is_article? ? 'article' : 'story'
+ elsif type == 'Comment'
+ 'comment'
+ elsif type == 'Idea'
+ 'idea'
+ else
+ type
+ end
+ end
+
+ def voteable_type_link(vote)
+ type = vote.voteable.class.name
+ if type == 'Content'
+ link_to vote.voteable.title, story_path(vote.voteable)
+ elsif type == 'Comment'
+ link_to vote.voteable.title, story_path(vote.voteable, :anchor => "commentListTop")
+ elsif type == 'Idea'
+ link_to 'Idea', '#'
+ else
+ ''
+ end
+ end
+
+ def local_linked_profile_pic(user, options={})
+ if user.facebook_user?
+ options.merge!(:linked => false)
+ link_to fb_profile_pic(user, options), user_path(user)
+ else
+ link_to image_tag(default_image), user
+ end
+ end
+
+ def local_linked_profile_name(user, options={})
+ if user.facebook_user?
+ options.merge!(:linked => false)
+ link_to fb_name(user, options), user_path(user)
+ else
+ link_to user.name, user
+ end
+ end
+
+ def nl2br(string)
+ string.gsub("\n\r","<br>").gsub("\r", "").gsub("\n", "<br />")
+ end
+
+ def profile_fb_name(user)
+ fb_name(user, :use_you => true, :possessive => true, :capitalize => true)
+ end
+
+ def twitter_share_story_link(story)
+ caption = caption strip_tags(story.caption)
+ url = story_url(story)
+ text = CGI.escape("#{caption} #{url}")
+ twitter_url = "http://twitter.com/?status=#{text}"
+ link_to image_tag('/images/default/tweet_button.gif'), twitter_url, :class => "tweetButton"
+ end
+
+ def base_url(path)
+ if APP_CONFIG['base_url'].present?
+ "#{APP_CONFIG['base_url']}#{path}"
+ end
+ end
+
+ def fb_list_of_names(fb_user_ids)
+ return false if fb_user_ids.empty?
+ return fb_name(fb_user_ids.first) if fb_user_ids.size == 1
+
+ last = fb_user_ids.pop
+ "#{fb_user_ids.collect { |c| fb_name c }.join ', '} and #{fb_name last}"
+ end
+
+ def twitter_url(query)
+ "http://twitter.com/#{query}"
+ end
+
+ def flash_messages
+ messages = []
+ [:success, :notice, :error, :warning].each do |type|
+ messages << content_tag(:div, content_tag(:p, flash[type]), :class => "flash flash_#{type}") if flash[type].present?
+ flash[type] = nil
+ end
+
+ (messages.size > 0) ? messages.join : ''
+ end
+
+ def ar_xid(record)
+ "#{record.class.model_name.tableize}-#{record.id}"
+ end
+
+ def tag_list(tags, item)
+ tag_list = []
+ tag_cloud(tags, %w(css1 css2 css3 css4)) do |tag, css_class|
+ tag_list << link_to(tag.name, tag_link(tag, item), :class => css_class)
+ end
+
+ tag_list.size > 0 ? tag_list.join('&nbsp;') : ''
+ end
+
+ def tag_link(tag, item)
+ if item.class.name == 'Content'
+ tagged_stories_path(:tag => tag.name)
+ else
+ [item, tag]
+ end
+ end
+
+ def default_image
+ APP_CONFIG['default_image']
+ end
+
+end
2 app/helpers/articles_helper.rb
@@ -0,0 +1,2 @@
+module ArticlesHelper
+end
2 app/helpers/comments_helper.rb
@@ -0,0 +1,2 @@
+module CommentsHelper
+end
2 app/helpers/events_helper.rb
@@ -0,0 +1,2 @@
+module EventsHelper
+end
2 app/helpers/home_helper.rb
@@ -0,0 +1,2 @@
+module HomeHelper
+end
2 app/helpers/idea_boards_helper.rb
@@ -0,0 +1,2 @@
+module IdeaBoardsHelper
+end
2 app/helpers/ideas_helper.rb
@@ -0,0 +1,2 @@