Skip to content

Commit 67a353c

Browse files
authored
Merge pull request #397 from depromeet/develop
v1.3.9
2 parents a10e3ac + 5b5377d commit 67a353c

File tree

11 files changed

+188
-42
lines changed

11 files changed

+188
-42
lines changed
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
package org.layer.admin.space.entity;
2+
3+
import java.time.LocalDateTime;
4+
5+
import jakarta.persistence.Entity;
6+
import jakarta.persistence.GeneratedValue;
7+
import jakarta.persistence.GenerationType;
8+
import jakarta.persistence.Id;
9+
import jakarta.validation.constraints.NotNull;
10+
import lombok.AccessLevel;
11+
import lombok.Builder;
12+
import lombok.Getter;
13+
import lombok.NoArgsConstructor;
14+
15+
@Entity
16+
@NoArgsConstructor(access = AccessLevel.PROTECTED)
17+
@Getter
18+
public class AdminMemberSpaceHistory {
19+
@Id
20+
@GeneratedValue(strategy = GenerationType.IDENTITY)
21+
private Long id;
22+
23+
@NotNull
24+
private LocalDateTime eventTime;
25+
26+
@NotNull
27+
private Long memberId;
28+
29+
@NotNull
30+
private String eventId;
31+
32+
@NotNull
33+
private Long spaceId;
34+
35+
@Builder
36+
private AdminMemberSpaceHistory(
37+
LocalDateTime eventTime,
38+
Long memberId,
39+
String eventId,
40+
Long spaceId
41+
) {
42+
this.eventTime = eventTime;
43+
this.memberId = memberId;
44+
this.eventId = eventId;
45+
this.spaceId = spaceId;
46+
}
47+
48+
49+
}

layer-admin/src/main/java/org/layer/admin/space/entity/AdminSpaceHistory.java

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,15 +33,25 @@ public class AdminSpaceHistory {
3333
@NotNull
3434
private String eventId;
3535

36+
@NotNull
37+
private Long spaceId;
38+
3639
@NotNull
3740
@Enumerated(EnumType.STRING)
3841
private AdminSpaceCategory category;
3942

4043
@Builder
41-
private AdminSpaceHistory(LocalDateTime eventTime, Long memberId, String eventId, AdminSpaceCategory category) {
44+
private AdminSpaceHistory(
45+
LocalDateTime eventTime,
46+
Long memberId,
47+
String eventId,
48+
Long spaceId,
49+
AdminSpaceCategory category
50+
) {
4251
this.eventTime = eventTime;
4352
this.memberId = memberId;
4453
this.eventId = eventId;
54+
this.spaceId = spaceId;
4555
this.category = category;
4656
}
4757
}

layer-admin/src/main/java/org/layer/admin/space/listener/CreateSpaceEventListener.java renamed to layer-admin/src/main/java/org/layer/admin/space/listener/SpaceEventListener.java

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,18 +2,30 @@
22

33
import org.layer.admin.space.service.AdminSpaceService;
44
import org.layer.event.space.CreateSpaceEvent;
5+
import org.layer.event.space.JoinSpaceEvent;
6+
import org.layer.event.space.LeaveSpaceEvent;
57
import org.springframework.context.event.EventListener;
68
import org.springframework.stereotype.Component;
79

810
import lombok.RequiredArgsConstructor;
911

1012
@Component
1113
@RequiredArgsConstructor
12-
public class CreateSpaceEventListener {
14+
public class SpaceEventListener {
1315
private final AdminSpaceService adminSpaceService;
1416

1517
@EventListener
1618
public void handleSignUp(CreateSpaceEvent event) {
1719
adminSpaceService.saveSpaceHistory(event);
1820
}
21+
22+
@EventListener
23+
public void handleJoinSpace(JoinSpaceEvent event) {
24+
adminSpaceService.saveMemberSpaceHistory(event);
25+
}
26+
27+
@EventListener
28+
public void handleLeaveSpace(LeaveSpaceEvent event) {
29+
adminSpaceService.deleteMemberSpaceHistory(event);
30+
}
1931
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
package org.layer.admin.space.repository;
2+
3+
import org.layer.admin.space.entity.AdminMemberSpaceHistory;
4+
import org.springframework.data.jpa.repository.JpaRepository;
5+
6+
public interface AdminMemberSpaceRepository extends JpaRepository<AdminMemberSpaceHistory, Long>, AdminMemberSpaceRepositoryCustom {
7+
void deleteByMemberIdAndSpaceId(Long memberId, Long spaceId);
8+
}

layer-admin/src/main/java/org/layer/admin/space/repository/AdminSpaceRepositoryCustom.java renamed to layer-admin/src/main/java/org/layer/admin/space/repository/AdminMemberSpaceRepositoryCustom.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
import org.springframework.data.domain.Page;
77
import org.springframework.data.domain.Pageable;
88

9-
public interface AdminSpaceRepositoryCustom {
9+
public interface AdminMemberSpaceRepositoryCustom {
1010
Page<TeamSpaceRatioPerMemberDto> findTeamSpaceRatioPerMemberWithPeriod(LocalDateTime startTime,
1111
LocalDateTime endTime, Pageable pageable);
1212

layer-admin/src/main/java/org/layer/admin/space/repository/AdminSpaceRepositoryImpl.java renamed to layer-admin/src/main/java/org/layer/admin/space/repository/AdminMemberSpaceRepositoryImpl.java

Lines changed: 14 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -12,20 +12,21 @@
1212
import lombok.RequiredArgsConstructor;
1313

1414
@RequiredArgsConstructor
15-
public class AdminSpaceRepositoryImpl implements AdminSpaceRepositoryCustom {
15+
public class AdminMemberSpaceRepositoryImpl implements AdminMemberSpaceRepositoryCustom {
1616

1717
private final EntityManager em;
1818

1919
@Override
2020
public Page<TeamSpaceRatioPerMemberDto> findTeamSpaceRatioPerMemberWithPeriod(LocalDateTime start, LocalDateTime end, Pageable pageable) {
2121
String sql = """
22-
SELECT ash.member_id AS memberId,
22+
SELECT amsh.member_id AS memberId,
2323
COUNT(*) AS totalCount,
2424
SUM(CASE WHEN ash.category = 'TEAM' THEN 1 ELSE 0 END) AS teamCount
25-
FROM admin_space_history ash
26-
WHERE ash.event_time BETWEEN :startTime AND :endTime
27-
GROUP BY ash.member_id
28-
ORDER BY ash.member_id
25+
FROM admin_member_space_history amsh
26+
JOIN admin_space_history ash ON amsh.space_id = ash.space_id
27+
WHERE amsh.event_time BETWEEN :startTime AND :endTime
28+
GROUP BY amsh.member_id
29+
ORDER BY amsh.member_id
2930
LIMIT :limit OFFSET :offset
3031
""";
3132

@@ -46,9 +47,9 @@ public Page<TeamSpaceRatioPerMemberDto> findTeamSpaceRatioPerMemberWithPeriod(Lo
4647

4748
// 전체 멤버 수 (조건 포함)
4849
Long total = ((Number) em.createNativeQuery("""
49-
SELECT COUNT(DISTINCT ash.member_id)
50-
FROM admin_space_history ash
51-
WHERE ash.event_time BETWEEN :startTime AND :endTime
50+
SELECT COUNT(DISTINCT amsh.member_id)
51+
FROM admin_member_space_history amsh
52+
WHERE amsh.event_time BETWEEN :startTime AND :endTime
5253
""")
5354
.setParameter("startTime", start)
5455
.setParameter("endTime", end)
@@ -61,9 +62,10 @@ public double findAverageOfTeamSpaceRatiosWithPeriod(LocalDateTime startTime, Lo
6162
String sql = """
6263
SELECT AVG(ratio) FROM (
6364
SELECT
64-
member_id,
65-
SUM(CASE WHEN category = 'TEAM' THEN 1 ELSE 0 END) * 1.0 / COUNT(*) AS ratio
66-
FROM admin_space_history
65+
amsh.member_id,
66+
SUM(CASE WHEN ash.category = 'TEAM' THEN 1 ELSE 0 END) * 1.0 / COUNT(*) AS ratio
67+
FROM admin_member_space_history amsh
68+
JOIN admin_space_history ash ON amsh.space_id = ash.space_id
6769
WHERE event_time BETWEEN :startTime AND :endTime
6870
GROUP BY member_id
6971
) AS per_member

layer-admin/src/main/java/org/layer/admin/space/repository/AdminSpaceRepository.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
import org.springframework.data.repository.query.Param;
1111

1212
public interface AdminSpaceRepository
13-
extends JpaRepository<AdminSpaceHistory, Long>, AdminSpaceRepositoryCustom {
13+
extends JpaRepository<AdminSpaceHistory, Long> {
1414

1515
@Query("SELECT new org.layer.admin.space.controller.dto.SpaceCountResponse(a.category, COUNT(a)) " +
1616
"FROM AdminSpaceHistory a " +

layer-admin/src/main/java/org/layer/admin/space/service/AdminSpaceService.java

Lines changed: 28 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,14 @@
88
import org.layer.admin.space.controller.dto.SpaceCountResponse;
99
import org.layer.admin.space.controller.dto.TeamSpaceRatioPerMemberDto;
1010
import org.layer.admin.space.controller.dto.TeamSpaceRatioResponse;
11+
import org.layer.admin.space.entity.AdminMemberSpaceHistory;
1112
import org.layer.admin.space.entity.AdminSpaceHistory;
1213
import org.layer.admin.space.enums.AdminSpaceCategory;
14+
import org.layer.admin.space.repository.AdminMemberSpaceRepository;
1315
import org.layer.admin.space.repository.AdminSpaceRepository;
1416
import org.layer.event.space.CreateSpaceEvent;
17+
import org.layer.event.space.JoinSpaceEvent;
18+
import org.layer.event.space.LeaveSpaceEvent;
1519
import org.springframework.data.domain.Page;
1620
import org.springframework.data.domain.PageRequest;
1721
import org.springframework.scheduling.annotation.Async;
@@ -25,6 +29,7 @@
2529
public class AdminSpaceService {
2630

2731
private final AdminSpaceRepository adminSpaceRepository;
32+
private final AdminMemberSpaceRepository adminMemberSpaceRepository;
2833

2934
public List<SpaceCountResponse> getSpaceCount(LocalDateTime startDate, LocalDateTime endDate) {
3035
return adminSpaceRepository.findAllByCategory(startDate, endDate);
@@ -33,13 +38,13 @@ public List<SpaceCountResponse> getSpaceCount(LocalDateTime startDate, LocalDate
3338
public TeamSpaceRatioResponse getAverageTeamSpaceRatioPerMember(
3439
LocalDateTime startDate, LocalDateTime endDate, int page, int size) {
3540

36-
Page<TeamSpaceRatioPerMemberDto> histories = adminSpaceRepository.findTeamSpaceRatioPerMemberWithPeriod(
41+
Page<TeamSpaceRatioPerMemberDto> histories = adminMemberSpaceRepository.findTeamSpaceRatioPerMemberWithPeriod(
3742
startDate, endDate, PageRequest.of(page - 1, size));
3843
if (histories.isEmpty()) {
3944
return new TeamSpaceRatioResponse(null, 0.0, false, 0);
4045
}
4146

42-
double averageTeamSpaceRatioPerMember = adminSpaceRepository.findAverageOfTeamSpaceRatiosWithPeriod(startDate,
47+
double averageTeamSpaceRatioPerMember = adminMemberSpaceRepository.findAverageOfTeamSpaceRatiosWithPeriod(startDate,
4348
endDate);
4449

4550
return TeamSpaceRatioResponse.of(histories.getContent(), averageTeamSpaceRatioPerMember, histories.hasNext(),
@@ -49,13 +54,32 @@ public TeamSpaceRatioResponse getAverageTeamSpaceRatioPerMember(
4954
@Transactional(propagation = REQUIRES_NEW)
5055
@Async
5156
public void saveSpaceHistory(CreateSpaceEvent event) {
52-
AdminSpaceHistory adminMemberSignupHistory = AdminSpaceHistory.builder()
57+
AdminSpaceHistory spaceHistory = AdminSpaceHistory.builder()
5358
.eventId(event.eventId())
5459
.eventTime(event.eventTime())
5560
.memberId(event.memberId())
5661
.category(AdminSpaceCategory.from(event.category()))
5762
.build();
5863

59-
adminSpaceRepository.save(adminMemberSignupHistory);
64+
adminSpaceRepository.save(spaceHistory);
65+
}
66+
67+
@Transactional(propagation = REQUIRES_NEW)
68+
@Async
69+
public void saveMemberSpaceHistory(JoinSpaceEvent event) {
70+
AdminMemberSpaceHistory memberSpaceHistory = AdminMemberSpaceHistory.builder()
71+
.eventId(event.eventId())
72+
.eventTime(event.eventTime())
73+
.memberId(event.memberId())
74+
.build();
75+
76+
adminMemberSpaceRepository.save(memberSpaceHistory);
77+
}
78+
79+
@Transactional(propagation = REQUIRES_NEW)
80+
@Async
81+
public void deleteMemberSpaceHistory(LeaveSpaceEvent event) {
82+
adminMemberSpaceRepository.deleteByMemberIdAndSpaceId(
83+
event.memberId(), event.spaceId());
6084
}
6185
}

layer-api/src/main/java/org/layer/domain/space/service/SpaceService.java

Lines changed: 35 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import lombok.RequiredArgsConstructor;
44
import lombok.extern.slf4j.Slf4j;
5+
56
import org.layer.common.dto.Meta;
67
import org.layer.domain.common.random.CustomRandom;
78
import org.layer.event.space.CreateSpaceEvent;
@@ -24,6 +25,8 @@
2425
import org.layer.domain.space.exception.SpaceException;
2526
import org.layer.domain.space.repository.MemberSpaceRelationRepository;
2627
import org.layer.domain.space.repository.SpaceRepository;
28+
import org.layer.event.space.JoinSpaceEvent;
29+
import org.layer.event.space.LeaveSpaceEvent;
2730
import org.layer.storage.service.StorageService;
2831
import org.springframework.context.ApplicationEventPublisher;
2932
import org.springframework.stereotype.Service;
@@ -98,6 +101,7 @@ public Long createSpace(Long memberId, SpaceRequest.CreateSpaceRequest createSpa
98101
memberSpaceRelationRepository.save(memberSpaceRelation);
99102

100103
publishCreateSpaceEvent(space, memberId);
104+
publishJoinSpaceEvent(memberId, space.getId());
101105
return space.getId();
102106
}
103107

@@ -153,42 +157,51 @@ public SpaceResponse.SpaceWithMemberCountInfo getPublicSpaceById(Long spaceId) {
153157

154158
@Transactional
155159
public void createMemberSpace(Long memberId, Long spaceId) {
156-
157-
/*
158-
존재하는 스페이스 여부 확인
159-
*/
160+
// 존재하는 스페이스 여부 확인
160161
var foundSpace = spaceRepository.findById(spaceId).orElseThrow(() -> new SpaceException(NOT_FOUND_SPACE));
161162
if (foundSpace.getCategory() == SpaceCategory.INDIVIDUAL) {
162163
throw new SpaceException(NOT_TEAM_SPACE);
163164
}
164165

165-
/*
166-
이미 참여중인 스페이스 여부 확인
167-
*/
166+
// 이미 참여중인 스페이스 여부 확인
168167
memberSpaceRelationRepository.findBySpaceIdAndMemberId(spaceId, memberId).ifPresent(it -> {
169168
throw new SpaceException(SPACE_ALREADY_JOINED);
170169
});
171170

172-
/*
173-
스페이스 참여여부 저장
174-
*/
171+
// 스페이스 참여여부 저장
175172
var joinedSpace = MemberSpaceRelation.builder()
176173
.space(foundSpace)
177174
.memberId(memberId)
178175
.build();
179176
memberSpaceRelationRepository.save(joinedSpace);
177+
178+
publishJoinSpaceEvent(memberId, spaceId);
179+
}
180+
181+
private void publishJoinSpaceEvent(Long memberId, Long spaceId) {
182+
eventPublisher.publishEvent(JoinSpaceEvent.of(
183+
random.generateRandomValue(),
184+
memberId,
185+
time.now(),
186+
spaceId
187+
));
188+
}
189+
190+
private void publishLeaveSpaceEvent(Long memberId, Long spaceId) {
191+
eventPublisher.publishEvent(LeaveSpaceEvent.of(
192+
random.generateRandomValue(),
193+
memberId,
194+
time.now(),
195+
spaceId
196+
));
180197
}
181198

182199
@Transactional
183200
public void removeMemberSpace(Long memberId, Long spaceId) {
184-
/*
185-
존재하는 스페이스 여부 확인
186-
*/
201+
// 존재하는 스페이스 여부 확인
187202
var foundSpace = spaceRepository.findById(spaceId).orElseThrow(() -> new SpaceException(NOT_FOUND_SPACE));
188203

189-
/*
190-
스페이스 팀장 여부 확인
191-
*/
204+
// 스페이스 팀장 여부 확인
192205
if (foundSpace.getLeaderId().equals(memberId)) {
193206
throw new SpaceException(SPACE_LEADER_CANNOT_LEAVE);
194207
}
@@ -204,16 +217,14 @@ public void removeMemberSpace(Long memberId, Long spaceId) {
204217
throw new SpaceException(NOT_FOUND_SPACE);
205218
}
206219

207-
/*
208-
이미 참여중인 스페이스 여부 확인
209-
*/
220+
// 이미 참여중인 스페이스 여부 확인
210221
var foundMemberSpaceRelation = memberSpaceRelationRepository.findBySpaceIdAndMemberId(spaceId, memberId)
211222
.orElseThrow(() -> new SpaceException(SPACE_ALREADY_JOINED));
212223

213-
/*
214-
스페이스 참여여부 삭제 ( 스페이스 떠나기 )
215-
*/
224+
// 스페이스 참여여부 삭제 ( 스페이스 떠나기 )
216225
memberSpaceRelationRepository.deleteById(foundMemberSpaceRelation.getId());
226+
227+
publishLeaveSpaceEvent(memberId, spaceId);
217228
}
218229

219230
@Transactional
@@ -239,6 +250,8 @@ public void kickMemberFromSpace(Long leaderId, Long spaceId, Long memberId) {
239250

240251
// 팀에서 삭제하기
241252
memberSpaceRelationRepository.delete(foundTeamByMemberId);
253+
254+
publishLeaveSpaceEvent(memberId, spaceId);
242255
}
243256

244257
public List<SpaceResponse.SpaceMemberResponse> getSpaceMembers(Long memberId, Long spaceId) {

0 commit comments

Comments
 (0)