using System.IdentityModel.Tokens.Jwt; using System.Security.Claims; using Microsoft.IdentityModel.Tokens; using AcaMate.Common.Data; using AcaMate.Common.Models; using AcaMate.V1.Models; using Microsoft.AspNetCore.Mvc; using Microsoft.EntityFrameworkCore; using System.Linq.Expressions; using AcaMate.V1.Services; using AcaMate.Common.Token; using Microsoft.Extensions.Logging; using Microsoft.EntityFrameworkCore.Query; using MySqlConnector; using System.Linq; namespace AcaMate.V1.Controllers; [ApiController] [Route("/api/v1/in/user")] [ApiExplorerSettings(GroupName = "사용자")] public class UserController : ControllerBase { private readonly AppDbContext _dbContext; private readonly ILogger _logger; private readonly JwtTokenService _jwtTokenService; public UserController(AppDbContext dbContext, ILogger logger, JwtTokenService jwtTokenService) { _dbContext = dbContext; _logger = logger; _jwtTokenService = jwtTokenService; } [HttpGet] [CustomOperation("회원 정보 조회", "회원 정보 조회", "사용자")] public IActionResult GetUserData(string uid) { if (string.IsNullOrEmpty(uid)) return BadRequest(DefaultResponse.InvalidInputError); try { var user = _dbContext.User .Where(u => u.uid == uid) .Select(u => new User { uid = u.uid, name = u.name, auto_login_yn = u.auto_login_yn, birth = u.birth, device_id = u.device_id, login_date = u.login_date, type = u.type }) .FirstOrDefault(); var response = new APIResponseStatus { status = new Status { code = "000", message = "정상" }, data = user }; return Ok(response.JsonToString()); } catch (Exception ex) { return StatusCode(500, DefaultResponse.UnknownError); } } [HttpGet("login")] [CustomOperation("SNS 로그인", "로그인 후 회원이 있는지 확인", "사용자")] public IActionResult Login(string acctype, string sns_id) { if (string.IsNullOrEmpty(acctype) && string.IsNullOrEmpty(sns_id)) return BadRequest(DefaultResponse.InvalidInputError); try { var login = _dbContext.Login.FirstOrDefault(l => l.sns_type == acctype && l.sns_id == sns_id); var uid = ""; List bids = new List(); if (login != null) { uid = login.uid; var user = _dbContext.User.FirstOrDefault(user => user.uid == uid); if (user != null) { user.login_date = DateTime.Now; _dbContext.SaveChanges(); } // 토큰 생성은 로그인 부분에서 하는거지 var accessToken = _jwtTokenService.GenerateJwtToken(uid, "Normal"); var refreshToken = _jwtTokenService.GenerateRefreshToken(uid); _dbContext.RefreshTokens.Add(refreshToken); _dbContext.SaveChanges(); var userAcademy = _dbContext.UserAcademy.Where(u => u.uid == uid).ToList(); foreach (var userData in userAcademy) { _logger.LogInformation($"uid: {userData.uid} || bid: {userData.bid}"); bids.Add(userData.bid); } var response = new APIResponseStatus { status = new Status { code = "000", message = "정상" }, data = new { uid = $"{uid}", bid = bids } }; return Ok(response.JsonToString()); } else { // 계정이 없다는 거 var response = new APIResponseStatus { status = new Status { code = "010", message = "정상" }, data = new { uid = "", bid = new string[] { } } }; return Ok(response.JsonToString()); } } catch (Exception ex) { return StatusCode(500, DefaultResponse.UnknownError); } } [HttpPost("academy")] [CustomOperation("학원 리스트 확인", "등록된 학원 리스트 확인", "사용자")] public IActionResult ReadAcademyInfo([FromBody] RequestAcademy request) { if (!request.bids.Any()) { var error = DefaultResponse.InvalidInputError; return Ok(error); } var academies = _dbContext .Academy .Where(a => request.bids.Contains(a.bid)) .Select(a => new AcademyName { bid = a.bid, name = a.business_name }) .ToList(); var response = new APIResponseStatus> { status = new Status { code = "000", message = "정상" }, data = academies }; return Ok(response); } [HttpPost("register")] [CustomOperation("회원 가입", "사용자 회원 가입", "사용자")] public async Task UserRegister([FromBody] UserAll request) { if (!ModelState.IsValid) return BadRequest(DefaultResponse.InvalidInputError); var atIndext = request.email.IndexOf('@'); var localPart_email = request.email.Substring(0, atIndext); var uid = $"AM{localPart_email}{DateTime.Now:yyyyMMdd}"; var user = new User { uid = uid, name = request.name, birth = request.birth, type = request.type, device_id = request.device_id, auto_login_yn = request.auto_login_yn, login_date = request.login_date }; var login = new Login { uid = uid, sns_id = request.sns_id, sns_type = request.sns_type }; var permission = new Permission { uid = uid, location_yn = request.location_yn, camera_yn = request.camera_yn, photo_yn = request.photo_yn, push_yn = request.push_yn, market_app_yn = request.market_app_yn, market_sms_yn = request.market_sms_yn, market_email_yn = request.market_email_yn }; var contact = new Contact { uid = uid, email = request.email, phone = request.phone, address = request.address }; if (await SaveData(user, u => u.uid)) { await SaveData(login, l => l.sns_id); await SaveData(permission, p => p.uid); await SaveData(contact, c => c.uid); } // TO-DO: jwt 토큰 만들어서 여기서 보내는 작업을 해야 함 var token = _jwtTokenService.GenerateJwtToken(uid, "admin"); var refreshToken = _jwtTokenService.GenerateRefreshToken(uid); await SaveData(refreshToken, rt => rt.uid); /* */ var principalToken = _jwtTokenService.ValidateToken(token); if (principalToken != null) { var jti = principalToken.FindFirst(JwtRegisteredClaimNames.Jti)?.Value; var sub = principalToken.FindFirst(JwtRegisteredClaimNames.Sub)?.Value; var id = principalToken.FindFirst(ClaimTypes.NameIdentifier)?.Value; var id2 = principalToken.FindFirst(JwtRegisteredClaimNames.Sub)?.Value; // var check = principalToken.FindFirst("sub")?.Value; _logger.LogInformation($"토큰? - {jti}"); _logger.LogInformation($"토큰? - {sub}"); _logger.LogInformation($"토큰? - {id}"); // TODO: 도대체 토큰 이거 sub확인이 왜 안되는걸까.? } else { _logger.LogInformation("dd"); } /* */ var result = new APIResponseStatus() { status = new Status() { code = "000", message = "정상" }, data = new { uid = uid, accessToken = token, refreshToken = refreshToken.refresh_token } }; return Ok(result.JsonToString()); } private 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 { dbSet.Add(entity); } await _dbContext.SaveChangesAsync(); _logger.LogInformation($"[{typeof(T)}] DB 저장 완료: 종료"); return true; } catch (Exception ex) { _logger.LogInformation($"[{typeof(T)}] 알 수 없는 오류: 종료\n{ex}"); return false; } } [HttpGet("logout")] [CustomOperation("로그아웃", "사용자 로그아웃", "사용자")] public async Task LogOut(string token, string refresh)//([FromBody] UserAll request) { var principalToken = _jwtTokenService.ValidateToken(token); if (principalToken != null) { // var uid = principalToken.FindFirst(JwtRegisteredClaimNames.Jti)?.Value; var uid = principalToken.FindFirst("sub")?.Value; _logger.LogInformation($"토큰? - {uid}"); } else { _logger.LogInformation("dd"); } return Ok("로그아웃"); } }