publify_core 9.0.0.pre1

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 (372) hide show
  1. checksums.yaml +7 -0
  2. data/MIT-LICENSE +21 -0
  3. data/README.rdoc +3 -0
  4. data/Rakefile +35 -0
  5. data/app/assets/fonts/open-sans-bold.woff +0 -0
  6. data/app/assets/fonts/open-sans.woff +0 -0
  7. data/app/assets/images/admin/loading.gif +0 -0
  8. data/app/assets/images/admin/typologo.gif +0 -0
  9. data/app/assets/images/calendar_date_select/calendar.gif +0 -0
  10. data/app/assets/images/close.gif +0 -0
  11. data/app/assets/images/closelabel.gif +0 -0
  12. data/app/assets/images/go.png +0 -0
  13. data/app/assets/images/loading.gif +0 -0
  14. data/app/assets/images/nextlabel.gif +0 -0
  15. data/app/assets/images/overlay.png +0 -0
  16. data/app/assets/images/powered.gif +0 -0
  17. data/app/assets/images/prevlabel.gif +0 -0
  18. data/app/assets/images/spinner-blue.gif +0 -0
  19. data/app/assets/images/spinner.gif +0 -0
  20. data/app/assets/images/thumb_blank.jpg +0 -0
  21. data/app/assets/javascripts/application.js +2 -0
  22. data/app/assets/javascripts/cookies.js +60 -0
  23. data/app/assets/javascripts/datetimepicker.js +1470 -0
  24. data/app/assets/javascripts/lang/da_DK.js +17 -0
  25. data/app/assets/javascripts/lang/default.js +21 -0
  26. data/app/assets/javascripts/lang/en_US.js +21 -0
  27. data/app/assets/javascripts/lang/fr_FR.js +21 -0
  28. data/app/assets/javascripts/lang/nl_NL.js +21 -0
  29. data/app/assets/javascripts/lang/zh_TW.js +17 -0
  30. data/app/assets/javascripts/lightbox.js +350 -0
  31. data/app/assets/javascripts/observe.js +28 -0
  32. data/app/assets/javascripts/publify.js +11 -0
  33. data/app/assets/javascripts/publify_admin.js +138 -0
  34. data/app/assets/javascripts/quicktags.js +440 -0
  35. data/app/assets/javascripts/set-timeago-lang.js +3 -0
  36. data/app/assets/javascripts/sidebar.js +28 -0
  37. data/app/assets/javascripts/spinnable.js +5 -0
  38. data/app/assets/javascripts/tagmanager.js +481 -0
  39. data/app/assets/javascripts/typeahead.js +1139 -0
  40. data/app/assets/javascripts/widearea.js +486 -0
  41. data/app/assets/stylesheets/accounts.css.scss +7 -0
  42. data/app/assets/stylesheets/administration_structure.css.scss +239 -0
  43. data/app/assets/stylesheets/coderay.css +135 -0
  44. data/app/assets/stylesheets/datetimepicker.css +306 -0
  45. data/app/assets/stylesheets/lightbox.css +63 -0
  46. data/app/assets/stylesheets/publify.css.scss +9 -0
  47. data/app/assets/stylesheets/publify_admin.css.scss +11 -0
  48. data/app/assets/stylesheets/rss.css +53 -0
  49. data/app/assets/stylesheets/sidebar_admin.css.scss +36 -0
  50. data/app/assets/stylesheets/tagmanager.css +102 -0
  51. data/app/assets/stylesheets/user-styles.css +29 -0
  52. data/app/assets/stylesheets/widearea.css +133 -0
  53. data/app/controllers/accounts_controller.rb +2 -0
  54. data/app/controllers/admin/base_controller.rb +41 -0
  55. data/app/controllers/admin/cache_controller.rb +33 -0
  56. data/app/controllers/admin/content_controller.rb +174 -0
  57. data/app/controllers/admin/dashboard_controller.rb +87 -0
  58. data/app/controllers/admin/feedback_controller.rb +159 -0
  59. data/app/controllers/admin/migrations_controller.rb +20 -0
  60. data/app/controllers/admin/notes_controller.rb +69 -0
  61. data/app/controllers/admin/pages_controller.rb +88 -0
  62. data/app/controllers/admin/post_types_controller.rb +56 -0
  63. data/app/controllers/admin/profiles_controller.rb +48 -0
  64. data/app/controllers/admin/redirects_controller.rb +47 -0
  65. data/app/controllers/admin/resources_controller.rb +30 -0
  66. data/app/controllers/admin/seo_controller.rb +45 -0
  67. data/app/controllers/admin/settings_controller.rb +53 -0
  68. data/app/controllers/admin/sidebar_controller.rb +66 -0
  69. data/app/controllers/admin/tags_controller.rb +53 -0
  70. data/app/controllers/admin/textfilters_controller.rb +6 -0
  71. data/app/controllers/admin/themes_controller.rb +37 -0
  72. data/app/controllers/admin/users_controller.rb +65 -0
  73. data/app/controllers/articles_controller.rb +205 -0
  74. data/app/controllers/authors_controller.rb +27 -0
  75. data/app/controllers/base_controller.rb +45 -0
  76. data/app/controllers/comments_controller.rb +69 -0
  77. data/app/controllers/content_controller.rb +31 -0
  78. data/app/controllers/feedback_controller.rb +47 -0
  79. data/app/controllers/notes_controller.rb +37 -0
  80. data/app/controllers/setup_controller.rb +62 -0
  81. data/app/controllers/tags_controller.rb +55 -0
  82. data/app/controllers/text_controller.rb +9 -0
  83. data/app/controllers/textfilter_controller.rb +3 -0
  84. data/app/controllers/theme_controller.rb +59 -0
  85. data/app/controllers/trackbacks_controller.rb +36 -0
  86. data/app/controllers/xml_controller.rb +70 -0
  87. data/app/helpers/admin/base_helper.rb +87 -0
  88. data/app/helpers/admin/feedback_helper.rb +42 -0
  89. data/app/helpers/articles_helper.rb +8 -0
  90. data/app/helpers/authors_helper.rb +39 -0
  91. data/app/helpers/base_helper.rb +246 -0
  92. data/app/helpers/blog_helper.rb +12 -0
  93. data/app/helpers/xml_helper.rb +16 -0
  94. data/app/mailers/notification_mailer.rb +38 -0
  95. data/app/models/ability.rb +52 -0
  96. data/app/models/archives_sidebar.rb +45 -0
  97. data/app/models/article/factory.rb +56 -0
  98. data/app/models/article/states.rb +178 -0
  99. data/app/models/article.rb +321 -0
  100. data/app/models/blog.rb +290 -0
  101. data/app/models/blog_sweeper.rb +86 -0
  102. data/app/models/comment.rb +53 -0
  103. data/app/models/config_manager.rb +81 -0
  104. data/app/models/content.rb +138 -0
  105. data/app/models/content_base.rb +95 -0
  106. data/app/models/feedback/states.rb +256 -0
  107. data/app/models/feedback.rb +225 -0
  108. data/app/models/meta_sidebar.rb +8 -0
  109. data/app/models/note.rb +144 -0
  110. data/app/models/page.rb +36 -0
  111. data/app/models/page_cache.rb +33 -0
  112. data/app/models/page_sidebar.rb +12 -0
  113. data/app/models/ping.rb +116 -0
  114. data/app/models/post_type.rb +15 -0
  115. data/app/models/redirect.rb +45 -0
  116. data/app/models/redirection.rb +4 -0
  117. data/app/models/resource.rb +28 -0
  118. data/app/models/search_sidebar.rb +7 -0
  119. data/app/models/sidebar.rb +138 -0
  120. data/app/models/static_sidebar.rb +20 -0
  121. data/app/models/tag.rb +63 -0
  122. data/app/models/tag_sidebar.rb +27 -0
  123. data/app/models/text_filter.rb +61 -0
  124. data/app/models/trackback.rb +58 -0
  125. data/app/models/trigger.rb +45 -0
  126. data/app/models/user.rb +148 -0
  127. data/app/services/migrator.rb +25 -0
  128. data/app/services/title_builder.rb +80 -0
  129. data/app/uploaders/resource_uploader.rb +30 -0
  130. data/app/views/accounts/confirm.html.erb +8 -0
  131. data/app/views/admin/cache/show.html.erb +18 -0
  132. data/app/views/admin/content/_article_list.html.erb +26 -0
  133. data/app/views/admin/content/_form.html.erb +165 -0
  134. data/app/views/admin/content/autosave.js.erb +5 -0
  135. data/app/views/admin/content/edit.html.erb +3 -0
  136. data/app/views/admin/content/index.html.erb +48 -0
  137. data/app/views/admin/content/index.js.erb +1 -0
  138. data/app/views/admin/content/new.html.erb +3 -0
  139. data/app/views/admin/dashboard/_comment.html.erb +18 -0
  140. data/app/views/admin/dashboard/_comments.html.erb +10 -0
  141. data/app/views/admin/dashboard/_drafts.html.erb +25 -0
  142. data/app/views/admin/dashboard/_inbound.html.erb +31 -0
  143. data/app/views/admin/dashboard/_overview.html.erb +23 -0
  144. data/app/views/admin/dashboard/_welcome.html.erb +28 -0
  145. data/app/views/admin/dashboard/index.html.erb +17 -0
  146. data/app/views/admin/feedback/_button.html.erb +19 -0
  147. data/app/views/admin/feedback/_feedback.html.erb +7 -0
  148. data/app/views/admin/feedback/_ham.html.erb +17 -0
  149. data/app/views/admin/feedback/_spam.html.erb +23 -0
  150. data/app/views/admin/feedback/article.html.erb +69 -0
  151. data/app/views/admin/feedback/edit.html.erb +48 -0
  152. data/app/views/admin/feedback/ham.js +1 -0
  153. data/app/views/admin/feedback/index.html.erb +53 -0
  154. data/app/views/admin/feedback/spam.js +1 -0
  155. data/app/views/admin/migrations/show.html.erb +39 -0
  156. data/app/views/admin/notes/_form.html.erb +37 -0
  157. data/app/views/admin/notes/_header.html.erb +6 -0
  158. data/app/views/admin/notes/_list.html.erb +13 -0
  159. data/app/views/admin/notes/_note.html.erb +14 -0
  160. data/app/views/admin/notes/edit.html.erb +11 -0
  161. data/app/views/admin/notes/index.html.erb +11 -0
  162. data/app/views/admin/notes/show.html.erb +14 -0
  163. data/app/views/admin/pages/_form.html.erb +101 -0
  164. data/app/views/admin/pages/_pages.html.erb +21 -0
  165. data/app/views/admin/pages/edit.html.erb +1 -0
  166. data/app/views/admin/pages/index.html.erb +17 -0
  167. data/app/views/admin/pages/new.html.erb +1 -0
  168. data/app/views/admin/post_types/_index_and_form.html.erb +65 -0
  169. data/app/views/admin/post_types/edit.html.erb +1 -0
  170. data/app/views/admin/post_types/index.html.erb +1 -0
  171. data/app/views/admin/profiles/index.html.erb +10 -0
  172. data/app/views/admin/redirects/_index_and_form.html.erb +68 -0
  173. data/app/views/admin/redirects/edit.html.erb +1 -0
  174. data/app/views/admin/redirects/index.html.erb +1 -0
  175. data/app/views/admin/resources/index.html.erb +68 -0
  176. data/app/views/admin/seo/_general.html.erb +123 -0
  177. data/app/views/admin/seo/_permalinks.html.erb +53 -0
  178. data/app/views/admin/seo/_titles.html.erb +210 -0
  179. data/app/views/admin/seo/show.html.erb +32 -0
  180. data/app/views/admin/settings/display.html.erb +110 -0
  181. data/app/views/admin/settings/feedback.html.erb +125 -0
  182. data/app/views/admin/settings/index.html.erb +73 -0
  183. data/app/views/admin/settings/write.html.erb +87 -0
  184. data/app/views/admin/shared/_edit.html.erb +4 -0
  185. data/app/views/admin/shared/_menu.html.erb +122 -0
  186. data/app/views/admin/shared/_twitter_alert.html.erb +3 -0
  187. data/app/views/admin/sidebar/_available.html.erb +6 -0
  188. data/app/views/admin/sidebar/_available.json.erb +6 -0
  189. data/app/views/admin/sidebar/_config.html.erb +27 -0
  190. data/app/views/admin/sidebar/_target.html.erb +9 -0
  191. data/app/views/admin/sidebar/_target_sidebar.html.erb +20 -0
  192. data/app/views/admin/sidebar/destroy.js.erb +1 -0
  193. data/app/views/admin/sidebar/index.html.erb +31 -0
  194. data/app/views/admin/sidebar/sortable.js.erb +3 -0
  195. data/app/views/admin/sidebar/update.js.erb +2 -0
  196. data/app/views/admin/tags/_index_and_form.html.erb +59 -0
  197. data/app/views/admin/tags/edit.html.erb +1 -0
  198. data/app/views/admin/tags/index.html.erb +1 -0
  199. data/app/views/admin/themes/index.html.erb +27 -0
  200. data/app/views/admin/users/_form.html.erb +215 -0
  201. data/app/views/admin/users/edit.html.erb +8 -0
  202. data/app/views/admin/users/index.html.erb +39 -0
  203. data/app/views/admin/users/new.html.erb +8 -0
  204. data/app/views/archives_sidebar/_content.html.erb +13 -0
  205. data/app/views/articles/_article.html.erb +9 -0
  206. data/app/views/articles/_article_collection.html.erb +8 -0
  207. data/app/views/articles/_article_content.html.erb +5 -0
  208. data/app/views/articles/_article_excerpt.html.erb +13 -0
  209. data/app/views/articles/_article_links.html.erb +10 -0
  210. data/app/views/articles/_comment.html.erb +1 -0
  211. data/app/views/articles/_comment_errors.html.erb +2 -0
  212. data/app/views/articles/_comment_form.html.erb +48 -0
  213. data/app/views/articles/_comment_list.html.erb +5 -0
  214. data/app/views/articles/_comment_preview.html.erb +4 -0
  215. data/app/views/articles/_full_article_content.html.erb +2 -0
  216. data/app/views/articles/_password_form.html.erb +10 -0
  217. data/app/views/articles/_protected_article_content.html.erb +6 -0
  218. data/app/views/articles/_trackback.html.erb +6 -0
  219. data/app/views/articles/archives.html.erb +25 -0
  220. data/app/views/articles/comment.js.erb +5 -0
  221. data/app/views/articles/comment_failed.js.erb +3 -0
  222. data/app/views/articles/error.html.erb +3 -0
  223. data/app/views/articles/feedback_atom_feed.atom.builder +8 -0
  224. data/app/views/articles/feedback_rss_feed.rss.builder +21 -0
  225. data/app/views/articles/index.html.erb +1 -0
  226. data/app/views/articles/index_atom_feed.atom.builder +8 -0
  227. data/app/views/articles/index_rss_feed.rss.builder +20 -0
  228. data/app/views/articles/live_search.html.erb +10 -0
  229. data/app/views/articles/read.html.erb +61 -0
  230. data/app/views/articles/search.html.erb +8 -0
  231. data/app/views/articles/trackback.xml.builder +5 -0
  232. data/app/views/articles/view_page.html.erb +3 -0
  233. data/app/views/authors/show.html.erb +40 -0
  234. data/app/views/authors/show_atom_feed.atom.builder +8 -0
  235. data/app/views/authors/show_rss_feed.rss.builder +20 -0
  236. data/app/views/comments/_comment.html.erb +16 -0
  237. data/app/views/comments/index.html.erb +1 -0
  238. data/app/views/comments/index_atom_feed.atom.builder +8 -0
  239. data/app/views/comments/index_rss_feed.rss.builder +20 -0
  240. data/app/views/comments/preview.html.erb +1 -0
  241. data/app/views/comments/preview.js.erb +3 -0
  242. data/app/views/devise/mailer/reset_password_instructions.html.erb +13 -0
  243. data/app/views/devise/passwords/edit.html.erb +28 -0
  244. data/app/views/devise/passwords/new.html.erb +20 -0
  245. data/app/views/devise/registrations/new.html.erb +36 -0
  246. data/app/views/devise/sessions/new.html.erb +32 -0
  247. data/app/views/devise/shared/_links.html.erb +15 -0
  248. data/app/views/errors/404.html.erb +2 -0
  249. data/app/views/layouts/accounts.html.erb +33 -0
  250. data/app/views/layouts/administration.html.erb +37 -0
  251. data/app/views/layouts/default.html.erb +32 -0
  252. data/app/views/layouts/editor.html.erb +31 -0
  253. data/app/views/meta_sidebar/_content.html.erb +8 -0
  254. data/app/views/notes/_note.html.erb +15 -0
  255. data/app/views/notes/error.html.erb +3 -0
  256. data/app/views/notes/index.html.erb +15 -0
  257. data/app/views/notes/show.html.erb +5 -0
  258. data/app/views/notes/show_in_reply.html.erb +16 -0
  259. data/app/views/notification_mailer/_mail_footer.html.erb +7 -0
  260. data/app/views/notification_mailer/_mail_header.html.erb +1 -0
  261. data/app/views/notification_mailer/article.html.erb +6 -0
  262. data/app/views/notification_mailer/comment.html.erb +11 -0
  263. data/app/views/notification_mailer/notif_user.html.erb +14 -0
  264. data/app/views/page_sidebar/_content.html.erb +12 -0
  265. data/app/views/search_sidebar/_content.html.erb +10 -0
  266. data/app/views/settings/done.html.erb +2 -0
  267. data/app/views/settings/install.html.erb +12 -0
  268. data/app/views/setup/index.html.erb +13 -0
  269. data/app/views/shared/_atom_header.atom.builder +6 -0
  270. data/app/views/shared/_atom_item_article.atom.builder +39 -0
  271. data/app/views/shared/_atom_item_comment.atom.builder +10 -0
  272. data/app/views/shared/_atom_item_trackback.atom.builder +9 -0
  273. data/app/views/shared/_flash.erb +10 -0
  274. data/app/views/shared/_page_header.html.erb +26 -0
  275. data/app/views/shared/_rss_item_article.rss.builder +35 -0
  276. data/app/views/shared/_rss_item_comment.rss.builder +8 -0
  277. data/app/views/shared/_rss_item_trackback.rss.builder +7 -0
  278. data/app/views/sidebar/_row.html.erb +1 -0
  279. data/app/views/sidebar/_sidebar.html.erb +5 -0
  280. data/app/views/sidebar/display_plugins.html.erb +5 -0
  281. data/app/views/sidebar/show.html.erb +1 -0
  282. data/app/views/static_sidebar/_content.html.erb +2 -0
  283. data/app/views/tag_sidebar/_content.html.erb +10 -0
  284. data/app/views/tags/index.html.erb +15 -0
  285. data/app/views/tags/show.html.erb +1 -0
  286. data/app/views/theme/static_view_test.html.erb +1 -0
  287. data/app/views/trackbacks/index_atom_feed.atom.builder +7 -0
  288. data/app/views/trackbacks/index_rss_feed.rss.builder +20 -0
  289. data/app/views/trackbacks/trackback.xml.builder +4 -0
  290. data/app/views/xml/_googlesitemap_item_article.googlesitemap.builder +5 -0
  291. data/app/views/xml/_googlesitemap_item_category.googlesitemap.builder +4 -0
  292. data/app/views/xml/_googlesitemap_item_page.googlesitemap.builder +4 -0
  293. data/app/views/xml/_googlesitemap_item_tag.googlesitemap.builder +4 -0
  294. data/app/views/xml/feed.googlesitemap.builder +7 -0
  295. data/app/views/xml/rsd.rsd.builder +8 -0
  296. data/config/i18n-tasks.yml +49 -0
  297. data/config/initializers/devise.rb +265 -0
  298. data/config/initializers/mime_types.rb +6 -0
  299. data/config/locales/da.yml +827 -0
  300. data/config/locales/de.yml +827 -0
  301. data/config/locales/en.yml +827 -0
  302. data/config/locales/es-MX.yml +827 -0
  303. data/config/locales/fr.yml +827 -0
  304. data/config/locales/he.yml +827 -0
  305. data/config/locales/it.yml +827 -0
  306. data/config/locales/ja.yml +827 -0
  307. data/config/locales/lt.yml +827 -0
  308. data/config/locales/nb-NO.yml +827 -0
  309. data/config/locales/nl.yml +827 -0
  310. data/config/locales/pl.yml +827 -0
  311. data/config/locales/pt-BR.yml +827 -0
  312. data/config/locales/ro.yml +827 -0
  313. data/config/locales/ru.yml +827 -0
  314. data/config/locales/sidebars.da.yml +20 -0
  315. data/config/locales/sidebars.de.yml +20 -0
  316. data/config/locales/sidebars.en.yml +20 -0
  317. data/config/locales/sidebars.es-MX.yml +20 -0
  318. data/config/locales/sidebars.fr.yml +20 -0
  319. data/config/locales/sidebars.he.yml +20 -0
  320. data/config/locales/sidebars.it.yml +20 -0
  321. data/config/locales/sidebars.ja.yml +20 -0
  322. data/config/locales/sidebars.lt.yml +20 -0
  323. data/config/locales/sidebars.nb-NO.yml +20 -0
  324. data/config/locales/sidebars.nl.yml +20 -0
  325. data/config/locales/sidebars.pl.yml +20 -0
  326. data/config/locales/sidebars.pt-BR.yml +20 -0
  327. data/config/locales/sidebars.ro.yml +20 -0
  328. data/config/locales/sidebars.ru.yml +20 -0
  329. data/config/locales/sidebars.zh-CN.yml +20 -0
  330. data/config/locales/sidebars.zh-TW.yml +20 -0
  331. data/config/locales/zh-CN.yml +827 -0
  332. data/config/locales/zh-TW.yml +827 -0
  333. data/config/routes.rb +177 -0
  334. data/db/migrate/113_initial_schema.rb +205 -0
  335. data/db/migrate/114_fixes_buggy_articles_and_notes.rb +52 -0
  336. data/db/migrate/115_drops_categories_for_tags.rb +34 -0
  337. data/db/migrate/20150207131657_add_missing_indexes.rb +19 -0
  338. data/db/migrate/20150807134129_simplify_redirect_relations.rb +38 -0
  339. data/db/migrate/20150808052637_add_blog_ids.rb +33 -0
  340. data/db/migrate/20150808191127_add_blog_id_to_redirects.rb +15 -0
  341. data/db/migrate/20150810094754_add_blog_id_to_tags.rb +15 -0
  342. data/db/migrate/20160108111120_add_devise_to_users.rb +53 -0
  343. data/db/migrate/20160108184201_move_last_connection_to_last_sign_in_at.rb +16 -0
  344. data/db/migrate/20160110094906_remove_profiles_rights.rb +14 -0
  345. data/db/migrate/20160605103918_replace_profile_id_with_string.rb +30 -0
  346. data/db/migrate/20160605154632_remove_profiles.rb +24 -0
  347. data/db/migrate/20160701061851_demand_blog_id_on_contents.rb +9 -0
  348. data/db/migrate/20160701062604_add_blog_id_to_resources.rb +28 -0
  349. data/db/seeds.rb +37 -0
  350. data/lib/email_notify.rb +26 -0
  351. data/lib/format.rb +17 -0
  352. data/lib/publify_core/engine.rb +23 -0
  353. data/lib/publify_core/lang.rb +5 -0
  354. data/lib/publify_core/version.rb +3 -0
  355. data/lib/publify_core.rb +56 -0
  356. data/lib/publify_guid.rb +9 -0
  357. data/lib/publify_plugins.rb +72 -0
  358. data/lib/publify_textfilter_markdown.rb +44 -0
  359. data/lib/publify_textfilter_none.rb +14 -0
  360. data/lib/publify_textfilter_smartypants.rb +14 -0
  361. data/lib/publify_textfilter_textile.rb +21 -0
  362. data/lib/publify_textfilter_twitterfilter.rb +33 -0
  363. data/lib/publify_time.rb +30 -0
  364. data/lib/sidebar_field.rb +115 -0
  365. data/lib/sidebar_registry.rb +33 -0
  366. data/lib/spam_protection.rb +101 -0
  367. data/lib/stateful.rb +106 -0
  368. data/lib/tasks/publify_core_tasks.rake +4 -0
  369. data/lib/text_filter_plugin.rb +182 -0
  370. data/lib/theme.rb +72 -0
  371. data/lib/transforms.rb +45 -0
  372. metadata +865 -0
@@ -0,0 +1,246 @@
1
+ # coding: utf-8
2
+ # Methods added to this helper will be available to all templates in the application.
3
+ require 'digest/sha1'
4
+
5
+ module BaseHelper
6
+ include BlogHelper
7
+
8
+ # Need to rewrite this one, quick hack to test my changes.
9
+ attr_reader :page_title
10
+
11
+ def render_sidebars(*sidebars)
12
+ rendered_sidebars = (sidebars.blank? ? Sidebar.order(:active_position) : sidebars).map do |sb|
13
+ @sidebar = sb
14
+ sb.parse_request(content_array, params)
15
+ render_sidebar(sb)
16
+ end
17
+ safe_join rendered_sidebars
18
+ rescue => e
19
+ logger.error e
20
+ logger.error e.backtrace.join("\n")
21
+ I18n.t('errors.render_sidebar')
22
+ end
23
+
24
+ def render_sidebar(sidebar)
25
+ render_to_string(partial: sidebar.content_partial, locals: sidebar.to_locals_hash, layout: false)
26
+ end
27
+
28
+ def themeable_stylesheet_link_tag(name)
29
+ src = this_blog.current_theme.path + "/stylesheets/#{name}.css"
30
+ stylesheet_link_tag "/stylesheets/theme/#{name}.css" if File.exist? src
31
+ end
32
+
33
+ def render_to_string(*args, &block)
34
+ controller.send(:render_to_string, *args, &block)
35
+ end
36
+
37
+ def link_to_permalink(item, title, anchor = nil, style = nil, nofollow = nil, only_path = false)
38
+ options = {}
39
+ options[:class] = style if style
40
+ options[:rel] = 'nofollow' if nofollow
41
+ link_to title, item.permalink_url(anchor, only_path), options
42
+ end
43
+
44
+ def avatar_tag(options = {})
45
+ begin
46
+ avatar_class = this_blog.plugin_avatar.constantize
47
+ rescue NameError
48
+ return ''
49
+ end
50
+ return '' unless avatar_class.respond_to?(:get_avatar)
51
+ avatar_class.get_avatar(options)
52
+ end
53
+
54
+ def meta_tag(name, value)
55
+ tag :meta, name: name, content: value unless value.blank?
56
+ end
57
+
58
+ def markup_help_popup(markup, text)
59
+ if markup && markup.commenthelp.size > 1
60
+ link_to text, url_for(controller: 'articles', action: 'markup_help', id: markup.id), onclick: "return popup(this, 'Publify Markup Help')"
61
+ else
62
+ ''
63
+ end
64
+ end
65
+
66
+ def onhover_show_admin_tools(type, id = nil)
67
+ admin_id = "#admin_#{[type, id].compact.join('_')}"
68
+ tag = []
69
+ tag << %{ onmouseover="if (getCookie('publify_user_profile') == 'admin') { $('#{admin_id}').show(); }" }
70
+ tag << %{ onmouseout="$('#{admin_id}').hide();" }
71
+ safe_join(tag, ' ')
72
+ end
73
+
74
+ def feed_title
75
+ if @feed_title.present?
76
+ @feed_title
77
+ elsif @page_title.present?
78
+ @page_title
79
+ else
80
+ this_blog.blog_name
81
+ end
82
+ end
83
+
84
+ def html(content, what = :all, _deprecated = false)
85
+ content.html(what)
86
+ end
87
+
88
+ def display_user_avatar(user, size = 'avatar', klass = 'alignleft')
89
+ if user.resource.present?
90
+ avatar_path = case size
91
+ when 'thumb'
92
+ user.resource.upload.thumb.url
93
+ when 'medium'
94
+ user.resource.upload.medium.url
95
+ when 'large'
96
+ user.resource.upload.large.url
97
+ else
98
+ user.resource.upload.avatar.url
99
+ end
100
+ return if avatar_path.nil?
101
+ avatar_url = File.join(this_blog.base_url, avatar_path)
102
+ elsif user.twitter_profile_image.present?
103
+ avatar_url = user.twitter_profile_image
104
+ end
105
+ return unless avatar_url
106
+ image_tag(avatar_url, alt: user.nickname, class: klass)
107
+ end
108
+
109
+ def author_picture(status)
110
+ return if status.user.twitter_profile_image.blank?
111
+
112
+ image_tag(status.user.twitter_profile_image, class: 'alignleft', alt: status.user.nickname)
113
+ end
114
+
115
+ def google_analytics
116
+ unless this_blog.google_analytics.empty?
117
+ <<-HTML
118
+ <script type="text/javascript">
119
+ var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www.");
120
+ document.write(unescape("%3Cscript src='" + gaJsHost + "google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E"));
121
+ </script>
122
+ <script type="text/javascript">
123
+ var pageTracker = _gat._getTracker("#{this_blog.google_analytics}");
124
+ pageTracker._trackPageview();
125
+ </script>
126
+ HTML
127
+ end
128
+ end
129
+
130
+ def page_header_includes
131
+ content_array.map(&:whiteboard).map do |w|
132
+ w.select { |k, _v| k =~ /^page_header_/ }.map do |_, v|
133
+ v = v.chomp
134
+ # trim the same number of spaces from the beginning of each line
135
+ # this way plugins can indent nicely without making ugly source output
136
+ spaces = /\A[ \t]*/.match(v)[0].gsub(/\t/, ' ')
137
+ v.gsub!(/^#{spaces}/, ' ') # add 2 spaces to line up with the assumed position of the surrounding tags
138
+ end
139
+ end.flatten.uniq.join("\n")
140
+ end
141
+
142
+ def feed_atom
143
+ feed_for('atom')
144
+ end
145
+
146
+ def feed_rss
147
+ feed_for('rss')
148
+ end
149
+
150
+ def content_array
151
+ if @articles
152
+ @articles
153
+ elsif @article
154
+ [@article]
155
+ elsif @page
156
+ [@page]
157
+ else
158
+ []
159
+ end
160
+ end
161
+
162
+ def display_date(date)
163
+ l(date, format: this_blog.date_format)
164
+ end
165
+
166
+ def display_time(time)
167
+ time.strftime(this_blog.time_format)
168
+ end
169
+
170
+ def display_date_and_time(timestamp)
171
+ if this_blog.date_format == 'setting_date_format_distance_of_time_in_words'
172
+ timeago_tag timestamp, date_only: false
173
+ else
174
+ "#{display_date(timestamp)} #{t('helper.at')} #{display_time(timestamp)}"
175
+ end
176
+ end
177
+
178
+ def show_meta_keyword
179
+ return unless this_blog.use_meta_keyword
180
+ meta_tag 'keywords', @keywords unless @keywords.blank?
181
+ end
182
+
183
+ def stop_index_robots?(blog)
184
+ stop = (params[:year].present? || params[:page].present?)
185
+ stop = blog.unindex_tags if controller_name == 'tags'
186
+ stop = blog.unindex_categories if controller_name == 'categories'
187
+ stop
188
+ end
189
+
190
+ def get_reply_context_url(reply)
191
+ link_to(reply['user']['name'], reply['user']['entities']['url']['urls'][0]['expanded_url'])
192
+ rescue
193
+ link_to(reply['user']['name'], "https://twitter.com/#{reply['user']['name']}")
194
+ end
195
+
196
+ def get_reply_context_twitter_link(reply)
197
+ link_to(display_date_and_time(reply['created_at'].to_time.in_time_zone),
198
+ "https://twitter.com/#{reply['user']['screen_name']}/status/#{reply['id_str']}")
199
+ end
200
+
201
+ private
202
+
203
+ def feed_for(type)
204
+ if params[:action] == 'search'
205
+ url_for(only_path: false, format: type, q: params[:q])
206
+ elsif !@article.nil?
207
+ @article.feed_url(type)
208
+ elsif !@auto_discovery_url_atom.nil?
209
+ instance_variable_get("@auto_discovery_url_#{type}")
210
+ end
211
+ end
212
+
213
+ # fetches appropriate html content for RSS and ATOM feeds. Checks for:
214
+ # - article being password protected
215
+ # - hiding extended content on RSS. In this case if there is an excerpt we
216
+ # show the excerpt, or else we show the body
217
+ def fetch_html_content_for_feeds(item, this_blog)
218
+ if item.password_protected?
219
+ "<p>This article is password protected. Please <a href='#{item.permalink_url}'>fill in your password</a> to read it</p>"
220
+ elsif this_blog.hide_extended_on_rss
221
+ if item.excerpt? && !item.excerpt.empty?
222
+ item.excerpt
223
+ else
224
+ html(item, :body)
225
+ end
226
+ else
227
+ html(item, :all)
228
+ end
229
+ end
230
+
231
+ def nofollowify_links(string)
232
+ if this_blog.dofollowify
233
+ string
234
+ else
235
+ string.gsub(/<a(.*?)>/i, '<a\1 rel="nofollow">')
236
+ end
237
+ end
238
+
239
+ def nofollowified_link_to(text, url)
240
+ if this_blog.dofollowify
241
+ link_to(text, url)
242
+ else
243
+ link_to(text, url, rel: 'nofollow')
244
+ end
245
+ end
246
+ end
@@ -0,0 +1,12 @@
1
+ module BlogHelper
2
+ # The base URL for this request, calculated by looking up the URL for the main
3
+ # blog index page.
4
+ def blog_base_url
5
+ url_for(controller: '/articles', action: 'index').gsub(%r{/$}, '')
6
+ end
7
+
8
+ # Find the blog whose base_url matches the current location.
9
+ def this_blog
10
+ @blog ||= Blog.find_blog(blog_base_url)
11
+ end
12
+ end
@@ -0,0 +1,16 @@
1
+ module XmlHelper
2
+ def collection_lastmod(collection)
3
+ article_updated = collection.articles.order(updated_at: :desc).first
4
+ article_published = collection.articles.order(published_at: :desc).first
5
+
6
+ times = []
7
+ times.push article_updated.updated_at if article_updated
8
+ times.push article_published.updated_at if article_published
9
+
10
+ if times.empty?
11
+ Time.at(0).xmlschema
12
+ else
13
+ times.max.xmlschema
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,38 @@
1
+ class NotificationMailer < ActionMailer::Base
2
+ helper :base
3
+ layout nil
4
+
5
+ def article(article, user)
6
+ @user = user
7
+ @blog = article.blog
8
+ @article = article
9
+ build_mail @blog, @user, "New article: #{article.title}"
10
+ end
11
+
12
+ def comment(comment, user)
13
+ @user = user
14
+ @blog = comment.blog
15
+ @comment = comment
16
+ build_mail @blog, @user, "New comment on #{comment.article.title}"
17
+ end
18
+
19
+ def notif_user(user)
20
+ @user = user
21
+ # TODO: Make user blog-dependent
22
+ @blog = Blog.first
23
+ build_mail @blog, @user, 'Welcome to Publify'
24
+ end
25
+
26
+ private
27
+
28
+ def make_subject(blog, subject)
29
+ "[#{blog.blog_name}] #{subject}"
30
+ end
31
+
32
+ def build_mail(blog, user, subject)
33
+ headers['X-Mailer'] = "Publify #{PublifyCore::VERSION}"
34
+ mail(from: blog.email_from,
35
+ to: user.email,
36
+ subject: make_subject(blog, subject))
37
+ end
38
+ end
@@ -0,0 +1,52 @@
1
+ require 'cancancan'
2
+
3
+ class Ability
4
+ include CanCan::Ability
5
+
6
+ def initialize(user)
7
+ return unless user
8
+
9
+ case user.profile
10
+ when 'admin'
11
+ add_admin_abilities
12
+ add_publisher_abilities
13
+ add_contributor_abilities
14
+ when 'publisher'
15
+ add_publisher_abilities
16
+ add_contributor_abilities
17
+ when 'contributor'
18
+ add_contributor_abilities
19
+ end
20
+ end
21
+
22
+ private
23
+
24
+ def add_admin_abilities
25
+ can :manage, 'admin/cache'
26
+ can :manage, 'admin/migrations'
27
+ can :manage, 'admin/seo'
28
+ can :manage, 'admin/settings'
29
+ can :manage, 'admin/sidebar'
30
+ can :manage, 'admin/textfilters'
31
+ can :manage, 'admin/themes'
32
+ can :manage, 'admin/users'
33
+ end
34
+
35
+ def add_publisher_abilities
36
+ can :manage, 'admin/content'
37
+ can :manage, 'admin/feedback'
38
+ can :manage, 'admin/notes'
39
+ can :manage, 'admin/pages'
40
+ can :manage, 'admin/post_types'
41
+ can :manage, 'admin/redirects'
42
+ can :manage, 'admin/resources'
43
+ can :manage, 'admin/tags'
44
+
45
+ can :manage, 'articles'
46
+ end
47
+
48
+ def add_contributor_abilities
49
+ can :manage, 'admin/dashboard'
50
+ can :manage, 'admin/profiles'
51
+ end
52
+ end
@@ -0,0 +1,45 @@
1
+ class ArchivesSidebar < Sidebar
2
+ description 'Displays links to monthly archives'
3
+ setting :title, 'Archives'
4
+ setting :show_count, true, label: 'Show article counts', input_type: :checkbox
5
+ setting :count, 10, label: 'Number of Months'
6
+
7
+ attr_accessor :archives
8
+
9
+ def self.date_func
10
+ @date_func ||=
11
+ begin
12
+ if Content.connection.is_a?(ActiveRecord::ConnectionAdapters::SQLite3Adapter)
13
+ "strftime('%Y', published_at) as year, strftime('%m', published_at) as month"
14
+ else
15
+ 'extract(year from published_at) as year,extract(month from published_at) as month'
16
+ end
17
+ rescue NameError
18
+ 'extract(year from published_at) as year,extract(month from published_at) as month'
19
+ end
20
+ end
21
+
22
+ def parse_request(_contents, _params)
23
+ # The original query that was here instantiated every article and every
24
+ # tag, and then sorted through them just to do a 'group by date'.
25
+ # Unfortunately, there's no universally-supported way to do this
26
+ # across all three of our supported DBs. So, we resort to a bit of
27
+ # DB-specific code.
28
+ date_func = self.class.date_func
29
+
30
+ article_counts = Content.find_by_sql(["select count(*) as count, #{date_func} from contents where type='Article' and published = ? and published_at < ? group by year,month order by year desc,month desc limit ? ", true, Time.now, count.to_i])
31
+
32
+ @archives = article_counts.map do |entry|
33
+ month = entry.month.to_i
34
+ year = entry.year.to_i
35
+ {
36
+ name: I18n.l(Date.new(year, month), format: '%B %Y'),
37
+ month: month,
38
+ year: year,
39
+ article_count: entry.count
40
+ }
41
+ end
42
+ end
43
+ end
44
+
45
+ SidebarRegistry.register_sidebar ArchivesSidebar
@@ -0,0 +1,56 @@
1
+ class Article::Factory
2
+ attr_reader :blog, :user
3
+
4
+ def initialize(blog, user)
5
+ @blog = blog
6
+ @user = user
7
+ end
8
+
9
+ def default
10
+ blog.articles.build.tap do |art|
11
+ art.allow_comments = blog.default_allow_comments
12
+ art.allow_pings = blog.default_allow_pings
13
+ art.text_filter = user.default_text_filter
14
+ art.published = true
15
+ end
16
+ end
17
+
18
+ def get_or_build_from(id)
19
+ return blog.articles.find(id) if id.present?
20
+ default
21
+ end
22
+
23
+ def match_permalink_format(path, format)
24
+ article_params = extract_params(path, format)
25
+ requested_article(article_params) if article_params
26
+ end
27
+
28
+ def requested_article(params = {})
29
+ params[:title] ||= params[:article_id]
30
+ Article.requested_article(params)
31
+ end
32
+
33
+ def extract_params(path, format)
34
+ specs = format.split('/')
35
+ specs.delete('')
36
+ parts = path.split('/')
37
+ parts.delete('')
38
+
39
+ return if parts.length != specs.length
40
+
41
+ specs.zip(parts).reduce({}) do |result, (spec, item)|
42
+ if spec =~ /(.*)%(.*)%(.*)/
43
+ before_format = Regexp.last_match[1]
44
+ format_string = Regexp.last_match[2]
45
+ after_format = Regexp.last_match[3]
46
+ item =~ /^#{before_format}(.*)#{after_format}$/
47
+ break unless Regexp.last_match
48
+ value = Regexp.last_match[1]
49
+ result[format_string.to_sym] = value
50
+ elsif spec != item
51
+ break
52
+ end
53
+ result
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,178 @@
1
+ module Article::States
2
+ class Base < Stateful::State
3
+ alias content model
4
+
5
+ def to_s
6
+ self.class.to_s.demodulize
7
+ end
8
+
9
+ def exit_hook(_target)
10
+ ::Rails.logger.debug("#{content} leaving state #{self.class}")
11
+ end
12
+
13
+ def enter_hook
14
+ ::Rails.logger.debug("#{content} entering state #{self.class}")
15
+ end
16
+
17
+ def post_trigger
18
+ true
19
+ end
20
+
21
+ def send_notifications
22
+ true
23
+ end
24
+
25
+ def send_pings
26
+ true
27
+ end
28
+
29
+ def withdraw
30
+ end
31
+ end
32
+
33
+ class New < Base
34
+ def enter_hook
35
+ super
36
+ content[:published] = false
37
+ content[:published_at] = nil
38
+ end
39
+
40
+ def published=(boolean)
41
+ content.state = :just_published if boolean
42
+ boolean
43
+ end
44
+
45
+ def published_at=(new_time)
46
+ unless new_time.nil?
47
+ content.state = new_time <= Time.new ? :just_published : :publication_pending
48
+ end
49
+ content[:published_at] = new_time
50
+ end
51
+
52
+ def draft?
53
+ true
54
+ end
55
+ end
56
+
57
+ class JustPublished < Base
58
+ def enter_hook
59
+ super
60
+ content.just_changed_published_status = true
61
+ content.state = :published
62
+ end
63
+ end
64
+
65
+ class Published < Base
66
+ def enter_hook
67
+ super
68
+ content[:published] = true
69
+ content[:published_at] ||= Time.now
70
+ end
71
+
72
+ def published=(boolean)
73
+ content.state = :just_withdrawn unless boolean
74
+ end
75
+
76
+ def withdraw
77
+ content.state = :just_withdrawn
78
+ end
79
+
80
+ def published_at=(new_time)
81
+ return if new_time.blank?
82
+ content[:published_at] = new_time
83
+ content.state = :publication_pending if new_time > Time.now
84
+ end
85
+
86
+ def send_notifications
87
+ content.really_send_notifications if just_published?
88
+ true
89
+ end
90
+
91
+ def send_pings
92
+ content.really_send_pings if just_published?
93
+ true
94
+ end
95
+
96
+ def just_published?
97
+ content.just_changed_published_status?
98
+ end
99
+ end
100
+
101
+ class JustWithdrawn < Base
102
+ def enter_hook
103
+ super
104
+ content.just_changed_published_status = true
105
+ content.state = :withdrawn
106
+ end
107
+ end
108
+
109
+ class Withdrawn < Base
110
+ def enter_hook
111
+ content[:published] = false
112
+ end
113
+
114
+ def published=(boolean)
115
+ return unless boolean
116
+ content.state = :published
117
+ end
118
+
119
+ def published_at=(new_time)
120
+ content[:published_at] = new_time
121
+ Trigger.remove(content, trigger_method: 'publish!')
122
+ return if new_time.nil? || new_time <= Time.now
123
+ content.state = :publication_pending
124
+ end
125
+ end
126
+
127
+ class PublicationPending < Base
128
+ def enter_hook
129
+ content[:published] = false if content.new_record?
130
+ end
131
+
132
+ def published=(published)
133
+ content[:published] = published
134
+
135
+ if published && content.published_at <= Time.now
136
+ content.state = :just_published
137
+ end
138
+ end
139
+
140
+ def published_at=(new_time)
141
+ content[:published_at] = new_time
142
+ Trigger.remove(content, trigger_method: 'publish!')
143
+ if new_time.nil?
144
+ content.state = :draft
145
+ elsif new_time <= Time.now
146
+ content.state = :just_published
147
+ end
148
+ end
149
+
150
+ def post_trigger
151
+ Trigger.post_action(content.published_at, content, 'publish!')
152
+ end
153
+
154
+ def withdraw(content)
155
+ content.state = :draft
156
+ end
157
+ end
158
+
159
+ class Draft < Base
160
+ def enter_hook
161
+ super
162
+ content[:published] = false
163
+ content[:published_at] = nil
164
+ end
165
+
166
+ def published=(boolean)
167
+ content.state = :just_published if boolean
168
+ end
169
+
170
+ def published_at=(new_time)
171
+ # Because of the workings of the controller, we should ignore
172
+ # publication times before the current time.
173
+ return if new_time.nil? || new_time <= Time.now
174
+ content[:published_at] = new_time
175
+ content.state = :publication_pending
176
+ end
177
+ end
178
+ end