게시물 삭제 기능 추가.

master
강석 최 2021-12-17 15:17:15 +09:00
parent 93da80a1ff
commit bde144db79
12 changed files with 98 additions and 29 deletions

View File

@ -8,22 +8,20 @@ import java.util.HashMap;
@AllArgsConstructor
@Getter
public enum LogStatus {
WRITE("WRITE", "작성"),
MODIFY("MODIFY", "수정"),
MOVE("MOVE", "이동"),
DELETE("DELETE", "삭제"),
FILE_ADD("FILE_ADD", "파일추가"),
FILE_REMOVE("FILE_REMOVE", "파일삭제"),
FILE_DOWN("FILE_DOWN", "파일다운로드");
WRITE("작성"),
MODIFY("수정"),
MOVE("이동"),
DELETE("삭제"),
FILE_ADD("파일추가"),
FILE_REMOVE("파일삭제"),
FILE_DOWN("파일다운로드");
private String key;
private String value;
public static HashMap<String, String> getStatusMap(){
HashMap<String, String> statusMap = new HashMap<>();
for(LogStatus status: LogStatus.values()){
statusMap.put(status.getKey(), status.getValue());
statusMap.put(status.name(), status.getValue());
}
return statusMap;
}

View File

@ -33,8 +33,8 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests() // 페이지 권한 설정
.antMatchers("/board/**").hasRole("MEMBER") // MEMBER, ADMIN만 접근 허용
.antMatchers("/admin/**").hasRole("ADMIN") // ADMIN만 접근 허용
.antMatchers("/board/**").hasRole(Role.USER.name()) // USER, ADMIN 접근 허용
.antMatchers("/admin/**").hasRole(Role.ADMIN.name()) // ADMIN만 접근 허용
.antMatchers("/user/login").permitAll() // 로그인 페이지는 권한 없이 접근 허용
.and() // 로그인 설정
.formLogin() .loginPage("/user/login") // Custom login form 사용

View File

@ -7,6 +7,7 @@ import com.dbnt.kcgfilemanager.model.UserInfo;
import com.dbnt.kcgfilemanager.service.BoardService;
import lombok.RequiredArgsConstructor;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.util.FileCopyUtils;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartHttpServletRequest;
@ -62,10 +63,11 @@ public class BoardController {
}
@GetMapping("/selectBoardContent")
public ModelAndView selectBoardContent(Board content){
public ModelAndView selectBoardContent(Board content, @AuthenticationPrincipal UserInfo loginUser){
ModelAndView mav = new ModelAndView("board/contentDetail");
Board target = boardService.selectContentByContentSeqAndViewCntUp(content.getContentSeq());
mav.addObject("content", boardService.SelectContentForeignAttribute(target));
mav.addObject("loginUser", loginUser);
return mav;
}
@GetMapping("/selectBoardLog")
@ -76,6 +78,10 @@ public class BoardController {
mav.addObject("logList", boardService.selectContentLog(content.getContentSeq()));
return mav;
}
@DeleteMapping("/deleteContent")
public Integer deleteContent(Board content, @AuthenticationPrincipal UserInfo loginUser){
return boardService.deleteContent(content, loginUser);
}
@GetMapping("/fileDownload")
public void fileDownload(Principal principal, Integer contentSeq, Integer fileSeq, HttpServletRequest request, HttpServletResponse response){

View File

@ -3,6 +3,8 @@ package com.dbnt.kcgfilemanager.repository;
import com.dbnt.kcgfilemanager.model.HashTagLink;
import org.springframework.data.jpa.repository.JpaRepository;
public interface HashTagLinkRepository extends JpaRepository<HashTagLink, HashTagLink.HashTagLinkId> {
import java.util.List;
public interface HashTagLinkRepository extends JpaRepository<HashTagLink, HashTagLink.HashTagLinkId> {
List<HashTagLink> findByContentSeq(int contentSeq);
}

View File

@ -42,7 +42,7 @@ public class BoardService {
BoardLog log = new BoardLog();
log.setContentSeq(contentSeq);
log.setLogSeq(lastLog == null?1:(lastLog.getLogSeq()+1));
log.setLogStatus(status.getKey());
log.setLogStatus(status.name());
log.setDescription(description);
log.setCreateId(createId);
boardLogRepository.save(log);
@ -126,7 +126,9 @@ public class BoardService {
@Transactional
public Board selectContentByContentSeqAndViewCntUp(Integer contentSeq) {
Board target = boardRepository.findById(contentSeq).orElse(null);
target.setViewCnt(target.getViewCnt()+1);
if(target.getStatus()==null){
target.setViewCnt(target.getViewCnt()+1);
}
return target;
}
@ -157,6 +159,32 @@ public class BoardService {
return target;
}
@Transactional
public Integer deleteContent(Board content, UserInfo user) {
int contentSeq = content.getContentSeq();
content = boardRepository.findById(contentSeq).orElse(null);
content.setTitle("삭제된 게시물");
content.setDescription(null);
content.setStatus("D");
saveBoardLog(contentSeq, LogStatus.DELETE, null, user.getUserId());
deleteHashTagLink(contentSeq);
deleteFileInfo(contentSeq);
return contentSeq;
}
private void deleteHashTagLink(int contentSeq){
List<HashTagLink> tagLinkList = hashTagLinkRepository.findByContentSeq(contentSeq);
hashTagLinkRepository.deleteAll(tagLinkList);
}
private void deleteFileInfo(int contentSeq){
List<FileInfo> fileInfoList = fileInfoRepository.findByContentSeqOrderByFileSeqAsc(contentSeq);
for(FileInfo fileInfo: fileInfoList){
File file = new File(fileInfo.getSavePath(), fileInfo.getConversionName());
file.delete();
}
fileInfoRepository.deleteAll(fileInfoList);
}
private String makeFilePath(Integer categorySeq){
BoardCategory category = boardCategoryRepository.findById(categorySeq).orElse(null);
if(category.getParentSeq()==null){
@ -169,5 +197,4 @@ public class BoardService {
double unitSelector = Math.floor(Math.log(fileSize)/Math.log(1024));
return Math.round((fileSize/Math.pow(1024, unitSelector))*100)/100d+" "+units[(int)unitSelector];
}
}

View File

@ -14,7 +14,7 @@
FROM BOARD A
INNER JOIN USER_INFO B
ON A.CREATE_ID = B.USER_ID
INNER JOIN (SELECT CONTENT_SEQ, MAX(FILE_SEQ) AS FILE_CNT
LEFT OUTER JOIN (SELECT CONTENT_SEQ, MAX(FILE_SEQ) AS FILE_CNT
FROM FILE_INFO
GROUP BY CONTENT_SEQ ) C
ON A.CONTENT_SEQ = C.CONTENT_SEQ
@ -30,11 +30,11 @@
FROM BOARD A
INNER JOIN USER_INFO B
ON A.CREATE_ID = B.USER_ID
INNER JOIN (SELECT CONTENT_SEQ, MAX(FILE_SEQ) AS FILE_CNT
LEFT OUTER JOIN (SELECT CONTENT_SEQ, MAX(FILE_SEQ) AS FILE_CNT
FROM FILE_INFO
GROUP BY CONTENT_SEQ ) C
ON A.CONTENT_SEQ = C.CONTENT_SEQ
WHERE CATEGORY_SEQ = ${categorySeq}
WHERE A.CATEGORY_SEQ = ${categorySeq}
</select>
<select id="selectHashTagListFromContentSeq" resultType="HashTag" parameterType="int">

View File

@ -49,7 +49,28 @@ $(document).on('click', '#zipDownBtn', function (){
alert("선택된 파일이 없습니다.")
}
})
$(document).on('click', '#deleteBtn', function (){
if(confirm("이 게시물을 삭제하시겠습니까?\n되돌릴 수 없습니다.")){
$.ajax({
type : 'DELETE',
url : "/board/deleteContent",
data : {contentSeq: Number($(this).attr("data-contentseq"))},
beforeSend: function (xhr){
xhr.setRequestHeader($("[name='_csrf_header']").val(), $("[name='_csrf']").val());
},
success : function(data) {
alert("저장되었습니다.");
location.reload();
},
error : function(xhr, status) {
}
})
}
})
$(document).on('click', '#modifyBtn', function (){
})
function getContentSeq(){
return $(".contentCheckBox:checked").val();
}
@ -65,8 +86,10 @@ function getBoardContent(contentSeq){
dataType:"html",
success: function(html){
$("#contentDiv").empty().append(html)
const viewCntTd = $(".contentCheckBox:checked").parents("tr").find(".viewCntTd");
viewCntTd.text(Number(viewCntTd.text())+1);
if($("#contentStatus").val() !== "D"){
const viewCntTd = $(".contentCheckBox:checked").parents("tr").find(".viewCntTd");
viewCntTd.text(Number(viewCntTd.text())+1);
}
},
error:function(){

View File

@ -68,7 +68,7 @@
<div class="mb-3 row">
<div class="col-sm-4"></div>
<div class="col-sm-auto form-check ms-3">
<input type="hidden" name="userRole" value="ROLE_MEMBER">
<input type="hidden" name="userRole" value="ROLE_USER">
<input class="form-check-input" type="checkbox" value="ROLE_ADMIN" id="roleAdmin" name="userRole" th:checked="${#strings.contains(userInfo.userRole,'ADMIN')}">
<label class="form-check-label" for="roleAdmin">관리자 계정</label>
</div>

View File

@ -210,7 +210,7 @@
<div class="mb-3 row">
<div class="col-sm-4"></div>
<div class="col-sm-auto form-check ms-3">
<input type="hidden" name="userRole" value="ROLE_MEMBER">
<input type="hidden" name="userRole" value="ROLE_USER">
<input class="form-check-input" type="checkbox" value="ROLE_ADMIN" id="roleAdmin" name="userRole">
<label class="form-check-label" for="roleAdmin">관리자 계정</label>
</div>

View File

@ -2,8 +2,9 @@
<html lang="ko" xmlns:th="http://www.thymeleaf.org">
<div class="p-3">
<input type="hidden" id="detailViewContentSeq" th:value="${content.contentSeq}">
<input type="hidden" id="contentStatus" th:value="${content.status}">
<div class="row justify-content-between">
<div class="col-auto"><h3 th:text="${content.title}"></h3></div>
<div class="col-auto"><h5 class="fw-bold" th:text="${content.title}"></h5></div>
<div class="col-auto" th:text="|조회수: ${content.viewCnt}|"></div>
</div>
<div class="row justify-content-between border-bottom pb-3">
@ -11,7 +12,7 @@
<div class="col-auto" th:text="${content.createId}"></div>
</div>
<div class="row border-bottom py-3">
<div class="col-8">
<div th:class="|col-${content.childFileList.size()>1?8:12}|">
<table class="table">
<thead>
<tr>
@ -31,7 +32,7 @@
</tbody>
</table>
</div>
<div class="col-4 my-auto">
<div class="col-4 m-auto" th:if="${content.childFileList.size()>1}">
<button type="button" class="btn btn-info m-1" id="zipDownBtn"><i class="bi bi-file-zip"></i> 선택된 파일<br>압축 다운로드</button>
</div>
</div>
@ -43,4 +44,14 @@
<div class="col-auto" th:text="'#'+${hashTag.tagName}"></div>
</th:block>
</div>
<th:block th:if="${content.createId == loginUser.userId || loginUser.userRole.contains('ADMIN')}">
<div class="row justify-content-between py-3">
<div class="col-auto">
<button class="btn btn-danger" id="deleteBtn" th:data-contentseq="${content.contentSeq}"><i class="bi bi-trash"></i> 삭제</button>
</div>
<div class="col-auto">
<button class="btn btn-warning" id="modifyBtn" th:data-contentseq="${content.contentSeq}"><i class="bi bi-pencil-square"></i> 수정</button>
</div>
</div>
</th:block>
</div>

View File

@ -9,6 +9,8 @@
</th:block>
<div layout:fragment="content">
<main class="pt-3">
<input type="hidden" name="_csrf_header" th:value="${_csrf.headerName}"/>
<input type="hidden" th:name="${_csrf.parameterName}" th:value="${_csrf.token}"/>
<h4 th:text="${pageTitle}"></h4>
<div class="row mx-0">
<div class="col-12 card">

View File

@ -8,8 +8,8 @@
<form th:action="@{/signup}" method="post">
<input type="text" name="userId" placeholder="이메일 입력해주세요" />
<input type="password" name="password" placeholder="비밀번호" />
<input type="radio" name="userRole" value="ROLE_ADMIN,ROLE_MEMBER" /> admin
<input type="radio" name="userRole" value="ROLE_MEMBER" checked="checked" />
<input type="radio" name="userRole" value="ROLE_ADMIN,ROLE_USER" /> admin
<input type="radio" name="userRole" value="ROLE_USER" checked="checked" />
member <br />
<button type="submit">가입하기</button>
</form>