From 93eec7d367dbbc0198e3e0e55ddadbc4a650eeb2 Mon Sep 17 00:00:00 2001 From: Nell Hardcastle Date: Mon, 30 Mar 2026 12:22:52 -0700 Subject: [PATCH 1/3] fix(server): Return mock user info for reviewers to prevent logout --- .../src/graphql/resolvers/user.ts | 49 ++++++++++++++++++- 1 file changed, 48 insertions(+), 1 deletion(-) diff --git a/packages/openneuro-server/src/graphql/resolvers/user.ts b/packages/openneuro-server/src/graphql/resolvers/user.ts index 3eee77b27c..3774ce2904 100644 --- a/packages/openneuro-server/src/graphql/resolvers/user.ts +++ b/packages/openneuro-server/src/graphql/resolvers/user.ts @@ -7,11 +7,53 @@ function isValidOrcid(orcid: string): boolean { return /^[0-9]{4}-[0-9]{4}-[0-9]{4}-[0-9]{3}[0-9X]$/.test(orcid || "") } +// TODO - Use GraphQL codegen +type GraphQLUserType = { + id: string + provider: "orcid" | "google" + avatar: string + orcid: string + created: Date + modified: Date + lastSeen: Date + email: string + name: string + admin: boolean + blocked: boolean + location: string + institution: string + github: string + githubSynced: Date + links: [string] + notifications: [Record] + orcidConsent: boolean +} + export async function user( obj, { id }, { userInfo }: { userInfo?: Record } = {}, -) { +): Promise | null> { + if (userInfo.reviewer) { + const oneWeekAgo = new Date() + oneWeekAgo.setDate(oneWeekAgo.getDate() - 7) + return { + id: "reviewer", + name: "Anonymous Reviewer", + email: "reviewer@openneuro.org", + provider: "orcid", + orcid: "0000-0000-0000-0000", + admin: false, + blocked: false, + location: "", + institution: "", + orcidConsent: true, + created: oneWeekAgo, + lastSeen: new Date(), + modified: oneWeekAgo, + } + } + let user if (isValidOrcid(id)) { user = await User.findOne({ @@ -226,6 +268,11 @@ export const updateUser = async ( export async function notifications(obj, _, { userInfo }) { const userId = obj.id + // Reviewers never have notifications + if (userInfo.reviewer) { + return [] + } + // --- authorization --- if (!userInfo || (userInfo.id !== userId && !userInfo.admin)) { throw new Error("Not authorized to view these notifications.") From 082753dd605e21fafe4f2dbdbb2fd0ed26296bfd Mon Sep 17 00:00:00 2001 From: Nell Hardcastle Date: Mon, 30 Mar 2026 12:24:25 -0700 Subject: [PATCH 2/3] fix(app): Prevent reviewers from accidentally requesting contributor access --- .../src/scripts/dataset/snapshot-container.tsx | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/packages/openneuro-app/src/scripts/dataset/snapshot-container.tsx b/packages/openneuro-app/src/scripts/dataset/snapshot-container.tsx index afa2ebb716..6251c8d9dd 100644 --- a/packages/openneuro-app/src/scripts/dataset/snapshot-container.tsx +++ b/packages/openneuro-app/src/scripts/dataset/snapshot-container.tsx @@ -185,12 +185,13 @@ export const SnapshotContainer: React.FC = ({ heading="Authors" item={ <> - {profile && ( - - )} + {profile && !profile.scopes.includes("dataset:reviewer") && + ( + + )} Date: Mon, 30 Mar 2026 12:33:44 -0700 Subject: [PATCH 3/3] fix(app): Hide user menu actions for reviewer users --- .../src/scripts/users/user-menu.tsx | 72 +++++++++++-------- 1 file changed, 43 insertions(+), 29 deletions(-) diff --git a/packages/openneuro-app/src/scripts/users/user-menu.tsx b/packages/openneuro-app/src/scripts/users/user-menu.tsx index a71f317e75..0c6ab199ab 100644 --- a/packages/openneuro-app/src/scripts/users/user-menu.tsx +++ b/packages/openneuro-app/src/scripts/users/user-menu.tsx @@ -5,6 +5,46 @@ import { useUser } from "../queries/user" import { useNotifications } from "./notifications/user-notifications-context" import "./scss/user-menu.scss" +interface UserMenuListProps { + user: NonNullable["user"]> +} + +function UserMenuList({ user }: UserMenuListProps) { + return ( + <> +
  • + + My Datasets + +
  • + + {user.orcid && ( +
  • + Account Info +
  • + )} + +
  • + Obtain an API Key +
  • + + {user.provider !== "orcid" && ( +
  • + Link ORCID to my account +
  • + )} + + {user.admin && ( +
  • + Admin +
  • + )} + + ) +} + export interface UserMenuProps { signOutAndRedirect: () => void } @@ -15,6 +55,8 @@ export const UserMenu: React.FC = ({ signOutAndRedirect }) => { if (loading || !user) return null + const reviewer = user.id === "reviewer" + const inboxCount = notifications?.filter((n) => n.status === "unread").length || 0 @@ -66,35 +108,7 @@ export const UserMenu: React.FC = ({ signOutAndRedirect }) => {

    -
  • - - My Datasets - -
  • - - {user.orcid && ( -
  • - Account Info -
  • - )} - -
  • - Obtain an API Key -
  • - - {user.provider !== "orcid" && ( -
  • - Link ORCID to my account -
  • - )} - - {user.admin && ( -
  • - Admin -
  • - )} + {!reviewer && }