mirror of
https://github.com/umami-software/umami.git
synced 2025-12-06 01:18:00 +01:00
Merge branch 'master' into dev
# Conflicts: # .github/workflows/ci.yml # src/lang/es-ES.json # src/lang/sl-SI.json # src/lib/constants.ts # src/lib/detect.ts # src/queries/sql/reports/getRevenue.ts
This commit is contained in:
commit
04c06443a8
9 changed files with 259 additions and 370 deletions
28
.github/workflows/ci.yml
vendored
28
.github/workflows/ci.yml
vendored
|
|
@ -18,19 +18,15 @@ jobs:
|
||||||
db-type: postgresql
|
db-type: postgresql
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
|
- name: Use Node.js ${{ matrix.node-version }}
|
||||||
- name: Install pnpm
|
uses: actions/setup-node@v4
|
||||||
uses: pnpm/action-setup@v2
|
with:
|
||||||
with:
|
node-version: ${{ matrix.node-version }}
|
||||||
version: 10
|
cache: 'pnpm'
|
||||||
|
env:
|
||||||
- name: Use Node.js ${{ matrix.node-version }}
|
DATABASE_TYPE: ${{ matrix.db-type }}
|
||||||
uses: actions/setup-node@v4
|
- run: npm install --global pnpm
|
||||||
with:
|
- run: pnpm install
|
||||||
node-version: ${{ matrix.node-version }}
|
- run: pnpm test
|
||||||
cache: 'pnpm'
|
- run: pnpm build
|
||||||
|
|
||||||
- run: pnpm install
|
|
||||||
- run: pnpm test
|
|
||||||
- run: pnpm build
|
|
||||||
|
|
|
||||||
1
.gitignore
vendored
1
.gitignore
vendored
|
|
@ -4,6 +4,7 @@
|
||||||
node_modules
|
node_modules
|
||||||
.pnp
|
.pnp
|
||||||
.pnp.js
|
.pnp.js
|
||||||
|
.pnpm-store
|
||||||
|
|
||||||
# testing
|
# testing
|
||||||
/coverage
|
/coverage
|
||||||
|
|
|
||||||
10
README.md
10
README.md
|
|
@ -43,7 +43,7 @@ A detailed getting started guide can be found at [umami.is/docs](https://umami.i
|
||||||
```bash
|
```bash
|
||||||
git clone https://github.com/umami-software/umami.git
|
git clone https://github.com/umami-software/umami.git
|
||||||
cd umami
|
cd umami
|
||||||
npm install
|
pnpm install
|
||||||
```
|
```
|
||||||
|
|
||||||
### Configure Umami
|
### Configure Umami
|
||||||
|
|
@ -64,7 +64,7 @@ mysql://username:mypassword@localhost:3306/mydb
|
||||||
### Build the Application
|
### Build the Application
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
npm run build
|
pnpm run build
|
||||||
```
|
```
|
||||||
|
|
||||||
_The build step will create tables in your database if you are installing for the first time. It will also create a login user with username **admin** and password **umami**._
|
_The build step will create tables in your database if you are installing for the first time. It will also create a login user with username **admin** and password **umami**._
|
||||||
|
|
@ -72,7 +72,7 @@ _The build step will create tables in your database if you are installing for th
|
||||||
### Start the Application
|
### Start the Application
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
npm run start
|
pnpm run start
|
||||||
```
|
```
|
||||||
|
|
||||||
_By default, this will launch the application on `http://localhost:3000`. You will need to either [proxy](https://docs.nginx.com/nginx/admin-guide/web-server/reverse-proxy/) requests from your web server or change the [port](https://nextjs.org/docs/api-reference/cli#production) to serve the application directly._
|
_By default, this will launch the application on `http://localhost:3000`. You will need to either [proxy](https://docs.nginx.com/nginx/admin-guide/web-server/reverse-proxy/) requests from your web server or change the [port](https://nextjs.org/docs/api-reference/cli#production) to serve the application directly._
|
||||||
|
|
@ -107,8 +107,8 @@ To get the latest features, simply do a pull, install any new dependencies, and
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
git pull
|
git pull
|
||||||
npm install
|
pnpm install
|
||||||
npm run build
|
pnpm run build
|
||||||
```
|
```
|
||||||
|
|
||||||
To update the Docker image, simply pull the new images and rebuild:
|
To update the Docker image, simply pull the new images and rebuild:
|
||||||
|
|
|
||||||
|
|
@ -134,7 +134,7 @@
|
||||||
"label.last-days": "Últimos {x} días",
|
"label.last-days": "Últimos {x} días",
|
||||||
"label.last-hours": "Últimas {x} horas",
|
"label.last-hours": "Últimas {x} horas",
|
||||||
"label.last-months": "Últimos {x} meses",
|
"label.last-months": "Últimos {x} meses",
|
||||||
"label.last-seen": "Última vez visto",
|
"label.last-seen": "Visto por última vez",
|
||||||
"label.leave": "Abandonar",
|
"label.leave": "Abandonar",
|
||||||
"label.leave-team": "Abandonar equipo",
|
"label.leave-team": "Abandonar equipo",
|
||||||
"label.less-than": "Menor que",
|
"label.less-than": "Menor que",
|
||||||
|
|
@ -210,8 +210,9 @@
|
||||||
"label.reset-website": "Reiniciar analíticas",
|
"label.reset-website": "Reiniciar analíticas",
|
||||||
"label.retention": "Retención",
|
"label.retention": "Retención",
|
||||||
"label.retention-description": "Medir la frecuencia con la que los usuarios vuelven a tu sitio web.",
|
"label.retention-description": "Medir la frecuencia con la que los usuarios vuelven a tu sitio web.",
|
||||||
"label.revenue": "Ingresos",
|
"label.revenue": "Ganancias",
|
||||||
"label.revenue-description": "Consulte sus ingresos a lo largo del tiempo.",
|
"label.revenue-description": "Analice sus ganancias a lo largo del tiempo.",
|
||||||
|
"label.revenue-property": "Propiedad de ganancias",
|
||||||
"label.role": "Rol",
|
"label.role": "Rol",
|
||||||
"label.run-query": "Ejecutar consulta",
|
"label.run-query": "Ejecutar consulta",
|
||||||
"label.save": "Guardar",
|
"label.save": "Guardar",
|
||||||
|
|
@ -223,7 +224,6 @@
|
||||||
"label.select-role": "Seleccionar rol",
|
"label.select-role": "Seleccionar rol",
|
||||||
"label.select-website": "Seleccionar sitio web",
|
"label.select-website": "Seleccionar sitio web",
|
||||||
"label.session": "Sesión",
|
"label.session": "Sesión",
|
||||||
"label.session-data": "Datos de sesión",
|
|
||||||
"label.sessions": "Sesiones",
|
"label.sessions": "Sesiones",
|
||||||
"label.settings": "Ajustes",
|
"label.settings": "Ajustes",
|
||||||
"label.share": "Compartir",
|
"label.share": "Compartir",
|
||||||
|
|
@ -259,18 +259,19 @@
|
||||||
"label.total": "Total",
|
"label.total": "Total",
|
||||||
"label.total-records": "Total de registros",
|
"label.total-records": "Total de registros",
|
||||||
"label.tracking-code": "Código de rastreo",
|
"label.tracking-code": "Código de rastreo",
|
||||||
"label.transactions": "Transactions",
|
"label.transactions": "Transacciones",
|
||||||
"label.transfer": "Transferir",
|
"label.transfer": "Transferir",
|
||||||
"label.transfer-website": "Transferir sitio web",
|
"label.transfer-website": "Transferir sitio web",
|
||||||
"label.true": "Verdadero",
|
"label.true": "Verdadero",
|
||||||
"label.type": "Tipo",
|
"label.type": "Tipo",
|
||||||
"label.unique": "Único",
|
"label.unique": "Único",
|
||||||
"label.unique-visitors": "Visitantes únicos",
|
"label.unique-visitors": "Visitantes únicos",
|
||||||
"label.uniqueCustomers": "Unique Customers",
|
"label.uniqueCustomers": "Clientes únicos",
|
||||||
"label.unknown": "Desconocida",
|
"label.unknown": "Desconocida",
|
||||||
"label.untitled": "Sin título",
|
"label.untitled": "Sin título",
|
||||||
"label.update": "Actualizar",
|
"label.update": "Actualizar",
|
||||||
"label.user": "Usuario",
|
"label.user": "Usuario",
|
||||||
|
"label.user-property": "Propiedad de usuario",
|
||||||
"label.username": "Nombre de usuario",
|
"label.username": "Nombre de usuario",
|
||||||
"label.users": "Usuarios",
|
"label.users": "Usuarios",
|
||||||
"label.utm": "UTM",
|
"label.utm": "UTM",
|
||||||
|
|
|
||||||
|
|
@ -32,27 +32,21 @@
|
||||||
"label.cities": "Mesta",
|
"label.cities": "Mesta",
|
||||||
"label.city": "Mesto",
|
"label.city": "Mesto",
|
||||||
"label.clear-all": "Počisti vse",
|
"label.clear-all": "Počisti vse",
|
||||||
"label.cohort": "Kohorta",
|
|
||||||
"label.compare": "Primerjaj",
|
"label.compare": "Primerjaj",
|
||||||
"label.compare-dates": "Primerjaj datume",
|
|
||||||
"label.confirm": "Potrdi",
|
"label.confirm": "Potrdi",
|
||||||
"label.confirm-password": "Potrdi geslo",
|
"label.confirm-password": "Potrdi geslo",
|
||||||
"label.contains": "Vsebuje",
|
"label.contains": "Vsebuje",
|
||||||
"label.content": "Vsebina",
|
"label.content": "Vsebina",
|
||||||
"label.continue": "Nadaljuj",
|
"label.continue": "Nadaljuj",
|
||||||
"label.conversion": "Konverzija",
|
"label.count": "Število",
|
||||||
"label.conversion-rate": "Stopnja konverzije",
|
|
||||||
"label.conversion-step": "Korak konverzije",
|
|
||||||
"label.count": "Števec",
|
|
||||||
"label.countries": "Države",
|
"label.countries": "Države",
|
||||||
"label.country": "Država",
|
"label.country": "Država",
|
||||||
"label.create": "Create",
|
"label.create": "Ustvari",
|
||||||
"label.create-report": "Ustvari poročilo",
|
"label.create-report": "Ustvari poročilo",
|
||||||
"label.create-team": "Ustvari ekipo",
|
"label.create-team": "Ustvari ekipo",
|
||||||
"label.create-user": "Ustvari uporabnika",
|
"label.create-user": "Ustvari uporabnika",
|
||||||
"label.created": "Ustvarjeno",
|
"label.created": "Ustvarjeno",
|
||||||
"label.created-by": "Ustvaril",
|
"label.created-by": "Ustvaril",
|
||||||
"label.currency": "Valuta",
|
|
||||||
"label.current": "Trenutno",
|
"label.current": "Trenutno",
|
||||||
"label.current-password": "Trenutno geslo",
|
"label.current-password": "Trenutno geslo",
|
||||||
"label.custom-range": "Obdobje po meri",
|
"label.custom-range": "Obdobje po meri",
|
||||||
|
|
@ -83,16 +77,14 @@
|
||||||
"label.edit": "Uredi",
|
"label.edit": "Uredi",
|
||||||
"label.edit-dashboard": "Uredi nadzorno ploščo",
|
"label.edit-dashboard": "Uredi nadzorno ploščo",
|
||||||
"label.edit-member": "Uredi člana",
|
"label.edit-member": "Uredi člana",
|
||||||
"label.email": "Email",
|
"label.enable-share-url": "Omogoči povezavo za deljenje",
|
||||||
"label.enable-share-url": "Uredi povezavo za deljenje",
|
|
||||||
"label.end-step": "Končni korak",
|
"label.end-step": "Končni korak",
|
||||||
"label.entry": "Vhodni URL",
|
"label.entry": "Vstopni URL",
|
||||||
"label.event": "Dogodek",
|
"label.event": "Dogodek",
|
||||||
"label.event-data": "Podatki dogodka",
|
"label.event-data": "Podatki dogodka",
|
||||||
"label.event-name": "Ime dogodka",
|
"label.event-name": "Ime dogodka",
|
||||||
"label.events": "Dogodki",
|
"label.events": "Dogodki",
|
||||||
"label.exists": "Obstaja",
|
"label.exit": "Izhodni URL",
|
||||||
"label.exit": "Exit URL",
|
|
||||||
"label.false": "Napačno",
|
"label.false": "Napačno",
|
||||||
"label.field": "Polje",
|
"label.field": "Polje",
|
||||||
"label.fields": "Polja",
|
"label.fields": "Polja",
|
||||||
|
|
@ -100,22 +92,18 @@
|
||||||
"label.filter-combined": "Skupaj",
|
"label.filter-combined": "Skupaj",
|
||||||
"label.filter-raw": "Neobdelano",
|
"label.filter-raw": "Neobdelano",
|
||||||
"label.filters": "Filtri",
|
"label.filters": "Filtri",
|
||||||
"label.first-click": "Prvi klik",
|
"label.first-seen": "Prvič viden",
|
||||||
"label.first-seen": "First seen",
|
|
||||||
"label.funnel": "Prodajni lijak",
|
"label.funnel": "Prodajni lijak",
|
||||||
"label.funnel-description": "Understand the conversion and drop-off rate of users.",
|
"label.funnel-description": "Razumite stopnjo konverzije in osipa uporabnikov.",
|
||||||
"label.funnels": "Lijaki",
|
|
||||||
"label.goal": "Cilj",
|
"label.goal": "Cilj",
|
||||||
"label.goals": "Cilji",
|
"label.goals": "Cilji",
|
||||||
"label.goals-description": "Spremljajte svoje cilje za oglede strani in dogodke.",
|
"label.goals-description": "Spremljajte svoje cilje za oglede strani in dogodke.",
|
||||||
"label.greater-than": "Večje od",
|
"label.greater-than": "Večje od",
|
||||||
"label.greater-than-equals": "Večje ali enako kot",
|
"label.greater-than-equals": "Večje ali enako kot",
|
||||||
"label.grouped": "Združeno",
|
"label.host": "Gostitelj",
|
||||||
"label.hostname": "Ime gostitelja",
|
"label.hosts": "Gostitelji",
|
||||||
"label.includes": "Vključuje",
|
|
||||||
"label.insight": "Vpogled",
|
|
||||||
"label.insights": "Vpogled",
|
"label.insights": "Vpogled",
|
||||||
"label.insights-description": "Dive deeper into your data by using segments and filters.",
|
"label.insights-description": "Poglobite se v podatke z uporabo segmentov in filtrov.",
|
||||||
"label.is": "Je",
|
"label.is": "Je",
|
||||||
"label.is-false": "Je napačno",
|
"label.is-false": "Je napačno",
|
||||||
"label.is-not": "Ni",
|
"label.is-not": "Ni",
|
||||||
|
|
@ -124,9 +112,8 @@
|
||||||
"label.is-true": "Je res",
|
"label.is-true": "Je res",
|
||||||
"label.join": "Pridruži se",
|
"label.join": "Pridruži se",
|
||||||
"label.join-team": "Pridruži se ekipi",
|
"label.join-team": "Pridruži se ekipi",
|
||||||
"label.journey": "Potovanje",
|
"label.journey": "Uporabniška pot",
|
||||||
"label.journey-description": "Razumite, kako uporabniki krmarijo po vašem spletnem mestu.",
|
"label.journey-description": "Razumite, kako uporabniki krmarijo po vašem spletnem mestu.",
|
||||||
"label.journeys": "Potovanja",
|
|
||||||
"label.language": "Jezik",
|
"label.language": "Jezik",
|
||||||
"label.languages": "Jeziki",
|
"label.languages": "Jeziki",
|
||||||
"label.laptop": "Prenosni računalnik",
|
"label.laptop": "Prenosni računalnik",
|
||||||
|
|
@ -134,7 +121,7 @@
|
||||||
"label.last-days": "Zadnjih {x} dni",
|
"label.last-days": "Zadnjih {x} dni",
|
||||||
"label.last-hours": "Zadnjih {x} ur",
|
"label.last-hours": "Zadnjih {x} ur",
|
||||||
"label.last-months": "Zadnjih {x} mesecev",
|
"label.last-months": "Zadnjih {x} mesecev",
|
||||||
"label.last-seen": "Zadnjič videno",
|
"label.last-seen": "Nazadnje viden",
|
||||||
"label.leave": "Zapusti",
|
"label.leave": "Zapusti",
|
||||||
"label.leave-team": "Zapusti ekipo",
|
"label.leave-team": "Zapusti ekipo",
|
||||||
"label.less-than": "Manjše kot",
|
"label.less-than": "Manjše kot",
|
||||||
|
|
@ -142,11 +129,9 @@
|
||||||
"label.links": "Povezave",
|
"label.links": "Povezave",
|
||||||
"label.login": "Prijava",
|
"label.login": "Prijava",
|
||||||
"label.logout": "Odjava",
|
"label.logout": "Odjava",
|
||||||
"label.manage": "Manage",
|
"label.manage": "Upravljaj",
|
||||||
"label.manager": "Manager",
|
"label.manager": "Upravitelj",
|
||||||
"label.max": "Največ",
|
"label.max": "Največ",
|
||||||
"label.maximize": "Razširi",
|
|
||||||
"label.medium": "Srednje",
|
|
||||||
"label.member": "Član",
|
"label.member": "Član",
|
||||||
"label.members": "Člani",
|
"label.members": "Člani",
|
||||||
"label.min": "Najmanj",
|
"label.min": "Najmanj",
|
||||||
|
|
@ -182,7 +167,6 @@
|
||||||
"label.password": "Geslo",
|
"label.password": "Geslo",
|
||||||
"label.path": "Pot",
|
"label.path": "Pot",
|
||||||
"label.paths": "Poti",
|
"label.paths": "Poti",
|
||||||
"label.pixels": "Pikslov",
|
|
||||||
"label.powered-by": "Poganja {name}",
|
"label.powered-by": "Poganja {name}",
|
||||||
"label.previous": "Prejšnji",
|
"label.previous": "Prejšnji",
|
||||||
"label.previous-period": "Prejšnje obdobje",
|
"label.previous-period": "Prejšnje obdobje",
|
||||||
|
|
@ -203,48 +187,44 @@
|
||||||
"label.regions": "Regije",
|
"label.regions": "Regije",
|
||||||
"label.remaining": "Preostalo",
|
"label.remaining": "Preostalo",
|
||||||
"label.remove": "Odstrani",
|
"label.remove": "Odstrani",
|
||||||
"label.remove-member": "Remove member",
|
"label.remove-member": "Odstrani člana",
|
||||||
"label.reports": "Poročila",
|
"label.reports": "Poročila",
|
||||||
"label.required": "Zahtevano",
|
"label.required": "Zahtevano",
|
||||||
"label.reset": "Ponastavi",
|
"label.reset": "Ponastavi",
|
||||||
"label.reset-website": "Ponastavi statistiko",
|
"label.reset-website": "Ponastavi statistiko",
|
||||||
"label.retention": "Ohranjanje uporabnikov",
|
"label.retention": "Ohranjanje uporabnikov",
|
||||||
"label.retention-description": "Measure your website stickiness by tracking how often users return.",
|
"label.retention-description": "Merite uporabnikovo zadržanost s sledenjem, kako pogosto se vračajo.",
|
||||||
"label.revenue": "Prihodek",
|
"label.revenue": "Prihodki",
|
||||||
"label.revenue-description": "Oglejte si svoj prihodek skozi čas.",
|
"label.revenue-description": "Preglejte svoje prihodke skozi čas.",
|
||||||
|
"label.revenue-property": "Lastnost prihodkov",
|
||||||
"label.role": "Vloga",
|
"label.role": "Vloga",
|
||||||
"label.run-query": "Izvedi poizvedbo",
|
"label.run-query": "Izvedi poizvedbo",
|
||||||
"label.save": "Shrani",
|
"label.save": "Shrani",
|
||||||
"label.screens": "Zasloni",
|
"label.screens": "Zasloni",
|
||||||
"label.search": "Search",
|
"label.search": "Išči",
|
||||||
"label.select": "Select",
|
"label.select": "Izberi",
|
||||||
"label.select-date": "Izberi datum",
|
"label.select-date": "Izberi datum",
|
||||||
"label.select-filter": "Izberi filter",
|
"label.select-role": "Izberi vlogo",
|
||||||
"label.select-role": "Select role",
|
|
||||||
"label.select-website": "Izberi spletno mesto",
|
"label.select-website": "Izberi spletno mesto",
|
||||||
"label.session": "Seja",
|
"label.session": "Seja",
|
||||||
"label.session-data": "Podatki seje",
|
|
||||||
"label.sessions": "Seje",
|
"label.sessions": "Seje",
|
||||||
"label.settings": "Nastavitve",
|
"label.settings": "Nastavitve",
|
||||||
"label.share": "Deli",
|
"label.share": "Deli",
|
||||||
"label.share-url": "Deli povezavo",
|
"label.share-url": "Deli povezavo",
|
||||||
"label.single-day": "En dan",
|
"label.single-day": "En dan",
|
||||||
"label.sms": "SMS",
|
"label.start-step": "Začetni korak",
|
||||||
"label.sources": "Viri",
|
"label.steps": "Koraki",
|
||||||
"label.start-step": "Start Step",
|
|
||||||
"label.steps": "Steps",
|
|
||||||
"label.sum": "Seštevek",
|
"label.sum": "Seštevek",
|
||||||
"label.tablet": "Tablični računalnik",
|
"label.tablet": "Tablični računalnik",
|
||||||
"label.tag": "Oznaka",
|
"label.tag": "Oznaka",
|
||||||
"label.tags": "Oznake",
|
"label.tags": "Oznake",
|
||||||
"label.team": "Ekipa",
|
"label.team": "Ekipa",
|
||||||
"label.team-id": "ID ekipe",
|
"label.team-id": "ID ekipe",
|
||||||
"label.team-manager": "Vodja ekipe",
|
"label.team-manager": "Upravitelj ekipe",
|
||||||
"label.team-member": "Član ekipe",
|
"label.team-member": "Član ekipe",
|
||||||
"label.team-name": "Ime ekipe",
|
"label.team-name": "Ime ekipe",
|
||||||
"label.team-owner": "Lastnik ekipe",
|
"label.team-owner": "Lastnik ekipe",
|
||||||
"label.team-settings": "Nastavitve ekipe",
|
"label.team-view-only": "Ekipa samo za ogled",
|
||||||
"label.team-view-only": "Team view only",
|
|
||||||
"label.team-websites": "Spletna mesta ekipe",
|
"label.team-websites": "Spletna mesta ekipe",
|
||||||
"label.teams": "Ekipe",
|
"label.teams": "Ekipe",
|
||||||
"label.terms": "Pogoji",
|
"label.terms": "Pogoji",
|
||||||
|
|
@ -286,18 +266,17 @@
|
||||||
"label.visits": "Visits",
|
"label.visits": "Visits",
|
||||||
"label.website": "Spletno mesto",
|
"label.website": "Spletno mesto",
|
||||||
"label.website-id": "ID spletnega mesta",
|
"label.website-id": "ID spletnega mesta",
|
||||||
"label.websites": "Spletnih mest",
|
"label.websites": "Spletna mesta",
|
||||||
"label.window": "Okno",
|
"label.window": "Okno",
|
||||||
"label.yesterday": "Včeraj",
|
"label.yesterday": "Včeraj",
|
||||||
"message.action-confirmation": "Type {confirmation} in the box below to confirm.",
|
"message.action-confirmation": "Za potrditev v spodnje polje vnesite {confirmation}.",
|
||||||
"message.active-users": "{x} trenutni {x, plural, one {obiskovalec} other {obiskovalcev}}",
|
"message.active-users": "{x} trenutni {x, plural, one {obiskovalec} other {obiskovalcev}}",
|
||||||
"message.bad-request": "Bad request",
|
"message.collected-data": "Zbrani podatki",
|
||||||
"message.collected-data": "Collected data",
|
|
||||||
"message.confirm-delete": "Ste prepričani, da želite izbrisati {target}?",
|
"message.confirm-delete": "Ste prepričani, da želite izbrisati {target}?",
|
||||||
"message.confirm-leave": "Ste prepričani, da želite zapustiti {target}?",
|
"message.confirm-leave": "Ste prepričani, da želite zapustiti {target}?",
|
||||||
"message.confirm-remove": "Are you sure you want to remove {target}?",
|
"message.confirm-remove": "Ali ste prepričani, da želite odstraniti {target}?",
|
||||||
"message.confirm-reset": "Ste prepričani, da želite ponastaviti statistiko {target}?",
|
"message.confirm-reset": "Ste prepričani, da želite ponastaviti statistiko {target}?",
|
||||||
"message.delete-team-warning": "Deleting a team will also delete all team websites.",
|
"message.delete-team-warning": "Brisanje ekipe bo izbrisalo tudi vsa spletna mesta ekipe.",
|
||||||
"message.delete-website-warning": "Izbrisani bodo tudi vsi pripadajoči podatki.",
|
"message.delete-website-warning": "Izbrisani bodo tudi vsi pripadajoči podatki.",
|
||||||
"message.error": "Nekaj je šlo narobe.",
|
"message.error": "Nekaj je šlo narobe.",
|
||||||
"message.event-log": "{event} na {url}",
|
"message.event-log": "{event} na {url}",
|
||||||
|
|
@ -327,12 +306,12 @@
|
||||||
"message.team-not-found": "Ekipa ni bila najdena.",
|
"message.team-not-found": "Ekipa ni bila najdena.",
|
||||||
"message.team-websites-info": "Spletne strani si lahko ogleda vsak član ekipe.",
|
"message.team-websites-info": "Spletne strani si lahko ogleda vsak član ekipe.",
|
||||||
"message.tracking-code": "Koda za sledenje",
|
"message.tracking-code": "Koda za sledenje",
|
||||||
"message.transfer-team-website-to-user": "Transfer this website to your account?",
|
"message.transfer-team-website-to-user": "Želite prenesti to spletno mesto v svoj račun?",
|
||||||
"message.transfer-user-website-to-team": "Select the team to transfer this website to.",
|
"message.transfer-user-website-to-team": "Izberite ekipo, na katero želite prenesti to spletno mesto.",
|
||||||
"message.transfer-website": "Transfer website ownership to your account or another team.",
|
"message.transfer-website": "Prenesite lastništvo spletnega mesta na svoj račun ali drugo ekipo.",
|
||||||
"message.triggered-event": "Triggered event",
|
"message.triggered-event": "Sprožen dogodek",
|
||||||
"message.unauthorized": "Unauthorized",
|
|
||||||
"message.user-deleted": "Uporabnik je izbrisan.",
|
"message.user-deleted": "Uporabnik je izbrisan.",
|
||||||
"message.viewed-page": "Viewed page",
|
"message.viewed-page": "Ogledana stran",
|
||||||
"message.visitor-log": "Obiskovalec iz {country} uporablja {browser} na {os} {device}"
|
"message.visitor-log": "Obiskovalec iz {country} uporablja {browser} na {os} {device}",
|
||||||
|
"message.visitors-dropped-off": "Osip obiskovalcev"
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
import * as detect from '../detect';
|
import * as detect from '../detect';
|
||||||
|
|
||||||
const IP = '127.0.0.1';
|
const IP = '127.0.0.1';
|
||||||
|
const BAD_IP = '127.127.127.127';
|
||||||
|
|
||||||
test('getIpAddress: Custom header', () => {
|
test('getIpAddress: Custom header', () => {
|
||||||
process.env.CLIENT_IP_HEADER = 'x-custom-ip-header';
|
process.env.CLIENT_IP_HEADER = 'x-custom-ip-header';
|
||||||
|
|
@ -16,6 +17,12 @@ test('getIpAddress: Standard header', () => {
|
||||||
expect(detect.getIpAddress(new Headers({ 'x-forwarded-for': IP }))).toEqual(IP);
|
expect(detect.getIpAddress(new Headers({ 'x-forwarded-for': IP }))).toEqual(IP);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('getIpAddress: CloudFlare header is lower priority than standard header', () => {
|
||||||
|
expect(
|
||||||
|
detect.getIpAddress(new Headers({ 'cf-connecting-ip': BAD_IP, 'x-forwarded-for': IP })),
|
||||||
|
).toEqual(IP);
|
||||||
|
});
|
||||||
|
|
||||||
test('getIpAddress: No header', () => {
|
test('getIpAddress: No header', () => {
|
||||||
expect(detect.getIpAddress(new Headers())).toEqual(null);
|
expect(detect.getIpAddress(new Headers())).toEqual(null);
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -126,12 +126,12 @@ export const DATA_TYPES = {
|
||||||
|
|
||||||
export const ROLES = {
|
export const ROLES = {
|
||||||
admin: 'admin',
|
admin: 'admin',
|
||||||
user: 'user',
|
|
||||||
viewOnly: 'view-only',
|
|
||||||
teamOwner: 'team-owner',
|
|
||||||
teamManager: 'team-manager',
|
teamManager: 'team-manager',
|
||||||
teamMember: 'team-member',
|
teamMember: 'team-member',
|
||||||
|
teamOwner: 'team-owner',
|
||||||
teamViewOnly: 'team-view-only',
|
teamViewOnly: 'team-view-only',
|
||||||
|
user: 'user',
|
||||||
|
viewOnly: 'view-only',
|
||||||
} as const;
|
} as const;
|
||||||
|
|
||||||
export const PERMISSIONS = {
|
export const PERMISSIONS = {
|
||||||
|
|
@ -223,7 +223,7 @@ export const URL_LENGTH = 500;
|
||||||
export const PAGE_TITLE_LENGTH = 500;
|
export const PAGE_TITLE_LENGTH = 500;
|
||||||
export const EVENT_NAME_LENGTH = 50;
|
export const EVENT_NAME_LENGTH = 50;
|
||||||
|
|
||||||
export const UTM_PARAMS = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content'];
|
export const UTM_PARAMS = ['utm_campaign', 'utm_content', 'utm_medium', 'utm_source', 'utm_term'];
|
||||||
|
|
||||||
export const DESKTOP_OS = [
|
export const DESKTOP_OS = [
|
||||||
'BeOS',
|
'BeOS',
|
||||||
|
|
@ -261,8 +261,8 @@ export const OS_NAMES = {
|
||||||
export const BROWSERS = {
|
export const BROWSERS = {
|
||||||
android: 'Android',
|
android: 'Android',
|
||||||
aol: 'AOL',
|
aol: 'AOL',
|
||||||
beaker: 'Beaker',
|
|
||||||
bb10: 'BlackBerry 10',
|
bb10: 'BlackBerry 10',
|
||||||
|
beaker: 'Beaker',
|
||||||
chrome: 'Chrome',
|
chrome: 'Chrome',
|
||||||
'chromium-webview': 'Chrome (webview)',
|
'chromium-webview': 'Chrome (webview)',
|
||||||
crios: 'Chrome (iOS)',
|
crios: 'Chrome (iOS)',
|
||||||
|
|
@ -284,15 +284,17 @@ export const BROWSERS = {
|
||||||
phantomjs: 'PhantomJS',
|
phantomjs: 'PhantomJS',
|
||||||
safari: 'Safari',
|
safari: 'Safari',
|
||||||
samsung: 'Samsung',
|
samsung: 'Samsung',
|
||||||
silk: 'Silk',
|
|
||||||
searchbot: 'Searchbot',
|
searchbot: 'Searchbot',
|
||||||
|
silk: 'Silk',
|
||||||
yandexbrowser: 'Yandex',
|
yandexbrowser: 'Yandex',
|
||||||
} as const;
|
} as const;
|
||||||
|
|
||||||
|
// The order here is important and influences how IPs are detected by lib/detect.ts
|
||||||
|
// Please do not change the order unless you know exactly what you're doing - read https://developers.cloudflare.com/fundamentals/reference/http-headers/
|
||||||
export const IP_ADDRESS_HEADERS = [
|
export const IP_ADDRESS_HEADERS = [
|
||||||
'cf-connecting-ip',
|
|
||||||
'x-client-ip',
|
'x-client-ip',
|
||||||
'x-forwarded-for',
|
'x-forwarded-for',
|
||||||
|
'cf-connecting-ip', // This should be *after* x-forwarded-for, so that x-forwarded-for is respected if present
|
||||||
'do-connecting-ip',
|
'do-connecting-ip',
|
||||||
'fastly-client-ip',
|
'fastly-client-ip',
|
||||||
'true-client-ip',
|
'true-client-ip',
|
||||||
|
|
@ -301,354 +303,246 @@ export const IP_ADDRESS_HEADERS = [
|
||||||
'x-forwarded',
|
'x-forwarded',
|
||||||
'forwarded',
|
'forwarded',
|
||||||
'x-appengine-user-ip',
|
'x-appengine-user-ip',
|
||||||
|
'x-nf-client-connection-ip',
|
||||||
|
'x-real-ip',
|
||||||
];
|
];
|
||||||
|
|
||||||
export const SOCIAL_DOMAINS = [
|
export const SOCIAL_DOMAINS = [
|
||||||
|
'bsky.app',
|
||||||
'facebook.com',
|
'facebook.com',
|
||||||
'fb.com',
|
'fb.com',
|
||||||
'instagram.com',
|
|
||||||
'ig.com',
|
'ig.com',
|
||||||
'twitter.com',
|
'instagram.com',
|
||||||
't.co',
|
|
||||||
'x.com',
|
|
||||||
'linkedin.',
|
'linkedin.',
|
||||||
'tiktok.',
|
|
||||||
'reddit.',
|
|
||||||
'threads.net',
|
|
||||||
'bsky.app',
|
|
||||||
'news.ycombinator.com',
|
'news.ycombinator.com',
|
||||||
'snapchat.',
|
|
||||||
'pinterest.',
|
'pinterest.',
|
||||||
|
'reddit.',
|
||||||
|
'snapchat.',
|
||||||
|
't.co',
|
||||||
|
'threads.net',
|
||||||
|
'tiktok.',
|
||||||
|
'twitter.com',
|
||||||
|
'x.com',
|
||||||
];
|
];
|
||||||
|
|
||||||
export const SEARCH_DOMAINS = [
|
export const SEARCH_DOMAINS = [
|
||||||
'google.',
|
'baidu.com',
|
||||||
'bing.com',
|
'bing.com',
|
||||||
'msn.com',
|
'chatgpt.com',
|
||||||
'duckduckgo.com',
|
'duckduckgo.com',
|
||||||
|
'ecosia.org',
|
||||||
|
'google.',
|
||||||
|
'msn.com',
|
||||||
|
'perplexity.ai',
|
||||||
'search.brave.com',
|
'search.brave.com',
|
||||||
'yandex.',
|
'yandex.',
|
||||||
'baidu.com',
|
|
||||||
'ecosia.org',
|
|
||||||
'chatgpt.com',
|
|
||||||
'perplexity.ai',
|
|
||||||
];
|
];
|
||||||
|
|
||||||
export const SHOPPING_DOMAINS = [
|
export const SHOPPING_DOMAINS = [
|
||||||
'amazon.',
|
'alibaba.com',
|
||||||
'ebay.com',
|
|
||||||
'walmart.com',
|
|
||||||
'alibab.com',
|
|
||||||
'aliexpress.com',
|
'aliexpress.com',
|
||||||
'etsy.com',
|
'amazon.',
|
||||||
'bestbuy.com',
|
'bestbuy.com',
|
||||||
'target.com',
|
'ebay.com',
|
||||||
|
'etsy.com',
|
||||||
'newegg.com',
|
'newegg.com',
|
||||||
|
'target.com',
|
||||||
|
'walmart.com',
|
||||||
];
|
];
|
||||||
|
|
||||||
export const EMAIL_DOMAINS = [
|
export const EMAIL_DOMAINS = [
|
||||||
'gmail.',
|
'gmail.',
|
||||||
|
'hotmail.',
|
||||||
'mail.yahoo.',
|
'mail.yahoo.',
|
||||||
'outlook.',
|
'outlook.',
|
||||||
'hotmail.',
|
|
||||||
'protonmail.',
|
|
||||||
'proton.me',
|
'proton.me',
|
||||||
|
'protonmail.',
|
||||||
];
|
];
|
||||||
|
|
||||||
export const VIDEO_DOMAINS = ['youtube.', 'twitch.'];
|
export const VIDEO_DOMAINS = ['twitch.', 'youtube.'];
|
||||||
|
|
||||||
export const PAID_AD_PARAMS = [
|
export const PAID_AD_PARAMS = [
|
||||||
'utm_source=google',
|
|
||||||
'gclid=',
|
|
||||||
'fbclid=',
|
|
||||||
'msclkid=',
|
|
||||||
'dclid=',
|
|
||||||
'twclid=',
|
|
||||||
'li_fat_id=',
|
|
||||||
'epik=',
|
|
||||||
'ttclid=',
|
|
||||||
'scid=',
|
|
||||||
'aid=',
|
|
||||||
'pc_id=',
|
|
||||||
'ad_id=',
|
'ad_id=',
|
||||||
'rdt_cid=',
|
'aid=',
|
||||||
|
'dclid=',
|
||||||
|
'epik=',
|
||||||
|
'fbclid=',
|
||||||
|
'gclid=',
|
||||||
|
'li_fat_id=',
|
||||||
|
'msclkid=',
|
||||||
'ob_click_id=',
|
'ob_click_id=',
|
||||||
|
'pc_id=',
|
||||||
|
'rdt_cid=',
|
||||||
|
'scid=',
|
||||||
|
'ttclid=',
|
||||||
|
'twclid=',
|
||||||
'utm_medium=cpc',
|
'utm_medium=cpc',
|
||||||
'utm_medium=paid',
|
'utm_medium=paid',
|
||||||
'utm_medium=paid_social',
|
'utm_medium=paid_social',
|
||||||
|
'utm_source=google',
|
||||||
];
|
];
|
||||||
|
|
||||||
export const GROUPED_DOMAINS = [
|
export const GROUPED_DOMAINS = [
|
||||||
{ name: 'Google', domain: 'google.com', match: 'google.' },
|
{ name: 'Baidu', domain: 'baidu.com', match: 'baidu.' },
|
||||||
{ name: 'Facebook', domain: 'facebook.com', match: 'facebook.' },
|
|
||||||
{ name: 'Reddit', domain: 'reddit.com', match: 'reddit.' },
|
|
||||||
{ name: 'LinkedIn', domain: 'linkedin.com', match: 'linkedin.' },
|
|
||||||
{ name: 'GitHub', domain: 'github.com', match: 'github.' },
|
|
||||||
{ name: 'Hacker News', domain: 'news.ycombinator.com', match: 'news.ycombinator.com' },
|
|
||||||
{ name: 'Bing', domain: 'bing.com', match: 'bing.' },
|
{ name: 'Bing', domain: 'bing.com', match: 'bing.' },
|
||||||
{ name: 'Brave', domain: 'brave.com', match: 'brave.' },
|
{ name: 'Brave', domain: 'brave.com', match: 'brave.' },
|
||||||
{ name: 'DuckDuckGo', domain: 'duckduckgo.com', match: 'duckduckgo.' },
|
|
||||||
{ name: 'Twitter', domain: 'twitter.com', match: ['twitter.', 't.co', 'x.com'] },
|
|
||||||
{ name: 'Instagram', domain: 'instagram.com', match: ['instagram.', 'ig.com'] },
|
|
||||||
{ name: 'Snapchat', domain: 'snapchat.com', match: 'snapchat.' },
|
|
||||||
{ name: 'Pinterest', domain: 'pinterest.com', match: 'pinterest.' },
|
|
||||||
{ name: 'ChatGPT', domain: 'chatgpt.com', match: 'chatgpt.' },
|
{ name: 'ChatGPT', domain: 'chatgpt.com', match: 'chatgpt.' },
|
||||||
|
{ name: 'DuckDuckGo', domain: 'duckduckgo.com', match: 'duckduckgo.' },
|
||||||
|
{ name: 'Facebook', domain: 'facebook.com', match: 'facebook.' },
|
||||||
|
{ name: 'GitHub', domain: 'github.com', match: 'github.' },
|
||||||
|
{ name: 'Google', domain: 'google.com', match: 'google.' },
|
||||||
|
{ name: 'Hacker News', domain: 'news.ycombinator.com', match: 'news.ycombinator.com' },
|
||||||
|
{ name: 'Instagram', domain: 'instagram.com', match: ['instagram.', 'ig.com'] },
|
||||||
|
{ name: 'LinkedIn', domain: 'linkedin.com', match: 'linkedin.' },
|
||||||
|
{ name: 'Pinterest', domain: 'pinterest.com', match: 'pinterest.' },
|
||||||
|
{ name: 'Reddit', domain: 'reddit.com', match: 'reddit.' },
|
||||||
|
{ name: 'Snapchat', domain: 'snapchat.com', match: 'snapchat.' },
|
||||||
|
{ name: 'Twitter', domain: 'twitter.com', match: ['twitter.', 't.co', 'x.com'] },
|
||||||
{ name: 'Yahoo', domain: 'yahoo.com', match: 'yahoo.' },
|
{ name: 'Yahoo', domain: 'yahoo.com', match: 'yahoo.' },
|
||||||
{ name: 'Yandex', domain: 'yandex.ru', match: 'yandex.' },
|
{ name: 'Yandex', domain: 'yandex.ru', match: 'yandex.' },
|
||||||
{ name: 'Baidu', domain: 'baidu.com', match: 'baidu.' },
|
|
||||||
];
|
];
|
||||||
|
|
||||||
export const MAP_FILE = '/datamaps.world.json';
|
export const MAP_FILE = '/datamaps.world.json';
|
||||||
|
|
||||||
export const ISO_COUNTRIES = {
|
export const ISO_COUNTRIES = {
|
||||||
AFG: 'AF',
|
ANT: 'AN',
|
||||||
ALA: 'AX',
|
ARE: 'AE',
|
||||||
ALB: 'AL',
|
BLM: 'BL',
|
||||||
DZA: 'DZ',
|
CHE: 'CH',
|
||||||
ASM: 'AS',
|
ESH: 'EH',
|
||||||
AND: 'AD',
|
ESP: 'ES',
|
||||||
AGO: 'AO',
|
FSM: 'FM',
|
||||||
AIA: 'AI',
|
GBR: 'GB',
|
||||||
ATA: 'AQ',
|
|
||||||
ATG: 'AG',
|
|
||||||
ARG: 'AR',
|
|
||||||
ARM: 'AM',
|
|
||||||
ABW: 'AW',
|
|
||||||
AUS: 'AU',
|
|
||||||
AUT: 'AT',
|
|
||||||
AZE: 'AZ',
|
|
||||||
BHS: 'BS',
|
|
||||||
BHR: 'BH',
|
|
||||||
BGD: 'BD',
|
|
||||||
BRB: 'BB',
|
|
||||||
BLR: 'BY',
|
|
||||||
BEL: 'BE',
|
|
||||||
BLZ: 'BZ',
|
|
||||||
BEN: 'BJ',
|
|
||||||
BMU: 'BM',
|
|
||||||
BTN: 'BT',
|
|
||||||
BOL: 'BO',
|
|
||||||
BIH: 'BA',
|
|
||||||
BWA: 'BW',
|
|
||||||
BVT: 'BV',
|
|
||||||
BRA: 'BR',
|
|
||||||
VGB: 'VG',
|
|
||||||
IOT: 'IO',
|
|
||||||
BRN: 'BN',
|
|
||||||
BGR: 'BG',
|
|
||||||
BFA: 'BF',
|
|
||||||
BDI: 'BI',
|
|
||||||
KHM: 'KH',
|
|
||||||
CMR: 'CM',
|
|
||||||
CAN: 'CA',
|
|
||||||
CPV: 'CV',
|
|
||||||
CYM: 'KY',
|
|
||||||
CAF: 'CF',
|
|
||||||
TCD: 'TD',
|
|
||||||
CHL: 'CL',
|
|
||||||
CHN: 'CN',
|
|
||||||
HKG: 'HK',
|
|
||||||
MAC: 'MO',
|
|
||||||
CXR: 'CX',
|
|
||||||
CCK: 'CC',
|
|
||||||
COL: 'CO',
|
|
||||||
COM: 'KM',
|
|
||||||
COG: 'CG',
|
|
||||||
COD: 'CD',
|
|
||||||
COK: 'CK',
|
|
||||||
CRI: 'CR',
|
|
||||||
CIV: 'CI',
|
|
||||||
HRV: 'HR',
|
|
||||||
CUB: 'CU',
|
|
||||||
CYP: 'CY',
|
|
||||||
CZE: 'CZ',
|
|
||||||
DNK: 'DK',
|
|
||||||
DJI: 'DJ',
|
|
||||||
DMA: 'DM',
|
|
||||||
DOM: 'DO',
|
|
||||||
ECU: 'EC',
|
|
||||||
EGY: 'EG',
|
|
||||||
SLV: 'SV',
|
|
||||||
GNQ: 'GQ',
|
|
||||||
ERI: 'ER',
|
|
||||||
EST: 'EE',
|
|
||||||
ETH: 'ET',
|
|
||||||
FLK: 'FK',
|
|
||||||
FRO: 'FO',
|
|
||||||
FJI: 'FJ',
|
|
||||||
FIN: 'FI',
|
|
||||||
FRA: 'FR',
|
|
||||||
GUF: 'GF',
|
|
||||||
PYF: 'PF',
|
|
||||||
ATF: 'TF',
|
|
||||||
GAB: 'GA',
|
|
||||||
GMB: 'GM',
|
|
||||||
GEO: 'GE',
|
|
||||||
DEU: 'DE',
|
|
||||||
GHA: 'GH',
|
|
||||||
GIB: 'GI',
|
|
||||||
GRC: 'GR',
|
|
||||||
GRL: 'GL',
|
|
||||||
GRD: 'GD',
|
|
||||||
GLP: 'GP',
|
|
||||||
GUM: 'GU',
|
|
||||||
GTM: 'GT',
|
|
||||||
GGY: 'GG',
|
|
||||||
GIN: 'GN',
|
|
||||||
GNB: 'GW',
|
|
||||||
GUY: 'GY',
|
|
||||||
HTI: 'HT',
|
|
||||||
HMD: 'HM',
|
|
||||||
VAT: 'VA',
|
|
||||||
HND: 'HN',
|
|
||||||
HUN: 'HU',
|
|
||||||
ISL: 'IS',
|
|
||||||
IND: 'IN',
|
|
||||||
IDN: 'ID',
|
|
||||||
IRN: 'IR',
|
|
||||||
IRQ: 'IQ',
|
|
||||||
IRL: 'IE',
|
|
||||||
IMN: 'IM',
|
|
||||||
ISR: 'IL',
|
|
||||||
ITA: 'IT',
|
|
||||||
JAM: 'JM',
|
JAM: 'JM',
|
||||||
JPN: 'JP',
|
|
||||||
JEY: 'JE',
|
JEY: 'JE',
|
||||||
JOR: 'JO',
|
JOR: 'JO',
|
||||||
|
JPN: 'JP',
|
||||||
KAZ: 'KZ',
|
KAZ: 'KZ',
|
||||||
KEN: 'KE',
|
KEN: 'KE',
|
||||||
|
KGZ: 'KG',
|
||||||
KIR: 'KI',
|
KIR: 'KI',
|
||||||
PRK: 'KP',
|
KNA: 'KN',
|
||||||
KOR: 'KR',
|
KOR: 'KR',
|
||||||
KWT: 'KW',
|
KWT: 'KW',
|
||||||
KGZ: 'KG',
|
|
||||||
LAO: 'LA',
|
LAO: 'LA',
|
||||||
LVA: 'LV',
|
|
||||||
LBN: 'LB',
|
LBN: 'LB',
|
||||||
LSO: 'LS',
|
|
||||||
LBR: 'LR',
|
LBR: 'LR',
|
||||||
LBY: 'LY',
|
LBY: 'LY',
|
||||||
|
LCA: 'LC',
|
||||||
LIE: 'LI',
|
LIE: 'LI',
|
||||||
|
LKA: 'LK',
|
||||||
|
LSO: 'LS',
|
||||||
LTU: 'LT',
|
LTU: 'LT',
|
||||||
LUX: 'LU',
|
LUX: 'LU',
|
||||||
MKD: 'MK',
|
LVA: 'LV',
|
||||||
|
MAF: 'MF',
|
||||||
|
MAR: 'MA',
|
||||||
|
MCO: 'MC',
|
||||||
|
MDA: 'MD',
|
||||||
MDG: 'MG',
|
MDG: 'MG',
|
||||||
MWI: 'MW',
|
|
||||||
MYS: 'MY',
|
|
||||||
MDV: 'MV',
|
MDV: 'MV',
|
||||||
|
MEX: 'MX',
|
||||||
|
MHL: 'MH',
|
||||||
|
MKD: 'MK',
|
||||||
MLI: 'ML',
|
MLI: 'ML',
|
||||||
MLT: 'MT',
|
MLT: 'MT',
|
||||||
MHL: 'MH',
|
|
||||||
MTQ: 'MQ',
|
|
||||||
MRT: 'MR',
|
|
||||||
MUS: 'MU',
|
|
||||||
MYT: 'YT',
|
|
||||||
MEX: 'MX',
|
|
||||||
FSM: 'FM',
|
|
||||||
MDA: 'MD',
|
|
||||||
MCO: 'MC',
|
|
||||||
MNG: 'MN',
|
|
||||||
MNE: 'ME',
|
|
||||||
MSR: 'MS',
|
|
||||||
MAR: 'MA',
|
|
||||||
MOZ: 'MZ',
|
|
||||||
MMR: 'MM',
|
MMR: 'MM',
|
||||||
NAM: 'NA',
|
MNE: 'ME',
|
||||||
NRU: 'NR',
|
MNG: 'MN',
|
||||||
NPL: 'NP',
|
|
||||||
NLD: 'NL',
|
|
||||||
ANT: 'AN',
|
|
||||||
NCL: 'NC',
|
|
||||||
NZL: 'NZ',
|
|
||||||
NIC: 'NI',
|
|
||||||
NER: 'NE',
|
|
||||||
NGA: 'NG',
|
|
||||||
NIU: 'NU',
|
|
||||||
NFK: 'NF',
|
|
||||||
MNP: 'MP',
|
MNP: 'MP',
|
||||||
|
MOZ: 'MZ',
|
||||||
|
MRT: 'MR',
|
||||||
|
MSR: 'MS',
|
||||||
|
MTQ: 'MQ',
|
||||||
|
MUS: 'MU',
|
||||||
|
MWI: 'MW',
|
||||||
|
MYS: 'MY',
|
||||||
|
MYT: 'YT',
|
||||||
|
NAM: 'NA',
|
||||||
|
NCL: 'NC',
|
||||||
|
NER: 'NE',
|
||||||
|
NFK: 'NF',
|
||||||
|
NGA: 'NG',
|
||||||
|
NIC: 'NI',
|
||||||
|
NIU: 'NU',
|
||||||
|
NLD: 'NL',
|
||||||
NOR: 'NO',
|
NOR: 'NO',
|
||||||
|
NPL: 'NP',
|
||||||
|
NRU: 'NR',
|
||||||
|
NZL: 'NZ',
|
||||||
OMN: 'OM',
|
OMN: 'OM',
|
||||||
PAK: 'PK',
|
PAK: 'PK',
|
||||||
PLW: 'PW',
|
|
||||||
PSE: 'PS',
|
|
||||||
PAN: 'PA',
|
PAN: 'PA',
|
||||||
PNG: 'PG',
|
PCN: 'PN',
|
||||||
PRY: 'PY',
|
|
||||||
PER: 'PE',
|
PER: 'PE',
|
||||||
PHL: 'PH',
|
PHL: 'PH',
|
||||||
PCN: 'PN',
|
PLW: 'PW',
|
||||||
|
PNG: 'PG',
|
||||||
POL: 'PL',
|
POL: 'PL',
|
||||||
PRT: 'PT',
|
|
||||||
PRI: 'PR',
|
PRI: 'PR',
|
||||||
|
PRK: 'KP',
|
||||||
|
PRT: 'PT',
|
||||||
|
PRY: 'PY',
|
||||||
|
PSE: 'PS',
|
||||||
QAT: 'QA',
|
QAT: 'QA',
|
||||||
REU: 'RE',
|
REU: 'RE',
|
||||||
ROU: 'RO',
|
ROU: 'RO',
|
||||||
RUS: 'RU',
|
RUS: 'RU',
|
||||||
RWA: 'RW',
|
RWA: 'RW',
|
||||||
BLM: 'BL',
|
|
||||||
SHN: 'SH',
|
|
||||||
KNA: 'KN',
|
|
||||||
LCA: 'LC',
|
|
||||||
MAF: 'MF',
|
|
||||||
SPM: 'PM',
|
|
||||||
VCT: 'VC',
|
|
||||||
WSM: 'WS',
|
|
||||||
SMR: 'SM',
|
|
||||||
STP: 'ST',
|
|
||||||
SAU: 'SA',
|
SAU: 'SA',
|
||||||
|
SDN: 'SD',
|
||||||
SEN: 'SN',
|
SEN: 'SN',
|
||||||
SRB: 'RS',
|
|
||||||
SYC: 'SC',
|
|
||||||
SLE: 'SL',
|
|
||||||
SGP: 'SG',
|
SGP: 'SG',
|
||||||
|
SGS: 'GS',
|
||||||
|
SHN: 'SH',
|
||||||
|
SJM: 'SJ',
|
||||||
|
SLB: 'SB',
|
||||||
|
SLE: 'SL',
|
||||||
|
SMR: 'SM',
|
||||||
|
SOM: 'SO',
|
||||||
|
SPM: 'PM',
|
||||||
|
SRB: 'RS',
|
||||||
|
SSD: 'SS',
|
||||||
|
STP: 'ST',
|
||||||
|
SUR: 'SR',
|
||||||
SVK: 'SK',
|
SVK: 'SK',
|
||||||
SVN: 'SI',
|
SVN: 'SI',
|
||||||
SLB: 'SB',
|
|
||||||
SOM: 'SO',
|
|
||||||
ZAF: 'ZA',
|
|
||||||
SGS: 'GS',
|
|
||||||
SSD: 'SS',
|
|
||||||
ESP: 'ES',
|
|
||||||
LKA: 'LK',
|
|
||||||
SDN: 'SD',
|
|
||||||
SUR: 'SR',
|
|
||||||
SJM: 'SJ',
|
|
||||||
SWZ: 'SZ',
|
|
||||||
SWE: 'SE',
|
SWE: 'SE',
|
||||||
CHE: 'CH',
|
SWZ: 'SZ',
|
||||||
|
SYC: 'SC',
|
||||||
SYR: 'SY',
|
SYR: 'SY',
|
||||||
TWN: 'TW',
|
TCA: 'TC',
|
||||||
TJK: 'TJ',
|
|
||||||
TZA: 'TZ',
|
|
||||||
THA: 'TH',
|
|
||||||
TLS: 'TL',
|
|
||||||
TGO: 'TG',
|
TGO: 'TG',
|
||||||
|
THA: 'TH',
|
||||||
|
TJK: 'TJ',
|
||||||
TKL: 'TK',
|
TKL: 'TK',
|
||||||
|
TKM: 'TM',
|
||||||
|
TLS: 'TL',
|
||||||
TON: 'TO',
|
TON: 'TO',
|
||||||
TTO: 'TT',
|
TTO: 'TT',
|
||||||
TUN: 'TN',
|
TUN: 'TN',
|
||||||
TUR: 'TR',
|
TUR: 'TR',
|
||||||
TKM: 'TM',
|
|
||||||
TCA: 'TC',
|
|
||||||
TUV: 'TV',
|
TUV: 'TV',
|
||||||
|
TWN: 'TW',
|
||||||
|
TZA: 'TZ',
|
||||||
UGA: 'UG',
|
UGA: 'UG',
|
||||||
UKR: 'UA',
|
UKR: 'UA',
|
||||||
ARE: 'AE',
|
|
||||||
GBR: 'GB',
|
|
||||||
USA: 'US',
|
|
||||||
UMI: 'UM',
|
UMI: 'UM',
|
||||||
URY: 'UY',
|
URY: 'UY',
|
||||||
|
USA: 'US',
|
||||||
UZB: 'UZ',
|
UZB: 'UZ',
|
||||||
VUT: 'VU',
|
VCT: 'VC',
|
||||||
VEN: 'VE',
|
VEN: 'VE',
|
||||||
VNM: 'VN',
|
|
||||||
VIR: 'VI',
|
VIR: 'VI',
|
||||||
|
VNM: 'VN',
|
||||||
|
VUT: 'VU',
|
||||||
WLF: 'WF',
|
WLF: 'WF',
|
||||||
ESH: 'EH',
|
WSM: 'WS',
|
||||||
|
XKX: 'XK',
|
||||||
YEM: 'YE',
|
YEM: 'YE',
|
||||||
|
ZAF: 'ZA',
|
||||||
ZMB: 'ZM',
|
ZMB: 'ZM',
|
||||||
ZWE: 'ZW',
|
ZWE: 'ZW',
|
||||||
XKX: 'XK',
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export const CURRENCIES = [
|
export const CURRENCIES = [
|
||||||
|
|
|
||||||
|
|
@ -15,6 +15,27 @@ import { safeDecodeURIComponent } from '@/lib/url';
|
||||||
|
|
||||||
const MAXMIND = 'maxmind';
|
const MAXMIND = 'maxmind';
|
||||||
|
|
||||||
|
const PROVIDER_HEADERS = [
|
||||||
|
// Cloudflare headers
|
||||||
|
{
|
||||||
|
countryHeader: 'cf-ipcountry',
|
||||||
|
regionHeader: 'cf-region-code',
|
||||||
|
cityHeader: 'cf-ipcity',
|
||||||
|
},
|
||||||
|
// Vercel headers
|
||||||
|
{
|
||||||
|
countryHeader: 'x-vercel-ip-country',
|
||||||
|
regionHeader: 'x-vercel-ip-country-region',
|
||||||
|
cityHeader: 'x-vercel-ip-city',
|
||||||
|
},
|
||||||
|
// CloudFront headers
|
||||||
|
{
|
||||||
|
countryHeader: 'cloudfront-viewer-country',
|
||||||
|
regionHeader: 'cloudfront-viewer-country-region',
|
||||||
|
cityHeader: 'cloudfront-viewer-city',
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
export function getIpAddress(headers: Headers) {
|
export function getIpAddress(headers: Headers) {
|
||||||
const customHeader = process.env.CLIENT_IP_HEADER;
|
const customHeader = process.env.CLIENT_IP_HEADER;
|
||||||
|
|
||||||
|
|
@ -94,30 +115,19 @@ export async function getLocation(ip: string = '', headers: Headers, hasPayloadI
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!hasPayloadIP && !process.env.SKIP_LOCATION_HEADERS) {
|
if (!hasPayloadIP && !process.env.SKIP_LOCATION_HEADERS) {
|
||||||
// Cloudflare headers
|
for (const provider of PROVIDER_HEADERS) {
|
||||||
if (headers.get('cf-ipcountry')) {
|
const countryHeader = headers.get(provider.countryHeader);
|
||||||
const country = decodeHeader(headers.get('cf-ipcountry'));
|
if (countryHeader) {
|
||||||
const region = decodeHeader(headers.get('cf-region-code'));
|
const country = decodeHeader(countryHeader);
|
||||||
const city = decodeHeader(headers.get('cf-ipcity'));
|
const region = decodeHeader(headers.get(provider.regionHeader));
|
||||||
|
const city = decodeHeader(headers.get(provider.cityHeader));
|
||||||
|
|
||||||
return {
|
return {
|
||||||
country,
|
country,
|
||||||
region: getRegionCode(country, region),
|
region: getRegionCode(country, region),
|
||||||
city,
|
city,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
// Vercel headers
|
|
||||||
if (headers.get('x-vercel-ip-country')) {
|
|
||||||
const country = decodeHeader(headers.get('x-vercel-ip-country'));
|
|
||||||
const region = decodeHeader(headers.get('x-vercel-ip-country-region'));
|
|
||||||
const city = decodeHeader(headers.get('x-vercel-ip-city'));
|
|
||||||
|
|
||||||
return {
|
|
||||||
country,
|
|
||||||
region: getRegionCode(country, region),
|
|
||||||
city,
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -201,22 +201,23 @@ async function clickhouseQuery(
|
||||||
}[]
|
}[]
|
||||||
>(
|
>(
|
||||||
`
|
`
|
||||||
select
|
select
|
||||||
website_event.country as name,
|
website_event.country as name,
|
||||||
sum(website_revenue.revenue) as value
|
sum(website_revenue.revenue) as value
|
||||||
from website_revenue
|
from website_revenue
|
||||||
join website_event
|
join website_event
|
||||||
on website_event.website_id = website_revenue.website_id
|
on website_event.website_id = website_revenue.website_id
|
||||||
and website_event.session_id = website_revenue.session_id
|
and website_event.session_id = website_revenue.session_id
|
||||||
and website_event.event_id = website_revenue.event_id
|
and website_event.event_id = website_revenue.event_id
|
||||||
and website_event.website_id = {websiteId:UUID}
|
and website_event.website_id = {websiteId:UUID}
|
||||||
and website_event.created_at between {startDate:DateTime64} and {endDate:DateTime64}
|
and website_event.created_at between {startDate:DateTime64} and {endDate:DateTime64}
|
||||||
${cohortQuery}
|
${cohortQuery}
|
||||||
where website_revenue.website_id = {websiteId:UUID}
|
where website_revenue.website_id = {websiteId:UUID}
|
||||||
and website_revenue.created_at between {startDate:DateTime64} and {endDate:DateTime64}
|
and website_revenue.created_at between {startDate:DateTime64} and {endDate:DateTime64}
|
||||||
and website_revenue.currency = {currency:String}
|
and website_revenue.currency = {currency:String}
|
||||||
${filterQuery}
|
${filterQuery}
|
||||||
group by website_event.country
|
group by website_event.country
|
||||||
|
order by value desc
|
||||||
`,
|
`,
|
||||||
queryParams,
|
queryParams,
|
||||||
);
|
);
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue