decidim-core 0.0.1 → 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (118) hide show
  1. checksums.yaml +4 -4
  2. data/Rakefile +1 -1
  3. data/app/assets/config/decidim_core_manifest.js +1 -0
  4. data/app/assets/javascripts/decidim.js.es6 +3 -2
  5. data/app/assets/javascripts/decidim/append_elements.js.es6 +8 -0
  6. data/app/assets/javascripts/decidim/filters.js.es6 +22 -0
  7. data/app/assets/javascripts/decidim/form_filter.component.js.es6 +176 -0
  8. data/app/assets/javascripts/decidim/form_filter.component.test.js +151 -0
  9. data/app/assets/javascripts/decidim/inline_svg.js.es6 +12 -0
  10. data/app/assets/javascripts/decidim/user_registrations.js.es6 +22 -0
  11. data/app/assets/stylesheets/decidim/_variables.scss +1 -1
  12. data/app/assets/stylesheets/decidim/modules/_comments.scss +3 -6
  13. data/app/assets/stylesheets/decidim/modules/_cookie-bar.scss +22 -0
  14. data/app/assets/stylesheets/decidim/modules/_layout.scss +9 -1
  15. data/app/assets/stylesheets/decidim/modules/_navbar.scss +8 -5
  16. data/app/assets/stylesheets/decidim/modules/_order-by.scss +0 -1
  17. data/app/assets/stylesheets/decidim/modules/_process-phase.scss +4 -0
  18. data/app/assets/stylesheets/decidim/modules/_timeline.scss +62 -80
  19. data/app/assets/stylesheets/decidim/modules/_typography.scss +20 -31
  20. data/app/assets/stylesheets/decidim/utils/_fontface.scss +4 -16
  21. data/app/assets/stylesheets/decidim/utils/_settings.scss +29 -26
  22. data/app/assets/stylesheets/decidim/utils/_variables.scss +22 -0
  23. data/app/commands/decidim/authorize_user.rb +17 -1
  24. data/app/commands/decidim/create_omniauth_registration.rb +92 -0
  25. data/app/commands/decidim/create_registration.rb +50 -0
  26. data/app/commands/decidim/invite_user.rb +50 -0
  27. data/app/commands/decidim/invite_user_again.rb +25 -0
  28. data/app/commands/decidim/remove_user_role.rb +26 -0
  29. data/app/controllers/concerns/decidim/feature_settings.rb +27 -0
  30. data/app/controllers/concerns/decidim/filter_resource.rb +71 -0
  31. data/app/controllers/concerns/decidim/form_factory.rb +21 -18
  32. data/app/controllers/concerns/decidim/needs_participatory_process.rb +2 -3
  33. data/app/controllers/decidim/devise/confirmations_controller.rb +2 -0
  34. data/app/controllers/decidim/devise/invitations_controller.rb +4 -0
  35. data/app/controllers/decidim/devise/omniauth_registrations_controller.rb +96 -0
  36. data/app/controllers/decidim/devise/passwords_controller.rb +2 -0
  37. data/app/controllers/decidim/devise/registrations_controller.rb +34 -0
  38. data/app/controllers/decidim/devise/sessions_controller.rb +1 -0
  39. data/app/controllers/decidim/pages_controller.rb +10 -2
  40. data/app/controllers/decidim/participatory_process_steps_controller.rb +16 -0
  41. data/app/controllers/decidim/participatory_processes_controller.rb +6 -11
  42. data/app/forms/decidim/form.rb +6 -6
  43. data/app/forms/decidim/invite_admin_form.rb +37 -0
  44. data/app/forms/decidim/omniauth_registration_form.rb +24 -0
  45. data/app/forms/decidim/registration_form.rb +41 -0
  46. data/app/helpers/decidim/filters_helper.rb +21 -0
  47. data/app/helpers/decidim/layout_helper.rb +17 -1
  48. data/app/helpers/decidim/omniauth_helper.rb +23 -0
  49. data/app/helpers/decidim/paginate_helper.rb +21 -0
  50. data/app/helpers/decidim/participatory_process_helper.rb +14 -0
  51. data/app/helpers/decidim/participatory_process_steps_helper.rb +17 -0
  52. data/app/mailers/decidim/decidim_devise_mailer.rb +2 -2
  53. data/app/models/decidim/feature.rb +40 -0
  54. data/app/models/decidim/identity.rb +12 -0
  55. data/app/models/decidim/organization.rb +3 -10
  56. data/app/models/decidim/user.rb +3 -1
  57. data/app/models/decidim/user_group.rb +18 -0
  58. data/app/models/decidim/user_group_membership.rb +9 -0
  59. data/app/services/decidim/authorization_handler.rb +13 -13
  60. data/app/services/decidim/resource_search.rb +52 -0
  61. data/app/uploaders/decidim/organization_logo_uploader.rb +1 -1
  62. data/app/views/decidim/authorizations/new.html.erb +3 -1
  63. data/app/views/decidim/devise/omniauth_registrations/new.html.erb +40 -0
  64. data/app/views/decidim/devise/registrations/new.html.erb +21 -1
  65. data/app/views/decidim/devise/sessions/new.html.erb +1 -0
  66. data/app/views/decidim/devise/shared/_links.html.erb +0 -8
  67. data/app/views/decidim/devise/shared/_omniauth_buttons.html.erb +21 -0
  68. data/app/views/decidim/participatory_process_steps/_participatory_process_step.html.erb +16 -0
  69. data/app/views/decidim/participatory_process_steps/_timeline.html.erb +7 -0
  70. data/app/views/decidim/participatory_process_steps/index.html.erb +12 -0
  71. data/app/views/decidim/participatory_processes/show.html.erb +5 -5
  72. data/app/views/decidim/shared/_login_modal.html.erb +30 -0
  73. data/app/views/devise/mailer/invite_admin.html.erb +17 -0
  74. data/app/views/devise/mailer/invite_admin.text.erb +15 -0
  75. data/app/views/devise/mailer/organization_admin_invitation_instructions.html.erb +1 -1
  76. data/app/views/devise/mailer/organization_admin_invitation_instructions.text.erb +1 -1
  77. data/app/views/layouts/decidim/_application.html.erb +1 -0
  78. data/app/views/layouts/decidim/_header.html.erb +1 -1
  79. data/app/views/layouts/decidim/_meta.html.erb +1 -0
  80. data/app/views/layouts/decidim/_process_header.html.erb +12 -1
  81. data/app/views/layouts/decidim/_process_header_steps.html.erb +1 -0
  82. data/app/views/layouts/decidim/_social_meta.html.erb +11 -0
  83. data/app/views/layouts/decidim/participatory_process.html.erb +4 -0
  84. data/app/views/pages/home.html.erb +29 -2
  85. data/config/i18n-tasks.yml +1 -0
  86. data/config/initializers/devise.rb +10 -1
  87. data/config/locales/ca.yml +45 -3
  88. data/config/locales/en.yml +45 -3
  89. data/config/locales/es.yml +45 -3
  90. data/config/routes.rb +9 -2
  91. data/config/secrets.yml +36 -0
  92. data/db/migrate/20170110133113_add_configuration_to_features.rb +7 -0
  93. data/db/migrate/20170110153807_add_handler_to_organization.rb +5 -0
  94. data/db/migrate/20170116110851_create_identities.rb +11 -0
  95. data/db/migrate/20170116135237_loosen_step_requirements.rb +6 -0
  96. data/db/migrate/20170117142904_add_uniqueness_field_to_authorizations.rb +7 -0
  97. data/db/migrate/20170119145359_create_user_groups.rb +11 -0
  98. data/db/migrate/20170119150255_create_user_group_memberships.rb +12 -0
  99. data/db/migrate/20170119150649_add_show_statistics_to_organization.rb +5 -0
  100. data/db/migrate/20170120120733_add_user_groups_verified.rb +5 -0
  101. data/db/seeds.rb +45 -79
  102. data/lib/decidim/core.rb +8 -0
  103. data/lib/decidim/core/engine.rb +8 -0
  104. data/lib/decidim/core/test/factories.rb +188 -0
  105. data/lib/decidim/core/version.rb +1 -1
  106. data/lib/decidim/devise_failure_app.rb +1 -0
  107. data/lib/decidim/feature_manifest.rb +27 -0
  108. data/lib/decidim/features/base_controller.rb +8 -3
  109. data/lib/decidim/features/settings_manifest.rb +94 -0
  110. data/lib/decidim/filter_form_builder.rb +56 -0
  111. data/lib/decidim/form_builder.rb +4 -7
  112. data/vendor/assets/javascripts/svg-injector.js +464 -0
  113. metadata +142 -26
  114. data/app/assets/stylesheets/decidim/modules/_owl-carousel.scss +0 -72
  115. data/app/assets/stylesheets/decidim/modules/_phase-nav.scss +0 -177
  116. data/app/assets/stylesheets/decidim/utils/_helpers.sass +0 -21
  117. data/app/assets/stylesheets/decidim/utils/_keyframes.sass +0 -13
  118. data/app/assets/stylesheets/decidim/utils/_mixins.sass +0 -33
@@ -0,0 +1,22 @@
1
+ // Decidim Variables
2
+
3
+ $primary: map-get($foundation-palette, primary) !default;
4
+ $secondary: map-get($foundation-palette, secondary) !default;
5
+ $success: map-get($foundation-palette, success) !default;
6
+ $warning: map-get($foundation-palette, warning) !default;
7
+ $alert: map-get($foundation-palette, alert) !default;
8
+
9
+ $light-gray-dark: darken($light-gray, 2.5) !default;
10
+
11
+ $proposals: #238FF7 !default;
12
+ $actions: #57D685 !default;
13
+ $debates: #FA6C96 !default;
14
+ $meetings: #FABC6C !default;
15
+
16
+ $twitter: #55acee !default;
17
+ $facebook: #3b5998 !default;
18
+ $google: #dd4b39 !default;
19
+
20
+ $muted: lighten($body-font-color, 30) !default;
21
+
22
+ $border: 1px solid $medium-gray !default;
@@ -16,7 +16,7 @@ module Decidim
16
16
  #
17
17
  # Returns nothing.
18
18
  def call
19
- return broadcast(:invalid) unless handler.authorized?
19
+ return broadcast(:invalid) unless handler.valid? && unique?
20
20
 
21
21
  create_authorization
22
22
  broadcast(:ok)
@@ -29,9 +29,25 @@ module Decidim
29
29
  def create_authorization
30
30
  Authorization.create!(
31
31
  user: handler.user,
32
+ unique_id: handler.unique_id,
32
33
  name: handler.handler_name,
33
34
  metadata: handler.metadata
34
35
  )
35
36
  end
37
+
38
+ def unique?
39
+ return true if handler.unique_id.nil?
40
+
41
+ duplicates = Authorization.where(
42
+ user: User.where(organization: handler.user.organization.id),
43
+ name: handler.handler_name,
44
+ unique_id: handler.unique_id
45
+ )
46
+
47
+ return true unless duplicates.any?
48
+
49
+ handler.errors.add(:base, I18n.t("decidim.authorization_handlers.errors.duplicate_authorization"))
50
+ false
51
+ end
36
52
  end
37
53
  end
@@ -0,0 +1,92 @@
1
+ # frozen_string_literal: true
2
+ module Decidim
3
+ # A command with all the business logic to create a user from omniauth
4
+ class CreateOmniauthRegistration < Rectify::Command
5
+ # Public: Initializes the command.
6
+ #
7
+ # form - A form object with the params.
8
+ def initialize(form, verified_email = nil)
9
+ @form = form
10
+ @verified_email = verified_email
11
+ end
12
+
13
+ # Executes the command. Broadcasts these events:
14
+ #
15
+ # - :ok when everything is valid.
16
+ # - :invalid if the form wasn't valid and we couldn't proceed.
17
+ #
18
+ # Returns nothing.
19
+ def call
20
+ verify_oauth_signature!
21
+
22
+ begin
23
+ return broadcast(:ok, existing_identity.user) if existing_identity
24
+ return broadcast(:invalid) if form.invalid?
25
+
26
+ transaction do
27
+ create_or_find_user
28
+ create_identity
29
+ end
30
+
31
+ broadcast(:ok, @user)
32
+ rescue ActiveRecord::RecordInvalid
33
+ broadcast(:invalid)
34
+ end
35
+ end
36
+
37
+ private
38
+
39
+ attr_reader :form, :verified_email
40
+
41
+ def create_or_find_user
42
+ generated_password = SecureRandom.hex
43
+
44
+ @user = User.find_or_initialize_by(
45
+ email: verified_email,
46
+ organization: organization
47
+ )
48
+
49
+ unless @user.persisted?
50
+ @user.email = (verified_email || form.email)
51
+ @user.name = form.name
52
+ @user.password = generated_password
53
+ @user.password_confirmation = generated_password
54
+ @user.skip_confirmation! if verified_email
55
+ end
56
+
57
+ @user.tos_agreement = "1"
58
+ @user.save!
59
+ end
60
+
61
+ def create_identity
62
+ @user.identities.create!(
63
+ provider: form.provider,
64
+ uid: form.uid
65
+ )
66
+ end
67
+
68
+ def organization
69
+ @form.current_organization
70
+ end
71
+
72
+ def existing_identity
73
+ @existing_identity ||= Identity.where(
74
+ user: organization.users,
75
+ provider: form.provider,
76
+ uid: form.uid
77
+ ).first
78
+ end
79
+
80
+ def verify_oauth_signature!
81
+ raise InvalidOauthSignature, "Invalid oauth signature: #{form.oauth_signature}" unless signature_valid?
82
+ end
83
+
84
+ def signature_valid?
85
+ signature = OmniauthRegistrationForm.create_signature(form.provider, form.uid)
86
+ form.oauth_signature == signature
87
+ end
88
+ end
89
+
90
+ class InvalidOauthSignature < StandardError
91
+ end
92
+ end
@@ -0,0 +1,50 @@
1
+ # frozen_string_literal: true
2
+ module Decidim
3
+ # A command with all the business logic to create a user through the sign up form.
4
+ # It enables the option to sign up as a user group.
5
+ class CreateRegistration < Rectify::Command
6
+ # Public: Initializes the command.
7
+ #
8
+ # form - A form object with the params.
9
+ def initialize(form)
10
+ @form = form
11
+ end
12
+
13
+ # Executes the command. Broadcasts these events:
14
+ #
15
+ # - :ok when everything is valid.
16
+ # - :invalid if the form wasn't valid and we couldn't proceed.
17
+ #
18
+ # Returns nothing.
19
+ def call
20
+ return broadcast(:invalid) if form.invalid?
21
+
22
+ transaction do
23
+ create_user
24
+ create_user_group if form.is_user_group?
25
+ end
26
+
27
+ broadcast(:ok, @user)
28
+ end
29
+
30
+ private
31
+
32
+ attr_reader :form
33
+
34
+ def create_user
35
+ @user = User.create!(email: form.email,
36
+ name: form.name,
37
+ password: form.password,
38
+ password_confirmation: form.password_confirmation,
39
+ organization: form.current_organization,
40
+ tos_agreement: form.tos_agreement)
41
+ end
42
+
43
+ def create_user_group
44
+ UserGroupMembership.create!(user: @user,
45
+ user_group: UserGroup.new(name: form.user_group_name,
46
+ document_number: form.user_group_document_number,
47
+ phone: form.user_group_phone))
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,50 @@
1
+ # frozen_string_literal: true
2
+ module Decidim
3
+ # A command with the business logic to invite a user to an organization.
4
+ class InviteUser < Rectify::Command
5
+ # Public: Initializes the command.
6
+ #
7
+ # form - A form object with the params.
8
+ def initialize(form)
9
+ @form = form
10
+ end
11
+
12
+ def call
13
+ return broadcast(:invalid) if form.invalid?
14
+
15
+ if user.present?
16
+ set_user_roles
17
+ else
18
+ invite_user
19
+ end
20
+
21
+ broadcast(:ok)
22
+ end
23
+
24
+ private
25
+
26
+ attr_reader :form
27
+
28
+ def user
29
+ @user ||= Decidim::User.where(organization: form.organization).where(email: form.email.downcase).first
30
+ end
31
+
32
+ def set_user_roles
33
+ user.roles += form.roles
34
+ user.save!
35
+ end
36
+
37
+ def invite_user
38
+ Decidim::User.invite!(
39
+ {
40
+ name: form.name,
41
+ email: form.email.downcase,
42
+ organization: form.organization,
43
+ roles: form.roles
44
+ },
45
+ form.invited_by,
46
+ invitation_instructions: form.invitation_instructions
47
+ )
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+ module Decidim
3
+ # A command with the business logic to invite an user to an organization.
4
+ class InviteUserAgain < Rectify::Command
5
+ # Public: Initializes the command.
6
+ #
7
+ # form - A form object with the params.
8
+ def initialize(user, instructions)
9
+ @user = user
10
+ @instructions = instructions
11
+ end
12
+
13
+ def call
14
+ return broadcast(:invalid) unless user&.invited_to_sign_up?
15
+
16
+ user.deliver_invitation(invitation_instructions: instructions)
17
+
18
+ broadcast(:ok)
19
+ end
20
+
21
+ private
22
+
23
+ attr_reader :user, :instructions
24
+ end
25
+ end
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+ module Decidim
3
+ # A command to remove a role from a given User.
4
+ class RemoveUserRole < Rectify::Command
5
+ # Public: Initializes the command.
6
+ #
7
+ # form - A form object with the params.
8
+ def initialize(user, role)
9
+ @user = user
10
+ @role = role
11
+ end
12
+
13
+ def call
14
+ return broadcast(:invalid) unless user
15
+
16
+ user.roles.delete(role.to_s)
17
+ user.save!
18
+
19
+ broadcast(:ok)
20
+ end
21
+
22
+ private
23
+
24
+ attr_reader :user, :role
25
+ end
26
+ end
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+ require "active_support/concern"
3
+
4
+ module Decidim
5
+ # This concern groups methods and helpers related to accessing the settings
6
+ # of a feature from a controller.
7
+ module FeatureSettings
8
+ extend ActiveSupport::Concern
9
+
10
+ included do
11
+ include NeedsParticipatoryProcess
12
+
13
+ helper_method :feature_settings, :current_settings
14
+
15
+ def feature_settings
16
+ current_feature.settings
17
+ end
18
+
19
+ def current_settings
20
+ active_step = current_participatory_process.active_step
21
+ return nil unless active_step
22
+
23
+ current_feature.step_settings.fetch(active_step.id.to_s)
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,71 @@
1
+ # frozen_string_literal: true
2
+ # rubocop:disable Metrics/BlockLength
3
+ require "active_support/concern"
4
+
5
+ module Decidim
6
+ # Common logic to filter resources
7
+ module FilterResource
8
+ extend ActiveSupport::Concern
9
+
10
+ # Internal: Defines a class that will wrap in an object the URL params used by the filter.
11
+ # this way we can use Rails' form helpers and have automatically checked checkboxes and
12
+ # radio buttons in the view, for example.
13
+ class Filter
14
+ def initialize(filter)
15
+ @filter = filter
16
+ end
17
+
18
+ def method_missing(method_name, *_arguments)
19
+ @filter.present? && @filter.key?(method_name) ? @filter[method_name] : super
20
+ end
21
+
22
+ def respond_to_missing?(method_name, include_private = false)
23
+ @filter.present? && @filter.key?(method_name) || super
24
+ end
25
+ end
26
+
27
+ included do
28
+ helper_method :search, :filter
29
+
30
+ private
31
+
32
+ def search
33
+ @search ||= search_klass.new(search_params)
34
+ end
35
+
36
+ def search_klass
37
+ raise NotImplementedError, "A search class is neeeded to filter resources"
38
+ end
39
+
40
+ def filter
41
+ @filter ||= Filter.new(filter_params)
42
+ end
43
+
44
+ def search_params
45
+ default_search_params
46
+ .merge(filter_params)
47
+ .merge(context_params)
48
+ end
49
+
50
+ def filter_params
51
+ default_filter_params
52
+ .merge(params.to_unsafe_h[:filter].try(:symbolize_keys) || {})
53
+ end
54
+
55
+ def default_search_params
56
+ {}
57
+ end
58
+
59
+ def default_filter_params
60
+ {}
61
+ end
62
+
63
+ def context_params
64
+ {
65
+ feature: current_feature,
66
+ current_user: current_user
67
+ }
68
+ end
69
+ end
70
+ end
71
+ end
@@ -33,45 +33,48 @@ module Decidim
33
33
  # Initializes the form factory object.
34
34
  #
35
35
  # klass - the class name of the Form object that will be initialized
36
- # context - the Controller where the form is built.
37
- def initialize(klass, context)
36
+ # controller - the Controller where the form is built.
37
+ def initialize(klass, controller)
38
38
  @klass = klass
39
- @context = context
39
+ @controller = controller
40
40
  end
41
41
 
42
42
  # Returns a simple instance of the form klass.
43
- def instance(context = {})
44
- @klass.new(context)
43
+ #
44
+ # extra_context - A Hash with optional extra context data.
45
+ def instance(extra_context = {})
46
+ @klass.new(context.merge(extra_context))
45
47
  end
46
48
 
47
49
  # Initializes a form object from a model. Delegates the functionality
48
50
  # to the form object class method.
49
51
  #
50
- # model - the model instance from which the form object will be
51
- # initialized.
52
- # context - a Hash with optional context data.
53
- def from_model(model, context = {})
54
- from_params(model.attributes, context)
52
+ # model - the model instance from which the form object will be
53
+ # initialized.
54
+ # extra_context - a Hash with optional context data.
55
+ def from_model(model, extra_context = {})
56
+ @klass.from_model(model).with_context(context.merge(extra_context))
55
57
  end
56
58
 
57
59
  # Initializes a form object instance from params, and it
58
60
  # automatically adds some context. Context can be extended.
59
61
  #
60
- # params - a Hash with params. Mostly a set of params from a form.
61
- # context - a Hash with optional context data.
62
- def from_params(params, context = {})
63
- @klass.from_params(params, context_hash.merge(context))
62
+ # params - a Hash with params. Mostly a set of params from a form.
63
+ # extra_context - a Hash with optional context data.
64
+ def from_params(params, extra_context = {})
65
+ @klass.from_params(params).with_context(context.merge(extra_context))
64
66
  end
65
67
 
66
68
  # Sets a base context from the current controller. Since this can be
67
69
  # used from some controllers that do not respond to the helper
68
70
  # methods used here, this Hash can have different keys depending on
69
71
  # the controller that uses it.
70
- def context_hash
72
+ def context
71
73
  {
72
- current_organization: @context.try(:current_organization),
73
- current_user: @context.try(:current_user)
74
- }.compact
74
+ current_organization: @controller.try(:current_organization),
75
+ current_feature: @controller.try(:current_feature),
76
+ current_user: @controller.try(:current_user)
77
+ }
75
78
  end
76
79
  end.new(klass, self)
77
80
  end