Skip to content

Commit

Permalink
[Feat] member management (#54)
Browse files Browse the repository at this point in the history
* feat(member): implement member update

* feat(member): change member withddraw to delete other

* fix(member): add Transactional to updateMembers

* feat(member): implement member query

* fix(application): fix access permision to `/members/`

* fix(member): test member register with authorized user

* refactor(member): rename `memberService.getMembers` into `getMembersInBatch`

* refactor(member): move member update into domain layer
  • Loading branch information
goldentrash authored Nov 26, 2024
1 parent d1f92d3 commit c786d63
Show file tree
Hide file tree
Showing 10 changed files with 301 additions and 8 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

import gdsc.konkuk.platformcore.application.attendance.dtos.MemberAttendanceQueryDto;
import gdsc.konkuk.platformcore.application.member.dtos.MemberAttendances;
import gdsc.konkuk.platformcore.controller.member.dtos.MemberUpdateInfo;
import jakarta.validation.Valid;
import java.time.LocalDate;
import java.time.LocalTime;
import java.util.List;
Expand Down Expand Up @@ -36,6 +38,10 @@ public class MemberService {
private final AttendanceRepository attendanceRepository;
private final ParticipantRepository participantRepository;

public List<Member> getMembersInBatch(String batch) {
return memberRepository.findAllActiveByBatch(batch);
}

@Transactional
public Member register(MemberRegisterRequest registerRequest) {
if (checkMemberExistWithStudentId(registerRequest.getStudentId())) {
Expand All @@ -53,6 +59,13 @@ public void withdraw(Long currentId) {
member.withdraw();
}

@Transactional
public void updateMembers(String batch, @Valid List<MemberUpdateInfo> updateInfos) {
List<Long> memberIds = updateInfos.stream().map(MemberUpdateInfo::getMemberId).toList();
Map<Long, Member> memberMap = fetchMembers(memberIds, batch);
updateMembers(memberMap, updateInfos);
}

public List<MemberAttendances> getMemberAttendanceWithBatchAndPeriod(String batch, LocalDate month) {
List<MemberAttendanceQueryDto> attendanceInfoList =
attendanceRepository.findAllAttendanceInfoByBatchAndPeriod(
Expand All @@ -69,6 +82,24 @@ public void updateAttendances(
updateAttendanceStatuses(participantMap, attendanceUpdateInfoList);
}

private void updateMembers(Map<Long, Member> memberMap, List<MemberUpdateInfo> updateInfos) {
for (MemberUpdateInfo memberUpdateInfo : updateInfos) {
if (!memberMap.containsKey(memberUpdateInfo.getMemberId())) {
throw UserNotFoundException.of(MemberErrorCode.USER_NOT_FOUND);
}
Member member = memberMap.get(memberUpdateInfo.getMemberId());
member.update(memberUpdateInfo.toCommand());
}
}

private Map<Long, Member> fetchMembers(List<Long> memberIds, String batch) {
List<Member> members = memberRepository.findAllByIdsAndBatch(memberIds, batch);
if (members.size() != memberIds.size()) {
throw UserNotFoundException.of(MemberErrorCode.USER_NOT_FOUND);
}
return members.stream().collect(toMap(Member::getId, identity()));
}

private void updateAttendanceStatuses(Map<Long, Participant> participants, List<AttendanceUpdateInfo> updateInfos) {
for (AttendanceUpdateInfo attendanceUpdateInfo : updateInfos) {
if (!participants.containsKey(attendanceUpdateInfo.getParticipantId())) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package gdsc.konkuk.platformcore.application.member.dtos;

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

@Getter
@Setter
@Builder
@AllArgsConstructor
public class MemberUpdateCommand {
@NotNull private Long memberId;
private String studentId;
private String name;
private String email;
private String department;
private String batch;
private String role;
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@

import gdsc.konkuk.platformcore.application.member.dtos.MemberAttendances;
import gdsc.konkuk.platformcore.controller.member.dtos.AttendanceUpdateRequest;
import gdsc.konkuk.platformcore.controller.member.dtos.MemberInfo;
import gdsc.konkuk.platformcore.controller.member.dtos.MemberRegisterRequest;
import gdsc.konkuk.platformcore.controller.member.dtos.MemberUpdateRequest;
import java.net.URI;
import java.time.LocalDate;
import java.util.List;
Expand All @@ -21,7 +23,6 @@

import gdsc.konkuk.platformcore.application.member.MemberService;
import gdsc.konkuk.platformcore.domain.member.entity.Member;
import gdsc.konkuk.platformcore.global.utils.SecurityUtils;
import gdsc.konkuk.platformcore.global.responses.SuccessResponse;
import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;
Expand All @@ -33,6 +34,14 @@ public class MemberController {

private final MemberService memberService;

@GetMapping("/{batch}")
public ResponseEntity<SuccessResponse> getMembers(@PathVariable String batch) {
List<MemberInfo> memberInfos = memberService.getMembersInBatch(batch).stream()
.map(MemberInfo::from)
.toList();
return ResponseEntity.ok(SuccessResponse.of(memberInfos));
}

@PostMapping()
public ResponseEntity<SuccessResponse> signup(
@RequestBody @Valid MemberRegisterRequest registerRequest) {
Expand All @@ -41,13 +50,21 @@ public ResponseEntity<SuccessResponse> signup(
.body(SuccessResponse.messageOnly());
}

@DeleteMapping()
public ResponseEntity<SuccessResponse> withdraw() {
Long currentId = SecurityUtils.getCurrentUserId();
memberService.withdraw(currentId);
@DeleteMapping("/{batch}/{memberId}")
public ResponseEntity<SuccessResponse> withdraw(
@PathVariable String batch, @PathVariable Long memberId
) {
memberService.withdraw(memberId);
return ResponseEntity.noContent().build();
}

@PatchMapping("/{batch}")
public ResponseEntity<SuccessResponse> updateMembers(
@PathVariable String batch, @RequestBody @Valid MemberUpdateRequest updateInfos) {
memberService.updateMembers(batch, updateInfos.getMemberUpdateInfoList());
return ResponseEntity.ok(SuccessResponse.messageOnly());
}

@GetMapping("/{batch}/attendances")
public ResponseEntity<SuccessResponse> getAttendances(
@PathVariable String batch, @RequestParam Integer year, @RequestParam Integer month) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package gdsc.konkuk.platformcore.controller.member.dtos;

import gdsc.konkuk.platformcore.domain.member.entity.Member;
import lombok.Builder;
import lombok.Getter;
import lombok.Setter;

@Getter
@Setter
@Builder
public class MemberInfo {
private Long memberId;
private String studentId;
private String name;
private String email;
private String department;
private String batch;
private String role;

public static MemberInfo from(Member member) {
return MemberInfo.builder()
.memberId(member.getId())
.studentId(member.getStudentId())
.name(member.getName())
.email(member.getEmail())
.department(member.getDepartment())
.batch(member.getBatch())
.role(member.getRole().toString())
.build();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package gdsc.konkuk.platformcore.controller.member.dtos;

import gdsc.konkuk.platformcore.application.member.dtos.MemberUpdateCommand;
import jakarta.validation.constraints.NotNull;
import lombok.Builder;
import lombok.Getter;
import lombok.Setter;

@Getter
@Setter
@Builder
public class MemberUpdateInfo {
@NotNull private Long memberId;
private String studentId;
private String name;
private String email;
private String department;
private String batch;
private String role;

public MemberUpdateCommand toCommand() {
return MemberUpdateCommand.builder()
.memberId(memberId)
.studentId(studentId)
.name(name)
.email(email)
.department(department)
.batch(batch)
.role(role)
.build();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package gdsc.konkuk.platformcore.controller.member.dtos;

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

@Getter
@Setter
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class MemberUpdateRequest {
@NotNull
@Valid
private List<MemberUpdateInfo> memberUpdateInfoList;
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import static gdsc.konkuk.platformcore.global.consts.PlatformConstants.SOFT_DELETE_RETENTION_MONTHS;
import static gdsc.konkuk.platformcore.global.utils.FieldValidator.validateNotNull;

import gdsc.konkuk.platformcore.application.member.dtos.MemberUpdateCommand;
import java.time.LocalDateTime;

import org.hibernate.annotations.SQLRestriction;
Expand Down Expand Up @@ -68,6 +69,27 @@ public Boolean isMemberDeleted() {
return isDeleted;
}

public void update(MemberUpdateCommand command) {
if (command.getStudentId() != null) {
studentId = command.getStudentId();
}
if (command.getName() != null) {
name = command.getName();
}
if (command.getEmail() != null) {
email = command.getEmail();
}
if (command.getDepartment() != null) {
department = command.getDepartment();
}
if (command.getRole() != null) {
role = MemberRole.from(command.getRole());
}
if (command.getBatch() != null) {
batch = command.getBatch();
}
}

@Builder
public Member(
Long id,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,15 @@
import org.springframework.data.jpa.repository.JpaRepository;

import gdsc.konkuk.platformcore.domain.member.entity.Member;
import org.springframework.data.jpa.repository.Query;

public interface MemberRepository extends JpaRepository<Member, Long> {
@Query("SELECT m FROM Member m WHERE m.batch = :batch AND m.isDeleted = false")
List<Member> findAllActiveByBatch(String batch);

@Query("SELECT m FROM Member m WHERE m.id IN :memberIds AND m.batch = :batch")
List<Member> findAllByIdsAndBatch(List<Long> memberIds, String batch);

Optional<Member> findByStudentId(String studentId);

Optional<Member> findByEmail(String memberEmail);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ public SecurityFilterChain securityFilterChain(HttpSecurity httpSecurity) throws
.addFilterBefore(jwtAuthenticationFilter, UsernamePasswordAuthenticationFilter.class)
.authorizeHttpRequests(authorize -> authorize
// 모두를 위한 API
.requestMatchers("/login/**", "/docs/**", "/actuator/**", apiPath("/members"))
.requestMatchers("/login/**", "/docs/**", "/actuator/**")
.permitAll()
// 동아리 회원을 위한 API
.requestMatchers(apiPath("/attendances/attend/**"))
Expand Down
Loading

0 comments on commit c786d63

Please sign in to comment.