api_models 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/LICENSE +21 -0
- data/README.md +2 -0
- data/lib/api_models/version.rb +5 -0
- data/lib/api_models.rb +68 -0
- data/lib/models/account.rb +39 -0
- data/lib/models/agent.rb +439 -0
- data/lib/models/app.rb +18 -0
- data/lib/models/app47_cache.rb +69 -0
- data/lib/models/app_active_build.rb +32 -0
- data/lib/models/app_policy.rb +24 -0
- data/lib/models/app_shield_policy.rb +35 -0
- data/lib/models/authorized_user_policy.rb +44 -0
- data/lib/models/b2b_app.rb +8 -0
- data/lib/models/cat/customer.rb +9 -0
- data/lib/models/cat/customer_device.rb +10 -0
- data/lib/models/cl/customer.rb +9 -0
- data/lib/models/cl/customer_device.rb +10 -0
- data/lib/models/commerce_app_store.rb +8 -0
- data/lib/models/concerns/app47_app_analyzable.rb +46 -0
- data/lib/models/concerns/app47_app_buildable.rb +46 -0
- data/lib/models/concerns/app47_app_configurable.rb +34 -0
- data/lib/models/concerns/app47_app_policies.rb +59 -0
- data/lib/models/concerns/app47_cdn_url.rb +50 -0
- data/lib/models/concerns/app47_email_sendable.rb +29 -0
- data/lib/models/concerns/app47_logger.rb +109 -0
- data/lib/models/concerns/checkin_able.rb +28 -0
- data/lib/models/concerns/searchable.rb +54 -0
- data/lib/models/configuration_constraint.rb +22 -0
- data/lib/models/configuration_group.rb +50 -0
- data/lib/models/configuration_rule.rb +58 -0
- data/lib/models/device.rb +124 -0
- data/lib/models/external_app.rb +15 -0
- data/lib/models/gehc/customer.rb +17 -0
- data/lib/models/gehc/customer_device.rb +23 -0
- data/lib/models/group.rb +40 -0
- data/lib/models/internal_app.rb +11 -0
- data/lib/models/metric_data_job.rb +16 -0
- data/lib/models/option.rb +37 -0
- data/lib/models/pin_code_policy.rb +50 -0
- data/lib/models/platform.rb +26 -0
- data/lib/models/platform_model.rb +14 -0
- data/lib/models/product_app.rb +22 -0
- data/lib/models/product_support_app.rb +19 -0
- data/lib/models/queue_manager.rb +67 -0
- data/lib/models/redis_configuration.rb +137 -0
- data/lib/models/sso_ad_group.rb +7 -0
- data/lib/models/sso_ad_server.rb +13 -0
- data/lib/models/sso_ad_user.rb +13 -0
- data/lib/models/sso_azure_server.rb +18 -0
- data/lib/models/sso_directory_group.rb +13 -0
- data/lib/models/sso_directory_server.rb +21 -0
- data/lib/models/sso_google_server.rb +13 -0
- data/lib/models/sso_ldap_group.rb +8 -0
- data/lib/models/sso_ldap_rest_server.rb +34 -0
- data/lib/models/sso_ldap_server.rb +19 -0
- data/lib/models/sso_ldap_user.rb +7 -0
- data/lib/models/sso_oauth_server.rb +16 -0
- data/lib/models/sso_saml_v2_server.rb +25 -0
- data/lib/models/sso_server.rb +38 -0
- data/lib/models/sso_user.rb +13 -0
- data/lib/models/system_configuration.rb +92 -0
- data/lib/models/time_bomb_policy.rb +138 -0
- data/lib/models/user.rb +53 -0
- data/lib/models/user_app_permission.rb +16 -0
- data/lib/models/user_device.rb +83 -0
- data/lib/models/version_management_policy.rb +113 -0
- data/lib/models/web_app.rb +12 -0
- metadata +408 -0
@@ -0,0 +1,24 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
#
|
4
|
+
# Base class for an app policy
|
5
|
+
#
|
6
|
+
class AppPolicy
|
7
|
+
include Mongoid::Document
|
8
|
+
include Mongoid::Timestamps
|
9
|
+
#
|
10
|
+
# Fields
|
11
|
+
#
|
12
|
+
field :active, type: Boolean, default: false
|
13
|
+
field :message, type: String
|
14
|
+
#
|
15
|
+
# Relationships
|
16
|
+
#
|
17
|
+
belongs_to :app, inverse_of: :policies
|
18
|
+
#
|
19
|
+
# return the policy hash for this agent
|
20
|
+
#
|
21
|
+
def enforce_policy(_agent)
|
22
|
+
{}
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
#
|
4
|
+
# Is the user allowed use this device
|
5
|
+
#
|
6
|
+
class AppShieldPolicy < AppPolicy
|
7
|
+
#
|
8
|
+
# iOS fields
|
9
|
+
#
|
10
|
+
field :ios_debug, type: Boolean, default: false
|
11
|
+
field :ios_jail_break, type: Boolean, default: false
|
12
|
+
field :ios_hooking_frameworks, type: Boolean, default: false
|
13
|
+
field :ios_repackaging, type: Boolean, default: false
|
14
|
+
field :ios_user_screenshot, type: Boolean, default: false
|
15
|
+
field :ios_system_screenshot, type: Boolean, default: false
|
16
|
+
field :ios_run_time_library, type: Boolean, default: false
|
17
|
+
field :ios_library_injection, type: Boolean, default: false
|
18
|
+
field :ios_keyboard_cache_monitor, type: Boolean, default: false
|
19
|
+
field :ios_block_external_screens, type: Boolean, default: false
|
20
|
+
# Android fields
|
21
|
+
field :android_debug, type: Boolean, default: false
|
22
|
+
field :android_jail_break, type: Boolean, default: false
|
23
|
+
field :android_hooking_frameworks, type: Boolean, default: false
|
24
|
+
field :android_repackaging, type: Boolean, default: false
|
25
|
+
field :android_user_screenshot, type: Boolean, default: false
|
26
|
+
field :android_system_screenshot, type: Boolean, default: false
|
27
|
+
field :android_run_time_library, type: Boolean, default: false
|
28
|
+
field :android_library_injection, type: Boolean, default: false
|
29
|
+
field :android_keyboard_cache_monitor, type: Boolean, default: false
|
30
|
+
field :android_block_external_screens, type: Boolean, default: false
|
31
|
+
|
32
|
+
def enforce_policy(_agent)
|
33
|
+
{}
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
#
|
4
|
+
# If this app requires an authorized user
|
5
|
+
#
|
6
|
+
class AuthorizedUserPolicy < AppPolicy
|
7
|
+
#
|
8
|
+
# fields
|
9
|
+
#
|
10
|
+
field :wipe_app_data, type: Boolean, default: false
|
11
|
+
|
12
|
+
#
|
13
|
+
# return the policy hash for this agent
|
14
|
+
#
|
15
|
+
def enforce_policy(agent)
|
16
|
+
policy = super.merge(device_enabled: 1)
|
17
|
+
if active? && !user_can_run_app?(agent)
|
18
|
+
policy[:device_enabled] = 0
|
19
|
+
policy[:device_disabled_message] = message
|
20
|
+
policy[:wipe_app_data] = wipe_app_data
|
21
|
+
end
|
22
|
+
policy
|
23
|
+
rescue StandardError
|
24
|
+
# Return the default policy
|
25
|
+
{ device_enabled: 1 }
|
26
|
+
end
|
27
|
+
|
28
|
+
private
|
29
|
+
|
30
|
+
#
|
31
|
+
# can this user run this app?
|
32
|
+
# We first find the user by the agent's device unique identifier
|
33
|
+
# then we make sure hte user has access to that application.
|
34
|
+
#
|
35
|
+
def user_can_run_app?(agent)
|
36
|
+
user = agent.find_user
|
37
|
+
device_identifier = agent.device.unique_identifier
|
38
|
+
device = user.find_device_by device_identifier
|
39
|
+
device.present? && device.approved? && user.allowed_app_set.include?(app)
|
40
|
+
rescue StandardError
|
41
|
+
# On failure, say no
|
42
|
+
false
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
#
|
4
|
+
# Apps that are analyazble, i.e., they have an agent associated
|
5
|
+
# with them. For now, web apps and internal apps have these
|
6
|
+
# properties.
|
7
|
+
#
|
8
|
+
module App47AppAnalyzable
|
9
|
+
extend ActiveSupport::Concern
|
10
|
+
#
|
11
|
+
# Add fields, relationships and callbacks
|
12
|
+
#
|
13
|
+
def self.included(base)
|
14
|
+
base.class_eval do
|
15
|
+
#
|
16
|
+
# Fields
|
17
|
+
#
|
18
|
+
field :usage_ranking, type: Integer, default: 0
|
19
|
+
field :analyzable, type: Boolean, default: true
|
20
|
+
field :agent_count, type: Integer, default: 0
|
21
|
+
field :agent_log_level, type: String, default: 'Info'
|
22
|
+
field :agent_capture_timed_events, type: Boolean, default: true
|
23
|
+
field :agent_capture_generic_events, type: Boolean, default: true
|
24
|
+
field :agent_capture_sessions, type: Boolean, default: true
|
25
|
+
field :agent_enabled, type: Boolean, default: true
|
26
|
+
field :agent_upload_on_exit, type: Boolean, default: true
|
27
|
+
field :agent_capture_crash_format, type: String, default: 'none'
|
28
|
+
field :agent_delay_data_upload_interval, type: Integer, default: 1
|
29
|
+
field :agent_configuration_update_frequency, type: Float, default: 1
|
30
|
+
field :agent_session_threshold_seconds, type: Integer, default: 5
|
31
|
+
#
|
32
|
+
# Relationships
|
33
|
+
#
|
34
|
+
has_many :agents, dependent: :destroy, inverse_of: :app
|
35
|
+
|
36
|
+
#
|
37
|
+
# Is the api enabled for this app?
|
38
|
+
#
|
39
|
+
def api_enabled?
|
40
|
+
agent_enabled? && account.api_enabled?
|
41
|
+
rescue StandardError
|
42
|
+
false
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
#
|
4
|
+
# Applications that have builds
|
5
|
+
#
|
6
|
+
module App47AppBuildable
|
7
|
+
extend ActiveSupport::Concern
|
8
|
+
TRACKED_VERSION = 'version' unless defined? TRACKED_VERSION
|
9
|
+
TRACKED_VERSION_CODE = 'version_code' unless defined? TRACKED_VERSION_CODE
|
10
|
+
ALL_TRACKED_VERSIONS = [TRACKED_VERSION, TRACKED_VERSION_CODE].freeze unless defined? ALL_TRACKED_VERSIONS
|
11
|
+
#
|
12
|
+
# Add methods to class
|
13
|
+
#
|
14
|
+
def self.included(base)
|
15
|
+
base.class_eval do
|
16
|
+
#
|
17
|
+
# Fields
|
18
|
+
#
|
19
|
+
field :notify_users_on_build_activation, type: Boolean, default: true
|
20
|
+
field :max_builds, type: Integer, default: 10
|
21
|
+
field :buildable, type: Boolean, default: true
|
22
|
+
field :ios_tracked_version, type: String, default: TRACKED_VERSION
|
23
|
+
field :android_tracked_version, type: String, default: TRACKED_VERSION
|
24
|
+
#
|
25
|
+
# Relationships
|
26
|
+
#
|
27
|
+
has_many :app_active_builds, dependent: :destroy, inverse_of: :app
|
28
|
+
|
29
|
+
#
|
30
|
+
# Return what the tracked version is for this Buildable abject, either version or version code
|
31
|
+
#
|
32
|
+
def tracked_version(platform)
|
33
|
+
send("#{platform.downcase}_tracked_version")
|
34
|
+
rescue StandardError
|
35
|
+
TRACKED_VERSION
|
36
|
+
end
|
37
|
+
|
38
|
+
#
|
39
|
+
# Should use the version code for this app on the given platform
|
40
|
+
#
|
41
|
+
def use_version_code?(platform)
|
42
|
+
TRACKED_VERSION_CODE.eql?(tracked_version(platform))
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
#
|
4
|
+
# An app that can have a configuration
|
5
|
+
#
|
6
|
+
module App47AppConfigurable
|
7
|
+
extend ActiveSupport::Concern
|
8
|
+
#
|
9
|
+
# Add methods to class
|
10
|
+
#
|
11
|
+
def self.included(base)
|
12
|
+
base.class_eval do
|
13
|
+
#
|
14
|
+
# Relationships
|
15
|
+
#
|
16
|
+
has_many :configuration_groups, dependent: :destroy, inverse_of: :app do
|
17
|
+
#
|
18
|
+
# Return configuration groups that match the agent
|
19
|
+
#
|
20
|
+
def match_agent(agent)
|
21
|
+
where(active: true).collect do |group|
|
22
|
+
next unless group.match_agent?(agent)
|
23
|
+
|
24
|
+
{ version: group.version, id: group.id.to_s }
|
25
|
+
end.compact
|
26
|
+
end
|
27
|
+
end
|
28
|
+
#
|
29
|
+
# Fields
|
30
|
+
#
|
31
|
+
field :configurable, type: Boolean, default: true
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
#
|
4
|
+
# An app that can have a collection of security policies
|
5
|
+
#
|
6
|
+
module App47AppPolicies
|
7
|
+
extend ActiveSupport::Concern
|
8
|
+
|
9
|
+
def self.included(base)
|
10
|
+
base.class_eval do
|
11
|
+
has_many :policies, dependent: :destroy, class_name: 'AppPolicy', inverse_of: :app
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
#
|
16
|
+
# Return authorized users policy
|
17
|
+
#
|
18
|
+
def authorized_user_policy
|
19
|
+
policies.find_by!(_type: 'AuthorizedUserPolicy')
|
20
|
+
rescue StandardError
|
21
|
+
nil
|
22
|
+
end
|
23
|
+
|
24
|
+
#
|
25
|
+
# Return version management
|
26
|
+
#
|
27
|
+
def version_management_policy
|
28
|
+
policies.find_by!(_type: 'VersionManagementPolicy')
|
29
|
+
rescue StandardError
|
30
|
+
nil
|
31
|
+
end
|
32
|
+
|
33
|
+
#
|
34
|
+
# PIN Code policy
|
35
|
+
#
|
36
|
+
def pin_code_policy
|
37
|
+
policies.find_by!(_type: 'PinCodePolicy')
|
38
|
+
rescue StandardError
|
39
|
+
nil
|
40
|
+
end
|
41
|
+
|
42
|
+
#
|
43
|
+
# Time Bomb Policy
|
44
|
+
#
|
45
|
+
def time_bomb_policy
|
46
|
+
policies.find_by!(_type: 'TimeBombPolicy')
|
47
|
+
rescue StandardError
|
48
|
+
nil
|
49
|
+
end
|
50
|
+
|
51
|
+
#
|
52
|
+
# Return app shield policy
|
53
|
+
#
|
54
|
+
def app_shield_policy
|
55
|
+
policies.find_by!(_type: 'AppShieldPolicy')
|
56
|
+
rescue StandardError
|
57
|
+
nil
|
58
|
+
end
|
59
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
#
|
4
|
+
# Take an existing either paperclip object or database field and return
|
5
|
+
# a fully qualified cdn url for that file.
|
6
|
+
#
|
7
|
+
# If the system configuration parameter for the url is not set, then simply return the value.
|
8
|
+
#
|
9
|
+
# If it is set, then replace the prefix of the URL defined by the boundry of class name, so internal_build will be
|
10
|
+
# https://original.amazon.com/internal_builds/id/original.ipa
|
11
|
+
#
|
12
|
+
# will be transposed to:
|
13
|
+
# https://cnd.apazon.com/intenral_builds/id/original.ipa
|
14
|
+
#
|
15
|
+
# To use this, first include App47::CdnUrl in your class and then when you want the URL of an object call
|
16
|
+
# app.cdn_file_url or ubild.cdn_file_url instead of app.file_url or build.file_url.
|
17
|
+
#
|
18
|
+
#
|
19
|
+
module App47CdnUrl
|
20
|
+
#
|
21
|
+
# Handle the call to cdn_whatever
|
22
|
+
#
|
23
|
+
def method_missing(method, *args)
|
24
|
+
if method.to_s.start_with? 'cdn_'
|
25
|
+
url = send method.to_s.sub(/^cdn_/, '')
|
26
|
+
cdn_url = SystemConfiguration.cdn_url
|
27
|
+
unless cdn_url.blank? || url.blank?
|
28
|
+
model_name = "#{self.class.to_s.underscore}s"
|
29
|
+
url = "#{cdn_url}/#{model_name}/#{url.split("/#{model_name}/").last}" if url.include? "/#{model_name}/"
|
30
|
+
end
|
31
|
+
url
|
32
|
+
else
|
33
|
+
super
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
#
|
38
|
+
# Look for matches on cdn_
|
39
|
+
#
|
40
|
+
def respond_to_missing?(method_name, include_private = false)
|
41
|
+
method_name.to_s.start_with?('cdn_') ? true : super
|
42
|
+
end
|
43
|
+
|
44
|
+
#
|
45
|
+
# Look for matches on cdn_
|
46
|
+
#
|
47
|
+
def respond_to?(method, include_private = false)
|
48
|
+
super unless method.to_s.start_with? 'cdn_'
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
#
|
4
|
+
# Objects that emails can be sent too...
|
5
|
+
#
|
6
|
+
module App47EmailSendable
|
7
|
+
extend ActiveSupport::Concern
|
8
|
+
|
9
|
+
def self.included(base)
|
10
|
+
base.class_eval do
|
11
|
+
field :email, type: String
|
12
|
+
field :email_bounce_date, type: Time
|
13
|
+
field :email_bounce_reason, type: String
|
14
|
+
field :unconfirmed_email, type: String
|
15
|
+
field :email_enabled, type: Boolean, default: true
|
16
|
+
|
17
|
+
before_validation :downcase_email
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
|
23
|
+
#
|
24
|
+
# Make sure emails are always downcased
|
25
|
+
#
|
26
|
+
def downcase_email
|
27
|
+
self.email = email.strip.downcase unless email.blank?
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,109 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
#
|
4
|
+
# Mixin for App47 objects to handle logging in both the rails environment as well
|
5
|
+
# as the delayed jobs environment that doesn't know about Rails.logger
|
6
|
+
#
|
7
|
+
# Provides ways to log at the class level as well as instance level.
|
8
|
+
#
|
9
|
+
#
|
10
|
+
# Usage:
|
11
|
+
# App47Logger.log_debug('meesage')
|
12
|
+
#
|
13
|
+
# or
|
14
|
+
#
|
15
|
+
# class ClassName
|
16
|
+
# include App47Logger
|
17
|
+
#
|
18
|
+
# def method_name
|
19
|
+
# log_debug('message')
|
20
|
+
# end
|
21
|
+
#
|
22
|
+
module App47Logger
|
23
|
+
#
|
24
|
+
# Log a debug messages
|
25
|
+
#
|
26
|
+
def self.log_debug(message)
|
27
|
+
log_message :debug, message
|
28
|
+
end
|
29
|
+
|
30
|
+
#
|
31
|
+
# Log a warning messages
|
32
|
+
#
|
33
|
+
# 1. Prints the messages
|
34
|
+
# 2. If an exception is passed n
|
35
|
+
# 2a prints the exception message
|
36
|
+
# 2b prints the stack trace
|
37
|
+
#
|
38
|
+
def self.log_warn(message, exception = nil)
|
39
|
+
log_message :warn, message
|
40
|
+
log_exception :warn, exception
|
41
|
+
end
|
42
|
+
|
43
|
+
#
|
44
|
+
# Log an error messages
|
45
|
+
#
|
46
|
+
# 1. Prints the messages
|
47
|
+
# 2. If an exception is passed n
|
48
|
+
# 2a prints the exception message
|
49
|
+
# 2b prints the stack trace
|
50
|
+
#
|
51
|
+
def self.log_error(message, exception = nil)
|
52
|
+
log_message :error, message
|
53
|
+
log_exception :error, exception
|
54
|
+
end
|
55
|
+
|
56
|
+
#
|
57
|
+
# Log a given exception, but only the first 10 lines in anything but test.
|
58
|
+
#
|
59
|
+
# In testing, we want the full stack to know the test case that failed.
|
60
|
+
#
|
61
|
+
def self.log_exception(level, exception = nil, max_frame = 9)
|
62
|
+
return if exception.blank?
|
63
|
+
|
64
|
+
max_frame = -1 if ENV['RACK_ENV'].eql?('test')
|
65
|
+
log_message(level, exception.message)
|
66
|
+
exception.backtrace[0..max_frame].each { |frame| log_message(level, frame) } unless exception.backtrace.blank?
|
67
|
+
end
|
68
|
+
|
69
|
+
#
|
70
|
+
# Log a given message at the given level
|
71
|
+
#
|
72
|
+
def self.log_message(level, message)
|
73
|
+
if ENV['AWS_LAMBDA_FUNCTION_VERSION'].nil?
|
74
|
+
puts "#{level}: #{message}"
|
75
|
+
else
|
76
|
+
Logger.new($stdout).send(level, message)
|
77
|
+
end
|
78
|
+
rescue StandardError
|
79
|
+
puts "#{level}: #{message}"
|
80
|
+
end
|
81
|
+
|
82
|
+
#
|
83
|
+
# Log a debug message as part of the mixin
|
84
|
+
#
|
85
|
+
def log_message(level, message)
|
86
|
+
App47Logger.log_message level, message
|
87
|
+
end
|
88
|
+
|
89
|
+
#
|
90
|
+
# Log a debug message as part of the mixin
|
91
|
+
#
|
92
|
+
def log_debug(message)
|
93
|
+
App47Logger.log_debug message
|
94
|
+
end
|
95
|
+
|
96
|
+
#
|
97
|
+
# Log a warning message as part of the mixin
|
98
|
+
#
|
99
|
+
def log_warn(message, exception = nil)
|
100
|
+
App47Logger.log_warn message, exception
|
101
|
+
end
|
102
|
+
|
103
|
+
#
|
104
|
+
# Log an error message as part of the mixin
|
105
|
+
#
|
106
|
+
def log_error(message, exception = nil)
|
107
|
+
App47Logger.log_error message, exception
|
108
|
+
end
|
109
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
#
|
4
|
+
# Public: Add checkin timestamp to object
|
5
|
+
#
|
6
|
+
# Examples
|
7
|
+
#
|
8
|
+
# include CheckinAble
|
9
|
+
#
|
10
|
+
module CheckinAble
|
11
|
+
extend ActiveSupport::Concern
|
12
|
+
|
13
|
+
def self.included(base)
|
14
|
+
base.class_eval do
|
15
|
+
field :last_checkin_at, type: Time, default: Time.now.utc
|
16
|
+
set_callback :save, :before, :check_in_agent
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
private
|
21
|
+
|
22
|
+
#
|
23
|
+
# Update the last sign in time stamp
|
24
|
+
#
|
25
|
+
def check_in_agent
|
26
|
+
self.last_checkin_at = Time.now.utc
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
#
|
4
|
+
# Public: Add search text to an object
|
5
|
+
#
|
6
|
+
module Searchable
|
7
|
+
extend ActiveSupport::Concern
|
8
|
+
|
9
|
+
def self.included(base)
|
10
|
+
base.class_eval do
|
11
|
+
field :search_text, type: String
|
12
|
+
before_validation :update_search_text
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
private
|
17
|
+
|
18
|
+
#
|
19
|
+
# Internal: Update the search text
|
20
|
+
#
|
21
|
+
# Examples
|
22
|
+
#
|
23
|
+
# update_search_text
|
24
|
+
#
|
25
|
+
# Call before validation to update, changes are persisted with the object.
|
26
|
+
#
|
27
|
+
def update_search_text
|
28
|
+
return if destroyed?
|
29
|
+
|
30
|
+
items = search_fields.reject { |field| send(field.to_sym).blank? }.collect do |field|
|
31
|
+
value = send(field.to_sym)
|
32
|
+
if value.is_a? String
|
33
|
+
value.downcase
|
34
|
+
elsif value.is_a? Array
|
35
|
+
value.empty? ? nil : value.join(' ').downcase
|
36
|
+
end
|
37
|
+
end
|
38
|
+
self.search_text = items.compact.join ' '
|
39
|
+
end
|
40
|
+
|
41
|
+
#
|
42
|
+
# Internal: Which fields to add to search text
|
43
|
+
#
|
44
|
+
# Examples
|
45
|
+
#
|
46
|
+
# search_fields
|
47
|
+
# # => ['name', 'email', 'code']
|
48
|
+
#
|
49
|
+
# Return which fields should be added to search
|
50
|
+
#
|
51
|
+
def search_fields
|
52
|
+
%w[name email]
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
#
|
4
|
+
# List of available configuration constraints that are allowed for a given configuration group.
|
5
|
+
#
|
6
|
+
class ConfigurationConstraint
|
7
|
+
include Mongoid::Document
|
8
|
+
include Mongoid::Timestamps
|
9
|
+
#
|
10
|
+
# Fields
|
11
|
+
#
|
12
|
+
field :name, type: String
|
13
|
+
#
|
14
|
+
# Relationships
|
15
|
+
#
|
16
|
+
has_many :configuration_rules
|
17
|
+
#
|
18
|
+
# Validations
|
19
|
+
#
|
20
|
+
validates_presence_of :name
|
21
|
+
validates_uniqueness_of :name
|
22
|
+
end
|