decidim-api 0.31.6 → 0.31.8

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 61cb160723618a257df9405aa39500197934046e6082c7fa6d6fe69c74d87135
4
- data.tar.gz: 4b3e95e1cbc0c284dd195a5c48527b0784cac902f42e90c1fa1268c290deb3af
3
+ metadata.gz: 000be390e45024f2d1ece4e95cfd630e24a23c9c3fb5358e05238767aa89ca5d
4
+ data.tar.gz: 36a051e7271e07c8ea618d44e6e0f73c98184e7a275d0b3889d3045fcf3cc4ed
5
5
  SHA512:
6
- metadata.gz: c19c90f82366f13dd3c70b8b437a5df828a69b832e10c4345a47b6d05651aded1c4dc59d0b787d86b75e53c7f46f7831d84f7a100e979b5d1bc469fc75b0cc19
7
- data.tar.gz: b518b8b68e627eff552f84b5b3b9ec8faeda1181c24b777de57b372b825da37bccc54813bd5aaf7b88d064980b807ba0c92a08bb2baf6282686c7f29836cfa99
6
+ metadata.gz: 4ebe3978797e8f12fd6e89767d408f52c9b086110a70ceb34c61c6472e0acfbb65e12f6496a4fe188236e59041863340f67c7c74af6ebd4a84a520eba3c68afb
7
+ data.tar.gz: c7851eccab45b3541e31e63058739cd601e36686fe7e7d4bcc82adf11ac6477e4308a73c667c6150bf17b6e20efafb3ea573e6caa74addfd0a2833800e9a89b3
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "active_support/concern"
4
+
5
+ module Decidim
6
+ module Api
7
+ # This concern adds the JWT authenticable strategy for the User models to
8
+ # allow regular users to sign in through the API (if configured from the
9
+ # system panel). Allows normal users to utilize the API e.g. through mobile
10
+ # applications.
11
+ module UserExtension
12
+ extend ActiveSupport::Concern
13
+
14
+ included do
15
+ devise :jwt_authenticatable, jwt_revocation_strategy: Decidim::Api::JwtDenylist
16
+ end
17
+ end
18
+ end
19
+ end
@@ -3,5 +3,6 @@ cs:
3
3
  decidim:
4
4
  api:
5
5
  errors:
6
+ introspection_disabled: Introspekce je pro tento požadavek zakázána
6
7
  recursion_limit_exceeded_error: V dotazu bylo zjištěno příliš mnoho rekurzí
7
8
  too_many_aliases_error: Příliš mnoho aliasů. Použili jste aliasy %{size}, ale %{limit} jsou povoleny.
@@ -1 +1,8 @@
1
+ ---
1
2
  de:
3
+ decidim:
4
+ api:
5
+ errors:
6
+ introspection_disabled: Introspection ist für diese Anfrage deaktiviert
7
+ recursion_limit_exceeded_error: In der Abfrage wurden zu viele Rekursionen festgestellt
8
+ too_many_aliases_error: Es wurden zu viele Aliase verwendet. Sie haben %{size} Aliase verwendet, erlaubt sind jedoch nur %{limit}.
@@ -1 +1,8 @@
1
+ ---
1
2
  gl:
3
+ decidim:
4
+ api:
5
+ errors:
6
+ introspection_disabled: A introspección está desactivada para esta solicitude
7
+ recursion_limit_exceeded_error: Detectáronse demasiadas recursións na consulta
8
+ too_many_aliases_error: Usáronse demasiados alias. Usaches %{size}, pero só se permiten %{limit}.
@@ -41,6 +41,45 @@ module Decidim
41
41
  end
42
42
  end
43
43
 
44
+ initializer "decidim_api.devise", before: "add_routing_paths" do |app|
45
+ config.to_prepare do
46
+ Decidim::User.include Decidim::Api::UserExtension
47
+ end
48
+
49
+ # Required for the development environment because otherwise the JWT
50
+ # authentication strategy would be lost during code reloads.
51
+ app.reloader.after_class_unload do
52
+ Decidim::User.include Decidim::Api::UserExtension
53
+ end
54
+ end
55
+
56
+ initializer "decidim_api.devise_jwt", after: "devise.secret_key" do
57
+ Devise.jwt do |jwt|
58
+ # In order to be compatible with the JWT authentication, we need to set these
59
+ # configurations. JWT secret is being used by the devise-jwt to sign the
60
+ # tokens, once the user authenticated. The token signature ensures the
61
+ # validity of the token and that the user has not tampered with it. If the
62
+ # secret is not set correctly, the API authentication does not work.
63
+ #
64
+ # Note that the `dispatch_requests` and `revocation_requests` paths are the
65
+ # full paths because we do not want the JWT tokens to be dispatched or revoked
66
+ # during normal Decidim user sign ins or sign outs. This also requires a small
67
+ # override to `Warden::JWTAuth` which is defined at
68
+ # `decidim-api/lib/warden/jwt_auth/decidim_overrides.rb`.
69
+ jwt.secret = Decidim::Env.new("DECIDIM_API_JWT_SECRET").value || Devise.secret_key
70
+ raise "Please define the secret key for Devise" unless jwt.secret
71
+
72
+ jwt.dispatch_requests = [
73
+ ["POST", %r{^/api/sign_in$}]
74
+ ]
75
+ jwt.revocation_requests = [
76
+ ["DELETE", %r{^/api/sign_out$}]
77
+ ]
78
+ jwt.expiration_time = Decidim::Api.jwt_expires_in.minutes.to_i
79
+ jwt.aud_header = "X_JWT_AUD"
80
+ end
81
+ end
82
+
44
83
  initializer "decidim_api.data_migrate", after: "decidim_core.data_migrate" do
45
84
  DataMigrate.configure do |config|
46
85
  config.data_migrations_path << root.join("db/data").to_s
@@ -17,8 +17,8 @@ module Decidim
17
17
  subject = determine_subject_name(object)
18
18
  context[subject] = object
19
19
 
20
- chain.unshift(allowed_to?(:read, :participatory_space, object, context)) if object.respond_to?(:participatory_space)
21
- chain.unshift(allowed_to?(:read, :component, object, context)) if object.respond_to?(:component) && object.component.present?
20
+ chain.unshift(allowed_to?(:read, :participatory_space, object.participatory_space, context)) if object.respond_to?(:participatory_space)
21
+ chain.unshift(allowed_to?(:read, :component, object.component, context)) if object.respond_to?(:component) && object.component.present?
22
22
 
23
23
  super && chain.all?
24
24
  end
@@ -43,12 +43,7 @@ module Decidim
43
43
  permission_action = Decidim::PermissionAction.new(scope:, action:, subject:)
44
44
 
45
45
  permission_chain(object).inject(permission_action) do |current_permission_action, permission_class|
46
- permission_context =
47
- if scope == :admin
48
- local_admin_context(object, context)
49
- else
50
- local_context(object, context)
51
- end
46
+ permission_context = local_user_context(object, context)
52
47
 
53
48
  permission_class.new(
54
49
  context[:current_user],
@@ -58,25 +53,40 @@ module Decidim
58
53
  end.allowed?
59
54
  end
60
55
 
61
- # Injects into context object current_participatory_space and current_component keys as they are needed
56
+ # Injects into the context the current_participatory_space and current_component keys
57
+ # for the object being checked, as they are needed by the permission classes.
62
58
  #
63
59
  # @param object [ActiveModel::Base] The object that is being represented.
64
60
  # @param context [GraphQL::Query::Context] The GraphQL context
65
61
  #
66
62
  # @return Hash
67
63
  def local_context(object, context)
68
- context[:current_participatory_space] = object.participatory_space if object.respond_to?(:participatory_space)
69
- context[:current_component] =
70
- if object.is_a?(Decidim::Component)
71
- object
72
- elsif object.respond_to?(:component)
73
- object.component
74
- end
64
+ participatory_space = participatory_space_for(object)
65
+ component = component_for(object)
66
+
67
+ # Always use the associations of the object being checked. The context
68
+ # is shared by every field in the query, so keeping a previous object's
69
+ # space could authorize resources from a different space.
70
+ context[:current_participatory_space] = participatory_space if participatory_space
71
+ context[:current_component] = component if component
75
72
 
76
73
  context.to_h
77
74
  end
78
75
 
79
- def local_admin_context(object, context)
76
+ def participatory_space_for(object)
77
+ return object.participatory_space if object.respond_to?(:participatory_space)
78
+ return object if object.is_a?(Decidim::Participable)
79
+
80
+ component_for(object)&.participatory_space
81
+ end
82
+
83
+ def component_for(object)
84
+ return object if object.is_a?(Decidim::Component)
85
+
86
+ object.component if object.respond_to?(:component)
87
+ end
88
+
89
+ def local_user_context(object, context)
80
90
  context = local_context(object, context)
81
91
 
82
92
  component = context[:current_component]
@@ -103,7 +113,9 @@ module Decidim
103
113
  Decidim::Permissions
104
114
  ]
105
115
 
106
- if object.is_a?(Decidim::Component)
116
+ if object.is_a?(Decidim::Participable)
117
+ permissions.unshift(object.manifest.permissions_class)
118
+ elsif object.is_a?(Decidim::Component)
107
119
  permissions.unshift(object.participatory_space.manifest.permissions_class)
108
120
  permissions.unshift(object.manifest.permissions_class)
109
121
  else
@@ -10,4 +10,50 @@ shared_examples_for "commentable interface" do
10
10
  expect(response["totalCommentsCount"]).to eq(model.comments_count)
11
11
  end
12
12
  end
13
+
14
+ describe "with comments" do
15
+ let(:comments) { create_list(:comment, 5, commentable: model) }
16
+ let(:subcomments_level1) do
17
+ comments.map do |comment|
18
+ create_list(:comment, 2, commentable: comment)
19
+ end.flatten
20
+ end
21
+ let!(:subcomments_level2) do
22
+ subcomments_level1.map do |comment|
23
+ create(:comment, commentable: comment)
24
+ end
25
+ end
26
+
27
+ let(:query) do
28
+ %(
29
+ {
30
+ comments {
31
+ ...dataFragment
32
+ comments {
33
+ ...dataFragment
34
+ }
35
+ }
36
+ }
37
+ fragment dataFragment on Comment {
38
+ id
39
+ body
40
+ createdAt
41
+ author { name }
42
+ }
43
+ )
44
+ end
45
+
46
+ it "includes the comments" do
47
+ expect(response["comments"]).to be_a(Array)
48
+ expect(response["comments"].count).to eq(5)
49
+
50
+ response["comments"].each do |comment|
51
+ expect(comment["comments"]).to be_a(Array)
52
+ expect(comment["comments"].count).to eq(2)
53
+
54
+ subcomments = subcomments_level1.select { |c| c.commentable.id == comment["id"].to_i }
55
+ expect(comment["comments"].map { |c| c["id"].to_i }).to match_array(subcomments.map(&:id))
56
+ end
57
+ end
58
+ end
13
59
  end
@@ -4,7 +4,7 @@ module Decidim
4
4
  # This holds the decidim-api version.
5
5
  module Api
6
6
  def self.version
7
- "0.31.6"
7
+ "0.31.8"
8
8
  end
9
9
  end
10
10
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: decidim-api
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.31.6
4
+ version: 0.31.8
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: 2026-07-06 00:00:00.000000000 Z
13
+ date: 2026-10-22 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: decidim-core
@@ -18,14 +18,14 @@ dependencies:
18
18
  requirements:
19
19
  - - '='
20
20
  - !ruby/object:Gem::Version
21
- version: 0.31.6
21
+ version: 0.31.8
22
22
  type: :runtime
23
23
  prerelease: false
24
24
  version_requirements: !ruby/object:Gem::Requirement
25
25
  requirements:
26
26
  - - '='
27
27
  - !ruby/object:Gem::Version
28
- version: 0.31.6
28
+ version: 0.31.8
29
29
  - !ruby/object:Gem::Dependency
30
30
  name: devise-jwt
31
31
  requirement: !ruby/object:Gem::Requirement
@@ -94,56 +94,56 @@ dependencies:
94
94
  requirements:
95
95
  - - '='
96
96
  - !ruby/object:Gem::Version
97
- version: 0.31.6
97
+ version: 0.31.8
98
98
  type: :development
99
99
  prerelease: false
100
100
  version_requirements: !ruby/object:Gem::Requirement
101
101
  requirements:
102
102
  - - '='
103
103
  - !ruby/object:Gem::Version
104
- version: 0.31.6
104
+ version: 0.31.8
105
105
  - !ruby/object:Gem::Dependency
106
106
  name: decidim-comments
107
107
  requirement: !ruby/object:Gem::Requirement
108
108
  requirements:
109
109
  - - '='
110
110
  - !ruby/object:Gem::Version
111
- version: 0.31.6
111
+ version: 0.31.8
112
112
  type: :development
113
113
  prerelease: false
114
114
  version_requirements: !ruby/object:Gem::Requirement
115
115
  requirements:
116
116
  - - '='
117
117
  - !ruby/object:Gem::Version
118
- version: 0.31.6
118
+ version: 0.31.8
119
119
  - !ruby/object:Gem::Dependency
120
120
  name: decidim-dev
121
121
  requirement: !ruby/object:Gem::Requirement
122
122
  requirements:
123
123
  - - '='
124
124
  - !ruby/object:Gem::Version
125
- version: 0.31.6
125
+ version: 0.31.8
126
126
  type: :development
127
127
  prerelease: false
128
128
  version_requirements: !ruby/object:Gem::Requirement
129
129
  requirements:
130
130
  - - '='
131
131
  - !ruby/object:Gem::Version
132
- version: 0.31.6
132
+ version: 0.31.8
133
133
  - !ruby/object:Gem::Dependency
134
134
  name: decidim-participatory_processes
135
135
  requirement: !ruby/object:Gem::Requirement
136
136
  requirements:
137
137
  - - '='
138
138
  - !ruby/object:Gem::Version
139
- version: 0.31.6
139
+ version: 0.31.8
140
140
  type: :development
141
141
  prerelease: false
142
142
  version_requirements: !ruby/object:Gem::Requirement
143
143
  requirements:
144
144
  - - '='
145
145
  - !ruby/object:Gem::Version
146
- version: 0.31.6
146
+ version: 0.31.8
147
147
  description: API engine for decidim
148
148
  email:
149
149
  - josepjaume@gmail.com
@@ -160,6 +160,7 @@ files:
160
160
  - app/controllers/decidim/api/graphiql_controller.rb
161
161
  - app/controllers/decidim/api/queries_controller.rb
162
162
  - app/controllers/decidim/api/sessions_controller.rb
163
+ - app/models/concerns/decidim/api/user_extension.rb
163
164
  - app/models/decidim/api/api_user.rb
164
165
  - app/models/decidim/api/jwt_denylist.rb
165
166
  - app/packs/entrypoints/decidim_api_docs.js
@@ -172,7 +173,6 @@ files:
172
173
  - app/views/decidim/api/graphiql/show.html.erb
173
174
  - app/views/layouts/decidim/api/documentation.html.erb
174
175
  - config/assets.rb
175
- - config/initializers/devise.rb
176
176
  - config/locales/am-ET.yml
177
177
  - config/locales/ar.yml
178
178
  - config/locales/bg.yml
@@ -1,26 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- Devise.jwt do |jwt|
4
- # In order to be compatible with the JWT authentication, we need to set these
5
- # configurations. JWT secret is being used by the devise-jwt to sign the
6
- # tokens, once the user authenticated. The token signature ensures the
7
- # validity of the token and that the user has not tampered with it. If the
8
- # secret is not set correctly, the API authentication does not work.
9
- #
10
- # Note that the `dispatch_requests` and `revocation_requests` paths are the
11
- # full paths because we do not want the JWT tokens to be dispatched or revoked
12
- # during normal Decidim user sign ins or sign outs. This also requires a small
13
- # override to `Warden::JWTAuth` which is defined at
14
- # `decidim-api/lib/warden/jwt_auth/decidim_overrides.rb`.
15
- jwt.secret = Decidim::Env.new("DECIDIM_API_JWT_SECRET").value
16
- next unless jwt.secret
17
-
18
- jwt.dispatch_requests = [
19
- ["POST", %r{^/api/sign_in$}]
20
- ]
21
- jwt.revocation_requests = [
22
- ["DELETE", %r{^/api/sign_out$}]
23
- ]
24
- jwt.expiration_time = Decidim::Api.jwt_expires_in.minutes.to_i
25
- jwt.aud_header = "X_JWT_AUD"
26
- end