spina-admin-conferences-blog 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/MIT-LICENSE +20 -0
- data/README.md +42 -0
- data/Rakefile +34 -0
- data/app/assets/config/spina_admin_conferences_blog_manifest.js +0 -0
- data/app/controllers/spina/admin/conferences/blog/categories_controller.rb +80 -0
- data/app/controllers/spina/admin/conferences/blog/posts_controller.rb +103 -0
- data/app/decorators/spina/admin/conferences/blog/post_decorator.rb +26 -0
- data/app/helpers/spina/admin/conferences/blog/posts_helper.rb +18 -0
- data/app/models/spina/admin/conferences/blog/application_record.rb +12 -0
- data/app/models/spina/admin/conferences/blog/category.rb +23 -0
- data/app/models/spina/admin/conferences/blog/post.rb +52 -0
- data/app/models/spina/admin/conferences/blog.rb +10 -0
- data/app/views/layouts/spina/admin/conferences/blog/blog.html.haml +29 -0
- data/app/views/layouts/spina/admin/conferences/blog/categories.html.haml +10 -0
- data/app/views/spina/admin/conferences/blog/categories/_category.html.haml +8 -0
- data/app/views/spina/admin/conferences/blog/categories/_form.html.haml +42 -0
- data/app/views/spina/admin/conferences/blog/categories/edit.html.haml +3 -0
- data/app/views/spina/admin/conferences/blog/categories/index.html.haml +23 -0
- data/app/views/spina/admin/conferences/blog/categories/new.html.haml +2 -0
- data/app/views/spina/admin/conferences/blog/posts/_form.html.haml +43 -0
- data/app/views/spina/admin/conferences/blog/posts/_form_post_configuration.html.haml +50 -0
- data/app/views/spina/admin/conferences/blog/posts/_form_post_content.html.haml +46 -0
- data/app/views/spina/admin/conferences/blog/posts/_form_post_seo.html.haml +14 -0
- data/app/views/spina/admin/conferences/blog/posts/_post.html.haml +19 -0
- data/app/views/spina/admin/conferences/blog/posts/edit.html.haml +3 -0
- data/app/views/spina/admin/conferences/blog/posts/index.html.haml +23 -0
- data/app/views/spina/admin/conferences/blog/posts/new.html.haml +2 -0
- data/app/views/spina/admin/hooks/conferences/blog/_primary_navigation.html.haml +10 -0
- data/config/initializers/friendly_id.rb +94 -0
- data/config/locales/en.yml +41 -0
- data/config/locales/nl.yml +42 -0
- data/config/locales/pt-BR.yml +41 -0
- data/config/routes.rb +32 -0
- data/db/migrate/1_create_spina_blog_posts.rb +18 -0
- data/db/migrate/2_create_spina_blog_friendly_id_slugs.rb +19 -0
- data/db/migrate/3_create_spina_blog_categories.rb +12 -0
- data/db/migrate/4_add_category_id_to_spina_blog_posts.rb +7 -0
- data/db/migrate/5_add_featured_to_spina_blog_posts.rb +9 -0
- data/db/migrate/6_add_seo_fields.rb +11 -0
- data/lib/generators/spina_admin_conferences_blog/install_generator.rb +24 -0
- data/lib/spina/admin/conferences/blog/configuration.rb +17 -0
- data/lib/spina/admin/conferences/blog/engine.rb +24 -0
- data/lib/spina/admin/conferences/blog/version.rb +8 -0
- data/lib/spina/admin/conferences/blog.rb +18 -0
- data/lib/spina/admin/conferences.rb +6 -0
- data/lib/spina/admin.rb +5 -0
- data/lib/tasks/spina/admin/conferences/blog_tasks.rake +14 -0
- data/spec/controllers/spina/admin/conferences/blog/categories_controller_spec.rb +99 -0
- data/spec/controllers/spina/admin/conferences/blog/posts_controller_spec.rb +152 -0
- data/spec/dummy/Rakefile +8 -0
- data/spec/dummy/app/assets/config/manifest.js +4 -0
- data/spec/dummy/app/assets/javascripts/application.js +13 -0
- data/spec/dummy/app/assets/javascripts/cable.js +13 -0
- data/spec/dummy/app/assets/stylesheets/application.css +15 -0
- data/spec/dummy/app/assets/stylesheets/default/application.css.sass +0 -0
- data/spec/dummy/app/channels/application_cable/channel.rb +6 -0
- data/spec/dummy/app/channels/application_cable/connection.rb +6 -0
- data/spec/dummy/app/controllers/application_controller.rb +5 -0
- data/spec/dummy/app/helpers/application_helper.rb +4 -0
- data/spec/dummy/app/jobs/application_job.rb +4 -0
- data/spec/dummy/app/mailers/application_mailer.rb +6 -0
- data/spec/dummy/app/models/application_record.rb +6 -0
- data/spec/dummy/app/views/default/pages/homepage.html.haml +2 -0
- data/spec/dummy/app/views/default/pages/show.html.haml +3 -0
- data/spec/dummy/app/views/default/shared/_navigation.html.haml +2 -0
- data/spec/dummy/app/views/layouts/application.html.erb +14 -0
- data/spec/dummy/app/views/layouts/default/application.html.haml +11 -0
- data/spec/dummy/app/views/layouts/mailer.html.erb +13 -0
- data/spec/dummy/app/views/layouts/mailer.text.erb +1 -0
- data/spec/dummy/bin/bundle +5 -0
- data/spec/dummy/bin/rails +6 -0
- data/spec/dummy/bin/rake +6 -0
- data/spec/dummy/bin/setup +36 -0
- data/spec/dummy/bin/update +31 -0
- data/spec/dummy/config/application.rb +16 -0
- data/spec/dummy/config/boot.rb +7 -0
- data/spec/dummy/config/cable.yml +9 -0
- data/spec/dummy/config/database.yml +17 -0
- data/spec/dummy/config/environment.rb +7 -0
- data/spec/dummy/config/environments/development.rb +56 -0
- data/spec/dummy/config/environments/production.rb +88 -0
- data/spec/dummy/config/environments/test.rb +44 -0
- data/spec/dummy/config/initializers/application_controller_renderer.rb +8 -0
- data/spec/dummy/config/initializers/assets.rb +13 -0
- data/spec/dummy/config/initializers/backtrace_silencers.rb +9 -0
- data/spec/dummy/config/initializers/cookies_serializer.rb +7 -0
- data/spec/dummy/config/initializers/filter_parameter_logging.rb +6 -0
- data/spec/dummy/config/initializers/inflections.rb +18 -0
- data/spec/dummy/config/initializers/mime_types.rb +6 -0
- data/spec/dummy/config/initializers/mobility.rb +16 -0
- data/spec/dummy/config/initializers/new_framework_defaults.rb +25 -0
- data/spec/dummy/config/initializers/session_store.rb +5 -0
- data/spec/dummy/config/initializers/spina.rb +22 -0
- data/spec/dummy/config/initializers/themes/default.rb +32 -0
- data/spec/dummy/config/initializers/wrap_parameters.rb +16 -0
- data/spec/dummy/config/locales/en.yml +23 -0
- data/spec/dummy/config/puma.rb +49 -0
- data/spec/dummy/config/routes.rb +6 -0
- data/spec/dummy/config/secrets.yml +22 -0
- data/spec/dummy/config/spring.rb +8 -0
- data/spec/dummy/config.ru +7 -0
- data/spec/dummy/db/migrate/20190513103729_create_spina_tables.spina.rb +132 -0
- data/spec/dummy/db/migrate/20190513103730_create_spina_translation_tables.spina.rb +46 -0
- data/spec/dummy/db/migrate/20190513103731_create_spina_navigations.spina.rb +24 -0
- data/spec/dummy/db/migrate/20190513103732_add_password_reset_token_to_spina_users.spina.rb +9 -0
- data/spec/dummy/db/migrate/20190513103733_remove_translated_columns.spina.rb +14 -0
- data/spec/dummy/db/migrate/20190513103734_create_spina_options.spina.rb +11 -0
- data/spec/dummy/db/migrate/20190513103735_create_spina_settings.spina.rb +14 -0
- data/spec/dummy/db/migrate/20190513103736_create_spina_media_folders.spina.rb +11 -0
- data/spec/dummy/db/migrate/20190513103737_create_spina_images.spina.rb +13 -0
- data/spec/dummy/db/migrate/20190513103738_create_spina_image_collections.spina.rb +17 -0
- data/spec/dummy/db/migrate/20190513103739_create_spina_resources.spina.rb +18 -0
- data/spec/dummy/db/schema.rb +288 -0
- data/spec/dummy/db/seeds.rb +4 -0
- data/spec/dummy/public/404.html +67 -0
- data/spec/dummy/public/422.html +67 -0
- data/spec/dummy/public/500.html +66 -0
- data/spec/dummy/public/apple-touch-icon-precomposed.png +0 -0
- data/spec/dummy/public/apple-touch-icon.png +0 -0
- data/spec/dummy/public/favicon.ico +0 -0
- data/spec/factories/spina/admin/conferences/blog/categories.rb +11 -0
- data/spec/factories/spina/admin/conferences/blog/posts.rb +16 -0
- data/spec/models/spina/admin/conferences/blog/category_spec.rb +21 -0
- data/spec/models/spina/admin/conferences/blog/post_spec.rb +39 -0
- data/spec/rails_helper.rb +68 -0
- data/spec/spec_helper.rb +97 -0
- data/spec/support/capybara.rb +25 -0
- data/spec/support/controller_helpers.rb +25 -0
- data/spec/support/controller_routes.rb +13 -0
- data/spec/support/factory_bot.rb +5 -0
- data/spec/support/rails_controller_testing.rb +13 -0
- data/spec/support/system_tests.rb +11 -0
- data/spec/system/spina/admin/conferences/blog/posts_spec.rb +34 -0
- data/spec/system/support/image.png +0 -0
- metadata +508 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: f48bd9e0dcef8d18d11ad490f317221c5a35314ac5edbadd344eb8c7f626c82c
|
4
|
+
data.tar.gz: c9246101dc71030fbbfba1d4c7af71aa5d7d1070a699d10df445e430fdb0722c
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: c38f80add14ad94be8a44041cc4cec47ea9799d25df54280ed2f53453d36ccf2a0cf025a1c1f22c390e00ed67e1caa0c05ed4f20402494286a4f88e3e32174de
|
7
|
+
data.tar.gz: c0069a54fcd156f8c50ad164b4be8013af03355c75cf803273037002d982fb2edf78feda6aed4948091e572bc2734ce057dd88e797c97cd37dba0936a0b356cd
|
data/MIT-LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright 2017 Tom Simnett
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,42 @@
|
|
1
|
+
[![Build Status](https://travis-ci.org/SpinaCMS/spina-blog.svg?branch=master)](https://travis-ci.org/initforthe/spina-blog) [![Code Climate](https://codeclimate.com/github/initforthe/spina-blog/badges/gpa.svg)](https://codeclimate.com/github/initforthe/spina-blog) [![Test Coverage](https://codeclimate.com/github/initforthe/spina-blog/badges/coverage.svg)](https://codeclimate.com/github/initforthe/spina-blog/coverage)
|
2
|
+
|
3
|
+
# Spina::Blog
|
4
|
+
Simple blog engine for [Spina CMS](https://www.spinacms.com/). It supports posts and categories.
|
5
|
+
|
6
|
+
## Usage
|
7
|
+
How to use my plugin.
|
8
|
+
|
9
|
+
## Installation
|
10
|
+
Add this line to your application's Gemfile:
|
11
|
+
|
12
|
+
```ruby
|
13
|
+
gem 'spina-blog'
|
14
|
+
```
|
15
|
+
|
16
|
+
And then execute:
|
17
|
+
```bash
|
18
|
+
$ bundle
|
19
|
+
```
|
20
|
+
|
21
|
+
And install:
|
22
|
+
```bash
|
23
|
+
$ rails g spina_blog:install
|
24
|
+
```
|
25
|
+
|
26
|
+
Or install it yourself as:
|
27
|
+
```bash
|
28
|
+
$ gem install spina-blog
|
29
|
+
```
|
30
|
+
|
31
|
+
## Contributing
|
32
|
+
The version of Spina to develop this engine against is defined in the gemspec. To override the version of refinery to develop against, edit the project Gemfile to point to a local path containing a clone of Spina CMS.
|
33
|
+
|
34
|
+
### Testing
|
35
|
+
|
36
|
+
With rake spec
|
37
|
+
```bash
|
38
|
+
$ bundle exec rake spec
|
39
|
+
```
|
40
|
+
|
41
|
+
## License
|
42
|
+
The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
|
data/Rakefile
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
begin
|
4
|
+
require 'bundler/setup'
|
5
|
+
rescue LoadError
|
6
|
+
puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
|
7
|
+
end
|
8
|
+
|
9
|
+
require 'rdoc/task'
|
10
|
+
|
11
|
+
RDoc::Task.new(:rdoc) do |rdoc|
|
12
|
+
rdoc.rdoc_dir = 'rdoc'
|
13
|
+
rdoc.title = 'Spina::Admin::Conferences::Blog'
|
14
|
+
rdoc.options << '--line-numbers'
|
15
|
+
rdoc.rdoc_files.include('README.md')
|
16
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
17
|
+
end
|
18
|
+
|
19
|
+
require 'bundler/gem_tasks'
|
20
|
+
|
21
|
+
APP_RAKEFILE = File.expand_path('spec/dummy/Rakefile', __dir__)
|
22
|
+
load 'rails/tasks/engine.rake'
|
23
|
+
|
24
|
+
Bundler::GemHelper.install_tasks
|
25
|
+
|
26
|
+
Dir[File.join(File.dirname(__FILE__), 'tasks/**/*.rake')].each { |f| load f }
|
27
|
+
|
28
|
+
require 'rspec/core'
|
29
|
+
require 'rspec/core/rake_task'
|
30
|
+
|
31
|
+
desc 'Run all specs in spec directory (excluding plugin specs)'
|
32
|
+
RSpec::Core::RakeTask.new(spec: 'app:db:test:prepare')
|
33
|
+
|
34
|
+
task default: :spec
|
File without changes
|
@@ -0,0 +1,80 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Spina
|
4
|
+
module Admin
|
5
|
+
module Conferences::Blog
|
6
|
+
# Spina::Admin::Conferences::Blog::CategoriesController
|
7
|
+
class CategoriesController < AdminController
|
8
|
+
before_action :category, except: %i[new create index]
|
9
|
+
before_action :set_breadcrumb
|
10
|
+
before_action :set_locale
|
11
|
+
|
12
|
+
decorates_assigned :category
|
13
|
+
|
14
|
+
layout 'spina/admin/conferences/blog/categories'
|
15
|
+
|
16
|
+
def index
|
17
|
+
@categories = Spina::Admin::Conferences::Blog::Category.order(:name)
|
18
|
+
end
|
19
|
+
|
20
|
+
def new
|
21
|
+
@category = Spina::Admin::Conferences::Blog::Category.new
|
22
|
+
add_breadcrumb I18n.t('spina.blog.categories.new')
|
23
|
+
render layout: 'spina/admin/admin'
|
24
|
+
end
|
25
|
+
|
26
|
+
def create
|
27
|
+
@category = Spina::Admin::Conferences::Blog::Category.new category_params
|
28
|
+
if @category.save
|
29
|
+
redirect_to spina.edit_admin_conferences_blog_category_url(@category.id),
|
30
|
+
notice: t('spina.blog.categories.saved')
|
31
|
+
else
|
32
|
+
add_breadcrumb I18n.t('spina.blog.categories.new')
|
33
|
+
render :new, layout: 'spina/admin/admin'
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def edit
|
38
|
+
add_breadcrumb @category.name
|
39
|
+
render layout: 'spina/admin/admin'
|
40
|
+
end
|
41
|
+
|
42
|
+
def update
|
43
|
+
if @category.update(category_params)
|
44
|
+
add_breadcrumb @category.name
|
45
|
+
redirect_to spina.edit_admin_conferences_blog_category_url(
|
46
|
+
@category.id, params: { locale: @locale }
|
47
|
+
), notice: t('spina.blog.categories.saved')
|
48
|
+
else
|
49
|
+
render :edit, layout: 'spina/admin/admin'
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def destroy
|
54
|
+
@category.destroy
|
55
|
+
redirect_to spina.admin_conferences_blog_categories_path
|
56
|
+
end
|
57
|
+
|
58
|
+
private
|
59
|
+
|
60
|
+
def set_breadcrumb
|
61
|
+
add_breadcrumb I18n.t('spina.blog.categories.name'),
|
62
|
+
spina.admin_conferences_blog_categories_path
|
63
|
+
end
|
64
|
+
|
65
|
+
def category
|
66
|
+
@category = Spina::Admin::Conferences::Blog::Category.find params[:id]
|
67
|
+
end
|
68
|
+
|
69
|
+
def set_locale
|
70
|
+
@locale = params[:locale] || I18n.default_locale
|
71
|
+
I18n.locale = @locale
|
72
|
+
end
|
73
|
+
|
74
|
+
def category_params
|
75
|
+
params.require(:category).permit(:name)
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
@@ -0,0 +1,103 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Spina
|
4
|
+
module Admin
|
5
|
+
module Conferences::Blog
|
6
|
+
# Spina::Admin::Conferences::Blog::PostsController
|
7
|
+
class PostsController < AdminController
|
8
|
+
before_action :post, except: %i[index live draft future new create]
|
9
|
+
before_action :set_breadcrumb
|
10
|
+
before_action :set_tabs, only: %i[new create edit update]
|
11
|
+
before_action :set_locale
|
12
|
+
|
13
|
+
decorates_assigned :post
|
14
|
+
|
15
|
+
layout 'spina/admin/conferences/blog/blog'
|
16
|
+
|
17
|
+
def index
|
18
|
+
@posts = Spina::Admin::Conferences::Blog::Post.order(created_at: :desc)
|
19
|
+
end
|
20
|
+
|
21
|
+
def live
|
22
|
+
@posts = Spina::Admin::Conferences::Blog::Post.live.order(created_at: :desc)
|
23
|
+
render :index
|
24
|
+
end
|
25
|
+
|
26
|
+
def draft
|
27
|
+
@posts = Spina::Admin::Conferences::Blog::Post.draft.order(created_at: :desc)
|
28
|
+
render :index
|
29
|
+
end
|
30
|
+
|
31
|
+
def future
|
32
|
+
@posts = Spina::Admin::Conferences::Blog::Post.future.order(created_at: :desc)
|
33
|
+
render :index
|
34
|
+
end
|
35
|
+
|
36
|
+
def new
|
37
|
+
@post = Spina::Admin::Conferences::Blog::Post.new
|
38
|
+
add_breadcrumb I18n.t('spina.blog.posts.new')
|
39
|
+
render layout: 'spina/admin/admin'
|
40
|
+
end
|
41
|
+
|
42
|
+
def create
|
43
|
+
@post = Spina::Admin::Conferences::Blog::Post.new post_params
|
44
|
+
if @post.save
|
45
|
+
redirect_to spina.edit_admin_conferences_blog_post_url(@post.id),
|
46
|
+
notice: t('spina.blog.posts.saved')
|
47
|
+
else
|
48
|
+
add_breadcrumb I18n.t('spina.blog.posts.new')
|
49
|
+
render :new, layout: 'spina/admin/admin'
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def edit
|
54
|
+
add_breadcrumb @post.title
|
55
|
+
render layout: 'spina/admin/admin'
|
56
|
+
end
|
57
|
+
|
58
|
+
def update
|
59
|
+
if @post.update(post_params)
|
60
|
+
add_breadcrumb @post.title
|
61
|
+
redirect_to spina.edit_admin_conferences_blog_post_url(
|
62
|
+
@post.id, params: { locale: @locale }
|
63
|
+
), notice: t('spina.blog.posts.saved')
|
64
|
+
else
|
65
|
+
render :edit, layout: 'spina/admin/admin'
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
def destroy
|
70
|
+
@post.destroy
|
71
|
+
redirect_to spina.admin_conferences_blog_posts_path
|
72
|
+
end
|
73
|
+
|
74
|
+
private
|
75
|
+
|
76
|
+
def post
|
77
|
+
@post = Spina::Admin::Conferences::Blog::Post.find(params[:id])
|
78
|
+
end
|
79
|
+
|
80
|
+
def set_breadcrumb
|
81
|
+
add_breadcrumb I18n.t('spina.blog.posts.title'),
|
82
|
+
spina.admin_conferences_blog_posts_path
|
83
|
+
end
|
84
|
+
|
85
|
+
def set_tabs
|
86
|
+
@tabs = %w[post_content post_configuration post_seo]
|
87
|
+
end
|
88
|
+
|
89
|
+
def set_locale
|
90
|
+
@locale = params[:locale] || I18n.default_locale
|
91
|
+
I18n.locale = @locale
|
92
|
+
end
|
93
|
+
|
94
|
+
def post_params
|
95
|
+
params.require(:post).permit(
|
96
|
+
:title, :slug, :excerpt, :content, :image_id, :draft, :published_at,
|
97
|
+
:user_id, :category_id, :featured, :seo_title, :description
|
98
|
+
)
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Spina
|
4
|
+
module Admin::Conferences::Blog
|
5
|
+
# Spina::Blog::PostDecorator
|
6
|
+
class PostDecorator < Draper::Decorator
|
7
|
+
delegate_all
|
8
|
+
|
9
|
+
def published_date
|
10
|
+
l model.published_at.to_date, format: :long
|
11
|
+
end
|
12
|
+
|
13
|
+
def word_count
|
14
|
+
h.strip_tags(content).split.size
|
15
|
+
end
|
16
|
+
|
17
|
+
def image_count
|
18
|
+
Nokogiri::HTML(content).css('img').size
|
19
|
+
end
|
20
|
+
|
21
|
+
def read_time
|
22
|
+
((word_count / (275 / 60.to_f) + (image_count * 12)) / 60).ceil
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Spina
|
4
|
+
module Admin::Conferences::Blog
|
5
|
+
# Spina::Blog::PostsHelper
|
6
|
+
module PostsHelper
|
7
|
+
def formatted_date(year, month)
|
8
|
+
if month
|
9
|
+
date = Date.new year.to_i, month.to_i
|
10
|
+
date.strftime('%B %Y')
|
11
|
+
else
|
12
|
+
date = Date.new year.to_i
|
13
|
+
date.strftime('%Y')
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Spina
|
4
|
+
module Admin::Conferences::Blog
|
5
|
+
# Spina::Blog::Category
|
6
|
+
class Category < ApplicationRecord
|
7
|
+
extend FriendlyId
|
8
|
+
|
9
|
+
friendly_id :name, use: :slugged
|
10
|
+
|
11
|
+
has_many :posts, class_name: 'Spina::Blog::Post', inverse_of: :category
|
12
|
+
validates :name, presence: true, uniqueness: { case_sensitive: false }
|
13
|
+
|
14
|
+
def to_s
|
15
|
+
name
|
16
|
+
end
|
17
|
+
|
18
|
+
def self.table_name
|
19
|
+
'spina_blog_categories'
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Spina
|
4
|
+
module Admin::Conferences::Blog
|
5
|
+
# Spina::Blog::Post
|
6
|
+
class Post < ApplicationRecord
|
7
|
+
extend FriendlyId
|
8
|
+
|
9
|
+
friendly_id :title, use: :slugged
|
10
|
+
|
11
|
+
belongs_to :image, optional: true, class_name: 'Spina::Image'
|
12
|
+
|
13
|
+
belongs_to :user
|
14
|
+
belongs_to :category, inverse_of: :posts
|
15
|
+
|
16
|
+
validates :title, :content, presence: true
|
17
|
+
|
18
|
+
before_save :set_published_at
|
19
|
+
|
20
|
+
# Create a 301 redirect if the slug changed
|
21
|
+
after_update :rewrite_rule, if: -> { saved_change_to_slug? }
|
22
|
+
|
23
|
+
scope :available, -> { where('published_at <= ?', Time.zone.now) }
|
24
|
+
scope :future, -> { where('published_at >= ?', Time.zone.now) }
|
25
|
+
scope :draft, -> { where(draft: true) }
|
26
|
+
scope :live, -> { where(draft: false) }
|
27
|
+
scope :featured, -> { where(featured: true) }
|
28
|
+
scope :unfeatured, -> { where(featured: false) }
|
29
|
+
|
30
|
+
def self.table_name
|
31
|
+
'spina_blog_posts'
|
32
|
+
end
|
33
|
+
|
34
|
+
private
|
35
|
+
|
36
|
+
def set_published_at
|
37
|
+
self.published_at = Time.now if !draft? && published_at.blank?
|
38
|
+
end
|
39
|
+
|
40
|
+
def should_generate_new_friendly_id?
|
41
|
+
slug.blank? || draft_changed? || super
|
42
|
+
end
|
43
|
+
|
44
|
+
def rewrite_rule
|
45
|
+
::Spina::RewriteRule.create(
|
46
|
+
old_path: "/blog/posts/#{slug_before_last_save}",
|
47
|
+
new_path: "/blog/posts/#{slug}"
|
48
|
+
)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
- content_for(:permanent_notice) do
|
2
|
+
- unless current_account.robots_allowed?
|
3
|
+
.permanent-notice.permanent-notice-info
|
4
|
+
= icon('search')
|
5
|
+
%p
|
6
|
+
=t 'spina.pages.invisible_to_search_engines'
|
7
|
+
%small=t 'spina.pages.invisible_to_search_engines_description'
|
8
|
+
|
9
|
+
- content_for :application do
|
10
|
+
%header#header
|
11
|
+
#header_actions
|
12
|
+
= yield(:header_actions) if content_for?(:header_actions)
|
13
|
+
|
14
|
+
.breadcrumbs= render_breadcrumbs separator: '<div class="divider"></div>'
|
15
|
+
|
16
|
+
%nav#secondary.tabs
|
17
|
+
%ul
|
18
|
+
%li{class: ('active' if controller_name == 'posts' and action_name == 'index')}
|
19
|
+
= link_to t('spina.blog.posts.all_posts'), spina.admin_conferences_blog_posts_path
|
20
|
+
%li{class: ('active' if controller_name == 'posts' and action_name == 'live')}
|
21
|
+
= link_to t('spina.blog.posts.live_posts'), spina.live_admin_conferences_blog_posts_path
|
22
|
+
%li{class: ('active' if controller_name == 'posts' and action_name == 'draft')}
|
23
|
+
= link_to t('spina.blog.posts.draft_posts'), spina.draft_admin_conferences_blog_posts_path
|
24
|
+
%li{class: ('active' if controller_name == 'posts' and action_name == 'future')}
|
25
|
+
= link_to t('spina.blog.posts.scheduled_posts'), spina.future_admin_conferences_blog_posts_path
|
26
|
+
|
27
|
+
= yield
|
28
|
+
|
29
|
+
= render template: "layouts/spina/admin/admin"
|
@@ -0,0 +1,10 @@
|
|
1
|
+
- content_for :application do
|
2
|
+
%header#header
|
3
|
+
#header_actions
|
4
|
+
= yield(:header_actions) if content_for?(:header_actions)
|
5
|
+
|
6
|
+
.breadcrumbs= render_breadcrumbs separator: '<div class="divider"></div>'
|
7
|
+
|
8
|
+
= yield
|
9
|
+
|
10
|
+
= render template: "layouts/spina/admin/admin"
|
@@ -0,0 +1,8 @@
|
|
1
|
+
%tr{data: { id: category.id }}
|
2
|
+
%td.nowrap
|
3
|
+
%h3= link_to category.name, spina.edit_admin_conferences_blog_category_path(category.id)
|
4
|
+
|
5
|
+
%td.nowrap.text-right
|
6
|
+
= link_to spina.edit_admin_conferences_blog_category_path(category.id), class: 'button button-link' do
|
7
|
+
= icon 'pencil-outline'
|
8
|
+
= t('spina.blog.categorys.edit')
|
@@ -0,0 +1,42 @@
|
|
1
|
+
- if @category.errors.any?
|
2
|
+
- content_for :notifications do
|
3
|
+
.notification.notification-danger.animated.fadeInRight
|
4
|
+
= icon('exclamation')
|
5
|
+
.notification-message
|
6
|
+
=t 'spina.notifications.alert'
|
7
|
+
%small= @category.errors.full_messages.join('<br />').html_safe
|
8
|
+
= link_to '#', data: {close_notification: true} do
|
9
|
+
= icon('cross')
|
10
|
+
|
11
|
+
%header#header
|
12
|
+
.breadcrumbs= render_breadcrumbs separator: '<div class="divider"></div>'
|
13
|
+
- unless @category.new_record?
|
14
|
+
- if Spina.config.locales.size > 1
|
15
|
+
%div{style: 'display: inline-block; margin-left: 12px; top: -4px', data: {dropdown: true}}
|
16
|
+
= link_to '#', class: 'button button-link button-round button-small', data: {trigger: 'dropdown', target: '#locales'} do
|
17
|
+
= icon('comment')
|
18
|
+
= @locale.upcase
|
19
|
+
|
20
|
+
%ul#locales
|
21
|
+
- Spina.config.locales.each do |locale|
|
22
|
+
%li
|
23
|
+
= link_to t("languages.#{locale}"), "?locale=#{locale}", style: ('font-weight: 600' if @locale.to_s == locale.to_s)
|
24
|
+
|
25
|
+
#header_actions
|
26
|
+
%button.button.button-primary{type: 'submit', style: 'margin-right: 0', data: {disable_with: t('spina.blog.categories.saving')}}
|
27
|
+
= icon('check')
|
28
|
+
=t 'spina.blog.categories.save'
|
29
|
+
|
30
|
+
= hidden_field_tag :locale, @locale
|
31
|
+
|
32
|
+
- Mobility.with_locale(@locale) do
|
33
|
+
.active.well
|
34
|
+
.horizontal-form
|
35
|
+
.horizontal-form-group
|
36
|
+
.horizontal-form-label
|
37
|
+
= Spina::Admin::Conferences::Blog::Category.human_attribute_name :name
|
38
|
+
.horizontal-form-content
|
39
|
+
= f.text_field :name, placeholder: Spina::Admin::Conferences::Blog::Category.human_attribute_name(:name_placeholder)
|
40
|
+
|
41
|
+
- unless @category.new_record?
|
42
|
+
.pull-right= link_to t('spina.permanently_delete'), spina.admin_conferences_blog_category_path(@category.id), method: :delete, data: {confirm: t('spina.blog.category.delete_confirmation', subject: @category.name)}, class: 'button button-link button-danger'
|
@@ -0,0 +1,23 @@
|
|
1
|
+
- content_for :header_actions do
|
2
|
+
%span
|
3
|
+
= link_to spina.new_admin_conferences_blog_category_path, class: 'button button-primary', style: 'margin-right: 0' do
|
4
|
+
= icon 'plus'
|
5
|
+
= t 'spina.blog.categories.new'
|
6
|
+
|
7
|
+
|
8
|
+
|
9
|
+
.table-container
|
10
|
+
%table.table
|
11
|
+
%thead
|
12
|
+
%tr
|
13
|
+
%th Category name
|
14
|
+
%th
|
15
|
+
|
16
|
+
%tbody
|
17
|
+
- if @categories.any?
|
18
|
+
= render partial: 'category', collection: @categories, as: :category
|
19
|
+
|
20
|
+
- else
|
21
|
+
%tr
|
22
|
+
%td.align-center{colspan: 2}
|
23
|
+
%em There are no categories yet. Create your first one!
|
@@ -0,0 +1,43 @@
|
|
1
|
+
- if @post.errors.any?
|
2
|
+
- content_for :notifications do
|
3
|
+
.notification.notification-danger.animated.fadeInRight
|
4
|
+
= icon('exclamation')
|
5
|
+
.notification-message
|
6
|
+
=t 'spina.notifications.alert'
|
7
|
+
%small= @post.errors.full_messages.join('<br />').html_safe
|
8
|
+
= link_to '#', data: {close_notification: true} do
|
9
|
+
= icon('cross')
|
10
|
+
|
11
|
+
%header#header
|
12
|
+
.breadcrumbs= render_breadcrumbs separator: '<div class="divider"></div>'
|
13
|
+
- unless @post.new_record?
|
14
|
+
- if Spina.config.locales.size > 1
|
15
|
+
%div{style: 'display: inline-block; margin-left: 12px; top: -4px', data: {dropdown: true}}
|
16
|
+
= link_to '#', class: 'button button-link button-round button-small', data: {trigger: 'dropdown', target: '#locales'} do
|
17
|
+
= icon('comment')
|
18
|
+
= @locale.upcase
|
19
|
+
|
20
|
+
%ul#locales
|
21
|
+
- Spina.config.locales.each do |locale|
|
22
|
+
%li
|
23
|
+
= link_to t("languages.#{locale}"), "?locale=#{locale}", style: ('font-weight: 600' if @locale.to_s == locale.to_s)
|
24
|
+
|
25
|
+
#header_actions
|
26
|
+
%button.button.button-primary{type: 'submit', style: 'margin-right: 0', data: {disable_with: t('spina.blog.posts.saving')}}
|
27
|
+
= icon('check')
|
28
|
+
=t 'spina.blog.posts.save'
|
29
|
+
|
30
|
+
%nav#secondary.tabs
|
31
|
+
%ul
|
32
|
+
- @tabs.each_with_index do |tab, i|
|
33
|
+
%li{class: (i==0 ? 'active' : '')}
|
34
|
+
= link_to t("spina.blog.posts.#{tab}"), "##{tab}"
|
35
|
+
|
36
|
+
= hidden_field_tag :locale, @locale
|
37
|
+
|
38
|
+
- Mobility.with_locale(@locale) do
|
39
|
+
- @tabs.each do |tab|
|
40
|
+
= render "spina/admin/conferences/blog/posts/form_#{tab}", f: f
|
41
|
+
|
42
|
+
- unless @post.new_record?
|
43
|
+
.pull-right= link_to t('spina.permanently_delete'), spina.admin_conferences_blog_post_path(@post.id), method: :delete, data: {confirm: t('spina.post.delete_confirmation', subject: @post.title)}, class: 'button button-link button-danger'
|
@@ -0,0 +1,50 @@
|
|
1
|
+
#post_configuration.tab-content
|
2
|
+
.horizontal-form
|
3
|
+
%div{style: "margin: 40px 0"}
|
4
|
+
|
5
|
+
.horizontal-form-group
|
6
|
+
.horizontal-form-label
|
7
|
+
= Spina::Admin::Conferences::Blog::Post.human_attribute_name :category
|
8
|
+
.horizontal-form-content
|
9
|
+
.select-dropdown
|
10
|
+
= f.select :category_id, Spina::Admin::Conferences::Blog::Category.all.collect{|u| [u.name, u.id]},
|
11
|
+
include_blank: true, prompt: true
|
12
|
+
|
13
|
+
.horizontal-form-group
|
14
|
+
.horizontal-form-label
|
15
|
+
= Spina::Admin::Conferences::Blog::Post.human_attribute_name :draft
|
16
|
+
%small= Spina::Admin::Conferences::Blog::Post.human_attribute_name :draft_description
|
17
|
+
.horizontal-form-content
|
18
|
+
= f.check_box :draft, data: {switch: true}
|
19
|
+
|
20
|
+
.horizontal-form-group
|
21
|
+
.horizontal-form-label
|
22
|
+
= Spina::Admin::Conferences::Blog::Post.human_attribute_name :featured
|
23
|
+
%small= Spina::Admin::Conferences::Blog::Post.human_attribute_name :featured_description
|
24
|
+
.horizontal-form-content
|
25
|
+
= f.check_box :featured, data: {switch: true}
|
26
|
+
|
27
|
+
.horizontal-form-group
|
28
|
+
.horizontal-form-label
|
29
|
+
= Spina::Admin::Conferences::Blog::Post.human_attribute_name :slug
|
30
|
+
%small= Spina::Admin::Conferences::Blog::Post.human_attribute_name :slug_description
|
31
|
+
.horizontal-form-content
|
32
|
+
= f.text_field :slug, placeholder: Spina::Admin::Conferences::Blog::Post.human_attribute_name(:slug_placeholder)
|
33
|
+
- if @post.slug
|
34
|
+
%small
|
35
|
+
Current permalink:
|
36
|
+
\ /blog/posts/#{@post.slug}
|
37
|
+
|
38
|
+
.horizontal-form-group
|
39
|
+
.horizontal-form-label
|
40
|
+
= Spina::Admin::Conferences::Blog::Post.human_attribute_name :published_at
|
41
|
+
.horizontal-form-content
|
42
|
+
= f.datetime_field :published_at
|
43
|
+
|
44
|
+
.horizontal-form-group
|
45
|
+
.horizontal-form-label
|
46
|
+
= Spina::Admin::Conferences::Blog::Post.human_attribute_name :spina_user
|
47
|
+
.horizontal-form-content
|
48
|
+
.select-dropdown
|
49
|
+
= f.select :user_id, Spina::User.all.collect{|u| [u.name, u.id]},
|
50
|
+
include_blank: true, prompt: true
|