Fix invitee access to shared logbooks by listing collaborated logbooks in API and saving them locally on accept

This commit is contained in:
2026-05-28 21:42:47 +02:00
parent 9d24f4b71a
commit b62ca14cc1
2 changed files with 30 additions and 2 deletions
@@ -4,6 +4,7 @@ import { Ship, LogIn, UserPlus, AlertTriangle, ShieldCheck, Languages, ArrowRigh
import { getActiveMasterKey, registerUser, loginUser } from '../services/auth.js' import { getActiveMasterKey, registerUser, loginUser } from '../services/auth.js'
import { decryptJson, encryptBuffer } from '../services/crypto.js' import { decryptJson, encryptBuffer } from '../services/crypto.js'
import { saveLogbookKey } from '../services/logbookKeys.js' import { saveLogbookKey } from '../services/logbookKeys.js'
import { db } from '../services/db.js'
import { useDialog } from './ModalDialog.tsx' import { useDialog } from './ModalDialog.tsx'
interface InvitationAcceptanceProps { interface InvitationAcceptanceProps {
@@ -36,6 +37,7 @@ export default function InvitationAcceptance({ onAccepted, onCancel }: Invitatio
const [ownerUsername, setOwnerUsername] = useState('') const [ownerUsername, setOwnerUsername] = useState('')
const [decryptedTitle, setDecryptedTitle] = useState('') const [decryptedTitle, setDecryptedTitle] = useState('')
const [logbookId, setLogbookId] = useState('') const [logbookId, setLogbookId] = useState('')
const [rawEncryptedTitle, setRawEncryptedTitle] = useState('')
// Authentication states // Authentication states
const [isLoggedIn, setIsLoggedIn] = useState(false) const [isLoggedIn, setIsLoggedIn] = useState(false)
@@ -104,6 +106,8 @@ export default function InvitationAcceptance({ onAccepted, onCancel }: Invitatio
setOwnerUsername(details.ownerUsername) setOwnerUsername(details.ownerUsername)
setLogbookId(details.logbookId) setLogbookId(details.logbookId)
setRawEncryptedTitle(details.encryptedTitle)
// Decrypt title client-side using URL key // Decrypt title client-side using URL key
const parsed = JSON.parse(details.encryptedTitle) const parsed = JSON.parse(details.encryptedTitle)
const title = await decryptJson(parsed.ciphertext, parsed.iv, parsed.tag, logbookKey!) const title = await decryptJson(parsed.ciphertext, parsed.iv, parsed.tag, logbookKey!)
@@ -158,6 +162,16 @@ export default function InvitationAcceptance({ onAccepted, onCancel }: Invitatio
// 3. Save key locally in Dexie // 3. Save key locally in Dexie
await saveLogbookKey(logbookId, logbookKey) await saveLogbookKey(logbookId, logbookKey)
// 3b. Save logbook index locally in Dexie so sync is triggered immediately
if (rawEncryptedTitle) {
await db.logbooks.put({
id: logbookId,
encryptedTitle: rawEncryptedTitle,
updatedAt: new Date().toISOString(),
isSynced: 1
})
}
// 4. Redirect to workspace // 4. Redirect to workspace
onAccepted(logbookId, decryptedTitle) onAccepted(logbookId, decryptedTitle)
} catch (err: any) { } catch (err: any) {
+16 -2
View File
@@ -15,11 +15,25 @@ const requireUser = (req: any, res: any, next: any) => {
router.use(requireUser) router.use(requireUser)
// 1. Get all logbooks for the authenticated user // 1. Get all logbooks for the authenticated user (owned and shared)
router.get('/', async (req: any, res) => { router.get('/', async (req: any, res) => {
try { try {
const logbooks = await prisma.logbook.findMany({ const logbooks = await prisma.logbook.findMany({
where: { userId: req.userId }, where: {
OR: [
{ userId: req.userId },
{
collaborators: {
some: { userId: req.userId }
}
}
]
},
include: {
collaborators: {
where: { userId: req.userId }
}
},
orderBy: { createdAt: 'desc' } orderBy: { createdAt: 'desc' }
}) })
return res.json(logbooks) return res.json(logbooks)