Compare commits

...

3 Commits

27 changed files with 678 additions and 485 deletions

36
api/biome.json Normal file
View File

@ -0,0 +1,36 @@
{
"$schema": "https://biomejs.dev/schemas/1.7.3/schema.json",
"files": {
"ignore": [".expo/", ".vscode/", "node_modules/", "dist/", "*.json"]
},
"organizeImports": {
"enabled": true
},
"linter": {
"enabled": false,
"rules": {
"recommended": true
}
},
"formatter": {
"enabled": true,
"formatWithErrors": false,
"ignore": [],
"attributePosition": "auto",
"indentStyle": "tab",
"indentWidth": 2,
"lineEnding": "lf",
"lineWidth": 120
},
"javascript": {
"formatter": {
"arrowParentheses": "always",
"bracketSameLine": true,
"bracketSpacing": true,
"jsxQuoteStyle": "double",
"quoteProperties": "asNeeded",
"semicolons": "always",
"trailingComma": "all"
}
}
}

View File

@ -59,6 +59,7 @@
"eslint": "^8.3.0", "eslint": "^8.3.0",
"http": "^0.0.1-security", "http": "^0.0.1-security",
"jest": "^29.7.0", "jest": "^29.7.0",
"jest-html-reporter": "^3.10.2",
"mocha": "^9.1.3", "mocha": "^9.1.3",
"mongodb-memory-server": "^9.2.0", "mongodb-memory-server": "^9.2.0",
"npm-run-all": "^4.1.5", "npm-run-all": "^4.1.5",
@ -76,6 +77,12 @@
"testEnvironment": "node", "testEnvironment": "node",
"setupFilesAfterEnv": [ "setupFilesAfterEnv": [
"./tests/_setupFile.ts" "./tests/_setupFile.ts"
],
"reporters": [
"default",
["./node_modules/jest-html-reporter", {
"pageTitle": "Test Report"
}]
] ]
} }
} }

View File

@ -1,29 +1,29 @@
import express from "express"; import express from "express";
import morgan from "morgan"; import morgan from "morgan";
import path from 'path' import path from "path";
import cors from 'cors' import cors from "cors";
import cookieParser from 'cookie-parser' import cookieParser from "cookie-parser";
import { router as routes } from "./routes"; import { router as routes } from "./routes";
//import { router as middlewares } from './middlewares' //import { router as middlewares } from './middlewares'
import env from './config/environment' import env from "./config/environment";
export let corsWhitelist: Array<string> export let corsWhitelist: Array<string>;
if (env.CORS_WHITELIST != 'undefined') { if (env.CORS_WHITELIST != "undefined") {
corsWhitelist = [...['http://localhost:8080', 'http://localhost:6040'], ...env.CORS_WHITELIST.split(';')] corsWhitelist = [...["http://localhost:8080", "http://localhost:6040"], ...env.CORS_WHITELIST.split(";")];
} else { } else {
corsWhitelist = ['http://localhost:8080', 'http://localhost:6040'] corsWhitelist = ["http://localhost:8080", "http://localhost:6040"];
} }
const corsOptions = { const corsOptions = {
origin: function (origin: any, callback: any) { origin: function (origin: any, callback: any) {
if (!origin || corsWhitelist.indexOf(origin) !== -1) { if (!origin || corsWhitelist.indexOf(origin) !== -1) {
callback(null, true) callback(null, true);
} else { } else {
callback(new Error('Not allowed by CORS')) callback(new Error("Not allowed by CORS"));
} }
}, },
optionsSuccessStatus: 200, optionsSuccessStatus: 200,
credentials: true credentials: true,
} };
export const app = express(); export const app = express();
@ -31,12 +31,12 @@ export const app = express();
//app.use(middlewares) //app.use(middlewares)
//app.set('view engine', 'ejs') //app.set('view engine', 'ejs')
//app.set('views', path.join(__dirname, 'views')) //app.set('views', path.join(__dirname, 'views'))
app.use(cors(corsOptions)) app.use(cors(corsOptions));
app.use(morgan("dev")); app.use(morgan("dev"));
app.use(express.urlencoded({ extended: true })); app.use(express.urlencoded({ extended: true }));
app.use(express.json()); app.use(express.json());
app.use(express.static(path.join(__dirname, 'public'))) app.use(express.static(path.join(__dirname, "public")));
app.use(cookieParser()) app.use(cookieParser());
// Routes // Routes
app.use(routes); app.use(routes);

View File

@ -1,13 +1,13 @@
import { Request, Response } from 'express'; import { Request, Response } from "express";
import bcrypt from 'bcrypt'; import bcrypt from "bcrypt";
import jwt from 'jsonwebtoken'; import jwt from "jsonwebtoken";
import env from '../config/environment'; import env from "../config/environment";
import Docs from '../services/docsService'; import Docs from "../services/docsService";
import User from '../models/User'; import User from "../models/User";
import {Log} from 'nork' import { Log } from "nork";
import { IUser, signupExam, ISignin, signinExam } from '../validators/authValidator'; import { IUser, signupExam, ISignin, signinExam } from "../validators/authValidator";
new Docs('user', 'signup', '/api/v1/auth/signup', 'POST', 'user signup api', undefined, signupExam, 'status object'); new Docs("user", "signup", "/api/v1/auth/signup", "POST", "user signup api", undefined, signupExam, "status object");
export async function signup_post(req: Request, res: Response) { export async function signup_post(req: Request, res: Response) {
try { try {
const payload: IUser = req.body; const payload: IUser = req.body;
@ -16,27 +16,27 @@ export async function signup_post(req: Request, res: Response) {
const user = new User(payload); const user = new User(payload);
await user.save(); await user.save();
res.status(201).json(Log.info(201, 'user was successfully signed up')); res.status(201).json(Log.info(201, "user was successfully signed up"));
} catch (err: any) { } catch (err: any) {
if (err.code == 11000) { if (err.code == 11000) {
res.status(400).json(Log.error(400, 'this user already exists')); res.status(400).json(Log.error(400, "this user already exists"));
return; return;
} }
Log.error(500, err); Log.error(500, err);
res.status(500).json(Log.error(500, 'something went wrong')); res.status(500).json(Log.error(500, "something went wrong"));
} }
} }
new Docs('user', 'signin', '/api/v1/auth/signin', 'POST', 'user signin api', undefined, signinExam, 'status object'); new Docs("user", "signin", "/api/v1/auth/signin", "POST", "user signin api", undefined, signinExam, "status object");
export async function signin_post(req: Request, res: Response) { export async function signin_post(req: Request, res: Response) {
try { try {
const payload: ISignin = req.body; const payload: ISignin = req.body;
const user = await User.findOne({ email: payload.email }); const user = await User.findOne({ email: payload.email });
if (!user) { if (!user) {
res.cookie('jwt', '', { httpOnly: true, maxAge: 0 }); res.cookie("jwt", "", { httpOnly: true, maxAge: 0 });
res.cookie('auth', false, { httpOnly: false, maxAge: 0 }); res.cookie("auth", false, { httpOnly: false, maxAge: 0 });
res.status(401).json(Log.error(401, 'email or password is wrong')); res.status(401).json(Log.error(401, "email or password is wrong"));
return; return;
} }
@ -44,38 +44,47 @@ export async function signin_post(req: Request, res: Response) {
const maxAge = 3 * 24 * 60 * 60; // 3 days in seconds const maxAge = 3 * 24 * 60 * 60; // 3 days in seconds
const createToken = (id: any) => { const createToken = (id: any) => {
return jwt.sign({ id }, env.JWT_SECRET, { return jwt.sign({ id }, env.JWT_SECRET, {
expiresIn: maxAge expiresIn: maxAge,
}); });
}; };
const token = createToken(user._id); const token = createToken(user._id);
res.cookie('jwt', token, { httpOnly: true, maxAge: maxAge * 1000 }); res.cookie("jwt", token, { httpOnly: true, maxAge: maxAge * 1000 });
res.cookie('auth', true, { httpOnly: false, maxAge: maxAge * 1000 }); res.cookie("auth", true, { httpOnly: false, maxAge: maxAge * 1000 });
res.json(Log.info(200, 'user is logged in', {jwt: token})); res.json(Log.info(200, "user is logged in", { jwt: token }));
return; return;
} }
res.cookie('jwt', '', { httpOnly: true, maxAge: 0 }); res.cookie("jwt", "", { httpOnly: true, maxAge: 0 });
res.cookie('auth', false, { httpOnly: false, maxAge: 0 }); res.cookie("auth", false, { httpOnly: false, maxAge: 0 });
res.status(401).json(Log.error(401, 'email or password is wrong')); res.status(401).json(Log.error(401, "email or password is wrong"));
} catch (err: any) { } catch (err: any) {
Log.error(500, err); Log.error(500, err);
res.status(500).json(Log.error(500, 'something went wrong')); res.status(500).json(Log.error(500, "something went wrong"));
} }
} }
new Docs('user', 'logout', '/api/v1/auth/logout', 'POST', 'user logout api', undefined, {}, 'status object'); new Docs("user", "logout", "/api/v1/auth/logout", "POST", "user logout api", undefined, {}, "status object");
export function logout_post(req: Request, res: Response) { export function logout_post(req: Request, res: Response) {
res.cookie('jwt', '', { httpOnly: true, maxAge: 0 }); res.cookie("jwt", "", { httpOnly: true, maxAge: 0 });
res.cookie('auth', false, { httpOnly: false, maxAge: 0 }); res.cookie("auth", false, { httpOnly: false, maxAge: 0 });
res.json(Log.info(200, 'user was logged out')); res.json(Log.info(200, "user was logged out"));
} }
new Docs('user', 'status', '/api/v1/auth/status', 'GET', 'user login status api', undefined, undefined, 'status code | user object'); new Docs(
"user",
"status",
"/api/v1/auth/status",
"GET",
"user login status api",
undefined,
undefined,
"status code | user object",
);
export function status_get(req: Request, res: Response) { export function status_get(req: Request, res: Response) {
let userObject = res.locals.user; let userObject = res.locals.user;
userObject.password = undefined; userObject.password = undefined;
userObject.__v = undefined; userObject.__v = undefined;
res.status(200).json(Log.info(200, 'user is logged in', userObject)); res.status(200).json(Log.info(200, "user is logged in", userObject));
} }

View File

@ -1,13 +1,22 @@
import { Request, Response } from 'express'; import { Request, Response } from "express";
import Beer from '../models/Beer'; import Beer from "../models/Beer";
import { isValidObjectId, Types } from 'mongoose'; import { isValidObjectId, Types } from "mongoose";
import fs from 'fs'; import fs from "fs";
import path from 'path'; import path from "path";
import {Log} from 'nork' import { Log } from "nork";
import Docs from '../services/docsService'; import Docs from "../services/docsService";
import { addExam, delExam, editExam, IBeer } from '../validators/beerValidator'; import { addExam, delExam, editExam, IBeer } from "../validators/beerValidator";
new Docs('beer', 'add', '/api/v1/beer/add', 'POST', 'beer add api', undefined, { ...addExam, photos: 'optional field | max 4 images | formData' }, 'status object | beer object'); new Docs(
"beer",
"add",
"/api/v1/beer/add",
"POST",
"beer add api",
undefined,
{ ...addExam, photos: "optional field | max 4 images | formData" },
"status object | beer object",
);
export async function add_post(req: Request, res: Response) { export async function add_post(req: Request, res: Response) {
try { try {
if (req.files) { if (req.files) {
@ -19,28 +28,37 @@ export async function add_post(req: Request, res: Response) {
} }
const beer = new Beer(req.body); const beer = new Beer(req.body);
await beer.save(); await beer.save();
res.status(201).json(Log.info(201, 'beer was created', beer)); res.status(201).json(Log.info(201, "beer was created", beer));
} catch (err: any) { } catch (err: any) {
Log.error(500, 'error in add_post', err); Log.error(500, "error in add_post", err);
res.status(500).json(Log.error(500, 'something went wrong')); res.status(500).json(Log.error(500, "something went wrong"));
} }
} }
new Docs('beer', 'get', '/api/v1/beer/get', 'GET', 'beer get api', undefined, undefined, 'status object | array of beer objects'); new Docs(
"beer",
"get",
"/api/v1/beer/get",
"GET",
"beer get api",
undefined,
undefined,
"status object | array of beer objects",
);
export async function get_get(req: Request, res: Response) { export async function get_get(req: Request, res: Response) {
try { try {
const beer = await Beer.find({}, '-__v'); const beer = await Beer.find({}, "-__v");
res.status(200).json(Log.info(200, 'beers fetched', beer)); res.status(200).json(Log.info(200, "beers fetched", beer));
} catch (err: any) { } catch (err: any) {
Log.error(500, 'error in get_get', err); Log.error(500, "error in get_get", err);
res.status(500).json(Log.error(500, 'something went wrong')); res.status(500).json(Log.error(500, "something went wrong"));
} }
} }
new Docs('beer', 'del', '/api/v1/beer/del', 'POST', 'beer del api', undefined, delExam, 'status object'); new Docs("beer", "del", "/api/v1/beer/del", "POST", "beer del api", undefined, delExam, "status object");
export async function del_post(req: Request, res: Response) { export async function del_post(req: Request, res: Response) {
try { try {
if (!isValidObjectId(req.body._id)) throw Log.error(400, 'this is not valid _id'); if (!isValidObjectId(req.body._id)) throw Log.error(400, "this is not valid _id");
const beer = await Beer.deleteOne(new Types.ObjectId(req.body._id)); const beer = await Beer.deleteOne(new Types.ObjectId(req.body._id));
@ -54,30 +72,39 @@ export async function del_post(req: Request, res: Response) {
res.status(err.code).json(err); res.status(err.code).json(err);
return; return;
} }
Log.error(500, 'error in del_post', err); Log.error(500, "error in del_post", err);
res.status(500).json(Log.error(500, 'something went wrong')); res.status(500).json(Log.error(500, "something went wrong"));
} }
} }
new Docs('beer', 'edit', '/api/v1/beer/edit', 'POST', 'beer edit api', undefined, { ...editExam, photos: 'optional field | max 4 images | formData' }, 'status object | beer data'); new Docs(
"beer",
"edit",
"/api/v1/beer/edit",
"POST",
"beer edit api",
undefined,
{ ...editExam, photos: "optional field | max 4 images | formData" },
"status object | beer data",
);
export async function edit_post(req: Request, res: Response) { export async function edit_post(req: Request, res: Response) {
try { try {
if (!isValidObjectId(req.body._id)) throw Log.error(400, 'this is not valid _id'); if (!isValidObjectId(req.body._id)) throw Log.error(400, "this is not valid _id");
if (req.files) { if (req.files) {
if (!req.body.imgs) { if (!req.body.imgs) {
req.body.imgs = []; req.body.imgs = [];
} }
if (typeof req.body.imgs == 'string') { if (typeof req.body.imgs == "string") {
req.body.imgs = [req.body.imgs]; req.body.imgs = [req.body.imgs];
} }
if (req.body.imgs.length + req.files.length > 4) { if (req.body.imgs.length + req.files.length > 4) {
req.body.imgs.forEach((el: string[]) => { req.body.imgs.forEach((el: string[]) => {
fs.rmSync(path.join(__dirname, '../../uploads/' + el)); fs.rmSync(path.join(__dirname, "../../uploads/" + el));
}); });
throw Log.error(400, 'exceeds the 4 image limit'); throw Log.error(400, "exceeds the 4 image limit");
} }
const files: any = req.files; const files: any = req.files;
@ -90,11 +117,11 @@ export async function edit_post(req: Request, res: Response) {
const beer = await Beer.findOneAndUpdate(new Types.ObjectId(req.body._id), payload, { new: true }); const beer = await Beer.findOneAndUpdate(new Types.ObjectId(req.body._id), payload, { new: true });
res.json(Log.info(200, `beer ${req.body._id} edited`, beer)); res.json(Log.info(200, `beer ${req.body._id} edited`, beer));
} catch (err: any) { } catch (err: any) {
if (err.code && typeof err.code == 'number') { if (err.code && typeof err.code == "number") {
res.status(err.code).json(err); res.status(err.code).json(err);
return; return;
} }
Log.error(500, 'error in del_post', err); Log.error(500, "error in del_post", err);
res.status(500).json(Log.error(500, 'something went wrong')); res.status(500).json(Log.error(500, "something went wrong"));
} }
} }

View File

@ -1,14 +1,14 @@
import { Request, Response } from 'express'; import { Request, Response } from "express";
import path from 'path'; import path from "path";
import fs from 'fs'; import fs from "fs";
import {Log} from 'nork' import { Log } from "nork";
import { Docs } from '../services/docsService'; import { Docs } from "../services/docsService";
new Docs('docs', 'get_all', '/api/v1', 'GET', 'Get docs json', undefined, undefined, 'docs json'); new Docs("docs", "get_all", "/api/v1", "GET", "Get docs json", undefined, undefined, "docs json");
export function docs_get(req: Request, res: Response) { export function docs_get(req: Request, res: Response) {
try { try {
res.json(JSON.parse(fs.readFileSync(path.join(__dirname, '../public/api.json')).toString())); res.json(JSON.parse(fs.readFileSync(path.join(__dirname, "../public/api.json")).toString()));
} catch (err: any) { } catch (err: any) {
res.status(500).json(Log.error(500, 'api.json docs file does not exists under public folder')); res.status(500).json(Log.error(500, "api.json docs file does not exists under public folder"));
} }
} }

View File

@ -1,40 +1,58 @@
import { Request, Response } from 'express'; import { Request, Response } from "express";
import Review from "../models/Review" import Review from "../models/Review";
import { isValidObjectId, Types } from 'mongoose'; import { isValidObjectId, Types } from "mongoose";
import {Log} from 'nork' import { Log } from "nork";
import Docs from '../services/docsService'; import Docs from "../services/docsService";
import { addExam, delExam, IReview } from '../validators/reviewValidator'; import { addExam, delExam, IReview } from "../validators/reviewValidator";
new Docs('review', 'add', '/api/v1/review/add', 'POST', 'review add api', undefined, addExam, 'status object | review object'); new Docs(
"review",
"add",
"/api/v1/review/add",
"POST",
"review add api",
undefined,
addExam,
"status object | review object",
);
export async function add_post(req: Request, res: Response) { export async function add_post(req: Request, res: Response) {
try { try {
const data: IReview = req.body; const data: IReview = req.body;
const review = new Review(data) const review = new Review(data);
await review.save() await review.save();
res.status(201).json(Log.info(201, 'review was added', review)) res.status(201).json(Log.info(201, "review was added", review));
} catch (err) { } catch (err) {
Log.error(500, 'error while adding review', err) Log.error(500, "error while adding review", err);
res.status(500).json(Log.error(500, 'something went wrong')) res.status(500).json(Log.error(500, "something went wrong"));
} }
} }
new Docs('review', 'get', '/api/v1/review/get', 'GET', 'review get api', undefined, undefined, 'status object | array of review objects'); new Docs(
"review",
"get",
"/api/v1/review/get",
"GET",
"review get api",
undefined,
undefined,
"status object | array of review objects",
);
export async function get_get(req: Request, res: Response) { export async function get_get(req: Request, res: Response) {
try { try {
const review = await Review.find({}, '-__v') const review = await Review.find({}, "-__v");
res.status(200).json(Log.info(200, 'reviews fetched', review)) res.status(200).json(Log.info(200, "reviews fetched", review));
} catch (err) { } catch (err) {
Log.error(500, 'error while geting reviews', err) Log.error(500, "error while geting reviews", err);
res.status(500).json(Log.error(500, 'something went wrong')) res.status(500).json(Log.error(500, "something went wrong"));
} }
} }
new Docs('review', 'del', '/api/v1/review/del', 'POST', 'review del api', undefined, delExam, 'status object'); new Docs("review", "del", "/api/v1/review/del", "POST", "review del api", undefined, delExam, "status object");
export async function del_post(req: Request, res: Response) { export async function del_post(req: Request, res: Response) {
try { try {
if (!isValidObjectId(req.body._id)) throw Log.error(400, 'this is not valid _id'); if (!isValidObjectId(req.body._id)) throw Log.error(400, "this is not valid _id");
const review = await Review.deleteOne(new Types.ObjectId(req.body._id)) const review = await Review.deleteOne(new Types.ObjectId(req.body._id));
if (review.deletedCount > 0) { if (review.deletedCount > 0) {
res.status(200).json(Log.info(200, `review ${req.body._id} deleted`)); res.status(200).json(Log.info(200, `review ${req.body._id} deleted`));
@ -46,7 +64,7 @@ export async function del_post(req: Request, res: Response) {
res.status(err.code).json(err); res.status(err.code).json(err);
return; return;
} }
Log.error(500, 'error in del_post', err); Log.error(500, "error in del_post", err);
res.status(500).json(Log.error(500, 'something went wrong')); res.status(500).json(Log.error(500, "something went wrong"));
} }
} }

View File

@ -1,9 +1,9 @@
import { Request, Response, NextFunction } from 'express'; import { Request, Response, NextFunction } from "express";
import jwt from 'jsonwebtoken'; import jwt from "jsonwebtoken";
import env from '../config/environment'; import env from "../config/environment";
import { Log } from 'nork'; import { Log } from "nork";
import User from '../models/User'; import User from "../models/User";
import { isValidObjectId } from 'mongoose'; import { isValidObjectId } from "mongoose";
export function requireAuth(req: Request, res: Response, next: NextFunction) { export function requireAuth(req: Request, res: Response, next: NextFunction) {
const token = req.cookies?.jwt; const token = req.cookies?.jwt;
@ -12,40 +12,40 @@ export function requireAuth(req: Request, res: Response, next: NextFunction) {
jwt.verify(token, env.JWT_SECRET, async (err: any, decodedToken: any) => { jwt.verify(token, env.JWT_SECRET, async (err: any, decodedToken: any) => {
if (err) { if (err) {
// console.error(err.message) // console.error(err.message)
res.status(401).send(Log.error(401, 'user is not authenticated')); res.status(401).send(Log.error(401, "user is not authenticated"));
} }
if (!err) { if (!err) {
const user = await User.findById(decodedToken.id); const user = await User.findById(decodedToken.id);
if (user === null) { if (user === null) {
res.status(401).send(Log.error(401, 'user is not authenticated')); res.status(401).send(Log.error(401, "user is not authenticated"));
return; return;
} }
res.locals.user = user; res.locals.user = user;
Log.info(100, 'user is authenticated'); Log.info(100, "user is authenticated");
next(); next();
} }
}); });
} }
if (!token) { if (!token) {
res.status(401).send(Log.error(401, 'user is not authenticated')); res.status(401).send(Log.error(401, "user is not authenticated"));
} }
} }
export function requireVerified(req: Request, res: Response, next: NextFunction) { export function requireVerified(req: Request, res: Response, next: NextFunction) {
if (res.locals.user._id) { if (res.locals.user._id) {
if (res.locals.user.verified) { if (res.locals.user.verified) {
Log.info(100, 'user is verified'); Log.info(100, "user is verified");
next(); next();
return; return;
} }
res.status(403).json(Log.error(403, 'user is not verified')); res.status(403).json(Log.error(403, "user is not verified"));
return; return;
} }
if (!res.locals.user._id) { if (!res.locals.user._id) {
res.status(401).send(Log.error(401, 'user is not authenticated')); res.status(401).send(Log.error(401, "user is not authenticated"));
return; return;
} }
} }
@ -53,33 +53,33 @@ export function requireVerified(req: Request, res: Response, next: NextFunction)
export class requireRole { export class requireRole {
static Admin(req: Request, res: Response, next: NextFunction) { static Admin(req: Request, res: Response, next: NextFunction) {
if (res.locals.user.admin) { if (res.locals.user.admin) {
Log.info(100, 'user is admin'); Log.info(100, "user is admin");
next(); next();
return; return;
} }
res.status(403).json(Log.error(403, 'insufficient permissions')); res.status(403).json(Log.error(403, "insufficient permissions"));
return; return;
} }
static Owner(req: Request, res: Response, next: NextFunction) { static Owner(req: Request, res: Response, next: NextFunction) {
try { try {
if (!isValidObjectId(req.body.domain_id)) { if (!isValidObjectId(req.body.domain_id)) {
throw Log.error(400, 'neznámé domain_id'); throw Log.error(400, "neznámé domain_id");
} }
const domain = res.locals.user.domains.filter((domain: any) => domain.domain_id == req.body.domain_id); const domain = res.locals.user.domains.filter((domain: any) => domain.domain_id == req.body.domain_id);
console.log(domain); console.log(domain);
if (domain.length < 1) { if (domain.length < 1) {
throw Log.error(400, 'neznámé domain_id'); throw Log.error(400, "neznámé domain_id");
} }
if (domain[0].role == 1) { if (domain[0].role == 1) {
Log.info(100, 'user is owner'); Log.info(100, "user is owner");
next(); next();
return; return;
} }
res.status(403).json(Log.error(403, 'insufficient permissions')); res.status(403).json(Log.error(403, "insufficient permissions"));
return; return;
} catch (err: any) { } catch (err: any) {
res.status(400).json(err); res.status(400).json(err);

View File

@ -1,11 +1,11 @@
import multer from 'multer'; import multer from "multer";
import {Log} from 'nork' import { Log } from "nork";
import { Request, Response, NextFunction } from 'express'; import { Request, Response, NextFunction } from "express";
const validateMulterRequestMiddleware = async (err: any, req: Request, res: Response, next: NextFunction) => { const validateMulterRequestMiddleware = async (err: any, req: Request, res: Response, next: NextFunction) => {
if (err instanceof multer.MulterError) { if (err instanceof multer.MulterError) {
Log.error(500, 'error while processing uploaded files', JSON.stringify(err)); Log.error(500, "error while processing uploaded files", JSON.stringify(err));
res.status(400).json(Log.error(400, 'error while processing uploaded files')); res.status(400).json(Log.error(400, "error while processing uploaded files"));
return; return;
} else { } else {
next(); next();

View File

@ -1,6 +1,6 @@
import { Request, Response, NextFunction } from 'express'; import { Request, Response, NextFunction } from "express";
import { object, AnySchema } from 'yup'; import { object, AnySchema } from "yup";
import { Log } from 'nork'; import { Log } from "nork";
const validate = (schema: AnySchema) => async (req: Request, res: Response, next: NextFunction) => { const validate = (schema: AnySchema) => async (req: Request, res: Response, next: NextFunction) => {
try { try {
@ -8,7 +8,7 @@ const validate = (schema: AnySchema) => async (req: Request, res: Response, next
next(); next();
} catch (err: any) { } catch (err: any) {
return res.status(400).json(Log.error(400, 'validation error', err)); return res.status(400).json(Log.error(400, "validation error", err));
} }
}; };

View File

@ -1,34 +1,34 @@
import path from 'path'; import path from "path";
import { Schema, model } from 'mongoose'; import { Schema, model } from "mongoose";
import { IBeer } from '../validators/beerValidator'; import { IBeer } from "../validators/beerValidator";
const schema = new Schema<IBeer | any>( const schema = new Schema<IBeer | any>(
{ {
name: { name: {
type: String, type: String,
required: true required: true,
}, },
degree: { degree: {
type: Number, type: Number,
required: true required: true,
}, },
packaging: { packaging: {
type: String, type: String,
required: true required: true,
}, },
brand: { brand: {
type: String, type: String,
required: true required: true,
}, },
imgs: { imgs: {
type: Array, type: Array,
required: false, required: false,
default: [] default: [],
} },
}, },
{ {
timestamps: true timestamps: true,
} },
); );
export default model(path.basename(__filename).split('.')[0], schema); export default model(path.basename(__filename).split(".")[0], schema);

View File

@ -1,12 +1,12 @@
import path from 'path'; import path from "path";
import { Schema, model } from 'mongoose'; import { Schema, model } from "mongoose";
import { IReview } from '../validators/reviewValidator'; import { IReview } from "../validators/reviewValidator";
const schema = new Schema<IReview | any>( const schema = new Schema<IReview | any>(
{ {
foam : { foam: {
type: Number, type: Number,
required: true required: true,
}, },
bitter_sweetness: { bitter_sweetness: {
type: Number, type: Number,
@ -14,24 +14,24 @@ const schema = new Schema<IReview | any>(
}, },
taste: { taste: {
type: Number, type: Number,
required: true required: true,
}, },
packaging: { packaging: {
type: Number, type: Number,
required: true required: true,
}, },
sourness: { sourness: {
type: Boolean, type: Boolean,
required: true required: true,
}, },
would_again: { would_again: {
type: Boolean, type: Boolean,
required: true required: true,
} },
}, },
{ {
timestamps: true timestamps: true,
} },
); );
export default model(path.basename(__filename).split('.')[0], schema); export default model(path.basename(__filename).split(".")[0], schema);

View File

@ -1,26 +1,26 @@
import path from 'path'; import path from "path";
import { Schema, model } from 'mongoose'; import { Schema, model } from "mongoose";
import { IUser } from '../validators/authValidator'; import { IUser } from "../validators/authValidator";
const schema = new Schema<IUser>( const schema = new Schema<IUser>(
{ {
username: { username: {
type: String, type: String,
required: true required: true,
}, },
email: { email: {
type: String, type: String,
required: true, required: true,
unique: true unique: true,
}, },
password: { password: {
type: String, type: String,
required: true required: true,
} },
}, },
{ {
timestamps: true timestamps: true,
} },
); );
export default model(path.basename(__filename).split('.')[0], schema); export default model(path.basename(__filename).split(".")[0], schema);

View File

@ -1,32 +1,42 @@
import { Router } from "express"; import { Router } from "express";
import multer from 'multer'; import multer from "multer";
import path from 'path' import path from "path";
import * as authController from "../controllers/authController"; import * as authController from "../controllers/authController";
import * as beerController from "../controllers/beerController" import * as beerController from "../controllers/beerController";
import * as docsController from "../controllers/docsController" import * as docsController from "../controllers/docsController";
import * as reviewController from "../controllers/reviewController" import * as reviewController from "../controllers/reviewController";
import { requireAuth } from "../middlewares/authMiddleware"; import { requireAuth } from "../middlewares/authMiddleware";
import validate from '../middlewares/validateRequest' import validate from "../middlewares/validateRequest";
import valMulter from '../middlewares/validateMulterRequest'; import valMulter from "../middlewares/validateMulterRequest";
import * as AuthVal from '../validators/authValidator' import * as AuthVal from "../validators/authValidator";
import * as BVal from '../validators/beerValidator'; import * as BVal from "../validators/beerValidator";
import * as RVal from "../validators/reviewValidator";
const upload = multer({ dest: path.resolve(__dirname, '../../uploads') }); const upload = multer({ dest: path.resolve(__dirname, "../../uploads") });
const router = Router(); const router = Router();
router.get('/', docsController.docs_get); router.get("/", docsController.docs_get);
router.post("/auth/signup",validate(AuthVal.signup) , authController.signup_post); router.post("/auth/signup", validate(AuthVal.signup), authController.signup_post);
router.post("/auth/signin",validate(AuthVal.signin) , authController.signin_post); router.post("/auth/signin", validate(AuthVal.signin), authController.signin_post);
router.post("/auth/logout", requireAuth, authController.logout_post); router.post("/auth/logout", requireAuth, authController.logout_post);
router.get("/auth/status", requireAuth, authController.status_get); router.get("/auth/status", requireAuth, authController.status_get);
router.post('/beer/add', [requireAuth, upload.array('photos', 4), valMulter, validate(BVal.add)], beerController.add_post); router.post(
router.get('/beer/get', [requireAuth], beerController.get_get); "/beer/add",
router.post('/beer/del', [requireAuth, validate(BVal.del)], beerController.del_post); [requireAuth, upload.array("photos", 4), valMulter, validate(BVal.add)],
router.post('/beer/edit', [requireAuth, upload.array('photos', 4), valMulter, validate(BVal.edit)], beerController.edit_post); beerController.add_post,
);
router.get("/beer/get", [requireAuth], beerController.get_get);
router.post("/beer/del", [requireAuth, validate(BVal.del)], beerController.del_post);
router.post(
"/beer/edit",
[requireAuth, upload.array("photos", 4), valMulter, validate(BVal.edit)],
beerController.edit_post,
);
router.post('/review/add', requireAuth, reviewController.add_post) router.post("/review/add", [requireAuth, validate(RVal.add)], reviewController.add_post);
router.get("/review/get", requireAuth, reviewController.get_get);
export default router; export default router;

View File

@ -1,7 +1,7 @@
import http from "http"; import http from "http";
import { app } from "./app"; import { app } from "./app";
import env from "./config/environment"; import env from "./config/environment";
import mongoose from 'mongoose' // TODO: dopsat nork module pro db import mongoose from "mongoose"; // TODO: dopsat nork module pro db
import { Log } from "nork"; import { Log } from "nork";
const port: number = env.APP_PORT || 8080; const port: number = env.APP_PORT || 8080;
@ -23,13 +23,11 @@ export const server = http.createServer(app);
// runServer() // runServer()
//} //}
(async () => { (async () => {
if (!process.env.DOCS_GEN) { if (!process.env.DOCS_GEN) {
try { try {
await mongoose.connect(env.DB_URI); await mongoose.connect(env.DB_URI);
Log.info(200, 'connected to db'); Log.info(200, "connected to db");
server.listen(port, () => { server.listen(port, () => {
Log.info(200, `Server is listening on http://localhost:${port}`); Log.info(200, `Server is listening on http://localhost:${port}`);
}); });

View File

@ -1,8 +1,8 @@
import fs from 'fs'; import fs from "fs";
import path from 'path'; import path from "path";
export type HttpMethods = 'POST' | 'GET' | 'PUT' | 'DELETE'; export type HttpMethods = "POST" | "GET" | "PUT" | "DELETE";
export type ApiResponse = 'status object' | Object | string; export type ApiResponse = "status object" | Object | string;
export class Docs { export class Docs {
private name: string; private name: string;
@ -14,7 +14,16 @@ export class Docs {
private body?: Object; private body?: Object;
private response?: ApiResponse; private response?: ApiResponse;
public constructor(name: string, operation: string, route: string, method: HttpMethods, description?: string, parameters?: Object[], body?: Object, response?: ApiResponse) { public constructor(
name: string,
operation: string,
route: string,
method: HttpMethods,
description?: string,
parameters?: Object[],
body?: Object,
response?: ApiResponse,
) {
this.name = name; this.name = name;
this.operation = operation; this.operation = operation;
this.route = route; this.route = route;
@ -32,14 +41,14 @@ export class Docs {
return false; return false;
} }
const jsonPath = path.join(__dirname, '../public/api.json'); const jsonPath = path.join(__dirname, "../public/api.json");
const pkg = JSON.parse(fs.readFileSync(path.join(__dirname, '../../package.json')).toString()); const pkg = JSON.parse(fs.readFileSync(path.join(__dirname, "../../package.json")).toString());
const jsonAPI = () => JSON.parse(fs.readFileSync(jsonPath).toString()); const jsonAPI = () => JSON.parse(fs.readFileSync(jsonPath).toString());
const genJsonAPI = () => fs.writeFileSync(jsonPath, JSON.stringify({ version: pkg.version, endpoints: {} })); const genJsonAPI = () => fs.writeFileSync(jsonPath, JSON.stringify({ version: pkg.version, endpoints: {} }));
if (!fs.existsSync(path.join(__dirname, '../public'))) { if (!fs.existsSync(path.join(__dirname, "../public"))) {
fs.mkdirSync(path.join(__dirname, '../public')); fs.mkdirSync(path.join(__dirname, "../public"));
} }
if (!fs.existsSync(jsonPath)) { if (!fs.existsSync(jsonPath)) {

View File

@ -1,6 +1,6 @@
import * as shell from 'shelljs'; import * as shell from "shelljs";
// Copy all the view templates // Copy all the view templates
//shell.cp('-R', 'src/views', 'dist/') //shell.cp('-R', 'src/views', 'dist/')
shell.cp('-R', 'src/public', 'dist/'); shell.cp("-R", "src/public", "dist/");
shell.cp('-u', 'src/.env', 'dist/'); shell.cp("-u", "src/.env", "dist/");

View File

@ -1,10 +1,10 @@
const mongoose = require('mongoose'); const mongoose = require("mongoose");
const { MongoMemoryServer } = require('mongodb-memory-server'); const { MongoMemoryServer } = require("mongodb-memory-server");
let mongo: any = null; let mongo: any = null;
const connectDB = async () => { const connectDB = async () => {
mongo = await MongoMemoryServer.create({ binary: { os: { os: 'linux', dist: 'ubuntu', release: '18.04' } } }); // TODO: check that host OS is Void Linux, else remove the argument mongo = await MongoMemoryServer.create({ binary: { os: { os: "linux", dist: "ubuntu", release: "18.04" } } }); // TODO: check that host OS is Void Linux, else remove the argument
const uri = mongo.getUri(); const uri = mongo.getUri();
await mongoose.connect(uri); await mongoose.connect(uri);

View File

@ -1,7 +1,7 @@
import * as yup from 'yup'; import * as yup from "yup";
import YupPassword from 'yup-password'; import YupPassword from "yup-password";
YupPassword(yup); YupPassword(yup);
import { Schema } from 'mongoose'; import { Schema } from "mongoose";
interface mongooseAddition { interface mongooseAddition {
_id?: Schema.Types.ObjectId; _id?: Schema.Types.ObjectId;
@ -13,22 +13,22 @@ interface mongooseAddition {
export const signup = yup.object({ export const signup = yup.object({
username: yup.string().required(), username: yup.string().required(),
email: yup.string().email().required(), email: yup.string().email().required(),
password: yup.string().min(8).minLowercase(1).minUppercase(1).minNumbers(1).required() password: yup.string().min(8).minLowercase(1).minUppercase(1).minNumbers(1).required(),
}); });
export interface IUser extends yup.InferType<typeof signup>, mongooseAddition {} export interface IUser extends yup.InferType<typeof signup>, mongooseAddition {}
export const signupExam: IUser = { export const signupExam: IUser = {
username: 'testuser', username: "testuser",
email: 'text@example.com', email: "text@example.com",
password: 'Test1234' password: "Test1234",
}; };
// SignIn // SignIn
export const signin = yup.object({ export const signin = yup.object({
email: yup.string().email().required(), email: yup.string().email().required(),
password: yup.string().min(8).minLowercase(1).minUppercase(1).minNumbers(1).required() password: yup.string().min(8).minLowercase(1).minUppercase(1).minNumbers(1).required(),
}); });
export interface ISignin extends yup.InferType<typeof signin>, mongooseAddition {} export interface ISignin extends yup.InferType<typeof signin>, mongooseAddition {}
export const signinExam: ISignin = { export const signinExam: ISignin = {
email: 'text@example.com', email: "text@example.com",
password: 'Test1234' password: "Test1234",
}; };

View File

@ -1,7 +1,7 @@
import * as yup from 'yup'; import * as yup from "yup";
import YupPassword from 'yup-password'; import YupPassword from "yup-password";
YupPassword(yup); YupPassword(yup);
import { Schema } from 'mongoose'; import { Schema } from "mongoose";
interface mongooseAddition { interface mongooseAddition {
_id?: Schema.Types.ObjectId; _id?: Schema.Types.ObjectId;
@ -14,23 +14,23 @@ export const add = yup.object({
brand: yup.string().required(), brand: yup.string().required(),
name: yup.string().required(), name: yup.string().required(),
degree: yup.number().required(), degree: yup.number().required(),
packaging: yup.string().required() packaging: yup.string().required(),
}); });
export interface IBeer extends yup.InferType<typeof add>, mongooseAddition {} export interface IBeer extends yup.InferType<typeof add>, mongooseAddition {}
export const addExam: IBeer = { export const addExam: IBeer = {
brand: 'Pilsner Urqell', brand: "Pilsner Urqell",
name: 'Kozel', name: "Kozel",
degree: 11, degree: 11,
packaging: 'can' packaging: "can",
}; };
// Remove // Remove
export const del = yup.object({ export const del = yup.object({
_id: yup.string().required() _id: yup.string().required(),
}); });
export interface IDel extends yup.InferType<typeof del> {} export interface IDel extends yup.InferType<typeof del> {}
export const delExam: IDel = { export const delExam: IDel = {
_id: '6352b303b71cb62222f39895' _id: "6352b303b71cb62222f39895",
}; };
// Update // Update
@ -45,8 +45,13 @@ export const edit = yup.object({
// Array.isArray(imgs) ? schema.array() : schema.string() // Array.isArray(imgs) ? schema.array() : schema.string()
//) //)
imgs: yup.mixed().test('is-array-or-string', 'imgs must be either an array or a string', value => imgs: yup
Array.isArray(value) || typeof value === 'string') .mixed()
.test(
"is-array-or-string",
"imgs must be either an array or a string",
(value) => Array.isArray(value) || typeof value === "string",
),
//imgs: yup.mixed().when('isArray', { //imgs: yup.mixed().when('isArray', {
// is: Array.isArray, // is: Array.isArray,
@ -56,10 +61,10 @@ export const edit = yup.object({
}); });
export interface IEdit extends yup.InferType<typeof edit> {} export interface IEdit extends yup.InferType<typeof edit> {}
export const editExam: IEdit = { export const editExam: IEdit = {
_id: '6355b95dc03fad77bc380146', _id: "6355b95dc03fad77bc380146",
brand: 'Pilsner Urqell', brand: "Pilsner Urqell",
name: 'Radegast', name: "Radegast",
degree: 12, degree: 12,
packaging: 'bottle', packaging: "bottle",
imgs: [] imgs: [],
}; };

View File

@ -1,5 +1,5 @@
import * as yup from 'yup' import * as yup from "yup";
import mongoose, { Schema } from 'mongoose' import mongoose, { Schema } from "mongoose";
interface mongooseAddition { interface mongooseAddition {
_id?: Schema.Types.ObjectId; _id?: Schema.Types.ObjectId;
@ -7,11 +7,9 @@ interface mongooseAddition {
updatedAt?: Schema.Types.Date; updatedAt?: Schema.Types.Date;
} }
let objectIdSchema = yup.string().test( let objectIdSchema = yup
'is-objectId', .string()
'Invalid ObjectId', .test("is-objectId", "Invalid ObjectId", (value: any) => mongoose.Types.ObjectId.isValid(value));
(value: any) => mongoose.Types.ObjectId.isValid(value)
)
// Add // Add
export const add = yup.object({ export const add = yup.object({
@ -21,25 +19,24 @@ export const add = yup.object({
taste: yup.number().min(1).max(5).required(), taste: yup.number().min(1).max(5).required(),
packaging: yup.number().min(1).max(5).required(), packaging: yup.number().min(1).max(5).required(),
sourness: yup.boolean().required(), sourness: yup.boolean().required(),
would_again: yup.boolean().required() would_again: yup.boolean().required(),
}) });
export interface IReview extends yup.InferType<typeof add>, mongooseAddition {} export interface IReview extends yup.InferType<typeof add>, mongooseAddition {}
export const addExam: IReview = { export const addExam: IReview = {
beer_id: '6352b303b71cb62222f39895', beer_id: "6352b303b71cb62222f39895",
foam: 3, foam: 3,
bitter_sweetness: 2, bitter_sweetness: 2,
taste: 5, taste: 5,
packaging: 3, packaging: 3,
sourness: false, sourness: false,
would_again: true would_again: true,
} };
// Remove // Remove
export const del = yup.object({ export const del = yup.object({
_id: objectIdSchema.required() _id: objectIdSchema.required(),
}) });
export interface IDel extends yup.InferType<typeof del> {} export interface IDel extends yup.InferType<typeof del> {}
export const delExam: IDel = { export const delExam: IDel = {
_id: '6352b303b71cb62222f39895' _id: "6352b303b71cb62222f39895",
}; };

View File

@ -1,4 +1,4 @@
import { connectDB, dropDB, dropCollections } from '../src/utils/test_mongodb'; import { connectDB, dropDB, dropCollections } from "../src/utils/test_mongodb";
beforeAll(async () => { beforeAll(async () => {
await connectDB(); await connectDB();

View File

@ -1,22 +1,22 @@
import supertest from 'supertest'; import supertest from "supertest";
import { app } from '../src/app'; import { app } from "../src/app";
import { connectDB, dropDB, dropCollections } from '../src/utils/test_mongodb'; import { connectDB, dropDB, dropCollections } from "../src/utils/test_mongodb";
const request = supertest(app); const request = supertest(app);
export const getJWT = async () => { export const getJWT = async () => {
try { try {
const resReg: any = await request.post('/api/v1/auth/signup').send({ const resReg: any = await request.post("/api/v1/auth/signup").send({
email: 'test@example.local', email: "test@example.local",
password: 'admin1234', password: "admin1234",
username: 'Test Test' username: "Test Test",
}); });
const resLog: any = await request.post('/api/auth/login').send({ const resLog: any = await request.post("/api/auth/login").send({
email: 'test@example.local', email: "test@example.local",
password: 'admin1234' password: "admin1234",
}); });
if (resLog.statusCode != 200) throw 'error while logging in'; if (resLog.statusCode != 200) throw "error while logging in";
const body = JSON.parse(resLog.text); const body = JSON.parse(resLog.text);
return Promise.resolve(body.data.jwt); return Promise.resolve(body.data.jwt);
@ -31,194 +31,194 @@ export const getJWT = async () => {
* @returns JWT cookie * @returns JWT cookie
*/ */
export async function login(): Promise<string> { export async function login(): Promise<string> {
const res = await request.post('/api/v1/auth/signin').send({ const res = await request.post("/api/v1/auth/signin").send({
email: 'thisistest@host.local', email: "thisistest@host.local",
password: 'Admin1234' password: "Admin1234",
}); });
return res.headers['set-cookie']; return res.headers["set-cookie"];
} }
export async function signup(): Promise<boolean> { export async function signup(): Promise<boolean> {
const res = await request.post('/api/v1/auth/signup').send({ const res = await request.post("/api/v1/auth/signup").send({
email: 'thisistest@host.local', email: "thisistest@host.local",
password: 'Admin1234', password: "Admin1234",
username: 'Test Test' username: "Test Test",
}); });
if (res.statusCode == 201) return true; if (res.statusCode == 201) return true;
return false; return false;
} }
describe('POST /api/v1/auth/signup', () => { describe("POST /api/v1/auth/signup", () => {
describe('should drop validation error', () => { describe("should drop validation error", () => {
it('should drop 400 (empty request))', async () => { it("should drop 400 (empty request))", async () => {
const res: any = await request.post('/api/v1/auth/signup').send({}); const res: any = await request.post("/api/v1/auth/signup").send({});
expect(res.statusCode).toBe(400); expect(res.statusCode).toBe(400);
}); });
it('should drop 400 (email))', async () => { it("should drop 400 (email))", async () => {
const res: any = await request.post('/api/v1/auth/signup').send({ const res: any = await request.post("/api/v1/auth/signup").send({
email: '', email: "",
username: 'User Admin', username: "User Admin",
password: 'Admin1234' password: "Admin1234",
}); });
console.log(res) console.log(res);
const body = JSON.parse(res.text); const body = JSON.parse(res.text);
expect(res.statusCode).toBe(400); expect(res.statusCode).toBe(400);
expect(body.data.path).toBe('email'); expect(body.data.path).toBe("email");
}); });
it('should drop 400 (username))', async () => { it("should drop 400 (username))", async () => {
const res: any = await request.post('/api/v1/auth/signup').send({ const res: any = await request.post("/api/v1/auth/signup").send({
email: 'admin@localhost.local', email: "admin@localhost.local",
username: '', username: "",
password: 'Admin1234' password: "Admin1234",
}); });
const body = JSON.parse(res.text); const body = JSON.parse(res.text);
expect(res.statusCode).toBe(400); expect(res.statusCode).toBe(400);
expect(body.data.path).toBe('username'); expect(body.data.path).toBe("username");
}); });
it('should drop 400 (password))', async () => { it("should drop 400 (password))", async () => {
const res: any = await request.post('/api/v1/auth/signup').send({ const res: any = await request.post("/api/v1/auth/signup").send({
email: 'admin@localhost.local', email: "admin@localhost.local",
username: 'User Admin', username: "User Admin",
password: '' password: "",
}); });
const body = JSON.parse(res.text); const body = JSON.parse(res.text);
expect(res.statusCode).toBe(400); expect(res.statusCode).toBe(400);
expect(body.data.path).toBe('password'); expect(body.data.path).toBe("password");
}); });
it('should drop 400 (password - min 8 chars', async () => { it("should drop 400 (password - min 8 chars", async () => {
const res = await request.post('/api/v1/auth/signup').send({ const res = await request.post("/api/v1/auth/signup").send({
email: 'admin@localhost.local', email: "admin@localhost.local",
username: 'User Admin', username: "User Admin",
password: 'Admin12' password: "Admin12",
}); });
const body = JSON.parse(res.text); const body = JSON.parse(res.text);
expect(res.statusCode).toBe(400); expect(res.statusCode).toBe(400);
expect(body.data.path).toBe('password'); expect(body.data.path).toBe("password");
}); });
it('should drop 400 (password - min 1 number', async () => { it("should drop 400 (password - min 1 number", async () => {
const res = await request.post('/api/v1/auth/signup').send({ const res = await request.post("/api/v1/auth/signup").send({
email: 'admin@localhost.local', email: "admin@localhost.local",
username: 'User Admin', username: "User Admin",
password: 'Adminadmin' password: "Adminadmin",
}); });
const body = JSON.parse(res.text); const body = JSON.parse(res.text);
expect(res.statusCode).toBe(400); expect(res.statusCode).toBe(400);
expect(body.data.path).toBe('password'); expect(body.data.path).toBe("password");
}); });
it('should drop 400 (password - min 1 uppercase', async () => { it("should drop 400 (password - min 1 uppercase", async () => {
const res = await request.post('/api/v1/auth/signup').send({ const res = await request.post("/api/v1/auth/signup").send({
email: 'admin@localhost.local', email: "admin@localhost.local",
username: 'User Admin', username: "User Admin",
password: 'admin1234' password: "admin1234",
}); });
const body = JSON.parse(res.text); const body = JSON.parse(res.text);
expect(res.statusCode).toBe(400); expect(res.statusCode).toBe(400);
expect(body.data.path).toBe('password'); expect(body.data.path).toBe("password");
}); });
}); });
test('should register an user', async () => { test("should register an user", async () => {
const res: any = await request.post('/api/v1/auth/signup').send({ const res: any = await request.post("/api/v1/auth/signup").send({
email: 'thisistest@host.local', email: "thisistest@host.local",
password: 'Admin1234', password: "Admin1234",
username: 'Test Test' username: "Test Test",
}); });
expect(res.statusCode).toBe(201); expect(res.statusCode).toBe(201);
}); });
}); });
describe('POST /api/v1/auth/signin', () => { describe("POST /api/v1/auth/signin", () => {
const url = '/api/v1/auth/signin'; const url = "/api/v1/auth/signin";
describe('should drop an validation error', () => { describe("should drop an validation error", () => {
it('should drop 400 (empty)', async () => { it("should drop 400 (empty)", async () => {
const res = await request.post(url).send(); const res = await request.post(url).send();
expect(res.statusCode).toBe(400); expect(res.statusCode).toBe(400);
}); });
it('should drop 400 (email)', async () => { it("should drop 400 (email)", async () => {
const res = await request.post(url).send({ const res = await request.post(url).send({
password: 'Admin1234' password: "Admin1234",
}); });
const body = JSON.parse(res.text); const body = JSON.parse(res.text);
expect(res.statusCode).toBe(400); expect(res.statusCode).toBe(400);
expect(body.data.path).toBe('email'); expect(body.data.path).toBe("email");
}); });
it('should drop 400 (password)', async () => { it("should drop 400 (password)", async () => {
const res = await request.post(url).send({ const res = await request.post(url).send({
email: 'thisistest@host.local' email: "thisistest@host.local",
}); });
const body = JSON.parse(res.text); const body = JSON.parse(res.text);
expect(res.statusCode).toBe(400); expect(res.statusCode).toBe(400);
expect(body.data.path).toBe('password'); expect(body.data.path).toBe("password");
}); });
}); });
test('should drop 401', async () => { test("should drop 401", async () => {
const res = await request.post(url).send({ const res = await request.post(url).send({
email: 'thisistest@host.local', email: "thisistest@host.local",
password: 'Test12365465132' password: "Test12365465132",
}); });
expect(res.statusCode).toBe(401); expect(res.statusCode).toBe(401);
expect(res.header['set-cookie'][0]).toContain("jwt=; Max-Age=0") expect(res.header["set-cookie"][0]).toContain("jwt=; Max-Age=0");
expect(res.header['set-cookie'][1]).toContain("auth=false") expect(res.header["set-cookie"][1]).toContain("auth=false");
}); });
test('should login an user', async () => { test("should login an user", async () => {
const res: any = await request.post(url).send({ const res: any = await request.post(url).send({
email: 'thisistest@host.local', email: "thisistest@host.local",
password: 'Admin1234' password: "Admin1234",
}); });
expect(res.statusCode).toBe(200); expect(res.statusCode).toBe(200);
expect(res.header['set-cookie'][0]).toContain("jwt=") expect(res.header["set-cookie"][0]).toContain("jwt=");
expect(res.header['set-cookie'][1]).toContain("auth=true") expect(res.header["set-cookie"][1]).toContain("auth=true");
}); });
}); });
describe('POST /api/v1/auth/logout', () => { describe("POST /api/v1/auth/logout", () => {
const url = '/api/v1/auth/logout'; const url = "/api/v1/auth/logout";
test('should drop 401 error', async () => { test("should drop 401 error", async () => {
const res = await request.post(url).send({}); const res = await request.post(url).send({});
expect(res.statusCode).toBe(401); expect(res.statusCode).toBe(401);
}); });
test('should logout an user', async () => { test("should logout an user", async () => {
const jwt = await login(); const jwt = await login();
const res = await request.post(url).set('Cookie', jwt).send(); const res = await request.post(url).set("Cookie", jwt).send();
expect(res.statusCode).toBe(200); expect(res.statusCode).toBe(200);
expect(res.header['set-cookie'][0]).toContain("jwt=; Max-Age=0") expect(res.header["set-cookie"][0]).toContain("jwt=; Max-Age=0");
expect(res.header['set-cookie'][1]).toContain("auth=false") expect(res.header["set-cookie"][1]).toContain("auth=false");
}); });
}); });
describe('GET /api/v1/auth/status', () => { describe("GET /api/v1/auth/status", () => {
const url = '/api/v1/auth/status'; const url = "/api/v1/auth/status";
test('should return login status 401', async () => { test("should return login status 401", async () => {
const res = await request.get(url).send(); const res = await request.get(url).send();
expect(res.statusCode).toBe(401); expect(res.statusCode).toBe(401);
}); });
test('should return login status 200', async () => { test("should return login status 200", async () => {
const jwt = await login(); const jwt = await login();
const res = await request.get(url).set('Cookie', jwt).send(); const res = await request.get(url).set("Cookie", jwt).send();
expect(res.statusCode).toBe(200); expect(res.statusCode).toBe(200);
expect(res.body.data.username).toBe("Test Test") expect(res.body.data.username).toBe("Test Test");
expect(res.body.data.email).toBe("thisistest@host.local") expect(res.body.data.email).toBe("thisistest@host.local");
expect(res.body.data.password).toBeUndefined() expect(res.body.data.password).toBeUndefined();
}); });
}); });

View File

@ -1,166 +1,193 @@
import supertest from 'supertest'; import supertest from "supertest";
import { app } from '../src/app'; import { app } from "../src/app";
import { login } from './auth.test'; import { login } from "./auth.test";
import { addExam, delExam, editExam } from '../src/validators/beerValidator'; import { addExam, delExam, editExam } from "../src/validators/beerValidator";
const request = supertest(app); const request = supertest(app);
describe('POST /api/v1/beer/add', () => { describe("POST /api/v1/beer/add", () => {
const url = '/api/v1/beer/add'; const url = "/api/v1/beer/add";
test('should drop 401 error', async () => { test("should drop 401 error", async () => {
const res = await request.post(url).send({}); const res = await request.post(url).send({});
expect(res.statusCode).toBe(401); expect(res.statusCode).toBe(401);
}); });
test('should drop 400 ()', async () => { test("should drop 400 ()", async () => {
const jwt = await login(); const jwt = await login();
const res = await request.post(url).set('Cookie', jwt).send({}); const res = await request.post(url).set("Cookie", jwt).send({});
expect(res.statusCode).toBe(400); expect(res.statusCode).toBe(400);
}); });
test('should drop 400 (brand)', async () => { test("should drop 400 (name)", async () => {
const jwt = await login();
const body: any = { ...addExam };
delete body.name;
const res = await request.post(url).set("Cookie", jwt).send(body);
expect(res.statusCode).toBe(400);
});
test("should drop 400 (degree)", async () => {
const jwt = await login();
const body: any = { ...addExam };
delete body.degree;
const res = await request.post(url).set("Cookie", jwt).send(body);
expect(res.statusCode).toBe(400);
});
test("should drop 400 (packaging)", async () => {
const jwt = await login();
const body: any = { ...addExam };
delete body.packaging;
const res = await request.post(url).set("Cookie", jwt).send(body);
expect(res.statusCode).toBe(400);
});
test("should drop 400 (brand)", async () => {
const jwt = await login(); const jwt = await login();
const body: any = { ...addExam }; const body: any = { ...addExam };
delete body.brand; delete body.brand;
const res = await request.post(url).set('Cookie', jwt).send(body); const res = await request.post(url).set("Cookie", jwt).send(body);
expect(res.statusCode).toBe(400); expect(res.statusCode).toBe(400);
}); });
test('should drop 201', async () => { test("should drop 201", async () => {
const jwt = await login(); const jwt = await login();
const res = await request.post(url).set('Cookie', jwt).send(addExam); const res = await request.post(url).set("Cookie", jwt).send(addExam);
expect(res.statusCode).toBe(201); expect(res.statusCode).toBe(201);
}); });
}); });
describe('GET /api/v1/beer/get', () => { describe("GET /api/v1/beer/get", () => {
const url = '/api/v1/beer/get'; const url = "/api/v1/beer/get";
test('should drop 401', async () => { test("should drop 401", async () => {
const res = await request.get(url).send(); const res = await request.get(url).send();
expect(res.statusCode).toBe(401); expect(res.statusCode).toBe(401);
}); });
test('should drop 200', async () => { test("should drop 200", async () => {
const jwt = await login(); const jwt = await login();
const res = await request.get(url).set('Cookie', jwt).send(); const res = await request.get(url).set("Cookie", jwt).send();
expect(res.statusCode).toBe(200); expect(res.statusCode).toBe(200);
}); });
}); });
describe('POST /api/v1/beer/del', () => { describe("POST /api/v1/beer/del", () => {
const url = '/api/v1/beer/del'; const url = "/api/v1/beer/del";
test('should drop 401', async () => { test("should drop 401", async () => {
const res = await request.post(url).send(); const res = await request.post(url).send();
expect(res.statusCode).toBe(401); expect(res.statusCode).toBe(401);
}); });
test('should drop 400', async () => { test("should drop 400", async () => {
const jwt = await login(); const jwt = await login();
const res = await request.post(url).set('Cookie', jwt).send(delExam); const res = await request.post(url).set("Cookie", jwt).send(delExam);
expect(res.statusCode).toBe(400); expect(res.statusCode).toBe(400);
}); });
test('should drop 400', async () => { test("should drop 400", async () => {
const jwt = await login(); const jwt = await login();
const res = await request.post(url).set('Cookie', jwt).send({ const res = await request.post(url).set("Cookie", jwt).send({
_id: 'thisWillNotWork' _id: "thisWillNotWork",
}); });
expect(res.statusCode).toBe(400); expect(res.statusCode).toBe(400);
}); });
test('should drop 200', async () => { test("should drop 200", async () => {
const jwt = await login(); const jwt = await login();
const req = await request.post('/api/v1/beer/add').set('Cookie', jwt).send(addExam); const req = await request.post("/api/v1/beer/add").set("Cookie", jwt).send(addExam);
const id = req.body.data._id; const id = req.body.data._id;
const res = await request.post(url).set('Cookie', jwt).send({ const res = await request.post(url).set("Cookie", jwt).send({
_id: id _id: id,
}); });
expect(res.statusCode).toBe(200); expect(res.statusCode).toBe(200);
}); });
}); });
describe('POST /api/v1/beer/edit', () => { describe("POST /api/v1/beer/edit", () => {
const url = '/api/v1/beer/edit'; const url = "/api/v1/beer/edit";
test('should drop 401', async () => { test("should drop 401", async () => {
const res = await request.post(url).send(); const res = await request.post(url).send();
expect(res.statusCode).toBe(401); expect(res.statusCode).toBe(401);
}); });
test('should drop 400', async () => { test("should drop 400", async () => {
const jwt = await login(); const jwt = await login();
const payload: any = { ...editExam }; const payload: any = { ...editExam };
delete payload._id; delete payload._id;
const res = await request.post(url).set('Cookie', jwt).send(payload); const res = await request.post(url).set("Cookie", jwt).send(payload);
expect(res.statusCode).toBe(400); expect(res.statusCode).toBe(400);
}); });
test('should drop 200', async () => { test("should drop 200", async () => {
const jwt = await login(); const jwt = await login();
const payload: any = { ...editExam }; const payload: any = { ...editExam };
delete payload.name; delete payload.name;
const res = await request.post(url).set('Cookie', jwt).send(payload); const res = await request.post(url).set("Cookie", jwt).send(payload);
expect(res.statusCode).toBe(200); expect(res.statusCode).toBe(200);
}); });
test('should drop 200', async () => { test("should drop 200", async () => {
const jwt = await login(); const jwt = await login();
const payload: any = { ...editExam }; const payload: any = { ...editExam };
delete payload.degree; delete payload.degree;
const res = await request.post(url).set('Cookie', jwt).send(payload); const res = await request.post(url).set("Cookie", jwt).send(payload);
expect(res.statusCode).toBe(200); expect(res.statusCode).toBe(200);
}); });
test('should drop 200', async () => { test("should drop 200", async () => {
const jwt = await login(); const jwt = await login();
const payload: any = { ...editExam }; const payload: any = { ...editExam };
delete payload.packaging; delete payload.packaging;
const res = await request.post(url).set('Cookie', jwt).send(payload); const res = await request.post(url).set("Cookie", jwt).send(payload);
expect(res.statusCode).toBe(200); expect(res.statusCode).toBe(200);
}); });
test('should drop 200', async () => { test("should drop 200", async () => {
const jwt = await login(); const jwt = await login();
const payload: any = { ...editExam }; const payload: any = { ...editExam };
delete payload.brand; delete payload.brand;
const res = await request.post(url).set('Cookie', jwt).send(payload); const res = await request.post(url).set("Cookie", jwt).send(payload);
expect(res.statusCode).toBe(200); expect(res.statusCode).toBe(200);
}); });
test('should drop 200', async () => { test("should drop 200", async () => {
const jwt = await login(); const jwt = await login();
const req = await request.post('/api/v1/beer/add').set('Cookie', jwt).send(addExam); const req = await request.post("/api/v1/beer/add").set("Cookie", jwt).send(addExam);
const _id = req.body.data._id; const _id = req.body.data._id;
const payload = { ...editExam, _id: _id }; const payload = { ...editExam, _id: _id };
let res = await request.post(url).set('Cookie', jwt).send(payload); let res = await request.post(url).set("Cookie", jwt).send(payload);
delete res.body.data._id; delete res.body.data._id;
delete res.body.data.__v; delete res.body.data.__v;

View File

@ -1,11 +1,11 @@
import request from 'supertest'; import request from "supertest";
import { app } from '../src/app'; import { app } from "../src/app";
describe('GET /api/v1', () => { describe("GET /api/v1", () => {
describe('should return json with docs', () => { describe("should return json with docs", () => {
test('should respond with a 200 status code', async () => { test("should respond with a 200 status code", async () => {
const response = await request(app).get('/api/v1').send({}); const response = await request(app).get("/api/v1").send({});
expect(response.headers['content-type']).toMatch(/json/); expect(response.headers["content-type"]).toMatch(/json/);
expect(response.statusCode).toBe(200); expect(response.statusCode).toBe(200);
}); });
}); });

View File

@ -1,49 +1,99 @@
import supertest from 'supertest'; import supertest from "supertest";
import { app } from '../src/app'; import { app } from "../src/app";
import { login } from './auth.test'; import { login } from "./auth.test";
//import { addExam, delExam, editExam } from '../src/validators/beerValidator'; import { addExam, delExam } from "../src/validators/reviewValidator";
const request = supertest(app); const request = supertest(app);
describe('POST /api/v1/review/add', () => { describe("POST /api/v1/review/add", () => {
const url = '/api/v1/review/add'; const url = "/api/v1/review/add";
test('should drop 401 error', async () => { test("should drop 401 error", async () => {
const res = await request.post(url).send({}); const res = await request.post(url).send({});
expect(res.statusCode).toBe(401); expect(res.statusCode).toBe(401);
}); });
test('should drop 400 ()', async () => { test("should drop 400 ()", async () => {
const jwt = await login(); const jwt = await login();
const res = await request.post(url).set('Cookie', jwt).send({}); const res = await request.post(url).set("Cookie", jwt).send({});
console.log("TEST", await res.body)
expect(res.statusCode).toBe(400); expect(res.statusCode).toBe(400);
}); });
// test('should drop 201', async () => { test("should drop 400 (foam)", async () => {
// const jwt = await login(); const jwt = await login();
// const res = await request.post(url).set('Cookie', jwt).send(addExam); const body: any = { ...addExam };
// delete body.foam;
// expect(res.statusCode).toBe(201); const res = await request.post(url).set("Cookie", jwt).send(body);
// });
expect(res.statusCode).toBe(400);
});
test("should drop 400 (bitter_sweetness)", async () => {
const jwt = await login();
const body: any = { ...addExam };
delete body.bitter_sweetness;
const res = await request.post(url).set("Cookie", jwt).send(body);
expect(res.statusCode).toBe(400);
});
test("should drop 400 (taste)", async () => {
const jwt = await login();
const body: any = { ...addExam };
delete body.taste;
const res = await request.post(url).set("Cookie", jwt).send(body);
expect(res.statusCode).toBe(400);
});
test("should drop 400 (packaging)", async () => {
const jwt = await login();
const body: any = { ...addExam };
delete body.packaging;
const res = await request.post(url).set("Cookie", jwt).send(body);
expect(res.statusCode).toBe(400);
});
test("should drop 400 (sourness)", async () => {
const jwt = await login();
const body: any = { ...addExam };
delete body.sourness;
const res = await request.post(url).set("Cookie", jwt).send(body);
expect(res.statusCode).toBe(400);
});
test("should drop 400 (would_again)", async () => {
const jwt = await login();
const body: any = { ...addExam };
delete body.would_again;
const res = await request.post(url).set("Cookie", jwt).send(body);
expect(res.statusCode).toBe(400);
});
test("should drop 201", async () => {
const jwt = await login();
const res = await request.post(url).set("Cookie", jwt).send(addExam);
expect(res.statusCode).toBe(201);
});
}); });
//describe('GET /api/v1/beer/get', () => { describe("GET /api/v1/review/get", () => {
// const url = '/api/v1/beer/get'; const url = "/api/v1/review/get";
//
// test('should drop 401', async () => {
// const res = await request.get(url).send();
//
// expect(res.statusCode).toBe(401);
// });
//
// test('should drop 200', async () => {
// const jwt = await login();
// const res = await request.get(url).set('Cookie', jwt).send();
//
// expect(res.statusCode).toBe(200);
// });
//});
test("should drop 401", async () => {
const res = await request.get(url).send();
expect(res.statusCode).toBe(401);
});
test("should drop 200", async () => {
const jwt = await login();
const res = await request.get(url).set("Cookie", jwt).send();
expect(res.statusCode).toBe(200);
});
});