Move disk data to a class
This commit is contained in:
parent
fd4bc44842
commit
74c17bcd8e
|
@ -1,13 +1,15 @@
|
||||||
import { PostListener } from "./routes";
|
import { PostListener } from "./routes";
|
||||||
import express from "express";
|
import express from "express";
|
||||||
import dotenv from "dotenv";
|
import dotenv from "dotenv";
|
||||||
import { Logger } from "./utils";
|
import { checkFile, Logger } from "./utils";
|
||||||
|
import { ReviewData } from "./utils/ReviewData";
|
||||||
dotenv.config();
|
dotenv.config();
|
||||||
|
|
||||||
const app = express();
|
const app = express();
|
||||||
const post = new PostListener(app);
|
|
||||||
const logger = new Logger("Main");
|
const logger = new Logger("Main");
|
||||||
|
const data = new ReviewData(checkFile("data.json", "utf8"));
|
||||||
|
|
||||||
|
const post = new PostListener(app, data);
|
||||||
const port = +process.env.PORT || 8080;
|
const port = +process.env.PORT || 8080;
|
||||||
|
|
||||||
post.start();
|
post.start();
|
||||||
|
|
|
@ -1,19 +1,17 @@
|
||||||
import fs from "fs";
|
import fs from "fs";
|
||||||
import {
|
import { ServerSideReview, userReviewSchema, typeJson } from "../types";
|
||||||
serverReviewSchema,
|
import { bold, checkFile, emp, Logger, responder } from "../utils";
|
||||||
ServerSideReview,
|
|
||||||
userReviewSchema,
|
|
||||||
typeJson,
|
|
||||||
} from "../types";
|
|
||||||
import { appendId, bold, checkFile, emp, Logger, responder } from "../utils";
|
|
||||||
import { Express, Request, Response } from "express";
|
import { Express, Request, Response } from "express";
|
||||||
|
import { ReviewData } from "../utils/ReviewData";
|
||||||
|
|
||||||
export class PostListener {
|
export class PostListener {
|
||||||
private server: Express;
|
private server: Express;
|
||||||
|
private data: ReviewData;
|
||||||
private readonly logger = new Logger("Post Listener");
|
private readonly logger = new Logger("Post Listener");
|
||||||
|
|
||||||
constructor(server: Express) {
|
constructor(server: Express, data: ReviewData) {
|
||||||
this.server = server;
|
this.server = server;
|
||||||
|
this.data = data;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async start(): Promise<void> {
|
public async start(): Promise<void> {
|
||||||
|
@ -44,30 +42,21 @@ export class PostListener {
|
||||||
req.on("end", () => {
|
req.on("end", () => {
|
||||||
this.logger.log(`${sender} ~>`, validUserReview);
|
this.logger.log(`${sender} ~>`, validUserReview);
|
||||||
|
|
||||||
serverReviewSchema
|
try {
|
||||||
.validate(appendId(validUserReview))
|
this.data.appendReview(validUserReview);
|
||||||
|
|
||||||
.then((validServerReview) => {
|
res.writeHead(201, typeJson);
|
||||||
data.push(validServerReview);
|
res.write(responder.success("review was sent"));
|
||||||
fs.writeFileSync(
|
res.end();
|
||||||
"./persist/data.json",
|
} catch (err) {
|
||||||
JSON.stringify(data, null, 2),
|
this.logger.error("Failed to assign ID to review:", err);
|
||||||
);
|
|
||||||
|
|
||||||
res.writeHead(201, typeJson);
|
res.writeHead(500, typeJson);
|
||||||
res.write(responder.success("review was sent"));
|
res.write(
|
||||||
res.end();
|
responder.serverError("failed to assign ID to review"),
|
||||||
})
|
);
|
||||||
|
res.end();
|
||||||
.catch((err) => {
|
}
|
||||||
this.logger.error("Failed to assign ID to review:", err);
|
|
||||||
|
|
||||||
res.writeHead(500, typeJson);
|
|
||||||
res.write(
|
|
||||||
responder.serverError("failed to assign ID to review"),
|
|
||||||
);
|
|
||||||
res.end();
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
22
src/types.ts
22
src/types.ts
|
@ -1,18 +1,20 @@
|
||||||
import { object, string, number, InferType } from "yup";
|
import { object, string, number, InferType } from "yup";
|
||||||
|
|
||||||
|
const rating = number()
|
||||||
|
.positive()
|
||||||
|
.max(5)
|
||||||
|
.test(
|
||||||
|
"maxDigitsAfterDecimal",
|
||||||
|
"Rating can only have at most one integer at half intervals (.0 or .5)",
|
||||||
|
(number) => (number! * 10) % 5 === 0,
|
||||||
|
)
|
||||||
|
.required();
|
||||||
|
|
||||||
export const typeJson = { "Content-Type": "application/json" };
|
export const typeJson = { "Content-Type": "application/json" };
|
||||||
|
|
||||||
export const userReviewSchema = object({
|
export const userReviewSchema = object({
|
||||||
username: string().min(2).max(30).required(),
|
username: string().min(2).max(30).required(),
|
||||||
rating: number()
|
rating: rating,
|
||||||
.positive()
|
|
||||||
.max(5)
|
|
||||||
.test(
|
|
||||||
"maxDigitsAfterDecimal",
|
|
||||||
"Rating can only have at most one integer at half intervals (.0 or .5)",
|
|
||||||
(number) => (number! * 10) % 5 === 0,
|
|
||||||
)
|
|
||||||
.required(),
|
|
||||||
title: string().max(50).notRequired(),
|
title: string().max(50).notRequired(),
|
||||||
content: string().max(2000).notRequired(),
|
content: string().max(2000).notRequired(),
|
||||||
});
|
});
|
||||||
|
@ -22,5 +24,5 @@ export const serverReviewSchema = userReviewSchema.shape({
|
||||||
});
|
});
|
||||||
|
|
||||||
export type UserSideReview = InferType<typeof userReviewSchema>;
|
export type UserSideReview = InferType<typeof userReviewSchema>;
|
||||||
|
|
||||||
export type ServerSideReview = InferType<typeof serverReviewSchema>;
|
export type ServerSideReview = InferType<typeof serverReviewSchema>;
|
||||||
|
export type userRating = InferType<typeof rating>;
|
||||||
|
|
103
src/utils/ReviewData.ts
Normal file
103
src/utils/ReviewData.ts
Normal file
|
@ -0,0 +1,103 @@
|
||||||
|
import fs from "fs";
|
||||||
|
import {
|
||||||
|
serverReviewSchema,
|
||||||
|
ServerSideReview,
|
||||||
|
userRating,
|
||||||
|
UserSideReview,
|
||||||
|
} from "../types";
|
||||||
|
import { appendId } from "./functions";
|
||||||
|
|
||||||
|
export class ReviewData {
|
||||||
|
public data: ServerSideReview[];
|
||||||
|
|
||||||
|
constructor(existingData?: ServerSideReview[]) {
|
||||||
|
this.data = existingData ?? [];
|
||||||
|
}
|
||||||
|
|
||||||
|
public async appendReview(review: UserSideReview): Promise<void> {
|
||||||
|
await serverReviewSchema
|
||||||
|
.validate(appendId(review))
|
||||||
|
|
||||||
|
.then((validReview) => {
|
||||||
|
this.data.push(validReview);
|
||||||
|
fs.writeFileSync(
|
||||||
|
"./persist/data.json",
|
||||||
|
JSON.stringify(this.data, null, 2),
|
||||||
|
);
|
||||||
|
})
|
||||||
|
|
||||||
|
.catch((err) => {
|
||||||
|
throw new err();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public getReviews(maxCount = Infinity): ServerSideReview[] {
|
||||||
|
let final: ServerSideReview[] = [];
|
||||||
|
|
||||||
|
while (final.length < maxCount) {
|
||||||
|
for (const review of this.data) {
|
||||||
|
final.push(review);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return final;
|
||||||
|
}
|
||||||
|
|
||||||
|
public getReviewById(id: string): ServerSideReview | {} {
|
||||||
|
for (const review of this.data) {
|
||||||
|
if (review.id === id) {
|
||||||
|
return review;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
public getReviewsByUsername(
|
||||||
|
username: string,
|
||||||
|
maxCount = Infinity,
|
||||||
|
): ServerSideReview[] {
|
||||||
|
let final: ServerSideReview[] = [];
|
||||||
|
|
||||||
|
while (final.length < maxCount) {
|
||||||
|
for (const review of this.data) {
|
||||||
|
if (review.username === username) {
|
||||||
|
final.push(review);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return final;
|
||||||
|
}
|
||||||
|
|
||||||
|
public getReviewsByRating(
|
||||||
|
rating: userRating,
|
||||||
|
maxCount = Infinity,
|
||||||
|
): ServerSideReview[] {
|
||||||
|
let final: ServerSideReview[] = [];
|
||||||
|
|
||||||
|
while (final.length < maxCount) {
|
||||||
|
for (const review of this.data) {
|
||||||
|
if (review.rating === rating) {
|
||||||
|
final.push(review);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return final;
|
||||||
|
}
|
||||||
|
|
||||||
|
public getEmptyReviews(maxCount = Infinity): ServerSideReview[] {
|
||||||
|
let final: ServerSideReview[] = [];
|
||||||
|
|
||||||
|
while (final.length < maxCount) {
|
||||||
|
for (const review of this.data) {
|
||||||
|
if (!review.content && !review.title) {
|
||||||
|
final.push(review);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return final;
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue