기능구현중
This commit is contained in:
23
server/api/vcs-account/[id]/delete.delete.ts
Normal file
23
server/api/vcs-account/[id]/delete.delete.ts
Normal file
@@ -0,0 +1,23 @@
|
||||
import { execute, queryOne } from '../../../utils/db'
|
||||
import { getCurrentUserId } from '../../../utils/user'
|
||||
|
||||
/**
|
||||
* VCS 계정 삭제
|
||||
* DELETE /api/vcs-account/[id]/delete
|
||||
*/
|
||||
export default defineEventHandler(async (event) => {
|
||||
const accountId = Number(getRouterParam(event, 'id'))
|
||||
const userId = await getCurrentUserId(event)
|
||||
|
||||
const existing = await queryOne(
|
||||
'SELECT * FROM wr_employee_vcs_account WHERE account_id = $1 AND employee_id = $2',
|
||||
[accountId, userId]
|
||||
)
|
||||
if (!existing) {
|
||||
throw createError({ statusCode: 404, message: 'VCS 계정을 찾을 수 없습니다.' })
|
||||
}
|
||||
|
||||
await execute('DELETE FROM wr_employee_vcs_account WHERE account_id = $1', [accountId])
|
||||
|
||||
return { success: true, message: 'VCS 계정이 삭제되었습니다.' }
|
||||
})
|
||||
80
server/api/vcs-account/[id]/update.put.ts
Normal file
80
server/api/vcs-account/[id]/update.put.ts
Normal file
@@ -0,0 +1,80 @@
|
||||
import { execute, queryOne } from '../../../utils/db'
|
||||
import { getCurrentUserId } from '../../../utils/user'
|
||||
import crypto from 'crypto'
|
||||
|
||||
interface UpdateBody {
|
||||
vcsUsername?: string
|
||||
vcsEmail?: string
|
||||
authType?: string
|
||||
credential?: string
|
||||
isActive?: boolean
|
||||
}
|
||||
|
||||
function encryptCredential(text: string): string {
|
||||
const key = process.env.ENCRYPTION_KEY || 'weeklyreport-default-key-32byte!'
|
||||
const iv = crypto.randomBytes(16)
|
||||
const cipher = crypto.createCipheriv('aes-256-cbc', Buffer.from(key.padEnd(32, '0').slice(0, 32)), iv)
|
||||
let encrypted = cipher.update(text, 'utf8', 'hex')
|
||||
encrypted += cipher.final('hex')
|
||||
return iv.toString('hex') + ':' + encrypted
|
||||
}
|
||||
|
||||
/**
|
||||
* VCS 계정 수정
|
||||
* PUT /api/vcs-account/[id]/update
|
||||
*/
|
||||
export default defineEventHandler(async (event) => {
|
||||
const accountId = Number(getRouterParam(event, 'id'))
|
||||
const body = await readBody<UpdateBody>(event)
|
||||
const userId = await getCurrentUserId(event)
|
||||
|
||||
const existing = await queryOne(
|
||||
'SELECT * FROM wr_employee_vcs_account WHERE account_id = $1 AND employee_id = $2',
|
||||
[accountId, userId]
|
||||
)
|
||||
if (!existing) {
|
||||
throw createError({ statusCode: 404, message: 'VCS 계정을 찾을 수 없습니다.' })
|
||||
}
|
||||
|
||||
const updates: string[] = []
|
||||
const values: any[] = []
|
||||
let paramIndex = 1
|
||||
|
||||
if (body.vcsUsername !== undefined) {
|
||||
updates.push(`vcs_username = $${paramIndex++}`)
|
||||
values.push(body.vcsUsername)
|
||||
}
|
||||
|
||||
if (body.vcsEmail !== undefined) {
|
||||
updates.push(`vcs_email = $${paramIndex++}`)
|
||||
values.push(body.vcsEmail)
|
||||
}
|
||||
|
||||
if (body.authType !== undefined) {
|
||||
updates.push(`auth_type = $${paramIndex++}`)
|
||||
values.push(body.authType)
|
||||
}
|
||||
|
||||
if (body.credential !== undefined && body.credential) {
|
||||
updates.push(`encrypted_credential = $${paramIndex++}`)
|
||||
values.push(encryptCredential(body.credential))
|
||||
}
|
||||
|
||||
if (body.isActive !== undefined) {
|
||||
updates.push(`is_active = $${paramIndex++}`)
|
||||
values.push(body.isActive)
|
||||
}
|
||||
|
||||
if (updates.length === 0) {
|
||||
return { success: true, message: '변경된 내용이 없습니다.' }
|
||||
}
|
||||
|
||||
updates.push('updated_at = NOW()')
|
||||
values.push(accountId)
|
||||
|
||||
await execute(`
|
||||
UPDATE wr_employee_vcs_account SET ${updates.join(', ')} WHERE account_id = $${paramIndex}
|
||||
`, values)
|
||||
|
||||
return { success: true }
|
||||
})
|
||||
82
server/api/vcs-account/create.post.ts
Normal file
82
server/api/vcs-account/create.post.ts
Normal file
@@ -0,0 +1,82 @@
|
||||
import { insertReturning, queryOne } from '../../utils/db'
|
||||
import { getCurrentUserId } from '../../utils/user'
|
||||
import crypto from 'crypto'
|
||||
|
||||
interface CreateBody {
|
||||
serverId: number
|
||||
vcsUsername: string
|
||||
vcsEmail?: string
|
||||
authType: string // password | token | ssh
|
||||
credential?: string
|
||||
}
|
||||
|
||||
// 간단한 암호화 (실제 운영에서는 더 강력한 방식 사용)
|
||||
function encryptCredential(text: string): string {
|
||||
const key = process.env.ENCRYPTION_KEY || 'weeklyreport-default-key-32byte!'
|
||||
const iv = crypto.randomBytes(16)
|
||||
const cipher = crypto.createCipheriv('aes-256-cbc', Buffer.from(key.padEnd(32, '0').slice(0, 32)), iv)
|
||||
let encrypted = cipher.update(text, 'utf8', 'hex')
|
||||
encrypted += cipher.final('hex')
|
||||
return iv.toString('hex') + ':' + encrypted
|
||||
}
|
||||
|
||||
/**
|
||||
* VCS 계정 등록
|
||||
* POST /api/vcs-account/create
|
||||
*/
|
||||
export default defineEventHandler(async (event) => {
|
||||
const body = await readBody<CreateBody>(event)
|
||||
const userId = await getCurrentUserId(event)
|
||||
|
||||
if (!body.serverId) {
|
||||
throw createError({ statusCode: 400, message: 'VCS 서버를 선택해주세요.' })
|
||||
}
|
||||
|
||||
if (!body.vcsUsername?.trim()) {
|
||||
throw createError({ statusCode: 400, message: 'VCS 사용자명을 입력해주세요.' })
|
||||
}
|
||||
|
||||
// 서버 존재 확인
|
||||
const server = await queryOne('SELECT * FROM wr_vcs_server WHERE server_id = $1 AND is_active = true', [body.serverId])
|
||||
if (!server) {
|
||||
throw createError({ statusCode: 404, message: 'VCS 서버를 찾을 수 없습니다.' })
|
||||
}
|
||||
|
||||
// 중복 확인
|
||||
const existing = await queryOne(
|
||||
'SELECT * FROM wr_employee_vcs_account WHERE employee_id = $1 AND server_id = $2',
|
||||
[userId, body.serverId]
|
||||
)
|
||||
if (existing) {
|
||||
throw createError({ statusCode: 400, message: '이미 해당 서버에 계정이 등록되어 있습니다.' })
|
||||
}
|
||||
|
||||
// 자격증명 암호화
|
||||
let encryptedCred = null
|
||||
if (body.credential) {
|
||||
encryptedCred = encryptCredential(body.credential)
|
||||
}
|
||||
|
||||
const result = await insertReturning(`
|
||||
INSERT INTO wr_employee_vcs_account (
|
||||
employee_id, server_id, vcs_username, vcs_email, auth_type, encrypted_credential, is_active
|
||||
) VALUES ($1, $2, $3, $4, $5, $6, true)
|
||||
RETURNING *
|
||||
`, [
|
||||
userId,
|
||||
body.serverId,
|
||||
body.vcsUsername.trim(),
|
||||
body.vcsEmail || null,
|
||||
body.authType || 'password',
|
||||
encryptedCred
|
||||
])
|
||||
|
||||
return {
|
||||
success: true,
|
||||
account: {
|
||||
accountId: result.account_id,
|
||||
serverId: result.server_id,
|
||||
vcsUsername: result.vcs_username
|
||||
}
|
||||
}
|
||||
})
|
||||
37
server/api/vcs-account/my.get.ts
Normal file
37
server/api/vcs-account/my.get.ts
Normal file
@@ -0,0 +1,37 @@
|
||||
import { query } from '../../utils/db'
|
||||
import { getCurrentUserId } from '../../utils/user'
|
||||
|
||||
/**
|
||||
* 내 VCS 계정 목록 조회
|
||||
* GET /api/vcs-account/my
|
||||
*/
|
||||
export default defineEventHandler(async (event) => {
|
||||
const userId = await getCurrentUserId(event)
|
||||
|
||||
const accounts = await query(`
|
||||
SELECT
|
||||
a.*,
|
||||
s.server_name,
|
||||
s.server_type,
|
||||
s.server_url
|
||||
FROM wr_employee_vcs_account a
|
||||
JOIN wr_vcs_server s ON a.server_id = s.server_id
|
||||
WHERE a.employee_id = $1
|
||||
ORDER BY s.server_name, a.vcs_username
|
||||
`, [userId])
|
||||
|
||||
return {
|
||||
accounts: accounts.map((a: any) => ({
|
||||
accountId: a.account_id,
|
||||
serverId: a.server_id,
|
||||
serverName: a.server_name,
|
||||
serverType: a.server_type,
|
||||
serverUrl: a.server_url,
|
||||
vcsUsername: a.vcs_username,
|
||||
vcsEmail: a.vcs_email,
|
||||
authType: a.auth_type,
|
||||
isActive: a.is_active,
|
||||
createdAt: a.created_at
|
||||
}))
|
||||
}
|
||||
})
|
||||
Reference in New Issue
Block a user