mirror of
https://github.com/usatiuk/photos.git
synced 2025-10-28 23:37:48 +01:00
more type safety with zod
This commit is contained in:
39
backend/package-lock.json
generated
39
backend/package-lock.json
generated
@@ -15,7 +15,6 @@
|
||||
"class-validator": "^0.14.0",
|
||||
"exifreader": "^4.13.0",
|
||||
"hasha": "^5.2.2",
|
||||
"io-ts": "^2.2.20",
|
||||
"jsonwebtoken": "^9.0.1",
|
||||
"koa": "^2.14.2",
|
||||
"koa-body": "^5.0.0",
|
||||
@@ -2951,12 +2950,6 @@
|
||||
"url": "https://ko-fi.com/tunnckoCore/commissions"
|
||||
}
|
||||
},
|
||||
"node_modules/fp-ts": {
|
||||
"version": "2.16.1",
|
||||
"resolved": "https://registry.npmjs.org/fp-ts/-/fp-ts-2.16.1.tgz",
|
||||
"integrity": "sha512-by7U5W8dkIzcvDofUcO42yl9JbnHTEDBrzu3pt5fKT+Z4Oy85I21K80EYJYdjQGC2qum4Vo55Ag57iiIK4FYuA==",
|
||||
"peer": true
|
||||
},
|
||||
"node_modules/fresh": {
|
||||
"version": "0.5.2",
|
||||
"resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz",
|
||||
@@ -3602,14 +3595,6 @@
|
||||
"node": ">= 0.4"
|
||||
}
|
||||
},
|
||||
"node_modules/io-ts": {
|
||||
"version": "2.2.20",
|
||||
"resolved": "https://registry.npmjs.org/io-ts/-/io-ts-2.2.20.tgz",
|
||||
"integrity": "sha512-Rq2BsYmtwS5vVttie4rqrOCIfHCS9TgpRLFpKQCM1wZBBRY9nWVGmEvm2FnDbSE2un1UE39DvFpTR5UL47YDcA==",
|
||||
"peerDependencies": {
|
||||
"fp-ts": "^2.5.0"
|
||||
}
|
||||
},
|
||||
"node_modules/is-array-buffer": {
|
||||
"version": "3.0.2",
|
||||
"resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.2.tgz",
|
||||
@@ -4514,9 +4499,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/make-dir/node_modules/semver": {
|
||||
"version": "6.3.0",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
|
||||
"integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
|
||||
"version": "6.3.1",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
|
||||
"integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
|
||||
"bin": {
|
||||
"semver": "bin/semver.js"
|
||||
}
|
||||
@@ -9572,12 +9557,6 @@
|
||||
"qs": "^6.11.0"
|
||||
}
|
||||
},
|
||||
"fp-ts": {
|
||||
"version": "2.16.1",
|
||||
"resolved": "https://registry.npmjs.org/fp-ts/-/fp-ts-2.16.1.tgz",
|
||||
"integrity": "sha512-by7U5W8dkIzcvDofUcO42yl9JbnHTEDBrzu3pt5fKT+Z4Oy85I21K80EYJYdjQGC2qum4Vo55Ag57iiIK4FYuA==",
|
||||
"peer": true
|
||||
},
|
||||
"fresh": {
|
||||
"version": "0.5.2",
|
||||
"resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz",
|
||||
@@ -10027,12 +10006,6 @@
|
||||
"side-channel": "^1.0.4"
|
||||
}
|
||||
},
|
||||
"io-ts": {
|
||||
"version": "2.2.20",
|
||||
"resolved": "https://registry.npmjs.org/io-ts/-/io-ts-2.2.20.tgz",
|
||||
"integrity": "sha512-Rq2BsYmtwS5vVttie4rqrOCIfHCS9TgpRLFpKQCM1wZBBRY9nWVGmEvm2FnDbSE2un1UE39DvFpTR5UL47YDcA==",
|
||||
"requires": {}
|
||||
},
|
||||
"is-array-buffer": {
|
||||
"version": "3.0.2",
|
||||
"resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.2.tgz",
|
||||
@@ -10694,9 +10667,9 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"semver": {
|
||||
"version": "6.3.0",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
|
||||
"integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw=="
|
||||
"version": "6.3.1",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
|
||||
"integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
@@ -20,7 +20,6 @@
|
||||
"class-validator": "^0.14.0",
|
||||
"exifreader": "^4.13.0",
|
||||
"hasha": "^5.2.2",
|
||||
"io-ts": "^2.2.20",
|
||||
"jsonwebtoken": "^9.0.1",
|
||||
"koa": "^2.14.2",
|
||||
"koa-body": "^5.0.0",
|
||||
@@ -48,12 +47,12 @@
|
||||
"@types/hasha": "^3.0.1",
|
||||
"@types/jsonwebtoken": "^9.0.2",
|
||||
"@types/koa": "^2.13.7",
|
||||
"@types/koa__cors": "^4.0.0",
|
||||
"@types/koa__router": "^12.0.0",
|
||||
"@types/koa-logger": "^3.1.2",
|
||||
"@types/koa-send": "^4.1.3",
|
||||
"@types/koa-sslify": "^4.0.3",
|
||||
"@types/koa-static": "^4.0.2",
|
||||
"@types/koa__cors": "^4.0.0",
|
||||
"@types/koa__router": "^12.0.0",
|
||||
"@types/mime-types": "^2.1.1",
|
||||
"@types/mocha": "^10.0.1",
|
||||
"@types/mysql": "^2.15.21",
|
||||
@@ -85,4 +84,4 @@
|
||||
"pre-commit": "npm run lint-all && npm run prettier-check"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,8 +15,15 @@ import { config, EnvType } from "~config";
|
||||
import { userRouter } from "~routes/users";
|
||||
import { devRouter } from "~routes/dev";
|
||||
import { photosRouter } from "~routes/photos";
|
||||
import { TUserJWT } from "~shared/types";
|
||||
|
||||
export const app = new Koa();
|
||||
export interface IAppState extends Koa.DefaultState {
|
||||
user?: TUserJWT;
|
||||
}
|
||||
|
||||
export interface IAppContext extends Koa.DefaultContext {}
|
||||
|
||||
export const app = new Koa<IAppState, IAppContext>();
|
||||
|
||||
const tmpPath = path.join(config.dataDir, "tmp");
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@ import * as path from "path";
|
||||
import * as fs from "fs/promises";
|
||||
import * as mime from "mime-types";
|
||||
import * as jwt from "jsonwebtoken";
|
||||
import { IPhotoReqJSON, IPhotoJSON } from "~/shared/types";
|
||||
import { TPhotoReqJSON, TPhotoJSON } from "~/shared/types";
|
||||
|
||||
import {
|
||||
BaseEntity,
|
||||
@@ -212,7 +212,7 @@ export class Photo extends BaseEntity {
|
||||
}
|
||||
}
|
||||
|
||||
public async toJSON(): Promise<IPhotoJSON> {
|
||||
public async toJSON(): Promise<TPhotoJSON> {
|
||||
if (!isNumber(this.user.id)) {
|
||||
throw new Error("User not loaded");
|
||||
}
|
||||
@@ -232,7 +232,7 @@ export class Photo extends BaseEntity {
|
||||
};
|
||||
}
|
||||
|
||||
public async toReqJSON(): Promise<IPhotoReqJSON> {
|
||||
public async toReqJSON(): Promise<TPhotoReqJSON> {
|
||||
const token = await this.getJWTToken();
|
||||
return { ...(await this.toJSON()), accessToken: token };
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@ import * as bcrypt from "bcrypt";
|
||||
import * as jwt from "jsonwebtoken";
|
||||
import * as path from "path";
|
||||
import * as fs from "fs/promises";
|
||||
import { IUserJSON, IUserAuthJSON } from "~/shared/types";
|
||||
import { TUserJSON, TUserAuthJSON } from "~/shared/types";
|
||||
|
||||
import {
|
||||
AfterInsert,
|
||||
@@ -83,12 +83,12 @@ export class User extends BaseEntity {
|
||||
return validateOrReject(this);
|
||||
}
|
||||
|
||||
public toJSON(): IUserJSON {
|
||||
public toJSON(): TUserJSON {
|
||||
const { id, username, isAdmin } = this;
|
||||
return { id, username, isAdmin };
|
||||
}
|
||||
|
||||
public toAuthJSON(): IUserAuthJSON {
|
||||
public toAuthJSON(): TUserAuthJSON {
|
||||
const json = this.toJSON();
|
||||
return { ...json, jwt: this.toJWT() };
|
||||
}
|
||||
|
||||
@@ -1,10 +1,13 @@
|
||||
import * as Router from "@koa/router";
|
||||
import { Photo } from "~entity/Photo";
|
||||
import { User } from "~entity/User";
|
||||
import { IAppContext, IAppState } from "~app";
|
||||
|
||||
export const devRouter = new Router();
|
||||
export const devRouter = new Router<IAppState, IAppContext>();
|
||||
|
||||
devRouter.get("/dev/clean", async (ctx) => {
|
||||
type ContextType = Parameters<Parameters<(typeof devRouter)["post"]>["2"]>["0"];
|
||||
|
||||
devRouter.get("/dev/clean", async (ctx: ContextType) => {
|
||||
await Photo.remove(await Photo.find());
|
||||
await User.remove(await User.find());
|
||||
ctx.body = { success: true };
|
||||
|
||||
@@ -1,19 +1,18 @@
|
||||
import * as Router from "@koa/router";
|
||||
import { Photo } from "~entity/Photo";
|
||||
import {
|
||||
IPhotoReqJSON,
|
||||
IPhotosNewRespBody,
|
||||
IPhotosNewPostBody,
|
||||
IPhotoByIDDeleteRespBody,
|
||||
IPhotosUploadRespBody,
|
||||
IPhotosListRespBody,
|
||||
IPhotosByIDGetRespBody,
|
||||
IPhotosDeleteRespBody,
|
||||
IPhotosDeleteBody,
|
||||
IPhotosGetShowTokenByID,
|
||||
IPhotoShowToken,
|
||||
IAPIResponse,
|
||||
IPhotosListPagination,
|
||||
TPhotoReqJSON,
|
||||
TPhotosNewRespBody,
|
||||
TPhotoByIDDeleteRespBody,
|
||||
TPhotosUploadRespBody,
|
||||
TPhotosListRespBody,
|
||||
TPhotosByIDGetRespBody,
|
||||
TPhotosDeleteRespBody,
|
||||
PhotosListPagination,
|
||||
PhotosNewPostBody,
|
||||
PhotoJSON,
|
||||
TPhotosGetShowTokenByIDRespBody,
|
||||
PhotosDeleteBody,
|
||||
} from "~/shared/types";
|
||||
import send = require("koa-send");
|
||||
import { getHash, getSize } from "~util";
|
||||
@@ -21,24 +20,25 @@ import * as jwt from "jsonwebtoken";
|
||||
import { config } from "~config";
|
||||
import { ValidationError } from "class-validator";
|
||||
import { In } from "typeorm";
|
||||
import { IAppContext, IAppState } from "~app";
|
||||
|
||||
export const photosRouter = new Router();
|
||||
export const photosRouter = new Router<IAppState, IAppContext>();
|
||||
|
||||
photosRouter.post("/photos/new", async (ctx) => {
|
||||
// Typescript requires explicit type annotations for CFA......
|
||||
type ContextType = Parameters<
|
||||
Parameters<(typeof photosRouter)["post"]>["2"]
|
||||
>["0"];
|
||||
|
||||
photosRouter.post("/photos/new", async (ctx: ContextType) => {
|
||||
if (!ctx.state.user) {
|
||||
ctx.throw(401);
|
||||
}
|
||||
|
||||
const { user } = ctx.state;
|
||||
const body = ctx.request.body as IPhotosNewPostBody;
|
||||
const body = PhotosNewPostBody.parse(ctx.request.body);
|
||||
const { hash, size, format } = body;
|
||||
|
||||
if (!(hash && size && format)) {
|
||||
ctx.throw(400);
|
||||
return;
|
||||
}
|
||||
|
||||
const photo = new Photo(user, hash, size, format);
|
||||
const photo = Photo.create({ user, hash, size, format });
|
||||
|
||||
try {
|
||||
await photo.save();
|
||||
@@ -47,13 +47,12 @@ photosRouter.post("/photos/new", async (ctx) => {
|
||||
const photo = await Photo.findOne({ hash, size, user });
|
||||
if (!photo) {
|
||||
ctx.throw(404);
|
||||
return;
|
||||
}
|
||||
|
||||
ctx.body = {
|
||||
error: false,
|
||||
data: await photo.toReqJSON(),
|
||||
} as IPhotosNewRespBody;
|
||||
} as TPhotosNewRespBody;
|
||||
return;
|
||||
}
|
||||
if (
|
||||
@@ -61,7 +60,6 @@ photosRouter.post("/photos/new", async (ctx) => {
|
||||
(Array.isArray(e) && e.some((e) => e instanceof ValidationError))
|
||||
) {
|
||||
ctx.throw(400);
|
||||
return;
|
||||
}
|
||||
console.log(e);
|
||||
ctx.throw(500);
|
||||
@@ -70,10 +68,10 @@ photosRouter.post("/photos/new", async (ctx) => {
|
||||
ctx.body = {
|
||||
error: false,
|
||||
data: await photo.toReqJSON(),
|
||||
} as IPhotosNewRespBody;
|
||||
} as TPhotosNewRespBody;
|
||||
});
|
||||
|
||||
photosRouter.post("/photos/upload/:id", async (ctx) => {
|
||||
photosRouter.post("/photos/upload/:id", async (ctx: ContextType) => {
|
||||
if (!ctx.state.user) {
|
||||
ctx.throw(401);
|
||||
}
|
||||
@@ -84,32 +82,28 @@ photosRouter.post("/photos/upload/:id", async (ctx) => {
|
||||
|
||||
if (!id) {
|
||||
ctx.throw(400);
|
||||
return;
|
||||
}
|
||||
|
||||
const { user } = ctx.state;
|
||||
const photo = await Photo.findOne({ id: parseInt(id), user });
|
||||
if (!photo) {
|
||||
ctx.throw(404);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!ctx.request.files || Object.keys(ctx.request.files).length === 0) {
|
||||
ctx.throw(400, "No file");
|
||||
return;
|
||||
}
|
||||
|
||||
if (photo.uploaded) {
|
||||
ctx.throw(400, "Already uploaded");
|
||||
return;
|
||||
}
|
||||
|
||||
if (ctx.request.files) {
|
||||
const files = ctx.request.files;
|
||||
if (Object.keys(files).length > 1) {
|
||||
ctx.throw(400, "Too many files");
|
||||
return;
|
||||
}
|
||||
|
||||
const file = Object.values(files)[0];
|
||||
if (Array.isArray(file)) {
|
||||
throw "more than one file uploaded";
|
||||
@@ -120,7 +114,6 @@ photosRouter.post("/photos/upload/:id", async (ctx) => {
|
||||
|
||||
if (photoHash !== photo.hash || photoSize !== photo.size) {
|
||||
ctx.throw(400, "Wrong photo");
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
@@ -134,14 +127,14 @@ photosRouter.post("/photos/upload/:id", async (ctx) => {
|
||||
ctx.body = {
|
||||
error: false,
|
||||
data: await photo.toReqJSON(),
|
||||
} as IPhotosUploadRespBody;
|
||||
} as TPhotosUploadRespBody;
|
||||
});
|
||||
|
||||
/**
|
||||
export interface IPhotosByIDPatchBody {
|
||||
export interface TPhotosByIDPatchBody {
|
||||
}
|
||||
export type IPhotosByIDPatchRespBody = IAPIResponse<IPhotoReqJSON>;
|
||||
photosRouter.patch("/photos/byID/:id", async (ctx) => {
|
||||
export type TPhotosByIDPatchRespBody = IAPIResponse<TPhotoReqJSON>;
|
||||
photosRouter.patch("/photos/byID/:id", async (ctx: ContextType) => {
|
||||
if (!ctx.state.user) {
|
||||
ctx.throw(401);
|
||||
return;
|
||||
@@ -180,7 +173,7 @@ photosRouter.patch("/photos/byID/:id", async (ctx) => {
|
||||
});
|
||||
*/
|
||||
|
||||
photosRouter.get("/photos/list", async (ctx) => {
|
||||
photosRouter.get("/photos/list", async (ctx: ContextType) => {
|
||||
if (!ctx.state.user) {
|
||||
ctx.throw(401);
|
||||
}
|
||||
@@ -200,8 +193,8 @@ photosRouter.get("/photos/list", async (ctx) => {
|
||||
skip = parseInt(skip);
|
||||
}
|
||||
|
||||
if (!num || num > IPhotosListPagination) {
|
||||
num = IPhotosListPagination;
|
||||
if (!num || num > PhotosListPagination) {
|
||||
num = PhotosListPagination;
|
||||
}
|
||||
|
||||
const photos = await Photo.find({
|
||||
@@ -211,17 +204,17 @@ photosRouter.get("/photos/list", async (ctx) => {
|
||||
order: { shotAt: "DESC" },
|
||||
});
|
||||
|
||||
const photosList: IPhotoReqJSON[] = await Promise.all(
|
||||
const photosList: TPhotoReqJSON[] = await Promise.all(
|
||||
photos.map(async (photo) => await photo.toReqJSON()),
|
||||
);
|
||||
|
||||
ctx.body = {
|
||||
error: false,
|
||||
data: photosList,
|
||||
} as IPhotosListRespBody;
|
||||
} as TPhotosListRespBody;
|
||||
});
|
||||
|
||||
photosRouter.get("/photos/byID/:id", async (ctx) => {
|
||||
photosRouter.get("/photos/byID/:id", async (ctx: ContextType) => {
|
||||
if (!ctx.state.user) {
|
||||
ctx.throw(401);
|
||||
}
|
||||
@@ -232,7 +225,6 @@ photosRouter.get("/photos/byID/:id", async (ctx) => {
|
||||
|
||||
if (!id) {
|
||||
ctx.throw(400);
|
||||
return;
|
||||
}
|
||||
|
||||
const { user } = ctx.state;
|
||||
@@ -241,16 +233,15 @@ photosRouter.get("/photos/byID/:id", async (ctx) => {
|
||||
|
||||
if (!photo) {
|
||||
ctx.throw(404);
|
||||
return;
|
||||
}
|
||||
|
||||
ctx.body = {
|
||||
error: false,
|
||||
data: await photo.toReqJSON(),
|
||||
} as IPhotosByIDGetRespBody;
|
||||
} as TPhotosByIDGetRespBody;
|
||||
});
|
||||
|
||||
photosRouter.get("/photos/showByID/:id/:token", async (ctx) => {
|
||||
photosRouter.get("/photos/showByID/:id/:token", async (ctx: ContextType) => {
|
||||
const { id, token } = ctx.params as {
|
||||
id: string | undefined;
|
||||
token: string | undefined;
|
||||
@@ -258,7 +249,6 @@ photosRouter.get("/photos/showByID/:id/:token", async (ctx) => {
|
||||
|
||||
if (!(id && token)) {
|
||||
ctx.throw(400);
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
@@ -267,7 +257,7 @@ photosRouter.get("/photos/showByID/:id/:token", async (ctx) => {
|
||||
ctx.throw(401);
|
||||
}
|
||||
|
||||
const photoReqJSON = jwt.decode(token) as IPhotoReqJSON;
|
||||
const photoReqJSON = PhotoJSON.parse(jwt.decode(token));
|
||||
const { user } = photoReqJSON;
|
||||
|
||||
const photo = await Photo.findOne({
|
||||
@@ -277,7 +267,6 @@ photosRouter.get("/photos/showByID/:id/:token", async (ctx) => {
|
||||
|
||||
if (!photo) {
|
||||
ctx.throw(404);
|
||||
return;
|
||||
}
|
||||
|
||||
if (
|
||||
@@ -292,7 +281,7 @@ photosRouter.get("/photos/showByID/:id/:token", async (ctx) => {
|
||||
await send(ctx, await photo.getReadyPath("original"));
|
||||
});
|
||||
|
||||
photosRouter.get("/photos/showByID/:id", async (ctx) => {
|
||||
photosRouter.get("/photos/showByID/:id", async (ctx: ContextType) => {
|
||||
if (!ctx.state.user) {
|
||||
ctx.throw(401);
|
||||
}
|
||||
@@ -303,7 +292,6 @@ photosRouter.get("/photos/showByID/:id", async (ctx) => {
|
||||
|
||||
if (!id) {
|
||||
ctx.throw(400);
|
||||
return;
|
||||
}
|
||||
|
||||
const { user } = ctx.state;
|
||||
@@ -312,7 +300,6 @@ photosRouter.get("/photos/showByID/:id", async (ctx) => {
|
||||
|
||||
if (!photo) {
|
||||
ctx.throw(404);
|
||||
return;
|
||||
}
|
||||
|
||||
if (
|
||||
@@ -327,7 +314,7 @@ photosRouter.get("/photos/showByID/:id", async (ctx) => {
|
||||
await send(ctx, await photo.getReadyPath("original"));
|
||||
});
|
||||
|
||||
photosRouter.get("/photos/getShowByIDToken/:id", async (ctx) => {
|
||||
photosRouter.get("/photos/getShowByIDToken/:id", async (ctx: ContextType) => {
|
||||
if (!ctx.state.user) {
|
||||
ctx.throw(401);
|
||||
}
|
||||
@@ -338,7 +325,6 @@ photosRouter.get("/photos/getShowByIDToken/:id", async (ctx) => {
|
||||
|
||||
if (!id) {
|
||||
ctx.throw(400);
|
||||
return;
|
||||
}
|
||||
|
||||
const { user } = ctx.state;
|
||||
@@ -346,15 +332,14 @@ photosRouter.get("/photos/getShowByIDToken/:id", async (ctx) => {
|
||||
const photo = await Photo.findOne({ id: parseInt(id), user });
|
||||
if (!photo) {
|
||||
ctx.throw(404);
|
||||
return;
|
||||
}
|
||||
|
||||
const token = await photo.getJWTToken();
|
||||
|
||||
ctx.body = { error: false, data: token } as IPhotosGetShowTokenByID;
|
||||
ctx.body = { error: false, data: token } as TPhotosGetShowTokenByIDRespBody;
|
||||
});
|
||||
|
||||
photosRouter.delete("/photos/byID/:id", async (ctx) => {
|
||||
photosRouter.delete("/photos/byID/:id", async (ctx: ContextType) => {
|
||||
if (!ctx.state.user) {
|
||||
ctx.throw(401);
|
||||
}
|
||||
@@ -365,7 +350,6 @@ photosRouter.delete("/photos/byID/:id", async (ctx) => {
|
||||
|
||||
if (!id) {
|
||||
ctx.throw(400);
|
||||
return;
|
||||
}
|
||||
|
||||
const { user } = ctx.state;
|
||||
@@ -374,7 +358,6 @@ photosRouter.delete("/photos/byID/:id", async (ctx) => {
|
||||
|
||||
if (!photo) {
|
||||
ctx.throw(404);
|
||||
return;
|
||||
}
|
||||
|
||||
await photo.remove();
|
||||
@@ -382,22 +365,17 @@ photosRouter.delete("/photos/byID/:id", async (ctx) => {
|
||||
ctx.body = {
|
||||
error: false,
|
||||
data: true,
|
||||
} as IPhotoByIDDeleteRespBody;
|
||||
} as TPhotoByIDDeleteRespBody;
|
||||
});
|
||||
|
||||
photosRouter.post("/photos/delete", async (ctx) => {
|
||||
photosRouter.post("/photos/delete", async (ctx: ContextType) => {
|
||||
if (!ctx.state.user) {
|
||||
ctx.throw(401);
|
||||
}
|
||||
|
||||
const body = ctx.request.body as IPhotosDeleteBody;
|
||||
const body = PhotosDeleteBody.parse(ctx.request.body);
|
||||
const { photos } = body;
|
||||
|
||||
if (!photos || !Array.isArray(photos) || photos.length == 0) {
|
||||
ctx.throw(400);
|
||||
return;
|
||||
}
|
||||
|
||||
const { user } = ctx.state;
|
||||
try {
|
||||
await Photo.delete({
|
||||
@@ -408,11 +386,11 @@ photosRouter.post("/photos/delete", async (ctx) => {
|
||||
ctx.body = {
|
||||
error: false,
|
||||
data: true,
|
||||
} as IPhotosDeleteRespBody;
|
||||
} as TPhotosDeleteRespBody;
|
||||
} catch (e) {
|
||||
ctx.body = {
|
||||
data: null,
|
||||
error: "Internal server error",
|
||||
} as IPhotosDeleteRespBody;
|
||||
} as TPhotosDeleteRespBody;
|
||||
}
|
||||
});
|
||||
|
||||
@@ -2,70 +2,65 @@ import * as Router from "@koa/router";
|
||||
import { getConfigValue, ConfigKey } from "~entity/Config";
|
||||
import { User } from "~entity/User";
|
||||
import {
|
||||
IUserJWT,
|
||||
IUserGetRespBody,
|
||||
IUserEditRespBody,
|
||||
IUserSignupBody,
|
||||
IUserSignupRespBody,
|
||||
IUserLoginRespBody,
|
||||
IUserEditBody,
|
||||
IUserLoginBody,
|
||||
TUserJWT,
|
||||
TUserGetRespBody,
|
||||
TUserEditRespBody,
|
||||
TUserSignupBody,
|
||||
TUserSignupRespBody,
|
||||
TUserLoginRespBody,
|
||||
TUserEditBody,
|
||||
TUserLoginBody,
|
||||
UserLoginBody,
|
||||
UserSignupBody,
|
||||
UserEditBody,
|
||||
} from "~/shared/types";
|
||||
import { IAppContext, IAppState } from "~app";
|
||||
|
||||
export const userRouter = new Router();
|
||||
export const userRouter = new Router<IAppState, IAppContext>();
|
||||
|
||||
userRouter.get("/users/user", async (ctx) => {
|
||||
type ContextType = Parameters<
|
||||
Parameters<(typeof userRouter)["post"]>["2"]
|
||||
>["0"];
|
||||
|
||||
userRouter.get("/users/user", async (ctx: ContextType) => {
|
||||
if (!ctx.state.user) {
|
||||
ctx.throw(401);
|
||||
}
|
||||
|
||||
const jwt = ctx.state.user as IUserJWT;
|
||||
|
||||
const jwt = ctx.state.user;
|
||||
const user = await User.findOne(jwt.id);
|
||||
|
||||
if (!user) {
|
||||
ctx.throw(401);
|
||||
return;
|
||||
}
|
||||
|
||||
ctx.body = { error: false, data: user.toAuthJSON() } as IUserGetRespBody;
|
||||
ctx.body = { error: false, data: user.toAuthJSON() } as TUserGetRespBody;
|
||||
});
|
||||
|
||||
userRouter.post("/users/login", async (ctx) => {
|
||||
userRouter.post("/users/login", async (ctx: ContextType) => {
|
||||
const request = ctx.request;
|
||||
|
||||
if (!request.body) {
|
||||
ctx.throw(400);
|
||||
}
|
||||
const { username, password } = request.body as IUserLoginBody;
|
||||
|
||||
if (!(username && password)) {
|
||||
ctx.throw(400);
|
||||
return;
|
||||
}
|
||||
const { username, password } = UserLoginBody.parse(request.body);
|
||||
|
||||
const user = await User.findOne({ username });
|
||||
if (!user || !(await user.verifyPassword(password))) {
|
||||
ctx.throw(404, "User not found");
|
||||
return;
|
||||
}
|
||||
|
||||
ctx.body = { error: false, data: user.toAuthJSON() } as IUserLoginRespBody;
|
||||
ctx.body = { error: false, data: user.toAuthJSON() } as TUserLoginRespBody;
|
||||
});
|
||||
|
||||
userRouter.post("/users/signup", async (ctx) => {
|
||||
userRouter.post("/users/signup", async (ctx: ContextType) => {
|
||||
const request = ctx.request;
|
||||
|
||||
if (!request.body) {
|
||||
ctx.throw(400);
|
||||
}
|
||||
|
||||
const { username, password, email } = request.body as IUserSignupBody;
|
||||
|
||||
if (!(username && password && email)) {
|
||||
ctx.throw(400);
|
||||
return;
|
||||
}
|
||||
const { username, password, email } = UserSignupBody.parse(request.body);
|
||||
|
||||
const user = new User(username, email);
|
||||
const users = await User.find();
|
||||
@@ -91,33 +86,30 @@ userRouter.post("/users/signup", async (ctx) => {
|
||||
ctx.throw(500);
|
||||
}
|
||||
|
||||
ctx.body = { error: false, data: user.toAuthJSON() } as IUserSignupRespBody;
|
||||
ctx.body = { error: false, data: user.toAuthJSON() } as TUserSignupRespBody;
|
||||
});
|
||||
|
||||
userRouter.post("/users/edit", async (ctx) => {
|
||||
userRouter.post("/users/edit", async (ctx: ContextType) => {
|
||||
if (!ctx.state.user) {
|
||||
ctx.throw(401);
|
||||
}
|
||||
|
||||
const jwt = ctx.state.user as IUserJWT;
|
||||
const jwt = ctx.state.user;
|
||||
const user = await User.findOne(jwt.id);
|
||||
const request = ctx.request;
|
||||
|
||||
if (!user) {
|
||||
ctx.throw(401);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!request.body) {
|
||||
ctx.throw(400);
|
||||
return;
|
||||
}
|
||||
|
||||
const { password } = request.body as IUserEditBody;
|
||||
const { password } = UserEditBody.parse(request.body);
|
||||
|
||||
if (!password) {
|
||||
ctx.throw(400);
|
||||
return;
|
||||
}
|
||||
|
||||
await user.setPassword(password);
|
||||
@@ -129,5 +121,5 @@ userRouter.post("/users/edit", async (ctx) => {
|
||||
ctx.throw(500);
|
||||
}
|
||||
|
||||
ctx.body = { error: false, data: user.toAuthJSON() } as IUserEditRespBody;
|
||||
ctx.body = { error: false, data: user.toAuthJSON() } as TUserEditRespBody;
|
||||
});
|
||||
|
||||
@@ -4,10 +4,11 @@ import * as request from "supertest";
|
||||
import { getConnection } from "typeorm";
|
||||
import { app } from "~app";
|
||||
import { Photo } from "~entity/Photo";
|
||||
import { IPhotoReqJSON ,
|
||||
IPhotosDeleteBody,
|
||||
IPhotosListRespBody,
|
||||
IPhotosNewPostBody,
|
||||
import {
|
||||
TPhotoReqJSON,
|
||||
TPhotosDeleteBody,
|
||||
TPhotosListRespBody,
|
||||
TPhotosNewPostBody,
|
||||
} from "~shared/types";
|
||||
import * as fs from "fs/promises";
|
||||
import { constants as fsConstants } from "fs";
|
||||
@@ -60,7 +61,7 @@ describe("photos", function () {
|
||||
|
||||
expect(response.body.error).to.be.false;
|
||||
|
||||
const photo = response.body.data as IPhotoReqJSON;
|
||||
const photo = response.body.data as TPhotoReqJSON;
|
||||
|
||||
const usedPhoto = await seed.dogPhoto.toReqJSON();
|
||||
|
||||
@@ -85,9 +86,7 @@ describe("photos", function () {
|
||||
Authorization: `Bearer ${seed.user2.toJWT()}`,
|
||||
})
|
||||
.expect(200);
|
||||
expect(parseInt(response.header["content-length"])).to.equal(
|
||||
dogFileSize,
|
||||
);
|
||||
expect(parseInt(response.get("content-length"))).to.equal(dogFileSize);
|
||||
});
|
||||
|
||||
it("should delete a photo after file has been deleted", async function () {
|
||||
@@ -97,12 +96,10 @@ describe("photos", function () {
|
||||
Authorization: `Bearer ${seed.user2.toJWT()}`,
|
||||
})
|
||||
.expect(200);
|
||||
expect(parseInt(response.header["content-length"])).to.equal(
|
||||
dogFileSize,
|
||||
);
|
||||
expect(parseInt(response.get("content-length"))).to.equal(dogFileSize);
|
||||
|
||||
await fs.unlink(await seed.dogPhoto.getReadyPath("original"));
|
||||
const response2 = await request(callback)
|
||||
await request(callback)
|
||||
.get(`/photos/showByID/${seed.dogPhoto.id}`)
|
||||
.set({
|
||||
Authorization: `Bearer ${seed.user2.toJWT()}`,
|
||||
@@ -122,13 +119,13 @@ describe("photos", function () {
|
||||
const dogSmallThumbSize = (
|
||||
await fs.stat(seed.dogPhoto.getThumbPath("512"))
|
||||
).size;
|
||||
expect(parseInt(response.header["content-length"])).to.equal(
|
||||
expect(parseInt(response.get("content-length"))).to.equal(
|
||||
dogSmallThumbSize,
|
||||
);
|
||||
|
||||
await fs.unlink(await seed.dogPhoto.getReadyPath("512"));
|
||||
await fs.unlink(await seed.dogPhoto.getReadyPath("original"));
|
||||
const response2 = await request(callback)
|
||||
await request(callback)
|
||||
.get(`/photos/showByID/${seed.dogPhoto.id}?size=512`)
|
||||
.set({
|
||||
Authorization: `Bearer ${seed.user2.toJWT()}`,
|
||||
@@ -146,7 +143,7 @@ describe("photos", function () {
|
||||
Authorization: `Bearer ${seed.user2.toJWT()}`,
|
||||
})
|
||||
.expect(200);
|
||||
expect(parseInt(response.header["content-length"])).to.be.lessThan(
|
||||
expect(parseInt(response.get("content-length"))).to.be.lessThan(
|
||||
dogFileSize,
|
||||
);
|
||||
});
|
||||
@@ -161,12 +158,12 @@ describe("photos", function () {
|
||||
const dogSmallThumbSize = (
|
||||
await fs.stat(seed.dogPhoto.getThumbPath("512"))
|
||||
).size;
|
||||
expect(parseInt(response.header["content-length"])).to.equal(
|
||||
expect(parseInt(response.get("content-length"))).to.equal(
|
||||
dogSmallThumbSize,
|
||||
);
|
||||
|
||||
await fs.unlink(seed.dogPhoto.getThumbPath("512"));
|
||||
const response2 = await request(callback)
|
||||
await request(callback)
|
||||
.get(`/photos/showByID/${seed.dogPhoto.id}?size=512`)
|
||||
.set({
|
||||
Authorization: `Bearer ${seed.user2.toJWT()}`,
|
||||
@@ -175,7 +172,7 @@ describe("photos", function () {
|
||||
const dogSmallThumbSize2 = (
|
||||
await fs.stat(seed.dogPhoto.getThumbPath("512"))
|
||||
).size;
|
||||
expect(parseInt(response.header["content-length"])).to.equal(
|
||||
expect(parseInt(response.get("content-length"))).to.equal(
|
||||
dogSmallThumbSize2,
|
||||
);
|
||||
});
|
||||
@@ -188,7 +185,7 @@ describe("photos", function () {
|
||||
})
|
||||
.expect(200);
|
||||
|
||||
const listRespBody = listResp.body as IPhotosListRespBody;
|
||||
const listRespBody = listResp.body as TPhotosListRespBody;
|
||||
|
||||
if (listRespBody.error !== false) {
|
||||
expect(listResp.body.error).to.be.false;
|
||||
@@ -201,7 +198,7 @@ describe("photos", function () {
|
||||
const listAnyResp = await request(callback)
|
||||
.get(`/photos/showByID/${photos[0].id}/${photos[0].accessToken}`)
|
||||
.expect(200);
|
||||
expect(parseInt(listAnyResp.header["content-length"])).to.be.oneOf([
|
||||
expect(parseInt(listAnyResp.get("content-length"))).to.be.oneOf([
|
||||
dogFileSize,
|
||||
catFileSize,
|
||||
]);
|
||||
@@ -219,9 +216,7 @@ describe("photos", function () {
|
||||
const response = await request(callback)
|
||||
.get(`/photos/showByID/${seed.dogPhoto.id}/${token}`)
|
||||
.expect(200);
|
||||
expect(parseInt(response.header["content-length"])).to.equal(
|
||||
dogFileSize,
|
||||
);
|
||||
expect(parseInt(response.get("content-length"))).to.equal(dogFileSize);
|
||||
|
||||
const tokenSelfSigned = jwt.sign(
|
||||
await seed.dogPhoto.toReqJSON(),
|
||||
@@ -234,7 +229,7 @@ describe("photos", function () {
|
||||
const responseSS = await request(callback)
|
||||
.get(`/photos/showByID/${seed.dogPhoto.id}/${tokenSelfSigned}`)
|
||||
.expect(200);
|
||||
expect(parseInt(responseSS.header["content-length"])).to.equal(
|
||||
expect(parseInt(responseSS.get("content-length"))).to.equal(
|
||||
dogFileSize,
|
||||
);
|
||||
});
|
||||
@@ -248,7 +243,7 @@ describe("photos", function () {
|
||||
},
|
||||
);
|
||||
|
||||
const response = await request(callback)
|
||||
await request(callback)
|
||||
.get(`/photos/showByID/${seed.dogPhoto.id}/${token}`)
|
||||
.expect(401);
|
||||
});
|
||||
@@ -275,17 +270,17 @@ describe("photos", function () {
|
||||
hash: dogHash,
|
||||
size: dogSize,
|
||||
format: dogFormat,
|
||||
} as IPhotosNewPostBody)
|
||||
} as TPhotosNewPostBody)
|
||||
.expect(200);
|
||||
|
||||
expect(response.body.error).to.be.false;
|
||||
|
||||
const photo = response.body.data as IPhotoReqJSON;
|
||||
const photo = response.body.data as TPhotoReqJSON;
|
||||
|
||||
expect(photo.hash).to.be.equal(dogHash);
|
||||
const dbPhoto = await Photo.findOneOrFail({
|
||||
id: photo.id,
|
||||
user: seed.user1.id as any,
|
||||
user: { id: seed.user1.id },
|
||||
});
|
||||
expect(dbPhoto.hash).to.be.equal(dogHash);
|
||||
|
||||
@@ -302,7 +297,7 @@ describe("photos", function () {
|
||||
|
||||
const dbPhotoUpl = await Photo.findOneOrFail({
|
||||
id: photo.id,
|
||||
user: seed.user1.id as any,
|
||||
user: { id: seed.user1.id },
|
||||
});
|
||||
expect(dbPhotoUpl.hash).to.be.equal(dogHash);
|
||||
expect(await dbPhotoUpl.origFileExists()).to.be.equal(true);
|
||||
@@ -317,9 +312,7 @@ describe("photos", function () {
|
||||
})
|
||||
.expect(200);
|
||||
|
||||
expect(parseInt(showResp.header["content-length"])).to.equal(
|
||||
dogFileSize,
|
||||
);
|
||||
expect(parseInt(showResp.get("content-length"))).to.equal(dogFileSize);
|
||||
});
|
||||
|
||||
it("should create, upload and show a png file", async function () {
|
||||
@@ -333,17 +326,17 @@ describe("photos", function () {
|
||||
hash: pngHash,
|
||||
size: pngSize,
|
||||
format: pngFormat,
|
||||
} as IPhotosNewPostBody)
|
||||
} as TPhotosNewPostBody)
|
||||
.expect(200);
|
||||
|
||||
expect(response.body.error).to.be.false;
|
||||
|
||||
const photo = response.body.data as IPhotoReqJSON;
|
||||
const photo = response.body.data as TPhotoReqJSON;
|
||||
|
||||
expect(photo.hash).to.be.equal(pngHash);
|
||||
const dbPhoto = await Photo.findOneOrFail({
|
||||
id: photo.id,
|
||||
user: seed.user1.id as any,
|
||||
user: { id: seed.user1.id },
|
||||
});
|
||||
expect(dbPhoto.hash).to.be.equal(pngHash);
|
||||
|
||||
@@ -360,7 +353,7 @@ describe("photos", function () {
|
||||
|
||||
const dbPhotoUpl = await Photo.findOneOrFail({
|
||||
id: photo.id,
|
||||
user: seed.user1.id as any,
|
||||
user: { id: seed.user1.id },
|
||||
});
|
||||
expect(dbPhotoUpl.hash).to.be.equal(pngHash);
|
||||
expect(dbPhotoUpl.format).to.be.equal(pngFormat);
|
||||
@@ -377,9 +370,7 @@ describe("photos", function () {
|
||||
})
|
||||
.expect(200);
|
||||
|
||||
expect(parseInt(showResp.header["content-length"])).to.equal(
|
||||
pngFileSize,
|
||||
);
|
||||
expect(parseInt(showResp.get("content-length"))).to.equal(pngFileSize);
|
||||
});
|
||||
|
||||
it("should not create a photo twice", async function () {
|
||||
@@ -393,12 +384,12 @@ describe("photos", function () {
|
||||
hash: dogHash,
|
||||
size: dogSize,
|
||||
format: dogFormat,
|
||||
} as IPhotosNewPostBody)
|
||||
} as TPhotosNewPostBody)
|
||||
.expect(200);
|
||||
|
||||
expect(response.body.error).to.be.false;
|
||||
|
||||
const response2 = await request(callback)
|
||||
await request(callback)
|
||||
.post("/photos/new")
|
||||
.set({
|
||||
Authorization: `Bearer ${seed.user1.toJWT()}`,
|
||||
@@ -408,7 +399,7 @@ describe("photos", function () {
|
||||
hash: dogHash,
|
||||
size: dogSize,
|
||||
format: dogFormat,
|
||||
} as IPhotosNewPostBody)
|
||||
} as TPhotosNewPostBody)
|
||||
.expect(200);
|
||||
|
||||
const dbPhoto = await Photo.find({
|
||||
@@ -430,17 +421,17 @@ describe("photos", function () {
|
||||
hash: dogHash,
|
||||
size: dogSize,
|
||||
format: dogFormat,
|
||||
} as IPhotosNewPostBody)
|
||||
} as TPhotosNewPostBody)
|
||||
.expect(200);
|
||||
|
||||
expect(response.body.error).to.be.false;
|
||||
|
||||
const photo = response.body.data as IPhotoReqJSON;
|
||||
const photo = response.body.data as TPhotoReqJSON;
|
||||
|
||||
expect(photo.hash).to.be.equal(dogHash);
|
||||
const dbPhoto = await Photo.findOneOrFail({
|
||||
id: photo.id,
|
||||
user: seed.user1.id as any,
|
||||
user: { id: seed.user1.id },
|
||||
});
|
||||
expect(dbPhoto.hash).to.be.equal(dogHash);
|
||||
|
||||
@@ -473,9 +464,7 @@ describe("photos", function () {
|
||||
})
|
||||
.expect(200);
|
||||
|
||||
expect(parseInt(showResp.header["content-length"])).to.equal(
|
||||
dogFileSize,
|
||||
);
|
||||
expect(parseInt(showResp.get("content-length"))).to.equal(dogFileSize);
|
||||
});
|
||||
|
||||
it("should not upload a wrong photo", async function () {
|
||||
@@ -489,17 +478,17 @@ describe("photos", function () {
|
||||
hash: dogHash,
|
||||
size: dogSize,
|
||||
format: dogFormat,
|
||||
} as IPhotosNewPostBody)
|
||||
} as TPhotosNewPostBody)
|
||||
.expect(200);
|
||||
|
||||
expect(response.body.error).to.be.false;
|
||||
|
||||
const photo = response.body.data as IPhotoReqJSON;
|
||||
const photo = response.body.data as TPhotoReqJSON;
|
||||
|
||||
expect(photo.hash).to.be.equal(dogHash);
|
||||
const dbPhoto = await Photo.findOneOrFail({
|
||||
id: photo.id,
|
||||
user: seed.user1.id as any,
|
||||
user: { id: seed.user1.id },
|
||||
});
|
||||
expect(dbPhoto.hash).to.be.equal(dogHash);
|
||||
|
||||
@@ -516,7 +505,7 @@ describe("photos", function () {
|
||||
|
||||
expect(await dbPhoto.origFileExists()).to.be.equal(false);
|
||||
|
||||
const showResp = await request(callback)
|
||||
await request(callback)
|
||||
.get(`/photos/showByID/${photo.id}`)
|
||||
.set({
|
||||
Authorization: `Bearer ${seed.user1.toJWT()}`,
|
||||
@@ -535,17 +524,17 @@ describe("photos", function () {
|
||||
hash: dogHash,
|
||||
size: dogSize,
|
||||
format: dogFormat,
|
||||
} as IPhotosNewPostBody)
|
||||
} as TPhotosNewPostBody)
|
||||
.expect(200);
|
||||
|
||||
expect(response.body.error).to.be.false;
|
||||
|
||||
const photo = response.body.data as IPhotoReqJSON;
|
||||
const photo = response.body.data as TPhotoReqJSON;
|
||||
|
||||
expect(photo.hash).to.be.equal(dogHash);
|
||||
const dbPhoto = await Photo.findOneOrFail({
|
||||
id: photo.id,
|
||||
user: seed.user1.id as any,
|
||||
user: { id: seed.user1.id },
|
||||
});
|
||||
expect(dbPhoto.hash).to.be.equal(dogHash);
|
||||
expect(await dbPhoto.origFileExists()).to.be.equal(false);
|
||||
@@ -573,17 +562,17 @@ describe("photos", function () {
|
||||
hash: dogHash,
|
||||
size: dogSize,
|
||||
format: dogFormat,
|
||||
} as IPhotosNewPostBody)
|
||||
} as TPhotosNewPostBody)
|
||||
.expect(200);
|
||||
|
||||
expect(response.body.error).to.be.false;
|
||||
|
||||
const photo = response.body.data as IPhotoReqJSON;
|
||||
const photo = response.body.data as TPhotoReqJSON;
|
||||
|
||||
expect(photo.hash).to.be.equal(dogHash);
|
||||
const dbPhoto = await Photo.findOneOrFail({
|
||||
id: photo.id,
|
||||
user: seed.user1.id as any,
|
||||
user: { id: seed.user1.id },
|
||||
});
|
||||
expect(dbPhoto.hash).to.be.equal(dogHash);
|
||||
expect(await dbPhoto.origFileExists()).to.be.equal(false);
|
||||
@@ -608,7 +597,7 @@ describe("photos", function () {
|
||||
});
|
||||
|
||||
it("should not create a photo with weird properties", async function () {
|
||||
const response = await request(callback)
|
||||
await request(callback)
|
||||
.post("/photos/new")
|
||||
.set({
|
||||
Authorization: `Bearer ${seed.user1.toJWT()}`,
|
||||
@@ -618,7 +607,7 @@ describe("photos", function () {
|
||||
hash: "../test",
|
||||
size: "33333",
|
||||
format: dogFormat,
|
||||
} as IPhotosNewPostBody)
|
||||
} as TPhotosNewPostBody)
|
||||
.expect(400);
|
||||
});
|
||||
|
||||
@@ -635,13 +624,13 @@ describe("photos", function () {
|
||||
|
||||
expect(response.body.error).to.be.false;
|
||||
|
||||
const photo = response.body.data as IPhotoReqJSON;
|
||||
const photo = response.body.data as TPhotoReqJSON;
|
||||
|
||||
expect(photo.name).to.be.equal("Test1");
|
||||
|
||||
const dbPhoto = await Photo.findOne({
|
||||
id: seed.dogPhoto.id,
|
||||
user: seed.user1.id as any,
|
||||
user: {id:seed.user1.id} ,
|
||||
});
|
||||
|
||||
expect(dbPhoto.name).to.be.equal("Test1");
|
||||
@@ -662,7 +651,7 @@ describe("photos", function () {
|
||||
|
||||
expect(response.body.error).to.be.false;
|
||||
|
||||
const photos = response.body.data as IPhotoReqJSON[];
|
||||
const photos = response.body.data as TPhotoReqJSON[];
|
||||
const userPhotos = [
|
||||
await seed.dogPhoto.toReqJSON(),
|
||||
await seed.catPhoto.toReqJSON(),
|
||||
@@ -685,7 +674,7 @@ describe("photos", function () {
|
||||
|
||||
expect(response.body.error).to.be.false;
|
||||
|
||||
const photo = response.body.data as IPhotoReqJSON;
|
||||
const photo = response.body.data as TPhotoReqJSON;
|
||||
|
||||
const usedPhoto = seed.catPhoto.toReqJSON();
|
||||
|
||||
@@ -704,7 +693,7 @@ describe("photos", function () {
|
||||
})
|
||||
.send({
|
||||
photos: [await seed.dogPhoto.toReqJSON()],
|
||||
} as IPhotosDeleteBody)
|
||||
} as TPhotosDeleteBody)
|
||||
.expect(200);
|
||||
|
||||
expect(response.body.error).to.be.false;
|
||||
@@ -736,7 +725,7 @@ describe("photos", function () {
|
||||
await seed.dogPhoto.toReqJSON(),
|
||||
await seed.catPhoto.toReqJSON(),
|
||||
],
|
||||
} as IPhotosDeleteBody)
|
||||
} as TPhotosDeleteBody)
|
||||
.expect(200);
|
||||
|
||||
expect(response.body.error).to.be.false;
|
||||
|
||||
@@ -5,13 +5,13 @@ import { getConnection } from "typeorm";
|
||||
import { app } from "~app";
|
||||
import { User } from "~entity/User";
|
||||
import {
|
||||
IUserEditBody,
|
||||
IUserEditRespBody,
|
||||
IUserGetRespBody,
|
||||
IUserLoginBody,
|
||||
IUserLoginRespBody,
|
||||
IUserSignupBody,
|
||||
IUserSignupRespBody,
|
||||
TUserEditBody,
|
||||
TUserEditRespBody,
|
||||
TUserGetRespBody,
|
||||
TUserLoginBody,
|
||||
TUserLoginRespBody,
|
||||
TUserSignupBody,
|
||||
TUserSignupRespBody,
|
||||
} from "~shared/types";
|
||||
|
||||
import { allowSignups, ISeed, seedDB } from "./util";
|
||||
@@ -43,13 +43,13 @@ describe("users", function () {
|
||||
.expect("Content-Type", /json/)
|
||||
.expect(200);
|
||||
|
||||
const body = response.body as IUserGetRespBody;
|
||||
const body = response.body as TUserGetRespBody;
|
||||
|
||||
if (body.error !== false) {
|
||||
assert(false);
|
||||
return;
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
const { jwt: _, ...user } = body.data;
|
||||
|
||||
expect(user).to.deep.equal(seed.user1.toJSON());
|
||||
@@ -59,17 +59,17 @@ describe("users", function () {
|
||||
const response = await request(callback)
|
||||
.post("/users/login")
|
||||
.set({ "Content-Type": "application/json" })
|
||||
.send({ username: "User1", password: "User1" } as IUserLoginBody)
|
||||
.send({ username: "User1", password: "User1" } as TUserLoginBody)
|
||||
.expect("Content-Type", /json/)
|
||||
.expect(200);
|
||||
|
||||
const body = response.body as IUserLoginRespBody;
|
||||
const body = response.body as TUserLoginRespBody;
|
||||
|
||||
if (body.error !== false) {
|
||||
assert(false);
|
||||
return;
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
const { jwt: _, ...user } = response.body.data;
|
||||
expect(user).to.deep.equal(seed.user1.toJSON());
|
||||
});
|
||||
@@ -78,10 +78,10 @@ describe("users", function () {
|
||||
const response = await request(callback)
|
||||
.post("/users/login")
|
||||
.set({ "Content-Type": "application/json" })
|
||||
.send({ username: "User1", password: "asdf" } as IUserLoginBody)
|
||||
.send({ username: "User1", password: "asdf" } as TUserLoginBody)
|
||||
.expect(404);
|
||||
|
||||
const body = response.body as IUserLoginRespBody;
|
||||
const body = response.body as TUserLoginRespBody;
|
||||
expect(body.error).to.be.equal("User not found");
|
||||
expect(body.data).to.be.false;
|
||||
});
|
||||
@@ -96,17 +96,17 @@ describe("users", function () {
|
||||
username: "NUser1",
|
||||
password: "NUser1",
|
||||
email: "nuser1@users.com",
|
||||
} as IUserSignupBody)
|
||||
} as TUserSignupBody)
|
||||
.expect("Content-Type", /json/)
|
||||
.expect(200);
|
||||
|
||||
const body = response.body as IUserSignupRespBody;
|
||||
const body = response.body as TUserSignupRespBody;
|
||||
|
||||
if (body.error !== false) {
|
||||
assert(false);
|
||||
return;
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
const { jwt: _, ...user } = body.data;
|
||||
const newUser = await User.findOneOrFail({ username: "NUser1" });
|
||||
expect(user).to.deep.equal(newUser.toJSON());
|
||||
@@ -120,11 +120,11 @@ describe("users", function () {
|
||||
username: "NUser1",
|
||||
password: "NUser1",
|
||||
email: "nuser1@users.com",
|
||||
} as IUserSignupBody)
|
||||
} as TUserSignupBody)
|
||||
.expect("Content-Type", /json/)
|
||||
.expect(400);
|
||||
|
||||
const body = response.body as IUserSignupRespBody;
|
||||
const body = response.body as TUserSignupRespBody;
|
||||
|
||||
expect(body.error).to.be.equal("Signups not allowed");
|
||||
expect(body.data).to.be.false;
|
||||
@@ -140,17 +140,17 @@ describe("users", function () {
|
||||
username: "NUser1",
|
||||
password: "NUser1",
|
||||
email: "nuser1@users.com",
|
||||
} as IUserSignupBody)
|
||||
} as TUserSignupBody)
|
||||
.expect("Content-Type", /json/)
|
||||
.expect(200);
|
||||
|
||||
const body = response.body as IUserSignupRespBody;
|
||||
const body = response.body as TUserSignupRespBody;
|
||||
|
||||
if (body.error !== false) {
|
||||
assert(false);
|
||||
return;
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
const { jwt: _, ...user } = body.data;
|
||||
const newUser = await User.findOneOrFail({ username: "NUser1" });
|
||||
expect(user).to.deep.equal(newUser.toJSON());
|
||||
@@ -163,11 +163,11 @@ describe("users", function () {
|
||||
username: "NUser2",
|
||||
password: "NUser2",
|
||||
email: "nuser2@users.com",
|
||||
} as IUserSignupBody)
|
||||
} as TUserSignupBody)
|
||||
.expect("Content-Type", /json/)
|
||||
.expect(400);
|
||||
|
||||
const body2 = response2.body as IUserSignupRespBody;
|
||||
const body2 = response2.body as TUserSignupRespBody;
|
||||
|
||||
expect(body2.error).to.be.equal("Signups not allowed");
|
||||
expect(body2.data).to.be.false;
|
||||
@@ -184,17 +184,17 @@ describe("users", function () {
|
||||
username: "NUser1",
|
||||
password: "NUser1",
|
||||
email: "nuser1@users.com",
|
||||
} as IUserSignupBody)
|
||||
} as TUserSignupBody)
|
||||
.expect("Content-Type", /json/)
|
||||
.expect(200);
|
||||
|
||||
const body = response.body as IUserSignupRespBody;
|
||||
const body = response.body as TUserSignupRespBody;
|
||||
|
||||
if (body.error !== false) {
|
||||
assert(false);
|
||||
return;
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
const { jwt: jwt1, ...user } = body.data;
|
||||
const newUser = await User.findOneOrFail({ username: "NUser1" });
|
||||
expect(user).to.deep.equal(newUser.toJSON());
|
||||
@@ -207,17 +207,17 @@ describe("users", function () {
|
||||
username: "NUser2",
|
||||
password: "NUser2",
|
||||
email: "nuser2@users.com",
|
||||
} as IUserSignupBody)
|
||||
} as TUserSignupBody)
|
||||
.expect("Content-Type", /json/)
|
||||
.expect(200);
|
||||
|
||||
const body2 = response2.body as IUserSignupRespBody;
|
||||
const body2 = response2.body as TUserSignupRespBody;
|
||||
|
||||
if (body2.error !== false) {
|
||||
assert(false);
|
||||
return;
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
const { jwt: jwt2, ...user2 } = body2.data;
|
||||
const newUser2 = await User.findOneOrFail({ username: "NUser2" });
|
||||
expect(user2).to.deep.equal(newUser2.toJSON());
|
||||
@@ -234,10 +234,10 @@ describe("users", function () {
|
||||
username: "User1",
|
||||
password: "NUser1",
|
||||
email: "user1@users.com",
|
||||
} as IUserSignupBody)
|
||||
} as TUserSignupBody)
|
||||
.expect(400);
|
||||
|
||||
const body = response.body as IUserSignupRespBody;
|
||||
const body = response.body as TUserSignupRespBody;
|
||||
|
||||
expect(body.error).to.be.equal("User already exists");
|
||||
expect(body.data).to.be.false;
|
||||
@@ -252,15 +252,14 @@ describe("users", function () {
|
||||
})
|
||||
.send({
|
||||
password: "User1NewPass",
|
||||
} as IUserEditBody)
|
||||
} as TUserEditBody)
|
||||
.expect("Content-Type", /json/)
|
||||
.expect(200);
|
||||
|
||||
const body = response.body as IUserEditRespBody;
|
||||
const body = response.body as TUserEditRespBody;
|
||||
|
||||
if (body.error !== false) {
|
||||
assert(false);
|
||||
return;
|
||||
}
|
||||
|
||||
const loginResponse = await request(callback)
|
||||
@@ -269,27 +268,27 @@ describe("users", function () {
|
||||
.send({
|
||||
username: "User1",
|
||||
password: "User1NewPass",
|
||||
} as IUserLoginBody)
|
||||
} as TUserLoginBody)
|
||||
.expect("Content-Type", /json/)
|
||||
.expect(200);
|
||||
|
||||
const loginBody = loginResponse.body as IUserLoginRespBody;
|
||||
const loginBody = loginResponse.body as TUserLoginRespBody;
|
||||
|
||||
if (loginBody.error !== false) {
|
||||
assert(false);
|
||||
return;
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
const { jwt: _, ...user } = loginBody.data;
|
||||
expect(user).to.deep.equal(seed.user1.toJSON());
|
||||
|
||||
const badLoginResponse = await request(callback)
|
||||
.post("/users/login")
|
||||
.set({ "Content-Type": "application/json" })
|
||||
.send({ username: "User1", password: "User1" } as IUserLoginBody)
|
||||
.send({ username: "User1", password: "User1" } as TUserLoginBody)
|
||||
.expect(404);
|
||||
|
||||
const badLoginBody = badLoginResponse.body as IUserLoginRespBody;
|
||||
const badLoginBody = badLoginResponse.body as TUserLoginRespBody;
|
||||
|
||||
expect(badLoginBody.error).to.be.equal("User not found");
|
||||
expect(badLoginBody.data).to.be.false;
|
||||
|
||||
@@ -24,8 +24,5 @@
|
||||
"include": [
|
||||
"./src/**/*.ts",
|
||||
"./tests/**/*.ts",
|
||||
],
|
||||
"exclude": [
|
||||
"frontend"
|
||||
]
|
||||
}
|
||||
Reference in New Issue
Block a user