fix: address coderabbit review on #6214
- Remove invalid null return from session callback (must return session object) - Prevent admin from disabling their own account (guard with isSelf check) - Hide disable UI when viewing own profile - Add user existence check to changeDisabled endpoint - Add OpenAPI metadata to changeDisabled mutation
This commit is contained in:
1 parent
fbac0c8752
commit
39a1a3695e
4 files changed
+35
-12
No files matched your search
+6
-2
@@ -10,9 +10,10 @@ import { useI18n } from "@homarr/translation/client";
|
||||
|
||||
interface DisableUserButtonProps {
|
||||
user: RouterOutputs["user"]["getById"];
|
||||
isSelf?: boolean;
|
||||
}
|
||||
|
||||
export const DisableUserButton = ({ user }: DisableUserButtonProps) => {
|
||||
export const DisableUserButton = ({ user, isSelf = false }: DisableUserButtonProps) => {
|
||||
const t = useI18n();
|
||||
const [isPending, startTransition] = useTransition();
|
||||
const changeDisabledMutation = clientApi.user.changeDisabled.useMutation();
|
||||
@@ -32,6 +33,8 @@ export const DisableUserButton = ({ user }: DisableUserButtonProps) => {
|
||||
};
|
||||
|
||||
const handleToggle = () => {
|
||||
if (isSelf) return;
|
||||
|
||||
startTransition(async () => {
|
||||
try {
|
||||
await changeDisabledMutation.mutateAsync({
|
||||
@@ -65,12 +68,13 @@ export const DisableUserButton = ({ user }: DisableUserButtonProps) => {
|
||||
const getButtonColor = () => (isDisabled ? "green" : "yellow");
|
||||
|
||||
return (
|
||||
<Tooltip label={getTooltipLabel()} position="top">
|
||||
<Tooltip label={isSelf ? t("user.action.disableSelf.disabled", { defaultValue: "Cannot disable your own account" }) : getTooltipLabel()} position="top">
|
||||
<Button
|
||||
onClick={handleToggle}
|
||||
loading={isPending || changeDisabledMutation.isPending}
|
||||
color={getButtonColor()}
|
||||
variant="light"
|
||||
disabled={isSelf}
|
||||
>
|
||||
{getButtonLabel()}
|
||||
</Button>
|
||||
|
||||
@@ -110,11 +110,13 @@ export default async function EditUserPage(props: Props) {
|
||||
)}
|
||||
|
||||
<DangerZoneRoot>
|
||||
<DangerZoneItem
|
||||
label={getDisableItemLabel()}
|
||||
description={getDisableItemDescription()}
|
||||
action={<DisableUserButton user={user} />}
|
||||
/>
|
||||
{!isSelf && (
|
||||
<DangerZoneItem
|
||||
label={getDisableItemLabel()}
|
||||
description={getDisableItemDescription()}
|
||||
action={<DisableUserButton user={user} isSelf={isSelf} />}
|
||||
/>
|
||||
)}
|
||||
<DangerZoneItem
|
||||
label={t("user.action.delete.label")}
|
||||
description={t("user.action.delete.description")}
|
||||
|
||||
@@ -790,7 +790,29 @@ export const userRouter = createTRPCRouter({
|
||||
}),
|
||||
)
|
||||
.output(z.void())
|
||||
.meta({
|
||||
openapi: {
|
||||
method: "PATCH",
|
||||
path: "/api/users/disabled",
|
||||
tags: ["users"],
|
||||
protect: true,
|
||||
},
|
||||
})
|
||||
.mutation(async ({ input, ctx }) => {
|
||||
const dbUser = await ctx.db.query.users.findFirst({
|
||||
columns: {
|
||||
id: true,
|
||||
},
|
||||
where: eq(users.id, input.userId),
|
||||
});
|
||||
|
||||
if (!dbUser) {
|
||||
throw new TRPCError({
|
||||
code: "NOT_FOUND",
|
||||
message: "User not found",
|
||||
});
|
||||
}
|
||||
|
||||
await ctx.db
|
||||
.update(users)
|
||||
.set({
|
||||
|
||||
@@ -47,14 +47,9 @@ export const createSessionCallback = (db: Database): NextAuthCallbackOf<"session
|
||||
where: eq(users.id, user.id),
|
||||
columns: {
|
||||
colorScheme: true,
|
||||
disabled: true,
|
||||
},
|
||||
});
|
||||
|
||||
if (additionalProperties?.disabled) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return {
|
||||
...session,
|
||||
user: {
|
||||
|
||||
Reference in new issue
Block a user