On a ticket, «Recordármelo» offers in an hour, this evening, tomorrow or
next Monday at 9, in a week, or any date and time, with an optional note.
The ticket shows the waiting one («Te lo recordaré el mié 21 a las 9:00»)
to change or drop. Every minute a scheduler tells the ones whose time
came as a REMINDER notification (bell, push, e-mail), once, and forgets
those whose ticket went to the trash or out of reach. One per person and
ticket, private, no history (Mongo `issue_reminders`).
API: setReminder / clearReminder, Issue.myReminder, myReminders;
PUT/DELETE /api/issues/{issue}/reminder, GET /api/me/reminders. MCP:
remind_me.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
64 lines
1.8 KiB
TypeScript
64 lines
1.8 KiB
TypeScript
import { Injectable } from '@nestjs/common';
|
|
import { InjectModel } from '@nestjs/mongoose';
|
|
import {
|
|
IssueReminder,
|
|
IssueRemindersRepository,
|
|
} from '@task-stream/api/tracker/application';
|
|
import { Model } from 'mongoose';
|
|
import { ReadModels } from './read-model.schemas';
|
|
|
|
type Stored = IssueReminder & { _id?: unknown };
|
|
|
|
const strip = ({ _id: _ignored, ...reminder }: Stored): IssueReminder =>
|
|
reminder;
|
|
|
|
@Injectable()
|
|
export class MongoIssueRemindersRepository extends IssueRemindersRepository {
|
|
constructor(
|
|
@InjectModel(ReadModels.IssueReminder)
|
|
private readonly reminders: Model<Stored>,
|
|
) {
|
|
super();
|
|
}
|
|
|
|
async save(reminder: IssueReminder): Promise<void> {
|
|
await this.remove(reminder.userId, reminder.issueId);
|
|
await this.reminders.create(reminder);
|
|
}
|
|
|
|
async waitingFor(
|
|
userId: string,
|
|
issueId: string,
|
|
): Promise<IssueReminder | null> {
|
|
const doc = await this.reminders
|
|
.findOne({ userId, issueId, sentAt: null })
|
|
.lean<Stored>();
|
|
return doc ? strip(doc) : null;
|
|
}
|
|
|
|
async waitingOf(userId: string): Promise<IssueReminder[]> {
|
|
const docs = await this.reminders
|
|
.find({ userId, sentAt: null })
|
|
.sort({ at: 1 })
|
|
.lean<Stored[]>();
|
|
return docs.map(strip);
|
|
}
|
|
|
|
async remove(userId: string, issueId: string): Promise<void> {
|
|
await this.reminders.deleteMany({ userId, issueId, sentAt: null });
|
|
}
|
|
|
|
async due(now: string, limit: number): Promise<IssueReminder[]> {
|
|
const docs = await this.reminders
|
|
.find({ sentAt: null, at: { $lte: now } })
|
|
.sort({ at: 1 })
|
|
.limit(limit)
|
|
.lean<Stored[]>();
|
|
return docs.map(strip);
|
|
}
|
|
|
|
async markSent(id: string, at: string): Promise<void> {
|
|
await this.reminders.updateOne({ id }, { $set: { sentAt: at } });
|
|
}
|
|
}
|