mirror of
https://github.com/overleaf/overleaf.git
synced 2024-11-21 20:47:08 -05:00
Merge pull request #15044 from overleaf/mf-send-warning-to-users-with-personal-and-group-subscriptions
Show notification warning to user with both personal and group subscriptions GitOrigin-RevId: 7f46d7af10389f552175ce26fae9469e0167f95b
This commit is contained in:
parent
a4d9c900fc
commit
e53f3bb158
6 changed files with 119 additions and 0 deletions
|
@ -255,6 +255,32 @@ function groupInvitation(userId, subscriptionId, managedUsersEnabled) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function personalAndGroupSubscriptions(userId) {
|
||||||
|
return {
|
||||||
|
key: 'personal-and-group-subscriptions',
|
||||||
|
create(callback) {
|
||||||
|
if (callback == null) {
|
||||||
|
callback = function () {}
|
||||||
|
}
|
||||||
|
NotificationsHandler.createNotification(
|
||||||
|
userId,
|
||||||
|
this.key,
|
||||||
|
'notification_personal_and_group_subscriptions',
|
||||||
|
{},
|
||||||
|
null,
|
||||||
|
false,
|
||||||
|
callback
|
||||||
|
)
|
||||||
|
},
|
||||||
|
read(callback) {
|
||||||
|
if (callback == null) {
|
||||||
|
callback = function () {}
|
||||||
|
}
|
||||||
|
NotificationsHandler.markAsReadByKeyOnly(this.key, callback)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const NotificationsBuilder = {
|
const NotificationsBuilder = {
|
||||||
// Note: notification keys should be url-safe
|
// Note: notification keys should be url-safe
|
||||||
dropboxUnlinkedDueToLapsedReconfirmation,
|
dropboxUnlinkedDueToLapsedReconfirmation,
|
||||||
|
@ -265,6 +291,7 @@ const NotificationsBuilder = {
|
||||||
ipMatcherAffiliation,
|
ipMatcherAffiliation,
|
||||||
tpdsFileLimit,
|
tpdsFileLimit,
|
||||||
groupInvitation,
|
groupInvitation,
|
||||||
|
personalAndGroupSubscriptions,
|
||||||
}
|
}
|
||||||
|
|
||||||
NotificationsBuilder.promises = {
|
NotificationsBuilder.promises = {
|
||||||
|
@ -286,6 +313,9 @@ NotificationsBuilder.promises = {
|
||||||
projectInvite(invite, project, sendingUser, user) {
|
projectInvite(invite, project, sendingUser, user) {
|
||||||
return promisifyAll(projectInvite(invite, project, sendingUser, user))
|
return promisifyAll(projectInvite(invite, project, sendingUser, user))
|
||||||
},
|
},
|
||||||
|
personalAndGroupSubscriptions(userId) {
|
||||||
|
return promisifyAll(personalAndGroupSubscriptions(userId))
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = NotificationsBuilder
|
module.exports = NotificationsBuilder
|
||||||
|
|
|
@ -738,6 +738,7 @@
|
||||||
"normally_x_price_per_year": "",
|
"normally_x_price_per_year": "",
|
||||||
"not_managed": "",
|
"not_managed": "",
|
||||||
"not_now": "",
|
"not_now": "",
|
||||||
|
"notification_personal_and_group_subscriptions": "",
|
||||||
"notification_project_invite_accepted_message": "",
|
"notification_project_invite_accepted_message": "",
|
||||||
"notification_project_invite_message": "",
|
"notification_project_invite_message": "",
|
||||||
"number_of_users": "",
|
"number_of_users": "",
|
||||||
|
|
|
@ -257,6 +257,19 @@ function CommonNotification({ notification }: CommonNotificationProps) {
|
||||||
</Notification>
|
</Notification>
|
||||||
) : templateKey === 'notification_group_invitation' ? (
|
) : templateKey === 'notification_group_invitation' ? (
|
||||||
<GroupInvitationNotification notification={notification} />
|
<GroupInvitationNotification notification={notification} />
|
||||||
|
) : templateKey === 'notification_personal_and_group_subscriptions' ? (
|
||||||
|
<Notification
|
||||||
|
bsStyle="warning"
|
||||||
|
onDismiss={() => id && handleDismiss(id)}
|
||||||
|
>
|
||||||
|
<Notification.Body>
|
||||||
|
<Trans
|
||||||
|
i18nKey="notification_personal_and_group_subscriptions"
|
||||||
|
/* eslint-disable-next-line jsx-a11y/anchor-has-content, react/jsx-key */
|
||||||
|
components={[<strong />, <a href="/user/subscription" />]}
|
||||||
|
/>
|
||||||
|
</Notification.Body>
|
||||||
|
</Notification>
|
||||||
) : (
|
) : (
|
||||||
<Notification bsStyle="info" onDismiss={() => id && handleDismiss(id)}>
|
<Notification bsStyle="info" onDismiss={() => id && handleDismiss(id)}>
|
||||||
<Notification.Body>{html}</Notification.Body>
|
<Notification.Body>{html}</Notification.Body>
|
||||||
|
|
|
@ -1161,6 +1161,7 @@
|
||||||
"note_features_under_development": "<0>Please note</0> that features in this program are still being tested and actively developed. This means that they might <0>change</0>, be <0>removed</0> or <0>become part of a premium plan</0>",
|
"note_features_under_development": "<0>Please note</0> that features in this program are still being tested and actively developed. This means that they might <0>change</0>, be <0>removed</0> or <0>become part of a premium plan</0>",
|
||||||
"nothing_to_install_ready_to_go": "There’s nothing complicated or difficult for you to install, and you can <0>__start_now__</0>, even if you’ve never seen it before. __appName__ comes with a complete, ready to go LaTeX environment which runs on our servers.",
|
"nothing_to_install_ready_to_go": "There’s nothing complicated or difficult for you to install, and you can <0>__start_now__</0>, even if you’ve never seen it before. __appName__ comes with a complete, ready to go LaTeX environment which runs on our servers.",
|
||||||
"notification_features_upgraded_by_affiliation": "Good news! Your affiliated organization __institutionName__ has an Overleaf subscription, and you now have access to all of Overleaf’s Professional features.",
|
"notification_features_upgraded_by_affiliation": "Good news! Your affiliated organization __institutionName__ has an Overleaf subscription, and you now have access to all of Overleaf’s Professional features.",
|
||||||
|
"notification_personal_and_group_subscriptions": "We’ve spotted that you’ve got <0>more than one active __appName__ subscription</0>. To avoid paying more than you need to, <1>review your subscriptions</1>.",
|
||||||
"notification_personal_subscription_not_required_due_to_affiliation": " Good news! Your affiliated organization __institutionName__ has an Overleaf subscription, and you now have access to Overleaf’s Professional features through your affiliation. You can cancel your individual subscription without losing access to any features.",
|
"notification_personal_subscription_not_required_due_to_affiliation": " Good news! Your affiliated organization __institutionName__ has an Overleaf subscription, and you now have access to Overleaf’s Professional features through your affiliation. You can cancel your individual subscription without losing access to any features.",
|
||||||
"notification_project_invite": "<b>__userName__</b> would like you to join <b>__projectName__</b> <a class=\"btn btn-sm btn-info pull-right\" href=\"/project/__projectId__/invite/token/__token__\">Join Project</a>",
|
"notification_project_invite": "<b>__userName__</b> would like you to join <b>__projectName__</b> <a class=\"btn btn-sm btn-info pull-right\" href=\"/project/__projectId__/invite/token/__token__\">Join Project</a>",
|
||||||
"notification_project_invite_accepted_message": "You’ve joined <b>__projectName__</b>",
|
"notification_project_invite_accepted_message": "You’ve joined <b>__projectName__</b>",
|
||||||
|
|
|
@ -0,0 +1,73 @@
|
||||||
|
const NotificationsBuilder = require('../app/src/Features/Notifications/NotificationsBuilder')
|
||||||
|
const { db, waitForDb } = require('../app/src/infrastructure/mongodb')
|
||||||
|
const { batchedUpdate } = require('./helpers/batchedUpdate')
|
||||||
|
|
||||||
|
const DRY_RUN = !process.argv.includes('--dry-run=false')
|
||||||
|
|
||||||
|
if (DRY_RUN) {
|
||||||
|
console.log('Doing dry run')
|
||||||
|
}
|
||||||
|
|
||||||
|
async function processBatch(groupSubscriptionsBatch) {
|
||||||
|
console.log('\n')
|
||||||
|
console.log('----- Batch computation started -----')
|
||||||
|
const flattenedMemberIds = groupSubscriptionsBatch
|
||||||
|
.map(sub => sub.member_ids)
|
||||||
|
.flatMap(memberId => memberId)
|
||||||
|
const uniqueFlattenedMemberIds = [...new Set(flattenedMemberIds)]
|
||||||
|
|
||||||
|
const userWithIndividualAndGroupSubscriptions = await db.subscriptions
|
||||||
|
.find({
|
||||||
|
groupPlan: false,
|
||||||
|
'recurlyStatus.state': 'active',
|
||||||
|
admin_id: { $in: uniqueFlattenedMemberIds },
|
||||||
|
})
|
||||||
|
.toArray()
|
||||||
|
|
||||||
|
console.log(
|
||||||
|
`Found ${userWithIndividualAndGroupSubscriptions.length} affected users in this batch`
|
||||||
|
)
|
||||||
|
|
||||||
|
if (DRY_RUN) {
|
||||||
|
console.error('---')
|
||||||
|
console.error('Dry-run enabled, use --dry-run=false to commit changes')
|
||||||
|
console.error('---')
|
||||||
|
} else {
|
||||||
|
if (userWithIndividualAndGroupSubscriptions.length > 0) {
|
||||||
|
console.log(
|
||||||
|
`Notifying ${userWithIndividualAndGroupSubscriptions.length} users`
|
||||||
|
)
|
||||||
|
|
||||||
|
for (const notif of userWithIndividualAndGroupSubscriptions) {
|
||||||
|
await NotificationsBuilder.promises
|
||||||
|
.personalAndGroupSubscriptions(notif.admin_id.toString())
|
||||||
|
.create()
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log(
|
||||||
|
`${userWithIndividualAndGroupSubscriptions.length} users successfully notified in this batch`
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
console.log(
|
||||||
|
'No users currently subscribe to both individual and group subscription in this batch'
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function main() {
|
||||||
|
await waitForDb()
|
||||||
|
|
||||||
|
await batchedUpdate('subscriptions', { groupPlan: true }, processBatch, {
|
||||||
|
member_ids: 1,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
main()
|
||||||
|
.then(() => {
|
||||||
|
process.exit(0)
|
||||||
|
})
|
||||||
|
.catch(err => {
|
||||||
|
console.error(err)
|
||||||
|
process.exit(1)
|
||||||
|
})
|
|
@ -6,6 +6,7 @@ type TemplateKey =
|
||||||
| 'notification_dropbox_duplicate_project_names'
|
| 'notification_dropbox_duplicate_project_names'
|
||||||
| 'notification_dropbox_unlinked_due_to_lapsed_reconfirmation'
|
| 'notification_dropbox_unlinked_due_to_lapsed_reconfirmation'
|
||||||
| 'notification_group_invitation'
|
| 'notification_group_invitation'
|
||||||
|
| 'notification_personal_and_group_subscriptions'
|
||||||
|
|
||||||
type NotificationBase = {
|
type NotificationBase = {
|
||||||
_id?: number
|
_id?: number
|
||||||
|
|
Loading…
Reference in a new issue