decidim-core 0.0.6 → 0.0.7

Sign up to get free protection for your applications and to get access to all the features.
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.