ssh키 등록 기능 추가
All checks were successful
Build And Test / build-and-push (push) Successful in 1m3s

This commit is contained in:
2025-05-20 13:57:11 +09:00
parent d3cb5d8b70
commit a015c52dbd
4 changed files with 160 additions and 53 deletions

View File

@ -1,50 +1,37 @@
// ✅ EditForm.js
import React from 'react';
function EditForm({ form, onChange, onSubmit }) {
return (
<form onSubmit={onSubmit} className="bg-white p-8 rounded shadow-md w-full max-w-md mx-auto">
<h2 className="text-2xl font-bold mb-6 text-center text-[#3B82F6]">회원정보 수정</h2>
<form onSubmit={onSubmit} className="space-y-4">
<input
name="name"
value={form.name}
onChange={onChange}
className="w-full px-4 py-2 border rounded"
placeholder="이름"
/>
<div className="mb-4">
<label className="block text-sm font-medium text-gray-700 mb-1">이름</label>
<input
name="name"
value={form.name}
onChange={onChange}
className="w-full px-4 py-2 border border-gray-300 rounded"
placeholder="이름을 입력하세요"
/>
</div>
<input
name="email"
type="email"
value={form.email}
onChange={onChange}
className="w-full px-4 py-2 border rounded"
placeholder="이메일"
/>
<div className="mb-4">
<label className="block text-sm font-medium text-gray-700 mb-1">이메일</label>
<input
name="email"
type="email"
value={form.email}
onChange={onChange}
className="w-full px-4 py-2 border border-gray-300 rounded"
placeholder="이메일을 입력하세요"
/>
</div>
<textarea
name="desc"
value={form.desc}
onChange={onChange}
className="w-full px-4 py-2 border rounded"
placeholder="자기소개"
rows={4}
/>
<div className="mb-6">
<label className="block text-sm font-medium text-gray-700 mb-1">설명</label>
<textarea
name="desc"
value={form.desc}
onChange={onChange}
rows="4"
className="w-full px-4 py-2 border border-gray-300 rounded"
placeholder="자기소개 또는 간단한 설명을 입력하세요"
/>
</div>
<button
type="submit"
className="w-full bg-[#3B82F6] text-white py-2 rounded hover:bg-blue-700 transition"
>
수정
<button type="submit" className="w-full bg-blue-600 text-white py-2 rounded hover:bg-blue-700">
저장
</button>
</form>
);

View File

@ -0,0 +1,79 @@
// ✅ SSHKeyForm.js
import React, { useEffect, useState } from 'react';
import authApi from '../../api/authApi';
function SSHKeyForm({ form, onChange, onSubmit }) {
const [keyInfo, setKeyInfo] = useState(null);
useEffect(() => {
const fetchKeyInfo = async () => {
try {
const res = await authApi.get('/api/auth/ssh-key/info/');
setKeyInfo(res.data);
} catch (err) {
console.error("SSH 키 정보 조회 실패", err);
}
};
fetchKeyInfo();
}, []);
const handleDelete = async () => {
if (!window.confirm("등록된 SSH 키를 삭제하시겠습니까?")) return;
try {
await authApi.delete('/api/auth/ssh-key/');
alert("SSH 키가 삭제되었습니다.");
setKeyInfo(null);
} catch (err) {
console.error("삭제 실패", err);
alert("SSH 키 삭제에 실패했습니다.");
}
};
return (
<form onSubmit={onSubmit} className="space-y-4">
{keyInfo?.has_key && (
<div className="p-4 bg-gray-100 rounded border border-gray-300">
<p className="text-sm text-gray-700 mb-1">
<strong>등록된 이름:</strong> {keyInfo.encrypted_private_key_name || ' '}
</p>
<p className="text-sm text-gray-600">
<strong>마지막 사용 시각:</strong>{' '}
{keyInfo.last_used_at ? new Date(keyInfo.last_used_at).toLocaleString() : '없음'}
</p>
<button
type="button"
onClick={handleDelete}
className="mt-2 px-4 py-1 text-sm bg-red-500 text-white rounded hover:bg-red-600"
>
SSH 삭제
</button>
</div>
)}
<input
name="encrypted_private_key_name"
value={form.encrypted_private_key_name || ''}
onChange={onChange}
className="w-full px-4 py-2 border rounded"
placeholder="SSH 키 이름"
/>
<textarea
name="private_key"
value={form.private_key || ''}
onChange={onChange}
className="w-full px-4 py-2 border rounded font-mono"
placeholder="-----BEGIN OPENSSH PRIVATE KEY-----"
rows={6}
/>
<button type="submit" className="w-full bg-green-600 text-white py-2 rounded hover:bg-green-700">
등록
</button>
</form>
);
}
export default SSHKeyForm;

View File

@ -1,15 +1,18 @@
// ✅ index.js
import React, { useEffect, useState } from 'react';
import { useNavigate } from 'react-router-dom';
import EditForm from './EditForm';
import authApi from '../../api/authApi';
import EditForm from './EditForm';
import SSHKeyForm from './SSHKeyForm';
function ProfilePage() {
const navigate = useNavigate();
const [form, setForm] = useState({
name: '',
email: '',
desc: '' // ✅ desc 상태 추가
desc: '',
encrypted_private_key_name: '',
private_key: ''
});
useEffect(() => {
@ -22,8 +25,8 @@ function ProfilePage() {
const fetchUser = async () => {
try {
const res = await authApi.get('/api/auth/me/');
const { name, email, desc } = res.data;
setForm({ name, email, desc }); // ✅ desc 상태 반영
const { name, email, desc, encrypted_private_key_name } = res.data;
setForm((prev) => ({ ...prev, name, email, desc, encrypted_private_key_name }));
} catch (err) {
console.error(err);
navigate('/login');
@ -34,13 +37,19 @@ function ProfilePage() {
}, [navigate]);
const handleChange = (e) => {
setForm({ ...form, [e.target.name]: e.target.value });
const { name, value } = e.target;
setForm((prev) => ({ ...prev, [name]: value }));
};
const handleSubmit = async (e) => {
const handleProfileSubmit = async (e) => {
e.preventDefault();
try {
await authApi.put('/api/auth/me/', form); // ✅ desc 포함해서 PUT
await authApi.put('/api/auth/me/', {
name: form.name,
email: form.email,
desc: form.desc,
encrypted_private_key_name: form.encrypted_private_key_name
});
alert('회원정보가 수정되었습니다.');
} catch (err) {
console.error(err);
@ -48,9 +57,41 @@ function ProfilePage() {
}
};
const handleKeySubmit = async (e) => {
e.preventDefault();
if (!form.private_key) {
alert('키 내용을 입력해주세요.');
return;
}
try {
await authApi.post('/api/auth/ssh-key/', {
private_key: form.private_key,
key_name: form.encrypted_private_key_name
});
alert('SSH 키가 등록되었습니다.');
setForm((prev) => ({ ...prev, private_key: '' }));
} catch (err) {
console.error(err);
alert('SSH 키 등록 실패');
}
};
return (
<div className="container mt-5">
<EditForm form={form} onChange={handleChange} onSubmit={handleSubmit} />
<div className="min-h-screen bg-gray-100 py-16 px-4 flex justify-center items-start">
<div className="w-full max-w-5xl bg-white shadow-lg rounded-xl p-8 space-y-12">
<div>
<h2 className="text-2xl font-bold text-center text-blue-700 mb-6">👤 회원정보 수정</h2>
<EditForm form={form} onChange={handleChange} onSubmit={handleProfileSubmit} />
</div>
<hr className="border-gray-300" />
<div>
<h2 className="text-2xl font-bold text-center text-green-700 mb-6">🔐 SSH 등록</h2>
<SSHKeyForm form={form} onChange={handleChange} onSubmit={handleKeySubmit} />
</div>
</div>
</div>
);
}

View File

@ -1 +1 @@
0.0.12-rc1
0.0.12