first commit
This commit is contained in:
147
src/modules/likes/likes.service.ts
Normal file
147
src/modules/likes/likes.service.ts
Normal file
@@ -0,0 +1,147 @@
|
||||
import {
|
||||
BadRequestException,
|
||||
Injectable,
|
||||
} from '@nestjs/common';
|
||||
import { and, eq, or } from 'drizzle-orm';
|
||||
import { DrizzleService } from '../../database/drizzle.service';
|
||||
import { like, match, user } from '../../database/schema';
|
||||
import { NotificationsService } from '../../notifications/notifications.service';
|
||||
import { RedisService } from '../../redis/redis.service';
|
||||
import { ConfigService } from '@nestjs/config';
|
||||
import { CreateLikeDto } from './dto/create-like.dto';
|
||||
|
||||
@Injectable()
|
||||
export class LikesService {
|
||||
constructor(
|
||||
private readonly drizzleService: DrizzleService,
|
||||
private readonly notificationsService: NotificationsService,
|
||||
private readonly redisService: RedisService,
|
||||
private readonly configService: ConfigService,
|
||||
) {}
|
||||
|
||||
async createLike(sourceUserId: string, dto: CreateLikeDto) {
|
||||
if (sourceUserId === dto.targetUserId) {
|
||||
throw new BadRequestException('Cannot like yourself');
|
||||
}
|
||||
|
||||
const maxMatches = this.configService.get<number>('app.maxMatchesBeforePause');
|
||||
const activeMatchesCount = await this.getActiveMatchesCount(sourceUserId);
|
||||
if (activeMatchesCount >= maxMatches) {
|
||||
throw new BadRequestException(
|
||||
`You have ${activeMatchesCount} matches. Resolve them before searching for new ones.`,
|
||||
);
|
||||
}
|
||||
|
||||
const existing = await this.drizzleService.db
|
||||
.select()
|
||||
.from(like)
|
||||
.where(
|
||||
and(
|
||||
eq(like.sourceUser, sourceUserId),
|
||||
eq(like.targetUser, dto.targetUserId),
|
||||
),
|
||||
)
|
||||
.limit(1);
|
||||
|
||||
if (existing.length > 0) {
|
||||
throw new BadRequestException('Already reacted to this user');
|
||||
}
|
||||
|
||||
const [newLike] = await this.drizzleService.db
|
||||
.insert(like)
|
||||
.values({
|
||||
sourceUser: sourceUserId,
|
||||
targetUser: dto.targetUserId,
|
||||
type: dto.type,
|
||||
})
|
||||
.returning();
|
||||
|
||||
if (dto.type === 'like') {
|
||||
return this.checkAndCreateMatch(sourceUserId, dto.targetUserId, newLike);
|
||||
}
|
||||
|
||||
return { like: newLike, match: null };
|
||||
}
|
||||
|
||||
private async checkAndCreateMatch(userId1: string, userId2: string, newLike: any) {
|
||||
const reverseLike = await this.drizzleService.db
|
||||
.select()
|
||||
.from(like)
|
||||
.where(
|
||||
and(
|
||||
eq(like.sourceUser, userId2),
|
||||
eq(like.targetUser, userId1),
|
||||
eq(like.type, 'like'),
|
||||
),
|
||||
)
|
||||
.limit(1);
|
||||
|
||||
if (reverseLike.length === 0) {
|
||||
return { like: newLike, match: null };
|
||||
}
|
||||
|
||||
const existingMatch = await this.drizzleService.db
|
||||
.select()
|
||||
.from(match)
|
||||
.where(
|
||||
or(
|
||||
and(eq(match.user1Id, userId1), eq(match.user2Id, userId2)),
|
||||
and(eq(match.user1Id, userId2), eq(match.user2Id, userId1)),
|
||||
),
|
||||
)
|
||||
.limit(1);
|
||||
|
||||
if (existingMatch.length > 0) {
|
||||
return { like: newLike, match: existingMatch[0] };
|
||||
}
|
||||
|
||||
const [newMatch] = await this.drizzleService.db
|
||||
.insert(match)
|
||||
.values({ user1Id: userId1, user2Id: userId2 })
|
||||
.returning();
|
||||
|
||||
await this.notifyMatch(userId1, userId2, newMatch.id);
|
||||
|
||||
return { like: newLike, match: newMatch };
|
||||
}
|
||||
|
||||
private async getActiveMatchesCount(userId: string): Promise<number> {
|
||||
const matches = await this.drizzleService.db
|
||||
.select({ id: match.id })
|
||||
.from(match)
|
||||
.where(
|
||||
or(eq(match.user1Id, userId), eq(match.user2Id, userId)),
|
||||
);
|
||||
return matches.length;
|
||||
}
|
||||
|
||||
private async notifyMatch(userId1: string, userId2: string, matchId: string) {
|
||||
const users = await this.drizzleService.db
|
||||
.select({ id: user.id, fcmToken: user.fcmToken })
|
||||
.from(user)
|
||||
.where(or(eq(user.id, userId1), eq(user.id, userId2)));
|
||||
|
||||
for (const u of users) {
|
||||
if (u.fcmToken) {
|
||||
await this.notificationsService.sendPushNotification(
|
||||
u.fcmToken,
|
||||
'New Match!',
|
||||
'You have a new match! Start chatting now.',
|
||||
{ matchId, type: 'match' },
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
await this.redisService.publish('match:created', JSON.stringify({ matchId, userId1, userId2 }));
|
||||
}
|
||||
|
||||
async getMyMatches(userId: string) {
|
||||
return this.drizzleService.db
|
||||
.select()
|
||||
.from(match)
|
||||
.where(
|
||||
or(eq(match.user1Id, userId), eq(match.user2Id, userId)),
|
||||
)
|
||||
.orderBy(match.createdAt);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user