octocore-mongo 0.0.6

Sign up to get free protection for your applications and to get access to all the features.
Files changed (105) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGES.md +12 -0
  3. data/CONTRIBUTING +0 -0
  4. data/Gemfile +11 -0
  5. data/Gemfile.lock +150 -0
  6. data/LICENSE +202 -0
  7. data/MAINTAINERS +0 -0
  8. data/NOTICE +8 -0
  9. data/README.md +69 -0
  10. data/Rakefile +51 -0
  11. data/bin/fakestream-mongo +258 -0
  12. data/bin/octocore-admin-mongo +54 -0
  13. data/lib/octocore-mongo.rb +157 -0
  14. data/lib/octocore-mongo/baseline.rb +131 -0
  15. data/lib/octocore-mongo/callbacks.rb +117 -0
  16. data/lib/octocore-mongo/config.rb +39 -0
  17. data/lib/octocore-mongo/config/config.yml +1 -0
  18. data/lib/octocore-mongo/config/search/index/user.yml +42 -0
  19. data/lib/octocore-mongo/counter.rb +265 -0
  20. data/lib/octocore-mongo/counter/helpers.rb +168 -0
  21. data/lib/octocore-mongo/email.rb +63 -0
  22. data/lib/octocore-mongo/featureflag.rb +79 -0
  23. data/lib/octocore-mongo/helpers.rb +6 -0
  24. data/lib/octocore-mongo/helpers/api_consumer_helper.rb +51 -0
  25. data/lib/octocore-mongo/helpers/api_helper.rb +65 -0
  26. data/lib/octocore-mongo/helpers/api_logger.rb +14 -0
  27. data/lib/octocore-mongo/helpers/client_helper.rb +104 -0
  28. data/lib/octocore-mongo/helpers/kong_helper.rb +164 -0
  29. data/lib/octocore-mongo/helpers/sinatra_helper.rb +22 -0
  30. data/lib/octocore-mongo/kafka_bridge.rb +60 -0
  31. data/lib/octocore-mongo/kldivergence.rb +14 -0
  32. data/lib/octocore-mongo/mailer.rb +1 -0
  33. data/lib/octocore-mongo/mailer/subscriber_mailer.rb +32 -0
  34. data/lib/octocore-mongo/message_parser.rb +114 -0
  35. data/lib/octocore-mongo/models.rb +275 -0
  36. data/lib/octocore-mongo/models/contactus.rb +42 -0
  37. data/lib/octocore-mongo/models/enterprise.rb +75 -0
  38. data/lib/octocore-mongo/models/enterprise/adapter_details.rb +18 -0
  39. data/lib/octocore-mongo/models/enterprise/api_event.rb +14 -0
  40. data/lib/octocore-mongo/models/enterprise/api_hit.rb +20 -0
  41. data/lib/octocore-mongo/models/enterprise/api_key.rb +11 -0
  42. data/lib/octocore-mongo/models/enterprise/api_track.rb +13 -0
  43. data/lib/octocore-mongo/models/enterprise/app_init.rb +13 -0
  44. data/lib/octocore-mongo/models/enterprise/app_login.rb +12 -0
  45. data/lib/octocore-mongo/models/enterprise/app_logout.rb +12 -0
  46. data/lib/octocore-mongo/models/enterprise/authorization.rb +67 -0
  47. data/lib/octocore-mongo/models/enterprise/category.rb +14 -0
  48. data/lib/octocore-mongo/models/enterprise/category_baseline.rb +19 -0
  49. data/lib/octocore-mongo/models/enterprise/category_hit.rb +26 -0
  50. data/lib/octocore-mongo/models/enterprise/category_trend.rb +19 -0
  51. data/lib/octocore-mongo/models/enterprise/conversions.rb +69 -0
  52. data/lib/octocore-mongo/models/enterprise/ctr.rb +54 -0
  53. data/lib/octocore-mongo/models/enterprise/dimension_choice.rb +21 -0
  54. data/lib/octocore-mongo/models/enterprise/engagement_time.rb +43 -0
  55. data/lib/octocore-mongo/models/enterprise/funnel_data.rb +20 -0
  56. data/lib/octocore-mongo/models/enterprise/funnel_tracker.rb +19 -0
  57. data/lib/octocore-mongo/models/enterprise/funnels.rb +129 -0
  58. data/lib/octocore-mongo/models/enterprise/gcm.rb +21 -0
  59. data/lib/octocore-mongo/models/enterprise/newsfeed_hit.rb +52 -0
  60. data/lib/octocore-mongo/models/enterprise/notification_hit.rb +42 -0
  61. data/lib/octocore-mongo/models/enterprise/page.rb +15 -0
  62. data/lib/octocore-mongo/models/enterprise/page_view.rb +14 -0
  63. data/lib/octocore-mongo/models/enterprise/pageload_time.rb +43 -0
  64. data/lib/octocore-mongo/models/enterprise/product.rb +22 -0
  65. data/lib/octocore-mongo/models/enterprise/product_baseline.rb +20 -0
  66. data/lib/octocore-mongo/models/enterprise/product_hit.rb +26 -0
  67. data/lib/octocore-mongo/models/enterprise/product_page_view.rb +13 -0
  68. data/lib/octocore-mongo/models/enterprise/product_trend.rb +18 -0
  69. data/lib/octocore-mongo/models/enterprise/push_key.rb +15 -0
  70. data/lib/octocore-mongo/models/enterprise/rules.rb +45 -0
  71. data/lib/octocore-mongo/models/enterprise/segment.rb +65 -0
  72. data/lib/octocore-mongo/models/enterprise/segment_data.rb +22 -0
  73. data/lib/octocore-mongo/models/enterprise/tag.rb +14 -0
  74. data/lib/octocore-mongo/models/enterprise/tag_baseline.rb +19 -0
  75. data/lib/octocore-mongo/models/enterprise/tag_hit.rb +26 -0
  76. data/lib/octocore-mongo/models/enterprise/tag_trend.rb +19 -0
  77. data/lib/octocore-mongo/models/enterprise/template.rb +18 -0
  78. data/lib/octocore-mongo/models/plans.rb +17 -0
  79. data/lib/octocore-mongo/models/subscribe.rb +13 -0
  80. data/lib/octocore-mongo/models/user.rb +13 -0
  81. data/lib/octocore-mongo/models/user/push_token.rb +15 -0
  82. data/lib/octocore-mongo/models/user/user_browser_details.rb +16 -0
  83. data/lib/octocore-mongo/models/user/user_location_history.rb +15 -0
  84. data/lib/octocore-mongo/models/user/user_persona.rb +101 -0
  85. data/lib/octocore-mongo/models/user/user_phone_details.rb +17 -0
  86. data/lib/octocore-mongo/models/user/user_profile.rb +20 -0
  87. data/lib/octocore-mongo/models/user/user_timeline.rb +111 -0
  88. data/lib/octocore-mongo/record.rb +20 -0
  89. data/lib/octocore-mongo/schedeuleable.rb +20 -0
  90. data/lib/octocore-mongo/scheduler.rb +72 -0
  91. data/lib/octocore-mongo/search.rb +5 -0
  92. data/lib/octocore-mongo/search/client.rb +33 -0
  93. data/lib/octocore-mongo/search/indexer.rb +0 -0
  94. data/lib/octocore-mongo/search/searchable.rb +18 -0
  95. data/lib/octocore-mongo/search/setup.rb +71 -0
  96. data/lib/octocore-mongo/segment.rb +287 -0
  97. data/lib/octocore-mongo/stats.rb +33 -0
  98. data/lib/octocore-mongo/trendable.rb +88 -0
  99. data/lib/octocore-mongo/trends.rb +158 -0
  100. data/lib/octocore-mongo/utils.rb +90 -0
  101. data/lib/octocore-mongo/version.rb +4 -0
  102. data/octocore-mongo.gemspec +50 -0
  103. data/spec/lib/stats_spec.rb +20 -0
  104. data/spec/spec_helper.rb +103 -0
  105. metadata +545 -0
@@ -0,0 +1,17 @@
1
+ require 'mongo_mapper'
2
+
3
+ module Octo
4
+ class UserPhoneDetails
5
+ include MongoMapper::Document
6
+
7
+ belongs_to :user, class_name: 'Octo::User'
8
+
9
+ key :deviceid, String
10
+ key :manufacturer, String
11
+ key :model, String
12
+ key :os, String
13
+
14
+ timestamps!
15
+ end
16
+ end
17
+
@@ -0,0 +1,20 @@
1
+ require 'mongo_mapper'
2
+
3
+ module Octo
4
+ class UserProfileDetails
5
+ include MongoMapper::Document
6
+
7
+ belongs_to :user, class_name: 'Octo::User'
8
+
9
+ key :email, String
10
+ key :username, String
11
+ key :dob, String
12
+ key :gender, String
13
+ key :alternate_email, String
14
+ key :mobile, String
15
+ key :extras, String
16
+
17
+ timestamps!
18
+ end
19
+ end
20
+
@@ -0,0 +1,111 @@
1
+ require 'mongo_mapper'
2
+ require 'ostruct'
3
+
4
+ module Octo
5
+ class UserTimeline
6
+ include MongoMapper::Document
7
+
8
+ BROWSE_PRODUCT = 0
9
+ BROWSE_PAGE = 1
10
+ SEARCH = 2
11
+ SHARE = 3
12
+ ADD_TO_CART = 4
13
+ CHECKOUT = 5
14
+ APP_OPEN = 6
15
+ APP_CLOSE = 7
16
+ PAGE_RELOAD = 8
17
+
18
+ LOC_HOME = 11
19
+ LOC_OFFICE = 12
20
+ LOC_TRANSIT = 13
21
+ LOC_VACATION = 14
22
+ LOC_OOH = 15
23
+ LOC_OTHERS = 16
24
+
25
+ belongs_to :user, class_name: 'Octo::User'
26
+
27
+ key :ts, Time
28
+
29
+ key :type, Integer
30
+ key :title, String
31
+ key :location_type, Integer
32
+ key :insight, String
33
+ key :details, String
34
+
35
+ timestamps!
36
+
37
+ def self.fakedata(user, n = rand(7..20))
38
+ Array.new(3*n) do |i|
39
+ i+1
40
+ end.shuffle.sample(n).sort.reverse.collect do |i|
41
+ args = {
42
+ user: user,
43
+ ts: i.minutes.ago,
44
+ type: rand(0..8),
45
+ title: 'Product Name',
46
+ location_type: rand(11..16),
47
+ insight: 'some valueable insight',
48
+ details: 'other details here'
49
+ }
50
+ self.new(args).save!
51
+ end
52
+ end
53
+
54
+ def location_text(location_type)
55
+ case location_type
56
+ when LOC_HOME
57
+ 'Home'
58
+ when LOC_OFFICE
59
+ 'Office'
60
+ when LOC_TRANSIT
61
+ 'In Transit'
62
+ when LOC_VACATION
63
+ 'While Vacation'
64
+ when LOC_OOH
65
+ 'Out of Home City'
66
+ when LOC_OTHERS
67
+ 'Other Location'
68
+ end
69
+ end
70
+
71
+ def type_text(activity_type)
72
+ case activity_type
73
+ when BROWSE_PRODUCT
74
+ 'Browsed for Product'
75
+ when BROWSE_PAGE
76
+ 'Browsed for Page'
77
+ when SEARCH
78
+ 'Searched'
79
+ when SHARE
80
+ 'Shared'
81
+ when ADD_TO_CART
82
+ 'Added to Cart'
83
+ when CHECKOUT
84
+ 'Performed Checkout'
85
+ when APP_OPEN
86
+ 'Opened App'
87
+ when APP_CLOSE
88
+ 'Closed App'
89
+ when PAGE_RELOAD
90
+ 'Reloaded Page'
91
+ end
92
+ end
93
+
94
+ def human_readable
95
+ args = {
96
+ user: self.user,
97
+ ts: self.ts,
98
+ type: type_text(self.type),
99
+ type_raw: self.type,
100
+ title: self.title,
101
+ location: location_text(self.location_type),
102
+ location_raw: self.location_type,
103
+ insight: self.insight,
104
+ details: self.details
105
+ }
106
+ OpenStruct.new(args)
107
+ end
108
+
109
+ end
110
+ end
111
+
@@ -0,0 +1,20 @@
1
+ module Octo
2
+ module Record
3
+
4
+ def unique_id
5
+ candidates = self.key_attributes
6
+ if candidates.length == 1
7
+ # This is most likely going to be the enterpriseid of some sort
8
+ candidates.first[1].to_s
9
+ elsif candidates.length == 2
10
+ if candidates.has_key?(:enterprise_id)
11
+ candidates.delete(:enterprise_id)
12
+ candidates.first[1].to_s
13
+ end
14
+ else
15
+ raise NotImplementedError, 'See Octo::Record#unique_id'
16
+ end
17
+ end
18
+
19
+ end
20
+ end
@@ -0,0 +1,20 @@
1
+ require 'octocore-mongo/counter'
2
+
3
+ module Octo
4
+ module Scheduleable
5
+
6
+ def perform(*args)
7
+ type = args[0].to_sym
8
+
9
+ if Octo::Counter.constants.include?type
10
+ if type == :TYPE_MINUTE and self.respond_to?(:aggregate!)
11
+ aggregate!
12
+ else
13
+ method_name = type_counters_method_names type
14
+ send(method_name.to_sym, Time.now.floor)
15
+ end
16
+ end
17
+ end
18
+
19
+ end
20
+ end
@@ -0,0 +1,72 @@
1
+ require 'rake'
2
+ require 'resque'
3
+ require 'resque/tasks'
4
+ require 'resque/scheduler/tasks'
5
+
6
+ # Make sure dynamic scheduling is turned ON
7
+ Resque::Scheduler.dynamic = true
8
+
9
+ module Octo
10
+ module Scheduler
11
+
12
+ # Setup the schedules for counters.
13
+ def schedule_counters
14
+ counter_classes = [
15
+ Octo::ProductHit,
16
+ Octo::CategoryHit,
17
+ Octo::TagHit,
18
+ Octo::ApiHit,
19
+ Octo::NewsfeedHit
20
+ ]
21
+ counter_classes.each do |clazz|
22
+ clazz.send(:get_typecounters).each do |counter|
23
+ name = [clazz, counter].join('::')
24
+ config = {
25
+ class: clazz.to_s,
26
+ args: [counter],
27
+ cron: '* * * * *',
28
+ persist: true,
29
+ queue: 'high'
30
+ }
31
+ Resque.set_schedule name, config
32
+ end
33
+ end
34
+
35
+ # Schedules the processing of baselines
36
+ def schedule_baseline
37
+ baseline_classes = [
38
+ Octo::ProductBaseline,
39
+ Octo::CategoryBaseline,
40
+ Octo::TagBaseline
41
+ ]
42
+ baseline_classes.each do |clazz|
43
+ clazz.send(:get_typecounters).each do |counter|
44
+ name = [clazz, counter].join('::')
45
+ config = {
46
+ class: clazz.to_s,
47
+ args: [counter],
48
+ cron: '* * * * *',
49
+ persists: true,
50
+ queue: 'baseline_processing'
51
+ }
52
+ Resque.set_schedule name, config
53
+ end
54
+ end
55
+ end
56
+
57
+ # Schedules the daily mail, to be sent at noon
58
+ def schedule_subscribermail
59
+ name = 'SubscriberDailyMailer'
60
+ config = {
61
+ class: Octo::Mailer::SubscriberMailer,
62
+ args: [],
63
+ cron: '0 0 * * *',
64
+ persist: true,
65
+ queue: 'subscriber_notifier'
66
+ }
67
+ Resque.set_schedule name, config
68
+ end
69
+
70
+ end
71
+ end
72
+ end
@@ -0,0 +1,5 @@
1
+ require 'octocore-mongo/search/client'
2
+ require 'octocore-mongo/search/setup'
3
+ require 'octocore-mongo/search/indexer'
4
+ require 'octocore-mongo/search/searchable'
5
+
@@ -0,0 +1,33 @@
1
+ require 'multi_json'
2
+ require 'faraday'
3
+ require 'elasticsearch/api'
4
+
5
+ module Octo
6
+
7
+ # Search wrapper around ElasticSearch
8
+ module Search
9
+
10
+ class Client
11
+
12
+ include Elasticsearch::API
13
+
14
+ CONNECTION = ::Faraday::Connection.new(url: Octo.get_config(:search)[:server])
15
+
16
+ # Low level method for performing a request to Elastic Search cluster
17
+ # @param [String] method The method ex: get, put, post, etc..
18
+ # @param [String] path The path of the request
19
+ # @param [Hash] params The params of the request
20
+ # @param [String] body The body of the request
21
+ def perform_request(method, path, params, body)
22
+ Octo.logger.debug "--> #{method.upcase} #{path} #{params} #{body}"
23
+
24
+ CONNECTION.run_request \
25
+ method.downcase.to_sym,
26
+ path,
27
+ ( body ? MultiJson.dump(body): nil ),
28
+ {'Content-Type' => 'application/json'}
29
+ end
30
+ end
31
+ end
32
+ end
33
+
File without changes
@@ -0,0 +1,18 @@
1
+ module Octo
2
+ module Searchable
3
+
4
+ # Gets the search client
5
+ def searchclient
6
+ unless @searchClient
7
+ @searchClient = Octo::Search::Client.new
8
+ end
9
+ @searchClient
10
+ end
11
+
12
+ # Defines the indice with which this would be indexed
13
+ def indexable_with(indice_name, type)
14
+
15
+ end
16
+
17
+ end
18
+ end
@@ -0,0 +1,71 @@
1
+ module Octo
2
+
3
+ # Setup module for ElasticSearch
4
+ module Setup
5
+
6
+ # Creates the necessary indices
7
+ class Create
8
+
9
+ def self.perform
10
+ sclient = Octo::Search::Client.new
11
+ sconfig = Octo.get_config(:search)
12
+
13
+ # Set the cluster disk space thresholds first. That's necessary
14
+ # because the defaults are too less for development machines. So,
15
+ # in order to keep it moving, we set a lower threshold in development.
16
+ # Refer
17
+ # https://www.elastic.co/guide/en/elasticsearch/reference/current/disk-allocator.html
18
+ if sconfig.has_key?(:disk_threshold_low) and sconfig.has_key?(:disk_threshold_high)
19
+ cluster_settings = {
20
+ body: {
21
+ persistent: {
22
+ 'cluster.routing.allocation.disk.threshold_enabled' => true,
23
+ 'cluster.routing.allocation.disk.watermark.low' => sconfig[:disk_threshold_low],
24
+ 'cluster.routing.allocation.disk.watermark.high' => sconfig[:disk_threshold_high],
25
+ 'cluster.info.update.interval' => '60s'
26
+ }
27
+ }
28
+ }
29
+ sclient.cluster.put_settings cluster_settings
30
+ end
31
+
32
+ # Check if any indices specified exists. If not exists, create them
33
+ sconfig[:index].keys.each do |index_name|
34
+ args = { index: index_name }
35
+ if sclient.indices.exists?(args)
36
+ Octo.logger.info "Search Index: #{ index_name } exists."
37
+ else
38
+ Octo.logger.warn "Search Index: #{ index_name } DOES NOT EXIST."
39
+ Octo.logger.info "Creating Index: #{ index_name }"
40
+ create_args = {
41
+ index: index_name,
42
+ body: sconfig[:index][index_name]
43
+ }
44
+ sclient.indices.create create_args
45
+ end
46
+ end
47
+
48
+ # Also check if there are any indices present that should not be
49
+ # present
50
+ _indices = JSON.parse(sclient.cluster.state)['metadata']['indices'].
51
+ keys.map(&:to_sym)
52
+ extra_indices = _indices - sconfig[:index].keys
53
+ Octo.logger.warn "Found extra indices: #{ extra_indices }"
54
+ end
55
+ end
56
+
57
+ # Updates the indices.
58
+ # The major differene between this and the Create is that while create
59
+ # just checks for the existance by name, and passes if the name is found
60
+ # This actually overwrites all the mappings, properties, warmers etc
61
+ # So, this should be used only when we need to explicitly "UPDATE" the
62
+ # index.
63
+ class Update
64
+
65
+ end
66
+
67
+
68
+ end
69
+
70
+
71
+ end
@@ -0,0 +1,287 @@
1
+ require 'set'
2
+ require 'active_support/concern'
3
+ require 'octocore-mongo/helpers/api_consumer_helper'
4
+
5
+ module Octo
6
+
7
+ # The Segmentation module
8
+ module Segmentation
9
+
10
+ Octo.featureflag self, true
11
+
12
+ extend ActiveSupport::Concern
13
+
14
+ module Helpers
15
+
16
+ class << self
17
+
18
+ # Helper method for returning operators as a hash to be used in UX
19
+ # @param [Fixnum] dimension The dimension for which the operators
20
+ # are to be fetched
21
+ # @return [Array<Hash{Symbol => String }>] The hash containing key :text
22
+ # as the text to display, and another key :id as the id to be used
23
+ # as reference while communicating
24
+ def operators_as_choice(dimension = nil)
25
+ mapping_as_choice operator_text
26
+ end
27
+
28
+ # Helper method for returning dimensions as choice to be used in the UX
29
+ # @return [Array<Hash{Symbol => String }>] The hash containing key :text
30
+ # as the text to display, and another key :id as the id to be used
31
+ # as reference while communicating
32
+ def dimensions_as_choice
33
+ mapping_as_choice dimension_text
34
+ end
35
+
36
+ # Returns logic operatos as a choice for operating between dimensions
37
+ def logic_operators_as_choice
38
+ mapping_as_choice logic_text
39
+ end
40
+
41
+ # Helper method to return valid choices for a given dimension. It tries
42
+ # to find the values from db first. In case, there is nothing, it
43
+ # shows some default values, so the dashboard does not look totally
44
+ # blank.
45
+ # @param [Fixnum] dimension The dimension ID for which choices to be
46
+ # found
47
+ # @param [String] enterprise_id The enterprise ID for which the choices
48
+ # to be found
49
+ def choices_for_dimensions(dimension, enterprise_id)
50
+ args = {
51
+ enterprise_id: enterprise_id,
52
+ dimension: dimension
53
+ }
54
+ res = Octo::DimensionChoice.where(args)
55
+ choices = Array.new
56
+ if res.count > 0
57
+ choices = res.collect do |r|
58
+ r.column
59
+ end
60
+ elsif dimension_choice.has_key?(dimension)
61
+ func = dimension_choice[dimension]
62
+ choices = self.send(func, enterprise_id)
63
+ end
64
+ mapping_as_choice Hash[Array.new(choices.count) { |i| i }.zip(choices)]
65
+ end
66
+
67
+
68
+ private
69
+
70
+ # Returns a hash containing keys as Operators and the values as string
71
+ # text corresponding to them.
72
+ def operator_text
73
+ {
74
+ Octo::Segmentation::Operators::EQUAL => '= Equals',
75
+ Octo::Segmentation::Operators::NOT_EQUAL => '!= Not Equals',
76
+ Octo::Segmentation::Operators::IN => 'Within range'
77
+ }
78
+ end
79
+
80
+ # Return a hash containing keys as dimensions and the values as methods
81
+ # which should be called to populate the values
82
+ def dimension_choice
83
+ {
84
+ Octo::Segmentation::Dimensions::CITY => :city_choices,
85
+ Octo::Segmentation::Dimensions::STATE => :state_choices,
86
+ Octo::Segmentation::Dimensions::COUNTRY => :country_choices,
87
+ Octo::Segmentation::Dimensions::OS => :os_choices,
88
+ Octo::Segmentation::Dimensions::MANUFACTURER => :manufacturer_choices,
89
+ Octo::Segmentation::Dimensions::BROWSER => :browser_choices,
90
+ Octo::Segmentation::Dimensions::MODEL => :model_choices,
91
+ Octo::Segmentation::Dimensions::ENGAGEMENT => :engagement_choices
92
+ }
93
+ end
94
+
95
+ # Returns a hash containing the dimension value and the string text
96
+ def dimension_text
97
+ {
98
+ Octo::Segmentation::Dimensions::CITY => 'City',
99
+ Octo::Segmentation::Dimensions::STATE => 'State',
100
+ Octo::Segmentation::Dimensions::COUNTRY => 'Country',
101
+ Octo::Segmentation::Dimensions::OS => 'OS',
102
+ Octo::Segmentation::Dimensions::MANUFACTURER => 'Manufacturer',
103
+ Octo::Segmentation::Dimensions::BROWSER => 'Browser',
104
+ Octo::Segmentation::Dimensions::MODEL => 'Model',
105
+ Octo::Segmentation::Dimensions::ENGAGEMENT => 'Engagement',
106
+ Octo::Segmentation::Dimensions::LAST_ACTIVE => 'Last Active On',
107
+ Octo::Segmentation::Dimensions::CREATED_ON => 'Created On'
108
+ }
109
+ end
110
+
111
+ # Defines which operators can be used for which dimensions
112
+ def dimension_operator
113
+ ops = Set.new([Octo::Segmentation::Operators::EQUAL,
114
+ Octo::Segmentation::Operators::NOT_EQUAL,
115
+ Octo::Segmentation::Operators::IN])
116
+ Hash.new { |h,k| h[k] = ops }
117
+ end
118
+
119
+ def logic_text
120
+ {
121
+ Octo::Segmentation::Operators::AND => 'AND',
122
+ Octo::Segmentation::Operators::OR => 'OR',
123
+ Octo::Segmentation::Operators::NOT => 'NOT',
124
+ Octo::Segmentation::Operators::XOR => 'XOR',
125
+ }
126
+ end
127
+
128
+ # Generates the city choices for the enterprise
129
+ # @param [String] enterprise_id The enterpriseID for which city choices
130
+ # to be found
131
+ # @return [Array<String>] Array of string values
132
+ def city_choices(enterprise_id=nil)
133
+ ['New Delhi', 'Mumbai', 'Bengaluru', 'San Francisco', 'Seattle']
134
+ end
135
+
136
+ def state_choices(enterprise_id=nil)
137
+ ['Delhi', 'Maharashtra', 'Karnataka', 'California']
138
+ end
139
+
140
+ def country_choices(enterprise_id=nil)
141
+ ['India', 'United States of America (USA)']
142
+ end
143
+
144
+ def os_choices(enterprise_id=nil)
145
+ ['Windows', 'OS X', 'iOS', 'android']
146
+ end
147
+
148
+ def manufacturer_choices(enterprise_id=nil)
149
+ ['Apple', 'Dell', 'HP', 'Samsung', 'Micromax']
150
+ end
151
+
152
+ def browser_choices(enterprise_id=nil)
153
+ ['Firefox', 'Chrome', 'Safari']
154
+ end
155
+
156
+ def model_choices(enterprise_id=nil)
157
+ ['iPhone 6', 'iPhone 6s', 'iPhone 5', 'Samsung S6']
158
+ end
159
+
160
+ def engagement_choices(enterprise_id=nil)
161
+ [Octo::UserPersona::HIGH_ENGAGED,
162
+ Octo::UserPersona::MEDIUM_ENGAGED,
163
+ Octo::UserPersona::LOW_ENGAGED,
164
+ Octo::UserPersona::DEAD].collect { |x| Octo::UserPersona.engaged_text(x) }
165
+ end
166
+
167
+
168
+ # Converts a hash mapping into choices ready for UX
169
+ # @return [Array<Hash{Symbol => String }>] The hash containing key :text
170
+ # as the text to display, and another key :id as the id to be used
171
+ # as reference while communicating
172
+ def mapping_as_choice(map)
173
+ map.inject([]) do | choices, pair |
174
+ key, val = pair
175
+ choices << { text: val, id: key }
176
+ end
177
+ end
178
+
179
+ end
180
+ end
181
+
182
+ module SegmentType
183
+
184
+ USER = 0
185
+ EVENT = 1
186
+ end
187
+
188
+ # The Operators modules. Defines Operators and necessary methods around
189
+ module Operators
190
+
191
+ EQUAL = 0
192
+ NOT_EQUAL = 1
193
+ GTE = 2
194
+ GT = 3
195
+ LTE = 4
196
+ LT = 5
197
+ IN = 6
198
+ AND = 7
199
+ OR = 8
200
+ NOT = 9
201
+ XOR = 10
202
+
203
+ class << self
204
+
205
+ # Returns if the given operator is valid or not
206
+ def valid?(operator)
207
+ Set.new([EQUAL, NOT_EQUAL, GTE, GT, LTE, LT, IN]).include?(operator.to_i)
208
+ end
209
+
210
+ end
211
+ end
212
+
213
+ # The Dimensions module. Defines the dimensions possible and its abstraction
214
+ module Dimensions
215
+
216
+ # Geographical Dimensions seems most obvious
217
+ CITY = 0
218
+ STATE = 1
219
+ COUNTRY = 2
220
+
221
+ # Followed by User's device details
222
+ OS = 3
223
+ MANUFACTURER = 4
224
+ BROWSER = 5
225
+ MODEL = 6
226
+
227
+ # Followed by User's engagement patterns
228
+ ENGAGEMENT = 7
229
+
230
+ # What about their last active, created dates
231
+ LAST_ACTIVE = 8
232
+ CREATED_ON = 9
233
+
234
+ # Usage Pattern
235
+ DAYTIME_USAGE = 10
236
+
237
+
238
+ end
239
+
240
+ # Extend
241
+ module ClassMethods
242
+
243
+ # Returns a boolean specifying if the segment is a valid choice or not
244
+ # @param [String] segment The string to be evaluated
245
+ # @return [Boolean] If the provided string exists in valid choices
246
+ def is_valid_segment segment
247
+ all_segment_choices.include?segment
248
+ end
249
+
250
+ # Returns all possible segment choices. Segment choices are the first
251
+ # data point that is picked on top of which segment would be made. It
252
+ # could be one of the supported octo events (eg: app.init etc) or users
253
+ def all_segment_choices
254
+ valid_events << :users
255
+ end
256
+
257
+ private
258
+
259
+ # Get all the valid events
260
+ # @return [Set<Symbol>] Valid events globally
261
+ def valid_events
262
+ Set.new(Octo.get_config(:allowed_events))
263
+ end
264
+
265
+
266
+
267
+ # Merges choices and returns the set with opts taken care of
268
+ # @param [Array] c The initial choices
269
+ # @param [Hash] opts Optional hash specifying anything to be exluded or
270
+ # included
271
+ # @option opts [Array<String>] :include Strings to be included in choices
272
+ # @option opts [Array<String>] :exclude Strings to be excluded in choices
273
+ # @return [Array<String>] Merged choices
274
+ def merge_choices(c, opts={})
275
+ Set.new(c).merge(
276
+ Set.new(opts.fetch(:include, []))
277
+ ).subtract(
278
+ Set.new(opts.fetch(:exclude, []))
279
+ )
280
+ end
281
+
282
+
283
+ end
284
+
285
+ end
286
+ end
287
+