plausible_api 0.1.10 → 0.3

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: 5fcd7e3adaeb1c8fb8dc1de67e305573708d04e971e995bcffeb4d0fe71ec8ff
4
- data.tar.gz: b729b5a5de1b5f6572c175879e77daed92aba1cc60075033b1e693752e13b7ce
3
+ metadata.gz: 3164447cd3eac3c7a7cbf0c7e7cccd36eaf2bd195966283fc0da4ad023b7b21e
4
+ data.tar.gz: 34acbb3e21f80bd3537d4273b6555dea0da7e4fdb5cf3dcbf8bede5d477e8ce0
5
5
  SHA512:
6
- metadata.gz: 0d0757ae94943225433757648bc542dd2afa2a1706696b35cdb179f7f117cb8a8b34581ea0bc7a50ac1d8973c137206bf520e2b6d27129d06c7ff310ca757d6e
7
- data.tar.gz: db68b71615cb9026ae5a9dddaa1fee92c51740d0314f556e032cd0975ea71675fbade8733e80c1b4975e53d64d7f1347747b10cb1a73b8f5c034d29b3f396590
6
+ metadata.gz: 03273d140652347b6b282d94ff0c6294746fc7bd410dcaa1feab54a627d80ed64fa8eb1c9c56c0a3a0e3e2a95cb9cda755501987f46a3b795cb9dc2862aa1e01
7
+ data.tar.gz: b6e84673b3763918a28488c717e3be089107571ecb1b357b4d7e2b1ded589b68eade9d65f615e70a6655b4571a73c7bf767a0af3363b6ca90631cd0810ea91e8
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- plausible_api (0.1.10)
4
+ plausible_api (0.3)
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,31 @@ 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
+ ```
89
+
90
+
91
+ ### Self-hosted Plausible instances
92
+
93
+ If you are using a self-hosted Plausible instance, you can set the `base_url` before initializing the client. On a Ruby on Rails app, you can add this to an initializer like `config/initializers/plausible.rb`
94
+
95
+ ```rb
96
+ # Do not include a trailing slash
97
+ PlausibleApi.configure do |config|
98
+ config.base_url = "https://your-plausible-instance.com"
99
+ end
100
+ ```
76
101
 
77
102
  ## Development
78
103
 
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,23 @@
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
-
19
18
  def initialize(site_id, token)
20
19
  @site_id = site_id.to_s
21
- @token = token.to_s
20
+ @token = token.to_s
22
21
  end
23
22
 
24
23
  def aggregate(options = {})
@@ -38,34 +37,42 @@ module PlausibleApi
38
37
  end
39
38
 
40
39
  def valid?
41
- begin
42
- realtime_visitors
43
- return true
44
- rescue
45
- return false
46
- end
40
+ realtime_visitors
41
+ true
42
+ rescue
43
+ false
44
+ end
45
+
46
+ def event(options = {})
47
+ call PlausibleApi::Event::Post.new(options.merge(domain: @site_id))
47
48
  end
48
49
 
49
50
  private
50
- def call(api)
51
- raise StandardError.new api.errors unless api.valid?
52
-
53
- url = "#{BASE_URL}#{api.request_url.gsub('$SITE_ID', @site_id)}"
51
+
52
+ SUCCESS_CODES = %w[200 202].freeze
53
+
54
+ def call(api)
55
+ raise Error, api.errors unless api.valid?
56
+ raise ConfigurationError, PlausibleApi.configuration.errors unless PlausibleApi.configuration.valid?
57
+
58
+ url = "#{PlausibleApi.configuration.base_url}#{api.request_url.gsub("$SITE_ID", @site_id)}"
54
59
  uri = URI.parse(url)
55
60
 
56
- req = Net::HTTP::Get.new(uri.request_uri)
57
- req.add_field('Authorization', "Bearer #{@token}")
61
+ req = api.request_class.new(uri.request_uri)
62
+ req.initialize_http_header(api.request_headers)
63
+ req.add_field("authorization", "Bearer #{@token}") if api.request_auth?
64
+ req.body = api.request_body if api.request_body?
58
65
 
59
66
  http = Net::HTTP.new(uri.host, uri.port)
60
- http.use_ssl = true
67
+ http.use_ssl = true
61
68
 
62
69
  response = http.request(req)
63
70
 
64
- if response.code == "200"
71
+ if SUCCESS_CODES.include?(response.code)
65
72
  api.parse_response response.body
66
73
  else
67
74
  raise StandardError.new response.body
68
75
  end
69
76
  end
70
77
  end
71
- end
78
+ end
@@ -0,0 +1,26 @@
1
+ module PlausibleApi
2
+ class Configuration
3
+ attr_accessor :base_url
4
+
5
+ # Setting up default values
6
+ def initialize
7
+ @base_url = "https://plausible.io"
8
+ end
9
+
10
+ def valid?
11
+ errors.empty?
12
+ end
13
+
14
+ def errors
15
+ errors = []
16
+ if base_url.nil? || base_url.empty?
17
+ errors.push(base_url: "base_url is required")
18
+ elsif !(URI.parse base_url).is_a? URI::HTTP
19
+ errors.push(base_url: "base_url is not a valid URL")
20
+ elsif base_url.end_with?("/")
21
+ errors.push(base_url: "base_url should not end with a trailing slash")
22
+ end
23
+ errors
24
+ end
25
+ end
26
+ 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
@@ -5,11 +5,11 @@ module PlausibleApi
5
5
  class Aggregate < Base
6
6
 
7
7
  def initialize(options = {})
8
- super({ period: '30d',
8
+ super({ period: '30d',
9
9
  metrics: 'visitors,visits,pageviews,views_per_visit,bounce_rate,visit_duration,events' }
10
10
  .merge(options))
11
11
  end
12
-
12
+
13
13
  def request_url_base
14
14
  "/api/v1/stats/aggregate?site_id=$SITE_ID"
15
15
  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
@@ -7,7 +7,7 @@ module PlausibleApi
7
7
  def initialize(options = {})
8
8
  super({ period: '30d', property: 'event:page' }.merge(options))
9
9
  end
10
-
10
+
11
11
  def request_url_base
12
12
  "/api/v1/stats/breakdown?site_id=$SITE_ID"
13
13
  end
@@ -17,4 +17,4 @@ module PlausibleApi
17
17
  end
18
18
  end
19
19
  end
20
- end
20
+ end
@@ -7,7 +7,7 @@ module PlausibleApi
7
7
  def initialize(options = {})
8
8
  super({ period: '30d' }.merge(options))
9
9
  end
10
-
10
+
11
11
  def request_url_base
12
12
  "/api/v1/stats/timeseries?site_id=$SITE_ID"
13
13
  end
@@ -17,4 +17,4 @@ module PlausibleApi
17
17
  end
18
18
  end
19
19
  end
20
- end
20
+ end
@@ -1,3 +1,3 @@
1
1
  module PlausibleApi
2
- VERSION = "0.1.10"
2
+ VERSION = "0.3"
3
3
  end
data/lib/plausible_api.rb CHANGED
@@ -1,7 +1,20 @@
1
- require 'plausible_api/version'
2
- require 'plausible_api/client'
1
+ require "plausible_api/version"
2
+ require "plausible_api/client"
3
+ require "plausible_api/configuration"
3
4
 
4
5
  module PlausibleApi
5
6
  class Error < StandardError; end
7
+
8
+ class ConfigurationError < StandardError; end
9
+
6
10
  # Your code goes here...
11
+ class << self
12
+ def configuration
13
+ @configuration ||= Configuration.new
14
+ end
15
+
16
+ def configure
17
+ yield(configuration)
18
+ end
19
+ end
7
20
  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.10
4
+ version: '0.3'
5
5
  platform: ruby
6
6
  authors:
7
7
  - Gustavo Garcia
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2023-07-14 00:00:00.000000000 Z
11
+ date: 2024-02-02 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,13 @@ 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/configuration.rb
34
+ - lib/plausible_api/event/base.rb
35
+ - lib/plausible_api/event/post.rb
31
36
  - lib/plausible_api/stats/aggregate.rb
32
37
  - lib/plausible_api/stats/base.rb
33
38
  - lib/plausible_api/stats/breakdown.rb