ItemController.cs 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350
  1. using System.Diagnostics;
  2. using Microsoft.AspNetCore.Authorization;
  3. using Microsoft.AspNetCore.Mvc;
  4. using Microsoft.EntityFrameworkCore;
  5. using Microsoft.AspNetCore.Mvc.Rendering;
  6. using Microsoft.AspNetCore.Mvc.Filters;
  7. using Microsoft.AspNetCore.WebUtilities;
  8. using bitforum.Models;
  9. using bitforum.Models.Page.Banner;
  10. using bitforum.Services;
  11. using bitforum.Helpers;
  12. using bitforum.Repository;
  13. using bitforum.Constants;
  14. namespace bitforum.Controllers.Page.Banner
  15. {
  16. [Authorize]
  17. [Route("Page/Banner")]
  18. public class ItemController : Controller
  19. {
  20. private readonly ILogger<ItemController> _logger;
  21. private readonly IFileUploadService _fileUploadService;
  22. private readonly IRedisRepository _redisRepository;
  23. private readonly DefaultDbContext _db;
  24. private readonly string _IndexViewPath = "~/Views/Page/Banner/Item/Index.cshtml";
  25. private readonly string _WriteViewPath = "~/Views/Page/Banner/Item/Write.cshtml";
  26. private readonly string _EditViewPath = "~/Views/Page/Banner/Item/Edit.cshtml";
  27. private string? _queryString = null;
  28. public ItemController(ILogger<ItemController> logger, IFileUploadService fileUploadService, IRedisRepository redisRepository, DefaultDbContext db)
  29. {
  30. _logger = logger;
  31. _fileUploadService = fileUploadService;
  32. _redisRepository = redisRepository;
  33. _db = db;
  34. }
  35. [ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]
  36. public IActionResult Error()
  37. {
  38. return View(new ErrorViewModel { RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier });
  39. }
  40. public override void OnActionExecuting(ActionExecutingContext context)
  41. {
  42. ViewBag.QueryString = _queryString = string.Join("&", QueryHelpers.ParseQuery(HttpContext.Request.QueryString.Value).Select(r => $"{r.Key}={string.Join(",", r.Value)}"));
  43. base.OnActionExecuting(context);
  44. }
  45. [HttpGet("Item/{positionID?}")]
  46. public IActionResult Index(int? positionID, [FromQuery] int page = 1)
  47. {
  48. ViewBag.positionID = positionID;
  49. // 위치 목록
  50. ViewBag.BannerPositions = _db.BannerPosition.Include(c => c.BannerItem).Where(c => c.IsActive).ToList();
  51. // 배너 목록
  52. var bannerItemQuery = _db.BannerItem.Include(c => c.BannerPosition).OrderBy(c => c.Order).AsQueryable();
  53. if (positionID.HasValue)
  54. {
  55. bannerItemQuery = bannerItemQuery.Where(c => c.PositionID == positionID);
  56. }
  57. var bannerItems = bannerItemQuery.ToList();
  58. var data = new List<object>();
  59. if (bannerItems.Count > 0)
  60. {
  61. foreach (var row in bannerItems)
  62. {
  63. string Expired = row switch
  64. {
  65. { StartAt: not null, EndAt: not null } => $"{row.StartAt.GetDateAt()} ~ {row.EndAt.GetDateAt()}",
  66. { StartAt: not null, EndAt: null } => $"{row.StartAt.GetDateAt()}",
  67. { StartAt: null, EndAt: not null } => $"~ {row.EndAt.GetDateAt()}",
  68. _ => "[무기한]"
  69. };
  70. var entry = new
  71. {
  72. row.ID,
  73. BannerPositionName = row.BannerPosition?.Subject,
  74. Expired,
  75. row.Subject,
  76. row.Image,
  77. row.Width,
  78. row.Height,
  79. row.Link,
  80. row.Order,
  81. IsActive = (row.IsActive ? 'Y' : 'N'),
  82. Views = row.Views.ToString("N0"),
  83. UpdatedAt = row.UpdatedAt.GetDateAt(),
  84. CreatedAt = row.CreatedAt.GetDateAt(),
  85. EditURL = $"/Page/Banner/Item/{row.ID}/Edit?{_queryString}",
  86. DeleteURL = $"/Page/Banner/Item/{row.ID}/Delete?{_queryString}"
  87. };
  88. data.Add(entry);
  89. }
  90. }
  91. ViewBag.Data = data;
  92. ViewBag.Total = (data?.Count ?? 0);
  93. ViewBag.Pagination = new Pagination(ViewBag.Total, page, 20, null);
  94. return View(_IndexViewPath);
  95. }
  96. [HttpGet("Item/Write")]
  97. public IActionResult Write()
  98. {
  99. ViewBag.BannerPositions = _db.BannerPosition.Where(c => c.IsActive).ToList();
  100. return View(_WriteViewPath);
  101. }
  102. [HttpPost("Item/Create")]
  103. public async Task<IActionResult> Create(BannerItem request, IFormFile? Image)
  104. {
  105. try
  106. {
  107. if (!ModelState.IsValid)
  108. {
  109. throw new Exception("유효성 검사에 실패하였습니다.");
  110. }
  111. if (request.PositionID <= 0 || !_db.BannerPosition.Any(c => c.ID == request.PositionID))
  112. {
  113. throw new Exception("유효한 위치를 선택하세요.");
  114. }
  115. // 이미지 저장
  116. request.Image = await _fileUploadService.UploadImageAsync(Image, UploadFolder.Banner);
  117. request.UpdatedAt = null;
  118. request.CreatedAt = DateTime.UtcNow;
  119. _db.BannerItem.Add(request);
  120. int affectedRows = await _db.SaveChangesAsync();
  121. if (affectedRows <= 0)
  122. {
  123. throw new Exception("배너 등록 중 오류가 발생했습니다.");
  124. }
  125. await _redisRepository.DeleteAsync(RedisConst.BannerKey);
  126. string message = "배너가 등록되었습니다.";
  127. TempData["SuccessMessage"] = message;
  128. _logger.LogInformation(message);
  129. return Redirect($"/Page/Banner/Item?{_queryString}");
  130. }
  131. catch (ArgumentException e)
  132. {
  133. TempData["ErrorMessages"] = e.Message;
  134. _logger.LogError(e, e.Message);
  135. return Write();
  136. }
  137. catch (Exception e)
  138. {
  139. TempData["ErrorMessages"] = e.Message;
  140. _logger.LogError(e, e.Message);
  141. return Write();
  142. }
  143. }
  144. [HttpGet("Item/{id}/Edit")]
  145. public async Task<IActionResult> Edit(int id)
  146. {
  147. try
  148. {
  149. if (id <= 0)
  150. {
  151. throw new Exception("유효하지 않은 접근입니다.");
  152. }
  153. var bannerItem = await _db.BannerItem.FirstAsync(c => c.ID == id);
  154. if (bannerItem is null)
  155. {
  156. throw new Exception("FAQ 정보를 찾을 수 없습니다.");
  157. }
  158. // 위치 목록
  159. ViewBag.BannerPositions = new SelectList(_db.BannerPosition.Where(c => c.IsActive).ToList(), "ID", "Subject", bannerItem.PositionID);
  160. return View(_EditViewPath, bannerItem);
  161. }
  162. catch (Exception e)
  163. {
  164. TempData["ErrorMessages"] = e.Message;
  165. _logger.LogError(e, e.Message);
  166. return Redirect($"/Page/Banner/Item?{_queryString}");
  167. }
  168. }
  169. [HttpPost("Item/Update")]
  170. public async Task<IActionResult> Update(BannerItem request, IFormFile? Image, [FromForm] bool IsImageRemove = false)
  171. {
  172. try
  173. {
  174. if (!ModelState.IsValid)
  175. {
  176. throw new Exception("유효성 검사에 실패하였습니다.");
  177. }
  178. if (request.PositionID <= 0 || !_db.BannerPosition.Any(c => c.ID == request.PositionID))
  179. {
  180. throw new Exception("유효한 분류를 선택하세요.");
  181. }
  182. if (request.EndAt < request.StartAt)
  183. {
  184. throw new Exception("사용 기간을 확인해주세요.");
  185. }
  186. var bannerItem = await _db.BannerItem.FirstAsync(c => c.ID == request.ID);
  187. if (bannerItem is null)
  188. {
  189. throw new Exception("배너 정보를 찾을 수 없습니다.");
  190. }
  191. // 이미지 저장
  192. if (IsImageRemove)
  193. {
  194. // 실제 파일 삭제
  195. _fileUploadService.RemoveFile(bannerItem.Image);
  196. bannerItem.Image = null;
  197. }
  198. else if (Image is not null)
  199. {
  200. bannerItem.Image = await _fileUploadService.UploadImageAsync(Image, UploadFolder.Banner);
  201. }
  202. bannerItem.PositionID = request.PositionID;
  203. bannerItem.Subject = request.Subject;
  204. bannerItem.Width = request.Width;
  205. bannerItem.Height = request.Height;
  206. bannerItem.Link = request.Link;
  207. bannerItem.Order = request.Order;
  208. bannerItem.IsActive = request.IsActive;
  209. bannerItem.StartAt = request.StartAt;
  210. bannerItem.EndAt = request.EndAt;
  211. bannerItem.UpdatedAt = DateTime.UtcNow;
  212. int affectedRows = await _db.SaveChangesAsync();
  213. if (affectedRows <= 0)
  214. {
  215. throw new Exception("배너 수정 중 오류가 발생했습니다.");
  216. }
  217. await _redisRepository.DeleteAsync(RedisConst.BannerKey);
  218. string message = "배너가 수정되었습니다.";
  219. TempData["SuccessMessage"] = message;
  220. _logger.LogInformation(message);
  221. return Redirect($"/Page/Banner/Item/{request.ID}/Edit?{_queryString}");
  222. }
  223. catch (Exception e)
  224. {
  225. TempData["ErrorMessages"] = e.Message;
  226. _logger.LogError(e, e.Message);
  227. return await Edit(request.ID);
  228. }
  229. }
  230. [HttpGet("Item/{id}/Delete")]
  231. public async Task<IActionResult> Delete(int id)
  232. {
  233. try
  234. {
  235. if (id <= 0)
  236. {
  237. throw new Exception("유효하지 않은 접근입니다.");
  238. }
  239. var bannerItem = await _db.BannerItem.FindAsync(id);
  240. if (bannerItem == null)
  241. {
  242. throw new Exception("배너 정보를 찾을 수 없습니다.");
  243. }
  244. _db.BannerItem.Remove(bannerItem);
  245. int affectedRows = await _db.SaveChangesAsync();
  246. if (affectedRows <= 0)
  247. {
  248. throw new Exception("배너 삭제 중 오류가 발생했습니다.");
  249. }
  250. _fileUploadService.RemoveFile(bannerItem.Image);
  251. await _redisRepository.DeleteAsync(RedisConst.BannerKey);
  252. string message = "배너가 삭제되었습니다.";
  253. TempData["SuccessMessage"] = message;
  254. _logger.LogInformation(message);
  255. }
  256. catch (Exception e)
  257. {
  258. TempData["ErrorMessages"] = e.Message;
  259. _logger.LogError(e, e.Message);
  260. }
  261. return Redirect($"/Page/Banner/Item?{_queryString}");
  262. }
  263. [HttpPost("Item/Delete")]
  264. public async Task<IActionResult> Delete([FromForm] int[] ids)
  265. {
  266. try
  267. {
  268. if (ids == null || ids.Length <= 0)
  269. {
  270. throw new Exception("유효하지 않은 접근입니다.");
  271. }
  272. foreach (var id in ids)
  273. {
  274. var bannerItem = await _db.BannerItem.FindAsync(id);
  275. if (bannerItem == null)
  276. {
  277. throw new Exception($"{id}번 배너 정보를 찾을 수 없습니다.");
  278. }
  279. _db.BannerItem.Remove(bannerItem);
  280. int affectedRows = await _db.SaveChangesAsync();
  281. if (affectedRows <= 0)
  282. {
  283. throw new Exception($"{id}번 배너 삭제 중 오류가 발생했습니다.");
  284. }
  285. _fileUploadService.RemoveFile(bannerItem.Image);
  286. await _redisRepository.DeleteAsync(RedisConst.BannerKey);
  287. }
  288. string message = $"{ids.Length}건의 배너가 삭제되었습니다.";
  289. TempData["SuccessMessage"] = message;
  290. _logger.LogInformation(message);
  291. }
  292. catch (Exception e)
  293. {
  294. TempData["ErrorMessages"] = e.Message;
  295. _logger.LogError(e, e.Message);
  296. }
  297. return Redirect($"/Page/Banner/Item?{_queryString}");
  298. }
  299. }
  300. }