mirror of
https://github.com/yu-i-i/overleaf-cep.git
synced 2026-11-12 13:13:45 +01:00
Merge pull request #28380 from overleaf/td-zod-history
Migrate history-related web back end to Zod GitOrigin-RevId: 38ed56927bee4f5670604d7178b096e382c8cb65
This commit is contained in:
@@ -25,6 +25,7 @@ import ProjectEntityUpdateHandler from '../Project/ProjectEntityUpdateHandler.js
|
|||||||
import RestoreManager from './RestoreManager.mjs'
|
import RestoreManager from './RestoreManager.mjs'
|
||||||
import { prepareZipAttachment } from '../../infrastructure/Response.js'
|
import { prepareZipAttachment } from '../../infrastructure/Response.js'
|
||||||
import Features from '../../infrastructure/Features.js'
|
import Features from '../../infrastructure/Features.js'
|
||||||
|
import { z, zz, validateReq } from '../../infrastructure/Validation.js'
|
||||||
|
|
||||||
// Number of seconds after which the browser should send a request to revalidate
|
// Number of seconds after which the browser should send a request to revalidate
|
||||||
// blobs
|
// blobs
|
||||||
@@ -44,8 +45,19 @@ async function headBlob(req, res) {
|
|||||||
await requestBlob('HEAD', req, res)
|
await requestBlob('HEAD', req, res)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const requestBlobSchema = z.object({
|
||||||
|
params: z.object({
|
||||||
|
project_id: zz.coercedObjectId(),
|
||||||
|
hash: zz.hex().length(40),
|
||||||
|
}),
|
||||||
|
query: z.object({
|
||||||
|
fallback: zz.coercedObjectId().optional(),
|
||||||
|
}),
|
||||||
|
})
|
||||||
|
|
||||||
async function requestBlob(method, req, res) {
|
async function requestBlob(method, req, res) {
|
||||||
const { project_id: projectId, hash } = req.params
|
const { params } = validateReq(req, requestBlobSchema)
|
||||||
|
const { project_id: projectId, hash } = params
|
||||||
|
|
||||||
// Handle conditional GET request
|
// Handle conditional GET request
|
||||||
if (req.get('If-None-Match') === hash) {
|
if (req.get('If-None-Match') === hash) {
|
||||||
@@ -461,17 +473,35 @@ async function _pipeHistoryZipToResponse(v1ProjectId, version, name, req, res) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const getLatestHistorySchema = z.object({
|
||||||
|
params: z.object({
|
||||||
|
project_id: zz.objectId(),
|
||||||
|
}),
|
||||||
|
})
|
||||||
|
|
||||||
async function getLatestHistory(req, res, next) {
|
async function getLatestHistory(req, res, next) {
|
||||||
const projectId = req.params.project_id
|
const { params } = validateReq(req, getLatestHistorySchema)
|
||||||
|
const projectId = params.project_id
|
||||||
const history = await HistoryManager.promises.getLatestHistory(projectId)
|
const history = await HistoryManager.promises.getLatestHistory(projectId)
|
||||||
res.json(history)
|
res.json(history)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const getChangesSchema = z.object({
|
||||||
|
params: z.object({
|
||||||
|
project_id: zz.objectId(),
|
||||||
|
}),
|
||||||
|
query: z.object({
|
||||||
|
since: z.coerce.number().int().min(0).optional(),
|
||||||
|
paginated: z.stringbool().optional(),
|
||||||
|
}),
|
||||||
|
})
|
||||||
|
|
||||||
async function getChanges(req, res, next) {
|
async function getChanges(req, res, next) {
|
||||||
const projectId = req.params.project_id
|
const { params, query } = validateReq(req, getChangesSchema)
|
||||||
let since = req.query.since
|
const projectId = params.project_id
|
||||||
|
let since = query.since
|
||||||
// TODO: Transition flag; remove after a while
|
// TODO: Transition flag; remove after a while
|
||||||
const paginated = req.query.paginated === 'true'
|
const paginated = query.paginated
|
||||||
|
|
||||||
if (paginated) {
|
if (paginated) {
|
||||||
const changes = await HistoryManager.promises.getChanges(projectId, {
|
const changes = await HistoryManager.promises.getChanges(projectId, {
|
||||||
|
|||||||
@@ -280,8 +280,8 @@ async function getLatestHistory(projectId) {
|
|||||||
* Get history changes since a given version
|
* Get history changes since a given version
|
||||||
*
|
*
|
||||||
* @param {string} projectId
|
* @param {string} projectId
|
||||||
* @param {object} opts
|
* @param {object} [opts]
|
||||||
* @param {number} opts.since - The start version of changes to get
|
* @param {number} [opts.since] - The start version of changes to get
|
||||||
*/
|
*/
|
||||||
async function getChanges(projectId, opts = {}) {
|
async function getChanges(projectId, opts = {}) {
|
||||||
const historyId = await getHistoryId(projectId)
|
const historyId = await getHistoryId(projectId)
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
// @ts-check
|
// @ts-check
|
||||||
|
|
||||||
import Settings from '@overleaf/settings'
|
import Settings from '@overleaf/settings'
|
||||||
import { Joi, validate } from '../../infrastructure/Validation.js'
|
|
||||||
import { RateLimiter } from '../../infrastructure/RateLimiter.js'
|
import { RateLimiter } from '../../infrastructure/RateLimiter.js'
|
||||||
import AuthenticationController from '../Authentication/AuthenticationController.js'
|
import AuthenticationController from '../Authentication/AuthenticationController.js'
|
||||||
import AuthorizationMiddleware from '../Authorization/AuthorizationMiddleware.mjs'
|
import AuthorizationMiddleware from '../Authorization/AuthorizationMiddleware.mjs'
|
||||||
@@ -29,30 +28,12 @@ function apply(webRouter, privateApiRouter) {
|
|||||||
|
|
||||||
webRouter.head(
|
webRouter.head(
|
||||||
'/project/:project_id/blob/:hash',
|
'/project/:project_id/blob/:hash',
|
||||||
validate({
|
|
||||||
params: Joi.object({
|
|
||||||
project_id: Joi.objectId().required(),
|
|
||||||
hash: Joi.string().required().hex().length(40),
|
|
||||||
}),
|
|
||||||
query: Joi.object({
|
|
||||||
fallback: Joi.objectId().optional(),
|
|
||||||
}),
|
|
||||||
}),
|
|
||||||
RateLimiterMiddleware.rateLimit(rateLimiters.getProjectBlob),
|
RateLimiterMiddleware.rateLimit(rateLimiters.getProjectBlob),
|
||||||
AuthorizationMiddleware.ensureUserCanReadProject,
|
AuthorizationMiddleware.ensureUserCanReadProject,
|
||||||
HistoryController.headBlob
|
HistoryController.headBlob
|
||||||
)
|
)
|
||||||
webRouter.get(
|
webRouter.get(
|
||||||
'/project/:project_id/blob/:hash',
|
'/project/:project_id/blob/:hash',
|
||||||
validate({
|
|
||||||
params: Joi.object({
|
|
||||||
project_id: Joi.objectId().required(),
|
|
||||||
hash: Joi.string().required().hex().length(40),
|
|
||||||
}),
|
|
||||||
query: Joi.object({
|
|
||||||
fallback: Joi.objectId().optional(),
|
|
||||||
}),
|
|
||||||
}),
|
|
||||||
RateLimiterMiddleware.rateLimit(rateLimiters.getProjectBlob),
|
RateLimiterMiddleware.rateLimit(rateLimiters.getProjectBlob),
|
||||||
AuthorizationMiddleware.ensureUserCanReadProject,
|
AuthorizationMiddleware.ensureUserCanReadProject,
|
||||||
HistoryController.getBlob
|
HistoryController.getBlob
|
||||||
@@ -151,25 +132,12 @@ function apply(webRouter, privateApiRouter) {
|
|||||||
|
|
||||||
webRouter.get(
|
webRouter.get(
|
||||||
'/project/:project_id/latest/history',
|
'/project/:project_id/latest/history',
|
||||||
validate({
|
|
||||||
params: Joi.object({
|
|
||||||
project_id: Joi.objectId().required(),
|
|
||||||
}),
|
|
||||||
}),
|
|
||||||
AuthorizationMiddleware.blockRestrictedUserFromProject,
|
AuthorizationMiddleware.blockRestrictedUserFromProject,
|
||||||
AuthorizationMiddleware.ensureUserCanReadProject,
|
AuthorizationMiddleware.ensureUserCanReadProject,
|
||||||
HistoryController.getLatestHistory
|
HistoryController.getLatestHistory
|
||||||
)
|
)
|
||||||
webRouter.get(
|
webRouter.get(
|
||||||
'/project/:project_id/changes',
|
'/project/:project_id/changes',
|
||||||
validate({
|
|
||||||
params: Joi.object({
|
|
||||||
project_id: Joi.objectId().required(),
|
|
||||||
}),
|
|
||||||
query: Joi.object({
|
|
||||||
since: Joi.number().integer().min(0).optional(),
|
|
||||||
}),
|
|
||||||
}),
|
|
||||||
AuthorizationMiddleware.blockRestrictedUserFromProject,
|
AuthorizationMiddleware.blockRestrictedUserFromProject,
|
||||||
AuthorizationMiddleware.ensureUserCanReadProject,
|
AuthorizationMiddleware.ensureUserCanReadProject,
|
||||||
HistoryController.getChanges
|
HistoryController.getChanges
|
||||||
|
|||||||
@@ -48,6 +48,7 @@ const zz = {
|
|||||||
.string()
|
.string()
|
||||||
.refine(ObjectId.isValid, { message: 'invalid Mongo ObjectId' })
|
.refine(ObjectId.isValid, { message: 'invalid Mongo ObjectId' })
|
||||||
.transform(val => new ObjectId(val)),
|
.transform(val => new ObjectId(val)),
|
||||||
|
hex: () => z.string().regex(/^[0-9a-f]*$/),
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
Reference in New Issue
Block a user