Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
15 commits
Select commit Hold shift + click to select a range
addbdc0
refactor/#261: 인터셉터, μ–΄λ…Έν…Œμ΄μ…˜ μ‚¬μš©ν•œ workspace 인증/인가 둜직 μˆ˜μ •
hknhj Aug 16, 2025
a3cb1ba
refactor/#261: meeting의 μœ νš¨μ„± 및 인증/인가 μžλ™ν™”λ₯Ό μœ„ν•œ μ–΄λ…Έν…Œμ΄μ…˜
hknhj Aug 16, 2025
f892728
refactor/#261: meeting controller, service 인증/인가 μ½”λ“œ λ¦¬νŒ©ν† λ§
hknhj Aug 16, 2025
f5d4b15
refactor/#261: LastOpenedAspect 둜직 μˆ˜μ •
hknhj Aug 16, 2025
bb70481
refactor/#261: DeleteDocument μ»€μŠ€ν…€ μ–΄λ…Έν…Œμ΄μ…˜ κ΅¬ν˜„
hknhj Aug 16, 2025
9a3b5f0
refactor/#261: UpdateDocumentTitle μ–΄λ…Έν…Œμ΄μ…˜μ„ ν†΅ν•΄μ„œ, 제λͺ©μ„ μˆ˜μ •ν•˜λ©΄ μžλ™μœΌλ‘œ last ope…
hknhj Aug 17, 2025
c6a6351
Merge pull request #262 from HaRu-Developers/refactor/#261-auth-autom…
hknhj Aug 18, 2025
6a46c97
feat/#265: νšŒμ›κ°€μž… ν›„ 둜그인 API에 μ›Œν¬μŠ€νŽ˜μ΄μŠ€ μ΄ˆλŒ€ 수락 κΈ°λŠ₯ μΆ”κ°€
hknhj Aug 18, 2025
7255c7f
Merge pull request #266 from HaRu-Developers/feat/#265-accept-invite-…
hknhj Aug 18, 2025
97c216d
refactor/#267: SnsEvent μ–΄λ…Έν…Œμ΄μ…˜ 생성
hknhj Aug 18, 2025
0aedd62
refactor/#267: entity 속성 λ³€κ²½
hknhj Aug 18, 2025
93737e3
refactor/#267: 인터셉터, μ–΄λ…Έν…Œμ΄μ…˜μ„ ν™œμš©ν•˜μ—¬ controller, service, repository, dto…
hknhj Aug 18, 2025
0446e8b
Merge pull request #268 from HaRu-Developers/refactor/#267-sns-event-…
hknhj Aug 18, 2025
081b637
feat/#269: ν…ŒμŠ€νŠΈμš© μ›Ήμ†ŒμΌ“ κ΅¬ν˜„
hknhj Aug 18, 2025
9abbe68
Merge pull request #270 from HaRu-Developers/feat/#269-web-socket-for…
hknhj Aug 18, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,44 +1,22 @@
package com.haru.api.domain.lastOpened.converter;

import com.haru.api.domain.lastOpened.entity.Documentable;
import com.haru.api.domain.lastOpened.entity.UserDocumentId;
import com.haru.api.domain.lastOpened.entity.UserDocumentLastOpened;
import com.haru.api.domain.lastOpened.entity.enums.DocumentType;
import com.haru.api.domain.meeting.entity.Meeting;
import com.haru.api.domain.moodTracker.entity.MoodTracker;
import com.haru.api.domain.snsEvent.entity.SnsEvent;
import com.haru.api.domain.user.entity.User;

public class UserDocumentLastOpenedConverter {
public static UserDocumentLastOpened toUserDocumentLastOpened(Meeting meeting, User user) {
public static UserDocumentLastOpened toUserDocumentLastOpened(Documentable document, User user) {

UserDocumentId userDocumentId = new UserDocumentId(user.getId(), meeting.getId(), DocumentType.AI_MEETING_MANAGER);

return UserDocumentLastOpened.builder()
.id(userDocumentId)
.user(user)
.lastOpened(null)
.build();
}

public static UserDocumentLastOpened toUserDocumentLastOpened(SnsEvent snsEvent, User user) {

UserDocumentId userDocumentId = new UserDocumentId(user.getId(), snsEvent.getId(), DocumentType.SNS_EVENT_ASSISTANT);

return UserDocumentLastOpened.builder()
.id(userDocumentId)
.user(user)
.lastOpened(null)
.build();
}

public static UserDocumentLastOpened toUserDocumentLastOpened(MoodTracker moodTracker, User user) {

UserDocumentId userDocumentId = new UserDocumentId(user.getId(), moodTracker.getId(), DocumentType.TEAM_MOOD_TRACKER);
UserDocumentId userDocumentId = new UserDocumentId(user.getId(), document.getId(), document.getDocumentType());

return UserDocumentLastOpened.builder()
.id(userDocumentId)
.user(user)
.workspaceId(document.getWorkspaceId())
.lastOpened(null)
.thumbnailKeyName(document.getThumbnailKeyName())
.title(document.getTitle())
.build();
}
}
Original file line number Diff line number Diff line change
@@ -1,18 +1,21 @@
package com.haru.api.domain.lastOpened.service;

import com.haru.api.domain.lastOpened.entity.Documentable;
import com.haru.api.domain.lastOpened.entity.enums.DocumentType;
import com.haru.api.domain.lastOpened.entity.UserDocumentId;
import com.haru.api.domain.user.entity.User;
import com.haru.api.global.common.entity.TitleHolder;

import java.util.List;

public interface UserDocumentLastOpenedService {

void updateLastOpened(Long userId, DocumentType documentType, Long documentId, Long workspaceId, String title);
void updateLastOpened(UserDocumentId userDocumentId, Long workspaceId, String title);

void createInitialRecordsForWorkspaceUsers(List<User> usersInWorkspace, Documentable document);

void deleteRecordsForWorkspaceUsers(Documentable document);

void updateRecordsForWorkspaceUsers(Documentable document);

void updateRecordsForWorkspaceUsers(Documentable document, TitleHolder titleHolder);
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,12 @@
import com.haru.api.domain.lastOpened.entity.Documentable;
import com.haru.api.domain.lastOpened.entity.UserDocumentId;
import com.haru.api.domain.lastOpened.entity.UserDocumentLastOpened;
import com.haru.api.domain.lastOpened.entity.enums.DocumentType;
import com.haru.api.domain.lastOpened.repository.UserDocumentLastOpenedRepository;
import com.haru.api.domain.user.entity.User;
import com.haru.api.domain.user.repository.UserRepository;
import com.haru.api.global.apiPayload.code.status.ErrorStatus;
import com.haru.api.global.apiPayload.exception.handler.MemberHandler;
import com.haru.api.global.common.entity.TitleHolder;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
Expand All @@ -28,15 +28,14 @@ public class UserDocumentLastOpenedServiceImpl implements UserDocumentLastOpened

@Override
@Transactional
public void updateLastOpened(Long userId, DocumentType documentType, Long documentId, Long workspaceId, String title) {
UserDocumentId id = new UserDocumentId(userId, documentId, documentType);
public void updateLastOpened(UserDocumentId userDocumentId, Long workspaceId, String title) {

UserDocumentLastOpened record = userDocumentLastOpenedRepository.findById(id)
UserDocumentLastOpened record = userDocumentLastOpenedRepository.findById(userDocumentId)
.orElseGet(() -> {
User foundUser = userRepository.findById(userId)
User foundUser = userRepository.findById(userDocumentId.getUserId())
.orElseThrow(() -> new MemberHandler(ErrorStatus.MEMBER_NOT_FOUND));
return UserDocumentLastOpened.builder()
.id(id)
.id(userDocumentId)
.user(foundUser)
.workspaceId(workspaceId)
.title(title)
Expand All @@ -50,6 +49,7 @@ public void updateLastOpened(Long userId, DocumentType documentType, Long docume
}

@Override
@Transactional
public void createInitialRecordsForWorkspaceUsers(List<User> usersInWorkspace, Documentable document) {

// μ €μž₯ν•  μ—”ν‹°ν‹° 리슀트 생성
Expand Down Expand Up @@ -86,6 +86,20 @@ public void updateRecordsForWorkspaceUsers(Documentable documentable) {
}
}

@Override
@Transactional
public void updateRecordsForWorkspaceUsers(Documentable documentable, TitleHolder titleHolder) {

// ν•΄λ‹Ή λ¬Έμ„œ id, λ¬Έμ„œ νƒ€μž…μ— ν•΄λ‹Ήν•˜λŠ” last opened νŠœν”Œ 검색
List<UserDocumentLastOpened> recordsToUpdate = userDocumentLastOpenedRepository.findByDocumentIdAndDocumentType(documentable.getId(), documentable.getDocumentType());

if (!recordsToUpdate.isEmpty()) {
for (UserDocumentLastOpened record : recordsToUpdate) {
record.updateTitle(titleHolder.getTitle());
}
}
}

private List<UserDocumentLastOpened> recordsToProcess(List<User> usersInWorkspace, Documentable document) {
// μ²˜λ¦¬ν•  엔티티듀을 담을 리슀트 생성
List<UserDocumentLastOpened> recordsToProcess = new ArrayList<>();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,17 @@

import com.haru.api.domain.meeting.dto.MeetingRequestDTO;
import com.haru.api.domain.meeting.dto.MeetingResponseDTO;
import com.haru.api.domain.meeting.entity.Meeting;
import com.haru.api.domain.meeting.service.MeetingCommandService;
import com.haru.api.domain.meeting.service.MeetingQueryService;
import com.haru.api.domain.user.security.jwt.SecurityUtil;
import com.haru.api.domain.user.entity.User;
import com.haru.api.global.annotation.AuthMeeting;
import com.haru.api.global.annotation.AuthUser;
import com.haru.api.global.apiPayload.ApiResponse;
import com.haru.api.global.apiPayload.code.status.ErrorStatus;
import com.haru.api.global.apiPayload.exception.GeneralException;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.media.Encoding;
import lombok.RequiredArgsConstructor;
Expand Down Expand Up @@ -45,15 +49,16 @@ public class MeetingController {
)
public ApiResponse<MeetingResponseDTO.createMeetingResponse> createMeeting(
@RequestPart("agendaFile") MultipartFile agendaFile,
@RequestPart("request") MeetingRequestDTO.createMeetingRequest request) {
@RequestPart("request") MeetingRequestDTO.createMeetingRequest request,
@Parameter(hidden = true) @AuthUser User user
) {

// fileμ—…λ‘œλ“œκ°€ λ˜μ§€ μ•ŠλŠ” 경우 controllerλ‹¨μ—μ„œ μš”μ²­ 처리
if (agendaFile == null || agendaFile.isEmpty()) {
throw new GeneralException(ErrorStatus.MEETING_AGENDAFILE_NOT_FOUND);
}
Long userId = SecurityUtil.getCurrentUserId();

MeetingResponseDTO.createMeetingResponse response = meetingCommandService.createMeeting(userId, agendaFile, request);
MeetingResponseDTO.createMeetingResponse response = meetingCommandService.createMeeting(user, agendaFile, request);

return ApiResponse.onSuccess(response);
}
Expand All @@ -64,11 +69,12 @@ public ApiResponse<MeetingResponseDTO.createMeetingResponse> createMeeting(
)
@GetMapping("/workspaces/{workspaceId}")
public ApiResponse<List<MeetingResponseDTO.getMeetingResponse>> getMeetings(
@PathVariable("workspaceId") String workspaceId){

Long userId = SecurityUtil.getCurrentUserId();
@PathVariable("workspaceId") String workspaceId,
@Parameter(hidden = true) @AuthUser User user,
@Parameter(hidden = true) @AuthMeeting Meeting meeting
) {

List<MeetingResponseDTO.getMeetingResponse> response = meetingQueryService.getMeetings(userId, Long.parseLong(workspaceId));
List<MeetingResponseDTO.getMeetingResponse> response = meetingQueryService.getMeetings(user, meeting);

return ApiResponse.onSuccess(response);
}
Expand All @@ -79,11 +85,12 @@ public ApiResponse<List<MeetingResponseDTO.getMeetingResponse>> getMeetings(
@PatchMapping("/{meetingId}/title")
public ApiResponse<String> updateMeetingTitle(
@PathVariable("meetingId")String meetingId,
@RequestBody MeetingRequestDTO.updateTitle request) {

Long userId = SecurityUtil.getCurrentUserId();
@RequestBody MeetingRequestDTO.updateTitle request,
@Parameter(hidden = true) @AuthUser User user,
@Parameter(hidden = true) @AuthMeeting Meeting meeting
) {

meetingCommandService.updateMeetingTitle(userId, Long.parseLong(meetingId), request.getTitle());
meetingCommandService.updateMeetingTitle(user, meeting, request);

return ApiResponse.onSuccess("제λͺ©μˆ˜μ •이 μ™„λ£Œλ˜μ—ˆμŠ΅λ‹ˆλ‹€.");
}
Expand All @@ -93,11 +100,12 @@ public ApiResponse<String> updateMeetingTitle(
)
@DeleteMapping("/{meetingId}")
public ApiResponse<String> deleteMeeting(
@PathVariable("meetingId") String meetingId) {

Long userId = SecurityUtil.getCurrentUserId();
@PathVariable("meetingId") String meetingId,
@Parameter(hidden = true) @AuthUser User user,
@Parameter(hidden = true) @AuthMeeting Meeting meeting
) {

meetingCommandService.deleteMeeting(userId, Long.parseLong(meetingId));
meetingCommandService.deleteMeeting(user, meeting);

return ApiResponse.onSuccess("νšŒμ˜κ°€ μ‚­μ œλ˜μ—ˆμŠ΅λ‹ˆλ‹€.");
}
Expand All @@ -107,12 +115,15 @@ public ApiResponse<String> deleteMeeting(
)
@GetMapping("/{meetingId}/ai-proceeding")
public ApiResponse<MeetingResponseDTO.getMeetingProceeding> getMeetingProceeding(
@PathVariable("meetingId")String meetingId) {
@PathVariable("meetingId")String meetingId,
@Parameter(hidden = true) @AuthUser User user,
@Parameter(hidden = true) @AuthMeeting Meeting meeting
) {

Long userId = SecurityUtil.getCurrentUserId();
MeetingResponseDTO.getMeetingProceeding response = meetingQueryService.getMeetingProceeding(userId, Long.parseLong(meetingId));
MeetingResponseDTO.getMeetingProceeding response = meetingQueryService.getMeetingProceeding(user, meeting);

return ApiResponse.onSuccess(response);

}


Expand All @@ -122,13 +133,15 @@ public ApiResponse<MeetingResponseDTO.getMeetingProceeding> getMeetingProceeding
@PatchMapping("/{meetingId}")
public ApiResponse<String> adjustProceeding(
@PathVariable("meetingId") String meetingId,
@RequestBody MeetingRequestDTO.meetingProceedingRequest request) {

Long userId = SecurityUtil.getCurrentUserId();
@RequestBody MeetingRequestDTO.meetingProceedingRequest request,
@Parameter(hidden = true) @AuthUser User user,
@Parameter(hidden = true) @AuthMeeting Meeting meeting
) {

meetingCommandService.adjustProceeding(userId, Long.parseLong(meetingId), request);
meetingCommandService.adjustProceeding(user, meeting, request);

return ApiResponse.onSuccess("νšŒμ˜κ°€ μˆ˜μ •λ˜μ—ˆμŠ΅λ‹ˆλ‹€.");

}

@Operation(summary = "회의 μ’…λ£Œ", description =
Expand All @@ -137,13 +150,15 @@ public ApiResponse<String> adjustProceeding(
)
@PostMapping("/{meetingId}/end")
public ApiResponse<String> endMeeting(
@PathVariable("meetindId") String meetingId
@PathVariable("meetingId") String meetingId,
@Parameter(hidden = true) @AuthUser User user,
@Parameter(hidden = true) @AuthMeeting Meeting meeting
) {
Long userId = SecurityUtil.getCurrentUserId();

meetingCommandService.endMeeting(userId, Long.parseLong(meetingId));
meetingCommandService.endMeeting(user, meeting);

return ApiResponse.onSuccess("νšŒμ˜κ°€ μ’…λ£Œλ˜μ—ˆμŠ΅λ‹ˆλ‹€");

}

@Operation(summary = "회의둝 λ‹€μš΄λ‘œλ“œ", description =
Expand All @@ -152,13 +167,15 @@ public ApiResponse<String> endMeeting(
)
@GetMapping("{meetingId}/ai-proceeding/download")
public ApiResponse<MeetingResponseDTO.proceedingDownLoadLinkResponse> downloadMeeting(
@PathVariable("meetingId") String meetingId
@PathVariable("meetingId") String meetingId,
@Parameter(hidden = true) @AuthUser User user,
@Parameter(hidden = true) @AuthMeeting Meeting meeting
){
Long userId = SecurityUtil.getCurrentUserId();

MeetingResponseDTO.proceedingDownLoadLinkResponse response = meetingQueryService.downloadMeeting(userId, Long.parseLong(meetingId));
MeetingResponseDTO.proceedingDownLoadLinkResponse response = meetingQueryService.downloadMeeting(user, meeting);

return ApiResponse.onSuccess(response);

}


Expand All @@ -168,15 +185,16 @@ public ApiResponse<MeetingResponseDTO.proceedingDownLoadLinkResponse> downloadMe
)
@GetMapping("/{meetingId}/transcript")
public ApiResponse<MeetingResponseDTO.TranscriptResponse> getMeetingTranscript(
@PathVariable("meetingId") String meetingId
@PathVariable("meetingId") String meetingId,
@Parameter(hidden = true) @AuthUser User user,
@Parameter(hidden = true) @AuthMeeting Meeting meeting
) {
Long userId = SecurityUtil.getCurrentUserId();

MeetingResponseDTO.TranscriptResponse transcriptResponse = meetingQueryService.getTranscript(userId, Long.parseLong(meetingId));
MeetingResponseDTO.TranscriptResponse transcriptResponse = meetingQueryService.getTranscript(user, meeting);

return ApiResponse.onSuccess(transcriptResponse);
}

}


@Operation(summary = "회의둝 μŒμ„±νŒŒμΌ 쑰회API", description =
Expand All @@ -185,12 +203,14 @@ public ApiResponse<MeetingResponseDTO.TranscriptResponse> getMeetingTranscript(
)
@GetMapping("{meetingId}/ai-proceeding/voice")
public ApiResponse<MeetingResponseDTO.proceedingVoiceLinkResponse> MeetingvoiceFile(
@PathVariable("meetingId") String meetingId
@PathVariable("meetingId") String meetingId,
@Parameter(hidden = true) @AuthUser User user,
@Parameter(hidden = true) @AuthMeeting Meeting meeting
){
Long userId = SecurityUtil.getCurrentUserId();

MeetingResponseDTO.proceedingVoiceLinkResponse response = meetingQueryService.MeetingVoiceFile(userId, Long.parseLong(meetingId));
MeetingResponseDTO.proceedingVoiceLinkResponse response = meetingQueryService.getMeetingVoiceFile(user, meeting);

return ApiResponse.onSuccess(response);

}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.haru.api.domain.meeting.dto;

import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.haru.api.global.common.entity.TitleHolder;
import com.haru.api.global.util.json.ToLongDeserializer;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.AllArgsConstructor;
Expand All @@ -21,7 +22,7 @@ public static class createMeetingRequest{
private String title;
}
@Getter
public static class updateTitle {
public static class updateTitle implements TitleHolder {
private String title;
}

Expand Down
11 changes: 4 additions & 7 deletions src/main/java/com/haru/api/domain/meeting/entity/Meeting.java
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ public class Meeting extends BaseEntity implements Documentable {
@Column(columnDefinition="TEXT")
private String proceeding;

@ManyToOne(fetch = FetchType.LAZY)
@ManyToOne(fetch = FetchType.EAGER)
@JoinColumn(name = "user_id")
private User creator;

Expand All @@ -49,7 +49,7 @@ public class Meeting extends BaseEntity implements Documentable {
private String proceedingKeyName;

@Column(columnDefinition = "TEXT")
private String thumbnailKey;
private String thumbnailKeyName;

@OneToMany(mappedBy = "meeting", cascade = CascadeType.ALL, orphanRemoval = true)
private List<MeetingKeyword> meetingKeywords = new ArrayList<>();
Expand All @@ -61,9 +61,6 @@ public class Meeting extends BaseEntity implements Documentable {
@Setter
private String audioFileKey;

@Column(columnDefinition = "TEXT")
private String thumbnailKeyName;

private Meeting(String title, String agendaResult, User user, Workspace workspace) {
this.title = title;
this.agendaResult = agendaResult;
Expand All @@ -80,8 +77,8 @@ public void updateTitle(String title) {
public void updateProceeding(String proceeding) {
this.proceeding = proceeding;
}
public void initProceedingKeyName(String proceedingKeyName) {this.proceedingKeyName = proceedingKeyName;}
public void initThumbnailKey(String thumbnailKey) {this.thumbnailKey = thumbnailKey;}
public void initProceedingKeyName(String proceedingKeyName) { this.proceedingKeyName = proceedingKeyName; }
public void initThumbnailKeyName(String thumbnailKeyName) { this.thumbnailKeyName = thumbnailKeyName; }
public void initStartTime(LocalDateTime startTime) {
this.startTime = startTime;
}
Expand Down
Loading