mirror of
https://github.com/yu-i-i/overleaf-cep.git
synced 2026-11-12 13:13:45 +01:00
Merge pull request #36225 from overleaf/jpa-zod-web-final
[web] fully adopt strict zod schema and enforce in tests GitOrigin-RevId: 1bb03ed3a819be6de38c8ca5758b3909cfa23318
This commit is contained in:
@@ -40,9 +40,19 @@ export default {
|
||||
grantAccessRequest: expressify(grantAccessRequest),
|
||||
}
|
||||
|
||||
const removeUserFromProjectSchema = z.object({
|
||||
params: z.strictObject({
|
||||
Project_id: zz.objectId(),
|
||||
user_id: zz.objectId(),
|
||||
}),
|
||||
})
|
||||
|
||||
async function removeUserFromProject(req, res, next) {
|
||||
const projectId = req.params.Project_id
|
||||
const userId = req.params.user_id
|
||||
const { params } = parseReq(req, removeUserFromProjectSchema, {
|
||||
logOnly: true,
|
||||
})
|
||||
const projectId = params.Project_id
|
||||
const userId = params.user_id
|
||||
const sessionUserId = SessionManager.getLoggedInUserId(req.session)
|
||||
await _removeUserIdFromProject(projectId, userId)
|
||||
EditorRealTimeController.emitToRoom(projectId, 'project:membership:changed', {
|
||||
@@ -68,8 +78,17 @@ async function removeUserFromProject(req, res, next) {
|
||||
res.sendStatus(204)
|
||||
}
|
||||
|
||||
const removeSelfFromProjectSchema = z.object({
|
||||
params: z.strictObject({
|
||||
Project_id: zz.objectId(),
|
||||
}),
|
||||
})
|
||||
|
||||
async function removeSelfFromProject(req, res, next) {
|
||||
const projectId = req.params.Project_id
|
||||
const { params } = parseReq(req, removeSelfFromProjectSchema, {
|
||||
logOnly: true,
|
||||
})
|
||||
const projectId = params.Project_id
|
||||
const userId = SessionManager.getLoggedInUserId(req.session)
|
||||
await _removeUserIdFromProject(projectId, userId)
|
||||
EditorRealTimeController.emitToRoom(projectId, 'project:membership:changed', {
|
||||
@@ -86,8 +105,15 @@ async function removeSelfFromProject(req, res, next) {
|
||||
res.sendStatus(204)
|
||||
}
|
||||
|
||||
const getAllMembersSchema = z.object({
|
||||
params: z.strictObject({
|
||||
Project_id: zz.objectId(),
|
||||
}),
|
||||
})
|
||||
|
||||
async function getAllMembers(req, res, next) {
|
||||
const projectId = req.params.Project_id
|
||||
const { params } = parseReq(req, getAllMembersSchema, { logOnly: true })
|
||||
const projectId = params.Project_id
|
||||
logger.debug({ projectId }, 'getting all active members for project')
|
||||
let members
|
||||
try {
|
||||
@@ -98,11 +124,20 @@ async function getAllMembers(req, res, next) {
|
||||
res.json({ members })
|
||||
}
|
||||
|
||||
const getAccessRequestsSchema = z.object({
|
||||
params: z.strictObject({
|
||||
Project_id: zz.objectId(),
|
||||
}),
|
||||
})
|
||||
|
||||
// The pending access requests carry requester identities, so this is admin
|
||||
// gated by the router (ensureUserCanAdminProject). A requester's own
|
||||
// `myAccessRequest` is delivered via the editor bootstrap instead.
|
||||
async function getAccessRequests(req, res) {
|
||||
const projectId = req.params.Project_id
|
||||
const { params } = parseReq(req, getAccessRequestsSchema, {
|
||||
logOnly: true,
|
||||
})
|
||||
const projectId = params.Project_id
|
||||
const projectAccess =
|
||||
await CollaboratorsGetter.promises.getProjectAccess(projectId)
|
||||
const editAccessRequests = await projectAccess.loadAccessRequestsView()
|
||||
@@ -110,6 +145,22 @@ async function getAccessRequests(req, res) {
|
||||
}
|
||||
|
||||
const setCollaboratorInfoSchema = z.object({
|
||||
params: z.strictObject({
|
||||
Project_id: zz.objectId(),
|
||||
user_id: zz.objectId(),
|
||||
}),
|
||||
body: z.strictObject({
|
||||
privilegeLevel: z.enum([
|
||||
PrivilegeLevels.READ_ONLY,
|
||||
PrivilegeLevels.READ_AND_WRITE,
|
||||
PrivilegeLevels.REVIEW,
|
||||
]),
|
||||
}),
|
||||
})
|
||||
|
||||
// Rollout-temporary fallback (pre-refinement schema from main); delete
|
||||
// when this route's REQ_VALIDATION_MODE instrumentation is removed.
|
||||
const setCollaboratorInfoFallbackSchema = z.object({
|
||||
params: z.object({
|
||||
Project_id: zz.objectId(),
|
||||
user_id: zz.objectId(),
|
||||
@@ -125,7 +176,9 @@ const setCollaboratorInfoSchema = z.object({
|
||||
|
||||
async function setCollaboratorInfo(req, res, next) {
|
||||
try {
|
||||
const { params, body } = parseReq(req, setCollaboratorInfoSchema)
|
||||
const { params, body } = parseReq(req, setCollaboratorInfoSchema, {
|
||||
fallbackSchema: setCollaboratorInfoFallbackSchema,
|
||||
})
|
||||
const projectId = params.Project_id
|
||||
const userId = params.user_id
|
||||
const { privilegeLevel } = body
|
||||
@@ -172,6 +225,17 @@ async function setCollaboratorInfo(req, res, next) {
|
||||
}
|
||||
|
||||
const transferOwnershipSchema = z.object({
|
||||
params: z.strictObject({
|
||||
Project_id: zz.objectId(),
|
||||
}),
|
||||
body: z.strictObject({
|
||||
user_id: zz.objectId(),
|
||||
}),
|
||||
})
|
||||
|
||||
// Rollout-temporary fallback (pre-refinement schema from main); delete
|
||||
// when this route's REQ_VALIDATION_MODE instrumentation is removed.
|
||||
const transferOwnershipFallbackSchema = z.object({
|
||||
params: z.object({
|
||||
Project_id: zz.objectId(),
|
||||
}),
|
||||
@@ -182,7 +246,9 @@ const transferOwnershipSchema = z.object({
|
||||
|
||||
async function transferOwnership(req, res, next) {
|
||||
const sessionUser = SessionManager.getSessionUser(req.session)
|
||||
const { params, body } = parseReq(req, transferOwnershipSchema)
|
||||
const { params, body } = parseReq(req, transferOwnershipSchema, {
|
||||
fallbackSchema: transferOwnershipFallbackSchema,
|
||||
})
|
||||
const projectId = params.Project_id
|
||||
const toUserId = body.user_id
|
||||
try {
|
||||
@@ -214,6 +280,20 @@ async function transferOwnership(req, res, next) {
|
||||
}
|
||||
|
||||
const requestAccessSchema = z.object({
|
||||
params: z.strictObject({
|
||||
Project_id: zz.objectId(),
|
||||
}),
|
||||
body: z.strictObject({
|
||||
privilegeLevel: z.enum([
|
||||
PrivilegeLevels.READ_AND_WRITE,
|
||||
PrivilegeLevels.REVIEW,
|
||||
]),
|
||||
}),
|
||||
})
|
||||
|
||||
// Rollout-temporary fallback (pre-refinement schema from main); delete
|
||||
// when this route's REQ_VALIDATION_MODE instrumentation is removed.
|
||||
const requestAccessFallbackSchema = z.object({
|
||||
params: z.object({
|
||||
Project_id: zz.objectId(),
|
||||
}),
|
||||
@@ -238,7 +318,9 @@ const REQUESTABLE_LEVELS_BY_CURRENT_LEVEL = {
|
||||
}
|
||||
|
||||
async function requestAccess(req, res) {
|
||||
const { params, body } = parseReq(req, requestAccessSchema)
|
||||
const { params, body } = parseReq(req, requestAccessSchema, {
|
||||
fallbackSchema: requestAccessFallbackSchema,
|
||||
})
|
||||
const projectId = params.Project_id
|
||||
const { privilegeLevel } = body
|
||||
const userId = SessionManager.getLoggedInUserId(req.session)
|
||||
@@ -279,6 +361,18 @@ async function requestAccess(req, res) {
|
||||
}
|
||||
|
||||
const declineAccessRequestSchema = z.object({
|
||||
params: z.strictObject({
|
||||
Project_id: zz.objectId(),
|
||||
user_id: zz.objectId(),
|
||||
}),
|
||||
body: z.strictObject({
|
||||
notify: z.boolean().optional(),
|
||||
}),
|
||||
})
|
||||
|
||||
// Rollout-temporary fallback (pre-refinement schema from main); delete
|
||||
// when this route's REQ_VALIDATION_MODE instrumentation is removed.
|
||||
const declineAccessRequestFallbackSchema = z.object({
|
||||
params: z.object({
|
||||
Project_id: zz.objectId(),
|
||||
user_id: zz.objectId(),
|
||||
@@ -289,7 +383,9 @@ const declineAccessRequestSchema = z.object({
|
||||
})
|
||||
|
||||
async function declineAccessRequest(req, res) {
|
||||
const { params, body } = parseReq(req, declineAccessRequestSchema)
|
||||
const { params, body } = parseReq(req, declineAccessRequestSchema, {
|
||||
fallbackSchema: declineAccessRequestFallbackSchema,
|
||||
})
|
||||
const projectId = params.Project_id
|
||||
const userId = params.user_id
|
||||
const notify = body.notify === true
|
||||
@@ -323,6 +419,22 @@ async function declineAccessRequest(req, res) {
|
||||
}
|
||||
|
||||
const grantAccessRequestSchema = z.object({
|
||||
params: z.strictObject({
|
||||
Project_id: zz.objectId(),
|
||||
user_id: zz.objectId(),
|
||||
}),
|
||||
body: z.strictObject({
|
||||
privilegeLevel: z.enum([
|
||||
PrivilegeLevels.READ_AND_WRITE,
|
||||
PrivilegeLevels.REVIEW,
|
||||
]),
|
||||
notify: z.boolean().optional(),
|
||||
}),
|
||||
})
|
||||
|
||||
// Rollout-temporary fallback (pre-refinement schema from main); delete
|
||||
// when this route's REQ_VALIDATION_MODE instrumentation is removed.
|
||||
const grantAccessRequestFallbackSchema = z.object({
|
||||
params: z.object({
|
||||
Project_id: zz.objectId(),
|
||||
user_id: zz.objectId(),
|
||||
@@ -337,7 +449,9 @@ const grantAccessRequestSchema = z.object({
|
||||
})
|
||||
|
||||
async function grantAccessRequest(req, res) {
|
||||
const { params, body } = parseReq(req, grantAccessRequestSchema)
|
||||
const { params, body } = parseReq(req, grantAccessRequestSchema, {
|
||||
fallbackSchema: grantAccessRequestFallbackSchema,
|
||||
})
|
||||
const projectId = params.Project_id
|
||||
const requesterId = params.user_id
|
||||
const { privilegeLevel, notify } = body
|
||||
@@ -507,8 +621,15 @@ async function _removeUserIdFromProject(projectId, userId) {
|
||||
await TagsHandler.promises.removeProjectFromAllTags(userId, projectId)
|
||||
}
|
||||
|
||||
const getShareTokensSchema = z.object({
|
||||
params: z.strictObject({
|
||||
Project_id: zz.objectId(),
|
||||
}),
|
||||
})
|
||||
|
||||
async function getShareTokens(req, res) {
|
||||
const projectId = req.params.Project_id
|
||||
const { params } = parseReq(req, getShareTokensSchema, { logOnly: true })
|
||||
const projectId = params.Project_id
|
||||
const userId = SessionManager.getLoggedInUserId(req.session)
|
||||
|
||||
if (!Features.hasFeature('link-sharing')) {
|
||||
|
||||
@@ -40,8 +40,15 @@ const rateLimiter = new RateLimiter('invite-to-project-by-user-id', {
|
||||
duration: 60 * 30,
|
||||
})
|
||||
|
||||
const getAllInvitesSchema = z.object({
|
||||
params: z.strictObject({
|
||||
Project_id: zz.objectId(),
|
||||
}),
|
||||
})
|
||||
|
||||
async function getAllInvites(req, res) {
|
||||
const projectId = req.params.Project_id
|
||||
const { params } = parseReq(req, getAllInvitesSchema, { logOnly: true })
|
||||
const projectId = params.Project_id
|
||||
logger.debug({ projectId }, 'getting all active invites for project')
|
||||
const invites =
|
||||
await CollaboratorsInviteGetter.promises.getAllInvites(projectId)
|
||||
@@ -89,6 +96,21 @@ async function _checkRateLimit(userId) {
|
||||
}
|
||||
|
||||
const inviteToProjectSchema = z.object({
|
||||
params: z.strictObject({
|
||||
Project_id: zz.objectId(),
|
||||
}),
|
||||
body: z.strictObject({
|
||||
email: z.string(),
|
||||
privileges: z.enum([
|
||||
PrivilegeLevels.READ_ONLY,
|
||||
PrivilegeLevels.READ_AND_WRITE,
|
||||
PrivilegeLevels.REVIEW,
|
||||
]),
|
||||
}),
|
||||
})
|
||||
// Rollout-temporary fallback (pre-refinement schema from main); delete
|
||||
// when this route's REQ_VALIDATION_MODE instrumentation is removed.
|
||||
const inviteToProjectFallbackSchema = z.object({
|
||||
params: z.object({
|
||||
Project_id: zz.objectId(),
|
||||
}),
|
||||
@@ -103,7 +125,9 @@ const inviteToProjectSchema = z.object({
|
||||
})
|
||||
|
||||
async function inviteToProject(req, res) {
|
||||
const { params, body } = parseReq(req, inviteToProjectSchema)
|
||||
const { params, body } = parseReq(req, inviteToProjectSchema, {
|
||||
fallbackSchema: inviteToProjectFallbackSchema,
|
||||
})
|
||||
const projectId = params.Project_id
|
||||
let { email, privileges } = body
|
||||
const sendingUser = SessionManager.getSessionUser(req.session)
|
||||
@@ -189,9 +213,17 @@ async function inviteToProject(req, res) {
|
||||
})
|
||||
res.json({ invite })
|
||||
}
|
||||
const revokeInviteSchema = z.object({
|
||||
params: z.strictObject({
|
||||
Project_id: zz.objectId(),
|
||||
invite_id: zz.objectId(),
|
||||
}),
|
||||
})
|
||||
|
||||
async function revokeInvite(req, res) {
|
||||
const projectId = req.params.Project_id
|
||||
const inviteId = req.params.invite_id
|
||||
const { params } = parseReq(req, revokeInviteSchema, { logOnly: true })
|
||||
const projectId = params.Project_id
|
||||
const inviteId = params.invite_id
|
||||
const user = SessionManager.getSessionUser(req.session)
|
||||
|
||||
logger.debug({ projectId, inviteId }, 'revoking invite')
|
||||
@@ -223,9 +255,19 @@ async function revokeInvite(req, res) {
|
||||
res.sendStatus(204)
|
||||
}
|
||||
|
||||
const generateNewInviteSchema = z.object({
|
||||
params: z.strictObject({
|
||||
Project_id: zz.objectId(),
|
||||
invite_id: zz.objectId(),
|
||||
}),
|
||||
})
|
||||
|
||||
async function generateNewInvite(req, res) {
|
||||
const projectId = req.params.Project_id
|
||||
const inviteId = req.params.invite_id
|
||||
const { params } = parseReq(req, generateNewInviteSchema, {
|
||||
logOnly: true,
|
||||
})
|
||||
const projectId = params.Project_id
|
||||
const inviteId = params.invite_id
|
||||
const user = SessionManager.getSessionUser(req.session)
|
||||
|
||||
logger.debug({ projectId, inviteId }, 'resending invite')
|
||||
@@ -275,9 +317,17 @@ const _renderInvalidPage = function (res, projectId, sharingUpdates) {
|
||||
}
|
||||
}
|
||||
|
||||
const viewInviteSchema = z.object({
|
||||
params: z.strictObject({
|
||||
Project_id: zz.objectId(),
|
||||
token: z.string(),
|
||||
}),
|
||||
})
|
||||
|
||||
async function viewInvite(req, res) {
|
||||
const projectId = req.params.Project_id
|
||||
const { token } = req.params
|
||||
const { params } = parseReq(req, viewInviteSchema, { logOnly: true })
|
||||
const projectId = params.Project_id
|
||||
const { token } = params
|
||||
|
||||
const { variant: sharingUpdates } =
|
||||
await SplitTestHandler.promises.getAssignment(req, res, 'sharing-updates')
|
||||
@@ -361,8 +411,15 @@ async function viewInvite(req, res) {
|
||||
}
|
||||
}
|
||||
|
||||
const viewSharingLinkSchema = z.object({
|
||||
params: z.strictObject({
|
||||
Project_id: zz.objectId(),
|
||||
}),
|
||||
})
|
||||
|
||||
async function viewSharingLink(req, res) {
|
||||
const projectId = req.params.Project_id
|
||||
const { params } = parseReq(req, viewSharingLinkSchema, { logOnly: true })
|
||||
const projectId = params.Project_id
|
||||
|
||||
// ensure the project exists
|
||||
const project = await ProjectGetter.promises.getProject(projectId, {
|
||||
@@ -397,9 +454,22 @@ async function viewSharingLink(req, res) {
|
||||
})
|
||||
}
|
||||
|
||||
const acceptInviteSchema = z.object({
|
||||
params: z.strictObject({
|
||||
Project_id: zz.objectId(),
|
||||
token: z.string().optional(),
|
||||
}),
|
||||
body: z.strictObject({
|
||||
token: z.string().optional(),
|
||||
}),
|
||||
})
|
||||
|
||||
async function acceptInvite(req, res) {
|
||||
const { Project_id: projectId, token: urlToken } = req.params
|
||||
const { token: bodyToken } = req.body
|
||||
const { params, body } = parseReq(req, acceptInviteSchema, {
|
||||
logOnly: true,
|
||||
})
|
||||
const { Project_id: projectId, token: urlToken } = params
|
||||
const { token: bodyToken } = body
|
||||
const currentUser = SessionManager.getSessionUser(req.session)
|
||||
logger.debug(
|
||||
{ projectId, userId: currentUser._id },
|
||||
@@ -519,8 +589,16 @@ async function acceptInvite(req, res) {
|
||||
}
|
||||
}
|
||||
|
||||
const getSharingLinkSchema = z.object({
|
||||
params: z.strictObject({
|
||||
Project_id: zz.objectId(),
|
||||
}),
|
||||
})
|
||||
|
||||
async function getSharingLink(req, res) {
|
||||
const { Project_id: projectId } = req.params
|
||||
const { Project_id: projectId } = parseReq(req, getSharingLinkSchema, {
|
||||
logOnly: true,
|
||||
}).params
|
||||
|
||||
const invite =
|
||||
await CollaboratorsInviteGetter.promises.getSharingLinkInvite(projectId)
|
||||
@@ -541,6 +619,26 @@ async function getSharingLink(req, res) {
|
||||
}
|
||||
|
||||
const updateSharingLinkSchema = z.object({
|
||||
params: z.strictObject({
|
||||
Project_id: zz.objectId(),
|
||||
}),
|
||||
body: z.strictObject({
|
||||
// We have to use a union here, as Zod enums must be strings,
|
||||
// but NONE is defined as boolean false
|
||||
privileges: z.union([
|
||||
z.literal(PrivilegeLevels.NONE),
|
||||
z.enum([
|
||||
PrivilegeLevels.READ_ONLY,
|
||||
PrivilegeLevels.READ_AND_WRITE,
|
||||
PrivilegeLevels.REVIEW,
|
||||
]),
|
||||
]),
|
||||
subscriptionId: zz.objectId().optional(),
|
||||
}),
|
||||
})
|
||||
// Rollout-temporary fallback (pre-refinement schema from main); delete
|
||||
// when this route's REQ_VALIDATION_MODE instrumentation is removed.
|
||||
const updateSharingLinkFallbackSchema = z.object({
|
||||
params: z.object({
|
||||
Project_id: zz.objectId(),
|
||||
}),
|
||||
@@ -560,7 +658,9 @@ const updateSharingLinkSchema = z.object({
|
||||
})
|
||||
|
||||
async function updateSharingLink(req, res) {
|
||||
const { params, body } = parseReq(req, updateSharingLinkSchema)
|
||||
const { params, body } = parseReq(req, updateSharingLinkSchema, {
|
||||
fallbackSchema: updateSharingLinkFallbackSchema,
|
||||
})
|
||||
const projectId = params.Project_id
|
||||
const privileges = body.privileges
|
||||
const subscriptionId = body.subscriptionId
|
||||
@@ -635,6 +735,16 @@ async function updateSharingLink(req, res) {
|
||||
}
|
||||
|
||||
const validateSharingLinkSchema = z.object({
|
||||
params: z.strictObject({
|
||||
Project_id: zz.objectId(),
|
||||
}),
|
||||
body: z.strictObject({
|
||||
token: z.string(),
|
||||
}),
|
||||
})
|
||||
// Rollout-temporary fallback (pre-refinement schema from main); delete
|
||||
// when this route's REQ_VALIDATION_MODE instrumentation is removed.
|
||||
const validateSharingLinkFallbackSchema = z.object({
|
||||
params: z.object({
|
||||
Project_id: zz.objectId(),
|
||||
}),
|
||||
@@ -644,7 +754,9 @@ const validateSharingLinkSchema = z.object({
|
||||
})
|
||||
|
||||
async function validateSharingLink(req, res) {
|
||||
const { params, body } = parseReq(req, validateSharingLinkSchema)
|
||||
const { params, body } = parseReq(req, validateSharingLinkSchema, {
|
||||
fallbackSchema: validateSharingLinkFallbackSchema,
|
||||
})
|
||||
const projectId = params.Project_id
|
||||
const { token } = body
|
||||
|
||||
|
||||
Reference in New Issue
Block a user