decidim 0.0.1.alpha4 → 0.0.1.alpha5

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of decidim might be problematic. Click here for more details.

Files changed (63) hide show
  1. checksums.yaml +4 -4
  2. data/.codeclimate.yml +1 -0
  3. data/.gitignore +2 -0
  4. data/.travis.yml +2 -1
  5. data/Dockerfile +1 -12
  6. data/Gemfile +8 -3
  7. data/Gemfile.common +1 -0
  8. data/Gemfile.lock +49 -38
  9. data/README.md +1 -0
  10. data/decidim-admin/Gemfile +3 -14
  11. data/decidim-admin/Rakefile +0 -5
  12. data/decidim-admin/app/assets/javascripts/decidim/admin.js +4 -3
  13. data/decidim-admin/app/commands/decidim/admin/create_participatory_process.rb +47 -0
  14. data/decidim-admin/app/commands/decidim/admin/update_participatory_process.rb +49 -0
  15. data/decidim-admin/app/controllers/concerns/decidim/needs_authorization.rb +50 -0
  16. data/decidim-admin/app/controllers/decidim/admin/application_controller.rb +2 -0
  17. data/decidim-admin/app/controllers/decidim/admin/dashboard_controller.rb +11 -0
  18. data/decidim-admin/app/controllers/decidim/admin/participatory_processes_controller.rb +85 -0
  19. data/decidim-admin/app/forms/decidim/admin/participatory_process_form.rb +37 -0
  20. data/decidim-admin/app/helpers/decidim/admin/application_helper.rb +2 -0
  21. data/decidim-admin/app/helpers/decidim/admin/attributes_display_helper.rb +62 -0
  22. data/decidim-admin/app/policies/decidim/admin/dashboard_policy.rb +15 -0
  23. data/decidim-admin/app/policies/decidim/admin/participatory_process_policy.rb +57 -0
  24. data/decidim-admin/app/views/decidim/admin/participatory_processes/_form.html.erb +23 -0
  25. data/decidim-admin/app/views/decidim/admin/participatory_processes/edit.html.erb +11 -0
  26. data/decidim-admin/app/views/decidim/admin/participatory_processes/index.html.erb +34 -0
  27. data/decidim-admin/app/views/decidim/admin/participatory_processes/new.html.erb +11 -0
  28. data/decidim-admin/app/views/decidim/admin/participatory_processes/show.html.erb +20 -0
  29. data/decidim-admin/app/views/layouts/decidim/admin/_sidebar.html.erb +1 -0
  30. data/decidim-admin/config/locales/ca.yml +40 -0
  31. data/decidim-admin/config/locales/en.yml +32 -0
  32. data/decidim-admin/config/locales/es.yml +40 -0
  33. data/decidim-admin/config/routes.rb +4 -1
  34. data/decidim-admin/decidim-admin.gemspec +1 -2
  35. data/decidim-admin/lib/decidim/admin/engine.rb +1 -1
  36. data/decidim-admin/spec/features/admin_invite_spec.rb +2 -6
  37. data/decidim-admin/spec/features/manage_participatory_processes_spec.rb +127 -0
  38. data/decidim-admin/spec/policies/dashboard_policy_spec.rb +23 -0
  39. data/decidim-admin/spec/policies/participatory_process_policy_spec.rb +153 -0
  40. data/decidim-dev/Gemfile +3 -14
  41. data/decidim-dev/decidim-dev.gemspec +2 -3
  42. data/decidim-dev/lib/decidim/test/i18n_spec.rb +16 -0
  43. data/decidim-dev/lib/decidim/test/rspec_support/action_mailer.rb +3 -2
  44. data/decidim-dev/lib/decidim/test/rspec_support/warden.rb +1 -0
  45. data/decidim-system/Gemfile +3 -14
  46. data/decidim-system/Rakefile +0 -5
  47. data/decidim-system/app/assets/javascripts/decidim/system.js +4 -3
  48. data/decidim-system/app/commands/decidim/system/register_organization.rb +1 -0
  49. data/decidim-system/app/forms/decidim/system/register_organization_form.rb +2 -1
  50. data/decidim-system/app/views/decidim/system/organizations/new.html.erb +4 -0
  51. data/decidim-system/config/locales/ca.yml +60 -0
  52. data/decidim-system/config/locales/es.yml +60 -0
  53. data/decidim-system/decidim-system.gemspec +1 -2
  54. data/decidim-system/lib/decidim/system/engine.rb +0 -1
  55. data/decidim-system/spec/commands/decidim/system/register_organization_spec.rb +1 -0
  56. data/decidim-system/spec/features/organizations_spec.rb +1 -0
  57. data/decidim.gemspec +1 -0
  58. data/lib/generators/decidim/templates/Gemfile.erb +0 -11
  59. metadata +43 -12
  60. data/common_gemfile.rb +0 -12
  61. data/decidim-admin/Gemfile.lock +0 -383
  62. data/decidim-dev/Gemfile.lock +0 -381
  63. data/decidim-system/Gemfile.lock +0 -377
@@ -0,0 +1,50 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "active_support/concern"
4
+
5
+ module Decidim
6
+ # Shared behaviour for controllers that need authorization to work.
7
+ module NeedsAuthorization
8
+ extend ActiveSupport::Concern
9
+
10
+ included do
11
+ include Pundit
12
+ after_action :verify_authorized
13
+
14
+ rescue_from Pundit::NotAuthorizedError, with: :user_not_authorized
15
+
16
+ private
17
+
18
+ # Overwrites the `policy` method from the `pundit` gem in order to be
19
+ # able to specify which policy class should be used in each case. This is
20
+ # due to `pundit` failing to correctly identify the policy class when the
21
+ # model class name is scoped and the policy class is in a different scope
22
+ # (eg. `Decidim::ParticipatoryProcess` and
23
+ # `Decidim::Admin::ParticipatoryProcessPolicy`). The original method does
24
+ # not let us specify the correct class.
25
+ #
26
+ # Remember that, in order to make this work, you'll need to define the
27
+ # `policy_class` method in the controller, which should only return a
28
+ # policy class name.
29
+ #
30
+ # record - the record that will be evaluated against the policy class.
31
+ def policy(record)
32
+ policies[record] ||= policy_class.new(current_user, record)
33
+ end
34
+
35
+ # Needed in order to make the `policy` method work. Overwirite it in the
36
+ # given controller and make it return a Policy class.
37
+ def policy_class
38
+ raise NotImplementedError, "Define this method and make it return a policy class name in order to make it work"
39
+ end
40
+
41
+ # Handles the case when a user visits a path that is not allowed to them.
42
+ # Redirects the user to the root path and shows a flash message telling
43
+ # them they are not authorized.
44
+ def user_not_authorized
45
+ flash[:alert] = t("actions.unauthorized", scope: "decidim.admin")
46
+ redirect_to(request.referrer || decidim_admin.root_path)
47
+ end
48
+ end
49
+ end
50
+ end
@@ -4,6 +4,8 @@ module Decidim
4
4
  # The main application controller that inherits from Rails.
5
5
  class ApplicationController < ActionController::Base
6
6
  include NeedsOrganization
7
+ include NeedsAuthorization
8
+
7
9
  protect_from_forgery with: :exception, prepend: true
8
10
  end
9
11
  end
@@ -3,7 +3,18 @@ require_dependency "decidim/admin/application_controller"
3
3
 
4
4
  module Decidim
5
5
  module Admin
6
+ # Controller that shows a simple dashboard.
7
+ #
6
8
  class DashboardController < ApplicationController
9
+ def show
10
+ authorize :dashboard
11
+ end
12
+
13
+ private
14
+
15
+ def policy_class
16
+ Decidim::Admin::DashboardPolicy
17
+ end
7
18
  end
8
19
  end
9
20
  end
@@ -0,0 +1,85 @@
1
+ # frozen_string_literal: true
2
+ require_dependency "decidim/admin/application_controller"
3
+
4
+ module Decidim
5
+ module Admin
6
+ # Controller that allows managing all the Admins.
7
+ #
8
+ class ParticipatoryProcessesController < ApplicationController
9
+ def index
10
+ @participatory_processes = collection
11
+ authorize @participatory_processes
12
+ end
13
+
14
+ def new
15
+ @form = ParticipatoryProcessForm.new
16
+ authorize ParticipatoryProcess
17
+ end
18
+
19
+ def create
20
+ @form = ParticipatoryProcessForm.from_params(params)
21
+ authorize ParticipatoryProcess
22
+
23
+ CreateParticipatoryProcess.call(@form, current_organization) do
24
+ on(:ok) do
25
+ flash[:notice] = I18n.t("participatory_processes.create.success", scope: "decidim.admin")
26
+ redirect_to participatory_processes_path
27
+ end
28
+
29
+ on(:invalid) do
30
+ flash.now[:alert] = I18n.t("participatory_processes.create.error", scope: "decidim.admin")
31
+ render :new
32
+ end
33
+ end
34
+ end
35
+
36
+ def edit
37
+ @participatory_process = collection.find(params[:id])
38
+ authorize @participatory_process
39
+ @form = ParticipatoryProcessForm.from_model(@participatory_process)
40
+ end
41
+
42
+ def update
43
+ @participatory_process = collection.find(params[:id])
44
+ authorize @participatory_process
45
+ @form = ParticipatoryProcessForm.from_params(params)
46
+
47
+ UpdateParticipatoryProcess.call(@participatory_process, @form) do
48
+ on(:ok) do
49
+ flash[:notice] = I18n.t("participatory_processes.update.success", scope: "decidim.admin")
50
+ redirect_to participatory_processes_path
51
+ end
52
+
53
+ on(:invalid) do
54
+ flash.now[:alert] = I18n.t("participatory_processes.update.error", scope: "decidim.admin")
55
+ render :edit
56
+ end
57
+ end
58
+ end
59
+
60
+ def show
61
+ @participatory_process = collection.find(params[:id])
62
+ authorize @participatory_process
63
+ end
64
+
65
+ def destroy
66
+ @participatory_process = collection.find(params[:id]).destroy!
67
+ authorize @participatory_process
68
+
69
+ flash[:notice] = I18n.t("participatory_processes.destroy.success", scope: "decidim.admin")
70
+
71
+ redirect_to participatory_processes_path
72
+ end
73
+
74
+ private
75
+
76
+ def collection
77
+ current_organization.participatory_processes
78
+ end
79
+
80
+ def policy_class
81
+ Decidim::Admin::ParticipatoryProcessPolicy
82
+ end
83
+ end
84
+ end
85
+ end
@@ -0,0 +1,37 @@
1
+ # frozen_string_literal: true
2
+ module Decidim
3
+ module Admin
4
+ # A form object used to create participatory processes from the admin
5
+ # dashboard.
6
+ #
7
+ class ParticipatoryProcessForm < Rectify::Form
8
+ include TranslatableAttributes
9
+
10
+ translatable_attribute :title, String
11
+ translatable_attribute :subtitle, String
12
+ translatable_attribute :description, String
13
+ translatable_attribute :short_description, String
14
+
15
+ mimic :participatory_process
16
+
17
+ attribute :slug, String
18
+ attribute :hashtag, String
19
+
20
+ validates :slug, presence: true
21
+ translatable_validates :title, :subtitle, :description, :short_description, presence: true
22
+
23
+ validate :slug, :slug_uniqueness
24
+
25
+ private
26
+
27
+ def slug_uniqueness
28
+ return unless ParticipatoryProcess.where(slug: slug).where.not(id: id).any?
29
+
30
+ errors.add(
31
+ :slug,
32
+ I18n.t("models.participatory_process.validations.slug_uniqueness", scope: "decidim.admin")
33
+ )
34
+ end
35
+ end
36
+ end
37
+ end
@@ -4,6 +4,8 @@ module Decidim
4
4
  # Custom helpers, scoped to the admin panel.
5
5
  #
6
6
  module ApplicationHelper
7
+ include Decidim::TranslationsHelper
8
+
7
9
  def title
8
10
  current_organization.name
9
11
  end
@@ -0,0 +1,62 @@
1
+ # frozen_string_literal: true
2
+ module Decidim
3
+ module Admin
4
+ # Custom helpers, scoped to the admin panel.
5
+ #
6
+ module AttributesDisplayHelper
7
+ # Displays the given attributes list in a list. This is a simple
8
+ # `show_for` alternative, so there's no way to modify how an attribute is
9
+ # shown and there is no intention on adding this. It is intnded to be
10
+ # used inside a `dl` HTML tag, so you can customize how a specific
11
+ # attribute has to be shown directly:
12
+ #
13
+ # <dl>
14
+ # <%= display_for @post, :title, :body %>
15
+ # <dt>Comments number</dt>
16
+ # <dd>2</dd>
17
+ # </dl>
18
+ #
19
+ # This will render this HTML:
20
+ #
21
+ # <dl>
22
+ # <dt>Title</dt>
23
+ # <dd>Hello, world!</dd>
24
+ # <dt>Body</dt>
25
+ # <dd>Lorem ipsum dolor sit amet...</dd>
26
+ # <dt>Comments number</dt>
27
+ # <dd>2</dd>
28
+ # </dl>
29
+ #
30
+ # record - any Ruby object that needs some attributes rendered
31
+ # attrs - a list of N attributes of the `record`.
32
+ def display_for(record, *attrs)
33
+ attrs.map do |attr|
34
+ if record.column_for_attribute(attr).type == :hstore
35
+ I18n.available_locales.map do |locale|
36
+ content_tag(:dt, record.class.human_attribute_name(attr) + " (#{locale})") +
37
+ display_value(record, attr, locale)
38
+ end.reduce(:+)
39
+ else
40
+ display_label(record, attr) + display_value(record, attr)
41
+ end
42
+ end.reduce(:+)
43
+ end
44
+
45
+ private
46
+
47
+ # Private: Holds the logic to render a label for a given attribute.
48
+ def display_label(record, attr)
49
+ content_tag(:dt, record.class.human_attribute_name(attr))
50
+ end
51
+
52
+ # Private: Holds the logic to render the attribute value.
53
+ def display_value(record, attr, locale = nil)
54
+ return I18n.with_locale(locale) do
55
+ content_tag(:dd, translated_attribute(record.send(attr)).try(:html_safe))
56
+ end if locale
57
+
58
+ content_tag(:dd, record.send(attr).try(:html_safe))
59
+ end
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+ module Decidim
3
+ module Admin
4
+ # A policy to define all the authorizations regarding a
5
+ # ParticipatoryProcess, to be used with Pundit.
6
+ class DashboardPolicy < ApplicationPolicy
7
+ # Checks if the user can see the admin dashboard.
8
+ #
9
+ # Returns a Boolean.
10
+ def show?
11
+ user.roles.include?("admin")
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,57 @@
1
+ # frozen_string_literal: true
2
+ module Decidim
3
+ module Admin
4
+ # A policy to define all the authorizations regarding a
5
+ # ParticipatoryProcess, to be used with Pundit.
6
+ class ParticipatoryProcessPolicy < ApplicationPolicy
7
+ # Checks if the user can see the form for participatory process creation.
8
+ #
9
+ # Returns a Boolean.
10
+ def new?
11
+ user.roles.include?("admin")
12
+ end
13
+
14
+ # Checks if the user can create a participatory process.
15
+ #
16
+ # Returns a Boolean.
17
+ def create?
18
+ user.roles.include?("admin")
19
+ end
20
+
21
+ # Checks if the user can list a participatory process.
22
+ #
23
+ # Returns a Boolean.
24
+ def index?
25
+ user.roles.include?("admin") && user.organization == record.first.organization
26
+ end
27
+
28
+ # Checks if the user can see a participatory process.
29
+ #
30
+ # Returns a Boolean.
31
+ def show?
32
+ user.roles.include?("admin") && user.organization == record.organization
33
+ end
34
+
35
+ # Checks if the user can edit a participatory process.
36
+ #
37
+ # Returns a Boolean.
38
+ def edit?
39
+ user.roles.include?("admin") && user.organization == record.organization
40
+ end
41
+
42
+ # Checks if the user can update a participatory process.
43
+ #
44
+ # Returns a Boolean.
45
+ def update?
46
+ user.roles.include?("admin") && user.organization == record.organization
47
+ end
48
+
49
+ # Checks if the user can destroy a participatory process.
50
+ #
51
+ # Returns a Boolean.
52
+ def destroy?
53
+ user.roles.include?("admin") && user.organization == record.organization
54
+ end
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,23 @@
1
+ <div class="field">
2
+ <%= form.translated :text_field, :title, autofocus: true %>
3
+ </div>
4
+
5
+ <div class="field">
6
+ <%= form.translated :text_field, :subtitle %>
7
+ </div>
8
+
9
+ <div class="field">
10
+ <%= form.text_field :slug %>
11
+ </div>
12
+
13
+ <div class="field">
14
+ <%= form.text_field :hashtag %>
15
+ </div>
16
+
17
+ <div class="field">
18
+ <%= form.translated :text_area, :short_description %>
19
+ </div>
20
+
21
+ <div class="field">
22
+ <%= form.translated :text_area, :description %>
23
+ </div>
@@ -0,0 +1,11 @@
1
+ <% content_for :title do %>
2
+ <h2><%= t ".title" %></h2>
3
+ <% end %>
4
+
5
+ <%= form_for(@form) do |f| %>
6
+ <%= render partial: 'form', object: f %>
7
+
8
+ <div class="actions">
9
+ <%= f.submit t(".update") %>
10
+ </div>
11
+ <% end %>
@@ -0,0 +1,34 @@
1
+ <% content_for :title do %>
2
+ <h2><%= t "decidim.admin.titles.participatory_processes" %></h2>
3
+ <% end %>
4
+
5
+ <div class="actions title">
6
+ <%= link_to t("actions.new", scope: "decidim.admin", name: t("models.participatory_process.name", scope: "decidim.admin")), ['new', 'participatory_process'], class: 'new' %>
7
+ </div>
8
+
9
+ <table class="stack">
10
+ <thead>
11
+ <tr>
12
+ <th><%= t("models.participatory_process.fields.title", scope: "decidim.admin") %></th>
13
+ <th><%= t("models.participatory_process.fields.created_at", scope: "decidim.admin") %></th>
14
+ <th class="actions"><%= t("actions.title", scope: "decidim.admin") %></th>
15
+ </tr>
16
+ </thead>
17
+ <tbody>
18
+ <% @participatory_processes.each do |process| %>
19
+ <tr>
20
+ <td>
21
+ <%= link_to translated_attribute(process.title), process %><br />
22
+ </td>
23
+ <td>
24
+ <%= l process.created_at, format: :short %>
25
+ </td>
26
+ <td class="actions">
27
+ <%= link_to_if policy(process).edit?, t("actions.edit", scope: "decidim.admin"), ['edit', process] %>
28
+
29
+ <%= link_to_if policy(process).destroy?, t("actions.destroy", scope: "decidim.admin"), process, method: :delete, class: "small alert button", data: { confirm: t("actions.confirm_destroy", scope: "decidim.admin") } %>
30
+ </td>
31
+ </tr>
32
+ <% end %>
33
+ </tbody>
34
+ </table>
@@ -0,0 +1,11 @@
1
+ <% content_for :title do %>
2
+ <h2><%= t ".title" %></h2>
3
+ <% end %>
4
+
5
+ <%= form_for(@form) do |f| %>
6
+ <%= render partial: 'form', object: f %>
7
+
8
+ <div class="actions">
9
+ <%= f.submit t(".create") %>
10
+ </div>
11
+ <% end %>
@@ -0,0 +1,20 @@
1
+ <% content_for :title do %>
2
+ <h2><%= link_to translated_attribute(@participatory_process.title), @participatory_process %></h2>
3
+ <h3 class="subheader"><%= translated_attribute(@participatory_process.subtitle) %></h3>
4
+ <% end %>
5
+
6
+ <div class="actions">
7
+ <hr />
8
+ <%= link_to_if policy(@participatory_process).edit?, t("decidim.admin.actions.edit"), ['edit', @participatory_process] %>
9
+ <%= link_to_if policy(@participatory_process).destroy?, t("decidim.admin.actions.destroy"), @participatory_process, method: :delete, class: "alert button", data: { confirm: t("decidim.admin.actions.confirm_destroy") } %>
10
+ </div>
11
+
12
+ <dl>
13
+ <%= display_for @participatory_process,
14
+ :title,
15
+ :subtitle,
16
+ :hashtag,
17
+ :short_description,
18
+ :description
19
+ %>
20
+ </dl>