morpho 1.1.2 → 1.2.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/app/api/morpho/entities/error.rb +21 -2
- data/app/api/morpho/exceptions/standard_error.rb +19 -0
- data/app/api/morpho/formatters/standard_error.rb +26 -0
- data/app/api/morpho/helpers/http_responses.rb +32 -56
- data/app/api/morpho/resources/activations.rb +4 -14
- data/app/api/morpho/resources/externals.rb +4 -7
- data/app/api/morpho/resources/hello.rb +3 -1
- data/app/api/morpho/resources/passwords.rb +4 -16
- data/app/api/morpho/resources/tokens.rb +9 -31
- data/app/api/morpho/resources/unlocks.rb +4 -14
- data/app/api/morpho/resources/users.rb +2 -10
- data/app/concepts/morpho/user/operation/activate.rb +27 -25
- data/app/concepts/morpho/user/operation/external_sign_in.rb +26 -26
- data/app/concepts/morpho/user/operation/refresh_token.rb +21 -19
- data/app/concepts/morpho/user/operation/reset_password.rb +25 -34
- data/app/concepts/morpho/user/operation/sign_in.rb +48 -46
- data/app/concepts/morpho/user/operation/sign_up.rb +17 -21
- data/app/concepts/morpho/user/operation/unlock.rb +27 -25
- data/app/models/morpho/user.rb +4 -0
- data/config/locales/morpho.en.yml +18 -17
- data/config/locales/morpho.es.yml +18 -17
- data/lib/morpho/version.rb +1 -1
- metadata +4 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 82024952461a4e2bd7809b6490d89a95ea14ffbdb09bf0eb48f38293195a77d3
|
4
|
+
data.tar.gz: 3f7ddb7bdb31f77544040cc6b6b7576fd6ec2536f88cc66bcbe9e2c4b8ca0065
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9accfa9064d5a4d9cfcc2110c107007a8fe511c6847bdb368206d2f57caf5e8549c08e1fbed88b47ed61661ee3eb2deae199196a14955db7f0f829382e469202
|
7
|
+
data.tar.gz: 60ed2c1e0f7fed8363d114ff1d98801455b02ad5f9c627e2b6f098b0443dfdbd6352c9001f565257924a7cd91992a6637bc542b7d325f4bede7533daf4ad7254
|
@@ -1,8 +1,27 @@
|
|
1
1
|
module Morpho
|
2
2
|
module Entities
|
3
3
|
class Error < ::Grape::Entity
|
4
|
-
expose :
|
5
|
-
|
4
|
+
expose :errors, safe: true, documentation: { type: 'array', desc: 'Error message details' }
|
5
|
+
|
6
|
+
def errors
|
7
|
+
messages = []
|
8
|
+
|
9
|
+
keys = object.errors.keys
|
10
|
+
|
11
|
+
keys.each do |key|
|
12
|
+
messages << {
|
13
|
+
field_name: key,
|
14
|
+
messages: object.errors.messages[key]
|
15
|
+
}
|
16
|
+
end
|
17
|
+
|
18
|
+
messages << {
|
19
|
+
field_name: 'base',
|
20
|
+
messages: [ object.message ]
|
21
|
+
} if messages.empty?
|
22
|
+
|
23
|
+
messages
|
24
|
+
end
|
6
25
|
end
|
7
26
|
end
|
8
27
|
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module Morpho
|
2
|
+
module Exceptions
|
3
|
+
class StandardError < ::StandardError
|
4
|
+
attr_reader :status
|
5
|
+
attr_reader :message
|
6
|
+
attr_reader :errors
|
7
|
+
|
8
|
+
def initialize(*args)
|
9
|
+
options = args.extract_options!
|
10
|
+
|
11
|
+
@status = options[:status] || 422
|
12
|
+
@message = options[:message] || I18n.t("morpho.api.messages.general.#{@status}")
|
13
|
+
@errors = options[:errors] || {}
|
14
|
+
|
15
|
+
super(@message)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
module Morpho
|
2
|
+
module Formatters
|
3
|
+
module StandardError
|
4
|
+
class << self
|
5
|
+
def call(message, backtrace, options, env, original_exception)
|
6
|
+
if message.is_a?(String)
|
7
|
+
result = {
|
8
|
+
message: message,
|
9
|
+
errors: [
|
10
|
+
{ field_name: 'base', messages: [ message ] }
|
11
|
+
]
|
12
|
+
}
|
13
|
+
elsif message.is_a?(Hash)
|
14
|
+
result = message
|
15
|
+
elsif message.is_a?(Object)
|
16
|
+
return message.to_json if message.respond_to?(:to_json)
|
17
|
+
|
18
|
+
result = message
|
19
|
+
end
|
20
|
+
|
21
|
+
::Grape::Json.dump(result)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -3,76 +3,52 @@ module Morpho
|
|
3
3
|
module HTTPResponses
|
4
4
|
protected
|
5
5
|
|
6
|
-
def render_bad_request
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
with: Morpho::Entities::Error
|
11
|
-
}, 400)
|
6
|
+
def render_bad_request
|
7
|
+
raise Morpho::Exceptions::StandardError.new(
|
8
|
+
status: 400
|
9
|
+
)
|
12
10
|
end
|
13
11
|
|
14
|
-
def render_unauthorized
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
with: Morpho::Entities::Error
|
19
|
-
}, 401)
|
12
|
+
def render_unauthorized
|
13
|
+
raise Morpho::Exceptions::StandardError.new(
|
14
|
+
status: 401
|
15
|
+
)
|
20
16
|
end
|
21
17
|
|
22
|
-
def
|
23
|
-
|
18
|
+
def render_payment_required
|
19
|
+
raise Morpho::Exceptions::StandardError.new(
|
20
|
+
status: 402
|
21
|
+
)
|
24
22
|
end
|
25
23
|
|
26
|
-
def
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
with: Morpho::Entities::Error
|
31
|
-
}, 402)
|
24
|
+
def render_forbidden
|
25
|
+
raise Morpho::Exceptions::StandardError.new(
|
26
|
+
status: 403
|
27
|
+
)
|
32
28
|
end
|
33
29
|
|
34
|
-
def
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
with: Morpho::Entities::Error
|
39
|
-
}, 403)
|
30
|
+
def render_not_found
|
31
|
+
raise Morpho::Exceptions::StandardError.new(
|
32
|
+
status: 404
|
33
|
+
)
|
40
34
|
end
|
41
35
|
|
42
|
-
def
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
with: Morpho::Entities::Error
|
47
|
-
}, 404)
|
36
|
+
def render_method_not_allowed
|
37
|
+
raise Morpho::Exceptions::StandardError.new(
|
38
|
+
status: 405
|
39
|
+
)
|
48
40
|
end
|
49
41
|
|
50
|
-
def
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
with: Morpho::Entities::Error
|
55
|
-
}, 405)
|
42
|
+
def render_unprocessable_entity
|
43
|
+
raise Morpho::Exceptions::StandardError.new(
|
44
|
+
status: 422
|
45
|
+
)
|
56
46
|
end
|
57
47
|
|
58
|
-
def
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
with: Morpho::Entities::Error
|
63
|
-
}, 422)
|
64
|
-
end
|
65
|
-
|
66
|
-
def render_locked(errors = {})
|
67
|
-
error!({
|
68
|
-
message: I18n.t('morpho.api.messages.locked'),
|
69
|
-
errors: errors,
|
70
|
-
with: Morpho::Entities::Error
|
71
|
-
}, 423)
|
72
|
-
end
|
73
|
-
|
74
|
-
def render_unprocessable_entity_detailed(errors = {})
|
75
|
-
render_unprocessable_entity(errors)
|
48
|
+
def render_locked
|
49
|
+
raise Morpho::Exceptions::StandardError.new(
|
50
|
+
status: 423
|
51
|
+
)
|
76
52
|
end
|
77
53
|
|
78
54
|
def render_no_content
|
@@ -5,11 +5,12 @@ module Morpho
|
|
5
5
|
|
6
6
|
namespace :activations do
|
7
7
|
desc 'Request user activation token' do
|
8
|
+
detail ''
|
8
9
|
success Morpho::Grape::DataWrapper.new(Morpho::Entities::User)
|
9
10
|
failure [
|
10
|
-
[ 404, I18n.t('morpho.api.messages.
|
11
|
-
[ 405, I18n.t('morpho.api.messages.
|
12
|
-
[ 422, I18n.t('morpho.api.messages.
|
11
|
+
[ 404, I18n.t('morpho.api.messages.general.404'), Morpho::Entities::Error ],
|
12
|
+
[ 405, I18n.t('morpho.api.messages.general.405'), Morpho::Entities::Error ],
|
13
|
+
[ 422, I18n.t('morpho.api.messages.general.422'), Morpho::Entities::Error ]
|
13
14
|
]
|
14
15
|
end
|
15
16
|
params do
|
@@ -20,17 +21,6 @@ module Morpho
|
|
20
21
|
|
21
22
|
if result.success?
|
22
23
|
present result['model'], with: Morpho::Entities::User
|
23
|
-
else
|
24
|
-
case result['error']
|
25
|
-
when :unprocessable_entity
|
26
|
-
render_unprocessable_entity(result['contract'].errors)
|
27
|
-
when :not_found
|
28
|
-
render_not_found({ base: I18n.t('morpho.api.messages.activate.not_found') })
|
29
|
-
when :method_not_allowed
|
30
|
-
render_method_not_allowed({ base: I18n.t('morpho.api.messages.activate.method_not_allowed') })
|
31
|
-
else
|
32
|
-
render_unprocessable_entity
|
33
|
-
end
|
34
24
|
end
|
35
25
|
end
|
36
26
|
end
|
@@ -5,7 +5,11 @@ module Morpho
|
|
5
5
|
|
6
6
|
namespace :externals do
|
7
7
|
desc 'Request user authentication from external provider' do
|
8
|
+
detail ''
|
8
9
|
success Morpho::Grape::DataWrapper.new(Morpho::Entities::AuthenticationToken)
|
10
|
+
failure [
|
11
|
+
[ 422, I18n.t('morpho.api.messages.general.422'), Morpho::Entities::Error ]
|
12
|
+
]
|
9
13
|
end
|
10
14
|
params do
|
11
15
|
requires :data, type: Morpho::Entities::External
|
@@ -15,13 +19,6 @@ module Morpho
|
|
15
19
|
|
16
20
|
if result.success?
|
17
21
|
present result['token'], with: Morpho::Entities::AuthenticationToken
|
18
|
-
else
|
19
|
-
case result['error']
|
20
|
-
when :unprocessable_entity
|
21
|
-
render_unprocessable_entity(result['contract'].errors)
|
22
|
-
else
|
23
|
-
render_unprocessable_entity
|
24
|
-
end
|
25
22
|
end
|
26
23
|
end
|
27
24
|
end
|
@@ -5,6 +5,7 @@ module Morpho
|
|
5
5
|
|
6
6
|
namespace :hello do
|
7
7
|
desc 'Request hello message' do
|
8
|
+
detail ''
|
8
9
|
success Morpho::Grape::DataWrapper.new(Morpho::Entities::Message)
|
9
10
|
end
|
10
11
|
get :public do
|
@@ -19,9 +20,10 @@ module Morpho
|
|
19
20
|
end
|
20
21
|
|
21
22
|
desc 'Request hello message' do
|
23
|
+
detail ''
|
22
24
|
success Morpho::Grape::DataWrapper.new(Morpho::Entities::Message)
|
23
25
|
failure [
|
24
|
-
[ 401, I18n.t('morpho.api.messages.
|
26
|
+
[ 401, I18n.t('morpho.api.messages.general.401'), Morpho::Entities::Error ]
|
25
27
|
]
|
26
28
|
end
|
27
29
|
get :private do
|
@@ -5,11 +5,12 @@ module Morpho
|
|
5
5
|
|
6
6
|
namespace :passwords do
|
7
7
|
desc 'Request user reset password token' do
|
8
|
+
detail ''
|
8
9
|
success Morpho::Grape::DataWrapper.new(Morpho::Entities::User)
|
9
10
|
failure [
|
10
|
-
[ 404, I18n.t('morpho.api.messages.
|
11
|
-
[ 405, I18n.t('morpho.api.messages.
|
12
|
-
[ 422, I18n.t('morpho.api.messages.
|
11
|
+
[ 404, I18n.t('morpho.api.messages.general.404'), Morpho::Entities::Error ],
|
12
|
+
[ 405, I18n.t('morpho.api.messages.general.405'), Morpho::Entities::Error ],
|
13
|
+
[ 422, I18n.t('morpho.api.messages.general.422'), Morpho::Entities::Error ]
|
13
14
|
]
|
14
15
|
end
|
15
16
|
params do
|
@@ -20,19 +21,6 @@ module Morpho
|
|
20
21
|
|
21
22
|
if result.success?
|
22
23
|
present result['model'], with: Morpho::Entities::User
|
23
|
-
else
|
24
|
-
case result['error']
|
25
|
-
when :not_valid
|
26
|
-
render_unprocessable_entity(result['contract'].errors)
|
27
|
-
when :not_found
|
28
|
-
render_not_found
|
29
|
-
when :not_allowed
|
30
|
-
render_method_not_allowed
|
31
|
-
when :not_delivered
|
32
|
-
render_unprocessable_entity
|
33
|
-
else
|
34
|
-
render_unprocessable_entity
|
35
|
-
end
|
36
24
|
end
|
37
25
|
end
|
38
26
|
end
|
@@ -5,13 +5,14 @@ module Morpho
|
|
5
5
|
|
6
6
|
namespace :tokens do
|
7
7
|
desc 'Request user authentication token' do
|
8
|
+
detail ''
|
8
9
|
success Morpho::Grape::DataWrapper.new(Morpho::Entities::AuthenticationToken)
|
9
10
|
failure [
|
10
|
-
[ 401, I18n.t('morpho.api.messages.
|
11
|
-
[ 403, I18n.t('morpho.api.messages.
|
12
|
-
[ 404, I18n.t('morpho.api.messages.
|
13
|
-
[ 422, I18n.t('morpho.api.messages.
|
14
|
-
[ 423, I18n.t('morpho.api.messages.
|
11
|
+
[ 401, I18n.t('morpho.api.messages.general.401'), Morpho::Entities::Error ],
|
12
|
+
[ 403, I18n.t('morpho.api.messages.general.403'), Morpho::Entities::Error ],
|
13
|
+
[ 404, I18n.t('morpho.api.messages.general.404'), Morpho::Entities::Error ],
|
14
|
+
[ 422, I18n.t('morpho.api.messages.general.422'), Morpho::Entities::Error ],
|
15
|
+
[ 423, I18n.t('morpho.api.messages.general.423'), Morpho::Entities::Error ]
|
15
16
|
]
|
16
17
|
end
|
17
18
|
params do
|
@@ -22,29 +23,15 @@ module Morpho
|
|
22
23
|
|
23
24
|
if result.success?
|
24
25
|
present result['token'], with: Morpho::Entities::AuthenticationToken
|
25
|
-
else
|
26
|
-
case result['error']
|
27
|
-
when :unprocessable_entity
|
28
|
-
render_unprocessable_entity(result['contract'].errors)
|
29
|
-
when :not_found
|
30
|
-
render_not_found({ base: I18n.t('morpho.api.messages.sign_in.not_found') })
|
31
|
-
when :forbidden
|
32
|
-
render_forbidden({ base: I18n.t('morpho.api.messages.sign_in.forbidden') })
|
33
|
-
when :locked
|
34
|
-
render_locked({ base: I18n.t('morpho.api.messages.sign_in.locked') })
|
35
|
-
when :unauthorized
|
36
|
-
render_unauthorized({ base: I18n.t('morpho.api.messages.sign_in.unauthorized') })
|
37
|
-
else
|
38
|
-
render_unprocessable_entity
|
39
|
-
end
|
40
26
|
end
|
41
27
|
end
|
42
28
|
|
43
29
|
desc 'Refresh user authentication token' do
|
30
|
+
detail ''
|
44
31
|
success Morpho::Grape::DataWrapper.new(Morpho::Entities::AuthenticationToken)
|
45
32
|
failure [
|
46
|
-
[ 404, I18n.t('morpho.api.messages.
|
47
|
-
[ 422, I18n.t('morpho.api.messages.
|
33
|
+
[ 404, I18n.t('morpho.api.messages.general.404'), Morpho::Entities::Error ],
|
34
|
+
[ 422, I18n.t('morpho.api.messages.general.422'), Morpho::Entities::Error ]
|
48
35
|
]
|
49
36
|
end
|
50
37
|
params do
|
@@ -55,15 +42,6 @@ module Morpho
|
|
55
42
|
|
56
43
|
if result.success?
|
57
44
|
present result['token'], with: Morpho::Entities::AuthenticationToken
|
58
|
-
else
|
59
|
-
case result['error']
|
60
|
-
when :unprocessable_entity
|
61
|
-
render_unprocessable_entity(result['contract'].errors)
|
62
|
-
when :not_found
|
63
|
-
render_not_found({ base: I18n.t('morpho.api.messages.refresh_token.not_found') })
|
64
|
-
else
|
65
|
-
render_unprocessable_entity
|
66
|
-
end
|
67
45
|
end
|
68
46
|
end
|
69
47
|
end
|
@@ -5,11 +5,12 @@ module Morpho
|
|
5
5
|
|
6
6
|
namespace :unlocks do
|
7
7
|
desc 'Request user unlock token' do
|
8
|
+
detail ''
|
8
9
|
success Morpho::Grape::DataWrapper.new(Morpho::Entities::UserEmail)
|
9
10
|
failure [
|
10
|
-
[ 404, I18n.t('morpho.api.messages.
|
11
|
-
[ 405, I18n.t('morpho.api.messages.
|
12
|
-
[ 422, I18n.t('morpho.api.messages.
|
11
|
+
[ 404, I18n.t('morpho.api.messages.general.404'), Morpho::Entities::Error ],
|
12
|
+
[ 405, I18n.t('morpho.api.messages.general.405'), Morpho::Entities::Error ],
|
13
|
+
[ 422, I18n.t('morpho.api.messages.general.422'), Morpho::Entities::Error ]
|
13
14
|
]
|
14
15
|
end
|
15
16
|
params do
|
@@ -20,17 +21,6 @@ module Morpho
|
|
20
21
|
|
21
22
|
if result.success?
|
22
23
|
present result['model'], with: Morpho::Entities::User
|
23
|
-
else
|
24
|
-
case result['error']
|
25
|
-
when :unprocessable_entity
|
26
|
-
render_unprocessable_entity(result['contract'].errors)
|
27
|
-
when :not_found
|
28
|
-
render_not_found({ base: I18n.t('morpho.api.messages.unlock.not_found') })
|
29
|
-
when :method_not_allowed
|
30
|
-
render_method_not_allowed({ base: I18n.t('morpho.api.messages.unlock.method_not_allowed') })
|
31
|
-
else
|
32
|
-
render_unprocessable_entity
|
33
|
-
end
|
34
24
|
end
|
35
25
|
end
|
36
26
|
end
|
@@ -5,9 +5,10 @@ module Morpho
|
|
5
5
|
|
6
6
|
namespace :users do
|
7
7
|
desc 'User registration' do
|
8
|
+
detail ''
|
8
9
|
success Morpho::Grape::DataWrapper.new(Morpho::Entities::User)
|
9
10
|
failure [
|
10
|
-
[ 422, I18n.t('morpho.api.messages.
|
11
|
+
[ 422, I18n.t('morpho.api.messages.general.422'), Morpho::Entities::Error ]
|
11
12
|
]
|
12
13
|
end
|
13
14
|
params do
|
@@ -18,15 +19,6 @@ module Morpho
|
|
18
19
|
|
19
20
|
if result.success?
|
20
21
|
present result['model'], with: Morpho::Entities::User
|
21
|
-
else
|
22
|
-
case result['error']
|
23
|
-
when :not_valid
|
24
|
-
render_unprocessable_entity(result['contract'].errors)
|
25
|
-
when :not_saved
|
26
|
-
render_unprocessable_entity(result['model'].errors)
|
27
|
-
else
|
28
|
-
render_unprocessable_entity
|
29
|
-
end
|
30
22
|
end
|
31
23
|
end
|
32
24
|
end
|
@@ -1,40 +1,42 @@
|
|
1
1
|
module Morpho
|
2
2
|
class User::Operation::Activate < Trailblazer::Operation
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
step :check
|
8
|
-
fail :method_not_allowed, fail_fast: true
|
9
|
-
pass :activation_email
|
3
|
+
pass :validate!
|
4
|
+
pass :find!
|
5
|
+
pass :check!
|
6
|
+
pass :activation_email!
|
10
7
|
|
11
|
-
def validate
|
8
|
+
def validate!(options, **)
|
12
9
|
options['contract'] = Morpho::User::Contract::Activate.new(OpenStruct.new)
|
13
|
-
options['contract'].validate(options['data'])
|
14
|
-
end
|
15
|
-
|
16
|
-
def find (options, **)
|
17
|
-
options['model'] = Morpho::User.find_by(email: options['data']['email'])
|
18
|
-
end
|
19
10
|
|
20
|
-
|
21
|
-
|
11
|
+
unless options['contract'].validate(options['data'])
|
12
|
+
raise Morpho::Exceptions::StandardError.new(
|
13
|
+
errors: options['contract'].errors
|
14
|
+
)
|
15
|
+
end
|
22
16
|
end
|
23
17
|
|
24
|
-
def
|
25
|
-
options['model'].
|
26
|
-
end
|
18
|
+
def find!(options, **)
|
19
|
+
options['model'] = Morpho::User.find_by(email: options['data']['email'])
|
27
20
|
|
28
|
-
|
29
|
-
|
21
|
+
if options['model'].nil?
|
22
|
+
raise Morpho::Exceptions::StandardError.new(
|
23
|
+
message: I18n.t('morpho.api.messages.activate.email_not_exists'),
|
24
|
+
status: 404
|
25
|
+
)
|
26
|
+
end
|
30
27
|
end
|
31
28
|
|
32
|
-
def
|
33
|
-
options['
|
29
|
+
def check!(options, **)
|
30
|
+
if options['model'].active?
|
31
|
+
raise Morpho::Exceptions::StandardError.new(
|
32
|
+
message: I18n.t('morpho.api.messages.activate.account_already_confirmed'),
|
33
|
+
status: 405
|
34
|
+
)
|
35
|
+
end
|
34
36
|
end
|
35
37
|
|
36
|
-
def
|
37
|
-
options['
|
38
|
+
def activation_email!(options, **)
|
39
|
+
options['model'].resend_activation_needed_email!
|
38
40
|
end
|
39
41
|
end
|
40
42
|
end
|
@@ -1,48 +1,52 @@
|
|
1
1
|
module Morpho
|
2
2
|
class User::Operation::ExternalSignIn < Trailblazer::Operation
|
3
|
-
|
4
|
-
|
5
|
-
pass :
|
6
|
-
pass :
|
7
|
-
pass :
|
8
|
-
pass :
|
9
|
-
pass :
|
10
|
-
|
11
|
-
|
12
|
-
step :authentication_token
|
3
|
+
pass :validate!
|
4
|
+
pass :find_authentication!
|
5
|
+
pass :find_user!
|
6
|
+
pass :sign_in!
|
7
|
+
pass :register!
|
8
|
+
pass :sign_up!
|
9
|
+
pass :generate_refresh_token!
|
10
|
+
pass :register_last_login_activity!
|
11
|
+
pass :authentication_token!
|
13
12
|
|
14
|
-
def validate
|
13
|
+
def validate!(options, **)
|
15
14
|
options['contract'] = Morpho::User::Contract::ExternalSignIn.new(OpenStruct.new)
|
16
|
-
|
15
|
+
|
16
|
+
unless options['contract'].validate(options['data'])
|
17
|
+
raise Morpho::Exceptions::StandardError.new(
|
18
|
+
errors: options['contract'].errors
|
19
|
+
)
|
20
|
+
end
|
17
21
|
end
|
18
22
|
|
19
|
-
def find_authentication
|
23
|
+
def find_authentication!(options, **)
|
20
24
|
options['authentication.model'] = Morpho::Authentication.find_by(
|
21
25
|
uid: options['data']['uid'],
|
22
26
|
provider: options['data']['provider']
|
23
27
|
)
|
24
28
|
end
|
25
29
|
|
26
|
-
def find_user
|
30
|
+
def find_user!(options, **)
|
27
31
|
options['user.model'] = Morpho::User.find_by(email: options['data']['email'])
|
28
32
|
end
|
29
33
|
|
30
|
-
def sign_in
|
34
|
+
def sign_in!(options, **)
|
31
35
|
if options['authentication.model']
|
32
36
|
options['user.model'] = options['authentication.model'].user
|
33
37
|
end
|
34
38
|
end
|
35
39
|
|
36
|
-
def register
|
37
|
-
if options['user.model'] &&
|
40
|
+
def register!(options, **)
|
41
|
+
if options['user.model'] && options['authentication.model'].nil?
|
38
42
|
provider = options['data']['provider'].downcase
|
39
43
|
|
40
44
|
options['user.model'].add_provider_to_user(provider, options['data']['uid'])
|
41
45
|
end
|
42
46
|
end
|
43
47
|
|
44
|
-
def sign_up
|
45
|
-
if
|
48
|
+
def sign_up!(options, **)
|
49
|
+
if options['user.model'].nil? && options['authentication.model'].nil?
|
46
50
|
provider = options['data']['provider'].downcase
|
47
51
|
|
48
52
|
options['user.model'] = Morpho::User.create_from_provider(provider, options['data']['uid'], {
|
@@ -51,19 +55,15 @@ module Morpho
|
|
51
55
|
end
|
52
56
|
end
|
53
57
|
|
54
|
-
def generate_refresh_token
|
58
|
+
def generate_refresh_token!(options, **)
|
55
59
|
options['user.model'].generate_refresh_token!
|
56
60
|
end
|
57
61
|
|
58
|
-
def register_last_login_activity
|
62
|
+
def register_last_login_activity!(options, **)
|
59
63
|
options['user.model'].register_last_login_activity!(options['ip'])
|
60
64
|
end
|
61
65
|
|
62
|
-
def
|
63
|
-
options['error'] = :unprocessable_entity
|
64
|
-
end
|
65
|
-
|
66
|
-
def authentication_token (options, **)
|
66
|
+
def authentication_token!(options, **)
|
67
67
|
options['token'] = ::Morpho::JWT::Payload.new(options['user.model'])
|
68
68
|
end
|
69
69
|
end
|
@@ -1,34 +1,36 @@
|
|
1
1
|
module Morpho
|
2
2
|
class User::Operation::RefreshToken < Trailblazer::Operation
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
step :generate_refresh_token
|
8
|
-
step :authentication_token
|
3
|
+
pass :validate!
|
4
|
+
pass :find!
|
5
|
+
pass :generate_refresh_token!
|
6
|
+
pass :authentication_token!
|
9
7
|
|
10
|
-
def validate
|
8
|
+
def validate!(options, **)
|
11
9
|
options['contract'] = Morpho::User::Contract::RefreshToken.new(OpenStruct.new)
|
12
|
-
options['contract'].validate(options['data'])
|
13
|
-
end
|
14
10
|
|
15
|
-
|
16
|
-
|
11
|
+
unless options['contract'].validate(options['data'])
|
12
|
+
raise Morpho::Exceptions::StandardError.new(
|
13
|
+
errors: options['contract'].errors
|
14
|
+
)
|
15
|
+
end
|
17
16
|
end
|
18
17
|
|
19
|
-
def
|
20
|
-
options['model'].
|
21
|
-
end
|
18
|
+
def find!(options, **)
|
19
|
+
options['model'] = Morpho::User.find_by(refresh_token: options['data']['refresh_token'])
|
22
20
|
|
23
|
-
|
24
|
-
|
21
|
+
if options['model'].nil?
|
22
|
+
raise Morpho::Exceptions::StandardError.new(
|
23
|
+
message: I18n.t('morpho.api.messages.refresh_token.invalid'),
|
24
|
+
status: 404
|
25
|
+
)
|
26
|
+
end
|
25
27
|
end
|
26
28
|
|
27
|
-
def
|
28
|
-
options['
|
29
|
+
def generate_refresh_token!(options, **)
|
30
|
+
options['model'].generate_refresh_token!
|
29
31
|
end
|
30
32
|
|
31
|
-
def authentication_token
|
33
|
+
def authentication_token!(options, **)
|
32
34
|
options['token'] = ::Morpho::JWT::Payload.new(options['model'])
|
33
35
|
end
|
34
36
|
end
|
@@ -1,49 +1,40 @@
|
|
1
1
|
module Morpho
|
2
2
|
class User::Operation::ResetPassword < Trailblazer::Operation
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
step :check
|
8
|
-
fail :not_allowed, fail_fast: true
|
9
|
-
step :reset_password_email
|
10
|
-
fail :not_delivered, fail_fast: true
|
3
|
+
pass :validate!
|
4
|
+
pass :find!
|
5
|
+
pass :check!
|
6
|
+
pass :reset_password_email!
|
11
7
|
|
12
|
-
def validate
|
8
|
+
def validate!(options, **)
|
13
9
|
options['contract'] = Morpho::User::Contract::ResetPassword.new(OpenStruct.new)
|
14
|
-
options['contract'].validate(options['data'])
|
15
|
-
end
|
16
|
-
|
17
|
-
def find (options, **)
|
18
|
-
options['model'] = Morpho::User.find_by(email: options['data']['email'])
|
19
|
-
end
|
20
|
-
|
21
|
-
def check (options, **)
|
22
|
-
!options['model'].external?
|
23
|
-
end
|
24
10
|
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
options['error'] = :not_valid
|
11
|
+
unless options['contract'].validate(options['data'])
|
12
|
+
raise Morpho::Exceptions::StandardError.new(
|
13
|
+
errors: options['contract'].errors
|
14
|
+
)
|
15
|
+
end
|
31
16
|
end
|
32
17
|
|
33
|
-
def
|
34
|
-
options['
|
35
|
-
end
|
18
|
+
def find!(options, **)
|
19
|
+
options['model'] = Morpho::User.find_by(email: options['data']['email'])
|
36
20
|
|
37
|
-
|
38
|
-
|
21
|
+
if options['model'].nil?
|
22
|
+
raise Morpho::Exceptions::StandardError.new(
|
23
|
+
status: 404
|
24
|
+
)
|
25
|
+
end
|
39
26
|
end
|
40
27
|
|
41
|
-
def
|
42
|
-
options['
|
28
|
+
def check!(options, **)
|
29
|
+
if options['model'].external?
|
30
|
+
raise Morpho::Exceptions::StandardError.new(
|
31
|
+
status: 405
|
32
|
+
)
|
33
|
+
end
|
43
34
|
end
|
44
35
|
|
45
|
-
def
|
46
|
-
options['model']
|
36
|
+
def reset_password_email!(options, **)
|
37
|
+
options['model'].deliver_reset_password_instructions!
|
47
38
|
end
|
48
39
|
end
|
49
40
|
end
|
@@ -1,70 +1,72 @@
|
|
1
1
|
module Morpho
|
2
2
|
class User::Operation::SignIn < Trailblazer::Operation
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
step :check_password
|
12
|
-
fail :unauthorized, fail_fast: true
|
13
|
-
step :generate_refresh_token
|
14
|
-
step :register_last_login_activity
|
15
|
-
step :authentication_token
|
3
|
+
pass :validate!
|
4
|
+
pass :find!
|
5
|
+
pass :check_active!
|
6
|
+
pass :check_unlocked!
|
7
|
+
pass :check_password!
|
8
|
+
pass :generate_refresh_token!
|
9
|
+
pass :register_last_login_activity!
|
10
|
+
pass :authentication_token!
|
16
11
|
|
17
|
-
def validate
|
12
|
+
def validate!(options, **)
|
18
13
|
options['contract'] = Morpho::User::Contract::SignIn.new(OpenStruct.new)
|
19
|
-
|
14
|
+
|
15
|
+
unless options['contract'].validate(options['data'])
|
16
|
+
raise Morpho::Exceptions::StandardError.new(
|
17
|
+
errors: options['contract'].errors
|
18
|
+
)
|
19
|
+
end
|
20
20
|
end
|
21
21
|
|
22
|
-
def find
|
22
|
+
def find!(options, **)
|
23
23
|
options['model'] = Morpho::User.find_by(email: options['data']['email'])
|
24
|
+
|
25
|
+
if options['model'].nil?
|
26
|
+
raise Morpho::Exceptions::StandardError.new(
|
27
|
+
message: I18n.t('morpho.api.messages.sign_in.email_not_exists'),
|
28
|
+
status: 404
|
29
|
+
)
|
30
|
+
end
|
24
31
|
end
|
25
32
|
|
26
|
-
def check_active
|
27
|
-
options['model'].active?
|
33
|
+
def check_active!(options, **)
|
34
|
+
unless options['model'].active?
|
35
|
+
raise Morpho::Exceptions::StandardError.new(
|
36
|
+
message: I18n.t('morpho.api.messages.sign_in.account_not_confirmed'),
|
37
|
+
status: 403
|
38
|
+
)
|
39
|
+
end
|
28
40
|
end
|
29
41
|
|
30
|
-
def check_unlocked
|
31
|
-
options['model'].unlocked?
|
42
|
+
def check_unlocked!(options, **)
|
43
|
+
unless options['model'].unlocked?
|
44
|
+
raise Morpho::Exceptions::StandardError.new(
|
45
|
+
message: I18n.t('morpho.api.messages.sign_in.account_locked'),
|
46
|
+
status: 423
|
47
|
+
)
|
48
|
+
end
|
32
49
|
end
|
33
50
|
|
34
|
-
def check_password
|
35
|
-
options['model'].valid_password?(options['data']['password'])
|
51
|
+
def check_password!(options, **)
|
52
|
+
unless options['model'].valid_password?(options['data']['password'])
|
53
|
+
options['model'].register_failed_login!
|
54
|
+
raise Morpho::Exceptions::StandardError.new(
|
55
|
+
message: I18n.t('morpho.api.messages.sign_in.bad_credentials'),
|
56
|
+
status: 401
|
57
|
+
)
|
58
|
+
end
|
36
59
|
end
|
37
60
|
|
38
|
-
def generate_refresh_token
|
61
|
+
def generate_refresh_token!(options, **)
|
39
62
|
options['model'].generate_refresh_token!
|
40
63
|
end
|
41
64
|
|
42
|
-
def register_last_login_activity
|
65
|
+
def register_last_login_activity!(options, **)
|
43
66
|
options['model'].register_last_login_activity!(options['ip'])
|
44
67
|
end
|
45
68
|
|
46
|
-
def
|
47
|
-
options['error'] = :unprocessable_entity
|
48
|
-
end
|
49
|
-
|
50
|
-
def not_found (options, **)
|
51
|
-
options['error'] = :not_found
|
52
|
-
end
|
53
|
-
|
54
|
-
def forbidden (options, **)
|
55
|
-
options['error'] = :forbidden
|
56
|
-
end
|
57
|
-
|
58
|
-
def locked (options, **)
|
59
|
-
options['error'] = :locked
|
60
|
-
end
|
61
|
-
|
62
|
-
def unauthorized (options, **)
|
63
|
-
options['model'].register_failed_login!
|
64
|
-
options['error'] = :unauthorized
|
65
|
-
end
|
66
|
-
|
67
|
-
def authentication_token (options, **)
|
69
|
+
def authentication_token!(options, **)
|
68
70
|
options['token'] = ::Morpho::JWT::Payload.new(options['model'])
|
69
71
|
end
|
70
72
|
end
|
@@ -1,36 +1,32 @@
|
|
1
1
|
module Morpho
|
2
2
|
class User::Operation::SignUp < Trailblazer::Operation
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
fail :not_synced, fail_fast: true
|
7
|
-
step :save
|
8
|
-
fail :not_saved, fail_fast: true
|
3
|
+
pass :validate!
|
4
|
+
pass :sync!
|
5
|
+
pass :save!
|
9
6
|
|
10
|
-
def validate(options, **)
|
7
|
+
def validate!(options, **)
|
11
8
|
options['contract'] = Morpho::User::Contract::SignUp.new(Morpho::User.new)
|
12
|
-
|
9
|
+
|
10
|
+
unless options['contract'].validate(options['data'])
|
11
|
+
raise Morpho::Exceptions::StandardError.new(
|
12
|
+
errors: options['contract'].errors
|
13
|
+
)
|
14
|
+
end
|
13
15
|
end
|
14
16
|
|
15
|
-
def sync(options, **)
|
17
|
+
def sync!(options, **)
|
16
18
|
options['contract'].sync
|
17
19
|
end
|
18
20
|
|
19
|
-
def save
|
21
|
+
def save!(options, **)
|
20
22
|
options['model'] = options['contract'].model
|
21
23
|
options['model'].save
|
22
|
-
end
|
23
|
-
|
24
|
-
def not_valid(options, **)
|
25
|
-
options['error'] = :not_valid
|
26
|
-
end
|
27
|
-
|
28
|
-
def not_synced(options, **)
|
29
|
-
options['error'] = :not_synced
|
30
|
-
end
|
31
24
|
|
32
|
-
|
33
|
-
|
25
|
+
unless options['model'].persisted?
|
26
|
+
raise Morpho::Exceptions::StandardError.new(
|
27
|
+
errors: options['model'].errors
|
28
|
+
)
|
29
|
+
end
|
34
30
|
end
|
35
31
|
end
|
36
32
|
end
|
@@ -1,40 +1,42 @@
|
|
1
1
|
module Morpho
|
2
2
|
class User::Operation::Unlock < Trailblazer::Operation
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
step :check
|
8
|
-
fail :method_not_allowed, fail_fast: true
|
9
|
-
pass :unlock_token_email
|
3
|
+
pass :validate!
|
4
|
+
pass :find!
|
5
|
+
pass :check!
|
6
|
+
pass :unlock_token_email!
|
10
7
|
|
11
|
-
def validate
|
8
|
+
def validate!(options, **)
|
12
9
|
options['contract'] = Morpho::User::Contract::Unlock.new(OpenStruct.new)
|
13
|
-
options['contract'].validate(options['data'])
|
14
|
-
end
|
15
|
-
|
16
|
-
def find (options, **)
|
17
|
-
options['model'] = Morpho::User.find_by(email: options['data']['email'])
|
18
|
-
end
|
19
10
|
|
20
|
-
|
21
|
-
|
11
|
+
unless options['contract'].validate(options['data'])
|
12
|
+
raise Morpho::Exceptions::StandardError.new(
|
13
|
+
errors: options['contract'].errors
|
14
|
+
)
|
15
|
+
end
|
22
16
|
end
|
23
17
|
|
24
|
-
def
|
25
|
-
options['model'].
|
26
|
-
end
|
18
|
+
def find!(options, **)
|
19
|
+
options['model'] = Morpho::User.find_by(email: options['data']['email'])
|
27
20
|
|
28
|
-
|
29
|
-
|
21
|
+
if options['model'].nil?
|
22
|
+
raise Morpho::Exceptions::StandardError.new(
|
23
|
+
message: I18n.t('morpho.api.messages.unlock.email_not_exists'),
|
24
|
+
status: 404
|
25
|
+
)
|
26
|
+
end
|
30
27
|
end
|
31
28
|
|
32
|
-
def
|
33
|
-
options['
|
29
|
+
def check!(options, **)
|
30
|
+
unless options['model'].login_locked?
|
31
|
+
raise Morpho::Exceptions::StandardError.new(
|
32
|
+
message: I18n.t('morpho.api.messages.unlock.account_not_locked'),
|
33
|
+
status: 405
|
34
|
+
)
|
35
|
+
end
|
34
36
|
end
|
35
37
|
|
36
|
-
def
|
37
|
-
options['
|
38
|
+
def unlock_token_email!(options, **)
|
39
|
+
options['model'].resend_unlock_token_email!
|
38
40
|
end
|
39
41
|
end
|
40
42
|
end
|
data/app/models/morpho/user.rb
CHANGED
@@ -130,27 +130,28 @@ en:
|
|
130
130
|
|
131
131
|
api:
|
132
132
|
messages:
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
133
|
+
general:
|
134
|
+
"400": 'Bad request'
|
135
|
+
"401": 'Unauthorized'
|
136
|
+
"402": 'Payment required'
|
137
|
+
"403": 'Forbidden'
|
138
|
+
"404": 'Not found'
|
139
|
+
"405": 'Method not allowed'
|
140
|
+
"422": 'Unprocessable entity'
|
141
|
+
"423": 'Locked'
|
141
142
|
activate:
|
142
|
-
|
143
|
-
|
143
|
+
email_not_exists: 'Email address does not belongs to a registered account'
|
144
|
+
account_already_confirmed: 'User account has already been confirmed'
|
144
145
|
sign_in:
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
146
|
+
email_not_exists: 'Email address does not belongs to a registered account'
|
147
|
+
account_not_confirmed: 'User account has not been confirmed'
|
148
|
+
account_locked: 'User account has been locked'
|
149
|
+
bad_credentials: 'User email and/or password is incorrect'
|
149
150
|
refresh_token:
|
150
|
-
|
151
|
+
invalid: 'Invalid token'
|
151
152
|
unlock:
|
152
|
-
|
153
|
-
|
153
|
+
email_not_exists: 'Email address does not belongs to a registered account'
|
154
|
+
account_not_locked: 'User account has not been locked'
|
154
155
|
simple_form:
|
155
156
|
'yes': 'Yes'
|
156
157
|
'no': 'No'
|
@@ -130,27 +130,28 @@ es:
|
|
130
130
|
|
131
131
|
api:
|
132
132
|
messages:
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
133
|
+
general:
|
134
|
+
"400": 'Solicitud incorrecta'
|
135
|
+
"401": 'No autorizado'
|
136
|
+
"402": 'Pago requerido'
|
137
|
+
"403": 'Prohibido'
|
138
|
+
"404": 'No encontrado'
|
139
|
+
"405": 'Método no permitido'
|
140
|
+
"422": 'Entidad no procesable'
|
141
|
+
"423": 'Bloqueado'
|
141
142
|
activate:
|
142
|
-
|
143
|
-
|
143
|
+
email_not_exists: 'Correo electrónico no pertenece a un usuario registrado'
|
144
|
+
account_already_confirmed: 'Cuenta de usuario ya ha sido confirmada'
|
144
145
|
sign_in:
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
146
|
+
email_not_exists: 'Correo electrónico no pertenece a un usuario registrado'
|
147
|
+
account_not_confirmed: 'Cuenta de usuario no ha sido confirmada'
|
148
|
+
account_locked: 'Cuenta de usuario ha sido bloqueada'
|
149
|
+
bad_credentials: 'Correo electrónico y/o contraseña es incorrecto(a)'
|
149
150
|
refresh_token:
|
150
|
-
|
151
|
+
invalid: 'El token es inválido'
|
151
152
|
unlock:
|
152
|
-
|
153
|
-
|
153
|
+
email_not_exists: 'Correo electrónico no pertenece a un usuario registrado'
|
154
|
+
account_not_locked: 'Cuenta de usuario no ha sido bloqueada'
|
154
155
|
simple_form:
|
155
156
|
'yes': 'Si'
|
156
157
|
'no': 'No'
|
data/lib/morpho/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: morpho
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Hugo Gilmar Erazo
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2018-11-
|
11
|
+
date: 2018-11-13 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rails
|
@@ -296,6 +296,8 @@ files:
|
|
296
296
|
- app/api/morpho/entities/user.rb
|
297
297
|
- app/api/morpho/entities/user_email.rb
|
298
298
|
- app/api/morpho/entities/user_sign_up.rb
|
299
|
+
- app/api/morpho/exceptions/standard_error.rb
|
300
|
+
- app/api/morpho/formatters/standard_error.rb
|
299
301
|
- app/api/morpho/helpers/http_responses.rb
|
300
302
|
- app/api/morpho/helpers/jwt_utils.rb
|
301
303
|
- app/api/morpho/resources/activations.rb
|