Skip to content

Commit

Permalink
Add client.ListSites and site.Details functions (#5)
Browse files Browse the repository at this point in the history
* Fix error message.

* Add ListSites function.

* Add get site function.

* Add doc.

* Finish up the PR

---------

Co-authored-by: André Santos <andrerfcsantos@gmail.com>
  • Loading branch information
francois2metz and andrerfcsantos authored Aug 3, 2024
1 parent aabdf92 commit a3af610
Show file tree
Hide file tree
Showing 8 changed files with 234 additions and 2 deletions.
91 changes: 91 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ It currently supports the full API of Plausible, which includes:
* [Breakdown Queries](#breakdown-queries)

* [Site Provisioning API](#site-provisioning-api)
* [List sites](#provisioning-api-get-sites)
* [Get site](#provisioning-api-get-site)
* [Get/Create Shared Links](#provisioning-api-shared-links)
* [Create new sites](#provisioning-api-create-new-sites)

Expand Down Expand Up @@ -414,6 +416,95 @@ go here to know more about how to get a token for this API:

* [Plausible Docs: Site Provisioning API](https://plausible.io/docs/sites-api)

### <a name="provisioning-api-get-sites"></a> List sites

Gets a list of existing sites your Plausible account can access.

```go
package main

import (
"fmt"
"github.com/andrerfcsantos/go-plausible/plausible"
)

func main() {
// Create a client with an API token
// Warning: This token must have permissions to the site provisioning API
client := plausible.NewClient("<your_api_token>")

sites, err := client.ListSites()

if err != nil {
// handle error
}

fmt.Printf("Sites %s\n", sites.Sites)
}
```

If the response contains a lot of sites, it will be paginated. To access other pages, use the pagination options:

```go
package main

import (
"fmt"
"github.com/andrerfcsantos/go-plausible/plausible"
"github.com/andrerfcsantos/go-plausible/plausible/urlmaker/pagination"
)

func main() {
// Create a client with an API token
// Warning: This token must have permissions to the site provisioning API
client := plausible.NewClient("<your_api_token>")

sites, err := client.ListSites(
pagination.After("awebsite"),
pagination.Before("otherwebsite"),
pagination.Limit(20),
)

if err != nil {
// handle error
}

fmt.Printf("Sites %s\n", sites.Sites)
}
```



### <a name="provisioning-api-get-site"></a> Get site

Gets details of a site. Your Plausible account must have access to it.

```go
package main

import (
"fmt"
"github.com/andrerfcsantos/go-plausible/plausible"
)

func main() {
// Create a client with an API token
// Warning: This token must have permissions to the site provisioning API
client := plausible.NewClient("<your_api_token>")

// Get an handler to perform queries for a given site
mysite := client.Site("example.com")

siteResult, err := mysite.Details()

if err != nil {
// handle error
}

fmt.Printf("Site %v\n", siteResult)
}
```

### <a name="provisioning-api-shared-links"></a> Get or create Shared Links

Shared Links are URLs that you can generate to give others access to your dashboards.
Expand Down
30 changes: 28 additions & 2 deletions plausible/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"mime/multipart"
"strings"

"github.com/andrerfcsantos/go-plausible/plausible/urlmaker/pagination"
"github.com/valyala/fasthttp"
)

Expand Down Expand Up @@ -144,7 +145,32 @@ func (c *Client) CreateNewSite(siteRequest CreateSiteRequest) (CreateSiteResult,
var res CreateSiteResult
err = json.Unmarshal(data, &res)
if err != nil {
return CreateSiteResult{}, fmt.Errorf("error parsing shared link response: %w", err)
return CreateSiteResult{}, fmt.Errorf("error parsing create site response: %w", err)
}

return res, nil
}

// ListSites lists existing sites in Plausible
func (c *Client) ListSites(pagOptions ...pagination.Option) (ListSitesResult, error) {

paginator := pagination.NewPaginator(pagOptions...)
qArgs := QueryArgsFromPaginator(paginator)

req, err := c.acquireRequest("GET", "sites", qArgs, nil)
if err != nil {
return ListSitesResult{}, fmt.Errorf("error acquiring request: %v", err)
}

data, err := doRequest(c.client, req)
if err != nil {
return ListSitesResult{}, fmt.Errorf("error performing request to list sites: %v", err)
}

var res ListSitesResult
err = json.Unmarshal(data, &res)
if err != nil {
return ListSitesResult{}, fmt.Errorf("error parsing list sites response: %w", err)
}

return res, nil
Expand All @@ -156,5 +182,5 @@ func (c *Client) PushEvent(ev EventRequest) ([]byte, error) {
if err != nil {
return nil, fmt.Errorf("acquiring event request from client: %w", err)
}
return doRequest(s.httpClient, req)
return doRequest(c.client, req)
}
19 changes: 19 additions & 0 deletions plausible/list_site_request.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package plausible

import "github.com/andrerfcsantos/go-plausible/plausible/urlmaker/pagination"

// SiteResult contains the details for a Site
type SiteResult struct {
// Domain of the site.
Domain string `json:"domain"`
// Timezone of the newly created site.
Timezone string `json:"timezone"`
}

// ListSitesResult is the result of a request to list sites.
type ListSitesResult struct {
// Sites is the list of sites in a response
Sites []SiteResult `json:"sites"`
// Meta is the pagination meta information of a page
Meta pagination.Meta `json:"meta"`
}
22 changes: 22 additions & 0 deletions plausible/query_args.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
package plausible

import (
"github.com/andrerfcsantos/go-plausible/plausible/urlmaker/pagination"
"strconv"
)

// QueryArgs represents a list of query arguments.
type QueryArgs []QueryArg

Expand Down Expand Up @@ -48,3 +53,20 @@ type QueryArg struct {
// Value is the value for the query argument
Value string
}

// QueryArgsFromPaginator takes the information on a paginator and converts it into query args
func QueryArgsFromPaginator(paginator *pagination.Paginator) QueryArgs {
queryArgs := QueryArgs{}

if paginator.After != "" {
queryArgs.Add(QueryArg{Name: "after", Value: paginator.After})
}
if paginator.Before != "" {
queryArgs.Add(QueryArg{Name: "before", Value: paginator.Before})
}
if paginator.Limit != 0 {
queryArgs.Add(QueryArg{Name: "limit", Value: strconv.Itoa(paginator.Limit)})
}

return queryArgs
}
16 changes: 16 additions & 0 deletions plausible/site.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,22 @@ func (s *Site) CurrentVisitors() (int, error) {
return visitors, nil
}

// Details contains information about a site
func (s *Site) Details() (SiteResult, error) {
data, err := s.doRequest("GET", fmt.Sprintf("sites/%s", s.id), nil, nil)
if err != nil {
return SiteResult{}, fmt.Errorf("error performing get request: %w", err)
}

var res SiteResult
err = json.Unmarshal(data, &res)
if err != nil {
return SiteResult{}, fmt.Errorf("error parsing get response: %w", err)
}

return res, nil
}

// Aggregate performs an aggregate query.
// An aggregate query reports data for metrics aggregated over a period of time,
// eg, "total number of visitors/pageviews for a particular day".
Expand Down
11 changes: 11 additions & 0 deletions plausible/urlmaker/pagination/meta.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package pagination

// Meta contains pagination information related with a response
type Meta struct {
// After is the domain id that appears before all the records in the current page
After string `json:"after"`
// Before is the domain id that appears after all the records in the current page
Before string `json:"before"`
// Limit limits the number of records in a page
Limit int `json:"limit"`
}
27 changes: 27 additions & 0 deletions plausible/urlmaker/pagination/option.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package pagination

// Option represents a pagination option.
// It is not meant to be created directly - instead, you should get
// an Option via the helper functions, like After, Before and Limit.
type Option func(*Paginator)

// After sets the 'after' pagination option
func After(after string) Option {
return func(p *Paginator) {
p.After = after
}
}

// Before sets the 'before' pagination option
func Before(before string) Option {
return func(p *Paginator) {
p.Before = before
}
}

// Limit sets the 'limit' pagination option
func Limit(limit int) Option {
return func(p *Paginator) {
p.Limit = limit
}
}
20 changes: 20 additions & 0 deletions plausible/urlmaker/pagination/paginator.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package pagination

// Paginator holds information to paginate requests
type Paginator struct {
// After is the domain id that appears before all the records in the desired page
After string
// Before is the domain id that appears after all the records in the desired page
Before string
// Limit sets the maximum records in the desired page
Limit int
}

// NewPaginator creates a new paginator with the given options
func NewPaginator(options ...Option) *Paginator {
paginator := &Paginator{}
for _, opt := range options {
opt(paginator)
}
return paginator
}

0 comments on commit a3af610

Please sign in to comment.