Add Instagram-style social features and Postman collections

هذا الالتزام موجود في:
boutmoun123
2026-05-24 15:21:03 +03:00
الأصل fdc40192f7
التزام 367fce6557
56 ملفات معدلة مع 20266 إضافات و5965 حذوفات

عرض الملف

@@ -7,6 +7,7 @@ import { decodeOffsetCursor, encodeOffsetCursor } from '../../common/utils/curso
import { buildPaginatedResponse } from '../../common/utils/pagination.util';
import { AppCacheService } from '../../infrastructure/cache/app-cache.service';
import { FeedVersionService } from '../../infrastructure/cache/feed-version.service';
import { BlocksService } from '../blocks/blocks.service';
import { FollowsService } from '../follows/follows.service';
import { LikesRepository } from '../likes/likes.repository';
import { MarketplaceService } from '../marketplace/marketplace.service';
@@ -66,6 +67,7 @@ export class FeedService {
private readonly savesRepository: SavesRepository,
private readonly followsService: FollowsService,
private readonly marketplaceService: MarketplaceService,
private readonly blocksService: BlocksService,
) {}
async getMyFeed(currentUserId: string, query: FeedQueryDto) {
@@ -104,8 +106,11 @@ export class FeedService {
const radiusKm = query.radiusKm ?? 30;
const skip = cursorOffset ?? (page - 1) * limit;
const followingIds = await this.feedRepository.findFollowingIds(currentUserId);
let filter = this.buildVisiblePostsFilter(currentUserId, followingIds, followingOnly);
const [followingIds, invisibleUserIds] = await Promise.all([
this.feedRepository.findFollowingIds(currentUserId),
this.blocksService.getInvisibleUserIds(currentUserId),
]);
let filter = this.buildVisiblePostsFilter(currentUserId, followingIds, followingOnly, invisibleUserIds);
let candidates = await this.feedRepository.findCandidatePosts(filter, Math.max(limit * 12, 300));
// Keep the default home feed focused on followed accounts, but avoid an empty screen
@@ -115,7 +120,7 @@ export class FeedService {
typeof query.followingOnly === 'undefined' &&
followingOnly
) {
filter = this.buildVisiblePostsFilter(currentUserId, followingIds, false);
filter = this.buildVisiblePostsFilter(currentUserId, followingIds, false, invisibleUserIds);
candidates = await this.feedRepository.findCandidatePosts(filter, Math.max(limit * 12, 300));
}
@@ -177,6 +182,14 @@ export class FeedService {
return result;
}
async getExplore(currentUserId: string, query: FeedQueryDto) {
return this.getTrending(currentUserId, {
...query,
followingOnly: false,
includeSuggestions: false,
});
}
async getTrending(currentUserId: string, query: FeedQueryDto) {
const cacheEnabled =
this.configService.get<boolean>('feedCache.enabled', { infer: true }) ?? true;
@@ -200,8 +213,14 @@ export class FeedService {
const cursorOffset = decodeOffsetCursor(query.cursor);
const page = query.page ?? 1;
const skip = cursorOffset ?? (page - 1) * limit;
const followingIds = await this.feedRepository.findFollowingIds(currentUserId);
const [followingIds, invisibleUserIds] = await Promise.all([
this.feedRepository.findFollowingIds(currentUserId),
this.blocksService.getInvisibleUserIds(currentUserId),
]);
const trendingFilter: Record<string, unknown> = { visibility: PostVisibility.PUBLIC };
if (invisibleUserIds.length) {
trendingFilter.authorId = { $nin: invisibleUserIds.map((id) => new Types.ObjectId(id)) };
}
if (query.preferredPostType) {
trendingFilter.postType = query.preferredPostType;
}
@@ -377,12 +396,13 @@ export class FeedService {
currentUserId: string,
followingIds: string[],
followingOnly: boolean,
invisibleUserIds: string[] = [],
): Record<string, unknown> {
const currentUserObjectId = new Types.ObjectId(currentUserId);
const followingObjectIds = followingIds.map((id) => new Types.ObjectId(id));
if (followingOnly) {
return {
const visibilityFilter = followingOnly
? {
$or: [
{ authorId: currentUserObjectId },
{
@@ -390,10 +410,8 @@ export class FeedService {
visibility: { $in: [PostVisibility.PUBLIC, PostVisibility.FOLLOWERS] },
},
],
};
}
return {
}
: {
$or: [
{ visibility: PostVisibility.PUBLIC },
{ authorId: currentUserObjectId },
@@ -403,6 +421,17 @@ export class FeedService {
},
],
};
if (!invisibleUserIds.length) {
return visibilityFilter;
}
return {
$and: [
visibilityFilter,
{ authorId: { $nin: invisibleUserIds.map((id) => new Types.ObjectId(id)) } },
],
};
}
private scorePost(input: {