virtuatable-core 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
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