From 2ec2a752cd33421ece3e78f27f53ef72c22abac2 Mon Sep 17 00:00:00 2001 From: James Kolpack Date: Mon, 31 Dec 2012 14:49:41 -0500 Subject: [PATCH] Admin auth functionally complete --- Web/Content/Site.css | 6 -- Web/Controllers/AccountController.cs | 31 +++++--- Web/Controllers/CreateLogController.cs | 13 +++- Web/Controllers/UserController.cs | 67 ++++++++++++++++- Web/Controllers/VehicleController.cs | 3 +- Web/DAL/CodeFirstMembershipProvider.cs | 4 +- Web/DAL/DataService.cs | 2 + Web/DAL/UserAccountDisabledException.cs | 8 +++ Web/DAL/UserLockedOutException.cs | 8 +++ Web/Scripts/Shared/Site.js | 3 +- Web/Utility/CustomExtensions.cs | 7 -- Web/ViewModels/User/CreateUserViewModel.cs | 3 + Web/Views/Account/Login.cshtml | 4 +- Web/Views/CreateLog/Index.cshtml | 2 + Web/Views/CreateLog/Success.cshtml | 17 ----- Web/Views/Log/Create.cshtml | 2 + Web/Views/Log/Delete.cshtml | 2 + Web/Views/Log/Details.cshtml | 3 - Web/Views/Log/Edit.cshtml | 2 + Web/Views/Log/MonthlyEmployeeMileage.cshtml | 2 + Web/Views/Log/MonthlyVehicleMileage.cshtml | 2 + Web/Views/Shared/_StatusMessage.cshtml | 6 +- Web/Views/User/Details.cshtml | 80 +++++++++++++++++++-- Web/Views/User/Edit.cshtml | 4 +- Web/Views/User/Index.cshtml | 33 ++++----- Web/Views/User/SetPassword.cshtml | 2 + Web/Views/User/_UserStatusLabels.cshtml | 15 ++++ Web/Views/Vehicle/Create.cshtml | 2 + Web/Views/Vehicle/Edit.cshtml | 2 + Web/Web.csproj | 4 +- 30 files changed, 260 insertions(+), 79 deletions(-) create mode 100644 Web/DAL/UserAccountDisabledException.cs create mode 100644 Web/DAL/UserLockedOutException.cs delete mode 100644 Web/Views/CreateLog/Success.cshtml create mode 100644 Web/Views/User/_UserStatusLabels.cshtml diff --git a/Web/Content/Site.css b/Web/Content/Site.css index a2c973d..048c793 100644 --- a/Web/Content/Site.css +++ b/Web/Content/Site.css @@ -6,7 +6,6 @@ body { .center-content { display: block; max-width: 400px; - padding: 10px; margin: 0 auto 20px; } @@ -78,10 +77,6 @@ footer { padding: 4px; } -.alert .close { - position: static; -} - .qtip-content dt { line-height: 10px; width: 110px; @@ -211,7 +206,6 @@ dl.inline { } .center-content { - padding: 5px; margin: 0 auto 10px; } diff --git a/Web/Controllers/AccountController.cs b/Web/Controllers/AccountController.cs index 87ba7c7..3943673 100644 --- a/Web/Controllers/AccountController.cs +++ b/Web/Controllers/AccountController.cs @@ -1,6 +1,7 @@ using System; using System.Web.Mvc; using System.Web.Security; +using MileageTraker.Web.DAL; using MileageTraker.Web.ViewModels.Account; namespace MileageTraker.Web.Controllers @@ -22,17 +23,28 @@ namespace MileageTraker.Web.Controllers { if (ModelState.IsValid) { - var success = Membership.ValidateUser(model.Username, model.Password); - if (success) + try { - FormsAuthentication.SetAuthCookie(model.Username, model.RememberMe); - TempData["StatusMessage"] = "Logged in as " + model.Username; - return RedirectToLocal(returnUrl); + var success = Membership.ValidateUser(model.Username, model.Password); + if (success) + { + FormsAuthentication.SetAuthCookie(model.Username, model.RememberMe); + TempData["StatusMessage"] = "Logged in as " + model.Username; + return RedirectToLocal(returnUrl); + } + ModelState.AddModelError("", "The user name or password provided is incorrect."); + } + catch (UserAccountDisabledException) + { + ModelState.AddModelError("", "Account is disabled for " + model.Username + "."); + } + catch (UserLockedOutException) + { + ModelState.AddModelError("", "Too many failed password attempts for " + model.Username + ". Account is locked."); } } // If we got this far, something failed, redisplay form - ModelState.AddModelError("", "The user name or password provided is incorrect."); return View(model); } @@ -40,9 +52,10 @@ namespace MileageTraker.Web.Controllers [ValidateAntiForgeryToken] public ActionResult LogOff() { + TempData["StatusMessage"] = User.Identity.Name + " logged off"; + FormsAuthentication.SignOut(); - TempData["StatusMessage"] = "Logged off"; return RedirectToAction("Index", "CreateLog"); } @@ -81,7 +94,7 @@ namespace MileageTraker.Web.Controllers ViewBag.StatusMessage = message == ManageMessageId.ChangePasswordSuccess ? "Your password has been changed." : message == ManageMessageId.SetPasswordSuccess ? "Your password has been set." - : ""; + : null; ViewBag.ReturnUrl = Url.Action("Manage"); return View(); } @@ -108,7 +121,7 @@ namespace MileageTraker.Web.Controllers if (changePasswordSucceeded) { - TempData["StatusMessage"] = ManageMessageId.ChangePasswordSuccess; + TempData["StatusMessage"] = "Your password has been changed."; return RedirectToAction("Manage"); } ModelState.AddModelError("", "The current password is incorrect or the new password is invalid."); diff --git a/Web/Controllers/CreateLogController.cs b/Web/Controllers/CreateLogController.cs index 4dbe450..888838b 100644 --- a/Web/Controllers/CreateLogController.cs +++ b/Web/Controllers/CreateLogController.cs @@ -45,7 +45,7 @@ namespace MileageTraker.Web.Controllers [HttpParamAction] [HttpPost] [ActionLog] - public ViewResult Confirm(CreateLogViewModel model) + public ActionResult Confirm(CreateLogViewModel model) { if (ModelState.IsValid) { @@ -59,7 +59,16 @@ namespace MileageTraker.Web.Controllers log.UserHostAddress = HttpContext.Request.UserHostAddress; log.UserAgent = HttpContext.Request.UserAgent; DataService.AddLog(log); - return View("Success", model); + TempData["StatusMessage-Type"] = "alert-success"; + TempData["StatusMessage"] = + @"You've successfully created an entry + for " + model.EmployeeName + @" + traveling to " + model.CityName + @" + on " + model.Date.ToShortDateString() + @" + in Vehicle Id " + model.VehicleId + @" + ending in " + model.EndOdometer + @" + miles on the odometer."; + return RedirectToAction("Index"); } return View("Index", model); diff --git a/Web/Controllers/UserController.cs b/Web/Controllers/UserController.cs index 8e4a69a..684a2d2 100644 --- a/Web/Controllers/UserController.cs +++ b/Web/Controllers/UserController.cs @@ -24,6 +24,18 @@ namespace MileageTraker.Web.Controllers return View(DataService.GetUser(id)); } + public JsonResult UsernameAvailable(string username) + { + var user = DataService.FindUserByUsername(username); + return Json(user == null, JsonRequestBehavior.AllowGet); + } + + public JsonResult EmailAvailable(string email) + { + var user = DataService.FindUserByEmail(email); + return Json(user == null, JsonRequestBehavior.AllowGet); + } + public ActionResult Create() { var vm = new CreateUserViewModel @@ -111,7 +123,7 @@ namespace MileageTraker.Web.Controllers } TempData["StatusMessage"] = "Changes saved for " + user.Username; - return RedirectToAction("Index"); + return RedirectToAction("Details", new { id = viewModel.UserId}); } return View(viewModel); } @@ -132,7 +144,6 @@ namespace MileageTraker.Web.Controllers { if (ModelState.IsValid) { - // ChangePassword will throw an exception rather than return false in certain failure scenarios. try { DataService.UpdateUserPassword(viewModel.UserId, viewModel.NewPassword); @@ -149,6 +160,58 @@ namespace MileageTraker.Web.Controllers return View(viewModel); } + public ActionResult DisableUser(Guid id) + { + var user = DataService.GetUser(id); + if (user == null) + { + return HttpNotFound(); + } + user.IsApproved = false; + DataService.UpdateUser(user); + + TempData["StatusMessage"] = user.Username + " disabled"; + + if (Request.UrlReferrer != null) + return Redirect(Request.UrlReferrer.AbsolutePath); + return RedirectToAction("Index"); + } + + public ActionResult EnableUser(Guid id) + { + var user = DataService.GetUser(id); + if (user == null) + { + return HttpNotFound(); + } + user.IsApproved = true; + DataService.UpdateUser(user); + + TempData["StatusMessage"] = user.Username + " enabled"; + + if (Request.UrlReferrer != null) + return Redirect(Request.UrlReferrer.AbsolutePath); + return RedirectToAction("Index"); + } + + public ActionResult UnlockUser(Guid id) + { + var user = DataService.GetUser(id); + if (user == null) + { + return HttpNotFound(); + } + user.IsLockedOut = false; + user.PasswordFailuresSinceLastSuccess = 0; + DataService.UpdateUser(user); + + TempData["StatusMessage"] = user.Username + " unlocked"; + + if (Request.UrlReferrer != null) + return Redirect(Request.UrlReferrer.AbsolutePath); + return RedirectToAction("Index"); + } + private static string ErrorCodeToString(MembershipCreateStatus createStatus) { // See http://go.microsoft.com/fwlink/?LinkID=177550 for diff --git a/Web/Controllers/VehicleController.cs b/Web/Controllers/VehicleController.cs index 2a2045c..a120081 100644 --- a/Web/Controllers/VehicleController.cs +++ b/Web/Controllers/VehicleController.cs @@ -62,7 +62,8 @@ namespace MileageTraker.Web.Controllers } return View(vehicle); } - + + [AllowAnonymous] public JsonResult Exists(string vehicleId) { var vehicle = DataService.GetVehicle(vehicleId); diff --git a/Web/DAL/CodeFirstMembershipProvider.cs b/Web/DAL/CodeFirstMembershipProvider.cs index 1dd6b0d..2d28b26 100644 --- a/Web/DAL/CodeFirstMembershipProvider.cs +++ b/Web/DAL/CodeFirstMembershipProvider.cs @@ -136,11 +136,11 @@ namespace MileageTraker.Web.DAL } if (!user.IsApproved) { - return false; + throw new UserAccountDisabledException(); } if (user.IsLockedOut) { - return false; + throw new UserLockedOutException(); } var hashedPassword = user.Password; var verificationSucceeded = (hashedPassword != null && Crypto.VerifyHashedPassword(hashedPassword, password)); diff --git a/Web/DAL/DataService.cs b/Web/DAL/DataService.cs index 98c21d5..cfa580a 100644 --- a/Web/DAL/DataService.cs +++ b/Web/DAL/DataService.cs @@ -475,6 +475,8 @@ namespace MileageTraker.Web.DAL var user = GetUser(userId); user.Password = Crypto.HashPassword(password); user.LastPasswordChangedDate = DateTime.Now; + user.IsLockedOut = false; + user.PasswordFailuresSinceLastSuccess = 0; UpdateUser(user); } diff --git a/Web/DAL/UserAccountDisabledException.cs b/Web/DAL/UserAccountDisabledException.cs new file mode 100644 index 0000000..214e7ce --- /dev/null +++ b/Web/DAL/UserAccountDisabledException.cs @@ -0,0 +1,8 @@ +using System; + +namespace MileageTraker.Web.DAL +{ + public class UserAccountDisabledException : Exception + { + } +} \ No newline at end of file diff --git a/Web/DAL/UserLockedOutException.cs b/Web/DAL/UserLockedOutException.cs new file mode 100644 index 0000000..eda2c71 --- /dev/null +++ b/Web/DAL/UserLockedOutException.cs @@ -0,0 +1,8 @@ +using System; + +namespace MileageTraker.Web.DAL +{ + public class UserLockedOutException : Exception + { + } +} \ No newline at end of file diff --git a/Web/Scripts/Shared/Site.js b/Web/Scripts/Shared/Site.js index 41836c9..c0e870f 100644 --- a/Web/Scripts/Shared/Site.js +++ b/Web/Scripts/Shared/Site.js @@ -253,7 +253,8 @@ $(function () { }, unhighlight: function (element) { $(element).closest(".control-group").removeClass("error"); - } + }, + debug: true }); }); diff --git a/Web/Utility/CustomExtensions.cs b/Web/Utility/CustomExtensions.cs index 88b79c7..874d80d 100644 --- a/Web/Utility/CustomExtensions.cs +++ b/Web/Utility/CustomExtensions.cs @@ -6,7 +6,6 @@ using System.Linq; using System.Reflection; using System.Text; using System.Web.Mvc; -using MileageTraker.Web.Models; namespace MileageTraker.Web.Utility { @@ -182,11 +181,5 @@ namespace MileageTraker.Web.Utility Convert.ToDouble( System.Web.Security.Membership.UserIsOnlineTimeWindow))); } - - public static bool IsOnline(this User user) - { - return user.LastActivityDate != null - && user.LastActivityDate > UserOnlineThreshold(); - } } } \ No newline at end of file diff --git a/Web/ViewModels/User/CreateUserViewModel.cs b/Web/ViewModels/User/CreateUserViewModel.cs index fbc3052..6da2c9b 100644 --- a/Web/ViewModels/User/CreateUserViewModel.cs +++ b/Web/ViewModels/User/CreateUserViewModel.cs @@ -1,4 +1,5 @@ using System.ComponentModel.DataAnnotations; +using System.Web.Mvc; using AutoMapper; using MileageTraker.Web.Attributes; @@ -9,12 +10,14 @@ namespace MileageTraker.Web.ViewModels.User [Required] [StringLength(64)] [InputSize("small")] + [Remote("UsernameAvailable", "User", ErrorMessage = "Username already in use")] public string Username { get; set; } [Required] [DataType(DataType.EmailAddress)] [RegularExpression(@"[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,4}", ErrorMessage = "Must be an email address")] [InputSize("large")] + [Remote("EmailAvailable", "User", ErrorMessage = "Email already in use")] public string Email { get; set; } [Required] diff --git a/Web/Views/Account/Login.cshtml b/Web/Views/Account/Login.cshtml index f49f92d..cc47368 100644 --- a/Web/Views/Account/Login.cshtml +++ b/Web/Views/Account/Login.cshtml @@ -10,7 +10,9 @@ } @using (Html.BeginForm("Login", "Account", new { ViewBag.ReturnUrl }, FormMethod.Post, new {@class = "form-login"})) { - + + @Html.Partial("_StatusMessage") +

@ViewBag.Title

diff --git a/Web/Views/CreateLog/Index.cshtml b/Web/Views/CreateLog/Index.cshtml index 36956c0..a8af2db 100644 --- a/Web/Views/CreateLog/Index.cshtml +++ b/Web/Views/CreateLog/Index.cshtml @@ -4,6 +4,8 @@ ViewBag.Title = "Enter Mileage Log"; } +@Html.Partial("_StatusMessage") +

@ViewBag.Title

@using (Html.BeginForm("Index", "CreateLog", FormMethod.Post, new { @class = "form-horizontal well center-content" })) diff --git a/Web/Views/CreateLog/Success.cshtml b/Web/Views/CreateLog/Success.cshtml deleted file mode 100644 index 86f7022..0000000 --- a/Web/Views/CreateLog/Success.cshtml +++ /dev/null @@ -1,17 +0,0 @@ -@model MileageTraker.Web.ViewModels.CreateLog.CreateLogViewModel -@{ - ViewBag.Title = "Success"; -} - -

- You've successfully created an entry - for @Html.DisplayTextFor(m => m.EmployeeName) - traveling to @Html.DisplayTextFor(m => m.CityName) - on @Html.Encode(Model.Date.ToShortDateString()) - in Vehicle Id @Html.DisplayTextFor(m => m.VehicleId) - ending in @Html.DisplayTextFor(m => m.EndOdometer) - miles on the odometer. -

-

- @Html.ActionLink("Create another", "Index", null, new { @class = "btn" }) -

diff --git a/Web/Views/Log/Create.cshtml b/Web/Views/Log/Create.cshtml index 0394840..353b669 100644 --- a/Web/Views/Log/Create.cshtml +++ b/Web/Views/Log/Create.cshtml @@ -6,6 +6,8 @@ @{ Html.RenderPartial("BackToLogs"); } +@Html.Partial("_StatusMessage") +

@ViewBag.Title

@using (Html.BeginForm("Create", "Log", FormMethod.Post, new { @class = "form-horizontal well center-content" })) diff --git a/Web/Views/Log/Delete.cshtml b/Web/Views/Log/Delete.cshtml index 4936d64..ff084d2 100644 --- a/Web/Views/Log/Delete.cshtml +++ b/Web/Views/Log/Delete.cshtml @@ -6,6 +6,8 @@ @{ Html.RenderPartial("BackToLogs"); } +@Html.Partial("_StatusMessage") +

@ViewBag.Title

Are you sure you wish to delete this log?
diff --git a/Web/Views/Log/Details.cshtml b/Web/Views/Log/Details.cshtml index eafb154..d53c065 100644 --- a/Web/Views/Log/Details.cshtml +++ b/Web/Views/Log/Details.cshtml @@ -15,9 +15,6 @@ - @if(TempData["Message"] != null) { // so, yeah, span doesn't go here, but it renders - @TempData["Message"] - } diff --git a/Web/Views/Log/Edit.cshtml b/Web/Views/Log/Edit.cshtml index 21304e3..7b51d1d 100644 --- a/Web/Views/Log/Edit.cshtml +++ b/Web/Views/Log/Edit.cshtml @@ -6,6 +6,8 @@ @{ Html.RenderPartial("BackToLogs"); } +@Html.Partial("_StatusMessage") +

@ViewBag.Title

@using (Html.BeginForm("Edit", "Log", FormMethod.Post, new { @class = "form-horizontal well center-content" })) diff --git a/Web/Views/Log/MonthlyEmployeeMileage.cshtml b/Web/Views/Log/MonthlyEmployeeMileage.cshtml index 8770f05..38d2a31 100644 --- a/Web/Views/Log/MonthlyEmployeeMileage.cshtml +++ b/Web/Views/Log/MonthlyEmployeeMileage.cshtml @@ -5,6 +5,8 @@ @{ Html.RenderPartial("BackToLogs"); } +@Html.Partial("_StatusMessage") +

@ViewBag.Title

diff --git a/Web/Views/Log/MonthlyVehicleMileage.cshtml b/Web/Views/Log/MonthlyVehicleMileage.cshtml index 72d9ec6..a0bfbd7 100644 --- a/Web/Views/Log/MonthlyVehicleMileage.cshtml +++ b/Web/Views/Log/MonthlyVehicleMileage.cshtml @@ -5,6 +5,8 @@ @{ Html.RenderPartial("BackToLogs"); } +@Html.Partial("_StatusMessage") +

@ViewBag.Title

diff --git a/Web/Views/Shared/_StatusMessage.cshtml b/Web/Views/Shared/_StatusMessage.cshtml index 1d4bd2b..e072297 100644 --- a/Web/Views/Shared/_StatusMessage.cshtml +++ b/Web/Views/Shared/_StatusMessage.cshtml @@ -1,12 +1,12 @@ @if (TempData.ContainsKey("StatusMessage")) { -

+

- @TempData["StatusMessage"] + @Html.Raw(TempData["StatusMessage"])

} else if (ViewBag.StatusMessage != null) { -

+

@ViewBag.StatusMessage

diff --git a/Web/Views/User/Details.cshtml b/Web/Views/User/Details.cshtml index 6c3acc3..ab6592b 100644 --- a/Web/Views/User/Details.cshtml +++ b/Web/Views/User/Details.cshtml @@ -12,9 +12,20 @@

@ViewBag.Title

+ +
+
+ @Html.DisplayNameFor(m => m.Username) +
+
+ @Html.Encode(Model.Username) + @Html.Partial("_UserStatusLabels") +
+
@Html.DisplayFor(m => m.Email) - @Html.DisplayFor(m => m.Username) + + @Html.DisplayFor(m => m.FullName)
@@ -33,7 +44,7 @@
-
+
@Html.DisplayNameFor(m => m.LastActivityDate)
@@ -50,14 +61,73 @@
+
+
+ @Html.DisplayNameFor(m => m.LastLoginDate) +
+
+ @if (!Model.LastLoginDate.IsSqlMinValue()) + { + @Html.Encode(Model.LastLoginDate) + (@Html.Encode((DateTime.Now - Model.LastLoginDate).ToVerboseStringHistoric())) + } + else + { + Never Logged In + } +
+
+ +
+
+ @Html.DisplayNameFor(m => m.LastPasswordChangedDate) +
+
+ @if (!Model.LastPasswordChangedDate.IsSqlMinValue()) + { + @Html.Encode(Model.LastPasswordChangedDate) + (@Html.Encode((DateTime.Now - Model.LastPasswordChangedDate).ToVerboseStringHistoric())) + } + else + { + Never Changed + } +
+
+ @if (Model.IsLockedOut) { -

- Locked out on @Html.DisplayTextFor(m => m.LastLockoutDate) -

+
+
+ Lockout Password Date +
+
+ @if (!Model.LastLockoutDate.IsSqlMinValue()) + { + @Html.Encode(Model.LastLockoutDate) + (@Html.Encode((DateTime.Now - Model.LastLockoutDate).ToVerboseStringHistoric())) + } + else + { + Never Locked (?) + } +
+
}
@Html.ActionLink("Edit", "Edit", new { id = Model.UserId }, new { @class = "btn" }) @Html.ActionLink("Set Password", "SetPassword", new { id = Model.UserId }, new { @class = "btn" }) + @if (Model.IsApproved) + { + @Html.ActionLink("Disable Account", "DisableUser", new {id = Model.UserId}, new {@class = "btn"}) + } + else + { + @Html.ActionLink("Enable Account", "EnableUser", new {id = Model.UserId}, new {@class = "btn"}) + } + @if (Model.IsLockedOut) + { + @Html.ActionLink("Unlock", "UnlockUser", new {id = Model.UserId}, new {@class = "btn"}) + }
diff --git a/Web/Views/User/Edit.cshtml b/Web/Views/User/Edit.cshtml index 64c2dd1..e5aecf3 100644 --- a/Web/Views/User/Edit.cshtml +++ b/Web/Views/User/Edit.cshtml @@ -6,6 +6,8 @@ @{ Html.RenderPartial("BackToUsers"); } +@Html.Partial("_StatusMessage") +

@ViewBag.Title

@using (Html.BeginForm("Edit", "User", FormMethod.Post, new { @class = "form-horizontal well center-content" })) @@ -25,5 +27,5 @@ }
- @Html.ActionLink("Set Password", "SetPassword", new { id = Model.UserId }, new { @class = "btn" }) + @Html.ActionLink("Details", "Details", new { id = Model.UserId }, new { @class = "btn" })
diff --git a/Web/Views/User/Index.cshtml b/Web/Views/User/Index.cshtml index f67d01b..ca3552e 100644 --- a/Web/Views/User/Index.cshtml +++ b/Web/Views/User/Index.cshtml @@ -1,5 +1,5 @@ -@using MileageTraker.Web.Utility -@model IEnumerable +@using MileageTraker.Web.Models +@model IEnumerable @{ ViewBag.Title = "Users"; @@ -21,23 +21,20 @@ grid.Columns( grid.Column("Username", format: @ - - @Html.Encode(item.Username) - - @if (item.LastActivityDate > CustomExtensions.UserOnlineThreshold()) { - Online - } - @if (item.IsLockedOut) { - Locked Out - } - @if (!item.IsApproved) - { - Account Disabled - } ), + + @Html.Encode(item.Username) + + @Html.Partial("_UserStatusLabels", + new User{ + LastActivityDate = item.LastActivityDate, + IsLockedOut = item.IsLockedOut, + LastLockoutDate = item.LastLockoutDate, + IsApproved = item.IsApproved}) + ), grid.Column("FullName", "Full Name"), grid.Column("Roles", format: @ - @{ var roles = Roles.Provider.GetRolesForUser(item.Username); } + @{var roles = Roles.Provider.GetRolesForUser(item.Username);} @if (roles.Length > 0) { @Html.Encode(string.Join(", ", roles)) @@ -49,8 +46,8 @@ ), grid.Column(format: @
- @Html.ActionLink("Edit", "Edit", new { id = item.UserId }, new { @class = "btn btn-mini" }) - @Html.ActionLink("Details", "Details", new { id = item.UserId }, new { @class = "btn btn-mini" }) + @*Html.ActionLink("Edit", "Edit", new { id = item.UserId }, new { @class = "btn btn-mini" })*@ + @Html.ActionLink("Details / Edit", "Details", new { id = item.UserId }, new { @class = "btn btn-mini" })
) ), htmlAttributes: new { @class = "table table-striped table-bordered table-hover table-condensed"}, diff --git a/Web/Views/User/SetPassword.cshtml b/Web/Views/User/SetPassword.cshtml index ec4f9af..617358a 100644 --- a/Web/Views/User/SetPassword.cshtml +++ b/Web/Views/User/SetPassword.cshtml @@ -3,6 +3,8 @@ ViewBag.Title = "Change Password"; } +@Html.Partial("_StatusMessage") +

@ViewBag.Title

@using (Html.BeginForm("SetPassword", "User", FormMethod.Post, new { @class = "form-horizontal well center-content" })) diff --git a/Web/Views/User/_UserStatusLabels.cshtml b/Web/Views/User/_UserStatusLabels.cshtml new file mode 100644 index 0000000..a51fa49 --- /dev/null +++ b/Web/Views/User/_UserStatusLabels.cshtml @@ -0,0 +1,15 @@ +@using MileageTraker.Web.Utility +@model MileageTraker.Web.Models.User + +@if (Model.LastActivityDate > CustomExtensions.UserOnlineThreshold()) +{ + Online +} +@if (Model.IsLockedOut) +{ + Locked Out +} +@if (!Model.IsApproved) +{ + Account Disabled +} \ No newline at end of file diff --git a/Web/Views/Vehicle/Create.cshtml b/Web/Views/Vehicle/Create.cshtml index 43ecf5b..005de1a 100644 --- a/Web/Views/Vehicle/Create.cshtml +++ b/Web/Views/Vehicle/Create.cshtml @@ -6,6 +6,8 @@ @{ Html.RenderPartial("BackToVehicles"); } +@Html.Partial("_StatusMessage") +

@ViewBag.Title

@using (Html.BeginForm("Create", "Vehicle", FormMethod.Post, new { @class = "form-horizontal well center-content" })) diff --git a/Web/Views/Vehicle/Edit.cshtml b/Web/Views/Vehicle/Edit.cshtml index e85a1d2..9a72ac5 100644 --- a/Web/Views/Vehicle/Edit.cshtml +++ b/Web/Views/Vehicle/Edit.cshtml @@ -6,6 +6,8 @@ @{ Html.RenderPartial("BackToVehicles"); } +@Html.Partial("_StatusMessage") +

@ViewBag.Title

@using (Html.BeginForm("Edit", "Vehicle", FormMethod.Post, new { @class = "form-horizontal well center-content" })) diff --git a/Web/Web.csproj b/Web/Web.csproj index fe772f2..ed1bd8c 100644 --- a/Web/Web.csproj +++ b/Web/Web.csproj @@ -124,6 +124,8 @@ + + 201204181847082_InitialMigration.cs @@ -234,7 +236,6 @@ - Designer @@ -278,6 +279,7 @@ +