integral 1.3.0 → 1.4.0

Sign up to get free protection for your applications and to get access to all the features.
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