mirror of
https://github.com/usatiuk/writer.git
synced 2025-10-29 00:17:48 +01:00
crud documents
This commit is contained in:
@@ -6,6 +6,7 @@ import * as bodyParser from "koa-body";
|
||||
import * as jwt from "koa-jwt";
|
||||
import * as logger from "koa-logger";
|
||||
import { config } from "~config";
|
||||
import { docsRouter } from "~routes/docs";
|
||||
import { userRouter } from "~routes/users";
|
||||
|
||||
export const app = new Koa();
|
||||
@@ -31,6 +32,7 @@ app.use(async (ctx, next) => {
|
||||
});
|
||||
|
||||
app.use(userRouter.routes()).use(userRouter.allowedMethods());
|
||||
app.use(docsRouter.routes()).use(docsRouter.allowedMethods());
|
||||
|
||||
app.on("error", (err, ctx) => {
|
||||
ctx.body = {
|
||||
|
||||
@@ -21,4 +21,11 @@ export class Document extends BaseEntity {
|
||||
|
||||
@Column({ type: "text" })
|
||||
public content: string;
|
||||
|
||||
constructor(user: User, name: string, content: string) {
|
||||
super();
|
||||
this.user = user;
|
||||
this.name = name;
|
||||
this.content = content;
|
||||
}
|
||||
}
|
||||
|
||||
168
src/routes/docs.ts
Normal file
168
src/routes/docs.ts
Normal file
@@ -0,0 +1,168 @@
|
||||
import * as Router from "koa-router";
|
||||
import { Document } from "~entity/Document";
|
||||
|
||||
export const docsRouter = new Router();
|
||||
|
||||
export type IDocumentJSON = Pick<Document, "id" | "name" | "content">;
|
||||
|
||||
docsRouter.post("/docs/new", async ctx => {
|
||||
if (!ctx.state.user) {
|
||||
ctx.throw(401);
|
||||
}
|
||||
|
||||
const { user } = ctx.state;
|
||||
|
||||
const { name, content } = ctx.request.body as {
|
||||
name: string | null;
|
||||
content: string | null;
|
||||
};
|
||||
|
||||
if (!(name && content)) {
|
||||
ctx.throw(400);
|
||||
}
|
||||
|
||||
const document = new Document(user.id, name, content);
|
||||
|
||||
try {
|
||||
await document.save();
|
||||
} catch (e) {
|
||||
ctx.throw(400);
|
||||
}
|
||||
|
||||
ctx.body = {
|
||||
error: false,
|
||||
data: {
|
||||
id: document.id,
|
||||
name: document.name,
|
||||
content: document.content,
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
docsRouter.patch("/docs/byID/:id", async ctx => {
|
||||
if (!ctx.state.user) {
|
||||
ctx.throw(401);
|
||||
}
|
||||
|
||||
const { user } = ctx.state;
|
||||
|
||||
const { id } = ctx.params as {
|
||||
id: number | null;
|
||||
};
|
||||
|
||||
if (!id) {
|
||||
ctx.throw(400);
|
||||
}
|
||||
|
||||
const { name, content } = ctx.request.body as {
|
||||
name: string | null;
|
||||
content: string | null;
|
||||
};
|
||||
|
||||
const document = await Document.findOne({ id, user: user.id });
|
||||
|
||||
if (!document) {
|
||||
ctx.throw(404);
|
||||
}
|
||||
|
||||
if (name) {
|
||||
document.name = name;
|
||||
}
|
||||
if (content) {
|
||||
document.content = content;
|
||||
}
|
||||
|
||||
try {
|
||||
await document.save();
|
||||
} catch (e) {
|
||||
ctx.throw(400);
|
||||
}
|
||||
|
||||
ctx.body = {
|
||||
error: false,
|
||||
data: {
|
||||
id: document.id,
|
||||
name: document.name,
|
||||
content: document.content,
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
docsRouter.get("/docs/list", async ctx => {
|
||||
if (!ctx.state.user) {
|
||||
ctx.throw(401);
|
||||
}
|
||||
|
||||
const { user } = ctx.state;
|
||||
|
||||
const documents = await Document.find({ user: user.id });
|
||||
|
||||
ctx.body = {
|
||||
error: false,
|
||||
data: documents.map(document => ({
|
||||
id: document.id,
|
||||
name: document.name,
|
||||
content: document.content,
|
||||
})),
|
||||
};
|
||||
});
|
||||
|
||||
docsRouter.get("/docs/byID/:id", async ctx => {
|
||||
if (!ctx.state.user) {
|
||||
ctx.throw(401);
|
||||
}
|
||||
|
||||
const { id } = ctx.params as {
|
||||
id: number | null;
|
||||
};
|
||||
|
||||
if (!id) {
|
||||
ctx.throw(400);
|
||||
}
|
||||
|
||||
const { user } = ctx.state;
|
||||
|
||||
const document = await Document.findOne({ id, user: user.id });
|
||||
|
||||
if (!document) {
|
||||
ctx.throw(404);
|
||||
}
|
||||
|
||||
ctx.body = {
|
||||
error: false,
|
||||
data: {
|
||||
id: document.id,
|
||||
name: document.name,
|
||||
content: document.content,
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
docsRouter.delete("/docs/byID/:id", async ctx => {
|
||||
if (!ctx.state.user) {
|
||||
ctx.throw(401);
|
||||
}
|
||||
|
||||
const { id } = ctx.params as {
|
||||
id: number | null;
|
||||
};
|
||||
|
||||
if (!id) {
|
||||
ctx.throw(400);
|
||||
}
|
||||
|
||||
const { user } = ctx.state;
|
||||
|
||||
const document = await Document.findOne({ id, user: user.id });
|
||||
|
||||
if (!document) {
|
||||
ctx.throw(404);
|
||||
}
|
||||
|
||||
await document.remove();
|
||||
|
||||
ctx.body = {
|
||||
error: false,
|
||||
data: true,
|
||||
};
|
||||
});
|
||||
145
tests/integration/docs.test.ts
Normal file
145
tests/integration/docs.test.ts
Normal file
@@ -0,0 +1,145 @@
|
||||
import { expect } from "chai";
|
||||
import { connect } from "config/database";
|
||||
import * as request from "supertest";
|
||||
import { getConnection } from "typeorm";
|
||||
import { app } from "~app";
|
||||
import { Document } from "~entity/Document";
|
||||
import { IDocumentJSON } from "~routes/docs";
|
||||
|
||||
import { ISeed, seedDB } from "./util";
|
||||
|
||||
const callback = app.callback();
|
||||
|
||||
let seed: ISeed;
|
||||
|
||||
describe("users", () => {
|
||||
before(async () => {
|
||||
await connect();
|
||||
});
|
||||
|
||||
after(async () => {
|
||||
await getConnection().close();
|
||||
});
|
||||
|
||||
beforeEach(async () => {
|
||||
seed = await seedDB();
|
||||
});
|
||||
|
||||
it("should create a document", async () => {
|
||||
const response = await request(callback)
|
||||
.post("/docs/new")
|
||||
.set({
|
||||
Authorization: `Bearer ${seed.user1.toJWT()}`,
|
||||
"Content-Type": "application/json",
|
||||
})
|
||||
.send({ name: "Test1", content: "Test1" })
|
||||
.expect(200);
|
||||
|
||||
expect(response.body.error).to.be.false;
|
||||
|
||||
const document = response.body.data as IDocumentJSON;
|
||||
|
||||
expect(document.name).to.be.equal("Test1");
|
||||
|
||||
const dbDocument = await Document.findOneOrFail({
|
||||
id: document.id,
|
||||
user: seed.user1.id as any,
|
||||
});
|
||||
|
||||
expect(dbDocument.name).to.be.equal("Test1");
|
||||
});
|
||||
|
||||
it("should update a document", async () => {
|
||||
const response = await request(callback)
|
||||
.patch(`/docs/byID/${seed.doc1.id}`)
|
||||
.set({
|
||||
Authorization: `Bearer ${seed.user1.toJWT()}`,
|
||||
"Content-Type": "application/json",
|
||||
})
|
||||
.send({ name: "Test1", content: "Test1" })
|
||||
.expect(200);
|
||||
|
||||
expect(response.body.error).to.be.false;
|
||||
|
||||
const document = response.body.data as IDocumentJSON;
|
||||
|
||||
expect(document.name).to.be.equal("Test1");
|
||||
|
||||
const dbDocument = await Document.findOne({
|
||||
id: seed.doc1.id,
|
||||
user: seed.user1.id as any,
|
||||
});
|
||||
|
||||
expect(dbDocument.name).to.be.equal("Test1");
|
||||
});
|
||||
|
||||
it("should list docs", async () => {
|
||||
const response = await request(callback)
|
||||
.get("/docs/list")
|
||||
.set({
|
||||
Authorization: `Bearer ${seed.user1.toJWT()}`,
|
||||
})
|
||||
.expect(200);
|
||||
|
||||
expect(response.body.error).to.be.false;
|
||||
|
||||
const documents = response.body.data as IDocumentJSON[];
|
||||
|
||||
const userDocs = [
|
||||
{
|
||||
id: seed.doc1.id,
|
||||
name: seed.doc1.name,
|
||||
content: seed.doc1.content,
|
||||
},
|
||||
];
|
||||
|
||||
expect(documents).to.deep.equal(userDocs);
|
||||
});
|
||||
|
||||
it("should get a document", async () => {
|
||||
const response = await request(callback)
|
||||
.get(`/docs/byID/${seed.doc1.id}`)
|
||||
.set({
|
||||
Authorization: `Bearer ${seed.user1.toJWT()}`,
|
||||
})
|
||||
.expect(200);
|
||||
|
||||
expect(response.body.error).to.be.false;
|
||||
|
||||
const document = response.body.data as IDocumentJSON;
|
||||
|
||||
const usedDoc = {
|
||||
id: seed.doc1.id,
|
||||
name: seed.doc1.name,
|
||||
content: seed.doc1.content,
|
||||
};
|
||||
|
||||
expect(document).to.deep.equal(usedDoc);
|
||||
});
|
||||
|
||||
it("should not get a document without jwt", async () => {
|
||||
const response = await request(callback)
|
||||
.get(`/docs/byID/${seed.doc1.id}`)
|
||||
.set({
|
||||
Authorization: `Bearer ${seed.user2.toJWT()}`,
|
||||
})
|
||||
.expect(404);
|
||||
|
||||
expect(response.body.error).to.be.equal("Not Found");
|
||||
});
|
||||
|
||||
it("should delete a document", async () => {
|
||||
const response = await request(callback)
|
||||
.delete(`/docs/byID/${seed.doc1.id}`)
|
||||
.set({
|
||||
Authorization: `Bearer ${seed.user1.toJWT()}`,
|
||||
})
|
||||
.expect(200);
|
||||
|
||||
expect(response.body.error).to.be.false;
|
||||
|
||||
const dbDocument = await Document.findOne(seed.doc1.id);
|
||||
|
||||
expect(dbDocument).to.be.undefined;
|
||||
});
|
||||
});
|
||||
@@ -1,11 +1,14 @@
|
||||
import { User } from "entity/User";
|
||||
import { Document } from "~entity/Document";
|
||||
|
||||
export interface ISeed {
|
||||
user1: User;
|
||||
user2: User;
|
||||
doc1: Document;
|
||||
}
|
||||
|
||||
export async function seedDB(): Promise<ISeed> {
|
||||
await Document.remove(await Document.find());
|
||||
await User.remove(await User.find());
|
||||
|
||||
const user1 = new User("User1", "user1@users.com");
|
||||
@@ -16,5 +19,8 @@ export async function seedDB(): Promise<ISeed> {
|
||||
await user2.setPassword("User2");
|
||||
await user2.save();
|
||||
|
||||
return { user1, user2 };
|
||||
const doc1 = new Document(user1, "Doc1", "Doc1");
|
||||
await doc1.save();
|
||||
|
||||
return { user1, user2, doc1 };
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user