graphql_devise 2.3.0 → 2.4.0
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 +4 -4
- data/.circleci/config.yml +60 -42
- data/Appraisals +15 -88
- data/CHANGELOG.md +9 -0
- data/README.md +9 -0
- data/config/locales/en.yml +1 -0
- data/config/locales/pt-BR.yml +1 -0
- data/graphql_devise.gemspec +2 -2
- data/lib/graphql_devise/default_operations.rb +2 -1
- data/lib/graphql_devise/mount_method/operation_preparers/default_operation_preparer.rb +1 -1
- data/lib/graphql_devise/mount_method/operation_sanitizer.rb +41 -14
- data/lib/graphql_devise/mount_method/supported_options.rb +2 -1
- data/lib/graphql_devise/mutations/destroy_account.rb +26 -0
- data/lib/graphql_devise/resource_loader.rb +4 -1
- data/lib/graphql_devise/version.rb +1 -1
- data/spec/dummy/config/routes.rb +3 -1
- data/spec/requests/mutations/destroy_account_spec.rb +67 -0
- data/spec/services/mount_method/operation_sanitizer_spec.rb +58 -1
- data/spec/spec_helper.rb +4 -2
- metadata +20 -17
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: daddc316d120f12ed4a6a781871ec676a0eb11d6d6a407a438e01460fbd5c668
|
|
4
|
+
data.tar.gz: 73f19c61b7484b7cb7801e99d5889ddffdb8a0c8bfed393bd22e669c5143ccf3
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 1ca7946d638f1e40e2b0bfe4f427cf1c60fc63e7b947ffb716858ba5278dfbb06717a8919e276e221701729069a8b421f8bd094874b7dc729cbb69e2dbfaaa7c
|
|
7
|
+
data.tar.gz: 31a7f42e8eaa5e268c829ea9b091c8edc3e73f4c0101520eee737de55c8fab1e12d1b67246709e6cca8f7a3278906fb61a675d9f8c439d861422aac26ab17baf
|
data/.circleci/config.yml
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
version: 2.1
|
|
2
2
|
orbs:
|
|
3
|
-
coveralls: coveralls/coveralls@
|
|
3
|
+
coveralls: coveralls/coveralls@2.2.5
|
|
4
4
|
|
|
5
5
|
jobs:
|
|
6
6
|
test:
|
|
@@ -12,9 +12,8 @@ jobs:
|
|
|
12
12
|
docker:
|
|
13
13
|
- image: 'ruby:<< parameters.ruby-version >>'
|
|
14
14
|
environment:
|
|
15
|
-
BUNDLE_GEMFILE:
|
|
15
|
+
BUNDLE_GEMFILE: gemfiles/<< parameters.gemfile >>.gemfile
|
|
16
16
|
BUNDLE_JOBS: '2'
|
|
17
|
-
COVERALLS_PARALLEL: 'true'
|
|
18
17
|
EAGER_LOAD: 'true'
|
|
19
18
|
RUBYOPT: '-rostruct'
|
|
20
19
|
steps:
|
|
@@ -27,6 +26,13 @@ jobs:
|
|
|
27
26
|
name: Run Specs
|
|
28
27
|
command:
|
|
29
28
|
bundle exec rspec
|
|
29
|
+
- coveralls/upload:
|
|
30
|
+
parallel: true
|
|
31
|
+
coverage_file: ./coverage/.resultset.json
|
|
32
|
+
coverage_format: simplecov
|
|
33
|
+
# Parallel jobs must each report a unique flag_name or Coveralls
|
|
34
|
+
# collapses them into a single job. Keep it free of slashes.
|
|
35
|
+
flag_name: ruby-<< parameters.ruby-version >>-<< parameters.gemfile >>
|
|
30
36
|
report-coverage:
|
|
31
37
|
docker:
|
|
32
38
|
- image: 'cimg/node:22.1.0'
|
|
@@ -47,63 +53,75 @@ workflows:
|
|
|
47
53
|
- '3.3'
|
|
48
54
|
- '3.4'
|
|
49
55
|
gemfile:
|
|
50
|
-
-
|
|
51
|
-
-
|
|
52
|
-
-
|
|
53
|
-
-
|
|
54
|
-
-
|
|
55
|
-
-
|
|
56
|
-
-
|
|
57
|
-
-
|
|
58
|
-
-
|
|
59
|
-
-
|
|
60
|
-
-
|
|
61
|
-
-
|
|
62
|
-
-
|
|
63
|
-
-
|
|
64
|
-
-
|
|
65
|
-
-
|
|
66
|
-
-
|
|
67
|
-
-
|
|
68
|
-
-
|
|
69
|
-
-
|
|
70
|
-
-
|
|
71
|
-
-
|
|
56
|
+
- rails7.0_graphql2.3
|
|
57
|
+
- rails7.0_graphql2.4
|
|
58
|
+
- rails7.1_graphql2.0
|
|
59
|
+
- rails7.1_graphql2.1
|
|
60
|
+
- rails7.1_graphql2.2
|
|
61
|
+
- rails7.1_graphql2.3
|
|
62
|
+
- rails7.1_graphql2.4
|
|
63
|
+
- rails7.2_graphql2.0
|
|
64
|
+
- rails7.2_graphql2.1
|
|
65
|
+
- rails7.2_graphql2.2
|
|
66
|
+
- rails7.2_graphql2.3
|
|
67
|
+
- rails7.2_graphql2.4
|
|
68
|
+
- rails7.2_graphql2.5
|
|
69
|
+
- rails7.2_graphql2.6
|
|
70
|
+
- rails8.0_graphql2.2
|
|
71
|
+
- rails8.0_graphql2.3
|
|
72
|
+
- rails8.0_graphql2.4
|
|
73
|
+
- rails8.0_graphql2.5
|
|
74
|
+
- rails8.0_graphql2.6
|
|
75
|
+
- rails8.1_graphql2.4
|
|
76
|
+
- rails8.1_graphql2.5
|
|
77
|
+
- rails8.1_graphql2.6
|
|
72
78
|
exclude:
|
|
73
79
|
- ruby-version: '3.0'
|
|
74
|
-
gemfile:
|
|
80
|
+
gemfile: rails7.2_graphql2.0
|
|
81
|
+
- ruby-version: '3.0'
|
|
82
|
+
gemfile: rails7.2_graphql2.1
|
|
83
|
+
- ruby-version: '3.0'
|
|
84
|
+
gemfile: rails7.2_graphql2.2
|
|
85
|
+
- ruby-version: '3.0'
|
|
86
|
+
gemfile: rails7.2_graphql2.3
|
|
75
87
|
- ruby-version: '3.0'
|
|
76
|
-
gemfile:
|
|
88
|
+
gemfile: rails7.2_graphql2.4
|
|
77
89
|
- ruby-version: '3.0'
|
|
78
|
-
gemfile:
|
|
90
|
+
gemfile: rails7.2_graphql2.5
|
|
79
91
|
- ruby-version: '3.0'
|
|
80
|
-
gemfile:
|
|
92
|
+
gemfile: rails7.2_graphql2.6
|
|
81
93
|
- ruby-version: '3.0'
|
|
82
|
-
gemfile:
|
|
94
|
+
gemfile: rails8.0_graphql2.2
|
|
83
95
|
- ruby-version: '3.0'
|
|
84
|
-
gemfile:
|
|
96
|
+
gemfile: rails8.0_graphql2.3
|
|
85
97
|
- ruby-version: '3.0'
|
|
86
|
-
gemfile:
|
|
98
|
+
gemfile: rails8.0_graphql2.4
|
|
87
99
|
- ruby-version: '3.0'
|
|
88
|
-
gemfile:
|
|
100
|
+
gemfile: rails8.0_graphql2.5
|
|
89
101
|
- ruby-version: '3.0'
|
|
90
|
-
gemfile:
|
|
102
|
+
gemfile: rails8.0_graphql2.6
|
|
91
103
|
- ruby-version: '3.0'
|
|
92
|
-
gemfile:
|
|
104
|
+
gemfile: rails8.1_graphql2.4
|
|
93
105
|
- ruby-version: '3.0'
|
|
94
|
-
gemfile:
|
|
106
|
+
gemfile: rails8.1_graphql2.5
|
|
95
107
|
- ruby-version: '3.0'
|
|
96
|
-
gemfile:
|
|
108
|
+
gemfile: rails8.1_graphql2.6
|
|
109
|
+
- ruby-version: '3.1'
|
|
110
|
+
gemfile: rails8.0_graphql2.2
|
|
111
|
+
- ruby-version: '3.1'
|
|
112
|
+
gemfile: rails8.0_graphql2.3
|
|
113
|
+
- ruby-version: '3.1'
|
|
114
|
+
gemfile: rails8.0_graphql2.4
|
|
97
115
|
- ruby-version: '3.1'
|
|
98
|
-
gemfile:
|
|
116
|
+
gemfile: rails8.0_graphql2.5
|
|
99
117
|
- ruby-version: '3.1'
|
|
100
|
-
gemfile:
|
|
118
|
+
gemfile: rails8.0_graphql2.6
|
|
101
119
|
- ruby-version: '3.1'
|
|
102
|
-
gemfile:
|
|
120
|
+
gemfile: rails8.1_graphql2.4
|
|
103
121
|
- ruby-version: '3.1'
|
|
104
|
-
gemfile:
|
|
122
|
+
gemfile: rails8.1_graphql2.5
|
|
105
123
|
- ruby-version: '3.1'
|
|
106
|
-
gemfile:
|
|
124
|
+
gemfile: rails8.1_graphql2.6
|
|
107
125
|
- report-coverage:
|
|
108
126
|
requires:
|
|
109
127
|
- test
|
data/Appraisals
CHANGED
|
@@ -1,37 +1,3 @@
|
|
|
1
|
-
appraise 'rails6.1-graphql1.10' do
|
|
2
|
-
gem 'sqlite3', '~> 1.5.4'
|
|
3
|
-
gem 'devise', '>= 4.7'
|
|
4
|
-
gem 'rails', git: 'https://github.com/rails/rails', branch: '6-1-stable'
|
|
5
|
-
gem 'graphql', '~> 1.10.0'
|
|
6
|
-
gem 'factory_bot', '<= 6.4.4'
|
|
7
|
-
end
|
|
8
|
-
|
|
9
|
-
appraise 'rails6.1-graphql1.11' do
|
|
10
|
-
gem 'sqlite3', '~> 1.5.4'
|
|
11
|
-
gem 'public_suffix', '< 5'
|
|
12
|
-
gem 'devise', '>= 4.7'
|
|
13
|
-
gem 'rails', git: 'https://github.com/rails/rails', branch: '6-1-stable'
|
|
14
|
-
gem 'graphql', '~> 1.11.0'
|
|
15
|
-
gem 'factory_bot', '<= 6.4.4'
|
|
16
|
-
end
|
|
17
|
-
|
|
18
|
-
appraise 'rails6.1-graphql1.12' do
|
|
19
|
-
gem 'sqlite3', '~> 1.5.4'
|
|
20
|
-
gem 'public_suffix', '< 5'
|
|
21
|
-
gem 'devise', '>= 4.7'
|
|
22
|
-
gem 'rails', git: 'https://github.com/rails/rails', branch: '6-1-stable'
|
|
23
|
-
gem 'graphql', '~> 1.12.0'
|
|
24
|
-
gem 'factory_bot', '<= 6.4.4'
|
|
25
|
-
end
|
|
26
|
-
|
|
27
|
-
appraise 'rails6.1-graphql1.13' do
|
|
28
|
-
gem 'sqlite3', '~> 1.5.4'
|
|
29
|
-
gem 'devise', '>= 4.7'
|
|
30
|
-
gem 'rails', git: 'https://github.com/rails/rails', branch: '6-1-stable'
|
|
31
|
-
gem 'graphql', '~> 1.13.0'
|
|
32
|
-
gem 'factory_bot', '<= 6.4.4'
|
|
33
|
-
end
|
|
34
|
-
|
|
35
1
|
appraise 'rails6.1-graphql2.0' do
|
|
36
2
|
gem 'public_suffix', '< 5'
|
|
37
3
|
gem 'sqlite3', '~> 1.5.4'
|
|
@@ -41,60 +7,6 @@ appraise 'rails6.1-graphql2.0' do
|
|
|
41
7
|
gem 'factory_bot', '<= 6.4.4'
|
|
42
8
|
end
|
|
43
9
|
|
|
44
|
-
appraise 'rails7.0-graphql1.11' do
|
|
45
|
-
gem 'sassc-rails'
|
|
46
|
-
gem 'sqlite3', '~> 1.5.4'
|
|
47
|
-
gem 'devise', '>= 4.7'
|
|
48
|
-
gem 'devise_token_auth', '>= 1.2.1'
|
|
49
|
-
gem 'rails', git: 'https://github.com/rails/rails', branch: '7-0-stable'
|
|
50
|
-
gem 'graphql', '~> 1.11.0'
|
|
51
|
-
end
|
|
52
|
-
|
|
53
|
-
appraise 'rails7.0-graphql1.12' do
|
|
54
|
-
gem 'sassc-rails'
|
|
55
|
-
gem 'sqlite3', '~> 1.5.4'
|
|
56
|
-
gem 'devise', '>= 4.7'
|
|
57
|
-
gem 'devise_token_auth', '>= 1.2.1'
|
|
58
|
-
gem 'rails', git: 'https://github.com/rails/rails', branch: '7-0-stable'
|
|
59
|
-
gem 'graphql', '~> 1.12.0'
|
|
60
|
-
end
|
|
61
|
-
|
|
62
|
-
appraise 'rails7.0-graphql1.13' do
|
|
63
|
-
gem 'sassc-rails'
|
|
64
|
-
gem 'sqlite3', '~> 1.5.4'
|
|
65
|
-
gem 'devise', '>= 4.7'
|
|
66
|
-
gem 'devise_token_auth', '>= 1.2.1'
|
|
67
|
-
gem 'rails', git: 'https://github.com/rails/rails', branch: '7-0-stable'
|
|
68
|
-
gem 'graphql', '~> 1.13.0'
|
|
69
|
-
end
|
|
70
|
-
|
|
71
|
-
appraise 'rails7.0-graphql2.0' do
|
|
72
|
-
gem 'sassc-rails'
|
|
73
|
-
gem 'sqlite3', '~> 1.5.4'
|
|
74
|
-
gem 'devise_token_auth', '>= 1.2.1'
|
|
75
|
-
gem 'devise', '>= 4.7'
|
|
76
|
-
gem 'rails', git: 'https://github.com/rails/rails', branch: '7-0-stable'
|
|
77
|
-
gem 'graphql', '>= 2.0', '< 2.1'
|
|
78
|
-
end
|
|
79
|
-
|
|
80
|
-
appraise 'rails7.0-graphql2.1' do
|
|
81
|
-
gem 'sassc-rails'
|
|
82
|
-
gem 'sqlite3', '~> 1.5.4'
|
|
83
|
-
gem 'devise_token_auth', '>= 1.2.1'
|
|
84
|
-
gem 'devise', '>= 4.7'
|
|
85
|
-
gem 'rails', git: 'https://github.com/rails/rails', branch: '7-0-stable'
|
|
86
|
-
gem 'graphql', '>= 2.1', '< 2.2'
|
|
87
|
-
end
|
|
88
|
-
|
|
89
|
-
appraise 'rails7.0-graphql2.2' do
|
|
90
|
-
gem 'sassc-rails'
|
|
91
|
-
gem 'sqlite3', '~> 1.5.4'
|
|
92
|
-
gem 'devise_token_auth', '>= 1.2.1'
|
|
93
|
-
gem 'devise', '>= 4.7'
|
|
94
|
-
gem 'rails', git: 'https://github.com/rails/rails', branch: '7-0-stable'
|
|
95
|
-
gem 'graphql', '>= 2.2', '< 2.3'
|
|
96
|
-
end
|
|
97
|
-
|
|
98
10
|
appraise 'rails7.0-graphql2.3' do
|
|
99
11
|
gem 'sassc-rails'
|
|
100
12
|
gem 'sqlite3', '~> 1.5.4'
|
|
@@ -232,3 +144,18 @@ appraise 'rails8.0-graphql2.6' do
|
|
|
232
144
|
gem 'rails', git: 'https://github.com/rails/rails', branch: '8-0-stable'
|
|
233
145
|
gem 'graphql', '>= 2.6', '< 2.7'
|
|
234
146
|
end
|
|
147
|
+
|
|
148
|
+
appraise 'rails8.1-graphql2.4' do
|
|
149
|
+
gem 'rails', git: 'https://github.com/rails/rails', branch: '8-1-stable'
|
|
150
|
+
gem 'graphql', '>= 2.4', '< 2.5'
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
appraise 'rails8.1-graphql2.5' do
|
|
154
|
+
gem 'rails', git: 'https://github.com/rails/rails', branch: '8-1-stable'
|
|
155
|
+
gem 'graphql', '>= 2.5', '< 2.6'
|
|
156
|
+
end
|
|
157
|
+
|
|
158
|
+
appraise 'rails8.1-graphql2.6' do
|
|
159
|
+
gem 'rails', git: 'https://github.com/rails/rails', branch: '8-1-stable'
|
|
160
|
+
gem 'graphql', '>= 2.6', '< 2.7'
|
|
161
|
+
end
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,14 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [v2.4.0](https://github.com/graphql-devise/graphql_devise/tree/v2.4.0) (2026-07-23)
|
|
4
|
+
|
|
5
|
+
[Full Changelog](https://github.com/graphql-devise/graphql_devise/compare/v2.3.0...v2.4.0)
|
|
6
|
+
|
|
7
|
+
**Implemented enhancements:**
|
|
8
|
+
|
|
9
|
+
- Add Rails 8.1 support [\#297](https://github.com/graphql-devise/graphql_devise/pull/297) ([mcelicalderon](https://github.com/mcelicalderon))
|
|
10
|
+
- Add opt-in destroy\_account mutation [\#296](https://github.com/graphql-devise/graphql_devise/pull/296) ([mcelicalderon](https://github.com/mcelicalderon))
|
|
11
|
+
|
|
3
12
|
## [v2.3.0](https://github.com/graphql-devise/graphql_devise/tree/v2.3.0) (2026-07-20)
|
|
4
13
|
|
|
5
14
|
[Full Changelog](https://github.com/graphql-devise/graphql_devise/compare/v2.2.0...v2.3.0)
|
data/README.md
CHANGED
|
@@ -294,6 +294,13 @@ Please note the gem provided schema is shared by all mounted resources, so setti
|
|
|
294
294
|
mount will disable introspection for all of them. **This option only works if you are using the mount method.**
|
|
295
295
|
If you are mounting the auth operations into your own schema, use the `public_introspection` option of the
|
|
296
296
|
`SchemaPlugin` instead.
|
|
297
|
+
1. `allow_destroy`: Defaults to `false`. The `destroy_account` operation is opt-in: it is **not** mounted
|
|
298
|
+
automatically, so upgrading the gem will never add a way to delete accounts to an existing schema. Set
|
|
299
|
+
`allow_destroy: true` to mount it (works alongside `skip`, and additively when no `skip`/`only` is given), or
|
|
300
|
+
list `:destroy_account` in the `only` option. While the operation is available but not mounted, a warning is
|
|
301
|
+
logged on boot explaining how to opt in. If you have decided you don't want the mutation and want to silence
|
|
302
|
+
the warning, add `:destroy_account` to the `skip` option (for example `skip: [:destroy_account]`, or combined
|
|
303
|
+
with the flag as `allow_destroy: true, skip: [:destroy_account]`).
|
|
297
304
|
|
|
298
305
|
Additional mutations and queries will be added to the schema regardless
|
|
299
306
|
of other options you might have specified like `skip` or `only`.
|
|
@@ -315,6 +322,7 @@ The following is a list of the symbols you can provide to the `operations`, `ski
|
|
|
315
322
|
:send_password_reset_with_token
|
|
316
323
|
:resend_confirmation_with_token
|
|
317
324
|
:confirm_registration_with_token
|
|
325
|
+
:destroy_account # opt-in, see the `allow_destroy` option above
|
|
318
326
|
```
|
|
319
327
|
|
|
320
328
|
### Configuring Model
|
|
@@ -479,6 +487,7 @@ register | The parameter `confirmUrl` is optional unless you are using the `conf
|
|
|
479
487
|
sendPasswordResetWithToken | Sends an email to the provided address with a link to reset the password of the resource. First step of the most recently implemented password reset flow. | userSendPasswordResetWithToken(email: String!, redirectUrl: String!): UserSendPasswordResetWithTokenPayload |
|
|
480
488
|
updatePasswordWithToken | Uses a `resetPasswordToken` to update the password of a resource. Second and last step of the most recently implemented password reset flow. | userSendPasswordResetWithToken(resetPasswordToken: String!, password: String!, passwordConfirmation: String!): UserUpdatePasswordWithTokenPayload |
|
|
481
489
|
resendConfirmationWithToken | The `UserResendConfirmationWithTokenPayload` will return a `message: String!` that can be used to notify a user what to do after the instructions were sent to them. Email will contain a link to the provided `confirmUrl` and a `confirmationToken` query param. | userResendConfirmationWithToken(email: String!, confirmUrl: String!): UserResendConfirmationWithTokenPayload |
|
|
490
|
+
destroyAccount | Opt-in (see the `allow_destroy` mount option). Requires authentication headers. Destroys the current resource and clears the session so no auth headers are returned. | userDestroyAccount: UserDestroyAccountPayload |
|
|
482
491
|
|
|
483
492
|
### Reset Password Flow
|
|
484
493
|
This gem supports two password recovery flows. The most recently implemented is preferred and
|
data/config/locales/en.yml
CHANGED
|
@@ -2,6 +2,7 @@ en:
|
|
|
2
2
|
graphql_devise:
|
|
3
3
|
redirect_url_not_allowed: "Redirect to '%{redirect_url}' not allowed."
|
|
4
4
|
registration_failed: "User couldn't be registered"
|
|
5
|
+
destroy_account_failed: "Account couldn't be destroyed"
|
|
5
6
|
resource_build_failed: "Resource couldn't be built, execution stopped."
|
|
6
7
|
not_authenticated: "User is not logged in."
|
|
7
8
|
user_not_found: "User was not found or was not logged in."
|
data/config/locales/pt-BR.yml
CHANGED
|
@@ -2,6 +2,7 @@ pt-BR:
|
|
|
2
2
|
graphql_devise:
|
|
3
3
|
redirect_url_not_allowed: "Redirecionamento para '%{redirect_url}' não permitido."
|
|
4
4
|
registration_failed: "Usuário não pôde ser registrado"
|
|
5
|
+
destroy_account_failed: "A conta não pôde ser excluída"
|
|
5
6
|
resource_build_failed: "O recurso não pôde ser construído, execução interrompida."
|
|
6
7
|
not_authenticated: "Usuário não logado."
|
|
7
8
|
user_not_found: "Usuário não encontrado ou não logado."
|
data/graphql_devise.gemspec
CHANGED
|
@@ -29,11 +29,10 @@ Gem::Specification.new do |spec|
|
|
|
29
29
|
|
|
30
30
|
spec.add_dependency 'devise_token_auth', '>= 0.1.43', '< 2.0'
|
|
31
31
|
spec.add_dependency 'graphql', '>= 1.8', '< 2.7'
|
|
32
|
-
spec.add_dependency 'rails', '>= 6.0', '< 8.
|
|
32
|
+
spec.add_dependency 'rails', '>= 6.0', '< 8.2'
|
|
33
33
|
spec.add_dependency 'zeitwerk'
|
|
34
34
|
|
|
35
35
|
spec.add_development_dependency 'appraisal'
|
|
36
|
-
spec.add_development_dependency 'coveralls_reborn'
|
|
37
36
|
spec.add_development_dependency 'factory_bot'
|
|
38
37
|
spec.add_development_dependency 'faker'
|
|
39
38
|
spec.add_development_dependency 'generator_spec'
|
|
@@ -46,5 +45,6 @@ Gem::Specification.new do |spec|
|
|
|
46
45
|
spec.add_development_dependency 'rubocop-performance', '< 1.6.0'
|
|
47
46
|
spec.add_development_dependency 'rubocop-rails', '< 2.6.0'
|
|
48
47
|
spec.add_development_dependency 'rubocop-rspec', '< 1.39.0'
|
|
48
|
+
spec.add_development_dependency 'simplecov'
|
|
49
49
|
spec.add_development_dependency 'sqlite3'
|
|
50
50
|
end
|
|
@@ -10,7 +10,8 @@ module GraphqlDevise
|
|
|
10
10
|
update_password_with_token: { klass: Mutations::UpdatePasswordWithToken, authenticatable: true },
|
|
11
11
|
send_password_reset_with_token: { klass: Mutations::SendPasswordResetWithToken, authenticatable: false },
|
|
12
12
|
resend_confirmation_with_token: { klass: Mutations::ResendConfirmationWithToken, authenticatable: false },
|
|
13
|
-
confirm_registration_with_token: { klass: Mutations::ConfirmRegistrationWithToken, authenticatable: true }
|
|
13
|
+
confirm_registration_with_token: { klass: Mutations::ConfirmRegistrationWithToken, authenticatable: true },
|
|
14
|
+
destroy_account: { klass: Mutations::DestroyAccount, authenticatable: true, allow_destroy: true }
|
|
14
15
|
}.freeze
|
|
15
16
|
end
|
|
16
17
|
end
|
|
@@ -17,7 +17,7 @@ module GraphqlDevise
|
|
|
17
17
|
@selected_operations.except(*@custom_keys).each_with_object({}) do |(action, operation_info), result|
|
|
18
18
|
mapped_action = "#{mapping_name}_#{action}"
|
|
19
19
|
operation = operation_info[:klass]
|
|
20
|
-
options = operation_info.except(:klass, :deprecation_reason)
|
|
20
|
+
options = operation_info.except(:klass, :deprecation_reason, :allow_destroy)
|
|
21
21
|
|
|
22
22
|
result[mapped_action.to_sym] = [
|
|
23
23
|
OperationPreparers::GqlNameSetter.new(mapped_action),
|
|
@@ -3,29 +3,56 @@
|
|
|
3
3
|
module GraphqlDevise
|
|
4
4
|
module MountMethod
|
|
5
5
|
class OperationSanitizer
|
|
6
|
-
def self.call(default:, only:, skipped:)
|
|
6
|
+
def self.call(default:, only:, skipped:, allow_destroy: false)
|
|
7
7
|
new(
|
|
8
|
-
default:
|
|
9
|
-
only:
|
|
10
|
-
skipped:
|
|
8
|
+
default: default,
|
|
9
|
+
only: only,
|
|
10
|
+
skipped: skipped,
|
|
11
|
+
allow_destroy: allow_destroy
|
|
11
12
|
).call
|
|
12
13
|
end
|
|
13
14
|
|
|
14
|
-
def initialize(default:, only:, skipped:)
|
|
15
|
-
@default
|
|
16
|
-
@only
|
|
17
|
-
@skipped
|
|
15
|
+
def initialize(default:, only:, skipped:, allow_destroy: false)
|
|
16
|
+
@default = default
|
|
17
|
+
@only = only
|
|
18
|
+
@skipped = skipped
|
|
19
|
+
@allow_destroy = allow_destroy
|
|
18
20
|
end
|
|
19
21
|
|
|
20
22
|
def call
|
|
21
|
-
operations
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
23
|
+
# When `only` is provided the list is explicit, so `allow_destroy` operations are included
|
|
24
|
+
# (and never warned about) whenever they are named in it.
|
|
25
|
+
return @default.slice(*@only) if @only.present?
|
|
26
|
+
|
|
27
|
+
selected = @skipped.present? ? @default.except(*@skipped) : @default
|
|
28
|
+
|
|
29
|
+
reject_allow_destroy(selected)
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
private
|
|
33
|
+
|
|
34
|
+
def reject_allow_destroy(operations)
|
|
35
|
+
return operations if @allow_destroy
|
|
36
|
+
|
|
37
|
+
operations.reject do |name, options|
|
|
38
|
+
next false unless requires_allow_destroy?(options)
|
|
39
|
+
|
|
40
|
+
warn_excluded(name)
|
|
41
|
+
true
|
|
27
42
|
end
|
|
28
43
|
end
|
|
44
|
+
|
|
45
|
+
def requires_allow_destroy?(options)
|
|
46
|
+
options.is_a?(Hash) && options[:allow_destroy]
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def warn_excluded(name)
|
|
50
|
+
::Rails.logger&.warn(
|
|
51
|
+
"[graphql_devise] The `#{name}` operation is not mounted because it is opt-in. " \
|
|
52
|
+
"Pass `allow_destroy: true` (or add it to the `only:` option) to include it. " \
|
|
53
|
+
"To keep it out and silence this warning, add `#{name}` to the `skip:` option."
|
|
54
|
+
)
|
|
55
|
+
end
|
|
29
56
|
end
|
|
30
57
|
end
|
|
31
58
|
end
|
|
@@ -10,7 +10,8 @@ module GraphqlDevise
|
|
|
10
10
|
additional_queries: OptionSanitizers::HashChecker.new(GraphQL::Schema::Resolver),
|
|
11
11
|
additional_mutations: OptionSanitizers::HashChecker.new(GraphQL::Schema::Mutation),
|
|
12
12
|
authenticatable_type: OptionSanitizers::ClassChecker.new(GraphQL::Schema::Member),
|
|
13
|
-
public_introspection: OptionSanitizers::BooleanChecker.new(true)
|
|
13
|
+
public_introspection: OptionSanitizers::BooleanChecker.new(true),
|
|
14
|
+
allow_destroy: OptionSanitizers::BooleanChecker.new(false)
|
|
14
15
|
}.freeze
|
|
15
16
|
end
|
|
16
17
|
end
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module GraphqlDevise
|
|
4
|
+
module Mutations
|
|
5
|
+
class DestroyAccount < Base
|
|
6
|
+
def resolve
|
|
7
|
+
raise_user_error(I18n.t('graphql_devise.user_not_found')) unless current_resource
|
|
8
|
+
|
|
9
|
+
if current_resource.destroy
|
|
10
|
+
# Clear the controller resource/token so devise_token_auth's `update_auth_header`
|
|
11
|
+
# after_action doesn't try to reload the now deleted record.
|
|
12
|
+
remove_resource
|
|
13
|
+
|
|
14
|
+
yield current_resource if block_given?
|
|
15
|
+
|
|
16
|
+
{ authenticatable: current_resource }
|
|
17
|
+
else
|
|
18
|
+
raise_user_error_list(
|
|
19
|
+
I18n.t('graphql_devise.destroy_account_failed'),
|
|
20
|
+
resource: current_resource
|
|
21
|
+
)
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
@@ -117,7 +117,10 @@ module GraphqlDevise
|
|
|
117
117
|
additional_operations: clean_options.additional_mutations,
|
|
118
118
|
preparer: MountMethod::OperationPreparers::MutationFieldSetter.new(authenticatable_type),
|
|
119
119
|
selected_operations: MountMethod::OperationSanitizer.call(
|
|
120
|
-
default:
|
|
120
|
+
default: DefaultOperations::MUTATIONS,
|
|
121
|
+
only: clean_options.only,
|
|
122
|
+
skipped: clean_options.skip,
|
|
123
|
+
allow_destroy: clean_options.allow_destroy
|
|
121
124
|
)
|
|
122
125
|
).call
|
|
123
126
|
end
|
data/spec/dummy/config/routes.rb
CHANGED
|
@@ -7,13 +7,15 @@ Rails.application.routes.draw do
|
|
|
7
7
|
base_controller: CookiesController,
|
|
8
8
|
operations: { login: Mutations::Login, register: Mutations::Register },
|
|
9
9
|
additional_mutations: { register_confirmed_user: Mutations::RegisterConfirmedUser },
|
|
10
|
-
additional_queries: { public_user: Resolvers::PublicUser }
|
|
10
|
+
additional_queries: { public_user: Resolvers::PublicUser },
|
|
11
|
+
allow_destroy: true
|
|
11
12
|
)
|
|
12
13
|
|
|
13
14
|
mount_graphql_devise_for(
|
|
14
15
|
Admin,
|
|
15
16
|
authenticatable_type: Types::CustomAdminType,
|
|
16
17
|
skip: [:register],
|
|
18
|
+
allow_destroy: true,
|
|
17
19
|
operations: {
|
|
18
20
|
update_password_with_token: Mutations::ResetAdminPasswordWithToken
|
|
19
21
|
},
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'rails_helper'
|
|
4
|
+
|
|
5
|
+
RSpec.describe 'Destroy Account Requests' do
|
|
6
|
+
include_context 'with graphql query request'
|
|
7
|
+
|
|
8
|
+
let(:user) { create(:user, :confirmed) }
|
|
9
|
+
let(:query) do
|
|
10
|
+
<<-GRAPHQL
|
|
11
|
+
mutation {
|
|
12
|
+
userDestroyAccount {
|
|
13
|
+
authenticatable { email }
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
GRAPHQL
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
before { post_request }
|
|
20
|
+
|
|
21
|
+
context 'when user is logged in' do
|
|
22
|
+
let(:headers) { user.create_new_auth_token }
|
|
23
|
+
|
|
24
|
+
it 'destroys the account and does not set auth headers' do
|
|
25
|
+
expect(response).not_to include_auth_headers
|
|
26
|
+
expect(User.exists?(user.id)).to be(false)
|
|
27
|
+
expect(json_response[:data][:userDestroyAccount]).to match(
|
|
28
|
+
authenticatable: { email: user.email }
|
|
29
|
+
)
|
|
30
|
+
expect(json_response[:errors]).to be_nil
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
context 'when user is not logged in' do
|
|
35
|
+
it 'returns an error and does not delete anything' do
|
|
36
|
+
expect(response).not_to include_auth_headers
|
|
37
|
+
expect(User.exists?(user.id)).to be(true)
|
|
38
|
+
expect(json_response[:data][:userDestroyAccount]).to be_nil
|
|
39
|
+
expect(json_response[:errors]).to contain_exactly(
|
|
40
|
+
hash_including(message: 'User was not found or was not logged in.', extensions: { code: 'USER_ERROR' })
|
|
41
|
+
)
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
context 'when using the admin model' do
|
|
46
|
+
let(:query) do
|
|
47
|
+
<<-GRAPHQL
|
|
48
|
+
mutation {
|
|
49
|
+
adminDestroyAccount {
|
|
50
|
+
authenticatable { email }
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
GRAPHQL
|
|
54
|
+
end
|
|
55
|
+
let(:admin) { create(:admin, :confirmed) }
|
|
56
|
+
let(:headers) { admin.create_new_auth_token }
|
|
57
|
+
|
|
58
|
+
it 'destroys the admin account' do
|
|
59
|
+
expect(response).not_to include_auth_headers
|
|
60
|
+
expect(Admin.exists?(admin.id)).to be(false)
|
|
61
|
+
expect(json_response[:data][:adminDestroyAccount]).to match(
|
|
62
|
+
authenticatable: { email: admin.email }
|
|
63
|
+
)
|
|
64
|
+
expect(json_response[:errors]).to be_nil
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
end
|
|
@@ -4,11 +4,14 @@ require 'rails_helper'
|
|
|
4
4
|
|
|
5
5
|
RSpec.describe GraphqlDevise::MountMethod::OperationSanitizer do
|
|
6
6
|
describe '.call' do
|
|
7
|
-
subject
|
|
7
|
+
subject(:sanitized) do
|
|
8
|
+
described_class.call(default: default, only: only, skipped: skipped, allow_destroy: allow_destroy)
|
|
9
|
+
end
|
|
8
10
|
|
|
9
11
|
let(:op_class1) { Class.new }
|
|
10
12
|
let(:op_class2) { Class.new }
|
|
11
13
|
let(:op_class3) { Class.new }
|
|
14
|
+
let(:allow_destroy) { false }
|
|
12
15
|
|
|
13
16
|
context 'when the operations passed are mutations' do
|
|
14
17
|
let(:skipped) { [] }
|
|
@@ -31,5 +34,59 @@ RSpec.describe GraphqlDevise::MountMethod::OperationSanitizer do
|
|
|
31
34
|
it { is_expected.to eq(operation1: { klass: op_class1 }) }
|
|
32
35
|
end
|
|
33
36
|
end
|
|
37
|
+
|
|
38
|
+
context 'when an operation requires the allow_destroy option' do
|
|
39
|
+
let(:skipped) { [] }
|
|
40
|
+
let(:only) { [] }
|
|
41
|
+
let(:default) do
|
|
42
|
+
{
|
|
43
|
+
operation1: { klass: op_class1 },
|
|
44
|
+
destroy_account: { klass: op_class2, allow_destroy: true }
|
|
45
|
+
}
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
context 'when no only/skip option and allow_destroy is off' do
|
|
49
|
+
it 'excludes the operation and logs a warning' do
|
|
50
|
+
expect(Rails.logger).to receive(:warn).with(/destroy_account/)
|
|
51
|
+
expect(sanitized).to eq(operation1: { klass: op_class1 })
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
context 'when using skip on other operations without allow_destroy' do
|
|
56
|
+
let(:skipped) { [:operation1] }
|
|
57
|
+
|
|
58
|
+
it 'still excludes the operation and logs a warning' do
|
|
59
|
+
expect(Rails.logger).to receive(:warn).with(/destroy_account/)
|
|
60
|
+
expect(sanitized).to eq({})
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
context 'when the operation itself is skipped' do
|
|
65
|
+
let(:skipped) { [:destroy_account] }
|
|
66
|
+
|
|
67
|
+
it 'excludes the operation without logging a warning' do
|
|
68
|
+
expect(Rails.logger).not_to receive(:warn)
|
|
69
|
+
expect(sanitized).to eq(operation1: { klass: op_class1 })
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
context 'when allow_destroy is on' do
|
|
74
|
+
let(:allow_destroy) { true }
|
|
75
|
+
|
|
76
|
+
it 'includes the operation without warning' do
|
|
77
|
+
expect(Rails.logger).not_to receive(:warn)
|
|
78
|
+
expect(sanitized).to eq(default)
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
context 'when named explicitly in only' do
|
|
83
|
+
let(:only) { [:destroy_account] }
|
|
84
|
+
|
|
85
|
+
it 'includes the operation without warning' do
|
|
86
|
+
expect(Rails.logger).not_to receive(:warn)
|
|
87
|
+
expect(sanitized).to eq(destroy_account: { klass: op_class2, allow_destroy: true })
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
end
|
|
34
91
|
end
|
|
35
92
|
end
|
data/spec/spec_helper.rb
CHANGED
|
@@ -2,9 +2,11 @@
|
|
|
2
2
|
|
|
3
3
|
if ENV['CI'] && !ENV['SKIP_COVERALLS']
|
|
4
4
|
require 'simplecov'
|
|
5
|
-
require 'coveralls'
|
|
6
5
|
|
|
7
|
-
SimpleCov.
|
|
6
|
+
# SimpleCov writes coverage/.resultset.json, which the Coveralls coverage-reporter
|
|
7
|
+
# (invoked by the coveralls CircleCI orb) picks up and uploads. We no longer upload
|
|
8
|
+
# from within Ruby so that every parallel job and the parallel_finished webhook share
|
|
9
|
+
# the same service number and aggregate into a single Coveralls build.
|
|
8
10
|
SimpleCov.start 'rails' do
|
|
9
11
|
add_filter ['spec']
|
|
10
12
|
end
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: graphql_devise
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 2.
|
|
4
|
+
version: 2.4.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Mario Celi
|
|
@@ -59,7 +59,7 @@ dependencies:
|
|
|
59
59
|
version: '6.0'
|
|
60
60
|
- - "<"
|
|
61
61
|
- !ruby/object:Gem::Version
|
|
62
|
-
version: '8.
|
|
62
|
+
version: '8.2'
|
|
63
63
|
type: :runtime
|
|
64
64
|
prerelease: false
|
|
65
65
|
version_requirements: !ruby/object:Gem::Requirement
|
|
@@ -69,7 +69,7 @@ dependencies:
|
|
|
69
69
|
version: '6.0'
|
|
70
70
|
- - "<"
|
|
71
71
|
- !ruby/object:Gem::Version
|
|
72
|
-
version: '8.
|
|
72
|
+
version: '8.2'
|
|
73
73
|
- !ruby/object:Gem::Dependency
|
|
74
74
|
name: zeitwerk
|
|
75
75
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -98,20 +98,6 @@ dependencies:
|
|
|
98
98
|
- - ">="
|
|
99
99
|
- !ruby/object:Gem::Version
|
|
100
100
|
version: '0'
|
|
101
|
-
- !ruby/object:Gem::Dependency
|
|
102
|
-
name: coveralls_reborn
|
|
103
|
-
requirement: !ruby/object:Gem::Requirement
|
|
104
|
-
requirements:
|
|
105
|
-
- - ">="
|
|
106
|
-
- !ruby/object:Gem::Version
|
|
107
|
-
version: '0'
|
|
108
|
-
type: :development
|
|
109
|
-
prerelease: false
|
|
110
|
-
version_requirements: !ruby/object:Gem::Requirement
|
|
111
|
-
requirements:
|
|
112
|
-
- - ">="
|
|
113
|
-
- !ruby/object:Gem::Version
|
|
114
|
-
version: '0'
|
|
115
101
|
- !ruby/object:Gem::Dependency
|
|
116
102
|
name: factory_bot
|
|
117
103
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -280,6 +266,20 @@ dependencies:
|
|
|
280
266
|
- - "<"
|
|
281
267
|
- !ruby/object:Gem::Version
|
|
282
268
|
version: 1.39.0
|
|
269
|
+
- !ruby/object:Gem::Dependency
|
|
270
|
+
name: simplecov
|
|
271
|
+
requirement: !ruby/object:Gem::Requirement
|
|
272
|
+
requirements:
|
|
273
|
+
- - ">="
|
|
274
|
+
- !ruby/object:Gem::Version
|
|
275
|
+
version: '0'
|
|
276
|
+
type: :development
|
|
277
|
+
prerelease: false
|
|
278
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
279
|
+
requirements:
|
|
280
|
+
- - ">="
|
|
281
|
+
- !ruby/object:Gem::Version
|
|
282
|
+
version: '0'
|
|
283
283
|
- !ruby/object:Gem::Dependency
|
|
284
284
|
name: sqlite3
|
|
285
285
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -369,6 +369,7 @@ files:
|
|
|
369
369
|
- lib/graphql_devise/mount_method/supported_options.rb
|
|
370
370
|
- lib/graphql_devise/mutations/base.rb
|
|
371
371
|
- lib/graphql_devise/mutations/confirm_registration_with_token.rb
|
|
372
|
+
- lib/graphql_devise/mutations/destroy_account.rb
|
|
372
373
|
- lib/graphql_devise/mutations/login.rb
|
|
373
374
|
- lib/graphql_devise/mutations/logout.rb
|
|
374
375
|
- lib/graphql_devise/mutations/register.rb
|
|
@@ -475,6 +476,7 @@ files:
|
|
|
475
476
|
- spec/requests/mutations/additional_mutations_spec.rb
|
|
476
477
|
- spec/requests/mutations/additional_queries_spec.rb
|
|
477
478
|
- spec/requests/mutations/confirm_registration_with_token_spec.rb
|
|
479
|
+
- spec/requests/mutations/destroy_account_spec.rb
|
|
478
480
|
- spec/requests/mutations/login_spec.rb
|
|
479
481
|
- spec/requests/mutations/logout_spec.rb
|
|
480
482
|
- spec/requests/mutations/register_spec.rb
|
|
@@ -622,6 +624,7 @@ test_files:
|
|
|
622
624
|
- spec/requests/mutations/additional_mutations_spec.rb
|
|
623
625
|
- spec/requests/mutations/additional_queries_spec.rb
|
|
624
626
|
- spec/requests/mutations/confirm_registration_with_token_spec.rb
|
|
627
|
+
- spec/requests/mutations/destroy_account_spec.rb
|
|
625
628
|
- spec/requests/mutations/login_spec.rb
|
|
626
629
|
- spec/requests/mutations/logout_spec.rb
|
|
627
630
|
- spec/requests/mutations/register_spec.rb
|