Add administrator editing

This commit is contained in:
2016-09-27 11:56:10 -04:00
parent 75b7c02979
commit 3caf0bd766
13 changed files with 207 additions and 59 deletions
@@ -2,7 +2,6 @@
using System.Threading.Tasks;
using System.Web.Mvc;
using AutoMapper;
using AutoMapper.QueryableExtensions;
using InventoryTraker.Web.Attributes;
using InventoryTraker.Web.Core;
using InventoryTraker.Web.Identity;
@@ -11,9 +10,10 @@ using Microsoft.AspNet.Identity;
namespace InventoryTraker.Web.Controllers
{
[Authorize(Roles = ApplicationRoleManager.AdminRoleName)]
public class UserController : ControllerBase
{
private readonly ApplicationUserManager _userManager;
private readonly ApplicationUserManager _userManager;
private readonly IMapper _mapper;
public UserController(ApplicationUserManager userManager, IMapper mapper)
@@ -29,13 +29,18 @@ namespace InventoryTraker.Web.Controllers
public JsonResult All()
{
var users =
_userManager
.Users
.ProjectTo<UserViewModel>(_mapper.ConfigurationProvider)
.OrderBy(u => u.UserName);
var users =
from u in _userManager.Users.ToList()
let ad = _userManager.GetRoles(u.Id).Contains(ApplicationRoleManager.AdminRoleName)
orderby u.UserName
select new UserViewModel
{
UserName = u.UserName,
Email = u.Email,
Administrator = ad
};
return BetterJson(users);
return BetterJson(users.ToList());
}
[ActionLog]
@@ -57,7 +62,17 @@ namespace InventoryTraker.Web.Controllers
if (!identityResult.Succeeded)
return GetErrorListJson(identityResult.Errors.ToArray());
return BetterJson(_mapper.Map<UserViewModel>(user));
user = _userManager.FindByEmail(form.Email);
if (form.Administrator)
{
var result = _userManager.AddToRole(user.Id, ApplicationRoleManager.AdminRoleName);
if (!result.Succeeded)
return GetErrorListJson(result.Errors.ToArray());
}
var userViewModel = _mapper.Map<UserViewModel>(user);
userViewModel.Administrator = _userManager.IsInRole(user.Id, ApplicationRoleManager.AdminRoleName);
return BetterJson(userViewModel);
}
[ActionLog]
@@ -79,12 +94,33 @@ namespace InventoryTraker.Web.Controllers
return GetErrorListJson(resetResult.Errors.ToArray());
}
var rolesForUser = _userManager.GetRoles(user.Id);
if (rolesForUser.Contains(ApplicationRoleManager.AdminRoleName) && !form.Administrator)
{
var currentUser = _userManager.FindById(User.Identity.GetUserId());
if (currentUser == user)
return GetErrorListJson("Cannot remove admin from yourself");
var result = _userManager.RemoveFromRole(user.Id, ApplicationRoleManager.AdminRoleName);
if (!result.Succeeded)
return GetErrorListJson(result.Errors.ToArray());
}
else if (!rolesForUser.Contains(ApplicationRoleManager.AdminRoleName) && form.Administrator)
{
var result = _userManager.AddToRole(user.Id, ApplicationRoleManager.AdminRoleName);
if (!result.Succeeded)
return GetErrorListJson(result.Errors.ToArray());
}
var identityResult = _userManager.Update(user);
if (!identityResult.Succeeded)
return GetErrorListJson(identityResult.Errors.ToArray());
return BetterJson(_mapper.Map<UserViewModel>(user));
var userViewModel = _mapper.Map<UserViewModel>(user);
userViewModel.Administrator = _userManager.IsInRole(user.Id, ApplicationRoleManager.AdminRoleName);
return BetterJson(userViewModel);
}
}
}
+2
View File
@@ -2,6 +2,7 @@
using System.Web.Mvc;
using System.Web.Optimization;
using System.Web.Routing;
using InventoryTraker.Web.Migrations;
namespace InventoryTraker.Web
{
@@ -14,6 +15,7 @@ namespace InventoryTraker.Web
BundleConfig.RegisterBundles(BundleTable.Bundles);
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
EFConfig.Initialize();
SeedData.AddAdminRole();
//SeedData.Init();
}
}
@@ -75,40 +75,68 @@ namespace InventoryTraker.Web.Helpers
var expression = ExpressionForInternal(property);
//Creates <div class="form-group has-feedback"
// form-group-validation="Name">
var formGroup = new HtmlTag("div")
.AddClasses("form-group", "has-feedback")
.Attr("form-group-validation", name);
var labelText = metadata.DisplayName ?? name.Humanize(LetterCasing.Title);
//Creates <label class="control-label" for="Name">Name</label>
var label = new HtmlTag("label")
.AddClass("control-label")
.Attr("for", name)
.Text(labelText);
var tagName = metadata.DataTypeName == "MultilineText"
? "textarea"
var tagName =
metadata.DataTypeName == "MultilineText"
? "textarea"
: "input";
var placeholder = metadata.Watermark ??
(labelText + "...");
//Creates <input ng-model="expression"
// class="form-control" name="Name" type="text" >
var input = new HtmlTag(tagName)
.AddClass("form-control")
.Attr("ng-model", expression)
.Attr("name", name)
.Attr("type", "text")
.Attr("placeholder", placeholder);
.Attr("name", name);
ApplyValidationToInput(input, metadata);
var formGroup = new HtmlTag("div");
return formGroup
.Append(label)
.Append(input);
if (metadata.ModelType != typeof(bool))
{
label.AddClass("control-label");
var placeholder = metadata.Watermark ??
labelText + "...";
input
.AddClass("form-control")
.Attr("type", "text")
.Attr("placeholder", placeholder);
ApplyValidationToInput(input, metadata);
//Creates <div class="form-group has-feedback"
// form-group-validation="Name">
formGroup
.AddClass("form-group")
.AddClass("has-feedback")
.Attr("form-group-validation", name)
.Append(label)
.Append(input);
}
else if (metadata.ModelType == typeof(bool))
{
label.AddClass("form-check-label");
input
.AddClass("form-check-input")
.Attr("type", "checkbox");
label.Text("")
.Append(input)
.AppendHtml("&nbsp;&nbsp;")
.Append(new HtmlTag("text").NoTag().Text(labelText));
formGroup
.AddClass("form-check")
.Append(label);
}
return formGroup;
}
private void ApplyValidationToInput(HtmlTag input, ModelMetadata metadata)
@@ -2,11 +2,21 @@ using System;
using System.Threading.Tasks;
using InventoryTraker.Web.Core;
using Microsoft.AspNet.Identity;
using Microsoft.AspNet.Identity.EntityFramework;
using Microsoft.AspNet.Identity.Owin;
using Microsoft.Owin.Security.DataProtection;
namespace InventoryTraker.Web.Identity
{
public class ApplicationRoleManager : RoleManager<IdentityRole>
{
public const string AdminRoleName = "Admin";
public ApplicationRoleManager(IRoleStore<IdentityRole, string> store) : base(store)
{
}
}
public class ApplicationUserManager : UserManager<User>
{
public ApplicationUserManager(IUserStore<User> store, IDataProtectionProvider dataProtectionProvider)
@@ -14,6 +14,34 @@ namespace InventoryTraker.Web.Migrations
{
public static class SeedData
{
public static void AddAdminRole()
{
using (var context = new AppDbContext())
AddAdminRole(context);
}
private static void AddAdminRole(AppDbContext context)
{
var manager = new ApplicationRoleManager(new RoleStore<IdentityRole>(context));
if (!manager.RoleExists(ApplicationRoleManager.AdminRoleName))
{
var result = manager.Create(new IdentityRole(ApplicationRoleManager.AdminRoleName));
}
// if no users are admins, make them all!
var adminRole = manager.Roles.First(r => r.Name == ApplicationRoleManager.AdminRoleName);
var userManager = new ApplicationUserManager(new UserStore<User>(context), null);
var admins = userManager.Users.Where(u => u.Roles.Any(r => r.RoleId == adminRole.Id));
if (!admins.Any())
{
foreach (var user in userManager.Users.ToList())
{
userManager.AddToRole(user.Id, ApplicationRoleManager.AdminRoleName);
}
}
}
public static void Init()
{
using (var context = new AppDbContext())
@@ -14,6 +14,9 @@ namespace InventoryTraker.Web.Models
[RegularExpression(@"[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,4}", ErrorMessage = "Must be an email address")]
public string Email { get; set; }
//[Required]
public bool Administrator { get; set; }
[DataType(DataType.Password)]
public string Password { get; set; }
@@ -16,6 +16,8 @@ namespace InventoryTraker.Web.Models
[RegularExpression(@"[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,4}", ErrorMessage = "Must be an email address")]
public string Email { get; set; }
public bool Administrator { get; set; }
public override string ToString()
{
return $"UserName: {UserName}, email: {Email}";
+30 -22
View File
@@ -2,32 +2,40 @@
<!DOCTYPE html>
<html lang="en" ng-app="InventoryTraker">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>@ViewBag.Title - InventoryTraker</title>
@Styles.Render("~/Content/all-styles")
@RenderSection("Styles", required: false)
<!-- HTML5 Shim and Respond.js IE8 support of HTML5 elements and media queries -->
<!-- WARNING: Respond.js doesn't work if you view the page via file:// -->
<!--[if lt IE 9]>
<script src="https://oss.maxcdn.com/libs/html5shiv/3.7.0/html5shiv.js"></script>
<script src="https://oss.maxcdn.com/libs/respond.js/1.4.2/respond.min.js"></script>
<![endif]-->
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>@ViewBag.Title - Inventory Traker</title>
@Styles.Render("~/Content/all-styles")
@RenderSection("Styles", false)
<!-- HTML5 Shim and Respond.js IE8 support of HTML5 elements and media queries -->
<!-- WARNING: Respond.js doesn't work if you view the page via file:// -->
<!--[if lt IE 9]>
<script src="https://oss.maxcdn.com/libs/html5shiv/3.7.0/html5shiv.js"></script>
<script src="https://oss.maxcdn.com/libs/respond.js/1.4.2/respond.min.js"></script>
<![endif]-->
</head>
<body>
<div id="wrapper" ng-cloak>
@(Request.IsAuthenticated ? Html.Partial("_Navigation") : Html.Partial("_NavigationNoAuth"))
<div id="page-wrapper">
<div class="container-fluid">
@RenderBody()
</div>
<div id="wrapper" ng-cloak>
@(Request.IsAuthenticated ? Html.Partial("_Navigation") : Html.Partial("_NavigationNoAuth"))
<div id="page-wrapper">
<div class="container-fluid">
@RenderBody()
</div>
<!-- /#page-wrapper -->
</div>
<!-- /#wrapper -->
@Scripts.Render("~/js/all-javascript")
@RenderSection("Scripts", required: false)
@if (Request.IsAuthenticated)
{
<footer class="footer hidden-print">
<div class="container">
<p>Inventory Traker &copy; 2016 Kolpack Software Consulting LLC</p>
</div>
</footer>
}
<!-- /#page-wrapper -->
</div>
<!-- /#wrapper -->
@Scripts.Render("~/js/all-javascript")
@RenderSection("Scripts", false)
</body>
</html>
@@ -1,4 +1,5 @@
<nav class="navbar navbar-inverse navbar-fixed-top" role="navigation">
@using InventoryTraker.Web.Identity
<nav class="navbar navbar-inverse navbar-fixed-top" role="navigation">
<!-- Brand and toggle get grouped for better mobile display -->
<div class="navbar-header">
<button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-ex1-collapse">
@@ -7,13 +8,16 @@
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="navbar-brand" href="~/">Inventory Traker</a>
<a class="navbar-brand" href="~/"><i class="fa fa-fw fa-cubes"></i> Inventory Traker</a>
</div>
<!-- Top Menu Items -->
<ul class="nav navbar-right top-nav">
<li>
<a href="@(Html.BuildUrlFromExpression<UserController>(c => c.Index()))"><i class="fa fa-fw fa-users"></i> Users</a>
</li>
@if (User.IsInRole(ApplicationRoleManager.AdminRoleName))
{
<li>
<a href="@(Html.BuildUrlFromExpression<UserController>(c => c.Index()))"><i class="fa fa-fw fa-users"></i> Users</a>
</li>
}
<li class="dropdown">
<a href="" class="dropdown-toggle" data-toggle="dropdown"><i class="fa fa-user"></i> @User.Identity.Name <b class="caret"></b></a>
<ul class="dropdown-menu">
@@ -1,6 +1,6 @@
<nav class="navbar navbar-inverse navbar-fixed-top" role="navigation">
<!-- Brand and toggle get grouped for better mobile display -->
<div class="navbar-header">
<a class="navbar-brand" href="~/">Inventory Traker</a>
<a class="navbar-brand" href="~/"><i class="fa fa-fw fa-cubes"></i> Inventory Traker</a>
</div>
</nav>
+22
View File
@@ -10,9 +10,31 @@ body {
margin-top: 0;
}
.footer {
color: #aaa;
text-align: center;
width: 100%;
/* Set the fixed height of the footer here */
height: 60px;
}
#page-wrapper {
padding-top: 50px;
min-height: 100%;
padding-bottom: 60px;
margin-bottom: -60px;
}
.navbar-brand i {
color:palegreen
}
.navbar-brand:link,
.navbar-brand:visited,
.navbar-brand:hover,
.navbar-brand:active {
font-weight: bolder;
color: #92B9BD;
}
.navbar.navbar-fixed-top {
@@ -4,6 +4,7 @@
<th class="control-column"></th>
<th>Name</th>
<th>Email</th>
<th>Administrator</th>
</tr>
</thead>
<tbody>
@@ -11,6 +12,10 @@
<td><a href="" ng-click="vm.edit(user)"><i class="fa fa-edit"></i></a></td>
<td>{{user.userName}}</td>
<td>{{user.email}}</td>
<td>
<i class="fa fa-check-square-o" ng-show="user.administrator"></i>
<i class="fa fa-square-o" ng-show="!user.administrator"></i>
</td>
</tr>
</tbody>
</table>
+2 -2
View File
@@ -36,8 +36,8 @@
function edit(existingUser, editedUser) {
return $http.post("/User/Edit", editedUser)
.success(function(user) {
angular.copy(user, existingUser);
.success(function(data) {
angular.copy(data, existingUser);
});
}
}