publify_core 10.0.4 → 11.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (200) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +243 -53
  3. data/app/assets/javascripts/publify.js +0 -1
  4. data/app/assets/javascripts/publify_admin.js +10 -9
  5. data/app/assets/stylesheets/accounts.css.scss +0 -2
  6. data/app/assets/stylesheets/administration_structure.css.scss +0 -4
  7. data/app/assets/stylesheets/publify.css.scss +0 -1
  8. data/app/assets/stylesheets/publify_admin.css.scss +0 -2
  9. data/app/assets/stylesheets/sidebar_admin.css.scss +0 -6
  10. data/app/controllers/admin/articles_controller.rb +1 -1
  11. data/app/controllers/admin/base_controller.rb +2 -2
  12. data/app/controllers/admin/redirects_controller.rb +2 -2
  13. data/app/controllers/admin/resources_controller.rb +1 -1
  14. data/app/controllers/admin/seo_controller.rb +2 -2
  15. data/app/controllers/admin/settings_controller.rb +2 -2
  16. data/app/controllers/admin/tags_controller.rb +1 -1
  17. data/app/controllers/admin/users_controller.rb +2 -2
  18. data/app/controllers/articles_controller.rb +2 -5
  19. data/app/controllers/authors_controller.rb +0 -2
  20. data/app/controllers/comments_controller.rb +5 -2
  21. data/app/controllers/content_controller.rb +0 -4
  22. data/app/controllers/notes_controller.rb +1 -6
  23. data/app/controllers/setup_controller.rb +1 -1
  24. data/app/controllers/tags_controller.rb +0 -1
  25. data/app/controllers/users/registrations_controller.rb +1 -0
  26. data/app/helpers/admin/base_helper.rb +20 -13
  27. data/app/helpers/admin/feedback_helper.rb +4 -4
  28. data/app/helpers/base_helper.rb +10 -6
  29. data/app/helpers/xml_helper.rb +4 -0
  30. data/app/models/article.rb +7 -7
  31. data/app/models/blog.rb +3 -3
  32. data/app/models/comment.rb +1 -1
  33. data/app/models/config_manager.rb +1 -3
  34. data/app/models/content.rb +4 -5
  35. data/app/models/content_base.rb +4 -3
  36. data/app/models/feedback.rb +1 -1
  37. data/app/models/note.rb +74 -8
  38. data/app/models/page.rb +1 -1
  39. data/app/models/redirect.rb +0 -4
  40. data/app/models/resource.rb +1 -0
  41. data/app/models/sidebar.rb +6 -14
  42. data/app/models/tag.rb +2 -2
  43. data/app/models/text_filter.rb +2 -2
  44. data/app/models/trigger.rb +1 -1
  45. data/app/models/user.rb +12 -21
  46. data/app/uploaders/resource_uploader.rb +1 -0
  47. data/app/views/admin/articles/_form.html.erb +99 -105
  48. data/app/views/admin/articles/index.html.erb +15 -23
  49. data/app/views/admin/dashboard/_comment.html.erb +1 -1
  50. data/app/views/admin/dashboard/_comments.html.erb +4 -6
  51. data/app/views/admin/dashboard/_drafts.html.erb +4 -6
  52. data/app/views/admin/dashboard/_overview.html.erb +2 -5
  53. data/app/views/admin/dashboard/_welcome.html.erb +19 -19
  54. data/app/views/admin/dashboard/index.html.erb +3 -3
  55. data/app/views/admin/feedback/_button.html.erb +7 -13
  56. data/app/views/admin/feedback/article.html.erb +17 -17
  57. data/app/views/admin/feedback/edit.html.erb +17 -21
  58. data/app/views/admin/feedback/index.html.erb +8 -8
  59. data/app/views/admin/notes/_form.html.erb +5 -5
  60. data/app/views/admin/notes/_list.html.erb +1 -1
  61. data/app/views/admin/notes/_note.html.erb +1 -1
  62. data/app/views/admin/notes/edit.html.erb +1 -1
  63. data/app/views/admin/notes/index.html.erb +1 -1
  64. data/app/views/admin/pages/_form.html.erb +23 -27
  65. data/app/views/admin/post_types/_index_and_form.html.erb +5 -5
  66. data/app/views/admin/redirects/_index_and_form.html.erb +2 -2
  67. data/app/views/admin/resources/index.html.erb +20 -8
  68. data/app/views/admin/seo/_general.html.erb +36 -36
  69. data/app/views/admin/seo/_permalinks.html.erb +22 -14
  70. data/app/views/admin/seo/_titles.html.erb +63 -63
  71. data/app/views/admin/settings/display.html.erb +23 -23
  72. data/app/views/admin/settings/feedback.html.erb +29 -29
  73. data/app/views/admin/settings/index.html.erb +21 -21
  74. data/app/views/admin/settings/write.html.erb +18 -18
  75. data/app/views/admin/shared/_flash.html.erb +6 -0
  76. data/app/views/admin/shared/_menu.html.erb +56 -68
  77. data/app/views/admin/sidebar/_config.html.erb +15 -19
  78. data/app/views/admin/sidebar/_target.html.erb +3 -3
  79. data/app/views/admin/sidebar/_target_sidebar.html.erb +14 -13
  80. data/app/views/admin/sidebar/index.html.erb +2 -2
  81. data/app/views/admin/tags/_index_and_form.html.erb +3 -3
  82. data/app/views/admin/themes/index.html.erb +21 -19
  83. data/app/views/admin/users/_form.html.erb +79 -79
  84. data/app/views/articles/search.html.erb +1 -1
  85. data/app/views/layouts/accounts.html.erb +7 -9
  86. data/app/views/layouts/administration.html.erb +2 -2
  87. data/app/views/notes/show.html.erb +15 -0
  88. data/app/views/setup/index.html.erb +1 -1
  89. data/app/views/shared/_atom_item_article.atom.builder +1 -3
  90. data/app/views/shared/_rss_item_article.rss.builder +1 -2
  91. data/config/i18n-tasks.yml +0 -1
  92. data/config/locales/ar.yml +3 -2
  93. data/config/locales/da.yml +3 -2
  94. data/config/locales/de.yml +3 -2
  95. data/config/locales/en.yml +3 -2
  96. data/config/locales/es-MX.yml +3 -2
  97. data/config/locales/fr.yml +3 -2
  98. data/config/locales/he.yml +3 -2
  99. data/config/locales/it.yml +3 -2
  100. data/config/locales/ja.yml +3 -2
  101. data/config/locales/lt.yml +3 -2
  102. data/config/locales/nb.yml +3 -2
  103. data/config/locales/nl.yml +3 -2
  104. data/config/locales/pl.yml +3 -2
  105. data/config/locales/pt-BR.yml +3 -2
  106. data/config/locales/ro.yml +3 -2
  107. data/config/locales/ru.yml +3 -2
  108. data/config/locales/zh-CN.yml +3 -2
  109. data/config/locales/zh-TW.yml +3 -2
  110. data/config/routes.rb +0 -11
  111. data/db/migrate/114_fixes_buggy_articles_and_notes.rb +2 -2
  112. data/db/migrate/20150807134129_simplify_redirect_relations.rb +1 -1
  113. data/db/migrate/20160605154632_remove_profiles.rb +1 -1
  114. data/db/migrate/20190208152646_move_text_filter_to_name.rb +2 -2
  115. data/lib/format.rb +2 -2
  116. data/lib/publify_core/engine.rb +10 -0
  117. data/lib/publify_core/string_ext.rb +1 -13
  118. data/lib/publify_core/text_filter/markdown.rb +5 -1
  119. data/lib/publify_core/text_filter/markdown_smartquotes.rb +6 -1
  120. data/lib/publify_core/version.rb +1 -1
  121. data/lib/publify_core.rb +2 -2
  122. data/lib/text_filter_plugin.rb +20 -22
  123. data/lib/theme.rb +56 -37
  124. metadata +100 -397
  125. data/app/assets/javascripts/bootstrap/affix.js +0 -164
  126. data/app/assets/javascripts/bootstrap/alert.js +0 -95
  127. data/app/assets/javascripts/bootstrap/button.js +0 -125
  128. data/app/assets/javascripts/bootstrap/collapse.js +0 -212
  129. data/app/assets/javascripts/bootstrap/dropdown.js +0 -165
  130. data/app/assets/javascripts/bootstrap/modal.js +0 -358
  131. data/app/assets/javascripts/bootstrap/tab.js +0 -155
  132. data/app/assets/javascripts/bootstrap/transition.js +0 -59
  133. data/app/assets/javascripts/bootstrap-sprockets.js +0 -8
  134. data/app/assets/javascripts/lightbox.js +0 -350
  135. data/app/assets/stylesheets/_bootstrap-compass.scss +0 -9
  136. data/app/assets/stylesheets/_bootstrap-mincer.scss +0 -19
  137. data/app/assets/stylesheets/_bootstrap-sprockets.scss +0 -9
  138. data/app/assets/stylesheets/_bootstrap.scss +0 -42
  139. data/app/assets/stylesheets/bootstrap/_alerts.scss +0 -73
  140. data/app/assets/stylesheets/bootstrap/_button-groups.scss +0 -242
  141. data/app/assets/stylesheets/bootstrap/_buttons.scss +0 -168
  142. data/app/assets/stylesheets/bootstrap/_close.scss +0 -37
  143. data/app/assets/stylesheets/bootstrap/_code.scss +0 -69
  144. data/app/assets/stylesheets/bootstrap/_component-animations.scss +0 -38
  145. data/app/assets/stylesheets/bootstrap/_dropdowns.scss +0 -213
  146. data/app/assets/stylesheets/bootstrap/_forms.scss +0 -586
  147. data/app/assets/stylesheets/bootstrap/_grid.scss +0 -94
  148. data/app/assets/stylesheets/bootstrap/_labels.scss +0 -66
  149. data/app/assets/stylesheets/bootstrap/_media.scss +0 -66
  150. data/app/assets/stylesheets/bootstrap/_mixins.scss +0 -37
  151. data/app/assets/stylesheets/bootstrap/_modals.scss +0 -150
  152. data/app/assets/stylesheets/bootstrap/_navbar.scss +0 -479
  153. data/app/assets/stylesheets/bootstrap/_navs.scss +0 -242
  154. data/app/assets/stylesheets/bootstrap/_normalize.scss +0 -427
  155. data/app/assets/stylesheets/bootstrap/_pagination.scss +0 -86
  156. data/app/assets/stylesheets/bootstrap/_panels.scss +0 -222
  157. data/app/assets/stylesheets/bootstrap/_print.scss +0 -99
  158. data/app/assets/stylesheets/bootstrap/_scaffolding.scss +0 -160
  159. data/app/assets/stylesheets/bootstrap/_tables.scss +0 -234
  160. data/app/assets/stylesheets/bootstrap/_theme.scss +0 -224
  161. data/app/assets/stylesheets/bootstrap/_type.scss +0 -296
  162. data/app/assets/stylesheets/bootstrap/_utilities.scss +0 -55
  163. data/app/assets/stylesheets/bootstrap/_variables.scss +0 -638
  164. data/app/assets/stylesheets/bootstrap/_wells.scss +0 -29
  165. data/app/assets/stylesheets/bootstrap/mixins/_alerts.scss +0 -15
  166. data/app/assets/stylesheets/bootstrap/mixins/_background-variant.scss +0 -12
  167. data/app/assets/stylesheets/bootstrap/mixins/_border-radius.scss +0 -18
  168. data/app/assets/stylesheets/bootstrap/mixins/_buttons.scss +0 -56
  169. data/app/assets/stylesheets/bootstrap/mixins/_center-block.scss +0 -7
  170. data/app/assets/stylesheets/bootstrap/mixins/_clearfix.scss +0 -22
  171. data/app/assets/stylesheets/bootstrap/mixins/_forms.scss +0 -82
  172. data/app/assets/stylesheets/bootstrap/mixins/_gradients.scss +0 -56
  173. data/app/assets/stylesheets/bootstrap/mixins/_grid-framework.scss +0 -81
  174. data/app/assets/stylesheets/bootstrap/mixins/_grid.scss +0 -122
  175. data/app/assets/stylesheets/bootstrap/mixins/_hide-text.scss +0 -21
  176. data/app/assets/stylesheets/bootstrap/mixins/_image.scss +0 -28
  177. data/app/assets/stylesheets/bootstrap/mixins/_labels.scss +0 -12
  178. data/app/assets/stylesheets/bootstrap/mixins/_nav-divider.scss +0 -10
  179. data/app/assets/stylesheets/bootstrap/mixins/_nav-vertical-align.scss +0 -9
  180. data/app/assets/stylesheets/bootstrap/mixins/_opacity.scss +0 -7
  181. data/app/assets/stylesheets/bootstrap/mixins/_pagination.scss +0 -24
  182. data/app/assets/stylesheets/bootstrap/mixins/_panels.scss +0 -20
  183. data/app/assets/stylesheets/bootstrap/mixins/_reset-filter.scss +0 -8
  184. data/app/assets/stylesheets/bootstrap/mixins/_resize.scss +0 -6
  185. data/app/assets/stylesheets/bootstrap/mixins/_responsive-visibility.scss +0 -17
  186. data/app/assets/stylesheets/bootstrap/mixins/_size.scss +0 -10
  187. data/app/assets/stylesheets/bootstrap/mixins/_tab-focus.scss +0 -9
  188. data/app/assets/stylesheets/bootstrap/mixins/_table-row.scss +0 -28
  189. data/app/assets/stylesheets/bootstrap/mixins/_text-emphasis.scss +0 -12
  190. data/app/assets/stylesheets/bootstrap/mixins/_text-overflow.scss +0 -8
  191. data/app/assets/stylesheets/bootstrap/mixins/_vendor-prefixes.scss +0 -222
  192. data/app/assets/stylesheets/lightbox.css +0 -63
  193. data/app/controllers/theme_controller.rb +0 -63
  194. data/app/views/notes/show_in_reply.html.erb +0 -18
  195. data/app/views/theme/static_view_test.html.erb +0 -1
  196. data/lib/publify_core/text_filter/twitterfilter.rb +0 -55
  197. data/lib/tasks/manifest.rake +0 -30
  198. /data/app/views/layouts/{default.html.erb → application.html.erb} +0 -0
  199. /data/themes/plain/javascripts/{theme.js → plain/theme.js} +0 -0
  200. /data/themes/plain/stylesheets/{theme.css → plain/theme.css} +0 -0
data/app/models/user.rb CHANGED
@@ -8,11 +8,12 @@ class User < ApplicationRecord
8
8
  ADMIN = "admin"
9
9
  PUBLISHER = "publisher"
10
10
  CONTRIBUTOR = "contributor"
11
+ MIN_PASSWORD_SCORE = 4
11
12
 
12
13
  # Include default devise modules. Others available are:
13
14
  # :confirmable, :lockable, :timeoutable and :omniauthable
14
15
  devise :database_authenticatable, :registerable,
15
- :recoverable, :rememberable, :trackable, :validatable, :zxcvbnable
16
+ :recoverable, :rememberable, :trackable, :validatable
16
17
  include ConfigManager
17
18
  include StringLengthLimit
18
19
 
@@ -23,6 +24,7 @@ class User < ApplicationRecord
23
24
  validates :login, length: { in: 3..40 }
24
25
  validates_default_string_length :email, :text_filter_name
25
26
  validates :name, length: { maximum: 2048 }
27
+ validate :strong_password, if: :password_required?
26
28
 
27
29
  belongs_to :resource, optional: true
28
30
  has_many :notifications, foreign_key: "notify_user_id"
@@ -31,7 +33,7 @@ class User < ApplicationRecord
31
33
 
32
34
  has_many :articles
33
35
 
34
- serialize :settings, Hash
36
+ serialize :settings, type: Hash, coder: YAML
35
37
 
36
38
  STATUS = %w(active inactive).freeze
37
39
 
@@ -73,24 +75,6 @@ class User < ApplicationRecord
73
75
  .map { |f| send(f) }.delete_if(&:empty?)
74
76
  end
75
77
 
76
- # Authenticate users with old password hashes
77
- alias devise_valid_password? valid_password?
78
-
79
- def valid_password?(password)
80
- devise_valid_password?(password)
81
- rescue BCrypt::Errors::InvalidHash
82
- digest = Digest::SHA1.hexdigest("#{self.class.salt}--#{password}--")
83
- if digest == encrypted_password
84
- # Update old SHA1 password with new Devise ByCrypt password
85
- self.encrypted_password = password_digest(password)
86
- save
87
- true
88
- else
89
- # If not BCrypt password and not old SHA1 password deny access
90
- false
91
- end
92
- end
93
-
94
78
  def active_for_authentication?
95
79
  super && state == "active"
96
80
  end
@@ -138,7 +122,14 @@ class User < ApplicationRecord
138
122
 
139
123
  private
140
124
 
125
+ def strong_password
126
+ return if password.blank?
127
+
128
+ test = Zxcvbn.test(password)
129
+ errors.add :password, :weak_password if test.score < MIN_PASSWORD_SCORE
130
+ end
131
+
141
132
  def set_default_profile
142
- self.profile ||= User.count.zero? ? "admin" : "contributor"
133
+ self.profile ||= User.none? ? "admin" : "contributor"
143
134
  end
144
135
  end
@@ -4,6 +4,7 @@ require "marcel"
4
4
 
5
5
  class ResourceUploader < CarrierWave::Uploader::Base
6
6
  include CarrierWave::MiniMagick
7
+
7
8
  before :process, :check_content_type!
8
9
 
9
10
  process :fix_exif_rotation, if: :image?
@@ -3,15 +3,15 @@
3
3
  <%= hidden_field_tag('article[id]', @article.id) if @article.present? %>
4
4
  </div>
5
5
  <div class="row save-bar">
6
- <div class="col-md-8 col-md-offset-2" id="save-bar">
7
- <div class="pull-right">
6
+ <div class="col-lg-8 offset-lg-2 d-flex justify-content-end" id="save-bar">
7
+ <div>
8
8
  <%= link_to(t('.cancel'), { action: 'index' }, { class: 'btn btn-default' }) %>
9
9
  <span id="preview_link">
10
10
  <%= link_to(t('.preview'), { controller: '/articles', action: 'preview', id: @article.id }, { target: 'new', class: 'btn btn-default' }) if @article.id %>
11
11
  </span>
12
- <input id="save_draft" type="submit" value="<%= t('.save_as_draft') %>" name="article[draft]" class="btn btn-default">
12
+ <input id="save_draft" type="submit" value="<%= t('.save_as_draft') %>" name="article[draft]" class="btn btn-secondary">
13
13
  <!-- Button trigger modal -->
14
- <button class="btn btn-success" data-toggle="modal" type="button" data-target="#publishOptions">
14
+ <button class="btn btn-success" data-bs-toggle="modal" type="button" data-bs-target="#publishOptions">
15
15
  <%= controller.action_name == 'new' ? t('.publish') : t('.save') %>
16
16
  </button>
17
17
  </div>
@@ -19,7 +19,7 @@
19
19
  </div>
20
20
 
21
21
  <div class="row">
22
- <div class="col-md-8 col-md-offset-2" id="error-message-article">
22
+ <div class="col-lg-8 offset-lg-2" id="error-message-article">
23
23
  <%= render 'shared/flash', flash: flash %>
24
24
  <% if @article.errors.any? %>
25
25
  <div id="error_explanation">
@@ -36,12 +36,12 @@
36
36
  </div>
37
37
 
38
38
  <div class="row">
39
- <div class="col-md-2" id="quicktags-block">
40
- <div id="quicktags" class="pull-right">
39
+ <div class="col-lg-2" id="quicktags-block">
40
+ <div id="quicktags" class="float-right">
41
41
  <script type="text/javascript">edToolbar('article_body_and_extended', '<%= @article.text_filter_name %>');</script>
42
42
  </div>
43
43
  </div>
44
- <div class="col-md-8">
44
+ <div class="col-lg-8">
45
45
  <%= text_field 'article', 'title', class: 'form-control', placeholder: t('.title') %>
46
46
  <div id="editor">
47
47
  <%= text_area('article', 'body_and_extended', class: 'form-control ', style: 'height: 360px', placeholder: t('.type_your_post')) %>
@@ -60,134 +60,128 @@
60
60
  </h2>
61
61
  </div>
62
62
  <div class="modal-body">
63
- <div class="well">
64
- <h4><%= t('.tags') %></h4>
65
- <div class="form-group">
66
- <%= text_field 'article', 'keywords', autocomplete: 'off', class: 'form-control tm-input' %>
63
+ <div class="card mb-3">
64
+ <div class="card-body">
65
+ <h4 class="card-title"><%= t('.tags') %></h4>
66
+ <div class="form-group">
67
+ <%= text_field 'article', 'keywords', autocomplete: 'off', class: 'form-control tm-input' %>
68
+ </div>
69
+ <p class="alert alert-warning"><%= t('.tags_explanation_html') %></p>
67
70
  </div>
68
- <p class="alert alert-warning"><%= t('.tags_explanation_html') %></p>
69
71
  </div>
70
72
 
71
73
  <% post_types = @post_types || [] %>
72
74
  <% if post_types.size.zero? %>
73
75
  <%= hidden_field_tag 'article[post_type]', 'read' %>
74
76
  <% else %>
75
- <div class="well">
76
- <h4><%= t('.article_type') %></h4>
77
- <%= select :article, :post_type, post_types.map { |pt| [pt.name, pt.permalink] }, include_blank: t('.default') %>
77
+ <div class="card mb-3">
78
+ <div class="card-body">
79
+ <h4 class="card-title"><%= t('.article_type') %></h4>
80
+ <%= select :article, :post_type, post_types.map { |pt| [pt.name, pt.permalink] }, include_blank: t('.default') %>
81
+ </div>
78
82
  </div>
79
83
  <% end %>
80
84
 
81
- <div class="well">
82
- <fieldset>
83
- <legend><%= t('.publish_settings') %></legend>
84
- <div class='control-group'>
85
- <p>
86
- <%= t('.permalink') %>:
87
- <%= toggle_element('permalink') %>
88
- </p>
89
- <div id="permalink" class="collapse">
90
- <div class="form-group">
91
- <%= text_field 'article', 'permalink', autocomplete: 'off', class: 'form-control' %>
92
- </div>
85
+ <div class="card">
86
+ <div class="card-body">
87
+ <fieldset>
88
+ <legend><%= t('.publish_settings') %></legend>
89
+ <div class='control-group'>
93
90
  <p>
94
- <span class="btn btn-mini btn-default">
95
- <%= toggle_element('permalink', t('.ok')) %>
96
- </span>
91
+ <%= t('.permalink') %>:
92
+ <%= toggle_element('permalink') %>
97
93
  </p>
94
+ <div id="permalink" class="mb-3 collapse">
95
+ <div class="mb-3">
96
+ <%= text_field 'article', 'permalink', autocomplete: 'off', class: 'form-control' %>
97
+ </div>
98
+ <%= toggle_element('permalink', t('.ok'), class: "btn btn-mini btn-secondary") %>
99
+ </div>
98
100
  </div>
99
- </div>
100
- <div class="control-group">
101
- <p>
102
- <%= t('.status') %>: <strong><%= @article.state.to_s.downcase %></strong>
103
- <%= toggle_element('status') %>
104
- </p>
105
- <div id="status" class="collapse">
106
- <label for="article_published" class="checkbox">
107
- <%= check_box 'article', 'published?' %>
108
- <%= t('.published') %>
109
- </label>
101
+ <div class="control-group">
110
102
  <p>
111
- <span class="btn btn-mini btn-default">
112
- <%= toggle_element 'status', t('.ok') %>
113
- </span>
103
+ <%= t('.status') %>: <strong><%= @article.state.to_s.downcase %></strong>
104
+ <%= toggle_element('status') %>
114
105
  </p>
106
+ <div id="status" class="mb-3 collapse">
107
+ <div class="mb-3">
108
+ <label for="article_published" class="checkbox">
109
+ <%= check_box 'article', 'published?' %>
110
+ <%= t('.published') %>
111
+ </label>
112
+ </div>
113
+ <%= toggle_element('status', t('.ok'), class: "btn btn-mini btn-secondary") %>
114
+ </div>
115
115
  </div>
116
- </div>
117
- <div class="control-group">
118
- <p>
119
- <%= t('.allowed_comments_html', allow_comment: content_tag(:strong, @article.allow_comments? ? t('.allow_comments_status.enabled') : t('.allow_comments_status.disabled'))) %>
120
- <%= toggle_element('conversation') %>
121
- </p>
122
- <div id="conversation" class="collapse">
123
- <label for="article_allow_comments" class="checkbox">
124
- <%= check_box 'article', 'allow_comments' %>
125
- <%= t('.allow_comments') %>
126
- </label>
116
+ <div class="control-group">
127
117
  <p>
128
- <span class="btn btn-mini btn-default">
129
- <%= toggle_element('conversation', t('.ok')) %>
130
- </span>
118
+ <%= t('.allowed_comments_html', allow_comment: content_tag(:strong, @article.allow_comments? ? t('.allow_comments_status.enabled') : t('.allow_comments_status.disabled'))) %>
119
+ <%= toggle_element('conversation') %>
131
120
  </p>
121
+ <div id="conversation" class="mb-3 collapse">
122
+ <div class="mb-3">
123
+ <label for="article_allow_comments" class="checkbox">
124
+ <%= check_box 'article', 'allow_comments' %>
125
+ <%= t('.allow_comments') %>
126
+ </label>
127
+ </div>
128
+ <div>
129
+ <%= toggle_element('conversation', t('.ok'), class: "btn btn-mini btn-secondary") %>
130
+ </div>
131
+ </div>
132
132
  </div>
133
- </div>
134
- <div class="control-group">
135
- <p>
136
- <%= t('.published') %>
137
- <strong>
138
- <% if @article.published_at.present? %>
139
- <%= display_date_and_time(@article.published_at) %>
140
- <% else %>
141
- <%= t('.now') %>
142
- <% end %>
143
- </strong>
144
- <%= toggle_element('publish') %>
145
- </p>
146
- <div id="publish" class="collapse">
147
- <%= datetime_field 'article', 'published_at' %>
133
+ <div class="control-group">
148
134
  <p>
149
- <span class="btn btn-mini btn-default">
150
- <%= toggle_element('publish', t('.ok')) %>
151
- </span>
135
+ <%= t('.published') %>
136
+ <strong>
137
+ <% if @article.published_at.present? %>
138
+ <%= display_date_and_time(@article.published_at) %>
139
+ <% else %>
140
+ <%= t('.now') %>
141
+ <% end %>
142
+ </strong>
143
+ <%= toggle_element('publish') %>
152
144
  </p>
145
+ <div id="publish" class="mb-3 collapse">
146
+ <div class="mb-3">
147
+ <%= datetime_field 'article', 'published_at' %>
148
+ </div>
149
+ <%= toggle_element('publish', t('.ok'), class: "btn btn-mini btn-secondary") %>
150
+ </div>
153
151
  </div>
154
- </div>
155
- <div class="control-group">
156
- <p>
157
- <%= t('.visibility') %>: <strong><%= @article.password.blank? ? t('.public') : t('.protected') %></strong>
158
- <%= toggle_element('visibility') %>
159
- </p>
160
- <div id="visibility" class="collapse">
161
- <label for="article_password"><%= t('.password') %></label>
162
- <%= text_field 'article', 'password', class: 'form-control' %>
152
+ <div class="control-group">
163
153
  <p>
164
- <span class="btn btn-mini btn-default">
165
- <%= toggle_element('visibility', t('.ok')) %>
166
- </span>
154
+ <%= t('.visibility') %>: <strong><%= @article.password.blank? ? t('.public') : t('.protected') %></strong>
155
+ <%= toggle_element('visibility') %>
167
156
  </p>
157
+ <div id="visibility" class="mb-3 collapse">
158
+ <div class="mb-3">
159
+ <label for="article_password"><%= t('.password') %></label>
160
+ <%= text_field 'article', 'password', class: 'form-control' %>
161
+ </div>
162
+ <%= toggle_element('visibility', t('.ok'), class: "btn btn-mini btn-secondary") %>
163
+ </div>
168
164
  </div>
169
- </div>
170
- <div class="control-group">
171
- <p>
172
- <%= t('.article_filter') %>: <strong><%= @article.text_filter.description %></strong>
173
- <%= toggle_element 'text_filter' %>
174
- </p>
175
- <div id="text_filter" class="collapse">
176
- <select name="article[text_filter_name]" id="text_filter_name" class='form-control'>
177
- <%= options_for_select text_filter_options, @article.text_filter_name %>
178
- </select>
165
+ <div class="control-group">
179
166
  <p>
180
- <span class="btn btn-mini btn-default">
181
- <%= toggle_element 'text_filter', 'OK' %>
182
- </span>
167
+ <%= t('.article_filter') %>: <strong><%= @article.text_filter.description %></strong>
168
+ <%= toggle_element 'text_filter' %>
183
169
  </p>
170
+ <div id="text_filter" class="collapse">
171
+ <div class="mb-3">
172
+ <select name="article[text_filter_name]" id="text_filter_name" class='form-select'>
173
+ <%= options_for_select text_filter_options, @article.text_filter_name %>
174
+ </select>
175
+ </div>
176
+ <%= toggle_element('text_filter', t('.ok'), class: "btn btn-mini btn-secondary") %>
177
+ </div>
184
178
  </div>
185
- </div>
186
- </fieldset>
179
+ </fieldset>
180
+ </div>
187
181
  </div>
188
182
  </div>
189
183
  <div class="modal-footer">
190
- <button type="button" class="btn btn-default" data-dismiss="modal"><%= t('.cancel') %></button>
184
+ <button type="button" class="btn btn-secondary" data-bs-dismiss="modal"><%= t('.cancel') %></button>
191
185
  <%= submit_tag(t('.publish'), class: 'btn btn-success') %>
192
186
  </div>
193
187
  </div>
@@ -1,40 +1,32 @@
1
1
  <% content_for :page_heading do %>
2
2
  <h2>
3
3
  <%= t('.manage_articles') %>
4
- <%= link_to(t('.new_article'), { controller: 'articles', action: 'new' }, { id: 'dialog-link', class: 'btn btn-info pull-right' }) %>
4
+ <%= link_to(t('.new_article'), { controller: 'articles', action: 'new' }, { id: 'dialog-link', class: 'btn btn-info float-right' }) %>
5
5
  </h2>
6
6
  <% end %>
7
7
 
8
- <%= form_tag({ action: 'index' }, { method: :get, name: 'article', remote: true, class: 'form-inline spinnable', "data-update-success": 'articleList' }) do %>
8
+ <%= form_tag({ action: 'index' }, { method: :get, name: 'article', remote: true, class: 'spinnable', "data-update-success": 'articleList' }) do %>
9
9
 
10
10
  <% if params[:search] and params[:search]['state'] %>
11
11
  <input type="hidden" name="search[state]" value="<%= params[:search]['state'] %>">
12
12
  <% end %>
13
13
 
14
14
  <p>
15
- <%= link_to(t('.all_articles'), { action: 'index' }, { class: 'label label-default' }) %>
16
- <%= link_to(t('.published'), { action: 'index', search: { state: 'published' } }, { class: 'label label-success' }) %>
17
- <%= link_to(t('.withdrawn'), { action: 'index', search: { state: 'withdrawn' } }, { class: 'label label-danger' }) %>
18
- <%= link_to(t('.drafts'), { action: 'index', search: { state: 'drafts' } }, { class: 'label label-info' }) %>
19
- <%= link_to(t('.publication_pending'), { action: 'index', search: { state: 'pending' } }, { class: 'label label-warning' }) %>
15
+ <%= link_to(t('.all_articles'), { action: 'index' }, { class: 'badge text-bg-secondary' }) %>
16
+ <%= link_to(t('.published'), { action: 'index', search: { state: 'published' } }, { class: 'badge text-bg-success' }) %>
17
+ <%= link_to(t('.withdrawn'), { action: 'index', search: { state: 'withdrawn' } }, { class: 'badge text-bg-danger' }) %>
18
+ <%= link_to(t('.drafts'), { action: 'index', search: { state: 'drafts' } }, { class: 'badge text-bg-info' }) %>
19
+ <%= link_to(t('.publication_pending'), { action: 'index', search: { state: 'pending' } }, { class: 'badge text-bg-warning' }) %>
20
20
  </p>
21
21
 
22
- <div class="panel panel-default">
23
- <div class="panel-heading clearfix">
24
- <div class="pull-right">
25
- <div class="form-group">
26
- <%= select_tag('search[user_id]', options_from_collection_for_select(User.all, 'id', 'name'), prompt: t('.select_an_author'), class: 'form-control') %>
27
- </div>
28
- <div class="form-group">
29
- <%= select_tag('search[published_at]', options_for_select(Article.publication_months), prompt: t('.publication_date'), class: 'form-control') %>
30
- </div>
31
- <div class="form-group">
32
- <input id="search" type="text" name="search[searchstring]" class="form-control" autocomplete="off">
33
- </div>
34
- <div class="form-group">
35
- <%= submit_tag(t('.search'), class: 'btn btn-success') %>
36
- <span id="spinner" class="hidden"><%= image_tag('spinner.gif') %></span>
37
- </div>
22
+ <div class="card mb-4">
23
+ <div class="card-header">
24
+ <div class="d-sm-flex">
25
+ <%= select_tag('search[user_id]', options_from_collection_for_select(User.all, 'id', 'name'), prompt: t('.select_an_author'), class: 'form-select ms-sm-auto me-sm-2') %>
26
+ <%= select_tag('search[published_at]', options_for_select(Article.publication_months), prompt: t('.publication_date'), class: 'form-select me-sm-2') %>
27
+ <input id="search" type="text" name="search[searchstring]" class="form-control me-sm-2" autocomplete="off">
28
+ <%= submit_tag(t('.search'), class: 'btn btn-success') %>
29
+ <span id="spinner" class="d-none"><%= image_tag('spinner.gif') %></span>
38
30
  </div>
39
31
  </div>
40
32
  </div>
@@ -9,7 +9,7 @@
9
9
  <%= display_date_and_time comment.created_at %>
10
10
  </h5>
11
11
  <p>
12
- <%= comment.html.strip_html.slice(0..300) %>
12
+ <%= comment.excerpt_text(300) %>
13
13
  </p>
14
14
  <%= button_to_conversation(comment) %>
15
15
  <hr>
@@ -1,9 +1,7 @@
1
- <div class="panel panel-default">
2
- <div class="panel-heading">
3
- <h3 class='panel-title'><%= t('.latest_comments') %></h3>
4
- </div>
5
- <div class="panel-body">
6
- <ul class='list-unstyled' id="commentList">
1
+ <div class="card mb-4">
2
+ <h3 class="card-header"><%= t('.latest_comments') %></h3>
3
+ <div class="card-body">
4
+ <ul class="list-unstyled" id="commentList">
7
5
  <%= render partial: 'comment' %>
8
6
  </ul>
9
7
  </div>
@@ -1,8 +1,6 @@
1
- <div class="panel panel-default">
2
- <div class="panel-heading">
3
- <h3 class='panel-title'><%= t('.your_drafts') %></h3>
4
- </div>
5
- <div class="panel-body">
1
+ <div class="card">
2
+ <h3 class="card-header"><%= t('.your_drafts') %></h3>
3
+ <div class="card-body">
6
4
  <ul class='list-unstyled'>
7
5
  <% if @drafts.empty? %>
8
6
  <li class='alert alert-info'>
@@ -15,7 +13,7 @@
15
13
  <%= link_to(post.title, controller: 'admin/articles', action: 'edit', id: post.id) %>
16
14
  <%= display_date_and_time(post.created_at) %>
17
15
  </h5>
18
- <p><%= post.body&.strip_html&.slice(0, 300) %></p>
16
+ <p><%= post.excerpt_text(300) %></p>
19
17
  <hr>
20
18
  </li>
21
19
  <% end %>
@@ -1,8 +1,5 @@
1
- <div class='alert alert-info'>
2
- <button type="button" class="close" data-dismiss="alert">
3
- <span aria-hidden="true">&times;</span>
4
- <span class="sr-only">Close</span>
5
- </button>
1
+ <div class="alert alert-info alert-dismissible fade show">
2
+ <button type="button" class="btn-close float-right" data-bs-dismiss="alert" aria-label="Close"></button>
6
3
  <% links = []
7
4
  links << link_to(t('.write_a_post'), controller: 'articles', action: 'new') if can? :new, 'admin/articles'
8
5
  links << link_to(t('.write_a_page'), controller: 'pages', action: 'new') if can? :new, 'admin/pages'
@@ -1,27 +1,27 @@
1
- <div class="panel panel-default">
2
- <div class="panel-heading">
3
- <h3 class="panel-title"><%= t('.today') %></h3>
4
- </div>
5
- <div class="panel-body">
1
+ <div class="card mb-4">
2
+ <h3 class="card-header"><%= t('.today') %></h3>
3
+ <div class="card-body">
6
4
  <p><%= t('.articles_and_comments_count_since', articles_count: @newposts_count, comments_count: @newcomments_count) %></p>
7
5
  <p><%= t('.running_publify', version: PublifyCore::VERSION) %> <%= @version_message %></p>
8
- <div class='col-md-6'>
6
+ <div class='row'>
9
7
  <% if can? :index, 'admin/articles' %>
10
- <h4 class='page-header'><%= t('.content') %></h4>
11
- <p><%= link_to(t('.articles_count', count: @statposts), controller: 'admin/articles') %></p>
12
- <p><%= link_to(t('.your_articles_count', count: @statuserposts), controller: 'admin/articles', 'search[user_id]' => current_user.id) %></p>
13
- <p><%= link_to(t('.drafts_count', count: @statsdrafts), controller: 'admin/articles', 'search[state]' => 'drafts') %></p>
14
- <p><%= link_to(t('.pages_count', count: @statspages), controller: 'admin/pages') %></p>
15
- <p><%= link_to(t('.notes_count', count: @statuses), controller: 'admin/notes') %></p>
8
+ <div class="col-lg-6">
9
+ <h4 class='mb-2 pb-2 border-bottom'><%= t('.content') %></h4>
10
+ <p><%= link_to(t('.articles_count', count: @statposts), controller: 'admin/articles') %></p>
11
+ <p><%= link_to(t('.your_articles_count', count: @statuserposts), controller: 'admin/articles', 'search[user_id]' => current_user.id) %></p>
12
+ <p><%= link_to(t('.drafts_count', count: @statsdrafts), controller: 'admin/articles', 'search[state]' => 'drafts') %></p>
13
+ <p><%= link_to(t('.pages_count', count: @statspages), controller: 'admin/pages') %></p>
14
+ <p><%= link_to(t('.notes_count', count: @statuses), controller: 'admin/notes') %></p>
15
+ </div>
16
16
  <% end %>
17
- </div>
18
- <div class='col-md-6'>
19
17
  <% if can? :index, 'admin/feedback' %>
20
- <h4 class='page-header'><%= t('.feedback') %></h4>
21
- <p><%= link_to(t('.comments_count', count: @statcomments), controller: 'admin/feedback') %></p>
22
- <p><%= link_to(t('.approved_count', count: @confirmed), controller: 'admin/feedback', only: 'ham') %></p>
23
- <p><%= link_to(t('.unconfirmed_count', count: @unconfirmed), controller: 'admin/feedback', only: 'unapproved') %></p>
24
- <p><%= link_to(t('.spam_count', count: @statspam), controller: 'admin/feedback', only: 'spam') %></p>
18
+ <div class="col-lg-6">
19
+ <h4 class='mb-2 pb-2 border-bottom'><%= t('.feedback') %></h4>
20
+ <p><%= link_to(t('.comments_count', count: @statcomments), controller: 'admin/feedback') %></p>
21
+ <p><%= link_to(t('.approved_count', count: @confirmed), controller: 'admin/feedback', only: 'ham') %></p>
22
+ <p><%= link_to(t('.unconfirmed_count', count: @unconfirmed), controller: 'admin/feedback', only: 'unapproved') %></p>
23
+ <p><%= link_to(t('.spam_count', count: @statspam), controller: 'admin/feedback', only: 'spam') %></p>
24
+ </div>
25
25
  <% end %>
26
26
  </div>
27
27
  </div>
@@ -1,15 +1,15 @@
1
1
  <% content_for :page_heading do %>
2
- <h2 class="page-title"><%= t('.welcome_back', user_name: current_user.name) %></h2>
2
+ <h2 class="display-4"><%= t('.welcome_back', user_name: current_user.name) %></h2>
3
3
  <% end %>
4
4
 
5
5
  <%= render 'overview' %>
6
6
 
7
7
  <div class='row'>
8
- <div class='col-md-6'>
8
+ <div class='col-lg-6'>
9
9
  <%= render 'welcome' %>
10
10
  <%= render 'comments' %>
11
11
  </div>
12
- <div class='col-md-6'>
12
+ <div class='col-lg-6'>
13
13
  <%= render 'drafts' %>
14
14
  </div>
15
15
  </div>
@@ -1,19 +1,13 @@
1
1
  <%= hidden_field_tag 'confirmed', params[:confirmed] %>
2
2
  <%= hidden_field_tag 'published', params[:published] %>
3
3
 
4
- <div class="panel panel-default">
5
- <div class="panel-heading">
6
- <div class='form-group'>
7
- <button name='<%= "bulkop_#{position}" %>' class="btn btn-success btn-sm" value='Mark Checked Items as Ham'><%= t('.mark_checked_items_as_ham') %></button>
8
- </div>
9
- <div class='form-group'>
10
- <button name='<%= "bulkop_#{position}" %>' class="btn btn-warning btn-sm" value='Mark Checked Items as Spam'><%= t('.mark_checked_items_as_spam') %></button>
11
- </div>
12
- <div class='form-group'>
13
- <button name='<%= "bulkop_#{position}" %>' class="btn btn-danger btn-sm" value='Delete Checked Items'><%= t('.delete_checked_items') %></button>
14
- </div>
15
- <div class='form-group pull-right'>
16
- <button name='<%= "bulkop_#{position}" %>' class="btn btn-danger btn-sm" value='Delete all spam'><%= t('.delete_all_spam') %></button>
4
+ <div class="card mb-4">
5
+ <div class="card-header">
6
+ <div class="d-sm-flex">
7
+ <button name='<%= "bulkop_#{position}" %>' class="btn btn-success btn-sm me-sm-2" value='Mark Checked Items as Ham'><%= t('.mark_checked_items_as_ham') %></button>
8
+ <button name='<%= "bulkop_#{position}" %>' class="btn btn-warning btn-sm me-sm-2" value='Mark Checked Items as Spam'><%= t('.mark_checked_items_as_spam') %></button>
9
+ <button name='<%= "bulkop_#{position}" %>' class="btn btn-danger btn-sm me-sm-2" value='Delete Checked Items'><%= t('.delete_checked_items') %></button>
10
+ <button name='<%= "bulkop_#{position}" %>' class="btn btn-danger btn-sm ms-sm-auto" value='Delete all spam'><%= t('.delete_all_spam') %></button>
17
11
  </div>
18
12
  </div>
19
13
  </div>
@@ -4,7 +4,7 @@
4
4
  </h2>
5
5
  <% end %>
6
6
 
7
- <%= form_tag({ action: 'bulkops' }, { class: 'form-inline' }) do %>
7
+ <%= form_tag({ action: 'bulkops' }) do %>
8
8
 
9
9
  <%= hidden_field_tag 'article_id', @article.id %>
10
10
 
@@ -40,35 +40,35 @@
40
40
  </table>
41
41
  <% end %>
42
42
 
43
- <%= form_tag action: 'create' do %>
44
- <%= hidden_field_tag('article_id', @article.id) %>
45
- <fieldset class='form-horizontal'>
43
+ <%= form_with url: {action: 'create'}, local: true do |form| %>
44
+ <%= form.hidden_field :article_id, value: @article.id %>
45
+ <fieldset class='mb-4'>
46
46
  <legend><%= t('.add_a_comment') %></legend>
47
- <div class="form-group">
48
- <label for="comment_author" class='control-label col-sm-2'><%= t('.author') %></label>
49
- <div class='col-sm-5'>
47
+ <div class="form-group row">
48
+ <label for="comment_author" class='col-form-label col-md-2'><%= t('.author') %></label>
49
+ <div class="col-md-5">
50
50
  <%= text_field 'comment', 'author', class: 'form-control' %>
51
51
  </div>
52
52
  </div>
53
- <div class='form-group'>
54
- <label for="comment_email" class='control-label col-sm-2'><%= t('.email') %></label>
55
- <div class='col-sm-5'>
53
+ <div class="form-group row">
54
+ <label for="comment_email" class='col-form-label col-md-2'><%= t('.email') %></label>
55
+ <div class="col-md-5">
56
56
  <%= text_field 'comment', 'email', class: 'form-control' %>
57
57
  </div>
58
58
  </div>
59
- <div class='form-group'>
60
- <label for="comment_url" class='control-label col-sm-2'><%= t('.url') %></label>
61
- <div class='col-sm-5'>
59
+ <div class="form-group row">
60
+ <label for="comment_url" class='col-form-label col-md-2'><%= t('.url') %></label>
61
+ <div class="col-md-5">
62
62
  <%= text_field 'comment', 'url', class: 'form-control' %>
63
63
  </div>
64
64
  </div>
65
- <div class='form-group'>
66
- <label for='comment_body' class='control-label col-sm-2'><%= t('.your_comment') %></label>
67
- <div class='col-sm-5'>
65
+ <div class="form-group row">
66
+ <label for="comment_body" class='col-form-label col-md-2'><%= t('.your_comment') %></label>
67
+ <div class="col-md-5">
68
68
  <%= text_area 'comment', 'body', rows: '10', class: 'form-control' %>
69
69
  </div>
70
70
  </div>
71
- <div>
71
+ <div class="mt-3">
72
72
  <%= t('.action_or_other_html', first_action: link_to(t('.cancel'), action: 'index'), second_action: submit_tag(t('.save'), class: 'btn btn-primary')) %>
73
73
  </div>
74
74
  </fieldset>