Skip to content

Commit

Permalink
chore : merge with develop
Browse files Browse the repository at this point in the history
  • Loading branch information
binary-ho committed Feb 12, 2024
2 parents bae67e8 + 09a2837 commit fbba831
Show file tree
Hide file tree
Showing 42 changed files with 775 additions and 63 deletions.
29 changes: 29 additions & 0 deletions .github/workflows/develop_deploy.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
name: Deploy to Develop

on:
workflow_dispatch:
inputs:
commit_hash:
description: 'commit_hash'
required: true

jobs:
deploy:
runs-on: ubuntu-latest
environment: develop
steps:
- name: Deploy to EC2 Server
uses: appleboy/ssh-action@master
env:
DOCKERHUB_USERNAME: ${{ secrets.DOCKERHUB_USERNAME }}
DOCKERHUB_IMAGE_TAG: ${{ github.event.inputs.commit_hash }}
with:
host: ${{ secrets.EC2_HOST }}
username: ${{ secrets.EC2_USERNAME }}
key: ${{ secrets.EC2_PRIVATE_KEY }}
envs: DOCKERHUB_USERNAME,DOCKERHUB_IMAGE_TAG # docker-compose.yml 에서 사용할 환경 변수
script: |
echo "${{ secrets.DOCKERHUB_TOKEN }}" | docker login -u "${{ secrets.DOCKERHUB_USERNAME }}" --password-stdin
docker pull ${{ env.DOCKERHUB_USERNAME }}/gdsc-server:${{ env.DOCKERHUB_IMAGE_TAG }}
docker compose -f /home/ubuntu/docker-compose.yml up -d
docker image prune -a -f
6 changes: 6 additions & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,12 @@ dependencies {
// Swagger
implementation 'org.springdoc:springdoc-openapi-starter-webmvc-ui:2.3.0'

// Actuator
implementation 'org.springframework.boot:spring-boot-starter-actuator'

// Discord
implementation 'net.dv8tion:JDA:5.0.0-beta.20'

// Mail
implementation 'org.springframework.boot:spring-boot-starter-mail'
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package com.gdschongik.gdsc.domain.discord.listener;

import com.gdschongik.gdsc.global.discord.Listener;
import lombok.extern.slf4j.Slf4j;
import net.dv8tion.jda.api.entities.Message;
import net.dv8tion.jda.api.entities.User;
import net.dv8tion.jda.api.entities.channel.concrete.TextChannel;
import net.dv8tion.jda.api.events.message.MessageReceivedEvent;
import net.dv8tion.jda.api.hooks.ListenerAdapter;

@Slf4j
@Listener
public class PingpongListener extends ListenerAdapter {

@Override
public void onMessageReceived(MessageReceivedEvent event) {
User author = event.getAuthor();
TextChannel channel = event.getChannel().asTextChannel();
Message message = event.getMessage();
String content = message.getContentRaw(); // get only textual content of message

log.info("Message from {} in {}: {}", author.getName(), channel.getName(), message.getContentDisplay());

if (author.isBot()) return;

if (content.equals("!ping")) {
channel.sendMessage("Pong!").queue();
}
}
}
Original file line number Diff line number Diff line change
@@ -1,34 +1,68 @@
package com.gdschongik.gdsc.domain.member.api;

import com.gdschongik.gdsc.domain.member.application.MemberService;
import com.gdschongik.gdsc.domain.member.application.AdminMemberService;
import com.gdschongik.gdsc.domain.member.dto.request.MemberGrantRequest;
import com.gdschongik.gdsc.domain.member.dto.request.MemberQueryRequest;
import com.gdschongik.gdsc.domain.member.dto.request.MemberUpdateRequest;
import com.gdschongik.gdsc.domain.member.dto.response.MemberFindAllResponse;
import com.gdschongik.gdsc.domain.member.dto.response.MemberGrantResponse;
import com.gdschongik.gdsc.domain.member.dto.response.MemberPendingFindAllResponse;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@Tag(name = "Admin Member", description = "어드민 회원 관리 API입니다.")
@RestController
@RequestMapping("/admin/members")
@RequiredArgsConstructor
public class AdminMemberController {

private final MemberService memberService;
private final AdminMemberService adminMemberService;

@Operation(summary = "전체 회원 목록 조회", description = "전체 회원 목록을 조회합니다.")
@GetMapping
public ResponseEntity<Page<MemberFindAllResponse>> getMembers(MemberQueryRequest queryRequest, Pageable pageable) {
Page<MemberFindAllResponse> response = memberService.findAll(queryRequest, pageable);
Page<MemberFindAllResponse> response = adminMemberService.findAll(queryRequest, pageable);
return ResponseEntity.ok().body(response);
}

@Operation(summary = "회원 탈퇴", description = "회원을 탈퇴시킵니다.")
@DeleteMapping("/{memberId}")
public ResponseEntity<Void> withdrawMember(@PathVariable Long memberId) {
memberService.withdrawMember(memberId);
adminMemberService.withdrawMember(memberId);
return ResponseEntity.ok().build();
}

@Operation(summary = "대기중인 회원 목록 조회", description = "대기중인 회원 목록을 조회합니다.")
@GetMapping("/pending")
public ResponseEntity<Page<MemberPendingFindAllResponse>> getPendingMembers(Pageable pageable) {
Page<MemberPendingFindAllResponse> response = adminMemberService.findAllPendingMembers(pageable);
return ResponseEntity.ok().body(response);
}

@Operation(summary = "회원 정보 수정", description = "회원 정보를 수정합니다.")
@PutMapping("/{memberId}")
public ResponseEntity<Void> updateMember(
@PathVariable Long memberId, @Valid @RequestBody MemberUpdateRequest request) {
adminMemberService.updateMember(memberId, request);
return ResponseEntity.ok().build();
}

@Operation(summary = "회원 승인", description = "회원의 가입을 승인합니다.")
@PutMapping("/grant")
public ResponseEntity<MemberGrantResponse> grantMember(@Valid @RequestBody MemberGrantRequest request) {
MemberGrantResponse response = adminMemberService.grantMember(request);
return ResponseEntity.ok().body(response);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package com.gdschongik.gdsc.domain.member.api;

import com.gdschongik.gdsc.domain.member.application.OnboardingMemberService;
import com.gdschongik.gdsc.domain.member.dto.request.MemberSignupRequest;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;
import org.springframework.http.ResponseEntity;
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.RestController;

@Tag(name = "Onboarding Member", description = "회원 온보딩 API입니다.")
@RestController
@RequestMapping("/onboarding/members")
@RequiredArgsConstructor
public class OnboardingMemberController {

private final OnboardingMemberService onboardingMemberService;

@Operation(summary = "회원 가입 신청", description = "회원 가입을 신청합니다.")
@PostMapping
public ResponseEntity<Void> signupMember(@Valid @RequestBody MemberSignupRequest request) {
onboardingMemberService.signupMember(request);
return ResponseEntity.ok().build();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
package com.gdschongik.gdsc.domain.member.application;

import static com.gdschongik.gdsc.global.exception.ErrorCode.*;

import com.gdschongik.gdsc.domain.member.dao.MemberRepository;
import com.gdschongik.gdsc.domain.member.domain.Member;
import com.gdschongik.gdsc.domain.member.domain.MemberRole;
import com.gdschongik.gdsc.domain.member.dto.request.MemberGrantRequest;
import com.gdschongik.gdsc.domain.member.dto.request.MemberQueryRequest;
import com.gdschongik.gdsc.domain.member.dto.request.MemberUpdateRequest;
import com.gdschongik.gdsc.domain.member.dto.response.MemberFindAllResponse;
import com.gdschongik.gdsc.domain.member.dto.response.MemberGrantResponse;
import com.gdschongik.gdsc.domain.member.dto.response.MemberPendingFindAllResponse;
import com.gdschongik.gdsc.global.exception.CustomException;
import com.gdschongik.gdsc.global.exception.ErrorCode;
import java.util.List;
import java.util.Optional;
import lombok.RequiredArgsConstructor;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

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

private final MemberRepository memberRepository;

public Page<MemberFindAllResponse> findAll(MemberQueryRequest queryRequest, Pageable pageable) {
Page<Member> members = memberRepository.findAll(queryRequest, pageable);
return members.map(MemberFindAllResponse::of);
}

@Transactional
public void withdrawMember(Long memberId) {
Member member = memberRepository.findById(memberId).orElseThrow(() -> new CustomException(MEMBER_NOT_FOUND));
member.withdraw();
}

@Transactional
public void updateMember(Long memberId, MemberUpdateRequest request) {
Member member =
memberRepository.findById(memberId).orElseThrow(() -> new CustomException(ErrorCode.MEMBER_NOT_FOUND));
member.updateMemberInfo(
request.studentId(),
request.name(),
request.phone(),
request.department(),
request.email(),
request.discordUsername(),
request.nickname());
}

public Page<MemberPendingFindAllResponse> findAllPendingMembers(Pageable pageable) {
Page<Member> members = memberRepository.findAllByRole(MemberRole.GUEST, pageable);
return members.map(MemberPendingFindAllResponse::of);
}

@Transactional
public MemberGrantResponse grantMember(MemberGrantRequest request) {
List<Member> verifiedMembers = getVerifiedMembers(request);
verifiedMembers.forEach(Member::grant);
return MemberGrantResponse.of(verifiedMembers);
}

private List<Member> getVerifiedMembers(MemberGrantRequest request) {
List<Long> memberIdList = request.memberIdList();
return memberIdList.stream()
.map(memberRepository::findVerifiedById)
.filter(Optional::isPresent)
.map(Optional::get)
.toList();
}
}

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package com.gdschongik.gdsc.domain.member.application;

import com.gdschongik.gdsc.domain.member.domain.Member;
import com.gdschongik.gdsc.domain.member.dto.request.MemberSignupRequest;
import com.gdschongik.gdsc.global.util.MemberUtil;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

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

private final MemberUtil memberUtil;

@Transactional
public void signupMember(MemberSignupRequest request) {
Member currentMember = memberUtil.getCurrentMember();
currentMember.signup(
request.studentId(), request.name(), request.phone(), request.department(), request.email());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,6 @@ public interface MemberCustomRepository {
Page<Member> findAll(MemberQueryRequest queryRequest, Pageable pageable);

Optional<Member> findNormalByOauthId(String oauthId);

Optional<Member> findVerifiedById(Long id);
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

import com.gdschongik.gdsc.domain.member.domain.Member;
import com.gdschongik.gdsc.domain.member.domain.MemberStatus;
import com.gdschongik.gdsc.domain.member.domain.RequirementStatus;
import com.gdschongik.gdsc.domain.member.dto.request.MemberQueryRequest;
import com.querydsl.core.BooleanBuilder;
import com.querydsl.core.types.dsl.BooleanExpression;
Expand Down Expand Up @@ -44,6 +45,34 @@ public Optional<Member> findNormalByOauthId(String oauthId) {
.fetchOne());
}

@Override
public Optional<Member> findVerifiedById(Long id) {
return Optional.ofNullable(queryFactory
.selectFrom(member)
.where(eqId(id), requirementVerified())
.fetchOne());
}

private BooleanBuilder requirementVerified() {
return new BooleanBuilder().and(discordVerified()).and(univVerified()).and(paymentVerified());
}

private BooleanExpression discordVerified() {
return member.requirement.discordStatus.eq(RequirementStatus.VERIFIED);
}

private BooleanExpression univVerified() {
return member.requirement.univStatus.eq(RequirementStatus.VERIFIED);
}

private BooleanExpression paymentVerified() {
return member.requirement.paymentStatus.eq(RequirementStatus.VERIFIED);
}

private BooleanExpression eqId(Long id) {
return member.id.eq(id);
}

private BooleanExpression eqOauthId(String oauthId) {
return member.oauthId.eq(oauthId);
}
Expand All @@ -62,7 +91,7 @@ private BooleanBuilder queryOption(MemberQueryRequest queryRequest) {
.and(eqDepartment(queryRequest.department()))
.and(eqEmail(queryRequest.email()))
.and(eqDiscordUsername(queryRequest.discordUsername()))
.and(eqDiscordNickname(queryRequest.discordNickname()));
.and(eqNickname(queryRequest.nickname()));
}

private BooleanExpression eqStudentId(String studentId) {
Expand All @@ -89,7 +118,7 @@ private BooleanExpression eqDiscordUsername(String discordUsername) {
return discordUsername != null ? member.discordUsername.containsIgnoreCase(discordUsername) : null;
}

private BooleanExpression eqDiscordNickname(String discordNickname) {
return discordNickname != null ? member.nickname.containsIgnoreCase(discordNickname) : null;
private BooleanExpression eqNickname(String nickname) {
return nickname != null ? member.nickname.containsIgnoreCase(nickname) : null;
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
package com.gdschongik.gdsc.domain.member.dao;

import com.gdschongik.gdsc.domain.member.domain.Member;
import com.gdschongik.gdsc.domain.member.domain.MemberRole;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.JpaRepository;

public interface MemberRepository extends JpaRepository<Member, Long>, MemberCustomRepository {}
public interface MemberRepository extends JpaRepository<Member, Long>, MemberCustomRepository {

Page<Member> findAllByRole(MemberRole role, Pageable pageable);
}
Loading

0 comments on commit fbba831

Please sign in to comment.