using System; using System.Linq; using System.Threading.Tasks; using FMSAdmin.Data; using FMSAdmin.Models; using FMSAdmin.Entities; using FMSAdmin.Services; using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Logging; using Microsoft.AspNetCore.Authorization; using Microsoft.EntityFrameworkCore; using FMSAdmin.Helpers; using System.Data; using System.IO; using OfficeOpenXml; using System.Security.Cryptography; using System.Text; using System.Net.Mail; using System.Net; namespace FMSAdmin.Controllers { [Authorize] [ApiController] [ApiVersion("1")] [Route("api/users")] public class UserController : Controller { private readonly ILogger _logger; private readonly FMSContext _context; private readonly UserService _service; private readonly StorageHelper _storage; public UserController( ILogger logger, FMSContext context, UserService service, StorageHelper storage ) { _logger = logger; _context = context; _service = service; _storage = storage; } /// /// 로그인 /// [AllowAnonymous] [HttpPost("[action]")] public IActionResult Login([FromBody] LoginModel model) { _logger.LogInformation(model.Dump()); var user = _service.Login(model); if (user == null) return BadRequest("아이디나 비밀번호가 잘못되었습니다."); if (user.EmploymentStatus == EmploymentStatus.퇴직) return BadRequest("로그인 할 수 없습니다."); return Ok(new { user.SiteId, user.UserId, user.UserGroupId, UserGroup = new { user.UserGroupId, user.Name, }, user.Name, user.OfficePhoneNo, user.Email, user.PositionId, Position = new { user.CmPosition?.Name, }, SiteName = user.CmSite?.Name, user.RefreshToken, user.AccessToken, user.IsAdmin, user.PasswordUpdatedDate, user.IsSysop, }); } /// /// 패스워드 변경 /// [AllowAnonymous] [HttpPost("[action]/{siteId}/{id}")] public IActionResult ChangePassword(int siteId, string id, [FromForm] string password, [FromForm] string auth) { _logger.LogInformation("password:" + password); _logger.LogInformation("auth:" + auth); // auth 체크는 나중에.. _service.ChangePassword(siteId, id, password); return Ok(id); } /// /// 목록 /// [HttpGet] public IActionResult List([FromQuery] PagingRequest req, [FromQuery] string str, int? type) { _logger.LogInformation(req.Dump()); var query = _FilterAndSort(req, str); if (type != null) query = query.Where(x => x.EmploymentStatus == EmploymentStatus.재직); var list = _ListSelect(query); var paging = PagingList.Pagination(list, req.page, req.limit); return Ok(paging); } /// /// 엑셀파일 익스포트 /// [HttpGet("excel")] public IActionResult ExportExcel([FromQuery] PagingRequest req, string filename) { req.page = 1; req.limit = 0; var query = _FilterAndSort(req, ""); var list = _ListSelect(query); var stream = new MemoryStream(); using (var package = new ExcelPackage(stream)) { var workSheet = package.Workbook.Worksheets.Add("Sheet1"); workSheet.Cells.LoadFromCollection(list, true); if (req.columns != null && req.columns.Length > 0) { workSheet.AddStyle(req.columns, req.sort?.order?.ToLower() == "asc", filename); } package.Save(); } stream.Position = 0; string excelName = $"excel-{DateTime.Now.ToString("yyyyMMddHHmmssfff")}.xlsx"; return File(stream, "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", excelName); } /// /// 상세조회 /// [HttpGet("{id}")] public IActionResult GetByUserId(string id) { var emp = _service.GetByUserId(id); if (emp == null) return NotFound(); return Ok(new { emp.SiteId, emp.UserId, emp.UserGroupId, emp.Name, emp.OfficePhoneNo, emp.Email, //UserGroupName = emp.CmUserGroup.Name, emp.AccessToken, }); } /// /// 조회 /// /// /// /// [HttpGet("{siteId}/{id}")] public IActionResult Get(int siteId, string id) { var data = _service.Gets(id, siteId); if (data.Count() == 0) { return NotFound("사용자정보를 찾을 수 없습니다."); } var item = data.Select(x => new { x.UserGroupId, CmUserGroup = new { x.CmUserGroup.Name, }, x.SiteId, CmSite = new { x.CmSite.Name, }, x.UserId, x.Name, x.Passwd, x.OfficePhoneNo, x.Email, x.EmploymentStatus, EmploymentStatusName = x.EmploymentStatus.ToString(), x.EmploymentType, EmploymentTypeName = x.EmploymentType.ToString(), x.CompanyId, CmCompany = new { x.CmCompany.Name, }, x.DepartmentId, CmDepartment = new { x.CmDepartment.Name, }, x.PositionId, CmPosition = new { x.CmPosition.Name, }, x.BusinessFieldId, CmBusinessField = new { x.CmBusinessField.Name, }, x.MobilePhoneNo, x.EnterDate, x.RetireDate, x.Certificated, x.IsScheduleUser, x.IsSi, x.IsMobile, x.Comment, x.IsUse, x.IsAdmin, CmFile = _storage.ParseFile(x.CmFile), CmFile1 = _storage.ParseFile(x.CmFile1), }); return Ok(item.First()); } /// /// 수정 /// [HttpPost("{siteId}/{id}")] public IActionResult Edit(int siteId, string id, [FromBody] CmUser emp) { _logger.LogInformation(emp.Dump()); /* var currentUserId = int.Parse(User.Identity.Name); if (id != currentUserId) return Forbid(); if (!User.IsInRole(Role.Admin)) return Forbid(); */ if (id != emp.UserId) { return NotFound(); } //ModelState.Remove("Password"); // 이 수정에서는 비밀번호 제외 if (ModelState.IsValid) { try { _service.Edit(id, siteId, emp); } catch (ServiceException ex) { return BadRequest(ex.Message); } } else { foreach (var ms in ModelState.ToArray()) { _logger.LogInformation(ms.Key); } return BadRequest(ModelState); } return Ok(); } /// /// 등록 /// [HttpPut] public IActionResult Create([FromBody] CmUser emp) { // if (!User.IsInRole("Admin")) // return Forbid(); if (ModelState.IsValid) { try { _service.Create(emp); } catch (ServiceException ex) { return BadRequest(ex.Message); } } else { return BadRequest(ModelState); } return Ok(); } /// /// 삭제 /// [HttpDelete("{siteId}/{id}")] public IActionResult Delete(int siteId, string id) { _service.Delete(id, siteId); return Ok(); } // Role 제한 테스트 [AllowAnonymous] [HttpGet("auth")] public IActionResult Auth() { return Ok(); } // 검색 & 정렬 공통 private IQueryable _FilterAndSort(PagingRequest req, string str) { var query = _service.GetAll(); // 기본 Entity 검색 query = query.Filter(req.conditions); // 추가 검색 예제 /* if (req.conditions != null) { foreach (var cond in req.conditions) { switch ($"{cond.field}_{cond.op}") { case "fffff_eq": query = query.Where(x => x.Name == cond.value); break; } } } */ //query = query.Where(x => x.IsUse == true); //아이콘트롤스 시스템 관리자 HIDDEN query = query.Where(x => x.IsSysop == false); if (req.siteId != null) { query = query.Where(x => x.SiteId == Util.ToInt(req.siteId)); } if (req.siteIds != null && req.siteIds.Length > 0) { query = query.Where(x => req.siteIds.Contains(x.SiteId)); } // 업무분야 필드가 있는경우만 추가 if (req.businessFieldId != null) { query = query.Where(x => x.SiteId == req.siteId); query = query.Where(x => x.BusinessFieldId == req.businessFieldId || x.CmBusinessField.Name == "공통"); } if (str != null) { query = query.Where(x => x.UserId.Contains(str) || x.Name.Contains(str)); } // 추가 정렬 예제 /* if (req.sort != null) { switch ($"{req.sort.field}_{req.sort.order}") { case "userId_asc": query = query.OrderBy(x => x.UserId); break; case "userId_desc": query = query.OrderByDescending(x => x.UserId); break; } } */ // 고정정렬 (사옥 준공순) var sortQuery = query.OrderBy(x => x.CmSite.SortOrderNo); sortQuery = sortQuery.ThenByDescending(x => x.CmPosition.Position); // 추가 정렬 sortQuery = sortQuery.ThenSort(req.sort); return sortQuery; } // 셀렉트 공통 private dynamic _ListSelect(IQueryable query) { var list = query.Select(x => new { x.SiteId, SiteName = x.CmSite.Name, x.UserId, x.UserGroupId, x.Name, CmUserGroup = new { x.CmUserGroup.UserGroupId, x.CmUserGroup.Name }, UserGroupName = x.CmUserGroup.Name, x.EmploymentStatus, EmploymentStatusName = x.EmploymentStatus.ToString(), x.OfficePhoneNo, x.MobilePhoneNo, x.Email, x.AccessToken, CmCompanyNm = new { x.CmCompany.Name }, CompanyName = x.CmCompany.Name, CmDepartment = new { x.CmDepartment.Name }, DepartmentName = x.CmDepartment.Name, Dept = x.CmCompany.Name + '/' + x.CmPosition.Name, PositionName = x.CmPosition.Name, BusinessFieldName = x.CmBusinessField.Name, x.EmploymentType, EmploymentTypeName = x.EmploymentType.ToString(), CmFile = _storage.ParseFile(x.CmFile) }); return list; } /// /// 로그인 - 사이트 ID 조회 /// [AllowAnonymous] [HttpGet("GetSite")] public IActionResult GetSite() { var site = _service.GetCmSites(); if (site == null) return BadRequest("사이트 정보를 가져오지 못했습니다."); var list = site.Select(x => new { Id = x.SiteId, x.Name, }); return Ok(list); } [AllowAnonymous] [HttpPost("[action]/{reqid}/{email}")] public IActionResult SendEmailAuthCode(string email, string reqid) { // 요청번호 reqid 무시. 안쓰고있음 if (string.IsNullOrEmpty(email)) { return BadRequest("이메일을 입력해주세요."); } email = email.Trim(); var query = _service.GetAll().Where(x => x.Email == email); if (query.Count() == 0) { return BadRequest("이메일과 일치하는 회원이 없습니다."); } if (query.Count() > 1) { return BadRequest("동일한 이메일이 여러개 존재합니다."); } string authCode = "" + new Random().Next(10000, 99999); _logger.LogInformation("authCode:" + authCode); var user = query.FirstOrDefault(); // 이메일 발송 using (var message = new MailMessage()) { message.To.Add(new MailAddress(email, user.Name)); message.From = new MailAddress("hdc.icontrols.rnd1@gmail.com", "FMS"); message.Subject = "FMS 비밀번호 찾기 인증번호"; message.Body = $"
{user.Name}님의 아이디는 {user.UserId.Substring(0, user.UserId.Length - 2)}** 입니다.

보안을 위해 아래 인증번호를 입력하시고,
비밀번호를 새로 설정해 주시기 바랍니다.

인증번호 : {authCode}
"; message.IsBodyHtml = true; var smtp = new SmtpClient { Host = "smtp.gmail.com", Port = 587, EnableSsl = true, DeliveryMethod = SmtpDeliveryMethod.Network, Credentials = new NetworkCredential("hdc.icontrols.rnd1@gmail.com", "pwrd12#$"), Timeout = 20000 }; smtp.Send(message); } // 검증용 코드 출력 string code = null; using (SHA256 mySHA256 = SHA256.Create()) { code = Convert.ToBase64String(mySHA256.ComputeHash(Encoding.UTF8.GetBytes(email + authCode))).Replace("+", ".").Replace("/", "_").Replace("=", "-"); } return Ok(code); } [AllowAnonymous] [HttpPost("[action]/{authCode}/{code}/{email}")] public IActionResult ValidAuthCode(string authCode, string code, string email) { string check = ""; if (string.IsNullOrEmpty(email)) { return BadRequest("이메일을 입력해주세요."); } if (string.IsNullOrEmpty(authCode)) { return BadRequest("인증번호를 입력해주세요."); } var query = _service.GetAll().Where(x => x.Email == email); if (query.Count() == 0) { return BadRequest("이메일과 일치하는 회원이 없습니다."); } if (query.Count() > 1) { return BadRequest("동일한 이메일이 여러개 존재합니다."); } var member = query.FirstOrDefault(); // 검증용 코드로 검증 authCode = authCode.Trim(); using (SHA256 mySHA256 = SHA256.Create()) { check = Convert.ToBase64String(mySHA256.ComputeHash(Encoding.UTF8.GetBytes(email + authCode))).Replace("+", ".").Replace("/", "_").Replace("=", "-"); } if (code != check) { return BadRequest("인증번호가 일치하지 않습니다."); } // 검증완료 비밀번호 초기화 _service.ChangePassword(member.SiteId, member.UserId, member.UserId, true); return Ok(new { SiteId = member.SiteId, UserId = member.UserId, }); } } }