ahoy_matey 1.6.1 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (95) hide show
  1. checksums.yaml +4 -4
  2. data/.github/ISSUE_TEMPLATE.md +7 -0
  3. data/CHANGELOG.md +22 -0
  4. data/CONTRIBUTING.md +40 -0
  5. data/LICENSE.txt +1 -1
  6. data/README.md +210 -489
  7. data/Rakefile +1 -0
  8. data/ahoy_matey.gemspec +6 -8
  9. data/app/controllers/ahoy/base_controller.rb +2 -6
  10. data/app/controllers/ahoy/events_controller.rb +7 -1
  11. data/app/controllers/ahoy/visits_controller.rb +7 -1
  12. data/app/jobs/ahoy/geocode_job.rb +10 -0
  13. data/app/jobs/ahoy/geocode_v2_job.rb +29 -0
  14. data/config/routes.rb +1 -1
  15. data/docs/Ahoy-2-Upgrade.md +147 -0
  16. data/docs/Data-Store-Examples.md +240 -0
  17. data/lib/ahoy.rb +30 -88
  18. data/lib/ahoy/base_store.rb +72 -0
  19. data/lib/ahoy/controller.rb +4 -10
  20. data/lib/ahoy/database_store.rb +72 -0
  21. data/lib/ahoy/engine.rb +5 -7
  22. data/lib/ahoy/model.rb +4 -26
  23. data/lib/ahoy/{properties.rb → query_methods.rb} +18 -4
  24. data/lib/ahoy/tracker.rb +60 -38
  25. data/lib/ahoy/version.rb +1 -1
  26. data/lib/ahoy/visit_properties.rb +65 -39
  27. data/lib/generators/ahoy/activerecord_generator.rb +58 -0
  28. data/lib/generators/ahoy/base_generator.rb +13 -0
  29. data/lib/generators/ahoy/install_generator.rb +44 -0
  30. data/lib/generators/ahoy/mongoid_generator.rb +20 -0
  31. data/lib/generators/ahoy/templates/active_record_event_model.rb +10 -0
  32. data/lib/generators/ahoy/{stores/templates/active_record_visits_migration.rb → templates/active_record_migration.rb} +19 -21
  33. data/lib/generators/ahoy/templates/active_record_visit_model.rb +6 -0
  34. data/lib/generators/ahoy/templates/base_store_initializer.rb +17 -0
  35. data/lib/generators/ahoy/templates/database_store_initializer.rb +5 -0
  36. data/lib/generators/ahoy/{stores/templates → templates}/mongoid_event_model.rb +4 -2
  37. data/lib/generators/ahoy/{stores/templates → templates}/mongoid_visit_model.rb +7 -3
  38. data/test/query_methods/mongoid_test.rb +23 -0
  39. data/test/{properties → query_methods}/mysql_json_test.rb +1 -1
  40. data/test/{properties → query_methods}/mysql_text_test.rb +1 -1
  41. data/test/{properties → query_methods}/postgresql_hstore_test.rb +1 -1
  42. data/test/{properties → query_methods}/postgresql_json_test.rb +1 -1
  43. data/test/{properties → query_methods}/postgresql_jsonb_test.rb +1 -1
  44. data/test/{properties → query_methods}/postgresql_text_test.rb +1 -1
  45. data/test/test_helper.rb +4 -3
  46. data/vendor/assets/javascripts/ahoy.js +551 -325
  47. metadata +67 -112
  48. data/lib/ahoy/deckhands/location_deckhand.rb +0 -49
  49. data/lib/ahoy/deckhands/request_deckhand.rb +0 -52
  50. data/lib/ahoy/deckhands/technology_deckhand.rb +0 -47
  51. data/lib/ahoy/deckhands/traffic_source_deckhand.rb +0 -22
  52. data/lib/ahoy/deckhands/utm_parameter_deckhand.rb +0 -23
  53. data/lib/ahoy/geocode_job.rb +0 -13
  54. data/lib/ahoy/logger_silencer.rb +0 -75
  55. data/lib/ahoy/stores/active_record_store.rb +0 -61
  56. data/lib/ahoy/stores/active_record_token_store.rb +0 -114
  57. data/lib/ahoy/stores/base_store.rb +0 -88
  58. data/lib/ahoy/stores/bunny_store.rb +0 -33
  59. data/lib/ahoy/stores/fluentd_store.rb +0 -17
  60. data/lib/ahoy/stores/kafka_store.rb +0 -42
  61. data/lib/ahoy/stores/kinesis_firehose_store.rb +0 -42
  62. data/lib/ahoy/stores/log_store.rb +0 -53
  63. data/lib/ahoy/stores/mongoid_store.rb +0 -63
  64. data/lib/ahoy/stores/nats_store.rb +0 -34
  65. data/lib/ahoy/stores/nsq_store.rb +0 -36
  66. data/lib/ahoy/subscribers/active_record.rb +0 -19
  67. data/lib/ahoy/throttle.rb +0 -17
  68. data/lib/generators/ahoy/stores/active_record_events_generator.rb +0 -59
  69. data/lib/generators/ahoy/stores/active_record_generator.rb +0 -16
  70. data/lib/generators/ahoy/stores/active_record_visits_generator.rb +0 -49
  71. data/lib/generators/ahoy/stores/bunny_generator.rb +0 -15
  72. data/lib/generators/ahoy/stores/custom_generator.rb +0 -15
  73. data/lib/generators/ahoy/stores/fluentd_generator.rb +0 -15
  74. data/lib/generators/ahoy/stores/kafka_generator.rb +0 -15
  75. data/lib/generators/ahoy/stores/kinesis_firehose_generator.rb +0 -15
  76. data/lib/generators/ahoy/stores/log_generator.rb +0 -15
  77. data/lib/generators/ahoy/stores/mongoid_events_generator.rb +0 -19
  78. data/lib/generators/ahoy/stores/mongoid_generator.rb +0 -14
  79. data/lib/generators/ahoy/stores/mongoid_visits_generator.rb +0 -27
  80. data/lib/generators/ahoy/stores/nats_generator.rb +0 -15
  81. data/lib/generators/ahoy/stores/nsq_generator.rb +0 -15
  82. data/lib/generators/ahoy/stores/templates/active_record_event_model.rb +0 -12
  83. data/lib/generators/ahoy/stores/templates/active_record_events_migration.rb +0 -20
  84. data/lib/generators/ahoy/stores/templates/active_record_initializer.rb +0 -3
  85. data/lib/generators/ahoy/stores/templates/active_record_visit_model.rb +0 -4
  86. data/lib/generators/ahoy/stores/templates/bunny_initializer.rb +0 -9
  87. data/lib/generators/ahoy/stores/templates/custom_initializer.rb +0 -10
  88. data/lib/generators/ahoy/stores/templates/fluentd_initializer.rb +0 -3
  89. data/lib/generators/ahoy/stores/templates/kafka_initializer.rb +0 -9
  90. data/lib/generators/ahoy/stores/templates/kinesis_firehose_initializer.rb +0 -17
  91. data/lib/generators/ahoy/stores/templates/log_initializer.rb +0 -3
  92. data/lib/generators/ahoy/stores/templates/mongoid_initializer.rb +0 -3
  93. data/lib/generators/ahoy/stores/templates/nats_initializer.rb +0 -9
  94. data/lib/generators/ahoy/stores/templates/nsq_initializer.rb +0 -9
  95. data/test/visit_properties_test.rb +0 -44
@@ -1,42 +0,0 @@
1
- module Ahoy
2
- module Stores
3
- class KafkaStore < LogStore
4
- def log_visit(data)
5
- post(visits_topic, data)
6
- end
7
-
8
- def log_event(data)
9
- post(events_topic, data)
10
- end
11
-
12
- def client
13
- @client ||= begin
14
- Kafka.new(
15
- seed_brokers: ENV["KAFKA_URL"] || "localhost:9092",
16
- logger: Rails.logger
17
- )
18
- end
19
- end
20
-
21
- def producer
22
- @producer ||= begin
23
- producer = client.async_producer(delivery_interval: 3)
24
- at_exit { producer.shutdown }
25
- producer
26
- end
27
- end
28
-
29
- def post(topic, data)
30
- producer.produce(data.to_json, topic: topic)
31
- end
32
-
33
- def visits_topic
34
- "ahoy_visits"
35
- end
36
-
37
- def events_topic
38
- "ahoy_events"
39
- end
40
- end
41
- end
42
- end
@@ -1,42 +0,0 @@
1
- module Ahoy
2
- module Stores
3
- class KinesisFirehoseStore < LogStore
4
- def log_visit(data)
5
- post(visits_stream, data)
6
- end
7
-
8
- def log_event(data)
9
- post(events_stream, data)
10
- end
11
-
12
- def client
13
- @client ||= Aws::Firehose::Client.new(credentials)
14
- end
15
-
16
- def post(stream, data)
17
- client.put_record(
18
- delivery_stream_name: stream,
19
- record: {
20
- data: "#{data.to_json}\n"
21
- }
22
- )
23
- end
24
-
25
- def credentials
26
- {
27
- access_key_id: ENV["AWS_ACCESS_KEY_ID"],
28
- secret_access_key: ENV["AWS_SECRET_ACCESS_KEY"],
29
- region: "us-east-1"
30
- }
31
- end
32
-
33
- def visits_stream
34
- "ahoy_visits"
35
- end
36
-
37
- def events_stream
38
- "ahoy_events"
39
- end
40
- end
41
- end
42
- end
@@ -1,53 +0,0 @@
1
- module Ahoy
2
- module Stores
3
- class LogStore < BaseStore
4
- def track_visit(options, &block)
5
- data = {
6
- id: ahoy.visit_id,
7
- visitor_id: ahoy.visitor_id
8
- }.merge(visit_properties.to_hash)
9
- data[:user_id] = user.id if user
10
- data[:started_at] = options[:started_at]
11
-
12
- yield(data) if block_given?
13
-
14
- log_visit(data)
15
- end
16
-
17
- def track_event(name, properties, options, &block)
18
- data = {
19
- id: options[:id],
20
- name: name,
21
- properties: properties,
22
- visit_id: ahoy.visit_id,
23
- visitor_id: ahoy.visitor_id
24
- }
25
- data[:user_id] = user.id if user
26
- data[:time] = options[:time]
27
-
28
- yield(data) if block_given?
29
-
30
- log_event(data)
31
- end
32
-
33
- protected
34
-
35
- def log_visit(data)
36
- visit_logger.info data.to_json
37
- end
38
-
39
- def log_event(data)
40
- event_logger.info data.to_json
41
- end
42
-
43
- # TODO disable header
44
- def visit_logger
45
- @visit_logger ||= ActiveSupport::Logger.new(Rails.root.join("log/visits.log"))
46
- end
47
-
48
- def event_logger
49
- @event_logger ||= ActiveSupport::Logger.new(Rails.root.join("log/events.log"))
50
- end
51
- end
52
- end
53
- end
@@ -1,63 +0,0 @@
1
- module Ahoy
2
- module Stores
3
- class MongoidStore < BaseStore
4
- def track_visit(options, &block)
5
- @visit =
6
- visit_model.new do |v|
7
- v.id = binary(ahoy.visit_id)
8
- v.visitor_id = binary(ahoy.visitor_id)
9
- v.user = user if v.respond_to?(:user=) && user
10
- v.started_at = options[:started_at]
11
- end
12
-
13
- set_visit_properties(visit)
14
-
15
- yield(visit) if block_given?
16
-
17
- visit.upsert
18
- geocode(visit)
19
- end
20
-
21
- def track_event(name, properties, options, &block)
22
- event =
23
- event_model.new do |e|
24
- e.id = binary(options[:id])
25
- e.visit_id = binary(ahoy.visit_id)
26
- e.user = user if e.respond_to?(:user)
27
- e.name = name
28
- e.properties = properties
29
- e.time = options[:time]
30
- end
31
-
32
- yield(event) if block_given?
33
-
34
- event.upsert
35
- end
36
-
37
- def visit
38
- @visit ||= visit_model.where(_id: binary(ahoy.visit_id)).first if ahoy.visit_id
39
- end
40
-
41
- protected
42
-
43
- def visit_model
44
- ::Visit
45
- end
46
-
47
- def event_model
48
- ::Ahoy::Event
49
- end
50
-
51
- def binary(token)
52
- token = token.delete("-")
53
- if defined?(::BSON)
54
- ::BSON::Binary.new(token, :uuid)
55
- elsif defined?(::Moped::BSON)
56
- ::Moped::BSON::Binary.new(:uuid, token)
57
- else
58
- token
59
- end
60
- end
61
- end
62
- end
63
- end
@@ -1,34 +0,0 @@
1
- module Ahoy
2
- module Stores
3
- class NatsStore < LogStore
4
- def log_visit(data)
5
- publish(visits_subject, data)
6
- end
7
-
8
- def log_event(data)
9
- publish(events_subject, data)
10
- end
11
-
12
- def publish(subject, data)
13
- client.publish(subject, data.to_json)
14
- end
15
-
16
- def client
17
- @client ||= begin
18
- require "nats/io/client"
19
- client = NATS::IO::Client.new
20
- client.connect(servers: (ENV["NATS_URL"] || "nats://127.0.0.1:4222").split(","))
21
- client
22
- end
23
- end
24
-
25
- def visits_subject
26
- "ahoy_visits"
27
- end
28
-
29
- def events_subject
30
- "ahoy_events"
31
- end
32
- end
33
- end
34
- end
@@ -1,36 +0,0 @@
1
- module Ahoy
2
- module Stores
3
- class NsqStore < LogStore
4
- def log_visit(data)
5
- post(visits_topic, data)
6
- end
7
-
8
- def log_event(data)
9
- post(events_topic, data)
10
- end
11
-
12
- def client
13
- @client ||= begin
14
- require "nsq"
15
- client = Nsq::Producer.new(
16
- nsqd: ENV["NSQ_URL"] || "127.0.0.1:4150"
17
- )
18
- at_exit { client.terminate }
19
- client
20
- end
21
- end
22
-
23
- def post(topic, data)
24
- client.write_to_topic(topic, data.to_json)
25
- end
26
-
27
- def visits_topic
28
- "ahoy_visits"
29
- end
30
-
31
- def events_topic
32
- "ahoy_events"
33
- end
34
- end
35
- end
36
- end
@@ -1,19 +0,0 @@
1
- module Ahoy
2
- module Subscribers
3
- class ActiveRecord
4
- def initialize(options = {})
5
- @model = options[:model] || Ahoy::Event
6
- end
7
-
8
- def track(name, properties, options = {})
9
- @model.create! do |e|
10
- e.visit = options[:visit]
11
- e.user = options[:user]
12
- e.name = name
13
- e.properties = properties
14
- e.time = options[:time]
15
- end
16
- end
17
- end
18
- end
19
- end
data/lib/ahoy/throttle.rb DELETED
@@ -1,17 +0,0 @@
1
- require "rack/attack"
2
-
3
- module Ahoy
4
- class Throttle < Rack::Attack
5
- throttle("ahoy/ip", limit: Ahoy.throttle_limit, period: Ahoy.throttle_period) do |req|
6
- if req.path.start_with?("/ahoy/")
7
- req.ip
8
- end
9
- end
10
-
11
- def_delegators self, :whitelisted?, :blacklisted?, :throttled?, :tracked?, :blocklisted?, :safelisted?
12
-
13
- def self.throttled_response
14
- Rack::Attack.throttled_response
15
- end
16
- end
17
- end
@@ -1,59 +0,0 @@
1
- # taken from https://github.com/collectiveidea/audited/blob/master/lib/generators/audited/install_generator.rb
2
- require "rails/generators"
3
- require "rails/generators/migration"
4
- require "active_record"
5
- require "rails/generators/active_record"
6
-
7
- module Ahoy
8
- module Stores
9
- module Generators
10
- class ActiveRecordEventsGenerator < Rails::Generators::Base
11
- include Rails::Generators::Migration
12
- source_root File.expand_path("../templates", __FILE__)
13
-
14
- class_option :database, type: :string, aliases: "-d"
15
-
16
- # Implement the required interface for Rails::Generators::Migration.
17
- def self.next_migration_number(dirname) #:nodoc:
18
- next_migration_number = current_migration_number(dirname) + 1
19
- if ::ActiveRecord::Base.timestamped_migrations
20
- [Time.now.utc.strftime("%Y%m%d%H%M%S"), "%.14d" % next_migration_number].max
21
- else
22
- "%.3d" % next_migration_number
23
- end
24
- end
25
-
26
- def copy_migration
27
- @database = options["database"] || detect_database
28
- unless @database.in?([nil, "postgresql", "postgresql-jsonb", "mysql", "sqlite"])
29
- raise Thor::Error, "Unknown database option"
30
- end
31
- migration_template "active_record_events_migration.rb", "db/migrate/create_ahoy_events.rb", migration_version: migration_version
32
- end
33
-
34
- def generate_model
35
- template "active_record_event_model.rb", "app/models/ahoy/event.rb"
36
- end
37
-
38
- def create_initializer
39
- template "active_record_initializer.rb", "config/initializers/ahoy.rb"
40
- end
41
-
42
- def detect_database
43
- postgresql_version = ActiveRecord::Base.connection.send(:postgresql_version) rescue 0
44
- if postgresql_version >= 90400
45
- "postgresql-jsonb"
46
- elsif postgresql_version >= 90200
47
- "postgresql"
48
- end
49
- end
50
-
51
- def migration_version
52
- if ActiveRecord::VERSION::MAJOR >= 5
53
- "[#{ActiveRecord::VERSION::MAJOR}.#{ActiveRecord::VERSION::MINOR}]"
54
- end
55
- end
56
- end
57
- end
58
- end
59
- end
@@ -1,16 +0,0 @@
1
- require "rails/generators"
2
-
3
- module Ahoy
4
- module Stores
5
- module Generators
6
- class ActiveRecordGenerator < Rails::Generators::Base
7
- class_option :database, type: :string, aliases: "-d"
8
-
9
- def boom
10
- invoke "ahoy:stores:active_record_visits", nil, options
11
- invoke "ahoy:stores:active_record_events", nil, options
12
- end
13
- end
14
- end
15
- end
16
- end
@@ -1,49 +0,0 @@
1
- # taken from https://github.com/collectiveidea/audited/blob/master/lib/generators/audited/install_generator.rb
2
- require "rails/generators"
3
- require "rails/generators/migration"
4
- require "active_record"
5
- require "rails/generators/active_record"
6
-
7
- module Ahoy
8
- module Stores
9
- module Generators
10
- class ActiveRecordVisitsGenerator < Rails::Generators::Base
11
- include Rails::Generators::Migration
12
- source_root File.expand_path("../templates", __FILE__)
13
-
14
- class_option :database, type: :string, aliases: "-d"
15
-
16
- # Implement the required interface for Rails::Generators::Migration.
17
- def self.next_migration_number(dirname) #:nodoc:
18
- next_migration_number = current_migration_number(dirname) + 1
19
- if ::ActiveRecord::Base.timestamped_migrations
20
- [Time.now.utc.strftime("%Y%m%d%H%M%S"), "%.14d" % next_migration_number].max
21
- else
22
- "%.3d" % next_migration_number
23
- end
24
- end
25
-
26
- def copy_migration
27
- unless options["database"].in?([nil, "postgresql", "postgresql-jsonb"])
28
- raise Thor::Error, "Unknown database option"
29
- end
30
- migration_template "active_record_visits_migration.rb", "db/migrate/create_visits.rb", migration_version: migration_version
31
- end
32
-
33
- def generate_model
34
- template "active_record_visit_model.rb", "app/models/visit.rb"
35
- end
36
-
37
- def create_initializer
38
- template "active_record_initializer.rb", "config/initializers/ahoy.rb"
39
- end
40
-
41
- def migration_version
42
- if ActiveRecord::VERSION::MAJOR >= 5
43
- "[#{ActiveRecord::VERSION::MAJOR}.#{ActiveRecord::VERSION::MINOR}]"
44
- end
45
- end
46
- end
47
- end
48
- end
49
- end