diff --git a/.github/workflows/alpha.yml b/.github/workflows/alpha.yml index ba1572f3c..c68b8828b 100644 --- a/.github/workflows/alpha.yml +++ b/.github/workflows/alpha.yml @@ -2,7 +2,7 @@ name: 'Alpha Build' on: push: - branches: [v4110/force-dep] + branches: [v4120/db_conventions] jobs: build: diff --git a/README.md b/README.md index 97220e7d8..8cc0e7509 100644 --- a/README.md +++ b/README.md @@ -84,6 +84,11 @@ This will run a demo version, which you can turn into a fully licenced version b ## Versions History +### Version 4.12.0 (unreleased) + +- Changing naming convention for the database. All fields and tables are now `snake_case`. +- Simplified the configuration of TypeORM, removed the generation of `ormconfig.json`. + ### Version 4.11.5 (hotfix) - Making secure cookies an optional setting, as they won't work unless it is hosted on HTTPS. diff --git a/backend/.dockerignore b/backend/.dockerignore index 2249fb9be..9738728fb 100644 --- a/backend/.dockerignore +++ b/backend/.dockerignore @@ -2,4 +2,5 @@ node_modules npm-debug.log persist Dockerfile* -dist \ No newline at end of file +dist +yarn-error.log \ No newline at end of file diff --git a/backend/Dockerfile b/backend/Dockerfile index d11771bbd..1b0ff2541 100644 --- a/backend/Dockerfile +++ b/backend/Dockerfile @@ -16,6 +16,7 @@ RUN yarn --network-timeout 1000000 install COPY ./ ./ RUN yarn build +RUN rm -rf ./src EXPOSE ${BACKEND_PORT} CMD [ "yarn", "backend-production" ] diff --git a/backend/Makefile b/backend/Makefile new file mode 100644 index 000000000..4117e8912 --- /dev/null +++ b/backend/Makefile @@ -0,0 +1,2 @@ +build: + docker build -t retrospected/backend:local . \ No newline at end of file diff --git a/backend/package.json b/backend/package.json index 22c73a793..d51062c6c 100644 --- a/backend/package.json +++ b/backend/package.json @@ -1,19 +1,20 @@ { "name": "@retrospected/backend", - "version": "4.11.5", + "version": "4.12.0", "license": "GNU GPLv3", "private": true, "scripts": { "build": "rimraf dist && tsc --build", "start": "nodemon --exec 'yarn fix & ts-node' --files ./src/index.ts", - "backend-production": "yarn migrate && cd ./dist/src && node index.js", - "create-migration": "ts-node ./src/init.ts --ts && ts-node ./node_modules/typeorm/cli.js migration:generate -n ", - "migrate": "node ./dist/src/init.js && node ./node_modules/typeorm/cli.js migration:run", - "revert": "node ./dist/src/init.js && node ./node_modules/typeorm/cli.js migration:revert", + "create-migration": "ts-node ./node_modules/typeorm/cli.js --config src/db/orm-config.ts migration:generate -n ", + "migrate": "ts-node ./node_modules/typeorm/cli.js --config src/db/orm-config.ts migration:run", + "revert": "ts-node ./node_modules/typeorm/cli.js --config src/db/orm-config.ts migration:revert", "lint": "eslint 'src/**/*.ts'", "test": "yarn jest", "ci-test": "CI=true yarn test", - "fix": "eslint 'src/**/*.ts' --fix" + "fix": "eslint 'src/**/*.ts' --fix", + "backend-production": "yarn migrate-production && cd ./dist/src && node index.js", + "migrate-production": "node ./node_modules/typeorm/cli.js --config dist/src/db/orm-config.js migration:run" }, "dependencies": { "@sendgrid/mail": "7.6.0", @@ -25,11 +26,9 @@ "@types/express": "4.17.13", "@types/express-mung": "0.5.2", "@types/express-rate-limit": "6.0.0", - "@types/express-serve-static-core": "4.17.28", "@types/express-session": "1.17.4", "@types/jest": "27.4.0", "@types/lodash": "4.14.178", - "@types/md5": "2.3.1", "@types/node": "17.0.10", "@types/node-fetch": "2.5.12", "@types/passport": "1.0.7", @@ -44,10 +43,8 @@ "@typescript-eslint/eslint-plugin": "5.10.0", "@typescript-eslint/parser": "5.10.0", "bcryptjs": "2.4.3", - "body-parser": "1.19.1", "chalk": "4.1.2", "connect-redis": "6.0.0", - "cross-env": "7.0.3", "crypto-js": "4.1.1", "csurf": "1.11.0", "date-fns": "2.28.0", @@ -63,7 +60,6 @@ "jest": "27.4.7", "lexorank": "1.0.4", "lodash": "4.17.21", - "md5": "2.3.0", "moment": "2.29.1", "node-fetch": "2.6.1", "nodemon": "2.0.15", @@ -87,9 +83,9 @@ "ts-jest": "27.1.3", "ts-node": "10.4.0", "typeorm": "0.2.41", + "typeorm-naming-strategies": "^2.0.0", "typescript": "4.5.4", - "uuid": "8.3.2", - "yargs": "17.3.1" + "uuid": "8.3.2" }, "resolutions": { "@types/connect-redis": "0.0.18", diff --git a/backend/src/build-config.ts b/backend/src/build-config.ts deleted file mode 100644 index e95e49e59..000000000 --- a/backend/src/build-config.ts +++ /dev/null @@ -1,46 +0,0 @@ -import getOrmConfig from './db/orm-config'; -import path from 'path'; -import fs from 'fs'; -import yargs from 'yargs/yargs'; -import { hideBin } from 'yargs/helpers'; - -const argv = yargs(hideBin(process.argv)).argv; - -async function buildOrmConfig() { - if (argv.ts) { - console.log('Creating TypeScript ormconfig.json before migrations'); - await buildOrmConfigTs(); - } else { - console.log('Creating JavaScript ormconfig.json before migrations'); - await buildOrmConfigJs(); - } -} - -async function buildOrmConfigJs() { - const config = getConfig('js'); - const jsonPath = path.resolve(__dirname, '..', '..', 'ormconfig.json'); - fs.writeFileSync(jsonPath, JSON.stringify(config, null, 2)); -} - -async function buildOrmConfigTs() { - const config = getConfig('ts'); - const jsonPath = path.resolve(__dirname, '..', 'ormconfig.json'); - fs.writeFileSync(jsonPath, JSON.stringify(config, null, 2)); -} - -function getConfig(extension: 'js' | 'ts') { - const rootPath = path.resolve(__dirname); - const entities = path.resolve(rootPath, 'db', 'entities'); - const migrations = - extension === 'ts' ? 'src/db/migrations' : 'dist/src/db/migrations'; - - const config = getOrmConfig({ - entities: [`${entities}/*.${extension}`], - migrations: [`${migrations}/*.${extension}`], - migrationDir: migrations, - }); - - return config; -} - -export default buildOrmConfig; diff --git a/backend/src/db/actions/delete.ts b/backend/src/db/actions/delete.ts index 4d01417eb..c294db5b7 100644 --- a/backend/src/db/actions/delete.ts +++ b/backend/src/db/actions/delete.ts @@ -42,10 +42,10 @@ async function deleteVisits( anon: UserIdentityEntity ) { if (hardDelete) { - await manager.query('delete from visitors where "usersId" = $1', [user.id]); + await manager.query('delete from visitors where users_id = $1', [user.id]); } else { await manager.query( - 'update visitors set "usersId" = $1 where "usersId" = $2', + 'update visitors set users_id = $1 where users_id = $2', [anon.user.id, user.id] ); } @@ -78,13 +78,13 @@ async function deletePosts( if (hardDelete) { await manager.query( ` - delete from votes where "postId" in (select id from posts where "userId" = $1) + delete from votes where post_id in (select id from posts where user_id = $1) `, [user.id] ); await manager.query( ` - update posts set "groupId" = null where "groupId" in (select id from groups where "userId" = $1) + update posts set group_id = null where group_id in (select id from groups where user_id = $1) `, [user.id] ); @@ -108,25 +108,25 @@ async function deleteSessions( if (hardDelete) { await manager.query( ` - delete from votes where "postId" in (select id from posts where "sessionId" in (select id from sessions where "createdById" = $1)) + delete from votes where post_id in (select id from posts where session_id in (select id from sessions where created_by_id = $1)) `, [user.id] ); await manager.query( ` - delete from posts where "sessionId" in (select id from sessions where "createdById" = $1) + delete from posts where session_id in (select id from sessions where created_by_id = $1) `, [user.id] ); await manager.query( ` - delete from groups where "sessionId" in (select id from sessions where "createdById" = $1) + delete from groups where session_id in (select id from sessions where created_by_id = $1) `, [user.id] ); await manager.query( ` - delete from columns where "sessionId" in (select id from sessions where "createdById" = $1) + delete from columns where session_id in (select id from sessions where created_by_id = $1) `, [user.id] ); @@ -141,21 +141,21 @@ async function deleteSessions( async function deleteUserAccount(manager: EntityManager, user: UserView) { await manager.query( ` - update users set "defaultTemplateId" = null where "defaultTemplateId" in (select id from templates where "createdById" = $1) + update users set default_template_id = null where default_template_id in (select id from templates where created_by_id = $1) `, [user.id] ); await manager.query( - 'delete from "templates-columns" where "templateId" in (select id from templates where "createdById" = $1)', + 'delete from templates_columns where template_id in (select id from templates where created_by_id = $1)', [user.id] ); - await manager.query('delete from templates where "createdById" = $1', [ + await manager.query('delete from templates where created_by_id = $1', [ user.id, ]); - await manager.query('delete from subscriptions where "ownerId" = $1', [ + await manager.query('delete from subscriptions where owner_id = $1', [ user.id, ]); - await manager.query('delete from users_identities where "userId" = $1', [ + await manager.query('delete from users_identities where user_id = $1', [ user.id, ]); await manager.query('delete from users where id = $1', [user.id]); diff --git a/backend/src/db/actions/sessions.ts b/backend/src/db/actions/sessions.ts index 61d192fe9..d64058126 100644 --- a/backend/src/db/actions/sessions.ts +++ b/backend/src/db/actions/sessions.ts @@ -227,20 +227,19 @@ export async function deleteSessions( return false; } await sessionRepository.query( - `delete from visitors where "sessionsId" = $1;`, + `delete from visitors where sessions_id = $1;`, [sessionId] ); - await sessionRepository.query(`delete from posts where "sessionId" = $1;`, [ + await sessionRepository.query(`delete from posts where session_id = $1;`, [ sessionId, ]); await sessionRepository.query( - `delete from columns where "sessionId" = $1;`, - [sessionId] - ); - await sessionRepository.query( - `delete from groups where "sessionId" = $1;`, + `delete from columns where session_id = $1;`, [sessionId] ); + await sessionRepository.query(`delete from groups where session_id = $1;`, [ + sessionId, + ]); await sessionRepository.query(`delete from sessions where id = $1;`, [ sessionId, ]); @@ -255,8 +254,8 @@ export async function previousSessions( return await transaction(async (manager) => { const sessionsAsVisitors: { sessionsId: string }[] = await manager.query( ` - select distinct v."sessionsId" from visitors v - where v."usersId" = $1 + select distinct v.sessions_id from visitors v + where v.users_id = $1 `, [userId] ); @@ -264,7 +263,7 @@ export async function previousSessions( const sessionsAsOwner: { id: string }[] = await manager.query( ` select s.id from sessions s - where s."createdById" = $1 + where s.created_by_id = $1 `, [userId] ); diff --git a/backend/src/db/entities/ColumnDefinition.ts b/backend/src/db/entities/ColumnDefinition.ts index a35d5b90c..cece958b9 100644 --- a/backend/src/db/entities/ColumnDefinition.ts +++ b/backend/src/db/entities/ColumnDefinition.ts @@ -5,6 +5,7 @@ import { ManyToOne, CreateDateColumn, UpdateDateColumn, + Index, } from 'typeorm'; import { IconName, ColumnDefinition, ColumnDefinitionType } from '../../common'; import SessionEntity from './Session'; @@ -59,6 +60,7 @@ class ColumnDefinitionEntityBase { @Entity({ name: 'columns' }) export class ColumnDefinitionEntity extends ColumnDefinitionEntityBase { @ManyToOne(() => SessionEntity, { nullable: false }) + @Index() public session: SessionEntity; constructor( id: string, @@ -74,9 +76,10 @@ export class ColumnDefinitionEntity extends ColumnDefinitionEntityBase { } } -@Entity({ name: 'templates-columns' }) +@Entity({ name: 'templates_columns' }) export class TemplateColumnDefinitionEntity extends ColumnDefinitionEntityBase { @ManyToOne(() => SessionTemplateEntity, { nullable: false }) + @Index() public template: SessionTemplateEntity; constructor( id: string, diff --git a/backend/src/db/entities/Licence.ts b/backend/src/db/entities/Licence.ts index 24aa714e7..52970ac5c 100644 --- a/backend/src/db/entities/Licence.ts +++ b/backend/src/db/entities/Licence.ts @@ -4,6 +4,7 @@ import { PrimaryColumn, CreateDateColumn, UpdateDateColumn, + Index, } from 'typeorm'; @Entity({ name: 'licences' }) @@ -11,6 +12,7 @@ export default class LicenceEntity { @PrimaryColumn({ primary: true, generated: false, unique: true }) public id: string; @Column({ nullable: true, type: 'character varying' }) + @Index() public email: string | null; @Column({ nullable: false }) public key: string; diff --git a/backend/src/db/entities/SessionView.ts b/backend/src/db/entities/SessionView.ts index bc40ed066..020aaeb15 100644 --- a/backend/src/db/entities/SessionView.ts +++ b/backend/src/db/entities/SessionView.ts @@ -10,28 +10,28 @@ select ( select to_jsonb(cb) from ( select cbu.id, cbu.name, cbu.photo from users cbu - where cbu.id = s."createdById" + where cbu.id = s.created_by_id ) as cb - ) as "createdBy", + ) as created_by, s.encrypted, s.locked, - (select count(*) from posts p where p."sessionId" = s.id and p.action is not null) as "numberOfActions", - (select count(*) from posts p where p."sessionId" = s.id) as "numberOfPosts", + (select count(*) from posts p where p.session_id = s.id and p.action is not null) as "number_of_actions", + (select count(*) from posts p where p.session_id = s.id) as "number_of_posts", ( select count(*) from votes vv - left join posts vp on vp.id = vv."postId" - where vp."sessionId" = s.id - ) as "numberOfVotes", + left join posts vp on vp.id = vv.post_id + where vp.session_id = s.id + ) as "number_of_votes", ( select json_agg(vis) from ( select vu.id, vu.name, vu.photo from visitors v - join users vu on vu.id = v."usersId" - where v."sessionsId" = s.id + join users vu on vu.id = v.users_id + where v.sessions_id = s.id ) as vis ) as participants from sessions s -left join users u on s."createdById" = u.id +left join users u on s.created_by_id = u.id order by s.updated desc `, diff --git a/backend/src/db/entities/UserView.ts b/backend/src/db/entities/UserView.ts index 81a459f7b..3edf666c5 100644 --- a/backend/src/db/entities/UserView.ts +++ b/backend/src/db/entities/UserView.ts @@ -3,29 +3,29 @@ import { AccountType, FullUser, Currency, Plan } from '../../common'; @ViewEntity({ expression: ` - select +select u.id, - i.id as "identityId", + i.id as identity_id, u.name, - i."accountType", + i.account_type, i.username, u.currency, - u."stripeId", + u.stripe_id, i.photo, u.language, u.email, - case when i."accountType" = 'anonymous' and i.password is null then false else true end as "canDeleteSession", + case when i.account_type = 'anonymous' and i.password is null then false else true end as "can_delete_session", u.trial, - s.id as "ownSubscriptionsId", - s.plan as "ownPlan", - coalesce(s.id, s2.id, s3.id) as "subscriptionsId", + s.id as "own_subscriptions_id", + s.plan as "own_plan", + coalesce(s.id, s2.id, s3.id) as "subscriptions_id", coalesce(s.active, s2.active, s3.active, false) as "pro", coalesce(s.plan, s2.plan, s3.plan) as "plan", coalesce(s.domain, s2.domain, s3.domain) as "domain" from users_identities i -join users u on u.id = i."userId" -left join subscriptions s on s."ownerId" = u.id and s.active is true +join users u on u.id = i.user_id +left join subscriptions s on s.owner_id = u.id and s.active is true left join subscriptions s2 on lower(u.email) = any(lower(s2.members::text)::text[]) and s2.active is true left join subscriptions s3 on s3.domain = split_part(u.email, '@', 2) and s3.active is true `, diff --git a/backend/src/db/index.ts b/backend/src/db/index.ts index 6f9cd026b..50adacd35 100644 --- a/backend/src/db/index.ts +++ b/backend/src/db/index.ts @@ -1,9 +1,9 @@ import 'reflect-metadata'; import chalk from 'chalk'; import { createConnection } from 'typeorm'; -import getOrmConfig from './orm-config'; +import ormConfig from './orm-config'; export default async function getDb(): Promise { console.log(chalk`{yellow 💻 Using {red Postgres} database}`); - await createConnection(getOrmConfig()); + await createConnection(ormConfig); } diff --git a/backend/src/db/migrations/1643049742051-BigRenaming.ts b/backend/src/db/migrations/1643049742051-BigRenaming.ts new file mode 100644 index 000000000..fb984328b --- /dev/null +++ b/backend/src/db/migrations/1643049742051-BigRenaming.ts @@ -0,0 +1,920 @@ +import { MigrationInterface, QueryRunner } from 'typeorm'; + +export class BigRenaming1643049742051 implements MigrationInterface { + name = 'BigRenaming1643049742051'; + + public async up(queryRunner: QueryRunner): Promise { + /** + * RENAMING COLUMNS + */ + await queryRunner.query( + `ALTER TABLE "users_identities" DROP CONSTRAINT "FK_a10dca6aa6bda5865287bf2792a"` + ); + await queryRunner.query( + `ALTER TABLE "users" DROP CONSTRAINT "FK_5b086b03bb64304390cec7635ec"` + ); + await queryRunner.query( + `ALTER TABLE "templates" DROP CONSTRAINT "FK_c58b12b1a7b4012bb238bc26542"` + ); + await queryRunner.query( + `ALTER TABLE "columns" DROP CONSTRAINT "FK_37907d102f38ece687182bf5237"` + ); + await queryRunner.query( + `ALTER TABLE "templates-columns" DROP CONSTRAINT "FK_c96b807f7154ddb4fb7017af12e"` + ); + await queryRunner.query( + `ALTER TABLE "groups" DROP CONSTRAINT "FK_9ad140fba0b4ad9559e65302825"` + ); + await queryRunner.query( + `ALTER TABLE "groups" DROP CONSTRAINT "FK_898cf6af34722df13f760cc364f"` + ); + await queryRunner.query( + `ALTER TABLE "messages" DROP CONSTRAINT "FK_066163c46cda7e8187f96bc87a0"` + ); + await queryRunner.query( + `ALTER TABLE "messages" DROP CONSTRAINT "FK_4838cd4fc48a6ff2d4aa01aa646"` + ); + await queryRunner.query( + `ALTER TABLE "sessions" DROP CONSTRAINT "FK_d26fe2e6102cd9c47650a0d7a6f"` + ); + await queryRunner.query( + `ALTER TABLE "votes" DROP CONSTRAINT "FK_5169384e31d0989699a318f3ca4"` + ); + await queryRunner.query( + `ALTER TABLE "votes" DROP CONSTRAINT "FK_b5b05adc89dda0614276a13a599"` + ); + await queryRunner.query( + `ALTER TABLE "posts" DROP CONSTRAINT "FK_764b665f832e28c01595ec15cf3"` + ); + await queryRunner.query( + `ALTER TABLE "posts" DROP CONSTRAINT "FK_ae05faaa55c866130abef6e1fee"` + ); + await queryRunner.query( + `ALTER TABLE "posts" DROP CONSTRAINT "FK_d10acbe503da4c56853181efc98"` + ); + await queryRunner.query( + `ALTER TABLE "subscriptions" DROP CONSTRAINT "FK_331400b3a08ee505d42ddba1db0"` + ); + await queryRunner.query( + `ALTER TABLE "visitors" DROP CONSTRAINT "FK_89c90edf2f369cfbcb220d2e09f"` + ); + await queryRunner.query( + `ALTER TABLE "visitors" DROP CONSTRAINT "FK_d50229c10adbf294a228c35cb19"` + ); + await queryRunner.query( + `DROP INDEX "public"."IDX_3c67bd4e6a014698751d9242e3"` + ); + await queryRunner.query( + `DROP INDEX "public"."IDX_a10dca6aa6bda5865287bf2792"` + ); + await queryRunner.query( + `DROP INDEX "public"."IDX_5b086b03bb64304390cec7635e"` + ); + await queryRunner.query( + `DROP INDEX "public"."IDX_c58b12b1a7b4012bb238bc2654"` + ); + await queryRunner.query( + `DROP INDEX "public"."IDX_898cf6af34722df13f760cc364"` + ); + await queryRunner.query( + `DROP INDEX "public"."IDX_9ad140fba0b4ad9559e6530282"` + ); + await queryRunner.query( + `DROP INDEX "public"."IDX_066163c46cda7e8187f96bc87a"` + ); + await queryRunner.query( + `DROP INDEX "public"."IDX_4838cd4fc48a6ff2d4aa01aa64"` + ); + await queryRunner.query( + `DROP INDEX "public"."IDX_d26fe2e6102cd9c47650a0d7a6"` + ); + await queryRunner.query( + `DROP INDEX "public"."IDX_5169384e31d0989699a318f3ca"` + ); + await queryRunner.query( + `DROP INDEX "public"."IDX_b5b05adc89dda0614276a13a59"` + ); + await queryRunner.query( + `DROP INDEX "public"."IDX_764b665f832e28c01595ec15cf"` + ); + await queryRunner.query( + `DROP INDEX "public"."IDX_ae05faaa55c866130abef6e1fe"` + ); + await queryRunner.query( + `DROP INDEX "public"."IDX_d10acbe503da4c56853181efc9"` + ); + await queryRunner.query( + `DROP INDEX "public"."IDX_331400b3a08ee505d42ddba1db"` + ); + await queryRunner.query( + `DROP INDEX "public"."IDX_89c90edf2f369cfbcb220d2e09"` + ); + await queryRunner.query( + `DROP INDEX "public"."IDX_d50229c10adbf294a228c35cb1"` + ); + await queryRunner.query( + `ALTER TABLE "columns" RENAME COLUMN "sessionId" TO "session_id"` + ); + await queryRunner.query( + `ALTER TABLE "templates-columns" RENAME COLUMN "templateId" TO "template_id"` + ); + await queryRunner.query( + `ALTER TABLE "subscriptions" RENAME COLUMN "ownerId" TO "owner_id"` + ); + await queryRunner.query( + `ALTER TABLE "users_identities" RENAME COLUMN "accountType" TO "account_type"` + ); + await queryRunner.query( + `ALTER TABLE "users_identities" RENAME COLUMN "emailVerification" TO "email_verification"` + ); + await queryRunner.query( + `ALTER TABLE "users_identities" RENAME COLUMN "userId" TO "user_id"` + ); + await queryRunner.query( + `ALTER TABLE "users" RENAME COLUMN "defaultTemplateId" TO "default_template_id"` + ); + await queryRunner.query( + `ALTER TABLE "users" RENAME COLUMN "stripeId" TO "stripe_id"` + ); + await queryRunner.query( + `ALTER TABLE "users" RENAME COLUMN "slackUserId" TO "slack_user_id"` + ); + await queryRunner.query( + `ALTER TABLE "users" RENAME COLUMN "slackTeamId" TO "slack_team_id"` + ); + await queryRunner.query( + `ALTER TABLE "templates" RENAME COLUMN "createdById" TO "created_by_id"` + ); + await queryRunner.query( + `ALTER TABLE "templates" RENAME COLUMN "optionsMaxupvotes" TO "options_max_up_votes"` + ); + await queryRunner.query( + `ALTER TABLE "templates" RENAME COLUMN "optionsMaxdownvotes" TO "options_max_down_votes"` + ); + await queryRunner.query( + `ALTER TABLE "templates" RENAME COLUMN "optionsAllowactions" TO "options_allow_actions"` + ); + await queryRunner.query( + `ALTER TABLE "templates" RENAME COLUMN "optionsAllowselfvoting" TO "options_allow_self_voting"` + ); + await queryRunner.query( + `ALTER TABLE "templates" RENAME COLUMN "optionsAllowmultiplevotes" TO "options_allow_multiple_votes"` + ); + await queryRunner.query( + `ALTER TABLE "templates" RENAME COLUMN "optionsAllowauthorvisible" TO "options_allow_author_visible"` + ); + await queryRunner.query( + `ALTER TABLE "templates" RENAME COLUMN "optionsAllowgiphy" TO "options_allow_giphy"` + ); + await queryRunner.query( + `ALTER TABLE "templates" RENAME COLUMN "optionsAllowgrouping" TO "options_allow_grouping"` + ); + await queryRunner.query( + `ALTER TABLE "templates" RENAME COLUMN "optionsAllowreordering" TO "options_allow_reordering"` + ); + await queryRunner.query( + `ALTER TABLE "templates" RENAME COLUMN "optionsBlurcards" TO "options_blur_cards"` + ); + await queryRunner.query( + `ALTER TABLE "templates" RENAME COLUMN "optionsMaxposts" TO "options_max_posts"` + ); + await queryRunner.query( + `ALTER TABLE "templates" RENAME COLUMN "optionsNewpostsfirst" TO "options_new_posts_first"` + ); + await queryRunner.query( + `ALTER TABLE "groups" RENAME COLUMN "sessionId" TO "session_id"` + ); + await queryRunner.query( + `ALTER TABLE "groups" RENAME COLUMN "userId" TO "user_id"` + ); + await queryRunner.query( + `ALTER TABLE "messages" RENAME COLUMN "sessionId" TO "session_id"` + ); + await queryRunner.query( + `ALTER TABLE "messages" RENAME COLUMN "userId" TO "user_id"` + ); + await queryRunner.query( + `ALTER TABLE "sessions" RENAME COLUMN "createdById" TO "created_by_id"` + ); + await queryRunner.query( + `ALTER TABLE "sessions" RENAME COLUMN "optionsMaxupvotes" TO "options_max_up_votes"` + ); + await queryRunner.query( + `ALTER TABLE "sessions" RENAME COLUMN "optionsMaxdownvotes" TO "options_max_down_votes"` + ); + await queryRunner.query( + `ALTER TABLE "sessions" RENAME COLUMN "optionsAllowactions" TO "options_allow_actions"` + ); + await queryRunner.query( + `ALTER TABLE "sessions" RENAME COLUMN "optionsAllowselfvoting" TO "options_allow_self_voting"` + ); + await queryRunner.query( + `ALTER TABLE "sessions" RENAME COLUMN "optionsAllowmultiplevotes" TO "options_allow_multiple_votes"` + ); + await queryRunner.query( + `ALTER TABLE "sessions" RENAME COLUMN "optionsAllowauthorvisible" TO "options_allow_author_visible"` + ); + await queryRunner.query( + `ALTER TABLE "sessions" RENAME COLUMN "optionsAllowgiphy" TO "options_allow_giphy"` + ); + await queryRunner.query( + `ALTER TABLE "sessions" RENAME COLUMN "optionsAllowgrouping" TO "options_allow_grouping"` + ); + await queryRunner.query( + `ALTER TABLE "sessions" RENAME COLUMN "optionsAllowreordering" TO "options_allow_reordering"` + ); + await queryRunner.query( + `ALTER TABLE "sessions" RENAME COLUMN "optionsBlurcards" TO "options_blur_cards"` + ); + await queryRunner.query( + `ALTER TABLE "sessions" RENAME COLUMN "optionsMaxposts" TO "options_max_posts"` + ); + await queryRunner.query( + `ALTER TABLE "sessions" RENAME COLUMN "optionsNewpostsfirst" TO "options_new_posts_first"` + ); + await queryRunner.query( + `ALTER TABLE "votes" RENAME COLUMN "userId" TO "user_id"` + ); + await queryRunner.query( + `ALTER TABLE "votes" RENAME COLUMN "postId" TO "post_id"` + ); + await queryRunner.query( + `ALTER TABLE "posts" RENAME COLUMN "sessionId" TO "session_id"` + ); + await queryRunner.query( + `ALTER TABLE "posts" RENAME COLUMN "userId" TO "user_id"` + ); + await queryRunner.query( + `ALTER TABLE "posts" RENAME COLUMN "groupId" TO "group_id"` + ); + await queryRunner.query( + `ALTER TABLE "licences" RENAME COLUMN "stripeCustomerId" TO "stripe_customer_id"` + ); + await queryRunner.query( + `ALTER TABLE "licences" RENAME COLUMN "stripeSessionId" TO "stripe_session_id"` + ); + await queryRunner.query( + `ALTER TABLE "visitors" DROP CONSTRAINT IF EXISTS "PK_c16501c34b8530a425739e400bd"` + ); + await queryRunner.query( + `ALTER TABLE "visitors" RENAME COLUMN "sessionsId" to "sessions_id"` + ); + await queryRunner.query( + `ALTER TABLE "visitors" RENAME COLUMN "usersId" to "users_id"` + ); + await queryRunner.query( + `ALTER TABLE "visitors" ADD CONSTRAINT "PK_96af66c2594330cf6578ef210c2" PRIMARY KEY ("sessions_id", "users_id")` + ); + await queryRunner.query( + `CREATE INDEX "IDX_b3b8654b4e2311526fcefdb9ce" ON "users_identities" ("user_id") ` + ); + await queryRunner.query( + `CREATE UNIQUE INDEX "IDX_de8111fd70689bb6934b7650e5" ON "users_identities" ("username", "account_type") ` + ); + await queryRunner.query( + `CREATE INDEX "IDX_ac509eeb1d008dda662c19bc2a" ON "users" ("default_template_id") ` + ); + await queryRunner.query( + `CREATE INDEX "IDX_7fe85a796a57a6cccfaa2dff03" ON "templates" ("created_by_id") ` + ); + await queryRunner.query( + `CREATE INDEX "IDX_4e97c4fa8c699264016d1a4d92" ON "groups" ("session_id") ` + ); + await queryRunner.query( + `CREATE INDEX "IDX_9f71bda715870718997ed62f64" ON "groups" ("user_id") ` + ); + await queryRunner.query( + `CREATE INDEX "IDX_ff71b7760071ed9caba7f02beb" ON "messages" ("session_id") ` + ); + await queryRunner.query( + `CREATE INDEX "IDX_830a3c1d92614d1495418c4673" ON "messages" ("user_id") ` + ); + await queryRunner.query( + `CREATE INDEX "IDX_1ccf045da14e5350b26ee88259" ON "sessions" ("created_by_id") ` + ); + await queryRunner.query( + `CREATE INDEX "IDX_27be2cab62274f6876ad6a3164" ON "votes" ("user_id") ` + ); + await queryRunner.query( + `CREATE INDEX "IDX_18499a5b9b4cf71093f7b7f79f" ON "votes" ("post_id") ` + ); + await queryRunner.query( + `CREATE INDEX "IDX_5b08cabd478d3eb9fcc657d426" ON "posts" ("session_id") ` + ); + await queryRunner.query( + `CREATE INDEX "IDX_7628aa3741a30d6217271a226c" ON "posts" ("group_id") ` + ); + await queryRunner.query( + `CREATE INDEX "IDX_c4f9a7bd77b489e711277ee598" ON "posts" ("user_id") ` + ); + await queryRunner.query( + `CREATE INDEX "IDX_7dc6f309358b04777f86d1f3fe" ON "subscriptions" ("owner_id") ` + ); + await queryRunner.query( + `CREATE INDEX "IDX_93910938d4f16f57a137da768b" ON "visitors" ("sessions_id") ` + ); + await queryRunner.query( + `CREATE INDEX "IDX_44b69e6f1b8c5328046a6f6a2c" ON "visitors" ("users_id") ` + ); + await queryRunner.query( + `ALTER TABLE "users_identities" ADD CONSTRAINT "FK_b3b8654b4e2311526fcefdb9ce8" FOREIGN KEY ("user_id") REFERENCES "users"("id") ON DELETE CASCADE ON UPDATE CASCADE` + ); + await queryRunner.query( + `ALTER TABLE "users" ADD CONSTRAINT "FK_ac509eeb1d008dda662c19bc2a3" FOREIGN KEY ("default_template_id") REFERENCES "templates"("id") ON DELETE NO ACTION ON UPDATE NO ACTION` + ); + await queryRunner.query( + `ALTER TABLE "templates" ADD CONSTRAINT "FK_7fe85a796a57a6cccfaa2dff03c" FOREIGN KEY ("created_by_id") REFERENCES "users"("id") ON DELETE NO ACTION ON UPDATE NO ACTION` + ); + await queryRunner.query( + `ALTER TABLE "columns" ADD CONSTRAINT "FK_9f5aedb06b838d50b1b4a56e042" FOREIGN KEY ("session_id") REFERENCES "sessions"("id") ON DELETE NO ACTION ON UPDATE NO ACTION` + ); + await queryRunner.query( + `ALTER TABLE "templates-columns" ADD CONSTRAINT "FK_f5ccf851c3134ac587eb4e794d9" FOREIGN KEY ("template_id") REFERENCES "templates"("id") ON DELETE NO ACTION ON UPDATE NO ACTION` + ); + await queryRunner.query( + `ALTER TABLE "groups" ADD CONSTRAINT "FK_4e97c4fa8c699264016d1a4d929" FOREIGN KEY ("session_id") REFERENCES "sessions"("id") ON DELETE NO ACTION ON UPDATE NO ACTION` + ); + await queryRunner.query( + `ALTER TABLE "groups" ADD CONSTRAINT "FK_9f71bda715870718997ed62f64b" FOREIGN KEY ("user_id") REFERENCES "users"("id") ON DELETE NO ACTION ON UPDATE NO ACTION` + ); + await queryRunner.query( + `ALTER TABLE "messages" ADD CONSTRAINT "FK_ff71b7760071ed9caba7f02beb4" FOREIGN KEY ("session_id") REFERENCES "sessions"("id") ON DELETE NO ACTION ON UPDATE NO ACTION` + ); + await queryRunner.query( + `ALTER TABLE "messages" ADD CONSTRAINT "FK_830a3c1d92614d1495418c46736" FOREIGN KEY ("user_id") REFERENCES "users"("id") ON DELETE NO ACTION ON UPDATE NO ACTION` + ); + await queryRunner.query( + `ALTER TABLE "sessions" ADD CONSTRAINT "FK_1ccf045da14e5350b26ee882592" FOREIGN KEY ("created_by_id") REFERENCES "users"("id") ON DELETE NO ACTION ON UPDATE NO ACTION` + ); + await queryRunner.query( + `ALTER TABLE "votes" ADD CONSTRAINT "FK_27be2cab62274f6876ad6a31641" FOREIGN KEY ("user_id") REFERENCES "users"("id") ON DELETE NO ACTION ON UPDATE NO ACTION` + ); + await queryRunner.query( + `ALTER TABLE "votes" ADD CONSTRAINT "FK_18499a5b9b4cf71093f7b7f79f8" FOREIGN KEY ("post_id") REFERENCES "posts"("id") ON DELETE CASCADE ON UPDATE CASCADE` + ); + await queryRunner.query( + `ALTER TABLE "posts" ADD CONSTRAINT "FK_5b08cabd478d3eb9fcc657d4269" FOREIGN KEY ("session_id") REFERENCES "sessions"("id") ON DELETE NO ACTION ON UPDATE NO ACTION` + ); + await queryRunner.query( + `ALTER TABLE "posts" ADD CONSTRAINT "FK_7628aa3741a30d6217271a226cf" FOREIGN KEY ("group_id") REFERENCES "groups"("id") ON DELETE SET NULL ON UPDATE CASCADE` + ); + await queryRunner.query( + `ALTER TABLE "posts" ADD CONSTRAINT "FK_c4f9a7bd77b489e711277ee5986" FOREIGN KEY ("user_id") REFERENCES "users"("id") ON DELETE NO ACTION ON UPDATE NO ACTION` + ); + await queryRunner.query( + `ALTER TABLE "subscriptions" ADD CONSTRAINT "FK_7dc6f309358b04777f86d1f3fef" FOREIGN KEY ("owner_id") REFERENCES "users"("id") ON DELETE NO ACTION ON UPDATE NO ACTION` + ); + await queryRunner.query( + `ALTER TABLE "visitors" ADD CONSTRAINT "FK_93910938d4f16f57a137da768b3" FOREIGN KEY ("sessions_id") REFERENCES "sessions"("id") ON DELETE CASCADE ON UPDATE CASCADE` + ); + await queryRunner.query( + `ALTER TABLE "visitors" ADD CONSTRAINT "FK_44b69e6f1b8c5328046a6f6a2c0" FOREIGN KEY ("users_id") REFERENCES "users"("id") ON DELETE NO ACTION ON UPDATE NO ACTION` + ); + + /** + * VIEWS UPDATE + */ + await queryRunner.query( + `DELETE FROM "typeorm_metadata" WHERE "type" = $1 AND "name" = $2 AND "schema" = $3`, + ['VIEW', 'user_view', 'public'] + ); + await queryRunner.query(`DROP VIEW "user_view"`); + await queryRunner.query(`CREATE VIEW "user_view" AS +select + u.id, + i.id as identity_id, + u.name, + i.account_type, + i.username, + u.currency, + u.stripe_id, + i.photo, + u.language, + u.email, + case when i.account_type = 'anonymous' and i.password is null then false else true end as "can_delete_session", + u.trial, + s.id as "own_subscriptions_id", + s.plan as "own_plan", + coalesce(s.id, s2.id, s3.id) as "subscriptions_id", + coalesce(s.active, s2.active, s3.active, false) as "pro", + coalesce(s.plan, s2.plan, s3.plan) as "plan", + coalesce(s.domain, s2.domain, s3.domain) as "domain" +from users_identities i + +join users u on u.id = i.user_id +left join subscriptions s on s.owner_id = u.id and s.active is true +left join subscriptions s2 on lower(u.email) = any(lower(s2.members::text)::text[]) and s2.active is true +left join subscriptions s3 on s3.domain = split_part(u.email, '@', 2) and s3.active is true + `); + await queryRunner.query( + `INSERT INTO "typeorm_metadata"("database", "schema", "table", "type", "name", "value") VALUES (DEFAULT, $1, DEFAULT, $2, $3, $4)`, + [ + 'public', + 'VIEW', + 'user_view', + 'select \n u.id,\n i.id as identity_id,\n u.name,\n i.account_type,\n i.username,\n u.currency,\n u.stripe_id,\n i.photo,\n u.language,\n u.email,\n case when i.account_type = \'anonymous\' and i.password is null then false else true end as "can_delete_session",\n u.trial,\n s.id as "own_subscriptions_id",\n s.plan as "own_plan",\n coalesce(s.id, s2.id, s3.id) as "subscriptions_id",\n coalesce(s.active, s2.active, s3.active, false) as "pro",\n coalesce(s.plan, s2.plan, s3.plan) as "plan",\n coalesce(s.domain, s2.domain, s3.domain) as "domain"\nfrom users_identities i\n\njoin users u on u.id = i.user_id\nleft join subscriptions s on s.owner_id = u.id and s.active is true\nleft join subscriptions s2 on lower(u.email) = any(lower(s2.members::text)::text[]) and s2.active is true\nleft join subscriptions s3 on s3.domain = split_part(u.email, \'@\', 2) and s3.active is true', + ] + ); + + await queryRunner.query( + `DELETE FROM "typeorm_metadata" WHERE "type" = $1 AND "name" = $2 AND "schema" = $3`, + ['VIEW', 'session_view', 'public'] + ); + await queryRunner.query(`DROP VIEW "session_view"`); + await queryRunner.query(`CREATE VIEW "session_view" AS +select + s.id, + s.name, + s.created, + ( + select to_jsonb(cb) from ( + select cbu.id, cbu.name, cbu.photo from users cbu + where cbu.id = s.created_by_id + ) as cb + ) as created_by, + s.encrypted, + s.locked, + (select count(*) from posts p where p.session_id = s.id and p.action is not null) as "number_of_actions", + (select count(*) from posts p where p.session_id = s.id) as "number_of_posts", + ( + select count(*) from votes vv + left join posts vp on vp.id = vv.post_id + where vp.session_id = s.id + ) as "number_of_votes", + ( + select json_agg(vis) from ( + select vu.id, vu.name, vu.photo from visitors v + join users vu on vu.id = v.users_id + where v.sessions_id = s.id + ) as vis + ) as participants + +from sessions s +left join users u on s.created_by_id = u.id + +order by s.updated desc + `); + await queryRunner.query( + `INSERT INTO "typeorm_metadata"("database", "schema", "table", "type", "name", "value") VALUES (DEFAULT, $1, DEFAULT, $2, $3, $4)`, + [ + 'public', + 'VIEW', + 'session_view', + 'select \n\ts.id,\n\ts.name,\n\ts.created,\n\t(\n\t\tselect to_jsonb(cb) from (\n\t\t\tselect cbu.id, cbu.name, cbu.photo from users cbu\n\t\t\twhere cbu.id = s.created_by_id\n\t\t) as cb\n\t) as created_by,\n\ts.encrypted,\n\ts.locked,\n\t(select count(*) from posts p where p.session_id = s.id and p.action is not null) as "number_of_actions",\t\n\t(select count(*) from posts p where p.session_id = s.id) as "number_of_posts",\n\t(\n\t\tselect count(*) from votes vv\n\t\tleft join posts vp on vp.id = vv.post_id\n\t\twhere vp.session_id = s.id\n\t) as "number_of_votes",\n\t(\n\t\tselect json_agg(vis) from (\n\t\t\tselect vu.id, vu.name, vu.photo from visitors v\n\t\t\tjoin users vu on vu.id = v.users_id\n\t\t\twhere v.sessions_id = s.id\n\t\t) as vis\n\t) as participants\n\nfrom sessions s\nleft join users u on s.created_by_id = u.id\n\norder by s.updated desc', + ] + ); + } + + public async down(queryRunner: QueryRunner): Promise { + await queryRunner.query( + `ALTER TABLE "visitors" DROP CONSTRAINT "FK_44b69e6f1b8c5328046a6f6a2c0"` + ); + await queryRunner.query( + `ALTER TABLE "visitors" DROP CONSTRAINT "FK_93910938d4f16f57a137da768b3"` + ); + await queryRunner.query( + `ALTER TABLE "subscriptions" DROP CONSTRAINT "FK_7dc6f309358b04777f86d1f3fef"` + ); + await queryRunner.query( + `ALTER TABLE "posts" DROP CONSTRAINT "FK_c4f9a7bd77b489e711277ee5986"` + ); + await queryRunner.query( + `ALTER TABLE "posts" DROP CONSTRAINT "FK_7628aa3741a30d6217271a226cf"` + ); + await queryRunner.query( + `ALTER TABLE "posts" DROP CONSTRAINT "FK_5b08cabd478d3eb9fcc657d4269"` + ); + await queryRunner.query( + `ALTER TABLE "votes" DROP CONSTRAINT "FK_18499a5b9b4cf71093f7b7f79f8"` + ); + await queryRunner.query( + `ALTER TABLE "votes" DROP CONSTRAINT "FK_27be2cab62274f6876ad6a31641"` + ); + await queryRunner.query( + `ALTER TABLE "sessions" DROP CONSTRAINT "FK_1ccf045da14e5350b26ee882592"` + ); + await queryRunner.query( + `ALTER TABLE "messages" DROP CONSTRAINT "FK_830a3c1d92614d1495418c46736"` + ); + await queryRunner.query( + `ALTER TABLE "messages" DROP CONSTRAINT "FK_ff71b7760071ed9caba7f02beb4"` + ); + await queryRunner.query( + `ALTER TABLE "groups" DROP CONSTRAINT "FK_9f71bda715870718997ed62f64b"` + ); + await queryRunner.query( + `ALTER TABLE "groups" DROP CONSTRAINT "FK_4e97c4fa8c699264016d1a4d929"` + ); + await queryRunner.query( + `ALTER TABLE "templates-columns" DROP CONSTRAINT "FK_f5ccf851c3134ac587eb4e794d9"` + ); + await queryRunner.query( + `ALTER TABLE "columns" DROP CONSTRAINT "FK_9f5aedb06b838d50b1b4a56e042"` + ); + await queryRunner.query( + `ALTER TABLE "templates" DROP CONSTRAINT "FK_7fe85a796a57a6cccfaa2dff03c"` + ); + await queryRunner.query( + `ALTER TABLE "users" DROP CONSTRAINT "FK_ac509eeb1d008dda662c19bc2a3"` + ); + await queryRunner.query( + `ALTER TABLE "users_identities" DROP CONSTRAINT "FK_b3b8654b4e2311526fcefdb9ce8"` + ); + await queryRunner.query( + `DROP INDEX "public"."IDX_44b69e6f1b8c5328046a6f6a2c"` + ); + await queryRunner.query( + `DROP INDEX "public"."IDX_93910938d4f16f57a137da768b"` + ); + await queryRunner.query( + `DROP INDEX "public"."IDX_7dc6f309358b04777f86d1f3fe"` + ); + await queryRunner.query( + `DROP INDEX "public"."IDX_c4f9a7bd77b489e711277ee598"` + ); + await queryRunner.query( + `DROP INDEX "public"."IDX_7628aa3741a30d6217271a226c"` + ); + await queryRunner.query( + `DROP INDEX "public"."IDX_5b08cabd478d3eb9fcc657d426"` + ); + await queryRunner.query( + `DROP INDEX "public"."IDX_18499a5b9b4cf71093f7b7f79f"` + ); + await queryRunner.query( + `DROP INDEX "public"."IDX_27be2cab62274f6876ad6a3164"` + ); + await queryRunner.query( + `DROP INDEX "public"."IDX_1ccf045da14e5350b26ee88259"` + ); + await queryRunner.query( + `DROP INDEX "public"."IDX_830a3c1d92614d1495418c4673"` + ); + await queryRunner.query( + `DROP INDEX "public"."IDX_ff71b7760071ed9caba7f02beb"` + ); + await queryRunner.query( + `DROP INDEX "public"."IDX_9f71bda715870718997ed62f64"` + ); + await queryRunner.query( + `DROP INDEX "public"."IDX_4e97c4fa8c699264016d1a4d92"` + ); + await queryRunner.query( + `DROP INDEX "public"."IDX_7fe85a796a57a6cccfaa2dff03"` + ); + await queryRunner.query( + `DROP INDEX "public"."IDX_ac509eeb1d008dda662c19bc2a"` + ); + await queryRunner.query( + `DROP INDEX "public"."IDX_de8111fd70689bb6934b7650e5"` + ); + await queryRunner.query( + `DROP INDEX "public"."IDX_b3b8654b4e2311526fcefdb9ce"` + ); + await queryRunner.query( + `ALTER TABLE "visitors" DROP CONSTRAINT "PK_96af66c2594330cf6578ef210c2"` + ); + await queryRunner.query( + `ALTER TABLE "visitors" RENAME COLUMN "users_id" to "usersId"` + ); + await queryRunner.query( + `ALTER TABLE "visitors" RENAME COLUMN "sessions_id" to "sessionsId"` + ); + await queryRunner.query( + `ALTER TABLE "licences" RENAME COLUMN "stripe_session_id" to "stripeSessionId"` + ); + await queryRunner.query( + `ALTER TABLE "licences" RENAME COLUMN "stripe_customer_id" to "stripeCustomerId"` + ); + await queryRunner.query( + `ALTER TABLE "posts" RENAME COLUMN "user_id" to "userId"` + ); + await queryRunner.query( + `ALTER TABLE "posts" RENAME COLUMN "group_id" to "groupId"` + ); + await queryRunner.query( + `ALTER TABLE "posts" RENAME COLUMN "session_id" to "sessionId"` + ); + await queryRunner.query( + `ALTER TABLE "votes" RENAME COLUMN "post_id" to "postId"` + ); + await queryRunner.query( + `ALTER TABLE "votes" RENAME COLUMN "user_id" to "userId"` + ); + await queryRunner.query( + `ALTER TABLE "sessions" RENAME COLUMN "options_new_posts_first" to "optionsNewpostsfirst"` + ); + await queryRunner.query( + `ALTER TABLE "sessions" RENAME COLUMN "options_blur_cards" to "optionsBlurcards"` + ); + await queryRunner.query( + `ALTER TABLE "sessions" RENAME COLUMN "options_allow_reordering" to "optionsAllowreordering"` + ); + await queryRunner.query( + `ALTER TABLE "sessions" RENAME COLUMN "options_allow_grouping" to "optionsAllowgrouping"` + ); + await queryRunner.query( + `ALTER TABLE "sessions" RENAME COLUMN "options_allow_giphy" to "optionsAllowgiphy"` + ); + await queryRunner.query( + `ALTER TABLE "sessions" RENAME COLUMN "options_allow_author_visible" to "optionsAllowauthorvisible"` + ); + await queryRunner.query( + `ALTER TABLE "sessions" RENAME COLUMN "options_allow_multiple_votes" to "optionsAllowmultiplevotes"` + ); + await queryRunner.query( + `ALTER TABLE "sessions" RENAME COLUMN "options_allow_self_voting" to "optionsAllowselfvoting"` + ); + await queryRunner.query( + `ALTER TABLE "sessions" RENAME COLUMN "options_allow_actions" to "optionsAllowactions"` + ); + await queryRunner.query( + `ALTER TABLE "sessions" RENAME COLUMN "options_max_posts" to "optionsMaxposts"` + ); + await queryRunner.query( + `ALTER TABLE "sessions" RENAME COLUMN "options_max_down_votes" to "optionsMaxdownvotes"` + ); + await queryRunner.query( + `ALTER TABLE "sessions" RENAME COLUMN "options_max_up_votes" to "optionsMaxupvotes"` + ); + await queryRunner.query( + `ALTER TABLE "sessions" RENAME COLUMN "created_by_id" to "createdById"` + ); + await queryRunner.query( + `ALTER TABLE "messages" RENAME COLUMN "user_id" to "userId"` + ); + await queryRunner.query( + `ALTER TABLE "messages" RENAME COLUMN "session_id" to "sessionId"` + ); + await queryRunner.query( + `ALTER TABLE "groups" RENAME COLUMN "user_id" to "userId"` + ); + await queryRunner.query( + `ALTER TABLE "groups" RENAME COLUMN "session_id" to "sessionId"` + ); + await queryRunner.query( + `ALTER TABLE "templates" RENAME COLUMN "options_new_posts_first" to "optionsNewpostsfirst"` + ); + await queryRunner.query( + `ALTER TABLE "templates" RENAME COLUMN "options_blur_cards" to "optionsBlurcards"` + ); + await queryRunner.query( + `ALTER TABLE "templates" RENAME COLUMN "options_allow_reordering" to "optionsAllowreordering"` + ); + await queryRunner.query( + `ALTER TABLE "templates" RENAME COLUMN "options_allow_grouping" to "optionsAllowgrouping"` + ); + await queryRunner.query( + `ALTER TABLE "templates" RENAME COLUMN "options_allow_giphy" to "optionsAllowgiphy"` + ); + await queryRunner.query( + `ALTER TABLE "templates" RENAME COLUMN "options_allow_author_visible" to "optionsAllowauthorvisible"` + ); + await queryRunner.query( + `ALTER TABLE "templates" RENAME COLUMN "options_allow_multiple_votes" to "optionsAllowmultiplevotes"` + ); + await queryRunner.query( + `ALTER TABLE "templates" RENAME COLUMN "options_allow_self_voting" to "optionsAllowselfvoting"` + ); + await queryRunner.query( + `ALTER TABLE "templates" RENAME COLUMN "options_allow_actions" to "optionsAllowactions"` + ); + await queryRunner.query( + `ALTER TABLE "templates" RENAME COLUMN "options_max_posts" to "optionsMaxposts"` + ); + await queryRunner.query( + `ALTER TABLE "templates" RENAME COLUMN "options_max_down_votes" to "optionsMaxdownvotes"` + ); + await queryRunner.query( + `ALTER TABLE "templates" RENAME COLUMN "options_max_up_votes" to "optionsMaxupvotes"` + ); + await queryRunner.query( + `ALTER TABLE "templates" RENAME COLUMN "created_by_id" to "createdById"` + ); + await queryRunner.query( + `ALTER TABLE "users" RENAME COLUMN "default_template_id" to "defaultTemplateId"` + ); + await queryRunner.query( + `ALTER TABLE "users" RENAME COLUMN "slack_team_id" to "slackTeamId"` + ); + await queryRunner.query( + `ALTER TABLE "users" RENAME COLUMN "slack_user_id" to "slackUserId"` + ); + await queryRunner.query( + `ALTER TABLE "users" RENAME COLUMN "stripe_id" to "stripeId"` + ); + await queryRunner.query( + `ALTER TABLE "users_identities" RENAME COLUMN "user_id" to "userId"` + ); + await queryRunner.query( + `ALTER TABLE "users_identities" RENAME COLUMN "email_verification" to "emailVerification"` + ); + await queryRunner.query( + `ALTER TABLE "users_identities" RENAME COLUMN "account_type" to "accountType"` + ); + await queryRunner.query( + `ALTER TABLE "subscriptions" RENAME COLUMN "owner_id" TO "ownerId"` + ); + await queryRunner.query( + `ALTER TABLE "templates-columns" RENAME COLUMN "template_id" TO "templateId"` + ); + await queryRunner.query( + `ALTER TABLE "columns" RENAME COLUMN "session_id" TO "sessionId"` + ); + await queryRunner.query( + `CREATE INDEX "IDX_d50229c10adbf294a228c35cb1" ON "visitors" ("usersId") ` + ); + await queryRunner.query( + `CREATE INDEX "IDX_89c90edf2f369cfbcb220d2e09" ON "visitors" ("sessionsId") ` + ); + await queryRunner.query( + `CREATE INDEX "IDX_331400b3a08ee505d42ddba1db" ON "subscriptions" ("ownerId") ` + ); + await queryRunner.query( + `CREATE INDEX "IDX_d10acbe503da4c56853181efc9" ON "posts" ("groupId") ` + ); + await queryRunner.query( + `CREATE INDEX "IDX_ae05faaa55c866130abef6e1fe" ON "posts" ("userId") ` + ); + await queryRunner.query( + `CREATE INDEX "IDX_764b665f832e28c01595ec15cf" ON "posts" ("sessionId") ` + ); + await queryRunner.query( + `CREATE INDEX "IDX_b5b05adc89dda0614276a13a59" ON "votes" ("postId") ` + ); + await queryRunner.query( + `CREATE INDEX "IDX_5169384e31d0989699a318f3ca" ON "votes" ("userId") ` + ); + await queryRunner.query( + `CREATE INDEX "IDX_d26fe2e6102cd9c47650a0d7a6" ON "sessions" ("createdById") ` + ); + await queryRunner.query( + `CREATE INDEX "IDX_4838cd4fc48a6ff2d4aa01aa64" ON "messages" ("userId") ` + ); + await queryRunner.query( + `CREATE INDEX "IDX_066163c46cda7e8187f96bc87a" ON "messages" ("sessionId") ` + ); + await queryRunner.query( + `CREATE INDEX "IDX_9ad140fba0b4ad9559e6530282" ON "groups" ("sessionId") ` + ); + await queryRunner.query( + `CREATE INDEX "IDX_898cf6af34722df13f760cc364" ON "groups" ("userId") ` + ); + await queryRunner.query( + `CREATE INDEX "IDX_c58b12b1a7b4012bb238bc2654" ON "templates" ("createdById") ` + ); + await queryRunner.query( + `CREATE INDEX "IDX_5b086b03bb64304390cec7635e" ON "users" ("defaultTemplateId") ` + ); + await queryRunner.query( + `CREATE INDEX "IDX_a10dca6aa6bda5865287bf2792" ON "users_identities" ("userId") ` + ); + await queryRunner.query( + `CREATE UNIQUE INDEX "IDX_3c67bd4e6a014698751d9242e3" ON "users_identities" ("accountType", "username") ` + ); + await queryRunner.query( + `ALTER TABLE "visitors" ADD CONSTRAINT "FK_d50229c10adbf294a228c35cb19" FOREIGN KEY ("usersId") REFERENCES "users"("id") ON DELETE NO ACTION ON UPDATE NO ACTION` + ); + await queryRunner.query( + `ALTER TABLE "visitors" ADD CONSTRAINT "FK_89c90edf2f369cfbcb220d2e09f" FOREIGN KEY ("sessionsId") REFERENCES "sessions"("id") ON DELETE CASCADE ON UPDATE CASCADE` + ); + await queryRunner.query( + `ALTER TABLE "subscriptions" ADD CONSTRAINT "FK_331400b3a08ee505d42ddba1db0" FOREIGN KEY ("ownerId") REFERENCES "users"("id") ON DELETE NO ACTION ON UPDATE NO ACTION` + ); + await queryRunner.query( + `ALTER TABLE "posts" ADD CONSTRAINT "FK_d10acbe503da4c56853181efc98" FOREIGN KEY ("groupId") REFERENCES "groups"("id") ON DELETE SET NULL ON UPDATE CASCADE` + ); + await queryRunner.query( + `ALTER TABLE "posts" ADD CONSTRAINT "FK_ae05faaa55c866130abef6e1fee" FOREIGN KEY ("userId") REFERENCES "users"("id") ON DELETE NO ACTION ON UPDATE NO ACTION` + ); + await queryRunner.query( + `ALTER TABLE "posts" ADD CONSTRAINT "FK_764b665f832e28c01595ec15cf3" FOREIGN KEY ("sessionId") REFERENCES "sessions"("id") ON DELETE NO ACTION ON UPDATE NO ACTION` + ); + await queryRunner.query( + `ALTER TABLE "votes" ADD CONSTRAINT "FK_b5b05adc89dda0614276a13a599" FOREIGN KEY ("postId") REFERENCES "posts"("id") ON DELETE CASCADE ON UPDATE CASCADE` + ); + await queryRunner.query( + `ALTER TABLE "votes" ADD CONSTRAINT "FK_5169384e31d0989699a318f3ca4" FOREIGN KEY ("userId") REFERENCES "users"("id") ON DELETE NO ACTION ON UPDATE NO ACTION` + ); + await queryRunner.query( + `ALTER TABLE "sessions" ADD CONSTRAINT "FK_d26fe2e6102cd9c47650a0d7a6f" FOREIGN KEY ("createdById") REFERENCES "users"("id") ON DELETE NO ACTION ON UPDATE NO ACTION` + ); + await queryRunner.query( + `ALTER TABLE "messages" ADD CONSTRAINT "FK_4838cd4fc48a6ff2d4aa01aa646" FOREIGN KEY ("userId") REFERENCES "users"("id") ON DELETE NO ACTION ON UPDATE NO ACTION` + ); + await queryRunner.query( + `ALTER TABLE "messages" ADD CONSTRAINT "FK_066163c46cda7e8187f96bc87a0" FOREIGN KEY ("sessionId") REFERENCES "sessions"("id") ON DELETE NO ACTION ON UPDATE NO ACTION` + ); + await queryRunner.query( + `ALTER TABLE "groups" ADD CONSTRAINT "FK_898cf6af34722df13f760cc364f" FOREIGN KEY ("userId") REFERENCES "users"("id") ON DELETE NO ACTION ON UPDATE NO ACTION` + ); + await queryRunner.query( + `ALTER TABLE "groups" ADD CONSTRAINT "FK_9ad140fba0b4ad9559e65302825" FOREIGN KEY ("sessionId") REFERENCES "sessions"("id") ON DELETE NO ACTION ON UPDATE NO ACTION` + ); + await queryRunner.query( + `ALTER TABLE "templates-columns" ADD CONSTRAINT "FK_c96b807f7154ddb4fb7017af12e" FOREIGN KEY ("templateId") REFERENCES "templates"("id") ON DELETE NO ACTION ON UPDATE NO ACTION` + ); + await queryRunner.query( + `ALTER TABLE "columns" ADD CONSTRAINT "FK_37907d102f38ece687182bf5237" FOREIGN KEY ("sessionId") REFERENCES "sessions"("id") ON DELETE NO ACTION ON UPDATE NO ACTION` + ); + await queryRunner.query( + `ALTER TABLE "templates" ADD CONSTRAINT "FK_c58b12b1a7b4012bb238bc26542" FOREIGN KEY ("createdById") REFERENCES "users"("id") ON DELETE NO ACTION ON UPDATE NO ACTION` + ); + await queryRunner.query( + `ALTER TABLE "users" ADD CONSTRAINT "FK_5b086b03bb64304390cec7635ec" FOREIGN KEY ("defaultTemplateId") REFERENCES "templates"("id") ON DELETE NO ACTION ON UPDATE NO ACTION` + ); + await queryRunner.query( + `ALTER TABLE "users_identities" ADD CONSTRAINT "FK_a10dca6aa6bda5865287bf2792a" FOREIGN KEY ("userId") REFERENCES "users"("id") ON DELETE CASCADE ON UPDATE CASCADE` + ); + + /** + * VIEWS + */ + + await queryRunner.query( + `DELETE FROM "typeorm_metadata" WHERE "type" = $1 AND "name" = $2 AND "schema" = $3`, + ['VIEW', 'user_view', 'public'] + ); + await queryRunner.query(`DROP VIEW "user_view"`); + await queryRunner.query(`CREATE VIEW "user_view" AS select + u.id, + i.id as "identityId", + u.name, + i."accountType", + i.username, + u.currency, + u."stripeId", + i.photo, + u.language, + u.email, + case when i."accountType" = 'anonymous' and i.password is null then false else true end as "canDeleteSession", + u.trial, + s.id as "ownSubscriptionsId", + s.plan as "ownPlan", + coalesce(s.id, s2.id, s3.id) as "subscriptionsId", + coalesce(s.active, s2.active, s3.active, false) as "pro", + coalesce(s.plan, s2.plan, s3.plan) as "plan", + coalesce(s.domain, s2.domain, s3.domain) as "domain" +from users_identities i + +join users u on u.id = i."userId" +left join subscriptions s on s."ownerId" = u.id and s.active is true +left join subscriptions s2 on lower(u.email) = any(lower(s2.members::text)::text[]) and s2.active is true +left join subscriptions s3 on s3.domain = split_part(u.email, '@', 2) and s3.active is true`); + await queryRunner.query( + `INSERT INTO "typeorm_metadata"("database", "schema", "table", "type", "name", "value") VALUES (DEFAULT, $1, DEFAULT, $2, $3, $4)`, + [ + 'public', + 'VIEW', + 'user_view', + 'select \n u.id,\n i.id as "identityId",\n u.name,\n i."accountType",\n i.username,\n u.currency,\n u."stripeId",\n i.photo,\n u.language,\n u.email,\n case when i."accountType" = \'anonymous\' and i.password is null then false else true end as "canDeleteSession",\n u.trial,\n s.id as "ownSubscriptionsId",\n s.plan as "ownPlan",\n coalesce(s.id, s2.id, s3.id) as "subscriptionsId",\n coalesce(s.active, s2.active, s3.active, false) as "pro",\n coalesce(s.plan, s2.plan, s3.plan) as "plan",\n coalesce(s.domain, s2.domain, s3.domain) as "domain"\nfrom users_identities i\n\njoin users u on u.id = i."userId"\nleft join subscriptions s on s."ownerId" = u.id and s.active is true\nleft join subscriptions s2 on lower(u.email) = any(lower(s2.members::text)::text[]) and s2.active is true\nleft join subscriptions s3 on s3.domain = split_part(u.email, \'@\', 2) and s3.active is true', + ] + ); + + await queryRunner.query( + `DELETE FROM "typeorm_metadata" WHERE "type" = $1 AND "name" = $2 AND "schema" = $3`, + ['VIEW', 'session_view', 'public'] + ); + await queryRunner.query(`DROP VIEW "session_view"`); + await queryRunner.query(`CREATE VIEW "session_view" AS select + s.id, + s.name, + s.created, + ( + select to_jsonb(cb) from ( + select cbu.id, cbu.name, cbu.photo from users cbu + where cbu.id = s."createdById" + ) as cb + ) as "createdBy", + s.encrypted, + s.locked, + (select count(*) from posts p where p."sessionId" = s.id and p.action is not null) as "numberOfActions", + (select count(*) from posts p where p."sessionId" = s.id) as "numberOfPosts", + ( + select count(*) from votes vv + left join posts vp on vp.id = vv."postId" + where vp."sessionId" = s.id + ) as "numberOfVotes", + ( + select json_agg(vis) from ( + select vu.id, vu.name, vu.photo from visitors v + join users vu on vu.id = v."usersId" + where v."sessionsId" = s.id + ) as vis + ) as participants + +from sessions s +left join users u on s."createdById" = u.id + +order by s.updated desc`); + await queryRunner.query( + `INSERT INTO "typeorm_metadata"("database", "schema", "table", "type", "name", "value") VALUES (DEFAULT, $1, DEFAULT, $2, $3, $4)`, + [ + 'public', + 'VIEW', + 'session_view', + 'select \n\ts.id,\n\ts.name,\n\ts.created,\n\t(\n\t\tselect to_jsonb(cb) from (\n\t\t\tselect cbu.id, cbu.name, cbu.photo from users cbu\n\t\t\twhere cbu.id = s."createdById"\n\t\t) as cb\n\t) as "createdBy",\n\ts.encrypted,\n\ts.locked,\n\t(select count(*) from posts p where p."sessionId" = s.id and p.action is not null) as "numberOfActions",\t\n\t(select count(*) from posts p where p."sessionId" = s.id) as "numberOfPosts",\n\t(\n\t\tselect count(*) from votes vv\n\t\tleft join posts vp on vp.id = vv."postId"\n\t\twhere vp."sessionId" = s.id\n\t) as "numberOfVotes",\n\t(\n\t\tselect json_agg(vis) from (\n\t\t\tselect vu.id, vu.name, vu.photo from visitors v\n\t\t\tjoin users vu on vu.id = v."usersId"\n\t\t\twhere v."sessionsId" = s.id\n\t\t) as vis\n\t) as participants\n\nfrom sessions s\nleft join users u on s."createdById" = u.id\n\norder by s.updated desc', + ] + ); + } +} diff --git a/backend/src/db/migrations/1643053991480-TemplateColumnsRename.ts b/backend/src/db/migrations/1643053991480-TemplateColumnsRename.ts new file mode 100644 index 000000000..d5ff095aa --- /dev/null +++ b/backend/src/db/migrations/1643053991480-TemplateColumnsRename.ts @@ -0,0 +1,17 @@ +import { MigrationInterface, QueryRunner } from 'typeorm'; + +export class TemplateColumnsRename1643053991480 implements MigrationInterface { + name = 'TemplateColumnsRename1643053991480'; + + public async up(queryRunner: QueryRunner): Promise { + await queryRunner.query( + `ALTER TABLE "templates-columns" RENAME TO "templates_columns"` + ); + } + + public async down(queryRunner: QueryRunner): Promise { + await queryRunner.query( + `ALTER TABLE "templates_columns" RENAME TO "templates-columns"` + ); + } +} diff --git a/backend/src/db/migrations/1643107796386-MissingConstraint.ts b/backend/src/db/migrations/1643107796386-MissingConstraint.ts new file mode 100644 index 000000000..8add0e4d5 --- /dev/null +++ b/backend/src/db/migrations/1643107796386-MissingConstraint.ts @@ -0,0 +1,23 @@ +import { MigrationInterface, QueryRunner } from 'typeorm'; + +export class MissingConstraint1643107796386 implements MigrationInterface { + name = 'MissingConstraint1643107796386'; + + public async up(queryRunner: QueryRunner): Promise { + await queryRunner.query( + `ALTER TABLE "templates_columns" DROP CONSTRAINT "FK_f5ccf851c3134ac587eb4e794d9"` + ); + await queryRunner.query( + `ALTER TABLE "templates_columns" ADD CONSTRAINT "FK_6d169517f9e0e1b10bac42c215d" FOREIGN KEY ("template_id") REFERENCES "templates"("id") ON DELETE NO ACTION ON UPDATE NO ACTION` + ); + } + + public async down(queryRunner: QueryRunner): Promise { + await queryRunner.query( + `ALTER TABLE "templates_columns" DROP CONSTRAINT "FK_6d169517f9e0e1b10bac42c215d"` + ); + await queryRunner.query( + `ALTER TABLE "templates_columns" ADD CONSTRAINT "FK_f5ccf851c3134ac587eb4e794d9" FOREIGN KEY ("template_id") REFERENCES "templates"("id") ON DELETE NO ACTION ON UPDATE NO ACTION` + ); + } +} diff --git a/backend/src/db/migrations/1643116159073-MissingIndices.ts b/backend/src/db/migrations/1643116159073-MissingIndices.ts new file mode 100644 index 000000000..a9eab9976 --- /dev/null +++ b/backend/src/db/migrations/1643116159073-MissingIndices.ts @@ -0,0 +1,29 @@ +import { MigrationInterface, QueryRunner } from 'typeorm'; + +export class MissingIndices1643116159073 implements MigrationInterface { + name = 'MissingIndices1643116159073'; + + public async up(queryRunner: QueryRunner): Promise { + await queryRunner.query( + `CREATE INDEX "IDX_9f5aedb06b838d50b1b4a56e04" ON "columns" ("session_id") ` + ); + await queryRunner.query( + `CREATE INDEX "IDX_6d169517f9e0e1b10bac42c215" ON "templates_columns" ("template_id") ` + ); + await queryRunner.query( + `CREATE INDEX "IDX_db22f6defb263cc5b40a39847b" ON "licences" ("email") ` + ); + } + + public async down(queryRunner: QueryRunner): Promise { + await queryRunner.query( + `DROP INDEX "public"."IDX_db22f6defb263cc5b40a39847b"` + ); + await queryRunner.query( + `DROP INDEX "public"."IDX_6d169517f9e0e1b10bac42c215"` + ); + await queryRunner.query( + `DROP INDEX "public"."IDX_9f5aedb06b838d50b1b4a56e04"` + ); + } +} diff --git a/backend/src/db/orm-config.ts b/backend/src/db/orm-config.ts index 197e52b01..c9a5ad522 100644 --- a/backend/src/db/orm-config.ts +++ b/backend/src/db/orm-config.ts @@ -17,56 +17,48 @@ import { import LicenceEntity from './entities/Licence'; import SessionOptionsEntity from './entities/SessionOptions'; import UserIdentityEntity from './entities/UserIdentity'; +import { SnakeNamingStrategy } from 'typeorm-naming-strategies'; +import path from 'path'; -const migrationsDirectory = 'src/db/migrations'; - -export type ConnectionOptionsCustomisation = { - entities: string[]; - migrations: string[]; - migrationDir: string; -}; +function getMigrationsDirectory(): string { + return path.resolve(__dirname, 'migrations'); +} -export default function ( - customisation?: Partial -): ConnectionOptions { - return { - type: 'postgres', - host: config.DB_HOST, - port: config.DB_PORT, - username: config.DB_USER, - password: config.DB_PASSWORD, - database: config.DB_NAME, - entities: - customisation && customisation.entities - ? customisation.entities - : [ - PostEntity, - PostGroupEntity, - SessionEntity, - SessionView, - UserEntity, - UserIdentityEntity, - UserView, - ColumnDefinitionEntity, - VoteEntity, - SessionTemplateEntity, - TemplateColumnDefinitionEntity, - SubscriptionEntity, - LicenceEntity, - SessionOptionsEntity, - MessageEntity, - ], - synchronize: false, - logging: config.SQL_LOG ? 'all' : undefined, - migrations: - customisation && customisation.migrations - ? customisation.migrations - : [`${migrationsDirectory}/*.ts`], - cli: { - migrationsDir: - customisation && customisation.migrationDir - ? customisation.migrationDir - : migrationsDirectory, - }, - }; +function getMigrationsFiles(): string { + return `${getMigrationsDirectory()}/*.${ + __filename.endsWith('js') ? 'js' : 'ts' + }`; } + +export default { + type: 'postgres', + host: config.DB_HOST, + port: config.DB_PORT, + username: config.DB_USER, + password: config.DB_PASSWORD, + database: config.DB_NAME, + namingStrategy: new SnakeNamingStrategy(), + entities: [ + PostEntity, + PostGroupEntity, + SessionEntity, + SessionView, + UserEntity, + UserIdentityEntity, + UserView, + ColumnDefinitionEntity, + VoteEntity, + SessionTemplateEntity, + TemplateColumnDefinitionEntity, + SubscriptionEntity, + LicenceEntity, + SessionOptionsEntity, + MessageEntity, + ], + synchronize: false, + logging: config.SQL_LOG ? 'all' : undefined, + migrations: [getMigrationsFiles()], + cli: { + migrationsDir: getMigrationsDirectory(), + }, +} as ConnectionOptions; diff --git a/backend/src/init.ts b/backend/src/init.ts deleted file mode 100644 index 8784b70f8..000000000 --- a/backend/src/init.ts +++ /dev/null @@ -1,7 +0,0 @@ -import buildConfig from './build-config'; - -async function go() { - await buildConfig(); -} - -go(); diff --git a/backend/yarn.lock b/backend/yarn.lock index b6668f4e7..77627fb7b 100644 --- a/backend/yarn.lock +++ b/backend/yarn.lock @@ -790,7 +790,7 @@ dependencies: express-rate-limit "*" -"@types/express-serve-static-core@*", "@types/express-serve-static-core@4.17.28", "@types/express-serve-static-core@^4.17.18": +"@types/express-serve-static-core@*", "@types/express-serve-static-core@^4.17.18": version "4.17.28" resolved "https://registry.yarnpkg.com/@types/express-serve-static-core/-/express-serve-static-core-4.17.28.tgz#c47def9f34ec81dc6328d0b1b5303d1ec98d86b8" integrity sha512-P1BJAEAW3E2DJUlkgq4tOL3RyMunoWXqbSCygWo5ZIWTjUgN1YnaXWW4VWl/oc8vs/XoYibEGBKP0uZyF4AHig== @@ -874,13 +874,6 @@ resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.178.tgz#341f6d2247db528d4a13ddbb374bcdc80406f4f8" integrity sha512-0d5Wd09ItQWH1qFbEyQ7oTQ3GZrMfth5JkbN3EvTKLXcHLRDSXeLnlvlOn0wvxVIwK5o2M8JzP/OWz7T3NRsbw== -"@types/md5@2.3.1": - version "2.3.1" - resolved "https://registry.yarnpkg.com/@types/md5/-/md5-2.3.1.tgz#010bcf3bb50a2cff3a574cb1c0b4051a9c67d6bc" - integrity sha512-OK3oe+ALIoPSo262lnhAYwpqFNXbiwH2a+0+Z5YBnkQEwWD8fk5+PIeRhYA48PzvX9I4SGNpWy+9bLj8qz92RQ== - dependencies: - "@types/node" "*" - "@types/mime@^1": version "1.3.2" resolved "https://registry.yarnpkg.com/@types/mime/-/mime-1.3.2.tgz#93e25bf9ee75fe0fd80b594bc4feb0e862111b5a" @@ -1536,11 +1529,6 @@ char-regex@^1.0.2: resolved "https://registry.yarnpkg.com/char-regex/-/char-regex-1.0.2.tgz#d744358226217f981ed58f479b1d6bcc29545dcf" integrity sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw== -charenc@0.0.2: - version "0.0.2" - resolved "https://registry.yarnpkg.com/charenc/-/charenc-0.0.2.tgz#c0a1d2f3a7092e03774bfa83f14c0fc5790a8667" - integrity sha1-wKHS86cJLgN3S/qD8UwPxXkKhmc= - chokidar@^3.5.2: version "3.5.3" resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.5.3.tgz#1cf37c8707b932bd1af1ae22c0432e2acd1903bd" @@ -1719,14 +1707,7 @@ create-require@^1.1.0: resolved "https://registry.yarnpkg.com/create-require/-/create-require-1.1.1.tgz#c1d7e8f1e5f6cfc9ff65f9cd352d37348756c333" integrity sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ== -cross-env@7.0.3: - version "7.0.3" - resolved "https://registry.yarnpkg.com/cross-env/-/cross-env-7.0.3.tgz#865264b29677dc015ba8418918965dd232fc54cf" - integrity sha512-+/HKd6EgcQCJGh2PSjZuUitQBQynKor4wrFbRg4DtAgS1aWO+gU52xpH7M9ScGgXSYmAVS9bIJ8EzuaGw0oNAw== - dependencies: - cross-spawn "^7.0.1" - -cross-spawn@^7.0.1, cross-spawn@^7.0.2, cross-spawn@^7.0.3: +cross-spawn@^7.0.2, cross-spawn@^7.0.3: version "7.0.3" resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6" integrity sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w== @@ -1735,11 +1716,6 @@ cross-spawn@^7.0.1, cross-spawn@^7.0.2, cross-spawn@^7.0.3: shebang-command "^2.0.0" which "^2.0.1" -crypt@0.0.2: - version "0.0.2" - resolved "https://registry.yarnpkg.com/crypt/-/crypt-0.0.2.tgz#88d7ff7ec0dfb86f713dc87bbb42d044d3e6c41b" - integrity sha1-iNf/fsDfuG9xPch7u0LQRNPmxBs= - crypto-js@4.1.1: version "4.1.1" resolved "https://registry.yarnpkg.com/crypto-js/-/crypto-js-4.1.1.tgz#9e485bcf03521041bd85844786b83fb7619736cf" @@ -2709,11 +2685,6 @@ is-binary-path@~2.1.0: dependencies: binary-extensions "^2.0.0" -is-buffer@~1.1.6: - version "1.1.6" - resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be" - integrity sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w== - is-ci@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/is-ci/-/is-ci-2.0.0.tgz#6bc6334181810e04b5c22b3d589fdca55026404c" @@ -3437,15 +3408,6 @@ makeerror@1.0.12: dependencies: tmpl "1.0.5" -md5@2.3.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/md5/-/md5-2.3.0.tgz#c3da9a6aae3a30b46b7b0c349b87b110dc3bda4f" - integrity sha512-T1GITYmFaKuO91vxyoQMFETst+O71VUPEU3ze5GNzDm0OWdP8v1ziTaAEPUr/3kLsY3Sftgz242A1SetQiDL7g== - dependencies: - charenc "0.0.2" - crypt "0.0.2" - is-buffer "~1.1.6" - media-typer@0.3.0: version "0.3.0" resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748" @@ -4813,6 +4775,11 @@ typedarray-to-buffer@^3.1.5: dependencies: is-typedarray "^1.0.0" +typeorm-naming-strategies@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/typeorm-naming-strategies/-/typeorm-naming-strategies-2.0.0.tgz#c7c10bc768ddce2592ef9ad4d2dca55fd5fa6ad6" + integrity sha512-nsJ5jDjhBBEG6olFmxojkO4yrW7hEv38sH7ZXWWx9wnDoo9uaoH/mo2mBYAh/VKgwoFHBLu+CYxGmzXz2GUMcA== + typeorm@0.2.41: version "0.2.41" resolved "https://registry.yarnpkg.com/typeorm/-/typeorm-0.2.41.tgz#88758101ac158dc0a0a903d70eaacea2974281cc" @@ -5125,31 +5092,31 @@ yargs-parser@^21.0.0: resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-21.0.0.tgz#a485d3966be4317426dd56bdb6a30131b281dc55" integrity sha512-z9kApYUOCwoeZ78rfRYYWdiU/iNL6mwwYlkkZfJoyMR1xps+NEBX5X7XmRpxkZHhXJ6+Ey00IwKxBBSW9FIjyA== -yargs@17.3.1, yargs@^17.0.1: - version "17.3.1" - resolved "https://registry.yarnpkg.com/yargs/-/yargs-17.3.1.tgz#da56b28f32e2fd45aefb402ed9c26f42be4c07b9" - integrity sha512-WUANQeVgjLbNsEmGk20f+nlHgOqzRFpiGWVaBrYGYIGANIIu3lWjoyi0fNlFmJkvfhCZ6BXINe7/W2O2bV4iaA== +yargs@^16.0.0, yargs@^16.2.0: + version "16.2.0" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-16.2.0.tgz#1c82bf0f6b6a66eafce7ef30e376f49a12477f66" + integrity sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw== dependencies: cliui "^7.0.2" escalade "^3.1.1" get-caller-file "^2.0.5" require-directory "^2.1.1" - string-width "^4.2.3" + string-width "^4.2.0" y18n "^5.0.5" - yargs-parser "^21.0.0" + yargs-parser "^20.2.2" -yargs@^16.0.0, yargs@^16.2.0: - version "16.2.0" - resolved "https://registry.yarnpkg.com/yargs/-/yargs-16.2.0.tgz#1c82bf0f6b6a66eafce7ef30e376f49a12477f66" - integrity sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw== +yargs@^17.0.1: + version "17.3.1" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-17.3.1.tgz#da56b28f32e2fd45aefb402ed9c26f42be4c07b9" + integrity sha512-WUANQeVgjLbNsEmGk20f+nlHgOqzRFpiGWVaBrYGYIGANIIu3lWjoyi0fNlFmJkvfhCZ6BXINe7/W2O2bV4iaA== dependencies: cliui "^7.0.2" escalade "^3.1.1" get-caller-file "^2.0.5" require-directory "^2.1.1" - string-width "^4.2.0" + string-width "^4.2.3" y18n "^5.0.5" - yargs-parser "^20.2.2" + yargs-parser "^21.0.0" yn@3.1.1: version "3.1.1" diff --git a/docs/package.json b/docs/package.json index be7435876..a07d93011 100644 --- a/docs/package.json +++ b/docs/package.json @@ -1,6 +1,6 @@ { "name": "docs", - "version": "4.11.5", + "version": "4.12.0", "private": true, "scripts": { "docusaurus": "docusaurus", diff --git a/frontend/package.json b/frontend/package.json index 93001db0d..c9a6d90b0 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -1,6 +1,6 @@ { "name": "@retrospected/frontend", - "version": "4.11.5", + "version": "4.12.0", "license": "GNU GPLv3", "private": true, "dependencies": { @@ -8,7 +8,6 @@ "@emotion/styled": "11.6.0", "@mui/core": "5.0.0-alpha.54", "@mui/icons-material": "5.3.0", - "@mui/lab": "5.0.0-alpha.65", "@mui/material": "5.3.0", "@mui/styles": "5.3.0", "@mui/x-data-grid": "5.2.2", @@ -68,7 +67,6 @@ "socket.io-client": "4.4.1", "source-map-explorer": "2.5.2", "typescript": "4.5.4", - "util": "0.12.4", "uuid": "8.3.2", "whatwg-fetch": "3.6.2" }, diff --git a/frontend/yarn.lock b/frontend/yarn.lock index 834eb9679..5800a5042 100644 --- a/frontend/yarn.lock +++ b/frontend/yarn.lock @@ -1248,39 +1248,6 @@ resolved "https://registry.yarnpkg.com/@csstools/normalize.css/-/normalize.css-10.1.0.tgz#f0950bba18819512d42f7197e56c518aa491cf18" integrity sha512-ij4wRiunFfaJxjB0BdrYHIH8FxBJpOwNPhhAcunlmPdXudL1WQV1qoP9un6JsEBAgQH+7UXyyjh0g7jTxXK6tg== -"@date-io/core@^2.11.0": - version "2.11.0" - resolved "https://registry.yarnpkg.com/@date-io/core/-/core-2.11.0.tgz#28580cda1c8228ab2c7ed6aee673ef0495f913e6" - integrity sha512-DvPBnNoeuLaoSJZaxgpu54qzRhRKjSYVyQjhznTFrllKuDpm0sDFjHo6lvNLCM/cfMx2gb2PM2zY2kc9C8nmuw== - -"@date-io/date-fns@^2.11.0": - version "2.11.0" - resolved "https://registry.yarnpkg.com/@date-io/date-fns/-/date-fns-2.11.0.tgz#142fbf954eda7ad66514af7a2802d78c4ea40053" - integrity sha512-mPQ71plBeFrArvBSHtjWMHXA89IUbZ6kuo2dsjlRC/1uNOybo91spIb+wTu03NxKTl8ut07s0jJ9svF71afpRg== - dependencies: - "@date-io/core" "^2.11.0" - -"@date-io/dayjs@^2.11.0": - version "2.11.0" - resolved "https://registry.yarnpkg.com/@date-io/dayjs/-/dayjs-2.11.0.tgz#41f4b4b9629612e6012accffd848875d1aeffb74" - integrity sha512-w67vRK56NZJIKhJM/CrNbfnIcuMvR3ApfxzNZiCZ5w29sxgBDeKuX4M+P7A9r5HXOMGcsOcpgaoTDINNGkdpGQ== - dependencies: - "@date-io/core" "^2.11.0" - -"@date-io/luxon@^2.11.1": - version "2.11.1" - resolved "https://registry.yarnpkg.com/@date-io/luxon/-/luxon-2.11.1.tgz#31a72f7b5e163c74e8a3b29d8f16c4c30de6ed43" - integrity sha512-JUXo01kdPQxLORxqdENrgdUhooKgDUggsNRSdi2BcUhASIY2KGwwWXu8ikVHHGkw+DUF4FOEKGfkQd0RHSvX6g== - dependencies: - "@date-io/core" "^2.11.0" - -"@date-io/moment@^2.11.0": - version "2.11.0" - resolved "https://registry.yarnpkg.com/@date-io/moment/-/moment-2.11.0.tgz#850f8dd090d401845b39276d034dbabe20224ef5" - integrity sha512-QSL+83qezQ9Ty0dtFgAkk6eC0GMl/lgYfDajeVUDB3zVA2A038hzczRLBg29ifnBGhQMPABxuOafgWwhDjlarg== - dependencies: - "@date-io/core" "^2.11.0" - "@emotion/babel-plugin@^11.0.0", "@emotion/babel-plugin@^11.3.0": version "11.7.2" resolved "https://registry.yarnpkg.com/@emotion/babel-plugin/-/babel-plugin-11.7.2.tgz#fec75f38a6ab5b304b0601c74e2a5e77c95e5fa0" @@ -1684,25 +1651,6 @@ dependencies: "@babel/runtime" "^7.16.7" -"@mui/lab@5.0.0-alpha.65": - version "5.0.0-alpha.65" - resolved "https://registry.yarnpkg.com/@mui/lab/-/lab-5.0.0-alpha.65.tgz#cc0712d5e66eda49adaf838e0d4488283842ec9b" - integrity sha512-YiZvUGK/GbwgR4WU/JgdYrjF9AC9C4qn+mM3ShGsX0xPzTkwFG28uyKoNy2PN+/r10aQxdkkUsVQk3BCLC8/Sg== - dependencies: - "@babel/runtime" "^7.16.7" - "@date-io/date-fns" "^2.11.0" - "@date-io/dayjs" "^2.11.0" - "@date-io/luxon" "^2.11.1" - "@date-io/moment" "^2.11.0" - "@mui/base" "5.0.0-alpha.65" - "@mui/system" "^5.3.0" - "@mui/utils" "^5.3.0" - clsx "^1.1.1" - prop-types "^15.7.2" - react-is "^17.0.2" - react-transition-group "^4.4.2" - rifm "^0.12.1" - "@mui/material@5.3.0": version "5.3.0" resolved "https://registry.yarnpkg.com/@mui/material/-/material-5.3.0.tgz#564395bc4dd96bd12e51884214330f22ee876408" @@ -3183,11 +3131,6 @@ autosize@^4.0.2: resolved "https://registry.yarnpkg.com/autosize/-/autosize-4.0.4.tgz#924f13853a466b633b9309330833936d8bccce03" integrity sha512-5yxLQ22O0fCRGoxGfeLSNt3J8LB1v+umtpMnPW6XjkTWXKoN0AmXAIhelJcDtFT/Y/wYWmfE+oqU10Q0b8FhaQ== -available-typed-arrays@^1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz#92f95616501069d07d10edb2fc37d3e1c65123b7" - integrity sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw== - axe-core@^4.3.5: version "4.3.5" resolved "https://registry.yarnpkg.com/axe-core/-/axe-core-4.3.5.tgz#78d6911ba317a8262bfee292aeafcc1e04b49cc5" @@ -5193,7 +5136,7 @@ error-stack-parser@^2.0.6: dependencies: stackframe "^1.1.1" -es-abstract@^1.17.2, es-abstract@^1.18.5, es-abstract@^1.19.0, es-abstract@^1.19.1: +es-abstract@^1.17.2, es-abstract@^1.19.0, es-abstract@^1.19.1: version "1.19.1" resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.19.1.tgz#d4885796876916959de78edaa0df456627115ec3" integrity sha512-2vJ6tjA/UfqLm2MPs7jxVybLoB8i1t1Jd9R3kISld20sIxPcTbLuggQOUxeWeAvIUkduv/CfMjuh4WmiXr2v9w== @@ -5924,11 +5867,6 @@ for-in@^1.0.2: resolved "https://registry.yarnpkg.com/for-in/-/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80" integrity sha1-gQaNKVqBQuwKxybG4iAMMPttXoA= -foreach@^2.0.5: - version "2.0.5" - resolved "https://registry.yarnpkg.com/foreach/-/foreach-2.0.5.tgz#0bee005018aeb260d0a3af3ae658dd0136ec1b99" - integrity sha1-C+4AUBiusmDQo6865ljdATbsG5k= - fork-ts-checker-webpack-plugin@4.1.6: version "4.1.6" resolved "https://registry.yarnpkg.com/fork-ts-checker-webpack-plugin/-/fork-ts-checker-webpack-plugin-4.1.6.tgz#5055c703febcf37fa06405d400c122b905167fc5" @@ -7005,13 +6943,6 @@ is-generator-fn@^2.0.0: resolved "https://registry.yarnpkg.com/is-generator-fn/-/is-generator-fn-2.1.0.tgz#7d140adc389aaf3011a8f2a2a4cfa6faadffb118" integrity sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ== -is-generator-function@^1.0.7: - version "1.0.10" - resolved "https://registry.yarnpkg.com/is-generator-function/-/is-generator-function-1.0.10.tgz#f1558baf1ac17e0deea7c0415c438351ff2b3c72" - integrity sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A== - dependencies: - has-tostringtag "^1.0.0" - is-glob@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-3.1.0.tgz#7ba5ae24217804ac70707b96922567486cc3e84a" @@ -7178,17 +7109,6 @@ is-symbol@^1.0.2, is-symbol@^1.0.3: dependencies: has-symbols "^1.0.2" -is-typed-array@^1.1.3, is-typed-array@^1.1.7: - version "1.1.8" - resolved "https://registry.yarnpkg.com/is-typed-array/-/is-typed-array-1.1.8.tgz#cbaa6585dc7db43318bc5b89523ea384a6f65e79" - integrity sha512-HqH41TNZq2fgtGT8WHVFVJhBVGuY3AnP3Q36K8JKXUxSxRgk/d+7NjmwG2vo2mYmXK8UYZKu0qH8bVP5gEisjA== - dependencies: - available-typed-arrays "^1.0.5" - call-bind "^1.0.2" - es-abstract "^1.18.5" - foreach "^2.0.5" - has-tostringtag "^1.0.0" - is-typedarray@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a" @@ -11054,11 +10974,6 @@ rgba-regex@^1.0.0: resolved "https://registry.yarnpkg.com/rgba-regex/-/rgba-regex-1.0.0.tgz#43374e2e2ca0968b0ef1523460b7d730ff22eeb3" integrity sha1-QzdOLiyglosO8VI0YLfXMP8i7rM= -rifm@^0.12.1: - version "0.12.1" - resolved "https://registry.yarnpkg.com/rifm/-/rifm-0.12.1.tgz#8fa77f45b7f1cda2a0068787ac821f0593967ac4" - integrity sha512-OGA1Bitg/dSJtI/c4dh90svzaUPt228kzFsUkJbtA2c964IqEAwWXeL9ZJi86xWv3j5SMqRvGULl7bA6cK0Bvg== - rimraf@^2.5.4, rimraf@^2.6.3: version "2.7.1" resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.7.1.tgz#35797f13a7fdadc566142c29d4f07ccad483e3ec" @@ -12688,18 +12603,6 @@ util@0.10.3: dependencies: inherits "2.0.1" -util@0.12.4: - version "0.12.4" - resolved "https://registry.yarnpkg.com/util/-/util-0.12.4.tgz#66121a31420df8f01ca0c464be15dfa1d1850253" - integrity sha512-bxZ9qtSlGUWSOy9Qa9Xgk11kSslpuZwaxCg4sNIDj6FLucDab2JxnHwyNTCpHMtK1MjoQiWQ6DiUMZYbSrO+Sw== - dependencies: - inherits "^2.0.3" - is-arguments "^1.0.4" - is-generator-function "^1.0.7" - is-typed-array "^1.1.3" - safe-buffer "^5.1.2" - which-typed-array "^1.1.2" - util@^0.11.0: version "0.11.1" resolved "https://registry.yarnpkg.com/util/-/util-0.11.1.tgz#3236733720ec64bb27f6e26f421aaa2e1b588d61" @@ -13035,18 +12938,6 @@ which-module@^2.0.0: resolved "https://registry.yarnpkg.com/which-module/-/which-module-2.0.0.tgz#d9ef07dce77b9902b8a3a8fa4b31c3e3f7e6e87a" integrity sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho= -which-typed-array@^1.1.2: - version "1.1.7" - resolved "https://registry.yarnpkg.com/which-typed-array/-/which-typed-array-1.1.7.tgz#2761799b9a22d4b8660b3c1b40abaa7739691793" - integrity sha512-vjxaB4nfDqwKI0ws7wZpxIlde1XrLX5uB0ZjpfshgmapJMD7jJWhZI+yToJTqaFByF0eNBcYxbjmCzoRP7CfEw== - dependencies: - available-typed-arrays "^1.0.5" - call-bind "^1.0.2" - es-abstract "^1.18.5" - foreach "^2.0.5" - has-tostringtag "^1.0.0" - is-typed-array "^1.1.7" - which@^1.2.9, which@^1.3.1: version "1.3.1" resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a" diff --git a/package.json b/package.json index 14d77aa36..cdb230c62 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "retrospected", - "version": "4.11.5", + "version": "4.12.0", "description": "An agile retrospective board - Powering www.retrospected.com", "private": true, "scripts": { @@ -10,7 +10,8 @@ "backend": "cd backend && yarn start && cd ..", "stripe-login": "stripe login", "stripe-listen": "stripe listen --forward-to localhost:3000/api/stripe/webhook", - "bump": ". ./scripts/bump.sh" + "bump": ". ./scripts/bump.sh", + "mig": "cd backend && yarn mig" }, "repository": { "type": "git",