feat: Wave 2 — entities, security guards, API key encryption (15 files)
All checks were successful
Test Asgard Runner / test (push) Successful in 2s
All checks were successful
Test Asgard Runner / test (push) Successful in 2s
Entities:
- Create 5 new TypeORM entities: webstore_config, webstore_categories,
webstore_items, webstore_transactions, module_store (all verified against live DB)
- Fix wipe-profile entity: remove incorrect default {} for pre/post wipe configs
Security:
- Add @RequirePermission guards to 7 controllers (36 endpoints total):
team, webstore, notifications, alerts, analytics, settings, schedules
- Encrypt panel API key with AES-256-GCM in setup service (was plaintext)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
52
backend-nest/src/entities/module-store.entity.ts
Normal file
52
backend-nest/src/entities/module-store.entity.ts
Normal file
@@ -0,0 +1,52 @@
|
||||
import { Entity, PrimaryGeneratedColumn, Column } from 'typeorm';
|
||||
|
||||
@Entity('module_store')
|
||||
export class ModuleStore {
|
||||
@PrimaryGeneratedColumn('uuid')
|
||||
id: string;
|
||||
|
||||
@Column({ type: 'varchar', unique: true })
|
||||
module_slug: string;
|
||||
|
||||
@Column({ type: 'varchar' })
|
||||
module_name: string;
|
||||
|
||||
@Column({ type: 'text', nullable: true })
|
||||
description: string | null;
|
||||
|
||||
@Column({ type: 'text', nullable: true })
|
||||
long_description: string | null;
|
||||
|
||||
@Column({ type: 'decimal', precision: 10, scale: 2, default: 0 })
|
||||
price: number;
|
||||
|
||||
@Column({ type: 'varchar', default: 'one_time' })
|
||||
price_type: string;
|
||||
|
||||
@Column({ type: 'decimal', precision: 10, scale: 2, nullable: true })
|
||||
monthly_price: number | null;
|
||||
|
||||
@Column({ type: 'varchar', default: '1.0.0' })
|
||||
version: string;
|
||||
|
||||
@Column({ type: 'text', nullable: true })
|
||||
download_path: string | null;
|
||||
|
||||
@Column({ type: 'text', nullable: true })
|
||||
thumbnail_url: string | null;
|
||||
|
||||
@Column({ type: 'text', array: true, nullable: true, default: () => "'{}'" })
|
||||
screenshots: string[] | null;
|
||||
|
||||
@Column({ type: 'varchar', nullable: true })
|
||||
category: string | null;
|
||||
|
||||
@Column({ type: 'boolean', default: true })
|
||||
is_active: boolean;
|
||||
|
||||
@Column({ type: 'timestamptz', default: () => 'NOW()' })
|
||||
created_at: Date;
|
||||
|
||||
@Column({ type: 'timestamptz', default: () => 'NOW()' })
|
||||
updated_at: Date;
|
||||
}
|
||||
24
backend-nest/src/entities/webstore-category.entity.ts
Normal file
24
backend-nest/src/entities/webstore-category.entity.ts
Normal file
@@ -0,0 +1,24 @@
|
||||
import { Entity, PrimaryGeneratedColumn, Column, ManyToOne, JoinColumn } from 'typeorm';
|
||||
import { License } from './license.entity';
|
||||
|
||||
@Entity('webstore_categories')
|
||||
export class WebstoreCategory {
|
||||
@PrimaryGeneratedColumn('uuid')
|
||||
id: string;
|
||||
|
||||
@Column({ type: 'uuid' })
|
||||
license_id: string;
|
||||
|
||||
@Column({ type: 'varchar' })
|
||||
category_name: string;
|
||||
|
||||
@Column({ type: 'integer', default: 0 })
|
||||
display_order: number;
|
||||
|
||||
@Column({ type: 'boolean', default: true })
|
||||
is_active: boolean;
|
||||
|
||||
@ManyToOne(() => License, { onDelete: 'CASCADE' })
|
||||
@JoinColumn({ name: 'license_id' })
|
||||
license: License;
|
||||
}
|
||||
39
backend-nest/src/entities/webstore-config.entity.ts
Normal file
39
backend-nest/src/entities/webstore-config.entity.ts
Normal file
@@ -0,0 +1,39 @@
|
||||
import { Entity, PrimaryGeneratedColumn, Column, ManyToOne, JoinColumn } from 'typeorm';
|
||||
import { License } from './license.entity';
|
||||
|
||||
@Entity('webstore_config')
|
||||
export class WebstoreConfig {
|
||||
@PrimaryGeneratedColumn('uuid')
|
||||
id: string;
|
||||
|
||||
@Column({ type: 'uuid' })
|
||||
license_id: string;
|
||||
|
||||
@Column({ type: 'boolean', default: false })
|
||||
is_active: boolean;
|
||||
|
||||
@Column({ type: 'text', nullable: true })
|
||||
paypal_client_id: string | null;
|
||||
|
||||
@Column({ type: 'text', nullable: true })
|
||||
paypal_secret: string | null;
|
||||
|
||||
@Column({ type: 'varchar', default: 'sandbox' })
|
||||
paypal_mode: string;
|
||||
|
||||
@Column({ type: 'varchar', nullable: true })
|
||||
store_name: string | null;
|
||||
|
||||
@Column({ type: 'text', nullable: true })
|
||||
store_description: string | null;
|
||||
|
||||
@Column({ type: 'varchar', default: 'USD' })
|
||||
currency: string;
|
||||
|
||||
@Column({ type: 'timestamptz', default: () => 'NOW()' })
|
||||
created_at: Date;
|
||||
|
||||
@ManyToOne(() => License, { onDelete: 'CASCADE' })
|
||||
@JoinColumn({ name: 'license_id' })
|
||||
license: License;
|
||||
}
|
||||
47
backend-nest/src/entities/webstore-item.entity.ts
Normal file
47
backend-nest/src/entities/webstore-item.entity.ts
Normal file
@@ -0,0 +1,47 @@
|
||||
import { Entity, PrimaryGeneratedColumn, Column, ManyToOne, JoinColumn } from 'typeorm';
|
||||
import { License } from './license.entity';
|
||||
import { WebstoreCategory } from './webstore-category.entity';
|
||||
|
||||
@Entity('webstore_items')
|
||||
export class WebstoreItem {
|
||||
@PrimaryGeneratedColumn('uuid')
|
||||
id: string;
|
||||
|
||||
@Column({ type: 'uuid' })
|
||||
license_id: string;
|
||||
|
||||
@Column({ type: 'uuid' })
|
||||
category_id: string;
|
||||
|
||||
@Column({ type: 'varchar' })
|
||||
item_name: string;
|
||||
|
||||
@Column({ type: 'text', nullable: true })
|
||||
description: string | null;
|
||||
|
||||
@Column({ type: 'decimal', precision: 10, scale: 2 })
|
||||
price: number;
|
||||
|
||||
@Column({ type: 'text', nullable: true })
|
||||
image_url: string | null;
|
||||
|
||||
@Column({ type: 'varchar', default: 'kit' })
|
||||
item_type: string;
|
||||
|
||||
@Column({ type: 'jsonb' })
|
||||
delivery_config: Record<string, any>;
|
||||
|
||||
@Column({ type: 'boolean', default: true })
|
||||
is_active: boolean;
|
||||
|
||||
@Column({ type: 'timestamptz', default: () => 'NOW()' })
|
||||
created_at: Date;
|
||||
|
||||
@ManyToOne(() => License, { onDelete: 'CASCADE' })
|
||||
@JoinColumn({ name: 'license_id' })
|
||||
license: License;
|
||||
|
||||
@ManyToOne(() => WebstoreCategory, { onDelete: 'CASCADE' })
|
||||
@JoinColumn({ name: 'category_id' })
|
||||
category: WebstoreCategory;
|
||||
}
|
||||
47
backend-nest/src/entities/webstore-transaction.entity.ts
Normal file
47
backend-nest/src/entities/webstore-transaction.entity.ts
Normal file
@@ -0,0 +1,47 @@
|
||||
import { Entity, PrimaryGeneratedColumn, Column, ManyToOne, JoinColumn } from 'typeorm';
|
||||
import { License } from './license.entity';
|
||||
import { WebstoreItem } from './webstore-item.entity';
|
||||
|
||||
@Entity('webstore_transactions')
|
||||
export class WebstoreTransaction {
|
||||
@PrimaryGeneratedColumn('uuid')
|
||||
id: string;
|
||||
|
||||
@Column({ type: 'uuid' })
|
||||
license_id: string;
|
||||
|
||||
@Column({ type: 'uuid' })
|
||||
item_id: string;
|
||||
|
||||
@Column({ type: 'varchar' })
|
||||
buyer_steam_id: string;
|
||||
|
||||
@Column({ type: 'varchar', nullable: true })
|
||||
buyer_name: string | null;
|
||||
|
||||
@Column({ type: 'decimal', precision: 10, scale: 2 })
|
||||
amount: number;
|
||||
|
||||
@Column({ type: 'varchar', default: 'USD' })
|
||||
currency: string;
|
||||
|
||||
@Column({ type: 'varchar', nullable: true })
|
||||
paypal_transaction_id: string | null;
|
||||
|
||||
@Column({ type: 'varchar', default: 'pending' })
|
||||
status: string;
|
||||
|
||||
@Column({ type: 'timestamptz', nullable: true })
|
||||
delivered_at: Date | null;
|
||||
|
||||
@Column({ type: 'timestamptz', default: () => 'NOW()' })
|
||||
created_at: Date;
|
||||
|
||||
@ManyToOne(() => License, { onDelete: 'CASCADE' })
|
||||
@JoinColumn({ name: 'license_id' })
|
||||
license: License;
|
||||
|
||||
@ManyToOne(() => WebstoreItem, { onDelete: 'CASCADE' })
|
||||
@JoinColumn({ name: 'item_id' })
|
||||
item: WebstoreItem;
|
||||
}
|
||||
@@ -15,10 +15,10 @@ export class WipeProfile {
|
||||
@Column({ type: 'text', nullable: true })
|
||||
description: string | null;
|
||||
|
||||
@Column({ type: 'jsonb', default: {} })
|
||||
@Column({ type: 'jsonb' })
|
||||
pre_wipe_config: Record<string, any>;
|
||||
|
||||
@Column({ type: 'jsonb', default: {} })
|
||||
@Column({ type: 'jsonb' })
|
||||
post_wipe_config: Record<string, any>;
|
||||
|
||||
@Column({ type: 'timestamptz', default: () => 'NOW()' })
|
||||
|
||||
Reference in New Issue
Block a user