mirror of
https://github.com/kremalicious/umami.git
synced 2025-02-14 21:10:34 +01:00
commit
4246d4fa50
.github/workflows
.gitignoreDockerfileREADME.mdapp.jsoncomponents
db
mysql
postgresql
hooks
lang
lib
next.config.jspackage.jsonpages
prisma
public/intl
country
language
messages
scripts
sql
store
yarn.lock
36
.github/workflows/cd-manual.yml
vendored
Normal file
36
.github/workflows/cd-manual.yml
vendored
Normal file
@ -0,0 +1,36 @@
|
||||
name: Create docker images
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
version:
|
||||
type: string
|
||||
description: Version
|
||||
required: true
|
||||
add-latest:
|
||||
type: boolean
|
||||
description: Add latest tag
|
||||
required: false
|
||||
|
||||
jobs:
|
||||
build:
|
||||
name: Build, push, and deploy
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
strategy:
|
||||
matrix:
|
||||
db-type: [postgresql, mysql]
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
|
||||
- uses: mr-smithers-excellent/docker-build-push@v5
|
||||
name: Build & push Docker image for ${{ matrix.db-type }}
|
||||
with:
|
||||
image: umami
|
||||
tags: ${{ matrix.db-type }}-${{ inputs.version }}
|
||||
addLatest: ${{ inputs.add-latest }}
|
||||
buildArgs: DATABASE_TYPE=${{ matrix.db-type }}
|
||||
registry: ghcr.io/${{ github.actor }}
|
||||
username: ${{ github.actor }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
15
.github/workflows/cd.yml
vendored
15
.github/workflows/cd.yml
vendored
@ -1,16 +1,12 @@
|
||||
name: Create docker images
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
version:
|
||||
type: string
|
||||
description: Version
|
||||
required: true
|
||||
on: [create]
|
||||
|
||||
jobs:
|
||||
|
||||
build:
|
||||
name: Build, push, and deploy
|
||||
if: ${{ startsWith(github.ref, 'refs/tags/v') }}
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
strategy:
|
||||
@ -20,11 +16,14 @@ jobs:
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
|
||||
- name: Set env
|
||||
run: echo "RELEASE_VERSION=${GITHUB_REF#refs/*/}" >> $GITHUB_ENV
|
||||
|
||||
- uses: mr-smithers-excellent/docker-build-push@v5
|
||||
name: Build & push Docker image for ${{ matrix.db-type }}
|
||||
with:
|
||||
image: umami
|
||||
tags: ${{ matrix.db-type }}-${{ inputs.version }}
|
||||
tags: ${{ matrix.db-type }}-${{ env.RELEASE_VERSION }}, ${{ matrix.db-type }}-latest
|
||||
buildArgs: DATABASE_TYPE=${{ matrix.db-type }}
|
||||
registry: ghcr.io/${{ github.actor }}
|
||||
username: ${{ github.actor }}
|
||||
|
2
.gitignore
vendored
2
.gitignore
vendored
@ -11,7 +11,7 @@
|
||||
# next.js
|
||||
/.next/
|
||||
/out/
|
||||
/prisma/schema.prisma
|
||||
/prisma/
|
||||
|
||||
# production
|
||||
/build
|
||||
|
25
Dockerfile
25
Dockerfile
@ -8,18 +8,20 @@ RUN yarn install --frozen-lockfile
|
||||
|
||||
# Rebuild the source code only when needed
|
||||
FROM node:16-alpine AS builder
|
||||
ARG BASE_PATH
|
||||
ARG DATABASE_TYPE
|
||||
ENV BASE_PATH=$BASE_PATH
|
||||
ENV DATABASE_URL "postgresql://umami:umami@db:5432/umami"
|
||||
ENV DATABASE_TYPE=$DATABASE_TYPE
|
||||
WORKDIR /app
|
||||
COPY --from=deps /app/node_modules ./node_modules
|
||||
COPY . .
|
||||
|
||||
# Next.js collects completely anonymous telemetry data about general usage.
|
||||
# Learn more here: https://nextjs.org/telemetry
|
||||
# Uncomment the following line in case you want to disable telemetry during the build.
|
||||
ARG DATABASE_URL
|
||||
ARG DATABASE_TYPE
|
||||
ARG BASE_PATH
|
||||
ARG DISABLE_LOGIN
|
||||
|
||||
ENV DATABASE_URL $DATABASE_URL
|
||||
ENV DATABASE_TYPE $DATABASE_TYPE
|
||||
ENV BASE_PATH $BASE_PATH
|
||||
ENV DISABLE_LOGIN $DISABLE_LOGIN
|
||||
|
||||
ENV NEXT_TELEMETRY_DISABLED 1
|
||||
|
||||
RUN yarn build
|
||||
@ -29,16 +31,19 @@ FROM node:16-alpine AS runner
|
||||
WORKDIR /app
|
||||
|
||||
ENV NODE_ENV production
|
||||
# Uncomment the following line in case you want to disable telemetry during runtime.
|
||||
ENV NEXT_TELEMETRY_DISABLED 1
|
||||
|
||||
RUN addgroup --system --gid 1001 nodejs
|
||||
RUN adduser --system --uid 1001 nextjs
|
||||
|
||||
RUN yarn global add prisma
|
||||
|
||||
# You only need to copy next.config.js if you are NOT using the default configuration
|
||||
COPY --from=builder /app/next.config.js ./
|
||||
COPY --from=builder /app/public ./public
|
||||
COPY --from=builder /app/package.json ./package.json
|
||||
COPY --from=builder /app/prisma/schema.prisma ./prisma/schema.prisma
|
||||
COPY --from=builder /app/prisma/migrations ./prisma/migrations
|
||||
|
||||
# Automatically leverage output traces to reduce image size
|
||||
# https://nextjs.org/docs/advanced-features/output-file-tracing
|
||||
@ -51,4 +56,4 @@ EXPOSE 3000
|
||||
|
||||
ENV PORT 3000
|
||||
|
||||
CMD ["node", "server.js"]
|
||||
CMD ["yarn", "start-docker"]
|
||||
|
37
README.md
37
README.md
@ -16,10 +16,10 @@ See [Running on Railway](https://umami.is/docs/running-on-railway) to get starte
|
||||
|
||||
### Requirements
|
||||
|
||||
- A server with Node.js 12 or newer
|
||||
- A database (MySQL or Postgresql)
|
||||
- A server with Node.js version 12 or newer
|
||||
- A database. Umami supports [MySQL](https://www.mysql.com/) and [Postgresql](https://www.postgresql.org/) databases.
|
||||
|
||||
### Install Yarn (if needed)
|
||||
### Install Yarn
|
||||
|
||||
```
|
||||
npm install -g yarn
|
||||
@ -33,32 +33,12 @@ cd umami
|
||||
yarn install
|
||||
```
|
||||
|
||||
### Create database tables
|
||||
|
||||
Umami supports [MySQL](https://www.mysql.com/) and [Postgresql](https://www.postgresql.org/).
|
||||
Create a database for your Umami installation and install the tables with the included scripts.
|
||||
|
||||
For MySQL:
|
||||
|
||||
```
|
||||
mysql -u username -p databasename < sql/schema.mysql.sql
|
||||
```
|
||||
|
||||
For Postgresql:
|
||||
|
||||
```
|
||||
psql -h hostname -U username -d databasename -f sql/schema.postgresql.sql
|
||||
```
|
||||
|
||||
This will also create a login account with username **admin** and password **umami**.
|
||||
|
||||
### Configure umami
|
||||
|
||||
Create an `.env` file with the following
|
||||
|
||||
```
|
||||
DATABASE_URL=(connection url)
|
||||
HASH_SALT=(any random string)
|
||||
```
|
||||
|
||||
The connection url is in the following format:
|
||||
@ -68,7 +48,7 @@ postgresql://username:mypassword@localhost:5432/mydb
|
||||
mysql://username:mypassword@localhost:3306/mydb
|
||||
```
|
||||
|
||||
The `HASH_SALT` is used to generate unique values for your installation.
|
||||
This will also create a login account with username **admin** and password **umami**.
|
||||
|
||||
### Build the application
|
||||
|
||||
@ -76,13 +56,19 @@ The `HASH_SALT` is used to generate unique values for your installation.
|
||||
yarn build
|
||||
```
|
||||
|
||||
### Create database tables
|
||||
|
||||
```bash
|
||||
yarn update-db
|
||||
```
|
||||
|
||||
### Start the application
|
||||
|
||||
```bash
|
||||
yarn start
|
||||
```
|
||||
|
||||
By default this will launch the application on `http://localhost:3000`. You will need to either
|
||||
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.
|
||||
|
||||
@ -112,6 +98,7 @@ To get the latest features, simply do a pull, install any new dependencies, and
|
||||
git pull
|
||||
yarn install
|
||||
yarn build
|
||||
yarn update-db
|
||||
```
|
||||
|
||||
To update the Docker image, simply pull the new images and rebuild:
|
||||
|
38
app.json
38
app.json
@ -1,26 +1,16 @@
|
||||
{
|
||||
"name": "Umami",
|
||||
"description": "Umami is a simple, fast, website analytics alternative to Google Analytics.",
|
||||
"keywords": [
|
||||
"analytics",
|
||||
"charts",
|
||||
"statistics",
|
||||
"web-analytics"
|
||||
],
|
||||
"website": "https://umami.is",
|
||||
"repository": "https://github.com/mikecao/umami",
|
||||
"addons": [
|
||||
"heroku-postgresql"
|
||||
],
|
||||
"env": {
|
||||
"HASH_SALT": {
|
||||
"description": "Used to generate unique values for your installation",
|
||||
"required": true,
|
||||
"generator": "secret"
|
||||
}
|
||||
},
|
||||
"scripts": {
|
||||
"postdeploy": "psql $DATABASE_URL -f sql/schema.postgresql.sql"
|
||||
},
|
||||
"success_url": "/"
|
||||
"name": "Umami",
|
||||
"description": "Umami is a simple, fast, website analytics alternative to Google Analytics.",
|
||||
"keywords": ["analytics", "charts", "statistics", "web-analytics"],
|
||||
"website": "https://umami.is",
|
||||
"repository": "https://github.com/mikecao/umami",
|
||||
"addons": ["heroku-postgresql"],
|
||||
"env": {
|
||||
"HASH_SALT": {
|
||||
"description": "Used to generate unique values for your installation",
|
||||
"required": true,
|
||||
"generator": "secret"
|
||||
}
|
||||
},
|
||||
"success_url": "/"
|
||||
}
|
||||
|
@ -2,6 +2,7 @@ import React from 'react';
|
||||
import Link from 'next/link';
|
||||
import classNames from 'classnames';
|
||||
import usePageQuery from 'hooks/usePageQuery';
|
||||
import { safeDecodeURI } from 'lib/url';
|
||||
import Icon from './Icon';
|
||||
import External from 'assets/arrow-up-right-from-square.svg';
|
||||
import styles from './FilterLink.module.css';
|
||||
@ -20,7 +21,7 @@ export default function FilterLink({ id, value, label, externalUrl }) {
|
||||
[styles.active]: active && selected,
|
||||
})}
|
||||
>
|
||||
{label || value}
|
||||
{safeDecodeURI(label || value)}
|
||||
</a>
|
||||
</Link>
|
||||
{externalUrl && (
|
||||
|
@ -1,27 +1,38 @@
|
||||
import React from 'react';
|
||||
import { useState, useEffect, useCallback } from 'react';
|
||||
import { FormattedMessage } from 'react-intl';
|
||||
import useVersion from 'hooks/useVersion';
|
||||
import styles from './UpdateNotice.module.css';
|
||||
import ButtonLayout from '../layout/ButtonLayout';
|
||||
import ButtonLayout from 'components/layout/ButtonLayout';
|
||||
import useStore, { checkVersion } from 'store/version';
|
||||
import { setItem } from 'lib/web';
|
||||
import { VERSION_CHECK, VERSION_URL } from 'lib/constants';
|
||||
import Button from './Button';
|
||||
import useForceUpdate from '../../hooks/useForceUpdate';
|
||||
import styles from './UpdateNotice.module.css';
|
||||
|
||||
export default function UpdateNotice() {
|
||||
const forceUpdate = useForceUpdate();
|
||||
const { hasUpdate, checked, latest, updateCheck } = useVersion(true);
|
||||
const { latest, checked, hasUpdate } = useStore();
|
||||
const [dismissed, setDismissed] = useState(false);
|
||||
|
||||
const updateCheck = useCallback(() => {
|
||||
setItem(VERSION_CHECK, { version: latest, time: Date.now() });
|
||||
}, [latest]);
|
||||
|
||||
function handleViewClick() {
|
||||
location.href = 'https://github.com/mikecao/umami/releases';
|
||||
updateCheck();
|
||||
forceUpdate();
|
||||
setDismissed(true);
|
||||
location.href = VERSION_URL;
|
||||
}
|
||||
|
||||
function handleDismissClick() {
|
||||
updateCheck();
|
||||
forceUpdate();
|
||||
setDismissed(true);
|
||||
}
|
||||
|
||||
if (!hasUpdate || checked) {
|
||||
useEffect(() => {
|
||||
if (!checked) {
|
||||
checkVersion();
|
||||
}
|
||||
}, []);
|
||||
|
||||
if (!hasUpdate || dismissed) {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
@ -3,11 +3,11 @@ import classNames from 'classnames';
|
||||
import { FormattedMessage } from 'react-intl';
|
||||
import Link from 'components/common/Link';
|
||||
import styles from './Footer.module.css';
|
||||
import useVersion from 'hooks/useVersion';
|
||||
import useStore from 'store/version';
|
||||
import { HOMEPAGE_URL, VERSION_URL } from 'lib/constants';
|
||||
|
||||
export default function Footer() {
|
||||
const { current } = useVersion();
|
||||
const { current } = useStore();
|
||||
|
||||
return (
|
||||
<footer className={classNames(styles.footer, 'row')}>
|
||||
|
@ -19,7 +19,7 @@ export default function Header() {
|
||||
|
||||
return (
|
||||
<>
|
||||
{user?.is_admin && <UpdateNotice />}
|
||||
{user?.is_admin && !process.env.updatesDisabled && <UpdateNotice />}
|
||||
<header className={classNames(styles.header, 'row')}>
|
||||
<div className={styles.title}>
|
||||
<Icon icon={<Logo />} size="large" className={styles.logo} />
|
||||
|
@ -1,14 +1,21 @@
|
||||
import React from 'react';
|
||||
import MetricsTable from './MetricsTable';
|
||||
import { percentFilter } from 'lib/filters';
|
||||
import { FormattedMessage } from 'react-intl';
|
||||
import { useIntl, defineMessages } from 'react-intl';
|
||||
import FilterLink from 'components/common/FilterLink';
|
||||
import useCountryNames from 'hooks/useCountryNames';
|
||||
import useLocale from 'hooks/useLocale';
|
||||
|
||||
const messages = defineMessages({
|
||||
unknown: { id: 'label.unknown', defaultMessage: 'Unknown' },
|
||||
countries: { id: 'metrics.countries', defaultMessage: 'Countries' },
|
||||
visitors: { id: 'metrics.visitors', defaultMessage: 'Visitors' },
|
||||
});
|
||||
|
||||
export default function CountriesTable({ websiteId, onDataLoad, ...props }) {
|
||||
const { locale } = useLocale();
|
||||
const countryNames = useCountryNames(locale);
|
||||
const { formatMessage } = useIntl();
|
||||
|
||||
function renderLink({ x: code }) {
|
||||
return (
|
||||
@ -16,9 +23,7 @@ export default function CountriesTable({ websiteId, onDataLoad, ...props }) {
|
||||
<FilterLink
|
||||
id="country"
|
||||
value={code}
|
||||
label={
|
||||
countryNames[code] ?? <FormattedMessage id="label.unknown" defaultMessage="Unknown" />
|
||||
}
|
||||
label={countryNames[code] ?? formatMessage(messages.unknown)}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
@ -27,9 +32,9 @@ export default function CountriesTable({ websiteId, onDataLoad, ...props }) {
|
||||
return (
|
||||
<MetricsTable
|
||||
{...props}
|
||||
title={<FormattedMessage id="metrics.countries" defaultMessage="Countries" />}
|
||||
title={formatMessage(messages.countries)}
|
||||
type="country"
|
||||
metric={<FormattedMessage id="metrics.visitors" defaultMessage="Visitors" />}
|
||||
metric={formatMessage(messages.visitors)}
|
||||
websiteId={websiteId}
|
||||
onDataLoad={data => onDataLoad?.(percentFilter(data))}
|
||||
renderLabel={renderLink}
|
||||
|
@ -97,3 +97,6 @@ ALTER TABLE `session` ADD FOREIGN KEY (`website_id`) REFERENCES `website`(`websi
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE `website` ADD FOREIGN KEY (`user_id`) REFERENCES `account`(`user_id`) ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- CreateAdminUser
|
||||
INSERT INTO account (username, password, is_admin) values ('admin', '$2b$10$BUli0c.muyCW1ErNJc3jL.vFRFtFJWrT8/GcR4A.sUdCznaXiqFXa', true);
|
@ -127,3 +127,6 @@ ALTER TABLE "session" ADD FOREIGN KEY ("website_id") REFERENCES "website"("websi
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "website" ADD FOREIGN KEY ("user_id") REFERENCES "account"("user_id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- CreateAdminUser
|
||||
INSERT INTO account (username, password, is_admin) values ('admin', '$2b$10$BUli0c.muyCW1ErNJc3jL.vFRFtFJWrT8/GcR4A.sUdCznaXiqFXa', true);
|
@ -1,21 +0,0 @@
|
||||
import { useEffect, useCallback } from 'react';
|
||||
import useStore, { checkVersion } from 'store/version';
|
||||
import { VERSION_CHECK } from 'lib/constants';
|
||||
import { getItem, setItem } from 'lib/web';
|
||||
|
||||
export default function useVersion(check) {
|
||||
const versions = useStore();
|
||||
const checked = versions.latest === getItem(VERSION_CHECK)?.version;
|
||||
|
||||
const updateCheck = useCallback(() => {
|
||||
setItem(VERSION_CHECK, { version: versions.latest, time: Date.now() });
|
||||
}, [versions]);
|
||||
|
||||
useEffect(() => {
|
||||
if (check && !versions.latest) {
|
||||
checkVersion();
|
||||
}
|
||||
}, [versions, check]);
|
||||
|
||||
return { ...versions, checked, updateCheck };
|
||||
}
|
@ -5,7 +5,7 @@
|
||||
"label.administrator": "مدیر",
|
||||
"label.all": "همه",
|
||||
"label.all-events": "همهی رویدادها",
|
||||
"label.all-time": "All time",
|
||||
"label.all-time": "همه زمان",
|
||||
"label.all-websites": "همهی وبسایتها",
|
||||
"label.back": "برگشت",
|
||||
"label.cancel": "انصراف",
|
||||
@ -28,16 +28,16 @@
|
||||
"label.enable-share-url": "فعال کردن اشتراک گذاری URL",
|
||||
"label.invalid": "نامعتبر",
|
||||
"label.invalid-domain": "دامنهی نامعتبر",
|
||||
"label.language": "Language",
|
||||
"label.last-days": "لیست {x} روز",
|
||||
"label.last-hours": "لیست {x} ساعت",
|
||||
"label.language": "زبان",
|
||||
"label.last-days": "لیست {x} روز گذشته",
|
||||
"label.last-hours": "لیست {x} ساعت گذشته",
|
||||
"label.logged-in-as": "وارد شده به عنوان {username}",
|
||||
"label.login": "ورود",
|
||||
"label.logout": "خروج",
|
||||
"label.more": "بیشتر",
|
||||
"label.name": "نام",
|
||||
"label.new-password": "رمز جدید",
|
||||
"label.owner": "Owner",
|
||||
"label.owner": "ایجاد شده توسط",
|
||||
"label.password": "رمز",
|
||||
"label.passwords-dont-match": "رمزها یکسان نیستند",
|
||||
"label.profile": "پروفایل",
|
||||
@ -46,12 +46,12 @@
|
||||
"label.refresh": "بهروزرسانی",
|
||||
"label.required": "ضروری",
|
||||
"label.reset": "بازنشانی",
|
||||
"label.reset-website": "Reset statistics",
|
||||
"label.reset-website": "بازنشانی آمار",
|
||||
"label.save": "ذخیره",
|
||||
"label.settings": "تنظیمات",
|
||||
"label.share-url": "به اشتراک گذاری URL",
|
||||
"label.single-day": "یک روز",
|
||||
"label.theme": "Theme",
|
||||
"label.theme": "تم",
|
||||
"label.this-month": "این ماه",
|
||||
"label.this-week": "این هفته",
|
||||
"label.this-year": "امسال",
|
||||
@ -64,7 +64,7 @@
|
||||
"label.websites": "وبسایتها",
|
||||
"message.active-users": "{x} هم اکنون {x, plural, one {یک} other {از میان}}",
|
||||
"message.confirm-delete": "آیا مطمئن هستید میخواهید {target} را حذف کنید?",
|
||||
"message.confirm-reset": "Are your sure you want to reset {target}'s statistics?",
|
||||
"message.confirm-reset": "آیا از بازنشانی آمار {target} مطمئن هستید?",
|
||||
"message.copied": "کپی شد!",
|
||||
"message.delete-warning": "همهی دادههای مرتبط هم حذف خواهد شد.",
|
||||
"message.failure": "مشکلی پیش آمده است.",
|
||||
@ -78,7 +78,7 @@
|
||||
"message.no-websites-configured": "شما هیچ وبسایتی را پیکربندی نکردهاید.",
|
||||
"message.page-not-found": "صفحه یافت نشد.",
|
||||
"message.powered-by": "قدرت گرفته توسط {name}",
|
||||
"message.reset-warning": "All statistics for this website will be deleted, but your tracking code will remain intact.",
|
||||
"message.reset-warning": "تمامی آمارهای این وبسایت حذف خواهد شد اما tracking code بدون تغییر باقی میماند.",
|
||||
"message.save-success": "با موفقیت ذخیره شد.",
|
||||
"message.share-url": "این URL به اشتراک گذاشته شده عمومی برای {target} است.",
|
||||
"message.toggle-charts": "Toggle charts",
|
||||
@ -99,7 +99,7 @@
|
||||
"metrics.filter.combined": "ترکیب شده",
|
||||
"metrics.filter.domain-only": "فقط دامنه",
|
||||
"metrics.filter.raw": "خام",
|
||||
"metrics.languages": "Languages",
|
||||
"metrics.languages": "زبانها",
|
||||
"metrics.operating-systems": "سیستمعاملها",
|
||||
"metrics.page-views": "بازدید صفحه",
|
||||
"metrics.pages": "صفحهها",
|
||||
|
@ -5,7 +5,7 @@
|
||||
"label.administrator": "Administrateur",
|
||||
"label.all": "Tout",
|
||||
"label.all-events": "Tous les événements",
|
||||
"label.all-time": "Toutes périodes",
|
||||
"label.all-time": "Toutes les données",
|
||||
"label.all-websites": "Tous les sites web",
|
||||
"label.back": "Retour",
|
||||
"label.cancel": "Annuler",
|
||||
@ -13,10 +13,10 @@
|
||||
"label.confirm-password": "Confirmation du mot de passe",
|
||||
"label.copy-to-clipboard": "Copier dans le presse papier",
|
||||
"label.current-password": "Mot de passe actuel",
|
||||
"label.custom-range": "Intervalle personnalisé",
|
||||
"label.custom-range": "Période personnalisée",
|
||||
"label.dashboard": "Tableau de bord",
|
||||
"label.date-range": "Intervalle",
|
||||
"label.default-date-range": "Intervalle par défaut",
|
||||
"label.date-range": "Période",
|
||||
"label.default-date-range": "Période par défaut",
|
||||
"label.delete": "Supprimer",
|
||||
"label.delete-account": "Supprimer le compte",
|
||||
"label.delete-website": "Supprimer le site",
|
||||
@ -25,7 +25,7 @@
|
||||
"label.edit": "Modifier",
|
||||
"label.edit-account": "Modifier le compte",
|
||||
"label.edit-website": "Modifier le site",
|
||||
"label.enable-share-url": "Activer le partage d'URL",
|
||||
"label.enable-share-url": "Activer l'URL de partage",
|
||||
"label.invalid": "Invalide",
|
||||
"label.invalid-domain": "Domaine invalide",
|
||||
"label.language": "Langage",
|
||||
@ -68,10 +68,10 @@
|
||||
"message.copied": "Copié !",
|
||||
"message.delete-warning": "Toutes les données associées seront également supprimées.",
|
||||
"message.failure": "Un problème est survenu.",
|
||||
"message.get-share-url": "Obtenez l'URL de partage",
|
||||
"message.get-tracking-code": "Obtenez le code de suivi",
|
||||
"message.get-share-url": "Obtenir l'URL de partage",
|
||||
"message.get-tracking-code": "Obtenir le code de suivi",
|
||||
"message.go-to-settings": "Aller aux paramètres",
|
||||
"message.incorrect-username-password": "nom d'utilisateurs/mot de passe incorrect.",
|
||||
"message.incorrect-username-password": "Nom d'utilisateur/Mot de passe incorrect.",
|
||||
"message.log.visitor": "Visiteur de {country} utilisant {browser} sur {os} {device}",
|
||||
"message.new-version-available": "Une nouvelle version de umami {version} est disponible !",
|
||||
"message.no-data-available": "Pas de données disponibles.",
|
||||
@ -81,7 +81,7 @@
|
||||
"message.reset-warning": "Toutes les statistiques pour ce site seront supprimés, mais votre code de suivi restera intact.",
|
||||
"message.save-success": "Enregistré avec succès.",
|
||||
"message.share-url": "Ceci est l'URL partagée pour {target}.",
|
||||
"message.toggle-charts": "Changer les graphiques",
|
||||
"message.toggle-charts": "Afficher/Masquer les graphiques",
|
||||
"message.track-stats": "Pour suivre les statistiques de {target}, placez le code suivant dans la section {head} de votre site Web.",
|
||||
"message.type-delete": "Tapez {delete} dans la case ci-dessous pour confirmer.",
|
||||
"message.type-reset": "Tapez {reset} dans la case ci-dessous pour confirmer.",
|
||||
@ -98,12 +98,12 @@
|
||||
"metrics.events": "Événements",
|
||||
"metrics.filter.combined": "Combiné",
|
||||
"metrics.filter.domain-only": "Domaine uniquement",
|
||||
"metrics.filter.raw": "Brute",
|
||||
"metrics.filter.raw": "Brut",
|
||||
"metrics.languages": "Langages",
|
||||
"metrics.operating-systems": "Systèmes d'exploitation",
|
||||
"metrics.page-views": "Pages vues",
|
||||
"metrics.pages": "Pages",
|
||||
"metrics.referrers": "URL Référentes",
|
||||
"metrics.referrers": "Sources",
|
||||
"metrics.unique-visitors": "Visiteurs uniques",
|
||||
"metrics.views": "Vues",
|
||||
"metrics.visitors": "Visiteurs"
|
||||
|
110
lang/ga-ES.json
Normal file
110
lang/ga-ES.json
Normal file
@ -0,0 +1,110 @@
|
||||
{
|
||||
"label.accounts": "Contas",
|
||||
"label.add-account": "Engadir conta",
|
||||
"label.add-website": "Engadir sitio web",
|
||||
"label.administrator": "Administradora",
|
||||
"label.all": "Todo",
|
||||
"label.all-events": "Tódolos eventos",
|
||||
"label.all-time": "Sempre",
|
||||
"label.all-websites": "Tódolos sitios web",
|
||||
"label.back": "Atrás",
|
||||
"label.cancel": "Cancelar",
|
||||
"label.change-password": "Mudar contrasinal",
|
||||
"label.confirm-password": "Confirmar contrasinal",
|
||||
"label.copy-to-clipboard": "Copiar ao portapapeis",
|
||||
"label.current-password": "Contrasinal actual",
|
||||
"label.custom-range": "Rango personalizado",
|
||||
"label.dashboard": "Taboleiro",
|
||||
"label.date-range": "Rango temporal",
|
||||
"label.default-date-range": "Rango temporal por defecto",
|
||||
"label.delete": "Eliminar",
|
||||
"label.delete-account": "Eliminar conta",
|
||||
"label.delete-website": "Eliminar sitio web",
|
||||
"label.dismiss": "Desbotar",
|
||||
"label.domain": "Dominio",
|
||||
"label.edit": "Editar",
|
||||
"label.edit-account": "Editar conta",
|
||||
"label.edit-website": "Editar sitio web",
|
||||
"label.enable-share-url": "Activar URL de compartición",
|
||||
"label.invalid": "Non válido",
|
||||
"label.invalid-domain": "Dominio non válido",
|
||||
"label.language": "Idioma",
|
||||
"label.last-days": "Últimos {x} días",
|
||||
"label.last-hours": "Últimas {x} horas",
|
||||
"label.logged-in-as": "Sesión de {username}",
|
||||
"label.login": "Acceder",
|
||||
"label.logout": "Pechar sesión",
|
||||
"label.more": "Máis",
|
||||
"label.name": "Nome",
|
||||
"label.new-password": "Novo contrasinal",
|
||||
"label.owner": "Dona",
|
||||
"label.password": "Contrasinal",
|
||||
"label.passwords-dont-match": "Non concordan os contrasinais",
|
||||
"label.profile": "Perfil",
|
||||
"label.realtime": "Agora mesmo",
|
||||
"label.realtime-logs": "Rexistro neste intre",
|
||||
"label.refresh": "Actualizar",
|
||||
"label.required": "Requerido",
|
||||
"label.reset": "Restablecer",
|
||||
"label.reset-website": "Restablecer estatísticas",
|
||||
"label.save": "Gardar",
|
||||
"label.settings": "Axustes",
|
||||
"label.share-url": "Compartir URL",
|
||||
"label.single-day": "Un só día",
|
||||
"label.theme": "Decorado",
|
||||
"label.this-month": "Este mes",
|
||||
"label.this-week": "Esta semana",
|
||||
"label.this-year": "Este ano",
|
||||
"label.timezone": "Zona horaria",
|
||||
"label.today": "Hoxe",
|
||||
"label.tracking-code": "Código de seguimento",
|
||||
"label.unknown": "Descoñecido",
|
||||
"label.username": "Identificador",
|
||||
"label.view-details": "Ver detalles",
|
||||
"label.websites": "Sitios web",
|
||||
"message.active-users": "{x} actual {x, plural, one {visitante} other {visitantes}}",
|
||||
"message.confirm-delete": "Tes a certeza de querer eliminar {target}?",
|
||||
"message.confirm-reset": "Tes a certeza de querer restablecer as estatísticas de {target}?",
|
||||
"message.copied": "Copiado!",
|
||||
"message.delete-warning": "Tamén serán borrados tódolos datos asociados.",
|
||||
"message.failure": "Houbo un fallo.",
|
||||
"message.get-share-url": "Obter URL de compartición",
|
||||
"message.get-tracking-code": "Obter código de seguimento",
|
||||
"message.go-to-settings": "Ir aos axustes",
|
||||
"message.incorrect-username-password": "Credenciais incorrectas.",
|
||||
"message.log.visitor": "Visitante desde {country} usando {browser} en {os} {device}",
|
||||
"message.new-version-available": "A nova versión {version} de umami está dispoñible!",
|
||||
"message.no-data-available": "Sen datos dispoñibles.",
|
||||
"message.no-websites-configured": "Non tes sitios web configurados.",
|
||||
"message.page-not-found": "Páxina non atopada.",
|
||||
"message.powered-by": "Funciona grazas a {name}",
|
||||
"message.reset-warning": "Vanse eliminar tódalas estatísticas deste sitio web, pero o código de seguimento permanecerá sen cambios.",
|
||||
"message.save-success": "Gardouse correctamente.",
|
||||
"message.share-url": "Este é o URL da compartición pública de {target}.",
|
||||
"message.toggle-charts": "Activación das gráficas",
|
||||
"message.track-stats": "Para crear estatísticas de {target}, pon este código na sección {head} do teu sitio web.",
|
||||
"message.type-delete": "Escribe {delete} na caixa inferior para confirmar.",
|
||||
"message.type-reset": "Escribe {reset} na caixa inferior para confirmar.",
|
||||
"metrics.actions": "Accións",
|
||||
"metrics.average-visit-time": "Tempo medio de visita",
|
||||
"metrics.bounce-rate": "Proporción de rebote",
|
||||
"metrics.browsers": "Navegadores",
|
||||
"metrics.countries": "Países",
|
||||
"metrics.device.desktop": "Escritorio",
|
||||
"metrics.device.laptop": "Portátil",
|
||||
"metrics.device.mobile": "Móbil",
|
||||
"metrics.device.tablet": "Tableta",
|
||||
"metrics.devices": "Dispositivos",
|
||||
"metrics.events": "Eventos",
|
||||
"metrics.filter.combined": "Combinado",
|
||||
"metrics.filter.domain-only": "Só dominio",
|
||||
"metrics.filter.raw": "Raw",
|
||||
"metrics.languages": "Idiomas",
|
||||
"metrics.operating-systems": "Sistemas operativos",
|
||||
"metrics.page-views": "Vistas de páxinas",
|
||||
"metrics.pages": "Páxinas",
|
||||
"metrics.referrers": "Orixes",
|
||||
"metrics.unique-visitors": "Visitas únicas",
|
||||
"metrics.views": "Visualizacións",
|
||||
"metrics.visitors": "Visitantes"
|
||||
}
|
@ -5,7 +5,7 @@
|
||||
"label.administrator": "Админ",
|
||||
"label.all": "Бүх",
|
||||
"label.all-events": "Бүх үйл явдал",
|
||||
"label.all-time": "All time",
|
||||
"label.all-time": "Бүх цаг үеийн",
|
||||
"label.all-websites": "Бүх вебүүд",
|
||||
"label.back": "Буцах",
|
||||
"label.cancel": "Цуцлах",
|
||||
@ -28,7 +28,7 @@
|
||||
"label.enable-share-url": "Хуваалцах холбоос идэвхжүүлэх",
|
||||
"label.invalid": "Буруу",
|
||||
"label.invalid-domain": "Буруу домэйн",
|
||||
"label.language": "Language",
|
||||
"label.language": "Хэл",
|
||||
"label.last-days": "Сүүлийн {x} хоног",
|
||||
"label.last-hours": "Сүүлийн {x} цаг",
|
||||
"label.logged-in-as": "{username}-р нэвтэрсэн",
|
||||
@ -37,7 +37,7 @@
|
||||
"label.more": "Цааш",
|
||||
"label.name": "Нэр",
|
||||
"label.new-password": "Шинэ нууц үг",
|
||||
"label.owner": "Owner",
|
||||
"label.owner": "Эзэмшигч",
|
||||
"label.password": "Нууц үг",
|
||||
"label.passwords-dont-match": "Нууц үг тохирохгүй байна",
|
||||
"label.profile": "Бүртгэл",
|
||||
@ -46,12 +46,12 @@
|
||||
"label.refresh": "Сэргээх",
|
||||
"label.required": "Шаардлагатай",
|
||||
"label.reset": "Хуучин хэвд нь оруулах",
|
||||
"label.reset-website": "Reset statistics",
|
||||
"label.reset-website": "Тоон үзүүлэлтийг дахин эхлүүлэх",
|
||||
"label.save": "Хадгалах",
|
||||
"label.settings": "Тохиргоо",
|
||||
"label.share-url": "Хуваалцах холбоос",
|
||||
"label.single-day": "Нэг өдөр",
|
||||
"label.theme": "Theme",
|
||||
"label.theme": "Загвар",
|
||||
"label.this-month": "Энэ сар",
|
||||
"label.this-week": "Энэ долоо хоног",
|
||||
"label.this-year": "Энэ жил",
|
||||
@ -78,10 +78,10 @@
|
||||
"message.no-websites-configured": "Та ямар нэгэн веб тохируулаагүй байна.",
|
||||
"message.page-not-found": "Хуудас олдсонгүй.",
|
||||
"message.powered-by": "{name} дээр суурилсан",
|
||||
"message.reset-warning": "All statistics for this website will be deleted, but your tracking code will remain intact.",
|
||||
"message.reset-warning": "Энэ вебийн бүх тоон үзүүлэлтүүдийг устгах болно. Гэхдээ мөрдөх код хэвэндээ үлдэнэ.",
|
||||
"message.save-success": "Амжилттай хадгаллаа.",
|
||||
"message.share-url": "{target}-г нийтэд хуваалцах холбоос.",
|
||||
"message.toggle-charts": "Toggle charts",
|
||||
"message.toggle-charts": "Графикийг харуулах/нуух",
|
||||
"message.track-stats": "{target} вебийн статистикийг бүртгэхийн тулд доорх кодыг вебийнхээ {head} хэсэгт байрлуулна уу.",
|
||||
"message.type-delete": "Доорх хэсэгт {delete} гэж бичиж баталгаажуулна уу.",
|
||||
"message.type-reset": "Доорх хэсэгт {reset} гэж бичиж баталгаажуулна уу.",
|
||||
@ -99,7 +99,7 @@
|
||||
"metrics.filter.combined": "Нэгтгэсэн",
|
||||
"metrics.filter.domain-only": "Зөвхөн домэйн",
|
||||
"metrics.filter.raw": "Түүхий",
|
||||
"metrics.languages": "Languages",
|
||||
"metrics.languages": "Хэл",
|
||||
"metrics.operating-systems": "Үйлдлийн систем",
|
||||
"metrics.page-views": "Хуудас үзсэн",
|
||||
"metrics.pages": "Хуудас",
|
||||
|
@ -4,8 +4,8 @@
|
||||
"label.add-website": "Adicionar site",
|
||||
"label.administrator": "Administrador",
|
||||
"label.all": "Todos",
|
||||
"label.all-events": "All events",
|
||||
"label.all-time": "All time",
|
||||
"label.all-events": "Todos os eventos",
|
||||
"label.all-time": "Todo o período",
|
||||
"label.all-websites": "Todos os sites",
|
||||
"label.back": "Voltar",
|
||||
"label.cancel": "Cancelar",
|
||||
@ -28,7 +28,7 @@
|
||||
"label.enable-share-url": "Ativar link de compartilhamento",
|
||||
"label.invalid": "Inválido",
|
||||
"label.invalid-domain": "Domínio inválido",
|
||||
"label.language": "Language",
|
||||
"label.language": "Idioma",
|
||||
"label.last-days": "Últimos {x} dias",
|
||||
"label.last-hours": "Últimas {x} horas",
|
||||
"label.logged-in-as": "Sessão iniciada como {username}",
|
||||
@ -37,7 +37,7 @@
|
||||
"label.more": "Mais",
|
||||
"label.name": "Nome",
|
||||
"label.new-password": "Nova senha",
|
||||
"label.owner": "Owner",
|
||||
"label.owner": "Proprietário",
|
||||
"label.password": "Senha",
|
||||
"label.passwords-dont-match": "As senhas não correspondem",
|
||||
"label.profile": "Perfil",
|
||||
@ -46,12 +46,12 @@
|
||||
"label.refresh": "Atualizar",
|
||||
"label.required": "Obrigatório",
|
||||
"label.reset": "Redefinir",
|
||||
"label.reset-website": "Reset statistics",
|
||||
"label.reset-website": "Redefinir estatísticas",
|
||||
"label.save": "Salvar",
|
||||
"label.settings": "Configurações",
|
||||
"label.share-url": "Link de compartilhamento",
|
||||
"label.single-day": "Dia específico",
|
||||
"label.theme": "Theme",
|
||||
"label.theme": "Tema",
|
||||
"label.this-month": "Este mês",
|
||||
"label.this-week": "Esta semana",
|
||||
"label.this-year": "Este ano",
|
||||
@ -64,7 +64,7 @@
|
||||
"label.websites": "Sites",
|
||||
"message.active-users": "{x} {x, plural, one {visitante} other {visitantes}} neste momento",
|
||||
"message.confirm-delete": "Deseja realmente remover {target}?",
|
||||
"message.confirm-reset": "Are your sure you want to reset {target}'s statistics?",
|
||||
"message.confirm-reset": "Você tem certeza que deseja redefinir as estatísticas de {target}?",
|
||||
"message.copied": "Copiado!",
|
||||
"message.delete-warning": "Todos os dados associados também serão eliminados.",
|
||||
"message.failure": "Ocorreu um erro.",
|
||||
@ -78,10 +78,10 @@
|
||||
"message.no-websites-configured": "Nenhum site foi configurado ainda.",
|
||||
"message.page-not-found": "Página não encontrada.",
|
||||
"message.powered-by": "Distribuído por {name}",
|
||||
"message.reset-warning": "All statistics for this website will be deleted, but your tracking code will remain intact.",
|
||||
"message.reset-warning": "Todas as estatísticas deste site serão removidas, mas seu código de rastreamento permanecerá intacto.",
|
||||
"message.save-success": "Salvo com sucesso.",
|
||||
"message.share-url": "Este é o link público de compartilhamento para {target}.",
|
||||
"message.toggle-charts": "Toggle charts",
|
||||
"message.toggle-charts": "Mostrar/Esconder gráficos",
|
||||
"message.track-stats": "Para gerar estatística para {target}, coloque o seguinte código no {head} do html do seu site.",
|
||||
"message.type-delete": "Escreva {delete} abaixo para continuar.",
|
||||
"message.type-reset": "Escreva {reset} abaixo para continuar.",
|
||||
@ -99,7 +99,7 @@
|
||||
"metrics.filter.combined": "Combinado",
|
||||
"metrics.filter.domain-only": "Apenas domínio",
|
||||
"metrics.filter.raw": "Dados brutos",
|
||||
"metrics.languages": "Languages",
|
||||
"metrics.languages": "Idiomas",
|
||||
"metrics.operating-systems": "Sistemas operacionais",
|
||||
"metrics.page-views": "Visualizações de página",
|
||||
"metrics.pages": "Páginas",
|
||||
|
@ -2,11 +2,11 @@
|
||||
"label.accounts": "Tài khoản",
|
||||
"label.add-account": "Thêm tài khoản",
|
||||
"label.add-website": "Thêm website",
|
||||
"label.administrator": "Quản Trị",
|
||||
"label.administrator": "Quản trị",
|
||||
"label.all": "Tất cả",
|
||||
"label.all-events": "Tất cả events",
|
||||
"label.all-time": "All time",
|
||||
"label.all-websites": "Tất cả websites",
|
||||
"label.all-events": "Tất cả sự kiện",
|
||||
"label.all-time": "Toàn thời gian",
|
||||
"label.all-websites": "Tất cả website",
|
||||
"label.back": "Quay về",
|
||||
"label.cancel": "Huỷ bỏ",
|
||||
"label.change-password": "Đổi mật khẩu",
|
||||
@ -16,7 +16,7 @@
|
||||
"label.custom-range": "Phạm vi ngày tuỳ chọn",
|
||||
"label.dashboard": "Bảng điều khiển",
|
||||
"label.date-range": "Phạm vi ngày",
|
||||
"label.default-date-range": "Phạm vi ngày mặc định",
|
||||
"label.default-date-range": "Khoảng thời gian mặc định",
|
||||
"label.delete": "Xoá",
|
||||
"label.delete-account": "Xoá tài khoản",
|
||||
"label.delete-website": "Xáo website",
|
||||
@ -37,7 +37,7 @@
|
||||
"label.more": "Thêm",
|
||||
"label.name": "Tên",
|
||||
"label.new-password": "Mật khẩu mới",
|
||||
"label.owner": "Owner",
|
||||
"label.owner": "Chủ nhân",
|
||||
"label.password": "Mật khẩu",
|
||||
"label.passwords-dont-match": "Mật khẩu không đồng nhất",
|
||||
"label.profile": "Hồ sơ",
|
||||
@ -81,7 +81,7 @@
|
||||
"message.reset-warning": "Tất cả số liệu thống kê của website này sẽ bị xoá, nhưng mã theo dõi sẽ vẫn giữ nguyên.",
|
||||
"message.save-success": "Đã lưu thành công.",
|
||||
"message.share-url": "Đây là đường dẫn URL cho {target}.",
|
||||
"message.toggle-charts": "Toggle charts",
|
||||
"message.toggle-charts": "Bật/tắt biểu đồ",
|
||||
"message.track-stats": "Để theo dõi {target}, dán mã theo dõi vào {head} của website bạn.",
|
||||
"message.type-delete": "Nhập {delete} bên dưới để xác nhận.",
|
||||
"message.type-reset": "Nhập {reset} bên dưới để xác nhận.",
|
||||
@ -99,12 +99,12 @@
|
||||
"metrics.filter.combined": "Kết hợp",
|
||||
"metrics.filter.domain-only": "Chỉ tên miền",
|
||||
"metrics.filter.raw": "Gốc",
|
||||
"metrics.languages": "Languages",
|
||||
"metrics.languages": "Ngôn ngũ",
|
||||
"metrics.operating-systems": "Hệ điều hành",
|
||||
"metrics.page-views": "Lượt xem",
|
||||
"metrics.pages": "Trang",
|
||||
"metrics.referrers": "Liên kết giới thiệu",
|
||||
"metrics.unique-visitors": "Khách truy cập duy nhất",
|
||||
"metrics.unique-visitors": "Khách truy cập một lần",
|
||||
"metrics.views": "Xem",
|
||||
"metrics.visitors": "Khách"
|
||||
}
|
||||
|
10
lib/db.js
10
lib/db.js
@ -11,23 +11,23 @@ const options = {
|
||||
};
|
||||
|
||||
function logQuery(e) {
|
||||
if (process.env.LOG_QUERY) {
|
||||
console.log(chalk.yellow(e.params), '->', e.query, chalk.greenBright(`${e.duration}ms`));
|
||||
}
|
||||
console.log(chalk.yellow(e.params), '->', e.query, chalk.greenBright(`${e.duration}ms`));
|
||||
}
|
||||
|
||||
let prisma;
|
||||
|
||||
if (process.env.NODE_ENV === 'production') {
|
||||
prisma = new PrismaClient(options);
|
||||
prisma.$on('query', logQuery);
|
||||
} else {
|
||||
if (!global.prisma) {
|
||||
global.prisma = new PrismaClient(options);
|
||||
global.prisma.$on('query', logQuery);
|
||||
}
|
||||
|
||||
prisma = global.prisma;
|
||||
}
|
||||
|
||||
if (process.env.LOG_QUERY) {
|
||||
prisma.$on('query', logQuery);
|
||||
}
|
||||
|
||||
export default prisma;
|
||||
|
@ -53,6 +53,7 @@ export const languages = {
|
||||
'fa-IR': { label: 'فارسی', dateLocale: faIR, dir: 'rtl' },
|
||||
'fo-FO': { label: 'Føroyskt' },
|
||||
'fr-FR': { label: 'Français', dateLocale: fr },
|
||||
'ga-ES': { label: 'Galacian (Spain)', dateLocale: es },
|
||||
'el-GR': { label: 'Ελληνικά', dateLocale: el },
|
||||
'he-IL': { label: 'עברית', dateLocale: he },
|
||||
'hi-IN': { label: 'हिन्दी', dateLocale: hi },
|
||||
|
@ -315,6 +315,13 @@ export async function getAccounts() {
|
||||
username: 'asc',
|
||||
},
|
||||
],
|
||||
select: {
|
||||
user_id: true,
|
||||
username: true,
|
||||
is_admin: true,
|
||||
created_at: true,
|
||||
updated_at: true,
|
||||
},
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
@ -3,7 +3,9 @@ const pkg = require('./package.json');
|
||||
|
||||
module.exports = {
|
||||
env: {
|
||||
VERSION: pkg.version,
|
||||
currentVersion: pkg.version,
|
||||
loginDisabled: process.env.DISABLE_LOGIN,
|
||||
updatesDisabled: process.env.DISABLE_UPDATES,
|
||||
},
|
||||
basePath: process.env.BASE_PATH,
|
||||
experimental: {
|
||||
|
26
package.json
26
package.json
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "umami",
|
||||
"version": "1.32.0",
|
||||
"version": "1.33.0",
|
||||
"description": "A simple, fast, privacy-focused alternative to Google Analytics.",
|
||||
"author": "Mike Cao <mike@mikecao.com>",
|
||||
"license": "MIT",
|
||||
@ -12,20 +12,21 @@
|
||||
"scripts": {
|
||||
"dev": "next dev",
|
||||
"build": "npm-run-all build-tracker build-geo build-db build-app",
|
||||
"start": "next start",
|
||||
"start": "npm-run-all check-db start-next",
|
||||
"start-docker": "npm-run-all check-db start-server",
|
||||
"start-env": "node -r dotenv/config scripts/start-env.js",
|
||||
"start-server": "node server.js",
|
||||
"start-next": "next start",
|
||||
"build-app": "next build",
|
||||
"build-tracker": "rollup -c rollup.tracker.config.js",
|
||||
"build-db": "npm-run-all copy-db-schema build-db-client",
|
||||
"build-db": "npm-run-all copy-db-files build-db-client",
|
||||
"build-lang": "npm-run-all format-lang compile-lang",
|
||||
"build-geo": "node scripts/build-geo.js",
|
||||
"build-db-schema": "dotenv prisma introspect",
|
||||
"build-db-client": "dotenv prisma generate",
|
||||
"build-mysql-schema": "dotenv prisma db pull -- --schema=./prisma/schema.mysql.prisma",
|
||||
"build-mysql-client": "dotenv prisma generate -- --schema=./prisma/schema.mysql.prisma",
|
||||
"build-postgresql-schema": "dotenv prisma db pull -- --schema=./prisma/schema.postgresql.prisma",
|
||||
"build-postgresql-client": "dotenv prisma generate -- --schema=./prisma/schema.postgresql.prisma",
|
||||
"copy-db-schema": "node scripts/copy-db-schema.js",
|
||||
"build-db-schema": "prisma db pull",
|
||||
"build-db-client": "prisma generate",
|
||||
"update-db": "prisma migrate deploy",
|
||||
"check-db": "node scripts/check-db.js",
|
||||
"copy-db-files": "node scripts/copy-db-files.js",
|
||||
"generate-lang": "npm-run-all extract-lang merge-lang",
|
||||
"extract-lang": "formatjs extract \"{pages,components}/**/*.js\" --out-file build/messages.json",
|
||||
"merge-lang": "node scripts/merge-lang.js",
|
||||
@ -54,13 +55,14 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@fontsource/inter": "4.5.7",
|
||||
"@prisma/client": "3.14.0",
|
||||
"@prisma/client": "3.15.2",
|
||||
"bcryptjs": "^2.4.3",
|
||||
"chalk": "^4.1.1",
|
||||
"chart.js": "^2.9.4",
|
||||
"classnames": "^2.3.1",
|
||||
"colord": "^2.9.2",
|
||||
"cors": "^2.8.5",
|
||||
"cross-spawn": "^7.0.3",
|
||||
"date-fns": "^2.23.0",
|
||||
"date-fns-tz": "^1.1.4",
|
||||
"del": "^6.0.0",
|
||||
@ -115,7 +117,7 @@
|
||||
"postcss-preset-env": "7.4.3",
|
||||
"postcss-rtlcss": "^3.6.1",
|
||||
"prettier": "^2.6.2",
|
||||
"prisma": "3.14.0",
|
||||
"prisma": "3.15.2",
|
||||
"prompts": "2.4.2",
|
||||
"rollup": "^2.70.1",
|
||||
"rollup-plugin-terser": "^7.0.2",
|
||||
|
@ -15,12 +15,6 @@ function customScriptName(req) {
|
||||
}
|
||||
}
|
||||
|
||||
function disableLogin(req) {
|
||||
if (process.env.DISABLE_LOGIN && req.nextUrl.pathname.endsWith('/login')) {
|
||||
return new Response('Login is disabled', { status: 403 });
|
||||
}
|
||||
}
|
||||
|
||||
function forceSSL(req, res) {
|
||||
if (process.env.FORCE_SSL && req.nextUrl.protocol === 'http:') {
|
||||
res.headers.set('Strict-Transport-Security', 'max-age=31536000; includeSubDomains');
|
||||
@ -30,7 +24,7 @@ function forceSSL(req, res) {
|
||||
}
|
||||
|
||||
export function middleware(req) {
|
||||
const fns = [customScriptName, disableLogin];
|
||||
const fns = [customScriptName];
|
||||
|
||||
for (const fn of fns) {
|
||||
const res = fn(req);
|
||||
|
@ -1,9 +1,10 @@
|
||||
const { Resolver } = require('dns').promises;
|
||||
import isbot from 'isbot';
|
||||
import ipaddr from 'ipaddr.js';
|
||||
import { savePageView, saveEvent } from 'lib/queries';
|
||||
import { useCors, useSession } from 'lib/middleware';
|
||||
import { getJsonBody, getIpAddress } from 'lib/request';
|
||||
import { ok, send, badRequest } from 'lib/response';
|
||||
import { ok, send, badRequest, forbidden } from 'lib/response';
|
||||
import { createToken } from 'lib/crypto';
|
||||
import { removeTrailingSlash } from 'lib/url';
|
||||
|
||||
@ -15,16 +16,35 @@ export default async (req, res) => {
|
||||
}
|
||||
|
||||
const ignoreIps = process.env.IGNORE_IP;
|
||||
if (ignoreIps) {
|
||||
const ips = ignoreIps.split(',').map(n => n.trim());
|
||||
const ip = getIpAddress(req);
|
||||
const blocked = ips.find(i => {
|
||||
if (i === ip) return true;
|
||||
const ignoreHostnames = process.env.IGNORE_HOSTNAME;
|
||||
|
||||
if (ignoreIps || ignoreHostnames) {
|
||||
const ips = [];
|
||||
|
||||
if (ignoreIps) {
|
||||
ips.push(...ignoreIps.split(',').map(n => n.trim()));
|
||||
}
|
||||
|
||||
if (ignoreHostnames) {
|
||||
const resolver = new Resolver();
|
||||
const promises = ignoreHostnames
|
||||
.split(',')
|
||||
.map(n => resolver.resolve4(n.trim()).catch(() => {}));
|
||||
|
||||
await Promise.all(promises).then(resolvedIps => {
|
||||
ips.push(...resolvedIps.filter(n => n).flatMap(n => n));
|
||||
});
|
||||
}
|
||||
|
||||
const clientIp = getIpAddress(req);
|
||||
|
||||
const blocked = ips.find(ip => {
|
||||
if (ip === clientIp) return true;
|
||||
|
||||
// CIDR notation
|
||||
if (i.indexOf('/') > 0) {
|
||||
const addr = ipaddr.parse(ip);
|
||||
const range = ipaddr.parseCIDR(i);
|
||||
if (ip.indexOf('/') > 0) {
|
||||
const addr = ipaddr.parse(clientIp);
|
||||
const range = ipaddr.parseCIDR(ip);
|
||||
|
||||
if (addr.kind() === range[0].kind() && addr.match(range)) return true;
|
||||
}
|
||||
@ -33,7 +53,7 @@ export default async (req, res) => {
|
||||
});
|
||||
|
||||
if (blocked) {
|
||||
return ok(res);
|
||||
return forbidden(res);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3,7 +3,7 @@ import Layout from 'components/layout/Layout';
|
||||
import LoginForm from 'components/forms/LoginForm';
|
||||
|
||||
export default function LoginPage() {
|
||||
if (process.env.DISABLE_LOGIN) {
|
||||
if (process.env.loginDisabled) {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
@ -1 +0,0 @@
|
||||
../schema.mysql.prisma
|
@ -1 +0,0 @@
|
||||
../schema.postgresql.prisma
|
@ -1,29 +0,0 @@
|
||||
const bcrypt = require('bcryptjs');
|
||||
const { PrismaClient } = require('@prisma/client');
|
||||
const prisma = new PrismaClient();
|
||||
const SALT_ROUNDS = 10;
|
||||
|
||||
const hashPassword = password => {
|
||||
return bcrypt.hashSync(password, SALT_ROUNDS);
|
||||
};
|
||||
|
||||
async function main() {
|
||||
await prisma.account.upsert({
|
||||
where: { username: 'admin' },
|
||||
update: {},
|
||||
create: {
|
||||
username: 'admin',
|
||||
password: hashPassword(process.env.ADMIN_PASSWORD || 'umami'),
|
||||
is_admin: true,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
main()
|
||||
.catch(e => {
|
||||
console.error(e);
|
||||
process.exit(1);
|
||||
})
|
||||
.finally(async () => {
|
||||
await prisma.$disconnect();
|
||||
});
|
1
public/intl/country/ga-ES.json
Normal file
1
public/intl/country/ga-ES.json
Normal file
@ -0,0 +1 @@
|
||||
404: Not Found
|
1
public/intl/language/ga-ES.json
Normal file
1
public/intl/language/ga-ES.json
Normal file
@ -0,0 +1 @@
|
||||
404: Not Found
|
@ -38,7 +38,7 @@
|
||||
"label.all-time": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "All time"
|
||||
"value": "همه زمان"
|
||||
}
|
||||
],
|
||||
"label.all-websites": [
|
||||
@ -176,7 +176,7 @@
|
||||
"label.language": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Language"
|
||||
"value": "زبان"
|
||||
}
|
||||
],
|
||||
"label.last-days": [
|
||||
@ -190,7 +190,7 @@
|
||||
},
|
||||
{
|
||||
"type": 0,
|
||||
"value": " روز"
|
||||
"value": " روز گذشته"
|
||||
}
|
||||
],
|
||||
"label.last-hours": [
|
||||
@ -204,7 +204,7 @@
|
||||
},
|
||||
{
|
||||
"type": 0,
|
||||
"value": " ساعت"
|
||||
"value": " ساعت گذشته"
|
||||
}
|
||||
],
|
||||
"label.logged-in-as": [
|
||||
@ -250,7 +250,7 @@
|
||||
"label.owner": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Owner"
|
||||
"value": "ایجاد شده توسط"
|
||||
}
|
||||
],
|
||||
"label.password": [
|
||||
@ -304,7 +304,7 @@
|
||||
"label.reset-website": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Reset statistics"
|
||||
"value": "بازنشانی آمار"
|
||||
}
|
||||
],
|
||||
"label.save": [
|
||||
@ -334,7 +334,7 @@
|
||||
"label.theme": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Theme"
|
||||
"value": "تم"
|
||||
}
|
||||
],
|
||||
"label.this-month": [
|
||||
@ -448,7 +448,7 @@
|
||||
"message.confirm-reset": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Are your sure you want to reset "
|
||||
"value": "آیا از بازنشانی آمار "
|
||||
},
|
||||
{
|
||||
"type": 1,
|
||||
@ -456,7 +456,7 @@
|
||||
},
|
||||
{
|
||||
"type": 0,
|
||||
"value": "'s statistics?"
|
||||
"value": " مطمئن هستید?"
|
||||
}
|
||||
],
|
||||
"message.copied": [
|
||||
@ -580,7 +580,7 @@
|
||||
"message.reset-warning": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "All statistics for this website will be deleted, but your tracking code will remain intact."
|
||||
"value": "تمامی آمارهای این وبسایت حذف خواهد شد اما tracking code بدون تغییر باقی میماند."
|
||||
}
|
||||
],
|
||||
"message.save-success": [
|
||||
@ -730,7 +730,7 @@
|
||||
"metrics.languages": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Languages"
|
||||
"value": "زبانها"
|
||||
}
|
||||
],
|
||||
"metrics.operating-systems": [
|
||||
|
@ -38,7 +38,7 @@
|
||||
"label.all-time": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Toutes périodes"
|
||||
"value": "Toutes les données"
|
||||
}
|
||||
],
|
||||
"label.all-websites": [
|
||||
@ -86,7 +86,7 @@
|
||||
"label.custom-range": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Intervalle personnalisé"
|
||||
"value": "Période personnalisée"
|
||||
}
|
||||
],
|
||||
"label.dashboard": [
|
||||
@ -98,13 +98,13 @@
|
||||
"label.date-range": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Intervalle"
|
||||
"value": "Période"
|
||||
}
|
||||
],
|
||||
"label.default-date-range": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Intervalle par défaut"
|
||||
"value": "Période par défaut"
|
||||
}
|
||||
],
|
||||
"label.delete": [
|
||||
@ -158,7 +158,7 @@
|
||||
"label.enable-share-url": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Activer le partage d'URL"
|
||||
"value": "Activer l'URL de partage"
|
||||
}
|
||||
],
|
||||
"label.invalid": [
|
||||
@ -476,13 +476,13 @@
|
||||
"message.get-share-url": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Obtenez l'URL de partage"
|
||||
"value": "Obtenir l'URL de partage"
|
||||
}
|
||||
],
|
||||
"message.get-tracking-code": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Obtenez le code de suivi"
|
||||
"value": "Obtenir le code de suivi"
|
||||
}
|
||||
],
|
||||
"message.go-to-settings": [
|
||||
@ -494,7 +494,7 @@
|
||||
"message.incorrect-username-password": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "nom d'utilisateurs/mot de passe incorrect."
|
||||
"value": "Nom d'utilisateur/Mot de passe incorrect."
|
||||
}
|
||||
],
|
||||
"message.log.visitor": [
|
||||
@ -602,7 +602,7 @@
|
||||
"message.toggle-charts": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Changer les graphiques"
|
||||
"value": "Afficher/Masquer les graphiques"
|
||||
}
|
||||
],
|
||||
"message.track-stats": [
|
||||
@ -736,7 +736,7 @@
|
||||
"metrics.filter.raw": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Brute"
|
||||
"value": "Brut"
|
||||
}
|
||||
],
|
||||
"metrics.languages": [
|
||||
@ -766,7 +766,7 @@
|
||||
"metrics.referrers": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "URL Référentes"
|
||||
"value": "Sources"
|
||||
}
|
||||
],
|
||||
"metrics.unique-visitors": [
|
||||
|
794
public/intl/messages/ga-ES.json
Normal file
794
public/intl/messages/ga-ES.json
Normal file
@ -0,0 +1,794 @@
|
||||
{
|
||||
"label.accounts": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Contas"
|
||||
}
|
||||
],
|
||||
"label.add-account": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Engadir conta"
|
||||
}
|
||||
],
|
||||
"label.add-website": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Engadir sitio web"
|
||||
}
|
||||
],
|
||||
"label.administrator": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Administradora"
|
||||
}
|
||||
],
|
||||
"label.all": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Todo"
|
||||
}
|
||||
],
|
||||
"label.all-events": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Tódolos eventos"
|
||||
}
|
||||
],
|
||||
"label.all-time": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Sempre"
|
||||
}
|
||||
],
|
||||
"label.all-websites": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Tódolos sitios web"
|
||||
}
|
||||
],
|
||||
"label.back": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Atrás"
|
||||
}
|
||||
],
|
||||
"label.cancel": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Cancelar"
|
||||
}
|
||||
],
|
||||
"label.change-password": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Mudar contrasinal"
|
||||
}
|
||||
],
|
||||
"label.confirm-password": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Confirmar contrasinal"
|
||||
}
|
||||
],
|
||||
"label.copy-to-clipboard": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Copiar ao portapapeis"
|
||||
}
|
||||
],
|
||||
"label.current-password": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Contrasinal actual"
|
||||
}
|
||||
],
|
||||
"label.custom-range": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Rango personalizado"
|
||||
}
|
||||
],
|
||||
"label.dashboard": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Taboleiro"
|
||||
}
|
||||
],
|
||||
"label.date-range": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Rango temporal"
|
||||
}
|
||||
],
|
||||
"label.default-date-range": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Rango temporal por defecto"
|
||||
}
|
||||
],
|
||||
"label.delete": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Eliminar"
|
||||
}
|
||||
],
|
||||
"label.delete-account": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Eliminar conta"
|
||||
}
|
||||
],
|
||||
"label.delete-website": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Eliminar sitio web"
|
||||
}
|
||||
],
|
||||
"label.dismiss": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Desbotar"
|
||||
}
|
||||
],
|
||||
"label.domain": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Dominio"
|
||||
}
|
||||
],
|
||||
"label.edit": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Editar"
|
||||
}
|
||||
],
|
||||
"label.edit-account": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Editar conta"
|
||||
}
|
||||
],
|
||||
"label.edit-website": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Editar sitio web"
|
||||
}
|
||||
],
|
||||
"label.enable-share-url": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Activar URL de compartición"
|
||||
}
|
||||
],
|
||||
"label.invalid": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Non válido"
|
||||
}
|
||||
],
|
||||
"label.invalid-domain": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Dominio non válido"
|
||||
}
|
||||
],
|
||||
"label.language": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Idioma"
|
||||
}
|
||||
],
|
||||
"label.last-days": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Últimos "
|
||||
},
|
||||
{
|
||||
"type": 1,
|
||||
"value": "x"
|
||||
},
|
||||
{
|
||||
"type": 0,
|
||||
"value": " días"
|
||||
}
|
||||
],
|
||||
"label.last-hours": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Últimas "
|
||||
},
|
||||
{
|
||||
"type": 1,
|
||||
"value": "x"
|
||||
},
|
||||
{
|
||||
"type": 0,
|
||||
"value": " horas"
|
||||
}
|
||||
],
|
||||
"label.logged-in-as": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Sesión de "
|
||||
},
|
||||
{
|
||||
"type": 1,
|
||||
"value": "username"
|
||||
}
|
||||
],
|
||||
"label.login": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Acceder"
|
||||
}
|
||||
],
|
||||
"label.logout": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Pechar sesión"
|
||||
}
|
||||
],
|
||||
"label.more": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Máis"
|
||||
}
|
||||
],
|
||||
"label.name": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Nome"
|
||||
}
|
||||
],
|
||||
"label.new-password": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Novo contrasinal"
|
||||
}
|
||||
],
|
||||
"label.owner": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Dona"
|
||||
}
|
||||
],
|
||||
"label.password": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Contrasinal"
|
||||
}
|
||||
],
|
||||
"label.passwords-dont-match": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Non concordan os contrasinais"
|
||||
}
|
||||
],
|
||||
"label.profile": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Perfil"
|
||||
}
|
||||
],
|
||||
"label.realtime": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Agora mesmo"
|
||||
}
|
||||
],
|
||||
"label.realtime-logs": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Rexistro neste intre"
|
||||
}
|
||||
],
|
||||
"label.refresh": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Actualizar"
|
||||
}
|
||||
],
|
||||
"label.required": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Requerido"
|
||||
}
|
||||
],
|
||||
"label.reset": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Restablecer"
|
||||
}
|
||||
],
|
||||
"label.reset-website": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Restablecer estatísticas"
|
||||
}
|
||||
],
|
||||
"label.save": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Gardar"
|
||||
}
|
||||
],
|
||||
"label.settings": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Axustes"
|
||||
}
|
||||
],
|
||||
"label.share-url": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Compartir URL"
|
||||
}
|
||||
],
|
||||
"label.single-day": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Un só día"
|
||||
}
|
||||
],
|
||||
"label.theme": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Decorado"
|
||||
}
|
||||
],
|
||||
"label.this-month": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Este mes"
|
||||
}
|
||||
],
|
||||
"label.this-week": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Esta semana"
|
||||
}
|
||||
],
|
||||
"label.this-year": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Este ano"
|
||||
}
|
||||
],
|
||||
"label.timezone": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Zona horaria"
|
||||
}
|
||||
],
|
||||
"label.today": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Hoxe"
|
||||
}
|
||||
],
|
||||
"label.tracking-code": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Código de seguimento"
|
||||
}
|
||||
],
|
||||
"label.unknown": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Descoñecido"
|
||||
}
|
||||
],
|
||||
"label.username": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Identificador"
|
||||
}
|
||||
],
|
||||
"label.view-details": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Ver detalles"
|
||||
}
|
||||
],
|
||||
"label.websites": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Sitios web"
|
||||
}
|
||||
],
|
||||
"message.active-users": [
|
||||
{
|
||||
"type": 1,
|
||||
"value": "x"
|
||||
},
|
||||
{
|
||||
"type": 0,
|
||||
"value": " actual "
|
||||
},
|
||||
{
|
||||
"offset": 0,
|
||||
"options": {
|
||||
"one": {
|
||||
"value": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "visitante"
|
||||
}
|
||||
]
|
||||
},
|
||||
"other": {
|
||||
"value": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "visitantes"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"pluralType": "cardinal",
|
||||
"type": 6,
|
||||
"value": "x"
|
||||
}
|
||||
],
|
||||
"message.confirm-delete": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Tes a certeza de querer eliminar "
|
||||
},
|
||||
{
|
||||
"type": 1,
|
||||
"value": "target"
|
||||
},
|
||||
{
|
||||
"type": 0,
|
||||
"value": "?"
|
||||
}
|
||||
],
|
||||
"message.confirm-reset": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Tes a certeza de querer restablecer as estatísticas de "
|
||||
},
|
||||
{
|
||||
"type": 1,
|
||||
"value": "target"
|
||||
},
|
||||
{
|
||||
"type": 0,
|
||||
"value": "?"
|
||||
}
|
||||
],
|
||||
"message.copied": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Copiado!"
|
||||
}
|
||||
],
|
||||
"message.delete-warning": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Tamén serán borrados tódolos datos asociados."
|
||||
}
|
||||
],
|
||||
"message.failure": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Houbo un fallo."
|
||||
}
|
||||
],
|
||||
"message.get-share-url": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Obter URL de compartición"
|
||||
}
|
||||
],
|
||||
"message.get-tracking-code": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Obter código de seguimento"
|
||||
}
|
||||
],
|
||||
"message.go-to-settings": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Ir aos axustes"
|
||||
}
|
||||
],
|
||||
"message.incorrect-username-password": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Credenciais incorrectas."
|
||||
}
|
||||
],
|
||||
"message.log.visitor": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Visitante desde "
|
||||
},
|
||||
{
|
||||
"type": 1,
|
||||
"value": "country"
|
||||
},
|
||||
{
|
||||
"type": 0,
|
||||
"value": " usando "
|
||||
},
|
||||
{
|
||||
"type": 1,
|
||||
"value": "browser"
|
||||
},
|
||||
{
|
||||
"type": 0,
|
||||
"value": " en "
|
||||
},
|
||||
{
|
||||
"type": 1,
|
||||
"value": "os"
|
||||
},
|
||||
{
|
||||
"type": 0,
|
||||
"value": " "
|
||||
},
|
||||
{
|
||||
"type": 1,
|
||||
"value": "device"
|
||||
}
|
||||
],
|
||||
"message.new-version-available": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "A nova versión "
|
||||
},
|
||||
{
|
||||
"type": 1,
|
||||
"value": "version"
|
||||
},
|
||||
{
|
||||
"type": 0,
|
||||
"value": " de umami está dispoñible!"
|
||||
}
|
||||
],
|
||||
"message.no-data-available": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Sen datos dispoñibles."
|
||||
}
|
||||
],
|
||||
"message.no-websites-configured": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Non tes sitios web configurados."
|
||||
}
|
||||
],
|
||||
"message.page-not-found": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Páxina non atopada."
|
||||
}
|
||||
],
|
||||
"message.powered-by": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Funciona grazas a "
|
||||
},
|
||||
{
|
||||
"type": 1,
|
||||
"value": "name"
|
||||
}
|
||||
],
|
||||
"message.reset-warning": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Vanse eliminar tódalas estatísticas deste sitio web, pero o código de seguimento permanecerá sen cambios."
|
||||
}
|
||||
],
|
||||
"message.save-success": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Gardouse correctamente."
|
||||
}
|
||||
],
|
||||
"message.share-url": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Este é o URL da compartición pública de "
|
||||
},
|
||||
{
|
||||
"type": 1,
|
||||
"value": "target"
|
||||
},
|
||||
{
|
||||
"type": 0,
|
||||
"value": "."
|
||||
}
|
||||
],
|
||||
"message.toggle-charts": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Activación das gráficas"
|
||||
}
|
||||
],
|
||||
"message.track-stats": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Para crear estatísticas de "
|
||||
},
|
||||
{
|
||||
"type": 1,
|
||||
"value": "target"
|
||||
},
|
||||
{
|
||||
"type": 0,
|
||||
"value": ", pon este código na sección "
|
||||
},
|
||||
{
|
||||
"type": 1,
|
||||
"value": "head"
|
||||
},
|
||||
{
|
||||
"type": 0,
|
||||
"value": " do teu sitio web."
|
||||
}
|
||||
],
|
||||
"message.type-delete": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Escribe "
|
||||
},
|
||||
{
|
||||
"type": 1,
|
||||
"value": "delete"
|
||||
},
|
||||
{
|
||||
"type": 0,
|
||||
"value": " na caixa inferior para confirmar."
|
||||
}
|
||||
],
|
||||
"message.type-reset": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Escribe "
|
||||
},
|
||||
{
|
||||
"type": 1,
|
||||
"value": "reset"
|
||||
},
|
||||
{
|
||||
"type": 0,
|
||||
"value": " na caixa inferior para confirmar."
|
||||
}
|
||||
],
|
||||
"metrics.actions": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Accións"
|
||||
}
|
||||
],
|
||||
"metrics.average-visit-time": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Tempo medio de visita"
|
||||
}
|
||||
],
|
||||
"metrics.bounce-rate": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Proporción de rebote"
|
||||
}
|
||||
],
|
||||
"metrics.browsers": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Navegadores"
|
||||
}
|
||||
],
|
||||
"metrics.countries": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Países"
|
||||
}
|
||||
],
|
||||
"metrics.device.desktop": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Escritorio"
|
||||
}
|
||||
],
|
||||
"metrics.device.laptop": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Portátil"
|
||||
}
|
||||
],
|
||||
"metrics.device.mobile": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Móbil"
|
||||
}
|
||||
],
|
||||
"metrics.device.tablet": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Tableta"
|
||||
}
|
||||
],
|
||||
"metrics.devices": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Dispositivos"
|
||||
}
|
||||
],
|
||||
"metrics.events": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Eventos"
|
||||
}
|
||||
],
|
||||
"metrics.filter.combined": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Combinado"
|
||||
}
|
||||
],
|
||||
"metrics.filter.domain-only": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Só dominio"
|
||||
}
|
||||
],
|
||||
"metrics.filter.raw": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Raw"
|
||||
}
|
||||
],
|
||||
"metrics.languages": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Idiomas"
|
||||
}
|
||||
],
|
||||
"metrics.operating-systems": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Sistemas operativos"
|
||||
}
|
||||
],
|
||||
"metrics.page-views": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Vistas de páxinas"
|
||||
}
|
||||
],
|
||||
"metrics.pages": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Páxinas"
|
||||
}
|
||||
],
|
||||
"metrics.referrers": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Orixes"
|
||||
}
|
||||
],
|
||||
"metrics.unique-visitors": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Visitas únicas"
|
||||
}
|
||||
],
|
||||
"metrics.views": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Visualizacións"
|
||||
}
|
||||
],
|
||||
"metrics.visitors": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Visitantes"
|
||||
}
|
||||
]
|
||||
}
|
@ -38,7 +38,7 @@
|
||||
"label.all-time": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "All time"
|
||||
"value": "Бүх цаг үеийн"
|
||||
}
|
||||
],
|
||||
"label.all-websites": [
|
||||
@ -176,7 +176,7 @@
|
||||
"label.language": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Language"
|
||||
"value": "Хэл"
|
||||
}
|
||||
],
|
||||
"label.last-days": [
|
||||
@ -250,7 +250,7 @@
|
||||
"label.owner": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Owner"
|
||||
"value": "Эзэмшигч"
|
||||
}
|
||||
],
|
||||
"label.password": [
|
||||
@ -304,7 +304,7 @@
|
||||
"label.reset-website": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Reset statistics"
|
||||
"value": "Тоон үзүүлэлтийг дахин эхлүүлэх"
|
||||
}
|
||||
],
|
||||
"label.save": [
|
||||
@ -334,7 +334,7 @@
|
||||
"label.theme": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Theme"
|
||||
"value": "Загвар"
|
||||
}
|
||||
],
|
||||
"label.this-month": [
|
||||
@ -588,7 +588,7 @@
|
||||
"message.reset-warning": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "All statistics for this website will be deleted, but your tracking code will remain intact."
|
||||
"value": "Энэ вебийн бүх тоон үзүүлэлтүүдийг устгах болно. Гэхдээ мөрдөх код хэвэндээ үлдэнэ."
|
||||
}
|
||||
],
|
||||
"message.save-success": [
|
||||
@ -610,7 +610,7 @@
|
||||
"message.toggle-charts": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Toggle charts"
|
||||
"value": "Графикийг харуулах/нуух"
|
||||
}
|
||||
],
|
||||
"message.track-stats": [
|
||||
@ -746,7 +746,7 @@
|
||||
"metrics.languages": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Languages"
|
||||
"value": "Хэл"
|
||||
}
|
||||
],
|
||||
"metrics.operating-systems": [
|
||||
|
@ -32,13 +32,13 @@
|
||||
"label.all-events": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "All events"
|
||||
"value": "Todos os eventos"
|
||||
}
|
||||
],
|
||||
"label.all-time": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "All time"
|
||||
"value": "Todo o período"
|
||||
}
|
||||
],
|
||||
"label.all-websites": [
|
||||
@ -176,7 +176,7 @@
|
||||
"label.language": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Language"
|
||||
"value": "Idioma"
|
||||
}
|
||||
],
|
||||
"label.last-days": [
|
||||
@ -250,7 +250,7 @@
|
||||
"label.owner": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Owner"
|
||||
"value": "Proprietário"
|
||||
}
|
||||
],
|
||||
"label.password": [
|
||||
@ -304,7 +304,7 @@
|
||||
"label.reset-website": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Reset statistics"
|
||||
"value": "Redefinir estatísticas"
|
||||
}
|
||||
],
|
||||
"label.save": [
|
||||
@ -334,7 +334,7 @@
|
||||
"label.theme": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Theme"
|
||||
"value": "Tema"
|
||||
}
|
||||
],
|
||||
"label.this-month": [
|
||||
@ -452,7 +452,7 @@
|
||||
"message.confirm-reset": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Are your sure you want to reset "
|
||||
"value": "Você tem certeza que deseja redefinir as estatísticas de "
|
||||
},
|
||||
{
|
||||
"type": 1,
|
||||
@ -460,7 +460,7 @@
|
||||
},
|
||||
{
|
||||
"type": 0,
|
||||
"value": "'s statistics?"
|
||||
"value": "?"
|
||||
}
|
||||
],
|
||||
"message.copied": [
|
||||
@ -584,7 +584,7 @@
|
||||
"message.reset-warning": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "All statistics for this website will be deleted, but your tracking code will remain intact."
|
||||
"value": "Todas as estatísticas deste site serão removidas, mas seu código de rastreamento permanecerá intacto."
|
||||
}
|
||||
],
|
||||
"message.save-success": [
|
||||
@ -610,7 +610,7 @@
|
||||
"message.toggle-charts": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Toggle charts"
|
||||
"value": "Mostrar/Esconder gráficos"
|
||||
}
|
||||
],
|
||||
"message.track-stats": [
|
||||
@ -750,7 +750,7 @@
|
||||
"metrics.languages": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Languages"
|
||||
"value": "Idiomas"
|
||||
}
|
||||
],
|
||||
"metrics.operating-systems": [
|
||||
|
@ -20,7 +20,7 @@
|
||||
"label.administrator": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Quản Trị"
|
||||
"value": "Quản trị"
|
||||
}
|
||||
],
|
||||
"label.all": [
|
||||
@ -32,19 +32,19 @@
|
||||
"label.all-events": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Tất cả events"
|
||||
"value": "Tất cả sự kiện"
|
||||
}
|
||||
],
|
||||
"label.all-time": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "All time"
|
||||
"value": "Toàn thời gian"
|
||||
}
|
||||
],
|
||||
"label.all-websites": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Tất cả websites"
|
||||
"value": "Tất cả website"
|
||||
}
|
||||
],
|
||||
"label.back": [
|
||||
@ -104,7 +104,7 @@
|
||||
"label.default-date-range": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Phạm vi ngày mặc định"
|
||||
"value": "Khoảng thời gian mặc định"
|
||||
}
|
||||
],
|
||||
"label.delete": [
|
||||
@ -242,7 +242,7 @@
|
||||
"label.owner": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Owner"
|
||||
"value": "Chủ nhân"
|
||||
}
|
||||
],
|
||||
"label.password": [
|
||||
@ -590,7 +590,7 @@
|
||||
"message.toggle-charts": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Toggle charts"
|
||||
"value": "Bật/tắt biểu đồ"
|
||||
}
|
||||
],
|
||||
"message.track-stats": [
|
||||
@ -730,7 +730,7 @@
|
||||
"metrics.languages": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Languages"
|
||||
"value": "Ngôn ngũ"
|
||||
}
|
||||
],
|
||||
"metrics.operating-systems": [
|
||||
@ -760,7 +760,7 @@
|
||||
"metrics.unique-visitors": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Khách truy cập duy nhất"
|
||||
"value": "Khách truy cập một lần"
|
||||
}
|
||||
],
|
||||
"metrics.views": [
|
||||
|
100
scripts/check-db.js
Normal file
100
scripts/check-db.js
Normal file
@ -0,0 +1,100 @@
|
||||
require('dotenv').config();
|
||||
const { PrismaClient } = require('@prisma/client');
|
||||
const prisma = new PrismaClient();
|
||||
const chalk = require('chalk');
|
||||
const spawn = require('cross-spawn');
|
||||
|
||||
let message = '';
|
||||
const updateMessage = `To update your database, you need to run:\n${chalk.bold.whiteBright(
|
||||
'yarn update-db',
|
||||
)}`;
|
||||
const baselineMessage = cmd =>
|
||||
`You need to update your database by running:\n${chalk.bold.whiteBright(cmd)}`;
|
||||
|
||||
function success(msg) {
|
||||
console.log(chalk.greenBright(`✓ ${msg}`));
|
||||
}
|
||||
|
||||
async function checkEnv() {
|
||||
if (!process.env.DATABASE_URL) {
|
||||
throw new Error('DATABASE_URL is not defined.');
|
||||
} else {
|
||||
success('DATABASE_URL is defined.');
|
||||
}
|
||||
}
|
||||
|
||||
async function checkConnection() {
|
||||
try {
|
||||
await prisma.$connect();
|
||||
|
||||
success('Database connection successful.');
|
||||
} catch (e) {
|
||||
throw new Error('Unable to connect to the database.');
|
||||
}
|
||||
}
|
||||
|
||||
async function checkTables() {
|
||||
try {
|
||||
await prisma.account.findFirst();
|
||||
|
||||
success('Database tables found.');
|
||||
} catch (e) {
|
||||
message = updateMessage;
|
||||
|
||||
throw new Error('Database tables not found.');
|
||||
}
|
||||
}
|
||||
|
||||
async function run(cmd, args) {
|
||||
const buffer = [];
|
||||
const proc = spawn(cmd, args);
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
proc.stdout.on('data', data => buffer.push(data));
|
||||
|
||||
proc.on('error', () => {
|
||||
reject(new Error('Failed to run Prisma.'));
|
||||
});
|
||||
|
||||
proc.on('exit', () => resolve(buffer.join('')));
|
||||
});
|
||||
}
|
||||
|
||||
async function checkMigrations() {
|
||||
const output = await run('prisma', ['migrate', 'status']);
|
||||
|
||||
const missingMigrations = output.includes('Following migration have not yet been applied');
|
||||
const notManaged = output.includes('The current database is not managed');
|
||||
|
||||
if (notManaged) {
|
||||
const cmd = output.match(/yarn prisma migrate resolve --applied ".*"/g);
|
||||
|
||||
message = baselineMessage(cmd[0]);
|
||||
|
||||
throw new Error('Database is out of date.');
|
||||
} else if (missingMigrations) {
|
||||
message = updateMessage;
|
||||
|
||||
throw new Error('Database is out of date.');
|
||||
}
|
||||
|
||||
success('Database is up to date.');
|
||||
}
|
||||
|
||||
(async () => {
|
||||
let err = false;
|
||||
for (let fn of [checkEnv, checkConnection, checkTables, checkMigrations]) {
|
||||
try {
|
||||
await fn();
|
||||
} catch (e) {
|
||||
console.log(chalk.red(`✗ ${e.message}`));
|
||||
err = true;
|
||||
} finally {
|
||||
await prisma.$disconnect();
|
||||
if (err) {
|
||||
console.log(message);
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
})();
|
@ -1,8 +1,9 @@
|
||||
require('dotenv').config();
|
||||
const fs = require('fs');
|
||||
const fse = require('fs-extra');
|
||||
const path = require('path');
|
||||
const del = require('del');
|
||||
|
||||
function getDatabase() {
|
||||
function getDatabaseType() {
|
||||
const type =
|
||||
process.env.DATABASE_TYPE ||
|
||||
(process.env.DATABASE_URL && process.env.DATABASE_URL.split(':')[0]);
|
||||
@ -14,7 +15,7 @@ function getDatabase() {
|
||||
return type;
|
||||
}
|
||||
|
||||
const databaseType = getDatabase();
|
||||
const databaseType = getDatabaseType();
|
||||
|
||||
if (!databaseType || !['mysql', 'postgresql'].includes(databaseType)) {
|
||||
throw new Error('Missing or invalid database');
|
||||
@ -22,9 +23,11 @@ if (!databaseType || !['mysql', 'postgresql'].includes(databaseType)) {
|
||||
|
||||
console.log(`Database type detected: ${databaseType}`);
|
||||
|
||||
const src = path.resolve(__dirname, `../prisma/schema.${databaseType}.prisma`);
|
||||
const dest = path.resolve(__dirname, '../prisma/schema.prisma');
|
||||
const src = path.resolve(__dirname, `../db/${databaseType}`);
|
||||
const dest = path.resolve(__dirname, '../prisma');
|
||||
|
||||
fs.copyFileSync(src, dest);
|
||||
del.sync(dest);
|
||||
|
||||
fse.copySync(src, dest);
|
||||
|
||||
console.log(`Copied ${src} to ${dest}`);
|
@ -4,7 +4,7 @@ const https = require('https');
|
||||
const chalk = require('chalk');
|
||||
|
||||
const src = path.resolve(__dirname, '../lang');
|
||||
const dest = path.resolve(__dirname, '../public/country');
|
||||
const dest = path.resolve(__dirname, '../public/intl/country');
|
||||
const files = fs.readdirSync(src);
|
||||
|
||||
const getUrl = locale =>
|
||||
|
@ -4,7 +4,7 @@ const https = require('https');
|
||||
const chalk = require('chalk');
|
||||
|
||||
const src = path.resolve(__dirname, '../lang');
|
||||
const dest = path.resolve(__dirname, '../public/language');
|
||||
const dest = path.resolve(__dirname, '../public/intl/language');
|
||||
const files = fs.readdirSync(src);
|
||||
|
||||
const getUrl = locale =>
|
||||
|
@ -71,4 +71,4 @@ create index event_created_at_idx on event(created_at);
|
||||
create index event_website_id_idx on event(website_id);
|
||||
create index event_session_id_idx on event(session_id);
|
||||
|
||||
insert into account (username, password, is_admin) values ('admin', '$2b$10$BUli0c.muyCW1ErNJc3jL.vFRFtFJWrT8/GcR4A.sUdCznaXiqFXa', true);
|
||||
insert into account (username, password, is_admin) values ('admin', '$2b$10$BUli0c.muyCW1ErNJc3jL.vFRFtFJWrT8/GcR4A.sUdCznaXiqFXa', true);
|
||||
|
@ -4,12 +4,13 @@ import semver from 'semver';
|
||||
import { VERSION_CHECK } from 'lib/constants';
|
||||
import { getItem } from 'lib/web';
|
||||
|
||||
const REPO_URL = 'https://api.umami.is/v1/updates';
|
||||
const UPDATES_URL = 'https://api.umami.is/v1/updates';
|
||||
|
||||
const initialState = {
|
||||
current: process.env.VERSION,
|
||||
current: process.env.currentVersion,
|
||||
latest: null,
|
||||
hasUpdate: false,
|
||||
checked: false,
|
||||
};
|
||||
|
||||
const store = create(() => ({ ...initialState }));
|
||||
@ -17,8 +18,8 @@ const store = create(() => ({ ...initialState }));
|
||||
export async function checkVersion() {
|
||||
const { current } = store.getState();
|
||||
|
||||
const data = await fetch(REPO_URL, {
|
||||
method: 'get',
|
||||
const data = await fetch(`${UPDATES_URL}?v=${current}`, {
|
||||
method: 'GET',
|
||||
headers: {
|
||||
Accept: 'application/json',
|
||||
},
|
||||
@ -38,11 +39,13 @@ export async function checkVersion() {
|
||||
produce(state => {
|
||||
const { latest } = data;
|
||||
const lastCheck = getItem(VERSION_CHECK);
|
||||
const hasUpdate = latest && semver.gt(latest, current) && lastCheck?.version !== latest;
|
||||
|
||||
const hasUpdate = !!(latest && lastCheck?.version !== latest && semver.gt(latest, current));
|
||||
|
||||
state.current = current;
|
||||
state.latest = latest;
|
||||
state.hasUpdate = hasUpdate;
|
||||
state.checked = true;
|
||||
|
||||
return state;
|
||||
}),
|
||||
|
59
yarn.lock
59
yarn.lock
@ -1359,22 +1359,22 @@
|
||||
resolved "https://registry.yarnpkg.com/@panva/asn1.js/-/asn1.js-1.0.0.tgz#dd55ae7b8129e02049f009408b97c61ccf9032f6"
|
||||
integrity sha512-UdkG3mLEqXgnlKsWanWcgb6dOjUzJ+XC5f+aWw30qrtjxeNUSfKX1cd5FBzOaXQumoe9nIqeZUvrRJS03HCCtw==
|
||||
|
||||
"@prisma/client@3.14.0":
|
||||
version "3.14.0"
|
||||
resolved "https://registry.yarnpkg.com/@prisma/client/-/client-3.14.0.tgz#bb90405c012fcca11f4647d91153ed4c58f3bd48"
|
||||
integrity sha512-atb41UpgTR1MCst0VIbiHTMw8lmXnwUvE1KyUCAkq08+wJyjRE78Due+nSf+7uwqQn+fBFYVmoojtinhlLOSaA==
|
||||
"@prisma/client@3.15.2":
|
||||
version "3.15.2"
|
||||
resolved "https://registry.yarnpkg.com/@prisma/client/-/client-3.15.2.tgz#2181398147afc79bfe0d83c03a88dc45b49bd365"
|
||||
integrity sha512-ErqtwhX12ubPhU4d++30uFY/rPcyvjk+mdifaZO5SeM21zS3t4jQrscy8+6IyB0GIYshl5ldTq6JSBo1d63i8w==
|
||||
dependencies:
|
||||
"@prisma/engines-version" "3.14.0-36.2b0c12756921c891fec4f68d9444e18c7d5d4a6a"
|
||||
"@prisma/engines-version" "3.15.1-1.461d6a05159055555eb7dfb337c9fb271cbd4d7e"
|
||||
|
||||
"@prisma/engines-version@3.14.0-36.2b0c12756921c891fec4f68d9444e18c7d5d4a6a":
|
||||
version "3.14.0-36.2b0c12756921c891fec4f68d9444e18c7d5d4a6a"
|
||||
resolved "https://registry.yarnpkg.com/@prisma/engines-version/-/engines-version-3.14.0-36.2b0c12756921c891fec4f68d9444e18c7d5d4a6a.tgz#4edae57cf6527f35e22cebe75e49214fc0e99ac9"
|
||||
integrity sha512-D+yHzq4a2r2Rrd0ZOW/mTZbgDIkUkD8ofKgusEI1xPiZz60Daks+UM7Me2ty5FzH3p/TgyhBpRrfIHx+ha20RQ==
|
||||
"@prisma/engines-version@3.15.1-1.461d6a05159055555eb7dfb337c9fb271cbd4d7e":
|
||||
version "3.15.1-1.461d6a05159055555eb7dfb337c9fb271cbd4d7e"
|
||||
resolved "https://registry.yarnpkg.com/@prisma/engines-version/-/engines-version-3.15.1-1.461d6a05159055555eb7dfb337c9fb271cbd4d7e.tgz#bf5e2373ca68ce7556b967cb4965a7095e93fe53"
|
||||
integrity sha512-e3k2Vd606efd1ZYy2NQKkT4C/pn31nehyLhVug6To/q8JT8FpiMrDy7zmm3KLF0L98NOQQcutaVtAPhzKhzn9w==
|
||||
|
||||
"@prisma/engines@3.14.0-36.2b0c12756921c891fec4f68d9444e18c7d5d4a6a":
|
||||
version "3.14.0-36.2b0c12756921c891fec4f68d9444e18c7d5d4a6a"
|
||||
resolved "https://registry.yarnpkg.com/@prisma/engines/-/engines-3.14.0-36.2b0c12756921c891fec4f68d9444e18c7d5d4a6a.tgz#7fa11bc26a51d450185c816cc0ab8cac673fb4bf"
|
||||
integrity sha512-LwZvI3FY6f43xFjQNRuE10JM5R8vJzFTSmbV9X0Wuhv9kscLkjRlZt0BEoiHmO+2HA3B3xxbMfB5du7ZoSFXGg==
|
||||
"@prisma/engines@3.15.1-1.461d6a05159055555eb7dfb337c9fb271cbd4d7e":
|
||||
version "3.15.1-1.461d6a05159055555eb7dfb337c9fb271cbd4d7e"
|
||||
resolved "https://registry.yarnpkg.com/@prisma/engines/-/engines-3.15.1-1.461d6a05159055555eb7dfb337c9fb271cbd4d7e.tgz#f691893df506b93e3cb1ccc15ec6e5ac64e8e570"
|
||||
integrity sha512-NHlojO1DFTsSi3FtEleL9QWXeSF/UjhCW0fgpi7bumnNZ4wj/eQ+BJJ5n2pgoOliTOGv9nX2qXvmHap7rJMNmg==
|
||||
|
||||
"@react-spring/animated@~9.4.5":
|
||||
version "9.4.5"
|
||||
@ -2246,25 +2246,10 @@ camelcase@^6.2.0:
|
||||
resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-6.3.0.tgz#5685b95eb209ac9c0c177467778c9c84df58ba9a"
|
||||
integrity sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==
|
||||
|
||||
caniuse-lite@^1.0.30001283:
|
||||
version "1.0.30001314"
|
||||
resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001314.tgz#65c7f9fb7e4594fca0a333bec1d8939662377596"
|
||||
integrity sha512-0zaSO+TnCHtHJIbpLroX7nsD+vYuOVjl3uzFbJO1wMVbuveJA0RK2WcQA9ZUIOiO0/ArMiMgHJLxfEZhQiC0kw==
|
||||
|
||||
caniuse-lite@^1.0.30001313:
|
||||
version "1.0.30001320"
|
||||
resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001320.tgz#8397391bec389b8ccce328636499b7284ee13285"
|
||||
integrity sha512-MWPzG54AGdo3nWx7zHZTefseM5Y1ccM7hlQKHRqJkPozUaw3hNbBTMmLn16GG2FUzjR13Cr3NPfhIieX5PzXDA==
|
||||
|
||||
caniuse-lite@^1.0.30001317, caniuse-lite@^1.0.30001332, caniuse-lite@^1.0.30001335:
|
||||
version "1.0.30001344"
|
||||
resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001344.tgz#8a1e7fdc4db9c2ec79a05e9fd68eb93a761888bb"
|
||||
integrity sha512-0ZFjnlCaXNOAYcV7i+TtdKBp0L/3XEU2MF/x6Du1lrh+SRX4IfzIVL4HNJg5pB2PmFb8rszIGyOvsZnqqRoc2g==
|
||||
|
||||
caniuse-lite@^1.0.30001349:
|
||||
version "1.0.30001352"
|
||||
resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001352.tgz#cc6f5da3f983979ad1e2cdbae0505dccaa7c6a12"
|
||||
integrity sha512-GUgH8w6YergqPQDGWhJGt8GDRnY0L/iJVQcU3eJ46GYf52R8tk0Wxp0PymuFVZboJYXGiCqwozAYZNRjVj6IcA==
|
||||
caniuse-lite@^1.0.30001283, caniuse-lite@^1.0.30001313, caniuse-lite@^1.0.30001317, caniuse-lite@^1.0.30001332, caniuse-lite@^1.0.30001335, caniuse-lite@^1.0.30001349:
|
||||
version "1.0.30001356"
|
||||
resolved "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001356.tgz"
|
||||
integrity sha512-/30854bktMLhxtjieIxsrJBfs2gTM1pel6MXKF3K+RdIVJZcsn2A2QdhsuR4/p9+R204fZw0zCBBhktX8xWuyQ==
|
||||
|
||||
chalk@^2.0.0, chalk@^2.4.1, chalk@^2.4.2:
|
||||
version "2.4.2"
|
||||
@ -5077,12 +5062,12 @@ prettier@^2.6.2:
|
||||
resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.6.2.tgz#e26d71a18a74c3d0f0597f55f01fb6c06c206032"
|
||||
integrity sha512-PkUpF+qoXTqhOeWL9fu7As8LXsIUZ1WYaJiY/a7McAQzxjk82OF0tibkFXVCDImZtWxbvojFjerkiLb0/q8mew==
|
||||
|
||||
prisma@3.14.0:
|
||||
version "3.14.0"
|
||||
resolved "https://registry.yarnpkg.com/prisma/-/prisma-3.14.0.tgz#dd67ece37d7b5373e9fd9588971de0024b49be81"
|
||||
integrity sha512-l9MOgNCn/paDE+i1K2fp9NZ+Du4trzPTJsGkaQHVBufTGqzoYHuNk8JfzXuIn0Gte6/ZjyKj652Jq/Lc1tp2yw==
|
||||
prisma@3.15.2:
|
||||
version "3.15.2"
|
||||
resolved "https://registry.yarnpkg.com/prisma/-/prisma-3.15.2.tgz#4ebe32fb284da3ac60c49fbc16c75e56ecf32067"
|
||||
integrity sha512-nMNSMZvtwrvoEQ/mui8L/aiCLZRCj5t6L3yujKpcDhIPk7garp8tL4nMx2+oYsN0FWBacevJhazfXAbV1kfBzA==
|
||||
dependencies:
|
||||
"@prisma/engines" "3.14.0-36.2b0c12756921c891fec4f68d9444e18c7d5d4a6a"
|
||||
"@prisma/engines" "3.15.1-1.461d6a05159055555eb7dfb337c9fb271cbd4d7e"
|
||||
|
||||
progress@^2.0.0:
|
||||
version "2.0.3"
|
||||
|
Loading…
Reference in New Issue
Block a user