88import inha .gdgoc .domain .core .attendance .dto .response .TeamResponse ;
99import inha .gdgoc .domain .core .attendance .service .CoreAttendanceService ;
1010import inha .gdgoc .domain .user .enums .TeamType ;
11- import inha .gdgoc .domain .user .enums .UserRole ;
1211import inha .gdgoc .global .config .jwt .TokenProvider .CustomUserDetails ;
1312import inha .gdgoc .global .dto .response .ApiResponse ;
1413import inha .gdgoc .global .dto .response .PageMeta ;
@@ -44,12 +43,6 @@ public class CoreAttendanceController {
4443
4544 private final CoreAttendanceService service ;
4645
47- /* ===== helpers ===== */
48- private static TeamType requiredTeamFrom (CustomUserDetails me ) {
49- if (me .getTeam () == null ) throw new IllegalArgumentException ("LEAD 권한 토큰에 team 정보가 없습니다." );
50- return me .getTeam ();
51- }
52-
5346 private static ResponseEntity <ApiResponse <Map <String , Object >, Void >> okUpdated (long updated , List <Long > ignored ) {
5447 return ResponseEntity .ok (ApiResponse .ok (CoreAttendanceMessage .ATTENDANCE_ALL_SET_SUCCESS , Map .of ("updated" , updated , "ignoredUserIds" , ignored )));
5548 }
@@ -77,7 +70,9 @@ public ResponseEntity<ApiResponse<DateListResponse, Void>> deleteDate(@PathVaria
7770 /* ===== 팀 목록 (리드=본인 팀만 / 관리자=전체) ===== */
7871 @ GetMapping ("/teams" )
7972 public ResponseEntity <ApiResponse <List <TeamResponse >, PageMeta >> getTeams (@ AuthenticationPrincipal CustomUserDetails me ) {
80- List <TeamResponse > list = (me .getRole () == UserRole .LEAD && me .getTeam () != TeamType .HR ) ? service .getTeamsForLead (requiredTeamFrom (me )) : service .getTeamsForOrganizerOrAdmin ();
73+ List <TeamResponse > list = service .isLeadScoped (me .getRole (), me .getTeam ())
74+ ? service .getTeamsForLead (service .resolveEffectiveTeam (me .getRole (), me .getTeam (), null ))
75+ : service .getTeamsForOrganizerOrAdmin ();
8176
8277 var page = new PageImpl <>(list , PageRequest .of (0 , Math .max (1 , list .size ()), Sort .by (Sort .Direction .DESC , "createdAt" )), list .size ());
8378 return ResponseEntity .ok (ApiResponse .ok (CoreAttendanceMessage .TEAM_LIST_RETRIEVED_SUCCESS , list , PageMeta .of (page )));
@@ -88,7 +83,7 @@ public ResponseEntity<ApiResponse<List<TeamResponse>, PageMeta>> getTeams(@Authe
8883 @ GetMapping ("/{date}/members" )
8984 public ResponseEntity <ApiResponse <List <Map <String , Object >>, Void >> membersOfMeeting (@ AuthenticationPrincipal CustomUserDetails me , @ PathVariable @ DateTimeFormat (iso = DateTimeFormat .ISO .DATE ) LocalDate date , @ RequestParam (required = false ) TeamType team // 관리자만 사용, 리드는 무시
9085 ) {
91- TeamType effectiveTeam = (me .getRole () == UserRole . LEAD && me .getTeam () != TeamType . HR ) ? requiredTeamFrom ( me ) : team ;
86+ TeamType effectiveTeam = service . resolveEffectiveTeam (me .getRole (), me .getTeam (), team ) ;
9287 var list = service .getMembersWithPresence (date .toString (), effectiveTeam );
9388 // list 원소 예시: { "userId": "123", "name": "홍길동", "present": true, "lastModifiedAt": "..." }
9489 return ResponseEntity .ok (ApiResponse .ok (CoreAttendanceMessage .TEAM_LIST_RETRIEVED_SUCCESS , list ));
@@ -99,34 +94,28 @@ public ResponseEntity<ApiResponse<List<Map<String, Object>>, Void>> membersOfMee
9994 @ PutMapping ("/{date}/attendance" )
10095 public ResponseEntity <ApiResponse <Map <String , Object >, Void >> saveAttendanceSnapshot (@ AuthenticationPrincipal CustomUserDetails me , @ PathVariable @ DateTimeFormat (iso = DateTimeFormat .ISO .DATE ) LocalDate date , @ RequestBody @ Valid SetAttendanceRequest req ) {
10196 var userIds = req .safeUserIds ();
102-
103- // LEAD → 본인 팀 검증
104- if (me .getRole () == UserRole .LEAD && me .getTeam () != TeamType .HR ) {
105- TeamType myTeam = requiredTeamFrom (me );
106- var validation = service .filterUserIdsNotInTeam (myTeam , userIds );
107- if (validation .validIds ().isEmpty ()) {
108- return okUpdated (0L , validation .invalidIds ());
109- }
110- long updated = service .setAttendance (date .toString (), validation .validIds (), req .presentValue ());
111- return okUpdated (updated , validation .invalidIds ());
112- }
113-
114- // ORGANIZER / ADMIN → 팀 추론/검증 없이 바로 업서트
115- long updated = service .setAttendance (date .toString (), userIds , req .presentValue ());
116- return okUpdated (updated , List .of ());
97+ CoreAttendanceService .AttendanceUpdateResult result = service .saveAttendanceSnapshot (
98+ date .toString (),
99+ userIds ,
100+ req .presentValue (),
101+ me .getRole (),
102+ me .getTeam ()
103+ );
104+ return okUpdated (result .updatedCount (), result .ignoredUserIds ());
117105 }
118106
119107 /* ===== 날짜 요약(JSON) ===== */
120108 @ GetMapping ("/{date}/summary" )
121109 public ResponseEntity <ApiResponse <DaySummaryResponse , Void >> summary (@ AuthenticationPrincipal CustomUserDetails me , @ PathVariable @ DateTimeFormat (iso = DateTimeFormat .ISO .DATE ) LocalDate date , @ RequestParam (required = false ) TeamType team ) {
122- DaySummaryResponse body = (me .getRole () == UserRole .LEAD && me .getTeam () != TeamType .HR ) ? service .summary (date .toString (), requiredTeamFrom (me )) : service .summary (date .toString (), team );
110+ TeamType effectiveTeam = service .resolveEffectiveTeam (me .getRole (), me .getTeam (), team );
111+ DaySummaryResponse body = service .summary (date .toString (), effectiveTeam );
123112 return ResponseEntity .ok (ApiResponse .ok (CoreAttendanceMessage .SUMMARY_RETRIEVED_SUCCESS , body ));
124113 }
125114
126115 /* ===== 날짜 요약(CSV) ===== */
127116 @ GetMapping (value = "/{date}/summary.csv" , produces = "text/csv; charset=UTF-8" )
128117 public ResponseEntity <String > summaryCsv (@ AuthenticationPrincipal CustomUserDetails me , @ PathVariable @ DateTimeFormat (iso = DateTimeFormat .ISO .DATE ) LocalDate date , @ RequestParam (required = false ) TeamType team ) {
129- TeamType effective = (me .getRole () == UserRole . LEAD && me .getTeam () != TeamType . HR ) ? requiredTeamFrom ( me ) : team ;
118+ TeamType effective = service . resolveEffectiveTeam (me .getRole (), me .getTeam (), team ) ;
130119 String csv = service .buildSummaryCsv (date .toString (), effective );
131120 return ResponseEntity .ok ()
132121 .header ("Content-Disposition" , "attachment; filename=\" attendance-" + date + ".csv\" " )
@@ -138,10 +127,7 @@ public ResponseEntity<String> summaryCsvAll(
138127 @ AuthenticationPrincipal CustomUserDetails me ,
139128 @ RequestParam (required = false ) TeamType team
140129 ) {
141- // LEAD & not HR → 자신의 팀만
142- TeamType effective = (me .getRole () == UserRole .LEAD && me .getTeam () != TeamType .HR )
143- ? requiredTeamFrom (me )
144- : team ;
130+ TeamType effective = service .resolveEffectiveTeam (me .getRole (), me .getTeam (), team );
145131
146132 String csv = service .buildFullMatrixCsv (effective );
147133 return ResponseEntity .ok ()
0 commit comments