diff --git a/src/actions/mail/read.ts b/src/actions/mail/read.ts index 0e9303951..e59fa1980 100644 --- a/src/actions/mail/read.ts +++ b/src/actions/mail/read.ts @@ -7,7 +7,7 @@ import { readMailAliases } from '@/services/mail/alias/read' import { readMailingLists } from '@/services/mail/list/read' import { readMailAddressExternal } from '@/services/mail/mailAddressExternal/read' import { getUser } from '@/auth/getUser' -import type { UserFiltered } from '@/services/users/Types' +import type { UserContactInfoFiltered } from '@/services/users/Types' import type { MailListTypes } from '@/services/mail/Types' import type { MailingList, MailAlias, MailAddressExternal } from '@prisma/client' import type { ActionReturn } from '@/actions/Types' @@ -35,7 +35,7 @@ export async function readMailOptions(): Promise> { const { authorized, status } = await getUser({ requiredPermissions: [ diff --git a/src/app/(auth)/register-email/EmailregistrationForm.tsx b/src/app/(auth)/register-email/EmailregistrationForm.tsx index d250fc39c..99d6dfd7a 100644 --- a/src/app/(auth)/register-email/EmailregistrationForm.tsx +++ b/src/app/(auth)/register-email/EmailregistrationForm.tsx @@ -4,12 +4,12 @@ import Form from '@/components/Form/Form' import TextInput from '@/components/UI/TextInput' import { useSearchParams, useRouter } from 'next/navigation' import { useState } from 'react' -import type { UserFiltered } from '@/services/users/Types' +import type { UserContactInfoFiltered } from '@/services/users/Types' export default function EmailRegistrationForm({ - user + user, }: { - user: UserFiltered + user: UserContactInfoFiltered, }) { const searchParams = useSearchParams() const callbackUrl = searchParams.get('callbackUrl') || '/users/me' diff --git a/src/app/admin/mail/[filter]/[id]/MailFlow.tsx b/src/app/admin/mail/[filter]/[id]/MailFlow.tsx index ef2de79ec..c2ea0f0e3 100644 --- a/src/app/admin/mail/[filter]/[id]/MailFlow.tsx +++ b/src/app/admin/mail/[filter]/[id]/MailFlow.tsx @@ -14,7 +14,7 @@ import type { MailFlowObject, MailListTypes } from '@/services/mail/Types' type DestroyFunction = null | ((id: number) => Promise>) -export default async function MailFlow({ +export default function MailFlow({ filter, id, data, diff --git a/src/app/admin/mail/[filter]/[id]/mailList.tsx b/src/app/admin/mail/[filter]/[id]/mailList.tsx index bf3b48b35..125c43718 100644 --- a/src/app/admin/mail/[filter]/[id]/mailList.tsx +++ b/src/app/admin/mail/[filter]/[id]/mailList.tsx @@ -8,7 +8,7 @@ import { useState } from 'react' import type { ActionReturn } from '@/actions/Types' import type { MailListTypes, ViaArrayType } from '@/services/mail/Types' import type { Group, MailAddressExternal, MailAlias, MailingList } from '@prisma/client' -import type { UserFiltered } from '@/services/users/Types' +import type { UserNameFiltered } from '@/services/users/Types' const typeDisplayName: Record = { alias: 'Alias', @@ -22,7 +22,7 @@ type TypeConversion = { alias: (MailAlias & ViaArrayType), mailingList: (MailingList & ViaArrayType), group: (Group & ViaArrayType), - user: (UserFiltered & ViaArrayType), + user: (UserNameFiltered & ViaArrayType), mailaddressExternal: (MailAddressExternal & ViaArrayType), } diff --git a/src/app/layout.tsx b/src/app/layout.tsx index 767702d72..622b5f997 100644 --- a/src/app/layout.tsx +++ b/src/app/layout.tsx @@ -1,4 +1,5 @@ import styles from './layout.module.scss' +import { unwrapActionReturn } from './redirectToErrorPage' import { SessionProvider } from '@/auth/useUser' import MobileNavBar from '@/components/NavBar/MobileNavBar' import NavBar from '@/components/NavBar/NavBar' @@ -8,14 +9,13 @@ import EditModeProvider from '@/contexts/EditMode' import PopUpProvider from '@/contexts/PopUp' import DefaultPermissionsProvider from '@/contexts/DefaultPermissions' import { readDefaultPermissionsAction } from '@/actions/permissionRoles/read' +import { readUserProfileAction } from '@/actions/users/read' import { Inter } from 'next/font/google' import '@/styles/globals.scss' import { config } from '@fortawesome/fontawesome-svg-core' import '@fortawesome/fontawesome-svg-core/styles.css' import { getServerSession } from 'next-auth' import type { ReactNode } from 'react' -import { readUserProfileAction } from '@/actions/users/read' -import { unwrapActionReturn } from './redirectToErrorPage' config.autoAddCss = false @@ -24,7 +24,6 @@ const inter = Inter({ subsets: ['latin'] }) export const metadata = { title: 'projectnext', description: '', - charset: 'utf-8', } type PropTypes = { diff --git a/src/app/users/[username]/(user-admin)/notifications/notificationSettings.tsx b/src/app/users/[username]/(user-admin)/notifications/notificationSettings.tsx index a567cb87b..806da5b9f 100644 --- a/src/app/users/[username]/(user-admin)/notifications/notificationSettings.tsx +++ b/src/app/users/[username]/(user-admin)/notifications/notificationSettings.tsx @@ -10,7 +10,7 @@ import { updateSubscriptionsAction } from '@/actions/notifications/subscription/ import { SUCCESS_FEEDBACK_TIME } from '@/components/Form/ConfigVars' import { v4 as uuid } from 'uuid' import { useState } from 'react' -import type { UserFiltered } from '@/services/users/Types' +import type { UserNameFiltered } from '@/services/users/Types' import type { MinimizedSubscription, Subscription } from '@/services/notifications/subscription/Types' import type { NotificationBranch } from './Types' import type { ErrorMessage } from '@/services/error' @@ -131,17 +131,16 @@ function prepareDataForDelivery(tree: NotificationBranch) { return ret } -type PropTypes = { - channels: ExpandedNotificationChannel[], - subscriptions: Subscription[], - user: UserFiltered -} export default function NotificationSettings({ channels, subscriptions, - user -}: PropTypes) { + user, +}: { + channels: ExpandedNotificationChannel[], + subscriptions: Subscription[], + user: UserNameFiltered, +}) { const [channelTree, setChannelTree] = useState( generateChannelTree(channels, subscriptions) ) diff --git a/src/auth/Session.ts b/src/auth/Session.ts index a53d009b6..d403d738e 100644 --- a/src/auth/Session.ts +++ b/src/auth/Session.ts @@ -6,13 +6,13 @@ import { decodeApiKey } from '@/services/api-keys/apiKeyEncoder' import { ServerError } from '@/services/error' import { getServerSession as getSessionNextAuth } from 'next-auth' import type { Permission } from '@prisma/client' -import type { UserFiltered } from '@/services/users/Types' +import type { UserAuthFiltered } from '@/services/users/Types' import type { MembershipFiltered } from '@/services/groups/memberships/Types' export type UserGuaranteeOption = 'HAS_USER' | 'NO_USER' export type SessionType = { - user: UserGuarantee extends 'HAS_USER' ? UserFiltered : ( + user: UserGuarantee extends 'HAS_USER' ? UserAuthFiltered : ( UserGuarantee extends 'NO_USER' ? null : never ), permissions: Permission[], diff --git a/src/auth/VevenAdapter.ts b/src/auth/VevenAdapter.ts index 0f88fc769..9bab2ae61 100644 --- a/src/auth/VevenAdapter.ts +++ b/src/auth/VevenAdapter.ts @@ -4,7 +4,7 @@ import { createFeideAccount } from '@/services/auth/feideAccounts/create' import { readUserOrNullOfFeideAccount } from '@/services/auth/feideAccounts/read' import { UserMethods } from '@/services/users/methods' import { UserConfig } from '@/services/users/config' -import type { UserFiltered } from '@/services/users/Types' +import type { UserAuthFiltered } from '@/services/users/Types' import type { PrismaClient } from '@prisma/client' import type { Adapter, AdapterUser, AdapterAccount } from 'next-auth/adapters' @@ -15,7 +15,7 @@ import type { Adapter, AdapterUser, AdapterAccount } from 'next-auth/adapters' * @param user - User of the type used in veven. * @returns User object of the type `AdapterUser`. */ -function convertToAdapterUser(user: UserFiltered): AdapterUser { +function convertToAdapterUser(user: UserAuthFiltered): AdapterUser { return { ...user, id: String(user.id), @@ -96,7 +96,7 @@ export default function VevenAdapter(prisma: PrismaClient): Adapter { username, emailVerified: null, }, - select: UserConfig.filterSelection, + select: UserConfig.filterAuthSelection, }) return convertToAdapterUser(createdUser) @@ -133,7 +133,7 @@ export default function VevenAdapter(prisma: PrismaClient): Adapter { }, include: { user: { - select: UserConfig.filterSelection, + select: UserConfig.filterAuthSelection, }, }, }) @@ -165,7 +165,7 @@ export default function VevenAdapter(prisma: PrismaClient): Adapter { firstname: user.firstname, lastname: user.lastname, }, - select: UserConfig.filterSelection, + select: UserConfig.filterAuthSelection, }) return convertToAdapterUser(updatedUser) diff --git a/src/auth/getUser.ts b/src/auth/getUser.ts index 75f07c293..46d39d067 100644 --- a/src/auth/getUser.ts +++ b/src/auth/getUser.ts @@ -7,7 +7,7 @@ import { notFound, redirect } from 'next/navigation' import type { Matrix } from '@/utils/checkMatrix' import type { Permission } from '@prisma/client' import type { MembershipFiltered } from '@/services/groups/memberships/Types' -import type { UserFiltered } from '@/services/users/Types' +import type { UserAuthFiltered } from '@/services/users/Types' type GetUserArgsType = { requiredPermissions?: Matrix, @@ -18,7 +18,7 @@ type GetUserArgsType = ({ - user: UserFiltered, + user: UserAuthFiltered, status: 'AUTHORIZED', } | ( UserRequired extends true ? never : { @@ -35,7 +35,7 @@ type UnAuthorizedGetUserReturnType = ({ user: null, status: 'UNAUTHENTICATED', } | { - user: UserFiltered, + user: UserAuthFiltered, status: 'UNAUTHORIZED', }) & { authorized: false, diff --git a/src/auth/useUser.ts b/src/auth/useUser.ts index 130c2254b..bdc2ac5ed 100644 --- a/src/auth/useUser.ts +++ b/src/auth/useUser.ts @@ -6,7 +6,7 @@ import { useSession } from 'next-auth/react' import { usePathname, useRouter } from 'next/navigation' import { useContext, useEffect, useState } from 'react' import type { Permission } from '@prisma/client' -import type { UserFiltered } from '@/services/users/Types' +import type { UserAuthFiltered } from '@/services/users/Types' import type { Matrix } from '@/utils/checkMatrix' import type { MembershipFiltered } from '@/services/groups/memberships/Types' @@ -23,7 +23,7 @@ type UseUserArgsType = ({ - user: UserFiltered, + user: UserAuthFiltered, authorized: true, status: 'AUTHORIZED', } | ( @@ -50,7 +50,7 @@ type UseUserReturnType = ( authorized: false, status: 'UNAUTHENTICATED', } | { - user: UserFiltered, + user: UserAuthFiltered, authorized: false, status: 'UNAUTHORIZED', }) & { diff --git a/src/contexts/UserSelection.tsx b/src/contexts/UserSelection.tsx index 340224d7f..4236e150b 100644 --- a/src/contexts/UserSelection.tsx +++ b/src/contexts/UserSelection.tsx @@ -1,11 +1,11 @@ 'use client' import { createContext, useEffect, useRef, useState } from 'react' import type { ReactNode } from 'react' -import type { UserFiltered } from '@/services/users/Types' +import type { UserNameFiltered } from '@/services/users/Types' type PropTypes = { children: ReactNode - initialUser?: UserFiltered | null + initialUser?: UserNameFiltered | null } /** @@ -13,15 +13,15 @@ type PropTypes = { * If UserList is rendered inside IserSelectionProvider, it will display a checkbox next to each user. */ export const UserSelectionContext = createContext<{ - user: UserFiltered | null - setUser: (user: UserFiltered | null) => void - onSelection: (handler: (user: UserFiltered | null) => void) => void + user: UserNameFiltered | null + setUser: (user: UserNameFiltered | null) => void + onSelection: (handler: (user: UserNameFiltered | null) => void) => void } | null>(null) -type Handler = (user: UserFiltered | null) => void +type Handler = (user: UserNameFiltered | null) => void export default function UserSelectionProvider({ children, initialUser }: PropTypes) { - const [user, setUser] = useState(initialUser ? initialUser : null) + const [user, setUser] = useState(initialUser ? initialUser : null) const onSelection = useRef(() => {}) useEffect(() => { onSelection.current(user) diff --git a/src/contexts/UsersSelection.tsx b/src/contexts/UsersSelection.tsx index 6b72eda46..d54f47b93 100644 --- a/src/contexts/UsersSelection.tsx +++ b/src/contexts/UsersSelection.tsx @@ -2,7 +2,7 @@ import { createContext, useState } from 'react' import type { ReactNode } from 'react' -import type { UserFiltered } from '@/services/users/Types' +import type { UserNameFiltered } from '@/services/users/Types' type PropTypes = { children: ReactNode @@ -13,23 +13,23 @@ type PropTypes = { * If UserList is rendered inside IserSelectionProvider, it will display a checkbox next to each user. */ export const UsersSelectionContext = createContext<{ - users: UserFiltered[] - addUser: (user: UserFiltered) => void - removeUser: (user: UserFiltered) => void - toggle: (user: UserFiltered) => void - includes: (user: UserFiltered) => boolean + users: UserNameFiltered[] + addUser: (user: UserNameFiltered) => void + removeUser: (user: UserNameFiltered) => void + toggle: (user: UserNameFiltered) => void + includes: (user: UserNameFiltered) => boolean } | null>(null) export default function UsesrSelectionProvider({ children }: PropTypes) { - const [users, setUsers] = useState([]) + const [users, setUsers] = useState([]) - const addUser = (user: UserFiltered) => { + const addUser = (user: UserNameFiltered) => { setUsers([...users, user]) } - const removeUser = (user: UserFiltered) => { + const removeUser = (user: UserNameFiltered) => { setUsers(users.filter(u => u !== user)) } - const toggle = (user: UserFiltered) => { + const toggle = (user: UserNameFiltered) => { if (users.includes(user)) { removeUser(user) } else { @@ -37,7 +37,7 @@ export default function UsesrSelectionProvider({ children }: PropTypes) { } } - const includes = (user: UserFiltered) => users.includes(user) + const includes = (user: UserNameFiltered) => users.includes(user) return {children} diff --git a/src/services/admission/Types.ts b/src/services/admission/Types.ts index c245088ce..d84fcc6de 100644 --- a/src/services/admission/Types.ts +++ b/src/services/admission/Types.ts @@ -1,6 +1,6 @@ import type { AdmissionTrial } from '@prisma/client' -import type { UserFiltered } from '@/services/users/Types' +import type { UserNameFiltered } from '@/services/users/Types' export type ExpandedAdmissionTrail = AdmissionTrial & { - user: UserFiltered + user: UserNameFiltered } diff --git a/src/services/admission/methods.ts b/src/services/admission/methods.ts index 4f5fb6893..2d04699cc 100644 --- a/src/services/admission/methods.ts +++ b/src/services/admission/methods.ts @@ -43,7 +43,7 @@ export namespace AdmissionMethods { }, include: { user: { - select: UserConfig.filterSelection + select: UserConfig.filterNameSelection, } } }) diff --git a/src/services/auth/methods.ts b/src/services/auth/methods.ts index 85459bb12..cbb45e202 100644 --- a/src/services/auth/methods.ts +++ b/src/services/auth/methods.ts @@ -49,7 +49,7 @@ export namespace AuthMethods { emailVerified: new Date(), email, }, - select: UserConfig.filterSelection + select: UserConfig.filterAuthSelection, }) } }) diff --git a/src/services/mail/Types.ts b/src/services/mail/Types.ts index b0ecc84c2..3cba1ee9a 100644 --- a/src/services/mail/Types.ts +++ b/src/services/mail/Types.ts @@ -1,6 +1,6 @@ import type { Group, MailAddressExternal, MailAlias, MailingList } from '@prisma/client' -import type { UserFiltered } from '@/services/users/Types' +import type { UserNameFiltered } from '@/services/users/Types' export const MailListTypeArray = ['alias', 'mailingList', 'group', 'user', 'mailaddressExternal'] as const @@ -20,6 +20,6 @@ export type MailFlowObject = { alias: MailAlias[] & ViaArrayType, mailingList: MailingList[] & ViaArrayType, group: Group[] & ViaArrayType, - user: UserFiltered[] & ViaArrayType, + user: UserNameFiltered[] & ViaArrayType, mailaddressExternal: MailAddressExternal[] & ViaArrayType, } diff --git a/src/services/mail/read.ts b/src/services/mail/read.ts index 7e14ce38c..e0b625ec1 100644 --- a/src/services/mail/read.ts +++ b/src/services/mail/read.ts @@ -5,6 +5,7 @@ import prisma from '@/prisma' import { UserConfig } from '@/services/users/config' import type { MailFlowObject, MailListTypes, ViaArrayType, ViaType } from './Types' +const userFilter = UserConfig.filterNameSelection /** * This file reads how incomming mail is routed. @@ -89,7 +90,7 @@ async function readAliasTraversal(id: number): Promise { // TODO: only find valid memberships include: { user: { - select: UserConfig.filterSelection, + select: userFilter, } } } @@ -100,7 +101,7 @@ async function readAliasTraversal(id: number): Promise { users: { include: { user: { - select: UserConfig.filterSelection, + select: userFilter, }, }, }, @@ -220,7 +221,7 @@ async function readMailingListTraversal(id: number): Promise { },*/ include: { user: { - select: UserConfig.filterSelection, + select: userFilter, } } } @@ -231,7 +232,7 @@ async function readMailingListTraversal(id: number): Promise { users: { include: { user: { - select: UserConfig.filterSelection, + select: userFilter, }, }, }, @@ -355,7 +356,7 @@ async function readGroupTraversal(id: number): Promise { memberships: { include: { user: { - select: UserConfig.filterSelection, + select: userFilter, } } }, @@ -419,7 +420,8 @@ async function readUserTraversal(id: number): Promise { where: { id, }, - include: { + select: { + ...userFilter, mailingLists: { include: { mailingList: { diff --git a/src/services/notifications/create.ts b/src/services/notifications/create.ts index 89dfc9bde..b62c6482d 100644 --- a/src/services/notifications/create.ts +++ b/src/services/notifications/create.ts @@ -77,7 +77,7 @@ export async function dispatchNotification(data: CreateNotificationType['Detaile select: allMethodsOn, }, user: { - select: UserConfig.filterSelection, + select: UserConfig.filterContactInfoSelection, }, }, }, diff --git a/src/services/notifications/dispatch.ts b/src/services/notifications/dispatch.ts index 89b754ac2..f2f0b380e 100644 --- a/src/services/notifications/dispatch.ts +++ b/src/services/notifications/dispatch.ts @@ -1,6 +1,6 @@ import { dispatchEmailNotifications } from './email/dispatch' import { dispatchPushNotifications } from './push/dispath' -import type { UserFiltered } from '@/services/users/Types' +import type { UserContactInfoFiltered, UserNameFiltered } from '@/services/users/Types' import type { Notification } from '@prisma/client' import type { ExpandedNotificationChannel, notificationMethods } from './Types' @@ -11,10 +11,10 @@ export const dispathMethod = { push: dispatchPushNotifications, } satisfies Record< typeof notificationMethods[number], - ((channel: ExpandedNotificationChannel, notification: Notification, users: UserFiltered[]) => Promise) + ((channel: ExpandedNotificationChannel, notification: Notification, users: UserContactInfoFiltered[]) => Promise) > -export function repalceSpecialSymbols(text: string, user: UserFiltered) { +export function repalceSpecialSymbols(text: string, user: UserNameFiltered) { return text .replaceAll('%u', user.username) .replaceAll('%n', user.firstname) diff --git a/src/services/notifications/email/dispatch.tsx b/src/services/notifications/email/dispatch.tsx index cd1de89e6..ba4edb433 100644 --- a/src/services/notifications/email/dispatch.tsx +++ b/src/services/notifications/email/dispatch.tsx @@ -8,13 +8,13 @@ import prisma from '@/prisma' import { render } from '@react-email/render' import type { ExpandedNotificationChannel } from '@/services/notifications/Types' import type { Notification } from '@prisma/client' -import type { UserFiltered } from '@/services/users/Types' +import type { UserContactInfoFiltered } from '@/services/users/Types' export async function dispatchEmailNotifications( channel: ExpandedNotificationChannel, notificaion: Notification, - users: UserFiltered[] + users: UserContactInfoFiltered[] ) { console.log('Email') @@ -62,6 +62,6 @@ export async function dispatchEmailNotifications( await sendBulkMail(mails) } -async function wrapInHTML(user: UserFiltered, text: string): Promise { +async function wrapInHTML(user: UserContactInfoFiltered, text: string): Promise { return render() } diff --git a/src/services/notifications/email/systemMail/userInvitivation.tsx b/src/services/notifications/email/systemMail/userInvitivation.tsx index 4942b3472..701b9aee9 100644 --- a/src/services/notifications/email/systemMail/userInvitivation.tsx +++ b/src/services/notifications/email/systemMail/userInvitivation.tsx @@ -1,12 +1,11 @@ -import { generateJWT } from '@/jwt/jwt' -import type { UserFiltered } from '@/services/users/Types' import 'server-only' import { userInvitationExpiration } from './ConfigVars' +import { generateJWT } from '@/jwt/jwt' import { sendSystemMail } from '@/services/notifications/email/send' import { UserInvitationTemplate } from '@/services/notifications/email/templates/userInvitation' +import type { UserContactInfoFiltered } from '@/services/users/Types' - -export async function sendUserInvitationEmail(user: UserFiltered) { +export async function sendUserInvitationEmail(user: UserContactInfoFiltered) { const jwt = generateJWT('verifyemail', { sub: user.id, email: user.email, diff --git a/src/services/notifications/email/systemMail/verifyEmail.tsx b/src/services/notifications/email/systemMail/verifyEmail.tsx index ae729018b..f25b8019d 100644 --- a/src/services/notifications/email/systemMail/verifyEmail.tsx +++ b/src/services/notifications/email/systemMail/verifyEmail.tsx @@ -4,10 +4,10 @@ import { VerifyEmailTemplate } from '@/services/notifications/email/templates/ve import { sendSystemMail } from '@/services/notifications/email/send' import { generateJWT } from '@/jwt/jwt' import { UserSchemas } from '@/services/users/schemas' -import type { UserFiltered } from '@/services/users/Types' +import type { UserContactInfoFiltered } from '@/services/users/Types' // TODO: Fix this with new validation -export async function sendVerifyEmail(user: UserFiltered, email: string) { +export async function sendVerifyEmail(user: UserContactInfoFiltered, email: string) { const parse = UserSchemas.verifyEmail.parse({ email }) const jwt = generateJWT('verifyemail', { diff --git a/src/services/notifications/email/templates/default.tsx b/src/services/notifications/email/templates/default.tsx index 179a78022..705d479b2 100644 --- a/src/services/notifications/email/templates/default.tsx +++ b/src/services/notifications/email/templates/default.tsx @@ -1,12 +1,12 @@ import 'server-only' import { Html, Markdown } from '@react-email/components' -import type { UserFiltered } from '@/services/users/Types' +import type { UserContactInfoFiltered } from '@/services/users/Types' export function DefaultEmailTemplate({ text, }: { - user: UserFiltered, + user: UserContactInfoFiltered, text: string, }) { return ( diff --git a/src/services/notifications/email/templates/resetPassword.tsx b/src/services/notifications/email/templates/resetPassword.tsx index 998e8bcf1..49f75ba66 100644 --- a/src/services/notifications/email/templates/resetPassword.tsx +++ b/src/services/notifications/email/templates/resetPassword.tsx @@ -1,13 +1,13 @@ import 'server-only' import { Html } from '@react-email/components' -import type { UserFiltered } from '@/services/users/Types' +import type { UserNameFiltered } from '@/services/users/Types' export function ResetPasswordTemplate({ user, link, }: { - user: UserFiltered, + user: UserNameFiltered, link: string, }) { return ( diff --git a/src/services/notifications/email/templates/userInvitation.tsx b/src/services/notifications/email/templates/userInvitation.tsx index 8279f8779..a9ee51d86 100644 --- a/src/services/notifications/email/templates/userInvitation.tsx +++ b/src/services/notifications/email/templates/userInvitation.tsx @@ -1,13 +1,13 @@ import 'server-only' import { Html } from '@react-email/components' -import type { UserFiltered } from '@/services/users/Types' +import type { UserNameFiltered } from '@/services/users/Types' export function UserInvitationTemplate({ user, link, }: { - user: UserFiltered, + user: UserNameFiltered, link: string, }) { return ( diff --git a/src/services/notifications/email/templates/verifyEmail.tsx b/src/services/notifications/email/templates/verifyEmail.tsx index 18bed021f..9ea1ee1e0 100644 --- a/src/services/notifications/email/templates/verifyEmail.tsx +++ b/src/services/notifications/email/templates/verifyEmail.tsx @@ -1,13 +1,13 @@ import 'server-only' import { Html } from '@react-email/components' -import type { UserFiltered } from '@/services/users/Types' +import type { UserContactInfoFiltered } from '@/services/users/Types' export function VerifyEmailTemplate({ user, link, }: { - user: UserFiltered, + user: UserContactInfoFiltered, link: string, }) { return ( diff --git a/src/services/notifications/push/dispath.ts b/src/services/notifications/push/dispath.ts index c1283c86f..89a6f53a6 100644 --- a/src/services/notifications/push/dispath.ts +++ b/src/services/notifications/push/dispath.ts @@ -1,12 +1,12 @@ import type { ExpandedNotificationChannel } from '@/services/notifications/Types' -import type { UserFiltered } from '@/services/users/Types' +import type { UserContactInfoFiltered } from '@/services/users/Types' import type { Notification } from '@prisma/client' export async function dispatchPushNotifications( channel: ExpandedNotificationChannel, notificaion: Notification, - users: UserFiltered[] + users: UserContactInfoFiltered[] ) { console.log('Push') diff --git a/src/services/omegaid/Types.ts b/src/services/omegaid/Types.ts index 3d82cbe70..7fd132e54 100644 --- a/src/services/omegaid/Types.ts +++ b/src/services/omegaid/Types.ts @@ -1,9 +1,10 @@ -import type { UserFiltered } from '@/services/users/Types' -export type OmegaId = Pick +export type OmegaId = { + id: number +} export type OmegaIdJWT = { iat: number, exp: number, - sub: UserFiltered['id'], + sub: OmegaId['id'], } diff --git a/src/services/shop/purchase/methods.ts b/src/services/shop/purchase/methods.ts index 87d67c58b..10afb8d9c 100644 --- a/src/services/shop/purchase/methods.ts +++ b/src/services/shop/purchase/methods.ts @@ -41,7 +41,7 @@ export namespace PurchaseMethods { where: { studentCard: data.studentCard, }, - select: UserConfig.filterSelection + select: UserConfig.filterNameSelection, }) // Find the price of the different products diff --git a/src/services/users/Types.ts b/src/services/users/Types.ts index 24459dfde..8143dc8ee 100644 --- a/src/services/users/Types.ts +++ b/src/services/users/Types.ts @@ -1,8 +1,22 @@ import type { MembershipFiltered } from '@/services/groups/memberships/Types' import type { UserConfig } from './config' -import type { OmegaMembershipLevel, User, Image, Permission } from '@prisma/client' +import type { Image, OmegaMembershipLevel, Permission, Prisma } from '@prisma/client' -export type UserFiltered = Pick +export type UserNameFiltered = Prisma.UserGetPayload<{ + select: typeof UserConfig.filterNameSelection +}> +export type UserContactInfoFiltered = Prisma.UserGetPayload<{ + select: typeof UserConfig.filterContactInfoSelection +}> +export type UserProfileFiltered = Prisma.UserGetPayload<{ + select: typeof UserConfig.filterProfileSelection +}> +export type UserAuthFiltered = Prisma.UserGetPayload<{ + select: typeof UserConfig.filterAuthSelection +}> +export type UserAllFiltered = Prisma.UserGetPayload<{ + select: typeof UserConfig.filterAllSelection +}> export type StandardMembeships = { class?: number @@ -10,7 +24,7 @@ export type StandardMembeships = { membershipType?: OmegaMembershipLevel } -export type UserPagingReturn = UserFiltered & StandardMembeships & { +export type UserPagingReturn = UserNameFiltered & StandardMembeships & { selectedGroupInfo?: { title?: string admin?: boolean @@ -45,7 +59,7 @@ export type UserCursor = { } export type Profile = { - user: UserFiltered & { image: Image, bio: string }, + user: Omit & { image: Image }, memberships: MembershipFiltered[], permissions: Permission[], } diff --git a/src/services/users/config.ts b/src/services/users/config.ts index 2fdcd0d31..bd2955f00 100644 --- a/src/services/users/config.ts +++ b/src/services/users/config.ts @@ -5,8 +5,43 @@ export namespace UserConfig { export const maxNumberOfGroupsInFilter = 7 export const studentCardRegistrationExpiry = 2 // minutter - // TODO: This needs to be divived into seperate filters, depending on how much information is needed - export const fieldsToExpose = [ + export const exposeName = [ + 'id', + 'username', + 'firstname', + 'lastname' + ] as const satisfies (keyof User)[] + export const filterNameSelection = createSelection([...exposeName]) + + export const exposeContactInfo = [ + ...exposeName, + 'email', + 'mobile', + ] as const satisfies (keyof User)[] + export const filterContactInfoSelection = createSelection([...exposeContactInfo]) + + export const exposeProfile = [ + ...exposeContactInfo, + 'sex', + 'bio', + 'imageId', + ] as const satisfies (keyof User)[] + export const filterProfileSelection = { + ...createSelection([...exposeProfile]), + image: true, + } as const + + // The auth is what is exposed to the user in the session + export const exposeAuth = [ + ...exposeContactInfo, + 'sex', + 'emailVerified', + 'acceptedTerms', + 'updatedAt', + ] as const satisfies (keyof User)[] + export const filterAuthSelection = createSelection([...exposeAuth]) + + export const exposeAll = [ 'id', 'username', 'firstname', @@ -19,9 +54,10 @@ export namespace UserConfig { 'acceptedTerms', 'sex', 'allergies', + 'imageId', + 'studentCard', ] as const satisfies (keyof User)[] - - export const filterSelection = createSelection([...fieldsToExpose]) + export const filterAllSelection = createSelection([...exposeAll]) export const standardMembershipSelection = [ { diff --git a/src/services/users/methods.ts b/src/services/users/methods.ts index bba7c4abd..571eba742 100644 --- a/src/services/users/methods.ts +++ b/src/services/users/methods.ts @@ -69,7 +69,7 @@ export namespace UserMethods { id: params.id, ...params }, - select: UserConfig.filterSelection + select: UserConfig.filterAllSelection, // TODO: This should maybe not need all the fields }) }) @@ -86,7 +86,7 @@ export namespace UserMethods { id: params.id, // This is a bit wierd, but now ts is satisfied. ...params }, - select: UserConfig.filterSelection + select: UserConfig.filterAllSelection, // TODO: This should maybe not need all the fields }) }) @@ -103,13 +103,11 @@ export namespace UserMethods { const user = await prisma.user.findUniqueOrThrow({ where: { username: params.username.toLowerCase() }, select: { - ...UserConfig.filterSelection, - bio: true, - image: true, + ...UserConfig.filterProfileSelection, }, }).then(async u => ({ ...u, - image: u.image || defaultProfileImage, + image: u.image ? u.image : defaultProfileImage, })) const memberships = await readMembershipsOfUser(user.id) @@ -154,7 +152,7 @@ export namespace UserMethods { const users = await prisma.user.findMany({ ...cursorPageingSelection(page), select: { - ...UserConfig.filterSelection, + ...UserConfig.filterNameSelection, memberships: { select: { admin: true, @@ -282,7 +280,7 @@ export namespace UserMethods { data: { studentCard: data.studentCard, }, - select: UserConfig.filterSelection, + select: UserConfig.filterNameSelection, }) ]) @@ -322,7 +320,8 @@ export namespace UserMethods { auther: () => UserAuthers.update.dynamicFields({}), method: async ({ prisma: prisma_, params, data }) => prisma_.user.update({ where: params, - data + data, + select: UserConfig.filterNameSelection, }) }) @@ -361,7 +360,7 @@ export namespace UserMethods { id: params.id, }, select: { - ...UserConfig.filterSelection, + ...UserConfig.filterAuthSelection, feideAccount: { select: { email: true, @@ -430,14 +429,12 @@ export namespace UserMethods { id: params.id, }, select: { - acceptedTerms: true, - email: true, + ...UserConfig.filterAuthSelection, feideAccount: { select: { email: true, }, }, - emailVerified: true, memberships: { select: { group: { @@ -471,7 +468,7 @@ export namespace UserMethods { mobile, allergies, }, - select: UserConfig.filterSelection + select: UserConfig.filterAuthSelection, }), prisma.credentials.upsert({ where: { @@ -526,9 +523,7 @@ export namespace UserMethods { method: async ({ prisma: prisma_, params }) => { const user = await prisma_.user.findFirstOrThrow({ where: params, - include: { - image: true, - } + include: UserConfig.filterProfileSelection, }) return { @@ -551,7 +546,8 @@ export namespace UserMethods { await prisma.user.delete({ where: { id: params.id, - } + }, + select: UserConfig.filterContactInfoSelection, }) } }) diff --git a/src/typings/next-auth.d.ts b/src/typings/next-auth.d.ts index 424f9088a..f6b1d4aae 100644 --- a/src/typings/next-auth.d.ts +++ b/src/typings/next-auth.d.ts @@ -3,19 +3,19 @@ import 'next-auth/adapters' import type { MembershipFiltered } from '@/services/groups/Types' import type { Permission } from '@prisma/client' -import type { UserFiltered } from '@/services/users/Types' +import type { UserAuthFiltered } from '@/services/users/Types' declare module 'next-auth' { // Normally we dissallow typing with empty objects, but in this case we // need to extend the User object with additional properties. The User // object is defined in next-auth, and we need to extend it with the - // properties from UserFiltered. So for this case we allow it. + // properties from UserAuthFiltered. So for this case we allow it. // // eslint-disable-next-line @typescript-eslint/no-empty-object-type - interface User extends Partial {} + interface User extends Partial {} interface Session { - user: UserFiltered, + user: UserAuthFiltered, permissions: Permission[], memberships: MembershipFiltered[], } @@ -24,7 +24,7 @@ declare module 'next-auth' { declare module 'next-auth/jwt' { interface JWT { provider: 'credentials' | 'feide', - user: UserFiltered, + user: UserAuthFiltered, permissions: Permission[], memberships: MembershipFiltered[],