diff --git a/book/10-begin/api/server/api/team-leader.ts b/book/10-begin/api/server/api/team-leader.ts index db9eecc5..fabeb733 100644 --- a/book/10-begin/api/server/api/team-leader.ts +++ b/book/10-begin/api/server/api/team-leader.ts @@ -93,11 +93,11 @@ router.post('/stripe/fetch-checkout-session', async (req, res, next) => { try { const { mode, teamId } = req.body; - const user = await User.findById(req.user.id).select(['stripeCustomer', 'email']).lean(); + const user = await User.findById(req.user.id).select(['stripeCustomer', 'email']).setOptions({ lean: true }); const team = await Team.findById(teamId) .select(['stripeSubscription', 'slug', 'teamLeaderId']) - .lean(); + .setOptions({ lean: true }); if (!user || !team || team.teamLeaderId !== req.user.id) { throw new Error('Permission denied'); diff --git a/book/10-begin/api/server/aws-s3.ts b/book/10-begin/api/server/aws-s3.ts index 6d50475b..bf432d48 100644 --- a/book/10-begin/api/server/aws-s3.ts +++ b/book/10-begin/api/server/aws-s3.ts @@ -21,7 +21,7 @@ async function signRequestForUpload({ fileName, fileType, prefix, bucket }) { const s3 = new aws.S3({ apiVersion: 'latest', - region: 'us-east-1', + region: process.env.AWS_REGION, accessKeyId: process.env.AWS_ACCESSKEYID, secretAccessKey: process.env.AWS_SECRETACCESSKEY, }); diff --git a/book/10-begin/api/server/aws-ses.ts b/book/10-begin/api/server/aws-ses.ts index faf399eb..fff1565e 100644 --- a/book/10-begin/api/server/aws-ses.ts +++ b/book/10-begin/api/server/aws-ses.ts @@ -3,7 +3,7 @@ import * as aws from 'aws-sdk'; export default function sendEmail(options) { const ses = new aws.SES({ apiVersion: 'latest', - region: 'us-east-1', + region: process.env.AWS_REGION, accessKeyId: process.env.AWS_ACCESSKEYID, secretAccessKey: process.env.AWS_SECRETACCESSKEY, }); diff --git a/book/10-begin/api/server/models/Discussion.ts b/book/10-begin/api/server/models/Discussion.ts index e9931e9d..a5d8869f 100644 --- a/book/10-begin/api/server/models/Discussion.ts +++ b/book/10-begin/api/server/models/Discussion.ts @@ -24,7 +24,11 @@ const mongoSchema = new mongoose.Schema({ type: String, required: true, }, - memberIds: [String], + memberIds: [ + { + type: String, + }, + ], createdAt: { type: Date, required: true, @@ -104,7 +108,7 @@ class DiscussionClass extends mongoose.Model { const filter: any = { teamId, memberIds: userId }; - const discussions: any[] = await this.find(filter).lean(); + const discussions: any[] = await this.find(filter).setOptions({ lean: true }); return { discussions }; } @@ -134,7 +138,7 @@ class DiscussionClass extends mongoose.Model { throw new Error('Bad data'); } - const discussion = await this.findById(id).select('teamId createdUserId').lean(); + const discussion = await this.findById(id).select('teamId createdUserId').setOptions({ lean: true }); const team = await this.checkPermissionAndGetTeam({ userId, @@ -164,7 +168,7 @@ class DiscussionClass extends mongoose.Model { throw new Error('Bad data'); } - const discussion = await this.findById(id).select('teamId').lean(); + const discussion = await this.findById(id).select('teamId').setOptions({ lean: true }); await this.checkPermissionAndGetTeam({ userId, teamId: discussion.teamId }); @@ -180,7 +184,7 @@ class DiscussionClass extends mongoose.Model { throw new Error('Bad data'); } - const team = await Team.findById(teamId).select('memberIds teamLeaderId').lean(); + const team = await Team.findById(teamId).select('memberIds teamLeaderId').setOptions({ lean: true }); if (!team || team.memberIds.indexOf(userId) === -1) { throw new Error('Team not found'); diff --git a/book/10-begin/api/server/models/EmailTemplate.ts b/book/10-begin/api/server/models/EmailTemplate.ts index 54ca2241..db9089d7 100644 --- a/book/10-begin/api/server/models/EmailTemplate.ts +++ b/book/10-begin/api/server/models/EmailTemplate.ts @@ -74,7 +74,7 @@ export async function insertTemplates() { ]; for (const t of templates) { - const et = await EmailTemplate.findOne({ name: t.name }).lean(); + const et = await EmailTemplate.findOne({ name: t.name }).setOptions({ lean: true }); const message = t.message.replace(/\n/g, '').replace(/[ ]+/g, ' ').trim(); if (!et) { @@ -88,7 +88,7 @@ export async function insertTemplates() { export default async function getEmailTemplate(name: string, params: any) { await insertTemplates(); - const et = await EmailTemplate.findOne({ name }).lean(); + const et = await EmailTemplate.findOne({ name }).setOptions({ lean: true }); if (!et) { throw new Error('Email Template is not found in database.'); diff --git a/book/10-begin/api/server/models/Invitation.ts b/book/10-begin/api/server/models/Invitation.ts index c1d15471..60cd8dcf 100644 --- a/book/10-begin/api/server/models/Invitation.ts +++ b/book/10-begin/api/server/models/Invitation.ts @@ -68,12 +68,12 @@ class InvitationClass extends mongoose.Model { throw new Error('Bad data'); } - const team = await Team.findById(teamId).lean(); + const team = await Team.findById(teamId).setOptions({ lean: true }); if (!team || team.teamLeaderId !== userId) { throw new Error('Team does not exist or you have no permission'); } - const registeredUser = await User.findOne({ email }).select('defaultTeamSlug').lean(); + const registeredUser = await User.findOne({ email }).select('defaultTeamSlug').setOptions({ lean: true }); if (registeredUser) { if (team.memberIds.includes(registeredUser._id.toString())) { @@ -90,7 +90,7 @@ class InvitationClass extends mongoose.Model { } let token; - const invitation = await this.findOne({ teamId, email }).select('token').lean(); + const invitation = await this.findOne({ teamId, email }).select('token').setOptions({ lean: true }); if (invitation) { token = invitation.token; @@ -125,17 +125,17 @@ class InvitationClass extends mongoose.Model { console.log('Email sending error:', err); }); - return await this.findOne({ teamId, email }).lean(); + return await this.findOne({ teamId, email }).setOptions({ lean: true }); } public static async getTeamInvitations({ userId, teamId }) { - const team = await Team.findOne({ _id: teamId }).select('teamLeaderId').lean(); + const team = await Team.findOne({ _id: teamId }).select('teamLeaderId').setOptions({ lean: true }); if (userId !== team.teamLeaderId) { throw new Error('You have no permission.'); } - return this.find({ teamId }).select('email').lean(); + return this.find({ teamId }).select('email').setOptions({ lean: true }); } public static async getTeamByToken({ token }) { @@ -143,7 +143,7 @@ class InvitationClass extends mongoose.Model { throw new Error('Bad data'); } - const invitation = await this.findOne({ token }).lean(); + const invitation = await this.findOne({ token }).setOptions({ lean: true }); if (!invitation) { throw new Error('Invitation not found'); @@ -151,7 +151,7 @@ class InvitationClass extends mongoose.Model { const team = await Team.findById(invitation.teamId) .select('name slug avatarUrl memberIds') - .lean(); + .setOptions({ lean: true }); if (!team) { throw new Error('Team does not exist'); @@ -165,7 +165,7 @@ class InvitationClass extends mongoose.Model { throw new Error('Bad data'); } - const invitation = await this.findOne({ token }).lean(); + const invitation = await this.findOne({ token }).setOptions({ lean: true }); if (!invitation) { throw new Error('Invitation not found'); @@ -173,7 +173,7 @@ class InvitationClass extends mongoose.Model { const team = await Team.findById(invitation.teamId) .select('name slug avatarUrl memberIds') - .lean(); + .setOptions({ lean: true }); if (!team) { throw new Error('Team does not exist'); @@ -189,7 +189,7 @@ class InvitationClass extends mongoose.Model { throw new Error('Bad data'); } - const invitation = await this.findOne({ token }).lean(); + const invitation = await this.findOne({ token }).setOptions({ lean: true }); if (!invitation || invitation.email !== user.email) { throw new Error('Invitation not found'); @@ -199,7 +199,7 @@ class InvitationClass extends mongoose.Model { const team = await Team.findById(invitation.teamId) .select('memberIds slug teamLeaderId') - .lean(); + .setOptions({ lean: true }); if (!team) { throw new Error('Team does not exist'); diff --git a/book/10-begin/api/server/models/Post.ts b/book/10-begin/api/server/models/Post.ts index ec47eab1..44e695e4 100644 --- a/book/10-begin/api/server/models/Post.ts +++ b/book/10-begin/api/server/models/Post.ts @@ -126,7 +126,7 @@ class PostClass extends mongoose.Model { const filter: any = { discussionId }; - const posts: any[] = await this.find(filter).sort({ createdAt: 1 }).lean(); + const posts: any[] = await this.find(filter).sort({ createdAt: 1 }).setOptions({ lean: true }); return posts; } @@ -156,7 +156,7 @@ class PostClass extends mongoose.Model { throw new Error('Bad data'); } - const post = await this.findById(id).select('createdUserId discussionId').lean(); + const post = await this.findById(id).select('createdUserId discussionId').setOptions({ lean: true }); await this.checkPermissionAndGetTeamAndDiscussion({ userId, @@ -180,7 +180,7 @@ class PostClass extends mongoose.Model { throw new Error('Bad data'); } - const post = await this.findById(id).select('createdUserId discussionId content').lean(); + const post = await this.findById(id).select('createdUserId discussionId content').setOptions({ lean: true }); await this.checkPermissionAndGetTeamAndDiscussion({ userId, @@ -206,7 +206,7 @@ class PostClass extends mongoose.Model { const discussion = await Discussion.findById(discussionId) .select('teamId memberIds slug') - .lean(); + .setOptions({ lean: true }); if (!discussion) { throw new Error('Discussion not found'); @@ -216,7 +216,7 @@ class PostClass extends mongoose.Model { throw new Error('Permission denied'); } - const team = await Team.findById(discussion.teamId).select('memberIds slug').lean(); + const team = await Team.findById(discussion.teamId).select('memberIds slug').setOptions({ lean: true }); if (!team || team.memberIds.indexOf(userId) === -1) { throw new Error('Team not found'); diff --git a/book/10-begin/api/server/models/Team.ts b/book/10-begin/api/server/models/Team.ts index 49a2eb2f..047cc105 100644 --- a/book/10-begin/api/server/models/Team.ts +++ b/book/10-begin/api/server/models/Team.ts @@ -26,10 +26,12 @@ const mongoSchema = new mongoose.Schema({ type: String, required: true, }, - memberIds: { - type: [String], - required: true, - }, + memberIds: [ + { + type: String, + required: true, + }, + ], defaultTeam: { type: Boolean, default: false, @@ -183,12 +185,12 @@ class TeamClass extends mongoose.Model { await this.updateOne({ _id: teamId }, { $set: modifier }, { runValidators: true }); - return this.findById(teamId, 'name avatarUrl slug defaultTeam').lean(); + return this.findById(teamId, 'name avatarUrl slug defaultTeam').setOptions({ lean: true }); } public static getAllTeamsForUser(userId: string) { console.log(`userId:${userId}`); - return this.find({ memberIds: userId }).lean(); + return this.find({ memberIds: userId }).setOptions({ lean: true }); } public static async removeMember({ teamId, teamLeaderId, userId }) { @@ -259,13 +261,13 @@ class TeamClass extends mongoose.Model { { new: true, runValidators: true }, ) .select('isSubscriptionActive stripeSubscription') - .lean(); + .setOptions({ lean: true }); } public static async cancelSubscriptionAfterFailedPayment({ subscriptionId }) { const team: any = await this.find({ 'stripeSubscription.id': subscriptionId }) .select('teamLeaderId isSubscriptionActive stripeSubscription isPaymentFailed') - .lean(); + .setOptions({ lean: true }); if (!team.isSubscriptionActive) { throw new Error('Team is already unsubscribed.'); } @@ -285,7 +287,7 @@ class TeamClass extends mongoose.Model { { new: true, runValidators: true }, ) .select('isSubscriptionActive stripeSubscription isPaymentFailed') - .lean(); + .setOptions({ lean: true }); } } diff --git a/book/10-begin/api/server/models/User.ts b/book/10-begin/api/server/models/User.ts index 9dd1158d..639487fa 100644 --- a/book/10-begin/api/server/models/User.ts +++ b/book/10-begin/api/server/models/User.ts @@ -221,7 +221,7 @@ class UserClass extends mongoose.Model { public static async getUserBySlug({ slug }) { console.log('Static method: getUserBySlug'); - return this.findOne({ slug }, 'email displayName avatarUrl').lean(); + return this.findOne({ slug }, 'email displayName avatarUrl').setOptions({ lean: true }); } public static async updateProfile({ userId, name, avatarUrl }) { @@ -240,7 +240,7 @@ class UserClass extends mongoose.Model { return this.findByIdAndUpdate(userId, { $set: modifier }, { new: true, runValidators: true }) .select('displayName avatarUrl slug') - .lean(); + .setOptions({ lean: true }); } public static publicFields(): string[] { @@ -269,7 +269,7 @@ class UserClass extends mongoose.Model { }) { const user = await this.findOne({ email }) .select([...this.publicFields(), 'googleId'].join(' ')) - .lean(); + .setOptions({ lean: true }); if (user) { if (_.isEmpty(googleToken) && user.googleId) { @@ -331,7 +331,7 @@ class UserClass extends mongoose.Model { } public static async signInOrSignUpByPasswordless({ uid, email }) { - const user = await this.findOne({ email }).select(this.publicFields().join(' ')).lean(); + const user = await this.findOne({ email }).select(this.publicFields().join(' ')).setOptions({ lean: true }); if (user) { throw Error('User already exists'); @@ -382,7 +382,7 @@ class UserClass extends mongoose.Model { return this.find({ _id: { $in: team.memberIds } }) .select(this.publicFields().join(' ')) - .lean(); + .setOptions({ lean: true }); } public static async saveStripeCustomerAndCard({ @@ -456,7 +456,7 @@ class UserClass extends mongoose.Model { return this.findByIdAndUpdate(userId, { $set: modifier }, { new: true, runValidators: true }) .select('stripeListOfInvoices') - .lean(); + .setOptions({ lean: true }); } private static async checkPermissionAndGetTeam({ userId, teamId }) { @@ -466,7 +466,7 @@ class UserClass extends mongoose.Model { throw new Error('Bad data'); } - const team = await Team.findById(teamId).select('memberIds').lean(); + const team = await Team.findById(teamId).select('memberIds').setOptions({ lean: true }); if (!team || team.memberIds.indexOf(userId) === -1) { throw new Error('Team not found'); diff --git a/book/10-begin/api/server/passwordless-auth.ts b/book/10-begin/api/server/passwordless-auth.ts index 3b3292b4..ac354223 100644 --- a/book/10-begin/api/server/passwordless-auth.ts +++ b/book/10-begin/api/server/passwordless-auth.ts @@ -50,7 +50,7 @@ function setupPasswordless({ server }) { '/auth/email-login-link', passwordless.requestToken(async (email, __, callback) => { try { - const user = await User.findOne({ email }).select('_id').lean(); + const user = await User.findOne({ email }).select('_id').setOptions({ lean: true }); if (user) { callback(null, user._id); diff --git a/book/10-begin/api/server/passwordless-token-mongostore.ts b/book/10-begin/api/server/passwordless-token-mongostore.ts index 7cd4825c..25eef0b5 100644 --- a/book/10-begin/api/server/passwordless-token-mongostore.ts +++ b/book/10-begin/api/server/passwordless-token-mongostore.ts @@ -52,7 +52,7 @@ MongoStore.prototype.authenticate = async function (token, uid, callback) { } try { - const tokenDoc = await PasswordlessToken.findOne({ uid, ttl: { $gt: new Date() } }).lean(); + const tokenDoc = await PasswordlessToken.findOne({ uid, ttl: { $gt: new Date() } }).setOptions({ lean: true }); if (tokenDoc) { const isMatch = await bcrypt.compare(token, tokenDoc.hashedToken); @@ -130,7 +130,7 @@ MongoStore.prototype.storeOrUpdateByEmail = async function addEmail(email: strin throw new Error('TokenStore:addEmail called with invalid parameters'); } - const obj = await PasswordlessToken.findOne({ email }).select('uid').lean(); + const obj = await PasswordlessToken.findOne({ email }).select('uid').setOptions({ lean: true }); if (obj) { return obj.uid; diff --git a/book/10-begin/api/server/stripe.ts b/book/10-begin/api/server/stripe.ts index a0f0b116..90d7080d 100644 --- a/book/10-begin/api/server/stripe.ts +++ b/book/10-begin/api/server/stripe.ts @@ -121,12 +121,12 @@ function stripeWebhookAndCheckoutCallback({ server }) { const user = await User.findById( session.metadata.userId, '_id stripeCustomer email displayName isSubscriptionActive stripeSubscription', - ).lean(); + ).setOptions({ lean: true }); const team = await Team.findById( session.metadata.teamId, 'isSubscriptionActive stripeSubscription teamLeaderId slug', - ).lean(); + ).setOptions({ lean: true }); if (!user) { throw new Error('User not found.'); diff --git a/book/10-begin/api/server/utils/slugify.ts b/book/10-begin/api/server/utils/slugify.ts index e76af3c6..f2394edd 100644 --- a/book/10-begin/api/server/utils/slugify.ts +++ b/book/10-begin/api/server/utils/slugify.ts @@ -5,7 +5,7 @@ const slugify = (text) => _.kebabCase(text); async function createUniqueSlug(Model, slug, count, filter) { const obj = await Model.findOne({ slug: `${slug}-${count}`, ...filter }) .select('_id') - .lean(); + .setOptions({ lean: true }); if (!obj) { return `${slug}-${count}`; @@ -19,7 +19,7 @@ async function generateSlug(Model, name, filter = {}) { const obj = await Model.findOne({ slug: origSlug, ...filter }) .select('_id') - .lean(); + .setOptions({ lean: true }); if (!obj) { return origSlug; @@ -31,7 +31,7 @@ async function generateSlug(Model, name, filter = {}) { async function generateNumberSlug(Model, filter = {}, n = 1) { const obj = await Model.findOne({ slug: n, ...filter }) .select('_id') - .lean(); + .setOptions({ lean: true }); if (!obj) { return `${n}`; diff --git a/book/10-begin/lambda/handler.ts b/book/10-begin/lambda/handler.ts index 43918a6c..26fa72d2 100644 --- a/book/10-begin/lambda/handler.ts +++ b/book/10-begin/lambda/handler.ts @@ -39,7 +39,7 @@ export const sendEmailForNewPost = async (event) => { const usersToNotify = await User.find({ _id: { $in: userIds } }) .select('email') - .lean(); + .setOptions({ lean: true }); console.log('usersToNotify', usersToNotify); diff --git a/book/10-end/api/server/api/team-leader.ts b/book/10-end/api/server/api/team-leader.ts index db9eecc5..fabeb733 100644 --- a/book/10-end/api/server/api/team-leader.ts +++ b/book/10-end/api/server/api/team-leader.ts @@ -93,11 +93,11 @@ router.post('/stripe/fetch-checkout-session', async (req, res, next) => { try { const { mode, teamId } = req.body; - const user = await User.findById(req.user.id).select(['stripeCustomer', 'email']).lean(); + const user = await User.findById(req.user.id).select(['stripeCustomer', 'email']).setOptions({ lean: true }); const team = await Team.findById(teamId) .select(['stripeSubscription', 'slug', 'teamLeaderId']) - .lean(); + .setOptions({ lean: true }); if (!user || !team || team.teamLeaderId !== req.user.id) { throw new Error('Permission denied'); diff --git a/book/10-end/api/server/aws-s3.ts b/book/10-end/api/server/aws-s3.ts index 6d50475b..28d938b7 100644 --- a/book/10-end/api/server/aws-s3.ts +++ b/book/10-end/api/server/aws-s3.ts @@ -1,7 +1,17 @@ import * as url from 'url'; import * as aws from 'aws-sdk'; -async function signRequestForUpload({ fileName, fileType, prefix, bucket }) { +async function signRequestForUpload({ + fileName, + fileType, + prefix, + bucket, +}: { + fileName: string; + fileType: string; + prefix: string; + bucket: string; +}) { const randomStringForPrefix = Math.random().toString(36).substring(2, 12) + Math.random().toString(36).substring(2, 12); @@ -21,7 +31,7 @@ async function signRequestForUpload({ fileName, fileType, prefix, bucket }) { const s3 = new aws.S3({ apiVersion: 'latest', - region: 'us-east-1', + region: process.env.AWS_REGION, accessKeyId: process.env.AWS_ACCESSKEYID, secretAccessKey: process.env.AWS_SECRETACCESSKEY, }); diff --git a/book/10-end/api/server/aws-ses.ts b/book/10-end/api/server/aws-ses.ts index faf399eb..fff1565e 100644 --- a/book/10-end/api/server/aws-ses.ts +++ b/book/10-end/api/server/aws-ses.ts @@ -3,7 +3,7 @@ import * as aws from 'aws-sdk'; export default function sendEmail(options) { const ses = new aws.SES({ apiVersion: 'latest', - region: 'us-east-1', + region: process.env.AWS_REGION, accessKeyId: process.env.AWS_ACCESSKEYID, secretAccessKey: process.env.AWS_SECRETACCESSKEY, }); diff --git a/book/10-end/api/server/mailchimp.ts b/book/10-end/api/server/mailchimp.ts index 6f3eb9ef..7abf8d5e 100644 --- a/book/10-end/api/server/mailchimp.ts +++ b/book/10-end/api/server/mailchimp.ts @@ -4,7 +4,18 @@ const LIST_IDS = { signups: process.env.MAILCHIMP_SAAS_ALL_LIST_ID, }; -function callAPI({ path, method, data }): Promise { +function callAPI({ + path, + method, + data, +}: { + path: string; + method: string; + data: { + email_address: string; + status: string; + }; +}): Promise { const ROOT_URI = `https://${process.env.MAILCHIMP_REGION}.api.mailchimp.com/3.0`; return fetch(`${ROOT_URI}${path}`, { @@ -19,9 +30,8 @@ function callAPI({ path, method, data }): Promise { }); } -async function addToMailchimp({ email, listName }) { +async function addToMailchimp({ email, listName }: { email: string; listName: string }) { const data = { - // eslint-disable-next-line email_address: email, status: 'subscribed', }; diff --git a/book/10-end/api/server/models/Discussion.ts b/book/10-end/api/server/models/Discussion.ts index e9931e9d..a5d8869f 100644 --- a/book/10-end/api/server/models/Discussion.ts +++ b/book/10-end/api/server/models/Discussion.ts @@ -24,7 +24,11 @@ const mongoSchema = new mongoose.Schema({ type: String, required: true, }, - memberIds: [String], + memberIds: [ + { + type: String, + }, + ], createdAt: { type: Date, required: true, @@ -104,7 +108,7 @@ class DiscussionClass extends mongoose.Model { const filter: any = { teamId, memberIds: userId }; - const discussions: any[] = await this.find(filter).lean(); + const discussions: any[] = await this.find(filter).setOptions({ lean: true }); return { discussions }; } @@ -134,7 +138,7 @@ class DiscussionClass extends mongoose.Model { throw new Error('Bad data'); } - const discussion = await this.findById(id).select('teamId createdUserId').lean(); + const discussion = await this.findById(id).select('teamId createdUserId').setOptions({ lean: true }); const team = await this.checkPermissionAndGetTeam({ userId, @@ -164,7 +168,7 @@ class DiscussionClass extends mongoose.Model { throw new Error('Bad data'); } - const discussion = await this.findById(id).select('teamId').lean(); + const discussion = await this.findById(id).select('teamId').setOptions({ lean: true }); await this.checkPermissionAndGetTeam({ userId, teamId: discussion.teamId }); @@ -180,7 +184,7 @@ class DiscussionClass extends mongoose.Model { throw new Error('Bad data'); } - const team = await Team.findById(teamId).select('memberIds teamLeaderId').lean(); + const team = await Team.findById(teamId).select('memberIds teamLeaderId').setOptions({ lean: true }); if (!team || team.memberIds.indexOf(userId) === -1) { throw new Error('Team not found'); diff --git a/book/10-end/api/server/models/EmailTemplate.ts b/book/10-end/api/server/models/EmailTemplate.ts index 54ca2241..db9089d7 100644 --- a/book/10-end/api/server/models/EmailTemplate.ts +++ b/book/10-end/api/server/models/EmailTemplate.ts @@ -74,7 +74,7 @@ export async function insertTemplates() { ]; for (const t of templates) { - const et = await EmailTemplate.findOne({ name: t.name }).lean(); + const et = await EmailTemplate.findOne({ name: t.name }).setOptions({ lean: true }); const message = t.message.replace(/\n/g, '').replace(/[ ]+/g, ' ').trim(); if (!et) { @@ -88,7 +88,7 @@ export async function insertTemplates() { export default async function getEmailTemplate(name: string, params: any) { await insertTemplates(); - const et = await EmailTemplate.findOne({ name }).lean(); + const et = await EmailTemplate.findOne({ name }).setOptions({ lean: true }); if (!et) { throw new Error('Email Template is not found in database.'); diff --git a/book/10-end/api/server/models/Invitation.ts b/book/10-end/api/server/models/Invitation.ts index f36745d8..2a46dd49 100644 --- a/book/10-end/api/server/models/Invitation.ts +++ b/book/10-end/api/server/models/Invitation.ts @@ -68,12 +68,14 @@ class InvitationClass extends mongoose.Model { throw new Error('Bad data'); } - const team = await Team.findById(teamId).lean(); + const team = await Team.findById(teamId).setOptions({ lean: true }); if (!team || team.teamLeaderId !== userId) { throw new Error('Team does not exist or you have no permission'); } - const registeredUser = await User.findOne({ email }).select('defaultTeamSlug').lean(); + const registeredUser = await User.findOne({ email }) + .select('defaultTeamSlug') + .setOptions({ lean: true }); if (registeredUser) { if (team.memberIds.includes(registeredUser._id.toString())) { @@ -90,7 +92,9 @@ class InvitationClass extends mongoose.Model { } let token; - const invitation = await this.findOne({ teamId, email }).select('token').lean(); + const invitation = await this.findOne({ teamId, email }) + .select('token') + .setOptions({ lean: true }); if (invitation) { token = invitation.token; @@ -129,17 +133,19 @@ class InvitationClass extends mongoose.Model { console.log('Email sending error:', err); }); - return await this.findOne({ teamId, email }).lean(); + return await this.findOne({ teamId, email }).setOptions({ lean: true }); } public static async getTeamInvitations({ userId, teamId }) { - const team = await Team.findOne({ _id: teamId }).select('teamLeaderId').lean(); + const team = await Team.findOne({ _id: teamId }) + .select('teamLeaderId') + .setOptions({ lean: true }); if (userId !== team.teamLeaderId) { throw new Error('You have no permission.'); } - return this.find({ teamId }).select('email').lean(); + return this.find({ teamId }).select('email').setOptions({ lean: true }); } public static async getTeamByToken({ token }) { @@ -147,7 +153,7 @@ class InvitationClass extends mongoose.Model { throw new Error('Bad data'); } - const invitation = await this.findOne({ token }).lean(); + const invitation = await this.findOne({ token }).setOptions({ lean: true }); if (!invitation) { throw new Error('Invitation not found'); @@ -155,7 +161,7 @@ class InvitationClass extends mongoose.Model { const team = await Team.findById(invitation.teamId) .select('name slug avatarUrl memberIds') - .lean(); + .setOptions({ lean: true }); if (!team) { throw new Error('Team does not exist'); @@ -169,7 +175,7 @@ class InvitationClass extends mongoose.Model { throw new Error('Bad data'); } - const invitation = await this.findOne({ token }).lean(); + const invitation = await this.findOne({ token }).setOptions({ lean: true }); if (!invitation) { throw new Error('Invitation not found'); @@ -177,7 +183,7 @@ class InvitationClass extends mongoose.Model { const team = await Team.findById(invitation.teamId) .select('name slug avatarUrl memberIds') - .lean(); + .setOptions({ lean: true }); if (!team) { throw new Error('Team does not exist'); @@ -193,7 +199,7 @@ class InvitationClass extends mongoose.Model { throw new Error('Bad data'); } - const invitation = await this.findOne({ token }).lean(); + const invitation = await this.findOne({ token }).setOptions({ lean: true }); if (!invitation || invitation.email !== user.email) { throw new Error('Invitation not found'); @@ -203,7 +209,7 @@ class InvitationClass extends mongoose.Model { const team = await Team.findById(invitation.teamId) .select('memberIds slug teamLeaderId') - .lean(); + .setOptions({ lean: true }); if (!team) { throw new Error('Team does not exist'); diff --git a/book/10-end/api/server/models/Post.ts b/book/10-end/api/server/models/Post.ts index ec47eab1..44e695e4 100644 --- a/book/10-end/api/server/models/Post.ts +++ b/book/10-end/api/server/models/Post.ts @@ -126,7 +126,7 @@ class PostClass extends mongoose.Model { const filter: any = { discussionId }; - const posts: any[] = await this.find(filter).sort({ createdAt: 1 }).lean(); + const posts: any[] = await this.find(filter).sort({ createdAt: 1 }).setOptions({ lean: true }); return posts; } @@ -156,7 +156,7 @@ class PostClass extends mongoose.Model { throw new Error('Bad data'); } - const post = await this.findById(id).select('createdUserId discussionId').lean(); + const post = await this.findById(id).select('createdUserId discussionId').setOptions({ lean: true }); await this.checkPermissionAndGetTeamAndDiscussion({ userId, @@ -180,7 +180,7 @@ class PostClass extends mongoose.Model { throw new Error('Bad data'); } - const post = await this.findById(id).select('createdUserId discussionId content').lean(); + const post = await this.findById(id).select('createdUserId discussionId content').setOptions({ lean: true }); await this.checkPermissionAndGetTeamAndDiscussion({ userId, @@ -206,7 +206,7 @@ class PostClass extends mongoose.Model { const discussion = await Discussion.findById(discussionId) .select('teamId memberIds slug') - .lean(); + .setOptions({ lean: true }); if (!discussion) { throw new Error('Discussion not found'); @@ -216,7 +216,7 @@ class PostClass extends mongoose.Model { throw new Error('Permission denied'); } - const team = await Team.findById(discussion.teamId).select('memberIds slug').lean(); + const team = await Team.findById(discussion.teamId).select('memberIds slug').setOptions({ lean: true }); if (!team || team.memberIds.indexOf(userId) === -1) { throw new Error('Team not found'); diff --git a/book/10-end/api/server/models/Team.ts b/book/10-end/api/server/models/Team.ts index 49a2eb2f..047cc105 100644 --- a/book/10-end/api/server/models/Team.ts +++ b/book/10-end/api/server/models/Team.ts @@ -26,10 +26,12 @@ const mongoSchema = new mongoose.Schema({ type: String, required: true, }, - memberIds: { - type: [String], - required: true, - }, + memberIds: [ + { + type: String, + required: true, + }, + ], defaultTeam: { type: Boolean, default: false, @@ -183,12 +185,12 @@ class TeamClass extends mongoose.Model { await this.updateOne({ _id: teamId }, { $set: modifier }, { runValidators: true }); - return this.findById(teamId, 'name avatarUrl slug defaultTeam').lean(); + return this.findById(teamId, 'name avatarUrl slug defaultTeam').setOptions({ lean: true }); } public static getAllTeamsForUser(userId: string) { console.log(`userId:${userId}`); - return this.find({ memberIds: userId }).lean(); + return this.find({ memberIds: userId }).setOptions({ lean: true }); } public static async removeMember({ teamId, teamLeaderId, userId }) { @@ -259,13 +261,13 @@ class TeamClass extends mongoose.Model { { new: true, runValidators: true }, ) .select('isSubscriptionActive stripeSubscription') - .lean(); + .setOptions({ lean: true }); } public static async cancelSubscriptionAfterFailedPayment({ subscriptionId }) { const team: any = await this.find({ 'stripeSubscription.id': subscriptionId }) .select('teamLeaderId isSubscriptionActive stripeSubscription isPaymentFailed') - .lean(); + .setOptions({ lean: true }); if (!team.isSubscriptionActive) { throw new Error('Team is already unsubscribed.'); } @@ -285,7 +287,7 @@ class TeamClass extends mongoose.Model { { new: true, runValidators: true }, ) .select('isSubscriptionActive stripeSubscription isPaymentFailed') - .lean(); + .setOptions({ lean: true }); } } diff --git a/book/10-end/api/server/models/User.ts b/book/10-end/api/server/models/User.ts index 972aa8d6..61129f7e 100644 --- a/book/10-end/api/server/models/User.ts +++ b/book/10-end/api/server/models/User.ts @@ -240,7 +240,7 @@ class UserClass extends mongoose.Model { return this.findByIdAndUpdate(userId, { $set: modifier }, { new: true, runValidators: true }) .select('displayName avatarUrl slug') - .lean(); + .setOptions({ lean: true }); } public static publicFields(): string[] { @@ -269,7 +269,7 @@ class UserClass extends mongoose.Model { }) { const user = await this.findOne({ email }) .select([...this.publicFields(), 'googleId'].join(' ')) - .lean(); + .setOptions({ lean: true }); if (user) { if (_.isEmpty(googleToken) && user.googleId) { @@ -331,7 +331,7 @@ class UserClass extends mongoose.Model { } public static async signInOrSignUpByPasswordless({ uid, email }) { - const user = await this.findOne({ email }).select(this.publicFields().join(' ')).lean(); + const user = await this.findOne({ email }).select(this.publicFields().join(' ')).setOptions({ lean: true }); if (user) { throw Error('User already exists'); @@ -373,6 +373,7 @@ class UserClass extends mongoose.Model { return _.pick(newUser, this.publicFields()); } + // try private instead of public, run `yarn build` public static toggleTheme({ userId, darkTheme }) { return this.updateOne({ _id: userId }, { darkTheme: !!darkTheme }); } @@ -382,7 +383,7 @@ class UserClass extends mongoose.Model { return this.find({ _id: { $in: team.memberIds } }) .select(this.publicFields().join(' ')) - .lean(); + .setOptions({ lean: true }); } public static async saveStripeCustomerAndCard({ @@ -456,7 +457,7 @@ class UserClass extends mongoose.Model { return this.findByIdAndUpdate(userId, { $set: modifier }, { new: true, runValidators: true }) .select('stripeListOfInvoices') - .lean(); + .setOptions({ lean: true }); } private static async checkPermissionAndGetTeam({ userId, teamId }) { @@ -466,7 +467,7 @@ class UserClass extends mongoose.Model { throw new Error('Bad data'); } - const team = await Team.findById(teamId).select('memberIds').lean(); + const team = await Team.findById(teamId).select('memberIds').setOptions({ lean: true }); if (!team || team.memberIds.indexOf(userId) === -1) { throw new Error('Team not found'); diff --git a/book/10-end/api/server/passwordless-auth.ts b/book/10-end/api/server/passwordless-auth.ts index ba5b1986..db3748b9 100644 --- a/book/10-end/api/server/passwordless-auth.ts +++ b/book/10-end/api/server/passwordless-auth.ts @@ -52,7 +52,7 @@ function setupPasswordless({ server }) { '/auth/email-login-link', passwordless.requestToken(async (email, __, callback) => { try { - const user = await User.findOne({ email }).select('_id').lean(); + const user = await User.findOne({ email }).select('_id').setOptions({ lean: true }); if (user) { callback(null, user._id); diff --git a/book/10-end/api/server/passwordless-token-mongostore.ts b/book/10-end/api/server/passwordless-token-mongostore.ts index 7cd4825c..7ebc9c11 100644 --- a/book/10-end/api/server/passwordless-token-mongostore.ts +++ b/book/10-end/api/server/passwordless-token-mongostore.ts @@ -52,7 +52,9 @@ MongoStore.prototype.authenticate = async function (token, uid, callback) { } try { - const tokenDoc = await PasswordlessToken.findOne({ uid, ttl: { $gt: new Date() } }).lean(); + const tokenDoc = await PasswordlessToken.findOne({ uid, ttl: { $gt: new Date() } }).setOptions({ + lean: true, + }); if (tokenDoc) { const isMatch = await bcrypt.compare(token, tokenDoc.hashedToken); @@ -130,7 +132,7 @@ MongoStore.prototype.storeOrUpdateByEmail = async function addEmail(email: strin throw new Error('TokenStore:addEmail called with invalid parameters'); } - const obj = await PasswordlessToken.findOne({ email }).select('uid').lean(); + const obj = await PasswordlessToken.findOne({ email }).select('uid').setOptions({ lean: true }); if (obj) { return obj.uid; diff --git a/book/10-end/api/server/sockets.ts b/book/10-end/api/server/sockets.ts index 5f1f3d46..50e21eee 100644 --- a/book/10-end/api/server/sockets.ts +++ b/book/10-end/api/server/sockets.ts @@ -1,5 +1,7 @@ import { Response } from 'express'; +import * as express from 'express'; import { Server } from 'socket.io'; +import * as httpModule from 'http'; import { DiscussionDocument } from './models/Discussion'; import { PostDocument } from './models/Post'; @@ -8,7 +10,15 @@ let io: Server = null; const dev = process.env.NODE_ENV !== 'production'; -function setupSockets({ httpServer, origin, sessionMiddleware }) { +function setupSockets({ + httpServer, + origin, + sessionMiddleware, +}: { + httpServer: httpModule.Server; + origin: string | boolean | RegExp | (string | RegExp)[]; + sessionMiddleware: express.RequestHandler; +}) { if (io === null) { io = new Server(httpServer, { cors: { @@ -19,7 +29,7 @@ function setupSockets({ httpServer, origin, sessionMiddleware }) { cookie: { httpOnly: true, maxAge: 14 * 24 * 60 * 60 * 1000, // expires in 14 days - domain: dev ? 'localhost' : '.builderbook.org', // update value in the next book update + domain: dev ? 'localhost' : '.async-await.com', secure: dev ? false : true, }, serveClient: false, diff --git a/book/10-end/api/server/stripe.ts b/book/10-end/api/server/stripe.ts index ac3f2a96..87881e85 100644 --- a/book/10-end/api/server/stripe.ts +++ b/book/10-end/api/server/stripe.ts @@ -1,3 +1,4 @@ +import * as express from 'express'; import * as bodyParser from 'body-parser'; import Stripe from 'stripe'; @@ -13,7 +14,23 @@ const stripeInstance = new Stripe( { apiVersion: '2020-08-27' }, ); -function createSession({ userId, teamId, teamSlug, customerId, subscriptionId, userEmail, mode }) { +function createSession({ + userId, + teamId, + teamSlug, + customerId, + subscriptionId, + userEmail, + mode, +}: { + userId: string; + teamId: string; + teamSlug: string; + customerId: string; + subscriptionId: string; + userEmail: string; + mode: Stripe.Checkout.SessionCreateParams.Mode; +}) { const params: Stripe.Checkout.SessionCreateParams = { customer_email: customerId ? undefined : userEmail, customer: customerId, @@ -70,17 +87,17 @@ function updateSubscription(subscriptionId: string, params: Stripe.SubscriptionU return stripeInstance.subscriptions.update(subscriptionId, params); } -function cancelSubscription({ subscriptionId }) { +function cancelSubscription({ subscriptionId }: { subscriptionId: string }) { logger.debug('cancel subscription', subscriptionId); return stripeInstance.subscriptions.del(subscriptionId); } -function getListOfInvoices({ customerId }) { +function getListOfInvoices({ customerId }: { customerId: string }) { logger.debug('getting list of invoices for customer', customerId); return stripeInstance.invoices.list({ customer: customerId, limit: 100 }); } -function stripeWebhookAndCheckoutCallback({ server }) { +function stripeWebhookAndCheckoutCallback({ server }: { server: express.Application }) { server.post( '/api/v1/public/stripe-invoice-payment-failed', bodyParser.raw({ type: 'application/json' }), @@ -127,12 +144,12 @@ function stripeWebhookAndCheckoutCallback({ server }) { const user = await User.findById( session.metadata.userId, '_id stripeCustomer email displayName isSubscriptionActive stripeSubscription', - ).lean(); + ).setOptions({ lean: true }); const team = await Team.findById( session.metadata.teamId, 'isSubscriptionActive stripeSubscription teamLeaderId slug', - ).lean(); + ).setOptions({ lean: true }); if (!user) { throw new Error('User not found.'); diff --git a/book/10-end/api/server/utils/slugify.ts b/book/10-end/api/server/utils/slugify.ts index e76af3c6..f2394edd 100644 --- a/book/10-end/api/server/utils/slugify.ts +++ b/book/10-end/api/server/utils/slugify.ts @@ -5,7 +5,7 @@ const slugify = (text) => _.kebabCase(text); async function createUniqueSlug(Model, slug, count, filter) { const obj = await Model.findOne({ slug: `${slug}-${count}`, ...filter }) .select('_id') - .lean(); + .setOptions({ lean: true }); if (!obj) { return `${slug}-${count}`; @@ -19,7 +19,7 @@ async function generateSlug(Model, name, filter = {}) { const obj = await Model.findOne({ slug: origSlug, ...filter }) .select('_id') - .lean(); + .setOptions({ lean: true }); if (!obj) { return origSlug; @@ -31,7 +31,7 @@ async function generateSlug(Model, name, filter = {}) { async function generateNumberSlug(Model, filter = {}, n = 1) { const obj = await Model.findOne({ slug: n, ...filter }) .select('_id') - .lean(); + .setOptions({ lean: true }); if (!obj) { return `${n}`; diff --git a/book/10-end/app/server/server.ts b/book/10-end/app/server/server.ts index 940c3874..2fc12b4c 100644 --- a/book/10-end/app/server/server.ts +++ b/book/10-end/app/server/server.ts @@ -81,6 +81,8 @@ app.prepare().then(() => { handle(req, res); }); + // listen(handle: any, listeningListener?: () => void): http.Server; + // "@types/express-serve-static-core", "version": "4.17.1" server.listen(port, () => { console.log(`> Ready on ${dev ? process.env.URL_APP : process.env.PRODUCTION_URL_APP}`); }); diff --git a/book/10-end/lambda/handler.ts b/book/10-end/lambda/handler.ts index a5e89456..ac907afb 100644 --- a/book/10-end/lambda/handler.ts +++ b/book/10-end/lambda/handler.ts @@ -46,7 +46,7 @@ export const sendEmailForNewPost = async (event) => { const usersToNotify = await User.find({ _id: { $in: userIds } }) .select('email') - .lean(); + .setOptions({ lean: true }); console.log('usersToNotify', usersToNotify); diff --git a/book/3-begin/app/server/server.ts b/book/3-begin/app/server/server.ts index 01cfcf06..4d2bc446 100644 --- a/book/3-begin/app/server/server.ts +++ b/book/3-begin/app/server/server.ts @@ -26,10 +26,7 @@ app.prepare().then(() => { handle(req, res); }); - server.listen(process.env.PORT_APP, (err) => { - if (err) { - throw err; - } + server.listen(process.env.PORT_APP, () => { console.log(`> Ready on ${process.env.URL_APP}`); }); }); diff --git a/book/3-end/api/server/server.ts b/book/3-end/api/server/server.ts index 875e55ca..8d74dee8 100644 --- a/book/3-end/api/server/server.ts +++ b/book/3-end/api/server/server.ts @@ -18,9 +18,6 @@ server.get('*', (_, res) => { console.log(process.env.PORT_API, process.env.URL_API); -server.listen(process.env['PORT_API'], (err) => { - if (err) { - throw err; - } +server.listen(process.env.PORT_API, () => { console.log(`> Ready on ${process.env.URL_API}`); }); diff --git a/book/3-end/app/server/server.ts b/book/3-end/app/server/server.ts index 2ea549d6..095437fe 100644 --- a/book/3-end/app/server/server.ts +++ b/book/3-end/app/server/server.ts @@ -28,10 +28,7 @@ app.prepare().then(() => { console.log(process.env.PORT_APP); - server.listen(process.env.PORT_APP, (err) => { - if (err) { - throw err; - } + server.listen(process.env.PORT_APP, () => { console.log(`> Ready on ${process.env.URL_APP}`); }); }); diff --git a/book/4-begin/api/server/server.ts b/book/4-begin/api/server/server.ts index ad2e9e54..f6255b1d 100644 --- a/book/4-begin/api/server/server.ts +++ b/book/4-begin/api/server/server.ts @@ -16,9 +16,6 @@ server.get('*', (_, res) => { res.sendStatus(403); }); -server.listen(process.env.PORT_API, (err) => { - if (err) { - throw err; - } +server.listen(process.env.PORT_API, () => { console.log(`> Ready on ${process.env.URL_API}`); }); diff --git a/book/4-begin/app/server/server.ts b/book/4-begin/app/server/server.ts index 01cfcf06..4d2bc446 100644 --- a/book/4-begin/app/server/server.ts +++ b/book/4-begin/app/server/server.ts @@ -26,10 +26,7 @@ app.prepare().then(() => { handle(req, res); }); - server.listen(process.env.PORT_APP, (err) => { - if (err) { - throw err; - } + server.listen(process.env.PORT_APP, () => { console.log(`> Ready on ${process.env.URL_APP}`); }); }); diff --git a/book/4-end/api/server/aws-s3.ts b/book/4-end/api/server/aws-s3.ts index 81b9671c..302b4659 100644 --- a/book/4-end/api/server/aws-s3.ts +++ b/book/4-end/api/server/aws-s3.ts @@ -21,7 +21,7 @@ async function signRequestForUpload({ fileName, fileType, prefix, bucket }) { const s3 = new aws.S3({ apiVersion: 'latest', - region: 'us-east-1', + region: process.env.AWS_REGION, accessKeyId: process.env.AWS_ACCESSKEYID, secretAccessKey: process.env.AWS_SECRETACCESSKEY, }); diff --git a/book/4-end/api/server/models/User.ts b/book/4-end/api/server/models/User.ts index 0077c773..45c07d22 100644 --- a/book/4-end/api/server/models/User.ts +++ b/book/4-end/api/server/models/User.ts @@ -50,7 +50,7 @@ class UserClass extends mongoose.Model { public static async getUserBySlug({ slug }) { console.log('Static method: getUserBySlug'); - return this.findOne({ slug }, 'email displayName avatarUrl').lean(); + return this.findOne({ slug }, 'email displayName avatarUrl').setOptions({ lean: true }); } public static async updateProfile({ userId, name, avatarUrl }) { @@ -69,7 +69,7 @@ class UserClass extends mongoose.Model { return this.findByIdAndUpdate(userId, { $set: modifier }, { new: true, runValidators: true }) .select('displayName avatarUrl slug') - .lean(); + .setOptions({ lean: true }); } } diff --git a/book/4-end/api/server/server.ts b/book/4-end/api/server/server.ts index bbf5a9a0..ec3778cc 100644 --- a/book/4-end/api/server/server.ts +++ b/book/4-end/api/server/server.ts @@ -34,9 +34,6 @@ server.get('*', (_, res) => { res.sendStatus(403); }); -server.listen(process.env.PORT_API, (err) => { - if (err) { - throw err; - } +server.listen(process.env.PORT_API, () => { console.log(`> Ready on ${process.env.URL_API}`); }); diff --git a/book/4-end/api/server/utils/slugify.ts b/book/4-end/api/server/utils/slugify.ts index 9f970667..1a0b9d99 100644 --- a/book/4-end/api/server/utils/slugify.ts +++ b/book/4-end/api/server/utils/slugify.ts @@ -5,7 +5,7 @@ const slugify = (text) => _.kebabCase(text); async function createUniqueSlug(Model, slug, count, filter) { const obj = await Model.findOne({ slug: `${slug}-${count}`, ...filter }) .select('_id') - .lean(); + .setOptions({ lean: true }); if (!obj) { return `${slug}-${count}`; @@ -19,7 +19,7 @@ async function generateSlug(Model, name, filter = {}) { const obj = await Model.findOne({ slug: origSlug, ...filter }) .select('_id') - .lean(); + .setOptions({ lean: true }); if (!obj) { return origSlug; diff --git a/book/4-end/app/server/server.ts b/book/4-end/app/server/server.ts index 01cfcf06..4d2bc446 100644 --- a/book/4-end/app/server/server.ts +++ b/book/4-end/app/server/server.ts @@ -26,10 +26,7 @@ app.prepare().then(() => { handle(req, res); }); - server.listen(process.env.PORT_APP, (err) => { - if (err) { - throw err; - } + server.listen(process.env.PORT_APP, () => { console.log(`> Ready on ${process.env.URL_APP}`); }); }); diff --git a/book/5-begin/api/server/aws-s3.ts b/book/5-begin/api/server/aws-s3.ts index 81b9671c..302b4659 100644 --- a/book/5-begin/api/server/aws-s3.ts +++ b/book/5-begin/api/server/aws-s3.ts @@ -21,7 +21,7 @@ async function signRequestForUpload({ fileName, fileType, prefix, bucket }) { const s3 = new aws.S3({ apiVersion: 'latest', - region: 'us-east-1', + region: process.env.AWS_REGION, accessKeyId: process.env.AWS_ACCESSKEYID, secretAccessKey: process.env.AWS_SECRETACCESSKEY, }); diff --git a/book/5-begin/api/server/models/User.ts b/book/5-begin/api/server/models/User.ts index 0077c773..45c07d22 100644 --- a/book/5-begin/api/server/models/User.ts +++ b/book/5-begin/api/server/models/User.ts @@ -50,7 +50,7 @@ class UserClass extends mongoose.Model { public static async getUserBySlug({ slug }) { console.log('Static method: getUserBySlug'); - return this.findOne({ slug }, 'email displayName avatarUrl').lean(); + return this.findOne({ slug }, 'email displayName avatarUrl').setOptions({ lean: true }); } public static async updateProfile({ userId, name, avatarUrl }) { @@ -69,7 +69,7 @@ class UserClass extends mongoose.Model { return this.findByIdAndUpdate(userId, { $set: modifier }, { new: true, runValidators: true }) .select('displayName avatarUrl slug') - .lean(); + .setOptions({ lean: true }); } } diff --git a/book/5-begin/api/server/server.ts b/book/5-begin/api/server/server.ts index bbf5a9a0..ec3778cc 100644 --- a/book/5-begin/api/server/server.ts +++ b/book/5-begin/api/server/server.ts @@ -34,9 +34,6 @@ server.get('*', (_, res) => { res.sendStatus(403); }); -server.listen(process.env.PORT_API, (err) => { - if (err) { - throw err; - } +server.listen(process.env.PORT_API, () => { console.log(`> Ready on ${process.env.URL_API}`); }); diff --git a/book/5-begin/api/server/utils/slugify.ts b/book/5-begin/api/server/utils/slugify.ts index 9f970667..1a0b9d99 100644 --- a/book/5-begin/api/server/utils/slugify.ts +++ b/book/5-begin/api/server/utils/slugify.ts @@ -5,7 +5,7 @@ const slugify = (text) => _.kebabCase(text); async function createUniqueSlug(Model, slug, count, filter) { const obj = await Model.findOne({ slug: `${slug}-${count}`, ...filter }) .select('_id') - .lean(); + .setOptions({ lean: true }); if (!obj) { return `${slug}-${count}`; @@ -19,7 +19,7 @@ async function generateSlug(Model, name, filter = {}) { const obj = await Model.findOne({ slug: origSlug, ...filter }) .select('_id') - .lean(); + .setOptions({ lean: true }); if (!obj) { return origSlug; diff --git a/book/5-begin/app/server/server.ts b/book/5-begin/app/server/server.ts index 01cfcf06..4d2bc446 100644 --- a/book/5-begin/app/server/server.ts +++ b/book/5-begin/app/server/server.ts @@ -26,10 +26,7 @@ app.prepare().then(() => { handle(req, res); }); - server.listen(process.env.PORT_APP, (err) => { - if (err) { - throw err; - } + server.listen(process.env.PORT_APP, () => { console.log(`> Ready on ${process.env.URL_APP}`); }); }); diff --git a/book/5-end/api/server/aws-s3.ts b/book/5-end/api/server/aws-s3.ts index 81b9671c..302b4659 100644 --- a/book/5-end/api/server/aws-s3.ts +++ b/book/5-end/api/server/aws-s3.ts @@ -21,7 +21,7 @@ async function signRequestForUpload({ fileName, fileType, prefix, bucket }) { const s3 = new aws.S3({ apiVersion: 'latest', - region: 'us-east-1', + region: process.env.AWS_REGION, accessKeyId: process.env.AWS_ACCESSKEYID, secretAccessKey: process.env.AWS_SECRETACCESSKEY, }); diff --git a/book/5-end/api/server/models/User.ts b/book/5-end/api/server/models/User.ts index 3444efe3..814785d3 100644 --- a/book/5-end/api/server/models/User.ts +++ b/book/5-end/api/server/models/User.ts @@ -81,7 +81,7 @@ class UserClass extends mongoose.Model { public static async getUserBySlug({ slug }) { console.log('Static method: getUserBySlug'); - return this.findOne({ slug }, 'email displayName avatarUrl').lean(); + return this.findOne({ slug }, 'email displayName avatarUrl').setOptions({ lean: true }); } public static async updateProfile({ userId, name, avatarUrl }) { @@ -100,7 +100,7 @@ class UserClass extends mongoose.Model { return this.findByIdAndUpdate(userId, { $set: modifier }, { new: true, runValidators: true }) .select('displayName avatarUrl slug') - .lean(); + .setOptions({ lean: true }); } public static publicFields(): string[] { @@ -116,7 +116,7 @@ class UserClass extends mongoose.Model { }) { const user = await this.findOne({ email }) .select([...this.publicFields(), 'googleId'].join(' ')) - .lean(); + .setOptions({ lean: true }); if (user) { if (_.isEmpty(googleToken) && user.googleId) { diff --git a/book/5-end/api/server/server.ts b/book/5-end/api/server/server.ts index eec116de..2b21ff4e 100644 --- a/book/5-end/api/server/server.ts +++ b/book/5-end/api/server/server.ts @@ -62,9 +62,6 @@ server.get('*', (_, res) => { res.sendStatus(403); }); -server.listen(process.env.PORT_API, (err) => { - if (err) { - throw err; - } +server.listen(process.env.PORT_API, () => { console.log(`> Ready on ${process.env.URL_API}`); }); diff --git a/book/5-end/api/server/utils/slugify.ts b/book/5-end/api/server/utils/slugify.ts index 9f970667..1a0b9d99 100644 --- a/book/5-end/api/server/utils/slugify.ts +++ b/book/5-end/api/server/utils/slugify.ts @@ -5,7 +5,7 @@ const slugify = (text) => _.kebabCase(text); async function createUniqueSlug(Model, slug, count, filter) { const obj = await Model.findOne({ slug: `${slug}-${count}`, ...filter }) .select('_id') - .lean(); + .setOptions({ lean: true }); if (!obj) { return `${slug}-${count}`; @@ -19,7 +19,7 @@ async function generateSlug(Model, name, filter = {}) { const obj = await Model.findOne({ slug: origSlug, ...filter }) .select('_id') - .lean(); + .setOptions({ lean: true }); if (!obj) { return origSlug; diff --git a/book/5-end/app/server/server.ts b/book/5-end/app/server/server.ts index 01cfcf06..4d2bc446 100644 --- a/book/5-end/app/server/server.ts +++ b/book/5-end/app/server/server.ts @@ -26,10 +26,7 @@ app.prepare().then(() => { handle(req, res); }); - server.listen(process.env.PORT_APP, (err) => { - if (err) { - throw err; - } + server.listen(process.env.PORT_APP, () => { console.log(`> Ready on ${process.env.URL_APP}`); }); }); diff --git a/book/6-begin/api/server/aws-s3.ts b/book/6-begin/api/server/aws-s3.ts index 81b9671c..302b4659 100644 --- a/book/6-begin/api/server/aws-s3.ts +++ b/book/6-begin/api/server/aws-s3.ts @@ -21,7 +21,7 @@ async function signRequestForUpload({ fileName, fileType, prefix, bucket }) { const s3 = new aws.S3({ apiVersion: 'latest', - region: 'us-east-1', + region: process.env.AWS_REGION, accessKeyId: process.env.AWS_ACCESSKEYID, secretAccessKey: process.env.AWS_SECRETACCESSKEY, }); diff --git a/book/6-begin/api/server/models/User.ts b/book/6-begin/api/server/models/User.ts index b801d1cc..34eb8f77 100644 --- a/book/6-begin/api/server/models/User.ts +++ b/book/6-begin/api/server/models/User.ts @@ -83,7 +83,7 @@ class UserClass extends mongoose.Model { public static async getUserBySlug({ slug }) { console.log('Static method: getUserBySlug'); - return this.findOne({ slug }, 'email displayName avatarUrl').lean(); + return this.findOne({ slug }, 'email displayName avatarUrl').setOptions({ lean: true }); } public static async updateProfile({ userId, name, avatarUrl }) { @@ -102,7 +102,7 @@ class UserClass extends mongoose.Model { return this.findByIdAndUpdate(userId, { $set: modifier }, { new: true, runValidators: true }) .select('displayName avatarUrl slug') - .lean(); + .setOptions({ lean: true }); } public static publicFields(): string[] { @@ -118,7 +118,7 @@ class UserClass extends mongoose.Model { }) { const user = await this.findOne({ email }) .select([...this.publicFields(), 'googleId'].join(' ')) - .lean(); + .setOptions({ lean: true }); if (user) { if (_.isEmpty(googleToken) && user.googleId) { diff --git a/book/6-begin/api/server/server.ts b/book/6-begin/api/server/server.ts index eec116de..2b21ff4e 100644 --- a/book/6-begin/api/server/server.ts +++ b/book/6-begin/api/server/server.ts @@ -62,9 +62,6 @@ server.get('*', (_, res) => { res.sendStatus(403); }); -server.listen(process.env.PORT_API, (err) => { - if (err) { - throw err; - } +server.listen(process.env.PORT_API, () => { console.log(`> Ready on ${process.env.URL_API}`); }); diff --git a/book/6-begin/api/server/utils/slugify.ts b/book/6-begin/api/server/utils/slugify.ts index 9f970667..1a0b9d99 100644 --- a/book/6-begin/api/server/utils/slugify.ts +++ b/book/6-begin/api/server/utils/slugify.ts @@ -5,7 +5,7 @@ const slugify = (text) => _.kebabCase(text); async function createUniqueSlug(Model, slug, count, filter) { const obj = await Model.findOne({ slug: `${slug}-${count}`, ...filter }) .select('_id') - .lean(); + .setOptions({ lean: true }); if (!obj) { return `${slug}-${count}`; @@ -19,7 +19,7 @@ async function generateSlug(Model, name, filter = {}) { const obj = await Model.findOne({ slug: origSlug, ...filter }) .select('_id') - .lean(); + .setOptions({ lean: true }); if (!obj) { return origSlug; diff --git a/book/6-begin/app/server/server.ts b/book/6-begin/app/server/server.ts index 01cfcf06..4d2bc446 100644 --- a/book/6-begin/app/server/server.ts +++ b/book/6-begin/app/server/server.ts @@ -26,10 +26,7 @@ app.prepare().then(() => { handle(req, res); }); - server.listen(process.env.PORT_APP, (err) => { - if (err) { - throw err; - } + server.listen(process.env.PORT_APP, () => { console.log(`> Ready on ${process.env.URL_APP}`); }); }); diff --git a/book/6-end/api/server/aws-s3.ts b/book/6-end/api/server/aws-s3.ts index 81b9671c..302b4659 100644 --- a/book/6-end/api/server/aws-s3.ts +++ b/book/6-end/api/server/aws-s3.ts @@ -21,7 +21,7 @@ async function signRequestForUpload({ fileName, fileType, prefix, bucket }) { const s3 = new aws.S3({ apiVersion: 'latest', - region: 'us-east-1', + region: process.env.AWS_REGION, accessKeyId: process.env.AWS_ACCESSKEYID, secretAccessKey: process.env.AWS_SECRETACCESSKEY, }); diff --git a/book/6-end/api/server/aws-ses.ts b/book/6-end/api/server/aws-ses.ts index faf399eb..fff1565e 100644 --- a/book/6-end/api/server/aws-ses.ts +++ b/book/6-end/api/server/aws-ses.ts @@ -3,7 +3,7 @@ import * as aws from 'aws-sdk'; export default function sendEmail(options) { const ses = new aws.SES({ apiVersion: 'latest', - region: 'us-east-1', + region: process.env.AWS_REGION, accessKeyId: process.env.AWS_ACCESSKEYID, secretAccessKey: process.env.AWS_SECRETACCESSKEY, }); diff --git a/book/6-end/api/server/models/EmailTemplate.ts b/book/6-end/api/server/models/EmailTemplate.ts index 5f3c412c..eae337f1 100644 --- a/book/6-end/api/server/models/EmailTemplate.ts +++ b/book/6-end/api/server/models/EmailTemplate.ts @@ -58,7 +58,7 @@ export async function insertTemplates() { ]; for (const t of templates) { - const et = await EmailTemplate.findOne({ name: t.name }).lean(); + const et = await EmailTemplate.findOne({ name: t.name }).setOptions({ lean: true }); const message = t.message.replace(/\n/g, '').replace(/[ ]+/g, ' ').trim(); if (!et) { @@ -72,7 +72,7 @@ export async function insertTemplates() { export default async function getEmailTemplate(name: string, params: any) { await insertTemplates(); - const et = await EmailTemplate.findOne({ name }).lean(); + const et = await EmailTemplate.findOne({ name }).setOptions({ lean: true }); if (!et) { throw new Error('Email Template is not found in database.'); diff --git a/book/6-end/api/server/models/User.ts b/book/6-end/api/server/models/User.ts index 09c676f9..aed09c95 100644 --- a/book/6-end/api/server/models/User.ts +++ b/book/6-end/api/server/models/User.ts @@ -94,7 +94,7 @@ class UserClass extends mongoose.Model { public static async getUserBySlug({ slug }) { console.log('Static method: getUserBySlug'); - return this.findOne({ slug }, 'email displayName avatarUrl').lean(); + return this.findOne({ slug }, 'email displayName avatarUrl').setOptions({ lean: true }); } public static async updateProfile({ userId, name, avatarUrl }) { @@ -113,7 +113,7 @@ class UserClass extends mongoose.Model { return this.findByIdAndUpdate(userId, { $set: modifier }, { new: true, runValidators: true }) .select('displayName avatarUrl slug') - .lean(); + .setOptions({ lean: true }); } public static publicFields(): string[] { @@ -129,7 +129,7 @@ class UserClass extends mongoose.Model { }) { const user = await this.findOne({ email }) .select([...this.publicFields(), 'googleId'].join(' ')) - .lean(); + .setOptions({ lean: true }); if (user) { if (_.isEmpty(googleToken) && user.googleId) { @@ -190,7 +190,7 @@ class UserClass extends mongoose.Model { } public static async signInOrSignUpByPasswordless({ uid, email }) { - const user = await this.findOne({ email }).select(this.publicFields().join(' ')).lean(); + const user = await this.findOne({ email }).select(this.publicFields().join(' ')).setOptions({ lean: true }); if (user) { throw Error('User already exists'); diff --git a/book/6-end/api/server/passwordless-auth.ts b/book/6-end/api/server/passwordless-auth.ts index 4674dc39..3c5e546b 100644 --- a/book/6-end/api/server/passwordless-auth.ts +++ b/book/6-end/api/server/passwordless-auth.ts @@ -49,7 +49,7 @@ function setupPasswordless({ server }) { '/auth/email-login-link', passwordless.requestToken(async (email, __, callback) => { try { - const user = await User.findOne({ email }).select('_id').lean(); + const user = await User.findOne({ email }).select('_id').setOptions({ lean: true }); if (user) { callback(null, user._id); diff --git a/book/6-end/api/server/passwordless-token-mongostore.ts b/book/6-end/api/server/passwordless-token-mongostore.ts index 55166cba..d6546e36 100644 --- a/book/6-end/api/server/passwordless-token-mongostore.ts +++ b/book/6-end/api/server/passwordless-token-mongostore.ts @@ -130,7 +130,7 @@ MongoStore.prototype.storeOrUpdateByEmail = async function addEmail(email: strin throw new Error('TokenStore:addEmail called with invalid parameters'); } - const obj = await PasswordlessToken.findOne({ email }).select('uid').lean(); + const obj = await PasswordlessToken.findOne({ email }).select('uid').setOptions({ lean: true }); if (obj) { return obj.uid; diff --git a/book/6-end/api/server/server.ts b/book/6-end/api/server/server.ts index f84bdcde..6dc72f2d 100644 --- a/book/6-end/api/server/server.ts +++ b/book/6-end/api/server/server.ts @@ -68,9 +68,6 @@ server.get('*', (_, res) => { res.sendStatus(403); }); -server.listen(process.env.PORT_API, (err) => { - if (err) { - throw err; - } +server.listen(process.env.PORT_API, () => { console.log(`> Ready on ${process.env.URL_API}`); }); diff --git a/book/6-end/api/server/utils/slugify.ts b/book/6-end/api/server/utils/slugify.ts index 9f970667..1a0b9d99 100644 --- a/book/6-end/api/server/utils/slugify.ts +++ b/book/6-end/api/server/utils/slugify.ts @@ -5,7 +5,7 @@ const slugify = (text) => _.kebabCase(text); async function createUniqueSlug(Model, slug, count, filter) { const obj = await Model.findOne({ slug: `${slug}-${count}`, ...filter }) .select('_id') - .lean(); + .setOptions({ lean: true }); if (!obj) { return `${slug}-${count}`; @@ -19,7 +19,7 @@ async function generateSlug(Model, name, filter = {}) { const obj = await Model.findOne({ slug: origSlug, ...filter }) .select('_id') - .lean(); + .setOptions({ lean: true }); if (!obj) { return origSlug; diff --git a/book/6-end/app/server/server.ts b/book/6-end/app/server/server.ts index 01cfcf06..4d2bc446 100644 --- a/book/6-end/app/server/server.ts +++ b/book/6-end/app/server/server.ts @@ -26,10 +26,7 @@ app.prepare().then(() => { handle(req, res); }); - server.listen(process.env.PORT_APP, (err) => { - if (err) { - throw err; - } + server.listen(process.env.PORT_APP, () => { console.log(`> Ready on ${process.env.URL_APP}`); }); }); diff --git a/book/7-begin/api/server/aws-s3.ts b/book/7-begin/api/server/aws-s3.ts index 81b9671c..302b4659 100644 --- a/book/7-begin/api/server/aws-s3.ts +++ b/book/7-begin/api/server/aws-s3.ts @@ -21,7 +21,7 @@ async function signRequestForUpload({ fileName, fileType, prefix, bucket }) { const s3 = new aws.S3({ apiVersion: 'latest', - region: 'us-east-1', + region: process.env.AWS_REGION, accessKeyId: process.env.AWS_ACCESSKEYID, secretAccessKey: process.env.AWS_SECRETACCESSKEY, }); diff --git a/book/7-begin/api/server/aws-ses.ts b/book/7-begin/api/server/aws-ses.ts index faf399eb..fff1565e 100644 --- a/book/7-begin/api/server/aws-ses.ts +++ b/book/7-begin/api/server/aws-ses.ts @@ -3,7 +3,7 @@ import * as aws from 'aws-sdk'; export default function sendEmail(options) { const ses = new aws.SES({ apiVersion: 'latest', - region: 'us-east-1', + region: process.env.AWS_REGION, accessKeyId: process.env.AWS_ACCESSKEYID, secretAccessKey: process.env.AWS_SECRETACCESSKEY, }); diff --git a/book/7-begin/api/server/models/EmailTemplate.ts b/book/7-begin/api/server/models/EmailTemplate.ts index 5f3c412c..eae337f1 100644 --- a/book/7-begin/api/server/models/EmailTemplate.ts +++ b/book/7-begin/api/server/models/EmailTemplate.ts @@ -58,7 +58,7 @@ export async function insertTemplates() { ]; for (const t of templates) { - const et = await EmailTemplate.findOne({ name: t.name }).lean(); + const et = await EmailTemplate.findOne({ name: t.name }).setOptions({ lean: true }); const message = t.message.replace(/\n/g, '').replace(/[ ]+/g, ' ').trim(); if (!et) { @@ -72,7 +72,7 @@ export async function insertTemplates() { export default async function getEmailTemplate(name: string, params: any) { await insertTemplates(); - const et = await EmailTemplate.findOne({ name }).lean(); + const et = await EmailTemplate.findOne({ name }).setOptions({ lean: true }); if (!et) { throw new Error('Email Template is not found in database.'); diff --git a/book/7-begin/api/server/models/User.ts b/book/7-begin/api/server/models/User.ts index 09c676f9..aed09c95 100644 --- a/book/7-begin/api/server/models/User.ts +++ b/book/7-begin/api/server/models/User.ts @@ -94,7 +94,7 @@ class UserClass extends mongoose.Model { public static async getUserBySlug({ slug }) { console.log('Static method: getUserBySlug'); - return this.findOne({ slug }, 'email displayName avatarUrl').lean(); + return this.findOne({ slug }, 'email displayName avatarUrl').setOptions({ lean: true }); } public static async updateProfile({ userId, name, avatarUrl }) { @@ -113,7 +113,7 @@ class UserClass extends mongoose.Model { return this.findByIdAndUpdate(userId, { $set: modifier }, { new: true, runValidators: true }) .select('displayName avatarUrl slug') - .lean(); + .setOptions({ lean: true }); } public static publicFields(): string[] { @@ -129,7 +129,7 @@ class UserClass extends mongoose.Model { }) { const user = await this.findOne({ email }) .select([...this.publicFields(), 'googleId'].join(' ')) - .lean(); + .setOptions({ lean: true }); if (user) { if (_.isEmpty(googleToken) && user.googleId) { @@ -190,7 +190,7 @@ class UserClass extends mongoose.Model { } public static async signInOrSignUpByPasswordless({ uid, email }) { - const user = await this.findOne({ email }).select(this.publicFields().join(' ')).lean(); + const user = await this.findOne({ email }).select(this.publicFields().join(' ')).setOptions({ lean: true }); if (user) { throw Error('User already exists'); diff --git a/book/7-begin/api/server/passwordless-auth.ts b/book/7-begin/api/server/passwordless-auth.ts index 4674dc39..3c5e546b 100644 --- a/book/7-begin/api/server/passwordless-auth.ts +++ b/book/7-begin/api/server/passwordless-auth.ts @@ -49,7 +49,7 @@ function setupPasswordless({ server }) { '/auth/email-login-link', passwordless.requestToken(async (email, __, callback) => { try { - const user = await User.findOne({ email }).select('_id').lean(); + const user = await User.findOne({ email }).select('_id').setOptions({ lean: true }); if (user) { callback(null, user._id); diff --git a/book/7-begin/api/server/passwordless-token-mongostore.ts b/book/7-begin/api/server/passwordless-token-mongostore.ts index 55166cba..d6546e36 100644 --- a/book/7-begin/api/server/passwordless-token-mongostore.ts +++ b/book/7-begin/api/server/passwordless-token-mongostore.ts @@ -130,7 +130,7 @@ MongoStore.prototype.storeOrUpdateByEmail = async function addEmail(email: strin throw new Error('TokenStore:addEmail called with invalid parameters'); } - const obj = await PasswordlessToken.findOne({ email }).select('uid').lean(); + const obj = await PasswordlessToken.findOne({ email }).select('uid').setOptions({ lean: true }); if (obj) { return obj.uid; diff --git a/book/7-begin/api/server/server.ts b/book/7-begin/api/server/server.ts index 4f51bd98..955ed9fa 100644 --- a/book/7-begin/api/server/server.ts +++ b/book/7-begin/api/server/server.ts @@ -64,9 +64,6 @@ server.get('*', (_, res) => { res.sendStatus(403); }); -server.listen(process.env.PORT_API, (err) => { - if (err) { - throw err; - } +server.listen(process.env.PORT_API, () => { console.log(`> Ready on ${process.env.URL_API}`); }); diff --git a/book/7-begin/api/server/utils/slugify.ts b/book/7-begin/api/server/utils/slugify.ts index 9f970667..1a0b9d99 100644 --- a/book/7-begin/api/server/utils/slugify.ts +++ b/book/7-begin/api/server/utils/slugify.ts @@ -5,7 +5,7 @@ const slugify = (text) => _.kebabCase(text); async function createUniqueSlug(Model, slug, count, filter) { const obj = await Model.findOne({ slug: `${slug}-${count}`, ...filter }) .select('_id') - .lean(); + .setOptions({ lean: true }); if (!obj) { return `${slug}-${count}`; @@ -19,7 +19,7 @@ async function generateSlug(Model, name, filter = {}) { const obj = await Model.findOne({ slug: origSlug, ...filter }) .select('_id') - .lean(); + .setOptions({ lean: true }); if (!obj) { return origSlug; diff --git a/book/7-begin/app/server/server.ts b/book/7-begin/app/server/server.ts index 01cfcf06..4d2bc446 100644 --- a/book/7-begin/app/server/server.ts +++ b/book/7-begin/app/server/server.ts @@ -26,10 +26,7 @@ app.prepare().then(() => { handle(req, res); }); - server.listen(process.env.PORT_APP, (err) => { - if (err) { - throw err; - } + server.listen(process.env.PORT_APP, () => { console.log(`> Ready on ${process.env.URL_APP}`); }); }); diff --git a/book/7-end/api/server/aws-s3.ts b/book/7-end/api/server/aws-s3.ts index 6d50475b..bf432d48 100644 --- a/book/7-end/api/server/aws-s3.ts +++ b/book/7-end/api/server/aws-s3.ts @@ -21,7 +21,7 @@ async function signRequestForUpload({ fileName, fileType, prefix, bucket }) { const s3 = new aws.S3({ apiVersion: 'latest', - region: 'us-east-1', + region: process.env.AWS_REGION, accessKeyId: process.env.AWS_ACCESSKEYID, secretAccessKey: process.env.AWS_SECRETACCESSKEY, }); diff --git a/book/7-end/api/server/aws-ses.ts b/book/7-end/api/server/aws-ses.ts index faf399eb..fff1565e 100644 --- a/book/7-end/api/server/aws-ses.ts +++ b/book/7-end/api/server/aws-ses.ts @@ -3,7 +3,7 @@ import * as aws from 'aws-sdk'; export default function sendEmail(options) { const ses = new aws.SES({ apiVersion: 'latest', - region: 'us-east-1', + region: process.env.AWS_REGION, accessKeyId: process.env.AWS_ACCESSKEYID, secretAccessKey: process.env.AWS_SECRETACCESSKEY, }); diff --git a/book/7-end/api/server/models/EmailTemplate.ts b/book/7-end/api/server/models/EmailTemplate.ts index fb8ae2e6..44cb9648 100644 --- a/book/7-end/api/server/models/EmailTemplate.ts +++ b/book/7-end/api/server/models/EmailTemplate.ts @@ -74,7 +74,7 @@ export async function insertTemplates() { ]; for (const t of templates) { - const et = await EmailTemplate.findOne({ name: t.name }).lean(); + const et = await EmailTemplate.findOne({ name: t.name }).setOptions({ lean: true }); const message = t.message.replace(/\n/g, '').replace(/[ ]+/g, ' ').trim(); if (!et) { @@ -88,7 +88,7 @@ export async function insertTemplates() { export default async function getEmailTemplate(name: string, params: any) { await insertTemplates(); - const et = await EmailTemplate.findOne({ name }).lean(); + const et = await EmailTemplate.findOne({ name }).setOptions({ lean: true }); if (!et) { throw new Error('Email Template is not found in database.'); diff --git a/book/7-end/api/server/models/Invitation.ts b/book/7-end/api/server/models/Invitation.ts index c1d15471..60cd8dcf 100644 --- a/book/7-end/api/server/models/Invitation.ts +++ b/book/7-end/api/server/models/Invitation.ts @@ -68,12 +68,12 @@ class InvitationClass extends mongoose.Model { throw new Error('Bad data'); } - const team = await Team.findById(teamId).lean(); + const team = await Team.findById(teamId).setOptions({ lean: true }); if (!team || team.teamLeaderId !== userId) { throw new Error('Team does not exist or you have no permission'); } - const registeredUser = await User.findOne({ email }).select('defaultTeamSlug').lean(); + const registeredUser = await User.findOne({ email }).select('defaultTeamSlug').setOptions({ lean: true }); if (registeredUser) { if (team.memberIds.includes(registeredUser._id.toString())) { @@ -90,7 +90,7 @@ class InvitationClass extends mongoose.Model { } let token; - const invitation = await this.findOne({ teamId, email }).select('token').lean(); + const invitation = await this.findOne({ teamId, email }).select('token').setOptions({ lean: true }); if (invitation) { token = invitation.token; @@ -125,17 +125,17 @@ class InvitationClass extends mongoose.Model { console.log('Email sending error:', err); }); - return await this.findOne({ teamId, email }).lean(); + return await this.findOne({ teamId, email }).setOptions({ lean: true }); } public static async getTeamInvitations({ userId, teamId }) { - const team = await Team.findOne({ _id: teamId }).select('teamLeaderId').lean(); + const team = await Team.findOne({ _id: teamId }).select('teamLeaderId').setOptions({ lean: true }); if (userId !== team.teamLeaderId) { throw new Error('You have no permission.'); } - return this.find({ teamId }).select('email').lean(); + return this.find({ teamId }).select('email').setOptions({ lean: true }); } public static async getTeamByToken({ token }) { @@ -143,7 +143,7 @@ class InvitationClass extends mongoose.Model { throw new Error('Bad data'); } - const invitation = await this.findOne({ token }).lean(); + const invitation = await this.findOne({ token }).setOptions({ lean: true }); if (!invitation) { throw new Error('Invitation not found'); @@ -151,7 +151,7 @@ class InvitationClass extends mongoose.Model { const team = await Team.findById(invitation.teamId) .select('name slug avatarUrl memberIds') - .lean(); + .setOptions({ lean: true }); if (!team) { throw new Error('Team does not exist'); @@ -165,7 +165,7 @@ class InvitationClass extends mongoose.Model { throw new Error('Bad data'); } - const invitation = await this.findOne({ token }).lean(); + const invitation = await this.findOne({ token }).setOptions({ lean: true }); if (!invitation) { throw new Error('Invitation not found'); @@ -173,7 +173,7 @@ class InvitationClass extends mongoose.Model { const team = await Team.findById(invitation.teamId) .select('name slug avatarUrl memberIds') - .lean(); + .setOptions({ lean: true }); if (!team) { throw new Error('Team does not exist'); @@ -189,7 +189,7 @@ class InvitationClass extends mongoose.Model { throw new Error('Bad data'); } - const invitation = await this.findOne({ token }).lean(); + const invitation = await this.findOne({ token }).setOptions({ lean: true }); if (!invitation || invitation.email !== user.email) { throw new Error('Invitation not found'); @@ -199,7 +199,7 @@ class InvitationClass extends mongoose.Model { const team = await Team.findById(invitation.teamId) .select('memberIds slug teamLeaderId') - .lean(); + .setOptions({ lean: true }); if (!team) { throw new Error('Team does not exist'); diff --git a/book/7-end/api/server/models/Team.ts b/book/7-end/api/server/models/Team.ts index f26f9e7f..37697b26 100644 --- a/book/7-end/api/server/models/Team.ts +++ b/book/7-end/api/server/models/Team.ts @@ -24,10 +24,12 @@ const mongoSchema = new mongoose.Schema({ type: String, required: true, }, - memberIds: { - type: [String], - required: true, - }, + memberIds: [ + { + type: String, + required: true, + }, + ], defaultTeam: { type: Boolean, default: false, @@ -128,12 +130,12 @@ class TeamClass extends mongoose.Model { await this.updateOne({ _id: teamId }, { $set: modifier }, { runValidators: true }); - return this.findById(teamId, 'name avatarUrl slug defaultTeam').lean(); + return this.findById(teamId, 'name avatarUrl slug defaultTeam').setOptions({ lean: true }); } public static getAllTeamsForUser(userId: string) { console.log(`userId:${userId}`); - return this.find({ memberIds: userId }).lean(); + return this.find({ memberIds: userId }).setOptions({ lean: true }); } public static async removeMember({ teamId, teamLeaderId, userId }) { diff --git a/book/7-end/api/server/models/User.ts b/book/7-end/api/server/models/User.ts index 3ea37d04..62dc091d 100644 --- a/book/7-end/api/server/models/User.ts +++ b/book/7-end/api/server/models/User.ts @@ -120,7 +120,7 @@ class UserClass extends mongoose.Model { public static async getUserBySlug({ slug }) { console.log('Static method: getUserBySlug'); - return this.findOne({ slug }, 'email displayName avatarUrl').lean(); + return this.findOne({ slug }, 'email displayName avatarUrl').setOptions({ lean: true }); } public static async updateProfile({ userId, name, avatarUrl }) { @@ -139,7 +139,7 @@ class UserClass extends mongoose.Model { return this.findByIdAndUpdate(userId, { $set: modifier }, { new: true, runValidators: true }) .select('displayName avatarUrl slug') - .lean(); + .setOptions({ lean: true }); } public static publicFields(): string[] { @@ -165,7 +165,7 @@ class UserClass extends mongoose.Model { }) { const user = await this.findOne({ email }) .select([...this.publicFields(), 'googleId'].join(' ')) - .lean(); + .setOptions({ lean: true }); if (user) { if (_.isEmpty(googleToken) && user.googleId) { @@ -227,7 +227,7 @@ class UserClass extends mongoose.Model { } public static async signInOrSignUpByPasswordless({ uid, email }) { - const user = await this.findOne({ email }).select(this.publicFields().join(' ')).lean(); + const user = await this.findOne({ email }).select(this.publicFields().join(' ')).setOptions({ lean: true }); if (user) { throw Error('User already exists'); @@ -278,7 +278,7 @@ class UserClass extends mongoose.Model { return this.find({ _id: { $in: team.memberIds } }) .select(this.publicFields().join(' ')) - .lean(); + .setOptions({ lean: true }); } private static async checkPermissionAndGetTeam({ userId, teamId }) { @@ -288,7 +288,7 @@ class UserClass extends mongoose.Model { throw new Error('Bad data'); } - const team = await Team.findById(teamId).select('memberIds').lean(); + const team = await Team.findById(teamId).select('memberIds').setOptions({ lean: true }); if (!team || team.memberIds.indexOf(userId) === -1) { throw new Error('Team not found'); diff --git a/book/7-end/api/server/passwordless-auth.ts b/book/7-end/api/server/passwordless-auth.ts index b6e8b605..7b05d7b5 100644 --- a/book/7-end/api/server/passwordless-auth.ts +++ b/book/7-end/api/server/passwordless-auth.ts @@ -50,7 +50,7 @@ function setupPasswordless({ server }) { '/auth/email-login-link', passwordless.requestToken(async (email, __, callback) => { try { - const user = await User.findOne({ email }).select('_id').lean(); + const user = await User.findOne({ email }).select('_id').setOptions({ lean: true }); if (user) { callback(null, user._id); diff --git a/book/7-end/api/server/passwordless-token-mongostore.ts b/book/7-end/api/server/passwordless-token-mongostore.ts index 55166cba..d6546e36 100644 --- a/book/7-end/api/server/passwordless-token-mongostore.ts +++ b/book/7-end/api/server/passwordless-token-mongostore.ts @@ -130,7 +130,7 @@ MongoStore.prototype.storeOrUpdateByEmail = async function addEmail(email: strin throw new Error('TokenStore:addEmail called with invalid parameters'); } - const obj = await PasswordlessToken.findOne({ email }).select('uid').lean(); + const obj = await PasswordlessToken.findOne({ email }).select('uid').setOptions({ lean: true }); if (obj) { return obj.uid; diff --git a/book/7-end/api/server/server.ts b/book/7-end/api/server/server.ts index 4f51bd98..955ed9fa 100644 --- a/book/7-end/api/server/server.ts +++ b/book/7-end/api/server/server.ts @@ -64,9 +64,6 @@ server.get('*', (_, res) => { res.sendStatus(403); }); -server.listen(process.env.PORT_API, (err) => { - if (err) { - throw err; - } +server.listen(process.env.PORT_API, () => { console.log(`> Ready on ${process.env.URL_API}`); }); diff --git a/book/7-end/api/server/utils/slugify.ts b/book/7-end/api/server/utils/slugify.ts index e76af3c6..f2394edd 100644 --- a/book/7-end/api/server/utils/slugify.ts +++ b/book/7-end/api/server/utils/slugify.ts @@ -5,7 +5,7 @@ const slugify = (text) => _.kebabCase(text); async function createUniqueSlug(Model, slug, count, filter) { const obj = await Model.findOne({ slug: `${slug}-${count}`, ...filter }) .select('_id') - .lean(); + .setOptions({ lean: true }); if (!obj) { return `${slug}-${count}`; @@ -19,7 +19,7 @@ async function generateSlug(Model, name, filter = {}) { const obj = await Model.findOne({ slug: origSlug, ...filter }) .select('_id') - .lean(); + .setOptions({ lean: true }); if (!obj) { return origSlug; @@ -31,7 +31,7 @@ async function generateSlug(Model, name, filter = {}) { async function generateNumberSlug(Model, filter = {}, n = 1) { const obj = await Model.findOne({ slug: n, ...filter }) .select('_id') - .lean(); + .setOptions({ lean: true }); if (!obj) { return `${n}`; diff --git a/book/7-end/app/server/server.ts b/book/7-end/app/server/server.ts index e8849294..55d01719 100644 --- a/book/7-end/app/server/server.ts +++ b/book/7-end/app/server/server.ts @@ -31,10 +31,7 @@ app.prepare().then(() => { handle(req, res); }); - server.listen(process.env.PORT_APP, (err) => { - if (err) { - throw err; - } + server.listen(process.env.PORT_APP, () => { console.log(`> Ready on ${process.env.URL_APP}`); }); }); diff --git a/book/8-begin/api/server/aws-s3.ts b/book/8-begin/api/server/aws-s3.ts index 6d50475b..bf432d48 100644 --- a/book/8-begin/api/server/aws-s3.ts +++ b/book/8-begin/api/server/aws-s3.ts @@ -21,7 +21,7 @@ async function signRequestForUpload({ fileName, fileType, prefix, bucket }) { const s3 = new aws.S3({ apiVersion: 'latest', - region: 'us-east-1', + region: process.env.AWS_REGION, accessKeyId: process.env.AWS_ACCESSKEYID, secretAccessKey: process.env.AWS_SECRETACCESSKEY, }); diff --git a/book/8-begin/api/server/aws-ses.ts b/book/8-begin/api/server/aws-ses.ts index faf399eb..fff1565e 100644 --- a/book/8-begin/api/server/aws-ses.ts +++ b/book/8-begin/api/server/aws-ses.ts @@ -3,7 +3,7 @@ import * as aws from 'aws-sdk'; export default function sendEmail(options) { const ses = new aws.SES({ apiVersion: 'latest', - region: 'us-east-1', + region: process.env.AWS_REGION, accessKeyId: process.env.AWS_ACCESSKEYID, secretAccessKey: process.env.AWS_SECRETACCESSKEY, }); diff --git a/book/8-begin/api/server/models/EmailTemplate.ts b/book/8-begin/api/server/models/EmailTemplate.ts index fb8ae2e6..44cb9648 100644 --- a/book/8-begin/api/server/models/EmailTemplate.ts +++ b/book/8-begin/api/server/models/EmailTemplate.ts @@ -74,7 +74,7 @@ export async function insertTemplates() { ]; for (const t of templates) { - const et = await EmailTemplate.findOne({ name: t.name }).lean(); + const et = await EmailTemplate.findOne({ name: t.name }).setOptions({ lean: true }); const message = t.message.replace(/\n/g, '').replace(/[ ]+/g, ' ').trim(); if (!et) { @@ -88,7 +88,7 @@ export async function insertTemplates() { export default async function getEmailTemplate(name: string, params: any) { await insertTemplates(); - const et = await EmailTemplate.findOne({ name }).lean(); + const et = await EmailTemplate.findOne({ name }).setOptions({ lean: true }); if (!et) { throw new Error('Email Template is not found in database.'); diff --git a/book/8-begin/api/server/models/Invitation.ts b/book/8-begin/api/server/models/Invitation.ts index c1d15471..60cd8dcf 100644 --- a/book/8-begin/api/server/models/Invitation.ts +++ b/book/8-begin/api/server/models/Invitation.ts @@ -68,12 +68,12 @@ class InvitationClass extends mongoose.Model { throw new Error('Bad data'); } - const team = await Team.findById(teamId).lean(); + const team = await Team.findById(teamId).setOptions({ lean: true }); if (!team || team.teamLeaderId !== userId) { throw new Error('Team does not exist or you have no permission'); } - const registeredUser = await User.findOne({ email }).select('defaultTeamSlug').lean(); + const registeredUser = await User.findOne({ email }).select('defaultTeamSlug').setOptions({ lean: true }); if (registeredUser) { if (team.memberIds.includes(registeredUser._id.toString())) { @@ -90,7 +90,7 @@ class InvitationClass extends mongoose.Model { } let token; - const invitation = await this.findOne({ teamId, email }).select('token').lean(); + const invitation = await this.findOne({ teamId, email }).select('token').setOptions({ lean: true }); if (invitation) { token = invitation.token; @@ -125,17 +125,17 @@ class InvitationClass extends mongoose.Model { console.log('Email sending error:', err); }); - return await this.findOne({ teamId, email }).lean(); + return await this.findOne({ teamId, email }).setOptions({ lean: true }); } public static async getTeamInvitations({ userId, teamId }) { - const team = await Team.findOne({ _id: teamId }).select('teamLeaderId').lean(); + const team = await Team.findOne({ _id: teamId }).select('teamLeaderId').setOptions({ lean: true }); if (userId !== team.teamLeaderId) { throw new Error('You have no permission.'); } - return this.find({ teamId }).select('email').lean(); + return this.find({ teamId }).select('email').setOptions({ lean: true }); } public static async getTeamByToken({ token }) { @@ -143,7 +143,7 @@ class InvitationClass extends mongoose.Model { throw new Error('Bad data'); } - const invitation = await this.findOne({ token }).lean(); + const invitation = await this.findOne({ token }).setOptions({ lean: true }); if (!invitation) { throw new Error('Invitation not found'); @@ -151,7 +151,7 @@ class InvitationClass extends mongoose.Model { const team = await Team.findById(invitation.teamId) .select('name slug avatarUrl memberIds') - .lean(); + .setOptions({ lean: true }); if (!team) { throw new Error('Team does not exist'); @@ -165,7 +165,7 @@ class InvitationClass extends mongoose.Model { throw new Error('Bad data'); } - const invitation = await this.findOne({ token }).lean(); + const invitation = await this.findOne({ token }).setOptions({ lean: true }); if (!invitation) { throw new Error('Invitation not found'); @@ -173,7 +173,7 @@ class InvitationClass extends mongoose.Model { const team = await Team.findById(invitation.teamId) .select('name slug avatarUrl memberIds') - .lean(); + .setOptions({ lean: true }); if (!team) { throw new Error('Team does not exist'); @@ -189,7 +189,7 @@ class InvitationClass extends mongoose.Model { throw new Error('Bad data'); } - const invitation = await this.findOne({ token }).lean(); + const invitation = await this.findOne({ token }).setOptions({ lean: true }); if (!invitation || invitation.email !== user.email) { throw new Error('Invitation not found'); @@ -199,7 +199,7 @@ class InvitationClass extends mongoose.Model { const team = await Team.findById(invitation.teamId) .select('memberIds slug teamLeaderId') - .lean(); + .setOptions({ lean: true }); if (!team) { throw new Error('Team does not exist'); diff --git a/book/8-begin/api/server/models/Team.ts b/book/8-begin/api/server/models/Team.ts index f26f9e7f..37697b26 100644 --- a/book/8-begin/api/server/models/Team.ts +++ b/book/8-begin/api/server/models/Team.ts @@ -24,10 +24,12 @@ const mongoSchema = new mongoose.Schema({ type: String, required: true, }, - memberIds: { - type: [String], - required: true, - }, + memberIds: [ + { + type: String, + required: true, + }, + ], defaultTeam: { type: Boolean, default: false, @@ -128,12 +130,12 @@ class TeamClass extends mongoose.Model { await this.updateOne({ _id: teamId }, { $set: modifier }, { runValidators: true }); - return this.findById(teamId, 'name avatarUrl slug defaultTeam').lean(); + return this.findById(teamId, 'name avatarUrl slug defaultTeam').setOptions({ lean: true }); } public static getAllTeamsForUser(userId: string) { console.log(`userId:${userId}`); - return this.find({ memberIds: userId }).lean(); + return this.find({ memberIds: userId }).setOptions({ lean: true }); } public static async removeMember({ teamId, teamLeaderId, userId }) { diff --git a/book/8-begin/api/server/models/User.ts b/book/8-begin/api/server/models/User.ts index 3ea37d04..62dc091d 100644 --- a/book/8-begin/api/server/models/User.ts +++ b/book/8-begin/api/server/models/User.ts @@ -120,7 +120,7 @@ class UserClass extends mongoose.Model { public static async getUserBySlug({ slug }) { console.log('Static method: getUserBySlug'); - return this.findOne({ slug }, 'email displayName avatarUrl').lean(); + return this.findOne({ slug }, 'email displayName avatarUrl').setOptions({ lean: true }); } public static async updateProfile({ userId, name, avatarUrl }) { @@ -139,7 +139,7 @@ class UserClass extends mongoose.Model { return this.findByIdAndUpdate(userId, { $set: modifier }, { new: true, runValidators: true }) .select('displayName avatarUrl slug') - .lean(); + .setOptions({ lean: true }); } public static publicFields(): string[] { @@ -165,7 +165,7 @@ class UserClass extends mongoose.Model { }) { const user = await this.findOne({ email }) .select([...this.publicFields(), 'googleId'].join(' ')) - .lean(); + .setOptions({ lean: true }); if (user) { if (_.isEmpty(googleToken) && user.googleId) { @@ -227,7 +227,7 @@ class UserClass extends mongoose.Model { } public static async signInOrSignUpByPasswordless({ uid, email }) { - const user = await this.findOne({ email }).select(this.publicFields().join(' ')).lean(); + const user = await this.findOne({ email }).select(this.publicFields().join(' ')).setOptions({ lean: true }); if (user) { throw Error('User already exists'); @@ -278,7 +278,7 @@ class UserClass extends mongoose.Model { return this.find({ _id: { $in: team.memberIds } }) .select(this.publicFields().join(' ')) - .lean(); + .setOptions({ lean: true }); } private static async checkPermissionAndGetTeam({ userId, teamId }) { @@ -288,7 +288,7 @@ class UserClass extends mongoose.Model { throw new Error('Bad data'); } - const team = await Team.findById(teamId).select('memberIds').lean(); + const team = await Team.findById(teamId).select('memberIds').setOptions({ lean: true }); if (!team || team.memberIds.indexOf(userId) === -1) { throw new Error('Team not found'); diff --git a/book/8-begin/api/server/passwordless-auth.ts b/book/8-begin/api/server/passwordless-auth.ts index b6e8b605..7b05d7b5 100644 --- a/book/8-begin/api/server/passwordless-auth.ts +++ b/book/8-begin/api/server/passwordless-auth.ts @@ -50,7 +50,7 @@ function setupPasswordless({ server }) { '/auth/email-login-link', passwordless.requestToken(async (email, __, callback) => { try { - const user = await User.findOne({ email }).select('_id').lean(); + const user = await User.findOne({ email }).select('_id').setOptions({ lean: true }); if (user) { callback(null, user._id); diff --git a/book/8-begin/api/server/passwordless-token-mongostore.ts b/book/8-begin/api/server/passwordless-token-mongostore.ts index 55166cba..d6546e36 100644 --- a/book/8-begin/api/server/passwordless-token-mongostore.ts +++ b/book/8-begin/api/server/passwordless-token-mongostore.ts @@ -130,7 +130,7 @@ MongoStore.prototype.storeOrUpdateByEmail = async function addEmail(email: strin throw new Error('TokenStore:addEmail called with invalid parameters'); } - const obj = await PasswordlessToken.findOne({ email }).select('uid').lean(); + const obj = await PasswordlessToken.findOne({ email }).select('uid').setOptions({ lean: true }); if (obj) { return obj.uid; diff --git a/book/8-begin/api/server/server.ts b/book/8-begin/api/server/server.ts index 4f51bd98..955ed9fa 100644 --- a/book/8-begin/api/server/server.ts +++ b/book/8-begin/api/server/server.ts @@ -64,9 +64,6 @@ server.get('*', (_, res) => { res.sendStatus(403); }); -server.listen(process.env.PORT_API, (err) => { - if (err) { - throw err; - } +server.listen(process.env.PORT_API, () => { console.log(`> Ready on ${process.env.URL_API}`); }); diff --git a/book/8-begin/api/server/utils/slugify.ts b/book/8-begin/api/server/utils/slugify.ts index e76af3c6..f2394edd 100644 --- a/book/8-begin/api/server/utils/slugify.ts +++ b/book/8-begin/api/server/utils/slugify.ts @@ -5,7 +5,7 @@ const slugify = (text) => _.kebabCase(text); async function createUniqueSlug(Model, slug, count, filter) { const obj = await Model.findOne({ slug: `${slug}-${count}`, ...filter }) .select('_id') - .lean(); + .setOptions({ lean: true }); if (!obj) { return `${slug}-${count}`; @@ -19,7 +19,7 @@ async function generateSlug(Model, name, filter = {}) { const obj = await Model.findOne({ slug: origSlug, ...filter }) .select('_id') - .lean(); + .setOptions({ lean: true }); if (!obj) { return origSlug; @@ -31,7 +31,7 @@ async function generateSlug(Model, name, filter = {}) { async function generateNumberSlug(Model, filter = {}, n = 1) { const obj = await Model.findOne({ slug: n, ...filter }) .select('_id') - .lean(); + .setOptions({ lean: true }); if (!obj) { return `${n}`; diff --git a/book/8-begin/app/server/server.ts b/book/8-begin/app/server/server.ts index e8849294..55d01719 100644 --- a/book/8-begin/app/server/server.ts +++ b/book/8-begin/app/server/server.ts @@ -31,10 +31,7 @@ app.prepare().then(() => { handle(req, res); }); - server.listen(process.env.PORT_APP, (err) => { - if (err) { - throw err; - } + server.listen(process.env.PORT_APP, () => { console.log(`> Ready on ${process.env.URL_APP}`); }); }); diff --git a/book/8-end/api/server/aws-s3.ts b/book/8-end/api/server/aws-s3.ts index 6d50475b..bf432d48 100644 --- a/book/8-end/api/server/aws-s3.ts +++ b/book/8-end/api/server/aws-s3.ts @@ -21,7 +21,7 @@ async function signRequestForUpload({ fileName, fileType, prefix, bucket }) { const s3 = new aws.S3({ apiVersion: 'latest', - region: 'us-east-1', + region: process.env.AWS_REGION, accessKeyId: process.env.AWS_ACCESSKEYID, secretAccessKey: process.env.AWS_SECRETACCESSKEY, }); diff --git a/book/8-end/api/server/aws-ses.ts b/book/8-end/api/server/aws-ses.ts index faf399eb..fff1565e 100644 --- a/book/8-end/api/server/aws-ses.ts +++ b/book/8-end/api/server/aws-ses.ts @@ -3,7 +3,7 @@ import * as aws from 'aws-sdk'; export default function sendEmail(options) { const ses = new aws.SES({ apiVersion: 'latest', - region: 'us-east-1', + region: process.env.AWS_REGION, accessKeyId: process.env.AWS_ACCESSKEYID, secretAccessKey: process.env.AWS_SECRETACCESSKEY, }); diff --git a/book/8-end/api/server/models/Discussion.ts b/book/8-end/api/server/models/Discussion.ts index 850fd152..8160be46 100644 --- a/book/8-end/api/server/models/Discussion.ts +++ b/book/8-end/api/server/models/Discussion.ts @@ -24,7 +24,11 @@ const mongoSchema = new mongoose.Schema({ type: String, required: true, }, - memberIds: [String], + memberIds: [ + { + type: String, + }, + ], createdAt: { type: Date, required: true, @@ -93,7 +97,7 @@ class DiscussionClass extends mongoose.Model { const filter: any = { teamId, memberIds: userId }; - const discussions: any[] = await this.find(filter).lean(); + const discussions: any[] = await this.find(filter).setOptions({ lean: true }); return { discussions }; } @@ -122,7 +126,7 @@ class DiscussionClass extends mongoose.Model { throw new Error('Bad data'); } - const discussion = await this.findById(id).select('teamId createdUserId').lean(); + const discussion = await this.findById(id).select('teamId createdUserId').setOptions({ lean: true }); const team = await this.checkPermissionAndGetTeam({ userId, @@ -151,7 +155,7 @@ class DiscussionClass extends mongoose.Model { throw new Error('Bad data'); } - const discussion = await this.findById(id).select('teamId').lean(); + const discussion = await this.findById(id).select('teamId').setOptions({ lean: true }); await this.checkPermissionAndGetTeam({ userId, teamId: discussion.teamId }); @@ -167,7 +171,7 @@ class DiscussionClass extends mongoose.Model { throw new Error('Bad data'); } - const team = await Team.findById(teamId).select('memberIds teamLeaderId').lean(); + const team = await Team.findById(teamId).select('memberIds teamLeaderId').setOptions({ lean: true }); if (!team || team.memberIds.indexOf(userId) === -1) { throw new Error('Team not found'); diff --git a/book/8-end/api/server/models/EmailTemplate.ts b/book/8-end/api/server/models/EmailTemplate.ts index fb8ae2e6..44cb9648 100644 --- a/book/8-end/api/server/models/EmailTemplate.ts +++ b/book/8-end/api/server/models/EmailTemplate.ts @@ -74,7 +74,7 @@ export async function insertTemplates() { ]; for (const t of templates) { - const et = await EmailTemplate.findOne({ name: t.name }).lean(); + const et = await EmailTemplate.findOne({ name: t.name }).setOptions({ lean: true }); const message = t.message.replace(/\n/g, '').replace(/[ ]+/g, ' ').trim(); if (!et) { @@ -88,7 +88,7 @@ export async function insertTemplates() { export default async function getEmailTemplate(name: string, params: any) { await insertTemplates(); - const et = await EmailTemplate.findOne({ name }).lean(); + const et = await EmailTemplate.findOne({ name }).setOptions({ lean: true }); if (!et) { throw new Error('Email Template is not found in database.'); diff --git a/book/8-end/api/server/models/Invitation.ts b/book/8-end/api/server/models/Invitation.ts index c1d15471..60cd8dcf 100644 --- a/book/8-end/api/server/models/Invitation.ts +++ b/book/8-end/api/server/models/Invitation.ts @@ -68,12 +68,12 @@ class InvitationClass extends mongoose.Model { throw new Error('Bad data'); } - const team = await Team.findById(teamId).lean(); + const team = await Team.findById(teamId).setOptions({ lean: true }); if (!team || team.teamLeaderId !== userId) { throw new Error('Team does not exist or you have no permission'); } - const registeredUser = await User.findOne({ email }).select('defaultTeamSlug').lean(); + const registeredUser = await User.findOne({ email }).select('defaultTeamSlug').setOptions({ lean: true }); if (registeredUser) { if (team.memberIds.includes(registeredUser._id.toString())) { @@ -90,7 +90,7 @@ class InvitationClass extends mongoose.Model { } let token; - const invitation = await this.findOne({ teamId, email }).select('token').lean(); + const invitation = await this.findOne({ teamId, email }).select('token').setOptions({ lean: true }); if (invitation) { token = invitation.token; @@ -125,17 +125,17 @@ class InvitationClass extends mongoose.Model { console.log('Email sending error:', err); }); - return await this.findOne({ teamId, email }).lean(); + return await this.findOne({ teamId, email }).setOptions({ lean: true }); } public static async getTeamInvitations({ userId, teamId }) { - const team = await Team.findOne({ _id: teamId }).select('teamLeaderId').lean(); + const team = await Team.findOne({ _id: teamId }).select('teamLeaderId').setOptions({ lean: true }); if (userId !== team.teamLeaderId) { throw new Error('You have no permission.'); } - return this.find({ teamId }).select('email').lean(); + return this.find({ teamId }).select('email').setOptions({ lean: true }); } public static async getTeamByToken({ token }) { @@ -143,7 +143,7 @@ class InvitationClass extends mongoose.Model { throw new Error('Bad data'); } - const invitation = await this.findOne({ token }).lean(); + const invitation = await this.findOne({ token }).setOptions({ lean: true }); if (!invitation) { throw new Error('Invitation not found'); @@ -151,7 +151,7 @@ class InvitationClass extends mongoose.Model { const team = await Team.findById(invitation.teamId) .select('name slug avatarUrl memberIds') - .lean(); + .setOptions({ lean: true }); if (!team) { throw new Error('Team does not exist'); @@ -165,7 +165,7 @@ class InvitationClass extends mongoose.Model { throw new Error('Bad data'); } - const invitation = await this.findOne({ token }).lean(); + const invitation = await this.findOne({ token }).setOptions({ lean: true }); if (!invitation) { throw new Error('Invitation not found'); @@ -173,7 +173,7 @@ class InvitationClass extends mongoose.Model { const team = await Team.findById(invitation.teamId) .select('name slug avatarUrl memberIds') - .lean(); + .setOptions({ lean: true }); if (!team) { throw new Error('Team does not exist'); @@ -189,7 +189,7 @@ class InvitationClass extends mongoose.Model { throw new Error('Bad data'); } - const invitation = await this.findOne({ token }).lean(); + const invitation = await this.findOne({ token }).setOptions({ lean: true }); if (!invitation || invitation.email !== user.email) { throw new Error('Invitation not found'); @@ -199,7 +199,7 @@ class InvitationClass extends mongoose.Model { const team = await Team.findById(invitation.teamId) .select('memberIds slug teamLeaderId') - .lean(); + .setOptions({ lean: true }); if (!team) { throw new Error('Team does not exist'); diff --git a/book/8-end/api/server/models/Post.ts b/book/8-end/api/server/models/Post.ts index ec47eab1..44e695e4 100644 --- a/book/8-end/api/server/models/Post.ts +++ b/book/8-end/api/server/models/Post.ts @@ -126,7 +126,7 @@ class PostClass extends mongoose.Model { const filter: any = { discussionId }; - const posts: any[] = await this.find(filter).sort({ createdAt: 1 }).lean(); + const posts: any[] = await this.find(filter).sort({ createdAt: 1 }).setOptions({ lean: true }); return posts; } @@ -156,7 +156,7 @@ class PostClass extends mongoose.Model { throw new Error('Bad data'); } - const post = await this.findById(id).select('createdUserId discussionId').lean(); + const post = await this.findById(id).select('createdUserId discussionId').setOptions({ lean: true }); await this.checkPermissionAndGetTeamAndDiscussion({ userId, @@ -180,7 +180,7 @@ class PostClass extends mongoose.Model { throw new Error('Bad data'); } - const post = await this.findById(id).select('createdUserId discussionId content').lean(); + const post = await this.findById(id).select('createdUserId discussionId content').setOptions({ lean: true }); await this.checkPermissionAndGetTeamAndDiscussion({ userId, @@ -206,7 +206,7 @@ class PostClass extends mongoose.Model { const discussion = await Discussion.findById(discussionId) .select('teamId memberIds slug') - .lean(); + .setOptions({ lean: true }); if (!discussion) { throw new Error('Discussion not found'); @@ -216,7 +216,7 @@ class PostClass extends mongoose.Model { throw new Error('Permission denied'); } - const team = await Team.findById(discussion.teamId).select('memberIds slug').lean(); + const team = await Team.findById(discussion.teamId).select('memberIds slug').setOptions({ lean: true }); if (!team || team.memberIds.indexOf(userId) === -1) { throw new Error('Team not found'); diff --git a/book/8-end/api/server/models/Team.ts b/book/8-end/api/server/models/Team.ts index f26f9e7f..37697b26 100644 --- a/book/8-end/api/server/models/Team.ts +++ b/book/8-end/api/server/models/Team.ts @@ -24,10 +24,12 @@ const mongoSchema = new mongoose.Schema({ type: String, required: true, }, - memberIds: { - type: [String], - required: true, - }, + memberIds: [ + { + type: String, + required: true, + }, + ], defaultTeam: { type: Boolean, default: false, @@ -128,12 +130,12 @@ class TeamClass extends mongoose.Model { await this.updateOne({ _id: teamId }, { $set: modifier }, { runValidators: true }); - return this.findById(teamId, 'name avatarUrl slug defaultTeam').lean(); + return this.findById(teamId, 'name avatarUrl slug defaultTeam').setOptions({ lean: true }); } public static getAllTeamsForUser(userId: string) { console.log(`userId:${userId}`); - return this.find({ memberIds: userId }).lean(); + return this.find({ memberIds: userId }).setOptions({ lean: true }); } public static async removeMember({ teamId, teamLeaderId, userId }) { diff --git a/book/8-end/api/server/models/User.ts b/book/8-end/api/server/models/User.ts index c0415b1f..4fe818b0 100644 --- a/book/8-end/api/server/models/User.ts +++ b/book/8-end/api/server/models/User.ts @@ -120,7 +120,7 @@ class UserClass extends mongoose.Model { public static async getUserBySlug({ slug }) { console.log('Static method: getUserBySlug'); - return this.findOne({ slug }, 'email displayName avatarUrl').lean(); + return this.findOne({ slug }, 'email displayName avatarUrl').setOptions({ lean: true }); } public static async updateProfile({ userId, name, avatarUrl }) { @@ -139,7 +139,7 @@ class UserClass extends mongoose.Model { return this.findByIdAndUpdate(userId, { $set: modifier }, { new: true, runValidators: true }) .select('displayName avatarUrl slug') - .lean(); + .setOptions({ lean: true }); } public static publicFields(): string[] { @@ -165,7 +165,7 @@ class UserClass extends mongoose.Model { }) { const user = await this.findOne({ email }) .select([...this.publicFields(), 'googleId'].join(' ')) - .lean(); + .setOptions({ lean: true }); if (user) { if (_.isEmpty(googleToken) && user.googleId) { @@ -227,7 +227,7 @@ class UserClass extends mongoose.Model { } public static async signInOrSignUpByPasswordless({ uid, email }) { - const user = await this.findOne({ email }).select(this.publicFields().join(' ')).lean(); + const user = await this.findOne({ email }).select(this.publicFields().join(' ')).setOptions({ lean: true }); if (user) { throw Error('User already exists'); @@ -278,7 +278,7 @@ class UserClass extends mongoose.Model { return this.find({ _id: { $in: team.memberIds } }) .select(this.publicFields().join(' ')) - .lean(); + .setOptions({ lean: true }); } private static async checkPermissionAndGetTeam({ userId, teamId }) { @@ -288,7 +288,7 @@ class UserClass extends mongoose.Model { throw new Error('Bad data'); } - const team = await Team.findById(teamId).select('memberIds').lean(); + const team = await Team.findById(teamId).select('memberIds').setOptions({ lean: true }); if (!team || team.memberIds.indexOf(userId) === -1) { throw new Error('Team not found'); diff --git a/book/8-end/api/server/passwordless-auth.ts b/book/8-end/api/server/passwordless-auth.ts index 3b3292b4..ac354223 100644 --- a/book/8-end/api/server/passwordless-auth.ts +++ b/book/8-end/api/server/passwordless-auth.ts @@ -50,7 +50,7 @@ function setupPasswordless({ server }) { '/auth/email-login-link', passwordless.requestToken(async (email, __, callback) => { try { - const user = await User.findOne({ email }).select('_id').lean(); + const user = await User.findOne({ email }).select('_id').setOptions({ lean: true }); if (user) { callback(null, user._id); diff --git a/book/8-end/api/server/passwordless-token-mongostore.ts b/book/8-end/api/server/passwordless-token-mongostore.ts index 55166cba..d6546e36 100644 --- a/book/8-end/api/server/passwordless-token-mongostore.ts +++ b/book/8-end/api/server/passwordless-token-mongostore.ts @@ -130,7 +130,7 @@ MongoStore.prototype.storeOrUpdateByEmail = async function addEmail(email: strin throw new Error('TokenStore:addEmail called with invalid parameters'); } - const obj = await PasswordlessToken.findOne({ email }).select('uid').lean(); + const obj = await PasswordlessToken.findOne({ email }).select('uid').setOptions({ lean: true }); if (obj) { return obj.uid; diff --git a/book/8-end/api/server/utils/slugify.ts b/book/8-end/api/server/utils/slugify.ts index e76af3c6..f2394edd 100644 --- a/book/8-end/api/server/utils/slugify.ts +++ b/book/8-end/api/server/utils/slugify.ts @@ -5,7 +5,7 @@ const slugify = (text) => _.kebabCase(text); async function createUniqueSlug(Model, slug, count, filter) { const obj = await Model.findOne({ slug: `${slug}-${count}`, ...filter }) .select('_id') - .lean(); + .setOptions({ lean: true }); if (!obj) { return `${slug}-${count}`; @@ -19,7 +19,7 @@ async function generateSlug(Model, name, filter = {}) { const obj = await Model.findOne({ slug: origSlug, ...filter }) .select('_id') - .lean(); + .setOptions({ lean: true }); if (!obj) { return origSlug; @@ -31,7 +31,7 @@ async function generateSlug(Model, name, filter = {}) { async function generateNumberSlug(Model, filter = {}, n = 1) { const obj = await Model.findOne({ slug: n, ...filter }) .select('_id') - .lean(); + .setOptions({ lean: true }); if (!obj) { return `${n}`; diff --git a/book/9-begin/api/server/aws-s3.ts b/book/9-begin/api/server/aws-s3.ts index 6d50475b..bf432d48 100644 --- a/book/9-begin/api/server/aws-s3.ts +++ b/book/9-begin/api/server/aws-s3.ts @@ -21,7 +21,7 @@ async function signRequestForUpload({ fileName, fileType, prefix, bucket }) { const s3 = new aws.S3({ apiVersion: 'latest', - region: 'us-east-1', + region: process.env.AWS_REGION, accessKeyId: process.env.AWS_ACCESSKEYID, secretAccessKey: process.env.AWS_SECRETACCESSKEY, }); diff --git a/book/9-begin/api/server/aws-ses.ts b/book/9-begin/api/server/aws-ses.ts index faf399eb..fff1565e 100644 --- a/book/9-begin/api/server/aws-ses.ts +++ b/book/9-begin/api/server/aws-ses.ts @@ -3,7 +3,7 @@ import * as aws from 'aws-sdk'; export default function sendEmail(options) { const ses = new aws.SES({ apiVersion: 'latest', - region: 'us-east-1', + region: process.env.AWS_REGION, accessKeyId: process.env.AWS_ACCESSKEYID, secretAccessKey: process.env.AWS_SECRETACCESSKEY, }); diff --git a/book/9-begin/api/server/models/Discussion.ts b/book/9-begin/api/server/models/Discussion.ts index 850fd152..8160be46 100644 --- a/book/9-begin/api/server/models/Discussion.ts +++ b/book/9-begin/api/server/models/Discussion.ts @@ -24,7 +24,11 @@ const mongoSchema = new mongoose.Schema({ type: String, required: true, }, - memberIds: [String], + memberIds: [ + { + type: String, + }, + ], createdAt: { type: Date, required: true, @@ -93,7 +97,7 @@ class DiscussionClass extends mongoose.Model { const filter: any = { teamId, memberIds: userId }; - const discussions: any[] = await this.find(filter).lean(); + const discussions: any[] = await this.find(filter).setOptions({ lean: true }); return { discussions }; } @@ -122,7 +126,7 @@ class DiscussionClass extends mongoose.Model { throw new Error('Bad data'); } - const discussion = await this.findById(id).select('teamId createdUserId').lean(); + const discussion = await this.findById(id).select('teamId createdUserId').setOptions({ lean: true }); const team = await this.checkPermissionAndGetTeam({ userId, @@ -151,7 +155,7 @@ class DiscussionClass extends mongoose.Model { throw new Error('Bad data'); } - const discussion = await this.findById(id).select('teamId').lean(); + const discussion = await this.findById(id).select('teamId').setOptions({ lean: true }); await this.checkPermissionAndGetTeam({ userId, teamId: discussion.teamId }); @@ -167,7 +171,7 @@ class DiscussionClass extends mongoose.Model { throw new Error('Bad data'); } - const team = await Team.findById(teamId).select('memberIds teamLeaderId').lean(); + const team = await Team.findById(teamId).select('memberIds teamLeaderId').setOptions({ lean: true }); if (!team || team.memberIds.indexOf(userId) === -1) { throw new Error('Team not found'); diff --git a/book/9-begin/api/server/models/EmailTemplate.ts b/book/9-begin/api/server/models/EmailTemplate.ts index fb8ae2e6..44cb9648 100644 --- a/book/9-begin/api/server/models/EmailTemplate.ts +++ b/book/9-begin/api/server/models/EmailTemplate.ts @@ -74,7 +74,7 @@ export async function insertTemplates() { ]; for (const t of templates) { - const et = await EmailTemplate.findOne({ name: t.name }).lean(); + const et = await EmailTemplate.findOne({ name: t.name }).setOptions({ lean: true }); const message = t.message.replace(/\n/g, '').replace(/[ ]+/g, ' ').trim(); if (!et) { @@ -88,7 +88,7 @@ export async function insertTemplates() { export default async function getEmailTemplate(name: string, params: any) { await insertTemplates(); - const et = await EmailTemplate.findOne({ name }).lean(); + const et = await EmailTemplate.findOne({ name }).setOptions({ lean: true }); if (!et) { throw new Error('Email Template is not found in database.'); diff --git a/book/9-begin/api/server/models/Invitation.ts b/book/9-begin/api/server/models/Invitation.ts index c1d15471..60cd8dcf 100644 --- a/book/9-begin/api/server/models/Invitation.ts +++ b/book/9-begin/api/server/models/Invitation.ts @@ -68,12 +68,12 @@ class InvitationClass extends mongoose.Model { throw new Error('Bad data'); } - const team = await Team.findById(teamId).lean(); + const team = await Team.findById(teamId).setOptions({ lean: true }); if (!team || team.teamLeaderId !== userId) { throw new Error('Team does not exist or you have no permission'); } - const registeredUser = await User.findOne({ email }).select('defaultTeamSlug').lean(); + const registeredUser = await User.findOne({ email }).select('defaultTeamSlug').setOptions({ lean: true }); if (registeredUser) { if (team.memberIds.includes(registeredUser._id.toString())) { @@ -90,7 +90,7 @@ class InvitationClass extends mongoose.Model { } let token; - const invitation = await this.findOne({ teamId, email }).select('token').lean(); + const invitation = await this.findOne({ teamId, email }).select('token').setOptions({ lean: true }); if (invitation) { token = invitation.token; @@ -125,17 +125,17 @@ class InvitationClass extends mongoose.Model { console.log('Email sending error:', err); }); - return await this.findOne({ teamId, email }).lean(); + return await this.findOne({ teamId, email }).setOptions({ lean: true }); } public static async getTeamInvitations({ userId, teamId }) { - const team = await Team.findOne({ _id: teamId }).select('teamLeaderId').lean(); + const team = await Team.findOne({ _id: teamId }).select('teamLeaderId').setOptions({ lean: true }); if (userId !== team.teamLeaderId) { throw new Error('You have no permission.'); } - return this.find({ teamId }).select('email').lean(); + return this.find({ teamId }).select('email').setOptions({ lean: true }); } public static async getTeamByToken({ token }) { @@ -143,7 +143,7 @@ class InvitationClass extends mongoose.Model { throw new Error('Bad data'); } - const invitation = await this.findOne({ token }).lean(); + const invitation = await this.findOne({ token }).setOptions({ lean: true }); if (!invitation) { throw new Error('Invitation not found'); @@ -151,7 +151,7 @@ class InvitationClass extends mongoose.Model { const team = await Team.findById(invitation.teamId) .select('name slug avatarUrl memberIds') - .lean(); + .setOptions({ lean: true }); if (!team) { throw new Error('Team does not exist'); @@ -165,7 +165,7 @@ class InvitationClass extends mongoose.Model { throw new Error('Bad data'); } - const invitation = await this.findOne({ token }).lean(); + const invitation = await this.findOne({ token }).setOptions({ lean: true }); if (!invitation) { throw new Error('Invitation not found'); @@ -173,7 +173,7 @@ class InvitationClass extends mongoose.Model { const team = await Team.findById(invitation.teamId) .select('name slug avatarUrl memberIds') - .lean(); + .setOptions({ lean: true }); if (!team) { throw new Error('Team does not exist'); @@ -189,7 +189,7 @@ class InvitationClass extends mongoose.Model { throw new Error('Bad data'); } - const invitation = await this.findOne({ token }).lean(); + const invitation = await this.findOne({ token }).setOptions({ lean: true }); if (!invitation || invitation.email !== user.email) { throw new Error('Invitation not found'); @@ -199,7 +199,7 @@ class InvitationClass extends mongoose.Model { const team = await Team.findById(invitation.teamId) .select('memberIds slug teamLeaderId') - .lean(); + .setOptions({ lean: true }); if (!team) { throw new Error('Team does not exist'); diff --git a/book/9-begin/api/server/models/Post.ts b/book/9-begin/api/server/models/Post.ts index ec47eab1..44e695e4 100644 --- a/book/9-begin/api/server/models/Post.ts +++ b/book/9-begin/api/server/models/Post.ts @@ -126,7 +126,7 @@ class PostClass extends mongoose.Model { const filter: any = { discussionId }; - const posts: any[] = await this.find(filter).sort({ createdAt: 1 }).lean(); + const posts: any[] = await this.find(filter).sort({ createdAt: 1 }).setOptions({ lean: true }); return posts; } @@ -156,7 +156,7 @@ class PostClass extends mongoose.Model { throw new Error('Bad data'); } - const post = await this.findById(id).select('createdUserId discussionId').lean(); + const post = await this.findById(id).select('createdUserId discussionId').setOptions({ lean: true }); await this.checkPermissionAndGetTeamAndDiscussion({ userId, @@ -180,7 +180,7 @@ class PostClass extends mongoose.Model { throw new Error('Bad data'); } - const post = await this.findById(id).select('createdUserId discussionId content').lean(); + const post = await this.findById(id).select('createdUserId discussionId content').setOptions({ lean: true }); await this.checkPermissionAndGetTeamAndDiscussion({ userId, @@ -206,7 +206,7 @@ class PostClass extends mongoose.Model { const discussion = await Discussion.findById(discussionId) .select('teamId memberIds slug') - .lean(); + .setOptions({ lean: true }); if (!discussion) { throw new Error('Discussion not found'); @@ -216,7 +216,7 @@ class PostClass extends mongoose.Model { throw new Error('Permission denied'); } - const team = await Team.findById(discussion.teamId).select('memberIds slug').lean(); + const team = await Team.findById(discussion.teamId).select('memberIds slug').setOptions({ lean: true }); if (!team || team.memberIds.indexOf(userId) === -1) { throw new Error('Team not found'); diff --git a/book/9-begin/api/server/models/Team.ts b/book/9-begin/api/server/models/Team.ts index f26f9e7f..37697b26 100644 --- a/book/9-begin/api/server/models/Team.ts +++ b/book/9-begin/api/server/models/Team.ts @@ -24,10 +24,12 @@ const mongoSchema = new mongoose.Schema({ type: String, required: true, }, - memberIds: { - type: [String], - required: true, - }, + memberIds: [ + { + type: String, + required: true, + }, + ], defaultTeam: { type: Boolean, default: false, @@ -128,12 +130,12 @@ class TeamClass extends mongoose.Model { await this.updateOne({ _id: teamId }, { $set: modifier }, { runValidators: true }); - return this.findById(teamId, 'name avatarUrl slug defaultTeam').lean(); + return this.findById(teamId, 'name avatarUrl slug defaultTeam').setOptions({ lean: true }); } public static getAllTeamsForUser(userId: string) { console.log(`userId:${userId}`); - return this.find({ memberIds: userId }).lean(); + return this.find({ memberIds: userId }).setOptions({ lean: true }); } public static async removeMember({ teamId, teamLeaderId, userId }) { diff --git a/book/9-begin/api/server/models/User.ts b/book/9-begin/api/server/models/User.ts index c0415b1f..4fe818b0 100644 --- a/book/9-begin/api/server/models/User.ts +++ b/book/9-begin/api/server/models/User.ts @@ -120,7 +120,7 @@ class UserClass extends mongoose.Model { public static async getUserBySlug({ slug }) { console.log('Static method: getUserBySlug'); - return this.findOne({ slug }, 'email displayName avatarUrl').lean(); + return this.findOne({ slug }, 'email displayName avatarUrl').setOptions({ lean: true }); } public static async updateProfile({ userId, name, avatarUrl }) { @@ -139,7 +139,7 @@ class UserClass extends mongoose.Model { return this.findByIdAndUpdate(userId, { $set: modifier }, { new: true, runValidators: true }) .select('displayName avatarUrl slug') - .lean(); + .setOptions({ lean: true }); } public static publicFields(): string[] { @@ -165,7 +165,7 @@ class UserClass extends mongoose.Model { }) { const user = await this.findOne({ email }) .select([...this.publicFields(), 'googleId'].join(' ')) - .lean(); + .setOptions({ lean: true }); if (user) { if (_.isEmpty(googleToken) && user.googleId) { @@ -227,7 +227,7 @@ class UserClass extends mongoose.Model { } public static async signInOrSignUpByPasswordless({ uid, email }) { - const user = await this.findOne({ email }).select(this.publicFields().join(' ')).lean(); + const user = await this.findOne({ email }).select(this.publicFields().join(' ')).setOptions({ lean: true }); if (user) { throw Error('User already exists'); @@ -278,7 +278,7 @@ class UserClass extends mongoose.Model { return this.find({ _id: { $in: team.memberIds } }) .select(this.publicFields().join(' ')) - .lean(); + .setOptions({ lean: true }); } private static async checkPermissionAndGetTeam({ userId, teamId }) { @@ -288,7 +288,7 @@ class UserClass extends mongoose.Model { throw new Error('Bad data'); } - const team = await Team.findById(teamId).select('memberIds').lean(); + const team = await Team.findById(teamId).select('memberIds').setOptions({ lean: true }); if (!team || team.memberIds.indexOf(userId) === -1) { throw new Error('Team not found'); diff --git a/book/9-begin/api/server/passwordless-auth.ts b/book/9-begin/api/server/passwordless-auth.ts index 3b3292b4..ac354223 100644 --- a/book/9-begin/api/server/passwordless-auth.ts +++ b/book/9-begin/api/server/passwordless-auth.ts @@ -50,7 +50,7 @@ function setupPasswordless({ server }) { '/auth/email-login-link', passwordless.requestToken(async (email, __, callback) => { try { - const user = await User.findOne({ email }).select('_id').lean(); + const user = await User.findOne({ email }).select('_id').setOptions({ lean: true }); if (user) { callback(null, user._id); diff --git a/book/9-begin/api/server/passwordless-token-mongostore.ts b/book/9-begin/api/server/passwordless-token-mongostore.ts index 55166cba..d6546e36 100644 --- a/book/9-begin/api/server/passwordless-token-mongostore.ts +++ b/book/9-begin/api/server/passwordless-token-mongostore.ts @@ -130,7 +130,7 @@ MongoStore.prototype.storeOrUpdateByEmail = async function addEmail(email: strin throw new Error('TokenStore:addEmail called with invalid parameters'); } - const obj = await PasswordlessToken.findOne({ email }).select('uid').lean(); + const obj = await PasswordlessToken.findOne({ email }).select('uid').setOptions({ lean: true }); if (obj) { return obj.uid; diff --git a/book/9-begin/api/server/utils/slugify.ts b/book/9-begin/api/server/utils/slugify.ts index e76af3c6..f2394edd 100644 --- a/book/9-begin/api/server/utils/slugify.ts +++ b/book/9-begin/api/server/utils/slugify.ts @@ -5,7 +5,7 @@ const slugify = (text) => _.kebabCase(text); async function createUniqueSlug(Model, slug, count, filter) { const obj = await Model.findOne({ slug: `${slug}-${count}`, ...filter }) .select('_id') - .lean(); + .setOptions({ lean: true }); if (!obj) { return `${slug}-${count}`; @@ -19,7 +19,7 @@ async function generateSlug(Model, name, filter = {}) { const obj = await Model.findOne({ slug: origSlug, ...filter }) .select('_id') - .lean(); + .setOptions({ lean: true }); if (!obj) { return origSlug; @@ -31,7 +31,7 @@ async function generateSlug(Model, name, filter = {}) { async function generateNumberSlug(Model, filter = {}, n = 1) { const obj = await Model.findOne({ slug: n, ...filter }) .select('_id') - .lean(); + .setOptions({ lean: true }); if (!obj) { return `${n}`; diff --git a/book/9-end/api/server/api/team-leader.ts b/book/9-end/api/server/api/team-leader.ts index db9eecc5..fbfb0082 100644 --- a/book/9-end/api/server/api/team-leader.ts +++ b/book/9-end/api/server/api/team-leader.ts @@ -93,11 +93,13 @@ router.post('/stripe/fetch-checkout-session', async (req, res, next) => { try { const { mode, teamId } = req.body; - const user = await User.findById(req.user.id).select(['stripeCustomer', 'email']).lean(); + const user = await User.findById(req.user.id) + .select(['stripeCustomer', 'email']) + .setOptions({ lean: true }); const team = await Team.findById(teamId) .select(['stripeSubscription', 'slug', 'teamLeaderId']) - .lean(); + .setOptions({ lean: true }); if (!user || !team || team.teamLeaderId !== req.user.id) { throw new Error('Permission denied'); diff --git a/book/9-end/api/server/aws-s3.ts b/book/9-end/api/server/aws-s3.ts index 6d50475b..bf432d48 100644 --- a/book/9-end/api/server/aws-s3.ts +++ b/book/9-end/api/server/aws-s3.ts @@ -21,7 +21,7 @@ async function signRequestForUpload({ fileName, fileType, prefix, bucket }) { const s3 = new aws.S3({ apiVersion: 'latest', - region: 'us-east-1', + region: process.env.AWS_REGION, accessKeyId: process.env.AWS_ACCESSKEYID, secretAccessKey: process.env.AWS_SECRETACCESSKEY, }); diff --git a/book/9-end/api/server/aws-ses.ts b/book/9-end/api/server/aws-ses.ts index faf399eb..fff1565e 100644 --- a/book/9-end/api/server/aws-ses.ts +++ b/book/9-end/api/server/aws-ses.ts @@ -3,7 +3,7 @@ import * as aws from 'aws-sdk'; export default function sendEmail(options) { const ses = new aws.SES({ apiVersion: 'latest', - region: 'us-east-1', + region: process.env.AWS_REGION, accessKeyId: process.env.AWS_ACCESSKEYID, secretAccessKey: process.env.AWS_SECRETACCESSKEY, }); diff --git a/book/9-end/api/server/models/Discussion.ts b/book/9-end/api/server/models/Discussion.ts index e9931e9d..5b2c78e8 100644 --- a/book/9-end/api/server/models/Discussion.ts +++ b/book/9-end/api/server/models/Discussion.ts @@ -24,7 +24,11 @@ const mongoSchema = new mongoose.Schema({ type: String, required: true, }, - memberIds: [String], + memberIds: [ + { + type: String, + }, + ], createdAt: { type: Date, required: true, @@ -104,7 +108,7 @@ class DiscussionClass extends mongoose.Model { const filter: any = { teamId, memberIds: userId }; - const discussions: any[] = await this.find(filter).lean(); + const discussions: any[] = await this.find(filter).setOptions({ lean: true }); return { discussions }; } @@ -134,7 +138,9 @@ class DiscussionClass extends mongoose.Model { throw new Error('Bad data'); } - const discussion = await this.findById(id).select('teamId createdUserId').lean(); + const discussion = await this.findById(id) + .select('teamId createdUserId') + .setOptions({ lean: true }); const team = await this.checkPermissionAndGetTeam({ userId, @@ -164,7 +170,7 @@ class DiscussionClass extends mongoose.Model { throw new Error('Bad data'); } - const discussion = await this.findById(id).select('teamId').lean(); + const discussion = await this.findById(id).select('teamId').setOptions({ lean: true }); await this.checkPermissionAndGetTeam({ userId, teamId: discussion.teamId }); @@ -180,7 +186,9 @@ class DiscussionClass extends mongoose.Model { throw new Error('Bad data'); } - const team = await Team.findById(teamId).select('memberIds teamLeaderId').lean(); + const team = await Team.findById(teamId) + .select('memberIds teamLeaderId') + .setOptions({ lean: true }); if (!team || team.memberIds.indexOf(userId) === -1) { throw new Error('Team not found'); diff --git a/book/9-end/api/server/models/EmailTemplate.ts b/book/9-end/api/server/models/EmailTemplate.ts index 54ca2241..db9089d7 100644 --- a/book/9-end/api/server/models/EmailTemplate.ts +++ b/book/9-end/api/server/models/EmailTemplate.ts @@ -74,7 +74,7 @@ export async function insertTemplates() { ]; for (const t of templates) { - const et = await EmailTemplate.findOne({ name: t.name }).lean(); + const et = await EmailTemplate.findOne({ name: t.name }).setOptions({ lean: true }); const message = t.message.replace(/\n/g, '').replace(/[ ]+/g, ' ').trim(); if (!et) { @@ -88,7 +88,7 @@ export async function insertTemplates() { export default async function getEmailTemplate(name: string, params: any) { await insertTemplates(); - const et = await EmailTemplate.findOne({ name }).lean(); + const et = await EmailTemplate.findOne({ name }).setOptions({ lean: true }); if (!et) { throw new Error('Email Template is not found in database.'); diff --git a/book/9-end/api/server/models/Invitation.ts b/book/9-end/api/server/models/Invitation.ts index c1d15471..60cd8dcf 100644 --- a/book/9-end/api/server/models/Invitation.ts +++ b/book/9-end/api/server/models/Invitation.ts @@ -68,12 +68,12 @@ class InvitationClass extends mongoose.Model { throw new Error('Bad data'); } - const team = await Team.findById(teamId).lean(); + const team = await Team.findById(teamId).setOptions({ lean: true }); if (!team || team.teamLeaderId !== userId) { throw new Error('Team does not exist or you have no permission'); } - const registeredUser = await User.findOne({ email }).select('defaultTeamSlug').lean(); + const registeredUser = await User.findOne({ email }).select('defaultTeamSlug').setOptions({ lean: true }); if (registeredUser) { if (team.memberIds.includes(registeredUser._id.toString())) { @@ -90,7 +90,7 @@ class InvitationClass extends mongoose.Model { } let token; - const invitation = await this.findOne({ teamId, email }).select('token').lean(); + const invitation = await this.findOne({ teamId, email }).select('token').setOptions({ lean: true }); if (invitation) { token = invitation.token; @@ -125,17 +125,17 @@ class InvitationClass extends mongoose.Model { console.log('Email sending error:', err); }); - return await this.findOne({ teamId, email }).lean(); + return await this.findOne({ teamId, email }).setOptions({ lean: true }); } public static async getTeamInvitations({ userId, teamId }) { - const team = await Team.findOne({ _id: teamId }).select('teamLeaderId').lean(); + const team = await Team.findOne({ _id: teamId }).select('teamLeaderId').setOptions({ lean: true }); if (userId !== team.teamLeaderId) { throw new Error('You have no permission.'); } - return this.find({ teamId }).select('email').lean(); + return this.find({ teamId }).select('email').setOptions({ lean: true }); } public static async getTeamByToken({ token }) { @@ -143,7 +143,7 @@ class InvitationClass extends mongoose.Model { throw new Error('Bad data'); } - const invitation = await this.findOne({ token }).lean(); + const invitation = await this.findOne({ token }).setOptions({ lean: true }); if (!invitation) { throw new Error('Invitation not found'); @@ -151,7 +151,7 @@ class InvitationClass extends mongoose.Model { const team = await Team.findById(invitation.teamId) .select('name slug avatarUrl memberIds') - .lean(); + .setOptions({ lean: true }); if (!team) { throw new Error('Team does not exist'); @@ -165,7 +165,7 @@ class InvitationClass extends mongoose.Model { throw new Error('Bad data'); } - const invitation = await this.findOne({ token }).lean(); + const invitation = await this.findOne({ token }).setOptions({ lean: true }); if (!invitation) { throw new Error('Invitation not found'); @@ -173,7 +173,7 @@ class InvitationClass extends mongoose.Model { const team = await Team.findById(invitation.teamId) .select('name slug avatarUrl memberIds') - .lean(); + .setOptions({ lean: true }); if (!team) { throw new Error('Team does not exist'); @@ -189,7 +189,7 @@ class InvitationClass extends mongoose.Model { throw new Error('Bad data'); } - const invitation = await this.findOne({ token }).lean(); + const invitation = await this.findOne({ token }).setOptions({ lean: true }); if (!invitation || invitation.email !== user.email) { throw new Error('Invitation not found'); @@ -199,7 +199,7 @@ class InvitationClass extends mongoose.Model { const team = await Team.findById(invitation.teamId) .select('memberIds slug teamLeaderId') - .lean(); + .setOptions({ lean: true }); if (!team) { throw new Error('Team does not exist'); diff --git a/book/9-end/api/server/models/Post.ts b/book/9-end/api/server/models/Post.ts index ec47eab1..e612a735 100644 --- a/book/9-end/api/server/models/Post.ts +++ b/book/9-end/api/server/models/Post.ts @@ -126,7 +126,7 @@ class PostClass extends mongoose.Model { const filter: any = { discussionId }; - const posts: any[] = await this.find(filter).sort({ createdAt: 1 }).lean(); + const posts: any[] = await this.find(filter).sort({ createdAt: 1 }).setOptions({ lean: true }); return posts; } @@ -156,7 +156,9 @@ class PostClass extends mongoose.Model { throw new Error('Bad data'); } - const post = await this.findById(id).select('createdUserId discussionId').lean(); + const post = await this.findById(id) + .select('createdUserId discussionId') + .setOptions({ lean: true }); await this.checkPermissionAndGetTeamAndDiscussion({ userId, @@ -180,7 +182,9 @@ class PostClass extends mongoose.Model { throw new Error('Bad data'); } - const post = await this.findById(id).select('createdUserId discussionId content').lean(); + const post = await this.findById(id) + .select('createdUserId discussionId content') + .setOptions({ lean: true }); await this.checkPermissionAndGetTeamAndDiscussion({ userId, @@ -206,7 +210,7 @@ class PostClass extends mongoose.Model { const discussion = await Discussion.findById(discussionId) .select('teamId memberIds slug') - .lean(); + .setOptions({ lean: true }); if (!discussion) { throw new Error('Discussion not found'); @@ -216,7 +220,9 @@ class PostClass extends mongoose.Model { throw new Error('Permission denied'); } - const team = await Team.findById(discussion.teamId).select('memberIds slug').lean(); + const team = await Team.findById(discussion.teamId) + .select('memberIds slug') + .setOptions({ lean: true }); if (!team || team.memberIds.indexOf(userId) === -1) { throw new Error('Team not found'); diff --git a/book/9-end/api/server/models/Team.ts b/book/9-end/api/server/models/Team.ts index 49a2eb2f..047cc105 100644 --- a/book/9-end/api/server/models/Team.ts +++ b/book/9-end/api/server/models/Team.ts @@ -26,10 +26,12 @@ const mongoSchema = new mongoose.Schema({ type: String, required: true, }, - memberIds: { - type: [String], - required: true, - }, + memberIds: [ + { + type: String, + required: true, + }, + ], defaultTeam: { type: Boolean, default: false, @@ -183,12 +185,12 @@ class TeamClass extends mongoose.Model { await this.updateOne({ _id: teamId }, { $set: modifier }, { runValidators: true }); - return this.findById(teamId, 'name avatarUrl slug defaultTeam').lean(); + return this.findById(teamId, 'name avatarUrl slug defaultTeam').setOptions({ lean: true }); } public static getAllTeamsForUser(userId: string) { console.log(`userId:${userId}`); - return this.find({ memberIds: userId }).lean(); + return this.find({ memberIds: userId }).setOptions({ lean: true }); } public static async removeMember({ teamId, teamLeaderId, userId }) { @@ -259,13 +261,13 @@ class TeamClass extends mongoose.Model { { new: true, runValidators: true }, ) .select('isSubscriptionActive stripeSubscription') - .lean(); + .setOptions({ lean: true }); } public static async cancelSubscriptionAfterFailedPayment({ subscriptionId }) { const team: any = await this.find({ 'stripeSubscription.id': subscriptionId }) .select('teamLeaderId isSubscriptionActive stripeSubscription isPaymentFailed') - .lean(); + .setOptions({ lean: true }); if (!team.isSubscriptionActive) { throw new Error('Team is already unsubscribed.'); } @@ -285,7 +287,7 @@ class TeamClass extends mongoose.Model { { new: true, runValidators: true }, ) .select('isSubscriptionActive stripeSubscription isPaymentFailed') - .lean(); + .setOptions({ lean: true }); } } diff --git a/book/9-end/api/server/models/User.ts b/book/9-end/api/server/models/User.ts index 9dd1158d..9a91292a 100644 --- a/book/9-end/api/server/models/User.ts +++ b/book/9-end/api/server/models/User.ts @@ -221,7 +221,7 @@ class UserClass extends mongoose.Model { public static async getUserBySlug({ slug }) { console.log('Static method: getUserBySlug'); - return this.findOne({ slug }, 'email displayName avatarUrl').lean(); + return this.findOne({ slug }, 'email displayName avatarUrl').setOptions({ lean: true }); } public static async updateProfile({ userId, name, avatarUrl }) { @@ -240,7 +240,7 @@ class UserClass extends mongoose.Model { return this.findByIdAndUpdate(userId, { $set: modifier }, { new: true, runValidators: true }) .select('displayName avatarUrl slug') - .lean(); + .setOptions({ lean: true }); } public static publicFields(): string[] { @@ -269,7 +269,7 @@ class UserClass extends mongoose.Model { }) { const user = await this.findOne({ email }) .select([...this.publicFields(), 'googleId'].join(' ')) - .lean(); + .setOptions({ lean: true }); if (user) { if (_.isEmpty(googleToken) && user.googleId) { @@ -331,7 +331,9 @@ class UserClass extends mongoose.Model { } public static async signInOrSignUpByPasswordless({ uid, email }) { - const user = await this.findOne({ email }).select(this.publicFields().join(' ')).lean(); + const user = await this.findOne({ email }) + .select(this.publicFields().join(' ')) + .setOptions({ lean: true }); if (user) { throw Error('User already exists'); @@ -382,7 +384,7 @@ class UserClass extends mongoose.Model { return this.find({ _id: { $in: team.memberIds } }) .select(this.publicFields().join(' ')) - .lean(); + .setOptions({ lean: true }); } public static async saveStripeCustomerAndCard({ @@ -456,7 +458,7 @@ class UserClass extends mongoose.Model { return this.findByIdAndUpdate(userId, { $set: modifier }, { new: true, runValidators: true }) .select('stripeListOfInvoices') - .lean(); + .setOptions({ lean: true }); } private static async checkPermissionAndGetTeam({ userId, teamId }) { @@ -466,7 +468,7 @@ class UserClass extends mongoose.Model { throw new Error('Bad data'); } - const team = await Team.findById(teamId).select('memberIds').lean(); + const team = await Team.findById(teamId).select('memberIds').setOptions({ lean: true }); if (!team || team.memberIds.indexOf(userId) === -1) { throw new Error('Team not found'); diff --git a/book/9-end/api/server/passwordless-auth.ts b/book/9-end/api/server/passwordless-auth.ts index 3b3292b4..ac354223 100644 --- a/book/9-end/api/server/passwordless-auth.ts +++ b/book/9-end/api/server/passwordless-auth.ts @@ -50,7 +50,7 @@ function setupPasswordless({ server }) { '/auth/email-login-link', passwordless.requestToken(async (email, __, callback) => { try { - const user = await User.findOne({ email }).select('_id').lean(); + const user = await User.findOne({ email }).select('_id').setOptions({ lean: true }); if (user) { callback(null, user._id); diff --git a/book/9-end/api/server/passwordless-token-mongostore.ts b/book/9-end/api/server/passwordless-token-mongostore.ts index 55166cba..d6546e36 100644 --- a/book/9-end/api/server/passwordless-token-mongostore.ts +++ b/book/9-end/api/server/passwordless-token-mongostore.ts @@ -130,7 +130,7 @@ MongoStore.prototype.storeOrUpdateByEmail = async function addEmail(email: strin throw new Error('TokenStore:addEmail called with invalid parameters'); } - const obj = await PasswordlessToken.findOne({ email }).select('uid').lean(); + const obj = await PasswordlessToken.findOne({ email }).select('uid').setOptions({ lean: true }); if (obj) { return obj.uid; diff --git a/book/9-end/api/server/stripe.ts b/book/9-end/api/server/stripe.ts index a0f0b116..90d7080d 100644 --- a/book/9-end/api/server/stripe.ts +++ b/book/9-end/api/server/stripe.ts @@ -121,12 +121,12 @@ function stripeWebhookAndCheckoutCallback({ server }) { const user = await User.findById( session.metadata.userId, '_id stripeCustomer email displayName isSubscriptionActive stripeSubscription', - ).lean(); + ).setOptions({ lean: true }); const team = await Team.findById( session.metadata.teamId, 'isSubscriptionActive stripeSubscription teamLeaderId slug', - ).lean(); + ).setOptions({ lean: true }); if (!user) { throw new Error('User not found.'); diff --git a/book/9-end/api/server/utils/slugify.ts b/book/9-end/api/server/utils/slugify.ts index e76af3c6..f2394edd 100644 --- a/book/9-end/api/server/utils/slugify.ts +++ b/book/9-end/api/server/utils/slugify.ts @@ -5,7 +5,7 @@ const slugify = (text) => _.kebabCase(text); async function createUniqueSlug(Model, slug, count, filter) { const obj = await Model.findOne({ slug: `${slug}-${count}`, ...filter }) .select('_id') - .lean(); + .setOptions({ lean: true }); if (!obj) { return `${slug}-${count}`; @@ -19,7 +19,7 @@ async function generateSlug(Model, name, filter = {}) { const obj = await Model.findOne({ slug: origSlug, ...filter }) .select('_id') - .lean(); + .setOptions({ lean: true }); if (!obj) { return origSlug; @@ -31,7 +31,7 @@ async function generateSlug(Model, name, filter = {}) { async function generateNumberSlug(Model, filter = {}, n = 1) { const obj = await Model.findOne({ slug: n, ...filter }) .select('_id') - .lean(); + .setOptions({ lean: true }); if (!obj) { return `${n}`; diff --git a/book/9-end/lambda/handler.ts b/book/9-end/lambda/handler.ts index 43918a6c..26fa72d2 100644 --- a/book/9-end/lambda/handler.ts +++ b/book/9-end/lambda/handler.ts @@ -39,7 +39,7 @@ export const sendEmailForNewPost = async (event) => { const usersToNotify = await User.find({ _id: { $in: userIds } }) .select('email') - .lean(); + .setOptions({ lean: true }); console.log('usersToNotify', usersToNotify); diff --git a/saas/app/pages/team-settings.tsx b/saas/app/pages/team-settings.tsx index e06a07cf..4010b1ab 100644 --- a/saas/app/pages/team-settings.tsx +++ b/saas/app/pages/team-settings.tsx @@ -221,7 +221,7 @@ class TeamSettings extends React.Component {

Invited users

- +