Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add review status to API response #296

Draft
wants to merge 8 commits into
base: dev
Choose a base branch
from
2 changes: 1 addition & 1 deletion api/.env.example
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
DB_URL=postgres://postgres:postgres@localhost:5432/postgres
DB_URL="postgres://postgres:postgres@localhost:5432/postgres?sslmode=disable"
NODE_ENV=development
PORT=8080
JWT_SECRET=''
Expand Down
14 changes: 0 additions & 14 deletions api/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -29,17 +29,3 @@ migrate:
undo-migrate:
yarn run migrate:undo


# move along, this is for mocking
create-mock-network:
docker network create queuer || true

start-mock-deps:
docker run --network=queuer --name transcription-db -e POSTGRES_PASSWORD=postgres -p 5432:5432 -d postgres
docker run --network=queuer --name transcription-redis -p 6379:6379 -d redis

build-mock:
docker build -t transcription .

run-mock:
docker run --network=queuer transcription
219 changes: 34 additions & 185 deletions api/app/controllers/review.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,8 @@ import { Request, Response } from "express";
import { Op } from "sequelize";

import { Review, Transaction, Transcript, User } from "../db/models";
import {
DB_QUERY_LIMIT,
DB_START_PAGE,
QUERY_REVIEW_STATUS,
HOUR_END_OF_DAY,
MINUTE_END_OF_DAY,
SECOND_END_OF_DAY,
MILLISECOND_END_OF_DAY,
} from "../utils/constants";
import {
buildIsActiveCondition,
buildIsInActiveCondition,
buildIsPendingCondition,
} from "../utils/review.inference";
import { DB_QUERY_LIMIT, DB_START_PAGE } from "../utils/constants";
import { buildCondition, buildReviewResponse, computeReviewStatus } from "../utils/review.inference";
import { parseMdToJSON } from "../helpers/transcript";
import axios from "axios";
import { BaseParsedMdContent, TranscriptAttributes } from "../types/transcript";
Expand Down Expand Up @@ -95,10 +83,10 @@ export async function create(req: Request, res: Response) {

// Retrieve all reviews from the database.
export async function findAll(req: Request, res: Response) {
let queryStatus = req.query.status;
const queryStatus = req.query.status as string | undefined;
const userId = Number(req.body.userId);
const page: number = Number(req.query.page) || 1;
const limit: number = Number(req.query.limit) || 5;
const page: number = Number(req.query.page) || DB_START_PAGE;
const limit: number = Number(req.query.limit) || DB_QUERY_LIMIT;
const offset: number = (page - 1) * limit;

const user = await User.findOne({
Expand All @@ -114,59 +102,26 @@ export async function findAll(req: Request, res: Response) {
return;
}

let groupedCondition = {};
const currentTime = new Date().getTime();

const userIdCondition = { userId: { [Op.eq]: user.id } };

// add condition if query exists
if (Boolean(user.id)) {
groupedCondition = { ...groupedCondition, ...userIdCondition };
}
if (queryStatus) {
switch (queryStatus) {
case QUERY_REVIEW_STATUS.ACTIVE:
const activeCondition = buildIsActiveCondition(currentTime);
groupedCondition = { ...groupedCondition, ...activeCondition };
break;
case QUERY_REVIEW_STATUS.PENDING:
const pendingCondition = buildIsPendingCondition();
groupedCondition = { ...groupedCondition, ...pendingCondition };
break;
case QUERY_REVIEW_STATUS.INACTIVE:
const inActiveCondition = buildIsInActiveCondition(currentTime);
groupedCondition = { ...groupedCondition, ...inActiveCondition };
break;
default:
break;
}
}
const { condition } = buildCondition({
status: queryStatus,
userId: user.id,
});

try {
const totalItems = await Review.count({
where: groupedCondition,
where: condition,
});
const totalPages = Math.ceil(totalItems / limit);
const hasNextPage = page < totalPages;
const hasPreviousPage = page > 1;

const data = await Review.findAll({
where: groupedCondition,
limit: limit,
offset: offset,
where: condition,
limit,
offset,
order: [["createdAt", "DESC"]],
include: { model: Transcript },
});

const response = {
totalItems: totalItems,
itemsPerPage: limit,
totalPages: totalPages,
currentPage: page,
hasNextPage,
hasPreviousPage,
data,
};
const response = buildReviewResponse(data, page, limit, totalItems);

res.status(200).send(response);
} catch (error) {
console.log(error);
Expand Down Expand Up @@ -206,7 +161,8 @@ export async function findOne(req: Request, res: Response) {
const branchUrl = data.branchUrl;
const transcriptData = data.transcript.dataValues;
const transcript = await transcriptWrapper(transcriptData, branchUrl);
return res.status(200).send({ ...data.dataValues, transcript });
const reviewWithComputedStatus = computeReviewStatus(data);
return res.status(200).send({ ...reviewWithComputedStatus.dataValues, transcript });
} catch (err) {
res.status(500).send({
message: "Error retrieving review with id=" + id,
Expand Down Expand Up @@ -279,124 +235,28 @@ export const getAllReviewsForAdmin = async (req: Request, res: Response) => {
const transcriptId = Number(req.query.transcriptId);
const userId = Number(req.query.userId);
const mergedAt = req.query.mergedAt as string;
const submittedAt = req.query.submittedAt as string;
const status = req.query.status as string;
const userSearch = req.query.user as string;
const page: number = Number(req.query.page) || DB_START_PAGE;
const limit: number = Number(req.query.limit) || DB_QUERY_LIMIT;

const condition: {
[key: string | number]: any;
} = {};

const userCondition: {
[Op.or]?: {
email?: { [Op.iLike]: string };
githubUsername?: { [Op.iLike]: string };
}[];
} = {};

if (status) {
const currentTime = new Date().getTime();
switch (status) {
case QUERY_REVIEW_STATUS.ACTIVE:
const activeCondition = buildIsActiveCondition(currentTime);
condition[Op.and as unknown as keyof typeof Op] = activeCondition;
break;

case "expired":
const expiredCondition = buildIsInActiveCondition(currentTime);
condition[Op.and as unknown as keyof typeof Op] = expiredCondition;
break;

case QUERY_REVIEW_STATUS.PENDING:
const pendingCondition = buildIsPendingCondition();
condition[Op.and as unknown as keyof typeof Op] = pendingCondition;
break;

default:
break;
}
}

// Check if the mergedAt parameter is provided in the query
if (Boolean(mergedAt)) {
// Convert the mergedAt string to a Date object
const date = new Date(mergedAt as string);

// Calculate the start of the day (00:00:00.000) for the mergedAt date
const startOfDay = new Date(
date.getFullYear(),
date.getMonth(),
date.getDate()
);

// Calculate the end of the day (23:59:59.999) for the mergedAt date
const endOfDay = new Date(
date.getFullYear(),
date.getMonth(),
date.getDate(),
HOUR_END_OF_DAY,
MINUTE_END_OF_DAY,
SECOND_END_OF_DAY,
MILLISECOND_END_OF_DAY
);

// Set the condition for mergedAt to filter records within the specified day
condition.mergedAt = {
[Op.gte]: startOfDay,
[Op.lte]: endOfDay,
};
}

if (Boolean(transcriptId)) {
condition.transcriptId = { [Op.eq]: transcriptId };
}
if (Boolean(userId)) {
condition.userId = { [Op.eq]: userId };
}

// Check if the mergedAt parameter is provided in the query for all time zone support
if (Boolean(mergedAt)) {
// Convert the mergedAt string to a Date object
const date = new Date(mergedAt as string);

// Calculate the start of the day (00:00:00.000) for the mergedAt date
const startOfDay = new Date(
date.getFullYear(),
date.getMonth(),
date.getDate()
);

// Calculate the end of the day (23:59:59.999) for the mergedAt date
const endOfDay = new Date(
date.getFullYear(),
date.getMonth(),
date.getDate(),
HOUR_END_OF_DAY,
MINUTE_END_OF_DAY,
SECOND_END_OF_DAY,
MILLISECOND_END_OF_DAY
);

// Set the condition for mergedAt to filter records within the specified day
condition.mergedAt = {
[Op.gte]: startOfDay,
[Op.lte]: endOfDay,
};
}

if (userSearch) {
const searchCondition = { [Op.iLike]: `%${userSearch.toLowerCase()}%` };
userCondition[Op.or] = [
{ email: searchCondition },
{ githubUsername: searchCondition },
];
}
const offset = Math.max(0, (page - 1) * limit);

const { condition, userCondition } = buildCondition({
status,
transcriptId,
userId,
mergedAt,
userSearch,
submittedAt,
});

try {
const reviews = await Review.findAll({
where: condition,
order: [["createdAt", "DESC"]],
offset,
limit,
include: [
{ model: Transcript, required: true, attributes: { exclude: ["id"] } },
{
Expand All @@ -421,19 +281,7 @@ export const getAllReviewsForAdmin = async (req: Request, res: Response) => {
],
});

const totalPages = Math.ceil(reviewCount / limit);
const hasNextPage = page < totalPages;
const hasPreviousPage = page > 1;

const response = {
totalItems: reviewCount,
totalPages,
currentPage: page,
itemsPerPage: limit,
hasNextPage,
hasPreviousPage,
data: reviews,
};
const response = buildReviewResponse(reviews, page, limit, reviewCount);

res.status(200).json(response);
} catch (error) {
Expand Down Expand Up @@ -478,10 +326,11 @@ export const getReviewsByPaymentStatus = async (
);
const unpaidMergedReviews = mergedReviews.filter(
(review) => !creditTransactionReviewIds.includes(review.id)
);
).map((review) => computeReviewStatus(review));
const paidMergedReviews = mergedReviews.filter((review) =>
creditTransactionReviewIds.includes(review.id)
);
).map((review) => computeReviewStatus(review))


let response: {
totalItems: number;
Expand Down
Loading