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.
- checksums.yaml +7 -0
- data/LICENSE-AGPLv3.txt +661 -0
- data/README.md +40 -0
- data/Rakefile +9 -0
- data/app/cells/decidim/posts/comments/add_comment.erb +15 -0
- data/app/cells/decidim/posts/comments/comments_loading.erb +1 -0
- data/app/cells/decidim/posts/comments/order_control.erb +13 -0
- data/app/cells/decidim/posts/comments/show.erb +31 -0
- data/app/cells/decidim/posts/comments_cell.rb +158 -0
- data/app/cells/decidim/posts/content_blocks/posts/show.erb +3 -0
- data/app/cells/decidim/posts/content_blocks/posts_cell.rb +50 -0
- data/app/cells/decidim/posts/content_blocks/posts_settings_form/show.erb +3 -0
- data/app/cells/decidim/posts/content_blocks/posts_settings_form_cell.rb +23 -0
- data/app/cells/decidim/posts/feed_dropdown_metadata_cell.rb +19 -0
- data/app/cells/decidim/posts/meeting/show.erb +65 -0
- data/app/cells/decidim/posts/meeting_cell.rb +44 -0
- data/app/cells/decidim/posts/post/show.erb +30 -0
- data/app/cells/decidim/posts/post/survey.erb +68 -0
- data/app/cells/decidim/posts/post_attachments/show.erb +40 -0
- data/app/cells/decidim/posts/post_attachments_cell.rb +17 -0
- data/app/cells/decidim/posts/post_cell.rb +44 -0
- data/app/cells/decidim/posts/post_comment/show.erb +17 -0
- data/app/cells/decidim/posts/post_comment_cell.rb +49 -0
- data/app/cells/decidim/posts/post_header/show.erb +53 -0
- data/app/cells/decidim/posts/post_header_cell.rb +79 -0
- data/app/cells/decidim/posts/post_host/show.erb +74 -0
- data/app/cells/decidim/posts/post_host_cell.rb +73 -0
- data/app/cells/decidim/posts/post_metadata/show.erb +9 -0
- data/app/cells/decidim/posts/post_metadata_cell.rb +67 -0
- data/app/cells/decidim/posts/reaction_menu/show.erb +18 -0
- data/app/cells/decidim/posts/reaction_menu/styles.erb +7 -0
- data/app/cells/decidim/posts/reaction_menu_cell.rb +26 -0
- data/app/cells/decidim/posts/reactions/show.erb +8 -0
- data/app/cells/decidim/posts/reactions_cell.rb +22 -0
- data/app/commands/decidim/posts/add_reaction_to_resource.rb +90 -0
- data/app/commands/decidim/posts/create_post.rb +112 -0
- data/app/commands/decidim/posts/destroy_post.rb +20 -0
- data/app/commands/decidim/posts/remove_reaction_from_resource.rb +41 -0
- data/app/commands/decidim/posts/update_post.rb +72 -0
- data/app/controllers/concerns/decidim/posts/admin/filterable.rb +46 -0
- data/app/controllers/concerns/decidim/posts/reactionable.rb +31 -0
- data/app/controllers/decidim/posts/admin/application_controller.rb +26 -0
- data/app/controllers/decidim/posts/admin/posts_controller.rb +93 -0
- data/app/controllers/decidim/posts/application_controller.rb +18 -0
- data/app/controllers/decidim/posts/meetings_controller.rb +176 -0
- data/app/controllers/decidim/posts/posts_controller.rb +202 -0
- data/app/controllers/decidim/posts/reactions_controller.rb +54 -0
- data/app/controllers/decidim/posts/user_answers_controller.rb +36 -0
- data/app/events/decidim/posts/resource_reacted_event.rb +38 -0
- data/app/forms/decidim/posts/answer_form.rb +13 -0
- data/app/forms/decidim/posts/post_form.rb +121 -0
- data/app/forms/decidim/posts/question_form.rb +20 -0
- data/app/helpers/decidim/posts/admin/posts_helper.rb +8 -0
- data/app/helpers/decidim/posts/application_helper.rb +20 -0
- data/app/helpers/decidim/posts/post_cells_helper.rb +35 -0
- data/app/helpers/decidim/posts/posts_helper.rb +34 -0
- data/app/helpers/decidim/posts/reaction_helper.rb +22 -0
- data/app/models/decidim/posts/answer.rb +13 -0
- data/app/models/decidim/posts/application_record.rb +10 -0
- data/app/models/decidim/posts/post.rb +116 -0
- data/app/models/decidim/posts/question.rb +17 -0
- data/app/models/decidim/posts/reaction.rb +22 -0
- data/app/models/decidim/posts/reaction_type.rb +13 -0
- data/app/models/decidim/posts/user_answer.rb +11 -0
- data/app/packs/entrypoints/decidim_posts.js +5 -0
- data/app/packs/entrypoints/decidim_posts.scss +1 -0
- data/app/packs/images/decidim/posts/icon.svg +1 -0
- data/app/packs/src/decidim/posts/carousel.js +112 -0
- data/app/packs/src/decidim/posts/host_status.js +75 -0
- data/app/packs/src/decidim/posts/newFeeds.js +98 -0
- data/app/packs/src/decidim/posts/posts.js +272 -0
- data/app/packs/src/decidim/posts/submenu.js +46 -0
- data/app/packs/src/decidim/posts/survey.js +94 -0
- data/app/packs/stylesheets/decidim/posts/_variables.scss +10 -0
- data/app/packs/stylesheets/decidim/posts/posts.scss +415 -0
- data/app/permissions/decidim/posts/admin/permissions.rb +23 -0
- data/app/permissions/decidim/posts/permissions.rb +101 -0
- data/app/presenters/decidim/posts/post_presenter.rb +45 -0
- data/app/views/decidim/posts/admin/posts/_post-tr.html.erb +45 -0
- data/app/views/decidim/posts/admin/posts/index.html.erb +54 -0
- data/app/views/decidim/posts/meetings/edit.html.erb +24 -0
- data/app/views/decidim/posts/posts/_admin_options.html.erb +30 -0
- data/app/views/decidim/posts/posts/_attachment.html.erb +24 -0
- data/app/views/decidim/posts/posts/_edit_form.html.erb +16 -0
- data/app/views/decidim/posts/posts/_feed.html.erb +8 -0
- data/app/views/decidim/posts/posts/_form.html.erb +104 -0
- data/app/views/decidim/posts/posts/_index.html.erb +49 -0
- data/app/views/decidim/posts/posts/_meeting_form.erb +18 -0
- data/app/views/decidim/posts/posts/_new.html.erb +33 -0
- data/app/views/decidim/posts/posts/_new_survey.html.erb +20 -0
- data/app/views/decidim/posts/posts/_new_survey_answer.html.erb +11 -0
- data/app/views/decidim/posts/posts/_new_survey_question.html.erb +17 -0
- data/app/views/decidim/posts/posts/_post.html.erb +11 -0
- data/app/views/decidim/posts/posts/_post_form.html.erb +5 -0
- data/app/views/decidim/posts/posts/_sidebar.html.erb +36 -0
- data/app/views/decidim/posts/posts/edit.html.erb +34 -0
- data/app/views/decidim/posts/posts/index.html.erb +1 -0
- data/app/views/decidim/posts/posts/show.html.erb +12 -0
- data/app/views/decidim/posts/reactions/_update_buttons_and_counters.html.erb +1 -0
- data/config/assets.rb +9 -0
- data/config/i18n-tasks.yml +10 -0
- data/config/locales/bs.yml +215 -0
- data/config/locales/de.yml +217 -0
- data/config/locales/en.yml +216 -0
- data/config/locales/hr.yml +219 -0
- data/config/locales/it.yml +215 -0
- data/config/locales/sr.yml +220 -0
- data/config/locales/tr.yml +219 -0
- data/lib/decidim/posts/admin.rb +10 -0
- data/lib/decidim/posts/admin_engine.rb +25 -0
- data/lib/decidim/posts/component.rb +59 -0
- data/lib/decidim/posts/content_blocks/content_blocks_homepage.rb +19 -0
- data/lib/decidim/posts/engine.rb +84 -0
- data/lib/decidim/posts/test/factories.rb +14 -0
- data/lib/decidim/posts/version.rb +9 -0
- data/lib/decidim/posts.rb +13 -0
- metadata +183 -0
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# require_dependency "decidim/posts/application_controller"
|
|
4
|
+
|
|
5
|
+
module Decidim
|
|
6
|
+
module Posts
|
|
7
|
+
class PostsController < Decidim::Posts::ApplicationController
|
|
8
|
+
include Decidim::ApplicationHelper
|
|
9
|
+
include FormFactory
|
|
10
|
+
include Flaggable
|
|
11
|
+
include Decidim::AttachmentsHelper
|
|
12
|
+
|
|
13
|
+
helper_method :post_presenter, :form_presenter
|
|
14
|
+
|
|
15
|
+
def index
|
|
16
|
+
enforce_permission_to :read, :post
|
|
17
|
+
|
|
18
|
+
@posts = posts(filter_post_category).where(fixed: [false, nil])
|
|
19
|
+
@fixed_posts = posts.where(fixed: true).order(created_at: :desc)
|
|
20
|
+
|
|
21
|
+
@meetings = meetings(filter_post_category)
|
|
22
|
+
|
|
23
|
+
@non_fixed_objects = (@posts + @meetings).sort_by(&:created_at).reverse
|
|
24
|
+
@non_fixed_objects = Kaminari.paginate_array(@non_fixed_objects).page(params[:page]).per(20)
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
# action to load more posts and meetings on the index page via ajax
|
|
28
|
+
def load_more
|
|
29
|
+
enforce_permission_to :read, :post
|
|
30
|
+
|
|
31
|
+
@posts = posts(filter_post_category).where(fixed: false)
|
|
32
|
+
@meetings = meetings(filter_post_category)
|
|
33
|
+
|
|
34
|
+
@non_fixed_objects = (@posts + @meetings).sort_by(&:created_at).reverse
|
|
35
|
+
@non_fixed_objects = Kaminari.paginate_array(@non_fixed_objects).page(params[:page]).per(20)
|
|
36
|
+
|
|
37
|
+
render partial: "decidim/posts/posts/feed", locals: { objects: @non_fixed_objects }
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def show
|
|
41
|
+
@post = Post.find(params[:id])
|
|
42
|
+
|
|
43
|
+
enforce_permission_to :read, :post
|
|
44
|
+
|
|
45
|
+
raise ActionController::RoutingError, "Not Found" unless @post
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def new
|
|
49
|
+
enforce_permission_to :create, :post
|
|
50
|
+
@form = form(PostForm).from_params(post_creation_params)
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def create
|
|
54
|
+
enforce_permission_to :create, :post
|
|
55
|
+
|
|
56
|
+
@form = form(PostForm).from_params(post_creation_params)
|
|
57
|
+
|
|
58
|
+
CreatePost.call(@form) do
|
|
59
|
+
on(:ok) do |post|
|
|
60
|
+
flash[:notice] = I18n.t("posts.create.success", scope: "decidim.posts")
|
|
61
|
+
# TODO: implement javascript to create a new post without reloading the page
|
|
62
|
+
# redirect_to decidim.root_path
|
|
63
|
+
# redirect_to current_component_path
|
|
64
|
+
redirect_to posts_path
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
on(:invalid) do
|
|
68
|
+
flash.now[:alert] = I18n.t("posts.create.invalid", scope: "decidim.posts")
|
|
69
|
+
redirect_to posts_path
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
def edit
|
|
75
|
+
@post = Post.find(params[:id])
|
|
76
|
+
enforce_permission_to :edit, :post, post: @post
|
|
77
|
+
@form = Decidim::Posts::PostForm.from_model(@post).with_context(context)
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
def update
|
|
81
|
+
@post = Post.find(params[:id])
|
|
82
|
+
enforce_permission_to :edit, :post, post: @post
|
|
83
|
+
|
|
84
|
+
@form = form(PostForm).from_params(params)
|
|
85
|
+
UpdatePost.call(@form, current_user, @post) do
|
|
86
|
+
on(:ok) do |post|
|
|
87
|
+
flash[:notice] = I18n.t("posts.update.success", scope: "decidim.posts")
|
|
88
|
+
redirect_to posts_path
|
|
89
|
+
# redirect_to Decidim::ResourceLocatorPresenter.new(@post).path
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
on(:invalid) do
|
|
93
|
+
flash.now[:alert] = I18n.t("posts.update.invalid", scope: "decidim.posts")
|
|
94
|
+
render :edit
|
|
95
|
+
end
|
|
96
|
+
end
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
def destroy
|
|
100
|
+
@post = Post.find(params[:id])
|
|
101
|
+
enforce_permission_to :delete, :post, post: @post
|
|
102
|
+
|
|
103
|
+
DestroyPost.call(@post, current_user) do
|
|
104
|
+
on(:ok) do
|
|
105
|
+
flash[:notice] = I18n.t("posts.destroy.success", scope: "decidim.posts")
|
|
106
|
+
redirect_to posts_path
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
on(:invalid) do
|
|
110
|
+
flash.now[:alert] = I18n.t("posts.destroy.invalid", scope: "decidim.posts")
|
|
111
|
+
redirect_to posts_path
|
|
112
|
+
end
|
|
113
|
+
end
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
def change_status
|
|
117
|
+
@post = Decidim::Posts::Post.find(params[:id])
|
|
118
|
+
# enable_comments: params[:status] ? true : false
|
|
119
|
+
if @post.update(status: params[:status], enable_comments: false)
|
|
120
|
+
render json: { message: 'Status updated successfully', new_content: cell("decidim/posts/post_host", @post).call(:show) }, status: :ok
|
|
121
|
+
else
|
|
122
|
+
render json: { error: 'Failed to update status' }, status: :unprocessable_entity
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
private
|
|
128
|
+
|
|
129
|
+
def post_categories
|
|
130
|
+
["post", "host", "calendar", "survey", "sharecare"]
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
def allowed_post_categories
|
|
134
|
+
["all"] + post_categories
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
def default_filter_post_category
|
|
138
|
+
return "host" if current_user.admin?
|
|
139
|
+
|
|
140
|
+
"all"
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
def filter_post_category
|
|
144
|
+
allowed_post_categories.include?(params[:filter_post_category]) ? params[:filter_post_category] : default_filter_post_category
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
def posts(filter_category=nil)
|
|
148
|
+
category = filter_category == "all" ? nil : filter_category
|
|
149
|
+
|
|
150
|
+
Decidim::Posts::Post
|
|
151
|
+
.where(decidim_component_id: current_component.id)
|
|
152
|
+
.filter_category(category)
|
|
153
|
+
.order(created_at: :desc)
|
|
154
|
+
.includes(:attachments)
|
|
155
|
+
end
|
|
156
|
+
|
|
157
|
+
def meetings(filter_category=nil)
|
|
158
|
+
category = filter_category == "all" ? nil : filter_category
|
|
159
|
+
|
|
160
|
+
if category.blank? || category == 'calendar'
|
|
161
|
+
meetings_component.blank? ? [] : Decidim::Meetings::Meeting.where(component: meetings_component).published.except_withdrawn
|
|
162
|
+
else
|
|
163
|
+
[]
|
|
164
|
+
end
|
|
165
|
+
end
|
|
166
|
+
|
|
167
|
+
def post_presenter
|
|
168
|
+
@post_presenter ||= present(@post)
|
|
169
|
+
end
|
|
170
|
+
|
|
171
|
+
def form_presenter
|
|
172
|
+
@form_presenter ||= present(@form, presenter_class: Decidim::Posts::PostPresenter)
|
|
173
|
+
end
|
|
174
|
+
|
|
175
|
+
def post_creation_params
|
|
176
|
+
params[:post]
|
|
177
|
+
end
|
|
178
|
+
|
|
179
|
+
def participatory_space
|
|
180
|
+
@participatory_space ||= current_component.participatory_space
|
|
181
|
+
end
|
|
182
|
+
|
|
183
|
+
def meetings_component
|
|
184
|
+
@meetings_component ||= participatory_space.components.find_by(manifest_name: "meetings")
|
|
185
|
+
end
|
|
186
|
+
|
|
187
|
+
# def meeting_form
|
|
188
|
+
# form(Decidim::Meetings::MeetingForm).from_params(params)
|
|
189
|
+
# end
|
|
190
|
+
|
|
191
|
+
def context
|
|
192
|
+
{
|
|
193
|
+
current_component: current_component,
|
|
194
|
+
current_organization: current_component.organization,
|
|
195
|
+
current_user:,
|
|
196
|
+
current_participatory_space: participatory_space
|
|
197
|
+
}
|
|
198
|
+
end
|
|
199
|
+
|
|
200
|
+
end
|
|
201
|
+
end
|
|
202
|
+
end
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Decidim
|
|
4
|
+
module Posts
|
|
5
|
+
class ReactionsController < Decidim::Components::BaseController
|
|
6
|
+
before_action :authenticate_user!
|
|
7
|
+
|
|
8
|
+
def create
|
|
9
|
+
enforce_permission_to(:create, :reaction, resource:)
|
|
10
|
+
|
|
11
|
+
reaction_type_id = params[:reaction_type_id]
|
|
12
|
+
user_group_id = params[:user_group_id]
|
|
13
|
+
|
|
14
|
+
AddReactionToResource.call(resource, current_user, user_group_id, reaction_type_id) do
|
|
15
|
+
on(:ok) do
|
|
16
|
+
resource.reload
|
|
17
|
+
render partial: "update_buttons_and_counters", locals: { resource: resource }
|
|
18
|
+
#render json: { success: true, reaction_type: @reaction.reaction_type }, status: :ok
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
on(:invalid) do
|
|
22
|
+
render json: { error: I18n.t("resource_reactions.create.error", scope: "decidim") }, status: :unprocessable_entity
|
|
23
|
+
#render json: { success: false, errors: @reaction.errors.full_messages }, status: :unprocessable_entity
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def destroy
|
|
29
|
+
enforce_permission_to(:withdraw, :reaction, resource:)
|
|
30
|
+
|
|
31
|
+
user_group_id = params[:user_group_id]
|
|
32
|
+
user_group = user_groups.find(user_group_id) if user_group_id
|
|
33
|
+
|
|
34
|
+
RemoveReactionFromResource.call(resource, current_user, user_group) do
|
|
35
|
+
on(:ok) do
|
|
36
|
+
resource.reload
|
|
37
|
+
render :update_buttons_and_counters
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
private
|
|
43
|
+
|
|
44
|
+
def resource
|
|
45
|
+
gid_param = params[:id] || params[:resource_id]
|
|
46
|
+
@resource ||= GlobalID::Locator.locate(GlobalID.parse(gid_param))
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def user_groups
|
|
50
|
+
Decidim::UserGroups::ManageableUserGroups.for(current_user).verified
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
end
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
# app/controllers/decidim/posts/user_answers_controller.rb
|
|
2
|
+
module Decidim
|
|
3
|
+
module Posts
|
|
4
|
+
class UserAnswersController < ApplicationController
|
|
5
|
+
|
|
6
|
+
def create
|
|
7
|
+
answer_id = params[:answer_id].to_i
|
|
8
|
+
checked = params[:checked].to_s.downcase == "true" ? true : false
|
|
9
|
+
|
|
10
|
+
answer = Answer.find(answer_id)
|
|
11
|
+
|
|
12
|
+
if checked
|
|
13
|
+
if answer.question.single_choice?
|
|
14
|
+
UserAnswer.where(decidim_user_id: current_user.id, decidim_posts_answer_id: answer.question.answers.pluck(:id)).destroy_all
|
|
15
|
+
end
|
|
16
|
+
UserAnswer.find_or_create_by(decidim_user_id: current_user.id, decidim_posts_answer_id: answer_id)
|
|
17
|
+
else
|
|
18
|
+
UserAnswer.where(decidim_user_id: current_user.id, decidim_posts_answer_id: answer_id).destroy_all
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
# get count of user_answers for all answers of the question
|
|
22
|
+
user_answers_counts = {}
|
|
23
|
+
answer.question.answers.each do |a|
|
|
24
|
+
user_answers_counts[a.id] = UserAnswer.where(decidim_posts_answer_id: a.id).count
|
|
25
|
+
end
|
|
26
|
+
result = {
|
|
27
|
+
user_answers: user_answers_counts,
|
|
28
|
+
survey_responses_count: answer.question.post.survey_responses_count
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
render json: result, status: :ok
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Decidim
|
|
4
|
+
module Posts
|
|
5
|
+
class ResourceReactedEvent < Decidim::Events::SimpleEvent
|
|
6
|
+
i18n_attributes :reactor_nickname, :reactor_name, :reactor_path, :nickname, :resource_type
|
|
7
|
+
|
|
8
|
+
delegate :nickname, :name, to: :reactor, prefix: true
|
|
9
|
+
|
|
10
|
+
def nickname
|
|
11
|
+
reactor_nickname
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def reactor_path
|
|
15
|
+
reactor.profile_path
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def resource_text
|
|
19
|
+
return resource.body if resource.respond_to? :body
|
|
20
|
+
return resource.description if resource.respond_to? :description
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def resource_type
|
|
24
|
+
resource.class.model_name.human
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
private
|
|
28
|
+
|
|
29
|
+
def reactor
|
|
30
|
+
@reactor ||= Decidim::UserPresenter.new(reactor_user)
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def reactor_user
|
|
34
|
+
@reactor_user ||= Decidim::User.find_by(id: extra[:reactor_id])
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Decidim
|
|
4
|
+
module Posts
|
|
5
|
+
class PostForm < Decidim::Form
|
|
6
|
+
include Decidim::TranslatableAttributes
|
|
7
|
+
include Decidim::AttachmentAttributes
|
|
8
|
+
# include Decidim::HasUploadValidations # should be included by AttachmentForm
|
|
9
|
+
|
|
10
|
+
mimic :post
|
|
11
|
+
|
|
12
|
+
#attribute :body, Decidim::Attributes::CleanString
|
|
13
|
+
# attribute :body, String
|
|
14
|
+
attribute :body, Decidim::Attributes::CleanString
|
|
15
|
+
attribute :category, String
|
|
16
|
+
attribute :enable_comments, Boolean, default: true
|
|
17
|
+
#attribute :body_template, String
|
|
18
|
+
#attribute :user_group_id, Integer
|
|
19
|
+
#attribute :category_id, Integer
|
|
20
|
+
#attribute :scope_id, Integer
|
|
21
|
+
attribute :attachment, AttachmentForm
|
|
22
|
+
#attribute :suggested_hashtags, Array[String]
|
|
23
|
+
attribute :questions, Array[QuestionForm]
|
|
24
|
+
attribute :highlighted, Boolean
|
|
25
|
+
attribute :fixed, Boolean
|
|
26
|
+
|
|
27
|
+
attachments_attribute :documents
|
|
28
|
+
|
|
29
|
+
validates :body, presence: true#, etiquette: true
|
|
30
|
+
# validates :body, length: { in: 15..150 }
|
|
31
|
+
validates :category, presence: true
|
|
32
|
+
validate :questions_validator
|
|
33
|
+
|
|
34
|
+
# validate :body_is_not_bare_template
|
|
35
|
+
validate :notify_missing_attachment_if_errored
|
|
36
|
+
|
|
37
|
+
alias component current_component
|
|
38
|
+
# delegate :categories, to: :current_component
|
|
39
|
+
|
|
40
|
+
def map_model(model)
|
|
41
|
+
self.body = translated_attribute(model.body)
|
|
42
|
+
self.highlighted = model.highlighted
|
|
43
|
+
self.fixed = model.fixed
|
|
44
|
+
self.category = model.category
|
|
45
|
+
self.enable_comments = model.enable_comments
|
|
46
|
+
|
|
47
|
+
self.questions = model.questions.map do |question|
|
|
48
|
+
QuestionForm.from_model(question)
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
# @suggested_hashtags = Decidim::ContentRenderers::HashtagRenderer.new(body).extra_hashtags.map(&:name).map(&:downcase)
|
|
52
|
+
|
|
53
|
+
# presenter = PostPresenter.new(model)
|
|
54
|
+
# self.body = presenter.editor_body(all_locales: body.is_a?(Hash))
|
|
55
|
+
|
|
56
|
+
self.documents = model.attachments
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
# Finds the Category from the category_id.
|
|
60
|
+
#
|
|
61
|
+
# Returns a Decidim::Category
|
|
62
|
+
# def category
|
|
63
|
+
# @category ||= categories.find_by(id: category_id)
|
|
64
|
+
# end
|
|
65
|
+
|
|
66
|
+
# def extra_hashtags
|
|
67
|
+
# @extra_hashtags ||= (component_automatic_hashtags + suggested_hashtags).uniq
|
|
68
|
+
# end
|
|
69
|
+
|
|
70
|
+
# def suggested_hashtags
|
|
71
|
+
# downcased_suggested_hashtags = super.to_set(&:downcase)
|
|
72
|
+
# component_suggested_hashtags.select { |hashtag| downcased_suggested_hashtags.member?(hashtag.downcase) }
|
|
73
|
+
# end
|
|
74
|
+
|
|
75
|
+
# def suggested_hashtag_checked?(hashtag)
|
|
76
|
+
# suggested_hashtags.member?(hashtag)
|
|
77
|
+
# end
|
|
78
|
+
|
|
79
|
+
# def component_automatic_hashtags
|
|
80
|
+
# @component_automatic_hashtags ||= ordered_hashtag_list(current_component.current_settings.automatic_hashtags)
|
|
81
|
+
# end
|
|
82
|
+
|
|
83
|
+
# def component_suggested_hashtags
|
|
84
|
+
# @component_suggested_hashtags ||= ordered_hashtag_list(current_component.current_settings.suggested_hashtags)
|
|
85
|
+
# end
|
|
86
|
+
|
|
87
|
+
def has_attachments?
|
|
88
|
+
post.has_attachments? && errors[:documents].empty? && documents.present?
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
def has_error_in_attachments?
|
|
92
|
+
errors[:documents].present?
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
private
|
|
96
|
+
|
|
97
|
+
# def body_is_not_bare_template
|
|
98
|
+
# return if body_template.blank?
|
|
99
|
+
|
|
100
|
+
# errors.add(:body, :cant_be_equal_to_template) if body.presence == body_template.presence
|
|
101
|
+
# end
|
|
102
|
+
|
|
103
|
+
# This method will add an error to the "documents" field only if there is any error
|
|
104
|
+
# in any other field. This is needed because when the form has an error, the attachment
|
|
105
|
+
# is lost, so we need a way to inform the user of this problem.
|
|
106
|
+
def notify_missing_attachment_if_errored
|
|
107
|
+
errors.add(:documents, :needs_to_be_reattached) if errors.any? && documents.present?
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
def questions_validator
|
|
111
|
+
@questions_validator ||= questions.reject(&:deleted).each do |question|
|
|
112
|
+
errors.add(:questions, I18n.t("decidim.posts.posts.form.question_too_short")) if question.title.length <= 3
|
|
113
|
+
end.map(&:title).uniq
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
# def ordered_hashtag_list(string)
|
|
117
|
+
# string.to_s.split.compact_blank.uniq.sort_by(&:parameterize)
|
|
118
|
+
# end
|
|
119
|
+
end
|
|
120
|
+
end
|
|
121
|
+
end
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
module Decidim
|
|
2
|
+
module Posts
|
|
3
|
+
class QuestionForm < Decidim::Form
|
|
4
|
+
include Decidim::TranslatableAttributes
|
|
5
|
+
|
|
6
|
+
mimic :question
|
|
7
|
+
|
|
8
|
+
attribute :title, Decidim::Attributes::CleanString
|
|
9
|
+
attribute :answers, Array[AnswerForm]
|
|
10
|
+
attribute :deleted, Boolean, default: false
|
|
11
|
+
attribute :question_type, String
|
|
12
|
+
|
|
13
|
+
validates :title, presence: true
|
|
14
|
+
|
|
15
|
+
def map_model(model)
|
|
16
|
+
self.title = translated_attribute(model.title)
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Decidim
|
|
4
|
+
module Posts
|
|
5
|
+
# Custom helpers, scoped to the feeds engine.
|
|
6
|
+
#
|
|
7
|
+
module ApplicationHelper
|
|
8
|
+
include PaginateHelper
|
|
9
|
+
include SanitizeHelper
|
|
10
|
+
# include Decidim::Posts::PostsHelper
|
|
11
|
+
include ::Decidim::EndorsableHelper
|
|
12
|
+
include ::Decidim::FollowableHelper
|
|
13
|
+
include Decidim::Comments::CommentsHelper
|
|
14
|
+
|
|
15
|
+
def posts_component_for_meeting(meeting)
|
|
16
|
+
meeting.component.participatory_space.components.find_by(manifest_name: "posts")
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Decidim
|
|
4
|
+
module Posts
|
|
5
|
+
module PostCellsHelper
|
|
6
|
+
include Decidim::Posts::ApplicationHelper
|
|
7
|
+
include Decidim::Posts::Engine.routes.url_helpers
|
|
8
|
+
include Decidim::LayoutHelper
|
|
9
|
+
include Decidim::ApplicationHelper
|
|
10
|
+
include Decidim::TranslationsHelper
|
|
11
|
+
include Decidim::ResourceReferenceHelper
|
|
12
|
+
include Decidim::TranslatableAttributes
|
|
13
|
+
include Decidim::CardHelper
|
|
14
|
+
|
|
15
|
+
delegate :body, :category, to: :model
|
|
16
|
+
|
|
17
|
+
def current_settings
|
|
18
|
+
model.component.current_settings
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def component_settings
|
|
22
|
+
model.component.settings
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def current_component
|
|
26
|
+
model.component
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def participatory_space
|
|
30
|
+
@participatory_space ||= current_component.participatory_space
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Decidim
|
|
4
|
+
module Posts
|
|
5
|
+
# Custom helpers used in posts views
|
|
6
|
+
module PostsHelper
|
|
7
|
+
include Decidim::ApplicationHelper
|
|
8
|
+
include Decidim::TranslationsHelper
|
|
9
|
+
include Decidim::ResourceHelper
|
|
10
|
+
include Decidim::Meetings::ApplicationHelper
|
|
11
|
+
|
|
12
|
+
def calendar_months
|
|
13
|
+
[Date.current, Date.current.next_month]
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def collection
|
|
17
|
+
@collection ||= meetings.limit(limit)
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def meetings
|
|
21
|
+
@meetings ||= show_upcoming_meetings? ? upcoming_meetings : past_meetings
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def limit
|
|
25
|
+
3
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def participatory_space
|
|
29
|
+
@participatory_space ||= current_component.participatory_space
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Decidim
|
|
4
|
+
module Posts
|
|
5
|
+
module ReactionHelper
|
|
6
|
+
def reaction_icon(icon_name)
|
|
7
|
+
emojis = {
|
|
8
|
+
"heart": "❤️",
|
|
9
|
+
"laugh": "😂",
|
|
10
|
+
"surprise": "😮",
|
|
11
|
+
"sad": "😢",
|
|
12
|
+
"angry": "😡",
|
|
13
|
+
"like": "👍"
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
return "?" unless emojis.key?(icon_name.to_sym)
|
|
17
|
+
|
|
18
|
+
emojis[icon_name.to_sym]
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
module Decidim
|
|
2
|
+
module Posts
|
|
3
|
+
class Answer < Feeds::ApplicationRecord
|
|
4
|
+
include Decidim::TranslatableResource
|
|
5
|
+
include Decidim::TranslatableAttributes
|
|
6
|
+
|
|
7
|
+
belongs_to :question, class_name: "Decidim::Posts::Question", foreign_key: "decidim_posts_question_id"
|
|
8
|
+
has_many :user_answers, class_name: "Decidim::Posts::UserAnswer", dependent: :destroy, foreign_key: "decidim_posts_answer_id"
|
|
9
|
+
|
|
10
|
+
translatable_fields :title
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
end
|