diff --git a/.github/ISSUE_TEMPLATE/1.bug_report.yml b/.github/ISSUE_TEMPLATE/1.bug_report.yml new file mode 100644 index 00000000..db8be210 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/1.bug_report.yml @@ -0,0 +1,32 @@ +name: "🐛 Bug Report" +description: Create a bug report for Umami. +body: + - type: textarea + attributes: + label: Describe the Bug + description: A clear and concise description of what the bug is. + validations: + required: true + - type: dropdown + attributes: + label: Database + description: What database are you using? + options: + - PostgreSQL + - MySQL + - Umami Cloud + validations: + required: true + - type: textarea + attributes: + label: Relevant log output + description: Please copy and paste any relevant log output. This will be automatically formatted into code, so no need for backticks. + render: shell + - type: input + attributes: + label: Which browser are you using? (if relevant) + description: 'For example: Chrome, Edge, Firefox, etc' + - type: input + attributes: + label: How are you deploying your application? (if relevant) + description: 'For example: Vercel, Railway, Docker, etc' \ No newline at end of file diff --git a/.github/ISSUE_TEMPLATE/2.feature_request.yml b/.github/ISSUE_TEMPLATE/2.feature_request.yml new file mode 100644 index 00000000..3034767b --- /dev/null +++ b/.github/ISSUE_TEMPLATE/2.feature_request.yml @@ -0,0 +1,10 @@ +name: "✨ Feature Request" +description: Create a feature or enhancement request for Umami. +labels: ['enhancement'] +body: + - type: textarea + attributes: + label: Describe the feature or enhancement + description: A clear and concise description of what the feature or enhancement is. + validations: + required: true \ No newline at end of file diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml new file mode 100644 index 00000000..92132929 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -0,0 +1,6 @@ + +blank_issues_enabled: false +contact_links: + - name: "🤔 Ask a question" + url: https://github.com/umami-software/umami/discussions + about: Ask questions and discuss with other community members. \ No newline at end of file diff --git a/components/metrics/MetricsTable.js b/components/metrics/MetricsTable.js index 3ad7f434..3bb313cd 100644 --- a/components/metrics/MetricsTable.js +++ b/components/metrics/MetricsTable.js @@ -73,7 +73,10 @@ export function MetricsTable({ const filteredData = useMemo(() => { if (data) { - let items = percentFilter(dataFilter ? dataFilter(data, filterOptions) : data); + const dataWithoutNullValues = data.filter(val => val.x !== null); + let items = percentFilter( + dataFilter ? dataFilter(dataWithoutNullValues, filterOptions) : dataWithoutNullValues, + ); if (limit) { items = items.filter((e, i) => i < limit); } diff --git a/db/clickhouse/schema.sql b/db/clickhouse/schema.sql index 77176413..8f48b434 100644 --- a/db/clickhouse/schema.sql +++ b/db/clickhouse/schema.sql @@ -58,7 +58,10 @@ CREATE TABLE umami.website_event_queue ( --event event_type UInt32, event_name String, - created_at DateTime('UTC') + created_at DateTime('UTC'), + --virtual columns + _error String, + _raw_message String ) ENGINE = Kafka SETTINGS kafka_broker_list = 'domain:9092,domain:9093,domain:9094', -- input broker list @@ -66,7 +69,7 @@ SETTINGS kafka_broker_list = 'domain:9092,domain:9093,domain:9094', -- input bro kafka_group_name = 'event_consumer_group', kafka_format = 'JSONEachRow', kafka_max_block_size = 1048576, - kafka_skip_broken_messages = 100; + kafka_handle_error_mode = 'stream' CREATE MATERIALIZED VIEW umami.website_event_queue_mv TO umami.website_event AS SELECT website_id, @@ -93,6 +96,19 @@ SELECT website_id, created_at FROM umami.website_event_queue; +CREATE MATERIALIZED VIEW umami.website_event_errors_mv +( + error String, + raw String +) +ENGINE = MergeTree +ORDER BY (error, raw) +SETTINGS index_granularity = 8192 AS +SELECT _error AS error, + _raw_message AS raw +FROM umami.website_event_queue +WHERE length(_error) > 0 + CREATE TABLE umami.event_data ( website_id UUID, @@ -122,7 +138,10 @@ CREATE TABLE umami.event_data_queue ( event_numeric_value Nullable(Decimal64(4)), --922337203685477.5625 event_date_value Nullable(DateTime('UTC')), event_data_type UInt32, - created_at DateTime('UTC') + created_at DateTime('UTC'), + --virtual columns + _error String, + _raw_message String ) ENGINE = Kafka SETTINGS kafka_broker_list = 'domain:9092,domain:9093,domain:9094', -- input broker list @@ -130,7 +149,7 @@ SETTINGS kafka_broker_list = 'domain:9092,domain:9093,domain:9094', -- input bro kafka_group_name = 'event_data_consumer_group', kafka_format = 'JSONEachRow', kafka_max_block_size = 1048576, - kafka_skip_broken_messages = 100; + kafka_handle_error_mode = 'stream' CREATE MATERIALIZED VIEW umami.event_data_queue_mv TO umami.event_data AS SELECT website_id, @@ -144,4 +163,17 @@ SELECT website_id, event_date_value, event_data_type, created_at -FROM umami.event_data_queue; \ No newline at end of file +FROM umami.event_data_queue; + +CREATE MATERIALIZED VIEW umami.event_data_errors_mv +( + error String, + raw String +) +ENGINE = MergeTree +ORDER BY (error, raw) +SETTINGS index_granularity = 8192 AS +SELECT _error AS error, + _raw_message AS raw +FROM umami.event_data_queue +WHERE length(_error) > 0 \ No newline at end of file diff --git a/docker-compose.yml b/docker-compose.yml index bd63c68b..b8da9373 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -10,7 +10,8 @@ services: DATABASE_TYPE: postgresql APP_SECRET: replace-me-with-a-random-string depends_on: - - db + db: + condition: service_healthy restart: always db: image: postgres:15-alpine @@ -19,8 +20,12 @@ services: POSTGRES_USER: umami POSTGRES_PASSWORD: umami volumes: - - ./sql/schema.postgresql.sql:/docker-entrypoint-initdb.d/schema.postgresql.sql:ro - umami-db-data:/var/lib/postgresql/data restart: always + healthcheck: + test: ["CMD-SHELL", "pg_isready -U $${POSTGRES_USER} -d $${POSTGRES_DB}"] + interval: 5s + timeout: 5s + retries: 5 volumes: umami-db-data: diff --git a/lang-ignore.json b/lang-ignore.json index d4707cda..4a0f9d41 100644 --- a/lang-ignore.json +++ b/lang-ignore.json @@ -1,16 +1,32 @@ { "cs-CZ": ["label.reset", "metrics.device.tablet"], - "de-DE": [ - "label.administrator", - "label.name", + "de-CH": [ + "label.admin", + "label.analytics", + "label.desktop", + "label.details", "label.domain", - "label.theme", - "metrics.device.desktop", - "metrics.device.laptop", - "metrics.device.tablet", - "metrics.referrers", - "metrics.utm", - "metrics.utm_medium" + "label.laptop", + "label.tablet", + "label.name", + "label.sessions", + "label.team", + "label.team-id", + "label.teams" + ], + "de-DE": [ + "label.admin", + "label.analytics", + "label.desktop", + "label.details", + "label.domain", + "label.laptop", + "label.tablet", + "label.name", + "label.sessions", + "label.team", + "label.team-id", + "label.teams" ], "en-GB": "*", "fr-FR": ["metrics.actions", "metrics.pages"], @@ -22,12 +38,15 @@ ], "nb-NO": ["label.administrator", "label.dashboard"], "nl-NL": [ - "label.administrator", - "label.websites", - "metrics.browsers", - "metrics.device.desktop", - "metrics.device.laptop", - "metrics.device.tablet" + "label.analytics", + "label.browsers", + "label.laptop", + "label.tablet", + "label.team", + "label.team-id", + "label.teams", + "label.website-id", + "label.websites" ], "it-IT": [ "label.password", @@ -37,9 +56,5 @@ "metrics.device.tablet", "metrics.filter.raw" ], - "pt-PT": [ - "label.websites", - "metrics.device.desktop", - "metrics.device.tablet" - ] + "pt-PT": ["label.websites", "metrics.device.desktop", "metrics.device.tablet"] } diff --git a/lang/de-CH.json b/lang/de-CH.json index 03980e5c..f8602bc3 100644 --- a/lang/de-CH.json +++ b/lang/de-CH.json @@ -1,7 +1,7 @@ { - "label.access-code": "Access code", + "label.access-code": "Zuegangscode", "label.actions": "Aktione", - "label.activity-log": "Activity log", + "label.activity-log": "Aktivitätsverlauf", "label.add-website": "Websiite hinzuefüege", "label.admin": "Administrator", "label.all": "Alli", @@ -13,24 +13,24 @@ "label.browsers": "Browser", "label.cancel": "Abbreche", "label.change-password": "Passwort ändere", - "label.cities": "Cities", - "label.clear-all": "Clear all", - "label.confirm": "Confirm", + "label.cities": "Städt", + "label.clear-all": "Alles lösche", + "label.confirm": "Bestätige", "label.confirm-password": "Passwort widerhole", - "label.continue": "Continue", + "label.continue": "Wiiter", "label.countries": "Länder", - "label.create-team": "Create team", - "label.create-user": "Create user", - "label.created": "Created", + "label.create-team": "Team erstelle", + "label.create-user": "Benutzer erstelle", + "label.created": "Erstellt", "label.current-password": "Jetzigs Passwort", "label.custom-range": "Benutzerdefinierte Bereich", "label.dashboard": "Übersicht", - "label.data": "Data", + "label.data": "Datä", "label.date-range": "Datumsbereich", "label.default-date-range": "Vorigstellte Datumsbereich", "label.delete": "Lösche", - "label.delete-team": "Delete team", - "label.delete-user": "Delete user", + "label.delete-team": "Team lösche", + "label.delete-user": "Benutzer lösche", "label.delete-website": "Websiite lösche", "label.desktop": "Desktop", "label.details": "Details", @@ -43,104 +43,104 @@ "label.events": "Ereigniss", "label.filter-combined": "Kombiniert", "label.filter-raw": "Rohdate", - "label.join": "Join", - "label.join-team": "Join team", + "label.join": "Biträte", + "label.join-team": "Team biträte", "label.language": "Sprach", "label.languages": "Sprache", "label.laptop": "Laptop", "label.last-days": "Letzti {x} Täg", "label.last-hours": "Letzti {x} Stunde", - "label.leave": "Leave", - "label.leave-team": "Leave team", - "label.login": "Login", + "label.leave": "Verlah", + "label.leave-team": "Team verlah", + "label.login": "Aamelde", "label.logout": "Abmelde", - "label.members": "Members", + "label.members": "Mitglieder", "label.mobile": "Handy", "label.more": "Meh", "label.name": "Name", "label.new-password": "Neus Passwort", "label.none": "Keis", - "label.operating-systems": "Betriebssystem", + "label.operating-systems": "Betriibssystem", "label.owner": "Bsitzer", "label.page-views": "Siitenufrüef", "label.pages": "Siite", "label.password": "Passwort", "label.powered-by": "Betribe dur {name}", "label.profile": "Profil", - "label.queries": "Queries", + "label.queries": "Abfrage", "label.query-parameters": "Abfragparameter", "label.realtime": "Echtzit", "label.referrers": "Referrer", "label.refresh": "Aktualisiere", - "label.regenerate": "Regenerate", - "label.regions": "Regions", - "label.remove": "Remove", + "label.regenerate": "Erneuere", + "label.regions": "Regionä", + "label.remove": "Entferne", "label.required": "Erforderlich", "label.reset": "Zruggsetze", "label.reset-website": "Statistik zruggsetze", - "label.role": "Role", + "label.role": "Rollä", "label.save": "Speichere", "label.screens": "Bildschirmuflösige", - "label.select-website": "Select website", + "label.select-website": "Websiite uuswähle", "label.sessions": "Sessions", "label.settings": "Istellige", "label.share-url": "Freigab-URL", "label.single-day": "Ein Tag", "label.tablet": "Tablet", "label.team": "Team", - "label.team-guest": "Team guest", + "label.team-guest": "Team Gast", "label.team-id": "Team ID", - "label.team-member": "Team member", - "label.team-owner": "Team owner", + "label.team-member": "Team Mitglied", + "label.team-owner": "Team Bsitzer", "label.teams": "Teams", "label.theme": "Thema", "label.this-month": "De Monet", "label.this-week": "Die Wuche", "label.this-year": "Das Jahr", - "label.timezone": "Zitzone", - "label.title": "Title", + "label.timezone": "Ziitzone", + "label.title": "Titel", "label.today": "Hüt", "label.toggle-charts": "Schaubilder umschalte", "label.tracking-code": "Tracking Code", "label.unique-visitors": "Eidütigi Bsuecher", "label.unknown": "Unbekannt", - "label.user": "User", + "label.user": "Benutzer", "label.username": "Benutzername", - "label.users": "Users", - "label.view": "View", + "label.users": "Benutzer", + "label.view": "Azeige", "label.view-details": "Details azeige", "label.views": "Ufrüef", "label.visitors": "Bsuecher", - "label.website-id": "Website ID", + "label.website-id": "Websiite ID", "label.websites": "Websiite", "label.yesterday": "Gester", "message.active-users": "{x} {x, plural, one {aktive Bsuecher} other {aktivi Bsuecher}}", "message.confirm-delete": "Sind Sie sich sicher, {target} zlösche?", - "message.confirm-leave": "Are you sure you want to leave {target}?", + "message.confirm-leave": "Sind Sie sich sicher, {target} zverlah?", "message.confirm-reset": "Sind Sie sicher, dass Sie dStatistike vo {target} zruggsetze wend?", "message.delete-website": "Websiite lösche", "message.delete-website-warning": "Alli dezueghörige Date werdet ebefalls glöscht.", "message.error": "Es isch en Fehler uftrete.", - "message.event-log": "{event} on {url}", + "message.event-log": "{event} uf {url}", "message.go-to-settings": "Zu de Istellige", "message.incorrect-username-password": "Falschs Passwort oder Benutzername.", "message.invalid-domain": "Ungültigi Domain", - "message.min-password-length": "Minimum length of {n} characters", + "message.min-password-length": "Miminamli längi vo {n} Zeiche", "message.no-data-available": "Kei Date vorhande.", "message.no-match-password": "Passwörter stimmed ned überi", - "message.no-teams": "You have not created any teams.", - "message.no-users": "There are no users.", + "message.no-teams": "Bisher sind no kei Teams erstellt worde.", + "message.no-users": "Da gits kei Benutzer", "message.page-not-found": "Siite ned gfunde.", "message.reset-website": "Statistik zruggsetze", "message.reset-website-warning": "Alli Date für die Websiite werdet glöscht, nur de Tracking Code blibt bestah.", "message.saved": "Erfolgrich gspeichert.", - "message.share-url": "Das isch die öffentlichi URL zum Teile für {target}.", - "message.team-already-member": "You are already a member of the team.", - "message.team-not-found": "Team not found.", + "message.share-url": "Ihri Websiitestatistik isch under de folgende URL öffentlich zuegänglich:", + "message.team-already-member": "Sie sind bereits es Mitglied vo dem Team.", + "message.team-not-found": "Team nöd gfunde.", "message.tracking-code": "Tracking Code", - "message.user-deleted": "User deleted.", + "message.user-deleted": "Benutzer glöscht.", "message.visitor-log": "Bsuecher us {country} benutzt {browser} uf {os} {device}", - "messages.no-team-websites": "This team does not have any websites.", + "messages.no-team-websites": "Dem Team sind kei Websiite zuegordnet.", "messages.no-websites-configured": "Es isch kei Websiite vorhande.", - "messages.team-websites-info": "Websites can be viewed by anyone on the team." + "messages.team-websites-info": "Websiite chönd vo jedem im Team agluegt werde" } diff --git a/lang/de-DE.json b/lang/de-DE.json index 0190d13c..b3611d5b 100644 --- a/lang/de-DE.json +++ b/lang/de-DE.json @@ -19,8 +19,8 @@ "label.confirm-password": "Passwort wiederholen", "label.continue": "Weiter", "label.countries": "Länder", - "label.create-team": "Erstelle Team", - "label.create-user": "Erstelle Nutzer", + "label.create-team": "Team erstellen", + "label.create-user": "Benutzer erstellen", "label.created": "Erstellt", "label.current-password": "Derzeitiges Passwort", "label.custom-range": "Benutzerdefinierter Bereich", @@ -29,8 +29,8 @@ "label.date-range": "Datumsbereich", "label.default-date-range": "Voreingestellter Datumsbereich", "label.delete": "Löschen", - "label.delete-team": "Lösche Team", - "label.delete-user": "Lösche Nutzer", + "label.delete-team": "Team löschen", + "label.delete-user": "Benutzer löschen", "label.delete-website": "Webseite löschen", "label.desktop": "Desktop", "label.details": "Details", @@ -48,8 +48,8 @@ "label.language": "Sprache", "label.languages": "Sprachen", "label.laptop": "Laptop", - "label.last-days": "Letzten {x} Tage", - "label.last-hours": "Letzten {x} Stunden", + "label.last-days": "Letzte {x} Tage", + "label.last-hours": "Letzte {x} Stunden", "label.leave": "Verlassen", "label.leave-team": "Team verlassen", "label.login": "Anmelden", @@ -73,7 +73,7 @@ "label.referrers": "Referrer", "label.refresh": "Aktualisieren", "label.regenerate": "Erneuern", - "label.regions": "Regions", + "label.regions": "Regionen", "label.remove": "Entfernen", "label.required": "Erforderlich", "label.reset": "Zurücksetzen", @@ -101,17 +101,17 @@ "label.title": "Titel", "label.today": "Heute", "label.toggle-charts": "Schaubilder umschalten", - "label.tracking-code": "Tracking Kennung", + "label.tracking-code": "Tracking Code", "label.unique-visitors": "Eindeutige Besucher", "label.unknown": "Unbekannt", - "label.user": "User", + "label.user": "Benutzer", "label.username": "Benutzername", - "label.users": "Users", - "label.view": "View", + "label.users": "Benutzer", + "label.view": "Anzeigen", "label.view-details": "Details anzeigen", "label.views": "Aufrufe", "label.visitors": "Besucher", - "label.website-id": "Website ID", + "label.website-id": "Webseite ID", "label.websites": "Webseiten", "label.yesterday": "Gestern", "message.active-users": "{x} {x, plural, one {aktiver Besucher} other {aktive Besucher}}", @@ -121,7 +121,7 @@ "message.delete-website": "Webseite löschen", "message.delete-website-warning": "Alle zugehörigen Daten werden ebenfalls gelöscht.", "message.error": "Es ist ein Fehler aufgetreten.", - "message.event-log": "{event} on {url}", + "message.event-log": "{event} auf {url}", "message.go-to-settings": "Zu den Einstellungen", "message.incorrect-username-password": "Falsches Passwort oder Benutzername.", "message.invalid-domain": "Ungültige Domain", @@ -129,16 +129,16 @@ "message.no-data-available": "Keine Daten vorhanden.", "message.no-match-password": "Passwörter stimmen nicht überein", "message.no-teams": "Bisher wurden keine Teams erstellt.", - "message.no-users": "Hier gibt es keine Nutzer.", + "message.no-users": "Hier gibt es keine Benutzer.", "message.page-not-found": "Seite nicht gefunden.", "message.reset-website": "Statistik zurücksetzen", "message.reset-website-warning": "Alle Daten für diese Webseite werden gelöscht, jedoch bleibt der Tracking Code bestehen.", "message.saved": "Erfolgreich gespeichert.", - "message.share-url": "Dies ist die öffentliche URL zum Teilen für {target}.", + "message.share-url": "Ihre Webseitenstatistik ist unter der folgenden URL öffentlich zugänglich:", "message.team-already-member": "Sie sind bereits Mitglied des Teams.", "message.team-not-found": "Team nicht gefunden.", - "message.tracking-code": "Tracking Kennung", - "message.user-deleted": "Nutzer gelöscht.", + "message.tracking-code": "Tracking Code", + "message.user-deleted": "Benutzer gelöscht.", "message.visitor-log": "Besucher aus {country} benutzt {browser} auf {os} {device}", "messages.no-team-websites": "Diesem Team sind keine Websites zugeordnet.", "messages.no-websites-configured": "Es ist keine Webseite vorhanden.", diff --git a/lang/mn-MN.json b/lang/mn-MN.json index 9e3b4499..b15076ad 100644 --- a/lang/mn-MN.json +++ b/lang/mn-MN.json @@ -1,7 +1,7 @@ { - "label.access-code": "Access code", + "label.access-code": "Хандалтын код", "label.actions": "Үйлдлүүд", - "label.activity-log": "Activity log", + "label.activity-log": "Үйл ажиллагааны бүртгэл", "label.add-website": "Веб нэмэх", "label.admin": "Админ", "label.all": "Бүх", @@ -13,27 +13,27 @@ "label.browsers": "Хөтөч", "label.cancel": "Цуцлах", "label.change-password": "Нууц үг солих", - "label.cities": "Cities", - "label.clear-all": "Clear all", - "label.confirm": "Confirm", + "label.cities": "Хотууд", + "label.clear-all": "Бүгдийг арилгах", + "label.confirm": "Батлах", "label.confirm-password": "Шинэ нууц үгээ давтах", - "label.continue": "Continue", + "label.continue": "Үргэлжлүүлэх", "label.countries": "Улс", - "label.create-team": "Create team", - "label.create-user": "Create user", - "label.created": "Created", + "label.create-team": "Баг үүсгэх", + "label.create-user": "Хэрэглэгч үүсгэх", + "label.created": "Үүсгэсэн", "label.current-password": "Ашиглаж буй нууц үг", "label.custom-range": "Дурын хугацаа", "label.dashboard": "Хянах самбар", - "label.data": "Data", - "label.date-range": "Хугацааны мужид", + "label.data": "Өгөгдөл", + "label.date-range": "Хугацааны муж", "label.default-date-range": "Өгөгдмөл хугацааны муж", "label.delete": "Устгах", - "label.delete-team": "Delete team", - "label.delete-user": "Delete user", + "label.delete-team": "Баг устгах", + "label.delete-user": "Хэрэглэгч устгах", "label.delete-website": "Веб устгах", "label.desktop": "Суурин компьютер", - "label.details": "Details", + "label.details": "Мэдээлэл", "label.devices": "Төхөөрөмж", "label.dismiss": "Үл хэргэсэх", "label.domain": "Домэйн", @@ -43,18 +43,18 @@ "label.events": "Үйлдэл", "label.filter-combined": "Нэгтгэсэн", "label.filter-raw": "Түүхий", - "label.join": "Join", - "label.join-team": "Join team", + "label.join": "Нэгдэх", + "label.join-team": "Багт нэгдэх", "label.language": "Хэл", "label.languages": "Хэл", "label.laptop": "Зөөврийн компьютер", "label.last-days": "Сүүлийн {x} хоног", "label.last-hours": "Сүүлийн {x} цаг", - "label.leave": "Leave", - "label.leave-team": "Leave team", + "label.leave": "Гарах", + "label.leave-team": "Багаас гарах", "label.login": "Нэвтрэх", "label.logout": "Гарах", - "label.members": "Members", + "label.members": "Гишүүд", "label.mobile": "Утас", "label.more": "Цааш", "label.name": "Нэр", @@ -67,80 +67,80 @@ "label.password": "Нууц үг", "label.powered-by": "{name} дээр суурилсан", "label.profile": "Бүртгэл", - "label.queries": "Queries", + "label.queries": "Query-нүүд", "label.query-parameters": "Query параметр", "label.realtime": "Яг одоо", "label.referrers": "Чиглүүлэгч", "label.refresh": "Сэргээх", - "label.regenerate": "Regenerate", - "label.regions": "Regions", - "label.remove": "Remove", + "label.regenerate": "Дахин үүсгэх", + "label.regions": "Бүсүүд", + "label.remove": "Устгах", "label.required": "Шаардлагатай", - "label.reset": "Хуучин хэвд нь оруулах", + "label.reset": "Дахин эхлүүлэх", "label.reset-website": "Тоон үзүүлэлтийг дахин эхлүүлэх", - "label.role": "Role", + "label.role": "Эрх", "label.save": "Хадгалах", "label.screens": "Дэлгэц", - "label.select-website": "Select website", + "label.select-website": "Веб сонгох", "label.sessions": "Sessions", "label.settings": "Тохиргоо", "label.share-url": "Хуваалцах холбоос", "label.single-day": "Нэг өдөр", "label.tablet": "Таблет", - "label.team": "Team", - "label.team-guest": "Team guest", - "label.team-id": "Team ID", - "label.team-member": "Team member", - "label.team-owner": "Team owner", - "label.teams": "Teams", + "label.team": "Баг", + "label.team-guest": "Багийн зочин", + "label.team-id": "Багийн ID", + "label.team-member": "Багийн гишүүн", + "label.team-owner": "Багийн эзэмшигч", + "label.teams": "Багууд", "label.theme": "Загвар", "label.this-month": "Энэ сар", "label.this-week": "Энэ долоо хоног", "label.this-year": "Энэ жил", "label.timezone": "Цагийн бүс", - "label.title": "Title", + "label.title": "Гарчиг", "label.today": "Өнөөдөр", "label.toggle-charts": "Графикийг харуулах/нуух", "label.tracking-code": "Мөрдөх код", "label.unique-visitors": "Зочин", "label.unknown": "Тодорхойгүй", - "label.user": "User", + "label.user": "Хэрэглэгч", "label.username": "Хэрэглэгчийн нэр", - "label.users": "Users", - "label.view": "View", + "label.users": "Хэрэглэгчид", + "label.view": "Харах", "label.view-details": "Дэлгэрүүлж харах", "label.views": "Үзсэн", "label.visitors": "Зочин", - "label.website-id": "Website ID", + "label.website-id": "Вебийн ID", "label.websites": "Вебүүд", "label.yesterday": "Өчигдөр", "message.active-users": "одоо {x} {x, plural, one {зочин} other {зочин}} байна", "message.confirm-delete": "Та {target}-г устгахдаа итгэлтэй байна уу?", - "message.confirm-leave": "Are you sure you want to leave {target}?", + "message.confirm-leave": "Та {target}-с гарахдаа итгэлтэй байна уу?", "message.confirm-reset": "Та {target}-н тоон үзүүлэлтүүдийг устгахдаа итгэлтэй байна уу?", - "message.delete-website": "Веб устгах", - "message.delete-website-warning": "Үүнтэй холбоотой бүх өгөгдөл устах болно.", + "message.delete-website": "Веб устгахын тулд доорх хэсэгт {confirmation} гэж бичиж, баталгаажуулна уу.", + "message.delete-website-warning": "Энэ вебтэй холбоотой бүх өгөгдөл устах болно.", "message.error": "Ямар нэг зүйл буруу боллоо.", - "message.event-log": "{event} on {url}", + "message.event-log": "{url}-д {event}", "message.go-to-settings": "Тохиргоо руу очих", "message.incorrect-username-password": "Буруу хэрэглэгчийн нэр/нууц үг.", "message.invalid-domain": "Буруу домэйн", - "message.min-password-length": "Minimum length of {n} characters", + "message.min-password-length": "Хамгийн багадаа {n} тэмдэгт", "message.no-data-available": "Өгөгдөл алга.", - "message.no-match-password": "Нууц үг тохирохгүй байна", - "message.no-teams": "You have not created any teams.", - "message.no-users": "There are no users.", + "message.no-match-password": "Нууц үг тохирохгүй байна.", + "message.no-teams": "Та ямар ч баг үүсгээгүй байна.", + "message.no-users": "Хэрэглэгч байхгүй байна.", "message.page-not-found": "Хуудас олдсонгүй.", - "message.reset-website": "Тоон үзүүлэлтийг дахин эхлүүлэх", + "message.reset-website": "Тоон үзүүлэлийг дахин эхлүүлэхийн тулд доорх хэсэгт {confirmation} гэж бичиж, баталгаажуулна уу.", "message.reset-website-warning": "Энэ вебийн бүх тоон үзүүлэлтүүдийг устгах болно. Гэхдээ мөрдөх код хэвэндээ үлдэнэ.", - "message.saved": "Амжилттай хадгаллаа.", - "message.share-url": "{target}-г нийтэд хуваалцах холбоос.", - "message.team-already-member": "You are already a member of the team.", - "message.team-not-found": "Team not found.", - "message.tracking-code": "Мөрдөх код", - "message.user-deleted": "User deleted.", + "message.saved": "Хадгалсан.", + "message.share-url": "Таны вебийн тоон үзүүлэлтүүд доорх URL дээр нийтэд харагдах болно:", + "message.team-already-member": "Та аль хэдийн энэ багийн гишүүн болсон байна.", + "message.team-not-found": "Баг олдсонгүй.", + "message.tracking-code": "Энэ вебийн хандалтуудыг мөрдөхийн тулд доорх кодыг HTML-нхээ ... хэсэгт байрлуулна уу.", + "message.user-deleted": "Хэрэглэгч устсан.", "message.visitor-log": "{country} улсаас {os} {device} дээр {browser} хөтөч ашиглан орсон", - "messages.no-team-websites": "This team does not have any websites.", + "messages.no-team-websites": "Энэ багт ямар ч веб алга.", "messages.no-websites-configured": "Та ямар нэгэн веб тохируулаагүй байна.", - "messages.team-websites-info": "Websites can be viewed by anyone on the team." + "messages.team-websites-info": "Вебийг багийн бүх гишүүд үзэж болно." } diff --git a/lang/nl-NL.json b/lang/nl-NL.json index bac675f9..b86ff423 100644 --- a/lang/nl-NL.json +++ b/lang/nl-NL.json @@ -1,9 +1,9 @@ { - "label.access-code": "Access code", + "label.access-code": "Toegangscode", "label.actions": "Acties", - "label.activity-log": "Activity log", - "label.add-website": "Website toevoegen", - "label.admin": "Administrator", + "label.activity-log": "Activiteiten logboek", + "label.add-website": "Website koppelen", + "label.admin": "Beheerder", "label.all": "Alles", "label.all-time": "Onbeperkt", "label.analytics": "Analytics", @@ -13,48 +13,48 @@ "label.browsers": "Browsers", "label.cancel": "Annuleren", "label.change-password": "Wachtwoord wijzigen", - "label.cities": "Cities", - "label.clear-all": "Clear all", - "label.confirm": "Confirm", + "label.cities": "Steden", + "label.clear-all": "Filters wissen", + "label.confirm": "Bevestigen", "label.confirm-password": "Wachtwoord bevestigen", - "label.continue": "Continue", + "label.continue": "Doorgaan", "label.countries": "Landen", - "label.create-team": "Create team", - "label.create-user": "Create user", - "label.created": "Created", + "label.create-team": "Team aanmaken", + "label.create-user": "Gebruiker maken", + "label.created": "Gemaakt", "label.current-password": "Huidig wachtwoord", "label.custom-range": "Aangepast bereik", "label.dashboard": "Overzicht", - "label.data": "Data", + "label.data": "Gegevens", "label.date-range": "Datumbereik", "label.default-date-range": "Standaard bereik", "label.delete": "Verwijderen", - "label.delete-team": "Delete team", - "label.delete-user": "Delete user", + "label.delete-team": "Team verwijderen", + "label.delete-user": "Verwijder gebruiker", "label.delete-website": "Website verwijderen", - "label.desktop": "Desktop", - "label.details": "Details", + "label.desktop": "Computer", + "label.details": "Informatie", "label.devices": "Apparaten", "label.dismiss": "Negeren", "label.domain": "Domein", "label.edit": "Bewerken", - "label.edit-dashboard": "Edit dashboard", + "label.edit-dashboard": "Dashboard aanpassen", "label.enable-share-url": "Sta delen via openbare URL toe", "label.events": "Gebeurtenissen", "label.filter-combined": "Gecombineerd", "label.filter-raw": "Ruw", - "label.join": "Join", - "label.join-team": "Join team", + "label.join": "Lid worden", + "label.join-team": "Word lid van een team", "label.language": "Taal", - "label.languages": "Languages", + "label.languages": "Talen", "label.laptop": "Laptop", "label.last-days": "Laatste {x} dagen", "label.last-hours": "Laatste {x} uur", - "label.leave": "Leave", - "label.leave-team": "Leave team", + "label.leave": "Verlaten", + "label.leave-team": "Verlaat team", "label.login": "Inloggen", "label.logout": "Uitloggen", - "label.members": "Members", + "label.members": "Gebruikers", "label.mobile": "Mobiel", "label.more": "Toon meer", "label.name": "Naam", @@ -67,80 +67,80 @@ "label.password": "Wachtwoord", "label.powered-by": "mogelijk gemaakt door {name}", "label.profile": "Profiel", - "label.queries": "Queries", - "label.query-parameters": "Query parameters", + "label.queries": "Parameters", + "label.query-parameters": "URL-parameters", "label.realtime": "Actueel", "label.referrers": "Verwijzers", "label.refresh": "Vernieuwen", - "label.regenerate": "Regenerate", - "label.regions": "Regions", - "label.remove": "Remove", + "label.regenerate": "Opnieuw genereren", + "label.regions": "Regio's", + "label.remove": "Verwijderen", "label.required": "Verplicht", - "label.reset": "Resetten", + "label.reset": "Opnieuw instellen", "label.reset-website": "Statistieken opnieuw instellen", - "label.role": "Role", + "label.role": "Gebruikersrol", "label.save": "Opslaan", "label.screens": "Schermen", - "label.select-website": "Select website", - "label.sessions": "Sessions", + "label.select-website": "Website selecteren", + "label.sessions": "Sessies", "label.settings": "Instellingen", "label.share-url": "URL delen", "label.single-day": "Enkele dag", "label.tablet": "Tablet", "label.team": "Team", - "label.team-guest": "Team guest", + "label.team-guest": "Team gast", "label.team-id": "Team ID", - "label.team-member": "Team member", - "label.team-owner": "Team owner", + "label.team-member": "Teamlid", + "label.team-owner": "Teameigenaar", "label.teams": "Teams", "label.theme": "Thema", "label.this-month": "Deze maand", "label.this-week": "Deze week", "label.this-year": "Dit jaar", "label.timezone": "Tijdzone", - "label.title": "Title", + "label.title": "Titel", "label.today": "Vandaag", "label.toggle-charts": "Grafieken tonen/verbergen", "label.tracking-code": "Volgcode", "label.unique-visitors": "Unieke bezoekers", "label.unknown": "Onbekend", - "label.user": "User", + "label.user": "Gebruiker", "label.username": "Gebruikersnaam", - "label.users": "Users", - "label.view": "View", + "label.users": "Gebruikers", + "label.view": "Weergave", "label.view-details": "Meer details", "label.views": "Weergaven", "label.visitors": "Bezoekers", "label.website-id": "Website ID", "label.websites": "Websites", - "label.yesterday": "Yesterday", + "label.yesterday": "Gisteren", "message.active-users": "{x} actieve {x, plural, one {bezoeker} other {bezoekers}}", "message.confirm-delete": "Weet je zeker dat je {target} wilt verwijderen?", - "message.confirm-leave": "Are you sure you want to leave {target}?", + "message.confirm-leave": "Weet je zeker dat je {target} wilt verlaten?", "message.confirm-reset": "Weet je zeker dat je de statistieken van {target} opnieuw wilt instellen?", "message.delete-website": "Website verwijderen", "message.delete-website-warning": "Alle verwante gegezens zullen ook verwijderd worden.", "message.error": "Er is iets misgegaan.", - "message.event-log": "{event} on {url}", + "message.event-log": "{event} op {url}", "message.go-to-settings": "Naar instellingen", "message.incorrect-username-password": "Incorrecte gebruikersnaam/wachtwoord.", "message.invalid-domain": "Ongeldig domein", - "message.min-password-length": "Minimum length of {n} characters", + "message.min-password-length": "Minimale lengte van {n} tekens", "message.no-data-available": "Geen gegevens beschikbaar.", "message.no-match-password": "Wachtwoorden komen niet overeen", - "message.no-teams": "You have not created any teams.", - "message.no-users": "There are no users.", + "message.no-teams": "Er zijn nog geen teams aangemaakt.", + "message.no-users": "Er zijn geen gebruikers.", "message.page-not-found": "Pagina niet gevonden.", "message.reset-website": "Statistieken opnieuw instellen", "message.reset-website-warning": "Alle bijhorende statistieken van deze website worden verwijderd, maar jouw volgcode blijft gelden.", "message.saved": "Opslaan succesvol.", "message.share-url": "Met deze URL kan {target} openbaar gedeeld worden.", - "message.team-already-member": "You are already a member of the team.", - "message.team-not-found": "Team not found.", + "message.team-already-member": "Je bent al lid van het team.", + "message.team-not-found": "Team niet gevonden.", "message.tracking-code": "Volgcode", - "message.user-deleted": "User deleted.", + "message.user-deleted": "Gebruiker verwijderd.", "message.visitor-log": "Bezoeker uit {country} met {browser} op een {os} {device}", - "messages.no-team-websites": "This team does not have any websites.", + "messages.no-team-websites": "Er zijn geen websites gekoppeld aan dit team.", "messages.no-websites-configured": "Je hebt geen websites ingesteld.", - "messages.team-websites-info": "Websites can be viewed by anyone on the team." + "messages.team-websites-info": "Websites kunnen door iedereen in het team worden bekeken." } diff --git a/lang/pt-BR.json b/lang/pt-BR.json index f02b7fb9..590cb33c 100644 --- a/lang/pt-BR.json +++ b/lang/pt-BR.json @@ -1,27 +1,27 @@ { - "label.access-code": "Access code", + "label.access-code": "Código de acesso", "label.actions": "Ações", - "label.activity-log": "Activity log", + "label.activity-log": "Log de atividade", "label.add-website": "Adicionar site", "label.admin": "Administrador", "label.all": "Todos", "label.all-time": "Todo o período", - "label.analytics": "Analytics", + "label.analytics": "Estatísticas", "label.average-visit-time": "Tempo médio da visita", "label.back": "Voltar", "label.bounce-rate": "Taxa de rejeição", "label.browsers": "Navegadores", "label.cancel": "Cancelar", "label.change-password": "Alterar a senha", - "label.cities": "Cities", - "label.clear-all": "Clear all", - "label.confirm": "Confirm", + "label.cities": "Cidades", + "label.clear-all": "Limpar tudo", + "label.confirm": "Confirmar", "label.confirm-password": "Confirme a nova senha", - "label.continue": "Continue", + "label.continue": "Continuar", "label.countries": "Países", - "label.create-team": "Create team", - "label.create-user": "Create user", - "label.created": "Created", + "label.create-team": "Criar time", + "label.create-user": "Criar usuário", + "label.created": "Criado", "label.current-password": "Senha atual", "label.custom-range": "Intervalo personalizado", "label.dashboard": "Painel", @@ -29,37 +29,37 @@ "label.date-range": "Intervalo de datas", "label.default-date-range": "Intervalo de datas predefinido", "label.delete": "Remover", - "label.delete-team": "Delete team", - "label.delete-user": "Delete user", + "label.delete-team": "Remover time", + "label.delete-user": "Remover usuário", "label.delete-website": "Remover site", "label.desktop": "Computador", - "label.details": "Details", + "label.details": "Detalhes", "label.devices": "Dispositivos", "label.dismiss": "Dispensar", "label.domain": "Domínio", "label.edit": "Editar", - "label.edit-dashboard": "Edit dashboard", + "label.edit-dashboard": "Editar painel", "label.enable-share-url": "Ativar link de compartilhamento", "label.events": "Eventos", "label.filter-combined": "Combinado", "label.filter-raw": "Dados brutos", - "label.join": "Join", - "label.join-team": "Join team", + "label.join": "Entrar", + "label.join-team": "Entrar no time", "label.language": "Idioma", "label.languages": "Idiomas", "label.laptop": "Notebook", "label.last-days": "Últimos {x} dias", "label.last-hours": "Últimas {x} horas", - "label.leave": "Leave", - "label.leave-team": "Leave team", + "label.leave": "Sair", + "label.leave-team": "Sair do time", "label.login": "Iniciar sessão", "label.logout": "Sair", - "label.members": "Members", + "label.members": "Membros", "label.mobile": "Celular", "label.more": "Mais", "label.name": "Nome", "label.new-password": "Nova senha", - "label.none": "None", + "label.none": "Nenhum", "label.operating-systems": "Sistemas operacionais", "label.owner": "Proprietário", "label.page-views": "Visualizações de página", @@ -67,80 +67,80 @@ "label.password": "Senha", "label.powered-by": "Distribuído por {name}", "label.profile": "Perfil", - "label.queries": "Queries", + "label.queries": "Parâmetros", "label.query-parameters": "Parâmetros de Consulta", "label.realtime": "Tempo real", "label.referrers": "Referências", "label.refresh": "Atualizar", - "label.regenerate": "Regenerate", - "label.regions": "Regions", - "label.remove": "Remove", + "label.regenerate": "Regerar", + "label.regions": "Regiões", + "label.remove": "Remover", "label.required": "Obrigatório", "label.reset": "Redefinir", "label.reset-website": "Redefinir estatísticas", - "label.role": "Role", + "label.role": "Papel", "label.save": "Salvar", "label.screens": "Telas", - "label.select-website": "Select website", - "label.sessions": "Sessions", + "label.select-website": "Selecionar site", + "label.sessions": "Sessões", "label.settings": "Configurações", "label.share-url": "Link de compartilhamento", "label.single-day": "Dia específico", "label.tablet": "Tablet", - "label.team": "Team", - "label.team-guest": "Team guest", - "label.team-id": "Team ID", - "label.team-member": "Team member", - "label.team-owner": "Team owner", - "label.teams": "Teams", + "label.team": "Time", + "label.team-guest": "Convidado", + "label.team-id": "ID do Time", + "label.team-member": "Membro", + "label.team-owner": "Proprietário", + "label.teams": "Times", "label.theme": "Tema", "label.this-month": "Este mês", "label.this-week": "Esta semana", "label.this-year": "Este ano", "label.timezone": "Fuso horário", - "label.title": "Title", + "label.title": "Título", "label.today": "Hoje", "label.toggle-charts": "Mostrar/Esconder gráficos", "label.tracking-code": "Código de rastreamento", "label.unique-visitors": "Visitantes únicos", "label.unknown": "Desconhecido", - "label.user": "User", + "label.user": "Usuário", "label.username": "Nome de usuário", - "label.users": "Users", - "label.view": "View", + "label.users": "Usuários", + "label.view": "Ver", "label.view-details": "Ver detalhes", "label.views": "Visualizações", "label.visitors": "Visitantes", - "label.website-id": "Website ID", + "label.website-id": "ID do Site", "label.websites": "Sites", "label.yesterday": "Ontem", "message.active-users": "{x} {x, plural, one {visitante} other {visitantes}} neste momento", "message.confirm-delete": "Deseja realmente remover {target}?", - "message.confirm-leave": "Are you sure you want to leave {target}?", + "message.confirm-leave": "Você tem certeza que deseja sair de {target}?", "message.confirm-reset": "Você tem certeza que deseja redefinir as estatísticas de {target}?", "message.delete-website": "Remover site", "message.delete-website-warning": "Todos os dados associados também serão eliminados.", "message.error": "Ocorreu um erro.", - "message.event-log": "{event} on {url}", + "message.event-log": "{event} em {url}", "message.go-to-settings": "Ir para as configurações", "message.incorrect-username-password": "O nome de usuário e/ou senha está incorreto.", "message.invalid-domain": "Domínio inválido", - "message.min-password-length": "Minimum length of {n} characters", + "message.min-password-length": "Quantidade mínima de {n} caracteres", "message.no-data-available": "Sem dados disponíveis.", "message.no-match-password": "As senhas não correspondem", - "message.no-teams": "You have not created any teams.", - "message.no-users": "There are no users.", + "message.no-teams": "Você não criou nenhum time.", + "message.no-users": "Não há nenhum usuário.", "message.page-not-found": "Página não encontrada.", "message.reset-website": "Redefinir estatísticas", "message.reset-website-warning": "Todas as estatísticas deste site serão removidas, mas seu código de rastreamento permanecerá intacto.", "message.saved": "Salvo com sucesso.", "message.share-url": "Este é o link público de compartilhamento para {target}.", - "message.team-already-member": "You are already a member of the team.", - "message.team-not-found": "Team not found.", + "message.team-already-member": "Você já um membro do time.", + "message.team-not-found": "Time não encontrado.", "message.tracking-code": "Código de rastreamento", - "message.user-deleted": "User deleted.", + "message.user-deleted": "Usuário removido.", "message.visitor-log": "Visitante de {country} usando {browser} no {device} {os}", - "messages.no-team-websites": "This team does not have any websites.", + "messages.no-team-websites": "Este time não possui nenhum site.", "messages.no-websites-configured": "Nenhum site foi configurado ainda.", - "messages.team-websites-info": "Websites can be viewed by anyone on the team." + "messages.team-websites-info": "Os sites podem ser visualizados por qualquer membro da equipe." } diff --git a/lib/cache.ts b/lib/cache.ts index 2aad7ed8..e63a53bb 100644 --- a/lib/cache.ts +++ b/lib/cache.ts @@ -2,35 +2,7 @@ import { User, Website } from '@prisma/client'; import redis from '@umami/redis-client'; import { getSession, getUser, getWebsite } from '../queries'; -const DELETED = 'DELETED'; - -async function fetchObject(key, query) { - const obj = await redis.get(key); - - if (obj === DELETED) { - return null; - } - - if (!obj) { - return query().then(async data => { - if (data) { - await redis.set(key, data); - } - - return data; - }); - } - - return obj; -} - -async function storeObject(key, data) { - return redis.set(key, data); -} - -async function deleteObject(key, soft = false) { - return soft ? redis.set(key, DELETED) : redis.del(key); -} +const { fetchObject, storeObject, deleteObject } = redis; async function fetchWebsite(id): Promise { return fetchObject(`website:${id}`, () => getWebsite({ id })); @@ -77,6 +49,11 @@ async function deleteSession(id) { return deleteObject(`session:${id}`); } +async function fetchUserBlock(userId: string) { + const key = `user:block:${userId}`; + return redis.get(key); +} + export default { fetchWebsite, storeWebsite, @@ -87,5 +64,6 @@ export default { fetchSession, storeSession, deleteSession, + fetchUserBlock, enabled: redis.enabled, }; diff --git a/lib/middleware.ts b/lib/middleware.ts index 79c48404..1fd13b09 100644 --- a/lib/middleware.ts +++ b/lib/middleware.ts @@ -1,4 +1,10 @@ -import { createMiddleware, unauthorized, badRequest, parseSecureToken } from 'next-basics'; +import { + createMiddleware, + unauthorized, + badRequest, + parseSecureToken, + tooManyRequest, +} from 'next-basics'; import debug from 'debug'; import cors from 'cors'; import { validate } from 'uuid'; @@ -30,6 +36,9 @@ export const useSession = createMiddleware(async (req, res, next) => { (req as any).session = session; } catch (e: any) { + if (e.message === 'Usage Limit.') { + return tooManyRequest(res, e.message); + } return badRequest(res, e.message); } diff --git a/lib/session.ts b/lib/session.ts index 937bfef2..32f3bdc8 100644 --- a/lib/session.ts +++ b/lib/session.ts @@ -6,6 +6,7 @@ import { CollectRequestBody, NextApiRequestCollect } from 'pages/api/send'; import { createSession } from 'queries'; import { validate } from 'uuid'; import { loadSession, loadWebsite } from './query'; +import cache from './cache'; export async function findSession(req: NextApiRequestCollect) { const { payload } = getJsonBody(req); @@ -21,6 +22,8 @@ export async function findSession(req: NextApiRequestCollect) { const result = await parseToken(cacheToken, secret()); if (result) { + await checkUserBlock(result?.ownerId); + return result; } } @@ -39,6 +42,8 @@ export async function findSession(req: NextApiRequestCollect) { throw new Error(`Website not found: ${websiteId}.`); } + await checkUserBlock(website.userId); + const { userAgent, browser, os, ip, country, subdivision1, subdivision2, city, device } = await getClientInfo(req, payload); const sessionId = uuid(websiteId, hostname, ip, userAgent); @@ -88,5 +93,11 @@ export async function findSession(req: NextApiRequestCollect) { } } - return session; + return { ...session, ownerId: website.userId }; +} + +async function checkUserBlock(userId: string) { + if (process.env.ENABLE_BLOCKER && (await cache.fetchUserBlock(userId))) { + throw new Error('Usage Limit.'); + } } diff --git a/package.json b/package.json index 736ec659..0db07f49 100644 --- a/package.json +++ b/package.json @@ -62,7 +62,7 @@ "@prisma/client": "4.13.0", "@tanstack/react-query": "^4.16.1", "@umami/prisma-client": "^0.2.0", - "@umami/redis-client": "^0.2.0", + "@umami/redis-client": "^0.5.0", "chalk": "^4.1.1", "chart.js": "^4.2.1", "chartjs-adapter-date-fns": "^3.0.0", diff --git a/pages/api/send.ts b/pages/api/send.ts index 51ddb980..df7ceb6e 100644 --- a/pages/api/send.ts +++ b/pages/api/send.ts @@ -28,6 +28,7 @@ export interface NextApiRequestCollect extends NextApiRequest { session: { id: string; websiteId: string; + ownerId: string; hostname: string; browser: string; os: string; diff --git a/pages/api/users/[id]/index.ts b/pages/api/users/[id]/index.ts index 8219c4a7..de4642cb 100644 --- a/pages/api/users/[id]/index.ts +++ b/pages/api/users/[id]/index.ts @@ -51,11 +51,11 @@ export default async ( data.password = hashPassword(password); } + // Only admin can change these fields if (role && isAdmin) { data.role = role; } - // Only admin can change these fields if (username && isAdmin) { data.username = username; } diff --git a/pages/api/websites/[id]/index.ts b/pages/api/websites/[id]/index.ts index c1907fce..3f660a91 100644 --- a/pages/api/websites/[id]/index.ts +++ b/pages/api/websites/[id]/index.ts @@ -1,8 +1,8 @@ +import { NextApiResponse } from 'next'; +import { methodNotAllowed, ok, serverError, unauthorized } from 'next-basics'; import { Website, NextApiRequestQueryBody } from 'lib/types'; import { canViewWebsite, canUpdateWebsite, canDeleteWebsite } from 'lib/auth'; import { useAuth, useCors } from 'lib/middleware'; -import { NextApiResponse } from 'next'; -import { methodNotAllowed, ok, serverError, unauthorized } from 'next-basics'; import { deleteWebsite, getWebsite, updateWebsite } from 'queries'; export interface WebsiteRequestQuery { diff --git a/pages/realtime/[id]/index.js b/pages/realtime/[id]/index.js index 43475fa5..ba13ded3 100644 --- a/pages/realtime/[id]/index.js +++ b/pages/realtime/[id]/index.js @@ -10,7 +10,7 @@ export default function RealtimeDetailsPage() { const { formatMessage, labels } = useMessages(); const { get, useQuery } = useApi(); const { data: website } = useQuery(['websites', websiteId], () => - get(`/websites/${websiteId}`, { enabled: !!websiteId }), + websiteId ? get(`/websites/${websiteId}`, { enabled: !!websiteId }) : null, ); const title = `${formatMessage(labels.realtime)}${website?.name ? ` - ${website.name}` : ''}`; diff --git a/public/intl/messages/de-CH.json b/public/intl/messages/de-CH.json index 8e2630ad..88a93208 100644 --- a/public/intl/messages/de-CH.json +++ b/public/intl/messages/de-CH.json @@ -2,7 +2,7 @@ "label.access-code": [ { "type": 0, - "value": "Access code" + "value": "Zuegangscode" } ], "label.actions": [ @@ -14,7 +14,7 @@ "label.activity-log": [ { "type": 0, - "value": "Activity log" + "value": "Aktivitätsverlauf" } ], "label.add-website": [ @@ -86,19 +86,19 @@ "label.cities": [ { "type": 0, - "value": "Cities" + "value": "Städt" } ], "label.clear-all": [ { "type": 0, - "value": "Clear all" + "value": "Alles lösche" } ], "label.confirm": [ { "type": 0, - "value": "Confirm" + "value": "Bestätige" } ], "label.confirm-password": [ @@ -110,7 +110,7 @@ "label.continue": [ { "type": 0, - "value": "Continue" + "value": "Wiiter" } ], "label.countries": [ @@ -122,19 +122,19 @@ "label.create-team": [ { "type": 0, - "value": "Create team" + "value": "Team erstelle" } ], "label.create-user": [ { "type": 0, - "value": "Create user" + "value": "Benutzer erstelle" } ], "label.created": [ { "type": 0, - "value": "Created" + "value": "Erstellt" } ], "label.current-password": [ @@ -158,7 +158,7 @@ "label.data": [ { "type": 0, - "value": "Data" + "value": "Datä" } ], "label.date-range": [ @@ -182,13 +182,13 @@ "label.delete-team": [ { "type": 0, - "value": "Delete team" + "value": "Team lösche" } ], "label.delete-user": [ { "type": 0, - "value": "Delete user" + "value": "Benutzer lösche" } ], "label.delete-website": [ @@ -266,13 +266,13 @@ "label.join": [ { "type": 0, - "value": "Join" + "value": "Biträte" } ], "label.join-team": [ { "type": 0, - "value": "Join team" + "value": "Team biträte" } ], "label.language": [ @@ -324,19 +324,19 @@ "label.leave": [ { "type": 0, - "value": "Leave" + "value": "Verlah" } ], "label.leave-team": [ { "type": 0, - "value": "Leave team" + "value": "Team verlah" } ], "label.login": [ { "type": 0, - "value": "Login" + "value": "Aamelde" } ], "label.logout": [ @@ -348,7 +348,7 @@ "label.members": [ { "type": 0, - "value": "Members" + "value": "Mitglieder" } ], "label.mobile": [ @@ -384,7 +384,7 @@ "label.operating-systems": [ { "type": 0, - "value": "Betriebssystem" + "value": "Betriibssystem" } ], "label.owner": [ @@ -430,7 +430,7 @@ "label.queries": [ { "type": 0, - "value": "Queries" + "value": "Abfrage" } ], "label.query-parameters": [ @@ -460,19 +460,19 @@ "label.regenerate": [ { "type": 0, - "value": "Regenerate" + "value": "Erneuere" } ], "label.regions": [ { "type": 0, - "value": "Regions" + "value": "Regionä" } ], "label.remove": [ { "type": 0, - "value": "Remove" + "value": "Entferne" } ], "label.required": [ @@ -496,7 +496,7 @@ "label.role": [ { "type": 0, - "value": "Role" + "value": "Rollä" } ], "label.save": [ @@ -514,7 +514,7 @@ "label.select-website": [ { "type": 0, - "value": "Select website" + "value": "Websiite uuswähle" } ], "label.sessions": [ @@ -556,7 +556,7 @@ "label.team-guest": [ { "type": 0, - "value": "Team guest" + "value": "Team Gast" } ], "label.team-id": [ @@ -568,13 +568,13 @@ "label.team-member": [ { "type": 0, - "value": "Team member" + "value": "Team Mitglied" } ], "label.team-owner": [ { "type": 0, - "value": "Team owner" + "value": "Team Bsitzer" } ], "label.teams": [ @@ -610,13 +610,13 @@ "label.timezone": [ { "type": 0, - "value": "Zitzone" + "value": "Ziitzone" } ], "label.title": [ { "type": 0, - "value": "Title" + "value": "Titel" } ], "label.today": [ @@ -652,7 +652,7 @@ "label.user": [ { "type": 0, - "value": "User" + "value": "Benutzer" } ], "label.username": [ @@ -664,13 +664,13 @@ "label.users": [ { "type": 0, - "value": "Users" + "value": "Benutzer" } ], "label.view": [ { "type": 0, - "value": "View" + "value": "Azeige" } ], "label.view-details": [ @@ -694,7 +694,7 @@ "label.website-id": [ { "type": 0, - "value": "Website ID" + "value": "Websiite ID" } ], "label.websites": [ @@ -760,7 +760,7 @@ "message.confirm-leave": [ { "type": 0, - "value": "Are you sure you want to leave " + "value": "Sind Sie sich sicher, " }, { "type": 1, @@ -768,7 +768,7 @@ }, { "type": 0, - "value": "?" + "value": " zverlah?" } ], "message.confirm-reset": [ @@ -810,7 +810,7 @@ }, { "type": 0, - "value": " on " + "value": " uf " }, { "type": 1, @@ -838,7 +838,7 @@ "message.min-password-length": [ { "type": 0, - "value": "Minimum length of " + "value": "Miminamli längi vo " }, { "type": 1, @@ -846,7 +846,7 @@ }, { "type": 0, - "value": " characters" + "value": " Zeiche" } ], "message.no-data-available": [ @@ -864,13 +864,13 @@ "message.no-teams": [ { "type": 0, - "value": "You have not created any teams." + "value": "Bisher sind no kei Teams erstellt worde." } ], "message.no-users": [ { "type": 0, - "value": "There are no users." + "value": "Da gits kei Benutzer" } ], "message.page-not-found": [ @@ -900,27 +900,19 @@ "message.share-url": [ { "type": 0, - "value": "Das isch die öffentlichi URL zum Teile für " - }, - { - "type": 1, - "value": "target" - }, - { - "type": 0, - "value": "." + "value": "Ihri Websiitestatistik isch under de folgende URL öffentlich zuegänglich:" } ], "message.team-already-member": [ { "type": 0, - "value": "You are already a member of the team." + "value": "Sie sind bereits es Mitglied vo dem Team." } ], "message.team-not-found": [ { "type": 0, - "value": "Team not found." + "value": "Team nöd gfunde." } ], "message.tracking-code": [ @@ -932,7 +924,7 @@ "message.user-deleted": [ { "type": 0, - "value": "User deleted." + "value": "Benutzer glöscht." } ], "message.visitor-log": [ @@ -972,7 +964,7 @@ "messages.no-team-websites": [ { "type": 0, - "value": "This team does not have any websites." + "value": "Dem Team sind kei Websiite zuegordnet." } ], "messages.no-websites-configured": [ @@ -984,7 +976,7 @@ "messages.team-websites-info": [ { "type": 0, - "value": "Websites can be viewed by anyone on the team." + "value": "Websiite chönd vo jedem im Team agluegt werde" } ] } diff --git a/public/intl/messages/de-DE.json b/public/intl/messages/de-DE.json index 84e252f4..d8a64915 100644 --- a/public/intl/messages/de-DE.json +++ b/public/intl/messages/de-DE.json @@ -122,13 +122,13 @@ "label.create-team": [ { "type": 0, - "value": "Erstelle Team" + "value": "Team erstellen" } ], "label.create-user": [ { "type": 0, - "value": "Erstelle Nutzer" + "value": "Benutzer erstellen" } ], "label.created": [ @@ -182,13 +182,13 @@ "label.delete-team": [ { "type": 0, - "value": "Lösche Team" + "value": "Team löschen" } ], "label.delete-user": [ { "type": 0, - "value": "Lösche Nutzer" + "value": "Benutzer löschen" } ], "label.delete-website": [ @@ -296,7 +296,7 @@ "label.last-days": [ { "type": 0, - "value": "Letzten " + "value": "Letzte " }, { "type": 1, @@ -310,7 +310,7 @@ "label.last-hours": [ { "type": 0, - "value": "Letzten " + "value": "Letzte " }, { "type": 1, @@ -466,7 +466,7 @@ "label.regions": [ { "type": 0, - "value": "Regions" + "value": "Regionen" } ], "label.remove": [ @@ -634,7 +634,7 @@ "label.tracking-code": [ { "type": 0, - "value": "Tracking Kennung" + "value": "Tracking Code" } ], "label.unique-visitors": [ @@ -652,7 +652,7 @@ "label.user": [ { "type": 0, - "value": "User" + "value": "Benutzer" } ], "label.username": [ @@ -664,13 +664,13 @@ "label.users": [ { "type": 0, - "value": "Users" + "value": "Benutzer" } ], "label.view": [ { "type": 0, - "value": "View" + "value": "Anzeigen" } ], "label.view-details": [ @@ -694,7 +694,7 @@ "label.website-id": [ { "type": 0, - "value": "Website ID" + "value": "Webseite ID" } ], "label.websites": [ @@ -810,7 +810,7 @@ }, { "type": 0, - "value": " on " + "value": " auf " }, { "type": 1, @@ -870,7 +870,7 @@ "message.no-users": [ { "type": 0, - "value": "Hier gibt es keine Nutzer." + "value": "Hier gibt es keine Benutzer." } ], "message.page-not-found": [ @@ -900,15 +900,7 @@ "message.share-url": [ { "type": 0, - "value": "Dies ist die öffentliche URL zum Teilen für " - }, - { - "type": 1, - "value": "target" - }, - { - "type": 0, - "value": "." + "value": "Ihre Webseitenstatistik ist unter der folgenden URL öffentlich zugänglich:" } ], "message.team-already-member": [ @@ -926,13 +918,13 @@ "message.tracking-code": [ { "type": 0, - "value": "Tracking Kennung" + "value": "Tracking Code" } ], "message.user-deleted": [ { "type": 0, - "value": "Nutzer gelöscht." + "value": "Benutzer gelöscht." } ], "message.visitor-log": [ diff --git a/public/intl/messages/mn-MN.json b/public/intl/messages/mn-MN.json index 92befd98..beaab2d7 100644 --- a/public/intl/messages/mn-MN.json +++ b/public/intl/messages/mn-MN.json @@ -2,7 +2,7 @@ "label.access-code": [ { "type": 0, - "value": "Access code" + "value": "Хандалтын код" } ], "label.actions": [ @@ -14,7 +14,7 @@ "label.activity-log": [ { "type": 0, - "value": "Activity log" + "value": "Үйл ажиллагааны бүртгэл" } ], "label.add-website": [ @@ -86,19 +86,19 @@ "label.cities": [ { "type": 0, - "value": "Cities" + "value": "Хотууд" } ], "label.clear-all": [ { "type": 0, - "value": "Clear all" + "value": "Бүгдийг арилгах" } ], "label.confirm": [ { "type": 0, - "value": "Confirm" + "value": "Батлах" } ], "label.confirm-password": [ @@ -110,7 +110,7 @@ "label.continue": [ { "type": 0, - "value": "Continue" + "value": "Үргэлжлүүлэх" } ], "label.countries": [ @@ -122,19 +122,19 @@ "label.create-team": [ { "type": 0, - "value": "Create team" + "value": "Баг үүсгэх" } ], "label.create-user": [ { "type": 0, - "value": "Create user" + "value": "Хэрэглэгч үүсгэх" } ], "label.created": [ { "type": 0, - "value": "Created" + "value": "Үүсгэсэн" } ], "label.current-password": [ @@ -158,13 +158,13 @@ "label.data": [ { "type": 0, - "value": "Data" + "value": "Өгөгдөл" } ], "label.date-range": [ { "type": 0, - "value": "Хугацааны мужид" + "value": "Хугацааны муж" } ], "label.default-date-range": [ @@ -182,13 +182,13 @@ "label.delete-team": [ { "type": 0, - "value": "Delete team" + "value": "Баг устгах" } ], "label.delete-user": [ { "type": 0, - "value": "Delete user" + "value": "Хэрэглэгч устгах" } ], "label.delete-website": [ @@ -206,7 +206,7 @@ "label.details": [ { "type": 0, - "value": "Details" + "value": "Мэдээлэл" } ], "label.devices": [ @@ -266,13 +266,13 @@ "label.join": [ { "type": 0, - "value": "Join" + "value": "Нэгдэх" } ], "label.join-team": [ { "type": 0, - "value": "Join team" + "value": "Багт нэгдэх" } ], "label.language": [ @@ -324,13 +324,13 @@ "label.leave": [ { "type": 0, - "value": "Leave" + "value": "Гарах" } ], "label.leave-team": [ { "type": 0, - "value": "Leave team" + "value": "Багаас гарах" } ], "label.login": [ @@ -348,7 +348,7 @@ "label.members": [ { "type": 0, - "value": "Members" + "value": "Гишүүд" } ], "label.mobile": [ @@ -430,7 +430,7 @@ "label.queries": [ { "type": 0, - "value": "Queries" + "value": "Query-нүүд" } ], "label.query-parameters": [ @@ -460,19 +460,19 @@ "label.regenerate": [ { "type": 0, - "value": "Regenerate" + "value": "Дахин үүсгэх" } ], "label.regions": [ { "type": 0, - "value": "Regions" + "value": "Бүсүүд" } ], "label.remove": [ { "type": 0, - "value": "Remove" + "value": "Устгах" } ], "label.required": [ @@ -484,7 +484,7 @@ "label.reset": [ { "type": 0, - "value": "Хуучин хэвд нь оруулах" + "value": "Дахин эхлүүлэх" } ], "label.reset-website": [ @@ -496,7 +496,7 @@ "label.role": [ { "type": 0, - "value": "Role" + "value": "Эрх" } ], "label.save": [ @@ -514,7 +514,7 @@ "label.select-website": [ { "type": 0, - "value": "Select website" + "value": "Веб сонгох" } ], "label.sessions": [ @@ -550,37 +550,37 @@ "label.team": [ { "type": 0, - "value": "Team" + "value": "Баг" } ], "label.team-guest": [ { "type": 0, - "value": "Team guest" + "value": "Багийн зочин" } ], "label.team-id": [ { "type": 0, - "value": "Team ID" + "value": "Багийн ID" } ], "label.team-member": [ { "type": 0, - "value": "Team member" + "value": "Багийн гишүүн" } ], "label.team-owner": [ { "type": 0, - "value": "Team owner" + "value": "Багийн эзэмшигч" } ], "label.teams": [ { "type": 0, - "value": "Teams" + "value": "Багууд" } ], "label.theme": [ @@ -616,7 +616,7 @@ "label.title": [ { "type": 0, - "value": "Title" + "value": "Гарчиг" } ], "label.today": [ @@ -652,7 +652,7 @@ "label.user": [ { "type": 0, - "value": "User" + "value": "Хэрэглэгч" } ], "label.username": [ @@ -664,13 +664,13 @@ "label.users": [ { "type": 0, - "value": "Users" + "value": "Хэрэглэгчид" } ], "label.view": [ { "type": 0, - "value": "View" + "value": "Харах" } ], "label.view-details": [ @@ -694,7 +694,7 @@ "label.website-id": [ { "type": 0, - "value": "Website ID" + "value": "Вебийн ID" } ], "label.websites": [ @@ -768,7 +768,7 @@ "message.confirm-leave": [ { "type": 0, - "value": "Are you sure you want to leave " + "value": "Та " }, { "type": 1, @@ -776,7 +776,7 @@ }, { "type": 0, - "value": "?" + "value": "-с гарахдаа итгэлтэй байна уу?" } ], "message.confirm-reset": [ @@ -796,13 +796,21 @@ "message.delete-website": [ { "type": 0, - "value": "Веб устгах" + "value": "Веб устгахын тулд доорх хэсэгт " + }, + { + "type": 1, + "value": "confirmation" + }, + { + "type": 0, + "value": " гэж бичиж, баталгаажуулна уу." } ], "message.delete-website-warning": [ { "type": 0, - "value": "Үүнтэй холбоотой бүх өгөгдөл устах болно." + "value": "Энэ вебтэй холбоотой бүх өгөгдөл устах болно." } ], "message.error": [ @@ -814,15 +822,15 @@ "message.event-log": [ { "type": 1, - "value": "event" + "value": "url" }, { "type": 0, - "value": " on " + "value": "-д " }, { "type": 1, - "value": "url" + "value": "event" } ], "message.go-to-settings": [ @@ -846,7 +854,7 @@ "message.min-password-length": [ { "type": 0, - "value": "Minimum length of " + "value": "Хамгийн багадаа " }, { "type": 1, @@ -854,7 +862,7 @@ }, { "type": 0, - "value": " characters" + "value": " тэмдэгт" } ], "message.no-data-available": [ @@ -866,19 +874,19 @@ "message.no-match-password": [ { "type": 0, - "value": "Нууц үг тохирохгүй байна" + "value": "Нууц үг тохирохгүй байна." } ], "message.no-teams": [ { "type": 0, - "value": "You have not created any teams." + "value": "Та ямар ч баг үүсгээгүй байна." } ], "message.no-users": [ { "type": 0, - "value": "There are no users." + "value": "Хэрэглэгч байхгүй байна." } ], "message.page-not-found": [ @@ -890,7 +898,15 @@ "message.reset-website": [ { "type": 0, - "value": "Тоон үзүүлэлтийг дахин эхлүүлэх" + "value": "Тоон үзүүлэлийг дахин эхлүүлэхийн тулд доорх хэсэгт " + }, + { + "type": 1, + "value": "confirmation" + }, + { + "type": 0, + "value": " гэж бичиж, баталгаажуулна уу." } ], "message.reset-website-warning": [ @@ -902,41 +918,51 @@ "message.saved": [ { "type": 0, - "value": "Амжилттай хадгаллаа." + "value": "Хадгалсан." } ], "message.share-url": [ - { - "type": 1, - "value": "target" - }, { "type": 0, - "value": "-г нийтэд хуваалцах холбоос." + "value": "Таны вебийн тоон үзүүлэлтүүд доорх URL дээр нийтэд харагдах болно:" } ], "message.team-already-member": [ { "type": 0, - "value": "You are already a member of the team." + "value": "Та аль хэдийн энэ багийн гишүүн болсон байна." } ], "message.team-not-found": [ { "type": 0, - "value": "Team not found." + "value": "Баг олдсонгүй." } ], "message.tracking-code": [ { "type": 0, - "value": "Мөрдөх код" + "value": "Энэ вебийн хандалтуудыг мөрдөхийн тулд доорх кодыг HTML-нхээ " + }, + { + "children": [ + { + "type": 0, + "value": "..." + } + ], + "type": 8, + "value": "head" + }, + { + "type": 0, + "value": " хэсэгт байрлуулна уу." } ], "message.user-deleted": [ { "type": 0, - "value": "User deleted." + "value": "Хэрэглэгч устсан." } ], "message.visitor-log": [ @@ -976,7 +1002,7 @@ "messages.no-team-websites": [ { "type": 0, - "value": "This team does not have any websites." + "value": "Энэ багт ямар ч веб алга." } ], "messages.no-websites-configured": [ @@ -988,7 +1014,7 @@ "messages.team-websites-info": [ { "type": 0, - "value": "Websites can be viewed by anyone on the team." + "value": "Вебийг багийн бүх гишүүд үзэж болно." } ] } diff --git a/public/intl/messages/nl-NL.json b/public/intl/messages/nl-NL.json index bdaa16cb..714c31a0 100644 --- a/public/intl/messages/nl-NL.json +++ b/public/intl/messages/nl-NL.json @@ -2,7 +2,7 @@ "label.access-code": [ { "type": 0, - "value": "Access code" + "value": "Toegangscode" } ], "label.actions": [ @@ -14,19 +14,19 @@ "label.activity-log": [ { "type": 0, - "value": "Activity log" + "value": "Activiteiten logboek" } ], "label.add-website": [ { "type": 0, - "value": "Website toevoegen" + "value": "Website koppelen" } ], "label.admin": [ { "type": 0, - "value": "Administrator" + "value": "Beheerder" } ], "label.all": [ @@ -86,19 +86,19 @@ "label.cities": [ { "type": 0, - "value": "Cities" + "value": "Steden" } ], "label.clear-all": [ { "type": 0, - "value": "Clear all" + "value": "Filters wissen" } ], "label.confirm": [ { "type": 0, - "value": "Confirm" + "value": "Bevestigen" } ], "label.confirm-password": [ @@ -110,7 +110,7 @@ "label.continue": [ { "type": 0, - "value": "Continue" + "value": "Doorgaan" } ], "label.countries": [ @@ -122,19 +122,19 @@ "label.create-team": [ { "type": 0, - "value": "Create team" + "value": "Team aanmaken" } ], "label.create-user": [ { "type": 0, - "value": "Create user" + "value": "Gebruiker maken" } ], "label.created": [ { "type": 0, - "value": "Created" + "value": "Gemaakt" } ], "label.current-password": [ @@ -158,7 +158,7 @@ "label.data": [ { "type": 0, - "value": "Data" + "value": "Gegevens" } ], "label.date-range": [ @@ -182,13 +182,13 @@ "label.delete-team": [ { "type": 0, - "value": "Delete team" + "value": "Team verwijderen" } ], "label.delete-user": [ { "type": 0, - "value": "Delete user" + "value": "Verwijder gebruiker" } ], "label.delete-website": [ @@ -200,13 +200,13 @@ "label.desktop": [ { "type": 0, - "value": "Desktop" + "value": "Computer" } ], "label.details": [ { "type": 0, - "value": "Details" + "value": "Informatie" } ], "label.devices": [ @@ -236,7 +236,7 @@ "label.edit-dashboard": [ { "type": 0, - "value": "Edit dashboard" + "value": "Dashboard aanpassen" } ], "label.enable-share-url": [ @@ -266,13 +266,13 @@ "label.join": [ { "type": 0, - "value": "Join" + "value": "Lid worden" } ], "label.join-team": [ { "type": 0, - "value": "Join team" + "value": "Word lid van een team" } ], "label.language": [ @@ -284,7 +284,7 @@ "label.languages": [ { "type": 0, - "value": "Languages" + "value": "Talen" } ], "label.laptop": [ @@ -324,13 +324,13 @@ "label.leave": [ { "type": 0, - "value": "Leave" + "value": "Verlaten" } ], "label.leave-team": [ { "type": 0, - "value": "Leave team" + "value": "Verlaat team" } ], "label.login": [ @@ -348,7 +348,7 @@ "label.members": [ { "type": 0, - "value": "Members" + "value": "Gebruikers" } ], "label.mobile": [ @@ -430,13 +430,13 @@ "label.queries": [ { "type": 0, - "value": "Queries" + "value": "Parameters" } ], "label.query-parameters": [ { "type": 0, - "value": "Query parameters" + "value": "URL-parameters" } ], "label.realtime": [ @@ -460,19 +460,19 @@ "label.regenerate": [ { "type": 0, - "value": "Regenerate" + "value": "Opnieuw genereren" } ], "label.regions": [ { "type": 0, - "value": "Regions" + "value": "Regio's" } ], "label.remove": [ { "type": 0, - "value": "Remove" + "value": "Verwijderen" } ], "label.required": [ @@ -484,7 +484,7 @@ "label.reset": [ { "type": 0, - "value": "Resetten" + "value": "Opnieuw instellen" } ], "label.reset-website": [ @@ -496,7 +496,7 @@ "label.role": [ { "type": 0, - "value": "Role" + "value": "Gebruikersrol" } ], "label.save": [ @@ -514,13 +514,13 @@ "label.select-website": [ { "type": 0, - "value": "Select website" + "value": "Website selecteren" } ], "label.sessions": [ { "type": 0, - "value": "Sessions" + "value": "Sessies" } ], "label.settings": [ @@ -556,7 +556,7 @@ "label.team-guest": [ { "type": 0, - "value": "Team guest" + "value": "Team gast" } ], "label.team-id": [ @@ -568,13 +568,13 @@ "label.team-member": [ { "type": 0, - "value": "Team member" + "value": "Teamlid" } ], "label.team-owner": [ { "type": 0, - "value": "Team owner" + "value": "Teameigenaar" } ], "label.teams": [ @@ -616,7 +616,7 @@ "label.title": [ { "type": 0, - "value": "Title" + "value": "Titel" } ], "label.today": [ @@ -652,7 +652,7 @@ "label.user": [ { "type": 0, - "value": "User" + "value": "Gebruiker" } ], "label.username": [ @@ -664,13 +664,13 @@ "label.users": [ { "type": 0, - "value": "Users" + "value": "Gebruikers" } ], "label.view": [ { "type": 0, - "value": "View" + "value": "Weergave" } ], "label.view-details": [ @@ -706,7 +706,7 @@ "label.yesterday": [ { "type": 0, - "value": "Yesterday" + "value": "Gisteren" } ], "message.active-users": [ @@ -760,7 +760,7 @@ "message.confirm-leave": [ { "type": 0, - "value": "Are you sure you want to leave " + "value": "Weet je zeker dat je " }, { "type": 1, @@ -768,7 +768,7 @@ }, { "type": 0, - "value": "?" + "value": " wilt verlaten?" } ], "message.confirm-reset": [ @@ -810,7 +810,7 @@ }, { "type": 0, - "value": " on " + "value": " op " }, { "type": 1, @@ -838,7 +838,7 @@ "message.min-password-length": [ { "type": 0, - "value": "Minimum length of " + "value": "Minimale lengte van " }, { "type": 1, @@ -846,7 +846,7 @@ }, { "type": 0, - "value": " characters" + "value": " tekens" } ], "message.no-data-available": [ @@ -864,13 +864,13 @@ "message.no-teams": [ { "type": 0, - "value": "You have not created any teams." + "value": "Er zijn nog geen teams aangemaakt." } ], "message.no-users": [ { "type": 0, - "value": "There are no users." + "value": "Er zijn geen gebruikers." } ], "message.page-not-found": [ @@ -914,13 +914,13 @@ "message.team-already-member": [ { "type": 0, - "value": "You are already a member of the team." + "value": "Je bent al lid van het team." } ], "message.team-not-found": [ { "type": 0, - "value": "Team not found." + "value": "Team niet gevonden." } ], "message.tracking-code": [ @@ -932,7 +932,7 @@ "message.user-deleted": [ { "type": 0, - "value": "User deleted." + "value": "Gebruiker verwijderd." } ], "message.visitor-log": [ @@ -972,7 +972,7 @@ "messages.no-team-websites": [ { "type": 0, - "value": "This team does not have any websites." + "value": "Er zijn geen websites gekoppeld aan dit team." } ], "messages.no-websites-configured": [ @@ -984,7 +984,7 @@ "messages.team-websites-info": [ { "type": 0, - "value": "Websites can be viewed by anyone on the team." + "value": "Websites kunnen door iedereen in het team worden bekeken." } ] } diff --git a/public/intl/messages/pt-BR.json b/public/intl/messages/pt-BR.json index ffd77c16..63e9a49e 100644 --- a/public/intl/messages/pt-BR.json +++ b/public/intl/messages/pt-BR.json @@ -2,7 +2,7 @@ "label.access-code": [ { "type": 0, - "value": "Access code" + "value": "Código de acesso" } ], "label.actions": [ @@ -14,7 +14,7 @@ "label.activity-log": [ { "type": 0, - "value": "Activity log" + "value": "Log de atividade" } ], "label.add-website": [ @@ -44,7 +44,7 @@ "label.analytics": [ { "type": 0, - "value": "Analytics" + "value": "Estatísticas" } ], "label.average-visit-time": [ @@ -86,19 +86,19 @@ "label.cities": [ { "type": 0, - "value": "Cities" + "value": "Cidades" } ], "label.clear-all": [ { "type": 0, - "value": "Clear all" + "value": "Limpar tudo" } ], "label.confirm": [ { "type": 0, - "value": "Confirm" + "value": "Confirmar" } ], "label.confirm-password": [ @@ -110,7 +110,7 @@ "label.continue": [ { "type": 0, - "value": "Continue" + "value": "Continuar" } ], "label.countries": [ @@ -122,19 +122,19 @@ "label.create-team": [ { "type": 0, - "value": "Create team" + "value": "Criar time" } ], "label.create-user": [ { "type": 0, - "value": "Create user" + "value": "Criar usuário" } ], "label.created": [ { "type": 0, - "value": "Created" + "value": "Criado" } ], "label.current-password": [ @@ -182,13 +182,13 @@ "label.delete-team": [ { "type": 0, - "value": "Delete team" + "value": "Remover time" } ], "label.delete-user": [ { "type": 0, - "value": "Delete user" + "value": "Remover usuário" } ], "label.delete-website": [ @@ -206,7 +206,7 @@ "label.details": [ { "type": 0, - "value": "Details" + "value": "Detalhes" } ], "label.devices": [ @@ -236,7 +236,7 @@ "label.edit-dashboard": [ { "type": 0, - "value": "Edit dashboard" + "value": "Editar painel" } ], "label.enable-share-url": [ @@ -266,13 +266,13 @@ "label.join": [ { "type": 0, - "value": "Join" + "value": "Entrar" } ], "label.join-team": [ { "type": 0, - "value": "Join team" + "value": "Entrar no time" } ], "label.language": [ @@ -324,13 +324,13 @@ "label.leave": [ { "type": 0, - "value": "Leave" + "value": "Sair" } ], "label.leave-team": [ { "type": 0, - "value": "Leave team" + "value": "Sair do time" } ], "label.login": [ @@ -348,7 +348,7 @@ "label.members": [ { "type": 0, - "value": "Members" + "value": "Membros" } ], "label.mobile": [ @@ -378,7 +378,7 @@ "label.none": [ { "type": 0, - "value": "None" + "value": "Nenhum" } ], "label.operating-systems": [ @@ -430,7 +430,7 @@ "label.queries": [ { "type": 0, - "value": "Queries" + "value": "Parâmetros" } ], "label.query-parameters": [ @@ -460,19 +460,19 @@ "label.regenerate": [ { "type": 0, - "value": "Regenerate" + "value": "Regerar" } ], "label.regions": [ { "type": 0, - "value": "Regions" + "value": "Regiões" } ], "label.remove": [ { "type": 0, - "value": "Remove" + "value": "Remover" } ], "label.required": [ @@ -496,7 +496,7 @@ "label.role": [ { "type": 0, - "value": "Role" + "value": "Papel" } ], "label.save": [ @@ -514,13 +514,13 @@ "label.select-website": [ { "type": 0, - "value": "Select website" + "value": "Selecionar site" } ], "label.sessions": [ { "type": 0, - "value": "Sessions" + "value": "Sessões" } ], "label.settings": [ @@ -550,37 +550,37 @@ "label.team": [ { "type": 0, - "value": "Team" + "value": "Time" } ], "label.team-guest": [ { "type": 0, - "value": "Team guest" + "value": "Convidado" } ], "label.team-id": [ { "type": 0, - "value": "Team ID" + "value": "ID do Time" } ], "label.team-member": [ { "type": 0, - "value": "Team member" + "value": "Membro" } ], "label.team-owner": [ { "type": 0, - "value": "Team owner" + "value": "Proprietário" } ], "label.teams": [ { "type": 0, - "value": "Teams" + "value": "Times" } ], "label.theme": [ @@ -616,7 +616,7 @@ "label.title": [ { "type": 0, - "value": "Title" + "value": "Título" } ], "label.today": [ @@ -652,7 +652,7 @@ "label.user": [ { "type": 0, - "value": "User" + "value": "Usuário" } ], "label.username": [ @@ -664,13 +664,13 @@ "label.users": [ { "type": 0, - "value": "Users" + "value": "Usuários" } ], "label.view": [ { "type": 0, - "value": "View" + "value": "Ver" } ], "label.view-details": [ @@ -694,7 +694,7 @@ "label.website-id": [ { "type": 0, - "value": "Website ID" + "value": "ID do Site" } ], "label.websites": [ @@ -764,7 +764,7 @@ "message.confirm-leave": [ { "type": 0, - "value": "Are you sure you want to leave " + "value": "Você tem certeza que deseja sair de " }, { "type": 1, @@ -814,7 +814,7 @@ }, { "type": 0, - "value": " on " + "value": " em " }, { "type": 1, @@ -842,7 +842,7 @@ "message.min-password-length": [ { "type": 0, - "value": "Minimum length of " + "value": "Quantidade mínima de " }, { "type": 1, @@ -850,7 +850,7 @@ }, { "type": 0, - "value": " characters" + "value": " caracteres" } ], "message.no-data-available": [ @@ -868,13 +868,13 @@ "message.no-teams": [ { "type": 0, - "value": "You have not created any teams." + "value": "Você não criou nenhum time." } ], "message.no-users": [ { "type": 0, - "value": "There are no users." + "value": "Não há nenhum usuário." } ], "message.page-not-found": [ @@ -918,13 +918,13 @@ "message.team-already-member": [ { "type": 0, - "value": "You are already a member of the team." + "value": "Você já um membro do time." } ], "message.team-not-found": [ { "type": 0, - "value": "Team not found." + "value": "Time não encontrado." } ], "message.tracking-code": [ @@ -936,7 +936,7 @@ "message.user-deleted": [ { "type": 0, - "value": "User deleted." + "value": "Usuário removido." } ], "message.visitor-log": [ @@ -976,7 +976,7 @@ "messages.no-team-websites": [ { "type": 0, - "value": "This team does not have any websites." + "value": "Este time não possui nenhum site." } ], "messages.no-websites-configured": [ @@ -988,7 +988,7 @@ "messages.team-websites-info": [ { "type": 0, - "value": "Websites can be viewed by anyone on the team." + "value": "Os sites podem ser visualizados por qualquer membro da equipe." } ] } diff --git a/queries/admin/user.ts b/queries/admin/user.ts index 412c7785..a81a76ef 100644 --- a/queries/admin/user.ts +++ b/queries/admin/user.ts @@ -1,4 +1,5 @@ import { Prisma, Team, TeamUser } from '@prisma/client'; +import { getRandomChars } from 'next-basics'; import cache from 'lib/cache'; import { ROLES } from 'lib/constants'; import prisma from 'lib/prisma'; @@ -222,6 +223,7 @@ export async function deleteUser( cloudMode ? client.user.update({ data: { + username: getRandomChars(32), deletedAt: new Date(), }, where: { diff --git a/scripts/check-db.js b/scripts/check-db.js index 3fd3a908..a84a775c 100644 --- a/scripts/check-db.js +++ b/scripts/check-db.js @@ -11,7 +11,7 @@ if (process.env.SKIP_DB_CHECK) { } function getDatabaseType(url = process.env.DATABASE_URL) { - const type = process.env.DATABASE_TYPE || (url && url.split(':')[0]); + const type = url && url.split(':')[0]; if (type === 'postgres') { return 'postgresql'; @@ -20,7 +20,6 @@ function getDatabaseType(url = process.env.DATABASE_URL) { return type; } -const databaseType = getDatabaseType(); const prisma = new PrismaClient(); function success(msg) { @@ -49,10 +48,11 @@ async function checkConnection() { } } -async function checkDatabaseVersion(databaseType) { +async function checkDatabaseVersion() { const query = await prisma.$queryRaw`select version() as version`; const version = semver.valid(semver.coerce(query[0].version)); + const databaseType = getDatabaseType(); const minVersion = databaseType === 'postgresql' ? '9.4.0' : '5.7.0'; if (semver.lt(version, minVersion)) { @@ -87,7 +87,7 @@ async function applyMigration() { let err = false; for (let fn of [checkEnv, checkConnection, checkDatabaseVersion, checkV1Tables, applyMigration]) { try { - fn.name === 'checkDatabaseVersion' ? await fn(databaseType) : await fn(); + await fn(); } catch (e) { error(e.message); err = true; diff --git a/tracker/index.d.ts b/tracker/index.d.ts new file mode 100644 index 00000000..67cebc08 --- /dev/null +++ b/tracker/index.d.ts @@ -0,0 +1,138 @@ +type TrackedProperties = { + /** + * Hostname of server + * + * @description extracted from `window.location.hostname` + * @example 'analytics.umami.is' + */ + hostname: string; + + /** + * Browser language + * + * @description extracted from `window.navigator.language` + * @example 'en-US', 'fr-FR' + */ + language: string; + + /** + * Page referrer + * + * @description extracted from `window.navigator.language` + * @example 'https://analytics.umami.is/docs/getting-started' + */ + referrer: string; + + /** + * Screen dimensions + * + * @description extracted from `window.screen.width` and `window.screen.height` + * @example '1920x1080', '2560x1440' + */ + screen: string; + + /** + * Page title + * + * @description extracted from `document.querySelector('head > title')` + * @example 'umami' + */ + title: string; + + /** + * Page url + * + * @description built from `${window.location.pathname}${window.location.search}` + * @example 'docs/getting-started' + */ + url: string; + + /** + * Website ID (required) + * + * @example 'b59e9c65-ae32-47f1-8400-119fcf4861c4' + */ + website: string; +}; + +type WithRequired = T & { [P in K]-?: T[P] } + +/** + * + * Event Data can work with any JSON data. There are a few rules in place to maintain performance. + * - Numbers have a max precision of 4. + * - Strings have a max length of 500. + * - Arrays are converted to a String, with the same max length of 500. + * - Objects have a max of 50 properties. Arrays are considered 1 property. + */ +type EventData = Record; +type EventProperties = { + name: string; + data?: EventData; +} & WithRequired +| WithRequired; + +interface Window { + umami: { + track: { + /** + * Track a page view + * + * @example ``` + * umami.track(); + * ``` + */ + (): Promise; + + /** + * Track an event with a given name + * + * @example ``` + * umami.track('signup-button'); + * ``` + */ + (eventName: string): Promise; + + /** + * Tracks an event with dynamic data. + * + * When tracking events, the default properties are included in the payload. This is equivalent to running: + * + * ```js + * umami.track(props => ({ + * ...props, + * name: 'signup-button', + * data: { + * name: 'newsletter', + * id: 123 + * } + * })); + * ``` + * + * @example ``` + * umami.track('signup-button', { name: 'newsletter', id: 123 }); + * ``` + */ + (eventName: string, obj: EventData): Promise; + + /** + * Tracks a page view with custom properties + * + * @example ``` + * umami.track({ website: 'e676c9b4-11e4-4ef1-a4d7-87001773e9f2', url: '/home', title: 'Home page' }); + * ``` + */ + (properties: WithRequired, 'website'>): Promise; + + /** + * Tracks an event with fully customizable dynamic data + * Ilf you don't specify any `name` and/or `data`, it will be treated as a page view + * + * @example ``` + * umami.track((props) => ({ ...props, url: path })); + * ``` + */ + (eventFunction: (prop: TrackedProperties) => EventProperties): Promise; + }; + }; +} diff --git a/yarn.lock b/yarn.lock index d98ada11..41cca434 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3272,10 +3272,10 @@ dependencies: debug "^4.3.4" -"@umami/redis-client@^0.2.0": - version "0.2.0" - resolved "https://registry.yarnpkg.com/@umami/redis-client/-/redis-client-0.2.0.tgz#bdb1cd8b5c99afc5230621f19296c6d3559d68af" - integrity sha512-TONWhkuC//K2hRo3Psk7FHsuvu3XkQIYMY62/CERPtlIJz4Ac7DqsmYw4jO9/RkljA9XLl/5u+OggD4ARhMV8A== +"@umami/redis-client@^0.5.0": + version "0.5.0" + resolved "https://registry.yarnpkg.com/@umami/redis-client/-/redis-client-0.5.0.tgz#09b15458001bc172fc856d65316efbe5ff749461" + integrity sha512-x7wx/pMjyg3AAYzgjGOw031bNhyZ81h6tRMAl60RQQI9xlJaJEA1r0TEUrWfFi21gHAvdBLJGYCsvHzpix4LKQ== dependencies: debug "^4.3.4" redis "^4.5.1"