Skip to content

Commit

Permalink
add support for zip exported from /api/v1/scenes/:id
Browse files Browse the repository at this point in the history
  • Loading branch information
sdumetz committed May 13, 2024
1 parent 5def1e9 commit 5c5109d
Show file tree
Hide file tree
Showing 2 changed files with 67 additions and 9 deletions.
50 changes: 49 additions & 1 deletion source/server/routes/api/v1/scenes/post.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,21 +37,31 @@ describe("POST /api/v1/scenes", function(){
.expect(401);
});

it("can import an exported scene", async function(){
it("can import a zip of exported scenes", async function(){
//Where scenes are exported from the `GET /api/v1/scenes` endpoint
const user = await userManager.addUser("alice", "12345678", true);
await vfs.createScene("foo", user.uid);
await vfs.writeDoc(`{"id":1}`, "foo", user.uid);
await vfs.writeFile(dataStream(), {scene:"foo", name:"articles/hello.html", mime: "text/html", user_id:user.uid});

await vfs.createScene("bar", user.uid);
await vfs.writeDoc(`{"id":2}`, "bar", user.uid);
await vfs.writeFile(dataStream(), {scene:"bar", name:"articles/hello.html", mime: "text/html", user_id:user.uid});

let zip = await request(this.server).get("/api/v1/scenes")
.auth("alice", "12345678")
.set("Accept", "application/zip")
.parse(binaryParser)
.expect(200)
.expect("Content-Type", "application/zip");

expect(Buffer.isBuffer(zip.body), `Expected a buffer. got : ${zip.body}`).to.be.true;

//Change the data
await vfs.removeScene("foo");
await expect(vfs.getFileProps({scene:"foo", name:"articles/hello.html"})).to.be.rejectedWith(NotFoundError);
await vfs.removeScene("bar");
await expect(vfs.getScene("bar")).to.be.rejectedWith(NotFoundError);

let res = await request(this.server).post("/api/v1/scenes")
.auth("alice", "12345678")
Expand All @@ -60,6 +70,44 @@ describe("POST /api/v1/scenes", function(){
.expect(200);

expect(await vfs.getScene("foo")).to.be.ok;
expect(await vfs.getScene("bar")).to.be.ok;
let {id}= await vfs.getScene("foo");
expect(await vfs.getFileProps({scene: "foo", name:"articles/hello.html"})).to.have.property("hash", "IHQcUEH8CVmcu6Jc_zSB5HCc0K9HPvP0XGSk3S6f0rQ");
expect(await vfs.getDoc(id)).to.have.property("data", `{"id":1}`);
});

it("can import a scene zip", async function(){
//Where scene is exported from the `GET /api/v1/scenes/{id}` endpoint
const user = await userManager.addUser("alice", "12345678", true);
await vfs.createScene("foo", user.uid);
await vfs.writeDoc(`{"id":1}`, "foo", user.uid);
await vfs.writeFile(dataStream(), {scene:"foo", name:"articles/hello.html", mime: "text/html", user_id:user.uid});
let zip = await request(this.server).get("/api/v1/scenes/foo")
.auth("alice", "12345678")
.set("Accept", "application/zip")
.parse(binaryParser)
.expect(200)
.expect("Content-Type", "application/zip");
expect(Buffer.isBuffer(zip.body), `Expected a buffer. got : ${zip.body}`).to.be.true;
//Change the data
await vfs.removeScene("foo");
await expect(vfs.getFileProps({scene:"foo", name:"articles/hello.html"})).to.be.rejectedWith(NotFoundError);

let res = await request(this.server).post("/api/v1/scenes")
.auth("alice", "12345678")
.set("Content-Type", "application/zip")
.send(zip.body)
.expect(200);

expect(res.body).to.be.an("object");
expect(res.body.fail).to.deep.equal([]);
expect(res.body.ok).to.deep.equal([
'foo',
'foo/articles/hello.html',
'foo/scene.svx.json'
]);

await expect(vfs.getScene("foo")).to.be.fulfilled;
let {id}= await vfs.getScene("foo");
expect(await vfs.getFileProps({scene: "foo", name:"articles/hello.html"})).to.have.property("hash", "IHQcUEH8CVmcu6Jc_zSB5HCc0K9HPvP0XGSk3S6f0rQ");
expect(await vfs.getDoc(id)).to.have.property("data", `{"id":1}`);
Expand Down
26 changes: 18 additions & 8 deletions source/server/routes/api/v1/scenes/post.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,9 +34,12 @@ export default async function postScenes(req :Request, res :Response){
await handle.close();
}


/** @fixme make atomic */
for (let record of await unzip(tmpfile)){
let {groups:{scene, name}={} as any} = /^scenes\/(?<scene>[^/]+)(?:\/(?<name>.+))?\/?$/.exec(record.filename) ?? {};
let m = /^(?<contained>scenes\/)?(?<scene>[^/]+)(?:\/(?<name>.+))?\/?$/.exec(record.filename);
const scene :string|undefined = m?.groups?.scene;
const name :string|undefined = m?.groups?.name;

if(!scene){
results.fail.push(`${record.filename}: not matching pattern`);
continue;
Expand All @@ -45,15 +48,22 @@ export default async function postScenes(req :Request, res :Response){
if(!name){
//Create the scene
try{
let s = await vfs.createScene(scene, requester.uid);
await vfs.createScene(scene, requester.uid);
}catch(e){
if((e as HTTPError).code != 409) throw e;
//Scene already exist, it's OK.
//409 == Scene already exist, it's OK.
}
results.ok.push(scene);
}else if(record.isDirectory){
/** @fixme handle folders creation */
continue;
}

if(record.isDirectory){
try{
await vfs.createFolder({scene, name: name.endsWith("/")? name.slice(0, -1): name, user_id: requester.uid});
}catch(e){
if((e as HTTPError).code != 409) throw e;
//409 == Folder already exist, it's OK.
}
}else if(name.endsWith(".svx.json")){
let data = Buffer.alloc(record.end-record.start);
let handle = await fs.open(tmpfile, "r");
Expand All @@ -63,13 +73,13 @@ export default async function postScenes(req :Request, res :Response){
await handle.close();
}
await vfs.writeDoc(data.toString("utf8"), scene, requester.uid);
results.ok.push(`${scene}/${name}`);
}else{
//Add the file
let rs = createReadStream(tmpfile, {start: record.start, end: record.end});
let f = await vfs.writeFile(rs, {user_id: requester.uid, scene, name, mime: getMimeType(name)});
results.ok.push(`${scene}/${name}`);
}

results.ok.push(`${scene}/${name}`);
}
}finally{
await fs.rm(tmpfile, {force: true});
Expand Down

0 comments on commit 5c5109d

Please sign in to comment.