Skip to content

Commit

Permalink
feat: add umamiTeamId to organize websites
Browse files Browse the repository at this point in the history
  • Loading branch information
astappiev committed Oct 16, 2024
1 parent 3ca46c9 commit 3e5c982
Show file tree
Hide file tree
Showing 5 changed files with 25 additions and 8 deletions.
1 change: 1 addition & 0 deletions .traefik.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ testData:
umamiToken: ""
umamiUsername: ""
umamiPassword: ""
umamiTeamId: ""
websites:
domain: websiteId
createNewWebsites: false
Expand Down
1 change: 1 addition & 0 deletions demo/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,5 @@ http:
umamiHost: http://umami:3000
umamiUsername: "admin"
umamiPassword: "umami"
umamiTeamId: "8e39c6ad-e44a-4d3e-be98-015db2d62d40"
createNewWebsites: true
6 changes: 5 additions & 1 deletion readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,19 +56,22 @@ http:
```

You have an option to give a list of domains to track (and their website IDs on Umami). \
Or, you can give a token and the list will be fetched from Umami. For this, you need either [retrieve the token yourself](https://umami.is/docs/api/authentication), or use
Or, you can give a token and the list will be fetched from Umami. For this, you need
either [retrieve the token yourself](https://umami.is/docs/api/authentication), or use
username/password instead.

After that, you need to add the middleware to a [router](https://doc.traefik.io/traefik/routing/routers/#middlewares_1).
Remember to reference the
correct [provider namespace](https://doc.traefik.io/traefik/providers/overview/#provider-namespace).

E.g. as Docker labels:

```yaml
- "traefik.http.routers.whoami.middlewares=my-umami-middleware@file"
```
Or, for all routers in a static configuration:
```yaml
entryPoints:
web:
Expand All @@ -85,6 +88,7 @@ entryPoints:
| `umamiToken` | - | `string` | An API Token, used to automatize work with websites, not needed if you provide `websites` |
| `umamiUsername` | - | `string` | An alternative to `umamiToken`, you can provide an username and password |
| `umamiPassword` | - | `string` | Only in combination with `umamiUsername` |
| `umamiTeamId` | - | `string` | In order to organize websites, you can use Umami Teams |
| `websites` | - | `map` | A map of hostnames and their associated Umami IDs. Can also be used to override or extend fetched websites |
| `createNewWebsites` | false | `bool` | If set to `true`, will try to create a new website on Umami, if domain not found there |
| `debug` | false | `bool` | Something doesn't work? Set to `true` to see more logs (plugins doesn't have access to Traefik's log level) |
8 changes: 6 additions & 2 deletions umami.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ type Config struct {
// as an alternative to UmamiToken, you can set UmamiUsername and UmamiPassword to authenticate
UmamiUsername string `json:"umamiUsername"`
UmamiPassword string `json:"umamiPassword"`
UmamiTeamId string `json:"umamiTeamId"`
// if both UmamiToken and Websites are set, Websites will be used to override the websites in the API
Websites map[string]string `json:"websites"`
// if createNewWebsites is set to true, the plugin will create new websites in the API, UmamiToken is required
Expand All @@ -31,6 +32,7 @@ func CreateConfig() *Config {
UmamiToken: "",
UmamiUsername: "",
UmamiPassword: "",
UmamiTeamId: "",
Websites: map[string]string{},
CreateNewWebsites: false,
Debug: false,
Expand All @@ -46,6 +48,7 @@ type UmamiFeeder struct {

UmamiHost string
UmamiToken string
UmamiTeamId string
Websites map[string]string
CreateNewWebsites bool
}
Expand All @@ -61,6 +64,7 @@ func New(ctx context.Context, next http.Handler, config *Config, name string) (h

UmamiHost: config.UmamiHost,
UmamiToken: config.UmamiToken,
UmamiTeamId: config.UmamiTeamId,
Websites: config.Websites,
CreateNewWebsites: config.CreateNewWebsites,
}
Expand Down Expand Up @@ -88,7 +92,7 @@ func New(ctx context.Context, next http.Handler, config *Config, name string) (h
}

if h.UmamiToken != "" {
websites, err := fetchWebsites(h.UmamiHost, h.UmamiToken)
websites, err := fetchWebsites(h.UmamiHost, h.UmamiToken, h.UmamiTeamId)
if err != nil {
return nil, fmt.Errorf("failed to fetch websites: %w", err)
}
Expand Down Expand Up @@ -134,7 +138,7 @@ func (h *UmamiFeeder) trackRequest(req *http.Request) {
hostname := parseDomainFromHost(req.Host)
websiteId, ok := h.Websites[hostname]
if !ok {
website, err := createWebsite(h.UmamiHost, h.UmamiToken, hostname)
website, err := createWebsite(h.UmamiHost, h.UmamiToken, h.UmamiTeamId, hostname)
if err != nil {
h.log("failed to create website: " + err.Error())
return
Expand Down
17 changes: 12 additions & 5 deletions umami_websites.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,19 +15,21 @@ type WebsitesResponse struct {

type Website struct {
ID string `json:"id,omitempty"`
Name string `json:"name"`
Domain string `json:"domain"`
Name string `json:"name,omitempty"`
TeamId string `json:"teamId,omitempty"`
Domain string `json:"domain,omitempty"`
CreatedAt time.Time `json:"createdAt,omitempty"`
}

func createWebsite(umamiHost string, umamiToken string, websiteDomain string) (*Website, error) {
func createWebsite(umamiHost string, umamiToken string, teamId string, websiteDomain string) (*Website, error) {
var headers = make(http.Header)
headers.Set("Authorization", "Bearer "+umamiToken)

var result Website
err := sendRequestAndParse(umamiHost+"/api/websites", Website{
Name: websiteDomain,
Domain: websiteDomain,
TeamId: teamId,
}, headers, &result)

if err != nil {
Expand All @@ -37,12 +39,17 @@ func createWebsite(umamiHost string, umamiToken string, websiteDomain string) (*
return &result, nil
}

func fetchWebsites(umamiHost string, umamiToken string) (*[]Website, error) {
func fetchWebsites(umamiHost string, umamiToken string, teamId string) (*[]Website, error) {
var headers = make(http.Header)
headers.Set("Authorization", "Bearer "+umamiToken)

url := umamiHost + "/api/websites?pageSize=200"
if len(teamId) != 0 {
url = umamiHost + "/api/teams/" + teamId + "/websites?pageSize=200"
}

var result WebsitesResponse
err := sendRequestAndParse(umamiHost+"/api/websites?pageSize=200", nil, headers, &result)
err := sendRequestAndParse(url, nil, headers, &result)

if err != nil {
return nil, err
Expand Down

0 comments on commit 3e5c982

Please sign in to comment.