Improve collaboration request details response
This commit is contained in:
@@ -3046,7 +3046,10 @@
|
||||
"pm.test('Status is 200 or 201', function () { pm.expect([200, 201]).to.include(pm.response.code); });",
|
||||
"const json = pm.response.json();",
|
||||
"pm.expect(json).to.have.property('request');",
|
||||
"pm.expect(json.request).to.have.property('requester');",
|
||||
"pm.expect(json.request).to.have.property('targetUser');",
|
||||
"pm.environment.set('collaborationRequestId', json.request._id || json.request.id);",
|
||||
"pm.environment.set('requestId', json.request._id || json.request.id);",
|
||||
"pm.test('Rich collaboration fields are accepted', function () {",
|
||||
" pm.expect(json.request).to.have.property('collaborationType');",
|
||||
" pm.expect(json.request).to.have.property('message');",
|
||||
@@ -3104,7 +3107,10 @@
|
||||
"pm.test('Status is 200 or 201', function () { pm.expect([200, 201]).to.include(pm.response.code); });",
|
||||
"const json = pm.response.json();",
|
||||
"pm.expect(json).to.have.property('request');",
|
||||
"pm.expect(json.request).to.have.property('requester');",
|
||||
"pm.expect(json.request).to.have.property('targetUser');",
|
||||
"pm.environment.set('collaborationRequestId', json.request._id || json.request.id);",
|
||||
"pm.environment.set('requestId', json.request._id || json.request.id);",
|
||||
"pm.test('General collaboration request has no post', function () {",
|
||||
" pm.expect(json.request.postId === null || typeof json.request.postId === 'undefined').to.equal(true);",
|
||||
" pm.expect(json.request).to.have.property('status', 'pending');",
|
||||
@@ -3138,6 +3144,7 @@
|
||||
"pm.expect(json).to.have.property('pagination');",
|
||||
"if (json.items.length) {",
|
||||
" pm.environment.set('collaborationRequestId', json.items[0]._id || json.items[0].id);",
|
||||
" pm.environment.set('requestId', json.items[0]._id || json.items[0].id);",
|
||||
" pm.expect(json.items[0]).to.have.property('status');",
|
||||
" pm.expect(json.items[0]).to.have.property('collaborationType');",
|
||||
"}"
|
||||
@@ -3170,10 +3177,15 @@
|
||||
"pm.expect(json).to.have.property('pagination');",
|
||||
"if (json.items.length) {",
|
||||
" pm.environment.set('collaborationRequestId', json.items[0]._id || json.items[0].id);",
|
||||
" pm.environment.set('requestId', json.items[0]._id || json.items[0].id);",
|
||||
" pm.expect(json.items[0]).to.have.property('status');",
|
||||
" pm.expect(json.items[0]).to.have.property('requesterId');",
|
||||
" pm.expect(json.items[0]).to.have.property('targetUserId');",
|
||||
" pm.expect(json.items[0]).to.have.property('postId');",
|
||||
" pm.expect(json.items[0]).to.have.property('requester');",
|
||||
" pm.expect(json.items[0]).to.have.property('targetUser');",
|
||||
" pm.expect(json.items[0].requester).to.have.property('username');",
|
||||
" pm.expect(json.items[0].targetUser).to.have.property('username');",
|
||||
"}"
|
||||
]
|
||||
}
|
||||
@@ -3204,10 +3216,15 @@
|
||||
"pm.expect(json).to.have.property('pagination');",
|
||||
"if (json.items.length) {",
|
||||
" pm.environment.set('collaborationRequestId', json.items[0]._id || json.items[0].id);",
|
||||
" pm.environment.set('requestId', json.items[0]._id || json.items[0].id);",
|
||||
" pm.expect(json.items[0]).to.have.property('status');",
|
||||
" pm.expect(json.items[0]).to.have.property('requesterId');",
|
||||
" pm.expect(json.items[0]).to.have.property('targetUserId');",
|
||||
" pm.expect(json.items[0]).to.have.property('postId');",
|
||||
" pm.expect(json.items[0]).to.have.property('requester');",
|
||||
" pm.expect(json.items[0]).to.have.property('targetUser');",
|
||||
" pm.expect(json.items[0].requester).to.have.property('username');",
|
||||
" pm.expect(json.items[0].targetUser).to.have.property('username');",
|
||||
"}"
|
||||
]
|
||||
}
|
||||
@@ -3235,6 +3252,8 @@
|
||||
"pm.test('Status is 200', function () { pm.response.to.have.status(200); });",
|
||||
"const json = pm.response.json();",
|
||||
"pm.expect(json).to.have.property('request');",
|
||||
"pm.expect(json.request).to.have.property('requester');",
|
||||
"pm.expect(json.request).to.have.property('targetUser');",
|
||||
"pm.expect(json.request).to.have.property('status');",
|
||||
"pm.expect(json.request).to.have.property('requesterId');",
|
||||
"pm.expect(json.request).to.have.property('targetUserId');",
|
||||
@@ -3265,7 +3284,10 @@
|
||||
"pm.test('Status is 200', function () { pm.response.to.have.status(200); });",
|
||||
"const json = pm.response.json();",
|
||||
"pm.expect(json).to.have.property('approved', true);",
|
||||
"pm.expect(json).to.have.property('request');"
|
||||
"pm.expect(json.request).to.have.property('status', 'approved');",
|
||||
"pm.expect(json).to.have.property('request');",
|
||||
"pm.expect(json.request).to.have.property('requester');",
|
||||
"pm.expect(json.request).to.have.property('targetUser');"
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -3292,7 +3314,10 @@
|
||||
"pm.test('Status is 200', function () { pm.response.to.have.status(200); });",
|
||||
"const json = pm.response.json();",
|
||||
"pm.expect(json).to.have.property('rejected', true);",
|
||||
"pm.expect(json).to.have.property('request');"
|
||||
"pm.expect(json.request).to.have.property('status', 'rejected');",
|
||||
"pm.expect(json).to.have.property('request');",
|
||||
"pm.expect(json.request).to.have.property('requester');",
|
||||
"pm.expect(json.request).to.have.property('targetUser');"
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -3320,6 +3345,8 @@
|
||||
"const json = pm.response.json();",
|
||||
"pm.expect(json).to.have.property('cancelled', true);",
|
||||
"pm.expect(json).to.have.property('request');",
|
||||
"pm.expect(json.request).to.have.property('requester');",
|
||||
"pm.expect(json.request).to.have.property('targetUser');",
|
||||
"pm.expect(json.request).to.have.property('status', 'cancelled');"
|
||||
]
|
||||
}
|
||||
|
||||
@@ -10,6 +10,33 @@ const chain = <T>(value: T) => ({
|
||||
exec: jest.fn().mockResolvedValue(value),
|
||||
});
|
||||
|
||||
const createUser = (overrides: Record<string, any> = {}) => {
|
||||
const userId = overrides._id ?? new Types.ObjectId();
|
||||
return {
|
||||
_id: userId,
|
||||
id: userId.toString(),
|
||||
username: overrides.username ?? 'artist',
|
||||
name: overrides.name ?? 'Artist Name',
|
||||
stageName: overrides.stageName ?? 'Stage Artist',
|
||||
avatar: overrides.avatar ?? '/avatar.png',
|
||||
isVerified: overrides.isVerified ?? false,
|
||||
...overrides,
|
||||
};
|
||||
};
|
||||
|
||||
const createPost = (overrides: Record<string, any> = {}) => {
|
||||
const postId = overrides._id ?? new Types.ObjectId();
|
||||
return {
|
||||
_id: postId,
|
||||
id: postId.toString(),
|
||||
content: overrides.content ?? 'Post content',
|
||||
thumbnailUrl: overrides.thumbnailUrl ?? '/thumb.png',
|
||||
media: overrides.media ?? {},
|
||||
authorId: overrides.authorId ?? new Types.ObjectId(),
|
||||
...overrides,
|
||||
};
|
||||
};
|
||||
|
||||
const createRequestDoc = (overrides: Record<string, any> = {}) => {
|
||||
const requestId = overrides._id ?? new Types.ObjectId();
|
||||
return {
|
||||
@@ -116,6 +143,13 @@ describe('CollaborationRequestsService', () => {
|
||||
type: 'collaboration_request',
|
||||
referenceId: postId,
|
||||
deepLink: `/posts/${postId}`,
|
||||
metadata: expect.objectContaining({
|
||||
collaborationRequestId: request.id,
|
||||
requestId: request.id,
|
||||
collaborationType: 'duet',
|
||||
status: 'pending',
|
||||
postId,
|
||||
}),
|
||||
}),
|
||||
);
|
||||
});
|
||||
@@ -321,6 +355,58 @@ describe('CollaborationRequestsService', () => {
|
||||
});
|
||||
});
|
||||
|
||||
it('returns request details with requester, targetUser, and post aliases', async () => {
|
||||
const requesterId = new Types.ObjectId().toString();
|
||||
const targetUserId = new Types.ObjectId().toString();
|
||||
const postId = new Types.ObjectId().toString();
|
||||
const requester = createUser({ _id: new Types.ObjectId(requesterId), username: 'rami' });
|
||||
const targetUser = createUser({ _id: new Types.ObjectId(targetUserId), username: 'sara' });
|
||||
const post = createPost({ _id: new Types.ObjectId(postId), authorId: targetUser._id });
|
||||
const request = createRequestDoc({
|
||||
postId: post,
|
||||
requesterId: requester,
|
||||
targetUserId: targetUser,
|
||||
attachmentUrl: '/uploads/collaboration-requests/audio/file.mp3',
|
||||
attachmentType: 'audio',
|
||||
});
|
||||
const { service, model } = createService();
|
||||
|
||||
model.findOne.mockReturnValue(chain(request));
|
||||
|
||||
const result = await service.getById(requesterId, request.id);
|
||||
|
||||
expect(result.request).toMatchObject({
|
||||
id: request.id,
|
||||
postId,
|
||||
attachmentUrl: '/uploads/collaboration-requests/audio/file.mp3',
|
||||
attachmentType: 'audio',
|
||||
requester: expect.objectContaining({ id: requesterId, username: 'rami' }),
|
||||
targetUser: expect.objectContaining({ id: targetUserId, username: 'sara' }),
|
||||
post: expect.objectContaining({ id: postId, content: 'Post content' }),
|
||||
});
|
||||
});
|
||||
|
||||
it('lists received requests with populated requester and targetUser aliases', async () => {
|
||||
const requesterId = new Types.ObjectId().toString();
|
||||
const targetUserId = new Types.ObjectId().toString();
|
||||
const items = [
|
||||
createRequestDoc({
|
||||
requesterId: createUser({ _id: new Types.ObjectId(requesterId), username: 'rami' }),
|
||||
targetUserId: createUser({ _id: new Types.ObjectId(targetUserId), username: 'sara' }),
|
||||
}),
|
||||
];
|
||||
const { service, model } = createService();
|
||||
|
||||
model.find.mockReturnValue(chain(items));
|
||||
model.countDocuments.mockReturnValue(chain(1));
|
||||
|
||||
const result = await service.listReceived(targetUserId, { page: 1, limit: 20 });
|
||||
|
||||
expect(result.items[0]).toMatchObject({
|
||||
requester: expect.objectContaining({ id: requesterId, username: 'rami' }),
|
||||
targetUser: expect.objectContaining({ id: targetUserId, username: 'sara' }),
|
||||
});
|
||||
});
|
||||
it('approves a pending request, updates post collaborators, and notifies requester', async () => {
|
||||
const targetUserId = new Types.ObjectId().toString();
|
||||
const requesterId = new Types.ObjectId().toString();
|
||||
|
||||
@@ -294,7 +294,10 @@ export class CollaborationRequestsService {
|
||||
this.collaborationRequestModel.countDocuments(filter).exec(),
|
||||
]);
|
||||
|
||||
return buildPaginatedResponse(items, { page, limit, total, offset: skip });
|
||||
return buildPaginatedResponse(
|
||||
items.map((item: CollaborationRequestDocument) => this.serializeRequest(item)),
|
||||
{ page, limit, total, offset: skip },
|
||||
);
|
||||
}
|
||||
|
||||
async approve(targetUserId: string, requestId: string) {
|
||||
@@ -510,7 +513,7 @@ export class CollaborationRequestsService {
|
||||
throw new NotFoundException('Collaboration request not found');
|
||||
}
|
||||
|
||||
return request;
|
||||
return this.serializeRequest(request);
|
||||
}
|
||||
|
||||
private async createCollaborationNotification(options: {
|
||||
@@ -538,6 +541,9 @@ export class CollaborationRequestsService {
|
||||
metadata: {
|
||||
...(options.metadata ?? {}),
|
||||
collaborationRequestId: options.requestId,
|
||||
requestId: options.requestId,
|
||||
status: options.metadata?.status ?? 'pending',
|
||||
postId: options.resourceType === 'post' ? options.referenceId : options.metadata?.postId,
|
||||
},
|
||||
});
|
||||
} catch (error) {
|
||||
@@ -594,4 +600,90 @@ export class CollaborationRequestsService {
|
||||
}
|
||||
return '';
|
||||
}
|
||||
|
||||
private serializeRequest(request: unknown) {
|
||||
const plain = this.toPlainRecord(request);
|
||||
const requester = this.serializeUser(plain.requesterId);
|
||||
const targetUser = this.serializeUser(plain.targetUserId);
|
||||
const post = this.serializePost(plain.postId);
|
||||
const postId = this.extractEntityId(plain.postId) || plain.postId;
|
||||
|
||||
return {
|
||||
...plain,
|
||||
id: this.extractEntityId(plain) || plain.id,
|
||||
requesterId: plain.requesterId,
|
||||
targetUserId: plain.targetUserId,
|
||||
postId,
|
||||
requester,
|
||||
targetUser,
|
||||
post,
|
||||
attachmentUrl: typeof plain.attachmentUrl === 'string' ? plain.attachmentUrl : '',
|
||||
attachmentType: plain.attachmentType ?? null,
|
||||
};
|
||||
}
|
||||
|
||||
private serializeUser(value: unknown) {
|
||||
if (!value) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const plain = this.toPlainRecord(value);
|
||||
const id = this.extractEntityId(plain) || this.extractEntityId(value);
|
||||
|
||||
return {
|
||||
...plain,
|
||||
_id: plain._id ?? id,
|
||||
id,
|
||||
username: plain.username ?? '',
|
||||
name: plain.name ?? '',
|
||||
stageName: plain.stageName ?? '',
|
||||
avatar: plain.avatar ?? '',
|
||||
isVerified: Boolean(plain.isVerified),
|
||||
};
|
||||
}
|
||||
|
||||
private serializePost(value: unknown) {
|
||||
if (!value) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const plain = this.toPlainRecord(value);
|
||||
const id = this.extractEntityId(plain) || this.extractEntityId(value);
|
||||
|
||||
return {
|
||||
...plain,
|
||||
_id: plain._id ?? id,
|
||||
id,
|
||||
};
|
||||
}
|
||||
|
||||
private toPlainRecord(value: unknown): Record<string, any> {
|
||||
if (!value) {
|
||||
return {};
|
||||
}
|
||||
|
||||
if (typeof value === 'string' || value instanceof Types.ObjectId) {
|
||||
const id = this.extractEntityId(value);
|
||||
return { _id: id, id };
|
||||
}
|
||||
|
||||
if (typeof value === 'object') {
|
||||
const maybeDocument = value as { toJSON?: () => unknown; toObject?: () => unknown };
|
||||
if (typeof maybeDocument.toJSON === 'function') {
|
||||
const json = maybeDocument.toJSON();
|
||||
if (json && typeof json === 'object') {
|
||||
return json as Record<string, any>;
|
||||
}
|
||||
}
|
||||
if (typeof maybeDocument.toObject === 'function') {
|
||||
const object = maybeDocument.toObject();
|
||||
if (object && typeof object === 'object') {
|
||||
return object as Record<string, any>;
|
||||
}
|
||||
}
|
||||
return { ...(value as Record<string, any>) };
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user