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.EntityFrameworkCore; using System; using System.Collections.Generic; using System.Linq; using System.Reflection; namespace Infrastructure.Web.Mvc { public class CrudController : BaseController where TEntity : BaseEntity { protected IRepository Repo { get; } private readonly ControllerScopeType? _scope; public CrudController(IRepository repo) { this.Repo = repo; this._scope = this.GetType().GetCustomAttribute()?.Scope; } [HttpGet] public virtual IActionResult Index(PagedListModel 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.EntityToModel(o,m); this.ToDisplayModel(o, m); return m; }) .ToList()); this.ToEditModel(null, model.Query); 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.EntityToModel(entity,model); 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 AddApi([FromBody] TEditModel model) { return this.Add(model); } [HttpPost] public virtual IActionResult EditApi([FromBody] TEditModel model) { return this.Edit(model); } [HttpPost] public virtual IActionResult DeleteApi([FromBody] List list) { return this.Delete(list); } [HttpPost] public virtual IActionResult RemoveApi([FromBody] List list) { return this.Remove(list); } [HttpPost] public IActionResult RestoreApi([FromBody] List list) { return this.Restore(list); } [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(); this.AfterEdit(entity,model); return this.Success(); } catch (Exception 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.EntityToModel(entity,model); 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.BeforeEdit(entity, model); this.Repo.SaveChanges(); this.AfterEdit(entity, model); return this.Success(); } catch (Exception ex) { ex.PrintStack(); ModelState.AddModelError("", ex.Message); } } this.EntityToModel(entity,model); this.ToEditModel(entity, model); return Result(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.Deleted = DateTimeOffset.UtcNow; this.Repo.SaveChanges(); } return Success(); } catch (Exception ex) { ex.PrintStack(); return Error(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.Deleted = null; this.Repo.SaveChanges(); } return Success(); } catch (Exception ex) { ex.PrintStack(); return Error(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(); } this.AfterDelete(list); return Success(); } catch (Exception ex) { ex.PrintStack(); return Error(ex.Message); } } [ApiExplorerSettings(IgnoreApi = true)] public virtual IQueryable Include(IQueryable query) { return query; } [ApiExplorerSettings(IgnoreApi = true)] public virtual IQueryable Query(PagedListModel model, IQueryable query) { return query; } [ApiExplorerSettings(IgnoreApi = true)] public virtual void EntityToModel(TEntity entity, TEditModel model) { } [ApiExplorerSettings(IgnoreApi = true)] public virtual void ToEditModel(TEntity entity, TEditModel model) { if (_scope == ControllerScopeType.Organ) { var organId = User.GetOrganId(); if (organId.HasValue) { typeof(TEditModel).GetProperty("OrganId")?.SetValue(model, organId); } } } [ApiExplorerSettings(IgnoreApi = true)] public virtual void ToEntity(TEditModel model, TEntity entity) { } [ApiExplorerSettings(IgnoreApi = true)] public virtual void ToDisplayModel(TEntity entity, TEditModel model) { } [ApiExplorerSettings(IgnoreApi = true)] public override void OnActionExecuting(ActionExecutingContext context) { if (context == null) { throw new ArgumentNullException(nameof(context)); } if(Assembly.GetEntryAssembly().GetName().Name== "IoTNode") { return; } var type = _scope.ToString(); var name = (context.ActionDescriptor as ControllerActionDescriptor).ActionName; var permission = string.Empty; if (name == "Index") { permission = $"Read-{_scope}-{typeof(TEntity).Name}"; } else if (name == "Details") { permission = $"Read-{_scope}-{typeof(TEntity).Name}"; } else if (name == "Add") { permission = $"Add-{_scope}-{typeof(TEntity).Name}"; } else if (name == "Edit" || name == "Remove" || name == "Restore") { permission = $"Edit-{_scope}-{typeof(TEntity).Name}"; } else if (name == "Delete") { permission = $"Delete-{_scope}-{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 }); } } ViewBag.ControllerScope = type; } [ApiExplorerSettings(IgnoreApi = true)] protected IActionResult Result(object model) { return Result(model); } [ApiExplorerSettings(IgnoreApi = true)] protected IActionResult Success() { if (this.IsJsonRequest()) { return this.NoContent(); } return RedirectTo(); } [ApiExplorerSettings(IgnoreApi = true)] protected IActionResult Error(string message) { if (this.IsJsonRequest()) { return this.Problem(message); } return RedirectTo(); } protected ControllerScopeType? GetScopeType() { return this.GetType().GetCustomAttribute()?.Scope; } [ApiExplorerSettings(IgnoreApi = true)] protected virtual void BeforeEdit(TEntity entity,TEditModel model) { } [ApiExplorerSettings(IgnoreApi = true)] protected virtual void AfterEdit(TEntity entity, TEditModel model) { } [ApiExplorerSettings(IgnoreApi = true)] protected virtual void AfterDelete(List list) { } } }