Add Instagram-style social features and Postman collections
هذا الالتزام موجود في:
@@ -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: {
|
||||
|
||||
المرجع في مشكلة جديدة
حظر مستخدم