decidim-proposals 0.0.2 → 0.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (43) hide show
  1. checksums.yaml +4 -4
  2. data/app/assets/stylesheets/decidim/proposals/social_share.css.scss +5 -0
  3. data/app/commands/decidim/proposals/admin/answer_proposal.rb +43 -0
  4. data/app/commands/decidim/proposals/create_proposal.rb +1 -0
  5. data/app/controllers/decidim/proposals/admin/proposal_answers_controller.rb +37 -0
  6. data/app/controllers/decidim/proposals/admin/proposals_controller.rb +1 -0
  7. data/app/controllers/decidim/proposals/proposal_votes_controller.rb +18 -7
  8. data/app/controllers/decidim/proposals/proposals_controller.rb +8 -7
  9. data/app/forms/decidim/proposals/admin/proposal_answer_form.rb +18 -0
  10. data/app/forms/decidim/proposals/proposal_form.rb +1 -0
  11. data/app/helpers/decidim/proposals/application_helper.rb +17 -0
  12. data/app/helpers/decidim/proposals/proposal_votes_helper.rb +19 -0
  13. data/app/models/decidim/proposals/abilities/current_user.rb +59 -0
  14. data/app/models/decidim/proposals/proposal.rb +30 -33
  15. data/app/models/decidim/proposals/proposal_vote.rb +2 -0
  16. data/app/services/decidim/proposals/proposal_search.rb +11 -0
  17. data/app/views/decidim/proposals/admin/proposal_answers/edit.html.erb +15 -0
  18. data/app/views/decidim/proposals/admin/proposals/index.html.erb +8 -0
  19. data/app/views/decidim/proposals/proposal_votes/update_buttons_and_counters.js.erb +20 -0
  20. data/app/views/decidim/proposals/proposals/_filters.html.erb +3 -1
  21. data/app/views/decidim/proposals/proposals/_filters_small_view.html.erb +18 -0
  22. data/app/views/decidim/proposals/proposals/_linked_proposals.html.erb +27 -0
  23. data/app/views/decidim/proposals/proposals/_proposal.html.erb +3 -2
  24. data/app/views/decidim/proposals/proposals/_proposal_badge.html.erb +3 -0
  25. data/app/views/decidim/proposals/proposals/_remaining_votes_count.html.erb +1 -0
  26. data/app/views/decidim/proposals/proposals/_share.html.erb +1 -1
  27. data/app/views/decidim/proposals/proposals/_vote_button.html.erb +16 -4
  28. data/app/views/decidim/proposals/proposals/_votes_limit.html.erb +23 -0
  29. data/app/views/decidim/proposals/proposals/index.html.erb +13 -3
  30. data/app/views/decidim/proposals/proposals/new.html.erb +6 -0
  31. data/app/views/decidim/proposals/proposals/show.html.erb +15 -2
  32. data/config/i18n-tasks.yml +3 -0
  33. data/config/locales/ca.yml +54 -1
  34. data/config/locales/en.yml +54 -0
  35. data/config/locales/es.yml +54 -1
  36. data/db/migrate/20170120151202_add_user_group_id_to_proposals.rb +5 -0
  37. data/db/migrate/20170131092413_add_answers_to_proposals.rb +7 -0
  38. data/lib/decidim/proposals/admin_engine.rb +3 -1
  39. data/lib/decidim/proposals/engine.rb +7 -1
  40. data/lib/decidim/proposals/feature.rb +28 -1
  41. data/lib/decidim/proposals/test/factories.rb +83 -0
  42. metadata +64 -9
  43. data/app/views/decidim/proposals/proposal_votes/create.js.erb +0 -5
@@ -46,6 +46,17 @@ module Decidim
46
46
  end
47
47
  end
48
48
 
49
+ # Handle the state filter
50
+ def search_state
51
+ if state == "accepted"
52
+ query.accepted
53
+ elsif state == "rejected"
54
+ query.rejected
55
+ else # Assume 'all'
56
+ query
57
+ end
58
+ end
59
+
49
60
  # Returns the random proposals for the current page.
50
61
  def results
51
62
  @proposals ||= Proposal.transaction do
@@ -0,0 +1,15 @@
1
+ <h3><%= t ".title", title: proposal.title %></h3>
2
+
3
+ <%= form_for(@form, url: proposal_proposal_answer_path(proposal, @form)) do |f| %>
4
+ <div class="field">
5
+ <%= f.collection_radio_buttons :state, [["accepted", t('.accepted')], ["rejected", t('.rejected')]], :first, :last, prompt: true %>
6
+ </div>
7
+
8
+ <div class="field">
9
+ <%= f.translated :text_area, :answer, autofocus: true, rows: 15 %>
10
+ </div>
11
+
12
+ <div class="actions">
13
+ <%= f.submit t(".answer_proposal") %>
14
+ </div>
15
+ <% end %>
@@ -10,6 +10,8 @@
10
10
  <th><%= t("models.proposal.fields.title", scope: "decidim.proposals") %></th>
11
11
  <th><%= t("models.proposal.fields.category", scope: "decidim.proposals") %></th>
12
12
  <th><%= t("models.proposal.fields.scope", scope: "decidim.proposals") %></th>
13
+ <th><%= t("models.proposal.fields.state", scope: "decidim.proposals") %></th>
14
+ <th class="actions"><%= t("actions.title", scope: "decidim.proposals") %></th>
13
15
  </tr>
14
16
  </thead>
15
17
  <tbody>
@@ -28,6 +30,12 @@
28
30
  <%= translated_attribute proposal.scope.name %>
29
31
  <% end %>
30
32
  </td>
33
+ <td>
34
+ <%= humanize_proposal_state proposal.state %>
35
+ </td>
36
+ <td class="actions">
37
+ <%= link_to t("actions.answer", scope: "decidim.proposals"), edit_proposal_proposal_answer_path(proposal_id: proposal.id, id: proposal.id) if can? :update, current_feature %>
38
+ </td>
31
39
  </tr>
32
40
  <% end %>
33
41
  </tbody>
@@ -0,0 +1,20 @@
1
+ var $proposalVotesCount = $('#proposal-<%= proposal.id %>-votes-count');
2
+ var $proposalVoteButton = $('#proposal-<%= proposal.id %>-vote-button');
3
+
4
+ $proposalVotesCount.html('<%= j(render partial: 'decidim/proposals/proposals/votes_count', locals: { proposal: proposal, from_proposals_list: @from_proposals_list }) %>');
5
+ $proposalVoteButton.html('<%= j(render partial: 'decidim/proposals/proposals/vote_button', locals: { proposal: proposal, from_proposals_list: @from_proposals_list }) %>');
6
+
7
+ <% if vote_limit_enabled? %>
8
+ var $remainingVotesCount = $('#remaining-votes-count');
9
+ var $notVotedButtons = $('.card__button.button').not('.success');
10
+
11
+ $remainingVotesCount.html('<%= j(render partial: 'decidim/proposals/proposals/remaining_votes_count') %>');
12
+
13
+ <% if remaining_votes_count_for(current_user) == 0 %>
14
+ $notVotedButtons.attr('disabled', true);
15
+ $notVotedButtons.val('<%= t('decidim.proposals.proposals.vote_button.no_votes_remaining') %>');
16
+ <% else %>
17
+ $notVotedButtons.attr('disabled', false);
18
+ $notVotedButtons.val('<%= t('decidim.proposals.proposals.vote_button.vote') %>');
19
+ <% end %>
20
+ <% end %>
@@ -14,12 +14,14 @@
14
14
 
15
15
  <%= form.collection_radio_buttons :origin, [["all", t('.all')], ["official", t('.official')], ["citizenship", t('.citizenship')]], :first, :last, legend_title: t('.origin') %>
16
16
 
17
+ <%= form.collection_radio_buttons :state, [["all", t('.all')], ["accepted", t('.accepted')], ["rejected", t('.rejected')]], :first, :last, legend_title: t('.state') %>
18
+
17
19
  <% if current_user && current_settings.votes_enabled? %>
18
20
  <%= form.collection_check_boxes :activity, [["voted", t('.voted')]], :first, :last, legend_title: t('.activity') %>
19
21
  <% end %>
20
22
 
21
23
  <% if current_feature.categories.any? %>
22
- <%= form.categories_select :category_id, current_feature.categories, legend_title: t('.category'), disable_parents: false, label: false, include_blank: true %>
24
+ <%= form.categories_select :category_id, current_feature.categories, legend_title: t('.category'), disable_parents: false, label: false, include_blank: true %>
23
25
  <% end %>
24
26
 
25
27
  <%= form.hidden_field :random_seed %>
@@ -0,0 +1,18 @@
1
+ <div class="filters-controls hide-for-mediumlarge">
2
+ <button data-open="filter-box" class="filters-controls__trigger">
3
+ <%= t ".filter" %>
4
+ <%= icon "caret-bottom", class: "icon--small float-right", aria_label: t('.unfold'), role: "img" %>
5
+ </button>
6
+ </div>
7
+
8
+ <div class="reveal" id="filter-box" data-reveal>
9
+ <div class="reveal__header">
10
+ <h3 class="reveal__title"><%= t ".filter_for" %>:</h3>
11
+ <button class="close-button" data-close aria-label="<%= t(".close_modal") %>" type="button">
12
+ <span aria-hidden="true">&times;</span>
13
+ </button>
14
+ </div>
15
+ <div class="filters">
16
+ <%= render partial: "filters" %>
17
+ </div>
18
+ </div>
@@ -0,0 +1,27 @@
1
+ <div class="card card--action card--list">
2
+ <% resources.each do |proposal| %>
3
+ <div class="card--list__item">
4
+ <div class="card--list__text">
5
+ <%= link_to decidim_resource_path(proposal) do %>
6
+ <%= icon "proposals", class: "card--list__icon", remove_icon_class: true %>
7
+ <% end %>
8
+ <div>
9
+ <%= link_to decidim_resource_path(proposal), class: "card__link" do %>
10
+ <h5 class="card--list__heading"><%= proposal.title %></h5>
11
+ <% end %>
12
+ <div class="author">
13
+ <span class="author__avatar">
14
+ <%= image_tag proposal.author_avatar_url %>
15
+ </span>
16
+ <span class="author__name">
17
+ <%= proposal.author_name %>
18
+ </span>
19
+ </div>
20
+ </div>
21
+ </div>
22
+ <div class="card--list__data">
23
+ <%==t(".proposal_votes", count: proposal.votes.size) %>
24
+ </div>
25
+ </div>
26
+ <% end %>
27
+ </div>
@@ -17,6 +17,7 @@
17
17
  </div>
18
18
  </div>
19
19
  </div>
20
+ <%= render partial: "proposal_badge", locals: { proposal: proposal } %>
20
21
  <p><%= truncate(proposal.body, length: 100) %></p>
21
22
  <% if proposal.category %>
22
23
  <ul class="tags tags--proposal">
@@ -33,9 +34,9 @@
33
34
  <div id="proposal-<%= proposal.id %>-vote-button">
34
35
  <%= render partial: "vote_button", locals: { proposal: proposal, from_proposals_list: true } %>
35
36
  </div>
36
- <% else %>
37
+ <% elsif !current_settings.votes_enabled? || current_settings.votes_enabled? && current_settings.votes_blocked? %>
37
38
  <div class="card__support__data"></div>
38
- <%= link_to t(".view_proposal"), proposal, class: "card__button button small secondary" %>
39
+ <%= link_to t(".view_proposal"), proposal, class: "card__button button small secondary" %>
39
40
  <% end %>
40
41
  </div>
41
42
  </div>
@@ -0,0 +1,3 @@
1
+ <% if proposal.answered? %>
2
+ <span class="<%= (proposal.accepted? ? 'success' : 'warning') %> label proposal-status"><%= humanize_proposal_state proposal.state %></span>
3
+ <% end %>
@@ -0,0 +1 @@
1
+ <%= remaining_votes_count_for(current_user) %>
@@ -1,5 +1,5 @@
1
1
  <div class="text-center">
2
- <button class="link text-center" data-open="processShare">
2
+ <button class="share-link link text-center" data-open="processShare">
3
3
  <%= t(".share") %>
4
4
  <%= icon "share", class: "icon--after"%>
5
5
  </button>
@@ -1,10 +1,22 @@
1
1
  <% if current_user %>
2
2
  <% if proposal.voted_by? current_user %>
3
- <button class="card__button button <%= vote_button_classes(from_proposals_list) %> success">
4
- <%= t('.already_voted') %>
5
- </button>
3
+ <% if vote_limit_enabled? %>
4
+ <%= button_to t('.already_voted'), proposal_proposal_vote_path(proposal_id: proposal, from_proposals_list: from_proposals_list), method: :delete, remote: true, data: { disable: true }, class: "card__button button #{vote_button_classes(from_proposals_list)} success" %>
5
+ <% else %>
6
+ <button class="card__button button <%= vote_button_classes(from_proposals_list) %> success">
7
+ <%= t('.already_voted') %>
8
+ </button>
9
+ <% end %>
6
10
  <% else %>
7
- <%= button_to t('.vote'), proposal_proposal_votes_path(proposal_id: proposal, from_proposals_list: from_proposals_list), remote: true, data: { disable: true }, class: "card__button button #{vote_button_classes(from_proposals_list)}" %>
11
+ <% if vote_limit_enabled? && remaining_votes_count_for(current_user) == 0 %>
12
+ <%= button_to t('.no_votes_remaining'), proposal_proposal_vote_path(proposal_id: proposal, from_proposals_list: from_proposals_list), remote: true, data: { disable: true }, class: "card__button button #{vote_button_classes(from_proposals_list)}", disabled: true %>
13
+ <% elsif current_settings.votes_blocked? %>
14
+ <button class="card__button button <%= vote_button_classes(from_proposals_list) %> disabled">
15
+ <%= t('.votes_blocked') %>
16
+ </button>
17
+ <% else %>
18
+ <%= button_to t('.vote'), proposal_proposal_vote_path(proposal_id: proposal, from_proposals_list: from_proposals_list), remote: true, data: { disable: true }, class: "card__button button #{vote_button_classes(from_proposals_list)}" %>
19
+ <% end %>
8
20
  <% end %>
9
21
  <% else %>
10
22
  <button class="card__button button <%= vote_button_classes(from_proposals_list) %>" data-toggle="loginModal">
@@ -0,0 +1,23 @@
1
+ <% if vote_limit_enabled? %>
2
+ <div class="row column">
3
+ <div class="callout secondary">
4
+ <div class="row">
5
+ <div class="columns medium-8 large-9">
6
+ <h3 class="heading3"><%= t('.vote_limit.title', limit: feature_settings.vote_limit) %></h3>
7
+ <p><%= t('.vote_limit.description', limit: feature_settings.vote_limit) %></p>
8
+ </div>
9
+ <div class="columns medium-4 large-3">
10
+ <div class="card card--nomargin text-center">
11
+ <div class="card__content">
12
+ <span class="definition-data__title"><%= t('.vote_limit.left', limit: feature_settings.vote_limit) %></span>
13
+ <span id="remaining-votes-count" class="extra__suport-number">
14
+ <%= render partial: "remaining_votes_count" %>
15
+ </span>
16
+ <span class="extra__suport-text"><%= t('.vote_limit.votes') %></span>
17
+ </div>
18
+ </div>
19
+ </div>
20
+ </div>
21
+ </div>
22
+ </div>
23
+ <% end %>
@@ -1,16 +1,25 @@
1
+ <%= render partial: "votes_limit" %>
1
2
  <div class="row columns">
2
3
  <div class="title-action">
3
4
  <h2 id="proposals-count" class="title-action__title section-heading">
4
5
  <%= render partial: "count" %>
5
6
  </h2>
6
- <%= link_to new_proposal_path, class: "title-action__action button small hollow" do %>
7
- <%= t(".new_proposal") %>
8
- <%= icon "plus" %>
7
+ <% if can? :create, Decidim::Proposals::Proposal %>
8
+ <%= link_to new_proposal_path, class: "title-action__action button small hollow" do %>
9
+ <%= t(".new_proposal") %>
10
+ <%= icon "plus" %>
11
+ <% end %>
12
+ <% else %>
13
+ <span class="title-action__action button small hollow disabled">
14
+ <%= t(".new_proposal") %>
15
+ <%= icon "plus" %>
16
+ </span>
9
17
  <% end %>
10
18
  </div>
11
19
  </div>
12
20
  <div class="row">
13
21
  <div class="columns mediumlarge-4 large-3">
22
+ <%= render partial: "filters_small_view" %>
14
23
  <div class="card card--secondary show-for-mediumlarge" >
15
24
  <%= render partial: "filters" %>
16
25
  </div>
@@ -20,4 +29,5 @@
20
29
  </div>
21
30
  </div>
22
31
 
32
+ <%= javascript_include_tag("decidim/filters") %>
23
33
  <%= render partial: "decidim/shared/login_modal" %>
@@ -30,6 +30,12 @@
30
30
  </div>
31
31
  <% end %>
32
32
 
33
+ <% if current_user.user_groups.verified.any? %>
34
+ <div class="field">
35
+ <%= form.select :user_group_id, current_user.user_groups.verified.map{|g| [g.name, g.id]}, prompt: current_user.name %>
36
+ </div>
37
+ <% end %>
38
+
33
39
  <div class="actions">
34
40
  <%= form.submit t(".send"), class: "button expanded" %>
35
41
  </div>
@@ -3,6 +3,7 @@
3
3
  <% content_for :meta_url, proposal_url(@proposal.id) %>
4
4
  <% content_for :twitter_handler, current_organization.twitter_handler %>
5
5
 
6
+ <%= render partial: "votes_limit" %>
6
7
  <div class="row column view-header">
7
8
  <h2 class="heading2"><%= @proposal.title %></h2>
8
9
  <div class="author-data">
@@ -27,7 +28,7 @@
27
28
  <div id="proposal-<%= @proposal.id %>-votes-count">
28
29
  <%= render partial: "votes_count", locals: { proposal: @proposal, from_proposals_list: false } %>
29
30
  </div>
30
- <div id="proposal-<%= @proposal.id %>-vote-button">
31
+ <div id="proposal-<%= @proposal.id %>-vote-button">
31
32
  <%= render partial: "vote_button", locals: { proposal: @proposal, from_proposals_list: false } %>
32
33
  </div>
33
34
  </div>
@@ -37,6 +38,7 @@
37
38
  </div>
38
39
  <div class="columns mediumlarge-8 mediumlarge-pull-4">
39
40
  <div class="section">
41
+ <%= render partial: "proposal_badge", locals: { proposal: @proposal } %>
40
42
  <p><%= @proposal.body %></p>
41
43
  <% if @proposal.category || @proposal.scope %>
42
44
  <ul class="tags tags--proposal">
@@ -49,11 +51,22 @@
49
51
  </ul>
50
52
  <% end %>
51
53
  </div>
54
+ <% if @proposal.rejected? %>
55
+ <div class="section">
56
+ <div class="callout warning">
57
+ <h5><%= t(".proposal_rejected_reason") %></h5>
58
+ <p><%= translated_attribute @proposal.answer %></p>
59
+ </div>
60
+ </div>
61
+ <% end %>
62
+ <%= linked_resources_for @proposal, :results, "included_proposals" %>
63
+ <%= linked_resources_for @proposal, :projects, "included_proposals" %>
64
+ <%= linked_resources_for @proposal, :meetings, "proposals_from_meeting" %>
52
65
  </div>
53
66
  </div>
54
67
 
55
68
  <%= content_for :expanded do %>
56
- <% if @proposal.commentable? %>
69
+ <% if feature_settings.comments_always_enabled || current_settings.comments_enabled %>
57
70
  <%= comments_for @proposal, arguable: true, votable: true %>
58
71
  <% end %>
59
72
  <% end %>
@@ -3,3 +3,6 @@ locales: [en]
3
3
  ignore_unused:
4
4
  - "decidim.features.proposals.name"
5
5
  - "decidim.features.proposals.settings.*"
6
+ - "decidim.resource_links.*"
7
+ - "activemodel.attributes.proposal.*"
8
+ - "decidim.proposals.answers.*"
@@ -1,19 +1,40 @@
1
1
  ca:
2
+ activemodel:
3
+ attributes:
4
+ proposal:
5
+ body: Cos
6
+ category_id: Categoria
7
+ scope_id: Àmbit
8
+ title: Títol
9
+ user_group_id: Crear proposta
2
10
  decidim:
3
11
  features:
4
12
  proposals:
5
13
  name: Propostes
6
14
  settings:
7
15
  step:
16
+ creation_enabled: Habilitar de creació de propostes
17
+ votes_blocked: Vots bloquejats
8
18
  votes_enabled: Vots habilitats
9
19
  proposals:
10
20
  actions:
21
+ answer: Respondre
11
22
  new: Nova proposta
23
+ title: Accions
12
24
  admin:
13
25
  models:
14
26
  proposal:
15
27
  name: Proposta
28
+ proposal_answers:
29
+ edit:
30
+ accepted: Acceptada
31
+ answer_proposal: Resposta de la proposta
32
+ rejected: Rebutjada
33
+ title: Respondre a la proposta %{title}
16
34
  proposals:
35
+ answer:
36
+ invalid: Hi ha hagut un problema en respondre a aquesta proposta
37
+ success: Proposta resposta amb èxit
17
38
  create:
18
39
  invalid: Hi ha hagut un problema en crear aquesta proposta
19
40
  success: Proposta creada correctament
@@ -25,6 +46,10 @@ ca:
25
46
  new:
26
47
  create: Crear proposta
27
48
  title: Nova proposta
49
+ answers:
50
+ accepted: Acceptada
51
+ not_answered: No resposta
52
+ rejected: Rebutjada
28
53
  create:
29
54
  error: Hi ha hagut errors en desar la proposta.
30
55
  success: Proposta creada correctament.
@@ -34,6 +59,7 @@ ca:
34
59
  category: Categoria
35
60
  official_proposal: Proposta oficial
36
61
  scope: Àmbit
62
+ state: Estat
37
63
  title: Títol
38
64
  proposals:
39
65
  count:
@@ -41,16 +67,28 @@ ca:
41
67
  one: 1 proposta
42
68
  other: "%{count} propostes"
43
69
  filters:
70
+ accepted: Acceptades
44
71
  activity: Activitat
45
72
  all: Tots
46
73
  category: Categoria
47
74
  citizenship: Ciutadania
48
75
  official: Oficial
49
76
  origin: Origen
77
+ rejected: Rebutjades
50
78
  search: Cerca
79
+ state: Estat
51
80
  voted: Votat
81
+ filters_small_view:
82
+ close_modal: Tancar finestra
83
+ filter: Filtra
84
+ filter_for: Filtrar per
85
+ unfold: Desplegar
52
86
  index:
53
87
  new_proposal: Nova proposta
88
+ linked_proposals:
89
+ proposal_votes:
90
+ one: <span class="card--list__data__number">1</span>vot
91
+ other: <span class="card--list__data__number">%{count}</span>vots
54
92
  new:
55
93
  back: Enrere
56
94
  select_a_category: Si us plau, seleccioni una categoria
@@ -63,10 +101,25 @@ ca:
63
101
  close_window: Tanca la finestra
64
102
  share: Compartir
65
103
  share_link: Comparteix l'enllaç
104
+ show:
105
+ proposal_rejected_reason: 'Aquesta proposta ha estat rebutjada perquè:'
66
106
  vote_button:
67
107
  already_voted: Ja has votat
108
+ no_votes_remaining: No hi ha vots restants
68
109
  vote: Votar
110
+ votes_blocked: Votació desactivada
69
111
  votes_count:
70
112
  count:
71
113
  one: VOT
72
- other: VOTS
114
+ other: VOTS
115
+ votes_limit:
116
+ vote_limit:
117
+ description: En lloc de votar tantes propostes com vulgui, només es pot votar fins %{limit} propostes.
118
+ left: Restant
119
+ title: Té %{limit} vots a distribuir
120
+ votes: Vots
121
+ resource_links:
122
+ included_proposals:
123
+ results: 'La proposta apareix en aquests resultats:'
124
+ proposals_from_meeting:
125
+ meetings: Trobades relacionades