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
|
@ -1,35 +1,34 @@
|
||||||
#region Copyright
|
#region Copyright
|
||||||
// /************************************************************************
|
// /************************************************************************
|
||||||
// Copyright (c) 2016 Jamie Rees
|
// Copyright (c) 2016 Jamie Rees
|
||||||
// File: UserProperties.cs
|
// File: UserProperties.cs
|
||||||
// Created By: Jamie Rees
|
// Created By: Jamie Rees
|
||||||
//
|
//
|
||||||
// Permission is hereby granted, free of charge, to any person obtaining
|
// Permission is hereby granted, free of charge, to any person obtaining
|
||||||
// a copy of this software and associated documentation files (the
|
// a copy of this software and associated documentation files (the
|
||||||
// "Software"), to deal in the Software without restriction, including
|
// "Software"), to deal in the Software without restriction, including
|
||||||
// without limitation the rights to use, copy, modify, merge, publish,
|
// without limitation the rights to use, copy, modify, merge, publish,
|
||||||
// distribute, sublicense, and/or sell copies of the Software, and to
|
// distribute, sublicense, and/or sell copies of the Software, and to
|
||||||
// permit persons to whom the Software is furnished to do so, subject to
|
// permit persons to whom the Software is furnished to do so, subject to
|
||||||
// the following conditions:
|
// the following conditions:
|
||||||
//
|
//
|
||||||
// The above copyright notice and this permission notice shall be
|
// The above copyright notice and this permission notice shall be
|
||||||
// included in all copies or substantial portions of the Software.
|
// included in all copies or substantial portions of the Software.
|
||||||
//
|
//
|
||||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||||
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||||
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||||
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
// ************************************************************************/
|
// ************************************************************************/
|
||||||
#endregion
|
#endregion
|
||||||
namespace PlexRequests.Core.Models
|
namespace PlexRequests.Core.Models
|
||||||
{
|
{
|
||||||
public class UserProperties
|
public class UserProperties
|
||||||
{
|
{
|
||||||
public string EmailAddress { get; set; }
|
public string EmailAddress { get; set; }
|
||||||
public bool NotifyOnRelease { get; set; }
|
public string UserAlias { get; set; }
|
||||||
public bool NotifyOnApprove { get; set; }
|
}
|
||||||
}
|
|
||||||
}
|
}
|
|
@ -1,183 +1,191 @@
|
||||||
#region Copyright
|
#region Copyright
|
||||||
// /************************************************************************
|
// /************************************************************************
|
||||||
// Copyright (c) 2016 Jamie Rees
|
// Copyright (c) 2016 Jamie Rees
|
||||||
// File: UserMapper.cs
|
// File: UserMapper.cs
|
||||||
// Created By: Jamie Rees
|
// Created By: Jamie Rees
|
||||||
//
|
//
|
||||||
// Permission is hereby granted, free of charge, to any person obtaining
|
// Permission is hereby granted, free of charge, to any person obtaining
|
||||||
// a copy of this software and associated documentation files (the
|
// a copy of this software and associated documentation files (the
|
||||||
// "Software"), to deal in the Software without restriction, including
|
// "Software"), to deal in the Software without restriction, including
|
||||||
// without limitation the rights to use, copy, modify, merge, publish,
|
// without limitation the rights to use, copy, modify, merge, publish,
|
||||||
// distribute, sublicense, and/or sell copies of the Software, and to
|
// distribute, sublicense, and/or sell copies of the Software, and to
|
||||||
// permit persons to whom the Software is furnished to do so, subject to
|
// permit persons to whom the Software is furnished to do so, subject to
|
||||||
// the following conditions:
|
// the following conditions:
|
||||||
//
|
//
|
||||||
// The above copyright notice and this permission notice shall be
|
// The above copyright notice and this permission notice shall be
|
||||||
// included in all copies or substantial portions of the Software.
|
// included in all copies or substantial portions of the Software.
|
||||||
//
|
//
|
||||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||||
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||||
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||||
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
// ************************************************************************/
|
// ************************************************************************/
|
||||||
#endregion
|
#endregion
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Security;
|
using System.Security;
|
||||||
|
using System.Threading.Tasks;
|
||||||
using Nancy;
|
|
||||||
using Nancy.Authentication.Forms;
|
using Nancy;
|
||||||
using Nancy.Security;
|
using Nancy.Authentication.Forms;
|
||||||
|
using Nancy.Security;
|
||||||
using PlexRequests.Core.Models;
|
|
||||||
using PlexRequests.Helpers;
|
using PlexRequests.Core.Models;
|
||||||
using PlexRequests.Store;
|
using PlexRequests.Helpers;
|
||||||
using PlexRequests.Store.Repository;
|
using PlexRequests.Store;
|
||||||
|
using PlexRequests.Store.Repository;
|
||||||
namespace PlexRequests.Core
|
|
||||||
{
|
namespace PlexRequests.Core
|
||||||
public class UserMapper : IUserMapper, ICustomUserMapper
|
{
|
||||||
{
|
public class UserMapper : IUserMapper, ICustomUserMapper
|
||||||
public UserMapper(IRepository<UsersModel> repo)
|
{
|
||||||
{
|
public UserMapper(IRepository<UsersModel> repo)
|
||||||
Repo = repo;
|
{
|
||||||
}
|
Repo = repo;
|
||||||
private static IRepository<UsersModel> Repo { get; set; }
|
}
|
||||||
public IUserIdentity GetUserFromIdentifier(Guid identifier, NancyContext context)
|
private static IRepository<UsersModel> Repo { get; set; }
|
||||||
{
|
public IUserIdentity GetUserFromIdentifier(Guid identifier, NancyContext context)
|
||||||
var user = Repo.Get(identifier.ToString());
|
{
|
||||||
|
var user = Repo.Get(identifier.ToString());
|
||||||
if (user == null)
|
|
||||||
{
|
if (user == null)
|
||||||
return null;
|
{
|
||||||
}
|
return null;
|
||||||
|
}
|
||||||
return new UserIdentity
|
|
||||||
{
|
return new UserIdentity
|
||||||
UserName = user.UserName,
|
{
|
||||||
Claims = ByteConverterHelper.ReturnObject<string[]>(user.Claims)
|
UserName = user.UserName,
|
||||||
};
|
Claims = ByteConverterHelper.ReturnObject<string[]>(user.Claims)
|
||||||
}
|
};
|
||||||
|
}
|
||||||
public Guid? ValidateUser(string username, string password)
|
|
||||||
{
|
public Guid? ValidateUser(string username, string password)
|
||||||
var users = Repo.GetAll();
|
{
|
||||||
|
var users = Repo.GetAll();
|
||||||
foreach (var u in users)
|
|
||||||
{
|
foreach (var u in users)
|
||||||
if (username == u.UserName)
|
{
|
||||||
{
|
if (username == u.UserName)
|
||||||
var passwordMatch = PasswordHasher.VerifyPassword(password, u.Salt, u.Hash);
|
{
|
||||||
if (passwordMatch)
|
var passwordMatch = PasswordHasher.VerifyPassword(password, u.Salt, u.Hash);
|
||||||
{
|
if (passwordMatch)
|
||||||
return new Guid(u.UserGuid);
|
{
|
||||||
}
|
return new Guid(u.UserGuid);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return null;
|
}
|
||||||
}
|
return null;
|
||||||
|
}
|
||||||
public UsersModel EditUser(UsersModel user)
|
|
||||||
{
|
public UsersModel EditUser(UsersModel user)
|
||||||
var existingUser = Repo.Get(user.UserGuid);
|
{
|
||||||
|
var existingUser = Repo.Get(user.UserGuid);
|
||||||
user.Id = existingUser.Id;
|
|
||||||
user.UserGuid = existingUser.UserGuid;
|
user.Id = existingUser.Id;
|
||||||
Repo.Update(user);
|
user.UserGuid = existingUser.UserGuid;
|
||||||
return user;
|
Repo.Update(user);
|
||||||
}
|
return user;
|
||||||
|
}
|
||||||
public bool DoUsersExist()
|
|
||||||
{
|
public bool DoUsersExist()
|
||||||
var users = Repo.GetAll();
|
{
|
||||||
|
var users = Repo.GetAll();
|
||||||
return users.Any();
|
|
||||||
}
|
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();
|
{
|
||||||
|
var salt = PasswordHasher.GenerateSalt();
|
||||||
var userModel = new UsersModel
|
|
||||||
{
|
var userModel = new UsersModel
|
||||||
UserName = username,
|
{
|
||||||
UserGuid = Guid.NewGuid().ToString(),
|
UserName = username,
|
||||||
Salt = salt,
|
UserGuid = Guid.NewGuid().ToString(),
|
||||||
Hash = PasswordHasher.ComputeHash(password, salt),
|
Salt = salt,
|
||||||
Claims = ByteConverterHelper.ReturnBytes(claims),
|
Hash = PasswordHasher.ComputeHash(password, salt),
|
||||||
UserProperties = ByteConverterHelper.ReturnBytes(new UserProperties())
|
Claims = ByteConverterHelper.ReturnBytes(claims),
|
||||||
};
|
UserProperties = ByteConverterHelper.ReturnBytes(properties ?? new UserProperties())
|
||||||
Repo.Insert(userModel);
|
};
|
||||||
|
Repo.Insert(userModel);
|
||||||
var userRecord = Repo.Get(userModel.UserGuid);
|
|
||||||
|
var userRecord = Repo.Get(userModel.UserGuid);
|
||||||
return new Guid(userRecord.UserGuid);
|
|
||||||
}
|
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)
|
|
||||||
{
|
public bool UpdatePassword(string username, string oldPassword, string newPassword)
|
||||||
var users = Repo.GetAll();
|
{
|
||||||
var userToChange = users.FirstOrDefault(x => x.UserName == username);
|
var users = Repo.GetAll();
|
||||||
if (userToChange == null)
|
var userToChange = users.FirstOrDefault(x => x.UserName == username);
|
||||||
return false;
|
if (userToChange == null)
|
||||||
|
return false;
|
||||||
var passwordMatch = PasswordHasher.VerifyPassword(oldPassword, userToChange.Salt, userToChange.Hash);
|
|
||||||
if (!passwordMatch)
|
var passwordMatch = PasswordHasher.VerifyPassword(oldPassword, userToChange.Salt, userToChange.Hash);
|
||||||
{
|
if (!passwordMatch)
|
||||||
throw new SecurityException("Password does not match");
|
{
|
||||||
}
|
throw new SecurityException("Password does not match");
|
||||||
|
}
|
||||||
var newSalt = PasswordHasher.GenerateSalt();
|
|
||||||
var newHash = PasswordHasher.ComputeHash(newPassword, newSalt);
|
var newSalt = PasswordHasher.GenerateSalt();
|
||||||
|
var newHash = PasswordHasher.ComputeHash(newPassword, newSalt);
|
||||||
userToChange.Hash = newHash;
|
|
||||||
userToChange.Salt = newSalt;
|
userToChange.Hash = newHash;
|
||||||
|
userToChange.Salt = newSalt;
|
||||||
return Repo.Update(userToChange);
|
|
||||||
}
|
return Repo.Update(userToChange);
|
||||||
|
}
|
||||||
public IEnumerable<UsersModel> GetUsers()
|
|
||||||
{
|
public async Task<IEnumerable<UsersModel>> GetUsersAsync()
|
||||||
return Repo.GetAll();
|
{
|
||||||
}
|
return await Repo.GetAllAsync();
|
||||||
|
}
|
||||||
public UsersModel GetUser(Guid userId)
|
|
||||||
{
|
public IEnumerable<UsersModel> GetUsers()
|
||||||
var user = Repo.Get(userId.ToString());
|
{
|
||||||
return user;
|
return Repo.GetAll();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
public UsersModel GetUser(Guid userId)
|
||||||
public interface ICustomUserMapper
|
{
|
||||||
{
|
var user = Repo.Get(userId.ToString());
|
||||||
IEnumerable<UsersModel> GetUsers();
|
return user;
|
||||||
UsersModel GetUser(Guid userId);
|
}
|
||||||
UsersModel EditUser(UsersModel user);
|
}
|
||||||
bool DoUsersExist();
|
|
||||||
Guid? ValidateUser(string username, string password);
|
public interface ICustomUserMapper
|
||||||
bool UpdatePassword(string username, string oldPassword, string newPassword);
|
{
|
||||||
Guid? CreateAdmin(string username, string password);
|
IEnumerable<UsersModel> GetUsers();
|
||||||
Guid? CreatePowerUser(string username, string password);
|
Task<IEnumerable<UsersModel>> GetUsersAsync();
|
||||||
Guid? CreateRegularUser(string username, string password);
|
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, 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()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -58,17 +58,18 @@ namespace PlexRequests.UI.Helpers
|
||||||
settings.ThemeName = Themes.PlexTheme;
|
settings.ThemeName = Themes.PlexTheme;
|
||||||
}
|
}
|
||||||
if (settings.ThemeName == "PlexBootstrap.css") settings.ThemeName = Themes.PlexTheme;
|
if (settings.ThemeName == "PlexBootstrap.css") settings.ThemeName = Themes.PlexTheme;
|
||||||
if (settings.ThemeName == "OriginalBootstrap.css") settings.ThemeName = Themes.OriginalTheme;
|
if (settings.ThemeName == "OriginalBootstrap.css") settings.ThemeName = Themes.OriginalTheme;
|
||||||
|
|
||||||
sb.AppendLine($"<link rel=\"stylesheet\" href=\"{content}/Content/bootstrap.css\" type=\"text/css\"/>");
|
sb.AppendLine($"<link rel=\"stylesheet\" href=\"{content}/Content/bootstrap.css\" type=\"text/css\"/>");
|
||||||
sb.AppendLine($"<link rel=\"stylesheet\" href=\"{content}/Content/font-awesome.css\" type=\"text/css\"/>");
|
sb.AppendLine($"<link rel=\"stylesheet\" href=\"{content}/Content/font-awesome.css\" type=\"text/css\"/>");
|
||||||
sb.AppendLine($"<link rel=\"stylesheet\" href=\"{content}/Content/pace.min.css\" type=\"text/css\"/>");
|
sb.AppendLine($"<link rel=\"stylesheet\" href=\"{content}/Content/pace.min.css\" type=\"text/css\"/>");
|
||||||
sb.AppendLine($"<link rel=\"stylesheet\" href=\"{content}/Content/awesome-bootstrap-checkbox.css\" type=\"text/css\"/>");
|
sb.AppendLine($"<link rel=\"stylesheet\" href=\"{content}/Content/awesome-bootstrap-checkbox.css\" type=\"text/css\"/>");
|
||||||
sb.AppendLine($"<link rel=\"stylesheet\" href=\"{content}/Content/base.css\" type=\"text/css\"/>");
|
sb.AppendLine($"<link rel=\"stylesheet\" href=\"{content}/Content/base.css\" type=\"text/css\"/>");
|
||||||
sb.AppendLine($"<link rel=\"stylesheet\" href=\"{content}/Content/Themes/{settings.ThemeName}\" type=\"text/css\"/>");
|
sb.AppendLine($"<link rel=\"stylesheet\" href=\"{content}/Content/Themes/{settings.ThemeName}\" type=\"text/css\"/>");
|
||||||
sb.AppendLine($"<link rel=\"stylesheet\" href=\"{content}/Content/datepicker.min.css\" type=\"text/css\"/>");
|
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/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/handlebars.min.js\"></script>");
|
||||||
sb.AppendLine($"<script src=\"{content}/Content/bootstrap.min.js\"></script>");
|
sb.AppendLine($"<script src=\"{content}/Content/bootstrap.min.js\"></script>");
|
||||||
sb.AppendLine($"<script src=\"{content}/Content/bootstrap-notify.min.js\"></script>");
|
sb.AppendLine($"<script src=\"{content}/Content/bootstrap-notify.min.js\"></script>");
|
||||||
|
@ -104,8 +105,8 @@ namespace PlexRequests.UI.Helpers
|
||||||
sb.AppendLine($"<script src=\"{content}/Content/requests-1.7.js\" type=\"text/javascript\"></script>");
|
sb.AppendLine($"<script src=\"{content}/Content/requests-1.7.js\" type=\"text/javascript\"></script>");
|
||||||
|
|
||||||
return helper.Raw(sb.ToString());
|
return helper.Raw(sb.ToString());
|
||||||
}
|
}
|
||||||
|
|
||||||
public static IHtmlString LoadIssueAssets(this HtmlHelpers helper)
|
public static IHtmlString LoadIssueAssets(this HtmlHelpers helper)
|
||||||
{
|
{
|
||||||
var sb = new StringBuilder();
|
var sb = new StringBuilder();
|
||||||
|
@ -116,8 +117,8 @@ namespace PlexRequests.UI.Helpers
|
||||||
sb.AppendLine($"<script src=\"{content}/Content/issues.js\" type=\"text/javascript\"></script>");
|
sb.AppendLine($"<script src=\"{content}/Content/issues.js\" type=\"text/javascript\"></script>");
|
||||||
|
|
||||||
return helper.Raw(sb.ToString());
|
return helper.Raw(sb.ToString());
|
||||||
}
|
}
|
||||||
|
|
||||||
public static IHtmlString LoadIssueDetailsAssets(this HtmlHelpers helper)
|
public static IHtmlString LoadIssueDetailsAssets(this HtmlHelpers helper)
|
||||||
{
|
{
|
||||||
var assetLocation = GetBaseUrl();
|
var assetLocation = GetBaseUrl();
|
||||||
|
@ -147,8 +148,8 @@ namespace PlexRequests.UI.Helpers
|
||||||
if (!settings.CollectAnalyticData)
|
if (!settings.CollectAnalyticData)
|
||||||
{
|
{
|
||||||
return helper.Raw(string.Empty);
|
return helper.Raw(string.Empty);
|
||||||
}
|
}
|
||||||
|
|
||||||
var assetLocation = GetBaseUrl();
|
var assetLocation = GetBaseUrl();
|
||||||
var content = GetContentUrl(assetLocation);
|
var content = GetContentUrl(assetLocation);
|
||||||
|
|
||||||
|
@ -164,19 +165,19 @@ namespace PlexRequests.UI.Helpers
|
||||||
if (!string.IsNullOrEmpty(content))
|
if (!string.IsNullOrEmpty(content))
|
||||||
{
|
{
|
||||||
url = $"/{content}{url}";
|
url = $"/{content}{url}";
|
||||||
}
|
}
|
||||||
if (context.Request.Path == url)
|
if (context.Request.Path == url)
|
||||||
{
|
{
|
||||||
returnString = $"<a class=\"list-group-item active\" href=\"{url}\">{title}</a>";
|
returnString = $"<a class=\"list-group-item active\" href=\"{url}\">{title}</a>";
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
returnString = $"<a class=\"list-group-item\" href=\"{url}\">{title}</a>";
|
returnString = $"<a class=\"list-group-item\" href=\"{url}\">{title}</a>";
|
||||||
}
|
}
|
||||||
|
|
||||||
return helper.Raw(returnString);
|
return helper.Raw(returnString);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static IHtmlString GetNavbarUrl(this HtmlHelpers helper, NancyContext context, string url, string title, string fontIcon)
|
public static IHtmlString GetNavbarUrl(this HtmlHelpers helper, NancyContext context, string url, string title, string fontIcon)
|
||||||
{
|
{
|
||||||
var returnString = string.Empty;
|
var returnString = string.Empty;
|
||||||
|
@ -184,19 +185,19 @@ namespace PlexRequests.UI.Helpers
|
||||||
if (!string.IsNullOrEmpty(content))
|
if (!string.IsNullOrEmpty(content))
|
||||||
{
|
{
|
||||||
url = $"/{content}{url}";
|
url = $"/{content}{url}";
|
||||||
}
|
}
|
||||||
if (context.Request.Path == url)
|
if (context.Request.Path == url)
|
||||||
{
|
{
|
||||||
returnString = $"<li class=\"active\"><a href=\"{url}\"><i class=\"fa fa-{fontIcon}\"></i> {title}</a></li>";
|
returnString = $"<li class=\"active\"><a href=\"{url}\"><i class=\"fa fa-{fontIcon}\"></i> {title}</a></li>";
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
returnString = $"<li><a href=\"{url}\"><i class=\"fa fa-{fontIcon}\"></i> {title}</a></li>";
|
returnString = $"<li><a href=\"{url}\"><i class=\"fa fa-{fontIcon}\"></i> {title}</a></li>";
|
||||||
}
|
}
|
||||||
|
|
||||||
return helper.Raw(returnString);
|
return helper.Raw(returnString);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static IHtmlString GetNavbarUrl(this HtmlHelpers helper, NancyContext context, string url, string title, string fontIcon, string extraHtml)
|
public static IHtmlString GetNavbarUrl(this HtmlHelpers helper, NancyContext context, string url, string title, string fontIcon, string extraHtml)
|
||||||
{
|
{
|
||||||
var returnString = string.Empty;
|
var returnString = string.Empty;
|
||||||
|
@ -204,12 +205,12 @@ namespace PlexRequests.UI.Helpers
|
||||||
if (!string.IsNullOrEmpty(content))
|
if (!string.IsNullOrEmpty(content))
|
||||||
{
|
{
|
||||||
url = $"/{content}{url}";
|
url = $"/{content}{url}";
|
||||||
}
|
}
|
||||||
|
|
||||||
if (context.Request.Path == url)
|
if (context.Request.Path == url)
|
||||||
{
|
{
|
||||||
returnString = $"<li class=\"active\"><a href=\"{url}\"><i class=\"fa fa-{fontIcon}\"></i> {title} {extraHtml}</a></li>";
|
returnString = $"<li class=\"active\"><a href=\"{url}\"><i class=\"fa fa-{fontIcon}\"></i> {title} {extraHtml}</a></li>";
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
returnString = $"<li><a href=\"{url}\"><i class=\"fa fa-{fontIcon}\"></i> {title} {extraHtml}</a></li>";
|
returnString = $"<li><a href=\"{url}\"><i class=\"fa fa-{fontIcon}\"></i> {title} {extraHtml}</a></li>";
|
||||||
|
@ -218,33 +219,33 @@ namespace PlexRequests.UI.Helpers
|
||||||
return helper.Raw(returnString);
|
return helper.Raw(returnString);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static IHtmlString GetBaseUrl(this HtmlHelpers helper)
|
public static IHtmlString GetBaseUrl(this HtmlHelpers helper)
|
||||||
{
|
{
|
||||||
return helper.Raw(GetBaseUrl());
|
return helper.Raw(GetBaseUrl());
|
||||||
}
|
}
|
||||||
|
|
||||||
private static string GetBaseUrl()
|
private static string GetBaseUrl()
|
||||||
{
|
{
|
||||||
return GetSettings().BaseUrl;
|
return GetSettings().BaseUrl;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static PlexRequestSettings GetSettings()
|
private static PlexRequestSettings GetSettings()
|
||||||
{
|
{
|
||||||
var returnValue = Cache.GetOrSet(CacheKeys.GetPlexRequestSettings, () =>
|
var returnValue = Cache.GetOrSet(CacheKeys.GetPlexRequestSettings, () =>
|
||||||
{
|
{
|
||||||
var settings = Locator.Resolve<ISettingsService<PlexRequestSettings>>().GetSettings();
|
var settings = Locator.Resolve<ISettingsService<PlexRequestSettings>>().GetSettings();
|
||||||
return settings;
|
return settings;
|
||||||
});
|
});
|
||||||
return returnValue;
|
return returnValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static string GetLinkUrl(string assetLocation)
|
private static string GetLinkUrl(string assetLocation)
|
||||||
{
|
{
|
||||||
return string.IsNullOrEmpty(assetLocation) ? string.Empty : $"{assetLocation}";
|
return string.IsNullOrEmpty(assetLocation) ? string.Empty : $"{assetLocation}";
|
||||||
}
|
}
|
||||||
private static string GetContentUrl(string assetLocation)
|
private static string GetContentUrl(string assetLocation)
|
||||||
{
|
{
|
||||||
return string.IsNullOrEmpty(assetLocation) ? string.Empty : $"/{assetLocation}";
|
return string.IsNullOrEmpty(assetLocation) ? string.Empty : $"/{assetLocation}";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,20 +1,19 @@
|
||||||
using System;
|
namespace PlexRequests.UI.Models
|
||||||
|
|
||||||
namespace PlexRequests.UI
|
|
||||||
{
|
{
|
||||||
public class UserManagementUsersViewModel
|
public class UserManagementUsersViewModel
|
||||||
{
|
{
|
||||||
public string Username{get;set;}
|
public string Username { get; set; }
|
||||||
public string Claims{get;set;}
|
public string Claims { get; set; }
|
||||||
public int Id {get;set;}
|
public int Id { get; set; }
|
||||||
public string Alias {get;set;}
|
public string Alias { get; set; }
|
||||||
public UserType Type { get; set;}
|
public UserType Type { get; set; }
|
||||||
}
|
public string EmailAddress { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
public enum UserType
|
public enum UserType
|
||||||
{
|
{
|
||||||
PlexUser,
|
PlexUser,
|
||||||
LocalUser
|
LocalUser
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,10 +1,14 @@
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
using Nancy;
|
using Nancy;
|
||||||
using Nancy.Responses.Negotiation;
|
using Nancy.Responses.Negotiation;
|
||||||
using Nancy.Security;
|
using Nancy.Security;
|
||||||
|
|
||||||
|
using PlexRequests.Api.Interfaces;
|
||||||
using PlexRequests.Core;
|
using PlexRequests.Core;
|
||||||
|
using PlexRequests.Core.Models;
|
||||||
using PlexRequests.Core.SettingModels;
|
using PlexRequests.Core.SettingModels;
|
||||||
using PlexRequests.Helpers;
|
using PlexRequests.Helpers;
|
||||||
using PlexRequests.UI.Models;
|
using PlexRequests.UI.Models;
|
||||||
|
@ -13,57 +17,88 @@ namespace PlexRequests.UI.Modules
|
||||||
{
|
{
|
||||||
public class UserManagementModule : BaseModule
|
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["/"] = x => Load();
|
||||||
|
|
||||||
Get["/users"] = x => LoadUsers();
|
Get["/users", true] = async (x, ct) => await LoadUsers();
|
||||||
UserMapper = m;
|
Post["/createuser"] = x => CreateUser(Request.Form["userName"].ToString(), Request.Form["password"].ToString());
|
||||||
}
|
}
|
||||||
|
|
||||||
private ICustomUserMapper UserMapper { get; }
|
private ICustomUserMapper UserMapper { get; }
|
||||||
|
private IPlexApi PlexApi { get; }
|
||||||
|
private ISettingsService<AuthenticationSettings> AuthSettings { get; }
|
||||||
|
|
||||||
private Negotiator Load()
|
private Negotiator Load()
|
||||||
{
|
{
|
||||||
return View["Index"];
|
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>();
|
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
|
model.Add(new UserManagementUsersViewModel
|
||||||
{
|
{
|
||||||
//Claims = ByteConverterHelper.ReturnObject<string[]>(user.Claims),
|
Claims = claimsString,
|
||||||
Claims = "test",
|
|
||||||
Id = user.Id,
|
|
||||||
Username = user.UserName,
|
Username = user.UserName,
|
||||||
//Type = UserType.LocalUser
|
Type = UserType.LocalUser,
|
||||||
|
EmailAddress = userProps.EmailAddress
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
return Response.AsJson(users);
|
|
||||||
|
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
|
||||||
|
{
|
||||||
|
Username = u.Username,
|
||||||
|
Type = UserType.PlexUser,
|
||||||
|
//Alias =
|
||||||
|
Claims = "Requestor",
|
||||||
|
EmailAddress = u.Email
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Response.AsJson(model);
|
||||||
}
|
}
|
||||||
|
|
||||||
//private Response CreateUser(string username, string password, string claims)
|
private Response CreateUser(string username, string password)
|
||||||
//{
|
{
|
||||||
// if (string.IsNullOrWhiteSpace(username) || string.IsNullOrWhiteSpace(password))
|
if (string.IsNullOrWhiteSpace(username) || string.IsNullOrWhiteSpace(password))
|
||||||
// {
|
{
|
||||||
// return Response.AsJson(new JsonResponseModel
|
return Response.AsJson(new JsonResponseModel
|
||||||
// {
|
{
|
||||||
// Result = true,
|
Result = true,
|
||||||
// Message = "Please enter in a valid Username and Password"
|
Message = "Please enter in a valid Username and Password"
|
||||||
// });
|
});
|
||||||
// }
|
}
|
||||||
// var user = UserMapper.CreateUser(username, password, new string[] {claims});
|
var user = UserMapper.CreateRegularUser(username, password);
|
||||||
// if (user.HasValue)
|
if (user.HasValue)
|
||||||
// {
|
{
|
||||||
// return Response.AsJson(new JsonResponseModel {Result = true});
|
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\ContravariantBindingResolver.cs" />
|
||||||
<Compile Include="Helpers\CultureHelper.cs" />
|
<Compile Include="Helpers\CultureHelper.cs" />
|
||||||
<Compile Include="Helpers\CustomHtmlHelper.cs" />
|
<Compile Include="Helpers\CustomHtmlHelper.cs" />
|
||||||
<Compile Include="Helpers\HeadphonesSender.cs" />
|
|
||||||
<Compile Include="Helpers\EmptyViewBase.cs" />
|
<Compile Include="Helpers\EmptyViewBase.cs" />
|
||||||
|
<Compile Include="Helpers\HeadphonesSender.cs" />
|
||||||
|
<Compile Include="Helpers\AngularViewBase.cs" />
|
||||||
<Compile Include="Helpers\ServiceLocator.cs" />
|
<Compile Include="Helpers\ServiceLocator.cs" />
|
||||||
<Compile Include="Helpers\StringHelper.cs" />
|
<Compile Include="Helpers\StringHelper.cs" />
|
||||||
<Compile Include="Helpers\Themes.cs" />
|
<Compile Include="Helpers\Themes.cs" />
|
||||||
|
@ -246,6 +247,9 @@
|
||||||
<Compile Include="Validators\RequestedModelValidator.cs" />
|
<Compile Include="Validators\RequestedModelValidator.cs" />
|
||||||
<Compile Include="Validators\SickRageValidator.cs" />
|
<Compile Include="Validators\SickRageValidator.cs" />
|
||||||
<Compile Include="Validators\SonarrValidator.cs" />
|
<Compile Include="Validators\SonarrValidator.cs" />
|
||||||
|
<Content Include="Content\app\app.js">
|
||||||
|
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||||
|
</Content>
|
||||||
<Content Include="Content\awesome-bootstrap-checkbox.css">
|
<Content Include="Content\awesome-bootstrap-checkbox.css">
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
</Content>
|
</Content>
|
||||||
|
@ -298,6 +302,9 @@
|
||||||
<Content Include="Content\issues.js">
|
<Content Include="Content\issues.js">
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
</Content>
|
</Content>
|
||||||
|
<Content Include="Content\app\services\userManagement\userManagementService.js">
|
||||||
|
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||||
|
</Content>
|
||||||
<Content Include="Content\swagger\backbone-min.js">
|
<Content Include="Content\swagger\backbone-min.js">
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
</Content>
|
</Content>
|
||||||
|
@ -494,6 +501,9 @@
|
||||||
<None Include="sqlite3.dll">
|
<None Include="sqlite3.dll">
|
||||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||||
</None>
|
</None>
|
||||||
|
<Content Include="Content\app\controllers\userManagement\userManagementController.js">
|
||||||
|
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||||
|
</Content>
|
||||||
<Content Include="web.config">
|
<Content Include="web.config">
|
||||||
<SubType>Designer</SubType>
|
<SubType>Designer</SubType>
|
||||||
</Content>
|
</Content>
|
||||||
|
@ -596,6 +606,18 @@
|
||||||
<Content Include="Views\Admin\SchedulerSettings.cshtml">
|
<Content Include="Views\Admin\SchedulerSettings.cshtml">
|
||||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||||
</Content>
|
</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">
|
<None Include="Web.Debug.config">
|
||||||
<DependentUpon>web.config</DependentUpon>
|
<DependentUpon>web.config</DependentUpon>
|
||||||
</None>
|
</None>
|
||||||
|
@ -698,6 +720,8 @@
|
||||||
<Target Name="AfterBuild">
|
<Target Name="AfterBuild">
|
||||||
</Target>
|
</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')" />
|
<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>
|
</Project>
|
|
@ -2,7 +2,7 @@
|
||||||
@using Nancy.Session
|
@using Nancy.Session
|
||||||
@using PlexRequests.UI.Helpers
|
@using PlexRequests.UI.Helpers
|
||||||
@using PlexRequests.UI.Models
|
@using PlexRequests.UI.Models
|
||||||
@inherits Nancy.ViewEngines.Razor.NancyRazorViewBase
|
@inherits Nancy.ViewEngines.Razor.NancyRazorViewBase<dynamic>
|
||||||
@{
|
@{
|
||||||
var baseUrl = Html.GetBaseUrl();
|
var baseUrl = Html.GetBaseUrl();
|
||||||
var url = string.Empty;
|
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 PlexRequests.UI.Helpers
|
||||||
@using Nancy.Session
|
|
||||||
@using PlexRequests.UI.Helpers
|
|
||||||
@using PlexRequests.UI.Models
|
|
||||||
@using PlexRequests.UI.Resources
|
|
||||||
@inherits Nancy.ViewEngines.Razor.NancyRazorViewBase
|
@inherits Nancy.ViewEngines.Razor.NancyRazorViewBase
|
||||||
@{
|
|
||||||
var baseUrl = Html.GetBaseUrl();
|
|
||||||
var url = string.Empty;
|
|
||||||
if (!string.IsNullOrEmpty(baseUrl.ToHtmlString()))
|
|
||||||
{
|
|
||||||
url = "/" + baseUrl.ToHtmlString();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
<html>
|
<html>
|
||||||
<div hidden="hidden" id="baseUrl">@baseUrl.ToHtmlString()</div>
|
@Html.Partial("Shared/Partial/_Head")
|
||||||
<head>
|
|
||||||
<title>@UI.Layout_Title</title>
|
|
||||||
<!-- Styles -->
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
||||||
@Html.LoadAnalytics()
|
|
||||||
@Html.LoadAssets()
|
|
||||||
</head>
|
|
||||||
<body>
|
<body>
|
||||||
|
|
||||||
|
@Html.Partial("Shared/Partial/_Navbar")
|
||||||
|
|
||||||
<nav class="navbar navbar-default">
|
<div class="container">
|
||||||
<div class="container-fluid">
|
@RenderBody()
|
||||||
<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>
|
||||||
<div id="updateAvailable" hidden="hidden"></div>
|
<div class="scroll-top-wrapper ">
|
||||||
</nav>
|
<span class="scroll-top-inner">
|
||||||
|
|
||||||
<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>
|
<i class="fa fa-2x fa-arrow-circle-up"></i>
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</body>
|
</body>
|
||||||
@Html.GetInformationalVersion();
|
|
||||||
|
@Html.GetInformationalVersion()
|
||||||
|
|
||||||
</html>
|
</html>
|
||||||
<script>
|
@Html.Partial("Shared/Partial/_LayoutScripts")
|
||||||
|
|
||||||
$(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>
|
|
||||||
|
|
|
@ -1,4 +1,7 @@
|
||||||
@using PlexRequests.UI.Helpers
|
@using PlexRequests.UI.Helpers
|
||||||
|
|
||||||
|
@inherits PlexRequests.UI.Helpers.AngularViewBase
|
||||||
|
|
||||||
@Html.LoadTableAssets()
|
@Html.LoadTableAssets()
|
||||||
@{
|
@{
|
||||||
var baseUrl = Html.GetBaseUrl().ToHtmlString();
|
var baseUrl = Html.GetBaseUrl().ToHtmlString();
|
||||||
|
@ -8,41 +11,53 @@
|
||||||
url = "/" + baseUrl;
|
url = "/" + baseUrl;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
<script src="/Content/app/controllers/userManagement/userManagementController.js"></script>
|
||||||
|
<script src="/Content/app/services/userManagement/userManagementService.js"></script>
|
||||||
<h2>User Management</h2>
|
<div ng-controller="userManagementController" ng-init="getUsers()">
|
||||||
|
|
||||||
<button class="btn btn-success-outline" type="submit">Create User <div class="fa fa-plus"/></button>
|
<br>
|
||||||
<br>
|
<br>
|
||||||
<br>
|
|
||||||
<fieldset>
|
<fieldset>
|
||||||
<table id="example" class="table table-striped table-hover table-responsive">
|
<table class="table table-striped table-hover table-responsive">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th>Id</th>
|
<th>Id</th>
|
||||||
<th>Username</th>
|
<th>Username</th>
|
||||||
<th>Permissions</th>
|
<th>Email</th>
|
||||||
</tr>
|
<th>User T</th>
|
||||||
|
</tr>
|
||||||
</thead>
|
</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>
|
</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>
|
</fieldset>
|
||||||
|
</div>
|
||||||
|
|
||||||
<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"]]
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
</script>
|
|
Loading…
Add table
Add a link
Reference in a new issue