@replyke/express
Version:
Replyke: Build interactive apps with social features like comments, votes, feeds, user lists, notifications, and more.
122 lines (121 loc) • 5.02 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const models_1 = require("../../../models");
const sequelize_query_params_1 = require("../../../constants/sequelize-query-params");
const config_1 = require("../../../config");
exports.default = async (req, res) => {
try {
const { entityId, userId, parentId, sortBy = "new", page = 1, limit = 10, includeEntity, } = req.query;
const projectId = req.project.id;
if ((!entityId && !userId && !parentId) ||
(entityId && typeof entityId !== "string") ||
(userId && typeof userId !== "string") ||
(parentId && typeof parentId !== "string")) {
res.status(400).json({
error: "Invalid request data",
code: "comment/invalid-request",
});
return;
}
// Convert 'limit' and 'page' to numbers and validate them.
let limitAsNumber = Number(limit);
if (isNaN(limitAsNumber) || limitAsNumber <= 0) {
res.status(400).json({
error: "Invalid request: limit must be a positive number.",
code: "comment/invalid-limit",
});
return;
}
limitAsNumber = Math.min(limitAsNumber, 100);
const pageAsNumber = Number(page);
if (isNaN(pageAsNumber) || pageAsNumber < 1 || pageAsNumber % 1 !== 0) {
res.status(400).json({
error: "Invalid request: page must be a whole number greater than 0.",
code: "comment/invalid-page",
});
return;
}
const { sequelize } = (0, config_1.getCoreConfig)();
// Define the sort filter based on 'sortBy' query parameter.
let order = []; // Sequelize uses `order` for sorting
switch (sortBy) {
case "top":
order = [
[
sequelize.literal(`
(COALESCE(array_length("Comment"."upvotes", 1), 0) - COALESCE(array_length("Comment"."downvotes", 1), 0)) DESC,
COALESCE(array_length("Comment"."upvotes", 1), 0) DESC
`),
],
["createdAt", "DESC"],
];
break;
case "new":
order = [["createdAt", "DESC"]];
break;
case "old":
order = [["createdAt", "ASC"]];
break;
case "controversial":
order = [
[
sequelize.literal(`
LOG(COALESCE(array_length("Comment"."upvotes", 1), 0) + COALESCE(array_length("Comment"."downvotes", 1), 0) + 1) *
(LEAST(COALESCE(array_length("Comment"."upvotes", 1), 0), COALESCE(array_length("Comment"."downvotes", 1), 0)) /
GREATEST(COALESCE(array_length("Comment"."upvotes", 1), 0), COALESCE(array_length("Comment"."downvotes", 1), 0)))
`),
"DESC",
],
["createdAt", "DESC"], // Secondary sort by creation time for ties
];
}
// Calculate the offset for pagination.
const offset = (pageAsNumber - 1) * limitAsNumber;
const whereCondition = {
projectId,
};
if (entityId) {
whereCondition.entityId = entityId;
}
if (userId) {
whereCondition.userId = userId;
}
if (parentId) {
whereCondition.parentId = parentId;
}
// Clone the commentParams to safely modify includes
const queryOptions = { ...sequelize_query_params_1.commentParams };
// Conditionally include the Entity model if includeEntity is truthy
if (includeEntity === "true") {
// Ensure our queryOptions.include is an array, then push the Entity model
if (!Array.isArray(queryOptions.include)) {
queryOptions.include = [];
}
queryOptions.include.push({
model: models_1.Entity,
as: "entity",
attributes: {
exclude: ["upvotes", "downvotes"], // Adjust as needed
},
});
}
// Fetch comments based on filters, pagination, and sorting.
const comments = (await models_1.Comment.findAll({
where: whereCondition,
limit: limitAsNumber,
offset,
order, // Sorting by likesCount and/or createdAt
...sequelize_query_params_1.commentParams,
}));
// Respond with the fetched comments.
res.status(200).json(comments.map((i) => i.toJSON()));
}
catch (err) {
console.error("Error fetching comments: ", err);
res.status(500).json({
error: "Internal server error.",
code: "comment/server-error",
details: err.message,
});
}
};