notification
This commit is contained in:
@@ -120,6 +120,16 @@
|
|||||||
<artifactId>spring-boot-starter-test</artifactId>
|
<artifactId>spring-boot-starter-test</artifactId>
|
||||||
<scope>test</scope>
|
<scope>test</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.auth0</groupId>
|
||||||
|
<artifactId>java-jwt</artifactId>
|
||||||
|
<version>4.5.0</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.eatthepath</groupId>
|
||||||
|
<artifactId>pushy</artifactId>
|
||||||
|
<version>0.15.4</version>
|
||||||
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
<build>
|
<build>
|
||||||
<plugins>
|
<plugins>
|
||||||
|
|||||||
@@ -9,7 +9,11 @@ import java.io.InputStreamReader;
|
|||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
|
|
||||||
|
import com.auth0.jwt.JWT;
|
||||||
|
import com.auth0.jwt.interfaces.DecodedJWT;
|
||||||
|
import com.mgm.mcrm.apigateway.common.dtos.LoginUserInfo;
|
||||||
import com.mgm.mcrm.apigateway.common.utils.LogUtil;
|
import com.mgm.mcrm.apigateway.common.utils.LogUtil;
|
||||||
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.springframework.boot.system.ApplicationHome;
|
import org.springframework.boot.system.ApplicationHome;
|
||||||
import org.springframework.core.io.ClassPathResource;
|
import org.springframework.core.io.ClassPathResource;
|
||||||
@@ -99,4 +103,27 @@ public class SysCommon {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static LoginUserInfo parseUserFromToken(String tokenContent) {
|
||||||
|
LoginUserInfo loginUser = null;
|
||||||
|
if(StringUtils.isNotBlank(tokenContent)) {
|
||||||
|
try {
|
||||||
|
tokenContent = tokenContent.replace("Bearer ", "");
|
||||||
|
|
||||||
|
DecodedJWT decodeData = JWT.decode(tokenContent);
|
||||||
|
loginUser = new LoginUserInfo();
|
||||||
|
String userId = decodeData.getSubject();
|
||||||
|
if(StringUtils.isNotBlank(userId)) {
|
||||||
|
loginUser.setId(Long.parseLong(userId));
|
||||||
|
}else {
|
||||||
|
loginUser.setId(-1L);
|
||||||
|
}
|
||||||
|
loginUser.setLoginId(decodeData.getClaim("login_id").asString());
|
||||||
|
loginUser.setGroupName(decodeData.getClaim("user_group").asString());
|
||||||
|
}catch(Exception err) {
|
||||||
|
LogUtil.error(SysCommon.class, "Parse Token failed:"+err.getMessage());
|
||||||
|
loginUser =null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return loginUser;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,12 @@
|
|||||||
|
package com.mgm.mcrm.apigateway.common.dtos;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public class LoginUserInfo {
|
||||||
|
private Long id;
|
||||||
|
private String loginId;
|
||||||
|
private String displayName;
|
||||||
|
private String groupName;
|
||||||
|
private String tokenUuid;
|
||||||
|
}
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
package com.mgm.mcrm.apigateway.common.utils;
|
||||||
|
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
@Component
|
||||||
|
public class NotificationUtil {
|
||||||
|
|
||||||
|
public String distinguishLanguage(String inputMsg,Integer languageIndex){
|
||||||
|
|
||||||
|
if (StringUtils.isBlank(inputMsg)) {
|
||||||
|
return inputMsg;
|
||||||
|
}
|
||||||
|
String preferredTag = Integer.valueOf(1).equals(languageIndex) ? "CN" : "EN";
|
||||||
|
String fallbackTag = Integer.valueOf(1).equals(languageIndex) ? "EN" : "CN";
|
||||||
|
String preferredText = extractNotificationText(inputMsg, preferredTag);
|
||||||
|
if (StringUtils.isNotBlank(preferredText)) {
|
||||||
|
return preferredText;
|
||||||
|
}
|
||||||
|
String fallbackText = extractNotificationText(inputMsg, fallbackTag);
|
||||||
|
return StringUtils.isNotBlank(fallbackText) ? fallbackText : inputMsg;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private static String extractNotificationText(String text, String tag) {
|
||||||
|
String marker = "#" + tag + "#";
|
||||||
|
int start = text.indexOf(marker);
|
||||||
|
if (start < 0) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
start += marker.length();
|
||||||
|
int end = text.indexOf(marker, start);
|
||||||
|
if (end < 0) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return text.substring(start, end).trim();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
+12
@@ -46,6 +46,12 @@ public class DaylightConfigurationScheduler {
|
|||||||
public void fetchDaylightConfigurationOnStartupIfMissing() {
|
public void fetchDaylightConfigurationOnStartupIfMissing() {
|
||||||
LogUtil.info(DaylightConfigurationScheduler.class, "Checking saved Daylight configurations on startup");
|
LogUtil.info(DaylightConfigurationScheduler.class, "Checking saved Daylight configurations on startup");
|
||||||
try {
|
try {
|
||||||
|
if (cfgDaylightConfigurationDao.existsSavedDaylightConfiguration()) {
|
||||||
|
LogUtil.info(DaylightConfigurationScheduler.class, "Saved Daylight configurations found, skip startup fetch");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
LogUtil.warn(DaylightConfigurationScheduler.class, "No saved Daylight configurations found, start startup fetch");
|
||||||
BaseApiResponse configResponse = daylightFetchConfigurationService.fetchDaylightConfiguration();
|
BaseApiResponse configResponse = daylightFetchConfigurationService.fetchDaylightConfiguration();
|
||||||
if (configResponse.isSuccess()) {
|
if (configResponse.isSuccess()) {
|
||||||
LogUtil.info(DaylightConfigurationScheduler.class, "Startup configurations completed: " + configResponse.getMessage());
|
LogUtil.info(DaylightConfigurationScheduler.class, "Startup configurations completed: " + configResponse.getMessage());
|
||||||
@@ -67,6 +73,12 @@ public class DaylightConfigurationScheduler {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (cfgDaylightConfigurationDao.existsSavedDaylightBlockCodes()) {
|
||||||
|
LogUtil.info(DaylightConfigurationScheduler.class, "Saved Daylight block codes found, skip startup fetch");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
LogUtil.warn(DaylightConfigurationScheduler.class, "No saved Daylight block codes found, start startup fetch");
|
||||||
BaseApiResponse blockResponse = daylightFetchConfigurationService.fetchDaylightBlockCodes();
|
BaseApiResponse blockResponse = daylightFetchConfigurationService.fetchDaylightBlockCodes();
|
||||||
if (blockResponse.isSuccess()) {
|
if (blockResponse.isSuccess()) {
|
||||||
LogUtil.info(DaylightConfigurationScheduler.class, "Startup block codes completed: " + blockResponse.getMessage());
|
LogUtil.info(DaylightConfigurationScheduler.class, "Startup block codes completed: " + blockResponse.getMessage());
|
||||||
|
|||||||
+1
-1
@@ -106,7 +106,7 @@ public class DaylightFetchConfigurationService {
|
|||||||
String apiUrl = daylightApiSetting.getServerUrl() + path;
|
String apiUrl = daylightApiSetting.getServerUrl() + path;
|
||||||
String types = "PurchaseElement,MarketSegment,RatePlan,BookingSource,MembershipLevel," +
|
String types = "PurchaseElement,MarketSegment,RatePlan,BookingSource,MembershipLevel," +
|
||||||
"Attribute,RoomType,GuaranteeType,DistributionChannel,AgeBucket,CancellationReason," +
|
"Attribute,RoomType,GuaranteeType,DistributionChannel,AgeBucket,CancellationReason," +
|
||||||
"ComplimentaryAccountingPreset,ComplimentaryType,TransactionCode";
|
"ComplimentaryAccountingPreset,ComplimentaryType,TransactionCode,Room";
|
||||||
|
|
||||||
String pagingNext;
|
String pagingNext;
|
||||||
int pageNumber = 1;
|
int pageNumber = 1;
|
||||||
|
|||||||
+7
@@ -29,4 +29,11 @@ public interface CfgDaylightConfigurationDao extends JpaRepository<CfgDaylightCo
|
|||||||
+ "and c.configValue is not null "
|
+ "and c.configValue is not null "
|
||||||
+ "and c.configValue <> ''")
|
+ "and c.configValue <> ''")
|
||||||
boolean existsSavedConfigurationByDlPropertyId(String dlPropertyId);
|
boolean existsSavedConfigurationByDlPropertyId(String dlPropertyId);
|
||||||
|
|
||||||
|
@Query("select case when count(c) > 0 then true else false end "
|
||||||
|
+ "from CfgDaylightConfiguration c "
|
||||||
|
+ "where c.configName = 'BlockCode' "
|
||||||
|
+ "and c.configValue is not null "
|
||||||
|
+ "and c.configValue <> ''")
|
||||||
|
boolean existsSavedDaylightBlockCodes();
|
||||||
}
|
}
|
||||||
|
|||||||
+3
@@ -7,6 +7,7 @@ import com.mgm.mcrm.apigateway.logging.services.WebhookLogService;
|
|||||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
import jakarta.annotation.Resource;
|
import jakarta.annotation.Resource;
|
||||||
import jakarta.servlet.http.HttpServletRequest;
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.springframework.http.HttpStatus;
|
import org.springframework.http.HttpStatus;
|
||||||
import org.springframework.http.ResponseEntity;
|
import org.springframework.http.ResponseEntity;
|
||||||
@@ -14,6 +15,7 @@ import org.springframework.web.bind.annotation.*;
|
|||||||
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
@Tag(name = "Allotment", description = "APIs for Room Allotment functions")
|
@Tag(name = "Allotment", description = "APIs for Room Allotment functions")
|
||||||
@RestController
|
@RestController
|
||||||
@RequestMapping("/api/daylight/webhook")
|
@RequestMapping("/api/daylight/webhook")
|
||||||
@@ -56,6 +58,7 @@ public class DaylightWebhook {
|
|||||||
}catch(Exception err){
|
}catch(Exception err){
|
||||||
result.setSuccess(false);
|
result.setSuccess(false);
|
||||||
result.setMessage("Handle Message ["+messageId+"] failed with error:"+err.getMessage());
|
result.setMessage("Handle Message ["+messageId+"] failed with error:"+err.getMessage());
|
||||||
|
log.error("Handle Message [{}] failed with error:", messageId, err);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+1
@@ -48,6 +48,7 @@ public class ReservationNotificationHandler implements DaylightWebhookHandler {
|
|||||||
|
|
||||||
private Bookings convertEventToBooking(ReservationNotificationEvent eventData) {
|
private Bookings convertEventToBooking(ReservationNotificationEvent eventData) {
|
||||||
|
|
||||||
|
|
||||||
log.info("Reservation Notification Event Data: {}", JSON.toJSONString(eventData));
|
log.info("Reservation Notification Event Data: {}", JSON.toJSONString(eventData));
|
||||||
|
|
||||||
Bookings result = new Bookings();
|
Bookings result = new Bookings();
|
||||||
|
|||||||
@@ -0,0 +1,13 @@
|
|||||||
|
package com.mgm.mcrm.apigateway.logging.dao;
|
||||||
|
|
||||||
|
import com.mgm.mcrm.apigateway.logging.models.SysLogDeviceToken;
|
||||||
|
import org.springframework.data.jpa.repository.JpaRepository;
|
||||||
|
import org.springframework.stereotype.Repository;
|
||||||
|
|
||||||
|
@Repository
|
||||||
|
public interface SysLogDeviceTokenRepository extends JpaRepository<SysLogDeviceToken, Long> {
|
||||||
|
|
||||||
|
SysLogDeviceToken findByUserId(String bookerId);
|
||||||
|
|
||||||
|
void deleteByUserId(String userId);
|
||||||
|
}
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
package com.mgm.mcrm.apigateway.logging.models;
|
||||||
|
|
||||||
|
import jakarta.persistence.*;
|
||||||
|
import lombok.Data;
|
||||||
|
import org.hibernate.annotations.CreationTimestamp;
|
||||||
|
import org.hibernate.annotations.UpdateTimestamp;
|
||||||
|
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@Entity
|
||||||
|
@Table(name = "sys_log_device_token",
|
||||||
|
indexes = {
|
||||||
|
@Index(name = "idx_device_token", columnList = "deviceToken")
|
||||||
|
})
|
||||||
|
public class SysLogDeviceToken {
|
||||||
|
|
||||||
|
@Id
|
||||||
|
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||||
|
@Column(name = "id")
|
||||||
|
private Integer id;
|
||||||
|
|
||||||
|
@Column(name = "user_id", unique = true, nullable = false, length = 64)
|
||||||
|
private String userId;
|
||||||
|
|
||||||
|
@Column(name = "device_token", length = 255)
|
||||||
|
private String deviceToken;
|
||||||
|
|
||||||
|
@CreationTimestamp
|
||||||
|
@Column(name = "created_at", updatable = false)
|
||||||
|
private Date createdAt;
|
||||||
|
|
||||||
|
@UpdateTimestamp
|
||||||
|
@Column(name = "updated_at")
|
||||||
|
private Date updatedAt;
|
||||||
|
|
||||||
|
@Column(name = "use_language_type")
|
||||||
|
private Integer useLanguageType;
|
||||||
|
}
|
||||||
@@ -0,0 +1,66 @@
|
|||||||
|
package com.mgm.mcrm.apigateway.logging.models;
|
||||||
|
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||||
|
import jakarta.persistence.*;
|
||||||
|
import lombok.Data;
|
||||||
|
import org.hibernate.annotations.Nationalized;
|
||||||
|
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@Entity
|
||||||
|
@Table(name = "sys_log_notification")
|
||||||
|
public class SysLogNotification {
|
||||||
|
|
||||||
|
@Id
|
||||||
|
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||||
|
@Column(name = "id")
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
@Column(name = "user_id", length = 64, nullable = false)
|
||||||
|
private String userId;
|
||||||
|
|
||||||
|
@Column(name = "sender_id", length = 64)
|
||||||
|
private String senderId;
|
||||||
|
|
||||||
|
@Column(name = "transaction_id")
|
||||||
|
private String transactionId;
|
||||||
|
|
||||||
|
@Column(name = "device_token")
|
||||||
|
private String deviceToken;
|
||||||
|
|
||||||
|
@Column(name = "status", nullable = false)
|
||||||
|
private Integer status;
|
||||||
|
|
||||||
|
@Nationalized
|
||||||
|
@Column(name = "title", columnDefinition = "NVARCHAR(MAX)")
|
||||||
|
private String title;
|
||||||
|
|
||||||
|
@Nationalized
|
||||||
|
@Column(name = "content", columnDefinition = "NVARCHAR(MAX)")
|
||||||
|
private String content;
|
||||||
|
|
||||||
|
@Column(name = "booking_id", length = 100)
|
||||||
|
private String bookingId;
|
||||||
|
|
||||||
|
@Column(name = "confirmation_no", length = 100)
|
||||||
|
private String confirmationNo;
|
||||||
|
|
||||||
|
@Column(name = "booking_type")
|
||||||
|
private String bookingType;
|
||||||
|
|
||||||
|
@Column(name = "result_message", length = 512)
|
||||||
|
private String resultMessage;
|
||||||
|
|
||||||
|
@Column(name = "apn_response_id")
|
||||||
|
private String apnResponseId;
|
||||||
|
|
||||||
|
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
|
||||||
|
@Column(name = "created_at")
|
||||||
|
private LocalDateTime createdAt;
|
||||||
|
|
||||||
|
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
|
||||||
|
@Column(name = "updated_at")
|
||||||
|
private LocalDateTime updatedAt;
|
||||||
|
}
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
package com.mgm.mcrm.apigateway.logging.repositories;
|
||||||
|
|
||||||
|
import com.mgm.mcrm.apigateway.logging.models.SysLogDeviceToken;
|
||||||
|
import org.springframework.data.jpa.repository.JpaRepository;
|
||||||
|
import org.springframework.stereotype.Repository;
|
||||||
|
|
||||||
|
@Repository
|
||||||
|
public interface SysLogDeviceTokenDao extends JpaRepository<SysLogDeviceToken, Long> {
|
||||||
|
|
||||||
|
SysLogDeviceToken findByUserId(String bookerId);
|
||||||
|
|
||||||
|
void deleteByUserId(String userId);
|
||||||
|
}
|
||||||
+14
@@ -0,0 +1,14 @@
|
|||||||
|
package com.mgm.mcrm.apigateway.logging.repositories;
|
||||||
|
|
||||||
|
import com.mgm.mcrm.apigateway.logging.models.SysLogNotification;
|
||||||
|
import org.springframework.data.jpa.repository.JpaRepository;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public interface SysLogNotificationRepository extends JpaRepository<SysLogNotification, Long> {
|
||||||
|
List<SysLogNotification> findByUserIdAndStatus(String userId, Integer status);
|
||||||
|
|
||||||
|
List<SysLogNotification> findAllByDeviceTokenAndTransactionId(String deviceToken, String transactionId);
|
||||||
|
|
||||||
|
long countByUserIdAndStatus(String userId, Integer status);
|
||||||
|
}
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
package com.mgm.mcrm.apigateway.logging.services;
|
||||||
|
|
||||||
|
import com.mgm.mcrm.apigateway.common.utils.LogUtil;
|
||||||
|
import com.mgm.mcrm.apigateway.logging.models.SysLogDeviceToken;
|
||||||
|
import com.mgm.mcrm.apigateway.logging.repositories.SysLogDeviceTokenDao;
|
||||||
|
import jakarta.annotation.Resource;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
public class SysLogDeviceTokenService {
|
||||||
|
}
|
||||||
+142
@@ -0,0 +1,142 @@
|
|||||||
|
package com.mgm.mcrm.apigateway.notification.services;
|
||||||
|
|
||||||
|
import com.eatthepath.pushy.apns.ApnsClient;
|
||||||
|
import com.eatthepath.pushy.apns.PushNotificationResponse;
|
||||||
|
import com.eatthepath.pushy.apns.util.SimpleApnsPayloadBuilder;
|
||||||
|
import com.eatthepath.pushy.apns.util.SimpleApnsPushNotification;
|
||||||
|
import com.eatthepath.pushy.apns.util.concurrent.PushNotificationFuture;
|
||||||
|
import com.mgm.mcrm.apigateway.common.dtos.BaseApiResponse;
|
||||||
|
import com.mgm.mcrm.apigateway.common.utils.LogUtil;
|
||||||
|
import com.mgm.mcrm.apigateway.logging.models.SysLogNotification;
|
||||||
|
import com.mgm.mcrm.apigateway.logging.repositories.SysLogNotificationRepository;
|
||||||
|
import jakarta.annotation.Resource;
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
public class ApnNotificationService {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private ApnsClient apnsClient;
|
||||||
|
@Value("${apns.bundle-id}")
|
||||||
|
private String bundleId;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private SysLogNotificationRepository notificationLogDao;
|
||||||
|
|
||||||
|
private final Logger logger = LoggerFactory.getLogger(ApnNotificationService.class);
|
||||||
|
|
||||||
|
public BaseApiResponse pushApnMessage(String transactionId, String deviceToken, String title, String body, boolean isWaitResponse) {
|
||||||
|
return pushApnMessage(transactionId, deviceToken, title, body, isWaitResponse, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public BaseApiResponse pushApnMessage(String transactionId, String deviceToken, String title, String body, boolean isWaitResponse, String confirmNo) {
|
||||||
|
BaseApiResponse result = new BaseApiResponse();
|
||||||
|
if(StringUtils.isBlank(deviceToken)){
|
||||||
|
result.setSuccess(false);
|
||||||
|
result.setMessage("Device Token is empty");
|
||||||
|
return result;
|
||||||
|
}else{
|
||||||
|
LogUtil.info(ApnNotificationService.class, "Pushing Apn Start");
|
||||||
|
SimpleApnsPayloadBuilder payloadBuilder = new SimpleApnsPayloadBuilder();
|
||||||
|
payloadBuilder
|
||||||
|
.setAlertTitle(title)
|
||||||
|
.setAlertBody(body)
|
||||||
|
.setSound("default")
|
||||||
|
.setBadgeNumber(1);
|
||||||
|
if(StringUtils.isNotBlank(confirmNo)){
|
||||||
|
payloadBuilder.addCustomProperty("ConfirmNo", confirmNo);
|
||||||
|
}
|
||||||
|
String payload = payloadBuilder.build();
|
||||||
|
|
||||||
|
SimpleApnsPushNotification pushNotification = new SimpleApnsPushNotification(
|
||||||
|
deviceToken,
|
||||||
|
bundleId,
|
||||||
|
payload
|
||||||
|
);
|
||||||
|
PushNotificationFuture<SimpleApnsPushNotification, PushNotificationResponse<SimpleApnsPushNotification>>
|
||||||
|
sendFuture = apnsClient.sendNotification(pushNotification);
|
||||||
|
if(isWaitResponse){
|
||||||
|
String resultMessage ="";
|
||||||
|
boolean isSuccess =false;
|
||||||
|
String apnResponseId=null;
|
||||||
|
try {
|
||||||
|
PushNotificationResponse<SimpleApnsPushNotification> response = sendFuture.get();
|
||||||
|
if(response!=null && response.isAccepted()){
|
||||||
|
isSuccess=true;
|
||||||
|
apnResponseId = response.getApnsId()==null?null:response.getApnsId().toString();
|
||||||
|
resultMessage = "APN message pushed success with response Id:"+response.getApnsId();
|
||||||
|
}else if(response!=null && !response.isAccepted()){
|
||||||
|
resultMessage = "APN message was rejected with reason:"+response.getRejectionReason();
|
||||||
|
}else{
|
||||||
|
resultMessage = "APN no response";
|
||||||
|
}
|
||||||
|
}catch(Exception err){
|
||||||
|
resultMessage = "Push APN message failed with error:"+err.getMessage();
|
||||||
|
}
|
||||||
|
result.setSuccess(isSuccess);
|
||||||
|
result.setMessage(resultMessage);
|
||||||
|
LogUtil.info(ApnNotificationService.class, "Pushing Apn result:"+resultMessage);
|
||||||
|
if(StringUtils.isNotBlank(transactionId) && StringUtils.isNotBlank(deviceToken)){
|
||||||
|
List<SysLogNotification> notificationLogs = notificationLogDao.findAllByDeviceTokenAndTransactionId(deviceToken, transactionId);
|
||||||
|
if(!notificationLogs.isEmpty()){
|
||||||
|
LocalDateTime currentTime = LocalDateTime.now();
|
||||||
|
for(SysLogNotification logItem:notificationLogs){
|
||||||
|
logItem.setStatus(isSuccess?0:-1);
|
||||||
|
logItem.setApnResponseId(apnResponseId);
|
||||||
|
logItem.setUpdatedAt(currentTime);
|
||||||
|
logItem.setResultMessage(resultMessage);
|
||||||
|
}
|
||||||
|
notificationLogDao.saveAll(notificationLogs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}else{
|
||||||
|
result.setSuccess(true);
|
||||||
|
result.setMessage("APN message was pushed and process with ASYNC mode, use txnId to trace log");
|
||||||
|
// process response in async mode
|
||||||
|
sendFuture.whenComplete((response, throwable) -> {
|
||||||
|
String resultMessage ="";
|
||||||
|
boolean isSuccess =false;
|
||||||
|
String apnResponseId=null;
|
||||||
|
if (response != null && response.isAccepted()) {
|
||||||
|
isSuccess =true;
|
||||||
|
apnResponseId = response.getApnsId()==null?null:response.getApnsId().toString();
|
||||||
|
resultMessage = "APN message pushed success with response Id:"+response.getApnsId();
|
||||||
|
} else if (response != null && !response.isAccepted()) {
|
||||||
|
resultMessage = "APN message was rejected with reason:"+response.getRejectionReason();
|
||||||
|
} else {
|
||||||
|
if(throwable!=null){
|
||||||
|
resultMessage = "Push APN message failed with error:"+throwable.getMessage();
|
||||||
|
}else{
|
||||||
|
resultMessage = "APN no response";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(!isSuccess)
|
||||||
|
logger.error(resultMessage);
|
||||||
|
//-- update notification log
|
||||||
|
if(StringUtils.isNotBlank(transactionId) && StringUtils.isNotBlank(deviceToken)){
|
||||||
|
List<SysLogNotification> notificationLogs = notificationLogDao.findAllByDeviceTokenAndTransactionId(deviceToken, transactionId);
|
||||||
|
if(!notificationLogs.isEmpty()){
|
||||||
|
LocalDateTime currentTime = LocalDateTime.now();
|
||||||
|
for(SysLogNotification logItem:notificationLogs){
|
||||||
|
logItem.setStatus(isSuccess?0:-1);
|
||||||
|
logItem.setApnResponseId(apnResponseId);
|
||||||
|
logItem.setUpdatedAt(currentTime);
|
||||||
|
logItem.setResultMessage(resultMessage);
|
||||||
|
}
|
||||||
|
notificationLogDao.saveAll(notificationLogs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,109 @@
|
|||||||
|
package com.mgm.mcrm.apigateway.proxy.config;
|
||||||
|
|
||||||
|
import com.eatthepath.pushy.apns.ApnsClient;
|
||||||
|
import com.eatthepath.pushy.apns.ApnsClientBuilder;
|
||||||
|
import com.eatthepath.pushy.apns.auth.ApnsSigningKey;
|
||||||
|
import com.eatthepath.pushy.apns.proxy.HttpProxyHandlerFactory;
|
||||||
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.util.StringUtils;
|
||||||
|
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.net.InetSocketAddress;
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
public class ApnClientConfig {
|
||||||
|
|
||||||
|
@Value("${apns.team-id}")
|
||||||
|
private String teamId;
|
||||||
|
|
||||||
|
@Value("${apns.key-id}")
|
||||||
|
private String keyId;
|
||||||
|
|
||||||
|
@Value("${apns.key-file}")
|
||||||
|
private String keyFilePath;
|
||||||
|
|
||||||
|
@Value("${apns.host}")
|
||||||
|
private String apnHost;
|
||||||
|
|
||||||
|
@Value("${apns.proxy.enabled:false}")
|
||||||
|
private boolean proxyEnabled;
|
||||||
|
|
||||||
|
@Value("${apns.proxy.host:}")
|
||||||
|
private String proxyHost;
|
||||||
|
|
||||||
|
@Value("${apns.proxy.port:0}")
|
||||||
|
private int proxyPort;
|
||||||
|
|
||||||
|
@Value("${apns.proxy.username:}")
|
||||||
|
private String proxyUsername;
|
||||||
|
|
||||||
|
@Value("${apns.proxy.password:}")
|
||||||
|
private String proxyPassword;
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public ApnsClient apnsClient() throws Exception {
|
||||||
|
|
||||||
|
String tid = teamId != null ? teamId.trim() : "";
|
||||||
|
String kid = keyId != null ? keyId.trim() : "";
|
||||||
|
|
||||||
|
if (!StringUtils.hasText(tid) || !StringUtils.hasText(kid)) {
|
||||||
|
throw new IllegalStateException("apns.team-id / apns.key-id must be non-empty after trim");
|
||||||
|
}
|
||||||
|
|
||||||
|
InputStream privateKeyStream = openApnsKeyStream(keyFilePath);
|
||||||
|
if (privateKeyStream == null) {
|
||||||
|
throw new IllegalStateException(
|
||||||
|
"Cannot load APNs .p8 from classpath (apns.key-file=" + keyFilePath + "). "
|
||||||
|
+ "Put file under src/main/resources and use path like /AuthKey_XXX.p8");
|
||||||
|
}
|
||||||
|
|
||||||
|
ApnsClientBuilder builder = new ApnsClientBuilder()
|
||||||
|
.setSigningKey(ApnsSigningKey.loadFromInputStream(privateKeyStream, tid, kid))
|
||||||
|
.setApnsServer(apnHost.trim());
|
||||||
|
|
||||||
|
if (proxyEnabled) {
|
||||||
|
String host = proxyHost != null ? proxyHost.trim() : "";
|
||||||
|
if (!StringUtils.hasText(host) || proxyPort <= 0) {
|
||||||
|
throw new IllegalStateException("apns.proxy.host / apns.proxy.port must be configured when apns.proxy.enabled=true");
|
||||||
|
}
|
||||||
|
|
||||||
|
InetSocketAddress proxyAddress = new InetSocketAddress(host, proxyPort);
|
||||||
|
if (StringUtils.hasText(proxyUsername)) {
|
||||||
|
builder.setProxyHandlerFactory(new HttpProxyHandlerFactory(proxyAddress, proxyUsername.trim(), proxyPassword != null ? proxyPassword : ""));
|
||||||
|
} else {
|
||||||
|
builder.setProxyHandlerFactory(new HttpProxyHandlerFactory(proxyAddress));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return builder.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Spring Boot / fat jar 下用上下文 ClassLoader 读 resources 比 {@code getClass().getResourceAsStream}
|
||||||
|
* <p>
|
||||||
|
* 更可靠;兼容 {@code /xxx.p8} 与 {@code xxx.p8} 两种写法。
|
||||||
|
*/
|
||||||
|
|
||||||
|
private static InputStream openApnsKeyStream(String configuredPath) {
|
||||||
|
if (!StringUtils.hasText(configuredPath)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
String path = configuredPath.trim();
|
||||||
|
String withoutLeadingSlash = path.startsWith("/") ? path.substring(1) : path;
|
||||||
|
|
||||||
|
ClassLoader cl = Thread.currentThread().getContextClassLoader();
|
||||||
|
|
||||||
|
InputStream in = cl != null ? cl.getResourceAsStream(withoutLeadingSlash) : null;
|
||||||
|
|
||||||
|
if (in != null) {
|
||||||
|
return in;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ApnClientConfig.class.getResourceAsStream(path.startsWith("/") ? path : "/" + path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
+70
@@ -0,0 +1,70 @@
|
|||||||
|
package com.mgm.mcrm.apigateway.proxy.controllers;
|
||||||
|
|
||||||
|
import com.mgm.mcrm.apigateway.common.constants.SysCommon;
|
||||||
|
import com.mgm.mcrm.apigateway.common.dtos.BaseApiResponse;
|
||||||
|
import com.mgm.mcrm.apigateway.common.dtos.LoginUserInfo;
|
||||||
|
import com.mgm.mcrm.apigateway.common.dtos.config.DaylightApiSetting;
|
||||||
|
import com.mgm.mcrm.apigateway.common.dtos.config.EsbApiSetting;
|
||||||
|
import com.mgm.mcrm.apigateway.common.dtos.config.OperaApiSetting;
|
||||||
|
import com.mgm.mcrm.apigateway.daylight.common.services.DaylightTokenService;
|
||||||
|
import com.mgm.mcrm.apigateway.esb.common.services.EsbTokenService;
|
||||||
|
import com.mgm.mcrm.apigateway.proxy.dtos.request.SendNotificationRequest;
|
||||||
|
import com.mgm.mcrm.apigateway.proxy.exception.HttpProxyErrorHandler;
|
||||||
|
import com.mgm.mcrm.apigateway.proxy.exception.SoapProxyErrorHandler;
|
||||||
|
import com.mgm.mcrm.apigateway.proxy.services.NotificationProxyService;
|
||||||
|
import com.mgm.mcrm.apigateway.proxy.services.WebProxyService;
|
||||||
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
|
import jakarta.annotation.Resource;
|
||||||
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.http.HttpHeaders;
|
||||||
|
import org.springframework.http.HttpMethod;
|
||||||
|
import org.springframework.http.HttpStatus;
|
||||||
|
import org.springframework.http.ResponseEntity;
|
||||||
|
import org.springframework.web.bind.annotation.RequestBody;
|
||||||
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.time.Duration;
|
||||||
|
import java.util.Collections;
|
||||||
|
|
||||||
|
@Tag(name = "Notification Proxy", description = "Controller for Notification proxy")
|
||||||
|
@RestController
|
||||||
|
public class NotificationProxyController {
|
||||||
|
|
||||||
|
private final Logger logger = LoggerFactory.getLogger(WebProxyController.class);
|
||||||
|
@Resource
|
||||||
|
private NotificationProxyService notificationProxyService;
|
||||||
|
|
||||||
|
@RequestMapping("/api/notification/proxy/**")
|
||||||
|
public ResponseEntity<BaseApiResponse> invokeNotificationApiProxy(HttpServletRequest request, @RequestBody SendNotificationRequest notificationRequest) throws Exception {
|
||||||
|
LoginUserInfo requestUser = SysCommon.parseUserFromToken(request.getHeader("Authorization"));
|
||||||
|
return ResponseEntity.status(HttpStatus.OK).body(notificationProxyService.sendNotificationByRequest(notificationRequest,requestUser.getLoginId()));
|
||||||
|
}
|
||||||
|
|
||||||
|
private HttpHeaders extractHeaders(HttpServletRequest request) {
|
||||||
|
HttpHeaders headers = new HttpHeaders();
|
||||||
|
Collections.list(request.getHeaderNames()).forEach(name -> {
|
||||||
|
if (!name.equalsIgnoreCase("host") &&
|
||||||
|
!name.equalsIgnoreCase("content-length") &&
|
||||||
|
!name.equalsIgnoreCase("application-id") &&
|
||||||
|
!name.equalsIgnoreCase("authorization")
|
||||||
|
) {
|
||||||
|
headers.add(name, request.getHeader(name));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return headers;
|
||||||
|
}
|
||||||
|
|
||||||
|
private byte[] getRequestBody(HttpServletRequest request) {
|
||||||
|
try {
|
||||||
|
return request.getInputStream().readAllBytes();
|
||||||
|
} catch (IOException e) {
|
||||||
|
logger.error("Failed to read request body of request[{}]",request.getRequestURI(), e);
|
||||||
|
return new byte[0];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
package com.mgm.mcrm.apigateway.proxy.dtos.request;
|
||||||
|
|
||||||
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
|
import jakarta.validation.constraints.NotBlank;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@Schema(description = "Request to send notification by employeeId")
|
||||||
|
public class SendNotificationRequest {
|
||||||
|
@Schema(description = "Transaction Id for external tracing, if blank, internal uuid will be generated")
|
||||||
|
private String transactionId;
|
||||||
|
|
||||||
|
@Schema(description = "Employee Id to receive notification")
|
||||||
|
@NotBlank(message = "Employee Id must not be empty")
|
||||||
|
private String employeeId;
|
||||||
|
|
||||||
|
@Schema(description = "Title of message")
|
||||||
|
@NotBlank(message = "Title of message must not be blank")
|
||||||
|
private String title;
|
||||||
|
|
||||||
|
@Schema(description = "Content of message")
|
||||||
|
private String content;
|
||||||
|
|
||||||
|
@Schema(description = "Booking confirmation No if need")
|
||||||
|
private String confirmationNumber;
|
||||||
|
|
||||||
|
@Schema(description = "Type of booking ")
|
||||||
|
private String type;
|
||||||
|
}
|
||||||
@@ -0,0 +1,132 @@
|
|||||||
|
package com.mgm.mcrm.apigateway.proxy.services;
|
||||||
|
|
||||||
|
|
||||||
|
import com.mgm.mcrm.apigateway.common.dtos.BaseApiResponse;
|
||||||
|
import com.mgm.mcrm.apigateway.logging.models.SysLogDeviceToken;
|
||||||
|
import com.mgm.mcrm.apigateway.logging.models.SysLogNotification;
|
||||||
|
import com.mgm.mcrm.apigateway.logging.repositories.SysLogDeviceTokenDao;
|
||||||
|
import com.mgm.mcrm.apigateway.logging.repositories.SysLogNotificationRepository;
|
||||||
|
import com.mgm.mcrm.apigateway.notification.services.ApnNotificationService;
|
||||||
|
import com.mgm.mcrm.apigateway.proxy.dtos.request.SendNotificationRequest;
|
||||||
|
import jakarta.annotation.Resource;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
@Service
|
||||||
|
public class NotificationProxyService {
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private SysLogDeviceTokenDao sysLogDeviceTokenDao;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private SysLogNotificationRepository sysLogNotificationRepository;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private ApnNotificationService apnNotificationService;
|
||||||
|
|
||||||
|
public BaseApiResponse sendNotificationByRequest(SendNotificationRequest requestData, String senderId) {
|
||||||
|
BaseApiResponse result = new BaseApiResponse();
|
||||||
|
String[] userIds = requestData.getEmployeeId().split("[;,]");
|
||||||
|
String transactionId = requestData.getTransactionId();
|
||||||
|
if(StringUtils.isBlank(transactionId)){
|
||||||
|
transactionId = UUID.randomUUID().toString();
|
||||||
|
}
|
||||||
|
// result.setData(transactionId);
|
||||||
|
if(userIds.length>0){
|
||||||
|
int successCount =0;
|
||||||
|
for(String userId:userIds){
|
||||||
|
if(StringUtils.isNotBlank(userId)){
|
||||||
|
userId = userId.trim();
|
||||||
|
SysLogDeviceToken deviceToken = sysLogDeviceTokenDao.findByUserId(userId);
|
||||||
|
String deviceTokenValue =null;
|
||||||
|
if(deviceToken!=null){
|
||||||
|
deviceTokenValue = deviceToken.getDeviceToken();
|
||||||
|
}
|
||||||
|
|
||||||
|
Integer useLanguage = deviceToken == null ? null : deviceToken.getUseLanguageType();
|
||||||
|
String notificationTitle = resolveNotificationText(requestData.getTitle(), useLanguage);
|
||||||
|
String notificationContent = resolveNotificationText(requestData.getContent(), useLanguage);
|
||||||
|
|
||||||
|
//这里需要加上判断,判断deviceToken中的UseLanguage是什么语言 0:英文 1:中文 根据不同的Language来推送不同语言的通知
|
||||||
|
|
||||||
|
SysLogNotification notificationLog = createNotificationLogByRequest(requestData,transactionId,senderId,userId,deviceTokenValue,notificationTitle,notificationContent);
|
||||||
|
if(StringUtils.isBlank(deviceTokenValue)){
|
||||||
|
notificationLog.setStatus(-1);
|
||||||
|
notificationLog.setResultMessage("No APN token is setup for user:"+userId);
|
||||||
|
notificationLog.setUpdatedAt(LocalDateTime.now());
|
||||||
|
}
|
||||||
|
sysLogNotificationRepository.save(notificationLog);
|
||||||
|
//-- Process APN sending
|
||||||
|
BaseApiResponse sendResult = apnNotificationService.pushApnMessage(
|
||||||
|
transactionId,
|
||||||
|
deviceTokenValue,
|
||||||
|
notificationTitle,
|
||||||
|
notificationContent,
|
||||||
|
true,
|
||||||
|
requestData.getConfirmationNumber());
|
||||||
|
if(sendResult.isSuccess()){
|
||||||
|
successCount++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(successCount>0){
|
||||||
|
result.setSuccess(true);
|
||||||
|
}else{
|
||||||
|
result.setSuccess(false);
|
||||||
|
result.setMessage("No message was success processed");
|
||||||
|
}
|
||||||
|
}else{
|
||||||
|
result.setSuccess(false);
|
||||||
|
result.setMessage("employeeId list is empty");
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String resolveNotificationText(String text, Integer useLanguage) {
|
||||||
|
if (StringUtils.isBlank(text)) {
|
||||||
|
return text;
|
||||||
|
}
|
||||||
|
String preferredTag = Integer.valueOf(1).equals(useLanguage) ? "CN" : "EN";
|
||||||
|
String fallbackTag = Integer.valueOf(1).equals(useLanguage) ? "EN" : "CN";
|
||||||
|
String preferredText = extractNotificationText(text, preferredTag);
|
||||||
|
if (StringUtils.isNotBlank(preferredText)) {
|
||||||
|
return preferredText;
|
||||||
|
}
|
||||||
|
String fallbackText = extractNotificationText(text, fallbackTag);
|
||||||
|
return StringUtils.isNotBlank(fallbackText) ? fallbackText : text;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String extractNotificationText(String text, String tag) {
|
||||||
|
String marker = "#" + tag + "#";
|
||||||
|
int start = text.indexOf(marker);
|
||||||
|
if (start < 0) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
start += marker.length();
|
||||||
|
int end = text.indexOf(marker, start);
|
||||||
|
if (end < 0) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return text.substring(start, end).trim();
|
||||||
|
}
|
||||||
|
|
||||||
|
private SysLogNotification createNotificationLogByRequest(SendNotificationRequest requestData,String transactionId, String senderId, String userId, String deviceToken, String title, String content){
|
||||||
|
SysLogNotification notificationLog = new SysLogNotification();
|
||||||
|
notificationLog.setUserId(userId);
|
||||||
|
notificationLog.setDeviceToken(deviceToken);
|
||||||
|
notificationLog.setSenderId(senderId);
|
||||||
|
notificationLog.setStatus(0);
|
||||||
|
notificationLog.setConfirmationNo(requestData.getConfirmationNumber());
|
||||||
|
notificationLog.setBookingType(requestData.getType());
|
||||||
|
notificationLog.setTitle(title);
|
||||||
|
notificationLog.setContent(content);
|
||||||
|
notificationLog.setTransactionId(transactionId);
|
||||||
|
notificationLog.setCreatedAt(LocalDateTime.now());
|
||||||
|
return notificationLog;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -22,19 +22,26 @@ import com.mgm.mcrm.apigateway.basesetting.room.repositories.RoomTypeDao;
|
|||||||
import com.mgm.mcrm.apigateway.common.dtos.ServiceResult;
|
import com.mgm.mcrm.apigateway.common.dtos.ServiceResult;
|
||||||
import com.mgm.mcrm.apigateway.common.utils.DateTimeUtil;
|
import com.mgm.mcrm.apigateway.common.utils.DateTimeUtil;
|
||||||
import com.mgm.mcrm.apigateway.common.utils.LogUtil;
|
import com.mgm.mcrm.apigateway.common.utils.LogUtil;
|
||||||
|
import com.mgm.mcrm.apigateway.common.utils.NotificationUtil;
|
||||||
import com.mgm.mcrm.apigateway.esb.common.dtos.mgmapi.PlayerProfileApiResult;
|
import com.mgm.mcrm.apigateway.esb.common.dtos.mgmapi.PlayerProfileApiResult;
|
||||||
import com.mgm.mcrm.apigateway.esb.common.dtos.mgmapi.UserInfoApiRecord;
|
import com.mgm.mcrm.apigateway.esb.common.dtos.mgmapi.UserInfoApiRecord;
|
||||||
import com.mgm.mcrm.apigateway.esb.player.services.MgmUserService;
|
import com.mgm.mcrm.apigateway.esb.player.services.MgmUserService;
|
||||||
|
import com.mgm.mcrm.apigateway.logging.dao.SysLogDeviceTokenRepository;
|
||||||
|
import com.mgm.mcrm.apigateway.logging.models.SysLogDeviceToken;
|
||||||
|
import com.mgm.mcrm.apigateway.notification.services.ApnNotificationService;
|
||||||
import com.mgm.mcrm.apigateway.player.services.PlayerService;
|
import com.mgm.mcrm.apigateway.player.services.PlayerService;
|
||||||
import com.mgm.mcrm.apigateway.reservation.models.Bookings;
|
import com.mgm.mcrm.apigateway.reservation.models.Bookings;
|
||||||
import com.mgm.mcrm.apigateway.reservation.repositories.BookingDao;
|
import com.mgm.mcrm.apigateway.reservation.repositories.BookingDao;
|
||||||
import jakarta.annotation.Resource;
|
import jakarta.annotation.Resource;
|
||||||
|
import lombok.extern.java.Log;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
import org.apache.commons.lang3.Strings;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import org.springframework.util.CollectionUtils;
|
import org.springframework.util.CollectionUtils;
|
||||||
|
|
||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Date;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
@@ -65,11 +72,20 @@ public class BookingService {
|
|||||||
private MgmUserService mgmUserService;
|
private MgmUserService mgmUserService;
|
||||||
@Resource
|
@Resource
|
||||||
private BlockCodeDao blockCodeDao;
|
private BlockCodeDao blockCodeDao;
|
||||||
|
@Resource
|
||||||
|
private SysLogDeviceTokenRepository sysLogDeviceTokenRepository;
|
||||||
|
@Resource
|
||||||
|
private NotificationUtil notificationUtil;
|
||||||
|
@Resource
|
||||||
|
private ApnNotificationService apnNotificationService;
|
||||||
|
|
||||||
public void processDaylightUpdateBooking(Bookings daylightBooking) throws Exception {
|
public void processDaylightUpdateBooking(Bookings daylightBooking) throws Exception {
|
||||||
if(daylightBooking!=null){
|
if(daylightBooking!=null){
|
||||||
String dlReservationId=daylightBooking.getDlReservationId();
|
String dlReservationId=daylightBooking.getDlReservationId();
|
||||||
String confirmNo = daylightBooking.getConfirmationNo();
|
String confirmNo = daylightBooking.getConfirmationNo();
|
||||||
|
String dbBookingStatus = null;
|
||||||
|
LocalDateTime checkInDate = null;
|
||||||
|
LocalDateTime checkOutDate = null;
|
||||||
if(StringUtils.isNotBlank(confirmNo)
|
if(StringUtils.isNotBlank(confirmNo)
|
||||||
&& StringUtils.isNotBlank(dlReservationId)
|
&& StringUtils.isNotBlank(dlReservationId)
|
||||||
){
|
){
|
||||||
@@ -92,6 +108,9 @@ public class BookingService {
|
|||||||
for(Bookings booking:dbBookings){
|
for(Bookings booking:dbBookings){
|
||||||
if("N".equalsIgnoreCase(booking.getApproveStatus())) {
|
if("N".equalsIgnoreCase(booking.getApproveStatus())) {
|
||||||
dbBooking = booking;
|
dbBooking = booking;
|
||||||
|
dbBookingStatus = dbBooking.getLastOperaStatus();
|
||||||
|
checkInDate = dbBooking.getCheckinDate();
|
||||||
|
checkOutDate = dbBooking.getCheckoutDate();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -102,6 +121,88 @@ public class BookingService {
|
|||||||
dbBooking = this.createBookingFromDaylight(daylightBooking);
|
dbBooking = this.createBookingFromDaylight(daylightBooking);
|
||||||
}
|
}
|
||||||
bookingDao.save(dbBooking);
|
bookingDao.save(dbBooking);
|
||||||
|
|
||||||
|
CfgProperties property = propertyDao.findByDlPropertyId(dbBooking.getDlPropertyId());
|
||||||
|
|
||||||
|
//Send Notification to Booker when booking lastOpera status Changed
|
||||||
|
|
||||||
|
LogUtil.info(BookingService.class,"Daylight webhook updated, prepare send notification");
|
||||||
|
LogUtil.info(BookingService.class,"DaylightBooking status=" + daylightBooking.getLastOperaStatus());
|
||||||
|
LogUtil.info(BookingService.class,"Db booking status=" + dbBookingStatus);
|
||||||
|
if (Strings.CS.equals(daylightBooking.getLastOperaStatus(),"RESERVED") && !Strings.CS.equals(dbBookingStatus,daylightBooking.getLastOperaStatus())){
|
||||||
|
LogUtil.info(BookingService.class,"Booking last opera status changed, DB Record status:"+dbBookingStatus+", DlBooking status:"+daylightBooking.getLastOperaStatus());
|
||||||
|
//设置Notification 内容
|
||||||
|
String notificationTitle = "#EN# Room status updated#EN#" +
|
||||||
|
"#CN#房間狀態已更改#CN#";
|
||||||
|
String notificationContent = "#EN#Player {playerId}, {propertyName}, {roomCode},room status changed to reserved.#EN#" +
|
||||||
|
"#CN#Player {playerId}, {propertyName}, {roomCode}, 房間狀態已預訂。#CN#";
|
||||||
|
String[] placeholders = {
|
||||||
|
"{playerId}", "{propertyName}", "{roomCode}"
|
||||||
|
};
|
||||||
|
LogUtil.info(BookingService.class,"Set notification info");
|
||||||
|
String[] values = {
|
||||||
|
StringUtils.defaultString(dbBooking.getPlayerId()),
|
||||||
|
StringUtils.defaultString(property == null ? null : property.getName()),
|
||||||
|
StringUtils.defaultString(dbBooking.getRoomTypeCode())
|
||||||
|
};
|
||||||
|
LogUtil.info(BookingService.class,"Replace each");
|
||||||
|
notificationContent = StringUtils.replaceEach(notificationContent, placeholders, values);
|
||||||
|
String transactionId = "DLBKSC"+dbBooking.getId();
|
||||||
|
LogUtil.info(BookingService.class,"Get device token from DB Start");
|
||||||
|
SysLogDeviceToken deviceToken = sysLogDeviceTokenRepository.findByUserId(StringUtils.trim(dbBooking.getCreatedBy()));
|
||||||
|
LogUtil.info(BookingService.class,"Get device token from DB:" + (deviceToken == null ? "null" : deviceToken.getDeviceToken()));
|
||||||
|
String deviceTokenValue =null;
|
||||||
|
String finalTitle = null;
|
||||||
|
String finalContent = null;
|
||||||
|
if(deviceToken!=null){
|
||||||
|
deviceTokenValue = deviceToken.getDeviceToken();
|
||||||
|
finalTitle = notificationUtil.distinguishLanguage(notificationTitle,deviceToken.getUseLanguageType());
|
||||||
|
notificationContent = notificationUtil.distinguishLanguage(notificationContent,deviceToken.getUseLanguageType());
|
||||||
|
|
||||||
|
}
|
||||||
|
// NOTIFICATION
|
||||||
|
apnNotificationService.pushApnMessage(transactionId,deviceTokenValue,finalTitle,notificationContent,true);
|
||||||
|
}
|
||||||
|
|
||||||
|
//Send notification to Booker when Booking C/I | C/O date changed
|
||||||
|
if ((checkInDate != null && !checkInDate.equals(daylightBooking.getCheckinDate()))||
|
||||||
|
(checkOutDate != null && !checkOutDate.equals(daylightBooking.getCheckoutDate()))) {
|
||||||
|
LogUtil.info(BookingService.class,"Booking date changed, DB Record C/I:"+checkInDate+", DB Record C/O:"+checkOutDate+
|
||||||
|
", Dl Record C/I"+daylightBooking.getCheckinDate()+", Dl Record C/O"+daylightBooking.getCheckoutDate());
|
||||||
|
|
||||||
|
|
||||||
|
//设置Notification 内容
|
||||||
|
String notificationTitle = "#EN# Room status updated#EN#" +
|
||||||
|
"#CN#房間狀態已更改#CN#";
|
||||||
|
String notificationContent = "#EN#Player {playerId}, {propertyName}, {roomCode},Stay date changed.#EN#" +
|
||||||
|
"#CN#Player {playerId}, {propertyName}, {roomCode}, 住宿日期已變更。#CN#";
|
||||||
|
String[] placeholders = {
|
||||||
|
"{playerId}", "{propertyName}", "{roomCode}"
|
||||||
|
};
|
||||||
|
String[] values = {
|
||||||
|
StringUtils.defaultString(dbBooking.getPlayerId()),
|
||||||
|
StringUtils.defaultString(property == null ? null : property.getName()),
|
||||||
|
StringUtils.defaultString(dbBooking.getRoomTypeCode())
|
||||||
|
};
|
||||||
|
|
||||||
|
notificationContent = StringUtils.replaceEach(notificationContent, placeholders, values);
|
||||||
|
String transactionId = "DLBKDC" + dbBooking.getId();
|
||||||
|
|
||||||
|
SysLogDeviceToken deviceToken = sysLogDeviceTokenRepository.findByUserId(StringUtils.trim(dbBooking.getCreatedBy()));
|
||||||
|
LogUtil.info(BookingService.class,"Get device token from DB:" + (deviceToken == null ? "null" : deviceToken.getDeviceToken()));
|
||||||
|
String deviceTokenValue = null;
|
||||||
|
String finalTitle = null;
|
||||||
|
String finalContent = null;
|
||||||
|
if (deviceToken != null) {
|
||||||
|
LogUtil.info(BookingService.class,"Get device Token success");
|
||||||
|
deviceTokenValue = deviceToken.getDeviceToken();
|
||||||
|
finalTitle = notificationUtil.distinguishLanguage(notificationTitle, deviceToken.getUseLanguageType());
|
||||||
|
notificationContent = notificationUtil.distinguishLanguage(notificationContent, deviceToken.getUseLanguageType());
|
||||||
|
}
|
||||||
|
// NOTIFICATION
|
||||||
|
apnNotificationService.pushApnMessage(transactionId, deviceTokenValue, finalTitle, notificationContent, true);
|
||||||
|
}
|
||||||
|
LogUtil.info(BookingService.class,"End send notification function");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -128,6 +229,14 @@ public class BookingService {
|
|||||||
updateBooking.setDlAccountId(daylightBooking.getDlAccountId());
|
updateBooking.setDlAccountId(daylightBooking.getDlAccountId());
|
||||||
updateBooking.setDlBlockId(daylightBooking.getDlBlockId());
|
updateBooking.setDlBlockId(daylightBooking.getDlBlockId());
|
||||||
updateBooking.setDlExternalNo(daylightBooking.getDlExternalNo());
|
updateBooking.setDlExternalNo(daylightBooking.getDlExternalNo());
|
||||||
|
|
||||||
|
if (updateBooking.getWaitlistId() != null) {
|
||||||
|
bookingDao.findById(updateBooking.getWaitlistId()).ifPresent(booking -> {
|
||||||
|
booking.setConfirmationNo(daylightBooking.getConfirmationNo());
|
||||||
|
bookingDao.save(booking);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
// updateBooking.setGroupId(daylightBooking.getGroupId());
|
// updateBooking.setGroupId(daylightBooking.getGroupId());
|
||||||
updateBooking.setDlReservationId(daylightBooking.getDlReservationId());
|
updateBooking.setDlReservationId(daylightBooking.getDlReservationId());
|
||||||
// 通过 dlRoomTypeId 查找 room type(与 createBookingFromDaylight 流程保持一致)
|
// 通过 dlRoomTypeId 查找 room type(与 createBookingFromDaylight 流程保持一致)
|
||||||
@@ -190,7 +299,7 @@ public class BookingService {
|
|||||||
String booker = StringUtils.trim(updateBooking.getBooker());
|
String booker = StringUtils.trim(updateBooking.getBooker());
|
||||||
if(booker==null||StringUtils.isEmpty(booker)) getUser=true;
|
if(booker==null||StringUtils.isEmpty(booker)) getUser=true;
|
||||||
if(daylightBooking.getCreatedBy()!=null && !daylightBooking.getCreatedBy().equals(updateBooking.getCreatedBy())) {
|
if(daylightBooking.getCreatedBy()!=null && !daylightBooking.getCreatedBy().equals(updateBooking.getCreatedBy())) {
|
||||||
updateBooking.setCreatedBy(daylightBooking.getCreatedBy());
|
// updateBooking.setCreatedBy(daylightBooking.getCreatedBy());
|
||||||
getUser=true;
|
getUser=true;
|
||||||
}
|
}
|
||||||
if(getUser) {
|
if(getUser) {
|
||||||
|
|||||||
@@ -0,0 +1,6 @@
|
|||||||
|
-----BEGIN PRIVATE KEY-----
|
||||||
|
MIGTAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBHkwdwIBAQQgfQ1bQlwCYsPyrRua
|
||||||
|
2OB2VRxxlA2/3PUFWuS/+/3P1RygCgYIKoZIzj0DAQehRANCAASn2hmu3BJ02OmZ
|
||||||
|
hNS/y6SwiIJi4tWQB1lxX0EksfsRgU1e3pp9gcMeIvY8gQA44QQJSvV7JWIu2fMj
|
||||||
|
1b9xpZU/
|
||||||
|
-----END PRIVATE KEY-----
|
||||||
@@ -138,3 +138,19 @@ springdoc:
|
|||||||
path: /v3/api-docs
|
path: /v3/api-docs
|
||||||
default-consumes-media-type: application/json
|
default-consumes-media-type: application/json
|
||||||
default-produces-media-type: application/json
|
default-produces-media-type: application/json
|
||||||
|
|
||||||
|
apns:
|
||||||
|
team-id: YXJ2H36G5R
|
||||||
|
key-id: 79FNU7K4J9
|
||||||
|
bundle-id: com.mgm.crmhostroombookingdaylightdevelopment
|
||||||
|
key-file: /AuthKey_79FNU7K4J9_Development.p8
|
||||||
|
proxy:
|
||||||
|
enabled: false
|
||||||
|
host:
|
||||||
|
port: 0
|
||||||
|
username:
|
||||||
|
password:
|
||||||
|
# Dev host
|
||||||
|
host: api.sandbox.push.apple.com
|
||||||
|
# Production Host
|
||||||
|
# host: api.push.apple.com
|
||||||
Reference in New Issue
Block a user