diff --git a/Program.cs b/Program.cs index a35dfbe..8fb8c6a 100644 --- a/Program.cs +++ b/Program.cs @@ -129,6 +129,9 @@ builder.Services.AddScoped(); builder.Services.AddScoped(); builder.Services.AddScoped(); + +builder.Services.AddScoped(); +builder.Services.AddScoped(); // builder.Services.AddScoped(); // // builder.Services.AddScoped(); diff --git a/Program/Controllers/V1/PushController.cs b/Program/Controllers/V1/PushController.cs index 0ee4783..60a5435 100644 --- a/Program/Controllers/V1/PushController.cs +++ b/Program/Controllers/V1/PushController.cs @@ -4,6 +4,7 @@ using Back.Program.Common.Data; using Back.Program.Common.Model; using Back.Program.Models.Entities; using Back.Program.Services.V1; +using Back.Program.Services.V1.Interfaces; using Microsoft.AspNetCore.Mvc; using Microsoft.EntityFrameworkCore; @@ -15,19 +16,19 @@ namespace Back.Program.Controllers.V1 public class PushController : ControllerBase { private readonly ILogger _logger; - private readonly IPushQueue _pushQueue; - private readonly AppDbContext _dbContext; private readonly IRepositoryService _repositoryService; - private readonly JwtTokenService _jwtTokenService; - public PushController(ILogger logger, IPushQueue pushQueue, AppDbContext dbContext, IRepositoryService repositoryService, JwtTokenService jwtTokenService) + private readonly IPushQueue _pushQueue; + private readonly IPushService _pushService; + + public PushController(ILogger logger, IRepositoryService repositoryService, + IPushQueue pushQueue, IPushService pushService) { _logger = logger; - _pushQueue = pushQueue; - _dbContext = dbContext; _repositoryService = repositoryService; - _jwtTokenService = jwtTokenService; + _pushQueue = pushQueue; + _pushService = pushService; } - + // 추가 사항 // 카테고리 별 조회 하는 부분도 추가를 할 지 고민을 해야 할 것 같음 @@ -36,35 +37,10 @@ namespace Back.Program.Controllers.V1 [ProducesResponseType(StatusCodes.Status200OK, Type = typeof(APIResponseStatus))] public async Task GetPush(string bid, string? pid, string? category) { - string summary = String.Empty; - - try - { - summary = _repositoryService.ReadSummary(typeof(PushController), "GetPush"); - - if (!(await _dbContext.Academy.AnyAsync(a=>a.bid == bid))) - return Ok(APIResponse.Send("100", $"[{summary}], 존재하지 않는 BID", Empty)); - - List pushData = new List(); - var pushQuery = _dbContext.DBPayload.Where(p => p.bid == bid); - if (pid != null) - pushQuery = pushQuery.Where(p=>p.pid == pid); - if (category != null) - pushQuery = pushQuery.Where(p=>p.category == category); - pushData = await pushQuery.ToListAsync(); - - if (pushData.Count > 0) - { - return Ok(APIResponse.Send("000", $"[{summary}, 정상", pushData)); - } - - return Ok(APIResponse.Send("001", $"[{summary}], PUSH 데이터 없음", Empty)); - } - catch (Exception ex) - { - _logger.LogError($"[{summary}] : {ex.Message}"); - return StatusCode(500, APIResponse.UnknownError()); - } + if (string.IsNullOrEmpty(bid)) return BadRequest(APIResponse.InvalidInputError()); + string summary = _repositoryService.ReadSummary(typeof(PushController), "GetPush"); + var result = await _pushService.GetPush(summary, bid, pid, category); + return Ok(result); } @@ -73,114 +49,11 @@ namespace Back.Program.Controllers.V1 [ProducesResponseType(StatusCodes.Status200OK, Type = typeof(APIResponseStatus))] public async Task SendPush([FromBody] PushRequest pushRequest) { - string summary = String.Empty; - try { - summary = _repositoryService.ReadSummary(typeof(PushController), "SendPush"); - - if (!ModelState.IsValid) return BadRequest(APIResponse.InvalidInputError()); - - var payload = await _dbContext.DBPayload - .Where(p => p.pid == pushRequest.pid && p.bid == pushRequest.bid) - .Select(p => new Payload - { - aps = new Aps - { - alert = new Alert { title = p.title, body = p.body, subtitle = p.subtitle ?? "" }, - category = p.category - }, - pid = pushRequest.pid, - bid = pushRequest.bid, - content = pushRequest.content ?? (p.content ?? ""), - }) - .FirstOrDefaultAsync(); - - await Task.Run(async () => - { - if (payload == null) - throw new PushInvalidException("payload is NULL"); - - foreach (var uid in pushRequest.uids) - { - // 학원 내부에 해당 uid의 일원이 존재하는지 확인 - if ( - await _dbContext.UserAcademy - .Where(ua => ua.uid == uid && ua.bid == pushRequest.bid) - .AnyAsync() - ) - { - // 유저한테 온 모든 푸시에 대해서 안 읽은 것에 대한 뱃지 갯수 확인 - var badge = await _dbContext.PushCabinet - .Where(c => c.uid == uid - && c.check_yn == false) - .CountAsync(); - payload.aps.badge = badge + 1; - - // 푸시를 보내야 하니 푸시 토큰 확인 - var pushToken = await _dbContext.User - .Where(u => u.uid == uid) - .Select(u => u.push_token) - .FirstOrDefaultAsync() ?? ""; - - var pushCabinet = new PushCabinet - { - uid = uid, - bid = pushRequest.bid, - pid = pushRequest.pid, - send_date = DateTime.Now, - content = payload.content != "" ? payload.content : null, - }; - - var pushData = new PushData - { - pushToken = pushToken, - payload = payload - }; - - if (await _repositoryService.SaveData(pushCabinet)) - { - var logPush = new LogPush - { - bid = pushRequest.bid, - pid = pushRequest.pid, - create_date = DateTime.Now, - create_uid = "System", - log = $"[{summary}] : 푸시 캐비닛 저장 성공" - }; - if (await _repositoryService.SaveData(logPush)) - _logger.LogInformation($"[{summary}] : 로그 추가"); - } - - _pushQueue.Enqueue(pushData); - } - else - { - // 존재하지 않는 경우에는 지나가서 다른 uid 로 확인 하겠지 - var logPush = new LogPush - { - bid = pushRequest.bid, - pid = pushRequest.pid, - create_date = DateTime.Now, - create_uid = "System", - log = $"[{summary}] : 푸시 전송 실패" - }; - if (await _repositoryService.SaveData(logPush)) - _logger.LogInformation($"[{summary}] : 로그 추가"); - } - - } - }); - return Ok(APIResponse.Send("000", $"[{summary}], 정상", Empty)); - } - catch (PushInvalidException ex) - { - _logger.LogError($"[{summary}] : {ex.Message}"); - return Ok(APIResponse.Send("001", $"[{summary}], 푸시 송신 중 문제 발생",Empty)); - } - catch (Exception ex) - { - _logger.LogError($"[{summary}] : {ex.Message}"); - return StatusCode(500, APIResponse.UnknownError(ex.Message)); - } + if (!ModelState.IsValid) return BadRequest(APIResponse.InvalidInputError()); + string summary = _repositoryService.ReadSummary(typeof(PushController), "SendPush"); + + var result = await _pushService.SendPush(summary, pushRequest); + return Ok(result); } [HttpPost("set")] @@ -190,58 +63,10 @@ namespace Back.Program.Controllers.V1 { if (string.IsNullOrEmpty(token)) return BadRequest(APIResponse.InvalidInputError()); if (!ModelState.IsValid) return BadRequest(APIResponse.InvalidInputError()); - string summary = String.Empty; - string uid = String.Empty; - - try - { - if (token == "System") uid = "System"; - else - { - var validateToken = await _jwtTokenService.ValidateToken(token); - if (validateToken == null) return Ok(APIResponse.AccessExpireError()); - uid = validateToken.FindFirst(ClaimTypes.NameIdentifier)?.Value ?? string.Empty; - } + string summary = _repositoryService.ReadSummary(typeof(PushController), "SetPush"); - summary = _repositoryService.ReadSummary(typeof(PushController), "SetPush"); - var dbPayload = await _dbContext.DBPayload - .FirstOrDefaultAsync(p => p.pid == request.pid && p.bid == request.bid); - - - if (dbPayload != null) - { - var logPush = new LogPush - { - bid = dbPayload.bid, - pid = dbPayload.pid, - create_uid = uid, - create_date = DateTime.Now, - }; - - if (dbPayload.title != request.title && request.title != "") dbPayload.title = request.title; - if (dbPayload.body != request.body && request.body != "") dbPayload.body = request.body; - if (dbPayload.subtitle != request.subtitle) dbPayload.subtitle = request.subtitle; - if (dbPayload.alert_yn != request.alert_yn) dbPayload.alert_yn = request.alert_yn; - if (dbPayload.category != request.category && request.category != "") dbPayload.category = request.category; - if (dbPayload.content != request.content) dbPayload.content = request.content; - if (await _repositoryService.SaveData(dbPayload)) - { - logPush.log = $"[{summary} : 정상 변경"; - return Ok(APIResponse.Send("000", $"[{summary}], 정상", Empty)); - } - - // 로그를 이제 만들어서 추가를 해야 합니다. - if (await _repositoryService.SaveData(logPush)) - _logger.LogInformation($"[{summary}] : 로그 추가"); - } - - return Ok(APIResponse.Send("100", $"[{summary}], PID, BID 또는 Cabinet 오류", Empty)); - } - catch (Exception ex) - { - _logger.LogError($"[{summary}] : {ex.Message}"); - return StatusCode(500, APIResponse.UnknownError(ex.Message)); - } + var result = await _pushService.SetPush(summary, token, request); + return Ok(result); } [HttpPost("create")] @@ -251,76 +76,9 @@ namespace Back.Program.Controllers.V1 { if (string.IsNullOrEmpty(token)) return BadRequest(APIResponse.InvalidInputError()); if (!ModelState.IsValid) return BadRequest(APIResponse.InvalidInputError()); - string summary = String.Empty; - string uid = ""; - - Func randomLetter = (letters, count) => new string(Enumerable.Range(0, count).Select(_ => letters[new Random().Next(letters.Length)]).ToArray()); - var letters = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; - var digits = "0123456789"; - var frontLetters = $"{randomLetter(letters, 1)}{randomLetter(digits, 1)}{randomLetter(letters, 1)}"; - var afterLetters = $"{randomLetter(letters, 1)}{randomLetter(digits, 1)}{randomLetter(letters, 1)}"; - - try - { - if (token == "System") uid = "System"; - else { - var validateToken = await _jwtTokenService.ValidateToken(token); - if (validateToken == null) return Ok(APIResponse.AccessExpireError()); - uid = validateToken.FindFirst(ClaimTypes.NameIdentifier)?.Value ?? string.Empty; - } - - summary = _repositoryService.ReadSummary(typeof(PushController), "CreatePush"); - - if (await _dbContext.Academy.AnyAsync(a => a.bid == request.bid)) - { - DBPayload payload = new DBPayload - { - bid = request.bid, - pid = $"AP{DateTime.Now:yyyyMMdd}{frontLetters}{DateTime.Now:HHmmss}{afterLetters}", - title = request.title, - subtitle = request.subtitle, - body = request.body, - alert_yn = request.alert_yn, - category = request.category, - content = request.content, - }; - - if (await _repositoryService.SaveData(payload)) - { - var logPush = new LogPush - { - bid = payload.bid, - pid = payload.pid, - create_uid = uid, - create_date = DateTime.Now, - log = $"[{summary}] : 정상 생성" - }; - - // 로그를 이제 만들어서 추가를 해야 합니다. - if (await _repositoryService.SaveData(logPush)) - _logger.LogInformation($"[{summary}] : 로그 추가"); - - return Ok(APIResponse.Send("000", $"[{summary}], 정상", Empty)); - } - - } - return Ok(APIResponse.Send("100", $"[{summary}], 학원 정보(BID) 확인 불가", Empty)); - } - catch (TokenException tokenEx) - { - _logger.LogInformation($"[{summary}] : {tokenEx}"); - return Ok(APIResponse.Send("001", $"[{summary}], 토큰에 문제가 있음",Empty)); - } - catch (RefreshRevokeException refreshEx) - { - _logger.LogInformation($"[{summary}] : {refreshEx}"); - return Ok(APIResponse.Send("001", $"[{summary}], 폐기된 리프레시 토큰",Empty)); - } - catch (Exception ex) - { - _logger.LogError($"[{summary}] : {ex.Message}"); - return StatusCode(500, APIResponse.UnknownError()); - } + string summary = _repositoryService.ReadSummary(typeof(PushController), "CreatePush"); + var result = await _pushService.CreatePush(summary, token, request); + return Ok(result); } @@ -332,44 +90,9 @@ namespace Back.Program.Controllers.V1 { if (string.IsNullOrEmpty(token)) return BadRequest(APIResponse.InvalidInputError()); if (!ModelState.IsValid) return BadRequest(APIResponse.InvalidInputError()); - string uid = ""; - string summary = String.Empty; - - try - { - if (token == "System") uid = "System"; - else { - var validateToken = await _jwtTokenService.ValidateToken(token); - if (validateToken == null) return Ok(APIResponse.AccessExpireError()); - uid = validateToken.FindFirst(ClaimTypes.NameIdentifier)?.Value ?? string.Empty; - } - - summary = _repositoryService.ReadSummary(typeof(PushController), "DeletePush"); - - var payload = await _dbContext.DBPayload.FirstOrDefaultAsync(p => p.bid == bid && p.pid == pid); - if (payload == null) return Ok(APIResponse.Send("001", $"[{summary}], 삭제 할 PUSH 없음", Empty)); - if (!await _repositoryService.DeleteData(payload)) return Ok(APIResponse.Send("002", $"[{summary}], PUSH 삭제 실패", Empty)); - - // 로그를 이제 만들어서 추가를 해야 합니다. - var logPush = new LogPush - { - bid = bid, - pid = pid, - create_uid = uid, - create_date = DateTime.Now, - log = $"[{summary}] : {pid} 삭제 - {uid}" - }; - - // 로그를 이제 만들어서 추가를 해야 합니다. - if (await _repositoryService.SaveData(logPush)) _logger.LogInformation($"[{summary}] : 로그 추가"); - - return Ok(APIResponse.Send("000", $"[{summary}], 정상", Empty)); - } - catch (Exception ex) - { - _logger.LogError($"[{summary}] : {ex.Message}"); - return BadRequest(APIResponse.UnknownError(ex.Message)); - } + string summary = _repositoryService.ReadSummary(typeof(PushController), "DeletePush"); + var result = await _pushService.DeletePush(summary,token,bid,pid); + return Ok(result); } @@ -380,41 +103,9 @@ namespace Back.Program.Controllers.V1 { if (string.IsNullOrEmpty(token)) return BadRequest(APIResponse.InvalidInputError()); if (!ModelState.IsValid) return BadRequest(APIResponse.InvalidInputError()); - string uid = ""; - string summary = String.Empty; - try - { - if (token == "System") uid = "System"; - else { - var validateToken = await _jwtTokenService.ValidateToken(token); - if (validateToken == null) return Ok(APIResponse.AccessExpireError()); - uid = validateToken.FindFirst(ClaimTypes.NameIdentifier)?.Value ?? string.Empty; - } - - summary = _repositoryService.ReadSummary(typeof(PushController), "DeleteListPush"); - var cabinetPush = await _dbContext.PushCabinet.FirstOrDefaultAsync(c => c.id == id); - if (cabinetPush == null) return Ok(APIResponse.Send("001", $"[{summary}], 삭제 할 PUSH 없음", Empty)); - if (!await _repositoryService.DeleteData(cabinetPush)) - return Ok(APIResponse.Send("002", $"[{summary}], PUSH 삭제 실패", Empty)); - - // // 로그를 이제 만들어서 추가를 해야 합니다. - var logPush = new LogPush - { - bid = cabinetPush.bid, - pid = cabinetPush.pid, - create_uid = uid, - create_date = DateTime.Now, - log = $"[{summary}] : {cabinetPush.pid} 삭제 - {uid}" - }; - if (await _repositoryService.SaveData(logPush)) _logger.LogInformation($"[{summary}] : 로그 추가"); - - return Ok(APIResponse.Send("000", $"[{summary}], 정상", Empty)); - } - catch (Exception ex) - { - _logger.LogError($"[{summary}] : {ex.Message}"); - return BadRequest(APIResponse.UnknownError(ex.Message)); - } + string summary = _repositoryService.ReadSummary(typeof(PushController), "DeleteListPush"); + var result = await _pushService.DeleteListPush(summary, token, id); + return Ok(result); } @@ -426,9 +117,11 @@ namespace Back.Program.Controllers.V1 { if (string.IsNullOrEmpty(token)) return BadRequest(APIResponse.InvalidInputError()); if (!ModelState.IsValid) return BadRequest(APIResponse.InvalidInputError()); - string uid = ""; - string summary = String.Empty; + string summary = _repositoryService.ReadSummary(typeof(PushController), "SearchToUserPush"); + var result = await _pushService.SearchToUserPush(summary, token, size, request); + return Ok(result); + /* try { if (token == "System") uid = "System"; @@ -439,6 +132,8 @@ namespace Back.Program.Controllers.V1 } summary = _repositoryService.ReadSummary(typeof(PushController), "SearchToUserPush"); + + // 여기서부터 리팩토링 진행 if (request == null) { var pagedData = await _dbContext.PushCabinet.Where(c => c.uid == uid) @@ -463,6 +158,7 @@ namespace Back.Program.Controllers.V1 _logger.LogError($"[{summary}] : {ex.Message}"); return BadRequest(APIResponse.UnknownError(ex.Message)); } + */ } diff --git a/Program/Controllers/V1/UserController.cs b/Program/Controllers/V1/UserController.cs index c03420e..700ab93 100644 --- a/Program/Controllers/V1/UserController.cs +++ b/Program/Controllers/V1/UserController.cs @@ -18,30 +18,17 @@ namespace Back.Program.Controllers.V1 [ApiExplorerSettings(GroupName = "사용자")] public class UserController : ControllerBase { - private readonly AppDbContext _dbContext; private readonly ILogger _logger; - private readonly JwtTokenService _jwtTokenService; private readonly IRepositoryService _repositoryService; private readonly IUserService _userService; - public UserController(AppDbContext dbContext, ILogger logger, JwtTokenService jwtTokenService, + public UserController(ILogger logger, IRepositoryService repositoryService, IUserService userService) { - _dbContext = dbContext; _logger = logger; - _jwtTokenService = jwtTokenService; _repositoryService = repositoryService; _userService = userService; } - - - /* - catch (Exception ex) - { - _logger.LogInformation($"[{summary}] : {ex.Message}"); - return BadRequest(APIResponse.UnknownError(ex.Message)); - } - */ [HttpGet] [CustomOperation("회원 정보 조회", "회원 정보 조회 (자기자신)", "사용자")] diff --git a/Program/Repositories/V1/Interfaces/IPushRepository.cs b/Program/Repositories/V1/Interfaces/IPushRepository.cs index 1d3037e..f0ed436 100644 --- a/Program/Repositories/V1/Interfaces/IPushRepository.cs +++ b/Program/Repositories/V1/Interfaces/IPushRepository.cs @@ -4,11 +4,13 @@ namespace Back.Program.Repositories.V1.Interfaces; public interface IPushRepository { - Task FindAcademy(string bid); - Task FindPushPayload(string bid, string? pid, string? category); - Task FindUserAcademy(string uid, string bid); - Task FindPushCabinet(string uid); - Task FindUser(string uid); + Task FindAcademy(string bid); + Task> FindPushList(string bid, string? pid, string? category); + Task FindPushPayload(string bid, string pid); + Task FindUserAcademy(string uid, string bid); + Task CountBadge(string uid); + Task FindPushToken(string uid); + Task FindPushCabinet(int id); } \ No newline at end of file diff --git a/Program/Repositories/V1/PushRepository.cs b/Program/Repositories/V1/PushRepository.cs index 799cf61..ac1ab50 100644 --- a/Program/Repositories/V1/PushRepository.cs +++ b/Program/Repositories/V1/PushRepository.cs @@ -15,28 +15,47 @@ public class PushRepository: IPushRepository } - public async Task FindAcademy(string bid, string? pid, string? category) + public async Task FindAcademy(string bid) { - return await _context.Academy.FirstOrDefaultAsync(a => a.bid == bid); + return await _context.Academy.AnyAsync(a => a.bid == bid); } - public async Task FindPushPayload(string bid, string pid, string? category) + public async Task> FindPushList(string bid, string? pid, string? category) { - throw new NotImplementedException(); + var pushQuery = _context.DBPayload.Where(p => p.bid == bid); + if (pid != null) + pushQuery = pushQuery.Where(p => p.pid == pid); + if (category != null) + pushQuery = pushQuery.Where(p=>p.category == category); + return await pushQuery.ToListAsync(); + } - public async Task FindUserAcademy(string uid, string bid) + public async Task FindPushPayload(string bid, string pid) { - throw new NotImplementedException(); + return await _context.DBPayload.FirstOrDefaultAsync(p => p.bid == bid && p.pid == pid); } - public async Task FindPushCabinet(string uid) + public async Task FindUserAcademy(string uid, string bid) { - throw new NotImplementedException(); + return await _context.UserAcademy.AnyAsync(ua => ua.uid == uid && ua.bid == bid); } - public async Task FindUser(string uid) + public async Task CountBadge(string uid) { - throw new NotImplementedException(); + return await _context.PushCabinet.CountAsync(c => c.uid == uid && c.check_yn == false); + } + + public async Task FindPushToken(string uid) + { + return await _context.User + .Where(u => u.uid == uid) + .Select(u => u.push_token) + .FirstOrDefaultAsync(); + } + + public async Task FindPushCabinet(int id) + { + return await _context.PushCabinet.FirstOrDefaultAsync(c => c.id == id); } } \ No newline at end of file diff --git a/Program/Services/V1/InMemoryPushQueue.cs b/Program/Services/V1/InMemoryPushQueue.cs index fc04058..6621244 100644 --- a/Program/Services/V1/InMemoryPushQueue.cs +++ b/Program/Services/V1/InMemoryPushQueue.cs @@ -31,16 +31,10 @@ namespace Back.Program.Services.V1 } } - public class PushBackgroundService : BackgroundService + public class PushBackgroundService(IPushQueue queue, IPushService pushService) : BackgroundService { - private readonly IPushQueue _queue; - private readonly IPushService _pushService; - - public PushBackgroundService(IPushQueue queue, IPushService pushService) - { - _queue = queue; - _pushService = pushService; - } + private readonly IPushQueue _queue = queue; + private readonly IPushService _pushService = pushService; protected override async Task ExecuteAsync(CancellationToken stoppingToken) { diff --git a/Program/Services/V1/Interfaces/IPushService.cs b/Program/Services/V1/Interfaces/IPushService.cs index 32546d5..5028504 100644 --- a/Program/Services/V1/Interfaces/IPushService.cs +++ b/Program/Services/V1/Interfaces/IPushService.cs @@ -1,8 +1,18 @@ +using Back.Program.Common.Model; using Back.Program.Models.Entities; namespace Back.Program.Services.V1.Interfaces; public interface IPushService { + Task SendPushNotificationAsync(string deviceToken, Payload payload); -} \ No newline at end of file + Task> GetPush(string summary, string bid, string? pid, string? category); + Task> SendPush(string summary, PushRequest pushRequest); + Task> SetPush(string summary, string token, DBPayload request); + Task> CreatePush(string summary, string token, CreatePush request); + Task> DeletePush(string summary, string token, string bid, string pid); + Task> DeleteListPush(string summary, string token, int id); + Task> SearchToUserPush(string summary, string token, int size, PushCabinet? request); + +} diff --git a/Program/Services/V1/PushService.cs b/Program/Services/V1/PushService.cs index bc578da..1ea5bd2 100644 --- a/Program/Services/V1/PushService.cs +++ b/Program/Services/V1/PushService.cs @@ -1,34 +1,53 @@ +using System.Security.Claims; using System.Text; using System.Text.Json; +using Back.Program.Common.Auth; using Back.Program.Common.Model; using Back.Program.Models.Entities; +using Back.Program.Repositories.V1; +using Back.Program.Repositories.V1.Interfaces; using Back.Program.Services.V1.Interfaces; +using Microsoft.AspNetCore.Http.HttpResults; using Microsoft.Extensions.Options; using Polly; using Version = System.Version; namespace Back.Program.Services.V1 { - public class PushService: IPushService + public class PushService : IPushService { + private readonly ILogger _logger; private readonly HttpClient _httpClient; private readonly PushFileSetting _setting; + private readonly JwtTokenService _jwtTokenService; + private readonly IRepositoryService _repositoryService; + private readonly IPushQueue _pushQueue; - public PushService(HttpClient httpClient, IOptions options) + private readonly ILogRepository _logRepository; + private readonly IPushRepository _pushRepository; + + public PushService(ILogger logger, HttpClient httpClient, IOptions options, + IPushRepository pushRepository, IRepositoryService repositoryService, IPushQueue pushQueue, + ILogRepository logRepository, JwtTokenService jwtTokenService) { + _logger = logger; _httpClient = httpClient; _setting = options.Value; + _pushRepository = pushRepository; + _repositoryService = repositoryService; + _pushQueue = pushQueue; + _logRepository = logRepository; + _jwtTokenService = jwtTokenService; } public async Task SendPushNotificationAsync(string deviceToken, Payload payload) { - // 존재 안하면 예외 던져 버리는거 if (!File.Exists(_setting.p12Path) || !File.Exists(_setting.p12PWPath)) throw new FileNotFoundException("[푸시] : p12 관련 파일 확인 필요"); - + var jsonPayload = JsonSerializer.Serialize(payload); - + var request = new HttpRequestMessage(HttpMethod.Post, $"/3/device/{deviceToken}") { Content = new StringContent(jsonPayload, Encoding.UTF8, "application/json"), @@ -38,9 +57,9 @@ namespace Back.Program.Services.V1 // 필수 헤더 추가 request.Headers.Add("apns-topic", _setting.apnsTopic); request.Headers.Add("apns-push-type", "alert"); - + var policy = Policy.Handle() - .WaitAndRetryAsync(3, retryAttempt => + .WaitAndRetryAsync(3, retryAttempt => TimeSpan.FromSeconds(Math.Pow(2, retryAttempt))); await policy.ExecuteAsync(async () => @@ -52,8 +71,248 @@ namespace Back.Program.Services.V1 throw new ServiceConnectionFailedException($"[푸시] : APNS 통신 실패 - {errorContent}"); } }); + } + + public async Task> GetPush(string summary, string bid, string? pid, string? category) + { + if (!(await _pushRepository.FindAcademy(bid))) + return APIResponse.Send("100", $"[{summary}], 존재하지 않는 BID", string.Empty); + + var pushData = await _pushRepository.FindPushList(bid, pid, category); + + if (pushData.Count > 0) + return APIResponse.Send("000", $"[{summary}, 정상", pushData); + return APIResponse.Send("001", $"[{summary}], PUSH 데이터 없음", string.Empty); + } + + public async Task> SendPush(string summary, PushRequest pushRequest) + { + var payload = await _pushRepository.FindPushPayload(pushRequest.bid, pushRequest.pid); + if (payload == null) return APIResponse.InvalidInputError($"[{summary}], 저장된 payload 없음"); + + var pushTasks = pushRequest.uids.Select(async uid => + { + if (!await _pushRepository.FindUserAcademy(uid, pushRequest.bid)) return; + var badge = await _pushRepository.CountBadge(uid); + var pushToken = await _pushRepository.FindPushToken(uid); + if (pushToken == null) return; + + var newPayload = new Payload + { + aps = new Aps + { + alert = new Alert + { title = payload.title, body = payload.body, subtitle = payload.subtitle ?? "" }, + category = payload.category, + badge = badge + 1 + }, + pid = pushRequest.pid, + bid = pushRequest.bid, + content = pushRequest.content ?? (payload.content ?? "") + }; + + var pushCabinet = new PushCabinet + { + uid = uid, + bid = pushRequest.bid, + pid = pushRequest.pid, + send_date = DateTime.Now, + content = newPayload.content != "" ? newPayload.content : null + }; + + var pushData = new PushData + { + pushToken = pushToken, + payload = newPayload + }; + + var log = new LogPush + { + bid = pushRequest.bid, + pid = pushRequest.pid, + create_date = DateTime.Now, + create_uid = "System", + log = "" + }; + + var saved = await _repositoryService.SaveData(pushCabinet); + log.log = saved ? $"[{summary}]: 푸시 캐비닛 저장 성공 및 푸시 전송 시도" : $"[{summary}]: 푸시 전송 실패"; + var logSaved = await _repositoryService.SaveData(log); + _logger.LogInformation($"[{summary}]: 캐비닛 저장 = {saved} : 로그 저장 = {logSaved}"); + + if(saved) _pushQueue.Enqueue(pushData); + }); + + await Task.WhenAll(pushTasks); + + return APIResponse.Send("000", $"[{summary}], 정상", string.Empty); + } + + + public async Task> SetPush(string summary, string token, DBPayload request) + { + string uid = String.Empty; + if (token == "System") uid = "System"; + else + { + var validToken = await _jwtTokenService.ValidateToken(token); + if (validToken == null) return APIResponse.AccessExpireError(); + uid = validToken.FindFirst(ClaimTypes.NameIdentifier)?.Value ?? string.Empty; + } + var payload = await _pushRepository.FindPushPayload(request.bid, request.pid); + if (payload == null) + return APIResponse.Send("100", $"[{summary}], PID, BID 또는 Cabinet 오류", string.Empty); + + var log = new LogPush + { + bid = request.bid, + pid = request.pid, + create_date = DateTime.Now, + create_uid = uid + }; + + if (payload.title != request.title && request.title != "") payload.title = request.title; + if (payload.body != request.body && request.body != "") payload.body = request.body; + if (payload.subtitle != request.subtitle) payload.subtitle = request.subtitle; + if (payload.alert_yn != request.alert_yn) payload.alert_yn = request.alert_yn; + if (payload.category != request.category) payload.category = request.category; + if (request.content != request.content) payload.content = request.content; + + var saved = (await _repositoryService.SaveData(payload)); + log.log = $"[{summary}] : 상태 = {saved}"; + var logSaved = await _repositoryService.SaveData(log); + _logger.LogInformation($"[{summary}]: 상태 = {saved} : 로그 저장 = {logSaved}"); + + if (!saved) return APIResponse.Send("001", $"[{summary}], 실패", string.Empty); + return APIResponse.Send("000", $"[{summary}], 정상", string.Empty); + } + + + public async Task> CreatePush(string summary, string token, CreatePush request) + { + Func randomLetter = (letters, count) => new string(Enumerable.Range(0, count).Select(_ => letters[new Random().Next(letters.Length)]).ToArray()); + var letters = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + var digits = "0123456789"; + var frontLetters = $"{randomLetter(letters, 1)}{randomLetter(digits, 1)}{randomLetter(letters, 1)}"; + var afterLetters = $"{randomLetter(letters, 1)}{randomLetter(digits, 1)}{randomLetter(letters, 1)}"; + + string uid = String.Empty; + if (token == "System") uid = "System"; + else + { + var validToken = await _jwtTokenService.ValidateToken(token); + if (validToken == null) return APIResponse.AccessExpireError(); + uid = validToken.FindFirst(ClaimTypes.NameIdentifier)?.Value ?? string.Empty; + } + + if (!(await _pushRepository.FindAcademy(request.bid))) + return APIResponse.Send("100", $"[{summary}], 학원 정보(BID) 확인 불가", string.Empty); + + DBPayload payload = new DBPayload + { + bid = request.bid, + pid = $"AP{DateTime.Now:yyyyMMdd}{frontLetters}{DateTime.Now:HHmmss}{afterLetters}", + title = request.title, + subtitle = request.subtitle, + body = request.body, + alert_yn = request.alert_yn, + category = request.category, + content = request.content, + }; + + var log = new LogPush + { + bid = payload.bid, + pid = payload.pid, + create_date = DateTime.Now, + create_uid = uid + }; + + var saved = await _repositoryService.SaveData(payload); + log.log = $"[{summary}] : 푸시 생성 = {saved}"; + var logSaved = await _repositoryService.SaveData(log); + _logger.LogInformation($"[{summary}]: 푸시 생성 = {saved} : 로그 저장 = {logSaved}"); + if (!saved) return APIResponse.Send("001", $"[{summary}], 실패", string.Empty); + return APIResponse.Send("000", $"[{summary}], 정상", string.Empty); + } + public async Task> DeletePush(string summary, string token, string bid, string pid) + { + string uid = String.Empty; + if (token == "System") uid = "System"; + else + { + var validToken = await _jwtTokenService.ValidateToken(token); + if (validToken == null) return APIResponse.AccessExpireError(); + uid = validToken.FindFirst(ClaimTypes.NameIdentifier)?.Value ?? string.Empty; + } + + var payload = await _pushRepository.FindPushPayload(bid, pid); + if (payload == null) return APIResponse.Send("001", $"[{summary}], 삭제 할 PUSH 없음", string.Empty); + + var log = new LogPush + { + bid = payload.bid, + pid = payload.pid, + create_date = DateTime.Now, + create_uid = uid + }; + var delete = await _repositoryService.DeleteData(payload); + + log.log = $"[{summary}] : 삭제 = {delete}"; + var logSaved = await _repositoryService.SaveData(log); + _logger.LogInformation($"[{summary}]: 삭제 = {delete} : 로그 저장 = {logSaved}"); + if (!delete) return APIResponse.Send("002", $"[{summary}], 실패", string.Empty); + return APIResponse.Send("000", $"[{summary}], 정상", string.Empty); + } + + public async Task> DeleteListPush(string summary, string token, int id) + { + string uid = String.Empty; + if (token == "System") uid = "System"; + else + { + var validToken = await _jwtTokenService.ValidateToken(token); + if (validToken == null) return APIResponse.AccessExpireError(); + uid = validToken.FindFirst(ClaimTypes.NameIdentifier)?.Value ?? string.Empty; + } + + var cabinet = await _pushRepository.FindPushCabinet(id); + if (cabinet == null) return APIResponse.Send("001", $"[{summary}], 삭제 할 PUSH 없음", string.Empty); + + + var log = new LogPush + { + bid = cabinet.bid, + pid = cabinet.pid, + create_date = DateTime.Now, + create_uid = uid + }; + + var delete = await _repositoryService.DeleteData(cabinet); + log.log = $"[{summary}] : {cabinet.pid} 삭제 = {delete}"; + var logSaved = await _repositoryService.SaveData(log); + _logger.LogInformation($"[{summary}]: {cabinet.pid} 삭제 = {delete} : 로그 저장 = {logSaved}"); + if (!delete) return APIResponse.Send("002", $"[{summary}], 실패", string.Empty); + return APIResponse.Send("000", $"[{summary}], 정상", string.Empty); + } + + + public async Task> SearchToUserPush(string summary, string token, int size, PushCabinet? request) + { + string uid = String.Empty; + if (token == "System") uid = "System"; + else + { + var validToken = await _jwtTokenService.ValidateToken(token); + if (validToken == null) return APIResponse.AccessExpireError(); + uid = validToken.FindFirst(ClaimTypes.NameIdentifier)?.Value ?? string.Empty; + } + + return APIResponse.Send("000", $"[{summary}], 정상", string.Empty); + } } + } \ No newline at end of file