diff --git a/.env.example b/.env.example index 7859710..26ff070 100644 --- a/.env.example +++ b/.env.example @@ -15,8 +15,10 @@ BOARD_SOCIALS_PASSWORD= # Passwords for /board/ucla (UCLA's hub). Fiona and Will get # BOARD_UCLA_ADMIN_PASSWORD (admin view); everyone else on the UCLA board # gets BOARD_UCLA_PASSWORD. Use values different from Berkeley's; neither -# chapter's passwords open the other's hub. +# chapter's passwords open the other's hub. Whoever runs UCLA's events gets +# BOARD_UCLA_EVENTS_PASSWORD (member view plus editing events). BOARD_UCLA_ADMIN_PASSWORD= +BOARD_UCLA_EVENTS_PASSWORD= BOARD_UCLA_PASSWORD= # Signs the board hub login cookies (both chapters). Any random string of 32+ characters, # e.g. the output of: openssl rand -base64 32 diff --git a/BOARD_SETUP.md b/BOARD_SETUP.md index 37cd6a8..c721410 100644 --- a/BOARD_SETUP.md +++ b/BOARD_SETUP.md @@ -31,8 +31,13 @@ signs out everyone who used it, and you share the new one with the rest. | Railway variable | Who gets it | What it unlocks | | --------------------------- | ----------------------- | ------------------------------------- | | `BOARD_UCLA_PASSWORD` | everyone on the UCLA board | view everything, submit deliverables | +| `BOARD_UCLA_EVENTS_PASSWORD` | the events editor | also add, edit and delete events | | `BOARD_UCLA_ADMIN_PASSWORD` | Fiona and Will | edit everything on the UCLA hub | +The events password sees what members see and can change events (dates, +times, locations, leads, status), nothing else. Its edits go in the change +log as "UCLA events editor". + Use passwords that differ from Berkeley's. Ten wrong tries from the same connection lock a hub's form for 15 minutes. @@ -119,7 +124,7 @@ board. Postgres service's `DATABASE_URL` (Railway offers it as a reference). 2. **Passwords and secret.** In the same Variables screen, add: - `BOARD_PASSWORD`, `BOARD_SOCIALS_PASSWORD`, `BOARD_ADMIN_PASSWORD` - - `BOARD_UCLA_PASSWORD`, `BOARD_UCLA_ADMIN_PASSWORD` + - `BOARD_UCLA_PASSWORD`, `BOARD_UCLA_EVENTS_PASSWORD`, `BOARD_UCLA_ADMIN_PASSWORD` - `BOARD_SESSION_SECRET`: a random string of at least 32 characters. `openssl rand -base64 32` makes one. 3. Redeploy, open `https://www.getvindicated.org/board`, and sign in with diff --git a/components/board/ChangesTab.tsx b/components/board/ChangesTab.tsx index 6a7efe7..bdddfbc 100644 --- a/components/board/ChangesTab.tsx +++ b/components/board/ChangesTab.tsx @@ -30,24 +30,41 @@ const when = (iso: string) => // "Restore previous version". export function ChangesTab() { const { chapter, data, user } = useBoard(); - const [name, setName] = useState(""); - const [saved, setSaved] = useState(false); - useEffect(() => setName(getActor()), []); if (user.role !== "admin") return null; - const who = chapter.id === "ucla" ? "UCLA admin" : "Berkeley admin"; + const place = chapter.id === "ucla" ? "UCLA" : "Berkeley"; + const who = (role: string) => `${place} ${chapter.roleLabels[role] ?? role}`; return (

Changes

-

Every change made with the {chapter.id === "ucla" ? "UCLA" : "Berkeley"} admin password, newest first. Only admins see this tab.

+

Every change made on the {place} hub, newest first. Only admins see this tab.

+ + + {data.changelog.length === 0 &&

No changes yet.

} + +
+ ); +} + +// "Your name for the log": optional, saved in this browser, sent with each +// change. Everyone with a password shares it, so the log calls it self-reported. +export function ActorName() { + const [name, setName] = useState(""); + const [saved, setSaved] = useState(false); + useEffect(() => setName(getActor()), []); + return (
- - {data.changelog.length === 0 &&

No changes yet.

} - - ); } diff --git a/components/board/SocialsTab.tsx b/components/board/SocialsTab.tsx index c8b7c8f..1a14f27 100644 --- a/components/board/SocialsTab.tsx +++ b/components/board/SocialsTab.tsx @@ -5,6 +5,7 @@ import type { Social } from "@/lib/board/types"; import { SOCIAL_MONTHS, SOCIAL_STATUSES } from "@/lib/board/static"; import type { ChapterConfig } from "@/lib/board/chapters"; import { canEditSocials } from "@/lib/board/roles"; +import { ActorName } from "./ChangesTab"; import { useBoard } from "./BoardApp"; import { RowEditor, type FieldDef } from "./RowEditor"; import { D, fmt, isoDate } from "./util"; @@ -66,6 +67,7 @@ export function SocialsTab() { return (

{cfg.heading}

+ {editor && user.role !== "admin" && }
{FILTERS.map((f) => (