api_models 0.1.0

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