Skip to content

Commit

Permalink
[WIP] ability to request a scene with a specified revision
Browse files Browse the repository at this point in the history
  • Loading branch information
sdumetz committed Jan 15, 2024
1 parent 9a5344a commit 02b84b7
Show file tree
Hide file tree
Showing 6 changed files with 56 additions and 9 deletions.
5 changes: 4 additions & 1 deletion source/server/routes/api/v1/scenes/scene/history/post.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,11 @@ import { ItemEntry } from "../../../../../../vfs/index.js";
* What is "before" or "after" is defined by the reverse of what is returned by `GET /api/v1/scenes/:scene/history`
* That is the algorithm will remove everything in indices :
* history[0] .. history[indexOf(:id)]
*
* It uses a file's name and generation or id and type to find the point to restore to.
*
* @see {getSceneHistory}
* @see {@link getSceneHistory} for content ordering
* @see {@link getScene} for another example
*/
export async function postSceneHistory(req :Request, res :Response){
let requester = getUser(req);
Expand Down
11 changes: 9 additions & 2 deletions source/server/utils/locals.test.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import express, { Express, NextFunction, Request, RequestHandler, Response } from "express";
import request from "supertest";
import { InternalError, UnauthorizedError } from "./errors.js";
import { either } from "./locals.js";
import { either, getSceneParams } from "./locals.js";

//Dummy middlewares
function pass(req :Request, res :Response, next :NextFunction){
Expand Down Expand Up @@ -52,4 +52,11 @@ describe("either() middleware", function(){
app.get("/", either(fail, fail), h);
await request(app).get("/").expect(401);
});
});
});

describe("getSceneParams()", function(){

it("parses a request's scene parameter", function(){
expect(getSceneParams({params:{scene:"foo"}} as any)).to.deep.equal({scene:"foo", revision: undefined});
})
})
15 changes: 12 additions & 3 deletions source/server/utils/locals.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { NextFunction, Request, RequestHandler, Response } from "express";
import {basename, dirname} from "path";
import User, { SafeUser } from "../auth/User.js";
import UserManager, { AccessType, AccessTypes } from "../auth/UserManager.js";
import Vfs, { GetFileParams } from "../vfs/index.js";
import Vfs, { GetFileParams, GetSceneParams } from "../vfs/index.js";
import { BadRequestError, ForbiddenError, HTTPError, InternalError, NotFoundError, UnauthorizedError } from "./errors.js";
import Templates from "./templates.js";

Expand Down Expand Up @@ -136,12 +136,21 @@ export function getUserId(req :Request){
return getUser(req).uid;
}

export function getSceneParams(req :Request) :GetSceneParams{
const {scene:sceneSlug} = req.params;
if(!sceneSlug) throw new BadRequestError(`Scene parameter not provided`);
const [scene, revision] = sceneSlug.split("$");
if(revision && !/^(?:file|document)\.\d+$/.test(revision)) throw new BadRequestError(`Invalid revision parameter "${revision}"`);
return {scene, revision};
}

export function getFileParams(req :Request):GetFileParams{
let {scene, name} = req.params;
const {scene, revision} = getSceneParams(req);
let {name} = req.params;
if(!scene) throw new BadRequestError(`Scene parameter not provided`);
if(!name) throw new BadRequestError(`File parameter not provided`);

return {scene, name};
return {scene, revision, name};
}

export function getVfs(req :Request){
Expand Down
15 changes: 15 additions & 0 deletions source/server/vfs/Scenes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,25 @@ import { ItemEntry, Scene, SceneQuery } from "./types.js";

export default abstract class ScenesVfs extends BaseVfs{

/**
* Create a new scene
* Will check if name is a valid scene name. ie:
* - not empty
* - not too long (< 255 bytes)
* - not containing a "$" (reserved for generation selection)
*/
async createScene(name :string):Promise<number>
async createScene(name :string, author_id :number):Promise<number>
async createScene(name :string, permissions:Record<string,AccessType>):Promise<number>
async createScene(name :string, perms ?:Record<string,AccessType>|number) :Promise<number>{

//Check name validity
if(typeof name !== "string") throw new BadRequestError(`Scene name must be a string. Received "${typeof name}"`);
if(name.length == 0) throw new BadRequestError("Scene name cannot be empty");
if(Buffer.byteLength(name) >= 255) throw new BadRequestError("Scene name is too long (max 254 bytes)");
if(name.includes("$")) throw new BadRequestError("Scene name cannot contain '$'");


let permissions :Record<string,AccessType> = (typeof perms === "object")? perms : {};
//Always provide permissions for default user
permissions['0'] ??= (config.public?"read":"none");
Expand Down
8 changes: 5 additions & 3 deletions source/server/vfs/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,13 @@ import { AccessType } from "../auth/UserManager.js";

export type DataStream = ReadStream|AsyncGenerator<Buffer|Uint8Array>|Request;



export interface GetFileParams {
export interface GetSceneParams {
/** Scene name or scene id */
scene :string|number;
revision ?:string;
}

export interface GetFileParams extends GetSceneParams{
name :string;
/**Also return deleted files */
archive ?:boolean;
Expand Down
11 changes: 11 additions & 0 deletions source/server/vfs/vfs.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,17 @@ describe("Vfs", function(){
Uid.make = old;
}
});

it("requires valid names", async function(){
await Promise.all(([
[null, "Scene name must be a string. Received \"object\""],
["", "Scene name cannot be empty"],
["a".repeat(255), "Scene name is too long (max 254 bytes)"],
["$", "Scene name cannot contain '$'"],
] as Array<[string, string]>).map(async ([name, error])=>{
await expect(vfs.createScene(name)).to.be.rejectedWith(error);
}));
})
});

describe("getScenes()", function(){
Expand Down

0 comments on commit 02b84b7

Please sign in to comment.