atreides 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (309) hide show
  1. data/LICENSE +7 -0
  2. data/README.rdoc +1 -0
  3. data/app/assets/javascripts/atreides/admin.js +22 -0
  4. data/app/assets/javascripts/atreides/admin_base.js.erb +247 -0
  5. data/app/assets/javascripts/atreides/admin_edit.js +9 -0
  6. data/app/assets/javascripts/atreides/application.js +15 -0
  7. data/app/assets/javascripts/atreides/comments.coffee +50 -0
  8. data/app/assets/javascripts/atreides/public.js +24 -0
  9. data/app/assets/javascripts/atreides/public_base.js.erb +119 -0
  10. data/app/assets/javascripts/atreides/terryblr.js +57 -0
  11. data/app/assets/stylesheets/atreides/admin.css +21 -0
  12. data/app/assets/stylesheets/atreides/admin_base.css.erb +1762 -0
  13. data/app/assets/stylesheets/atreides/application.css +13 -0
  14. data/app/assets/stylesheets/atreides/formtastic_changes.css +10 -0
  15. data/app/assets/stylesheets/atreides/iphone-checkboxes.css.erb +97 -0
  16. data/app/assets/stylesheets/atreides/jBreadCrumb.css +109 -0
  17. data/app/assets/stylesheets/atreides/public.css +15 -0
  18. data/app/assets/stylesheets/atreides/public_base.css +101 -0
  19. data/app/assets/stylesheets/atreides/swfupload.css.erb +63 -0
  20. data/app/controllers/admin/atreides/comments_controller.rb +47 -0
  21. data/app/controllers/admin/atreides/content_parts_controller.rb +43 -0
  22. data/app/controllers/admin/atreides/dropbox_controller.rb +40 -0
  23. data/app/controllers/admin/atreides/features_controller.rb +63 -0
  24. data/app/controllers/admin/atreides/github_controller.rb +35 -0
  25. data/app/controllers/admin/atreides/links_controller.rb +3 -0
  26. data/app/controllers/admin/atreides/messages_controller.rb +3 -0
  27. data/app/controllers/admin/atreides/orders_controller.rb +35 -0
  28. data/app/controllers/admin/atreides/pages_controller.rb +59 -0
  29. data/app/controllers/admin/atreides/photos_controller.rb +79 -0
  30. data/app/controllers/admin/atreides/posts_controller.rb +109 -0
  31. data/app/controllers/admin/atreides/products_controller.rb +39 -0
  32. data/app/controllers/admin/atreides/sessions_controller.rb +7 -0
  33. data/app/controllers/admin/atreides/sizes_controller.rb +4 -0
  34. data/app/controllers/admin/atreides/tags_controller.rb +20 -0
  35. data/app/controllers/admin/atreides/users_controller.rb +50 -0
  36. data/app/controllers/admin/atreides/videos_controller.rb +53 -0
  37. data/app/controllers/atreides/admin_controller.rb +96 -0
  38. data/app/controllers/atreides/admin_home_controller.rb +211 -0
  39. data/app/controllers/atreides/application_controller.rb +93 -0
  40. data/app/controllers/atreides/comments_controller.rb +43 -0
  41. data/app/controllers/atreides/home_controller.rb +71 -0
  42. data/app/controllers/atreides/likes_controller.rb +44 -0
  43. data/app/controllers/atreides/pages_controller.rb +34 -0
  44. data/app/controllers/atreides/posts_controller.rb +119 -0
  45. data/app/controllers/atreides/public_controller.rb +43 -0
  46. data/app/helpers/admin/atreides/comments_helper.rb +8 -0
  47. data/app/helpers/admin/atreides/dropbox_helper.rb +42 -0
  48. data/app/helpers/admin/atreides/features_helper.rb +4 -0
  49. data/app/helpers/admin/atreides/github_helper.rb +43 -0
  50. data/app/helpers/admin/atreides/links_helper.rb +4 -0
  51. data/app/helpers/admin/atreides/messages_helper.rb +4 -0
  52. data/app/helpers/admin/atreides/orders_helper.rb +30 -0
  53. data/app/helpers/admin/atreides/pages_helper.rb +17 -0
  54. data/app/helpers/admin/atreides/photos_helper.rb +14 -0
  55. data/app/helpers/admin/atreides/posts_helper.rb +41 -0
  56. data/app/helpers/admin/atreides/products_helper.rb +37 -0
  57. data/app/helpers/admin/atreides/sizes_helper.rb +4 -0
  58. data/app/helpers/admin/atreides/user_sessions_helper.rb +4 -0
  59. data/app/helpers/admin/atreides/users_helper.rb +8 -0
  60. data/app/helpers/admin/atreides/videos_helper.rb +4 -0
  61. data/app/helpers/atreides/admin_helper.rb +243 -0
  62. data/app/helpers/atreides/admin_home_helper.rb +4 -0
  63. data/app/helpers/atreides/application_helper.rb +210 -0
  64. data/app/helpers/atreides/home_helper.rb +4 -0
  65. data/app/helpers/atreides/posts_helper.rb +119 -0
  66. data/app/inputs/files_input.rb +13 -0
  67. data/app/inputs/price_input.rb +18 -0
  68. data/app/inputs/underline_input.rb +16 -0
  69. data/app/models/atreides/ability.rb +24 -0
  70. data/app/models/atreides/comment.rb +93 -0
  71. data/app/models/atreides/content_part.rb +107 -0
  72. data/app/models/atreides/feature.rb +90 -0
  73. data/app/models/atreides/github.rb +74 -0
  74. data/app/models/atreides/like.rb +35 -0
  75. data/app/models/atreides/line_item.rb +4 -0
  76. data/app/models/atreides/link.rb +32 -0
  77. data/app/models/atreides/message.rb +34 -0
  78. data/app/models/atreides/order.rb +209 -0
  79. data/app/models/atreides/page.rb +114 -0
  80. data/app/models/atreides/photo.rb +130 -0
  81. data/app/models/atreides/post.rb +271 -0
  82. data/app/models/atreides/product.rb +75 -0
  83. data/app/models/atreides/site.rb +59 -0
  84. data/app/models/atreides/size.rb +44 -0
  85. data/app/models/atreides/tag.rb +31 -0
  86. data/app/models/atreides/tweet.rb +123 -0
  87. data/app/models/atreides/user.rb +129 -0
  88. data/app/models/atreides/video.rb +206 -0
  89. data/app/models/atreides/vote.rb +43 -0
  90. data/app/models/fb_post_publisher_job.rb +72 -0
  91. data/app/models/settings.rb +19 -0
  92. data/app/models/tumblr_post_publisher_job.rb +75 -0
  93. data/app/models/tw_post_publisher_job.rb +54 -0
  94. data/app/views/admin/_edit_head_content.html.haml +2 -0
  95. data/app/views/admin/atreides/comments/_line.html.haml +60 -0
  96. data/app/views/admin/atreides/comments/_sidebar.html.haml +52 -0
  97. data/app/views/admin/atreides/comments/create.js.haml +1 -0
  98. data/app/views/admin/atreides/comments/index.html.haml +34 -0
  99. data/app/views/admin/atreides/content_parts/_form.html.haml +21 -0
  100. data/app/views/admin/atreides/content_parts/_photos.html.haml +18 -0
  101. data/app/views/admin/atreides/content_parts/_text.html.haml +1 -0
  102. data/app/views/admin/atreides/content_parts/_videos.html.haml +12 -0
  103. data/app/views/admin/atreides/content_parts/destroy.js.haml +3 -0
  104. data/app/views/admin/atreides/content_parts/edit.html.haml +0 -0
  105. data/app/views/admin/atreides/content_parts/new.html.haml +0 -0
  106. data/app/views/admin/atreides/content_parts/new.js.haml +11 -0
  107. data/app/views/admin/atreides/dropbox/_uploader.html.haml +134 -0
  108. data/app/views/admin/atreides/dropbox/list.html.haml +27 -0
  109. data/app/views/admin/atreides/dropbox/setup.html.haml +8 -0
  110. data/app/views/admin/atreides/features/_form.html.haml +60 -0
  111. data/app/views/admin/atreides/features/edit.html.haml +1 -0
  112. data/app/views/admin/atreides/features/index.html.haml +24 -0
  113. data/app/views/admin/atreides/features/new.html.haml +1 -0
  114. data/app/views/admin/atreides/github/index.html.haml +26 -0
  115. data/app/views/admin/atreides/github/show.html.haml +19 -0
  116. data/app/views/admin/atreides/likes/create.js.haml +2 -0
  117. data/app/views/admin/atreides/orders/_sidebar.html.haml +20 -0
  118. data/app/views/admin/atreides/orders/edit.html.haml +52 -0
  119. data/app/views/admin/atreides/orders/index.html.haml +8 -0
  120. data/app/views/admin/atreides/pages/_form.html.haml +31 -0
  121. data/app/views/admin/atreides/pages/edit.html.haml +3 -0
  122. data/app/views/admin/atreides/pages/index.html.haml +15 -0
  123. data/app/views/admin/atreides/pages/index.js.haml +4 -0
  124. data/app/views/admin/atreides/pages/new.html.haml +2 -0
  125. data/app/views/admin/atreides/photos/create.js.haml +18 -0
  126. data/app/views/admin/atreides/photos/destroy.js.haml +3 -0
  127. data/app/views/admin/atreides/posts/_archives.html.haml +19 -0
  128. data/app/views/admin/atreides/posts/_form.html.haml +66 -0
  129. data/app/views/admin/atreides/posts/_form_buttons.html.haml +9 -0
  130. data/app/views/admin/atreides/posts/_form_sidebar.html.haml +85 -0
  131. data/app/views/admin/atreides/posts/edit.html.haml +2 -0
  132. data/app/views/admin/atreides/posts/index.html.haml +24 -0
  133. data/app/views/admin/atreides/posts/index.js.haml +1 -0
  134. data/app/views/admin/atreides/posts/new.html.haml +2 -0
  135. data/app/views/admin/atreides/products/edit.html.haml +69 -0
  136. data/app/views/admin/atreides/products/index.html.haml +31 -0
  137. data/app/views/admin/atreides/sessions/new.html.haml +13 -0
  138. data/app/views/admin/atreides/user_sessions/new.html.haml +10 -0
  139. data/app/views/admin/atreides/users/_form.html.haml +19 -0
  140. data/app/views/admin/atreides/users/edit.html.haml +6 -0
  141. data/app/views/admin/atreides/users/index.html.haml +11 -0
  142. data/app/views/admin/atreides/users/new.html.haml +6 -0
  143. data/app/views/admin/atreides/users/show.html.haml +4 -0
  144. data/app/views/admin/atreides/videos/create.js.haml +9 -0
  145. data/app/views/admin/atreides/videos/destroy.js.haml +3 -0
  146. data/app/views/admin/common/_archive_sidebar.html.haml +29 -0
  147. data/app/views/admin/common/_list_table.html.erb +37 -0
  148. data/app/views/admin/common/_list_table_row.html.erb +18 -0
  149. data/app/views/admin/common/_pagination.html.erb +1 -0
  150. data/app/views/admin/common/_search_form.html.erb +6 -0
  151. data/app/views/admin/common/access_denied.html.haml +1 -0
  152. data/app/views/atreides/admin/_content_nav.html.haml +8 -0
  153. data/app/views/atreides/admin_home/_analytics.html.haml +93 -0
  154. data/app/views/atreides/admin_home/_fb_page_likes_analytics_tbody.haml +10 -0
  155. data/app/views/atreides/admin_home/_fb_page_views_analytics_tbody.haml +10 -0
  156. data/app/views/atreides/admin_home/_top_landing_pages_analytics_tbody.haml +14 -0
  157. data/app/views/atreides/admin_home/_top_referrers_analytics_tbody.haml +12 -0
  158. data/app/views/atreides/admin_home/_tweets_analytics_tbody.html.haml +8 -0
  159. data/app/views/atreides/admin_home/_visitors_analytics_tbody.html.haml +12 -0
  160. data/app/views/atreides/admin_home/index.html.haml +57 -0
  161. data/app/views/atreides/admin_home/search.html.haml +11 -0
  162. data/app/views/atreides/admin_home/setup.html.haml +15 -0
  163. data/app/views/atreides/common/_gallery_params.xml.erb +174 -0
  164. data/app/views/atreides/common/slideshow.xml.haml +6 -0
  165. data/app/views/atreides/errors/404.html.haml +10 -0
  166. data/app/views/atreides/errors/500.html.haml +4 -0
  167. data/app/views/atreides/home/index.html.haml +30 -0
  168. data/app/views/atreides/home/index.js.haml +1 -0
  169. data/app/views/atreides/home/robots.txt.erb +5 -0
  170. data/app/views/atreides/home/sitemap.xml.builder +35 -0
  171. data/app/views/atreides/pages/show.html.haml +3 -0
  172. data/app/views/atreides/posts/_archives.html.haml +19 -0
  173. data/app/views/atreides/posts/_featured_posts.html.haml +10 -0
  174. data/app/views/atreides/posts/_list.html.haml +9 -0
  175. data/app/views/atreides/posts/archives.html.haml +3 -0
  176. data/app/views/atreides/posts/archives.js.haml +1 -0
  177. data/app/views/atreides/posts/gallery_params.xml.haml +1 -0
  178. data/app/views/atreides/posts/index.atom.builder +22 -0
  179. data/app/views/atreides/posts/index.html.haml +13 -0
  180. data/app/views/atreides/posts/index.rss.builder +21 -0
  181. data/app/views/atreides/posts/show.html.haml +23 -0
  182. data/app/views/atreides/posts/tagged.html.haml +4 -0
  183. data/app/views/atreides/posts/tagged.js.haml +1 -0
  184. data/app/views/layouts/admin.html.haml +62 -0
  185. data/app/views/layouts/application.html.haml +37 -0
  186. data/app/views/layouts/atreides/application.html.erb +14 -0
  187. data/app/views/layouts/public.html.haml +39 -0
  188. data/config/cucumber.yml +11 -0
  189. data/config/locales/en.yml +236 -0
  190. data/config/locales/fr.yml +199 -0
  191. data/config/routes.rb +119 -0
  192. data/lib/assets/images/atreides/admin/add.png +0 -0
  193. data/lib/assets/images/atreides/admin/add_btn.png +0 -0
  194. data/lib/assets/images/atreides/admin/add_dashboard.png +0 -0
  195. data/lib/assets/images/atreides/admin/add_photo_button_sprite.png +0 -0
  196. data/lib/assets/images/atreides/admin/add_photos_btn.png +0 -0
  197. data/lib/assets/images/atreides/admin/background.png +0 -0
  198. data/lib/assets/images/atreides/admin/calendar.png +0 -0
  199. data/lib/assets/images/atreides/admin/chevron.gif +0 -0
  200. data/lib/assets/images/atreides/admin/chevron_overlay.png +0 -0
  201. data/lib/assets/images/atreides/admin/choose_photos_button_sprite.png +0 -0
  202. data/lib/assets/images/atreides/admin/content_bg.png +0 -0
  203. data/lib/assets/images/atreides/admin/content_bg_edit_form.png +0 -0
  204. data/lib/assets/images/atreides/admin/content_part_break.png +0 -0
  205. data/lib/assets/images/atreides/admin/content_part_drop_target.png +0 -0
  206. data/lib/assets/images/atreides/admin/content_part_icons.png +0 -0
  207. data/lib/assets/images/atreides/admin/content_part_photos.png +0 -0
  208. data/lib/assets/images/atreides/admin/content_part_text.png +0 -0
  209. data/lib/assets/images/atreides/admin/content_part_videos.png +0 -0
  210. data/lib/assets/images/atreides/admin/content_top_edit_form.png +0 -0
  211. data/lib/assets/images/atreides/admin/dashboard-indicator.gif +0 -0
  212. data/lib/assets/images/atreides/admin/dashboard_controls_activity.png +0 -0
  213. data/lib/assets/images/atreides/admin/dashboard_controls_customize.png +0 -0
  214. data/lib/assets/images/atreides/admin/dashboard_controls_drafts.png +0 -0
  215. data/lib/assets/images/atreides/admin/dashboard_controls_open.png +0 -0
  216. data/lib/assets/images/atreides/admin/dashboard_controls_posts.png +0 -0
  217. data/lib/assets/images/atreides/admin/dashboard_controls_queue.png +0 -0
  218. data/lib/assets/images/atreides/admin/dashboard_nav_border.png +0 -0
  219. data/lib/assets/images/atreides/admin/delete_bg.png +0 -0
  220. data/lib/assets/images/atreides/admin/down_arrow.png +0 -0
  221. data/lib/assets/images/atreides/admin/dropbox_big.jpg +0 -0
  222. data/lib/assets/images/atreides/admin/dropbox_btn.png +0 -0
  223. data/lib/assets/images/atreides/admin/dropbox_folder.png +0 -0
  224. data/lib/assets/images/atreides/admin/dropbox_icon.gif +0 -0
  225. data/lib/assets/images/atreides/admin/dropbox_icon.png +0 -0
  226. data/lib/assets/images/atreides/admin/expand_collapse.png +0 -0
  227. data/lib/assets/images/atreides/admin/form_sidebar_divider.png +0 -0
  228. data/lib/assets/images/atreides/admin/grey_hatch_bg.png +0 -0
  229. data/lib/assets/images/atreides/admin/header.png +0 -0
  230. data/lib/assets/images/atreides/admin/icon_dropbox.gif +0 -0
  231. data/lib/assets/images/atreides/admin/icon_home.gif +0 -0
  232. data/lib/assets/images/atreides/admin/input_bg.gif +0 -0
  233. data/lib/assets/images/atreides/admin/large_loading.gif +0 -0
  234. data/lib/assets/images/atreides/admin/new_content_icons.png +0 -0
  235. data/lib/assets/images/atreides/admin/off.png +0 -0
  236. data/lib/assets/images/atreides/admin/on.png +0 -0
  237. data/lib/assets/images/atreides/admin/page_icon.png +0 -0
  238. data/lib/assets/images/atreides/admin/permalink.png +0 -0
  239. data/lib/assets/images/atreides/admin/photos-display-type-gallery.png +0 -0
  240. data/lib/assets/images/atreides/admin/photos-display-type-photos.png +0 -0
  241. data/lib/assets/images/atreides/admin/product.png +0 -0
  242. data/lib/assets/images/atreides/admin/remove.png +0 -0
  243. data/lib/assets/images/atreides/admin/resize.png +0 -0
  244. data/lib/assets/images/atreides/admin/save_btn.png +0 -0
  245. data/lib/assets/images/atreides/admin/search_icon.png +0 -0
  246. data/lib/assets/images/atreides/admin/select_arrows.png +0 -0
  247. data/lib/assets/images/atreides/admin/slider.png +0 -0
  248. data/lib/assets/images/atreides/admin/slider_center.png +0 -0
  249. data/lib/assets/images/atreides/admin/slider_left.png +0 -0
  250. data/lib/assets/images/atreides/admin/slider_right.png +0 -0
  251. data/lib/assets/images/atreides/admin/sprite.png +0 -0
  252. data/lib/assets/images/atreides/admin/upload_btn.png +0 -0
  253. data/lib/assets/images/atreides/admin/video_bg.png +0 -0
  254. data/lib/assets/images/atreides/blank.gif +0 -0
  255. data/lib/assets/images/atreides/closelabel.png +0 -0
  256. data/lib/assets/images/atreides/loading.gif +0 -0
  257. data/lib/assets/images/atreides/sprite.png +0 -0
  258. data/lib/assets/images/atreides/tipsy.gif +0 -0
  259. data/lib/atreides.rb +82 -0
  260. data/lib/atreides/base/aasmstates.rb +117 -0
  261. data/lib/atreides/base/base.rb +40 -0
  262. data/lib/atreides/base/taggable.rb +43 -0
  263. data/lib/atreides/base/validation.rb +23 -0
  264. data/lib/atreides/configuration.rb +61 -0
  265. data/lib/atreides/engine.rb +41 -0
  266. data/lib/atreides/extendable.rb +12 -0
  267. data/lib/atreides/i18n_helpers.rb +65 -0
  268. data/lib/atreides/railties/tasks.rake +68 -0
  269. data/lib/atreides/time_formats.rb +19 -0
  270. data/lib/atreides/validators.rb +15 -0
  271. data/lib/atreides/version.rb +4 -0
  272. data/lib/generators/atreides/USAGE +0 -0
  273. data/lib/generators/atreides/atreides_generator.rb +58 -0
  274. data/lib/generators/templates/Procfile +2 -0
  275. data/lib/generators/templates/add_role_to_users.rb +16 -0
  276. data/lib/generators/templates/add_userid_to_resources.rb +15 -0
  277. data/lib/generators/templates/create_comments.rb +19 -0
  278. data/lib/generators/templates/create_content_parts.rb +66 -0
  279. data/lib/generators/templates/create_features.rb +21 -0
  280. data/lib/generators/templates/create_likes.rb +16 -0
  281. data/lib/generators/templates/create_line_items.rb +21 -0
  282. data/lib/generators/templates/create_links.rb +16 -0
  283. data/lib/generators/templates/create_messages.rb +24 -0
  284. data/lib/generators/templates/create_orders.rb +31 -0
  285. data/lib/generators/templates/create_pages.rb +31 -0
  286. data/lib/generators/templates/create_photos.rb +22 -0
  287. data/lib/generators/templates/create_posts.rb +38 -0
  288. data/lib/generators/templates/create_products.rb +24 -0
  289. data/lib/generators/templates/create_sessions.rb +16 -0
  290. data/lib/generators/templates/create_sites.rb +35 -0
  291. data/lib/generators/templates/create_sizes.rb +16 -0
  292. data/lib/generators/templates/create_tweets.rb +25 -0
  293. data/lib/generators/templates/create_videos.rb +24 -0
  294. data/lib/generators/templates/create_votes.rb +20 -0
  295. data/lib/generators/templates/delayed_job.rb +5 -0
  296. data/lib/generators/templates/devise_create_users.rb +42 -0
  297. data/lib/generators/templates/disqussion.rb +30 -0
  298. data/lib/generators/templates/em-net-http_override.rb +74 -0
  299. data/lib/generators/templates/initializer.rb +21 -0
  300. data/lib/generators/templates/new_relic.rb +6 -0
  301. data/lib/generators/templates/oembed.yml +63 -0
  302. data/lib/generators/templates/settings.yml +110 -0
  303. data/lib/generators/templates/string_extensions.rb +20 -0
  304. data/lib/generators/templates/unicorn.rb +2 -0
  305. data/lib/tasks/atreides_tasks.rake +4 -0
  306. data/lib/tasks/cucumber.rake +58 -0
  307. data/lib/tasks/tasks.rake +403 -0
  308. data/lib/tasks/yard.rake +18 -0
  309. metadata +1458 -0
@@ -0,0 +1,114 @@
1
+ class Atreides::Page < Atreides::Base
2
+
3
+ include Atreides::Base::Taggable
4
+ include Atreides::Base::AasmStates
5
+ include Atreides::Base::Validation
6
+
7
+ #
8
+ # Constants
9
+ #
10
+
11
+ #
12
+ # Associatons
13
+ #
14
+ belongs_to :site, :class_name => "Atreides::Site"
15
+ belongs_to :author, :class_name => "Atreides::User"
16
+ belongs_to :last_editor, :class_name => "Atreides::User"
17
+ has_many :photos, :as => :photoable, :order => "display_order", :class_name => "Atreides::Photo"
18
+ has_many :messages, :as => :messagable, :class_name => "Atreides::Message"
19
+
20
+ #
21
+ # Behaviours
22
+ #
23
+
24
+ accepts_nested_attributes_for :messages
25
+ accepts_nested_attributes_for :photos, :allow_destroy => true
26
+
27
+ #
28
+ # Validations
29
+ #
30
+ validate :site_id, :presence => true
31
+ validates_presence_of :title, :body, :slug, :unless => :pending?
32
+ validate :slug, :uniqueness => true, :if => :slug?, :scope => :site_id
33
+
34
+ #
35
+ # Scopes
36
+ #
37
+ scope :roots, where(:parent_id => nil)
38
+
39
+ #
40
+ # Callbacks
41
+ #
42
+ before_validation :update_slug
43
+
44
+ def update_slug
45
+ # Set slug if not set or changed
46
+ self.slug = title.to_s.parameterize if !slug? or (!new_record? && title_changed?)
47
+ end
48
+
49
+ #
50
+ # Class Methods
51
+ #
52
+ class << self
53
+ def base_class
54
+ self
55
+ end
56
+ end
57
+
58
+ #
59
+ # Instance Methods
60
+ #
61
+
62
+ def thumbnail(size = :thumb)
63
+ # Find the first thumbnail image
64
+ url = nil
65
+ url = photos.first.image.url(size) unless photos.empty?
66
+
67
+ # FIXME: THIS NEEDS TO BE MOVED TO A VIEW/PRESENTER/DECORATOR
68
+ # asset_path('atreides/missing_thumb.png')
69
+
70
+ url || "/images/missing_thumb.png"
71
+ end
72
+
73
+
74
+ def children
75
+ @children ||= self.class.find_all_by_parent_id(id)
76
+ end
77
+
78
+ def parent
79
+ @parent ||= parent_of
80
+ end
81
+
82
+ def parents
83
+ @parents ||= []
84
+ return @parents unless @parents.empty?
85
+
86
+ prnt = self
87
+ while prnt.parent_id?
88
+ prnt = parent_of(prnt)
89
+ @parents << prnt
90
+ end
91
+ @parents
92
+ end
93
+
94
+ def root()
95
+ return @root unless @root.nil?
96
+ prnt = self.parent || self
97
+ while prnt.parent_id?
98
+ prnt = parent_of(prnt)
99
+ end
100
+ @root = prnt
101
+ end
102
+
103
+ private
104
+
105
+ def do_publish
106
+ update_attribute :published_at, Time.zone.now
107
+ end
108
+
109
+ def parent_of(page = self)
110
+ page.parent_id? ? self.class.find(page.parent_id) : nil
111
+ end
112
+
113
+ include Atreides::Extendable
114
+ end
@@ -0,0 +1,130 @@
1
+ class Atreides::Photo < Atreides::Base
2
+
3
+ #
4
+ # Constants
5
+ #
6
+
7
+ #
8
+ # Behaviours
9
+ #
10
+ serialize :sizes
11
+
12
+ # Regen thumbs with rake paperclip:refresh CLASS=Atreides::Photo or .reprocess!
13
+ has_attached_file :image,
14
+ :styles => Settings.photo_dimensions.dup.symbolize_keys,
15
+ :storage => Settings.s3_enabled? ? :s3 : :filesystem,
16
+ :convert_options => {
17
+ :all => Settings.photo_conv_options || "-density 72 "
18
+ },
19
+ :path => Settings.s3_enabled? ? ":attachment/:id/:style/:basename.:extension" : ":rails_root/public/system/:attachment/:id/:style/:basename.:extension",
20
+ :url => Settings.s3_enabled? ? ":attachment/:id/:style/:basename.:extension" : "/system/:attachment/:id/:style/:basename.:extension",
21
+ :s3_credentials => (Settings.s3.symbolize_keys rescue nil),
22
+ :bucket => [Settings.app_name, Rails.env].join('-').parameterize.to_s,
23
+ :log_command => Rails.env.development?
24
+
25
+ #
26
+ # Callbacks
27
+ #
28
+
29
+ #
30
+ # Associatons
31
+ #
32
+ belongs_to :photoable, :polymorphic => true, :touch => true
33
+ has_many :features, :class_name => "Atreides::Feature"
34
+
35
+ # using :dependent => :nullify just did not worked on the has_many :features association
36
+ # so we make this to make each features clean and valid
37
+ before_destroy :clean_features
38
+ def clean_features
39
+ features.each do |f|
40
+ f.photo = nil
41
+ f.save
42
+ end
43
+ end
44
+ #
45
+ # Validations
46
+ #
47
+ validates_attachment_presence :image
48
+ validates_attachment_size :image, :less_than => 3.megabytes
49
+ validates_presence_of :url, :unless => :image_file_name?
50
+ validates :url, :presence => true, :url => true, :if => :url?
51
+
52
+ #
53
+ # Scopes
54
+ #
55
+ default_scope :order => "display_order asc, id desc"
56
+
57
+ #
58
+ # Class Methods
59
+ #
60
+ class << self
61
+
62
+ def base_class
63
+ self
64
+ end
65
+
66
+ end
67
+
68
+ #
69
+ # Instance Methods
70
+ #
71
+ before_validation :fetch_remote_image
72
+ before_create :add_to_queue
73
+ after_save :update_associated_models
74
+
75
+ def fetch_remote_image
76
+ # If there is a URL then download it and use
77
+ self.image = do_download_remote_image if url_changed?
78
+ end
79
+
80
+ def add_to_queue
81
+ # Set the display order to be last
82
+ self.display_order = Atreides::Photo.count(:conditions => {:photoable_id => self.photoable_id, :photoable_type => self.photoable_type})
83
+ end
84
+
85
+ def update_associated_models
86
+ # Update assoc'd models
87
+ features.update_all({:updated_at => Time.zone.now})
88
+ end
89
+
90
+ def size(thumb)
91
+ sizes[thumb.to_sym]
92
+ rescue => exception
93
+ logger.error { "Error getting image sizes: #{exception}" }
94
+ {}
95
+ end
96
+
97
+ # Overload Paperclip so that images are only resaved when it changes - uses too much memory otherwise
98
+ def save_attached_files
99
+ super if image_file_size_changed?
100
+ end
101
+
102
+ # Save the images dimensions before being sent to storage
103
+ after_post_process :calculate_attachment_sizes
104
+ def calculate_attachment_sizes
105
+ if (image_file_name?)
106
+ self.sizes = {}
107
+ self.image.queued_for_write.each {|key,file|
108
+ self.sizes[key.to_sym]={}
109
+ geo = Paperclip::Geometry.from_file(file.path)
110
+ %w(width height).each{|dim|
111
+ self.sizes[key.to_sym][dim.to_sym] = geo.send(dim.to_sym).to_i
112
+ }
113
+ }
114
+ end
115
+ end
116
+
117
+ private
118
+
119
+ def do_download_remote_image
120
+ require 'open-uri'
121
+ io = open(URI.parse(url))
122
+ def io.original_filename; base_uri.path.split('/').last; end
123
+ io.original_filename.blank? ? nil : io
124
+ rescue Exception
125
+ errors.add(:url, "not valid. Unable to download image.")
126
+ return nil
127
+ end
128
+
129
+ include Atreides::Extendable
130
+ end
@@ -0,0 +1,271 @@
1
+ class Atreides::Post < Atreides::Base
2
+
3
+ include Atreides::Base::Taggable
4
+ include Atreides::Base::AasmStates
5
+ include Atreides::Base::Validation
6
+
7
+ #
8
+ # Constants
9
+ #
10
+
11
+ #
12
+ # Associatons
13
+ #
14
+ has_many :parts, :as => :contentable, :order => "display_order", :class_name => "Atreides::ContentPart", :dependent => :destroy
15
+ has_many :features, :class_name => "Atreides::Feature"
16
+ belongs_to :site, :class_name => "Atreides::Site"
17
+ belongs_to :tw_delayed_job, :class_name => "::Delayed::Job"
18
+ belongs_to :fb_delayed_job, :class_name => "::Delayed::Job"
19
+ belongs_to :tumblr_delayed_job, :class_name => "::Delayed::Job"
20
+ belongs_to :author, :class_name => "Atreides::User"
21
+ belongs_to :last_editor, :class_name => "Atreides::User"
22
+
23
+ #
24
+ # Behaviours
25
+ #
26
+
27
+ attr_accessor :url, :tw_me, :fb_me, :tumblr_me
28
+ accepts_nested_attributes_for :parts, :allow_destroy => true
29
+
30
+ #
31
+ # Validations
32
+ #
33
+ validate :site_id, :presence => true
34
+ validates :title, :presence => true, :if => :published?
35
+ validates :slug, :presence => { :message => "can't be blank. Did you set a title?" }, :if => :published?
36
+ validates :social_msg, :length => { :within => 0..140 }, :if => :social_msg?
37
+ validate :content_parts
38
+
39
+ #
40
+ # Scopes
41
+ #
42
+ default_scope order("posts.published_at desc, posts.id desc")
43
+
44
+ scope :for_month, lambda { |date, col|
45
+ col ||= :published_at
46
+ where("#{col} >= ? AND #{col} <= ?", date.to_time.beginning_of_month, date.to_time.end_of_month)
47
+ }
48
+
49
+ scope :by_month, lambda { |*args|
50
+ # Needs to be sep variable or AR will cache the first time and it'll never change
51
+ now = Time.zone.now
52
+ select("distinct(EXTRACT(DAY from posts.published_at)), posts.*").
53
+ where("EXTRACT(MONTH from posts.published_at) = ? and EXTRACT(YEAR from posts.published_at) = ? and posts.published_at <= ?", args.flatten[0].to_i, now.year, now).
54
+ order("posts.published_at asc")
55
+ }
56
+
57
+ scope :by_year, lambda { |year|
58
+ # Needs to be sep variable or AR will cache the first time and it'll never change
59
+ where("EXTRACT(YEAR from posts.published_at) = ? and posts.published_at <= ?", year.to_i, Time.zone.now)
60
+ }
61
+
62
+ scope :popular_photos, lambda {
63
+ now = Time.zone.now
64
+ joins("INNER JOIN photos ON photos.photoable_type = 'Atreides::Post' AND photos.photoable_id = posts.id").
65
+ select("posts.*, ((comments_count*2)+likes_count) as final_count").
66
+ where("posts.state = 'published' AND posts.published_at < ? AND posts.published_at < ?", now-1.week, now).
67
+ order("final_count desc, published_at desc").
68
+ group("posts.id").
69
+ limit(6)
70
+ }
71
+
72
+ #
73
+ # Callbacks
74
+ #
75
+ after_initialize :setup_social_network
76
+ after_initialize :set_diary
77
+
78
+ def setup_social_network
79
+ # Setup social network callback flags
80
+ begin
81
+ self.tw_me ||= ((Settings.default_cross_post_to?(:twitter) && pending?) or tw_delayed_job_id?) unless twitter_id?
82
+ self.fb_me ||= ((Settings.default_cross_post_to?(:facebook) && pending?) or fb_delayed_job_id?) unless facebook_id?
83
+ self.tumblr_me ||= ((Settings.default_cross_post_to?(:tumblr) && pending?) or tumblr_delayed_job_id?) unless tumblr_id?
84
+ rescue
85
+ end
86
+ end
87
+
88
+ def set_diary
89
+ # Set diary as default location
90
+ if pending? or new_record? and respond_to?(:location_list) and location_list.empty?
91
+ location_list << Settings.tags.posts.location.first
92
+ end
93
+ end
94
+
95
+ before_save :push_publication
96
+ after_save :push_to_social
97
+
98
+ def push_publication
99
+ # If have just been saved as published then do do_publish to post to twitter/fb etc
100
+ do_publish if (state_changed? and published?) or (!state_changed? and published_at_changed?)
101
+ end
102
+
103
+ def push_to_social
104
+ # Atreides::Post to social networks
105
+ social_cross_posts if published? and (tw_me or fb_me or tumblr_me)
106
+ end
107
+
108
+ #
109
+ # Class Methods
110
+ #
111
+ class << self
112
+
113
+ def next(post)
114
+ with_exclusive_scope {
115
+ # Due to problems with the default_scope ordering the 'live' scope must come AFTER the order scope
116
+ where("published_at >= ? and id != ?", post.published_at, post.id).order("published_at asc, id asc").live.first
117
+ }
118
+ end
119
+
120
+ def previous(post)
121
+ with_exclusive_scope {
122
+ # Due to problems with the default_scope ordering the 'live' scope must come AFTER the order scope
123
+ where("published_at <= ? and id != ?", post.published_at, post.id).order("published_at desc, id desc").live.first
124
+ }
125
+ end
126
+
127
+ def next_month(month = Date.today.month)
128
+ p = self.live.first(:conditions => ["EXTRACT(MONTH from published_at) > ?", month.to_i], :order => "published_at asc, id desc")
129
+ p ? p.published_at.month : nil
130
+ end
131
+
132
+ def previous_month(month = Date.today.month)
133
+ p = self.live.first(:conditions => ["EXTRACT(MONTH from published_at) < ?", month.to_i], :order => "published_at desc, id desc")
134
+ p ? p.published_at.month : nil
135
+ end
136
+
137
+ def base_class
138
+ self
139
+ end
140
+ end
141
+
142
+ #
143
+ # Instance Methods
144
+ #
145
+ def to_param
146
+ # Used for urls like /posts/:id/:slug
147
+ id.to_s
148
+ end
149
+
150
+ def next
151
+ @_next ||= self.class.next(self)
152
+ end
153
+
154
+ def previous
155
+ @_previous ||= self.class.previous(self)
156
+ end
157
+
158
+ def related_posts
159
+ # Don't recalc twice
160
+ return @related_posts unless @related_posts.nil?
161
+
162
+ max = 6
163
+ @related_posts = []
164
+ @related_posts += Atreides::Post.live.tagged_with(tag_list, :match_all => :true).all(:conditions => ["posts.id not in (?)", [id]], :limit => max) rescue []
165
+ @related_posts += Atreides::Post.live.tagged_with(tag_list, :any => :true).all(:conditions => ["posts.id not in (?)", @related_posts.map(&:id)+[id]], :limit => max - @related_posts.size) if @related_posts.size < max rescue []
166
+ @related_posts.uniq!
167
+ @related_posts += Atreides::Post.live.all(:conditions => ["posts.id not in (?)", @related_posts.map(&:id)+[id]], :limit => max - @related_posts.size) if @related_posts.size < max rescue []
168
+ @related_posts
169
+ end
170
+
171
+ # Return the first found text/video/photo
172
+ def first_body
173
+ (part = parts.where(:content_type => :text).detect{|p| p.body? }) ? part.body : ""
174
+ end
175
+ alias_method :body, :first_body
176
+
177
+ def first_photo
178
+ (part = parts.where(:content_type => :photos).detect{|p| !p.photos.first.nil? }) ? part.photos.first : nil
179
+ end
180
+ alias_method :photo, :first_photo
181
+
182
+ def first_video
183
+ (part = parts.where(:content_type => :videos).detect{|p| !p.videos.first.nil? }) ? part.videos.first : nil
184
+ end
185
+ alias_method :video, :first_video
186
+
187
+ # Return the first found photo
188
+ def thumbnail(size = :thumb)
189
+ # Find the first thumbnail image
190
+ url = if first_photo
191
+ first_photo.image.url(size)
192
+ elsif first_video
193
+ first_video.thumb_url
194
+ end
195
+
196
+ # FIXME: THIS NEEDS TO BE MOVED TO A VIEW/PRESENTER/DECORATOR
197
+ # asset_path('atreides/missing_thumb.png')
198
+
199
+ url || "/images/missing_thumb.png"
200
+ end
201
+
202
+
203
+ def update_twitter_id(twitter_id)
204
+ self.twitter_id = twitter_id
205
+ save
206
+ end
207
+
208
+ def update_facebook_id(facebook_id)
209
+ self.facebook_id = facebook_id
210
+ save
211
+ end
212
+
213
+ def update_tumblr_id(tumblr_id)
214
+ self.tumblr_id = tumblr_id
215
+ save
216
+ end
217
+
218
+ def post_types
219
+ @post_types ||= parts.map {|part| part.content_type}
220
+ end
221
+
222
+ def slug=(value)
223
+ # Do not let id based slugs through
224
+ write_attribute(:slug, value.to_s.match(/^\d+$/) ? nil : value)
225
+ end
226
+
227
+ # Make social posting flags understand booleans and form submitted num booleans
228
+ def tw_me=(value)
229
+ @tw_me = (value.is_a?(TrueClass) || value.is_a?(FalseClass)) ? value : !value.to_i.zero?
230
+ end
231
+
232
+ def fb_me=(value)
233
+ @fb_me = (value.is_a?(TrueClass) || value.is_a?(FalseClass)) ? value : !value.to_i.zero?
234
+ end
235
+
236
+ def tumblr_me=(value)
237
+ @tumblr_me = (value.is_a?(TrueClass) || value.is_a?(FalseClass)) ? value : !value.to_i.zero?
238
+ end
239
+
240
+ private
241
+
242
+ def content_parts
243
+ errors.add(:parts, "cannot be empty. Add some content!") if parts.empty? and published?
244
+ end
245
+
246
+ def do_publish(msg = nil)
247
+ self.published_at = Time.zone.now if published_at.nil?
248
+ end
249
+
250
+ def social_cross_posts
251
+ %w(tw fb).each do |prefix|
252
+ next unless self.send("#{prefix}_me")
253
+
254
+ assoc = "#{prefix}_delayed_job"
255
+
256
+ # No Delayed Job id set or is failed? Then create one.
257
+ if !self.send("#{assoc}_id?") or (self.send(assoc) and self.send(assoc).failed_at?)
258
+ # Create new instance of class that will post to the soc network
259
+ job = "#{prefix.capitalize}PostPublisherJob".constantize.new(self.id)
260
+ dj = ::Delayed::Job.enqueue :payload_object => job, :priority => 0, :run_at => self.published_at
261
+ self.send("#{assoc}=", dj)
262
+
263
+ # If already got a delayed job awaiting, then update the exec date
264
+ elsif self.send(assoc) and self.send(assoc).run_at != self.published_at
265
+ self.send(assoc).update_attribute(:run_at, self.published_at)
266
+ end
267
+ end
268
+ end
269
+
270
+ include Atreides::Extendable
271
+ end