├── .tfignore ├── .nuget ├── NuGet.exe ├── NuGet.Config └── NuGet.targets ├── AspNetExtendingIdentityRoles ├── Views │ ├── _ViewStart.cshtml │ ├── Home │ │ ├── About.cshtml │ │ ├── Contact.cshtml │ │ └── Index.cshtml │ ├── Shared │ │ ├── Error.cshtml │ │ ├── EditorTemplates │ │ │ └── SelectRoleEditorViewModel.cshtml │ │ ├── _LoginPartial.cshtml │ │ └── _Layout.cshtml │ ├── Account │ │ ├── Manage.cshtml │ │ ├── _SetPasswordPartial.cshtml │ │ ├── Delete.cshtml │ │ ├── Index.cshtml │ │ ├── _ChangePasswordPartial.cshtml │ │ ├── UserRoles.cshtml │ │ ├── Edit.cshtml │ │ ├── Register.cshtml │ │ └── Login.cshtml │ ├── Roles │ │ ├── Index.cshtml │ │ ├── Delete.cshtml │ │ ├── Edit.cshtml │ │ └── Create.cshtml │ └── Web.config ├── Global.asax ├── favicon.ico ├── Scripts │ ├── _references.js │ ├── respond.min.js │ ├── jquery.validate.unobtrusive.min.js │ ├── respond.js │ ├── jquery.validate.unobtrusive.js │ ├── jquery.validate.min.js │ └── bootstrap.min.js ├── fonts │ ├── glyphicons-halflings-regular.eot │ ├── glyphicons-halflings-regular.ttf │ └── glyphicons-halflings-regular.woff ├── App_Start │ ├── FilterConfig.cs │ ├── RouteConfig.cs │ ├── BundleConfig.cs │ └── Startup.Auth.cs ├── Startup.cs ├── Models │ ├── ApplicationUserRole.cs │ ├── ApplicationUser.cs │ ├── ApplicationRole.cs │ ├── IdentityManager.cs │ ├── ApplicationDbContext.cs │ └── AccountViewModels.cs ├── Global.asax.cs ├── Controllers │ ├── HomeController.cs │ ├── RolesController.cs │ └── AccountController.cs ├── Content │ └── Site.css ├── Migrations │ ├── 201402130341319_init.Designer.cs │ ├── Configuration.cs │ ├── 201402130341319_init.cs │ └── 201402130341319_init.resx ├── Web.Debug.config ├── Web.Release.config ├── Properties │ └── AssemblyInfo.cs ├── packages.config ├── Web.config ├── Project_Readme.html └── AspNetExtendingIdentityRoles.csproj ├── .gitignore ├── AspNetExtendingIdentityRoles.sln └── README.md /.tfignore: -------------------------------------------------------------------------------- 1 | \.git -------------------------------------------------------------------------------- /.nuget/NuGet.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TypecastException/AspNetExtendingIdentityRoles/HEAD/.nuget/NuGet.exe -------------------------------------------------------------------------------- /AspNetExtendingIdentityRoles/Views/_ViewStart.cshtml: -------------------------------------------------------------------------------- 1 | @{ 2 | Layout = "~/Views/Shared/_Layout.cshtml"; 3 | } 4 | -------------------------------------------------------------------------------- /AspNetExtendingIdentityRoles/Global.asax: -------------------------------------------------------------------------------- 1 | <%@ Application Codebehind="Global.asax.cs" Inherits="AspNetExtendingIdentityRoles.MvcApplication" Language="C#" %> 2 | -------------------------------------------------------------------------------- /AspNetExtendingIdentityRoles/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TypecastException/AspNetExtendingIdentityRoles/HEAD/AspNetExtendingIdentityRoles/favicon.ico -------------------------------------------------------------------------------- /AspNetExtendingIdentityRoles/Scripts/_references.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TypecastException/AspNetExtendingIdentityRoles/HEAD/AspNetExtendingIdentityRoles/Scripts/_references.js -------------------------------------------------------------------------------- /.nuget/NuGet.Config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /AspNetExtendingIdentityRoles/fonts/glyphicons-halflings-regular.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TypecastException/AspNetExtendingIdentityRoles/HEAD/AspNetExtendingIdentityRoles/fonts/glyphicons-halflings-regular.eot -------------------------------------------------------------------------------- /AspNetExtendingIdentityRoles/fonts/glyphicons-halflings-regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TypecastException/AspNetExtendingIdentityRoles/HEAD/AspNetExtendingIdentityRoles/fonts/glyphicons-halflings-regular.ttf -------------------------------------------------------------------------------- /AspNetExtendingIdentityRoles/fonts/glyphicons-halflings-regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TypecastException/AspNetExtendingIdentityRoles/HEAD/AspNetExtendingIdentityRoles/fonts/glyphicons-halflings-regular.woff -------------------------------------------------------------------------------- /AspNetExtendingIdentityRoles/Views/Home/About.cshtml: -------------------------------------------------------------------------------- 1 | @{ 2 | ViewBag.Title = "About"; 3 | } 4 |

@ViewBag.Title.

5 |

@ViewBag.Message

6 | 7 |

Use this area to provide additional information.

8 | -------------------------------------------------------------------------------- /AspNetExtendingIdentityRoles/Views/Shared/Error.cshtml: -------------------------------------------------------------------------------- 1 | @model System.Web.Mvc.HandleErrorInfo 2 | 3 | @{ 4 | ViewBag.Title = "Error"; 5 | } 6 | 7 |

Error.

8 |

An error occurred while processing your request.

9 | 10 | -------------------------------------------------------------------------------- /AspNetExtendingIdentityRoles/App_Start/FilterConfig.cs: -------------------------------------------------------------------------------- 1 | using System.Web; 2 | using System.Web.Mvc; 3 | 4 | namespace AspNetExtendingIdentityRoles 5 | { 6 | public class FilterConfig 7 | { 8 | public static void RegisterGlobalFilters(GlobalFilterCollection filters) 9 | { 10 | filters.Add(new HandleErrorAttribute()); 11 | } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /AspNetExtendingIdentityRoles/Startup.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Owin; 2 | using Owin; 3 | 4 | [assembly: OwinStartupAttribute(typeof(AspNetExtendingIdentityRoles.Startup))] 5 | namespace AspNetExtendingIdentityRoles 6 | { 7 | public partial class Startup 8 | { 9 | public void Configuration(IAppBuilder app) 10 | { 11 | ConfigureAuth(app); 12 | } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | Thumbs.db 2 | *.obj 3 | *.exe 4 | !Nuget.exe 5 | *.pdb 6 | *.user 7 | *.aps 8 | *.pch 9 | *.vspscc 10 | *_i.c 11 | *_p.c 12 | *.ncb 13 | *.suo 14 | *.sln.docstates 15 | *.tlb 16 | *.tlh 17 | *.bak 18 | *.cache 19 | *.ilk 20 | *.log 21 | [Bb]in 22 | [Dd]ebug*/ 23 | *.lib 24 | *.sbr 25 | obj/ 26 | [Rr]elease*/ 27 | _ReSharper*/ 28 | [Tt]est[Rr]esult* 29 | *.vssscc 30 | $tf*/ 31 | packages*/ 32 | App_Data*/ -------------------------------------------------------------------------------- /AspNetExtendingIdentityRoles/Models/ApplicationUserRole.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNet.Identity.EntityFramework; 2 | using Microsoft.AspNet.Identity; 3 | using System.ComponentModel.DataAnnotations; 4 | using System.Collections.Generic; 5 | 6 | namespace AspNetExtendingIdentityRoles.Models 7 | { 8 | //public class ApplicationUserRole : IdentityUserRole 9 | //{ 10 | // new public virtual ApplicationRole Role { get; set; } 11 | // new public virtual ApplicationUser User { get; set; } 12 | //} 13 | 14 | 15 | } -------------------------------------------------------------------------------- /AspNetExtendingIdentityRoles/Views/Home/Contact.cshtml: -------------------------------------------------------------------------------- 1 | @{ 2 | ViewBag.Title = "Contact"; 3 | } 4 |

@ViewBag.Title.

5 |

@ViewBag.Message

6 | 7 |
8 | One Microsoft Way
9 | Redmond, WA 98052-6399
10 | P: 11 | 425.555.0100 12 |
13 | 14 |
15 | Support: Support@example.com
16 | Marketing: Marketing@example.com 17 |
-------------------------------------------------------------------------------- /AspNetExtendingIdentityRoles/Views/Shared/EditorTemplates/SelectRoleEditorViewModel.cshtml: -------------------------------------------------------------------------------- 1 | @model AspNetExtendingIdentityRoles.Models.SelectRoleEditorViewModel 2 | @Html.HiddenFor(model => model.RoleName) 3 | 4 | 5 | @Html.CheckBoxFor(model => model.Selected) 6 | 7 | 8 | @Html.DisplayFor(model => model.RoleName) 9 | 10 | 11 | @Html.DisplayFor(model => model.Description) 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /AspNetExtendingIdentityRoles/Models/ApplicationUser.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNet.Identity.EntityFramework; 2 | using Microsoft.AspNet.Identity; 3 | using System.ComponentModel.DataAnnotations; 4 | using System.Collections.Generic; 5 | 6 | namespace AspNetExtendingIdentityRoles.Models 7 | { 8 | public class ApplicationUser : IdentityUser 9 | { 10 | [Required] 11 | public string FirstName { get; set; } 12 | 13 | [Required] 14 | public string LastName { get; set; } 15 | 16 | [Required] 17 | public string Email { get; set; } 18 | } 19 | } -------------------------------------------------------------------------------- /AspNetExtendingIdentityRoles/Models/ApplicationRole.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNet.Identity.EntityFramework; 2 | using Microsoft.AspNet.Identity; 3 | using System.ComponentModel.DataAnnotations; 4 | using System.Collections.Generic; 5 | 6 | namespace AspNetExtendingIdentityRoles.Models 7 | { 8 | public class ApplicationRole : IdentityRole 9 | { 10 | public ApplicationRole() : base() { } 11 | 12 | 13 | public ApplicationRole(string name, string description) : base(name) 14 | { 15 | this.Description = description; 16 | } 17 | public virtual string Description { get; set; } 18 | } 19 | } -------------------------------------------------------------------------------- /AspNetExtendingIdentityRoles/Views/Account/Manage.cshtml: -------------------------------------------------------------------------------- 1 | @using AspNetExtendingIdentityRoles.Models; 2 | @using Microsoft.AspNet.Identity; 3 | @{ 4 | ViewBag.Title = "Manage Account"; 5 | } 6 | 7 |

@ViewBag.Title.

8 | 9 |

@ViewBag.StatusMessage

10 |
11 |
12 | @if (ViewBag.HasLocalPassword) 13 | { 14 | @Html.Partial("_ChangePasswordPartial") 15 | } 16 | else 17 | { 18 | @Html.Partial("_SetPasswordPartial") 19 | } 20 |
21 |
22 | @section Scripts { 23 | @Scripts.Render("~/bundles/jqueryval") 24 | } 25 | -------------------------------------------------------------------------------- /AspNetExtendingIdentityRoles/Global.asax.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Web; 5 | using System.Web.Mvc; 6 | using System.Web.Optimization; 7 | using System.Web.Routing; 8 | 9 | namespace AspNetExtendingIdentityRoles 10 | { 11 | public class MvcApplication : System.Web.HttpApplication 12 | { 13 | protected void Application_Start() 14 | { 15 | AreaRegistration.RegisterAllAreas(); 16 | FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters); 17 | RouteConfig.RegisterRoutes(RouteTable.Routes); 18 | BundleConfig.RegisterBundles(BundleTable.Bundles); 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /AspNetExtendingIdentityRoles/App_Start/RouteConfig.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Web; 5 | using System.Web.Mvc; 6 | using System.Web.Routing; 7 | 8 | namespace AspNetExtendingIdentityRoles 9 | { 10 | public class RouteConfig 11 | { 12 | public static void RegisterRoutes(RouteCollection routes) 13 | { 14 | routes.IgnoreRoute("{resource}.axd/{*pathInfo}"); 15 | 16 | routes.MapRoute( 17 | name: "Default", 18 | url: "{controller}/{action}/{id}", 19 | defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional } 20 | ); 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /AspNetExtendingIdentityRoles/Controllers/HomeController.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Web; 5 | using System.Web.Mvc; 6 | 7 | namespace AspNetExtendingIdentityRoles.Controllers 8 | { 9 | public class HomeController : Controller 10 | { 11 | public ActionResult Index() 12 | { 13 | return View(); 14 | } 15 | 16 | public ActionResult About() 17 | { 18 | ViewBag.Message = "Your application description page."; 19 | 20 | return View(); 21 | } 22 | 23 | public ActionResult Contact() 24 | { 25 | ViewBag.Message = "Your contact page."; 26 | 27 | return View(); 28 | } 29 | } 30 | } -------------------------------------------------------------------------------- /AspNetExtendingIdentityRoles/Views/Shared/_LoginPartial.cshtml: -------------------------------------------------------------------------------- 1 | @using Microsoft.AspNet.Identity 2 | @if (Request.IsAuthenticated) 3 | { 4 | using (Html.BeginForm("LogOff", "Account", FormMethod.Post, new { id = "logoutForm", @class = "navbar-right" })) 5 | { 6 | @Html.AntiForgeryToken() 7 | 8 | 14 | } 15 | } 16 | else 17 | { 18 | 21 | } 22 | -------------------------------------------------------------------------------- /AspNetExtendingIdentityRoles/Content/Site.css: -------------------------------------------------------------------------------- 1 | body { 2 | padding-top: 50px; 3 | padding-bottom: 20px; 4 | } 5 | 6 | /* Set padding to keep content from hitting the edges */ 7 | .body-content { 8 | padding-left: 15px; 9 | padding-right: 15px; 10 | } 11 | 12 | /* Set width on the form input elements since they're 100% wide by default */ 13 | input, 14 | select, 15 | textarea { 16 | max-width: 280px; 17 | } 18 | 19 | /* styles for validation helpers */ 20 | .field-validation-error { 21 | color: #b94a48; 22 | } 23 | 24 | .field-validation-valid { 25 | display: none; 26 | } 27 | 28 | input.input-validation-error { 29 | border: 1px solid #b94a48; 30 | } 31 | 32 | input[type="checkbox"].input-validation-error { 33 | border: 0 none; 34 | } 35 | 36 | .validation-summary-errors { 37 | color: #b94a48; 38 | } 39 | 40 | .validation-summary-valid { 41 | display: none; 42 | } -------------------------------------------------------------------------------- /AspNetExtendingIdentityRoles/Migrations/201402130341319_init.Designer.cs: -------------------------------------------------------------------------------- 1 | // 2 | namespace AspNetExtendingIdentityRoles.Migrations 3 | { 4 | using System.CodeDom.Compiler; 5 | using System.Data.Entity.Migrations; 6 | using System.Data.Entity.Migrations.Infrastructure; 7 | using System.Resources; 8 | 9 | [GeneratedCode("EntityFramework.Migrations", "6.0.0-20911")] 10 | public sealed partial class init : IMigrationMetadata 11 | { 12 | private readonly ResourceManager Resources = new ResourceManager(typeof(init)); 13 | 14 | string IMigrationMetadata.Id 15 | { 16 | get { return "201402130341319_init"; } 17 | } 18 | 19 | string IMigrationMetadata.Source 20 | { 21 | get { return null; } 22 | } 23 | 24 | string IMigrationMetadata.Target 25 | { 26 | get { return Resources.GetString("Target"); } 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /AspNetExtendingIdentityRoles/Views/Roles/Index.cshtml: -------------------------------------------------------------------------------- 1 | @model IEnumerable 2 | 3 | @{ 4 | ViewBag.Title = "Application Roles"; 5 | } 6 | 7 |

Application Roles

8 | 9 |

10 | @Html.ActionLink("Create New", "Create") 11 |

12 | 13 | 14 | 17 | 20 | 21 | 22 | 23 | @foreach (var item in Model) { 24 | 25 | 28 | 31 | 35 | 36 | } 37 | 38 |
15 | @Html.DisplayNameFor(model => model.RoleName) 16 | 18 | @Html.DisplayNameFor(model => model.Description) 19 |
26 | @Html.DisplayFor(modelItem => item.RoleName) 27 | 29 | @Html.DisplayFor(modelItem => item.Description) 30 | 32 | @Html.ActionLink("Edit", "Edit", new { id = item.RoleName }) | 33 | @Html.ActionLink("Delete", "Delete", new { id = item.RoleName }) 34 |
39 | -------------------------------------------------------------------------------- /AspNetExtendingIdentityRoles/Views/Roles/Delete.cshtml: -------------------------------------------------------------------------------- 1 | @model AspNetExtendingIdentityRoles.Models.RoleViewModel 2 | 3 | @{ 4 | ViewBag.Title = "Delete"; 5 | } 6 | 7 |

Delete

8 | 9 |

Are you sure you want to delete this?

10 |
11 |

RolesViewModel

12 |
13 |
14 |
15 | @Html.DisplayNameFor(model => model.RoleName) 16 |
17 | 18 |
19 | @Html.DisplayFor(model => model.RoleName) 20 |
21 | 22 |
23 | @Html.DisplayNameFor(model => model.Description) 24 |
25 | 26 |
27 | @Html.DisplayFor(model => model.Description) 28 |
29 | 30 |
31 | 32 | @using (Html.BeginForm()) { 33 | @Html.AntiForgeryToken() 34 | 35 |
36 | | 37 | @Html.ActionLink("Back to List", "Index") 38 |
39 | } 40 |
41 | -------------------------------------------------------------------------------- /AspNetExtendingIdentityRoles/Views/Account/_SetPasswordPartial.cshtml: -------------------------------------------------------------------------------- 1 | @model AspNetExtendingIdentityRoles.Models.ManageUserViewModel 2 | 3 |

4 | You do not have a local username/password for this site. Add a local 5 | account so you can log in without an external login. 6 |

7 | 8 | @using (Html.BeginForm("Manage", "Account", FormMethod.Post, new { @class = "form-horizontal", role = "form" })) 9 | { 10 | @Html.AntiForgeryToken() 11 | 12 |

Create Local Login

13 |
14 | @Html.ValidationSummary() 15 |
16 | @Html.LabelFor(m => m.NewPassword, new { @class = "col-md-2 control-label" }) 17 |
18 | @Html.PasswordFor(m => m.NewPassword, new { @class = "form-control" }) 19 |
20 |
21 |
22 | @Html.LabelFor(m => m.ConfirmPassword, new { @class = "col-md-2 control-label" }) 23 |
24 | @Html.PasswordFor(m => m.ConfirmPassword, new { @class = "form-control" }) 25 |
26 |
27 |
28 |
29 | 30 |
31 |
32 | } 33 | -------------------------------------------------------------------------------- /AspNetExtendingIdentityRoles/Web.Debug.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 17 | 18 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /AspNetExtendingIdentityRoles/App_Start/BundleConfig.cs: -------------------------------------------------------------------------------- 1 | using System.Web; 2 | using System.Web.Optimization; 3 | 4 | namespace AspNetExtendingIdentityRoles 5 | { 6 | public class BundleConfig 7 | { 8 | // For more information on bundling, visit http://go.microsoft.com/fwlink/?LinkId=301862 9 | public static void RegisterBundles(BundleCollection bundles) 10 | { 11 | bundles.Add(new ScriptBundle("~/bundles/jquery").Include( 12 | "~/Scripts/jquery-{version}.js")); 13 | 14 | bundles.Add(new ScriptBundle("~/bundles/jqueryval").Include( 15 | "~/Scripts/jquery.validate*")); 16 | 17 | // Use the development version of Modernizr to develop with and learn from. Then, when you're 18 | // ready for production, use the build tool at http://modernizr.com to pick only the tests you need. 19 | bundles.Add(new ScriptBundle("~/bundles/modernizr").Include( 20 | "~/Scripts/modernizr-*")); 21 | 22 | bundles.Add(new ScriptBundle("~/bundles/bootstrap").Include( 23 | "~/Scripts/bootstrap.js", 24 | "~/Scripts/respond.js")); 25 | 26 | bundles.Add(new StyleBundle("~/Content/css").Include( 27 | "~/Content/bootstrap.css", 28 | "~/Content/site.css")); 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /AspNetExtendingIdentityRoles/Web.Release.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 17 | 18 | 19 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /AspNetExtendingIdentityRoles/Views/Account/Delete.cshtml: -------------------------------------------------------------------------------- 1 | @model AspNetExtendingIdentityRoles.Models.EditUserViewModel 2 | 3 | @{ 4 | ViewBag.Title = "Delete"; 5 | } 6 | 7 |

Delete

8 | 9 |

Are you sure you want to delete this?

10 |
11 |

EditUserViewModel

12 |
13 |
14 |
15 | @Html.DisplayNameFor(model => model.UserName) 16 |
17 | 18 |
19 | @Html.DisplayFor(model => model.UserName) 20 |
21 | 22 |
23 | @Html.DisplayNameFor(model => model.FirstName) 24 |
25 | 26 |
27 | @Html.DisplayFor(model => model.FirstName) 28 |
29 | 30 |
31 | @Html.DisplayNameFor(model => model.LastName) 32 |
33 | 34 |
35 | @Html.DisplayFor(model => model.LastName) 36 |
37 | 38 |
39 | @Html.DisplayNameFor(model => model.Email) 40 |
41 | 42 |
43 | @Html.DisplayFor(model => model.Email) 44 |
45 | 46 |
47 | 48 | @using (Html.BeginForm()) { 49 | @Html.AntiForgeryToken() 50 | 51 |
52 | | 53 | @Html.ActionLink("Back to List", "Index") 54 |
55 | } 56 |
57 | -------------------------------------------------------------------------------- /AspNetExtendingIdentityRoles/Views/Account/Index.cshtml: -------------------------------------------------------------------------------- 1 | @model IEnumerable 2 | 3 | @{ 4 | ViewBag.Title = "Index"; 5 | } 6 | 7 |

Index

8 | 9 |

10 | @Html.ActionLink("Create New", "Register") 11 |

12 | 13 | 14 | 17 | 20 | 23 | 26 | 27 | 28 | 29 | @foreach (var item in Model) { 30 | 31 | 34 | 37 | 40 | 43 | 48 | 49 | } 50 | 51 |
15 | @Html.DisplayNameFor(model => model.UserName) 16 | 18 | @Html.DisplayNameFor(model => model.FirstName) 19 | 21 | @Html.DisplayNameFor(model => model.LastName) 22 | 24 | @Html.DisplayNameFor(model => model.Email) 25 |
32 | @Html.DisplayFor(modelItem => item.UserName) 33 | 35 | @Html.DisplayFor(modelItem => item.FirstName) 36 | 38 | @Html.DisplayFor(modelItem => item.LastName) 39 | 41 | @Html.DisplayFor(modelItem => item.Email) 42 | 44 | @Html.ActionLink("Edit", "Edit", new { id = item.UserName }) | 45 | @Html.ActionLink("Roles", "UserRoles", new { id = item.UserName }) | 46 | @Html.ActionLink("Delete", "Delete", new { id = item.UserName }) 47 |
52 | -------------------------------------------------------------------------------- /AspNetExtendingIdentityRoles/Views/Account/_ChangePasswordPartial.cshtml: -------------------------------------------------------------------------------- 1 | @using Microsoft.AspNet.Identity 2 | @model AspNetExtendingIdentityRoles.Models.ManageUserViewModel 3 | 4 |

You're logged in as @User.Identity.GetUserName().

5 | 6 | @using (Html.BeginForm("Manage", "Account", FormMethod.Post, new { @class = "form-horizontal", role = "form" })) 7 | { 8 | @Html.AntiForgeryToken() 9 |

Change Password Form

10 |
11 | @Html.ValidationSummary() 12 |
13 | @Html.LabelFor(m => m.OldPassword, new { @class = "col-md-2 control-label" }) 14 |
15 | @Html.PasswordFor(m => m.OldPassword, new { @class = "form-control" }) 16 |
17 |
18 |
19 | @Html.LabelFor(m => m.NewPassword, new { @class = "col-md-2 control-label" }) 20 |
21 | @Html.PasswordFor(m => m.NewPassword, new { @class = "form-control" }) 22 |
23 |
24 |
25 | @Html.LabelFor(m => m.ConfirmPassword, new { @class = "col-md-2 control-label" }) 26 |
27 | @Html.PasswordFor(m => m.ConfirmPassword, new { @class = "form-control" }) 28 |
29 |
30 | 31 |
32 |
33 | 34 |
35 |
36 | } 37 | -------------------------------------------------------------------------------- /AspNetExtendingIdentityRoles/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("AspNetExtendingIdentityRoles")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("AspNetExtendingIdentityRoles")] 13 | [assembly: AssemblyCopyright("Copyright © 2013")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("007b4066-9928-4140-a3cb-4cc527b22a69")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Revision and Build Numbers 33 | // by using the '*' as shown below: 34 | [assembly: AssemblyVersion("1.0.0.0")] 35 | [assembly: AssemblyFileVersion("1.0.0.0")] 36 | -------------------------------------------------------------------------------- /AspNetExtendingIdentityRoles/Views/Account/UserRoles.cshtml: -------------------------------------------------------------------------------- 1 | @model AspNetExtendingIdentityRoles.Models.SelectUserRolesViewModel 2 | 3 | @{ 4 | ViewBag.Title = "User Roles"; 5 | } 6 | 7 |

Roles for user @Html.DisplayFor(model => model.UserName)

8 |
9 | 10 | @using (Html.BeginForm("UserRoles", "Account", FormMethod.Post, new { encType = "multipart/form-data", name = "myform" })) 11 | { 12 | @Html.AntiForgeryToken() 13 | 14 |
15 | @Html.ValidationSummary(true) 16 |
17 |
18 | @Html.HiddenFor(model => model.UserName) 19 |
20 |
21 | 22 |

Select Role Assignments

23 |
24 |
25 | 26 | 27 | 28 | 29 | 32 | 35 | 38 | 39 | 40 | @Html.EditorFor(model => model.Roles) 41 |
30 | Select 31 | 33 | Role 34 | 36 | Description 37 |
42 |
43 |
44 | 45 |
46 |
47 | 48 |
49 |
50 |
51 | } 52 | 53 |
54 | @Html.ActionLink("Back to List", "Index") 55 |
56 | 57 | -------------------------------------------------------------------------------- /AspNetExtendingIdentityRoles/Views/Home/Index.cshtml: -------------------------------------------------------------------------------- 1 | @{ 2 | ViewBag.Title = "Home Page"; 3 | } 4 | 5 |
6 |

ASP.NET

7 |

ASP.NET is a free web framework for building great Web sites and Web applications using HTML, CSS and JavaScript.

8 |

Learn more »

9 |
10 | 11 |
12 |
13 |

Getting started

14 |

15 | ASP.NET MVC gives you a powerful, patterns-based way to build dynamic websites that 16 | enables a clean separation of concerns and gives you full control over markup 17 | for enjoyable, agile development. 18 |

19 |

Learn more »

20 |
21 |
22 |

Get more libraries

23 |

NuGet is a free Visual Studio extension that makes it easy to add, remove, and update libraries and tools in Visual Studio projects.

24 |

Learn more »

25 |
26 |
27 |

Web Hosting

28 |

You can easily find a web hosting company that offers the right mix of features and price for your applications.

29 |

Learn more »

30 |
31 |
-------------------------------------------------------------------------------- /AspNetExtendingIdentityRoles/App_Start/Startup.Auth.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNet.Identity; 2 | using Microsoft.Owin; 3 | using Microsoft.Owin.Security.Cookies; 4 | using Owin; 5 | 6 | namespace AspNetExtendingIdentityRoles 7 | { 8 | public partial class Startup 9 | { 10 | // For more information on configuring authentication, please visit http://go.microsoft.com/fwlink/?LinkId=301864 11 | public void ConfigureAuth(IAppBuilder app) 12 | { 13 | // Enable the application to use a cookie to store information for the signed in user 14 | app.UseCookieAuthentication(new CookieAuthenticationOptions 15 | { 16 | AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie, 17 | LoginPath = new PathString("/Account/Login") 18 | }); 19 | // Use a cookie to temporarily store information about a user logging in with a third party login provider 20 | app.UseExternalSignInCookie(DefaultAuthenticationTypes.ExternalCookie); 21 | 22 | // Uncomment the following lines to enable logging in with third party login providers 23 | //app.UseMicrosoftAccountAuthentication( 24 | // clientId: "", 25 | // clientSecret: ""); 26 | 27 | //app.UseTwitterAuthentication( 28 | // consumerKey: "", 29 | // consumerSecret: ""); 30 | 31 | //app.UseFacebookAuthentication( 32 | // appId: "", 33 | // appSecret: ""); 34 | 35 | //app.UseGoogleAuthentication(); 36 | } 37 | } 38 | } -------------------------------------------------------------------------------- /AspNetExtendingIdentityRoles.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 2013 4 | VisualStudioVersion = 12.0.21005.1 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AspNetExtendingIdentityRoles", "AspNetExtendingIdentityRoles\AspNetExtendingIdentityRoles.csproj", "{D7ADA016-6E82-4F70-B6CF-B687A3B6F6EA}" 7 | EndProject 8 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".nuget", ".nuget", "{6DCF7BBA-8C8E-4E64-A6F0-3CB2A778DA69}" 9 | ProjectSection(SolutionItems) = preProject 10 | .nuget\NuGet.Config = .nuget\NuGet.Config 11 | .nuget\NuGet.exe = .nuget\NuGet.exe 12 | .nuget\NuGet.targets = .nuget\NuGet.targets 13 | EndProjectSection 14 | EndProject 15 | Global 16 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 17 | Debug|Any CPU = Debug|Any CPU 18 | Release|Any CPU = Release|Any CPU 19 | EndGlobalSection 20 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 21 | {D7ADA016-6E82-4F70-B6CF-B687A3B6F6EA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 22 | {D7ADA016-6E82-4F70-B6CF-B687A3B6F6EA}.Debug|Any CPU.Build.0 = Debug|Any CPU 23 | {D7ADA016-6E82-4F70-B6CF-B687A3B6F6EA}.Release|Any CPU.ActiveCfg = Release|Any CPU 24 | {D7ADA016-6E82-4F70-B6CF-B687A3B6F6EA}.Release|Any CPU.Build.0 = Release|Any CPU 25 | EndGlobalSection 26 | GlobalSection(SolutionProperties) = preSolution 27 | HideSolutionNode = FALSE 28 | EndGlobalSection 29 | GlobalSection(NestedProjects) = preSolution 30 | {D7ADA016-6E82-4F70-B6CF-B687A3B6F6EA} = {6DCF7BBA-8C8E-4E64-A6F0-3CB2A778DA69} 31 | EndGlobalSection 32 | EndGlobal 33 | -------------------------------------------------------------------------------- /AspNetExtendingIdentityRoles/Views/Roles/Edit.cshtml: -------------------------------------------------------------------------------- 1 | @model AspNetExtendingIdentityRoles.Models.EditRoleViewModel 2 | 3 | @{ 4 | ViewBag.Title = "Edit"; 5 | } 6 | 7 |

Edit

8 | 9 | 10 | @using (Html.BeginForm()) 11 | { 12 | @Html.AntiForgeryToken() 13 | 14 |
15 |

EditRolesViewModel

16 |
17 | @Html.ValidationSummary(true) 18 | 19 | @*Hide the original name away for later:*@ 20 | @Html.HiddenFor(model => model.OriginalRoleName) 21 | 22 |
23 | @Html.LabelFor(model => model.RoleName, new { @class = "control-label col-md-2" }) 24 |
25 | @Html.EditorFor(model => model.RoleName) 26 | @Html.ValidationMessageFor(model => model.RoleName) 27 |
28 |
29 | 30 |
31 | @Html.LabelFor(model => model.Description, new { @class = "control-label col-md-2" }) 32 |
33 | @Html.EditorFor(model => model.Description) 34 | @Html.ValidationMessageFor(model => model.Description) 35 |
36 |
37 | 38 |
39 |
40 | 41 |
42 |
43 |
44 | } 45 | 46 |
47 | @Html.ActionLink("Back to List", "Index") 48 |
49 | 50 | @section Scripts { 51 | @Scripts.Render("~/bundles/jqueryval") 52 | } 53 | -------------------------------------------------------------------------------- /AspNetExtendingIdentityRoles/Views/Roles/Create.cshtml: -------------------------------------------------------------------------------- 1 | @model AspNetExtendingIdentityRoles.Models.RoleViewModel 2 | 3 | @{ 4 | ViewBag.Title = "Create"; 5 | } 6 | 7 |

Create Role

8 | 9 | 10 | @using (Html.BeginForm()) 11 | { 12 | @Html.AntiForgeryToken() 13 | 14 |
15 |

RolesViewModel

16 |
17 | @Html.ValidationSummary(true) 18 | 19 | @if(ViewBag.Message != "") 20 | { 21 |

ViewBag.Message

22 | } 23 |
24 | @Html.LabelFor(model => model.RoleName, new { @class = "control-label col-md-2" }) 25 |
26 | @Html.EditorFor(model => model.RoleName) 27 | @Html.ValidationMessageFor(model => model.RoleName) 28 |
29 |
30 | 31 |
32 | @Html.LabelFor(model => model.Description, new { @class = "control-label col-md-2" }) 33 |
34 | @Html.EditorFor(model => model.Description) 35 | @Html.ValidationMessageFor(model => model.Description) 36 |
37 |
38 | 39 |
40 |
41 | 42 |
43 |
44 |
45 | } 46 | 47 |
48 | @Html.ActionLink("Back to List", "Index") 49 |
50 | 51 | @section Scripts { 52 | @Scripts.Render("~/bundles/jqueryval") 53 | } 54 | -------------------------------------------------------------------------------- /AspNetExtendingIdentityRoles/Views/Web.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 |
7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /AspNetExtendingIdentityRoles/Views/Shared/_Layout.cshtml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | @ViewBag.Title - My ASP.NET Application 7 | @Styles.Render("~/Content/css") 8 | @Scripts.Render("~/bundles/modernizr") 9 | 10 | 11 | 12 | 34 |
35 | @RenderBody() 36 |
37 |
38 |

© @DateTime.Now.Year - My ASP.NET Application

39 |
40 |
41 | 42 | @Scripts.Render("~/bundles/jquery") 43 | @Scripts.Render("~/bundles/bootstrap") 44 | @RenderSection("scripts", required: false) 45 | 46 | 47 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ASP.NET Extending Identity Roles 2 | ====================================== 3 | 4 | This is an example project to accompany a blog post describing how to extend the `AspNet.Identity.EntityFramework.IdentityRole` class as implemented in the ASP.NET MVC 5 Identity system. 5 | 6 | This project builds upon the foundation created by another example, [ASP.NET Role-Based Security Example][3], covered in the article [Extending Identity Accounts and Implementing Role-Based Authentication in ASP.NET MVC 5][1]. You can see in the commit history the basic steps taken to move from the previous project structure to one where I have added some very basic extensions to the `IdentityRole` class. 7 | 8 | In the previous article, we discuss the relative ease with which the `IdentityUser` class may be extended to add additional properties, and the implementation of very basic role management. Unlike `IdentityUser`, extension of the `IdentityRole` class requires a bit more effort, a little insight into the internals of the ASP.NET 5 Identity system, and a few work-arounds. 9 | 10 | You will need to enable Nuget Package Restore in Visual Studio in order to download and restore Nuget packages during build. If you are not sure how to do this, see [Keep Nuget Packages Out of Source Control with Nuget Package Manager Restore][2] 11 | 12 | You will also need to run Entity Framework Migrations `Update-Database` command per the article. The migration files are included in the repo, so you will NOT need to `Enable-Migrations` or run `Add-Migration Init`. 13 | 14 | [1]: http://www.typecastexception.com/post/2013/11/11/Extending-Identity-Accounts-and-Implementing-Role-Based-Authentication-in-ASPNET-MVC-5.aspx "Extending Identity Accounts and Implementing Role-Based Authentication in ASP.NET MVC 5" 15 | 16 | [2]: http://www.typecastexception.com/post/2013/11/10/Keep-Nuget-Packages-Out-of-Source-Control-with-Nuget-Package-Manager-Restore.aspx "Keep Nuget Packages Out of Source Control with Nuget Package Manager Restore" 17 | 18 | [3]: https://github.com/xivSolutions/AspNetRoleBasedSecurityExample "ASP.NET Role-Based Security Example" 19 | 20 | -------------------------------------------------------------------------------- /AspNetExtendingIdentityRoles/Views/Account/Edit.cshtml: -------------------------------------------------------------------------------- 1 | @model AspNetExtendingIdentityRoles.Models.EditUserViewModel 2 | 3 | @{ 4 | ViewBag.Title = "Edit"; 5 | } 6 | 7 |

Edit

8 | 9 | 10 | @using (Html.BeginForm()) 11 | { 12 | @Html.AntiForgeryToken() 13 | 14 |
15 |

EditUserViewModel

16 |
17 | @Html.ValidationSummary(true) 18 |
19 | @Html.LabelFor(model => model.UserName, new { @class = "control-label col-md-2" }) 20 |
21 | @Html.EditorFor(model => model.UserName) 22 | @Html.ValidationMessageFor(model => model.UserName) 23 |
24 |
25 | 26 |
27 | @Html.LabelFor(model => model.FirstName, new { @class = "control-label col-md-2" }) 28 |
29 | @Html.EditorFor(model => model.FirstName) 30 | @Html.ValidationMessageFor(model => model.FirstName) 31 |
32 |
33 | 34 |
35 | @Html.LabelFor(model => model.LastName, new { @class = "control-label col-md-2" }) 36 |
37 | @Html.EditorFor(model => model.LastName) 38 | @Html.ValidationMessageFor(model => model.LastName) 39 |
40 |
41 | 42 |
43 | @Html.LabelFor(model => model.Email, new { @class = "control-label col-md-2" }) 44 |
45 | @Html.EditorFor(model => model.Email) 46 | @Html.ValidationMessageFor(model => model.Email) 47 |
48 |
49 | 50 |
51 |
52 | 53 |
54 |
55 |
56 | } 57 | 58 |
59 | @Html.ActionLink("Back to List", "Index") 60 |
61 | 62 | @section Scripts { 63 | @Scripts.Render("~/bundles/jqueryval") 64 | } 65 | -------------------------------------------------------------------------------- /AspNetExtendingIdentityRoles/Migrations/Configuration.cs: -------------------------------------------------------------------------------- 1 | using AspNetExtendingIdentityRoles.Models; 2 | using System.Data.Entity.Migrations; 3 | 4 | namespace AspNetExtendingIdentityRoles.Migrations 5 | { 6 | using System; 7 | using System.Data.Entity; 8 | using System.Data.Entity.Migrations; 9 | using System.Linq; 10 | 11 | internal sealed class Configuration : DbMigrationsConfiguration 12 | { 13 | public Configuration() 14 | { 15 | AutomaticMigrationsEnabled = true; 16 | } 17 | 18 | 19 | protected override void Seed(ApplicationDbContext context) 20 | { 21 | this.AddUserAndRoles(); 22 | } 23 | 24 | 25 | bool AddUserAndRoles() 26 | { 27 | bool success = false; 28 | 29 | var idManager = new IdentityManager(); 30 | success = idManager.CreateRole("Admin", "Global Access"); 31 | if (!success == true) return success; 32 | 33 | success = idManager.CreateRole("CanEdit", "Edit existing records"); 34 | if (!success == true) return success; 35 | 36 | success = idManager.CreateRole("User", "Restricted to business domain activity"); 37 | if (!success) return success; 38 | 39 | 40 | var newUser = new ApplicationUser() 41 | { 42 | UserName = "jatten", 43 | FirstName = "John", 44 | LastName = "Atten", 45 | Email = "jatten@typecastexception.com" 46 | }; 47 | 48 | // Be careful here - you will need to use a password which will 49 | // be valid under the password rules for the application, 50 | // or the process will abort: 51 | success = idManager.CreateUser(newUser, "Password1"); 52 | if (!success) return success; 53 | 54 | success = idManager.AddUserToRole(newUser.Id, "Admin"); 55 | if (!success) return success; 56 | 57 | success = idManager.AddUserToRole(newUser.Id, "CanEdit"); 58 | if (!success) return success; 59 | 60 | success = idManager.AddUserToRole(newUser.Id, "User"); 61 | if (!success) return success; 62 | 63 | return success; 64 | } 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /AspNetExtendingIdentityRoles/Views/Account/Register.cshtml: -------------------------------------------------------------------------------- 1 | @model AspNetExtendingIdentityRoles.Models.RegisterViewModel 2 | @{ 3 | ViewBag.Title = "Register"; 4 | } 5 | 6 |

@ViewBag.Title.

7 | 8 | @using (Html.BeginForm("Register", "Account", FormMethod.Post, new { @class = "form-horizontal", role = "form" })) 9 | { 10 | @Html.AntiForgeryToken() 11 |

Create a new account.

12 |
13 | @Html.ValidationSummary() 14 |
15 | @Html.LabelFor(m => m.UserName, new { @class = "col-md-2 control-label" }) 16 |
17 | @Html.TextBoxFor(m => m.UserName, new { @class = "form-control" }) 18 |
19 |
20 |
21 | @Html.LabelFor(m => m.Password, new { @class = "col-md-2 control-label" }) 22 |
23 | @Html.PasswordFor(m => m.Password, new { @class = "form-control" }) 24 |
25 |
26 |
27 | @Html.LabelFor(m => m.ConfirmPassword, new { @class = "col-md-2 control-label" }) 28 |
29 | @Html.PasswordFor(m => m.ConfirmPassword, new { @class = "form-control" }) 30 |
31 |
32 | 33 | //Add the LastName, FirstName, and Email Properties: 34 |
35 | @Html.LabelFor(m => m.LastName, new { @class = "col-md-2 control-label" }) 36 |
37 | @Html.TextBoxFor(m => m.LastName, new { @class = "form-control" }) 38 |
39 |
40 | 41 |
42 | @Html.LabelFor(m => m.FirstName, new { @class = "col-md-2 control-label" }) 43 |
44 | @Html.TextBoxFor(m => m.FirstName, new { @class = "form-control" }) 45 |
46 |
47 | 48 |
49 | @Html.LabelFor(m => m.Email, new { @class = "col-md-2 control-label" }) 50 |
51 | @Html.TextBoxFor(m => m.Email, new { @class = "form-control" }) 52 |
53 |
54 | 55 |
56 |
57 | 58 |
59 |
60 | } 61 | 62 | -------------------------------------------------------------------------------- /AspNetExtendingIdentityRoles/Views/Account/Login.cshtml: -------------------------------------------------------------------------------- 1 | @model AspNetExtendingIdentityRoles.Models.LoginViewModel 2 | 3 | @{ 4 | ViewBag.Title = "Log in"; 5 | } 6 | 7 |

@ViewBag.Title.

8 |
9 |
10 |
11 | @using (Html.BeginForm("Login", "Account", new { ReturnUrl = ViewBag.ReturnUrl }, FormMethod.Post, new { @class = "form-horizontal", role = "form" })) 12 | { 13 | @Html.AntiForgeryToken() 14 |

Use a local account to log in.

15 |
16 | @Html.ValidationSummary(true) 17 |
18 | @Html.LabelFor(m => m.UserName, new { @class = "col-md-2 control-label" }) 19 |
20 | @Html.TextBoxFor(m => m.UserName, new { @class = "form-control" }) 21 | @Html.ValidationMessageFor(m => m.UserName) 22 |
23 |
24 |
25 | @Html.LabelFor(m => m.Password, new { @class = "col-md-2 control-label" }) 26 |
27 | @Html.PasswordFor(m => m.Password, new { @class = "form-control" }) 28 | @Html.ValidationMessageFor(m => m.Password) 29 |
30 |
31 |
32 |
33 |
34 | @Html.CheckBoxFor(m => m.RememberMe) 35 | @Html.LabelFor(m => m.RememberMe) 36 |
37 |
38 |
39 |
40 |
41 | 42 |
43 |
44 |

45 | @Html.ActionLink("Register", "Register") if you don't have a local account. 46 |

47 | } 48 |
49 |
50 |
51 | @section Scripts { 52 | @Scripts.Render("~/bundles/jqueryval") 53 | } -------------------------------------------------------------------------------- /AspNetExtendingIdentityRoles/packages.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /AspNetExtendingIdentityRoles/Models/IdentityManager.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNet.Identity.EntityFramework; 2 | using Microsoft.AspNet.Identity; 3 | using System.ComponentModel.DataAnnotations; 4 | using System.Collections.Generic; 5 | using AspNetExtendingIdentityRoles.Models; 6 | using System.Linq; 7 | 8 | namespace AspNetExtendingIdentityRoles.Models 9 | { 10 | public class IdentityManager 11 | { 12 | // Swap ApplicationRole for IdentityRole: 13 | RoleManager _roleManager = new RoleManager( 14 | new RoleStore(new ApplicationDbContext())); 15 | 16 | UserManager _userManager = new UserManager( 17 | new UserStore(new ApplicationDbContext())); 18 | 19 | ApplicationDbContext _db = new ApplicationDbContext(); 20 | 21 | 22 | public bool RoleExists(string name) 23 | { 24 | return _roleManager.RoleExists(name); 25 | } 26 | 27 | 28 | public bool CreateRole(string name, string description = "") 29 | { 30 | // Swap ApplicationRole for IdentityRole: 31 | var idResult = _roleManager.Create(new ApplicationRole(name, description)); 32 | return idResult.Succeeded; 33 | } 34 | 35 | 36 | public bool CreateUser(ApplicationUser user, string password) 37 | { 38 | var idResult = _userManager.Create(user, password); 39 | return idResult.Succeeded; 40 | } 41 | 42 | 43 | public bool AddUserToRole(string userId, string roleName) 44 | { 45 | var idResult = _userManager.AddToRole(userId, roleName); 46 | return idResult.Succeeded; 47 | } 48 | 49 | 50 | public void ClearUserRoles(string userId) 51 | { 52 | var user = _userManager.FindById(userId); 53 | var currentRoles = new List(); 54 | 55 | currentRoles.AddRange(user.Roles); 56 | foreach (var role in currentRoles) 57 | { 58 | _userManager.RemoveFromRole(userId, role.Role.Name); 59 | } 60 | } 61 | 62 | 63 | public void RemoveFromRole(string userId, string roleName) 64 | { 65 | _userManager.RemoveFromRole(userId, roleName); 66 | } 67 | 68 | 69 | public void DeleteRole(string roleId) 70 | { 71 | var roleUsers = _db.Users.Where(u => u.Roles.Any(r => r.RoleId == roleId)); 72 | var role = _db.Roles.Find(roleId); 73 | 74 | foreach (var user in roleUsers) 75 | { 76 | this.RemoveFromRole(user.Id, role.Name); 77 | } 78 | _db.Roles.Remove(role); 79 | _db.SaveChanges(); 80 | } 81 | } 82 | } -------------------------------------------------------------------------------- /AspNetExtendingIdentityRoles/Web.config: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | -------------------------------------------------------------------------------- /AspNetExtendingIdentityRoles/Models/ApplicationDbContext.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNet.Identity.EntityFramework; 2 | using Microsoft.AspNet.Identity; 3 | using System.ComponentModel.DataAnnotations; 4 | using System.Collections.Generic; 5 | using System.Data.Entity; 6 | using System; 7 | using System.Data.Entity.Infrastructure; 8 | using System.Data.Entity.ModelConfiguration; 9 | using System.Data.Entity.ModelConfiguration.Configuration; 10 | using System.Data.Entity.Validation; 11 | using System.Globalization; 12 | using System.Linq; 13 | using System.Linq.Expressions; 14 | using System.Reflection; 15 | using System.Runtime.CompilerServices; 16 | 17 | namespace AspNetExtendingIdentityRoles.Models 18 | { 19 | public class ApplicationDbContext : IdentityDbContext 20 | { 21 | // Add an instance IDbSet using the 'new' keyword: 22 | new public virtual IDbSet Roles { get; set; } 23 | 24 | public ApplicationDbContext() 25 | : base("DefaultConnection") 26 | { 27 | 28 | } 29 | 30 | 31 | protected override void OnModelCreating(DbModelBuilder modelBuilder) 32 | { 33 | if (modelBuilder == null) 34 | { 35 | throw new ArgumentNullException("modelBuilder"); 36 | } 37 | 38 | // Keep this: 39 | modelBuilder.Entity().ToTable("AspNetUsers"); 40 | 41 | // Change TUser to ApplicationUser everywhere else - IdentityUser and ApplicationUser essentially 'share' the AspNetUsers Table in the database: 42 | EntityTypeConfiguration table = 43 | modelBuilder.Entity().ToTable("AspNetUsers"); 44 | 45 | table.Property((ApplicationUser u) => u.UserName).IsRequired(); 46 | 47 | // EF won't let us swap out IdentityUserRole for ApplicationUserRole here: 48 | modelBuilder.Entity().HasMany((ApplicationUser u) => u.Roles); 49 | modelBuilder.Entity().HasKey((IdentityUserRole r) => 50 | new { UserId = r.UserId, RoleId = r.RoleId }).ToTable("AspNetUserRoles"); 51 | 52 | // Leave this alone: 53 | EntityTypeConfiguration entityTypeConfiguration = 54 | modelBuilder.Entity().HasKey((IdentityUserLogin l) => 55 | new { UserId = l.UserId, LoginProvider = l.LoginProvider, ProviderKey = l.ProviderKey }).ToTable("AspNetUserLogins"); 56 | 57 | entityTypeConfiguration.HasRequired((IdentityUserLogin u) => u.User); 58 | EntityTypeConfiguration table1 = modelBuilder.Entity().ToTable("AspNetUserClaims"); 59 | table1.HasRequired((IdentityUserClaim u) => u.User); 60 | 61 | // Add this, so that IdentityRole can share a table with ApplicationRole: 62 | modelBuilder.Entity().ToTable("AspNetRoles"); 63 | 64 | // Change these from IdentityRole to ApplicationRole: 65 | EntityTypeConfiguration entityTypeConfiguration1 = modelBuilder.Entity().ToTable("AspNetRoles"); 66 | entityTypeConfiguration1.Property((ApplicationRole r) => r.Name).IsRequired(); 67 | } 68 | } 69 | } -------------------------------------------------------------------------------- /AspNetExtendingIdentityRoles/Controllers/RolesController.cs: -------------------------------------------------------------------------------- 1 | using AspNetExtendingIdentityRoles.Models; 2 | using System.Collections.Generic; 3 | using System.Data.Entity; 4 | using System.Linq; 5 | using System.Net; 6 | using System.Web.Mvc; 7 | 8 | namespace AspNetExtendingIdentityRoles.Controllers 9 | { 10 | public class RolesController : Controller 11 | { 12 | private ApplicationDbContext _db = new ApplicationDbContext(); 13 | 14 | public ActionResult Index() 15 | { 16 | var rolesList = new List(); 17 | foreach(var role in _db.Roles) 18 | { 19 | var roleModel = new RoleViewModel(role); 20 | rolesList.Add(roleModel); 21 | } 22 | return View(rolesList); 23 | } 24 | 25 | 26 | [Authorize(Roles = "Admin")] 27 | public ActionResult Create(string message = "") 28 | { 29 | ViewBag.Message = message; 30 | return View(); 31 | } 32 | 33 | 34 | [HttpPost] 35 | [Authorize(Roles = "Admin")] 36 | public ActionResult Create([Bind(Include = 37 | "RoleName,Description")]RoleViewModel model) 38 | { 39 | string message = "That role name has already been used"; 40 | if (ModelState.IsValid) 41 | { 42 | var role = new ApplicationRole(model.RoleName, model.Description); 43 | var idManager = new IdentityManager(); 44 | 45 | if(idManager.RoleExists(model.RoleName)) 46 | { 47 | return View(message); 48 | } 49 | else 50 | { 51 | idManager.CreateRole(model.RoleName, model.Description); 52 | return RedirectToAction("Index", "Account"); 53 | } 54 | } 55 | return View(); 56 | } 57 | 58 | 59 | [Authorize(Roles = "Admin")] 60 | public ActionResult Edit(string id) 61 | { 62 | // It's actually the Role.Name tucked into the id param: 63 | var role = _db.Roles.First(r => r.Name == id); 64 | var roleModel = new EditRoleViewModel(role); 65 | return View(roleModel); 66 | } 67 | 68 | 69 | [HttpPost] 70 | [Authorize(Roles = "Admin")] 71 | public ActionResult Edit([Bind(Include = 72 | "RoleName,OriginalRoleName,Description")] EditRoleViewModel model) 73 | { 74 | if (ModelState.IsValid) 75 | { 76 | var role = _db.Roles.First(r => r.Name == model.OriginalRoleName); 77 | role.Name = model.RoleName; 78 | role.Description = model.Description; 79 | _db.Entry(role).State = EntityState.Modified; 80 | _db.SaveChanges(); 81 | return RedirectToAction("Index"); 82 | } 83 | return View(model); 84 | } 85 | 86 | 87 | [Authorize(Roles = "Admin")] 88 | public ActionResult Delete(string id) 89 | { 90 | if (id == null) 91 | { 92 | return new HttpStatusCodeResult(HttpStatusCode.BadRequest); 93 | } 94 | var role = _db.Roles.First(r => r.Name == id); 95 | var model = new RoleViewModel(role); 96 | if (role == null) 97 | { 98 | return HttpNotFound(); 99 | } 100 | return View(model); 101 | } 102 | 103 | 104 | [Authorize(Roles = "Admin")] 105 | [HttpPost, ActionName("Delete")] 106 | public ActionResult DeleteConfirmed(string id) 107 | { 108 | var role = _db.Roles.First(r => r.Name == id); 109 | var idManager = new IdentityManager(); 110 | idManager.DeleteRole(role.Id); 111 | return RedirectToAction("Index"); 112 | } 113 | } 114 | } 115 | -------------------------------------------------------------------------------- /AspNetExtendingIdentityRoles/Migrations/201402130341319_init.cs: -------------------------------------------------------------------------------- 1 | namespace AspNetExtendingIdentityRoles.Migrations 2 | { 3 | using System; 4 | using System.Data.Entity.Migrations; 5 | 6 | public partial class init : DbMigration 7 | { 8 | public override void Up() 9 | { 10 | CreateTable( 11 | "dbo.AspNetRoles", 12 | c => new 13 | { 14 | Id = c.String(nullable: false, maxLength: 128), 15 | Name = c.String(), 16 | Description = c.String(), 17 | Discriminator = c.String(nullable: false, maxLength: 128), 18 | }) 19 | .PrimaryKey(t => t.Id); 20 | 21 | CreateTable( 22 | "dbo.AspNetUsers", 23 | c => new 24 | { 25 | Id = c.String(nullable: false, maxLength: 128), 26 | UserName = c.String(), 27 | PasswordHash = c.String(), 28 | SecurityStamp = c.String(), 29 | FirstName = c.String(), 30 | LastName = c.String(), 31 | Email = c.String(), 32 | Discriminator = c.String(nullable: false, maxLength: 128), 33 | }) 34 | .PrimaryKey(t => t.Id); 35 | 36 | CreateTable( 37 | "dbo.AspNetUserClaims", 38 | c => new 39 | { 40 | Id = c.Int(nullable: false, identity: true), 41 | ClaimType = c.String(), 42 | ClaimValue = c.String(), 43 | User_Id = c.String(nullable: false, maxLength: 128), 44 | }) 45 | .PrimaryKey(t => t.Id) 46 | .ForeignKey("dbo.AspNetUsers", t => t.User_Id, cascadeDelete: true) 47 | .Index(t => t.User_Id); 48 | 49 | CreateTable( 50 | "dbo.AspNetUserLogins", 51 | c => new 52 | { 53 | UserId = c.String(nullable: false, maxLength: 128), 54 | LoginProvider = c.String(nullable: false, maxLength: 128), 55 | ProviderKey = c.String(nullable: false, maxLength: 128), 56 | }) 57 | .PrimaryKey(t => new { t.UserId, t.LoginProvider, t.ProviderKey }) 58 | .ForeignKey("dbo.AspNetUsers", t => t.UserId, cascadeDelete: true) 59 | .Index(t => t.UserId); 60 | 61 | CreateTable( 62 | "dbo.AspNetUserRoles", 63 | c => new 64 | { 65 | UserId = c.String(nullable: false, maxLength: 128), 66 | RoleId = c.String(nullable: false, maxLength: 128), 67 | }) 68 | .PrimaryKey(t => new { t.UserId, t.RoleId }) 69 | .ForeignKey("dbo.AspNetRoles", t => t.RoleId, cascadeDelete: true) 70 | .ForeignKey("dbo.AspNetUsers", t => t.UserId, cascadeDelete: true) 71 | .Index(t => t.RoleId) 72 | .Index(t => t.UserId); 73 | 74 | } 75 | 76 | public override void Down() 77 | { 78 | DropForeignKey("dbo.AspNetUserClaims", "User_Id", "dbo.AspNetUsers"); 79 | DropForeignKey("dbo.AspNetUserRoles", "UserId", "dbo.AspNetUsers"); 80 | DropForeignKey("dbo.AspNetUserRoles", "RoleId", "dbo.AspNetRoles"); 81 | DropForeignKey("dbo.AspNetUserLogins", "UserId", "dbo.AspNetUsers"); 82 | DropIndex("dbo.AspNetUserClaims", new[] { "User_Id" }); 83 | DropIndex("dbo.AspNetUserRoles", new[] { "UserId" }); 84 | DropIndex("dbo.AspNetUserRoles", new[] { "RoleId" }); 85 | DropIndex("dbo.AspNetUserLogins", new[] { "UserId" }); 86 | DropTable("dbo.AspNetUserRoles"); 87 | DropTable("dbo.AspNetUserLogins"); 88 | DropTable("dbo.AspNetUserClaims"); 89 | DropTable("dbo.AspNetUsers"); 90 | DropTable("dbo.AspNetRoles"); 91 | } 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /AspNetExtendingIdentityRoles/Scripts/respond.min.js: -------------------------------------------------------------------------------- 1 | /* NUGET: BEGIN LICENSE TEXT 2 | * 3 | * Microsoft grants you the right to use these script files for the sole 4 | * purpose of either: (i) interacting through your browser with the Microsoft 5 | * website or online service, subject to the applicable licensing or use 6 | * terms; or (ii) using the files as included with a Microsoft product subject 7 | * to that product's license terms. Microsoft reserves all other rights to the 8 | * files not expressly granted by Microsoft, whether by implication, estoppel 9 | * or otherwise. Insofar as a script file is dual licensed under GPL, 10 | * Microsoft neither took the code under GPL nor distributes it thereunder but 11 | * under the terms set out in this paragraph. All notices and licenses 12 | * below are for informational purposes only. 13 | * 14 | * NUGET: END LICENSE TEXT */ 15 | /*! matchMedia() polyfill - Test a CSS media type/query in JS. Authors & copyright (c) 2012: Scott Jehl, Paul Irish, Nicholas Zakas. Dual MIT/BSD license */ 16 | /*! NOTE: If you're already including a window.matchMedia polyfill via Modernizr or otherwise, you don't need this part */ 17 | window.matchMedia=window.matchMedia||(function(e,f){var c,a=e.documentElement,b=a.firstElementChild||a.firstChild,d=e.createElement("body"),g=e.createElement("div");g.id="mq-test-1";g.style.cssText="position:absolute;top:-100em";d.style.background="none";d.appendChild(g);return function(h){g.innerHTML='­';a.insertBefore(d,b);c=g.offsetWidth==42;a.removeChild(d);return{matches:c,media:h}}})(document); 18 | 19 | /*! Respond.js v1.2.0: min/max-width media query polyfill. (c) Scott Jehl. MIT/GPLv2 Lic. j.mp/respondjs */ 20 | (function(e){e.respond={};respond.update=function(){};respond.mediaQueriesSupported=e.matchMedia&&e.matchMedia("only all").matches;if(respond.mediaQueriesSupported){return}var w=e.document,s=w.documentElement,i=[],k=[],q=[],o={},h=30,f=w.getElementsByTagName("head")[0]||s,g=w.getElementsByTagName("base")[0],b=f.getElementsByTagName("link"),d=[],a=function(){var D=b,y=D.length,B=0,A,z,C,x;for(;B-1,minw:F.match(/\(min\-width:[\s]*([\s]*[0-9\.]+)(px|em)[\s]*\)/)&&parseFloat(RegExp.$1)+(RegExp.$2||""),maxw:F.match(/\(max\-width:[\s]*([\s]*[0-9\.]+)(px|em)[\s]*\)/)&&parseFloat(RegExp.$1)+(RegExp.$2||"")})}}j()},l,r,v=function(){var z,A=w.createElement("div"),x=w.body,y=false;A.style.cssText="position:absolute;font-size:1em;width:1em";if(!x){x=y=w.createElement("body");x.style.background="none"}x.appendChild(A);s.insertBefore(x,s.firstChild);z=A.offsetWidth;if(y){s.removeChild(x)}else{x.removeChild(A)}z=p=parseFloat(z);return z},p,j=function(I){var x="clientWidth",B=s[x],H=w.compatMode==="CSS1Compat"&&B||w.body[x]||B,D={},G=b[b.length-1],z=(new Date()).getTime();if(I&&l&&z-l-1?(p||v()):1)}if(!!J){J=parseFloat(J)*(J.indexOf(y)>-1?(p||v()):1)}if(!K.hasquery||(!A||!L)&&(A||H>=C)&&(L||H<=J)){if(!D[K.media]){D[K.media]=[]}D[K.media].push(k[K.rules])}}for(var E in q){if(q[E]&&q[E].parentNode===f){f.removeChild(q[E])}}for(var E in D){var M=w.createElement("style"),F=D[E].join("\n");M.type="text/css";M.media=E;f.insertBefore(M,G.nextSibling);if(M.styleSheet){M.styleSheet.cssText=F}else{M.appendChild(w.createTextNode(F))}q.push(M)}},n=function(x,z){var y=c();if(!y){return}y.open("GET",x,true);y.onreadystatechange=function(){if(y.readyState!=4||y.status!=200&&y.status!=304){return}z(y.responseText)};if(y.readyState==4){return}y.send(null)},c=(function(){var x=false;try{x=new XMLHttpRequest()}catch(y){x=new ActiveXObject("Microsoft.XMLHTTP")}return function(){return x}})();a();respond.update=a;function t(){j(true)}if(e.addEventListener){e.addEventListener("resize",t,false)}else{if(e.attachEvent){e.attachEvent("onresize",t)}}})(this); -------------------------------------------------------------------------------- /AspNetExtendingIdentityRoles/Scripts/jquery.validate.unobtrusive.min.js: -------------------------------------------------------------------------------- 1 | /* NUGET: BEGIN LICENSE TEXT 2 | * 3 | * Microsoft grants you the right to use these script files for the sole 4 | * purpose of either: (i) interacting through your browser with the Microsoft 5 | * website or online service, subject to the applicable licensing or use 6 | * terms; or (ii) using the files as included with a Microsoft product subject 7 | * to that product's license terms. Microsoft reserves all other rights to the 8 | * files not expressly granted by Microsoft, whether by implication, estoppel 9 | * or otherwise. Insofar as a script file is dual licensed under GPL, 10 | * Microsoft neither took the code under GPL nor distributes it thereunder but 11 | * under the terms set out in this paragraph. All notices and licenses 12 | * below are for informational purposes only. 13 | * 14 | * NUGET: END LICENSE TEXT */ 15 | /* 16 | ** Unobtrusive validation support library for jQuery and jQuery Validate 17 | ** Copyright (C) Microsoft Corporation. All rights reserved. 18 | */ 19 | (function(a){var d=a.validator,b,e="unobtrusiveValidation";function c(a,b,c){a.rules[b]=c;if(a.message)a.messages[b]=a.message}function j(a){return a.replace(/^\s+|\s+$/g,"").split(/\s*,\s*/g)}function f(a){return a.replace(/([!"#$%&'()*+,./:;<=>?@\[\\\]^`{|}~])/g,"\\$1")}function h(a){return a.substr(0,a.lastIndexOf(".")+1)}function g(a,b){if(a.indexOf("*.")===0)a=a.replace("*.",b);return a}function m(c,e){var b=a(this).find("[data-valmsg-for='"+f(e[0].name)+"']"),d=b.attr("data-valmsg-replace"),g=d?a.parseJSON(d)!==false:null;b.removeClass("field-validation-valid").addClass("field-validation-error");c.data("unobtrusiveContainer",b);if(g){b.empty();c.removeClass("input-validation-error").appendTo(b)}else c.hide()}function l(e,d){var c=a(this).find("[data-valmsg-summary=true]"),b=c.find("ul");if(b&&b.length&&d.errorList.length){b.empty();c.addClass("validation-summary-errors").removeClass("validation-summary-valid");a.each(d.errorList,function(){a("
  • ").html(this.message).appendTo(b)})}}function k(d){var b=d.data("unobtrusiveContainer"),c=b.attr("data-valmsg-replace"),e=c?a.parseJSON(c):null;if(b){b.addClass("field-validation-valid").removeClass("field-validation-error");d.removeData("unobtrusiveContainer");e&&b.empty()}}function n(){var b=a(this);b.data("validator").resetForm();b.find(".validation-summary-errors").addClass("validation-summary-valid").removeClass("validation-summary-errors");b.find(".field-validation-error").addClass("field-validation-valid").removeClass("field-validation-error").removeData("unobtrusiveContainer").find(">*").removeData("unobtrusiveContainer")}function i(c){var b=a(c),d=b.data(e),f=a.proxy(n,c);if(!d){d={options:{errorClass:"input-validation-error",errorElement:"span",errorPlacement:a.proxy(m,c),invalidHandler:a.proxy(l,c),messages:{},rules:{},success:a.proxy(k,c)},attachValidation:function(){b.unbind("reset."+e,f).bind("reset."+e,f).validate(this.options)},validate:function(){b.validate();return b.valid()}};b.data(e,d)}return d}d.unobtrusive={adapters:[],parseElement:function(b,h){var d=a(b),f=d.parents("form")[0],c,e,g;if(!f)return;c=i(f);c.options.rules[b.name]=e={};c.options.messages[b.name]=g={};a.each(this.adapters,function(){var c="data-val-"+this.name,i=d.attr(c),h={};if(i!==undefined){c+="-";a.each(this.params,function(){h[this]=d.attr(c+this)});this.adapt({element:b,form:f,message:i,params:h,rules:e,messages:g})}});a.extend(e,{__dummy__:true});!h&&c.attachValidation()},parse:function(b){var c=a(b).parents("form").andSelf().add(a(b).find("form")).filter("form");a(b).find(":input").filter("[data-val=true]").each(function(){d.unobtrusive.parseElement(this,true)});c.each(function(){var a=i(this);a&&a.attachValidation()})}};b=d.unobtrusive.adapters;b.add=function(c,a,b){if(!b){b=a;a=[]}this.push({name:c,params:a,adapt:b});return this};b.addBool=function(a,b){return this.add(a,function(d){c(d,b||a,true)})};b.addMinMax=function(e,g,f,a,d,b){return this.add(e,[d||"min",b||"max"],function(b){var e=b.params.min,d=b.params.max;if(e&&d)c(b,a,[e,d]);else if(e)c(b,g,e);else d&&c(b,f,d)})};b.addSingleVal=function(a,b,d){return this.add(a,[b||"val"],function(e){c(e,d||a,e.params[b])})};d.addMethod("__dummy__",function(){return true});d.addMethod("regex",function(b,c,d){var a;if(this.optional(c))return true;a=(new RegExp(d)).exec(b);return a&&a.index===0&&a[0].length===b.length});d.addMethod("nonalphamin",function(c,d,b){var a;if(b){a=c.match(/\W/g);a=a&&a.length>=b}return a});if(d.methods.extension){b.addSingleVal("accept","mimtype");b.addSingleVal("extension","extension")}else b.addSingleVal("extension","extension","accept");b.addSingleVal("regex","pattern");b.addBool("creditcard").addBool("date").addBool("digits").addBool("email").addBool("number").addBool("url");b.addMinMax("length","minlength","maxlength","rangelength").addMinMax("range","min","max","range");b.add("equalto",["other"],function(b){var i=h(b.element.name),j=b.params.other,d=g(j,i),e=a(b.form).find(":input").filter("[name='"+f(d)+"']")[0];c(b,"equalTo",e)});b.add("required",function(a){(a.element.tagName.toUpperCase()!=="INPUT"||a.element.type.toUpperCase()!=="CHECKBOX")&&c(a,"required",true)});b.add("remote",["url","type","additionalfields"],function(b){var d={url:b.params.url,type:b.params.type||"GET",data:{}},e=h(b.element.name);a.each(j(b.params.additionalfields||b.element.name),function(i,h){var c=g(h,e);d.data[c]=function(){return a(b.form).find(":input").filter("[name='"+f(c)+"']").val()}});c(b,"remote",d)});b.add("password",["min","nonalphamin","regex"],function(a){a.params.min&&c(a,"minlength",a.params.min);a.params.nonalphamin&&c(a,"nonalphamin",a.params.nonalphamin);a.params.regex&&c(a,"regex",a.params.regex)});a(function(){d.unobtrusive.parse(document)})})(jQuery); 20 | -------------------------------------------------------------------------------- /AspNetExtendingIdentityRoles/Project_Readme.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Your ASP.NET application 6 | 95 | 96 | 97 | 98 | 102 | 103 |
    104 |
    105 |

    This application consists of:

    106 |
      107 |
    • Sample pages showing basic nav between Home, About, and Contact
    • 108 |
    • Theming using Bootstrap
    • 109 |
    • Authentication, if selected, shows how to register and sign in
    • 110 |
    • ASP.NET features managed using NuGet
    • 111 |
    112 |
    113 | 114 | 131 | 132 |
    133 |

    Deploy

    134 | 139 |
    140 | 141 |
    142 |

    Get help

    143 | 147 |
    148 |
    149 | 150 | 151 | -------------------------------------------------------------------------------- /AspNetExtendingIdentityRoles/Models/AccountViewModels.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel.DataAnnotations; 2 | 3 | // New namespace imports: 4 | using Microsoft.AspNet.Identity.EntityFramework; 5 | using System.Collections.Generic; 6 | 7 | namespace AspNetExtendingIdentityRoles.Models 8 | { 9 | public class ManageUserViewModel 10 | { 11 | [Required] 12 | [DataType(DataType.Password)] 13 | [Display(Name = "Current password")] 14 | public string OldPassword { get; set; } 15 | 16 | [Required] 17 | [StringLength(100, ErrorMessage = 18 | "The {0} must be at least {2} characters long.", MinimumLength = 6)] 19 | [DataType(DataType.Password)] 20 | [Display(Name = "New password")] 21 | public string NewPassword { get; set; } 22 | 23 | [DataType(DataType.Password)] 24 | [Display(Name = "Confirm new password")] 25 | [Compare("NewPassword", ErrorMessage = 26 | "The new password and confirmation password do not match.")] 27 | public string ConfirmPassword { get; set; } 28 | } 29 | 30 | 31 | public class LoginViewModel 32 | { 33 | [Required] 34 | [Display(Name = "User name")] 35 | public string UserName { get; set; } 36 | 37 | [Required] 38 | [DataType(DataType.Password)] 39 | [Display(Name = "Password")] 40 | public string Password { get; set; } 41 | 42 | [Display(Name = "Remember me?")] 43 | public bool RememberMe { get; set; } 44 | } 45 | 46 | 47 | public class RegisterViewModel 48 | { 49 | [Required] 50 | [Display(Name = "User name")] 51 | public string UserName { get; set; } 52 | 53 | [Required] 54 | [StringLength(100, ErrorMessage = 55 | "The {0} must be at least {2} characters long.", MinimumLength = 6)] 56 | [DataType(DataType.Password)] 57 | [Display(Name = "Password")] 58 | public string Password { get; set; } 59 | 60 | [DataType(DataType.Password)] 61 | [Display(Name = "Confirm password")] 62 | [Compare("Password", ErrorMessage = 63 | "The password and confirmation password do not match.")] 64 | public string ConfirmPassword { get; set; } 65 | 66 | // New Fields added to extend Application User class: 67 | 68 | [Required] 69 | [Display(Name = "First Name")] 70 | public string FirstName { get; set; } 71 | 72 | [Required] 73 | [Display(Name = "Last Name")] 74 | public string LastName { get; set; } 75 | 76 | [Required] 77 | public string Email { get; set; } 78 | 79 | // Return a pre-poulated instance of AppliationUser: 80 | public ApplicationUser GetUser() 81 | { 82 | var user = new ApplicationUser() 83 | { 84 | UserName = this.UserName, 85 | FirstName = this.FirstName, 86 | LastName = this.LastName, 87 | Email = this.Email, 88 | }; 89 | return user; 90 | } 91 | } 92 | 93 | 94 | public class EditUserViewModel 95 | { 96 | public EditUserViewModel() { } 97 | 98 | // Allow Initialization with an instance of ApplicationUser: 99 | public EditUserViewModel(ApplicationUser user) 100 | { 101 | this.UserName = user.UserName; 102 | this.FirstName = user.FirstName; 103 | this.LastName = user.LastName; 104 | this.Email = user.Email; 105 | } 106 | 107 | [Required] 108 | [Display(Name = "User Name")] 109 | public string UserName { get; set; } 110 | 111 | [Required] 112 | [Display(Name = "First Name")] 113 | public string FirstName { get; set; } 114 | 115 | [Required] 116 | [Display(Name = "Last Name")] 117 | public string LastName { get; set; } 118 | 119 | [Required] 120 | public string Email { get; set; } 121 | } 122 | 123 | 124 | public class SelectUserRolesViewModel 125 | { 126 | public SelectUserRolesViewModel() 127 | { 128 | this.Roles = new List(); 129 | } 130 | 131 | 132 | // Enable initialization with an instance of ApplicationUser: 133 | public SelectUserRolesViewModel(ApplicationUser user) 134 | : this() 135 | { 136 | this.UserName = user.UserName; 137 | this.FirstName = user.FirstName; 138 | this.LastName = user.LastName; 139 | 140 | var Db = new ApplicationDbContext(); 141 | 142 | // Add all available roles to the list of EditorViewModels: 143 | var allRoles = Db.Roles; 144 | foreach (var role in allRoles) 145 | { 146 | // An EditorViewModel will be used by Editor Template: 147 | var rvm = new SelectRoleEditorViewModel(role); 148 | this.Roles.Add(rvm); 149 | } 150 | 151 | // Set the Selected property to true for those roles for 152 | // which the current user is a member: 153 | foreach (var userRole in user.Roles) 154 | { 155 | var checkUserRole = 156 | this.Roles.Find(r => r.RoleName == userRole.Role.Name); 157 | checkUserRole.Selected = true; 158 | } 159 | } 160 | 161 | public string UserName { get; set; } 162 | public string FirstName { get; set; } 163 | public string LastName { get; set; } 164 | public List Roles { get; set; } 165 | } 166 | 167 | // Used to display a single role with a checkbox, within a list structure: 168 | public class SelectRoleEditorViewModel 169 | { 170 | public SelectRoleEditorViewModel() { } 171 | 172 | // Update this to accept an argument of type ApplicationRole: 173 | public SelectRoleEditorViewModel(ApplicationRole role) 174 | { 175 | this.RoleName = role.Name; 176 | 177 | // Assign the new Descrption property: 178 | this.Description = role.Description; 179 | } 180 | 181 | public bool Selected { get; set; } 182 | 183 | [Required] 184 | public string RoleName { get; set; } 185 | 186 | // Add the new Description property: 187 | public string Description { get; set; } 188 | } 189 | 190 | 191 | public class RoleViewModel 192 | { 193 | public string RoleName { get; set; } 194 | public string Description { get; set; } 195 | 196 | public RoleViewModel() { } 197 | public RoleViewModel(ApplicationRole role) 198 | { 199 | this.RoleName = role.Name; 200 | this.Description = role.Description; 201 | } 202 | } 203 | 204 | 205 | public class EditRoleViewModel 206 | { 207 | public string OriginalRoleName { get; set; } 208 | public string RoleName { get; set; } 209 | public string Description { get; set; } 210 | 211 | public EditRoleViewModel() { } 212 | public EditRoleViewModel(ApplicationRole role) 213 | { 214 | this.OriginalRoleName = role.Name; 215 | this.RoleName = role.Name; 216 | this.Description = role.Description; 217 | } 218 | } 219 | } -------------------------------------------------------------------------------- /.nuget/NuGet.targets: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | $(MSBuildProjectDirectory)\..\ 5 | 6 | 7 | false 8 | 9 | 10 | false 11 | 12 | 13 | true 14 | 15 | 16 | false 17 | 18 | 19 | 20 | 21 | 22 | 26 | 27 | 28 | 29 | 30 | $([System.IO.Path]::Combine($(SolutionDir), ".nuget")) 31 | $([System.IO.Path]::Combine($(ProjectDir), "packages.config")) 32 | 33 | 34 | 35 | 36 | $(SolutionDir).nuget 37 | packages.config 38 | 39 | 40 | 41 | 42 | $(NuGetToolsPath)\NuGet.exe 43 | @(PackageSource) 44 | 45 | "$(NuGetExePath)" 46 | mono --runtime=v4.0.30319 $(NuGetExePath) 47 | 48 | $(TargetDir.Trim('\\')) 49 | 50 | -RequireConsent 51 | -NonInteractive 52 | 53 | "$(SolutionDir) " 54 | "$(SolutionDir)" 55 | 56 | 57 | $(NuGetCommand) install "$(PackagesConfig)" -source "$(PackageSources)" $(NonInteractiveSwitch) $(RequireConsentSwitch) -solutionDir $(PaddedSolutionDir) 58 | $(NuGetCommand) pack "$(ProjectPath)" -Properties "Configuration=$(Configuration);Platform=$(Platform)" $(NonInteractiveSwitch) -OutputDirectory "$(PackageOutputDir)" -symbols 59 | 60 | 61 | 62 | RestorePackages; 63 | $(BuildDependsOn); 64 | 65 | 66 | 67 | 68 | $(BuildDependsOn); 69 | BuildPackage; 70 | 71 | 72 | 73 | 74 | 75 | 76 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 91 | 92 | 95 | 96 | 97 | 98 | 100 | 101 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 133 | 134 | 135 | 136 | -------------------------------------------------------------------------------- /AspNetExtendingIdentityRoles/Migrations/201402130341319_init.resx: -------------------------------------------------------------------------------- 1 | 2 | 3 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | text/microsoft-resx 110 | 111 | 112 | 2.0 113 | 114 | 115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 116 | 117 | 118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 119 | 120 | 121 | H4sIAAAAAAAEAN1cy27cNhTdF+g/CFolBTKynU0azCRwxnZrNLYDj5NtQEucMVGJUkWOO/62LvpJ/YWSelIiKVEjaR7ZGDZFnvvg4SV1den//vl3+nET+NYzjAkK8cw+nZzYFsRu6CG8mtlrunzzzv744eefppdesLG+5f3e8n5sJCYz+4nS6L3jEPcJBoBMAuTGIQmXdOKGgQO80Dk7OfnVOT11IIOwGZZlTe/XmKIAJn+wP+chdmFE18C/CT3ok6ydPVkkqNYtCCCJgAtn9jmJbiG93FCIuZLXHmRQ9OU+9CGZpMNt69xHgKm2gP7StgDGIQWUKf7+K4ELGod4tYhYA/AfXiLI+i2BT2Bm0Puyu6ltJ2fcNqccuJVv7MJqZvdlYhRXL7GdmR1FPnITdG6qbX0CBPLnqZUT0Q8iEsP6EocRjOlLhnQBiRujKNUzQ6Axc6Vt3YDNZ4hX9Glms19t6wptoJe3ZE76ihGjBxtE4zX70xG1dkq1G41pUPYP+FJpEPS/h8tifFUwF10fWDebj9Fae3r2zsja27Xvg0cfFs+dRpn85758LBCGsT7WEiZ52GjFFYoJHciUjg78DPYl+TIAyB9bbOcFwydr7gMU7H7VXGP69kxhjxBdFzSM4W8QwxhQ6H0BlMIYl8q3uTwxjAsbeMloJH0D/noEUbfgGa0Sf9SEpqvwHvrJQ/KEIsVKTDT7nna9isOAR0jF9Cc9vi/CdexyE8LGbg8gXkE6APN+5FDN7RshXMuCvgBC/g5j73dAnkYXtoDuOmazt6AgiHbI9YR9ZFi25zRuYXu+KExV/RyuEG5XNenWqGrZo1FVoVtXVZMzbqumvFejokWHRj3LXio1t4ofienbBBE+WA4kyq6JDNb8jDzuAYMReWemSfdQlWu263BVM3PX4is+G114vy2108pt2lIVC7z3ktj2DajDiuAittmF90XtXN/90Sp9wTYJs2nPhjCb/GgiVdlLxane5O+wGbRq2Zn554SELkrU0+0G3xXnykvsWWaLVP02m24z1s3ap4i/A7Pmmf2L5NhWMcXuqHlprkk4tetr8Q5fQB9SaJ27aTppDogLPJmJzH9etYUtXxhzWcCfs8mlMUCYymsdYRdFwDeyozba8LTOtSvk1J9cwAhiLtRovkwU0MY1p5BVc12bp6aOQENzdpbL24Q1irWuJk0aMLajphwqdPm/g2amZMaOiSnNlYl89Sa6L14aB01FdB+Jl8cfMSUz9sHLo42Xwqu8CWdUWSw1adJ055bUVKUPds1NrUPTQxObBMqmAMZy3v7ikT+EGyq5lA9cQFrNC5SHMOWeIDmsCiK5rQlRmJgOsG2IncDyvE0jYnYU7ADb5ssyWNZAhUluUDg7iwudm99Y6yQ0PhsXNqq9JsUL49OwBljCrNCede/oLeH1qtlZmoNah6OaxqKMCYaekg9nAqwSaggHmbBJc2LocGYYzkH7YJKYZG72lG4P67KLaYzKI6qhsxT71gDeyt/Tiy2neDZ10kKLrGHqaCoypjcgihBeCRUaWYu1SMsz5m8W3asfghTDcYmiCKLQtpBEwxisYO0pE800Tb5VXwAKHgHP+My9QOrWZYPNRYr7rDyD+VaR9+a/Z5t5e7HKpF7ZIR/7MtwrZnXAz47Jd1YFH9TDLV5FA3wQK76yzUN/HWD9UVY/ulJFIsJUHijxmM89lBwjk0+witqWCh7ieAHCgFmtQpw6Nf9IR2FphrpM4TXhv98tX5nMpdj4+khmMv3qKY5PW3bu6a4OPjz/SsyunsB3Suv8eRnFjGJcdW8ZMdapttkOM6gePs4KEQqgRBCh2RyrrGgSocpWc6SsQkmEyZo6R930cHT0UZeb0Sfq7pJTXJbMg7LVHKlaUCKiVZ+YI9aqRkTI2qOD3iMOM8Jo94g9LMIB9ojsxWbMOVQUPHaeSA3GOGtbKGQUQYTmjlhZqaIElrUfJDGyTNOYxFDUE3UmhgajKWzXyaHLwetRatU7lZNAc/2SHrNSklPZBfT1TQdClXHeq5vLbDoTpdsrwzA8yb86iii6L5Hjz2Q1r9SyJWQJt55RP0PpHNl5Wk0K6U3pNdmZRvtCAqH+/iZosLVy2g+BW29aer3qeUOZAlL6sN6lIGCRRqylC6dZ6q79lpeUy0u72FYezdhR9IVQGEx4h8niL3/uI+bDssMNwGgJCX0I/4R4Zp+dnJ7V7oVtcUfLIcTzmy9q6VMMuyiYx88gdp9ALBfM9bi6lIO+CsDmtYhkUoKuuG7WD696KO5l9pHcghhsUsvXywEmQnWRoReg8rJCL0Tp5lovtPpltF5glftlx70g9nQhDfFo33rlrOMKke6g9Zoa+Z5ZL7jitLH7Of7hr24MFmOVNzMGQ1dcvNglDY7musJgDq/eRhjY14MWyO+n7LKhbqhvgX7vis69lLwfV9mmeZl7+glzHxXn+nqinuXMvQimSSmNXiL8I5erH1II2ze/9hHAjPl1MPGrY9n5IREsq5/uV/Z+dBTTfcxTc0yTWx2cZLXEZv76JhUUaj5tqFJ/beX4aUJzZnuPISNBenRMc+TqamGdsJS9WmFZAl0rTF1D2iQsY2ajxKxPs1h1TWx70b9ZzX+zbHUdfOvNAKOLAc2S1bO7z9sD2tribtcEmu8cHMP1AHGG5XLBLoXujTXzx3IRoD8vdu2KEUv9+zujEjc1nzFHqeWXP7qxnVL4B4xsvyZoVULwEiUM3coeWfS5xssw36trGuVdahmUG0iBxzbQ85iiJXApe+xCQpL/6pCVQF0Gj9C7xndrGq0pMxkGj34lo8e3/Cb5yYWFqs7Tu+SbExnCBKYmYibAO/xpjXyv0PtKkerRQPCzRJan5nNJeb569VIg3YbYEChzX3EEeoBB5DMwcocX4BnqdWv3YdVj0wsEVjEISIZRjmd/Mvp5webD/xa6be1CVAAA 122 | 123 | 124 | dbo 125 | 126 | -------------------------------------------------------------------------------- /AspNetExtendingIdentityRoles/Scripts/respond.js: -------------------------------------------------------------------------------- 1 | /* NUGET: BEGIN LICENSE TEXT 2 | * 3 | * Microsoft grants you the right to use these script files for the sole 4 | * purpose of either: (i) interacting through your browser with the Microsoft 5 | * website or online service, subject to the applicable licensing or use 6 | * terms; or (ii) using the files as included with a Microsoft product subject 7 | * to that product's license terms. Microsoft reserves all other rights to the 8 | * files not expressly granted by Microsoft, whether by implication, estoppel 9 | * or otherwise. Insofar as a script file is dual licensed under GPL, 10 | * Microsoft neither took the code under GPL nor distributes it thereunder but 11 | * under the terms set out in this paragraph. All notices and licenses 12 | * below are for informational purposes only. 13 | * 14 | * NUGET: END LICENSE TEXT */ 15 | /*! matchMedia() polyfill - Test a CSS media type/query in JS. Authors & copyright (c) 2012: Scott Jehl, Paul Irish, Nicholas Zakas. Dual MIT/BSD license */ 16 | /*! NOTE: If you're already including a window.matchMedia polyfill via Modernizr or otherwise, you don't need this part */ 17 | window.matchMedia = window.matchMedia || (function(doc, undefined){ 18 | 19 | var bool, 20 | docElem = doc.documentElement, 21 | refNode = docElem.firstElementChild || docElem.firstChild, 22 | // fakeBody required for 23 | fakeBody = doc.createElement('body'), 24 | div = doc.createElement('div'); 25 | 26 | div.id = 'mq-test-1'; 27 | div.style.cssText = "position:absolute;top:-100em"; 28 | fakeBody.style.background = "none"; 29 | fakeBody.appendChild(div); 30 | 31 | return function(q){ 32 | 33 | div.innerHTML = '­'; 34 | 35 | docElem.insertBefore(fakeBody, refNode); 36 | bool = div.offsetWidth == 42; 37 | docElem.removeChild(fakeBody); 38 | 39 | return { matches: bool, media: q }; 40 | }; 41 | 42 | })(document); 43 | 44 | 45 | 46 | 47 | /*! Respond.js v1.2.0: min/max-width media query polyfill. (c) Scott Jehl. MIT/GPLv2 Lic. j.mp/respondjs */ 48 | (function( win ){ 49 | //exposed namespace 50 | win.respond = {}; 51 | 52 | //define update even in native-mq-supporting browsers, to avoid errors 53 | respond.update = function(){}; 54 | 55 | //expose media query support flag for external use 56 | respond.mediaQueriesSupported = win.matchMedia && win.matchMedia( "only all" ).matches; 57 | 58 | //if media queries are supported, exit here 59 | if( respond.mediaQueriesSupported ){ return; } 60 | 61 | //define vars 62 | var doc = win.document, 63 | docElem = doc.documentElement, 64 | mediastyles = [], 65 | rules = [], 66 | appendedEls = [], 67 | parsedSheets = {}, 68 | resizeThrottle = 30, 69 | head = doc.getElementsByTagName( "head" )[0] || docElem, 70 | base = doc.getElementsByTagName( "base" )[0], 71 | links = head.getElementsByTagName( "link" ), 72 | requestQueue = [], 73 | 74 | //loop stylesheets, send text content to translate 75 | ripCSS = function(){ 76 | var sheets = links, 77 | sl = sheets.length, 78 | i = 0, 79 | //vars for loop: 80 | sheet, href, media, isCSS; 81 | 82 | for( ; i < sl; i++ ){ 83 | sheet = sheets[ i ], 84 | href = sheet.href, 85 | media = sheet.media, 86 | isCSS = sheet.rel && sheet.rel.toLowerCase() === "stylesheet"; 87 | 88 | //only links plz and prevent re-parsing 89 | if( !!href && isCSS && !parsedSheets[ href ] ){ 90 | // selectivizr exposes css through the rawCssText expando 91 | if (sheet.styleSheet && sheet.styleSheet.rawCssText) { 92 | translate( sheet.styleSheet.rawCssText, href, media ); 93 | parsedSheets[ href ] = true; 94 | } else { 95 | if( (!/^([a-zA-Z:]*\/\/)/.test( href ) && !base) 96 | || href.replace( RegExp.$1, "" ).split( "/" )[0] === win.location.host ){ 97 | requestQueue.push( { 98 | href: href, 99 | media: media 100 | } ); 101 | } 102 | } 103 | } 104 | } 105 | makeRequests(); 106 | }, 107 | 108 | //recurse through request queue, get css text 109 | makeRequests = function(){ 110 | if( requestQueue.length ){ 111 | var thisRequest = requestQueue.shift(); 112 | 113 | ajax( thisRequest.href, function( styles ){ 114 | translate( styles, thisRequest.href, thisRequest.media ); 115 | parsedSheets[ thisRequest.href ] = true; 116 | makeRequests(); 117 | } ); 118 | } 119 | }, 120 | 121 | //find media blocks in css text, convert to style blocks 122 | translate = function( styles, href, media ){ 123 | var qs = styles.match( /@media[^\{]+\{([^\{\}]*\{[^\}\{]*\})+/gi ), 124 | ql = qs && qs.length || 0, 125 | //try to get CSS path 126 | href = href.substring( 0, href.lastIndexOf( "/" )), 127 | repUrls = function( css ){ 128 | return css.replace( /(url\()['"]?([^\/\)'"][^:\)'"]+)['"]?(\))/g, "$1" + href + "$2$3" ); 129 | }, 130 | useMedia = !ql && media, 131 | //vars used in loop 132 | i = 0, 133 | j, fullq, thisq, eachq, eql; 134 | 135 | //if path exists, tack on trailing slash 136 | if( href.length ){ href += "/"; } 137 | 138 | //if no internal queries exist, but media attr does, use that 139 | //note: this currently lacks support for situations where a media attr is specified on a link AND 140 | //its associated stylesheet has internal CSS media queries. 141 | //In those cases, the media attribute will currently be ignored. 142 | if( useMedia ){ 143 | ql = 1; 144 | } 145 | 146 | 147 | for( ; i < ql; i++ ){ 148 | j = 0; 149 | 150 | //media attr 151 | if( useMedia ){ 152 | fullq = media; 153 | rules.push( repUrls( styles ) ); 154 | } 155 | //parse for styles 156 | else{ 157 | fullq = qs[ i ].match( /@media *([^\{]+)\{([\S\s]+?)$/ ) && RegExp.$1; 158 | rules.push( RegExp.$2 && repUrls( RegExp.$2 ) ); 159 | } 160 | 161 | eachq = fullq.split( "," ); 162 | eql = eachq.length; 163 | 164 | for( ; j < eql; j++ ){ 165 | thisq = eachq[ j ]; 166 | mediastyles.push( { 167 | media : thisq.split( "(" )[ 0 ].match( /(only\s+)?([a-zA-Z]+)\s?/ ) && RegExp.$2 || "all", 168 | rules : rules.length - 1, 169 | hasquery: thisq.indexOf("(") > -1, 170 | minw : thisq.match( /\(min\-width:[\s]*([\s]*[0-9\.]+)(px|em)[\s]*\)/ ) && parseFloat( RegExp.$1 ) + ( RegExp.$2 || "" ), 171 | maxw : thisq.match( /\(max\-width:[\s]*([\s]*[0-9\.]+)(px|em)[\s]*\)/ ) && parseFloat( RegExp.$1 ) + ( RegExp.$2 || "" ) 172 | } ); 173 | } 174 | } 175 | 176 | applyMedia(); 177 | }, 178 | 179 | lastCall, 180 | 181 | resizeDefer, 182 | 183 | // returns the value of 1em in pixels 184 | getEmValue = function() { 185 | var ret, 186 | div = doc.createElement('div'), 187 | body = doc.body, 188 | fakeUsed = false; 189 | 190 | div.style.cssText = "position:absolute;font-size:1em;width:1em"; 191 | 192 | if( !body ){ 193 | body = fakeUsed = doc.createElement( "body" ); 194 | body.style.background = "none"; 195 | } 196 | 197 | body.appendChild( div ); 198 | 199 | docElem.insertBefore( body, docElem.firstChild ); 200 | 201 | ret = div.offsetWidth; 202 | 203 | if( fakeUsed ){ 204 | docElem.removeChild( body ); 205 | } 206 | else { 207 | body.removeChild( div ); 208 | } 209 | 210 | //also update eminpx before returning 211 | ret = eminpx = parseFloat(ret); 212 | 213 | return ret; 214 | }, 215 | 216 | //cached container for 1em value, populated the first time it's needed 217 | eminpx, 218 | 219 | //enable/disable styles 220 | applyMedia = function( fromResize ){ 221 | var name = "clientWidth", 222 | docElemProp = docElem[ name ], 223 | currWidth = doc.compatMode === "CSS1Compat" && docElemProp || doc.body[ name ] || docElemProp, 224 | styleBlocks = {}, 225 | lastLink = links[ links.length-1 ], 226 | now = (new Date()).getTime(); 227 | 228 | //throttle resize calls 229 | if( fromResize && lastCall && now - lastCall < resizeThrottle ){ 230 | clearTimeout( resizeDefer ); 231 | resizeDefer = setTimeout( applyMedia, resizeThrottle ); 232 | return; 233 | } 234 | else { 235 | lastCall = now; 236 | } 237 | 238 | for( var i in mediastyles ){ 239 | var thisstyle = mediastyles[ i ], 240 | min = thisstyle.minw, 241 | max = thisstyle.maxw, 242 | minnull = min === null, 243 | maxnull = max === null, 244 | em = "em"; 245 | 246 | if( !!min ){ 247 | min = parseFloat( min ) * ( min.indexOf( em ) > -1 ? ( eminpx || getEmValue() ) : 1 ); 248 | } 249 | if( !!max ){ 250 | max = parseFloat( max ) * ( max.indexOf( em ) > -1 ? ( eminpx || getEmValue() ) : 1 ); 251 | } 252 | 253 | // if there's no media query at all (the () part), or min or max is not null, and if either is present, they're true 254 | if( !thisstyle.hasquery || ( !minnull || !maxnull ) && ( minnull || currWidth >= min ) && ( maxnull || currWidth <= max ) ){ 255 | if( !styleBlocks[ thisstyle.media ] ){ 256 | styleBlocks[ thisstyle.media ] = []; 257 | } 258 | styleBlocks[ thisstyle.media ].push( rules[ thisstyle.rules ] ); 259 | } 260 | } 261 | 262 | //remove any existing respond style element(s) 263 | for( var i in appendedEls ){ 264 | if( appendedEls[ i ] && appendedEls[ i ].parentNode === head ){ 265 | head.removeChild( appendedEls[ i ] ); 266 | } 267 | } 268 | 269 | //inject active styles, grouped by media type 270 | for( var i in styleBlocks ){ 271 | var ss = doc.createElement( "style" ), 272 | css = styleBlocks[ i ].join( "\n" ); 273 | 274 | ss.type = "text/css"; 275 | ss.media = i; 276 | 277 | //originally, ss was appended to a documentFragment and sheets were appended in bulk. 278 | //this caused crashes in IE in a number of circumstances, such as when the HTML element had a bg image set, so appending beforehand seems best. Thanks to @dvelyk for the initial research on this one! 279 | head.insertBefore( ss, lastLink.nextSibling ); 280 | 281 | if ( ss.styleSheet ){ 282 | ss.styleSheet.cssText = css; 283 | } 284 | else { 285 | ss.appendChild( doc.createTextNode( css ) ); 286 | } 287 | 288 | //push to appendedEls to track for later removal 289 | appendedEls.push( ss ); 290 | } 291 | }, 292 | //tweaked Ajax functions from Quirksmode 293 | ajax = function( url, callback ) { 294 | var req = xmlHttp(); 295 | if (!req){ 296 | return; 297 | } 298 | req.open( "GET", url, true ); 299 | req.onreadystatechange = function () { 300 | if ( req.readyState != 4 || req.status != 200 && req.status != 304 ){ 301 | return; 302 | } 303 | callback( req.responseText ); 304 | } 305 | if ( req.readyState == 4 ){ 306 | return; 307 | } 308 | req.send( null ); 309 | }, 310 | //define ajax obj 311 | xmlHttp = (function() { 312 | var xmlhttpmethod = false; 313 | try { 314 | xmlhttpmethod = new XMLHttpRequest(); 315 | } 316 | catch( e ){ 317 | xmlhttpmethod = new ActiveXObject( "Microsoft.XMLHTTP" ); 318 | } 319 | return function(){ 320 | return xmlhttpmethod; 321 | }; 322 | })(); 323 | 324 | //translate CSS 325 | ripCSS(); 326 | 327 | //expose update for re-running respond later on 328 | respond.update = ripCSS; 329 | 330 | //adjust on resize 331 | function callMedia(){ 332 | applyMedia( true ); 333 | } 334 | if( win.addEventListener ){ 335 | win.addEventListener( "resize", callMedia, false ); 336 | } 337 | else if( win.attachEvent ){ 338 | win.attachEvent( "onresize", callMedia ); 339 | } 340 | })(this); 341 | -------------------------------------------------------------------------------- /AspNetExtendingIdentityRoles/Controllers/AccountController.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNet.Identity; 2 | using Microsoft.AspNet.Identity.EntityFramework; 3 | using Microsoft.Owin.Security; 4 | using System.Collections.Generic; 5 | using System.Linq; 6 | using System.Threading.Tasks; 7 | using System.Web; 8 | using System.Web.Mvc; 9 | using AspNetExtendingIdentityRoles.Models; 10 | 11 | namespace AspNetExtendingIdentityRoles.Controllers 12 | { 13 | [Authorize] 14 | public class AccountController : Controller 15 | { 16 | public AccountController() 17 | : this(new UserManager(new UserStore(new ApplicationDbContext()))) 18 | { 19 | } 20 | 21 | 22 | public AccountController(UserManager userManager) 23 | { 24 | UserManager = userManager; 25 | } 26 | 27 | 28 | public UserManager UserManager { get; private set; } 29 | 30 | 31 | [AllowAnonymous] 32 | public ActionResult Login(string returnUrl) 33 | { 34 | ViewBag.ReturnUrl = returnUrl; 35 | return View(); 36 | } 37 | 38 | 39 | [HttpPost] 40 | [AllowAnonymous] 41 | [ValidateAntiForgeryToken] 42 | public async Task Login(LoginViewModel model, string returnUrl) 43 | { 44 | if (ModelState.IsValid) 45 | { 46 | var user = await UserManager.FindAsync(model.UserName, model.Password); 47 | if (user != null) 48 | { 49 | await SignInAsync(user, model.RememberMe); 50 | return RedirectToLocal(returnUrl); 51 | } 52 | else 53 | { 54 | ModelState.AddModelError("", "Invalid username or password."); 55 | } 56 | } 57 | 58 | // If we got this far, something failed, redisplay form 59 | return View(model); 60 | } 61 | 62 | 63 | [Authorize(Roles = "Admin")] 64 | public ActionResult Register() 65 | { 66 | return View(); 67 | } 68 | 69 | 70 | [HttpPost] 71 | [Authorize(Roles = "Admin")] 72 | [ValidateAntiForgeryToken] 73 | public async Task Register(RegisterViewModel model) 74 | { 75 | if (ModelState.IsValid) 76 | { 77 | var user = model.GetUser(); 78 | var result = await UserManager.CreateAsync(user, model.Password); 79 | if (result.Succeeded) 80 | { 81 | return RedirectToAction("Index", "Account"); 82 | } 83 | 84 | } 85 | 86 | // If we got this far, something failed, redisplay form 87 | return View(model); 88 | } 89 | 90 | 91 | [Authorize(Roles = "Admin")] 92 | public ActionResult Manage(ManageMessageId? message) 93 | { 94 | ViewBag.StatusMessage = 95 | message == ManageMessageId.ChangePasswordSuccess ? "Your password has been changed." 96 | : message == ManageMessageId.SetPasswordSuccess ? "Your password has been set." 97 | : message == ManageMessageId.RemoveLoginSuccess ? "The external login was removed." 98 | : message == ManageMessageId.Error ? "An error has occurred." 99 | : ""; 100 | ViewBag.HasLocalPassword = HasPassword(); 101 | ViewBag.ReturnUrl = Url.Action("Manage"); 102 | return View(); 103 | } 104 | 105 | 106 | [HttpPost] 107 | [ValidateAntiForgeryToken] 108 | [Authorize(Roles = "Admin")] 109 | public async Task Manage(ManageUserViewModel model) 110 | { 111 | bool hasPassword = HasPassword(); 112 | ViewBag.HasLocalPassword = hasPassword; 113 | ViewBag.ReturnUrl = Url.Action("Manage"); 114 | if (hasPassword) 115 | { 116 | if (ModelState.IsValid) 117 | { 118 | IdentityResult result = await UserManager.ChangePasswordAsync(User.Identity.GetUserId(), model.OldPassword, model.NewPassword); 119 | if (result.Succeeded) 120 | { 121 | return RedirectToAction("Manage", new { Message = ManageMessageId.ChangePasswordSuccess }); 122 | } 123 | else 124 | { 125 | AddErrors(result); 126 | } 127 | } 128 | } 129 | else 130 | { 131 | // User does not have a password so remove any validation errors caused by a missing OldPassword field 132 | ModelState state = ModelState["OldPassword"]; 133 | if (state != null) 134 | { 135 | state.Errors.Clear(); 136 | } 137 | 138 | if (ModelState.IsValid) 139 | { 140 | IdentityResult result = await UserManager.AddPasswordAsync(User.Identity.GetUserId(), model.NewPassword); 141 | if (result.Succeeded) 142 | { 143 | return RedirectToAction("Manage", new { Message = ManageMessageId.SetPasswordSuccess }); 144 | } 145 | else 146 | { 147 | AddErrors(result); 148 | } 149 | } 150 | } 151 | 152 | // If we got this far, something failed, redisplay form 153 | return View(model); 154 | } 155 | 156 | 157 | [HttpPost] 158 | [ValidateAntiForgeryToken] 159 | public ActionResult LogOff() 160 | { 161 | AuthenticationManager.SignOut(); 162 | return RedirectToAction("Index", "Home"); 163 | } 164 | 165 | 166 | protected override void Dispose(bool disposing) 167 | { 168 | if (disposing && UserManager != null) 169 | { 170 | UserManager.Dispose(); 171 | UserManager = null; 172 | } 173 | base.Dispose(disposing); 174 | } 175 | 176 | 177 | [Authorize(Roles = "Admin")] 178 | public ActionResult Index() 179 | { 180 | var Db = new ApplicationDbContext(); 181 | var users = Db.Users; 182 | var model = new List(); 183 | foreach (var user in users) 184 | { 185 | var u = new EditUserViewModel(user); 186 | model.Add(u); 187 | } 188 | return View(model); 189 | } 190 | 191 | 192 | [Authorize(Roles = "Admin")] 193 | public ActionResult Edit(string id, ManageMessageId? Message = null) 194 | { 195 | var Db = new ApplicationDbContext(); 196 | var user = Db.Users.First(u => u.UserName == id); 197 | var model = new EditUserViewModel(user); 198 | ViewBag.MessageId = Message; 199 | return View(model); 200 | } 201 | 202 | 203 | [HttpPost] 204 | [Authorize(Roles = "Admin")] 205 | [ValidateAntiForgeryToken] 206 | public async Task Edit(EditUserViewModel model) 207 | { 208 | if (ModelState.IsValid) 209 | { 210 | var Db = new ApplicationDbContext(); 211 | var user = Db.Users.First(u => u.UserName == model.UserName); 212 | user.FirstName = model.FirstName; 213 | user.LastName = model.LastName; 214 | user.Email = model.Email; 215 | Db.Entry(user).State = System.Data.Entity.EntityState.Modified; 216 | await Db.SaveChangesAsync(); 217 | return RedirectToAction("Index"); 218 | } 219 | 220 | // If we got this far, something failed, redisplay form 221 | return View(model); 222 | } 223 | 224 | 225 | [Authorize(Roles = "Admin")] 226 | public ActionResult Delete(string id = null) 227 | { 228 | var Db = new ApplicationDbContext(); 229 | var user = Db.Users.First(u => u.UserName == id); 230 | var model = new EditUserViewModel(user); 231 | if (user == null) 232 | { 233 | return HttpNotFound(); 234 | } 235 | return View(model); 236 | } 237 | 238 | 239 | [HttpPost, ActionName("Delete")] 240 | [ValidateAntiForgeryToken] 241 | [Authorize(Roles = "Admin")] 242 | public ActionResult DeleteConfirmed(string id) 243 | { 244 | var Db = new ApplicationDbContext(); 245 | var user = Db.Users.First(u => u.UserName == id); 246 | Db.Users.Remove(user); 247 | Db.SaveChanges(); 248 | return RedirectToAction("Index"); 249 | } 250 | 251 | 252 | [Authorize(Roles = "Admin")] 253 | public ActionResult UserRoles(string id) 254 | { 255 | var Db = new ApplicationDbContext(); 256 | var user = Db.Users.First(u => u.UserName == id); 257 | var model = new SelectUserRolesViewModel(user); 258 | return View(model); 259 | } 260 | 261 | 262 | [HttpPost] 263 | [Authorize(Roles = "Admin")] 264 | [ValidateAntiForgeryToken] 265 | public ActionResult UserRoles(SelectUserRolesViewModel model) 266 | { 267 | if (ModelState.IsValid) 268 | { 269 | var idManager = new IdentityManager(); 270 | var Db = new ApplicationDbContext(); 271 | var user = Db.Users.First(u => u.UserName == model.UserName); 272 | idManager.ClearUserRoles(user.Id); 273 | foreach (var role in model.Roles) 274 | { 275 | if (role.Selected) 276 | { 277 | idManager.AddUserToRole(user.Id, role.RoleName); 278 | } 279 | } 280 | return RedirectToAction("index"); 281 | } 282 | return View(); 283 | } 284 | 285 | 286 | #region Helpers 287 | 288 | private IAuthenticationManager AuthenticationManager 289 | { 290 | get 291 | { 292 | return HttpContext.GetOwinContext().Authentication; 293 | } 294 | } 295 | 296 | 297 | private async Task SignInAsync(ApplicationUser user, bool isPersistent) 298 | { 299 | AuthenticationManager.SignOut(DefaultAuthenticationTypes.ExternalCookie); 300 | var identity = await UserManager.CreateIdentityAsync(user, DefaultAuthenticationTypes.ApplicationCookie); 301 | AuthenticationManager.SignIn(new AuthenticationProperties() { IsPersistent = isPersistent }, identity); 302 | } 303 | 304 | 305 | private void AddErrors(IdentityResult result) 306 | { 307 | foreach (var error in result.Errors) 308 | { 309 | ModelState.AddModelError("", error); 310 | } 311 | } 312 | 313 | 314 | private bool HasPassword() 315 | { 316 | var user = UserManager.FindById(User.Identity.GetUserId()); 317 | if (user != null) 318 | { 319 | return user.PasswordHash != null; 320 | } 321 | return false; 322 | } 323 | 324 | 325 | public enum ManageMessageId 326 | { 327 | ChangePasswordSuccess, 328 | SetPasswordSuccess, 329 | RemoveLoginSuccess, 330 | Error 331 | } 332 | 333 | 334 | private ActionResult RedirectToLocal(string returnUrl) 335 | { 336 | if (Url.IsLocalUrl(returnUrl)) 337 | { 338 | return Redirect(returnUrl); 339 | } 340 | else 341 | { 342 | return RedirectToAction("Index", "Home"); 343 | } 344 | } 345 | 346 | #endregion 347 | } 348 | } -------------------------------------------------------------------------------- /AspNetExtendingIdentityRoles/Scripts/jquery.validate.unobtrusive.js: -------------------------------------------------------------------------------- 1 | /* NUGET: BEGIN LICENSE TEXT 2 | * 3 | * Microsoft grants you the right to use these script files for the sole 4 | * purpose of either: (i) interacting through your browser with the Microsoft 5 | * website or online service, subject to the applicable licensing or use 6 | * terms; or (ii) using the files as included with a Microsoft product subject 7 | * to that product's license terms. Microsoft reserves all other rights to the 8 | * files not expressly granted by Microsoft, whether by implication, estoppel 9 | * or otherwise. Insofar as a script file is dual licensed under GPL, 10 | * Microsoft neither took the code under GPL nor distributes it thereunder but 11 | * under the terms set out in this paragraph. All notices and licenses 12 | * below are for informational purposes only. 13 | * 14 | * NUGET: END LICENSE TEXT */ 15 | /*! 16 | ** Unobtrusive validation support library for jQuery and jQuery Validate 17 | ** Copyright (C) Microsoft Corporation. All rights reserved. 18 | */ 19 | /*jslint white: true, browser: true, onevar: true, undef: true, nomen: true, eqeqeq: true, plusplus: true, bitwise: true, regexp: true, newcap: true, immed: true, strict: false */ 20 | /*global document: false, jQuery: false */ 21 | (function ($) { 22 | var $jQval = $.validator, 23 | adapters, 24 | data_validation = "unobtrusiveValidation"; 25 | function setValidationValues(options, ruleName, value) { 26 | options.rules[ruleName] = value; 27 | if (options.message) { 28 | options.messages[ruleName] = options.message; 29 | } 30 | } 31 | function splitAndTrim(value) { 32 | return value.replace(/^\s+|\s+$/g, "").split(/\s*,\s*/g); 33 | } 34 | function escapeAttributeValue(value) { 35 | // As mentioned on http://api.jquery.com/category/selectors/ 36 | return value.replace(/([!"#$%&'()*+,./:;<=>?@\[\\\]^`{|}~])/g, "\\$1"); 37 | } 38 | function getModelPrefix(fieldName) { 39 | return fieldName.substr(0, fieldName.lastIndexOf(".") + 1); 40 | } 41 | function appendModelPrefix(value, prefix) { 42 | if (value.indexOf("*.") === 0) { 43 | value = value.replace("*.", prefix); 44 | } 45 | return value; 46 | } 47 | function onError(error, inputElement) { // 'this' is the form element 48 | var container = $(this).find("[data-valmsg-for='" + escapeAttributeValue(inputElement[0].name) + "']"), 49 | replaceAttrValue = container.attr("data-valmsg-replace"), 50 | replace = replaceAttrValue ? $.parseJSON(replaceAttrValue) !== false : null; 51 | container.removeClass("field-validation-valid").addClass("field-validation-error"); 52 | error.data("unobtrusiveContainer", container); 53 | if (replace) { 54 | container.empty(); 55 | error.removeClass("input-validation-error").appendTo(container); 56 | } 57 | else { 58 | error.hide(); 59 | } 60 | } 61 | function onErrors(event, validator) { // 'this' is the form element 62 | var container = $(this).find("[data-valmsg-summary=true]"), 63 | list = container.find("ul"); 64 | if (list && list.length && validator.errorList.length) { 65 | list.empty(); 66 | container.addClass("validation-summary-errors").removeClass("validation-summary-valid"); 67 | $.each(validator.errorList, function () { 68 | $("
  • ").html(this.message).appendTo(list); 69 | }); 70 | } 71 | } 72 | function onSuccess(error) { // 'this' is the form element 73 | var container = error.data("unobtrusiveContainer"), 74 | replaceAttrValue = container.attr("data-valmsg-replace"), 75 | replace = replaceAttrValue ? $.parseJSON(replaceAttrValue) : null; 76 | if (container) { 77 | container.addClass("field-validation-valid").removeClass("field-validation-error"); 78 | error.removeData("unobtrusiveContainer"); 79 | if (replace) { 80 | container.empty(); 81 | } 82 | } 83 | } 84 | function onReset(event) { // 'this' is the form element 85 | var $form = $(this); 86 | $form.data("validator").resetForm(); 87 | $form.find(".validation-summary-errors") 88 | .addClass("validation-summary-valid") 89 | .removeClass("validation-summary-errors"); 90 | $form.find(".field-validation-error") 91 | .addClass("field-validation-valid") 92 | .removeClass("field-validation-error") 93 | .removeData("unobtrusiveContainer") 94 | .find(">*") // If we were using valmsg-replace, get the underlying error 95 | .removeData("unobtrusiveContainer"); 96 | } 97 | function validationInfo(form) { 98 | var $form = $(form), 99 | result = $form.data(data_validation), 100 | onResetProxy = $.proxy(onReset, form); 101 | if (!result) { 102 | result = { 103 | options: { // options structure passed to jQuery Validate's validate() method 104 | errorClass: "input-validation-error", 105 | errorElement: "span", 106 | errorPlacement: $.proxy(onError, form), 107 | invalidHandler: $.proxy(onErrors, form), 108 | messages: {}, 109 | rules: {}, 110 | success: $.proxy(onSuccess, form) 111 | }, 112 | attachValidation: function () { 113 | $form 114 | .unbind("reset." + data_validation, onResetProxy) 115 | .bind("reset." + data_validation, onResetProxy) 116 | .validate(this.options); 117 | }, 118 | validate: function () { // a validation function that is called by unobtrusive Ajax 119 | $form.validate(); 120 | return $form.valid(); 121 | } 122 | }; 123 | $form.data(data_validation, result); 124 | } 125 | return result; 126 | } 127 | $jQval.unobtrusive = { 128 | adapters: [], 129 | parseElement: function (element, skipAttach) { 130 | /// 131 | /// Parses a single HTML element for unobtrusive validation attributes. 132 | /// 133 | /// The HTML element to be parsed. 134 | /// [Optional] true to skip attaching the 135 | /// validation to the form. If parsing just this single element, you should specify true. 136 | /// If parsing several elements, you should specify false, and manually attach the validation 137 | /// to the form when you are finished. The default is false. 138 | var $element = $(element), 139 | form = $element.parents("form")[0], 140 | valInfo, rules, messages; 141 | if (!form) { // Cannot do client-side validation without a form 142 | return; 143 | } 144 | valInfo = validationInfo(form); 145 | valInfo.options.rules[element.name] = rules = {}; 146 | valInfo.options.messages[element.name] = messages = {}; 147 | $.each(this.adapters, function () { 148 | var prefix = "data-val-" + this.name, 149 | message = $element.attr(prefix), 150 | paramValues = {}; 151 | if (message !== undefined) { // Compare against undefined, because an empty message is legal (and falsy) 152 | prefix += "-"; 153 | $.each(this.params, function () { 154 | paramValues[this] = $element.attr(prefix + this); 155 | }); 156 | this.adapt({ 157 | element: element, 158 | form: form, 159 | message: message, 160 | params: paramValues, 161 | rules: rules, 162 | messages: messages 163 | }); 164 | } 165 | }); 166 | $.extend(rules, { "__dummy__": true }); 167 | if (!skipAttach) { 168 | valInfo.attachValidation(); 169 | } 170 | }, 171 | parse: function (selector) { 172 | /// 173 | /// Parses all the HTML elements in the specified selector. It looks for input elements decorated 174 | /// with the [data-val=true] attribute value and enables validation according to the data-val-* 175 | /// attribute values. 176 | /// 177 | /// Any valid jQuery selector. 178 | var $forms = $(selector) 179 | .parents("form") 180 | .andSelf() 181 | .add($(selector).find("form")) 182 | .filter("form"); 183 | // :input is a psuedoselector provided by jQuery which selects input and input-like elements 184 | // combining :input with other selectors significantly decreases performance. 185 | $(selector).find(":input").filter("[data-val=true]").each(function () { 186 | $jQval.unobtrusive.parseElement(this, true); 187 | }); 188 | $forms.each(function () { 189 | var info = validationInfo(this); 190 | if (info) { 191 | info.attachValidation(); 192 | } 193 | }); 194 | } 195 | }; 196 | adapters = $jQval.unobtrusive.adapters; 197 | adapters.add = function (adapterName, params, fn) { 198 | /// Adds a new adapter to convert unobtrusive HTML into a jQuery Validate validation. 199 | /// The name of the adapter to be added. This matches the name used 200 | /// in the data-val-nnnn HTML attribute (where nnnn is the adapter name). 201 | /// [Optional] An array of parameter names (strings) that will 202 | /// be extracted from the data-val-nnnn-mmmm HTML attributes (where nnnn is the adapter name, and 203 | /// mmmm is the parameter name). 204 | /// The function to call, which adapts the values from the HTML 205 | /// attributes into jQuery Validate rules and/or messages. 206 | /// 207 | if (!fn) { // Called with no params, just a function 208 | fn = params; 209 | params = []; 210 | } 211 | this.push({ name: adapterName, params: params, adapt: fn }); 212 | return this; 213 | }; 214 | adapters.addBool = function (adapterName, ruleName) { 215 | /// Adds a new adapter to convert unobtrusive HTML into a jQuery Validate validation, where 216 | /// the jQuery Validate validation rule has no parameter values. 217 | /// The name of the adapter to be added. This matches the name used 218 | /// in the data-val-nnnn HTML attribute (where nnnn is the adapter name). 219 | /// [Optional] The name of the jQuery Validate rule. If not provided, the value 220 | /// of adapterName will be used instead. 221 | /// 222 | return this.add(adapterName, function (options) { 223 | setValidationValues(options, ruleName || adapterName, true); 224 | }); 225 | }; 226 | adapters.addMinMax = function (adapterName, minRuleName, maxRuleName, minMaxRuleName, minAttribute, maxAttribute) { 227 | /// Adds a new adapter to convert unobtrusive HTML into a jQuery Validate validation, where 228 | /// the jQuery Validate validation has three potential rules (one for min-only, one for max-only, and 229 | /// one for min-and-max). The HTML parameters are expected to be named -min and -max. 230 | /// The name of the adapter to be added. This matches the name used 231 | /// in the data-val-nnnn HTML attribute (where nnnn is the adapter name). 232 | /// The name of the jQuery Validate rule to be used when you only 233 | /// have a minimum value. 234 | /// The name of the jQuery Validate rule to be used when you only 235 | /// have a maximum value. 236 | /// The name of the jQuery Validate rule to be used when you 237 | /// have both a minimum and maximum value. 238 | /// [Optional] The name of the HTML attribute that 239 | /// contains the minimum value. The default is "min". 240 | /// [Optional] The name of the HTML attribute that 241 | /// contains the maximum value. The default is "max". 242 | /// 243 | return this.add(adapterName, [minAttribute || "min", maxAttribute || "max"], function (options) { 244 | var min = options.params.min, 245 | max = options.params.max; 246 | if (min && max) { 247 | setValidationValues(options, minMaxRuleName, [min, max]); 248 | } 249 | else if (min) { 250 | setValidationValues(options, minRuleName, min); 251 | } 252 | else if (max) { 253 | setValidationValues(options, maxRuleName, max); 254 | } 255 | }); 256 | }; 257 | adapters.addSingleVal = function (adapterName, attribute, ruleName) { 258 | /// Adds a new adapter to convert unobtrusive HTML into a jQuery Validate validation, where 259 | /// the jQuery Validate validation rule has a single value. 260 | /// The name of the adapter to be added. This matches the name used 261 | /// in the data-val-nnnn HTML attribute(where nnnn is the adapter name). 262 | /// [Optional] The name of the HTML attribute that contains the value. 263 | /// The default is "val". 264 | /// [Optional] The name of the jQuery Validate rule. If not provided, the value 265 | /// of adapterName will be used instead. 266 | /// 267 | return this.add(adapterName, [attribute || "val"], function (options) { 268 | setValidationValues(options, ruleName || adapterName, options.params[attribute]); 269 | }); 270 | }; 271 | $jQval.addMethod("__dummy__", function (value, element, params) { 272 | return true; 273 | }); 274 | $jQval.addMethod("regex", function (value, element, params) { 275 | var match; 276 | if (this.optional(element)) { 277 | return true; 278 | } 279 | match = new RegExp(params).exec(value); 280 | return (match && (match.index === 0) && (match[0].length === value.length)); 281 | }); 282 | $jQval.addMethod("nonalphamin", function (value, element, nonalphamin) { 283 | var match; 284 | if (nonalphamin) { 285 | match = value.match(/\W/g); 286 | match = match && match.length >= nonalphamin; 287 | } 288 | return match; 289 | }); 290 | if ($jQval.methods.extension) { 291 | adapters.addSingleVal("accept", "mimtype"); 292 | adapters.addSingleVal("extension", "extension"); 293 | } else { 294 | // for backward compatibility, when the 'extension' validation method does not exist, such as with versions 295 | // of JQuery Validation plugin prior to 1.10, we should use the 'accept' method for 296 | // validating the extension, and ignore mime-type validations as they are not supported. 297 | adapters.addSingleVal("extension", "extension", "accept"); 298 | } 299 | adapters.addSingleVal("regex", "pattern"); 300 | adapters.addBool("creditcard").addBool("date").addBool("digits").addBool("email").addBool("number").addBool("url"); 301 | adapters.addMinMax("length", "minlength", "maxlength", "rangelength").addMinMax("range", "min", "max", "range"); 302 | adapters.add("equalto", ["other"], function (options) { 303 | var prefix = getModelPrefix(options.element.name), 304 | other = options.params.other, 305 | fullOtherName = appendModelPrefix(other, prefix), 306 | element = $(options.form).find(":input").filter("[name='" + escapeAttributeValue(fullOtherName) + "']")[0]; 307 | setValidationValues(options, "equalTo", element); 308 | }); 309 | adapters.add("required", function (options) { 310 | // jQuery Validate equates "required" with "mandatory" for checkbox elements 311 | if (options.element.tagName.toUpperCase() !== "INPUT" || options.element.type.toUpperCase() !== "CHECKBOX") { 312 | setValidationValues(options, "required", true); 313 | } 314 | }); 315 | adapters.add("remote", ["url", "type", "additionalfields"], function (options) { 316 | var value = { 317 | url: options.params.url, 318 | type: options.params.type || "GET", 319 | data: {} 320 | }, 321 | prefix = getModelPrefix(options.element.name); 322 | $.each(splitAndTrim(options.params.additionalfields || options.element.name), function (i, fieldName) { 323 | var paramName = appendModelPrefix(fieldName, prefix); 324 | value.data[paramName] = function () { 325 | return $(options.form).find(":input").filter("[name='" + escapeAttributeValue(paramName) + "']").val(); 326 | }; 327 | }); 328 | setValidationValues(options, "remote", value); 329 | }); 330 | adapters.add("password", ["min", "nonalphamin", "regex"], function (options) { 331 | if (options.params.min) { 332 | setValidationValues(options, "minlength", options.params.min); 333 | } 334 | if (options.params.nonalphamin) { 335 | setValidationValues(options, "nonalphamin", options.params.nonalphamin); 336 | } 337 | if (options.params.regex) { 338 | setValidationValues(options, "regex", options.params.regex); 339 | } 340 | }); 341 | $(function () { 342 | $jQval.unobtrusive.parse(document); 343 | }); 344 | }(jQuery)); 345 | -------------------------------------------------------------------------------- /AspNetExtendingIdentityRoles/AspNetExtendingIdentityRoles.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | 8 | 9 | 2.0 10 | {D7ADA016-6E82-4F70-B6CF-B687A3B6F6EA} 11 | {349c5851-65df-11da-9384-00065b846f21};{fae04ec0-301f-11d3-bf4b-00c04f79efbc} 12 | Library 13 | Properties 14 | AspNetExtendingIdentityRoles 15 | AspNetExtendingIdentityRoles 16 | v4.5 17 | false 18 | true 19 | 20 | 21 | 22 | 23 | ..\ 24 | true 25 | 26 | 27 | true 28 | full 29 | false 30 | bin\ 31 | DEBUG;TRACE 32 | prompt 33 | 4 34 | 35 | 36 | pdbonly 37 | true 38 | bin\ 39 | TRACE 40 | prompt 41 | 4 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | True 65 | ..\packages\Microsoft.Web.Infrastructure.1.0.0.0\lib\net40\Microsoft.Web.Infrastructure.dll 66 | 67 | 68 | 69 | 70 | 71 | 72 | True 73 | ..\packages\Microsoft.AspNet.WebPages.3.0.0\lib\net45\System.Web.Helpers.dll 74 | 75 | 76 | True 77 | ..\packages\Microsoft.AspNet.Mvc.5.0.0\lib\net45\System.Web.Mvc.dll 78 | 79 | 80 | ..\packages\Microsoft.AspNet.Web.Optimization.1.1.1\lib\net40\System.Web.Optimization.dll 81 | 82 | 83 | True 84 | ..\packages\Microsoft.AspNet.Razor.3.0.0\lib\net45\System.Web.Razor.dll 85 | 86 | 87 | True 88 | ..\packages\Microsoft.AspNet.WebPages.3.0.0\lib\net45\System.Web.WebPages.dll 89 | 90 | 91 | True 92 | ..\packages\Microsoft.AspNet.WebPages.3.0.0\lib\net45\System.Web.WebPages.Deployment.dll 93 | 94 | 95 | True 96 | ..\packages\Microsoft.AspNet.WebPages.3.0.0\lib\net45\System.Web.WebPages.Razor.dll 97 | 98 | 99 | True 100 | ..\packages\Newtonsoft.Json.5.0.6\lib\net45\Newtonsoft.Json.dll 101 | 102 | 103 | True 104 | ..\packages\WebGrease.1.5.2\lib\WebGrease.dll 105 | 106 | 107 | True 108 | ..\packages\Antlr.3.4.1.9004\lib\Antlr3.Runtime.dll 109 | 110 | 111 | 112 | 113 | ..\packages\EntityFramework.6.0.0\lib\net45\EntityFramework.dll 114 | 115 | 116 | ..\packages\EntityFramework.6.0.0\lib\net45\EntityFramework.SqlServer.dll 117 | 118 | 119 | ..\packages\Microsoft.AspNet.Identity.Core.1.0.0\lib\net45\Microsoft.AspNet.Identity.Core.dll 120 | 121 | 122 | ..\packages\Microsoft.AspNet.Identity.Owin.1.0.0\lib\net45\Microsoft.AspNet.Identity.Owin.dll 123 | 124 | 125 | ..\packages\Microsoft.AspNet.Identity.EntityFramework.1.0.0\lib\net45\Microsoft.AspNet.Identity.EntityFramework.dll 126 | 127 | 128 | ..\packages\Owin.1.0\lib\net40\Owin.dll 129 | 130 | 131 | ..\packages\Microsoft.Owin.2.0.0\lib\net45\Microsoft.Owin.dll 132 | 133 | 134 | ..\packages\Microsoft.Owin.Host.SystemWeb.2.0.0\lib\net45\Microsoft.Owin.Host.SystemWeb.dll 135 | 136 | 137 | ..\packages\Microsoft.Owin.Security.2.0.0\lib\net45\Microsoft.Owin.Security.dll 138 | 139 | 140 | ..\packages\Microsoft.Owin.Security.Facebook.2.0.0\lib\net45\Microsoft.Owin.Security.Facebook.dll 141 | 142 | 143 | ..\packages\Microsoft.Owin.Security.Cookies.2.0.0\lib\net45\Microsoft.Owin.Security.Cookies.dll 144 | 145 | 146 | ..\packages\Microsoft.Owin.Security.OAuth.2.0.0\lib\net45\Microsoft.Owin.Security.OAuth.dll 147 | 148 | 149 | ..\packages\Microsoft.Owin.Security.Google.2.0.0\lib\net45\Microsoft.Owin.Security.Google.dll 150 | 151 | 152 | ..\packages\Microsoft.Owin.Security.Twitter.2.0.0\lib\net45\Microsoft.Owin.Security.Twitter.dll 153 | 154 | 155 | ..\packages\Microsoft.Owin.Security.MicrosoftAccount.2.0.0\lib\net45\Microsoft.Owin.Security.MicrosoftAccount.dll 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | Global.asax 168 | 169 | 170 | 171 | 201402130341319_init.cs 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | Web.config 207 | 208 | 209 | Web.config 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 201402130341319_init.cs 248 | 249 | 250 | 251 | 10.0 252 | $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) 253 | 254 | 255 | 256 | 257 | 258 | 259 | 260 | 261 | 262 | 263 | 264 | True 265 | True 266 | 58980 267 | / 268 | http://localhost:58980/ 269 | False 270 | False 271 | 272 | 273 | False 274 | 275 | 276 | 277 | 278 | 279 | 285 | -------------------------------------------------------------------------------- /AspNetExtendingIdentityRoles/Scripts/jquery.validate.min.js: -------------------------------------------------------------------------------- 1 | /* NUGET: BEGIN LICENSE TEXT 2 | * 3 | * Microsoft grants you the right to use these script files for the sole 4 | * purpose of either: (i) interacting through your browser with the Microsoft 5 | * website or online service, subject to the applicable licensing or use 6 | * terms; or (ii) using the files as included with a Microsoft product subject 7 | * to that product's license terms. Microsoft reserves all other rights to the 8 | * files not expressly granted by Microsoft, whether by implication, estoppel 9 | * or otherwise. Insofar as a script file is dual licensed under GPL, 10 | * Microsoft neither took the code under GPL nor distributes it thereunder but 11 | * under the terms set out in this paragraph. All notices and licenses 12 | * below are for informational purposes only. 13 | * 14 | * NUGET: END LICENSE TEXT */ 15 | /*! jQuery Validation Plugin - v1.11.1 - 3/22/2013\n* https://github.com/jzaefferer/jquery-validation 16 | * Copyright (c) 2013 Jörn Zaefferer; Licensed MIT */(function(t){t.extend(t.fn,{validate:function(e){if(!this.length)return e&&e.debug&&window.console&&console.warn("Nothing selected, can't validate, returning nothing."),void 0;var i=t.data(this[0],"validator");return i?i:(this.attr("novalidate","novalidate"),i=new t.validator(e,this[0]),t.data(this[0],"validator",i),i.settings.onsubmit&&(this.validateDelegate(":submit","click",function(e){i.settings.submitHandler&&(i.submitButton=e.target),t(e.target).hasClass("cancel")&&(i.cancelSubmit=!0),void 0!==t(e.target).attr("formnovalidate")&&(i.cancelSubmit=!0)}),this.submit(function(e){function s(){var s;return i.settings.submitHandler?(i.submitButton&&(s=t("").attr("name",i.submitButton.name).val(t(i.submitButton).val()).appendTo(i.currentForm)),i.settings.submitHandler.call(i,i.currentForm,e),i.submitButton&&s.remove(),!1):!0}return i.settings.debug&&e.preventDefault(),i.cancelSubmit?(i.cancelSubmit=!1,s()):i.form()?i.pendingRequest?(i.formSubmitted=!0,!1):s():(i.focusInvalid(),!1)})),i)},valid:function(){if(t(this[0]).is("form"))return this.validate().form();var e=!0,i=t(this[0].form).validate();return this.each(function(){e=e&&i.element(this)}),e},removeAttrs:function(e){var i={},s=this;return t.each(e.split(/\s/),function(t,e){i[e]=s.attr(e),s.removeAttr(e)}),i},rules:function(e,i){var s=this[0];if(e){var r=t.data(s.form,"validator").settings,n=r.rules,a=t.validator.staticRules(s);switch(e){case"add":t.extend(a,t.validator.normalizeRule(i)),delete a.messages,n[s.name]=a,i.messages&&(r.messages[s.name]=t.extend(r.messages[s.name],i.messages));break;case"remove":if(!i)return delete n[s.name],a;var u={};return t.each(i.split(/\s/),function(t,e){u[e]=a[e],delete a[e]}),u}}var o=t.validator.normalizeRules(t.extend({},t.validator.classRules(s),t.validator.attributeRules(s),t.validator.dataRules(s),t.validator.staticRules(s)),s);if(o.required){var l=o.required;delete o.required,o=t.extend({required:l},o)}return o}}),t.extend(t.expr[":"],{blank:function(e){return!t.trim(""+t(e).val())},filled:function(e){return!!t.trim(""+t(e).val())},unchecked:function(e){return!t(e).prop("checked")}}),t.validator=function(e,i){this.settings=t.extend(!0,{},t.validator.defaults,e),this.currentForm=i,this.init()},t.validator.format=function(e,i){return 1===arguments.length?function(){var i=t.makeArray(arguments);return i.unshift(e),t.validator.format.apply(this,i)}:(arguments.length>2&&i.constructor!==Array&&(i=t.makeArray(arguments).slice(1)),i.constructor!==Array&&(i=[i]),t.each(i,function(t,i){e=e.replace(RegExp("\\{"+t+"\\}","g"),function(){return i})}),e)},t.extend(t.validator,{defaults:{messages:{},groups:{},rules:{},errorClass:"error",validClass:"valid",errorElement:"label",focusInvalid:!0,errorContainer:t([]),errorLabelContainer:t([]),onsubmit:!0,ignore:":hidden",ignoreTitle:!1,onfocusin:function(t){this.lastActive=t,this.settings.focusCleanup&&!this.blockFocusCleanup&&(this.settings.unhighlight&&this.settings.unhighlight.call(this,t,this.settings.errorClass,this.settings.validClass),this.addWrapper(this.errorsFor(t)).hide())},onfocusout:function(t){this.checkable(t)||!(t.name in this.submitted)&&this.optional(t)||this.element(t)},onkeyup:function(t,e){(9!==e.which||""!==this.elementValue(t))&&(t.name in this.submitted||t===this.lastElement)&&this.element(t)},onclick:function(t){t.name in this.submitted?this.element(t):t.parentNode.name in this.submitted&&this.element(t.parentNode)},highlight:function(e,i,s){"radio"===e.type?this.findByName(e.name).addClass(i).removeClass(s):t(e).addClass(i).removeClass(s)},unhighlight:function(e,i,s){"radio"===e.type?this.findByName(e.name).removeClass(i).addClass(s):t(e).removeClass(i).addClass(s)}},setDefaults:function(e){t.extend(t.validator.defaults,e)},messages:{required:"This field is required.",remote:"Please fix this field.",email:"Please enter a valid email address.",url:"Please enter a valid URL.",date:"Please enter a valid date.",dateISO:"Please enter a valid date (ISO).",number:"Please enter a valid number.",digits:"Please enter only digits.",creditcard:"Please enter a valid credit card number.",equalTo:"Please enter the same value again.",maxlength:t.validator.format("Please enter no more than {0} characters."),minlength:t.validator.format("Please enter at least {0} characters."),rangelength:t.validator.format("Please enter a value between {0} and {1} characters long."),range:t.validator.format("Please enter a value between {0} and {1}."),max:t.validator.format("Please enter a value less than or equal to {0}."),min:t.validator.format("Please enter a value greater than or equal to {0}.")},autoCreateRanges:!1,prototype:{init:function(){function e(e){var i=t.data(this[0].form,"validator"),s="on"+e.type.replace(/^validate/,"");i.settings[s]&&i.settings[s].call(i,this[0],e)}this.labelContainer=t(this.settings.errorLabelContainer),this.errorContext=this.labelContainer.length&&this.labelContainer||t(this.currentForm),this.containers=t(this.settings.errorContainer).add(this.settings.errorLabelContainer),this.submitted={},this.valueCache={},this.pendingRequest=0,this.pending={},this.invalid={},this.reset();var i=this.groups={};t.each(this.settings.groups,function(e,s){"string"==typeof s&&(s=s.split(/\s/)),t.each(s,function(t,s){i[s]=e})});var s=this.settings.rules;t.each(s,function(e,i){s[e]=t.validator.normalizeRule(i)}),t(this.currentForm).validateDelegate(":text, [type='password'], [type='file'], select, textarea, [type='number'], [type='search'] ,[type='tel'], [type='url'], [type='email'], [type='datetime'], [type='date'], [type='month'], [type='week'], [type='time'], [type='datetime-local'], [type='range'], [type='color'] ","focusin focusout keyup",e).validateDelegate("[type='radio'], [type='checkbox'], select, option","click",e),this.settings.invalidHandler&&t(this.currentForm).bind("invalid-form.validate",this.settings.invalidHandler)},form:function(){return this.checkForm(),t.extend(this.submitted,this.errorMap),this.invalid=t.extend({},this.errorMap),this.valid()||t(this.currentForm).triggerHandler("invalid-form",[this]),this.showErrors(),this.valid()},checkForm:function(){this.prepareForm();for(var t=0,e=this.currentElements=this.elements();e[t];t++)this.check(e[t]);return this.valid()},element:function(e){e=this.validationTargetFor(this.clean(e)),this.lastElement=e,this.prepareElement(e),this.currentElements=t(e);var i=this.check(e)!==!1;return i?delete this.invalid[e.name]:this.invalid[e.name]=!0,this.numberOfInvalids()||(this.toHide=this.toHide.add(this.containers)),this.showErrors(),i},showErrors:function(e){if(e){t.extend(this.errorMap,e),this.errorList=[];for(var i in e)this.errorList.push({message:e[i],element:this.findByName(i)[0]});this.successList=t.grep(this.successList,function(t){return!(t.name in e)})}this.settings.showErrors?this.settings.showErrors.call(this,this.errorMap,this.errorList):this.defaultShowErrors()},resetForm:function(){t.fn.resetForm&&t(this.currentForm).resetForm(),this.submitted={},this.lastElement=null,this.prepareForm(),this.hideErrors(),this.elements().removeClass(this.settings.errorClass).removeData("previousValue")},numberOfInvalids:function(){return this.objectLength(this.invalid)},objectLength:function(t){var e=0;for(var i in t)e++;return e},hideErrors:function(){this.addWrapper(this.toHide).hide()},valid:function(){return 0===this.size()},size:function(){return this.errorList.length},focusInvalid:function(){if(this.settings.focusInvalid)try{t(this.findLastActive()||this.errorList.length&&this.errorList[0].element||[]).filter(":visible").focus().trigger("focusin")}catch(e){}},findLastActive:function(){var e=this.lastActive;return e&&1===t.grep(this.errorList,function(t){return t.element.name===e.name}).length&&e},elements:function(){var e=this,i={};return t(this.currentForm).find("input, select, textarea").not(":submit, :reset, :image, [disabled]").not(this.settings.ignore).filter(function(){return!this.name&&e.settings.debug&&window.console&&console.error("%o has no name assigned",this),this.name in i||!e.objectLength(t(this).rules())?!1:(i[this.name]=!0,!0)})},clean:function(e){return t(e)[0]},errors:function(){var e=this.settings.errorClass.replace(" ",".");return t(this.settings.errorElement+"."+e,this.errorContext)},reset:function(){this.successList=[],this.errorList=[],this.errorMap={},this.toShow=t([]),this.toHide=t([]),this.currentElements=t([])},prepareForm:function(){this.reset(),this.toHide=this.errors().add(this.containers)},prepareElement:function(t){this.reset(),this.toHide=this.errorsFor(t)},elementValue:function(e){var i=t(e).attr("type"),s=t(e).val();return"radio"===i||"checkbox"===i?t("input[name='"+t(e).attr("name")+"']:checked").val():"string"==typeof s?s.replace(/\r/g,""):s},check:function(e){e=this.validationTargetFor(this.clean(e));var i,s=t(e).rules(),r=!1,n=this.elementValue(e);for(var a in s){var u={method:a,parameters:s[a]};try{if(i=t.validator.methods[a].call(this,n,e,u.parameters),"dependency-mismatch"===i){r=!0;continue}if(r=!1,"pending"===i)return this.toHide=this.toHide.not(this.errorsFor(e)),void 0;if(!i)return this.formatAndAdd(e,u),!1}catch(o){throw this.settings.debug&&window.console&&console.log("Exception occurred when checking element "+e.id+", check the '"+u.method+"' method.",o),o}}return r?void 0:(this.objectLength(s)&&this.successList.push(e),!0)},customDataMessage:function(e,i){return t(e).data("msg-"+i.toLowerCase())||e.attributes&&t(e).attr("data-msg-"+i.toLowerCase())},customMessage:function(t,e){var i=this.settings.messages[t];return i&&(i.constructor===String?i:i[e])},findDefined:function(){for(var t=0;arguments.length>t;t++)if(void 0!==arguments[t])return arguments[t];return void 0},defaultMessage:function(e,i){return this.findDefined(this.customMessage(e.name,i),this.customDataMessage(e,i),!this.settings.ignoreTitle&&e.title||void 0,t.validator.messages[i],"Warning: No message defined for "+e.name+"")},formatAndAdd:function(e,i){var s=this.defaultMessage(e,i.method),r=/\$?\{(\d+)\}/g;"function"==typeof s?s=s.call(this,i.parameters,e):r.test(s)&&(s=t.validator.format(s.replace(r,"{$1}"),i.parameters)),this.errorList.push({message:s,element:e}),this.errorMap[e.name]=s,this.submitted[e.name]=s},addWrapper:function(t){return this.settings.wrapper&&(t=t.add(t.parent(this.settings.wrapper))),t},defaultShowErrors:function(){var t,e;for(t=0;this.errorList[t];t++){var i=this.errorList[t];this.settings.highlight&&this.settings.highlight.call(this,i.element,this.settings.errorClass,this.settings.validClass),this.showLabel(i.element,i.message)}if(this.errorList.length&&(this.toShow=this.toShow.add(this.containers)),this.settings.success)for(t=0;this.successList[t];t++)this.showLabel(this.successList[t]);if(this.settings.unhighlight)for(t=0,e=this.validElements();e[t];t++)this.settings.unhighlight.call(this,e[t],this.settings.errorClass,this.settings.validClass);this.toHide=this.toHide.not(this.toShow),this.hideErrors(),this.addWrapper(this.toShow).show()},validElements:function(){return this.currentElements.not(this.invalidElements())},invalidElements:function(){return t(this.errorList).map(function(){return this.element})},showLabel:function(e,i){var s=this.errorsFor(e);s.length?(s.removeClass(this.settings.validClass).addClass(this.settings.errorClass),s.html(i)):(s=t("<"+this.settings.errorElement+">").attr("for",this.idOrName(e)).addClass(this.settings.errorClass).html(i||""),this.settings.wrapper&&(s=s.hide().show().wrap("<"+this.settings.wrapper+"/>").parent()),this.labelContainer.append(s).length||(this.settings.errorPlacement?this.settings.errorPlacement(s,t(e)):s.insertAfter(e))),!i&&this.settings.success&&(s.text(""),"string"==typeof this.settings.success?s.addClass(this.settings.success):this.settings.success(s,e)),this.toShow=this.toShow.add(s)},errorsFor:function(e){var i=this.idOrName(e);return this.errors().filter(function(){return t(this).attr("for")===i})},idOrName:function(t){return this.groups[t.name]||(this.checkable(t)?t.name:t.id||t.name)},validationTargetFor:function(t){return this.checkable(t)&&(t=this.findByName(t.name).not(this.settings.ignore)[0]),t},checkable:function(t){return/radio|checkbox/i.test(t.type)},findByName:function(e){return t(this.currentForm).find("[name='"+e+"']")},getLength:function(e,i){switch(i.nodeName.toLowerCase()){case"select":return t("option:selected",i).length;case"input":if(this.checkable(i))return this.findByName(i.name).filter(":checked").length}return e.length},depend:function(t,e){return this.dependTypes[typeof t]?this.dependTypes[typeof t](t,e):!0},dependTypes:{"boolean":function(t){return t},string:function(e,i){return!!t(e,i.form).length},"function":function(t,e){return t(e)}},optional:function(e){var i=this.elementValue(e);return!t.validator.methods.required.call(this,i,e)&&"dependency-mismatch"},startRequest:function(t){this.pending[t.name]||(this.pendingRequest++,this.pending[t.name]=!0)},stopRequest:function(e,i){this.pendingRequest--,0>this.pendingRequest&&(this.pendingRequest=0),delete this.pending[e.name],i&&0===this.pendingRequest&&this.formSubmitted&&this.form()?(t(this.currentForm).submit(),this.formSubmitted=!1):!i&&0===this.pendingRequest&&this.formSubmitted&&(t(this.currentForm).triggerHandler("invalid-form",[this]),this.formSubmitted=!1)},previousValue:function(e){return t.data(e,"previousValue")||t.data(e,"previousValue",{old:null,valid:!0,message:this.defaultMessage(e,"remote")})}},classRuleSettings:{required:{required:!0},email:{email:!0},url:{url:!0},date:{date:!0},dateISO:{dateISO:!0},number:{number:!0},digits:{digits:!0},creditcard:{creditcard:!0}},addClassRules:function(e,i){e.constructor===String?this.classRuleSettings[e]=i:t.extend(this.classRuleSettings,e)},classRules:function(e){var i={},s=t(e).attr("class");return s&&t.each(s.split(" "),function(){this in t.validator.classRuleSettings&&t.extend(i,t.validator.classRuleSettings[this])}),i},attributeRules:function(e){var i={},s=t(e),r=s[0].getAttribute("type");for(var n in t.validator.methods){var a;"required"===n?(a=s.get(0).getAttribute(n),""===a&&(a=!0),a=!!a):a=s.attr(n),/min|max/.test(n)&&(null===r||/number|range|text/.test(r))&&(a=Number(a)),a?i[n]=a:r===n&&"range"!==r&&(i[n]=!0)}return i.maxlength&&/-1|2147483647|524288/.test(i.maxlength)&&delete i.maxlength,i},dataRules:function(e){var i,s,r={},n=t(e);for(i in t.validator.methods)s=n.data("rule-"+i.toLowerCase()),void 0!==s&&(r[i]=s);return r},staticRules:function(e){var i={},s=t.data(e.form,"validator");return s.settings.rules&&(i=t.validator.normalizeRule(s.settings.rules[e.name])||{}),i},normalizeRules:function(e,i){return t.each(e,function(s,r){if(r===!1)return delete e[s],void 0;if(r.param||r.depends){var n=!0;switch(typeof r.depends){case"string":n=!!t(r.depends,i.form).length;break;case"function":n=r.depends.call(i,i)}n?e[s]=void 0!==r.param?r.param:!0:delete e[s]}}),t.each(e,function(s,r){e[s]=t.isFunction(r)?r(i):r}),t.each(["minlength","maxlength"],function(){e[this]&&(e[this]=Number(e[this]))}),t.each(["rangelength","range"],function(){var i;e[this]&&(t.isArray(e[this])?e[this]=[Number(e[this][0]),Number(e[this][1])]:"string"==typeof e[this]&&(i=e[this].split(/[\s,]+/),e[this]=[Number(i[0]),Number(i[1])]))}),t.validator.autoCreateRanges&&(e.min&&e.max&&(e.range=[e.min,e.max],delete e.min,delete e.max),e.minlength&&e.maxlength&&(e.rangelength=[e.minlength,e.maxlength],delete e.minlength,delete e.maxlength)),e},normalizeRule:function(e){if("string"==typeof e){var i={};t.each(e.split(/\s/),function(){i[this]=!0}),e=i}return e},addMethod:function(e,i,s){t.validator.methods[e]=i,t.validator.messages[e]=void 0!==s?s:t.validator.messages[e],3>i.length&&t.validator.addClassRules(e,t.validator.normalizeRule(e))},methods:{required:function(e,i,s){if(!this.depend(s,i))return"dependency-mismatch";if("select"===i.nodeName.toLowerCase()){var r=t(i).val();return r&&r.length>0}return this.checkable(i)?this.getLength(e,i)>0:t.trim(e).length>0},email:function(t,e){return this.optional(e)||/^((([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+(\.([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+)*)|((\x22)((((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(([\x01-\x08\x0b\x0c\x0e-\x1f\x7f]|\x21|[\x23-\x5b]|[\x5d-\x7e]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(\\([\x01-\x09\x0b\x0c\x0d-\x7f]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]))))*(((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(\x22)))@((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))$/i.test(t)},url:function(t,e){return this.optional(e)||/^(https?|s?ftp):\/\/(((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:)*@)?(((\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5]))|((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.?)(:\d*)?)(\/((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)+(\/(([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)*)*)?)?(\?((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)|[\uE000-\uF8FF]|\/|\?)*)?(#((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)|\/|\?)*)?$/i.test(t)},date:function(t,e){return this.optional(e)||!/Invalid|NaN/.test(""+new Date(t))},dateISO:function(t,e){return this.optional(e)||/^\d{4}[\/\-]\d{1,2}[\/\-]\d{1,2}$/.test(t)},number:function(t,e){return this.optional(e)||/^-?(?:\d+|\d{1,3}(?:,\d{3})+)?(?:\.\d+)?$/.test(t)},digits:function(t,e){return this.optional(e)||/^\d+$/.test(t)},creditcard:function(t,e){if(this.optional(e))return"dependency-mismatch";if(/[^0-9 \-]+/.test(t))return!1;var i=0,s=0,r=!1;t=t.replace(/\D/g,"");for(var n=t.length-1;n>=0;n--){var a=t.charAt(n);s=parseInt(a,10),r&&(s*=2)>9&&(s-=9),i+=s,r=!r}return 0===i%10},minlength:function(e,i,s){var r=t.isArray(e)?e.length:this.getLength(t.trim(e),i);return this.optional(i)||r>=s},maxlength:function(e,i,s){var r=t.isArray(e)?e.length:this.getLength(t.trim(e),i);return this.optional(i)||s>=r},rangelength:function(e,i,s){var r=t.isArray(e)?e.length:this.getLength(t.trim(e),i);return this.optional(i)||r>=s[0]&&s[1]>=r},min:function(t,e,i){return this.optional(e)||t>=i},max:function(t,e,i){return this.optional(e)||i>=t},range:function(t,e,i){return this.optional(e)||t>=i[0]&&i[1]>=t},equalTo:function(e,i,s){var r=t(s);return this.settings.onfocusout&&r.unbind(".validate-equalTo").bind("blur.validate-equalTo",function(){t(i).valid()}),e===r.val()},remote:function(e,i,s){if(this.optional(i))return"dependency-mismatch";var r=this.previousValue(i);if(this.settings.messages[i.name]||(this.settings.messages[i.name]={}),r.originalMessage=this.settings.messages[i.name].remote,this.settings.messages[i.name].remote=r.message,s="string"==typeof s&&{url:s}||s,r.old===e)return r.valid;r.old=e;var n=this;this.startRequest(i);var a={};return a[i.name]=e,t.ajax(t.extend(!0,{url:s,mode:"abort",port:"validate"+i.name,dataType:"json",data:a,success:function(s){n.settings.messages[i.name].remote=r.originalMessage;var a=s===!0||"true"===s;if(a){var u=n.formSubmitted;n.prepareElement(i),n.formSubmitted=u,n.successList.push(i),delete n.invalid[i.name],n.showErrors()}else{var o={},l=s||n.defaultMessage(i,"remote");o[i.name]=r.message=t.isFunction(l)?l(e):l,n.invalid[i.name]=!0,n.showErrors(o)}r.valid=a,n.stopRequest(i,a)}},s)),"pending"}}}),t.format=t.validator.format})(jQuery),function(t){var e={};if(t.ajaxPrefilter)t.ajaxPrefilter(function(t,i,s){var r=t.port;"abort"===t.mode&&(e[r]&&e[r].abort(),e[r]=s)});else{var i=t.ajax;t.ajax=function(s){var r=("mode"in s?s:t.ajaxSettings).mode,n=("port"in s?s:t.ajaxSettings).port;return"abort"===r?(e[n]&&e[n].abort(),e[n]=i.apply(this,arguments),e[n]):i.apply(this,arguments)}}}(jQuery),function(t){t.extend(t.fn,{validateDelegate:function(e,i,s){return this.bind(i,function(i){var r=t(i.target);return r.is(e)?s.apply(r,arguments):void 0})}})}(jQuery); -------------------------------------------------------------------------------- /AspNetExtendingIdentityRoles/Scripts/bootstrap.min.js: -------------------------------------------------------------------------------- 1 | /* NUGET: BEGIN LICENSE TEXT 2 | * 3 | * Microsoft grants you the right to use these script files for the sole 4 | * purpose of either: (i) interacting through your browser with the Microsoft 5 | * website or online service, subject to the applicable licensing or use 6 | * terms; or (ii) using the files as included with a Microsoft product subject 7 | * to that product's license terms. Microsoft reserves all other rights to the 8 | * files not expressly granted by Microsoft, whether by implication, estoppel 9 | * or otherwise. Insofar as a script file is dual licensed under GPL, 10 | * Microsoft neither took the code under GPL nor distributes it thereunder but 11 | * under the terms set out in this paragraph. All notices and licenses 12 | * below are for informational purposes only. 13 | * 14 | * NUGET: END LICENSE TEXT */ 15 | 16 | /** 17 | * bootstrap.js v3.0.0 by @fat and @mdo 18 | * Copyright 2013 Twitter Inc. 19 | * http://www.apache.org/licenses/LICENSE-2.0 20 | */ 21 | if(!jQuery)throw new Error("Bootstrap requires jQuery");+function(a){"use strict";function b(){var a=document.createElement("bootstrap"),b={WebkitTransition:"webkitTransitionEnd",MozTransition:"transitionend",OTransition:"oTransitionEnd otransitionend",transition:"transitionend"};for(var c in b)if(void 0!==a.style[c])return{end:b[c]}}a.fn.emulateTransitionEnd=function(b){var c=!1,d=this;a(this).one(a.support.transition.end,function(){c=!0});var e=function(){c||a(d).trigger(a.support.transition.end)};return setTimeout(e,b),this},a(function(){a.support.transition=b()})}(window.jQuery),+function(a){"use strict";var b='[data-dismiss="alert"]',c=function(c){a(c).on("click",b,this.close)};c.prototype.close=function(b){function c(){f.trigger("closed.bs.alert").remove()}var d=a(this),e=d.attr("data-target");e||(e=d.attr("href"),e=e&&e.replace(/.*(?=#[^\s]*$)/,""));var f=a(e);b&&b.preventDefault(),f.length||(f=d.hasClass("alert")?d:d.parent()),f.trigger(b=a.Event("close.bs.alert")),b.isDefaultPrevented()||(f.removeClass("in"),a.support.transition&&f.hasClass("fade")?f.one(a.support.transition.end,c).emulateTransitionEnd(150):c())};var d=a.fn.alert;a.fn.alert=function(b){return this.each(function(){var d=a(this),e=d.data("bs.alert");e||d.data("bs.alert",e=new c(this)),"string"==typeof b&&e[b].call(d)})},a.fn.alert.Constructor=c,a.fn.alert.noConflict=function(){return a.fn.alert=d,this},a(document).on("click.bs.alert.data-api",b,c.prototype.close)}(window.jQuery),+function(a){"use strict";var b=function(c,d){this.$element=a(c),this.options=a.extend({},b.DEFAULTS,d)};b.DEFAULTS={loadingText:"loading..."},b.prototype.setState=function(a){var b="disabled",c=this.$element,d=c.is("input")?"val":"html",e=c.data();a+="Text",e.resetText||c.data("resetText",c[d]()),c[d](e[a]||this.options[a]),setTimeout(function(){"loadingText"==a?c.addClass(b).attr(b,b):c.removeClass(b).removeAttr(b)},0)},b.prototype.toggle=function(){var a=this.$element.closest('[data-toggle="buttons"]');if(a.length){var b=this.$element.find("input").prop("checked",!this.$element.hasClass("active")).trigger("change");"radio"===b.prop("type")&&a.find(".active").removeClass("active")}this.$element.toggleClass("active")};var c=a.fn.button;a.fn.button=function(c){return this.each(function(){var d=a(this),e=d.data("bs.button"),f="object"==typeof c&&c;e||d.data("bs.button",e=new b(this,f)),"toggle"==c?e.toggle():c&&e.setState(c)})},a.fn.button.Constructor=b,a.fn.button.noConflict=function(){return a.fn.button=c,this},a(document).on("click.bs.button.data-api","[data-toggle^=button]",function(b){var c=a(b.target);c.hasClass("btn")||(c=c.closest(".btn")),c.button("toggle"),b.preventDefault()})}(window.jQuery),+function(a){"use strict";var b=function(b,c){this.$element=a(b),this.$indicators=this.$element.find(".carousel-indicators"),this.options=c,this.paused=this.sliding=this.interval=this.$active=this.$items=null,"hover"==this.options.pause&&this.$element.on("mouseenter",a.proxy(this.pause,this)).on("mouseleave",a.proxy(this.cycle,this))};b.DEFAULTS={interval:5e3,pause:"hover",wrap:!0},b.prototype.cycle=function(b){return b||(this.paused=!1),this.interval&&clearInterval(this.interval),this.options.interval&&!this.paused&&(this.interval=setInterval(a.proxy(this.next,this),this.options.interval)),this},b.prototype.getActiveIndex=function(){return this.$active=this.$element.find(".item.active"),this.$items=this.$active.parent().children(),this.$items.index(this.$active)},b.prototype.to=function(b){var c=this,d=this.getActiveIndex();return b>this.$items.length-1||0>b?void 0:this.sliding?this.$element.one("slid",function(){c.to(b)}):d==b?this.pause().cycle():this.slide(b>d?"next":"prev",a(this.$items[b]))},b.prototype.pause=function(b){return b||(this.paused=!0),this.$element.find(".next, .prev").length&&a.support.transition.end&&(this.$element.trigger(a.support.transition.end),this.cycle(!0)),this.interval=clearInterval(this.interval),this},b.prototype.next=function(){return this.sliding?void 0:this.slide("next")},b.prototype.prev=function(){return this.sliding?void 0:this.slide("prev")},b.prototype.slide=function(b,c){var d=this.$element.find(".item.active"),e=c||d[b](),f=this.interval,g="next"==b?"left":"right",h="next"==b?"first":"last",i=this;if(!e.length){if(!this.options.wrap)return;e=this.$element.find(".item")[h]()}this.sliding=!0,f&&this.pause();var j=a.Event("slide.bs.carousel",{relatedTarget:e[0],direction:g});if(!e.hasClass("active")){if(this.$indicators.length&&(this.$indicators.find(".active").removeClass("active"),this.$element.one("slid",function(){var b=a(i.$indicators.children()[i.getActiveIndex()]);b&&b.addClass("active")})),a.support.transition&&this.$element.hasClass("slide")){if(this.$element.trigger(j),j.isDefaultPrevented())return;e.addClass(b),e[0].offsetWidth,d.addClass(g),e.addClass(g),d.one(a.support.transition.end,function(){e.removeClass([b,g].join(" ")).addClass("active"),d.removeClass(["active",g].join(" ")),i.sliding=!1,setTimeout(function(){i.$element.trigger("slid")},0)}).emulateTransitionEnd(600)}else{if(this.$element.trigger(j),j.isDefaultPrevented())return;d.removeClass("active"),e.addClass("active"),this.sliding=!1,this.$element.trigger("slid")}return f&&this.cycle(),this}};var c=a.fn.carousel;a.fn.carousel=function(c){return this.each(function(){var d=a(this),e=d.data("bs.carousel"),f=a.extend({},b.DEFAULTS,d.data(),"object"==typeof c&&c),g="string"==typeof c?c:f.slide;e||d.data("bs.carousel",e=new b(this,f)),"number"==typeof c?e.to(c):g?e[g]():f.interval&&e.pause().cycle()})},a.fn.carousel.Constructor=b,a.fn.carousel.noConflict=function(){return a.fn.carousel=c,this},a(document).on("click.bs.carousel.data-api","[data-slide], [data-slide-to]",function(b){var c,d=a(this),e=a(d.attr("data-target")||(c=d.attr("href"))&&c.replace(/.*(?=#[^\s]+$)/,"")),f=a.extend({},e.data(),d.data()),g=d.attr("data-slide-to");g&&(f.interval=!1),e.carousel(f),(g=d.attr("data-slide-to"))&&e.data("bs.carousel").to(g),b.preventDefault()}),a(window).on("load",function(){a('[data-ride="carousel"]').each(function(){var b=a(this);b.carousel(b.data())})})}(window.jQuery),+function(a){"use strict";var b=function(c,d){this.$element=a(c),this.options=a.extend({},b.DEFAULTS,d),this.transitioning=null,this.options.parent&&(this.$parent=a(this.options.parent)),this.options.toggle&&this.toggle()};b.DEFAULTS={toggle:!0},b.prototype.dimension=function(){var a=this.$element.hasClass("width");return a?"width":"height"},b.prototype.show=function(){if(!this.transitioning&&!this.$element.hasClass("in")){var b=a.Event("show.bs.collapse");if(this.$element.trigger(b),!b.isDefaultPrevented()){var c=this.$parent&&this.$parent.find("> .panel > .in");if(c&&c.length){var d=c.data("bs.collapse");if(d&&d.transitioning)return;c.collapse("hide"),d||c.data("bs.collapse",null)}var e=this.dimension();this.$element.removeClass("collapse").addClass("collapsing")[e](0),this.transitioning=1;var f=function(){this.$element.removeClass("collapsing").addClass("in")[e]("auto"),this.transitioning=0,this.$element.trigger("shown.bs.collapse")};if(!a.support.transition)return f.call(this);var g=a.camelCase(["scroll",e].join("-"));this.$element.one(a.support.transition.end,a.proxy(f,this)).emulateTransitionEnd(350)[e](this.$element[0][g])}}},b.prototype.hide=function(){if(!this.transitioning&&this.$element.hasClass("in")){var b=a.Event("hide.bs.collapse");if(this.$element.trigger(b),!b.isDefaultPrevented()){var c=this.dimension();this.$element[c](this.$element[c]())[0].offsetHeight,this.$element.addClass("collapsing").removeClass("collapse").removeClass("in"),this.transitioning=1;var d=function(){this.transitioning=0,this.$element.trigger("hidden.bs.collapse").removeClass("collapsing").addClass("collapse")};return a.support.transition?(this.$element[c](0).one(a.support.transition.end,a.proxy(d,this)).emulateTransitionEnd(350),void 0):d.call(this)}}},b.prototype.toggle=function(){this[this.$element.hasClass("in")?"hide":"show"]()};var c=a.fn.collapse;a.fn.collapse=function(c){return this.each(function(){var d=a(this),e=d.data("bs.collapse"),f=a.extend({},b.DEFAULTS,d.data(),"object"==typeof c&&c);e||d.data("bs.collapse",e=new b(this,f)),"string"==typeof c&&e[c]()})},a.fn.collapse.Constructor=b,a.fn.collapse.noConflict=function(){return a.fn.collapse=c,this},a(document).on("click.bs.collapse.data-api","[data-toggle=collapse]",function(b){var c,d=a(this),e=d.attr("data-target")||b.preventDefault()||(c=d.attr("href"))&&c.replace(/.*(?=#[^\s]+$)/,""),f=a(e),g=f.data("bs.collapse"),h=g?"toggle":d.data(),i=d.attr("data-parent"),j=i&&a(i);g&&g.transitioning||(j&&j.find('[data-toggle=collapse][data-parent="'+i+'"]').not(d).addClass("collapsed"),d[f.hasClass("in")?"addClass":"removeClass"]("collapsed")),f.collapse(h)})}(window.jQuery),+function(a){"use strict";function b(){a(d).remove(),a(e).each(function(b){var d=c(a(this));d.hasClass("open")&&(d.trigger(b=a.Event("hide.bs.dropdown")),b.isDefaultPrevented()||d.removeClass("open").trigger("hidden.bs.dropdown"))})}function c(b){var c=b.attr("data-target");c||(c=b.attr("href"),c=c&&/#/.test(c)&&c.replace(/.*(?=#[^\s]*$)/,""));var d=c&&a(c);return d&&d.length?d:b.parent()}var d=".dropdown-backdrop",e="[data-toggle=dropdown]",f=function(b){a(b).on("click.bs.dropdown",this.toggle)};f.prototype.toggle=function(d){var e=a(this);if(!e.is(".disabled, :disabled")){var f=c(e),g=f.hasClass("open");if(b(),!g){if("ontouchstart"in document.documentElement&&!f.closest(".navbar-nav").length&&a(''}),b.prototype=a.extend({},a.fn.tooltip.Constructor.prototype),b.prototype.constructor=b,b.prototype.getDefaults=function(){return b.DEFAULTS},b.prototype.setContent=function(){var a=this.tip(),b=this.getTitle(),c=this.getContent();a.find(".popover-title")[this.options.html?"html":"text"](b),a.find(".popover-content")[this.options.html?"html":"text"](c),a.removeClass("fade top bottom left right in"),a.find(".popover-title").html()||a.find(".popover-title").hide()},b.prototype.hasContent=function(){return this.getTitle()||this.getContent()},b.prototype.getContent=function(){var a=this.$element,b=this.options;return a.attr("data-content")||("function"==typeof b.content?b.content.call(a[0]):b.content)},b.prototype.arrow=function(){return this.$arrow=this.$arrow||this.tip().find(".arrow")},b.prototype.tip=function(){return this.$tip||(this.$tip=a(this.options.template)),this.$tip};var c=a.fn.popover;a.fn.popover=function(c){return this.each(function(){var d=a(this),e=d.data("bs.popover"),f="object"==typeof c&&c;e||d.data("bs.popover",e=new b(this,f)),"string"==typeof c&&e[c]()})},a.fn.popover.Constructor=b,a.fn.popover.noConflict=function(){return a.fn.popover=c,this}}(window.jQuery),+function(a){"use strict";function b(c,d){var e,f=a.proxy(this.process,this);this.$element=a(c).is("body")?a(window):a(c),this.$body=a("body"),this.$scrollElement=this.$element.on("scroll.bs.scroll-spy.data-api",f),this.options=a.extend({},b.DEFAULTS,d),this.selector=(this.options.target||(e=a(c).attr("href"))&&e.replace(/.*(?=#[^\s]+$)/,"")||"")+" .nav li > a",this.offsets=a([]),this.targets=a([]),this.activeTarget=null,this.refresh(),this.process()}b.DEFAULTS={offset:10},b.prototype.refresh=function(){var b=this.$element[0]==window?"offset":"position";this.offsets=a([]),this.targets=a([]);var c=this;this.$body.find(this.selector).map(function(){var d=a(this),e=d.data("target")||d.attr("href"),f=/^#\w/.test(e)&&a(e);return f&&f.length&&[[f[b]().top+(!a.isWindow(c.$scrollElement.get(0))&&c.$scrollElement.scrollTop()),e]]||null}).sort(function(a,b){return a[0]-b[0]}).each(function(){c.offsets.push(this[0]),c.targets.push(this[1])})},b.prototype.process=function(){var a,b=this.$scrollElement.scrollTop()+this.options.offset,c=this.$scrollElement[0].scrollHeight||this.$body[0].scrollHeight,d=c-this.$scrollElement.height(),e=this.offsets,f=this.targets,g=this.activeTarget;if(b>=d)return g!=(a=f.last()[0])&&this.activate(a);for(a=e.length;a--;)g!=f[a]&&b>=e[a]&&(!e[a+1]||b<=e[a+1])&&this.activate(f[a])},b.prototype.activate=function(b){this.activeTarget=b,a(this.selector).parents(".active").removeClass("active");var c=this.selector+'[data-target="'+b+'"],'+this.selector+'[href="'+b+'"]',d=a(c).parents("li").addClass("active");d.parent(".dropdown-menu").length&&(d=d.closest("li.dropdown").addClass("active")),d.trigger("activate")};var c=a.fn.scrollspy;a.fn.scrollspy=function(c){return this.each(function(){var d=a(this),e=d.data("bs.scrollspy"),f="object"==typeof c&&c;e||d.data("bs.scrollspy",e=new b(this,f)),"string"==typeof c&&e[c]()})},a.fn.scrollspy.Constructor=b,a.fn.scrollspy.noConflict=function(){return a.fn.scrollspy=c,this},a(window).on("load",function(){a('[data-spy="scroll"]').each(function(){var b=a(this);b.scrollspy(b.data())})})}(window.jQuery),+function(a){"use strict";var b=function(b){this.element=a(b)};b.prototype.show=function(){var b=this.element,c=b.closest("ul:not(.dropdown-menu)"),d=b.attr("data-target");if(d||(d=b.attr("href"),d=d&&d.replace(/.*(?=#[^\s]*$)/,"")),!b.parent("li").hasClass("active")){var e=c.find(".active:last a")[0],f=a.Event("show.bs.tab",{relatedTarget:e});if(b.trigger(f),!f.isDefaultPrevented()){var g=a(d);this.activate(b.parent("li"),c),this.activate(g,g.parent(),function(){b.trigger({type:"shown.bs.tab",relatedTarget:e})})}}},b.prototype.activate=function(b,c,d){function e(){f.removeClass("active").find("> .dropdown-menu > .active").removeClass("active"),b.addClass("active"),g?(b[0].offsetWidth,b.addClass("in")):b.removeClass("fade"),b.parent(".dropdown-menu")&&b.closest("li.dropdown").addClass("active"),d&&d()}var f=c.find("> .active"),g=d&&a.support.transition&&f.hasClass("fade");g?f.one(a.support.transition.end,e).emulateTransitionEnd(150):e(),f.removeClass("in")};var c=a.fn.tab;a.fn.tab=function(c){return this.each(function(){var d=a(this),e=d.data("bs.tab");e||d.data("bs.tab",e=new b(this)),"string"==typeof c&&e[c]()})},a.fn.tab.Constructor=b,a.fn.tab.noConflict=function(){return a.fn.tab=c,this},a(document).on("click.bs.tab.data-api",'[data-toggle="tab"], [data-toggle="pill"]',function(b){b.preventDefault(),a(this).tab("show")})}(window.jQuery),+function(a){"use strict";var b=function(c,d){this.options=a.extend({},b.DEFAULTS,d),this.$window=a(window).on("scroll.bs.affix.data-api",a.proxy(this.checkPosition,this)).on("click.bs.affix.data-api",a.proxy(this.checkPositionWithEventLoop,this)),this.$element=a(c),this.affixed=this.unpin=null,this.checkPosition()};b.RESET="affix affix-top affix-bottom",b.DEFAULTS={offset:0},b.prototype.checkPositionWithEventLoop=function(){setTimeout(a.proxy(this.checkPosition,this),1)},b.prototype.checkPosition=function(){if(this.$element.is(":visible")){var c=a(document).height(),d=this.$window.scrollTop(),e=this.$element.offset(),f=this.options.offset,g=f.top,h=f.bottom;"object"!=typeof f&&(h=g=f),"function"==typeof g&&(g=f.top()),"function"==typeof h&&(h=f.bottom());var i=null!=this.unpin&&d+this.unpin<=e.top?!1:null!=h&&e.top+this.$element.height()>=c-h?"bottom":null!=g&&g>=d?"top":!1;this.affixed!==i&&(this.unpin&&this.$element.css("top",""),this.affixed=i,this.unpin="bottom"==i?e.top-d:null,this.$element.removeClass(b.RESET).addClass("affix"+(i?"-"+i:"")),"bottom"==i&&this.$element.offset({top:document.body.offsetHeight-h-this.$element.height()}))}};var c=a.fn.affix;a.fn.affix=function(c){return this.each(function(){var d=a(this),e=d.data("bs.affix"),f="object"==typeof c&&c;e||d.data("bs.affix",e=new b(this,f)),"string"==typeof c&&e[c]()})},a.fn.affix.Constructor=b,a.fn.affix.noConflict=function(){return a.fn.affix=c,this},a(window).on("load",function(){a('[data-spy="affix"]').each(function(){var b=a(this),c=b.data();c.offset=c.offset||{},c.offsetBottom&&(c.offset.bottom=c.offsetBottom),c.offsetTop&&(c.offset.top=c.offsetTop),b.affix(c)})})}(window.jQuery); --------------------------------------------------------------------------------