Mail: Outlook.com inside the app through Microsoft Graph (folders, reader, compose, reply, unread badge); Cypht webmail removed

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
nmemmertandClaude Sonnet 5.5 committed 2026-10-22 08:09:11 -04:00
1 parent 1564941ea5
commit a9c277b497
23 files changed
+637 -405

No files matched your search

+3 -3
View File
@@ -71,7 +71,7 @@ const T = (title, extra) => ({ title, notes: '', due: '', done: false, ...extra
await admin.call('/api/tasks', { list: 'local:inbox', fields: T('Admin private task') });
await admin.call('/api/cal/event', { cal: 'local', fields: { title: 'Admin private event', location: '', notes: '', allDay: true, start: '2026-11-03', end: '2026-11-03', tz: 'UTC', repeat: 'none' } });
await admin.call('/api/settings', { key: 'mail_hints', value: { gmail: 'admin@gmail.com' } }, 'PUT');
await admin.call('/api/settings', { key: 'office_loc', value: { gmail: 'admin@gmail.com' } }, 'PUT');
// ---- add Sam with only Tasks and Calendar
r = await admin.call('/api/users', { name: 'Sam', tabs: ['tasks', 'calendar', 'search'] }); const samUser = r.json.user, samCode = r.json.code;
@@ -99,13 +99,13 @@ const T = (title, extra) => ({ title, notes: '', due: '', done: false, ...extra
r = await sam.call('/api/tasks?list=local:inbox'); ok("Sam starts with an empty task list (the admin's task is not visible)", r.status === 200 && r.json.length === 0, r.json);
await sam.call('/api/tasks', { list: 'local:inbox', fields: T('Sam private task') });
await sam.call('/api/cal/event', { cal: 'local', fields: { title: 'Sam private event', location: '', notes: '', allDay: true, start: '2026-11-03', end: '2026-11-03', tz: 'UTC', repeat: 'none' } });
await sam.call('/api/settings', { key: 'mail_hints', value: { gmail: 'sam@gmail.com' } }, 'PUT');
await sam.call('/api/settings', { key: 'office_loc', value: { gmail: 'sam@gmail.com' } }, 'PUT');
const q = '/api/cal/events?from=' + Date.parse('2026-11-01T00:00:00Z') + '&to=' + Date.parse('2026-11-07T00:00:00Z') + '&fd=2026-11-01&td=2026-11-07';
const at = (await admin.call('/api/tasks?list=local:inbox')).json.map(t => t.title), st = (await sam.call('/api/tasks?list=local:inbox')).json.map(t => t.title);
ok('tasks are private to each person', at.join() === 'Admin private task' && st.join() === 'Sam private task', [at, st]);
const ae = (await admin.call(q)).json.events.map(e => e.title), se = (await sam.call(q)).json.events.map(e => e.title);
ok('NE Hub calendar events are private to each person', ae.join() === 'Admin private event' && se.join() === 'Sam private event', [ae, se]);
ok('settings are private to each person', (await admin.call('/api/settings')).json.values.mail_hints.gmail === 'admin@gmail.com' && (await sam.call('/api/settings')).json.values.mail_hints.gmail === 'sam@gmail.com');
ok('settings are private to each person', (await admin.call('/api/settings')).json.values.office_loc.gmail === 'admin@gmail.com' && (await sam.call('/api/settings')).json.values.office_loc.gmail === 'sam@gmail.com');
const fa = (await admin.call('/api/cal/feed')).json.url, fs_ = (await sam.call('/api/cal/feed')).json.url;
const fetchFeed = async u => { const x = await fetch(u.replace(/^https?:\/\/[^/]+/, base)); return { status: x.status, text: await x.text() }; };
const ta = await fetchFeed(fa), ts = await fetchFeed(fs_);