integral 1.3.0 → 1.4.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 (205) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +2 -30
  3. data/Rakefile +1 -1
  4. data/app/assets/images/integral/defaults/no_image_available.jpg +0 -0
  5. data/app/assets/javascripts/integral/backend.js +102 -11
  6. data/app/assets/javascripts/integral/frontend.js +37 -0
  7. data/app/assets/javascripts/integral/support/confirm_modal.coffee +2 -2
  8. data/app/assets/javascripts/integral/support/gallery.coffee +71 -54
  9. data/app/assets/javascripts/integral/support/lib/lazysizes.js +755 -0
  10. data/app/assets/javascripts/integral/support/lib/materialize-tags.js +49 -44
  11. data/app/assets/javascripts/integral/support/ls.instagram.js +57 -0
  12. data/app/assets/javascripts/integral/support/ls.twitter.js +66 -0
  13. data/app/assets/javascripts/integral/support/record_selector.coffee +1 -1
  14. data/app/assets/javascripts/integral/support/remote_form.coffee +5 -2
  15. data/app/assets/stylesheets/integral/backend.sass +2 -1
  16. data/app/assets/stylesheets/integral/backend/_foundation_settings.scss +3 -4
  17. data/app/assets/stylesheets/integral/backend/dashboard-layout.scss +4 -1
  18. data/app/assets/stylesheets/integral/backend/materialize-tags.sass +1 -1
  19. data/app/assets/stylesheets/integral/backend/modules/timeline.scss +214 -0
  20. data/app/assets/stylesheets/integral/backend/shared.sass +80 -11
  21. data/app/assets/stylesheets/integral/frontend.scss +45 -0
  22. data/app/assets/stylesheets/integral/frontend/_foundation_settings.scss +2 -2
  23. data/app/assets/stylesheets/integral/frontend/blog.sass +155 -142
  24. data/app/assets/stylesheets/integral/frontend/layout.sass +3 -3
  25. data/app/assets/stylesheets/integral/frontend/modules/article-footer.scss +55 -0
  26. data/app/assets/stylesheets/integral/frontend/modules/article.scss +34 -0
  27. data/app/assets/stylesheets/integral/frontend/modules/horizontal-post.scss +44 -0
  28. data/app/assets/stylesheets/integral/frontend/modules/inline-articles.scss +23 -0
  29. data/app/assets/stylesheets/integral/frontend/modules/latest-post.scss +37 -0
  30. data/app/assets/stylesheets/integral/frontend/modules/list-widget.scss +50 -0
  31. data/app/assets/stylesheets/integral/frontend/modules/piped-list.scss +33 -0
  32. data/app/assets/stylesheets/integral/frontend/modules/post-tags.scss +19 -0
  33. data/app/assets/stylesheets/integral/frontend/modules/scroll-container.scss +9 -0
  34. data/app/assets/stylesheets/integral/frontend/modules/sidebar-articles.scss +42 -0
  35. data/app/assets/stylesheets/integral/frontend/modules/sidebar-tags.scss +6 -0
  36. data/app/assets/stylesheets/integral/frontend/modules/sidebar-widget.scss +47 -0
  37. data/app/assets/stylesheets/integral/frontend/modules/vertical-post.scss +31 -0
  38. data/app/assets/stylesheets/integral/frontend/share_modal.sass +0 -5
  39. data/app/assets/stylesheets/integral/support/gallery.sass +8 -0
  40. data/app/assets/stylesheets/integral/support/media-query-indicator.sass +6 -0
  41. data/app/controllers/integral/application_controller.rb +7 -1
  42. data/app/controllers/integral/backend/activities_controller.rb +13 -2
  43. data/app/controllers/integral/backend/base_controller.rb +60 -7
  44. data/app/controllers/integral/backend/categories_controller.rb +49 -0
  45. data/app/controllers/integral/backend/pages_controller.rb +7 -2
  46. data/app/controllers/integral/backend/posts_controller.rb +8 -3
  47. data/app/controllers/integral/backend/static_pages_controller.rb +4 -0
  48. data/app/controllers/integral/backend/users_controller.rb +13 -7
  49. data/app/controllers/integral/categories_controller.rb +31 -0
  50. data/app/controllers/integral/pages_controller.rb +1 -1
  51. data/app/controllers/integral/posts_controller.rb +5 -3
  52. data/app/decorators/integral/category_decorator.rb +30 -0
  53. data/app/decorators/integral/category_version_decorator.rb +7 -0
  54. data/app/decorators/integral/image_version_decorator.rb +7 -0
  55. data/app/decorators/integral/list_decorator.rb +1 -1
  56. data/app/decorators/integral/list_version_decorator.rb +7 -0
  57. data/app/decorators/integral/page_version_decorator.rb +7 -0
  58. data/app/decorators/integral/post_decorator.rb +9 -1
  59. data/app/decorators/integral/post_version_decorator.rb +7 -0
  60. data/app/decorators/integral/user_decorator.rb +1 -1
  61. data/app/decorators/integral/user_version_decorator.rb +7 -0
  62. data/app/decorators/integral/version_decorator.rb +51 -12
  63. data/app/helpers/integral/backend/base_helper.rb +56 -2
  64. data/app/helpers/integral/blog_helper.rb +21 -4
  65. data/app/jobs/integral/webhook/delivery_job.rb +37 -0
  66. data/app/mailers/integral/contact_mailer.rb +4 -1
  67. data/app/models/concerns/integral/lazy_contentable.rb +54 -0
  68. data/app/models/concerns/integral/webhook/delivery.rb +30 -0
  69. data/app/models/concerns/integral/webhook/observable.rb +23 -0
  70. data/app/models/integral/category.rb +20 -0
  71. data/app/models/integral/category_version.rb +8 -0
  72. data/app/models/integral/list_item.rb +1 -2
  73. data/app/models/integral/page.rb +18 -3
  74. data/app/models/integral/post.rb +28 -1
  75. data/app/models/integral/version.rb +2 -2
  76. data/app/models/integral/webhook/endpoint.rb +40 -0
  77. data/app/models/integral/webhook/event.rb +20 -0
  78. data/app/policies/integral/base_policy.rb +1 -0
  79. data/app/policies/integral/category_policy.rb +9 -0
  80. data/app/serializers/integral/post_serializer.rb +24 -0
  81. data/app/uploaders/integral/avatar_uploader.rb +1 -1
  82. data/app/views/integral/backend/activities/_activity.haml +21 -0
  83. data/app/views/integral/backend/activities/_grid.haml +1 -2
  84. data/app/views/integral/backend/activities/shared/_grid.haml +3 -2
  85. data/app/views/integral/backend/activities/shared/{_listing.haml → index.haml} +1 -0
  86. data/app/views/integral/backend/activities/shared/{_log.haml → show.haml} +0 -0
  87. data/app/views/integral/backend/categories/_modal.haml +25 -0
  88. data/app/views/integral/backend/lists/_child_fields.haml +1 -1
  89. data/app/views/integral/backend/lists/_item_container.haml +1 -1
  90. data/app/views/integral/backend/lists/_item_modal.haml +1 -1
  91. data/app/views/integral/backend/lists/_list_item_fields.haml +1 -1
  92. data/app/views/integral/backend/pages/_form.haml +1 -4
  93. data/app/views/integral/backend/pages/_grid.haml +34 -9
  94. data/app/views/integral/backend/pages/edit.haml +9 -3
  95. data/app/views/integral/backend/pages/index.haml +11 -21
  96. data/app/views/integral/backend/pages/list.haml +22 -0
  97. data/app/views/integral/backend/pages/show.haml +48 -0
  98. data/app/views/integral/backend/posts/_form.haml +8 -6
  99. data/app/views/integral/backend/posts/_grid.haml +33 -7
  100. data/app/views/integral/backend/posts/index.haml +13 -19
  101. data/app/views/integral/backend/posts/list.haml +20 -0
  102. data/app/views/integral/backend/posts/show.haml +54 -0
  103. data/app/views/integral/backend/shared/_activity_modal.haml +13 -0
  104. data/app/views/integral/backend/shared/cards/_categories.haml +34 -0
  105. data/app/views/integral/backend/{static_pages/_card.haml → shared/cards/_object.haml} +0 -0
  106. data/app/views/integral/backend/shared/cards/_recent_activity.haml +20 -0
  107. data/app/views/integral/backend/shared/cards/_recent_pages.haml +19 -0
  108. data/app/views/integral/backend/shared/cards/_recent_posts.haml +18 -0
  109. data/app/views/integral/backend/shared/cards/_recent_user_activity.haml +1 -0
  110. data/app/views/integral/backend/shared/cards/_recent_users.haml +19 -0
  111. data/app/views/integral/backend/shared/cards/_top_post_authors.haml +19 -0
  112. data/app/views/integral/backend/shared/record_selector/_record.haml +6 -4
  113. data/app/views/integral/backend/static_pages/dashboard.haml +13 -11
  114. data/app/views/integral/backend/users/_grid.haml +24 -7
  115. data/app/views/integral/backend/users/index.haml +11 -17
  116. data/app/views/integral/backend/users/list.haml +18 -0
  117. data/app/views/integral/backend/users/show.haml +5 -11
  118. data/app/views/integral/categories/show.haml +5 -0
  119. data/app/views/integral/posts/_article_footer.haml +17 -0
  120. data/app/views/integral/posts/_card.haml +11 -0
  121. data/app/views/integral/posts/_latest_post.haml +8 -0
  122. data/app/views/integral/posts/_most_read_section.haml +8 -0
  123. data/app/views/integral/posts/_post.haml +11 -0
  124. data/app/views/integral/posts/_similar_posts.haml +5 -0
  125. data/app/views/integral/posts/index.haml +6 -5
  126. data/app/views/integral/posts/templates/default.haml +34 -33
  127. data/app/views/integral/shared/_subscribe_modal.haml +14 -0
  128. data/app/views/integral/shared/blog/_categories.haml +15 -0
  129. data/app/views/integral/shared/blog/_layout.haml +9 -0
  130. data/app/views/integral/shared/blog/_sidebar.haml +10 -0
  131. data/app/views/integral/shared/gallery/_placeholder.haml +1 -1
  132. data/app/views/integral/shared/gallery/_slide.haml +2 -2
  133. data/app/views/integral/shared/gallery/gallery.haml +5 -2
  134. data/app/views/integral/shared/sidebar/_item.haml +8 -0
  135. data/app/views/integral/shared/sidebar/_newsletter_signup.haml +7 -0
  136. data/app/views/integral/shared/sidebar/_popular_posts.haml +7 -0
  137. data/app/views/integral/shared/sidebar/_popular_tags.haml +7 -0
  138. data/app/views/integral/shared/sidebar/_recent_posts.haml +7 -0
  139. data/app/views/integral/tags/index.haml +2 -2
  140. data/app/views/integral/tags/show.haml +3 -6
  141. data/app/views/layouts/integral/backend.html.haml +3 -0
  142. data/app/views/layouts/integral/backend/_main_menu_items.haml +10 -0
  143. data/app/views/layouts/integral/frontend.html.haml +3 -3
  144. data/config/locales/en.yml +52 -49
  145. data/db/migrate/20190414172018_create_webhook_endpoints.rb +10 -0
  146. data/db/migrate/20190929191412_add_integral_post_categories.rb +13 -0
  147. data/db/migrate/20191203090008_add_image_to_integral_categories.rb +6 -0
  148. data/db/migrate/20200401210442_create_category_versions.rb +20 -0
  149. data/db/seeds.rb +3 -1
  150. data/lib/generators/integral/assets_generator.rb +2 -2
  151. data/lib/generators/integral/install_generator.rb +1 -1
  152. data/lib/generators/integral/views_generator.rb +1 -1
  153. data/lib/generators/templates/integral.rb +5 -0
  154. data/lib/integral.rb +3 -30
  155. data/lib/integral/acts_as_listable.rb +2 -2
  156. data/lib/integral/chart_renderer/base.rb +2 -0
  157. data/lib/integral/content_renderer.rb +2 -2
  158. data/lib/integral/engine.rb +2 -2
  159. data/lib/integral/grids/activities_grid.rb +15 -1
  160. data/lib/integral/list_item_renderer.rb +4 -2
  161. data/lib/integral/list_renderer.rb +1 -0
  162. data/lib/integral/middleware/page_router.rb +15 -6
  163. data/lib/integral/router.rb +19 -3
  164. data/lib/integral/version.rb +1 -1
  165. data/lib/integral/widgets/swiper_list.rb +3 -2
  166. data/public/images/integral/demo/continous-integration.png +0 -0
  167. data/public/images/integral/demo/foundation-frontend-framework.jpg +0 -0
  168. data/public/images/integral/demo/heroku.png +0 -0
  169. data/public/images/integral/demo/integral-cms-without-hassle.jpg +0 -0
  170. data/public/images/integral/demo/integral-features-activity-tracking.jpg +0 -0
  171. data/public/images/integral/demo/integral-features-contact-form.png +0 -0
  172. data/public/images/integral/demo/integral-features-design.jpg +0 -0
  173. data/public/images/integral/demo/integral-features-dynamic-pages.jpg +0 -0
  174. data/public/images/integral/demo/integral-features-image-management.jpg +0 -0
  175. data/public/images/integral/demo/integral-features-integrated-blog.jpg +0 -0
  176. data/public/images/integral/demo/integral-features-list-management.jpg +0 -0
  177. data/public/images/integral/demo/integral-features-seo-ready.jpg +0 -0
  178. data/public/images/integral/demo/integral-features-user-management.jpg +0 -0
  179. data/public/images/integral/demo/integral-presentation.png +0 -0
  180. data/spec/factories.rb +15 -7
  181. metadata +110 -98
  182. data/app/assets/javascripts/ckeditor/plugins/integral-card/icons/copywidget.png +0 -0
  183. data/app/assets/javascripts/ckeditor/plugins/integral-card/icons/editwidget.png +0 -0
  184. data/app/assets/javascripts/ckeditor/plugins/integral-card/icons/hidpi/copywidget.png +0 -0
  185. data/app/assets/javascripts/ckeditor/plugins/integral-card/icons/hidpi/editwidget.png +0 -0
  186. data/app/assets/javascripts/ckeditor/plugins/integral-card/icons/hidpi/removewidget.png +0 -0
  187. data/app/assets/javascripts/ckeditor/plugins/integral-card/icons/hidpi/widget.png +0 -0
  188. data/app/assets/javascripts/ckeditor/plugins/integral-card/icons/removewidget.png +0 -0
  189. data/app/assets/javascripts/ckeditor/plugins/integral-card/icons/widget.png +0 -0
  190. data/app/assets/javascripts/ckeditor/plugins/integral-card/plugin.js +0 -86
  191. data/app/assets/javascripts/ckeditor/plugins/integralrecentposts/dialogs/integralrecentposts.js +0 -40
  192. data/app/assets/javascripts/ckeditor/plugins/integralrecentposts/plugin.js +0 -32
  193. data/app/assets/javascripts/ckeditor/plugins/numericinput/LICENSE.md +0 -363
  194. data/app/assets/javascripts/ckeditor/plugins/numericinput/README.md +0 -16
  195. data/app/assets/javascripts/ckeditor/plugins/numericinput/plugin.js +0 -354
  196. data/app/assets/stylesheets/integral/frontend.sass +0 -25
  197. data/app/views/integral/backend/pages/activities.haml +0 -2
  198. data/app/views/integral/backend/pages/activity.haml +0 -1
  199. data/app/views/integral/backend/posts/activities.haml +0 -3
  200. data/app/views/integral/backend/posts/activity.haml +0 -1
  201. data/app/views/integral/posts/_collection.haml +0 -4
  202. data/app/views/integral/posts/_item.haml +0 -16
  203. data/app/views/integral/shared/_blog_layout.haml +0 -15
  204. data/app/views/integral/shared/_blog_sidebar.haml +0 -49
  205. data/lib/integral/slack_bot.rb +0 -45
@@ -9,10 +9,12 @@ module Integral
9
9
  # List blog posts
10
10
  def index
11
11
  add_breadcrumb I18n.t('integral.breadcrumbs.blog'), nil
12
- @posts = Integral::Post.published.order('published_at DESC').paginate(page: params[:page])
12
+ @latest_post = Integral::Post.published.order('published_at DESC').first&.decorate
13
+ @posts = Integral::Post.published.includes(:image, :user).order('published_at DESC').paginate(page: params[:page])
14
+ @posts = @posts.where.not(id: @latest_post.id) if @latest_post
13
15
  end
14
16
 
15
- # GET /blog.slug
17
+ # GET /<post.slug>
16
18
  # Presents blog postings
17
19
  def show
18
20
  add_breadcrumb I18n.t('integral.breadcrumbs.blog'), :posts_url
@@ -21,7 +23,7 @@ module Integral
21
23
  @meta_data = {
22
24
  page_title: @post.title,
23
25
  page_description: @post.description,
24
- open_graph: {
26
+ open_graph: {
25
27
  image: @post.preview_image(:large)
26
28
  }
27
29
  }
@@ -0,0 +1,30 @@
1
+ module Integral
2
+ # Category view-level logic
3
+ class CategoryDecorator < Draper::Decorator
4
+ delegate_all
5
+
6
+ # @return [String] URL to backend activity
7
+ def activity_url(activity_id)
8
+ Integral::Engine.routes.url_helpers.activity_backend_category_url(object.id, activity_id)
9
+ end
10
+
11
+ # @return [String] URL to backend Image page
12
+ def backend_url
13
+ Integral::Engine.routes.url_helpers.backend_posts_url
14
+ end
15
+
16
+ # @return [Relation] posts associated to the category
17
+ def posts(limit = nil)
18
+ object.posts.published.order('published_at DESC').limit(limit).decorate
19
+ end
20
+
21
+ # @return [String] image URL associated to the category
22
+ def image_url
23
+ if object.image.present?
24
+ object.image.url
25
+ else
26
+ helpers.image_url('integral/image-not-set.png')
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,7 @@
1
+ module Integral
2
+ class CategoryVersionDecorator < VersionDecorator
3
+ def item_icon
4
+ 'tags'
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,7 @@
1
+ module Integral
2
+ class ImageVersionDecorator < VersionDecorator
3
+ def item_icon
4
+ 'image'
5
+ end
6
+ end
7
+ end
@@ -10,7 +10,7 @@ module Integral
10
10
 
11
11
  # @return [String] URL to backend list page
12
12
  def backend_url
13
- Integral::Engine.routes.url_helpers.backend_list_url(self)
13
+ Integral::Engine.routes.url_helpers.edit_backend_list_url(self)
14
14
  end
15
15
 
16
16
  # @return [String] formatted title
@@ -0,0 +1,7 @@
1
+ module Integral
2
+ class ListVersionDecorator < VersionDecorator
3
+ def item_icon
4
+ 'list'
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,7 @@
1
+ module Integral
2
+ class PageVersionDecorator < VersionDecorator
3
+ def item_icon
4
+ 'file'
5
+ end
6
+ end
7
+ end
@@ -2,6 +2,7 @@ module Integral
2
2
  # Page view-level logic
3
3
  class PostDecorator < Draper::Decorator
4
4
  delegate_all
5
+ decorates_association :category
5
6
 
6
7
  # Enables pagination
7
8
  def self.collection_decorator_class
@@ -36,6 +37,12 @@ module Integral
36
37
  }
37
38
  end
38
39
 
40
+ # @return [String] avatar image
41
+ def avatar
42
+ avatar_url = user&.avatar&.url(:thumbnail)
43
+ h.image_tag avatar_url, class: 'user-avatar' unless avatar_url.nil?
44
+ end
45
+
39
46
  # Tags to be used within the header of an article to describe the subject
40
47
  def header_tags
41
48
  return I18n.t('integral.posts.show.subtitle') if object.tags_on('published').empty?
@@ -67,13 +74,14 @@ module Integral
67
74
  # Date the post was published
68
75
  def published_at
69
76
  return I18n.l(object.published_at, format: :blog) if object.published?
77
+
70
78
  'Not yet published'
71
79
  end
72
80
 
73
81
  # @return [String] URL to backend post page
74
82
  def backend_url
75
83
  if Integral.blog_enabled?
76
- Integral::Engine.routes.url_helpers.edit_backend_post_url(object.id)
84
+ Integral::Engine.routes.url_helpers.backend_post_url(object.id)
77
85
  else
78
86
  ''
79
87
  end
@@ -0,0 +1,7 @@
1
+ module Integral
2
+ class PostVersionDecorator < VersionDecorator
3
+ def item_icon
4
+ 'rss'
5
+ end
6
+ end
7
+ end
@@ -5,7 +5,7 @@ module Integral
5
5
 
6
6
  # @return [String] URL to backend activity
7
7
  def activity_url(activity_id)
8
- # Integral::Engine.routes.url_helpers.activity_backend_user_url(object.id, activity_id)
8
+ Integral::Engine.routes.url_helpers.activity_backend_user_url(object.id, activity_id)
9
9
  end
10
10
 
11
11
  # @return [String] URL to backend list page
@@ -0,0 +1,7 @@
1
+ module Integral
2
+ class UserVersionDecorator < VersionDecorator
3
+ def item_icon
4
+ 'user'
5
+ end
6
+ end
7
+ end
@@ -13,11 +13,20 @@ module Integral
13
13
  h.t("integral.actions.#{object.event}")
14
14
  end
15
15
 
16
+ # @return [String] formatted event verb (past)
17
+ def event_verb
18
+ h.t("integral.actions.tense.past.#{object.event}")
19
+ end
20
+
16
21
  # @return [String] Item URL
17
22
  def item_url
18
23
  decorated_item&.backend_url
19
24
  end
20
25
 
26
+ def whodunnit_url
27
+ Integral::Engine.routes.url_helpers.backend_user_url(whodunnit.id) if whodunnit.present?
28
+ end
29
+
21
30
  # @return [Integral::User] who carried out the version (if one exists)
22
31
  def whodunnit
23
32
  user_id = object.whodunnit.to_i
@@ -27,6 +36,28 @@ module Integral
27
36
  @user = Integral::User.unscoped.find_by_id(object.whodunnit)&.decorate
28
37
  end
29
38
 
39
+ # @return [String] image linked to whodunnit
40
+ def whodunnit_avatar_url
41
+ if whodunnit.present?
42
+ whodunnit.avatar.url(:thumbnail)
43
+ else
44
+ ActionController::Base.helpers.asset_path('integral/defaults/user_avatar.jpg')
45
+ end
46
+ end
47
+
48
+ # @return [String] name linked to whodunnit
49
+ def whodunnit_name
50
+ if whodunnit.present?
51
+ whodunnit.name
52
+ else
53
+ 'System'
54
+ end
55
+ end
56
+
57
+ def item
58
+ @item ||= item_type.constantize.unscoped.find(item_id)
59
+ end
60
+
30
61
  # @return [String] formatted title
31
62
  def item_title
32
63
  decorated_item&.title
@@ -37,21 +68,29 @@ module Integral
37
68
  @decorated_item ||= item&.decorate
38
69
  end
39
70
 
71
+ # @return [String] Font Awesome icon
72
+ def item_icon
73
+ 'ellipsis-v'
74
+ end
75
+
40
76
  # @return [String] formatted item type
41
- def item_type
77
+ def model_name
42
78
  object.item_type.constantize.model_name.human
43
79
  end
44
80
 
45
- # @return [String] formatted attributes changed
46
- def attributes_changed
47
- return unless object.event == 'update'
48
- keys = ''
49
-
50
- object.changeset.each_key do |key|
51
- # next if ['updated_at', 'lock_version'].include? key
52
- keys += "#{key}, "
53
- end
54
- keys[0..-3]
55
- end
81
+ # Currently not possible to show this as changeset isn't available in the query resultset for performance reasons - One possible solution would be to create a Grid class for each Version - rather than unioning all the tables it only includes it's own
82
+ #
83
+ # # @return [String] formatted attributes changed
84
+ # def attributes_changed
85
+ # return unless object.event == 'update'
86
+ #
87
+ # keys = ''
88
+ #
89
+ # object.changeset.each_key do |key|
90
+ # # next if ['updated_at', 'lock_version'].include? key
91
+ # keys += "#{key}, "
92
+ # end
93
+ # keys[0..-3]
94
+ # end
56
95
  end
57
96
  end
@@ -5,17 +5,54 @@ module Integral
5
5
  module BaseHelper
6
6
  include Integral::SupportHelper
7
7
 
8
+ # @return [String] Integral card
9
+ def render_card(partial, locals = {})
10
+ render(partial: "integral/backend/shared/cards/#{partial}", locals: locals)
11
+ end
12
+
13
+ # @return [Array] returns array of VersionDecorators subclassed depending on the Version subclass
14
+ def recent_user_activity_grid
15
+ @recent_user_activity_grid ||= begin
16
+ options = { user: current_user.id }
17
+ options[:object] = resource_klass.to_s if resource_klass.present?
18
+ options[:item_id] = @resource.id if @resource.present?
19
+
20
+ recent_activity_grid(options)
21
+ end
22
+ end
23
+
24
+ # @return [Array] returns array of VersionDecorators subclassed depending on the Version subclass
25
+ def recent_site_activity_grid
26
+ @recent_site_activity_grid ||= begin
27
+ options = {}
28
+ options[:object] = resource_klass.to_s if resource_klass.present?
29
+ options[:item_id] = @resource.id if @resource.present?
30
+
31
+ recent_activity_grid(options)
32
+ end
33
+ end
34
+
35
+ def recent_activity_grid(options)
36
+ Integral::Grids::ActivitiesGrid.new(options)
37
+ end
38
+
8
39
  # @return [String] title provided through yield or i18n scoped to controller namespace & action
9
40
  def page_title
10
41
  return content_for(:title) if content_for?(:title)
42
+ return t("devise.#{controller_name}.#{action_name}.title") if devise_controller?
11
43
 
12
44
  # Scope is set to current controller namespace & action
13
- t('title', scope: "#{controller_path.tr('/', '.')}.#{action_name}")
45
+ t('title', scope: "#{controller_path.tr('/', '.')}.#{action_name}",
46
+ default: I18n.t("integral.backend.titles.#{action_name}",
47
+ type_singular: resource_klass.model_name.human.capitalize,
48
+ type_plural: resource_klass.model_name.human(count: 2).capitalize))
14
49
  end
15
50
 
16
51
  # Renders a grid from a local partial within a datagrid container
17
52
  def render_data_grid
18
- return content_tag(:div, render(partial: 'grid', locals: { grid: @grid }), data: { 'grid' => true, 'form' => 'grid_form' }) unless block_given?
53
+ unless block_given?
54
+ return content_tag(:div, render(partial: 'grid', locals: { grid: @grid }), data: { 'grid' => true, 'form' => 'grid_form' })
55
+ end
19
56
 
20
57
  content_tag :div, data: { 'grid' => true, 'form' => 'grid_form' } do
21
58
  yield
@@ -48,6 +85,23 @@ module Integral
48
85
  ChartRenderer::Donut.render(dataset)
49
86
  end
50
87
 
88
+ # Donut Graph - At a Glance
89
+ def dataset_at_a_glance_posts
90
+ [
91
+ { scope: Integral::Post.published, label: 'Published' },
92
+ { scope: Integral::Post.draft, label: 'Draft ' }
93
+ ]
94
+ end
95
+
96
+ # Donut Graph - At a Glance
97
+ def dataset_at_a_glance_pages
98
+ [
99
+ { scope: Integral::Page.published, label: 'Published' },
100
+ { scope: Integral::Page.draft, label: 'Draft ' },
101
+ { scope: Integral::Page.archived, label: 'Archived ' }
102
+ ]
103
+ end
104
+
51
105
  # Donut Graph - At a Glance
52
106
  def dataset_dashboard_atg
53
107
  data = [
@@ -1,6 +1,11 @@
1
1
  module Integral
2
2
  # Blog Helper which contains methods used through the blog
3
3
  module BlogHelper
4
+ # @return [Relation] featured categories - currently all which have posts associated to them
5
+ def featured_categories
6
+ @featured_categories ||= Integral::Category.where(id: Integral::Post.published.select(:category_id).uniq.map(&:category_id))
7
+ end
8
+
4
9
  # @param post [Integral::Post] post to convert to JSON-LD
5
10
  #
6
11
  # @return [String] Javascript snippet containing JSON-LD of the provided post
@@ -13,14 +18,14 @@ module Integral
13
18
  # @param posts [Integral::Post] collection of posts to convert to JSON-LD
14
19
  #
15
20
  # @return [String] Javascript snippet containing JSON-LD of the provided posts
16
- def render_posts_as_json_ld(posts)
21
+ def render_posts_as_json_ld(posts, title: t('.title'), url: request.original_url, description: t('.description'))
17
22
  render_json_ld do
18
23
  {
19
24
  "@context": 'http://schema.org',
20
25
  "@type": 'Blog',
21
- "name": t('.title'),
22
- "url": request.original_url,
23
- "description": t('.description'),
26
+ "name": title,
27
+ "url": url,
28
+ "description": description,
24
29
  "publisher": {
25
30
  "@type": 'Organization',
26
31
  "name": Integral::Settings.website_title
@@ -38,12 +43,14 @@ module Integral
38
43
  # Whether or not to display share widget
39
44
  def display_share_widget?
40
45
  return true if "#{controller_name}.#{action_name}" == 'posts.show'
46
+
41
47
  false
42
48
  end
43
49
 
44
50
  # Whether or not to display recent posts sidebar widget
45
51
  def display_recent_posts_widget?
46
52
  return false if "#{controller_name}.#{action_name}" == 'posts.index'
53
+
47
54
  true
48
55
  end
49
56
 
@@ -51,5 +58,15 @@ module Integral
51
58
  def display_popular_posts_widget?
52
59
  Integral::Post.published.count > 4
53
60
  end
61
+
62
+ # Whether or not to display most read widget
63
+ def display_most_read_posts_widget?
64
+ Integral::Post.published.count > 10
65
+ end
66
+
67
+ # TODO: Change this to use GA API through a GoogleAnalyticsService
68
+ def most_read_posts
69
+ @popular_posts.decorate
70
+ end
54
71
  end
55
72
  end
@@ -0,0 +1,37 @@
1
+ require 'net/http'
2
+
3
+ module Integral
4
+ module Webhook
5
+ # Handles the delivery of a webhook event payload to a webhook endpoint
6
+ class DeliveryJob < ApplicationJob
7
+ # Delivers webhook payload to endpoint
8
+ def perform(endpoint_id, payload)
9
+ return unless endpoint = Webhook::Endpoint.find(endpoint_id)
10
+
11
+ response = request(endpoint.target_url, payload)
12
+
13
+ case response.code
14
+ when 410
15
+ endpoint.destroy
16
+ when 400..599
17
+ raise response.to_s
18
+ end
19
+ end
20
+
21
+ private
22
+
23
+ def request(endpoint, payload)
24
+ uri = URI.parse(endpoint)
25
+
26
+ request = Net::HTTP::Post.new(uri.request_uri)
27
+ request['Content-Type'] = 'application/json'
28
+ request.body = payload
29
+
30
+ http = Net::HTTP.new(uri.host, uri.port)
31
+ http.use_ssl = (uri.scheme == 'https')
32
+
33
+ http.request(request)
34
+ end
35
+ end
36
+ end
37
+ end
@@ -49,7 +49,10 @@ module Integral
49
49
  # Subject of the forwarding email
50
50
  # Adds the enquiry subject if it exists otherwise uses only reference
51
51
  def forwarding_subject(enquiry)
52
- return "#{enquiry.reference} #{I18n.t('integral.contact_mailer.forward_enquiry.subject')}" if enquiry.subject.blank?
52
+ if enquiry.subject.blank?
53
+ return "#{enquiry.reference} #{I18n.t('integral.contact_mailer.forward_enquiry.subject')}"
54
+ end
55
+
53
56
  "#{enquiry.reference} #{I18n.t('integral.contact_mailer.forward_enquiry.subject')} - #{enquiry.subject}"
54
57
  end
55
58
  end