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.
Files changed (69) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +21 -0
  3. data/README.md +2 -0
  4. data/lib/api_models/version.rb +5 -0
  5. data/lib/api_models.rb +68 -0
  6. data/lib/models/account.rb +39 -0
  7. data/lib/models/agent.rb +439 -0
  8. data/lib/models/app.rb +18 -0
  9. data/lib/models/app47_cache.rb +69 -0
  10. data/lib/models/app_active_build.rb +32 -0
  11. data/lib/models/app_policy.rb +24 -0
  12. data/lib/models/app_shield_policy.rb +35 -0
  13. data/lib/models/authorized_user_policy.rb +44 -0
  14. data/lib/models/b2b_app.rb +8 -0
  15. data/lib/models/cat/customer.rb +9 -0
  16. data/lib/models/cat/customer_device.rb +10 -0
  17. data/lib/models/cl/customer.rb +9 -0
  18. data/lib/models/cl/customer_device.rb +10 -0
  19. data/lib/models/commerce_app_store.rb +8 -0
  20. data/lib/models/concerns/app47_app_analyzable.rb +46 -0
  21. data/lib/models/concerns/app47_app_buildable.rb +46 -0
  22. data/lib/models/concerns/app47_app_configurable.rb +34 -0
  23. data/lib/models/concerns/app47_app_policies.rb +59 -0
  24. data/lib/models/concerns/app47_cdn_url.rb +50 -0
  25. data/lib/models/concerns/app47_email_sendable.rb +29 -0
  26. data/lib/models/concerns/app47_logger.rb +109 -0
  27. data/lib/models/concerns/checkin_able.rb +28 -0
  28. data/lib/models/concerns/searchable.rb +54 -0
  29. data/lib/models/configuration_constraint.rb +22 -0
  30. data/lib/models/configuration_group.rb +50 -0
  31. data/lib/models/configuration_rule.rb +58 -0
  32. data/lib/models/device.rb +124 -0
  33. data/lib/models/external_app.rb +15 -0
  34. data/lib/models/gehc/customer.rb +17 -0
  35. data/lib/models/gehc/customer_device.rb +23 -0
  36. data/lib/models/group.rb +40 -0
  37. data/lib/models/internal_app.rb +11 -0
  38. data/lib/models/metric_data_job.rb +16 -0
  39. data/lib/models/option.rb +37 -0
  40. data/lib/models/pin_code_policy.rb +50 -0
  41. data/lib/models/platform.rb +26 -0
  42. data/lib/models/platform_model.rb +14 -0
  43. data/lib/models/product_app.rb +22 -0
  44. data/lib/models/product_support_app.rb +19 -0
  45. data/lib/models/queue_manager.rb +67 -0
  46. data/lib/models/redis_configuration.rb +137 -0
  47. data/lib/models/sso_ad_group.rb +7 -0
  48. data/lib/models/sso_ad_server.rb +13 -0
  49. data/lib/models/sso_ad_user.rb +13 -0
  50. data/lib/models/sso_azure_server.rb +18 -0
  51. data/lib/models/sso_directory_group.rb +13 -0
  52. data/lib/models/sso_directory_server.rb +21 -0
  53. data/lib/models/sso_google_server.rb +13 -0
  54. data/lib/models/sso_ldap_group.rb +8 -0
  55. data/lib/models/sso_ldap_rest_server.rb +34 -0
  56. data/lib/models/sso_ldap_server.rb +19 -0
  57. data/lib/models/sso_ldap_user.rb +7 -0
  58. data/lib/models/sso_oauth_server.rb +16 -0
  59. data/lib/models/sso_saml_v2_server.rb +25 -0
  60. data/lib/models/sso_server.rb +38 -0
  61. data/lib/models/sso_user.rb +13 -0
  62. data/lib/models/system_configuration.rb +92 -0
  63. data/lib/models/time_bomb_policy.rb +138 -0
  64. data/lib/models/user.rb +53 -0
  65. data/lib/models/user_app_permission.rb +16 -0
  66. data/lib/models/user_device.rb +83 -0
  67. data/lib/models/version_management_policy.rb +113 -0
  68. data/lib/models/web_app.rb +12 -0
  69. metadata +408 -0
@@ -0,0 +1,50 @@
1
+ # frozen_string_literal: true
2
+
3
+ #
4
+ # Hold a collection of app configuration items as a group.
5
+ #
6
+ # Contains the actual key value pairs as well as the rules that
7
+ # apply to this configuration group.
8
+ #
9
+ class ConfigurationGroup
10
+ include Mongoid::Document
11
+ include Mongoid::Timestamps
12
+ #
13
+ # Fields
14
+ #
15
+ field :name, type: String
16
+ field :active, type: Boolean, default: true
17
+ field :version, type: Integer, default: 1
18
+ #
19
+ # Relationships
20
+ #
21
+ belongs_to :app, class_name: 'InternalApp', inverse_of: :configuration_groups
22
+ has_many :configuration_rules, dependent: :destroy
23
+ embeds_many 'options'
24
+ #
25
+ # Validations
26
+ #
27
+ validates_presence_of :name
28
+ validates_presence_of :version
29
+ validates_uniqueness_of :name, scope: :app_id, message: 'The configuration group already exists'
30
+
31
+ #
32
+ # Return true if the configuration rules match this agent
33
+ #
34
+ def match_agent?(agent)
35
+ return false unless active?
36
+
37
+ match = true
38
+ configuration_rules.where(active: true).each { |rule| match &&= rule.match_agent?(agent) }
39
+ match
40
+ rescue StandardError
41
+ false
42
+ end
43
+
44
+ #
45
+ # Return the configuration doc for the agent
46
+ #
47
+ def agent_payload
48
+ { name: name, version: version, items: options.collect(&:agent_payload) }
49
+ end
50
+ end
@@ -0,0 +1,58 @@
1
+ # frozen_string_literal: true
2
+
3
+ #
4
+ # A rule for a given configuration group
5
+ #
6
+ class ConfigurationRule
7
+ include Mongoid::Document
8
+ include Mongoid::Timestamps
9
+ #
10
+ # Fields
11
+ #
12
+ field :active, type: Boolean, default: false
13
+ field :option, type: String
14
+ field :operator, type: String
15
+ field :platform, type: Array, default: %w[android ios]
16
+ #
17
+ # Relationships
18
+ #
19
+ belongs_to :app
20
+ belongs_to :configuration_constraint, optional: true
21
+ belongs_to :configuration_group
22
+
23
+ #
24
+ # Return true if this rule matches the given agent
25
+ #
26
+ def match_agent?(agent)
27
+ active? && match_platform?(agent) && (platform_rule? || match_constraint_rule?(agent))
28
+ end
29
+
30
+ private
31
+
32
+ #
33
+ # Test if the constraint matches this agent
34
+ #
35
+ def match_constraint_rule?(agent)
36
+ name = configuration_constraint.name
37
+ value = agent.respond_to?(name) ? agent[name] : agent.device[name]
38
+ value.send(operator, option)
39
+ rescue StandardError
40
+ false
41
+ end
42
+
43
+ #
44
+ # Is this a global rule, or platform rule
45
+ #
46
+ def platform_rule?
47
+ configuration_constraint.blank?
48
+ end
49
+
50
+ #
51
+ # If the platform for the device's agent is in the list of platforms
52
+ #
53
+ def match_platform?(agent)
54
+ platform.include?(agent.device.platform.downcase)
55
+ rescue StandardError
56
+ false
57
+ end
58
+ end
@@ -0,0 +1,124 @@
1
+ # frozen_string_literal: true
2
+
3
+ #
4
+ # Holds a single device, where a device may have many agents (and thus apps)
5
+ # installed on it.
6
+ #
7
+ # 1. Data comes in as device_platform, device_os_version, device_model,
8
+ # device_manufacture, device_capacity, app_version
9
+ # 2. Raw model id is saved on internal_model if updated from market name
10
+ # 3. Add app ids to app_ids, need to copy over app_id array and delete it
11
+ # 4. Remove identifier
12
+ #
13
+ class Device
14
+ include Mongoid::Document
15
+ include Mongoid::Timestamps
16
+ include CheckinAble
17
+ #
18
+ # Fields
19
+ #
20
+ field :unique_identifier, type: String
21
+ field :platform, type: String
22
+ field :name, type: String
23
+ field :os_version, type: String
24
+ field :manufacture, type: String
25
+ field :model, type: String
26
+ field :internal_model, type: String
27
+ field :capacity, type: String
28
+ #
29
+ # relationships
30
+ #
31
+ has_many :agents
32
+ has_and_belongs_to_many :apps, class_name: 'InternalApp', inverse_of: nil
33
+ #
34
+ # Callbacks
35
+ #
36
+ set_callback :save, :before, :model_market_name
37
+ set_callback :find, :after, :migrate_data
38
+
39
+ #
40
+ # Fetch or create a device
41
+ #
42
+ def self.fetch(json)
43
+ device_identifier = json[:device_identifier]
44
+ raise 'device_id cannot be nil' if device_identifier.nil?
45
+
46
+ device = Device.find_or_initialize_by(unique_identifier: device_identifier)
47
+ device.update_attributes!(json)
48
+ device
49
+ end
50
+
51
+ #
52
+ # Safely update attributes from the document
53
+ #
54
+ def update_attributes!(attributes = {})
55
+ super(filter_json(attributes))
56
+ end
57
+
58
+ #
59
+ # Safely update attributes from the document
60
+ #
61
+ def update!(attributes = {})
62
+ super(filter_json(attributes))
63
+ end
64
+
65
+ #
66
+ # filter only the json parameters we want to take into the device. The agent
67
+ # sends up more than we need for the device.
68
+ #
69
+ def filter_json(json)
70
+ filtered_json = {}
71
+ filtered_json[:platform] = json[:device_platform] if json[:device_platform]
72
+ filtered_json[:os_version] = json[:device_os_version] if json[:device_os_version]
73
+ filtered_json[:manufacture] = json[:device_manufacture] if json[:device_manufacture]
74
+ filtered_json[:capacity] = json[:device_capacity] if json[:device_capacity]
75
+ filtered_json[:model] = json[:device_model] if json[:device_model]
76
+ filtered_json[:name] = json[:device_name] if json[:device_name]
77
+ filtered_json
78
+ end
79
+
80
+ private
81
+
82
+ #
83
+ # clean up old app_id list to add things to app_ids
84
+ # Also clear out the identifier attribute, should no longer be there.
85
+ #
86
+ def migrate_data
87
+ remove_attribute :identifier
88
+ migrate_app_ids if self[:app_id].present?
89
+ end
90
+
91
+ #
92
+ # Transfer the app_id array to app_ids
93
+ #
94
+ def migrate_app_ids
95
+ self[:app_id].each do |app_id|
96
+ begin
97
+ apps << InternalApp.find(app_id)
98
+ rescue StandardError
99
+ next
100
+ end
101
+ end
102
+ remove_attribute :app_id
103
+ end
104
+
105
+ #
106
+ # Update the model name based on the market name
107
+ #
108
+ def model_market_name
109
+ return unless changed.include?('model')
110
+
111
+ platform_key = "platform::#{platform}"
112
+ platform_model = App47Cache.get(platform_key)
113
+ if platform_model.nil?
114
+ platform_model = Platform.where(name: platform).first
115
+ App47Cache.set(platform_key, platform_model, 604_800)
116
+ end
117
+ return if platform_model.nil? || model.eql?(platform_model.market_name(model))
118
+
119
+ self.internal_model = model
120
+ self.model = platform_model.market_name(model)
121
+ rescue StandardError
122
+ App47Cache.delete(platform_key)
123
+ end
124
+ end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ #
4
+ # An external app is one that is in a public app store, iTunes, Google Play, etc..
5
+ #
6
+ class ExternalApp < App
7
+ #
8
+ # Fields
9
+ # @
10
+ field :wp8_external_id, type: String
11
+ field :windows_external_id, type: String
12
+ field :additional_note, type: String
13
+ field :windows_external_url, type: String
14
+ field :external_auto_update, type: Boolean, default: true
15
+ end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ #
4
+ # Extension of customer specific to GEHC features.
5
+ #
6
+ module Gehc
7
+ class Customer < User
8
+ #
9
+ # Find a user device by safely trying a number of approaches
10
+ #
11
+ def find_device_by(device_id)
12
+ suepr || devices.where(serialNumber: device_id).first
13
+ rescue StandardError
14
+ nil
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Gehc
4
+ #
5
+ # GEHC Customer device
6
+ #
7
+ class CustomerDevice < UserDevice
8
+ field :serialNumber, type: String
9
+
10
+ #
11
+ # Find a user device by safely trying a number of approaches
12
+ # 1. By ID
13
+ # 2. By unique identifier
14
+ # 3. By app47 identifier
15
+ # 4. By token
16
+ #
17
+ def self.find_device_by(device_id)
18
+ super || Gehc::CustomerDevice.where(serialNumber: device_id).first
19
+ rescue StandardError
20
+ nil
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,40 @@
1
+ # frozen_string_literal: true
2
+
3
+ #
4
+ # Holds a collection of users in a group. Also contains a collection of apps
5
+ # that those users will have access to
6
+ #
7
+ class Group
8
+ include Mongoid::Document
9
+ include Mongoid::Timestamps
10
+ include Searchable
11
+
12
+ field :name, type: String
13
+ field :display_name, type: String
14
+ field :description, type: String
15
+
16
+ validates_presence_of :name
17
+
18
+ belongs_to :parent, class_name: 'Group', inverse_of: :children
19
+ has_many :children, dependent: :destroy, class_name: 'Group', inverse_of: :parent
20
+
21
+ # has_and_belongs_to_many :users, dependent: :nullify
22
+ has_many :user_app_permissions, dependent: :destroy
23
+ has_and_belongs_to_many :inherited_apps, dependent: :nullify, class_name: 'App'
24
+ has_and_belongs_to_many :apps, inverse_of: :groups, dependent: :nullify
25
+ belongs_to :account, inverse_of: :groups
26
+
27
+ #
28
+ # Internal: Which fields to add to search text
29
+ #
30
+ # Examples
31
+ #
32
+ # search_fields
33
+ # # => ['name']
34
+ #
35
+ # Return which fields should be added to
36
+ #
37
+ def search_fields
38
+ %w[name]
39
+ end
40
+ end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ #
4
+ # Internal App, the only app that should be talking to the API
5
+ #
6
+ class InternalApp < App
7
+ include App47AppAnalyzable
8
+ include App47AppBuildable
9
+ include App47AppPolicies
10
+ include App47AppConfigurable
11
+ end
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ #
4
+ # Placeholder, job will be run in WebUI, not in the API
5
+ #
6
+ class MetricDataJob
7
+ attr_accessor :payload
8
+
9
+ def self.perform_later(payload = {})
10
+ MetricDataJob.new.perform(payload.to_json)
11
+ end
12
+
13
+ def perform(_payload = {}); end
14
+
15
+ handle_asynchronously :perform
16
+ end
@@ -0,0 +1,37 @@
1
+ # frozen_string_literal: true
2
+
3
+ #
4
+ # Holds a single app configuration option, essentially
5
+ # a key value pair within the configuration group
6
+ #
7
+ class Option
8
+ include Mongoid::Document
9
+ include Mongoid::Timestamps
10
+ #
11
+ # Fields
12
+ #
13
+ field :key, type: String
14
+ field :value_type, type: String
15
+ field :value, type: String
16
+ #
17
+ # Relationships
18
+ #
19
+ embedded_in :configuration_group
20
+ #
21
+ # Validations
22
+ #
23
+ validates_presence_of(:key)
24
+ validates_presence_of(:value_type)
25
+ validates_uniqueness_of(:key, scope: :configuration_group)
26
+
27
+ #
28
+ # Return the payload for the agent
29
+ #
30
+ def agent_payload
31
+ { updated_at: (updated_at || Date.new),
32
+ key: key,
33
+ value: value,
34
+ type: value_type,
35
+ id: id.to_s }
36
+ end
37
+ end
@@ -0,0 +1,50 @@
1
+ # frozen_string_literal: true
2
+
3
+ #
4
+ # Pin code policy for this app
5
+ #
6
+ class PinCodePolicy < AppPolicy
7
+ include Base64
8
+ #
9
+ # fields
10
+ #
11
+ field :dialog, type: String, default: 'PIN Code'
12
+ field :unknown_user_message, type: String, default: 'Unable to determine a valid user, please contact support'
13
+ field :pin_locked_message,
14
+ type: String,
15
+ default: 'PIN Code is locked, please return to the App Store to set your PIN Code or contact support'
16
+ field :lock_after_failures, type: Integer, default: 4
17
+ field :session_hours, type: Integer, default: 24
18
+ #
19
+ # return the policy hash for this agent
20
+ #
21
+ def enforce_policy(agent)
22
+ policy = super.merge(pin_code_required: 0)
23
+ return policy unless active?
24
+
25
+ policy[:pin_code_required] = 1
26
+ policy[:pin_code_locked] = 0
27
+ policy[:pin_code_dialog_label] = dialog
28
+ user = agent.find_user
29
+ if user.present?
30
+ if user.pin_code_locked?
31
+ policy[:pin_code_locked] = 1
32
+ policy[:pin_code_message] = pin_locked_message
33
+ elsif user.pin_code.blank?
34
+ policy[:pin_code_message] = message
35
+ else
36
+ policy[:pin_code] = agent.encrypt_data(user.pin_code)
37
+ policy[:pin_code_message] = pin_locked_message
38
+ policy[:pin_code_lock_after_failures] = lock_after_failures
39
+ policy[:pin_code_session_hours] = session_hours
40
+ end
41
+ else
42
+ policy[:pin_code_message] = unknown_user_message
43
+ end
44
+ policy
45
+ rescue StandardError => error
46
+ log_error("Unable to build pin code policy for agent: #{agent.inspect} - #{inspect}", error)
47
+ # Return the default policy
48
+ { require_passcode: 0 }
49
+ end
50
+ end
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ #
4
+ # Hold available platforms
5
+ #
6
+ class Platform
7
+ include Mongoid::Document
8
+ field :name, type: String
9
+ #
10
+ # Validations
11
+ #
12
+ validates_presence_of :name
13
+ validates_uniqueness_of :name
14
+ #
15
+ # relationships
16
+ #
17
+ embeds_many :models, class_name: 'PlatformModel'
18
+
19
+ #
20
+ # return the market name for the given name
21
+ #
22
+ def market_name(model_name)
23
+ market_model = models.where(name: model_name).first
24
+ market_model.nil? ? model_name : market_model.market_name
25
+ end
26
+ end
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ #
4
+ # A given model for a platform.
5
+ #
6
+ class PlatformModel
7
+ include Mongoid::Document
8
+ field :name, type: String
9
+ field :market_name, type: String
10
+ #
11
+ # Relationships
12
+ #
13
+ embedded_in :platform
14
+ end
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ #
4
+ # Product Apps is a base class for applications used in an Embeeded App Store Implementation such as
5
+ # GEHC and Caterpillar
6
+ #
7
+ # Currently there will be three types of apps extending this class
8
+ # * CommerceAppStore - Although a better name would be AppStoreApp, this already exists and not worth renaming
9
+ # * ProductSupportApp - A supporting app needed for the customer's product to work correctly.
10
+ #
11
+ class ProductApp < App
12
+ include App47AppAnalyzable
13
+ include App47AppBuildable
14
+ include App47AppConfigurable
15
+ include App47CdnUrl
16
+ #
17
+ # Fields
18
+ #
19
+ field :restart_required, type: Boolean, default: false
20
+ field :accept_permissions, type: Boolean, default: false
21
+ field :return_to_update, type: Boolean, default: false
22
+ end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ #
4
+ # A product support app related to an embedded app store. It's not the App47 app store, but a supporting
5
+ # app that is needed for the overall product
6
+ #
7
+ class ProductSupportApp < ProductApp
8
+ #
9
+ # Fields
10
+ #
11
+ field :unique_identifier
12
+
13
+ #
14
+ # What is the external name we want to display
15
+ #
16
+ def external_type_name
17
+ 'Product Support'
18
+ end
19
+ end
@@ -0,0 +1,67 @@
1
+ # frozen_string_literal: true
2
+
3
+ #
4
+ # Manage the interface with the queue, simplifying the interface for pushing documents.
5
+ #
6
+ class QueueManager
7
+ class << self
8
+ #
9
+ # Push a message onto the queue name.
10
+ #
11
+ def push(document, name = ENV['RACK_ENV'])
12
+ case SystemConfiguration.queue_impl
13
+ when 'DelayedJob'
14
+ document[:metric_name] = name
15
+ document[:created_at] = Time.now.utc.to_s
16
+ MetricDataJob.perform_later(document)
17
+ else
18
+ raise "Unknown queue implementation: #{SystemConfiguration.queue_impl}"
19
+ end
20
+ end
21
+
22
+ #
23
+ # Add a timestamp to the document.
24
+ #
25
+ def add_ts(document)
26
+ json = document.is_a?(String) ? JSON.parse(document) : document
27
+ json[:created_at] = Time.now.utc.to_s
28
+ json.to_json
29
+ end
30
+
31
+ #
32
+ # Push to the WebUI Worker
33
+ #
34
+ def push_worker(message)
35
+ push(message)
36
+ end
37
+
38
+ #
39
+ # Push to the session queue
40
+ #
41
+ def push_session(message)
42
+ push(message, :session_events)
43
+ end
44
+
45
+ #
46
+ # Push to the timed event queue
47
+ #
48
+ def push_timed_event(message)
49
+ push(message, :timedevents_events)
50
+ end
51
+
52
+ #
53
+ # Push the generic event queue
54
+ #
55
+ def push_generic_event(message)
56
+ push(message, :generic_events)
57
+ end
58
+
59
+ #
60
+ # push log event queue
61
+ #
62
+ def push_log_event(message)
63
+ # encoded_doc = message.to_s.force_encoding('UTF-8')
64
+ push(message, :log_events)
65
+ end
66
+ end
67
+ end