api_models 0.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.
- 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
|