Эх сурвалжийг харах

Merge pull request #25190 from overleaf/mj-survey-signup-limits

[web] Add options to limit survey exposure based on signup date

GitOrigin-RevId: 5719997339b5040d5cc42ffe7bee6d7b66bff12d
Mathias Jakobsen 1 жил өмнө
parent
commit
930401541d

+ 20 - 0
services/web/app/src/Features/Survey/SurveyHandler.mjs

@@ -4,6 +4,7 @@ import crypto from 'node:crypto'
 import SurveyCache from './SurveyCache.mjs'
 import SubscriptionLocator from '../Subscription/SubscriptionLocator.js'
 import { callbackify } from '@overleaf/promise-utils'
+import UserGetter from '../User/UserGetter.js'
 
 /**
  * @import { Survey } from '../../../../types/project/dashboard/survey'
@@ -33,6 +34,25 @@ async function getSurvey(userId) {
       return
     }
 
+    const { earliestSignupDate, latestSignupDate } = survey.options || {}
+    if (earliestSignupDate || latestSignupDate) {
+      const user = await UserGetter.promises.getUser(userId, { signUpDate: 1 })
+      if (!user) {
+        return
+      }
+      const { signUpDate } = user
+      if (latestSignupDate) {
+        // Make the check inclusive
+        latestSignupDate.setHours(23, 59, 59, 999)
+        if (signUpDate > latestSignupDate) {
+          return
+        }
+      }
+      if (earliestSignupDate && signUpDate < earliestSignupDate) {
+        return
+      }
+    }
+
     return { name, preText, linkText, url }
   }
 }

+ 36 - 0
services/web/app/src/Features/Survey/SurveyManager.js

@@ -10,6 +10,7 @@ async function getSurvey() {
 }
 
 async function updateSurvey({ name, preText, linkText, url, options }) {
+  validateOptions(options)
   let survey = await getSurvey()
   if (!survey) {
     survey = new Survey()
@@ -23,6 +24,41 @@ async function updateSurvey({ name, preText, linkText, url, options }) {
   return survey
 }
 
+function validateOptions(options) {
+  if (!options) {
+    return
+  }
+  if (typeof options !== 'object') {
+    throw new Error('options must be an object')
+  }
+  const { earliestSignupDate, latestSignupDate } = options
+
+  const earliestDate = parseDate(earliestSignupDate)
+  const latestDate = parseDate(latestSignupDate)
+  if (earliestDate && latestDate) {
+    if (earliestDate > latestDate) {
+      throw new Error('earliestSignupDate must be before latestSignupDate')
+    }
+  }
+}
+
+function parseDate(date) {
+  if (date) {
+    if (typeof date !== 'string') {
+      throw new Error('Date must be a string')
+    }
+    if (date.match(/^\d{4}-\d{2}-\d{2}$/) === null) {
+      throw new Error('Date must be in YYYY-MM-DD format')
+    }
+    const asDate = new Date(date)
+    if (isNaN(asDate.getTime())) {
+      throw new Error('Date must be a valid date')
+    }
+    return asDate
+  }
+  return null
+}
+
 async function deleteSurvey() {
   const survey = await getSurvey()
   if (survey) {

+ 6 - 0
services/web/app/src/models/Survey.js

@@ -36,6 +36,12 @@ const SurveySchema = new Schema(
         type: Boolean,
         default: false,
       },
+      earliestSignupDate: {
+        type: Date,
+      },
+      latestSignupDate: {
+        type: Date,
+      },
       rolloutPercentage: {
         type: Number,
         default: 100,

+ 8 - 1
services/web/test/acceptance/src/helpers/User.mjs

@@ -36,6 +36,7 @@ class User {
     this.request = request.defaults({
       jar: this.jar,
     })
+    this.signUpDate = options.signUpDate ?? new Date()
   }
 
   getSession(options, callback) {
@@ -425,7 +426,13 @@ class User {
 
         UserModel.findOneAndUpdate(
           filter,
-          { $set: { hashedPassword, emails: this.emails } },
+          {
+            $set: {
+              hashedPassword,
+              emails: this.emails,
+              signUpDate: this.signUpDate,
+            },
+          },
           options
         )
           .then(user => {