virtuatable-core 1.0.0 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (35) hide show
  1. checksums.yaml +4 -4
  2. data/lib/core/controllers/base.rb +65 -0
  3. data/lib/core/controllers.rb +9 -0
  4. data/lib/core/helpers/accounts.rb +22 -0
  5. data/lib/core/helpers/applications.rb +26 -0
  6. data/lib/core/helpers/declarators.rb +83 -0
  7. data/lib/core/helpers/errors/bad_request.rb +15 -0
  8. data/lib/core/helpers/errors/base.rb +36 -0
  9. data/lib/core/helpers/errors/forbidden.rb +15 -0
  10. data/lib/core/helpers/errors/not_found.rb +15 -0
  11. data/lib/core/helpers/errors.rb +48 -0
  12. data/lib/core/helpers/fields.rb +35 -0
  13. data/lib/core/helpers/parameters.rb +25 -0
  14. data/lib/core/helpers/responses.rb +50 -0
  15. data/lib/core/helpers/routes.rb +21 -0
  16. data/lib/core/helpers/sessions.rb +30 -0
  17. data/lib/core/helpers.rb +18 -0
  18. data/lib/core/models/account.rb +0 -3
  19. data/lib/core/models/concerns.rb +0 -1
  20. data/lib/core/models/permissions/group.rb +1 -1
  21. data/lib/core/models/{monitoring → permissions}/route.rb +4 -15
  22. data/lib/core/models/permissions.rb +1 -0
  23. data/lib/core/models.rb +0 -3
  24. data/lib/core/version.rb +1 -1
  25. data/lib/core.rb +2 -0
  26. metadata +75 -40
  27. data/lib/core/models/concerns/diagnosticable.rb +0 -24
  28. data/lib/core/models/decorators/errors/env_variable_missing.rb +0 -16
  29. data/lib/core/models/decorators/errors.rb +0 -11
  30. data/lib/core/models/decorators/gateway.rb +0 -111
  31. data/lib/core/models/factories/errors/gateway_not_found.rb +0 -16
  32. data/lib/core/models/factories/errors.rb +0 -11
  33. data/lib/core/models/factories.rb +0 -10
  34. data/lib/core/models/monitoring/service.rb +0 -33
  35. data/lib/core/models/monitoring.rb +0 -10
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: eaef58986378462da6ff78e3aeac595cbed418f3351254e3e99b303059fe21d1
4
- data.tar.gz: 1ed97f4ff856ecfbe5ccf969547ee0141f03f1e9c59304661880f6d4e87bfaf7
3
+ metadata.gz: 9afbc1d8f75f5d0b94194432b3a379a7b02d90d2490deeed47d46d9c89036b01
4
+ data.tar.gz: 56cfd05e3f53df001a852d26b6abf992313d52598902ecb21809cd16708ae266
5
5
  SHA512:
6
- metadata.gz: ffc760f437db7e376de09c5e88fa794e440729600819f8cce7474d4db6a122185fc20472020e131ae889d6371f1cf95f0fb7389506ac4ec1f5a9840a3ed2dc98
7
- data.tar.gz: '08addb4e9612082536359a2a624f5eded215ba382a8f9b16aebf016cfc35b9c9dbc12a503a3160780dc81896bdabf0434f1966062d5eb339e999eadef92cbec1'
6
+ metadata.gz: 7f4fdde3ecd17bb2b33a535ce22c927783ab5d88c00f639ee9374fcc7b36c6680ed0e2f1ce50071a22e1c4784d453c1b74b0bc71d5b817bd72e0501faf637611
7
+ data.tar.gz: 7622404c051938c9cee8567de61f25005e7f178ae4a7dd22146d279aa8413a52c92c25c36db2472a59588c2f0a10db22322d4f0ff8348fc3609124798bcd4587
@@ -0,0 +1,65 @@
1
+ # frozen_string_literal: true
2
+ require 'sinatra/config_file'
3
+ require 'sinatra/custom_logger'
4
+
5
+ module Core
6
+ module Controllers
7
+ # This class represents a base controller for the system, giving access
8
+ # to checking methods for sessions, gateways, applications, etc.
9
+ # @author Vincent Courtois <courtois.vincent@outlook.com>
10
+ class Base < Sinatra::Base
11
+ register Sinatra::ConfigFile
12
+ helpers Sinatra::CustomLogger
13
+ # Includes the custom errors throwers and responses helpers.
14
+ include Core::Helpers::Errors
15
+ include Core::Helpers::Responses
16
+ # Includes the checking methods for sessions.
17
+ include Core::Helpers::Sessions
18
+ # Include the checkers and getters for OAuth apps
19
+ include Core::Helpers::Applications
20
+ # Include checkers for field requirement and check
21
+ include Core::Helpers::Fields
22
+ # Include the getter for the currently requested route.
23
+ include Core::Helpers::Routes
24
+ # Include the getter and checkers for accounts.
25
+ include Core::Helpers::Accounts
26
+ # Include the loading of the parameters from the JSON body
27
+ include Core::Helpers::Parameters
28
+ # This module is extended, not included, because it provides routes
29
+ # declaration methods used in class declarations.
30
+ extend Core::Helpers::Declarators
31
+
32
+ configure do
33
+ set :logger, Logger.new(STDOUT)
34
+ logger.level = Logger::ERROR if ENV['RACK_ENV'] == 'test'
35
+ # This configuration options allow the error handler to work in tests.
36
+ set :show_exceptions, false
37
+ set :raise_errors, false
38
+ end
39
+
40
+ error Mongoid::Errors::Validations do |errors|
41
+ key = errors.document.errors.messages.keys.first
42
+ message = errors.document.errors.messages[key][0]
43
+ api_bad_request key, message: message
44
+ end
45
+
46
+ error Core::Helpers::Errors::NotFound do |exception|
47
+ api_not_found exception.message
48
+ end
49
+
50
+ error Core::Helpers::Errors::BadRequest do |exception|
51
+ api_bad_request exception.message
52
+ end
53
+
54
+ error Core::Helpers::Errors::Forbidden do |exception|
55
+ api_forbidden exception.message
56
+ end
57
+
58
+ if ENV['RACK_ENV'] != 'test'
59
+ error StandardError do |error|
60
+ api_error 500, "unknown_field.#{error.class.name}"
61
+ end
62
+ end
63
+ end
64
+ end
65
+ end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Core
4
+ # Controllers are to be subclassed in each service.
5
+ # @author Vincent Courtois <courtois.vincent@outlook.com>
6
+ module Controllers
7
+ autoload :Base, 'core/controllers/base'
8
+ end
9
+ end
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Core
4
+ module Helpers
5
+ # These helpers provide methods used to get and check accounts.
6
+ # @author Vincent Courtois <courtois.vincent@outlook.com>
7
+ module Accounts
8
+ # Raises a bad request error if the account if not found.
9
+ # @raise [Virtuatable::API::Errors::BadRequest] the error raised when the account is not found.
10
+ def account
11
+ return @account unless @account.nil?
12
+
13
+ session_id_required if !respond_to?(:session) || session.nil?
14
+ @account = session.account
15
+ end
16
+
17
+ def account_id_not_found
18
+ api_bad_request('session_id.required')
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Core
4
+ module Helpers
5
+ # Helpers to get and check OAuth applications connecting the the application.
6
+ # @author Vincent Courtois <courtois.vincent@outlook.com>
7
+ module Applications
8
+ # Looks for the application sending the API's request, and raises error if not found.
9
+ # @param [Arkaan::OAuth::Application] the application requesting the service.
10
+ def application(premium: false)
11
+ return @application unless @application.nil?
12
+
13
+ check_presence 'app_key'
14
+ @application = application_model.find_by(key: params['app_key'])
15
+ api_not_found 'app_key.unknown' if @application.nil?
16
+ api_forbidden 'app_key.forbidden' if premium && !@application.premium
17
+
18
+ @application
19
+ end
20
+
21
+ def application_model
22
+ Arkaan::OAuth::Application
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,83 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Core
4
+ module Helpers
5
+ # This helpers module is a bit larger than the others as it provides methods
6
+ # to declare routes whithin a service, performing needed checks and filters.
7
+ # @author Vincent Courtois <courtois.vincent@outlook.com>
8
+ module Declarators
9
+ # @!attribute [r] routes
10
+ # @return [Array<Arkaan::Monitoring::Route>] the currently declared routes.
11
+ attr_reader :api_routes
12
+
13
+ # Main method to declare new routes, persisting them in the database and
14
+ # declaring it in the Sinatra application with the needed before checks.
15
+ #
16
+ # @param verb [String] the HTTP method for the route.
17
+ # @param path [String] the whole URI with parameters for the route.
18
+ # @param options [Hash] the additional options for the route.
19
+ def api_route(verb, path, options: {}, &block)
20
+ options = default_options.merge(options)
21
+ route = add_route(verb: verb, path: path, options: options)
22
+
23
+ # TODO : do everything in the #send itself to avoid
24
+ # route reload issues when premium is changed. It will
25
+ # add some treatments but avoid many problems if route.premium
26
+ send(route.verb, route.path) do
27
+ application(premium: current_route.premium)
28
+ session if current_route.authenticated
29
+ instance_eval(&block)
30
+ end
31
+ end
32
+
33
+ # Add a route to the database, then to the routes array.
34
+ # @param verb [String] the HTTP method used to request this route.
35
+ # @param path [String] the path used to request this route.
36
+ # @return [Arkaan::Monitoring::Route] the created route.
37
+ def add_route(verb:, path:, options:)
38
+ route = Arkaan::Monitoring::Route.find_or_create_by!(
39
+ path: path,
40
+ verb: verb.downcase,
41
+ premium: options[:premium],
42
+ authenticated: options[:authenticated]
43
+ )
44
+ api_routes.nil? ? @api_routes = [route] : push_route(route)
45
+ add_permissions(route)
46
+ route
47
+ end
48
+
49
+ # Pushes the route in the api routes list, by creating it if needed
50
+ # @param route [Arkaan::Monitoring::Route] the route to push in the list of routes.
51
+ def push_route(route)
52
+ @api_routes << route if api_routes.none? do |tmp_route|
53
+ route.id == tmp_route.id
54
+ end
55
+ end
56
+
57
+ # Add the default access permissions to a route. Any group tagged superuser
58
+ # can automatically access any newly declared_route.
59
+ # params route [Arkaan::Monitoring::Route] the route to add the permissions to.
60
+ def add_permissions(route)
61
+ groups = Arkaan::Permissions::Group.where(is_superuser: true)
62
+ groups.each do |group|
63
+ unless route.groups.where(id: group.id).exists?
64
+ route.groups << group
65
+ route.save!
66
+ end
67
+ end
68
+ end
69
+
70
+ # The default options for a route, being the most used value for each key.
71
+ # @return [Hash] the default options as a hash.
72
+ def default_options
73
+ {
74
+ # If TRUE the application MUST be premium to access the route.
75
+ # Mainly used to protect administration routes against illegal accesses.
76
+ premium: false,
77
+ # If TRUE the user MUST be authenticated to access the route.
78
+ authenticated: true
79
+ }
80
+ end
81
+ end
82
+ end
83
+ end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Core
4
+ module Helpers
5
+ module Errors
6
+ # A bad request error is raised when the data given to a model makes this model invalid.
7
+ # @author Vincent Courtois <courtois.vincent@outlook.com>
8
+ class BadRequest < Core::Helpers::Errors::Base
9
+ def initialize(field:, error:)
10
+ super(field: field, error: error, status: 400)
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,36 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Core
4
+ module Helpers
5
+ module Errors
6
+ # Standard class parent to all specialized http errors.
7
+ # @author Vincent Courtois <courtois.vincent@outlook.com>
8
+ class Base < StandardError
9
+ # @!attribute [rw] field
10
+ # @return [String, Symbol] the name of the field in error in the model.
11
+ attr_accessor :field
12
+ # @!attribute [rw] action
13
+ # @return [String] the name of the action the user was trying to perform on the model (often crate or update).
14
+ attr_accessor :action
15
+ # @attribute [rw] error
16
+ # @return [String] the label of the error returned by the model.
17
+ attr_accessor :error
18
+ # @attribute [rw] status
19
+ # @return [Integer] the HTTP status code as a number (eg: 400, 422 or 500)
20
+ attr_accessor :status
21
+
22
+ def initialize(field:, error:, status:)
23
+ @field = field.to_s
24
+ @error = error
25
+ @status = status
26
+ end
27
+
28
+ # Returns the formatted message for this exception.
29
+ # @return [String] a message indicating what field fails, and why.
30
+ def message
31
+ "#{field}.#{error}"
32
+ end
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Core
4
+ module Helpers
5
+ module Errors
6
+ # A forbidden error occurs when a user tries to perform an action he's not allowed to.
7
+ # @author Vincent Courtois <courtois.vincent@outlook.com>
8
+ class Forbidden < Core::Helpers::Errors::Base
9
+ def initialize(field:, error:)
10
+ super(field: field, error: error, status: 403)
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Core
4
+ module Helpers
5
+ module Errors
6
+ # A not found error occurs when a user tries to reach a resource that does not exist.
7
+ # @author Vincent Courtois <courtois.vincent@outlook.com>
8
+ class NotFound < Core::Helpers::Errors::Base
9
+ def initialize(field:, error:)
10
+ super(field: field, error: error, status: 404)
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,48 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Core
4
+ module Helpers
5
+ # This module defines method to raise HTTP errors in the routes easily.
6
+ # @author Vincent Courtois <courtois.vincent@outlook.com>
7
+ module Errors
8
+ autoload :Base, 'core/helpers/errors/base'
9
+ autoload :BadRequest, 'core/helpers/errors/bad_request'
10
+ autoload :Forbidden, 'core/helpers/errors/forbidden'
11
+ autoload :NotFound, 'core/helpers/errors/not_found'
12
+
13
+ # Stops the executing and raises an HTTP error in the route.
14
+ # The message MUST be of the for <field>.<error> to be correctly parsed.
15
+ # The action is automatically parsed from the route call and added.
16
+ #
17
+ # @param status [Integer] the HTTP status code the response will have
18
+ # @param message [String] the raw message to split and format as body.
19
+ def api_error(status, message)
20
+ field, error = message.split('.')
21
+ docs = settings.errors.try(field).try(error)
22
+ errors = { status: status, field: field, error: error, docs: docs }
23
+ halt status, errors.to_json
24
+ end
25
+
26
+ # Stops the execution to return a NOT FOUND response.
27
+ # @param field [String] the field in params concerned by the error.
28
+ # @param message [String] the message if different of "unknown".
29
+ def api_not_found(field, message: 'unknown')
30
+ api_error 404, "#{field}.#{message}"
31
+ end
32
+
33
+ # Stops the execution to return a BAD REQUEST response.
34
+ # @param field [String] the field in params concerned by the error.
35
+ # @param message [String] the message if different of "required".
36
+ def api_bad_request(field, message: 'required')
37
+ api_error 400, "#{field}.#{message}"
38
+ end
39
+
40
+ # Stops the execution to return a FORBIDDEN response.
41
+ # @param field [String] the field in params concerned by the error.
42
+ # @param message [String] the message if different of "forbidden".
43
+ def api_forbidden(field, message: 'forbidden')
44
+ api_error 403, "#{field}.#{message}"
45
+ end
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,35 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Core
4
+ module Helpers
5
+ # Helpers for the parameters of a request.
6
+ # @author Vincent Courtois <courtois.vincent@outlook.com>
7
+ module Fields
8
+ # Checks the presence of several fields given as parameters and halts the execution if it's not present.
9
+ # @param fields [Array<String>] an array of fields names to search in the parameters
10
+ def check_presence(*fields)
11
+ fields.each do |field|
12
+ api_bad_request "#{field}.required" unless field_defined?(field)
13
+ end
14
+ end
15
+
16
+ # Checks the presence of either fields given in parameters.
17
+ # It halts with an error only if ALL parameters are not given.
18
+ #
19
+ # @param fields [Array<String>] an array of fields names to search in the parameters
20
+ # @param key [String] the key to search in the errors configuration file.
21
+ def check_either_presence(*fields, key:)
22
+ api_bad_request "#{key}.required" if fields.none? do |field|
23
+ field_defined?(field)
24
+ end
25
+ end
26
+
27
+ # Checks if a given field is defined in the params
28
+ # @param field [String] the name of the field to check in the params
29
+ # @return [Boolean] TRUE if the field exists, FALSE otherwise.
30
+ def field_defined?(field)
31
+ !params.nil? && params.key?(field) && params[field] != ''
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Core
4
+ module Helpers
5
+ # Helpers to correctly build the parameters hash, even from the JSON body.
6
+ # @author Vincent Courtois <courtois.vincent@outlook.com>
7
+ module Parameters
8
+ # Returns the parameters depending on whether the request has a body
9
+ # or not. If it has a body, it parses it, otherwise it just returns the params.
10
+ # @return [Hash] the parameters sent with the request.
11
+ def params
12
+ super.merge(body_params)
13
+ end
14
+
15
+ # The parameters from the JSON body if it is sent.
16
+ # @return [Hash] the JSON body parsed as a dictionary.
17
+ def body_params
18
+ request.body.rewind
19
+ JSON.parse(request.body.read.to_s)
20
+ rescue JSON::ParserError
21
+ {}
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,50 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Core
4
+ module Helpers
5
+ # Modules holding the responses that are NOT errors.
6
+ # @author Vincent Courtois <courtois.vincent@outlook.com>
7
+ module Responses
8
+ # Builds a list of items as a standard API response.
9
+ # The response will be a JSON hash containing two keys :
10
+ # - :count will hold the number of items displayed in the list
11
+ # - :items will hold the list of items.
12
+ # @param items [Array] the items to format as a standard API response.
13
+ def api_list(items)
14
+ halt 200, {
15
+ count: items.count,
16
+ items: items.map { |item| enhanced_h(item) }
17
+ }.to_json
18
+ end
19
+
20
+ # Displays a creation standard response,
21
+ # returning the informations about the created item.
22
+ # @param item [Object] any object that responds to #to_h to display to the user.
23
+ def api_created(item)
24
+ halt 201, enhanced_json(item)
25
+ end
26
+
27
+ # Displays an item with the standards of the API.
28
+ # @param item [Object] the item to display as a JSON formatted hash.
29
+ def api_item(item)
30
+ halt 200, enhanced_json(item)
31
+ end
32
+
33
+ # Displays a message with a 200 status code
34
+ # @param message [String] the message to display with the API standards.
35
+ def api_ok(message)
36
+ api_item message: message
37
+ end
38
+
39
+ private
40
+
41
+ def enhanced_h(item)
42
+ (item.respond_to?(:enhance) ? item.enhance : item).to_h
43
+ end
44
+
45
+ def enhanced_json(item)
46
+ enhanced_h(item).to_json
47
+ end
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Core
4
+ module Helpers
5
+ # This module provides the #current_route method to get the current
6
+ # Arkaan::Monitoring::Route object from whithin sinatra routes.
7
+ # @author Vincent Courtois <courtois.vincent@outlook.com>
8
+ module Routes
9
+ # The currently requested API route, used to see inside the block
10
+ # if the route is premium or not, authenticated or not.
11
+ # @return [Arkaan::Monitoring::Route] the currently requested route.
12
+ def current_route
13
+ splitted = request.env['sinatra.route'].split(' ')
14
+ verb = splitted.first.downcase
15
+ self.class.api_routes.find do |route|
16
+ route.verb == verb && route.path == splitted.last
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Core
4
+ module Helpers
5
+ # This helper gives access to methods about user's session on the API.
6
+ # @author Vincent Courtois <courtois.vincent@outlook.com>
7
+ module Sessions
8
+ # Checks the session of the user requesting the API and returns an error
9
+ # if it either not exists with the given token, or the token is not given.
10
+ #
11
+ # @raise [Virtuatable::API::Errors::NotFound] if the session is not found
12
+ # or the token not given in the parameters of the request.
13
+ # @raise [Virtuatable::API::Errors::BadRequest] if the session token is
14
+ # not correctly given in the parameters.
15
+ #
16
+ # @return [Arkaan::Authentication::Session] the current session of the user.
17
+ def session
18
+ return @session unless @session.nil?
19
+
20
+ check_presence 'session_id'
21
+ @session = session_model.find_by(token: params['session_id'])
22
+ @session.nil? ? api_not_found('session_id.unknown') : @session
23
+ end
24
+
25
+ def session_model
26
+ Arkaan::Authentication::Session
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Core
4
+ # The helpers are used inside the controllers to dynamically
5
+ # add features and functions.
6
+ # @author Vincent Courtois <courtois.vincent@outlook.com>
7
+ module Helpers
8
+ autoload :Accounts, 'core/helpers/accounts'
9
+ autoload :Applications, 'core/helpers/applications'
10
+ autoload :Declarators, 'core/helpers/declarators'
11
+ autoload :Errors, 'core/helpers/errors'
12
+ autoload :Fields, 'core/helpers/fields'
13
+ autoload :Parameters, 'core/helpers/parameters'
14
+ autoload :Responses, 'core/helpers/responses'
15
+ autoload :Routes, 'core/helpers/routes'
16
+ autoload :Sessions, 'core/helpers/sessions'
17
+ end
18
+ end
@@ -46,9 +46,6 @@ module Core
46
46
  # @!attribute [rw] authorizations
47
47
  # @return [Array<Core::Models::OAuth::Authorization>] the authorization issued by this account to third-party applications to access its data.
48
48
  has_many :authorizations, class_name: 'Core::Models::OAuth::Authorization', inverse_of: :account
49
- # @!attribute [rw] services
50
- # @return [Array<Core::Models::Monitoring::Service>] the services created by this user.
51
- has_many :services, class_name: 'Core::Models::Monitoring::Service', inverse_of: :creator
52
49
  # @!attribute [rw] sessions
53
50
  # @return [Array<Core::Models::Authentication::Session>] the sessions on which this account is, or has been logged in.
54
51
  has_many :sessions, class_name: 'Core::Models::Authentication::Session', inverse_of: :account
@@ -4,7 +4,6 @@ module Core
4
4
  # @author Vincent Courtois <courtois.vincent@outlook.com>
5
5
  module Concerns
6
6
  autoload :Activable , 'core/models/concerns/activable'
7
- autoload :Diagnosticable, 'core/models/concerns/diagnosticable'
8
7
  autoload :Enumerable , 'core/models/concerns/enumerable'
9
8
  autoload :Historizable , 'core/models/concerns/historizable'
10
9
  autoload :MimeTypable , 'core/models/concerns/mime_typable'
@@ -23,7 +23,7 @@ module Core
23
23
  has_and_belongs_to_many :rights, class_name: 'Core::Models::Permissions::Right', inverse_of: :groups
24
24
  # @!attribute [rw] routes
25
25
  # @return [Array<Core::Models::Monitoring::Route>] the routes this group can access in the API.
26
- has_and_belongs_to_many :routes, class_name: 'Core::Models::Monitoring::Route', inverse_of: :groups
26
+ has_and_belongs_to_many :routes, class_name: 'Core::Models::Permissions::Route', inverse_of: :groups
27
27
 
28
28
  make_sluggable 'group'
29
29
  end
@@ -1,7 +1,7 @@
1
1
  module Core
2
2
  module Models
3
- module Monitoring
4
- # A route is an endpoint accessible in a service. Each route has to have an associated endpoint in the deployed instances.
3
+ module Permissions
4
+ # A route is an endpoint accessible in the API. Each route has to have an associated endpoint in the deployed instances.
5
5
  # @param Vincent Courtois <courtois.vincent@outlook.com>
6
6
  class Route
7
7
  include Mongoid::Document
@@ -10,19 +10,14 @@ module Core
10
10
  include Core::Models::Concerns::Activable
11
11
 
12
12
  # @!attribute [rw] path
13
- # @return [String] the path (URI) of the route in the service?
13
+ # @return [String] the path (URI) of the route in the API.
14
14
  field :path, type: String, default: '/'
15
15
  # @!attribute [rw] verb
16
- # @return [String] the verb (HTTP method) of this route in the service.
16
+ # @return [String] the verb (HTTP method) of this route in the API.
17
17
  field :verb, type: String, default: 'get'
18
18
  # @!attribute [rw] authenticated
19
19
  # @return [Boolean] if true, the session_id is needed for this route, if false it is not.
20
20
  field :authenticated, type: Boolean, default: true
21
-
22
- # @!attribute [rw] service
23
- # @return [Core::Models::Monitoring::Service] the service in which this route is declared.
24
- belongs_to :service, class_name: 'Core::Models::Monitoring::Service', inverse_of: :routes
25
-
26
21
  # @!attribute [rw] groups
27
22
  # @return [Array<Core::Models::Permissions::Group>] the groups having permission to access this route.
28
23
  has_and_belongs_to_many :groups, class_name: 'Core::Models::Permissions::Group', inverse_of: :groups
@@ -32,12 +27,6 @@ module Core
32
27
 
33
28
  validates :verb,
34
29
  inclusion: {message: 'unknown', in: ['get', 'post', 'put', 'delete', 'patch', 'option']}
35
-
36
- # Returns the complete path, enriched with the path of the service.
37
- # @return [String] the complete path to access this route from the outside.
38
- def complete_path
39
- path == '/' ? service.path : "#{service.path}#{path}"
40
- end
41
30
  end
42
31
  end
43
32
  end
@@ -7,6 +7,7 @@ module Core
7
7
  autoload :Right , 'core/models/permissions/right'
8
8
  autoload :Group , 'core/models/permissions/group'
9
9
  autoload :Category, 'core/models/permissions/category'
10
+ autoload :Route , 'core/models/permissions/route'
10
11
  end
11
12
  end
12
13
  end
data/lib/core/models.rb CHANGED
@@ -15,13 +15,10 @@ module Core
15
15
  autoload :Chatrooms , 'core/models/chatrooms'
16
16
  autoload :Concerns , 'core/models/concerns'
17
17
  autoload :Event , 'core/models/event'
18
- autoload :Factories , 'core/models/factories'
19
18
  autoload :Files , 'core/models/files'
20
- autoload :Monitoring , 'core/models/monitoring'
21
19
  autoload :Notification , 'core/models/notification'
22
20
  autoload :OAuth , 'core/models/oauth'
23
21
  autoload :Permissions , 'core/models/permissions'
24
- autoload :Phone , 'core/models/phone'
25
22
  autoload :Ruleset , 'core/models/ruleset'
26
23
  end
27
24
  end
data/lib/core/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Core
2
- VERSION = '1.0.0'
2
+ VERSION = '1.1.0'
3
3
  end
data/lib/core.rb CHANGED
@@ -6,5 +6,7 @@ require 'dotenv/load'
6
6
  # Main module of the application, holding all the subsequent classes.
7
7
  # @author Vincent Courtois <courtois.vincent@outlook.com>
8
8
  module Core
9
+ autoload :Controllers, 'core/controllers'
10
+ autoload :Helpers, 'core/helpers'
9
11
  autoload :Models, 'core/models'
10
12
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: virtuatable-core
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0
4
+ version: 1.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Vincent Courtois
@@ -30,28 +30,14 @@ dependencies:
30
30
  requirements:
31
31
  - - '='
32
32
  - !ruby/object:Gem::Version
33
- version: 6.1.0
33
+ version: 6.2.1
34
34
  type: :development
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
38
  - - '='
39
39
  - !ruby/object:Gem::Version
40
- version: 6.1.0
41
- - !ruby/object:Gem::Dependency
42
- name: factory_girl
43
- requirement: !ruby/object:Gem::Requirement
44
- requirements:
45
- - - '='
46
- - !ruby/object:Gem::Version
47
- version: 4.8.1
48
- type: :development
49
- prerelease: false
50
- version_requirements: !ruby/object:Gem::Requirement
51
- requirements:
52
- - - '='
53
- - !ruby/object:Gem::Version
54
- version: 4.8.1
40
+ version: 6.2.1
55
41
  - !ruby/object:Gem::Dependency
56
42
  name: faker
57
43
  requirement: !ruby/object:Gem::Requirement
@@ -108,6 +94,20 @@ dependencies:
108
94
  - - '='
109
95
  - !ruby/object:Gem::Version
110
96
  version: 1.1.0
97
+ - !ruby/object:Gem::Dependency
98
+ name: require_all
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - '='
102
+ - !ruby/object:Gem::Version
103
+ version: 3.0.0
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - '='
109
+ - !ruby/object:Gem::Version
110
+ version: 3.0.0
111
111
  - !ruby/object:Gem::Dependency
112
112
  name: rspec
113
113
  requirement: !ruby/object:Gem::Requirement
@@ -179,21 +179,21 @@ dependencies:
179
179
  - !ruby/object:Gem::Version
180
180
  version: 0.9.25
181
181
  - !ruby/object:Gem::Dependency
182
- name: mongoid
182
+ name: activemodel
183
183
  requirement: !ruby/object:Gem::Requirement
184
184
  requirements:
185
185
  - - '='
186
186
  - !ruby/object:Gem::Version
187
- version: 7.1.0
187
+ version: 6.0.3.2
188
188
  type: :runtime
189
189
  prerelease: false
190
190
  version_requirements: !ruby/object:Gem::Requirement
191
191
  requirements:
192
192
  - - '='
193
193
  - !ruby/object:Gem::Version
194
- version: 7.1.0
194
+ version: 6.0.3.2
195
195
  - !ruby/object:Gem::Dependency
196
- name: activemodel
196
+ name: activesupport
197
197
  requirement: !ruby/object:Gem::Requirement
198
198
  requirements:
199
199
  - - '='
@@ -207,47 +207,75 @@ dependencies:
207
207
  - !ruby/object:Gem::Version
208
208
  version: 6.0.3.2
209
209
  - !ruby/object:Gem::Dependency
210
- name: activesupport
210
+ name: bcrypt
211
211
  requirement: !ruby/object:Gem::Requirement
212
212
  requirements:
213
213
  - - '='
214
214
  - !ruby/object:Gem::Version
215
- version: 6.0.3.2
215
+ version: 3.1.13
216
216
  type: :runtime
217
217
  prerelease: false
218
218
  version_requirements: !ruby/object:Gem::Requirement
219
219
  requirements:
220
220
  - - '='
221
221
  - !ruby/object:Gem::Version
222
- version: 6.0.3.2
222
+ version: 3.1.13
223
223
  - !ruby/object:Gem::Dependency
224
- name: bcrypt
224
+ name: dotenv
225
225
  requirement: !ruby/object:Gem::Requirement
226
226
  requirements:
227
227
  - - '='
228
228
  - !ruby/object:Gem::Version
229
- version: 3.1.13
229
+ version: 2.7.6
230
230
  type: :runtime
231
231
  prerelease: false
232
232
  version_requirements: !ruby/object:Gem::Requirement
233
233
  requirements:
234
234
  - - '='
235
235
  - !ruby/object:Gem::Version
236
- version: 3.1.13
236
+ version: 2.7.6
237
237
  - !ruby/object:Gem::Dependency
238
- name: dotenv
238
+ name: mongoid
239
239
  requirement: !ruby/object:Gem::Requirement
240
240
  requirements:
241
241
  - - '='
242
242
  - !ruby/object:Gem::Version
243
- version: 2.7.6
243
+ version: 7.1.0
244
244
  type: :runtime
245
245
  prerelease: false
246
246
  version_requirements: !ruby/object:Gem::Requirement
247
247
  requirements:
248
248
  - - '='
249
249
  - !ruby/object:Gem::Version
250
- version: 2.7.6
250
+ version: 7.1.0
251
+ - !ruby/object:Gem::Dependency
252
+ name: sinatra
253
+ requirement: !ruby/object:Gem::Requirement
254
+ requirements:
255
+ - - ">="
256
+ - !ruby/object:Gem::Version
257
+ version: 2.1.0
258
+ type: :runtime
259
+ prerelease: false
260
+ version_requirements: !ruby/object:Gem::Requirement
261
+ requirements:
262
+ - - ">="
263
+ - !ruby/object:Gem::Version
264
+ version: 2.1.0
265
+ - !ruby/object:Gem::Dependency
266
+ name: sinatra-contrib
267
+ requirement: !ruby/object:Gem::Requirement
268
+ requirements:
269
+ - - '='
270
+ - !ruby/object:Gem::Version
271
+ version: 2.1.0
272
+ type: :runtime
273
+ prerelease: false
274
+ version_requirements: !ruby/object:Gem::Requirement
275
+ requirements:
276
+ - - '='
277
+ - !ruby/object:Gem::Version
278
+ version: 2.1.0
251
279
  description: This gem holds the model layer for my table-top RPG games application.
252
280
  email: courtois.vincent@outlook.com
253
281
  executables: []
@@ -255,6 +283,22 @@ extensions: []
255
283
  extra_rdoc_files: []
256
284
  files:
257
285
  - lib/core.rb
286
+ - lib/core/controllers.rb
287
+ - lib/core/controllers/base.rb
288
+ - lib/core/helpers.rb
289
+ - lib/core/helpers/accounts.rb
290
+ - lib/core/helpers/applications.rb
291
+ - lib/core/helpers/declarators.rb
292
+ - lib/core/helpers/errors.rb
293
+ - lib/core/helpers/errors/bad_request.rb
294
+ - lib/core/helpers/errors/base.rb
295
+ - lib/core/helpers/errors/forbidden.rb
296
+ - lib/core/helpers/errors/not_found.rb
297
+ - lib/core/helpers/fields.rb
298
+ - lib/core/helpers/parameters.rb
299
+ - lib/core/helpers/responses.rb
300
+ - lib/core/helpers/routes.rb
301
+ - lib/core/helpers/sessions.rb
258
302
  - lib/core/models.rb
259
303
  - lib/core/models/account.rb
260
304
  - lib/core/models/authentication.rb
@@ -271,26 +315,16 @@ files:
271
315
  - lib/core/models/chatrooms/message.rb
272
316
  - lib/core/models/concerns.rb
273
317
  - lib/core/models/concerns/activable.rb
274
- - lib/core/models/concerns/diagnosticable.rb
275
318
  - lib/core/models/concerns/enumerable.rb
276
319
  - lib/core/models/concerns/historizable.rb
277
320
  - lib/core/models/concerns/mime_typable.rb
278
321
  - lib/core/models/concerns/premiumable.rb
279
322
  - lib/core/models/concerns/sluggable.rb
280
323
  - lib/core/models/concerns/typable.rb
281
- - lib/core/models/decorators/errors.rb
282
- - lib/core/models/decorators/errors/env_variable_missing.rb
283
- - lib/core/models/decorators/gateway.rb
284
324
  - lib/core/models/event.rb
285
- - lib/core/models/factories.rb
286
- - lib/core/models/factories/errors.rb
287
- - lib/core/models/factories/errors/gateway_not_found.rb
288
325
  - lib/core/models/files.rb
289
326
  - lib/core/models/files/document.rb
290
327
  - lib/core/models/files/permission.rb
291
- - lib/core/models/monitoring.rb
292
- - lib/core/models/monitoring/route.rb
293
- - lib/core/models/monitoring/service.rb
294
328
  - lib/core/models/notification.rb
295
329
  - lib/core/models/oauth.rb
296
330
  - lib/core/models/oauth/access_token.rb
@@ -301,6 +335,7 @@ files:
301
335
  - lib/core/models/permissions/category.rb
302
336
  - lib/core/models/permissions/group.rb
303
337
  - lib/core/models/permissions/right.rb
338
+ - lib/core/models/permissions/route.rb
304
339
  - lib/core/models/ruleset.rb
305
340
  - lib/core/version.rb
306
341
  homepage: https://rubygems.org/gems/virtuatable-core
@@ -1,24 +0,0 @@
1
- module Core
2
- module Models
3
- module Concerns
4
- # Includes the diagnostic URL field, and the related validations.
5
- # @author Vincent Courtois <courtois.vincent@outlook.com>
6
- module Diagnosticable
7
- extend ActiveSupport::Concern
8
-
9
- # Module holding the class methods for the classes including this concern.
10
- # @author Vincent Courtois <courtois.vincent@outlook.com>
11
- included do
12
- # @!attribute [rw] diagnostic
13
- # @return [String] the diagnostic URL to know the status of an entity (usually a gateway, or an instance of a service).
14
- field :diagnostic, type: String, default: '/status'
15
-
16
- validates :diagnostic,
17
- presence: {message: "required"},
18
- length: {minimum: 4, message: "minlength"},
19
- format: {with: /\A(\/[a-z]+)+\z/, message: "pattern"}
20
- end
21
- end
22
- end
23
- end
24
- end
@@ -1,16 +0,0 @@
1
- module Core
2
- module Models
3
- module Decorators
4
- module Errors
5
- # Error raised if the application key variable is missing.
6
- # @author Vincent Courtois <courtois.vincent@outlook.com>
7
- class EnvVariableMissing < Core::Models::Utils::Errors::HTTPError
8
-
9
- def initialize(action:)
10
- super(action, 'app_key', 'not_found', 404)
11
- end
12
- end
13
- end
14
- end
15
- end
16
- end
@@ -1,11 +0,0 @@
1
- module Core
2
- module Models
3
- module Decorators
4
- # Module holding all the errors concerning the code of the decorators.
5
- # @author Vincent Courtois <courtois.vincent@outlook.com>
6
- module Errors
7
- autoload :EnvVariableMissing, 'core/models/decorators/errors/env_variable_missing'
8
- end
9
- end
10
- end
11
- end
@@ -1,111 +0,0 @@
1
- module Core
2
- module Models
3
- module Decorators
4
- # Decorator for a service, providing methods to make requests on it.
5
- # @author Vincent Courtois <courtois.vincent@outlook.com>
6
- class Gateway < Draper::Decorator
7
- delegate_all
8
-
9
- # @!attribute [rw] action
10
- # @return [String] the action of the route using this API.
11
- attr_accessor :action
12
-
13
- attr_accessor :logger
14
-
15
- def initialize(action, _object)
16
- super(_object)
17
- @logger = Logger.new(STDOUT)
18
- @action = action
19
- end
20
-
21
- # Shortcut to make a DELETE request on the API.
22
- # @param session [Core::Models::Authentication::Session] the session of the user requesting the API.
23
- # @param url [String] the URL you want to reach on the service.
24
- # @param params [Hash] the additional parameters to pass in the JSON body.
25
- def delete(session:, url:, params:)
26
- return make_request_without_body(verb: 'delete', session: session, url: url, params: params)
27
- end
28
-
29
- # Shortcut to make a GET request on the API.
30
- # @param session [Core::Models::Authentication::Session] the session of the user requesting the API.
31
- # @param url [String] the URL you want to reach on the service.
32
- # @param params [Hash] the additional parameters to pass in the JSON body.
33
- def get(session:, url:, params:)
34
- return make_request_without_body(verb: 'get', session: session, url: url, params: params)
35
- end
36
-
37
- # Shortcut to make a POST request on the API.
38
- # @param session [Core::Models::Authentication::Session] the session of the user requesting the API.
39
- # @param url [String] the URL you want to reach on the service.
40
- # @param params [Hash] the additional parameters to pass in the JSON body.
41
- def post(session:, url:, params:)
42
- return make_request(verb: 'post', session: session, url: url, params: params)
43
- end
44
-
45
- # Shortcut to make a PUT request on the API.
46
- # @param session [Core::Models::Authentication::Session] the session of the user requesting the API.
47
- # @param url [String] the URL you want to reach on the service.
48
- # @param params [Hash] the additional parameters to pass in the JSON body.
49
- def put(session:, url:, params:)
50
- return make_request(verb: 'put', session: session, url: url, params: params)
51
- end
52
-
53
- private
54
-
55
- # Makes a POST request to the given service with the following steps :
56
- # 1. Gets an active and running instance of the service to make the request.
57
- # 2. Creates a Faraday connection to use it as a pipeline for the request.
58
- # 3. Makes the actual request and returns an object with the status and body of the response.
59
- #
60
- # @param verb [String] the HTTP verb to use for this request.
61
- # @param session [Core::Models::Authentication::Session] the session of the user requesting the API.
62
- # @param url [String] the URL you want to reach on the service.
63
- # @param params [Hash] the additional parameters to pass in the JSON body.
64
- #
65
- # @return [Hash, Boolean] FALSE if no instance are found, or an object with :status and :body keys correspding
66
- # to the status and body of the response to the request
67
- def make_request(verb:, session:, url:, params:)
68
- params = before_requests(session, params)
69
- connection = get_connection
70
-
71
- response = connection.send(verb) do |req|
72
- req.url url
73
- req.headers['Content-Type'] = 'application/json'
74
- req.body = params.to_json
75
- end
76
-
77
- return {
78
- status: response.status,
79
- body: JSON.parse(response.body)
80
- }
81
- end
82
-
83
- def make_request_without_body(verb:, session:, url:, params:)
84
- params = before_requests(session, params)
85
- connection = get_connection
86
- response = connection.send(verb) do |req|
87
- req.url url, params
88
- req.headers['Content-Type'] = 'application/json'
89
- end
90
- end
91
-
92
- def before_requests(session, params)
93
- if ENV['APP_KEY'].nil?
94
- raise Core::Models::Decorators::Errors::EnvVariableMissing.new(action: action)
95
- end
96
- params[:app_key] = ENV['APP_KEY']
97
- params[:session_id] = session.token
98
- return params
99
- end
100
-
101
- def get_connection
102
- Faraday.new(object.url) do |faraday|
103
- faraday.request :url_encoded
104
- faraday.response :logger
105
- faraday.adapter Faraday.default_adapter
106
- end
107
- end
108
- end
109
- end
110
- end
111
- end
@@ -1,16 +0,0 @@
1
- module Core
2
- module Models
3
- module Factories
4
- module Errors
5
- # Error raised when not gateway active and running is found in the factory.
6
- # @author Vincent Courtois <courtois.vincent@outlook.com>
7
- class GatewayNotFound < Core::Models::Utils::Errors::HTTPError
8
-
9
- def initialize(action:)
10
- super(action, 'gateway_id', 'not_found', 404)
11
- end
12
- end
13
- end
14
- end
15
- end
16
- end
@@ -1,11 +0,0 @@
1
- module Core
2
- module Models
3
- module Factories
4
- # Module holding all the errors concerning the code of the factories.
5
- # @author Vincent Courtois <courtois.vincent@outlook.com>
6
- module Errors
7
- autoload :GatewayNotFound, 'core/models/factories/errors/gateway_not_found'
8
- end
9
- end
10
- end
11
- end
@@ -1,10 +0,0 @@
1
- module Core
2
- module Models
3
- # Static factories are used to create decorated objects easily.
4
- # @author Vincent Courtois <courtois.vincent@outlook.com>
5
- module Factories
6
- autoload :Gateways, 'core/models/factories/gateways'
7
- autoload :Errors , 'core/models/factories/errors'
8
- end
9
- end
10
- end
@@ -1,33 +0,0 @@
1
- module Core
2
- module Models
3
- module Monitoring
4
- # A service is the representation of one of the applications composing the API.
5
- # @author Vincent Courtois <courtois.vincent@outlook.com>
6
- class Service
7
- include Mongoid::Document
8
- include Mongoid::Timestamps
9
- include Core::Models::Concerns::Activable
10
- include Core::Models::Concerns::Diagnosticable
11
- include Core::Models::Concerns::Premiumable
12
-
13
- # @!attribute [rw] key
14
- # @return [String] the name of the service, used as a namespace on the Kubernetes side.
15
- field :key, type: String
16
- # @!attribute [rw] path
17
- # @return [String] the path the service will be mapped on in the API. This will be used in the Ingress.
18
- field :path, type: String, default: '/'
19
-
20
- # @!attribute [rw] creator
21
- # @return [Core::Models::Account] the creator of this service.
22
- belongs_to :creator, class_name: 'Core::Models::Account', optional: true, inverse_of: :services
23
- # @!attribute [rw] routes
24
- # @return [Array<Core::Models::Monitoring::Route>] the routes associated to this service, accessible from the gateway.
25
- has_many :routes, class_name: 'Core::Models::Monitoring::Route', inverse_of: :service
26
-
27
- validates :key, uniqueness: {message: 'uniq'}
28
-
29
- validates :path, format: {with: /\A(\/:?[a-z]+)+\z/, message: 'pattern'}
30
- end
31
- end
32
- end
33
- end
@@ -1,10 +0,0 @@
1
- module Core
2
- module Models
3
- # The monitoring module holds all the logic about the services so they can be activated or deactivated.
4
- # @author Vincent Courtois <courtois.vincent@outlook.com>
5
- module Monitoring
6
- autoload :Route , 'core/models/monitoring/route'
7
- autoload :Service, 'core/models/monitoring/service'
8
- end
9
- end
10
- end