"use strict";
const boom = require("@hapi/boom");
/**
* Registers habit-related API routes on the Hapi server.
*
* This module defines endpoints for managing habits:
*
* - **GET /api.habits**: Retrieve a list of habits for the authenticated user.
* - **POST /api/habits**: Create a new habit for the authenticated user.
* - **PUT /api/habits/{id}**: Update an existing habit for the authenticated user.
* - **DELETE /api/habits/{id}**: Delete an existing habit for the authenticated user.
*
* Each route uses a "try" authentication mode. If the user is not authenticated,
* an unauthorized error is returned.
*
* @async
* @param {Object} server - The Hapi server instance.
* @returns {Promise<void>} A promise that resolves when the routes are registered.
*/
module.exports.register = async server => {
server.route( {
method: "GET",
path: "/api.habits",
options: {
auth: {mode: "try"}
},
/**
* Handler for retrieving habits.
*
* Checks if the request is authenticated. If so, retrieves habits for the user from the SQL client.
*
* @async
* @param {Object} request - The Hapi request object.
* @param {Object} request.auth - The authentication object.
* @param {boolean} request.auth.isAuthenticated - Indicates if the user is authenticated.
* @param {Object} request.auth.credentials - The credentials containing user profile details.
* @returns {Promise<Array<Object>>|Object} A promise that resolves to an array of habit objects or an unauthorized error.
*/
handler: async request => {
try {
if(!request.auth.isAuthenticated) {
return boom.unauthorized();
}
const db = request.server.plugins.sql.client;
const userId = request.auth.credentials.profile.id;
const res = await db.habits.getHabits(userId);
return res.recordset;
} catch (err) {
console.log(err);
}
}
});
server.route({
method: "POST",
path: "/api/habits",
options: {
auth: {mode: "try"}
},
/**
* Handler for creating a new habit.
*
* Validates user authentication and uses the request payload to create a new habit.
*
* @async
* @param {Object} request - The Hapi request object.
* @param {Object} request.auth - The authentication object.
* @param {Object} request.payload - The habit data payload.
* @param {string} request.payload.title - The title of the habit.
* @param {boolean} request.payload.complete - The completion status of the habit.
* @param {number} request.payload.daysComplete - The number of days the habit has been completed.
* @param {number} request.payload.maxDays - The maximum number of days for habit tracking.
* @param {number} request.payload.frequency - The frequency the habit is to be performed.
* @returns {Promise<Object>|Object} A promise that resolves to the newly created habit record or an unauthorized error.
*/
handler: async request => {
try {
if (!request.auth.isAuthenticated) {
return boom.unauthorized();
}
const db = request.server.plugins.sql.client;
const userId = request.auth.credentials.profile.id;
const {title, complete, daysComplete, maxDays, frequency} = request.payload;
const res = await db.habits.addHabit({userId, title, complete, daysComplete, maxDays, frequency});
return res.recordset[0];
} catch (err) {
console.log(err);
return boom.boomify(err);
}
}
});
server.route({
method: "PUT",
path: "/api/habits/{id}",
options: {
auth: {mode: "try"}
},
/**
* Handler for updating an existing habit.
*
* Validates user authentication, then updates the habit specified by the route parameter `id`
* with the data provided in the payload.
*
* @async
* @param {Object} request - The Hapi request object.
* @param {Object} request.auth - The authentication object.
* @param {Object} request.params - The route parameters.
* @param {string} request.params.id - The ID of the habit to update.
* @param {Object} request.payload - The updated habit data.
* @param {string} request.payload.title - The updated title of the habit.
* @param {boolean} request.payload.complete - The updated completion status of the habit.
* @param {number} request.payload.daysComplete - The updated count of days the habit has been completed.
* @param {number} request.payload.maxDays - The updated maximum number of days for habit tracking.
* @param {number} request.payload.frequency - The updated frequency of the habit.
* @returns {Promise<Object>|Object} A promise that resolves to the updated habit record or an error.
*/
handler: async request => {
try {
if (!request.auth.isAuthenticated) {
return boom.unauthorized();
}
const db = request.server.plugins.sql.client;
const userId = request.auth.credentials.profile.id;
const {id} = request.params;
const {title, complete, daysComplete, maxDays, frequency} = request.payload;
const res = await db.habits.updateHabit({id, userId, title, complete, daysComplete, maxDays, frequency});
return res.recordset[0];
} catch (err) {
console.log(err);
return boom.boomify(err);
}
}
});
/*
server.route({
method: "PATCH",
path: "/api/habits/{id}",
options: { auth: { mode: "try" } },
handler: async request => {
try {
if (!request.auth.isAuthenticated) {
return boom.unauthorized();
}
const db = request.server.plugins.sql.client;
const userId = request.auth.credentials.profile.id;
const { id } = request.params;
// Extract the fields sent in the payload for partial update
const patchData = request.payload;
// Ensure your database layer can handle partial updates
const res = await db.habits.patchHabit({ id, userId, ...patchData });
return res.recordset[0];
} catch (err) {
console.log(err);
return boom.boomify(err);
}
}
});
*/
server.route( {
method: "DELETE",
path: "/api/habits/{id}",
options: {
auth: {mode: "try"}
},
/**
* Handler for deleting a habit.
*
* Validates user authentication, deletes the habit with the provided `id`, and returns an HTTP 204 status
* if deletion is successful. Otherwise, returns a not found error.
*
* @async
* @param {Object} request - The Hapi request object.
* @param {Object} request.auth - The authentication object.
* @param {Object} request.params - The route parameters.
* @param {string} request.params.id - The ID of the habit to delete.
* @param {Object} h - The Hapi response toolkit.
* @returns {Promise<Object>|Object} A promise that resolves to an empty response with a 204 status code or an error.
*/
handler: async (request, h) => {
try {
if (!request.auth.isAuthenticated) {
return boom.unauthorized();
}
const id = request.params.id;
const userId = request.auth.credentials.profile.id;
const db = request.server.plugins.sql.client;
const res = await db.habits.deleteHabit({id, userId});
return res.rowsAffected[0] === 1 ? h.response().code(204) : boom.notFound();
} catch (err) {
console.log(err);
return boom.boomify(err);
}
}
});
};