From 3ca815690ecb1186b6c94bbffebbd052afff2e79 Mon Sep 17 00:00:00 2001 From: Evert Prants Date: Sat, 10 Sep 2022 12:52:39 +0300 Subject: [PATCH] old icynet migration --- package-lock.json | 75 +++-- package.json | 3 +- src/datasource.ts | 12 + src/migration/1662799286155-initial.ts | 296 ++++++++++++++++++ .../objects/privilege/privilege.entity.ts | 3 +- src/tools/migrate-old-icynet/.gitignore | 4 + src/tools/migrate-old-icynet/migrate.ts | 85 +++++ src/tools/migrate-old-icynet/to-json.mjs | 107 +++++++ 8 files changed, 556 insertions(+), 29 deletions(-) create mode 100644 src/migration/1662799286155-initial.ts create mode 100644 src/tools/migrate-old-icynet/.gitignore create mode 100644 src/tools/migrate-old-icynet/migrate.ts create mode 100644 src/tools/migrate-old-icynet/to-json.mjs diff --git a/package-lock.json b/package-lock.json index 9c3e4b6..befcf31 100644 --- a/package-lock.json +++ b/package-lock.json @@ -41,6 +41,7 @@ "reflect-metadata": "^0.1.13", "rimraf": "^3.0.2", "rxjs": "^7.5.6", + "thirty-two": "^1.0.2", "toml": "^3.0.0", "typeorm": "^0.3.7", "uuid": "^8.3.2" @@ -63,7 +64,7 @@ "@types/marked": "^4.0.4", "@types/mime-types": "^2.1.1", "@types/multer": "^1.4.7", - "@types/node": "^18.7.6", + "@types/node": "^18.7.16", "@types/nodemailer": "^6.4.5", "@types/qrcode": "^1.4.3", "@types/supertest": "^2.0.12", @@ -2623,6 +2624,16 @@ "node": ">=6.0.0" } }, + "node_modules/@jridgewell/source-map": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.2.tgz", + "integrity": "sha512-m7O9o2uR8k2ObDysZYzdfhb08VuEml5oWGiosa1VdaPZ/A6QyPkAJuwN0Q1lhULOf6B7MtQmHENS743hWtCrgw==", + "dev": true, + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.0", + "@jridgewell/trace-mapping": "^0.3.9" + } + }, "node_modules/@jridgewell/sourcemap-codec": { "version": "1.4.11", "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.11.tgz", @@ -3017,9 +3028,9 @@ "integrity": "sha512-l6qtdDPIkmAmzEO6egquYDfqQGPMRNGjYtrU13HAXb3YSRrt7HSb1sJY0pKp6o2bAa86tSB6iwaW2JbthPKr7Q==" }, "node_modules/@nestjs/swagger": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/@nestjs/swagger/-/swagger-6.1.0.tgz", - "integrity": "sha512-Lflplv216nXkH6By/jMggQjpuH1V67M07tgHXUAZujAwG3LAJ1CfSvzuFckK4MAb54xQTYvFgfVPWkXqvKXzdA==", + "version": "6.1.2", + "resolved": "https://registry.npmjs.org/@nestjs/swagger/-/swagger-6.1.2.tgz", + "integrity": "sha512-RU1DeTDyuN/lRXKFWaf7I9LYF34/ale3IIGeY3romAcXL/N9W0+50Ek3ou+Ajd5FqpLqzt7saYhnaQegVuU4UQ==", "dependencies": { "@nestjs/mapped-types": "1.1.0", "js-yaml": "4.1.0", @@ -3570,9 +3581,9 @@ } }, "node_modules/@types/node": { - "version": "18.7.6", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.7.6.tgz", - "integrity": "sha512-EdxgKRXgYsNITy5mjjXjVE/CS8YENSdhiagGrLqjG0pvA2owgJ6i4l7wy/PFZGC0B1/H20lWKN7ONVDNYDZm7A==", + "version": "18.7.16", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.7.16.tgz", + "integrity": "sha512-EQHhixfu+mkqHMZl1R2Ovuvn47PUw18azMJOTwSZr9/fhzHNGXAJ0ma0dayRVchprpCj0Kc1K1xKoWaATWF1qg==", "devOptional": true }, "node_modules/@types/nodemailer": { @@ -4831,7 +4842,7 @@ "node_modules/busboy": { "version": "0.2.14", "resolved": "https://registry.npmjs.org/busboy/-/busboy-0.2.14.tgz", - "integrity": "sha1-bCpiLvz0fFe7vh4qnDetNseSVFM=", + "integrity": "sha512-InWFDomvlkEj+xWLBfU3AvnbVYqeTWmQopiW0tWWEy5yehYm2YkGEc59sUmw/4ty5Zj/b0WHGs1LgecuBSBGrg==", "dependencies": { "dicer": "0.2.5", "readable-stream": "1.1.x" @@ -5660,7 +5671,7 @@ "node_modules/dicer": { "version": "0.2.5", "resolved": "https://registry.npmjs.org/dicer/-/dicer-0.2.5.tgz", - "integrity": "sha1-WZbAhrszIYyBLAkL3cCc0S+stw8=", + "integrity": "sha512-FDvbtnq7dzlPz0wyYlOExifDEZcu8h+rErEXgfxqmLfRfC/kJidEFh4+effJRO3P0xmfqyPbSMG0LveNRfTKVg==", "dependencies": { "readable-stream": "1.1.x", "streamsearch": "0.1.2" @@ -11257,14 +11268,14 @@ } }, "node_modules/terser": { - "version": "5.12.0", - "resolved": "https://registry.npmjs.org/terser/-/terser-5.12.0.tgz", - "integrity": "sha512-R3AUhNBGWiFc77HXag+1fXpAxTAFRQTJemlJKjAgD9r8xXTpjNKqIXwHM/o7Rh+O0kUJtS3WQVdBeMKFk5sw9A==", + "version": "5.15.0", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.15.0.tgz", + "integrity": "sha512-L1BJiXVmheAQQy+as0oF3Pwtlo4s3Wi1X2zNZ2NxOB4wx9bdS9Vk67XQENLFdLYGCK/Z2di53mTj/hBafR+dTA==", "dev": true, "dependencies": { + "@jridgewell/source-map": "^0.3.2", "acorn": "^8.5.0", "commander": "^2.20.0", - "source-map": "~0.7.2", "source-map-support": "~0.5.20" }, "bin": { @@ -11420,7 +11431,7 @@ "node_modules/thirty-two": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/thirty-two/-/thirty-two-1.0.2.tgz", - "integrity": "sha1-TKL//AKlEpDSdEueP1V2k8prYno=", + "integrity": "sha512-OEI0IWCe+Dw46019YLl6V10Us5bi574EvlJEOcAkB29IzQ/mYD1A6RyNHLjZPiHCmuodxvgF6U+vZO1L15lxVA==", "engines": { "node": ">=0.2.6" } @@ -14515,6 +14526,16 @@ "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==", "dev": true }, + "@jridgewell/source-map": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.2.tgz", + "integrity": "sha512-m7O9o2uR8k2ObDysZYzdfhb08VuEml5oWGiosa1VdaPZ/A6QyPkAJuwN0Q1lhULOf6B7MtQmHENS743hWtCrgw==", + "dev": true, + "requires": { + "@jridgewell/gen-mapping": "^0.3.0", + "@jridgewell/trace-mapping": "^0.3.9" + } + }, "@jridgewell/sourcemap-codec": { "version": "1.4.11", "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.11.tgz", @@ -14793,9 +14814,9 @@ } }, "@nestjs/swagger": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/@nestjs/swagger/-/swagger-6.1.0.tgz", - "integrity": "sha512-Lflplv216nXkH6By/jMggQjpuH1V67M07tgHXUAZujAwG3LAJ1CfSvzuFckK4MAb54xQTYvFgfVPWkXqvKXzdA==", + "version": "6.1.2", + "resolved": "https://registry.npmjs.org/@nestjs/swagger/-/swagger-6.1.2.tgz", + "integrity": "sha512-RU1DeTDyuN/lRXKFWaf7I9LYF34/ale3IIGeY3romAcXL/N9W0+50Ek3ou+Ajd5FqpLqzt7saYhnaQegVuU4UQ==", "requires": { "@nestjs/mapped-types": "1.1.0", "js-yaml": "4.1.0", @@ -15281,9 +15302,9 @@ } }, "@types/node": { - "version": "18.7.6", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.7.6.tgz", - "integrity": "sha512-EdxgKRXgYsNITy5mjjXjVE/CS8YENSdhiagGrLqjG0pvA2owgJ6i4l7wy/PFZGC0B1/H20lWKN7ONVDNYDZm7A==", + "version": "18.7.16", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.7.16.tgz", + "integrity": "sha512-EQHhixfu+mkqHMZl1R2Ovuvn47PUw18azMJOTwSZr9/fhzHNGXAJ0ma0dayRVchprpCj0Kc1K1xKoWaATWF1qg==", "devOptional": true }, "@types/nodemailer": { @@ -16249,7 +16270,7 @@ "busboy": { "version": "0.2.14", "resolved": "https://registry.npmjs.org/busboy/-/busboy-0.2.14.tgz", - "integrity": "sha1-bCpiLvz0fFe7vh4qnDetNseSVFM=", + "integrity": "sha512-InWFDomvlkEj+xWLBfU3AvnbVYqeTWmQopiW0tWWEy5yehYm2YkGEc59sUmw/4ty5Zj/b0WHGs1LgecuBSBGrg==", "requires": { "dicer": "0.2.5", "readable-stream": "1.1.x" @@ -16874,7 +16895,7 @@ "dicer": { "version": "0.2.5", "resolved": "https://registry.npmjs.org/dicer/-/dicer-0.2.5.tgz", - "integrity": "sha1-WZbAhrszIYyBLAkL3cCc0S+stw8=", + "integrity": "sha512-FDvbtnq7dzlPz0wyYlOExifDEZcu8h+rErEXgfxqmLfRfC/kJidEFh4+effJRO3P0xmfqyPbSMG0LveNRfTKVg==", "requires": { "readable-stream": "1.1.x", "streamsearch": "0.1.2" @@ -21096,14 +21117,14 @@ } }, "terser": { - "version": "5.12.0", - "resolved": "https://registry.npmjs.org/terser/-/terser-5.12.0.tgz", - "integrity": "sha512-R3AUhNBGWiFc77HXag+1fXpAxTAFRQTJemlJKjAgD9r8xXTpjNKqIXwHM/o7Rh+O0kUJtS3WQVdBeMKFk5sw9A==", + "version": "5.15.0", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.15.0.tgz", + "integrity": "sha512-L1BJiXVmheAQQy+as0oF3Pwtlo4s3Wi1X2zNZ2NxOB4wx9bdS9Vk67XQENLFdLYGCK/Z2di53mTj/hBafR+dTA==", "dev": true, "requires": { + "@jridgewell/source-map": "^0.3.2", "acorn": "^8.5.0", "commander": "^2.20.0", - "source-map": "~0.7.2", "source-map-support": "~0.5.20" }, "dependencies": { @@ -21214,7 +21235,7 @@ "thirty-two": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/thirty-two/-/thirty-two-1.0.2.tgz", - "integrity": "sha1-TKL//AKlEpDSdEueP1V2k8prYno=" + "integrity": "sha512-OEI0IWCe+Dw46019YLl6V10Us5bi574EvlJEOcAkB29IzQ/mYD1A6RyNHLjZPiHCmuodxvgF6U+vZO1L15lxVA==" }, "through": { "version": "2.3.8", diff --git a/package.json b/package.json index 0c78eb1..11c5c95 100644 --- a/package.json +++ b/package.json @@ -56,6 +56,7 @@ "reflect-metadata": "^0.1.13", "rimraf": "^3.0.2", "rxjs": "^7.5.6", + "thirty-two": "^1.0.2", "toml": "^3.0.0", "typeorm": "^0.3.7", "uuid": "^8.3.2" @@ -78,7 +79,7 @@ "@types/marked": "^4.0.4", "@types/mime-types": "^2.1.1", "@types/multer": "^1.4.7", - "@types/node": "^18.7.6", + "@types/node": "^18.7.16", "@types/nodemailer": "^6.4.5", "@types/qrcode": "^1.4.3", "@types/supertest": "^2.0.12", diff --git a/src/datasource.ts b/src/datasource.ts index 8b77e39..8d9cf45 100644 --- a/src/datasource.ts +++ b/src/datasource.ts @@ -18,4 +18,16 @@ const config = JSON.parse( JSON.stringify(toml.parse(readFileSync(CONFIG_PATH, { encoding: 'utf-8' }))), ); +if (config.database.entities?.length) { + config.database.entities = config.database.entities.map((path: string) => + join(process.cwd(), path), + ); +} + +if (config.database.migrations?.length) { + config.database.migrations = config.database.migrations.map((path: string) => + join(process.cwd(), path), + ); +} + export const AppDataSource = new DataSource(config.database); diff --git a/src/migration/1662799286155-initial.ts b/src/migration/1662799286155-initial.ts new file mode 100644 index 0000000..621c83f --- /dev/null +++ b/src/migration/1662799286155-initial.ts @@ -0,0 +1,296 @@ +import { MigrationInterface, QueryRunner } from 'typeorm'; + +export class initial1662799286155 implements MigrationInterface { + name = 'initial1662799286155'; + + public async up(queryRunner: QueryRunner): Promise { + await queryRunner.query( + `CREATE TABLE \`privilege\` (\`id\` int NOT NULL AUTO_INCREMENT, \`name\` text NOT NULL, PRIMARY KEY (\`id\`)) ENGINE=InnoDB`, + ); + await queryRunner.query( + `CREATE TABLE \`upload\` (\`id\` int NOT NULL AUTO_INCREMENT, \`original_name\` varchar(255) NOT NULL, \`mimetype\` varchar(255) NOT NULL, \`file\` varchar(255) NOT NULL, \`created_at\` datetime(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6), \`updated_at\` datetime(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6) ON UPDATE CURRENT_TIMESTAMP(6), \`uploaderId\` int NULL, PRIMARY KEY (\`id\`)) ENGINE=InnoDB`, + ); + await queryRunner.query( + `CREATE TABLE \`user\` (\`id\` int NOT NULL AUTO_INCREMENT, \`uuid\` varchar(36) NOT NULL, \`username\` varchar(26) NOT NULL, \`email\` varchar(255) NOT NULL, \`display_name\` varchar(32) NOT NULL, \`password\` text NULL, \`activated\` tinyint NOT NULL DEFAULT 0, \`activity_at\` timestamp NOT NULL, \`created_at\` datetime(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6), \`updated_at\` datetime(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6) ON UPDATE CURRENT_TIMESTAMP(6), \`pictureId\` int NULL, UNIQUE INDEX \`IDX_a95e949168be7b7ece1a2382fe\` (\`uuid\`), UNIQUE INDEX \`IDX_78a916df40e02a9deb1c4b75ed\` (\`username\`), UNIQUE INDEX \`IDX_e12875dfb3b1d92d7d7c5377e2\` (\`email\`), PRIMARY KEY (\`id\`)) ENGINE=InnoDB`, + ); + await queryRunner.query( + `CREATE TABLE \`audit_log\` (\`id\` int NOT NULL AUTO_INCREMENT, \`action\` text NOT NULL, \`content\` text NULL, \`actor_ip\` text NULL, \`actor_ua\` text NULL, \`flagged\` tinyint NOT NULL DEFAULT 0, \`created_at\` datetime(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6), \`actorId\` int NULL, PRIMARY KEY (\`id\`)) ENGINE=InnoDB`, + ); + await queryRunner.query( + `CREATE TABLE \`document\` (\`id\` int NOT NULL AUTO_INCREMENT, \`title\` text NOT NULL, \`slug\` text NOT NULL, \`body\` text NOT NULL, \`created_at\` datetime(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6), \`updated_at\` datetime(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6) ON UPDATE CURRENT_TIMESTAMP(6), \`authorId\` int NULL, PRIMARY KEY (\`id\`)) ENGINE=InnoDB`, + ); + await queryRunner.query( + `CREATE TABLE \`o_auth2_client_url\` (\`id\` int NOT NULL AUTO_INCREMENT, \`url\` varchar(255) NOT NULL, \`type\` enum ('redirect_uri', 'terms', 'privacy', 'website') NOT NULL, \`created_at\` timestamp(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6), \`updated_at\` timestamp(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6) ON UPDATE CURRENT_TIMESTAMP(6), \`clientId\` int NULL, PRIMARY KEY (\`id\`)) ENGINE=InnoDB`, + ); + await queryRunner.query( + `CREATE TABLE \`o_auth2_client\` (\`id\` int NOT NULL AUTO_INCREMENT, \`client_id\` varchar(36) NOT NULL, \`client_secret\` text NOT NULL, \`title\` varchar(255) NOT NULL, \`description\` text NULL, \`scope\` text NULL, \`grants\` text NOT NULL DEFAULT 'authorization_code', \`activated\` tinyint NOT NULL DEFAULT 0, \`verified\` tinyint NOT NULL DEFAULT 0, \`created_at\` datetime(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6), \`updated_at\` datetime(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6) ON UPDATE CURRENT_TIMESTAMP(6), \`pictureId\` int NULL, \`ownerId\` int NULL, UNIQUE INDEX \`IDX_e9d16c213910ad57bd05e97b42\` (\`client_id\`), PRIMARY KEY (\`id\`)) ENGINE=InnoDB`, + ); + await queryRunner.query( + `CREATE TABLE \`o_auth2_client_authorization\` (\`id\` int NOT NULL AUTO_INCREMENT, \`scope\` text NULL, \`expires_at\` timestamp NOT NULL, \`created_at\` datetime(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6), \`clientId\` int NULL, \`userId\` int NULL, PRIMARY KEY (\`id\`)) ENGINE=InnoDB`, + ); + await queryRunner.query( + `CREATE TABLE \`o_auth2_token\` (\`id\` int NOT NULL AUTO_INCREMENT, \`type\` enum ('code', 'access_token', 'refresh_token') NOT NULL, \`token\` text NOT NULL, \`scope\` text NULL, \`expires_at\` timestamp NOT NULL, \`created_at\` datetime(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6), \`updated_at\` datetime(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6) ON UPDATE CURRENT_TIMESTAMP(6), \`userId\` int NULL, \`clientId\` int NULL, PRIMARY KEY (\`id\`)) ENGINE=InnoDB`, + ); + await queryRunner.query( + `CREATE TABLE \`user_token\` (\`id\` int NOT NULL AUTO_INCREMENT, \`token\` text NOT NULL, \`type\` enum ('generic', 'activation', 'deactivation', 'password', 'login', 'gdpr', 'totp', 'recovery') NOT NULL, \`expires_at\` timestamp NULL, \`created_at\` datetime(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6), \`userId\` int NULL, PRIMARY KEY (\`id\`)) ENGINE=InnoDB`, + ); + await queryRunner.query( + `CREATE TABLE \`user_privileges_privilege\` (\`userId\` int NOT NULL, \`privilegeId\` int NOT NULL, INDEX \`IDX_0664a7ff494a1859a09014c0f1\` (\`userId\`), INDEX \`IDX_e71171f4ed20bc8564a1819d0b\` (\`privilegeId\`), PRIMARY KEY (\`userId\`, \`privilegeId\`)) ENGINE=InnoDB`, + ); + await queryRunner.query( + `ALTER TABLE \`upload\` DROP COLUMN \`created_at\``, + ); + await queryRunner.query( + `ALTER TABLE \`upload\` ADD \`created_at\` timestamp(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6)`, + ); + await queryRunner.query( + `ALTER TABLE \`upload\` DROP COLUMN \`updated_at\``, + ); + await queryRunner.query( + `ALTER TABLE \`upload\` ADD \`updated_at\` timestamp(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6) ON UPDATE CURRENT_TIMESTAMP(6)`, + ); + await queryRunner.query(`ALTER TABLE \`user\` DROP COLUMN \`created_at\``); + await queryRunner.query( + `ALTER TABLE \`user\` ADD \`created_at\` timestamp(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6)`, + ); + await queryRunner.query(`ALTER TABLE \`user\` DROP COLUMN \`updated_at\``); + await queryRunner.query( + `ALTER TABLE \`user\` ADD \`updated_at\` timestamp(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6) ON UPDATE CURRENT_TIMESTAMP(6)`, + ); + await queryRunner.query( + `ALTER TABLE \`document\` DROP COLUMN \`created_at\``, + ); + await queryRunner.query( + `ALTER TABLE \`document\` ADD \`created_at\` timestamp(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6)`, + ); + await queryRunner.query( + `ALTER TABLE \`document\` DROP COLUMN \`updated_at\``, + ); + await queryRunner.query( + `ALTER TABLE \`document\` ADD \`updated_at\` timestamp(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6) ON UPDATE CURRENT_TIMESTAMP(6)`, + ); + await queryRunner.query( + `ALTER TABLE \`o_auth2_client\` DROP COLUMN \`created_at\``, + ); + await queryRunner.query( + `ALTER TABLE \`o_auth2_client\` ADD \`created_at\` timestamp(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6)`, + ); + await queryRunner.query( + `ALTER TABLE \`o_auth2_client\` DROP COLUMN \`updated_at\``, + ); + await queryRunner.query( + `ALTER TABLE \`o_auth2_client\` ADD \`updated_at\` timestamp(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6) ON UPDATE CURRENT_TIMESTAMP(6)`, + ); + await queryRunner.query( + `ALTER TABLE \`o_auth2_client_authorization\` DROP COLUMN \`created_at\``, + ); + await queryRunner.query( + `ALTER TABLE \`o_auth2_client_authorization\` ADD \`created_at\` timestamp(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6)`, + ); + await queryRunner.query( + `ALTER TABLE \`o_auth2_token\` DROP COLUMN \`created_at\``, + ); + await queryRunner.query( + `ALTER TABLE \`o_auth2_token\` ADD \`created_at\` timestamp(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6)`, + ); + await queryRunner.query( + `ALTER TABLE \`o_auth2_token\` DROP COLUMN \`updated_at\``, + ); + await queryRunner.query( + `ALTER TABLE \`o_auth2_token\` ADD \`updated_at\` timestamp(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6) ON UPDATE CURRENT_TIMESTAMP(6)`, + ); + await queryRunner.query( + `ALTER TABLE \`user_token\` DROP COLUMN \`created_at\``, + ); + await queryRunner.query( + `ALTER TABLE \`user_token\` ADD \`created_at\` timestamp(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6)`, + ); + await queryRunner.query( + `ALTER TABLE \`upload\` ADD CONSTRAINT \`FK_7b8d52838a953b188255682597b\` FOREIGN KEY (\`uploaderId\`) REFERENCES \`user\`(\`id\`) ON DELETE SET NULL ON UPDATE CASCADE`, + ); + await queryRunner.query( + `ALTER TABLE \`user\` ADD CONSTRAINT \`FK_7478a15985dbfa32ed5fc77a7a1\` FOREIGN KEY (\`pictureId\`) REFERENCES \`upload\`(\`id\`) ON DELETE SET NULL ON UPDATE CASCADE`, + ); + await queryRunner.query( + `ALTER TABLE \`audit_log\` ADD CONSTRAINT \`FK_cb6aa6f6fd56f08eafb60316225\` FOREIGN KEY (\`actorId\`) REFERENCES \`user\`(\`id\`) ON DELETE SET NULL ON UPDATE NO ACTION`, + ); + await queryRunner.query( + `ALTER TABLE \`document\` ADD CONSTRAINT \`FK_6a2eb13cadfc503989cbe367572\` FOREIGN KEY (\`authorId\`) REFERENCES \`user\`(\`id\`) ON DELETE NO ACTION ON UPDATE NO ACTION`, + ); + await queryRunner.query( + `ALTER TABLE \`o_auth2_client_url\` ADD CONSTRAINT \`FK_aca59c7bdd65987487eea98d00f\` FOREIGN KEY (\`clientId\`) REFERENCES \`o_auth2_client\`(\`id\`) ON DELETE NO ACTION ON UPDATE NO ACTION`, + ); + await queryRunner.query( + `ALTER TABLE \`o_auth2_client\` ADD CONSTRAINT \`FK_e8d65b1eec13474e493420517d7\` FOREIGN KEY (\`pictureId\`) REFERENCES \`upload\`(\`id\`) ON DELETE SET NULL ON UPDATE NO ACTION`, + ); + await queryRunner.query( + `ALTER TABLE \`o_auth2_client\` ADD CONSTRAINT \`FK_4a6c878506b872e85b3d07f6252\` FOREIGN KEY (\`ownerId\`) REFERENCES \`user\`(\`id\`) ON DELETE SET NULL ON UPDATE NO ACTION`, + ); + await queryRunner.query( + `ALTER TABLE \`o_auth2_client_authorization\` ADD CONSTRAINT \`FK_9ca9ebb654e7ce71954d5fdb281\` FOREIGN KEY (\`clientId\`) REFERENCES \`o_auth2_client\`(\`id\`) ON DELETE NO ACTION ON UPDATE NO ACTION`, + ); + await queryRunner.query( + `ALTER TABLE \`o_auth2_client_authorization\` ADD CONSTRAINT \`FK_8227110f58510b7233f3db90cfb\` FOREIGN KEY (\`userId\`) REFERENCES \`user\`(\`id\`) ON DELETE NO ACTION ON UPDATE NO ACTION`, + ); + await queryRunner.query( + `ALTER TABLE \`o_auth2_token\` ADD CONSTRAINT \`FK_81ffb9b8d672cf3af1af9e789f3\` FOREIGN KEY (\`userId\`) REFERENCES \`user\`(\`id\`) ON DELETE NO ACTION ON UPDATE NO ACTION`, + ); + await queryRunner.query( + `ALTER TABLE \`o_auth2_token\` ADD CONSTRAINT \`FK_3ecb760b321ef9bbab635f05b45\` FOREIGN KEY (\`clientId\`) REFERENCES \`o_auth2_client\`(\`id\`) ON DELETE NO ACTION ON UPDATE NO ACTION`, + ); + await queryRunner.query( + `ALTER TABLE \`user_token\` ADD CONSTRAINT \`FK_d37db50eecdf9b8ce4eedd2f918\` FOREIGN KEY (\`userId\`) REFERENCES \`user\`(\`id\`) ON DELETE NO ACTION ON UPDATE NO ACTION`, + ); + await queryRunner.query( + `ALTER TABLE \`user_privileges_privilege\` ADD CONSTRAINT \`FK_0664a7ff494a1859a09014c0f17\` FOREIGN KEY (\`userId\`) REFERENCES \`user\`(\`id\`) ON DELETE CASCADE ON UPDATE CASCADE`, + ); + await queryRunner.query( + `ALTER TABLE \`user_privileges_privilege\` ADD CONSTRAINT \`FK_e71171f4ed20bc8564a1819d0b7\` FOREIGN KEY (\`privilegeId\`) REFERENCES \`privilege\`(\`id\`) ON DELETE CASCADE ON UPDATE CASCADE`, + ); + await queryRunner.query( + `INSERT INTO \`privilege\` (name) VALUES ('admin'), ('admin:user'), ('admin:user:privilege'), ('admin:oauth2'), ('admin:audit'), ('admin:document'), ('self:oauth2')`, + ); + } + + public async down(queryRunner: QueryRunner): Promise { + await queryRunner.query( + `ALTER TABLE \`user_privileges_privilege\` DROP FOREIGN KEY \`FK_e71171f4ed20bc8564a1819d0b7\``, + ); + await queryRunner.query( + `ALTER TABLE \`user_privileges_privilege\` DROP FOREIGN KEY \`FK_0664a7ff494a1859a09014c0f17\``, + ); + await queryRunner.query( + `ALTER TABLE \`user_token\` DROP FOREIGN KEY \`FK_d37db50eecdf9b8ce4eedd2f918\``, + ); + await queryRunner.query( + `ALTER TABLE \`o_auth2_token\` DROP FOREIGN KEY \`FK_3ecb760b321ef9bbab635f05b45\``, + ); + await queryRunner.query( + `ALTER TABLE \`o_auth2_token\` DROP FOREIGN KEY \`FK_81ffb9b8d672cf3af1af9e789f3\``, + ); + await queryRunner.query( + `ALTER TABLE \`o_auth2_client_authorization\` DROP FOREIGN KEY \`FK_8227110f58510b7233f3db90cfb\``, + ); + await queryRunner.query( + `ALTER TABLE \`o_auth2_client_authorization\` DROP FOREIGN KEY \`FK_9ca9ebb654e7ce71954d5fdb281\``, + ); + await queryRunner.query( + `ALTER TABLE \`o_auth2_client\` DROP FOREIGN KEY \`FK_4a6c878506b872e85b3d07f6252\``, + ); + await queryRunner.query( + `ALTER TABLE \`o_auth2_client\` DROP FOREIGN KEY \`FK_e8d65b1eec13474e493420517d7\``, + ); + await queryRunner.query( + `ALTER TABLE \`o_auth2_client_url\` DROP FOREIGN KEY \`FK_aca59c7bdd65987487eea98d00f\``, + ); + await queryRunner.query( + `ALTER TABLE \`document\` DROP FOREIGN KEY \`FK_6a2eb13cadfc503989cbe367572\``, + ); + await queryRunner.query( + `ALTER TABLE \`audit_log\` DROP FOREIGN KEY \`FK_cb6aa6f6fd56f08eafb60316225\``, + ); + await queryRunner.query( + `ALTER TABLE \`user\` DROP FOREIGN KEY \`FK_7478a15985dbfa32ed5fc77a7a1\``, + ); + await queryRunner.query( + `ALTER TABLE \`upload\` DROP FOREIGN KEY \`FK_7b8d52838a953b188255682597b\``, + ); + await queryRunner.query( + `ALTER TABLE \`user_token\` DROP COLUMN \`created_at\``, + ); + await queryRunner.query( + `ALTER TABLE \`user_token\` ADD \`created_at\` datetime(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6)`, + ); + await queryRunner.query( + `ALTER TABLE \`o_auth2_token\` DROP COLUMN \`updated_at\``, + ); + await queryRunner.query( + `ALTER TABLE \`o_auth2_token\` ADD \`updated_at\` datetime(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6) ON UPDATE CURRENT_TIMESTAMP(6)`, + ); + await queryRunner.query( + `ALTER TABLE \`o_auth2_token\` DROP COLUMN \`created_at\``, + ); + await queryRunner.query( + `ALTER TABLE \`o_auth2_token\` ADD \`created_at\` datetime(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6)`, + ); + await queryRunner.query( + `ALTER TABLE \`o_auth2_client_authorization\` DROP COLUMN \`created_at\``, + ); + await queryRunner.query( + `ALTER TABLE \`o_auth2_client_authorization\` ADD \`created_at\` datetime(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6)`, + ); + await queryRunner.query( + `ALTER TABLE \`o_auth2_client\` DROP COLUMN \`updated_at\``, + ); + await queryRunner.query( + `ALTER TABLE \`o_auth2_client\` ADD \`updated_at\` datetime(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6) ON UPDATE CURRENT_TIMESTAMP(6)`, + ); + await queryRunner.query( + `ALTER TABLE \`o_auth2_client\` DROP COLUMN \`created_at\``, + ); + await queryRunner.query( + `ALTER TABLE \`o_auth2_client\` ADD \`created_at\` datetime(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6)`, + ); + await queryRunner.query( + `ALTER TABLE \`document\` DROP COLUMN \`updated_at\``, + ); + await queryRunner.query( + `ALTER TABLE \`document\` ADD \`updated_at\` datetime(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6) ON UPDATE CURRENT_TIMESTAMP(6)`, + ); + await queryRunner.query( + `ALTER TABLE \`document\` DROP COLUMN \`created_at\``, + ); + await queryRunner.query( + `ALTER TABLE \`document\` ADD \`created_at\` datetime(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6)`, + ); + await queryRunner.query(`ALTER TABLE \`user\` DROP COLUMN \`updated_at\``); + await queryRunner.query( + `ALTER TABLE \`user\` ADD \`updated_at\` datetime(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6) ON UPDATE CURRENT_TIMESTAMP(6)`, + ); + await queryRunner.query(`ALTER TABLE \`user\` DROP COLUMN \`created_at\``); + await queryRunner.query( + `ALTER TABLE \`user\` ADD \`created_at\` datetime(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6)`, + ); + await queryRunner.query( + `ALTER TABLE \`upload\` DROP COLUMN \`updated_at\``, + ); + await queryRunner.query( + `ALTER TABLE \`upload\` ADD \`updated_at\` datetime(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6) ON UPDATE CURRENT_TIMESTAMP(6)`, + ); + await queryRunner.query( + `ALTER TABLE \`upload\` DROP COLUMN \`created_at\``, + ); + await queryRunner.query( + `ALTER TABLE \`upload\` ADD \`created_at\` datetime(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6)`, + ); + await queryRunner.query( + `DROP INDEX \`IDX_e71171f4ed20bc8564a1819d0b\` ON \`user_privileges_privilege\``, + ); + await queryRunner.query( + `DROP INDEX \`IDX_0664a7ff494a1859a09014c0f1\` ON \`user_privileges_privilege\``, + ); + await queryRunner.query(`DROP TABLE \`user_privileges_privilege\``); + await queryRunner.query(`DROP TABLE \`user_token\``); + await queryRunner.query(`DROP TABLE \`o_auth2_token\``); + await queryRunner.query(`DROP TABLE \`o_auth2_client_authorization\``); + await queryRunner.query( + `DROP INDEX \`IDX_e9d16c213910ad57bd05e97b42\` ON \`o_auth2_client\``, + ); + await queryRunner.query(`DROP TABLE \`o_auth2_client\``); + await queryRunner.query(`DROP TABLE \`o_auth2_client_url\``); + await queryRunner.query(`DROP TABLE \`document\``); + await queryRunner.query(`DROP TABLE \`audit_log\``); + await queryRunner.query( + `DROP INDEX \`IDX_e12875dfb3b1d92d7d7c5377e2\` ON \`user\``, + ); + await queryRunner.query( + `DROP INDEX \`IDX_78a916df40e02a9deb1c4b75ed\` ON \`user\``, + ); + await queryRunner.query( + `DROP INDEX \`IDX_a95e949168be7b7ece1a2382fe\` ON \`user\``, + ); + await queryRunner.query(`DROP TABLE \`user\``); + await queryRunner.query(`DROP TABLE \`upload\``); + await queryRunner.query(`DROP TABLE \`privilege\``); + } +} diff --git a/src/modules/objects/privilege/privilege.entity.ts b/src/modules/objects/privilege/privilege.entity.ts index 676588f..005fd32 100644 --- a/src/modules/objects/privilege/privilege.entity.ts +++ b/src/modules/objects/privilege/privilege.entity.ts @@ -16,5 +16,6 @@ export class Privilege { admin:user:privilege admin:document admin:oauth2 - self: oauth2 + admin:audit + self:oauth2 */ diff --git a/src/tools/migrate-old-icynet/.gitignore b/src/tools/migrate-old-icynet/.gitignore new file mode 100644 index 0000000..89e7c42 --- /dev/null +++ b/src/tools/migrate-old-icynet/.gitignore @@ -0,0 +1,4 @@ +*.json +*.sql +*.sh +docker-compose.yml diff --git a/src/tools/migrate-old-icynet/migrate.ts b/src/tools/migrate-old-icynet/migrate.ts new file mode 100644 index 0000000..0d37b45 --- /dev/null +++ b/src/tools/migrate-old-icynet/migrate.ts @@ -0,0 +1,85 @@ +import { AppDataSource } from 'src/datasource'; +import * as fs from 'fs/promises'; +import { join } from 'path'; +import { User } from 'src/modules/objects/user/user.entity'; +import { OAuth2Client } from 'src/modules/objects/oauth2-client/oauth2-client.entity'; +import { UserToken } from 'src/modules/objects/user-token/user-token.entity'; +import { AuditLog } from 'src/modules/objects/audit/audit.entity'; +import { Upload } from 'src/modules/objects/upload/upload.entity'; +import { OAuth2ClientURL } from 'src/modules/objects/oauth2-client/oauth2-client-url.entity'; + +async function run() { + await AppDataSource.initialize(); + const dumpFile = await fs.readFile(join(__dirname, 'output.json'), { + encoding: 'utf-8', + }); + const dump = JSON.parse(dumpFile); + + const userRepo = AppDataSource.getRepository(User); + const uploadRepo = AppDataSource.getRepository(Upload); + const oauth2Repo = AppDataSource.getRepository(OAuth2Client); + const oauth2URLRepo = AppDataSource.getRepository(OAuth2ClientURL); + const tokenRepo = AppDataSource.getRepository(UserToken); + const auditRepo = AppDataSource.getRepository(AuditLog); + + const users: User[] = []; + + console.log('Saving users...'); + for (const user of dump.users) { + const newUser = new User(); + Object.assign(newUser, user); + await userRepo.save(newUser); + users.push(newUser); + } + + console.log('Saving user uploads...'); + for (const user of dump.users.filter(({ picture }) => picture)) { + const belonging = users.find(({ id }) => id === user.id); + const newUpload = new Upload(); + + Object.assign(newUpload, user.picture); + newUpload.uploader = belonging; + await uploadRepo.save(newUpload); + + belonging.picture = newUpload; + await userRepo.save(belonging); + } + + console.log('Saving OAuth2 clients...'); + for (const client of dump.clients) { + const owner = users.find(({ id }) => id === client.ownerId); + const newClient = new OAuth2Client(); + Object.assign(newClient, client); + newClient.owner = owner; + await oauth2Repo.save(newClient); + + for (const url of client.urls || []) { + const newURL = new OAuth2ClientURL(); + Object.assign(newURL, url); + newURL.client = newClient; + await oauth2URLRepo.save(newURL); + } + } + + console.log('Saving tokens...'); + for (const token of dump.totp) { + const owner = users.find(({ id }) => id === token.userId); + const newTOTP = new UserToken(); + Object.assign(newTOTP, token); + newTOTP.user = owner; + await tokenRepo.save(newTOTP); + } + + console.log('Saving audit logs...'); + for (const audit of dump.auditLogs) { + const owner = users.find(({ id }) => id === audit.actorId); + const newAudit = new AuditLog(); + Object.assign(newAudit, audit); + newAudit.actor = owner; + await auditRepo.save(newAudit); + } +} + +run() + .catch(console.error) + .then(() => process.exit(0)); diff --git a/src/tools/migrate-old-icynet/to-json.mjs b/src/tools/migrate-old-icynet/to-json.mjs new file mode 100644 index 0000000..6811392 --- /dev/null +++ b/src/tools/migrate-old-icynet/to-json.mjs @@ -0,0 +1,107 @@ +import { createConnection } from 'mysql2/promise'; +import tt from 'thirty-two'; +import fs from 'fs/promises'; + +async function init() { + const dump = await createConnection({ + host: 'localhost', + user: 'icynet', + database: 'icynet', + port: 13306, + password: 'icynet', + }); + + const userQuery = await dump.execute('SELECT * FROM users'); + let users = userQuery[0]; + + const oauthQuery = await dump.execute('SELECT * FROM oauth2_client'); + const clients = oauthQuery[0].map((entry) => ({ + ...entry, + client_id: entry.id, + client_secret: entry.secret, + secret: undefined, + icon: undefined, + activated: true, + verified: Boolean(entry.verified), + ownerId: entry.user_id, + user_id: undefined, + urls: [ + entry.url + ? { + url: entry.url, + type: 'website', + created_at: entry.created_at, + } + : null, + entry.redirect_url + ? { + url: entry.redirect_url, + type: 'redirect_uri', + created_at: entry.created_at, + } + : null, + ].filter((item) => item), + url: undefined, + redirect_url: undefined, + })); + + const totpQuery = await dump.execute('SELECT * FROM totp_token'); + const totp = totpQuery[0].map((item) => ({ + token: tt.encode(item.token).toString(), + created_at: item.created_at, + type: 'totp', + userId: item.user_id, + })); + + const uploads = users + .filter((user) => user.avatar_file) + .map((item) => ({ + original_name: 'blob', + file: item.avatar_file, + mimetype: item.avatar_file.endsWith('.png') ? 'image/png' : 'image/jpeg', + created_at: item.created_at, + updated_at: item.updated_at, + uploaderId: item.id, + })); + + const auditLogs = [ + ...users.map((entry) => ({ + action: 'registration', + actorId: entry.id, + actor_ip: entry.ip_address, + created_at: entry.created_at, + })), + ...totp.map((entry) => ({ + action: 'totp_activate', + actorId: entry.userId, + created_at: entry.created_at, + })), + ]; + + users = users.map((entry) => ({ + ...entry, + locked: undefined, + nw_privilege: undefined, + ip_address: undefined, + avatar_file: undefined, + password: !entry.password && entry.activated ? 'external' : entry.password, + activated: Boolean(entry.activated), + picture: uploads.find((item) => item.file === entry.avatar_file), + })); + + await fs.writeFile( + 'output.json', + JSON.stringify( + { + users, + clients, + totp, + auditLogs, + }, + undefined, + 2, + ), + ); +} + +init().catch(console.error).then(process.exit);