Merge pull request #800 from tidusjar/EAP

Pushing V1.10.1 release
pull/803/head v1.10.1
SuperPotatoMen 8 years ago committed by GitHub
commit f5d7c81406

@ -1,6 +1,7 @@
using System;
using Nancy;
using Nancy.Security;
using Nancy.Session;
using PlexRequests.Helpers.Permissions;
namespace PlexRequests.Core
@ -29,6 +30,6 @@ namespace PlexRequests.Core
/// </summary>
/// <param name="username">The username.</param>
/// <returns><c>null</c> if we cannot find a user</returns>
string GetUsername(string username);
string GetUsername(string username, ISession session);
}
}

@ -7,5 +7,6 @@ namespace PlexRequests.Core
public interface IStatusChecker
{
Task<StatusModel> GetStatus();
Task<Issue> ReportBug(string title, string body);
}
}

@ -122,6 +122,7 @@
<Compile Include="SettingModels\ExternalSettings.cs" />
<Compile Include="SettingModels\HeadphonesSettings.cs" />
<Compile Include="SettingModels\LandingPageSettings.cs" />
<Compile Include="SettingModels\CustomizationSettings.cs" />
<Compile Include="SettingModels\NewsletterSettings.cs" />
<Compile Include="SettingModels\NotificationSettings.cs" />
<Compile Include="SettingModels\NotificationSettingsV2.cs" />

@ -30,6 +30,7 @@ using Nancy;
using Nancy.Linker;
using Nancy.Responses;
using Nancy.Security;
using Nancy.Session;
using PlexRequests.Core.Models;
using PlexRequests.Helpers;
using PlexRequests.Helpers.Permissions;
@ -91,7 +92,7 @@ namespace PlexRequests.Core
/// </summary>
/// <param name="username">The username.</param>
/// <returns><c>null</c> if we cannot find a user</returns>
public string GetUsername(string username)
public string GetUsername(string username, ISession session)
{
var plexUser = PlexUsers.GetUserByUsername(username);
if (plexUser != null)
@ -119,7 +120,11 @@ namespace PlexRequests.Core
return dbUser.UserName;
}
}
return null;
// could be a local user
var localName = session[SessionKeys.UsernameKey];
return localName as string;
}

@ -0,0 +1,39 @@
#region Copyright
// /************************************************************************
// Copyright (c) 2016 Jamie Rees
// File: NewsletterSettings.cs
// Created By: Jim MacKenzie
//
// 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
namespace PlexRequests.Core.SettingModels
{
public class CustomizationSettings : Settings
{
public string ApplicationName { get; set; }
/// <summary>
/// The CSS name of the theme we want
/// </summary>
public string ThemeName { get; set; }
}
}

@ -33,7 +33,6 @@ namespace PlexRequests.Core.SettingModels
public int EmailPort { get; set; }
public string EmailSender { get; set; }
public string EmailUsername { get; set; }
public bool Enabled { get; set; }
public bool Authentication { get; set; }
public bool EnableUserEmailNotifications { get; set; }
public string RecipientEmail { get; set; }

@ -45,6 +45,9 @@ namespace PlexRequests.Core.SettingModels
};
}
public bool Enabled { get; set; }
public List<NotificationMessage> Message { get; set; }
}

@ -30,6 +30,5 @@ namespace PlexRequests.Core.SettingModels
{
public string AccessToken { get; set; }
public string DeviceIdentifier { get; set; }
public bool Enabled { get; set; }
}
}

@ -29,7 +29,6 @@ namespace PlexRequests.Core.SettingModels
public sealed class PushoverNotificationSettings : NotificationSettings
{
public string AccessToken { get; set; }
public bool Enabled { get; set; }
public string UserToken { get; set; }
}
}

@ -6,7 +6,6 @@ namespace PlexRequests.Core.SettingModels
{
public sealed class SlackNotificationSettings : NotificationSettings
{
public bool Enabled { get; set; }
public string WebhookUrl { get; set; }
public string Channel { get; set; }
public string Username { get; set; }

@ -179,5 +179,16 @@ namespace PlexRequests.Core.StatusChecker
return model;
}
public async Task<Issue> ReportBug(string title, string body)
{
var issue = new NewIssue(title)
{
Body = body
};
var result = await Git.Issue.Create(Owner, RepoName, issue);
return result;
}
}
}

@ -0,0 +1,76 @@
#region Copyright
// /************************************************************************
// Copyright (c) 2016 Jamie Rees
// File: OperatingSystemHelper.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
namespace PlexRequests.Helpers
{
public static class OperatingSystemHelper
{
public static string GetOs()
{
var os = System.Environment.OSVersion;
var osVersion = os.Version;
if (osVersion.Major.Equals(10))
{
return "Windows 10/Windows Server 2016";
}
if (osVersion.Major.Equals(6))
{
if (osVersion.Minor.Equals(3))
{
return "Windows 8.1/Windows Server 2012 R2";
}
if (osVersion.Minor.Equals(2))
{
return "Windows 8/Windows Server 2012";
}
if (osVersion.Minor.Equals(1))
{
return "Windows 7/Windows Server 2008 R2";
}
if (osVersion.Minor.Equals(0))
{
return "Windows Vista/Windows Server 2008";
}
}
if (osVersion.Major.Equals(5))
{
if (osVersion.Minor.Equals(2))
{
return "Windows XP 64-Bit Edition/Windows Server 2003";
}
if (osVersion.Minor.Equals(1))
{
return "Windows XP";
}
if (osVersion.Minor.Equals(0))
{
return "Windows 2000";
}
}
return os.VersionString;
}
}
}

@ -83,6 +83,7 @@
<Compile Include="LoggingHelper.cs" />
<Compile Include="MemoryCacheProvider.cs" />
<Compile Include="ObjectCopier.cs" />
<Compile Include="OperatingSystemHelper.cs" />
<Compile Include="PasswordHasher.cs" />
<Compile Include="EnumExtensions.cs" />
<Compile Include="Permissions\Features.cs" />

@ -31,13 +31,11 @@ using System.Net;
using Mono.Data.Sqlite;
using Nancy;
using Nancy.Authentication.Forms;
using Nancy.Bootstrapper;
using Nancy.Bootstrappers.Ninject;
using Nancy.Conventions;
using Nancy.Cryptography;
using Nancy.Diagnostics;
using Nancy.Hosting.Self;
using Nancy.Session;
using PlexRequests.Api.Interfaces;
@ -53,6 +51,7 @@ using Nancy.Json;
using Ninject;
using PlexRequests.UI.Authentication;
using Nancy.Hosting.Self;
namespace PlexRequests.UI
{
@ -105,9 +104,6 @@ namespace PlexRequests.UI
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls;
ServicePointManager.ServerCertificateValidationCallback +=
(sender, certificate, chain, sslPolicyErrors) => true;
SubscribeAllObservers(container);
}
#if DEBUG
@ -142,39 +138,6 @@ namespace PlexRequests.UI
protected override DiagnosticsConfiguration DiagnosticsConfiguration => new DiagnosticsConfiguration { Password = @"password" };
private void SubscribeAllObservers(IKernel container)
{
var notificationService = container.Get<INotificationService>();
var emailSettingsService = container.Get<ISettingsService<EmailNotificationSettings>>();
var emailSettings = emailSettingsService.GetSettings();
if (emailSettings.Enabled)
{
notificationService.Subscribe(new EmailMessageNotification(emailSettingsService));
}
var pushbulletService = container.Get<ISettingsService<PushbulletNotificationSettings>>();
var pushbulletSettings = pushbulletService.GetSettings();
if (pushbulletSettings.Enabled)
{
notificationService.Subscribe(new PushbulletNotification(container.Get<IPushbulletApi>(), pushbulletService));
}
var pushoverService = container.Get<ISettingsService<PushoverNotificationSettings>>();
var pushoverSettings = pushoverService.GetSettings();
if (pushoverSettings.Enabled)
{
notificationService.Subscribe(new PushoverNotification(container.Get<IPushoverApi>(), pushoverService));
}
var slackService = container.Get<ISettingsService<SlackNotificationSettings>>();
var slackSettings = slackService.GetSettings();
if (slackSettings.Enabled)
{
notificationService.Subscribe(new SlackNotification(container.Get<ISlackApi>(), slackService));
}
}
protected override void RequestStartup(IKernel container, IPipelines pipelines, NancyContext context)
{
//CORS Enable

File diff suppressed because one or more lines are too long

@ -26,6 +26,7 @@
#endregion
using System.Collections.Generic;
using System.Text;
using System.Web.UI.WebControls;
using Nancy;
using Nancy.ViewEngines.Razor;
@ -66,7 +67,7 @@ namespace PlexRequests.UI.Helpers
var assetLocation = GetBaseUrl();
var content = GetContentUrl(assetLocation);
var settings = GetSettings();
var settings = GetCustomizationSettings();
if (string.IsNullOrEmpty(settings.ThemeName))
{
settings.ThemeName = Themes.PlexTheme;
@ -233,6 +234,16 @@ namespace PlexRequests.UI.Helpers
return helper.Raw(sb.ToString());
}
public static IHtmlString LoadAsset(this HtmlHelpers helper, string contentPath, bool javascript)
{
var assetLocation = GetBaseUrl();
var content = GetContentUrl(assetLocation);
if (javascript)
{
return helper.Raw($"<script src=\"{content}{contentPath}?v={Assembly}\" type=\"text/javascript\"></script>");
}
return helper.Raw($"<link rel=\"stylesheet\" type=\"text/css\" href=\"{content}{contentPath}?v={Assembly}\" />");
}
public static IHtmlString LoadTableAssets(this HtmlHelpers helper)
{
@ -328,6 +339,11 @@ namespace PlexRequests.UI.Helpers
return helper.Raw(GetBaseUrl());
}
public static IHtmlString GetApplicationName(this HtmlHelpers helper)
{
return helper.Raw(GetCustomizationSettings().ApplicationName);
}
private static string GetBaseUrl()
{
return GetSettings().BaseUrl;
@ -343,6 +359,16 @@ namespace PlexRequests.UI.Helpers
return returnValue;
}
private static CustomizationSettings GetCustomizationSettings()
{
var returnValue = Cache.GetOrSet(CacheKeys.GetPlexRequestSettings, () =>
{
var settings = Locator.Resolve<ISettingsService<CustomizationSettings>>().GetSettings();
return settings;
});
return returnValue;
}
private static string GetLinkUrl(string assetLocation)
{
return string.IsNullOrEmpty(assetLocation) ? string.Empty : $"{assetLocation}";

@ -0,0 +1,37 @@
#region Copyright
// /************************************************************************
// Copyright (c) 2016 Jamie Rees
// File: AboutAdminViewModel.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
namespace PlexRequests.UI.Models
{
public class AboutAdminViewModel
{
public string Os { get; set; } // Windows/Mono
public string SystemVersion { get; set; } // Windows 10/ mono 4.2.5
public string ApplicationVersion { get; set; } // File Version
public string Branch { get; set; }
public string LogLevel { get; set; }
}
}

@ -0,0 +1,115 @@
#region Copyright
// /************************************************************************
// Copyright (c) 2016 Jamie Rees
// File: AboutModule.cs
// Created By: Jamie Rees
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
// ************************************************************************/
#endregion
using System;
using System.Linq;
using System.Reflection;
using System.Threading.Tasks;
using Nancy;
using Nancy.Responses.Negotiation;
using NLog;
using PlexRequests.Core;
using PlexRequests.Core.SettingModels;
using PlexRequests.Helpers;
using PlexRequests.Helpers.Permissions;
using PlexRequests.UI.Models;
using TMDbLib.Utilities;
using ISecurityExtensions = PlexRequests.Core.ISecurityExtensions;
namespace PlexRequests.UI.Modules.Admin
{
public class AboutModule : BaseModule
{
public AboutModule(ISettingsService<PlexRequestSettings> settingsService,
ISettingsService<SystemSettings> systemService, ISecurityExtensions security,
IStatusChecker statusChecker) : base("admin", settingsService, security)
{
Before += (ctx) => Security.AdminLoginRedirect(Permissions.Administrator, ctx);
SettingsService = systemService;
StatusChecker = statusChecker;
Get["/about", true] = async (x,ct) => await Index();
Post["/about", true] = async (x,ct) => await ReportIssue();
}
private ISettingsService<SystemSettings> SettingsService { get; }
private IStatusChecker StatusChecker { get; }
private async Task<Negotiator> Index()
{
var vm = new AboutAdminViewModel();
var systemSettings = await SettingsService.GetSettingsAsync();
var type = Type.GetType("Mono.Runtime");
if (type != null) // mono
{
vm.Os = "Mono";
var displayName = type.GetMethod("GetDisplayName", BindingFlags.NonPublic | BindingFlags.Static);
if (displayName != null)
{
vm.SystemVersion = displayName.Invoke(null, null).ToString();
}
}
else
{
// Windows
vm.Os = OperatingSystemHelper.GetOs();
vm.SystemVersion = Environment.Version.ToString();
}
vm.ApplicationVersion = AssemblyHelper.GetFileVersion();
vm.Branch = EnumHelper<Branches>.GetDisplayValue(systemSettings.Branch);
vm.LogLevel = LogManager.Configuration.LoggingRules.FirstOrDefault(x => x.NameMatches("database"))?.Levels?.FirstOrDefault()?.Name ?? "Unknown";
return View["About", vm];
}
private async Task<Response> ReportIssue()
{
var title = Request.Form["title"];
var body = Request.Form["body"];
if (string.IsNullOrEmpty(title) || string.IsNullOrEmpty(body))
{
return
Response.AsJson(
new
{
result = false,
message = "The title or issue body is empty! Please give me a bit more detail :)"
});
}
var result = await StatusChecker.ReportBug(title,body);
return Response.AsJson(new {result = true, url = result.HtmlUrl.ToString()});
}
}
}

@ -0,0 +1,72 @@
#region Copyright
// /************************************************************************
// Copyright (c) 2016 Jamie Rees
// File: CustomizationModule.cs
// Created By: Jamie Rees
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
// ************************************************************************/
#endregion
using System.Threading.Tasks;
using Nancy;
using Nancy.ModelBinding;
using Nancy.Responses.Negotiation;
using PlexRequests.Core;
using PlexRequests.Core.SettingModels;
using PlexRequests.Helpers.Permissions;
using PlexRequests.UI.Models;
using ISecurityExtensions = PlexRequests.Core.ISecurityExtensions;
namespace PlexRequests.UI.Modules.Admin
{
public class CustomizationModule : BaseModule
{
public CustomizationModule(ISettingsService<PlexRequestSettings> settingsService, ISettingsService<CustomizationSettings> cust, ISecurityExtensions security) : base("admin", settingsService, security)
{
Before += (ctx) => Security.AdminLoginRedirect(Permissions.Administrator, ctx);
Settings = cust;
Get["/customization", true] = async (x,ct) => await Index();
Post["/customization", true] = async (x,ct) => await Save();
}
private ISettingsService<CustomizationSettings> Settings { get; }
private async Task<Negotiator> Index()
{
var model = await Settings.GetSettingsAsync();
return View["customization", model];
}
private async Task<Response> Save()
{
var model = this.Bind<CustomizationSettings>();
var result = await Settings.SaveSettingsAsync(model);
return Response.AsJson(result
? new JsonResponseModel { Result = true }
: new JsonResponseModel { Result = false, Message = "We could not save to the database, please try again" });
}
}
}

@ -112,7 +112,7 @@ namespace PlexRequests.UI.Modules
{
try
{
var username = Security.GetUsername(User.UserName);
var username = Security.GetUsername(User.UserName, Session);
if (string.IsNullOrEmpty(username))
{
return Session[SessionKeys.UsernameKey].ToString();

@ -18,7 +18,6 @@ namespace PlexRequests.UI.Modules
public DonationLinkModule(ICacheProvider provider, ISettingsService<PlexRequestSettings> pr, ISecurityExtensions security) : base("customDonation", pr, security)
{
Cache = provider;
Get["/", true] = async (x, ct) => await GetCustomDonationUrl(pr);
}
@ -31,14 +30,12 @@ namespace PlexRequests.UI.Modules
PlexRequestSettings settings = await pr.GetSettingsAsync();
try
{
if (settings.EnableCustomDonationUrl)
if (settings.EnableCustomDonationUrl && Security.IsLoggedIn(Context))
{
return Response.AsJson(new { url = settings.CustomDonationUrl, message = settings.CustomDonationMessage, enabled = true });
}
else
{
return Response.AsJson(new { enabled = false });
}
return Response.AsJson(new { enabled = false });
}
catch (Exception e)
{

@ -228,6 +228,33 @@ namespace PlexRequests.UI.Modules
loginGuid = Guid.Parse(dbUser.UserGuid);
}
if (loginGuid != Guid.Empty)
{
if (!settings.UserAuthentication)// Do not need to auth make admin use login screen for now TODO remove this
{
if (dbUser != null)
{
var perms = (Permissions) dbUser.Permissions;
if (perms.HasFlag(Permissions.Administrator))
{
var uri = Linker.BuildRelativeUri(Context, "UserLoginIndex");
Session["TempMessage"] = Resources.UI.UserLogin_AdminUsePassword;
return Response.AsRedirect(uri.ToString());
}
}
if (plexLocal != null)
{
var perms = (Permissions)plexLocal.Permissions;
if (perms.HasFlag(Permissions.Administrator))
{
var uri = Linker.BuildRelativeUri(Context, "UserLoginIndex");
Session["TempMessage"] = Resources.UI.UserLogin_AdminUsePassword;
return Response.AsRedirect(uri.ToString());
}
}
}
}
if(loginGuid == Guid.Empty && settings.UserAuthentication)
{
var defaultSettings = UserManagementSettings.GetSettings();

@ -105,6 +105,10 @@
<HintPath>..\packages\NLog.4.3.6\lib\net45\NLog.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="Octokit, Version=0.19.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\Octokit.0.19.0\lib\net45\Octokit.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="RestSharp, Version=105.2.3.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\RestSharp.105.2.3\lib\net45\RestSharp.dll</HintPath>
<Private>True</Private>
@ -228,6 +232,7 @@
<Compile Include="ModelDataProviders\AuthSettingsDataProvider.cs" />
<Compile Include="ModelDataProviders\UserUpdateViewModelDataProvider.cs" />
<Compile Include="ModelDataProviders\RequestedModelDataProvider.cs" />
<Compile Include="Models\AboutAdminViewModel.cs" />
<Compile Include="Models\DatatablesModel.cs" />
<Compile Include="Models\EpisodeListViewModel.cs" />
<Compile Include="Models\EpisodeRequestModel.cs" />
@ -244,6 +249,8 @@
<Compile Include="Models\SearchMovieViewModel.cs" />
<Compile Include="Models\UserManagement\DeleteUserViewModel.cs" />
<Compile Include="Models\UserManagement\UserUpdateViewModel.cs" />
<Compile Include="Modules\Admin\AboutModule.cs" />
<Compile Include="Modules\Admin\CustomizationModule.cs" />
<Compile Include="Modules\Admin\UserManagementSettingsModule.cs" />
<Compile Include="Modules\Admin\FaultQueueModule.cs" />
<Compile Include="Modules\Admin\SystemStatusModule.cs" />
@ -367,6 +374,9 @@
<DependentUpon>datepicker.css</DependentUpon>
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content>
<Content Include="Content\helpers\bootbox.min.js">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="Content\issue-details.js">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
@ -748,6 +758,9 @@
<Content Include="Views\Admin\NotificationSettings.cshtml">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content>
<Content Include="Views\About\About.cshtml">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content>
<None Include="Views\Admin\NewsletterSettings.cshtml">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
@ -757,6 +770,9 @@
<Content Include="Views\UserManagementSettings\UserManagementSettings.cshtml">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content>
<Content Include="Views\Customization\Customization.cshtml">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content>
<None Include="Web.Debug.config">
<DependentUpon>web.config</DependentUpon>
</None>

@ -473,4 +473,7 @@
<data name="Layout_Usermanagement" xml:space="preserve">
<value>User Management</value>
</data>
</root>
<data name="UserLogin_AdminUsePassword" xml:space="preserve">
<value>If you are an administrator, please use the other login page</value>
</data>
</root>

@ -223,7 +223,7 @@ namespace PlexRequests.UI.Resources {
}
/// <summary>
/// Looks up a localized string similar to A background process is currently running, so there might be some unexpected behavior. This shouldn&apos;t take too long..
/// Looks up a localized string similar to Currently we are indexing all of the available tv shows and movies on the Plex server, so there might be some unexpected behavior. This shouldn&apos;t take too long..
/// </summary>
public static string Layout_CacherRunning {
get {
@ -1113,6 +1113,15 @@ namespace PlexRequests.UI.Resources {
}
}
/// <summary>
/// Looks up a localized string similar to If you are an administrator, please use the other login page.
/// </summary>
public static string UserLogin_AdminUsePassword {
get {
return ResourceManager.GetString("UserLogin_AdminUsePassword", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Incorrect User or Password.
/// </summary>

@ -28,13 +28,17 @@ using System;
using System.Diagnostics;
using Ninject;
using Ninject.Planning.Bindings.Resolvers;
using Ninject.Syntax;
using NLog;
using Owin;
using PlexRequests.Api.Interfaces;
using PlexRequests.Core;
using PlexRequests.Core.Migration;
using PlexRequests.Core.SettingModels;
using PlexRequests.Services.Interfaces;
using PlexRequests.Services.Jobs;
using PlexRequests.Services.Notification;
using PlexRequests.Store.Models;
using PlexRequests.Store.Repository;
using PlexRequests.UI.Helpers;
@ -89,10 +93,8 @@ namespace PlexRequests.UI
jobSettings.Update(scheduledJobse);
}
scheduler.StartScheduler();
SubscribeAllObservers(kernel);
}
catch (Exception exception)
@ -101,5 +103,37 @@ namespace PlexRequests.UI
throw;
}
}
private void SubscribeAllObservers(IResolutionRoot container)
{
var notificationService = container.Get<INotificationService>();
var emailSettingsService = container.Get<ISettingsService<EmailNotificationSettings>>();
var emailSettings = emailSettingsService.GetSettings();
SubScribeOvserver(emailSettings, notificationService ,new EmailMessageNotification(emailSettingsService));
var pushbulletService = container.Get<ISettingsService<PushbulletNotificationSettings>>();
var pushbulletSettings = pushbulletService.GetSettings();
SubScribeOvserver(pushbulletSettings, notificationService, new PushbulletNotification(container.Get<IPushbulletApi>(), pushbulletService));
var pushoverService = container.Get<ISettingsService<PushoverNotificationSettings>>();
var pushoverSettings = pushoverService.GetSettings();
SubScribeOvserver(pushoverSettings, notificationService, new PushoverNotification(container.Get<IPushoverApi>(), pushoverService));
var slackService = container.Get<ISettingsService<SlackNotificationSettings>>();
var slackSettings = slackService.GetSettings();
SubScribeOvserver(slackSettings, notificationService, new SlackNotification(container.Get<ISlackApi>(), slackService));
}
private void SubScribeOvserver<T>(T settings, INotificationService notificationService, INotification notification)
where T : NotificationSettings
{
if (settings.Enabled)
{
notificationService.Subscribe(notification);
}
}
}
}

@ -0,0 +1,111 @@
@using PlexRequests.UI.Helpers
@inherits Nancy.ViewEngines.Razor.NancyRazorViewBase<PlexRequests.UI.Models.AboutAdminViewModel>
@Html.Partial("Shared/Partial/_Sidebar")
@Html.LoadAsset("/Content/helpers/bootbox.min.js", true)
<div id="lightbox" style="display:none"></div>
<div class="col-sm-8 col-sm-push-1">
<fieldset>
<legend>About</legend>
<div class="form-group">
<label>Application Version: </label>
<label>@Model.ApplicationVersion</label>
</div>
<div class="form-group">
<label class="control-label">OS: </label>
<label class="control-label">@Model.Os</label>
</div>
<div class="form-group">
<label class="control-label">System Version: </label>
<label class="control-label">@Model.SystemVersion</label>
</div>
<div class="form-group">
<label class="control-label">Branch: </label>
<label class="control-label">@Model.Branch</label>
</div>
<div class="form-group">
<label class="control-label">Log Level: </label>
<label class="control-label">@Model.LogLevel</label>
</div>
<div class="form-group">
<div>
<button id="save" type="submit" class="btn btn-danger-outline">Report a bug</button>
</div>
</div>
</fieldset>
</div>
<script>
var issueTitle = "";
var baseUrl = '@Html.GetBaseUrl()';
$('#save').click(function () {
startBug();
});
function startBug() {
bootbox.prompt({
size: "small",
title: "What is the title of the issue?",
inputType: 'textarea',
callback: mainContent
});
}
function mainContent(userTitle) {
if (!userTitle) {
generateNotify("Please provide a valid title", "danger");
return startBug();
}
issueTitle = userTitle;
bootbox.prompt({
title: "Please provide details of the issue including any logs and reproduction steps",
inputType: 'textarea',
callback: reportBug
});
}
function reportBug(additionalInfo) {
if (!additionalInfo) {
generateNotify("Please provide some information", "danger");
return mainContent();
}
var url = "/admin/about";
url = createBaseUrl(baseUrl, url);
$.ajax({
type: "post",
url: url,
data: {title : issueTitle, body : additionalInfo},
dataType: "json",
success: function (response) {
if (response && response.result) {
generateNotify("Issue Reported, see here: " + response.url);
} else {
if (response.message) {
generateNotify(response.message, "danger");
}
}
},
error: function (e) {
console.log(e);
generateNotify("Something went wrong!", "danger");
}
});
}
</script>

@ -19,18 +19,6 @@
{
formAction = "/" + baseUrl.ToHtmlString() + formAction;
}
var plexTheme = string.Empty;
var originalTheme = string.Empty;
if (!string.IsNullOrEmpty(Model.ThemeName))
{
plexTheme = Model.ThemeName.Equals(Themes.PlexTheme) ? "selected=\"selected\"" : string.Empty;
originalTheme = Model.ThemeName.Equals(Themes.OriginalTheme) ? "selected=\"selected\"" : string.Empty;
}
else
{
plexTheme = "selected=\"selected\"";
}
}
<div class="col-sm-8 col-sm-push-1">
<form class="form-horizontal" method="POST" id="mainForm">
@ -69,16 +57,6 @@
</div>
</div>
<div class="form-group">
<label for="select" class="control-label">Theme</label>
<div id="themes">
<select class="form-control form-control-custom" id="select">
<option @plexTheme class="form-control form-control-custom" value="@Themes.PlexTheme">Plex</option>
<option @originalTheme class="form-control form-control-custom" value="@Themes.OriginalTheme">Original Blue</option>
</select>
</div>
</div>
@Html.Checkbox(Model.SearchForMovies,"SearchForMovies","Search for Movies")

@ -0,0 +1,89 @@
@using PlexRequests.UI.Helpers
@inherits Nancy.ViewEngines.Razor.NancyRazorViewBase<PlexRequests.Core.SettingModels.CustomizationSettings>
@Html.Partial("Shared/Partial/_Sidebar")
@{
var plexTheme = string.Empty;
var originalTheme = string.Empty;
if (!string.IsNullOrEmpty(Model.ThemeName))
{
plexTheme = Model.ThemeName.Equals(Themes.PlexTheme) ? "selected=\"selected\"" : string.Empty;
originalTheme = Model.ThemeName.Equals(Themes.OriginalTheme) ? "selected=\"selected\"" : string.Empty;
}
else
{
plexTheme = "selected=\"selected\"";
}
}
<div class="col-sm-8 col-sm-push-1">
<form class="form-horizontal" method="POST" id="mainForm">
<fieldset>
<legend>Customization Settings</legend>
<div class="form-group">
<label for="ApplicationName" class="control-label">Application Name</label>
<div>
<input type="text" class="form-control form-control-custom " id="ApplicationName" name="ApplicationName" placeholder="Application Name" value="@Model.ApplicationName">
</div>
</div>
<div class="form-group">
<label for="select" class="control-label">Theme</label>
<div id="themes">
<select class="form-control form-control-custom" id="select">
<option @plexTheme class="form-control form-control-custom" value="@Themes.PlexTheme">Plex</option>
<option @originalTheme class="form-control form-control-custom" value="@Themes.OriginalTheme">Original Blue</option>
</select>
</div>
</div>
<div class="form-group">
<div>
<button type="submit" id="save" class="btn btn-primary-outline">Submit</button>
</div>
</div>
</fieldset>
</form>
</div>
<script>
$(function() {
$('#save').click(function (e) {
e.preventDefault();
var theme = $("#themes option:selected").val();
var $form = $("#mainForm");
var data = $form.serialize();
data = data + "&themeName=" + theme;
$.ajax({
type: $form.prop("method"),
data: data,
url: $form.prop("action"),
dataType: "json",
success: function (response) {
if (response.result === true) {
generateNotify("Success!", "success");
} else {
generateNotify(response.message, "warning");
}
},
error: function (e) {
console.log(e);
generateNotify("Something went wrong!", "danger");
}
});
});
});
</script>

@ -37,11 +37,6 @@
</li>
}
<li role="presentation" class="nav-tab-right nav-tab-icononly">
<a href="#NotificationsTab" aria-controls="profile" role="tab" data-toggle="tab"><i class="fa fa-bell"></i></a>
</li>
</ul>
<!-- Tab panes -->

@ -12,13 +12,19 @@
{
url = "/" + baseUrl.ToHtmlString();
}
var title = UI.Layout_Title;
var customName = Html.GetApplicationName().ToHtmlString();
if (!string.IsNullOrEmpty(customName))
{
title = customName;
}
}
<div hidden="hidden" id="baseUrl">@baseUrl.ToHtmlString()</div>
<head>
<title>@UI.Layout_Title</title>
<title>@title</title>
<meta charset="utf-8">
<!-- Styles -->
<meta name="viewport" content="width=device-width, initial-scale=1">

@ -15,6 +15,13 @@
{
url = "/" + baseUrl.ToHtmlString();
}
var title = UI.Layout_Title;
var customName = Html.GetApplicationName().ToHtmlString();
if (!string.IsNullOrEmpty(customName))
{
title = customName;
}
}
@ -28,7 +35,7 @@
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="navbar-brand" href="@url/search">@UI.Layout_Title</a>
<a class="navbar-brand" href="@url/search">@title</a>
</div>
<div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
@ -40,7 +47,6 @@
{
@Html.GetNavbarUrl(Context, "/usermanagement", UI.Layout_Usermanagement, "users")
}
@*@if (Context.CurrentUser.IsAuthenticated()) // TODO replace with IsAdmin*@
@if (Html.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>
@ -48,12 +54,10 @@
<li id="customDonate" style="display: none"><a id="customDonateHref" href="https://www.paypal.me/PlexRequestsNet" target="_blank"><i class="fa fa-heart" style="color: yellow;"></i> <span id="donationText">@UI.Custom_Donation_Default</span></a></li>
</ul>
<ul class="nav navbar-nav navbar-right">
@*@if (!Context.CurrentUser.IsAuthenticated() && Context.Request.Session[SessionKeys.UsernameKey] == null) // TODO replace with IsAdmin*@
@if (!Html.IsLoggedIn(Context))
{
<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*@
@if (Html.IsAdmin())
{
<li><a>@UI.Layout_Welcome @Context.CurrentUser.UserName</a></li>
@ -68,7 +72,6 @@
</ul>
</li>
}
@*@if (Context.Request.Session[SessionKeys.UsernameKey] != null && !Context.CurrentUser.IsAuthenticated())*@
else if (Html.IsNormalUser()) // Logged in but not admin
{
<li class="dropdown">
@ -90,6 +93,17 @@
</li>
}
else if (Html.IsLoggedIn(Context)) // Logged in but not admin
{
<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/logout"><i class="fa fa-sign-out"></i> @UI.Layout_Logout</a></li>
</ul>
</li>
}
<li class="dropdown">

@ -3,6 +3,7 @@
<div class="col-lg-3 col-md-3 col-sm-4">
<div class="list-group table-of-contents">
@Html.GetSidebarUrl(Context, "/admin", "Plex Request")
@Html.GetSidebarUrl(Context, "/admin/customization", "Customization")
@Html.GetSidebarUrl(Context, "/admin/landingpage", "Landing Page")
@Html.GetSidebarUrl(Context, "/admin/authentication", "Authentication")
@Html.GetSidebarUrl(Context, "/admin/usermanagementsettings", "User Management Settings")

@ -35,6 +35,7 @@
<package id="Ninject" version="3.2.0.0" targetFramework="net45" />
<package id="Ninject.Extensions.ChildKernel" version="3.2.0.0" targetFramework="net45" />
<package id="NLog" version="4.3.6" targetFramework="net45" />
<package id="Octokit" version="0.19.0" targetFramework="net45" />
<package id="Owin" version="1.0" targetFramework="net45" />
<package id="Quartz" version="2.3.3" targetFramework="net45" />
<package id="RestSharp" version="105.2.3" targetFramework="net45" />

@ -3,9 +3,9 @@ configuration: Release
assembly_info:
patch: true
file: '**\AssemblyInfo.*'
assembly_version: '1.10.0'
assembly_version: '1.10.1'
assembly_file_version: '{version}'
assembly_informational_version: '1.10.0'
assembly_informational_version: '1.10.1'
before_build:
- cmd: appveyor-retry nuget restore
build:

Loading…
Cancel
Save