isolate imported calendars by account
This commit is contained in:
@@ -25,6 +25,7 @@
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
"icsImported": true,
|
"icsImported": true,
|
||||||
|
"icsStorageScoped": true,
|
||||||
"icsPersistsAfterTabChange": true,
|
"icsPersistsAfterTabChange": true,
|
||||||
"readyPreparationStatus": 200,
|
"readyPreparationStatus": 200,
|
||||||
"readyOutputButtons": 4,
|
"readyOutputButtons": 4,
|
||||||
|
|||||||
@@ -2164,3 +2164,9 @@ Doğrulama: 293 otomatik test ve üretim derlemesi başarılı. Gerçek iki hesa
|
|||||||
Teklif dosyası hazırlama ekranındaki firma bilgileri artık ham e-posta yerine normalize edilip URL kodlanmış hesap anahtarında tutuluyor. Büyük/küçük harf farkı aynı hesabı farklı yerel kayda bölmüyor; özel karakterler anahtar yapısını bozamıyor. Eski ortak/normalize edilmemiş anahtarlardan otomatik veri alınmıyor.
|
Teklif dosyası hazırlama ekranındaki firma bilgileri artık ham e-posta yerine normalize edilip URL kodlanmış hesap anahtarında tutuluyor. Büyük/küçük harf farkı aynı hesabı farklı yerel kayda bölmüyor; özel karakterler anahtar yapısını bozamıyor. Eski ortak/normalize edilmemiş anahtarlardan otomatik veri alınmıyor.
|
||||||
|
|
||||||
Doğrulama: 293 otomatik test ve üretim derlemesi başarılı. Gerçek iki hesaplı tarayıcı kabulü ve canlı deployment ayrıca yapılmalı.
|
Doğrulama: 293 otomatik test ve üretim derlemesi başarılı. Gerçek iki hesaplı tarayıcı kabulü ve canlı deployment ayrıca yapılmalı.
|
||||||
|
|
||||||
|
### 2026-09-06 · ICS takvim verisinin hesap izolasyonu
|
||||||
|
|
||||||
|
Harici ICS etkinlikleri daha önce ortak `sessionStorage` anahtarında tutuluyordu. Kayıtlar artık normalize edilmiş hesap e-postasına bağlı anahtarda saklanıyor; hesap değişiminde takvim temizlenip yeni hesabın etkinlikleri yükleniyor. Browser QA, anahtarın hesap kapsamlı olduğunu ve sekme değişimi sonrası kalıcılığı doğruluyor.
|
||||||
|
|
||||||
|
Doğrulama: browser QA başarılı; 293 otomatik test ve üretim derlemesi başarılı. Gerçek iki hesaplı tarayıcı kabulü ve OAuth takvim senkronizasyonu açık.
|
||||||
|
|||||||
@@ -6,15 +6,24 @@ import { CalendarDays } from 'lucide-react';
|
|||||||
|
|
||||||
export const TenderCalendar = () => {
|
export const TenderCalendar = () => {
|
||||||
const now = useDeadlineClock();
|
const now = useDeadlineClock();
|
||||||
const { tenders, setActiveTenderDetail } = useApp();
|
const { tenders, setActiveTenderDetail, authUser } = useApp();
|
||||||
const today = istanbulDateKey(now);
|
const today = istanbulDateKey(now);
|
||||||
const [month,setMonth] = useState(today.slice(0,7));
|
const [month,setMonth] = useState(today.slice(0,7));
|
||||||
const [selectedDay, setSelectedDay] = useState(today);
|
const [selectedDay, setSelectedDay] = useState(today);
|
||||||
const [imported,setImported] = useState(() => {
|
const calendarStorageKey = authUser?.email ? `ihaleist_imported_calendar:${encodeURIComponent(authUser.email.toLowerCase())}` : null;
|
||||||
try { const saved = JSON.parse(sessionStorage.getItem('ihaleist_imported_calendar') || '[]'); return Array.isArray(saved) && saved.length <= 100 ? saved : []; }
|
const [imported,setImported] = useState([]), [importError,setImportError] = useState('');
|
||||||
catch { return []; }
|
const [loadedCalendarKey, setLoadedCalendarKey] = useState(null);
|
||||||
}), [importError,setImportError] = useState('');
|
React.useEffect(() => {
|
||||||
React.useEffect(() => { try { sessionStorage.setItem('ihaleist_imported_calendar', JSON.stringify(imported)); } catch { /* private browsing can deny storage */ } }, [imported]);
|
if (!calendarStorageKey) { setImported([]); setLoadedCalendarKey(null); return; }
|
||||||
|
let saved = null;
|
||||||
|
try { saved = JSON.parse(sessionStorage.getItem(calendarStorageKey) || '[]'); } catch { saved = []; }
|
||||||
|
setImported(Array.isArray(saved) && saved.length <= 100 ? saved : []);
|
||||||
|
setLoadedCalendarKey(calendarStorageKey);
|
||||||
|
}, [calendarStorageKey]);
|
||||||
|
React.useEffect(() => {
|
||||||
|
if (!loadedCalendarKey || loadedCalendarKey !== calendarStorageKey) return;
|
||||||
|
try { sessionStorage.setItem(loadedCalendarKey, JSON.stringify(imported)); } catch { /* private browsing can deny storage */ }
|
||||||
|
}, [imported, loadedCalendarKey, calendarStorageKey]);
|
||||||
const allTenders = useMemo(() => [...tenders, ...imported], [tenders, imported]);
|
const allTenders = useMemo(() => [...tenders, ...imported], [tenders, imported]);
|
||||||
const agenda=useMemo(()=>calendarAgenda(allTenders,now),[allTenders,now]);
|
const agenda=useMemo(()=>calendarAgenda(allTenders,now),[allTenders,now]);
|
||||||
const daysList=calendarMonthDays(month).map(day=>({...day,count:agenda.days.get(day.key)?.length || 0}));
|
const daysList=calendarMonthDays(month).map(day=>({...day,count:agenda.days.get(day.key)?.length || 0}));
|
||||||
|
|||||||
@@ -36,6 +36,8 @@ try {
|
|||||||
await page.locator('input[aria-label="ICS takvim dosyası seç"]').setInputFiles(icsPath);
|
await page.locator('input[aria-label="ICS takvim dosyası seç"]').setInputFiles(icsPath);
|
||||||
await page.getByText('1 harici etkinlik içe aktarıldı.', { exact: true }).waitFor();
|
await page.getByText('1 harici etkinlik içe aktarıldı.', { exact: true }).waitFor();
|
||||||
evidence.checks.icsImported = true;
|
evidence.checks.icsImported = true;
|
||||||
|
evidence.checks.icsStorageScoped = await page.evaluate(() => Object.keys(sessionStorage).some(key => key.startsWith('ihaleist_imported_calendar:')));
|
||||||
|
if (!evidence.checks.icsStorageScoped) throw new Error('ICS kaydı hesap kapsamlı sessionStorage anahtarı kullanmıyor.');
|
||||||
await page.getByRole('button', { name: 'Keşfet' }).click();
|
await page.getByRole('button', { name: 'Keşfet' }).click();
|
||||||
await page.getByRole('button', { name: 'İhale Takvimi' }).click();
|
await page.getByRole('button', { name: 'İhale Takvimi' }).click();
|
||||||
evidence.checks.icsPersistsAfterTabChange = await page.getByText('1 harici etkinlik içe aktarıldı.', { exact: true }).count() === 1;
|
evidence.checks.icsPersistsAfterTabChange = await page.getByText('1 harici etkinlik içe aktarıldı.', { exact: true }).count() === 1;
|
||||||
|
|||||||
Reference in New Issue
Block a user