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 +4 -4
- data/Gemfile.lock +1 -1
- data/README.md +14 -1
- data/examples/basic.rb +5 -0
- data/examples/event.rb +23 -0
- data/lib/plausible_api/client.rb +31 -23
- data/lib/plausible_api/event/base.rb +31 -0
- data/lib/plausible_api/event/post.rb +101 -0
- data/lib/plausible_api/stats/aggregate.rb +2 -2
- data/lib/plausible_api/stats/base.rb +21 -1
- data/lib/plausible_api/version.rb +1 -1
- data/lib/plausible_api.rb +2 -2
- metadata +7 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 77c960fb14e022fa7f1ae47a7c38903325d188d98c67ac598977812326b616be
|
4
|
+
data.tar.gz: 4d0ed7d883293c49bfb518d544efbad968b544d249cb0bfc05ff5366c87a325e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 6247be2a8f503c75bbff787771f1189598426171275122b6dddcc6581354db6ea3e2f81dd5c0ccc247c92ab7587f5f00c32ccc3d83b050ab70ff1470866bbbcb
|
7
|
+
data.tar.gz: 395a7b263fcfb9ce374f7e2d734a3d2ed608fd11755c4a6087fabc89a299da084fe5411063707e7066371660c1784ca2fa900d434d0daaefe8f00c398974dd7e
|
data/Gemfile.lock
CHANGED
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
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
|
+
)
|
data/lib/plausible_api/client.rb
CHANGED
@@ -1,24 +1,25 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require
|
4
|
-
require
|
5
|
-
require
|
6
|
-
require
|
7
|
-
require
|
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
|
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
|
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
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
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
|
-
|
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(
|
58
|
+
|
59
|
+
url = "#{BASE_URL}#{api.request_url.gsub("$SITE_ID", @site_id)}"
|
54
60
|
uri = URI.parse(url)
|
55
61
|
|
56
|
-
req =
|
57
|
-
req.
|
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
|
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
|
data/lib/plausible_api.rb
CHANGED
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.
|
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:
|
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.
|
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
|