virtuatable-core 1.0.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 (51) hide show
  1. checksums.yaml +7 -0
  2. data/lib/core/models/account.rb +102 -0
  3. data/lib/core/models/authentication/session.rb +30 -0
  4. data/lib/core/models/authentication.rb +9 -0
  5. data/lib/core/models/campaign.rb +110 -0
  6. data/lib/core/models/campaigns/invitation.rb +31 -0
  7. data/lib/core/models/campaigns/tag.rb +23 -0
  8. data/lib/core/models/campaigns.rb +10 -0
  9. data/lib/core/models/chatrooms/base.rb +16 -0
  10. data/lib/core/models/chatrooms/campaign.rb +13 -0
  11. data/lib/core/models/chatrooms/conversation.rb +9 -0
  12. data/lib/core/models/chatrooms/membership.rb +17 -0
  13. data/lib/core/models/chatrooms/message.rb +33 -0
  14. data/lib/core/models/chatrooms.rb +13 -0
  15. data/lib/core/models/concerns/activable.rb +20 -0
  16. data/lib/core/models/concerns/diagnosticable.rb +24 -0
  17. data/lib/core/models/concerns/enumerable.rb +50 -0
  18. data/lib/core/models/concerns/historizable.rb +64 -0
  19. data/lib/core/models/concerns/mime_typable.rb +44 -0
  20. data/lib/core/models/concerns/premiumable.rb +17 -0
  21. data/lib/core/models/concerns/sluggable.rb +29 -0
  22. data/lib/core/models/concerns/typable.rb +19 -0
  23. data/lib/core/models/concerns.rb +16 -0
  24. data/lib/core/models/decorators/errors/env_variable_missing.rb +16 -0
  25. data/lib/core/models/decorators/errors.rb +11 -0
  26. data/lib/core/models/decorators/gateway.rb +111 -0
  27. data/lib/core/models/event.rb +31 -0
  28. data/lib/core/models/factories/errors/gateway_not_found.rb +16 -0
  29. data/lib/core/models/factories/errors.rb +11 -0
  30. data/lib/core/models/factories.rb +10 -0
  31. data/lib/core/models/files/document.rb +52 -0
  32. data/lib/core/models/files/permission.rb +24 -0
  33. data/lib/core/models/files.rb +8 -0
  34. data/lib/core/models/monitoring/route.rb +44 -0
  35. data/lib/core/models/monitoring/service.rb +33 -0
  36. data/lib/core/models/monitoring.rb +10 -0
  37. data/lib/core/models/notification.rb +24 -0
  38. data/lib/core/models/oauth/access_token.rb +34 -0
  39. data/lib/core/models/oauth/application.rb +58 -0
  40. data/lib/core/models/oauth/authorization.rb +33 -0
  41. data/lib/core/models/oauth/refresh_token.rb +20 -0
  42. data/lib/core/models/oauth.rb +12 -0
  43. data/lib/core/models/permissions/category.rb +17 -0
  44. data/lib/core/models/permissions/group.rb +32 -0
  45. data/lib/core/models/permissions/right.rb +21 -0
  46. data/lib/core/models/permissions.rb +12 -0
  47. data/lib/core/models/ruleset.rb +32 -0
  48. data/lib/core/models.rb +27 -0
  49. data/lib/core/version.rb +3 -0
  50. data/lib/core.rb +10 -0
  51. metadata +329 -0
@@ -0,0 +1,29 @@
1
+ module Core
2
+ module Models
3
+ module Concerns
4
+ # Includes the slug field, always the same in all models.
5
+ # @author Vincent Courtois <courtois.vincent@outlook.com>
6
+ module Sluggable
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
+ module ClassMethods
12
+ # Add the field and its validations in the model including it.
13
+ # @param entity_type [String,Symbol] the name of the model including it, to be included in the error messages.
14
+ def make_sluggable(entity_type)
15
+ # @!attribute [rw] slug
16
+ # @return [String] the slug of the current entity ; it must be snake-cased, longer than four characters, unique for the entity and given.
17
+ field :slug, type: String
18
+
19
+ validates :slug,
20
+ length: {minimum: 4, message: 'minlength', if: :slug?},
21
+ format: {with: /\A[a-z]+(_[a-z]+)*\z/, message: 'pattern', if: :slug?},
22
+ uniqueness: {message: 'uniq', if: :slug?},
23
+ presence: {message: 'required'}
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,19 @@
1
+ module Core
2
+ module Models
3
+ module Concerns
4
+ # Concerns for the objects that can be activated or deactivated, included the corresponding scopes.
5
+ # @author Vincent Courtois <courtois.vincent@outlook.com>
6
+ module Typable
7
+ extend ActiveSupport::Concern
8
+
9
+ included do
10
+ include Core::Models::Concerns::Enumerable
11
+
12
+ # @!attribute [rw] type
13
+ # @return [Symbol] the type of the instance, determining its way of being deployed, restarted, etc.
14
+ enum_field :type, [:heroku, :local, :unix], default: :heroku
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,16 @@
1
+ module Core
2
+ module Models
3
+ # This module holds the shared concerns to include in the desired models.
4
+ # @author Vincent Courtois <courtois.vincent@outlook.com>
5
+ module Concerns
6
+ autoload :Activable , 'core/models/concerns/activable'
7
+ autoload :Diagnosticable, 'core/models/concerns/diagnosticable'
8
+ autoload :Enumerable , 'core/models/concerns/enumerable'
9
+ autoload :Historizable , 'core/models/concerns/historizable'
10
+ autoload :MimeTypable , 'core/models/concerns/mime_typable'
11
+ autoload :Premiumable , 'core/models/concerns/premiumable'
12
+ autoload :Sluggable , 'core/models/concerns/sluggable'
13
+ autoload :Typable , 'core/models/concerns/typable'
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,16 @@
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
@@ -0,0 +1,11 @@
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
@@ -0,0 +1,111 @@
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
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Core
4
+ module Models
5
+ # An event is symbolizing a timestamped change in a model.
6
+ # It is recommended NOT to use this class directly but to use
7
+ # the Core::Models::Concerns::Historizable concern in a model.
8
+ #
9
+ # @author Vincent Courtois <courtois.vincent@outlook.com>
10
+ class Event
11
+ include Mongoid::Document
12
+ include Mongoid::Timestamps
13
+
14
+ # @!attribute [rw] field
15
+ # @return [String] the name of the field being historized
16
+ field :field, type: String
17
+ # @!attribute [rw] from
18
+ # @return [Any] the value of the field before update
19
+ field :from
20
+ # @!attribute [rw] to
21
+ # @return [Any] the value of the field after update
22
+ field :to
23
+
24
+ # @!attribute [rw] document
25
+ # @return [Any] the model in which the history is embedded
26
+ embedded_in :document, polymorphic: true, inverse_of: :history
27
+
28
+ validates :field, presence: { message: 'required' }
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,16 @@
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
@@ -0,0 +1,11 @@
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
@@ -0,0 +1,10 @@
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
@@ -0,0 +1,52 @@
1
+ module Core
2
+ module Models
3
+ module Files
4
+ # a document is an uploaded file in the S3 clone application.
5
+ # @author Vincent Courtois <courtois.vincent@outlook.com>
6
+ class Document
7
+ include Mongoid::Document
8
+ include Mongoid::Timestamps
9
+
10
+ # @!attribute [rw] name
11
+ # @return [String] the filename the user entered when uploading the file.
12
+ field :name, type: String
13
+
14
+ field :extension, type: String
15
+ # @!attribute [rw] size
16
+ # @return [String] the size, in bytes, of the uploaded file.
17
+ field :size, type: Integer, default: 0
18
+ # @!attribute [rw] folder
19
+ # @return [String] the folder in which the file is stored in the S3 clone.
20
+ field :folder, type: String, default: '/'
21
+ # @!attribute [rw] mime_type
22
+ # @return [String] the MIME type of the file. this MAY not correspond to the real
23
+ # MIME type of the uploaded file, this is just an indication.
24
+ field :mime_type, type: String
25
+
26
+ # @!attribute [rw] creator
27
+ # @return [Core::Models::Account] the account of the person that uploaded the file.
28
+ belongs_to :creator, class_name: 'Core::Models::Account', inverse_of: :files
29
+
30
+ # @!attribute [rw] permissions
31
+ # @return [Array<Core::Models::Files::Permission>] the permissions granted to access this file.
32
+ has_many :permissions, class_name: 'Core::Models::Files::Permission', inverse_of: :file
33
+
34
+ validates :name, :extension, :folder, :mime_type, presence: {message: 'required'}
35
+
36
+ validates :folder, format: {without: /\/\//, message: 'format'}
37
+
38
+ validate :filename_unicity
39
+
40
+ def filename_unicity
41
+ existing = Core::Models::Files::Document.where(
42
+ name: name,
43
+ folder: folder,
44
+ extension: extension,
45
+ :id.ne => id
46
+ )
47
+ errors.add(:name, 'uniq') unless existing.first.nil?
48
+ end
49
+ end
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,24 @@
1
+ module Core
2
+ module Models
3
+ module Files
4
+ # The permission granted to a user to access and/or delete a file.
5
+ # @author Vincent Courtois <courtois.vincent@outlook.com>
6
+ class Permission
7
+ include Mongoid::Document
8
+ include Mongoid::Timestamps
9
+ include Core::Models::Concerns::Enumerable
10
+
11
+ # @!attribute [rw] type
12
+ # @return [Symbol] the type of permission granted (is the user able to delete the file ?)
13
+ enum_field :type, [:read, :read_write]
14
+
15
+ # @!attribute [rw] file
16
+ # @return [Core::Models::Files::Document] the document the permission is linked to.
17
+ belongs_to :file, class_name: 'Core::Models::Files::Document', inverse_of: :permissions
18
+ # @!attribute [rw] account
19
+ # @return [Core::Models::Account] the user being granted the access to the file.
20
+ belongs_to :account, class_name: 'Core::Models::Account', inverse_of: :permissions
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,8 @@
1
+ module Core
2
+ module Models
3
+ module Files
4
+ autoload :Document , 'core/models/files/document'
5
+ autoload :Permission, 'core/models/files/permission'
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,44 @@
1
+ module Core
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.
5
+ # @param Vincent Courtois <courtois.vincent@outlook.com>
6
+ class Route
7
+ include Mongoid::Document
8
+ include Mongoid::Timestamps
9
+ include Core::Models::Concerns::Premiumable
10
+ include Core::Models::Concerns::Activable
11
+
12
+ # @!attribute [rw] path
13
+ # @return [String] the path (URI) of the route in the service?
14
+ field :path, type: String, default: '/'
15
+ # @!attribute [rw] verb
16
+ # @return [String] the verb (HTTP method) of this route in the service.
17
+ field :verb, type: String, default: 'get'
18
+ # @!attribute [rw] authenticated
19
+ # @return [Boolean] if true, the session_id is needed for this route, if false it is not.
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
+ # @!attribute [rw] groups
27
+ # @return [Array<Core::Models::Permissions::Group>] the groups having permission to access this route.
28
+ has_and_belongs_to_many :groups, class_name: 'Core::Models::Permissions::Group', inverse_of: :groups
29
+
30
+ validates :path,
31
+ format: {with: /\A(\/|((\/:?[a-zA-Z0-9_]+)+))\z/, message: 'pattern', if: :path?}
32
+
33
+ validates :verb,
34
+ 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
+ end
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,33 @@
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
@@ -0,0 +1,10 @@
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
@@ -0,0 +1,24 @@
1
+ module Core
2
+ module Models
3
+ # A notification is a little something to warn a user that an action concerning him or her occurred.
4
+ # @author Vincent Courtois <courtois.vincent@outlook.com>
5
+ class Notification
6
+ include Mongoid::Document
7
+ include Mongoid::Timestamps
8
+
9
+ # @!attribute [rw] type
10
+ # @return [String] the type of notification this is supposed to be. All types are custom and facultative.
11
+ field :type, type: String, default: 'NOTIFICATIONS.DEFAULT'
12
+ # @!attribute [rw] read
13
+ # @return [Boolean] TRUE if the notification has been read (seen by the user), FALSE otherwise.
14
+ field :read, type: Boolean, default: false
15
+ # @!attribute [rw] data
16
+ # @return [Hash] the custom data that can be attached to this notification, for example for an invitation it can be the invited username.
17
+ field :data, type: Hash, default: {}
18
+
19
+ # @!attribute [rw] account
20
+ # @return [Core::Models::Account] the account concerned by this notification.
21
+ embedded_in :account, class_name: 'Core::Models::Account', inverse_of: :notifications
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,34 @@
1
+ module Core
2
+ module Models
3
+ module OAuth
4
+ # An access token is the value assigned to the application
5
+ # to access the data the user is allowed to access.
6
+ # @author Vincent Courtois <courtois.vincent@outlook.com>
7
+ class AccessToken
8
+ include Mongoid::Document
9
+ include Mongoid::Timestamps
10
+
11
+ # @!attribute [rw] value
12
+ # @return [String] the value of the token, returned to the application when built.
13
+ field :value, type: String, default: ->{ SecureRandom.hex }
14
+ # @!attribute [rw] expiration
15
+ # @return [Integer] the time, in seconds, after which the token is declared expired, and thus can't be used anymore.
16
+ field :expiration, type: Integer, default: 86400
17
+
18
+ # @!attribute [rw] authorization
19
+ # @return [Core::Models::OAuth::Authorization] the authorization code that issued this token to the application for this user.
20
+ belongs_to :authorization, class_name: 'Core::Models::OAuth::Authorization', inverse_of: :tokens
21
+
22
+ validates :value,
23
+ presence: {message: 'required'},
24
+ uniqueness: {message: 'uniq'}
25
+
26
+ # Checks if the current date is inferior to the creation date + expiration period
27
+ # @return [Boolean] TRUE if the token is expired, FALSE otherwise.
28
+ def expired?
29
+ created_at.to_time.to_i + expiration < Time.now.to_i
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,58 @@
1
+ module Core
2
+ module Models
3
+ module OAuth
4
+ # An application is what is referred to in the OAuth2.0 RFC as a client, wanting to access private informations about the user.
5
+ # @author Vincent Courtois <courtois.vincent@outlook.com>
6
+ class Application
7
+ include Mongoid::Document
8
+ include Mongoid::Timestamps
9
+
10
+ # @!attribute [rw] name
11
+ # @return [String] the unique name of the application, mainly used to identify and display it.
12
+ field :name, type: String
13
+ # @!attribute [rw] key
14
+ # @return [String] the unique key for the application, identifying it when requesting a token for the API.
15
+ field :key, type: String, default: ->{ SecureRandom.hex }
16
+ # @!attribute [rw] premium
17
+ # @return [Boolean] a value indicating whether the application should automatically receive a token when an account is created, or not.
18
+ field :premium, type: Boolean, default: false
19
+ # @!attirbute [rw] redirect_uris
20
+ # @return [Array<String>] the redirection URIs used for this application.
21
+ field :redirect_uris, type: Array, default: []
22
+
23
+ # @!attribute [rw] creator
24
+ # @return [Core::Models::Account] the account that has created this application, considered its owner.
25
+ belongs_to :creator, class_name: 'Core::Models::Account', inverse_of: :applications
26
+ # @!attribute [rw] authorizations
27
+ # @return [Array<Core::Models::OAuth::Authorization>] the authorizations linked to the accounts this application can get the data from.
28
+ has_many :authorizations, class_name: 'Core::Models::OAuth::Authorization', inverse_of: :application
29
+
30
+ validates :name,
31
+ presence: {message: 'required'},
32
+ length: {minimum: 6, message: 'minlength'},
33
+ uniqueness: {message: 'uniq'}
34
+
35
+ validates :key,
36
+ presence: {message: 'required'},
37
+ uniqueness: {message: 'uniq'}
38
+
39
+ validate :redirect_uris_values
40
+
41
+ # Checks the URIs to get sure they are correct, a URI is correct if :
42
+ # - it is a string
43
+ # - it has a correct URL format.
44
+ def redirect_uris_values
45
+ redirect_uris.each do |uri|
46
+ if !uri.is_a? String
47
+ errors.add(:redirect_uris, 'type')
48
+ break
49
+ elsif uri.match(/\A(https?:\/\/)((([\da-z\.-]+)\.([a-z\.]{2,6})([\/\w \.-]*)*)|(localhost:[0-9]{2,4})\/?)\z/).nil?
50
+ errors.add(:redirect_uris, 'format')
51
+ break
52
+ end
53
+ end
54
+ end
55
+ end
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,33 @@
1
+ module Core
2
+ module Models
3
+ module OAuth
4
+ # An OAuth authorization is granted by a user to an application to access its personal data.
5
+ # The application then transforms it into an access token to be able to send it with
6
+ # further requests, so that we know the user has authorized the application to access its data.
7
+ #
8
+ # @author Vincent Courtois <courtois.vincent@outlook.com>
9
+ class Authorization
10
+ include Mongoid::Document
11
+ include Mongoid::Timestamps
12
+
13
+ # @!attribute [rw] code
14
+ # @return [String] the value corresponding to the authentication code in the RFC of OAuth2.0, kep for historic purpose.
15
+ field :code, type: String, default: ->{ SecureRandom.hex }
16
+
17
+ # @!attribute [rw] account
18
+ # @return [Arkaaan::Account] the account granting the authorization to access its data to the application.
19
+ belongs_to :account, class_name: 'Core::Models::Account', inverse_of: :authorizations
20
+ # @!attribute [rw] application
21
+ # @return [Core::Models::OAuth::Application] the application asking to access account's data.
22
+ belongs_to :application, class_name: 'Core::Models::OAuth::Application', inverse_of: :authorizations
23
+ # @!attribute [rw] token
24
+ # @return [Core::Models::OAuth::AccessToken] the access token used further in the application process to access private data of the account.
25
+ has_many :tokens, class_name: 'Core::Models::OAuth::AccessToken', inverse_of: :authorization
26
+
27
+ validates :code,
28
+ presence: {message: 'required'},
29
+ uniqueness: {message: 'uniq'}
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,20 @@
1
+ module Core
2
+ module Models
3
+ module OAuth
4
+ # A refresh token is used when an access token is expired, to get a new one. It is then recreated for the next expiration.
5
+ # @author Vincent Courtois <courtois.vincent@outlook.com>
6
+ class RefreshToken
7
+ include Mongoid::Document
8
+ include Mongoid::Timestamps
9
+
10
+ # @!attribute [rw] value
11
+ # @return [String] the value of the token, returned to the application when built.
12
+ field :value, type: String, default: ->{ SecureRandom.hex }
13
+
14
+ # @!attribute [rw] authorization
15
+ # @return [Core::Models::OAuth::Authorization] the authorization code that issued this token to the application for this user.
16
+ belongs_to :authorization, class_name: 'Core::Models::OAuth::Authorization', inverse_of: :refresh_token
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,12 @@
1
+ module Core
2
+ module Models
3
+ # This module holds the logic for the connection of an application to our API.
4
+ # @author Vincent Courtois <courtois.vincent@outlook.com>
5
+ module OAuth
6
+ autoload :Application , 'core/models/oauth/application'
7
+ autoload :Authorization, 'core/models/oauth/authorization'
8
+ autoload :AccessToken , 'core/models/oauth/access_token'
9
+ autoload :RefreshToken , 'core/models/oauth/refresh_token'
10
+ end
11
+ end
12
+ end