initial describe catalog database
This commit is contained in:
parent
b6460f1cda
commit
42d4c4e40c
@ -1,10 +1,24 @@
|
||||
import { Module } from '@nestjs/common';
|
||||
import { Module, OnModuleInit } from '@nestjs/common';
|
||||
import { CatalogController } from './catalog.controller';
|
||||
import { CatalogService } from './catalog.service';
|
||||
import { ClientsModule } from '@nestjs/microservices';
|
||||
import { makeKnex, makeTypeOrm, natsClient } from '@freeblox/shared';
|
||||
import { ConfigModule, ConfigService } from '@nestjs/config';
|
||||
import { TypeOrmModule } from '@nestjs/typeorm';
|
||||
import knex from 'knex';
|
||||
import { ContentEntity } from './database/entities/content.entity';
|
||||
import { ContentRevisionEntity } from './database/entities/content-revision.entity';
|
||||
import {
|
||||
ContentModerationEntity,
|
||||
ContentModerationBanEntity,
|
||||
} from './database/entities/content-moderation.entity';
|
||||
import { ContentAssetEntity } from './database/entities/content-asset.entity';
|
||||
import { ContentPriceEntity } from './database/entities/content-price.entity';
|
||||
import { ContentOwnershipEntity } from './database/entities/content-ownership.entity';
|
||||
import { ContentTradeEntity } from './database/entities/content-trade.entity';
|
||||
import { ContentFavoriteEntity } from './database/entities/content-favorite.entity';
|
||||
import { ContentVoteEntity } from './database/entities/content-vote.entity';
|
||||
import { ContentReportEntity } from './database/entities/content-report.entity';
|
||||
|
||||
@Module({
|
||||
imports: [
|
||||
@ -17,6 +31,19 @@ import { TypeOrmModule } from '@nestjs/typeorm';
|
||||
inject: [ConfigService],
|
||||
useFactory: (config: ConfigService) => config.get('typeorm'),
|
||||
}),
|
||||
TypeOrmModule.forFeature([
|
||||
ContentEntity,
|
||||
ContentRevisionEntity,
|
||||
ContentModerationEntity,
|
||||
ContentModerationBanEntity,
|
||||
ContentAssetEntity,
|
||||
ContentPriceEntity,
|
||||
ContentOwnershipEntity,
|
||||
ContentTradeEntity,
|
||||
ContentFavoriteEntity,
|
||||
ContentVoteEntity,
|
||||
ContentReportEntity,
|
||||
]),
|
||||
ClientsModule.register([
|
||||
natsClient('catalog'),
|
||||
natsClient('auth'),
|
||||
@ -26,4 +53,12 @@ import { TypeOrmModule } from '@nestjs/typeorm';
|
||||
controllers: [CatalogController],
|
||||
providers: [CatalogService],
|
||||
})
|
||||
export class CatalogModule {}
|
||||
export class CatalogModule implements OnModuleInit {
|
||||
constructor(private readonly config: ConfigService) {}
|
||||
|
||||
async onModuleInit() {
|
||||
const knexInstance = knex(this.config.get('knex'));
|
||||
await knexInstance.migrate.latest();
|
||||
// await knexInstance.seed.run();
|
||||
}
|
||||
}
|
||||
|
44
apps/catalog/src/database/entities/content-asset.entity.ts
Normal file
44
apps/catalog/src/database/entities/content-asset.entity.ts
Normal file
@ -0,0 +1,44 @@
|
||||
import { Expose } from 'class-transformer';
|
||||
import {
|
||||
Column,
|
||||
Entity,
|
||||
JoinColumn,
|
||||
ManyToOne,
|
||||
PrimaryGeneratedColumn,
|
||||
} from 'typeorm';
|
||||
import { ContentAssetType } from '../../enums/content-asset-type.enum';
|
||||
import { ContentRevisionEntity } from './content-revision.entity';
|
||||
import { ContentEntity } from './content.entity';
|
||||
|
||||
@Entity('content_asset')
|
||||
@Expose()
|
||||
export class ContentAssetEntity {
|
||||
@PrimaryGeneratedColumn()
|
||||
id: number;
|
||||
|
||||
@Column({ name: 'content_id' })
|
||||
contentId: number;
|
||||
|
||||
@Column({ name: 'revision_id' })
|
||||
revisionId: number;
|
||||
|
||||
@Column({ name: 'asset_id', type: 'uuid' })
|
||||
assetId: string;
|
||||
|
||||
@Column({ type: 'string', enum: ContentAssetType })
|
||||
type: ContentAssetType;
|
||||
|
||||
@Column({ name: 'type_name', nullable: true })
|
||||
typeName?: string;
|
||||
|
||||
@Column()
|
||||
index: number;
|
||||
|
||||
@ManyToOne(() => ContentEntity, { onDelete: 'CASCADE' })
|
||||
@JoinColumn({ name: 'content_id' })
|
||||
content: ContentEntity;
|
||||
|
||||
@ManyToOne(() => ContentRevisionEntity, { onDelete: 'CASCADE' })
|
||||
@JoinColumn({ name: 'revision_id' })
|
||||
revision: ContentRevisionEntity;
|
||||
}
|
@ -0,0 +1,31 @@
|
||||
import { Exclude, Expose } from 'class-transformer';
|
||||
import {
|
||||
Column,
|
||||
Entity,
|
||||
Index,
|
||||
JoinColumn,
|
||||
ManyToOne,
|
||||
PrimaryGeneratedColumn,
|
||||
} from 'typeorm';
|
||||
import { ContentEntity } from './content.entity';
|
||||
import { MetaEntity } from '@freeblox/shared';
|
||||
|
||||
@Entity('content_favorite')
|
||||
@Expose()
|
||||
export class ContentFavoriteEntity extends MetaEntity {
|
||||
@PrimaryGeneratedColumn()
|
||||
id: number;
|
||||
|
||||
@Column({ name: 'content_id' })
|
||||
@Exclude()
|
||||
contentId: number;
|
||||
|
||||
@Column({ name: 'user_id', type: 'uuid', nullable: true })
|
||||
@Index()
|
||||
@Exclude()
|
||||
userId: string;
|
||||
|
||||
@ManyToOne(() => ContentEntity, { onDelete: 'CASCADE' })
|
||||
@JoinColumn({ name: 'content_id' })
|
||||
content: ContentEntity;
|
||||
}
|
107
apps/catalog/src/database/entities/content-moderation.entity.ts
Normal file
107
apps/catalog/src/database/entities/content-moderation.entity.ts
Normal file
@ -0,0 +1,107 @@
|
||||
import { MetaEntity } from '@freeblox/shared';
|
||||
import { Exclude, Expose, Type } from 'class-transformer';
|
||||
import {
|
||||
Column,
|
||||
CreateDateColumn,
|
||||
Entity,
|
||||
JoinColumn,
|
||||
ManyToOne,
|
||||
OneToMany,
|
||||
PrimaryGeneratedColumn,
|
||||
} from 'typeorm';
|
||||
import { ContentEntity } from './content.entity';
|
||||
import { ContentRevisionEntity } from './content-revision.entity';
|
||||
import { ModeratorAction } from '../../enums/moderation-action.enum';
|
||||
import { RejectionReason } from '../../enums/rejection-reason.enum';
|
||||
import {
|
||||
IsBoolean,
|
||||
IsEnum,
|
||||
IsNumber,
|
||||
IsOptional,
|
||||
IsString,
|
||||
} from 'class-validator';
|
||||
import { BanEntity } from 'apps/auth/src/database/entities/ban.entity';
|
||||
|
||||
@Entity('content_moderation')
|
||||
@Expose()
|
||||
export class ContentModerationEntity extends MetaEntity {
|
||||
@PrimaryGeneratedColumn()
|
||||
id: number;
|
||||
|
||||
@Column({ name: 'content_id' })
|
||||
@IsNumber()
|
||||
contentId: number;
|
||||
|
||||
@Column({ name: 'revision_id' })
|
||||
@IsNumber()
|
||||
revisionId: number;
|
||||
|
||||
@Column({ name: 'user_id', type: 'uuid', nullable: true })
|
||||
@Exclude()
|
||||
userId: string;
|
||||
|
||||
@Column({
|
||||
type: 'enum',
|
||||
enum: ModeratorAction,
|
||||
default: ModeratorAction.PENDING,
|
||||
})
|
||||
@IsEnum(ModeratorAction)
|
||||
action: ModeratorAction;
|
||||
|
||||
@Column({
|
||||
type: 'enum',
|
||||
enum: RejectionReason,
|
||||
nullable: true,
|
||||
name: 'rejection_reason',
|
||||
})
|
||||
@IsEnum(RejectionReason)
|
||||
rejectionReason?: RejectionReason;
|
||||
|
||||
@Column({ nullable: true })
|
||||
@IsString()
|
||||
@IsOptional()
|
||||
description?: string;
|
||||
|
||||
@Column({ default: false })
|
||||
@IsBoolean()
|
||||
@IsOptional()
|
||||
penalty: boolean;
|
||||
|
||||
@Column({ default: false, name: 'asset_delete' })
|
||||
@IsBoolean()
|
||||
@IsOptional()
|
||||
assetDelete: boolean;
|
||||
|
||||
@CreateDateColumn({ name: 'created_at' })
|
||||
@Expose()
|
||||
createdAt: Date;
|
||||
|
||||
@CreateDateColumn({ name: 'decided_at' })
|
||||
decidedAt: Date;
|
||||
|
||||
@ManyToOne(() => ContentEntity, { onDelete: 'CASCADE' })
|
||||
@JoinColumn({ name: 'content_id' })
|
||||
content: ContentEntity;
|
||||
|
||||
@ManyToOne(() => ContentRevisionEntity, { onDelete: 'CASCADE' })
|
||||
@JoinColumn({ name: 'revision_id' })
|
||||
revision: ContentRevisionEntity;
|
||||
|
||||
@OneToMany(() => ContentModerationBanEntity, (ban) => ban.moderation)
|
||||
@Type(() => ContentModerationBanEntity)
|
||||
bans?: ContentModerationBanEntity[];
|
||||
}
|
||||
|
||||
@Entity('content_moderation_ban')
|
||||
export class ContentModerationBanEntity {
|
||||
@Column({ nullable: true, name: 'ban_id' })
|
||||
banId: number;
|
||||
|
||||
@ManyToOne(() => ContentModerationEntity, (mod) => mod.bans)
|
||||
@JoinColumn({ name: 'content_moderation_id' })
|
||||
@Expose()
|
||||
moderation: ContentModerationEntity;
|
||||
|
||||
@Expose()
|
||||
ban?: BanEntity;
|
||||
}
|
@ -0,0 +1,82 @@
|
||||
import { Exclude, Expose } from 'class-transformer';
|
||||
import {
|
||||
Column,
|
||||
CreateDateColumn,
|
||||
Entity,
|
||||
Index,
|
||||
JoinColumn,
|
||||
ManyToOne,
|
||||
PrimaryGeneratedColumn,
|
||||
} from 'typeorm';
|
||||
import { ContentEntity } from './content.entity';
|
||||
import { Currency } from '../../enums/currency.enum';
|
||||
import { UserMetaEntity } from '@freeblox/shared';
|
||||
|
||||
@Entity('content_ownership')
|
||||
@Expose()
|
||||
export class ContentOwnershipEntity extends UserMetaEntity {
|
||||
@PrimaryGeneratedColumn()
|
||||
id: number;
|
||||
|
||||
@Column({ name: 'content_id' })
|
||||
contentId: number;
|
||||
|
||||
@Column({ name: 'user_id', type: 'uuid', nullable: true })
|
||||
@Exclude()
|
||||
userId: string;
|
||||
|
||||
@Column({ name: 'previous_ownership_id', nullable: true })
|
||||
@Exclude()
|
||||
previousOwnershipId: string;
|
||||
|
||||
@Column({ name: 'purchase_price', nullable: true })
|
||||
@Index()
|
||||
purchasePrice: number;
|
||||
|
||||
@Column({
|
||||
type: 'enum',
|
||||
enum: Currency,
|
||||
name: 'purchase_currency',
|
||||
nullable: true,
|
||||
})
|
||||
@Index()
|
||||
purchaseCurrency: Currency;
|
||||
|
||||
@Column({ nullable: true })
|
||||
@Index()
|
||||
serial: number;
|
||||
|
||||
@ManyToOne(() => ContentEntity, { onDelete: 'CASCADE' })
|
||||
@JoinColumn({ name: 'content_id' })
|
||||
@Exclude()
|
||||
content: ContentEntity;
|
||||
|
||||
@ManyToOne(() => ContentOwnershipEntity, { onDelete: 'SET NULL' })
|
||||
@JoinColumn({ name: 'previous_ownership_id' })
|
||||
@Exclude()
|
||||
previous?: ContentOwnershipEntity;
|
||||
|
||||
@CreateDateColumn({ name: 'created_at' })
|
||||
@Expose()
|
||||
createdAt: Date;
|
||||
|
||||
@Column({ type: Date, name: 'ended_at', nullable: true })
|
||||
endedAt: Date;
|
||||
|
||||
@Column({ type: Date, name: 'expires_at', nullable: true })
|
||||
expiresAt: Date;
|
||||
|
||||
/**
|
||||
* is ownership expired
|
||||
*/
|
||||
get expired() {
|
||||
return this.expiresAt.getTime() < Date.now();
|
||||
}
|
||||
|
||||
/**
|
||||
* is ownership invalid (Expired or ended)
|
||||
*/
|
||||
get invalid() {
|
||||
return !!this.endedAt || this.expired;
|
||||
}
|
||||
}
|
35
apps/catalog/src/database/entities/content-price.entity.ts
Normal file
35
apps/catalog/src/database/entities/content-price.entity.ts
Normal file
@ -0,0 +1,35 @@
|
||||
import { Exclude, Expose } from 'class-transformer';
|
||||
import {
|
||||
Column,
|
||||
Entity,
|
||||
Index,
|
||||
JoinColumn,
|
||||
ManyToOne,
|
||||
PrimaryGeneratedColumn,
|
||||
} from 'typeorm';
|
||||
import { ContentEntity } from './content.entity';
|
||||
import { Currency } from '../../enums/currency.enum';
|
||||
import { UserMetaEntity } from '@freeblox/shared';
|
||||
|
||||
@Entity('content_price')
|
||||
@Expose()
|
||||
export class ContentPriceEntity extends UserMetaEntity {
|
||||
@PrimaryGeneratedColumn()
|
||||
id: number;
|
||||
|
||||
@Column({ name: 'content_id' })
|
||||
contentId: number;
|
||||
|
||||
@Column()
|
||||
@Index()
|
||||
price: number;
|
||||
|
||||
@Column({ type: 'enum', enum: Currency })
|
||||
@Index()
|
||||
currency: Currency;
|
||||
|
||||
@ManyToOne(() => ContentEntity, { onDelete: 'CASCADE' })
|
||||
@JoinColumn({ name: 'content_id' })
|
||||
@Exclude()
|
||||
content: ContentEntity;
|
||||
}
|
82
apps/catalog/src/database/entities/content-report.entity.ts
Normal file
82
apps/catalog/src/database/entities/content-report.entity.ts
Normal file
@ -0,0 +1,82 @@
|
||||
import { MetaEntity } from '@freeblox/shared';
|
||||
import { Exclude, Expose } from 'class-transformer';
|
||||
import {
|
||||
Column,
|
||||
CreateDateColumn,
|
||||
Entity,
|
||||
JoinColumn,
|
||||
JoinTable,
|
||||
ManyToMany,
|
||||
ManyToOne,
|
||||
PrimaryGeneratedColumn,
|
||||
} from 'typeorm';
|
||||
import { ContentEntity } from './content.entity';
|
||||
import { ContentRevisionEntity } from './content-revision.entity';
|
||||
import { IsNumber, IsOptional, IsString } from 'class-validator';
|
||||
import { ReportStatus } from '../../enums/report-status.enum';
|
||||
import { ContentModerationEntity } from './content-moderation.entity';
|
||||
|
||||
@Entity('content_report')
|
||||
@Expose()
|
||||
export class ContentReportEntity extends MetaEntity {
|
||||
@PrimaryGeneratedColumn()
|
||||
id: number;
|
||||
|
||||
@Column({ name: 'content_id' })
|
||||
@IsNumber()
|
||||
contentId: number;
|
||||
|
||||
@Column({ name: 'revision_id' })
|
||||
revisionId: number;
|
||||
|
||||
@Column({ name: 'user_id', type: 'uuid' })
|
||||
@Exclude()
|
||||
userId: string;
|
||||
|
||||
@Column({ name: 'moderator_id', type: 'uuid', nullable: true })
|
||||
@Exclude()
|
||||
moderatorId?: string;
|
||||
|
||||
@Column()
|
||||
@IsString()
|
||||
reason: string;
|
||||
|
||||
@Column()
|
||||
@IsString()
|
||||
description: string;
|
||||
|
||||
@Column({ nullable: true })
|
||||
@IsString()
|
||||
@IsOptional()
|
||||
notes?: string;
|
||||
|
||||
@Column({ type: 'enum', enum: ReportStatus })
|
||||
status: ReportStatus;
|
||||
|
||||
@CreateDateColumn({ name: 'created_at' })
|
||||
@Expose()
|
||||
createdAt: Date;
|
||||
|
||||
@CreateDateColumn({ name: 'resolved_at' })
|
||||
resolvedAt: Date;
|
||||
|
||||
@ManyToOne(() => ContentEntity, { onDelete: 'CASCADE' })
|
||||
@JoinColumn({ name: 'content_id' })
|
||||
content: ContentEntity;
|
||||
|
||||
@ManyToOne(() => ContentRevisionEntity, { onDelete: 'CASCADE' })
|
||||
@JoinColumn({ name: 'revision_id' })
|
||||
revision?: ContentRevisionEntity;
|
||||
|
||||
@ManyToMany(() => ContentModerationEntity)
|
||||
@JoinTable({
|
||||
name: 'content_report_action',
|
||||
joinColumn: {
|
||||
name: 'content_report_id',
|
||||
},
|
||||
inverseJoinColumn: {
|
||||
name: 'content_moderation_id',
|
||||
},
|
||||
})
|
||||
actions?: ContentModerationEntity[];
|
||||
}
|
@ -0,0 +1,35 @@
|
||||
import { UserMetaEntity } from '@freeblox/shared';
|
||||
import { Exclude, Expose } from 'class-transformer';
|
||||
import {
|
||||
Column,
|
||||
CreateDateColumn,
|
||||
DeleteDateColumn,
|
||||
Entity,
|
||||
JoinColumn,
|
||||
ManyToOne,
|
||||
PrimaryGeneratedColumn,
|
||||
} from 'typeorm';
|
||||
import { ContentEntity } from './content.entity';
|
||||
|
||||
@Entity('content_revision')
|
||||
@Exclude()
|
||||
export class ContentRevisionEntity extends UserMetaEntity {
|
||||
@PrimaryGeneratedColumn()
|
||||
@Expose()
|
||||
id: number;
|
||||
|
||||
@Column({ name: 'content_id' })
|
||||
contentId: number;
|
||||
|
||||
@CreateDateColumn({ name: 'created_at' })
|
||||
@Expose()
|
||||
createdAt: Date;
|
||||
|
||||
@DeleteDateColumn({ name: 'deleted_at' })
|
||||
@Expose()
|
||||
deletedAt?: Date;
|
||||
|
||||
@ManyToOne(() => ContentEntity, { onDelete: 'CASCADE' })
|
||||
@JoinColumn({ name: 'content_id' })
|
||||
content: ContentEntity;
|
||||
}
|
58
apps/catalog/src/database/entities/content-trade.entity.ts
Normal file
58
apps/catalog/src/database/entities/content-trade.entity.ts
Normal file
@ -0,0 +1,58 @@
|
||||
import { Exclude, Expose } from 'class-transformer';
|
||||
import {
|
||||
Column,
|
||||
Entity,
|
||||
Index,
|
||||
JoinTable,
|
||||
ManyToMany,
|
||||
PrimaryGeneratedColumn,
|
||||
} from 'typeorm';
|
||||
import { MetaEntity } from '@freeblox/shared';
|
||||
import { TradeStatus } from '../../enums/trade-status.enum';
|
||||
import { ContentOwnershipEntity } from './content-ownership.entity';
|
||||
|
||||
@Entity('content_trade')
|
||||
@Expose()
|
||||
export class ContentTradeEntity extends MetaEntity {
|
||||
@PrimaryGeneratedColumn()
|
||||
id: number;
|
||||
|
||||
@Column({ name: 'user_id', type: 'uuid' })
|
||||
@Exclude()
|
||||
userId: string;
|
||||
|
||||
@Column({ name: 'recipient_id', type: 'uuid' })
|
||||
@Exclude()
|
||||
recipientId: string;
|
||||
|
||||
@Column({ type: 'enum', enum: TradeStatus })
|
||||
@Index()
|
||||
status: TradeStatus;
|
||||
|
||||
@Column()
|
||||
description: string;
|
||||
|
||||
@ManyToMany(() => ContentOwnershipEntity)
|
||||
@JoinTable({
|
||||
name: 'content_trade_user_content',
|
||||
joinColumn: {
|
||||
name: 'content_trade_id',
|
||||
},
|
||||
inverseJoinColumn: {
|
||||
name: 'content_ownership_id',
|
||||
},
|
||||
})
|
||||
userItems: ContentOwnershipEntity[];
|
||||
|
||||
@ManyToMany(() => ContentOwnershipEntity)
|
||||
@JoinTable({
|
||||
name: 'content_trade_recipient_content',
|
||||
joinColumn: {
|
||||
name: 'content_trade_id',
|
||||
},
|
||||
inverseJoinColumn: {
|
||||
name: 'content_ownership_id',
|
||||
},
|
||||
})
|
||||
recipientItems: ContentOwnershipEntity[];
|
||||
}
|
36
apps/catalog/src/database/entities/content-vote.entity.ts
Normal file
36
apps/catalog/src/database/entities/content-vote.entity.ts
Normal file
@ -0,0 +1,36 @@
|
||||
import { Exclude, Expose } from 'class-transformer';
|
||||
import {
|
||||
Column,
|
||||
Entity,
|
||||
Index,
|
||||
JoinColumn,
|
||||
ManyToOne,
|
||||
PrimaryGeneratedColumn,
|
||||
} from 'typeorm';
|
||||
import { ContentEntity } from './content.entity';
|
||||
import { MetaEntity } from '@freeblox/shared';
|
||||
import { Vote } from '../../enums/vote.enum';
|
||||
|
||||
@Entity('content_vote')
|
||||
@Expose()
|
||||
export class ContentVoteEntity extends MetaEntity {
|
||||
@PrimaryGeneratedColumn()
|
||||
id: number;
|
||||
|
||||
@Column({ name: 'content_id' })
|
||||
@Exclude()
|
||||
contentId: number;
|
||||
|
||||
@Column({ name: 'user_id', type: 'uuid', nullable: true })
|
||||
@Index()
|
||||
@Exclude()
|
||||
userId: string;
|
||||
|
||||
@Column({ type: 'enum', enum: Vote })
|
||||
vote: Vote;
|
||||
|
||||
@ManyToOne(() => ContentEntity, { onDelete: 'CASCADE' })
|
||||
@JoinColumn({ name: 'content_id' })
|
||||
@Exclude()
|
||||
content: ContentEntity;
|
||||
}
|
109
apps/catalog/src/database/entities/content.entity.ts
Normal file
109
apps/catalog/src/database/entities/content.entity.ts
Normal file
@ -0,0 +1,109 @@
|
||||
import { UserMetaEntity } from '@freeblox/shared';
|
||||
import {
|
||||
Column,
|
||||
CreateDateColumn,
|
||||
DeleteDateColumn,
|
||||
Entity,
|
||||
Index,
|
||||
JoinColumn,
|
||||
ManyToOne,
|
||||
PrimaryGeneratedColumn,
|
||||
} from 'typeorm';
|
||||
import { Privacy } from '../../enums/privacy.enum';
|
||||
import { ContentType } from '../../enums/content-type.enum';
|
||||
import { Exclude, Expose } from 'class-transformer';
|
||||
import { UserEntity } from 'apps/auth/src/database/entities/user.entity';
|
||||
import {
|
||||
IsBoolean,
|
||||
IsEnum,
|
||||
IsNotEmpty,
|
||||
IsNumber,
|
||||
IsOptional,
|
||||
IsString,
|
||||
MaxLength,
|
||||
} from 'class-validator';
|
||||
|
||||
@Entity('content')
|
||||
@Expose()
|
||||
export class ContentEntity extends UserMetaEntity {
|
||||
@PrimaryGeneratedColumn()
|
||||
id: number;
|
||||
|
||||
@Column({ length: 255 })
|
||||
@Index()
|
||||
@IsString()
|
||||
@IsNotEmpty()
|
||||
@MaxLength(255)
|
||||
name: string;
|
||||
|
||||
@Column()
|
||||
@IsString()
|
||||
@IsNotEmpty()
|
||||
@MaxLength(5000)
|
||||
description: string;
|
||||
|
||||
@Column({ type: 'uuid', name: 'user_id' })
|
||||
userId: string;
|
||||
|
||||
@Column({ name: 'parent_id', nullable: true })
|
||||
parentId: number;
|
||||
|
||||
@Column({ default: false })
|
||||
@IsBoolean()
|
||||
@IsOptional()
|
||||
restricted: boolean;
|
||||
|
||||
@Column({ default: false })
|
||||
@IsBoolean()
|
||||
@IsOptional()
|
||||
onsale: boolean;
|
||||
|
||||
@Column({ default: false })
|
||||
@IsBoolean()
|
||||
@IsOptional()
|
||||
published: boolean;
|
||||
|
||||
@Column({ default: true, name: 'comments_enabled' })
|
||||
@IsBoolean()
|
||||
@IsOptional()
|
||||
commentsEnabled: boolean;
|
||||
|
||||
@Column({ default: false, name: 'open_source' })
|
||||
@IsBoolean()
|
||||
@IsOptional()
|
||||
openSource: boolean;
|
||||
|
||||
@Column({ type: 'enum', enum: Privacy, default: Privacy.PUBLIC })
|
||||
@IsEnum(Privacy)
|
||||
privacy: Privacy;
|
||||
|
||||
@Column({ type: 'string', enum: ContentType })
|
||||
@IsEnum(ContentType)
|
||||
@Index()
|
||||
type: ContentType;
|
||||
|
||||
@Column({ unsigned: true, nullable: true })
|
||||
@IsNumber()
|
||||
@IsOptional()
|
||||
stock: number;
|
||||
|
||||
@Column({ nullable: true })
|
||||
@IsString()
|
||||
@IsOptional()
|
||||
license: string;
|
||||
|
||||
@ManyToOne(() => ContentEntity)
|
||||
@JoinColumn({ name: 'parent_id' })
|
||||
@Exclude()
|
||||
parent?: ContentEntity;
|
||||
|
||||
@CreateDateColumn({ name: 'created_at' })
|
||||
@Expose()
|
||||
createdAt: Date;
|
||||
|
||||
@DeleteDateColumn({ name: 'deleted_at' })
|
||||
@Exclude()
|
||||
deletedAt?: Date;
|
||||
|
||||
user?: UserEntity;
|
||||
}
|
@ -0,0 +1,41 @@
|
||||
import { Knex } from 'knex';
|
||||
|
||||
export async function up(knex: Knex): Promise<void> {
|
||||
return knex.schema.createTable('content', (table) => {
|
||||
table.increments('id').primary();
|
||||
|
||||
table.string('name', 255).notNullable().index();
|
||||
table.text('description').notNullable();
|
||||
|
||||
table.uuid('user_id').nullable();
|
||||
table.integer('parent_id').unsigned().nullable();
|
||||
|
||||
table.boolean('restricted').defaultTo(false);
|
||||
table.boolean('onsale').defaultTo(false).index();
|
||||
table.boolean('published').defaultTo(false);
|
||||
table.boolean('comments_enabled').defaultTo(true);
|
||||
table.boolean('open_source').defaultTo(false);
|
||||
|
||||
table
|
||||
.enum('privacy', ['public', 'friends', 'unlisted', 'private'])
|
||||
.notNullable()
|
||||
.defaultTo('public');
|
||||
|
||||
table.string('type').notNullable().index().defaultTo('content');
|
||||
|
||||
table.integer('stock').unsigned().nullable();
|
||||
table.text('license').nullable();
|
||||
|
||||
table.uuid('created_by').nullable();
|
||||
table.uuid('updated_by').nullable();
|
||||
|
||||
table.timestamps(true, true);
|
||||
table.timestamp('deleted_at');
|
||||
|
||||
table.foreign('parent_id').references('content.id').onDelete('CASCADE');
|
||||
});
|
||||
}
|
||||
|
||||
export async function down(knex: Knex): Promise<void> {
|
||||
return knex.schema.dropTable('content');
|
||||
}
|
@ -0,0 +1,21 @@
|
||||
import { Knex } from 'knex';
|
||||
|
||||
export async function up(knex: Knex): Promise<void> {
|
||||
return knex.schema.createTable('content_revision', (table) => {
|
||||
table.increments('id').primary();
|
||||
|
||||
table.integer('content_id').unsigned().notNullable();
|
||||
|
||||
table.uuid('created_by').nullable();
|
||||
table.uuid('updated_by').nullable();
|
||||
|
||||
table.timestamps(true, true);
|
||||
table.timestamp('deleted_at');
|
||||
|
||||
table.foreign('content_id').references('content.id').onDelete('CASCADE');
|
||||
});
|
||||
}
|
||||
|
||||
export async function down(knex: Knex): Promise<void> {
|
||||
return knex.schema.dropTable('content_revision');
|
||||
}
|
@ -0,0 +1,54 @@
|
||||
import { Knex } from 'knex';
|
||||
|
||||
export async function up(knex: Knex): Promise<void> {
|
||||
await Promise.all([
|
||||
knex.schema.createTable('content_moderation', (table) => {
|
||||
table.increments('id').primary();
|
||||
|
||||
table.integer('content_id').unsigned().notNullable();
|
||||
table.integer('revision_id').unsigned().notNullable();
|
||||
|
||||
table.uuid('user_id').nullable();
|
||||
|
||||
table
|
||||
.enum('action', ['pending', 'approve', 'reject', 'forward'])
|
||||
.index()
|
||||
.notNullable()
|
||||
.defaultTo('pending');
|
||||
|
||||
table
|
||||
.enum('rejection_reason', ['tos', 'illegal', 'dmca', 'other'])
|
||||
.index()
|
||||
.nullable();
|
||||
|
||||
table.text('description').nullable();
|
||||
|
||||
table.boolean('penalty').notNullable().defaultTo(false);
|
||||
table.boolean('asset_delete').notNullable().defaultTo(false);
|
||||
|
||||
table.timestamps(true, true);
|
||||
table.timestamp('decided_at');
|
||||
|
||||
table.foreign('content_id').references('content.id').onDelete('CASCADE');
|
||||
table
|
||||
.foreign('revision_id')
|
||||
.references('content_revision.id')
|
||||
.onDelete('CASCADE');
|
||||
}),
|
||||
knex.schema.createTable('content_moderation_ban', (table) => {
|
||||
table.integer('content_moderation_id').unsigned().notNullable();
|
||||
table.integer('ban_id').unsigned().nullable();
|
||||
table
|
||||
.foreign('content_moderation_id')
|
||||
.references('content_moderation.id')
|
||||
.onDelete('CASCADE');
|
||||
}),
|
||||
]);
|
||||
}
|
||||
|
||||
export async function down(knex: Knex): Promise<void> {
|
||||
await Promise.all([
|
||||
knex.schema.dropTable('content_moderation'),
|
||||
knex.schema.dropTable('content_moderation_ban'),
|
||||
]);
|
||||
}
|
@ -0,0 +1,25 @@
|
||||
import { Knex } from 'knex';
|
||||
|
||||
export async function up(knex: Knex): Promise<void> {
|
||||
return knex.schema.createTable('content_asset', (table) => {
|
||||
table.increments('id').primary();
|
||||
|
||||
table.integer('content_id').unsigned().notNullable();
|
||||
table.integer('revision_id').unsigned().notNullable();
|
||||
table.uuid('asset_id').notNullable().index();
|
||||
|
||||
table.string('type').notNullable().index();
|
||||
table.string('type_name').nullable();
|
||||
table.integer('index').notNullable().defaultTo(0);
|
||||
|
||||
table.foreign('content_id').references('content.id').onDelete('CASCADE');
|
||||
table
|
||||
.foreign('revision_id')
|
||||
.references('content_revision.id')
|
||||
.onDelete('CASCADE');
|
||||
});
|
||||
}
|
||||
|
||||
export async function down(knex: Knex): Promise<void> {
|
||||
return knex.schema.dropTable('content_asset');
|
||||
}
|
@ -0,0 +1,23 @@
|
||||
import { Knex } from 'knex';
|
||||
|
||||
export async function up(knex: Knex): Promise<void> {
|
||||
return knex.schema.createTable('content_price', (table) => {
|
||||
table.increments('id').primary();
|
||||
|
||||
table.integer('content_id').unsigned().notNullable();
|
||||
|
||||
table.integer('price').unsigned().notNullable().defaultTo(0).index();
|
||||
table.enum('currency', ['whole', 'denom']).notNullable().index();
|
||||
|
||||
table.uuid('created_by').nullable();
|
||||
table.uuid('updated_by').nullable();
|
||||
|
||||
table.timestamps(true, true);
|
||||
|
||||
table.foreign('content_id').references('content.id').onDelete('CASCADE');
|
||||
});
|
||||
}
|
||||
|
||||
export async function down(knex: Knex): Promise<void> {
|
||||
return knex.schema.dropTable('content_price');
|
||||
}
|
@ -0,0 +1,40 @@
|
||||
import { Knex } from 'knex';
|
||||
|
||||
export async function up(knex: Knex): Promise<void> {
|
||||
return knex.schema.createTable('content_ownership', (table) => {
|
||||
table.increments('id').primary();
|
||||
|
||||
table.integer('content_id').unsigned().notNullable();
|
||||
table.uuid('user_id').notNullable();
|
||||
|
||||
table
|
||||
.enum('source', ['author', 'purchase', 'trade', 'gift'])
|
||||
.notNullable()
|
||||
.defaultTo('author')
|
||||
.index();
|
||||
|
||||
table.integer('previous_ownership_id').unsigned().nullable();
|
||||
|
||||
table.integer('purchase_price').nullable();
|
||||
table.enum('purchase_currency', ['whole', 'denom']).nullable();
|
||||
|
||||
table.integer('serial').unsigned().nullable();
|
||||
|
||||
table.uuid('created_by').nullable();
|
||||
table.uuid('updated_by').nullable();
|
||||
|
||||
table.timestamps(true, true);
|
||||
table.timestamp('ended_at').nullable();
|
||||
table.timestamp('expires_at').nullable();
|
||||
|
||||
table.foreign('content_id').references('content.id').onDelete('CASCADE');
|
||||
table
|
||||
.foreign('previous_ownership_id')
|
||||
.references('content_ownership.id')
|
||||
.onDelete('CASCADE');
|
||||
});
|
||||
}
|
||||
|
||||
export async function down(knex: Knex): Promise<void> {
|
||||
return knex.schema.dropTable('content_ownership');
|
||||
}
|
@ -0,0 +1,61 @@
|
||||
import { Knex } from 'knex';
|
||||
|
||||
export async function up(knex: Knex): Promise<void> {
|
||||
await Promise.all([
|
||||
knex.schema.createTable('content_trade', (table) => {
|
||||
table.increments('id').primary();
|
||||
|
||||
table.uuid('user_id').notNullable();
|
||||
table.uuid('recipient_id').notNullable();
|
||||
|
||||
table
|
||||
.enum('status', [
|
||||
'sent',
|
||||
'opened',
|
||||
'rejected',
|
||||
'return_to_sender',
|
||||
'confirmed',
|
||||
'cancelled',
|
||||
])
|
||||
.notNullable()
|
||||
.defaultTo('sent')
|
||||
.index();
|
||||
|
||||
table.text('description').nullable();
|
||||
|
||||
table.timestamps(true, true);
|
||||
}),
|
||||
knex.schema.createTable('content_trade_user_content', (table) => {
|
||||
table.integer('content_trade_id').unsigned().notNullable();
|
||||
table.integer('content_ownership_id').unsigned().notNullable();
|
||||
table
|
||||
.foreign('content_trade_id')
|
||||
.references('content_trade.id')
|
||||
.onDelete('CASCADE');
|
||||
table
|
||||
.foreign('content_ownership_id')
|
||||
.references('content_ownership.id')
|
||||
.onDelete('CASCADE');
|
||||
}),
|
||||
knex.schema.createTable('content_trade_recipient_content', (table) => {
|
||||
table.integer('content_trade_id').unsigned().notNullable();
|
||||
table.integer('content_ownership_id').unsigned().notNullable();
|
||||
table
|
||||
.foreign('content_trade_id')
|
||||
.references('content_trade.id')
|
||||
.onDelete('CASCADE');
|
||||
table
|
||||
.foreign('content_ownership_id')
|
||||
.references('content_ownership.id')
|
||||
.onDelete('CASCADE');
|
||||
}),
|
||||
]);
|
||||
}
|
||||
|
||||
export async function down(knex: Knex): Promise<void> {
|
||||
await Promise.all([
|
||||
knex.schema.dropTable('content_trade'),
|
||||
knex.schema.dropTable('content_trade_user_content'),
|
||||
knex.schema.dropTable('content_trade_recipient_content'),
|
||||
]);
|
||||
}
|
@ -0,0 +1,18 @@
|
||||
import { Knex } from 'knex';
|
||||
|
||||
export async function up(knex: Knex): Promise<void> {
|
||||
return knex.schema.createTable('content_favorite', (table) => {
|
||||
table.increments('id').primary();
|
||||
|
||||
table.integer('content_id').unsigned().notNullable();
|
||||
table.uuid('user_id').index().notNullable();
|
||||
|
||||
table.timestamps(true, true);
|
||||
|
||||
table.foreign('content_id').references('content.id').onDelete('CASCADE');
|
||||
});
|
||||
}
|
||||
|
||||
export async function down(knex: Knex): Promise<void> {
|
||||
return knex.schema.dropTable('content_favorite');
|
||||
}
|
@ -0,0 +1,20 @@
|
||||
import { Knex } from 'knex';
|
||||
|
||||
export async function up(knex: Knex): Promise<void> {
|
||||
return knex.schema.createTable('content_vote', (table) => {
|
||||
table.increments('id').primary();
|
||||
|
||||
table.integer('content_id').index().unsigned().notNullable();
|
||||
table.uuid('user_id').notNullable();
|
||||
|
||||
table.enum('vote', ['up', 'down']).index().notNullable();
|
||||
|
||||
table.timestamps(true, true);
|
||||
|
||||
table.foreign('content_id').references('content.id').onDelete('CASCADE');
|
||||
});
|
||||
}
|
||||
|
||||
export async function down(knex: Knex): Promise<void> {
|
||||
return knex.schema.dropTable('content_vote');
|
||||
}
|
@ -0,0 +1,47 @@
|
||||
import { Knex } from 'knex';
|
||||
|
||||
export async function up(knex: Knex): Promise<void> {
|
||||
await Promise.all([
|
||||
knex.schema.createTable('content_report', (table) => {
|
||||
table.increments('id').primary();
|
||||
|
||||
table.integer('content_id').index().unsigned().notNullable();
|
||||
table.uuid('user_id').notNullable();
|
||||
table.uuid('moderator_id').nullable();
|
||||
|
||||
table.text('reason').notNullable();
|
||||
table.text('description').notNullable();
|
||||
table.text('notes').nullable();
|
||||
|
||||
table
|
||||
.enum('status', ['open', 'closed', 'invalid', 'resolved'])
|
||||
.index()
|
||||
.notNullable()
|
||||
.defaultTo('open');
|
||||
|
||||
table.timestamps(true, true);
|
||||
table.timestamp('resolved_at');
|
||||
|
||||
table.foreign('content_id').references('content.id').onDelete('CASCADE');
|
||||
}),
|
||||
knex.schema.createTable('content_report_action', (table) => {
|
||||
table.integer('content_report_id').index().unsigned().notNullable();
|
||||
table.integer('content_moderation_id').index().unsigned().notNullable();
|
||||
table
|
||||
.foreign('content_report_id')
|
||||
.references('content_report.id')
|
||||
.onDelete('CASCADE');
|
||||
table
|
||||
.foreign('content_moderation_id')
|
||||
.references('content_moderation.id')
|
||||
.onDelete('CASCADE');
|
||||
}),
|
||||
]);
|
||||
}
|
||||
|
||||
export async function down(knex: Knex): Promise<void> {
|
||||
await Promise.all([
|
||||
knex.schema.dropTable('content_report'),
|
||||
knex.schema.dropTable('content_report_action'),
|
||||
]);
|
||||
}
|
11
apps/catalog/src/enums/content-asset-type.enum.ts
Normal file
11
apps/catalog/src/enums/content-asset-type.enum.ts
Normal file
@ -0,0 +1,11 @@
|
||||
export enum ContentAssetType {
|
||||
IMAGE = 'image',
|
||||
TEXTURE = 'texture',
|
||||
TEXTURE3D = 'texture3d',
|
||||
MESH = 'mesh',
|
||||
ANIMATION = 'animation',
|
||||
GAMEOBJECT = 'gameobject',
|
||||
WORLD = 'world',
|
||||
CHARACTER = 'character',
|
||||
SOUND = 'sound',
|
||||
}
|
18
apps/catalog/src/enums/content-type.enum.ts
Normal file
18
apps/catalog/src/enums/content-type.enum.ts
Normal file
@ -0,0 +1,18 @@
|
||||
export enum ContentType {
|
||||
CONTENT = 'content',
|
||||
CHARACTER = 'character',
|
||||
HAT = 'hat',
|
||||
ACCESSORY = 'accessory',
|
||||
FRONT = 'front',
|
||||
BACK = 'back',
|
||||
TOOL = 'tool',
|
||||
MESH = 'mesh',
|
||||
TEXTURE = 'texture',
|
||||
GAMEOBJECT = 'gameobject',
|
||||
SOUND = 'sound',
|
||||
ANIMATION = 'animation',
|
||||
COMMENT = 'comment',
|
||||
STATUS = 'status',
|
||||
GAME = 'game',
|
||||
WORLD = 'world',
|
||||
}
|
4
apps/catalog/src/enums/currency.enum.ts
Normal file
4
apps/catalog/src/enums/currency.enum.ts
Normal file
@ -0,0 +1,4 @@
|
||||
export enum Currency {
|
||||
WHOLE = 'whole',
|
||||
DENOMINATION = 'denom',
|
||||
}
|
6
apps/catalog/src/enums/moderation-action.enum.ts
Normal file
6
apps/catalog/src/enums/moderation-action.enum.ts
Normal file
@ -0,0 +1,6 @@
|
||||
export enum ModeratorAction {
|
||||
PENDING = 'pending',
|
||||
APPROVE = 'approve',
|
||||
REJECT = 'reject',
|
||||
FORWARD = 'forward',
|
||||
}
|
6
apps/catalog/src/enums/privacy.enum.ts
Normal file
6
apps/catalog/src/enums/privacy.enum.ts
Normal file
@ -0,0 +1,6 @@
|
||||
export enum Privacy {
|
||||
PUBLIC = 'public',
|
||||
FRIENDS = 'friends',
|
||||
UNLISTED = 'unlisted',
|
||||
PRIVATE = 'private',
|
||||
}
|
6
apps/catalog/src/enums/rejection-reason.enum.ts
Normal file
6
apps/catalog/src/enums/rejection-reason.enum.ts
Normal file
@ -0,0 +1,6 @@
|
||||
export enum RejectionReason {
|
||||
TERMS_OF_SERVICE = 'tos',
|
||||
ILLEGAL_CONTENT = 'illegal',
|
||||
DMCA = 'dmca',
|
||||
OTHER = 'other',
|
||||
}
|
6
apps/catalog/src/enums/report-status.enum.ts
Normal file
6
apps/catalog/src/enums/report-status.enum.ts
Normal file
@ -0,0 +1,6 @@
|
||||
export enum ReportStatus {
|
||||
OPEN = 'open',
|
||||
CLOSED = 'closed',
|
||||
INVALID = 'invalid',
|
||||
RESOLVED = 'resolved',
|
||||
}
|
8
apps/catalog/src/enums/trade-status.enum.ts
Normal file
8
apps/catalog/src/enums/trade-status.enum.ts
Normal file
@ -0,0 +1,8 @@
|
||||
export enum TradeStatus {
|
||||
SENT = 'sent',
|
||||
OPENED = 'opened',
|
||||
REJECTED = 'rejected',
|
||||
RETURN_TO_SENDER = 'return_to_sender',
|
||||
CONFIRMED = 'confirmed',
|
||||
CANCELLED = 'cancelled',
|
||||
}
|
4
apps/catalog/src/enums/vote.enum.ts
Normal file
4
apps/catalog/src/enums/vote.enum.ts
Normal file
@ -0,0 +1,4 @@
|
||||
export enum Vote {
|
||||
UPVOTE = 'up',
|
||||
DOWNVOTE = 'down',
|
||||
}
|
5
apps/catalog/src/knexfile.ts
Normal file
5
apps/catalog/src/knexfile.ts
Normal file
@ -0,0 +1,5 @@
|
||||
import { getKnex } from '../../../libs/shared/src/';
|
||||
|
||||
module.exports = {
|
||||
development: getKnex('catalog', __dirname, ['.ts', '.js']),
|
||||
};
|
Loading…
Reference in New Issue
Block a user