using Infrastructure.Application; using Infrastructure.Data; using Infrastructure.Domain; using Infrastructure.Extensions; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.Controllers; using Microsoft.AspNetCore.Mvc.Filters; using Microsoft.AspNetCore.Mvc.ModelBinding; using Microsoft.EntityFrameworkCore; using Newtonsoft.Json; using Newtonsoft.Json.Serialization; using System; using System.Collections.Generic; using System.Linq; namespace Infrastructure.Web.Mvc { [ApiExplorerSettings(IgnoreApi = false)] [ApiController] [Route("Admin/[controller]/[action]")] public class CrudController : BaseController where TEntity : BaseEntity where TSearchModel : PagedListModel { protected IRepository Repo { get; } public CrudController(IRepository repo) { this.Repo = repo; } [HttpGet] public virtual IActionResult Index(TSearchModel model) { if (model == null) { throw new ArgumentNullException(nameof(model)); } var query = this.Repo.ReadOnlyTable(); //if (model is ISoftDeleteEntity && !model.IsDeleted) //{ // query = query.Where(o => o.IsDeleted == null); //} query = this.Include(query); query = this.Query(model, query); model.TotalCount = query.Count(); model.List.AddRange(query.Skip(model.PageSize * (model.PageIndex - 1)) .Take(model.PageSize) .ToList() .Select(o => { var m = o.To(); this.ToDisplayModel(o, m); return m; }) .ToList()); ViewData["EntityTypeExt"] = typeof(TEntity); ViewData["ModelTypeExt"] = typeof(TDisplayModel); return Result(model); } [HttpGet] public virtual IActionResult Details(Guid id) { var query = this.Repo.ReadOnlyTable(); query = this.Include(query); var entity = query.FirstOrDefault(o => o.Id == id); var model = entity.To(); this.ToDisplayModel(entity, model); return Result(model); } [HttpGet] public virtual IActionResult Add() { var model = Activator.CreateInstance(); this.ToEditModel(null, model); return Result(model); } [HttpPost] public virtual IActionResult Add(TEditModel model) { if (ModelState.IsValid) { try { var entity = Activator.CreateInstance(); entity.From(model); this.ToEntity(model, entity); this.Repo.Add(entity); this.Repo.SaveChanges(); return RedirectTo(); } catch (DbUpdateException ex) { ex.PrintStack(); ModelState.AddModelError("", $"{ex.Message}{ex.InnerException?.Message}"); } } this.ToEditModel(null, model); return Result(model); } [HttpGet] public virtual IActionResult Edit(Guid id) { var query = this.Repo.ReadOnlyTable(); query = this.Include(query); var entity = query.FirstOrDefault(o => o.Id == id); var model = entity.To(); this.ToEditModel(entity, model); return Result(model); } [HttpPost] public virtual IActionResult Edit(TEditModel model) { var id = (Guid)model.GetType().GetProperty("Id").GetValue(model); var query = this.Repo.Table(); query = this.Include(query); var entity = query.FirstOrDefault(o => o.Id == id); if (ModelState.IsValid) { try { entity.From(model, skipReadonly: true); this.ToEntity(model, entity); this.Repo.SaveChanges(); return RedirectTo(); } catch (DbUpdateException ex) { ex.PrintStack(); ModelState.AddModelError("", ex.Message); } } this.ToEditModel(entity, model); return Result(model); } [HttpPost] public virtual IActionResult EditApi([FromBody] TEditModel model) { return this.Edit(model); } [HttpPost] public virtual IActionResult Remove(List list) { if (list == null) { throw new ArgumentNullException(nameof(list)); } try { foreach (var id in list) { var query = this.Repo.Table(); var entity = query.FirstOrDefault(o => o.Id == id); entity.IsDeleted = Guid.NewGuid().ToString(); this.Repo.SaveChanges(); } return RedirectTo(); } catch (DbUpdateException ex) { ex.PrintStack(); return RedirectTo(rawMesage: ex.Message); } } [HttpPost] public IActionResult Restore(List list) { if (list == null) { throw new ArgumentNullException(nameof(list)); } try { foreach (var id in list) { var query = this.Repo.Table(); var entity = query.FirstOrDefault(o => o.Id == id); entity.IsDeleted = null; this.Repo.SaveChanges(); } return Success(); } catch (DbUpdateException ex) { ex.PrintStack(); return RedirectTo(rawMesage: ex.Message); } } [HttpPost] public virtual IActionResult Delete(List list) { if (list == null) { throw new ArgumentNullException(nameof(list)); } try { foreach (var id in list) { var query = this.Repo.Table(); var entity = query.FirstOrDefault(o => o.Id == id); this.Repo.Delete(entity); this.Repo.SaveChanges(); } return RedirectTo(); } catch (DbUpdateException ex) { ex.PrintStack(); return RedirectTo(rawMesage: ex.Message); } } [ApiExplorerSettings(IgnoreApi = true)] public virtual IQueryable Include(IQueryable query) { return query; } [ApiExplorerSettings(IgnoreApi = true)] public virtual IQueryable Query(TSearchModel model, IQueryable query) { return query; } [ApiExplorerSettings(IgnoreApi = true)] public virtual void ToEditModel(TEntity entity, TEditModel model) { } [ApiExplorerSettings(IgnoreApi = true)] public virtual void ToDisplayModel(TEntity entity, TDisplayModel model) { } [ApiExplorerSettings(IgnoreApi = true)] public virtual void ToEntity(TEditModel model, TEntity entity) { } [ApiExplorerSettings(IgnoreApi = true)] public override void OnActionExecuting(ActionExecutingContext context) { if (context == null) { throw new ArgumentNullException(nameof(context)); } var name = (context.ActionDescriptor as ControllerActionDescriptor).ActionName; var permission = string.Empty; if (name == "Index") { permission = $"Read-{typeof(TEntity).Name}"; } else if (name == "Details") { permission = $"Read-{typeof(TEntity).Name}"; } else if (name == "Add") { permission = $"Add-{typeof(TEntity).Name}"; } else if (name == "Edit" || name == "Remove" || name == "Restore") { permission = $"Edit-{typeof(TEntity).Name}"; } else if (name == "Delete") { permission = $"Delete-{typeof(TEntity).Name}"; } if (!string.IsNullOrEmpty(permission)) { var returnUrl = context.HttpContext.Request.GetUrl(); if (!context.HttpContext.User.Identity.IsAuthenticated) { context.Result = new RedirectToActionResult("Login", "Account", new { area = "", returnUrl }); ; } else if (!context.HttpContext.User.IsInRole(permission)) { context.Result = new RedirectToActionResult("AccessDenied", "Account", new { area = "", returnUrl }); } } } [ApiExplorerSettings(IgnoreApi = true)] protected IActionResult Result(object model) { if (this.Request.Headers["accept"].ToString().Contains("json", StringComparison.OrdinalIgnoreCase)) { return Json(new { schema = this.GetJsonSchema(), model, errors = ModelState.Where(o => o.Value.ValidationState == ModelValidationState.Invalid), data = ViewData }, new JsonSerializerSettings { ContractResolver = new CamelCasePropertyNamesContractResolver() }); } return View(model); } [ApiExplorerSettings(IgnoreApi = true)] protected IActionResult Success() { if (this.Request.Headers["accept"].ToString().Contains("json", StringComparison.OrdinalIgnoreCase)) { return this.NoContent(); } return RedirectTo(); } } }