- Added a visual indication on the UI to tell the admin there is a update available.

- We are now also recording the last scheduled run in the database
pull/193/head
tidusjar 9 years ago
parent af028f0b56
commit df3dc4ac04

@ -47,5 +47,7 @@ namespace PlexRequests.Core
public const string CouchPotatoQueued = "CouchPotatoQueued";
public const string GetBaseUrl = "GetBaseUrl";
public const string LastestProductVersion = "LatestProductVersion";
}
}

@ -49,10 +49,9 @@ namespace PlexRequests.Core
var entity = new RequestBlobs { Type = model.Type, Content = ByteConverterHelper.ReturnBytes(model), ProviderId = model.ProviderId };
var id = Repo.Insert(entity);
// TODO Keep an eye on this, since we are now doing 2 DB update for 1 single request, inserting and then updating
model.Id = (int)id;
entity = new RequestBlobs { Type = model.Type, Content = ByteConverterHelper.ReturnBytes(model), ProviderId = model.ProviderId, Id = (int)id, MusicId = model.MusicBrainzId};
entity = new RequestBlobs { Type = model.Type, Content = ByteConverterHelper.ReturnBytes(model), ProviderId = model.ProviderId, Id = (int)id, MusicId = model.MusicBrainzId };
var result = Repo.Update(entity);
return result ? id : -1;

@ -24,21 +24,11 @@
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
// ************************************************************************/
#endregion
using System.Text.RegularExpressions;
namespace PlexRequests.Core.Models
{
public class StatusModel
{
public string Version { get; set; }
public int DBVersion {
get
{
string trimStatus = new Regex("[^0-9]", RegexOptions.Compiled).Replace(Version, string.Empty).PadRight(4, '0');
return int.Parse(trimStatus);
}
}
public bool UpdateAvailable { get; set; }
public string UpdateUri { get; set; }
public string DownloadUri { get; set; }

@ -28,6 +28,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;
using Mono.Data.Sqlite;
using NLog;
@ -72,18 +73,19 @@ namespace PlexRequests.Core
private int CheckSchema()
{
var checker = new StatusChecker();
var status = checker.GetStatus();
var productVersion = AssemblyHelper.GetProductVersion();
var trimStatus = new Regex("[^0-9]", RegexOptions.Compiled).Replace(productVersion, string.Empty).PadRight(4, '0');
var version = int.Parse(trimStatus);
var connection = Db.DbConnection();
var schema = connection.GetSchemaVersion();
if (schema == null)
{
connection.CreateSchema(status.DBVersion); // Set the default.
connection.CreateSchema(version); // Set the default.
schema = connection.GetSchemaVersion();
}
var version = schema.SchemaVersion;
version = schema.SchemaVersion;
return version;
}

@ -0,0 +1,33 @@
#region Copyright
// /************************************************************************
// Copyright (c) 2016 Jamie Rees
// File: IJobRecord.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.Services.Interfaces
{
public interface IJobRecord
{
void Record(string jobName);
}
}

@ -41,16 +41,18 @@ namespace PlexRequests.Services.Jobs
{
public class CouchPotatoCacher : IJob, ICouchPotatoCacher
{
public CouchPotatoCacher(ISettingsService<CouchPotatoSettings> cpSettings, ICouchPotatoApi cpApi, ICacheProvider cache)
public CouchPotatoCacher(ISettingsService<CouchPotatoSettings> cpSettings, ICouchPotatoApi cpApi, ICacheProvider cache, IJobRecord rec)
{
CpSettings = cpSettings;
CpApi = cpApi;
Cache = cache;
Job = rec;
}
private ISettingsService<CouchPotatoSettings> CpSettings { get; }
private ICacheProvider Cache { get; }
private ICouchPotatoApi CpApi { get; }
private IJobRecord Job { get; }
private static Logger Log = LogManager.GetCurrentClassLogger();
@ -74,6 +76,10 @@ namespace PlexRequests.Services.Jobs
{
Log.Error(ex, "Failed caching queued items from CouchPotato");
}
finally
{
Job.Record(JobNames.CpCacher);
}
}
}

@ -0,0 +1,37 @@
#region Copyright
// /************************************************************************
// Copyright (c) 2016 Jamie Rees
// File: JobNames.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.Services
{
public static class JobNames
{
public const string StoreBackup = "Database Backup";
public const string CpCacher = "CouchPotato Cacher";
public const string SonarrCacher = "Sonarr Cacher";
public const string SrCacher = "SickRage Cacher";
public const string PlexChecker = "Plex Availability Cacher";
}
}

@ -0,0 +1,59 @@
#region Copyright
// /************************************************************************
// Copyright (c) 2016 Jamie Rees
// File: JobRecord.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 PlexRequests.Services.Interfaces;
using PlexRequests.Store.Models;
using PlexRequests.Store.Repository;
namespace PlexRequests.Services
{
public class JobRecord : IJobRecord
{
public JobRecord(IRepository<ScheduledJobs> repo)
{
Repo = repo;
}
private IRepository<ScheduledJobs> Repo { get; }
public void Record(string jobName)
{
var allJobs = Repo.GetAll();
var storeJob = allJobs.FirstOrDefault(x => x.Name == jobName);
if (storeJob != null)
{
storeJob.LastRun = DateTime.UtcNow;
Repo.Update(storeJob);
}
else
{
var job = new ScheduledJobs { LastRun = DateTime.UtcNow, Name = jobName };
Repo.Insert(job);
}
}
}
}

@ -47,7 +47,7 @@ namespace PlexRequests.Services.Jobs
public class PlexAvailabilityChecker : IJob, IAvailabilityChecker
{
public PlexAvailabilityChecker(ISettingsService<PlexSettings> plexSettings, ISettingsService<AuthenticationSettings> auth, IRequestService request, IPlexApi plex, ICacheProvider cache,
INotificationService notify)
INotificationService notify, IJobRecord rec)
{
Plex = plexSettings;
Auth = auth;
@ -55,6 +55,7 @@ namespace PlexRequests.Services.Jobs
PlexApi = plex;
Cache = cache;
Notification = notify;
Job = rec;
}
private ISettingsService<PlexSettings> Plex { get; }
@ -64,6 +65,7 @@ namespace PlexRequests.Services.Jobs
private IPlexApi PlexApi { get; }
private ICacheProvider Cache { get; }
private INotificationService Notification { get; }
private IJobRecord Job { get; }
public void CheckAndUpdateAll()
{
@ -144,6 +146,8 @@ namespace PlexRequests.Services.Jobs
RequestService.BatchUpdate(modifiedModel);
}
Job.Record(JobNames.PlexChecker);
}
public List<PlexMovie> GetPlexMovies()

@ -41,11 +41,12 @@ namespace PlexRequests.Services.Jobs
{
public class SickRageCacher : IJob, ISickRageCacher
{
public SickRageCacher(ISettingsService<SickRageSettings> srSettings, ISickRageApi srApi, ICacheProvider cache)
public SickRageCacher(ISettingsService<SickRageSettings> srSettings, ISickRageApi srApi, ICacheProvider cache, IJobRecord rec)
{
SrSettings = srSettings;
SrApi = srApi;
Cache = cache;
Job = rec;
}
private ISettingsService<SickRageSettings> SrSettings { get; }
@ -53,6 +54,7 @@ namespace PlexRequests.Services.Jobs
private ISickRageApi SrApi { get; }
private static Logger Log = LogManager.GetCurrentClassLogger();
private IJobRecord Job { get; }
public void Queued()
{
@ -74,6 +76,10 @@ namespace PlexRequests.Services.Jobs
{
Log.Error(ex, "Failed caching queued items from SickRage");
}
finally
{
Job.Record(JobNames.SrCacher);
}
}
}

@ -35,6 +35,8 @@ using PlexRequests.Core;
using PlexRequests.Core.SettingModels;
using PlexRequests.Helpers;
using PlexRequests.Services.Interfaces;
using PlexRequests.Store.Models;
using PlexRequests.Store.Repository;
using Quartz;
@ -42,16 +44,18 @@ namespace PlexRequests.Services.Jobs
{
public class SonarrCacher : IJob, ISonarrCacher
{
public SonarrCacher(ISettingsService<SonarrSettings> sonarrSettings, ISonarrApi sonarrApi, ICacheProvider cache)
public SonarrCacher(ISettingsService<SonarrSettings> sonarrSettings, ISonarrApi sonarrApi, ICacheProvider cache, IJobRecord rec)
{
SonarrSettings = sonarrSettings;
SonarrApi = sonarrApi;
Job = rec;
Cache = cache;
}
private ISettingsService<SonarrSettings> SonarrSettings { get; }
private ICacheProvider Cache { get; }
private ISonarrApi SonarrApi { get; }
private IJobRecord Job { get; }
private static Logger Log = LogManager.GetCurrentClassLogger();
@ -75,6 +79,10 @@ namespace PlexRequests.Services.Jobs
{
Log.Error(ex, "Failed caching queued items from Sonarr");
}
finally
{
Job.Record(JobNames.SonarrCacher);
}
}
}

@ -30,7 +30,10 @@ using System.Linq;
using NLog;
using PlexRequests.Services.Interfaces;
using PlexRequests.Store;
using PlexRequests.Store.Models;
using PlexRequests.Store.Repository;
using Quartz;
@ -40,12 +43,14 @@ namespace PlexRequests.Services.Jobs
{
public class StoreBackup : IJob
{
public StoreBackup(ISqliteConfiguration sql)
public StoreBackup(ISqliteConfiguration sql, IJobRecord rec)
{
Sql = sql;
JobRecord = rec;
}
private ISqliteConfiguration Sql { get; }
private IJobRecord JobRecord { get; }
private static Logger Log = LogManager.GetCurrentClassLogger();
@ -82,6 +87,10 @@ namespace PlexRequests.Services.Jobs
Log.Warn(e);
Log.Warn("Exception when trying to copy the backup.");
}
finally
{
JobRecord.Record(JobNames.StoreBackup);
}
}
}

@ -93,6 +93,9 @@
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="Interfaces\IJobRecord.cs" />
<Compile Include="Jobs\JobRecord.cs" />
<Compile Include="Jobs\JobNames.cs" />
<Compile Include="Jobs\StoreBackup.cs" />
<Compile Include="Jobs\CouchPotatoCacher.cs" />
<Compile Include="Jobs\PlexAvailabilityChecker.cs" />

@ -0,0 +1,39 @@
#region Copyright
// /************************************************************************
// Copyright (c) 2016 Jamie Rees
// File: LogEntity.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 Dapper.Contrib.Extensions;
namespace PlexRequests.Store.Models
{
[Table("ScheduledJobs")]
public class ScheduledJobs : Entity
{
public string Name { get; set; }
public DateTime LastRun { get; set; }
}
}

@ -63,6 +63,7 @@
<ItemGroup>
<Compile Include="DbConfiguration.cs" />
<Compile Include="Entity.cs" />
<Compile Include="Models\ScheduledJobs.cs" />
<Compile Include="Repository\IRequestRepository.cs" />
<Compile Include="Repository\ISettingsRepository.cs" />
<Compile Include="ISqliteConfiguration.cs" />

@ -45,5 +45,12 @@ CREATE UNIQUE INDEX IF NOT EXISTS Logs_Id ON Logs (Id);
CREATE TABLE IF NOT EXISTS DBInfo
(
SchemaVersion INTEGER
);
);
CREATE TABLE IF NOT EXISTS ScheduledJobs
(
Id INTEGER PRIMARY KEY AUTOINCREMENT,
Name varchar(100) NOT NULL,
LastRun varchar(100) NOT NULL
);
CREATE UNIQUE INDEX IF NOT EXISTS ScheduledJobs_Id ON ScheduledJobs (Id);

@ -87,8 +87,10 @@ namespace PlexRequests.UI
// Repo's
container.Register<IRepository<LogEntity>, GenericRepository<LogEntity>>();
container.Register<IRepository<ScheduledJobs>, GenericRepository<ScheduledJobs>>();
container.Register<IRequestService, JsonRequestService>();
container.Register<ISettingsRepository, SettingsJsonRepository>();
container.Register<IJobRecord, JobRecord>();
// Services
container.Register<IAvailabilityChecker, PlexAvailabilityChecker>();

@ -220,3 +220,7 @@ label {
border-radius: 0 0.25rem 0.25rem 0 !important;
padding: 12px 8px; }
#updateAvailable {
background-color: #ffa400;
text-align: center; }

@ -1 +1 @@
@media(min-width:768px){.row{position:relative;}.bottom-align-text{position:absolute;bottom:0;right:0;}}@media(max-width:48em){.home{padding-top:1rem;}}@media(min-width:48em){.home{padding-top:4rem;}}.btn{border-radius:.25rem !important;}.multiSelect{background-color:#4e5d6c;}.form-control-custom{background-color:#4e5d6c !important;color:#fff !important;border-radius:0;box-shadow:0 0 0 !important;}h1{font-size:3.5rem !important;font-weight:600 !important;}.request-title{margin-top:0 !important;font-size:1.9rem !important;}p{font-size:1.1rem !important;}label{display:inline-block !important;margin-bottom:.5rem !important;font-size:16px !important;}.nav-tabs>li.active>a,.nav-tabs>li.active>a:hover,.nav-tabs>li.active>a:focus{background:#4e5d6c;}.navbar .nav a .fa,.dropdown-menu a .fa{font-size:130%;top:1px;position:relative;display:inline-block;margin-right:5px;}.dropdown-menu a .fa{top:2px;}.btn-danger-outline{color:#d9534f !important;background-color:transparent;background-image:none;border-color:#d9534f !important;}.btn-danger-outline:focus,.btn-danger-outline.focus,.btn-danger-outline:active,.btn-danger-outline.active,.btn-danger-outline:hover,.open>.btn-danger-outline.dropdown-toggle{color:#fff !important;background-color:#d9534f !important;border-color:#d9534f !important;}.btn-primary-outline{color:#ff761b !important;background-color:transparent;background-image:none;border-color:#ff761b !important;}.btn-primary-outline:focus,.btn-primary-outline.focus,.btn-primary-outline:active,.btn-primary-outline.active,.btn-primary-outline:hover,.open>.btn-primary-outline.dropdown-toggle{color:#fff !important;background-color:#df691a !important;border-color:#df691a !important;}.btn-info-outline{color:#5bc0de !important;background-color:transparent;background-image:none;border-color:#5bc0de !important;}.btn-info-outline:focus,.btn-info-outline.focus,.btn-info-outline:active,.btn-info-outline.active,.btn-info-outline:hover,.open>.btn-info-outline.dropdown-toggle{color:#fff !important;background-color:#5bc0de !important;border-color:#5bc0de !important;}.btn-warning-outline{color:#f0ad4e !important;background-color:transparent;background-image:none;border-color:#f0ad4e !important;}.btn-warning-outline:focus,.btn-warning-outline.focus,.btn-warning-outline:active,.btn-warning-outline.active,.btn-warning-outline:hover,.open>.btn-warning-outline.dropdown-toggle{color:#fff !important;background-color:#f0ad4e !important;border-color:#f0ad4e !important;}.btn-success-outline{color:#5cb85c !important;background-color:transparent;background-image:none;border-color:#5cb85c !important;}.btn-success-outline:focus,.btn-success-outline.focus,.btn-success-outline:active,.btn-success-outline.active,.btn-success-outline:hover,.open>.btn-success-outline.dropdown-toggle{color:#fff !important;background-color:#5cb85c !important;border-color:#5cb85c !important;}#movieList .mix{display:none;}#tvList .mix{display:none;}.scroll-top-wrapper{position:fixed;opacity:0;visibility:hidden;overflow:hidden;text-align:center;z-index:99999999;background-color:#4e5d6c;color:#eee;width:50px;height:48px;line-height:48px;right:30px;bottom:30px;padding-top:2px;border-top-left-radius:10px;border-top-right-radius:10px;border-bottom-right-radius:10px;border-bottom-left-radius:10px;-webkit-transition:all .5s ease-in-out;-moz-transition:all .5s ease-in-out;-ms-transition:all .5s ease-in-out;-o-transition:all .5s ease-in-out;transition:all .5s ease-in-out;}.scroll-top-wrapper:hover{background-color:#637689;}.scroll-top-wrapper.show{visibility:visible;cursor:pointer;opacity:1;}.scroll-top-wrapper i.fa{line-height:inherit;}.no-search-results{text-align:center;}.no-search-results .no-search-results-icon{font-size:10em;color:#4e5d6c;}.no-search-results .no-search-results-text{margin:20px 0;color:#ccc;}.form-control-search{padding:13px 105px 13px 16px;height:100%;}.form-control-withbuttons{padding-right:105px;}.input-group-addon .btn-group{position:absolute;right:45px;z-index:3;top:13px;box-shadow:0 0 0;}.input-group-addon .btn-group .btn{border:1px solid rgba(255,255,255,.7) !important;padding:3px 12px;color:rgba(255,255,255,.7) !important;}.btn-split .btn{border-radius:0 !important;}.btn-split .btn:not(.dropdown-toggle){border-radius:.25rem 0 0 .25rem !important;}.btn-split .btn.dropdown-toggle{border-radius:0 .25rem .25rem 0 !important;padding:12px 8px;}
@media(min-width:768px){.row{position:relative;}.bottom-align-text{position:absolute;bottom:0;right:0;}}@media(max-width:48em){.home{padding-top:1rem;}}@media(min-width:48em){.home{padding-top:4rem;}}.btn{border-radius:.25rem !important;}.multiSelect{background-color:#4e5d6c;}.form-control-custom{background-color:#4e5d6c !important;color:#fff !important;border-radius:0;box-shadow:0 0 0 !important;}h1{font-size:3.5rem !important;font-weight:600 !important;}.request-title{margin-top:0 !important;font-size:1.9rem !important;}p{font-size:1.1rem !important;}label{display:inline-block !important;margin-bottom:.5rem !important;font-size:16px !important;}.nav-tabs>li.active>a,.nav-tabs>li.active>a:hover,.nav-tabs>li.active>a:focus{background:#4e5d6c;}.navbar .nav a .fa,.dropdown-menu a .fa{font-size:130%;top:1px;position:relative;display:inline-block;margin-right:5px;}.dropdown-menu a .fa{top:2px;}.btn-danger-outline{color:#d9534f !important;background-color:transparent;background-image:none;border-color:#d9534f !important;}.btn-danger-outline:focus,.btn-danger-outline.focus,.btn-danger-outline:active,.btn-danger-outline.active,.btn-danger-outline:hover,.open>.btn-danger-outline.dropdown-toggle{color:#fff !important;background-color:#d9534f !important;border-color:#d9534f !important;}.btn-primary-outline{color:#ff761b !important;background-color:transparent;background-image:none;border-color:#ff761b !important;}.btn-primary-outline:focus,.btn-primary-outline.focus,.btn-primary-outline:active,.btn-primary-outline.active,.btn-primary-outline:hover,.open>.btn-primary-outline.dropdown-toggle{color:#fff !important;background-color:#df691a !important;border-color:#df691a !important;}.btn-info-outline{color:#5bc0de !important;background-color:transparent;background-image:none;border-color:#5bc0de !important;}.btn-info-outline:focus,.btn-info-outline.focus,.btn-info-outline:active,.btn-info-outline.active,.btn-info-outline:hover,.open>.btn-info-outline.dropdown-toggle{color:#fff !important;background-color:#5bc0de !important;border-color:#5bc0de !important;}.btn-warning-outline{color:#f0ad4e !important;background-color:transparent;background-image:none;border-color:#f0ad4e !important;}.btn-warning-outline:focus,.btn-warning-outline.focus,.btn-warning-outline:active,.btn-warning-outline.active,.btn-warning-outline:hover,.open>.btn-warning-outline.dropdown-toggle{color:#fff !important;background-color:#f0ad4e !important;border-color:#f0ad4e !important;}.btn-success-outline{color:#5cb85c !important;background-color:transparent;background-image:none;border-color:#5cb85c !important;}.btn-success-outline:focus,.btn-success-outline.focus,.btn-success-outline:active,.btn-success-outline.active,.btn-success-outline:hover,.open>.btn-success-outline.dropdown-toggle{color:#fff !important;background-color:#5cb85c !important;border-color:#5cb85c !important;}#movieList .mix{display:none;}#tvList .mix{display:none;}.scroll-top-wrapper{position:fixed;opacity:0;visibility:hidden;overflow:hidden;text-align:center;z-index:99999999;background-color:#4e5d6c;color:#eee;width:50px;height:48px;line-height:48px;right:30px;bottom:30px;padding-top:2px;border-top-left-radius:10px;border-top-right-radius:10px;border-bottom-right-radius:10px;border-bottom-left-radius:10px;-webkit-transition:all .5s ease-in-out;-moz-transition:all .5s ease-in-out;-ms-transition:all .5s ease-in-out;-o-transition:all .5s ease-in-out;transition:all .5s ease-in-out;}.scroll-top-wrapper:hover{background-color:#637689;}.scroll-top-wrapper.show{visibility:visible;cursor:pointer;opacity:1;}.scroll-top-wrapper i.fa{line-height:inherit;}.no-search-results{text-align:center;}.no-search-results .no-search-results-icon{font-size:10em;color:#4e5d6c;}.no-search-results .no-search-results-text{margin:20px 0;color:#ccc;}.form-control-search{padding:13px 105px 13px 16px;height:100%;}.form-control-withbuttons{padding-right:105px;}.input-group-addon .btn-group{position:absolute;right:45px;z-index:3;top:13px;box-shadow:0 0 0;}.input-group-addon .btn-group .btn{border:1px solid rgba(255,255,255,.7) !important;padding:3px 12px;color:rgba(255,255,255,.7) !important;}.btn-split .btn{border-radius:0 !important;}.btn-split .btn:not(.dropdown-toggle){border-radius:.25rem 0 0 .25rem !important;}.btn-split .btn.dropdown-toggle{border-radius:0 .25rem .25rem 0 !important;padding:12px 8px;}#updateAvailable{background-color:#ffa400;text-align:center;}

@ -7,8 +7,7 @@ $warning-colour: #f0ad4e;
$danger-colour: #d9534f;
$success-colour: #5cb85c;
$i:
!important
;
!important;
@media (min-width: 768px ) {
.row {
@ -279,4 +278,9 @@ $border-radius: 10px;
.btn-split .btn.dropdown-toggle {
border-radius: 0 .25rem .25rem 0 $i;
padding: 12px 8px;
}
#updateAvailable {
background-color: rgb(255, 164, 0);
text-align: center;
}

@ -36,7 +36,7 @@ using Quartz.Spi;
namespace PlexRequests.UI.Jobs
{
/// <summary>
/// The custom job factory we are using so we are able to use our IoC container with DI in our Jobs.
/// The custom job factory we are using so we are able to use our IoC container with DI in our JobNames.
/// </summary>
/// <seealso cref="Quartz.Spi.IJobFactory" />
public class CustomJobFactory : IJobFactory

@ -0,0 +1,33 @@
#region Copyright
// /************************************************************************
// Copyright (c) 2016 Jamie Rees
// File: JsonUpdateAvailableModel.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 JsonUpdateAvailableModel
{
public bool UpdateAvailable { get; set; }
}
}

@ -295,8 +295,8 @@ namespace PlexRequests.UI.Modules
}
var result = CpService.SaveSettings(couchPotatoSettings);
return Response.AsJson(result
? new JsonResponseModel { Result = true, Message = "Successfully Updated the Settings for CouchPotato!" }
return Response.AsJson(result
? new JsonResponseModel { Result = true, Message = "Successfully Updated the Settings for CouchPotato!" }
: new JsonResponseModel { Result = false, Message = "Could not update the settings, take a look at the logs." });
}
@ -429,7 +429,7 @@ namespace PlexRequests.UI.Modules
finally
{
NotificationService.UnSubscribe(new EmailMessageNotification(EmailService));
}
}
return Response.AsJson(new JsonResponseModel { Result = true, Message = "Successfully sent a test Email Notification!" });
}
@ -464,7 +464,7 @@ namespace PlexRequests.UI.Modules
{
var checker = new StatusChecker();
var status = checker.GetStatus();
var md = new Markdown();
var md = new Markdown(new MarkdownOptions { AutoNewLines = true });
status.ReleaseNotes = md.Transform(status.ReleaseNotes);
return View["Status", status];
}
@ -623,7 +623,7 @@ namespace PlexRequests.UI.Modules
{
JsonSettings.MaxJsonLength = int.MaxValue;
var allLogs = LogsRepo.GetAll().OrderByDescending(x => x.Id).Take(200);
var model = new DatatablesModel<LogEntity> {Data = new List<LogEntity>()};
var model = new DatatablesModel<LogEntity> { Data = new List<LogEntity>() };
foreach (var l in allLogs)
{
l.DateString = l.Date.ToString("G");
@ -650,7 +650,7 @@ namespace PlexRequests.UI.Modules
settings.Level = level;
LogService.SaveSettings(settings);
return Response.AsJson(new JsonResponseModel { Result = true, Message = $"The new log level is now {newLevel}"});
return Response.AsJson(new JsonResponseModel { Result = true, Message = $"The new log level is now {newLevel}" });
}
private Negotiator Headphones()
@ -673,7 +673,7 @@ namespace PlexRequests.UI.Modules
Log.Trace(settings.DumpJson());
var result = HeadphonesService.SaveSettings(settings);
Log.Info("Saved headphones settings, result: {0}", result);
return Response.AsJson(result
? new JsonResponseModel { Result = true, Message = "Successfully Updated the Settings for Headphones!" }

@ -30,8 +30,11 @@ using Nancy.Extensions;
using PlexRequests.UI.Models;
using System;
using Nancy.Security;
using PlexRequests.Core;
using PlexRequests.Core.SettingModels;
using PlexRequests.Helpers;
namespace PlexRequests.UI.Modules
{
@ -52,6 +55,8 @@ namespace PlexRequests.UI.Modules
}
}
protected bool IsAdmin => Context.CurrentUser.IsAuthenticated();
protected int DateTimeOffset
{
get
@ -87,5 +92,7 @@ namespace PlexRequests.UI.Modules
: null;
}
}
}

@ -124,14 +124,6 @@ namespace PlexRequests.UI.Modules
private IHeadphonesApi HeadphonesApi { get; }
private static Logger Log = LogManager.GetCurrentClassLogger();
private bool IsAdmin
{
get
{
return Context.CurrentUser.IsAuthenticated();
}
}
private Negotiator RequestLoad()
{
var settings = PrService.GetSettings();
@ -626,7 +618,7 @@ namespace PlexRequests.UI.Modules
Status = showInfo.status,
RequestedDate = DateTime.UtcNow,
Approved = false,
RequestedUsers = new List<string>() { Username },
RequestedUsers = new List<string> { Username },
Issues = IssueState.None,
ImdbId = showInfo.externals?.imdb ?? string.Empty,
SeasonCount = showInfo.seasonCount
@ -802,7 +794,7 @@ namespace PlexRequests.UI.Modules
}
var sender = new HeadphonesSender(HeadphonesApi, hpSettings, RequestService);
sender.AddAlbum(model);
sender.AddAlbum(model).Wait();
model.Approved = true;
RequestService.AddRequest(model);

@ -0,0 +1,79 @@
#region Copyright
// /************************************************************************
// Copyright (c) 2016 Jamie Rees
// File: UpdateCheckerModule.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 Nancy;
using NLog;
using PlexRequests.Core;
using PlexRequests.Helpers;
using PlexRequests.UI.Models;
namespace PlexRequests.UI.Modules
{
public class UpdateCheckerModule : BaseAuthModule
{
public UpdateCheckerModule(ICacheProvider provider) : base("updatechecker")
{
Cache = provider;
Get["/"] = _ => CheckLatestVersion();
}
private ICacheProvider Cache { get; }
private static Logger Log = LogManager.GetCurrentClassLogger();
private Response CheckLatestVersion()
{
try
{
if (!IsAdmin)
{
return Response.AsJson(new JsonUpdateAvailableModel { UpdateAvailable = false });
}
var checker = new StatusChecker();
var release = Cache.GetOrSet(CacheKeys.LastestProductVersion, () => checker.GetStatus(), 30);
if (release.UpdateAvailable)
{
return Response.AsJson(new JsonUpdateAvailableModel { UpdateAvailable = true});
}
return Response.AsJson(new JsonUpdateAvailableModel { UpdateAvailable = false });
}
catch (Exception e)
{
Log.Warn("Exception Thrown when attempting to check the status");
Log.Warn(e);
return Response.AsJson(new JsonUpdateAvailableModel { UpdateAvailable = false });
}
}
}
}

@ -185,12 +185,14 @@
<Compile Include="Jobs\CustomJobFactory.cs" />
<Compile Include="Jobs\Scheduler.cs" />
<Compile Include="Models\DatatablesModel.cs" />
<Compile Include="Models\JsonUpdateAvailableModel.cs" />
<Compile Include="Models\MovieSearchType.cs" />
<Compile Include="Models\QualityModel.cs" />
<Compile Include="Models\SearchViewModel.cs" />
<Compile Include="Models\SearchMusicViewModel.cs" />
<Compile Include="Models\SearchMovieViewModel.cs" />
<Compile Include="Modules\BaseModule.cs" />
<Compile Include="Modules\UpdateCheckerModule.cs" />
<Compile Include="Start\StartupOptions.cs" />
<Compile Include="Validators\HeadphonesValidator.cs" />
<Compile Include="Validators\PushoverSettingsValidator.cs" />

@ -34,7 +34,7 @@
</button>
<a class="navbar-brand" href="@url/search">Plex Requests</a>
</div>
<div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
<ul class="nav navbar-nav">
@Html.GetNavbarUrl(Context, "/search", "Search", "search")
@ -42,7 +42,7 @@
</ul>
<ul class="nav navbar-nav navbar-right">
@if (!Context.CurrentUser.IsAuthenticated())
{
<li><a href="@url/login"><i class="fa fa-user"></i> Admin</a></li>
@ -66,6 +66,7 @@
</ul>
</div>
</div>
<div id="updateAvailable" hidden="hidden"></div>
</nav>
<div class="container">
@ -82,6 +83,24 @@
$(function () {
var urlBase = '@Html.GetBaseUrl()';
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("There is a new update available! Click <a style='color: white' href='"+status+"'>Here!</a>");
$('#updateAvailable').removeAttr("hidden");
}
},
error: function (e) {
console.log(e);
}
});
$(document).on('scroll', function () {
if ($(window).scrollTop() > 100) {

Loading…
Cancel
Save