Merge pull request #31827 from overleaf/ii-project-sharing-access-denied

[web] Project sharing access denied redesign

GitOrigin-RevId: b1e3016eb7ef9e2a502e0b67abc3b10c08531fe9
This commit is contained in:
ilkin-overleaf
2026-03-19 09:06:31 +00:00
committed by Copybot
parent 79cb219ad9
commit d61413e57d
14 changed files with 494 additions and 139 deletions
@@ -1035,54 +1035,108 @@ describe('CollaboratorsInviteController', function () {
})
describe('when the getInviteByToken does not produce an invite', function () {
beforeEach(async function (ctx) {
await new Promise(resolve => {
ctx.CollaboratorsInviteGetter.promises.getInviteByToken.resolves(null)
ctx.res.callback = () => resolve()
ctx.CollaboratorsInviteController.viewInvite(
ctx.req,
ctx.res,
ctx.next
describe('when the sharing-updates variant is "enabled"', function () {
beforeEach(async function (ctx) {
ctx.SplitTestHandler.promises.getAssignment.resolves({
variant: 'enabled',
})
await new Promise(resolve => {
ctx.CollaboratorsInviteGetter.promises.getInviteByToken.resolves(
null
)
ctx.res.callback = () => resolve()
ctx.CollaboratorsInviteController.viewInvite(
ctx.req,
ctx.res,
ctx.next
)
})
})
it('should render the not-valid view template', function (ctx) {
expect(ctx.res.render).toHaveBeenCalledTimes(1)
expect(ctx.res.render).toHaveBeenCalledWith(
'project/invite/not-valid',
expect.anything()
)
})
it('should not call next', function (ctx) {
ctx.next.callCount.should.equal(0)
})
})
it('should render the not-valid view template', function (ctx) {
expect(ctx.res.render).toHaveBeenCalledTimes(1)
expect(ctx.res.render).toHaveBeenCalledWith(
'project/invite/not-valid',
expect.anything()
)
describe('when the sharing-updates variant is "default"', function () {
beforeEach(async function (ctx) {
ctx.SplitTestHandler.promises.getAssignment.resolves({
variant: 'default',
})
await new Promise(resolve => {
ctx.CollaboratorsInviteGetter.promises.getInviteByToken.resolves(
null
)
ctx.res.callback = () => resolve()
ctx.CollaboratorsInviteController.viewInvite(
ctx.req,
ctx.res,
ctx.next
)
})
})
it('should render the not-valid-legacy view template', function (ctx) {
expect(ctx.res.render).toHaveBeenCalledTimes(1)
expect(ctx.res.render).toHaveBeenCalledWith(
'project/invite/not-valid-legacy',
expect.anything()
)
})
it('should not call next', function (ctx) {
ctx.next.callCount.should.equal(0)
})
})
it('should not call next', function (ctx) {
ctx.next.callCount.should.equal(0)
})
describe('common behaviour', function () {
beforeEach(async function (ctx) {
await new Promise(resolve => {
ctx.CollaboratorsInviteGetter.promises.getInviteByToken.resolves(
null
)
ctx.res.callback = () => resolve()
ctx.CollaboratorsInviteController.viewInvite(
ctx.req,
ctx.res,
ctx.next
)
})
})
it('should call CollaboratorsGetter.isUserInvitedMemberOfProject', function (ctx) {
ctx.CollaboratorsGetter.promises.isUserInvitedMemberOfProject.callCount.should.equal(
1
)
ctx.CollaboratorsGetter.promises.isUserInvitedMemberOfProject
.calledWith(ctx.currentUser._id, ctx.projectId)
.should.equal(true)
})
it('should call CollaboratorsGetter.isUserInvitedMemberOfProject', function (ctx) {
ctx.CollaboratorsGetter.promises.isUserInvitedMemberOfProject.callCount.should.equal(
1
)
ctx.CollaboratorsGetter.promises.isUserInvitedMemberOfProject
.calledWith(ctx.currentUser._id, ctx.projectId)
.should.equal(true)
})
it('should call getInviteByToken', function (ctx) {
ctx.CollaboratorsInviteGetter.promises.getInviteByToken.callCount.should.equal(
1
)
ctx.CollaboratorsGetter.promises.isUserInvitedMemberOfProject
.calledWith(ctx.currentUser._id, ctx.projectId)
.should.equal(true)
})
it('should call getInviteByToken', function (ctx) {
ctx.CollaboratorsInviteGetter.promises.getInviteByToken.callCount.should.equal(
1
)
ctx.CollaboratorsGetter.promises.isUserInvitedMemberOfProject
.calledWith(ctx.currentUser._id, ctx.projectId)
.should.equal(true)
})
it('should not call User.getUser', function (ctx) {
ctx.UserGetter.promises.getUser.callCount.should.equal(0)
})
it('should not call User.getUser', function (ctx) {
ctx.UserGetter.promises.getUser.callCount.should.equal(0)
})
it('should not call ProjectGetter.getProject', function (ctx) {
ctx.ProjectGetter.promises.getProject.callCount.should.equal(0)
it('should not call ProjectGetter.getProject', function (ctx) {
ctx.ProjectGetter.promises.getProject.callCount.should.equal(0)
})
})
})
@@ -1132,54 +1186,102 @@ describe('CollaboratorsInviteController', function () {
})
describe('when User.getUser does not find a user', function () {
beforeEach(async function (ctx) {
await new Promise(resolve => {
ctx.UserGetter.promises.getUser.resolves(null)
ctx.res.callback = () => resolve()
ctx.CollaboratorsInviteController.viewInvite(
ctx.req,
ctx.res,
ctx.next
describe('when the sharing-updates variant is "enabled"', function () {
beforeEach(async function (ctx) {
ctx.SplitTestHandler.promises.getAssignment.resolves({
variant: 'enabled',
})
await new Promise(resolve => {
ctx.UserGetter.promises.getUser.resolves(null)
ctx.res.callback = () => resolve()
ctx.CollaboratorsInviteController.viewInvite(
ctx.req,
ctx.res,
ctx.next
)
})
})
it('should render the not-valid view template', function (ctx) {
expect(ctx.res.render).toHaveBeenCalledTimes(1)
expect(ctx.res.render).toHaveBeenCalledWith(
'project/invite/not-valid',
expect.anything()
)
})
it('should not call next', function (ctx) {
ctx.next.callCount.should.equal(0)
})
})
it('should render the not-valid view template', function (ctx) {
expect(ctx.res.render).toHaveBeenCalledTimes(1)
expect(ctx.res.render).toHaveBeenCalledWith(
'project/invite/not-valid',
expect.anything()
)
describe('when the sharing-updates variant is "default"', function () {
beforeEach(async function (ctx) {
ctx.SplitTestHandler.promises.getAssignment.resolves({
variant: 'default',
})
await new Promise(resolve => {
ctx.UserGetter.promises.getUser.resolves(null)
ctx.res.callback = () => resolve()
ctx.CollaboratorsInviteController.viewInvite(
ctx.req,
ctx.res,
ctx.next
)
})
})
it('should render the not-valid-legacy view template', function (ctx) {
expect(ctx.res.render).toHaveBeenCalledTimes(1)
expect(ctx.res.render).toHaveBeenCalledWith(
'project/invite/not-valid-legacy',
expect.anything()
)
})
it('should not call next', function (ctx) {
ctx.next.callCount.should.equal(0)
})
})
it('should not call next', function (ctx) {
ctx.next.callCount.should.equal(0)
})
describe('common behaviour', function () {
beforeEach(async function (ctx) {
await new Promise(resolve => {
ctx.UserGetter.promises.getUser.resolves(null)
ctx.res.callback = () => resolve()
ctx.CollaboratorsInviteController.viewInvite(
ctx.req,
ctx.res,
ctx.next
)
})
})
it('should call CollaboratorsGetter.isUserInvitedMemberOfProject', function (ctx) {
ctx.CollaboratorsGetter.promises.isUserInvitedMemberOfProject.callCount.should.equal(
1
)
ctx.CollaboratorsGetter.promises.isUserInvitedMemberOfProject
.calledWith(ctx.currentUser._id, ctx.projectId)
.should.equal(true)
})
it('should call CollaboratorsGetter.isUserInvitedMemberOfProject', function (ctx) {
ctx.CollaboratorsGetter.promises.isUserInvitedMemberOfProject.callCount.should.equal(
1
)
ctx.CollaboratorsGetter.promises.isUserInvitedMemberOfProject
.calledWith(ctx.currentUser._id, ctx.projectId)
.should.equal(true)
})
it('should call getInviteByToken', function (ctx) {
ctx.CollaboratorsInviteGetter.promises.getInviteByToken.callCount.should.equal(
1
)
})
it('should call getInviteByToken', function (ctx) {
ctx.CollaboratorsInviteGetter.promises.getInviteByToken.callCount.should.equal(
1
)
})
it('should call User.getUser', function (ctx) {
ctx.UserGetter.promises.getUser.callCount.should.equal(1)
ctx.UserGetter.promises.getUser
.calledWith({ _id: ctx.fakeProject.owner_ref })
.should.equal(true)
})
it('should call User.getUser', function (ctx) {
ctx.UserGetter.promises.getUser.callCount.should.equal(1)
ctx.UserGetter.promises.getUser
.calledWith({ _id: ctx.fakeProject.owner_ref })
.should.equal(true)
})
it('should not call ProjectGetter.getProject', function (ctx) {
ctx.ProjectGetter.promises.getProject.callCount.should.equal(0)
it('should not call ProjectGetter.getProject', function (ctx) {
ctx.ProjectGetter.promises.getProject.callCount.should.equal(0)
})
})
})
@@ -1229,54 +1331,102 @@ describe('CollaboratorsInviteController', function () {
})
describe('when Project.getUser does not find a user', function () {
beforeEach(async function (ctx) {
await new Promise(resolve => {
ctx.ProjectGetter.promises.getProject.resolves(null)
ctx.res.callback = () => resolve()
ctx.CollaboratorsInviteController.viewInvite(
ctx.req,
ctx.res,
ctx.next
describe('when the sharing-updates variant is "enabled"', function () {
beforeEach(async function (ctx) {
ctx.SplitTestHandler.promises.getAssignment.resolves({
variant: 'enabled',
})
await new Promise(resolve => {
ctx.ProjectGetter.promises.getProject.resolves(null)
ctx.res.callback = () => resolve()
ctx.CollaboratorsInviteController.viewInvite(
ctx.req,
ctx.res,
ctx.next
)
})
})
it('should render the not-valid view template', function (ctx) {
expect(ctx.res.render).toHaveBeenCalledTimes(1)
expect(ctx.res.render).toHaveBeenCalledWith(
'project/invite/not-valid',
expect.anything()
)
})
it('should not call next', function (ctx) {
ctx.next.callCount.should.equal(0)
})
})
it('should render the not-valid view template', function (ctx) {
expect(ctx.res.render).toHaveBeenCalledTimes(1)
expect(ctx.res.render).toHaveBeenCalledWith(
'project/invite/not-valid',
expect.anything()
)
describe('when the sharing-updates variant is "default"', function () {
beforeEach(async function (ctx) {
ctx.SplitTestHandler.promises.getAssignment.resolves({
variant: 'default',
})
await new Promise(resolve => {
ctx.ProjectGetter.promises.getProject.resolves(null)
ctx.res.callback = () => resolve()
ctx.CollaboratorsInviteController.viewInvite(
ctx.req,
ctx.res,
ctx.next
)
})
})
it('should render the not-valid-legacy view template', function (ctx) {
expect(ctx.res.render).toHaveBeenCalledTimes(1)
expect(ctx.res.render).toHaveBeenCalledWith(
'project/invite/not-valid-legacy',
expect.anything()
)
})
it('should not call next', function (ctx) {
ctx.next.callCount.should.equal(0)
})
})
it('should not call next', function (ctx) {
ctx.next.callCount.should.equal(0)
})
describe('common behaviour', function () {
beforeEach(async function (ctx) {
await new Promise(resolve => {
ctx.ProjectGetter.promises.getProject.resolves(null)
ctx.res.callback = () => resolve()
ctx.CollaboratorsInviteController.viewInvite(
ctx.req,
ctx.res,
ctx.next
)
})
})
it('should call CollaboratorsGetter.isUserInvitedMemberOfProject', function (ctx) {
ctx.CollaboratorsGetter.promises.isUserInvitedMemberOfProject.callCount.should.equal(
1
)
ctx.CollaboratorsGetter.promises.isUserInvitedMemberOfProject
.calledWith(ctx.currentUser._id, ctx.projectId)
.should.equal(true)
})
it('should call CollaboratorsGetter.isUserInvitedMemberOfProject', function (ctx) {
ctx.CollaboratorsGetter.promises.isUserInvitedMemberOfProject.callCount.should.equal(
1
)
ctx.CollaboratorsGetter.promises.isUserInvitedMemberOfProject
.calledWith(ctx.currentUser._id, ctx.projectId)
.should.equal(true)
})
it('should call getInviteByToken', function (ctx) {
ctx.CollaboratorsInviteGetter.promises.getInviteByToken.callCount.should.equal(
1
)
})
it('should call getInviteByToken', function (ctx) {
ctx.CollaboratorsInviteGetter.promises.getInviteByToken.callCount.should.equal(
1
)
})
it('should call getUser', function (ctx) {
ctx.UserGetter.promises.getUser.callCount.should.equal(1)
ctx.UserGetter.promises.getUser
.calledWith({ _id: ctx.fakeProject.owner_ref })
.should.equal(true)
})
it('should call getUser', function (ctx) {
ctx.UserGetter.promises.getUser.callCount.should.equal(1)
ctx.UserGetter.promises.getUser
.calledWith({ _id: ctx.fakeProject.owner_ref })
.should.equal(true)
})
it('should call ProjectGetter.getProject', function (ctx) {
ctx.ProjectGetter.promises.getProject.callCount.should.equal(1)
it('should call ProjectGetter.getProject', function (ctx) {
ctx.ProjectGetter.promises.getProject.callCount.should.equal(1)
})
})
})
})