Appearance
Archivos de la Carpeta services
La carpeta src/services contiene la lógica de negocio central de la aplicación. Estos archivos encapsulan las operaciones específicas de cada entidad (ej., autenticación, usuarios, estudiantes, Google Drive) y manejan la interacción con la base de datos, servicios externos (como Google Drive) y otras utilidades. Son responsables de implementar las reglas de negocio, realizar validaciones complejas y asegurar que los datos se procesen y persistan correctamente, manteniendo a los controladores delgados y enfocados únicamente en la gestión de la solicitud y respuesta HTTP.
auth.service.ts
Este servicio gestiona toda la lógica relacionada con la autenticación y el registro de usuarios.
Descripción: Proporciona funciones para autenticar a un usuario (verificar email y contraseña) y para crear una nueva cuenta de usuario. Interactúa con
userServicepara buscar y registrar usuarios, utilizabcryptjspara el manejo seguro de contraseñas, yauth.utilpara la generación de tokens JWT. Maneja errores específicos como credenciales inválidas o usuarios no encontrados.Propósito: Centralizar y encapsular las operaciones de seguridad más críticas de la aplicación, como la verificación de identidad y la creación de cuentas, asegurando que se sigan los protocolos de seguridad adecuados (ej., hashing de contraseñas, uso de tokens).
Funcionalidad:
authenticateUser(email, password):- Busca al usuario por email utilizando
userService.findUserByEmail. - Verifica si el usuario existe y si sus datos esenciales están completos.
- Compara la contraseña proporcionada con la contraseña hasheada almacenada usando
bcryptjs.compare. - Si las credenciales son válidas, genera un token de acceso (JWT) con el email y el ID del usuario.
- Lanza
HttpErroren caso de email no registrado, datos incompletos o contraseña incorrecta.
- Busca al usuario por email utilizando
createUserAccount(email, password, role):- Llama a
userService.registerUserpara crear el nuevo usuario en la base de datos (lo que incluye el hashing de la contraseña). - Genera y retorna un token de acceso (JWT) para el usuario recién creado.
- Llama a
Rol en la aplicación: Es un servicio fundamental para la seguridad y la gestión de acceso. Actúa como el punto de control para la entrada de usuarios al sistema, asegurando que solo usuarios legítimos puedan acceder y que las nuevas cuentas se creen de forma segura.
ts
import bcryptjs from "bcryptjs"; // Importa la librería para el hashing y comparación de contraseñas
import { userService } from "./user.service"; // Importa el servicio de usuario para interactuar con los datos de usuario
import { allowedRoles } from "../interfaces/user.interface"; // Importa el tipo de roles permitidos
import { generateAccessToken } from "../utils/auth.util"; // Importa la utilidad para generar tokens JWT
import { HttpError } from "../utils/httpError.util"; // Importa la clase de error HTTP personalizada
// Función asíncrona para autenticar a un usuario
const authenticateUser = async (email: string, password: string) => {
// Busca un usuario en la base de datos por su email usando el userService
const user = await userService.findUserByEmail(email);
// Si no se encuentra ningún usuario con el email proporcionado, lanza un error 404.
if (!user) {
throw new HttpError("El email no está registrado", 404);
}
// Extrae los valores del modelo de usuario. Usar .get() convierte la instancia de Sequelize
// en un objeto plano de JavaScript para un acceso más seguro a las propiedades.
const { email: userEmail, id: userId, password: userPassword } = user.get();
// Valida que los campos esenciales (email y id) estén definidos en el usuario encontrado.
// Esto es una medida de seguridad para evitar trabajar con datos incompletos.
if (!userEmail || !userId) {
throw new HttpError("Error interno: datos del usuario incompletos", 500);
}
// Compara la contraseña proporcionada por el usuario (en texto plano)
// con la contraseña hasheada almacenada en la base de datos.
const isValidPassword = await bcryptjs.compare(password, userPassword);
// Si las contraseñas no coinciden, lanza un error 401 (Unauthorized).
if (!isValidPassword) {
throw new HttpError("La contraseña es incorrecta", 401);
}
// Si la autenticación es exitosa, genera un token de acceso JWT
// utilizando el email y el ID del usuario.
const token = generateAccessToken(userEmail, userId);
// Retorna el token generado.
return token;
};
// Función asíncrona para crear una nueva cuenta de usuario
const createUserAccount = async (
email: string,
password: string,
role: allowedRoles // El rol debe ser uno de los permitidos
) => {
// Llama al userService para registrar el nuevo usuario en la base de datos.
// Esto incluye el hashing de la contraseña.
const newUser = await userService.registerUser(email, password, role);
// Obtiene el objeto plano del nuevo usuario creado.
const user = newUser.get();
// Genera un token de acceso JWT para el usuario recién creado.
const token = generateAccessToken(user.email, user.id);
// Retorna el token.
return token;
};
// Exporta un objeto que agrupa las funciones de autenticación.
export const authService = {
authenticateUser,
createUserAccount,
};
user.service.ts
Este servicio se encarga de todas las operaciones CRUD y lógicas de negocio relacionadas con la entidad User.
Descripción: Proporciona funciones para registrar, buscar (por ID o email), actualizar, eliminar y listar usuarios. Interactúa directamente con el modelo
Userde Sequelize. Implementa validaciones específicas de negocio, como la unicidad del email o la validez de los roles, y se encarga del hashing de contraseñas conbcryptjs. También sanitiza los datos de usuario antes de retornarlos, omitiendo la contraseña.Propósito: Centralizar la lógica de negocio para la gestión de usuarios, asegurando la consistencia en el acceso y modificación de datos de usuario, y aplicando reglas de validación y seguridad.
Funcionalidad:
allowedRolesArray: Un array interno de roles permitidos, usado para validación.registerUser(email, password, role):- Valida que el
rolesea permitido. - Verifica si el email ya existe para evitar duplicados.
- Genera un
salty hashea lapasswordusandobcryptjs. - Crea un nuevo registro de usuario en la base de datos.
- Valida que el
findUserById(id): Busca un usuario por su clave primaria (ID). Si no lo encuentra, lanza un 404. Retorna el usuario sin la contraseña.findUserByEmail(email): Busca un usuario por su email. Si no lo encuentra, lanza un 404. Retorna el usuario (incluyendo la contraseña, ya que es para uso interno, como enauth.service).modifyUserById(id, email, password, role):- Valida el
role. - Busca el usuario. Si no existe, lanza un error.
- Hashea la nueva contraseña.
- Actualiza los datos del usuario en la base de datos.
- Retorna el usuario actualizado sin la contraseña.
- Valida el
removeUserById(id): Busca y elimina un usuario. Lanza un 404 si no se encuentra.listAllUsers(): Retorna una lista de todos los usuarios registrados. Si no hay usuarios, lanza un 404. Sanitiza la lista para excluir las contraseñas.
Rol en la aplicación: Es un servicio esencial para la administración de usuarios. Proporciona una capa de abstracción sobre las operaciones de base de datos para los usuarios, asegurando la aplicación de reglas de negocio y la seguridad de los datos sensibles como las contraseñas.
ts
import { User } from "../models/user.model"; // Importa el modelo User de Sequelize
import { allowedRoles } from "../interfaces/user.interface"; // Importa el tipo de roles permitidos desde la interfaz
import { HttpError } from "../utils/httpError.util"; // Importa la clase de error HTTP personalizada
import bcryptjs from "bcryptjs"; // Importa la librería para el hashing de contraseñas
// Array de roles válidos, usado para validación interna.
const allowedRolesArray: allowedRoles[] = [
"admin",
"catcher",
"editor",
"visit",
];
// Función para registrar un nuevo usuario en la base de datos.
const registerUser = async (
email: string,
password: string,
role: allowedRoles
) => {
// Busca si ya existe un usuario con el mismo email para evitar duplicados.
const existingUser = await User.findOne({ where: { email } });
// Valida si el rol proporcionado está en la lista de roles permitidos.
if (!allowedRolesArray.includes(role)) {
throw new HttpError("El rol no es válido.", 403); // Error 403 Forbidden si el rol es inválido.
}
// Si ya existe un usuario con ese email, lanza un error 409 (Conflict).
if (existingUser) {
throw new HttpError("El email ya está registrado", 409);
}
// Genera un 'salt' (cadena aleatoria) para añadir seguridad al hashing de la contraseña.
const salt = await bcryptjs.genSalt(10);
// Hashea la contraseña proporcionada utilizando el 'salt' generado.
const passwordHashed = await bcryptjs.hash(password, salt);
// Crea un nuevo registro de usuario en la base de datos.
// El email se guarda en minúsculas para consistencia.
const newUser = (await User.create({
email: email.toLowerCase(),
password: passwordHashed,
role,
})) as User;
return newUser; // Retorna la instancia del nuevo usuario creado.
};
// Función para encontrar un usuario por su ID.
const findUserById = async (id: string) => {
// Busca un usuario por su clave primaria (ID).
const user = await User.findByPk(id);
// Si no se encuentra el usuario, lanza un error 404 (Not Found).
if (!user) throw new HttpError("El ID de usuario no es válido", 404);
// Convierte la instancia del modelo a un objeto plano JSON.
// Luego, desestructura para excluir la contraseña ('password') del objeto retornado (sanitización).
const { password, ...sanitizedUser } = user.toJSON();
return sanitizedUser; // Retorna el usuario sin la contraseña.
};
// Función para encontrar un usuario por su email.
const findUserByEmail = async (email: string) => {
// Busca un usuario por su email (en minúsculas para la coincidencia).
const user = await User.findOne({ where: { email: email.toLowerCase() } });
// Si no se encuentra el usuario, lanza un error 404.
if (!user) throw new HttpError("El email no se encuentra registrado", 404);
return user; // Retorna la instancia del usuario (útil para la autenticación donde se necesita la contraseña).
};
// Función para actualizar un usuario por su ID.
const modifyUserById = async (
id: string,
email: string,
password: string,
role: allowedRoles
) => {
// Valida si el rol proporcionado es válido antes de proceder.
if (!allowedRolesArray.includes(role as allowedRoles)) {
throw new HttpError("El rol no es válido.", 403);
}
// Busca el usuario a actualizar por su ID.
const user = await User.findByPk(id);
// Si no se encuentra, lanza un error 400 (Bad Request).
if (!user) {
throw new HttpError("No se pudo actualizar el usuario: ID inválido", 400);
}
// Genera un nuevo 'salt' y hashea la nueva contraseña.
const salt = await bcryptjs.genSalt(10);
const passwordHashed = await bcryptjs.hash(password, salt);
// Actualiza los campos del usuario en la base de datos.
await user.update({ email, password: passwordHashed, role });
// Retorna el usuario actualizado, sanitizando la contraseña.
const { password: _, ...sanitizedUser } = user.get();
return sanitizedUser;
};
// Función para eliminar un usuario por su ID.
const removeUserById = async (id: string) => {
// Busca el usuario a eliminar.
const user = await User.findByPk(id);
// Si no se encuentra, lanza un error 404.
if (!user) {
throw new HttpError("No se encontró el usuario para eliminar", 404);
}
// Elimina el registro del usuario de la base de datos.
await user.destroy();
return { message: "Usuario eliminado correctamente" }; // Retorna un mensaje de éxito.
};
// Función para listar todos los usuarios registrados.
const listAllUsers = async () => {
// Busca todos los usuarios en la base de datos.
const users = await User.findAll();
// Si no se encuentran usuarios, lanza un error 404.
if (!users.length) {
throw new HttpError("No se encontraron usuarios registrados", 404);
}
// Mapea la lista de usuarios para sanitizar cada uno (eliminar la contraseña).
const sanitizedUsers = users.map((user) => {
const { password, ...rest } = user.get(); // Obtiene el objeto plano y excluye la contraseña.
return rest;
});
return sanitizedUsers; // Retorna la lista de usuarios sanitizados.
};
// Exporta un objeto que agrupa todas las funciones del servicio de usuario.
export const userService = {
registerUser,
findUserById,
findUserByEmail,
removeUserById,
modifyUserById,
listAllUsers,
};
student.service.ts
Este servicio gestiona todas las operaciones CRUD y lógicas de negocio relacionadas con la entidad Student, incluyendo la integración con Google Drive para la gestión de documentos.
Descripción: Proporciona funciones para crear, buscar (por ID o email), actualizar, eliminar y listar estudiantes. Interactúa directamente con el modelo
Studentde Sequelize y congoogleDriveServicepara manejar los archivos adjuntos (imágenes, certificados, DNI) en Google Drive, incluyendo su eliminación al borrar o desvincular un estudiante.Propósito: Centralizar la lógica de negocio para la gestión de estudiantes, asegurando la consistencia de los datos, aplicando validaciones (ej., obligatoriedad de campos, unicidad del teléfono) y gestionando el ciclo de vida de los archivos relacionados en Google Drive.
Funcionalidad:
createStudent(studentData):- Valida la presencia de campos obligatorios (
name,lastname,phone. - Verifica si el número de teléfono ya está registrado.
- Crea un nuevo registro de estudiante en la base de datos.
- Retorna el estudiante creado sin su ID.
- Valida la presencia de campos obligatorios (
getStudentById(id): Busca un estudiante por ID. Lanza un 404 si no lo encuentra.getStudentByEmail(email): Busca un estudiante por email. Lanza un 404 si no lo encuentra.deleteStudentById(id):- Busca el estudiante a eliminar.
- Elimina de Google Drive cualquier archivo asociado (
studentImage,birthCertificate,studyCertificate,linkDni) usando sus IDs de Drive. - Elimina el registro del estudiante de la base de datos.
updateStudentById(id, studentData):- Busca el estudiante a actualizar.
- Gestiona la eliminación de archivos en Google Drive: Si un campo de archivo se actualiza a
null(lo que indica que se desvincula), elimina el archivo correspondiente de Drive. - Actualiza los datos del estudiante en la base de datos.
- Retorna el estudiante actualizado sin su ID.
getAllStudents(): Retorna una lista de todos los estudiantes. Lanza un 404 si no se encuentran estudiantes. Retorna los estudiantes como objetos JSON.
Rol en la aplicación: Es el servicio clave para la administración del registro de estudiantes. Integra la gestión de datos con la persistencia de archivos externos (Google Drive), lo que es fundamental para mantener la integridad de la información de cada estudiante.
ts
import { Student } from "../models/student.model"; // Importa el modelo Student de Sequelize
import { HttpError } from "../utils/httpError.util"; // Importa la clase de error HTTP personalizada
import { CreationAttributes } from "sequelize"; // Importa un tipo de Sequelize para las propiedades de creación
import { googleDriveService } from "./google.drive.service"; // Importa el servicio de Google Drive para interactuar con los archivos
// Función para crear un nuevo estudiante en la base de datos.
const createStudent = async (
studentData: Partial<CreationAttributes<Student>> // Los datos del estudiante, parciales y con tipos de creación
): Promise<Omit<Student, "id">> => {
const { phone, name, lastname } = studentData; // Extrae campos obligatorios para validación
// Función interna para validar si un campo obligatorio está presente.
const validateField = (field: any, fieldName: string): void => {
if (!field) {
throw new HttpError(`${fieldName} es obligatorio`, 400); // Lanza un error si el campo está vacío.
}
};
// Llama a la función de validación para los campos obligatorios.
validateField(name, "El nombre");
validateField(lastname, "El apellido");
validateField(phone, "El número de teléfono");
// Verifica si un estudiante con el mismo número de teléfono ya está registrado.
const existingStudent = await Student.findOne({ where: { phone } });
if (existingStudent) {
throw new HttpError("El número de teléfono ya está registrado", 409); // Error 409 Conflict si el teléfono existe.
}
// Crea un nuevo registro de estudiante en la base de datos.
const newStudent = await Student.create(studentData);
// Convierte la instancia del modelo a un objeto JSON plano y omite el ID.
const { id, ...studentWithoutId } = newStudent.toJSON();
return studentWithoutId; // Retorna el nuevo estudiante sin su ID.
};
// Función para obtener un estudiante por su ID.
const getStudentById = async (id: string): Promise<Student> => {
// Busca un estudiante por su clave primaria (ID).
const student = await Student.findByPk(id);
// Si no se encuentra, lanza un error 404 (Not Found).
if (!student) throw new HttpError("El ID de estudiante no es válido", 404);
return student; // Retorna la instancia del estudiante.
};
// Función para obtener un estudiante por su email.
const getStudentByEmail = async (email: string): Promise<Student> => {
// Busca un estudiante por su email.
const student = await Student.findOne({ where: { email } });
// Si no se encuentra, lanza un error 404.
if (!student) throw new HttpError("El email no se encuentra registrado", 404);
return student; // Retorna la instancia del estudiante.
};
// Función para eliminar un estudiante por su ID.
const deleteStudentById = async (id: string): Promise<Student> => {
// Busca el estudiante a eliminar.
const student = await Student.findByPk(id);
// Si no se encuentra, lanza un error 404.
if (!student) {
throw new HttpError("No se encontró el estudiante para eliminar", 404);
}
// *** Lógica para eliminar archivos asociados de Google Drive si existen ***
if (student.studentImageDriveId) {
await googleDriveService.deleteFile(student.studentImageDriveId);
}
if (student.birthCertificateDriveId) {
await googleDriveService.deleteFile(student.birthCertificateDriveId);
}
if (student.studyCertificateDriveId) {
await googleDriveService.deleteFile(student.studyCertificateDriveId);
}
if (student.linkDniDriveId) {
await googleDriveService.deleteFile(student.linkDniDriveId);
}
// Elimina el registro del estudiante de la base de datos.
await student.destroy();
return student; // Retorna el estudiante eliminado.
};
// Función para actualizar un estudiante por su ID.
const updateStudentById = async (
id: string,
studentData: Partial<Student> // Datos parciales del estudiante a actualizar
): Promise<Omit<Student, "id">> => {
// Busca el estudiante que se va a actualizar.
const studentToUpdate = await Student.findByPk(id);
// Si no se encuentra, lanza un error 400 (Bad Request).
if (!studentToUpdate) {
throw new HttpError(
"No se pudo actualizar el estudiante: ID inválido",
400
);
}
// *** Lógica para eliminar archivos de Google Drive si se desvinculan en la actualización ***
// Si el campo 'studentImage' se setea a null y previamente tenía un ID de Drive,
// se elimina el archivo de Drive y se limpia el ID en el modelo.
if (
studentData.studentImage === null &&
studentToUpdate.studentImageDriveId
) {
await googleDriveService.deleteFile(studentToUpdate.studentImageDriveId);
studentData.studentImageDriveId = null; // Limpia el ID de Drive en los datos a actualizar
}
// Se repite la misma lógica para birthCertificate, studyCertificate y linkDni.
if (
studentData.birthCertificate === null &&
studentToUpdate.birthCertificateDriveId
) {
await googleDriveService.deleteFile(
studentToUpdate.birthCertificateDriveId
);
studentData.birthCertificateDriveId = null;
}
if (
studentData.studyCertificate === null &&
studentToUpdate.studyCertificateDriveId
) {
await googleDriveService.deleteFile(
studentToUpdate.studyCertificateDriveId
);
studentData.studyCertificateDriveId = null;
}
if (studentData.linkDni === null && studentToUpdate.linkDniDriveId) {
await googleDriveService.deleteFile(studentToUpdate.linkDniDriveId);
studentData.linkDniDriveId = null;
}
// Actualiza el registro del estudiante en la base de datos con los nuevos datos.
await studentToUpdate.update(studentData);
// Convierte la instancia actualizada a un objeto JSON plano y omite el ID.
const { id: studentId, ...studentWithoutId } = studentToUpdate.toJSON();
return studentWithoutId; // Retorna el estudiante actualizado sin su ID.
};
// Función para obtener todos los estudiantes.
const getAllStudents = async (): Promise<Student[]> => {
// Busca todos los estudiantes en la base de datos.
const students = await Student.findAll();
// Si no se encuentran estudiantes, lanza un error 404.
if (!students.length) {
throw new HttpError("No se encontraron estudiantes registrados", 404);
}
// Mapea la lista de instancias de Student a objetos JSON planos.
return students.map((student) => student.toJSON());
};
// Exporta un objeto que agrupa todas las funciones del servicio de estudiante.
export const studentService = {
createStudent,
getStudentById,
getStudentByEmail,
deleteStudentById,
updateStudentById,
getAllStudents,
};
google.drive.service.ts
Este servicio encapsula la lógica de interacción con la API de Google Drive, incluyendo la subida, eliminación y gestión de permisos de archivos.
- Descripción: Proporciona funciones para subir archivos a Google Drive, hacerlos públicos y eliminarlos. Utiliza la configuración de autenticación de Google Drive (
../config/google.drive) y la libreríagoogleapispara interactuar con la API de Drive. Implementa un patrón de singleton para la instancia de Drive para optimizar la autenticación. - Propósito: Abstraer la complejidad de la API de Google Drive, ofreciendo un conjunto de funciones sencillas y reutilizables para que otros servicios (como
student.service) puedan gestionar archivos en la nube sin preocuparse por los detalles de la integración. - Funcionalidad:
_driveInstanceygetDriveInstance(): Implementa un patrón de singleton para asegurar que la instancia del cliente de Google Drive (drive_v3.Drive) se inicialice una sola vez y se reutilice en llamadas posteriores, optimizando la autenticación.uploadFileToDrive(filePath, fileName):- Obtiene la instancia de Drive.
- Define metadatos para el archivo, incluyendo el nombre y, opcionalmente, la carpeta de destino (
GOOGLE_DRIVE_FOLDER_IDde las variables de entorno). - Crea un
ReadableStreamdel archivo local y lo sube a Drive. - Retorna los datos del archivo subido (ID, enlaces de vista/contenido).
- Maneja errores durante la subida.
setFilePublic(fileId):- Obtiene la instancia de Drive.
- Crea un permiso para el archivo especificado, haciéndolo de solo lectura (
reader) para "cualquiera" (anyone). - Maneja errores durante la configuración de permisos.
googleDriveService.deleteFile(fileId): (Exportado como parte de un objeto)- Obtiene la instancia de Drive.
- Elimina el archivo de Google Drive usando su ID.
- Registra el éxito o el error de la operación.
- Rol en la aplicación: Es el punto de contacto exclusivo para la gestión de archivos en la nube. Permite que la aplicación almacene, acceda y administre documentos de manera externa, desacoplando la lógica de la aplicación del almacenamiento físico de los archivos.
ts
// src/services/google.drive.service.ts
import { getGoogleDriveService } from "../config/google.drive"; // Importa la función de configuración de Google Drive
import { drive_v3 } from "googleapis"; // Importa el tipo de cliente de Google Drive de googleapis
import fs from "fs"; // Módulo de Node.js para operaciones de sistema de archivos
import { Readable } from "stream"; // Importa Readable para trabajar con streams
// Declara una variable para almacenar la instancia del servicio de Drive.
// Usamos '_driveInstance' para implementar un patrón de singleton:
// la instancia se crea una sola vez y se reutiliza en llamadas posteriores.
let _driveInstance: drive_v3.Drive | null = null;
// Función asíncrona para obtener la instancia autenticada del servicio de Drive.
const getDriveInstance = async (): Promise<drive_v3.Drive> => {
// Si la instancia ya existe, la retorna directamente.
if (!_driveInstance) {
// Si no existe, la inicializa llamando a la función de configuración.
_driveInstance = await getGoogleDriveService();
}
return _driveInstance; // Retorna la instancia de Drive.
};
// --- EXPORTACIONES DIRECTAS (métodos que se usan directamente) ---
// Esta función sube un archivo local a Google Drive.
export const uploadFileToDrive = async (
filePath: string, // Ruta completa del archivo local a subir (ej. 'uploads/mi_imagen.jpg')
fileName: string // Nombre deseado para el archivo en Google Drive (ej. 'imagen_estudiante.jpg')
): Promise<any> => {
try {
const drive = await getDriveInstance(); // Obtiene la instancia de Drive autenticada.
// Define los metadatos del archivo para la API de Drive.
const fileMetadata: any = {
name: fileName, // Nombre del archivo en Drive.
};
// Obtiene el ID de la carpeta de Google Drive desde las variables de entorno.
// Si GOOGLE_DRIVE_FOLDER_ID está definido, el archivo se subirá a esa carpeta.
const parents = process.env.GOOGLE_DRIVE_FOLDER_ID
? [process.env.GOOGLE_DRIVE_FOLDER_ID]
: [];
if (parents.length > 0) {
fileMetadata.parents = parents; // Asigna la carpeta padre si existe.
}
// Define los datos del medio (el archivo en sí).
const media = {
mimeType: "image/jpeg", // Tipo MIME del archivo. Se puede hacer configurable.
body: fs.createReadStream(filePath), // Crea un stream de lectura desde la ruta del archivo local.
};
// Realiza la llamada a la API de Drive para crear el archivo.
const response = await drive.files.create({
requestBody: fileMetadata, // Los metadatos del archivo.
media: media, // El contenido del archivo.
// Solicita los campos 'id', 'webViewLink' y 'webContentLink' en la respuesta.
fields: "id, webViewLink, webContentLink",
});
return response.data; // Retorna los datos del archivo subido (ID, enlaces).
} catch (error: any) {
// Captura y registra cualquier error durante la subida.
console.error("Error al subir el archivo a Google Drive:", error);
throw error; // Relanza el error para que sea manejado por el llamador.
}
};
// Esta función hace un archivo específico público en Google Drive.
export const setFilePublic = async (fileId: string): Promise<void> => {
try {
const drive = await getDriveInstance(); // Obtiene la instancia de Drive autenticada.
// Realiza la llamada a la API para crear un permiso para el archivo.
await drive.permissions.create({
fileId, // El ID del archivo al que se le aplicará el permiso.
requestBody: {
role: "reader", // El permiso es de solo lectura.
type: "anyone", // El permiso se aplica a "cualquiera" (lo hace público).
},
});
} catch (error: any) {
// Captura y registra cualquier error al hacer el archivo público.
console.error(`Error al hacer el archivo ${fileId} público:`, error);
throw error; // Relanza el error.
}
};
// --- Exportación de la instancia del servicio para otros métodos (como deleteFile) ---
// Este objeto 'googleDriveService' contiene métodos adicionales para interactuar con Drive.
// Se exporta como un objeto para agrupar funcionalidades relacionadas (ej. usada por student.service.ts).
export const googleDriveService = {
// Método asíncrono para eliminar un archivo de Google Drive por su ID.
async deleteFile(fileId: string): Promise<void> {
try {
const drive = await getDriveInstance(); // Obtiene la instancia de Drive autenticada.
// Realiza la llamada a la API para eliminar el archivo.
await drive.files.delete({
fileId: fileId, // El ID del archivo a eliminar.
});
console.log(`Archivo con ID ${fileId} eliminado de Google Drive.`); // Mensaje de éxito.
} catch (error: any) {
// Captura y registra cualquier error durante la eliminación.
console.error(
`Error al eliminar el archivo ${fileId} de Google Drive:`,
error
);
throw error; // Relanza el error.
}
},
};