Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Bp 27 출석현황조회 api #11

Merged
merged 15 commits into from
Jul 29, 2024
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
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
3 changes: 2 additions & 1 deletion build.gradle
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import io.swagger.v3.oas.models.servers.Server
import org.hidetake.gradle.swagger.generator.GenerateSwaggerUI
import org.springframework.boot.gradle.tasks.bundling.BootJar

Expand Down Expand Up @@ -69,7 +70,7 @@ dependencies {
openapi3 {
servers = [
{ url = 'http://localhost:8080' },
]
] as List<? extends Closure<Server>>
title = 'Post Service API'
description = 'Post Service API description'
version = '1.0.0'
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package gdsc.konkuk.platformcore.application.attendance;

import java.time.LocalDateTime;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import lombok.Setter;

@Getter
@Setter
@Builder
@AllArgsConstructor
public class AttendanceInfo {
private Long attendanceId;
private Long eventId;
private Long memberId;
private Long participantId;
private LocalDateTime attendanceDate;
private boolean attendance;
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package gdsc.konkuk.platformcore.application.attendance;

import gdsc.konkuk.platformcore.application.attendance.exceptions.AttendanceAlreadyExistException;
import gdsc.konkuk.platformcore.application.attendance.exceptions.AttendanceErrorCode;
import gdsc.konkuk.platformcore.application.attendance.exceptions.AttendanceNotFoundException;
import gdsc.konkuk.platformcore.application.attendance.exceptions.QrInvalidException;
Expand All @@ -12,6 +13,7 @@
import gdsc.konkuk.platformcore.domain.attendance.entity.Participant;
import gdsc.konkuk.platformcore.domain.attendance.repository.AttendanceRepository;
import gdsc.konkuk.platformcore.domain.attendance.repository.ParticipantRepository;
import gdsc.konkuk.platformcore.domain.event.entity.Event;
import gdsc.konkuk.platformcore.domain.event.repository.EventRepository;
import gdsc.konkuk.platformcore.domain.member.entity.Member;
import gdsc.konkuk.platformcore.domain.member.repository.MemberRepository;
Expand All @@ -35,14 +37,14 @@ public class AttendanceService {
@Transactional
public Participant attend(String memberEmail, Long attendanceId, String qrUuid) {
Member member =
memberRepository
.findByEmail(memberEmail)
.orElseThrow(() -> UserNotFoundException.of(MemberErrorCode.USER_NOT_FOUND));
memberRepository
.findByEmail(memberEmail)
.orElseThrow(() -> UserNotFoundException.of(MemberErrorCode.USER_NOT_FOUND));
Attendance attendance =
attendanceRepository
.findById(attendanceId)
.orElseThrow(
() -> AttendanceNotFoundException.of(AttendanceErrorCode.ATTENDANCE_NOT_FOUND));
attendanceRepository
.findById(attendanceId)
.orElseThrow(
() -> AttendanceNotFoundException.of(AttendanceErrorCode.ATTENDANCE_NOT_FOUND));
if (!attendance.isActiveQr(qrUuid)) {
throw QrInvalidException.of(AttendanceErrorCode.INVALID_QR_UUID);
}
Expand All @@ -52,15 +54,18 @@ public Participant attend(String memberEmail, Long attendanceId, String qrUuid)

@Transactional
public Long registerAttendance(AttendanceRegisterRequest registerRequest) {
checkEventExist(registerRequest.getEventId());
Event event =
eventRepository
.findById(registerRequest.getEventId())
.orElseThrow(() -> EventNotFoundException.of(EventErrorCode.EVENT_NOT_FOUND));
checkAttendanceAlreadyExist(event);

Attendance newAttendance = AttendanceRegisterRequest.toEntity(registerRequest);
attendanceRepository.saveAndFlush(newAttendance);

List<Member> members = memberRepository.findAllByBatch(registerRequest.getBatch());
List<Participant> participants =
MemberToParticipantMapper.mapMemberListToParticipantList(
members, newAttendance.getId(), false);
ParticipantMapper.mapMemberListToAbsentParticipantList(members, newAttendance.getId());
participantRepository.saveAll(participants);

return newAttendance.getId();
Expand All @@ -75,30 +80,34 @@ public void deleteAttendance(Long attendanceId) {
@Transactional
public String generateQr(Long attendanceId) {
ekgns33 marked this conversation as resolved.
Show resolved Hide resolved
Attendance attendance =
attendanceRepository
.findById(attendanceId)
.orElseThrow(
() -> AttendanceNotFoundException.of(AttendanceErrorCode.ATTENDANCE_NOT_FOUND));
attendanceRepository
.findById(attendanceId)
.orElseThrow(
() -> AttendanceNotFoundException.of(AttendanceErrorCode.ATTENDANCE_NOT_FOUND));
return attendance.generateQr();
}

@Transactional
public void expireQr(Long attendanceId, String qrUuid) {
Attendance attendance =
attendanceRepository
.findById(attendanceId)
.orElseThrow(
() -> AttendanceNotFoundException.of(AttendanceErrorCode.ATTENDANCE_NOT_FOUND));
attendanceRepository
.findById(attendanceId)
.orElseThrow(
() -> AttendanceNotFoundException.of(AttendanceErrorCode.ATTENDANCE_NOT_FOUND));
if (!attendance.isActiveQr(qrUuid)) {
throw QrInvalidException.of(AttendanceErrorCode.INVALID_QR_UUID);
}

attendance.expireQr();
}

private void checkEventExist(Long eventId) {
eventRepository
.findById(eventId)
.orElseThrow(() -> EventNotFoundException.of(EventErrorCode.EVENT_NOT_FOUND));
private void checkAttendanceAlreadyExist(Event event) {
attendanceRepository
.findByEventId(event.getId())
.ifPresent(
attendance -> {
throw AttendanceAlreadyExistException.of(
AttendanceErrorCode.ATTENDANCE_ALREADY_EXIST);
});
}
}

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package gdsc.konkuk.platformcore.application.attendance;

import gdsc.konkuk.platformcore.domain.attendance.entity.Participant;
import gdsc.konkuk.platformcore.domain.member.entity.Member;

import java.util.List;

public class ParticipantMapper {
public static List<Participant> mapMemberListToAbsentParticipantList(
List<Member> members, Long attendanceId) {
return members.stream()
.map(
member ->
Participant.builder()
.attendanceId(attendanceId)
.memberId(member.getId())
.attendance(false)
.build())
.toList();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package gdsc.konkuk.platformcore.application.attendance.exceptions;

import gdsc.konkuk.platformcore.global.exceptions.BusinessException;
import gdsc.konkuk.platformcore.global.exceptions.CustomErrorCode;

public class AttendanceAlreadyExistException extends BusinessException {
protected AttendanceAlreadyExistException(CustomErrorCode errorCode, String logMessage) {
super(errorCode, logMessage);
}

public static AttendanceAlreadyExistException of(CustomErrorCode errorCode) {
return new AttendanceAlreadyExistException(errorCode, errorCode.getMessage());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
@RequiredArgsConstructor
public enum AttendanceErrorCode implements CustomErrorCode {
ATTENDANCE_NOT_FOUND("출석 정보가 존재하지 않습니다", "[ERROR] : 출석 정보를 찾을 수 없음"),
ATTENDANCE_ALREADY_EXIST("출석 정보가 이미 존재합니다", "[ERROR] : 이미 존재하는 출석 정보"),
INVALID_QR_UUID("유효하지 않은 QR 코드입니다", "[ERROR] : 유효하지 않은 QR 코드"),
PARTICIPANT_NOT_FOUND("참가자 정보가 존재하지 않습니다", "[ERROR] : 참가자 정보를 찾을 수 없음");

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
package gdsc.konkuk.platformcore.application.member;

import gdsc.konkuk.platformcore.application.attendance.AttendanceInfo;
import gdsc.konkuk.platformcore.domain.member.entity.Member;
import gdsc.konkuk.platformcore.domain.member.entity.MemberRole;
import jakarta.validation.constraints.NotEmpty;
import jakarta.validation.constraints.NotNull;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import lombok.Setter;

@Getter
@Setter
@Builder
@AllArgsConstructor
public class MemberAttendanceInfo {
@NotNull private Long memberId;
@NotEmpty private String memberName;
@NotNull private MemberRole memberRole;
private String profileImageUrl;
@NotEmpty private String department;
@NotNull List<AttendanceInfo> attendanceInfoList;

public static List<MemberAttendanceInfo> from(
ekgns33 marked this conversation as resolved.
Show resolved Hide resolved
List<Member> batchMemberList, List<AttendanceInfo> attendanceInfoList) {
Map<Long, MemberAttendanceInfo> memberAttendanceInfoMap = new HashMap<>();
for (Member member : batchMemberList) {
memberAttendanceInfoMap.put(
member.getId(),
MemberAttendanceInfo.builder()
.memberId(member.getId())
.memberName(member.getName())
.memberRole(member.getRole())
.profileImageUrl(member.getProfileImageUrl())
.department(member.getDepartment())
.attendanceInfoList(new ArrayList<>())
.build());
}
for (AttendanceInfo attendanceInfo : attendanceInfoList) {
if (!memberAttendanceInfoMap.containsKey(attendanceInfo.getMemberId())) continue;
MemberAttendanceInfo memberAttendanceInfo =
memberAttendanceInfoMap.get(attendanceInfo.getMemberId());
memberAttendanceInfo.getAttendanceInfoList().add(attendanceInfo);
}
return memberAttendanceInfoMap.values().stream().toList();
}
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,18 @@
package gdsc.konkuk.platformcore.application.member;

import java.time.LocalDate;
import java.time.LocalTime;
import java.util.List;
import java.util.Map;
import java.util.Optional;

import gdsc.konkuk.platformcore.application.attendance.AttendanceInfo;
import gdsc.konkuk.platformcore.application.attendance.exceptions.AttendanceErrorCode;
import gdsc.konkuk.platformcore.application.attendance.exceptions.ParticipantNotFoundException;
import gdsc.konkuk.platformcore.controller.member.AttendanceUpdateInfo;
import gdsc.konkuk.platformcore.domain.attendance.entity.Participant;
import gdsc.konkuk.platformcore.domain.attendance.repository.AttendanceRepository;
import gdsc.konkuk.platformcore.domain.attendance.repository.ParticipantRepository;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
Expand All @@ -14,13 +25,18 @@
import gdsc.konkuk.platformcore.domain.member.repository.MemberRepository;
import lombok.RequiredArgsConstructor;

import static java.util.function.Function.identity;
import static java.util.stream.Collectors.toMap;

@Service
@RequiredArgsConstructor
@Transactional(readOnly = true)
public class MemberService {

private final PasswordEncoder passwordEncoder;
private final MemberRepository memberRepository;
private final AttendanceRepository attendanceRepository;
private final ParticipantRepository participantRepository;

@Transactional
public Member register(MemberRegisterRequest registerRequest) {
Expand All @@ -37,11 +53,44 @@ public Member register(MemberRegisterRequest registerRequest) {

@Transactional
public void withdraw(Long currentId) {
Member member = memberRepository.findById(currentId)
.orElseThrow(() -> UserNotFoundException.of(MemberErrorCode.USER_NOT_FOUND));
Member member =
memberRepository
.findById(currentId)
.orElseThrow(() -> UserNotFoundException.of(MemberErrorCode.USER_NOT_FOUND));
member.withdraw();
}

public List<MemberAttendanceInfo> getMemberAttendanceInfo(String batch, LocalDate month) {
List<Member> batchMemberList = memberRepository.findAllByBatch(batch);
List<AttendanceInfo> attendanceInfoList =
attendanceRepository.findAllAttendanceInfoByStartAtBetween(
month.withDayOfMonth(1).atStartOfDay(),
month.withDayOfMonth(month.lengthOfMonth()).atTime(LocalTime.MAX));
return MemberAttendanceInfo.from(batchMemberList, attendanceInfoList);
}

@Transactional
public void updateAttendances(
String batch, LocalDate month, List<AttendanceUpdateInfo> attendanceUpdateInfoList) {
Map<Long, Participant> participantMap =
participantRepository
.findAllByBatchAndStartAtBetween(
batch,
month.withDayOfMonth(1).atStartOfDay(),
month.withDayOfMonth(month.lengthOfMonth()).atTime(LocalTime.MAX))
.stream()
.collect(toMap(Participant::getId, identity()));

for (AttendanceUpdateInfo attendanceUpdateInfo : attendanceUpdateInfoList) {
if (!participantMap.containsKey(attendanceUpdateInfo.getParticipantId())) {
throw ParticipantNotFoundException.of(AttendanceErrorCode.PARTICIPANT_NOT_FOUND);
}

Participant participant = participantMap.get(attendanceUpdateInfo.getParticipantId());
participant.updateAttendance(attendanceUpdateInfo.isAttendance());
}
}

private boolean checkMemberExistWithMemberId(String memberId) {
Optional<Member> member = memberRepository.findByMemberId(memberId);
return member.isPresent();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package gdsc.konkuk.platformcore.controller.member;

import jakarta.validation.constraints.NotNull;
import lombok.Builder;
import lombok.Getter;
import lombok.Setter;

@Getter
@Setter
@Builder
public class AttendanceUpdateInfo {
@NotNull private Long participantId;
@NotNull private boolean attendance;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package gdsc.konkuk.platformcore.controller.member;

import jakarta.validation.Valid;
import jakarta.validation.constraints.NotNull;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;

import java.util.List;

@Getter
@Setter
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class AttendanceUpdateRequest {
ekgns33 marked this conversation as resolved.
Show resolved Hide resolved
@NotNull @Valid private List<AttendanceUpdateInfo> attendanceUpdateInfoList;
}
Loading