morpho 1.2.0 → 1.2.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (54) hide show
  1. checksums.yaml +4 -4
  2. data/app/api/morpho/entities/user.rb +0 -1
  3. data/app/api/morpho/resources/activations.rb +9 -4
  4. data/app/api/morpho/resources/externals.rb +8 -2
  5. data/app/api/morpho/resources/passwords.rb +9 -4
  6. data/app/api/morpho/resources/tokens.rb +19 -5
  7. data/app/api/morpho/resources/unlocks.rb +10 -5
  8. data/app/api/morpho/resources/users.rb +8 -3
  9. data/app/concepts/morpho/contracts/user/deliver_email.rb +13 -0
  10. data/app/concepts/morpho/contracts/user/external_sign_in.rb +17 -0
  11. data/app/concepts/morpho/contracts/user/refresh_token.rb +13 -0
  12. data/app/concepts/morpho/contracts/user/resend_activation_email.rb +8 -0
  13. data/app/concepts/morpho/contracts/user/resend_unlock_email.rb +8 -0
  14. data/app/concepts/morpho/contracts/user/send_reset_password_email.rb +8 -0
  15. data/app/concepts/morpho/contracts/user/sign_in.rb +15 -0
  16. data/app/concepts/morpho/contracts/user/sign_up.rb +25 -0
  17. data/app/concepts/morpho/operations/base/create.rb +14 -0
  18. data/app/concepts/morpho/operations/base/delete.rb +16 -0
  19. data/app/concepts/morpho/operations/base/fetch.rb +106 -0
  20. data/app/concepts/morpho/operations/base/find.rb +55 -0
  21. data/app/concepts/morpho/operations/base/form.rb +84 -0
  22. data/app/concepts/morpho/operations/base/update.rb +19 -0
  23. data/app/concepts/morpho/operations/user/deliver_email.rb +38 -0
  24. data/app/concepts/morpho/operations/user/external_sign_in.rb +38 -0
  25. data/app/concepts/morpho/operations/user/generate_token.rb +33 -0
  26. data/app/concepts/morpho/operations/user/refresh_token.rb +41 -0
  27. data/app/concepts/morpho/operations/user/resend_activation_email.rb +31 -0
  28. data/app/concepts/morpho/operations/user/resend_unlock_email.rb +31 -0
  29. data/app/concepts/morpho/operations/user/send_reset_password_email.rb +30 -0
  30. data/app/concepts/morpho/operations/user/sign_in.rb +49 -0
  31. data/app/concepts/morpho/operations/user/sign_up.rb +8 -0
  32. data/app/models/morpho/user.rb +6 -2
  33. data/config/locales/morpho.en.yml +2 -0
  34. data/config/locales/morpho.es.yml +2 -0
  35. data/lib/generators/morpho/install/templates/app/api/morpho/api.rb +12 -2
  36. data/lib/generators/morpho/install/templates/config/initializers/morpho.rb +2 -1
  37. data/lib/morpho/configuration.rb +2 -0
  38. data/lib/morpho/engine.rb +1 -6
  39. data/lib/morpho/version.rb +1 -1
  40. metadata +26 -17
  41. data/app/concepts/morpho/user/contract/activate.rb +0 -8
  42. data/app/concepts/morpho/user/contract/external_sign_in.rb +0 -12
  43. data/app/concepts/morpho/user/contract/refresh_token.rb +0 -8
  44. data/app/concepts/morpho/user/contract/reset_password.rb +0 -8
  45. data/app/concepts/morpho/user/contract/sign_in.rb +0 -10
  46. data/app/concepts/morpho/user/contract/sign_up.rb +0 -22
  47. data/app/concepts/morpho/user/contract/unlock.rb +0 -8
  48. data/app/concepts/morpho/user/operation/activate.rb +0 -42
  49. data/app/concepts/morpho/user/operation/external_sign_in.rb +0 -70
  50. data/app/concepts/morpho/user/operation/refresh_token.rb +0 -37
  51. data/app/concepts/morpho/user/operation/reset_password.rb +0 -40
  52. data/app/concepts/morpho/user/operation/sign_in.rb +0 -73
  53. data/app/concepts/morpho/user/operation/sign_up.rb +0 -32
  54. data/app/concepts/morpho/user/operation/unlock.rb +0 -42
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 82024952461a4e2bd7809b6490d89a95ea14ffbdb09bf0eb48f38293195a77d3
4
- data.tar.gz: 3f7ddb7bdb31f77544040cc6b6b7576fd6ec2536f88cc66bcbe9e2c4b8ca0065
3
+ metadata.gz: 031b5db81031a0b5580c14f0d5d2090d52232d4a2bef373f3b96252b02649701
4
+ data.tar.gz: 98beadb9189542547bf913eec75540898ebffafaeb4a14e8cf8a9cf34259fec4
5
5
  SHA512:
6
- metadata.gz: 9accfa9064d5a4d9cfcc2110c107007a8fe511c6847bdb368206d2f57caf5e8549c08e1fbed88b47ed61661ee3eb2deae199196a14955db7f0f829382e469202
7
- data.tar.gz: 60ed2c1e0f7fed8363d114ff1d98801455b02ad5f9c627e2b6f098b0443dfdbd6352c9001f565257924a7cd91992a6637bc542b7d325f4bede7533daf4ad7254
6
+ metadata.gz: a7635d8bc511ae7ecc7924604de502506e442a949cfa787ce317b62c1d040d9ffb6ccc5aac5a5854abaef0de0b028ca5e343e3eb5ffadd4f7aa65e8d0d0847ca
7
+ data.tar.gz: fbf30803bf591c3029b79e53d57b0102409874e43d0b3075e516c1c29db2c71619c6c722800f50c42816ccd71f2868cfca75453f56ba6cb3955db124f6262f4d
@@ -1,7 +1,6 @@
1
1
  module Morpho
2
2
  module Entities
3
3
  class User < ::Morpho::Entities::Base
4
- root 'data', 'data'
5
4
  expose :email, documentation: { type: 'string', desc: 'User email address' }
6
5
  end
7
6
  end
@@ -4,7 +4,7 @@ module Morpho
4
4
  helpers Morpho::Helpers::HTTPResponses
5
5
 
6
6
  namespace :activations do
7
- desc 'Request user activation token' do
7
+ desc 'Resend activation instructions email' do
8
8
  detail ''
9
9
  success Morpho::Grape::DataWrapper.new(Morpho::Entities::User)
10
10
  failure [
@@ -16,11 +16,16 @@ module Morpho
16
16
  params do
17
17
  requires :data, type: Morpho::Entities::UserEmail
18
18
  end
19
- post do
20
- result = Morpho::User::Operation::Activate.call(params)
19
+ post :resend_activation_email do
20
+ result = Morpho::Operations::User::ResendActivationEmail.call(
21
+ 'params' => params,
22
+ 'model.class' => Morpho::User,
23
+ 'contract.class' => Morpho::Contracts::User::ResendActivationEmail,
24
+ 'presenter.class' => Morpho::Entities::User
25
+ )
21
26
 
22
27
  if result.success?
23
- present result['model'], with: Morpho::Entities::User
28
+ present result['response']
24
29
  end
25
30
  end
26
31
  end
@@ -15,10 +15,16 @@ module Morpho
15
15
  requires :data, type: Morpho::Entities::External
16
16
  end
17
17
  post do
18
- result = Morpho::User::Operation::ExternalSignIn.call(params, ip: request.ip)
18
+ result = Morpho::Operations::User::ExternalSignIn.call(
19
+ 'params' => params,
20
+ 'model.class' => Morpho::User,
21
+ 'contract.class' => Morpho::Contracts::User::ExternalSignIn,
22
+ 'presenter.class' => Morpho::Entities::AuthenticationToken,
23
+ 'ip_address' => request.ip
24
+ )
19
25
 
20
26
  if result.success?
21
- present result['token'], with: Morpho::Entities::AuthenticationToken
27
+ present result['response']
22
28
  end
23
29
  end
24
30
  end
@@ -4,7 +4,7 @@ module Morpho
4
4
  helpers Morpho::Helpers::HTTPResponses
5
5
 
6
6
  namespace :passwords do
7
- desc 'Request user reset password token' do
7
+ desc 'Send reset password instructions email' do
8
8
  detail ''
9
9
  success Morpho::Grape::DataWrapper.new(Morpho::Entities::User)
10
10
  failure [
@@ -16,11 +16,16 @@ module Morpho
16
16
  params do
17
17
  requires :data, type: Morpho::Entities::UserEmail
18
18
  end
19
- post do
20
- result = Morpho::User::Operation::ResetPassword.call(params)
19
+ post :send_reset_password_email do
20
+ result = Morpho::Operations::User::SendResetPasswordEmail.call(
21
+ 'params' => params,
22
+ 'model.class' => Morpho::User,
23
+ 'contract.class' => Morpho::Contracts::User::SendResetPasswordEmail,
24
+ 'presenter.class' => Morpho::Entities::User
25
+ )
21
26
 
22
27
  if result.success?
23
- present result['model'], with: Morpho::Entities::User
28
+ present result['response']
24
29
  end
25
30
  end
26
31
  end
@@ -19,10 +19,16 @@ module Morpho
19
19
  requires :data, type: Morpho::Entities::Credentials
20
20
  end
21
21
  post do
22
- result = Morpho::User::Operation::SignIn.call(params, ip: request.ip)
22
+ result = Morpho::Operations::User::SignIn.call(
23
+ 'params' => params,
24
+ 'model.class' => Morpho::User,
25
+ 'contract.class' => Morpho::Contracts::User::SignIn,
26
+ 'presenter.class' => Morpho::Entities::AuthenticationToken,
27
+ 'ip_address' => request.ip
28
+ )
23
29
 
24
30
  if result.success?
25
- present result['token'], with: Morpho::Entities::AuthenticationToken
31
+ present result['response']
26
32
  end
27
33
  end
28
34
 
@@ -30,18 +36,26 @@ module Morpho
30
36
  detail ''
31
37
  success Morpho::Grape::DataWrapper.new(Morpho::Entities::AuthenticationToken)
32
38
  failure [
39
+ [ 403, I18n.t('morpho.api.messages.general.403'), Morpho::Entities::Error ],
33
40
  [ 404, I18n.t('morpho.api.messages.general.404'), Morpho::Entities::Error ],
34
- [ 422, I18n.t('morpho.api.messages.general.422'), Morpho::Entities::Error ]
41
+ [ 422, I18n.t('morpho.api.messages.general.422'), Morpho::Entities::Error ],
42
+ [ 423, I18n.t('morpho.api.messages.general.423'), Morpho::Entities::Error ]
35
43
  ]
36
44
  end
37
45
  params do
38
46
  requires :data, type: Morpho::Entities::RefreshToken
39
47
  end
40
48
  post :refresh do
41
- result = Morpho::User::Operation::RefreshToken.call(params)
49
+ result = Morpho::Operations::User::RefreshToken.call(
50
+ 'params' => params,
51
+ 'model.class' => Morpho::User,
52
+ 'contract.class' => Morpho::Contracts::User::RefreshToken,
53
+ 'presenter.class' => Morpho::Entities::AuthenticationToken,
54
+ 'ip_address' => request.ip
55
+ )
42
56
 
43
57
  if result.success?
44
- present result['token'], with: Morpho::Entities::AuthenticationToken
58
+ present result['response']
45
59
  end
46
60
  end
47
61
  end
@@ -4,9 +4,9 @@ module Morpho
4
4
  helpers Morpho::Helpers::HTTPResponses
5
5
 
6
6
  namespace :unlocks do
7
- desc 'Request user unlock token' do
7
+ desc 'Resend unlock instructions email' do
8
8
  detail ''
9
- success Morpho::Grape::DataWrapper.new(Morpho::Entities::UserEmail)
9
+ success Morpho::Grape::DataWrapper.new(Morpho::Entities::User)
10
10
  failure [
11
11
  [ 404, I18n.t('morpho.api.messages.general.404'), Morpho::Entities::Error ],
12
12
  [ 405, I18n.t('morpho.api.messages.general.405'), Morpho::Entities::Error ],
@@ -16,11 +16,16 @@ module Morpho
16
16
  params do
17
17
  requires :data, type: Morpho::Entities::UserEmail
18
18
  end
19
- post do
20
- result = Morpho::User::Operation::Unlock.call(params)
19
+ post :resend_unlock_email do
20
+ result = Morpho::Operations::User::ResendUnlockEmail.call(
21
+ 'params' => params,
22
+ 'model.class' => Morpho::User,
23
+ 'contract.class' => Morpho::Contracts::User::ResendActivationEmail,
24
+ 'presenter.class' => Morpho::Entities::User
25
+ )
21
26
 
22
27
  if result.success?
23
- present result['model'], with: Morpho::Entities::User
28
+ present result['response']
24
29
  end
25
30
  end
26
31
  end
@@ -4,7 +4,7 @@ module Morpho
4
4
  helpers Morpho::Helpers::HTTPResponses
5
5
 
6
6
  namespace :users do
7
- desc 'User registration' do
7
+ desc 'User sign up' do
8
8
  detail ''
9
9
  success Morpho::Grape::DataWrapper.new(Morpho::Entities::User)
10
10
  failure [
@@ -15,10 +15,15 @@ module Morpho
15
15
  requires :data, type: Morpho::Entities::UserSignUp
16
16
  end
17
17
  post do
18
- result = Morpho::User::Operation::SignUp.call(params)
18
+ result = Morpho::Operations::User::SignUp.call(
19
+ 'params' => params,
20
+ 'model.class' => Morpho::User,
21
+ 'contract.class' => Morpho::Contracts::User::SignUp,
22
+ 'presenter.class' => Morpho::Entities::User
23
+ )
19
24
 
20
25
  if result.success?
21
- present result['model'], with: Morpho::Entities::User
26
+ present result['response']
22
27
  end
23
28
  end
24
29
  end
@@ -0,0 +1,13 @@
1
+ module Morpho
2
+ module Contracts
3
+ module User
4
+ class DeliverEmail < Reform::Form
5
+ include Reform::Form::ActiveRecord
6
+
7
+ property :email
8
+
9
+ validates :email, presence: true, email_format: true
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,17 @@
1
+ module Morpho
2
+ module Contracts
3
+ module User
4
+ class ExternalSignIn < Reform::Form
5
+ include Reform::Form::ActiveRecord
6
+
7
+ property :email
8
+ property :provider
9
+ property :uid
10
+
11
+ validates :email, presence: true, email_format: true
12
+ validates :provider, presence: true
13
+ validates :uid, presence: true
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,13 @@
1
+ module Morpho
2
+ module Contracts
3
+ module User
4
+ class RefreshToken < Reform::Form
5
+ include Reform::Form::ActiveRecord
6
+
7
+ property :refresh_token
8
+
9
+ validates :refresh_token, presence: true
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,8 @@
1
+ module Morpho
2
+ module Contracts
3
+ module User
4
+ class ResendActivationEmail < Morpho::Contracts::User::DeliverEmail
5
+ end
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,8 @@
1
+ module Morpho
2
+ module Contracts
3
+ module User
4
+ class ResendUnlockEmail < Morpho::Contracts::User::DeliverEmail
5
+ end
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,8 @@
1
+ module Morpho
2
+ module Contracts
3
+ module User
4
+ class SendResetPasswordEmail < Morpho::Contracts::User::DeliverEmail
5
+ end
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,15 @@
1
+ module Morpho
2
+ module Contracts
3
+ module User
4
+ class SignIn < Reform::Form
5
+ include Reform::Form::ActiveRecord
6
+
7
+ property :email
8
+ property :password
9
+
10
+ validates :email, presence: true, email_format: true
11
+ validates :password, presence: true
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,25 @@
1
+ require 'reform/form/validation/unique_validator'
2
+
3
+ module Morpho
4
+ module Contracts
5
+ module User
6
+ class SignUp < Reform::Form
7
+ include Reform::Form::ActiveRecord
8
+
9
+ property :email
10
+ property :password
11
+ property :password_confirmation, virtual: true
12
+
13
+ validates :email, presence: true, unique: true, email_format: true
14
+ validates :password,
15
+ presence: true,
16
+ confirmation: true,
17
+ length: { minimum: Morpho.config.auth.password_minimum_length },
18
+ :'morpho/validators/contain_number' => true,
19
+ :'morpho/validators/contain_uppercase' => true,
20
+ :'morpho/validators/contain_symbol' => true
21
+ validates :password_confirmation, presence: true
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Morpho
4
+ module Operations
5
+ module Base
6
+ # Base create operation
7
+ class Create < Morpho::Operations::Base::Form
8
+ def build_model!(options, **)
9
+ options['model'] = options['model.class'].new
10
+ end
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Morpho
4
+ module Operations
5
+ module Base
6
+ # Base delete operation
7
+ class Delete < Morpho::Operations::Base::Find
8
+ pass :destroy!, after: :present!
9
+
10
+ def destroy!(options, model:, **)
11
+ model.destroy
12
+ end
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,106 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Morpho
4
+ module Operations
5
+ module Base
6
+ # Base fetch operation
7
+ class Fetch < Trailblazer::Operation
8
+ pass :init!
9
+ pass :params!
10
+ pass :meta!
11
+ pass :model_class!
12
+ pass :build_build_models!
13
+ pass :filter!
14
+ pass :page!
15
+ pass :paginate!
16
+ pass :search!
17
+ pass :update_meta!
18
+ pass :present!
19
+
20
+ def init!(options, **)
21
+ options['default.page.size'] ||= 25
22
+ end
23
+
24
+ def params!(options, **)
25
+ options['params'] ||= {}
26
+ end
27
+
28
+ def meta!(options, params:, **)
29
+ options['meta'] = params.fetch('meta', {})
30
+ end
31
+
32
+ def update_meta!(options, **)
33
+ if options['models'].try(:current_page)
34
+ options['meta'].merge!(
35
+ 'current_page' => options['models'].current_page,
36
+ 'from' => options['models'].prev_page,
37
+ 'last_page' => options['models'].total_pages,
38
+ 'per_page' => options['models'].limit_value,
39
+ 'to' => options['models'].next_page,
40
+ 'total' => options['models'].total_count
41
+ )
42
+ end
43
+ options
44
+ end
45
+
46
+ def model_class!(options, **)
47
+ model_class = options['model.class']
48
+ unless model_class.is_a?(Class) && model_class.ancestors
49
+ .include?(
50
+ ::ActiveRecord::Base
51
+ )
52
+ raise ArgumentError,
53
+ 'Supply a valid model.class option'
54
+ end
55
+ end
56
+
57
+ def build_models!(options, **)
58
+ options['models'] = options['model.class'].all
59
+ end
60
+
61
+ def filter!(options, params:, **)
62
+ options['filter'] = params.fetch('filter', {})
63
+ end
64
+
65
+ def page!(options, params:, **)
66
+ options['page'] = params.fetch(
67
+ 'page',
68
+ 'number' => 1,
69
+ 'size' => options['default.page.size']
70
+ )
71
+ end
72
+
73
+ def paginate!(options, page:, **)
74
+ page_size = page.fetch('size', 25)
75
+ page_number = page.fetch('number', 1)
76
+ if page &&
77
+ page_size.to_i.positive?
78
+ options['models'] = options['models']
79
+ .page(page_number)
80
+ .per(page_size)
81
+ end
82
+ options
83
+ end
84
+
85
+ def search!(options, **)
86
+ options['models'] = options['models']
87
+ .ransack(options['filter'])
88
+ .result(distinct: options['ransack.distinct'])
89
+ end
90
+
91
+ def present!(options, meta:, models:, **)
92
+ data =
93
+ if options['presenter.class']
94
+ options['presenter.class'].represent(models)['data']
95
+ else
96
+ models
97
+ end
98
+ options['response'] = {
99
+ data: data,
100
+ meta: meta
101
+ }
102
+ end
103
+ end
104
+ end
105
+ end
106
+ end