Skip to content

Commit ac37d1c

Browse files
verarojmanmicrostudi
authored andcommitted
Archive Debates (decidim#6940)
* Archive and unarchive debates * Add empty message * Fix erb, rb and i18norm offenses * Archive debate from debate close form * Put back accidentally removed create_debates migration * Add spec for Archive command * Add spec for archived? method in debate * Add system spec for archiving debates * Enable unarchiving from close form * Add seeds for archived debates * Change icon class when debate is closed / archived * Allow admin to archive non-official debates * Allow open debates to be archived too # Conflicts: # decidim-debates/app/views/decidim/debates/admin/debates/index.html.erb # decidim-debates/lib/decidim/debates/component.rb
1 parent 0bb15b5 commit ac37d1c

17 files changed

Lines changed: 356 additions & 60 deletions

File tree

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
# frozen_string_literal: true
2+
3+
module Decidim
4+
module Debates
5+
module Admin
6+
# A command with all the business logic when an admin archives a debate.
7+
class ArchiveDebate < Rectify::Command
8+
# Public: Initializes the command.
9+
#
10+
# archive - Boolean, whether to archive (true) or unarchive (false) the debate.
11+
# debate - The debate object to archive.
12+
# user - The user performing the action.
13+
def initialize(archive, debate, user)
14+
@archive = archive
15+
@debate = debate
16+
@user = user
17+
end
18+
19+
# Executes the command. Broadcasts these events:
20+
#
21+
# - :ok when the debate is valid.
22+
# - :invalid if the debate wasn't valid and we couldn't proceed.
23+
#
24+
# Returns nothing.
25+
def call
26+
archive_debate
27+
broadcast(:ok)
28+
rescue ActiveRecord::RecordInvalid
29+
broadcast(:invalid)
30+
end
31+
32+
attr_reader :debate
33+
34+
private
35+
36+
def archive_debate
37+
@debate = Decidim.traceability.perform_action!(
38+
:close,
39+
@debate,
40+
@user
41+
) do
42+
@debate.update!(
43+
archived_at: @archive ? Time.zone.now : nil
44+
)
45+
end
46+
end
47+
end
48+
end
49+
end
50+
end

decidim-debates/app/commands/decidim/debates/admin/close_debate.rb

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,8 @@ def close_debate
3737
) do
3838
form.debate.update!(
3939
conclusions: form.conclusions,
40-
closed_at: form.closed_at
40+
closed_at: form.closed_at,
41+
archived_at: (Time.zone.now if form.archive)
4142
)
4243
end
4344

decidim-debates/app/controllers/decidim/debates/admin/debates_controller.rb

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,24 @@ def update
6161
end
6262
end
6363

64+
def archive
65+
enforce_permission_to :archive, :debate, debate: debate
66+
67+
archive = params[:archive] == "true"
68+
69+
ArchiveDebate.call(archive, debate, current_user) do
70+
on(:ok) do
71+
flash[:notice] = I18n.t("debates.#{archive ? "archive" : "unarchive"}.success", scope: "decidim.debates.admin")
72+
redirect_to debates_path(archive ? {} : { filter: "archive" })
73+
end
74+
75+
on(:invalid) do
76+
flash.now[:alert] = I18n.t("debates.#{archive ? "archive" : "unarchive"}.invalid", scope: "decidim.debates.admin")
77+
redirect_to debates_path(archive ? {} : { filter: "archive" })
78+
end
79+
end
80+
end
81+
6482
def destroy
6583
enforce_permission_to :delete, :debate, debate: debate
6684

@@ -74,11 +92,19 @@ def destroy
7492
private
7593

7694
def debates
77-
@debates ||= Debate.where(component: current_component)
95+
@debates ||= archive? ? all_debates.archived : all_debates.not_archived
7896
end
7997

8098
def debate
81-
@debate ||= debates.find(params[:id])
99+
@debate ||= all_debates.find(params[:id])
100+
end
101+
102+
def all_debates
103+
Debate.where(component: current_component)
104+
end
105+
106+
def archive?
107+
params[:filter] == "archive"
82108
end
83109
end
84110
end

decidim-debates/app/forms/decidim/debates/admin/close_debate_form.rb

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ class CloseDebateForm < Decidim::Form
1515
end
1616

1717
attribute :debate, Debate
18+
attribute :archive, Boolean
1819

1920
validates :debate, presence: true
2021
validate :user_can_close_debate
@@ -23,6 +24,10 @@ def closed_at
2324
debate&.closed_at || Time.current
2425
end
2526

27+
def map_model(model)
28+
self.archive = model.archived_at.present?
29+
end
30+
2631
private
2732

2833
def user_can_close_debate

decidim-debates/app/helpers/decidim/debates/admin/application_helper.rb

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,15 @@ module Admin
77
#
88
module ApplicationHelper
99
include Decidim::Admin::ResourceScopeHelper
10+
11+
def link_to_filtered_debates
12+
unfiltered = params[:filter].blank?
13+
link_to(
14+
t("actions.#{unfiltered ? "archived" : "active"}", scope: "decidim.debates", name: t("models.debate.name", scope: "decidim.debates.admin")),
15+
debates_path(unfiltered ? { filter: "archive" } : {}),
16+
class: "button tiny button--title"
17+
)
18+
end
1019
end
1120
end
1221
end

decidim-debates/app/models/decidim/debates/debate.rb

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,8 @@ class Debate < Debates::ApplicationRecord
4242

4343
scope :open, -> { where(closed_at: nil) }
4444
scope :closed, -> { where.not(closed_at: nil) }
45+
scope :archived, -> { where.not(archived_at: nil) }
46+
scope :not_archived, -> { where(archived_at: nil) }
4547
scope :authored_by, ->(author) { where(author: author) }
4648
scope :commented_by, lambda { |author|
4749
joins(:comments).where(
@@ -86,6 +88,13 @@ def open?
8688
(ama? && open_ama?) || !ama?
8789
end
8890

91+
# Public: Checks if the debate is archived or not.
92+
#
93+
# Returns a boolean.
94+
def archived?
95+
archived_at.present?
96+
end
97+
8998
# Public: Overrides the `commentable?` Commentable concern method.
9099
def commentable?
91100
component.settings.comments_enabled?
@@ -157,6 +166,13 @@ def closeable_by?(user)
157166
authored_by?(user)
158167
end
159168

169+
# Checks whether the user can archive the debate.
170+
#
171+
# user - the user to check for authorship
172+
def archivable_by?(user)
173+
authored_by?(user)
174+
end
175+
160176
# Public: Updates the comments counter cache. We have to do it these
161177
# way in order to properly calculate the counter with hidden
162178
# comments.

decidim-debates/app/permissions/decidim/debates/admin/permissions.rb

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ def permissions
1212
case permission_action.action
1313
when :create, :read
1414
allow!
15+
when :archive
16+
toggle_allow(debate.present?)
1517
when :update
1618
toggle_allow(debate && !debate.closed? && debate.official?)
1719
when :delete, :close

decidim-debates/app/views/decidim/debates/admin/debate_closes/edit.html.erb

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,12 @@
99
<%= f.translated :editor, :conclusions, autofocus: true, rows: 15 %>
1010
</div>
1111
</div>
12+
<div class="card-section">
13+
<div class="row column space-top-10">
14+
<%= f.check_box :archive, label: t(".archive") %>
15+
<p class="help-text"><%= t(".archive_help") %></p>
16+
</div>
17+
</div>
1218
</div>
1319

1420
<div class="button--double form-general-submit">

decidim-debates/app/views/decidim/debates/admin/debates/index.html.erb

Lines changed: 61 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -4,55 +4,72 @@
44
<%= t(".title") %>
55

66
<%= link_to t("actions.new", scope: "decidim.debates", name: t("models.debate.name", scope: "decidim.debates.admin")), new_debate_path, class: "button tiny button--title" if allowed_to? :create, :debate %>
7+
<%= link_to_filtered_debates if allowed_to? :read, :debate %>
78
</h2>
89
</div>
910

1011
<div class="card-section">
11-
<div class="table-scroll">
12-
<table class="table-list">
13-
<thead>
14-
<tr>
15-
<th><%= t("models.debate.fields.title", scope: "decidim.debates") %></th>
16-
<th><%= t("models.debate.fields.start_time", scope: "decidim.debates") %></th>
17-
<th><%= t("models.debate.fields.end_time", scope: "decidim.debates") %></th>
18-
<%= th_resource_scope_label %>
19-
<th class="actions"><%= t("actions.title", scope: "decidim.debates") %></th>
20-
</tr>
21-
</thead>
22-
<tbody>
23-
<% debates.each do |debate| %>
24-
<tr data-id="<%= debate.id %>">
25-
<td>
26-
<%= link_to present(debate).title, resource_locator(debate).path, target: :blank %><br>
27-
</td>
28-
<td>
29-
<% if debate.start_time %>
30-
<%= l debate.start_time, format: :long %>
31-
<% end %>
32-
</td>
33-
<td>
34-
<% if debate.end_time %>
35-
<%= l debate.end_time, format: :long %>
36-
<% end %>
37-
</td>
38-
<%= td_resource_scope_for(debate.scope) %>
39-
<td class="table-list__actions">
40-
<% if allowed_to? :update, :debate, debate: debate %>
41-
<%= icon_link_to "pencil", edit_debate_path(debate), t("actions.edit", scope: "decidim.debates"), class: "action-icon--edit" %>
42-
<% end %>
12+
<% if debates.any? %>
13+
<div class="table-scroll">
14+
<table class="table-list">
15+
<thead>
16+
<tr>
17+
<th><%= t("models.debate.fields.title", scope: "decidim.debates") %></th>
18+
<th><%= t("models.debate.fields.start_time", scope: "decidim.debates") %></th>
19+
<th><%= t("models.debate.fields.end_time", scope: "decidim.debates") %></th>
20+
<%= th_resource_scope_label %>
21+
<th class="actions"><%= t("actions.title", scope: "decidim.debates") %></th>
22+
</tr>
23+
</thead>
24+
<tbody>
25+
<% debates.each do |debate| %>
26+
<tr data-id="<%= debate.id %>">
27+
<td>
28+
<%= link_to present(debate).title, resource_locator(debate).path, target: :blank %><br>
29+
</td>
30+
<td>
31+
<% if debate.start_time %>
32+
<%= l debate.start_time, format: :long %>
33+
<% end %>
34+
</td>
35+
<td>
36+
<% if debate.end_time %>
37+
<%= l debate.end_time, format: :long %>
38+
<% end %>
39+
</td>
40+
<%= td_resource_scope_for(debate.scope) %>
41+
<td class="table-list__actions">
42+
<% if allowed_to? :update, :debate, debate: debate %>
43+
<%= icon_link_to "pencil", edit_debate_path(debate), t("actions.edit", scope: "decidim.debates"), class: "action-icon--edit" %>
44+
<% else %>
45+
<span class="action-space icon"></span>
46+
<% end %>
4347

44-
<% if allowed_to? :close, :debate, debate: debate %>
45-
<%= icon_link_to "lock-locked", edit_debate_debate_close_path(debate_id: debate.id, id: debate.id), t("actions.close", scope: "decidim.debates"), class: "action-icon--close" %>
46-
<% end %>
48+
<% if allowed_to? :close, :debate, debate: debate %>
49+
<%= icon_link_to "lock-locked", edit_debate_debate_close_path(debate_id: debate.id, id: debate.id), t("actions.close", scope: "decidim.debates"), class: "action-icon--close #{"action-icon--highlighted" if debate.closed?}" %>
50+
<% else %>
51+
<span class="action-space icon"></span>
52+
<% end %>
4753

48-
<% if allowed_to? :delete, :debate, debate: debate %>
49-
<%= icon_link_to "circle-x", debate_path(debate), t("actions.destroy", scope: "decidim.debates"), method: :delete, class: "action-icon--remove", data: { confirm: t("actions.confirm_destroy", scope: "decidim.debates") } %>
50-
<% end %>
51-
</td>
52-
</tr>
53-
<% end %>
54-
</tbody>
55-
</table>
56-
</div>
54+
<% if allowed_to? :archive, :debate, debate: debate %>
55+
<%= icon_link_to "folder", archive_debate_path(id: debate.id, archive: !debate.archived?), t("actions.#{ debate.archived? ? "unarchive" : "archive" }", scope: "decidim.debates"), class: "action-icon--archive #{"action-icon--highlighted" if debate.archived?}", method: :post %>
56+
<% else %>
57+
<span class="action-space icon"></span>
58+
<% end %>
59+
60+
<% if allowed_to? :delete, :debate, debate: debate %>
61+
<%= icon_link_to "circle-x", debate_path(debate), t("actions.destroy", scope: "decidim.debates"), method: :delete, class: "action-icon--remove", data: { confirm: t("actions.confirm_destroy", scope: "decidim.debates") } %>
62+
<% else %>
63+
<span class="action-space icon"></span>
64+
<% end %>
65+
</td>
66+
</tr>
67+
<% end %>
68+
</tbody>
69+
</table>
70+
</div>
71+
<% else %>
72+
<%= t("debates.empty", scope: "decidim.debates.admin") %>
73+
<% end %>
5774
</div>
5875
</div>

decidim-debates/config/locales/en.yml

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,18 +46,27 @@ en:
4646
endorsements_enabled: Endorsements enabled
4747
debates:
4848
actions:
49+
active: Active debates
50+
archive: Archive
51+
archived: Archived debates
4952
close: Close
5053
confirm_destroy: Are you sure?
5154
destroy: Delete
5255
edit: Edit
5356
new: New %{name}
5457
title: Actions
58+
unarchive: Unarchive
5559
admin:
5660
debate_closes:
5761
edit:
62+
archive: Archive this debate
63+
archive_help: Archiving this debate will hide it from the public debates section
5864
close: Close
5965
title: Close debate
6066
debates:
67+
archive:
68+
invalid: There was a problem archiving the debate.
69+
success: Debate successfully archived.
6170
create:
6271
invalid: There was a problem creating the debate.
6372
success: Debate successfully created.
@@ -66,11 +75,15 @@ en:
6675
edit:
6776
title: Edit debate
6877
update: Update debate
78+
empty: There are no debates matching these criteria.
6979
index:
7080
title: Debates
7181
new:
7282
create: Create debate
7383
title: New debate
84+
unarchive:
85+
invalid: There was a problem unarchiving the debate.
86+
success: Debate successfully unarchived.
7487
update:
7588
invalid: There was a problem updating this debate.
7689
success: Debate successfully updated.

0 commit comments

Comments
 (0)