feat(M08-D): 补广告与装修管理
This commit is contained in:
@@ -3,6 +3,8 @@ import { mkdtemp, readFile, rm } from 'node:fs/promises';
|
||||
import { tmpdir } from 'node:os';
|
||||
import { join } from 'node:path';
|
||||
import sharp from 'sharp';
|
||||
import { buildApp } from '../dist/app.js';
|
||||
import { signAccessToken } from '../dist/auth/jwt.js';
|
||||
import { MediaStorage, MediaValidationError } from '../dist/content/media-storage.js';
|
||||
import { ContentError, ContentRepository } from '../dist/content/content-repository.js';
|
||||
|
||||
@@ -47,4 +49,65 @@ await assert.rejects(
|
||||
(error) => error instanceof ContentError && error.code === 'PLATFORM_AD_FORBIDDEN'
|
||||
);
|
||||
|
||||
console.log('PASS: M03-B image compression, tenant paths and advertisement scope validation are present.');
|
||||
await assert.rejects(
|
||||
() => repository.registerAsset(storeActor, undefined, {
|
||||
storagePath: 'asset.webp', publicUrl: '/asset.webp', mimeType: 'image/webp',
|
||||
byteSize: 100, width: 10, height: 10, checksumSha256: '0'.repeat(64)
|
||||
}),
|
||||
(error) => error instanceof ContentError && error.code === 'GLOBAL_ASSET_FORBIDDEN'
|
||||
);
|
||||
|
||||
const secret = 'test-only-content-management-secret-32';
|
||||
const token = signAccessToken({
|
||||
sub: '21', sid: '5c4d3af8-c63c-4edb-bf95-b84127bb3f6e', tid: '7', aid: '9', rv: 1
|
||||
}, secret, 900);
|
||||
let listedAssetStoreId;
|
||||
let listedDecorationStoreId;
|
||||
let updatedAdvertisement;
|
||||
const app = await buildApp({
|
||||
content: {
|
||||
jwtSecret: secret,
|
||||
authRepository: {
|
||||
async validateSession() {
|
||||
return {
|
||||
id: '5c4d3af8-c63c-4edb-bf95-b84127bb3f6e', tenantId: '7', platformAppId: '9',
|
||||
expiresAt: new Date(Date.now() + 60000),
|
||||
user: { id: '21', tenantId: '7', userType: 'STAFF', status: 'ACTIVE', roleVersion: 1,
|
||||
nickname: '', avatarUrl: '', phone: '' }
|
||||
};
|
||||
}
|
||||
},
|
||||
accessControl: { async getAccessProfile() { return storeActor.access; } },
|
||||
mediaStorage: { async storeImage() { throw new Error('not used'); } },
|
||||
repository: {
|
||||
async listAssets(_actor, storeId) { listedAssetStoreId = storeId; return [{ id: '31' }]; },
|
||||
async listDecorations(_actor, storeId) { listedDecorationStoreId = storeId; return [{ id: '41' }]; },
|
||||
async updateAdvertisement(_actor, id, input) { updatedAdvertisement = { id, input }; return { advertisementId: id }; },
|
||||
async listAdvertisements() { return []; },
|
||||
async registerAsset() {}, async saveDecoration() {}, async publishDecoration() {},
|
||||
async saveAdvertisement() {}
|
||||
}
|
||||
}
|
||||
});
|
||||
const authorization = { authorization: `Bearer ${token}` };
|
||||
const assets = await app.inject({ method: 'GET', url: '/admin-api/media/images?storeId=11', headers: authorization });
|
||||
assert.equal(assets.statusCode, 200);
|
||||
assert.equal(listedAssetStoreId, '11');
|
||||
const decorations = await app.inject({ method: 'GET', url: '/admin-api/decorations?storeId=11', headers: authorization });
|
||||
assert.equal(decorations.statusCode, 200);
|
||||
assert.equal(listedDecorationStoreId, '11');
|
||||
const updated = await app.inject({
|
||||
method: 'PUT', url: '/admin-api/advertisements/51', headers: authorization,
|
||||
payload: {
|
||||
scopeType: 'STORE', storeId: '11', title: '门店轮播', imageAssetId: '31',
|
||||
targetType: 'PAGE', targetValue: '/pages/booking/index', status: 'ACTIVE', sortOrder: 10
|
||||
}
|
||||
});
|
||||
assert.equal(updated.statusCode, 200);
|
||||
assert.equal(updatedAdvertisement.id, '51');
|
||||
assert.equal(updatedAdvertisement.input.storeId, '11');
|
||||
const missingStore = await app.inject({ method: 'GET', url: '/admin-api/decorations', headers: authorization });
|
||||
assert.equal(missingStore.statusCode, 400);
|
||||
await app.close();
|
||||
|
||||
console.log('PASS: content media, decoration and advertisement management contracts are scoped and editable.');
|
||||
|
||||
Reference in New Issue
Block a user