meteor3: Comments methods and mail fan-out to async
comments.insert/edit/remove/like/dislike use *Async collection APIs; requireOwner/toggle helpers are async; onCommentAdd iterates users with forEachAsync. subscriptions.* methods were already async. REST smoke stays byte-identical (12/12).
This commit is contained in:
parent
feaf66fe34
commit
66bab7a43b
3 changed files with 25 additions and 20 deletions
|
|
@ -236,6 +236,11 @@ MONGO_CONTAINER=tcef-mongo7 MONGO_SHELL=mongosh MONGO_PORT=27019 ./smoke/smoke.s
|
|||
- Note: the module-level `new Counter(...)` (natestrauser:publish-performant-counts)
|
||||
behind `falsePositivesTotal` boots fine; the publication itself is unused by
|
||||
the current UI — watch it if re-enabled.
|
||||
- ✅ **Comments methods → async** (`comments.insert/edit/remove/like/dislike`):
|
||||
`findOne/insert/update/remove` → `*Async`, helpers (`requireOwner`, `toggle`)
|
||||
async, `users.findOneAsync` for the username. `onCommentAdd` mail fan-out:
|
||||
`users.find().forEach` → `forEachAsync`. Still fire-and-forget from the
|
||||
insert. Comments UI staging verification pending (pre-existing note below).
|
||||
|
||||
### Still TODO before the web (not just REST) is fully deployable on 3.x
|
||||
- **React 16 → 18** render root + verify ancient react-* libs.
|
||||
|
|
|
|||
|
|
@ -14,27 +14,27 @@ function usernameOf(user) {
|
|||
: '';
|
||||
}
|
||||
|
||||
function requireOwner(commentId, userId) {
|
||||
const comment = Comments.findOne(commentId);
|
||||
async function requireOwner(commentId, userId) {
|
||||
const comment = await Comments.findOneAsync(commentId);
|
||||
if (!comment) throw new Meteor.Error('404', 'Comment not found');
|
||||
if (comment.userId !== userId) throw new Meteor.Error('403', 'Not your comment');
|
||||
return comment;
|
||||
}
|
||||
|
||||
function toggle(commentId, field, otherField, userId) {
|
||||
async function toggle(commentId, field, otherField, userId) {
|
||||
check(commentId, String);
|
||||
if (!userId) throw new Meteor.Error('403', 'Login required');
|
||||
const comment = Comments.findOne(commentId);
|
||||
const comment = await Comments.findOneAsync(commentId);
|
||||
if (!comment) throw new Meteor.Error('404', 'Comment not found');
|
||||
const has = (comment[field] || []).includes(userId);
|
||||
const modifier = has
|
||||
? { $pull: { [field]: userId } }
|
||||
: { $addToSet: { [field]: userId }, $pull: { [otherField]: userId } };
|
||||
Comments.update(commentId, modifier);
|
||||
await Comments.updateAsync(commentId, modifier);
|
||||
}
|
||||
|
||||
Meteor.methods({
|
||||
'comments.insert': function commentsInsert(referenceId, content) {
|
||||
'comments.insert': async function commentsInsert(referenceId, content) {
|
||||
check(referenceId, String);
|
||||
check(content, String);
|
||||
if (!this.userId) throw new Meteor.Error('403', 'Login required to comment');
|
||||
|
|
@ -47,7 +47,7 @@ Meteor.methods({
|
|||
referenceId,
|
||||
content: text,
|
||||
userId: this.userId,
|
||||
username: usernameOf(Meteor.users.findOne(this.userId)),
|
||||
username: usernameOf(await Meteor.users.findOneAsync(this.userId)),
|
||||
media: getMediaFromContent(text),
|
||||
likes: [],
|
||||
dislikes: [],
|
||||
|
|
@ -55,7 +55,7 @@ Meteor.methods({
|
|||
createdAt: now,
|
||||
updatedAt: now
|
||||
};
|
||||
const _id = Comments.insert(doc);
|
||||
const _id = await Comments.insertAsync(doc);
|
||||
// Fire-and-forget: notify other commenters of this fire. Never let a mail
|
||||
// failure break the insert.
|
||||
try {
|
||||
|
|
@ -66,32 +66,32 @@ Meteor.methods({
|
|||
return _id;
|
||||
},
|
||||
|
||||
'comments.edit': function commentsEdit(commentId, content) {
|
||||
'comments.edit': async function commentsEdit(commentId, content) {
|
||||
check(commentId, String);
|
||||
check(content, String);
|
||||
if (!this.userId) throw new Meteor.Error('403', 'Login required');
|
||||
requireOwner(commentId, this.userId);
|
||||
await requireOwner(commentId, this.userId);
|
||||
const text = content.trim();
|
||||
if (!text) throw new Meteor.Error('400', 'Empty comment');
|
||||
if (text.length > MAX_LEN) throw new Meteor.Error('400', 'Comment too long');
|
||||
Comments.update(commentId, {
|
||||
await Comments.updateAsync(commentId, {
|
||||
$set: { content: text, media: getMediaFromContent(text), updatedAt: new Date() }
|
||||
});
|
||||
},
|
||||
|
||||
'comments.remove': function commentsRemove(commentId) {
|
||||
'comments.remove': async function commentsRemove(commentId) {
|
||||
check(commentId, String);
|
||||
if (!this.userId) throw new Meteor.Error('403', 'Login required');
|
||||
requireOwner(commentId, this.userId);
|
||||
Comments.remove(commentId);
|
||||
await requireOwner(commentId, this.userId);
|
||||
await Comments.removeAsync(commentId);
|
||||
},
|
||||
|
||||
'comments.like': function commentsLike(commentId) {
|
||||
toggle(commentId, 'likes', 'dislikes', this.userId);
|
||||
'comments.like': async function commentsLike(commentId) {
|
||||
await toggle(commentId, 'likes', 'dislikes', this.userId);
|
||||
},
|
||||
|
||||
'comments.dislike': function commentsDislike(commentId) {
|
||||
toggle(commentId, 'dislikes', 'likes', this.userId);
|
||||
'comments.dislike': async function commentsDislike(commentId) {
|
||||
await toggle(commentId, 'dislikes', 'likes', this.userId);
|
||||
}
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -14,10 +14,10 @@ export default function onCommentAdd(payload) {
|
|||
const { referenceId, userId } = payload;
|
||||
const query = { referenceId, userId: { $ne: userId } };
|
||||
|
||||
Comments.rawCollection().distinct('userId', query).then((users) => {
|
||||
Comments.rawCollection().distinct('userId', query).then(async (users) => {
|
||||
const path = referenceId.replace(/fire-/, 'fire/archive/');
|
||||
const fireUrl = Meteor.absoluteUrl(path);
|
||||
Meteor.users.find({ _id: { $in: users } }).forEach((user) => {
|
||||
await Meteor.users.find({ _id: { $in: users } }).forEachAsync((user) => {
|
||||
const { firstName, emailAddress } = getEmailOf(user);
|
||||
if (emailAddress) {
|
||||
const emailOpts = {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue