Implement Board CRUD API: Add, Edit, Delete with authorization check
This commit is contained in:
@@ -154,5 +154,150 @@ namespace Project.Web
|
||||
return JsonConvert.SerializeObject(new { Success = false, Message = ex.Message });
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 게시판 추가
|
||||
/// </summary>
|
||||
public string Board_Add(int bidx, string header, string cate, string title, string contents)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (string.IsNullOrEmpty(info.Login.no) || string.IsNullOrEmpty(info.Login.gcode))
|
||||
{
|
||||
return JsonConvert.SerializeObject(new { Success = false, Message = "로그인이 필요합니다." });
|
||||
}
|
||||
|
||||
var connStr = Project.Properties.Settings.Default.CS;
|
||||
using (var conn = new SqlConnection(connStr))
|
||||
{
|
||||
conn.Open();
|
||||
|
||||
var cmd = new SqlCommand(@"
|
||||
INSERT INTO Board (bidx, header, cate, title, contents, wuid, wdate, gcode)
|
||||
VALUES (@bidx, @header, @cate, @title, @contents, @wuid, GETDATE(), @gcode);
|
||||
SELECT SCOPE_IDENTITY();", conn);
|
||||
|
||||
cmd.Parameters.Add("@bidx", SqlDbType.Int).Value = bidx;
|
||||
cmd.Parameters.Add("@header", SqlDbType.NVarChar).Value = string.IsNullOrEmpty(header) ? (object)DBNull.Value : header;
|
||||
cmd.Parameters.Add("@cate", SqlDbType.NVarChar).Value = string.IsNullOrEmpty(cate) ? (object)DBNull.Value : cate;
|
||||
cmd.Parameters.Add("@title", SqlDbType.NVarChar).Value = title;
|
||||
cmd.Parameters.Add("@contents", SqlDbType.NVarChar).Value = contents;
|
||||
cmd.Parameters.Add("@wuid", SqlDbType.VarChar).Value = info.Login.no;
|
||||
cmd.Parameters.Add("@gcode", SqlDbType.VarChar).Value = info.Login.gcode;
|
||||
|
||||
var newIdx = Convert.ToInt32(cmd.ExecuteScalar());
|
||||
|
||||
return JsonConvert.SerializeObject(new { Success = true, Message = "등록되었습니다.", Data = new { idx = newIdx } });
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return JsonConvert.SerializeObject(new { Success = false, Message = ex.Message });
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 게시판 수정
|
||||
/// </summary>
|
||||
public string Board_Edit(int idx, string header, string cate, string title, string contents)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (string.IsNullOrEmpty(info.Login.no) || string.IsNullOrEmpty(info.Login.gcode))
|
||||
{
|
||||
return JsonConvert.SerializeObject(new { Success = false, Message = "로그인이 필요합니다." });
|
||||
}
|
||||
|
||||
var connStr = Project.Properties.Settings.Default.CS;
|
||||
using (var conn = new SqlConnection(connStr))
|
||||
{
|
||||
conn.Open();
|
||||
|
||||
// 권한 확인: 작성자 본인이거나 레벨 9 이상만 수정 가능
|
||||
var checkCmd = new SqlCommand("SELECT wuid FROM Board WHERE idx = @idx", conn);
|
||||
checkCmd.Parameters.Add("@idx", SqlDbType.Int).Value = idx;
|
||||
var originalWuid = checkCmd.ExecuteScalar()?.ToString();
|
||||
|
||||
if (originalWuid != info.Login.no && info.Login.level < 9)
|
||||
{
|
||||
return JsonConvert.SerializeObject(new { Success = false, Message = "수정 권한이 없습니다." });
|
||||
}
|
||||
|
||||
var cmd = new SqlCommand(@"
|
||||
UPDATE Board
|
||||
SET header = @header, cate = @cate, title = @title, contents = @contents
|
||||
WHERE idx = @idx", conn);
|
||||
|
||||
cmd.Parameters.Add("@idx", SqlDbType.Int).Value = idx;
|
||||
cmd.Parameters.Add("@header", SqlDbType.NVarChar).Value = string.IsNullOrEmpty(header) ? (object)DBNull.Value : header;
|
||||
cmd.Parameters.Add("@cate", SqlDbType.NVarChar).Value = string.IsNullOrEmpty(cate) ? (object)DBNull.Value : cate;
|
||||
cmd.Parameters.Add("@title", SqlDbType.NVarChar).Value = title;
|
||||
cmd.Parameters.Add("@contents", SqlDbType.NVarChar).Value = contents;
|
||||
|
||||
var affected = cmd.ExecuteNonQuery();
|
||||
|
||||
if (affected > 0)
|
||||
{
|
||||
return JsonConvert.SerializeObject(new { Success = true, Message = "수정되었습니다." });
|
||||
}
|
||||
else
|
||||
{
|
||||
return JsonConvert.SerializeObject(new { Success = false, Message = "수정할 데이터를 찾을 수 없습니다." });
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return JsonConvert.SerializeObject(new { Success = false, Message = ex.Message });
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 게시판 삭제
|
||||
/// </summary>
|
||||
public string Board_Delete(int idx)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (string.IsNullOrEmpty(info.Login.no) || string.IsNullOrEmpty(info.Login.gcode))
|
||||
{
|
||||
return JsonConvert.SerializeObject(new { Success = false, Message = "로그인이 필요합니다." });
|
||||
}
|
||||
|
||||
var connStr = Project.Properties.Settings.Default.CS;
|
||||
using (var conn = new SqlConnection(connStr))
|
||||
{
|
||||
conn.Open();
|
||||
|
||||
// 권한 확인: 작성자 본인이거나 레벨 9 이상만 삭제 가능
|
||||
var checkCmd = new SqlCommand("SELECT wuid FROM Board WHERE idx = @idx", conn);
|
||||
checkCmd.Parameters.Add("@idx", SqlDbType.Int).Value = idx;
|
||||
var originalWuid = checkCmd.ExecuteScalar()?.ToString();
|
||||
|
||||
if (originalWuid != info.Login.no && info.Login.level < 9)
|
||||
{
|
||||
return JsonConvert.SerializeObject(new { Success = false, Message = "삭제 권한이 없습니다." });
|
||||
}
|
||||
|
||||
var cmd = new SqlCommand("DELETE FROM Board WHERE idx = @idx", conn);
|
||||
cmd.Parameters.Add("@idx", SqlDbType.Int).Value = idx;
|
||||
|
||||
var affected = cmd.ExecuteNonQuery();
|
||||
|
||||
if (affected > 0)
|
||||
{
|
||||
return JsonConvert.SerializeObject(new { Success = true, Message = "삭제되었습니다." });
|
||||
}
|
||||
else
|
||||
{
|
||||
return JsonConvert.SerializeObject(new { Success = false, Message = "삭제할 데이터를 찾을 수 없습니다." });
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return JsonConvert.SerializeObject(new { Success = false, Message = ex.Message });
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -917,6 +917,41 @@ namespace Project.Web
|
||||
}
|
||||
break;
|
||||
|
||||
case "BOARD_ADD":
|
||||
{
|
||||
int bidx = json.bidx ?? 5;
|
||||
string header = json.header ?? "";
|
||||
string cate = json.cate ?? "";
|
||||
string title = json.title ?? "";
|
||||
string contents = json.contents ?? "";
|
||||
string result = _bridge.Board_Add(bidx, header, cate, title, contents);
|
||||
var response = new { type = "BOARD_ADDED", data = JsonConvert.DeserializeObject(result) };
|
||||
await Send(socket, JsonConvert.SerializeObject(response));
|
||||
}
|
||||
break;
|
||||
|
||||
case "BOARD_EDIT":
|
||||
{
|
||||
int idx = json.idx ?? 0;
|
||||
string header = json.header ?? "";
|
||||
string cate = json.cate ?? "";
|
||||
string title = json.title ?? "";
|
||||
string contents = json.contents ?? "";
|
||||
string result = _bridge.Board_Edit(idx, header, cate, title, contents);
|
||||
var response = new { type = "BOARD_EDITED", data = JsonConvert.DeserializeObject(result) };
|
||||
await Send(socket, JsonConvert.SerializeObject(response));
|
||||
}
|
||||
break;
|
||||
|
||||
case "BOARD_DELETE":
|
||||
{
|
||||
int idx = json.idx ?? 0;
|
||||
string result = _bridge.Board_Delete(idx);
|
||||
var response = new { type = "BOARD_DELETED", data = JsonConvert.DeserializeObject(result) };
|
||||
await Send(socket, JsonConvert.SerializeObject(response));
|
||||
}
|
||||
break;
|
||||
|
||||
// ===== Mail API (메일 발신 내역) =====
|
||||
case "MAIL_GET_LIST":
|
||||
{
|
||||
|
||||
@@ -1264,6 +1264,56 @@ class CommunicationLayer {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 게시판 추가
|
||||
* @param bidx 게시판 인덱스
|
||||
* @param header 헤더
|
||||
* @param cate 카테고리
|
||||
* @param title 제목
|
||||
* @param contents 내용
|
||||
* @returns ApiResponse
|
||||
*/
|
||||
public async addBoard(bidx: number, header: string, cate: string, title: string, contents: string): Promise<ApiResponse> {
|
||||
if (isWebView && machine) {
|
||||
const result = await machine.Board_Add(bidx, header, cate, title, contents);
|
||||
return JSON.parse(result);
|
||||
} else {
|
||||
return this.wsRequest<ApiResponse>('BOARD_ADD', 'BOARD_ADDED', { bidx, header, cate, title, contents });
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 게시판 수정
|
||||
* @param idx 게시판 글 인덱스
|
||||
* @param header 헤더
|
||||
* @param cate 카테고리
|
||||
* @param title 제목
|
||||
* @param contents 내용
|
||||
* @returns ApiResponse
|
||||
*/
|
||||
public async editBoard(idx: number, header: string, cate: string, title: string, contents: string): Promise<ApiResponse> {
|
||||
if (isWebView && machine) {
|
||||
const result = await machine.Board_Edit(idx, header, cate, title, contents);
|
||||
return JSON.parse(result);
|
||||
} else {
|
||||
return this.wsRequest<ApiResponse>('BOARD_EDIT', 'BOARD_EDITED', { idx, header, cate, title, contents });
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 게시판 삭제
|
||||
* @param idx 게시판 글 인덱스
|
||||
* @returns ApiResponse
|
||||
*/
|
||||
public async deleteBoard(idx: number): Promise<ApiResponse> {
|
||||
if (isWebView && machine) {
|
||||
const result = await machine.Board_Delete(idx);
|
||||
return JSON.parse(result);
|
||||
} else {
|
||||
return this.wsRequest<ApiResponse>('BOARD_DELETE', 'BOARD_DELETED', { idx });
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 메일 발신 내역 조회
|
||||
* @param startDate 시작일 (yyyy-MM-dd)
|
||||
|
||||
@@ -87,15 +87,73 @@ export function PatchList() {
|
||||
if (!editFormData) return;
|
||||
|
||||
try {
|
||||
// TODO: Board_Edit API 구현 필요
|
||||
alert('게시판 수정 API가 아직 구현되지 않았습니다.');
|
||||
console.log('수정할 데이터:', editFormData);
|
||||
const isNew = editFormData.idx === 0;
|
||||
|
||||
if (isNew) {
|
||||
// 신규 등록
|
||||
const response = await comms.addBoard(
|
||||
5, // bidx: 패치내역
|
||||
editFormData.header || '',
|
||||
editFormData.cate || '',
|
||||
editFormData.title || '',
|
||||
editFormData.contents || ''
|
||||
);
|
||||
|
||||
if (response.Success) {
|
||||
alert('등록되었습니다.');
|
||||
setShowEditModal(false);
|
||||
setEditFormData(null);
|
||||
loadData();
|
||||
} else {
|
||||
alert(response.Message || '등록에 실패했습니다.');
|
||||
}
|
||||
} else {
|
||||
// 수정
|
||||
const response = await comms.editBoard(
|
||||
editFormData.idx,
|
||||
editFormData.header || '',
|
||||
editFormData.cate || '',
|
||||
editFormData.title || '',
|
||||
editFormData.contents || ''
|
||||
);
|
||||
|
||||
if (response.Success) {
|
||||
alert('수정되었습니다.');
|
||||
setShowEditModal(false);
|
||||
setEditFormData(null);
|
||||
loadData();
|
||||
} else {
|
||||
alert(response.Message || '수정에 실패했습니다.');
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('저장 오류:', error);
|
||||
alert('저장 중 오류가 발생했습니다.');
|
||||
}
|
||||
};
|
||||
|
||||
const handleDelete = async () => {
|
||||
if (!editFormData || editFormData.idx === 0) return;
|
||||
|
||||
if (!confirm('정말 삭제하시겠습니까?')) return;
|
||||
|
||||
try {
|
||||
const response = await comms.deleteBoard(editFormData.idx);
|
||||
|
||||
if (response.Success) {
|
||||
alert('삭제되었습니다.');
|
||||
setShowEditModal(false);
|
||||
setEditFormData(null);
|
||||
loadData();
|
||||
} else {
|
||||
alert(response.Message || '삭제에 실패했습니다.');
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('삭제 오류:', error);
|
||||
alert('삭제 중 오류가 발생했습니다.');
|
||||
}
|
||||
};
|
||||
|
||||
const formatDate = (dateStr: string | null) => {
|
||||
if (!dateStr) return '-';
|
||||
try {
|
||||
@@ -359,19 +417,31 @@ export function PatchList() {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="flex items-center justify-end gap-2 px-6 py-4 border-t border-white/10 bg-white/5">
|
||||
<button
|
||||
onClick={() => setShowEditModal(false)}
|
||||
className="px-4 py-2 rounded-lg bg-white/10 hover:bg-white/20 text-white transition-colors"
|
||||
>
|
||||
취소
|
||||
</button>
|
||||
<button
|
||||
onClick={handleEditSave}
|
||||
className="px-4 py-2 rounded-lg bg-primary-500 hover:bg-primary-600 text-white transition-colors"
|
||||
>
|
||||
저장
|
||||
</button>
|
||||
<div className="flex items-center justify-between px-6 py-4 border-t border-white/10 bg-white/5">
|
||||
<div>
|
||||
{editFormData && editFormData.idx > 0 && (
|
||||
<button
|
||||
onClick={handleDelete}
|
||||
className="px-4 py-2 rounded-lg bg-red-500 hover:bg-red-600 text-white transition-colors"
|
||||
>
|
||||
삭제
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
<div className="flex items-center gap-2">
|
||||
<button
|
||||
onClick={() => setShowEditModal(false)}
|
||||
className="px-4 py-2 rounded-lg bg-white/10 hover:bg-white/20 text-white transition-colors"
|
||||
>
|
||||
취소
|
||||
</button>
|
||||
<button
|
||||
onClick={handleEditSave}
|
||||
className="px-4 py-2 rounded-lg bg-primary-500 hover:bg-primary-600 text-white transition-colors"
|
||||
>
|
||||
저장
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -459,6 +459,9 @@ export interface MachineBridgeInterface {
|
||||
// Board API (게시판 - 패치내역 등)
|
||||
Board_GetList(bidx: number, searchKey: string): Promise<string>;
|
||||
Board_GetDetail(idx: number): Promise<string>;
|
||||
Board_Add(bidx: number, header: string, cate: string, title: string, contents: string): Promise<string>;
|
||||
Board_Edit(idx: number, header: string, cate: string, title: string, contents: string): Promise<string>;
|
||||
Board_Delete(idx: number): Promise<string>;
|
||||
|
||||
// Mail API (메일 발신 내역)
|
||||
Mail_GetList(startDate: string, endDate: string, searchKey: string): Promise<string>;
|
||||
|
||||
Reference in New Issue
Block a user