decidim-core 0.0.6 → 0.0.7

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 (32) hide show
  1. checksums.yaml +4 -4
  2. data/app/assets/javascripts/decidim/form_filter.component.js.es6 +2 -5
  3. data/app/assets/javascripts/decidim/form_filter.component.test.js +24 -49
  4. data/app/assets/stylesheets/decidim/editor.sass +1 -1
  5. data/app/commands/decidim/create_omniauth_registration.rb +2 -1
  6. data/app/commands/decidim/invite_user.rb +3 -2
  7. data/app/commands/decidim/update_account.rb +10 -3
  8. data/app/controllers/concerns/decidim/action_authorization.rb +1 -1
  9. data/app/controllers/decidim/devise/passwords_controller.rb +15 -0
  10. data/app/controllers/decidim/participatory_process_groups_controller.rb +2 -1
  11. data/app/forms/decidim/account_form.rb +1 -0
  12. data/app/models/decidim/identity.rb +11 -1
  13. data/app/models/decidim/organization.rb +2 -0
  14. data/app/models/decidim/user.rb +19 -2
  15. data/app/views/decidim/authorizations/index.html.erb +1 -1
  16. data/app/views/decidim/devise/passwords/edit.html.erb +1 -1
  17. data/app/views/decidim/participatory_processes/_order_by_processes.html.erb +1 -1
  18. data/app/views/layouts/decidim/_language_chooser.html.erb +9 -9
  19. data/config/locales/ca.yml +1 -0
  20. data/config/locales/en.yml +1 -0
  21. data/config/locales/es.yml +1 -0
  22. data/config/locales/eu.yml +147 -11
  23. data/db/migrate/20170405091801_change_decidim_user_email_index_uniqueness.rb +6 -0
  24. data/db/migrate/20170405094028_add_organization_to_identities.rb +5 -0
  25. data/db/migrate/20170405094258_change_decidim_identities_provider_uid_index_uniqueness.rb +12 -0
  26. data/lib/decidim/core/engine.rb +1 -0
  27. data/lib/decidim/core/test/factories.rb +1 -0
  28. data/lib/decidim/core/test/shared_examples/manage_moderations_examples.rb +3 -3
  29. data/lib/decidim/core/version.rb +1 -1
  30. data/lib/decidim/form_builder.rb +16 -12
  31. data/lib/decidim/i18n_exceptions.rb +15 -0
  32. metadata +17 -13
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 3eff907b57b0cab03cceeb32b458e2cfd59e7dc6
4
- data.tar.gz: 133dc98f767565fc733b02f8733c057855cd7d9b
3
+ metadata.gz: 59aba1722a03f74a972774bc6023125925137b79
4
+ data.tar.gz: 71a97c8c7e3b669e142897d9aaf6a6e9f09067be
5
5
  SHA512:
6
- metadata.gz: beb54c792c2e01aa0f08ebe85be2ad2b2b2888b2b102e008b1499e1a769279076bc650b7d14189bde0fd00d59d4d28734876271a81d02ea69c9b5e6746f70218
7
- data.tar.gz: a45d55c72e259bae57b7ba19a2293259a8ca8a9199f3b5c02f906d37e06e6ad7a879ee20cafef940175dc7740aaf37667897e6c1ff9b121d9c4faacd8a9d3e61
6
+ metadata.gz: 2b793c229ce33485dc9ddf1efc8e1af7c5d85fff82b7aa5c959f71b6d6ce2aef597a3ad59234bdcea636eeba942921e1756fa9b30061ec559b2eb044a15ebc63
7
+ data.tar.gz: 467bd6ed6b3f823671ea15fa871641779d345a3d6336774d28665a67046799ca613d8c17fd4c7b84f5270d6392c0a6030151564993f977281f78de5a3780a637
@@ -1,4 +1,4 @@
1
- /* eslint-disable no-div-regex, no-useless-escape, no-param-reassign */
1
+ /* eslint-disable no-div-regex, no-useless-escape, no-param-reassign, id-length */
2
2
 
3
3
  /**
4
4
  * A plain Javascript component that handles the form filter.
@@ -7,9 +7,6 @@
7
7
  */
8
8
  ((exports) => {
9
9
  class FormFilterComponent {
10
- mounted;
11
- $form;
12
-
13
10
  constructor($form) {
14
11
  this.$form = $form;
15
12
  this.mounted = false;
@@ -102,7 +99,7 @@
102
99
  _parseLocationOrderValue() {
103
100
  const url = this._getLocation();
104
101
  const match = url.match(/order=([^&]*)/);
105
- const $orderMenu = $('.order-by .menu');
102
+ const $orderMenu = this.$form.find('.order-by .menu');
106
103
  let order = $orderMenu.find('.menu a:first').data('order');
107
104
 
108
105
  if (match) {
@@ -1,5 +1,7 @@
1
- /* eslint-disable no-unused-expressions */
2
- require('jquery');
1
+ /* global spyOn */
2
+ /* eslint-disable id-length */
3
+ const $ = require('jquery');
4
+
3
5
  require('./history.js.es6');
4
6
  require('./form_filter.component.js.es6');
5
7
 
@@ -13,14 +15,9 @@ describe('FormFilterComponent', () => {
13
15
  let form = `
14
16
  <form id="new_filter" action="/filters" method="get">
15
17
  <fieldset>
16
- <input id="filter_order_start_time_asc" value="asc" type="radio" name="order_start_time" checked />
17
- <input id="filter_order_start_time_desc" value="desc" type="radio" name="order_start_time" />
18
- </fieldset>
19
-
20
- <fieldset>
21
- <input id="filter_scope_id_1" value="1" type="checkbox" name="scope_id[]" />
22
- <input id="filter_scope_id_2" value="2" type="checkbox" name="scope_id[]" />
23
- <input id="filter_scope_id_3" value="3" type="checkbox" name="scope_id[]" />
18
+ <input id="filter_scope_id_1" value="1" type="checkbox" name="filter[scope_id][]" />
19
+ <input id="filter_scope_id_2" value="2" type="checkbox" name="filter[scope_id][]" />
20
+ <input id="filter_scope_id_3" value="3" type="checkbox" name="filter[scope_id][]" />
24
21
  </fieldset>
25
22
 
26
23
  <fieldset>
@@ -36,95 +33,73 @@ describe('FormFilterComponent', () => {
36
33
  });
37
34
 
38
35
  it('exists', () => {
39
- expect(FormFilterComponent).to.exist;
36
+ expect(FormFilterComponent).toBeDefined();
40
37
  });
41
38
 
42
39
  it('initializes unmounted', () => {
43
- expect(subject.mounted).to.be.falsey;
40
+ expect(subject.mounted).toBeFalsy();
44
41
  });
45
42
 
46
43
  it('initializes the formSelector with the given selector', () => {
47
- expect(subject.$form).to.deep.equal($(selector));
44
+ expect(subject.$form).toEqual($(selector));
48
45
  });
49
46
 
50
47
  describe('when mounted', () => {
51
48
  beforeEach(() => {
52
- sinon.spy(subject.$form, 'on');
49
+ spyOn(subject.$form, 'on');
53
50
  subject.mountComponent();
54
51
  });
55
52
 
56
53
  afterEach(() => {
57
- subject.$form.on.restore();
58
54
  subject.unmountComponent();
59
55
  });
60
56
 
61
57
  it('mounts the component', () => {
62
- expect(subject.mounted).to.be.truthy;
58
+ expect(subject.mounted).toBeTruthy();
63
59
  });
64
60
 
65
61
  it('binds the form change event', () => {
66
- expect(subject.$form.on).to.have.been.calledWith('change', 'input, select', subject._onFormChange);
67
- });
68
-
69
- describe('on form change event', () => {
70
- let stub = null;
71
-
72
- beforeEach(() => {
73
- stub = sinon.stub(subject.$form, 'submit');
74
- });
75
-
76
- it('form is submitted', () => {
77
- $(selector).find('input[name=order_start_time][value=desc]').trigger('change');
78
-
79
- expect(stub).to.have.been.calledOnce;
80
- })
62
+ expect(subject.$form.on).toHaveBeenCalledWith('change', 'input, select', subject._onFormChange);
81
63
  });
82
64
 
83
65
  describe('onpopstate event', () => {
84
66
  beforeEach(() => {
85
- sinon.stub(subject.$form, 'submit');
67
+ spyOn(subject.$form, 'submit');
86
68
  });
87
69
 
88
70
  it('clears the form data', () => {
89
- let clearFormSpy = sinon.spy(subject, '_clearForm');
71
+ spyOn(subject, '_clearForm');
90
72
 
91
73
  window.onpopstate();
92
74
 
93
- expect(clearFormSpy).to.have.been.called;
75
+ expect(subject._clearForm).toHaveBeenCalled();
94
76
  });
95
77
 
96
78
  it('sets the correct form fields based on the current location', () => {
97
- sinon.stub(subject, '_getLocation').returns('/filters?order_start_time=desc&scope_id[]=1&scope_id[]=2&filter[category_id]=2')
98
-
79
+ spyOn(subject, '_getLocation').and.returnValue('/filters?filter[scope_id][]=1&scope_id[]=2&filter[category_id]=2');
99
80
  window.onpopstate();
100
81
 
101
- expect($(selector).find('select').val()).to.equal('2');
102
- expect($(selector).find('input[name=order_start_time][value=desc]').attr('checked')).to.be.truthy;
103
- expect($(selector).find('input[name=order_start_time][value=asc]').attr('checked')).to.be.falsey;
104
- expect($(selector).find('input[name=scope_id][value=1]').attr('checked')).to.be.truthy;
105
- expect($(selector).find('input[name=scope_id][value=2]').attr('checked')).to.be.truthy;
106
- expect($(selector).find('input[name=scope_id][value=3]').attr('checked')).to.be.falsey;
82
+ expect($(selector).find('select').val()).toEqual('2');
83
+ expect($(selector).find('input[name="filter[scope_id][]"][value="1"]')[0].checked).toBeTruthy();
84
+ expect($(selector).find('input[name="filter[scope_id][]"][value="2"]')[0].checked).toBeFalsy();
85
+ expect($(selector).find('input[name="filter[scope_id][]"][value="3"]')[0].checked).toBeFalsy();
107
86
  });
108
87
  });
109
88
  });
110
89
 
111
90
  describe('when unmounted', () => {
112
91
  beforeEach(() => {
113
- sinon.spy(subject.$form, 'off');
92
+ spyOn(subject.$form, 'off');
114
93
  subject.mountComponent();
115
94
  subject.unmountComponent();
116
95
  });
117
96
 
118
- afterEach(() => {
119
- subject.$form.off.restore();
120
- })
121
-
122
97
  it('mounts the component', () => {
123
- expect(subject.mounted).to.be.falsey;
98
+ expect(subject.mounted).toBeFalsy();
124
99
  });
125
100
 
126
101
  it('unbinds the form change event', () => {
127
- expect(subject.$form.off).to.have.been.calledWith('change', 'input, select', subject._onFormChange);
102
+ expect(subject.$form.off).toHaveBeenCalledWith('change', 'input, select', subject._onFormChange);
128
103
  });
129
104
  });
130
105
 
@@ -1,4 +1,4 @@
1
1
  @import "quill.snow"
2
2
 
3
3
  .editor-container
4
- margin-bottom: 1rem
4
+ margin-bottom: 1.5rem
@@ -63,7 +63,8 @@ module Decidim
63
63
  def create_identity
64
64
  @user.identities.create!(
65
65
  provider: form.provider,
66
- uid: form.uid
66
+ uid: form.uid,
67
+ organization: organization
67
68
  )
68
69
  end
69
70
 
@@ -35,7 +35,7 @@ module Decidim
35
35
  end
36
36
 
37
37
  def invite_user
38
- @user = Decidim::User.invite!(
38
+ @user = Decidim::User.create(
39
39
  {
40
40
  name: form.name,
41
41
  email: form.email.downcase,
@@ -43,7 +43,8 @@ module Decidim
43
43
  roles: form.roles,
44
44
  comments_notifications: true,
45
45
  replies_notifications: true
46
- },
46
+ })
47
+ @user.invite!(
47
48
  form.invited_by,
48
49
  invitation_instructions: form.invitation_instructions
49
50
  )
@@ -17,10 +17,17 @@ module Decidim
17
17
  update_personal_data
18
18
  update_avatar
19
19
  update_password
20
- @user.save!
21
20
 
22
- @form.remove_avatar = false
23
- broadcast(:ok, @user.unconfirmed_email.present?)
21
+ if @user.valid?
22
+ @user.save!
23
+ @form.remove_avatar = false
24
+ broadcast(:ok, @user.unconfirmed_email.present?)
25
+ else
26
+ if @user.errors.has_key? :avatar
27
+ @form.errors.add :avatar, @user.errors[:avatar]
28
+ end
29
+ broadcast(:invalid)
30
+ end
24
31
  end
25
32
 
26
33
  private
@@ -65,7 +65,7 @@ module Decidim
65
65
  end
66
66
 
67
67
  def _action_authorizer(action_name)
68
- ActionAuthorizer.new(current_user, current_feature, action_name)
68
+ ::Decidim::ActionAuthorizer.new(current_user, current_feature, action_name)
69
69
  end
70
70
 
71
71
  class Unauthorized < StandardError; end
@@ -4,6 +4,21 @@ module Decidim
4
4
  # Custom Devise PasswordsController to avoid namespace problems.
5
5
  class PasswordsController < ::Devise::PasswordsController
6
6
  include Decidim::DeviseControllers
7
+
8
+ private
9
+
10
+ # Since we're using a single Devise installation for multiple
11
+ # organizations, and user emails can be repeated across organizations,
12
+ # we need to identify the user by both the email and the organization.
13
+ # Setting the organization ID here will be used by Devise internally to
14
+ # find the correct user.
15
+ #
16
+ # Note that in orther for this to work we need to define the `reset_password_keys`
17
+ # Devise attribute in the `Decidim::User` model to include the
18
+ # `decidim_organization_id` attribute.
19
+ def resource_params
20
+ super.merge(decidim_organization_id: current_organization.id)
21
+ end
7
22
  end
8
23
  end
9
24
  end
@@ -3,7 +3,7 @@ require_dependency "decidim/application_controller"
3
3
 
4
4
  module Decidim
5
5
  class ParticipatoryProcessGroupsController < ApplicationController
6
- helper_method :participatory_processes, :group
6
+ helper_method :participatory_processes, :group, :collection
7
7
 
8
8
  def show
9
9
  authorize! :read, ParticipatoryProcessGroup
@@ -14,6 +14,7 @@ module Decidim
14
14
  def participatory_processes
15
15
  @participatory_processes ||= group.participatory_processes.published
16
16
  end
17
+ alias_method :collection, :participatory_processes
17
18
 
18
19
  def group
19
20
  Decidim::ParticipatoryProcessGroup.find(params[:id])
@@ -19,6 +19,7 @@ module Decidim
19
19
  validates :password, confirmation: true
20
20
  validates :password, length: { in: Decidim::User.password_length, allow_blank: true }
21
21
  validates :password_confirmation, presence: true, if: :password_present
22
+ validates :avatar, file_size: { less_than_or_equal_to: ->(_record) { Decidim::User::MAXIMUM_AVATAR_FILE_SIZE } }
22
23
 
23
24
  validate :unique_email
24
25
 
@@ -4,9 +4,19 @@ module Decidim
4
4
  # Store user's social identities
5
5
  class Identity < ApplicationRecord
6
6
  belongs_to :user, foreign_key: :decidim_user_id, class_name: Decidim::User
7
+ belongs_to :organization, foreign_key: :decidim_organization_id, class_name: Decidim::Organization
7
8
 
8
9
  validates :user, presence: true
9
10
  validates :provider, presence: true
10
- validates :uid, presence: true, uniqueness: { scope: :provider }
11
+ validates :uid, presence: true, uniqueness: { scope: [:provider, :organization] }
12
+
13
+ validate :same_organization
14
+
15
+ private
16
+
17
+ def same_organization
18
+ return if organization == user&.organization
19
+ errors.add(:organization, :invalid)
20
+ end
11
21
  end
12
22
  end
@@ -4,6 +4,8 @@ module Decidim
4
4
  # installation we can find many organizations and each of them can start
5
5
  # their own participatory processes.
6
6
  class Organization < ApplicationRecord
7
+ SOCIAL_HANDLERS = [:twitter, :facebook, :instagram, :youtube, :github]
8
+
7
9
  has_many :participatory_process_groups, foreign_key: "decidim_organization_id", class_name: Decidim::ParticipatoryProcessGroup, inverse_of: :organization
8
10
  has_many :participatory_processes, foreign_key: "decidim_organization_id", class_name: Decidim::ParticipatoryProcess, inverse_of: :organization
9
11
  has_many :static_pages, foreign_key: "decidim_organization_id", class_name: Decidim::StaticPage, inverse_of: :organization
@@ -4,9 +4,12 @@ require_dependency "devise/models/decidim_validatable"
4
4
  module Decidim
5
5
  # A User is a citizen that wants to join the platform to participate.
6
6
  class User < ApplicationRecord
7
+ MAXIMUM_AVATAR_FILE_SIZE = 5.megabytes
8
+
7
9
  devise :invitable, :database_authenticatable, :registerable, :confirmable,
8
10
  :recoverable, :rememberable, :trackable, :decidim_validatable,
9
- :omniauthable, omniauth_providers: [:facebook, :twitter, :google_oauth2]
11
+ :omniauthable, omniauth_providers: [:facebook, :twitter, :google_oauth2],
12
+ request_keys: [:env], reset_password_keys: [:decidim_organization_id, :email]
10
13
 
11
14
  belongs_to :organization, foreign_key: "decidim_organization_id", class_name: Decidim::Organization
12
15
  has_many :authorizations, foreign_key: "decidim_user_id", class_name: Decidim::Authorization, inverse_of: :user
@@ -19,7 +22,7 @@ module Decidim
19
22
  validates :organization, :name, presence: true
20
23
  validates :locale, inclusion: { in: I18n.available_locales.map(&:to_s) }, allow_blank: true
21
24
  validates :tos_agreement, acceptance: true, allow_nil: false, on: :create
22
- validates :avatar, file_size: { less_than_or_equal_to: 5.megabytes }
25
+ validates :avatar, file_size: { less_than_or_equal_to: MAXIMUM_AVATAR_FILE_SIZE }
23
26
  validates :email, uniqueness: { scope: :organization }
24
27
  validate :all_roles_are_valid
25
28
  mount_uploader :avatar, Decidim::AvatarUploader
@@ -51,6 +54,20 @@ module Decidim
51
54
  super || I18n.t("decidim.anonymous_user")
52
55
  end
53
56
 
57
+ # Check if the user exists with the given email and the current organization
58
+ #
59
+ # warden_conditions - A hash with the authentication conditions
60
+ # * email - a String that represents user's email.
61
+ # * env - A Hash containing environment variables.
62
+ # Returns a User.
63
+ def self.find_for_authentication(warden_conditions)
64
+ organization = warden_conditions.dig(:env, "decidim.current_organization")
65
+ where(
66
+ email: warden_conditions[:email],
67
+ decidim_organization_id: organization.id
68
+ ).first
69
+ end
70
+
54
71
  private
55
72
 
56
73
  def all_roles_are_valid
@@ -10,7 +10,7 @@
10
10
  <h5 class="card--list__heading">
11
11
  <%= t("#{authorization.name}.name", scope: "decidim.authorization_handlers") %>
12
12
  </h5>
13
- <span class="text-small"><%= l(authorization.created_at, format: :long) %></span>
13
+ <span class="text-small"><%= l(authorization.updated_at, format: :long) %></span>
14
14
  </div>
15
15
  </div>
16
16
  <div class="card--list__data">
@@ -22,7 +22,7 @@
22
22
  </div>
23
23
 
24
24
  <div class="actions">
25
- <%= f.submit t("devise.passwords.edit.change_my_password", class: "button expanded") %>
25
+ <%= f.submit t("devise.passwords.edit.change_my_password"), class: "button expanded" %>
26
26
  </div>
27
27
  <% end %>
28
28
 
@@ -1,3 +1,3 @@
1
1
  <div class="row collapse order-by">
2
- <h2 class="order-by__text section-heading"><%= t(".processes", scope: "layouts", count: participatory_processes.count) %></h2>
2
+ <h2 class="order-by__text section-heading"><%= t(".processes", scope: "layouts", count: collection.count) %></h2>
3
3
  </div>
@@ -1,14 +1,14 @@
1
- <div class="topbar__dropmenu language-choose">
2
- <ul class="dropdown menu" data-dropdown-menu data-close-on-click-inside="false">
3
- <li class="is-dropdown-submenu-parent">
4
- <%= link_to t("name", scope: "locale") %>
5
- <% if available_locales.length > 1 %>
1
+ <% if available_locales.length > 1 %>
2
+ <div class="topbar__dropmenu language-choose">
3
+ <ul class="dropdown menu" data-dropdown-menu data-close-on-click-inside="false">
4
+ <li class="is-dropdown-submenu-parent">
5
+ <%= link_to t("name", scope: "locale") %>
6
6
  <ul class="menu is-dropdown-submenu">
7
7
  <% (available_locales - [I18n.locale.to_s]).each do |locale| %>
8
8
  <li><%= link_to locale_name(locale), decidim.locale_path(locale: locale), method: :post%></li>
9
9
  <% end %>
10
10
  </ul>
11
- <% end %>
12
- </li>
13
- </ul>
14
- </div>
11
+ </li>
12
+ </ul>
13
+ </div>
14
+ <% end %>
@@ -249,6 +249,7 @@ ca:
249
249
  subject: Contrasenya modificada
250
250
  errors:
251
251
  messages:
252
+ content_type_whitelist_error: El tipus de fitxer no és vàlid
252
253
  file_size_is_less_than_or_equal_to: la mida del fitxer ha de ser menor que o igual a %{count}
253
254
  invalid_manifest: Arxiu de manifest invàlid
254
255
  invalid_participatory_process: Procés participatiu invàlid
@@ -250,6 +250,7 @@ en:
250
250
  subject: Password changed
251
251
  errors:
252
252
  messages:
253
+ content_type_whitelist_error: The file type is not valid
253
254
  file_size_is_less_than_or_equal_to: file size must be less than or equal to %{count}
254
255
  invalid_manifest: Invalid manifest
255
256
  invalid_participatory_process: Invalid participatory process
@@ -249,6 +249,7 @@ es:
249
249
  subject: Contraseña modificada
250
250
  errors:
251
251
  messages:
252
+ content_type_whitelist_error: El tipo de archivo no es válido
252
253
  file_size_is_less_than_or_equal_to: el tamaño del archivo debe ser menor que o igual a %{count}
253
254
  invalid_manifest: Manifiesto inválido
254
255
  invalid_participatory_process: Proceso participativo inválido
@@ -1,10 +1,12 @@
1
1
  eu:
2
2
  activemodel:
3
3
  attributes:
4
+ report:
5
+ details: Iruzkin gehigarriak
4
6
  user:
5
7
  email: Zure helbide elektronikoa
6
8
  name: Zure izena
7
- password: Pasahitz berria
9
+ password: Pasahitza
8
10
  password_confirmation: Baieztatu zure pasahitz berria
9
11
  user_group_document_number: Egiaztagiri-zenbakia
10
12
  user_group_name: Erakundearen izena
@@ -13,7 +15,7 @@ eu:
13
15
  attributes:
14
16
  decidim/user:
15
17
  current_password: Egungo pasahitza
16
- email: Posta elektronikoa
18
+ email: Helbide elektronikoa
17
19
  name: Erabiltzaile-izena
18
20
  password: Pasahitza
19
21
  password_confirmation: Baieztatu pasahitza
@@ -50,18 +52,24 @@ eu:
50
52
  name: baimen-adibidea
51
53
  errors:
52
54
  duplicate_authorization: Badago erabiltzaile bat, datu berberekin baimendua.
55
+ foo_authorization:
56
+ fields:
57
+ bar: Bar
58
+ foo: foo
59
+ name: foo baimena
53
60
  authorizations:
54
61
  create:
55
62
  error: Errorea gertatu da baimena sortzean.
56
63
  success: Baimendua izan zara zuzen.
57
- current_participatory_processes: behako bat eman egungo prozesuei
64
+ current_participatory_processes: eman behakoa egungo prozesuei
58
65
  first_login:
59
66
  actions:
60
- decidim/dummy_authorization_handler: Egiaztatu baimen-adibidea ........ren kontra
67
+ decidim/dummy_authorization_handler: 'Egiaztatu baimen-adibidea honekin erkatuta:'
61
68
  title: Egiaztatu zure nortasuna
62
69
  verify_with_these_options: 'Hona zure nortasuna egiaztatzeko dituzun aukerak:'
63
70
  new:
64
71
  authorize: Bidali
72
+ authorize_with: 'Egiaztatu nire nortasuna honen bidez: %{authorizer}'
65
73
  skip_verification: Oraingoz, urrats hau egin gabe utzi dezakezu eta %{link}
66
74
  core:
67
75
  actions:
@@ -87,6 +95,7 @@ eu:
87
95
  user_group: Erakundea / Kolektiboa
88
96
  subtitle: Sortu kontu bat eztabaidetan parte hartzeko eta proposamenen alde egiteko
89
97
  terms: erabilera-baldintzak
98
+ tos_agreement: 'Erregistratzean hau onartzen duzu: %{link}.'
90
99
  username_help: Izen publikoa, zuk argitaratutakoetan agertzekoa. Anonimatua bermatze aldera, edozein izen izan daiteke.
91
100
  sessions:
92
101
  new:
@@ -95,10 +104,26 @@ eu:
95
104
  shared:
96
105
  omniauth_buttons:
97
106
  or: Edo
107
+ features:
108
+ dummy:
109
+ actions:
110
+ bar: Bar
111
+ foo: foo
112
+ name: Funtzionaltasun-proba
113
+ settings:
114
+ global:
115
+ comments_enabled: Iruzkinak gaituta
116
+ dummy_global_attribute_1: Atributu-proba, 1
117
+ dummy_global_attribute_2: Atributu-proba, 2
118
+ step:
119
+ comments_blocked: Iruzkinak blokeatuta
120
+ dummy_step_attribute_1: Atributu-faseko proba, 1
121
+ dummy_step_attribute_2: Atributu-faseko proba, 2
98
122
  filters:
99
123
  linked_classes:
100
124
  all: Guztiak
101
125
  meeting: Topaketak
126
+ project: Proiektuak
102
127
  proposal: Proposamenak
103
128
  result: Emaitzak
104
129
  forms:
@@ -106,7 +131,11 @@ eu:
106
131
  error: Errorea bat dago eremu honetan.
107
132
  menu:
108
133
  home: Hasiera
134
+ more_information: Argibide gehiago
109
135
  processes: Prozesuak
136
+ newsletter_mailer:
137
+ newsletter:
138
+ note: 'Mezu hau jaso duzu albiste-buletinean harpidetuta zaudelako hemen: %{organization_name}. Ezarpenak aldatu ditzakezu zure <a href="%{link}">jakinarazpen-orrian</a>.'
110
139
  notifications_settings:
111
140
  show:
112
141
  comments_notifications: Jakinarazpenak jaso nahi ditut nik argitaratutakoei iruzkinak egiten dizkietenean.
@@ -120,6 +149,13 @@ eu:
120
149
  index:
121
150
  not_verified: Egiaztatu gabe
122
151
  verified: Egiaztatuta
152
+ pages:
153
+ index:
154
+ title: Argibide gehiago
155
+ participatory_process_groups:
156
+ show:
157
+ group_participatory_processes: '%{group} talderako prozesuak'
158
+ title: Prozesu partizipatiboen multzoak
123
159
  participatory_process_steps:
124
160
  index:
125
161
  process_steps: Prozesuaren faseak
@@ -127,6 +163,10 @@ eu:
127
163
  participatory_processes:
128
164
  index:
129
165
  title: Prozesu partizipatiboak
166
+ participatory_process_groups:
167
+ none: Bat ere ez
168
+ scopes:
169
+ global: Esparrua orokorrak
130
170
  show:
131
171
  developer_group: Talde sustatzailea
132
172
  end_date: Bukaera-data
@@ -135,6 +175,19 @@ eu:
135
175
  participatory_structure: Egitura partizipatiboa
136
176
  scope: Esparrua
137
177
  target: Nori zuzentzen zaio?
178
+ reported_mailer:
179
+ hide:
180
+ hello: Kaixo, %{name},
181
+ report_html: "<p>Honako eduki hau automatikoki ezkutatu da: <p>%{content} <p>.</p>"
182
+ subject: Eduki bat automatikoki ezkutatu da
183
+ report:
184
+ hello: Kaixo, %{name},
185
+ report_html: "<p>Honako eduki hau salatua izan da: <p>%{content}<p></p>"
186
+ subject: Eduki bat salatua izan da
187
+ reports:
188
+ create:
189
+ error: Errorea gertatu da edukia salatzean. Mesedez, saiatu berriro.
190
+ success: Salaketa zuzen sortu da, eta administratzaile batek aztertuko du.
138
191
  shared:
139
192
  action_authorization_modal:
140
193
  incomplete:
@@ -143,15 +196,28 @@ eu:
143
196
  reauthorize: Berriz eskuratu baimena
144
197
  title: Mesedez, eskura ezazu berriz baimena
145
198
  missing:
199
+ authorize: 'Baimena eskuratu honen bidez: "%{authorization}"'
200
+ explanation: 'Ekintza hau egiteko, baimen hau behar duzu: "%{authorization}".'
146
201
  title: Baimena behar da
147
202
  unauthorized:
148
203
  explanation: Ezin diozu heldu ekintza honi, baimen-datuetako batzuk ez direlako behar direnak.
149
204
  invalid: "%{field} ez da baliozkoa."
150
205
  ok: Ados
151
206
  title: Ez dago baimenduta
207
+ flag_modal:
208
+ already_reported: Eduki hau jada salatuta dago, eta administratzaile batek.
209
+ close: Itxi
210
+ description: Eduki hau desegokia da?
211
+ does_not_belong: Bertan badago legez kontrako jardunik, suizidio-mehatxurik, informazio pertsonalik edo beste zernahi, zure ustez %{organization_name}-ri ez dagokionik.
212
+ offensive: Ertan badago arrazakeriarik, sexismorik, irainik, eraso pertsonalik, heriotza-mehatxurik, suizidio-eskaerarik edo beste edozein eratako gorroto-diskurtsorik.
213
+ report: Salatu
214
+ spam: Bertan badago clickbait-ik, publizitaterik edo iruzurrik.
215
+ title: Salatu arazo bat
152
216
  login_modal:
153
217
  please_sign_in: Mesedez, erregistratu
154
218
  sign_up: Erregistratu
219
+ reference:
220
+ reference: 'Erreferentzia: %{reference}'
155
221
  share_modal:
156
222
  close_window: Itxi leihoa
157
223
  share: Partekatu
@@ -164,25 +230,42 @@ eu:
164
230
  mailer:
165
231
  invitation_instructions:
166
232
  accept: Onartu gonbita
233
+ accept_until: 'Gonbit hau data honetan iraungiko da: %{due_date}.'
167
234
  hello: Kaixo, %{email},
168
235
  ignore: |-
169
- Onartu nahi ez baduzu gonbit hau, ez egin kasu mezu honi.<br />
170
- Zure kontua ez da sortuko beheko estekara jo eta zure pasahitza aukeratu arte.
236
+ Nahi ez baduzu onartu gonbit hau, ez egin kasu mezu honi.<br />Zure kontua ez da sortuko beheko estekara jo eta zure pasahitza aukeratu arte.
171
237
  invited_you_as_admin: "%{invited_by} izeneko batek gonbit egin dizu %{application} aplikazioaren administratzaile izateko; onartzeko, egin klik esteka honetan:"
238
+ someone_invited_you: 'Orbaitek gonbit egin dizu aplikazio honetara: %{application}. Onartzeko, egin klik esteka honetan:'
239
+ invite_admin:
240
+ subject: 'Gonbita jaso duzu erakunde hau kudeatzeko: %{organization}'
241
+ invite_collaborator:
242
+ subject: 'Gonbita jaso duzu erakunde honekin lankidetzan aritzeko: %{organization}'
243
+ organization_admin_invitation_instructions:
244
+ subject: 'Gonbita jaso duzu erakunde hau kudeatzeko: %{organization}'
172
245
  password_change:
173
246
  greeting: Kaixo %{recipient}!
174
247
  message: Zuregana jotzen dugu jakinarazteko zure pasahitza zuzen aldatu dela.
175
248
  subject: Pasahitza aldatu da
176
249
  errors:
177
250
  messages:
251
+ content_type_whitelist_error: fitxategi mota ez da zuzena
178
252
  file_size_is_less_than_or_equal_to: fitxategiaren pisuak %{count} izan behar du, edo gutxiago
179
253
  invalid_manifest: Manifestua ez da baliozkoa
180
254
  invalid_participatory_process: Prozesu partizipatiboa ez da baliozkoa
255
+ long_words: Hitz luzeegiak ditu
256
+ must_start_with_caps: Letra larriz hasi behar du
181
257
  nesting_too_deep: ezin da egon azpikategoria batean
258
+ too_many_marks: Galdera- eta harridura-ikur gehiegi erabiltzen ari zara
259
+ too_much_caps: Letra larri gehiegi erabiltzen ari zara
260
+ too_short: Laburregia da
261
+ invisible_captcha:
262
+ sentence_for_humans: Gizaki bat bazara, ez egin kasu eremu honi
263
+ timestamp_error_message: Barkatu, baina azkarregi aritu zara! Mesedez, bidali.
182
264
  layouts:
183
265
  decidim:
184
266
  cookie_warning:
185
- link_label: aquí
267
+ description_html: 'Webgune honek bere cookieak eta hirugarrenenak erabiltzen ditu, nabigazioa hobetu eta intereseko edukiak eta zerbitzuak eskaintze aldera. Nabigatzen jarraituz gero, gure cookie-politika onartzen delakoan gaude. Argibide gehiago jasotzeko, kontsultatu hemen: %{link}.'
268
+ link_label: hemen
186
269
  ok: Ados nago
187
270
  footer:
188
271
  made_with_open_source: 'Webgune hau egiteko, <a target="_blank" href="https://github.com/AjuntamentdeBarcelona/decidim">software librea</a> erabili da.'
@@ -191,6 +274,9 @@ eu:
191
274
  navigation: Nabigazioa
192
275
  sign_in: Sartu
193
276
  sign_up: Erregistratu
277
+ participatory_process_groups:
278
+ participatory_process_group:
279
+ browse: Arakatu
194
280
  participatory_processes:
195
281
  index:
196
282
  promoted_processes: Prozesu nabarmenduak
@@ -198,7 +284,7 @@ eu:
198
284
  no_processes_yet: Oraindik ez dago prozesu partizipatiborik!
199
285
  order_by_processes:
200
286
  processes:
201
- one: "Prozesu %{count}"
287
+ one: "%{count} prozesu"
202
288
  other: "%{count} prozesu"
203
289
  participatory_process:
204
290
  active_step: 'Oraingo fasea:'
@@ -227,13 +313,63 @@ eu:
227
313
  name: Euskera
228
314
  pages:
229
315
  '404':
230
- back_home: Hasierara itzuli
316
+ back_home: Itzuli hasierara
231
317
  content_doesnt_exist: Helbide okerra da edo ezabatu da.
232
- title: Bilatzen duzun orria ez dago!
318
+ title: Ez dugu aurkitu bilatzen duzun orria!
233
319
  '500':
234
320
  title: Arazo bat izan da gure zerbitzariarekin
235
321
  try_later: Mesedez, berriz saiatu geroago.
236
322
  home:
237
323
  extended:
238
324
  debates: Eztabaidak
239
- debates_explanation: Gure ustez hirirako inportanteak diren gauzak ezagutu, eztabaidatu eta partekatuko ditugu.
325
+ debates_explanation: Gure ustez hirirako inportanteak diren gauzak ezagutu, eztabaidatu eta partekatuko ditugu.
326
+ how_to_participate: Nola har dezaket parte prozesu batean?
327
+ meetings: Topaketak
328
+ meetings_explanation: Gure ustez hirirako inportanteak diren gauzak ezagutu, eztabaidatu eta partekatuko ditugu.
329
+ more_info: Argibide gehiago
330
+ proposals: Proposamenak
331
+ proposals_explanation: Gune irekia herritarren proposamenetarako, adierazteko zer-nolako hiritan bizi nahi dugun.
332
+ footer_sub_hero:
333
+ footer_sub_hero_body: Bihurtu dezagun gizartea irekiago, gardenago eta kolaboratiboago <br /> Bat egin, parte hartu eta erabaki.
334
+ footer_sub_hero_headline: Ongi etorri %{organization} erakundearen plataforma partizipatibora.
335
+ register: Erregistratu
336
+ hero:
337
+ participate: Parte hartu
338
+ welcome: Ongi etorri %{organization} erakundera!
339
+ highlighted_processes:
340
+ active_processes: Prozesu aktiboak
341
+ active_step: Fase aktiboa
342
+ see_all_processes: Ikusi prozesu guztiak
343
+ statistics:
344
+ headline: '%{organization} erakundearen egungo egoera'
345
+ processes: Prozesuak
346
+ users: Erabiltzaileak
347
+ sub_hero:
348
+ register: Erregistroa
349
+ social_share_button:
350
+ delicious: Delicious
351
+ douban: Douban
352
+ email: Helbide elektronikoa
353
+ facebook: Facebook
354
+ google_bookmark: Google Bookmark
355
+ google_plus: Google+
356
+ hacker_news: hacker News
357
+ linkedin: Linkedin
358
+ pinterest: Pinterest
359
+ qq: Qzone
360
+ reddit: Reddit
361
+ share_to: 'Partekatu honekin: %{name}'
362
+ tumblr: Tumblr
363
+ twitter: Twitter
364
+ vkontakte: Vkontakte
365
+ wechat: WeChat
366
+ wechat_footer: Ireki zure WeChat, egin klik "Discover" botoian, eta gero, egin klik berriro "Eskaneatu QR kodea” menuan.
367
+ weibo: Sina Weibo
368
+ xing: Xing
369
+ views:
370
+ pagination:
371
+ first: "&laquo; Lehena"
372
+ last: Azkena &raquo;
373
+ next: Hurrengoa &rsaquo;
374
+ previous: "&lsaquo; Aurrekoa"
375
+ truncate: "&hellip;"
@@ -0,0 +1,6 @@
1
+ class ChangeDecidimUserEmailIndexUniqueness < ActiveRecord::Migration[5.0]
2
+ def change
3
+ remove_index :decidim_users, :email
4
+ add_index :decidim_users, [:email, :decidim_organization_id], unique: true
5
+ end
6
+ end
@@ -0,0 +1,5 @@
1
+ class AddOrganizationToIdentities < ActiveRecord::Migration[5.0]
2
+ def change
3
+ add_reference :decidim_identities, :decidim_organization, index: true, foreign_key: true
4
+ end
5
+ end
@@ -0,0 +1,12 @@
1
+ class ChangeDecidimIdentitiesProviderUidIndexUniqueness < ActiveRecord::Migration[5.0]
2
+ def change
3
+ remove_index :decidim_identities, [:provider, :uid]
4
+ add_index :decidim_identities, [:provider, :uid, :decidim_organization_id], unique: true,
5
+ name: "decidim_identities_provider_uid_organization_unique"
6
+
7
+ Decidim::Identity.includes(:user).find_each do |identity|
8
+ identity.organization = identity.user.organization
9
+ identity.save!
10
+ end
11
+ end
12
+ end
@@ -35,6 +35,7 @@ require "geocoder"
35
35
  require "decidim/api"
36
36
 
37
37
  require "decidim/query_extensions"
38
+ require "decidim/i18n_exceptions"
38
39
 
39
40
  module Decidim
40
41
  module Core
@@ -187,6 +187,7 @@ FactoryGirl.define do
187
187
  provider "facebook"
188
188
  sequence(:uid)
189
189
  user
190
+ organization { user.organization }
190
191
  end
191
192
 
192
193
  factory :authorization, class: Decidim::Authorization do
@@ -18,7 +18,7 @@ RSpec.shared_examples "manage moderations" do
18
18
  end
19
19
 
20
20
  before do
21
- visit decidim_admin.participatory_process_path(participatory_process)
21
+ visit decidim_admin.edit_participatory_process_path(participatory_process)
22
22
  click_link "Moderations"
23
23
  end
24
24
 
@@ -41,7 +41,7 @@ RSpec.shared_examples "manage moderations" do
41
41
  click_link "Unreport"
42
42
  end
43
43
 
44
- within ".flash" do
44
+ within ".callout-wrapper" do
45
45
  expect(page).to have_content("Resource successfully unreported")
46
46
  end
47
47
  end
@@ -53,7 +53,7 @@ RSpec.shared_examples "manage moderations" do
53
53
  click_link "Hide"
54
54
  end
55
55
 
56
- within ".flash" do
56
+ within ".callout-wrapper" do
57
57
  expect(page).to have_content("Resource successfully hidden")
58
58
  end
59
59
 
@@ -2,7 +2,7 @@
2
2
  # This holds Decidim's version and the Rails version on which it depends.
3
3
  module Decidim
4
4
  def self.version
5
- "0.0.6"
5
+ "0.0.7"
6
6
  end
7
7
 
8
8
  def self.rails_version
@@ -40,20 +40,24 @@ module Decidim
40
40
  )
41
41
  end
42
42
 
43
- field_label = label_i18n(name, options[:label] || label_for(name))
44
-
45
- tabs_panels = "".html_safe
46
- if options[:label] != false
47
- tabs_panels = content_tag(:ul, class: "tabs", id: "#{name}-tabs", data: { tabs: true }) do
48
- locales.each_with_index.inject("".html_safe) do |string, (locale, index)|
49
- string + content_tag(:li, class: tab_element_class_for("title", index)) do
50
- title = I18n.with_locale(locale) { I18n.t("name", scope: "locale") }
51
- element_class = ""
52
- element_class += "alert" if error?(name_with_locale(name, locale))
53
- content_tag(:a, title, href: "##{name}-panel-#{index}", class: element_class)
43
+ label_tabs = content_tag(:div, class: "label--tabs") do
44
+ field_label = label_i18n(name, options[:label] || label_for(name))
45
+
46
+ tabs_panels = "".html_safe
47
+ if options[:label] != false
48
+ tabs_panels = content_tag(:ul, class: "tabs tabs--lang", id: "#{name}-tabs", data: { tabs: true }) do
49
+ locales.each_with_index.inject("".html_safe) do |string, (locale, index)|
50
+ string + content_tag(:li, class: tab_element_class_for("title", index)) do
51
+ title = I18n.with_locale(locale) { I18n.t("name", scope: "locale") }
52
+ element_class = nil
53
+ element_class = "is-tab-error" if error?(name_with_locale(name, locale))
54
+ content_tag(:a, title, href: "##{name}-panel-#{index}", class: element_class)
55
+ end
54
56
  end
55
57
  end
56
58
  end
59
+
60
+ safe_join [field_label, tabs_panels]
57
61
  end
58
62
 
59
63
  tabs_content = content_tag(:div, class: "tabs-content", data: { tabs_content: "#{name}-tabs" }) do
@@ -64,7 +68,7 @@ module Decidim
64
68
  end
65
69
  end
66
70
 
67
- safe_join [field_label, tabs_panels, tabs_content]
71
+ safe_join [label_tabs, tabs_content]
68
72
  end
69
73
 
70
74
  # Public: generates a hidden field and a container for WYSIWYG editor
@@ -0,0 +1,15 @@
1
+ unless Rails.env.production?
2
+ module I18n
3
+ class JustRaiseExceptionHandler < ExceptionHandler
4
+ def call(exception, locale, key, options)
5
+ if exception.is_a?(MissingTranslationData) || exception.is_a?(MissingTranslation)
6
+ raise exception.to_exception
7
+ else
8
+ super
9
+ end
10
+ end
11
+ end
12
+ end
13
+
14
+ I18n.exception_handler = I18n::JustRaiseExceptionHandler.new
15
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: decidim-core
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.6
4
+ version: 0.0.7
5
5
  platform: ruby
6
6
  authors:
7
7
  - Josep Jaume Rey Peroy
@@ -10,7 +10,7 @@ authors:
10
10
  autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
- date: 2017-03-24 00:00:00.000000000 Z
13
+ date: 2017-04-07 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: rails
@@ -430,70 +430,70 @@ dependencies:
430
430
  requirements:
431
431
  - - '='
432
432
  - !ruby/object:Gem::Version
433
- version: 0.0.6
433
+ version: 0.0.7
434
434
  type: :runtime
435
435
  prerelease: false
436
436
  version_requirements: !ruby/object:Gem::Requirement
437
437
  requirements:
438
438
  - - '='
439
439
  - !ruby/object:Gem::Version
440
- version: 0.0.6
440
+ version: 0.0.7
441
441
  - !ruby/object:Gem::Dependency
442
442
  name: decidim-dev
443
443
  requirement: !ruby/object:Gem::Requirement
444
444
  requirements:
445
445
  - - '='
446
446
  - !ruby/object:Gem::Version
447
- version: 0.0.6
447
+ version: 0.0.7
448
448
  type: :development
449
449
  prerelease: false
450
450
  version_requirements: !ruby/object:Gem::Requirement
451
451
  requirements:
452
452
  - - '='
453
453
  - !ruby/object:Gem::Version
454
- version: 0.0.6
454
+ version: 0.0.7
455
455
  - !ruby/object:Gem::Dependency
456
456
  name: decidim-proposals
457
457
  requirement: !ruby/object:Gem::Requirement
458
458
  requirements:
459
459
  - - '='
460
460
  - !ruby/object:Gem::Version
461
- version: 0.0.6
461
+ version: 0.0.7
462
462
  type: :development
463
463
  prerelease: false
464
464
  version_requirements: !ruby/object:Gem::Requirement
465
465
  requirements:
466
466
  - - '='
467
467
  - !ruby/object:Gem::Version
468
- version: 0.0.6
468
+ version: 0.0.7
469
469
  - !ruby/object:Gem::Dependency
470
470
  name: decidim-meetings
471
471
  requirement: !ruby/object:Gem::Requirement
472
472
  requirements:
473
473
  - - '='
474
474
  - !ruby/object:Gem::Version
475
- version: 0.0.6
475
+ version: 0.0.7
476
476
  type: :development
477
477
  prerelease: false
478
478
  version_requirements: !ruby/object:Gem::Requirement
479
479
  requirements:
480
480
  - - '='
481
481
  - !ruby/object:Gem::Version
482
- version: 0.0.6
482
+ version: 0.0.7
483
483
  - !ruby/object:Gem::Dependency
484
484
  name: decidim-results
485
485
  requirement: !ruby/object:Gem::Requirement
486
486
  requirements:
487
487
  - - '='
488
488
  - !ruby/object:Gem::Version
489
- version: 0.0.6
489
+ version: 0.0.7
490
490
  type: :development
491
491
  prerelease: false
492
492
  version_requirements: !ruby/object:Gem::Requirement
493
493
  requirements:
494
494
  - - '='
495
495
  - !ruby/object:Gem::Version
496
- version: 0.0.6
496
+ version: 0.0.7
497
497
  description: Adds core features so other engines can hook into the framework.
498
498
  email:
499
499
  - josepjaume@gmail.com
@@ -883,6 +883,9 @@ files:
883
883
  - db/migrate/20170307084957_create_reports.rb
884
884
  - db/migrate/20170308091316_create_moderations.rb
885
885
  - db/migrate/20170313095436_add_available_authorizations_to_organization.rb
886
+ - db/migrate/20170405091801_change_decidim_user_email_index_uniqueness.rb
887
+ - db/migrate/20170405094028_add_organization_to_identities.rb
888
+ - db/migrate/20170405094258_change_decidim_identities_provider_uid_index_uniqueness.rb
886
889
  - db/seeds.rb
887
890
  - db/seeds/Exampledocument.pdf
888
891
  - db/seeds/city.jpeg
@@ -933,6 +936,7 @@ files:
933
936
  - lib/decidim/has_feature.rb
934
937
  - lib/decidim/has_reference.rb
935
938
  - lib/decidim/has_scope.rb
939
+ - lib/decidim/i18n_exceptions.rb
936
940
  - lib/decidim/page_finder.rb
937
941
  - lib/decidim/query_extensions.rb
938
942
  - lib/decidim/reportable.rb
@@ -978,7 +982,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
978
982
  version: '0'
979
983
  requirements: []
980
984
  rubyforge_project:
981
- rubygems_version: 2.6.8
985
+ rubygems_version: 2.6.11
982
986
  signing_key:
983
987
  specification_version: 4
984
988
  summary: The core of the Decidim framework.