fixes: favoritos y mas cosas
Signed-off-by: Omar Sánchez Pizarro <omar.sanchez@pistacero.net>
This commit is contained in:
@@ -88,6 +88,8 @@ async function createIndexes() {
|
||||
// Índices para sesiones (con TTL)
|
||||
await db.collection('sessions').createIndex({ token: 1 }, { unique: true });
|
||||
await db.collection('sessions').createIndex({ expiresAt: 1 }, { expireAfterSeconds: 0 });
|
||||
await db.collection('sessions').createIndex({ username: 1, fingerprint: 1 });
|
||||
await db.collection('sessions').createIndex({ fingerprint: 1 });
|
||||
|
||||
// Índices para workers
|
||||
await db.collection('workers').createIndex({ username: 1 });
|
||||
@@ -259,6 +261,54 @@ export function getRateLimiter() {
|
||||
return rateLimiter;
|
||||
}
|
||||
|
||||
// Obtener información del rate limiter y bloqueos (para memoria)
|
||||
export async function getRateLimiterInfo() {
|
||||
if (!rateLimiter) {
|
||||
return {
|
||||
enabled: false,
|
||||
type: 'none',
|
||||
blocks: [],
|
||||
stats: {
|
||||
totalBlocks: 0,
|
||||
activeBlocks: 0,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
try {
|
||||
// RateLimiterMemory no expone directamente las claves bloqueadas
|
||||
// Necesitamos usar una aproximación diferente
|
||||
// Por ahora, retornamos información básica
|
||||
return {
|
||||
enabled: true,
|
||||
type: 'memory',
|
||||
blocks: [],
|
||||
stats: {
|
||||
totalBlocks: 0,
|
||||
activeBlocks: 0,
|
||||
},
|
||||
config: {
|
||||
points: RATE_LIMIT.POINTS,
|
||||
duration: RATE_LIMIT.DURATION,
|
||||
blockDuration: RATE_LIMIT.BLOCK_DURATION,
|
||||
},
|
||||
note: 'Rate limiter en memoria no expone información detallada de bloqueos',
|
||||
};
|
||||
} catch (error) {
|
||||
console.error('Error obteniendo información del rate limiter:', error.message);
|
||||
return {
|
||||
enabled: true,
|
||||
type: 'memory',
|
||||
blocks: [],
|
||||
stats: {
|
||||
totalBlocks: 0,
|
||||
activeBlocks: 0,
|
||||
},
|
||||
error: error.message,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
export function getConfig() {
|
||||
return config;
|
||||
}
|
||||
@@ -303,6 +353,9 @@ export async function getNotifiedArticles(filter = {}) {
|
||||
.sort({ createdAt: -1, modified_at: -1 })
|
||||
.toArray();
|
||||
|
||||
// Obtener el username del usuario actual para incluir su is_favorite
|
||||
const currentUsername = filter.currentUsername || filter.username;
|
||||
|
||||
// Filtrar y transformar artículos según el usuario solicitado
|
||||
return articles.map(article => {
|
||||
// Si hay filtro de username, solo devolver el user_info correspondiente
|
||||
@@ -350,7 +403,15 @@ export async function getNotifiedArticles(filter = {}) {
|
||||
if (firstUserInfo) {
|
||||
result.username = firstUserInfo.username;
|
||||
result.worker_name = firstUserInfo.worker_name;
|
||||
result.is_favorite = firstUserInfo.is_favorite || false;
|
||||
// Si hay un usuario actual, buscar su is_favorite específico, sino usar el del primer user_info
|
||||
if (currentUsername) {
|
||||
const currentUserInfo = (article.user_info || []).find(
|
||||
ui => ui.username === currentUsername
|
||||
);
|
||||
result.is_favorite = currentUserInfo ? (currentUserInfo.is_favorite || false) : false;
|
||||
} else {
|
||||
result.is_favorite = firstUserInfo.is_favorite || false;
|
||||
}
|
||||
result.notifiedAt =
|
||||
firstUserInfo.notified_at?.getTime?.() ||
|
||||
(typeof firstUserInfo.notified_at === 'number' ? firstUserInfo.notified_at : null) ||
|
||||
@@ -579,6 +640,9 @@ export async function searchArticles(searchQuery, filter = {}, searchMode = 'AND
|
||||
.sort({ createdAt: -1, modified_at: -1 })
|
||||
.toArray();
|
||||
|
||||
// Obtener el username del usuario actual para incluir su is_favorite
|
||||
const currentUsername = filter.currentUsername || filter.username;
|
||||
|
||||
// Transformar artículos según el usuario solicitado (similar a getNotifiedArticles)
|
||||
return articles.map(article => {
|
||||
let relevantUserInfo = null;
|
||||
@@ -619,7 +683,15 @@ export async function searchArticles(searchQuery, filter = {}, searchMode = 'AND
|
||||
if (firstUserInfo) {
|
||||
result.username = firstUserInfo.username;
|
||||
result.worker_name = firstUserInfo.worker_name;
|
||||
result.is_favorite = firstUserInfo.is_favorite || false;
|
||||
// Si hay un usuario actual, buscar su is_favorite específico, sino usar el del primer user_info
|
||||
if (currentUsername) {
|
||||
const currentUserInfo = (article.user_info || []).find(
|
||||
ui => ui.username === currentUsername
|
||||
);
|
||||
result.is_favorite = currentUserInfo ? (currentUserInfo.is_favorite || false) : false;
|
||||
} else {
|
||||
result.is_favorite = firstUserInfo.is_favorite || false;
|
||||
}
|
||||
result.notifiedAt =
|
||||
firstUserInfo.notified_at?.getTime?.() ||
|
||||
(typeof firstUserInfo.notified_at === 'number' ? firstUserInfo.notified_at : null) ||
|
||||
@@ -978,7 +1050,7 @@ export async function setTelegramConfig(username, telegramConfig) {
|
||||
}
|
||||
|
||||
// Funciones para sesiones
|
||||
export async function createSession(username) {
|
||||
export async function createSession(username, fingerprint = null, deviceInfo = null) {
|
||||
if (!db) {
|
||||
throw new Error('MongoDB no está disponible');
|
||||
}
|
||||
@@ -989,9 +1061,22 @@ export async function createSession(username) {
|
||||
|
||||
try {
|
||||
const sessionsCollection = db.collection('sessions');
|
||||
|
||||
// Si hay fingerprint, eliminar sesiones anteriores del mismo dispositivo/usuario
|
||||
if (fingerprint) {
|
||||
await sessionsCollection.deleteMany({
|
||||
username,
|
||||
fingerprint,
|
||||
expiresAt: { $gt: new Date() } // Solo eliminar sesiones activas
|
||||
});
|
||||
}
|
||||
|
||||
// Crear nueva sesión con fingerprint
|
||||
await sessionsCollection.insertOne({
|
||||
token,
|
||||
username,
|
||||
fingerprint: fingerprint || null,
|
||||
deviceInfo: deviceInfo || null,
|
||||
createdAt: new Date(),
|
||||
expiresAt,
|
||||
});
|
||||
@@ -1046,15 +1131,95 @@ export async function deleteUserSessions(username) {
|
||||
}
|
||||
}
|
||||
|
||||
export async function getAllSessions() {
|
||||
if (!db) {
|
||||
return [];
|
||||
}
|
||||
|
||||
try {
|
||||
const sessionsCollection = db.collection('sessions');
|
||||
const sessions = await sessionsCollection.find({}).toArray();
|
||||
return sessions.map(session => ({
|
||||
token: session.token,
|
||||
username: session.username,
|
||||
fingerprint: session.fingerprint || null,
|
||||
deviceInfo: session.deviceInfo || null,
|
||||
createdAt: session.createdAt,
|
||||
expiresAt: session.expiresAt,
|
||||
isExpired: session.expiresAt ? new Date(session.expiresAt) < new Date() : false,
|
||||
}));
|
||||
} catch (error) {
|
||||
console.error('Error obteniendo todas las sesiones:', error.message);
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
// Funciones para artículos
|
||||
export async function getArticle(platform, id) {
|
||||
export async function getArticle(platform, id, currentUsername = null) {
|
||||
if (!db) {
|
||||
return null;
|
||||
}
|
||||
|
||||
try {
|
||||
const articlesCollection = db.collection('articles');
|
||||
return await articlesCollection.findOne({ platform, id });
|
||||
const article = await articlesCollection.findOne({ platform, id });
|
||||
|
||||
if (!article) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Transformar el artículo similar a getNotifiedArticles para incluir is_favorite
|
||||
const result = {
|
||||
...article,
|
||||
_id: article._id.toString(),
|
||||
expiresAt: article.expiresAt?.getTime() || null,
|
||||
};
|
||||
|
||||
const fallbackTime =
|
||||
article.createdAt?.getTime?.() ||
|
||||
(typeof article.createdAt === 'number' ? article.createdAt : null) ||
|
||||
article.modified_at?.getTime?.() ||
|
||||
null;
|
||||
|
||||
// Si hay un usuario actual, buscar su is_favorite específico
|
||||
if (currentUsername) {
|
||||
const currentUserInfo = (article.user_info || []).find(
|
||||
ui => ui.username === currentUsername
|
||||
);
|
||||
if (currentUserInfo) {
|
||||
result.is_favorite = currentUserInfo.is_favorite || false;
|
||||
result.notifiedAt =
|
||||
currentUserInfo.notified_at?.getTime?.() ||
|
||||
(typeof currentUserInfo.notified_at === 'number' ? currentUserInfo.notified_at : null) ||
|
||||
fallbackTime;
|
||||
} else {
|
||||
// Si no hay user_info para este usuario, usar false
|
||||
result.is_favorite = false;
|
||||
}
|
||||
} else {
|
||||
// Sin usuario específico, usar el primer user_info o datos generales
|
||||
const firstUserInfo = (article.user_info || [])[0];
|
||||
if (firstUserInfo) {
|
||||
result.username = firstUserInfo.username;
|
||||
result.worker_name = firstUserInfo.worker_name;
|
||||
result.is_favorite = firstUserInfo.is_favorite || false;
|
||||
result.notifiedAt =
|
||||
firstUserInfo.notified_at?.getTime?.() ||
|
||||
(typeof firstUserInfo.notified_at === 'number' ? firstUserInfo.notified_at : null) ||
|
||||
fallbackTime;
|
||||
} else {
|
||||
// Compatibilidad con estructura antigua
|
||||
result.username = article.username;
|
||||
result.worker_name = article.worker_name;
|
||||
result.is_favorite = article.is_favorite || false;
|
||||
result.notifiedAt =
|
||||
article.notifiedAt?.getTime?.() ||
|
||||
(typeof article.notifiedAt === 'number' ? article.notifiedAt : null) ||
|
||||
fallbackTime;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
} catch (error) {
|
||||
console.error('Error obteniendo artículo:', error.message);
|
||||
return null;
|
||||
|
||||
Reference in New Issue
Block a user