virtuaservices 0.1.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.
Files changed (42) hide show
  1. checksums.yaml +7 -0
  2. data/lib/virtuaservices.rb +11 -0
  3. data/lib/virtuaservices/account.rb +72 -0
  4. data/lib/virtuaservices/authentication.rb +7 -0
  5. data/lib/virtuaservices/authentication/session.rb +28 -0
  6. data/lib/virtuaservices/concerns.rb +13 -0
  7. data/lib/virtuaservices/concerns/activable.rb +18 -0
  8. data/lib/virtuaservices/concerns/diagnosticable.rb +22 -0
  9. data/lib/virtuaservices/concerns/enumerable.rb +44 -0
  10. data/lib/virtuaservices/concerns/mime_typable.rb +36 -0
  11. data/lib/virtuaservices/concerns/premiumable.rb +15 -0
  12. data/lib/virtuaservices/concerns/sluggable.rb +27 -0
  13. data/lib/virtuaservices/concerns/typable.rb +17 -0
  14. data/lib/virtuaservices/monitoring.rb +12 -0
  15. data/lib/virtuaservices/monitoring/action.rb +25 -0
  16. data/lib/virtuaservices/monitoring/gateway.rb +37 -0
  17. data/lib/virtuaservices/monitoring/instance.rb +36 -0
  18. data/lib/virtuaservices/monitoring/route.rb +36 -0
  19. data/lib/virtuaservices/monitoring/service.rb +37 -0
  20. data/lib/virtuaservices/monitoring/websocket.rb +25 -0
  21. data/lib/virtuaservices/oauth.rb +7 -0
  22. data/lib/virtuaservices/oauth/application.rb +33 -0
  23. data/lib/virtuaservices/permissions.rb +10 -0
  24. data/lib/virtuaservices/permissions/category.rb +15 -0
  25. data/lib/virtuaservices/permissions/group.rb +30 -0
  26. data/lib/virtuaservices/permissions/right.rb +19 -0
  27. data/lib/virtuaservices/specs.rb +89 -0
  28. data/lib/virtuaservices/utils.rb +10 -0
  29. data/lib/virtuaservices/utils/controllers.rb +8 -0
  30. data/lib/virtuaservices/utils/controllers/base.rb +193 -0
  31. data/lib/virtuaservices/utils/controllers/checked.rb +14 -0
  32. data/lib/virtuaservices/utils/errors.rb +12 -0
  33. data/lib/virtuaservices/utils/errors/bad_request.rb +14 -0
  34. data/lib/virtuaservices/utils/errors/forbidden.rb +14 -0
  35. data/lib/virtuaservices/utils/errors/http_error.rb +30 -0
  36. data/lib/virtuaservices/utils/errors/not_found.rb +14 -0
  37. data/lib/virtuaservices/utils/loaders.rb +7 -0
  38. data/lib/virtuaservices/utils/loaders/heroku.rb +20 -0
  39. data/lib/virtuaservices/utils/micro_service.rb +170 -0
  40. data/lib/virtuaservices/utils/seeder.rb +25 -0
  41. data/lib/virtuaservices/version.rb +3 -0
  42. metadata +321 -0
@@ -0,0 +1,36 @@
1
+ module Virtuaservices
2
+ module Monitoring
3
+ # A route is an endpoint accessible in a service. Each route has to have an associated endpoint in the deployed instances.
4
+ # @param Vincent Courtois <courtois.vincent@outlook.com>
5
+ class Route
6
+ include Mongoid::Document
7
+ include Mongoid::Timestamps
8
+ include Virtuaservices::Concerns::Premiumable
9
+ include Virtuaservices::Concerns::Activable
10
+
11
+ # @!attribute [rw] path
12
+ # @return [String] the path (URI) of the route in the service?
13
+ field :path, type: String, default: '/'
14
+ # @!attribute [rw] verb
15
+ # @return [String] the verb (HTTP method) of this route in the service.
16
+ field :verb, type: String, default: 'get'
17
+ # @!attribute [rw] authenticated
18
+ # @return [Boolean] if true, the session_id is needed for this route, if false it is not.
19
+ field :authenticated, type: Boolean, default: true
20
+
21
+ # @!attribute [rw] service
22
+ # @return [Virtuaservices::Monitoring::Service] the service in which this route is declared.
23
+ belongs_to :service, class_name: 'Virtuaservices::Monitoring::Service', inverse_of: :routes
24
+
25
+ # @!attribute [rw] groups
26
+ # @return [Array<Virtuaservices::Permissions::Group>] the groups having permission to access this route.
27
+ has_and_belongs_to_many :groups, class_name: 'Virtuaservices::Permissions::Group', inverse_of: :groups
28
+
29
+ validates :path,
30
+ format: {with: /\A(\/|((\/:?[a-zA-Z0-9_]+)+))\z/, message: 'pattern', if: :path?}
31
+
32
+ validates :verb,
33
+ inclusion: {message: 'unknown', in: ['get', 'post', 'put', 'delete', 'patch', 'option']}
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,37 @@
1
+ module Virtuaservices
2
+ module Monitoring
3
+ # A service is the representation of one of the applications composing the API.
4
+ # @author Vincent Courtois <courtois.vincent@outlook.com>
5
+ class Service
6
+ include Mongoid::Document
7
+ include Mongoid::Timestamps
8
+ include Virtuaservices::Concerns::Activable
9
+ include Virtuaservices::Concerns::Diagnosticable
10
+ include Virtuaservices::Concerns::Premiumable
11
+
12
+ # @!attribute [rw] key
13
+ # @return [String] the name, or title of the service, optionally given to identify it more easily.
14
+ field :key, type: String
15
+ # @!attribute [rw] path
16
+ # @return [String] the path the service will be mapped on in the API.
17
+ field :path, type: String, default: '/'
18
+ # @!attribute [rw] test_mode
19
+ # @return [Boolean] TRUE if the service is currently in test mode and thus the gateway shall only qurty local instances.
20
+ field :test_mode, type: Boolean, default: false
21
+
22
+ # @!attribute [rw] creator
23
+ # @return [Virtuaservices::Account] the creator of this service.
24
+ belongs_to :creator, class_name: 'Virtuaservices::Account', optional: true, inverse_of: :services
25
+ # @!attribute [rw] instances
26
+ # @return [Array<Virtuaservices::Monitoring::Instance>] the instances of this service currently deployed.
27
+ embeds_many :instances, class_name: 'Virtuaservices::Monitoring::Instance', inverse_of: :service
28
+ # @!attribute [rw] routes
29
+ # @return [Array<Virtuaservices::Monitoring::Route>] the routes associated to this service, accessible from the gateway.
30
+ has_many :routes, class_name: 'Virtuaservices::Monitoring::Route', inverse_of: :service
31
+
32
+ validates :key, uniqueness: {message: 'uniq'}
33
+
34
+ validates :path, format: {with: /\A(\/:?[a-z]+)+\z/, message: 'pattern'}
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,25 @@
1
+ module Virtuaservices
2
+ module Monitoring
3
+ # The websocket is a particular kind of service, just like the gateway. It always has the same signature.
4
+ # A websocket document is a particular instance of websocket, located on a server and answering to a URL.
5
+ # @author Vincent Courtois <courtois.vincent@outlook.com>
6
+ class Websocket
7
+ include Mongoid::Document
8
+ include Mongoid::Timestamps
9
+ include Virtuaservices::Concerns::Activable
10
+ include Virtuaservices::Concerns::Diagnosticable
11
+
12
+ # @!attribute [rw] url
13
+ # @return [String] the URL of the websocket to be contacted on.
14
+ field :url, type: String
15
+
16
+ # @!attribute [rw] creator
17
+ # @return [Virtuaservices::Account] the account that created this web socket instance in the database.
18
+ belongs_to :creator, class_name: 'Virtuaservices::Account', inverse_of: :web_sockets, optional: true
19
+
20
+ validates :url,
21
+ presence: {message: 'required'},
22
+ format: {with: /\A(ws:\/\/)([\da-z\.-]+)\.([a-z\.]{2,6})([\/\w \.-]*)*\/?\z/, message: 'pattern', if: :url?}
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,7 @@
1
+ module Virtuaservices
2
+ # This module holds the logic for the connection of an application to our API.
3
+ # @author Vincent Courtois <courtois.vincent@outlook.com>
4
+ module OAuth
5
+ autoload :Application, 'virtuaservices/oauth/application'
6
+ end
7
+ end
@@ -0,0 +1,33 @@
1
+ module Virtuaservices
2
+ module OAuth
3
+ # An application is what is referred to in the OAuth2.0 RFC as a client, wanting to access private informations about the user.
4
+ # @author Vincent Courtois <courtois.vincent@outlook.com>
5
+ class Application
6
+ include Mongoid::Document
7
+ include Mongoid::Timestamps
8
+
9
+ # @!attribute [rw] name
10
+ # @return [String] the unique name of the application, mainly used to identify and display it.
11
+ field :name, type: String
12
+ # @!attribute [rw] key
13
+ # @return [String] the unique key for the application, identifying it when requesting a token for the API.
14
+ field :key, type: String, default: ->{ SecureRandom.hex }
15
+ # @!attribute [rw] premium
16
+ # @return [Boolean] a value indicating whether the application should automatically receive a token when an account is created, or not.
17
+ field :premium, type: Boolean, default: false
18
+
19
+ # @!attribute [rw] creator
20
+ # @return [Virtuaservices::Account] the account that has created this application, considered its owner.
21
+ belongs_to :creator, class_name: 'Virtuaservices::Account', inverse_of: :applications
22
+
23
+ validates :name,
24
+ presence: {message: 'required'},
25
+ length: {minimum: 6, message: 'minlength'},
26
+ uniqueness: {message: 'uniq'}
27
+
28
+ validates :key,
29
+ presence: {message: 'required'},
30
+ uniqueness: {message: 'uniq'}
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,10 @@
1
+ module Virtuaservices
2
+ # This module holds the logic for all the classes concerning the permissions abd rights for the user.
3
+ # A permission is restricting the access to one or several features to the users having it.
4
+ # @author Vincent Courtois <courtois.vincent@outlook.com>
5
+ module Permissions
6
+ autoload :Right , 'virtuaservices/permissions/right'
7
+ autoload :Group , 'virtuaservices/permissions/group'
8
+ autoload :Category, 'virtuaservices/permissions/category'
9
+ end
10
+ end
@@ -0,0 +1,15 @@
1
+ module Virtuaservices
2
+ module Permissions
3
+ # A category of rights regroups one or several rights for convenience purposes.
4
+ # @author Vincent Courtois <courtois.vincent@outlook.com>
5
+ class Category
6
+ include Mongoid::Document
7
+ include Mongoid::Timestamps
8
+ include Virtuaservices::Concerns::Sluggable
9
+
10
+ has_many :rights, class_name: 'Virtuaservices::Permissions::Right', inverse_of: :category
11
+
12
+ make_sluggable 'category'
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,30 @@
1
+ module Virtuaservices
2
+ module Permissions
3
+ # A group gathers one or several users to give them the same rights for conviniency purposes.
4
+ # @author Vincent Courtois <courtois.vincent@outlook.com>
5
+ class Group
6
+ include Mongoid::Document
7
+ include Mongoid::Timestamps
8
+ include Virtuaservices::Concerns::Sluggable
9
+
10
+ # @!attribute [rw] is_default
11
+ # @return [Boolean] a boolean indicating whether this group is given when a new user registered or not.
12
+ field :is_default, type: Boolean, default: false
13
+ # @!attribute [rw] is_superuser
14
+ # @return [Boolean] a boolean indicating whether this group should have access to all groups and rights or not.
15
+ field :is_superuser, type: Boolean, default: false
16
+
17
+ # @!attribute [rw] accounts
18
+ # @return [Array<Virtuaservices::Account>] the accounts having the rights granted by this group.
19
+ has_and_belongs_to_many :accounts, class_name: 'Virtuaservices::Account', inverse_of: :groups
20
+ # @!attribute [rw] rights
21
+ # @return [Array<Virtuaservices::Permissions::Right>] the rights granted by belonging to this group.
22
+ has_and_belongs_to_many :rights, class_name: 'Virtuaservices::Permissions::Right', inverse_of: :groups
23
+ # @!attribute [rw] routes
24
+ # @return [Array<Virtuaservices::Monitoring::Route>] the routes this group can access in the API.
25
+ has_and_belongs_to_many :routes, class_name: 'Virtuaservices::Monitoring::Route', inverse_of: :groups
26
+
27
+ make_sluggable 'group'
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,19 @@
1
+ module Virtuaservices
2
+ module Permissions
3
+ # A right is the access to one or several features in the application. It's applied to a group, and transitively to an account.
4
+ # @author Vincent Courtois <courtois;vincent@outlook.com>
5
+ class Right
6
+ include Mongoid::Document
7
+ include Mongoid::Timestamps
8
+ include Virtuaservices::Concerns::Sluggable
9
+
10
+ # @!attribute [rw] groups
11
+ # @return [Array<Virtuaservices::Permissions::Group>] the groups granted with the permission to access features opened by this right.
12
+ has_and_belongs_to_many :groups, class_name: 'Virtuaservices::Permissions::Group', inverse_of: :rights
13
+
14
+ belongs_to :category, class_name: 'Virtuaservices::Permissions::Category', inverse_of: :rights
15
+
16
+ make_sluggable 'right'
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,89 @@
1
+ module Virtuaservices
2
+ # This module holds all the logic for the specs tools for all micro services (shared examples and other things).
3
+ # @author Vincent Courtois <courtois.vincent@outlook.com>
4
+ module Specs
5
+
6
+ # Includes all the shared examples you could need, describing the basic behaviour of a route.
7
+ def self.include_shared_examples
8
+ RSpec.shared_examples 'a route' do |_verb, _path|
9
+ let(:verb) { _verb }
10
+ let(:path) { _path }
11
+
12
+ def do_request(parameters)
13
+ public_send verb.to_sym, path, ['get', 'delete'].include?(verb) ? parameters : parameters.to_json
14
+ end
15
+
16
+ describe 'common errors' do
17
+ describe 'bad request errors' do
18
+ describe 'no token error' do
19
+ before do
20
+ do_request({app_key: 'test_key'})
21
+ end
22
+ it 'Raises a bad request (400) error when the parameters don\'t contain the token of the gateway' do
23
+ expect(last_response.status).to be 400
24
+ end
25
+ it 'returns the correct response if the parameters do not contain a gateway token' do
26
+ expect(JSON.parse(last_response.body)).to eq({
27
+ 'status' => 400,
28
+ 'field' => 'token',
29
+ 'error' => 'required',
30
+ 'docs' => 'https://github.com/jdr-tools/wiki/wiki/Common-errors#gateway-token-not-given'
31
+ })
32
+ end
33
+ end
34
+ describe 'no application key error' do
35
+ before do
36
+ do_request({token: 'test_token'})
37
+ end
38
+ it 'Raises a bad request (400) error when the parameters don\'t contain the application key' do
39
+ expect(last_response.status).to be 400
40
+ end
41
+ it 'returns the correct response if the parameters do not contain a application key' do
42
+ expect(JSON.parse(last_response.body)).to eq({
43
+ 'status' => 400,
44
+ 'field' => 'app_key',
45
+ 'error' => 'required',
46
+ 'docs' => 'https://github.com/jdr-tools/wiki/wiki/Common-errors#application-key-not-given'
47
+ })
48
+ end
49
+ end
50
+ end
51
+ describe 'not_found errors' do
52
+ describe 'application not found' do
53
+ before do
54
+ do_request({token: 'test_token', app_key: 'another_key'})
55
+ end
56
+ it 'Raises a not found (404) error when the key doesn\'t belong to any application' do
57
+ expect(last_response.status).to be 404
58
+ end
59
+ it 'returns the correct body when the application doesn\'t exist' do
60
+ expect(JSON.parse(last_response.body)).to eq({
61
+ 'status' => 404,
62
+ 'field' => 'app_key',
63
+ 'error' => 'unknown',
64
+ 'docs' => 'https://github.com/jdr-tools/wiki/wiki/Common-errors#application-key-not-found'
65
+ })
66
+ end
67
+ end
68
+ describe 'gateway not found' do
69
+ before do
70
+ do_request({token: 'other_token', app_key: 'test_key'})
71
+ end
72
+ it 'Raises a not found (404) error when the gateway does\'nt exist' do
73
+ expect(last_response.status).to be 404
74
+ end
75
+ it 'returns the correct body when the gateway doesn\'t exist' do
76
+ expect(JSON.parse(last_response.body)).to eq({
77
+ 'status' => 404,
78
+ 'field' => 'token',
79
+ 'error' => 'unknown',
80
+ 'docs' => 'https://github.com/jdr-tools/wiki/wiki/Common-errors#gateway-token-not-found'
81
+ })
82
+ end
83
+ end
84
+ end
85
+ end
86
+ end
87
+ end
88
+ end
89
+ end
@@ -0,0 +1,10 @@
1
+ module Virtuaservices
2
+ # Utility classes for the different micro-services of the suite.
3
+ # @author Vincent Courtois <courtois.vincent@outlook.com>
4
+ module Utils
5
+ autoload :Controllers , 'virtuaservices/utils/controllers'
6
+ autoload :Errors , 'virtuaservices/utils/errors'
7
+ autoload :Loaders , 'virtuaservices/utils/loaders'
8
+ autoload :MicroService, 'virtuaservices/utils/micro_service'
9
+ end
10
+ end
@@ -0,0 +1,8 @@
1
+ module Arkaan
2
+ module Utils
3
+ module Controllers
4
+ autoload :Base , 'arkaan/utils/controllers/base'
5
+ autoload :Checked, 'arkaan/utils/controllers/checked'
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,193 @@
1
+ module Arkaan
2
+ module Utils
3
+ module Controllers
4
+ # Base controller to handle the standard error when accessing the API.
5
+ # @author Vincent Courtois <courtois.vincenet@outlook.com>
6
+ class Base < Sinatra::Base
7
+ register Sinatra::ConfigFile
8
+ helpers Sinatra::CustomLogger
9
+
10
+ configure do
11
+ set :logger, Logger.new(STDOUT)
12
+ logger.level = Logger::ERROR if ENV['RACK_ENV'] == 'test'
13
+ end
14
+
15
+ # Creates a premium route whithin the Sinatra application, and registers it in the database if it does not already exists.
16
+ # @param verb [String] the HTTP method used to create this route.
17
+ # @param path [String] the path, beginning with a /, of the route to create.
18
+ def self.declare_route(verb, path, options: {}, &block)
19
+ self.declare_route_with(verb, path, false, options, &block)
20
+ end
21
+
22
+ # Creates a non premium route whithin the Sinatra application, and registers it in the database if it does not already exists.
23
+ # @param verb [String] the HTTP method used to create this route.
24
+ # @param path [String] the path, beginning with a /, of the route to create.
25
+ def self.declare_premium_route(verb, path, options: {}, &block)
26
+ self.declare_route_with(verb, path, true, options, &block)
27
+ end
28
+
29
+ # Creates a route whithin the Sinatra application, and registers it in the database if it does not already exists.
30
+ # @param verb [String] the HTTP method used to create this route.
31
+ # @param path [String] the path, beginning with a /, of the route to create.
32
+ # @param premium [Boolean] TRUE to make the route premium, FALSE otherwise.
33
+ def self.declare_route_with(verb, path, premium, options, &block)
34
+ service = Arkaan::Utils::MicroService.instance.service
35
+ complete_path = "#{Arkaan::Utils::MicroService.instance.path}#{path == '/' ? '' : path}"
36
+
37
+ unless service.nil? || !service.routes.where(path: path, verb: verb).first.nil?
38
+ route = Arkaan::Monitoring::Route.create(path: path, verb: verb, premium: premium, service: service)
39
+ if !options.nil? && !options[:authenticated].nil?
40
+ route.update_attribute(:authenticated, false)
41
+ end
42
+ Arkaan::Permissions::Group.where(is_superuser: true).each do |group|
43
+ group.routes << route
44
+ group.save!
45
+ end
46
+ end
47
+ if premium
48
+ self.public_send(verb, complete_path) do
49
+ @sinatra_route = parse_current_route
50
+ if !@application.premium?
51
+ custom_error(403, 'common.app_key.forbidden')
52
+ end
53
+ instance_eval(&block)
54
+ end
55
+ else
56
+ logger.info "#{verb} #{complete_path}"
57
+ self.public_send(verb, complete_path, &block)
58
+ end
59
+ end
60
+
61
+ # Loads the errors configuration file from the config folder.
62
+ # @param file [String] send __FILE__
63
+ def self.load_errors_from(file)
64
+ config_file File.join(File.dirname(file), '..', 'config', 'errors.yml')
65
+ end
66
+
67
+ def before_checks
68
+ add_body_to_params
69
+
70
+ check_presence('token', 'app_key', route: 'common')
71
+
72
+ gateway = Arkaan::Monitoring::Gateway.where(token: params['token']).first
73
+ @application = Arkaan::OAuth::Application.where(key: params['app_key']).first
74
+
75
+ if gateway.nil?
76
+ custom_error(404, 'common.token.unknown')
77
+ elsif @application.nil?
78
+ custom_error(404, 'common.app_key.unknown')
79
+ end
80
+ end
81
+
82
+ # Checks the presence of several fields given as parameters and halts the execution if it's not present.
83
+ # @param fields [Array<String>] an array of fields names to search in the parameters
84
+ # @param route [String] the name of the route you're requiring to put in the error message.
85
+ def check_presence(*fields, route:)
86
+ fields.each do |field|
87
+ custom_error(400, "#{route}.#{field}.required") if params[field].nil? || params[field] == ''
88
+ end
89
+ end
90
+
91
+ # Checks the presence of either fields given in parameters. It halts with an error only if ALL parameters are not given.
92
+ # @param fields [Array<String>] an array of fields names to search in the parameters
93
+ # @param route [String] the name of the route you're requiring to put in the error message.
94
+ # @param key [String] the key to search in the errors configuration file.
95
+ def check_either_presence(*fields, route:, key:)
96
+ fields.each do |field|
97
+ return true if !params[field].nil? && params[field] != ''
98
+ end
99
+ custom_error 400, "#{route}.#{key}.required"
100
+ end
101
+
102
+ # Checks if the session ID is given in the parameters and if the session exists.
103
+ # @param action [String] the action used to get the errors from the errors file.
104
+ # @return [Arkaan::Authentication::Session] the session when it exists.
105
+ def check_session(action)
106
+ check_presence('session_id', route: action)
107
+ session = Arkaan::Authentication::Session.where(token: params['session_id']).first
108
+ if session.nil?
109
+ custom_error(404, "#{action}.session_id.unknown")
110
+ end
111
+ return session
112
+ end
113
+
114
+ def check_application(action)
115
+ check_presence('app_key', route: action)
116
+ application = Arkaan::OAuth::Application.where(key: params['app_key']).first
117
+ custom_error(404, "#{action}.app_key.unknown") if application.nil?
118
+ return application
119
+ end
120
+
121
+ # Adds the parsed body to the parameters, overwriting the parameters of the querystring with the values
122
+ # of the SON body if they have similar keys.
123
+ def add_body_to_params
124
+ if request.body.respond_to?(:rewind) && request.body.respond_to?(:read)
125
+ request.body.rewind
126
+ parsed_body = JSON.parse(request.body.read.to_s) rescue {}
127
+ parsed_body.keys.each do |key|
128
+ params[key] = parsed_body[key]
129
+ end
130
+ end
131
+ end
132
+
133
+ # Gets the current route in the database from the sinatra route.
134
+ # @return [Arkaan::Monitoring::Route] the route declared in the services registry.
135
+ def parse_current_route
136
+ splitted = request.env['sinatra.route'].split(' ')
137
+ return Arkaan::Monitoring::Route.where(verb: splitted.first.downcase, path: splitted.last).first
138
+ end
139
+
140
+ # Halts the application and creates the returned body from the parameters and the errors config file.
141
+ # @param status [Integer] the HTTP status to halt the application with.
142
+ # @param path [String] the path in the configuration file to access the URL.
143
+ def custom_error(status, path)
144
+ route, field, error = path.split('.')
145
+ docs = settings.errors[route][field][error] rescue ''
146
+ halt status, {status: status, field: field, error: error, docs: docs}.to_json
147
+ end
148
+
149
+ # Halts the application with a Bad Request error affecting a field of a model.
150
+ # @param instance [Mongoid::Document] the document having a field in error.
151
+ # @param route [String] the type of action you're currently doing (e.g: 'creation')
152
+ def model_error(instance, route)
153
+ messages = instance.errors.messages
154
+ field = messages.keys.first
155
+ custom_error(400, "#{route}.#{field}.#{messages[field].first}")
156
+ end
157
+
158
+ # Select parameters in the params hash, by its keys.
159
+ # @param fields [Array<String>] the keys to select in the params hash.
160
+ # @return [Hash] the selected chunk of the params hash.
161
+ def select_params(*fields)
162
+ return params.select { |key, value| fields.include?(key) }
163
+ end
164
+
165
+ # Creates a custom error from an existing Arkaan exception class.
166
+ # @param exception {StandardError} the exception to transform in a usable error.
167
+ def handle_arkaan_exception(exception)
168
+ custom_error(exception.status, "#{exception.action}.#{exception.field}.#{exception.error}")
169
+ end
170
+
171
+ error Arkaan::Utils::Errors::BadRequest do |exception|
172
+ handle_arkaan_exception(exception)
173
+ end
174
+
175
+ error Arkaan::Utils::Errors::Forbidden do |exception|
176
+ handle_arkaan_exception(exception)
177
+ end
178
+
179
+ error Arkaan::Utils::Errors::NotFound do |exception|
180
+ handle_arkaan_exception(exception)
181
+ end
182
+
183
+ error Arkaan::Factories::Errors::GatewayNotFound do |exception|
184
+ handle_arkaan_exception(exception)
185
+ end
186
+
187
+ error StandardError do |exception|
188
+ custom_error(500, 'system_error.unknown_field.unknown_error')
189
+ end
190
+ end
191
+ end
192
+ end
193
+ end