fix: [web] managed group admins unable to re-subscribe (#29634)

GitOrigin-RevId: 5e3d46c39f4657fcc737403a80093b870bc42240
This commit is contained in:
Simon Gardner
2026-04-27 11:01:35 +01:00
committed by Copybot
parent 73cc1b571b
commit 8a331bc943
6 changed files with 78 additions and 2 deletions
@@ -337,6 +337,7 @@ async function userSubscriptionPage(req, res) {
groupSettingsAdvertisedFor,
groupSettingsEnabledFor,
isManagedAccount: !!req.managedBy,
isManagedGroupAdmin: !!req.isManagedGroupAdmin,
userRestrictions: Array.from(req.userRestrictions || []),
hasAiAssistViaWritefull,
aiAssistViaWritefullSource,
@@ -84,6 +84,11 @@ block append meta
data-type='string'
content=aiAssistViaWritefullSource
)
meta(
name='ol-isManagedGroupAdmin'
data-type='boolean'
content=isManagedGroupAdmin
)
meta(name='ol-user' data-type='json' content=user)
if personalSubscription && personalSubscription.payment
meta(name='ol-recurlyApiKey' content=settings.apis.recurly.publicKey)
@@ -20,8 +20,12 @@ function ReactivateSubscription() {
location.reload()
}
// Don't show the button to reactivate the subscription for managed users
if (getMeta('ol-cannot-reactivate-subscription')) {
// Don't show the button to reactivate the subscription for managed users,
// unless they are a managed group admin (who should be able to reactivate their own subscription)
if (
getMeta('ol-cannot-reactivate-subscription') &&
!getMeta('ol-isManagedGroupAdmin')
) {
return null
}
+1
View File
@@ -185,6 +185,7 @@ export interface Meta {
'ol-isCollectionMethodManual': boolean
'ol-isExternalAuthenticationSystemUsed': boolean
'ol-isManagedAccount': boolean
'ol-isManagedGroupAdmin': boolean
'ol-isProfessional': boolean
'ol-isRegisteredViaGoogle': boolean
'ol-isRestrictedTokenMember': boolean
@@ -115,6 +115,45 @@ describe('<PersonalSubscription />', function () {
fetchMock.removeRoutes().clearHistory()
})
it('hides reactivate button for managed users who cannot reactivate', function () {
renderWithSubscriptionDashContext(<PersonalSubscription />, {
metaTags: [
{ name: 'ol-subscription', value: canceledSubscription },
{ name: 'ol-cannot-reactivate-subscription', value: true },
],
})
screen.getByText(
'Your subscription has been canceled and will terminate on',
{ exact: false }
)
screen.getByRole('link', { name: 'View your invoices' })
// Should not show the reactivate button
expect(
screen.queryByRole('button', { name: 'Reactivate your subscription' })
).to.be.null
})
it('shows reactivate button for managed group admins even if they have reactivate restriction', function () {
renderWithSubscriptionDashContext(<PersonalSubscription />, {
metaTags: [
{ name: 'ol-subscription', value: canceledSubscription },
{ name: 'ol-cannot-reactivate-subscription', value: true },
{ name: 'ol-isManagedGroupAdmin', value: true },
],
})
screen.getByText(
'Your subscription has been canceled and will terminate on',
{ exact: false }
)
screen.getByRole('link', { name: 'View your invoices' })
// Should show the reactivate button for group admins
screen.getByRole('button', { name: 'Reactivate your subscription' })
})
it('renders the expired dash', function () {
renderWithSubscriptionDashContext(<PersonalSubscription />, {
metaTags: [
@@ -492,6 +492,32 @@ describe('SubscriptionController', function () {
expect(ctx.data.groupSettingsEnabledFor).to.deep.equal([])
})
it('should pass isManagedGroupAdmin as false when not set', function (ctx) {
expect(ctx.data.isManagedGroupAdmin).to.equal(false)
})
describe('when user is a managed group admin', function () {
beforeEach(async function (ctx) {
ctx.req.isManagedGroupAdmin = true
await new Promise((resolve, reject) => {
ctx.res.render = (view, data) => {
ctx.data = data
expect(view).to.equal('subscriptions/dashboard-react')
resolve()
}
ctx.SubscriptionController.userSubscriptionPage(
ctx.req,
ctx.res,
ctx.rejectOnError(reject)
)
})
})
it('should pass isManagedGroupAdmin as true', function (ctx) {
expect(ctx.data.isManagedGroupAdmin).to.equal(true)
})
})
describe('when errorCode query param is present', function () {
beforeEach(async function (ctx) {
ctx.req.query.errorCode = 'payment_failed'