diff --git a/Gemfile b/Gemfile
index ae12ddb0b..b9659381a 100644
--- a/Gemfile
+++ b/Gemfile
@@ -10,6 +10,8 @@ gem "ancestry", "~> 3.0.7"
gem "audited", "~> 4.9.0"
gem "autoprefixer-rails", "~> 8.2.0"
gem "cancancan", "~> 2.3.0"
+gem "caxlsx", "~> 3.0.2"
+gem "caxlsx_rails", "~> 0.6.2"
gem "ckeditor", "~> 4.3.0"
gem "cocoon", "~> 1.2.14"
gem "daemons", "~> 1.3.1"
diff --git a/Gemfile.lock b/Gemfile.lock
index 566735c56..71fdf2d8d 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -131,6 +131,14 @@ GEM
rack (>= 1.4)
rack-proxy (>= 0.6.0)
selenium-webdriver (~> 3.0)
+ caxlsx (3.0.2)
+ htmlentities (~> 4.3, >= 4.3.4)
+ mimemagic (~> 0.3)
+ nokogiri (~> 1.10, >= 1.10.4)
+ rubyzip (>= 1.3.0, < 3)
+ caxlsx_rails (0.6.2)
+ actionpack (>= 3.1)
+ caxlsx (>= 3.0)
chef-utils (16.4.41)
childprocess (0.9.0)
ffi (~> 1.0, >= 1.0.11)
@@ -638,6 +646,8 @@ DEPENDENCIES
capistrano3-puma (~> 4.0.0)
capybara (~> 3.29.0)
capybara-webmock (~> 0.5.5)
+ caxlsx (~> 3.0.2)
+ caxlsx_rails (~> 0.6.2)
ckeditor (~> 4.3.0)
cocoon (~> 1.2.14)
coveralls (~> 0.8.22)
diff --git a/app/assets/stylesheets/layout.scss b/app/assets/stylesheets/layout.scss
index c089d3b3d..25c769a2a 100644
--- a/app/assets/stylesheets/layout.scss
+++ b/app/assets/stylesheets/layout.scss
@@ -2045,10 +2045,6 @@ table {
padding: $line-height / 4;
position: relative;
- .relative {
- padding-left: rem-calc(18);
- }
-
.divider {
color: $text-light;
display: inline-block;
@@ -2060,23 +2056,22 @@ table {
}
.responses-count {
- .far {
- @extend .fa-minus-square;
- font-size: $small-font-size;
- left: 0;
- position: absolute;
- text-decoration: none;
- top: 2px;
- }
-
.show-children {
+ @include has-fa-icon(plus-square, r);
display: none;
}
+ .collapse-children {
+ @include has-fa-icon(minus-square, r);
+ }
+
+ .show-children::before,
+ .collapse-children::before {
+ margin-right: rem-calc(6);
+ transform: translateY(1px);
+ }
+
&.collapsed {
- .far {
- @extend .fa-plus-square;
- }
.collapse-children {
display: none;
diff --git a/app/assets/stylesheets/legislation_process.scss b/app/assets/stylesheets/legislation_process.scss
index cb4488004..8f3199c06 100644
--- a/app/assets/stylesheets/legislation_process.scss
+++ b/app/assets/stylesheets/legislation_process.scss
@@ -1006,3 +1006,91 @@
font-weight: bold;
}
}
+
+// 10. Legislation summary
+// -------------------------
+
+.process-summary {
+ > section {
+ @include grid-row;
+ margin-top: $line-height * 1.5;
+ padding: 0 rem-calc(16);
+
+ > header {
+ background: none;
+ border: 0;
+ margin: 0;
+ }
+ }
+
+ h4,
+ p {
+ margin-bottom: 0;
+ }
+
+ > section > header,
+ .question-title,
+ .annotation-title,
+ .comment-summary,
+ .proposal-summary {
+ @include breakpoint(medium) {
+ align-items: center;
+ display: flex;
+
+ > :first-child {
+ $margin: rem-calc(map-get($grid-column-gutter, "medium"));
+
+ margin-right: $margin;
+ width: calc(75% - #{$margin});
+ }
+ }
+ }
+
+ .debate-summary,
+ .proposal-summary,
+ .annotation-summary {
+ @extend %panel;
+ min-height: auto;
+ padding-bottom: rem-calc(16);
+ padding-top: rem-calc(16);
+
+ &:not(:last-child) {
+ margin-bottom: $line-height / 2;
+ }
+ }
+
+ .comments-count {
+ @include has-fa-icon(comments, r);
+ }
+
+ .question-title:not(:only-child) {
+ margin-bottom: $line-height / 2;
+ }
+
+ .annotation-title {
+ margin-bottom: $line-height / 2;
+ margin-top: $line-height / 2;
+ }
+
+ .annotation-quote {
+ border: 1px solid $black;
+ padding: rem-calc(10);
+ }
+
+ .comment-summary {
+ margin-bottom: $line-height / 2;
+
+ > :first-child {
+ background-color: rgba(217, 216, 243, 0.2);
+ border-radius: rem-calc(10);
+ padding: rem-calc(12);
+ }
+ }
+
+ .download-button {
+ margin-bottom: 0;
+ margin-left: 50%;
+ margin-top: $line-height;
+ transform: translateX(-50%);
+ }
+}
diff --git a/app/assets/stylesheets/mixins.scss b/app/assets/stylesheets/mixins.scss
index b5fb4b9f3..289eb83a6 100644
--- a/app/assets/stylesheets/mixins.scss
+++ b/app/assets/stylesheets/mixins.scss
@@ -148,3 +148,18 @@
transition: none;
}
}
+
+@mixin has-fa-icon($icon, $style) {
+ @extend .fa-#{$icon};
+
+ &::before {
+ @extend %fa-icon;
+ font-family: "Font Awesome 5 Free";
+
+ @if $style == "r" {
+ font-weight: normal;
+ } @else {
+ font-weight: bold;
+ }
+ }
+}
diff --git a/app/assets/stylesheets/participation.scss b/app/assets/stylesheets/participation.scss
index 895e4d2cc..a825c77bb 100644
--- a/app/assets/stylesheets/participation.scss
+++ b/app/assets/stylesheets/participation.scss
@@ -612,6 +612,45 @@
}
}
+%panel {
+ background: #fff;
+ border: 1px solid;
+ border-color: #e5e6e9 #dfe0e4 #d0d1d5;
+ border-radius: 0;
+ box-shadow: 0 1px 3px 0 $border;
+ margin-bottom: rem-calc(12);
+ min-height: rem-calc(192);
+ padding: rem-calc(12) rem-calc(12) 0;
+
+ @include breakpoint(medium) {
+ margin-bottom: rem-calc(-1);
+ padding-bottom: rem-calc(12);
+ }
+
+ @include breakpoint(medium) {
+ .divider {
+ display: inline-block;
+ }
+ }
+
+ h3 {
+ font-weight: bold;
+ margin-top: $line-height / 2;
+
+ a {
+ color: $text;
+ }
+ }
+
+ &.past-budgets {
+ min-height: 0;
+
+ .button ~ .button {
+ margin-left: $line-height / 2;
+ }
+ }
+}
+
.debate,
.proposal,
.investment-project,
@@ -621,42 +660,7 @@
margin: $line-height / 4 0;
.panel {
- background: #fff;
- border: 1px solid;
- border-color: #e5e6e9 #dfe0e4 #d0d1d5;
- border-radius: 0;
- box-shadow: 0 1px 3px 0 $border;
- margin-bottom: rem-calc(12);
- min-height: rem-calc(192);
- padding: rem-calc(12) rem-calc(12) 0;
-
- @include breakpoint(medium) {
- margin-bottom: rem-calc(-1);
- padding-bottom: rem-calc(12);
- }
-
- @include breakpoint(medium) {
- .divider {
- display: inline-block;
- }
- }
-
- h3 {
- font-weight: bold;
- margin-top: $line-height / 2;
-
- a {
- color: $text;
- }
- }
-
- &.past-budgets {
- min-height: 0;
-
- .button ~ .button {
- margin-left: $line-height / 2;
- }
- }
+ @extend %panel;
}
.debate-content,
diff --git a/app/controllers/legislation/processes_controller.rb b/app/controllers/legislation/processes_controller.rb
index d6dd6d3e5..0edd2cc5a 100644
--- a/app/controllers/legislation/processes_controller.rb
+++ b/app/controllers/legislation/processes_controller.rb
@@ -97,6 +97,17 @@ class Legislation::ProcessesController < Legislation::BaseController
@phase = :milestones
end
+ def summary
+ @phase = :summary
+ @proposals = @process.proposals.selected
+ @comments = @process.draft_versions.published.last&.best_comments || Comment.none
+
+ respond_to do |format|
+ format.html
+ format.xlsx { render xlsx: "summary", filename: "summary-#{Date.current}.xlsx" }
+ end
+ end
+
def proposals
set_process
@phase = :proposals_phase
diff --git a/app/models/abilities/administrator.rb b/app/models/abilities/administrator.rb
index 25dcb60c7..24b70e453 100644
--- a/app/models/abilities/administrator.rb
+++ b/app/models/abilities/administrator.rb
@@ -90,7 +90,9 @@ module Abilities
can :access, :ckeditor
can :manage, Ckeditor::Picture
- can [:manage], ::Legislation::Process
+ can [:read, :debate, :draft_publication, :allegations, :result_publication,
+ :milestones], Legislation::Process
+ can [:create, :update, :destroy], Legislation::Process
can [:manage], ::Legislation::DraftVersion
can [:manage], ::Legislation::Question
can [:manage], ::Legislation::Proposal
diff --git a/app/models/abilities/everyone.rb b/app/models/abilities/everyone.rb
index 89a29f4b9..432099150 100644
--- a/app/models/abilities/everyone.rb
+++ b/app/models/abilities/everyone.rb
@@ -21,6 +21,8 @@ module Abilities
can :new, DirectMessage
can [:read, :debate, :draft_publication, :allegations, :result_publication,
:proposals, :milestones], Legislation::Process, published: true
+ can :summary, Legislation::Process,
+ id: Legislation::Process.past.published.where(result_publication_enabled: true).ids
can [:read, :changes, :go_to_version], Legislation::DraftVersion
can [:read], Legislation::Question
can [:read, :map, :share], Legislation::Proposal
diff --git a/app/models/comment.rb b/app/models/comment.rb
index 1552ce3a5..7af862a73 100644
--- a/app/models/comment.rb
+++ b/app/models/comment.rb
@@ -49,6 +49,7 @@ class Comment < ApplicationRecord
scope :sort_by_most_voted, -> { order(confidence_score: :desc, created_at: :desc) }
scope :sort_descendants_by_most_voted, -> { order(confidence_score: :desc, created_at: :asc) }
+ scope :sort_by_supports, -> { order("cached_votes_up - cached_votes_down DESC") }
scope :sort_by_newest, -> { order(created_at: :desc) }
scope :sort_descendants_by_newest, -> { order(created_at: :desc) }
@@ -129,6 +130,10 @@ class Comment < ApplicationRecord
cached_votes_up)
end
+ def votes_score
+ cached_votes_up - cached_votes_down
+ end
+
private
def validate_body_length
diff --git a/app/models/legislation/draft_version.rb b/app/models/legislation/draft_version.rb
index 93b65eb8f..9019d6cb8 100644
--- a/app/models/legislation/draft_version.rb
+++ b/app/models/legislation/draft_version.rb
@@ -40,4 +40,8 @@ class Legislation::DraftVersion < ApplicationRecord
def total_comments
annotations.sum(:comments_count)
end
+
+ def best_comments
+ Comment.where(commentable: annotations, ancestry: nil).sort_by_supports.limit(10)
+ end
end
diff --git a/app/models/legislation/question.rb b/app/models/legislation/question.rb
index ff9e0ea94..73f1cc946 100644
--- a/app/models/legislation/question.rb
+++ b/app/models/legislation/question.rb
@@ -44,4 +44,8 @@ class Legislation::Question < ApplicationRecord
def comments_open?
process.debate_phase.open?
end
+
+ def best_comments
+ comments.sort_by_supports.limit(3)
+ end
end
diff --git a/app/views/comments/_responses_count.html.erb b/app/views/comments/_responses_count.html.erb
index 3915b5495..d9ac9fdf0 100644
--- a/app/views/comments/_responses_count.html.erb
+++ b/app/views/comments/_responses_count.html.erb
@@ -1,6 +1,5 @@
<% if count > 0 %>
- <%= link_to "", class: "js-toggle-children relative" do %>
-
+ <%= link_to "", class: "js-toggle-children" do %>
<%= t("comments.comment.responses_show", count: count) %>
<%= t("comments.comment.responses_collapse", count: count) %>
<% end %>
diff --git a/app/views/legislation/processes/_key_dates.html.erb b/app/views/legislation/processes/_key_dates.html.erb
index 4e8ab85c0..7e5842d1a 100644
--- a/app/views/legislation/processes/_key_dates.html.erb
+++ b/app/views/legislation/processes/_key_dates.html.erb
@@ -52,6 +52,15 @@
<% end %>
<% end %>
+
+ <% if can?(:summary, process) %>
+
>
+ <%= link_to summary_legislation_process_path(process) do %>
+ <%= t("legislation.summary.title") %>
+ <%= format_date(process.result_publication_date) %>
+ <% end %>
+
+ <% end %>
diff --git a/app/views/legislation/processes/_summary_allegations.html.erb b/app/views/legislation/processes/_summary_allegations.html.erb
new file mode 100644
index 000000000..345542dc1
--- /dev/null
+++ b/app/views/legislation/processes/_summary_allegations.html.erb
@@ -0,0 +1,32 @@
+
diff --git a/app/views/legislation/processes/_summary_comments.html.erb b/app/views/legislation/processes/_summary_comments.html.erb
new file mode 100644
index 000000000..7e8b61d60
--- /dev/null
+++ b/app/views/legislation/processes/_summary_comments.html.erb
@@ -0,0 +1,10 @@
+<% if comments.any? %>
+ <%= t("legislation.summary.most_voted_comments") %>
+
+ <% comments.each do |comment| %>
+
+ <% end %>
+<% end %>
diff --git a/app/views/legislation/processes/_summary_debate.html.erb b/app/views/legislation/processes/_summary_debate.html.erb
new file mode 100644
index 000000000..8530f192d
--- /dev/null
+++ b/app/views/legislation/processes/_summary_debate.html.erb
@@ -0,0 +1,28 @@
+
+
+ <%= t("legislation.summary.debate_phase") %>
+ <%= t("legislation.summary.debates", count: questions.count) %>
+
+
+ <% if questions.any? %>
+
+ <% questions.each do |question| %>
+
+
+
<%= link_to question.title, polymorphic_path(question) %>
+
+
+
+ <%= render "summary_comments", comments: question.best_comments %>
+
+ <% end %>
+
+ <% else %>
+
+
<%= t("legislation.processes.debate.empty_questions") %>
+
+ <% end %>
+
diff --git a/app/views/legislation/processes/_summary_proposals.html.erb b/app/views/legislation/processes/_summary_proposals.html.erb
new file mode 100644
index 000000000..09ccca777
--- /dev/null
+++ b/app/views/legislation/processes/_summary_proposals.html.erb
@@ -0,0 +1,23 @@
+
+
+ <%= t("legislation.summary.proposals_phase") %>
+ <%= t("legislation.summary.proposals", count: proposals.count) %>
+
+
+ <% if proposals.any? %>
+
+ <% proposals.sort_by_supports.each do |proposal| %>
+
+
+ <%= link_to proposal.title, polymorphic_path(proposal) %>
+
+
<%= t("legislation.summary.votes", count: proposal.votes_score) %>
+
+ <% end %>
+
+ <% else %>
+
+
<%= t("legislation.processes.proposals.empty_proposals") %>
+
+ <% end %>
+
diff --git a/app/views/legislation/processes/summary.html.erb b/app/views/legislation/processes/summary.html.erb
new file mode 100644
index 000000000..81145e8fe
--- /dev/null
+++ b/app/views/legislation/processes/summary.html.erb
@@ -0,0 +1,29 @@
+<% provide(:title) { @process.title } %>
+
+<%= render "legislation/processes/header", process: @process, header: :full %>
+
+<%= render "key_dates", process: @process, phase: @phase %>
+
+<% if @process.debate_phase.enabled? || @process.proposals_phase.enabled? || @process.allegations_phase.enabled? %>
+
+ <%= link_to t("legislation.summary.download"),
+ summary_legislation_process_path(@process, format: :xlsx),
+ class: "button hollow download-button" %>
+
+ <% if @process.debate_phase.enabled? %>
+ <%= render "summary_debate", questions: @process.questions %>
+ <% end %>
+
+ <% if @process.proposals_phase.enabled? %>
+ <%= render "summary_proposals", proposals: @proposals %>
+ <% end %>
+
+ <% if @process.allegations_phase.enabled? %>
+ <%= render "summary_allegations", comments: @comments %>
+ <% end %>
+
+<% else %>
+
+
<%= t("legislation.summary.process_empty") %>
+
+<% end %>
diff --git a/app/views/legislation/processes/summary.xlsx.axlsx b/app/views/legislation/processes/summary.xlsx.axlsx
new file mode 100644
index 000000000..97baddc24
--- /dev/null
+++ b/app/views/legislation/processes/summary.xlsx.axlsx
@@ -0,0 +1,50 @@
+xlsx_package.workbook.add_worksheet(name: "Summary") do |sheet|
+
+styles = xlsx_package.workbook.styles
+title = styles.add_style(b:true)
+link = styles.add_style(fg_color: "0000FF", u: true)
+
+ if @process.debate_phase.enabled? && @process.questions.any?
+ sheet.add_row [t("legislation.summary.debate_phase"), t("legislation.summary.debates", count: @process.questions.count)], style: title
+ @process.questions.each do |question|
+ sheet.add_row [question.title, t("legislation.summary.comments", count: question.comments.count)], style: link
+ sheet.add_hyperlink location: legislation_process_question_url(question.process, question), ref: sheet.rows.last.cells.first
+ sheet.add_hyperlink location: polymorphic_url(question, anchor: "comments"), ref: sheet.rows.last.cells.last
+ sheet.add_row [t("legislation.summary.most_voted_comments")] if question.best_comments.any?
+ question.best_comments.each do |comment|
+ sheet.add_row [comment.body, t("legislation.summary.votes", count: comment.votes_score)]
+ sheet.add_hyperlink location: comment_url(comment), ref: sheet.rows.last.cells.first
+ sheet.rows.last.cells.first.style = link
+ end
+ sheet.add_row ["", ""]
+ end
+ end
+
+ if @process.proposals_phase.enabled? && @proposals.any?
+ sheet.add_row [t("legislation.summary.proposals_phase"), t("legislation.summary.proposals", count: @proposals.count)], style: title
+ @proposals.sort_by_supports.each do |proposal|
+ sheet.add_row [proposal.title, t("legislation.summary.votes", count: proposal.votes_score)]
+ sheet.add_hyperlink location: legislation_process_proposal_url(proposal.legislation_process_id, proposal), ref: sheet.rows.last.cells.first
+ sheet.rows.last.cells.first.style = link
+ end
+ sheet.add_row ["", ""]
+ end
+
+ if @process.allegations_phase.enabled? && @comments.any?
+ sheet.add_row [t("legislation.summary.allegations_phase"),
+ t("legislation.summary.top_comments", count: @comments.count)], style: title
+ @comments.group_by(&:commentable).each do |annotation, annotation_comments|
+ sheet.add_row [t("legislation.annotations.index.comments_about")]
+ sheet.add_row [annotation.quote, t("legislation.summary.comments", count: annotation.comments.count)]
+ sheet.add_hyperlink location: polymorphic_url(annotation, anchor: "comments"), ref: sheet.rows.last.cells.last
+ sheet.rows.last.cells.last.style = link
+
+ annotation_comments.each do |comment|
+ sheet.add_row [comment.body, t("legislation.summary.votes", count: comment.votes_score)]
+ sheet.add_hyperlink location: comment_url(comment), ref: sheet.rows.last.cells.first
+ sheet.rows.last.cells.first.style = link
+ end
+ sheet.add_row ["", ""]
+ end
+ end
+end
diff --git a/config/locales/en/legislation.yml b/config/locales/en/legislation.yml
index 967f6d1d9..263dd4662 100644
--- a/config/locales/en/legislation.yml
+++ b/config/locales/en/legislation.yml
@@ -118,3 +118,32 @@ en:
tags_label: "Categories"
not_verified: "For vote proposals %{verify_account}."
process_title: Collaborative legislation process
+ summary:
+ title: "Summary"
+ votes:
+ zero: "%{count} votes"
+ one: "%{count} vote"
+ other: "%{count} votes"
+ debate_phase: "Debate phase"
+ proposals_phase: "Proposals phase"
+ allegations_phase: "Comments phase"
+ debates:
+ zero: "No debates"
+ one: "%{count} debate"
+ other: "%{count} debates"
+ proposals:
+ zero: "No proposals"
+ one: "%{count} proposal"
+ other: "%{count} proposals"
+ comments:
+ zero: "No comments"
+ one: "%{count} comment"
+ other: "%{count} comments"
+ download: "Download summary"
+ top_comments:
+ zero: "No comments"
+ one: "%{count} comment"
+ other: "Top comments"
+ most_voted_comments: "Most voted comments"
+ no_allegation: "There are no comments"
+ process_empty: "This process didn't have any participation phases"
diff --git a/config/locales/es/legislation.yml b/config/locales/es/legislation.yml
index fe723e250..480fce46b 100644
--- a/config/locales/es/legislation.yml
+++ b/config/locales/es/legislation.yml
@@ -118,3 +118,32 @@ es:
tags_label: "Categorías"
not_verified: "Para votar propuestas %{verify_account}."
process_title: Proceso de legislación colaborativa
+ summary:
+ title: "Resumen"
+ votes:
+ zero: "%{count} votos"
+ one: "%{count} voto"
+ other: "%{count} votos"
+ debate_phase: "Fase de debate"
+ proposals_phase: "Fase de propuestas"
+ allegations_phase: "Fase de comentarios"
+ debates:
+ zero: "No hay debates"
+ one: "%{count} debate"
+ other: "%{count} debates"
+ proposals:
+ zero: "No hay propuestas"
+ one: "%{count} propuesta"
+ other: "%{count} propuestas"
+ comments:
+ zero: "No hay comentarios"
+ one: "%{count} comentario"
+ other: "%{count} comentarios"
+ download: "Descargar resumen"
+ top_comments:
+ zero: "No hay comentarios"
+ one: "%{count} comentario"
+ other: "Los más votados"
+ most_voted_comments: "Comentarios más votados"
+ no_allegation: "No hay comentarios"
+ process_empty: "Este proceso no ha tenido fases de participación"
diff --git a/config/routes/legislation.rb b/config/routes/legislation.rb
index 2458a2bae..ee92ce26c 100644
--- a/config/routes/legislation.rb
+++ b/config/routes/legislation.rb
@@ -7,6 +7,7 @@ namespace :legislation do
get :result_publication
get :proposals
get :milestones
+ get :summary
end
resources :questions, only: [:show] do
diff --git a/spec/controllers/legislation/processes_controller_spec.rb b/spec/controllers/legislation/processes_controller_spec.rb
new file mode 100644
index 000000000..c15a293f3
--- /dev/null
+++ b/spec/controllers/legislation/processes_controller_spec.rb
@@ -0,0 +1,13 @@
+require "rails_helper"
+
+describe Legislation::ProcessesController do
+ let(:legislation_process) { create(:legislation_process, end_date: Date.current - 1.day) }
+
+ it "download excel file test" do
+ create(:legislation_question, process: legislation_process, title: "Question 1")
+
+ get :summary, params: { id: legislation_process, format: :xlsx }
+
+ expect(response).to be_success
+ end
+end
diff --git a/spec/models/abilities/administrator_spec.rb b/spec/models/abilities/administrator_spec.rb
index bbf8f91fe..c87cc889d 100644
--- a/spec/models/abilities/administrator_spec.rb
+++ b/spec/models/abilities/administrator_spec.rb
@@ -18,6 +18,10 @@ describe Abilities::Administrator do
let(:legislation_question) { create(:legislation_question) }
let(:poll_question) { create(:poll_question) }
+ let(:past_process) { create(:legislation_process, :past) }
+ let(:past_draft_process) { create(:legislation_process, :past, :not_published) }
+ let(:open_process) { create(:legislation_process, :open) }
+
let(:proposal_document) { build(:document, documentable: proposal, user: proposal.author) }
let(:budget_investment_document) { build(:document, documentable: budget_investment) }
let(:poll_question_document) { build(:document, documentable: poll_question) }
@@ -67,6 +71,10 @@ describe Abilities::Administrator do
it { should be_able_to(:comment_as_administrator, legislation_question) }
it { should_not be_able_to(:comment_as_moderator, legislation_question) }
+ it { should be_able_to(:summary, past_process) }
+ it { should_not be_able_to(:summary, past_draft_process) }
+ it { should_not be_able_to(:summary, open_process) }
+
it { should be_able_to(:create, Budget) }
it { should be_able_to(:update, Budget) }
it { should be_able_to(:read_results, Budget) }
diff --git a/spec/models/abilities/everyone_spec.rb b/spec/models/abilities/everyone_spec.rb
index cfdbbf932..fdc03c74d 100644
--- a/spec/models/abilities/everyone_spec.rb
+++ b/spec/models/abilities/everyone_spec.rb
@@ -48,4 +48,8 @@ describe Abilities::Everyone do
it { should be_able_to(:read_stats, create(:budget, :valuating, stats_enabled: true)) }
it { should_not be_able_to(:read_stats, create(:budget, :valuating, stats_enabled: false)) }
it { should_not be_able_to(:read_stats, create(:budget, :selecting, stats_enabled: true)) }
+
+ it { should be_able_to(:summary, create(:legislation_process, :past)) }
+ it { should_not be_able_to(:summary, create(:legislation_process, :open)) }
+ it { should_not be_able_to(:summary, create(:legislation_process, :past, :not_published)) }
end
diff --git a/spec/system/legislation/summary_spec.rb b/spec/system/legislation/summary_spec.rb
new file mode 100644
index 000000000..880c7ee4e
--- /dev/null
+++ b/spec/system/legislation/summary_spec.rb
@@ -0,0 +1,179 @@
+require "rails_helper"
+
+describe "Legislation" do
+ context "process summary page" do
+ scenario "summary tab is not shown for open processes" do
+ process = create(:legislation_process, :open)
+
+ visit legislation_process_path(process)
+
+ expect(page).not_to have_content "Summary"
+ end
+
+ scenario "summary tab is shown por past processes" do
+ process = create(:legislation_process, :past)
+
+ visit legislation_process_path(process)
+
+ expect(page).to have_content "Summary"
+ end
+ end
+
+ scenario "empty process" do
+ process = create(:legislation_process, :empty,
+ result_publication_enabled: true,
+ end_date: Date.current - 1.day
+ )
+
+ visit summary_legislation_process_path(process)
+
+ expect(page).to have_content "This process didn't have any participation phases"
+ end
+
+ scenario "empty phases" do
+ process = create(:legislation_process, end_date: Date.current - 1.day)
+ visit summary_legislation_process_path(process)
+
+ expect(page).to have_content "Debate phase"
+ expect(page).to have_content "No debates"
+ expect(page).to have_content "There aren't any questions"
+
+ expect(page).to have_content "Proposals phase"
+ expect(page).to have_content "No proposals"
+ expect(page).to have_content "There are no proposals"
+
+ expect(page).to have_content "Comments phase"
+ expect(page).to have_content "No comments"
+ expect(page).to have_content "There are no comments"
+ end
+
+ context "only debates exist" do
+ let(:process) { create(:legislation_process, end_date: Date.current - 1.day) }
+ let(:user) { create(:user, :level_two) }
+
+ before do
+ create(:legislation_question, process: process, title: "Question 1") do |question|
+ create(:comment, user: user, commentable: question, body: "Answer 1")
+ create(:comment, user: user, commentable: question, body: "Answer 2")
+ end
+
+ create(:legislation_question, process: process, title: "Question 2") do |question|
+ create(:comment, user: user, commentable: question, body: "Answer 3")
+ create(:comment, user: user, commentable: question, body: "Answer 4")
+ end
+ end
+
+ scenario "shows debates list" do
+ visit summary_legislation_process_path(process)
+
+ expect(page).to have_content "Debate phase"
+ expect(page).to have_content "2 debates"
+ expect(page).to have_link "Question 1"
+ expect(page).to have_content "Answer 1"
+ expect(page).to have_content "Answer 2"
+ expect(page).to have_link "Question 2"
+ expect(page).to have_content "Answer 3"
+ expect(page).to have_content "Answer 4"
+
+ expect(page).to have_content "Proposals phase"
+ expect(page).to have_content "No proposals"
+ expect(page).to have_content "There are no proposals"
+
+ expect(page).to have_content "Comments phase"
+ expect(page).to have_content "No comments"
+ expect(page).to have_content "There are no comments"
+ end
+ end
+
+ context "only proposals exist" do
+ let(:process) { create(:legislation_process, end_date: Date.current - 1.day) }
+
+ before do
+ create(:legislation_proposal, legislation_process_id: process.id,
+ title: "Legislation proposal 1", selected: true)
+ create(:legislation_proposal, legislation_process_id: process.id,
+ title: "Legislation proposal 2", selected: false)
+ create(:legislation_proposal, legislation_process_id: process.id,
+ title: "Legislation proposal 3", selected: true)
+ create(:legislation_proposal, legislation_process_id: process.id,
+ title: "Legislation proposal 4", selected: false)
+ end
+
+ scenario "shows proposals list" do
+ visit summary_legislation_process_path(process)
+
+ expect(page).to have_content "Debate phase"
+ expect(page).to have_content "No debates"
+ expect(page).to have_content "There aren't any questions"
+
+ expect(page).to have_content "Proposals phase"
+ expect(page).to have_content "2 proposals"
+ expect(page).to have_link "Legislation proposal 1"
+ expect(page).not_to have_content "Legislation proposal 2"
+ expect(page).to have_link "Legislation proposal 3"
+ expect(page).not_to have_content "Legislation proposal 4"
+
+ expect(page).to have_content "Comments phase"
+ expect(page).to have_content "No comments"
+ expect(page).to have_content "There are no comments"
+ end
+ end
+
+ context "only text comments exist" do
+ let(:process) { create(:legislation_process, end_date: Date.current - 1.day) }
+
+ before do
+ user = create(:user, :level_two)
+ draft_version_1 = create(:legislation_draft_version, process: process,
+ title: "Version 1", body: "Body of the first version",
+ status: "published")
+ draft_version_2 = create(:legislation_draft_version, process: process,
+ title: "Version 2", body: "Body of the second version and that's it all of it",
+ status: "published")
+ annotation0 = create(:legislation_annotation,
+ draft_version: draft_version_1, text: "my annotation123",
+ ranges: annotation_ranges(5, 10))
+ annotation1 = create(:legislation_annotation,
+ draft_version: draft_version_2, text: "hola",
+ ranges: annotation_ranges(5, 10))
+ annotation2 = create(:legislation_annotation,
+ draft_version: draft_version_2,
+ ranges: annotation_ranges(12, 19))
+
+ create(:comment, user: user, commentable: annotation0, body: "Comment 0")
+ create(:comment, user: user, commentable: annotation1, body: "Comment 1")
+ create(:comment, user: user, commentable: annotation2, body: "Comment 2")
+ create(:comment, user: user, commentable: annotation2, body: "Comment 3")
+ end
+
+ scenario "shows coments list" do
+ visit summary_legislation_process_path(process)
+
+ expect(page).to have_content "Debate phase"
+ expect(page).to have_content "No debates"
+ expect(page).to have_content "There aren't any questions"
+
+ expect(page).to have_content "Proposals phase"
+ expect(page).to have_content "No proposals"
+ expect(page).to have_content "There are no proposals"
+
+ expect(page).to have_content "Comments phase"
+ expect(page).to have_content "Top comments"
+ expect(page).not_to have_content "Comment 0"
+ expect(page).to have_link "Comment 1"
+ expect(page).to have_link "Comment 2"
+ expect(page).to have_link "Comment 3"
+ end
+
+ scenario "excel download" do
+ visit summary_legislation_process_path(process)
+ click_link "Download summary"
+
+ expect(page.response_headers["Content-Type"]).to match(/officedocument.spreadsheetml/)
+ end
+ end
+
+ def annotation_ranges(start_offset, end_offset)
+ [{ "start" => "/p[1]", "startOffset" => start_offset, "end" => "/p[1]", "endOffset" => end_offset }]
+ end
+end
<%= t("legislation.summary.allegations_phase") %>
+<%= t("legislation.summary.top_comments", count: comments.count) %>
+<%= t("legislation.summary.no_allegation") %>
+