You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
181 lines
5.9 KiB
181 lines
5.9 KiB
import { HttpException, HttpStatus, Injectable } from '@nestjs/common'
|
|
import { InjectModel } from '@nestjs/mongoose'
|
|
import { User, UserDocument } from './schemas/user.schema'
|
|
import { Model } from 'mongoose'
|
|
import { Cron, CronExpression } from '@nestjs/schedule'
|
|
import { MailService } from '../mail/mail.service'
|
|
import { BillingService } from '../billing/billing.service'
|
|
import { Device, DeviceDocument } from '../gateway/schemas/device.schema'
|
|
|
|
@Injectable()
|
|
export class UsersService {
|
|
constructor(
|
|
@InjectModel(User.name) private userModel: Model<UserDocument>,
|
|
@InjectModel(Device.name) private deviceModel: Model<DeviceDocument>,
|
|
private mailService: MailService,
|
|
private billingService: BillingService,
|
|
) {}
|
|
|
|
async findOne(params) {
|
|
return await this.userModel.findOne(params)
|
|
}
|
|
|
|
async findAll() {
|
|
return await this.userModel.find()
|
|
}
|
|
|
|
async create({
|
|
name,
|
|
email,
|
|
password,
|
|
phone,
|
|
}: {
|
|
name: string
|
|
email: string
|
|
password?: string
|
|
phone?: string
|
|
}) {
|
|
if (await this.findOne({ email })) {
|
|
throw new HttpException(
|
|
{
|
|
error: 'user exists with the same email',
|
|
},
|
|
HttpStatus.BAD_REQUEST,
|
|
)
|
|
}
|
|
|
|
const newUser = new this.userModel({
|
|
name,
|
|
email,
|
|
password,
|
|
phone,
|
|
})
|
|
return await newUser.save()
|
|
}
|
|
|
|
async updateProfile(
|
|
input: { name: string; phone: string },
|
|
user: UserDocument,
|
|
) {
|
|
const userToUpdate = await this.findOne({ _id: user._id })
|
|
if (!userToUpdate) {
|
|
throw new HttpException({ error: 'User not found' }, HttpStatus.NOT_FOUND)
|
|
}
|
|
|
|
if (input.name) {
|
|
userToUpdate.name = input.name
|
|
}
|
|
if (input.phone) {
|
|
userToUpdate.phone = input.phone
|
|
}
|
|
|
|
return await userToUpdate.save()
|
|
}
|
|
|
|
@Cron('0 12 * * *') // Every day at 12 PM
|
|
async sendEmailToInactiveNewUsers() {
|
|
try {
|
|
// Get users who signed up between 3-4 days ago (not 1-2 days)
|
|
const fourDaysAgo = new Date(Date.now() - 4 * 24 * 60 * 60 * 1000)
|
|
const threeDaysAgo = new Date(Date.now() - 3 * 24 * 60 * 60 * 1000)
|
|
|
|
const newUsers = await this.userModel.find({
|
|
createdAt: {
|
|
$gte: fourDaysAgo,
|
|
$lt: threeDaysAgo,
|
|
},
|
|
})
|
|
|
|
for (const user of newUsers) {
|
|
try {
|
|
// Check if user has any devices registered or has sent/received any SMS
|
|
const devices = await this.deviceModel.find({ user: user._id })
|
|
|
|
if (devices.length === 0 || devices.map(device=>device.sentSMSCount + device.receivedSMSCount).reduce((a,b)=>a+b,0) == 0) {
|
|
// User hasn't registered any device, send email
|
|
await this.mailService.sendEmailFromTemplate({
|
|
to: user.email,
|
|
subject:
|
|
'Getting Started with textbee.dev - How Can We Help?',
|
|
template: 'inactive-new-user',
|
|
context: {
|
|
name: user.name,
|
|
registerDeviceUrl: `${process.env.FRONTEND_URL}/dashboard`,
|
|
},
|
|
})
|
|
console.log(`Sent inactive new user email to ${user.email}`)
|
|
}
|
|
// Wait 200ms before processing the next user
|
|
await new Promise((resolve) => setTimeout(resolve, 200))
|
|
} catch (error) {
|
|
console.error(`Error processing email for user ${user.email}:`, error)
|
|
}
|
|
}
|
|
} catch (error) {
|
|
console.error('Error sending emails to inactive new users:', error)
|
|
}
|
|
}
|
|
|
|
@Cron('0 13 * * *') // Every day at 1 PM
|
|
async sendEmailToFreeUsers() {
|
|
try {
|
|
// Get users who signed up between 13-14 days ago
|
|
const fourteenDaysAgo = new Date(Date.now() - 14 * 24 * 60 * 60 * 1000)
|
|
const thirteenDaysAgo = new Date(Date.now() - 13 * 24 * 60 * 60 * 1000)
|
|
|
|
const usersToEmail = await this.userModel.find({
|
|
createdAt: {
|
|
$gte: fourteenDaysAgo,
|
|
$lt: thirteenDaysAgo,
|
|
},
|
|
})
|
|
|
|
for (const user of usersToEmail) {
|
|
try {
|
|
const subscription = await this.billingService.getActiveSubscription(
|
|
user._id.toString(),
|
|
)
|
|
|
|
if (subscription?.plan?.name === 'free') {
|
|
const devices = await this.deviceModel.find({ user: user._id })
|
|
|
|
if (devices.length === 0 || devices.map(device=>device.sentSMSCount + device.receivedSMSCount).reduce((a,b)=>a+b,0) == 0) {
|
|
// Only send this if they haven't set up any devices after 10-14 days
|
|
await this.mailService.sendEmailFromTemplate({
|
|
to: user.email,
|
|
subject: `${user.name?.split(' ')[0]}, we'd love to help you get started with textbee.dev`,
|
|
template: 'inactive-new-user-day-10',
|
|
context: {
|
|
name: user.name,
|
|
registerDeviceUrl: `${process.env.FRONTEND_URL}/dashboard`,
|
|
},
|
|
})
|
|
|
|
console.log(`Sent inactive new user email to ${user.email}`)
|
|
} else {
|
|
// Only send upgrade email to active users who have at least one device
|
|
await this.mailService.sendEmailFromTemplate({
|
|
to: user.email,
|
|
subject: `${user.name?.split(' ')[0]}, unlock more capabilities with textbee.dev Pro`,
|
|
template: 'upgrade-to-pro',
|
|
context: {
|
|
name: user.name,
|
|
upgradeUrl: `${process.env.FRONTEND_URL}/checkout/pro`,
|
|
deviceCount: devices.length,
|
|
},
|
|
})
|
|
console.log(`Sent upgrade to pro email to ${user.email}`)
|
|
}
|
|
}
|
|
|
|
// Wait 200ms before processing the next user
|
|
await new Promise((resolve) => setTimeout(resolve, 200))
|
|
} catch (error) {
|
|
console.error(`Error processing email for user ${user.email}:`, error)
|
|
}
|
|
}
|
|
} catch (error) {
|
|
console.error('Error sending emails to free plan users:', error)
|
|
}
|
|
}
|
|
}
|