| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596 |
- using System.Diagnostics;
- using Microsoft.AspNetCore.Mvc;
- using Microsoft.AspNetCore.Mvc.Filters;
- using Microsoft.AspNetCore.Mvc.Rendering;
- using Microsoft.AspNetCore.Authorization;
- using Microsoft.AspNetCore.WebUtilities;
- using Microsoft.EntityFrameworkCore;
- using bitforum.Helpers;
- using bitforum.Models;
- using bitforum.Models.Account;
- using bitforum.Services;
- using bitforum.Constants;
- namespace bitforum.Controllers.Member
- {
- [Authorize]
- [Route("Member")]
- public class ListController : Controller
- {
- private readonly ILogger<ListController> _logger;
- private readonly IFileUploadService _fileUploadService;
- private readonly DefaultDbContext _db;
- private readonly string _IndexViewPath = "~/Views/Member/List/Index.cshtml";
- private readonly string _WriteViewPath = "~/Views/Member/List/Write.cshtml";
- private readonly string _EditViewPath = "~/Views/Member/List/Edit.cshtml";
- private string? _queryString = null;
- public ListController(ILogger<ListController> logger, IFileUploadService fileUploadService, DefaultDbContext db)
- {
- _logger = logger;
- _fileUploadService = fileUploadService;
- _db = db;
- }
- [ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]
- public IActionResult Error()
- {
- return View(new ErrorViewModel { RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier });
- }
- public override void OnActionExecuting(ActionExecutingContext context)
- {
- ViewBag.QueryString = _queryString = string.Join("&", QueryHelpers.ParseQuery(HttpContext.Request.QueryString.Value).Select(r => $"{r.Key}={r.Value.FirstOrDefault()}"));
- base.OnActionExecuting(context);
- }
- [HttpGet("List")]
- public async Task<IActionResult> Index(
- [FromQuery]
- int page = 1, int perPage = 10, byte? search = null, string? keyword = null, string startAt = null!, string endAt = null!, sbyte tab = 0, sbyte isEmailVerified = 0, sbyte isAuthCertified = 0, Gender? gender = null
- ) {
- var query = _db.Member.AsQueryable();
- // 검색 조건 적용
- if (!string.IsNullOrEmpty(keyword) && search.HasValue)
- {
- switch (search)
- {
- case 1: // ID 검색
- if (int.TryParse(keyword, out int memberID))
- {
- query = query.Where(m => m.ID == memberID);
- }
- else
- {
- query = query.Where(m => m.ID == 0);
- }
- break;
- case 2: // 이메일 검색
- query = query.Where(m => m.Email.Contains(keyword));
- break;
- case 3: // 별명 검색
- query = query.Where(m => m.Name != null && m.Name.Contains(keyword));
- break;
- case 4: // 이름 검색
- query = query.Where(m => m.FullName != null && m.FullName.Contains(keyword));
- break;
- case 5: // 연락처 검색
- query = query.Where(m => m.Phone != null && m.Phone.Contains(keyword));
- break;
- }
- }
- if (tab > 0)
- {
- switch (tab)
- {
- case 1: // 차단
- query = query.Where(m => m.IsDenied);
- break;
- case 2: // 탈퇴
- query = query.Where(m => m.IsWithdraw);
- break;
- case 3: // 관리자
- query = query.Where(m => m.IsAdmin);
- break;
- }
- }
- if (gender is not null) // 성별
- {
- query = query.Where(m => m.Gender == gender);
- }
- if (isEmailVerified > 0) // 이메일 인증 여부
- {
- query = query.Where(m => m.IsEmailVerified == true);
- }
- if (isAuthCertified > 0) // 본인 인증 여부
- {
- query = query.Where(m => m.IsAuthCertified == true);
- }
- // 가입 일시
- var today = DateTime.UtcNow.Date;
- if (startAt != null && DateTime.TryParse(startAt, out var st))
- {
- query = query.Where(log => log.CreatedAt >= st);
- }
- if (endAt != null && DateTime.TryParse(endAt, out var et))
- {
- query = query.Where(log => log.CreatedAt <= et);
- }
- query = query.OrderByDescending(c => c.CreatedAt);
- var members = await query
- .Skip((page - 1) * perPage)
- .Take(perPage)
- .Select(c => new
- {
- GradeName = _db.MemberGrade.Where(m => m.ID == c.GradeID).Select(m => m.KorName).FirstOrDefault(), // 회원등급 이름
- c.ID,
- c.SID,
- c.Email,
- c.Name,
- c.FullName,
- c.Icon,
- c.Coin,
- c.Exp,
- c.Phone,
- c.Gender,
- c.Birthday,
- c.Following,
- c.Followed,
- c.IsEmailVerified,
- c.IsAuthCertified,
- c.IsDenied,
- c.IsAdmin,
- c.IsWithdraw,
- c.LastLoginIp,
- c.LastLoginAt,
- c.CreatedAt,
- c.UpdatedAt
- })
- .ToListAsync();
- var data = new List<object>();
- if (members.Count > 0)
- {
- foreach (var row in members)
- {
- data.Add(new
- {
- row.GradeName,
- row.ID,
- row.Email,
- row.Name,
- row.FullName,
- row.Icon,
- Phone = row?.Phone ?? "-",
- Gender = row.Gender.HasValue ? row.Gender.ToString() : "-",
- Birthday = row.Birthday?.ToString("yyyy.MM.dd"),
- Coin = row.Coin.ToString("N0"),
- Exp = row.Exp.ToString("N0"),
- Following = row.Following.ToString("N0"),
- Followed = row.Followed.ToString("N0"),
- row.IsEmailVerified,
- row.IsAuthCertified,
- row.IsDenied,
- row.IsAdmin,
- row.IsWithdraw,
- row.LastLoginIp,
- LastLoginAt = row.LastLoginAt?.ToString("yyyy.MM.dd"),
- CreatedAt = row.CreatedAt.ToString("yyyy.MM.dd"),
- UpdatedAt = row.UpdatedAt?.ToString("yyyy.MM.dd"),
- ApproveURL = $"/Member/List/{row.ID}/Approve?{_queryString}",
- EditURL = $"/Member/List/{row.ID}/Edit?{_queryString}",
- DeleteURL = $"/Member/List/{row.ID}/Delete?{_queryString}"
- });
- }
- }
- var parameter = new
- {
- Page = page,
- PerPage = perPage,
- Search = search,
- Keyword = keyword,
- StartAt = startAt,
- EndAt = endAt,
- Tab = tab,
- IsEmailVerified = isEmailVerified,
- IsAuthCertified = isAuthCertified,
- Gender = gender,
- };
- ViewBag.Data = data;
- ViewBag.Total = await query.CountAsync();
- ViewBag.Parameter = parameter;
- ViewBag.Pagination = new Pagination(ViewBag.Total, page, perPage, parameter);
- return View(_IndexViewPath);
- }
- [HttpGet("List/Write")]
- public IActionResult Write()
- {
- ViewBag.MemberGrades = new SelectList(
- _db.MemberGrade.Where(c => c.IsActive).OrderByDescending(c => c.Order),
- "ID",
- "KorName",
- null
- );
- return View(_WriteViewPath);
- }
- [HttpPost("List/Create")]
- public async Task<IActionResult> Create([FromForm] Models.Account.Member request, IFormFile? photo, IFormFile? icon)
- {
- try
- {
- if (!ModelState.IsValid)
- {
- throw new Exception("유효성 검사에 실패하였습니다.");
- }
- if (request.FirstName != null || request.LastName != null)
- {
- request.FullName = $"{request.FirstName}{request.LastName}";
- }
- // 이메일 중복 확인
- if (await _db.Member.AnyAsync(c => c.Email == request.Email))
- {
- throw new ArgumentException("이미 등록된 이메일 주소입니다.");
- }
- // 별명 중복 확인
- if (await _db.Member.AnyAsync(c => c.Name == request.Name))
- {
- throw new ArgumentException("이미 등록된 별명입니다.");
- }
-
- request.Password = BCrypt.Net.BCrypt.HashPassword(request.Password);
- request.PasswordUpdatedAt = DateTime.UtcNow;
- request.SignupIP = HttpContext.GetClientIP();
- request.CreatedAt = DateTime.UtcNow;
- await _db.Member.AddAsync(request);
- int affectedRows = await _db.SaveChangesAsync();
- if (affectedRows <= 0)
- {
- throw new Exception("회원 등록 중 오류가 발생했습니다.");
- }
- request.Photo = await _fileUploadService.UploadImageAsync(photo, UploadFolder.Member, request.ID);
- request.Icon = await _fileUploadService.UploadImageAsync(icon, UploadFolder.Member, request.ID);
- request.EmailVerifiedAt = (request.IsEmailVerified ? DateTime.UtcNow : null);
- request.AuthCertifiedAt = (request.IsAuthCertified ? DateTime.UtcNow : null);
- request.DeletedAt = (request.IsWithdraw ? DateTime.UtcNow : null);
- // 회원의 약관 및 알림 동의 정보 생성
- await _db.MemberApprove.AddAsync(new MemberApprove
- {
- MemberID = request.ID,
- IsReceiveSMS = false,
- IsReceiveEmail = false,
- IsReceiveNote = false,
- IsDisclosureInvest = false
- });
- await _db.SaveChangesAsync();
- string message = "회원이 등록되었습니다.";
- TempData["SuccessMessage"] = message;
- _logger.LogInformation(message);
- return Redirect("/Member/List");
- }
- catch (ArgumentException e)
- {
- TempData["ErrorMessages"] = e.Message;
- _logger.LogError(e, e.Message);
- return Write();
- }
- catch (Exception e)
- {
- TempData["ErrorMessages"] = e.Message;
- _logger.LogError(e, e.Message);
- return Write();
- }
- }
- [HttpGet("List/{id}/Edit")]
- public async Task<IActionResult> Edit(int id)
- {
- try
- {
- if (id <= 0)
- {
- throw new Exception("유효하지 않은 접근입니다.");
- }
- var member = await _db.Member.Where(m => m.ID == id).FirstOrDefaultAsync();
- if (member is null)
- {
- throw new Exception("회원 정보를 찾을 수 없습니다.");
- }
- ViewBag.MemberGrades = new SelectList(
- _db.MemberGrade.Where(c => c.IsActive).OrderByDescending(c => c.Order),
- "ID",
- "KorName",
- member.GradeID
- );
- return View(_EditViewPath, member);
- }
- catch (Exception e)
- {
- TempData["ErrorMessages"] = e.Message;
- _logger.LogError(e, e.Message);
- return Redirect("/Member/List");
- }
- }
- [HttpPost("List/Update")]
- public async Task<IActionResult> Update([FromForm] Models.Account.Member request, IFormFile? photo, IFormFile? icon, [FromForm] bool IsPhotoRemove = false, bool IsIconRemove = false)
- {
- try
- {
- if (!ModelState.IsValid)
- {
- throw new Exception("유효성 검사에 실패하였습니다.");
- }
- var member = await _db.Member.FirstOrDefaultAsync(c => c.ID == request.ID);
- if (member is null)
- {
- throw new Exception("회원 정보를 찾을 수 없습니다.");
- }
- if (request.FirstName != null || request.LastName != null)
- {
- member.FullName = $"{request.FirstName}{request.LastName}";
- }
- // 이메일 중복 확인
- if (await _db.Member.AnyAsync(c => c.Email == request.Email && c.ID != member.ID))
- {
- throw new ArgumentException("이미 등록된 이메일 주소입니다.");
- }
- // 별명 중복 확인
- if (await _db.Member.AnyAsync(c => c.Name == request.Name && c.ID != member.ID))
- {
- throw new ArgumentException("이미 등록된 별명입니다.");
- }
- // 비밀번호 변경
- if (!string.IsNullOrEmpty(request.Password))
- {
- member.Password = BCrypt.Net.BCrypt.HashPassword(request.Password);
- member.PasswordUpdatedAt = DateTime.UtcNow;
- }
- // 사진 저장
- if (IsPhotoRemove)
- {
- _fileUploadService.RemoveFile(request.Photo);
- member.Photo = null;
- }
- else if (photo is not null)
- {
- member.Photo = await _fileUploadService.UploadImageAsync(photo, UploadFolder.Grade, member.ID);
- }
- // 아이콘 저장
- if (IsIconRemove)
- {
- _fileUploadService.RemoveFile(request.Photo);
- member.Icon = null;
- }
- else if (icon is not null)
- {
- member.Icon = await _fileUploadService.UploadImageAsync(icon, UploadFolder.Grade, member.ID);
- }
- member.GradeID = request.GradeID;
- member.Email = request.Email;
- member.LastEmailChangedAt = (member.Email != request.Email ? DateTime.UtcNow : null);
- member.Name = request.Name;
- member.LastNameChangedAt = (member.Name != request.Name ? DateTime.UtcNow : null);
- member.FirstName = request.FirstName;
- member.LastName = request.LastName;
- member.Intro = request.Intro;
- member.Summary = request.Summary;
- member.Phone = request.Phone;
- member.Birthday = request.Birthday;
- member.Gender = request.Gender;
- member.EmailVerifiedAt = (request.IsEmailVerified && !member.IsEmailVerified && member.IsEmailVerified != request.IsEmailVerified ? DateTime.UtcNow : (request.IsEmailVerified ? member.EmailVerifiedAt : null));
- member.IsEmailVerified = request.IsEmailVerified;
- member.AuthCertifiedAt = (request.IsAuthCertified && !member.IsAuthCertified && member.IsAuthCertified != request.IsAuthCertified ? DateTime.UtcNow : (request.IsAuthCertified ? member.AuthCertifiedAt : null));
- member.IsAuthCertified = request.IsAuthCertified;
- member.IsDenied = request.IsDenied;
- member.IsAdmin = request.IsAdmin;
- member.DeletedAt = (request.IsWithdraw && !member.IsWithdraw && member.IsWithdraw != request.IsWithdraw ? DateTime.UtcNow : (request.IsWithdraw ? member.DeletedAt : null));
- member.IsWithdraw = request.IsWithdraw;
- member.UpdatedAt = DateTime.UtcNow;
- _db.Member.Update(member);
- int affectedRows = await _db.SaveChangesAsync();
- if (affectedRows <= 0)
- {
- throw new Exception("회원 수정 중 오류가 발생했습니다.");
- }
- string message = "회원 정보가 수정되었습니다.";
- TempData["SuccessMessage"] = message;
- _logger.LogInformation(message);
- return Redirect($"/Member/List/{request.ID}/Edit?{_queryString}");
- }
- catch (Exception e)
- {
- TempData["ErrorMessages"] = e.Message;
- _logger.LogError(e, e.Message);
- return await Edit(request.ID);
- }
- }
- [HttpGet("List/{id}/Delete")]
- public async Task<IActionResult> Delete(int id)
- {
- try
- {
- if (id <= 0)
- {
- throw new Exception("유효하지 않은 접근입니다.");
- }
- var isMember = await _db.Member.AnyAsync(c => c.ID == id);
- if (!isMember)
- {
- throw new Exception("회원 정보를 찾을 수 없습니다.");
- }
- var member = await _db.Member.FindAsync(id);
- _db.Member.Remove(member);
- int affectedRows = await _db.SaveChangesAsync();
- if (affectedRows <= 0)
- {
- throw new Exception("회원 삭제 중 오류가 발생했습니다.");
- }
- _fileUploadService.RemoveFile(member.Photo);
- _fileUploadService.RemoveFile(member.Icon);
- string message = "회원이 정상적으로 삭제되었습니다.";
- TempData["SuccessMessage"] = message;
- _logger.LogInformation(message);
- }
- catch (Exception e)
- {
- TempData["ErrorMessages"] = e.Message;
- _logger.LogError(e, e.Message);
- }
- return Redirect($"/Member/List?{_queryString}");
- }
- [HttpPost("List/Delete")]
- public async Task<IActionResult> Delete([FromForm] int[] ids)
- {
- try
- {
- if (ids == null || ids.Length <= 0)
- {
- throw new Exception("유효하지 않은 접근입니다.");
- }
- foreach (var id in ids)
- {
- var member = await _db.Member.FindAsync(id);
- if (member == null)
- {
- throw new Exception($"{id}번 회원을 찾을 수 없습니다.");
- }
- _db.Member.Remove(member);
- int affectedRows = await _db.SaveChangesAsync();
- if (affectedRows <= 0)
- {
- throw new Exception($"{id}번 회원 삭제 중 오류가 발생했습니다.");
- }
- _fileUploadService.RemoveFile(member.Photo);
- _fileUploadService.RemoveFile(member.Icon);
- }
- string message = $"{ids.Length}건의 회원이 삭제되었습니다.";
- TempData["SuccessMessage"] = message;
- _logger.LogInformation(message);
- }
- catch (Exception e)
- {
- TempData["ErrorMessages"] = e.Message;
- _logger.LogError(e, e.Message);
- }
- return Redirect($"/Member/List?{_queryString}");
- }
- [HttpGet("List/{id}/Approve")]
- public async Task<IActionResult> Approve(int id)
- {
- try
- {
- if (id <= 0)
- {
- throw new Exception("유효하지 않은 접근입니다.");
- }
- var memberApprove = await _db.MemberApprove.FindAsync(id);
- if (memberApprove is null)
- {
- throw new Exception("회원 알림 및 동의 정보를 찾을 수 없습니다.");
- }
- return View("~/Views/Member/List/Approve.cshtml", memberApprove);
- }
- catch (Exception e)
- {
- TempData["ErrorMessages"] = e.Message;
- _logger.LogError(e, e.Message);
- return Redirect("/Member/List");
- }
- }
- [HttpPost("List/Approve")]
- public async Task<IActionResult> Approve([FromForm] MemberApprove request)
- {
- try
- {
- if (!ModelState.IsValid)
- {
- throw new Exception("유효성 검사에 실패하였습니다.");
- }
- if (!await _db.MemberApprove.AnyAsync(c => c.MemberID == request.MemberID))
- {
- throw new ArgumentException("회원 알림 및 동의 정보를 찾을 수 없습니다.");
- }
- _db.MemberApprove.Update(request);
- int affectedRows = await _db.SaveChangesAsync();
- if (affectedRows <= 0)
- {
- throw new Exception("수정 중 오류가 발생했습니다.");
- }
- string message = "회원 알림 및 동의 정보가 수정되었습니다.";
- TempData["SuccessMessage"] = message;
- _logger.LogInformation(message);
- return Redirect("/Member/List");
- }
- catch (Exception e)
- {
- TempData["ErrorMessages"] = e.Message;
- _logger.LogError(e, e.Message);
- return await Approve(request.MemberID);
- }
- }
- }
- }
|