Merge pull request #26141 from overleaf/ii-managed-users-consent-screen
[web] Joining managed group from projects page GitOrigin-RevId: 191203559fba94cad45f35de1af2427b2abb9326
This commit is contained in:
@@ -33,4 +33,26 @@ export default {
|
||||
res.sendStatus(200)
|
||||
)
|
||||
},
|
||||
|
||||
getNotification(req, res, next) {
|
||||
const userId = SessionManager.getLoggedInUserId(req.session)
|
||||
const { notificationId } = req.params
|
||||
NotificationsHandler.getUserNotifications(
|
||||
userId,
|
||||
function (err, unreadNotifications) {
|
||||
if (err) {
|
||||
return next(err)
|
||||
}
|
||||
const notification = unreadNotifications.find(
|
||||
n => n._id === notificationId
|
||||
)
|
||||
|
||||
if (!notification) {
|
||||
return res.status(404).end()
|
||||
}
|
||||
|
||||
res.json(notification)
|
||||
}
|
||||
)
|
||||
},
|
||||
}
|
||||
|
||||
@@ -915,6 +915,12 @@ async function initialize(webRouter, privateApiRouter, publicApiRouter) {
|
||||
NotificationsController.markNotificationAsRead
|
||||
)
|
||||
|
||||
webRouter.get(
|
||||
'/user/notification/:notificationId',
|
||||
AuthenticationController.requireLogin(),
|
||||
NotificationsController.getNotification
|
||||
)
|
||||
|
||||
// Deprecated in favour of /internal/project/:project_id but still used by versioning
|
||||
privateApiRouter.get(
|
||||
'/project/:project_id/details',
|
||||
|
||||
+42
-34
@@ -9,6 +9,7 @@ import type { NotificationGroupInvitation } from '../../../../../../../../../typ
|
||||
import useAsync from '../../../../../../../shared/hooks/use-async'
|
||||
import {
|
||||
FetchError,
|
||||
getJSON,
|
||||
postJSON,
|
||||
putJSON,
|
||||
} from '../../../../../../../infrastructure/fetch-json'
|
||||
@@ -43,17 +44,12 @@ type UseGroupInvitationNotificationReturnType = {
|
||||
export function useGroupInvitationNotification(
|
||||
notification: NotificationGroupInvitation
|
||||
): UseGroupInvitationNotificationReturnType {
|
||||
const {
|
||||
_id: notificationId,
|
||||
messageOpts: { token, managedUsersEnabled },
|
||||
} = notification
|
||||
|
||||
const { _id: notificationId } = notification
|
||||
const [groupInvitationStatus, setGroupInvitationStatus] =
|
||||
useState<GroupInvitationStatus>(GroupInvitationStatus.Idle)
|
||||
const { runAsync, isLoading: isAcceptingInvitation } = useAsync<
|
||||
never,
|
||||
FetchError
|
||||
>()
|
||||
const { runAsync, isLoading } = useAsync<void, FetchError>()
|
||||
const { runAsync: runAsyncNotification, isLoading: isLoadingNotification } =
|
||||
useAsync<NotificationGroupInvitation, FetchError>()
|
||||
const location = useLocation()
|
||||
const { handleDismiss } = useAsyncDismiss()
|
||||
|
||||
@@ -72,31 +68,41 @@ export function useGroupInvitationNotification(
|
||||
}, [hasIndividualPaidSubscription])
|
||||
|
||||
const acceptGroupInvite = useCallback(() => {
|
||||
if (managedUsersEnabled) {
|
||||
location.assign(`/subscription/invites/${token}/`)
|
||||
} else {
|
||||
runAsync(
|
||||
putJSON(`/subscription/invites/${token}/`, {
|
||||
body: {
|
||||
_csrf: getMeta('ol-csrfToken'),
|
||||
},
|
||||
})
|
||||
)
|
||||
.then(() => {
|
||||
setGroupInvitationStatus(GroupInvitationStatus.SuccessfullyJoined)
|
||||
})
|
||||
.catch(err => {
|
||||
debugConsole.error(err)
|
||||
setGroupInvitationStatus(GroupInvitationStatus.Error)
|
||||
})
|
||||
.finally(() => {
|
||||
// remove notification automatically in the browser
|
||||
window.setTimeout(() => {
|
||||
setGroupInvitationStatus(GroupInvitationStatus.NotificationIsHidden)
|
||||
}, SUCCESSFUL_NOTIF_TIME_BEFORE_HIDDEN)
|
||||
})
|
||||
}
|
||||
}, [runAsync, token, location, managedUsersEnabled])
|
||||
// Fetch the latest notification data to ensure it's up-to-date
|
||||
runAsyncNotification(getJSON(`/user/notification/${notificationId}`))
|
||||
.then(notification => {
|
||||
const {
|
||||
messageOpts: { token, managedUsersEnabled },
|
||||
} = notification
|
||||
if (managedUsersEnabled) {
|
||||
location.assign(`/subscription/invites/${token}/`)
|
||||
} else {
|
||||
runAsync(
|
||||
putJSON(`/subscription/invites/${token}/`, {
|
||||
body: {
|
||||
_csrf: getMeta('ol-csrfToken'),
|
||||
},
|
||||
})
|
||||
)
|
||||
.then(() => {
|
||||
setGroupInvitationStatus(GroupInvitationStatus.SuccessfullyJoined)
|
||||
})
|
||||
.catch(err => {
|
||||
debugConsole.error(err)
|
||||
setGroupInvitationStatus(GroupInvitationStatus.Error)
|
||||
})
|
||||
.finally(() => {
|
||||
// remove notification automatically in the browser
|
||||
window.setTimeout(() => {
|
||||
setGroupInvitationStatus(
|
||||
GroupInvitationStatus.NotificationIsHidden
|
||||
)
|
||||
}, SUCCESSFUL_NOTIF_TIME_BEFORE_HIDDEN)
|
||||
})
|
||||
}
|
||||
})
|
||||
.catch(debugConsole.error)
|
||||
}, [runAsync, runAsyncNotification, notificationId, location])
|
||||
|
||||
const cancelPersonalSubscription = useCallback(() => {
|
||||
setGroupInvitationStatus(GroupInvitationStatus.AskToJoin)
|
||||
@@ -114,6 +120,8 @@ export function useGroupInvitationNotification(
|
||||
setGroupInvitationStatus(GroupInvitationStatus.NotificationIsHidden)
|
||||
}, [])
|
||||
|
||||
const isAcceptingInvitation = isLoadingNotification || isLoading
|
||||
|
||||
return {
|
||||
isAcceptingInvitation,
|
||||
groupInvitationStatus,
|
||||
|
||||
+7
@@ -27,6 +27,10 @@ describe('<GroupInvitationNotification />', function () {
|
||||
}
|
||||
|
||||
beforeEach(function () {
|
||||
cy.intercept('GET', `/user/notification/${notification._id}`, {
|
||||
statusCode: 200,
|
||||
body: notification,
|
||||
}).as('getNotification')
|
||||
cy.intercept(
|
||||
'PUT',
|
||||
`/subscription/invites/${notification.messageOpts.token}`,
|
||||
@@ -48,6 +52,7 @@ describe('<GroupInvitationNotification />', function () {
|
||||
|
||||
cy.findByRole('button', { name: 'Join now' }).click()
|
||||
|
||||
cy.wait('@getNotification')
|
||||
cy.wait('@acceptInvite')
|
||||
|
||||
cy.findByText(
|
||||
@@ -82,6 +87,7 @@ describe('<GroupInvitationNotification />', function () {
|
||||
|
||||
cy.findByRole('button', { name: 'Join now' }).click()
|
||||
|
||||
cy.wait('@getNotification')
|
||||
cy.wait('@acceptInvite')
|
||||
|
||||
cy.findByText(
|
||||
@@ -116,6 +122,7 @@ describe('<GroupInvitationNotification />', function () {
|
||||
|
||||
cy.findByRole('button', { name: 'Join now' }).click()
|
||||
|
||||
cy.wait('@getNotification')
|
||||
cy.wait('@acceptInvite')
|
||||
|
||||
cy.findByText(
|
||||
|
||||
@@ -14,6 +14,9 @@ describe('NotificationsController', function () {
|
||||
ctx.handler = {
|
||||
getUserNotifications: sinon.stub().callsArgWith(1),
|
||||
markAsRead: sinon.stub().callsArgWith(2),
|
||||
promises: {
|
||||
getUserNotifications: sinon.stub().callsArgWith(1),
|
||||
},
|
||||
}
|
||||
ctx.req = {
|
||||
params: {
|
||||
@@ -77,4 +80,22 @@ describe('NotificationsController', function () {
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
it('should get a notification by notification id', function (ctx) {
|
||||
return new Promise(resolve => {
|
||||
const notification = { _id: notificationId, user_id: userId }
|
||||
ctx.handler.getUserNotifications = sinon
|
||||
.stub()
|
||||
.callsArgWith(1, null, [notification])
|
||||
ctx.controller.getNotification(ctx.req, {
|
||||
json: body => {
|
||||
body.should.deep.equal(notification)
|
||||
resolve()
|
||||
},
|
||||
status: () => ({
|
||||
end: () => {},
|
||||
}),
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user