glass/src/features/common/repositories/session/firebase.repository.js
2025-07-12 20:11:20 +09:00

161 lines
5.1 KiB
JavaScript

const { doc, getDoc, collection, addDoc, query, where, getDocs, writeBatch, orderBy, limit, updateDoc, Timestamp } = require('firebase/firestore');
const { getFirestoreInstance } = require('../../services/firebaseClient');
const { createEncryptedConverter } = require('../firestoreConverter');
const encryptionService = require('../../services/encryptionService');
const sessionConverter = createEncryptedConverter(['title']);
function sessionsCol() {
const db = getFirestoreInstance();
return collection(db, 'sessions').withConverter(sessionConverter);
}
// Sub-collection references are now built from the top-level
function subCollections(sessionId) {
const db = getFirestoreInstance();
const sessionPath = `sessions/${sessionId}`;
return {
transcripts: collection(db, `${sessionPath}/transcripts`),
ai_messages: collection(db, `${sessionPath}/ai_messages`),
summary: collection(db, `${sessionPath}/summary`),
}
}
async function getById(id) {
const docRef = doc(sessionsCol(), id);
const docSnap = await getDoc(docRef);
return docSnap.exists() ? docSnap.data() : null;
}
async function create(uid, type = 'ask') {
const now = Timestamp.now();
const newSession = {
uid: uid,
members: [uid], // For future sharing functionality
title: `Session @ ${new Date().toLocaleTimeString()}`,
session_type: type,
started_at: now,
updated_at: now,
ended_at: null,
};
const docRef = await addDoc(sessionsCol(), newSession);
console.log(`Firebase: Created session ${docRef.id} for user ${uid}`);
return docRef.id;
}
async function getAllByUserId(uid) {
const q = query(sessionsCol(), where('members', 'array-contains', uid), orderBy('started_at', 'desc'));
const querySnapshot = await getDocs(q);
return querySnapshot.docs.map(doc => doc.data());
}
async function updateTitle(id, title) {
const docRef = doc(sessionsCol(), id);
await updateDoc(docRef, {
title: encryptionService.encrypt(title),
updated_at: Timestamp.now()
});
return { changes: 1 };
}
async function deleteWithRelatedData(id) {
const db = getFirestoreInstance();
const batch = writeBatch(db);
const { transcripts, ai_messages, summary } = subCollections(id);
const [transcriptsSnap, aiMessagesSnap, summarySnap] = await Promise.all([
getDocs(query(transcripts)),
getDocs(query(ai_messages)),
getDocs(query(summary)),
]);
transcriptsSnap.forEach(d => batch.delete(d.ref));
aiMessagesSnap.forEach(d => batch.delete(d.ref));
summarySnap.forEach(d => batch.delete(d.ref));
const sessionRef = doc(sessionsCol(), id);
batch.delete(sessionRef);
await batch.commit();
return { success: true };
}
async function end(id) {
const docRef = doc(sessionsCol(), id);
await updateDoc(docRef, { ended_at: Timestamp.now() });
return { changes: 1 };
}
async function updateType(id, type) {
const docRef = doc(sessionsCol(), id);
await updateDoc(docRef, { session_type: type });
return { changes: 1 };
}
async function touch(id) {
const docRef = doc(sessionsCol(), id);
await updateDoc(docRef, { updated_at: Timestamp.now() });
return { changes: 1 };
}
async function getOrCreateActive(uid, requestedType = 'ask') {
const findQuery = query(
sessionsCol(),
where('uid', '==', uid),
where('ended_at', '==', null),
orderBy('session_type', 'desc'),
limit(1)
);
const activeSessionSnap = await getDocs(findQuery);
if (!activeSessionSnap.empty) {
const activeSessionDoc = activeSessionSnap.docs[0];
const sessionRef = doc(sessionsCol(), activeSessionDoc.id);
const activeSession = activeSessionDoc.data();
console.log(`[Repo] Found active Firebase session ${activeSession.id}`);
const updates = { updated_at: Timestamp.now() };
if (activeSession.session_type === 'ask' && requestedType === 'listen') {
updates.session_type = 'listen';
console.log(`[Repo] Promoted Firebase session ${activeSession.id} to 'listen' type.`);
}
await updateDoc(sessionRef, updates);
return activeSessionDoc.id;
} else {
console.log(`[Repo] No active Firebase session for user ${uid}. Creating new.`);
return create(uid, requestedType);
}
}
async function endAllActiveSessions(uid) {
const q = query(sessionsCol(), where('uid', '==', uid), where('ended_at', '==', null));
const snapshot = await getDocs(q);
if (snapshot.empty) return { changes: 0 };
const batch = writeBatch(getFirestoreInstance());
const now = Timestamp.now();
snapshot.forEach(d => {
batch.update(d.ref, { ended_at: now });
});
await batch.commit();
console.log(`[Repo] Ended ${snapshot.size} active session(s) for user ${uid}.`);
return { changes: snapshot.size };
}
module.exports = {
getById,
create,
getAllByUserId,
updateTitle,
deleteWithRelatedData,
end,
updateType,
touch,
getOrCreateActive,
endAllActiveSessions,
};