hexabot/api/src/chat/repositories/subscriber.repository.ts

198 lines
5.6 KiB
TypeScript
Raw Normal View History

2024-09-10 09:50:11 +00:00
/*
* Copyright © 2024 Hexastack. All rights reserved.
*
* Licensed under the GNU Affero General Public License v3.0 (AGPLv3) with the following additional terms:
* 1. The name "Hexabot" is a trademark of Hexastack. You may not use this name in derivative works without express written permission.
* 2. All derivative works must include clear attribution to the original creator and software, Hexastack and Hexabot, in a prominent location (e.g., in the software's "About" section, documentation, and README file).
*/
import { Injectable } from '@nestjs/common';
import { EventEmitter2 } from '@nestjs/event-emitter';
import { InjectModel } from '@nestjs/mongoose';
import {
Document,
Model,
Query,
UpdateQuery,
UpdateWithAggregationPipeline,
} from 'mongoose';
import { BaseRepository } from '@/utils/generics/base-repository';
2024-10-29 13:36:46 +00:00
import { TFilterQuery } from '@/utils/types/filter.types';
2024-09-10 09:50:11 +00:00
import { SubscriberUpdateDto } from '../dto/subscriber.dto';
import {
Subscriber,
2024-09-21 18:43:04 +00:00
SUBSCRIBER_POPULATE,
2024-10-05 11:15:50 +00:00
SubscriberDocument,
2024-09-10 09:50:11 +00:00
SubscriberFull,
2024-09-21 11:15:36 +00:00
SubscriberPopulate,
2024-09-10 09:50:11 +00:00
} from '../schemas/subscriber.schema';
@Injectable()
export class SubscriberRepository extends BaseRepository<
Subscriber,
2024-09-21 11:15:36 +00:00
SubscriberPopulate,
SubscriberFull
2024-09-10 09:50:11 +00:00
> {
constructor(
2024-10-04 16:42:10 +00:00
readonly eventEmitter: EventEmitter2,
2024-10-05 11:15:50 +00:00
@InjectModel(Subscriber.name) readonly model: Model<Subscriber>,
2024-09-10 09:50:11 +00:00
) {
2024-10-05 11:15:50 +00:00
super(eventEmitter, model, Subscriber, SUBSCRIBER_POPULATE, SubscriberFull);
}
/**
* Emits events related to the creation of a new subscriber.
*
* @param created - The newly created subscriber document.
*/
async postCreate(created: SubscriberDocument): Promise<void> {
this.eventEmitter.emit(
'hook:stats:entry',
'new_users',
'New users',
created,
);
2024-09-10 09:50:11 +00:00
}
/**
* Emits events before updating a subscriber. Specifically handles the
* assignment of the subscriber and triggers appropriate events.
*
* @param _query - The Mongoose query object for finding and updating a subscriber.
* @param criteria - The filter criteria used to find the subscriber.
* @param updates - The update data, which may include fields like `assignedTo`.
*/
async preUpdate(
_query: Query<
Document<Subscriber, any, any>,
Document<Subscriber, any, any>,
unknown,
Subscriber,
'findOneAndUpdate'
>,
criteria: TFilterQuery<Subscriber>,
updates:
| UpdateWithAggregationPipeline
| UpdateQuery<Document<Subscriber, any, any>>,
): Promise<void> {
const subscriberUpdates: SubscriberUpdateDto = updates?.['$set'];
const oldSubscriber = await this.findOne(criteria);
if (subscriberUpdates.assignedTo !== oldSubscriber?.assignedTo) {
this.eventEmitter.emit(
'hook:subscriber:assign',
subscriberUpdates,
oldSubscriber,
);
if (!(subscriberUpdates.assignedTo && oldSubscriber?.assignedTo)) {
this.eventEmitter.emit(
'hook:analytics:passation',
oldSubscriber,
!!subscriberUpdates?.assignedTo,
);
}
}
}
/**
* Constructs a query to find a subscriber by their foreign ID.
*
* @param id - The foreign ID of the subscriber.
*
* @returns The constructed query object.
*/
findByForeignIdQuery(id: string) {
return this.findQuery(
2024-09-10 09:50:11 +00:00
{ foreign_id: id },
{ skip: 0, limit: 1, sort: ['lastvisit', 'desc'] },
);
}
/**
* Finds a single subscriber by his foreign ID (channel's id).
*
* @param id - The foreign ID of the subscriber.
*
* @returns The found subscriber entity.
*/
async findOneByForeignId(id: string): Promise<Subscriber> {
const query = this.findByForeignIdQuery(id);
const [result] = await this.execute(query, Subscriber);
return result;
}
/**
* Finds a subscriber by their foreign ID and populates related fields such as `labels` and `assignedTo`.
*
* @param id - The foreign ID of the subscriber.
*
* @returns The found subscriber entity with populated fields.
*/
async findOneByForeignIdAndPopulate(id: string): Promise<SubscriberFull> {
2024-09-21 11:15:36 +00:00
const query = this.findByForeignIdQuery(id).populate(this.populate);
const [result] = await this.execute(query, this.clsPopulate);
2024-09-10 09:50:11 +00:00
return result;
}
/**
* Updates a subscriber's information based on their foreign ID.
*
* @param id - The foreign ID of the subscriber.
* @param updates - The update data to apply to the subscriber.
*
* @returns The updated subscriber entity.
*/
async updateOneByForeignIdQuery(
id: string,
updates: SubscriberUpdateDto,
): Promise<Subscriber> {
return await this.updateOne({ foreign_id: id }, updates);
}
/**
* Unassigns a subscriber by their foreign ID by setting the `assignedTo` field to `null`.
*
* @param foreignId - The foreign ID of the subscriber.
*
* @returns The updated subscriber entity.
*/
async handBackByForeignIdQuery(foreignId: string): Promise<Subscriber> {
return await this.updateOne(
{
foreign_id: foreignId,
assignedTo: { $ne: null },
},
{
assignedTo: null,
},
);
}
/**
* Assigns a subscriber to a new user by their foreign ID.
*
* @param foreignId The foreign ID of the subscriber.
* @param userId The ID of the user to assign the subscriber to.
*
* @returns The updated subscriber entity.
*/
async handOverByForeignIdQuery(
foreignId: string,
userId: string,
): Promise<Subscriber> {
return await this.updateOne(
{
foreign_id: foreignId,
assignedTo: { $ne: userId },
},
{
assignedTo: userId,
},
);
}
}