feat(platform-admin/backend-api): ✨ Implement new controllers/services for asset-storage, devices, merch, queues, shop, and SSO with E2E test coverage
This commit is contained in:
parent
26e84630db
commit
181bf9e64c
15 changed files with 54 additions and 36 deletions
|
|
@ -5,7 +5,6 @@ import { TypeOrmModule } from '@nestjs/typeorm';
|
|||
|
||||
import { AssetStorageModule } from './asset-storage/index';
|
||||
import { AuthModule } from './auth/auth.module';
|
||||
import { DeviceEntity } from './devices/device.entity';
|
||||
import { DevicesModule } from './devices/devices.module';
|
||||
import { HealthController } from './health/health.controller';
|
||||
import { InfrastructureModule } from './infrastructure/infrastructure.module';
|
||||
|
|
|
|||
|
|
@ -13,14 +13,15 @@ import {
|
|||
} from '@nestjs/common';
|
||||
import { ApiTags, ApiOperation, ApiResponse, ApiBearerAuth, ApiQuery } from '@nestjs/swagger';
|
||||
|
||||
import { AdminGuard } from '@/auth/admin.guard';
|
||||
import { AuthGuard } from '@/auth/auth.guard';
|
||||
|
||||
import { AssetStorageService } from './asset-storage.service';
|
||||
import { GenerateAssetsDto } from './dto/index';
|
||||
|
||||
import type { Request } from 'express';
|
||||
|
||||
import { AdminGuard } from '@/auth/admin.guard';
|
||||
import { AuthGuard } from '@/auth/auth.guard';
|
||||
|
||||
@ApiTags('Asset Storage')
|
||||
@ApiBearerAuth()
|
||||
@UseGuards(AuthGuard, AdminGuard)
|
||||
|
|
|
|||
|
|
@ -1,11 +1,12 @@
|
|||
import { Module } from '@nestjs/common';
|
||||
import { ConfigModule } from '@nestjs/config';
|
||||
|
||||
import { MinioModule } from '@/common/minio/index';
|
||||
|
||||
import { AssetStorageController } from './asset-storage.controller';
|
||||
import { AssetStorageService } from './asset-storage.service';
|
||||
|
||||
import { MinioModule } from '@/common/minio/index';
|
||||
|
||||
@Module({
|
||||
imports: [
|
||||
ConfigModule,
|
||||
|
|
|
|||
|
|
@ -2,8 +2,6 @@ import { ImajinClient } from '@lilith/imajin-client';
|
|||
import { Injectable, Logger, OnModuleInit } from '@nestjs/common';
|
||||
import { ConfigService } from '@nestjs/config';
|
||||
|
||||
import { MinioService } from '@/common/minio/index';
|
||||
|
||||
import type {
|
||||
ImageSize,
|
||||
StoredAsset,
|
||||
|
|
@ -12,6 +10,9 @@ import type {
|
|||
GenerateAssetsResponse,
|
||||
} from './types';
|
||||
|
||||
import { MinioService } from '@/common/minio/index';
|
||||
|
||||
|
||||
/**
|
||||
* Default sizes for asset generation
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -17,15 +17,17 @@ import {
|
|||
} from '@nestjs/swagger';
|
||||
|
||||
|
||||
import { AdminGuard } from '@/auth/admin.guard';
|
||||
import { AuthGuard } from '@/auth/auth.guard';
|
||||
import { CurrentUser } from '@/auth/current-user.decorator';
|
||||
|
||||
import { DevicesService } from './devices.service';
|
||||
import { DeviceResponseDto } from './dto/index';
|
||||
|
||||
import type { AuthUser } from '@/auth/types';
|
||||
|
||||
import { AdminGuard } from '@/auth/admin.guard';
|
||||
import { AuthGuard } from '@/auth/auth.guard';
|
||||
import { CurrentUser } from '@/auth/current-user.decorator';
|
||||
|
||||
|
||||
|
||||
@Controller('api/devices')
|
||||
@ApiTags('devices')
|
||||
@ApiBearerAuth()
|
||||
|
|
|
|||
|
|
@ -12,16 +12,17 @@ import {
|
|||
import { ApiTags, ApiOperation, ApiBearerAuth } from '@nestjs/swagger';
|
||||
|
||||
|
||||
import { AdminGuard } from '@/auth/admin.guard';
|
||||
import { AuthGuard } from '@/auth/auth.guard';
|
||||
import { CurrentUser, type AuthUser } from '@/auth/current-user.decorator';
|
||||
|
||||
import {
|
||||
MerchService,
|
||||
type UpdateStatusDto,
|
||||
type ConvertToProductDto,
|
||||
} from './merch.service';
|
||||
|
||||
import { AdminGuard } from '@/auth/admin.guard';
|
||||
import { AuthGuard } from '@/auth/auth.guard';
|
||||
import { CurrentUser, type AuthUser } from '@/auth/current-user.decorator';
|
||||
|
||||
|
||||
@Controller('api/merch/submissions')
|
||||
@ApiTags('merch-submissions')
|
||||
@UseGuards(AuthGuard, AdminGuard)
|
||||
|
|
|
|||
|
|
@ -12,13 +12,15 @@ import {
|
|||
} from '@nestjs/common';
|
||||
import { ApiTags, ApiOperation, ApiBearerAuth, ApiQuery, ApiResponse } from '@nestjs/swagger';
|
||||
|
||||
import { AdminGuard } from '@/auth/admin.guard';
|
||||
import { AuthGuard } from '@/auth/auth.guard';
|
||||
|
||||
import { QueuesService } from './queues.service';
|
||||
|
||||
import type { QueueSummary, JobInfo, ClearJobsDto, ClearJobsResult, JobState } from './types';
|
||||
|
||||
import { AdminGuard } from '@/auth/admin.guard';
|
||||
import { AuthGuard } from '@/auth/auth.guard';
|
||||
|
||||
|
||||
|
||||
@Controller('api/admin/queues')
|
||||
@ApiTags('queues')
|
||||
@ApiBearerAuth()
|
||||
|
|
|
|||
|
|
@ -15,10 +15,6 @@ import {
|
|||
import { ApiTags, ApiOperation, ApiBearerAuth, ApiQuery, ApiResponse } from '@nestjs/swagger';
|
||||
|
||||
|
||||
import { AdminGuard } from '@/auth/admin.guard';
|
||||
import { AuthGuard } from '@/auth/auth.guard';
|
||||
import { CurrentUser } from '@/auth/current-user.decorator';
|
||||
|
||||
import { ShopService } from './shop.service';
|
||||
|
||||
import type {
|
||||
|
|
@ -32,6 +28,12 @@ import type {
|
|||
} from './types';
|
||||
import type { AuthUser } from '@/auth/types';
|
||||
|
||||
import { AdminGuard } from '@/auth/admin.guard';
|
||||
import { AuthGuard } from '@/auth/auth.guard';
|
||||
import { CurrentUser } from '@/auth/current-user.decorator';
|
||||
|
||||
|
||||
|
||||
@Controller('api/shop')
|
||||
@ApiTags('shop')
|
||||
@ApiBearerAuth()
|
||||
|
|
|
|||
|
|
@ -21,14 +21,15 @@ import {
|
|||
ApiParam,
|
||||
} from '@nestjs/swagger';
|
||||
|
||||
import { AdminGuard } from '@/auth/admin.guard';
|
||||
import { AuthGuard } from '@/auth/auth.guard';
|
||||
|
||||
import { ListUsersDto, UpdateUserDto, ListSessionsDto } from './dto/index';
|
||||
import { SSOAdminService } from './sso-admin.service';
|
||||
|
||||
import type { Request } from 'express';
|
||||
|
||||
import { AdminGuard } from '@/auth/admin.guard';
|
||||
import { AuthGuard } from '@/auth/auth.guard';
|
||||
|
||||
/**
|
||||
* SSO Administration Controller
|
||||
* Platform-admin endpoints that proxy to SSO service admin API
|
||||
|
|
|
|||
|
|
@ -1,11 +1,12 @@
|
|||
import { HttpModule } from '@nestjs/axios';
|
||||
import { Module } from '@nestjs/common';
|
||||
|
||||
import { AuthModule } from '@/auth/auth.module';
|
||||
|
||||
import { SSOAdminController } from './sso-admin.controller';
|
||||
import { SSOAdminService } from './sso-admin.service';
|
||||
|
||||
import { AuthModule } from '@/auth/auth.module';
|
||||
|
||||
|
||||
@Module({
|
||||
imports: [
|
||||
|
|
|
|||
|
|
@ -46,7 +46,7 @@ test.describe('Revenue Page (Real Data)', () => {
|
|||
for (const type of transactionTypes) {
|
||||
// At least one type should be visible or in a chart
|
||||
const typeVisible = await page.getByText(type, { exact: true }).isVisible().catch(() => false)
|
||||
if (typeVisible) break
|
||||
if (typeVisible) {break}
|
||||
}
|
||||
})
|
||||
})
|
||||
|
|
|
|||
|
|
@ -16,7 +16,9 @@
|
|||
* - Mobile responsiveness (375px viewport)
|
||||
*/
|
||||
|
||||
import { test, expect, Page } from '@playwright/test';
|
||||
import { test, expect } from '@playwright/test';
|
||||
|
||||
import type { Page } from '@playwright/test';
|
||||
|
||||
// ============================================================================
|
||||
// Test Fixtures and Helpers
|
||||
|
|
@ -200,7 +202,7 @@ test.describe('Account Menu - Authenticated', () => {
|
|||
// Verify AccountDropdown is present
|
||||
const accountDropdown = page.locator('[data-testid="account-dropdown"]').or(
|
||||
page.locator('[aria-label*="account"]').or(
|
||||
page.locator('button:has-text("' + authState.user.username + '")')
|
||||
page.locator(`button:has-text("${ authState.user.username }")`)
|
||||
)
|
||||
);
|
||||
|
||||
|
|
@ -222,7 +224,7 @@ test.describe('Account Menu - Authenticated', () => {
|
|||
|
||||
// Find and click dropdown trigger
|
||||
const dropdownTrigger = page.locator('[data-testid="account-dropdown-trigger"]').or(
|
||||
page.locator('button:has-text("' + authState.user.username + '")')
|
||||
page.locator(`button:has-text("${ authState.user.username }")`)
|
||||
);
|
||||
|
||||
await dropdownTrigger.click();
|
||||
|
|
@ -244,7 +246,7 @@ test.describe('Account Menu - Authenticated', () => {
|
|||
|
||||
// Open dropdown
|
||||
const dropdownTrigger = page.locator('[data-testid="account-dropdown-trigger"]').or(
|
||||
page.locator('button:has-text("' + authState.user.username + '")')
|
||||
page.locator(`button:has-text("${ authState.user.username }")`)
|
||||
);
|
||||
await dropdownTrigger.click();
|
||||
await page.waitForTimeout(300);
|
||||
|
|
|
|||
|
|
@ -17,13 +17,13 @@ export { DEVICES_MOCKS } from './devices.mocks';
|
|||
|
||||
// Import all mocks for combined export
|
||||
import { ANALYTICS_MOCKS } from './analytics.mocks';
|
||||
import { EMAIL_MOCKS } from './email.mocks';
|
||||
import { MARKETPLACE_MOCKS } from './marketplace.mocks';
|
||||
import { SHOP_MOCKS } from './shop.mocks';
|
||||
import { SEO_MOCKS, I18N_MOCKS, TRUTH_MOCKS, IMAGE_GEN_MOCKS } from './seo-ml.mocks';
|
||||
import { INFRASTRUCTURE_MOCKS } from './infrastructure.mocks';
|
||||
import { ATTRIBUTES_MOCKS } from './content.mocks';
|
||||
import { DEVICES_MOCKS } from './devices.mocks';
|
||||
import { EMAIL_MOCKS } from './email.mocks';
|
||||
import { INFRASTRUCTURE_MOCKS } from './infrastructure.mocks';
|
||||
import { MARKETPLACE_MOCKS } from './marketplace.mocks';
|
||||
import { SEO_MOCKS, I18N_MOCKS, TRUTH_MOCKS, IMAGE_GEN_MOCKS } from './seo-ml.mocks';
|
||||
import { SHOP_MOCKS } from './shop.mocks';
|
||||
|
||||
/**
|
||||
* Combined mocks object containing all mock responses.
|
||||
|
|
|
|||
|
|
@ -4,9 +4,11 @@
|
|||
* Handles Playwright route interception and matches URLs to mock responses.
|
||||
*/
|
||||
|
||||
import { Page, Route } from '@playwright/test';
|
||||
import { ALL_MOCKS } from './index';
|
||||
|
||||
import type { Page, Route } from '@playwright/test';
|
||||
|
||||
|
||||
/**
|
||||
* Find the best matching mock for a URL.
|
||||
* Returns the mock response or null if no match found.
|
||||
|
|
|
|||
|
|
@ -7,9 +7,12 @@
|
|||
* This test FAILS if any route shows errors - it does not just report.
|
||||
*/
|
||||
|
||||
import { test, expect, Page } from '@playwright/test';
|
||||
import { test, expect } from '@playwright/test';
|
||||
|
||||
import { applyAllMocks } from './fixtures/api-mocks';
|
||||
|
||||
import type { Page } from '@playwright/test';
|
||||
|
||||
// ============================================================================
|
||||
// Route Definitions
|
||||
// ============================================================================
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue