virtuatable-core 1.0.0 → 1.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 (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