commons_yellowme 0.11.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 +7 -0
- data/MIT-LICENSE +20 -0
- data/README.md +28 -0
- data/Rakefile +17 -0
- data/lib/commons.rb +67 -0
- data/lib/commons/authentication/authenticate_by_jwt.rb +27 -0
- data/lib/commons/authentication/json_web_token.rb +17 -0
- data/lib/commons/concerns/attributes/sex.rb +19 -0
- data/lib/commons/concerns/extensions/deleted.rb +25 -0
- data/lib/commons/concerns/guard/capitalizable.rb +32 -0
- data/lib/commons/concerns/validations/undestroyable.rb +18 -0
- data/lib/commons/config.rb +11 -0
- data/lib/commons/config/locales/en.yml +1 -0
- data/lib/commons/config/locales/es.yml +58 -0
- data/lib/commons/controllers/schema_validable.rb +27 -0
- data/lib/commons/errors/bad_request.rb +15 -0
- data/lib/commons/errors/conflict.rb +15 -0
- data/lib/commons/errors/default_handling.rb +44 -0
- data/lib/commons/errors/error_base.rb +64 -0
- data/lib/commons/errors/error_serializer.rb +10 -0
- data/lib/commons/errors/forbidden.rb +15 -0
- data/lib/commons/errors/internal_server_error.rb +15 -0
- data/lib/commons/errors/invalid_resource.rb +21 -0
- data/lib/commons/errors/maintenance_mode.rb +14 -0
- data/lib/commons/errors/missing_parameter.rb +13 -0
- data/lib/commons/errors/not_unique.rb +14 -0
- data/lib/commons/errors/payment_required.rb +15 -0
- data/lib/commons/errors/precondition_failed.rb +15 -0
- data/lib/commons/errors/resource_not_found.rb +14 -0
- data/lib/commons/errors/route_not_found.rb +14 -0
- data/lib/commons/errors/unauthorized.rb +15 -0
- data/lib/commons/errors/unprocessable_entity.rb +15 -0
- data/lib/commons/formatter/e164_phone.rb +47 -0
- data/lib/commons/formatter/null_attributes_remover.rb +9 -0
- data/lib/commons/formatter/regex_constants.rb +9 -0
- data/lib/commons/formatter/string_utils.rb +9 -0
- data/lib/commons/middleware/catch_json_parse_errors.rb +30 -0
- data/lib/commons/railtie.rb +4 -0
- data/lib/commons/repositories/base_repository.rb +227 -0
- data/lib/commons/repositories/catalogs/base_catalog.rb +68 -0
- data/lib/commons/repositories/catalogs/concerns/model_caching_extention.rb +27 -0
- data/lib/commons/services/concerns/callable.rb +15 -0
- data/lib/commons/version.rb +3 -0
- data/lib/tasks/commons_tasks.rake +4 -0
- metadata +254 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 72561778339f9301bc276ec516c4bf13d3e98323c93ba4a7bfce41d67dcca9d2
|
4
|
+
data.tar.gz: 9036b246544ec395c0cfb7829bdbea2b85deb1cbf14b465c8aacf3eaaf56c709
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 563e23f1dfecd7805b3e274327365fe77a789db503cb421e00773d4ada57fb990456cfc5dea53fb0a411d1622074e4ef5985e851f54bce516ae6237d5863c785
|
7
|
+
data.tar.gz: 87e562f16d6f70f1c870c6db5ade5f5ae3c48601704e7040f7c327f8ad7c3c42b56a345268a68fa2bc1c04965b5ab672512f9d46bd3dc83144eb31afc18c762d
|
data/MIT-LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright 2019 Juan Ku
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
# Commons
|
2
|
+
Commons is Yellowme's Rails APIs utilities gem
|
3
|
+
|
4
|
+
## Usage
|
5
|
+
How to use my plugin.
|
6
|
+
|
7
|
+
## Installation
|
8
|
+
Add this line to your application's Gemfile:
|
9
|
+
|
10
|
+
```ruby
|
11
|
+
gem 'commons', git: 'https://github.com/yellowme/commons.git'
|
12
|
+
```
|
13
|
+
|
14
|
+
And then execute:
|
15
|
+
```bash
|
16
|
+
$ bundle
|
17
|
+
```
|
18
|
+
|
19
|
+
Or install it yourself as:
|
20
|
+
```bash
|
21
|
+
$ gem install commons
|
22
|
+
```
|
23
|
+
|
24
|
+
## Contributing
|
25
|
+
Contribution directions go here.
|
26
|
+
|
27
|
+
## License
|
28
|
+
The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
|
data/Rakefile
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
begin
|
2
|
+
require 'bundler/setup'
|
3
|
+
rescue LoadError
|
4
|
+
puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
|
5
|
+
end
|
6
|
+
|
7
|
+
require 'rdoc/task'
|
8
|
+
|
9
|
+
RDoc::Task.new(:rdoc) do |rdoc|
|
10
|
+
rdoc.rdoc_dir = 'rdoc'
|
11
|
+
rdoc.title = 'Commons'
|
12
|
+
rdoc.options << '--line-numbers'
|
13
|
+
rdoc.rdoc_files.include('README.md')
|
14
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
15
|
+
end
|
16
|
+
|
17
|
+
require 'bundler/gem_tasks'
|
data/lib/commons.rb
ADDED
@@ -0,0 +1,67 @@
|
|
1
|
+
require 'commons/railtie'
|
2
|
+
|
3
|
+
require 'strip_attributes'
|
4
|
+
require 'active_model_serializers'
|
5
|
+
require 'jwt'
|
6
|
+
require 'phonelib'
|
7
|
+
|
8
|
+
require 'commons/config'
|
9
|
+
|
10
|
+
# authentication
|
11
|
+
require 'commons/authentication/json_web_token'
|
12
|
+
require 'commons/authentication/authenticate_by_jwt'
|
13
|
+
|
14
|
+
# controllers
|
15
|
+
require 'commons/controllers/schema_validable'
|
16
|
+
|
17
|
+
# repositories
|
18
|
+
require 'commons/repositories/base_repository'
|
19
|
+
require 'commons/repositories/catalogs/concerns/model_caching_extention'
|
20
|
+
require 'commons/repositories/catalogs/base_catalog'
|
21
|
+
|
22
|
+
# services
|
23
|
+
require 'commons/services/concerns/callable'
|
24
|
+
|
25
|
+
# models
|
26
|
+
require 'commons/concerns/attributes/sex'
|
27
|
+
require 'commons/concerns/extensions/deleted'
|
28
|
+
require 'commons/concerns/guard/capitalizable'
|
29
|
+
require 'commons/concerns/validations/undestroyable'
|
30
|
+
|
31
|
+
# utils
|
32
|
+
require 'commons/formatter/null_attributes_remover'
|
33
|
+
require 'commons/formatter/regex_constants'
|
34
|
+
require 'commons/formatter/string_utils'
|
35
|
+
require 'commons/formatter/e164_phone'
|
36
|
+
|
37
|
+
# errors
|
38
|
+
require 'commons/errors/error_base'
|
39
|
+
require 'commons/errors/error_serializer'
|
40
|
+
require 'commons/errors/bad_request'
|
41
|
+
require 'commons/errors/conflict'
|
42
|
+
require 'commons/errors/default_handling'
|
43
|
+
require 'commons/errors/forbidden'
|
44
|
+
require 'commons/errors/internal_server_error'
|
45
|
+
require 'commons/errors/unprocessable_entity'
|
46
|
+
require 'commons/errors/invalid_resource'
|
47
|
+
require 'commons/errors/maintenance_mode'
|
48
|
+
require 'commons/errors/missing_parameter'
|
49
|
+
require 'commons/errors/not_unique'
|
50
|
+
require 'commons/errors/payment_required'
|
51
|
+
require 'commons/errors/precondition_failed'
|
52
|
+
require 'commons/errors/resource_not_found'
|
53
|
+
require 'commons/errors/route_not_found'
|
54
|
+
require 'commons/errors/unauthorized'
|
55
|
+
|
56
|
+
# middleware
|
57
|
+
require 'commons/middleware/catch_json_parse_errors'
|
58
|
+
|
59
|
+
mydir = __dir__
|
60
|
+
|
61
|
+
I18n.load_path += Dir[File.join(mydir, 'commons', 'config', 'locales', '**/*.yml').to_s]
|
62
|
+
I18n.reload! if I18n.backend.initialized?
|
63
|
+
|
64
|
+
Phonelib.default_country = "MX"
|
65
|
+
|
66
|
+
module Commons
|
67
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module Commons
|
2
|
+
module Authentication
|
3
|
+
module AuthenticateByJWT
|
4
|
+
def authorize_jwt!
|
5
|
+
raise Commons::Errors::Unauthorized if jwt.blank?
|
6
|
+
|
7
|
+
begin
|
8
|
+
decoded = JSONWebToken.decode(jwt)
|
9
|
+
@current_user = UserRepository.instance.find_by(id: decoded[:user_id])
|
10
|
+
rescue ActiveRecord::RecordNotFound => e
|
11
|
+
raise Commons::Errors::Unauthorized
|
12
|
+
rescue JWT::DecodeError => e
|
13
|
+
raise Commons::Errors::Unauthorized
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
private
|
18
|
+
|
19
|
+
def jwt
|
20
|
+
jwt ||= request.headers['Authorization']
|
21
|
+
return nil unless jwt.instance_of? String
|
22
|
+
|
23
|
+
jwt = jwt.split(' ').last if jwt
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module Commons
|
2
|
+
module Authentication
|
3
|
+
class JSONWebToken
|
4
|
+
SECRET_KEY = Commons.secret_key_base.to_s
|
5
|
+
|
6
|
+
def self.encode(payload, exp = 24.hours.from_now)
|
7
|
+
payload[:expires_at] = exp.to_i
|
8
|
+
JWT.encode(payload, SECRET_KEY)
|
9
|
+
end
|
10
|
+
|
11
|
+
def self.decode(token)
|
12
|
+
decoded = JWT.decode(token, SECRET_KEY)[0]
|
13
|
+
HashWithIndifferentAccess.new decoded
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module Commons
|
2
|
+
module Concerns
|
3
|
+
module Attributes
|
4
|
+
module Sex
|
5
|
+
extend ActiveSupport::Concern
|
6
|
+
|
7
|
+
FEMALE = 'female'.freeze
|
8
|
+
MALE = 'male'.freeze
|
9
|
+
|
10
|
+
included do
|
11
|
+
enum sex: {
|
12
|
+
female: FEMALE,
|
13
|
+
male: MALE
|
14
|
+
}, _suffix: true
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module Commons
|
2
|
+
module Concerns
|
3
|
+
module Extensions
|
4
|
+
module Deleted
|
5
|
+
extend ActiveSupport::Concern
|
6
|
+
|
7
|
+
included do
|
8
|
+
before_validation :check_not_deleted, on: [:update]
|
9
|
+
|
10
|
+
def deleted?
|
11
|
+
raise ActiveModel::MissingAttributeError unless self.has_attribute?(:deleted_at)
|
12
|
+
self.deleted_at.present?
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
private
|
17
|
+
|
18
|
+
def check_not_deleted
|
19
|
+
raise ActiveModel::MissingAttributeError unless self.has_attribute?(:deleted_at)
|
20
|
+
raise ActiveRecord::RecordInvalid if self.deleted_at_in_database.present?
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
module Commons
|
2
|
+
module Concerns
|
3
|
+
module Guard
|
4
|
+
module Capitalizable
|
5
|
+
extend ActiveSupport::Concern
|
6
|
+
|
7
|
+
module ClassMethods
|
8
|
+
attr_reader :only
|
9
|
+
|
10
|
+
private
|
11
|
+
|
12
|
+
def capitalize(only: [])
|
13
|
+
@only = only
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
included do
|
18
|
+
before_validation :capitalize_attrs
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
|
23
|
+
def capitalize_attrs
|
24
|
+
self.class.only.each do |attr|
|
25
|
+
value = self.instance_eval(attr.to_s)
|
26
|
+
self.send("#{attr.to_s}=", Commons::Formatter::StringUtils.capitalize(value)) unless value.nil?
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module Commons
|
2
|
+
module Concerns
|
3
|
+
module Validations
|
4
|
+
module Undestroyable
|
5
|
+
extend ActiveSupport::Concern
|
6
|
+
included do
|
7
|
+
before_destroy :prevent_destroy
|
8
|
+
end
|
9
|
+
|
10
|
+
private
|
11
|
+
|
12
|
+
def prevent_destroy
|
13
|
+
raise Commons::Errors::Unauthorized
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
en:
|
@@ -0,0 +1,58 @@
|
|
1
|
+
es:
|
2
|
+
status_code:
|
3
|
+
IER4001_route_not_found:
|
4
|
+
code: 'IER4001'
|
5
|
+
title: 'Ruta no encontrada'
|
6
|
+
detail: 'IER4001: La ruta solicitada no se encuentra registrada'
|
7
|
+
IER4002_unauthorized:
|
8
|
+
code: 'IER4002'
|
9
|
+
title: 'No tienes permisos validos'
|
10
|
+
detail: 'IER4002: Parece que no tienes los permisos/credenciales correctos'
|
11
|
+
IER4003_bad_request:
|
12
|
+
code: 'IER4003'
|
13
|
+
title: 'El servidor no puede o no procesará la solicitud debido a un error aparente del cliente'
|
14
|
+
detail: 'IER4003: Su solicitud probablemente tenga alguna sintaxis con formato incorrecto, un encabezado incorrecto u otra cosa que no sepamos cómo procesar'
|
15
|
+
IER4004_conflict:
|
16
|
+
code: 'IER4004'
|
17
|
+
title: 'Hay un conflicto'
|
18
|
+
detail: 'IER4004: Su solicitud parece chocar con el estado del servidor'
|
19
|
+
IER4005_forbidden:
|
20
|
+
code: 'IER4005'
|
21
|
+
title: 'Tienes prohibido hacer esto.'
|
22
|
+
detail: 'IER4005: Parece que intentaste hacer algo que no debías hacer'
|
23
|
+
IER4006_invalid_resource:
|
24
|
+
code: 'IER4006'
|
25
|
+
title: 'Errores al procesar las validaciones.'
|
26
|
+
detail: 'IER4006: La información que ha enviado no es válida'
|
27
|
+
IER4007_missing_parameter:
|
28
|
+
code: 'IER4007'
|
29
|
+
title: 'Hacen faltan parámetros.'
|
30
|
+
detail: 'IER4007: Hacen faltan parámetros a la información suministrada'
|
31
|
+
IER4008_not_unique:
|
32
|
+
code: 'IER4008'
|
33
|
+
title: 'Hacen falta parámetros.'
|
34
|
+
detail: 'IER4008: Has violado una restricción de unicidad'
|
35
|
+
IER4009_payment_required:
|
36
|
+
code: 'IER4009'
|
37
|
+
title: 'Necesitas hacer un pago para que esta acción funcione.'
|
38
|
+
detail: 'IER4009: El servidor requiere que se realice un pago antes de continuar.'
|
39
|
+
IER4010_precondition_failed:
|
40
|
+
code: 'IER4010'
|
41
|
+
title: 'No se cumplió una condición previa.'
|
42
|
+
detail: 'IER4010: El servidor no cumple con una de las condiciones previas que el solicitante coloca en la solicitud.'
|
43
|
+
IER4011_resource_not_found:
|
44
|
+
code: 'IER4011'
|
45
|
+
title: 'Recurso no encontrado'
|
46
|
+
detail: 'IER4011: El recurso solicitado no se encuentra registrado'
|
47
|
+
IER4222_unprocessable_entity:
|
48
|
+
code: 'IER4222'
|
49
|
+
title: 'Incapaz de procesar la petición'
|
50
|
+
detail: 'IER4222: No se puede procesar la petición'
|
51
|
+
IER5000_internal_server_error:
|
52
|
+
code: 'IER5000'
|
53
|
+
title: 'Server Error.'
|
54
|
+
detail: 'IER5000: Su solicitud parece haber causado un error de servidor'
|
55
|
+
IER5030_maintenance_mode:
|
56
|
+
code: 'IER5030'
|
57
|
+
title: 'El servidor está en mantenimiento'
|
58
|
+
detail: 'IER5030: Mantenimiento en proceso'
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module Commons
|
2
|
+
module Controllers
|
3
|
+
module SchemaValidable
|
4
|
+
#
|
5
|
+
# Método que valida datos en base a un Schema
|
6
|
+
#
|
7
|
+
# @param [Hash] request_data datos a validar
|
8
|
+
# @param [Dry::Validation::Contract] schema Schema de validación
|
9
|
+
#
|
10
|
+
# @return [Hash]
|
11
|
+
#
|
12
|
+
# @raise [Commons::Errors::UnprocessableEntity]
|
13
|
+
#
|
14
|
+
def validate_request(request_data, schema)
|
15
|
+
validated_params = schema.call(request_data)
|
16
|
+
|
17
|
+
if validated_params.failure?
|
18
|
+
raise Commons::Errors::UnprocessableEntity.new(nil, nil,
|
19
|
+
meta: { validation_errors: validated_params.errors.to_h }
|
20
|
+
)
|
21
|
+
end
|
22
|
+
|
23
|
+
validated_params.to_h
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module Commons
|
2
|
+
module Errors
|
3
|
+
class BadRequest < ErrorBase
|
4
|
+
def initialize(message = nil, backtrace = nil, title: nil, code: nil, detail: nil, meta: {})
|
5
|
+
super message,
|
6
|
+
backtrace,
|
7
|
+
status: :bad_request,
|
8
|
+
title: title || I18n.t('status_code.IER4003_bad_request.title'),
|
9
|
+
code: code || I18n.t('status_code.IER4003_bad_request.code'),
|
10
|
+
detail: detail || I18n.t('status_code.IER4003_bad_request.detail'),
|
11
|
+
meta: meta
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module Commons
|
2
|
+
module Errors
|
3
|
+
class Conflict < ErrorBase
|
4
|
+
def initialize(message = nil, backtrace = nil, title: nil, code: nil, detail: nil, meta: {})
|
5
|
+
super message,
|
6
|
+
backtrace,
|
7
|
+
status: :conflict,
|
8
|
+
title: title || I18n.t('status_code.IER4004_conflict.title'),
|
9
|
+
code: code || I18n.t('status_code.IER4004_conflict.code'),
|
10
|
+
detail: detail || I18n.t('status_code.IER4004_conflict.detail'),
|
11
|
+
meta: meta
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
module Commons
|
2
|
+
module Errors
|
3
|
+
module DefaultHandling
|
4
|
+
def self.included(cls)
|
5
|
+
cls.class_eval do
|
6
|
+
# WARNING
|
7
|
+
# Avoid setting rescue_from Exception/StandardError since it will override your
|
8
|
+
# own custom rescue_from handlers https://stackoverflow.com/a/9121054/3287738
|
9
|
+
# WARNING
|
10
|
+
rescue_from ActiveRecord::RecordNotFound do |e|
|
11
|
+
respond ResourceNotFound.new e.message,
|
12
|
+
meta: {
|
13
|
+
model: e.model,
|
14
|
+
id: e.id,
|
15
|
+
primary_key: e.primary_key
|
16
|
+
}
|
17
|
+
end
|
18
|
+
|
19
|
+
rescue_from ActiveRecord::RecordInvalid do |e|
|
20
|
+
respond InvalidResource.new e.message,
|
21
|
+
validation_errors: e&.record&.errors&.to_hash
|
22
|
+
end
|
23
|
+
|
24
|
+
rescue_from ArgumentError do |e|
|
25
|
+
respond InvalidResource.new e.message
|
26
|
+
end
|
27
|
+
|
28
|
+
rescue_from ActiveRecord::RecordNotUnique do |e|
|
29
|
+
respond NotUnique.new e.message
|
30
|
+
end
|
31
|
+
|
32
|
+
rescue_from ActionController::ParameterMissing do |e|
|
33
|
+
respond MissingParameter.new e.message, param: e.param
|
34
|
+
end
|
35
|
+
|
36
|
+
rescue_from ActionController::RoutingError do |e|
|
37
|
+
respond RouteNotFound.new e.message,
|
38
|
+
detail: { failures: e.failures }
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|