멤버 등급 변경 권한 규칙 수정 v1.5.6

This commit is contained in:
2026-05-26 16:31:56 +09:00
parent 3843e16d9f
commit a5ae2c3fce
9 changed files with 120 additions and 94 deletions

View File

@@ -24,6 +24,13 @@ const getMemberRoleLabel = (roleCode) => roleCode === MEMBER_ROLE.OWNER
? 'VIP'
: '멤버'
/**
* 관리자 권한 코드 여부를 확인한다.
* @param {string} roleCode - 권한 코드
* @returns {boolean} 관리자 권한 여부
*/
const isPrivilegedRole = (roleCode) => PRIVILEGED_ROLES.includes(roleCode)
/**
* 관리자 회원 행을 응답 객체로 변환한다.
* @param {Object} row - DB 회원 행
@@ -816,63 +823,90 @@ export const updateMemberRoleByAdmin = async (input) => {
})
}
const actorCanManage = await isPrivilegedMember(input.actorUserId)
if (!actorCanManage) {
throw createError({
statusCode: 403,
message: '권한 변경 권한이 없습니다.'
})
}
const updatedRows = await sql.begin(async (tx) => {
await tx`LOCK TABLE users IN SHARE ROW EXCLUSIVE MODE`
const targetRows = await sql`
SELECT id, user_role AS "roleCode"
FROM users
WHERE id = ${input.targetUserId}
LIMIT 1
`
const target = targetRows?.[0]
if (!target) {
throw createError({
statusCode: 404,
message: '대상 회원을 찾을 수 없습니다.'
})
}
if (target.id === input.actorUserId && !PRIVILEGED_ROLES.includes(normalizedRole)) {
throw createError({
statusCode: 400,
message: '본인 계정을 관리자 권한 없는 등급으로 변경할 수 없습니다.'
})
}
if (target.roleCode === MEMBER_ROLE.OWNER && normalizedRole !== MEMBER_ROLE.OWNER) {
const ownerRows = await sql`
SELECT COUNT(*)::int AS "ownerCount"
const actorRows = await tx`
SELECT id, user_role AS "roleCode"
FROM users
WHERE user_role = ${MEMBER_ROLE.OWNER}
WHERE id = ${input.actorUserId}
LIMIT 1
`
const actor = actorRows?.[0]
if (Number(ownerRows?.[0]?.ownerCount || 0) <= 1) {
if (!actor || !isPrivilegedRole(actor.roleCode)) {
throw createError({
statusCode: 400,
message: '최소 1명의 소유자 권한은 유지되어야 합니다.'
statusCode: 403,
message: '권한 변경 권한이 없습니다.'
})
}
}
const updatedRows = await sql`
UPDATE users
SET
user_role = ${normalizedRole},
is_admin = ${normalizedRole === MEMBER_ROLE.OWNER || normalizedRole === MEMBER_ROLE.ADMIN},
updated_at = now()
WHERE id = ${input.targetUserId}
RETURNING
id,
user_role AS "roleCode",
is_admin AS "isAdmin"
`
const targetRows = await tx`
SELECT id, user_role AS "roleCode"
FROM users
WHERE id = ${input.targetUserId}
LIMIT 1
`
const target = targetRows?.[0]
if (!target) {
throw createError({
statusCode: 404,
message: '대상 회원을 찾을 수 없습니다.'
})
}
if (actor.roleCode === MEMBER_ROLE.ADMIN) {
if (isPrivilegedRole(target.roleCode)) {
throw createError({
statusCode: 403,
message: '관리자는 다른 소유자 또는 관리자 권한을 변경할 수 없습니다.'
})
}
if (isPrivilegedRole(normalizedRole)) {
throw createError({
statusCode: 403,
message: '관리자는 소유자 또는 관리자 등급을 부여할 수 없습니다.'
})
}
}
if (target.id === input.actorUserId && !isPrivilegedRole(normalizedRole)) {
throw createError({
statusCode: 400,
message: '본인 계정을 관리자 권한 없는 등급으로 변경할 수 없습니다.'
})
}
if (target.roleCode === MEMBER_ROLE.OWNER && normalizedRole !== MEMBER_ROLE.OWNER) {
const ownerRows = await tx`
SELECT COUNT(*)::int AS "ownerCount"
FROM users
WHERE user_role = ${MEMBER_ROLE.OWNER}
`
if (Number(ownerRows?.[0]?.ownerCount || 0) <= 1) {
throw createError({
statusCode: 400,
message: '최소 1명의 소유자 권한은 유지되어야 합니다.'
})
}
}
return tx`
UPDATE users
SET
user_role = ${normalizedRole},
is_admin = ${normalizedRole === MEMBER_ROLE.OWNER || normalizedRole === MEMBER_ROLE.ADMIN},
updated_at = now()
WHERE id = ${input.targetUserId}
RETURNING
id,
user_role AS "roleCode",
is_admin AS "isAdmin"
`
})
const updated = updatedRows?.[0]
if (!updated) {