using AcaMate.Common.Data; using AcaMate.Common.Token; using AcaMate.Common.Models; using Microsoft.AspNetCore.Mvc; using Microsoft.EntityFrameworkCore; using System.Linq.Expressions; using System.Security.Claims; using AcaMate.V1.Models; using Microsoft.IdentityModel.Tokens; using Microsoft.VisualBasic; namespace AcaMate.V1.Services; public interface IRepositoryService { Task SaveData(T entity, Expression> key) where T : class; Task ValidateToken(string token, string refresh); Task SaveDataFK(T entity) where T : class; } public class RepositoryService: IRepositoryService { private readonly AppDbContext _dbContext; private readonly ILogger _logger; private readonly JwtTokenService _jwtTokenService; public RepositoryService(AppDbContext dbContext, ILogger logger, JwtTokenService jwtTokenService) { _dbContext = dbContext; _logger = logger; _jwtTokenService = jwtTokenService; } public async Task SaveData (T entity, Expression> key) where T : class { try { var value = key.Compile()(entity); // x 라 함은 Expression 으로 생성되는 트리에서 T 타입으의 매개변수를 지칭함 var parameter = Expression.Parameter(typeof(T), "x"); var invokedExpr = Expression.Invoke(key, parameter); var constantExpr = Expression.Constant(value, key.Body.Type); var equalsExpr = Expression.Equal(invokedExpr, constantExpr); var predicate = Expression.Lambda>(equalsExpr, parameter); var dbSet = _dbContext.Set(); var entityData = await dbSet.FirstOrDefaultAsync(predicate); if (entityData != null) { _logger.LogInformation($"[{typeof(T)}] 해당 PK 존재 [{value}]: 계속"); var entry = _dbContext.Entry(entityData); entry.CurrentValues.SetValues(entity); if (entry.Properties.Any(p => p.IsModified)) { _logger.LogInformation($"[{typeof(T)}] 변경사항 존재: 계속"); } else { _logger.LogInformation($"[{typeof(T)}] 변경사항 없음: 종료"); return true; } } else { _logger.LogInformation($"[{typeof(T)}] 처음등록"); dbSet.Add(entity); } await _dbContext.SaveChangesAsync(); _logger.LogInformation($"[{typeof(T)}] DB 저장 완료: 종료"); return true; } catch (Exception ex) { _logger.LogInformation($"[{typeof(T)}] 알 수 없는 오류: 종료 {ex}"); return false; } } //토큰 태울때는 인코딩 된 걸로 태워야지 원본꺼 태우면 데이터에 손상옵니다. /// /// 실제로 엑세스 토큰과 리프레시 토큰으로 접근 하기 위한 메서드 /// public async Task ValidateToken(string token, string refresh) { var principalToken = _jwtTokenService.ValidateToken(token); if (principalToken != null) { var uid = principalToken.FindFirst(ClaimTypes.NameIdentifier)?.Value ?? string.Empty; _logger.LogInformation($"토큰 변환 - {uid}"); return new ValidateToken { token = token, refresh = refresh, uid = uid }; } else { _logger.LogInformation("엑세스 토큰 만료"); var refreshToken = await _dbContext.RefreshTokens .FirstOrDefaultAsync(t => t.refresh_token == refresh); if (refreshToken == null) throw new TokenException("입력 받은 토큰 자체의 문제"); var uid = refreshToken.uid; if (refreshToken.revoke_Date < DateTime.Now) throw new RefreshRevokeException("리프레시 토큰 해지"); if (refreshToken.expire_date > DateTime.Now) { _logger.LogInformation($"인증 완료 리프레시 : {uid}"); var access = _jwtTokenService.GenerateJwtToken(uid); return new ValidateToken { token = access, refresh = refreshToken.refresh_token, uid = uid }; } else { refreshToken = _jwtTokenService.GenerateRefreshToken(uid); _logger.LogInformation("리프레시 토큰 만료"); await SaveData(refreshToken, rt => rt.uid); return new ValidateToken { token = token, refresh = refreshToken.refresh_token, uid = uid }; } } } // public async Task SaveData(T pushCabinet) // { // throw new NotImplementedException(); // } public async Task SaveDataFK(T entity) where T : class { try { // EF Core 메타데이터를 통해 엔티티 T의 기본 키 속성 정보를 가져옴 var keyProperties = _dbContext.Model.FindEntityType(typeof(T)).FindPrimaryKey().Properties; // 각 키 속성에 대해, entity에서 실제 키 값을 추출 var keyValues = keyProperties .Select(p => typeof(T).GetProperty(p.Name).GetValue(entity)) .ToArray(); // 기본 키 값을 이용해서 기존 엔티티를 찾음 (복합 키도 자동으로 처리됨) var existingEntity = await _dbContext.Set().FindAsync(keyValues); if (existingEntity != null) { _logger.LogInformation($"[{typeof(T)}] 기존 데이터 발견: 기본 키 값({string.Join(", ", keyValues)})"); // 기존 엔티티를 업데이트: 새 entity의 값으로 교체 _dbContext.Entry(existingEntity).CurrentValues.SetValues(entity); } else { _logger.LogInformation($"[{typeof(T)}] 신규 데이터 등록: 기본 키 값({string.Join(", ", keyValues)})"); // 데이터가 없으면 새 엔티티 추가 _dbContext.Set().Add(entity); } // 변경 사항 저장 await _dbContext.SaveChangesAsync(); _logger.LogInformation($"[{typeof(T)}] DB 저장 완료"); return true; } catch (Exception ex) { _logger.LogError($"[{typeof(T)}] 저장 중 오류 발생: {ex}"); return false; } } }