EnVisageOnline/Main-RMO/Source/EnVisage/Controllers/RoleController.cs

667 lines
27 KiB
C#

using System;
using System.Collections.Generic;
//using System.Data;
using System.Data.Entity;
using System.Linq;
using System.Net;
using System.Web;
using System.Web.Mvc;
using EnVisage;
using EnVisage.Code;
using EnVisage.Code.BLL;
using EnVisage.Models;
using jQuery.DataTables.Mvc;
using System.Collections.ObjectModel;
using EnVisage.App_Start;
using EnVisage.Code.HtmlHelpers;
using Microsoft.AspNet.Identity;
using EnVisage.Code.Cache;
namespace EnVisage.Controllers
{
[Authorize]
public class RoleController : BaseController
{
// GET: /Role/
[HttpGet]
[AreaSecurityAttribute(area = Areas.Roles, level = AccessLevel.Read)]
public ActionResult Index()
{
if (!SecurityManager.CheckSecurityObjectPermission(Areas.Roles, AccessLevel.Read))
return Redirect("/");
return View(DbContext.AspNetRoles.ToList());
}
/// <summary>
/// Returns JSON user list with filters and sort for jQuery DataTables
/// </summary>
[HttpPost]
[AreaSecurityAttribute(area = Areas.Roles, level = AccessLevel.Read)]
public JsonResult Index(JQueryDataTablesModel jQueryDataTablesModel)
{
int totalRecordCount;
int searchRecordCount;
var users = GetRoles(startIndex: jQueryDataTablesModel.iDisplayStart,
pageSize: jQueryDataTablesModel.iDisplayLength, sortedColumns: jQueryDataTablesModel.GetSortedColumns(),
totalRecordCount: out totalRecordCount, searchRecordCount: out searchRecordCount, searchString: jQueryDataTablesModel.sSearch);
return this.DataTablesJson(items: users,
totalRecords: totalRecordCount,
totalDisplayRecords: searchRecordCount,
sEcho: jQueryDataTablesModel.sEcho);
}
private IEnumerable<RoleModel> GetRoles(int startIndex,
int pageSize,
IEnumerable<SortedColumn> sortedColumns,
out int totalRecordCount,
out int searchRecordCount,
string searchString)
{
var query = from c in DbContext.AspNetRoles select new {
Id = c.Id,
Name = c.Name,
UsersCount = c.AspNetUsers.Count};
//filter
if (!string.IsNullOrWhiteSpace(searchString))
{
query = query.Where(c => c.Name.ToLower().Contains(searchString.ToLower()));
}
//sort
foreach (var sortedColumn in sortedColumns)
{
switch (sortedColumn.PropertyName)
{
case "Id":
if (sortedColumn.Direction == SortingDirection.Ascending)
query = query.OrderBy(c => c.Id);
else
query = query.OrderByDescending(c => c.Id);
break;
case "AspNetUsersCount":
if (sortedColumn.Direction == SortingDirection.Ascending)
query = query.OrderBy(c => c.UsersCount);
else
query = query.OrderByDescending(c => c.UsersCount);
break;
default:
if (sortedColumn.Direction == SortingDirection.Ascending)
query = query.OrderBy(c => c.Name);
else
query = query.OrderByDescending(c => c.Name);
break;
}
}
totalRecordCount = DbContext.AspNetRoles.Count();
try
{
searchRecordCount = query.Count();
}
catch (Exception ex)
{
LogException(ex);
throw;
}
searchRecordCount = query.Count();
return
query.Skip(startIndex)
.Take(pageSize)
.ToList()
.Select(t => new RoleModel { Id = new Guid(t.Id), Name = t.Name, AspNetUsersCount = t.UsersCount});
}
[HttpGet]
[AreaSecurityAttribute(area = Areas.Roles, level = AccessLevel.Write)]
public ActionResult Create()
{
var model = new RoleModel();
return View(model);
}
[HttpPost]
[ValidateAntiForgeryToken]
[AreaSecurityAttribute(area = Areas.Roles, level = AccessLevel.Write)]
public ActionResult Create(RoleModel model)
{
if (ContentLocker.IsLock("Role", model.Id.ToString(), User.Identity.Name))
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
model.TrimStringProperties();
if (ModelState.IsValid)
{
try
{
var manager = new RoleManager(DbContext);
manager.Save(model);
DbContext.SaveChanges();
ContentLocker.RemoveLock("Role", model.Id.ToString(), User.Identity.Name);
return RedirectToAction("Index");
}
catch (BLLException blEx) // handle any system specific error
{
// display error message if required
if (blEx.DisplayError)
ModelState.AddModelError(string.Empty, blEx.Message);
else // if display not requried then display modal form with general error message
{
LogException(blEx);
SetErrorScript();
}
}
catch (Exception exception) // handle any unexpected error
{
LogException(exception);
SetErrorScript();
}
}
// return empty model with validation messages (if any)
return View(model);
}
// GET: /Role/Edit/5
[HttpGet]
[AreaSecurityAttribute(area = Areas.Roles, level = AccessLevel.Write)]
public ActionResult Edit(Guid? id)
{
var model = new RoleModel();
if (id.HasValue)
{
try
{
var manager = new RoleManager(DbContext);
model = (RoleModel)manager.Load(id) ?? new RoleModel();
}
catch (BLLException blEx)
{
if (blEx.DisplayError)
SetErrorScript(message: blEx.Message);
else
{
LogException(blEx);
SetErrorScript();
}
}
catch (Exception exception)
{
LogException(exception);
SetErrorScript();
}
}
return View(model);
}
// POST: /Role/Edit/5
// To protect from overposting attacks, please enable the specific properties you want to bind to, for
// more details see http://go.microsoft.com/fwlink/?LinkId=317598.
[HttpPost]
[ValidateAntiForgeryToken]
[AreaSecurityAttribute(area = Areas.Roles, level = AccessLevel.Write)]
//public ActionResult Edit(RoleModel model, string[] projectlistread, string[] projectlistwrite, string[] areasread, string[] areaswrite)
public ActionResult Edit(EditPermissionModel editrole)
{
RoleModel model = editrole.rolemodel;
ProjectTreeModel projecttree = editrole.projecttree;
model.TrimStringProperties();
//ENV-746 START
//var isNewRole = Guid.Empty.Equals(model.Id);
var isNewRole = model.isNew;
//ENV-746 END
if (projecttree.ProjectList == null) projecttree.ProjectList= new List<ProjectPermission>();
if (projecttree.AreaList == null) projecttree.AreaList=new List<AreaPermission>();
if (!isNewRole && ContentLocker.IsLock("Role", model.Id.ToString(), User.Identity.Name))
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
if (ModelState.IsValid)
{
var context = new EnVisageEntities();
if (isNewRole)
{
try
{
var manager = new RoleManager(context);
manager.Save(model);
context.SaveChanges();
}
catch (BLLException blEx) // handle any system specific error
{
// display error message if required
if (blEx.DisplayError)
ModelState.AddModelError(string.Empty, blEx.Message);
else // if display not requried then display modal form with general error message
{
LogException(blEx);
SetErrorScript();
}
}
catch (Exception exception) // handle any unexpected error
{
LogException(exception);
SetErrorScript();
}
}
#region Save Projects
// TODO: refactoring required. we need to move saving of referenced objects under the try-catch block and use single SQL transaction to save data
var permissions = (from pr in context.ProjectAccesses
where pr.PrincipalId == model.Id
select pr)
.ToDictionary(userProjectAccess => new Tuple<Guid, Guid>(userProjectAccess.PrincipalId, userProjectAccess.ProjectId));
var projects = (from pr in context.Projects
orderby pr.Name
select pr).ToList();
//if (projectlist != null)
foreach (var project in projects)
{
var UIProjectList = from m in projecttree.ProjectList
where m.id == project.Id.ToString()
select m;
var UIProject = UIProjectList.FirstOrDefault();
if (UIProject != null &&( UIProject.p.read || UIProject.p.write))
{
var pa = (from pr in context.ProjectAccesses
where pr.PrincipalId == model.Id && pr.ProjectId == project.Id
select pr).FirstOrDefault();
if (pa == null)
{
var newpa = new ProjectAccess
{
PrincipalId = model.Id,
ProjectId = project.Id,
Read = (int)(UIProject.p.read ? Permission.Allow : Permission.Deny),
Write = (int)(UIProject.p.write ? Permission.Allow : Permission.Deny)
};
permissions.Add(new Tuple<Guid, Guid>(model.Id, project.Id), newpa);
context.ProjectAccesses.Add(newpa);
if (project.ParentProjectId.HasValue)
{
if (!permissions.ContainsKey(new Tuple<Guid, Guid>(model.Id, project.ParentProjectId.Value)))
{
var parentPA = new ProjectAccess
{
PrincipalId = model.Id,
ProjectId = project.ParentProjectId.Value,
Read = 1,
Write = 1
};
context.ProjectAccesses.Add(parentPA);
permissions.Add(new Tuple<Guid, Guid>(model.Id, project.ParentProjectId.Value), parentPA);
}
else
{
var parentPA = permissions.ContainsKey(new Tuple<Guid, Guid>(model.Id, project.ParentProjectId.Value))
? permissions.FirstOrDefault(t => t.Key.Item1 == model.Id && t.Key.Item2 == project.ParentProjectId.Value).Value
: null;
if (parentPA != null && context.Entry(parentPA).State == EntityState.Unchanged || context.Entry(parentPA).State == EntityState.Modified)
{
parentPA.Read = 1;
parentPA.Write = 1;
context.Entry(parentPA).State = EntityState.Modified;
}
}
}
//context.SaveChanges();
}
else
{
pa.Read = (int)(UIProject.p.read ? Permission.Allow : Permission.Deny);
pa.Write = (int)(UIProject.p.write ? Permission.Allow : Permission.Deny);
//context.SaveChanges();
if (project.ParentProjectId.HasValue)
{
if (!permissions.ContainsKey(new Tuple<Guid, Guid>(model.Id, project.ParentProjectId.Value)))
{
var parentPA = new ProjectAccess
{
PrincipalId = model.Id,
ProjectId = project.ParentProjectId.Value,
Read = 1,
Write = 1
};
context.ProjectAccesses.Add(parentPA);
permissions.Add(new Tuple<Guid, Guid>(model.Id, project.ParentProjectId.Value), parentPA);
}
else
{
var parentPA = permissions.ContainsKey(new Tuple<Guid, Guid>(model.Id, project.ParentProjectId.Value))
? permissions.FirstOrDefault(t => t.Key.Item1 == model.Id && t.Key.Item2 == project.ParentProjectId.Value).Value
: null;
if (parentPA != null && context.Entry(parentPA).State == EntityState.Unchanged || context.Entry(parentPA).State == EntityState.Modified)
{
parentPA.Read = 1;
parentPA.Write = 1;
context.Entry(parentPA).State = EntityState.Modified;
}
}
}
}
}
else
{
var pa = (from pr in context.ProjectAccesses
where pr.PrincipalId == model.Id && pr.ProjectId == project.Id
select pr).FirstOrDefault();
if (pa != null)
{
context.ProjectAccesses.Remove(pa);
//context.SaveChanges();
}
if (project.ParentProjectId.HasValue)
{
var projectParts =
projects.Where(t => t.ParentProjectId == project.ParentProjectId.Value).Select(t => t.Id).ToArray();
var otherPartsAccess = permissions.Where(t => projectParts.Contains(t.Key.Item2) && t.Key.Item2 != project.ParentProjectId.Value);
if (!otherPartsAccess.Any())
{
var parentPA = permissions.ContainsKey(new Tuple<Guid, Guid>(model.Id, project.ParentProjectId.Value))
? permissions.FirstOrDefault(t => t.Key.Item1 == model.Id && t.Key.Item2 == project.ParentProjectId.Value).Value
: null;
if (parentPA != null && (context.Entry(parentPA).State == EntityState.Unchanged ||
context.Entry(parentPA).State == EntityState.Modified))
{
context.ProjectAccesses.Remove(parentPA);
permissions.Remove(new Tuple<Guid, Guid>(model.Id, project.ParentProjectId.Value));
}
}
}
}
}
context.SaveChanges();
new ProjectAccessCache().Invalidate();
#endregion
#region Save Areas
// TODO: refactoring required. we need to move saving of referenced objects under the try-catch block and use single SQL transaction to save data
SecurityAreasCache securityAreasCache = new SecurityAreasCache();
var areas = Enum.GetValues(typeof(Areas)).Cast<Areas>();
foreach (var area in areas)
{
var UIAreaList = from m in projecttree.AreaList
where m.id == area.ToString()
select m;
var UIArea = UIAreaList.FirstOrDefault();
//if ((projecttree.AreasRead != null && projecttree.AreasRead.Contains(area.ToString())) || (projecttree.AreasWrite != null && projecttree.AreasWrite.Contains(area.ToString())))
if (UIArea != null && (UIArea.p.read || UIArea.p.write))
{
var pa = (from pr in context.Securities
where pr.PrincipalId == model.Id && pr.SecurityObject == area.ToString()
select pr).FirstOrDefault();
if (pa == null)
{
var newpa = new Security();
newpa.PrincipalId = model.Id;
newpa.SecurityObject = area.ToString();
newpa.Read = (int)(UIArea.p.read ? Permission.Allow : Permission.Deny); ;
newpa.Write = (int)(UIArea.p.write ? Permission.Allow : Permission.Deny);
context.Securities.Add(newpa);
// TODO: burn in hell who do transaction commit after each object change
context.SaveChanges();
}
else
{
pa.Read = (int)(UIArea.p.read ? Permission.Allow : Permission.Deny);
pa.Write = (int)(UIArea.p.write ? Permission.Allow : Permission.Deny);
// TODO: burn in hell who do transaction commit after each object change
context.SaveChanges();
}
}
else
{
var pa = (from pr in context.Securities
where pr.PrincipalId == model.Id && pr.SecurityObject == area.ToString()
select pr).FirstOrDefault();
if (pa != null)
{
context.Securities.Remove(pa);
// TODO: burn in hell who do transaction commit after each object change
context.SaveChanges();
}
}
}
securityAreasCache.Invalidate();
#endregion
if (!isNewRole)
{
//var aspnetrole = DbContext.AspNetRoles.Find(model.Id.ToString());
//if (aspnetrole == null)
// return HttpNotFound();
//model.CopyTo(aspnetrole);
//DbContext.Entry(aspnetrole).State = System.Data.Entity.EntityState.Modified;
var manager = new RoleManager(context);
manager.Save(model);
context.SaveChanges();
ContentLocker.RemoveLock("Role", model.Id.ToString(), User.Identity.Name);
}
}
var redirectUrl = new UrlHelper(Request.RequestContext).Action("Index");
return Json(new { Url = redirectUrl });
// return RedirectToAction("Index");
}
// GET: /Role/Delete/5
[HttpGet]
[AreaSecurityAttribute(area = Areas.Roles, level = AccessLevel.Write)]
public ActionResult Delete(Guid? id)
{
if (id == null || id == Guid.Empty)
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
var model = new RoleModel();
try
{
var manager = new RoleManager(DbContext);
model = (RoleModel)manager.Load(id);
if (model == null)
return HttpNotFound();
if (model.AspNetUsersCount > 0)
return new HttpStatusCodeResult(HttpStatusCode.BadRequest,
"Role has Users assigned and could not be deleted");
}
catch (BLLException blEx)
{
if (blEx.DisplayError)
SetErrorScript(message: blEx.Message);
else
{
LogException(blEx);
SetErrorScript();
}
}
catch (Exception exception)
{
LogException(exception);
SetErrorScript();
}
return View(model);
}
// POST: /Role/Delete/5
[HttpPost]
[ValidateAntiForgeryToken]
[AreaSecurityAttribute(area = Areas.Roles, level = AccessLevel.Write)]
public ActionResult Delete(RoleModel model)
{
try
{
if (ContentLocker.IsLock("Role", model.Id.ToString(), User.Identity.Name))
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
var dbObj = DbContext.AspNetRoles.Find(model.Id.ToString());
if (dbObj == null)
return HttpNotFound();
if (dbObj.AspNetUsers.Count > 0)
return new HttpStatusCodeResult(HttpStatusCode.BadRequest,
"Role has Users assigned and could not be deleted");
DbContext.AspNetRoles.Remove(dbObj);
DbContext.SaveChanges();
ContentLocker.RemoveLock("Role", dbObj.Id, User.Identity.Name);
return RedirectToAction("Index");
}
catch (BLLException blEx) // handle any system specific error
{
// display error message if required
if (blEx.DisplayError)
ModelState.AddModelError(string.Empty, blEx.Message);
else // if display not requried then display modal form with general error message
{
LogException(blEx);
SetErrorScript();
}
}
catch (Exception exception) // handle any unexpected error
{
LogException(exception);
SetErrorScript();
}
return View(model);
}
protected class ListItem
{
public Guid Id { get; set; }
public string Name { get; set; }
}
protected class ProjectListItem : ListItem
{
public int Read { get;set;}
public int Write {get; set;}
}
protected class ClientListItem : ListItem
{
public List<ProjectListItem> Projects {get ;set;}
}
protected class CompanyListItem : ListItem
{
public List<ClientListItem> Clients { get; set; }
}
[HttpPost]
public JsonResult GetProjectAccessTree(Guid? roleId)
{
var result = new List<CompanyListItem>();
var companies = DbContext.Companies.Select(x => new { Id = x.Id, Name = x.Name, Clients = x.Company2Client }).ToList();
var mainProjects = DbContext.Projects.Where(t => t.HasChildren)
.Select(t => new { t.Id, t.Name })
.ToDictionary(key => key.Id, elem => elem.Name);
var paCache = new ProjectAccessCache();
foreach (var company in companies)
{
var clientsList = new List<ClientListItem>();
foreach(var client in company.Clients.Select(x => x.Client).Distinct())
{
if (result.Any(x => x.Clients.Any(c => c.Id == client.Id)))
continue;
var projList = new List<ProjectListItem>();
foreach (var project in client.Projects.OrderBy(p => p.ParentProjectId).ThenBy(p => p.Name))
{
if (project.HasChildren) // do not display main project, but only his parts
continue;
int read = 0, write = 0;
if (roleId != null)
{
var perm = paCache.Value.FirstOrDefault(x => x.PrincipalId == roleId && x.ProjectId == project.Id);
if (perm != null)
{
read = perm.Read;
write = perm.Write;
}
}
projList.Add(new ProjectListItem
{
Id = project.Id,
Name = !project.ParentProjectId.HasValue || !mainProjects.ContainsKey(project.ParentProjectId.Value)
? project.Name
: string.Format("{1}: {0}", mainProjects[project.ParentProjectId.Value], project.Name),
Read = read,
Write = write
});
}
clientsList.Add(new ClientListItem
{
Id = client.Id,
Name = client.Name,
Projects = projList
});
}
result.Add(new CompanyListItem
{
Id = company.Id,
Name = company.Name,
Clients = clientsList
});
}
return Json(result);
}
//env-648 start
#region CustomValidation
[HttpPost]
public JsonResult IsUnique(string Name,Guid Id)
{
bool result = false;
if (Name == null)
{
result = false;
}
else
{
result = CheckDbForUniqueness(Name,Id);
}
return Json(result);
}
private bool CheckDbForUniqueness(string roleName, Guid Id)
{
var query = from c in DbContext.AspNetRoles
select new
{
Id = c.Id,
Name = c.Name,
UsersCount = c.AspNetUsers.Count
};
if (Id == Guid.Empty)
query = query.Where(c => c.Name.ToLower() == (roleName.ToLower()));
else
query = query.Where(c => (c.Name.ToLower() == roleName.ToLower() && c.Id != Id.ToString()));
return !(query.Count() > 0);
}
#endregion
//env-648 end
}
}