HornsAndHooves-publify_core 10.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/CHANGELOG.md +102 -0
- data/MIT-LICENSE +21 -0
- data/README.md +9 -0
- data/app/assets/fonts/bootstrap/glyphicons-halflings-regular.eot +0 -0
- data/app/assets/fonts/bootstrap/glyphicons-halflings-regular.svg +288 -0
- data/app/assets/fonts/bootstrap/glyphicons-halflings-regular.ttf +0 -0
- data/app/assets/fonts/bootstrap/glyphicons-halflings-regular.woff +0 -0
- data/app/assets/fonts/bootstrap/glyphicons-halflings-regular.woff2 +0 -0
- data/app/assets/fonts/open-sans-bold.woff +0 -0
- data/app/assets/fonts/open-sans.woff +0 -0
- data/app/assets/images/admin/loading.gif +0 -0
- data/app/assets/images/admin/typologo.gif +0 -0
- data/app/assets/images/calendar_date_select/calendar.gif +0 -0
- data/app/assets/images/close.gif +0 -0
- data/app/assets/images/closelabel.gif +0 -0
- data/app/assets/images/go.png +0 -0
- data/app/assets/images/loading.gif +0 -0
- data/app/assets/images/nextlabel.gif +0 -0
- data/app/assets/images/overlay.png +0 -0
- data/app/assets/images/powered.gif +0 -0
- data/app/assets/images/prevlabel.gif +0 -0
- data/app/assets/images/spinner-blue.gif +0 -0
- data/app/assets/images/spinner.gif +0 -0
- data/app/assets/images/thumb_blank.jpg +0 -0
- data/app/assets/javascripts/application.js +2 -0
- data/app/assets/javascripts/bootstrap/affix.js +164 -0
- data/app/assets/javascripts/bootstrap/alert.js +95 -0
- data/app/assets/javascripts/bootstrap/button.js +125 -0
- data/app/assets/javascripts/bootstrap/collapse.js +212 -0
- data/app/assets/javascripts/bootstrap/dropdown.js +165 -0
- data/app/assets/javascripts/bootstrap/modal.js +358 -0
- data/app/assets/javascripts/bootstrap/tab.js +155 -0
- data/app/assets/javascripts/bootstrap/transition.js +59 -0
- data/app/assets/javascripts/bootstrap-sprockets.js +8 -0
- data/app/assets/javascripts/cookies.js +60 -0
- data/app/assets/javascripts/datetimepicker.js +1470 -0
- data/app/assets/javascripts/lang/da_DK.js +17 -0
- data/app/assets/javascripts/lang/default.js +21 -0
- data/app/assets/javascripts/lang/en_US.js +21 -0
- data/app/assets/javascripts/lang/fr_FR.js +21 -0
- data/app/assets/javascripts/lang/nl_NL.js +21 -0
- data/app/assets/javascripts/lang/zh_TW.js +17 -0
- data/app/assets/javascripts/lightbox.js +350 -0
- data/app/assets/javascripts/observe.js +28 -0
- data/app/assets/javascripts/publify.js +11 -0
- data/app/assets/javascripts/publify_admin.js +104 -0
- data/app/assets/javascripts/quicktags.js +448 -0
- data/app/assets/javascripts/set-timeago-lang.js +3 -0
- data/app/assets/javascripts/sidebar.js +28 -0
- data/app/assets/javascripts/spinnable.js +5 -0
- data/app/assets/javascripts/tagmanager.js +481 -0
- data/app/assets/javascripts/typeahead.js +1139 -0
- data/app/assets/stylesheets/_bootstrap-compass.scss +9 -0
- data/app/assets/stylesheets/_bootstrap-mincer.scss +19 -0
- data/app/assets/stylesheets/_bootstrap-sprockets.scss +9 -0
- data/app/assets/stylesheets/_bootstrap.scss +43 -0
- data/app/assets/stylesheets/accounts.css.scss +7 -0
- data/app/assets/stylesheets/administration_structure.css.scss +255 -0
- data/app/assets/stylesheets/bootstrap/_alerts.scss +73 -0
- data/app/assets/stylesheets/bootstrap/_button-groups.scss +242 -0
- data/app/assets/stylesheets/bootstrap/_buttons.scss +168 -0
- data/app/assets/stylesheets/bootstrap/_close.scss +37 -0
- data/app/assets/stylesheets/bootstrap/_code.scss +69 -0
- data/app/assets/stylesheets/bootstrap/_component-animations.scss +38 -0
- data/app/assets/stylesheets/bootstrap/_dropdowns.scss +213 -0
- data/app/assets/stylesheets/bootstrap/_forms.scss +586 -0
- data/app/assets/stylesheets/bootstrap/_glyphicons.scss +307 -0
- data/app/assets/stylesheets/bootstrap/_grid.scss +94 -0
- data/app/assets/stylesheets/bootstrap/_labels.scss +66 -0
- data/app/assets/stylesheets/bootstrap/_media.scss +66 -0
- data/app/assets/stylesheets/bootstrap/_mixins.scss +37 -0
- data/app/assets/stylesheets/bootstrap/_modals.scss +150 -0
- data/app/assets/stylesheets/bootstrap/_navbar.scss +479 -0
- data/app/assets/stylesheets/bootstrap/_navs.scss +242 -0
- data/app/assets/stylesheets/bootstrap/_normalize.scss +427 -0
- data/app/assets/stylesheets/bootstrap/_pagination.scss +86 -0
- data/app/assets/stylesheets/bootstrap/_panels.scss +222 -0
- data/app/assets/stylesheets/bootstrap/_print.scss +99 -0
- data/app/assets/stylesheets/bootstrap/_scaffolding.scss +160 -0
- data/app/assets/stylesheets/bootstrap/_tables.scss +234 -0
- data/app/assets/stylesheets/bootstrap/_theme.scss +224 -0
- data/app/assets/stylesheets/bootstrap/_type.scss +296 -0
- data/app/assets/stylesheets/bootstrap/_utilities.scss +55 -0
- data/app/assets/stylesheets/bootstrap/_variables.scss +654 -0
- data/app/assets/stylesheets/bootstrap/_wells.scss +29 -0
- data/app/assets/stylesheets/bootstrap/mixins/_alerts.scss +15 -0
- data/app/assets/stylesheets/bootstrap/mixins/_background-variant.scss +12 -0
- data/app/assets/stylesheets/bootstrap/mixins/_border-radius.scss +18 -0
- data/app/assets/stylesheets/bootstrap/mixins/_buttons.scss +56 -0
- data/app/assets/stylesheets/bootstrap/mixins/_center-block.scss +7 -0
- data/app/assets/stylesheets/bootstrap/mixins/_clearfix.scss +22 -0
- data/app/assets/stylesheets/bootstrap/mixins/_forms.scss +82 -0
- data/app/assets/stylesheets/bootstrap/mixins/_gradients.scss +56 -0
- data/app/assets/stylesheets/bootstrap/mixins/_grid-framework.scss +81 -0
- data/app/assets/stylesheets/bootstrap/mixins/_grid.scss +122 -0
- data/app/assets/stylesheets/bootstrap/mixins/_hide-text.scss +21 -0
- data/app/assets/stylesheets/bootstrap/mixins/_image.scss +28 -0
- data/app/assets/stylesheets/bootstrap/mixins/_labels.scss +12 -0
- data/app/assets/stylesheets/bootstrap/mixins/_nav-divider.scss +10 -0
- data/app/assets/stylesheets/bootstrap/mixins/_nav-vertical-align.scss +9 -0
- data/app/assets/stylesheets/bootstrap/mixins/_opacity.scss +7 -0
- data/app/assets/stylesheets/bootstrap/mixins/_pagination.scss +24 -0
- data/app/assets/stylesheets/bootstrap/mixins/_panels.scss +20 -0
- data/app/assets/stylesheets/bootstrap/mixins/_reset-filter.scss +8 -0
- data/app/assets/stylesheets/bootstrap/mixins/_resize.scss +6 -0
- data/app/assets/stylesheets/bootstrap/mixins/_responsive-visibility.scss +17 -0
- data/app/assets/stylesheets/bootstrap/mixins/_size.scss +10 -0
- data/app/assets/stylesheets/bootstrap/mixins/_tab-focus.scss +9 -0
- data/app/assets/stylesheets/bootstrap/mixins/_table-row.scss +28 -0
- data/app/assets/stylesheets/bootstrap/mixins/_text-emphasis.scss +12 -0
- data/app/assets/stylesheets/bootstrap/mixins/_text-overflow.scss +8 -0
- data/app/assets/stylesheets/bootstrap/mixins/_vendor-prefixes.scss +222 -0
- data/app/assets/stylesheets/coderay.css +135 -0
- data/app/assets/stylesheets/datetimepicker.css +306 -0
- data/app/assets/stylesheets/lightbox.css +63 -0
- data/app/assets/stylesheets/publify.css.scss +9 -0
- data/app/assets/stylesheets/publify_admin.css.scss +10 -0
- data/app/assets/stylesheets/rss.css +53 -0
- data/app/assets/stylesheets/sidebar_admin.css.scss +36 -0
- data/app/assets/stylesheets/tagmanager.css +102 -0
- data/app/assets/stylesheets/user-styles.css +29 -0
- data/app/controllers/accounts_controller.rb +4 -0
- data/app/controllers/admin/base_controller.rb +27 -0
- data/app/controllers/admin/content_controller.rb +194 -0
- data/app/controllers/admin/dashboard_controller.rb +33 -0
- data/app/controllers/admin/feedback_controller.rb +160 -0
- data/app/controllers/admin/notes_controller.rb +73 -0
- data/app/controllers/admin/pages_controller.rb +73 -0
- data/app/controllers/admin/post_types_controller.rb +57 -0
- data/app/controllers/admin/profiles_controller.rb +57 -0
- data/app/controllers/admin/redirects_controller.rb +51 -0
- data/app/controllers/admin/resources_controller.rb +36 -0
- data/app/controllers/admin/seo_controller.rb +46 -0
- data/app/controllers/admin/settings_controller.rb +53 -0
- data/app/controllers/admin/sidebar_controller.rb +67 -0
- data/app/controllers/admin/tags_controller.rb +55 -0
- data/app/controllers/admin/themes_controller.rb +31 -0
- data/app/controllers/admin/users_controller.rb +67 -0
- data/app/controllers/articles_controller.rb +215 -0
- data/app/controllers/authors_controller.rb +30 -0
- data/app/controllers/base_controller.rb +43 -0
- data/app/controllers/comments_controller.rb +67 -0
- data/app/controllers/content_controller.rb +24 -0
- data/app/controllers/feedback_controller.rb +13 -0
- data/app/controllers/notes_controller.rb +35 -0
- data/app/controllers/setup_controller.rb +61 -0
- data/app/controllers/tags_controller.rb +50 -0
- data/app/controllers/text_controller.rb +7 -0
- data/app/controllers/textfilter_controller.rb +5 -0
- data/app/controllers/theme_controller.rb +63 -0
- data/app/controllers/xml_controller.rb +20 -0
- data/app/helpers/admin/base_helper.rb +87 -0
- data/app/helpers/admin/feedback_helper.rb +53 -0
- data/app/helpers/articles_helper.rb +10 -0
- data/app/helpers/authors_helper.rb +30 -0
- data/app/helpers/base_helper.rb +257 -0
- data/app/helpers/blog_helper.rb +14 -0
- data/app/helpers/xml_helper.rb +18 -0
- data/app/jobs/application_job.rb +5 -0
- data/app/mailers/notification_mailer.rb +40 -0
- data/app/models/ability.rb +53 -0
- data/app/models/archives_sidebar.rb +45 -0
- data/app/models/article/factory.rb +64 -0
- data/app/models/article.rb +308 -0
- data/app/models/blog.rb +280 -0
- data/app/models/comment.rb +57 -0
- data/app/models/config_manager.rb +83 -0
- data/app/models/content.rb +118 -0
- data/app/models/content_base.rb +88 -0
- data/app/models/feedback.rb +250 -0
- data/app/models/meta_sidebar.rb +10 -0
- data/app/models/note.rb +152 -0
- data/app/models/page.rb +42 -0
- data/app/models/page_sidebar.rb +14 -0
- data/app/models/ping.rb +5 -0
- data/app/models/post_type.rb +16 -0
- data/app/models/redirect.rb +51 -0
- data/app/models/redirection.rb +6 -0
- data/app/models/resource.rb +12 -0
- data/app/models/search_sidebar.rb +9 -0
- data/app/models/sidebar.rb +142 -0
- data/app/models/static_sidebar.rb +22 -0
- data/app/models/tag.rb +71 -0
- data/app/models/tag_sidebar.rb +30 -0
- data/app/models/text_filter.rb +141 -0
- data/app/models/trackback.rb +46 -0
- data/app/models/trigger.rb +34 -0
- data/app/models/user.rb +142 -0
- data/app/services/title_builder.rb +88 -0
- data/app/uploaders/resource_uploader.rb +63 -0
- data/app/views/accounts/confirm.html.erb +7 -0
- data/app/views/admin/content/_article_list.html.erb +26 -0
- data/app/views/admin/content/_form.html.erb +145 -0
- data/app/views/admin/content/autosave.js.erb +5 -0
- data/app/views/admin/content/edit.html.erb +3 -0
- data/app/views/admin/content/index.html.erb +48 -0
- data/app/views/admin/content/index.js.erb +1 -0
- data/app/views/admin/content/new.html.erb +3 -0
- data/app/views/admin/dashboard/_comment.html.erb +18 -0
- data/app/views/admin/dashboard/_comments.html.erb +10 -0
- data/app/views/admin/dashboard/_drafts.html.erb +25 -0
- data/app/views/admin/dashboard/_overview.html.erb +21 -0
- data/app/views/admin/dashboard/_welcome.html.erb +28 -0
- data/app/views/admin/dashboard/index.html.erb +16 -0
- data/app/views/admin/feedback/_button.html.erb +19 -0
- data/app/views/admin/feedback/_feedback.html.erb +7 -0
- data/app/views/admin/feedback/_ham.html.erb +17 -0
- data/app/views/admin/feedback/_spam.html.erb +23 -0
- data/app/views/admin/feedback/article.html.erb +69 -0
- data/app/views/admin/feedback/edit.html.erb +48 -0
- data/app/views/admin/feedback/ham.js +1 -0
- data/app/views/admin/feedback/index.html.erb +53 -0
- data/app/views/admin/feedback/spam.js +1 -0
- data/app/views/admin/migrations/show.html.erb +39 -0
- data/app/views/admin/notes/_form.html.erb +37 -0
- data/app/views/admin/notes/_header.html.erb +6 -0
- data/app/views/admin/notes/_list.html.erb +13 -0
- data/app/views/admin/notes/_note.html.erb +14 -0
- data/app/views/admin/notes/edit.html.erb +11 -0
- data/app/views/admin/notes/index.html.erb +11 -0
- data/app/views/admin/notes/show.html.erb +14 -0
- data/app/views/admin/pages/_form.html.erb +101 -0
- data/app/views/admin/pages/_pages.html.erb +21 -0
- data/app/views/admin/pages/edit.html.erb +1 -0
- data/app/views/admin/pages/index.html.erb +17 -0
- data/app/views/admin/pages/new.html.erb +1 -0
- data/app/views/admin/post_types/_index_and_form.html.erb +65 -0
- data/app/views/admin/post_types/edit.html.erb +1 -0
- data/app/views/admin/post_types/index.html.erb +1 -0
- data/app/views/admin/profiles/index.html.erb +10 -0
- data/app/views/admin/redirects/_index_and_form.html.erb +68 -0
- data/app/views/admin/redirects/edit.html.erb +1 -0
- data/app/views/admin/redirects/index.html.erb +1 -0
- data/app/views/admin/resources/index.html.erb +72 -0
- data/app/views/admin/seo/_general.html.erb +104 -0
- data/app/views/admin/seo/_permalinks.html.erb +53 -0
- data/app/views/admin/seo/_titles.html.erb +209 -0
- data/app/views/admin/seo/show.html.erb +28 -0
- data/app/views/admin/settings/display.html.erb +101 -0
- data/app/views/admin/settings/feedback.html.erb +118 -0
- data/app/views/admin/settings/index.html.erb +73 -0
- data/app/views/admin/settings/write.html.erb +69 -0
- data/app/views/admin/shared/_edit.html.erb +4 -0
- data/app/views/admin/shared/_menu.html.erb +121 -0
- data/app/views/admin/shared/_twitter_alert.html.erb +3 -0
- data/app/views/admin/sidebar/_available.html.erb +6 -0
- data/app/views/admin/sidebar/_available.json.erb +6 -0
- data/app/views/admin/sidebar/_config.html.erb +27 -0
- data/app/views/admin/sidebar/_target.html.erb +9 -0
- data/app/views/admin/sidebar/_target_sidebar.html.erb +20 -0
- data/app/views/admin/sidebar/destroy.js.erb +1 -0
- data/app/views/admin/sidebar/index.html.erb +31 -0
- data/app/views/admin/sidebar/sortable.js.erb +3 -0
- data/app/views/admin/sidebar/update.js.erb +2 -0
- data/app/views/admin/tags/_index_and_form.html.erb +59 -0
- data/app/views/admin/tags/edit.html.erb +1 -0
- data/app/views/admin/tags/index.html.erb +1 -0
- data/app/views/admin/themes/index.html.erb +27 -0
- data/app/views/admin/users/_form.html.erb +215 -0
- data/app/views/admin/users/edit.html.erb +8 -0
- data/app/views/admin/users/index.html.erb +39 -0
- data/app/views/admin/users/new.html.erb +8 -0
- data/app/views/archives_sidebar/_content.html.erb +13 -0
- data/app/views/articles/_archives_article.html.erb +9 -0
- data/app/views/articles/_article.html.erb +9 -0
- data/app/views/articles/_article_author.html.erb +4 -0
- data/app/views/articles/_article_collection.html.erb +8 -0
- data/app/views/articles/_article_content.html.erb +5 -0
- data/app/views/articles/_article_excerpt.html.erb +15 -0
- data/app/views/articles/_article_links.html.erb +12 -0
- data/app/views/articles/_comment.html.erb +1 -0
- data/app/views/articles/_comment_errors.html.erb +2 -0
- data/app/views/articles/_comment_form.html.erb +48 -0
- data/app/views/articles/_comment_list.html.erb +5 -0
- data/app/views/articles/_comment_preview.html.erb +4 -0
- data/app/views/articles/_full_article_content.html.erb +4 -0
- data/app/views/articles/_password_form.html.erb +10 -0
- data/app/views/articles/_trackback.html.erb +6 -0
- data/app/views/articles/archives.html.erb +15 -0
- data/app/views/articles/comment.js.erb +5 -0
- data/app/views/articles/comment_failed.js.erb +3 -0
- data/app/views/articles/error.html.erb +3 -0
- data/app/views/articles/feedback_atom_feed.atom.builder +10 -0
- data/app/views/articles/feedback_rss_feed.rss.builder +21 -0
- data/app/views/articles/index.html.erb +1 -0
- data/app/views/articles/index_atom_feed.atom.builder +9 -0
- data/app/views/articles/index_rss_feed.rss.builder +20 -0
- data/app/views/articles/live_search.html.erb +10 -0
- data/app/views/articles/read.html.erb +43 -0
- data/app/views/articles/search.html.erb +8 -0
- data/app/views/articles/trackback.xml.builder +7 -0
- data/app/views/articles/view_page.html.erb +3 -0
- data/app/views/authors/show.html.erb +30 -0
- data/app/views/authors/show_atom_feed.atom.builder +9 -0
- data/app/views/authors/show_rss_feed.rss.builder +20 -0
- data/app/views/comments/_comment.html.erb +17 -0
- data/app/views/comments/preview.html.erb +1 -0
- data/app/views/comments/preview.js.erb +3 -0
- data/app/views/devise/mailer/reset_password_instructions.html.erb +11 -0
- data/app/views/devise/passwords/edit.html.erb +28 -0
- data/app/views/devise/passwords/new.html.erb +20 -0
- data/app/views/devise/registrations/new.html.erb +36 -0
- data/app/views/devise/sessions/new.html.erb +32 -0
- data/app/views/devise/shared/_links.html.erb +11 -0
- data/app/views/errors/404.html.erb +2 -0
- data/app/views/feedback/index.atom.builder +9 -0
- data/app/views/feedback/index.rss.builder +20 -0
- data/app/views/layouts/accounts.html.erb +33 -0
- data/app/views/layouts/administration.html.erb +37 -0
- data/app/views/layouts/default.html.erb +33 -0
- data/app/views/layouts/editor.html.erb +17 -0
- data/app/views/meta_sidebar/_content.html.erb +8 -0
- data/app/views/notes/_note.html.erb +16 -0
- data/app/views/notes/error.html.erb +3 -0
- data/app/views/notes/index.html.erb +15 -0
- data/app/views/notes/show.html.erb +5 -0
- data/app/views/notes/show_in_reply.html.erb +18 -0
- data/app/views/notification_mailer/_mail_footer.html.erb +5 -0
- data/app/views/notification_mailer/_mail_header.html.erb +3 -0
- data/app/views/notification_mailer/article.html.erb +7 -0
- data/app/views/notification_mailer/comment.html.erb +12 -0
- data/app/views/notification_mailer/notif_user.html.erb +9 -0
- data/app/views/page_sidebar/_content.html.erb +12 -0
- data/app/views/search_sidebar/_content.html.erb +10 -0
- data/app/views/settings/done.html.erb +2 -0
- data/app/views/settings/install.html.erb +12 -0
- data/app/views/setup/index.html.erb +17 -0
- data/app/views/shared/_atom_header.atom.builder +6 -0
- data/app/views/shared/_atom_item_article.atom.builder +36 -0
- data/app/views/shared/_atom_item_comment.atom.builder +10 -0
- data/app/views/shared/_atom_item_trackback.atom.builder +10 -0
- data/app/views/shared/_flash.erb +10 -0
- data/app/views/shared/_google_analytics.html.erb +8 -0
- data/app/views/shared/_page_header.html.erb +23 -0
- data/app/views/shared/_rss_item_article.rss.builder +32 -0
- data/app/views/shared/_rss_item_comment.rss.builder +9 -0
- data/app/views/shared/_rss_item_trackback.rss.builder +9 -0
- data/app/views/sidebar/_row.html.erb +1 -0
- data/app/views/sidebar/_sidebar.html.erb +5 -0
- data/app/views/sidebar/display_plugins.html.erb +5 -0
- data/app/views/sidebar/show.html.erb +1 -0
- data/app/views/static_sidebar/_content.html.erb +2 -0
- data/app/views/tag_sidebar/_content.html.erb +10 -0
- data/app/views/tags/index.html.erb +15 -0
- data/app/views/tags/show.html.erb +1 -0
- data/app/views/theme/static_view_test.html.erb +1 -0
- data/app/views/xml/_googlesitemap_item_article.googlesitemap.builder +7 -0
- data/app/views/xml/_googlesitemap_item_category.googlesitemap.builder +6 -0
- data/app/views/xml/_googlesitemap_item_page.googlesitemap.builder +6 -0
- data/app/views/xml/_googlesitemap_item_tag.googlesitemap.builder +6 -0
- data/app/views/xml/sitemap.googlesitemap.builder +9 -0
- data/config/i18n-tasks.yml +49 -0
- data/config/initializers/devise.rb +271 -0
- data/config/initializers/mime_types.rb +7 -0
- data/config/locales/da.yml +769 -0
- data/config/locales/de.yml +769 -0
- data/config/locales/en.yml +770 -0
- data/config/locales/es-MX.yml +769 -0
- data/config/locales/fr.yml +769 -0
- data/config/locales/he.yml +769 -0
- data/config/locales/it.yml +769 -0
- data/config/locales/ja.yml +769 -0
- data/config/locales/lt.yml +783 -0
- data/config/locales/nb-NO.yml +769 -0
- data/config/locales/nl.yml +769 -0
- data/config/locales/pl.yml +797 -0
- data/config/locales/pt-BR.yml +769 -0
- data/config/locales/ro.yml +782 -0
- data/config/locales/ru.yml +797 -0
- data/config/locales/sidebars.da.yml +20 -0
- data/config/locales/sidebars.de.yml +20 -0
- data/config/locales/sidebars.en.yml +20 -0
- data/config/locales/sidebars.es-MX.yml +20 -0
- data/config/locales/sidebars.fr.yml +20 -0
- data/config/locales/sidebars.he.yml +20 -0
- data/config/locales/sidebars.it.yml +20 -0
- data/config/locales/sidebars.ja.yml +20 -0
- data/config/locales/sidebars.lt.yml +20 -0
- data/config/locales/sidebars.nb-NO.yml +20 -0
- data/config/locales/sidebars.nl.yml +20 -0
- data/config/locales/sidebars.pl.yml +20 -0
- data/config/locales/sidebars.pt-BR.yml +20 -0
- data/config/locales/sidebars.ro.yml +20 -0
- data/config/locales/sidebars.ru.yml +20 -0
- data/config/locales/sidebars.zh-CN.yml +20 -0
- data/config/locales/sidebars.zh-TW.yml +20 -0
- data/config/locales/zh-CN.yml +768 -0
- data/config/locales/zh-TW.yml +769 -0
- data/config/routes.rb +174 -0
- data/db/migrate/113_initial_schema.rb +210 -0
- data/db/migrate/114_fixes_buggy_articles_and_notes.rb +56 -0
- data/db/migrate/115_drops_categories_for_tags.rb +37 -0
- data/db/migrate/20150207131657_add_missing_indexes.rb +23 -0
- data/db/migrate/20150807134129_simplify_redirect_relations.rb +45 -0
- data/db/migrate/20150808052637_add_blog_ids.rb +39 -0
- data/db/migrate/20150808191127_add_blog_id_to_redirects.rb +19 -0
- data/db/migrate/20150810094754_add_blog_id_to_tags.rb +19 -0
- data/db/migrate/20160108111120_add_devise_to_users.rb +57 -0
- data/db/migrate/20160108184201_move_last_connection_to_last_sign_in_at.rb +20 -0
- data/db/migrate/20160110094906_remove_profiles_rights.rb +18 -0
- data/db/migrate/20160605103918_replace_profile_id_with_string.rb +32 -0
- data/db/migrate/20160605154632_remove_profiles.rb +31 -0
- data/db/migrate/20160701061851_demand_blog_id_on_contents.rb +13 -0
- data/db/migrate/20160701062604_add_blog_id_to_resources.rb +32 -0
- data/db/migrate/20170528093024_move_resources_to_content.rb +9 -0
- data/db/migrate/20170528094923_move_tags_to_content.rb +10 -0
- data/db/migrate/20170528201606_remove_separate_published_flag.rb +9 -0
- data/db/migrate/20170605071626_remove_extra_state_columns_from_feedback.rb +10 -0
- data/db/migrate/20170702105201_remove_published_at_from_feedback.rb +9 -0
- data/db/migrate/20190208151235_add_text_filter_name_fields.rb +11 -0
- data/db/migrate/20190208152646_move_text_filter_to_name.rb +99 -0
- data/db/migrate/20190209155717_remove_text_filter_ids.rb +21 -0
- data/db/migrate/20190209160610_remove_text_filters.rb +19 -0
- data/db/seeds.rb +25 -0
- data/lib/email_notify.rb +28 -0
- data/lib/format.rb +9 -0
- data/lib/publify_core/engine.rb +31 -0
- data/lib/publify_core/lang.rb +9 -0
- data/lib/publify_core/testing_support/dns_mock.rb +15 -0
- data/lib/publify_core/testing_support/factories.rb +242 -0
- data/lib/publify_core/testing_support/feed_assertions.rb +48 -0
- data/lib/publify_core/testing_support/fixtures/exploit.svg +4 -0
- data/lib/publify_core/testing_support/fixtures/fakepng.png +1 -0
- data/lib/publify_core/testing_support/fixtures/otherfile.txt +1 -0
- data/lib/publify_core/testing_support/fixtures/testfile.png +0 -0
- data/lib/publify_core/testing_support/fixtures/testfile.txt +1 -0
- data/lib/publify_core/testing_support/upload_fixtures.rb +15 -0
- data/lib/publify_core/version.rb +5 -0
- data/lib/publify_core.rb +46 -0
- data/lib/publify_guid.rb +11 -0
- data/lib/publify_plugins.rb +77 -0
- data/lib/publify_textfilter_markdown.rb +57 -0
- data/lib/publify_textfilter_none.rb +16 -0
- data/lib/publify_textfilter_smartypants.rb +16 -0
- data/lib/publify_textfilter_textile.rb +23 -0
- data/lib/publify_textfilter_twitterfilter.rb +39 -0
- data/lib/publify_time.rb +34 -0
- data/lib/sidebar_field.rb +127 -0
- data/lib/sidebar_registry.rb +35 -0
- data/lib/spam_protection.rb +103 -0
- data/lib/tasks/i18n.rake +9 -0
- data/lib/tasks/manifest.rake +30 -0
- data/lib/tasks/publify_core_tasks.rake +6 -0
- data/lib/text_filter_plugin.rb +183 -0
- data/lib/theme.rb +72 -0
- data/lib/transforms.rb +47 -0
- data/themes/plain/about.markdown +4 -0
- data/themes/plain/javascripts/theme.js +0 -0
- data/themes/plain/preview.png +0 -0
- data/themes/plain/stylesheets/theme.css +57 -0
- metadata +1062 -0
@@ -0,0 +1,308 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "aasm"
|
4
|
+
require "uri"
|
5
|
+
require "net/http"
|
6
|
+
|
7
|
+
class Article < Content
|
8
|
+
include PublifyGuid
|
9
|
+
include ConfigManager
|
10
|
+
|
11
|
+
serialize :settings, Hash
|
12
|
+
|
13
|
+
content_fields :body, :extended
|
14
|
+
|
15
|
+
validates :guid, uniqueness: true
|
16
|
+
validates :title, presence: true
|
17
|
+
|
18
|
+
has_many :pings, dependent: :destroy
|
19
|
+
has_many :trackbacks, dependent: :destroy
|
20
|
+
has_many :feedback
|
21
|
+
has_many :triggers, as: :pending_item
|
22
|
+
has_many :comments, dependent: :destroy
|
23
|
+
|
24
|
+
belongs_to :resource
|
25
|
+
|
26
|
+
before_create :create_guid
|
27
|
+
before_save :set_permalink
|
28
|
+
after_save :keywords_to_tags, :shorten_url
|
29
|
+
|
30
|
+
scope :child_of, ->(article_id) { where(parent_id: article_id) }
|
31
|
+
scope :published_since, ->(time) { published.where("published_at > ?", time) }
|
32
|
+
scope :withdrawn, -> { where(state: "withdrawn").order(default_order) }
|
33
|
+
scope :pending, -> { where(state: "publication_pending"). order(default_order) }
|
34
|
+
|
35
|
+
scope :bestof, lambda {
|
36
|
+
joins(:feedback).
|
37
|
+
where("feedback.type" => "Comment",
|
38
|
+
"contents.state" => "published").
|
39
|
+
group("contents.id").
|
40
|
+
select("contents.*, count(feedback.id) as comment_count").
|
41
|
+
order("comment_count DESC").
|
42
|
+
limit(5)
|
43
|
+
}
|
44
|
+
|
45
|
+
setting :password, :string, ""
|
46
|
+
|
47
|
+
attr_accessor :draft, :keywords
|
48
|
+
|
49
|
+
include AASM
|
50
|
+
|
51
|
+
aasm column: :state do
|
52
|
+
state :draft, initial: true
|
53
|
+
# TODO: Disallow if published_at in past
|
54
|
+
state :publication_pending, after_enter: :trigger_publication
|
55
|
+
state :published, after_enter: :really_send_notifications
|
56
|
+
state :withdrawn
|
57
|
+
|
58
|
+
event :withdraw do
|
59
|
+
transitions from: :published, to: :withdrawn
|
60
|
+
transitions from: :publication_pending, to: :draft
|
61
|
+
end
|
62
|
+
|
63
|
+
event :publish do
|
64
|
+
before do
|
65
|
+
self.published_at ||= Time.zone.now
|
66
|
+
end
|
67
|
+
|
68
|
+
transitions from: [:new, :draft], to: :publication_pending do
|
69
|
+
guard do
|
70
|
+
published_at > Time.zone.now
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
transitions from: [:new, :draft, :publication_pending], to: :published do
|
75
|
+
guard do
|
76
|
+
published_at <= Time.zone.now
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
def set_permalink
|
83
|
+
return if draft? || permalink.present?
|
84
|
+
|
85
|
+
self.permalink = title.to_permalink
|
86
|
+
end
|
87
|
+
|
88
|
+
def has_child?
|
89
|
+
Article.exists?(parent_id: id)
|
90
|
+
end
|
91
|
+
|
92
|
+
def post_type
|
93
|
+
post_type = self[:post_type]
|
94
|
+
post_type = "read" if post_type.blank?
|
95
|
+
post_type
|
96
|
+
end
|
97
|
+
|
98
|
+
def self.last_draft(article_id)
|
99
|
+
article = Article.find(article_id)
|
100
|
+
article = Article.child_of(article.id).first while article.has_child?
|
101
|
+
article
|
102
|
+
end
|
103
|
+
|
104
|
+
def self.search_with(params)
|
105
|
+
params ||= {}
|
106
|
+
scoped = super(params)
|
107
|
+
if %w(no_draft drafts published withdrawn pending).include?(params[:state])
|
108
|
+
scoped = scoped.send(params[:state])
|
109
|
+
end
|
110
|
+
|
111
|
+
scoped.order("created_at DESC")
|
112
|
+
end
|
113
|
+
|
114
|
+
# FIXME: Use keyword params to clean up call sites.
|
115
|
+
def permalink_url(anchor = nil, only_path = false)
|
116
|
+
return unless published?
|
117
|
+
|
118
|
+
@cached_permalink_url ||= {}
|
119
|
+
@cached_permalink_url["#{anchor}#{only_path}"] ||=
|
120
|
+
blog.url_for(permalink_url_options, anchor: anchor, only_path: only_path)
|
121
|
+
end
|
122
|
+
|
123
|
+
def save_attachments!(files)
|
124
|
+
files ||= {}
|
125
|
+
files.each_value { |f| save_attachment!(f) }
|
126
|
+
end
|
127
|
+
|
128
|
+
def save_attachment!(file)
|
129
|
+
resources.create!(upload: file, blog: blog)
|
130
|
+
end
|
131
|
+
|
132
|
+
def comment_url
|
133
|
+
blog.url_for("comments?article_id=#{id}", only_path: true)
|
134
|
+
end
|
135
|
+
|
136
|
+
def preview_comment_url
|
137
|
+
blog.url_for("comments/preview?article_id=#{id}", only_path: true)
|
138
|
+
end
|
139
|
+
|
140
|
+
def feed_url(format)
|
141
|
+
"#{permalink_url}.#{format.gsub(/\d/, "")}"
|
142
|
+
end
|
143
|
+
|
144
|
+
def next
|
145
|
+
Article.where("published_at > ?", published_at).order("published_at asc").
|
146
|
+
limit(1).first
|
147
|
+
end
|
148
|
+
|
149
|
+
def previous
|
150
|
+
Article.where("published_at < ?", published_at).order("published_at desc").
|
151
|
+
limit(1).first
|
152
|
+
end
|
153
|
+
|
154
|
+
def publication_month
|
155
|
+
published_at.strftime("%Y-%m")
|
156
|
+
end
|
157
|
+
|
158
|
+
def self.publication_months
|
159
|
+
result = select("published_at").where("published_at is not NULL").where(type: "Article")
|
160
|
+
result.map { |it| [it.publication_month] }.uniq
|
161
|
+
end
|
162
|
+
|
163
|
+
# Finds one article which was posted on a certain date and matches the
|
164
|
+
# supplied dashed-title params is a Hash
|
165
|
+
def self.requested_article(params)
|
166
|
+
date_range = PublifyTime.delta(params[:year], params[:month], params[:day])
|
167
|
+
|
168
|
+
req_params = {}
|
169
|
+
req_params[:permalink] = params[:title] if params[:title]
|
170
|
+
req_params[:published_at] = date_range if date_range
|
171
|
+
|
172
|
+
return if req_params.empty? # no search if no params send
|
173
|
+
|
174
|
+
article = published.find_by(req_params)
|
175
|
+
return article if article
|
176
|
+
|
177
|
+
if params[:title]
|
178
|
+
req_params[:permalink] = CGI.escape(params[:title])
|
179
|
+
article = published.find_by(req_params)
|
180
|
+
return article if article
|
181
|
+
end
|
182
|
+
end
|
183
|
+
|
184
|
+
# Fulltext searches the body of published articles
|
185
|
+
def self.search(query, args = {})
|
186
|
+
query_s = query.to_s.strip
|
187
|
+
if !query_s.empty? && args.empty?
|
188
|
+
Article.searchstring(query)
|
189
|
+
elsif !query_s.empty? && !args.empty?
|
190
|
+
Article.searchstring(query).page(args[:page]).per(args[:per])
|
191
|
+
else
|
192
|
+
[]
|
193
|
+
end
|
194
|
+
end
|
195
|
+
|
196
|
+
def keywords_to_tags
|
197
|
+
Tag.create_from_article!(self)
|
198
|
+
end
|
199
|
+
|
200
|
+
def interested_users
|
201
|
+
User.where(notify_on_new_articles: true)
|
202
|
+
end
|
203
|
+
|
204
|
+
def notify_user_via_email(user)
|
205
|
+
EmailNotify.send_article(self, user) if user.notify_via_email?
|
206
|
+
end
|
207
|
+
|
208
|
+
def comments_closed?
|
209
|
+
!(allow_comments? && in_feedback_window?)
|
210
|
+
end
|
211
|
+
|
212
|
+
def html_urls
|
213
|
+
urls = []
|
214
|
+
html.gsub(/<a\s+[^>]*>/) do |tag|
|
215
|
+
urls.push(Regexp.last_match[2].strip) if tag =~ /\bhref=(["']?)([^ >"]+)\1/
|
216
|
+
end
|
217
|
+
urls.uniq
|
218
|
+
end
|
219
|
+
|
220
|
+
def pings_closed?
|
221
|
+
!(allow_pings? && in_feedback_window?)
|
222
|
+
end
|
223
|
+
|
224
|
+
# check if time to comment is open or not
|
225
|
+
def in_feedback_window?
|
226
|
+
blog.sp_article_auto_close.zero? ||
|
227
|
+
published_at.to_i > blog.sp_article_auto_close.days.ago.to_i
|
228
|
+
end
|
229
|
+
|
230
|
+
def content_fields
|
231
|
+
[:body, :extended]
|
232
|
+
end
|
233
|
+
|
234
|
+
# The web interface no longer distinguishes between separate "body" and
|
235
|
+
# "extended" fields, and instead edits everything in a single edit field,
|
236
|
+
# separating the extended content using "\<!--more-->".
|
237
|
+
def body_and_extended
|
238
|
+
if extended.blank?
|
239
|
+
body
|
240
|
+
else
|
241
|
+
body + "\n<!--more-->\n" + extended
|
242
|
+
end
|
243
|
+
end
|
244
|
+
|
245
|
+
# Split apart value around a "\<!--more-->" comment and assign it to our
|
246
|
+
# #body and #extended fields.
|
247
|
+
def body_and_extended=(value)
|
248
|
+
parts = value.split(/\n?<!--more-->\n?/, 2)
|
249
|
+
self.body = parts[0]
|
250
|
+
self.extended = parts[1] || ""
|
251
|
+
end
|
252
|
+
|
253
|
+
def password_protected?
|
254
|
+
password.present?
|
255
|
+
end
|
256
|
+
|
257
|
+
def add_comment(params)
|
258
|
+
comments.build(params)
|
259
|
+
end
|
260
|
+
|
261
|
+
def access_by?(user)
|
262
|
+
user.admin? || user_id == user.id
|
263
|
+
end
|
264
|
+
|
265
|
+
def allow_comments?
|
266
|
+
return allow_comments unless allow_comments.nil?
|
267
|
+
|
268
|
+
blog.default_allow_comments
|
269
|
+
end
|
270
|
+
|
271
|
+
def allow_pings?
|
272
|
+
return allow_pings unless allow_pings.nil?
|
273
|
+
|
274
|
+
blog.default_allow_pings
|
275
|
+
end
|
276
|
+
|
277
|
+
def published_comments
|
278
|
+
comments.published.oldest_first
|
279
|
+
end
|
280
|
+
|
281
|
+
def published_trackbacks
|
282
|
+
trackbacks.published.oldest_first
|
283
|
+
end
|
284
|
+
|
285
|
+
def published_feedback
|
286
|
+
feedback.published.oldest_first
|
287
|
+
end
|
288
|
+
|
289
|
+
private
|
290
|
+
|
291
|
+
def permalink_url_options
|
292
|
+
format_url = blog.permalink_format.dup
|
293
|
+
format_url.gsub!("%year%", published_at.year.to_s)
|
294
|
+
format_url.gsub!("%month%", sprintf("%.2d", published_at.month))
|
295
|
+
format_url.gsub!("%day%", sprintf("%.2d", published_at.day))
|
296
|
+
format_url.gsub!("%title%", URI::DEFAULT_PARSER.escape(permalink.to_s))
|
297
|
+
if format_url[0, 1] == "/"
|
298
|
+
format_url[1..-1]
|
299
|
+
else
|
300
|
+
format_url
|
301
|
+
end
|
302
|
+
end
|
303
|
+
|
304
|
+
def trigger_publication
|
305
|
+
# TODO: Skip if already published, update when published_at changes
|
306
|
+
Trigger.post_action(published_at, self, "publish!")
|
307
|
+
end
|
308
|
+
end
|
data/app/models/blog.rb
ADDED
@@ -0,0 +1,280 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# The Blog class represents the one and only blog. It stores most
|
4
|
+
# configuration settings and is linked to most of the assorted content
|
5
|
+
# classes via has_many.
|
6
|
+
#
|
7
|
+
# Once upon a time, there were plans to make publify handle multiple blogs,
|
8
|
+
# but it never happened and publify is now firmly single-blog.
|
9
|
+
#
|
10
|
+
class Blog < ApplicationRecord
|
11
|
+
include ConfigManager
|
12
|
+
include Rails.application.routes.url_helpers
|
13
|
+
|
14
|
+
has_many :contents
|
15
|
+
has_many :articles
|
16
|
+
has_many :feedback, through: :articles
|
17
|
+
|
18
|
+
has_many :published_articles, ->() { published }, class_name: "Article"
|
19
|
+
|
20
|
+
has_many :pages
|
21
|
+
has_many :tags
|
22
|
+
has_many :notes
|
23
|
+
|
24
|
+
has_many :redirects
|
25
|
+
has_many :sidebars, ->() { order("active_position ASC") }
|
26
|
+
|
27
|
+
attr_accessor :custom_permalink
|
28
|
+
|
29
|
+
default_scope -> { order("id") }
|
30
|
+
|
31
|
+
validates :blog_name, presence: true
|
32
|
+
|
33
|
+
serialize :settings, Hash
|
34
|
+
|
35
|
+
# Description
|
36
|
+
setting :blog_name, :string, "My Shiny Weblog!"
|
37
|
+
setting :blog_subtitle, :string, ""
|
38
|
+
setting :geourl_location, :string, ""
|
39
|
+
setting :canonical_server_url, :string, "" # Deprecated
|
40
|
+
setting :lang, :string, "en_US"
|
41
|
+
|
42
|
+
# Spam
|
43
|
+
setting :sp_global, :boolean, false
|
44
|
+
setting :sp_article_auto_close, :integer, 0
|
45
|
+
setting :sp_url_limit, :integer, 0
|
46
|
+
setting :sp_akismet_key, :string, ""
|
47
|
+
setting :use_recaptcha, :boolean, false
|
48
|
+
|
49
|
+
# Mostly Behaviour
|
50
|
+
setting :text_filter, :string, "markdown smartypants"
|
51
|
+
setting :comment_text_filter, :string, "markdown smartypants"
|
52
|
+
setting :limit_article_display, :integer, 9
|
53
|
+
setting :limit_archives_display, :integer, 9
|
54
|
+
setting :limit_rss_display, :integer, 10
|
55
|
+
setting :default_allow_pings, :boolean, false
|
56
|
+
setting :default_allow_comments, :boolean, false
|
57
|
+
setting :default_moderate_comments, :boolean, false
|
58
|
+
# deprecated but still needed for backward compatibility
|
59
|
+
setting :show_extended_on_rss, :boolean, false
|
60
|
+
setting :hide_extended_on_rss, :boolean, false
|
61
|
+
setting :theme, :string, "plain"
|
62
|
+
setting :plugin_avatar, :string, ""
|
63
|
+
setting :global_pings_disable, :boolean, false
|
64
|
+
setting :send_outbound_pings, :boolean, true
|
65
|
+
setting :email_from, :string, "publify@example.com"
|
66
|
+
setting :allow_signup, :integer, 0
|
67
|
+
setting :date_format, :string, "%d/%m/%Y"
|
68
|
+
setting :time_format, :string, "%Hh%M"
|
69
|
+
setting :image_avatar_size, :integer, 48
|
70
|
+
setting :image_thumb_size, :integer, 360
|
71
|
+
setting :image_medium_size, :integer, 805
|
72
|
+
|
73
|
+
# SEO
|
74
|
+
setting :meta_description, :string, ""
|
75
|
+
setting :meta_keywords, :string, ""
|
76
|
+
setting :google_analytics, :string, ""
|
77
|
+
setting :rss_description, :boolean, false
|
78
|
+
setting :rss_description_text, :string, <<-HTML.strip_heredoc
|
79
|
+
<hr />
|
80
|
+
<p><small>Original article written by %author% and published on <a href='%blog_url%'>%blog_name%</a>
|
81
|
+
| <a href='%permalink_url%'>direct link to this article</a>
|
82
|
+
| If you are reading this article anywhere other than on <a href='%blog_url%'>%blog_name%</a>,
|
83
|
+
it has been illegally reproduced and without proper authorization.</small></p>
|
84
|
+
HTML
|
85
|
+
setting :permalink_format, :string, "/%year%/%month%/%day%/%title%"
|
86
|
+
setting :robots, :string, 'User-agent: *\nAllow: /\nDisallow: /admin\n'
|
87
|
+
setting :humans, :string, <<-TEXT.strip_heredoc
|
88
|
+
/* TEAM */
|
89
|
+
Your title: Your name.
|
90
|
+
Site: email, link to a contact form, etc.
|
91
|
+
Twitter: your Twitter username.
|
92
|
+
|
93
|
+
/* SITE */
|
94
|
+
Software: Publify [https://publify.github.io/] #{PublifyCore::VERSION}
|
95
|
+
TEXT
|
96
|
+
# deprecated but still needed for backward compatibility
|
97
|
+
setting :index_categories, :boolean, true
|
98
|
+
setting :unindex_categories, :boolean, false
|
99
|
+
# deprecated but still needed for backward compatibility
|
100
|
+
setting :index_tags, :boolean, true
|
101
|
+
setting :unindex_tags, :boolean, false
|
102
|
+
setting :admin_display_elements, :integer, 10
|
103
|
+
setting :google_verification, :string, ""
|
104
|
+
# deprecated but still needed for backward compatibility
|
105
|
+
setting :nofollowify, :boolean, true
|
106
|
+
setting :dofollowify, :boolean, false
|
107
|
+
setting :use_meta_keyword, :boolean, true
|
108
|
+
setting :home_title_template, :string, "%blog_name% | %blog_subtitle%"
|
109
|
+
setting :home_desc_template, :string, "%blog_name% | %blog_subtitle% | %meta_keywords%"
|
110
|
+
setting :article_title_template, :string, "%title% | %blog_name%"
|
111
|
+
setting :article_desc_template, :string, "%excerpt%"
|
112
|
+
setting :page_title_template, :string, "%title% | %blog_name%"
|
113
|
+
setting :page_desc_template, :string, "%excerpt%"
|
114
|
+
setting :paginated_title_template, :string, "%blog_name% | %blog_subtitle% %page%"
|
115
|
+
setting :paginated_desc_template, :string,
|
116
|
+
"%blog_name% | %blog_subtitle% | %meta_keywords% %page%"
|
117
|
+
setting :tag_title_template, :string, "Category: %name% | %blog_name% %page%"
|
118
|
+
setting :tag_desc_template, :string, "%name% | %blog_name% | %blog_subtitle% %page%"
|
119
|
+
setting :author_title_template, :string, "%author% | %blog_name%"
|
120
|
+
setting :author_desc_template, :string, "%author% | %blog_name% | %blog_subtitle%"
|
121
|
+
setting :archives_title_template, :string, "Archives for %blog_name% %date% %page%"
|
122
|
+
setting :archives_desc_template, :string,
|
123
|
+
"Archives for %blog_name% %date% %page% %blog_subtitle%"
|
124
|
+
setting :search_title_template, :string, "Results for %search% | %blog_name% %page%"
|
125
|
+
setting :search_desc_template, :string,
|
126
|
+
"Results for %search% | %blog_name% | %blog_subtitle% %page%"
|
127
|
+
setting :statuses_title_template, :string, "Notes | %blog_name% %page%"
|
128
|
+
setting :statuses_desc_template, :string, "Notes | %blog_name% | %blog_subtitle% %page%"
|
129
|
+
setting :status_title_template, :string, "%body% | %blog_name%"
|
130
|
+
setting :status_desc_template, :string, "%excerpt%"
|
131
|
+
|
132
|
+
setting :custom_tracking_field, :string, ""
|
133
|
+
# setting :meta_author_template, :string, "%blog_name% | %nickname%"
|
134
|
+
|
135
|
+
setting :twitter_consumer_key, :string, ""
|
136
|
+
setting :twitter_consumer_secret, :string, ""
|
137
|
+
setting :custom_url_shortener, :string, ""
|
138
|
+
setting :statuses_in_timeline, :boolean, true
|
139
|
+
|
140
|
+
validate :permalink_has_identifier
|
141
|
+
# validates :base_url, presence: true
|
142
|
+
|
143
|
+
# Find the Blog that matches a specific base URL. If no Blog object is found
|
144
|
+
# that matches, then grab the first blog. If *that* fails, then create a new
|
145
|
+
# Blog. The last case should only be used when Publify is first installed.
|
146
|
+
def self.find_blog(base_url)
|
147
|
+
Blog.find_by(base_url: base_url) || Blog.first || Blog.new
|
148
|
+
end
|
149
|
+
|
150
|
+
def global_pings_enabled?
|
151
|
+
!global_pings_disable?
|
152
|
+
end
|
153
|
+
|
154
|
+
# Check that all required blog settings have a value.
|
155
|
+
def configured?
|
156
|
+
settings.key?("blog_name")
|
157
|
+
end
|
158
|
+
|
159
|
+
# The +Theme+ object for the current theme.
|
160
|
+
def current_theme(reload = nil)
|
161
|
+
@current_theme = nil if reload
|
162
|
+
@current_theme ||= Theme.find(theme) || Theme.new("", "")
|
163
|
+
end
|
164
|
+
|
165
|
+
module BasedUrlFor
|
166
|
+
# Generate a URL based on the +base_url+. This allows us to generate URLs
|
167
|
+
# without needing a controller handy, so we can produce URLs from within models
|
168
|
+
# where appropriate.
|
169
|
+
#
|
170
|
+
# It also caches the result in the Rails cache, so repeated URL generation
|
171
|
+
# requests should be fast, as they bypass all of Rails' route logic.
|
172
|
+
def url_for(options = {}, extra_params = {})
|
173
|
+
case options
|
174
|
+
when String
|
175
|
+
options = options.sub(%r{^/}, "")
|
176
|
+
url_generated = if extra_params[:only_path]
|
177
|
+
root_path
|
178
|
+
else
|
179
|
+
base_url
|
180
|
+
end
|
181
|
+
# They asked for 'url_for "/some/path"', so return it unedited.
|
182
|
+
url_generated += "/#{options}"
|
183
|
+
url_generated += "##{extra_params[:anchor]}" if extra_params[:anchor]
|
184
|
+
url_generated
|
185
|
+
when Hash
|
186
|
+
merged_opts = options.reverse_merge!(only_path: false, controller: "",
|
187
|
+
action: "permalink",
|
188
|
+
host: host_with_port,
|
189
|
+
script_name: root_path)
|
190
|
+
cache_key = merged_opts.values.prepend("blog-urlfor-withbaseurl").join("-")
|
191
|
+
unless Rails.cache.exist?(cache_key)
|
192
|
+
Rails.cache.write(cache_key, super(merged_opts))
|
193
|
+
end
|
194
|
+
Rails.cache.read(cache_key)
|
195
|
+
else
|
196
|
+
raise "Invalid URL in url_for: #{options.inspect}"
|
197
|
+
end
|
198
|
+
end
|
199
|
+
end
|
200
|
+
|
201
|
+
prepend BasedUrlFor
|
202
|
+
|
203
|
+
# The URL for a static file.
|
204
|
+
def file_url(filename)
|
205
|
+
if CarrierWave.configure { |config| config.storage.name == "CarrierWave::Storage::Fog" }
|
206
|
+
filename
|
207
|
+
else
|
208
|
+
url_for filename, only_path: false
|
209
|
+
end
|
210
|
+
end
|
211
|
+
|
212
|
+
def articles_matching(query, args = {})
|
213
|
+
Article.search(query, args)
|
214
|
+
end
|
215
|
+
|
216
|
+
def per_page(format)
|
217
|
+
return limit_article_display if format.nil? || format == "html"
|
218
|
+
|
219
|
+
limit_rss_display
|
220
|
+
end
|
221
|
+
|
222
|
+
def rss_limit_params
|
223
|
+
limit = limit_rss_display.to_i
|
224
|
+
if limit.zero?
|
225
|
+
{}
|
226
|
+
else
|
227
|
+
{ limit: limit }
|
228
|
+
end
|
229
|
+
end
|
230
|
+
|
231
|
+
def permalink_has_identifier
|
232
|
+
unless /(%title%)/.match?(permalink_format)
|
233
|
+
errors.add(:base, I18n.t("errors.permalink_need_a_title"))
|
234
|
+
end
|
235
|
+
|
236
|
+
if /\.(atom|rss)$/.match?(permalink_format)
|
237
|
+
errors.add(:permalink_format, I18n.t("errors.cant_end_with_rss_or_atom"))
|
238
|
+
end
|
239
|
+
end
|
240
|
+
|
241
|
+
def root_path
|
242
|
+
split_base_url[:root_path]
|
243
|
+
end
|
244
|
+
|
245
|
+
def text_filter_object
|
246
|
+
TextFilter.make_filter(text_filter)
|
247
|
+
end
|
248
|
+
|
249
|
+
def has_twitter_configured?
|
250
|
+
return false if twitter_consumer_key.nil? || twitter_consumer_secret.nil?
|
251
|
+
return false if twitter_consumer_key.empty? || twitter_consumer_secret.empty?
|
252
|
+
|
253
|
+
true
|
254
|
+
end
|
255
|
+
|
256
|
+
def allow_signup?
|
257
|
+
allow_signup == 1
|
258
|
+
end
|
259
|
+
|
260
|
+
def shortener_url
|
261
|
+
custom_url_shortener.present? ? custom_url_shortener : base_url
|
262
|
+
end
|
263
|
+
|
264
|
+
private
|
265
|
+
|
266
|
+
def host_with_port
|
267
|
+
split_base_url[:host_with_port]
|
268
|
+
end
|
269
|
+
|
270
|
+
def split_base_url
|
271
|
+
unless @split_base_url
|
272
|
+
raise "Invalid base_url: #{base_url}" unless base_url =~ %r{(https?)://([^/]*)(.*)}
|
273
|
+
|
274
|
+
@split_base_url = { protocol: Regexp.last_match[1],
|
275
|
+
host_with_port: Regexp.last_match[2],
|
276
|
+
root_path: Regexp.last_match[3].gsub(%r{/$}, "") }
|
277
|
+
end
|
278
|
+
@split_base_url
|
279
|
+
end
|
280
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "timeout"
|
4
|
+
|
5
|
+
class Comment < Feedback
|
6
|
+
belongs_to :user, optional: true
|
7
|
+
content_fields :body
|
8
|
+
validates :author, :body, presence: true
|
9
|
+
|
10
|
+
attr_accessor :referrer, :permalink
|
11
|
+
|
12
|
+
scope :spam, -> { where(state: "spam") }
|
13
|
+
scope :not_spam, -> { where("state != 'spam'") }
|
14
|
+
scope :presumed_spam, -> { where(state: "presumed_spam") }
|
15
|
+
scope :presumed_ham, -> { where(state: "presumed_ham") }
|
16
|
+
scope :ham, -> { where(state: "ham") }
|
17
|
+
scope :unconfirmed, -> { where(state: %w(presumed_spam presumed_ham)) }
|
18
|
+
|
19
|
+
scope :last_published, -> { published.limit(5).order("created_at DESC") }
|
20
|
+
|
21
|
+
def notify_user_via_email(user)
|
22
|
+
# EmailNotify.send_comment(self, user) if user.notify_via_email?
|
23
|
+
end
|
24
|
+
|
25
|
+
def interested_users
|
26
|
+
User.where(notify_on_comments: true)
|
27
|
+
end
|
28
|
+
|
29
|
+
def default_text_filter
|
30
|
+
TextFilter.find_or_default(blog.comment_text_filter)
|
31
|
+
end
|
32
|
+
|
33
|
+
def feed_title
|
34
|
+
"Comment on #{article.title} by #{author}"
|
35
|
+
end
|
36
|
+
|
37
|
+
def send_notifications
|
38
|
+
really_send_notifications
|
39
|
+
end
|
40
|
+
|
41
|
+
protected
|
42
|
+
|
43
|
+
def article_allows_feedback?
|
44
|
+
return true if article.allow_comments?
|
45
|
+
|
46
|
+
errors.add(:article, "Article is not open to comments")
|
47
|
+
false
|
48
|
+
end
|
49
|
+
|
50
|
+
def originator
|
51
|
+
author
|
52
|
+
end
|
53
|
+
|
54
|
+
def content_fields
|
55
|
+
[:body]
|
56
|
+
end
|
57
|
+
end
|