mirror of
https://github.com/Ombi-app/Ombi.git
synced 2025-07-10 15:32:37 -07:00
angular
This commit is contained in:
parent
a19e81d1f8
commit
c764d6557a
17 changed files with 765 additions and 513 deletions
|
@ -29,7 +29,6 @@ namespace PlexRequests.Core.Models
|
|||
public class UserProperties
|
||||
{
|
||||
public string EmailAddress { get; set; }
|
||||
public bool NotifyOnRelease { get; set; }
|
||||
public bool NotifyOnApprove { get; set; }
|
||||
public string UserAlias { get; set; }
|
||||
}
|
||||
}
|
|
@ -28,6 +28,7 @@ using System;
|
|||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Security;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
using Nancy;
|
||||
using Nancy.Authentication.Forms;
|
||||
|
@ -98,7 +99,7 @@ namespace PlexRequests.Core
|
|||
return users.Any();
|
||||
}
|
||||
|
||||
private Guid? CreateUser(string username, string password, string[] claims = default(string[]))
|
||||
private Guid? CreateUser(string username, string password, string[] claims = default(string[]), UserProperties properties = null)
|
||||
{
|
||||
var salt = PasswordHasher.GenerateSalt();
|
||||
|
||||
|
@ -109,7 +110,7 @@ namespace PlexRequests.Core
|
|||
Salt = salt,
|
||||
Hash = PasswordHasher.ComputeHash(password, salt),
|
||||
Claims = ByteConverterHelper.ReturnBytes(claims),
|
||||
UserProperties = ByteConverterHelper.ReturnBytes(new UserProperties())
|
||||
UserProperties = ByteConverterHelper.ReturnBytes(properties ?? new UserProperties())
|
||||
};
|
||||
Repo.Insert(userModel);
|
||||
|
||||
|
@ -118,19 +119,19 @@ namespace PlexRequests.Core
|
|||
return new Guid(userRecord.UserGuid);
|
||||
}
|
||||
|
||||
public Guid? CreateAdmin(string username, string password)
|
||||
public Guid? CreateAdmin(string username, string password, UserProperties properties = null)
|
||||
{
|
||||
return CreateUser(username, password, new[] { UserClaims.User, UserClaims.PowerUser, UserClaims.Admin });
|
||||
return CreateUser(username, password, new[] { UserClaims.User, UserClaims.PowerUser, UserClaims.Admin }, properties);
|
||||
}
|
||||
|
||||
public Guid? CreatePowerUser(string username, string password)
|
||||
public Guid? CreatePowerUser(string username, string password, UserProperties properties = null)
|
||||
{
|
||||
return CreateUser(username, password, new[] { UserClaims.User, UserClaims.PowerUser });
|
||||
return CreateUser(username, password, new[] { UserClaims.User, UserClaims.PowerUser }, properties);
|
||||
}
|
||||
|
||||
public Guid? CreateRegularUser(string username, string password)
|
||||
public Guid? CreateRegularUser(string username, string password, UserProperties properties = null)
|
||||
{
|
||||
return CreateUser(username, password, new[] { UserClaims.User });
|
||||
return CreateUser(username, password, new[] { UserClaims.User }, properties);
|
||||
}
|
||||
|
||||
public bool UpdatePassword(string username, string oldPassword, string newPassword)
|
||||
|
@ -155,6 +156,11 @@ namespace PlexRequests.Core
|
|||
return Repo.Update(userToChange);
|
||||
}
|
||||
|
||||
public async Task<IEnumerable<UsersModel>> GetUsersAsync()
|
||||
{
|
||||
return await Repo.GetAllAsync();
|
||||
}
|
||||
|
||||
public IEnumerable<UsersModel> GetUsers()
|
||||
{
|
||||
return Repo.GetAll();
|
||||
|
@ -170,14 +176,16 @@ namespace PlexRequests.Core
|
|||
public interface ICustomUserMapper
|
||||
{
|
||||
IEnumerable<UsersModel> GetUsers();
|
||||
Task<IEnumerable<UsersModel>> GetUsersAsync();
|
||||
UsersModel GetUser(Guid userId);
|
||||
UsersModel EditUser(UsersModel user);
|
||||
bool DoUsersExist();
|
||||
Guid? ValidateUser(string username, string password);
|
||||
bool UpdatePassword(string username, string oldPassword, string newPassword);
|
||||
Guid? CreateAdmin(string username, string password);
|
||||
Guid? CreatePowerUser(string username, string password);
|
||||
Guid? CreateRegularUser(string username, string password);
|
||||
Guid? CreateAdmin(string username, string password, UserProperties properties = null);
|
||||
Guid? CreatePowerUser(string username, string password, UserProperties properties = null);
|
||||
Guid? CreateRegularUser(string username, string password, UserProperties properties = null);
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
|
3
PlexRequests.UI/Content/app/app.js
Normal file
3
PlexRequests.UI/Content/app/app.js
Normal file
|
@ -0,0 +1,3 @@
|
|||
(function() {
|
||||
module = angular.module('PlexRequests', []);
|
||||
}());
|
|
@ -0,0 +1,36 @@
|
|||
(function () {
|
||||
|
||||
var controller = function ($scope, userManagementService) {
|
||||
|
||||
$scope.user = {}; // The local user to create
|
||||
$scope.users = []; // list of users
|
||||
|
||||
$scope.error = false;
|
||||
$scope.errorMessage = {};
|
||||
|
||||
$scope.getUsers = function () {
|
||||
$scope.users = userManagementService.getUsers()
|
||||
.then(function (data) {
|
||||
$scope.users = data.data;
|
||||
});
|
||||
};
|
||||
|
||||
$scope.addUser = function () {
|
||||
if ($scope.users.length === 0) {
|
||||
$scope.getUsers();
|
||||
}
|
||||
userManagementService.addUser($scope.user).then(function (data) {
|
||||
if (data.message) {
|
||||
$scope.error = true;
|
||||
$scope.errorMessage = data.message;
|
||||
} else {
|
||||
$scope.users.push(data);
|
||||
$scope.user = {};
|
||||
}
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
angular.module('PlexRequests').controller('userManagementController', ["$scope", "userManagementService", controller]);
|
||||
|
||||
}());
|
|
@ -0,0 +1,29 @@
|
|||
(function () {
|
||||
|
||||
var userManagementService = function ($http) {
|
||||
|
||||
var getUsers = function () {
|
||||
return $http.get('/usermanagement/users');
|
||||
};
|
||||
|
||||
var addUser = function (user) {
|
||||
|
||||
return $http({
|
||||
url: '/usermanagement/createuser',
|
||||
method: "POST",
|
||||
data: $.param(user),
|
||||
headers: {
|
||||
'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return {
|
||||
getUsers: getUsers,
|
||||
addUser: addUser
|
||||
};
|
||||
}
|
||||
|
||||
angular.module('PlexRequests').factory('userManagementService', ["$http", userManagementService]);
|
||||
|
||||
}());
|
44
PlexRequests.UI/Helpers/AngularViewBase.cs
Normal file
44
PlexRequests.UI/Helpers/AngularViewBase.cs
Normal file
|
@ -0,0 +1,44 @@
|
|||
#region Copyright
|
||||
// /************************************************************************
|
||||
// Copyright (c) 2016 Jamie Rees
|
||||
// File: EmptyViewBase.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 Nancy.ViewEngines.Razor;
|
||||
|
||||
namespace PlexRequests.UI.Helpers
|
||||
{
|
||||
public class AngularViewBase : NancyRazorViewBase
|
||||
{
|
||||
|
||||
public AngularViewBase()
|
||||
{
|
||||
Layout = "Shared/_AngularLayout.cshtml";
|
||||
}
|
||||
|
||||
public override void Execute()
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
|
@ -69,6 +69,7 @@ namespace PlexRequests.UI.Helpers
|
|||
sb.AppendLine($"<link rel=\"stylesheet\" href=\"{content}/Content/datepicker.min.css\" type=\"text/css\"/>");
|
||||
|
||||
sb.AppendLine($"<script src=\"{content}/Content/jquery-2.2.1.min.js\"></script>");
|
||||
sb.AppendLine($"<script src=\"{content}/Content/app/app.js\"></script>");
|
||||
sb.AppendLine($"<script src=\"{content}/Content/handlebars.min.js\"></script>");
|
||||
sb.AppendLine($"<script src=\"{content}/Content/bootstrap.min.js\"></script>");
|
||||
sb.AppendLine($"<script src=\"{content}/Content/bootstrap-notify.min.js\"></script>");
|
||||
|
|
|
@ -1,14 +1,13 @@
|
|||
using System;
|
||||
|
||||
namespace PlexRequests.UI
|
||||
namespace PlexRequests.UI.Models
|
||||
{
|
||||
public class UserManagementUsersViewModel
|
||||
{
|
||||
public string Username{get;set;}
|
||||
public string Claims{get;set;}
|
||||
public int Id {get;set;}
|
||||
public string Alias {get;set;}
|
||||
public UserType Type { get; set;}
|
||||
public string Username { get; set; }
|
||||
public string Claims { get; set; }
|
||||
public int Id { get; set; }
|
||||
public string Alias { get; set; }
|
||||
public UserType Type { get; set; }
|
||||
public string EmailAddress { get; set; }
|
||||
}
|
||||
|
||||
public enum UserType
|
||||
|
|
|
@ -1,10 +1,14 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
using Nancy;
|
||||
using Nancy.Responses.Negotiation;
|
||||
using Nancy.Security;
|
||||
|
||||
using PlexRequests.Api.Interfaces;
|
||||
using PlexRequests.Core;
|
||||
using PlexRequests.Core.Models;
|
||||
using PlexRequests.Core.SettingModels;
|
||||
using PlexRequests.Helpers;
|
||||
using PlexRequests.UI.Models;
|
||||
|
@ -13,57 +17,88 @@ namespace PlexRequests.UI.Modules
|
|||
{
|
||||
public class UserManagementModule : BaseModule
|
||||
{
|
||||
public UserManagementModule(ISettingsService<PlexRequestSettings> pr, ICustomUserMapper m) : base("usermanagement",pr)
|
||||
public UserManagementModule(ISettingsService<PlexRequestSettings> pr, ICustomUserMapper m, IPlexApi plexApi, ISettingsService<AuthenticationSettings> auth) : base("usermanagement", pr)
|
||||
{
|
||||
this.RequiresClaims(UserClaims.Admin);
|
||||
//this.RequiresClaims(UserClaims.Admin);
|
||||
|
||||
UserMapper = m;
|
||||
PlexApi = plexApi;
|
||||
AuthSettings = auth;
|
||||
|
||||
Get["/"] = x => Load();
|
||||
|
||||
Get["/users"] = x => LoadUsers();
|
||||
UserMapper = m;
|
||||
Get["/users", true] = async (x, ct) => await LoadUsers();
|
||||
Post["/createuser"] = x => CreateUser(Request.Form["userName"].ToString(), Request.Form["password"].ToString());
|
||||
}
|
||||
|
||||
private ICustomUserMapper UserMapper { get; }
|
||||
private IPlexApi PlexApi { get; }
|
||||
private ISettingsService<AuthenticationSettings> AuthSettings { get; }
|
||||
|
||||
private Negotiator Load()
|
||||
{
|
||||
return View["Index"];
|
||||
}
|
||||
|
||||
private Response LoadUsers()
|
||||
private async Task<Response> LoadUsers()
|
||||
{
|
||||
var users = UserMapper.GetUsers();
|
||||
var localUsers = await UserMapper.GetUsersAsync();
|
||||
var model = new List<UserManagementUsersViewModel>();
|
||||
foreach (var user in users)
|
||||
foreach (var user in localUsers)
|
||||
{
|
||||
var claims = ByteConverterHelper.ReturnObject<string[]>(user.Claims);
|
||||
var claimsString = string.Join(", ", claims);
|
||||
|
||||
var userProps = ByteConverterHelper.ReturnObject<UserProperties>(user.UserProperties);
|
||||
|
||||
model.Add(new UserManagementUsersViewModel
|
||||
{
|
||||
Claims = claimsString,
|
||||
Username = user.UserName,
|
||||
Type = UserType.LocalUser,
|
||||
EmailAddress = userProps.EmailAddress
|
||||
});
|
||||
}
|
||||
|
||||
var authSettings = await AuthSettings.GetSettingsAsync();
|
||||
if (!string.IsNullOrEmpty(authSettings.PlexAuthToken))
|
||||
{
|
||||
//Get Plex Users
|
||||
var plexUsers = PlexApi.GetUsers(authSettings.PlexAuthToken);
|
||||
|
||||
foreach (var u in plexUsers.User)
|
||||
{
|
||||
model.Add(new UserManagementUsersViewModel
|
||||
{
|
||||
//Claims = ByteConverterHelper.ReturnObject<string[]>(user.Claims),
|
||||
Claims = "test",
|
||||
Id = user.Id,
|
||||
Username = user.UserName,
|
||||
//Type = UserType.LocalUser
|
||||
Username = u.Username,
|
||||
Type = UserType.PlexUser,
|
||||
//Alias =
|
||||
Claims = "Requestor",
|
||||
EmailAddress = u.Email
|
||||
});
|
||||
}
|
||||
return Response.AsJson(users);
|
||||
}
|
||||
return Response.AsJson(model);
|
||||
}
|
||||
|
||||
//private Response CreateUser(string username, string password, string claims)
|
||||
//{
|
||||
// if (string.IsNullOrWhiteSpace(username) || string.IsNullOrWhiteSpace(password))
|
||||
// {
|
||||
// return Response.AsJson(new JsonResponseModel
|
||||
// {
|
||||
// Result = true,
|
||||
// Message = "Please enter in a valid Username and Password"
|
||||
// });
|
||||
// }
|
||||
// var user = UserMapper.CreateUser(username, password, new string[] {claims});
|
||||
// if (user.HasValue)
|
||||
// {
|
||||
// return Response.AsJson(new JsonResponseModel {Result = true});
|
||||
// }
|
||||
private Response CreateUser(string username, string password)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(username) || string.IsNullOrWhiteSpace(password))
|
||||
{
|
||||
return Response.AsJson(new JsonResponseModel
|
||||
{
|
||||
Result = true,
|
||||
Message = "Please enter in a valid Username and Password"
|
||||
});
|
||||
}
|
||||
var user = UserMapper.CreateRegularUser(username, password);
|
||||
if (user.HasValue)
|
||||
{
|
||||
return Response.AsJson(user);
|
||||
}
|
||||
|
||||
// return Response.AsJson(new JsonResponseModel {Result = false, Message = "Could not save user"});
|
||||
//}
|
||||
return Response.AsJson(new JsonResponseModel { Result = false, Message = "Could not save user" });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -180,8 +180,9 @@
|
|||
<Compile Include="Helpers\ContravariantBindingResolver.cs" />
|
||||
<Compile Include="Helpers\CultureHelper.cs" />
|
||||
<Compile Include="Helpers\CustomHtmlHelper.cs" />
|
||||
<Compile Include="Helpers\HeadphonesSender.cs" />
|
||||
<Compile Include="Helpers\EmptyViewBase.cs" />
|
||||
<Compile Include="Helpers\HeadphonesSender.cs" />
|
||||
<Compile Include="Helpers\AngularViewBase.cs" />
|
||||
<Compile Include="Helpers\ServiceLocator.cs" />
|
||||
<Compile Include="Helpers\StringHelper.cs" />
|
||||
<Compile Include="Helpers\Themes.cs" />
|
||||
|
@ -246,6 +247,9 @@
|
|||
<Compile Include="Validators\RequestedModelValidator.cs" />
|
||||
<Compile Include="Validators\SickRageValidator.cs" />
|
||||
<Compile Include="Validators\SonarrValidator.cs" />
|
||||
<Content Include="Content\app\app.js">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="Content\awesome-bootstrap-checkbox.css">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
|
@ -298,6 +302,9 @@
|
|||
<Content Include="Content\issues.js">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="Content\app\services\userManagement\userManagementService.js">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="Content\swagger\backbone-min.js">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
|
@ -494,6 +501,9 @@
|
|||
<None Include="sqlite3.dll">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</None>
|
||||
<Content Include="Content\app\controllers\userManagement\userManagementController.js">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="web.config">
|
||||
<SubType>Designer</SubType>
|
||||
</Content>
|
||||
|
@ -596,6 +606,18 @@
|
|||
<Content Include="Views\Admin\SchedulerSettings.cshtml">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="Views\Shared\Partial\_Navbar.cshtml">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="Views\Shared\Partial\_Head.cshtml">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="Views\Shared\Partial\_LayoutScripts.cshtml">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="Views\Shared\_AngularLayout.cshtml">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<None Include="Web.Debug.config">
|
||||
<DependentUpon>web.config</DependentUpon>
|
||||
</None>
|
||||
|
@ -698,6 +720,8 @@
|
|||
<Target Name="AfterBuild">
|
||||
</Target>
|
||||
-->
|
||||
<ItemGroup />
|
||||
<ItemGroup>
|
||||
<Folder Include="NewFolder1\" />
|
||||
</ItemGroup>
|
||||
<Import Project="..\packages\Nancy.Viewengines.Razor.1.4.3\build\Nancy.ViewEngines.Razor.targets" Condition="Exists('..\packages\Nancy.Viewengines.Razor.1.4.3\build\Nancy.ViewEngines.Razor.targets')" />
|
||||
</Project>
|
|
@ -2,7 +2,7 @@
|
|||
@using Nancy.Session
|
||||
@using PlexRequests.UI.Helpers
|
||||
@using PlexRequests.UI.Models
|
||||
@inherits Nancy.ViewEngines.Razor.NancyRazorViewBase
|
||||
@inherits Nancy.ViewEngines.Razor.NancyRazorViewBase<dynamic>
|
||||
@{
|
||||
var baseUrl = Html.GetBaseUrl();
|
||||
var url = string.Empty;
|
||||
|
|
27
PlexRequests.UI/Views/Shared/Partial/_Head.cshtml
Normal file
27
PlexRequests.UI/Views/Shared/Partial/_Head.cshtml
Normal file
|
@ -0,0 +1,27 @@
|
|||
@using Nancy.Security
|
||||
@using Nancy.Session
|
||||
@using PlexRequests.UI.Helpers
|
||||
@using PlexRequests.UI.Models
|
||||
@using PlexRequests.UI.Resources
|
||||
@inherits Nancy.ViewEngines.Razor.NancyRazorViewBase<dynamic>
|
||||
@{
|
||||
|
||||
var baseUrl = Html.GetBaseUrl();
|
||||
var url = string.Empty;
|
||||
if (!string.IsNullOrEmpty(baseUrl.ToHtmlString()))
|
||||
{
|
||||
url = "/" + baseUrl.ToHtmlString();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
<div hidden="hidden" id="baseUrl">@baseUrl.ToHtmlString()</div>
|
||||
<head>
|
||||
<title>@UI.Layout_Title</title>
|
||||
<!-- Styles -->
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.15/angular.min.js" type="text/JavaScript"></script>
|
||||
@Html.LoadAnalytics()
|
||||
@Html.LoadAssets()
|
||||
</head>
|
83
PlexRequests.UI/Views/Shared/Partial/_LayoutScripts.cshtml
Normal file
83
PlexRequests.UI/Views/Shared/Partial/_LayoutScripts.cshtml
Normal file
|
@ -0,0 +1,83 @@
|
|||
@using Nancy.Security
|
||||
@using Nancy.Session
|
||||
@using PlexRequests.UI.Helpers
|
||||
@using PlexRequests.UI.Models
|
||||
@using PlexRequests.UI.Resources
|
||||
@inherits Nancy.ViewEngines.Razor.NancyRazorViewBase<dynamic>
|
||||
<script>
|
||||
var urlBase = '@Html.GetBaseUrl()';
|
||||
|
||||
$(function () {
|
||||
|
||||
// Check for update
|
||||
var url = createBaseUrl(urlBase, '/updatechecker');
|
||||
$.ajax({
|
||||
type: "GET",
|
||||
url: url,
|
||||
dataType: "json",
|
||||
success: function (response) {
|
||||
if (response.updateAvailable) {
|
||||
var status = createBaseUrl(urlBase, '/admin/status');
|
||||
$('#updateAvailable').html("<i class='fa fa-cloud-download' aria-hidden='true'></i> @UI.Layout_UpdateAvailablePart1 <a style='color: white' href='" + status + "'>@UI.Layout_UpdateAvailablePart2</a>");
|
||||
$('#updateAvailable').removeAttr("hidden");
|
||||
$('body').addClass('update-available');
|
||||
}
|
||||
},
|
||||
error: function (e) {
|
||||
console.log(e);
|
||||
}
|
||||
});
|
||||
// End Check for update
|
||||
|
||||
|
||||
// Scroller
|
||||
$(document).on('scroll', function () {
|
||||
|
||||
if ($(window).scrollTop() > 100) {
|
||||
$('.scroll-top-wrapper').addClass('show');
|
||||
} else {
|
||||
$('.scroll-top-wrapper').removeClass('show');
|
||||
}
|
||||
});
|
||||
|
||||
$('.scroll-top-wrapper').on('click', scrollToTop);
|
||||
// End Scroller
|
||||
|
||||
|
||||
|
||||
|
||||
// Get Issue count
|
||||
var issueUrl = createBaseUrl(urlBase, '/issues/issuecount');
|
||||
$.ajax({
|
||||
type: "GET",
|
||||
url: issueUrl,
|
||||
dataType: "json",
|
||||
success: function (response) {
|
||||
if (response) {
|
||||
if (response > 0)
|
||||
$('#issueCount').addClass("badge");
|
||||
$('#issueCount').html(+response);
|
||||
}
|
||||
},
|
||||
error: function (e) {
|
||||
console.log(e);
|
||||
}
|
||||
});
|
||||
// End issue count
|
||||
|
||||
|
||||
$('#donate').click(function () {
|
||||
ga('send', 'event', 'Navbar', 'Donate', 'Donate Clicked');
|
||||
});
|
||||
|
||||
|
||||
});
|
||||
|
||||
function scrollToTop() {
|
||||
verticalOffset = typeof (verticalOffset) != 'undefined' ? verticalOffset : 0;
|
||||
element = $('body');
|
||||
offset = element.offset();
|
||||
offsetTop = offset.top;
|
||||
$('html, body').animate({ scrollTop: offsetTop }, 500, 'linear');
|
||||
}
|
||||
</script>
|
94
PlexRequests.UI/Views/Shared/Partial/_Navbar.cshtml
Normal file
94
PlexRequests.UI/Views/Shared/Partial/_Navbar.cshtml
Normal file
|
@ -0,0 +1,94 @@
|
|||
@using Nancy.Security
|
||||
@using Nancy.Session
|
||||
@using Nancy;
|
||||
@using PlexRequests.UI.Helpers
|
||||
@using PlexRequests.UI.Models
|
||||
@using PlexRequests.UI.Resources
|
||||
@inherits Nancy.ViewEngines.Razor.NancyRazorViewBase
|
||||
@{
|
||||
|
||||
var baseUrl = Html.GetBaseUrl();
|
||||
var url = string.Empty;
|
||||
if (!string.IsNullOrEmpty(baseUrl.ToHtmlString()))
|
||||
{
|
||||
url = "/" + baseUrl.ToHtmlString();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
<nav class="navbar navbar-default">
|
||||
<div class="container-fluid">
|
||||
<div class="navbar-header">
|
||||
<button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1">
|
||||
<span class="sr-only">Toggle navigation</span>
|
||||
<span class="icon-bar"></span>
|
||||
<span class="icon-bar"></span>
|
||||
<span class="icon-bar"></span>
|
||||
</button>
|
||||
<a class="navbar-brand" href="@url/search">@UI.Layout_Title</a>
|
||||
</div>
|
||||
|
||||
<div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
|
||||
<ul class="nav navbar-nav">
|
||||
@Html.GetNavbarUrl(Context, "/search", UI.Layout_Search, "search")
|
||||
@Html.GetNavbarUrl(Context, "/requests", UI.Layout_Requests, "plus-circle")
|
||||
@Html.GetNavbarUrl(Context, "/issues", UI.Layout_Issues, "exclamation", "<span id=\"issueCount\"></span>")
|
||||
@if (Context.CurrentUser.IsAuthenticated()) // TODO replace with IsAdmin
|
||||
{
|
||||
<li><a id="donate" href="https://www.paypal.me/PlexRequestsNet" target="_blank"><i class="fa fa-heart" style="color: red"></i> @UI.Layout_Donate</a></li>
|
||||
}
|
||||
</ul>
|
||||
<ul class="nav navbar-nav navbar-right">
|
||||
|
||||
|
||||
@if (!Context.CurrentUser.IsAuthenticated() && Context.Request.Session[SessionKeys.UsernameKey] == null) // TODO replace with IsAdmin
|
||||
{
|
||||
|
||||
<li><a href="@url/login?redirect=@Context.Request.Path"><i class="fa fa-user"></i> @UI.Layout_Admin</a></li>
|
||||
}
|
||||
@if (Context.CurrentUser.IsAuthenticated()) // TODO replace with IsAdmin
|
||||
{
|
||||
<li><a>@UI.Layout_Welcome @Context.Request.Session[SessionKeys.UsernameKey]</a></li>
|
||||
<li class="dropdown">
|
||||
<a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-expanded="false"><i class="fa fa-user"></i> @UI.Layout_Admin <span class="caret"></span></a>
|
||||
<ul class="dropdown-menu" role="menu">
|
||||
<li><a href="@url/admin"><i class="fa fa-cog"></i> @UI.Layout_Settings</a></li>
|
||||
<li><a href="@url/changepassword"><i class="fa fa-key"></i> @UI.Layout_ChangePassword</a></li>
|
||||
|
||||
<li class="divider"></li>
|
||||
<li><a href="@url/logout"><i class="fa fa-sign-out"></i> @UI.Layout_Logout</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
}
|
||||
@if (Context.Request.Session[SessionKeys.UsernameKey] != null && !Context.CurrentUser.IsAuthenticated())
|
||||
{
|
||||
<li class="dropdown">
|
||||
<a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-expanded="false"><i class="fa fa-user"></i> @UI.Layout_Welcome @Context.Request.Session[SessionKeys.UsernameKey] <span class="caret"></span></a>
|
||||
<ul class="dropdown-menu" role="menu">
|
||||
<li><a href="@url/login?redirect=@Context.Request.Path"><i class="fa fa-user"></i> @UI.Layout_Admin</a></li>
|
||||
<li class="divider"></li>
|
||||
<li><a href="@url/userlogin/logout"><i class="fa fa-sign-out"></i> @UI.Layout_Logout</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
|
||||
}
|
||||
<li class="dropdown">
|
||||
|
||||
<a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-expanded="false"><i class="fa fa-language" aria-hidden="true"><span class="caret"></span></i></a>
|
||||
<ul class="dropdown-menu" role="menu">
|
||||
<li><a href="@url/culture?l=en&u=@Context.Request.Path">@UI.Layout_English</a></li>
|
||||
<li><a href="@url/culture?l=nl&u=@Context.Request.Path">@UI.Layout_Dutch</a></li>
|
||||
<li><a href="@url/culture?l=es&u=@Context.Request.Path">@UI.Layout_Spanish</a></li>
|
||||
<li><a href="@url/culture?l=de&u=@Context.Request.Path">@UI.Layout_German</a></li>
|
||||
<li><a href="@url/culture?l=da&u=@Context.Request.Path">@UI.Layout_Danish</a></li>
|
||||
<li><a href="@url/culture?l=pt&u=@Context.Request.Path">@UI.Layout_Portuguese</a></li>
|
||||
<li><a href="@url/culture?l=sv&u=@Context.Request.Path">@UI.Layout_Swedish</a></li>
|
||||
<li><a href="@url/culture?l=it&u=@Context.Request.Path">@UI.Layout_Italian</a></li>
|
||||
</ul>
|
||||
<li/>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<div id="updateAvailable" hidden="hidden"></div>
|
||||
</nav>
|
23
PlexRequests.UI/Views/Shared/_AngularLayout.cshtml
Normal file
23
PlexRequests.UI/Views/Shared/_AngularLayout.cshtml
Normal file
|
@ -0,0 +1,23 @@
|
|||
@using PlexRequests.UI.Helpers
|
||||
@inherits Nancy.ViewEngines.Razor.NancyRazorViewBase
|
||||
<html ng-app="PlexRequests">
|
||||
@Html.Partial("Shared/Partial/_Head")
|
||||
|
||||
<body>
|
||||
|
||||
@Html.Partial("Shared/Partial/_Navbar")
|
||||
|
||||
<div class="container">
|
||||
@RenderBody()
|
||||
</div>
|
||||
<div class="scroll-top-wrapper ">
|
||||
<span class="scroll-top-inner">
|
||||
<i class="fa fa-2x fa-arrow-circle-up"></i>
|
||||
</span>
|
||||
</div>
|
||||
</body>
|
||||
|
||||
@Html.GetInformationalVersion()
|
||||
|
||||
</html>
|
||||
@Html.Partial("Shared/Partial/_LayoutScripts")
|
|
@ -1,191 +1,23 @@
|
|||
@using Nancy.Security
|
||||
@using Nancy.Session
|
||||
@using PlexRequests.UI.Helpers
|
||||
@using PlexRequests.UI.Models
|
||||
@using PlexRequests.UI.Resources
|
||||
@using PlexRequests.UI.Helpers
|
||||
@inherits Nancy.ViewEngines.Razor.NancyRazorViewBase
|
||||
@{
|
||||
var baseUrl = Html.GetBaseUrl();
|
||||
var url = string.Empty;
|
||||
if (!string.IsNullOrEmpty(baseUrl.ToHtmlString()))
|
||||
{
|
||||
url = "/" + baseUrl.ToHtmlString();
|
||||
}
|
||||
}
|
||||
<html>
|
||||
<div hidden="hidden" id="baseUrl">@baseUrl.ToHtmlString()</div>
|
||||
<head>
|
||||
<title>@UI.Layout_Title</title>
|
||||
<!-- Styles -->
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
@Html.LoadAnalytics()
|
||||
@Html.LoadAssets()
|
||||
</head>
|
||||
@Html.Partial("Shared/Partial/_Head")
|
||||
|
||||
<body>
|
||||
|
||||
@Html.Partial("Shared/Partial/_Navbar")
|
||||
|
||||
<nav class="navbar navbar-default">
|
||||
<div class="container-fluid">
|
||||
<div class="navbar-header">
|
||||
<button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1">
|
||||
<span class="sr-only">Toggle navigation</span>
|
||||
<span class="icon-bar"></span>
|
||||
<span class="icon-bar"></span>
|
||||
<span class="icon-bar"></span>
|
||||
</button>
|
||||
<a class="navbar-brand" href="@url/search">@UI.Layout_Title</a>
|
||||
</div>
|
||||
|
||||
<div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
|
||||
<ul class="nav navbar-nav">
|
||||
@Html.GetNavbarUrl(Context, "/search", UI.Layout_Search, "search")
|
||||
@Html.GetNavbarUrl(Context, "/requests", UI.Layout_Requests, "plus-circle")
|
||||
@Html.GetNavbarUrl(Context, "/issues", UI.Layout_Issues, "exclamation", "<span id=\"issueCount\"></span>")
|
||||
@if (Context.CurrentUser.IsAuthenticated()) // TODO replace with IsAdmin
|
||||
{
|
||||
<li><a id="donate" href="https://www.paypal.me/PlexRequestsNet" target="_blank"><i class="fa fa-heart" style="color: red"></i> @UI.Layout_Donate</a></li>
|
||||
}
|
||||
</ul>
|
||||
<ul class="nav navbar-nav navbar-right">
|
||||
|
||||
|
||||
@if (!Context.CurrentUser.IsAuthenticated() && Context.Request.Session[SessionKeys.UsernameKey] == null) // TODO replace with IsAdmin
|
||||
{
|
||||
|
||||
<li><a href="@url/login?redirect=@Context.Request.Path"><i class="fa fa-user"></i> @UI.Layout_Admin</a></li>
|
||||
}
|
||||
@if (Context.CurrentUser.IsAuthenticated()) // TODO replace with IsAdmin
|
||||
{
|
||||
<li><a>@UI.Layout_Welcome @Context.Request.Session[SessionKeys.UsernameKey]</a></li>
|
||||
<li class="dropdown">
|
||||
<a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-expanded="false"><i class="fa fa-user"></i> @UI.Layout_Admin <span class="caret"></span></a>
|
||||
<ul class="dropdown-menu" role="menu">
|
||||
<li><a href="@url/admin"><i class="fa fa-cog"></i> @UI.Layout_Settings</a></li>
|
||||
<li><a href="@url/changepassword"><i class="fa fa-key"></i> @UI.Layout_ChangePassword</a></li>
|
||||
|
||||
<li class="divider"></li>
|
||||
<li><a href="@url/logout"><i class="fa fa-sign-out"></i> @UI.Layout_Logout</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
}
|
||||
@if (Context.Request.Session[SessionKeys.UsernameKey] != null && !Context.CurrentUser.IsAuthenticated())
|
||||
{
|
||||
<li class="dropdown">
|
||||
<a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-expanded="false"><i class="fa fa-user"></i> @UI.Layout_Welcome @Context.Request.Session[SessionKeys.UsernameKey] <span class="caret"></span></a>
|
||||
<ul class="dropdown-menu" role="menu">
|
||||
<li><a href="@url/login?redirect=@Context.Request.Path"><i class="fa fa-user"></i> @UI.Layout_Admin</a></li>
|
||||
<li class="divider"></li>
|
||||
<li><a href="@url/userlogin/logout"><i class="fa fa-sign-out"></i> @UI.Layout_Logout</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
|
||||
}
|
||||
<li class="dropdown">
|
||||
|
||||
<a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-expanded="false"><i class="fa fa-language" aria-hidden="true"><span class="caret"></span></i></a>
|
||||
<ul class="dropdown-menu" role="menu">
|
||||
<li><a href="@url/culture?l=en&u=@Context.Request.Path">@UI.Layout_English</a></li>
|
||||
<li><a href="@url/culture?l=nl&u=@Context.Request.Path">@UI.Layout_Dutch</a></li>
|
||||
<li><a href="@url/culture?l=es&u=@Context.Request.Path">@UI.Layout_Spanish</a></li>
|
||||
<li><a href="@url/culture?l=de&u=@Context.Request.Path">@UI.Layout_German</a></li>
|
||||
<li><a href="@url/culture?l=da&u=@Context.Request.Path">@UI.Layout_Danish</a></li>
|
||||
<li><a href="@url/culture?l=pt&u=@Context.Request.Path">@UI.Layout_Portuguese</a></li>
|
||||
<li><a href="@url/culture?l=sv&u=@Context.Request.Path">@UI.Layout_Swedish</a></li>
|
||||
<li><a href="@url/culture?l=it&u=@Context.Request.Path">@UI.Layout_Italian</a></li>
|
||||
</ul>
|
||||
<li/>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<div id="updateAvailable" hidden="hidden"></div>
|
||||
</nav>
|
||||
|
||||
<div class="container">
|
||||
<div class="container">
|
||||
@RenderBody()
|
||||
</div>
|
||||
<div class="scroll-top-wrapper ">
|
||||
</div>
|
||||
<div class="scroll-top-wrapper ">
|
||||
<span class="scroll-top-inner">
|
||||
<i class="fa fa-2x fa-arrow-circle-up"></i>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
@Html.GetInformationalVersion();
|
||||
|
||||
@Html.GetInformationalVersion()
|
||||
|
||||
</html>
|
||||
<script>
|
||||
|
||||
$(function () {
|
||||
|
||||
var urlBase = '@Html.GetBaseUrl()';
|
||||
|
||||
// Check for update
|
||||
var url = createBaseUrl(urlBase, '/updatechecker');
|
||||
$.ajax({
|
||||
type: "GET",
|
||||
url: url,
|
||||
dataType: "json",
|
||||
success: function (response) {
|
||||
if (response.updateAvailable) {
|
||||
var status = createBaseUrl(urlBase, '/admin/status');
|
||||
$('#updateAvailable').html("<i class='fa fa-cloud-download' aria-hidden='true'></i> @UI.Layout_UpdateAvailablePart1 <a style='color: white' href='" + status + "'>@UI.Layout_UpdateAvailablePart2</a>");
|
||||
$('#updateAvailable').removeAttr("hidden");
|
||||
$('body').addClass('update-available');
|
||||
}
|
||||
},
|
||||
error: function (e) {
|
||||
console.log(e);
|
||||
}
|
||||
});
|
||||
// End Check for update
|
||||
|
||||
|
||||
// Scroller
|
||||
$(document).on('scroll', function () {
|
||||
|
||||
if ($(window).scrollTop() > 100) {
|
||||
$('.scroll-top-wrapper').addClass('show');
|
||||
} else {
|
||||
$('.scroll-top-wrapper').removeClass('show');
|
||||
}
|
||||
});
|
||||
|
||||
$('.scroll-top-wrapper').on('click', scrollToTop);
|
||||
// End Scroller
|
||||
|
||||
|
||||
|
||||
|
||||
// Get Issue count
|
||||
var issueUrl = createBaseUrl(urlBase, '/issues/issuecount');
|
||||
$.ajax({
|
||||
type: "GET",
|
||||
url: issueUrl,
|
||||
dataType: "json",
|
||||
success: function (response) {
|
||||
if (response) {
|
||||
if (response > 0)
|
||||
$('#issueCount').addClass("badge");
|
||||
$('#issueCount').html(+response);
|
||||
}
|
||||
},
|
||||
error: function (e) {
|
||||
console.log(e);
|
||||
}
|
||||
});
|
||||
// End issue count
|
||||
|
||||
|
||||
$('#donate').click(function () {
|
||||
ga('send', 'event', 'Navbar', 'Donate', 'Donate Clicked');
|
||||
});
|
||||
|
||||
|
||||
});
|
||||
|
||||
function scrollToTop() {
|
||||
verticalOffset = typeof (verticalOffset) != 'undefined' ? verticalOffset : 0;
|
||||
element = $('body');
|
||||
offset = element.offset();
|
||||
offsetTop = offset.top;
|
||||
$('html, body').animate({ scrollTop: offsetTop }, 500, 'linear');
|
||||
}
|
||||
</script>
|
||||
@Html.Partial("Shared/Partial/_LayoutScripts")
|
||||
|
|
|
@ -1,4 +1,7 @@
|
|||
@using PlexRequests.UI.Helpers
|
||||
|
||||
@inherits PlexRequests.UI.Helpers.AngularViewBase
|
||||
|
||||
@Html.LoadTableAssets()
|
||||
@{
|
||||
var baseUrl = Html.GetBaseUrl().ToHtmlString();
|
||||
|
@ -8,41 +11,53 @@
|
|||
url = "/" + baseUrl;
|
||||
}
|
||||
}
|
||||
<script src="/Content/app/controllers/userManagement/userManagementController.js"></script>
|
||||
<script src="/Content/app/services/userManagement/userManagementService.js"></script>
|
||||
<div ng-controller="userManagementController" ng-init="getUsers()">
|
||||
|
||||
|
||||
<h2>User Management</h2>
|
||||
|
||||
<button class="btn btn-success-outline" type="submit">Create User <div class="fa fa-plus"/></button>
|
||||
<br>
|
||||
<br>
|
||||
<br>
|
||||
<br>
|
||||
<fieldset>
|
||||
<table id="example" class="table table-striped table-hover table-responsive">
|
||||
<table class="table table-striped table-hover table-responsive">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Id</th>
|
||||
<th>Username</th>
|
||||
<th>Permissions</th>
|
||||
<th>Email</th>
|
||||
<th>User T</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr ng-repeat="u in users">
|
||||
<td>
|
||||
{{u.username}}
|
||||
</td>
|
||||
<td>
|
||||
{{u.emailAddress}}
|
||||
</td>
|
||||
<td>
|
||||
{{u.claims}}
|
||||
</td>
|
||||
<td>
|
||||
{{u.type == 0 ? 'Local User' : 'Plex User'}}
|
||||
{{u.type}}
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
|
||||
</table>
|
||||
|
||||
|
||||
<form ng-submit="addUser()">
|
||||
<div class="form-group">
|
||||
<input id="username" type="text" placeholder="user" ng-model="user.username" class="form-control-custom"/>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<input id="password" type="password" placeholder="password" ng-model="user.password" class="form-control-custom"/>
|
||||
</div>
|
||||
<input type="submit" class="btn btn-success-outline" value="Add"/>
|
||||
</form>
|
||||
</fieldset>
|
||||
|
||||
<script>
|
||||
|
||||
var baseUrl = '@Html.GetBaseUrl()';
|
||||
|
||||
var url = createBaseUrl(baseUrl, "usermanagement/users");
|
||||
$('#example').DataTable({
|
||||
"ajax": url,
|
||||
"columns": [
|
||||
{ "data": "id" },
|
||||
{ "data": "username" },
|
||||
{ "data": "claims" },
|
||||
//{ "data": "type" }
|
||||
],
|
||||
"order": [[1, "desc"]]
|
||||
});
|
||||
</div>
|
||||
|
||||
|
||||
</script>
|
Loading…
Add table
Add a link
Reference in a new issue