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