feat: «Recordármelo», a reminder of a ticket only for me
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>
This commit is contained in:
@@ -0,0 +1,63 @@
|
||||
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 } });
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user