plausible_api 0.1.9 → 0.2

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 946cc54d639da26e6d4e835df896ed3aa2237e9abf9c184085c28c7eafff0497
4
- data.tar.gz: c98ccc5b1060614edc3141282589fa5158d1367544699efadb89c5ff9aecb0f0
3
+ metadata.gz: 77c960fb14e022fa7f1ae47a7c38903325d188d98c67ac598977812326b616be
4
+ data.tar.gz: 4d0ed7d883293c49bfb518d544efbad968b544d249cb0bfc05ff5366c87a325e
5
5
  SHA512:
6
- metadata.gz: 9ce81d99cd4cce297c3cd388af7836e7f1415d6b5a04e83e51da7e44ba3bb042c8a97e7f9c059e1f1c69ad688e306c9cb98ed6c360e6afe26b908075a52e0063
7
- data.tar.gz: 21f54c76bd3a314748258681f34604e93928c257e663ff0f5df33bad13b5d5189feb9ecad6b1360e276160ad4dd11aa1e91c825ea2e2b8105827a6a63dbfdb17
6
+ metadata.gz: 6247be2a8f503c75bbff787771f1189598426171275122b6dddcc6581354db6ea3e2f81dd5c0ccc247c92ab7587f5f00c32ccc3d83b050ab70ff1470866bbbcb
7
+ data.tar.gz: 395a7b263fcfb9ce374f7e2d734a3d2ed608fd11755c4a6087fabc89a299da084fe5411063707e7066371660c1784ca2fa900d434d0daaefe8f00c398974dd7e
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- plausible_api (0.1.9)
4
+ plausible_api (0.2)
5
5
 
6
6
  GEM
7
7
  remote: https://rubygems.org/
data/README.md CHANGED
@@ -9,7 +9,7 @@ gem 'plausible_api'
9
9
  ```
10
10
  Then you need to initialize a Client with your `site_id` (the domain) and your `token`.
11
11
  ```rb
12
- c = PlausibleApi::Client.new('dailytics.com', '123123')
12
+ c = PlausibleApi::Client.new('dailytics.com', '123123')
13
13
 
14
14
  # Test if the site and token are valid
15
15
  c.valid?
@@ -73,6 +73,19 @@ c.realtime_visitors
73
73
  => 13
74
74
  ```
75
75
 
76
+ ### Events
77
+
78
+ You can send an event like this:
79
+
80
+ ```rb
81
+ # Example using Rack::Request in Rails for user_agent and ip.
82
+ c.event({
83
+ name: "signup",
84
+ url: 'https://dailytics.com/users/new',
85
+ user_agent: "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.3",
86
+ ip: "127.0.0.1"
87
+ })
88
+ ```
76
89
 
77
90
  ## Development
78
91
 
data/examples/basic.rb ADDED
@@ -0,0 +1,5 @@
1
+ require 'bundler/setup'
2
+ require 'plausible_api'
3
+
4
+ client = PlausibleApi::Client.new(ENV["SITE_ID"], ENV["TOKEN"])
5
+ p client.valid?
data/examples/event.rb ADDED
@@ -0,0 +1,23 @@
1
+ require 'bundler/setup'
2
+ require 'plausible_api'
3
+
4
+ client = PlausibleApi::Client.new(ENV["SITE_ID"], ENV["TOKEN"])
5
+
6
+ # default all the things, pointless but works
7
+ p client.event
8
+
9
+ # change the name
10
+ p client.event(
11
+ name: "test",
12
+ )
13
+
14
+ # send the whole kitchen sink
15
+ p client.event(
16
+ ip: "127.0.0.1",
17
+ user_agent: "test",
18
+ name: "test",
19
+ url: "app://localhost/test",
20
+ referrer: "https://example.com",
21
+ revenue: {currency: "USD", amount: 1.00},
22
+ props: {foo: "bar"},
23
+ )
@@ -1,24 +1,25 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'plausible_api/stats/base'
4
- require 'plausible_api/stats/realtime/visitors'
5
- require 'plausible_api/stats/aggregate'
6
- require 'plausible_api/stats/timeseries'
7
- require 'plausible_api/stats/breakdown'
3
+ require "plausible_api/stats/base"
4
+ require "plausible_api/stats/realtime/visitors"
5
+ require "plausible_api/stats/aggregate"
6
+ require "plausible_api/stats/timeseries"
7
+ require "plausible_api/stats/breakdown"
8
+ require "plausible_api/event/base"
9
+ require "plausible_api/event/post"
8
10
 
9
- require 'json'
11
+ require "json"
10
12
  require "net/http"
11
13
  require "uri"
12
14
  require "cgi"
13
15
 
14
16
  module PlausibleApi
15
17
  class Client
16
-
17
- BASE_URL = 'https://plausible.io'
18
+ BASE_URL = "https://plausible.io"
18
19
 
19
20
  def initialize(site_id, token)
20
21
  @site_id = site_id.to_s
21
- @token = token.to_s
22
+ @token = token.to_s
22
23
  end
23
24
 
24
25
  def aggregate(options = {})
@@ -38,34 +39,41 @@ module PlausibleApi
38
39
  end
39
40
 
40
41
  def valid?
41
- begin
42
- realtime_visitors
43
- return true
44
- rescue
45
- return false
46
- end
42
+ realtime_visitors
43
+ true
44
+ rescue
45
+ false
46
+ end
47
+
48
+ def event(options = {})
49
+ call PlausibleApi::Event::Post.new(options.merge(domain: @site_id))
47
50
  end
48
51
 
49
52
  private
50
- def call(api)
53
+
54
+ SUCCESS_CODES = %w[200 202].freeze
55
+
56
+ def call(api)
51
57
  raise StandardError.new api.errors unless api.valid?
52
-
53
- url = "#{BASE_URL}#{api.request_url.gsub('$SITE_ID', @site_id)}"
58
+
59
+ url = "#{BASE_URL}#{api.request_url.gsub("$SITE_ID", @site_id)}"
54
60
  uri = URI.parse(url)
55
61
 
56
- req = Net::HTTP::Get.new(uri.request_uri)
57
- req.add_field('Authorization', "Bearer #{@token}")
62
+ req = api.request_class.new(uri.request_uri)
63
+ req.initialize_http_header(api.request_headers)
64
+ req.add_field("authorization", "Bearer #{@token}") if api.request_auth?
65
+ req.body = api.request_body if api.request_body?
58
66
 
59
67
  http = Net::HTTP.new(uri.host, uri.port)
60
- http.use_ssl = true
68
+ http.use_ssl = true
61
69
 
62
70
  response = http.request(req)
63
71
 
64
- if response.code == "200"
72
+ if SUCCESS_CODES.include?(response.code)
65
73
  api.parse_response response.body
66
74
  else
67
75
  raise StandardError.new response.body
68
76
  end
69
77
  end
70
78
  end
71
- end
79
+ end
@@ -0,0 +1,31 @@
1
+ module PlausibleApi
2
+ module Event
3
+ class Base
4
+ DEFAULT_USER_AGENT = "plausible_api_ruby/#{PlausibleApi::VERSION}"
5
+
6
+ def request_class
7
+ Net::HTTP::Post
8
+ end
9
+
10
+ def request_url_base
11
+ "/api/event"
12
+ end
13
+
14
+ def request_url
15
+ request_url_base
16
+ end
17
+
18
+ def request_auth?
19
+ false
20
+ end
21
+
22
+ def request_body?
23
+ true
24
+ end
25
+
26
+ def valid?
27
+ errors.empty?
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,101 @@
1
+ # frozen_string_literal: true
2
+
3
+ module PlausibleApi
4
+ module Event
5
+ class Post < Base
6
+ DEFAULT_USER_AGENT = "plausible_api_ruby/#{PlausibleApi::VERSION}"
7
+ VALID_REVENUE_KEYS = %i[amount currency].freeze
8
+ OPTIONS_IN_HEADERS = %i[ip user_agent].freeze
9
+
10
+ attr_reader :domain
11
+ attr_reader :ip, :user_agent, :url
12
+ attr_reader :name, :props, :referrer, :revenue
13
+
14
+ def initialize(options = {})
15
+ @options = options.transform_keys(&:to_sym)
16
+
17
+ @domain = @options[:domain]
18
+ @ip = @options[:ip]
19
+ @user_agent = presence(@options[:user_agent]) || DEFAULT_USER_AGENT
20
+ @name = presence(@options[:name]) || "pageview"
21
+ @url = presence(@options[:url]) || "app://localhost/#{@name}"
22
+ @referrer = @options[:referrer]
23
+ @revenue = @options[:revenue]
24
+ @props = @options[:props]
25
+ end
26
+
27
+ def request_body
28
+ data = {
29
+ url: @url,
30
+ name: @name,
31
+ domain: @domain
32
+ }
33
+
34
+ data[:props] = @props if present?(@props)
35
+ data[:revenue] = @revenue if present?(@revenue)
36
+ data[:referrer] = @referrer if present?(@referrer)
37
+
38
+ JSON.generate(data)
39
+ end
40
+
41
+ def request_headers
42
+ headers = {
43
+ "content-type" => "application/json",
44
+ "user-agent" => @user_agent
45
+ }
46
+ headers["x-forwarded-for"] = @ip if present?(@ip)
47
+ headers
48
+ end
49
+
50
+ def parse_response(body)
51
+ body == "ok"
52
+ end
53
+
54
+ def errors
55
+ errors = []
56
+ errors.push(url: "url is required") if blank?(@url)
57
+ errors.push(name: "name is required") if blank?(@name)
58
+ errors.push(domain: "domain is required") if blank?(@domain)
59
+ errors.push(user_agent: "user_agent is required") if blank?(@user_agent)
60
+
61
+ if present?(@revenue)
62
+ if @revenue.is_a?(Hash)
63
+ unless valid_revenue_keys?(@revenue)
64
+ errors.push(
65
+ revenue: "revenue must have keys #{VALID_REVENUE_KEYS.join(", ")} " \
66
+ "but was #{@revenue.inspect}"
67
+ )
68
+ end
69
+ else
70
+ errors.push(revenue: "revenue must be a Hash")
71
+ end
72
+ end
73
+
74
+ if present?(@props) && !@props.is_a?(Hash)
75
+ errors.push(props: "props must be a Hash")
76
+ end
77
+
78
+ errors
79
+ end
80
+
81
+ private
82
+
83
+ def valid_revenue_keys?(revenue)
84
+ revenue.keys.sort.map(&:to_sym) == VALID_REVENUE_KEYS.sort
85
+ end
86
+
87
+ def present?(value)
88
+ !value.nil? && !value.empty?
89
+ end
90
+
91
+ def blank?(value)
92
+ !present?(value)
93
+ end
94
+
95
+ def presence(value)
96
+ return nil if blank?(value)
97
+ value
98
+ end
99
+ end
100
+ end
101
+ end
@@ -6,7 +6,7 @@ module PlausibleApi
6
6
 
7
7
  def initialize(options = {})
8
8
  super({ period: '30d',
9
- metrics: 'visitors,pageviews,bounce_rate,visit_duration' }
9
+ metrics: 'visitors,visits,pageviews,views_per_visit,bounce_rate,visit_duration,events' }
10
10
  .merge(options))
11
11
  end
12
12
 
@@ -19,4 +19,4 @@ module PlausibleApi
19
19
  end
20
20
  end
21
21
  end
22
- end
22
+ end
@@ -15,11 +15,31 @@ module PlausibleApi
15
15
  raise NotImplementedError
16
16
  end
17
17
 
18
+ def request_class
19
+ Net::HTTP::Get
20
+ end
21
+
22
+ def request_body?
23
+ false
24
+ end
25
+
26
+ def request_body
27
+ nil
28
+ end
29
+
18
30
  def request_url
19
31
  params = @options.select{ |_,v| !v.to_s.empty? }
20
32
  [request_url_base, URI.encode_www_form(params)].reject{|e| e.empty?}.join('&')
21
33
  end
22
34
 
35
+ def request_headers
36
+ {}
37
+ end
38
+
39
+ def request_auth?
40
+ true
41
+ end
42
+
23
43
  def parse_response(body)
24
44
  raise NotImplementedError
25
45
  end
@@ -30,7 +50,7 @@ module PlausibleApi
30
50
 
31
51
  def errors
32
52
  allowed_period = %w(12mo 6mo month 30d 7d day custom)
33
- allowed_metrics = %w(visitors pageviews bounce_rate visit_duration)
53
+ allowed_metrics = %w(visitors visits pageviews views_per_visit bounce_rate visit_duration events)
34
54
  allowed_compare = %w(previous_period)
35
55
  allowed_interval = %w(date month)
36
56
  allowed_property = %w(event:page visit:entry_page visit:exit_page visit:source visit:referrer
@@ -1,3 +1,3 @@
1
1
  module PlausibleApi
2
- VERSION = "0.1.9"
2
+ VERSION = "0.2"
3
3
  end
data/lib/plausible_api.rb CHANGED
@@ -1,5 +1,5 @@
1
- require 'plausible_api/version'
2
- require 'plausible_api/client'
1
+ require "plausible_api/version"
2
+ require "plausible_api/client"
3
3
 
4
4
  module PlausibleApi
5
5
  class Error < StandardError; end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: plausible_api
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.9
4
+ version: '0.2'
5
5
  platform: ruby
6
6
  authors:
7
7
  - Gustavo Garcia
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2021-10-18 00:00:00.000000000 Z
11
+ date: 2023-12-23 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: A very humble wrapper for the new API by Plausible
14
14
  email:
@@ -26,8 +26,12 @@ files:
26
26
  - Rakefile
27
27
  - bin/console
28
28
  - bin/setup
29
+ - examples/basic.rb
30
+ - examples/event.rb
29
31
  - lib/plausible_api.rb
30
32
  - lib/plausible_api/client.rb
33
+ - lib/plausible_api/event/base.rb
34
+ - lib/plausible_api/event/post.rb
31
35
  - lib/plausible_api/stats/aggregate.rb
32
36
  - lib/plausible_api/stats/base.rb
33
37
  - lib/plausible_api/stats/breakdown.rb
@@ -57,7 +61,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
57
61
  - !ruby/object:Gem::Version
58
62
  version: '0'
59
63
  requirements: []
60
- rubygems_version: 3.1.4
64
+ rubygems_version: 3.3.7
61
65
  signing_key:
62
66
  specification_version: 4
63
67
  summary: A simple Plausible API wrapper for Rails