From a8a79fe97f6807e669153dce4c4a35098f083ad4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Javi=20Mart=C3=ADn?= Date: Fri, 3 Jul 2020 23:42:29 +0200 Subject: [PATCH 1/3] Extract mixin to add font awesome icons This way we can simplify the HTML and easily apply font awesome icons to any element. Note the mixin uses `extend`, which we generally try to avoid. It's OK in this case, since `fa-` classes only have one rule, affecting the content of its `::before` pseudo-element. Unfortunately we can't use `include fa-content($fa-var-#{$icon})` because it's not valid SCSS. We could make the mixin accept an icon instead of an icon name, and call it using `has-fa-icon(r, $fa-var-plus-square)`. However, IMHO that would make the code a bit more complex with no real benefit. --- app/assets/stylesheets/layout.scss | 27 ++++++++------------ app/assets/stylesheets/mixins.scss | 15 +++++++++++ app/views/comments/_responses_count.html.erb | 3 +-- 3 files changed, 27 insertions(+), 18 deletions(-) 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/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/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 %> From 14df74fed74497576281efe9c83340c302665b10 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Javi=20Mart=C3=ADn?= Date: Thu, 16 Jul 2020 19:23:04 +0200 Subject: [PATCH 2/3] Add collaborative legislation summary again It was removed in commit 128a8164 because we hadn't reviewed it nor tested it properly. We're now adding it again, fixing the issues we've found while reviewing. --- .../stylesheets/legislation_process.scss | 81 +++++++++ app/assets/stylesheets/participation.scss | 76 ++++---- .../legislation/processes_controller.rb | 6 + app/models/abilities/administrator.rb | 4 +- app/models/abilities/everyone.rb | 2 + app/models/comment.rb | 5 + app/models/legislation/draft_version.rb | 4 + app/models/legislation/question.rb | 4 + .../legislation/processes/_key_dates.html.erb | 9 + .../processes/_summary_allegations.html.erb | 32 ++++ .../processes/_summary_comments.html.erb | 10 + .../processes/_summary_debate.html.erb | 28 +++ .../processes/_summary_proposals.html.erb | 23 +++ .../legislation/processes/summary.html.erb | 25 +++ config/locales/en/legislation.yml | 28 +++ config/locales/es/legislation.yml | 28 +++ config/routes/legislation.rb | 1 + spec/models/abilities/administrator_spec.rb | 8 + spec/models/abilities/everyone_spec.rb | 4 + spec/system/legislation/summary_spec.rb | 172 ++++++++++++++++++ 20 files changed, 513 insertions(+), 37 deletions(-) create mode 100644 app/views/legislation/processes/_summary_allegations.html.erb create mode 100644 app/views/legislation/processes/_summary_comments.html.erb create mode 100644 app/views/legislation/processes/_summary_debate.html.erb create mode 100644 app/views/legislation/processes/_summary_proposals.html.erb create mode 100644 app/views/legislation/processes/summary.html.erb create mode 100644 spec/system/legislation/summary_spec.rb diff --git a/app/assets/stylesheets/legislation_process.scss b/app/assets/stylesheets/legislation_process.scss index cb4488004..81c090a5f 100644 --- a/app/assets/stylesheets/legislation_process.scss +++ b/app/assets/stylesheets/legislation_process.scss @@ -1006,3 +1006,84 @@ 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); + } + } +} 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..2c8f01076 100644 --- a/app/controllers/legislation/processes_controller.rb +++ b/app/controllers/legislation/processes_controller.rb @@ -97,6 +97,12 @@ 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 + 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/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 @@ +
    +
    +

    <%= t("legislation.summary.allegations_phase") %>

    +

    <%= t("legislation.summary.top_comments", count: comments.count) %>

    +
    + + <% if comments.any? %> +
    + <% comments.group_by(&:commentable).each do |annotation, annotation_comments| %> +
    + <%= t("legislation.annotations.index.comments_about") %> +
    +
    + <%= annotation.quote %> +
    + + + <%= link_to t("legislation.summary.comments", count: annotation.comments.count), + polymorphic_path(annotation, anchor: "comments") %> + +
    + + <%= render "summary_comments", comments: annotation_comments %> +
    + <% end %> +
    + <% else %> +
    +

    <%= t("legislation.summary.no_allegation") %>

    +
    + <% end %> +
    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| %> +
    + <%= link_to simple_format(sanitize(comment.body, tags: [])), comment_path(comment) %> +

    <%= t("legislation.summary.votes", count: comment.votes_score) %>

    +
    + <% 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) %>

    + + <%= link_to t("legislation.summary.comments", count: question.comments.count), + polymorphic_path(question, anchor: "comments") %> + +
    + + <%= 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..97c211d7a --- /dev/null +++ b/app/views/legislation/processes/summary.html.erb @@ -0,0 +1,25 @@ +<% 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? %> +
    + <% 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/config/locales/en/legislation.yml b/config/locales/en/legislation.yml index 967f6d1d9..665cb35ee 100644 --- a/config/locales/en/legislation.yml +++ b/config/locales/en/legislation.yml @@ -118,3 +118,31 @@ 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" + 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..2c88e185b 100644 --- a/config/locales/es/legislation.yml +++ b/config/locales/es/legislation.yml @@ -118,3 +118,31 @@ 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" + 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/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..0763c16ba --- /dev/null +++ b/spec/system/legislation/summary_spec.rb @@ -0,0 +1,172 @@ +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 + end + + def annotation_ranges(start_offset, end_offset) + [{ "start" => "/p[1]", "startOffset" => start_offset, "end" => "/p[1]", "endOffset" => end_offset }] + end +end From b2b64ca8a04cc775867b8aaeda7afedf6d62eb11 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Javi=20Mart=C3=ADn?= Date: Tue, 25 Aug 2020 16:38:30 +0200 Subject: [PATCH 3/3] Add link to download summary in XLSX format again It was removed in commit 128a8164 alongside everything related to the legislation process summary. Co-Authored-By: taitus --- Gemfile | 2 + Gemfile.lock | 10 ++++ .../stylesheets/legislation_process.scss | 7 +++ .../legislation/processes_controller.rb | 5 ++ .../legislation/processes/summary.html.erb | 4 ++ .../legislation/processes/summary.xlsx.axlsx | 50 +++++++++++++++++++ config/locales/en/legislation.yml | 1 + config/locales/es/legislation.yml | 1 + .../legislation/processes_controller_spec.rb | 13 +++++ spec/system/legislation/summary_spec.rb | 7 +++ 10 files changed, 100 insertions(+) create mode 100644 app/views/legislation/processes/summary.xlsx.axlsx create mode 100644 spec/controllers/legislation/processes_controller_spec.rb 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/legislation_process.scss b/app/assets/stylesheets/legislation_process.scss index 81c090a5f..8f3199c06 100644 --- a/app/assets/stylesheets/legislation_process.scss +++ b/app/assets/stylesheets/legislation_process.scss @@ -1086,4 +1086,11 @@ padding: rem-calc(12); } } + + .download-button { + margin-bottom: 0; + margin-left: 50%; + margin-top: $line-height; + transform: translateX(-50%); + } } diff --git a/app/controllers/legislation/processes_controller.rb b/app/controllers/legislation/processes_controller.rb index 2c8f01076..0edd2cc5a 100644 --- a/app/controllers/legislation/processes_controller.rb +++ b/app/controllers/legislation/processes_controller.rb @@ -101,6 +101,11 @@ class Legislation::ProcessesController < Legislation::BaseController @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 diff --git a/app/views/legislation/processes/summary.html.erb b/app/views/legislation/processes/summary.html.erb index 97c211d7a..81145e8fe 100644 --- a/app/views/legislation/processes/summary.html.erb +++ b/app/views/legislation/processes/summary.html.erb @@ -6,6 +6,10 @@ <% 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 %> 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 665cb35ee..263dd4662 100644 --- a/config/locales/en/legislation.yml +++ b/config/locales/en/legislation.yml @@ -139,6 +139,7 @@ en: zero: "No comments" one: "%{count} comment" other: "%{count} comments" + download: "Download summary" top_comments: zero: "No comments" one: "%{count} comment" diff --git a/config/locales/es/legislation.yml b/config/locales/es/legislation.yml index 2c88e185b..480fce46b 100644 --- a/config/locales/es/legislation.yml +++ b/config/locales/es/legislation.yml @@ -139,6 +139,7 @@ es: zero: "No hay comentarios" one: "%{count} comentario" other: "%{count} comentarios" + download: "Descargar resumen" top_comments: zero: "No hay comentarios" one: "%{count} comentario" 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/system/legislation/summary_spec.rb b/spec/system/legislation/summary_spec.rb index 0763c16ba..880c7ee4e 100644 --- a/spec/system/legislation/summary_spec.rb +++ b/spec/system/legislation/summary_spec.rb @@ -164,6 +164,13 @@ describe "Legislation" do 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)