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

Feat/#23 add notification #26

Merged
merged 16 commits into from
Oct 3, 2023
Merged
Show file tree
Hide file tree
Changes from 14 commits
Commits
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
11 changes: 7 additions & 4 deletions .github/workflows/gradle.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,7 @@
name: Java CI with Gradle

on:
push:
branches: [ "main" ]
pull_request:
branches: [ "main" ]
workflow_dispatch:

permissions:
contents: read
Expand Down Expand Up @@ -38,5 +35,11 @@ jobs:
cd ./src/main/resources
echo "${{ secrets.APPLICATION }}" base64 -d > application.yml

- name: Create service-account-file.json
run: |
mkdir -p ./src/main/resources/firebase
cd ./src/main/resources/firebase
echo "${{ secrets.SERVICE_ACCOUNT_FILE }}" base64 -d > service-account-file.json

- name: Build with Gradle
run: ./gradlew clean build
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -41,5 +41,7 @@ out/

### VS Code ###
.vscode/

/src/main/resources/**/*.yml
/src/main/resources/**/*.yaml
/src/main/resources/firebase/**/*.json
7 changes: 6 additions & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -47,9 +47,14 @@ dependencies {
//swagger
implementation 'org.springdoc:springdoc-openapi-ui:1.7.0'


//sms
implementation group: 'org.apache.httpcomponents', name: 'httpclient', version: '4.5.13'

//firebase
implementation 'com.google.firebase:firebase-admin:9.2.0'

implementation group: 'com.squareup.okhttp3', name: 'okhttp', version: '4.9.0'

//querydsl 추가
implementation "com.querydsl:querydsl-jpa:5.0.0"
annotationProcessor "com.querydsl:querydsl-apt:5.0.0"
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package com.uspray.uspray.DTO.notification;

import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Builder;
import lombok.Data;

@Data
@Builder
public class FCMNotificationRequestDto {

@Schema(example = "device token")
private String token;
@Schema(example = "오펜하이머")
private String title;
@Schema(example = "나는 곧 쭈꾸미오")
dong2ast marked this conversation as resolved.
Show resolved Hide resolved
private String body;

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package com.uspray.uspray.DTO.notification;

import com.uspray.uspray.Enums.NotificationType;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;

@Data
public class NotificationAgreeDto {

@Schema(example = "2")
private NotificationType notificationType;
dong2ast marked this conversation as resolved.
Show resolved Hide resolved
@Schema(example = "false")
private Boolean agree;

}
16 changes: 16 additions & 0 deletions src/main/java/com/uspray/uspray/Enums/NotificationType.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package com.uspray.uspray.Enums;

import lombok.AccessLevel;
import lombok.Getter;
import lombok.RequiredArgsConstructor;

@Getter
@RequiredArgsConstructor(access = AccessLevel.PRIVATE)
public enum NotificationType {
PRAY_TIME("기도합시다~", "기도 시간: 오전 8시"),
PRAY_FOR_ME("기도받았다~", "다른 사람이 내 기도 제목을 기도 했을 때"),
SHARED_MY_PRAY("공유~", "다른 사람이 내 기도 제목을 공유 받았을 때")
;
private final String title;
private final String body;
}
1 change: 1 addition & 0 deletions src/main/java/com/uspray/uspray/config/SecurityConfig.java
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
.antMatchers("/auth/**").permitAll()
.antMatchers("/swagger-ui/**", "/v3/api-docs/**", "/api-docs/**", "/swagger-ui.html").permitAll()
.antMatchers("/sms/**").permitAll()
.antMatchers("/admin/**").permitAll()
.anyRequest().authenticated()
.and()
.apply(new JwtSecurityConfig(tokenProvider));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
import com.uspray.uspray.DTO.auth.request.FindPwDto;
import com.uspray.uspray.DTO.auth.request.MemberLoginRequestDto;
import com.uspray.uspray.DTO.auth.request.MemberRequestDto;
import com.uspray.uspray.DTO.auth.request.TokenRequestDto;
import com.uspray.uspray.DTO.ApiResponseDto;
import com.uspray.uspray.DTO.auth.TokenDto;
import com.uspray.uspray.exception.SuccessStatus;
Expand Down
29 changes: 29 additions & 0 deletions src/main/java/com/uspray/uspray/controller/FCMController.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package com.uspray.uspray.controller;

import com.uspray.uspray.DTO.ApiResponseDto;
import com.uspray.uspray.DTO.notification.FCMNotificationRequestDto;
import com.uspray.uspray.exception.SuccessStatus;
import com.uspray.uspray.service.FCMNotificationService;
import java.io.IOException;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequiredArgsConstructor
public class FCMController {

private final FCMNotificationService fcmNotificationService;

@PostMapping("/admin/send/push")
public ApiResponseDto<?> pushMessage(@RequestBody FCMNotificationRequestDto requestDto) throws IOException {

fcmNotificationService.sendMessageTo(
requestDto.getToken(),
requestDto.getTitle(),
requestDto.getBody());
return ApiResponseDto.success(SuccessStatus.PUSH_SUCCESS);
}

}
27 changes: 20 additions & 7 deletions src/main/java/com/uspray/uspray/controller/MemberController.java
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
package com.uspray.uspray.controller;

import com.uspray.uspray.DTO.notification.NotificationAgreeDto;
import com.uspray.uspray.DTO.ApiResponseDto;
import com.uspray.uspray.exception.SuccessStatus;
import com.uspray.uspray.service.MemberService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.security.SecurityRequirement;
import io.swagger.v3.oas.annotations.tags.Tag;
Expand All @@ -12,6 +14,7 @@
import org.springframework.security.core.userdetails.User;
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.RestController;

Expand All @@ -24,11 +27,21 @@ public class MemberController {

private final MemberService memberService;

@Operation(summary = "전화번호 변경")
@PostMapping("/{changePhone}")
public ApiResponseDto<?> changePhone(@AuthenticationPrincipal User user,
@Schema(example = "01046518879") @PathVariable("changePhone") String changePhone) {
memberService.changePhone(user.getUsername(), changePhone);
return ApiResponseDto.success(SuccessStatus.CHANGE_PHONE_SUCCESS);
}
@Operation(summary = "전화번호 변경")
@PostMapping("/{changePhone}")
public ApiResponseDto<?> changePhone(
@Parameter(hidden = true) @AuthenticationPrincipal User user,
@Schema(example = "01046518879") @PathVariable("changePhone") String changePhone) {
dong2ast marked this conversation as resolved.
Show resolved Hide resolved
memberService.changePhone(user.getUsername(), changePhone);
return ApiResponseDto.success(SuccessStatus.CHANGE_PHONE_SUCCESS);
}

@Operation(summary = "알림 On/Off")
dong2ast marked this conversation as resolved.
Show resolved Hide resolved
@PostMapping("/nodification-setting")
public ApiResponseDto<?> setNotificationAgree(
@Parameter(hidden = true) @AuthenticationPrincipal User user,
@RequestBody NotificationAgreeDto notificationAgreeDto) {
memberService.changeNotificationAgree(user.getUsername(), notificationAgreeDto);
return ApiResponseDto.success(SuccessStatus.CHANGE_PUSH_AGREE_SUCCESS);
}
}
30 changes: 30 additions & 0 deletions src/main/java/com/uspray/uspray/domain/FCMMessage.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package com.uspray.uspray.domain;

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

@Builder
@AllArgsConstructor
@Getter
public class FCMMessage {
private boolean validate_only;
private Message message;

@Builder
@AllArgsConstructor
@Getter
public static class Message {
private Notification notification; // 모든 mobile os를 아우를수 있는 Notification
private String token; // 특정 device에 알림을 보내기위해 사용
}

@Builder
@AllArgsConstructor
@Getter
public static class Notification {
private String title;
private String body;
private String image;
}
}
25 changes: 25 additions & 0 deletions src/main/java/com/uspray/uspray/domain/Member.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.uspray.uspray.domain;

import com.uspray.uspray.DTO.notification.NotificationAgreeDto;
import com.uspray.uspray.Enums.Authority;
import com.uspray.uspray.common.domain.AuditingTimeEntity;
import javax.persistence.Column;
Expand Down Expand Up @@ -35,13 +36,22 @@ public class Member extends AuditingTimeEntity {
private String phone;
private String birth;
private String gender;
private String firebaseToken;

private Boolean firstNotiAgree = true;
private Boolean secondNotiAgree= true;
private Boolean thirdNotiAgree = true;

private final Boolean deleted = false;

@Enumerated(EnumType.STRING)
private Authority authority;


public void changeFirebaseToken(String firebaseToken) {
this.firebaseToken = firebaseToken;
}

public void changePhone(String phone) {
this.phone = phone;
}
Expand All @@ -62,4 +72,19 @@ public Member(String userId, String password, String name, String phone, String
this.authority = authority;
}

public void changeAgree(NotificationAgreeDto notificationAgreeDto) {
dong2ast marked this conversation as resolved.
Show resolved Hide resolved
switch (notificationAgreeDto.getNotificationType()) {
case PRAY_TIME:
this.firstNotiAgree = notificationAgreeDto.getAgree();
break;
case PRAY_FOR_ME:
this.secondNotiAgree = notificationAgreeDto.getAgree();
break;
case SHARED_MY_PRAY:
this.thirdNotiAgree = notificationAgreeDto.getAgree();
break;
default:
break;
}
}
}
4 changes: 3 additions & 1 deletion src/main/java/com/uspray/uspray/exception/SuccessStatus.java
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@
@RequiredArgsConstructor(access = AccessLevel.PRIVATE)
public enum SuccessStatus {


/**
* 200 OK
*/
Expand All @@ -24,6 +23,8 @@ public enum SuccessStatus {
CHECK_USER_ID_SUCCESS(HttpStatus.OK, "사용 가능한 아이디입니다."),
UPDATE_PRAY_SUCCESS(HttpStatus.OK, "기도제목 수정에 성공했습니다."),
REISSUE_SUCCESS(HttpStatus.OK, "토큰 재발급에 성공했습니다."),
PUSH_SUCCESS(HttpStatus.OK, "푸쉬 알림을 성공적으로 전송했습니다."),
CHANGE_PUSH_AGREE_SUCCESS(HttpStatus.OK, "푸쉬 알림 설정을 성공적으로 변경했습니다."),


/*
Expand All @@ -41,4 +42,5 @@ public enum SuccessStatus {

private final HttpStatus httpStatus;
private final String message;

}
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,8 @@ public interface MemberRepository extends JpaRepository<Member, Long> {

Optional<Member> findByUserId(String userId);

Optional<Member> findByPhone(String phone);

boolean existsByUserId(String userId);

boolean existsByPhone(String phone);

Member findByNameAndPhone(String name, String phone);

Member findByNameAndPhoneAndUserId(String name, String phone, String userId);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package com.uspray.uspray.infrastructure.query;

import com.uspray.uspray.domain.Member;
import java.util.List;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import org.springframework.stereotype.Repository;

@Repository
public interface MemberQueryRepository extends JpaRepository<Member, Long> {

@Query("select m.firebaseToken from Member m where m.firstNotiAgree = :agree")
List<String> getDeviceTokensByFirstNotiAgree(@Param("agree") Boolean agree);

}
5 changes: 1 addition & 4 deletions src/main/java/com/uspray/uspray/service/AuthService.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,10 @@
import com.uspray.uspray.DTO.auth.request.FindPwDto;
import com.uspray.uspray.DTO.auth.request.MemberLoginRequestDto;
import com.uspray.uspray.DTO.auth.request.MemberRequestDto;
import com.uspray.uspray.DTO.auth.request.TokenRequestDto;
import com.uspray.uspray.DTO.auth.response.MemberResponseDto;
import com.uspray.uspray.domain.Member;
import com.uspray.uspray.exception.ErrorStatus;
import com.uspray.uspray.exception.model.ExistIdException;
import com.uspray.uspray.exception.model.TokenNotValidException;
import com.uspray.uspray.infrastructure.MemberRepository;
import com.uspray.uspray.jwt.TokenProvider;
import java.util.concurrent.TimeUnit;
Expand All @@ -37,8 +35,7 @@ public class AuthService {
public MemberResponseDto signup(MemberRequestDto memberRequestDto) {
// 핸드폰번호가 존재하거나 아이디가 존재하면 에러
// 핸드폰 번호 또는 아이디가 이미 존재하는지 확인
if (memberRepository.existsByUserId(memberRequestDto.getUserId())
|| memberRepository.existsByPhone(memberRequestDto.getPhone())) {
if (memberRepository.existsByUserId(memberRequestDto.getUserId())) {
dong2ast marked this conversation as resolved.
Show resolved Hide resolved
throw new RuntimeException("이미 가입되어 있는 유저입니다");
}

Expand Down
Loading