This commit is contained in:
backuppc
2025-07-08 13:29:40 +09:00
parent 8efe357430
commit 0d2da98470
4 changed files with 113 additions and 47 deletions

View File

@@ -122,7 +122,7 @@ namespace VNCServerList.Services
connection.Open(); connection.Open();
string sql = @" string sql = @"
INSERT INTO VNC_ServerList ([User], [IP], [Category], [Title],[Description], [Password], [Argument]) INSERT INTO VNC_ServerList ([User], [IP], [Category], [Title],[Description], [Password], [Argument])
VALUES (@User, @IP, @Category, @Description, @Password, @Argument)"; VALUES (@User, @IP, @Category, @Title,@Description, @Password, @Argument)";
using (var command = new SqlCommand(sql, connection)) using (var command = new SqlCommand(sql, connection))
{ {
@@ -165,6 +165,33 @@ namespace VNCServerList.Services
} }
} }
public bool UpdateServerByUserAndIP(string originalUser, string originalIp, VNCServer newServerData)
{
using (var connection = new SqlConnection(_connectionString))
{
connection.Open();
string sql = @"
UPDATE VNC_ServerList
SET [IP] = @NewIP, [Category] = @Category, [Title] = @Title, [Description] = @Description,
[Password] = @Password, [Argument] = @Argument
WHERE [User] = @User AND [IP] = @OriginalIP";
using (var command = new SqlCommand(sql, connection))
{
command.Parameters.AddWithValue("@User", originalUser);
command.Parameters.AddWithValue("@OriginalIP", originalIp);
command.Parameters.AddWithValue("@NewIP", newServerData.IP);
command.Parameters.AddWithValue("@Category", (object)newServerData.Category ?? DBNull.Value);
command.Parameters.AddWithValue("@Title", (object)newServerData.Title ?? DBNull.Value);
command.Parameters.AddWithValue("@Description", (object)newServerData.Description ?? DBNull.Value);
command.Parameters.AddWithValue("@Password", (object)newServerData.Password ?? DBNull.Value);
command.Parameters.AddWithValue("@Argument", (object)newServerData.Argument ?? DBNull.Value);
return command.ExecuteNonQuery() > 0;
}
}
}
public bool DeleteServer(string user, string ip) public bool DeleteServer(string user, string ip)
{ {
using (var connection = new SqlConnection(_connectionString)) using (var connection = new SqlConnection(_connectionString))

View File

@@ -28,13 +28,13 @@ namespace VNCServerList.Web.Controllers
try try
{ {
var servers = _databaseService.GetAllServers(); var servers = _databaseService.GetAllServers();
// 사용자 이름이 있으면 필터링 // 사용자 이름이 있으면 필터링
if (!string.IsNullOrEmpty(userName)) if (!string.IsNullOrEmpty(userName))
{ {
servers = servers.Where(s => s.User.Equals(userName, StringComparison.OrdinalIgnoreCase)).ToList(); servers = servers.Where(s => s.User.Equals(userName, StringComparison.OrdinalIgnoreCase)).ToList();
} }
// 사용자명으로 오름차순 정렬 // 사용자명으로 오름차순 정렬
var sortedServers = servers.OrderBy(s => s.User).ThenBy(s => s.IP).ToList(); var sortedServers = servers.OrderBy(s => s.User).ThenBy(s => s.IP).ToList();
return Ok(sortedServers); return Ok(sortedServers);
@@ -92,8 +92,8 @@ namespace VNCServerList.Web.Controllers
} }
[HttpPut] [HttpPut]
[Route("update")] [Route("update/{originalUser}/{originalIp}")]
public IHttpActionResult UpdateServer([FromBody] VNCServer server) public IHttpActionResult UpdateServer(string originalUser, string originalIp, [FromBody] VNCServer server)
{ {
try try
{ {
@@ -102,7 +102,8 @@ namespace VNCServerList.Web.Controllers
return BadRequest("서버 정보가 없습니다."); return BadRequest("서버 정보가 없습니다.");
} }
bool success = _databaseService.UpdateServer(server); // 원본 사용자명과 IP로 서버를 찾아서 업데이트
bool success = _databaseService.UpdateServerByUserAndIP(originalUser, originalIp, server);
if (success) if (success)
{ {
return Ok(new { Message = "서버가 성공적으로 업데이트되었습니다." }); return Ok(new { Message = "서버가 성공적으로 업데이트되었습니다." });
@@ -170,10 +171,11 @@ namespace VNCServerList.Web.Controllers
{ {
bool isInstalled = _vncService.IsVNCViewerInstalled(); bool isInstalled = _vncService.IsVNCViewerInstalled();
string path = _vncService.GetVNCViewerPath(); string path = _vncService.GetVNCViewerPath();
return Ok(new { return Ok(new
IsInstalled = isInstalled, {
Path = path IsInstalled = isInstalled,
Path = path
}); });
} }
catch (Exception ex) catch (Exception ex)
@@ -210,13 +212,13 @@ namespace VNCServerList.Web.Controllers
try try
{ {
System.Diagnostics.Debug.WriteLine("=== 설정 조회 시작 ==="); System.Diagnostics.Debug.WriteLine("=== 설정 조회 시작 ===");
var settings = _settingsService.GetSettings(); var settings = _settingsService.GetSettings();
// 디버깅용 로그 // 디버깅용 로그
System.Diagnostics.Debug.WriteLine($"조회된 설정: VNCViewerPath='{settings.VNCViewerPath}', WebServerPort={settings.WebServerPort}"); System.Diagnostics.Debug.WriteLine($"조회된 설정: VNCViewerPath='{settings.VNCViewerPath}', WebServerPort={settings.WebServerPort}");
System.Diagnostics.Debug.WriteLine("=== 설정 조회 완료 ==="); System.Diagnostics.Debug.WriteLine("=== 설정 조회 완료 ===");
return Ok(settings); return Ok(settings);
} }
catch (Exception ex) catch (Exception ex)
@@ -234,7 +236,7 @@ namespace VNCServerList.Web.Controllers
try try
{ {
System.Diagnostics.Debug.WriteLine("=== 설정 저장 요청 시작 ==="); System.Diagnostics.Debug.WriteLine("=== 설정 저장 요청 시작 ===");
if (settings == null) if (settings == null)
{ {
System.Diagnostics.Debug.WriteLine("설정 객체가 null입니다."); System.Diagnostics.Debug.WriteLine("설정 객체가 null입니다.");
@@ -247,12 +249,12 @@ namespace VNCServerList.Web.Controllers
System.Diagnostics.Debug.WriteLine($"WebServerPort 타입: {settings.WebServerPort.GetType()}"); System.Diagnostics.Debug.WriteLine($"WebServerPort 타입: {settings.WebServerPort.GetType()}");
_settingsService.SaveSettings(settings); _settingsService.SaveSettings(settings);
// 저장된 설정 확인 // 저장된 설정 확인
var savedSettings = _settingsService.GetSettings(); var savedSettings = _settingsService.GetSettings();
System.Diagnostics.Debug.WriteLine($"저장된 설정: VNCViewerPath='{savedSettings.VNCViewerPath}', WebServerPort={savedSettings.WebServerPort}"); System.Diagnostics.Debug.WriteLine($"저장된 설정: VNCViewerPath='{savedSettings.VNCViewerPath}', WebServerPort={savedSettings.WebServerPort}");
System.Diagnostics.Debug.WriteLine("=== 설정 저장 완료 ==="); System.Diagnostics.Debug.WriteLine("=== 설정 저장 완료 ===");
return Ok(new { Message = "설정이 저장되었습니다." }); return Ok(new { Message = "설정이 저장되었습니다." });
} }
catch (Exception ex) catch (Exception ex)
@@ -263,4 +265,4 @@ namespace VNCServerList.Web.Controllers
} }
} }
} }
} }

View File

@@ -63,34 +63,37 @@
<h3 id="modalTitle" class="text-lg font-semibold text-gray-800">서버 추가</h3> <h3 id="modalTitle" class="text-lg font-semibold text-gray-800">서버 추가</h3>
</div> </div>
<form id="serverForm" class="p-6"> <form id="serverForm" class="p-6">
<div class="mb-4"> <div class="grid grid-cols-2 gap-4 mb-4">
<label for="serverUser" class="block text-sm font-medium text-gray-700 mb-2">사용자</label> <div>
<input type="text" id="serverUser" class="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-primary focus:border-transparent" required> <label for="serverIp" class="block text-sm font-medium text-gray-700 mb-2">IP 주소</label>
</div> <input type="text" id="serverIp" class="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-primary focus:border-transparent" required>
<div class="mb-4"> </div>
<label for="serverIp" class="block text-sm font-medium text-gray-700 mb-2">IP 주소</label> <div>
<input type="text" id="serverIp" class="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-primary focus:border-transparent" required> <label for="serverPassword" class="block text-sm font-medium text-gray-700 mb-2">비밀번호</label>
</div> <input type="password" id="serverPassword" class="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-primary focus:border-transparent">
<div class="mb-4"> </div>
<label for="serverCategory" class="block text-sm font-medium text-gray-700 mb-2">카테고리</label>
<input type="text" id="serverCategory" class="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-primary focus:border-transparent">
</div> </div>
<div class="mb-4"> <div class="mb-4">
<label for="serverTitle" class="block text-sm font-medium text-gray-700 mb-2">제목</label> <label for="serverTitle" class="block text-sm font-medium text-gray-700 mb-2">제목</label>
<input type="text" id="serverTitle" class="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-primary focus:border-transparent"> <input type="text" id="serverTitle" class="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-primary focus:border-transparent">
</div> </div>
<div class="grid grid-cols-2 gap-4 mb-4">
<div >
<label for="serverCategory" class="block text-sm font-medium text-gray-700 mb-2">카테고리</label>
<input type="text" id="serverCategory" class="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-primary focus:border-transparent">
</div>
<div>
<label for="serverArgument" class="block text-sm font-medium text-gray-700 mb-2">VNC 인수</label>
<input type="text" id="serverArgument" placeholder="-port=5900" class="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-primary focus:border-transparent">
</div>
</div>
<div class="mb-4"> <div class="mb-4">
<label for="serverDescription" class="block text-sm font-medium text-gray-700 mb-2">설명</label> <label for="serverDescription" class="block text-sm font-medium text-gray-700 mb-2">설명</label>
<textarea id="serverDescription" rows="2" class="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-primary focus:border-transparent"></textarea> <textarea id="serverDescription" rows="2" class="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-primary focus:border-transparent"></textarea>
</div> </div>
<div class="mb-4">
<label for="serverPassword" class="block text-sm font-medium text-gray-700 mb-2">비밀번호</label>
<input type="password" id="serverPassword" class="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-primary focus:border-transparent">
</div>
<div class="mb-6">
<label for="serverArgument" class="block text-sm font-medium text-gray-700 mb-2">VNC 인수</label>
<input type="text" id="serverArgument" placeholder="-port=5900" class="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-primary focus:border-transparent">
</div>
<div class="flex justify-end space-x-3"> <div class="flex justify-end space-x-3">
<button type="button" id="cancelBtn" class="px-4 py-2 text-gray-700 bg-gray-200 rounded-md hover:bg-gray-300 transition duration-200">취소</button> <button type="button" id="cancelBtn" class="px-4 py-2 text-gray-700 bg-gray-200 rounded-md hover:bg-gray-300 transition duration-200">취소</button>
<button type="submit" class="px-4 py-2 bg-primary text-white rounded-md hover:bg-blue-700 transition duration-200">저장</button> <button type="submit" class="px-4 py-2 bg-primary text-white rounded-md hover:bg-blue-700 transition duration-200">저장</button>

View File

@@ -205,19 +205,29 @@ class VNCServerApp {
const modal = document.getElementById('serverModal'); const modal = document.getElementById('serverModal');
const title = document.getElementById('modalTitle'); const title = document.getElementById('modalTitle');
const form = document.getElementById('serverForm'); const form = document.getElementById('serverForm');
console.log('서버 정보2:', server); // 디버깅용
if (server) { if (server) {
title.textContent = '서버 편집'; title.textContent = '서버 편집';
document.getElementById('serverUser').value = server.user; document.getElementById('serverIp').value = server.IP;
document.getElementById('serverIp').value = server.ip; document.getElementById('serverCategory').value = server.Category || '';
document.getElementById('serverCategory').value = server.category || ''; document.getElementById('serverTitle').value = server.Title || '';
document.getElementById('serverTitle').value = server.title || ''; document.getElementById('serverDescription').value = server.Description || '';
document.getElementById('serverDescription').value = server.description || ''; document.getElementById('serverPassword').value = server.Password || '';
document.getElementById('serverPassword').value = server.password || ''; document.getElementById('serverArgument').value = server.Argument || '';
document.getElementById('serverArgument').value = server.argument || ''; // 편집 모드 플래그 설정
modal.dataset.editMode = 'true';
modal.dataset.editUser = server.User;
modal.dataset.editIp = server.IP;
} else { } else {
title.textContent = '서버 추가'; title.textContent = '서버 추가';
form.reset(); form.reset();
// 추가 모드 플래그 설정
modal.dataset.editMode = 'false';
delete modal.dataset.editUser;
delete modal.dataset.editIp;
} }
modal.classList.remove('hidden'); modal.classList.remove('hidden');
@@ -346,10 +356,18 @@ class VNCServerApp {
} }
async saveServer() { async saveServer() {
const serverUser = document.getElementById('serverUser').value;
const serverIp = document.getElementById('serverIp').value; const serverIp = document.getElementById('serverIp').value;
const userName = document.getElementById('userName')?.value || '';
const modal = document.getElementById('serverModal');
const isEditMode = modal.dataset.editMode === 'true';
if (!userName) {
this.showError('사용자 이름이 설정되지 않았습니다. 먼저 설정에서 사용자 이름을 입력해주세요.');
return;
}
const serverData = { const serverData = {
user: serverUser, user: userName,
ip: serverIp, ip: serverIp,
category: document.getElementById('serverCategory').value, category: document.getElementById('serverCategory').value,
title: document.getElementById('serverTitle').value, title: document.getElementById('serverTitle').value,
@@ -359,8 +377,19 @@ class VNCServerApp {
}; };
try { try {
const url = serverUser && serverIp ? `${this.apiBase}/update` : `${this.apiBase}/add`; let url, method;
const method = serverUser && serverIp ? 'PUT' : 'POST';
if (isEditMode) {
// 편집 모드: 원본 사용자명과 IP를 쿼리 파라미터로 전달
const originalUser = modal.dataset.editUser;
const originalIp = modal.dataset.editIp;
url = `${this.apiBase}/update/${encodeURIComponent(originalUser)}/${encodeURIComponent(originalIp)}`;
method = 'PUT';
} else {
// 추가 모드
url = `${this.apiBase}/add`;
method = 'POST';
}
const response = await fetch(url, { const response = await fetch(url, {
method: method, method: method,
@@ -382,13 +411,16 @@ class VNCServerApp {
} }
async editServer(user, ip) { async editServer(user, ip) {
console.log('편집 서버 호출:', { user, ip }); // 디버깅용
try { try {
const response = await fetch(`${this.apiBase}/get/${encodeURIComponent(user)}/${encodeURIComponent(ip)}`); const response = await fetch(`${this.apiBase}/get/${encodeURIComponent(user)}/${encodeURIComponent(ip)}`);
if (!response.ok) throw new Error('서버 정보를 불러올 수 없습니다.'); if (!response.ok) throw new Error('서버 정보를 불러올 수 없습니다.');
const server = await response.json(); const server = await response.json();
console.log('서버 정보:', server); // 디버깅용
this.showServerModal(server); this.showServerModal(server);
} catch (error) { } catch (error) {
console.error('편집 서버 오류:', error); // 디버깅용
this.showError('서버 정보를 불러오는 중 오류가 발생했습니다: ' + error.message); this.showError('서버 정보를 불러오는 중 오류가 발생했습니다: ' + error.message);
} }
} }
@@ -533,6 +565,7 @@ class VNCServerApp {
// 서버 목록 렌더링 // 서버 목록 렌더링
if (hasServers) { if (hasServers) {
categoryData.servers.forEach(server => { categoryData.servers.forEach(server => {
console.log('서버 데이터:', server); // 디버깅용
const serverData = { const serverData = {
serverName: `${server.User || server.user}@${server.Title || server.title}`, serverName: `${server.User || server.user}@${server.Title || server.title}`,
userName: server.User || server.user, userName: server.User || server.user,
@@ -542,6 +575,7 @@ class VNCServerApp {
serverDescription: server.Description || server.description, serverDescription: server.Description || server.description,
serverArgument: server.Argument || server.argument serverArgument: server.Argument || server.argument
}; };
console.log('렌더링할 서버 데이터:', serverData); // 디버깅용
html += this.renderTemplate('serverItemTemplate', serverData); html += this.renderTemplate('serverItemTemplate', serverData);
}); });
} }