using System.IdentityModel.Tokens.Jwt; using System.Security.Claims; using Microsoft.IdentityModel.Tokens; using Microsoft.AspNetCore.Mvc; using Microsoft.EntityFrameworkCore; using System.Linq.Expressions; using Microsoft.Extensions.Logging; using Microsoft.EntityFrameworkCore.Query; using MySqlConnector; using System.Linq; using AcaMate.Common.Data; using AcaMate.Common.Token; using AcaMate.Common.Models; using AcaMate.V1.Models; using AcaMate.V1.Services; namespace AcaMate.V1.Controllers; /// /// USER는 사용자가 자신의 데이터를 보거나 만들거나 하는 등 직접 사용하는 경우에 사용 /// [ApiController] [Route("/api/v1/in/user")] [ApiExplorerSettings(GroupName = "사용자")] public class UserController : ControllerBase { private readonly AppDbContext _dbContext; private readonly ILogger _logger; private readonly JwtTokenService _jwtTokenService; private readonly IRepositoryService _repositoryService; public UserController(AppDbContext dbContext, ILogger logger, JwtTokenService jwtTokenService, IRepositoryService repositoryService) { _dbContext = dbContext; _logger = logger; _jwtTokenService = jwtTokenService; _repositoryService = repositoryService; } [HttpGet] [CustomOperation("회원 정보 조회", "회원 정보 조회 (자기자신)", "사용자")] public async Task GetUserData(string token, string refresh) { if (string.IsNullOrEmpty(token) || string.IsNullOrEmpty(refresh)) return BadRequest(APIResponse.InvalidInputError()); if (!ModelState.IsValid) return BadRequest(APIResponse.InvalidInputError()); string summary = String.Empty; try { var validateToken = await _repositoryService.ValidateToken(token, refresh); summary = _repositoryService.ReadSummary(typeof(UserController), "GetUserData"); var user = await _dbContext.User .Where(u => u.uid == validateToken.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 }) .FirstOrDefaultAsync(); return Ok(APIResponse.Send("000", $"[{summary}], 정상", user)); } 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) { return StatusCode(500, APIResponse.UnknownError(ex.Message)); } } [HttpGet("academy")] [CustomOperation("학원 리스트 확인", "사용자가 등록된 학원 리스트 확인", "사용자")] public async Task ReadAcademyInfo(string token, string refresh) { if (string.IsNullOrEmpty(token) || string.IsNullOrEmpty(refresh)) return BadRequest(APIResponse.InvalidInputError()); if (!ModelState.IsValid) return BadRequest(APIResponse.InvalidInputError()); string summary = String.Empty; try { var validateToken = await _repositoryService.ValidateToken(token, refresh); summary = _repositoryService.ReadSummary(typeof(UserController), "ReadAcademyInfo"); var academies = await (from ua in _dbContext.UserAcademy join a in _dbContext.Academy on ua.bid equals a.bid where ua.uid == validateToken.uid select new AcademyName { bid = a.bid, name = a.business_name }).ToListAsync(); return Ok(APIResponse.Send("000", $"[{summary}], 정상.", academies)); } 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.LogInformation($"[{summary}] : {ex}"); return StatusCode(500, APIResponse.UnknownError(ex.Message)); } } [HttpGet("login")] [CustomOperation("SNS 로그인", "로그인 후 회원이 있는지 확인", "사용자")] public async Task Login(string acctype, string sns_id) { // API 동작 파라미터 입력 값 확인 if (string.IsNullOrEmpty(acctype) && string.IsNullOrEmpty(sns_id)) return BadRequest(APIResponse.InvalidInputError()); if (!ModelState.IsValid) return BadRequest(APIResponse.InvalidInputError()); string summary = String.Empty; try { summary = _repositoryService.ReadSummary(typeof(UserController), "Login"); var login = await _dbContext.Login .FirstOrDefaultAsync(l => l.sns_type == acctype && l.sns_id == sns_id); if (login != null) { // 로그인 정보가 존재 하는 상황 var user = await _dbContext.User .FirstOrDefaultAsync(u => u.uid == login.uid); // 회원 정보 없음 if (user == null) return Ok(APIResponse.Send("002", $"[{summary}], 회원 정보 오류", Empty)); // 정상적으로 User 테이블에도 있는것이 확인 됨 user.login_date = DateTime.Now; await _dbContext.SaveChangesAsync(); // 토큰 생성은 로그인이 이제 되고 나서 한다. var accessToken = _jwtTokenService.GenerateJwtToken(login.uid); var refreshToken = _jwtTokenService.GenerateRefreshToken(login.uid); _logger.LogInformation($"[{summary}] : {login.uid} = {accessToken}, {refreshToken}"); if (await _repositoryService.SaveData(refreshToken)) { var logUser = new LogUser { uid = login.uid, create_date = DateTime.Now, create_uid = "System", log = $"[{summary}] : 정상" }; await _repositoryService.SaveData(logUser); return Ok(APIResponse.Send("000", $"[{summary}], 정상", new { token = accessToken, refresh = refreshToken.refresh_token })); } else { var logUser = new LogUser { uid = login.uid, create_date = DateTime.Now, create_uid = "System", log = $"[{summary}] : 실패" }; await _repositoryService.SaveData(logUser); return Ok(APIResponse.InternalSeverError($"[{summary}], 로그인 저장 실패")); } } return Ok(APIResponse.Send("001", $"[{summary}], 로그인 정보 없음", Empty)); } catch (Exception ex) { _logger.LogInformation($"[{summary}] : {ex}"); return StatusCode(500, APIResponse.UnknownError(ex.Message)); } } [HttpPost("register")] [CustomOperation("회원 가입", "사용자 회원 가입", "사용자")] public async Task UserRegister([FromBody] UserAll request) { if (!ModelState.IsValid) return BadRequest(APIResponse.InvalidInputError()); string summary = String.Empty; try { summary = _repositoryService.ReadSummary(typeof(UserController), "UserRegister"); var localPartEmail = request.email.Substring(0, request.email.IndexOf('@')); var uid = $"AM{localPartEmail}{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, push_token = request.push_token }; 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 }; var logUser = new LogUser { uid = login.uid, create_date = DateTime.Now, create_uid = "System", log = "" }; var saveUser = await _repositoryService.SaveData(user); var saveLogin = await _repositoryService.SaveData(login); var savePermission = await _repositoryService.SaveData(permission); var saveContact = await _repositoryService.SaveData(contact); if (saveUser && saveLogin && savePermission && saveContact) { var token = _jwtTokenService.GenerateJwtToken(uid); var refreshToken = _jwtTokenService.GenerateRefreshToken(uid); if (await _repositoryService.SaveData(refreshToken)) { logUser.log = $"[{summary}] : 정상"; if (await _repositoryService.SaveData(logUser)) _logger.LogError($"[{summary}] : 로그 저장 성공"); return Ok(APIResponse.Send("000", $"[{summary}], 정상", new { accessToken = token, refreshToken = refreshToken.refresh_token })); } else { _logger.LogError($"[{summary}] : 토큰 저장 실패"); } } logUser.log = $"[{summary}] : 동작 실패"; await _repositoryService.SaveData(logUser); return Ok(APIResponse.InternalSeverError()); } catch (Exception ex) { _logger.LogInformation($"[{summary}] : {ex.Message}"); return BadRequest(APIResponse.UnknownError(ex.Message)); } } [HttpGet("logout")] [CustomOperation("로그아웃", "사용자 로그아웃", "사용자")] public async Task Logout(string token, string refresh) { if (string.IsNullOrEmpty(token) || string.IsNullOrEmpty(refresh)) return BadRequest(APIResponse.InvalidInputError()); if (!ModelState.IsValid) return BadRequest(APIResponse.InvalidInputError()); string summary = String.Empty; try { summary = _repositoryService.ReadSummary(typeof(UserController), "UserRegister"); // 여기서 애초에 토큰 관련 에러가 2개가 나오게 만들어져 있음 var validateToken = await _repositoryService.ValidateToken(token, refresh); var refreshToken = await _dbContext.RefreshTokens.FirstOrDefaultAsync(r => r.uid == validateToken.uid); if (refreshToken != null) { refreshToken.revoke_Date = DateTime.Now; await _repositoryService.SaveData(refreshToken); return Ok(APIResponse.Send("000", $"[{summary}], 로그아웃 정상", Empty)); } // 리프레시 토큰이 없다?? 그럼 이거 무조건 문제지 (이유를 알 수 없는) return Ok(APIResponse.UnknownError()); } catch (TokenException tokenEx) { return Ok(APIResponse.Send("101", $"[{summary}], 입력 받은 토큰의 문제", Empty)); } catch (RefreshRevokeException refreshEx) { return Ok(APIResponse.Send("102", $"[{summary}], 폐기된 리프레시 토큰", Empty)); } catch (Exception ex) { return StatusCode(500, APIResponse.UnknownError($"[{summary}], {ex.Message}")); } } [HttpGet("cancel")] [CustomOperation("회원 탈퇴", "사용자 탈퇴", "사용자")] public async Task Cancel(string token, string refresh) { if (string.IsNullOrEmpty(token) || string.IsNullOrEmpty(refresh)) return BadRequest(APIResponse.InvalidInputError()); if (!ModelState.IsValid) return BadRequest(APIResponse.InvalidInputError()); string summary = String.Empty; try { summary = _repositoryService.ReadSummary(typeof(UserController), "Cancel"); // 여기서 애초에 토큰 관련 에러가 2개가 나오게 만들어져 있음 var validateToken = await _repositoryService.ValidateToken(token, refresh); var user = await _dbContext.User.FirstOrDefaultAsync(u => u.uid == validateToken.uid); if (user == null) return Ok(APIResponse.Send("001", $"[{summary}], 회원 정보 확인 오류", Empty)); var logUser = new LogUser { uid = validateToken.uid, create_date = DateTime.Now, create_uid = "System", log = "" }; string returnCode = "000"; string returnMsg = $"[{summary}], 정상"; if (await _repositoryService.DeleteData(user)) logUser.log = $"[{summary}] : 정상"; else { logUser.log = $"[{summary}] : 실패"; returnMsg = $"[{summary}], 실패"; returnCode = "001"; } if (!(await _repositoryService.SaveData(logUser))) _logger.LogError($"[{summary}] : 로그 저장 실패"); return Ok(APIResponse.Send(returnCode, returnMsg, Empty)); } catch (TokenException tokenEx) { return Ok(APIResponse.Send("101", $"[{summary}], 입력 받은 토큰의 문제", Empty)); } catch (RefreshRevokeException refreshEx) { return Ok(APIResponse.Send("102", $"[{summary}], 폐기된 리프레시 토큰", Empty)); } catch (Exception ex) { return StatusCode(500, APIResponse.UnknownError($"[{summary}], {ex.Message}")); } } } // 근데 회원 정보를 변경하는게 뭐뭐를 변경해야 하는지 아직 정해진게 없어서 이건 일단 보류 /* [HttpGet("set")] [CustomOperation("회원 정보 변경", "회원 정보 변경", "사용자")] public async Task SetUserData(string token, string refresh) //, [FromBody]) { if (string.IsNullOrEmpty(token) || string.IsNullOrEmpty(refresh)) return BadRequest(APIResponse.InvalidInputError()); if (!ModelState.IsValid) return BadRequest(APIResponse.InvalidInputError()); string summary = String.Empty; try { summary = _repositoryService.ReadSummary(typeof(UserController), "Cancel"); // 여기서 애초에 토큰 관련 에러가 2개가 나오게 만들어져 있음 var validateToken = await _repositoryService.ValidateToken(token, refresh); var user = await _dbContext.User.FirstOrDefaultAsync(u => u.uid == validateToken.uid); } catch (TokenException tokenEx) { return Ok(APIResponse.Send("101", $"[{summary}], 입력 받은 토큰의 문제", Empty)); } catch (RefreshRevokeException refreshEx) { return Ok(APIResponse.Send("102", $"[{summary}], 폐기된 리프레시 토큰", Empty)); } catch (Exception ex) { return StatusCode(500, APIResponse.UnknownError($"[{summary}], {ex.Message}")); } } } /* string uid = ""; if (token == "System") uid = "System"; else { if (string.IsNullOrEmpty(token) || string.IsNullOrEmpty(refresh)) return BadRequest(APIResponse.InvalidInputError()); if(!ModelState.IsValid) return BadRequest(APIResponse.InvalidInputError()); var validateToken = await _repositoryService.ValidateToken(token, refresh); uid = validateToken.uid; } string summary = String.Empty; try { summary = _repositoryService.ReadSummary(typeof(PushController), "GetUserData"); } */