Skip to content

Commit

Permalink
Merge pull request #95 from IT-Cotato/develop
Browse files Browse the repository at this point in the history
[Release] 2024.08.14.01
  • Loading branch information
Youthhing authored Aug 14, 2024
2 parents 871134f + 8e3610e commit 4785381
Show file tree
Hide file tree
Showing 54 changed files with 1,656 additions and 149 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package org.cotato.csquiz.api.attendance.controller;

import io.swagger.v3.oas.annotations.Operation;
import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.cotato.csquiz.api.attendance.dto.UpdateAttendanceRequest;
import org.cotato.csquiz.domain.attendance.service.AttendanceAdminService;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PatchMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@Slf4j
@RestController
@RequiredArgsConstructor
@RequestMapping("/v2/api/attendances/admin")
public class AttendanceAdminController {

private final AttendanceAdminService attendanceAdminService;

@Operation(summary = "출석 정보 변경 API")
@PatchMapping
public ResponseEntity<Void> updateAttendance(@RequestBody @Valid UpdateAttendanceRequest request) {
attendanceAdminService.updateAttendance(request);
return ResponseEntity.noContent().build();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
package org.cotato.csquiz.api.attendance.controller;

import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.validation.Valid;
import jakarta.validation.constraints.Max;
import jakarta.validation.constraints.Min;
import java.util.List;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.cotato.csquiz.api.attendance.dto.AttendResponse;
import org.cotato.csquiz.api.attendance.dto.AttendanceRecordResponse;
import org.cotato.csquiz.api.attendance.dto.AttendancesResponse;
import org.cotato.csquiz.api.attendance.dto.MemberAttendanceRecordsResponse;
import org.cotato.csquiz.api.attendance.dto.OfflineAttendanceRequest;
import org.cotato.csquiz.api.attendance.dto.OnlineAttendanceRequest;
import org.cotato.csquiz.api.attendance.dto.UpdateAttendanceRequest;
import org.cotato.csquiz.domain.attendance.service.AttendanceAdminService;
import org.cotato.csquiz.domain.attendance.service.AttendanceRecordService;
import org.cotato.csquiz.domain.attendance.service.AttendanceService;
import org.springframework.http.ResponseEntity;
import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PatchMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

@Slf4j
@Tag(name = "출석 정보", description = "출석 관련 API 입니다.")
@RestController
@Validated
@RequiredArgsConstructor
@RequestMapping("/v2/api/attendances")
public class AttendanceController {

private final AttendanceAdminService attendanceAdminService;
private final AttendanceService attendanceService;
private final AttendanceRecordService attendanceRecordService;

@Operation(summary = "출석 정보 변경 API")
@PatchMapping
public ResponseEntity<Void> updateAttendance(@RequestBody @Valid UpdateAttendanceRequest request) {
attendanceAdminService.updateAttendance(request);
return ResponseEntity.noContent().build();
}

@Operation(summary = "회원 출결사항 기간 단위 조회 API")
@GetMapping("/records")
public ResponseEntity<List<AttendanceRecordResponse>> findAttendanceRecords(
@RequestParam(name = "generationId") Long generationId,
@RequestParam(name = "month", required = false) @Min(value = 1, message = "달은 1 이상이어야 합니다.") @Max(value = 12, message = "달은 12 이하이어야 합니다") Integer month
) {
return ResponseEntity.ok().body(attendanceAdminService.findAttendanceRecords(generationId, month));
}

@Operation(summary = "회원 출결사항 출석 단위 조회 API")
@GetMapping("/{attendance-id}/records")
public ResponseEntity<List<AttendanceRecordResponse>> findAttendanceRecordsByAttendance(
@PathVariable("attendance-id") Long attendanceId) {
return ResponseEntity.ok().body(attendanceAdminService.findAttendanceRecordsByAttendance(attendanceId));
}

@Operation(summary = "기수별 출석 목록 조회 API")
@GetMapping
public ResponseEntity<AttendancesResponse> findAttendancesByGeneration(@RequestParam("generationId") Long generationId) {
return ResponseEntity.ok().body(attendanceService.findAttendancesByGenerationId(generationId));
}

@Operation(summary = "대면 출결 입력 API",
responses = {
@ApiResponse(
responseCode = "200",
description = "성공"
),
@ApiResponse(
responseCode = "AT-301",
description = "이미 출석을 완료함"
),
@ApiResponse(
responseCode = "AT-401",
description = "출석 시간이 아님"
)
}
)
@PostMapping(value = "/records/offline")
public ResponseEntity<AttendResponse> submitOfflineAttendanceRecord(@RequestBody OfflineAttendanceRequest request,
@AuthenticationPrincipal Long memberId) {
return ResponseEntity.ok().body(attendanceRecordService.submitRecord(request, memberId));
}

@Operation(summary = "비대면 출결 입력 API",
responses = {
@ApiResponse(
responseCode = "200",
description = "성공"
),
@ApiResponse(
responseCode = "AT-301",
description = "이미 출석을 완료함"
),
@ApiResponse(
responseCode = "AT-401",
description = "출석 시간이 아님"
)
})
@PostMapping(value = "/records/online")
public ResponseEntity<AttendResponse> submitOnlineAttendanceRecord(@RequestBody OnlineAttendanceRequest request,
@AuthenticationPrincipal Long memberId) {
return ResponseEntity.ok().body(attendanceRecordService.submitRecord(request, memberId));
}

@Operation(summary = "부원의 기수별 출결 기록 반환 API")
@GetMapping("/records/members")
public ResponseEntity<MemberAttendanceRecordsResponse> findAllRecordsByGeneration(@RequestParam("generation-id") Long generationId ,
@AuthenticationPrincipal Long memberId) {
return ResponseEntity.ok().body(attendanceRecordService.findAllRecordsBy(generationId, memberId));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package org.cotato.csquiz.api.attendance.dto;

import org.cotato.csquiz.domain.attendance.enums.AttendanceResult;

public record AttendResponse(
AttendanceResult status,
String message
) {
public static AttendResponse from(AttendanceResult status) {
return new AttendResponse(
status,
status.getMessage()
);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package org.cotato.csquiz.api.attendance.dto;

import com.fasterxml.jackson.annotation.JsonFormat;
import java.time.LocalTime;
import java.util.Objects;
import lombok.Builder;
import org.cotato.csquiz.domain.attendance.enums.DeadLine;

public record AttendanceDeadLineDto(
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "HH:mm:ss")
LocalTime attendanceDeadLine,
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "HH:mm:ss")
LocalTime lateDeadLine
) {

@Builder
public AttendanceDeadLineDto {
if (Objects.isNull(attendanceDeadLine)) {
attendanceDeadLine = DeadLine.DEFAULT_ATTENDANCE_DEADLINE.getTime();
}
if (Objects.isNull(lateDeadLine)) {
lateDeadLine = DeadLine.DEFAULT_LATE_DEADLINE.getTime();
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package org.cotato.csquiz.api.attendance.dto;

import java.time.LocalDateTime;
import org.cotato.csquiz.domain.attendance.enums.AttendanceType;

public interface AttendanceParams {

AttendanceType attendanceType();

Long attendanceId();

LocalDateTime requestTime();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package org.cotato.csquiz.api.attendance.dto;

import org.cotato.csquiz.domain.auth.entity.Member;
import org.cotato.csquiz.domain.auth.enums.MemberPosition;


public record AttendanceRecordResponse(
AttendanceMemberInfo memberInfo,
AttendanceStatistic statistic
) {
public static AttendanceRecordResponse of(Member member, AttendanceStatistic attendanceStatistic) {
return new AttendanceRecordResponse(
AttendanceMemberInfo.from(member),
attendanceStatistic
);
}

public record AttendanceMemberInfo(
Long memberId,
String memberName,
MemberPosition position
){
static AttendanceMemberInfo from(Member member) {
return new AttendanceMemberInfo(
member.getId(),
member.getName(),
member.getPosition()
);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package org.cotato.csquiz.api.attendance.dto;

import java.time.LocalDate;
import lombok.Builder;
import org.cotato.csquiz.domain.attendance.enums.AttendanceOpenStatus;

@Builder
public record AttendanceResponse(
Long attendanceId,
String sessionTitle,
LocalDate sessionDate,
AttendanceOpenStatus openStatus
) {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package org.cotato.csquiz.api.attendance.dto;

import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import org.cotato.csquiz.domain.attendance.entity.AttendanceRecord;
import org.cotato.csquiz.domain.attendance.enums.AttendanceResult;
import org.cotato.csquiz.domain.attendance.enums.AttendanceType;

public record AttendanceStatistic(
Integer onLine,
Integer offLine,
Integer late,
Integer absent
) {
public static AttendanceStatistic of(List<AttendanceRecord> attendanceRecords, Integer totalAttendance) {
Map<AttendanceResult, List<AttendanceRecord>> countByStatus = attendanceRecords.stream()
.collect(Collectors.groupingBy(AttendanceRecord::getAttendanceResult));
List<AttendanceRecord> presentRecords = countByStatus.getOrDefault(AttendanceResult.PRESENT, List.of());

int onlineCount = (int) presentRecords.stream()
.filter(record -> AttendanceType.ONLINE == record.getAttendanceType())
.count();
int offLineCount = (int) presentRecords.stream()
.filter(record -> AttendanceType.OFFLINE == record.getAttendanceType())
.count();

return new AttendanceStatistic(
onlineCount,
offLineCount,
countByStatus.getOrDefault(AttendanceResult.LATE, List.of()).size(),
totalAttendance - attendanceRecords.size()
);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package org.cotato.csquiz.api.attendance.dto;

import java.util.List;
import lombok.Builder;

@Builder
public record AttendancesResponse(
Long generationId,
Long generationNumber,
List<AttendanceResponse> attendances
) {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package org.cotato.csquiz.api.attendance.dto;

import io.swagger.v3.oas.annotations.media.Schema;
import java.time.LocalDate;
import org.cotato.csquiz.domain.attendance.entity.AttendanceRecord;
import org.cotato.csquiz.domain.attendance.enums.AttendanceOpenStatus;
import org.cotato.csquiz.domain.attendance.enums.AttendanceResult;
import org.cotato.csquiz.domain.attendance.enums.AttendanceType;
import org.cotato.csquiz.domain.generation.entity.Session;

public record MemberAttendResponse(
@Schema(description = "멤버 PK")
Long memberId,
@Schema(description = "세션 타이틀", example = "3주차 세션")
String sessionTitle,
@Schema(description = "세션 날짜")
LocalDate sessionDate,
@Schema(description = "출결 진행 여부", examples = {
"CLOSED", "OPEN"
})
AttendanceOpenStatus isOpened,
@Schema(description = "출결 형식")
AttendanceType attendanceType,
@Schema(description = "마감된 출석에 대한 출결 결과", nullable = true)
AttendanceResult attendanceResult
) {
public static MemberAttendResponse closedAttendanceResponse(Session session, AttendanceRecord attendanceRecord) {
return new MemberAttendResponse(
attendanceRecord.getMemberId(),
session.getTitle(),
session.getSessionDate(),
AttendanceOpenStatus.CLOSED,
attendanceRecord.getAttendanceType(),
attendanceRecord.getAttendanceResult()
);
}

public static MemberAttendResponse openedAttendanceResponse(Session session, Long memberId) {
return new MemberAttendResponse(
memberId,
session.getTitle(),
session.getSessionDate(),
AttendanceOpenStatus.OPEN,
null,
null
);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package org.cotato.csquiz.api.attendance.dto;

import io.swagger.v3.oas.annotations.media.Schema;
import java.util.List;

public record MemberAttendanceRecordsResponse(
@Schema(description = "요청한 기수 PK")
Long generationId,
List<MemberAttendResponse> memberAttendResponses
) {
public static MemberAttendanceRecordsResponse of(Long generationId, List<MemberAttendResponse> memberAttendResponses) {
return new MemberAttendanceRecordsResponse(
generationId,
memberAttendResponses
);
}
}
Loading

0 comments on commit 4785381

Please sign in to comment.