From 9ea175eb3f2e1dbcfa09bb4a1fc570ebc991b79a Mon Sep 17 00:00:00 2001 From: Anbraten Date: Sun, 12 Jun 2022 08:38:58 +0200 Subject: [PATCH 01/31] Run migrations on start --- Dockerfile | 6 +- README.md | 19 +---- app.json | 38 ++++----- package.json | 3 +- .../20210320112658_init/migration.sql | 3 + .../20210320112717_init/migration.sql | 3 + scripts/copy-db-schema.js | 11 ++- sql/schema.mysql.sql | 80 ------------------- sql/schema.postgresql.sql | 74 ----------------- yarn.lock | 2 +- 10 files changed, 40 insertions(+), 199 deletions(-) delete mode 100644 sql/schema.mysql.sql delete mode 100644 sql/schema.postgresql.sql diff --git a/Dockerfile b/Dockerfile index 84752e17..aca314a2 100644 --- a/Dockerfile +++ b/Dockerfile @@ -35,10 +35,14 @@ 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 +55,4 @@ EXPOSE 3000 ENV PORT 3000 -CMD ["node", "server.js"] +CMD ["yarn", "production"] diff --git a/README.md b/README.md index fb2169c1..38958133 100644 --- a/README.md +++ b/README.md @@ -33,23 +33,10 @@ cd umami yarn install ``` -### Create database tables +### Database 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 -``` - +The database structure will automatically be applied on the first start of Umami. This will also create a login account with username **admin** and password **umami**. ### Configure umami @@ -82,7 +69,7 @@ yarn build 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. diff --git a/app.json b/app.json index a27dc6fe..ef62e0e5 100644 --- a/app.json +++ b/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": "/" } diff --git a/package.json b/package.json index f30a307c..3fc489a6 100644 --- a/package.json +++ b/package.json @@ -14,6 +14,7 @@ "build": "npm-run-all build-tracker build-geo build-db build-app", "start": "next start", "start-env": "node -r dotenv/config scripts/start-env.js", + "production": "prisma migrate deploy && node server.js", "build-app": "next build", "build-tracker": "rollup -c rollup.tracker.config.js", "build-db": "npm-run-all copy-db-schema build-db-client", @@ -68,7 +69,6 @@ "dotenv": "^10.0.0", "dotenv-cli": "^4.0.0", "formik": "^2.2.9", - "fs-extra": "^10.0.1", "immer": "^9.0.12", "ipaddr.js": "^2.0.1", "is-ci": "^3.0.1", @@ -107,6 +107,7 @@ "eslint-config-prettier": "^8.5.0", "eslint-plugin-prettier": "^4.0.0", "extract-react-intl-messages": "^4.1.1", + "fs-extra": "^10.1.0", "husky": "^7.0.0", "lint-staged": "^11.0.0", "postcss": "^8.4.12", diff --git a/prisma/mysql/migrations/20210320112658_init/migration.sql b/prisma/mysql/migrations/20210320112658_init/migration.sql index 0bb75d64..653c5de0 100644 --- a/prisma/mysql/migrations/20210320112658_init/migration.sql +++ b/prisma/mysql/migrations/20210320112658_init/migration.sql @@ -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); diff --git a/prisma/postgresql/migrations/20210320112717_init/migration.sql b/prisma/postgresql/migrations/20210320112717_init/migration.sql index 1567119d..cdabcd17 100644 --- a/prisma/postgresql/migrations/20210320112717_init/migration.sql +++ b/prisma/postgresql/migrations/20210320112717_init/migration.sql @@ -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); diff --git a/scripts/copy-db-schema.js b/scripts/copy-db-schema.js index 7773e696..9c4ed6db 100644 --- a/scripts/copy-db-schema.js +++ b/scripts/copy-db-schema.js @@ -1,5 +1,5 @@ require('dotenv').config(); -const fs = require('fs'); +const fse = require('fs-extra'); const path = require('path'); function getDatabase() { @@ -25,6 +25,13 @@ console.log(`Database type detected: ${databaseType}`); const src = path.resolve(__dirname, `../prisma/schema.${databaseType}.prisma`); const dest = path.resolve(__dirname, '../prisma/schema.prisma'); -fs.copyFileSync(src, dest); +fse.copyFileSync(src, dest); console.log(`Copied ${src} to ${dest}`); + +const srcMigrations = path.resolve(__dirname, `../prisma/${databaseType}/migrations`); +const destMigrations = path.resolve(__dirname, `../prisma/migrations`); + +fse.copySync(srcMigrations, destMigrations); + +console.log(`Copied ${srcMigrations} to ${destMigrations}`); diff --git a/sql/schema.mysql.sql b/sql/schema.mysql.sql deleted file mode 100644 index 0e05ec03..00000000 --- a/sql/schema.mysql.sql +++ /dev/null @@ -1,80 +0,0 @@ -drop table if exists event; -drop table if exists pageview; -drop table if exists session; -drop table if exists website; -drop table if exists account; - -create table account ( - user_id int unsigned not null auto_increment primary key, - username varchar(255) unique not null, - password varchar(60) not null, - is_admin bool not null default false, - created_at timestamp default current_timestamp, - updated_at timestamp default current_timestamp -) ENGINE=InnoDB COLLATE=utf8_general_ci; - -create table website ( - website_id int unsigned not null auto_increment primary key, - website_uuid varchar(36) unique not null, - user_id int unsigned not null, - name varchar(100) not null, - domain varchar(500), - share_id varchar(64) unique, - created_at timestamp default current_timestamp, - foreign key (user_id) references account(user_id) on delete cascade -) ENGINE=InnoDB COLLATE=utf8_general_ci; - -create table session ( - session_id int unsigned not null auto_increment primary key, - session_uuid varchar(36) unique not null, - website_id int unsigned not null references website(website_id) on delete cascade, - created_at timestamp default current_timestamp, - hostname varchar(100), - browser varchar(20), - os varchar(20), - device varchar(20), - screen varchar(11), - language varchar(35), - country char(2), - foreign key (website_id) references website(website_id) on delete cascade -) ENGINE=InnoDB COLLATE=utf8_general_ci; - -create table pageview ( - view_id int unsigned not null auto_increment primary key, - website_id int unsigned not null, - session_id int unsigned not null, - created_at timestamp default current_timestamp, - url varchar(500) not null, - referrer varchar(500), - foreign key (website_id) references website(website_id) on delete cascade, - foreign key (session_id) references session(session_id) on delete cascade -) ENGINE=InnoDB COLLATE=utf8_general_ci; - -create table event ( - event_id int unsigned not null auto_increment primary key, - website_id int unsigned not null, - session_id int unsigned not null, - created_at timestamp default current_timestamp, - url varchar(500) not null, - event_type varchar(50) not null, - event_value varchar(50) not null, - foreign key (website_id) references website(website_id) on delete cascade, - foreign key (session_id) references session(session_id) on delete cascade -) ENGINE=InnoDB COLLATE=utf8_general_ci; - -create index website_user_id_idx on website(user_id); - -create index session_created_at_idx on session(created_at); -create index session_website_id_idx on session(website_id); - -create index pageview_created_at_idx on pageview(created_at); -create index pageview_website_id_idx on pageview(website_id); -create index pageview_session_id_idx on pageview(session_id); -create index pageview_website_id_created_at_idx on pageview(website_id, created_at); -create index pageview_website_id_session_id_created_at_idx on pageview(website_id, session_id, created_at); - -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); diff --git a/sql/schema.postgresql.sql b/sql/schema.postgresql.sql deleted file mode 100644 index 28297c4a..00000000 --- a/sql/schema.postgresql.sql +++ /dev/null @@ -1,74 +0,0 @@ -drop table if exists event; -drop table if exists pageview; -drop table if exists session; -drop table if exists website; -drop table if exists account; - -create table account ( - user_id serial primary key, - username varchar(255) unique not null, - password varchar(60) not null, - is_admin bool not null default false, - created_at timestamp with time zone default current_timestamp, - updated_at timestamp with time zone default current_timestamp -); - -create table website ( - website_id serial primary key, - website_uuid uuid unique not null, - user_id int not null references account(user_id) on delete cascade, - name varchar(100) not null, - domain varchar(500), - share_id varchar(64) unique, - created_at timestamp with time zone default current_timestamp -); - -create table session ( - session_id serial primary key, - session_uuid uuid unique not null, - website_id int not null references website(website_id) on delete cascade, - created_at timestamp with time zone default current_timestamp, - hostname varchar(100), - browser varchar(20), - os varchar(20), - device varchar(20), - screen varchar(11), - language varchar(35), - country char(2) -); - -create table pageview ( - view_id serial primary key, - website_id int not null references website(website_id) on delete cascade, - session_id int not null references session(session_id) on delete cascade, - created_at timestamp with time zone default current_timestamp, - url varchar(500) not null, - referrer varchar(500) -); - -create table event ( - event_id serial primary key, - website_id int not null references website(website_id) on delete cascade, - session_id int not null references session(session_id) on delete cascade, - created_at timestamp with time zone default current_timestamp, - url varchar(500) not null, - event_type varchar(50) not null, - event_value varchar(50) not null -); - -create index website_user_id_idx on website(user_id); - -create index session_created_at_idx on session(created_at); -create index session_website_id_idx on session(website_id); - -create index pageview_created_at_idx on pageview(created_at); -create index pageview_website_id_idx on pageview(website_id); -create index pageview_session_id_idx on pageview(session_id); -create index pageview_website_id_created_at_idx on pageview(website_id, created_at); -create index pageview_website_id_session_id_created_at_idx on pageview(website_id, session_id, created_at); - -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); \ No newline at end of file diff --git a/yarn.lock b/yarn.lock index c6054736..d49dca19 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3353,7 +3353,7 @@ fraction.js@^4.2.0: resolved "https://registry.yarnpkg.com/fraction.js/-/fraction.js-4.2.0.tgz#448e5109a313a3527f5a3ab2119ec4cf0e0e2950" integrity sha512-MhLuK+2gUcnZe8ZHlaaINnQLl0xRIGRfcGk2yl8xoQAfHrSsL3rYu6FCmBdkdbhc9EPlwyGHewaRsvwRMJtAlA== -fs-extra@10, fs-extra@^10.0.1: +fs-extra@10, fs-extra@^10.1.0: version "10.1.0" resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-10.1.0.tgz#02873cfbc4084dde127eaa5f9905eef2325d1abf" integrity sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ== From 1bd59156b8562f6364b8094f23369ebff8831677 Mon Sep 17 00:00:00 2001 From: Anbraten Date: Sun, 12 Jun 2022 08:41:41 +0200 Subject: [PATCH 02/31] undo change to deps --- package.json | 2 +- yarn.lock | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 3fc489a6..20e3d05e 100644 --- a/package.json +++ b/package.json @@ -69,6 +69,7 @@ "dotenv": "^10.0.0", "dotenv-cli": "^4.0.0", "formik": "^2.2.9", + "fs-extra": "^10.0.1", "immer": "^9.0.12", "ipaddr.js": "^2.0.1", "is-ci": "^3.0.1", @@ -107,7 +108,6 @@ "eslint-config-prettier": "^8.5.0", "eslint-plugin-prettier": "^4.0.0", "extract-react-intl-messages": "^4.1.1", - "fs-extra": "^10.1.0", "husky": "^7.0.0", "lint-staged": "^11.0.0", "postcss": "^8.4.12", diff --git a/yarn.lock b/yarn.lock index d49dca19..c6054736 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3353,7 +3353,7 @@ fraction.js@^4.2.0: resolved "https://registry.yarnpkg.com/fraction.js/-/fraction.js-4.2.0.tgz#448e5109a313a3527f5a3ab2119ec4cf0e0e2950" integrity sha512-MhLuK+2gUcnZe8ZHlaaINnQLl0xRIGRfcGk2yl8xoQAfHrSsL3rYu6FCmBdkdbhc9EPlwyGHewaRsvwRMJtAlA== -fs-extra@10, fs-extra@^10.1.0: +fs-extra@10, fs-extra@^10.0.1: version "10.1.0" resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-10.1.0.tgz#02873cfbc4084dde127eaa5f9905eef2325d1abf" integrity sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ== From e960d15a1ea27426170f0121153e318f164786af Mon Sep 17 00:00:00 2001 From: Mohammad Amin Dehghani Date: Sun, 12 Jun 2022 13:12:33 +0430 Subject: [PATCH 03/31] Update lang/fa-IR.json --- lang/fa-IR.json | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/lang/fa-IR.json b/lang/fa-IR.json index 36c1dedc..a8b4a45c 100644 --- a/lang/fa-IR.json +++ b/lang/fa-IR.json @@ -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": "صفحه‌ها", From c2dad60607924aed1f271ba234763a4399b6d03b Mon Sep 17 00:00:00 2001 From: Bilguun Ochirbat Date: Mon, 13 Jun 2022 11:11:28 +0800 Subject: [PATCH 04/31] Updated mn-MN.json --- lang/mn-MN.json | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/lang/mn-MN.json b/lang/mn-MN.json index ca071e2f..f00beffc 100644 --- a/lang/mn-MN.json +++ b/lang/mn-MN.json @@ -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": "Хуудас", From 9cde3d8e40696721de2945d9b7263dfddf5e72f0 Mon Sep 17 00:00:00 2001 From: Felipe Valtl de Mello <3065339+valtlfelipe@users.noreply.github.com> Date: Mon, 13 Jun 2022 09:19:47 -0300 Subject: [PATCH 05/31] Improve pt-BR translations --- lang/pt-BR.json | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/lang/pt-BR.json b/lang/pt-BR.json index ed04c870..f5e5dd57 100644 --- a/lang/pt-BR.json +++ b/lang/pt-BR.json @@ -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", From 6ff4ce2ad6f7469145fcc30d3421bbbb9ced67ca Mon Sep 17 00:00:00 2001 From: Mike Cao Date: Tue, 14 Jun 2022 11:32:21 -0700 Subject: [PATCH 06/31] Updated docker file. --- Dockerfile | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/Dockerfile b/Dockerfile index 84752e17..1b0af259 100644 --- a/Dockerfile +++ b/Dockerfile @@ -8,18 +8,16 @@ 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 BASE_PATH +ARG DATABASE_URL +ARG DATABASE_TYPE +ENV BASE_PATH $BASE_PATH +ENV DATABASE_URL $DATABASE_URL +ENV DATABASE_TYPE $DATABASE_TYPE ENV NEXT_TELEMETRY_DISABLED 1 RUN yarn build @@ -29,7 +27,6 @@ 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 From d44bf55f07f92b9856ea7ca5bbdd8df5fadcd0ce Mon Sep 17 00:00:00 2001 From: Mike Cao Date: Tue, 14 Jun 2022 11:33:03 -0700 Subject: [PATCH 07/31] Updated language bundles. --- public/intl/messages/fa-IR.json | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/public/intl/messages/fa-IR.json b/public/intl/messages/fa-IR.json index 15b22079..0b64922b 100644 --- a/public/intl/messages/fa-IR.json +++ b/public/intl/messages/fa-IR.json @@ -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": [ From c45fe2bdb22de64db606f7235ef92c93caff6c1d Mon Sep 17 00:00:00 2001 From: Mike Cao Date: Tue, 14 Jun 2022 14:43:11 -0700 Subject: [PATCH 08/31] Updated language bundles. --- public/intl/messages/mn-MN.json | 16 ++++++++-------- public/intl/messages/pt-BR.json | 22 +++++++++++----------- 2 files changed, 19 insertions(+), 19 deletions(-) diff --git a/public/intl/messages/mn-MN.json b/public/intl/messages/mn-MN.json index b740cbc3..9c1c8cff 100644 --- a/public/intl/messages/mn-MN.json +++ b/public/intl/messages/mn-MN.json @@ -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": [ diff --git a/public/intl/messages/pt-BR.json b/public/intl/messages/pt-BR.json index 66af371c..de33ed62 100644 --- a/public/intl/messages/pt-BR.json +++ b/public/intl/messages/pt-BR.json @@ -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": [ From b66f4e973bdb47d3a7ccbfc9473b95c73be4321b Mon Sep 17 00:00:00 2001 From: Dzung Do Date: Sun, 19 Jun 2022 04:05:51 +0700 Subject: [PATCH 09/31] Update vi-VN.json --- lang/vi-VN.json | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/lang/vi-VN.json b/lang/vi-VN.json index 7e454641..a7d3c30b 100644 --- a/lang/vi-VN.json +++ b/lang/vi-VN.json @@ -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" } From 3122bab419ed91328a141abe6a4895f7f5af6e28 Mon Sep 17 00:00:00 2001 From: Mike Cao Date: Sun, 19 Jun 2022 00:07:01 -0700 Subject: [PATCH 10/31] Refactor migrations. --- .gitignore | 2 +- README.md | 21 ++++++++------ .../20210320112658_init/migration.sql | 0 .../mysql/migrations/migration_lock.toml | 0 .../mysql/schema.prisma | 0 .../20210320112717_init/migration.sql | 0 .../postgresql/migrations/migration_lock.toml | 0 .../postgresql/schema.prisma | 0 lib/db.js | 10 +++---- package.json | 18 ++++++------ prisma/mysql/schema.mysql.prisma | 1 - prisma/postgresql/schema.postgresql.prisma | 1 - prisma/seed.js | 29 ------------------- scripts/check-db.js | 16 ++++++++++ .../{copy-db-schema.js => copy-db-files.js} | 13 ++------- 15 files changed, 46 insertions(+), 65 deletions(-) rename {prisma => db}/mysql/migrations/20210320112658_init/migration.sql (100%) rename {prisma => db}/mysql/migrations/migration_lock.toml (100%) rename prisma/schema.mysql.prisma => db/mysql/schema.prisma (100%) rename {prisma => db}/postgresql/migrations/20210320112717_init/migration.sql (100%) rename {prisma => db}/postgresql/migrations/migration_lock.toml (100%) rename prisma/schema.postgresql.prisma => db/postgresql/schema.prisma (100%) delete mode 120000 prisma/mysql/schema.mysql.prisma delete mode 120000 prisma/postgresql/schema.postgresql.prisma delete mode 100644 prisma/seed.js create mode 100644 scripts/check-db.js rename scripts/{copy-db-schema.js => copy-db-files.js} (56%) diff --git a/.gitignore b/.gitignore index e6b35441..6414cc5f 100644 --- a/.gitignore +++ b/.gitignore @@ -11,7 +11,7 @@ # next.js /.next/ /out/ -/prisma/schema.prisma +/prisma/ # production /build diff --git a/README.md b/README.md index 38958133..3a14a010 100644 --- a/README.md +++ b/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,12 +33,6 @@ cd umami yarn install ``` -### Database - -Umami supports [MySQL](https://www.mysql.com/) and [Postgresql](https://www.postgresql.org/). -The database structure will automatically be applied on the first start of Umami. -This will also create a login account with username **admin** and password **umami**. - ### Configure umami Create an `.env` file with the following @@ -57,6 +51,15 @@ mysql://username:mypassword@localhost:3306/mydb The `HASH_SALT` is used to generate unique values for your installation. +### Check database + +```bash +yarn check-db +``` + +The database structure will automatically be applied on the first start of Umami. +This will also create a login account with username **admin** and password **umami**. + ### Build the application ```bash diff --git a/prisma/mysql/migrations/20210320112658_init/migration.sql b/db/mysql/migrations/20210320112658_init/migration.sql similarity index 100% rename from prisma/mysql/migrations/20210320112658_init/migration.sql rename to db/mysql/migrations/20210320112658_init/migration.sql diff --git a/prisma/mysql/migrations/migration_lock.toml b/db/mysql/migrations/migration_lock.toml similarity index 100% rename from prisma/mysql/migrations/migration_lock.toml rename to db/mysql/migrations/migration_lock.toml diff --git a/prisma/schema.mysql.prisma b/db/mysql/schema.prisma similarity index 100% rename from prisma/schema.mysql.prisma rename to db/mysql/schema.prisma diff --git a/prisma/postgresql/migrations/20210320112717_init/migration.sql b/db/postgresql/migrations/20210320112717_init/migration.sql similarity index 100% rename from prisma/postgresql/migrations/20210320112717_init/migration.sql rename to db/postgresql/migrations/20210320112717_init/migration.sql diff --git a/prisma/postgresql/migrations/migration_lock.toml b/db/postgresql/migrations/migration_lock.toml similarity index 100% rename from prisma/postgresql/migrations/migration_lock.toml rename to db/postgresql/migrations/migration_lock.toml diff --git a/prisma/schema.postgresql.prisma b/db/postgresql/schema.prisma similarity index 100% rename from prisma/schema.postgresql.prisma rename to db/postgresql/schema.prisma diff --git a/lib/db.js b/lib/db.js index 35948998..755696f4 100644 --- a/lib/db.js +++ b/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; diff --git a/package.json b/package.json index 20e3d05e..f5386cb5 100644 --- a/package.json +++ b/package.json @@ -14,19 +14,18 @@ "build": "npm-run-all build-tracker build-geo build-db build-app", "start": "next start", "start-env": "node -r dotenv/config scripts/start-env.js", - "production": "prisma migrate deploy && node server.js", + "start-server": "node server.js", "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", + "test-db": "node scripts/test-db.js", + "check-db": "prisma migrate status", + "update-db": "prisma migrate deploy", + "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", @@ -62,6 +61,7 @@ "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", diff --git a/prisma/mysql/schema.mysql.prisma b/prisma/mysql/schema.mysql.prisma deleted file mode 120000 index fec72c83..00000000 --- a/prisma/mysql/schema.mysql.prisma +++ /dev/null @@ -1 +0,0 @@ -../schema.mysql.prisma \ No newline at end of file diff --git a/prisma/postgresql/schema.postgresql.prisma b/prisma/postgresql/schema.postgresql.prisma deleted file mode 120000 index 6c19dc77..00000000 --- a/prisma/postgresql/schema.postgresql.prisma +++ /dev/null @@ -1 +0,0 @@ -../schema.postgresql.prisma \ No newline at end of file diff --git a/prisma/seed.js b/prisma/seed.js deleted file mode 100644 index 12f59004..00000000 --- a/prisma/seed.js +++ /dev/null @@ -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(); - }); diff --git a/scripts/check-db.js b/scripts/check-db.js new file mode 100644 index 00000000..118ebd21 --- /dev/null +++ b/scripts/check-db.js @@ -0,0 +1,16 @@ +require('dotenv').config(); +const { PrismaClient } = require('@prisma/client'); +const prisma = new PrismaClient(); + +async function check() { + await prisma.account.findMany({ limit: 1 }); +} + +check() + .catch(e => { + console.error(e); + process.exit(1); + }) + .finally(async () => { + await prisma.$disconnect(); + }); diff --git a/scripts/copy-db-schema.js b/scripts/copy-db-files.js similarity index 56% rename from scripts/copy-db-schema.js rename to scripts/copy-db-files.js index 9c4ed6db..9bba914d 100644 --- a/scripts/copy-db-schema.js +++ b/scripts/copy-db-files.js @@ -22,16 +22,9 @@ 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'); -fse.copyFileSync(src, dest); +fse.copySync(src, dest); console.log(`Copied ${src} to ${dest}`); - -const srcMigrations = path.resolve(__dirname, `../prisma/${databaseType}/migrations`); -const destMigrations = path.resolve(__dirname, `../prisma/migrations`); - -fse.copySync(srcMigrations, destMigrations); - -console.log(`Copied ${srcMigrations} to ${destMigrations}`); From ac3017b2e4a0dbea322140ba649821b49ba1fd52 Mon Sep 17 00:00:00 2001 From: Mike Cao Date: Wed, 22 Jun 2022 01:50:33 -0700 Subject: [PATCH 11/31] Added database check. --- Dockerfile | 2 +- README.md | 10 ++--- package.json | 9 ++-- scripts/check-db.js | 96 ++++++++++++++++++++++++++++++++++++---- scripts/copy-db-files.js | 4 +- yarn.lock | 23 ++-------- 6 files changed, 104 insertions(+), 40 deletions(-) diff --git a/Dockerfile b/Dockerfile index 7796eb23..e8cdc729 100644 --- a/Dockerfile +++ b/Dockerfile @@ -52,4 +52,4 @@ EXPOSE 3000 ENV PORT 3000 -CMD ["yarn", "production"] +CMD ["yarn", "start-docker"] diff --git a/README.md b/README.md index 3a14a010..224713d1 100644 --- a/README.md +++ b/README.md @@ -51,15 +51,14 @@ mysql://username:mypassword@localhost:3306/mydb The `HASH_SALT` is used to generate unique values for your installation. -### Check database +This will also create a login account with username **admin** and password **umami**. + +### Create database tables ```bash -yarn check-db +yarn update-db ``` -The database structure will automatically be applied on the first start of Umami. -This will also create a login account with username **admin** and password **umami**. - ### Build the application ```bash @@ -102,6 +101,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: diff --git a/package.json b/package.json index f5386cb5..684c4374 100644 --- a/package.json +++ b/package.json @@ -12,19 +12,20 @@ "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-files build-db-client", + "build-db": "npm-run-all copy-db-files build-db-client check-db", "build-lang": "npm-run-all format-lang compile-lang", "build-geo": "node scripts/build-geo.js", "build-db-schema": "prisma db pull", "build-db-client": "prisma generate", - "test-db": "node scripts/test-db.js", - "check-db": "prisma migrate status", "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", diff --git a/scripts/check-db.js b/scripts/check-db.js index 118ebd21..2e27a838 100644 --- a/scripts/check-db.js +++ b/scripts/check-db.js @@ -1,16 +1,94 @@ require('dotenv').config(); const { PrismaClient } = require('@prisma/client'); const prisma = new PrismaClient(); +const chalk = require('chalk'); +const spawn = require('cross-spawn'); -async function check() { - await prisma.account.findMany({ limit: 1 }); +let message = ''; + +function success(msg) { + console.log(chalk.greenBright(`✓ ${msg}`)); } -check() - .catch(e => { - console.error(e); - process.exit(1); - }) - .finally(async () => { - await prisma.$disconnect(); +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 = `To update your database, you need to run:\n${chalk.bold.whiteBright( + 'yarn update-db', + )}`; + 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 = `You need to update your database by running:\n${chalk.bold.whiteBright(cmd[0])}`; + throw new Error('Database is out of date.'); + } else if (missingMigrations) { + message = output; + 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); + } + } + } +})(); diff --git a/scripts/copy-db-files.js b/scripts/copy-db-files.js index 9bba914d..92d5c49f 100644 --- a/scripts/copy-db-files.js +++ b/scripts/copy-db-files.js @@ -2,7 +2,7 @@ require('dotenv').config(); const fse = require('fs-extra'); const path = require('path'); -function getDatabase() { +function getDatabaseType() { const type = process.env.DATABASE_TYPE || (process.env.DATABASE_URL && process.env.DATABASE_URL.split(':')[0]); @@ -14,7 +14,7 @@ function getDatabase() { return type; } -const databaseType = getDatabase(); +const databaseType = getDatabaseType(); if (!databaseType || !['mysql', 'postgresql'].includes(databaseType)) { throw new Error('Missing or invalid database'); diff --git a/yarn.lock b/yarn.lock index c6054736..6478c811 100644 --- a/yarn.lock +++ b/yarn.lock @@ -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" From c3bcf46dd34be7823873f50e58d3cf80eb7a747c Mon Sep 17 00:00:00 2001 From: Mike Cao Date: Wed, 22 Jun 2022 01:53:52 -0700 Subject: [PATCH 12/31] Remove check-db from build step. --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 684c4374..0559db85 100644 --- a/package.json +++ b/package.json @@ -19,7 +19,7 @@ "start-next": "next start", "build-app": "next build", "build-tracker": "rollup -c rollup.tracker.config.js", - "build-db": "npm-run-all copy-db-files build-db-client check-db", + "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": "prisma db pull", From 0f37c17cb5c7b4801b844e81a022e78f1283556d Mon Sep 17 00:00:00 2001 From: Mike Cao Date: Wed, 22 Jun 2022 02:08:13 -0700 Subject: [PATCH 13/31] Added logging to test Vercel issue. --- pages/_middleware.js | 1 + 1 file changed, 1 insertion(+) diff --git a/pages/_middleware.js b/pages/_middleware.js index 4eef336e..256efb42 100644 --- a/pages/_middleware.js +++ b/pages/_middleware.js @@ -16,6 +16,7 @@ function customScriptName(req) { } function disableLogin(req) { + console.log(process.env, process.env.DISABLE_LOGIN); if (process.env.DISABLE_LOGIN && req.nextUrl.pathname.endsWith('/login')) { return new Response('Login is disabled', { status: 403 }); } From 5a5a278d9e3a65f404f12967e3d5dde9e8f7fb05 Mon Sep 17 00:00:00 2001 From: Mike Cao Date: Wed, 22 Jun 2022 02:28:23 -0700 Subject: [PATCH 14/31] Removed DISABLE_LOGIN from middleware. --- next.config.js | 3 ++- pages/_middleware.js | 9 +-------- pages/login.js | 2 +- store/version.js | 2 +- 4 files changed, 5 insertions(+), 11 deletions(-) diff --git a/next.config.js b/next.config.js index e458b8dc..9630e22e 100644 --- a/next.config.js +++ b/next.config.js @@ -3,7 +3,8 @@ const pkg = require('./package.json'); module.exports = { env: { - VERSION: pkg.version, + version: pkg.version, + loginDisabled: process.env.DISABLE_LOGIN, }, basePath: process.env.BASE_PATH, experimental: { diff --git a/pages/_middleware.js b/pages/_middleware.js index 256efb42..b8c66e94 100644 --- a/pages/_middleware.js +++ b/pages/_middleware.js @@ -15,13 +15,6 @@ function customScriptName(req) { } } -function disableLogin(req) { - console.log(process.env, process.env.DISABLE_LOGIN); - 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'); @@ -31,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); diff --git a/pages/login.js b/pages/login.js index d975e3c7..94c0df64 100644 --- a/pages/login.js +++ b/pages/login.js @@ -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; } diff --git a/store/version.js b/store/version.js index eacca340..5f74141c 100644 --- a/store/version.js +++ b/store/version.js @@ -7,7 +7,7 @@ import { getItem } from 'lib/web'; const REPO_URL = 'https://api.umami.is/v1/updates'; const initialState = { - current: process.env.VERSION, + current: process.env.version, latest: null, hasUpdate: false, }; From 3c1308890a5476368cd67c7f82961d0d48bb2ff7 Mon Sep 17 00:00:00 2001 From: Mike Cao Date: Wed, 22 Jun 2022 09:32:58 -0700 Subject: [PATCH 15/31] Remove prisma dir before copying files. --- scripts/copy-db-files.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/scripts/copy-db-files.js b/scripts/copy-db-files.js index 92d5c49f..a7897fca 100644 --- a/scripts/copy-db-files.js +++ b/scripts/copy-db-files.js @@ -1,6 +1,7 @@ require('dotenv').config(); const fse = require('fs-extra'); const path = require('path'); +const del = require('del'); function getDatabaseType() { const type = @@ -25,6 +26,8 @@ console.log(`Database type detected: ${databaseType}`); const src = path.resolve(__dirname, `../db/${databaseType}`); const dest = path.resolve(__dirname, '../prisma'); +del.sync(dest); + fse.copySync(src, dest); console.log(`Copied ${src} to ${dest}`); From 50aa26e3fc58eb5becd91e86ae89126d04b20700 Mon Sep 17 00:00:00 2001 From: Mike Cao Date: Wed, 22 Jun 2022 09:34:03 -0700 Subject: [PATCH 16/31] Updated build order. --- README.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 224713d1..ad87928f 100644 --- a/README.md +++ b/README.md @@ -53,18 +53,18 @@ 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**. -### Create database tables - -```bash -yarn update-db -``` - ### Build the application ```bash yarn build ``` +### Create database tables + +```bash +yarn update-db +``` + ### Start the application ```bash From c246b883297064101ba497ac917e719162995361 Mon Sep 17 00:00:00 2001 From: Mike Cao Date: Wed, 22 Jun 2022 11:02:40 -0700 Subject: [PATCH 17/31] Removed HASH_SALT requirement. --- Dockerfile | 8 ++++++-- README.md | 3 --- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/Dockerfile b/Dockerfile index e8cdc729..31dfe7a3 100644 --- a/Dockerfile +++ b/Dockerfile @@ -12,12 +12,16 @@ WORKDIR /app COPY --from=deps /app/node_modules ./node_modules COPY . . -ARG BASE_PATH ARG DATABASE_URL ARG DATABASE_TYPE -ENV BASE_PATH $BASE_PATH +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 diff --git a/README.md b/README.md index ad87928f..afa6a249 100644 --- a/README.md +++ b/README.md @@ -39,7 +39,6 @@ Create an `.env` file with the following ``` DATABASE_URL=(connection url) -HASH_SALT=(any random string) ``` The connection url is in the following format: @@ -49,8 +48,6 @@ 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 From 89fb62a50ab2b6176e3754bbaa63f11bfd7f5cf4 Mon Sep 17 00:00:00 2001 From: Mike Cao Date: Wed, 22 Jun 2022 12:12:22 -0700 Subject: [PATCH 18/31] Updated to prisma 3.15.2. Updated check-db script. --- package.json | 4 ++-- scripts/check-db.js | 16 +++++++++++----- yarn.lock | 36 ++++++++++++++++++------------------ 3 files changed, 31 insertions(+), 25 deletions(-) diff --git a/package.json b/package.json index 0559db85..f4c90c95 100644 --- a/package.json +++ b/package.json @@ -55,7 +55,7 @@ }, "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", @@ -117,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", diff --git a/scripts/check-db.js b/scripts/check-db.js index 2e27a838..b9582dbd 100644 --- a/scripts/check-db.js +++ b/scripts/check-db.js @@ -5,6 +5,11 @@ 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}`)); @@ -34,9 +39,8 @@ async function checkTables() { success('Database tables found.'); } catch (e) { - message = `To update your database, you need to run:\n${chalk.bold.whiteBright( - 'yarn update-db', - )}`; + message = updateMessage; + throw new Error('Database tables not found.'); } } @@ -65,10 +69,12 @@ async function checkMigrations() { if (notManaged) { const cmd = output.match(/yarn prisma migrate resolve --applied ".*"/g); - message = `You need to update your database by running:\n${chalk.bold.whiteBright(cmd[0])}`; + message = baselineMessage(cmd[0]); + throw new Error('Database is out of date.'); } else if (missingMigrations) { - message = output; + message = updateMessage; + throw new Error('Database is out of date.'); } diff --git a/yarn.lock b/yarn.lock index 6478c811..65b1e2d3 100644 --- a/yarn.lock +++ b/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" @@ -5062,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" From 11ae382209f6056e3b0d79b05984d7af58ddda15 Mon Sep 17 00:00:00 2001 From: Mike Cao Date: Wed, 22 Jun 2022 17:40:05 -0700 Subject: [PATCH 19/31] Added SQL files for docker-compose. --- sql/schema.mysql.sql | 80 +++++++++++++++++++++++++++++++++++++++ sql/schema.postgresql.sql | 74 ++++++++++++++++++++++++++++++++++++ 2 files changed, 154 insertions(+) create mode 100644 sql/schema.mysql.sql create mode 100644 sql/schema.postgresql.sql diff --git a/sql/schema.mysql.sql b/sql/schema.mysql.sql new file mode 100644 index 00000000..0e05ec03 --- /dev/null +++ b/sql/schema.mysql.sql @@ -0,0 +1,80 @@ +drop table if exists event; +drop table if exists pageview; +drop table if exists session; +drop table if exists website; +drop table if exists account; + +create table account ( + user_id int unsigned not null auto_increment primary key, + username varchar(255) unique not null, + password varchar(60) not null, + is_admin bool not null default false, + created_at timestamp default current_timestamp, + updated_at timestamp default current_timestamp +) ENGINE=InnoDB COLLATE=utf8_general_ci; + +create table website ( + website_id int unsigned not null auto_increment primary key, + website_uuid varchar(36) unique not null, + user_id int unsigned not null, + name varchar(100) not null, + domain varchar(500), + share_id varchar(64) unique, + created_at timestamp default current_timestamp, + foreign key (user_id) references account(user_id) on delete cascade +) ENGINE=InnoDB COLLATE=utf8_general_ci; + +create table session ( + session_id int unsigned not null auto_increment primary key, + session_uuid varchar(36) unique not null, + website_id int unsigned not null references website(website_id) on delete cascade, + created_at timestamp default current_timestamp, + hostname varchar(100), + browser varchar(20), + os varchar(20), + device varchar(20), + screen varchar(11), + language varchar(35), + country char(2), + foreign key (website_id) references website(website_id) on delete cascade +) ENGINE=InnoDB COLLATE=utf8_general_ci; + +create table pageview ( + view_id int unsigned not null auto_increment primary key, + website_id int unsigned not null, + session_id int unsigned not null, + created_at timestamp default current_timestamp, + url varchar(500) not null, + referrer varchar(500), + foreign key (website_id) references website(website_id) on delete cascade, + foreign key (session_id) references session(session_id) on delete cascade +) ENGINE=InnoDB COLLATE=utf8_general_ci; + +create table event ( + event_id int unsigned not null auto_increment primary key, + website_id int unsigned not null, + session_id int unsigned not null, + created_at timestamp default current_timestamp, + url varchar(500) not null, + event_type varchar(50) not null, + event_value varchar(50) not null, + foreign key (website_id) references website(website_id) on delete cascade, + foreign key (session_id) references session(session_id) on delete cascade +) ENGINE=InnoDB COLLATE=utf8_general_ci; + +create index website_user_id_idx on website(user_id); + +create index session_created_at_idx on session(created_at); +create index session_website_id_idx on session(website_id); + +create index pageview_created_at_idx on pageview(created_at); +create index pageview_website_id_idx on pageview(website_id); +create index pageview_session_id_idx on pageview(session_id); +create index pageview_website_id_created_at_idx on pageview(website_id, created_at); +create index pageview_website_id_session_id_created_at_idx on pageview(website_id, session_id, created_at); + +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); diff --git a/sql/schema.postgresql.sql b/sql/schema.postgresql.sql new file mode 100644 index 00000000..40d9f254 --- /dev/null +++ b/sql/schema.postgresql.sql @@ -0,0 +1,74 @@ +drop table if exists event; +drop table if exists pageview; +drop table if exists session; +drop table if exists website; +drop table if exists account; + +create table account ( + user_id serial primary key, + username varchar(255) unique not null, + password varchar(60) not null, + is_admin bool not null default false, + created_at timestamp with time zone default current_timestamp, + updated_at timestamp with time zone default current_timestamp +); + +create table website ( + website_id serial primary key, + website_uuid uuid unique not null, + user_id int not null references account(user_id) on delete cascade, + name varchar(100) not null, + domain varchar(500), + share_id varchar(64) unique, + created_at timestamp with time zone default current_timestamp +); + +create table session ( + session_id serial primary key, + session_uuid uuid unique not null, + website_id int not null references website(website_id) on delete cascade, + created_at timestamp with time zone default current_timestamp, + hostname varchar(100), + browser varchar(20), + os varchar(20), + device varchar(20), + screen varchar(11), + language varchar(35), + country char(2) +); + +create table pageview ( + view_id serial primary key, + website_id int not null references website(website_id) on delete cascade, + session_id int not null references session(session_id) on delete cascade, + created_at timestamp with time zone default current_timestamp, + url varchar(500) not null, + referrer varchar(500) +); + +create table event ( + event_id serial primary key, + website_id int not null references website(website_id) on delete cascade, + session_id int not null references session(session_id) on delete cascade, + created_at timestamp with time zone default current_timestamp, + url varchar(500) not null, + event_type varchar(50) not null, + event_value varchar(50) not null +); + +create index website_user_id_idx on website(user_id); + +create index session_created_at_idx on session(created_at); +create index session_website_id_idx on session(website_id); + +create index pageview_created_at_idx on pageview(created_at); +create index pageview_website_id_idx on pageview(website_id); +create index pageview_session_id_idx on pageview(session_id); +create index pageview_website_id_created_at_idx on pageview(website_id, created_at); +create index pageview_website_id_session_id_created_at_idx on pageview(website_id, session_id, created_at); + +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); From 1bfb26ab447cc0b3ef4c11df91430c5cf88d5e0c Mon Sep 17 00:00:00 2001 From: Mike Cao Date: Thu, 23 Jun 2022 13:44:30 -0700 Subject: [PATCH 20/31] Fix display of encoded characters. Closes #1171. --- components/common/FilterLink.js | 3 ++- components/metrics/CountriesTable.js | 17 +++++++++++------ 2 files changed, 13 insertions(+), 7 deletions(-) diff --git a/components/common/FilterLink.js b/components/common/FilterLink.js index 9401cb13..459a8ae1 100644 --- a/components/common/FilterLink.js +++ b/components/common/FilterLink.js @@ -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)} {externalUrl && ( diff --git a/components/metrics/CountriesTable.js b/components/metrics/CountriesTable.js index 17d9127a..4a4c6132 100644 --- a/components/metrics/CountriesTable.js +++ b/components/metrics/CountriesTable.js @@ -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: 'label.countries', defaultMessage: 'Countries' }, + visitors: { id: 'label.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 }) { - } + label={countryNames[code] ?? formatMessage(messages.unknown)} /> ); @@ -27,9 +32,9 @@ export default function CountriesTable({ websiteId, onDataLoad, ...props }) { return ( } + title={formatMessage(messages.countries)} type="country" - metric={} + metric={formatMessage(messages.visitors)} websiteId={websiteId} onDataLoad={data => onDataLoad?.(percentFilter(data))} renderLabel={renderLink} From c8ca0a0a56d1700e60fbc7050abec3fa4a08e0f2 Mon Sep 17 00:00:00 2001 From: Mike Cao Date: Fri, 24 Jun 2022 01:54:55 -0700 Subject: [PATCH 21/31] Updated version checking. --- components/common/UpdateNotice.js | 33 ++++++++++++++++++++----------- components/layout/Footer.js | 4 ++-- components/layout/Header.js | 4 +++- hooks/useVersion.js | 21 -------------------- next.config.js | 3 ++- package.json | 2 +- store/version.js | 13 +++++++----- 7 files changed, 38 insertions(+), 42 deletions(-) delete mode 100644 hooks/useVersion.js diff --git a/components/common/UpdateNotice.js b/components/common/UpdateNotice.js index a31c2abf..a2963995 100644 --- a/components/common/UpdateNotice.js +++ b/components/common/UpdateNotice.js @@ -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; } diff --git a/components/layout/Footer.js b/components/layout/Footer.js index 603b9369..21ce0573 100644 --- a/components/layout/Footer.js +++ b/components/layout/Footer.js @@ -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 (