diff --git a/UPGRADE.md b/UPGRADE.md index bad25c8..d70d0d3 100644 --- a/UPGRADE.md +++ b/UPGRADE.md @@ -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. diff --git a/imports/api/Comments/server/methods.js b/imports/api/Comments/server/methods.js index 49ea3f0..fd491cd 100644 --- a/imports/api/Comments/server/methods.js +++ b/imports/api/Comments/server/methods.js @@ -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); } }); diff --git a/imports/api/Comments/server/onCommentAdd.js b/imports/api/Comments/server/onCommentAdd.js index f0349c8..d747707 100644 --- a/imports/api/Comments/server/onCommentAdd.js +++ b/imports/api/Comments/server/onCommentAdd.js @@ -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 = {