Chores, Family page, genre search, child accounts, wider Search and Notifications center
build-container / build (push) Successful in 4m6s
build-container / build (push) Successful in 4m6s
- Chores tab with repeats, points and a week/month board - Family page: calendar, chores, shopping, notes, chat and tasks on one start page - Genre search in the Store, Free Books and LibriVox - Child accounts: safe content, daily limit and bedtime, ask a parent - Search now covers notes, chat, contacts, chores, recipes and your books - Notifications center: bell with a per-person list of chat, reminders and announcements - Roadmap, README and tests updated Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
cf292e3bc7
commit
0383da87f5
38 files changed
+720
-79
No files matched your search
@@ -29,6 +29,7 @@ const auth = require('./auth');
|
||||
const cal = require('./cal');
|
||||
const tasks = require('./tasks');
|
||||
const settings = require('./settings');
|
||||
const inbox = require('./inbox');
|
||||
const search = require('./search');
|
||||
const users = require('./users');
|
||||
const admin = require('./admin');
|
||||
@@ -43,7 +44,9 @@ const savefiles = require('./savefiles'); // "Save to Files": copy books, lesson
|
||||
const vbv = require('./vbv'); // Verse By Verse Ministry teaching (free Bible studies)
|
||||
const recipes = require('./recipes'); // recipes and the shopping list, from Mealie (MEALIE_URL, MEALIE_TOKEN)
|
||||
const contacts = require('./contacts'); // each person's address book (mail suggestions, calendar birthdays, vCard import and export)
|
||||
const kidlimits = require('./kidlimits'); // child accounts: a daily time limit and bedtime, and asking a parent for more time
|
||||
const screentime = require('./screentime'); // fewer web addresses for iPad Screen Time: a report-only policy, the list of what devices reached, and a picture pass-through
|
||||
const chores = require('./chores'); // chores for the family, with points
|
||||
const notes = require('./notes'); // shared and private notes and checklists
|
||||
const chat = require('./chat'); // Family Chat: a messenger for the people with an account here
|
||||
const musicdata = require('./musicdata'); // what was played, favorites, smart and Family playlists for Music
|
||||
@@ -558,6 +561,7 @@ const ACCESS = [
|
||||
[/^\/api\/bible\//, ['bible']],
|
||||
[/^\/api\/read\//, ['read']],
|
||||
[/^\/api\/radio\//, ['radio']],
|
||||
[/^\/api\/chores(\/|$)/, ['chores']],
|
||||
[/^\/api\/notes(\/|$)/, ['notes']],
|
||||
[/^\/api\/chat(\/|$)/, ['chat']],
|
||||
[/^\/api\/music(\/|$)/, ['music']],
|
||||
@@ -616,6 +620,8 @@ async function handleRequest(req, res) {
|
||||
}
|
||||
// From here on, everything runs "as" this person: their own folder, and only the tabs they were given.
|
||||
return users.runAs(user, async () => {
|
||||
const lock = /^\/(api|sf|plex)\//.test(pathname) ? kidlimits.lockedFor(user, pathname) : null; // (a child whose time is up or whose bedtime it is)
|
||||
if (lock) { res.writeHead(403, { 'content-type': 'application/json', 'x-hub-limit': lock.locked, 'cache-control': 'no-store' }); return res.end(JSON.stringify({ error: lock.locked === 'bedtime' ? 'It is bedtime' : 'Time is up for today', limit: lock.locked, status: lock })); }
|
||||
const rule = ACCESS.find(([re]) => re.test(pathname));
|
||||
if (rule && !rule[1].some(t => users.can(user, t))) return forbidden(res);
|
||||
if ((pathname === '/api/system' || pathname === '/api/health' || pathname === '/api/audit' || pathname.startsWith('/api/users')) && user.role !== 'admin') return forbidden(res, 'Only an admin can do this');
|
||||
@@ -646,6 +652,7 @@ async function handleRequest(req, res) {
|
||||
if (pathname === '/api/system') { res.writeHead(200, { 'content-type': 'application/json' }); return res.end(JSON.stringify(storageInfo())); }
|
||||
if (pathname === '/api/settings') return settings.handle(req, res);
|
||||
if (pathname === '/api/search') return search.handle(req, res);
|
||||
if (pathname === '/api/inbox' || pathname.startsWith('/api/inbox/')) return inbox.handle(req, res);
|
||||
if (req.url.startsWith('/api/tasks')) return tasks.handle(req, res);
|
||||
if (req.url.startsWith('/api/cal/')) return cal.handle(req, res);
|
||||
if (pathname === '/api/audiobooks/enter') { // the secret sign-in link is added here, on the server, and never appears in the app's page or script
|
||||
@@ -660,7 +667,9 @@ async function handleRequest(req, res) {
|
||||
if (pathname.startsWith('/api/podcast/')) return podcast.handle(req, res);
|
||||
if (pathname.startsWith('/api/read/')) return books.handle(req, res);
|
||||
if (pathname.startsWith('/api/radio/')) return radio.handle(req, res);
|
||||
if (pathname.startsWith('/api/kid/')) return kidlimits.handle(req, res, user, { askParents: chat.askParents });
|
||||
if (pathname === '/api/csp-report' || pathname === '/api/img' || pathname === '/api/screentime') return screentime.handle(req, res, user);
|
||||
if (pathname === '/api/chores' || pathname.startsWith('/api/chores/')) return chores.handle(req, res);
|
||||
if (pathname === '/api/notes' || pathname.startsWith('/api/notes/')) return notes.handle(req, res);
|
||||
if (pathname.startsWith('/api/chat/')) return chat.handle(req, res);
|
||||
if (pathname.startsWith('/api/music/')) return musicdata.handle(req, res);
|
||||
|
||||
Reference in new issue
Block a user