decidim-core 0.4.3 → 0.4.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (62) hide show
  1. checksums.yaml +4 -4
  2. data/app/assets/stylesheets/decidim/modules/_card-grid.scss +2 -2
  3. data/app/assets/stylesheets/decidim/modules/_filters.scss +3 -3
  4. data/app/assets/stylesheets/decidim/modules/_main-container.scss +1 -5
  5. data/app/assets/stylesheets/decidim/modules/_process-nav.scss +1 -2
  6. data/app/constraints/decidim/current_participatory_process.rb +1 -1
  7. data/app/controllers/concerns/decidim/needs_authorization.rb +2 -3
  8. data/app/controllers/concerns/decidim/needs_participatory_process.rb +1 -1
  9. data/app/controllers/concerns/decidim/{feature_settings.rb → settings.rb} +1 -1
  10. data/app/controllers/decidim/features/base_controller.rb +1 -2
  11. data/app/controllers/decidim/pages_controller.rb +1 -1
  12. data/app/helpers/decidim/feature_path_helper.rb +1 -1
  13. data/{lib → app/models}/decidim/abilities/admin_ability.rb +1 -0
  14. data/app/models/decidim/abilities/base_ability.rb +34 -0
  15. data/{lib → app/models}/decidim/abilities/participatory_process_admin_ability.rb +4 -0
  16. data/{lib → app/models}/decidim/abilities/participatory_process_collaborator_ability.rb +4 -0
  17. data/{lib → app/models}/decidim/abilities/participatory_process_moderator_ability.rb +0 -0
  18. data/app/models/decidim/feature.rb +3 -78
  19. data/app/models/decidim/organization.rb +0 -2
  20. data/app/models/decidim/participatory_process.rb +2 -16
  21. data/app/models/decidim/participatory_process_group.rb +1 -2
  22. data/app/models/decidim/participatory_process_user_role.rb +9 -0
  23. data/app/models/decidim/user.rb +0 -7
  24. data/app/presenters/decidim/home_stats_presenter.rb +1 -1
  25. data/app/presenters/decidim/resource_locator_presenter.rb +57 -15
  26. data/app/queries/decidim/highlighted_participatory_processes.rb +1 -2
  27. data/app/queries/decidim/organization_participatory_process_groups.rb +14 -0
  28. data/app/queries/decidim/organization_participatory_processes.rb +2 -6
  29. data/app/queries/decidim/organization_prioritized_participatory_processes.rb +3 -3
  30. data/app/queries/decidim/organization_published_participatory_processes.rb +17 -0
  31. data/app/queries/decidim/participatory_processes_with_user_role.rb +1 -1
  32. data/app/queries/decidim/prioritized_participatory_processes.rb +1 -1
  33. data/app/queries/decidim/published_participatory_processes.rb +10 -0
  34. data/app/views/layouts/decidim/_process_header.html.erb +2 -2
  35. data/config/locales/ca.yml +19 -0
  36. data/config/locales/es.yml +19 -0
  37. data/config/locales/fr.yml +2 -2
  38. data/db/migrate/20170608142521_add_organization_to_user_groups.rb +16 -3
  39. data/db/seeds.rb +17 -12
  40. data/lib/decidim/abilities.rb +0 -4
  41. data/lib/decidim/abilities/participatory_process_role_ability.rb +4 -1
  42. data/lib/decidim/core.rb +20 -20
  43. data/lib/decidim/core/api/decidim_type.rb +1 -1
  44. data/lib/decidim/core/api/process_step_type.rb +2 -2
  45. data/lib/decidim/core/api/process_type.rb +1 -1
  46. data/lib/decidim/core/api/session_type.rb +1 -1
  47. data/lib/decidim/core/api/translated_field_type.rb +3 -3
  48. data/lib/decidim/core/test.rb +1 -0
  49. data/lib/decidim/core/test/factories.rb +21 -2
  50. data/lib/decidim/core/test/shared_examples/publicable.rb +27 -0
  51. data/lib/decidim/core/version.rb +1 -1
  52. data/lib/decidim/feature_manifest.rb +6 -6
  53. data/lib/decidim/form_builder.rb +1 -1
  54. data/lib/decidim/has_category.rb +1 -1
  55. data/lib/decidim/has_settings.rb +66 -0
  56. data/lib/decidim/manifest_registry.rb +45 -0
  57. data/lib/decidim/publicable.rb +49 -0
  58. data/lib/decidim/query_extensions.rb +1 -1
  59. data/lib/decidim/reportable.rb +3 -3
  60. data/lib/decidim/{features/settings_manifest.rb → settings_manifest.rb} +5 -5
  61. metadata +26 -33
  62. data/app/models/decidim/ability.rb +0 -32
@@ -13,7 +13,10 @@ module Decidim
13
13
  # Define abilities if the user is not an admin and has at least one process to manage.
14
14
  if not_admin? && has_manageable_processes?
15
15
  define_abilities
16
- define_participatory_process_abilities if current_participatory_process && can_manage_process?(current_participatory_process)
16
+
17
+ if current_participatory_process && can_manage_process?(current_participatory_process)
18
+ define_participatory_process_abilities
19
+ end
17
20
  end
18
21
  end
19
22
 
data/lib/decidim/core.rb CHANGED
@@ -18,9 +18,11 @@ module Decidim
18
18
  autoload :Reportable, "decidim/reportable"
19
19
  autoload :Authorable, "decidim/authorable"
20
20
  autoload :Notifiable, "decidim/notifiable"
21
+ autoload :Publicable, "decidim/publicable"
21
22
  autoload :Features, "decidim/features"
22
23
  autoload :HasAttachments, "decidim/has_attachments"
23
24
  autoload :FeatureValidator, "decidim/feature_validator"
25
+ autoload :HasSettings, "decidim/has_settings"
24
26
  autoload :HasFeature, "decidim/has_feature"
25
27
  autoload :HasScope, "decidim/has_scope"
26
28
  autoload :HasCategory, "decidim/has_category"
@@ -32,6 +34,7 @@ module Decidim
32
34
  autoload :Menu, "decidim/menu"
33
35
  autoload :MenuItem, "decidim/menu_item"
34
36
  autoload :MenuRegistry, "decidim/menu_registry"
37
+ autoload :ManifestRegistry, "decidim/manifest_registry"
35
38
  autoload :Abilities, "decidim/abilities"
36
39
 
37
40
  include ActiveSupport::Configurable
@@ -49,7 +52,11 @@ module Decidim
49
52
  railtie.load_seed
50
53
  end
51
54
 
52
- Decidim.feature_manifests.each(&:seed!)
55
+ Decidim::ParticipatoryProcess.find_each do |process|
56
+ Decidim.feature_manifests.each do |feature|
57
+ feature.seed!(process)
58
+ end
59
+ end
53
60
 
54
61
  I18n.available_locales = original_locale
55
62
  end
@@ -62,7 +69,8 @@ module Decidim
62
69
  config_accessor :mailer_sender
63
70
 
64
71
  # Exposes a configuration option: an Array of `cancancan`'s Ability classes
65
- # that will be automatically included to the base `Decidim::Ability` class.
72
+ # that will be automatically included to the base `Decidim::Abilities::BaseAbility`
73
+ # class.
66
74
  config_accessor :abilities do
67
75
  []
68
76
  end
@@ -138,19 +146,16 @@ module Decidim
138
146
  # name - A Symbol with the feature's unique name.
139
147
  #
140
148
  # Returns nothing.
141
- def self.register_feature(name)
142
- manifest = FeatureManifest.new(name: name.to_sym)
143
- yield(manifest)
144
- manifest.validate!
145
- feature_manifests << manifest
149
+ def self.register_feature(name, &block)
150
+ feature_registry.register(name, &block)
146
151
  end
147
152
 
148
- # Public: Finds all the registered feature manifest's via the
149
- # `register_feature` method.
153
+ # Public: Finds all registered feature manifest's via the `register_feature`
154
+ # method.
150
155
  #
151
156
  # Returns an Array[FeatureManifest].
152
157
  def self.feature_manifests
153
- @feature_manifests ||= Set.new
158
+ feature_registry.manifests
154
159
  end
155
160
 
156
161
  # Public: Finds a feature manifest by the feature's name.
@@ -159,8 +164,7 @@ module Decidim
159
164
  #
160
165
  # Returns a FeatureManifest if found, nil otherwise.
161
166
  def self.find_feature_manifest(name)
162
- name = name.to_sym
163
- feature_manifests.find { |manifest| manifest.name == name }
167
+ feature_registry.find(name.to_sym)
164
168
  end
165
169
 
166
170
  # Public: Finds a resource manifest by the resource's name.
@@ -170,16 +174,12 @@ module Decidim
170
174
  #
171
175
  # Returns a ResourceManifest if found, nil otherwise.
172
176
  def self.find_resource_manifest(resource_name_or_klass)
173
- resource_manifests.find do |manifest|
174
- manifest.model_class == resource_name_or_klass || manifest.name.to_s == resource_name_or_klass.to_s
175
- end
177
+ feature_registry.find_resource_manifest(resource_name_or_klass)
176
178
  end
177
179
 
178
- # Private: Stores all the resource manifest across all feature manifest.
179
- #
180
- # Returns an Array[ResourceManifest]
181
- def self.resource_manifests
182
- @resource_manifests ||= feature_manifests.flat_map(&:resource_manifests)
180
+ # Public: Stores the registry of features
181
+ def self.feature_registry
182
+ @feature_registry ||= ManifestRegistry.new(:features)
183
183
  end
184
184
 
185
185
  # Public: Stores an instance of StatsRegistry
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Decidim
4
- # This type represents a ParticipatoryProcess.
4
+ # This type represents a Decidim's global property.
5
5
  DecidimType = GraphQL::ObjectType.define do
6
6
  name "Decidim"
7
7
  description "Decidim's framework-related properties."
@@ -9,11 +9,11 @@ module Decidim
9
9
  field :id, !types.ID, "The unique ID of this step."
10
10
 
11
11
  field :process do
12
- type ProcessType
12
+ type !ProcessType
13
13
  description "The participatory process in which this step belongs to."
14
14
  property :participatory_process
15
15
  end
16
16
 
17
- field :title, TranslatedFieldType, "The title of this step"
17
+ field :title, !TranslatedFieldType, "The title of this step"
18
18
  end
19
19
  end
@@ -8,7 +8,7 @@ module Decidim
8
8
 
9
9
  field :id, !types.ID, "The Process' unique ID"
10
10
 
11
- field :title, TranslatedFieldType, "The title of this process."
11
+ field :title, !TranslatedFieldType, "The title of this process."
12
12
 
13
13
  connection :steps, ProcessStepType.connection_type do
14
14
  description "All the steps of this process."
@@ -10,7 +10,7 @@ module Decidim
10
10
  resolve ->(obj, _args, _ctx) { obj }
11
11
  end
12
12
 
13
- field :verifiedUserGroups, !types[UserGroupType], "The current user verified user groups" do
13
+ field :verifiedUserGroups, !types[!UserGroupType], "The current user verified user groups" do
14
14
  resolve ->(obj, _args, _ctx) { obj.user_groups.verified }
15
15
  end
16
16
  end
@@ -7,17 +7,17 @@ module Decidim
7
7
  description "A translated field"
8
8
 
9
9
  field :locales do
10
- type types[types.String]
10
+ type types[!types.String]
11
11
  description "Lists all the locales in which this translation is available"
12
12
  resolve ->(obj, _args, _ctx) { obj.keys }
13
13
  end
14
14
 
15
15
  field :translations do
16
- type !types[LocalizedStringType]
16
+ type !types[!LocalizedStringType]
17
17
  description "All the localized strings for this translation."
18
18
 
19
19
  argument :locales do
20
- type types[types.String]
20
+ type types[!types.String]
21
21
  description "A list of locales to scope the translations to."
22
22
  end
23
23
 
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "decidim/core/test/shared_examples/authorable"
4
+ require "decidim/core/test/shared_examples/publicable"
4
5
  require "decidim/core/test/shared_examples/localised_email"
5
6
  require "decidim/core/test/shared_examples/has_attachments"
6
7
  require "decidim/core/test/shared_examples/has_feature"
@@ -153,7 +153,11 @@ FactoryGirl.define do
153
153
  end
154
154
 
155
155
  trait :process_admin do
156
- transient { participatory_process nil }
156
+ transient do
157
+ participatory_process { create(:participatory_process) }
158
+ end
159
+
160
+ organization { participatory_process.organization }
157
161
 
158
162
  after(:create) do |user, evaluator|
159
163
  create :participatory_process_user_role,
@@ -162,11 +166,26 @@ FactoryGirl.define do
162
166
  role: :admin
163
167
  end
164
168
  end
169
+
170
+ trait :process_collaborator do
171
+ transient do
172
+ participatory_process { create(:participatory_process) }
173
+ end
174
+
175
+ organization { participatory_process.organization }
176
+
177
+ after(:create) do |user, evaluator|
178
+ create :participatory_process_user_role,
179
+ user: user,
180
+ participatory_process: evaluator.participatory_process,
181
+ role: :collaborator
182
+ end
183
+ end
165
184
  end
166
185
 
167
186
  factory :participatory_process_user_role, class: Decidim::ParticipatoryProcessUserRole do
168
187
  user
169
- participatory_process
188
+ participatory_process { create :participatory_process, organization: user.organization }
170
189
  role "admin"
171
190
  end
172
191
 
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "spec_helper"
4
+
5
+ shared_examples_for "publicable" do
6
+ let(:factory_name) { described_class.name.demodulize.underscore.to_sym }
7
+
8
+ let!(:published) do
9
+ create(factory_name, published_at: Time.zone.now)
10
+ end
11
+
12
+ let!(:unpublished) do
13
+ create(factory_name, published_at: nil)
14
+ end
15
+
16
+ describe ".published" do
17
+ let(:scope) { described_class.send(:published) }
18
+
19
+ it { expect(scope).to eq([published]) }
20
+ end
21
+
22
+ describe ".unpublished" do
23
+ let(:scope) { described_class.send(:unpublished) }
24
+
25
+ it { expect(scope).to eq([unpublished]) }
26
+ end
27
+ end
@@ -3,7 +3,7 @@
3
3
  # This holds Decidim's version and the Rails version on which it depends.
4
4
  module Decidim
5
5
  def self.version
6
- "0.4.3"
6
+ "0.4.4"
7
7
  end
8
8
 
9
9
  def self.rails_version
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "decidim/features/settings_manifest"
3
+ require "decidim/settings_manifest"
4
4
  require "decidim/features/export_manifest"
5
5
 
6
6
  module Decidim
@@ -92,15 +92,15 @@ module Decidim
92
92
  # Public: Creates the seeds for this features in order to populate the database.
93
93
  #
94
94
  # Returns nothing.
95
- def seed!
96
- @seeds&.call
95
+ def seed!(process)
96
+ @seeds&.call(process)
97
97
  end
98
98
 
99
99
  # Public: Adds configurable attributes for this feature, scoped to a name. It
100
- # uses the DSL specified under `Decidim::FeatureSettingsManifest`.
100
+ # uses the DSL specified under `Decidim::SettingsManifest`.
101
101
  #
102
102
  # name - Either `global` or `step`
103
- # &block - The DSL present on `Decidim::FeatureSettingsManifest`
103
+ # &block - The DSL present on `Decidim::SettingsManifest`
104
104
  #
105
105
  # Examples:
106
106
  #
@@ -112,7 +112,7 @@ module Decidim
112
112
  def settings(name = :global, &block)
113
113
  @settings ||= {}
114
114
  name = name.to_sym
115
- settings = (@settings[name] ||= FeatureSettingsManifest.new)
115
+ settings = (@settings[name] ||= SettingsManifest.new)
116
116
  yield(settings) if block
117
117
  settings
118
118
  end
@@ -161,7 +161,7 @@ module Decidim
161
161
  # datepicker library
162
162
  def datetime_field(attribute, options = {})
163
163
  value = object.send(attribute)
164
- if value
164
+ if value.present?
165
165
  iso_value = value.strftime("%Y-%m-%dT%H:%M:%S")
166
166
  formatted_value = I18n.localize(value, format: :timepicker)
167
167
  end
@@ -3,7 +3,7 @@
3
3
  require "active_support/concern"
4
4
 
5
5
  module Decidim
6
- # A concern with the features needed when you want a model to be have a category.
6
+ # A concern with the features needed when you want a model to have a category.
7
7
  module HasCategory
8
8
  extend ActiveSupport::Concern
9
9
 
@@ -0,0 +1,66 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "active_support/concern"
4
+
5
+ module Decidim
6
+ module HasSettings
7
+ extend ActiveSupport::Concern
8
+
9
+ included do
10
+ after_initialize :default_values
11
+ end
12
+
13
+ def settings
14
+ settings_schema(:global).new(self[:settings]["global"])
15
+ end
16
+
17
+ def settings=(data)
18
+ self[:settings]["global"] = serialize_settings(settings_schema(:global), data)
19
+ end
20
+
21
+ def default_step_settings
22
+ settings_schema(:step).new(self[:settings]["default_step"])
23
+ end
24
+
25
+ def default_step_settings=(data)
26
+ self[:settings]["default_step"] = serialize_settings(settings_schema(:step), data)
27
+ end
28
+
29
+ def step_settings
30
+ participatory_process.steps.each_with_object({}) do |step, result|
31
+ result[step.id.to_s] = settings_schema(:step).new(self[:settings].dig("steps", step.id.to_s))
32
+ end
33
+ end
34
+
35
+ def step_settings=(data)
36
+ self[:settings]["steps"] = data.each_with_object({}) do |(key, value), result|
37
+ result[key.to_s] = serialize_settings(settings_schema(:step), value)
38
+ end
39
+ end
40
+
41
+ def active_step_settings
42
+ active_step = participatory_process.active_step
43
+ return default_step_settings unless active_step
44
+
45
+ step_settings.fetch(active_step.id.to_s)
46
+ end
47
+
48
+ private
49
+
50
+ def serialize_settings(schema, value)
51
+ if value.respond_to?(:attributes)
52
+ value.attributes
53
+ else
54
+ schema.new(value)
55
+ end
56
+ end
57
+
58
+ def settings_schema(name)
59
+ manifest.settings(name.to_sym).schema
60
+ end
61
+
62
+ def default_values
63
+ self[:settings] ||= {}
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,45 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ #
5
+ # Takes care of holding and serving globally registered manifests.
6
+ #
7
+ class ManifestRegistry
8
+ def initialize(entity)
9
+ @entity = entity
10
+ end
11
+
12
+ def register(name)
13
+ manifest = manifest_class.new(name: name.to_sym)
14
+ yield(manifest)
15
+ manifest.validate!
16
+ manifests << manifest
17
+ end
18
+
19
+ def manifests
20
+ @manifests ||= Set.new
21
+ end
22
+
23
+ def find(name)
24
+ manifests.find { |manifest| manifest.name == name }
25
+ end
26
+
27
+ def resource_manifests
28
+ @resource_manifests ||= manifests.flat_map(&:resource_manifests)
29
+ end
30
+
31
+ def find_resource_manifest(resource_name_or_klass)
32
+ resource_manifests.find do |manifest|
33
+ manifest.model_class == resource_name_or_klass || manifest.name.to_s == resource_name_or_klass.to_s
34
+ end
35
+ end
36
+
37
+ private
38
+
39
+ def manifest_class
40
+ case @entity
41
+ when :features then FeatureManifest
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,49 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "active_support/concern"
4
+
5
+ module Decidim
6
+ # This concern contains the logic related to publication and promotion.
7
+ module Publicable
8
+ extend ActiveSupport::Concern
9
+
10
+ class_methods do
11
+ # Public: Scope to return only published records.
12
+ #
13
+ # Returns an ActiveRecord::Relation.
14
+ def published
15
+ where.not(published_at: nil)
16
+ end
17
+
18
+ # Public: Scope to return only unpublished records.
19
+ #
20
+ # Returns an ActiveRecord::Relation.
21
+ def unpublished
22
+ where(published_at: nil)
23
+ end
24
+ end
25
+
26
+ # Public: Checks whether the record has been published or not.
27
+ #
28
+ # Returns true if published, false otherwise.
29
+ def published?
30
+ published_at.present?
31
+ end
32
+
33
+ #
34
+ # Public: Publishes this feature
35
+ #
36
+ # Returns true if the record was properly saved, false otherwise.
37
+ def publish!
38
+ update_attribute(:published_at, Time.current)
39
+ end
40
+
41
+ #
42
+ # Public: Unpublishes this feature
43
+ #
44
+ # Returns true if the record was properly saved, false otherwise.
45
+ def unpublish!
46
+ update_attribute(:published_at, nil)
47
+ end
48
+ end
49
+ end