Lots of refactoring #865

Starting to refactor the Angular Modules now
pull/1488/head
Jamie.Rees 7 years ago
parent bad109c862
commit ffab4b7981

@ -1,5 +1,4 @@
using Ombi.Core.Claims;
using Ombi.Core.Rule;
using Ombi.Core.Rule;
using System.Collections.Generic;
using System.Security.Principal;
using System.Threading.Tasks;
@ -18,24 +17,13 @@ namespace Ombi.Core.Engine.Interfaces
}
protected IPrincipal User { get; }
protected IRuleEvaluator Rules { get; }
protected string Username => User.Identity.Name;
protected bool HasRole(string roleName)
{
return User.IsInRole(roleName);
}
protected bool ShouldSendNotification(BaseRequest req)
{
var sendNotification = !req.Approved; /*|| !prSettings.IgnoreNotifyForAutoApprovedRequests;*/
if (HasRole(OmbiClaims.Admin))
sendNotification = false; // Don't bother sending a notification if the user is an admin
return sendNotification;
}
public async Task<IEnumerable<RuleResult>> RunRequestRules(BaseRequest model)
{

@ -182,7 +182,8 @@ namespace Ombi.Core.Engine
{
await MovieRepository.Add(model);
if (ShouldSendNotification(model))
var result = await RunSpecificRule(model, SpecificRules.CanSendNotification);
if (result.Success)
{
NotificationHelper.NewRequest(model);
}

@ -12,6 +12,7 @@ using System.Security.Principal;
using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore;
using Ombi.Core.Engine.Interfaces;
using Ombi.Core.Helpers;
using Ombi.Core.IdentityResolver;
using Ombi.Core.Rule;
using Ombi.Core.Rule.Interfaces;
@ -42,128 +43,17 @@ namespace Ombi.Core.Engine
public async Task<RequestEngineResult> RequestTvShow(SearchTvShowViewModel tv)
{
var showInfo = await TvApi.ShowLookupByTheTvDbId(tv.Id);
DateTime.TryParse(showInfo.premiered, out DateTime firstAir);
// For some reason the poster path is always http
var posterPath = showInfo.image?.medium.Replace("http:", "https:");
var tvRequests = new List<SeasonRequests>();
// Only have the TV requests we actually requested and not everything
foreach (var season in tv.SeasonRequests)
{
for (int i = season.Episodes.Count - 1; i >= 0; i--)
{
if (!season.Episodes[i].Requested)
{
season.Episodes.RemoveAt(i); // Remove the episode since it's not requested
}
}
if (season.Episodes.Any())
{
tvRequests.Add(season);
}
}
var user = await UserManager.GetUser(User.Identity.Name);
var childRequest = new ChildRequests
{
Id = tv.Id,
RequestType = RequestType.TvShow,
RequestedDate = DateTime.UtcNow,
Approved = false,
RequestedUserId = user.Id,
SeasonRequests = new List<SeasonRequests>()
};
if (tv.RequestAll)
{
var episodes = await TvApi.EpisodeLookup(showInfo.id);
foreach (var ep in episodes)
{
var season = childRequest.SeasonRequests.FirstOrDefault(x => x.SeasonNumber == ep.season);
if (season == null)
{
childRequest.SeasonRequests.Add(new SeasonRequests
{
Episodes = new List<EpisodeRequests>{
new EpisodeRequests
{
EpisodeNumber = ep.number,
AirDate = DateTime.Parse(ep.airdate),
Title = ep.name,
Url = ep.url
}
},
SeasonNumber = ep.season,
});
}
else
{
season.Episodes.Add(new EpisodeRequests
{
EpisodeNumber = ep.number,
AirDate = DateTime.Parse(ep.airdate),
Title = ep.name,
Url = ep.url
});
}
}
var tvBuilder = new TvShowRequestBuilder(TvApi);
(await tvBuilder
.GetShowInfo(tv.Id))
.CreateTvList(tv)
.CreateChild(tv, user.Id);
}
else if (tv.LatestSeason)
{
var episodes = await TvApi.EpisodeLookup(showInfo.id);
var latest = episodes.OrderBy(x => x.season).FirstOrDefault();
var episodesRequests = new List<EpisodeRequests>();
foreach (var ep in episodes)
{
episodesRequests.Add(new EpisodeRequests
{
EpisodeNumber = ep.number,
AirDate = DateTime.Parse(ep.airdate),
Title = ep.name,
Url = ep.url
});
}
childRequest.SeasonRequests.Add(new SeasonRequests
{
Episodes = episodesRequests,
SeasonNumber = latest.season,
});
}
else if (tv.FirstSeason)
{
var episodes = await TvApi.EpisodeLookup(showInfo.id);
var first = episodes.OrderByDescending(x => x.season).FirstOrDefault();
var episodesRequests = new List<EpisodeRequests>();
foreach (var ep in episodes)
{
if (ep.season == first.season)
{
episodesRequests.Add(new EpisodeRequests
{
EpisodeNumber = ep.number,
AirDate = DateTime.Parse(ep.airdate),
Title = ep.name,
Url = ep.url
});
}
}
childRequest.SeasonRequests.Add(new SeasonRequests
{
Episodes = episodesRequests,
SeasonNumber = first.season,
});
}
else
{
// It's a custom request
childRequest.SeasonRequests = tvRequests;
}
var ruleResults = await RunRequestRules(childRequest);
await tvBuilder.BuildEpisodes(tv);
var ruleResults = await RunRequestRules(tvBuilder.ChildRequest);
var results = ruleResults as RuleResult[] ?? ruleResults.ToArray();
if (results.Any(x => !x.Success))
{
@ -180,7 +70,7 @@ namespace Ombi.Core.Engine
foreach (var existingSeason in existingRequest.ChildRequests)
foreach (var existing in existingSeason.SeasonRequests)
{
var newChild = childRequest.SeasonRequests.FirstOrDefault(x => x.SeasonNumber == existing.SeasonNumber);
var newChild = tvBuilder.ChildRequest.SeasonRequests.FirstOrDefault(x => x.SeasonNumber == existing.SeasonNumber);
if (newChild != null)
{
// We have some requests in this season...
@ -197,32 +87,19 @@ namespace Ombi.Core.Engine
if (!newChild.Episodes.Any())
{
// We may have removed all episodes
childRequest.SeasonRequests.Remove(newChild);
tvBuilder.ChildRequest.SeasonRequests.Remove(newChild);
}
}
}
// Remove the ID since this is a new child
childRequest.Id = 0;
return await AddExistingRequest(childRequest, existingRequest);
tvBuilder.ChildRequest.Id = 0;
return await AddExistingRequest(tvBuilder.ChildRequest, existingRequest);
}
// This is a new request
var model = new TvRequests
{
Id = tv.Id,
Overview = showInfo.summary.RemoveHtml(),
PosterPath = posterPath,
Title = showInfo.name,
ReleaseDate = firstAir,
Status = showInfo.status,
ImdbId = showInfo.externals?.imdb ?? string.Empty,
TvDbId = tv.Id,
ChildRequests = new List<ChildRequests>(),
TotalSeasons = tv.SeasonRequests.Count()
};
model.ChildRequests.Add(childRequest);
return await AddRequest(model);
var newRequest = tvBuilder.CreateNewRequest(tv);
return await AddRequest(newRequest.NewRequest);
}
public async Task<IEnumerable<TvRequests>> GetRequests(int count, int position)

@ -0,0 +1,197 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Ombi.Api.TvMaze;
using Ombi.Api.TvMaze.Models;
using Ombi.Core.Models.Search;
using Ombi.Helpers;
using Ombi.Store.Entities;
using Ombi.Store.Entities.Requests;
using Ombi.Store.Repository.Requests;
namespace Ombi.Core.Helpers
{
public class TvShowRequestBuilder
{
public TvShowRequestBuilder(ITvMazeApi tvApi)
{
TvApi = tvApi;
}
private ITvMazeApi TvApi { get; }
public ChildRequests ChildRequest { get; set; }
public List<SeasonRequests> TvRequests { get; protected set; }
public string PosterPath { get; protected set; }
public DateTime FirstAir { get; protected set; }
public TvRequests NewRequest { get; protected set; }
protected TvMazeShow ShowInfo { get; set; }
public async Task<TvShowRequestBuilder> GetShowInfo(int id)
{
ShowInfo = await TvApi.ShowLookupByTheTvDbId(id);
DateTime.TryParse(ShowInfo.premiered, out DateTime dt);
FirstAir = dt;
// For some reason the poster path is always http
PosterPath = ShowInfo.image?.medium.Replace("http:", "https:");
return this;
}
public TvShowRequestBuilder CreateChild(SearchTvShowViewModel model, int userId)
{
ChildRequest = new ChildRequests
{
Id = model.Id,
RequestType = RequestType.TvShow,
RequestedDate = DateTime.UtcNow,
Approved = false,
RequestedUserId = userId,
SeasonRequests = new List<SeasonRequests>()
};
return this;
}
public TvShowRequestBuilder CreateTvList(SearchTvShowViewModel tv)
{
TvRequests = new List<SeasonRequests>();
// Only have the TV requests we actually requested and not everything
foreach (var season in tv.SeasonRequests)
{
for (int i = season.Episodes.Count - 1; i >= 0; i--)
{
if (!season.Episodes[i].Requested)
{
season.Episodes.RemoveAt(i); // Remove the episode since it's not requested
}
}
if (season.Episodes.Any())
{
TvRequests.Add(season);
}
}
return this;
}
public async Task<TvShowRequestBuilder> BuildEpisodes(SearchTvShowViewModel tv)
{
if (tv.RequestAll)
{
var episodes = await TvApi.EpisodeLookup(ShowInfo.id);
foreach (var ep in episodes)
{
var season = ChildRequest.SeasonRequests.FirstOrDefault(x => x.SeasonNumber == ep.season);
if (season == null)
{
ChildRequest.SeasonRequests.Add(new SeasonRequests
{
Episodes = new List<EpisodeRequests>{
new EpisodeRequests
{
EpisodeNumber = ep.number,
AirDate = DateTime.Parse(ep.airdate),
Title = ep.name,
Url = ep.url
}
},
SeasonNumber = ep.season,
});
}
else
{
season.Episodes.Add(new EpisodeRequests
{
EpisodeNumber = ep.number,
AirDate = DateTime.Parse(ep.airdate),
Title = ep.name,
Url = ep.url
});
}
}
}
else if (tv.LatestSeason)
{
var episodes = await TvApi.EpisodeLookup(ShowInfo.id);
var latest = episodes.OrderBy(x => x.season).FirstOrDefault();
var episodesRequests = new List<EpisodeRequests>();
foreach (var ep in episodes)
{
episodesRequests.Add(new EpisodeRequests
{
EpisodeNumber = ep.number,
AirDate = DateTime.Parse(ep.airdate),
Title = ep.name,
Url = ep.url
});
}
ChildRequest.SeasonRequests.Add(new SeasonRequests
{
Episodes = episodesRequests,
SeasonNumber = latest.season,
});
}
else if (tv.FirstSeason)
{
var episodes = await TvApi.EpisodeLookup(ShowInfo.id);
var first = episodes.OrderByDescending(x => x.season).FirstOrDefault();
var episodesRequests = new List<EpisodeRequests>();
foreach (var ep in episodes)
{
if (ep.season == first.season)
{
episodesRequests.Add(new EpisodeRequests
{
EpisodeNumber = ep.number,
AirDate = DateTime.Parse(ep.airdate),
Title = ep.name,
Url = ep.url
});
}
}
ChildRequest.SeasonRequests.Add(new SeasonRequests
{
Episodes = episodesRequests,
SeasonNumber = first.season,
});
}
else
{
// It's a custom request
ChildRequest.SeasonRequests = TvRequests;
}
return this;
}
public TvShowRequestBuilder CreateNewRequest(SearchTvShowViewModel tv)
{
NewRequest = new TvRequests
{
Id = tv.Id,
Overview = ShowInfo.summary.RemoveHtml(),
PosterPath = PosterPath,
Title = ShowInfo.name,
ReleaseDate = FirstAir,
Status = ShowInfo.status,
ImdbId = ShowInfo.externals?.imdb ?? string.Empty,
TvDbId = tv.Id,
ChildRequests = new List<ChildRequests>(),
TotalSeasons = tv.SeasonRequests.Count()
};
NewRequest.ChildRequests.Add(ChildRequest);
return this;
}
}
}

@ -0,0 +1,32 @@
//using System.Linq;
//using Ombi.Store.Entities;
//using Xunit;
//using Xunit.Abstractions;
//namespace Ombi.Notifications.Tests
//{
// public class NotificationMessageResolverTests
// {
// public NotificationMessageResolverTests(ITestOutputHelper helper)
// {
// _resolver = new NotificationMessageResolver();
// output = helper;
// }
// private readonly NotificationMessageResolver _resolver;
// private readonly ITestOutputHelper output;
// [Fact]
// public void Resolved_ShouldResolve_RequestedUser()
// {
// var result = _resolver.ParseMessage(new NotificationTemplates
// {
// Subject = "This is a {RequestedUser}"
// }, new NotificationMessageCurlys {RequestedUser = "Abc"});
// output.WriteLine(result.Message);
// //Assert.True(result.Message.Equals("This is a Abc"));
// Assert.Contains("11a", result.Message);
// }
// }
//}

@ -0,0 +1,19 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netcoreapp1.1</TargetFramework>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.0.0" />
<PackageReference Include="Moq" Version="4.7.10" />
<PackageReference Include="xunit" Version="2.2.0" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.2.0" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Ombi.Notifications\Ombi.Notifications.csproj" />
</ItemGroup>
</Project>

@ -0,0 +1,9 @@
namespace Ombi.Notifications
{
public class NotificationMessageContent
{
public string Subject { get; set; }
public string Message { get; set; }
public string Image { get; set; }
}
}

@ -0,0 +1,73 @@
using System;
using System.Collections.Generic;
using Ombi.Store.Entities.Requests;
namespace Ombi.Notifications
{
public class NotificationMessageCurlys
{
public void Setup(FullBaseRequest req)
{
RequestedUser = string.IsNullOrEmpty(req.RequestedUser.Alias)
? req.RequestedUser.Username
: req.RequestedUser.Alias;
Title = req.Title;
RequestedDate = req.RequestedDate.ToString("D");
Type = req.RequestType.ToString();
Overview = req.Overview;
Year = req.ReleaseDate.Year.ToString();
PosterImage = req.PosterPath;
}
public void Setup(ChildRequests req)
{
RequestedUser = string.IsNullOrEmpty(req.RequestedUser.Alias)
? req.RequestedUser.Username
: req.RequestedUser.Alias;
Title = req.ParentRequest.Title;
RequestedDate = req.RequestedDate.ToString("D");
Type = req.RequestType.ToString();
Overview = req.ParentRequest.Overview;
Year = req.ParentRequest.ReleaseDate.Year.ToString();
PosterImage = req.ParentRequest.PosterPath;
// DO Episode and Season Lists
}
// User Defined
public string RequestedUser { get; set; }
public string Title { get; set; }
public string RequestedDate { get; set; }
public string Type { get; set; }
public string Issue { get; set; }
public string Overview { get; set; }
public string Year { get; set; }
public string EpisodesList { get; set; }
public string SeasonsList { get; set; }
public string PosterImage { get; set; }
// System Defined
private string LongDate => DateTime.Now.ToString("D");
private string ShortDate => DateTime.Now.ToString("d");
private string LongTime => DateTime.Now.ToString("T");
private string ShortTime => DateTime.Now.ToString("t");
public Dictionary<string, string> Curlys => new Dictionary<string, string>
{
{nameof(RequestedUser), RequestedUser },
{nameof(Title), Title },
{nameof(RequestedDate), RequestedDate },
{nameof(Type), Type },
{nameof(Issue), Issue },
{nameof(LongDate),LongDate},
{nameof(ShortDate),ShortDate},
{nameof(LongTime),LongTime},
{nameof(ShortTime),ShortTime},
{nameof(Overview),Overview},
{nameof(Year),Year},
{nameof(EpisodesList),EpisodesList},
{nameof(SeasonsList),SeasonsList},
{nameof(PosterImage),PosterImage},
};
}
}

@ -1,84 +1,10 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Diagnostics;
using Ombi.Store.Entities;
using Ombi.Store.Entities.Requests;
namespace Ombi.Notifications
{
public class NotificationMessageContent
{
public string Subject { get; set; }
public string Message { get; set; }
public string Image { get; set; }
}
public class NotificationMessageCurlys
{
public void Setup(FullBaseRequest req)
{
RequestedUser = string.IsNullOrEmpty(req.RequestedUser.Alias)
? req.RequestedUser.Username
: req.RequestedUser.Alias;
Title = req.Title;
RequestedDate = req.RequestedDate.ToString("D");
Type = req.RequestType.ToString();
Overview = req.Overview;
Year = req.ReleaseDate.Year.ToString();
PosterImage = req.PosterPath;
}
public void Setup(ChildRequests req)
{
RequestedUser = string.IsNullOrEmpty(req.RequestedUser.Alias)
? req.RequestedUser.Username
: req.RequestedUser.Alias;
Title = req.ParentRequest.Title;
RequestedDate = req.RequestedDate.ToString("D");
Type = req.RequestType.ToString();
Overview = req.ParentRequest.Overview;
Year = req.ParentRequest.ReleaseDate.Year.ToString();
PosterImage = req.ParentRequest.PosterPath;
// DO Episode and Season Lists
}
// User Defined
public string RequestedUser { get; set; }
public string Title { get; set; }
public string RequestedDate { get; set; }
public string Type { get; set; }
public string Issue { get; set; }
public string Overview { get; set; }
public string Year { get; set; }
public string EpisodesList { get; set; }
public string SeasonsList { get; set; }
public string PosterImage { get; set; }
// System Defined
private string LongDate => DateTime.Now.ToString("D");
private string ShortDate => DateTime.Now.ToString("d");
private string LongTime => DateTime.Now.ToString("T");
private string ShortTime => DateTime.Now.ToString("t");
public Dictionary<string, string> Curlys => new Dictionary<string, string>
{
{nameof(RequestedUser), RequestedUser },
{nameof(Title), Title },
{nameof(RequestedDate), RequestedDate },
{nameof(Type), Type },
{nameof(Issue), Issue },
{nameof(LongDate),LongDate},
{nameof(ShortDate),ShortDate},
{nameof(LongTime),LongTime},
{nameof(ShortTime),ShortTime},
{nameof(Overview),Overview},
{nameof(Year),Year},
{nameof(EpisodesList),EpisodesList},
{nameof(SeasonsList),SeasonsList},
{nameof(PosterImage),PosterImage},
};
}
public class NotificationMessageResolver
{
/// <summary>
@ -113,20 +39,99 @@ namespace Ombi.Notifications
private NotificationMessageContent Resolve(string body, string subject, IReadOnlyDictionary<string, string> parameters)
{
// Find the fields
var bodyFields = FindCurlyFields(body);
var subjectFields = FindCurlyFields(subject);
var bodyFields = FindFields(body, StartChar, EndChar);
var subjectFields = FindFields(subject, StartChar, EndChar);
//var conditionalFields = FindFields(body, '<', '>');
//ProcessConditions(conditionalFields, parameters);
body = ReplaceFields(bodyFields, parameters, body);
subject = ReplaceFields(subjectFields, parameters, subject);
return new NotificationMessageContent { Message = body ?? string.Empty, Subject = subject ?? string.Empty};
}
public IEnumerable<string> ProcessConditions(IEnumerable<string> conditionalFields, IReadOnlyDictionary<string, string> parameters)
{
foreach (var f in conditionalFields)
{
var field = f.ToLower();
if (field.StartsWith("if"))
{
var ifPosition = field.IndexOf("if", StringComparison.Ordinal);
Console.WriteLine(ifPosition);
var identifierStart = field.Substring(ifPosition + 3);
Console.WriteLine(identifierStart);
var identifierEnd = identifierStart.IndexOf(' ');
Console.WriteLine(identifierEnd);
var identitifier = identifierStart.Substring(ifPosition, identifierEnd);
if (identitifier.Equals("type"))
{
// Find the operator == or !=
var stringWithoutIdentifier = identifierStart.Substring(identitifier.Length + 1);
var operatorValue = stringWithoutIdentifier.Substring(0,2);
var stringWithoutOperator = stringWithoutIdentifier.Substring(operatorValue.Length + 1);
var endPosition = stringWithoutOperator.IndexOf(' ');
var comparison = stringWithoutOperator.Substring(0, endPosition);
if (operatorValue == "==")
{
var type = (RequestType)int.Parse(parameters["Type"]);
if (comparison.Equals("Movie", StringComparison.CurrentCultureIgnoreCase))
{
if (type == RequestType.Movie)
{
// Get the text
var stringWithoutComparison = stringWithoutOperator.Substring(comparison.Length + 2);
var endString = stringWithoutComparison.IndexOf(' ');
var text = stringWithoutComparison.Substring(0, endString - 1);
field = text;
}
else
{
// Get the text in the ELSE
var stringWithoutComparison = stringWithoutOperator.Substring(comparison.Length + 2);
var elseIndex = stringWithoutComparison.IndexOf("else", StringComparison.CurrentCultureIgnoreCase);
var endIndex = stringWithoutComparison.IndexOf(' ');
if (elseIndex >= 0)
{
var elseString = stringWithoutComparison.Substring(elseIndex, endIndex);
}
else
{
// No else
}
}
}
else if(comparison.Equals("TvShow", StringComparison.CurrentCultureIgnoreCase) || comparison.Equals("Tv", StringComparison.CurrentCultureIgnoreCase))
{
if (type == RequestType.TvShow)
{
}
}
}
else if (operatorValue == "!=")
{
}
}
}
}
return conditionalFields;
}
/// <summary>
/// Finds the curly fields.
/// </summary>
/// <param name="message">The message.</param>
/// <returns></returns>
private IEnumerable<string> FindCurlyFields(string message)
private IEnumerable<string> FindFields(string message, char start, char end)
{
if (string.IsNullOrEmpty(message))
{
@ -145,13 +150,13 @@ namespace Ombi.Notifications
continue;
}
if (c == StartChar) // Start of curly '{'
if (c == start) // Start of curly '{'
{
insideCurly = true;
continue;
}
if (c == EndChar) // End of curly '}'
if (c == end) // End of curly '}'
{
fields.Add(currentWord); // We have finished the curly, add the word into the list
currentWord = string.Empty;

@ -1,7 +1,7 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 15
VisualStudioVersion = 15.0.26430.6
VisualStudioVersion = 15.0.26430.14
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ombi", "Ombi\Ombi.csproj", "{C987AA67-AFE1-468F-ACD3-EAD5A48E1F6A}"
EndProject
@ -13,58 +13,60 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution
Build\publish.bat = Build\publish.bat
EndProjectSection
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Ombi.Core", "Ombi.Core\Ombi.Core.csproj", "{F56E79C7-791D-4668-A0EC-29E3BBC8D24B}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ombi.Core", "Ombi.Core\Ombi.Core.csproj", "{F56E79C7-791D-4668-A0EC-29E3BBC8D24B}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Api", "Api", "{9293CA11-360A-4C20-A674-B9E794431BF5}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Ombi.Api.TheMovieDb", "Ombi.TheMovieDbApi\Ombi.Api.TheMovieDb.csproj", "{132DA282-5894-4570-8916-D8C18ED2CE84}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ombi.Api.TheMovieDb", "Ombi.TheMovieDbApi\Ombi.Api.TheMovieDb.csproj", "{132DA282-5894-4570-8916-D8C18ED2CE84}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Ombi.Api", "Ombi.Api\Ombi.Api.csproj", "{EA31F915-31F9-4318-B521-1500CDF40DDF}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ombi.Api", "Ombi.Api\Ombi.Api.csproj", "{EA31F915-31F9-4318-B521-1500CDF40DDF}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ombi.Helpers", "Ombi.Helpers\Ombi.Helpers.csproj", "{C182B435-1FAB-49C5-9BF9-F7F5C6EF3C94}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ombi.Store", "Ombi.Store\Ombi.Store.csproj", "{68086581-1EFD-4390-8100-47F87D1CB628}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Ombi.DependencyInjection", "Ombi.DependencyInjection\Ombi.DependencyInjection.csproj", "{B39E4558-C557-48E7-AA74-19C5CD809617}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ombi.DependencyInjection", "Ombi.DependencyInjection\Ombi.DependencyInjection.csproj", "{B39E4558-C557-48E7-AA74-19C5CD809617}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Ombi.Mapping", "Ombi.Mapping\Ombi.Mapping.csproj", "{63E63511-1C7F-4162-8F92-8F7391B3C8A3}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ombi.Mapping", "Ombi.Mapping\Ombi.Mapping.csproj", "{63E63511-1C7F-4162-8F92-8F7391B3C8A3}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Mappers", "Mappers", "{025FB189-2FFB-4F43-A64B-6F1B5A0D2065}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "DI", "DI", "{410F36CF-9C60-428A-B191-6FD90610991A}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Ombi.Api.Plex", "Ombi.Api.Plex\Ombi.Api.Plex.csproj", "{2E1A7B91-F29B-42BC-8F1E-1CF2DCC389BA}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ombi.Api.Plex", "Ombi.Api.Plex\Ombi.Api.Plex.csproj", "{2E1A7B91-F29B-42BC-8F1E-1CF2DCC389BA}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Ombi.Schedule", "Ombi.Schedule\Ombi.Schedule.csproj", "{5B42ADD4-757A-47C1-9CC5-320829C5E665}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ombi.Schedule", "Ombi.Schedule\Ombi.Schedule.csproj", "{5B42ADD4-757A-47C1-9CC5-320829C5E665}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Ombi.Api.Emby", "Ombi.Api.Emby\Ombi.Api.Emby.csproj", "{08FF107D-31E1-470D-AF86-E09B015CEE06}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ombi.Api.Emby", "Ombi.Api.Emby\Ombi.Api.Emby.csproj", "{08FF107D-31E1-470D-AF86-E09B015CEE06}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Ombi.Api.Sonarr", "Ombi.Api.Sonarr\Ombi.Api.Sonarr.csproj", "{CFB5E008-D0D0-43C0-AA06-89E49D17F384}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ombi.Api.Sonarr", "Ombi.Api.Sonarr\Ombi.Api.Sonarr.csproj", "{CFB5E008-D0D0-43C0-AA06-89E49D17F384}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tests", "Tests", "{6F42AB98-9196-44C4-B888-D5E409F415A1}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Ombi.Api.TvMaze", "Ombi.Api.TvMaze\Ombi.Api.TvMaze.csproj", "{0E8EF835-E4F0-4EE5-A2B6-678DEE973721}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ombi.Api.TvMaze", "Ombi.Api.TvMaze\Ombi.Api.TvMaze.csproj", "{0E8EF835-E4F0-4EE5-A2B6-678DEE973721}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Ombi.Notifications", "Ombi.Notifications\Ombi.Notifications.csproj", "{E6EE2830-E4AC-4F2E-AD93-2C9305605761}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ombi.Notifications", "Ombi.Notifications\Ombi.Notifications.csproj", "{E6EE2830-E4AC-4F2E-AD93-2C9305605761}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Notifications", "Notifications", "{EA30DD15-6280-4687-B370-2956EC2E54E5}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Ombi.Notifications.Templates", "Ombi.Notifications.Templates\Ombi.Notifications.Templates.csproj", "{6EE01B17-0966-4E11-8BC1-A5318A92AB1D}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ombi.Notifications.Templates", "Ombi.Notifications.Templates\Ombi.Notifications.Templates.csproj", "{6EE01B17-0966-4E11-8BC1-A5318A92AB1D}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Ombi.Settings", "Ombi.Settings\Ombi.Settings.csproj", "{AE3AA23D-5B66-42AF-B44E-B9B4D8856C6F}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ombi.Settings", "Ombi.Settings\Ombi.Settings.csproj", "{AE3AA23D-5B66-42AF-B44E-B9B4D8856C6F}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Ombi.Api.Trakt", "Ombi.Api.Trakt\Ombi.Api.Trakt.csproj", "{3880375C-1A7E-4D75-96EC-63B954C42FEA}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ombi.Api.Trakt", "Ombi.Api.Trakt\Ombi.Api.Trakt.csproj", "{3880375C-1A7E-4D75-96EC-63B954C42FEA}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Ombi.Core.Tests", "Ombi.Core.Tests\Ombi.Core.Tests.csproj", "{FC6A8F7C-9722-4AE4-960D-277ACB0E81CB}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ombi.Core.Tests", "Ombi.Core.Tests\Ombi.Core.Tests.csproj", "{FC6A8F7C-9722-4AE4-960D-277ACB0E81CB}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Ombi.Api.Radarr", "Ombi.Api.Radarr\Ombi.Api.Radarr.csproj", "{94D04C1F-E35A-499C-B0A0-9FADEBDF8336}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ombi.Api.Radarr", "Ombi.Api.Radarr\Ombi.Api.Radarr.csproj", "{94D04C1F-E35A-499C-B0A0-9FADEBDF8336}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Ombi.Api.Discord", "Ombi.Api.Discord\Ombi.Api.Discord.csproj", "{5AF2B6D2-5CC6-49FE-928A-BA27AF52B194}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ombi.Api.Discord", "Ombi.Api.Discord\Ombi.Api.Discord.csproj", "{5AF2B6D2-5CC6-49FE-928A-BA27AF52B194}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Ombi.Updater", "Ombi.Updater\Ombi.Updater.csproj", "{6294A82D-4915-4FC3-B301-8F985716F34C}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ombi.Updater", "Ombi.Updater\Ombi.Updater.csproj", "{6294A82D-4915-4FC3-B301-8F985716F34C}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Update", "Update", "{D11FE57E-1E57-491D-A1D4-01AEF4BE5CB6}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Ombi.Notifications.Tests", "Ombi.Notifications.Tests\Ombi.Notifications.Tests.csproj", "{2C7836E7-B120-40A6-B641-DDAA02FBAE23}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@ -155,6 +157,10 @@ Global
{6294A82D-4915-4FC3-B301-8F985716F34C}.Debug|Any CPU.Build.0 = Debug|Any CPU
{6294A82D-4915-4FC3-B301-8F985716F34C}.Release|Any CPU.ActiveCfg = Release|Any CPU
{6294A82D-4915-4FC3-B301-8F985716F34C}.Release|Any CPU.Build.0 = Release|Any CPU
{2C7836E7-B120-40A6-B641-DDAA02FBAE23}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{2C7836E7-B120-40A6-B641-DDAA02FBAE23}.Debug|Any CPU.Build.0 = Debug|Any CPU
{2C7836E7-B120-40A6-B641-DDAA02FBAE23}.Release|Any CPU.ActiveCfg = Release|Any CPU
{2C7836E7-B120-40A6-B641-DDAA02FBAE23}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@ -175,5 +181,6 @@ Global
{94D04C1F-E35A-499C-B0A0-9FADEBDF8336} = {9293CA11-360A-4C20-A674-B9E794431BF5}
{5AF2B6D2-5CC6-49FE-928A-BA27AF52B194} = {9293CA11-360A-4C20-A674-B9E794431BF5}
{6294A82D-4915-4FC3-B301-8F985716F34C} = {D11FE57E-1E57-491D-A1D4-01AEF4BE5CB6}
{2C7836E7-B120-40A6-B641-DDAA02FBAE23} = {6F42AB98-9196-44C4-B888-D5E409F415A1}
EndGlobalSection
EndGlobal

@ -16,11 +16,8 @@ import { NgbModule } from '@ng-bootstrap/ng-bootstrap';
// Components
import { AppComponent } from './app.component';
// Search
import { SearchComponent } from './search/search.component';
import { MovieSearchComponent } from './search/moviesearch.component';
import { TvSearchComponent } from './search/tvsearch.component';
import { SeriesInformationComponent } from './search/seriesinformation.component';
// Request
import { RequestComponent } from './requests/request.component';
@ -32,10 +29,10 @@ import { RequestCardComponent } from './request-grid/request-card.component';
import { LoginComponent } from './login/login.component';
import { LandingPageComponent } from './landingpage/landingpage.component';
import { UserManagementComponent } from './usermanagement/usermanagement.component';
import { UserManagementEditComponent } from './usermanagement/usermanagement-edit.component';
import { PageNotFoundComponent } from './errors/not-found.component';
// Services
import { SearchService } from './services/search.service';
import { RequestService } from './services/request.service';
import { NotificationService } from './services/notification.service';
import { SettingsService } from './services/settings.service';
@ -49,17 +46,17 @@ import { StatusService } from './services/status.service';
// Modules
import { SettingsModule } from './settings/settings.module';
import { WizardModule } from './wizard/wizard.module';
import { SearchModule } from './search/search.module';
const routes: Routes = [
{ path: '*', component: PageNotFoundComponent },
{ path: '', redirectTo: '/search', pathMatch: 'full' },
{ path: 'search', component: SearchComponent, canActivate: [AuthGuard] },
{ path: 'search/show/:id', component: SeriesInformationComponent, canActivate: [AuthGuard] },
{ path: 'requests', component: RequestComponent, canActivate: [AuthGuard] },
//{ path: 'requests-grid', component: RequestGridComponent },
{ path: 'login', component: LoginComponent },
{ path: 'landingpage', component: LandingPageComponent },
{ path: 'usermanagement', component: UserManagementComponent, canActivate: [AuthGuard] },
{ path: 'usermanagement/edit/:id', component: UserManagementEditComponent, canActivate: [AuthGuard] },
];
@NgModule({
@ -77,6 +74,7 @@ const routes: Routes = [
InfiniteScrollModule,
AuthModule,
WizardModule,
SearchModule,
DialogModule,
MdButtonModule,
NgbModule.forRoot(),
@ -89,21 +87,17 @@ const routes: Routes = [
declarations: [
AppComponent,
PageNotFoundComponent,
SearchComponent,
RequestComponent,
LoginComponent,
MovieSearchComponent,
TvSearchComponent,
LandingPageComponent,
UserManagementComponent,
MovieRequestsComponent,
TvRequestsComponent,
SeriesInformationComponent,
//RequestGridComponent,
RequestCardComponent,
UserManagementEditComponent,
],
providers: [
SearchService,
RequestService,
NotificationService,
AuthService,

@ -2,11 +2,11 @@
you can substitue the span of reauth email for a input with the email and
include the remember me checkbox
-->
<div *ngIf="form">
<div *ngIf="form && customizationSettings">
<div class="container" id="login">
<div class="card card-container">
<!-- <img class="profile-img-card" src="//lh3.googleusercontent.com/-6V8xOA6M7BA/AAAAAAAAAAI/AAAAAAAAAAA/rzlHcD0KYwo/photo.jpg?sz=120" alt="" /> -->
<div *ngIf="!customizationSettings.logo"><img id="profile-img" class="profile-img-card" src="/images/logo.png" /></div>
<div *ngIf="!customizationSettings.logo"><img id="profile-img" class="profile-img-card" src="/images/ms-icon-150x150.png" /></div>
<div *ngIf="customizationSettings.logo"><img id="profile-img" class="profile-img-card" [src]="customizationSettings.logo" /></div>
<p id="profile-name" class="profile-name-card"></p>

@ -0,0 +1,45 @@
import { NgModule, } from '@angular/core';
import { CommonModule } from '@angular/common';
import { FormsModule } from '@angular/forms';
import { RouterModule, Routes } from '@angular/router';
import { NgbModule } from '@ng-bootstrap/ng-bootstrap';
import { SearchComponent } from './search.component';
import { MovieSearchComponent } from './moviesearch.component';
import { TvSearchComponent } from './tvsearch.component';
import { SeriesInformationComponent } from './seriesinformation.component';
import { SearchService } from '../services/search.service';
import { RequestService } from '../services/request.service';
import { AuthGuard } from '../auth/auth.guard';
const routes: Routes = [
{ path: 'search', component: SearchComponent, canActivate: [AuthGuard] },
{ path: 'search/show/:id', component: SeriesInformationComponent, canActivate: [AuthGuard] },
];
@NgModule({
imports: [
CommonModule,
FormsModule,
RouterModule.forChild(routes),
NgbModule.forRoot(),
],
declarations: [
SearchComponent,
MovieSearchComponent,
TvSearchComponent,
SeriesInformationComponent
],
exports: [
RouterModule
],
providers: [
SearchService,
RequestService
],
})
export class SearchModule { }

@ -20,6 +20,10 @@ export class IdentityService extends ServiceAuthHelpers {
return this.http.get(this.url).map(this.extractData);
}
getUserById(id: number): Observable<IUser> {
return this.http.get(`${this.url}User/${id}`).map(this.extractData);
}
getUsers(): Observable<IUser[]> {
return this.http.get(`${this.url}Users`).map(this.extractData);
}

@ -0,0 +1,53 @@
<h1>User Management</h1>
<div *ngIf="user">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" (click)="showEditDialog=false">&times;</button>
<h4 class="modal-title">Editing User {{user?.username}}</h4>
</div>
<div class="modal-body">
<div class="form-group">
<label for="username" class="control-label">Username</label>
<div>
<input type="text" [(ngModel)]="selectedUser.username" [readonly]="true" class="form-control form-control-custom " id="username" name="username" value="{{selectedUser?.username}}">
</div>
</div>
<div class="form-group">
<label for="alias" class="control-label">Alias</label>
<div>
<input type="text" [(ngModel)]="selectedUser.alias" class="form-control form-control-custom " id="alias" name="alias" value="{{selectedUser?.alias}}">
</div>
</div>
<div class="form-group">
<label for="alias" class="control-label">Email Address</label>
<div>
<input type="text" [(ngModel)]="selectedUser.emailAddress" class="form-control form-control-custom " id="emailAddress" name="emailAddress" value="{{selectedUser?.emailAddress}}">
</div>
</div>
<div *ngFor="let c of selectedUser.claims">
<div class="form-group">
<div class="checkbox">
<input type="checkbox" [(ngModel)]="c.enabled" [value]="c.value" id="create{{c.value}}" [attr.name]="'create' + c.value" ng-checked="c.enabled">
<label for="create{{c.value}}">{{c.value}}</label>
</div>
</div>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-danger-outline" (click)="showEditDialog=false">Close</button>
<button type="button" class="btn btn-primary-outline" (click)="updateUser()">Save changes</button>
</div>
</div>
</div>
</div>

@ -0,0 +1,31 @@
import { Component, OnInit } from '@angular/core';
import { IUser, ICheckbox } from '../interfaces/IUser';
import { IdentityService } from '../services/identity.service';
import { ActivatedRoute } from '@angular/router';
@Component({
templateUrl: './usermanagement-edit.component.html'
})
export class UserManagementEditComponent implements OnInit {
constructor(private identityService: IdentityService, private route: ActivatedRoute) {
this.route.params
.subscribe(params => {
this.userId = +params['id']; // (+) converts string 'id' to a number
});
}
ngOnInit(): void {
this.identityService.getAllAvailableClaims().subscribe(x => this.availableClaims = x);
this.identityService.getUserById(this.userId).subscribe(x => this.user = x);
}
user: IUser;
userId: number;
availableClaims : ICheckbox[];
}

@ -112,7 +112,7 @@ namespace Ombi.Controllers
/// Gets the user by the user id.
/// </summary>
/// <returns>Information about the user</returns>
[HttpGet("Users/{id}")]
[HttpGet("User/{id}")]
public async Task<UserViewModel> GetUser(int id)
{
var type = typeof(OmbiClaims);
@ -121,7 +121,7 @@ namespace Ombi.Controllers
var fields = fieldInfos.Where(fi => fi.IsLiteral && !fi.IsInitOnly).ToList();
var allClaims = fields.Select(x => x.Name).ToList();
var user = Mapper.Map<UserViewModel>(await IdentityManager.GetUser(id)).ToList();
var user = Mapper.Map<UserViewModel>(await IdentityManager.GetUser(id));
var userClaims = user.Claims.Select(x => x.Value);

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB

Loading…
Cancel
Save