mirror of
https://github.com/hwanny1128/HGZero.git
synced 2025-12-06 11:26:25 +00:00
Feat: 회의록 수정 API 개발
This commit is contained in:
parent
7e2094bcbc
commit
f1e9565d5b
File diff suppressed because it is too large
Load Diff
@ -1,6 +1,9 @@
|
||||
package com.unicorn.hgzero.meeting.biz.service;
|
||||
|
||||
import com.unicorn.hgzero.common.exception.BusinessException;
|
||||
import com.unicorn.hgzero.common.exception.ErrorCode;
|
||||
import com.unicorn.hgzero.meeting.biz.domain.AgendaSection;
|
||||
import com.unicorn.hgzero.meeting.infra.dto.request.UpdateAgendaSectionsRequest;
|
||||
import com.unicorn.hgzero.meeting.infra.gateway.entity.AgendaSectionEntity;
|
||||
import com.unicorn.hgzero.meeting.infra.gateway.repository.AgendaSectionRepository;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
@ -88,4 +91,50 @@ public class AgendaSectionService {
|
||||
.map(AgendaSectionEntity::toDomain)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
/**
|
||||
* 안건 섹션 요약 수정
|
||||
* @param agendaId 안건 ID
|
||||
* @param summary 새로운 요약 내용
|
||||
* @return 수정된 안건 섹션
|
||||
*/
|
||||
@Transactional
|
||||
public AgendaSection updateAgendaSummary(String agendaId, String summary) {
|
||||
log.info("안건 섹션 요약 수정 - agendaId: {}, summary length: {}",
|
||||
agendaId, summary != null ? summary.length() : 0);
|
||||
|
||||
// 먼저 존재 여부 확인
|
||||
AgendaSectionEntity entity = agendaSectionRepository.findById(agendaId)
|
||||
.orElseThrow(() -> new BusinessException(ErrorCode.AGENDA_SECTION_NOT_FOUND,
|
||||
"안건 섹션을 찾을 수 없습니다: " + agendaId));
|
||||
|
||||
// Native Query로 summary만 업데이트
|
||||
agendaSectionRepository.updateSummaryById(agendaId, summary);
|
||||
|
||||
// 업데이트된 엔티티 다시 조회
|
||||
AgendaSectionEntity updatedEntity = agendaSectionRepository.findById(agendaId)
|
||||
.orElseThrow(() -> new BusinessException(ErrorCode.AGENDA_SECTION_NOT_FOUND,
|
||||
"업데이트된 안건 섹션을 찾을 수 없습니다: " + agendaId));
|
||||
|
||||
log.info("안건 섹션 요약 수정 완료 - agendaId: {}", agendaId);
|
||||
return updatedEntity.toDomain();
|
||||
}
|
||||
|
||||
/**
|
||||
* 여러 안건 섹션의 요약을 한 번에 수정
|
||||
* @param updateItems 안건 ID와 새로운 요약 내용의 목록
|
||||
* @return 수정된 안건 섹션 목록
|
||||
*/
|
||||
@Transactional
|
||||
public List<AgendaSection> updateMultipleAgendaSummaries(
|
||||
List<UpdateAgendaSectionsRequest.AgendaUpdateItem> updateItems) {
|
||||
log.info("안건 섹션 일괄 수정 - 개수: {}", updateItems.size());
|
||||
|
||||
List<AgendaSection> updatedSections = updateItems.stream()
|
||||
.map(item -> updateAgendaSummary(item.getAgendaId(), item.getContent()))
|
||||
.collect(Collectors.toList());
|
||||
|
||||
log.info("안건 섹션 일괄 수정 완료 - 개수: {}", updatedSections.size());
|
||||
return updatedSections;
|
||||
}
|
||||
}
|
||||
@ -14,6 +14,7 @@ import com.unicorn.hgzero.meeting.biz.service.MinutesSectionService;
|
||||
import com.unicorn.hgzero.meeting.biz.service.TodoService;
|
||||
import com.unicorn.hgzero.meeting.biz.service.AgendaSectionService;
|
||||
import com.unicorn.hgzero.meeting.infra.dto.request.UpdateMinutesRequest;
|
||||
import com.unicorn.hgzero.meeting.infra.dto.request.UpdateAgendaSectionsRequest;
|
||||
import com.unicorn.hgzero.meeting.infra.dto.response.MinutesDetailResponse;
|
||||
import com.unicorn.hgzero.meeting.infra.dto.response.MinutesListResponse;
|
||||
import com.unicorn.hgzero.meeting.infra.cache.CacheService;
|
||||
@ -415,6 +416,54 @@ public class MinutesController {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 회의록 안건별 수정
|
||||
* PUT /api/minutes/{minutesId}/agenda-sections
|
||||
*/
|
||||
@PutMapping("/{minutesId}/agenda-sections")
|
||||
@Operation(summary = "회의록 안건별 수정",
|
||||
description = "회의록의 안건별 내용을 수정합니다. 각 안건의 summary 필드만 업데이트됩니다.")
|
||||
@ApiResponses({
|
||||
@io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "200", description = "성공"),
|
||||
@io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "400", description = "잘못된 요청"),
|
||||
@io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "403", description = "권한 없음"),
|
||||
@io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "404", description = "회의록을 찾을 수 없음")
|
||||
})
|
||||
public ResponseEntity<ApiResponse<String>> updateAgendaSections(
|
||||
@RequestHeader("X-User-Id") String userId,
|
||||
@RequestHeader(value = "X-User-Name", defaultValue = "System") String userName,
|
||||
@PathVariable String minutesId,
|
||||
@Valid @RequestBody UpdateAgendaSectionsRequest request) {
|
||||
|
||||
log.info("[API] 회의록 안건별 수정 요청 - userId: {}, minutesId: {}, agendaCount: {}",
|
||||
userId, minutesId, request.getAgendas().size());
|
||||
|
||||
try {
|
||||
// 권한 검증 제거 - 모든 사용자가 수정 가능
|
||||
log.info("회의록 수정 권한 검증 스킵 - 모든 사용자 수정 가능");
|
||||
|
||||
// 안건별 내용 수정
|
||||
List<AgendaSection> updatedSections = agendaSectionService.updateMultipleAgendaSummaries(request.getAgendas());
|
||||
|
||||
// 캐시 무효화
|
||||
cacheService.evictCacheMinutesDetail(minutesId);
|
||||
|
||||
log.info("회의록 안건별 수정 성공 - minutesId: {}, updatedCount: {}",
|
||||
minutesId, updatedSections.size());
|
||||
|
||||
return ResponseEntity.ok(ApiResponse.success("회의록이 성공적으로 수정되었습니다"));
|
||||
|
||||
} catch (BusinessException e) {
|
||||
log.error("회의록 안건별 수정 실패 - 비즈니스 예외 - minutesId: {}", minutesId, e);
|
||||
return ResponseEntity.badRequest()
|
||||
.body(ApiResponse.errorWithType(e.getMessage()));
|
||||
} catch (Exception e) {
|
||||
log.error("회의록 안건별 수정 실패 - minutesId: {}", minutesId, e);
|
||||
return ResponseEntity.badRequest()
|
||||
.body(ApiResponse.errorWithType("회의록 수정에 실패했습니다"));
|
||||
}
|
||||
}
|
||||
|
||||
// Helper methods
|
||||
|
||||
/**
|
||||
|
||||
@ -0,0 +1,44 @@
|
||||
package com.unicorn.hgzero.meeting.infra.dto.request;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 회의록 안건별 수정 요청 DTO
|
||||
*/
|
||||
@Getter
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class UpdateAgendaSectionsRequest {
|
||||
|
||||
/**
|
||||
* 수정할 안건 목록
|
||||
*/
|
||||
@NotNull(message = "안건 목록은 필수입니다")
|
||||
private List<AgendaUpdateItem> agendas;
|
||||
|
||||
@Getter
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public static class AgendaUpdateItem {
|
||||
/**
|
||||
* 안건 ID (agenda_sections.id)
|
||||
*/
|
||||
@NotBlank(message = "안건 ID는 필수입니다")
|
||||
private String agendaId;
|
||||
|
||||
/**
|
||||
* 안건 내용 (agenda_sections.summary)
|
||||
*/
|
||||
@NotBlank(message = "안건 내용은 필수입니다")
|
||||
private String content;
|
||||
}
|
||||
}
|
||||
@ -7,6 +7,8 @@ import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
import org.hibernate.annotations.JdbcTypeCode;
|
||||
import org.hibernate.type.SqlTypes;
|
||||
|
||||
/**
|
||||
* 안건별 회의록 섹션 Entity
|
||||
@ -39,9 +41,11 @@ public class AgendaSectionEntity extends BaseTimeEntity {
|
||||
@Column(name = "ai_summary_short", columnDefinition = "TEXT")
|
||||
private String aiSummaryShort;
|
||||
|
||||
@JdbcTypeCode(SqlTypes.JSON)
|
||||
@Column(name = "pending_items", columnDefinition = "json")
|
||||
private String pendingItems;
|
||||
|
||||
@JdbcTypeCode(SqlTypes.JSON)
|
||||
@Column(name = "todos", columnDefinition = "json")
|
||||
private String todos;
|
||||
|
||||
@ -84,4 +88,11 @@ public class AgendaSectionEntity extends BaseTimeEntity {
|
||||
.build();
|
||||
}
|
||||
|
||||
/**
|
||||
* 요약 내용 업데이트
|
||||
*/
|
||||
public void updateSummary(String summary) {
|
||||
this.summary = summary;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -2,6 +2,9 @@ package com.unicorn.hgzero.meeting.infra.gateway.repository;
|
||||
|
||||
import com.unicorn.hgzero.meeting.infra.gateway.entity.AgendaSectionEntity;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.data.jpa.repository.Modifying;
|
||||
import org.springframework.data.jpa.repository.Query;
|
||||
import org.springframework.data.repository.query.Param;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
import java.util.List;
|
||||
@ -25,4 +28,14 @@ public interface AgendaSectionRepository extends JpaRepository<AgendaSectionEnti
|
||||
* @return 안건 섹션 목록
|
||||
*/
|
||||
List<AgendaSectionEntity> findByMeetingIdOrderByAgendaNumber(String meetingId);
|
||||
|
||||
/**
|
||||
* 안건 섹션 요약 업데이트 (Native Query 사용)
|
||||
* @param agendaId 안건 ID
|
||||
* @param summary 요약 내용
|
||||
*/
|
||||
@Modifying
|
||||
@Query(value = "UPDATE agenda_sections SET summary = :summary, updated_at = CURRENT_TIMESTAMP WHERE id = :agendaId",
|
||||
nativeQuery = true)
|
||||
void updateSummaryById(@Param("agendaId") String agendaId, @Param("summary") String summary);
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user