From 427d6844888d8df1abd02f913a8f955197028520 Mon Sep 17 00:00:00 2001 From: Rahul R Date: Sat, 13 Jul 2024 13:22:11 +0530 Subject: [PATCH 1/2] [Fix] Product Review Plugin Migration (#7961) * fix: added missing columns for product review entity * feat(migration): created product_review [table] for PostgreSQL * feat(migration): created product_review [table] for SQLite * feat(migration): created product_review [table] for MySQL * fix: enabled Product Review Plugin * fix(cspell): typo spelling :-) --- .cspell.json | 4 +- apps/api/src/plugins.ts | 6 +- .../1720852356593-CreateProductReviewTable.ts | 250 ++++++++++++++++++ packages/plugins/product-reviews/package.json | 4 + .../src/lib/entities/product-review.entity.ts | 106 +++++++- .../src/lib/product-review.types.ts | 23 ++ 6 files changed, 385 insertions(+), 8 deletions(-) create mode 100644 packages/core/src/database/migrations/1720852356593-CreateProductReviewTable.ts create mode 100644 packages/plugins/product-reviews/src/lib/product-review.types.ts diff --git a/.cspell.json b/.cspell.json index 621ac92c526..e2dcfca530c 100644 --- a/.cspell.json +++ b/.cspell.json @@ -476,7 +476,9 @@ "allcaps", "iubgreen", "unixepoch", - "macbook" + "macbook", + "upvotes", + "downvotes" ], "useGitignore": true, "ignorePaths": [ diff --git a/apps/api/src/plugins.ts b/apps/api/src/plugins.ts index 63ba3c8b1d2..20b2e2efc72 100644 --- a/apps/api/src/plugins.ts +++ b/apps/api/src/plugins.ts @@ -10,7 +10,7 @@ import { JitsuAnalyticsPlugin } from '@gauzy/plugin-jitsu-analytics'; import { JobProposalPlugin } from '@gauzy/plugin-job-proposal'; import { JobSearchPlugin } from '@gauzy/plugin-job-search'; import { KnowledgeBasePlugin } from '@gauzy/plugin-knowledge-base'; -// import { ProductReviewsPlugin } from '@gauzy/plugin-product-reviews'; +import { ProductReviewsPlugin } from '@gauzy/plugin-product-reviews'; import { SentryTracing as SentryPlugin } from './sentry'; @@ -48,7 +48,7 @@ export const plugins = [ // Indicates the inclusion or intention to use the JobSearchPlugin in the codebase. JobSearchPlugin, // Indicates the inclusion or intention to use the KnowledgeBasePlugin in the codebase. - KnowledgeBasePlugin + KnowledgeBasePlugin, // Indicates the inclusion or intention to use the ProductReviewsPlugin in the codebase. - // ProductReviewsPlugin + ProductReviewsPlugin ]; diff --git a/packages/core/src/database/migrations/1720852356593-CreateProductReviewTable.ts b/packages/core/src/database/migrations/1720852356593-CreateProductReviewTable.ts new file mode 100644 index 00000000000..d8aeaa58a7c --- /dev/null +++ b/packages/core/src/database/migrations/1720852356593-CreateProductReviewTable.ts @@ -0,0 +1,250 @@ +import { MigrationInterface, QueryRunner } from 'typeorm'; +import { yellow } from 'chalk'; +import { DatabaseTypeEnum } from '@gauzy/config'; + +export class CreateProductReviewTable1720852356593 implements MigrationInterface { + name = 'CreateProductReviewTable1720852356593'; + + /** + * Up Migration + * + * @param queryRunner + */ + public async up(queryRunner: QueryRunner): Promise { + console.log(yellow(this.name + ' start running!')); + + switch (queryRunner.connection.options.type) { + case DatabaseTypeEnum.sqlite: + case DatabaseTypeEnum.betterSqlite3: + await this.sqliteUpQueryRunner(queryRunner); + break; + case DatabaseTypeEnum.postgres: + await this.postgresUpQueryRunner(queryRunner); + break; + case DatabaseTypeEnum.mysql: + await this.mysqlUpQueryRunner(queryRunner); + break; + default: + throw Error(`Unsupported database: ${queryRunner.connection.options.type}`); + } + } + + /** + * Down Migration + * + * @param queryRunner + */ + public async down(queryRunner: QueryRunner): Promise { + switch (queryRunner.connection.options.type) { + case DatabaseTypeEnum.sqlite: + case DatabaseTypeEnum.betterSqlite3: + await this.sqliteDownQueryRunner(queryRunner); + break; + case DatabaseTypeEnum.postgres: + await this.postgresDownQueryRunner(queryRunner); + break; + case DatabaseTypeEnum.mysql: + await this.mysqlDownQueryRunner(queryRunner); + break; + default: + throw Error(`Unsupported database: ${queryRunner.connection.options.type}`); + } + } + + /** + * PostgresDB Up Migration + * + * @param queryRunner + */ + public async postgresUpQueryRunner(queryRunner: QueryRunner): Promise { + await queryRunner.query( + `CREATE TABLE "product_review" ("deletedAt" TIMESTAMP, "id" uuid NOT NULL DEFAULT gen_random_uuid(), "createdAt" TIMESTAMP NOT NULL DEFAULT now(), "updatedAt" TIMESTAMP NOT NULL DEFAULT now(), "isActive" boolean DEFAULT true, "isArchived" boolean DEFAULT false, "tenantId" uuid, "organizationId" uuid, "title" character varying, "description" text, "rating" integer NOT NULL, "upvotes" integer NOT NULL DEFAULT '0', "downvotes" integer NOT NULL DEFAULT '0', "status" character varying NOT NULL DEFAULT 'pending', "editedAt" TIMESTAMP, "productId" uuid NOT NULL, "userId" uuid NOT NULL, CONSTRAINT "PK_6c00bd3bbee662e1f7a97dbce9a" PRIMARY KEY ("id"))` + ); + await queryRunner.query(`CREATE INDEX "IDX_6248458c7e237cef4adac4761d" ON "product_review" ("isActive") `); + await queryRunner.query(`CREATE INDEX "IDX_9cb4931c7348b6c171f13b6216" ON "product_review" ("isArchived") `); + await queryRunner.query(`CREATE INDEX "IDX_586e6b1273ba2732ec0ee41a80" ON "product_review" ("tenantId") `); + await queryRunner.query( + `CREATE INDEX "IDX_28ce717020729e36aa06cca5c5" ON "product_review" ("organizationId") ` + ); + await queryRunner.query(`CREATE INDEX "IDX_28f06c5655d507668b8839b59a" ON "product_review" ("upvotes") `); + await queryRunner.query(`CREATE INDEX "IDX_f3591fd59cc32b585c3ba7d3ae" ON "product_review" ("downvotes") `); + await queryRunner.query(`CREATE INDEX "IDX_913f7739f1262fc8c70cbbafa3" ON "product_review" ("editedAt") `); + await queryRunner.query(`CREATE INDEX "IDX_06e7335708b5e7870f1eaa608d" ON "product_review" ("productId") `); + await queryRunner.query(`CREATE INDEX "IDX_db21a1dc776b455ee83eb7ff88" ON "product_review" ("userId") `); + await queryRunner.query( + `ALTER TABLE "product_review" ADD CONSTRAINT "FK_586e6b1273ba2732ec0ee41a80b" FOREIGN KEY ("tenantId") REFERENCES "tenant"("id") ON DELETE CASCADE ON UPDATE NO ACTION` + ); + await queryRunner.query( + `ALTER TABLE "product_review" ADD CONSTRAINT "FK_28ce717020729e36aa06cca5c54" FOREIGN KEY ("organizationId") REFERENCES "organization"("id") ON DELETE CASCADE ON UPDATE CASCADE` + ); + await queryRunner.query( + `ALTER TABLE "product_review" ADD CONSTRAINT "FK_06e7335708b5e7870f1eaa608d2" FOREIGN KEY ("productId") REFERENCES "product"("id") ON DELETE CASCADE ON UPDATE NO ACTION` + ); + await queryRunner.query( + `ALTER TABLE "product_review" ADD CONSTRAINT "FK_db21a1dc776b455ee83eb7ff88e" FOREIGN KEY ("userId") REFERENCES "user"("id") ON DELETE CASCADE ON UPDATE NO ACTION` + ); + } + + /** + * PostgresDB Down Migration + * + * @param queryRunner + */ + public async postgresDownQueryRunner(queryRunner: QueryRunner): Promise { + await queryRunner.query(`ALTER TABLE "product_review" DROP CONSTRAINT "FK_db21a1dc776b455ee83eb7ff88e"`); + await queryRunner.query(`ALTER TABLE "product_review" DROP CONSTRAINT "FK_06e7335708b5e7870f1eaa608d2"`); + await queryRunner.query(`ALTER TABLE "product_review" DROP CONSTRAINT "FK_28ce717020729e36aa06cca5c54"`); + await queryRunner.query(`ALTER TABLE "product_review" DROP CONSTRAINT "FK_586e6b1273ba2732ec0ee41a80b"`); + await queryRunner.query(`DROP INDEX "public"."IDX_db21a1dc776b455ee83eb7ff88"`); + await queryRunner.query(`DROP INDEX "public"."IDX_06e7335708b5e7870f1eaa608d"`); + await queryRunner.query(`DROP INDEX "public"."IDX_913f7739f1262fc8c70cbbafa3"`); + await queryRunner.query(`DROP INDEX "public"."IDX_f3591fd59cc32b585c3ba7d3ae"`); + await queryRunner.query(`DROP INDEX "public"."IDX_28f06c5655d507668b8839b59a"`); + await queryRunner.query(`DROP INDEX "public"."IDX_28ce717020729e36aa06cca5c5"`); + await queryRunner.query(`DROP INDEX "public"."IDX_586e6b1273ba2732ec0ee41a80"`); + await queryRunner.query(`DROP INDEX "public"."IDX_9cb4931c7348b6c171f13b6216"`); + await queryRunner.query(`DROP INDEX "public"."IDX_6248458c7e237cef4adac4761d"`); + await queryRunner.query(`DROP TABLE "product_review"`); + } + + /** + * SqliteDB and BetterSQlite3DB Up Migration + * + * @param queryRunner + */ + public async sqliteUpQueryRunner(queryRunner: QueryRunner): Promise { + await queryRunner.query( + `CREATE TABLE "product_review" ("deletedAt" datetime, "id" varchar PRIMARY KEY NOT NULL, "createdAt" datetime NOT NULL DEFAULT (datetime('now')), "updatedAt" datetime NOT NULL DEFAULT (datetime('now')), "isActive" boolean DEFAULT (1), "isArchived" boolean DEFAULT (0), "tenantId" varchar, "organizationId" varchar, "title" varchar, "description" text, "rating" integer NOT NULL, "upvotes" integer NOT NULL DEFAULT (0), "downvotes" integer NOT NULL DEFAULT (0), "status" varchar NOT NULL DEFAULT ('pending'), "editedAt" datetime, "productId" varchar NOT NULL, "userId" varchar NOT NULL)` + ); + await queryRunner.query(`CREATE INDEX "IDX_6248458c7e237cef4adac4761d" ON "product_review" ("isActive") `); + await queryRunner.query(`CREATE INDEX "IDX_9cb4931c7348b6c171f13b6216" ON "product_review" ("isArchived") `); + await queryRunner.query(`CREATE INDEX "IDX_586e6b1273ba2732ec0ee41a80" ON "product_review" ("tenantId") `); + await queryRunner.query( + `CREATE INDEX "IDX_28ce717020729e36aa06cca5c5" ON "product_review" ("organizationId") ` + ); + await queryRunner.query(`CREATE INDEX "IDX_28f06c5655d507668b8839b59a" ON "product_review" ("upvotes") `); + await queryRunner.query(`CREATE INDEX "IDX_f3591fd59cc32b585c3ba7d3ae" ON "product_review" ("downvotes") `); + await queryRunner.query(`CREATE INDEX "IDX_913f7739f1262fc8c70cbbafa3" ON "product_review" ("editedAt") `); + await queryRunner.query(`CREATE INDEX "IDX_06e7335708b5e7870f1eaa608d" ON "product_review" ("productId") `); + await queryRunner.query(`CREATE INDEX "IDX_db21a1dc776b455ee83eb7ff88" ON "product_review" ("userId") `); + await queryRunner.query(`DROP INDEX "IDX_6248458c7e237cef4adac4761d"`); + await queryRunner.query(`DROP INDEX "IDX_9cb4931c7348b6c171f13b6216"`); + await queryRunner.query(`DROP INDEX "IDX_586e6b1273ba2732ec0ee41a80"`); + await queryRunner.query(`DROP INDEX "IDX_28ce717020729e36aa06cca5c5"`); + await queryRunner.query(`DROP INDEX "IDX_28f06c5655d507668b8839b59a"`); + await queryRunner.query(`DROP INDEX "IDX_f3591fd59cc32b585c3ba7d3ae"`); + await queryRunner.query(`DROP INDEX "IDX_913f7739f1262fc8c70cbbafa3"`); + await queryRunner.query(`DROP INDEX "IDX_06e7335708b5e7870f1eaa608d"`); + await queryRunner.query(`DROP INDEX "IDX_db21a1dc776b455ee83eb7ff88"`); + await queryRunner.query( + `CREATE TABLE "temporary_product_review" ("deletedAt" datetime, "id" varchar PRIMARY KEY NOT NULL, "createdAt" datetime NOT NULL DEFAULT (datetime('now')), "updatedAt" datetime NOT NULL DEFAULT (datetime('now')), "isActive" boolean DEFAULT (1), "isArchived" boolean DEFAULT (0), "tenantId" varchar, "organizationId" varchar, "title" varchar, "description" text, "rating" integer NOT NULL, "upvotes" integer NOT NULL DEFAULT (0), "downvotes" integer NOT NULL DEFAULT (0), "status" varchar NOT NULL DEFAULT ('pending'), "editedAt" datetime, "productId" varchar NOT NULL, "userId" varchar NOT NULL, CONSTRAINT "FK_586e6b1273ba2732ec0ee41a80b" FOREIGN KEY ("tenantId") REFERENCES "tenant" ("id") ON DELETE CASCADE ON UPDATE NO ACTION, CONSTRAINT "FK_28ce717020729e36aa06cca5c54" FOREIGN KEY ("organizationId") REFERENCES "organization" ("id") ON DELETE CASCADE ON UPDATE CASCADE, CONSTRAINT "FK_06e7335708b5e7870f1eaa608d2" FOREIGN KEY ("productId") REFERENCES "product" ("id") ON DELETE CASCADE ON UPDATE NO ACTION, CONSTRAINT "FK_db21a1dc776b455ee83eb7ff88e" FOREIGN KEY ("userId") REFERENCES "user" ("id") ON DELETE CASCADE ON UPDATE NO ACTION)` + ); + await queryRunner.query( + `INSERT INTO "temporary_product_review"("deletedAt", "id", "createdAt", "updatedAt", "isActive", "isArchived", "tenantId", "organizationId", "title", "description", "rating", "upvotes", "downvotes", "status", "editedAt", "productId", "userId") SELECT "deletedAt", "id", "createdAt", "updatedAt", "isActive", "isArchived", "tenantId", "organizationId", "title", "description", "rating", "upvotes", "downvotes", "status", "editedAt", "productId", "userId" FROM "product_review"` + ); + await queryRunner.query(`DROP TABLE "product_review"`); + await queryRunner.query(`ALTER TABLE "temporary_product_review" RENAME TO "product_review"`); + await queryRunner.query(`CREATE INDEX "IDX_6248458c7e237cef4adac4761d" ON "product_review" ("isActive") `); + await queryRunner.query(`CREATE INDEX "IDX_9cb4931c7348b6c171f13b6216" ON "product_review" ("isArchived") `); + await queryRunner.query(`CREATE INDEX "IDX_586e6b1273ba2732ec0ee41a80" ON "product_review" ("tenantId") `); + await queryRunner.query( + `CREATE INDEX "IDX_28ce717020729e36aa06cca5c5" ON "product_review" ("organizationId") ` + ); + await queryRunner.query(`CREATE INDEX "IDX_28f06c5655d507668b8839b59a" ON "product_review" ("upvotes") `); + await queryRunner.query(`CREATE INDEX "IDX_f3591fd59cc32b585c3ba7d3ae" ON "product_review" ("downvotes") `); + await queryRunner.query(`CREATE INDEX "IDX_913f7739f1262fc8c70cbbafa3" ON "product_review" ("editedAt") `); + await queryRunner.query(`CREATE INDEX "IDX_06e7335708b5e7870f1eaa608d" ON "product_review" ("productId") `); + await queryRunner.query(`CREATE INDEX "IDX_db21a1dc776b455ee83eb7ff88" ON "product_review" ("userId") `); + } + + /** + * SqliteDB and BetterSQlite3DB Down Migration + * + * @param queryRunner + */ + public async sqliteDownQueryRunner(queryRunner: QueryRunner): Promise { + await queryRunner.query(`DROP INDEX "IDX_db21a1dc776b455ee83eb7ff88"`); + await queryRunner.query(`DROP INDEX "IDX_06e7335708b5e7870f1eaa608d"`); + await queryRunner.query(`DROP INDEX "IDX_913f7739f1262fc8c70cbbafa3"`); + await queryRunner.query(`DROP INDEX "IDX_f3591fd59cc32b585c3ba7d3ae"`); + await queryRunner.query(`DROP INDEX "IDX_28f06c5655d507668b8839b59a"`); + await queryRunner.query(`DROP INDEX "IDX_28ce717020729e36aa06cca5c5"`); + await queryRunner.query(`DROP INDEX "IDX_586e6b1273ba2732ec0ee41a80"`); + await queryRunner.query(`DROP INDEX "IDX_9cb4931c7348b6c171f13b6216"`); + await queryRunner.query(`DROP INDEX "IDX_6248458c7e237cef4adac4761d"`); + await queryRunner.query(`ALTER TABLE "product_review" RENAME TO "temporary_product_review"`); + await queryRunner.query( + `CREATE TABLE "product_review" ("deletedAt" datetime, "id" varchar PRIMARY KEY NOT NULL, "createdAt" datetime NOT NULL DEFAULT (datetime('now')), "updatedAt" datetime NOT NULL DEFAULT (datetime('now')), "isActive" boolean DEFAULT (1), "isArchived" boolean DEFAULT (0), "tenantId" varchar, "organizationId" varchar, "title" varchar, "description" text, "rating" integer NOT NULL, "upvotes" integer NOT NULL DEFAULT (0), "downvotes" integer NOT NULL DEFAULT (0), "status" varchar NOT NULL DEFAULT ('pending'), "editedAt" datetime, "productId" varchar NOT NULL, "userId" varchar NOT NULL)` + ); + await queryRunner.query( + `INSERT INTO "product_review"("deletedAt", "id", "createdAt", "updatedAt", "isActive", "isArchived", "tenantId", "organizationId", "title", "description", "rating", "upvotes", "downvotes", "status", "editedAt", "productId", "userId") SELECT "deletedAt", "id", "createdAt", "updatedAt", "isActive", "isArchived", "tenantId", "organizationId", "title", "description", "rating", "upvotes", "downvotes", "status", "editedAt", "productId", "userId" FROM "temporary_product_review"` + ); + await queryRunner.query(`DROP TABLE "temporary_product_review"`); + await queryRunner.query(`CREATE INDEX "IDX_db21a1dc776b455ee83eb7ff88" ON "product_review" ("userId") `); + await queryRunner.query(`CREATE INDEX "IDX_06e7335708b5e7870f1eaa608d" ON "product_review" ("productId") `); + await queryRunner.query(`CREATE INDEX "IDX_913f7739f1262fc8c70cbbafa3" ON "product_review" ("editedAt") `); + await queryRunner.query(`CREATE INDEX "IDX_f3591fd59cc32b585c3ba7d3ae" ON "product_review" ("downvotes") `); + await queryRunner.query(`CREATE INDEX "IDX_28f06c5655d507668b8839b59a" ON "product_review" ("upvotes") `); + await queryRunner.query( + `CREATE INDEX "IDX_28ce717020729e36aa06cca5c5" ON "product_review" ("organizationId") ` + ); + await queryRunner.query(`CREATE INDEX "IDX_586e6b1273ba2732ec0ee41a80" ON "product_review" ("tenantId") `); + await queryRunner.query(`CREATE INDEX "IDX_9cb4931c7348b6c171f13b6216" ON "product_review" ("isArchived") `); + await queryRunner.query(`CREATE INDEX "IDX_6248458c7e237cef4adac4761d" ON "product_review" ("isActive") `); + await queryRunner.query(`DROP INDEX "IDX_db21a1dc776b455ee83eb7ff88"`); + await queryRunner.query(`DROP INDEX "IDX_06e7335708b5e7870f1eaa608d"`); + await queryRunner.query(`DROP INDEX "IDX_913f7739f1262fc8c70cbbafa3"`); + await queryRunner.query(`DROP INDEX "IDX_f3591fd59cc32b585c3ba7d3ae"`); + await queryRunner.query(`DROP INDEX "IDX_28f06c5655d507668b8839b59a"`); + await queryRunner.query(`DROP INDEX "IDX_28ce717020729e36aa06cca5c5"`); + await queryRunner.query(`DROP INDEX "IDX_586e6b1273ba2732ec0ee41a80"`); + await queryRunner.query(`DROP INDEX "IDX_9cb4931c7348b6c171f13b6216"`); + await queryRunner.query(`DROP INDEX "IDX_6248458c7e237cef4adac4761d"`); + await queryRunner.query(`DROP TABLE "product_review"`); + } + + /** + * MySQL Up Migration + * + * @param queryRunner + */ + public async mysqlUpQueryRunner(queryRunner: QueryRunner): Promise { + await queryRunner.query( + `CREATE TABLE \`product_review\` (\`deletedAt\` datetime(6) NULL, \`id\` varchar(36) NOT NULL, \`createdAt\` datetime(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6), \`updatedAt\` datetime(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6) ON UPDATE CURRENT_TIMESTAMP(6), \`isActive\` tinyint NULL DEFAULT 1, \`isArchived\` tinyint NULL DEFAULT 0, \`tenantId\` varchar(255) NULL, \`organizationId\` varchar(255) NULL, \`title\` varchar(255) NULL, \`description\` text NULL, \`rating\` int NOT NULL, \`upvotes\` int NOT NULL DEFAULT '0', \`downvotes\` int NOT NULL DEFAULT '0', \`status\` varchar(255) NOT NULL DEFAULT 'pending', \`editedAt\` datetime NULL, \`productId\` varchar(255) NOT NULL, \`userId\` varchar(255) NOT NULL, INDEX \`IDX_6248458c7e237cef4adac4761d\` (\`isActive\`), INDEX \`IDX_9cb4931c7348b6c171f13b6216\` (\`isArchived\`), INDEX \`IDX_586e6b1273ba2732ec0ee41a80\` (\`tenantId\`), INDEX \`IDX_28ce717020729e36aa06cca5c5\` (\`organizationId\`), INDEX \`IDX_28f06c5655d507668b8839b59a\` (\`upvotes\`), INDEX \`IDX_f3591fd59cc32b585c3ba7d3ae\` (\`downvotes\`), INDEX \`IDX_913f7739f1262fc8c70cbbafa3\` (\`editedAt\`), INDEX \`IDX_06e7335708b5e7870f1eaa608d\` (\`productId\`), INDEX \`IDX_db21a1dc776b455ee83eb7ff88\` (\`userId\`), PRIMARY KEY (\`id\`)) ENGINE=InnoDB` + ); + await queryRunner.query( + `ALTER TABLE \`product_review\` ADD CONSTRAINT \`FK_586e6b1273ba2732ec0ee41a80b\` FOREIGN KEY (\`tenantId\`) REFERENCES \`tenant\`(\`id\`) ON DELETE CASCADE ON UPDATE NO ACTION` + ); + await queryRunner.query( + `ALTER TABLE \`product_review\` ADD CONSTRAINT \`FK_28ce717020729e36aa06cca5c54\` FOREIGN KEY (\`organizationId\`) REFERENCES \`organization\`(\`id\`) ON DELETE CASCADE ON UPDATE CASCADE` + ); + await queryRunner.query( + `ALTER TABLE \`product_review\` ADD CONSTRAINT \`FK_06e7335708b5e7870f1eaa608d2\` FOREIGN KEY (\`productId\`) REFERENCES \`product\`(\`id\`) ON DELETE CASCADE ON UPDATE NO ACTION` + ); + await queryRunner.query( + `ALTER TABLE \`product_review\` ADD CONSTRAINT \`FK_db21a1dc776b455ee83eb7ff88e\` FOREIGN KEY (\`userId\`) REFERENCES \`user\`(\`id\`) ON DELETE CASCADE ON UPDATE NO ACTION` + ); + } + + /** + * MySQL Down Migration + * + * @param queryRunner + */ + public async mysqlDownQueryRunner(queryRunner: QueryRunner): Promise { + await queryRunner.query(`ALTER TABLE \`product_review\` DROP FOREIGN KEY \`FK_db21a1dc776b455ee83eb7ff88e\``); + await queryRunner.query(`ALTER TABLE \`product_review\` DROP FOREIGN KEY \`FK_06e7335708b5e7870f1eaa608d2\``); + await queryRunner.query(`ALTER TABLE \`product_review\` DROP FOREIGN KEY \`FK_28ce717020729e36aa06cca5c54\``); + await queryRunner.query(`ALTER TABLE \`product_review\` DROP FOREIGN KEY \`FK_586e6b1273ba2732ec0ee41a80b\``); + await queryRunner.query(`DROP INDEX \`IDX_db21a1dc776b455ee83eb7ff88\` ON \`product_review\``); + await queryRunner.query(`DROP INDEX \`IDX_06e7335708b5e7870f1eaa608d\` ON \`product_review\``); + await queryRunner.query(`DROP INDEX \`IDX_913f7739f1262fc8c70cbbafa3\` ON \`product_review\``); + await queryRunner.query(`DROP INDEX \`IDX_f3591fd59cc32b585c3ba7d3ae\` ON \`product_review\``); + await queryRunner.query(`DROP INDEX \`IDX_28f06c5655d507668b8839b59a\` ON \`product_review\``); + await queryRunner.query(`DROP INDEX \`IDX_28ce717020729e36aa06cca5c5\` ON \`product_review\``); + await queryRunner.query(`DROP INDEX \`IDX_586e6b1273ba2732ec0ee41a80\` ON \`product_review\``); + await queryRunner.query(`DROP INDEX \`IDX_9cb4931c7348b6c171f13b6216\` ON \`product_review\``); + await queryRunner.query(`DROP INDEX \`IDX_6248458c7e237cef4adac4761d\` ON \`product_review\``); + await queryRunner.query(`DROP TABLE \`product_review\``); + } +} diff --git a/packages/plugins/product-reviews/package.json b/packages/plugins/product-reviews/package.json index 94974f08102..ccae281baae 100644 --- a/packages/plugins/product-reviews/package.json +++ b/packages/plugins/product-reviews/package.json @@ -49,18 +49,22 @@ "tslib": "^2.6.2" }, "dependencies": { + "@gauzy/contracts": "^0.1.0", "@gauzy/core": "^0.1.0", "@gauzy/plugin": "^0.1.0", "@nestjs/common": "^10.3.7", + "@nestjs/swagger": "^7.3.0", "@nestjs/typeorm": "^10.0.2", "apollo-server-core": "^3.10.1", "chalk": "4.1.2", + "class-validator": "^0.14.0", "typeorm": "^0.3.20" }, "devDependencies": { "@types/jest": "^29.4.4", "@types/node": "^20.14.9", "rimraf": "^3.0.2", + "tslint": "^6.1.3", "typescript": "5.1.6" }, "engines": { diff --git a/packages/plugins/product-reviews/src/lib/entities/product-review.entity.ts b/packages/plugins/product-reviews/src/lib/entities/product-review.entity.ts index b0d469068b0..f5a88d7b56f 100644 --- a/packages/plugins/product-reviews/src/lib/entities/product-review.entity.ts +++ b/packages/plugins/product-reviews/src/lib/entities/product-review.entity.ts @@ -1,11 +1,109 @@ -import { MultiORMEntity, MultiORMColumn, TenantOrganizationBaseEntity } from '@gauzy/core'; +import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger'; +import { JoinColumn, RelationId } from 'typeorm'; +import { IsEnum, IsNotEmpty, IsNumber, IsOptional, IsUUID, Max, Min } from 'class-validator'; +import { ID, IProduct, IUser } from '@gauzy/contracts'; +import { + MultiORMEntity, + MultiORMColumn, + TenantOrganizationBaseEntity, + Product, + MultiORMManyToOne, + ColumnIndex, + User, + VirtualMultiOrmColumn +} from '@gauzy/core'; +import { IProductReview, ProductReviewStatus, ProductReviewStatusEnum } from '../product-review.types'; import { MikroOrmProductReviewRepository } from './repository/mikro-orm-product-review.repository'; @MultiORMEntity('product_review', { mikroOrmRepository: () => MikroOrmProductReviewRepository }) -export class ProductReview extends TenantOrganizationBaseEntity { - @MultiORMColumn('text') - body: string; +export class ProductReview extends TenantOrganizationBaseEntity implements IProductReview { + // Title of the review + @ApiPropertyOptional({ type: () => String }) + @IsOptional() + @MultiORMColumn({ nullable: true }) + title: string; + // Description of the review + @ApiPropertyOptional({ type: () => String }) + @IsOptional() + @MultiORMColumn('text', { nullable: true }) + description: string; + + // Rating of the review + @ApiProperty({ type: () => Number, minimum: 0, maximum: 10 }) + @IsNotEmpty() + @IsNumber() + @Min(0) + @Max(10) @MultiORMColumn() rating: number; + + // Up votes (Positive votes) + @ApiProperty({ type: () => Number }) + @IsNumber() + @ColumnIndex() + @MultiORMColumn({ type: 'int', default: 0 }) + upvotes: number; + + // Down votes (Negative votes) + @ApiProperty({ type: () => Number }) + @IsNumber() + @ColumnIndex() + @MultiORMColumn({ type: 'int', default: 0 }) + downvotes: number; + + // Status of the review + @ApiProperty({ type: () => String, enum: ProductReviewStatusEnum }) + @IsEnum(ProductReviewStatusEnum) + @MultiORMColumn({ type: 'varchar', default: ProductReviewStatusEnum.PENDING }) + status: ProductReviewStatus; + + // Date when the record was edited + @MultiORMColumn({ type: 'timestamp' }) + @ColumnIndex() + @MultiORMColumn({ nullable: true }) + editedAt: Date; + + // Indicates whether the ProductReview has been edited. + @VirtualMultiOrmColumn() + isEdited: boolean; + + /* + |-------------------------------------------------------------------------- + | @ManyToOne + |-------------------------------------------------------------------------- + */ + /** + * Product that is being reviewed + */ + @MultiORMManyToOne(() => Product, { + /** Database cascade action on delete. */ + onDelete: 'CASCADE' + }) + @JoinColumn() + product?: IProduct; + + @ApiProperty({ type: () => String }) + @IsUUID() + @RelationId((it: ProductReview) => it.product) + @ColumnIndex() + @MultiORMColumn({ relationId: true }) + productId?: ID; + + /** + * User`s who have reviewed the product + */ + @MultiORMManyToOne(() => User, { + /** Database cascade action on delete. */ + onDelete: 'CASCADE' + }) + @JoinColumn() + user?: IUser; + + @ApiProperty({ type: () => String }) + @IsUUID() + @RelationId((it: ProductReview) => it.user) + @ColumnIndex() + @MultiORMColumn({ relationId: true }) + userId?: ID; } diff --git a/packages/plugins/product-reviews/src/lib/product-review.types.ts b/packages/plugins/product-reviews/src/lib/product-review.types.ts new file mode 100644 index 00000000000..bf6cbeb4c02 --- /dev/null +++ b/packages/plugins/product-reviews/src/lib/product-review.types.ts @@ -0,0 +1,23 @@ +import { IBasePerTenantAndOrganizationEntityModel, ID, IProduct, IUser } from '@gauzy/contracts'; + +export type ProductReviewStatus = 'approved' | 'pending' | 'rejected'; + +// Enum for product review status +export enum ProductReviewStatusEnum { + APPROVED = 'approved', + PENDING = 'pending', + REJECTED = 'rejected' +} + +export interface IProductReview extends IBasePerTenantAndOrganizationEntityModel { + title: string; + description: string; + rating: number; + upvotes: number; + downvotes: number; + status: ProductReviewStatus; + product?: IProduct; + productId?: ID; + user?: IUser; + userId?: ID; +} From d3590a38428e200472dfaa43267aa76d61804477 Mon Sep 17 00:00:00 2001 From: Ruslan Konviser Date: Sat, 13 Jul 2024 11:00:40 +0200 Subject: [PATCH 2/2] fix: add deps --- packages/desktop-libs/package.json | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/desktop-libs/package.json b/packages/desktop-libs/package.json index 6b2c6106c4b..d54473ca2e0 100644 --- a/packages/desktop-libs/package.json +++ b/packages/desktop-libs/package.json @@ -33,6 +33,7 @@ "better-sqlite3": "^9.4.3", "electron-store": "^8.1.0", "electron-util": "^0.17.2", + "electron-log": "^4.4.8", "embedded-queue": "^0.0.11", "express": "^4.18.2", "form-data": "^3.0.0",