plausible_api 0.1.0 → 0.1.6

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: 799fea9f2d094075ca64a58235d62031d0f701c62b031e7f15982bbf2595d36e
4
- data.tar.gz: 2a4de4e741a1cee1858dfe132102c5a2d937a27382134b80e6a8e4ca28fa327c
3
+ metadata.gz: 040cbafdc8f270ac3f2bfdcaed7501535f801e93ba1059e6b776be42258714e9
4
+ data.tar.gz: 9e5511a3d7bb752a1b0a89e0f4d3b405eea5a6ca56262cf684626d7cf444dafc
5
5
  SHA512:
6
- metadata.gz: 57f336396b61f956dc2814fb1de4f628d7e0070334789488d0aa2ec257aec09f4ad6ef93e6fecef490049aa6884cccc72c5b2a56277bd0567923ceb1bc8b4750
7
- data.tar.gz: 635da11edc92ad2c69a6bcff7b1ea4211595c180babe00ca480450195151ec9270c1c1847067ad245dd720d5e4d2bcd833a3168fc212bf40bfde82831a5c213e
6
+ metadata.gz: 83077cd7edeb80de8388afbea3fd85d2ba2e8068345e10df04331c6356f7dc5a7c7096da9774bfe2fa6324d76fd68ec5c80cf4c39f1dd499a39dbb8d73ba24c7
7
+ data.tar.gz: fc95a48bf881567cce4f126c899206e18cdfbbc0b0f3ddeba6e66f37553a12f2a77a541472005eafd3c07ddc435d70886fc95d13b751b906056d616bd5604a42
data/Gemfile.lock CHANGED
@@ -1,21 +1,13 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- plausible_api (0.1.0)
5
- faraday (~> 1.0)
4
+ plausible_api (0.1.6)
6
5
 
7
6
  GEM
8
7
  remote: https://rubygems.org/
9
8
  specs:
10
- faraday (1.3.0)
11
- faraday-net_http (~> 1.0)
12
- multipart-post (>= 1.2, < 3)
13
- ruby2_keywords
14
- faraday-net_http (1.0.1)
15
9
  minitest (5.14.3)
16
- multipart-post (2.1.1)
17
10
  rake (12.3.3)
18
- ruby2_keywords (0.0.4)
19
11
 
20
12
  PLATFORMS
21
13
  ruby
data/README.md CHANGED
@@ -1,4 +1,4 @@
1
- # Plausible API (Work In Progress)
1
+ # Plausible API Ruby Gem
2
2
  This is a simple wrapper to read the Plausible API with Ruby.
3
3
  It's based on the WIP [API guide](https://plausible.io/docs/stats-api)
4
4
 
@@ -9,7 +9,11 @@ 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(site_id: 'dailytics.com', token: '123123')
12
+ c = PlausibleApi::Client.new('dailytics.com', '123123')
13
+
14
+ # Test if the site and token are valid
15
+ c.valid?
16
+ => true
13
17
  ```
14
18
 
15
19
  ### Stats > Aggregate
@@ -19,10 +23,11 @@ You have all these options to get the aggregate stats
19
23
  # Use the default parameters (3mo period + the 4 main metrics)
20
24
  c.aggregate
21
25
 
22
- # Set parameters (period, metrics, filter, date)
26
+ # Set parameters (period, metrics, filter, compare)
23
27
  c.aggregate({ period: '30d' })
24
28
  c.aggregate({ period: '30d', metrics: 'visitors,pageviews' })
25
29
  c.aggregate({ period: '30d', metrics: 'visitors,pageviews', filters: 'event:page==/order/confirmation' })
30
+ c.aggregate({ date: '2021-01-01,2021-02-10' })
26
31
 
27
32
  # You'll get something like this:
28
33
  => {"bounce_rate"=>{"value"=>81.0}, "pageviews"=>{"value"=>29}, "visit_duration"=>{"value"=>247.0}, "visitors"=>{"value"=>14}}
@@ -35,19 +40,37 @@ You have all these options to get the timeseries
35
40
  # Use the default parameters (3mo period)
36
41
  c.timeseries
37
42
 
38
- # Set parameters (period, metrics, filter, date)
43
+ # Set parameters (period, filters, interval)
39
44
  c.timeseries({ period: '7d' })
40
- c.timeseries({ period: '7d', filters: 'event:page==/order/confirmation', date: '2020/02/10' })
45
+ c.timeseries({ period: '7d', filters: 'event:page==/order/confirmation' })
46
+ c.timeseries({ date: '2021-01-01,2021-02-15' })
41
47
 
42
48
  # You'll get something like this:
43
49
  => [{"date"=>"2021-01-11", "value"=>100}, {"date"=>"2021-01-12", "value"=>120}, {"date"=>"2021-01-13", "value"=>80}...]
44
50
  ```
45
51
 
46
- ### Realtime >> Visitors
52
+ ### Stats > Breakdown
53
+ ```rb
54
+ # Use the default parameters (30d, event:page)
55
+ c.breakdown
56
+
57
+ # Set parameters (property, period, metrics, limit, page, filters, date)
58
+ c.breakdown({ property: 'visit:source' })
59
+ c.breakdown({ property: 'visit:source', metrics: 'visitors,pageviews' })
60
+ c.breakdown({ property: 'visit:source', metrics: 'visitors,pageviews', period: '30d' })
61
+ c.breakdown({ property: 'visit:source', metrics: 'visitors,pageviews', date: '2021-01-01,2021-02-01' })
62
+
63
+ # You'll get something like this:
64
+ => [{"page"=>"/", "visitors"=>41}, {"page"=>"/plans/", "visitors"=>14}, {"page"=>"/agencies/", "visitors"=>8}, {"page"=>"/features/", "visitors"=>8}, {"page"=>"/ready/", "visitors"=>5}, {"page"=>"/contact/", "visitors"=>4}, {"page"=>"/about/", "visitors"=>3}, {"page"=>"/donate/", "visitors"=>3}]
65
+ ```
66
+
67
+ ### Realtime > Visitors
47
68
 
48
- You have a uniq way to call this data
69
+ It's as simple as:
49
70
  ```rb
50
71
  c.realtime_visitors
72
+
73
+ => 13
51
74
  ```
52
75
 
53
76
 
@@ -59,7 +82,7 @@ To install this gem onto your local machine, run `bundle exec rake install`. To
59
82
 
60
83
  ## Contributing
61
84
 
62
- Bug reports and pull requests are welcome on GitHub at https://github.com/dailytics/plausible_api. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [code of conduct](https://github.com/dailytics/plausible_api/blob/master/CODE_OF_CONDUCT.md).
85
+ Bug reports and pull requests are welcome on GitHub at https://github.com/dailytics/plausible_api. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [code of conduct](https://github.com/dailytics/plausible_api/blob/main/CODE_OF_CONDUCT.md).
63
86
 
64
87
 
65
88
  ## License
@@ -68,4 +91,4 @@ The gem is available as open source under the terms of the [MIT License](https:/
68
91
 
69
92
  ## Code of Conduct
70
93
 
71
- Everyone interacting in the PlausibleApi project's codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/dailytics/plausible_api/blob/master/CODE_OF_CONDUCT.md).
94
+ Everyone interacting in the PlausibleApi project's codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/dailytics/plausible_api/blob/main/CODE_OF_CONDUCT.md).
@@ -1,18 +1,22 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'plausible_api/stats/base'
3
4
  require 'plausible_api/stats/realtime/visitors'
4
5
  require 'plausible_api/stats/aggregate'
5
6
  require 'plausible_api/stats/timeseries'
7
+ require 'plausible_api/stats/breakdown'
6
8
 
7
- require 'faraday'
8
9
  require 'json'
10
+ require "net/http"
11
+ require "uri"
12
+ require "cgi"
9
13
 
10
14
  module PlausibleApi
11
15
  class Client
12
16
 
13
17
  BASE_URL = 'https://plausible.io'
14
18
 
15
- def initialize(site_id:, token:)
19
+ def initialize(site_id, token)
16
20
  @site_id = site_id.to_s
17
21
  @token = token.to_s
18
22
  end
@@ -25,18 +29,32 @@ module PlausibleApi
25
29
  call PlausibleApi::Stats::Timeseries.new(options)
26
30
  end
27
31
 
32
+ def breakdown(options = {})
33
+ call PlausibleApi::Stats::Breakdown.new(options)
34
+ end
35
+
28
36
  def realtime_visitors
29
37
  call PlausibleApi::Stats::Realtime::Visitors.new
30
38
  end
31
39
 
40
+ def valid?
41
+ realtime_visitors.is_a? Integer
42
+ end
43
+
32
44
  private
33
- def call(api)
45
+ def call(api)
46
+ raise StandardError.new "There is some invalid parameters." unless api.valid?
47
+
34
48
  url = "#{BASE_URL}#{api.request_url.gsub('$SITE_ID', @site_id)}"
35
- puts url
36
- res = Faraday.get(url) do |req|
37
- req.headers['Authorization'] = "Bearer #{@token}"
38
- end
39
- JSON.parse res.body
49
+ uri = URI.parse(url)
50
+
51
+ req = Net::HTTP::Get.new(uri.request_uri)
52
+ req.add_field('Authorization', "Bearer #{@token}")
53
+
54
+ http = Net::HTTP.new(uri.host, uri.port)
55
+ http.use_ssl = true
56
+
57
+ api.parse_response http.request(req).body
40
58
  end
41
59
  end
42
60
  end
@@ -2,29 +2,20 @@
2
2
 
3
3
  module PlausibleApi
4
4
  module Stats
5
- class Aggregate
5
+ class Aggregate < Base
6
+
6
7
  def initialize(options = {})
7
- @period = options[:period] || '30d'
8
- @metrics = options[:metrics] || 'visitors,pageviews,bounce_rate,visit_duration'
9
- @filters = options[:filters]
10
- @date = options[:date]
8
+ super({ period: '30d',
9
+ metrics: 'visitors,pageviews,bounce_rate,visit_duration' }
10
+ .merge(options))
11
+ end
12
+
13
+ def request_url_base
14
+ "/api/v1/stats/aggregate?site_id=$SITE_ID"
11
15
  end
12
16
 
13
- def request_url
14
- url = "/api/v1/stats/aggregate?site_id=$SITE_ID"
15
- if @period
16
- url += "&period=#{@period}"
17
- end
18
- if @metrics
19
- url += "&metrics=#{@metrics}"
20
- end
21
- if @filters
22
- url += "&filters=#{CGI.escape(@filters)}"
23
- end
24
- if @date
25
- url += "&date=#{@date}"
26
- end
27
- url
17
+ def parse_response(body)
18
+ JSON.parse body
28
19
  end
29
20
  end
30
21
  end
@@ -0,0 +1,84 @@
1
+ # frozen_string_literal: true
2
+
3
+ module PlausibleApi
4
+ module Stats
5
+ class Base
6
+
7
+ def initialize(options = {})
8
+ @options = { compare: nil, date: nil, filters: nil, interval: nil,
9
+ limit: nil, metrics: nil, page: nil, period: nil,
10
+ property: nil }.merge(options)
11
+ @options[:period] = 'custom' if @options[:date]
12
+ end
13
+
14
+ def request_url_base
15
+ raise NotImplementedError
16
+ end
17
+
18
+ def request_url
19
+ params = @options.select{ |_,v| !v.to_s.empty? }
20
+ [request_url_base, URI.encode_www_form(params)].reject{|e| e.empty?}.join('&')
21
+ end
22
+
23
+ def parse_response(body)
24
+ raise NotImplementedError
25
+ end
26
+
27
+ def valid?
28
+ errors.empty?
29
+ end
30
+
31
+ def errors
32
+ allowed_period = %w(12mo 6mo month 30d 7d day custom)
33
+ allowed_metrics = %w(visitors pageviews bounce_rate visit_duration)
34
+ allowed_compare = %w(previous_period)
35
+ allowed_interval = %w(date month)
36
+ allowed_property = %w(event:page visit:source visit:referrer visit:utm_medium
37
+ visit:utm_source visit:utm_campaign visit:device visit:browser visit:browser_version
38
+ visit:os visit:os_version visit:country)
39
+ e = 'Not a valid parameter. Allowed parameters are: '
40
+
41
+ errors = []
42
+ if @options[:period]
43
+ errors.push({ period: "#{e}#{allowed_period.join(', ')}" }) unless allowed_period.include? @options[:period]
44
+ end
45
+ if @options[:metrics]
46
+ metrics_array = @options[:metrics].split(',')
47
+ errors.push({ metrics: "#{e}#{allowed_metrics.join(', ')}" }) unless metrics_array & allowed_metrics == metrics_array
48
+ end
49
+ if @options[:compare]
50
+ errors.push({ compare: "#{e}#{allowed_compare.join(', ')}" }) unless allowed_compare.include? @options[:compare]
51
+ end
52
+ if @options[:interval]
53
+ errors.push({ interval: "#{e}#{allowed_interval.join(', ')}" }) unless allowed_interval.include? @options[:interval]
54
+ end
55
+ if @options[:property]
56
+ errors.push({ property: "#{e}#{allowed_property.join(', ')}" }) unless allowed_property.include? @options[:property]
57
+ end
58
+ if @options[:filters]
59
+ filters_array = @options[:filters].to_s.split(';')
60
+ filters_array.each do |f|
61
+ parts = f.split("==")
62
+ errors.push({ filters: "Unrecognized filter: #{f}" }) unless parts.length == 2
63
+ errors.push({ filters: "Unknown metric for filter: #{parts[0]}" }) unless allowed_property.include? parts[0]
64
+ end
65
+ end
66
+ if @options[:limit]
67
+ errors.push({ limit: "Limit param must be a positive number" }) unless @options[:limit].is_a? Integer and @options[:limit] > 0
68
+ end
69
+ if @options[:page]
70
+ errors.push({ page: "Page param must be a positive number" }) unless @options[:page].is_a? Integer and @options[:page] > 0
71
+ end
72
+ if @options[:date]
73
+ errors.push({ date: 'You must define the period parameter as custom' }) unless @options[:period] == 'custom'
74
+ date_array = @options[:date].split(",")
75
+ errors.push({ date: 'You must define start and end dates divided by comma' }) unless date_array.length == 2
76
+ regex = /\d{4}\-\d{2}\-\d{2}/
77
+ errors.push({ date: 'Wrong format for the start date' }) unless date_array[0] =~ regex
78
+ errors.push({ date: 'Wrong format for the end date' }) unless date_array[1] =~ regex
79
+ end
80
+ errors
81
+ end
82
+ end
83
+ end
84
+ end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ module PlausibleApi
4
+ module Stats
5
+ class Breakdown < Base
6
+
7
+ def initialize(options = {})
8
+ super({ period: '30d', property: 'event:page' }.merge(options))
9
+ end
10
+
11
+ def request_url_base
12
+ "/api/v1/stats/breakdown?site_id=$SITE_ID"
13
+ end
14
+
15
+ def parse_response(body)
16
+ JSON.parse(body)['results']
17
+ end
18
+ end
19
+ end
20
+ end
@@ -3,12 +3,13 @@
3
3
  module PlausibleApi
4
4
  module Stats
5
5
  module Realtime
6
- class Visitors
7
- def initialize
6
+ class Visitors < PlausibleApi::Stats::Base
7
+ def request_url_base
8
+ "/api/v1/stats/realtime/visitors?site_id=$SITE_ID"
8
9
  end
9
10
 
10
- def request_url
11
- "/api/v1/stats/realtime/visitors?site_id=$SITE_ID"
11
+ def parse_response(body)
12
+ body.to_i
12
13
  end
13
14
  end
14
15
  end
@@ -2,25 +2,18 @@
2
2
 
3
3
  module PlausibleApi
4
4
  module Stats
5
- class Timeseries
5
+ class Timeseries < Base
6
+
6
7
  def initialize(options = {})
7
- @period = options[:period] || '30d'
8
- @filters = options[:filters]
9
- @date = options[:date]
8
+ super({ period: '30d' }.merge(options))
9
+ end
10
+
11
+ def request_url_base
12
+ "/api/v1/stats/timeseries?site_id=$SITE_ID"
10
13
  end
11
14
 
12
- def request_url
13
- url = "/api/v1/stats/timeseries?site_id=$SITE_ID"
14
- if @period
15
- url += "&period=#{@period}"
16
- end
17
- if @filters
18
- url += "&filters=#{CGI.escape(@filters)}"
19
- end
20
- if @date
21
- url += "&date=#{@date}"
22
- end
23
- url
15
+ def parse_response(body)
16
+ JSON.parse(body)['results']
24
17
  end
25
18
  end
26
19
  end
@@ -1,3 +1,3 @@
1
1
  module PlausibleApi
2
- VERSION = "0.1.0"
2
+ VERSION = "0.1.6"
3
3
  end
@@ -24,6 +24,4 @@ Gem::Specification.new do |spec|
24
24
  spec.bindir = "exe"
25
25
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
26
26
  spec.require_paths = ["lib"]
27
-
28
- spec.add_dependency 'faraday', '~> 1.0'
29
27
  end
metadata CHANGED
@@ -1,29 +1,15 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: plausible_api
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.1.6
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-02-12 00:00:00.000000000 Z
12
- dependencies:
13
- - !ruby/object:Gem::Dependency
14
- name: faraday
15
- requirement: !ruby/object:Gem::Requirement
16
- requirements:
17
- - - "~>"
18
- - !ruby/object:Gem::Version
19
- version: '1.0'
20
- type: :runtime
21
- prerelease: false
22
- version_requirements: !ruby/object:Gem::Requirement
23
- requirements:
24
- - - "~>"
25
- - !ruby/object:Gem::Version
26
- version: '1.0'
11
+ date: 2021-02-25 00:00:00.000000000 Z
12
+ dependencies: []
27
13
  description: A very humble wrapper for the new API by Plausible
28
14
  email:
29
15
  - gustavo@dailytics.com
@@ -43,6 +29,8 @@ files:
43
29
  - lib/plausible_api.rb
44
30
  - lib/plausible_api/client.rb
45
31
  - lib/plausible_api/stats/aggregate.rb
32
+ - lib/plausible_api/stats/base.rb
33
+ - lib/plausible_api/stats/breakdown.rb
46
34
  - lib/plausible_api/stats/realtime/visitors.rb
47
35
  - lib/plausible_api/stats/timeseries.rb
48
36
  - lib/plausible_api/version.rb