From e77add75a1bc5f8f25fe9e2bca18421c367765e2 Mon Sep 17 00:00:00 2001
From: tidusjar <jamierees@outlook.com>
Date: Fri, 26 Aug 2016 10:56:52 +0100
Subject: [PATCH 1/2] Fixed #505

---
 .../Interfaces/INotificationEngine.cs         |  39 +++++
 .../Jobs/PlexAvailabilityChecker.cs           |  65 +-------
 .../Notification/NotificationEngine.cs        | 156 ++++++++++++++++++
 .../PlexRequests.Services.csproj              |   2 +
 PlexRequests.UI/Modules/RequestsModule.cs     |   7 +-
 5 files changed, 209 insertions(+), 60 deletions(-)
 create mode 100644 PlexRequests.Services/Interfaces/INotificationEngine.cs
 create mode 100644 PlexRequests.Services/Notification/NotificationEngine.cs

diff --git a/PlexRequests.Services/Interfaces/INotificationEngine.cs b/PlexRequests.Services/Interfaces/INotificationEngine.cs
new file mode 100644
index 000000000..ba53eb9bf
--- /dev/null
+++ b/PlexRequests.Services/Interfaces/INotificationEngine.cs
@@ -0,0 +1,39 @@
+#region Copyright
+// /************************************************************************
+//    Copyright (c) 2016 Jamie Rees
+//    File: INotificationEngine.cs
+//    Created By: Jamie Rees
+//   
+//    Permission is hereby granted, free of charge, to any person obtaining
+//    a copy of this software and associated documentation files (the
+//    "Software"), to deal in the Software without restriction, including
+//    without limitation the rights to use, copy, modify, merge, publish,
+//    distribute, sublicense, and/or sell copies of the Software, and to
+//    permit persons to whom the Software is furnished to do so, subject to
+//    the following conditions:
+//   
+//    The above copyright notice and this permission notice shall be
+//    included in all copies or substantial portions of the Software.
+//   
+//    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+//    EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+//    MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+//    NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+//    LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+//    OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+//    WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//  ************************************************************************/
+#endregion
+
+using System.Collections.Generic;
+using System.Threading.Tasks;
+using PlexRequests.Store;
+
+namespace PlexRequests.Services.Interfaces
+{
+    public interface INotificationEngine
+    {
+        Task NotifyUsers(IEnumerable<RequestedModel> modelChanged, string apiKey);
+        Task NotifyUsers(RequestedModel modelChanged, string apiKey);
+    }
+}
\ No newline at end of file
diff --git a/PlexRequests.Services/Jobs/PlexAvailabilityChecker.cs b/PlexRequests.Services/Jobs/PlexAvailabilityChecker.cs
index e58a18c17..c72ed45d5 100644
--- a/PlexRequests.Services/Jobs/PlexAvailabilityChecker.cs
+++ b/PlexRequests.Services/Jobs/PlexAvailabilityChecker.cs
@@ -53,7 +53,7 @@ namespace PlexRequests.Services.Jobs
     public class PlexAvailabilityChecker : IJob, IAvailabilityChecker
     {
         public PlexAvailabilityChecker(ISettingsService<PlexSettings> plexSettings, IRequestService request, IPlexApi plex, ICacheProvider cache,
-            INotificationService notify, IJobRecord rec, IRepository<UsersToNotify> users, IRepository<PlexEpisodes> repo)
+            INotificationService notify, IJobRecord rec, IRepository<UsersToNotify> users, IRepository<PlexEpisodes> repo, INotificationEngine e)
         {
             Plex = plexSettings;
             RequestService = request;
@@ -63,6 +63,7 @@ namespace PlexRequests.Services.Jobs
             Job = rec;
             UserNotifyRepo = users;
             EpisodeRepo = repo;
+            NotificationEngine = e;
         }
 
         private ISettingsService<PlexSettings> Plex { get; }
@@ -74,6 +75,9 @@ namespace PlexRequests.Services.Jobs
         private INotificationService Notification { get; }
         private IJobRecord Job { get; }
         private IRepository<UsersToNotify> UserNotifyRepo { get; }
+        private INotificationEngine NotificationEngine { get; }
+
+
         public void CheckAndUpdateAll()
         {
             var plexSettings = Plex.GetSettings();
@@ -148,7 +152,7 @@ namespace PlexRequests.Services.Jobs
 
             if (modifiedModel.Any())
             {
-                NotifyUsers(modifiedModel, plexSettings.PlexAuthToken);
+                NotificationEngine.NotifyUsers(modifiedModel, plexSettings.PlexAuthToken);
                 RequestService.BatchUpdate(modifiedModel);
             }
 
@@ -462,63 +466,6 @@ namespace PlexRequests.Services.Jobs
             return true;
         }
 
-        private void NotifyUsers(IEnumerable<RequestedModel> modelChanged, string apiKey)
-        {
-            try
-            {
-                var plexUser = PlexApi.GetUsers(apiKey);
-                var userAccount = PlexApi.GetAccount(apiKey);
-
-                var adminUsername = userAccount.Username ?? string.Empty;
-
-                var users = UserNotifyRepo.GetAll().ToList();
-                Log.Debug("Notifying Users Count {0}", users.Count);
-                foreach (var model in modelChanged)
-                {
-                    var selectedUsers = users.Select(x => x.Username).Intersect(model.RequestedUsers);
-                    foreach (var user in selectedUsers)
-                    {
-                        Log.Info("Notifying user {0}", user);
-                        if (user == adminUsername)
-                        {
-                            Log.Info("This user is the Plex server owner");
-                            PublishUserNotification(userAccount.Username, userAccount.Email, model.Title);
-                            return;
-                        }
-
-                        var email = plexUser.User.FirstOrDefault(x => x.Username == user);
-                        if (email == null)
-                        {
-                            Log.Info("There is no email address for this Plex user, cannot send notification");
-                            // We do not have a plex user that requested this!
-                            continue;
-                        }
-
-                        Log.Info("Sending notification to: {0} at: {1}, for title: {2}", email.Username, email.Email, model.Title);
-                        PublishUserNotification(email.Username, email.Email, model.Title);
-                    }
-                }
-            }
-            catch (Exception e)
-            {
-                Log.Error(e);
-            }
-        }
-
-        private void PublishUserNotification(string username, string email, string title)
-        {
-            var notificationModel = new NotificationModel
-            {
-                User = username,
-                UserEmail = email,
-                NotificationType = NotificationType.RequestAvailable,
-                Title = title
-            };
-
-            // Send the notification to the user.
-            Notification.Publish(notificationModel);
-        }
-
         public void Execute(IJobExecutionContext context)
         {
             try
diff --git a/PlexRequests.Services/Notification/NotificationEngine.cs b/PlexRequests.Services/Notification/NotificationEngine.cs
new file mode 100644
index 000000000..ccbe07fec
--- /dev/null
+++ b/PlexRequests.Services/Notification/NotificationEngine.cs
@@ -0,0 +1,156 @@
+#region Copyright
+// /************************************************************************
+//    Copyright (c) 2016 Jamie Rees
+//    File: NotificationEngine.cs
+//    Created By: Jamie Rees
+//   
+//    Permission is hereby granted, free of charge, to any person obtaining
+//    a copy of this software and associated documentation files (the
+//    "Software"), to deal in the Software without restriction, including
+//    without limitation the rights to use, copy, modify, merge, publish,
+//    distribute, sublicense, and/or sell copies of the Software, and to
+//    permit persons to whom the Software is furnished to do so, subject to
+//    the following conditions:
+//   
+//    The above copyright notice and this permission notice shall be
+//    included in all copies or substantial portions of the Software.
+//   
+//    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+//    EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+//    MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+//    NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+//    LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+//    OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+//    WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//  ************************************************************************/
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+using NLog;
+using NLog.Fluent;
+using PlexRequests.Api;
+using PlexRequests.Api.Interfaces;
+using PlexRequests.Core.Models;
+using PlexRequests.Services.Interfaces;
+using PlexRequests.Store;
+using PlexRequests.Store.Models;
+using PlexRequests.Store.Repository;
+
+namespace PlexRequests.Services.Notification
+{
+    public class NotificationEngine : INotificationEngine
+    {
+        public NotificationEngine(IPlexApi p, IRepository<UsersToNotify> repo, INotificationService service)
+        {
+            PlexApi = p;
+            UserNotifyRepo = repo;
+            Notification = service;
+        }
+
+        private IPlexApi PlexApi { get; }
+        private IRepository<UsersToNotify> UserNotifyRepo { get; }
+        private static Logger Log = LogManager.GetCurrentClassLogger();
+        private INotificationService Notification { get; }
+
+        public async Task NotifyUsers(IEnumerable<RequestedModel> modelChanged, string apiKey)
+        {
+            try
+            {
+                var plexUser = PlexApi.GetUsers(apiKey);
+                var userAccount = PlexApi.GetAccount(apiKey);
+
+                var adminUsername = userAccount.Username ?? string.Empty;
+
+                var users = UserNotifyRepo.GetAll().ToList();
+                Log.Debug("Notifying Users Count {0}", users.Count);
+                foreach (var model in modelChanged)
+                {
+                    var selectedUsers = users.Select(x => x.Username).Intersect(model.RequestedUsers, StringComparer.CurrentCultureIgnoreCase);
+                    foreach (var user in selectedUsers)
+                    {
+                        Log.Info("Notifying user {0}", user);
+                        if (user.Equals(adminUsername, StringComparison.CurrentCultureIgnoreCase))
+                        {
+                            Log.Info("This user is the Plex server owner");
+                            await PublishUserNotification(userAccount.Username, userAccount.Email, model.Title);
+                            return;
+                        }
+
+                        var email = plexUser.User.FirstOrDefault(x => x.Username.Equals(user, StringComparison.CurrentCultureIgnoreCase));
+                        if (email == null)
+                        {
+                            Log.Info("There is no email address for this Plex user, cannot send notification");
+                            // We do not have a plex user that requested this!
+                            continue;
+                        }
+
+                        Log.Info("Sending notification to: {0} at: {1}, for title: {2}", email.Username, email.Email, model.Title);
+                        await PublishUserNotification(email.Username, email.Email, model.Title);
+                    }
+                }
+            }
+            catch (Exception e)
+            {
+                Log.Error(e);
+            }
+        }
+
+        public async Task NotifyUsers(RequestedModel model, string apiKey)
+        {
+            try
+            {
+                var plexUser = PlexApi.GetUsers(apiKey);
+                var userAccount = PlexApi.GetAccount(apiKey);
+
+                var adminUsername = userAccount.Username ?? string.Empty;
+
+                var users = UserNotifyRepo.GetAll().ToList();
+                Log.Debug("Notifying Users Count {0}", users.Count);
+
+                var selectedUsers = users.Select(x => x.Username).Intersect(model.RequestedUsers, StringComparer.CurrentCultureIgnoreCase);
+                foreach (var user in selectedUsers)
+                {
+                    Log.Info("Notifying user {0}", user);
+                    if (user.Equals(adminUsername, StringComparison.CurrentCultureIgnoreCase))
+                    {
+                        Log.Info("This user is the Plex server owner");
+                        await PublishUserNotification(userAccount.Username, userAccount.Email, model.Title);
+                        return;
+                    }
+
+                    var email = plexUser.User.FirstOrDefault(x => x.Username.Equals(user, StringComparison.CurrentCultureIgnoreCase));
+                    if (email == null)
+                    {
+                        Log.Info("There is no email address for this Plex user, cannot send notification");
+                        // We do not have a plex user that requested this!
+                        continue;
+                    }
+
+                    Log.Info("Sending notification to: {0} at: {1}, for title: {2}", email.Username, email.Email, model.Title);
+                    await PublishUserNotification(email.Username, email.Email, model.Title);
+                }
+            }
+            catch (Exception e)
+            {
+                Log.Error(e);
+            }
+        }
+
+        private async Task PublishUserNotification(string username, string email, string title)
+        {
+            var notificationModel = new NotificationModel
+            {
+                User = username,
+                UserEmail = email,
+                NotificationType = NotificationType.RequestAvailable,
+                Title = title
+            };
+
+            // Send the notification to the user.
+            await Notification.Publish(notificationModel);
+        }
+    }
+}
\ No newline at end of file
diff --git a/PlexRequests.Services/PlexRequests.Services.csproj b/PlexRequests.Services/PlexRequests.Services.csproj
index df4d694c9..6aed947bc 100644
--- a/PlexRequests.Services/PlexRequests.Services.csproj
+++ b/PlexRequests.Services/PlexRequests.Services.csproj
@@ -75,6 +75,7 @@
   </ItemGroup>
   <ItemGroup>
     <Compile Include="Interfaces\IJobRecord.cs" />
+    <Compile Include="Interfaces\INotificationEngine.cs" />
     <Compile Include="Jobs\JobRecord.cs" />
     <Compile Include="Jobs\JobNames.cs" />
     <Compile Include="Jobs\PlexEpisodeCacher.cs" />
@@ -97,6 +98,7 @@
     <Compile Include="Interfaces\INotification.cs" />
     <Compile Include="Interfaces\INotificationService.cs" />
     <Compile Include="Notification\EmailMessageNotification.cs" />
+    <Compile Include="Notification\NotificationEngine.cs" />
     <Compile Include="Notification\NotificationModel.cs" />
     <Compile Include="Notification\NotificationService.cs" />
     <Compile Include="Notification\PushoverNotification.cs" />
diff --git a/PlexRequests.UI/Modules/RequestsModule.cs b/PlexRequests.UI/Modules/RequestsModule.cs
index cb8ed6882..8a2a9821a 100644
--- a/PlexRequests.UI/Modules/RequestsModule.cs
+++ b/PlexRequests.UI/Modules/RequestsModule.cs
@@ -67,7 +67,8 @@ namespace PlexRequests.UI.Modules
             ISonarrApi sonarrApi,
             ISickRageApi sickRageApi,
             ICacheProvider cache,
-            IAnalytics an) : base("requests", prSettings)
+            IAnalytics an,
+            INotificationEngine engine) : base("requests", prSettings)
         {
             Service = service;
             PrSettings = prSettings;
@@ -81,6 +82,7 @@ namespace PlexRequests.UI.Modules
             CpApi = cpApi;
             Cache = cache;
             Analytics = an;
+            NotificationEngine = engine;
 
             Get["/", true] = async (x, ct) => await LoadRequests();
             Get["/movies", true] = async (x, ct) => await GetMovies();
@@ -108,6 +110,7 @@ namespace PlexRequests.UI.Modules
         private ISickRageApi SickRageApi { get; }
         private ICouchPotatoApi CpApi { get; }
         private ICacheProvider Cache { get; }
+        private INotificationEngine NotificationEngine { get; }
 
         private async Task<Negotiator> LoadRequests()
         {
@@ -376,6 +379,8 @@ namespace PlexRequests.UI.Modules
             originalRequest.Available = available;
 
             var result = await Service.UpdateRequestAsync(originalRequest);
+            var plexService = await PlexSettings.GetSettingsAsync();
+            await NotificationEngine.NotifyUsers(originalRequest, plexService.PlexAuthToken);
             return Response.AsJson(result
                                        ? new { Result = true, Available = available, Message = string.Empty }
                                        : new { Result = false, Available = false, Message = "Could not update the availability, please try again or check the logs" });

From d75e309e186373ce22df5b7355d6d7445aaf4aab Mon Sep 17 00:00:00 2001
From: tidusjar <jamierees@outlook.com>
Date: Fri, 26 Aug 2016 14:39:14 +0100
Subject: [PATCH 2/2] User management

---
 .../userManagementController.js               | 57 ++++++++++++-------
 PlexRequests.UI/Content/search.js             | 15 +++++
 PlexRequests.UI/Content/site.js               | 15 -----
 PlexRequests.UI/Helpers/BaseUrlHelper.cs      | 14 +++++
 .../Models/UserManagementUsersViewModel.cs    |  1 +
 .../Modules/UserManagementModule.cs           |  3 +-
 .../NinjectModules/ConfigurationModule.cs     |  1 +
 .../Views/UserManagement/Index.cshtml         | 23 +++++++-
 8 files changed, 88 insertions(+), 41 deletions(-)

diff --git a/PlexRequests.UI/Content/app/userManagement/userManagementController.js b/PlexRequests.UI/Content/app/userManagement/userManagementController.js
index a577b1380..88a85e7aa 100644
--- a/PlexRequests.UI/Content/app/userManagement/userManagementController.js
+++ b/PlexRequests.UI/Content/app/userManagement/userManagementController.js
@@ -9,6 +9,7 @@
         $scope.selectedUser = {}; // User on the right side
         $scope.selectedClaims = {};
 
+
         $scope.sortType = "username";
         $scope.sortReverse = false;
         $scope.searchTerm = "";
@@ -27,20 +28,20 @@
         // Get all users in the system
         $scope.getUsers = function () {
             $scope.users = userManagementService.getUsers()
-            .then(function (data) {
-                $scope.users = data.data;
-            });
+                .then(function (data) {
+                    $scope.users = data.data;
+                });
         };
 
         // Get the claims and populate the create dropdown
         $scope.getClaims = function () {
             userManagementService.getClaims()
-            .then(function (data) {
-                $scope.claims = data.data;
-            });
+                .then(function (data) {
+                    $scope.claims = data.data;
+                });
         }
 
-        // Create a user, do some validation too
+        // Create a user, do some validation too    
         $scope.addUser = function () {
 
             if (!$scope.user.username || !$scope.user.password) {
@@ -50,23 +51,35 @@
                 return;
             }
 
-            userManagementService.addUser($scope.user, $scope.selectedClaims).then(function (data) {
-                if (data.message) {
-                    $scope.error.error = true;
-                    $scope.error.errorMessage = data.message;
-                } else {
-                    $scope.users.push(data); // Push the new user into the array to update the DOM
-                    $scope.user = {};
-                    $scope.selectedClaims = {};
-                }
-            });
+            userManagementService.addUser($scope.user, $scope.selectedClaims)
+                .then(function (data) {
+                    if (data.message) {
+                        $scope.error.error = true;
+                        $scope.error.errorMessage = data.message;
+                    } else {
+                        $scope.users.push(data); // Push the new user into the array to update the DOM
+                        $scope.user = {};
+                        $scope.selectedClaims = {};
+                    }
+                });
         };
 
-        $scope.$watch('claims|filter:{selected:true}', function (nv) {
-            $scope.selectedClaims = nv.map(function (claim) {
-                return claim.name;
-            });
-        }, true);
+        $scope.$watch('claims|filter:{selected:true}',
+            function (nv) {
+                $scope.selectedClaims = nv.map(function (claim) {
+                    return claim.name;
+                });
+            },
+            true);
+
+
+        $scope.updateUser = function () {
+
+        }
+
+        function getBaseUrl() {
+            return $('#baseUrl').val();
+        }
 
 
         // On page load
diff --git a/PlexRequests.UI/Content/search.js b/PlexRequests.UI/Content/search.js
index bf5eea9db..932a68cca 100644
--- a/PlexRequests.UI/Content/search.js
+++ b/PlexRequests.UI/Content/search.js
@@ -5,6 +5,21 @@
         return opts.inverse(this);
 });
 
+Function.prototype.bind = function (parent) {
+    var f = this;
+    var args = [];
+
+    for (var a = 1; a < arguments.length; a++) {
+        args[args.length] = arguments[a];
+    }
+
+    var temp = function () {
+        return f.apply(parent, args);
+    }
+
+    return (temp);
+}
+
 
 
 $(function () {
diff --git a/PlexRequests.UI/Content/site.js b/PlexRequests.UI/Content/site.js
index 70639cf3e..85cae41f8 100644
--- a/PlexRequests.UI/Content/site.js
+++ b/PlexRequests.UI/Content/site.js
@@ -8,21 +8,6 @@
     return s;
 }
 
-Function.prototype.bind = function (parent) {
-    var f = this;
-    var args = [];
-
-    for (var a = 1; a < arguments.length; a++) {
-        args[args.length] = arguments[a];
-    }
-
-    var temp = function () {
-        return f.apply(parent, args);
-    }
-
-    return (temp);
-}
-
 $(function() {
     $('[data-toggle="tooltip"]').tooltip();
 });
diff --git a/PlexRequests.UI/Helpers/BaseUrlHelper.cs b/PlexRequests.UI/Helpers/BaseUrlHelper.cs
index ee821f7ac..8c55ccac8 100644
--- a/PlexRequests.UI/Helpers/BaseUrlHelper.cs
+++ b/PlexRequests.UI/Helpers/BaseUrlHelper.cs
@@ -206,6 +206,20 @@ namespace PlexRequests.UI.Helpers
             return helper.Raw(asset);
         }
 
+
+        public static IHtmlString LoadUserManagementAssets(this HtmlHelpers helper)
+        {
+            var assetLocation = GetBaseUrl();
+            var content = GetContentUrl(assetLocation);
+
+            var controller = $"<script src=\"{content}/Content/app/userManagement/userManagementController.js?v={Assembly}\" type=\"text/javascript\"></script>";
+            controller += $"<script src=\"{content}/Content/app/userManagement/userManagementService.js?v={Assembly}\" type=\"text/javascript\"></script>";
+
+
+            return helper.Raw(controller);
+        }
+
+
         public static IHtmlString LoadTableAssets(this HtmlHelpers helper)
         {
             var sb = new StringBuilder();
diff --git a/PlexRequests.UI/Models/UserManagementUsersViewModel.cs b/PlexRequests.UI/Models/UserManagementUsersViewModel.cs
index 3fbc936ec..915f90075 100644
--- a/PlexRequests.UI/Models/UserManagementUsersViewModel.cs
+++ b/PlexRequests.UI/Models/UserManagementUsersViewModel.cs
@@ -16,6 +16,7 @@ namespace PlexRequests.UI.Models
         public UserType Type { get; set; }
         public string EmailAddress { get; set; }
         public UserManagementPlexInformation PlexInfo { get; set; }
+        public string[] ClaimsArray { get; set; }
     }
 
     public class UserManagementPlexInformation
diff --git a/PlexRequests.UI/Modules/UserManagementModule.cs b/PlexRequests.UI/Modules/UserManagementModule.cs
index efcaeaa39..1e9909565 100644
--- a/PlexRequests.UI/Modules/UserManagementModule.cs
+++ b/PlexRequests.UI/Modules/UserManagementModule.cs
@@ -63,7 +63,8 @@ namespace PlexRequests.UI.Modules
                     Claims = claimsString,
                     Username = user.UserName,
                     Type = UserType.LocalUser,
-                    EmailAddress = userProps.EmailAddress
+                    EmailAddress = userProps.EmailAddress,
+                    ClaimsArray = claims
                 });
             }
 
diff --git a/PlexRequests.UI/NinjectModules/ConfigurationModule.cs b/PlexRequests.UI/NinjectModules/ConfigurationModule.cs
index 5bb10dca3..ae55786e1 100644
--- a/PlexRequests.UI/NinjectModules/ConfigurationModule.cs
+++ b/PlexRequests.UI/NinjectModules/ConfigurationModule.cs
@@ -50,6 +50,7 @@ namespace PlexRequests.UI.NinjectModules
             Bind<ICustomUserMapper>().To<UserMapper>();
 
             Bind<INotificationService>().To<NotificationService>().InSingletonScope();
+            Bind<INotificationEngine>().To<NotificationEngine>();
         }
     }
 }
\ No newline at end of file
diff --git a/PlexRequests.UI/Views/UserManagement/Index.cshtml b/PlexRequests.UI/Views/UserManagement/Index.cshtml
index 8307ef491..abdc5821b 100644
--- a/PlexRequests.UI/Views/UserManagement/Index.cshtml
+++ b/PlexRequests.UI/Views/UserManagement/Index.cshtml
@@ -1,8 +1,7 @@
 @using PlexRequests.UI.Helpers
 @inherits PlexRequests.UI.Helpers.AngularViewBase
 
-<script src="~/Content/app/userManagement/userManagementController.js"></script>
-<script src="~/Content/app/userManagement/userManagementService.js"></script>
+@Html.LoadUserManagementAssets()
 <div ng-controller="userManagementController" ng-init="init()">
 
     <br />
@@ -110,9 +109,27 @@
         <div>
             <strong>User Type: </strong><span ng-bind="selectedUser.type === 1 ? 'Local User' : 'Plex User'"></span>
         </div>
-    </div>
+    <br/>
+    <br/>
+        <div ng-show="selectedUser.type === 1">
+            <!--Edit-->
+            
+            <strong>Modify Roles:</strong>
+            <!--Load all claims-->
+                <div class="checkbox" ng-repeat="claim in claims">
+                    <input id="claimCheckboxEdit_{{$id}}" class="checkbox-custom" name="selectedClaims[]" ng-checked="@*//TODO: Need to figure our how to preselect them*@" ng-model="claim.selected" type="checkbox" value="claim" />
+                    <label for="claimCheckboxEdit_{{$id}}">{{claim.name}}</label>
+                </div>
+        
+
+ 
+            
+            
+            <button ng-click="updateUser()" class="btn btn-primary-outline">Update</button>
+        </div>
 
 
+    </div> <!-- End of user side menu -->
 
 
 </div>
\ No newline at end of file