decidim-posts 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 (117) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE-AGPLv3.txt +661 -0
  3. data/README.md +40 -0
  4. data/Rakefile +9 -0
  5. data/app/cells/decidim/posts/comments/add_comment.erb +15 -0
  6. data/app/cells/decidim/posts/comments/comments_loading.erb +1 -0
  7. data/app/cells/decidim/posts/comments/order_control.erb +13 -0
  8. data/app/cells/decidim/posts/comments/show.erb +31 -0
  9. data/app/cells/decidim/posts/comments_cell.rb +158 -0
  10. data/app/cells/decidim/posts/content_blocks/posts/show.erb +3 -0
  11. data/app/cells/decidim/posts/content_blocks/posts_cell.rb +50 -0
  12. data/app/cells/decidim/posts/content_blocks/posts_settings_form/show.erb +3 -0
  13. data/app/cells/decidim/posts/content_blocks/posts_settings_form_cell.rb +23 -0
  14. data/app/cells/decidim/posts/feed_dropdown_metadata_cell.rb +19 -0
  15. data/app/cells/decidim/posts/meeting/show.erb +65 -0
  16. data/app/cells/decidim/posts/meeting_cell.rb +44 -0
  17. data/app/cells/decidim/posts/post/show.erb +30 -0
  18. data/app/cells/decidim/posts/post/survey.erb +68 -0
  19. data/app/cells/decidim/posts/post_attachments/show.erb +40 -0
  20. data/app/cells/decidim/posts/post_attachments_cell.rb +17 -0
  21. data/app/cells/decidim/posts/post_cell.rb +44 -0
  22. data/app/cells/decidim/posts/post_comment/show.erb +17 -0
  23. data/app/cells/decidim/posts/post_comment_cell.rb +49 -0
  24. data/app/cells/decidim/posts/post_header/show.erb +53 -0
  25. data/app/cells/decidim/posts/post_header_cell.rb +79 -0
  26. data/app/cells/decidim/posts/post_host/show.erb +74 -0
  27. data/app/cells/decidim/posts/post_host_cell.rb +73 -0
  28. data/app/cells/decidim/posts/post_metadata/show.erb +9 -0
  29. data/app/cells/decidim/posts/post_metadata_cell.rb +67 -0
  30. data/app/cells/decidim/posts/reaction_menu/show.erb +18 -0
  31. data/app/cells/decidim/posts/reaction_menu/styles.erb +7 -0
  32. data/app/cells/decidim/posts/reaction_menu_cell.rb +26 -0
  33. data/app/cells/decidim/posts/reactions/show.erb +8 -0
  34. data/app/cells/decidim/posts/reactions_cell.rb +22 -0
  35. data/app/commands/decidim/posts/add_reaction_to_resource.rb +90 -0
  36. data/app/commands/decidim/posts/create_post.rb +112 -0
  37. data/app/commands/decidim/posts/destroy_post.rb +20 -0
  38. data/app/commands/decidim/posts/remove_reaction_from_resource.rb +41 -0
  39. data/app/commands/decidim/posts/update_post.rb +72 -0
  40. data/app/controllers/concerns/decidim/posts/admin/filterable.rb +46 -0
  41. data/app/controllers/concerns/decidim/posts/reactionable.rb +31 -0
  42. data/app/controllers/decidim/posts/admin/application_controller.rb +26 -0
  43. data/app/controllers/decidim/posts/admin/posts_controller.rb +93 -0
  44. data/app/controllers/decidim/posts/application_controller.rb +18 -0
  45. data/app/controllers/decidim/posts/meetings_controller.rb +176 -0
  46. data/app/controllers/decidim/posts/posts_controller.rb +202 -0
  47. data/app/controllers/decidim/posts/reactions_controller.rb +54 -0
  48. data/app/controllers/decidim/posts/user_answers_controller.rb +36 -0
  49. data/app/events/decidim/posts/resource_reacted_event.rb +38 -0
  50. data/app/forms/decidim/posts/answer_form.rb +13 -0
  51. data/app/forms/decidim/posts/post_form.rb +121 -0
  52. data/app/forms/decidim/posts/question_form.rb +20 -0
  53. data/app/helpers/decidim/posts/admin/posts_helper.rb +8 -0
  54. data/app/helpers/decidim/posts/application_helper.rb +20 -0
  55. data/app/helpers/decidim/posts/post_cells_helper.rb +35 -0
  56. data/app/helpers/decidim/posts/posts_helper.rb +34 -0
  57. data/app/helpers/decidim/posts/reaction_helper.rb +22 -0
  58. data/app/models/decidim/posts/answer.rb +13 -0
  59. data/app/models/decidim/posts/application_record.rb +10 -0
  60. data/app/models/decidim/posts/post.rb +116 -0
  61. data/app/models/decidim/posts/question.rb +17 -0
  62. data/app/models/decidim/posts/reaction.rb +22 -0
  63. data/app/models/decidim/posts/reaction_type.rb +13 -0
  64. data/app/models/decidim/posts/user_answer.rb +11 -0
  65. data/app/packs/entrypoints/decidim_posts.js +5 -0
  66. data/app/packs/entrypoints/decidim_posts.scss +1 -0
  67. data/app/packs/images/decidim/posts/icon.svg +1 -0
  68. data/app/packs/src/decidim/posts/carousel.js +112 -0
  69. data/app/packs/src/decidim/posts/host_status.js +75 -0
  70. data/app/packs/src/decidim/posts/newFeeds.js +98 -0
  71. data/app/packs/src/decidim/posts/posts.js +272 -0
  72. data/app/packs/src/decidim/posts/submenu.js +46 -0
  73. data/app/packs/src/decidim/posts/survey.js +94 -0
  74. data/app/packs/stylesheets/decidim/posts/_variables.scss +10 -0
  75. data/app/packs/stylesheets/decidim/posts/posts.scss +415 -0
  76. data/app/permissions/decidim/posts/admin/permissions.rb +23 -0
  77. data/app/permissions/decidim/posts/permissions.rb +101 -0
  78. data/app/presenters/decidim/posts/post_presenter.rb +45 -0
  79. data/app/views/decidim/posts/admin/posts/_post-tr.html.erb +45 -0
  80. data/app/views/decidim/posts/admin/posts/index.html.erb +54 -0
  81. data/app/views/decidim/posts/meetings/edit.html.erb +24 -0
  82. data/app/views/decidim/posts/posts/_admin_options.html.erb +30 -0
  83. data/app/views/decidim/posts/posts/_attachment.html.erb +24 -0
  84. data/app/views/decidim/posts/posts/_edit_form.html.erb +16 -0
  85. data/app/views/decidim/posts/posts/_feed.html.erb +8 -0
  86. data/app/views/decidim/posts/posts/_form.html.erb +104 -0
  87. data/app/views/decidim/posts/posts/_index.html.erb +49 -0
  88. data/app/views/decidim/posts/posts/_meeting_form.erb +18 -0
  89. data/app/views/decidim/posts/posts/_new.html.erb +33 -0
  90. data/app/views/decidim/posts/posts/_new_survey.html.erb +20 -0
  91. data/app/views/decidim/posts/posts/_new_survey_answer.html.erb +11 -0
  92. data/app/views/decidim/posts/posts/_new_survey_question.html.erb +17 -0
  93. data/app/views/decidim/posts/posts/_post.html.erb +11 -0
  94. data/app/views/decidim/posts/posts/_post_form.html.erb +5 -0
  95. data/app/views/decidim/posts/posts/_sidebar.html.erb +36 -0
  96. data/app/views/decidim/posts/posts/edit.html.erb +34 -0
  97. data/app/views/decidim/posts/posts/index.html.erb +1 -0
  98. data/app/views/decidim/posts/posts/show.html.erb +12 -0
  99. data/app/views/decidim/posts/reactions/_update_buttons_and_counters.html.erb +1 -0
  100. data/config/assets.rb +9 -0
  101. data/config/i18n-tasks.yml +10 -0
  102. data/config/locales/bs.yml +215 -0
  103. data/config/locales/de.yml +217 -0
  104. data/config/locales/en.yml +216 -0
  105. data/config/locales/hr.yml +219 -0
  106. data/config/locales/it.yml +215 -0
  107. data/config/locales/sr.yml +220 -0
  108. data/config/locales/tr.yml +219 -0
  109. data/lib/decidim/posts/admin.rb +10 -0
  110. data/lib/decidim/posts/admin_engine.rb +25 -0
  111. data/lib/decidim/posts/component.rb +59 -0
  112. data/lib/decidim/posts/content_blocks/content_blocks_homepage.rb +19 -0
  113. data/lib/decidim/posts/engine.rb +84 -0
  114. data/lib/decidim/posts/test/factories.rb +14 -0
  115. data/lib/decidim/posts/version.rb +9 -0
  116. data/lib/decidim/posts.rb +13 -0
  117. metadata +183 -0
@@ -0,0 +1,112 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module Posts
5
+ # This command is executed when a participant or user group creates a Meeting from the public
6
+ # views.
7
+ class CreatePost < Decidim::Command
8
+ # include CurrentLocale
9
+ include ::Decidim::MultipleAttachmentsMethods
10
+
11
+ def initialize(form)
12
+ @form = form
13
+ end
14
+
15
+ def call
16
+ return broadcast(:invalid) if form.invalid?
17
+
18
+ if process_attachments?
19
+ build_attachments
20
+ return broadcast(:invalid) if attachments_invalid?
21
+ end
22
+
23
+ with_events(with_transaction: true) do
24
+ Decidim.traceability.perform_action!("create_feeds_post", Post, form.current_user) do
25
+ create_post
26
+ end
27
+
28
+ # create_attachments(weight: first_attachment_weight) if process_attachments?
29
+ create_attachments if process_attachments?
30
+ end
31
+
32
+ # create_follow_form_resource(form.current_user)
33
+ #send_notification
34
+
35
+ broadcast(:ok, post)
36
+ end
37
+
38
+ private
39
+
40
+ attr_reader :post, :form, :attachment
41
+
42
+ def event_arguments
43
+ {
44
+ resource: post,
45
+ extra: {
46
+ event_author: form.current_user,
47
+ locale:
48
+ }
49
+ }
50
+ end
51
+
52
+ def create_post
53
+ # parsed_title = Decidim::ContentProcessor.parse_with_processor(:hashtag, form.title, current_organization: form.current_organization).rewrite
54
+ # parsed_description = Decidim::ContentProcessor.parse(form.description, current_organization: form.current_organization).rewrite
55
+
56
+ @post = Decidim::Posts::Post.new(
57
+ category: form.category,
58
+ enable_comments: form.enable_comments,
59
+ body: { I18n.locale => form.body },
60
+ author: form.current_user,
61
+ component: form.current_component,
62
+ highlighted: form.highlighted,
63
+ fixed: form.fixed
64
+ )
65
+
66
+ form.questions.each do |question_form|
67
+ @post.questions.build(
68
+ title: { I18n.locale => question_form.title },
69
+ question_type: question_form.question_type,
70
+ post: @post
71
+ )
72
+ # build answers for each question
73
+ question_form.answers.each do |answer_form|
74
+ @post.questions.last.answers.build(
75
+ title: { I18n.locale => answer_form.title },
76
+ question: @post.questions.last
77
+ )
78
+ end
79
+ end
80
+ @post.save!
81
+
82
+ @attached_to = @post
83
+
84
+ @post
85
+ end
86
+
87
+ # TODO: Finish this method
88
+ # def send_notification
89
+ # Decidim::EventsManager.publish(
90
+ # event: "decidim.events.feeds.post_created",
91
+ # event_class: Decidim::Posts::CreatePostEvent,
92
+ # resource: post,
93
+ # followers: post.participatory_space.followers,
94
+ # extra: {
95
+ # participatory_space: true,
96
+ # }
97
+ # )
98
+ # end
99
+
100
+ # def create_follow_form_resource(user)
101
+ # follow_form = Decidim::FollowForm.from_params(followable_gid: post.to_signed_global_id.to_s).with_context(current_user: user)
102
+ # Decidim::CreateFollow.call(follow_form, user)
103
+ # end
104
+
105
+ def first_attachment_weight
106
+ return 1 if post.documents.count.zero?
107
+
108
+ post.documents.count
109
+ end
110
+ end
111
+ end
112
+ end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module Posts
5
+ class DestroyPost < Decidim::Command
6
+ def initialize(post, current_user)
7
+ @post = post
8
+ @current_user = current_user
9
+ end
10
+
11
+ def call
12
+ return broadcast(:invalid) unless @post.authored_by?(@current_user) || @current_user.admin?
13
+
14
+ @post.destroy!
15
+
16
+ broadcast(:ok, @post)
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,41 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module Posts
5
+ # A command with all the business logic to remove a reaction from a resource, both as a user or as a user_group.
6
+ class RemoveReactionFromResource < Decidim::Command
7
+ # Public: Initializes the command.
8
+ #
9
+ # resource - A Decidim::Posts::Reactionable object.
10
+ # current_user - The current user.
11
+ # current_group- (optional) The current_group that is unendorsing the Resource.
12
+ def initialize(resource, current_user, current_group = nil)
13
+ @resource = resource
14
+ @current_user = current_user
15
+ @current_group = current_group
16
+ end
17
+
18
+ # Executes the command. Broadcasts these events:
19
+ #
20
+ # - :ok when everything is valid, together with the resource.
21
+ # - :invalid if the form was not valid and we could not proceed.
22
+ #
23
+ # Returns nothing.
24
+ def call
25
+ destroy_resource_reaction
26
+ broadcast(:ok, @resource)
27
+ end
28
+
29
+ private
30
+
31
+ def destroy_resource_reaction
32
+ query = if @current_group.present?
33
+ @resource.reactions.where(decidim_user_group_id: @current_group&.id)
34
+ else
35
+ @resource.reactions.where(author: @current_user, decidim_user_group_id: 0)
36
+ end
37
+ query.destroy_all
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,72 @@
1
+ module Decidim
2
+ module Posts
3
+ class UpdatePost < Decidim::Command
4
+ include ::Decidim::MultipleAttachmentsMethods
5
+
6
+ def initialize(form, current_user, post)
7
+ @form = form
8
+ @current_user = current_user
9
+ @post = post
10
+ @attached_to = post
11
+ end
12
+
13
+ def call
14
+ return broadcast(:invalid) if invalid?
15
+
16
+ if process_attachments?
17
+ build_attachments
18
+ return broadcast(:invalid) if attachments_invalid?
19
+ end
20
+
21
+ with_events(with_transaction: true) do
22
+ #Decidim.traceability.perform_action!("update_feeds_post", Post, form.current_user) do
23
+ update_post
24
+ #end
25
+ document_cleanup!(include_all_attachments: true)
26
+ create_attachments if process_attachments?
27
+ end
28
+
29
+
30
+ broadcast(:ok, @post)
31
+ end
32
+
33
+ private
34
+
35
+ attr_reader :post, :form, :current_user, :attachment
36
+
37
+ def event_arguments
38
+ {
39
+ resource: @post,
40
+ extra: {
41
+ event_author: form.current_user,
42
+ locale:
43
+ }
44
+ }
45
+ end
46
+
47
+ def invalid?
48
+ form.invalid? || !@post.editable_by?(current_user)
49
+ end
50
+
51
+ def update_post
52
+ @post = Decidim.traceability.update!(
53
+ @post,
54
+ current_user,
55
+ attributes,
56
+ visibility: "public-only"
57
+ )
58
+ end
59
+
60
+ def attributes
61
+ {
62
+ category: form.category,
63
+ body: { I18n.locale => form.body },
64
+ enable_comments: form.enable_comments,
65
+ highlighted: form.highlighted,
66
+ fixed: form.fixed
67
+ }
68
+ end
69
+ end
70
+ end
71
+ end
72
+
@@ -0,0 +1,46 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "active_support/concern"
4
+
5
+ module Decidim
6
+ module Posts
7
+ module Admin
8
+ module Filterable
9
+ extend ActiveSupport::Concern
10
+
11
+ included do
12
+ include Decidim::Admin::Filterable
13
+
14
+ private
15
+
16
+ # Comment about participatory_texts_enabled.
17
+ def base_query
18
+ return collection
19
+ end
20
+
21
+ def search_field_predicate
22
+ :id_string_or_title_cont
23
+ end
24
+
25
+ def filters
26
+ [
27
+ # :category_eq
28
+ ]
29
+ end
30
+
31
+ def filters_with_values
32
+ {
33
+ # category_eq: category_ids_hash(categories.first_class)
34
+ }
35
+ end
36
+
37
+ # Cannot user `super` here, because it does not belong to a superclass
38
+ # but to a concern.
39
+ # def dynamically_translated_filters
40
+ # [:scope_id_eq, :category_id_eq, :valuator_role_ids_has]
41
+ # end
42
+ end
43
+ end
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ # This concern contains the logic related with resources that can be reacted to.
5
+ # Thus, it is expected to be included into a resource that is wanted to be reactionable.
6
+ # This resource will have many `Decidim::Posts::Reactions.
7
+ module Posts
8
+ module Reactionable
9
+ extend ActiveSupport::Concern
10
+
11
+ included do
12
+ has_many :reactions,
13
+ as: :resource,
14
+ dependent: :destroy,
15
+ counter_cache: "reactions_count"
16
+
17
+ # Public: Check if the user has reacted to the resource.
18
+ # - user_group: may be nil if user is not representing any user_group.
19
+ #
20
+ # Returns Boolean.
21
+ def reacted_by?(user, user_group = nil)
22
+ if user_group
23
+ reactions.where(user_group:).any?
24
+ else
25
+ reactions.where(author: user, user_group: 0).any?
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module Posts
5
+ module Admin
6
+ # This controller is the abstract class from which all other controllers of
7
+ # this engine inherit.
8
+ #
9
+ # Note that it inherits from `Decidim::Admin::Components::BaseController`, which
10
+ # override its layout and provide all kinds of useful methods.
11
+ class ApplicationController < Decidim::Admin::Components::BaseController
12
+ def permission_class_chain
13
+ [::Decidim::Posts::Admin::Permissions] + super
14
+ end
15
+
16
+ def user_not_authorized_path
17
+ decidim.root_path
18
+ end
19
+
20
+ def user_has_no_permission_path
21
+ decidim.root_path
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,93 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module Posts
5
+ module Admin
6
+ # This controller allows admins to manage posts in a participatory space.
7
+ class PostsController < Admin::ApplicationController
8
+ include Decidim::ApplicationHelper
9
+ include Decidim::Posts::Admin::Filterable
10
+
11
+ helper Feeds::ApplicationHelper
12
+ # helper Decidim::Messaging::ConversationHelper
13
+ helper_method :posts, :query, :form_presenter, :post, :post_ids, :present
14
+
15
+ def index
16
+ end
17
+
18
+ def show
19
+ end
20
+
21
+ def new
22
+ enforce_permission_to :create, :post
23
+ # @form = form(Decidim::Posts::Admin::PostForm).from_params(
24
+ # attachment: form(AttachmentForm).from_params({})
25
+ # )
26
+ end
27
+
28
+ def create
29
+ enforce_permission_to :create, :post
30
+ @form = form(Decidim::Posts::Admin::PostForm).from_params(params)
31
+
32
+ Admin::CreatePost.call(@form) do
33
+ on(:ok) do
34
+ flash[:notice] = I18n.t("posts.create.success", scope: "decidim.posts.admin")
35
+ redirect_to posts_path
36
+ end
37
+
38
+ on(:invalid) do
39
+ flash.now[:alert] = I18n.t("posts.create.invalid", scope: "decidim.posts.admin")
40
+ render action: "new"
41
+ end
42
+ end
43
+ end
44
+
45
+ def edit
46
+ enforce_permission_to(:edit, :post, post:)
47
+ @form = form(Admin::PostForm).from_model(post)
48
+ end
49
+
50
+ def update
51
+ enforce_permission_to(:edit, :post, post:)
52
+
53
+ @form = form(Admin::PostForm).from_params(params)
54
+
55
+ Admin::UpdatePost.call(@form, @post) do
56
+ on(:ok) do |_post|
57
+ flash[:notice] = t("feeds.update.success", scope: "decidim")
58
+ redirect_to posts_path
59
+ end
60
+
61
+ on(:invalid) do
62
+ flash.now[:alert] = t("feeds.update.error", scope: "decidim")
63
+ render :edit
64
+ end
65
+ end
66
+ end
67
+
68
+ private
69
+
70
+ def collection
71
+ @collection ||= Post.where(component: current_component)#.not_hidden
72
+ end
73
+
74
+ def posts
75
+ # @posts ||= filtered_collection
76
+ @posts ||= collection
77
+ end
78
+
79
+ def post
80
+ @post ||= collection.find(params[:id])
81
+ end
82
+
83
+ def post_ids
84
+ @post_ids ||= params[:post_ids]
85
+ end
86
+
87
+ def form_presenter
88
+ @form_presenter ||= present(@form, presenter_class: Decidim::Posts::PostPresenter)
89
+ end
90
+ end
91
+ end
92
+ end
93
+ end
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module Posts
5
+ # This controller is the abstract class from which all other controllers of
6
+ # this engine inherit.
7
+ #
8
+ # Note that it inherits from `Decidim::Components::BaseController`, which
9
+ # override its layout and provide all kinds of useful methods.
10
+ class ApplicationController < Decidim::Components::BaseController
11
+ helper Decidim::Posts::ApplicationHelper
12
+
13
+ def user_has_no_permission_path
14
+ decidim.new_user_session_path
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,176 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module Posts
5
+ # Exposes the meeting resource so users can view them
6
+ class MeetingsController < Decidim::Posts::ApplicationController
7
+ # include FilterResource
8
+ # include ComponentFilterable
9
+ include Flaggable
10
+ include Withdrawable
11
+ include FormFactory
12
+ # include Paginable
13
+
14
+ helper Decidim::ResourceVersionsHelper
15
+ helper Decidim::ShortLinkHelper
16
+ include Decidim::AttachmentsHelper
17
+
18
+ helper_method :meetings, :meeting, :registration, :search, :nav_paths, :tab_panel_items
19
+
20
+ before_action :add_addtional_csp_directives, only: [:show]
21
+
22
+ def new
23
+ enforce_permission_to :create, :meeting
24
+
25
+ @form = meeting_form.instance
26
+ end
27
+
28
+ def create
29
+ enforce_permission_to :create, :meeting
30
+
31
+ # Duplicate location to address field
32
+ params[:meeting][:address] = params[:meeting][:location] if params[:meeting][:address].blank?
33
+
34
+ @form = meeting_form.from_params(params, current_component: meetings_component)
35
+
36
+ Decidim::Meetings::CreateMeeting.call(@form) do
37
+ on(:ok) do |meeting|
38
+ flash[:notice] = I18n.t("meetings.create.success", scope: "decidim.meetings")
39
+ redirect_to posts_path
40
+ end
41
+
42
+ on(:invalid) do
43
+ flash.now[:alert] = I18n.t("meetings.create.invalid", scope: "decidim.meetings")
44
+ redirect_to posts_path
45
+ end
46
+ end
47
+ end
48
+
49
+ def edit
50
+ enforce_permission_to(:update, :meeting, meeting:)
51
+
52
+ @context = {
53
+ current_organization: @controller.try(:current_organization),
54
+ current_component: @controller.try(:current_component),
55
+ current_user: @controller.try(:current_user),
56
+ current_participatory_space: @controller.try(:current_participatory_space)
57
+ }
58
+ @feeds_component = current_component.participatory_space.components.find_by(manifest_name: "posts")
59
+ @target_participatory_space = @feeds_component.participatory_space
60
+ @form = meeting_form.from_model(meeting).with_context(@context)
61
+ end
62
+
63
+ def update
64
+ enforce_permission_to(:update, :meeting, meeting:)
65
+
66
+ @form = meeting_form.from_params(params)
67
+
68
+ Decidim::Meetings::UpdateMeeting.call(@form, current_user, meeting) do
69
+ on(:ok) do |meeting|
70
+ flash[:notice] = I18n.t("meetings.update.success", scope: "decidim.meetings")
71
+ redirect_to posts_path
72
+ end
73
+
74
+ on(:invalid) do
75
+ flash.now[:alert] = I18n.t("meetings.update.invalid", scope: "decidim.meetings")
76
+ render :edit
77
+ end
78
+ end
79
+ end
80
+
81
+ def withdraw
82
+ enforce_permission_to(:withdraw, :meeting, meeting:)
83
+
84
+ Decidim::Meetings::WithdrawMeeting.call(@meeting, current_user) do
85
+ on(:ok) do
86
+ flash[:notice] = I18n.t("meetings.withdraw.success", scope: "decidim")
87
+ redirect_to posts_path
88
+ end
89
+ on(:invalid) do
90
+ flash[:alert] = I18n.t("meetings.withdraw.error", scope: "decidim")
91
+ redirect_to posts_path
92
+ end
93
+ end
94
+ end
95
+
96
+ private
97
+
98
+ def meeting
99
+ @meeting ||= Decidim::Meetings::Meeting.not_hidden.where(component: current_component.participatory_space.components.find_by(manifest_name: "meetings")).find_by(id: params[:id])
100
+ end
101
+
102
+ def nav_paths
103
+ return {} if meeting.blank?
104
+
105
+ { prev_path: prev_meeting, next_path: next_meeting }.compact_blank.transform_values { |meeting| meeting_path(meeting) }
106
+ end
107
+
108
+ def meetings
109
+ is_past_meetings = params.dig("filter", "with_any_date")&.include?("past")
110
+ @meetings ||= paginate(search.result.order(start_time: is_past_meetings ? :desc : :asc))
111
+ end
112
+
113
+ def registration
114
+ @registration ||= meeting.registrations.find_by(user: current_user)
115
+ end
116
+
117
+ def search_collection
118
+ Decidim::Meetings::Meeting.where(component: current_component).published.not_hidden.visible_for(current_user).with_availability(
119
+ filter_params[:with_availability]
120
+ ).includes(
121
+ :component,
122
+ attachments: :file_attachment
123
+ )
124
+ end
125
+
126
+ def participatory_space
127
+ @participatory_space ||= current_component.participatory_space
128
+ end
129
+
130
+ def meetings_component
131
+ @meetings_component ||= participatory_space.components.find_by(manifest_name: "meetings")
132
+ end
133
+
134
+ def meeting_form
135
+ form(Decidim::Meetings::MeetingForm)
136
+ end
137
+
138
+ def tab_panel_items
139
+ @tab_panel_items ||= [
140
+ {
141
+ enabled: meeting.public_participants.any?,
142
+ id: "participants",
143
+ text: t("attending_participants", scope: "decidim.meetings.public_participants_list"),
144
+ icon: "group-line",
145
+ method: :cell,
146
+ args: ["decidim/meetings/public_participants_list", meeting]
147
+ },
148
+ {
149
+ enabled: !meeting.closed? && meeting.user_group_registrations.any?,
150
+ id: "organizations",
151
+ text: t("attending_organizations", scope: "decidim.meetings.public_participants_list"),
152
+ icon: "community-line",
153
+ method: :cell,
154
+ args: ["decidim/meetings/attending_organizations_list", meeting]
155
+ },
156
+ {
157
+ enabled: meeting.linked_resources(:proposals, "proposals_from_meeting").present?,
158
+ id: "included_proposals",
159
+ text: t("decidim/proposals/proposal", scope: "activerecord.models", count: 2),
160
+ icon: resource_type_icon_key("Decidim::Proposals::Proposal"),
161
+ method: :cell,
162
+ args: ["decidim/linked_resources_for", meeting, { type: :proposals, link_name: "proposals_from_meeting" }]
163
+ },
164
+ {
165
+ enabled: meeting.linked_resources(:results, "meetings_through_proposals").present?,
166
+ id: "included_meetings",
167
+ text: t("decidim/accountability/result", scope: "activerecord.models", count: 2),
168
+ icon: resource_type_icon_key("Decidim::Accountability::Result"),
169
+ method: :cell,
170
+ args: ["decidim/linked_resources_for", meeting, { type: :results, link_name: "meetings_through_proposals" }]
171
+ }
172
+ ] + attachments_tab_panel_items(@meeting)
173
+ end
174
+ end
175
+ end
176
+ end