decidim-feeds 1.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 (77) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE-AGPLv3.txt +661 -0
  3. data/README.md +39 -0
  4. data/Rakefile +9 -0
  5. data/app/cells/decidim/feeds/content_blocks/feeds_settings_form/show.erb +3 -0
  6. data/app/cells/decidim/feeds/content_blocks/feeds_settings_form_cell.rb +23 -0
  7. data/app/cells/decidim/feeds/feed_cell.rb +24 -0
  8. data/app/cells/decidim/feeds/feed_dropdown_metadata_cell.rb +19 -0
  9. data/app/cells/decidim/feeds/feed_g_cell.rb +33 -0
  10. data/app/cells/decidim/feeds/feed_metadata_g_cell.rb +25 -0
  11. data/app/cells/decidim/feeds/feed_s_cell.rb +13 -0
  12. data/app/commands/decidim/feeds/admin/create_feed.rb +90 -0
  13. data/app/commands/decidim/feeds/admin/update_feed.rb +85 -0
  14. data/app/commands/decidim/feeds/create_feed.rb +90 -0
  15. data/app/commands/decidim/feeds/update_feed.rb +73 -0
  16. data/app/constraints/decidim/feeds/current_component.rb +28 -0
  17. data/app/constraints/decidim/feeds/current_feed.rb +43 -0
  18. data/app/controllers/concerns/decidim/feeds/feed_breadcrumb.rb +36 -0
  19. data/app/controllers/decidim/feeds/admin/application_controller.rb +26 -0
  20. data/app/controllers/decidim/feeds/admin/components_controller.rb +14 -0
  21. data/app/controllers/decidim/feeds/admin/concerns/feed_admin.rb +51 -0
  22. data/app/controllers/decidim/feeds/admin/feeds_controller.rb +92 -0
  23. data/app/controllers/decidim/feeds/application_controller.rb +37 -0
  24. data/app/controllers/decidim/feeds/feeds_controller.rb +137 -0
  25. data/app/forms/decidim/feeds/admin/feed_form.rb +102 -0
  26. data/app/forms/decidim/feeds/feed_form.rb +70 -0
  27. data/app/helpers/decidim/feeds/admin/feeds_admin_menu_helper.rb +10 -0
  28. data/app/helpers/decidim/feeds/application_helper.rb +16 -0
  29. data/app/helpers/decidim/feeds/feeds_helper.rb +38 -0
  30. data/app/models/decidim/feeds/application_record.rb +10 -0
  31. data/app/models/decidim/feeds/feed.rb +113 -0
  32. data/app/packs/entrypoints/decidim_feeds.js +5 -0
  33. data/app/packs/entrypoints/decidim_feeds.scss +1 -0
  34. data/app/packs/images/decidim/feeds/decidim_feeds.svg +1 -0
  35. data/app/packs/images/decidim/feeds/icon.svg +1 -0
  36. data/app/packs/src/decidim/feeds/feeds.js +0 -0
  37. data/app/packs/stylesheets/decidim/feeds/_variables.scss +10 -0
  38. data/app/packs/stylesheets/decidim/feeds/feeds.scss +3 -0
  39. data/app/permissions/decidim/feeds/permissions.rb +53 -0
  40. data/app/presenters/decidim/feeds/admin_log/feed_presenter.rb +46 -0
  41. data/app/queries/decidim/feeds/admin/admin_users.rb +60 -0
  42. data/app/queries/decidim/feeds/organization_feeds.rb +16 -0
  43. data/app/views/decidim/feeds/admin/feeds/_form.html.erb +66 -0
  44. data/app/views/decidim/feeds/admin/feeds/edit.html.erb +20 -0
  45. data/app/views/decidim/feeds/admin/feeds/index.html.erb +65 -0
  46. data/app/views/decidim/feeds/admin/feeds/new.html.erb +20 -0
  47. data/app/views/decidim/feeds/feeds/_form.html.erb +18 -0
  48. data/app/views/decidim/feeds/feeds/edit.html.erb +10 -0
  49. data/app/views/decidim/feeds/feeds/index.html.erb +5 -0
  50. data/app/views/decidim/feeds/feeds/new.html.erb +20 -0
  51. data/app/views/decidim/feeds/feeds/show.html.erb +33 -0
  52. data/app/views/layouts/decidim/admin/_manage_feeds.html.erb +11 -0
  53. data/app/views/layouts/decidim/admin/feed.html.erb +17 -0
  54. data/app/views/layouts/decidim/admin/feeds.html.erb +17 -0
  55. data/app/views/layouts/decidim/feed.html.erb +18 -0
  56. data/config/assets.rb +9 -0
  57. data/config/i18n-tasks.yml +10 -0
  58. data/config/locales/bs.yml +75 -0
  59. data/config/locales/de.yml +77 -0
  60. data/config/locales/en.yml +75 -0
  61. data/config/locales/hr.yml +75 -0
  62. data/config/locales/it.yml +75 -0
  63. data/config/locales/sr.yml +75 -0
  64. data/config/locales/tr.yml +75 -0
  65. data/lib/decidim/api/feed_type.rb +30 -0
  66. data/lib/decidim/feeds/admin.rb +10 -0
  67. data/lib/decidim/feeds/admin_engine.rb +81 -0
  68. data/lib/decidim/feeds/api.rb +9 -0
  69. data/lib/decidim/feeds/content_blocks/content_blocks_homepage.rb +19 -0
  70. data/lib/decidim/feeds/engine.rb +83 -0
  71. data/lib/decidim/feeds/menu.rb +106 -0
  72. data/lib/decidim/feeds/participatory_space.rb +52 -0
  73. data/lib/decidim/feeds/seeds.rb +47 -0
  74. data/lib/decidim/feeds/test/factories.rb +17 -0
  75. data/lib/decidim/feeds/version.rb +9 -0
  76. data/lib/decidim/feeds.rb +13 -0
  77. metadata +142 -0
@@ -0,0 +1,51 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "active_support/concern"
4
+
5
+ module Decidim
6
+ module Feeds
7
+ module Admin
8
+ module Concerns
9
+ # This concern is meant to be included in all controllers that are scoped
10
+ # into a feed's admin panel. It will override the layout so it shows
11
+ # the sidebar, preload the feed, etc.
12
+ module FeedAdmin
13
+ extend ActiveSupport::Concern
14
+
15
+ RegistersPermissions
16
+ .register_permissions(::Decidim::Feeds::Admin::Concerns::FeedAdmin,
17
+ Decidim::Feeds::Permissions,
18
+ Decidim::Admin::Permissions)
19
+
20
+ included do
21
+ include Decidim::Admin::ParticipatorySpaceAdminContext
22
+ helper_method :current_feed
23
+ add_breadcrumb_item_from_menu :admin_feed_menu
24
+
25
+ participatory_space_admin_layout
26
+
27
+ def current_feed
28
+ @current_feed ||= organization_feeds.find_by!(
29
+ slug: params[:feed_slug] || params[:slug]
30
+ )
31
+ end
32
+
33
+ alias_method :current_participatory_space, :current_feed
34
+
35
+ def organization_feeds
36
+ @organization_feeds ||= OrganizationFeeds.new(current_organization).query
37
+ end
38
+
39
+ def permissions_context
40
+ super.merge(current_participatory_space:)
41
+ end
42
+
43
+ def permission_class_chain
44
+ PermissionsRegistry.chain_for(FeedAdmin)
45
+ end
46
+ end
47
+ end
48
+ end
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,92 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module Feeds
5
+ module Admin
6
+ # Controller that allows managing feeds.
7
+ #
8
+ class FeedsController < Decidim::Feeds::Admin::ApplicationController
9
+ include Decidim::Admin::ParticipatorySpaceAdminBreadcrumb
10
+ helper_method :current_feed, :current_participatory_space
11
+ layout "decidim/admin/feeds"
12
+
13
+ def index
14
+ enforce_permission_to :read, :feed_list
15
+ @feeds = collection
16
+ end
17
+
18
+ def new
19
+ enforce_permission_to :create, :feed
20
+ @form = form(FeedForm).instance
21
+ end
22
+
23
+ def create
24
+ enforce_permission_to :create, :feed
25
+
26
+ params[:created_by] = current_user
27
+ @form = form(FeedForm).from_params(params)
28
+
29
+ CreateFeed.call(@form) do
30
+ on(:ok) do |feed|
31
+ flash[:notice] = I18n.t("feeds.create.success", scope: "decidim.admin")
32
+ redirect_to feeds_path
33
+ end
34
+
35
+ on(:invalid) do
36
+ flash.now[:alert] = I18n.t("feeds.create.error", scope: "decidim.admin")
37
+ render :new
38
+ end
39
+ end
40
+ end
41
+
42
+ def edit
43
+ enforce_permission_to :update, :feed, feed: current_feed
44
+ @form = form(FeedForm).from_model(current_feed)
45
+ render layout: "decidim/admin/feed"
46
+ end
47
+
48
+ def update
49
+ enforce_permission_to :update, :feed, feed: current_feed
50
+ @form = form(FeedForm).from_params(
51
+ feed_params,
52
+ feed_id: current_feed.id
53
+ )
54
+
55
+ UpdateFeed.call(current_feed, @form) do
56
+ on(:ok) do |feed|
57
+ flash[:notice] = I18n.t("feeds.update.success", scope: "decidim.admin")
58
+ redirect_to edit_feed_path(feed)
59
+ end
60
+
61
+ on(:invalid) do
62
+ flash.now[:alert] = I18n.t("feeds.update.error", scope: "decidim.admin")
63
+ render :edit, layout: "decidim/admin/feed"
64
+ end
65
+ end
66
+ end
67
+
68
+ def copy
69
+ enforce_permission_to :create, :feed
70
+ end
71
+
72
+ private
73
+
74
+ def collection
75
+ @collection ||= OrganizationFeeds.new(current_user.organization).query
76
+ end
77
+
78
+ def current_feed
79
+ @current_feed ||= collection.where(slug: params[:slug]).or(
80
+ collection.where(id: params[:slug])
81
+ ).first
82
+ end
83
+
84
+ alias current_participatory_space current_feed
85
+
86
+ def feed_params
87
+ { id: params[:slug] }.merge(params[:feed].to_unsafe_h)
88
+ end
89
+ end
90
+ end
91
+ end
92
+ end
@@ -0,0 +1,37 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module Feeds
5
+ # The main admin application controller for feeds
6
+ class ApplicationController < Decidim::ApplicationController
7
+ helper Decidim::ApplicationHelper
8
+ helper Decidim::Feeds::FeedsHelper
9
+ include NeedsPermission
10
+
11
+ register_permissions(Decidim::Feeds::ApplicationController,
12
+ ::Decidim::Feeds::Permissions,
13
+ ::Decidim::Admin::Permissions,
14
+ ::Decidim::Permissions)
15
+
16
+ private
17
+
18
+ def user_has_no_permission_path
19
+ decidim.new_user_session_path
20
+ end
21
+
22
+ def permissions_context
23
+ super.merge(
24
+ current_participatory_space: try(:current_participatory_space)
25
+ )
26
+ end
27
+
28
+ def permission_class_chain
29
+ ::Decidim.permissions_registry.chain_for(::Decidim::Feeds::ApplicationController)
30
+ end
31
+
32
+ def permission_scope
33
+ :public
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,137 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module Feeds
5
+ # A controller that holds the logic to show Feeds in a public layout.
6
+ class FeedsController < Decidim::Feeds::ApplicationController
7
+ include ParticipatorySpaceContext
8
+ include FeedBreadcrumb
9
+ include FormFactory
10
+
11
+ participatory_space_layout only: :show
12
+
13
+ include FilterResource
14
+ include Paginable
15
+ include HasParticipatorySpaceContentBlocks
16
+
17
+ # helper_method :collection, :stats
18
+
19
+ def index
20
+ enforce_permission_to :list, :feed
21
+
22
+ @feeds = published_feeds.query
23
+ end
24
+
25
+ def show
26
+ enforce_permission_to :read, :feed, feed: current_participatory_space
27
+
28
+ @posts_component = current_feed.components.find_by(manifest_name: "posts")
29
+
30
+ if @posts_component.nil?
31
+ flash[:alert] = I18n.t("feeds.show.posts_component_not_found", scope: "decidim.feeds")
32
+ redirect_to feeds_path
33
+ end
34
+
35
+ # redirect_to decidim_feed_posts_path(current_participatory_space, posts_component) if posts_component
36
+ end
37
+
38
+ def new
39
+ enforce_permission_to :create, :feed
40
+
41
+ @form = form(FeedForm).instance
42
+ end
43
+
44
+ def create
45
+ enforce_permission_to :create, :feed
46
+
47
+ @form = form(FeedForm).from_params(params)
48
+
49
+ CreateFeed.call(@form) do
50
+ on(:ok) do |feed|
51
+ flash[:notice] = I18n.t("feeds.create.success", scope: "decidim.feeds")
52
+ redirect_to feeds_path
53
+ end
54
+
55
+ on(:invalid) do
56
+ flash.now[:alert] = I18n.t("feeds.create.error", scope: "decidim.feeds")
57
+ render :new
58
+ end
59
+ end
60
+ end
61
+
62
+ def edit
63
+ enforce_permission_to :update, :feed, feed: current_feed
64
+
65
+ @form = form(FeedForm).from_model(current_feed)
66
+ end
67
+
68
+ def update
69
+ enforce_permission_to :update, :feed, feed: current_feed
70
+
71
+ @form = form(FeedForm).from_params(
72
+ feed_params,
73
+ feed_id: current_feed.id
74
+ )
75
+
76
+ UpdateFeed.call(current_feed, @form) do
77
+ on(:ok) do |feed|
78
+ flash[:notice] = I18n.t("feeds.update.success", scope: "decidim.feeds")
79
+ redirect_to feed
80
+ end
81
+
82
+ on(:invalid) do
83
+ flash.now[:alert] = I18n.t("feeds.update.error", scope: "decidim.feeds")
84
+ render :edit
85
+ end
86
+ end
87
+ end
88
+
89
+ private
90
+
91
+ def collection
92
+ @collection ||= OrganizationFeeds.new(current_user.organization).query
93
+ end
94
+
95
+ def current_feed
96
+ @current_feed ||= collection.where(slug: params[:slug]).or(
97
+ collection.where(id: params[:slug])
98
+ ).first
99
+ end
100
+
101
+ def search_collection
102
+ Feed.where(organization: current_organization)
103
+ end
104
+
105
+ def default_filter_params
106
+ {
107
+ with_any_scope: nil,
108
+ with_any_area: nil,
109
+ with_any_type: nil
110
+ }
111
+ end
112
+
113
+ def current_participatory_space
114
+ return unless params[:slug]
115
+
116
+ @current_participatory_space ||= OrganizationFeeds.new(current_organization).query.where(slug: params[:slug]).or(
117
+ OrganizationFeeds.new(current_organization).query.where(id: params[:slug])
118
+ ).first!
119
+ end
120
+
121
+ def published_feeds
122
+ @published_feeds ||= OrganizationFeeds.new(current_organization)
123
+ end
124
+
125
+ # def collection
126
+ # @collection ||= paginate(Kaminari.paginate_array(parent_feeds))
127
+ # end
128
+
129
+ def feed_params
130
+ # only allow title to be updated
131
+ title_params = current_organization.available_locales.map { |locale| "title_#{locale}" }
132
+ permitted_params = params.require(:feed).permit(title_params)
133
+ { id: params[:slug] }.merge(permitted_params)
134
+ end
135
+ end
136
+ end
137
+ end
@@ -0,0 +1,102 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module Feeds
5
+ module Admin
6
+ # A form object used to create feeds from the admin
7
+ # dashboard.
8
+ #
9
+ class FeedForm < Form
10
+ include TranslatableAttributes
11
+ include AttachmentAttributes
12
+
13
+ mimic :feed
14
+
15
+ translatable_attribute :title, String
16
+
17
+ attribute :created_by, String
18
+ attribute :slug, String
19
+ attribute :attachment, AttachmentForm
20
+ # attribute :participatory_processes_ids, Array[Integer]
21
+ # attribute :included_at, Decidim::Attributes::LocalizedDate
22
+
23
+ # attribute :banner_image
24
+ # attribute :hero_image
25
+ # attribute :remove_banner_image, Boolean, default: false
26
+ # attribute :remove_hero_image, Boolean, default: false
27
+
28
+ attachments_attribute :documents
29
+
30
+ validates :slug, presence: true, format: { with: Decidim::Feeds::Feed.slug_format }
31
+
32
+ validate :slug_uniqueness
33
+ # validate :same_type_organization, if: ->(form) { form.decidim_feeds_type_id }
34
+
35
+ validates :title, translatable_presence: true
36
+
37
+ # validates :banner_image, passthru: { to: Decidim::Feed }
38
+ # validates :hero_image, passthru: { to: Decidim::Feed }
39
+
40
+ # validates :weight, presence: true
41
+
42
+ alias organization current_organization
43
+
44
+ def map_model(model)
45
+ self.title = model.title # translated_attribute(model.title)
46
+ self.slug = model.slug
47
+ self.documents = model.attachments
48
+ end
49
+
50
+ # def created_by_for_select
51
+ # CREATED_BY.map do |creator|
52
+ # [
53
+ # I18n.t("created_by.#{creator}", scope: "decidim.feeds"),
54
+ # creator
55
+ # ]
56
+ # end
57
+ # end
58
+
59
+ # def processes_for_select
60
+ # @processes_for_select ||= organization_participatory_processes
61
+ # &.map { |pp| [translated_attribute(pp.title), pp.id] }
62
+ # &.sort_by { |arr| arr[0] }
63
+ # end
64
+
65
+ def has_attachments?
66
+ feed.has_attachments? && errors[:documents].empty? && documents.present?
67
+ end
68
+
69
+ def has_error_in_attachments?
70
+ errors[:documents].present?
71
+ end
72
+
73
+ private
74
+
75
+ # def organization_participatory_processes
76
+ # Decidim.find_participatory_space_manifest(:participatory_processes)
77
+ # .participatory_spaces.call(current_organization)
78
+ # end
79
+
80
+ def organization_feeds
81
+ OrganizationFeeds.new(current_organization).query
82
+ end
83
+
84
+ def slug_uniqueness
85
+ return unless organization_feeds
86
+ .where(slug:)
87
+ .where.not(id: context[:feed_id])
88
+ .any?
89
+
90
+ errors.add(:slug, :taken)
91
+ end
92
+
93
+ # def same_type_organization
94
+ # return unless feed_type
95
+ # return if feed_type.organization == current_organization
96
+
97
+ # errors.add(:feed_type, :invalid)
98
+ # end
99
+ end
100
+ end
101
+ end
102
+ end
@@ -0,0 +1,70 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module Feeds
5
+ # A form object used to create feeds from the admin
6
+ # dashboard.
7
+ #
8
+ class FeedForm < Form
9
+ include TranslatableAttributes
10
+
11
+ mimic :feed
12
+
13
+ translatable_attribute :title, String
14
+
15
+ attribute :created_by, String
16
+
17
+ # attribute :participatory_processes_ids, Array[Integer]
18
+ # attribute :included_at, Decidim::Attributes::LocalizedDate
19
+
20
+ # attribute :banner_image
21
+ # attribute :hero_image
22
+ # attribute :remove_banner_image, Boolean, default: false
23
+ # attribute :remove_hero_image, Boolean, default: false
24
+
25
+ # validate :same_type_organization, if: ->(form) { form.decidim_feeds_type_id }
26
+
27
+ validates :title, translatable_presence: true
28
+
29
+ # validates :banner_image, passthru: { to: Decidim::Feed }
30
+ # validates :hero_image, passthru: { to: Decidim::Feed }
31
+
32
+ # validates :weight, presence: true
33
+
34
+ alias organization current_organization
35
+
36
+ # def created_by_for_select
37
+ # CREATED_BY.map do |creator|
38
+ # [
39
+ # I18n.t("created_by.#{creator}", scope: "decidim.feeds"),
40
+ # creator
41
+ # ]
42
+ # end
43
+ # end
44
+
45
+ # def processes_for_select
46
+ # @processes_for_select ||= organization_participatory_processes
47
+ # &.map { |pp| [translated_attribute(pp.title), pp.id] }
48
+ # &.sort_by { |arr| arr[0] }
49
+ # end
50
+
51
+ private
52
+
53
+ # def organization_participatory_processes
54
+ # Decidim.find_participatory_space_manifest(:participatory_processes)
55
+ # .participatory_spaces.call(current_organization)
56
+ # end
57
+
58
+ def organization_feeds
59
+ OrganizationFeeds.new(current_organization).query
60
+ end
61
+
62
+ # def same_type_organization
63
+ # return unless feed_type
64
+ # return if feed_type.organization == current_organization
65
+
66
+ # errors.add(:feed_type, :invalid)
67
+ # end
68
+ end
69
+ end
70
+ end
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module Feeds
5
+ module Admin
6
+ module FeedsAdminMenuHelper
7
+ end
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module Feeds
5
+ # Custom helpers, scoped to the feeds engine.
6
+ #
7
+ module ApplicationHelper
8
+ include PaginateHelper
9
+ include SanitizeHelper
10
+ # include Decidim::Feeds::PostsHelper
11
+ include ::Decidim::EndorsableHelper
12
+ include ::Decidim::FollowableHelper
13
+ include Decidim::Comments::CommentsHelper
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,38 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module Feeds
5
+ # Helpers related to the Feeds layout.
6
+ module FeedsHelper
7
+ include Decidim::ResourceHelper
8
+ # include Decidim::AttachmentsHelper
9
+ include Decidim::IconHelper
10
+ include Decidim::SanitizeHelper
11
+ include Decidim::ResourceReferenceHelper
12
+ # include Decidim::FiltersHelper
13
+ # include FilterFeedsHelper
14
+
15
+ # Items to display in the navigation of an feed
16
+ def feed_nav_items(participatory_space)
17
+ components = participatory_space.components.published.or(Decidim::Component.where(id: try(:current_component)))
18
+
19
+ [
20
+ *(if participatory_space.members.not_ceased.any?
21
+ [{
22
+ name: t("feed_member_menu_item", scope: "layouts.decidim.feed_navigation"),
23
+ url: decidim_feeds.feed_feed_members_path(participatory_space),
24
+ active: is_active_link?(decidim_feeds.feed_feed_members_path(participatory_space), :inclusive)
25
+ }]
26
+ end
27
+ )
28
+ ] + components.map do |component|
29
+ {
30
+ name: decidim_escape_translated(component.name),
31
+ url: main_component_path(component),
32
+ active: is_active_link?(main_component_path(component), :inclusive)
33
+ }
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module Feeds
5
+ # Abstract class from which all models in this engine inherit.
6
+ class ApplicationRecord < ActiveRecord::Base
7
+ self.abstract_class = true
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,113 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module Feeds
5
+ class Feed < ApplicationRecord
6
+ include Decidim::Participable
7
+ include Decidim::ParticipatorySpaceResourceable
8
+ include Decidim::TranslatableResource
9
+ include Decidim::Loggable
10
+ include Decidim::Traceable
11
+ include Decidim::Searchable
12
+ include Decidim::HasAttachments
13
+ # include Decidim::HasAttachmentCollections
14
+ # include Decidim::Publicable
15
+ # include Decidim::ScopableParticipatorySpace
16
+ # include Decidim::Followable
17
+ # include Decidim::HasReference
18
+ # include Decidim::HasPrivateUsers
19
+ # include Decidim::HasUploadValidations
20
+ # include Decidim::FilterableResource
21
+
22
+ translatable_fields :title
23
+
24
+ belongs_to :organization,
25
+ foreign_key: "decidim_organization_id",
26
+ class_name: "Decidim::Organization"
27
+
28
+ has_many :components, as: :participatory_space, dependent: :destroy
29
+ has_many :categories,
30
+ foreign_key: "decidim_participatory_space_id",
31
+ foreign_type: "decidim_participatory_space_type",
32
+ dependent: :destroy,
33
+ as: :participatory_space
34
+
35
+ # has_one_attached :hero_image
36
+ # validates_upload :hero_image, uploader: Decidim::HeroImageUploader
37
+
38
+ # has_one_attached :banner_image
39
+ # validates_upload :banner_image, uploader: Decidim::BannerImageUploader
40
+
41
+ validates :slug, uniqueness: { scope: :organization }
42
+ validates :slug, presence: true, format: { with: Decidim::Feeds::Feed.slug_format }
43
+
44
+ searchable_fields({
45
+ # scope_id: :decidim_scope_id,
46
+ participatory_space: :itself,
47
+ A: :title,
48
+ # B: :subtitle,
49
+ # C: :short_description,
50
+ # D: :description,
51
+ datetime: :created_at
52
+ },
53
+ index_on_create: true,
54
+ index_on_update: true
55
+ )
56
+
57
+ # Overwriting existing method Decidim::HasPrivateUsers.public_spaces
58
+ # def self.public_spaces
59
+ # where(private_space: false).or(where(private_space: true).where(is_transparent: true)).published
60
+ # end
61
+
62
+ def self.log_presenter_class_for(_log)
63
+ Decidim::Feeds::AdminLog::FeedPresenter
64
+ end
65
+
66
+ # This is required by participable, but Feed is not publicable
67
+ def self.published
68
+ all
69
+ end
70
+
71
+ # def hashtag
72
+ # attributes["hashtag"].to_s.delete("#")
73
+ # end
74
+
75
+ def to_param
76
+ slug
77
+ end
78
+
79
+ def translated_title
80
+ Decidim::FeedPresenter.new(self).translated_title
81
+ end
82
+
83
+ def scopes_enabled?
84
+ false
85
+ end
86
+
87
+ def scope
88
+ nil
89
+ end
90
+
91
+ def followers
92
+ Decidim::User.none
93
+ end
94
+
95
+ def private_space?
96
+ false
97
+ end
98
+
99
+ def has_subscopes?
100
+ false
101
+ end
102
+
103
+ def published?
104
+ true
105
+ end
106
+
107
+ # private
108
+
109
+ # Allow ransacker to search for a key in a hstore column (`title`.`en`)
110
+ # ransacker_i18n :title # requires filterable
111
+ end
112
+ end
113
+ end
@@ -0,0 +1,5 @@
1
+ import 'src/decidim/feeds/feeds.js';
2
+
3
+ require.context('../images', true);
4
+
5
+ import 'entrypoints/decidim_feeds.scss';
@@ -0,0 +1 @@
1
+ @import 'stylesheets/decidim/feeds/feeds';
@@ -0,0 +1 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 35 35"><path d="M17.5 35A17.5 17.5 0 1 1 35 17.5 17.52 17.52 0 0 1 17.5 35zm0-33.06A15.56 15.56 0 1 0 33.06 17.5 15.57 15.57 0 0 0 17.5 1.94zm9.5 13.7H8a1 1 0 0 1 0-1.94h19a1 1 0 0 1 0 1.94zm0 3.68H8a1 1 0 0 1 0-1.94h19a1 1 0 0 1 0 1.94zM22.26 23H8a1 1 0 0 1 0-1.94h14.26a1 1 0 0 1 0 1.94z"/></svg>
@@ -0,0 +1 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 35 35"><path d="M17.5 35A17.5 17.5 0 1 1 35 17.5 17.52 17.52 0 0 1 17.5 35zm0-33.06A15.56 15.56 0 1 0 33.06 17.5 15.57 15.57 0 0 0 17.5 1.94zm9.5 13.7H8a1 1 0 0 1 0-1.94h19a1 1 0 0 1 0 1.94zm0 3.68H8a1 1 0 0 1 0-1.94h19a1 1 0 0 1 0 1.94zM22.26 23H8a1 1 0 0 1 0-1.94h14.26a1 1 0 0 1 0 1.94z"/></svg>